/** * `agent-coord` CLI entry point. Phase 1: every subcommand no-ops with a * structured debug log. The one exception is `verdict`, which replies * fail-open so adapters can already wire it up without affecting flow. * * Phase 2 replaces the no-op branches with real state projection + CLI * handlers; Phase 4 flips the default so `harn agents …` shims through here. */ import { createHash } from "node:crypto"; import { appendFileSync, existsSync } from "node:fs"; import { appendFile, mkdir } from "node:fs/promises"; import { hostname } from "node:os"; import { dirname, join, resolve } from "node:path"; import { coordEnv } from "../../lib/env.ts"; import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.ts"; import { acquireNoClobberLease } from "../workflow/workspaces/leases.ts"; function sharedDiagnostic( root: string, event: string, fields: Record, error?: unknown, ): boolean { if (coordEnv("SHARED_LOGS") === "0") return false; try { const logger = processLogger(root, "agent-coord"); if (error === undefined) logger.debug(event, legacyLogFields(fields)); else logger.error(event, legacyLogFields(fields), error); return true; } catch { return false; } } function findCoordRoot(start: string): string | null { // HARNERY_COORD_ROOT_OVERRIDE: the bash side's test-mode escape hatch. agent-coord // honors the same env so sandboxed test runs don't get derailed when cwd // doesn't contain a .harnery/ tree. Phase 8: dropped the `.harnery/` existence // precondition so test fixtures that haven't bootstrapped the dir yet still // resolve. const override = coordEnv("COORD_ROOT_OVERRIDE"); if (override) return override; let dir = resolve(start); while (true) { if (existsSync(join(dir, ".harnery"))) return dir; const parent = dirname(dir); if (parent === dir) return null; dir = parent; } } async function readStdin(): Promise { if (process.stdin.isTTY) return ""; const chunks: Uint8Array[] = []; for await (const chunk of process.stdin) { chunks.push(chunk as Uint8Array); } return Buffer.concat(chunks).toString("utf8"); } async function logNoop(root: string, subcommand: string, argv: string[]): Promise { const entry = { ts: new Date().toISOString(), note: "called, no-op", subcommand, extra_argv: argv, cwd: process.cwd(), pid: process.pid, ppid: process.ppid, }; if (sharedDiagnostic(root, "agent_coord.noop", entry)) return; const logPath = join(root, ".harnery", "debug", "agent-coord.ndjson"); await mkdir(dirname(logPath), { recursive: true }); await appendFile(logPath, `${JSON.stringify(entry)}\n`, "utf8"); } /** * Verdict endpoint. Reads a JSON request from stdin, dispatches to the * matching rule evaluator, writes a JSON verdict to stdout. Exit code is * 0 regardless; the caller branches on the JSON's `exit_code` field so * fail-open semantics survive a malformed-request bug here. * * The Stop and PreToolUse hooks route here. */ async function handleVerdict(root: string): Promise { const raw = await readStdin(); let parsed: { rule?: string } & Record = {}; let parseErr: string | null = null; try { if (raw.trim().length > 0) { parsed = JSON.parse(raw) as { rule?: string } & Record; } } catch (err) { parseErr = err instanceof Error ? err.message : String(err); } let verdict: { allow: boolean; exit_code: number; rule: string; reason?: string; }; if (parseErr) { verdict = { allow: true, exit_code: 0, rule: "verdict.bad_request", reason: `invalid JSON: ${parseErr} (fail-open)`, }; } else if (parsed.rule === "stop-hook") { const { evaluateStopHook } = await import("./rules/stop-hook.ts"); verdict = evaluateStopHook(root, parsed as unknown as Parameters[1]); } else if (parsed.rule === "claim") { const { evaluateClaim } = await import("./rules/claim-conflict.ts"); verdict = evaluateClaim(root, parsed as unknown as Parameters[1]); } else { // NB: rule === "commit" was served here until 2026-08-09; the commit // guard now enters through `git-hook pre-commit`, which runs the same // evaluateCommit in-process. A straggler host lands in this fail-open // branch, which is the pre-migration behavior for a malformed request. verdict = { allow: true, exit_code: 0, rule: "verdict.unknown_rule", reason: `no evaluator for rule=${parsed.rule ?? ""} (fail-open)`, }; } const diagnostic = { request_preview: raw.slice(0, 500), verdict }; if (!sharedDiagnostic(root, "agent_coord.verdict", diagnostic)) { const logPath = join(root, ".harnery", "debug", "agent-coord-verdict.ndjson"); await mkdir(dirname(logPath), { recursive: true }); await appendFile( logPath, `${JSON.stringify({ ts: new Date().toISOString(), ...diagnostic })}\n`, "utf8", ); } process.stdout.write(`${JSON.stringify(verdict)}\n`); return 0; } async function handleProject(root: string, rest: string[]): Promise { const { resolveLiveEventLedgerRouteV3 } = await import("../events/v3/live-routing.ts"); const route = resolveLiveEventLedgerRouteV3(root); if (route.state === "blocked") { process.stderr.write(`agent-coord project: V3 route is unsafe (${route.reason})\n`); return 1; } const { readCoordinationViewV3 } = await import("../events/v3/coordination-view.ts"); const view = readCoordinationViewV3(root); const report = { contract_major: 2, source_complete: view.source_complete, authority_safe: view.authority_safe, owners_projected: Object.keys(view.instances).length, owners: Object.keys(view.instances).sort(), diagnostics: view.diagnostics, materialized: false, }; process.stdout.write(`${JSON.stringify(report, null, rest.includes("--json") ? 2 : 0)}\n`); return view.authority_safe ? 0 : 1; } function adapterFromPlatform(platform: unknown): "claude-code" | "cursor" | "codex" { if (platform === "cursor") return "cursor"; if (platform === "codex") return "codex"; return "claude-code"; } const coordinationRetryCell = new Int32Array(new SharedArrayBuffer(4)); const COORDINATION_RETRY_ATTEMPTS = 240; const COORDINATION_RETRY_DELAY_MS = 25; function isRetryableCoordinationContention(error: unknown): boolean { return ( error instanceof Error && error.message.includes( "lease event-v3-coordination-producer is held by a live or unexpired owner", ) ); } function waitForCoordinationLease(): void { Atomics.wait(coordinationRetryCell, 0, 0, COORDINATION_RETRY_DELAY_MS); } function pidIsAlive(pid: number): boolean { if (!Number.isSafeInteger(pid) || pid < 1) return false; try { process.kill(pid, 0); return true; } catch (error) { return (error as NodeJS.ErrnoException).code !== "ESRCH"; } } // The V3 producer lease begins after its caller has materialized and read the // disposable heartbeat. Serialize that larger registration boundary per owner // so overlapping first declarations cannot both derive state from an unnamed, // missing heartbeat and then strand a conflicting authority transaction. function acquireSetTaskLease(root: string, owner: string) { const leasePath = join(root, ".harnery", "active", ".set-task-leases", `${owner}.lease`); const authoritySha256 = createHash("sha256") .update(resolve(root)) .update("\0") .update(owner) .digest("hex"); for (let attempt = 0; ; attempt += 1) { try { return acquireNoClobberLease({ path: leasePath, scope: "agent-set-task", authoritySha256, staleAfterMs: 5_000, validateStaleOwner: (leaseOwner) => leaseOwner.host === hostname() && !pidIsAlive(leaseOwner.pid), }); } catch (error) { const busy = error instanceof Error && error.message.includes("lease agent-set-task is held by a live or unexpired owner"); if (!busy || attempt >= COORDINATION_RETRY_ATTEMPTS - 1) throw error; waitForCoordinationLease(); } } } async function handleStateAction(root: string, action: string, rest: string[]): Promise { const writer = await import("./state/heartbeat-writer.ts"); const [owner, ...args] = rest; if (!owner) { process.stderr.write(`agent-coord ${action}: missing \n`); return 2; } switch (action) { case "set-task": { const task = args.join(" "); let setTaskLease: ReturnType; try { setTaskLease = acquireSetTaskLease(root, owner); } catch (error) { process.stderr.write( `agent-coord set-task: registration lease refused (${error instanceof Error ? error.message : String(error)})\n`, ); return 1; } try { let before = writer.readHeartbeat(root, owner); const humanFacing = before?.kind !== "subagent" && before?.kind !== "transient" && !before?.workflow_run_id; // A mid-flight-onboarded generation can exist before SessionStart's // assign-name step ran. Repair that private display metadata before the // first non-empty task mints its operator-facing title. assignName is the // same durable, idempotent pool path used by normal SessionStart. if (task && before && humanFacing && !before.name?.trim()) { const { assignName } = await import("./state/names.ts"); const { coordFreshnessSeconds } = await import("../config.ts"); const name = assignName(root, owner, "session", { freshnessSecs: coordFreshnessSeconds(root), }); before = writer.setAssignedNameCache(root, owner, name, "session"); if (!before) { process.stderr.write( `agent-coord set-task: could not restore assigned name for ${owner}\n`, ); return 1; } } let hb: ReturnType; try { const { recordLiveTaskChangeV3 } = await import("./live-authority-v3.ts"); for (let attempt = 0; ; attempt += 1) { try { recordLiveTaskChangeV3({ coordRoot: root, owner, nativeSessionId: before?.session_id ?? owner, adapter: adapterFromPlatform(before?.platform), task, }); break; } catch (error) { if ( !isRetryableCoordinationContention(error) || attempt >= COORDINATION_RETRY_ATTEMPTS - 1 ) { throw error; } waitForCoordinationLease(); } } hb = writer.readHeartbeat(root, owner); const currentHumanFacing = hb?.kind !== "subagent" && hb?.kind !== "transient" && !hb?.workflow_run_id; if ( task && hb && currentHumanFacing && (!hb.name?.trim() || /^Agent unknown - /.test(hb.suggested_session_name ?? "")) ) { const { assignName } = await import("./state/names.ts"); const { coordFreshnessSeconds } = await import("../config.ts"); const name = hb.name?.trim() || assignName(root, owner, "session", { freshnessSecs: coordFreshnessSeconds(root) }); hb = writer.setAssignedNameCache(root, owner, name, "session"); } } catch (error) { process.stderr.write( `agent-coord set-task: V3 authority refused (${error instanceof Error ? error.message : String(error)})\n`, ); return 1; } if (!hb) { // Name the RESOLVED root: when a nested .harnery/ shadows the real // coordination home, the full path is what makes that diagnosable. process.stderr.write( `agent-coord set-task: no heartbeat at ${root}/.harnery/active/${owner}.json\n`, ); return 1; } process.stdout.write( `${JSON.stringify({ instance_id: owner, task: hb.task ?? null, cleared: !task })}\n`, ); return 0; } finally { setTaskLease.release(); } } case "release-claim": { const path = args[0]; if (!path) { process.stderr.write("agent-coord release-claim: missing \n"); return 2; } const before = writer.readHeartbeat(root, owner); let hb: ReturnType; try { const { recordLiveClaimChangeV3 } = await import("./live-authority-v3.ts"); recordLiveClaimChangeV3({ coordRoot: root, owner, nativeSessionId: before?.session_id ?? owner, adapter: adapterFromPlatform(before?.platform), operation: "released", path, access: "write", }); hb = writer.readHeartbeat(root, owner); } catch (error) { process.stderr.write( `agent-coord release-claim: V3 authority refused (${error instanceof Error ? error.message : String(error)})\n`, ); return 1; } if (!hb) return 1; process.stdout.write( `${JSON.stringify({ instance_id: owner, files_touched: hb.files_touched })}\n`, ); return 0; } case "heal-pidmap": { const pidArg = args[0]; const pid = pidArg ? Number(pidArg) : process.ppid; if (!Number.isFinite(pid)) { process.stderr.write(`agent-coord heal-pidmap: invalid pid ${pidArg}\n`); return 2; } try { const { liveCoordinationWriteModeV3 } = await import("./live-authority-v3.ts"); liveCoordinationWriteModeV3(root); writer.healPidmap(root, owner, pid); } catch (error) { process.stderr.write( `agent-coord heal-pidmap: V3 route refused (${error instanceof Error ? error.message : String(error)})\n`, ); return 1; } process.stdout.write(`${JSON.stringify({ instance_id: owner, pid })}\n`); return 0; } case "repair-coordination-cache": { // adapter arrives as a `--adapter=` flag (not positional) so the live // tool.requested repair and the manual `harn agents heal` path (which pass // different positional counts) can both supply it without arg-order // fragility. Positionals (sessionId, model) stay as-is once flags are // filtered out. const adapter = args.find((a) => a.startsWith("--adapter="))?.slice("--adapter=".length); const positional = args.filter((a) => !a.startsWith("--")); const sessionId = positional[0]; const model = positional[1]; let hb: import("./state/heartbeat-writer.ts").Heartbeat | null; try { const { liveCoordinationWriteModeV3 } = await import("./live-authority-v3.ts"); liveCoordinationWriteModeV3(root); const { readCoordinationViewV3 } = await import("../events/v3/coordination-view.ts"); const { liveInstanceIdV3 } = await import("../events/v3/live-routing.ts"); const projected = readCoordinationViewV3(root).instances[liveInstanceIdV3(owner)]; if (projected?.provisional_termination) { const { recordLiveResumeObservationV3 } = await import("./live-lifecycle-v3.ts"); recordLiveResumeObservationV3({ coordRoot: root, owner, nativeSessionId: sessionId ?? owner, adapter: adapterFromPlatform(adapter), }); } const { repairLiveCoordinationHeartbeat } = await import( "./state/live-coordination-writer.ts" ); hb = repairLiveCoordinationHeartbeat( root, owner, sessionId ?? owner, adapterFromPlatform(adapter), model, ); } catch (error) { process.stderr.write( `agent-coord repair-coordination-cache: V3 route refused (${error instanceof Error ? error.message : String(error)})\n`, ); return 1; } process.stdout.write(`${JSON.stringify({ instance_id: owner, recreated: !!hb })}\n`); return hb ? 0 : 1; } case "quarantine-authority-transaction": { const adapter = args.find((a) => a.startsWith("--adapter="))?.slice("--adapter=".length); const positional = args.filter((a) => !a.startsWith("--")); const [transactionId, approvalRecordId, sessionId] = positional; if (!transactionId || !approvalRecordId) { process.stderr.write( "agent-coord quarantine-authority-transaction: missing or \n", ); return 2; } try { const { coordinationAuthorityStateDigestV3, liveCoordinationWriteModeV3 } = await import( "./live-authority-v3.ts" ); liveCoordinationWriteModeV3(root); const { liveInstanceIdV3 } = await import("../events/v3/live-routing.ts"); const { repairLiveCoordinationHeartbeat } = await import( "./state/live-coordination-writer.ts" ); const heartbeat = repairLiveCoordinationHeartbeat( root, owner, sessionId ?? owner, adapterFromPlatform(adapter), ); if (!heartbeat) { throw new Error("authoritative coordination cache could not be materialized"); } const { quarantineConflictingCoordinationTransactionV3 } = await import( "../events/v3/coordination-transaction-recovery.ts" ); const receipt = quarantineConflictingCoordinationTransactionV3(root, { transaction_id: transactionId, actor_instance_id: liveInstanceIdV3(owner), observed_current_state_digest: coordinationAuthorityStateDigestV3(heartbeat), approval_record_id: approvalRecordId, }); const repaired = repairLiveCoordinationHeartbeat( root, owner, sessionId ?? owner, adapterFromPlatform(adapter), ); process.stdout.write( `${JSON.stringify({ instance_id: owner, receipt, heartbeat: repaired ? { task_state: repaired.task_state, files_touched: repaired.files_touched } : null, })}\n`, ); return repaired ? 0 : 1; } catch (error) { process.stderr.write( `agent-coord quarantine-authority-transaction: recovery refused (${error instanceof Error ? error.message : String(error)})\n`, ); return 1; } } default: process.stderr.write(`agent-coord: unknown state action ${action}\n`); return 2; } } async function handleJournalAction(root: string, action: string, rest: string[]): Promise { const journal = await import("./state/journal.ts"); if (action === "append-journal") { const [owner, category, ...bodyParts] = rest; const body = bodyParts.join(" "); if (!owner || !category || !body) { process.stderr.write("agent-coord append-journal \n"); return 2; } const result = journal.appendJournal(root, owner, category, body); if (!result.ok) { process.stderr.write(`agent-coord append-journal: ${result.reason}\n`); return 1; } process.stdout.write( `${JSON.stringify({ instance_id: owner, category, path: result.path })}\n`, ); return 0; } if (action === "edit-journal") { const [owner, newBodyFile, ...summaryParts] = rest; const summary = summaryParts.join(" "); if (!owner || !newBodyFile) { process.stderr.write("agent-coord edit-journal []\n"); return 2; } if (!existsSync(newBodyFile)) { process.stderr.write(`agent-coord edit-journal: file not found: ${newBodyFile}\n`); return 2; } const { readFileSync } = await import("node:fs"); const newBody = readFileSync(newBodyFile, "utf8"); const result = journal.editJournal(root, owner, newBody, summary); if (!result.ok) { process.stderr.write(`agent-coord edit-journal: ${result.reason}\n`); return 1; } process.stdout.write( `${JSON.stringify({ instance_id: owner, path: result.path, archive_path: result.archivePath })}\n`, ); return 0; } process.stderr.write(`agent-coord: unknown journal action ${action}\n`); return 2; } async function handleCouncilAction(root: string, action: string, rest: string[]): Promise { const council = await import("./state/council.ts"); const [councilId, ...args] = rest; if (!councilId) { process.stderr.write(`agent-coord ${action}: missing \n`); return 2; } switch (action) { case "council-advance": { const force = args.includes("--force"); const result = council.advanceCouncil(root, councilId, { force }); if (!result.ok) { process.stderr.write(`agent-coord council-advance: ${result.reason}\n`); return 1; } process.stdout.write(`${JSON.stringify({ council_id: councilId, ok: true })}\n`); return 0; } case "council-close": { const result = council.closeCouncil(root, councilId); if (!result.ok) { process.stderr.write(`agent-coord council-close: ${result.reason}\n`); return 1; } process.stdout.write(`${JSON.stringify({ council_id: councilId, ok: true })}\n`); return 0; } case "council-archive": { const result = council.archiveCouncil(root, councilId); if (!result.ok) { process.stderr.write(`agent-coord council-archive: ${result.reason}\n`); return 1; } process.stdout.write(`${JSON.stringify({ council_id: councilId, ok: true })}\n`); return 0; } case "council-unarchive": { const result = council.unarchiveCouncil(root, councilId); if (!result.ok) { process.stderr.write(`agent-coord council-unarchive: ${result.reason}\n`); return 1; } process.stdout.write(`${JSON.stringify({ council_id: councilId, ok: true })}\n`); return 0; } case "council-delete": { const result = council.deleteCouncil(root, councilId); if (!result.ok) { process.stderr.write(`agent-coord council-delete: ${result.reason}\n`); return 1; } process.stdout.write(`${JSON.stringify({ council_id: councilId, ok: true })}\n`); return 0; } case "council-set-steward": { const steward = args[0] ?? ""; const stewardId = args[1] ?? ""; const result = council.setCouncilSteward(root, councilId, steward, stewardId); if (!result.ok) { process.stderr.write(`agent-coord council-set-steward: ${result.reason}\n`); return 1; } process.stdout.write( `${JSON.stringify({ council_id: councilId, steward: steward || null, ok: true })}\n`, ); return 0; } } process.stderr.write(`agent-coord: unknown council action ${action}\n`); return 2; } async function handleAssignName(root: string, rest: string[]): Promise { const { assignName } = await import("./state/names.ts"); // Optional recorded-fork-lineage flag: --forked-from . // Supplied by an adapter layer that knows (or detected) that this session // was branched from another conversation. Inert on resume: assignName only // stamps lineage on the row that first assigns the instance. let forkedFrom: string | undefined; const positional: string[] = []; for (let i = 0; i < rest.length; i++) { if (rest[i] === "--forked-from") { forkedFrom = rest[++i]; continue; } positional.push(rest[i]!); } const [owner, kindArg] = positional; if (!owner || !kindArg) { process.stderr.write( "agent-coord assign-name [--forked-from ]\n", ); return 2; } if (kindArg !== "session" && kindArg !== "subagent" && kindArg !== "transient") { process.stderr.write(`agent-coord assign-name: invalid kind ${kindArg}\n`); return 2; } const { coordFreshnessSeconds } = await import("../config.ts"); const name = assignName(root, owner, kindArg, { freshnessSecs: coordFreshnessSeconds(root), ...(forkedFrom ? { forkedFrom } : {}), }); process.stdout.write( `${JSON.stringify({ instance_id: owner, name, kind: kindArg, ...(forkedFrom ? { forked_from: forkedFrom } : {}), })}\n`, ); return 0; } async function handleShellMutationPaths(root: string, rest: string[]): Promise { const { shellMutationPaths } = await import("./state/shell-mutation.ts"); // --cmd "" form; falls back to stdin if --cmd not supplied let cmd: string | undefined; for (let i = 0; i < rest.length; i++) { const a = rest[i]!; if (a === "--cmd") { cmd = rest[i + 1]; i++; } } if (cmd === undefined) cmd = await readStdin(); const paths = shellMutationPaths(cmd, root); for (const p of paths) process.stdout.write(`${p}\n`); return 0; } async function handleShellMutationClaimLog(root: string, rest: string[]): Promise { // Parse + log in one spawn, avoids per-line process spawn from the bash loop. // Usage: // agent-coord shell-mutation-claim-log --cmd "" --owner --platform

const args: Record = {}; for (let i = 0; i < rest.length; i++) { const a = rest[i]!; if (a.startsWith("--")) { const key = a.slice(2); const val = rest[i + 1]; if (val === undefined || val.startsWith("--")) { args[key] = "true"; } else { args[key] = val; i++; } } } const cmd = args.cmd ?? ""; if (!cmd) return 0; const platform = args.platform ?? "unknown"; const owner = args.owner ?? null; const { shellMutationPaths } = await import("./state/shell-mutation.ts"); const paths = shellMutationPaths(cmd, root); const truncated = cmd.length > 80 ? cmd.slice(0, 80) : cmd; process.stdout.write( `${JSON.stringify({ schema_version: 2, owner, platform, command_preview: truncated, paths })}\n`, ); return 0; } async function handleStaleSweep(root: string, _rest: string[]): Promise { const { staleSweep } = await import("./state/stale-sweep.ts"); const result = staleSweep(root); process.stdout.write(`${JSON.stringify(result)}\n`); return 0; } async function handleReconcileFinalization(root: string): Promise { // Shares the supervisor composition with `agents reconcile` so session start // sweeps the stale cache in the same pass, as ADR 0077 specified. const { reconcileCoordinationV3 } = await import("./reconcile-coordination-v3.ts"); const result = reconcileCoordinationV3(root); process.stdout.write(`${JSON.stringify(result)}\n`); return result.diagnostics.some((item) => item === "ledger_not_authority_safe") ? 2 : 0; } async function handleEndSession(root: string, rest: string[]): Promise { const instanceId = rest[0]; if (!instanceId || !/^inst_[A-Za-z0-9._-]+$/.test(instanceId)) return 2; const { listHookProducerStateRecordsV3 } = await import("../events/v3/producers/recorder.ts"); const record = listHookProducerStateRecordsV3(root, { includeTerminal: false }).find( ({ state }) => state.instance_id === instanceId, ); if (!record) return 2; const { requestSessionEndExplicitV3 } = await import("./session-finalizer-v3.ts"); const result = requestSessionEndExplicitV3({ coordRoot: root, instance_id: record.state.instance_id, generation_id: record.state.generation_id, outcome: "interrupted", coordination_finalized: false, }); process.stdout.write(`${JSON.stringify(result)}\n`); return result.state === "recorded" || result.state === "already_ended" || result.state === "queued" || result.state === "already_requested" ? 0 : result.state === "delegated_work_open" ? 3 : 2; } async function handlePromptContext(root: string, rest: string[]): Promise { const args: Record = {}; for (let i = 0; i < rest.length; i++) { const a = rest[i]!; if (a.startsWith("--")) { const key = a.slice(2); const val = rest[i + 1]; if (val === undefined || val.startsWith("--")) { args[key] = "true"; } else { args[key] = val; i++; } } } const instanceId = args.instance; const sessionId = args.session ?? instanceId; const agentName = args.name; const sessionNameNudge = args["session-name-nudge"] === "true"; const taskNudge = args["task-nudge"] === "true"; const hostPromptReminder = args["host-prompt-reminder"] === "true"; const statusFooterNudge = args["status-footer-nudge"] === "true"; // Value is the adapter id; a bare flag (parsed as "true") still enables the // reminder with the adapter-neutral wording. const turnRitualNudge = args["turn-ritual-nudge"] === "true" ? "generic" : args["turn-ritual-nudge"]; if (!instanceId) { process.stderr.write( "agent-coord prompt-context --instance [--session ] [--name ] [--session-name-nudge] [--task-nudge] [--host-prompt-reminder] [--status-footer-nudge] [--turn-ritual-nudge ]\n", ); return 2; } const { renderPromptContext } = await import("./render/prompt-context.ts"); const text = renderPromptContext({ coordRoot: root, instanceId, sessionId: sessionId!, agentName, sessionNameNudge, taskNudge, hostPromptReminder, statusFooterNudge, turnRitualNudge, }); process.stdout.write(text); return 0; } async function handleSessionContext(root: string, rest: string[]): Promise { const args: Record = {}; for (let i = 0; i < rest.length; i++) { const a = rest[i]!; if (a.startsWith("--")) { const key = a.slice(2); const val = rest[i + 1]; if (val === undefined || val.startsWith("--")) { args[key] = "true"; } else { args[key] = val; i++; } } } const instanceId = args.instance; const sessionId = args.session ?? instanceId; const agentName = args.name; const platformLabel = args["platform-label"]; if (!instanceId) { process.stderr.write( "agent-coord session-context --instance [--session ] [--name ] [--platform-label