Skip to repository content936 lines · 29.4 KB · javascript
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T01:54:48.752Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
fake_effectd.mjs
1#!/usr/bin/env node
2/**
3 * Minimal omega-effectd framed-protocol fixture for Rust supervisor tests.
4 * Speaks openagents.omega.effectd.v1 on stdin/stdout.
5 */
6import { createInterface } from "node:readline"
7import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs"
8import path from "node:path"
9
10const schema = "openagents.omega.effectd.v1"
11const oversizedHealthResponse = process.argv.includes("--oversized-health-response")
12const hostRequestHealth = process.argv.includes("--host-request-health")
13const unavailableHostRequestHealth = process.argv.includes("--unavailable-host-request-health")
14const staleHostRequestHealth = process.argv.includes("--stale-host-request-health")
15const staleHealthResponse = process.argv.includes("--stale-health-response")
16const dataRoot = process.env.OPENAGENTS_OMEGA_EFFECTD_DATA_ROOT
17if (!dataRoot) {
18 console.error("OPENAGENTS_OMEGA_EFFECTD_DATA_ROOT is required")
19 process.exit(2)
20}
21
22const runsFile = path.join(dataRoot, "full-auto", "runs.json")
23const bindingsFile = path.join(dataRoot, "full-auto", "native-bindings.json")
24const agentComputerSessionsFile = path.join(dataRoot, "agent-computer", "sessions.json")
25mkdirSync(path.join(dataRoot, "full-auto"), { recursive: true, mode: 0o700 })
26mkdirSync(path.join(dataRoot, "agent-computer"), { recursive: true, mode: 0o700 })
27
28let generation = 0
29let running = false
30let pendingHostHealth = null
31
32const respond = (id, gen, ok, result, error) => {
33 process.stdout.write(
34 `${JSON.stringify({
35 schema,
36 kind: "response",
37 id,
38 generation: gen,
39 ok,
40 ...(result === undefined ? {} : { result }),
41 ...(error === undefined ? {} : { error }),
42 })}\n`,
43 )
44}
45
46const loadRuns = () => {
47 if (!existsSync(runsFile)) return []
48 try {
49 const parsed = JSON.parse(readFileSync(runsFile, "utf8"))
50 return Array.isArray(parsed.runs) ? parsed.runs : []
51 } catch {
52 return []
53 }
54}
55
56const saveRuns = (runs) => {
57 writeFileSync(
58 runsFile,
59 JSON.stringify(
60 { schema: "openagents.desktop.full_auto_run_registry.v1", runs },
61 null,
62 2,
63 ),
64 )
65}
66
67const loadBindings = () => {
68 if (!existsSync(bindingsFile)) return []
69 try {
70 const parsed = JSON.parse(readFileSync(bindingsFile, "utf8"))
71 return Array.isArray(parsed.bindings) ? parsed.bindings : []
72 } catch {
73 return []
74 }
75}
76
77const saveBindings = (bindings) => {
78 writeFileSync(
79 bindingsFile,
80 JSON.stringify(
81 {
82 schema: "openagents.omega.full_auto_native_binding.v1",
83 bindings,
84 },
85 null,
86 2,
87 ),
88 )
89}
90
91const loadAgentComputerSessions = () => {
92 if (!existsSync(agentComputerSessionsFile)) return []
93 try {
94 const parsed = JSON.parse(readFileSync(agentComputerSessionsFile, "utf8"))
95 return Array.isArray(parsed.sessions) ? parsed.sessions : []
96 } catch {
97 return []
98 }
99}
100
101const saveAgentComputerSessions = (sessions) => {
102 writeFileSync(
103 agentComputerSessionsFile,
104 JSON.stringify(
105 {
106 schema: "openagents.omega.agent_computer_session.v1",
107 sessions,
108 },
109 null,
110 2,
111 ),
112 )
113}
114
115// SARAH-NR-06 mock conversation store (in-memory; no Khala Sync).
116const SARAH_CONVERSATION_DIGEST = "aaaaaaaaaaaaaaaaaaaaaaaa"
117const SARAH_CONVERSATION_REF = `sarah.${SARAH_CONVERSATION_DIGEST}`
118const SARAH_LEGACY_THREAD_REF = `thread.sarah.${SARAH_CONVERSATION_DIGEST}`
119const sarahStore = {
120 messages: [],
121 messageSeq: 0,
122 runState: "idle",
123 activeTurnRef: null,
124}
125
126const sarahRoomState = () => ({
127 method: "sarah_room_state",
128 connection: "connected",
129 freshness: "fresh",
130 gapState: "none",
131 connectedRelays: ["mock://local"],
132 lastAcknowledgedEventId: sarahStore.messages.at(-1)?.eventId ?? null,
133 lastAcknowledgedCursor:
134 sarahStore.messages.length > 0
135 ? `cursor.${sarahStore.messages.length - 1}`
136 : null,
137 authenticated: true,
138 transport: "mock_relay",
139})
140
141const sarahSessionStatus = () => ({
142 signedIn: true,
143 accountLabel: "owner@example.com",
144 bindingState: "bound",
145 ownerPublicKeyHex: "b".repeat(64),
146 bindingExpiresAt: null,
147 transport: "mock_relay",
148})
149
150const sarahBootstrap = () => ({
151 principalRef: "principal.sarah",
152 displayName: "Sarah",
153 role: "owner_orchestrator",
154 conversationRef: SARAH_CONVERSATION_REF,
155 legacyThreadRef: SARAH_LEGACY_THREAD_REF,
156 ownerPublicKeyHex: "b".repeat(64),
157 sarahPublicKeyHex: "c".repeat(64),
158 authorityProfileRef: "docs/authority/SARAH_AUTHORITY.md",
159 authorityProfileRevision: 7,
160 roomState: sarahRoomState(),
161})
162
163const sarahSendMessage = (text) => {
164 sarahStore.messageSeq += 1
165 const turnRef = `turn.${sarahStore.messageSeq}`
166 const messageRef = `msg.${sarahStore.messageSeq}`
167 const eventId = `evt.msg.${sarahStore.messageSeq}`
168 const cursor = `cursor.${sarahStore.messages.length}`
169 sarahStore.activeTurnRef = turnRef
170 sarahStore.runState = "running"
171 sarahStore.messages.push({
172 eventId,
173 cursor,
174 role: "owner",
175 kind: "text",
176 text: String(text).slice(0, 512),
177 createdAt: new Date().toISOString(),
178 status: "accepted",
179 turnRef,
180 })
181 return {
182 accepted: true,
183 messageRef,
184 turnRef,
185 eventId,
186 cursor,
187 status: "accepted",
188 }
189}
190
191const sarahRoomSnapshot = (params) => {
192 const limit = Math.min(Math.max(Number(params.limit) || 32, 1), 64)
193 const entries = sarahStore.messages.slice(-limit).map((row) => ({
194 eventId: row.eventId,
195 cursor: row.cursor,
196 role: row.role,
197 kind: row.kind,
198 text: row.text,
199 createdAt: row.createdAt,
200 status: row.status,
201 }))
202 const cursor =
203 entries.at(-1)?.cursor ?? params.cursor ?? "cursor.start"
204 return {
205 conversationRef: SARAH_CONVERSATION_REF,
206 transcript: {
207 entries,
208 cursor,
209 nextCursor: null,
210 gapState: "none",
211 },
212 activity: {
213 entries: [],
214 cursor,
215 nextCursor: null,
216 gapState: "none",
217 },
218 runState: {
219 state: sarahStore.runState,
220 turnRef: sarahStore.activeTurnRef,
221 reason: null,
222 },
223 roomState: sarahRoomState(),
224 }
225}
226
227const sarahInterruptTurn = (turnRef) => {
228 sarahStore.runState = "interrupt_pending"
229 return {
230 accepted: true,
231 turnRef,
232 intentRef: `intent.interrupt.${sarahStore.messageSeq + 1}`,
233 status: "pending",
234 pending: true,
235 }
236}
237
238const projectAgentComputerSession = (params, state = "queued") => {
239 const startedAt = new Date().toISOString()
240 return {
241 sessionRef: `ccs.fixture.${Date.now().toString(36)}`,
242 environment: "openagents_cloud",
243 controlPlaneBaseUrl: params.controlPlaneBaseUrl,
244 repoRef: params.repoRef,
245 objectiveDigest: "fixture-objective-digest",
246 state,
247 adapter: params.adapter ?? "codex",
248 lane: params.lane ?? "cloud-gcp",
249 placementRef: "placement.fixture.ac01",
250 artifactRef: state === "completed" ? "artifact.fixture.ac01" : null,
251 agentComputerRef: "agentcomputer.fixture.ac01",
252 agentComputerState: state === "completed" ? "reclaimed" : "active",
253 startedAt,
254 updatedAt: startedAt,
255 }
256}
257
258const listRuns = () =>
259 loadRuns().map((run) => ({
260 runRef: run.runRef,
261 threadRef: run.threadRef ?? null,
262 state: run.state,
263 title: run.title,
264 updatedAt: run.updatedAt,
265 }))
266
267const healthResult = () => ({
268 ok: true,
269 status: running ? "running" : "stopped",
270 generation,
271 dataRoot,
272 activeRunCount: listRuns().filter((run) =>
273 ["running", "pausing", "paused", "retrying", "stalled"].includes(run.state),
274 ).length,
275})
276
277const detail = (run) => {
278 const binding = loadBindings().find((row) => row.runRef === run.runRef) ?? null
279 return {
280 runRef: run.runRef,
281 threadRef: run.threadRef ?? null,
282 state: run.state,
283 title: run.title,
284 objective: run.objective ?? "",
285 doneCondition: run.doneCondition ?? "",
286 workspaceRef: run.workspaceRef ?? null,
287 lane: run.lane ?? "codex-local",
288 turnCap: run.turnCap ?? 40,
289 successfulAttempts: run.successfulAttempts ?? 0,
290 failedAttempts: run.failedAttempts ?? 0,
291 stallCause: run.stallCause ?? null,
292 recoveryAction: run.recoveryAction ?? "none",
293 terminalReason: run.terminalReason ?? null,
294 startedAt: run.startedAt ?? run.createdAt ?? null,
295 updatedAt: run.updatedAt,
296 turns: run.turns ?? [],
297 nativeEvidence: binding
298 ? {
299 projectRef: binding.projectRef,
300 worktreeRef: binding.worktreeRef,
301 worktreePathDigest: binding.worktreePathDigest ?? null,
302 gitHead: binding.gitHead ?? null,
303 }
304 : null,
305 }
306}
307
308console.error(
309 JSON.stringify({
310 service: "fake-omega-effectd",
311 status: "listening",
312 protocol: schema,
313 dataRoot,
314 }),
315)
316
317const rl = createInterface({ input: process.stdin, crlfDelay: Infinity })
318for await (const line of rl) {
319 const trimmed = line.trim()
320 if (!trimmed) continue
321 let request
322 try {
323 request = JSON.parse(trimmed)
324 } catch {
325 respond("invalid", generation, false, undefined, {
326 code: "invalid_request",
327 message: "Frame was not valid JSON.",
328 })
329 continue
330 }
331 if (request.kind === "host_response" && pendingHostHealth !== null) {
332 const pending = pendingHostHealth
333 pendingHostHealth = null
334 const expectedError = pending.mode === "stale" ? "stale_generation" : "unavailable"
335 const accepted =
336 request.id === pending.hostId &&
337 request.generation === pending.hostGeneration &&
338 (pending.mode === "success"
339 ? request.ok === true && request.result?.workspaceRef === "workspace.omega.supervised"
340 : request.ok === false && request.error?.code === expectedError)
341 if (!accepted) {
342 respond(pending.request.id, generation, false, undefined, {
343 code: "invalid_request",
344 message: "Host response did not match the fixture contract.",
345 })
346 continue
347 }
348 respond(pending.request.id, generation, true, healthResult())
349 continue
350 }
351 if (request.method === "initialize") {
352 generation = request.params?.generation ?? 1
353 running = true
354 respond(request.id, generation, true, {
355 schema,
356 protocolVersion: 1,
357 serviceVersion: "0.1.0",
358 generation,
359 capabilities: [
360 "health",
361 "list_runs",
362 "get_run",
363 "start",
364 "pause",
365 "resume",
366 "handoff",
367 "stop",
368 "retry",
369 "get_capacity",
370 "decide_attention",
371 "get_report",
372 "get_receipt",
373 "apply_control_intent",
374 "get_sync_status",
375 "publish_projection",
376 "get_native_binding",
377 "assess_native_boundary",
378 "start_agent_computer_session",
379 "refresh_agent_computer_session",
380 "run_agent_computer_turn",
381 "get_agent_computer_session",
382 "list_agent_computer_sessions",
383 "sarah_session_status",
384 "sarah_bootstrap",
385 "sarah_room_snapshot",
386 "sarah_send_message",
387 "sarah_interrupt_turn",
388 ],
389 dataRoot,
390 activeRunLimit: 8,
391 })
392 continue
393 }
394 if (request.generation !== generation) {
395 respond(request.id, generation, false, undefined, {
396 code: "stale_generation",
397 message: `Expected generation ${generation}, got ${request.generation}.`,
398 })
399 continue
400 }
401 if (request.method === "health") {
402 if (oversizedHealthResponse) {
403 respond(request.id, generation, true, {
404 padding: "x".repeat(64 * 1024),
405 })
406 continue
407 }
408 if (hostRequestHealth || unavailableHostRequestHealth || staleHostRequestHealth) {
409 const mode = staleHostRequestHealth
410 ? "stale"
411 : unavailableHostRequestHealth
412 ? "unavailable"
413 : "success"
414 const hostGeneration = mode === "stale" ? generation - 1 : generation
415 const hostId = `host.${hostGeneration}.fixture`
416 pendingHostHealth = { request, hostId, hostGeneration, mode }
417 process.stdout.write(
418 `${JSON.stringify({
419 schema,
420 kind: "host_request",
421 id: hostId,
422 generation: hostGeneration,
423 method: "resolve_workspace",
424 params: { expectedWorkspaceRef: "workspace.omega.supervised" },
425 })}\n`,
426 )
427 continue
428 }
429 respond(request.id, staleHealthResponse ? generation - 1 : generation, true, healthResult())
430 continue
431 }
432 if (request.method === "list_runs") {
433 respond(request.id, generation, true, { runs: listRuns() })
434 continue
435 }
436 if (request.method === "get_run") {
437 const run = loadRuns().find((row) => row.runRef === request.params?.runRef)
438 if (!run) {
439 respond(request.id, generation, false, undefined, {
440 code: "run_not_found",
441 message: "No Full Auto run exists for that runRef.",
442 })
443 continue
444 }
445 respond(request.id, generation, true, { run: detail(run) })
446 continue
447 }
448 if (request.method === "start") {
449 const params = request.params ?? {}
450 if (!params.workspaceRef || !params.title || !params.objective || !params.doneCondition) {
451 respond(request.id, generation, false, undefined, {
452 code: "invalid_request",
453 message: "start requires workspaceRef, title, objective, and doneCondition.",
454 })
455 continue
456 }
457 if (params.rebaseUnsafe === true) {
458 respond(request.id, generation, false, undefined, {
459 code: "invalid_request",
460 message: "rebase_unsafe: refusing to start Full Auto on a rebase-unsafe worktree.",
461 })
462 continue
463 }
464 const now = new Date().toISOString()
465 const run = {
466 runRef: `run.full-auto.fixture.${Date.now().toString(36)}`,
467 threadRef: `thread.omega.${Date.now().toString(36)}`,
468 state: "running",
469 title: params.title,
470 objective: params.objective,
471 doneCondition: params.doneCondition,
472 workspaceRef: params.workspaceRef,
473 lane: params.lane ?? "codex-local",
474 turnCap: params.turnCap ?? 40,
475 successfulAttempts: 0,
476 failedAttempts: 0,
477 stallCause: null,
478 recoveryAction: "none",
479 terminalReason: null,
480 updatedAt: now,
481 turns: [],
482 }
483 const runs = loadRuns()
484 runs.push(run)
485 saveRuns(runs)
486 if (params.projectRef && params.worktreeRef) {
487 const bindings = loadBindings()
488 bindings.push({
489 runRef: run.runRef,
490 workspaceRef: params.workspaceRef,
491 projectRef: params.projectRef,
492 worktreeRef: params.worktreeRef,
493 worktreePathDigest: params.worktreePathDigest ?? null,
494 gitHead: params.gitHead ?? null,
495 rebaseUnsafe: false,
496 boundAt: now,
497 })
498 saveBindings(bindings)
499 }
500 respond(request.id, generation, true, { run: detail(run) })
501 continue
502 }
503 if (["pause", "resume", "stop", "retry"].includes(request.method)) {
504 const runs = loadRuns()
505 const index = runs.findIndex((row) => row.runRef === request.params?.runRef)
506 if (index < 0) {
507 respond(request.id, generation, false, undefined, {
508 code: "run_not_found",
509 message: "No Full Auto run exists for that runRef.",
510 })
511 continue
512 }
513 const nextState =
514 request.method === "pause"
515 ? "paused"
516 : request.method === "resume"
517 ? "running"
518 : request.method === "stop"
519 ? "stopped"
520 : "retrying"
521 runs[index] = {
522 ...runs[index],
523 state: nextState,
524 updatedAt: new Date().toISOString(),
525 }
526 saveRuns(runs)
527 respond(request.id, generation, true, { run: detail(runs[index]) })
528 continue
529 }
530 if (request.method === "handoff") {
531 const runs = loadRuns()
532 const index = runs.findIndex((row) => row.runRef === request.params?.runRef)
533 if (index < 0) {
534 respond(request.id, generation, false, undefined, {
535 code: "run_not_found",
536 message: "No Full Auto run exists for that runRef.",
537 })
538 continue
539 }
540 if (runs[index].state !== "paused") {
541 respond(request.id, generation, false, undefined, {
542 code: "invalid_request",
543 message: "A provider handoff is legal only while paused.",
544 })
545 continue
546 }
547 const targetLaneRef = request.params?.targetLaneRef
548 if (!["codex-local", "claude-local"].includes(targetLaneRef)) {
549 respond(request.id, generation, false, undefined, {
550 code: "invalid_request",
551 message: "That provider lane is not registered.",
552 })
553 continue
554 }
555 runs[index] = {
556 ...runs[index],
557 lane: targetLaneRef,
558 updatedAt: new Date().toISOString(),
559 }
560 saveRuns(runs)
561 respond(request.id, generation, true, {
562 run: detail(runs[index]),
563 transition: {
564 from: targetLaneRef === "claude-local" ? "codex-local" : "claude-local",
565 to: targetLaneRef,
566 disposition: "complete_within_bounds",
567 },
568 })
569 continue
570 }
571 if (request.method === "get_capacity") {
572 respond(request.id, generation, true, {
573 activeRunLimit: 8,
574 activeRunCount: listRuns().filter((run) =>
575 ["running", "pausing", "paused", "retrying", "stalled"].includes(run.state),
576 ).length,
577 lanes: [
578 { lane: "codex-local", state: "available", activeRuns: 0, reason: "ready and idle" },
579 { lane: "claude-local", state: "available", activeRuns: 0, reason: "ready and idle" },
580 ],
581 accounts: [
582 { accountRef: "account.codex.fixture", provider: "openai", label: "ChatGPT fixture", state: "ready", quotaState: "available", lane: "codex-local" },
583 { accountRef: "account.claude.fixture", provider: "anthropic", label: "Claude fixture", state: "ready", quotaState: "available", lane: "claude-local" },
584 ],
585 nonOverridableGuardrails: [
586 "workspace_binding",
587 "own_capacity_only",
588 "no_rate_limit_reset_triggering",
589 ],
590 ownerConfigurableGuardrails: [
591 "maxWallClockMs",
592 "maxTurns",
593 "maxPerTurnFailures",
594 "tokenBudgetRef",
595 ],
596 enabledThreadsNeverEvicted: true,
597 })
598 continue
599 }
600 if (request.method === "decide_attention") {
601 const run = loadRuns().find((row) => row.runRef === request.params?.runRef)
602 if (!run) {
603 respond(request.id, generation, false, undefined, {
604 code: "run_not_found",
605 message: "No Full Auto run exists for that runRef.",
606 })
607 continue
608 }
609 const state = run.state
610 if (state !== "stalled" && state !== "retrying") {
611 respond(request.id, generation, true, { attention: null })
612 continue
613 }
614 const dedupKey = `${run.runRef}:${state}:${run.stallCause ?? "none"}`
615 if (request.params?.previousDedupKey === dedupKey) {
616 respond(request.id, generation, true, { attention: null })
617 continue
618 }
619 respond(request.id, generation, true, {
620 attention: {
621 notify: request.params?.permissionGranted === true,
622 dedupKey,
623 title: `Full Auto ${state}`,
624 body: `${run.title} needs attention (${state}).`,
625 },
626 })
627 continue
628 }
629 if (request.method === "get_report") {
630 const run = loadRuns().find((row) => row.runRef === request.params?.runRef)
631 if (!run) {
632 respond(request.id, generation, false, undefined, {
633 code: "run_not_found",
634 message: "No Full Auto run exists for that runRef.",
635 })
636 continue
637 }
638 respond(request.id, generation, true, {
639 report: {
640 schema: "openagents.desktop.full_auto_run_report.v1",
641 runRef: run.runRef,
642 title: run.title,
643 objective: run.objective,
644 doneCondition: run.doneCondition,
645 state: run.state,
646 turns: run.turns ?? [],
647 evidence: {
648 objectiveRef: `objective.${run.runRef}`,
649 turnRef: `turn.${run.runRef}.latest`,
650 changeRef: `change.${run.runRef}.latest`,
651 projectGeneration: "project.generation.fixture.1",
652 diffSummary: "2 files changed, 18 insertions, 3 deletions",
653 testCommand: "cargo test -p full_auto_ui",
654 testOutcome: "passed",
655 verificationRef: `verification.host.${run.runRef}.latest`,
656 hostExecuted: true,
657 },
658 },
659 })
660 continue
661 }
662 if (request.method === "get_receipt") {
663 const run = loadRuns().find((row) => row.runRef === request.params?.runRef)
664 if (!run) {
665 respond(request.id, generation, false, undefined, {
666 code: "run_not_found",
667 message: "No Full Auto run exists for that runRef.",
668 })
669 continue
670 }
671 respond(request.id, generation, true, {
672 receipt: {
673 schema: "openagents.desktop.full_auto_run_receipt.v1",
674 runRef: run.runRef,
675 objectiveDigest: "fixture-objective-digest",
676 doneConditionDigest: "fixture-done-digest",
677 objectiveRevisionCount: 1,
678 turnCount: (run.turns ?? []).length,
679 state: run.state,
680 objectiveRef: `objective.${run.runRef}`,
681 turnRef: `turn.${run.runRef}.latest`,
682 changeRef: `change.${run.runRef}.latest`,
683 verificationRef: `verification.host.${run.runRef}.latest`,
684 authorityReceiptRef: `receipt.authority.${run.runRef}.latest`,
685 decisionRef: `decision.authority.${run.runRef}.latest`,
686 allowed: true,
687 },
688 })
689 continue
690 }
691 if (request.method === "apply_control_intent") {
692 const params = request.params ?? {}
693 if (!params.intentId || !params.runRef || !["pause", "resume", "stop"].includes(params.action)) {
694 respond(request.id, generation, false, undefined, {
695 code: "invalid_request",
696 message: "apply_control_intent requires intentId, runRef, and action pause|resume|stop.",
697 })
698 continue
699 }
700 const runs = loadRuns()
701 const index = runs.findIndex((row) => row.runRef === params.runRef)
702 if (index < 0) {
703 respond(request.id, generation, true, {
704 outcome: {
705 intentId: params.intentId,
706 status: "rejected",
707 rejectionReason: "run_not_found",
708 },
709 })
710 continue
711 }
712 const nextState =
713 params.action === "pause" ? "paused" : params.action === "resume" ? "running" : "stopped"
714 runs[index] = { ...runs[index], state: nextState, updatedAt: new Date().toISOString() }
715 saveRuns(runs)
716 respond(request.id, generation, true, {
717 outcome: {
718 intentId: params.intentId,
719 status: "applied",
720 resultLifecycleState: nextState,
721 },
722 })
723 continue
724 }
725 if (request.method === "get_sync_status") {
726 respond(request.id, generation, true, {
727 available: false,
728 publishBlocksDispatch: false,
729 reason: "omega_khala_sync_session_unavailable",
730 })
731 continue
732 }
733 if (request.method === "publish_projection") {
734 respond(request.id, generation, true, {
735 ok: false,
736 status: "sync_unavailable",
737 reason: "omega_khala_sync_session_unavailable",
738 })
739 continue
740 }
741 if (request.method === "get_native_binding") {
742 const run = loadRuns().find((row) => row.runRef === request.params?.runRef)
743 if (!run) {
744 respond(request.id, generation, false, undefined, {
745 code: "run_not_found",
746 message: "No Full Auto run exists for that runRef.",
747 })
748 continue
749 }
750 const binding = loadBindings().find((row) => row.runRef === run.runRef) ?? null
751 respond(request.id, generation, true, { binding })
752 continue
753 }
754 if (request.method === "assess_native_boundary") {
755 const run = loadRuns().find((row) => row.runRef === request.params?.runRef)
756 if (!run) {
757 respond(request.id, generation, false, undefined, {
758 code: "run_not_found",
759 message: "No Full Auto run exists for that runRef.",
760 })
761 continue
762 }
763 const binding = loadBindings().find((row) => row.runRef === run.runRef) ?? null
764 if (!binding) {
765 respond(request.id, generation, true, {
766 assessment: {
767 ok: false,
768 reason: "missing_binding",
769 message: "No native project/worktree binding exists for this Full Auto run.",
770 },
771 })
772 continue
773 }
774 if (binding.workspaceRef !== run.workspaceRef) {
775 respond(request.id, generation, true, {
776 assessment: {
777 ok: false,
778 reason: "workspace_mismatch",
779 message: "The bound workspace does not match the currently resolved workspace.",
780 },
781 })
782 continue
783 }
784 if (binding.rebaseUnsafe) {
785 respond(request.id, generation, true, {
786 assessment: {
787 ok: false,
788 reason: "rebase_unsafe",
789 message: "The bound worktree is rebase-unsafe; Full Auto refuses to continue.",
790 },
791 })
792 continue
793 }
794 respond(request.id, generation, true, {
795 assessment: {
796 ok: true,
797 evidence: {
798 projectRef: binding.projectRef,
799 worktreeRef: binding.worktreeRef,
800 worktreePathDigest: binding.worktreePathDigest ?? null,
801 gitHead: binding.gitHead ?? null,
802 },
803 },
804 })
805 continue
806 }
807 if (request.method === "start_agent_computer_session") {
808 const params = request.params ?? {}
809 if (
810 typeof params.bearerToken !== "string" ||
811 typeof params.controlPlaneBaseUrl !== "string" ||
812 typeof params.repoRef !== "string" ||
813 typeof params.objective !== "string"
814 ) {
815 respond(request.id, generation, false, undefined, {
816 code: "invalid_request",
817 message:
818 "start_agent_computer_session requires bearerToken, controlPlaneBaseUrl, repoRef, and objective.",
819 })
820 continue
821 }
822 const sessions = loadAgentComputerSessions()
823 const session = projectAgentComputerSession(params, "queued")
824 sessions.push(session)
825 saveAgentComputerSessions(sessions)
826 respond(request.id, generation, true, { session })
827 continue
828 }
829 if (request.method === "refresh_agent_computer_session") {
830 const params = request.params ?? {}
831 const sessions = loadAgentComputerSessions()
832 const index = sessions.findIndex((row) => row.sessionRef === params.sessionRef)
833 if (index === -1) {
834 respond(request.id, generation, false, undefined, {
835 code: "invalid_request",
836 message: "No Agent Computer session exists for that sessionRef.",
837 })
838 continue
839 }
840 const next = {
841 ...sessions[index],
842 state: "running",
843 updatedAt: new Date().toISOString(),
844 }
845 sessions[index] = next
846 saveAgentComputerSessions(sessions)
847 respond(request.id, generation, true, { session: next })
848 continue
849 }
850 if (request.method === "run_agent_computer_turn") {
851 const params = request.params ?? {}
852 if (
853 typeof params.bearerToken !== "string" ||
854 typeof params.controlPlaneBaseUrl !== "string" ||
855 typeof params.repoRef !== "string" ||
856 typeof params.objective !== "string"
857 ) {
858 respond(request.id, generation, false, undefined, {
859 code: "invalid_request",
860 message:
861 "run_agent_computer_turn requires bearerToken, controlPlaneBaseUrl, repoRef, and objective.",
862 })
863 continue
864 }
865 const sessions = loadAgentComputerSessions()
866 const session = projectAgentComputerSession(params, "completed")
867 sessions.push(session)
868 saveAgentComputerSessions(sessions)
869 respond(request.id, generation, true, {
870 session,
871 finishReason: "stop",
872 eventKinds: ["turn.started", "text.delta", "turn.finished"],
873 })
874 continue
875 }
876 if (request.method === "get_agent_computer_session") {
877 const session =
878 loadAgentComputerSessions().find((row) => row.sessionRef === request.params?.sessionRef) ??
879 null
880 respond(request.id, generation, true, { session })
881 continue
882 }
883 if (request.method === "list_agent_computer_sessions") {
884 respond(request.id, generation, true, { sessions: loadAgentComputerSessions() })
885 continue
886 }
887 // SARAH-NR-06: Nostr conversation methods (mock transport; no Khala Sync).
888 if (request.method === "sarah_session_status") {
889 respond(request.id, generation, true, sarahSessionStatus())
890 continue
891 }
892 if (request.method === "sarah_bootstrap") {
893 respond(request.id, generation, true, sarahBootstrap())
894 continue
895 }
896 if (request.method === "sarah_room_snapshot") {
897 respond(request.id, generation, true, sarahRoomSnapshot(request.params ?? {}))
898 continue
899 }
900 if (request.method === "sarah_send_message") {
901 const text = request.params?.text
902 if (typeof text !== "string" || text.trim().length === 0) {
903 respond(request.id, generation, false, undefined, {
904 code: "invalid_request",
905 message: "sarah_send_message requires text.",
906 })
907 continue
908 }
909 if (/bearer\s|sk-|authorization:/i.test(text)) {
910 respond(request.id, generation, false, undefined, {
911 code: "invalid_request",
912 message: "message must not carry raw credentials.",
913 })
914 continue
915 }
916 respond(request.id, generation, true, sarahSendMessage(text))
917 continue
918 }
919 if (request.method === "sarah_interrupt_turn") {
920 const turnRef = request.params?.turnRef
921 if (typeof turnRef !== "string" || turnRef.trim().length === 0) {
922 respond(request.id, generation, false, undefined, {
923 code: "invalid_request",
924 message: "sarah_interrupt_turn requires turnRef.",
925 })
926 continue
927 }
928 respond(request.id, generation, true, sarahInterruptTurn(turnRef))
929 continue
930 }
931 respond(request.id, generation, false, undefined, {
932 code: "unknown_method",
933 message: `Unknown method ${request.method}.`,
934 })
935}
936