@rallycry/conveyor-agent 10.13.63 → 10.13.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/setup/bootstrap.ts","../src/connection/agent-connection.ts","../src/setup/bootstrap-poll.ts","../src/connection/auth-errors.ts","../src/utils/logger.ts","../src/runner/git-utils.ts","../../shared/dist/chunk-6RHVH33O.js","../../shared/dist/index.js","../src/runner/mode-controller.ts","../src/runner/lifecycle.ts","../src/harness/types.ts","../src/harness/claude-code/index.ts","../src/harness/pty/session.ts","../src/harness/opencode/plugin.ts","../src/harness/opencode/events.ts","../src/harness/opencode/event-source.ts","../src/harness/pty/event-queue.ts","../src/harness/pty/hook-socket.ts","../src/harness/pty/jsonl-tailer.ts","../src/harness/pty/record-mapper.ts","../src/harness/pty/limit-banner.ts","../src/harness/pty/chat-record-mapper.ts","../src/harness/pty/settings.ts","../src/execution/redactor.ts","../src/harness/pty/output-coalescer.ts","../src/harness/pty/tool-server.ts","../src/harness/pty/mcp-server.ts","../src/harness/pty/credentials.ts","../src/harness/pty/credentials-marker.ts","../src/harness/pty/adapters/claude.ts","../src/harness/pty/config-home-health.ts","../src/harness/pty/index.ts","../src/harness/opencode/index.ts","../src/harness/pty/adapters/types.ts","../src/harness/pty/adapters/opencode-auth.ts","../src/harness/opencode/credentials.ts","../src/harness/opencode/spawn.ts","../src/harness/index.ts","../src/harness/pty/adapters/opencode.ts","../src/harness/pty/adapters/index.ts","../src/harness/pty/stream-server.ts","../src/harness/pty/direct-stream.ts","../src/execution/query-executor.ts","../src/execution/chat-instructions.ts","../src/execution/relaunch-hold.ts","../src/execution/pack-runner-prompt.ts","../src/execution/prompt-formatters.ts","../src/workbench/fs.ts","../src/execution/tag-context-resolver.ts","../src/execution/prompt-truncation.ts","../src/execution/pm-relaunch-instructions.ts","../src/execution/mode-prompt.ts","../src/execution/system-prompt.ts","../src/execution/prompt-builder.ts","../src/tools/task-context-tools.ts","../../shared/dist/tool-contracts/index.js","../src/tools/contract-tool.ts","../src/tools/helpers.ts","../src/tools/dependency-suggestion-tools.ts","../src/tools/mutation-tools.ts","../src/tools/attachment-tools.ts","../src/tools/checklist-tools.ts","../src/tools/common-tools.ts","../src/tools/pm-tools.ts","../src/tools/discovery-tools.ts","../src/tools/project-tools.ts","../src/execution/context-path-verifier.ts","../src/tools/drive-tools.ts","../src/tools/code-review-tools.ts","../src/tools/index.ts","../src/execution/playwright-mcp.ts","../src/execution/event-handlers.ts","../src/execution/event-processor.ts","../src/execution/key-cycle.ts","../src/execution/task-property-utils.ts","../src/runner/heavy-gate.ts","../src/execution/tool-loop-tracker.ts","../src/execution/tool-access.ts","../src/runner/query-bridge.ts","../src/execution/usage-sampler.ts","../src/usage/reset-parse.ts","../src/usage/parse-usage.ts","../src/usage/run-probe.ts","../src/setup/git-ready.ts","../src/runner/port-discovery.ts","../src/runner/codespace-port-visibility.ts","../src/runner/parent-pull-handler.ts","../src/runner/background-work.ts","../src/runner/session-runner.ts","../src/setup/config.ts","../src/setup/codespace.ts"],"sourcesContent":["/**\n * Codespace bootstrap fetch — wraps the `/api/codespace/bootstrap/:name` call\n * with an AbortController timeout, exponential-backoff retries, and structured\n * stderr events the agent-runner-handler can ingest.\n *\n * Used at agent startup (`cli.ts`) and for runtime taskToken refresh when the\n * server signals an auth rejection (`agent-connection.ts`).\n */\nimport { sleep } from \"../utils/sleep.js\";\n\nexport interface BootstrapConfig {\n mode?: \"task\" | \"project\";\n taskId?: string;\n sessionId?: string;\n taskToken?: string;\n runnerMode?: string;\n agentMode?: string;\n isAuto?: string;\n taskBranch?: string;\n projectId?: string;\n projectToken?: string;\n apiUrl?: string;\n workspaceBranch?: string;\n envVars?: Record<string, string>;\n}\n\nexport interface BootstrapAttemptResult {\n ok: boolean;\n status?: number;\n body?: BootstrapConfig;\n errorText?: string;\n reason?: string;\n}\n\nexport interface BootstrapFailureEvent {\n event: \"bootstrap_failed\";\n reason: string;\n apiUrl: string;\n instanceName: string;\n hasBootstrapToken: boolean;\n hasTaskToken: boolean;\n attempt: number;\n status?: number;\n detail?: string;\n}\n\nconst BOOTSTRAP_TIMEOUT_MS = 30_000;\nconst RETRY_DELAYS_MS = [5_000, 10_000, 20_000];\n\nfunction emitFailureEvent(payload: BootstrapFailureEvent): void {\n process.stderr.write(JSON.stringify(payload) + \"\\n\");\n}\n\nasync function singleBootstrapAttempt(\n apiUrl: string,\n instanceName: string,\n bootstrapToken: string | undefined,\n timeoutMs: number,\n): Promise<BootstrapAttemptResult> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const headers: Record<string, string> = {};\n if (bootstrapToken) headers[\"x-codespace-token\"] = bootstrapToken;\n const response = await fetch(`${apiUrl}/api/codespace/bootstrap/${instanceName}`, {\n headers,\n signal: controller.signal,\n });\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n return {\n ok: false,\n status: response.status,\n errorText: errorText.slice(0, 500),\n reason: response.status === 401 || response.status === 403 ? \"auth_rejected\" : \"http_error\",\n };\n }\n const body = (await response.json()) as BootstrapConfig;\n return { ok: true, body };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const reason = controller.signal.aborted ? \"timeout\" : \"network_error\";\n return { ok: false, errorText: message.slice(0, 500), reason };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport interface FetchBootstrapOptions {\n apiUrl: string;\n instanceName: string;\n bootstrapToken: string | undefined;\n timeoutMs?: number;\n retryDelaysMs?: number[];\n /** Whether to consider any HTTP error retryable. Network/timeout always retry. */\n retryOnHttpError?: boolean;\n}\n\nexport interface FetchBootstrapSuccess {\n ok: true;\n config: BootstrapConfig;\n attempts: number;\n}\n\nexport interface FetchBootstrapFailure {\n ok: false;\n reason: string;\n status?: number;\n detail?: string;\n attempts: number;\n}\n\nfunction buildFailure(\n reason: string,\n attempts: number,\n status: number | undefined,\n detail: string | undefined,\n): FetchBootstrapFailure {\n const out: FetchBootstrapFailure = { ok: false, reason, attempts };\n if (status === undefined) {\n // no status field\n } else {\n out.status = status;\n }\n if (detail) out.detail = detail;\n return out;\n}\n\nfunction isRetryable(reason: string, retryOnHttpError: boolean | undefined): boolean {\n if (reason === \"timeout\" || reason === \"network_error\") return true;\n return retryOnHttpError === true && reason === \"http_error\";\n}\n\n/**\n * Fetch the bootstrap payload with retries. Network errors and timeouts always\n * trigger a retry; HTTP errors are retried only when `retryOnHttpError` is set\n * (off by default — a 401/403/404 won't recover from retries).\n */\nexport async function fetchBootstrap(\n opts: FetchBootstrapOptions,\n): Promise<FetchBootstrapSuccess | FetchBootstrapFailure> {\n const timeoutMs = opts.timeoutMs ?? BOOTSTRAP_TIMEOUT_MS;\n const delays = opts.retryDelaysMs ?? RETRY_DELAYS_MS;\n const maxAttempts = delays.length + 1;\n const hasBootstrapToken = Boolean(opts.bootstrapToken);\n const hasTaskToken = Boolean(process.env.CONVEYOR_TASK_TOKEN);\n\n let lastReason = \"unknown\";\n let lastStatus: number | undefined;\n let lastDetail: string | undefined;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const result = await singleBootstrapAttempt(\n opts.apiUrl,\n opts.instanceName,\n opts.bootstrapToken,\n timeoutMs,\n );\n if (result.ok && result.body) {\n return { ok: true, config: result.body, attempts: attempt };\n }\n lastReason = result.reason ?? \"unknown\";\n lastStatus = result.status;\n lastDetail = result.errorText;\n\n const failurePayload: BootstrapFailureEvent = {\n event: \"bootstrap_failed\",\n reason: lastReason,\n apiUrl: opts.apiUrl,\n instanceName: opts.instanceName,\n hasBootstrapToken,\n hasTaskToken,\n attempt,\n };\n if (lastStatus === undefined) {\n // no status field\n } else {\n failurePayload.status = lastStatus;\n }\n if (lastDetail) failurePayload.detail = lastDetail;\n emitFailureEvent(failurePayload);\n\n if (!isRetryable(lastReason, opts.retryOnHttpError) || attempt >= maxAttempts) {\n return buildFailure(lastReason, attempt, lastStatus, lastDetail);\n }\n await sleep(delays[attempt - 1]);\n }\n\n return buildFailure(lastReason, maxAttempts, lastStatus, lastDetail);\n}\n\n/** Apply a successful bootstrap config to process.env (mutates env vars). */\nexport function applyBootstrapToEnv(config: BootstrapConfig): void {\n for (const [key, value] of Object.entries(config.envVars ?? {})) {\n process.env[key] = value;\n }\n if (config.mode === \"project\") {\n if (config.projectToken) process.env.CONVEYOR_PROJECT_TOKEN = config.projectToken;\n if (config.projectId) process.env.CONVEYOR_PROJECT_ID = config.projectId;\n if (config.workspaceBranch) process.env.CONVEYOR_WORKSPACE_BRANCH = config.workspaceBranch;\n return;\n }\n if (config.taskId) process.env.CONVEYOR_TASK_ID = config.taskId;\n if (config.sessionId) process.env.CONVEYOR_SESSION_ID = config.sessionId;\n if (config.taskToken) process.env.CONVEYOR_TASK_TOKEN = config.taskToken;\n if (config.agentMode !== undefined) process.env.CONVEYOR_AGENT_MODE = config.agentMode;\n if (config.isAuto !== undefined) process.env.CONVEYOR_IS_AUTO = config.isAuto;\n if (config.runnerMode) process.env.CONVEYOR_MODE = config.runnerMode;\n if (config.taskBranch) process.env.CONVEYOR_TASK_BRANCH = config.taskBranch;\n}\n","/* oxlint-disable max-lines -- service method bindings are flat and cohesive; splitting would scatter closely-coupled call wrappers */\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport { io, type Socket } from \"socket.io-client\";\nimport type {\n AgentSessionServiceMethods,\n AgentMode,\n AgentQuestion,\n PtyChatEventPayload,\n RunnerMode,\n WorkspaceDiscoveredPort,\n} from \"@project/shared\";\nimport {\n buildConveyorSocketOptions,\n callWithAck,\n waitForConnected as waitForSocketConnected,\n} from \"@project/shared/socket-core\";\nimport { fetchBootstrap, applyBootstrapToEnv } from \"../setup/bootstrap.js\";\nimport { pollUntilBound, PollUntilBoundHttpError } from \"../setup/bootstrap-poll.js\";\nimport { syncGithubTokenFiles } from \"../boot/git-credential.js\";\nimport { heartbeatStatusFor, loopStatusForRunnerStatus, type LoopStatus } from \"./loop-lag.js\";\n\n/**\n * The milestones an agent may declare — narrower than the server's full slug\n * set, which also covers server-generated review verdicts.\n */\ntype AgentMilestone = NonNullable<\n AgentSessionServiceMethods[\"postAgentMessage\"][\"payload\"][\"milestone\"]\n>;\n\n// ── Configuration ──────────────────────────────────────────────────────────\n\nexport interface AgentConnectionConfig {\n apiUrl: string;\n taskToken: string;\n sessionId: string;\n runnerMode?: RunnerMode;\n}\n\n// ── Incoming server-push event types ───────────────────────────────────────\n\nexport interface IncomingMessage {\n content: string;\n userId: string;\n source?: string;\n files?: Array<{ name: string; content: string; mimeType?: string }>;\n /**\n * Delivery hint for the PTY harness: \"prefill\" parks the message in the\n * Connected-TUI input for a human to review/edit/Enter instead of\n * auto-submitting (set by Refine → Discovery/Review). Absent → submit.\n */\n delivery?: \"prefill\";\n}\n\nexport interface SetModeData {\n agentMode: AgentMode;\n}\n\nexport interface ApiKeyUpdateData {\n apiKey: string;\n isSubscription?: boolean;\n}\n\n/**\n * Server push asking the builder pod to spawn a same-pod review child: a\n * second conveyor-agent process bound to a fresh review WorkspaceSession\n * (sessionId + sessionJwt). No taskId on the wire — the child inherits the\n * parent's CONVEYOR_TASK_ID and the server derives it from the JWT.\n */\nexport interface SpawnReviewData {\n sessionId: string;\n sessionJwt: string;\n mode: \"code-review\";\n branch?: string | null;\n prNumber?: number | null;\n checkoutRef?: string | null;\n}\n\n/**\n * Server push asking the builder pod to spawn an extra interactive child on\n * this pod: a second Claude TUI (mode \"adhoc\") or a raw login shell (mode\n * \"shell\"), each bound to a fresh WorkspaceSession (sessionId + sessionJwt).\n * No taskId on the wire — the child inherits the parent's CONVEYOR_TASK_ID\n * and the server derives it from the JWT.\n */\nexport interface SpawnTuiData {\n sessionId: string;\n sessionJwt: string;\n mode: \"adhoc\" | \"shell\";\n projectId: string;\n}\n\n// ── Connection class ───────────────────────────────────────────────────────\n\nconst EVENT_BATCH_MS = 500;\nconst MAX_EVENT_BUFFER = 5000;\n\n// refreshTaskTokenFromBootstrap() re-fetches the WHOLE bundle and swaps every\n// credential in place — the 24h task JWT AND the ~1h-lived GCP access token\n// (CLOUDSDK_AUTH_ACCESS_TOKEN) and GitHub installation token. The cadence must\n// track the SHORTEST-lived credential, not the JWT: at 6h a pod working >1h\n// silently lost GCP/GitHub auth until the next reconnect or the 6h tick. 45min\n// sits comfortably inside the ~1h window with room for a retry before expiry.\n// (Still far inside the 24h JWT TTL.) The bootstrap route is rate-limited to\n// once/60s, so this is safe fleet-wide.\nconst TOKEN_REFRESH_INTERVAL_MS = 45 * 60 * 1000;\n\nexport class AgentConnection {\n private socket: Socket | null = null;\n private readonly config: AgentConnectionConfig;\n private eventBuffer: Array<{ event: { type: string; [key: string]: unknown } }> = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private tokenRefreshTimer: ReturnType<typeof setInterval> | null = null;\n private lastEmittedStatus: string | null = null;\n private lastReportedStatus: string | null = null;\n private droppedEventCount = 0;\n\n // Pending answer resolvers for askUserQuestion room-event fallback\n private pendingAnswerResolvers = new Map<string, (answers: Record<string, string>) => void>();\n\n // Dedup: suppress near-identical messages within a short window\n private recentMessages: Array<{ words: Set<string>; timestamp: number; preview: string }> = [];\n private static readonly DEDUP_WINDOW_MS = 30_000;\n private static readonly DEDUP_SIMILARITY_THRESHOLD = 0.7;\n private static readonly DEDUP_PREVIEW_LIMIT = 120;\n\n // Early-buffering: events that arrive before callbacks are registered\n private earlyMessages: IncomingMessage[] = [];\n private earlyStop = false;\n private earlySoftStop = false;\n private earlyModeChanges: SetModeData[] = [];\n\n // Registered callbacks\n private messageCallback: ((msg: IncomingMessage) => void) | null = null;\n private stopCallback: (() => void) | null = null;\n private softStopCallback: (() => void) | null = null;\n private modeChangeCallback: ((data: SetModeData) => void) | null = null;\n private apiKeyUpdateCallback: ((data: ApiKeyUpdateData) => void) | null = null;\n private pullBranchCallback: ((data: { branch: string }) => void) | null = null;\n private runStartCommandCallback: (() => void) | null = null;\n private earlyPullBranches: Array<{ branch: string }> = [];\n private spawnReviewCallback: ((data: SpawnReviewData) => void) | null = null;\n private earlySpawnReviews: SpawnReviewData[] = [];\n private spawnTuiCallback: ((data: SpawnTuiData) => void) | null = null;\n private earlySpawnTuis: SpawnTuiData[] = [];\n private probeUsageCallback: (() => void) | null = null;\n private earlyProbeUsage = false;\n\n // PTY relay (S5 terminal). Single-slot callbacks, set per PtySession run.\n private ptyInputCallback: ((data: string) => void) | null = null;\n private ptyResizeCallback: ((cols: number, rows: number) => void) | null = null;\n\n constructor(config: AgentConnectionConfig) {\n this.config = config;\n }\n\n get sessionId(): string {\n return this.config.sessionId;\n }\n\n get connected(): boolean {\n return this.socket?.connected ?? false;\n }\n\n // ── Typed service method call ──────────────────────────────────────────\n\n // Socket.IO keeps the SAME Socket instance across transport-level\n // reconnects (it only goes null on an explicit disconnect() teardown), so a\n // brief flap leaves `this.socket` non-null but `.connected === false`. Rather\n // than failing a tool call instantly (which the spawned `claude` surfaces as\n // \"Conveyor MCP disconnected\" and an excuse to go idle), we wait out a short\n // reconnect window, then emit with an ack timeout so a buffered packet whose\n // ack never returns can't hang the call forever. We do NOT auto-retry the\n // emit — re-sending a write could double-apply it; the agent prompt instructs\n // the model to retry the tool, which is the safe place to decide idempotency.\n private static readonly CALL_CONNECT_WAIT_MS = 20_000;\n private static readonly CALL_ACK_TIMEOUT_MS = 30_000;\n\n // ── Proactive socket recycle ───────────────────────────────────────────\n // Cloud Run severs every WebSocket at its request timeout (3600s is the\n // platform ceiling), so a socket that lives past ~60 minutes is killed at a\n // random moment — historically mid-tool-call, which let the spawned CLI\n // abandon its MCP session. Recycle the transport at a QUIET moment (no\n // in-flight RPC) before the platform deadline instead: an engine-level close\n // looks like a transport drop, so Socket.IO's auto-reconnect and the\n // io \"reconnect\" → reconnectToSession() recovery path run unchanged. Jitter\n // keeps a fleet of pods from recycling in one thundering herd.\n private static readonly SOCKET_RECYCLE_BASE_MS = 52 * 60 * 1000;\n private static readonly SOCKET_RECYCLE_JITTER_MS = 4 * 60 * 1000;\n private static readonly SOCKET_RECYCLE_BUSY_POLL_MS = 15_000;\n private recycleTimer: NodeJS.Timeout | null = null;\n private pendingCalls = 0;\n\n async call<M extends keyof AgentSessionServiceMethods>(\n method: M,\n payload: AgentSessionServiceMethods[M][\"payload\"],\n ): Promise<AgentSessionServiceMethods[M][\"response\"]> {\n const socket = this.socket;\n if (!socket) {\n throw new Error(\n `Not connected (method: ${String(method)}, session: ${this.config.sessionId})`,\n );\n }\n this.pendingCalls++;\n try {\n if (!socket.connected) {\n // Mid-reconnect — ride it out instead of failing fast.\n await this.waitForConnected(socket, AgentConnection.CALL_CONNECT_WAIT_MS, String(method));\n }\n return await this.emitWithAck(socket, method, payload);\n } finally {\n this.pendingCalls--;\n }\n }\n\n /** (Re)arm the recycle timer — called on every successful (re)connect. */\n private scheduleSocketRecycle(): void {\n this.clearSocketRecycle();\n const delay =\n AgentConnection.SOCKET_RECYCLE_BASE_MS +\n Math.random() * AgentConnection.SOCKET_RECYCLE_JITTER_MS;\n this.armRecycleTimer(delay);\n }\n\n private clearSocketRecycle(): void {\n if (this.recycleTimer) {\n clearTimeout(this.recycleTimer);\n this.recycleTimer = null;\n }\n }\n\n private armRecycleTimer(delay: number): void {\n this.recycleTimer = setTimeout(() => {\n this.recycleTimer = null;\n this.attemptSocketRecycle();\n }, delay);\n // Never hold the process open for a recycle.\n (this.recycleTimer as { unref?: () => void }).unref?.();\n }\n\n private attemptSocketRecycle(): void {\n const socket = this.socket;\n // Torn down, or the platform sever already beat us — the next \"connect\"\n // re-arms a fresh cycle.\n if (!socket?.connected) return;\n if (this.pendingCalls > 0) {\n // Busy — poll until quiet. If the platform severs first, we're no worse\n // off than before this existed.\n this.armRecycleTimer(AgentConnection.SOCKET_RECYCLE_BUSY_POLL_MS);\n return;\n }\n process.stderr.write(\n \"[conveyor-agent] Recycling socket ahead of the platform request timeout\\n\",\n );\n (socket.io as { engine?: { close?: () => void } }).engine?.close?.();\n }\n\n /** Resolve once `socket` reports connected, or reject after `timeoutMs`. */\n private waitForConnected(socket: Socket, timeoutMs: number, method: string): Promise<void> {\n return waitForSocketConnected(socket, timeoutMs, () => {\n return new Error(\n `Not connected — socket did not reconnect within ${timeoutMs / 1000}s ` +\n `(method: ${method}, session: ${this.config.sessionId}). Transient; retry.`,\n );\n });\n }\n\n /** Emit an RPC and resolve on ack, rejecting if no ack arrives in time. */\n private emitWithAck<M extends keyof AgentSessionServiceMethods>(\n socket: Socket,\n method: M,\n payload: AgentSessionServiceMethods[M][\"payload\"],\n ): Promise<AgentSessionServiceMethods[M][\"response\"]> {\n return callWithAck<AgentSessionServiceMethods[M][\"response\"]>(\n socket,\n `agentSessionService:${String(method)}`,\n payload,\n {\n timeoutMs: AgentConnection.CALL_ACK_TIMEOUT_MS,\n requireData: true,\n makeTimeoutError: () =>\n new Error(\n `Service call timed out after ${AgentConnection.CALL_ACK_TIMEOUT_MS / 1000}s ` +\n `(method: ${String(method)}, session: ${this.config.sessionId}). ` +\n `Usually a transient reconnect; retry.`,\n ),\n makeFailureError: (error) => new Error(error ?? `Service call failed: ${String(method)}`),\n },\n );\n }\n\n // ── Connection lifecycle ───────────────────────────────────────────────\n\n // oxlint-disable-next-line max-lines-per-function -- socket setup requires registering many co-located event handlers\n connect(): Promise<void> {\n if (!this.config.apiUrl) {\n return Promise.reject(new Error(\"Cannot connect: apiUrl is empty\"));\n }\n this.startProactiveTokenRefresh();\n // oxlint-disable-next-line max-lines-per-function -- socket event registration requires co-located handlers\n return new Promise((resolve, reject) => {\n let settled = false;\n let attempts = 0;\n const maxInitialAttempts = 30;\n\n process.stderr.write(\n `[conveyor-agent] Connecting to ${this.config.apiUrl} (mode: ${this.config.runnerMode ?? \"task\"}, session: ${this.config.sessionId})\\n`,\n );\n\n this.socket = io(\n this.config.apiUrl,\n buildConveyorSocketOptions({\n taskToken: this.config.taskToken,\n runnerMode: this.config.runnerMode ?? \"task\",\n }),\n );\n\n // ── Server-push event handlers (v7 room-based events) ─────────\n // These events are emitted to the agentSessionService:<sessionId>\n // room. The agent joins this room via the connectAgent() call after\n // the socket connects.\n\n this.socket.on(\"session:message\", (msg: IncomingMessage) => {\n // Preserve source field from server for critical message filtering\n const incoming: IncomingMessage = {\n content: msg.content,\n userId: msg.userId,\n ...(msg.source && { source: msg.source }),\n ...(msg.files && { files: msg.files }),\n ...(msg.delivery === \"prefill\" && { delivery: msg.delivery }),\n };\n if (this.messageCallback) this.messageCallback(incoming);\n else this.earlyMessages.push(incoming);\n });\n\n this.socket.on(\"session:stop\", () => {\n if (this.stopCallback) this.stopCallback();\n else this.earlyStop = true;\n });\n\n this.socket.on(\"session:softStop\", () => {\n if (this.softStopCallback) this.softStopCallback();\n else this.earlySoftStop = true;\n });\n\n this.socket.on(\"session:modeChange\", (data: SetModeData) => {\n if (this.modeChangeCallback) this.modeChangeCallback(data);\n else this.earlyModeChanges.push(data);\n });\n\n this.socket.on(\n \"session:answerQuestion\",\n (data: { requestId: string; answers: Record<string, string> }) => {\n const resolver = this.pendingAnswerResolvers.get(data.requestId);\n if (resolver) resolver(data.answers);\n },\n );\n\n this.socket.on(\"agentRunner:updateApiKey\", (data: ApiKeyUpdateData) => {\n if (this.apiKeyUpdateCallback) this.apiKeyUpdateCallback(data);\n });\n\n this.socket.on(\"session:pullBranch\", (data: { branch: string }) => {\n if (this.pullBranchCallback) this.pullBranchCallback(data);\n else this.earlyPullBranches.push(data);\n });\n\n // Same-pod review: spawn a child conveyor-agent bound to a fresh review\n // session. Early-buffered — the push can land while the runner is still\n // booting (CI green races pod startup after a wake).\n this.socket.on(\"session:spawnReview\", (data: SpawnReviewData) => {\n if (this.spawnReviewCallback) this.spawnReviewCallback(data);\n else this.earlySpawnReviews.push(data);\n });\n\n // Same-pod TUI/shell tab: spawn a child conveyor-agent bound to a fresh\n // adhoc/shell session. Early-buffered like spawnReview — the push can\n // land while the runner is still booting.\n this.socket.on(\"session:spawnTui\", (data: SpawnTuiData) => {\n if (this.spawnTuiCallback) this.spawnTuiCallback(data);\n else this.earlySpawnTuis.push(data);\n });\n\n // On-demand usage refresh: re-sample all the owner's keys NOW (the adhoc\n // runner's multi-key /usage probe). Early-buffered — a \"refresh\" click can\n // land while the pod is still booting; the runner drains it on register.\n this.socket.on(\"session:probeUsage\", () => {\n if (this.probeUsageCallback) this.probeUsageCallback();\n else this.earlyProbeUsage = true;\n });\n\n this.socket.on(\"session:runStartCommand\", () => {\n this.runStartCommandCallback?.();\n });\n\n // PTY relay (S2 → agent): keystrokes and reconciled resizes from the S5\n // terminal. Events are room-scoped so each targets this session; the\n // sessionId guard is defensive. No early-buffer — input/resize are\n // meaningless until a PtySession is live and has registered a callback.\n this.socket.on(\"pty:input\", (data: { sessionId?: string; data: string }) => {\n if (data.sessionId && data.sessionId !== this.config.sessionId) return;\n this.ptyInputCallback?.(data.data);\n });\n\n this.socket.on(\"pty:resize\", (data: { sessionId?: string; cols: number; rows: number }) => {\n if (data.sessionId && data.sessionId !== this.config.sessionId) return;\n this.ptyResizeCallback?.(data.cols, data.rows);\n });\n\n // ── Socket lifecycle events ────────────────────────────────────\n this.socket.on(\"connect\", () => {\n process.stderr.write(\"[conveyor-agent] Socket connected\\n\");\n // Every (re)connect starts a fresh Cloud Run request clock — arm the\n // proactive recycle so the hourly sever lands on our schedule.\n this.scheduleSocketRecycle();\n if (!settled) {\n settled = true;\n resolve();\n }\n });\n\n this.socket.on(\"connect_error\", (err: Error) => {\n attempts++;\n process.stderr.write(\n `[conveyor-agent] Connection error (attempt ${attempts}/${maxInitialAttempts}): ${err.message}\\n`,\n );\n if (!settled && attempts >= maxInitialAttempts) {\n settled = true;\n reject(\n new Error(\n `Failed to connect to ${this.config.apiUrl} after ${maxInitialAttempts} attempts: ${err.message}`,\n ),\n );\n }\n });\n\n this.socket.on(\"disconnect\", (reason: string) => {\n process.stderr.write(`[conveyor-agent] Disconnected: ${reason}\\n`);\n // Server-initiated disconnect (auth rejected, session terminated)\n // arrives with reason \"server namespace disconnect\" or\n // \"io server disconnect\". socket.io does NOT auto-reconnect for these,\n // so we drive a bounded reconnect loop ourselves. Recovery is\n // deliberately NOT gated on a successful token refresh: the refresh\n // returns false on an unchanged token, a consumed 60s window (e.g. eaten\n // by a preceding auth:rejected), or absent bootstrap env — yet the\n // socket still has to come back, else the heartbeat worker keeps the\n // lease alive while the agent goes permanently deaf to server pushes.\n if (reason === \"io server disconnect\" || reason === \"server namespace disconnect\") {\n this.scheduleReconnectAfterServerDisconnect();\n }\n });\n\n this.socket.on(\"auth:rejected\", () => {\n process.stderr.write(\"[conveyor-agent] Auth rejected by server, refreshing taskToken\\n\");\n void this.refreshTaskTokenFromBootstrap().catch(() => {});\n });\n\n this.socket.io.on(\"reconnect\", (reconnectAttempts: number) => {\n process.stderr.write(\n `[conveyor-agent] Reconnected (attempts: ${reconnectAttempts}, ${new Date().toISOString()})\\n`,\n );\n // Renew the session lease IMMEDIATELY — a starvation-induced strand\n // recovers the instant the loop unbricks (Stranded → Active), instead\n // of waiting out the up-to-30s heartbeat timer against the 120s grace.\n this.sendHeartbeat();\n // Re-join the session room and process any pending messages from the disconnect window\n void this.reconnectToSession();\n });\n\n this.socket.io.on(\"reconnect_attempt\", () => {\n // Attempt counting is handled in connect_error handler above\n });\n });\n }\n\n disconnect(): void {\n this.stopProactiveTokenRefresh();\n this.clearSocketRecycle();\n this.stopHeartbeatWorker();\n // Best-effort flush on disconnect — don't await\n void this.flushEvents();\n if (this.socket) {\n this.socket.io.reconnection(false);\n this.socket.removeAllListeners();\n this.socket.disconnect();\n this.socket = null;\n }\n }\n\n // ── Reconnect with retry ────────────────────────────────────────────\n //\n // Socket.IO already retries the transport forever. This higher-level helper\n // re-issues the `connectAgent` RPC after a successful reconnect to re-join\n // the session room and drain pending messages. We retry indefinitely with a\n // capped exponential backoff — a stranded codespace with a missing agent is\n // worse than a long-running reconnect loop, and a transient API outage\n // shouldn't kill the agent process.\n\n private static readonly RECONNECT_BASE_DELAY_MS = 2_000;\n private static readonly RECONNECT_MAX_DELAY_MS = 60_000;\n private static readonly RECONNECT_STATUS_EVERY_N = 3;\n\n private isReconnecting = false;\n private reconnectingAfterServerDisconnect = false;\n\n /** Capped exponential backoff (2s, 4s, 8s, 16s, 32s, then 60s steady) shared\n * by both reconnect loops (connectAgent-RPC and server-disconnect). */\n private static backoffDelayMs(attempt: number): number {\n return Math.min(\n AgentConnection.RECONNECT_BASE_DELAY_MS * 2 ** Math.min(attempt - 1, 5),\n AgentConnection.RECONNECT_MAX_DELAY_MS,\n );\n }\n\n /** Sleep `ms`, unref'd so it never holds the process open on its own. */\n private static delay(ms: number): Promise<void> {\n return new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n }\n\n /**\n * Invoked after every successful session reconnect (the `connectAgent` RPC\n * re-established the session room). The runner uses this to force a TUI\n * repaint: the reconnect may have landed on a different/restarted API\n * process whose PTY scrollback ring is empty, and a quiet terminal would\n * otherwise never re-seed it.\n */\n onReconnected?: () => void;\n\n private async reconnectToSession(): Promise<void> {\n if (this.isReconnecting) return;\n this.isReconnecting = true;\n try {\n let attempt = 0;\n while (this.socket) {\n attempt++;\n try {\n const { pendingMessages } = await this.call(\"connectAgent\", {\n sessionId: this.config.sessionId,\n });\n this.drainPendingMessages(pendingMessages);\n process.stderr.write(\n `[conveyor-agent] Reconnected to session successfully (attempts: ${attempt})\\n`,\n );\n // Only re-report status if it actually changed since the last\n // successful report — avoids spamming duplicate status transitions\n // through the system on every reconnect.\n if (this.lastEmittedStatus && this.lastEmittedStatus !== this.lastReportedStatus) {\n const status = this.lastEmittedStatus;\n void this.call(\"reportAgentStatus\", {\n sessionId: this.config.sessionId,\n status,\n })\n .then(() => {\n this.lastReportedStatus = status;\n })\n .catch(() => {});\n }\n // Notify UI subscribers that reconnect succeeded.\n this.sendEvent({\n type: \"agent_runner_status\",\n reason: \"reconnected\",\n attempts: attempt,\n });\n try {\n this.onReconnected?.();\n } catch {\n /* repaint is best-effort — never fail the reconnect over it */\n }\n return;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n const delayMs = AgentConnection.backoffDelayMs(attempt);\n process.stderr.write(\n `[conveyor-agent] connectAgent failed (attempt ${attempt}): ${errMsg} — retrying in ${delayMs / 1000}s\\n`,\n );\n\n // Auth-rejected on the connectAgent RPC — the taskToken may be\n // stale (e.g. after a 24h JWT TTL or a server-side rotation). Try\n // refreshing from the bootstrap endpoint before the next attempt.\n if (this.looksLikeAuthError(errMsg)) {\n void this.refreshTaskTokenFromBootstrap().catch(() => {});\n }\n\n // Every Nth failure, emit a status event so the UI shows we're\n // still trying — piggybacks on the existing `task:agentStatus`\n // pathway via sendEvent (no new socket event needed).\n if (attempt % AgentConnection.RECONNECT_STATUS_EVERY_N === 0) {\n this.sendEvent({\n type: \"agent_runner_status\",\n reason: \"reconnecting\",\n attempt,\n });\n }\n\n await AgentConnection.delay(delayMs);\n }\n }\n } finally {\n this.isReconnecting = false;\n }\n }\n\n /**\n * Drive a bounded reconnect after a server-initiated disconnect. Loops until\n * the socket reconnects or is torn down, nudging socket.connect() on each\n * pass with a capped exponential backoff. A token refresh is attempted every\n * pass (rate-limited to once/60s inside refreshTaskTokenFromBootstrap) but\n * its result NEVER gates the reconnect — the socket must recover even when\n * there is no fresh token to apply.\n */\n private scheduleReconnectAfterServerDisconnect(): void {\n if (this.reconnectingAfterServerDisconnect) return;\n this.reconnectingAfterServerDisconnect = true;\n void this.reconnectAfterServerDisconnect().finally(() => {\n this.reconnectingAfterServerDisconnect = false;\n });\n }\n\n private async reconnectAfterServerDisconnect(): Promise<void> {\n let attempt = 0;\n while (this.socket && !this.socket.connected) {\n attempt++;\n // Best-effort token refresh — the disconnect is often a stale-JWT\n // rejection — but treat the outcome as advisory, never as a gate.\n try {\n await this.refreshTaskTokenFromBootstrap();\n } catch {\n /* advisory only */\n }\n const socket = this.socket;\n if (!socket || socket.connected) return;\n socket.connect();\n try {\n await this.waitForConnected(\n socket,\n AgentConnection.CALL_CONNECT_WAIT_MS,\n \"server-disconnect-reconnect\",\n );\n // A manual socket.connect() fires \"connect\" but NOT the manager-level\n // \"reconnect\" (the manager never saw a transport drop), so the session-\n // room rejoin that io.on(\"reconnect\") normally drives would be skipped —\n // leaving the agent deaf to session:message/stop/spawn. Drive it here:\n // renew the lease immediately, then re-run connectAgent + drain pending.\n this.sendHeartbeat();\n void this.reconnectToSession();\n return;\n } catch {\n const delayMs = AgentConnection.backoffDelayMs(attempt);\n process.stderr.write(\n `[conveyor-agent] server-disconnect reconnect attempt ${attempt} did not connect within ` +\n `${AgentConnection.CALL_CONNECT_WAIT_MS / 1000}s — retrying in ${delayMs / 1000}s\\n`,\n );\n await AgentConnection.delay(delayMs);\n }\n }\n }\n\n private looksLikeAuthError(message: string): boolean {\n // \"session not found\" / \"session expired\" / \"invalid session\" are the\n // server's wording for an evicted-or-expired task session — the symptom of\n // a stale token. They contain none of unauthor/forbid/auth/token, so match\n // them explicitly, otherwise the refresh-on-reconnect path never fires.\n return /unauthor|forbid|auth|token|session (?:not found|expired|invalid)|invalid session/i.test(\n message,\n );\n }\n\n // ── Proactive task-token refresh ────────────────────────────────────────\n //\n // Socket.IO only re-presents the taskToken on a (re)connect handshake, and\n // the server only re-validates the JWT then. So a token that expires while\n // the socket stays connected goes unnoticed until the next RPC fails. Re-mint\n // periodically from the bootstrap endpoint — refreshFromBootstrap() updates\n // both this.config.taskToken and socket.auth.taskToken, so any later\n // reconnect carries a fresh token. No-ops for project mode / missing\n // codespace env, and is rate-limited to once/60s inside refreshFromBootstrap.\n\n private startProactiveTokenRefresh(): void {\n if (this.tokenRefreshTimer) return;\n this.tokenRefreshTimer = setInterval(() => {\n void this.refreshTaskTokenFromBootstrap().catch(() => {});\n }, TOKEN_REFRESH_INTERVAL_MS);\n // Don't let the refresh timer keep the process alive on its own.\n this.tokenRefreshTimer.unref?.();\n }\n\n private stopProactiveTokenRefresh(): void {\n if (this.tokenRefreshTimer) {\n clearInterval(this.tokenRefreshTimer);\n this.tokenRefreshTimer = null;\n }\n }\n\n private drainPendingMessages(messages: Array<{ content: string; userId: string }>): void {\n for (const msg of messages) {\n if (!msg.content) continue;\n if (this.messageCallback) {\n this.messageCallback({ content: msg.content, userId: msg.userId });\n } else {\n this.earlyMessages.push({ content: msg.content, userId: msg.userId });\n }\n }\n }\n\n // ── Callback registration with early-buffer draining ───────────────\n\n onMessage(callback: (msg: IncomingMessage) => void): void {\n this.messageCallback = callback;\n for (const msg of this.earlyMessages) callback(msg);\n this.earlyMessages = [];\n }\n\n onStop(callback: () => void): void {\n this.stopCallback = callback;\n if (this.earlyStop) {\n callback();\n this.earlyStop = false;\n }\n }\n\n onSoftStop(callback: () => void): void {\n this.softStopCallback = callback;\n if (this.earlySoftStop) {\n callback();\n this.earlySoftStop = false;\n }\n }\n\n onModeChange(callback: (data: SetModeData) => void): void {\n this.modeChangeCallback = callback;\n for (const data of this.earlyModeChanges) callback(data);\n this.earlyModeChanges = [];\n }\n\n onApiKeyUpdate(callback: (data: ApiKeyUpdateData) => void): void {\n this.apiKeyUpdateCallback = callback;\n }\n\n onPullBranch(callback: (data: { branch: string }) => void): void {\n this.pullBranchCallback = callback;\n for (const data of this.earlyPullBranches) callback(data);\n this.earlyPullBranches = [];\n }\n\n onSpawnReview(callback: (data: SpawnReviewData) => void): void {\n this.spawnReviewCallback = callback;\n for (const data of this.earlySpawnReviews) callback(data);\n this.earlySpawnReviews = [];\n }\n\n /**\n * Report that a same-pod review child failed to spawn (fire-and-forget).\n * The server Ends the orphaned review session and falls back to a dedicated\n * review pod. sessionId is OUR (builder) session — the task-identity guard runs on\n * it; the review session is identified separately.\n */\n reportReviewSpawnFailure(reviewSessionId: string, error?: string): void {\n if (!this.socket) return;\n void this.call(\"reportReviewSpawnFailure\", {\n sessionId: this.config.sessionId,\n reviewSessionId,\n ...(error ? { error: error.slice(0, 2000) } : {}),\n }).catch(() => {});\n }\n\n /**\n * Ask the server to destroy and recreate this pod (fire-and-forget). The\n * agent calls this only when it has proven it cannot recover in place — the\n * shared `~/.claude` GCS FUSE mount is dead and no in-container action can\n * remount it. The server rate-limits the recycle and posts `reason` to the\n * card; old servers that don't know the method reject harmlessly, leaving\n * today's behavior (a failed turn with a chat warning).\n */\n requestWorkspaceRecycle(reason: string): void {\n if (!this.socket) return;\n void this.call(\"requestWorkspaceRecycle\", {\n sessionId: this.config.sessionId,\n reason: reason.slice(0, 2000),\n }).catch(() => {});\n }\n\n onSpawnTui(callback: (data: SpawnTuiData) => void): void {\n this.spawnTuiCallback = callback;\n for (const data of this.earlySpawnTuis) callback(data);\n this.earlySpawnTuis = [];\n }\n\n /** Register the on-demand usage-refresh handler; drains an early-buffered\n * `session:probeUsage` that arrived before the runner was ready. */\n onProbeUsage(callback: () => void): void {\n this.probeUsageCallback = callback;\n if (this.earlyProbeUsage) {\n this.earlyProbeUsage = false;\n callback();\n }\n }\n\n /**\n * Report that a same-pod TUI/shell child failed to spawn (fire-and-forget).\n * The server Ends the orphaned session — no fallback pod (unlike review).\n * sessionId is OUR (builder) session — the task-identity guard runs on it.\n */\n reportSessionSpawnFailure(spawnedSessionId: string, error?: string): void {\n if (!this.socket) return;\n void this.call(\"reportSessionSpawnFailure\", {\n sessionId: this.config.sessionId,\n spawnedSessionId,\n ...(error ? { error: error.slice(0, 2000) } : {}),\n }).catch(() => {});\n }\n\n onRunStartCommand(callback: () => void): void {\n this.runStartCommandCallback = callback;\n }\n\n // ── PTY relay (S5 Connected-TUI terminal) ──────────────────────────\n\n /**\n * Forward a raw chunk of terminal output to the S2 relay (fire-and-forget).\n * The first chunk creates the server-side scrollback ring, which is what\n * surfaces the terminal in the UI. `dims` seed/refresh the ring geometry.\n */\n sendPtyOutput(data: string, dims?: { cols: number; rows: number }): void {\n if (!this.socket) return;\n void this.call(\"ptyOutput\", {\n sessionId: this.config.sessionId,\n data,\n ...(dims ? { cols: dims.cols, rows: dims.rows } : {}),\n }).catch(() => {});\n }\n\n /**\n * Forward one compact chat-proxy event derived from the transcript JSONL to\n * the relay (fire-and-forget). Feeds the experimental chat PTY proxy ring.\n * Old servers that don't know the method reject harmlessly.\n */\n sendPtyChatEvent(event: PtyChatEventPayload): void {\n if (!this.socket) return;\n void this.call(\"ptyChatEvent\", {\n sessionId: this.config.sessionId,\n event,\n }).catch(() => {});\n }\n\n /**\n * Report that the interactive CLI process for this session has died and no\n * respawn is imminent (fire-and-forget). The server clears the scrollback\n * ring and broadcasts pty:ended so clients hide the Connected-TUI tab. Old\n * servers that don't know the method reject harmlessly.\n */\n sendPtyEnded(): void {\n if (!this.socket) return;\n void this.call(\"ptyEnded\", { sessionId: this.config.sessionId }).catch(() => {});\n }\n\n /**\n * Report the port this pod's in-pod PTY stream server bound to, or null when\n * it stopped (fire-and-forget). The server persists it so a viewer can be\n * handed a port-scoped tunnel URL and stream the TUI straight from the pod.\n * Old servers that don't know the method reject harmlessly — the session then\n * just stays on the relay transport.\n */\n reportPtyStream(port: number | null): void {\n if (!this.socket) return;\n void this.call(\"reportPtyStream\", {\n sessionId: this.config.sessionId,\n port,\n }).catch(() => {});\n }\n\n /** Subscribe to relayed keystrokes. Returns an unsubscribe fn. */\n onPtyInput(handler: (data: string) => void): () => void {\n this.ptyInputCallback = handler;\n return () => {\n if (this.ptyInputCallback === handler) this.ptyInputCallback = null;\n };\n }\n\n /** Subscribe to relayed (reconciled) terminal resizes. Returns an unsubscribe fn. */\n onPtyResize(handler: (cols: number, rows: number) => void): () => void {\n this.ptyResizeCallback = handler;\n return () => {\n if (this.ptyResizeCallback === handler) this.ptyResizeCallback = null;\n };\n }\n\n // ── Convenience methods (thin wrappers around call / emit) ─────────\n\n async emitStatus(status: string, reason?: string, questionText?: string): Promise<void> {\n this.lastEmittedStatus = status;\n // Await event flush (e.g. \"completed\") before reporting status change\n // so the API processes \"completed\" before \"idle\" — eliminates the\n // ordering race that caused duplicate completion message spam.\n await this.flushEvents();\n const payload = {\n sessionId: this.config.sessionId,\n status,\n ...(reason ? { reason } : {}),\n // Only sent with a pending TUI questionnaire (reason \"user_question\") so\n // the server can surface the real question text in the notification.\n ...(questionText ? { questionText } : {}),\n };\n const AWAIT_STATUSES = [\"idle\", \"waiting_for_input\", \"connected\"];\n if (AWAIT_STATUSES.includes(status)) {\n // Critical transition — server must process before agent blocks on waitForMessage()\n try {\n await this.call(\"reportAgentStatus\", payload);\n this.lastReportedStatus = status;\n } catch {\n // Best-effort — proceed even if status report fails.\n // Server-side forwardOrQueue has a DB cross-check fallback.\n }\n } else {\n void this.call(\"reportAgentStatus\", payload)\n .then(() => {\n this.lastReportedStatus = status;\n })\n .catch(() => {});\n }\n }\n\n postChatMessage(content: string, milestone?: AgentMilestone): void {\n if (!this.socket) return;\n if (this.suppressIfDuplicate(content)) return;\n void this.call(\"postAgentMessage\", {\n sessionId: this.config.sessionId,\n content,\n milestone,\n }).catch(() => {});\n }\n\n // Awaitable variant of postChatMessage for callers that need to guarantee\n // the message is acknowledged by the server before proceeding (e.g. before\n // aborting the session). Dedup still applies; a suppressed message resolves\n // immediately without hitting the wire.\n async postChatMessageAwait(content: string, milestone?: AgentMilestone): Promise<void> {\n if (!this.socket) return;\n if (this.suppressIfDuplicate(content)) return;\n try {\n await this.call(\"postAgentMessage\", {\n sessionId: this.config.sessionId,\n content,\n milestone,\n });\n } catch (err) {\n process.stderr.write(\n `[conveyor-agent] postChatMessageAwait failed: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n }\n }\n\n private suppressIfDuplicate(content: string): boolean {\n const d = this.checkAndTrackDuplicate(content);\n if (!d.duplicate) return false;\n process.stderr.write(\n `[dedup] Suppressed near-duplicate (matched: \"${d.matchedMessagePreview}\")\\n`,\n );\n return true;\n }\n\n // Exposed so `post_to_chat` can surface suppression back to the agent.\n checkAndTrackDuplicate(\n content: string,\n ): { duplicate: false } | { duplicate: true; matchedMessagePreview: string } {\n const now = Date.now();\n this.recentMessages = this.recentMessages.filter(\n (m) => now - m.timestamp < AgentConnection.DEDUP_WINDOW_MS,\n );\n const words = new Set(\n content\n .toLowerCase()\n .replace(/[^\\w\\s]/g, \"\")\n .split(/\\s+/)\n .filter((w) => w.length >= 3),\n );\n if (words.size === 0) return { duplicate: false };\n for (const recent of this.recentMessages) {\n let intersection = 0;\n for (const w of words) if (recent.words.has(w)) intersection++;\n const union = new Set([...words, ...recent.words]).size;\n if (union > 0 && intersection / union > AgentConnection.DEDUP_SIMILARITY_THRESHOLD) {\n return { duplicate: true, matchedMessagePreview: recent.preview };\n }\n }\n const max = AgentConnection.DEDUP_PREVIEW_LIMIT;\n const preview = content.length > max ? content.slice(0, max) + \"…\" : content;\n this.recentMessages.push({ words, timestamp: now, preview });\n if (this.recentMessages.length > 3) this.recentMessages.shift();\n return { duplicate: false };\n }\n\n /**\n * @param loopStatus overrides the status derived from the last emitted\n * runner status. SessionRunner passes it so an idle runner that still has\n * background work outstanding in the pod beats as `waiting` (→ `active` on\n * the wire) rather than `idle`, which would let the workspace activity\n * clock expire mid-gate. See connection/loop-lag.ts `heartbeatStatusFor`.\n *\n * Without an override the status comes from `loopStatusForRunnerStatus`, the\n * same total classifier SessionRunner uses, so both paths agree. This used to\n * be a partial map covering 5 of the 11 `AgentRunnerStatus` values with a\n * `?? \"active\"` fallback, which meant a parked runner (`waiting_for_input`,\n * `finished`, `error`, `stopping`, `disconnected`) beat as ACTIVE on every\n * no-arg call site — the reconnect paths below, and the shell/project/adhoc\n * runners, which never pass a loop status at all. That renewed the workspace\n * activity clock for an agent doing nothing, so the card stayed \"active\" and\n * its pod stayed up long past the project's inactivity window.\n */\n sendHeartbeat(loopLagMs?: number, loopStatus?: LoopStatus): void {\n if (!this.socket) return;\n const heartbeatStatus = heartbeatStatusFor(\n loopStatus ?? loopStatusForRunnerStatus(this.lastEmittedStatus),\n );\n void this.call(\"heartbeat\", {\n sessionId: this.config.sessionId,\n timestamp: new Date().toISOString(),\n status: heartbeatStatus,\n ...(loopLagMs !== undefined && loopLagMs > 0 ? { loopLagMs: Math.round(loopLagMs) } : {}),\n }).catch(() => {});\n }\n\n // ── Starvation-proof heartbeat worker ────────────────────────────────\n //\n // A worker thread with its own event loop + Socket.IO connection keeps the\n // v3 session lease renewed even when the MAIN loop is stalled (the failure\n // mode where a heavy gate got the session declared stranded and restarted\n // mid-run). Best-effort by design: any spawn/runtime failure just degrades\n // heartbeats to main-loop-only. See heartbeat-worker.ts for the policy.\n private heartbeatWorker: Worker | null = null;\n\n startHeartbeatWorker(sharedBuffer: SharedArrayBuffer, intervalMs = 30_000): void {\n if (this.heartbeatWorker) return;\n try {\n const workerUrl = new URL(\"./heartbeat-worker.js\", import.meta.url);\n // Under vitest/tsx the sibling is the .ts source — no compiled worker to\n // spawn. dist builds emit heartbeat-worker.js next to index/cli bundles.\n if (!existsSync(fileURLToPath(workerUrl))) {\n process.stderr.write(\n \"[conveyor-agent] heartbeat worker bundle not found — main-loop heartbeat only\\n\",\n );\n return;\n }\n const worker = new Worker(workerUrl, {\n workerData: {\n apiUrl: this.config.apiUrl,\n taskToken: this.config.taskToken,\n sessionId: this.config.sessionId,\n runnerMode: this.config.runnerMode ?? \"task\",\n sharedBuffer,\n intervalMs,\n },\n });\n worker.unref();\n worker.on(\"error\", (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] heartbeat worker error: ${message}\\n`);\n this.heartbeatWorker = null;\n });\n worker.on(\"exit\", (code) => {\n if (code !== 0) {\n process.stderr.write(`[conveyor-agent] heartbeat worker exited (code ${code})\\n`);\n }\n this.heartbeatWorker = null;\n });\n this.heartbeatWorker = worker;\n process.stderr.write(\"[conveyor-agent] heartbeat worker started\\n\");\n } catch (err) {\n process.stderr.write(\n `[conveyor-agent] heartbeat worker failed to start: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n this.heartbeatWorker = null;\n }\n }\n\n stopHeartbeatWorker(): void {\n const worker = this.heartbeatWorker;\n this.heartbeatWorker = null;\n if (worker) void worker.terminate();\n }\n\n emitModeChanged(agentMode?: AgentMode | null): void {\n this.sendEvent({ type: \"mode_changed\", agentMode });\n }\n\n async updateTaskFields(fields: {\n plan?: string;\n description?: string;\n }): Promise<{ ok: boolean; error?: string }> {\n if (!this.socket) return { ok: false, error: \"socket not connected\" };\n try {\n await this.call(\"updateTaskFields\", { sessionId: this.config.sessionId, ...fields });\n return { ok: true };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n }\n\n storeSessionId(sdkSessionId: string): void {\n void this.call(\"storeSessionId\", { sessionId: this.config.sessionId, sdkSessionId }).catch(\n () => {},\n );\n }\n\n /** Report the full current set of runtime-discovered listening ports.\n * Throws on failure so the PortDiscovery poller can retry on its next\n * tick (a swallowed error here would silently drop the delta). */\n async reportDiscoveredPorts(ports: WorkspaceDiscoveredPort[]): Promise<void> {\n await this.call(\"reportDiscoveredPorts\", { sessionId: this.config.sessionId, ports });\n }\n\n /** Boot-milestone report over the socket — the codespace-parity fallback\n * for the GKE pod bootstrap-token route. Fire-and-forget: a failed report\n * must never delay or fail the boot path. */\n reportBootMilestone(key: string): void {\n void this.call(\"reportBootMilestone\", { sessionId: this.config.sessionId, key }).catch(\n () => {},\n );\n }\n\n // ── Typing indicators ───────────────────────────────────────────────\n\n sendTypingStart(): void {\n this.sendEvent({ type: \"agent_typing_start\" });\n }\n\n sendTypingStop(): void {\n this.sendEvent({ type: \"agent_typing_stop\" });\n }\n\n // ── RPC convenience wrappers (v6 compat, will migrate to call()) ───\n\n emitRateLimitPause(resetsAt: string): void {\n this.sendEvent({ type: \"rate_limit_update\", resetsAt });\n }\n\n updateStatus(status: string): void {\n this.emitStatus(status);\n }\n\n /**\n * The session's key hit a hard usage cap — ask the server to stamp it\n * limited and hand back the best remaining key's credential env (or a\n * requeue confirmation when none is left). Awaited: the caller swaps\n * credentials and resumes on success, so it needs the real response.\n */\n async cycleCodingAgentKey(\n rateLimitType: string,\n resetsAt?: string,\n ): Promise<\n | { cycled: true; label: string; envVars: Record<string, string> }\n | { cycled: false; resetsAt: string }\n > {\n return await this.call(\"cycleCodingAgentKey\", {\n sessionId: this.config.sessionId,\n rateLimitType,\n ...(resetsAt ? { resetsAt } : {}),\n });\n }\n\n // ── Question handling ──────────────────────────────────────────────\n\n async askUserQuestion(questions: AgentQuestion[]): Promise<Record<string, string>> {\n const questionText = questions\n .map(\n (q) =>\n `**${q.header}**\\n${q.question}${q.options.length ? \"\\n\" + q.options.map((o) => `- ${o.label}: ${o.description}`).join(\"\\n\") : \"\"}`,\n )\n .join(\"\\n\\n\");\n\n const requestId = crypto.randomUUID();\n\n // Race the RPC callback against the room-event fallback.\n // If the socket disconnects/reconnects while waiting, the RPC callback is\n // lost but the room event (emitted after reconnect to the session room)\n // will still deliver the answer.\n const roomEventPromise = new Promise<Record<string, string>>((resolve) => {\n this.pendingAnswerResolvers.set(requestId, resolve);\n });\n\n const rpcPromise = this.call(\"askUserQuestion\", {\n sessionId: this.config.sessionId,\n question: questionText,\n requestId,\n questions,\n }).then((res) => res.answers);\n\n try {\n return await Promise.race([rpcPromise, roomEventPromise]);\n } finally {\n this.pendingAnswerResolvers.delete(requestId);\n }\n }\n\n // ── Typed service method wrappers ───────────────────────────────────\n\n getTaskProperties(): Promise<{\n plan?: string;\n storyPointId?: string;\n title?: string;\n riskLevel?: \"critical\" | \"high\" | \"medium\" | \"low\";\n }> {\n return this.call(\"getTaskProperties\", { sessionId: this.config.sessionId });\n }\n\n triggerIdentification(): Promise<{ identified: boolean }> {\n return this.call(\"triggerIdentification\", { sessionId: this.config.sessionId });\n }\n\n handoffToImplementer(payload: {\n storyPoints?: number;\n message?: string;\n }): Promise<{ handedOff: boolean; agentName?: string; model?: string; reason?: string }> {\n return this.call(\"handoffToImplementer\", {\n sessionId: this.config.sessionId,\n ...payload,\n });\n }\n\n async refreshAuthToken(): Promise<boolean> {\n const result = await this.refreshFromBootstrap();\n return result.refreshedClaude;\n }\n\n /**\n * Refresh the in-process `CONVEYOR_TASK_TOKEN` from the bootstrap endpoint.\n * Returns true if a new token was applied. Rate-limited locally to once per\n * 60s so a tight auth-rejected loop can't hammer the bootstrap endpoint —\n * the server enforces the same window via `lastBootstrapAt`.\n */\n private lastTaskTokenRefreshAt = 0;\n async refreshTaskTokenFromBootstrap(): Promise<boolean> {\n const result = await this.refreshFromBootstrap();\n return result.refreshedTaskToken;\n }\n\n private refreshFromBootstrap(): Promise<{\n refreshedClaude: boolean;\n refreshedTaskToken: boolean;\n }> {\n const none = Promise.resolve({ refreshedClaude: false, refreshedTaskToken: false });\n // Claudespace pods carry POD_BOOTSTRAP_TOKEN (retained by the entrypoint as\n // the credential-refresh key); the legacy GitHub Codespaces path keys on\n // instance name + CONVEYOR_BOOTSTRAP_TOKEN.\n const podBootstrapToken = process.env.POD_BOOTSTRAP_TOKEN;\n const codespaceName = process.env.CODESPACE_NAME;\n const apiUrl = this.config.apiUrl;\n if (!apiUrl || (!podBootstrapToken && !codespaceName)) {\n return none;\n }\n const now = Date.now();\n if (now - this.lastTaskTokenRefreshAt < 60_000) {\n return none;\n }\n this.lastTaskTokenRefreshAt = now;\n if (podBootstrapToken) {\n return this.refreshFromV3Bootstrap(apiUrl, podBootstrapToken);\n }\n if (!codespaceName) return none;\n return this.refreshFromCodespaceBootstrap(apiUrl, codespaceName);\n }\n\n /** Legacy GitHub Codespaces refresh path — keys on instance name. */\n private async refreshFromCodespaceBootstrap(\n apiUrl: string,\n codespaceName: string,\n ): Promise<{ refreshedClaude: boolean; refreshedTaskToken: boolean }> {\n const bootstrapToken = process.env.CONVEYOR_BOOTSTRAP_TOKEN;\n const result = await fetchBootstrap({\n apiUrl,\n instanceName: codespaceName,\n bootstrapToken,\n // Do not retry on http errors during a runtime refresh — a 401/403\n // means the token is consumed / session terminal and retrying won't\n // help. Network/timeout still retry inside fetchBootstrap.\n });\n if (!result.ok) return { refreshedClaude: false, refreshedTaskToken: false };\n const previousTaskToken = process.env.CONVEYOR_TASK_TOKEN;\n applyBootstrapToEnv(result.config);\n // Same reason as the v3 path below: env writes never reach the already\n // running CLI, so the file copies carry the fresh token.\n const env = result.config.envVars ?? {};\n syncGithubTokenFiles(env.CONVEYOR_GITHUB_TOKEN ?? env.GH_TOKEN ?? env.GITHUB_TOKEN);\n const refreshedTaskToken =\n result.config.mode !== \"project\" &&\n Boolean(result.config.taskToken) &&\n result.config.taskToken !== previousTaskToken;\n if (refreshedTaskToken && result.config.taskToken) {\n this.config.taskToken = result.config.taskToken;\n // Update socket auth so the next reconnect cycle uses the fresh token.\n if (this.socket) {\n const auth = this.socket.auth as Record<string, unknown> | undefined;\n if (auth && typeof auth === \"object\") {\n auth.taskToken = result.config.taskToken;\n }\n }\n this.heartbeatWorker?.postMessage({ taskToken: result.config.taskToken });\n }\n const refreshedClaude = Boolean(result.config.envVars?.CLAUDE_CODE_OAUTH_TOKEN);\n return { refreshedClaude, refreshedTaskToken };\n }\n\n /**\n * v3 refresh: re-fetch the full bootstrap bundle from the pod's bound v3\n * route and swap the credentials in place. The GitHub installation token\n * dies at ~1h and the sessionJwt at 24h; re-polling the bootstrap GET with\n * the same pod token is the designed refresh mechanism.\n */\n private async refreshFromV3Bootstrap(\n apiUrl: string,\n bootstrapToken: string,\n ): Promise<{ refreshedClaude: boolean; refreshedTaskToken: boolean }> {\n // maxWaitMs 0: a bound pod answers 200 on the first request; a 204\n // (unbound — should not happen at refresh time) or any HTTP/network error\n // must fail the refresh, not park the agent in a poll loop. The one\n // exception is a transient 429 (shared Cloud NAT IP vs podBootstrapLimiter),\n // which pollBundleWithRateLimitRetry retries before giving up.\n const bundle = await this.pollBundleWithRateLimitRetry(apiUrl, bootstrapToken);\n if (!bundle) {\n return { refreshedClaude: false, refreshedTaskToken: false };\n }\n\n const previousTaskToken = process.env.CONVEYOR_TASK_TOKEN;\n for (const [key, value] of Object.entries(bundle.envVars ?? {})) {\n process.env[key] = value;\n }\n if (bundle.githubToken) {\n process.env.CONVEYOR_GITHUB_TOKEN = bundle.githubToken;\n // Independent of the runner's own refreshGithubToken RPC path: this one\n // still lands when the RPC fails, and the file copies are the only ones\n // the long-parked `claude` CLI can read (see boot/git-credential.ts).\n syncGithubTokenFiles(bundle.githubToken);\n }\n if (bundle.anthropicKey) process.env.ANTHROPIC_API_KEY = bundle.anthropicKey;\n if (bundle.gcpToken) process.env.CLOUDSDK_AUTH_ACCESS_TOKEN = bundle.gcpToken;\n\n const refreshedTaskToken =\n Boolean(bundle.sessionJwt) && bundle.sessionJwt !== previousTaskToken;\n if (refreshedTaskToken) {\n process.env.CONVEYOR_TASK_TOKEN = bundle.sessionJwt;\n this.config.taskToken = bundle.sessionJwt;\n // Update socket auth so the next reconnect cycle uses the fresh token.\n if (this.socket) {\n const auth = this.socket.auth as Record<string, unknown> | undefined;\n if (auth && typeof auth === \"object\") {\n auth.taskToken = bundle.sessionJwt;\n }\n }\n this.heartbeatWorker?.postMessage({ taskToken: bundle.sessionJwt });\n }\n const refreshedClaude = Boolean(bundle.envVars?.CLAUDE_CODE_OAUTH_TOKEN);\n return { refreshedClaude, refreshedTaskToken };\n }\n\n /**\n * Poll the bootstrap bundle once (maxWaitMs 0), retrying only on a transient\n * 429 (standby-pool pods share one Cloud NAT IP against podBootstrapLimiter)\n * with a short backoff. Returns null when the refresh should be abandoned —\n * a non-429 error, or 429s past the retry budget — so the caller no-ops\n * instead of parking a RUNNING pod in a poll loop.\n */\n private async pollBundleWithRateLimitRetry(\n apiUrl: string,\n bootstrapToken: string,\n ): Promise<Awaited<ReturnType<typeof pollUntilBound>> | null> {\n const retryDelaysMs = [1_000, 3_000];\n for (let attempt = 0; ; attempt++) {\n try {\n return await pollUntilBound({ apiUrl, bootstrapToken, maxWaitMs: 0 });\n } catch (err) {\n const isRateLimited = err instanceof PollUntilBoundHttpError && err.status === 429;\n if (!isRateLimited || attempt >= retryDelaysMs.length) {\n return null;\n }\n await new Promise<void>((resolve) => {\n setTimeout(resolve, retryDelaysMs[attempt]);\n });\n }\n }\n }\n\n // ── Event buffering ────────────────────────────────────────────────\n\n sendEvent(event: { type: string; [key: string]: unknown }): void {\n if (!this.socket) return;\n this.enqueueEvents([{ event }], false);\n }\n\n /** Append (or, on `toFront`, prepend for a failed-flush re-queue) events to\n * the buffer, then cap + arm the flush timer. Single owner of the overflow\n * policy so append and re-queue can't diverge on the drop accounting. */\n private enqueueEvents(\n entries: Array<{ event: { type: string; [key: string]: unknown } }>,\n toFront: boolean,\n ): void {\n if (toFront) this.eventBuffer.unshift(...entries);\n else this.eventBuffer.push(...entries);\n // Cap the buffer so a long disconnect can't accumulate an unbounded replay\n // storm. Drop oldest on overflow (keeps the most recent state).\n while (this.eventBuffer.length > MAX_EVENT_BUFFER) {\n this.eventBuffer.shift();\n this.droppedEventCount++;\n if (this.droppedEventCount === 1 || this.droppedEventCount % 500 === 0) {\n process.stderr.write(\n `[conveyor-agent] eventBuffer overflow — dropped ${this.droppedEventCount} event(s) (cap: ${MAX_EVENT_BUFFER})\\n`,\n );\n }\n }\n if (this.socket && !this.flushTimer) {\n this.flushTimer = setTimeout(() => void this.flushEvents(), EVENT_BATCH_MS);\n }\n }\n\n async flushEvents(): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n if (!this.socket || this.eventBuffer.length === 0) return;\n const entries = this.eventBuffer;\n this.eventBuffer = [];\n const events = entries.map((entry) => entry.event);\n try {\n // Await so callers (emitStatus) can guarantee ordering.\n await this.call(\"emitAgentEvent\", { sessionId: this.config.sessionId, events });\n } catch {\n // The RPC failed — typically a flush that raced a disconnect. Re-queue the\n // batch instead of silently dropping it; a reconnect (or the next\n // sendEvent) retries. this.call already rides out a short reconnect window\n // before rejecting, so this is not a tight spin loop.\n this.requeueFailedEvents(entries);\n }\n }\n\n /** Put a failed flush's events back at the FRONT of the buffer, preserving\n * order, via the shared cap-and-arm path. */\n private requeueFailedEvents(\n entries: Array<{ event: { type: string; [key: string]: unknown } }>,\n ): void {\n this.enqueueEvents(entries, true);\n }\n}\n","import type { BootstrapBundle } from \"./bootstrap-bundle-types.js\";\nimport { sleep } from \"../utils/sleep.js\";\n\nexport interface PollUntilBoundOptions {\n apiUrl: string;\n bootstrapToken: string;\n pollIntervalMs?: number;\n maxWaitMs?: number;\n}\n\n/** Thrown by `pollUntilBound` on a non-200/204 response; carries the HTTP\n * status so callers can distinguish transient conditions (e.g. 429) from\n * fatal ones (e.g. 401/403) without string-matching the message. */\nexport class PollUntilBoundHttpError extends Error {\n constructor(public readonly status: number) {\n super(`pollUntilBound got unexpected status ${status}`);\n this.name = \"PollUntilBoundHttpError\";\n }\n}\n\nexport async function pollUntilBound(opts: PollUntilBoundOptions): Promise<BootstrapBundle> {\n const pollIntervalMs = opts.pollIntervalMs ?? 2_000;\n const maxWaitMs = opts.maxWaitMs ?? 30 * 60 * 1_000;\n const deadline = Date.now() + maxWaitMs;\n\n while (true) {\n const response = await fetch(`${opts.apiUrl}/api/v3/pods/bootstrap`, {\n headers: { Authorization: `Bearer ${opts.bootstrapToken}` },\n });\n\n if (response.status === 200) {\n return (await response.json()) as BootstrapBundle;\n }\n if (response.status === 204) {\n if (Date.now() >= deadline) {\n throw new Error(`pollUntilBound timed out after ${maxWaitMs}ms waiting for pod bind`);\n }\n await sleep(pollIntervalMs);\n continue;\n }\n throw new PollUntilBoundHttpError(response.status);\n }\n}\n","/**\n * Predicate for a PERSISTENT authorization denial from the API — the session's\n * user is not a member of the project (AgentSessionService authorizes every RPC\n * against project membership and disables service-level access). The API's ACL\n * layer (quickdraw-core) throws \"Insufficient permissions\"; a missing/invalid\n * identity throws \"Authentication required\".\n *\n * This is deliberately DISTINCT from `AgentConnection.looksLikeAuthError` (stale\n * token / expired session), which a token refresh CAN fix. A permission denial\n * cannot be fixed by retrying or refreshing — the runner parks cleanly instead\n * of crash-looping the process (which would burn the 3× supervisor restarts on\n * an outcome that never changes). See `session-runner.ts` connect().\n */\nexport function isPermissionDeniedError(err: unknown): boolean {\n const message = err instanceof Error ? err.message : String(err);\n return /insufficient permissions|authentication required/i.test(message);\n}\n","/** Minimal structured logger for conveyor-agent (writes to stderr). */\nexport function createServiceLogger(service: string) {\n const prefix = `[conveyor-agent:${service}]`;\n return {\n info(message: string, data?: Record<string, unknown>): void {\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n process.stderr.write(`${prefix} ${message}${extra}\\n`);\n },\n warn(message: string, data?: Record<string, unknown>): void {\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n process.stderr.write(`${prefix} WARN ${message}${extra}\\n`);\n },\n error(message: string, data?: Record<string, unknown>): void {\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n process.stderr.write(`${prefix} ERROR ${message}${extra}\\n`);\n },\n };\n}\n","import { execFile } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { promisify } from \"node:util\";\nimport { workbenchEnabled } from \"../workbench/mode.js\";\nimport { getWorkbenchClient } from \"../workbench/client.js\";\nimport {\n type GithubTokenFileSync,\n gitCredentialHelper,\n syncGithubTokenFiles,\n writeGitCredential,\n} from \"../boot/git-credential.js\";\n\n// EVERY git call in this file is async (`execFile`, no shell). `execSync`\n// freezes the single Node event loop, which starves the agent's socket.io\n// heartbeat — the API's stall detection then restarts the session, tearing\n// down whatever the agent was doing. This is not hypothetical: the periodic\n// WIP flush used to run `git status`/`git add -A`/`git stash create`\n// synchronously with no timeout, and on an IO-starved pod (a heavy test gate\n// hammering the same disk) a single tick blocked the loop for 40+ minutes —\n// the execution log went silent and the socket reconnected on attempt 1 the\n// moment the stuck call finally returned. Awaiting a child process instead\n// keeps the loop free to answer pings while git grinds.\n//\n// Rules for this file:\n// - no execSync, ever;\n// - every call has a timeout (a hung git can't wedge a flush tick forever);\n// - args are passed as arrays (no shell quoting surprises).\nconst execFileAsync = promisify(execFile);\n\nexport const GIT_TIMEOUT_MS = 60_000;\n// Staging/stashing a large dirty tree is legitimately slow on a loaded pod —\n// give the IO-heavy calls more headroom before declaring them hung.\nconst GIT_SLOW_TIMEOUT_MS = 120_000;\n// `git status -z` output on a very dirty tree can exceed the 1MB default.\nconst GIT_MAX_BUFFER = 16 * 1024 * 1024;\n\n/** Run git with args (no shell), bounded by a timeout. Returns trimmed stdout.\n * Throws on non-zero exit or timeout — callers decide the failure policy.\n * Split-mode pods: the repo lives in the workbench container, so the call\n * routes over the launcher (same argv/no-shell/timeout contract). */\nasync function git(cwd: string, args: string[], timeoutMs = GIT_TIMEOUT_MS): Promise<string> {\n if (workbenchEnabled()) {\n const { stdout } = await getWorkbenchClient().execFile(\"git\", args, {\n cwd,\n timeout: timeoutMs,\n maxBuffer: GIT_MAX_BUFFER,\n });\n return stdout.trim();\n }\n const { stdout } = await execFileAsync(\"git\", args, {\n cwd,\n timeout: timeoutMs,\n maxBuffer: GIT_MAX_BUFFER,\n });\n return stdout.toString().trim();\n}\n\n/** Ensure the repo is on the expected task branch, creating it from\n * `origin/<baseBranch>` and pushing (`-u`) when it doesn't exist on origin\n * yet — the create-from-base responsibility that used to live in the\n * entrypoint's `sync_task_branch_to_repo`. Returns true on success, false on\n * failure (including when the branch is missing on origin and no\n * `baseBranch` was supplied to create it from). */\nexport async function ensureOnTaskBranch(\n cwd: string,\n taskBranch: string,\n baseBranch?: string,\n): Promise<boolean> {\n if (!taskBranch) return true;\n try {\n // Already on the task branch — no-op. Do NOT re-fetch/`checkout -B`: that\n // force-moves the branch ref to origin, silently orphaning any local\n // commits/working-tree state ahead of origin (reflog-only recovery). This\n // subsystem exists to not lose work, so preserving an already-correct\n // checkout takes priority over resyncing to origin.\n if ((await getCurrentBranch(cwd)) === taskBranch) return true;\n // Fetch the task branch into a local ref if it exists on origin.\n let existsOnOrigin = true;\n try {\n await git(cwd, [\n \"fetch\",\n \"origin\",\n `+refs/heads/${taskBranch}:refs/remotes/origin/${taskBranch}`,\n ]);\n } catch (err) {\n if (String(err).includes(\"couldn't find remote ref\")) existsOnOrigin = false;\n else throw err;\n }\n if (existsOnOrigin) {\n // Use `checkout -B` which creates or resets the local branch to track\n // origin. This handles the detached-HEAD case (entrypoint.sh leaves the\n // repo detached after `git reset --hard origin/<branch>`) and the case\n // where a stale local branch exists pointing at a different SHA.\n await git(cwd, [\"checkout\", \"-B\", taskBranch, `origin/${taskBranch}`], 30_000);\n process.stderr.write(`[conveyor-agent] Checked out task branch ${taskBranch}\\n`);\n return true;\n }\n // Missing on origin — create from base and push -u so tracking is set.\n if (!baseBranch) {\n process.stderr.write(\n `[conveyor-agent] Warning: task branch ${taskBranch} missing on origin and no base branch given\\n`,\n );\n return false;\n }\n await git(cwd, [\n \"fetch\",\n \"origin\",\n `+refs/heads/${baseBranch}:refs/remotes/origin/${baseBranch}`,\n ]);\n await git(cwd, [\"checkout\", \"-B\", taskBranch, `origin/${baseBranch}`], 30_000);\n await git(cwd, [\"push\", \"-u\", \"origin\", taskBranch], 30_000);\n process.stderr.write(\n `[conveyor-agent] Created task branch ${taskBranch} from origin/${baseBranch} and pushed\\n`,\n );\n return true;\n } catch {\n process.stderr.write(`[conveyor-agent] Warning: ensureOnTaskBranch(${taskBranch}) failed\\n`);\n return false;\n }\n}\n\n/** Returns true if the working tree has uncommitted changes (staged or unstaged). */\nexport async function hasUncommittedChanges(cwd: string): Promise<boolean> {\n const status = await git(cwd, [\"status\", \"--porcelain\"], GIT_SLOW_TIMEOUT_MS);\n return status.length > 0;\n}\n\n/** Returns the current branch name, or null if on detached HEAD. */\nexport async function getCurrentBranch(cwd: string): Promise<string | null> {\n try {\n const branch = await git(cwd, [\"branch\", \"--show-current\"]);\n return branch || null;\n } catch {\n return null;\n }\n}\n\n/** Returns true if there are committed changes that haven't been pushed to origin. */\nexport async function hasUnpushedCommits(cwd: string): Promise<boolean> {\n try {\n const currentBranch = await getCurrentBranch(cwd);\n if (!currentBranch) return false;\n\n try {\n await git(cwd, [\"rev-parse\", `origin/${currentBranch}`]);\n } catch {\n try {\n await git(cwd, [\"rev-parse\", \"HEAD\"]);\n return true;\n } catch {\n return false;\n }\n }\n\n const ahead = await git(cwd, [\n \"rev-list\",\n \"--count\",\n \"HEAD\",\n \"--not\",\n `origin/${currentBranch}`,\n ]);\n return parseInt(ahead, 10) > 0;\n } catch {\n return false;\n }\n}\n\n/** Stage all changes and create a commit. Returns the commit hash if successful. */\nexport async function stageAndCommit(cwd: string, message: string): Promise<string | null> {\n try {\n await git(cwd, [\"add\", \"-A\"], GIT_SLOW_TIMEOUT_MS);\n\n if (!(await hasUncommittedChanges(cwd))) return null;\n\n await git(cwd, [\"commit\", \"-m\", message], GIT_SLOW_TIMEOUT_MS);\n\n return await git(cwd, [\"rev-parse\", \"HEAD\"]);\n } catch {\n return null;\n }\n}\n\n/** Does a caught git error carry auth/authorization markers (or a kill/timeout,\n * which we treat as auth so the token-refresh retry fires)? Shared by the\n * force-with-lease guard and `isAuthError`'s dry-run inspection. */\nfunction errLooksLikeAuth(err: unknown): boolean {\n if ((err as { killed?: boolean }).killed) return true;\n const stderr = (err as { stderr?: Buffer | string }).stderr?.toString() ?? \"\";\n const stdout = (err as { stdout?: Buffer | string }).stdout?.toString() ?? \"\";\n const msg = stderr || stdout || (err instanceof Error ? err.message : \"\");\n return /authentication|authorization|403|401|token/i.test(msg);\n}\n\nasync function tryPush(cwd: string, branch: string, skipVerify = false): Promise<boolean> {\n const noVerify = skipVerify ? [\"--no-verify\"] : [];\n try {\n await git(cwd, [\"push\", ...noVerify, \"origin\", branch], 30_000);\n return true;\n } catch (err) {\n // Falling back to --force-with-lease on the REAL task branch rewrites remote\n // history — never do it silently, and never for an auth failure (forcing\n // can't fix that and would be pure downside; the caller refreshes the token\n // and retries). --force-with-lease still refuses if the remote moved beyond\n // our tracked ref, so a genuine non-fast-forward is the only case it helps.\n if (errLooksLikeAuth(err)) return false;\n process.stderr.write(\n `[conveyor-agent] Plain push of ${branch} failed — retrying with --force-with-lease\\n`,\n );\n try {\n await git(cwd, [\"push\", ...noVerify, \"--force-with-lease\", \"origin\", branch], 30_000);\n return true;\n } catch {\n return false;\n }\n }\n}\n\nasync function isAuthError(cwd: string): Promise<boolean> {\n try {\n await git(cwd, [\"push\", \"--dry-run\"], 30_000);\n return false;\n } catch (err: unknown) {\n return errLooksLikeAuth(err);\n }\n}\n\nexport interface RefreshedGitCredential {\n username: string;\n secret: string;\n cloneUrl?: string;\n}\n\n/** What a credential refresh actually managed to write. */\nexport interface GitCredentialUpdate {\n /** Both the credential file and the helper config are current. */\n ok: boolean;\n /** The credential store file was rewritten with the new secret. */\n storeWritten: boolean;\n /** `credential.helper` in the repo's local config points at our helper. */\n helperConfigured: boolean;\n /** Why the update fell short, when it did. Never carries the secret. */\n error?: string;\n}\n\nfunction credentialErrorText(err: unknown): string {\n const raw = err instanceof Error ? err.message : String(err);\n // A failing git command can echo the remote URL, which carries the token.\n return raw.replace(/\\/\\/[^@\\s]+@/g, \"//***@\");\n}\n\n/**\n * Refresh pod-local auth without putting the secret in Git config or argv.\n *\n * Never throws — a refresh runs on timers and inside push retries, where an\n * exception would take out the caller's real work. It no longer swallows the\n * failure either: the returned result says exactly which half is current, so\n * `refresh_github_token` can report the truth instead of claiming success over\n * an empty credential store.\n */\nexport async function updateRemoteCredential(\n cwd: string,\n credential: RefreshedGitCredential,\n): Promise<GitCredentialUpdate> {\n const result: GitCredentialUpdate = { ok: false, storeWritten: false, helperConfigured: false };\n try {\n const currentUrl = await git(cwd, [\"remote\", \"get-url\", \"origin\"]);\n const cloneUrl = credential.cloneUrl ?? currentUrl;\n const normalizedUrl = writeGitCredential(cwd, cloneUrl, credential);\n result.storeWritten = true;\n if (currentUrl !== normalizedUrl) {\n await git(cwd, [\"remote\", \"set-url\", \"origin\", normalizedUrl]);\n }\n await git(cwd, [\"config\", \"--local\", \"credential.helper\", gitCredentialHelper(cwd)]);\n result.helperConfigured = true;\n result.ok = true;\n } catch (err) {\n result.error = credentialErrorText(err);\n }\n return result;\n}\n\n/** Everything one token refresh wrote: the git credential and the token files. */\nexport interface TokenRefreshResult {\n credential: GitCredentialUpdate;\n files: GithubTokenFileSync;\n}\n\n/** Compatibility alias for the existing refreshGithubToken RPC. */\nexport async function updateRemoteToken(cwd: string, token: string): Promise<TokenRefreshResult> {\n const username = process.env.CONVEYOR_GIT_USERNAME || \"x-access-token\";\n const cloneUrl = process.env.CONVEYOR_GIT_CLONE_URL || undefined;\n const credential = await updateRemoteCredential(cwd, { username, secret: token, cloneUrl });\n process.env.CONVEYOR_GIT_SECRET = token;\n // Refresh the file-based copies too. Setting process.env here only reaches\n // children this process spawns LATER — the already-running `claude` CLI\n // keeps its boot-time value forever, so `gh` and the agent's shell can only\n // get a current token from a file.\n const files = syncGithubTokenFiles(token);\n return { credential, files };\n}\n\n/**\n * Prove the pod can authenticate to origin right now.\n *\n * `ls-remote` walks the whole chain in one call — the configured helper, the\n * credential it serves, and GitHub's verdict on the token — so it is the only\n * check that can tell a successful write from a working credential.\n */\nexport async function verifyGitCredential(\n cwd: string,\n): Promise<{ ok: boolean; error?: string }> {\n try {\n await git(cwd, [\"ls-remote\", \"--heads\", \"origin\"], 30_000);\n return { ok: true };\n } catch (err) {\n return { ok: false, error: credentialErrorText(err) };\n }\n}\n\n// ── WIP snapshot ref ────────────────────────────────────────────────────\n//\n// Crash protection without polluting the task branch: uncommitted work is\n// captured as a stash-shaped commit (`git stash create` — does not touch\n// HEAD, the index, or the working tree) and force-pushed to a dedicated\n// `conveyor-wip/<branch>` ref. Real (intentional) commits are still pushed\n// to the task branch itself. On a fresh pod, `restoreWipSnapshot` re-applies\n// the snapshot when the branch head matches; once the tree is clean the\n// stale remote ref is deleted.\n\n/** The remote ref that holds the WIP snapshot for a task branch. */\nexport function wipRefForBranch(branch: string): string {\n return `conveyor-wip/${branch}`;\n}\n\n/** cwd values whose remote WIP ref WE created, or that we successfully restored\n * into the working tree — safe to overwrite with a fresh snapshot or drop once\n * the tree is clean. */\nconst wipRefPushed = new Set<string>();\n\n/** cwd values whose remote WIP ref holds work we could NOT get into the working\n * tree — a stale 3-way conflict, an error mid-restore, or a transient fetch\n * failure that leaves the ref state unknown. The ref must be preserved for\n * manual recovery: never dropped, and never force-pushed over by a fresh\n * snapshot (which would only contain the current head's changes, silently\n * clobbering the unrestored work). Cleared once a later restore succeeds. */\nconst wipRefPreserved = new Set<string>();\n\n/**\n * Capture the working tree + index (including untracked files) as a\n * stash-shaped commit WITHOUT moving HEAD or dirtying history. The index is\n * staged so untracked files are included, then restored so the agent's\n * `git status` view — including whatever it had staged mid-turn — is unchanged.\n *\n * The snapshot runs concurrently with a live agent turn, so it must restore the\n * agent's EXACT index, not blanket-`reset` to HEAD: a bare `git reset` would\n * silently unstage the agent's own in-progress staging. We record the index as\n * a tree first and `read-tree` it back afterwards (no working-tree changes).\n * `write-tree` fails on an unmerged index (mid-conflict) — bail rather than\n * risk corrupting the agent's conflict resolution.\n */\nasync function createWipSnapshot(cwd: string, message: string): Promise<string | null> {\n let savedIndexTree: string;\n try {\n savedIndexTree = await git(cwd, [\"write-tree\"], GIT_SLOW_TIMEOUT_MS);\n } catch {\n // Unmerged index (mid-conflict) or a git error — don't touch the index.\n return null;\n }\n try {\n await git(cwd, [\"add\", \"-A\"], GIT_SLOW_TIMEOUT_MS);\n const sha = await git(cwd, [\"stash\", \"create\", message], GIT_SLOW_TIMEOUT_MS);\n return sha || null;\n } catch {\n return null;\n } finally {\n try {\n // Restore the agent's exact staged state (index only — the working tree\n // is left untouched by add/stash-create, so this fully reproduces the\n // pre-snapshot `git status`).\n await git(cwd, [\"read-tree\", savedIndexTree], GIT_SLOW_TIMEOUT_MS);\n } catch {\n // best effort\n }\n }\n}\n\nasync function tryPushRefspec(cwd: string, refspec: string, force = false): Promise<boolean> {\n try {\n // --no-verify: a WIP snapshot to a throwaway conveyor-wip/* ref is a machine\n // crash-protection push, not a real branch update — it must never run the\n // pre-push quality gate (lint/typecheck/test).\n const forceArgs = force ? [\"--force\"] : [];\n await git(cwd, [\"push\", \"--no-verify\", ...forceArgs, \"origin\", refspec], 30_000);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function refreshRemoteToken(\n cwd: string,\n refreshToken?: () => Promise<string | undefined>,\n): Promise<void> {\n if (!refreshToken) return;\n try {\n const token = await refreshToken();\n if (token) {\n await updateRemoteToken(cwd, token);\n process.env.GITHUB_TOKEN = token;\n process.env.GH_TOKEN = token;\n }\n } catch {\n // best effort — proceed with existing token\n }\n}\n\n/**\n * Re-apply a WIP snapshot pushed by a previous pod of this task. When the\n * snapshot was taken on the current HEAD, this is a plain re-apply. When the\n * branch advanced past the snapshot (review commits, a dev merge, another\n * pod), the snapshot is 3-way applied onto the new head so newer remote work\n * AND the WIP both land. Only a genuine line-level conflict refuses\n * (\"stale\") — the wip ref is kept on origin in that case so nothing is lost:\n * git fetch origin refs/heads/conveyor-wip/<branch> && git stash apply FETCH_HEAD\n */\nexport async function restoreWipSnapshot(\n cwd: string,\n branch: string,\n): Promise<\"applied\" | \"stale\" | \"none\" | \"failed\"> {\n if (!branch) return \"none\";\n const ref = wipRefForBranch(branch);\n try {\n await git(cwd, [\"fetch\", \"origin\", `+refs/heads/${ref}:refs/remotes/origin/${ref}`]);\n } catch (err) {\n // Distinguish \"the ref genuinely doesn't exist\" from \"the fetch failed\n // transiently\". Only the former is a true \"nothing to restore\" — treating a\n // transient network failure as absent lets the first flush force-push a\n // fresh snapshot over the never-restored ref, silently losing the prior\n // pod's work. On a transient failure, preserve the ref and report failure.\n if (isMissingRefError(err)) return \"none\";\n wipRefPreserved.add(cwd);\n return \"failed\";\n }\n try {\n const sha = await git(cwd, [\"rev-parse\", `refs/remotes/origin/${ref}`]);\n // First parent of a stash-shaped commit is the HEAD it was created on.\n const parent = await git(cwd, [\"rev-parse\", `${sha}^`]);\n const head = await git(cwd, [\"rev-parse\", \"HEAD\"]);\n if (parent !== head) {\n // Branch moved since the snapshot. Try the 3-way apply (the stash\n // commit's first parent is the merge base, so git can transplant the\n // WIP onto the new head); back out cleanly on conflict and keep the\n // origin ref for manual recovery.\n try {\n await git(cwd, [\"stash\", \"apply\", sha], GIT_SLOW_TIMEOUT_MS);\n // Applied — the ref's content is now in the working tree, so the ref is\n // redundant and may be dropped/overwritten by the next flush.\n wipRefPushed.add(cwd);\n wipRefPreserved.delete(cwd);\n return \"applied\";\n } catch {\n try {\n await git(cwd, [\"reset\", \"--merge\"], GIT_SLOW_TIMEOUT_MS);\n } catch {\n // best effort — leave whatever git managed to clean up\n }\n // Conflict — the WIP lives only on origin. Preserve it; do NOT let a\n // later flush delete or force-push over it.\n wipRefPreserved.add(cwd);\n return \"stale\";\n }\n }\n await git(cwd, [\"stash\", \"apply\", sha], GIT_SLOW_TIMEOUT_MS);\n wipRefPushed.add(cwd);\n wipRefPreserved.delete(cwd);\n return \"applied\";\n } catch {\n // The ref was fetched but couldn't be applied (rev-parse/apply error).\n // Preserve it rather than overwrite unrestored work.\n wipRefPreserved.add(cwd);\n return \"failed\";\n }\n}\n\n/** A `git fetch` for a specific ref fails one of two ways: the ref simply\n * doesn't exist on origin (\"couldn't find remote ref …\"), or the fetch failed\n * transiently (network, auth, timeout). Only the first means \"no snapshot\". */\nfunction isMissingRefError(err: unknown): boolean {\n const stderr = (err as { stderr?: Buffer | string }).stderr?.toString() ?? \"\";\n const msg = stderr || (err instanceof Error ? err.message : String(err));\n return /couldn't find remote ref|couldn't find remote|no such ref|not our ref/i.test(msg);\n}\n\n/** Best-effort flush of pending work: pushes any real (intentional) commits to\n * the task branch, and captures uncommitted changes as a WIP snapshot on the\n * `conveyor-wip/<branch>` ref — never as commits on the branch itself. When\n * the tree is clean, a previously pushed WIP ref is deleted. Never throws. */\nexport async function flushPendingChanges(\n cwd: string,\n opts?: { wipMessage?: string; refreshToken?: () => Promise<string | undefined> },\n): Promise<{ committed: boolean; pushed: boolean; hadWork: boolean }> {\n let committed = false;\n let pushed = false;\n let hadWork = false;\n\n try {\n const branch = await getCurrentBranch(cwd);\n if (!branch) return { committed, pushed, hadWork };\n\n const dirty = await hasUncommittedChanges(cwd);\n const unpushed = await hasUnpushedCommits(cwd);\n\n if (!dirty && !unpushed) {\n await dropStaleWipRef(cwd, branch, opts?.refreshToken);\n return { committed, pushed, hadWork };\n }\n\n hadWork = true;\n await refreshRemoteToken(cwd, opts?.refreshToken);\n\n // Real commits first so a WIP snapshot taken below sits on the pushed head.\n if (unpushed) {\n pushed = await pushToOrigin(cwd, opts?.refreshToken);\n }\n\n if (dirty && !wipRefPreserved.has(cwd)) {\n // wipRefPreserved: a prior restore left unrestored work on the wip ref\n // (stale conflict / fetch failure). Force-pushing a fresh snapshot here\n // would clobber it — skip the WIP push. Real commits above still reached\n // the task branch; the whole-repo backstop still protects other trees.\n const message = opts?.wipMessage ?? \"WIP: conveyor-agent snapshot\";\n const sha = await createWipSnapshot(cwd, message);\n if (sha) {\n committed = await tryPushRefspec(cwd, `${sha}:refs/heads/${wipRefForBranch(branch)}`, true);\n if (committed) wipRefPushed.add(cwd);\n }\n }\n } catch {\n // best effort\n }\n\n return { committed, pushed, hadWork };\n}\n\n/** Clean tree: the last WIP snapshot is stale — drop the remote ref so\n * recovery never resurrects superseded work. */\nasync function dropStaleWipRef(\n cwd: string,\n branch: string,\n refreshToken?: () => Promise<string | undefined>,\n): Promise<void> {\n // Never drop a ref holding unrestored work (stale/failed restore), and only\n // drop one we know we own or successfully restored.\n if (wipRefPreserved.has(cwd) || !wipRefPushed.has(cwd)) return;\n await refreshRemoteToken(cwd, refreshToken);\n if (await tryPushRefspec(cwd, `:refs/heads/${wipRefForBranch(branch)}`)) {\n wipRefPushed.delete(cwd);\n }\n}\n\n/** Push current branch to origin. Proactively refreshes the GitHub token before\n * attempting the push. On auth failure, refreshes again and retries. */\nexport async function pushToOrigin(\n cwd: string,\n refreshToken?: () => Promise<string | undefined>,\n skipVerify = false,\n): Promise<boolean> {\n try {\n const currentBranch = await getCurrentBranch(cwd);\n if (!currentBranch) return false;\n\n // Proactively refresh token before pushing to avoid wasting time with a stale token\n if (refreshToken) {\n try {\n const token = await refreshToken();\n if (token) {\n await updateRemoteToken(cwd, token);\n process.env.GITHUB_TOKEN = token;\n process.env.GH_TOKEN = token;\n }\n } catch {\n // best effort — proceed with existing token\n }\n }\n\n if (await tryPush(cwd, currentBranch, skipVerify)) return true;\n\n if (refreshToken && (await isAuthError(cwd))) {\n const token = await refreshToken();\n if (token) {\n await updateRemoteToken(cwd, token);\n process.env.GITHUB_TOKEN = token;\n process.env.GH_TOKEN = token;\n return await tryPush(cwd, currentBranch, skipVerify);\n }\n }\n\n return false;\n } catch {\n return false;\n }\n}\n\n// ── Whole-repo crash protection ─────────────────────────────────────────\n//\n// `flushPendingChanges` only protects the primary workspace's current branch.\n// A pod that dies while a 5-subagent build has produced several unpushed\n// feature branches (and/or dirty per-subagent worktrees) loses all of it — the\n// pod is reprovisioned as a fresh clone of the branch tip on GitHub (see runbook\n// claudespace-pod-deaths-unpushed-work-loss). `flushAllPendingWork` widens the\n// net to EVERY local branch and worktree, backing them up under the throwaway\n// `conveyor-wip/*` namespace (never real branch names, so origin isn't polluted\n// with half-baked branches and CI/PRs aren't triggered).\n\n/** Backup ref that mirrors a local branch's tip (committed, unpushed work). */\nexport function branchBackupRef(branch: string): string {\n return `conveyor-wip/branches/${branch}`;\n}\n\n/** Enumerate the repo's worktrees as { path, branch }. branch is null for a\n * detached HEAD. Returns [] on any failure. */\nasync function listWorktrees(cwd: string): Promise<{ path: string; branch: string | null }[]> {\n try {\n const out = await git(cwd, [\"worktree\", \"list\", \"--porcelain\"]);\n const result: { path: string; branch: string | null }[] = [];\n for (const entry of out.split(\"\\n\\n\")) {\n const lines = entry.trim().split(\"\\n\");\n const wl = lines.find((l) => l.startsWith(\"worktree \"));\n if (!wl) continue;\n const bl = lines.find((l) => l.startsWith(\"branch \"));\n result.push({\n path: wl.slice(\"worktree \".length),\n branch: bl ? bl.slice(\"branch refs/heads/\".length) : null,\n });\n }\n return result;\n } catch {\n return [];\n }\n}\n\n/** All local branch short-names (refs/heads/*). Returns [] on failure. */\nasync function listLocalBranches(cwd: string): Promise<string[]> {\n try {\n const out = await git(cwd, [\"for-each-ref\", \"--format=%(refname:short)\", \"refs/heads/\"]);\n return out\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/** Count of commits on `branch` not reachable from any origin/* ref — i.e.\n * genuinely unpushed local work. 0 covers both \"already pushed\" and \"an exact\n * copy of a remote branch (e.g. base)\". */\nasync function branchUnpushedCount(cwd: string, branch: string): Promise<number> {\n try {\n const n = await git(cwd, [\"rev-list\", \"--count\", branch, \"--not\", \"--remotes=origin\"]);\n return Number.parseInt(n, 10) || 0;\n } catch {\n return 0;\n }\n}\n\nfunction samePath(a: string, b: string): boolean {\n try {\n return realpathSync(a) === realpathSync(b);\n } catch {\n return a === b;\n }\n}\n\n/** Best-effort crash protection for the WHOLE repo, not just the primary\n * branch:\n * 1. the primary workspace via `flushPendingChanges` (real commits → task\n * branch, dirty tree → conveyor-wip/<branch>) — unchanged behavior;\n * 2. dirty working trees in every OTHER worktree → a stash-shaped snapshot on\n * conveyor-wip/<worktree-branch>;\n * 3. committed-but-unpushed work on every OTHER local branch → its tip mirrored\n * to conveyor-wip/branches/<branch>.\n * Each unit is failure-isolated so one bad branch/worktree can't abort the rest.\n * Never throws. */\nexport async function flushAllPendingWork(\n cwd: string,\n opts?: { wipMessage?: string; refreshToken?: () => Promise<string | undefined> },\n): Promise<{ hadWork: boolean; branchesBackedUp: number; worktreesSnapshotted: number }> {\n try {\n // 1. Primary workspace — existing behavior (real push + current-branch WIP).\n const primary = await flushPendingChanges(cwd, opts);\n await refreshRemoteToken(cwd, opts?.refreshToken);\n const currentBranch = await getCurrentBranch(cwd);\n\n // 2 & 3. Widen to the other worktrees and branches.\n const worktreesSnapshotted = await snapshotOtherWorktrees(cwd, opts?.wipMessage);\n const branchesBackedUp = await backupOtherBranches(cwd, currentBranch);\n\n return {\n hadWork: primary.hadWork || worktreesSnapshotted > 0 || branchesBackedUp > 0,\n branchesBackedUp,\n worktreesSnapshotted,\n };\n } catch {\n return { hadWork: false, branchesBackedUp: 0, worktreesSnapshotted: 0 };\n }\n}\n\n/** Snapshot dirty working trees in every worktree except the primary `cwd` to\n * conveyor-wip/<worktree-branch>. Returns how many were snapshotted. */\nasync function snapshotOtherWorktrees(cwd: string, wipMessage?: string): Promise<number> {\n let count = 0;\n for (const wt of await listWorktrees(cwd)) {\n if (samePath(wt.path, cwd) || !wt.branch) continue;\n try {\n if (!(await hasUncommittedChanges(wt.path))) continue;\n const sha = await createWipSnapshot(wt.path, wipMessage ?? \"WIP: conveyor-agent snapshot\");\n if (\n sha &&\n (await tryPushRefspec(wt.path, `${sha}:refs/heads/${wipRefForBranch(wt.branch)}`, true))\n ) {\n wipRefPushed.add(wt.path);\n count++;\n }\n } catch {\n // isolate per-worktree failure\n }\n }\n return count;\n}\n\n/** Mirror committed-but-unpushed work on every local branch (except the primary\n * workspace's current branch and our own conveyor-wip/* refs) to\n * conveyor-wip/branches/<branch>. Returns how many were backed up. */\nasync function backupOtherBranches(cwd: string, currentBranch: string | null): Promise<number> {\n let count = 0;\n for (const branch of await listLocalBranches(cwd)) {\n // The current branch is handled by step 1; never back up our own snapshots.\n if (branch === currentBranch || branch.startsWith(\"conveyor-wip/\")) continue;\n try {\n if ((await branchUnpushedCount(cwd, branch)) === 0) continue;\n if (\n await tryPushRefspec(\n cwd,\n `refs/heads/${branch}:refs/heads/${branchBackupRef(branch)}`,\n true,\n )\n ) {\n count++;\n }\n } catch {\n // isolate per-branch failure\n }\n }\n return count;\n}\n","// src/utils/card-description.ts\nvar CARD_DESCRIPTION_MAX = 255;\nvar CARD_DESCRIPTION_LIMIT_MESSAGE = `Card descriptions are capped at ${CARD_DESCRIPTION_MAX} characters \\u2014 write 1-2 plain sentences a non-engineer can read; put technical detail in the plan or card chat.`;\nvar CARD_DESCRIPTION_FIELD_HINT = `max ${CARD_DESCRIPTION_MAX} chars, 1-2 plain sentences a non-engineer can read \\u2014 put technical detail in the plan`;\nvar DIVIDER = /^\\s*-{3,}\\s*$/m;\nfunction clampDescription(text, max = CARD_DESCRIPTION_MAX) {\n const trimmed = text?.trim() ?? \"\";\n if (trimmed.length <= max) return trimmed;\n const slice = trimmed.slice(0, max - 1);\n const lastSpace = slice.lastIndexOf(\" \");\n const head = lastSpace > max * 0.6 ? slice.slice(0, lastSpace) : slice;\n return `${head.replace(/[\\s.,;:—-]+$/, \"\")}\\u2026`;\n}\nfunction clampDescriptionField(value) {\n return typeof value === \"string\" ? clampDescription(value) : value;\n}\nfunction collapse(text) {\n return text.replace(/\\s*\\n\\s*/g, \" \").trim();\n}\nfunction summarizeReportBody(body, max = CARD_DESCRIPTION_MAX) {\n const raw = body?.trim();\n if (!raw) return \"\";\n const divider = DIVIDER.exec(raw);\n const withoutFooter = (divider ? raw.slice(0, divider.index) : raw).trim();\n const source = withoutFooter.length > 0 ? withoutFooter : raw;\n const oneLine = collapse(source);\n if (oneLine.length <= max) return oneLine;\n const firstParagraph = collapse(source.split(/\\n\\s*\\n/)[0]);\n return clampDescription(firstParagraph.length > 0 ? firstParagraph : oneLine, max);\n}\n\nexport {\n CARD_DESCRIPTION_MAX,\n CARD_DESCRIPTION_LIMIT_MESSAGE,\n CARD_DESCRIPTION_FIELD_HINT,\n clampDescription,\n clampDescriptionField,\n summarizeReportBody\n};\n","import {\n CARD_DESCRIPTION_FIELD_HINT,\n CARD_DESCRIPTION_LIMIT_MESSAGE,\n CARD_DESCRIPTION_MAX,\n clampDescription,\n clampDescriptionField,\n summarizeReportBody\n} from \"./chunk-6RHVH33O.js\";\n\n// src/types/common.ts\nfunction isCuid(str) {\n return /^c[a-z0-9]{24}$/.test(str);\n}\n\n// src/types/message-types.ts\nvar MESSAGE_KINDS = [\n \"chat\",\n \"human_input\",\n \"agent_milestone\",\n \"lifecycle\",\n \"external\",\n \"detail\"\n];\nvar AGENT_MILESTONE_SLUGS = [\n \"plan_ready\",\n \"implementation_complete\",\n \"blocked\",\n \"review_approved\",\n \"review_changes_requested\"\n];\nvar EXTERNAL_AGENT_MESSAGE_SOURCE = \"external_agent\";\nfunction deriveMessageSource(metadata) {\n if (!metadata) return void 0;\n switch (metadata.type) {\n case \"system_notification\":\n case \"automated_feedback\":\n return metadata.source;\n case \"code_review_result\":\n return metadata.source === \"changes_requested\" ? \"review_trigger\" : \"code_review_approved\";\n case \"agent_mention\":\n return EXTERNAL_AGENT_MESSAGE_SOURCE;\n default:\n return void 0;\n }\n}\n\n// src/constants/models.ts\nvar DEFAULT_SONNET_MODEL = \"claude-sonnet-5\";\nvar DEFAULT_OPUS_MODEL = \"claude-opus-5\";\nvar DEFAULT_HAIKU_MODEL = \"claude-haiku-4-5-20251001\";\nvar FABLE_MODEL = \"claude-fable-5\";\nvar PREVIOUS_SONNET_MODEL = \"claude-sonnet-4-6\";\nvar PREVIOUS_OPUS_MODEL = \"claude-opus-4-8\";\nfunction modelSupportsEffort(model) {\n return !(model.startsWith(\"claude-\") && model.includes(\"haiku\"));\n}\n\n// src/types/pty-stream.ts\nvar PTY_STREAM_PORT_BASE = 7420;\nvar PTY_STREAM_PORT_ATTEMPTS = 8;\nfunction isPtyStreamPort(port) {\n return Number.isInteger(port) && port >= PTY_STREAM_PORT_BASE && port < PTY_STREAM_PORT_BASE + PTY_STREAM_PORT_ATTEMPTS;\n}\nfunction encodePtyStreamFrame(frame) {\n return `${JSON.stringify(frame)}\n`;\n}\nfunction isRecord(value) {\n return typeof value === \"object\" && value !== null;\n}\nfunction parsePtyStreamFrame(line) {\n if (!line) return null;\n let parsed;\n try {\n parsed = JSON.parse(line);\n } catch {\n return null;\n }\n if (!isRecord(parsed) || typeof parsed.t !== \"string\") return null;\n switch (parsed.t) {\n case \"hello\":\n case \"data\":\n case \"ended\":\n case \"input\":\n case \"resize\":\n return parsed;\n default:\n return null;\n }\n}\nvar PtyStreamFrameReader = class {\n constructor(onFrame) {\n this.onFrame = onFrame;\n }\n onFrame;\n buffer = \"\";\n push(chunk) {\n this.buffer += chunk;\n let index = this.buffer.indexOf(\"\\n\");\n while (index >= 0) {\n const line = this.buffer.slice(0, index);\n this.buffer = this.buffer.slice(index + 1);\n const frame = parsePtyStreamFrame(line);\n if (frame) this.onFrame(frame);\n index = this.buffer.indexOf(\"\\n\");\n }\n }\n};\n\n// src/types/project-settings-types.ts\nimport { z } from \"zod\";\nvar PREVIEW_PORT_DENY_LIST = [\n 5432,\n 6379,\n 9200,\n ...Array.from({ length: PTY_STREAM_PORT_ATTEMPTS }, (_, i) => PTY_STREAM_PORT_BASE + i)\n];\nfunction isAllowablePreviewPort(port) {\n if (typeof port !== \"number\" || !Number.isInteger(port)) return false;\n if (port < 1 || port > 65535) return false;\n return !PREVIEW_PORT_DENY_LIST.includes(port);\n}\nfunction sanitizeSessionPreviewPorts(ports) {\n if (!Array.isArray(ports)) return [];\n const seen = /* @__PURE__ */ new Set();\n const out = [];\n for (const raw of ports) {\n if (!raw || typeof raw !== \"object\") continue;\n const portValue = raw.port;\n if (!isAllowablePreviewPort(portValue)) continue;\n if (seen.has(portValue)) continue;\n seen.add(portValue);\n const labelValue = raw.label;\n const visValue = raw.visibility;\n out.push({\n port: portValue,\n ...typeof labelValue === \"string\" ? { label: labelValue } : {},\n ...visValue === \"public\" || visValue === \"private\" ? { visibility: visValue } : {}\n });\n }\n return out;\n}\nfunction resolveAllowedPreviewPorts(sources) {\n const set = /* @__PURE__ */ new Set();\n if (Array.isArray(sources.sessionPreviewPorts)) {\n for (const entry of sources.sessionPreviewPorts) {\n if (isAllowablePreviewPort(entry?.port)) set.add(entry.port);\n }\n }\n return [...set].sort((a, b) => a - b);\n}\nfunction pickPreferredPreviewPort(allowed, preferred) {\n if (preferred !== null && preferred !== void 0 && allowed.includes(preferred))\n return preferred;\n return allowed[0] ?? null;\n}\nfunction normalizeCheckpointPath(value) {\n let normalized = value.trim().replace(/\\/{2,}/g, \"/\");\n normalized = normalized.split(\"/\").filter((segment) => segment !== \".\").join(\"/\");\n while (normalized.endsWith(\"/\")) normalized = normalized.slice(0, -1);\n return normalized;\n}\nvar checkpointPathSchema = z.string().transform(normalizeCheckpointPath).pipe(\n z.string().min(1).refine((value) => value !== \".\", \"Checkpoint paths must name a repository entry\").refine((value) => !value.startsWith(\"/\"), \"Checkpoint paths must be repository-relative\").refine(\n (value) => !/^[A-Za-z]:[\\\\/]/.test(value) && !value.includes(\"\\\\\"),\n \"Checkpoint paths must use repository-relative POSIX syntax\"\n ).refine(\n (value) => !value.split(\"/\").includes(\"..\"),\n \"Checkpoint paths must not traverse a parent directory\"\n )\n);\nvar secretNameSchema = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/);\nvar checkpointKeySchema = z.string().regex(/^[0-9a-f]{64}$/);\nvar checkpointDigestRefSchema = z.string().regex(/^[^\\s@]+@sha256:[0-9a-f]{64}$/);\nvar ACTIONS_PREBAKE_REGISTRY_PATTERN = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::(?:[1-9][0-9]{0,4}))?(?:\\/[a-z0-9]+(?:[._-][a-z0-9]+)*)*$/;\nvar actionsPrebakeRegistrySchema = z.string().trim().min(1).regex(\n ACTIONS_PREBAKE_REGISTRY_PATTERN,\n \"Actions prebake registry must be a lowercase host[:port] with an optional path prefix\"\n).refine((value) => {\n const port = /:([0-9]+)(?:\\/|$)/.exec(value)?.[1];\n return !port || Number(port) <= 65535;\n}, \"Actions prebake registry port must be between 1 and 65535\");\nfunction uniqueSortedArray(item, minimum = 0) {\n return z.array(item).min(minimum).superRefine((values, ctx) => {\n if (new Set(values).size !== values.length) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, message: \"Duplicate values are not allowed\" });\n }\n }).transform((values) => [...values].sort());\n}\nvar projectCheckpointSettingsSchema = z.object({\n enabled: z.literal(true),\n cacheCommand: z.string().trim().min(1),\n cacheInputPaths: uniqueSortedArray(checkpointPathSchema, 1),\n reusableArtifactPaths: uniqueSortedArray(checkpointPathSchema, 1),\n finalizeCommand: z.string().trim().min(1),\n credentialEpoch: z.string().trim().min(1),\n requiredSecretNames: uniqueSortedArray(secretNameSchema).optional(),\n optionalSecretNames: uniqueSortedArray(secretNameSchema).optional()\n}).superRefine((checkpoint, ctx) => {\n const required = new Set(checkpoint.requiredSecretNames ?? []);\n for (const name of checkpoint.optionalSecretNames ?? []) {\n if (required.has(name)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"optionalSecretNames\"],\n message: \"A secret cannot be both required and optional\"\n });\n }\n }\n});\nfunction resolveProjectCheckpointSettings(settings) {\n if (settings?.checkpoint?.enabled !== true) return null;\n const parsed = projectCheckpointSettingsSchema.safeParse(settings.checkpoint);\n return parsed.success ? parsed.data : null;\n}\nfunction isPlainProjectSettings(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction coerceProjectSettings(value) {\n return isPlainProjectSettings(value) ? value : {};\n}\nfunction resolveMaxOpenPrs(settings) {\n const configured = settings?.maxOpenPrs;\n return typeof configured === \"number\" && Number.isInteger(configured) && configured >= 0 ? configured : null;\n}\nvar PROJECT_FUNCTION_IDS = [\n \"identification\",\n \"reportsHandler\",\n \"prReview\",\n \"reporterEmail\",\n \"pmChat\",\n \"releaseNotes\"\n];\nvar PROJECT_FUNCTION_DEFAULTS = {\n identification: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"low\",\n thinking: { type: \"disabled\" }\n },\n reportsHandler: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"high\",\n thinking: { type: \"disabled\" }\n },\n prReview: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"low\",\n thinking: { type: \"disabled\" }\n },\n reporterEmail: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"high\",\n thinking: { type: \"disabled\" }\n },\n pmChat: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"medium\",\n thinking: { type: \"disabled\" }\n },\n releaseNotes: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"medium\",\n thinking: { type: \"disabled\" }\n }\n};\nfunction resolveProjectFunctionConfig(settings, functionId) {\n const defaults = PROJECT_FUNCTION_DEFAULTS[functionId];\n const override = settings?.functionSettings?.[functionId];\n return {\n model: override?.model ?? defaults.model,\n effort: override?.effort ?? defaults.effort,\n thinking: override?.thinking ?? defaults.thinking,\n instructions: override?.instructions\n };\n}\nvar MAX_AGENT_FLAVOR_LENGTH = 2e3;\nfunction applyAgentFlavor(instructions, settings) {\n const flavor = settings?.agentFlavor?.trim();\n if (!flavor) return instructions;\n const section = `Flavor:\n${flavor}`;\n return instructions?.trim() ? `${instructions}\n\n${section}` : section;\n}\nfunction resolveCodeReviewMode(settings) {\n return settings?.codeReviewMode ?? \"off\";\n}\nfunction resolveVerifiedLinksPrCheck(settings) {\n return settings?.verifiedLinksPrCheck === true;\n}\nvar TRIAGE_INCLUDE_VALUES = [\"all\", \"incidents\", \"suggestions\"];\nfunction resolveTriageSettings(settings) {\n const triage = settings?.triage;\n if (!triage || typeof triage !== \"object\") return null;\n const { agentId, userId, include } = triage;\n if (typeof agentId !== \"string\" || agentId.length === 0) return null;\n if (typeof userId !== \"string\" || userId.length === 0) return null;\n if (!TRIAGE_INCLUDE_VALUES.includes(include)) return null;\n return { agentId, userId, include };\n}\nfunction resolveGcpEnvResources(settings) {\n return settings?.gcpEnvResources ?? {};\n}\n\n// src/types/ops-types.ts\nvar OPS_ENVIRONMENTS = [\"live\", \"dev\"];\nfunction resolveOpsSettings(settings) {\n return settings?.ops ?? {};\n}\nfunction resolveOpsEnv(settings, env) {\n return resolveOpsSettings(settings).environments?.[env] ?? {};\n}\nfunction buildOpsEnvConfigDTO(conn) {\n return {\n redisUrlSet: Boolean(conn.redisUrlEnc),\n queueDiscovery: Boolean(conn.queueDiscovery),\n queueNames: conn.queueNames ?? [],\n elasticsearchUrlSet: Boolean(conn.elasticsearchUrlEnc)\n };\n}\nfunction buildOpsConfigDTO(settings) {\n const ops = resolveOpsSettings(settings);\n const envs = ops.environments ?? {};\n return {\n environments: {\n live: buildOpsEnvConfigDTO(envs.live ?? {}),\n dev: buildOpsEnvConfigDTO(envs.dev ?? {})\n },\n readOnly: Boolean(ops.readOnly)\n };\n}\nfunction mergeOpsEnvSettings(settings, env, patch) {\n const ops = { ...settings.ops ?? {} };\n const environments = {\n ...ops.environments ?? {}\n };\n if (patch === null) {\n delete environments[env];\n } else {\n const next = { ...environments[env] ?? {} };\n for (const [key, value] of Object.entries(patch)) {\n if (value !== void 0) next[key] = value;\n }\n environments[env] = next;\n }\n ops.environments = environments;\n return { ...settings, ops };\n}\nfunction clearOpsEnvFields(settings, env, fields) {\n const ops = { ...settings.ops ?? {} };\n const environments = {\n ...ops.environments ?? {}\n };\n const next = { ...environments[env] ?? {} };\n for (const key of fields) delete next[key];\n if (Object.keys(next).length === 0) {\n delete environments[env];\n } else {\n environments[env] = next;\n }\n ops.environments = environments;\n return { ...settings, ops };\n}\nfunction setOpsReadOnly(settings, readOnly) {\n const ops = { ...settings.ops ?? {}, readOnly };\n return { ...settings, ops };\n}\nfunction validateRedisUrl(value) {\n let parsed;\n try {\n parsed = new URL(value);\n } catch {\n return { ok: false, message: \"Redis URL is not a valid URL\" };\n }\n if (parsed.protocol !== \"redis:\" && parsed.protocol !== \"rediss:\") {\n return { ok: false, message: \"Redis URL must use redis:// or rediss://\" };\n }\n if (!parsed.hostname) {\n return { ok: false, message: \"Redis URL is missing a host\" };\n }\n return { ok: true };\n}\nfunction validateElasticsearchUrl(value) {\n let parsed;\n try {\n parsed = new URL(value);\n } catch {\n return { ok: false, message: \"Elasticsearch URL is not a valid URL\" };\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return { ok: false, message: \"Elasticsearch URL must use http:// or https://\" };\n }\n if (!parsed.hostname) {\n return { ok: false, message: \"Elasticsearch URL is missing a host\" };\n }\n return { ok: true };\n}\nvar OPS_TAB_REGISTRY = [\n {\n id: \"redis\",\n labelKey: \"opsTabRedis\",\n requires: (conn) => Boolean(conn.redisUrlEnc)\n },\n {\n id: \"queues\",\n labelKey: \"opsTabQueues\",\n // Queues live inside Redis and only make sense once discovery is on.\n requires: (conn) => Boolean(conn.redisUrlEnc) && Boolean(conn.queueDiscovery)\n },\n {\n id: \"elasticsearch\",\n labelKey: \"opsTabElasticsearch\",\n requires: (conn) => Boolean(conn.elasticsearchUrlEnc)\n }\n];\nfunction resolveAvailableOpsTabsForEnv(conn) {\n return OPS_TAB_REGISTRY.filter((tab) => tab.requires(conn)).map((tab) => tab.id);\n}\nfunction resolveAvailableOpsTabs(settings) {\n const envs = resolveOpsSettings(settings).environments ?? {};\n const available = /* @__PURE__ */ new Set();\n for (const env of OPS_ENVIRONMENTS) {\n for (const id of resolveAvailableOpsTabsForEnv(envs[env] ?? {})) available.add(id);\n }\n return OPS_TAB_REGISTRY.filter((tab) => available.has(tab.id)).map((tab) => tab.id);\n}\nfunction isOpsEnvConfigured(conn) {\n return resolveAvailableOpsTabsForEnv(conn).length > 0;\n}\nfunction isOpsConfigured(settings) {\n return resolveAvailableOpsTabs(settings).length > 0;\n}\nfunction connFromEnvDTO(dto) {\n return {\n redisUrlEnc: dto.redisUrlSet ? \"set\" : void 0,\n queueDiscovery: dto.queueDiscovery,\n queueNames: dto.queueNames,\n elasticsearchUrlEnc: dto.elasticsearchUrlSet ? \"set\" : void 0\n };\n}\nfunction availableTabsForEnvDTO(dto) {\n return resolveAvailableOpsTabsForEnv(connFromEnvDTO(dto));\n}\nfunction isOpsEnvConfiguredDTO(dto) {\n return availableTabsForEnvDTO(dto).length > 0;\n}\nfunction availableTabsFromConfigDTO(config) {\n const available = /* @__PURE__ */ new Set();\n for (const env of OPS_ENVIRONMENTS) {\n for (const id of availableTabsForEnvDTO(config.environments[env])) available.add(id);\n }\n return OPS_TAB_REGISTRY.filter((tab) => available.has(tab.id)).map((tab) => tab.id);\n}\nvar QUEUE_JOB_STATES = [\n \"waiting\",\n \"active\",\n \"delayed\",\n \"completed\",\n \"failed\",\n \"paused\"\n];\nvar QUEUE_JOBS_PAGE_SIZE = 25;\n\n// src/types/gcp-types.ts\nvar GCP_ENVS = [\"prod\", \"dev\", \"claudespace\"];\n\n// src/types/ga-traffic-types.ts\nvar GA_TRAFFIC_RANGE_DAYS = [7, 28, 90];\nfunction resolveGoogleAnalyticsSettings(settings) {\n const ga = settings.googleAnalytics;\n if (!ga?.propertyId?.trim()) return null;\n return ga;\n}\n\n// src/types/grafana-types.ts\nvar GRAFANA_ENVS = [\"prod\", \"dev\"];\nvar GRAFANA_LOG_LEVELS = [\"debug\", \"info\", \"warn\", \"error\", \"fatal\"];\nfunction resolveGrafanaSettings(settings) {\n return settings?.grafana ?? {};\n}\n\n// src/types/coding-agent.ts\nvar TUI_KINDS = [\"claude-code\", \"opencode\"];\nvar AGENT_PROVIDERS = [\"anthropic\", \"openai\", \"zen\"];\nvar AGENT_KEY_KINDS = [\"oauth_token\", \"api_key\", \"chatgpt_oauth\", \"claude_oauth\"];\n\n// src/types/agent-project-types.ts\nvar TASK_STATUS_ORDER = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\"\n];\n\n// src/types/achievement-types.ts\nvar ACHIEVEMENT_RARITY_KEYS = [\"common\", \"magic\", \"rare\", \"unique\", \"pack\"];\nvar ACHIEVEMENT_RARITIES = [\n {\n key: \"common\",\n name: \"Common\",\n color: \"#22c55e\",\n iconPath: \"/storypoints/square-solid-full.svg\"\n },\n {\n key: \"magic\",\n name: \"Magic\",\n color: \"#3b82f6\",\n iconPath: \"/storypoints/diamond-solid-full.svg\"\n },\n { key: \"rare\", name: \"Rare\", color: \"#eab308\", iconPath: \"/storypoints/gem-solid-full.svg\" },\n {\n key: \"unique\",\n name: \"Unique\",\n color: \"#f97316\",\n iconPath: \"/storypoints/scroll-sharp-solid-full.svg\"\n },\n { key: \"pack\", name: \"Pack\", color: \"#9c27b0\", iconPath: \"/storypoints/pack.svg\" }\n];\nvar ACHIEVEMENT_PATTERNS = [\n \"foil\",\n \"rainbow\",\n \"stripes\",\n \"galaxy\",\n \"illusion\",\n \"glitch\",\n \"noir\",\n \"halftone\",\n \"crt\",\n \"frost\",\n \"aurora\",\n \"hologram\",\n \"neon\",\n \"static\"\n];\nvar ACHIEVEMENT_IMAGE_POSITIONS = [\n \"center\",\n \"top\",\n \"bottom\",\n \"left\",\n \"right\",\n \"top-left\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-right\"\n];\nvar ACHIEVEMENT_STAT_ICON_KEYS = [\n \"sp\",\n \"bugs\",\n \"review\",\n \"loc-add\",\n \"loc-del\",\n \"star\",\n \"trophy\"\n];\nvar MAX_ACHIEVEMENT_STATS = 6;\nvar MAX_ACHIEVEMENT_STAT_LABEL_LENGTH = 40;\nvar MAX_ACHIEVEMENT_STAT_VALUE_LENGTH = 20;\nvar MAX_ACHIEVEMENT_TITLE_LENGTH = 120;\nvar MAX_ACHIEVEMENT_DESCRIPTION_LENGTH = 500;\n\n// src/types/risk-catalog.ts\nimport { z as z2 } from \"zod\";\nvar RISK_LEVELS = [\"critical\", \"high\", \"medium\", \"low\"];\nvar riskLevelSchema = z2.enum(RISK_LEVELS);\nvar RISK_RANK = {\n critical: 4,\n high: 3,\n medium: 2,\n low: 1\n};\nvar DEFAULT_RISK_LEVELS = [\n {\n level: \"critical\",\n value: 4,\n label: \"Critical\",\n description: \"Touches critical surface area; give it the closest review.\",\n color: \"#dc2626\",\n ordinal: 0\n },\n {\n level: \"high\",\n value: 3,\n label: \"Elevated\",\n description: \"Touches important surface area; review carefully.\",\n color: \"#ea580c\",\n ordinal: 1\n },\n {\n level: \"medium\",\n value: 2,\n label: \"Moderate\",\n description: \"Moderate surface area; normal review.\",\n color: \"#d97706\",\n ordinal: 2\n },\n {\n level: \"low\",\n value: 1,\n label: \"Minimal\",\n description: \"Small or isolated surface area.\",\n color: \"#64748b\",\n ordinal: 3\n }\n];\nvar LEVEL_BY_VALUE = new Map(\n DEFAULT_RISK_LEVELS.map((m) => [m.value, m.level])\n);\nfunction riskLevelForValue(value) {\n if (value === null || value === void 0) return null;\n return LEVEL_BY_VALUE.get(value) ?? null;\n}\nfunction riskRank(level) {\n return RISK_RANK[level];\n}\nfunction isHigherRisk(next, current) {\n return current === null || current === void 0 || next > current;\n}\nfunction riskFromReviewSeverities(severities) {\n if (severities.includes(\"critical\")) return \"critical\";\n if (severities.includes(\"major\")) return \"high\";\n return \"medium\";\n}\n\n// src/types/task-status.ts\nvar PR_PRODUCING_AGENT_MODES = [\"building\", \"auto\"];\nfunction isPrProducingMode(mode) {\n return PR_PRODUCING_AGENT_MODES.includes(mode ?? \"\");\n}\nvar CARD_TYPE_VALUES = [\"task\", \"incident\", \"suggestion\", \"chat\"];\nvar UNIFIED_STATUSES = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\"\n];\nvar CARD_TYPE_STATUSES = {\n task: UNIFIED_STATUSES,\n incident: UNIFIED_STATUSES,\n suggestion: UNIFIED_STATUSES,\n // Chat cards spawn a conversational cloud agent that never opens a PR — they\n // move InProgress → Complete directly. Reuse the unified set so the direct\n // Complete transition validates.\n chat: UNIFIED_STATUSES\n};\nfunction validateStatusForType(type, status) {\n return CARD_TYPE_STATUSES[type].includes(status);\n}\nvar ACTIVE_WORK_STATUSES = [\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\"\n];\nfunction isActiveWorkStatus(status) {\n return ACTIVE_WORK_STATUSES.includes(status);\n}\nvar IDENTIFIED_WORK_STATUSES = [\"Open\", ...ACTIVE_WORK_STATUSES];\nfunction isIdentifiedWorkStatus(status) {\n return IDENTIFIED_WORK_STATUSES.includes(status);\n}\nvar HIDDEN_REPORT_STATUSES = [\"Cancelled\", \"Rejected\", \"Duplicate\"];\nvar REPORT_STATUS_TO_LANE = {\n Planning: \"Planning\",\n Open: \"Open\",\n Investigating: \"InProgress\",\n Accepted: \"InProgress\",\n InProgress: \"InProgress\",\n ReviewPR: \"ReviewPR\",\n ReviewDev: \"ReviewDev\",\n ReviewLive: \"ReviewLive\",\n Resolved: \"Complete\",\n Implemented: \"Complete\",\n Closed: \"Complete\",\n Complete: \"Complete\",\n Rejected: null,\n Duplicate: null,\n Cancelled: null\n};\nfunction normalizeReportStatus(status) {\n return REPORT_STATUS_TO_LANE[status] ?? null;\n}\nvar LEGACY_TERMINAL_STATUSES = /* @__PURE__ */ new Set([\"Rejected\", \"Duplicate\"]);\nfunction normalizeTaskStatus(status) {\n return LEGACY_TERMINAL_STATUSES.has(status) ? \"Cancelled\" : status;\n}\nvar TASK_STATUS_COLORS = {\n Planning: \"#9ca3af\",\n Open: \"#60a5fa\",\n InProgress: \"#fbbf24\",\n ReviewPR: \"#a78bfa\",\n ReviewDev: \"#939bf9\",\n ReviewLive: \"#4ade80\",\n Complete: \"#10b981\",\n Cancelled: \"#a8a29e\"\n};\nvar DEFAULT_TASK_STATUS_COLOR = \"#a8a29e\";\nfunction taskStatusColor(status) {\n const direct = TASK_STATUS_COLORS[status];\n if (direct) return direct;\n const lane = normalizeReportStatus(status);\n return lane ? TASK_STATUS_COLORS[lane] : DEFAULT_TASK_STATUS_COLOR;\n}\nfunction taskStatusColorInt(status) {\n return Number.parseInt(taskStatusColor(status).slice(1), 16);\n}\nvar CREATED_DESC_STATUSES = [\"ReviewLive\"];\nfunction isCreatedDescStatus(status) {\n return CREATED_DESC_STATUSES.includes(status);\n}\n\n// src/types/file-upload-limits.ts\nvar MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024;\nvar MAX_FILE_TAGS = 5;\nvar MAX_FILE_TAG_LENGTH = 100;\n\n// src/types/service-map.ts\nvar ALLOWED_FILE_MIME_TYPES = [\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"application/json\",\n \"text/csv\",\n \"text/plain\",\n \"text/markdown\",\n \"text/vnd.mermaid\",\n \"application/pdf\"\n];\nvar EMBED_THRESHOLD_IMAGES = 5 * 1024 * 1024;\nvar EMBED_THRESHOLD_TEXT = 2 * 1024 * 1024;\nvar EMBEDDABLE_IMAGE_TYPES = [\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\"\n];\nvar EMBEDDABLE_TEXT_TYPES = [\n \"text/plain\",\n \"text/csv\",\n \"text/markdown\",\n \"text/vnd.mermaid\",\n \"application/json\"\n];\nfunction isEmbeddableFile(mimeType, fileSize) {\n if (EMBEDDABLE_IMAGE_TYPES.some((t) => mimeType === t)) {\n return fileSize <= EMBED_THRESHOLD_IMAGES;\n }\n if (EMBEDDABLE_TEXT_TYPES.some((t) => mimeType === t)) {\n return fileSize <= EMBED_THRESHOLD_TEXT;\n }\n return false;\n}\n\n// src/types/connection-state.ts\nvar IDLE_HEARTBEAT_MS = 90 * 1e3;\nvar STRANDED_RUNNER_STATUSES = /* @__PURE__ */ new Set([\"stalled_heartbeat\", \"stranded\", \"crashed\"]);\nfunction deriveConnectionState(inputs, now = Date.now()) {\n const heartbeatAgeMs = inputs.lastHeartbeatAt ? Math.max(0, now - new Date(inputs.lastHeartbeatAt).getTime()) : null;\n if (inputs.deletionRequestedAt) {\n return { state: \"pendingDeletion\", heartbeatAgeMs };\n }\n const status = inputs.codespaceStatus;\n if (status === \"Deleted\") {\n return { state: \"deleted\", heartbeatAgeMs };\n }\n if (status === \"Creating\" || inputs.podStatus === \"Creating\") {\n return { state: \"creating\", heartbeatAgeMs };\n }\n if (inputs.agentRunnerStatus && STRANDED_RUNNER_STATUSES.has(inputs.agentRunnerStatus)) {\n return { state: \"stranded\", heartbeatAgeMs };\n }\n if (status === \"Stopped\" || inputs.podStatus === \"Stopped\" || inputs.podStatus === \"Sleeping\") {\n return { state: \"stopped\", heartbeatAgeMs };\n }\n if (status !== \"Running\" && !inputs.codespaceId && !inputs.podName) {\n return { state: \"none\", heartbeatAgeMs };\n }\n if (heartbeatAgeMs !== null && heartbeatAgeMs >= IDLE_HEARTBEAT_MS) {\n return { state: \"idle\", heartbeatAgeMs };\n }\n if (status === \"Running\") {\n return { state: \"active\", heartbeatAgeMs };\n }\n return { state: \"none\", heartbeatAgeMs };\n}\nfunction formatHeartbeatAge(ms) {\n if (ms === null) return \"never\";\n const sec = Math.floor(ms / 1e3);\n if (sec < 60) return `${sec}s ago`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const days = Math.floor(hr / 24);\n return `${days}d ago`;\n}\n\n// src/types/agent-event-schema.ts\nimport { z as z3 } from \"zod\";\nvar TurnEndToolCallSchema = z3.object({\n tool: z3.string(),\n input: z3.string().optional(),\n output: z3.string().optional(),\n timestamp: z3.string().optional()\n}).passthrough();\nvar KnownAgentEventSchema = z3.discriminatedUnion(\"type\", [\n // ── Lifecycle / connection ────────────────────────────────────────────\n z3.object({\n type: z3.literal(\"connected\"),\n sessionId: z3.string(),\n projectId: z3.string().optional()\n }).passthrough(),\n // Open-ended context snapshot spread from buildInitializationContext().\n z3.object({ type: z3.literal(\"session_manifest\") }).passthrough(),\n z3.object({\n type: z3.literal(\"agent_runner_status\"),\n reason: z3.string(),\n attempt: z3.number().optional(),\n attempts: z3.number().optional()\n }).passthrough(),\n z3.object({ type: z3.literal(\"shutdown\"), reason: z3.string().optional() }).passthrough(),\n z3.object({ type: z3.literal(\"mode_changed\"), agentMode: z3.string() }).passthrough(),\n z3.object({ type: z3.literal(\"mode_transition\"), from: z3.string(), to: z3.string() }).passthrough(),\n // ── Turn stream ───────────────────────────────────────────────────────\n z3.object({ type: z3.literal(\"message\"), content: z3.string() }).passthrough(),\n z3.object({ type: z3.literal(\"thinking\"), message: z3.string() }).passthrough(),\n z3.object({\n type: z3.literal(\"tool_use\"),\n tool: z3.string(),\n // Producers send JSON.stringify(input); consumers defend against\n // object inputs from older agents, so the wire stays permissive here.\n input: z3.unknown().optional()\n }).passthrough(),\n z3.object({\n type: z3.literal(\"tool_result\"),\n tool: z3.string(),\n output: z3.unknown().optional(),\n isError: z3.boolean().optional(),\n redactedCount: z3.number().optional()\n }).passthrough(),\n z3.object({ type: z3.literal(\"turn_end\"), toolCalls: z3.array(TurnEndToolCallSchema) }).passthrough(),\n z3.object({\n type: z3.literal(\"completed\"),\n summary: z3.string().optional(),\n durationMs: z3.number().optional()\n }).passthrough(),\n z3.object({ type: z3.literal(\"error\"), message: z3.string() }).passthrough(),\n z3.object({ type: z3.literal(\"agent_typing_start\") }).passthrough(),\n z3.object({ type: z3.literal(\"agent_typing_stop\") }).passthrough(),\n // ── Telemetry ─────────────────────────────────────────────────────────\n // heartbeat/typing: legacy telemetry the server still classifies as\n // transient (TRANSIENT_EVENT_TYPES) — kept in the vocabulary.\n z3.object({ type: z3.literal(\"heartbeat\") }).passthrough(),\n z3.object({ type: z3.literal(\"typing\") }).passthrough(),\n z3.object({\n type: z3.literal(\"context_update\"),\n contextTokens: z3.number(),\n contextWindow: z3.number(),\n inputTokens: z3.number().optional(),\n cacheReadInputTokens: z3.number().optional(),\n cacheCreationInputTokens: z3.number().optional(),\n totalTokensUsed: z3.number().optional()\n }).passthrough(),\n // Three producer shapes share this type: {rateLimitType, utilization, status}\n // (SDK rate_limit_event), {resetsAt} (agent-connection resume notice), and\n // the usage-sampler ({rateLimitType, utilization, status, resetsAt, gauges}\n // — resetsAt matches rateLimitType; gauges survives via .passthrough()).\n z3.object({\n type: z3.literal(\"rate_limit_update\"),\n rateLimitType: z3.string().optional(),\n utilization: z3.number().optional(),\n status: z3.string().optional(),\n resetsAt: z3.string().optional()\n }).passthrough(),\n z3.object({\n type: z3.literal(\"context_compacted\"),\n trigger: z3.string().optional(),\n preTokens: z3.number().optional()\n }).passthrough(),\n z3.object({\n type: z3.literal(\"tool_progress\"),\n toolName: z3.string().optional(),\n elapsedSeconds: z3.number().optional()\n }).passthrough(),\n z3.object({\n type: z3.literal(\"subagent_started\"),\n sdkTaskId: z3.string().optional(),\n description: z3.string().optional()\n }).passthrough(),\n z3.object({\n type: z3.literal(\"subagent_progress\"),\n sdkTaskId: z3.string().optional(),\n description: z3.string().optional(),\n toolUses: z3.number().optional(),\n durationMs: z3.number().optional()\n }).passthrough(),\n // ── Work products ─────────────────────────────────────────────────────\n z3.object({ type: z3.literal(\"pr_created\"), url: z3.string(), number: z3.number() }).passthrough(),\n z3.object({\n type: z3.literal(\"code_review_complete\"),\n result: z3.enum([\"approved\", \"changes_requested\"]),\n summary: z3.string().optional(),\n issues: z3.array(\n z3.object({\n file: z3.string(),\n line: z3.number().optional(),\n severity: z3.string().optional(),\n description: z3.string().optional()\n }).passthrough()\n ).optional()\n }).passthrough(),\n // ── Environment setup / start command ─────────────────────────────────\n z3.object({ type: z3.literal(\"setup_output\"), stream: z3.string(), data: z3.string() }).passthrough(),\n z3.object({\n type: z3.literal(\"setup_complete\"),\n startCommandRunning: z3.boolean().optional(),\n // Sanitized server-side by sanitizeSessionPreviewPorts — stays unknown.\n previewPorts: z3.unknown().optional()\n }).passthrough(),\n z3.object({ type: z3.literal(\"setup_error\"), message: z3.string() }).passthrough(),\n z3.object({ type: z3.literal(\"start_command_started\") }).passthrough(),\n z3.object({ type: z3.literal(\"start_command_output\"), stream: z3.string(), data: z3.string() }).passthrough(),\n z3.object({\n type: z3.literal(\"start_command_exited\"),\n code: z3.number().nullable().optional(),\n signal: z3.string().nullable().optional(),\n message: z3.string().optional()\n }).passthrough(),\n z3.object({ type: z3.literal(\"start_command_error\"), message: z3.string() }).passthrough()\n]);\nvar AgentEventSchema = z3.union([\n KnownAgentEventSchema,\n z3.object({ type: z3.string().min(1) }).catchall(z3.unknown())\n]);\n\n// src/types/agent-session-requests.ts\nimport { z as z4 } from \"zod\";\nvar cardDescription = z4.string().max(CARD_DESCRIPTION_MAX, CARD_DESCRIPTION_LIMIT_MESSAGE).optional();\nvar AgentHeartbeatSchema = z4.object({\n sessionId: z4.string().optional(),\n timestamp: z4.string(),\n status: z4.enum([\"active\", \"idle\", \"building\"]),\n currentAction: z4.string().optional(),\n /** Sender-observed main event-loop lag (ms) — see AgentHeartbeat.loopLagMs. */\n loopLagMs: z4.number().nonnegative().optional()\n});\nvar CreatePRInputSchema = z4.object({\n title: z4.string().min(1),\n body: z4.string(),\n head: z4.string().optional(),\n base: z4.string().optional()\n});\nvar PostToChatInputSchema = z4.object({\n message: z4.string().min(1),\n type: z4.enum([\"message\", \"question\", \"update\"]).optional().default(\"message\"),\n milestone: z4.enum([\"plan_ready\", \"implementation_complete\", \"blocked\"]).optional()\n});\nvar GetTaskContextRequestSchema = z4.object({\n sessionId: z4.string(),\n includeHistory: z4.boolean().optional().default(false)\n});\nvar GetChatMessagesRequestSchema = z4.object({\n sessionId: z4.string(),\n limit: z4.number().int().positive().optional().default(50),\n offset: z4.number().int().nonnegative().optional().default(0),\n /** Task id or slug to read chat from. Omit for the session's own task. Only\n * the session's own task or one of its children resolves — anything else is\n * an error, never a silent fallback to the caller's own chat. */\n taskId: z4.string().optional()\n});\nvar GetTaskFilesRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar GetTaskFileRequestSchema = z4.object({\n sessionId: z4.string(),\n fileId: z4.string()\n});\nvar GetTaskRequestSchema = z4.object({\n sessionId: z4.string(),\n taskSlugOrId: z4.string()\n});\nvar GetCliHistoryRequestSchema = z4.object({\n sessionId: z4.string(),\n limit: z4.number().int().positive().optional().default(100),\n source: z4.enum([\"agent\", \"application\"]).optional(),\n /** Task id or slug to read logs from. Omit for the session's own task. Only\n * the session's own task or one of its children resolves — anything else is\n * an error, never a silent fallback to the caller's own logs. */\n taskId: z4.string().optional()\n});\nvar ListSubtasksRequestSchema = z4.object({\n sessionId: z4.string(),\n /** \"compact\" returns the slim orchestration view (ListSubtasksCompactResponse)\n * with the pack build-slot picture; \"full\" (default — wire-compat with older\n * agents) returns the verbose SubtaskSummaryDTO[] including description/plan. */\n view: z4.enum([\"compact\", \"full\"]).optional()\n});\nvar GetDependenciesRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar GetSuggestionsRequestSchema = z4.object({\n sessionId: z4.string(),\n status: z4.string().optional(),\n limit: z4.number().int().min(1).max(100).optional()\n});\nvar ListManualTestsRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar QueryManualTestsRequestSchema = z4.object({\n sessionId: z4.string(),\n cardStatuses: z4.array(z4.string()).optional(),\n testStatuses: z4.array(z4.enum([\"open\", \"approved\", \"rejected\"])).optional()\n});\nvar PostToChatRequestSchema = PostToChatInputSchema;\nvar CreatePullRequestRequestSchema = CreatePRInputSchema.extend({ sessionId: z4.string() });\nvar RequestFileUploadRequestSchema = z4.object({\n sessionId: z4.string(),\n fileName: z4.string().min(1).max(255),\n mimeType: z4.string().min(1).max(128),\n fileSize: z4.number().int().positive().max(MAX_FILE_SIZE_BYTES)\n});\nvar ConfirmFileUploadRequestSchema = z4.object({\n sessionId: z4.string(),\n fileId: z4.string(),\n title: z4.string().max(500).optional(),\n /** Glossary tag names (or ids) this file is an example of. */\n tags: z4.array(z4.string().min(1).max(MAX_FILE_TAG_LENGTH)).max(MAX_FILE_TAGS).optional()\n});\nvar UpdateTaskStatusRequestSchema = z4.object({\n sessionId: z4.string(),\n status: z4.string(),\n force: z4.boolean().optional().default(false)\n});\nvar StoreSessionIdRequestSchema = z4.object({\n sessionId: z4.string(),\n sdkSessionId: z4.string()\n});\nvar SetManualTestsRequestSchema = z4.object({\n sessionId: z4.string(),\n items: z4.array(z4.object({ title: z4.string().min(1) })).min(1)\n});\nvar EditManualTestRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1),\n newTitle: z4.string().min(1)\n});\nvar RemoveManualTestRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1)\n});\nvar ApproveManualTestRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1)\n});\nvar RejectManualTestRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1),\n reason: z4.string().min(1).max(2e3)\n});\nvar HeartbeatRequestSchema = AgentHeartbeatSchema;\nvar SessionStartRequestSchema = z4.object({\n sessionId: z4.string(),\n agentVersion: z4.string(),\n capabilities: z4.array(z4.string())\n});\nvar SessionStopRequestSchema = z4.object({\n sessionId: z4.string(),\n reason: z4.string().optional()\n});\nvar EndReviewSessionRequestSchema = z4.object({\n sessionId: z4.string(),\n reason: z4.enum([\"approved\", \"changes_requested\", \"finished\"]).optional()\n});\nvar ConnectAgentRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar ReportAgentStatusRequestSchema = z4.object({\n sessionId: z4.string(),\n status: z4.string(),\n /** Why the agent reports this status (e.g. \"user_question\" while an AskUserQuestion questionnaire is pending in the TUI). */\n reason: z4.string().optional(),\n /**\n * The pending question text, sent only alongside `reason: \"user_question\"`\n * so the server can surface it in the user-question notification body (and\n * thus the Attention feed) instead of a generic string. Optional: older\n * agents omit it and the server falls back to the generic wording.\n */\n questionText: z4.string().optional()\n});\nvar NotifyAgentVersionRequestSchema = z4.object({\n sessionId: z4.string(),\n agentVersion: z4.string()\n});\nvar DiscoveredPortSchema = z4.object({\n port: z4.number().int().min(1).max(65535),\n label: z4.string().min(1).max(64).optional(),\n protocol: z4.enum([\"http\", \"tcp\"]).optional(),\n detectedAt: z4.string()\n});\nvar ReportDiscoveredPortsRequestSchema = z4.object({\n sessionId: z4.string(),\n ports: z4.array(DiscoveredPortSchema).max(64)\n});\nvar ReportBootMilestoneRequestSchema = z4.object({\n sessionId: z4.string(),\n key: z4.string().max(64)\n});\nvar CreateSubtaskRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1),\n description: cardDescription,\n plan: z4.string().optional(),\n storyPointValue: z4.number().int().positive().optional(),\n ordinal: z4.number().int().nonnegative().optional(),\n followParentStatus: z4.boolean().optional(),\n /** Sibling subtask ids or slugs this subtask blocks on (explicit dependency\n * metadata — preferred over encoding order in plan text / ordinal). */\n dependsOn: z4.array(z4.string().min(1)).max(32).optional(),\n /** Glossary tag names to assign to the child. Unmatched names come back in\n * the response rather than failing the create. */\n tags: z4.array(z4.string().min(1)).max(10).optional()\n});\nvar UpdateSubtaskRequestSchema = z4.object({\n sessionId: z4.string(),\n subtaskId: z4.string(),\n title: z4.string().min(1).optional(),\n description: cardDescription,\n plan: z4.string().optional(),\n /** Orchestration statuses only (\"Planning\" | \"Open\") — the pack parent's\n * sanctioned promotion path. Execution statuses stay with the build\n * pipeline / force_update_task_status. Enforced server-side. */\n status: z4.string().optional(),\n /** Assign a project agent to the child — accepts the agent's id or exact\n * name; resolved against the parent task's project server-side. */\n agentIdOrName: z4.string().min(1).optional(),\n storyPointValue: z4.number().int().positive().optional(),\n followParentStatus: z4.boolean().optional(),\n /** Replace this subtask's dependency edges with these sibling ids/slugs.\n * Empty array clears all. Omit to leave dependencies unchanged. */\n dependsOn: z4.array(z4.string().min(1)).max(32).optional()\n});\nvar DeleteSubtaskRequestSchema = z4.object({\n sessionId: z4.string(),\n subtaskId: z4.string()\n});\nvar GetTaskPropertiesRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar UpdateTaskFieldsRequestSchema = z4.object({\n sessionId: z4.string(),\n plan: z4.string().optional(),\n description: cardDescription\n});\nvar UpdateTaskPropertiesRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().optional(),\n storyPointValue: z4.number().int().positive().optional(),\n tagIds: z4.array(z4.string()).optional(),\n tagNames: z4.array(z4.string()).optional(),\n githubPRUrl: z4.string().url().optional(),\n githubBranch: z4.string().optional(),\n // Canonical risk level, or null to clear — same semantics as the headless\n // update_task boundary (resolved to the project's Risk row in the handler).\n risk: riskLevelSchema.nullable().optional()\n});\nvar ListIconsRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar GenerateTaskIconRequestSchema = z4.object({\n sessionId: z4.string(),\n prompt: z4.string().min(1),\n aspectRatio: z4.string().optional()\n});\nvar SearchFaIconsRequestSchema = z4.object({\n sessionId: z4.string(),\n query: z4.string().min(1),\n first: z4.number().int().positive().optional()\n});\nvar PickFaIconRequestSchema = z4.object({\n sessionId: z4.string(),\n fontAwesomeId: z4.string().min(1),\n fontAwesomeStyle: z4.string().optional()\n});\nvar CreateFollowUpTaskRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1),\n description: cardDescription,\n plan: z4.string().optional(),\n storyPointValue: z4.number().int().positive().optional()\n});\nvar AddDependencyRequestSchema = z4.object({\n sessionId: z4.string(),\n dependsOnSlugOrId: z4.string()\n});\nvar RemoveDependencyRequestSchema = z4.object({\n sessionId: z4.string(),\n dependsOnSlugOrId: z4.string()\n});\nvar CreateSuggestionRequestSchema = z4.object({\n sessionId: z4.string(),\n title: z4.string().min(1),\n description: cardDescription,\n tagNames: z4.array(z4.string()).optional()\n});\nvar VoteSuggestionRequestSchema = z4.object({\n sessionId: z4.string(),\n suggestionId: z4.string(),\n value: z4.union([z4.literal(1), z4.literal(-1)])\n});\nvar TriggerIdentificationRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar HandoffToImplementerRequestSchema = z4.object({\n sessionId: z4.string(),\n // Optional difficulty sizing — sets the task's story points before resolving\n // the matched implementer agent. Omit to hand off using the task's current\n // story points (or the project's default task agent when unsized).\n storyPoints: z4.number().int().positive().optional(),\n // Optional kickoff note posted to the task chat alongside the handoff notice.\n message: z4.string().optional()\n});\nvar SubmitCodeReviewResultRequestSchema = z4.object({\n sessionId: z4.string(),\n approved: z4.boolean(),\n content: z4.string(),\n // Canonical risk level the reviewer assigned to this change. Required on every\n // verdict — the reviewer must judge it. Applied authoritatively server-side\n // (may raise OR lower an already-set value; the reviewer has that authority).\n risk: riskLevelSchema,\n // The commit SHA the reviewer actually reviewed. When present, the verdict is\n // rejected unless the task is still at this SHA (guards against a late\n // old-SHA verdict overwriting a newer review cycle).\n reviewedSha: z4.string().optional()\n});\nvar CycleCodingAgentKeyRequestSchema = z4.object({\n sessionId: z4.string(),\n rateLimitType: z4.string(),\n resetsAt: z4.string().optional()\n});\nvar StartChildCloudBuildRequestSchema = z4.object({\n sessionId: z4.string(),\n childTaskId: z4.string()\n});\nvar StopChildBuildRequestSchema = z4.object({\n sessionId: z4.string(),\n childTaskId: z4.string()\n});\nvar ApproveAndMergePRRequestSchema = z4.object({\n sessionId: z4.string(),\n childTaskId: z4.string()\n});\nvar PostChildChatMessageRequestSchema = z4.object({\n sessionId: z4.string(),\n childTaskId: z4.string(),\n message: z4.string().min(1)\n});\nvar UpdateChildStatusRequestSchema = z4.object({\n sessionId: z4.string(),\n childTaskId: z4.string(),\n status: z4.string()\n});\nvar GetAgentStatusRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar GetUiCliHistoryRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar GetActivePtySessionRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar ListActivePtySessionsRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar SendSoftStopRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar StopTaskSessionRequestSchema = z4.object({\n taskId: z4.string(),\n sessionId: z4.string()\n});\nvar FlushTaskQueueRequestSchema = z4.object({\n taskId: z4.string(),\n softStop: z4.boolean().optional()\n});\nvar CancelTaskQueuedMessageRequestSchema = z4.object({\n taskId: z4.string(),\n messageId: z4.string()\n});\nvar FlushSingleQueuedMessageRequestSchema = z4.object({\n taskId: z4.string(),\n messageId: z4.string(),\n softStop: z4.boolean().optional()\n});\nvar AnswerAgentQuestionRequestSchema = z4.object({\n taskId: z4.string(),\n requestId: z4.string(),\n answers: z4.record(z4.string(), z4.string())\n});\nvar ClearAgentTodosRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar AgentQuestionOptionSchema = z4.object({\n label: z4.string(),\n description: z4.string(),\n preview: z4.string().optional()\n});\nvar AgentQuestionSchema = z4.object({\n question: z4.string(),\n header: z4.string(),\n options: z4.array(AgentQuestionOptionSchema),\n multiSelect: z4.boolean().optional()\n});\nvar AskUserQuestionRequestSchema = z4.object({\n sessionId: z4.string(),\n question: z4.string().min(1),\n requestId: z4.string().min(1),\n questions: z4.array(AgentQuestionSchema).min(1)\n});\nvar PostAgentMessageRequestSchema = z4.object({\n sessionId: z4.string().min(1),\n content: z4.string(),\n milestone: z4.enum([\"plan_ready\", \"implementation_complete\", \"blocked\"]).optional()\n});\nvar EmitAgentEventRequestSchema = z4.object({\n sessionId: z4.string(),\n events: z4.array(AgentEventSchema).max(500)\n});\nvar RefreshGithubTokenRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar ReportReviewSpawnFailureRequestSchema = z4.object({\n sessionId: z4.string(),\n reviewSessionId: z4.string(),\n error: z4.string().max(2e3).optional()\n});\nvar RequestWorkspaceRecycleRequestSchema = z4.object({\n sessionId: z4.string(),\n reason: z4.string().max(2e3)\n});\nvar SpawnTaskSessionRequestSchema = z4.object({\n taskId: z4.string(),\n kind: z4.enum([\"tui\", \"shell\"])\n});\nvar StartCodeReviewRequestSchema = z4.object({\n taskId: z4.string(),\n force: z4.boolean().optional()\n});\nvar StopCodeReviewRequestSchema = z4.object({\n taskId: z4.string()\n});\nvar ReportSessionSpawnFailureRequestSchema = z4.object({\n sessionId: z4.string(),\n spawnedSessionId: z4.string(),\n error: z4.string().max(2e3).optional()\n});\nvar RefreshGithubTokenResponseSchema = z4.object({\n token: z4.string()\n});\nvar PTY_FRAME_MAX_CHARS = 256 * 1024;\nvar PTY_MAX_DIMENSION = 1e3;\nvar PtyOutputRequestSchema = z4.object({\n sessionId: z4.string(),\n data: z4.string().max(PTY_FRAME_MAX_CHARS),\n cols: z4.number().int().positive().max(PTY_MAX_DIMENSION).optional(),\n rows: z4.number().int().positive().max(PTY_MAX_DIMENSION).optional()\n});\nvar PtyEndedRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar PtyInputRequestSchema = z4.object({\n sessionId: z4.string(),\n data: z4.string().max(PTY_FRAME_MAX_CHARS)\n});\nvar PtyResizeRequestSchema = z4.object({\n sessionId: z4.string(),\n cols: z4.number().int().positive().max(PTY_MAX_DIMENSION),\n rows: z4.number().int().positive().max(PTY_MAX_DIMENSION)\n});\nvar PtyAttachRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar ReportPtyStreamRequestSchema = z4.object({\n sessionId: z4.string(),\n port: z4.number().int().positive().max(65535).nullable()\n});\nvar GetPtyStreamEndpointRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar PtyChatEventPayloadSchema = z4.discriminatedUnion(\"kind\", [\n z4.object({\n kind: z4.literal(\"init\"),\n model: z4.string().max(200),\n claudeSessionId: z4.string().max(100).optional()\n }),\n z4.object({\n kind: z4.literal(\"user_text\"),\n text: z4.string().max(16384),\n // Set by the SERVER (never the agent) when this prompt was injected by\n // Conveyor rather than typed by a human — the routed message's `source`\n // (`ci_success`, `review_trigger`, `automated_feedback`, …). The agent\n // pastes automated messages into the TUI exactly like human prompts, so the\n // CLI records both as plain transcript `user` records; without this the\n // builder chat renders \"All CI checks passed on your PR.\" as the human's\n // own bubble. Absent ⇒ a genuine human prompt.\n source: z4.string().max(60).optional()\n }),\n z4.object({ kind: z4.literal(\"assistant_text\"), text: z4.string().max(16384) }),\n z4.object({\n kind: z4.literal(\"tool_use\"),\n name: z4.string().max(200),\n // Compact preview: JSON.stringify(input) truncated agent-side. The cap\n // matches the text events because AskUserQuestion payloads ride this field\n // and the web lifts them into an interactive card — a tight cap forced\n // option descriptions down to 80 chars, making them unreadable. Every\n // other tool keeps a far smaller agent-side budget (`TOOL_INPUT_MAX` in\n // `chat-record-mapper.ts`), so the ring does not grow for normal calls.\n input: z4.string().max(16384),\n // Transcript tool_use block id — lets the client pair the tool_result.\n id: z4.string().max(100).optional()\n }),\n z4.object({\n kind: z4.literal(\"tool_result\"),\n // tool_use block id this result answers (absent on malformed records).\n toolUseId: z4.string().max(100).optional(),\n // Compact output preview, truncated agent-side.\n output: z4.string().max(2e3),\n isError: z4.boolean().optional()\n }),\n z4.object({ kind: z4.literal(\"turn_end\") })\n]);\nvar PtyChatEventRequestSchema = z4.object({\n sessionId: z4.string(),\n event: PtyChatEventPayloadSchema\n});\nvar PtyChatAttachRequestSchema = z4.object({\n sessionId: z4.string()\n});\nvar CreatePRResponseSchema = z4.object({\n prNumber: z4.number().int().positive(),\n prUrl: z4.string().url(),\n /** Advisory glossary-upkeep note derived from the PR's changed files matched\n * against tag contextPaths — rendered into the tool result, never stored. */\n glossaryNote: z4.string().optional()\n});\nvar PostToChatResponseSchema = z4.object({\n messageId: z4.string()\n});\nvar UpdateTaskStatusResponseSchema = z4.object({\n taskId: z4.string(),\n status: z4.string()\n});\nvar StoreSessionIdResponseSchema = z4.object({\n success: z4.boolean()\n});\nvar HeartbeatResponseSchema = z4.object({\n acknowledged: z4.boolean()\n});\nvar SessionStartResponseSchema = z4.object({\n sessionId: z4.string(),\n startedAt: z4.string()\n});\nvar SessionStopResponseSchema = z4.object({\n sessionId: z4.string(),\n stoppedAt: z4.string()\n});\nvar DeleteSubtaskResponseSchema = z4.object({\n deleted: z4.boolean()\n});\n\n// src/types/agent-session-project-requests.ts\nimport { z as z5 } from \"zod\";\nvar cardDescription2 = z5.string().max(CARD_DESCRIPTION_MAX, CARD_DESCRIPTION_LIMIT_MESSAGE).optional();\nvar ListAccessibleProjectsRequestSchema = z5.object({\n pageSize: z5.number().int().positive().max(100).optional().default(100)\n});\nvar ListProjectTasksRequestSchema = z5.object({\n projectId: z5.string(),\n status: z5.string().optional(),\n // Card types to include. Omitted/empty → defaults to [\"task\"] in the handler\n // (mirrors searchProjectTasks) so listing doesn't surface incidents/suggestions\n // unless asked. Enum validation lives at the MCP tool layer.\n typeFilters: z5.array(z5.string()).optional(),\n assigneeId: z5.string().optional(),\n unassigned: z5.boolean().optional(),\n // Scope to a sub-project board when provided. Unlike the board layer's `?? null`\n // semantics, agents default to seeing the whole project when omitted.\n subProjectId: z5.string().nullable().optional(),\n limit: z5.number().int().positive().optional().default(50)\n}).refine((p) => !(p.unassigned && p.assigneeId), {\n message: \"Pass either assigneeId or unassigned, not both\"\n});\nvar GetProjectTaskRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string()\n});\nvar SearchProjectTasksRequestSchema = z5.object({\n projectId: z5.string(),\n // Tag names, matched case-insensitively against the project glossary.\n tagNames: z5.array(z5.string()).optional(),\n // How to combine tagNames: \"any\" (default) = carries at least one,\n // \"all\" = carries every one.\n tagMatch: z5.enum([\"any\", \"all\"]).optional(),\n // Expand each named tag to its descendants in the tag DAG before matching,\n // so a parent tag sweeps its whole area. Default false.\n includeChildTags: z5.boolean().optional(),\n searchQuery: z5.string().optional(),\n statusFilters: z5.array(z5.string()).optional(),\n // Card types to include. Omitted/empty → defaults to [\"task\"] in the handler so\n // search doesn't surface incidents/suggestions unless asked. Enum validation lives\n // at the MCP tool layer (mirrors statusFilters).\n typeFilters: z5.array(z5.string()).optional(),\n assigneeId: z5.string().optional(),\n unassigned: z5.boolean().optional(),\n // Scope to a sub-project board when provided. Unlike the board layer's `?? null`\n // semantics, agents default to seeing the whole project when omitted.\n subProjectId: z5.string().nullable().optional(),\n limit: z5.number().int().positive().optional().default(20)\n}).refine((p) => !(p.unassigned && p.assigneeId), {\n message: \"Pass either assigneeId or unassigned, not both\"\n});\nvar ListProjectTagsRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar GetProjectTagRequestSchema = z5.object({\n projectId: z5.string(),\n /** Tag id or exact (case-insensitive) tag name. */\n tag: z5.string().min(1).max(100)\n});\nvar ListProjectTagAttachmentsRequestSchema = z5.object({\n projectId: z5.string(),\n /** Tag id or exact (case-insensitive) tag name. */\n tag: z5.string().min(1).max(100),\n limit: z5.number().int().min(1).max(60).optional(),\n offset: z5.number().int().min(0).optional()\n});\nvar SetProjectFileTagsRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n fileId: z5.string(),\n tags: z5.array(z5.string().min(1).max(MAX_FILE_TAG_LENGTH)).max(MAX_FILE_TAGS),\n requestingUserId: z5.string().optional()\n});\nvar GetProjectSummaryRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar GetProjectOnboardingStatusRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar GetProjectOnboardingStepRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar GetProjectConnectUrlsRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar conveyorCapabilitySchema = z5.enum([\n \"read\",\n \"create\",\n \"update\",\n \"chat\",\n \"files\",\n \"build\"\n]);\nvar GetConnectionContextRequestSchema = z5.object({\n projectId: z5.string(),\n // Optional board scope (CONVEYOR_SUBPROJECT_ID). Validated to belong to the\n // project in the handler; an invalid/foreign id is reported, not silently\n // dropped, so a mis-scoped connection is never presented as board-specific.\n subProjectId: z5.string().nullable().optional()\n});\nvar VerifyConnectionRequestSchema = z5.object({\n projectId: z5.string(),\n subProjectId: z5.string().nullable().optional(),\n intendedActions: z5.array(conveyorCapabilitySchema).optional()\n});\nvar ListAccessibleSubprojectsRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar CreateProjectTaskRequestSchema = z5.object({\n projectId: z5.string(),\n title: z5.string().min(1),\n description: cardDescription2,\n plan: z5.string().optional(),\n status: z5.string().optional(),\n // Assign to a sub-project board. Validated to belong to `projectId` in the handler.\n subProjectId: z5.string().nullable().optional(),\n requestingUserId: z5.string().optional()\n});\nvar UpdateProjectTaskRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n title: z5.string().optional(),\n description: cardDescription2,\n plan: z5.string().optional(),\n // Enum validation lives at the MCP tool layer (mirrors createProjectTask);\n // the handler routes through the shared updateStatus core (InProgress\n // dependency check + cleanup/board/Slack side effects), not the stricter\n // card-type-validating path the Socket.IO updateTaskStatus mutation uses.\n status: z5.string().optional(),\n // Canonical risk level, or null to clear. Resolved to the project's\n // configured Risk row (by rank) in the handler.\n risk: riskLevelSchema.nullable().optional(),\n // Story-point value, or null to clear. Resolved to the project's configured\n // StoryPoint row in the handler, which rejects an unconfigured value.\n storyPointValue: z5.number().int().positive().nullable().optional(),\n assignedUserId: z5.string().nullish(),\n // Move to a different sub-project board, or null to move to the parent board.\n // Validated to belong to `projectId` in the handler.\n subProjectId: z5.string().nullable().optional(),\n requestingUserId: z5.string().optional()\n}).strict().refine(\n (v) => v.title !== void 0 || v.description !== void 0 || v.plan !== void 0 || v.status !== void 0 || v.risk !== void 0 || v.storyPointValue !== void 0 || v.assignedUserId !== void 0 || v.subProjectId !== void 0,\n {\n message: \"update_task requires at least one field to change (title, description, plan, status, risk, storyPointValue, assignedUserId, or subProjectId)\"\n }\n);\nvar TransitionProjectTaskStatusRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n toStatus: z5.string(),\n expectedFromStatus: z5.string().optional(),\n // Optional raise-only risk to attempt alongside the transition\n // (approve → low, request_changes → medium by default).\n risk: riskLevelSchema.optional(),\n requestingUserId: z5.string().optional()\n});\nvar MoveProjectCardRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n destinationProjectId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar PostToProjectTaskChatRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n content: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar GetProjectTaskCliRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n limit: z5.number().int().positive().optional().default(50),\n source: z5.string().optional()\n});\nvar GetProjectTaskSessionsRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string()\n});\nvar QueryProjectGcpLogsRequestSchema = z5.object({\n projectId: z5.string(),\n env: z5.enum([\"prod\", \"dev\", \"claudespace\"]).optional(),\n severity: z5.enum([\"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\", \"CRITICAL\", \"ALERT\", \"EMERGENCY\"]).optional(),\n services: z5.array(z5.string().min(1).max(200)).max(25).optional(),\n sqlInstances: z5.array(z5.string().min(1).max(200)).max(25).optional(),\n allServices: z5.boolean().optional(),\n search: z5.string().max(256).optional(),\n filter: z5.string().max(1e3).optional(),\n startTime: z5.string().optional(),\n endTime: z5.string().optional(),\n limit: z5.number().int().min(1).max(200).optional().default(50),\n pageToken: z5.string().max(4096).optional()\n});\nvar QueryProjectGrafanaLogsRequestSchema = z5.object({\n projectId: z5.string(),\n env: z5.enum([\"prod\", \"dev\"]).optional(),\n services: z5.array(z5.string().min(1).max(200)).max(25).optional(),\n level: z5.enum([\"debug\", \"info\", \"warn\", \"error\", \"fatal\"]).optional(),\n search: z5.string().max(256).optional(),\n logql: z5.string().max(2e3).optional(),\n startTime: z5.string().optional(),\n endTime: z5.string().optional(),\n limit: z5.number().int().min(1).max(200).optional().default(50)\n});\nvar driveFileNameSchema = z5.string().min(1).max(255).regex(/^[^/\\\\\\r\\n]+$/, \"File names cannot contain slashes or line breaks\");\nvar DRIVE_MAX_CONTENT_CHARS = 1e6;\nvar ListProjectDriveFilesRequestSchema = z5.object({\n projectId: z5.string(),\n folderId: z5.string().max(200).optional(),\n search: z5.string().max(200).optional(),\n limit: z5.number().int().min(1).max(200).optional()\n});\nvar ReadProjectDriveFileRequestSchema = z5.object({\n projectId: z5.string(),\n fileId: z5.string().min(1).max(200)\n});\nvar CreateProjectDriveFileRequestSchema = z5.object({\n projectId: z5.string(),\n name: driveFileNameSchema,\n content: z5.string().max(DRIVE_MAX_CONTENT_CHARS),\n mimeType: z5.string().max(200).optional(),\n folderId: z5.string().max(200).optional()\n});\nvar UpdateProjectDriveFileRequestSchema = z5.object({\n projectId: z5.string(),\n fileId: z5.string().min(1).max(200),\n content: z5.string().max(DRIVE_MAX_CONTENT_CHARS),\n mimeType: z5.string().max(200).optional()\n});\nvar DeleteProjectDriveFileRequestSchema = z5.object({\n projectId: z5.string(),\n fileId: z5.string().min(1).max(200)\n});\nvar CreateProjectDriveFolderRequestSchema = z5.object({\n projectId: z5.string(),\n name: driveFileNameSchema,\n folderId: z5.string().max(200).optional()\n});\nvar StartProjectBuildRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar StopProjectBuildRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar StartProjectWorkspaceRequestSchema = z5.object({\n projectId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar StopProjectWorkspaceRequestSchema = z5.object({\n projectId: z5.string(),\n destroy: z5.boolean().optional(),\n requestingUserId: z5.string().optional()\n});\nvar ListMyLiveSessionsRequestSchema = z5.object({\n projectId: z5.string(),\n /** Admin-only: list another member's sessions instead of the caller's. */\n targetUserId: z5.string().optional()\n});\nvar ListProjectSessionGroupsRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar ListMyLiveSessionsAcrossProjectsRequestSchema = z5.object({});\nvar GetProjectAvailableTuisRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar StartAdhocSessionRequestSchema = z5.object({\n projectId: z5.string(),\n label: z5.string().max(200).optional(),\n /** Coding-agent key to launch under — validated pick-time (ownership + TUI availability) in the handler. */\n codingAgentKeyId: z5.string().optional(),\n /** Model override (Claude model id) — overrides the launch key's own model. */\n model: z5.string().max(200).optional(),\n /**\n * Session role. Constrained: other task-less modes fall through to the pm\n * runner in the pod entrypoint, and \"review\" would crash without a task.\n */\n mode: z5.enum([\"adhoc\", \"pm\"]).optional(),\n /** Base branch to check out (defaults to the project's dev branch). */\n branch: z5.string().max(300).optional(),\n /**\n * Server-assembled instructions the pod's TUI auto-submits once on first boot\n * (headless kickoff). Used by the onboarding \"Set it up for me\" flow to seed a\n * setup-driver prompt; the session stays watchable/interactive in the Sessions\n * view. `ensureAdhocWorkspace` persists it and clears it after first submit.\n */\n initialPrompt: z5.string().max(2e4).optional(),\n requestingUserId: z5.string().optional()\n});\nvar StopAdhocSessionRequestSchema = z5.object({\n projectId: z5.string(),\n workspaceId: z5.string(),\n destroy: z5.boolean().optional(),\n requestingUserId: z5.string().optional()\n});\nvar ResumeAdhocSessionRequestSchema = z5.object({\n projectId: z5.string(),\n workspaceId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar RefreshCodingAgentKeyUsageRequestSchema = z5.object({\n projectId: z5.string(),\n keyId: z5.string().optional(),\n requestingUserId: z5.string().optional()\n});\nvar ListKeysToProbeRequestSchema = z5.object({\n sessionId: z5.string()\n});\nvar CreateProjectReleaseRequestSchema = z5.object({\n projectId: z5.string(),\n taskIds: z5.array(z5.string()).optional(),\n requestingUserId: z5.string().optional()\n});\nvar AddTasksToProjectReleaseRequestSchema = z5.object({\n projectId: z5.string(),\n taskIds: z5.array(z5.string()).min(1),\n requestingUserId: z5.string().optional()\n});\nvar ApproveProjectMergePRRequestSchema = z5.object({\n projectId: z5.string(),\n childTaskId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar ListProjectSubtasksRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string()\n});\nvar CreateProjectSubtaskRequestSchema = z5.object({\n projectId: z5.string(),\n parentTaskId: z5.string(),\n title: z5.string().min(1),\n description: cardDescription2,\n plan: z5.string().optional(),\n ordinal: z5.number().int().nonnegative().optional(),\n storyPointValue: z5.number().int().positive().optional(),\n followParentStatus: z5.boolean().optional(),\n /** Sibling subtask ids or slugs this subtask blocks on (explicit dependency\n * metadata — preferred over encoding order in plan text / ordinal). */\n dependsOn: z5.array(z5.string().min(1)).max(32).optional(),\n requestingUserId: z5.string().optional()\n});\nvar UpdateProjectSubtaskRequestSchema = z5.object({\n projectId: z5.string(),\n subtaskId: z5.string(),\n title: z5.string().optional(),\n description: cardDescription2,\n plan: z5.string().optional(),\n status: z5.string().optional(),\n ordinal: z5.number().int().nonnegative().optional(),\n storyPointValue: z5.number().int().positive().optional(),\n followParentStatus: z5.boolean().optional(),\n /** Replace-set of sibling subtask ids/slugs this subtask blocks on ([] clears).\n * Mirrors the in-pod updateSubtask semantics. */\n dependsOn: z5.array(z5.string().min(1)).max(32).optional(),\n requestingUserId: z5.string().optional()\n});\nvar DeleteProjectSubtaskRequestSchema = z5.object({\n projectId: z5.string(),\n subtaskId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar GetProjectTaskChatRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n limit: z5.number().int().positive().optional().default(20)\n});\nvar AddProjectTaskDependencyRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n dependsOnSlugOrId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar RemoveProjectTaskDependencyRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n dependsOnSlugOrId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar VoteProjectSuggestionRequestSchema = z5.object({\n projectId: z5.string(),\n suggestionId: z5.string(),\n value: z5.union([z5.literal(1), z5.literal(-1)]),\n requestingUserId: z5.string().optional()\n});\nvar GetProjectTaskDependenciesRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string()\n});\nvar ListProjectTaskFilesRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string()\n});\nvar GetProjectAttachmentRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n fileId: z5.string(),\n /** Byte offset into text content (paging large logs/JSON). Default 0. */\n offset: z5.number().int().nonnegative().optional(),\n /** Max bytes of text content to return from `offset`. Server default applies. */\n maxBytes: z5.number().int().positive().optional()\n});\nvar RequestProjectFileUploadRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n fileName: z5.string().min(1).max(255),\n mimeType: z5.string().min(1).max(128),\n fileSize: z5.number().int().positive().max(MAX_FILE_SIZE_BYTES),\n requestingUserId: z5.string().optional()\n});\nvar ConfirmProjectFileUploadRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n fileId: z5.string(),\n /** When set, the attachment is also posted to the task chat with this text. */\n comment: z5.string().max(2e3).optional(),\n /** Glossary tag names (or ids) this file is an example of. */\n tags: z5.array(z5.string().min(1).max(MAX_FILE_TAG_LENGTH)).max(MAX_FILE_TAGS).optional(),\n requestingUserId: z5.string().optional()\n});\nvar CreateProjectPullRequestRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n title: z5.string().min(1),\n body: z5.string(),\n head: z5.string().optional(),\n base: z5.string().optional(),\n requestingUserId: z5.string().optional()\n});\nvar ListProjectMembersRequestSchema = z5.object({\n projectId: z5.string()\n});\nvar AddProjectTaskReviewerRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n userId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar RemoveProjectTaskReviewerRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n userId: z5.string(),\n requestingUserId: z5.string().optional()\n});\nvar ListProjectManualTestsRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string()\n});\nvar QueryProjectManualTestsRequestSchema = z5.object({\n projectId: z5.string(),\n cardStatuses: z5.array(z5.string()).optional(),\n testStatuses: z5.array(z5.enum([\"open\", \"approved\", \"rejected\"])).optional()\n});\nvar SetProjectManualTestsRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n items: z5.array(z5.object({ title: z5.string().min(1) })).min(1),\n requestingUserId: z5.string().optional()\n});\nvar EditProjectManualTestRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n title: z5.string().min(1),\n newTitle: z5.string().min(1),\n requestingUserId: z5.string().optional()\n});\nvar RemoveProjectManualTestRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n title: z5.string().min(1),\n requestingUserId: z5.string().optional()\n});\nvar ApproveProjectManualTestRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n title: z5.string().min(1),\n requestingUserId: z5.string().optional()\n});\nvar RejectProjectManualTestRequestSchema = z5.object({\n projectId: z5.string(),\n taskId: z5.string(),\n title: z5.string().min(1),\n reason: z5.string().min(1).max(2e3),\n requestingUserId: z5.string().optional()\n});\nvar CreateProjectSuggestionRequestSchema = z5.object({\n projectId: z5.string(),\n title: z5.string().min(1),\n description: cardDescription2,\n tagNames: z5.array(z5.string()).optional(),\n requestingUserId: z5.string().optional()\n});\n\n// src/types/review-guide-types.ts\nimport { z as z6 } from \"zod\";\nvar SHA_PATTERN = /^[0-9a-f]{40}$/i;\nvar ReviewGuideFileReferenceSchema = z6.object({\n path: z6.string().min(1).max(500),\n startLine: z6.number().int().positive().max(1e6).optional(),\n endLine: z6.number().int().positive().max(1e6).optional(),\n hunkHeader: z6.string().min(1).max(300).optional()\n}).strict().superRefine((value, ctx) => {\n if (value.endLine !== void 0 && value.startLine === void 0) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"startLine\"],\n message: \"startLine is required when endLine is set\"\n });\n }\n if (value.startLine !== void 0 && value.endLine !== void 0 && value.endLine < value.startLine) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"endLine\"],\n message: \"endLine must be greater than or equal to startLine\"\n });\n }\n});\nvar ReviewGuideSectionSchema = z6.object({\n title: z6.string().min(1).max(160),\n explanation: z6.string().min(1).max(2e3),\n classification: z6.enum([\"core\", \"supporting\"]).optional(),\n files: z6.array(ReviewGuideFileReferenceSchema).min(1).max(20)\n}).strict();\nvar ReviewGuideContentSchema = z6.object({\n overview: z6.string().min(1).max(3e3),\n sections: z6.array(ReviewGuideSectionSchema).min(1).max(12)\n}).strict();\nvar PublishReviewGuideRequestSchema = ReviewGuideContentSchema.extend({\n sessionId: z6.string().min(1),\n reviewedSha: z6.string().regex(SHA_PATTERN, \"reviewedSha must be a 40-character commit SHA\")\n}).strict();\n\n// src/types/task-audit-requests.ts\nimport { z as z7 } from \"zod\";\n\n// src/utils/context-path-core.ts\nvar CONTEXT_PATH_UNTRACKED_PREFIXES = [\n \"node_modules/\",\n \".git/\",\n \"dist/\",\n \"build/\",\n \".next/\"\n];\nfunction normalizeContextPath(rawPath) {\n return rawPath.trim().replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\n\n// src/utils/context-link-verify.ts\nvar CONTEXT_LINK_LOCATOR_MAX = 300;\nvar TEST_TITLE = /\\b(?:it|test|describe)(?:\\.\\w+)?\\s*\\(\\s*(['\"`])((?:(?!\\1)[\\s\\S])*)\\1/g;\nfunction extractTestTitles(content) {\n return [...content.matchAll(TEST_TITLE)].map((m) => m[2]);\n}\nfunction isPlaceholderLocator(locator) {\n return locator.includes(\"<\") || locator.includes(\">\");\n}\nfunction locatorMatchesContent(content, locatorType, locator) {\n if (locatorType === \"code\") return content.includes(locator);\n return extractTestTitles(content).some((title) => title.includes(locator));\n}\nfunction contextLinkCheckKey(link) {\n return [normalizeContextPath(link.path), link.locatorType ?? \"\", link.locator ?? \"\"].join(\"\\n\");\n}\nfunction judgeContextLink(link, evidence) {\n const path = normalizeContextPath(link.path);\n if (!path) return { status: \"unchecked\", detail: \"empty path\" };\n if (CONTEXT_PATH_UNTRACKED_PREFIXES.some((prefix) => path.startsWith(prefix))) {\n return { status: \"unchecked\", detail: \"path is outside the tracked tree\" };\n }\n if (link.type === \"folder\") {\n if (evidence.entryType === \"tree\") return { status: \"ok\" };\n if (evidence.entryType === \"blob\") return { status: \"stale\", detail: \"expected a folder, found a file\" };\n return { status: \"stale\", detail: \"folder not found\" };\n }\n if (evidence.entryType === void 0) return { status: \"stale\", detail: \"file not found\" };\n if (evidence.entryType === \"tree\") return { status: \"stale\", detail: \"expected a file, found a folder\" };\n const { locator, locatorType } = link;\n if (!locator || !locatorType) return { status: \"ok\" };\n if (isPlaceholderLocator(locator)) {\n return { status: \"unchecked\", detail: \"placeholder locator (contains <>)\" };\n }\n const content = evidence.content ?? null;\n if (content === null) {\n return { status: \"unchecked\", detail: \"file content unavailable\" };\n }\n if (locatorMatchesContent(content, locatorType, locator)) return { status: \"ok\" };\n return {\n status: \"stale\",\n detail: locatorType === \"test\" ? `no test titled \"${locator}\" (renamed/removed?)` : `no match for \"${locator}\" (renamed/removed?)`\n };\n}\nfunction linkNeedsContent(link) {\n return link.type !== \"folder\" && typeof link.locator === \"string\" && link.locator.length > 0 && !isPlaceholderLocator(link.locator);\n}\nfunction verificationForLink(link, checks) {\n const entry = checks?.results[contextLinkCheckKey(link)];\n if (!checks || !entry) return { status: \"unchecked\" };\n return {\n status: entry.status,\n ...entry.detail === void 0 ? {} : { detail: entry.detail },\n checkedAt: checks.checkedAt,\n ref: checks.ref,\n ...checks.sha === void 0 ? {} : { sha: checks.sha }\n };\n}\nfunction withLinkVerification(links, checks) {\n return links.map((link) => ({ ...link, verification: verificationForLink(link, checks) }));\n}\nfunction parseTagContextLink(entry) {\n if (typeof entry !== \"object\" || entry === null) return null;\n const { type, path, label, locator, locatorType } = entry;\n if (typeof path !== \"string\" || path.length === 0) return null;\n if (type !== \"rule\" && type !== \"doc\" && type !== \"file\" && type !== \"folder\") return null;\n return {\n type,\n path,\n ...typeof label === \"string\" ? { label } : {},\n ...typeof locator === \"string\" && locator.length > 0 ? { locator } : {},\n ...locatorType === \"test\" || locatorType === \"code\" ? { locatorType } : {}\n };\n}\nfunction parseTagContextLinks(value) {\n if (!Array.isArray(value)) return [];\n return value.map(parseTagContextLink).filter((link) => link !== null);\n}\nfunction parseContextPathChecks(value) {\n if (typeof value !== \"object\" || value === null) return null;\n const { checkedAt, ref, sha, results } = value;\n if (typeof checkedAt !== \"string\" || typeof ref !== \"string\") return null;\n if (typeof results !== \"object\" || results === null) return null;\n const parsed = {};\n for (const [key, entry] of Object.entries(results)) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const { status, detail } = entry;\n if (status !== \"ok\" && status !== \"stale\" && status !== \"unchecked\") continue;\n parsed[key] = { status, ...typeof detail === \"string\" ? { detail } : {} };\n }\n return {\n checkedAt,\n ref,\n ...typeof sha === \"string\" ? { sha } : {},\n results: parsed\n };\n}\n\n// src/utils/tag-limits.ts\nvar TAG_DESCRIPTION_MAX = CARD_DESCRIPTION_MAX;\nvar TAG_OVERVIEW_MAX = 32e3;\nvar TAG_REASON_MAX = 500;\n\n// src/types/task-audit-requests.ts\nvar ProjectTagContextPathSchema = z7.object({\n type: z7.enum([\"rule\", \"doc\", \"file\", \"folder\"]),\n path: z7.string().min(1).max(500),\n label: z7.string().max(100).optional(),\n /** Verified-link tether — text that must keep existing in the file. */\n locator: z7.string().min(1).max(CONTEXT_LINK_LOCATOR_MAX).regex(/^[^\\r\\n]*$/, \"Locator cannot contain line breaks\").optional(),\n /** test = must appear in a real test/describe title; code = any substring. */\n locatorType: z7.enum([\"test\", \"code\"]).optional()\n}).refine((link) => link.locator === void 0 === (link.locatorType === void 0), {\n message: \"locator and locatorType must be provided together\"\n}).refine((link) => link.locator === void 0 || link.type !== \"folder\", {\n message: \"folder links cannot carry a locator\"\n});\nvar hexColor = z7.string().regex(/^#[0-9a-fA-F]{6}$/, \"Expected #RRGGBB hex color\");\nvar overviewPathSchema = z7.string().min(1).max(500).regex(/^[^\\r\\n]*$/, \"Overview path cannot contain line breaks\");\nvar CreateProjectTagRequestSchema = z7.object({\n projectId: z7.string(),\n name: z7.string().min(1).max(50),\n color: hexColor.optional(),\n description: z7.string().max(TAG_DESCRIPTION_MAX).optional(),\n overview: z7.string().max(TAG_OVERVIEW_MAX).optional(),\n /** Source the overview from this repo file (stored overview stays as the pending fallback). */\n overviewPath: overviewPathSchema.optional(),\n contextPaths: z7.array(ProjectTagContextPathSchema).max(20).optional(),\n /** Parents to link at create time (multi-parent DAG). */\n parentTagIds: z7.array(z7.string()).max(25).optional(),\n requestingUserId: z7.string().optional()\n});\nvar UpdateProjectTagRequestSchema = z7.object({\n projectId: z7.string(),\n tagId: z7.string(),\n name: z7.string().min(1).max(50).optional(),\n color: hexColor.optional(),\n description: z7.string().max(TAG_DESCRIPTION_MAX).optional(),\n /** Full markdown glossary body; null clears it. Rejected while overviewPath is set. */\n overview: z7.string().max(TAG_OVERVIEW_MAX).nullable().optional(),\n /** Repo file to source the overview from; null clears back to the stored overview. */\n overviewPath: overviewPathSchema.nullable().optional(),\n /** Full replacement of the tag's context links when provided. */\n contextPaths: z7.array(ProjectTagContextPathSchema).max(20).optional(),\n /** Full-set replacement of the tag's parent tags (multi-parent DAG). */\n parentTagIds: z7.array(z7.string()).max(25).optional(),\n /** One-line revision provenance, recorded in the tag's history. */\n reason: z7.string().max(TAG_REASON_MAX).optional(),\n /** Card the caller was working in — stamped into the revision history. */\n taskId: z7.string().optional(),\n requestingUserId: z7.string().optional()\n});\nvar PostToProjectChatRequestSchema = z7.object({\n projectId: z7.string(),\n content: z7.string().min(1).max(2e4),\n requestingUserId: z7.string().optional(),\n /** Marks the post so the server can persist it beyond chat (tag-audit summaries land in tag history). */\n kind: z7.enum([\"tag_audit_summary\"]).optional()\n});\nvar StartTagAuditRequestSchema = z7.object({\n projectId: z7.string(),\n requestingUserId: z7.string().optional()\n});\nvar StartTaskAuditRequestSchema = z7.object({\n projectId: z7.string(),\n taskIds: z7.array(z7.string()).min(1).max(20),\n requestingUserId: z7.string().optional()\n});\nvar GetActiveAuditSessionsRequestSchema = z7.object({\n projectId: z7.string()\n});\nvar ReportTaskAuditResultRequestSchema = z7.object({\n projectId: z7.string(),\n taskId: z7.string(),\n summary: z7.string(),\n turnGrades: z7.array(\n z7.object({\n turnIndex: z7.number(),\n phase: z7.enum([\"planning\", \"building\", \"human\"]),\n grade: z7.enum([\"correct\", \"neutral\", \"blunder\"]),\n reasoning: z7.string(),\n eventType: z7.string(),\n eventSummary: z7.string()\n })\n ),\n planningAccuracy: z7.number().nullable(),\n buildingAccuracy: z7.number().nullable(),\n humanAccuracy: z7.number().nullable(),\n planningCorrect: z7.number(),\n planningNeutral: z7.number(),\n planningBlunder: z7.number(),\n buildingCorrect: z7.number(),\n buildingNeutral: z7.number(),\n buildingBlunder: z7.number(),\n humanCorrect: z7.number(),\n humanNeutral: z7.number(),\n humanBlunder: z7.number(),\n humanEvaluations: z7.array(\n z7.object({\n messageIndex: z7.number(),\n rating: z7.union([z7.literal(-1), z7.literal(0), z7.literal(1)]),\n reasoning: z7.string()\n })\n ).optional(),\n suggestionIds: z7.array(z7.string()),\n auditCostUsd: z7.number().nullable(),\n model: z7.string().nullable(),\n /** When set, the audit is marked failed with this message instead. */\n error: z7.string().optional()\n});\nvar GetTaskAuditsRequestSchema = z7.object({\n projectId: z7.string(),\n limit: z7.number().int().positive().max(200).optional().default(50)\n});\nvar GetTaskAuditRequestSchema = z7.object({\n projectId: z7.string(),\n auditId: z7.string()\n});\nvar GetTaskAuditAggregatesRequestSchema = z7.object({\n projectId: z7.string()\n});\nvar DeleteTaskAuditRequestSchema = z7.object({\n projectId: z7.string(),\n auditId: z7.string(),\n requestingUserId: z7.string().optional()\n});\nvar MarkInitialPromptSubmittedRequestSchema = z7.object({\n sessionId: z7.string()\n});\n\n// src/types/agent-session-events.ts\nvar CRITICAL_AUTOMATED_SOURCES = /* @__PURE__ */ new Set([\n \"ci_failure\",\n \"review_trigger\",\n \"merge_conflict\",\n \"merge_failed\",\n \"pull_branch\",\n // Child-task events for pack parents: the orchestrator must act (merge the\n // child's PR, start unblocked siblings, finish the pack) even after it\n // reported completed for a prior turn. Only ever sent to parent tasks.\n \"parent\"\n]);\nvar createAgentSessionRoom = (sessionId) => `agentSession:${sessionId}`;\nvar createProjectRoom = (projectId) => `project:${projectId}`;\n\n// src/types/workspace-v3.ts\nvar WORKSPACE_DESIRED_STATES = [\"Running\", \"Sleeping\", \"Destroyed\"];\nvar WORKSPACE_OBSERVED_STATES = [\n \"Pending\",\n \"Provisioning\",\n \"Running\",\n \"Sleeping\",\n \"Destroying\",\n \"Destroyed\",\n \"Failed\"\n];\nvar WORKSPACE_PURPOSES = [\"primary\", \"review\", \"project\", \"adhoc\"];\nvar TASK_LESS_WORKSPACE_PURPOSES = [\n \"project\",\n \"adhoc\"\n];\nvar WORKSPACE_POD_PHASES = [\n \"Creating\",\n \"Ready\",\n \"Bound\",\n \"Suspended\",\n \"Terminating\",\n \"Gone\",\n \"Failed\"\n];\nvar WORKSPACE_BACKENDS = [\"gke\", \"codespace\"];\nvar WORKSPACE_SESSION_ROLES = [\"writer\", \"reader\"];\nvar WORKSPACE_SESSION_MODES = [\n \"build\",\n \"review\",\n \"pm\",\n \"help\",\n \"adhoc\",\n \"pack\",\n \"shell\"\n];\nvar WORKSPACE_SESSION_STATUSES = [\"Pending\", \"Active\", \"Stranded\", \"Ended\"];\nvar MAX_DISCOVERED_PORTS = 16;\nfunction sanitizeDiscoveredPorts(raw) {\n if (!Array.isArray(raw)) return [];\n const seen = /* @__PURE__ */ new Set();\n const out = [];\n for (const entry of raw) {\n if (out.length >= MAX_DISCOVERED_PORTS) break;\n if (!entry || typeof entry !== \"object\") continue;\n const port = entry.port;\n if (!isAllowablePreviewPort(port)) continue;\n if (seen.has(port)) continue;\n seen.add(port);\n const label = entry.label;\n const protocol = entry.protocol;\n const detectedAt = entry.detectedAt;\n out.push({\n port,\n ...typeof label === \"string\" && label.length > 0 ? { label } : {},\n ...protocol === \"http\" || protocol === \"tcp\" ? { protocol } : {},\n detectedAt: typeof detectedAt === \"string\" ? detectedAt : (/* @__PURE__ */ new Date(0)).toISOString()\n });\n }\n return out;\n}\n\n// src/types/repository-provider-types.ts\nvar REPOSITORY_PROVIDER_IDS = [\"github\", \"forgejo\"];\nfunction forgeProviderName(settings) {\n const provider = settings?.forge?.provider;\n return typeof provider === \"string\" && provider.length > 0 ? provider : \"github\";\n}\nfunction normalizedUrl(value, field, protocols) {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`Forgejo ${field} is required`);\n }\n let parsed;\n try {\n parsed = new URL(value.trim());\n } catch {\n throw new Error(`Forgejo ${field} must be an absolute URL`);\n }\n if (!protocols.includes(parsed.protocol)) {\n throw new Error(`Forgejo ${field} must use ${protocols.join(\" or \")}`);\n }\n if (parsed.username || parsed.password) {\n throw new Error(`Forgejo ${field} must not contain credentials`);\n }\n return parsed.toString().replace(/\\/$/, \"\");\n}\nfunction resolveForgejoConnectionSettings(settings) {\n const forge = settings?.forge;\n const username = typeof forge?.username === \"string\" ? forge.username.trim() : \"\";\n if (!username) throw new Error(\"Forgejo username is required\");\n const apiBase = normalizedUrl(forge?.apiBase, \"apiBase\", [\"http:\", \"https:\"]);\n if (!new URL(apiBase).pathname.endsWith(\"/api/v1\")) {\n throw new Error(\"Forgejo apiBase must end with /api/v1\");\n }\n return {\n provider: \"forgejo\",\n apiBase,\n cloneUrl: normalizedUrl(forge?.cloneUrl, \"cloneUrl\", [\"http:\", \"https:\"]),\n username\n };\n}\nfunction resolveForgeSettings(settings) {\n const forge = settings?.forge;\n if (!forge || forge.provider === void 0 || forge.provider === \"github\") {\n return { provider: \"github\" };\n }\n if (forge.provider !== \"forgejo\") {\n throw new Error(\"Unsupported repository provider\");\n }\n return resolveForgejoConnectionSettings(settings);\n}\n\n// src/types/deployment-service-types.ts\nvar DEPLOYMENT_TARGET_PROVIDERS = [\n \"pm2-local\",\n \"github-actions\",\n \"vercel\",\n \"cloud-run\",\n \"gke\"\n];\nvar DEPLOYMENT_TARGET_ENVIRONMENTS = [\"dev\", \"prod\", \"staging\", \"custom\"];\n\n// src/generated/mcp-tool-registry.generated.ts\nvar MCP_TOOL_REGISTRY = [\n {\n name: \"upload_attachment\",\n description: \"Upload a file (doc, notes, data, diagram, screenshot \\u2014 any file type, up to 25MB) as a task attachment AND post it to the task chat in one step \\u2014 no follow-up post_to_chat call needed. This is how you deliver a file the user should keep: it attaches to the card. Never publish deliverables as an external Claude artifact. Pass `tags` when the file is a good example of a glossary tag in some state.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/attachment-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"approve_manual_test\",\n description: \"Sign off on (approve) a manual test step on behalf of your authenticated user. Identify the test by its title (case-insensitive). Use after you have verified the step passes.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"edit_manual_test\",\n description: \"Rename an existing manual test step. Identify the test by its current title (case-insensitive); pass the new title to replace it. Use to correct or refine a recorded manual verification step.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"list_manual_tests\",\n description: \"List the manual test checklist items for the current task. Use to see what manual verification steps have already been recorded.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"query_manual_tests\",\n description: \"Query manual tests across many tasks in this project, grouped by task. Filter by card status (ReviewDev, ReviewLive, Complete, ...) and/or test status (open | approved | rejected). Use to answer 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"reject_manual_test\",\n description: \"Flag an issue with (reject) a manual test step on behalf of your authenticated user, recording the reason. Identify the test by its title (case-insensitive). Use when the step fails verification.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"remove_manual_test\",\n description: \"Remove an existing manual test step from the task checklist. Identify the test by its title (case-insensitive). Use to delete a stale or incorrect manual verification step.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"set_manual_tests\",\n description: \"Add manual test steps to the task checklist. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing this PR.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/checklist-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"approve_code_review\",\n description: \"Approve the code review and exit. Use when the diff passes all review criteria. Requires a summary and a risk level \\u2014 for changes, use request_code_changes with a structured issues[] list.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/code-review-tools.ts\",\n category: \"codeReview\",\n modes: \"review\"\n },\n {\n name: \"request_code_changes\",\n description: \"Request changes during code review and exit. Use when substantive issues must be fixed before merge. Each issue: { file, line?, severity: critical|major|minor, description }.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/code-review-tools.ts\",\n category: \"codeReview\",\n modes: \"review\"\n },\n {\n name: \"get_dependencies\",\n description: \"Get this task's dependencies and their met/unmet status (met = merged to dev). Use to confirm blockers merged, or see why a task cannot start. For task state use get_task.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/dependency-suggestion-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"get_suggestions\",\n description: \"List project suggestions sorted by vote score. Filter by status or cap with limit (default 20). Suggestions are project-level ideas, not tasks \\u2014 use get_task for tasks.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/dependency-suggestion-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"update_task_properties\",\n description: \"Set one or more task properties in a single call. Valid keys: title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk. All are optional \\u2014 include only the ones you want to update (at least one). Unknown keys are rejected.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/discovery-tools.ts\",\n category: \"discovery\",\n modes: \"discovery, auto\"\n },\n {\n name: \"drive_create_file\",\n description: \"Create a new file in the project's connected Google Drive folder. Use drive_update_file to change an existing file instead.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/drive-tools.ts\",\n category: \"global\",\n modes: \"all modes, only when the project has a Google Drive folder connected\"\n },\n {\n name: \"drive_create_folder\",\n description: \"Create a folder inside the project's connected Google Drive folder.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/drive-tools.ts\",\n category: \"global\",\n modes: \"all modes, only when the project has a Google Drive folder connected\"\n },\n {\n name: \"drive_delete_file\",\n description: \"Move a file in the project's connected Google Drive folder to the Drive trash. The file is recoverable from the trash; it is never permanently deleted.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/drive-tools.ts\",\n category: \"global\",\n modes: \"all modes, only when the project has a Google Drive folder connected\"\n },\n {\n name: \"drive_list_files\",\n description: \"List files and folders in the project's connected Google Drive folder. Omit folderId to list the project's root folder. Returns id, name, mimeType, size, and modified time for each entry.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/drive-tools.ts\",\n category: \"global\",\n modes: \"all modes, only when the project has a Google Drive folder connected\"\n },\n {\n name: \"drive_read_file\",\n description: \"Read a file's text content from the project's connected Google Drive folder. Google Docs, Sheets, and Slides are exported to text automatically. Content over 100 KB is truncated.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/drive-tools.ts\",\n category: \"global\",\n modes: \"all modes, only when the project has a Google Drive folder connected\"\n },\n {\n name: \"drive_update_file\",\n description: \"Replace the content of an existing file in the project's connected Google Drive folder. This overwrites the whole file. Google-native documents cannot be overwritten.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/drive-tools.ts\",\n category: \"global\",\n modes: \"all modes, only when the project has a Google Drive folder connected\"\n },\n {\n name: \"add_dependency\",\n description: \"Add a blocking dependency \\u2014 this task cannot start until the named task is merged to dev. For post-task follow-ups use create_follow_up_task instead.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"create_follow_up_task\",\n description: \"Create a follow-up task that depends on the current task. The new card is a SIBLING of this one (same parent) and is blocked until this task merges \\u2014 it is NOT a child of this card. To break this card into child cards that build as a pack, use create_subtask. For blockers use add_dependency.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"create_pull_request\",\n description: \"Create a GitHub PR for this task. Auto-stages, commits (commitMessage or title default), pushes to origin, then opens the PR. Always use this instead of gh CLI or raw git.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"create_suggestion\",\n description: \"Suggest a feature, improvement, rule, or idea for the project. Duplicates are deduped and your upvote is recorded. For actionable work on this task open a follow-up task.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"force_update_task_status\",\n description: \"EMERGENCY ONLY: force-override a task's Kanban status. Use when an automatic transition failed and the task is wedged. Normal flow transitions status automatically.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all modes (emergency override; always exposed)\"\n },\n {\n name: \"post_to_chat\",\n description: \"Post a message to the task chat for the team to see. Your turn output is NOT shown in chat, so this is the only way the team sees your status, summaries, and questions. Omit task_id to post to the current task's chat; pass a child's ID to message its chat.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"refresh_github_token\",\n description: \"Mint a fresh GitHub token for this pod when git or gh fails with a 401 / 'Bad credentials'. The pod's token expires about every hour. This updates the git credential store and the gh CLI config, and returns the shell command that puts a current token in your environment.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"remove_dependency\",\n description: \"Remove a previously added dependency from this task. When to use: the dependency was added in error or is no longer relevant. Returns: confirmation string.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"vote_suggestion\",\n description: \"Vote +1 or -1 on a project suggestion. Use to express support or disagreement with a specific suggestion returned by get_suggestions.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/mutation-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (common tools)\"\n },\n {\n name: \"approve_and_merge_pr\",\n description: \"Approve and merge a child task's PR. Preconditions: child in ReviewPR. Returns { merged }: true = merged (status\\u2192ReviewDev); false = automerge queued, wait for ReviewDev. Requires project Admin, or a sub-project merge grant covering every changed file; release PRs require Admin.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"packRunner\",\n modes: \"parent task only (review, auto, discovery, help, building)\"\n },\n {\n name: \"create_subtask\",\n description: \"Create a subtask (a child card) under the CURRENT card. This is how a card becomes a pack: the first child turns this card into the pack parent, and the children build as one unit. Use when breaking the current card into smaller pieces during planning. For a sibling card that lands after this one merges, use create_follow_up_task.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"pm\",\n modes: \"task mode: discovery, auto, building, chat. PM/agent modes: review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require a pack runner or a parent task.\"\n },\n {\n name: \"delete_subtask\",\n description: \"Delete a subtask by id. When to use: a subtask was created in error or is no longer needed. Returns: confirmation string.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"pm\",\n modes: \"task mode: discovery, auto, building, chat. PM/agent modes: review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require a pack runner or a parent task.\"\n },\n {\n name: \"handoff_to_agent\",\n description: \"Hand this task off to an implementer agent for the build phase \\u2014 mid-conversation, same session, no restart. Call this once the plan is compiled and saved (update_task_plan). The server swaps this task to the difficulty-sized implementer agent (which may run at a different model level), announces the handoff in the activity log + chat, and switches you into build mode to start implementing. Size the work with the storyPoints arg (or set it first via update_task_properties). Returns the implementer's name + model.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"pm\",\n modes: \"task mode: discovery, auto, building, chat. PM/agent modes: review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require a pack runner or a parent task.\"\n },\n {\n name: \"list_subtasks\",\n description: \"List all subtasks under the current parent task. Default compact view returns per child: status, agent, story points, PR number/state, dependencies, and holdsBuildSlot \\u2014 plus packSlots (in-flight environments vs the PACK_CHILD_LIMIT cap, and which children hold the slots). Use to coordinate child work; pass verbose:true only when you need full description/plan text (large). For non-child tasks use get_task.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"pm\",\n modes: \"task mode: discovery, auto, building, chat. PM/agent modes: review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require a pack runner or a parent task.\"\n },\n {\n name: \"start_child_cloud_build\",\n description: \"Start a cloud build (codespace) for a child task. Preconditions: child status is `Open`, story points set, and an agent assigned \\u2014 satisfy all three with update_subtask (status/agentIdOrName/storyPointValue) first; none happen automatically. A PACK_CHILD_LIMIT error is backpressure, not failure: check list_subtasks packSlots for which children hold the in-flight slots, merge/stop one, then retry. On a feature-branch pack, dev is merged into the pack branch first so the child branches from a fresh base; a conflict is reported in the result and never blocks the launch.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"packRunner\",\n modes: \"parent task only (review, auto, discovery, help, building)\"\n },\n {\n name: \"stop_child_build\",\n description: \"Send a graceful stop signal to a running child build's agent. Not a force-kill \\u2014 the agent may take a moment to wind down. Stopping a child eventually frees its PACK_CHILD_LIMIT build slot (see list_subtasks packSlots).\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"packRunner\",\n modes: \"parent task only (review, auto, discovery, help, building)\"\n },\n {\n name: \"update_subtask\",\n description: \"Update an existing subtask's fields (title, description, plan, ordinal, storyPointValue, dependsOn) \\u2014 and the sanctioned path to make a child buildable: promote it to status Open, assign its agent (agentIdOrName), and set story points. Setting story points does NOT auto-promote; set status explicitly. For the current task use update_task_plan.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"pm\",\n modes: \"task mode: discovery, auto, building, chat. PM/agent modes: review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require a pack runner or a parent task.\"\n },\n {\n name: \"update_task_plan\",\n description: \"Save the plan and/or description to the current task. In auto/building mode, save the plan BEFORE writing code and keep it current as the approach evolves \\u2014 post it, then build; never pause the build waiting for approval. For children use update_subtask; for title/tags/PR use update_task_properties.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/pm-tools.ts\",\n category: \"pm\",\n modes: \"task mode: discovery, auto, building, chat. PM/agent modes: review, auto, discovery, help; building (parent task only).\"\n },\n {\n name: \"create_suggestion\",\n description: \"File a project suggestion (idea/improvement for maintainers to review). Duplicates are AI-deduped into an existing suggestion with an upvote. Returns the suggestion id.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"create_tag\",\n description: \"Create a project tag. Include a crisp description (\\u2264255 chars \\u2014 the summary) and contextPaths (rule/doc/file/folder links agents auto-load when working on matching tasks); put the full spec in overview. Set parentTagIds to place the tag in the hierarchy right away. Every contextPath is checked against the repo checkout \\u2014 a path that does not exist, or whose type does not match what is on disk, rejects the whole call. Fails if the name already exists.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"get_project_task\",\n description: \"Fetch any task in the project by id or slug: title, description, plan, status, and metadata. The audit evidence trail starts here.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"get_project_task_logs\",\n description: \"Read any project task's persisted agent event stream (message / tool_use / turn_end / error / completed). Turn boundaries are turn_end events. Entries are truncated to ~2KB each; max 500 per call.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"get_tag\",\n description: \"Read one tag's full glossary entry: description, the full markdown overview (the term's spec \\u2014 philosophy, mechanics, invariants), linked files/rules (each with its verified-link status \\u2014 ok/stale/unchecked \\u2014 from the periodic repo check), parent/child tags, active-card count, attachment count (files labelled as examples of the term), and recent revisions with their reasons. Call this whenever a chat message, plan, or tag list points at a term you need the full context for. A response with `overviewPath` set means the overview is sourced from that repo file \\u2014 prefer Reading the path from your checkout (branch-correct); the served overview is materialized from the project's dev branch (the PR base; default branch when the repo has no dev branch) (`overviewSource.state`: ok/pending/stale).\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"all card sessions + headless task-less sessions\"\n },\n {\n name: \"list_tags\",\n description: \"List the project glossary: every tag's id, name, color, description, parent/child tag ids, its contextPaths (the rule/doc/file/folder links it wires into agent context \\u2014 `[]` means none), whether it carries a full overview (fetch that with get_tag), and its attachmentCount (files labelled as examples of the term). The context links ship inline, so you only need get_tag for a term's full overview. Use the ids with get_tag / update_tag.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"all card sessions + headless task-less sessions\"\n },\n {\n name: \"post_to_project_chat\",\n description: \"Post a markdown message to the PROJECT chat \\u2014 use once at the end of an audit for the summary the team reads.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"read_project_task_chat\",\n description: \"Read any project task's chat messages (newest last). role 'user' rows are HUMAN turns; 'assistant'/'system' rows are agent posts and activity-log entries.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"report_task_audit_result\",\n description: \"Persist one audited task's grades (call once per task after grading it). Pass error instead to mark the audit failed when the evidence is unusable.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"headless task-less sessions (tag/task audits on ad-hoc pods)\"\n },\n {\n name: \"search_tasks\",\n description: `Search this project's cards by tag, text, status, type, and/or assignment. Tags are the project's glossary, so tagNames is the fastest way to find prior work in the area you are touching \\u2014 e.g. every ReviewPR card tagged \"mcp\". Searches the whole project, not just the current card. Defaults to type=task \\u2014 pass typeFilters for incidents/suggestions. Every result lists the tags it carries, so you can see why it matched. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \\u2014 plan omitted, description truncated; use get_task for full details.`,\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"all card sessions + headless task-less sessions\"\n },\n {\n name: \"update_tag\",\n description: \"Update a tag's name, color, description (\\u2264255), markdown overview, parent tags, or contextPaths. contextPaths and parentTagIds are FULL replacements \\u2014 include what you want to keep. ALWAYS pass a short reason; it lands in the tag's revision history (with your current card auto-stamped) so the team sees why the glossary changed. Every contextPath is checked against the repo checkout \\u2014 a path that does not exist, or whose type does not match what is on disk, rejects the whole call and nothing is written.\",\n readOnly: false,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/project-tools.ts\",\n category: \"projectRunner\",\n modes: \"all card sessions + headless task-less sessions\"\n },\n {\n name: \"get_attachment\",\n description: \"Fetch one task file's content plus metadata by file ID. Call list_task_files first to discover IDs and check sizes \\u2014 large binaries may be truncated by the service's size limit.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/task-context-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (read-only common tools)\"\n },\n {\n name: \"get_current_plan\",\n description: \"Re-read the current task's plan. Use when the user updated the plan or asked you to re-read it \\u2014 otherwise the plan is already in initial context. For task metadata use get_task.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/task-context-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (read-only common tools)\"\n },\n {\n name: \"get_execution_logs\",\n description: \"Read CLI execution logs \\u2014 agent reasoning, tool calls, and setup/dev-server output. Filter via source='agent' or 'application'. For human chat use read_task_chat.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/task-context-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (read-only common tools)\"\n },\n {\n name: \"get_task\",\n description: \"Look up any task by slug or ID. Returns JSON with id, slug, title, description, plan, status, branch, githubPRNumber, githubPRUrl, storyPoints. For children use list_subtasks.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/task-context-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (read-only common tools)\"\n },\n {\n name: \"list_task_files\",\n description: \"List all files attached to this task with metadata. Use before fetching a specific file to see what is available and how large each is. For file contents use get_attachment.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/task-context-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (read-only common tools)\"\n },\n {\n name: \"read_task_chat\",\n description: \"Read recent human/user chat messages for a task. Omit task_id for the current task; pass a child ID for a child's chat. For agent logs use get_execution_logs.\",\n readOnly: true,\n package: \"conveyor-agent\",\n sourceFile: \"packages/conveyor-agent/src/tools/task-context-tools.ts\",\n category: \"global\",\n modes: \"all PM/agent modes (read-only common tools)\"\n },\n {\n name: \"get_attachment\",\n description: \"Fetch one task file's content plus metadata by file ID (accepts task id or slug). Pass projectId to target a specific project; otherwise the configured default project is used. Images are returned as viewable image blocks. Large text files (logs, JSON) are returned in pages \\u2014 use `offset`/`maxBytes` to read more, or fetch `downloadUrl` for the whole file. Call list_task_files first to discover IDs and sizes.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/attachments.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_task_files\",\n description: \"List all files attached to a task with metadata (no contents \\u2014 fast and small). Pass projectId to target a specific project; otherwise the configured default project is used. Use before fetching a specific file to see what is available and how large each is. For file contents use get_attachment.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/attachments.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"set_file_tags\",\n description: \"Replace the glossary tags on a file that is already uploaded \\u2014 the labelling upload_attachment does at upload time, applied to an existing file. Use it to add older attachments to a tag's Attachments gallery, which is what makes a file a visible example of that tagged entity. `tags` is the FULL replacement set: the names you pass become the file's tags and any others are removed, so pass [] to clear every tag. Names are matched case-insensitively within the project; a name that matches no tag is reported back and never fails the tags that did match. Max 5. Call list_task_files for file IDs and list_tags for tag names. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/attachments.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"upload_attachment\",\n description: \"Upload a local file as a task attachment (any file type, up to 25MB). Pass projectId to target a specific project; otherwise the configured default project is used. The file appears under the task's Files. Pass `comment` to also post it to the task chat in the same step, and `tags` when the file is a good example of a glossary tag in some state.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/attachments.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"add_to_release\",\n description: \"Add Review (Dev) cards to the project's pending release \\u2014 the same flow as the 'Add to Release' button in the web UI. Pass projectId to target a specific project; otherwise the configured default project is used. Cards must be in Review (Dev) and not already part of another release; the release branch is updated with the latest dev changes. Fails if no release is pending (use create_release instead).\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"create_release\",\n description: \"Create a release for the project \\u2014 the same flow as the Release button in the web UI. Pass projectId to target a specific project; otherwise the configured default project is used. Creates a release task with a release/YYYY.MM.N branch and a PR from the dev branch to the default branch. Omit taskIds to release ALL cards currently in Review (Dev); pass a subset to cherry-pick \\u2014 a cloud build agent then cherry-picks those changes and resolves conflicts. Fails if a release is already in progress or no cards are in Review (Dev).\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"delete_task_environment\",\n description: \"Delete a task environment, including durable Claudespace state. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_build_status\",\n description: \"Check codespace and agent status for a task. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"resume_task\",\n description: \"Resume a sleeping task Claudespace. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"sleep_task\",\n description: \"Sleep a task Claudespace, stopping compute while preserving durable state. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"start_task\",\n description: \"Start a cloud build (codespace) for a task. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"stop_task\",\n description: \"Compatibility alias for the legacy stop path. stop_task now performs the same durable sleep behavior as sleep_task, preserving task Claudespace state while stopping compute. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/builds.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"approve_manual_test\",\n description: \"Sign off on (approve) a manual test step on a task on behalf of your authenticated user. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use after you have verified the step passes.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"edit_manual_test\",\n description: \"Rename an existing manual test step on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its current title (case-insensitive) and pass the new title to replace it.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_manual_tests\",\n description: \"List the manual test checklist items for a task. Pass projectId to target a specific project; otherwise the configured default project is used. Use to see what manual verification steps have already been recorded.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"query_manual_tests\",\n description: \"Query manual tests across many tasks in a project, grouped by task. Filter by card status (e.g. ReviewDev, ReviewLive, Complete) and/or test status (open | approved | rejected). Use to answer questions like 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests in ReviewDev/ReviewLive with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"reject_manual_test\",\n description: \"Flag an issue with (reject) a manual test step on a task on behalf of your authenticated user, recording the reason. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use when the step fails verification.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"remove_manual_test\",\n description: \"Remove an existing manual test step from a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive).\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"set_manual_tests\",\n description: \"Add manual test steps to a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing the task's PR.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/checklists.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_connection_context\",\n description: \"Resolve WHO this connection is and WHAT project/board it points at \\u2014 call this FIRST, before inferring anything from names. Returns the effective account, project, and board (sub-project) each with BOTH its immutable ID and its human-readable name/slug, the granted capabilities (read/create/update/chat/files/build), management URLs, and a one-line summary. Removes the ambiguity between a project's canonical name and a board label. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/connection.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_accessible_subprojects\",\n description: \"List the boards (sub-projects) under the connected project \\u2014 each with its ID, name, slug, board URL, owned root path, and the role/capabilities this token has on it. Use this to discover which board to create or list cards on (pass a returned id as subProjectId, or set CONVEYOR_SUBPROJECT_ID) instead of asking the human for one. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/connection.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"verify_connection\",\n description: \"Prove the connection is correct AND that you can actually write to the intended board \\u2014 not just that auth works. Runs layered checks (auth \\u2192 account \\u2192 project \\u2192 target board \\u2192 capabilities \\u2192 read) and returns a plain pass/fail with, on failure, the exact failing layer and ONE next action. Use this instead of get_project_summary to confirm setup: a summary that returns data proves auth, not scope. Pass intendedActions to verify specific capabilities (defaults to read+create+update). Pass projectId to target a specific project; otherwise the configured default project is used. The board scope comes from CONVEYOR_SUBPROJECT_ID.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/connection.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"add_dependency\",\n description: \"Add a blocking dependency \\u2014 this task cannot start until the named task is merged to dev. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/dependencies.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_dependencies\",\n description: \"Get a task's dependencies and their met/unmet status (met = merged to dev). Pass projectId to target a specific project; otherwise the configured default project is used. Use to confirm blockers merged, or see why a task cannot start. For task state use get_task.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/dependencies.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"remove_dependency\",\n description: \"Remove a previously added dependency from a task. Pass projectId to target a specific project; otherwise the configured default project is used. The task is no longer blocked by the named task. Returns: confirmation string.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/dependencies.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"query_gcp_logs\",\n description: \"Query Google Cloud Logging for a project's linked GCP environments \\u2014 use this to investigate production or dev issues directly ('something broke on prod'). Envs: 'prod' and 'dev' are the project's Cloud Run apps + Cloud SQL databases (scoped by default to the resources linked in project settings); 'claudespace' is the project's GKE agent-pod namespace. Start broad (severity=ERROR, sinceMinutes=60), then narrow with services/search. Returns compact lines: '<time> <SEVERITY> [<source>] <message> | key=value \\u2026' (the key=value tail is the entry's structured payload \\u2014 error details, service/method, actor and entity ids). When the response ends with a pageToken line, pass that token back as pageToken for the next page. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/logs.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"query_grafana_logs\",\n description: \"Query the project's connected Grafana (Loki) logs \\u2014 the application logs shipped to Grafana Cloud/Loki, complementing query_gcp_logs (GCP infrastructure logs). Start with structured filters (env, level=error, sinceMinutes=60, services), then narrow with search; pass raw LogQL via logql only when structured filters can't express the query (it REPLACES them). The response header echoes the composed LogQL \\u2014 iterate on it. Returns compact lines: '<time> <SEVERITY> [<service>] <message>'.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/logs.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_connect_urls\",\n description: \"Get browser-only setup URLs to hand to the user: the Google Cloud OAuth connect link (gcpConnect) plus Settings deep links (gcpSettings, memberSettings, projectSettings, setupWizard). Use these for setup steps an agent cannot perform (OAuth grants, secret entry). Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project-config.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_tag\",\n description: \"Read one tag's full glossary entry \\u2014 description, markdown overview, context links (each with its verified-link status: ok/stale/unchecked plus last-checked provenance), parent/child tags, active-card count, attachment count (files labelled as examples of the term \\u2014 read the tiles with list_tag_attachments), and recent revisions with provenance. A response with `overviewPath` set means the overview is sourced from that repo file at the project's dev branch (the PR base; default branch when the repo has no dev branch) (`overviewSource.state`: ok/pending/stale) \\u2014 clients with a checkout can read the path directly for the branch-correct copy. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project-config.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_tag_attachments\",\n description: \"List the files labelled as examples of one tag \\u2014 the tag page's Attachments gallery, newest label first. Each tile carries the file's name, mime type, size, a downloadUrl, the card it came from, and the tag's other labels on that file. Only uploaded files appear. The page returns `hasMore` instead of a total: pass offset to read the next page. Tag names come from list_tags, which reports each tag's attachmentCount. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project-config.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"manage_priorities\",\n description: \"List, create, update, or delete project priorities. create requires value (1-100), name, and color; update/delete require the priority id. create/update require a Moderate role; delete requires Admin.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project-config.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"update_project_settings\",\n description: \"Update project configuration: name, description, default agent assignments, or a deep-merged patch of the project settings JSON (JSON Merge Patch: nested objects merge recursively, null deletes a key, arrays replace \\u2014 a partial patch never wipes sibling keys). Requires a Moderate project role. Does NOT touch repositories or branches \\u2014 those are configured in the Conveyor UI.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project-config.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_onboarding_status\",\n description: \"Get the project's onboarding/setup readiness checklist so you can drive setup to green without the user opening Project Settings. Returns { ok, checks[] } where each check has a key (githubApp, githubOauthScopes, claudeToken, devcontainer, devBranch, anthropicKey, compute, codespaceQuota), a status (ok | warn | fail), a human-readable reason, and an optional fix hint. Call this first during onboarding, resolve every 'fail' (use gh/gcloud CLIs or point the user at the fix), then call again until ok is true. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_onboarding_step\",\n description: \"Drive project setup one contextual step at a time (the choose-your-own-adventure onboarding flow). Returns { done, ok, step, remaining, checks }: `step` is the SINGLE next thing to configure (fails before warnings) with a human `title`, the `reason`, agent-facing `guidance` on how to resolve it, `autoFixable` (true = you can fix it via gh/git/tools, false = a browser-only step the user must do), an optional `fix` hint, and `connectUrls` (URLs to hand the user for browser-only steps). `remaining` lists the other unresolved checks. Prefer this over get_onboarding_status during setup: call it, resolve the returned step (do it yourself if autoFixable, otherwise give the user the connectUrl and wait), then call again \\u2014 repeat until `done` is true. The repository and branches are already configured; never change them. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_project_summary\",\n description: \"Get overall project status: task counts by status, active builds, repo info. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_project_members\",\n description: \"List project members with user ID, name, email, and access level \\u2014 use to resolve a person's name or email to a user ID for task assignment or review. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_projects\",\n description: \"List Conveyor projects available to this MCP token's user. Use a returned project id as projectId on other tools when no default project is configured or when targeting a different project.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/project.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"create_pull_request\",\n description: \"Open a GitHub pull request for a task's existing branch (the branch must already be pushed to origin). Pass projectId to target a specific project; otherwise the configured default project is used. Moves the task to ReviewPR. Returns the PR number and URL.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/pull-request.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"create_subtask\",\n description: \"Create a subtask under a parent task. Pass projectId to target a specific project; otherwise the configured default project is used. Subtasks break a larger task into independently buildable pieces. For children that instead ship on the parent's own branch/PR (e.g. per-theme tracking cards for one bundled PR), set followParentStatus so their status rides the parent's automatically.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/subtasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"delete_subtask\",\n description: \"Delete a subtask by ID. Pass projectId to target a specific project; otherwise the configured default project is used. This is permanent \\u2014 use update_subtask to set status to Cancelled if you only want to close it.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/subtasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_subtasks\",\n description: \"List all subtasks of a parent task with their status and ordering. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/subtasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"update_subtask\",\n description: \"Update a subtask's fields: title, description, plan, status, ordering, story points, or dependencies. Pass projectId to target a specific project; otherwise the configured default project is used. Moving a subtask beyond Planning auto-fills missing story points and agent assignment \\u2014 don't spend turns on them.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/subtasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"create_suggestion\",\n description: \"Suggest a feature, improvement, rule, or idea for the project. Pass projectId to target a specific project; otherwise the configured default project is used. Duplicates are deduped and your upvote is recorded.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/suggestions.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"add_reviewer\",\n description: \"Add a project member as a reviewer on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Idempotent \\u2014 adding an existing reviewer is a no-op.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"approve_and_merge_pr\",\n description: \"Approve a child task's pull request and QUEUE it for merge \\u2014 the merge lands asynchronously (~30s sweep) once the CI and code-review gates pass; the response says whether it merged or was queued, so verify PR state before depending on it. Pass projectId to target a specific project; otherwise the configured default project is used. The child task must be in ReviewPR status with a PR. Requires project Admin, or a sub-project merge grant covering every changed file; release PRs require Admin.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"approve_task\",\n description: \"Move a task forward in the review flow (ReviewPR -> ReviewDev, or -> Complete). Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"create_task\",\n description: \"Create a new task with title, description, and optional plan. Pass projectId to target a specific project; otherwise the configured default project is used. Icon, story points, and agent assignment are auto-filled when a task is created in (or later moved to) a status beyond Planning \\u2014 don't spend turns on them.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_card_by_slug\",\n description: \"Get full card details by the slug from a card URL (/cards/<slug>) instead of a task ID. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_task\",\n description: \"Get full task details including plan, chat history, PR info, subtasks, and build status. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"get_task_sessions\",\n description: \"Read compute-session state for a task: legacy CodespaceSession rows plus v3 workspaces, including purpose=review review workspaces. Shows pod identity, liveness, lifecycle, and code-review claim state. Use to diagnose stalled/dead agents or code-review runs. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"list_tags\",\n description: \"List all project tags with names, IDs, colors, descriptions, hierarchy (parent/child ids), contextPaths (the rule/doc/file/folder links each tag wires into agent context \\u2014 `[]` means none), a hasOverview flag, and an attachmentCount (files labelled as examples of the term \\u2014 read the tiles with list_tag_attachments). Context links ship inline; call get_tag only for a term's full overview. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"move_card\",\n description: \"Move an eligible Planning or Open task, incident, or suggestion card to another project. Cards with identification or automation in progress, active compute, pull requests, deployments, releases, reviews, or delivered reporter email cannot move. Project-specific metadata is cleared instead of mapped by name. Pass projectId for the source project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"post_to_chat\",\n description: \"Post a message to a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"read_task_chat\",\n description: \"Read messages from a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used. For agent execution logs use get_task_logs.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"remove_reviewer\",\n description: \"Remove a reviewer from a task. Pass projectId to target a specific project; otherwise the configured default project is used. Idempotent \\u2014 removing a non-reviewer is a no-op.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"request_changes\",\n description: \"Post feedback and send task back to InProgress for more work. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"search_tasks\",\n description: \"Search cards by tag name, text query, status, type, and/or assignment. Defaults to type=task \\u2014 pass typeFilters to include incidents/suggestions. Pass projectId to target a specific project; otherwise the configured default project is used. Use tag names like 'agent-runner', not IDs. Every result lists the tags it carries, so you can see why it matched. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \\u2014 plan omitted, description truncated; use get_task for full details.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"update_task\",\n description: \"Update task fields: title, description, plan, status, risk, story points, assignment, or tags. Set status to claim a card (InProgress), triage it (Open), or cancel it (Cancelled); for review approvals prefer approve_task / request_changes, which guard against stale-state races. Tags are additive/subtractive \\u2014 pass addTags/removeTags with tag names (not a replace-set). Pass projectId to target a specific project; otherwise the configured default project is used. Moving a task beyond Planning auto-fills any missing icon, story points, and agent assignment \\u2014 don't spend turns on them; pass storyPointValue only to correct the sizing yourself. For subtasks use update_subtask.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/tasks.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"workspace_attach_info\",\n description: \"Return SSH/SFTP attach metadata for a running task Claudespace, plus hosted preview URLs and configured preview ports. Optionally installs an OpenSSH public key for this attach session.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/workspace.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"workspace_preview_urls\",\n description: \"Return the hosted preview URLs and preview ports for a running task Claudespace. This mirrors the web UI preview link metadata.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/workspace.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"workspace_start_tunnel\",\n description: \"Start a local loopback tunnel through the MCP server to a running task Claudespace port. Use port 2222 for SSH/SFTP, or one of previewPorts for app access.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/workspace.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n },\n {\n name: \"workspace_stop_tunnel\",\n description: \"Stop a local workspace tunnel previously opened by workspace_start_tunnel.\",\n readOnly: false,\n package: \"conveyor-mcp\",\n sourceFile: \"packages/conveyor-mcp/src/tools/workspace.ts\",\n category: \"mcp\",\n modes: \"conveyor-mcp (MCP server)\"\n }\n];\n\n// src/types/agent-tool-registry.ts\nfunction getToolsByCategory(category) {\n return MCP_TOOL_REGISTRY.filter((tool) => tool.category === category);\n}\n\n// src/constants/timezone.ts\nvar PROJECT_TIMEZONE = \"America/Los_Angeles\";\n\n// src/constants/agent-session-runner.ts\nvar CODESPACE_SESSION_ACTIVE_RUNNER_STATUSES = [\n \"connected\",\n \"idle\",\n \"busy\",\n \"running\",\n \"fetching_context\",\n \"waiting_for_input\",\n \"setup\",\n \"connecting\"\n];\nvar TERMINAL_TASK_STATUSES = [\"Complete\", \"Cancelled\"];\nvar AGENT_STATUS_REASON_USER_QUESTION = \"user_question\";\n\n// src/constants/agent-chat-history.ts\nvar TASK_CHAT_HISTORY_LIMIT = 20;\nvar PM_CHAT_HISTORY_LIMIT = 40;\nvar AGENT_CHAT_HISTORY_FETCH_LIMIT = Math.max(TASK_CHAT_HISTORY_LIMIT, PM_CHAT_HISTORY_LIMIT) + 10;\n\n// src/constants/providers.ts\nvar MODEL_PROVIDERS = [\"anthropic\", \"zen\"];\nvar DEFAULT_MODEL_PROVIDER = \"anthropic\";\nfunction isModelProvider(value) {\n return MODEL_PROVIDERS.includes(value);\n}\nfunction parseModelId(id) {\n const slash = id.indexOf(\"/\");\n if (slash > 0) {\n const prefix = id.slice(0, slash);\n if (isModelProvider(prefix)) {\n return { provider: prefix, model: id.slice(slash + 1) };\n }\n }\n return { provider: DEFAULT_MODEL_PROVIDER, model: id };\n}\nfunction formatModelId(provider, model) {\n return `${provider}/${model}`;\n}\n\n// src/constants/model-catalog.ts\nvar MODEL_WIRE_FORMATS = [\n \"anthropic-messages\",\n \"openai-chat\",\n \"openai-responses\",\n \"google-generate-content\"\n];\nvar SUPPORTED_WIRE_FORMATS = [\"anthropic-messages\", \"openai-chat\"];\nfunction isSupportedWireFormat(format) {\n return SUPPORTED_WIRE_FORMATS.includes(format);\n}\nfunction anthropicEntry(model, label, inputPerMillion, outputPerMillion, experimental = false) {\n return {\n provider: \"anthropic\",\n model,\n id: formatModelId(\"anthropic\", model),\n label,\n format: \"anthropic-messages\",\n inputPrice: inputPerMillion / 1e6,\n outputPrice: outputPerMillion / 1e6,\n supportsTools: true,\n ...experimental ? { experimental: true } : {}\n };\n}\nvar ANTHROPIC_CATALOG = [\n anthropicEntry(DEFAULT_OPUS_MODEL, \"Opus 5 Latest\", 5, 25),\n anthropicEntry(PREVIOUS_OPUS_MODEL, \"Opus 4.8\", 5, 25),\n anthropicEntry(DEFAULT_SONNET_MODEL, \"Sonnet 5 Latest\", 3, 15),\n anthropicEntry(PREVIOUS_SONNET_MODEL, \"Sonnet 4.6\", 3, 15),\n anthropicEntry(DEFAULT_HAIKU_MODEL, \"Haiku 4.5\", 1, 5),\n anthropicEntry(FABLE_MODEL, \"Fable 5 (experimental)\", 10, 50, true)\n];\nfunction zenWireFormat(model) {\n const id = model.toLowerCase();\n if (id.startsWith(\"claude-\") || id.startsWith(\"qwen\")) return \"anthropic-messages\";\n if (id.startsWith(\"gpt-\") || id.startsWith(\"grok-\")) return \"openai-responses\";\n if (id.startsWith(\"gemini-\")) return \"google-generate-content\";\n return \"openai-chat\";\n}\nfunction getCatalogModelLabel(id, catalog) {\n const { provider, model } = parseModelId(id);\n const entry = catalog.find((e) => e.provider === provider && e.model === model);\n return entry?.label ?? id;\n}\n\n// src/constants/workspace-tunnel.ts\nvar WORKSPACE_TUNNEL_HEARTBEAT_MS = 3e4;\n\n// src/prompts/writing-style.ts\nvar HUMAN_PROSE_WRITING_STYLE = `## Writing style for humans\nWhen you write prose a person will read \\u2014 chat messages, plan updates, PR titles and bodies, PR review guides (the \\`publish_review_guide\\` overview and section explanations), review comments \\u2014 follow these rules (based on ASD-STE100 Simplified Technical English):\n- Use active voice. Say who does what (\"The API rejects the request\", not \"the request is rejected\").\n- Use simple tenses (\"we received\", not \"we have received\").\n- One instruction or fact per sentence. Keep sentences under ~20 words.\n- Pick one word for one thing and reuse it. Do not rotate synonyms (check/verify/confirm) for the same action.\n- Prefer the plain, common word (\"use\", not \"utilize\"; \"start\", not \"initiate\").\n- Do not stack more than 3 nouns in a row (\"task queue handler\" is the limit).\n- Use a numbered or bulleted list for 3+ steps or conditions instead of burying them in one sentence.\n- Define a technical term on first use when a non-engineer will read the message.\n- Never drop a condition, number, or scope qualifier to shorten a sentence. Precision beats brevity.\nThese rules do NOT apply to code, code comments, commit messages, or quoted output.`;\n\n// src/room-helpers.ts\nimport { serviceRoom as coreServiceRoom, userRoom as coreUserRoom } from \"@fitzzero/quickdraw-core\";\nfunction serviceRoom(service, entityId) {\n return coreServiceRoom(service, entityId);\n}\nfunction userRoom(userId) {\n return coreUserRoom(userId);\n}\n\n// src/admin-services.ts\nvar ADMIN_CREATE_SERVICES = /* @__PURE__ */ new Set([\n \"agentService\",\n \"chatService\",\n \"documentService\",\n \"loginAllowlistService\",\n \"messageService\",\n \"projectService\",\n \"taskService\",\n \"userService\"\n]);\nfunction adminSupportsCreate(serviceName) {\n return ADMIN_CREATE_SERVICES.has(serviceName);\n}\n\n// src/utils/access-levels.ts\nvar ACCESS_LEVEL_RANK = {\n Public: 0,\n Read: 1,\n Moderate: 2,\n Admin: 3\n};\nfunction accessLevelRank(level) {\n return level ? ACCESS_LEVEL_RANK[level] ?? 0 : 0;\n}\nfunction canGrantLevel(actorLevel, targetLevel) {\n return accessLevelRank(actorLevel) >= accessLevelRank(targetLevel);\n}\nfunction canModifyMember(actorLevel, memberLevel) {\n const actor = accessLevelRank(actorLevel);\n return actor >= ACCESS_LEVEL_RANK.Admin || actor > accessLevelRank(memberLevel);\n}\n\n// src/utils/personal-cluster-rbac.ts\nfunction poolNamespaceForProject(projectId) {\n return `claudespace-${projectId.slice(0, 16).toLowerCase().replace(/[^a-z0-9-]/g, \"-\")}`;\n}\nvar RBAC_SA_NAME_PLACEHOLDER = \"<service-account-name>\";\nvar RBAC_SA_NAMESPACE_PLACEHOLDER = \"<service-account-namespace>\";\nfunction buildPersonalClusterRbacManifest(namespaces) {\n const subject = [\n \"subjects:\",\n \"- kind: ServiceAccount\",\n ` name: ${RBAC_SA_NAME_PLACEHOLDER}`,\n ` namespace: ${RBAC_SA_NAMESPACE_PLACEHOLDER}`\n ].join(\"\\n\");\n const perNamespace = namespaces.map(\n (ns) => [\n `apiVersion: v1`,\n `kind: Namespace`,\n `metadata:`,\n ` name: ${ns}`,\n `---`,\n `apiVersion: rbac.authorization.k8s.io/v1`,\n `kind: Role`,\n `metadata:`,\n ` name: conveyor-workspace-manager`,\n ` namespace: ${ns}`,\n `rules:`,\n `- apiGroups: [\"\"]`,\n ` resources: [\"pods\"]`,\n ` verbs: [\"get\",\"list\",\"create\",\"delete\",\"patch\"]`,\n `- apiGroups: [\"\"]`,\n ` resources: [\"pods/log\",\"pods/proxy\",\"pods/exec\"]`,\n ` verbs: [\"get\",\"create\"]`,\n `- apiGroups: [\"\"]`,\n ` resources: [\"resourcequotas\"]`,\n ` verbs: [\"get\",\"create\",\"update\"]`,\n `- apiGroups: [\"\"]`,\n ` resources: [\"serviceaccounts\"]`,\n ` verbs: [\"get\",\"create\",\"patch\"]`,\n `---`,\n `apiVersion: rbac.authorization.k8s.io/v1`,\n `kind: RoleBinding`,\n `metadata:`,\n ` name: conveyor-workspace-manager`,\n ` namespace: ${ns}`,\n `roleRef:`,\n ` apiGroup: rbac.authorization.k8s.io`,\n ` kind: Role`,\n ` name: conveyor-workspace-manager`,\n subject\n ].join(\"\\n\")\n );\n const clusterScope = [\n `apiVersion: rbac.authorization.k8s.io/v1`,\n `kind: ClusterRole`,\n `metadata:`,\n ` name: conveyor-personal-clusters`,\n `rules:`,\n `- apiGroups: [\"\"]`,\n ` resources: [\"namespaces\"]`,\n ` resourceNames: [${namespaces.map((ns) => `\"${ns}\"`).join(\",\")}]`,\n ` verbs: [\"get\",\"delete\"]`,\n `- apiGroups: [\"\"]`,\n ` resources: [\"nodes\"]`,\n ` verbs: [\"get\",\"list\"]`,\n `- apiGroups: [\"scheduling.k8s.io\"]`,\n ` resources: [\"priorityclasses\"]`,\n ` resourceNames: [\"claudespace-agent\"]`,\n ` verbs: [\"get\"]`,\n `---`,\n `apiVersion: rbac.authorization.k8s.io/v1`,\n `kind: ClusterRoleBinding`,\n `metadata:`,\n ` name: conveyor-personal-clusters`,\n `roleRef:`,\n ` apiGroup: rbac.authorization.k8s.io`,\n ` kind: ClusterRole`,\n ` name: conveyor-personal-clusters`,\n subject\n ].join(\"\\n\");\n return [...perNamespace, clusterScope].join(\"\\n---\\n\") + \"\\n\";\n}\n\n// src/utils/local-arm64-bake.ts\nvar LOCAL_ARM64_REGISTRY = \"localhost\";\nfunction isLocalArm64Bake(settings) {\n const claudespace = settings?.claudespace;\n if (claudespace?.bakeRunner !== \"actions\") return false;\n if (!claudespace.bakeRunsOnArm64?.trim()) return false;\n return claudespace.bakeArm64Local === true;\n}\n\n// src/utils/xp.ts\nvar SP_XP_RATE = 10;\nvar REPORT_XP_RATE = 10;\nvar REVIEW_XP_RATE = 5;\nvar MAX_GATE_LEVEL = 99;\nfunction xpToReachLevel(level) {\n if (level <= 1) return 0;\n return 5 * level * (level - 1);\n}\nfunction computeTotalXp({ spValueSum, reportCount, reviewCount }) {\n const spXp = spValueSum * SP_XP_RATE;\n const reportXp = reportCount * REPORT_XP_RATE;\n const reviewXp = reviewCount * REVIEW_XP_RATE;\n return { spXp, reportXp, reviewXp, totalXp: spXp + reportXp + reviewXp };\n}\nfunction levelFromXp(totalXp) {\n const xp = Number.isFinite(totalXp) && totalXp > 0 ? Math.floor(totalXp) : 0;\n let level = Math.floor((5 + Math.sqrt(25 + 20 * xp)) / 10);\n while (xpToReachLevel(level + 1) <= xp) level++;\n while (level > 1 && xpToReachLevel(level) > xp) level--;\n level = Math.max(1, level);\n const floor = xpToReachLevel(level);\n const xpForNextLevel = xpToReachLevel(level + 1) - floor;\n const xpIntoLevel = xp - floor;\n const progress = xpForNextLevel === 0 ? 1 : Math.min(1, Math.max(0, xpIntoLevel / xpForNextLevel));\n return { level, xpIntoLevel, xpForNextLevel, progress };\n}\n\n// src/utils/merge-levels.ts\nvar MIN_CONTRIBUTOR_LEVEL = 1;\nfunction toContributorLevel(value) {\n if (value === null || value === void 0) return null;\n if (!Number.isFinite(value)) return null;\n const level = Math.floor(value);\n if (level <= MIN_CONTRIBUTOR_LEVEL) return null;\n return Math.min(MAX_GATE_LEVEL, level);\n}\nfunction requiredContributorLevel(storyPointMin, riskMin) {\n const sp = toContributorLevel(storyPointMin);\n const risk = toContributorLevel(riskMin);\n if (sp === null) return risk;\n if (risk === null) return sp;\n return Math.max(sp, risk);\n}\nfunction meetsContributorLevel(actorLevel, required) {\n if (required === null) return true;\n if (actorLevel === null || actorLevel === void 0 || !Number.isFinite(actorLevel)) return false;\n return actorLevel >= required;\n}\n\n// src/utils/stat-date.ts\nfunction todayInProjectTZ() {\n return (/* @__PURE__ */ new Date()).toLocaleDateString(\"en-CA\", { timeZone: PROJECT_TIMEZONE });\n}\nfunction formatDateInProjectTZ(date) {\n return date.toLocaleDateString(\"en-CA\", { timeZone: PROJECT_TIMEZONE });\n}\nfunction resolveCustomRange(startDate, endDate, today) {\n const [lo, hi] = startDate <= endDate ? [startDate, endDate] : [endDate, startDate];\n return { sinceDate: lo, untilDate: hi < today ? hi : today };\n}\nfunction resolveStatDateRange(statDate, fallbackDays) {\n const today = todayInProjectTZ();\n if (statDate) {\n if (statDate.mode === \"custom\" && statDate.startDate && statDate.endDate) {\n return resolveCustomRange(statDate.startDate, statDate.endDate, today);\n }\n if (statDate.mode === \"day\" && typeof statDate.month === \"number\" && typeof statDate.day === \"number\") {\n const dayStr = `${statDate.year}-${String(statDate.month).padStart(2, \"0\")}-${String(statDate.day).padStart(2, \"0\")}`;\n const clamped = dayStr < today ? dayStr : today;\n return { sinceDate: clamped, untilDate: clamped };\n }\n if (statDate.mode === \"month\" && typeof statDate.month === \"number\") {\n const sinceDate3 = `${statDate.year}-${String(statDate.month).padStart(2, \"0\")}-01`;\n const lastDay = new Date(statDate.year, statDate.month, 0).getDate();\n const endStr2 = `${statDate.year}-${String(statDate.month).padStart(2, \"0\")}-${String(lastDay).padStart(2, \"0\")}`;\n return { sinceDate: sinceDate3, untilDate: endStr2 < today ? endStr2 : today };\n }\n const sinceDate2 = `${statDate.year}-01-01`;\n const endStr = `${statDate.year}-12-31`;\n return { sinceDate: sinceDate2, untilDate: endStr < today ? endStr : today };\n }\n const days = fallbackDays ?? 30;\n const d = /* @__PURE__ */ new Date();\n d.setDate(d.getDate() - days);\n const sinceDate = formatDateInProjectTZ(d);\n return { sinceDate, untilDate: today };\n}\nvar DAILY_MAX_DAYS = 31;\nvar MS_PER_DAY = 24 * 60 * 60 * 1e3;\nfunction utcFromIso(dateStr) {\n const [y, m, d] = dateStr.split(\"-\").map(Number);\n return Date.UTC(y, m - 1, d);\n}\nfunction isoFromUtc(ms) {\n const d = new Date(ms);\n const yyyy = d.getUTCFullYear();\n const mm = String(d.getUTCMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getUTCDate()).padStart(2, \"0\");\n return `${yyyy}-${mm}-${dd}`;\n}\nfunction resolveStatGranularity(sinceDate, untilDate) {\n if (sinceDate === untilDate) return \"hour\";\n const days = Math.round((utcFromIso(untilDate) - utcFromIso(sinceDate)) / MS_PER_DAY) + 1;\n return days <= DAILY_MAX_DAYS ? \"day\" : \"week\";\n}\nfunction isHourlyRange(sinceDate, untilDate) {\n return resolveStatGranularity(sinceDate, untilDate) === \"hour\";\n}\nfunction weekStartKey(dateStr) {\n const ms = utcFromIso(dateStr);\n const mondayOffset = (new Date(ms).getUTCDay() + 6) % 7;\n return `${isoFromUtc(ms - mondayOffset * MS_PER_DAY)}/W`;\n}\nfunction bucketDateKey(dateStr, granularity) {\n return granularity === \"week\" ? weekStartKey(dateStr) : dateStr;\n}\nfunction generateHourRange(dateStr) {\n const hours = [];\n for (let h = 0; h < 24; h++) {\n hours.push(`${dateStr} ${String(h).padStart(2, \"0\")}:00`);\n }\n return hours;\n}\nfunction generateDateRange(sinceStr, untilStr) {\n const dates = [];\n let current = utcFromIso(sinceStr);\n const end = utcFromIso(untilStr);\n while (current <= end) {\n dates.push(isoFromUtc(current));\n current += MS_PER_DAY;\n }\n return dates;\n}\nfunction generateWeekRange(sinceStr, untilStr) {\n const weeks = [];\n const mondayOffset = (new Date(utcFromIso(sinceStr)).getUTCDay() + 6) % 7;\n let current = utcFromIso(sinceStr) - mondayOffset * MS_PER_DAY;\n const end = utcFromIso(untilStr);\n while (current <= end) {\n weeks.push(`${isoFromUtc(current)}/W`);\n current += 7 * MS_PER_DAY;\n }\n return weeks;\n}\nfunction generateBucketRange(sinceStr, untilStr, granularity) {\n if (granularity === \"hour\") return generateHourRange(sinceStr);\n if (granularity === \"week\") return generateWeekRange(sinceStr, untilStr);\n return generateDateRange(sinceStr, untilStr);\n}\n\n// src/utils/message-filter.ts\nvar ACTIVITY_KIND_FILTERS = [\n \"inputs\",\n \"milestones\",\n \"lifecycle\",\n \"external\",\n \"tools\"\n];\nvar KIND_CHIP = {\n human_input: \"inputs\",\n agent_milestone: \"milestones\",\n detail: \"milestones\",\n lifecycle: \"lifecycle\",\n external: \"external\"\n};\nvar SPECIAL_CARD_METADATA_TYPES = /* @__PURE__ */ new Set([\n \"activity_block\",\n \"activity_log\",\n \"codespace_boot_progress\",\n \"agent_question\",\n \"reporter_email_draft\"\n]);\nfunction effectiveMessageKind(msg) {\n const kind = msg.kind ?? \"chat\";\n if (kind !== \"chat\") return kind;\n const metaType = msg.metadata?.type;\n if (metaType === \"agent_mention\") return \"external\";\n if (metaType && SPECIAL_CARD_METADATA_TYPES.has(metaType)) return \"chat\";\n if (metaType === \"agent_response\" || msg.role === \"assistant\") return \"detail\";\n return \"chat\";\n}\nfunction legacyChatChip(msg) {\n if (msg.metadata?.type === \"activity_block\") return \"tools\";\n if (msg.metadata?.type === \"activity_log\") return \"lifecycle\";\n if (msg.metadata?.type === \"system_notification\") return \"external\";\n if (msg.role === \"user\") return \"inputs\";\n return \"milestones\";\n}\nfunction messageMatchesActivityFilters(msg, filters) {\n if (msg.parentMessageId) return true;\n const chip = KIND_CHIP[effectiveMessageKind(msg)] ?? legacyChatChip(msg);\n return filters.includes(chip);\n}\n\n// src/utils/mentions.ts\nvar MENTION_TOKEN_REGEX = /@\\[(\\w+):([^\\]]+)\\]/g;\nfunction serializeMention(type, id) {\n return `@[${type}:${id}]`;\n}\nfunction buildMentionKey(type, id) {\n return `${type}:${id}`;\n}\nfunction parseMentions(content) {\n const tokens = [];\n for (const match of content.matchAll(MENTION_TOKEN_REGEX)) {\n tokens.push({ type: match[1], id: match[2] });\n }\n return tokens;\n}\nfunction hasMentionToken(content) {\n return content.includes(\"@[\");\n}\nfunction replaceMentionTokens(content, resolve) {\n if (!hasMentionToken(content)) return content;\n return content.replace(MENTION_TOKEN_REGEX, (raw, type, id) => {\n const hit = resolve(type, id);\n if (!hit) return raw;\n if (hit.slug) return `#${hit.slug}`;\n return hit.label ? `@${hit.label}` : raw;\n });\n}\nfunction stripMentionTokens(content) {\n if (!hasMentionToken(content)) return content;\n return content.replace(MENTION_TOKEN_REGEX, \"\").replace(/\\s{2,}/g, \" \").trim();\n}\nvar BUILDER_STREAM_ID = \"builder\";\nvar REVIEWER_STREAM_ID = \"reviewer\";\nvar STREAM_MENTION_IDS = /* @__PURE__ */ new Set([BUILDER_STREAM_ID, REVIEWER_STREAM_ID]);\nfunction getStreamMentionTarget(tokens) {\n const hit = tokens.find((t) => t.type === \"agent\" && STREAM_MENTION_IDS.has(t.id));\n return hit ? hit.id : null;\n}\nfunction getStreamMentionTargetFromKeys(keys) {\n for (const key of keys) {\n if (key === buildMentionKey(\"agent\", BUILDER_STREAM_ID)) return BUILDER_STREAM_ID;\n if (key === buildMentionKey(\"agent\", REVIEWER_STREAM_ID)) return REVIEWER_STREAM_ID;\n }\n return null;\n}\nvar STREAM_MENTION_STRIP_REGEX = /(?:@\\[agent:(?:builder|reviewer)\\]|@\\S+ \\(agent:(?:builder|reviewer)\\))[ \\t]*/g;\nfunction stripStreamMentionText(content) {\n return content.replace(STREAM_MENTION_STRIP_REGEX, \"\").trim();\n}\nfunction resolveMentions(content, metadata) {\n if (!metadata || typeof metadata !== \"object\") return content;\n const meta = metadata;\n if (meta.type !== \"mentions\" || !meta.mentions) return content;\n const mentions = meta.mentions;\n return content.replace(MENTION_TOKEN_REGEX, (_match, type, id) => {\n const key = `${type}:${id}`;\n const mention = mentions[key];\n if (!mention) return _match;\n const prefix = mention.slug ? `#${mention.slug}` : `@${mention.label}`;\n return `${prefix} (${type}:${id})`;\n });\n}\n\n// src/utils/tag-mentions.ts\nfunction hasTagMentionToken(content) {\n return content.includes(\"@[tag:\");\n}\nfunction indexTags(tags) {\n const byId = /* @__PURE__ */ new Map();\n const byName = /* @__PURE__ */ new Map();\n for (const tag of tags) {\n byId.set(tag.id, tag);\n const key = tag.name.trim().toLowerCase();\n byName.set(key, byName.has(key) ? null : tag);\n }\n return { byId, byName };\n}\nfunction toMentionData(tag) {\n return {\n type: \"tag\",\n label: tag.name,\n ...tag.color ? { color: tag.color } : {},\n ...tag.description ? { description: tag.description } : {},\n // Breadcrumb for external readers: a full spec exists, call get_tag for it.\n ...(tag.overview ?? \"\").trim().length > 0 ? { hasOverview: true } : {}\n };\n}\nfunction canonicalizeTagMentions(content, tags, redirects) {\n if (!hasTagMentionToken(content) || tags.length === 0 && !redirects?.size) {\n return { content, mentions: {}, rewritten: false };\n }\n const { byId, byName } = indexTags(tags);\n const mentions = {};\n let rewritten = false;\n const next = content.replace(MENTION_TOKEN_REGEX, (match, type, ref) => {\n if (type !== \"tag\") return match;\n const key = ref.trim().toLowerCase();\n const tag = byId.get(ref) ?? (byName.has(key) ? byName.get(key) : redirects?.get(key)) ?? null;\n if (!tag) return match;\n mentions[buildMentionKey(\"tag\", tag.id)] = toMentionData(tag);\n const token = serializeMention(\"tag\", tag.id);\n if (token !== match) rewritten = true;\n return token;\n });\n return { content: next, mentions, rewritten };\n}\n\n// src/utils/agent-triggers.ts\nvar FORCE_PREFIX = \"!\";\nfunction hasForcePrefix(content) {\n return content.trimStart().startsWith(FORCE_PREFIX);\n}\nfunction stripForcePrefix(content) {\n const stripped = content.trimStart().slice(FORCE_PREFIX.length).trimStart();\n return stripped || content;\n}\nfunction resolveAgentTrigger(rawContent, opts) {\n const streamTarget = getStreamMentionTarget(parseMentions(rawContent));\n if (streamTarget) {\n return {\n target: streamTarget,\n deliveredContent: stripStreamMentionText(rawContent) || rawContent\n };\n }\n if (hasForcePrefix(rawContent)) {\n const stripped = rawContent.trimStart().slice(FORCE_PREFIX.length).trim();\n if (stripped || opts?.hasAttachments) {\n return { target: \"builder\", deliveredContent: stripped || rawContent };\n }\n }\n return { target: null, deliveredContent: rawContent };\n}\nfunction isAwaitingUserInput(source) {\n if (!source) return false;\n return !!source.awaitingUserInput || source.agentRunnerStatus === \"waiting_for_input\";\n}\n\n// src/utils/autopilot-ratio.ts\nvar AUTOPILOT_RATIO_MIN = 1;\nvar AUTOPILOT_RATIO_MAX = 6.5;\nfunction computeMemoryBounds(agentCpu, sidecarCpu, sidecarMemoryGi) {\n const totalCpu = agentCpu + sidecarCpu;\n const minPodMemory = totalCpu * AUTOPILOT_RATIO_MIN;\n const maxPodMemory = totalCpu * AUTOPILOT_RATIO_MAX;\n const minAgentMemory = minPodMemory - sidecarMemoryGi;\n const maxAgentMemory = maxPodMemory - sidecarMemoryGi;\n const minMemoryGi = Math.max(1, Math.ceil(minAgentMemory));\n const maxMemoryGi = Math.floor(maxAgentMemory);\n return { minMemoryGi, maxMemoryGi };\n}\nfunction computePodRatio(agentCpu, agentMemoryGi, sidecarCpu, sidecarMemoryGi) {\n const totalCpu = agentCpu + sidecarCpu;\n const totalMemory = agentMemoryGi + sidecarMemoryGi;\n if (totalCpu === 0) return 0;\n return totalMemory / totalCpu;\n}\nfunction isValidAutopilotConfig(agentCpu, agentMemoryGi, sidecarCpu, sidecarMemoryGi) {\n const ratio = computePodRatio(agentCpu, agentMemoryGi, sidecarCpu, sidecarMemoryGi);\n return ratio >= AUTOPILOT_RATIO_MIN && ratio <= AUTOPILOT_RATIO_MAX;\n}\n\n// src/utils/service-definitions.ts\nvar POSTGRES_ENV = {\n POSTGRES_HOST_AUTH_METHOD: \"trust\",\n POSTGRES_DB: \"conveyor\"\n};\nvar FIREBASE_EMULATOR_COMMAND = [\n \"sh\",\n \"-c\",\n `set -e; mkdir -p /home/node && cd /home/node && cat > firebase.json <<'EOF'\n{\"emulators\":{\"auth\":{\"host\":\"0.0.0.0\",\"port\":9099},\"hub\":{\"host\":\"0.0.0.0\",\"port\":4400},\"ui\":{\"enabled\":false}}}\nEOF\nexec firebase emulators:start --only=auth --project=rally-cry-dev`\n];\nvar FIREBASE_EMULATOR_ENV = {\n METADATA_SERVER_DETECTION: \"none\",\n GOOGLE_APPLICATION_CREDENTIALS: \"/dev/null\"\n};\nvar CATALOG = {\n postgresql: {\n name: \"postgresql\",\n image: \"postgres:16-alpine\",\n command: [\n \"sh\",\n \"-c\",\n // Start postgres, wait for readiness, then create the test database.\n // Durability flags: service state is ephemeral by design (overlayfs, no\n // PVC; a crash re-seeds from pod-data), so commits must never wait on a\n // WAL flush. fsync=off + synchronous_commit=off + full_page_writes=off\n // remove all blocking storage I/O — without them, per-commit flushes on\n // the node's network boot disk dominated int-test wall time (~100ms/commit).\n \"if [ ! -s /var/lib/postgresql/data/PG_VERSION ] && [ -d /var/lib/postgresql/pod-data ]; then cp -a /var/lib/postgresql/pod-data/. /var/lib/postgresql/data/; fi; chown -R postgres:postgres /var/lib/postgresql/data; docker-entrypoint.sh postgres -c fsync=off -c synchronous_commit=off -c full_page_writes=off & PID=$!; for i in $(seq 1 30); do pg_isready -U postgres && break; sleep 1; done; createdb -U postgres conveyor_test 2>/dev/null || true; wait $PID\"\n ],\n ports: [5432],\n livenessProbe: {\n exec: [\"pg_isready\", \"-U\", \"postgres\"],\n periodSeconds: 30,\n failureThreshold: 3,\n timeoutSeconds: 5,\n initialDelaySeconds: 60\n },\n env: { ...POSTGRES_ENV },\n resources: {\n // postgres runs from the baked seed at /var/lib/postgresql/pod-data via\n // overlayfs CoW (no emptyDir — see k8s-pod-spec.ts), so WAL + catalog +\n // re-seed churn charges the container's ephemeral-storage. It must exceed\n // the ~1Gi ceiling where pods evicted, but is bounded by TWO Autopilot rules:\n // 1) limit == request — Autopilot caps the limit DOWN to the request at\n // admission, so headroom must live on the REQUEST, not just the limit;\n // 2) the SUM of all container ephemeral requests in a pod must be ≤ 10Gi\n // (an emptyDir doesn't escape this: its usage still evicts against the\n // container limit, and raising the limit re-hits rule 1 → the cap).\n // The agent is trimmed to 4Gi (resource-tiers.ts) to free room: with\n // agent 4 + gcsfuse 1 + lgtm 1 + es/redis/firebase 0.75, postgres gets 3Gi\n // and the heaviest (URC) pod sits at 9.75Gi + 10Mi for GCS Fuse metadata\n // prefetch — under the 10Gi cap — while giving postgres 3x the ~1Gi\n // ceiling that evicted. Keep request == limit;\n // see the per-pod ephemeral budget guard test.\n // CPU: the request is the CFS floor; the old 50m starved postgres to 5ms\n // of CPU per 100ms period — every query burst hit throttle stalls, which\n // showed up as ~100ms floors on trivial statements and dominated the API\n // int suite even after the fsync flags above. 500m is paid for out of the\n // agent's derived share (resource-tiers.ts). The limit bursts to 2 for\n // spiky work — the first-boot pod-data seed copy and int-suite query\n // storms — borrowing idle node CPU without moving the request.\n requests: { cpuMillicores: 500, memoryMi: 512, ephemeralMi: 3 * 1024 },\n limits: { cpuMillicores: 2e3, memoryMi: 512, ephemeralMi: 3 * 1024 }\n },\n connectionEnv: {\n DATABASE_URL: \"postgresql://postgres@postgresql:5432/conveyor\",\n TEST_DATABASE_URL: \"postgresql://postgres@postgresql:5432/conveyor_test\"\n },\n statefulBake: true,\n bake: {\n // Start postgres, wait for readiness, then create the test database so\n // it's baked into the committed image. No pod-data restore (nothing is\n // seeded yet) and no durability flags (the bake's writes must land).\n // NOTE: docker-compose interpolates `$VAR`/`$(...)`, so every `$` that\n // must reach the shell is doubled.\n command: [\n \"sh\",\n \"-c\",\n \"docker-entrypoint.sh postgres & PID=$$!; for i in $$(seq 1 30); do pg_isready -U postgres && break; sleep 1; done; createdb -U postgres conveyor_test 2>/dev/null || true; wait $$PID\"\n ],\n environment: { ...POSTGRES_ENV },\n healthcheck: {\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"],\n intervalSec: 2,\n timeoutSec: 5,\n retries: 15\n }\n }\n },\n redis: {\n name: \"redis\",\n image: \"redis:7-alpine\",\n command: [\"redis-server\", \"--appendonly\", \"yes\", \"--dir\", \"/data\"],\n ports: [6379],\n env: {},\n resources: {\n requests: { cpuMillicores: 25, memoryMi: 32, ephemeralMi: 256 },\n limits: { cpuMillicores: 50, memoryMi: 64, ephemeralMi: 256 }\n },\n connectionEnv: {\n REDIS_URL: \"redis://redis:6379\",\n AUTH_REDIS_URL: \"redis://redis:6379\"\n },\n statefulBake: false,\n // Redis holds no baked state, so the bake runs the stock image CMD.\n bake: {},\n mirror: { src: \"redis:7-alpine\", dest: \"mirror-redis:7-alpine\" }\n },\n elasticsearch: {\n name: \"elasticsearch\",\n // 9.4.0 matches universal-rally-cry's local compose + its v9 ES client —\n // the v9 client sends Accept: compatible-with=9, which an 8.x server\n // rejects (media_type_header_exception), breaking search/audit indexing\n // in pods. 512m heap matches the project compose sizing.\n image: \"docker.elastic.co/elasticsearch/elasticsearch:9.4.0\",\n ports: [9200],\n // Baked service images are `docker commit`s of a recently-running ES, so\n // they carry a stale data-dir node.lock; ES 9 hard-fails on it at boot\n // (\"Underlying file changed by an external force\" → AlreadyClosedException).\n // Clear it before handing off to the stock entrypoint.\n command: [\n \"sh\",\n \"-c\",\n // ALL Lucene lock files, not just node.lock — the baked image also\n // carries per-index write.lock + snapshot_cache/write.lock, and ES 9\n // fail-fasts on any of them (\"changed by an external force\").\n \"find /usr/share/elasticsearch/data -name '*.lock' -type f -delete 2>/dev/null; exec /usr/local/bin/docker-entrypoint.sh eswrapper\"\n ],\n env: {\n \"discovery.type\": \"single-node\",\n \"xpack.security.enabled\": \"false\",\n \"xpack.ml.enabled\": \"false\",\n \"xpack.watcher.enabled\": \"false\",\n \"xpack.profiling.enabled\": \"false\",\n \"ingest.geoip.downloader.enabled\": \"false\",\n ES_JAVA_OPTS: \"-Xms512m -Xmx512m\"\n },\n resources: {\n // CPU limit 4x the request: ES cold-start is a CPU-bound JVM boot\n // (class loading + JIT + recovery of the docker-commit'ed data dir),\n // and the 500m hard cap put it at ~135s to yellow — past the sidecar\n // wait script's original 90s budget. Bursting to 2 cut it to ~40s on\n // the real cluster (A/B on identical nodes, 2 rounds). The burst only\n // borrows idle node CPU at boot; under contention CFS still floors ES\n // at its 500m request.\n requests: { cpuMillicores: 500, memoryMi: 1024, ephemeralMi: 256 },\n limits: { cpuMillicores: 2e3, memoryMi: 1024, ephemeralMi: 256 }\n },\n connectionEnv: {\n ELASTICSEARCH_URL: \"http://elasticsearch:9200\"\n },\n statefulBake: true,\n bake: {\n // No lock-clearing command at bake time: the bake starts from the stock\n // image, which has no committed data dir to unlock yet.\n environment: {\n \"discovery.type\": \"single-node\",\n \"xpack.security.enabled\": \"false\",\n ES_JAVA_OPTS: \"-Xms512m -Xmx512m\"\n }\n }\n },\n // All-in-one image bundling Grafana + Loki + Tempo + Mimir + an OTEL Collector.\n // Pinned tag (not :latest) so the image-builder content hash stays\n // deterministic across upstream releases — see image-builder.ts content-hash\n // dedup keyed on `deps.sorted()`.\n lgtm: {\n name: \"lgtm\",\n image: \"grafana/otel-lgtm:0.11.6\",\n // The otel-lgtm image's own CMD is [\"/otel-lgtm/run-all.sh\"] (WORKDIR\n // /otel-lgtm). Declaring it explicitly makes lgtm a command-based service so\n // the lazy start-file gate wraps it like the others — otherwise it launches\n // via image CMD at boot and can't be parked (which is why warm-booting it at\n // a minimal request OOMKilled it). getSidecarSpecs strips this command for a\n // baked lgtm image, so it only applies to the stock image whose launcher is\n // exactly this path.\n command: [\"/otel-lgtm/run-all.sh\"],\n ports: [\n // OTLP gRPC + HTTP — agents and user code emit telemetry here.\n 4317,\n 4318,\n // Grafana UI — reachable through the existing preview proxy on\n // https://3000-{sessionId}.preview.<PREVIEW_DOMAIN>/.\n 3e3\n ],\n env: {\n // The pod is per-task; the preview proxy authenticates the session\n // upstream, so anonymous in-pod admin is acceptable here.\n GF_AUTH_ANONYMOUS_ENABLED: \"true\",\n GF_AUTH_ANONYMOUS_ORG_ROLE: \"Admin\",\n GF_SECURITY_ALLOW_EMBEDDING: \"true\",\n ENABLE_LOGS_GRAFANA: \"true\",\n ENABLE_LOGS_OTELCOL: \"true\"\n },\n resources: {\n // Autopilot caps the ephemeral-storage limit to the request (see the\n // postgresql note), so the 1Gi headroom must be on the request too.\n requests: { cpuMillicores: 250, memoryMi: 1024, ephemeralMi: 1024 },\n limits: { cpuMillicores: 1e3, memoryMi: 2048, ephemeralMi: 1024 }\n },\n statefulBake: false,\n // No `bake` block: a BAKE produces traces nobody reads, so starting the\n // (heavy) collector image would only add a pull + boot to every build.\n // lgtm still runs for live pods, and is never committed regardless.\n mirror: { src: \"grafana/otel-lgtm:0.11.6\", dest: \"mirror-otel-lgtm:0.11.6\" }\n },\n \"firebase-auth-emulator\": {\n name: \"firebase-auth-emulator\",\n image: \"andreysenov/firebase-tools:latest\",\n command: FIREBASE_EMULATOR_COMMAND,\n ports: [9099, 4400],\n env: {\n // The emulator container inherits the pod's Workload Identity, so\n // firebase-tools finds GCP credentials and its `emulators:start` does an\n // online \"auto auth\" + project validation that stalls ~47s on the pod's\n // locked-down egress (the dominant service boot cost — measured live).\n // The emulator needs NO real credentials, so cut off credential discovery\n // for this container only: google-auth-library skips metadata detection\n // and finds no key file, firebase-tools logs \"not authenticated\" and\n // starts the emulator immediately. The agent container keeps its WI.\n ...FIREBASE_EMULATOR_ENV\n },\n resources: {\n requests: { cpuMillicores: 100, memoryMi: 256, ephemeralMi: 256 },\n limits: { cpuMillicores: 500, memoryMi: 512, ephemeralMi: 256 }\n },\n connectionEnv: {\n // In docker-compose, services reach each other by service name — the\n // runtime pod equivalents use `localhost` because co-located services\n // share the pod's network namespace.\n FIREBASE_AUTH_EMULATOR_HOST: \"firebase-auth-emulator:9099\",\n NEXT_PUBLIC_FIREBASE_AUTH_EMULATOR_HOST: \"firebase-auth-emulator:9099\"\n },\n statefulBake: false,\n mirror: {\n src: \"andreysenov/firebase-tools:latest\",\n dest: \"mirror-firebase-tools:latest\"\n },\n bake: {\n // The emulator writes its config at startup, so the bake needs the same\n // inline command the runtime uses.\n command: FIREBASE_EMULATOR_COMMAND,\n environment: FIREBASE_EMULATOR_ENV,\n healthcheck: {\n // Probe with node, the one runtime this image guarantees. The image\n // (`andreysenov/firebase-tools`) is a slim Node image that ships\n // NEITHER `wget` NOR `curl`, so the `wget -qO- …` probe this replaced\n // exited 127 on every attempt: a healthy emulator burned all 20 retries\n // and every bake reported it unhealthy. See the catalog invariant in\n // `service-definitions.test.ts`, which also executes this probe.\n test: [\n \"CMD-SHELL\",\n `node -e \"fetch('http://localhost:9099/').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))\"`\n ],\n intervalSec: 3,\n timeoutSec: 5,\n retries: 20\n }\n }\n }\n};\nvar SERVICE_DEFINITIONS = CATALOG;\nvar SUPPORTED_CLAUDESPACE_DEPS = Object.keys(CATALOG);\nvar STATEFUL_BAKE_DEPS = new Set(\n SUPPORTED_CLAUDESPACE_DEPS.filter((dep) => SERVICE_DEFINITIONS[dep].statefulBake)\n);\nvar MIRRORABLE_SIDECARS = Object.fromEntries(\n SUPPORTED_CLAUDESPACE_DEPS.flatMap((dep) => {\n const mirror = SERVICE_DEFINITIONS[dep].mirror;\n return mirror ? [[dep, mirror]] : [];\n })\n);\nfunction sidecarRequestTotals(deps) {\n let totalCpu = 0;\n let totalMemoryMi = 0;\n for (const dep of deps) {\n const definition = SERVICE_DEFINITIONS[dep];\n if (!definition) continue;\n totalCpu += definition.resources.requests.cpuMillicores / 1e3;\n totalMemoryMi += definition.resources.requests.memoryMi;\n }\n return { cpu: totalCpu, memoryGi: totalMemoryMi / 1024 };\n}\n\n// src/utils/prestige.ts\nvar LEVELS_PER_BAND = 100;\nvar PRESTIGE_TIERS = ACHIEVEMENT_RARITIES.map((rarity, index) => ({\n prestige: index + 1,\n name: rarity.name,\n color: rarity.color,\n iconPath: rarity.iconPath,\n minLevel: (index + 1) * LEVELS_PER_BAND\n}));\nvar TOP_PRESTIGE_BAND = PRESTIGE_TIERS.length;\nfunction prestigeBandForLevel(level) {\n if (!Number.isFinite(level) || level < LEVELS_PER_BAND) return 0;\n return Math.min(TOP_PRESTIGE_BAND, Math.floor(level / LEVELS_PER_BAND));\n}\nfunction prestigeTierForBand(band) {\n if (band <= 0) return null;\n return PRESTIGE_TIERS[band - 1] ?? null;\n}\nfunction prestigeFromXp(totalXp) {\n const levelInfo = levelFromXp(totalXp);\n const prestige = prestigeBandForLevel(levelInfo.level);\n return { ...levelInfo, prestige, tier: prestigeTierForBand(prestige) };\n}\n\n// src/utils/format-number.ts\nvar RAW_MAX = 9999.5;\nvar K_MAX = 999950;\nvar M_MAX = 99995e4;\nfunction scaled(abs, divisor, suffix) {\n return `${(abs / divisor).toFixed(1).replace(/\\.0$/, \"\")}${suffix}`;\n}\nfunction formatCompactNumber(value) {\n if (!Number.isFinite(value)) return \"0\";\n const sign = value < 0 ? \"-\" : \"\";\n const abs = Math.abs(value);\n if (abs < RAW_MAX) return `${sign}${Math.round(abs)}`;\n if (abs < K_MAX) return `${sign}${scaled(abs, 1e3, \"K\")}`;\n if (abs < M_MAX) return `${sign}${scaled(abs, 1e6, \"M\")}`;\n return `${sign}${scaled(abs, 1e9, \"B\")}`;\n}\nfunction formatCompactSigned(value) {\n const formatted = formatCompactNumber(value);\n return value > 0 ? `+${formatted}` : formatted;\n}\nfunction formatCompactUsd(value) {\n if (!Number.isFinite(value)) return \"$0\";\n const sign = value < 0 ? \"-\" : \"\";\n const abs = Math.abs(value);\n if (abs < RAW_MAX) return `${sign}$${abs.toFixed(2)}`;\n return `${sign}$${formatCompactNumber(abs)}`;\n}\n\n// src/utils/pod-size-presets.ts\nvar POD_SIZE_NAMES = [\"small\", \"medium\", \"large\"];\nvar POD_SIZE_PRESETS = {\n small: { cpu: 1.95, memory: 7 },\n medium: { cpu: 3.9, memory: 14 },\n large: { cpu: 5.25, memory: 18 }\n};\nvar DEFAULT_POD_SIZE = \"small\";\nfunction isPodSizeName(value) {\n return typeof value === \"string\" && POD_SIZE_NAMES.includes(value);\n}\n\n// src/utils/compute-provider.ts\nvar COMPUTE_PROVIDER_IDS = [\n \"github\",\n \"claudespace\",\n \"none\"\n];\nvar DEFAULT_COMPUTE_PROVIDER = \"github\";\nfunction resolveComputeProvider(value) {\n return COMPUTE_PROVIDER_IDS.includes(value) ? value : DEFAULT_COMPUTE_PROVIDER;\n}\nfunction isComputeDisabled(value) {\n return resolveComputeProvider(value) === \"none\";\n}\nvar COMPUTE_DISABLED_REASON = 'Compute is set to \"None\" for this project, so cards do not spawn environments. Connect a local agent, or pick a compute provider in Settings \\u2192 Cloud.';\n\n// src/utils/chat-provider.ts\nvar CHAT_PROVIDER_IDS = [\"slack\", \"discord\", \"none\"];\nvar DEFAULT_CHAT_PROVIDER = \"none\";\nfunction resolveChatProvider(value) {\n return CHAT_PROVIDER_IDS.includes(value) ? value : DEFAULT_CHAT_PROVIDER;\n}\nfunction chatProviderExclusiveReason(connected) {\n const name = connected === \"slack\" ? \"Slack\" : \"Discord\";\n return `A project can have one chat integration \\u2014 disconnect ${name} in Settings \\u2192 Integrations first.`;\n}\n\n// src/utils/json-merge-patch.ts\nfunction isPlainObject(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n}\nfunction applyJsonMergePatch(target, patch) {\n if (!isPlainObject(patch)) return patch;\n const base = isPlainObject(target) ? { ...target } : {};\n for (const [key, value] of Object.entries(patch)) {\n if (value === null) {\n delete base[key];\n } else if (isPlainObject(value)) {\n base[key] = applyJsonMergePatch(base[key], value);\n } else {\n base[key] = value;\n }\n }\n return base;\n}\n\n// src/utils/boot-progress.ts\nvar V3_BOOT_STEP_KEYS = [\n \"pod_created\",\n \"pod_scheduled\",\n \"containers_ready\",\n \"workbench_ready\",\n \"repo_synced\",\n \"agent_connected\",\n \"sidecars_ready\",\n \"branch_ready\",\n \"agent_live\",\n \"start_command_launched\",\n \"app_serving\"\n];\nvar POD_REPORTABLE_BOOT_STEPS = [\n \"workbench_ready\",\n \"repo_synced\",\n \"sidecars_ready\",\n \"branch_ready\",\n \"agent_live\",\n \"start_command_launched\"\n];\nfunction isPodReportableBootStep(value) {\n return typeof value === \"string\" && POD_REPORTABLE_BOOT_STEPS.includes(value);\n}\nfunction isBootStepKey(value) {\n return typeof value === \"string\" && V3_BOOT_STEP_KEYS.includes(value);\n}\nvar V3_BOOT_STEPS = [\n { key: \"pod_created\", label: \"Pod created\", track: \"agent\", fallbackWeightMs: 2e3 },\n { key: \"pod_scheduled\", label: \"Pod scheduled\", track: \"agent\", fallbackWeightMs: 4e3 },\n { key: \"containers_ready\", label: \"Containers up\", track: \"agent\", fallbackWeightMs: 14e3 },\n { key: \"workbench_ready\", label: \"Workbench daemon up\", track: \"agent\", fallbackWeightMs: 2e3 },\n { key: \"repo_synced\", label: \"Repository synced\", track: \"agent\", fallbackWeightMs: 6e3 },\n { key: \"agent_connected\", label: \"Agent connected\", track: \"agent\", fallbackWeightMs: 6e3 },\n { key: \"sidecars_ready\", label: \"Sidecars ready\", track: \"agent\", fallbackWeightMs: 1e3 },\n { key: \"branch_ready\", label: \"Branch checked out\", track: \"agent\", fallbackWeightMs: 2e3 },\n { key: \"agent_live\", label: \"Agent working\", track: \"agent\", fallbackWeightMs: 4e3 },\n {\n key: \"start_command_launched\",\n label: \"App launched\",\n track: \"app\",\n fallbackWeightMs: 2e3\n },\n { key: \"app_serving\", label: \"App serving\", track: \"app\", fallbackWeightMs: 12e4 }\n];\nvar CODESPACE_BOOT_STEPS = [\n { key: \"pod_created\", label: \"Codespace created\", track: \"agent\", fallbackWeightMs: 4e3 },\n { key: \"pod_scheduled\", label: \"VM starting\", track: \"agent\", fallbackWeightMs: 2e4 },\n { key: \"containers_ready\", label: \"VM up\", track: \"agent\", fallbackWeightMs: 12e4 },\n { key: \"agent_connected\", label: \"Agent connected\", track: \"agent\", fallbackWeightMs: 9e4 },\n { key: \"agent_live\", label: \"Agent working\", track: \"agent\", fallbackWeightMs: 3e4 },\n {\n key: \"start_command_launched\",\n label: \"App launched\",\n track: \"app\",\n fallbackWeightMs: 2e3\n },\n { key: \"app_serving\", label: \"App serving\", track: \"app\", fallbackWeightMs: 12e4 }\n];\nfunction bootStepsForBackend(backend) {\n return backend === \"codespace\" ? CODESPACE_BOOT_STEPS : V3_BOOT_STEPS;\n}\nfunction sanitizeBootTimeline(raw) {\n if (!Array.isArray(raw)) return [];\n const byKey = /* @__PURE__ */ new Map();\n for (const entry of raw) {\n if (!entry || typeof entry !== \"object\") continue;\n const key = entry.key;\n const at = entry.at;\n if (!isBootStepKey(key) || typeof at !== \"string\") continue;\n if (Number.isNaN(Date.parse(at))) continue;\n if (!byKey.has(key)) byKey.set(key, { key, at });\n }\n return V3_BOOT_STEP_KEYS.filter((k) => byKey.has(k)).map((k) => byKey.get(k));\n}\nfunction summarizeBootEstimates(samples) {\n const estimates = {};\n for (const sample of samples) {\n const at = /* @__PURE__ */ new Map();\n for (const m of sanitizeBootTimeline(sample)) at.set(m.key, Date.parse(m.at));\n for (let i = 1; i < V3_BOOT_STEP_KEYS.length; i++) {\n const key = V3_BOOT_STEP_KEYS[i];\n const prev = V3_BOOT_STEP_KEYS[i - 1];\n const cur = at.get(key);\n const before = at.get(prev);\n if (cur === void 0 || before === void 0) continue;\n const delta = cur - before;\n if (delta < 0) continue;\n const current = estimates[key];\n if (current === void 0 || delta > current) estimates[key] = delta;\n }\n }\n return { estimates, sampleCount: samples.length };\n}\nfunction weightFor(key, estimates, defs) {\n const est = estimates[key];\n if (typeof est === \"number\" && est >= 0) return est;\n return defs.find((s) => s.key === key)?.fallbackWeightMs ?? 1;\n}\nfunction buildSteps(defs, doneAt, now) {\n const steps = [];\n let activeKey = null;\n let prevAt = null;\n for (const def of defs) {\n const doneTs = doneAt.get(def.key);\n if (doneTs !== void 0) {\n const at = Date.parse(doneTs);\n const durationMs = prevAt === null ? void 0 : Math.max(0, at - prevAt);\n steps.push({\n key: def.key,\n label: def.label,\n track: def.track,\n status: \"done\",\n at: doneTs,\n durationMs\n });\n prevAt = at;\n } else if (activeKey === null) {\n activeKey = def.key;\n const durationMs = prevAt === null ? void 0 : Math.max(0, now - prevAt);\n steps.push({\n key: def.key,\n label: def.label,\n track: def.track,\n status: \"active\",\n durationMs\n });\n } else {\n steps.push({ key: def.key, label: def.label, track: def.track, status: \"pending\" });\n }\n }\n return { steps, activeKey };\n}\nfunction trackProgress(defs, allSteps, doneAt, estimates, now) {\n const keys = new Set(defs.map((d) => d.key));\n const steps = allSteps.filter((s) => keys.has(s.key));\n const totalWeight = defs.reduce((sum, s) => sum + weightFor(s.key, estimates, defs), 0) || 1;\n const firstUndoneIndex = steps.findIndex((s) => s.status === \"active\" || s.status === \"pending\");\n if (firstUndoneIndex === -1) return { fraction: 1, etaMs: null, complete: true, steps };\n let active = steps[firstUndoneIndex];\n if (active.status === \"pending\") {\n let lastDoneMs = null;\n for (const at of doneAt.values()) {\n const ts = Date.parse(at);\n if (lastDoneMs === null || ts > lastDoneMs) lastDoneMs = ts;\n }\n active = {\n ...active,\n status: \"active\",\n durationMs: lastDoneMs === null ? void 0 : Math.max(0, now - lastDoneMs)\n };\n steps[firstUndoneIndex] = active;\n }\n let doneWeight = 0;\n for (const def of defs) {\n if (doneAt.has(def.key)) doneWeight += weightFor(def.key, estimates, defs);\n }\n const activeWeight = weightFor(active.key, estimates, defs);\n const runningMs = active.durationMs ?? 0;\n const partial = activeWeight > 0 ? Math.min(runningMs / activeWeight, 0.95) * activeWeight : 0;\n const pending = defs.filter((d) => d.key !== active.key && !doneAt.has(d.key)).reduce((sum, d) => sum + weightFor(d.key, estimates, defs), 0);\n const fraction = Math.min((doneWeight + partial) / totalWeight, 0.99);\n const etaMs = Math.max(0, Math.round(activeWeight - runningMs) + pending);\n return { fraction, etaMs, complete: false, steps };\n}\nfunction computeBootProgress(input) {\n const estimates = input.estimates ?? {};\n const defs = input.steps ?? V3_BOOT_STEPS;\n const milestones = sanitizeBootTimeline(input.milestones);\n const doneAt = /* @__PURE__ */ new Map();\n for (const m of milestones) doneAt.set(m.key, m.at);\n const firstAt = milestones.length > 0 ? Date.parse(milestones[0].at) : null;\n const elapsedMs = firstAt === null ? null : Math.max(0, input.now - firstAt);\n const { steps: allSteps, activeKey } = buildSteps(defs, doneAt, input.now);\n const agentDefs = defs.filter((s) => s.track === \"agent\");\n const appDefs = defs.filter((s) => s.track === \"app\");\n const agent = trackProgress(agentDefs, allSteps, doneAt, estimates, input.now);\n const app = trackProgress(appDefs, allSteps, doneAt, estimates, input.now);\n return {\n fraction: agent.fraction,\n steps: agent.steps,\n activeKey,\n complete: agent.complete,\n elapsedMs,\n etaMs: agent.etaMs,\n app\n };\n}\n\n// src/utils/task-planning.ts\nvar PRE_BUILD_TASK_STATUSES = /* @__PURE__ */ new Set([\"Planning\", \"Open\"]);\nfunction hasTaskPlan(plan) {\n return !!plan?.trim();\n}\n\n// src/utils/task-card-dto.ts\nfunction toCardFromTaskDTO(dto) {\n return {\n id: dto.id,\n slug: dto.slug,\n subProjectId: dto.subProjectId,\n title: dto.title,\n status: dto.status,\n statusChangedAt: dto.statusChangedAt,\n isRelease: dto.isRelease,\n releaseTaskId: dto.releaseTaskId,\n releaseTitle: dto.releaseTitle,\n hasPlan: !!dto.plan?.trim(),\n priorityId: dto.priorityId,\n priority: dto.priority,\n riskId: dto.riskId,\n risk: dto.risk,\n taskTags: dto.taskTags,\n onHold: dto.onHold,\n iconId: dto.iconId,\n parentIconId: dto.parentIconId,\n storyPointId: dto.storyPointId,\n storyPoint: dto.storyPoint,\n description: dto.description,\n agentId: dto.agentId,\n agent: dto.agent ?? null,\n prAdditions: dto.prAdditions,\n prDeletions: dto.prDeletions,\n prLintWarnings: dto.prLintWarnings,\n prMergedAt: dto.prMergedAt,\n fatigued: dto.fatigued,\n assignedUser: dto.assignedUser,\n reviewers: dto.reviewers,\n queuedByUserId: dto.queuedByUserId,\n queuedByUserName: dto.queuedByUserName,\n queuedUntil: dto.queuedUntil,\n branchLabel: dto.branchLabel,\n githubPRNumber: dto.githubPRNumber,\n githubPRUrl: dto.githubPRUrl,\n codespaceId: dto.codespaceId,\n codespaceUrl: dto.codespaceUrl,\n codespaceHostUrl: dto.codespaceHostUrl,\n codespaceStatus: dto.codespaceStatus,\n codespaceProvider: dto.codespaceProvider,\n identifying: dto.identifying,\n type: dto.type,\n source: dto.source,\n score: dto.score,\n fingerprint: dto.fingerprint,\n mergeQueuedByUserId: dto.mergeQueuedByUserId,\n codeReviewStatus: dto.codeReviewStatus,\n aiReviewedAt: dto.aiReviewedAt,\n humanReviewedAt: dto.humanReviewedAt,\n agentRunnerStatus: dto.agentRunnerStatus,\n lastHeartbeatAt: dto.lastHeartbeatAt,\n hasActivePod: dto.hasActivePod,\n activeSubscriptionKeyLabel: dto.activeSubscriptionKeyLabel,\n parentTaskId: dto.parentTaskId,\n ordinal: dto.ordinal,\n featureBranch: dto.featureBranch,\n isDuplicate: dto.isDuplicate,\n childTaskCount: dto.childTaskCount,\n childTaskDoneCount: dto.childTaskDoneCount,\n childStatusCounts: dto.childStatusCounts,\n aggregatedAdditions: dto.aggregatedAdditions,\n aggregatedDeletions: dto.aggregatedDeletions,\n releaseRiskSummary: dto.releaseRiskSummary,\n releaseStoryPointSummary: dto.releaseStoryPointSummary,\n chatId: dto.chatId,\n hasUnmetDependencies: dto.hasUnmetDependencies,\n createdAt: dto.createdAt,\n updatedAt: dto.updatedAt\n };\n}\n\n// src/utils/code-location.ts\nvar DEV_ENVIRONMENT = \"dev\";\nvar PROD_ENVIRONMENT = \"prod\";\nvar CODE_LOCATION_PHASES = [\n /** Merged to the dev branch, but no dev deploy has picked it up yet. */\n \"pending-dev\",\n /** A dev deploy carrying this card is in flight. */\n \"deploying-dev\",\n /** A dev deploy that includes this card has completed successfully. */\n \"in-dev\",\n /** A prod deploy carrying this card's release is in flight. */\n \"deploying-prod\",\n /** The card's code is live in production. */\n \"in-prod\"\n];\nvar PROMOTED_STATUSES = /* @__PURE__ */ new Set([\"ReviewLive\", \"Complete\"]);\nvar MERGED_STATUSES = /* @__PURE__ */ new Set([\"ReviewDev\", \"ReviewLive\", \"Complete\"]);\nfunction toMs(value) {\n if (!value) return null;\n const ms = new Date(value).getTime();\n return Number.isNaN(ms) ? null : ms;\n}\nfunction findReleaseRun(task, snapshot) {\n const releaseTaskId = task.isRelease ? task.id : task.releaseTaskId ?? null;\n if (!releaseTaskId) return null;\n return snapshot.releaseRuns.find((run) => run.releaseTaskId === releaseTaskId) ?? null;\n}\nfunction prodLocation(run) {\n const environment = run.environment || PROD_ENVIRONMENT;\n if (run.status !== \"completed\") {\n return { phase: \"deploying-prod\", environment, deploying: true };\n }\n if (run.conclusion !== \"success\") {\n return { phase: \"deploying-prod\", environment, deploying: true };\n }\n return { phase: \"in-prod\", environment, deploying: false };\n}\nfunction devLocation(mergedAtMs, snapshot) {\n const dev = snapshot.environments.find((env) => env.environment === DEV_ENVIRONMENT);\n const pending = {\n phase: \"pending-dev\",\n environment: DEV_ENVIRONMENT,\n deploying: false\n };\n if (!dev) return pending;\n const lastSuccessAt = toMs(dev.lastSuccess?.completedAt);\n if (lastSuccessAt !== null && lastSuccessAt >= mergedAtMs) {\n return { phase: \"in-dev\", environment: DEV_ENVIRONMENT, deploying: false };\n }\n const activeStartedAt = toMs(dev.active?.startedAt);\n if (dev.active && (activeStartedAt === null || activeStartedAt >= mergedAtMs)) {\n return { phase: \"deploying-dev\", environment: DEV_ENVIRONMENT, deploying: true };\n }\n return pending;\n}\nfunction resolveCodeLocation(task, snapshot) {\n if (!snapshot) return null;\n const promoted = PROMOTED_STATUSES.has(task.status);\n const merged = MERGED_STATUSES.has(task.status) && Boolean(task.prMergedAt);\n if (!promoted && !merged) return null;\n const releaseRun = findReleaseRun(task, snapshot);\n if (releaseRun) return prodLocation(releaseRun);\n if (promoted) {\n return { phase: \"in-prod\", environment: PROD_ENVIRONMENT, deploying: false };\n }\n const mergedAtMs = toMs(task.prMergedAt);\n if (mergedAtMs === null) return null;\n return devLocation(mergedAtMs, snapshot);\n}\n\n// src/utils/tag-path-match.ts\nfunction parseTagContextPaths(contextPaths) {\n if (!Array.isArray(contextPaths)) return [];\n const refs = [];\n for (const entry of contextPaths) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const { path, type } = entry;\n if (typeof path !== \"string\" || path.length === 0) continue;\n if (type !== \"rule\" && type !== \"doc\" && type !== \"file\" && type !== \"folder\") continue;\n refs.push({ path: normalizePath(path), type });\n }\n return refs;\n}\nfunction normalizePath(path) {\n return path.replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\nfunction refMatchesPath(ref, path) {\n if (path === ref.path) return true;\n return ref.type === \"folder\" && path.startsWith(`${ref.path}/`);\n}\nfunction matchTagsByPaths(paths, tags) {\n const uniquePaths = [...new Set(paths.map(normalizePath).filter(Boolean))];\n if (uniquePaths.length === 0) return [];\n const matches = [];\n for (const tag of tags) {\n const refs = parseTagContextPaths(tag.contextPaths);\n if (refs.length === 0) continue;\n const matched = uniquePaths.filter((path) => refs.some((ref) => refMatchesPath(ref, path)));\n if (matched.length > 0) {\n matches.push({ tagId: tag.id, tagName: tag.name, matchedPaths: matched });\n }\n }\n return matches.sort(\n (a, b) => b.matchedPaths.length - a.matchedPaths.length || a.tagName.localeCompare(b.tagName)\n );\n}\nvar REPO_PATH_PATTERN = /(?:^|[\\s`(\"'[])((?:apps|packages|scripts|docs|\\.claude|\\.github)\\/[A-Za-z0-9_@][A-Za-z0-9_@\\-./]*)/g;\nfunction extractRepoPaths(markdown) {\n const found = /* @__PURE__ */ new Set();\n for (const match of markdown.matchAll(REPO_PATH_PATTERN)) {\n const cleaned = match[1].replace(/[).,:;!?]+$/, \"\").replace(/\\/+$/, \"\");\n if (cleaned.includes(\"/\")) found.add(cleaned);\n }\n return [...found];\n}\n\n// src/utils/tag-snapshot-diff.ts\nfunction contextPathKey(link) {\n return [link.type, link.path, link.label ?? \"\"].join(\"|\");\n}\nfunction contextPathsEqual(a, b) {\n const left = (a ?? []).map(contextPathKey).sort();\n const right = (b ?? []).map(contextPathKey).sort();\n return left.length === right.length && left.every((value, i) => value === right[i]);\n}\nfunction idsEqual(a, b) {\n const left = [...a ?? []].sort();\n const right = [...b ?? []].sort();\n return left.length === right.length && left.every((value, i) => value === right[i]);\n}\nfunction tagSnapshotsEqual(before, after) {\n return before.name === after.name && before.color === after.color && (before.description ?? \"\") === (after.description ?? \"\") && (before.overview ?? \"\") === (after.overview ?? \"\") && (before.overviewPath ?? \"\") === (after.overviewPath ?? \"\") && before.ordinal === after.ordinal && contextPathsEqual(before.contextPaths, after.contextPaths) && idsEqual(before.parentTagIds, after.parentTagIds);\n}\nfunction renderContextLink(link) {\n const label = link.label ? [\" (\", link.label, \")\"].join(\"\") : \"\";\n return [\" \", link.type, \": \", link.path, label].join(\"\");\n}\nfunction renderContextPaths(links) {\n if (!links || links.length === 0) return \" (none)\";\n return links.map(renderContextLink).sort().join(\"\\n\");\n}\nfunction renderParents(ids, resolveName) {\n if (!ids || ids.length === 0) return \" (none)\";\n return ids.map((id) => [\" \", resolveName?.(id) ?? id].join(\"\")).sort().join(\"\\n\");\n}\nfunction tagSnapshotToText(snapshot, resolveName) {\n if (!snapshot) return \"\";\n return [\n [\"name: \", snapshot.name].join(\"\"),\n [\"color: \", snapshot.color].join(\"\"),\n [\"order: \", String(snapshot.ordinal)].join(\"\"),\n [\"description: \", snapshot.description ?? \"\"].join(\"\"),\n \"parents:\",\n renderParents(snapshot.parentTagIds, resolveName),\n \"context links:\",\n renderContextPaths(snapshot.contextPaths),\n [\"overview path: \", snapshot.overviewPath ?? \"\"].join(\"\"),\n \"overview:\",\n snapshot.overview ?? \"\",\n \"\"\n ].join(\"\\n\");\n}\n\n// src/utils/context-path-warnings.ts\nfunction buildRepoEntryTypeMap(entries) {\n const map = /* @__PURE__ */ new Map();\n for (const entry of entries) map.set(entry.path, entry.type);\n return map;\n}\nfunction findContextPathWarning(link, entryTypes, contentByPath) {\n const path = normalizeContextPath(link.path);\n if (!path) return null;\n if (CONTEXT_PATH_UNTRACKED_PREFIXES.some((prefix) => path.startsWith(prefix))) return null;\n const wantsDirectory = link.type === \"folder\";\n const entryType = entryTypes.get(path);\n if (!entryType) return \"notFound\";\n if (wantsDirectory && entryType !== \"tree\") return \"expectedFolder\";\n if (!wantsDirectory && entryType === \"tree\") return \"expectedFile\";\n const { locator, locatorType } = link;\n if (!locator || !locatorType || isPlaceholderLocator(locator)) return null;\n const content = contentByPath?.get(path) ?? null;\n if (content === null) return null;\n if (!locatorMatchesContent(content, locatorType, locator)) return \"locatorNotFound\";\n return null;\n}\nfunction findContextPathWarnings(links, entryTypes, contentByPath) {\n const warnings = [];\n for (const link of links) {\n const warning = findContextPathWarning(link, entryTypes, contentByPath);\n if (warning) {\n warnings.push({\n path: link.path,\n type: link.type,\n warning,\n ...warning === \"locatorNotFound\" && link.locator ? { locator: link.locator } : {}\n });\n }\n }\n return warnings;\n}\n\n// src/utils/tag-overview-source.ts\nfunction overviewSourceLink(overviewPath) {\n return { type: \"doc\", path: overviewPath };\n}\nfunction toIso(value) {\n if (value === null || value === void 0) return void 0;\n return typeof value === \"string\" ? value : value.toISOString();\n}\nfunction resolveTagOverview(row, checks) {\n if (!row.overviewPath) return { overview: row.overview ?? null, source: null };\n const sha = row.overviewFileSha ?? void 0;\n const syncedAt = toIso(row.overviewFileSyncedAt);\n if (row.overviewFileCache === null || row.overviewFileCache === void 0) {\n return {\n overview: row.overview ?? null,\n source: { state: \"pending\", ...sha === void 0 ? {} : { sha } }\n };\n }\n const verification = verificationForLink(overviewSourceLink(row.overviewPath), checks ?? null);\n return {\n overview: row.overviewFileCache,\n source: {\n state: verification.status === \"stale\" ? \"stale\" : \"ok\",\n ...sha === void 0 ? {} : { sha },\n ...syncedAt === void 0 ? {} : { syncedAt }\n }\n };\n}\nfunction hasEffectiveOverview(row, checks) {\n return (resolveTagOverview(row, checks).overview ?? \"\").trim().length > 0;\n}\n\n// src/utils/gcp-exceptional.ts\nvar EXCEPTIONAL_GCP_LOG_FILTER = \"(severity>=WARNING OR httpRequest.status>=400)\";\nfunction isExceptionalLogEntry(entry) {\n return [\"WARNING\", \"ERROR\", \"CRITICAL\", \"ALERT\", \"EMERGENCY\"].includes(entry.severity) || (entry.httpRequest?.status ?? 0) >= 400;\n}\nfunction exceptionalLogKind(entry) {\n return [\"ERROR\", \"CRITICAL\", \"ALERT\", \"EMERGENCY\"].includes(entry.severity) || (entry.httpRequest?.status ?? 0) >= 500 ? \"error\" : \"warning\";\n}\nfunction normalize(value) {\n return value.replace(/(?<=\\btrace=)[0-9a-f]+/gi, \":id\").replace(/[0-9a-f]{8,}/gi, \":id\").replace(/\\b\\d+\\b/g, \":n\").replace(/\\/\\d+(?=\\/|$)/g, \"/:id\").trim().toLowerCase();\n}\nfunction exceptionalLogSource(entry) {\n return entry.resource.service_name ?? entry.resource.pod_name ?? entry.resource.database_id ?? entry.resourceType ?? \"unknown\";\n}\nfunction normalizedSearchTerms(entry) {\n return normalize(entry.httpRequest?.url ?? entry.message).replace(/:[a-z]+/g, \" \").replace(/[^a-z0-9/_-]+/g, \" \").trim().replace(/\\s+/g, \" \");\n}\nfunction representativeFilter(entry) {\n const http = entry.httpRequest;\n const stableTerms = normalizedSearchTerms(entry).replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n const searchFilter = stableTerms ? `SEARCH(\"${stableTerms}\")` : void 0;\n if (http && (http.status ?? 0) >= 400) {\n const method = http.method?.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n return [\n `httpRequest.status=${http.status}`,\n method ? `httpRequest.requestMethod=\"${method}\"` : void 0,\n searchFilter\n ].filter(Boolean).join(\" AND \");\n }\n return [`severity=${entry.severity}`, searchFilter].filter(Boolean).join(\" AND \");\n}\nvar SUMMARY_MAX_CHARS = 200;\nfunction exceptionalLogSummary(entry) {\n const message = entry.message.trim();\n if (message) return message;\n const http = entry.httpRequest;\n if (http && (http.method || http.url || http.status)) {\n const target = [http.method, http.url].filter(Boolean).join(\" \");\n const httpLine = http.status ? [target, http.status].filter(Boolean).join(\" \\u2192 \") : target;\n if (httpLine) return httpLine.slice(0, SUMMARY_MAX_CHARS);\n }\n const payload = entry.payload?.replace(/\\s+/g, \" \").trim();\n if (payload) return payload.slice(0, SUMMARY_MAX_CHARS);\n return `${entry.severity} log entry from ${exceptionalLogSource(entry)}`;\n}\nfunction exceptionalLogSignature(entry) {\n const source = exceptionalLogSource(entry);\n const http = entry.httpRequest;\n return [\n source,\n exceptionalLogKind(entry),\n http?.method ?? \"\",\n http?.status ?? \"\",\n normalize(http?.url ?? \"\"),\n normalize(entry.message)\n ].join(\"|\");\n}\nfunction groupExceptionalLogEntries(entries, options) {\n const grouped = /* @__PURE__ */ new Map();\n let errors = 0;\n let warnings = 0;\n for (const entry of entries) {\n if (!isExceptionalLogEntry(entry)) continue;\n const kind = exceptionalLogKind(entry);\n if (kind === \"error\") errors += 1;\n else warnings += 1;\n const signature = exceptionalLogSignature(entry);\n const existing = grouped.get(signature);\n if (existing) {\n existing.count += 1;\n if (entry.timestamp < existing.firstSeen) existing.firstSeen = entry.timestamp;\n if (entry.timestamp > existing.lastSeen) existing.lastSeen = entry.timestamp;\n existing.samples.push(entry);\n continue;\n }\n grouped.set(signature, {\n id: signature,\n env: options.env,\n source: exceptionalLogSource(entry),\n kind,\n count: 1,\n firstSeen: entry.timestamp,\n lastSeen: entry.timestamp,\n summary: exceptionalLogSummary(entry),\n representativeFilter: representativeFilter(entry),\n samples: [entry]\n });\n }\n const groups = [...grouped.values()];\n for (const group of groups) {\n group.samples.sort((left, right) => right.timestamp.localeCompare(left.timestamp));\n group.samples = group.samples.slice(0, options.sampleLimit);\n }\n groups.sort(\n (left, right) => (left.kind === right.kind ? 0 : left.kind === \"error\" ? -1 : 1) || right.lastSeen.localeCompare(left.lastSeen) || right.count - left.count\n );\n return { errors, warnings, groups };\n}\n\n// src/utils/grafana-links.ts\nfunction buildGrafanaExploreUrl(params) {\n const base = params.baseUrl.replace(/\\/+$/, \"\");\n const panes = {\n a: {\n datasource: params.datasourceUid,\n queries: [\n {\n refId: \"A\",\n expr: params.logql,\n datasource: { type: \"loki\", uid: params.datasourceUid }\n }\n ],\n range: { from: String(params.fromMs), to: String(params.toMs) }\n }\n };\n return `${base}/explore?schemaVersion=1&panes=${encodeURIComponent(JSON.stringify(panes))}&orgId=1`;\n}\n\n// src/utils/slack-links.ts\nfunction buildSlackThreadUrl({ channelId, messageTs, teamId }) {\n if (!channelId || !messageTs) return null;\n const ts = messageTs.replace(\".\", \"\");\n const base = `https://slack.com/archives/${channelId}/p${ts}`;\n return teamId ? `${base}?team=${teamId}` : base;\n}\n\n// src/utils/discord-links.ts\nfunction buildDiscordThreadUrl({ guildId, threadId }) {\n if (!guildId || !threadId) return null;\n return `https://discord.com/channels/${guildId}/${threadId}`;\n}\nexport {\n ACCESS_LEVEL_RANK,\n ACHIEVEMENT_IMAGE_POSITIONS,\n ACHIEVEMENT_PATTERNS,\n ACHIEVEMENT_RARITIES,\n ACHIEVEMENT_RARITY_KEYS,\n ACHIEVEMENT_STAT_ICON_KEYS,\n ACTIVE_WORK_STATUSES,\n ACTIVITY_KIND_FILTERS,\n ADMIN_CREATE_SERVICES,\n AGENT_CHAT_HISTORY_FETCH_LIMIT,\n AGENT_KEY_KINDS,\n AGENT_MILESTONE_SLUGS,\n AGENT_PROVIDERS,\n AGENT_STATUS_REASON_USER_QUESTION,\n ALLOWED_FILE_MIME_TYPES,\n ANTHROPIC_CATALOG,\n AUTOPILOT_RATIO_MAX,\n AUTOPILOT_RATIO_MIN,\n AddDependencyRequestSchema,\n AddProjectTaskDependencyRequestSchema,\n AddProjectTaskReviewerRequestSchema,\n AddTasksToProjectReleaseRequestSchema,\n AgentEventSchema,\n AgentHeartbeatSchema,\n AgentQuestionOptionSchema,\n AgentQuestionSchema,\n AnswerAgentQuestionRequestSchema,\n ApproveAndMergePRRequestSchema,\n ApproveManualTestRequestSchema,\n ApproveProjectManualTestRequestSchema,\n ApproveProjectMergePRRequestSchema,\n AskUserQuestionRequestSchema,\n BUILDER_STREAM_ID,\n CARD_DESCRIPTION_FIELD_HINT,\n CARD_DESCRIPTION_LIMIT_MESSAGE,\n CARD_DESCRIPTION_MAX,\n CARD_TYPE_STATUSES,\n CARD_TYPE_VALUES,\n CHAT_PROVIDER_IDS,\n CODESPACE_BOOT_STEPS,\n CODESPACE_SESSION_ACTIVE_RUNNER_STATUSES,\n CODE_LOCATION_PHASES,\n COMPUTE_DISABLED_REASON,\n COMPUTE_PROVIDER_IDS,\n CONTEXT_LINK_LOCATOR_MAX,\n CONTEXT_PATH_UNTRACKED_PREFIXES,\n CREATED_DESC_STATUSES,\n CRITICAL_AUTOMATED_SOURCES,\n CancelTaskQueuedMessageRequestSchema,\n ClearAgentTodosRequestSchema,\n ConfirmFileUploadRequestSchema,\n ConfirmProjectFileUploadRequestSchema,\n ConnectAgentRequestSchema,\n CreateFollowUpTaskRequestSchema,\n CreatePRInputSchema,\n CreatePRResponseSchema,\n CreateProjectDriveFileRequestSchema,\n CreateProjectDriveFolderRequestSchema,\n CreateProjectPullRequestRequestSchema,\n CreateProjectReleaseRequestSchema,\n CreateProjectSubtaskRequestSchema,\n CreateProjectSuggestionRequestSchema,\n CreateProjectTagRequestSchema,\n CreateProjectTaskRequestSchema,\n CreatePullRequestRequestSchema,\n CreateSubtaskRequestSchema,\n CreateSuggestionRequestSchema,\n CycleCodingAgentKeyRequestSchema,\n DEFAULT_CHAT_PROVIDER,\n DEFAULT_COMPUTE_PROVIDER,\n DEFAULT_HAIKU_MODEL,\n DEFAULT_MODEL_PROVIDER,\n DEFAULT_OPUS_MODEL,\n DEFAULT_POD_SIZE,\n DEFAULT_RISK_LEVELS,\n DEFAULT_SONNET_MODEL,\n DEFAULT_TASK_STATUS_COLOR,\n DEPLOYMENT_TARGET_ENVIRONMENTS,\n DEPLOYMENT_TARGET_PROVIDERS,\n DEV_ENVIRONMENT,\n DRIVE_MAX_CONTENT_CHARS,\n DeleteProjectDriveFileRequestSchema,\n DeleteProjectSubtaskRequestSchema,\n DeleteSubtaskRequestSchema,\n DeleteSubtaskResponseSchema,\n DeleteTaskAuditRequestSchema,\n DiscoveredPortSchema,\n EMBEDDABLE_IMAGE_TYPES,\n EXCEPTIONAL_GCP_LOG_FILTER,\n EXTERNAL_AGENT_MESSAGE_SOURCE,\n EditManualTestRequestSchema,\n EditProjectManualTestRequestSchema,\n EmitAgentEventRequestSchema,\n EndReviewSessionRequestSchema,\n FABLE_MODEL,\n FlushSingleQueuedMessageRequestSchema,\n FlushTaskQueueRequestSchema,\n GA_TRAFFIC_RANGE_DAYS,\n GCP_ENVS,\n GRAFANA_ENVS,\n GRAFANA_LOG_LEVELS,\n GenerateTaskIconRequestSchema,\n GetActiveAuditSessionsRequestSchema,\n GetActivePtySessionRequestSchema,\n GetAgentStatusRequestSchema,\n GetChatMessagesRequestSchema,\n GetCliHistoryRequestSchema,\n GetConnectionContextRequestSchema,\n GetDependenciesRequestSchema,\n GetProjectAttachmentRequestSchema,\n GetProjectAvailableTuisRequestSchema,\n GetProjectConnectUrlsRequestSchema,\n GetProjectOnboardingStatusRequestSchema,\n GetProjectOnboardingStepRequestSchema,\n GetProjectSummaryRequestSchema,\n GetProjectTagRequestSchema,\n GetProjectTaskChatRequestSchema,\n GetProjectTaskCliRequestSchema,\n GetProjectTaskDependenciesRequestSchema,\n GetProjectTaskRequestSchema,\n GetProjectTaskSessionsRequestSchema,\n GetPtyStreamEndpointRequestSchema,\n GetSuggestionsRequestSchema,\n GetTaskAuditAggregatesRequestSchema,\n GetTaskAuditRequestSchema,\n GetTaskAuditsRequestSchema,\n GetTaskContextRequestSchema,\n GetTaskFileRequestSchema,\n GetTaskFilesRequestSchema,\n GetTaskPropertiesRequestSchema,\n GetTaskRequestSchema,\n GetUiCliHistoryRequestSchema,\n HIDDEN_REPORT_STATUSES,\n HUMAN_PROSE_WRITING_STYLE,\n HandoffToImplementerRequestSchema,\n HeartbeatRequestSchema,\n HeartbeatResponseSchema,\n IDENTIFIED_WORK_STATUSES,\n IDLE_HEARTBEAT_MS,\n KnownAgentEventSchema,\n LEVELS_PER_BAND,\n LOCAL_ARM64_REGISTRY,\n ListAccessibleProjectsRequestSchema,\n ListAccessibleSubprojectsRequestSchema,\n ListActivePtySessionsRequestSchema,\n ListIconsRequestSchema,\n ListKeysToProbeRequestSchema,\n ListManualTestsRequestSchema,\n ListMyLiveSessionsAcrossProjectsRequestSchema,\n ListMyLiveSessionsRequestSchema,\n ListProjectDriveFilesRequestSchema,\n ListProjectManualTestsRequestSchema,\n ListProjectMembersRequestSchema,\n ListProjectSessionGroupsRequestSchema,\n ListProjectSubtasksRequestSchema,\n ListProjectTagAttachmentsRequestSchema,\n ListProjectTagsRequestSchema,\n ListProjectTaskFilesRequestSchema,\n ListProjectTasksRequestSchema,\n ListSubtasksRequestSchema,\n MAX_ACHIEVEMENT_DESCRIPTION_LENGTH,\n MAX_ACHIEVEMENT_STATS,\n MAX_ACHIEVEMENT_STAT_LABEL_LENGTH,\n MAX_ACHIEVEMENT_STAT_VALUE_LENGTH,\n MAX_ACHIEVEMENT_TITLE_LENGTH,\n MAX_AGENT_FLAVOR_LENGTH,\n MAX_DISCOVERED_PORTS,\n MAX_FILE_SIZE_BYTES,\n MAX_FILE_TAGS,\n MAX_FILE_TAG_LENGTH,\n MAX_GATE_LEVEL,\n MCP_TOOL_REGISTRY,\n MENTION_TOKEN_REGEX,\n MESSAGE_KINDS,\n MIN_CONTRIBUTOR_LEVEL,\n MIRRORABLE_SIDECARS,\n MODEL_PROVIDERS,\n MODEL_WIRE_FORMATS,\n MarkInitialPromptSubmittedRequestSchema,\n MoveProjectCardRequestSchema,\n NotifyAgentVersionRequestSchema,\n OPS_ENVIRONMENTS,\n OPS_TAB_REGISTRY,\n PM_CHAT_HISTORY_LIMIT,\n POD_REPORTABLE_BOOT_STEPS,\n POD_SIZE_NAMES,\n POD_SIZE_PRESETS,\n PRESTIGE_TIERS,\n PREVIEW_PORT_DENY_LIST,\n PREVIOUS_OPUS_MODEL,\n PREVIOUS_SONNET_MODEL,\n PRE_BUILD_TASK_STATUSES,\n PROD_ENVIRONMENT,\n PROJECT_FUNCTION_DEFAULTS,\n PROJECT_FUNCTION_IDS,\n PROJECT_TIMEZONE,\n PR_PRODUCING_AGENT_MODES,\n PTY_STREAM_PORT_ATTEMPTS,\n PTY_STREAM_PORT_BASE,\n PickFaIconRequestSchema,\n PostAgentMessageRequestSchema,\n PostChildChatMessageRequestSchema,\n PostToChatInputSchema,\n PostToChatRequestSchema,\n PostToChatResponseSchema,\n PostToProjectChatRequestSchema,\n PostToProjectTaskChatRequestSchema,\n ProjectTagContextPathSchema,\n PtyAttachRequestSchema,\n PtyChatAttachRequestSchema,\n PtyChatEventPayloadSchema,\n PtyChatEventRequestSchema,\n PtyEndedRequestSchema,\n PtyInputRequestSchema,\n PtyOutputRequestSchema,\n PtyResizeRequestSchema,\n PtyStreamFrameReader,\n PublishReviewGuideRequestSchema,\n QUEUE_JOBS_PAGE_SIZE,\n QUEUE_JOB_STATES,\n QueryManualTestsRequestSchema,\n QueryProjectGcpLogsRequestSchema,\n QueryProjectGrafanaLogsRequestSchema,\n QueryProjectManualTestsRequestSchema,\n RBAC_SA_NAMESPACE_PLACEHOLDER,\n RBAC_SA_NAME_PLACEHOLDER,\n REPORT_STATUS_TO_LANE,\n REPORT_XP_RATE,\n REPOSITORY_PROVIDER_IDS,\n REVIEWER_STREAM_ID,\n REVIEW_XP_RATE,\n RISK_LEVELS,\n RISK_RANK,\n ReadProjectDriveFileRequestSchema,\n RefreshCodingAgentKeyUsageRequestSchema,\n RefreshGithubTokenRequestSchema,\n RefreshGithubTokenResponseSchema,\n RejectManualTestRequestSchema,\n RejectProjectManualTestRequestSchema,\n RemoveDependencyRequestSchema,\n RemoveManualTestRequestSchema,\n RemoveProjectManualTestRequestSchema,\n RemoveProjectTaskDependencyRequestSchema,\n RemoveProjectTaskReviewerRequestSchema,\n ReportAgentStatusRequestSchema,\n ReportBootMilestoneRequestSchema,\n ReportDiscoveredPortsRequestSchema,\n ReportPtyStreamRequestSchema,\n ReportReviewSpawnFailureRequestSchema,\n ReportSessionSpawnFailureRequestSchema,\n ReportTaskAuditResultRequestSchema,\n RequestFileUploadRequestSchema,\n RequestProjectFileUploadRequestSchema,\n RequestWorkspaceRecycleRequestSchema,\n ResumeAdhocSessionRequestSchema,\n ReviewGuideContentSchema,\n ReviewGuideFileReferenceSchema,\n ReviewGuideSectionSchema,\n SERVICE_DEFINITIONS,\n SP_XP_RATE,\n STATEFUL_BAKE_DEPS,\n STRANDED_RUNNER_STATUSES,\n SUPPORTED_CLAUDESPACE_DEPS,\n SUPPORTED_WIRE_FORMATS,\n SearchFaIconsRequestSchema,\n SearchProjectTasksRequestSchema,\n SendSoftStopRequestSchema,\n SessionStartRequestSchema,\n SessionStartResponseSchema,\n SessionStopRequestSchema,\n SessionStopResponseSchema,\n SetManualTestsRequestSchema,\n SetProjectFileTagsRequestSchema,\n SetProjectManualTestsRequestSchema,\n SpawnTaskSessionRequestSchema,\n StartAdhocSessionRequestSchema,\n StartChildCloudBuildRequestSchema,\n StartCodeReviewRequestSchema,\n StartProjectBuildRequestSchema,\n StartProjectWorkspaceRequestSchema,\n StartTagAuditRequestSchema,\n StartTaskAuditRequestSchema,\n StopAdhocSessionRequestSchema,\n StopChildBuildRequestSchema,\n StopCodeReviewRequestSchema,\n StopProjectBuildRequestSchema,\n StopProjectWorkspaceRequestSchema,\n StopTaskSessionRequestSchema,\n StoreSessionIdRequestSchema,\n StoreSessionIdResponseSchema,\n SubmitCodeReviewResultRequestSchema,\n TAG_DESCRIPTION_MAX,\n TAG_OVERVIEW_MAX,\n TAG_REASON_MAX,\n TASK_CHAT_HISTORY_LIMIT,\n TASK_LESS_WORKSPACE_PURPOSES,\n TASK_STATUS_COLORS,\n TASK_STATUS_ORDER,\n TERMINAL_TASK_STATUSES,\n TOP_PRESTIGE_BAND,\n TRIAGE_INCLUDE_VALUES,\n TUI_KINDS,\n TransitionProjectTaskStatusRequestSchema,\n TriggerIdentificationRequestSchema,\n UpdateChildStatusRequestSchema,\n UpdateProjectDriveFileRequestSchema,\n UpdateProjectSubtaskRequestSchema,\n UpdateProjectTagRequestSchema,\n UpdateProjectTaskRequestSchema,\n UpdateSubtaskRequestSchema,\n UpdateTaskFieldsRequestSchema,\n UpdateTaskPropertiesRequestSchema,\n UpdateTaskStatusRequestSchema,\n UpdateTaskStatusResponseSchema,\n V3_BOOT_STEPS,\n V3_BOOT_STEP_KEYS,\n VerifyConnectionRequestSchema,\n VoteProjectSuggestionRequestSchema,\n VoteSuggestionRequestSchema,\n WORKSPACE_BACKENDS,\n WORKSPACE_DESIRED_STATES,\n WORKSPACE_OBSERVED_STATES,\n WORKSPACE_POD_PHASES,\n WORKSPACE_PURPOSES,\n WORKSPACE_SESSION_MODES,\n WORKSPACE_SESSION_ROLES,\n WORKSPACE_SESSION_STATUSES,\n WORKSPACE_TUNNEL_HEARTBEAT_MS,\n accessLevelRank,\n actionsPrebakeRegistrySchema,\n adminSupportsCreate,\n applyAgentFlavor,\n applyJsonMergePatch,\n availableTabsForEnvDTO,\n availableTabsFromConfigDTO,\n bootStepsForBackend,\n bucketDateKey,\n buildDiscordThreadUrl,\n buildGrafanaExploreUrl,\n buildMentionKey,\n buildOpsConfigDTO,\n buildPersonalClusterRbacManifest,\n buildRepoEntryTypeMap,\n buildSlackThreadUrl,\n canGrantLevel,\n canModifyMember,\n canonicalizeTagMentions,\n chatProviderExclusiveReason,\n checkpointDigestRefSchema,\n checkpointKeySchema,\n clampDescription,\n clampDescriptionField,\n clearOpsEnvFields,\n coerceProjectSettings,\n computeBootProgress,\n computeMemoryBounds,\n computePodRatio,\n computeTotalXp,\n contextLinkCheckKey,\n conveyorCapabilitySchema,\n createAgentSessionRoom,\n createProjectRoom,\n deriveConnectionState,\n deriveMessageSource,\n effectiveMessageKind,\n encodePtyStreamFrame,\n exceptionalLogKind,\n exceptionalLogSignature,\n exceptionalLogSummary,\n extractRepoPaths,\n extractTestTitles,\n findContextPathWarning,\n findContextPathWarnings,\n forgeProviderName,\n formatCompactNumber,\n formatCompactSigned,\n formatCompactUsd,\n formatHeartbeatAge,\n formatModelId,\n generateBucketRange,\n generateDateRange,\n generateHourRange,\n generateWeekRange,\n getCatalogModelLabel,\n getStreamMentionTarget,\n getStreamMentionTargetFromKeys,\n getToolsByCategory,\n groupExceptionalLogEntries,\n hasEffectiveOverview,\n hasForcePrefix,\n hasMentionToken,\n hasTagMentionToken,\n hasTaskPlan,\n isActiveWorkStatus,\n isAllowablePreviewPort,\n isAwaitingUserInput,\n isBootStepKey,\n isComputeDisabled,\n isCreatedDescStatus,\n isCuid,\n isEmbeddableFile,\n isExceptionalLogEntry,\n isHigherRisk,\n isHourlyRange,\n isIdentifiedWorkStatus,\n isLocalArm64Bake,\n isModelProvider,\n isOpsConfigured,\n isOpsEnvConfigured,\n isOpsEnvConfiguredDTO,\n isPlaceholderLocator,\n isPlainProjectSettings,\n isPodReportableBootStep,\n isPodSizeName,\n isPrProducingMode,\n isPtyStreamPort,\n isSupportedWireFormat,\n isValidAutopilotConfig,\n judgeContextLink,\n levelFromXp,\n linkNeedsContent,\n locatorMatchesContent,\n matchTagsByPaths,\n meetsContributorLevel,\n mergeOpsEnvSettings,\n messageMatchesActivityFilters,\n modelSupportsEffort,\n normalizeContextPath,\n normalizeReportStatus,\n normalizeTaskStatus,\n overviewSourceLink,\n parseContextPathChecks,\n parseMentions,\n parseModelId,\n parsePtyStreamFrame,\n parseTagContextLinks,\n parseTagContextPaths,\n pickPreferredPreviewPort,\n poolNamespaceForProject,\n prestigeBandForLevel,\n prestigeFromXp,\n prestigeTierForBand,\n projectCheckpointSettingsSchema,\n replaceMentionTokens,\n requiredContributorLevel,\n resolveAgentTrigger,\n resolveAllowedPreviewPorts,\n resolveAvailableOpsTabs,\n resolveAvailableOpsTabsForEnv,\n resolveChatProvider,\n resolveCodeLocation,\n resolveCodeReviewMode,\n resolveComputeProvider,\n resolveForgeSettings,\n resolveForgejoConnectionSettings,\n resolveGcpEnvResources,\n resolveGoogleAnalyticsSettings,\n resolveGrafanaSettings,\n resolveMaxOpenPrs,\n resolveMentions,\n resolveOpsEnv,\n resolveOpsSettings,\n resolveProjectCheckpointSettings,\n resolveProjectFunctionConfig,\n resolveStatDateRange,\n resolveStatGranularity,\n resolveTagOverview,\n resolveTriageSettings,\n resolveVerifiedLinksPrCheck,\n riskFromReviewSeverities,\n riskLevelForValue,\n riskLevelSchema,\n riskRank,\n sanitizeBootTimeline,\n sanitizeDiscoveredPorts,\n sanitizeSessionPreviewPorts,\n serializeMention,\n serviceRoom,\n setOpsReadOnly,\n sidecarRequestTotals,\n stripForcePrefix,\n stripMentionTokens,\n stripStreamMentionText,\n summarizeBootEstimates,\n summarizeReportBody,\n tagSnapshotToText,\n tagSnapshotsEqual,\n taskStatusColor,\n taskStatusColorInt,\n toCardFromTaskDTO,\n toContributorLevel,\n todayInProjectTZ,\n userRoom,\n validateElasticsearchUrl,\n validateRedisUrl,\n validateStatusForType,\n verificationForLink,\n weekStartKey,\n withLinkVerification,\n xpToReachLevel,\n zenWireFormat\n};\n","import type { AgentMode, RunnerMode } from \"@project/shared\";\n\n// ── Mode action types ──────────────────────────────────────────────────────\n\nexport type ModeAction =\n | { type: \"noop\" }\n | { type: \"restart_query\"; newMode: AgentMode }\n | { type: \"soft_stop\" }\n | { type: \"start_auto\" };\n\n// ── Task context subset needed by ModeController ───────────────────────────\n\nexport interface ModeTaskContext {\n status: string;\n plan: string | null;\n storyPointId: string | null;\n isParentTask?: boolean;\n model: string;\n builderModel?: string | null;\n githubPRUrl?: string | null;\n}\n\n// ── ModeController: pure state machine with no I/O ─────────────────────────\n\nexport class ModeController {\n private _mode: AgentMode;\n private _hasExitedPlanMode = false;\n private _pendingModeRestart = false;\n private _runnerMode: RunnerMode;\n private _isAuto: boolean;\n\n constructor(initialMode: AgentMode, runnerMode: RunnerMode = \"task\", isAuto = false) {\n this._mode = initialMode;\n this._runnerMode = runnerMode;\n this._isAuto = isAuto;\n }\n\n // ── Getters ────────────────────────────────────────────────────────\n\n get mode(): AgentMode {\n return this._mode;\n }\n\n get isAuto(): boolean {\n return this._isAuto;\n }\n\n get hasExitedPlanMode(): boolean {\n return this._hasExitedPlanMode;\n }\n\n set hasExitedPlanMode(val: boolean) {\n this._hasExitedPlanMode = val;\n }\n\n get pendingModeRestart(): boolean {\n return this._pendingModeRestart;\n }\n\n set pendingModeRestart(val: boolean) {\n this._pendingModeRestart = val;\n }\n\n /** Effective mode accounting for PM/task defaults */\n get effectiveMode(): AgentMode {\n if (this._mode) return this._mode;\n if (this._runnerMode === \"pm\") {\n return this._isAuto ? \"auto\" : \"discovery\";\n }\n return \"building\";\n }\n\n get isReadOnly(): boolean {\n const m = this.effectiveMode;\n if ([\"discovery\", \"help\"].includes(m)) return true;\n return m === \"auto\" && !this._hasExitedPlanMode;\n }\n\n get isAutoPlanning(): boolean {\n return this.effectiveMode === \"auto\" && !this._hasExitedPlanMode;\n }\n\n get isBuildCapable(): boolean {\n const m = this.effectiveMode;\n return (\n m === \"building\" ||\n m === \"review\" ||\n m === \"chat\" ||\n (m === \"auto\" && this._hasExitedPlanMode)\n );\n }\n\n /**\n * Apply authoritative mode from the server's task context.\n * Called after getTaskContext to override env-var defaults with the\n * actual task state — ensures pods that launch without CONVEYOR_AGENT_MODE\n * still get the correct mode.\n */\n applyServerMode(agentMode: AgentMode | null | undefined, isAuto: boolean | undefined): void {\n if (agentMode) {\n this._mode = agentMode;\n this._isAuto = agentMode === \"auto\" || !!isAuto;\n } else if (isAuto !== undefined) {\n this._isAuto = isAuto;\n if (isAuto && this._runnerMode === \"pm\" && !this._mode) {\n this._mode = \"auto\";\n }\n }\n\n // Safety net: discovery + isAuto means the server didn't set agentMode correctly\n if (this._isAuto && this._mode === \"discovery\") {\n this._mode = \"auto\";\n }\n }\n\n // ── Mode resolution ────────────────────────────────────────────────\n\n /** Resolve the initial mode based on task context */\n resolveInitialMode(context: ModeTaskContext): AgentMode {\n // Code-review runner maps to unified review mode\n if (this._runnerMode === \"code-review\") {\n this._mode = \"review\";\n return this._mode;\n }\n\n // Auto mode always bypasses planning: the agent boots straight into\n // building (--dangerously-skip-permissions) and posts its plan to the\n // card before writing code. Use discovery for a human-gated plan turn.\n if (this._mode === \"auto\" && this.canBypassPlanning(context)) {\n this.transitionToBuilding(context);\n return this._mode;\n }\n\n return this._mode;\n }\n\n /**\n * Auto mode always bypasses the plan turn: resolveInitialMode calls\n * transitionToBuilding() at boot, so the agent runs with\n * `--dangerously-skip-permissions` from turn 1. The prompts require it to\n * post its plan to the card (via update_task_plan) before writing code —\n * a record for the team, never an approval gate. Use discovery mode for a\n * plan turn that stops for human approval. Non-auto modes never bypass.\n */\n canBypassPlanning(_context: ModeTaskContext): boolean {\n return this._mode === \"auto\";\n }\n\n // ── Mode transitions ───────────────────────────────────────────────\n\n /** Handle mode change from server */\n handleModeChange(newMode: AgentMode, _context?: ModeTaskContext | null): ModeAction {\n if (newMode === this._mode) return { type: \"noop\" };\n\n // Task runners can transition to review mode (same-box code review)\n if (this._runnerMode === \"task\" && newMode === \"review\") {\n this._mode = newMode;\n return { type: \"restart_query\", newMode: \"review\" };\n }\n\n // Task runners can transition to building mode (server-side auto-advancement)\n if (this._runnerMode === \"task\" && newMode === \"building\") {\n this._mode = newMode;\n this._isAuto = true;\n this._hasExitedPlanMode = true;\n return { type: \"restart_query\", newMode: \"building\" };\n }\n\n // Task runners can transition to auto mode (e.g., Build button after\n // discovery). Auto has no plan turn — build immediately; the plan is\n // documented into the card as the agent works.\n if (this._runnerMode === \"task\" && newMode === \"auto\") {\n this._mode = newMode;\n this._isAuto = true;\n this._hasExitedPlanMode = true;\n return { type: \"restart_query\", newMode: \"auto\" };\n }\n\n // Already building in auto mode — server confirmed via wakeAgentForBuilding.\n // Update mode label but don't restart the running query.\n if (this._mode === \"auto\" && this._hasExitedPlanMode && newMode === \"building\") {\n this._mode = newMode;\n return { type: \"noop\" };\n }\n\n if (this._runnerMode !== \"pm\") return { type: \"noop\" };\n\n this._mode = newMode;\n this.updateExitedPlanModeFlag(newMode);\n\n if (this.isBuildCapable) {\n return { type: \"start_auto\" };\n }\n return { type: \"noop\" };\n }\n\n /** Handle ExitPlanMode call from the agent */\n handleExitPlanMode(context: ModeTaskContext): ModeAction {\n if (this._hasExitedPlanMode) return { type: \"noop\" };\n this.transitionToBuilding(context);\n this._pendingModeRestart = true;\n return { type: \"restart_query\", newMode: this._mode };\n }\n\n /** Check if pack runner behavior should be used */\n isPackRunner(context: ModeTaskContext): boolean {\n return !!context.isParentTask;\n }\n\n // ── Internal helpers ───────────────────────────────────────────────\n\n private transitionToBuilding(context: ModeTaskContext): void {\n this._hasExitedPlanMode = true;\n this._mode = context.isParentTask ? \"review\" : \"building\";\n }\n\n private updateExitedPlanModeFlag(newMode: AgentMode): void {\n if (newMode === \"building\") {\n this._hasExitedPlanMode = true;\n }\n // For auto mode, we can't set the flag without context — it gets\n // set during context fetch or when ExitPlanMode is called\n }\n}\n","// ── Configuration ──────────────────────────────────────────────────────────\n\nexport interface LifecycleConfig {\n /** Idle timeout before the agent stops (default: 30 min) */\n idleTimeoutMs: number;\n /** Dormant timeout — bound on dormant-after-completed wait (default: 60 min).\n * Defense-in-depth: the server-side polling is supposed to shut us down,\n * but if it regresses, the agent shuts itself down here. */\n dormantTimeoutMs: number;\n /** Heartbeat interval (default: 30s) */\n heartbeatIntervalMs: number;\n /** Token refresh interval (default: 45 min — before 1h GitHub token expiry) */\n tokenRefreshIntervalMs: number;\n /** Periodic WIP git flush interval (default: 2 min). Covers ungraceful\n * pod termination (OOMKilled, node eviction) where preStop doesn't run.\n * Set to `0` to disable the timer entirely — used for environments with\n * persistent state (local, workspace, GitHub Codespaces) that don't lose\n * in-flight work on a crash. */\n gitFlushIntervalMs: number;\n /** Claude key usage sample interval (default: 5 min). Polls the Anthropic\n * OAuth usage endpoint and reports session/weekly rate-limit utilization for\n * the running subscription key. Deliberately NOT the heartbeat cadence — the\n * endpoint is rate-limited. Set to `0` to disable the timer entirely. */\n usageSampleIntervalMs: number;\n /** Delay before the FIRST usage sample (default: 30s). The sample spawns a\n * full `claude -p \"/usage\"` subprocess; sampling immediately at startup put\n * that CPU cost inside the boot-critical window on the throttled controller\n * container. Usage freshness 30s later costs nothing. */\n usageSampleInitialDelayMs: number;\n}\n\nexport interface LifecycleCallbacks {\n onHeartbeat: () => void;\n onIdleTimeout: () => void;\n onDormantTimeout: () => void;\n onTokenRefresh: () => void;\n onGitFlush: () => void;\n onUsageSample: () => void;\n}\n\n// ── Default configuration ──────────────────────────────────────────────────\n\n/** 30 min idle, 60 min dormant, 30s heartbeat, 45 min token refresh, 2 min git flush, 5 min usage sample */\nexport const DEFAULT_LIFECYCLE_CONFIG: LifecycleConfig = {\n idleTimeoutMs: 30 * 60 * 1000,\n dormantTimeoutMs: 60 * 60 * 1000,\n heartbeatIntervalMs: 30_000,\n tokenRefreshIntervalMs: 45 * 60 * 1000,\n gitFlushIntervalMs: 2 * 60 * 1000,\n usageSampleIntervalMs: 5 * 60 * 1000,\n usageSampleInitialDelayMs: 30_000,\n};\n\n// ── Lifecycle: timer management for idle/heartbeat ───────────────────────\n\nexport class Lifecycle {\n readonly config: LifecycleConfig;\n private readonly callbacks: LifecycleCallbacks;\n\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private tokenRefreshTimer: ReturnType<typeof setInterval> | null = null;\n private idleTimer: ReturnType<typeof setTimeout> | null = null;\n private idleCheckInterval: ReturnType<typeof setInterval> | null = null;\n private dormantTimer: ReturnType<typeof setTimeout> | null = null;\n private gitFlushTimer: ReturnType<typeof setInterval> | null = null;\n private usageSampleTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(config: LifecycleConfig, callbacks: LifecycleCallbacks) {\n this.config = config;\n this.callbacks = callbacks;\n }\n\n // ── Heartbeat ──────────────────────────────────────────────────────\n\n startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.callbacks.onHeartbeat();\n }, this.config.heartbeatIntervalMs);\n }\n\n stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n // ── Token refresh ─────────────────────────────────────────────────\n\n startTokenRefresh(): void {\n this.stopTokenRefresh();\n // Immediately refresh to ensure we have a fresh token at startup\n this.callbacks.onTokenRefresh();\n this.tokenRefreshTimer = setInterval(() => {\n this.callbacks.onTokenRefresh();\n }, this.config.tokenRefreshIntervalMs);\n }\n\n stopTokenRefresh(): void {\n if (this.tokenRefreshTimer) {\n clearInterval(this.tokenRefreshTimer);\n this.tokenRefreshTimer = null;\n }\n }\n\n // ── Periodic git flush ────────────────────────────────────────────\n\n startGitFlush(): void {\n this.stopGitFlush();\n if (this.config.gitFlushIntervalMs <= 0) return;\n this.gitFlushTimer = setInterval(() => {\n this.callbacks.onGitFlush();\n }, this.config.gitFlushIntervalMs);\n }\n\n stopGitFlush(): void {\n if (this.gitFlushTimer) {\n clearInterval(this.gitFlushTimer);\n this.gitFlushTimer = null;\n }\n }\n\n // ── Claude key usage sampling ─────────────────────────────────────\n\n startUsageSample(): void {\n this.stopUsageSample();\n if (this.config.usageSampleIntervalMs <= 0) return;\n // First sample after a short delay — NOT immediately: the sample spawns a\n // `claude -p \"/usage\"` subprocess, and doing that at startup raced the\n // boot-critical path for CPU. Then on the interval.\n this.usageSampleTimer = setTimeout(() => {\n this.callbacks.onUsageSample();\n this.usageSampleTimer = setInterval(() => {\n this.callbacks.onUsageSample();\n }, this.config.usageSampleIntervalMs);\n }, this.config.usageSampleInitialDelayMs);\n }\n\n stopUsageSample(): void {\n if (this.usageSampleTimer) {\n clearInterval(this.usageSampleTimer);\n this.usageSampleTimer = null;\n }\n }\n\n // ── Idle timer ─────────────────────────────────────────────────────\n\n startIdleTimer(): void {\n this.clearIdleTimers();\n this.idleTimer = setTimeout(() => {\n this.callbacks.onIdleTimeout();\n }, this.config.idleTimeoutMs);\n }\n\n cancelIdleTimer(): void {\n this.clearIdleTimers();\n }\n\n // ── Dormant timer ──────────────────────────────────────────────────\n\n /** Start (or restart) the dormant timer.\n * @param overrideMs Optional custom delay in ms. When provided, the timer\n * fires after exactly that delay instead of `dormantTimeoutMs`. SessionRunner\n * uses this to enforce an *absolute* deadline across cycles: even if the\n * dormant wait is interrupted by an inbound message, the next iteration\n * passes the remaining time, so the agent shuts down at the original\n * deadline regardless of message volume. */\n startDormantTimer(overrideMs?: number): void {\n this.cancelDormantTimer();\n const delay = Math.max(0, overrideMs ?? this.config.dormantTimeoutMs);\n this.dormantTimer = setTimeout(() => {\n this.callbacks.onDormantTimeout();\n }, delay);\n }\n\n cancelDormantTimer(): void {\n if (this.dormantTimer) {\n clearTimeout(this.dormantTimer);\n this.dormantTimer = null;\n }\n }\n\n // ── Cleanup ────────────────────────────────────────────────────────\n\n destroy(): void {\n this.stopHeartbeat();\n this.stopTokenRefresh();\n this.stopGitFlush();\n this.stopUsageSample();\n this.clearIdleTimers();\n this.cancelDormantTimer();\n }\n\n // ── Private ────────────────────────────────────────────────────────\n\n private clearIdleTimers(): void {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer);\n this.idleTimer = null;\n }\n if (this.idleCheckInterval) {\n clearInterval(this.idleCheckInterval);\n this.idleCheckInterval = null;\n }\n }\n}\n","/**\n * Harness-neutral types for agent query execution.\n *\n * These types abstract the underlying agent SDK so that the runner,\n * execution, and tool layers never reference SDK-specific imports\n * directly. The only place that should import from\n * `@anthropic-ai/claude-agent-sdk` is `harness/claude-code/`.\n */\n\nimport type { z } from \"zod\";\nimport type { PtyChatEventPayload } from \"@project/shared\";\n\n// ── Events emitted by the harness during a query ────────────────────────\n\nexport interface HarnessSystemInitEvent {\n type: \"system\";\n subtype: \"init\";\n session_id?: string;\n model: string;\n}\n\nexport interface HarnessCompactBoundaryEvent {\n type: \"system\";\n subtype: \"compact_boundary\";\n compact_metadata: { trigger: \"manual\" | \"auto\"; pre_tokens: number };\n}\n\nexport interface HarnessTaskStartedEvent {\n type: \"system\";\n subtype: \"task_started\";\n task_id: string;\n description: string;\n}\n\nexport interface HarnessTaskProgressEvent {\n type: \"system\";\n subtype: \"task_progress\";\n task_id: string;\n description: string;\n usage?: { tool_uses: number; duration_ms: number };\n}\n\nexport type HarnessSystemEvent =\n | HarnessSystemInitEvent\n | HarnessCompactBoundaryEvent\n | HarnessTaskStartedEvent\n | HarnessTaskProgressEvent;\n\nexport interface HarnessContentBlock {\n type: string;\n text?: string;\n name?: string;\n input?: unknown;\n id?: string;\n}\n\nexport interface HarnessAssistantEvent {\n type: \"assistant\";\n message: {\n role: \"assistant\";\n content: HarnessContentBlock[];\n usage?: {\n input_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n };\n}\n\nexport interface HarnessResultSuccessEvent {\n type: \"result\";\n subtype: \"success\";\n result: string;\n total_cost_usd: number;\n modelUsage?: Record<string, unknown>;\n sessionId?: string;\n}\n\nexport interface HarnessResultErrorEvent {\n type: \"result\";\n subtype: \"error\";\n errors: string[];\n sessionId?: string;\n}\n\nexport type HarnessResultEvent = HarnessResultSuccessEvent | HarnessResultErrorEvent;\n\nexport interface HarnessRateLimitEvent {\n type: \"rate_limit_event\";\n rate_limit_info: {\n status: string;\n rateLimitType?: string;\n utilization?: number;\n resetsAt?: unknown;\n };\n}\n\nexport interface HarnessToolProgressEvent {\n type: \"tool_progress\";\n tool_name?: string;\n elapsed_time_seconds?: number;\n}\n\nexport interface HarnessUserQuestion {\n question: string;\n header: string;\n options: { label: string; description: string }[];\n multiSelect?: boolean;\n}\n\n/**\n * PTY harness only: the interactive CLI is about to render an AskUserQuestion\n * questionnaire (observed via the PreToolUse hook). The TUI collects the\n * answer natively — this event exists so the runner can report\n * `waiting_for_input` while the questionnaire is pending. The SDK harness\n * never emits it (AskUserQuestion routes through `canUseTool` there).\n */\nexport interface HarnessUserQuestionEvent {\n type: \"user_question\";\n questions: HarnessUserQuestion[];\n}\n\nexport type HarnessEvent =\n | HarnessSystemEvent\n | HarnessAssistantEvent\n | HarnessResultEvent\n | HarnessRateLimitEvent\n | HarnessToolProgressEvent\n | HarnessUserQuestionEvent;\n\n// ── User message fed into a query ───────────────────────────────────────\n\nexport interface HarnessUserMessage {\n type: \"user\";\n session_id: string;\n message: { role: \"user\"; content: string | unknown[] };\n parent_tool_use_id: null;\n}\n\n// ── Tool definition (harness-neutral) ───────────────────────────────────\n\nexport interface HarnessToolAnnotations {\n readOnlyHint?: boolean;\n}\n\nexport interface HarnessToolDefinition {\n name: string;\n description: string;\n schema: z.ZodRawShape;\n handler: (\n // oxlint-disable-next-line typescript/no-explicit-any -- generic tool handler\n input: any,\n ) => Promise<{ content: { type: string; text?: string; data?: string; mimeType?: string }[] }>;\n annotations?: HarnessToolAnnotations;\n /**\n * Reject unknown input keys at validation time instead of silently\n * stripping them (the Zod default). Set this on tools where every field is\n * optional — there, a misspelled key (e.g. `storyPoints` instead of\n * `storyPointValue`) would otherwise validate as an empty update and\n * \"succeed\" while doing nothing. Enforced by both harness transports with\n * `z.strictObject`.\n */\n strict?: boolean;\n /**\n * Preload this tool into the model's prompt instead of deferring it behind\n * ToolSearch. Both harnesses honor it: the SDK harness passes it to the\n * SDK's `tool()` helper, and the PTY tool server advertises it as\n * `_meta['anthropic/alwaysLoad']` in the `tools/list` response — the flag\n * the spawned `claude` CLI reads when deciding which MCP tools to defer.\n * Reserve it for the hot protocol tools every session calls (see\n * `ALWAYS_LOADED_TOOLS` in `tools/index.ts`); deferring the long tail keeps\n * the prompt small.\n */\n alwaysLoad?: boolean;\n}\n\n// ── Hook types ──────────────────────────────────────────────────────────\n\nexport interface HarnessHookInput {\n hook_event_name: string;\n tool_name: string;\n tool_response: unknown;\n}\n\nexport interface HarnessHookOutput {\n continue: boolean;\n}\n\nexport type HarnessPostToolUseHook = (input: HarnessHookInput) => Promise<HarnessHookOutput>;\n\n// ── MCP server handle (opaque to the runner) ────────────────────────────\n\n/** Opaque handle returned by `AgentHarness.createMcpServer()`. */\nexport type HarnessMcpServer = unknown;\n\n/**\n * An external stdio MCP server (a spawned binary, e.g. the baked\n * `playwright-mcp`). The SDK harness passes this through to `query()`\n * untouched (the SDK natively supports stdio server configs); the PTY harness\n * writes it into the generated `--mcp-config` alongside the in-process HTTP\n * tool servers.\n */\nexport interface ExternalMcpStdioServer {\n type: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\n\n/** Runtime guard distinguishing external stdio entries from in-process tool\n * server handles inside the `HarnessMcpServer` (unknown) union. */\nexport function isExternalMcpStdioServer(value: unknown): value is ExternalMcpStdioServer {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Partial<ExternalMcpStdioServer>;\n return v.type === \"stdio\" && typeof v.command === \"string\";\n}\n\n// ── PTY relay bridge ────────────────────────────────────────────────────\n\n/**\n * Bidirectional bridge between a PTY harness session and the S2 server relay.\n *\n * Kept harness-neutral (no AgentConnection import) so this module never depends\n * on the connection layer. Only the PTY harness consumes it; the SDK harness\n * ignores it. The runner adapts an `AgentConnection` into this shape.\n */\nexport interface PtyBridge {\n /** Forward a raw chunk of terminal output to the relay (fire-and-forget). */\n sendOutput(data: string, dims?: { cols: number; rows: number }): void;\n /**\n * Forward one compact chat-proxy event derived from the transcript JSONL\n * (fire-and-forget). Optional — only relays that surface the experimental\n * chat PTY proxy provide it.\n */\n sendChatEvent?(event: PtyChatEventPayload): void;\n /**\n * Report that the interactive CLI process actually died with no respawn\n * imminent, so the server clears the scrollback ring and the Connected-TUI\n * tab hides (fire-and-forget). Optional — SDK-only callers omit it.\n */\n sendEnded?(): void;\n /**\n * Report that the CLI injected a background-task completion notification —\n * a `run_in_background` command or backgrounded subagent finished\n * (fire-and-forget). The runner uses it to retire one outstanding entry from\n * its background-work tracking, which is what lets it stop reporting\n * non-idle once the pod is genuinely quiet again. Optional — callers that\n * don't track background work omit it.\n */\n notifyBackgroundTaskDone?(): void;\n /**\n * Report that the interactive CLI is about to spawn with no usable Claude\n * credential and will therefore park on the sign-in screen (fire-and-forget).\n * The relay adapter surfaces `detail` as an actionable chat message so the\n * otherwise-silent login freeze is visible and recoverable. Optional —\n * SDK-only callers omit it.\n */\n notifyAuthNotReady?(detail: string): void;\n /**\n * Report that a submitted prompt never started a turn — the paste landed in\n * the TUI input box but the submitting Enter (and every nudge re-press) was\n * swallowed, so the CLI is parked with an unsubmitted prompt\n * (fire-and-forget). The relay adapter surfaces `detail` as a chat message so\n * the park is visible on the card instead of being a silent shrug; an\n * autonomous card has no human at the terminal to notice it. Optional —\n * SDK-only callers omit it.\n */\n notifyPromptDeliveryFailure?(detail: string): void;\n /**\n * Ask the server to destroy and recreate this pod (fire-and-forget). The one\n * caller is the prompt-delivery recovery's terminal branch, and only when the\n * shared `~/.claude` GCS FUSE mount is confirmed dead: no in-pod action can\n * remount it, so a new pod is the only real recovery. The server bounds the\n * rate; the harness bounds it again at once per process. Optional — SDK-only\n * callers omit it.\n */\n requestPodRecycle?(reason: string): void;\n /** Subscribe to user keystrokes forwarded from the relay. Returns unsubscribe. */\n onInput(handler: (data: string) => void): () => void;\n /** Subscribe to reconciled terminal-resize events from the relay. Returns unsubscribe. */\n onResize(handler: (cols: number, rows: number) => void): () => void;\n}\n\n// ── Query options ───────────────────────────────────────────────────────\n\nexport interface HarnessQueryOptions {\n model: string;\n systemPrompt: unknown;\n cwd: string;\n permissionMode: \"plan\" | \"bypassPermissions\";\n allowDangerouslySkipPermissions: boolean;\n tools: { type: \"preset\"; preset: \"claude_code\" };\n mcpServers: Record<string, HarnessMcpServer>;\n settingSources?: (\"user\" | \"project\" | \"local\")[];\n sandbox?: { enabled: boolean };\n maxTurns?: number;\n effort?: string;\n thinking?: unknown;\n betas?: unknown;\n disallowedTools?: string[];\n abortController?: AbortController;\n enableFileCheckpointing?: boolean;\n canUseTool?: (\n toolName: string,\n input: Record<string, unknown>,\n ) => Promise<\n | { behavior: \"allow\"; updatedInput?: Record<string, unknown> }\n | { behavior: \"deny\"; message: string }\n >;\n hooks?: Record<string, { hooks: HarnessPostToolUseHook[]; timeout: number }[]>;\n resume?: string;\n sessionId?: string;\n stderr?: (data: string) => void;\n /**\n * How the PTY harness delivers the query prompt to the spawned CLI:\n * - \"submit\" (default): paste the prompt and press Enter — the turn runs\n * immediately (auto-mode tasks, follow-up chat messages, resumes).\n * - \"prefill\": paste the prompt into the TUI input WITHOUT submitting, so\n * a human at the Connected-TUI terminal can review/edit/Enter it\n * (manual-mode initial instructions).\n * The SDK harness has no interactive input box and ignores this option.\n */\n promptDelivery?: \"submit\" | \"prefill\";\n /**\n * Extra system-prompt text passed to the spawned CLI via\n * `--append-system-prompt`. PTY harness only — the SDK harness already\n * receives the full system prompt through `systemPrompt.append` and ignores\n * this field.\n */\n appendSystemPrompt?: string;\n /**\n * PTY harness only: after the PreToolUse hook allows an ExitPlanMode call,\n * the interactive CLI still shows the plan-approval dialog (a hook \"allow\"\n * does not bypass it). When set, the session presses Enter to accept the\n * default option (\"Yes, auto-accept edits\") so an autonomous agent\n * continues building in the same session without a human at the terminal.\n * Conveyor's validation already happened in the hook — the dialog is\n * residual UX at that point.\n */\n planDialogAutoAccept?: boolean;\n}\n\n// ── Tool definition helper ──────────────────────────────────────────────\n\n/**\n * Construct a `HarnessToolDefinition` with the same signature as the SDK's\n * `tool()` helper, but without importing the SDK. The harness implementation\n * converts these into SDK-native tools when `createMcpServer()` is called.\n */\nexport function defineTool<T extends z.ZodRawShape>(\n name: string,\n description: string,\n schema: T,\n handler: (\n input: z.infer<z.ZodObject<T>>,\n ) => Promise<{ content: { type: string; text?: string; data?: string; mimeType?: string }[] }>,\n options?: { annotations?: HarnessToolAnnotations; strict?: boolean },\n): HarnessToolDefinition {\n return {\n name,\n description,\n schema,\n handler: handler as HarnessToolDefinition[\"handler\"],\n annotations: options?.annotations,\n strict: options?.strict,\n };\n}\n\n// ── AgentHarness interface ──────────────────────────────────────────────\n\nexport interface AgentHarness {\n /**\n * Whether this harness has a trusted structured-event source (an SDK stream,\n * or a transcript + hook socket) that makes mid-turn silence *meaningful*.\n *\n * `false` means raw relay: the harness emits no events between spawn and\n * exit by design, so silence carries no information and the mid-turn wedge\n * watchdog must not read it as a hang (`watchForParkedTui` layer 2 would\n * otherwise abort every long raw turn at the silence deadline). Undefined is\n * treated as `true` — only an explicitly raw harness opts out.\n */\n readonly emitsStructuredEvents?: boolean;\n\n /** Start a streaming query and return an async generator of events. */\n executeQuery(options: {\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>;\n options: HarnessQueryOptions;\n resume?: string;\n }): AsyncGenerator<HarnessEvent, void>;\n\n /** Wrap an array of harness-neutral tool definitions into an MCP server. */\n createMcpServer(config: { name: string; tools: HarnessToolDefinition[] }): HarnessMcpServer;\n\n /**\n * Force the active terminal (if any) to redraw its full screen. PTY-only:\n * used after a socket reconnect to re-seed the server's per-process\n * scrollback ring. Optional — the SDK harness has no terminal and omits it.\n */\n forceRepaint?(): void;\n\n /**\n * Tear down any long-lived resources the harness holds between queries.\n * PTY-only: the harness keeps the `claude` CLI process parked (alive) across\n * turns so the Connected-TUI stays interactive while idle; dispose() kills\n * that parked process and signals the ring teardown. The runner calls it on\n * stop/shutdown. Optional — the SDK harness holds nothing between queries.\n */\n dispose?(): Promise<void>;\n\n /**\n * PTY-only: subscribe to \"the parked CLI produced transcript activity with no\n * query running\" — i.e. a human typed into the idle Connected-TUI. The runner\n * uses this to start a promptless \"passive turn\" so the exchange is reflected\n * in status and mirrored to chat. Returns an unsubscribe fn. Optional.\n */\n onPassiveActivity?(handler: () => void): () => void;\n\n /**\n * PTY-only: drain events for a passive turn against the already-parked\n * process (no prompt is fed — the human already submitted in the TUI).\n * Returns an empty stream when no parked session exists. Optional.\n */\n executePassiveTurn?(options: HarnessQueryOptions): AsyncGenerator<HarnessEvent, void>;\n\n /**\n * PTY-only: inject a follow-up message into the CURRENTLY-RUNNING turn by\n * pasting it into the live TUI input — the CLI queues it and picks it up at\n * the next turn boundary, exactly as a human typing mid-turn would. Unlike a\n * superseding chat message this does NOT abort/kill the running `claude`\n * process. Returns true when it was injected; false when there is no live,\n * actively-draining turn to inject into (parked/idle, torn down, exited) — the\n * caller then falls back to the abort+respawn supersede path. Optional — the\n * SDK harness has no live TUI and omits it (callers treat absence as false).\n */\n injectIntoRunningTurn?(text: string): boolean;\n}\n","/**\n * ClaudeCodeHarness — wraps `@anthropic-ai/claude-agent-sdk` behind the\n * generic `AgentHarness` interface.\n *\n * This is the ONLY module that should import from the SDK.\n */\n\nimport { query, tool, createSdkMcpServer } from \"@anthropic-ai/claude-agent-sdk\";\nimport { z } from \"zod\";\nimport type {\n AgentHarness,\n HarnessEvent,\n HarnessQueryOptions,\n HarnessToolDefinition,\n HarnessMcpServer,\n HarnessUserMessage,\n} from \"../types.js\";\n\nexport class ClaudeCodeHarness implements AgentHarness {\n /** The SDK stream is itself the structured-event source. */\n readonly emitsStructuredEvents = true;\n\n async *executeQuery(opts: {\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>;\n options: HarnessQueryOptions;\n resume?: string;\n }): AsyncGenerator<HarnessEvent, void> {\n const sdkEvents = query({\n prompt: opts.prompt as Parameters<typeof query>[0][\"prompt\"],\n options: {\n ...(opts.options as Parameters<typeof query>[0][\"options\"]),\n ...(opts.resume ? { resume: opts.resume } : {}),\n ...(opts.options.sessionId ? { sessionId: opts.options.sessionId } : {}),\n ...(opts.options.abortController ? { abortController: opts.options.abortController } : {}),\n },\n });\n\n for await (const event of sdkEvents) {\n yield event as unknown as HarnessEvent;\n }\n }\n\n createMcpServer(config: { name: string; tools: HarnessToolDefinition[] }): HarnessMcpServer {\n const sdkTools = config.tools.map((t) => {\n const sdkTool = tool(\n t.name,\n t.description,\n t.schema,\n t.handler as Parameters<typeof tool>[3],\n {\n ...(t.annotations ? { annotations: t.annotations } : {}),\n // Preloads the tool into the prompt (skips ToolSearch deferral) via\n // `_meta['anthropic/alwaysLoad']` on the SDK MCP transport.\n ...(t.alwaysLoad ? { alwaysLoad: true } : {}),\n },\n );\n if (t.strict) {\n // The SDK helper accepts only a raw shape and rebuilds a permissive\n // object schema. Its MCP server also accepts a complete Zod schema, so\n // preserve outer strictness by replacing the helper's shape.\n sdkTool.inputSchema = z.strictObject(t.schema) as never;\n }\n return sdkTool;\n });\n return createSdkMcpServer({ name: config.name, tools: sdkTools });\n }\n}\n","/* oxlint-disable import/max-dependencies, max-lines -- session orchestrator: one cohesive lifecycle state machine driving a single `claude` PTY across turns (spawn, feed, park, reuse, teardown); it aggregates the pty submodules (queue, tailer, hook socket, spawn args, settings, coalescer, tool server) and the pure helpers are already split out to pty-support.ts */\n/**\n * PtySession — orchestrates one `claude` CLI run under a pseudo-terminal.\n *\n * It merges two event sources into a single stream:\n * 1. the on-disk transcript JSONL (tailed via JsonlTailer), and\n * 2. PostToolUse progress envelopes relayed over a Unix socket.\n *\n * Raw PTY stdout is never turned into HarnessEvents — only the trusted\n * transcript file and the validated socket envelopes become events. When a\n * PtyBridge is supplied, that raw stdout is instead mirrored verbatim to the\n * S2 relay so the S5 \"Connected TUI\" terminal can render it, and relayed\n * keystrokes / resizes are fed back into the pty.\n *\n * `node-pty` is loaded lazily so that SDK-only consumers never pull in the\n * native module.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdtemp, mkdir, rm, writeFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { stageOpenCodePlugin } from \"../opencode/plugin.js\";\nimport { OpenCodeEventSource } from \"../opencode/event-source.js\";\nimport type { PtyChatEventPayload } from \"@project/shared\";\nimport type {\n HarnessEvent,\n HarnessQueryOptions,\n HarnessUserMessage,\n HarnessUserQuestion,\n PtyBridge,\n} from \"../types.js\";\nimport { AsyncEventQueue } from \"./event-queue.js\";\nimport {\n HookSocketServer,\n type ToolProgress,\n type PreToolUseRequest,\n type PreToolUseVerdict,\n} from \"./hook-socket.js\";\nimport { JsonlTailer } from \"./jsonl-tailer.js\";\nimport { matchUsageLimitBanner } from \"./limit-banner.js\";\nimport {\n mapChatRecords,\n compactQuestionsJson,\n isBackgroundTaskNotificationRecord,\n} from \"./chat-record-mapper.js\";\nimport { writeHookSettings, sessionTranscriptPath } from \"./settings.js\";\nimport { cleanTerminalOutput } from \"./spawn-args.js\";\nimport { redact } from \"../../execution/redactor.js\";\nimport { PtyOutputCoalescer } from \"./output-coalescer.js\";\nimport { PtyToolServer, startToolServers } from \"./tool-server.js\";\nimport { ClaudeTuiAdapter } from \"./adapters/claude.js\";\nimport type { TuiAdapter } from \"./adapters/types.js\";\nimport {\n resolvePtySpawn,\n sessionTempBase,\n inheritedEnv,\n buildPromptBytes,\n renderPromptContentText,\n sleep,\n transcriptSize,\n parseUserQuestions,\n turnOptionsFrom,\n MAX_DIAGNOSTIC_OUTPUT,\n MAX_BETWEEN_TURN_BUFFER,\n resolveSubmitSettleMs,\n resolveSubmitNudgeTiming,\n resolvePlanDialogTiming,\n resolveRawTuiProbeTiming,\n sentinelEchoed,\n sawTerminalSetup as detectTerminalSetup,\n needsRawReadyGate,\n killPtyWithEscalation,\n type PtyProcess,\n type TurnOptions,\n} from \"./pty-support.js\";\n\n// Re-exported for tests and callers that imported them from this module before\n// the pure helpers moved to pty-support.ts.\nexport { inheritedEnv, buildPromptBytes, parseUserQuestions };\n\nexport class PtySession {\n // The current turn's event stream. Null between turns (process parked) — the\n // process outlives any single turn, so the queue is per-turn, not per-process.\n private activeQueue: AsyncEventQueue<HarnessEvent> | null = null;\n // The drain generator for the current turn, captured at turn-start and bound\n // to that turn's queue instance. events() returns THIS, not a fresh drain of\n // activeQueue — a turn can end (closing + nulling activeQueue) synchronously\n // within beginPassiveTurn (a buffered result) before the consumer calls\n // events(), and the consumer must still drain the already-buffered records.\n private turnStream: AsyncGenerator<HarnessEvent, void> | null = null;\n // Transcript events that arrive with no turn draining (parked window). A\n // passive turn replays these; beginTurn drops them.\n private betweenTurnBuffer: HarnessEvent[] = [];\n // Leading-edge guard so a burst of parked activity fires onPassiveActivity\n // once, not per event. Reset when a turn (re)starts.\n private passiveSignaled = false;\n private passiveListener: (() => void) | null = null;\n // Set once the CLI process actually exits (distinct from _toreDown, which is\n // our own teardown). Blocks reuse of a dead process.\n private exited = false;\n // Whether the turn that just ended did so via a clean transcript `result`\n // (eligible for parking) vs. an abort/error (must teardown).\n private lastTurnCleanResult = false;\n private socket: HookSocketServer | null = null;\n private tailer: JsonlTailer | null = null;\n // opencode structured-events state: the sink-record interpreter, and the\n // opencode-assigned session id it latched (reported via a synthetic init and\n // used for `--session` resume — opencode manages its own lineage, unlike\n // Claude's deterministic transcript UUIDs).\n private opencodeSource: OpenCodeEventSource | null = null;\n private reportedOpenCodeId: string | null = null;\n private pty: PtyProcess | null = null;\n private tempDir = \"\";\n private sawResult = false;\n private limitBannerReported = false;\n // Rolling tail of raw PTY output, retained only to enrich the error when the\n // CLI exits before emitting a result (the bytes are otherwise relayed to S5\n // and never become events). Trimmed to MAX_DIAGNOSTIC_OUTPUT on every write.\n private recentOutput = \"\";\n private coalescer: PtyOutputCoalescer | null = null;\n private _toreDown = false;\n // Raw-TUI input detection (see awaitRawTuiInputLive). `probeWindow`, when\n // non-null, accumulates raw output so a probe can look for its own sentinel\n // coming back.\n private spawnedAt = 0;\n // Set once the child writes a DEC private mode — it owns the tty from then on,\n // so the kernel no longer echoes our keystrokes and a sentinel coming back is\n // attributable to the app's own repaint.\n private sawTerminalSetup = false;\n private probeWindow: string | null = null;\n // Whether this process has already taken a prompt write. Only the FIRST one\n // waits on readiness: once the TUI is up, later writes (a multi-message\n // prompt, a follow-up turn) must go straight through — output is flowing\n // while the model works, so a quiet check would block until the turn ended.\n private wroteToProcess = false;\n private readonly exitListeners: ((code: number) => void)[] = [];\n private readonly idleListeners: (() => void)[] = [];\n private abortHandler: (() => void) | null = null;\n private cols = 120;\n private rows = 40;\n private unsubInput: (() => void) | null = null;\n private unsubResize: (() => void) | null = null;\n // In-process HTTP MCP servers exposing the harness tools to the spawned CLI,\n // plus the path to the `--mcp-config` that points at them.\n private toolServers: PtyToolServer[] = [];\n private mcpConfigPath: string | null = null;\n // Plan-dialog auto-accept state (see armPlanDialogAutoAccept).\n private pendingPlanApproval = false;\n private planApprovalTimer: NodeJS.Timeout | null = null;\n // Submit-nudge state (see armSubmitNudge).\n private pendingSubmitNudge = false;\n private submitNudgeTimer: NodeJS.Timeout | null = null;\n // Set when the nudge window expired with the turn still unstarted — the\n // pasted prompt is parked in the input box and no Enter will ever land. The\n // harness reads it after the turn's stream completes to respawn + redeliver.\n private _promptDeliveryFailed = false;\n // Text actually written into the TUI input this turn, retained so a respawn\n // can redeliver the identical prompt (the caller's prompt may be a\n // single-yield async generator that is already exhausted by then).\n private deliveredTexts: string[] = [];\n // Synthetic AskUserQuestion chat-card state. The CLI does NOT flush the\n // assistant record holding a pending AskUserQuestion tool_use to the\n // transcript until the questionnaire resolves (verified live on CLI 2.1.209:\n // dialog parked on screen, transcript untouched) — so a transcript-derived\n // question card could only ever render AFTER the human answered in the raw\n // terminal. Instead the PreToolUse hook (which fires at ask time and carries\n // the full questions input) emits a synthetic `tool_use` chat event under an\n // `aq-…` id. When the real records eventually flush, the duplicate tool_use\n // is dropped (FIFO match below) and its tool_result is re-pointed at the\n // synthetic id so the card flips to answered.\n private pendingSyntheticQuestionIds: string[] = [];\n private questionResultRemap = new Map<string, string>();\n\n // Per-turn state: the prompt to feed and the per-turn options subset. Both\n // start from the constructor args (turn 1) and are replaced by beginTurn.\n private turnPrompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>;\n private turn: TurnOptions;\n\n constructor(\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>,\n // Spawn-level options — fixed for the life of the CLI process. Per-turn\n // fields (canUseTool/promptDelivery/planDialogAutoAccept/abortController)\n // are snapshotted into `this.turn` and overridden each turn.\n private readonly options: HarnessQueryOptions,\n private readonly resume?: string,\n private readonly bridge?: PtyBridge,\n private readonly adapter: TuiAdapter = new ClaudeTuiAdapter(),\n ) {\n this.turnPrompt = prompt;\n this.turn = turnOptionsFrom(options);\n }\n\n onIdle(listener: () => void): void {\n this.idleListeners.push(listener);\n }\n\n onExit(listener: (code: number) => void): void {\n this.exitListeners.push(listener);\n }\n\n /** Subscribe to parked-window transcript activity (human typed into the idle\n * TUI). Returns unsubscribe. Only one listener is retained. */\n onPassiveActivity(listener: () => void): () => void {\n this.passiveListener = listener;\n return () => {\n if (this.passiveListener === listener) this.passiveListener = null;\n };\n }\n\n get isToreDown(): boolean {\n return this._toreDown;\n }\n\n /** True once the underlying CLI process has exited. */\n get hasExited(): boolean {\n return this.exited;\n }\n\n /** True when the last turn ended via a clean transcript result (parkable). */\n get endedCleanly(): boolean {\n return this.lastTurnCleanResult;\n }\n\n /**\n * True when this turn's prompt was pasted but never submitted — the nudge\n * window expired with no transcript record proving the turn started. The\n * harness treats it as a delivery failure and respawns + redelivers.\n */\n get promptDeliveryFailed(): boolean {\n return this._promptDeliveryFailed;\n }\n\n /** The exact text pasted into the TUI this turn — the payload a respawn\n * redelivers. Empty when nothing was delivered. */\n get deliveredPromptText(): string {\n return this.deliveredTexts.join(\"\\n\\n\");\n }\n\n /**\n * The tail of the raw terminal screen, ANSI-stripped and secret-scrubbed —\n * DIAGNOSTICS ONLY. The harness logs it when a prompt delivery fails, which\n * is the only record of what the TUI was actually parked on (a startup\n * dialog, a mount error, a login screen). Without it every park is\n * undiagnosable after the fact. This does not weaken the parity rule that raw\n * stdout is never parsed into events: nothing here becomes a HarnessEvent.\n */\n get diagnosticFrame(): string {\n const tail = cleanTerminalOutput(this.recentOutput, MAX_DIAGNOSTIC_OUTPUT);\n return tail ? redact(tail).output : \"\";\n }\n\n /**\n * The session identity this process is bound to. For Claude, the\n * deterministic lineage UUID; for opencode, the `ses_…` id the engine\n * assigned (latched from the plugin events), which wins once known so a\n * respawn's explicit resume target matches.\n */\n get sessionUuid(): string | undefined {\n return this.reportedOpenCodeId ?? this.resume ?? this.options.sessionId;\n }\n\n /** The opencode-assigned session id, or null (always null for Claude). */\n get reportedSessionId(): string | null {\n return this.reportedOpenCodeId;\n }\n\n /** Fingerprint of the spawn-time options a reused process cannot change. */\n get spawnFingerprint(): string {\n return this.adapter.spawnFingerprint({\n model: this.options.model,\n permissionMode: this.options.permissionMode,\n ...(this.options.appendSystemPrompt\n ? { appendSystemPrompt: this.options.appendSystemPrompt }\n : {}),\n cwd: this.options.cwd,\n });\n }\n\n /**\n * Whether this parked process can serve a turn wanting `resume`/`fingerprint`.\n * Requires: live (not torn down / not exited), idle (no turn draining), a\n * matching resume target, and matching spawn options.\n *\n * The resume match is adapter-shaped. Claude's resume tokens are transcript\n * files, so an undefined `resume` means \"start a fresh conversation\" and\n * must NOT reuse a parked process bound to an old one. opencode manages its\n * own lineage — the executor can never learn its `ses_…` ids from disk, so\n * every follow-up arrives with `resume` undefined; there, the live parked\n * process IS the conversation, and reuse is keyed on the id the plugin\n * events latched. Gating on `reportedOpenCodeId` (which Claude sessions\n * never set) keeps the Claude semantics byte-identical.\n */\n canReuse(resume: string | undefined, fingerprint: string): boolean {\n const resumeMatches =\n resume === undefined ? this.reportedOpenCodeId !== null : resume === this.sessionUuid;\n return (\n !this._toreDown &&\n !this.exited &&\n this.activeQueue === null &&\n resumeMatches &&\n fingerprint === this.spawnFingerprint\n );\n }\n\n get hookSocketPath(): string | null {\n return this.socket ? this.socket.socketPath : null;\n }\n\n events(): AsyncGenerator<HarnessEvent, void> {\n // Return the stream captured at the current turn's start. It is always set\n // by start()/beginTurn()/beginPassiveTurn() before the consumer calls this;\n // guard defensively so a stray call yields an empty, completed stream.\n if (!this.turnStream) {\n const empty = new AsyncEventQueue<HarnessEvent>();\n empty.close();\n return empty.drain();\n }\n return this.turnStream;\n }\n\n /**\n * Route a harness event to the current turn's queue, or — when no turn is\n * draining (the process is parked) — into the between-turn buffer, firing the\n * passive-activity signal once per parked window.\n */\n private pushEvent(event: HarnessEvent): void {\n if (this.activeQueue) {\n this.activeQueue.push(event);\n return;\n }\n this.betweenTurnBuffer.push(event);\n if (this.betweenTurnBuffer.length > MAX_BETWEEN_TURN_BUFFER) {\n this.betweenTurnBuffer.shift();\n }\n if (!this.passiveSignaled) {\n this.passiveSignaled = true;\n this.passiveListener?.();\n }\n }\n\n /**\n * Begin a follow-up turn on the ALREADY-RUNNING process: fresh per-turn state\n * and queue, rewire the abort listener to this turn's controller, then feed\n * the prompt into the live pty. The caller must have verified canReuse().\n */\n async beginTurn(\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>,\n options: HarnessQueryOptions,\n ): Promise<void> {\n this.turnPrompt = prompt;\n this.turn = turnOptionsFrom(options);\n this.resetForTurn();\n // A stale buffered `result` from the parked window must never terminate this\n // fresh turn, so drop the buffer (a passive turn replays it instead).\n this.betweenTurnBuffer = [];\n this.activeQueue = new AsyncEventQueue<HarnessEvent>();\n this.turnStream = this.activeQueue.drain();\n if (!this.rearmAbort()) return;\n await this.feedPrompt();\n }\n\n /**\n * Begin a PASSIVE turn: a human typed into the parked TUI and the CLI is\n * producing transcript records with no prompt from us. Replay the buffered\n * records into a fresh queue (a buffered `result` ends the turn at once) and\n * let live records continue to flow.\n */\n beginPassiveTurn(turn: TurnOptions): void {\n this.turn = turn;\n this.resetForTurn();\n const buffered = this.betweenTurnBuffer;\n this.betweenTurnBuffer = [];\n this.activeQueue = new AsyncEventQueue<HarnessEvent>();\n // Capture the stream before replaying: a buffered `result` ends the turn\n // (closing + nulling activeQueue) synchronously below, but the consumer must\n // still drain the records we just pushed.\n this.turnStream = this.activeQueue.drain();\n if (!this.rearmAbort()) return;\n for (const event of buffered) {\n this.activeQueue?.push(event);\n if (event.type === \"result\") this.endTurn(true);\n }\n }\n\n /** Reset per-turn state shared by beginTurn/beginPassiveTurn. */\n private resetForTurn(): void {\n this.sawResult = false;\n this.lastTurnCleanResult = false;\n this.passiveSignaled = false;\n this._promptDeliveryFailed = false;\n this.deliveredTexts = [];\n this.disarmSubmitNudge();\n this.disarmPlanDialogAutoAccept();\n // Backstop for a dialog dismissed without any transcript trace (endTurn\n // covers the clean-result path): a fresh turn means the old dialog is gone.\n this.closeSyntheticQuestionCards();\n }\n\n /**\n * (Re)register the abort→teardown listener on the current turn's controller,\n * removing any prior one. Returns false (after tearing down) when the signal\n * is already aborted, so callers can bail.\n */\n private rearmAbort(): boolean {\n if (this.abortHandler && this.turn.abortController) {\n this.turn.abortController.signal.removeEventListener(\"abort\", this.abortHandler);\n }\n this.abortHandler = null;\n const signal = this.turn.abortController?.signal;\n if (!signal) return true;\n if (signal.aborted) {\n void this.teardown();\n return false;\n }\n this.abortHandler = () => {\n void this.teardown();\n };\n signal.addEventListener(\"abort\", this.abortHandler, { once: true });\n return true;\n }\n\n /**\n * End the current turn WITHOUT killing the process: close+null the queue so\n * the consumer's generator completes, and unhook the (now-finished) turn's\n * abort listener so a later abort of that controller can't teardown a process\n * we intend to reuse. The process stays alive (parked) for the next turn.\n */\n private endTurn(clean: boolean): void {\n this.lastTurnCleanResult = clean;\n // An answered questionnaire drained this state before the turn's result\n // record (transcript order); anything left is an interrupted dialog whose\n // records will never flush — close its card.\n this.closeSyntheticQuestionCards();\n this.activeQueue?.close();\n this.activeQueue = null;\n if (this.abortHandler && this.turn.abortController) {\n this.turn.abortController.signal.removeEventListener(\"abort\", this.abortHandler);\n this.abortHandler = null;\n }\n }\n\n async start(): Promise<void> {\n // Fail fast before allocating resources: the tailer can only locate the\n // transcript if we know which session id the CLI will write to.\n const sessionId = this.resume ?? this.options.sessionId;\n if (!sessionId) {\n throw new Error(\"PtySession requires options.sessionId or a resume target\");\n }\n // This is turn 1: allocate its queue up front so the abort-before-alloc\n // teardown below has a queue to close (a parked consumer completes).\n this.activeQueue = new AsyncEventQueue<HarnessEvent>();\n this.turnStream = this.activeQueue.drain();\n // stop()/softStop() abort the query's shared AbortController. The SDK\n // harness consumes it natively; under the PTY harness we must translate an\n // abort into teardown() — otherwise a mid-turn `claude` (which may never\n // emit a transcript `result` and does not exit) is left running while the\n // event consumer stays parked on the queue.\n const signal = this.turn.abortController?.signal;\n if (signal?.aborted) {\n // Already aborted before we allocated anything — tear down (which closes\n // the empty queue so a parked consumer completes) and bail.\n await this.teardown();\n return;\n }\n try {\n if (this.adapter.capabilities.structuredEvents && this.adapter.id === \"opencode\") {\n // Trusted structured-event source, opencode flavor: the Conveyor\n // events plugin appends the client engine's bus to an NDJSON sink,\n // tailed like a transcript. Tool servers are shared with the Claude\n // path; the config rides the child env instead of files/sockets.\n const extras = await this.startOpenCodeEventSources();\n await this.spawn(undefined, undefined, extras);\n } else if (this.adapter.capabilities.structuredEvents) {\n // Trusted structured-event source (transcript tailer + hook socket +\n // tool servers): lifecycle status derives from transcript records, not\n // process aliveness. Allocate it, then spawn wired to those resources.\n const { settingsPath, socketPath } = await this.startStructuredEventSources(sessionId);\n await this.spawn(settingsPath, socketPath);\n } else {\n // Raw terminal mode: the TUI exposes no trusted event source, so we run\n // it as a plain relayed terminal — no hook socket, settings, tool\n // servers, or tailer. Lifecycle status derives from process aliveness:\n // a synthetic init on spawn here, and a result on exit in\n // finalizeOnExit. A tempDir is still allocated for teardown symmetry.\n this.tempDir = await mkdtemp(join(sessionTempBase(), \"conveyor-pty-\"));\n await this.spawn();\n this.pushEvent({\n type: \"system\",\n subtype: \"init\",\n session_id: sessionId,\n model: this.options.model,\n });\n }\n // Register after spawn so the handler has a live pty to kill, then\n // re-check: an abort racing with allocation (fired before the listener\n // attached) would otherwise be missed.\n if (signal) {\n this.abortHandler = () => {\n void this.teardown();\n };\n signal.addEventListener(\"abort\", this.abortHandler, { once: true });\n if (signal.aborted) {\n await this.teardown();\n return;\n }\n }\n // Wire relayed keystrokes / resizes into the live pty. Registered only\n // after a successful spawn so writeStdin/resizePty have a process to\n // target; the unsubscribers are cleared in teardown().\n if (this.bridge) {\n this.unsubInput = this.bridge.onInput((data) => this.writeStdin(data));\n this.unsubResize = this.bridge.onResize((cols, rows) => this.resizePty(cols, rows));\n }\n await this.feedPrompt();\n } catch (err) {\n // A failure after we begin allocating (socket listen, tailer interval,\n // temp dir, spawn) would otherwise leak those resources: the PtyHarness\n // consumer only calls teardown() once start() has resolved.\n await this.teardown();\n throw err;\n }\n }\n\n /**\n * Allocate the opencode structured-event sources: the in-process tool\n * servers (shared with the Claude path — the same loopback StreamableHTTP\n * servers, consumed via config `mcp` entries instead of `--mcp-config`),\n * the instructions file carrying the system prompt, the staged Conveyor\n * events plugin, and a tailer on its sink. Returns the spawn extras the\n * adapter bakes into OPENCODE_CONFIG_CONTENT.\n *\n * The tailer routes every parsed record to the OpenCodeEventSource, which\n * owns per-turn state (roles, usage, busy/idle) and feeds the mapped events\n * through the SAME handleTranscriptEvent path Claude records take — so\n * nudge-disarm, passive buffering, and result-ends-turn run unchanged. The\n * synthetic `system init` reports the opencode-assigned session id the\n * moment it is known, which is how the runner learns the resume target.\n */\n private async startOpenCodeEventSources(): Promise<{\n mcpEntries: Record<string, import(\"./tool-server.js\").McpConfigEntry>;\n eventsSinkPath: string;\n pluginPath: string;\n instructionsPath?: string;\n }> {\n this.tempDir = await mkdtemp(join(sessionTempBase(), \"conveyor-pty-\"));\n const { servers, entries } = await startToolServers(\n this.options.mcpServers ?? {},\n this.tempDir,\n );\n this.toolServers = servers;\n const { pluginPath, eventsSinkPath } = await stageOpenCodePlugin(this.tempDir);\n let instructionsPath: string | undefined;\n const systemPrompt = this.options.appendSystemPrompt;\n if (systemPrompt && systemPrompt.trim() !== \"\") {\n instructionsPath = join(this.tempDir, \"conveyor-instructions.md\");\n await writeFile(instructionsPath, systemPrompt, \"utf8\");\n }\n this.opencodeSource = new OpenCodeEventSource(\n (event) => this.handleTranscriptEvent(event),\n (id) => {\n this.reportedOpenCodeId = id;\n this.pushEvent({\n type: \"system\",\n subtype: \"init\",\n session_id: id,\n model: this.options.model,\n });\n this.sendChatEvent({ kind: \"init\", model: this.options.model, claudeSessionId: id });\n },\n (event) => this.sendChatEvent(event),\n );\n this.tailer = new JsonlTailer(\n eventsSinkPath,\n () => undefined,\n (raw) => this.opencodeSource?.handleRecord(raw),\n () => null,\n );\n this.tailer.start(0);\n return {\n mcpEntries: entries,\n eventsSinkPath,\n pluginPath,\n ...(instructionsPath ? { instructionsPath } : {}),\n };\n }\n\n /**\n * Allocate the Claude-style structured-event sources: the PostToolUse hook\n * socket, the per-run settings file, the in-process tool servers, and the\n * transcript tailer. Only structured-events adapters call this — raw-terminal\n * adapters have no trusted event source and skip it entirely. Returns the\n * paths spawn() must wire into the child's argv/env.\n */\n private async startStructuredEventSources(\n sessionId: string,\n ): Promise<{ settingsPath: string; socketPath: string }> {\n this.tempDir = await mkdtemp(join(sessionTempBase(), \"conveyor-pty-\"));\n const socketPath = join(this.tempDir, \"hook.sock\");\n this.socket = new HookSocketServer(\n socketPath,\n (progress) => this.handleProgress(progress),\n (request) => this.handlePreToolUse(request),\n );\n await this.socket.listen();\n // Plan-permission spawns prompt for any tool the CLI cannot prove is\n // read-only, and a card agent has nobody at the terminal to answer — so\n // Conveyor answers for EVERY tool there. Build-capable spawns bypass\n // prompts entirely and keep the scoped matcher list.\n const { settingsPath } = await writeHookSettings(this.tempDir, {\n gateAllTools: this.options.permissionMode === \"plan\",\n });\n // Expose the harness's in-process tools to the spawned CLI over a loopback\n // HTTP MCP server, written into a `--mcp-config` consumed by spawn().\n await this.setupToolServers();\n const transcriptPath = sessionTranscriptPath(this.options.cwd, sessionId);\n await mkdir(dirname(transcriptPath), { recursive: true });\n // On resume the transcript already holds the prior session's records; start\n // tailing at EOF so historical records aren't replayed as fresh events.\n const startOffset = this.resume ? await transcriptSize(transcriptPath) : 0;\n // Chat-proxy relay: raw records (including user prompts, which the\n // harness mapper drops) are projected to compact chat events at the\n // tailer level, so between-turn/parked records relay too. The same raw\n // feed carries the background-task completion notifications — also a user\n // record the harness mapper drops.\n const wantsRawRecords =\n typeof this.bridge?.sendChatEvent === \"function\" ||\n typeof this.bridge?.notifyBackgroundTaskDone === \"function\";\n this.tailer = new JsonlTailer(\n transcriptPath,\n (event) => this.handleTranscriptEvent(event),\n wantsRawRecords ? (raw) => this.handleRawRecord(raw) : undefined,\n );\n this.tailer.start(startOffset);\n return { settingsPath, socketPath };\n }\n\n /**\n * Fan one tailed transcript record out to its raw-record consumers: the\n * background-work signal (a `<task-notification>` user turn means a\n * backgrounded gate/subagent just finished) and the chat-proxy projection.\n */\n private handleRawRecord(raw: unknown): void {\n if (isBackgroundTaskNotificationRecord(raw)) this.bridge?.notifyBackgroundTaskDone?.();\n if (typeof this.bridge?.sendChatEvent === \"function\") this.relayChatRecord(raw);\n }\n\n /**\n * Project a tailed transcript record to chat events, reconciling them with\n * any synthetic question card already emitted at hook time: the flushed\n * AskUserQuestion `tool_use` duplicate is dropped (its real id remembered),\n * and the paired `tool_result` is re-pointed at the synthetic id so the\n * live-rendered card is the one that flips to answered.\n */\n private relayChatRecord(raw: unknown): void {\n for (const event of mapChatRecords(raw)) {\n if (event.kind === \"tool_use\" && event.name === \"AskUserQuestion\") {\n const syntheticId = this.pendingSyntheticQuestionIds.shift();\n if (syntheticId) {\n if (event.id) this.questionResultRemap.set(event.id, syntheticId);\n continue;\n }\n } else if (event.kind === \"tool_result\" && event.toolUseId) {\n const syntheticId = this.questionResultRemap.get(event.toolUseId);\n if (syntheticId) {\n this.questionResultRemap.delete(event.toolUseId);\n this.sendChatEvent({ ...event, toolUseId: syntheticId });\n continue;\n }\n }\n this.sendChatEvent(event);\n }\n }\n\n private sendChatEvent(event: PtyChatEventPayload): void {\n this.bridge?.sendChatEvent?.(event);\n }\n\n /** Render the question card in the web chat NOW — at hook time — instead of\n * whenever the CLI flushes the transcript records (which is only after the\n * questionnaire resolves; see the field comment). */\n private emitSyntheticQuestionCard(questions: HarnessUserQuestion[]): void {\n if (questions.length === 0 || typeof this.bridge?.sendChatEvent !== \"function\") return;\n const id = `aq-${randomUUID()}`;\n this.pendingSyntheticQuestionIds.push(id);\n this.sendChatEvent({\n kind: \"tool_use\",\n name: \"AskUserQuestion\",\n input: compactQuestionsJson(questions),\n id,\n });\n }\n\n /**\n * Close any still-open synthetic question cards. The questionnaire can only\n * outlive its card via a path that never flushes the paired records — Esc /\n * interrupt, a superseding turn, or process teardown — so an answering\n * tool_result will never arrive for these ids; emit one so the web card\n * stops soliciting input for a dialog that no longer exists.\n */\n private closeSyntheticQuestionCards(): void {\n const orphaned = [...this.pendingSyntheticQuestionIds, ...this.questionResultRemap.values()];\n this.pendingSyntheticQuestionIds = [];\n this.questionResultRemap.clear();\n for (const toolUseId of orphaned) {\n this.sendChatEvent({ kind: \"tool_result\", toolUseId, output: \"\", isError: false });\n }\n }\n\n writeStdin(text: string): void {\n this.pty?.write(text);\n }\n\n /**\n * Inject a follow-up message into the CURRENTLY-RUNNING turn by pasting it into\n * the live TUI input, exactly as a human typing mid-turn would — the CLI queues\n * it and picks it up at the next turn boundary. Unlike beginTurn this does NOT\n * reset per-turn state, allocate a new queue, or re-arm the abort listener: the\n * in-flight turn (and its transcript stream) keeps flowing, so the injected\n * message and its response ride the SAME event pipeline. Returns false when\n * there is no live, actively-draining turn to inject into — parked/idle\n * (activeQueue === null), torn down, exited, or a raw-terminal TUI that gives\n * us no trusted signal that a turn is running — so the caller falls back to the\n * abort+respawn supersede path.\n */\n injectIntoRunningTurn(text: string): boolean {\n if (!this.pty || this._toreDown || this.exited) return false;\n // A null activeQueue means the process is parked/idle (no turn draining):\n // there is nothing to inject into, so a fresh turn (feedPrompt via beginTurn)\n // is the correct path, not a mid-turn paste.\n if (this.activeQueue === null) return false;\n // Only trusted structured-event TUIs (claude) — a raw terminal exposes no\n // way to know a turn is actually running, so injecting could race a parked\n // process we misread as busy.\n if (!this.adapter.capabilities.structuredEvents) return false;\n if (!text.trim()) return false;\n void this.submitLivePrompt(text);\n return true;\n }\n\n /**\n * Paste + submit a prompt into the live pty WITHOUT any turn bookkeeping.\n * Mirrors deliverPrompt's submit path (bracketed paste, then a separate Enter\n * after a settle window) but never arms the submit nudge — the running turn is\n * already producing transcript records, so re-pressing Enter would risk\n * accepting an unrelated mid-turn dialog. Fire-and-forget.\n */\n private async submitLivePrompt(text: string): Promise<void> {\n this.writeStdin(this.adapter.encodePromptBytes(text));\n await sleep(resolveSubmitSettleMs());\n if (this._toreDown || this.exited) return;\n this.writeStdin(\"\\r\");\n }\n\n /** Apply a relayed resize to the live pty (reconciled dims from the server). */\n private resizePty(cols: number, rows: number): void {\n if (cols <= 0 || rows <= 0) return;\n this.cols = cols;\n this.rows = rows;\n try {\n this.pty?.resize(cols, rows);\n } catch {\n /* pty already exited */\n }\n }\n\n /**\n * Force the CLI to repaint its full screen by wiggling the pty size\n * (SIGWINCH). Used after a socket reconnect: the server's scrollback ring is\n * per-process and starts empty on a new instance, so without a repaint a\n * quiet TUI would leave the Connected-TUI terminal blank (and hidden) until\n * the CLI next draws on its own.\n */\n forceRepaint(): void {\n if (!this.pty) return;\n try {\n this.pty.resize(this.cols, Math.max(1, this.rows - 1));\n this.pty.resize(this.cols, this.rows);\n } catch {\n /* pty already exited */\n }\n }\n\n async teardown(): Promise<void> {\n if (this._toreDown) return;\n this._toreDown = true;\n this.disarmPlanDialogAutoAccept();\n this.disarmSubmitNudge();\n // A dialog parked at kill time will never resolve — close its web card.\n this.closeSyntheticQuestionCards();\n this.unsubInput?.();\n this.unsubInput = null;\n this.unsubResize?.();\n this.unsubResize = null;\n if (this.abortHandler) {\n this.turn.abortController?.signal.removeEventListener(\"abort\", this.abortHandler);\n this.abortHandler = null;\n }\n const pty = this.pty;\n this.pty = null;\n if (pty) killPtyWithEscalation(pty, () => this.exited);\n this.coalescer?.dispose();\n this.coalescer = null;\n this.tailer?.close();\n this.tailer = null;\n if (this.socket) {\n await this.socket.close();\n this.socket = null;\n }\n for (const toolServer of this.toolServers) {\n try {\n await toolServer.close();\n } catch {\n /* already closed */\n }\n }\n this.toolServers = [];\n this.mcpConfigPath = null;\n this.activeQueue?.close();\n this.activeQueue = null;\n if (this.tempDir) {\n await rm(this.tempDir, { recursive: true, force: true });\n this.tempDir = \"\";\n }\n }\n\n /**\n * Serve the harness's in-process tools to the spawned CLI over loopback HTTP\n * (handlers run in THIS process against the live task-token connection) and\n * record the `--mcp-config` path for spawn(). No-op when the harness was\n * constructed without tools (e.g. SDK-only callers).\n */\n private async setupToolServers(): Promise<void> {\n const { servers, mcpConfigPath } = await startToolServers(\n this.options.mcpServers ?? {},\n this.tempDir,\n );\n this.toolServers = servers;\n this.mcpConfigPath = mcpConfigPath;\n }\n\n private async spawn(\n settingsPath?: string,\n socketPath?: string,\n opencodeExtras?: {\n mcpEntries: Record<string, import(\"./tool-server.js\").McpConfigEntry>;\n eventsSinkPath: string;\n pluginPath: string;\n instructionsPath?: string;\n },\n ): Promise<void> {\n // An opencode respawn resumes the engine-assigned id when one was latched\n // (the constructor `resume` is a Claude-lineage UUID opencode cannot know).\n const resume = this.reportedOpenCodeId ?? this.resume;\n const spec = this.adapter.buildSpawn({\n options: this.options,\n ...(resume ? { resume } : {}),\n ...(settingsPath ? { settingsPath } : {}),\n ...(socketPath ? { hookSocketPath: socketPath } : {}),\n // Only this config: ignore the user's ~/.claude.json / project .mcp.json\n // so the agent's tool set is deterministic (and a stale personal conveyor\n // server doesn't load).\n ...(this.mcpConfigPath ? { mcpConfigPath: this.mcpConfigPath } : {}),\n ...(opencodeExtras ?? {}),\n });\n const spawn = await resolvePtySpawn();\n const pty = spawn(spec.file, spec.args, {\n name: \"xterm-color\",\n cols: this.cols,\n rows: this.rows,\n cwd: this.options.cwd,\n env: spec.env,\n });\n // Mirror raw terminal output to the relay (and on to the S5 terminal). The\n // first flush creates the server-side scrollback ring — which is what makes\n // the Connected-TUI terminal appear, i.e. this doubles as the attach\n // handshake. Output is coalesced (~40ms windows) so a busy redraw becomes\n // one relay call instead of tens — per-frame server cost was starving the\n // stream. Stdout is intentionally NOT turned into HarnessEvents.\n const bridge = this.bridge;\n if (bridge) {\n this.coalescer = new PtyOutputCoalescer(\n (data, dims) => {\n bridge.sendOutput(data, dims);\n },\n () => ({ cols: this.cols, rows: this.rows }),\n );\n }\n pty.onData((data) => {\n this.coalescer?.write(data);\n // Raw-TUI input detection: an open probe window collects output so a probe\n // can confirm the TUI rendered its sentinel back.\n if (!this.sawTerminalSetup && detectTerminalSetup(data)) this.sawTerminalSetup = true;\n if (this.probeWindow !== null) this.probeWindow += data;\n // Retain a bounded tail so finalizeOnExit can explain an early exit.\n this.recentOutput = (this.recentOutput + data).slice(-MAX_DIAGNOSTIC_OUTPUT);\n });\n pty.onExit((event) => {\n void this.finalizeOnExit(event.exitCode);\n });\n this.spawnedAt = Date.now();\n this.sawTerminalSetup = false;\n this.probeWindow = null;\n // A respawn (submit-redelivery) faces a cold TUI again, so the next write\n // must re-wait rather than inherit the previous process's readiness.\n this.wroteToProcess = false;\n this.pty = pty;\n }\n\n /** Open a fresh probe-observation window over raw output. */\n private openProbeWindow(): void {\n this.probeWindow = \"\";\n }\n\n /**\n * Write `bytes`, then wait up to `ackMs` for the TUI to render `sentinel` back.\n * Positive proof that a live input box consumed the keystrokes.\n */\n private async writeAndAwaitEcho(\n bytes: string,\n sentinel: string,\n timing: { ackMs: number; pollMs: number },\n ): Promise<boolean> {\n this.openProbeWindow();\n this.writeStdin(bytes);\n const deadline = Date.now() + timing.ackMs;\n while (Date.now() < deadline) {\n if (this._toreDown) return false;\n if (sentinelEchoed(this.probeWindow ?? \"\", sentinel)) return true;\n await sleep(timing.pollMs);\n }\n return false;\n }\n\n /**\n * Wait until a raw-relay TUI's input box is DEMONSTRABLY accepting keystrokes,\n * by typing a short sentinel and watching for the TUI to render it back, then\n * erasing it. Readiness is detected, never inferred from elapsed time.\n *\n * A structured-events TUI does not need this: `armSubmitNudge` re-presses\n * Enter until a transcript record proves the turn started. A raw adapter has\n * no such evidence, so the nudge is deliberately never armed for it — its\n * single paste + Enter is the only shot, and one fired during startup is\n * discarded with no trace, leaving the card parked on an empty input box.\n *\n * See resolveRawTuiProbeTiming for the measurements behind this, including the\n * signals that were tried and rejected (DECSET 2004, output-quiet windows, and\n * \"any output after a keystroke\" — all of which report ready too early).\n */\n private async awaitRawTuiInputLive(): Promise<void> {\n if (!needsRawReadyGate(this.adapter.capabilities)) return;\n const timing = resolveRawTuiProbeTiming();\n const { sentinel } = timing;\n const start = this.spawnedAt || Date.now();\n\n // 1. Wait for the child to take over the terminal. Before that the tty is\n // still in canonical mode and the kernel echoes our own keystrokes back,\n // which is indistinguishable from a repaint — probing there reports live\n // instantly and the prompt is then pasted into a dead input.\n const setupDeadline = start + timing.firstOutputMaxMs;\n while (!this._toreDown && Date.now() < setupDeadline) {\n if (this.sawTerminalSetup) break;\n await sleep(timing.pollMs);\n }\n if (this._toreDown) return;\n\n // 2. Probe until the box echoes the sentinel. A probe that lands before the\n // input handler is live is discarded silently, leaving nothing behind —\n // which is exactly why retrying is safe.\n const deadline = start + timing.maxMs;\n let live = false;\n let probes = 0;\n while (!this._toreDown && Date.now() < deadline) {\n probes++;\n if (await this.writeAndAwaitEcho(sentinel, sentinel, timing)) {\n live = true;\n break;\n }\n await sleep(timing.retryMs);\n }\n if (this._toreDown) return;\n\n if (!live) {\n // Cap reached. Paste anyway: a stalled turn whose prompt was never sent is\n // strictly worse to debug than one that failed loudly downstream.\n process.stderr.write(\n `[conveyor-agent] raw TUI never echoed the input probe after ${probes} attempt(s) ` +\n `in ${Date.now() - start}ms — pasting anyway\\n`,\n );\n this.probeWindow = null;\n return;\n }\n\n // 3. Erase the sentinel. An unacknowledged probe leaves nothing, but a\n // LATE-acknowledged one can have deposited more than one copy, so erase\n // until the box no longer shows it.\n for (let round = 0; round < probes && !this._toreDown; round++) {\n const gone = !(await this.writeAndAwaitEcho(\n \"\\x7f\".repeat(sentinel.length),\n sentinel,\n timing,\n ));\n if (gone) break;\n }\n this.probeWindow = null;\n }\n\n private async deliverPrompt(text: string): Promise<void> {\n // An empty prompt on a TUI that can't prefill has nothing to paste and no\n // parked input to leave editable — deliver nothing (a raw-mode wake just\n // spawns the terminal for the human).\n if (text === \"\" && !this.adapter.capabilities.prefill) return;\n if (!this.wroteToProcess) {\n await this.awaitRawTuiInputLive();\n if (this._toreDown) return;\n this.wroteToProcess = true;\n }\n this.writeStdin(this.adapter.encodePromptBytes(text));\n if (this.turn.promptDelivery === \"prefill\") return;\n // Retain the submitted text so a delivery failure can be recovered by\n // respawning and redelivering it verbatim. Prefill returns above: a parked\n // prefill is waiting on a human by design, never a failure.\n this.deliveredTexts.push(text);\n // The Enter goes in a separate write after a settle window — folded into\n // the same chunk as the paste, the CLI can treat it as part of the paste\n // burst and leave the prompt parked unsubmitted in the input box.\n await sleep(resolveSubmitSettleMs());\n if (this._toreDown) return;\n this.writeStdin(\"\\r\");\n // The submit nudge is disarmed by the first transcript record proving the\n // turn started; a raw-terminal TUI produces no such evidence, so arming it\n // would re-press Enter for the full window. Only arm with a trusted source.\n if (this.adapter.capabilities.structuredEvents) this.armSubmitNudge();\n }\n\n private async feedPrompt(): Promise<void> {\n if (typeof this.turnPrompt === \"string\") {\n await this.deliverPrompt(this.turnPrompt);\n return;\n }\n for await (const message of this.turnPrompt) {\n const content = message.message.content;\n const text = typeof content === \"string\" ? content : renderPromptContentText(content);\n await this.deliverPrompt(text);\n }\n }\n\n /**\n * Even as a separate write, the submitting Enter can race CLI startup and\n * be swallowed, leaving the pasted prompt parked in the input box with\n * nothing to un-park it (the 45s parked-TUI watchdog only reports status).\n * Until the first transcript record proves the turn started, re-press Enter\n * on a bounded interval. Enter on an empty or mid-turn input box is a no-op.\n * Deliberate trade-off (same as the plan-dialog auto-accept below): a press\n * can accept the default of an unexpected startup dialog — in a headless\n * pod that unblocks the run rather than parking it forever.\n *\n * Two phases: SUBMIT_NUDGE_MAX_PRESSES fast presses for the swallowed-Enter\n * race, then a slow cadence out to SUBMIT_NUDGE_WINDOW_MS for startup\n * dialogs that render late on cold pods (the folder-trust dialog's default\n * is the accept option, so one late Enter un-parks the run).\n *\n * Exhausting the window without a transcript record is NOT a shrug — Enter\n * cannot clear every startup dialog (one needing an arrow-key selection eats\n * every press), and an autonomous card has no human at the terminal and no\n * next message coming, so the old silent give-up parked it indefinitely. The\n * window now ends in an explicit delivery failure the harness recovers from.\n */\n private armSubmitNudge(): void {\n if (this.submitNudgeTimer) return;\n this.pendingSubmitNudge = true;\n const startedAt = Date.now();\n const { intervalMs, slowIntervalMs, maxPresses, windowMs } = resolveSubmitNudgeTiming();\n let presses = 0;\n const press = (): void => {\n if (this._toreDown || !this.pendingSubmitNudge) {\n this.disarmSubmitNudge();\n return;\n }\n if (Date.now() - startedAt >= windowMs) {\n this.disarmSubmitNudge();\n this.handleSubmitDeliveryFailure(presses, windowMs);\n return;\n }\n presses++;\n this.writeStdin(\"\\r\");\n if (presses === maxPresses && this.submitNudgeTimer) {\n clearInterval(this.submitNudgeTimer);\n this.submitNudgeTimer = setInterval(press, slowIntervalMs);\n }\n };\n this.submitNudgeTimer = setInterval(press, intervalMs);\n }\n\n /**\n * The nudge window expired with the prompt still parked in the input box.\n * Record it, log the presses-used telemetry (so fleet audits can measure how\n * often Enter is actually being swallowed), surface it on the card, and END\n * THE TURN so the harness's drain completes and can respawn + redeliver —\n * otherwise the consumer stays parked on a queue that will never produce an\n * event. `clean: false` routes the session to teardown, not to parking.\n */\n private handleSubmitDeliveryFailure(pressesUsed: number, windowMs: number): void {\n if (this._promptDeliveryFailed) return;\n this._promptDeliveryFailed = true;\n const seconds = Math.round(windowMs / 1000);\n process.stderr.write(\n `[PtySession] prompt submission failed — no transcript record after ${pressesUsed} Enter ` +\n `press(es) over ${seconds}s; the prompt is parked unsubmitted in the TUI input\\n`,\n );\n this.bridge?.notifyPromptDeliveryFailure?.(\n `⚠️ The agent's prompt was pasted into the Claude TUI but never submitted — ` +\n `${pressesUsed} Enter press(es) over ${seconds}s produced no turn. ` +\n `Restarting the TUI and redelivering the prompt.`,\n );\n this.endTurn(false);\n }\n\n private disarmSubmitNudge(): void {\n this.pendingSubmitNudge = false;\n if (this.submitNudgeTimer) {\n clearInterval(this.submitNudgeTimer);\n this.submitNudgeTimer = null;\n }\n }\n\n private handleProgress(progress: ToolProgress): void {\n // The ExitPlanMode PostToolUse envelope is the proof the plan-approval\n // dialog was answered — the tool only executes after approval. It is the\n // one reliable stop signal for the auto-accept presses (see\n // armPlanDialogAutoAccept for why transcript records are NOT one).\n if (this.pendingPlanApproval && progress.tool_name === \"ExitPlanMode\") {\n this.disarmPlanDialogAutoAccept();\n }\n // A tool actually ran: the turn is unambiguously underway even if the\n // transcript records haven't flushed yet (the CLI batches them).\n if (this.pendingSubmitNudge) this.disarmSubmitNudge();\n this.pushEvent({\n type: \"tool_progress\",\n ...(progress.tool_name === undefined ? {} : { tool_name: progress.tool_name }),\n ...(progress.elapsed_time_seconds === undefined\n ? {}\n : { elapsed_time_seconds: progress.elapsed_time_seconds }),\n });\n }\n\n /**\n * PreToolUse request from the hook helper → the runner's `canUseTool`\n * verdict. ExitPlanMode is the Conveyor plan-exit gate (validation +\n * identification trigger run inside the callback); Bash is answered by\n * Conveyor's per-mode policy so plan mode never parks on the CLI approval\n * dialog; AskUserQuestion is observed and always allowed. Absent callback →\n * allow (mirrors the SDK default).\n */\n private async handlePreToolUse(request: PreToolUseRequest): Promise<PreToolUseVerdict> {\n // The model is calling a tool, so the turn started — earliest proof we get,\n // ahead of both the transcript flush and the PostToolUse envelope.\n if (this.pendingSubmitNudge) this.disarmSubmitNudge();\n if (request.tool_name === \"AskUserQuestion\") {\n // Observe-only: the TUI renders the questionnaire and collects the\n // answer natively. Never delegate to `canUseTool` — the SDK-era handler\n // there parks on a blocking RPC, which under PTY would time the hook\n // out and deny the questionnaire. Disarm both press loops first: a\n // pending Enter press would answer the dialog's default option.\n this.disarmSubmitNudge();\n this.disarmPlanDialogAutoAccept();\n const questions = parseUserQuestions(request.tool_input);\n this.pushEvent({ type: \"user_question\", questions });\n // The hook is the ONLY ask-time signal — the transcript record of this\n // tool_use doesn't flush until the questionnaire resolves — so the web\n // question card must be emitted here to render while it matters.\n this.emitSyntheticQuestionCard(questions);\n return { decision: \"allow\" };\n }\n const canUseTool = this.turn.canUseTool;\n let verdict: PreToolUseVerdict;\n if (canUseTool) {\n const result = await canUseTool(request.tool_name, request.tool_input);\n verdict =\n result.behavior === \"allow\"\n ? { decision: \"allow\" }\n : { decision: \"deny\", reason: result.message };\n } else {\n verdict = { decision: \"allow\" };\n }\n if (\n verdict.decision === \"allow\" &&\n request.tool_name === \"ExitPlanMode\" &&\n this.turn.planDialogAutoAccept\n ) {\n this.armPlanDialogAutoAccept();\n }\n return verdict;\n }\n\n /**\n * A hook \"allow\" does not bypass the CLI's plan-approval dialog — it renders\n * right after the verdict and parks the turn until answered. Press Enter\n * (default option approves) until the ExitPlanMode PostToolUse envelope\n * proves the dialog was answered (handleProgress), or the turn ends, over a\n * two-phase fast/slow window.\n *\n * Transcript records are deliberately NOT a stop signal: the CLI flushes the\n * assistant record holding the ExitPlanMode tool_use ~0.5s AFTER the\n * PreToolUse hook fires (verified live on 2.1.202), so when the Conveyor\n * verdict resolves quickly that record lands right after arming — a\n * record-based disarm then cancels the presses before the first one fires,\n * which is exactly the failure that parked auto cards on the approval\n * dialog until a human pressed Enter.\n */\n private armPlanDialogAutoAccept(): void {\n if (this.pendingPlanApproval) return;\n this.pendingPlanApproval = true;\n const startedAt = Date.now();\n const { firstPressMs, intervalMs, slowIntervalMs, fastWindowMs, windowMs } =\n resolvePlanDialogTiming();\n const press = (): void => {\n if (this._toreDown || !this.pendingPlanApproval) return;\n const elapsed = Date.now() - startedAt;\n if (elapsed >= windowMs) {\n // Give up, loudly: without the PostToolUse envelope the dialog is\n // (most likely) still parked — leave a trace for diagnosis.\n process.stderr.write(\n \"[PtySession] plan-dialog auto-accept window expired without ExitPlanMode executing — the approval dialog may still be parked\\n\",\n );\n this.disarmPlanDialogAutoAccept();\n return;\n }\n this.writeStdin(\"\\r\");\n const interval = elapsed < fastWindowMs ? intervalMs : slowIntervalMs;\n this.planApprovalTimer = setTimeout(press, interval);\n };\n this.planApprovalTimer = setTimeout(press, firstPressMs);\n }\n\n private disarmPlanDialogAutoAccept(): void {\n this.pendingPlanApproval = false;\n if (this.planApprovalTimer) {\n clearTimeout(this.planApprovalTimer);\n this.planApprovalTimer = null;\n }\n }\n\n private handleTranscriptEvent(event: HarnessEvent): void {\n // End-of-turn means the dialog is moot (answered, or the CLI moved on).\n // The mid-turn stop signal is the ExitPlanMode PostToolUse envelope in\n // handleProgress — see armPlanDialogAutoAccept for why arbitrary\n // transcript records must not disarm.\n if (this.pendingPlanApproval && event.type === \"result\") {\n this.disarmPlanDialogAutoAccept();\n }\n // Model output proves the submitted prompt actually started a turn — the\n // submit nudge has done its job. Deliberately NOT \"any transcript record\":\n // a `--resume` spawn tails from EOF, so a `system` record the CLI writes at\n // boot lands after our start offset and would disarm the nudge while the\n // prompt is still parked unsubmitted — the exact false-positive that turns\n // a recoverable swallowed Enter into a silent indefinite park. Extra Enter\n // presses against an already-running turn are harmless (the input box is\n // empty), so erring toward a late disarm is the safe direction.\n if (this.pendingSubmitNudge && (event.type === \"assistant\" || event.type === \"result\")) {\n this.disarmSubmitNudge();\n }\n this.synthesizeRateLimitFromBanner(event);\n this.pushEvent(event);\n if (event.type === \"result\") {\n this.sawResult = true;\n for (const listener of this.idleListeners) listener();\n // A transcript `result` marks end-of-turn. End the turn (close the\n // stream so the consumer's generator completes — mirroring the SDK\n // harness's per-query model) but keep the process alive: interactive\n // `claude` does not exit after a result, so the harness parks it for the\n // next turn instead of tearing it down.\n this.endTurn(true);\n }\n }\n\n /**\n * The interactive CLI reports a hard usage cap only as a conversation banner\n * (\"You've hit your weekly limit · resets 7am (UTC)\") — it never writes a\n * structured rate_limit_event to the transcript. Recognize the banner in\n * assistant/result text and push the same harness-level event the SDK\n * harness emits, so cap handling (key cycle → pause) is one code path.\n * Once per session: the CLI repeats the banner on every rejected turn.\n */\n private synthesizeRateLimitFromBanner(event: HarnessEvent): void {\n if (this.limitBannerReported) return;\n let text: string | undefined;\n if (event.type === \"assistant\") {\n text = event.message.content\n .map((block) => block.text ?? \"\")\n .filter(Boolean)\n .join(\"\\n\");\n } else if (event.type === \"result\" && event.subtype === \"success\") {\n text = event.result;\n }\n if (!text) return;\n const match = matchUsageLimitBanner(text);\n if (!match) return;\n this.limitBannerReported = true;\n this.pushEvent({\n type: \"rate_limit_event\",\n rate_limit_info: {\n status: \"rejected\",\n rateLimitType: match.rateLimitType,\n ...(match.resetsAtEpochSeconds === undefined\n ? {}\n : { resetsAt: match.resetsAtEpochSeconds }),\n },\n });\n }\n\n private async finalizeOnExit(exitCode: number): Promise<void> {\n // Ship any buffered terminal tail (exit message, final repaint) before the\n // relay goes quiet — runs even on the teardown path, where dispose() below\n // may already have flushed (flush is a no-op when empty).\n this.coalescer?.flush();\n // The process is gone: block any reuse of this session regardless of which\n // path we take below.\n this.exited = true;\n // A teardown-driven kill (stop/softStop/abort) fires this exit handler, but\n // the turn is already discarded — pushing a synthetic error result here\n // would be spurious and would race teardown()'s queue close.\n if (this._toreDown) return;\n if (this.tailer) {\n this.tailer.close();\n await this.tailer.flush();\n }\n if (!this.adapter.capabilities.structuredEvents) {\n // Raw terminal mode: process exit IS the end-of-turn signal (there is no\n // transcript `result`). A clean exit is a successful turn; any other code\n // folds the terminal tail into an error result. endTurn closes the turn's\n // stream — the exit bookkeeping below still runs for both paths.\n if (exitCode === 0) {\n this.pushEvent({ type: \"result\", subtype: \"success\", result: \"\", total_cost_usd: 0 });\n } else {\n this.pushEvent({\n type: \"result\",\n subtype: \"error\",\n errors: this.adapter.buildExitErrors(exitCode, this.recentOutput),\n });\n }\n this.endTurn(exitCode === 0);\n } else if (!this.sawResult && this.activeQueue) {\n // A mid-turn crash with no result: fold the swallowed terminal tail into an\n // error result so a bare exit (missing `claude` binary, auth stop, unknown\n // flag) is diagnosable from the logs rather than only the live S5 terminal.\n // Only meaningful while a turn is draining — a parked-window death has no\n // consumer, and the harness's exit listener handles teardown + ended there.\n this.activeQueue.push({\n type: \"result\",\n subtype: \"error\",\n errors: this.adapter.buildExitErrors(exitCode, this.recentOutput),\n });\n }\n for (const listener of this.exitListeners) listener(exitCode);\n this.activeQueue?.close();\n this.activeQueue = null;\n }\n}\n","/**\n * The Conveyor opencode events plugin — the trusted structured-event source\n * for the interactive opencode TUI.\n *\n * opencode's client engine loads config-declared plugins and awaits their\n * `event` hook for every bus event (verified live on 1.18.4 AND 1.18.15 with a\n * real tool turn: every `message.part.updated` — text, step-start,\n * tool pending→running→completed, step-finish — plus the session.status/idle\n * lifecycle arrived in the hook). The plugin appends each event as one NDJSON\n * line to the sink file named by CONVEYOR_OPENCODE_EVENTS_FILE, and the PTY\n * session tails that file exactly the way it tails Claude's transcript JSONL.\n *\n * The source is EMBEDDED as a string and written to the session temp dir at\n * spawn time rather than shipped as a dist asset: it versions with this file,\n * needs no tsup asset plumbing, and the `file://` config specifier it is\n * loaded through was probe-verified. Design notes:\n * - `message.part.delta` is skipped IN the plugin — the hook is awaited per\n * event, so per-token deltas would be pure sink bloat.\n * - A missing sink env makes the plugin a no-op instead of throwing: a\n * plugin error inside opencode must never take down a human's session.\n * - appendFileSync keeps event ordering without an async queue; events are\n * small and local, and the same call pattern was used by the live probe.\n */\n\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/** Child env var naming the NDJSON sink the plugin appends to. */\nexport const OPENCODE_EVENTS_FILE_ENV = \"CONVEYOR_OPENCODE_EVENTS_FILE\";\n\nexport const CONVEYOR_PLUGIN_SOURCE = `import { appendFileSync } from \"node:fs\";\n\nexport const ConveyorEventsPlugin = async () => ({\n event: async ({ event }) => {\n const sink = process.env.${OPENCODE_EVENTS_FILE_ENV};\n if (!sink || !event || event.type === \"message.part.delta\") return;\n try {\n appendFileSync(sink, JSON.stringify(event) + \"\\\\n\");\n } catch {\n // Never let a sink hiccup break the user's opencode session.\n }\n },\n});\n`;\n\n/**\n * Write the plugin into `tempDir` and return its path plus the sink path the\n * spawned TUI's env must carry. The sink file itself is created empty so the\n * tailer has something to stat before the first event.\n */\nexport async function stageOpenCodePlugin(\n tempDir: string,\n): Promise<{ pluginPath: string; eventsSinkPath: string }> {\n const pluginPath = join(tempDir, \"conveyor-events-plugin.mjs\");\n const eventsSinkPath = join(tempDir, \"opencode-events.ndjson\");\n await writeFile(pluginPath, CONVEYOR_PLUGIN_SOURCE, \"utf8\");\n await writeFile(eventsSinkPath, \"\", \"utf8\");\n return { pluginPath, eventsSinkPath };\n}\n","/**\n * opencode headless event mapping — `opencode run --format json` NDJSON lines\n * into HarnessEvents.\n *\n * Pure and side-effect free so the whole mapping is unit-testable without\n * spawning anything. The shapes below were captured from opencode 1.18.15:\n *\n * {\"type\":\"step_start\",\"timestamp\":…,\"sessionID\":\"ses_…\",\"part\":{…,\"type\":\"step-start\"}}\n * {\"type\":\"text\",\"…\",\"part\":{\"type\":\"text\",\"text\":\"HEADLESS\",\"time\":{…}}}\n * {\"type\":\"tool_use\",\"…\",\"part\":{\"type\":\"tool\",\"tool\":\"write\",\"state\":{\"status\":\"completed\",\"output\":\"…\"}}}\n * {\"type\":\"step_finish\",\"…\",\"part\":{\"type\":\"step-finish\", …usage…}}\n *\n * A run emits one or more step_start/…/step_finish groups and then exits; the\n * process exit is the end of the turn, so `result` is synthesized by the caller\n * rather than appearing in the stream.\n */\n\nimport type { HarnessEvent } from \"../types.js\";\n\n/** One parsed NDJSON line. Deliberately loose — opencode may add fields. */\nexport interface OpenCodeEvent {\n type?: string;\n timestamp?: number;\n sessionID?: string;\n /** Present on `type: \"error\"` — see errorMessageOf. */\n error?: unknown;\n part?: {\n type?: string;\n text?: string;\n tool?: string;\n state?: { status?: string; output?: unknown; input?: unknown; error?: unknown };\n tokens?: unknown;\n cost?: unknown;\n [k: string]: unknown;\n };\n [k: string]: unknown;\n}\n\n/** Token/cost totals accumulated across a run's step_finish parts. */\nexport interface OpenCodeUsage {\n inputTokens: number;\n outputTokens: number;\n totalCostUsd: number;\n}\n\n/**\n * Parse one NDJSON line. Returns null for blank lines and for anything that is\n * not JSON — `--format json` writes events to stdout, but a stray banner or\n * warning must never abort the turn.\n */\nexport function parseOpenCodeLine(line: string): OpenCodeEvent | null {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"{\")) return null;\n try {\n return JSON.parse(trimmed) as OpenCodeEvent;\n } catch {\n return null;\n }\n}\n\nfunction numberAt(source: unknown, ...keys: string[]): number {\n let cursor: unknown = source;\n for (const key of keys) {\n if (typeof cursor !== \"object\" || cursor === null) return 0;\n cursor = (cursor as Record<string, unknown>)[key];\n }\n return typeof cursor === \"number\" && Number.isFinite(cursor) ? cursor : 0;\n}\n\n/**\n * Fold a step_finish part's usage into a running total. opencode nests token\n * counts under `tokens` and cost under `cost`; both are treated as optional\n * because a provider that reports neither must not zero the accumulator.\n */\nexport function accumulateUsage(event: OpenCodeEvent, into: OpenCodeUsage): void {\n const part = event.part;\n if (!part) return;\n into.inputTokens += numberAt(part.tokens, \"input\");\n into.outputTokens += numberAt(part.tokens, \"output\");\n const cost = part.cost;\n if (typeof cost === \"number\" && Number.isFinite(cost)) into.totalCostUsd += cost;\n}\n\n/**\n * Map one opencode event to a HarnessEvent, or null when it carries no\n * information the runner consumes (step boundaries, unknown future types).\n *\n * Tool names arrive namespaced by their MCP server — a Conveyor tool registered\n * as `post_to_chat` is reported by opencode as `conveyor_post_to_chat`. The name\n * is passed through verbatim: the runner's activity summaries are display-only,\n * and rewriting it would misreport what actually ran.\n */\nexport function mapOpenCodeEvent(event: OpenCodeEvent): HarnessEvent | null {\n const part = event.part;\n if (!part) return null;\n if (part.type === \"text\") return mapTextPart(part);\n if (part.type === \"tool\") return mapToolPart(part);\n return null;\n}\n\ntype OpenCodePart = NonNullable<OpenCodeEvent[\"part\"]>;\n\nfunction mapTextPart(part: OpenCodePart): HarnessEvent | null {\n const text = typeof part.text === \"string\" ? part.text : \"\";\n // opencode emits whitespace-only text parts between tool calls; they would\n // otherwise become empty assistant messages in card chat.\n if (text.trim() === \"\") return null;\n return {\n type: \"assistant\",\n message: { role: \"assistant\", content: [{ type: \"text\", text }] },\n };\n}\n\nfunction mapToolPart(part: OpenCodePart): HarnessEvent | null {\n const status = part.state?.status;\n // Only terminal states are reported: opencode re-emits a part as it moves\n // pending → running → completed, and the runner's activity batching would\n // otherwise count one call several times.\n if (status !== \"completed\" && status !== \"error\") return null;\n // A tool call reaches the runner the same way the Claude transcript delivers\n // one — an assistant message carrying a `tool_use` content block, which\n // event-handlers turns into a `tool_use` event and an activity summary.\n return {\n type: \"assistant\",\n message: {\n role: \"assistant\",\n content: [\n {\n type: \"tool_use\",\n name: typeof part.tool === \"string\" ? part.tool : \"unknown\",\n input: part.state?.input ?? {},\n ...(typeof part.id === \"string\" ? { id: part.id } : {}),\n },\n ],\n },\n };\n}\n\n/** Tool output is free-form; keep text as-is and JSON-encode anything else. */\nexport function stringifyToolOutput(output: unknown): string {\n if (output === undefined || output === null) return \"\";\n if (typeof output === \"string\") return output;\n try {\n return JSON.stringify(output);\n } catch {\n return String(output);\n }\n}\n\n/**\n * A provider/runtime failure opencode reported as a first-class event, or null.\n *\n * A credential failure is the common case and it arrives HERE, on stdout, not on\n * stderr — which is empty. Without reading this event an auth failure surfaces as\n * a bare \"exited with code 1\" and a card gives no clue why (observed live: an\n * invalid OpenAI key produced exactly that). opencode redacts the credential in\n * its own message before we ever see it.\n */\nexport function errorMessageOf(event: OpenCodeEvent): string | null {\n if (event.type !== \"error\") return null;\n const error = event.error as\n | { name?: unknown; data?: { message?: unknown; statusCode?: unknown } }\n | undefined;\n const message = typeof error?.data?.message === \"string\" ? error.data.message : null;\n const name = typeof error?.name === \"string\" ? error.name : \"error\";\n const status =\n typeof error?.data?.statusCode === \"number\" ? ` (HTTP ${error.data.statusCode})` : \"\";\n return message ? `${name}${status}: ${message}` : `${name}${status}`;\n}\n\n/** The session id opencode assigned, for `--session` resume on the next turn. */\nexport function sessionIdOf(event: OpenCodeEvent): string | null {\n return typeof event.sessionID === \"string\" && event.sessionID.length > 0 ? event.sessionID : null;\n}\n\n// ── Plugin bus events ────────────────────────────────────────────────────\n//\n// The Conveyor opencode plugin (see ./plugin.ts) appends the CLIENT engine's\n// bus events to an NDJSON sink the PTY session tails. Bus events wrap their\n// payload in `properties` (the server's SSE stream uses `data` — a different\n// surface; do not conflate them). `message.part.updated` carries the SAME\n// `part` shapes as the NDJSON stream above, so the mapping and usage helpers\n// are shared: `busPartOf` unwraps the part and callers feed `{ part }` back\n// into `mapOpenCodeEvent` / `accumulateUsage`.\n//\n// Parts do NOT carry the author's role. `message.updated` (which the bus emits\n// BEFORE a message's parts — verified in the committed fixtures) does, via\n// `properties.info.{id,role}` — consumers map roles first and only surface\n// parts of assistant messages, or the user's own pasted prompt would echo back\n// into card chat as an assistant message.\n\n/** One parsed plugin-bus NDJSON line. Loose — opencode may add fields. */\nexport interface OpenCodeBusEvent {\n type?: string;\n properties?: Record<string, unknown> & {\n sessionID?: string;\n status?: { type?: string };\n info?: { id?: string; role?: string; sessionID?: string };\n part?: OpenCodeEvent[\"part\"] & { messageID?: string };\n };\n}\n\n/** Parse one sink line. Null for blanks and anything that is not JSON. */\nexport function parseBusLine(line: string): OpenCodeBusEvent | null {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"{\")) return null;\n try {\n return JSON.parse(trimmed) as OpenCodeBusEvent;\n } catch {\n return null;\n }\n}\n\n/** The opencode session id the event belongs to, from whichever field has it. */\nexport function busSessionIdOf(event: OpenCodeBusEvent): string | null {\n const direct = event.properties?.sessionID;\n if (typeof direct === \"string\" && direct.length > 0) return direct;\n const viaInfo = event.properties?.info?.sessionID;\n return typeof viaInfo === \"string\" && viaInfo.length > 0 ? viaInfo : null;\n}\n\n/**\n * The turn-end signal. 1.18.4 emits BOTH `session.idle` and\n * `session.status {type:\"idle\"}` back-to-back; 1.18.15 emits only the latter —\n * consumers must accept either, and end a turn at most once.\n */\nexport function isIdleEvent(event: OpenCodeBusEvent): boolean {\n if (event.type === \"session.idle\") return true;\n return event.type === \"session.status\" && event.properties?.status?.type === \"idle\";\n}\n\n/** The turn-started signal (`session.status {type:\"busy\"}`). */\nexport function isBusyEvent(event: OpenCodeBusEvent): boolean {\n return event.type === \"session.status\" && event.properties?.status?.type === \"busy\";\n}\n\n/** The message info from a `message.updated` event, or null. */\nexport function busInfoOf(event: OpenCodeBusEvent): { id?: string; role?: string } | null {\n if (event.type !== \"message.updated\") return null;\n return event.properties?.info ?? null;\n}\n\n/** The part from a `message.part.updated` event, or null. */\nexport function busPartOf(\n event: OpenCodeBusEvent,\n): NonNullable<OpenCodeBusEvent[\"properties\"]>[\"part\"] | null {\n if (event.type !== \"message.part.updated\") return null;\n return event.properties?.part ?? null;\n}\n\n/**\n * Build the terminal `result` for a finished run. opencode's stream has no\n * result record — the process exiting IS the end of the turn — so exit code and\n * the accumulated usage are all we have.\n */\nexport function buildResultEvent(\n exitCode: number,\n usage: OpenCodeUsage,\n assistantText: string,\n stderrTail: string,\n reportedError?: string | null,\n): HarnessEvent {\n if (exitCode === 0) {\n return {\n type: \"result\",\n subtype: \"success\",\n // The runner substitutes \"Task completed.\" for an empty summary, so a run\n // that only used tools still reads sensibly in chat.\n result: assistantText,\n total_cost_usd: usage.totalCostUsd,\n };\n }\n // A reported error event is far more useful than the exit code, so it leads.\n const errors = reportedError ? [reportedError] : [`opencode run exited with code ${exitCode}`];\n if (stderrTail.trim()) errors.push(`stderr:\\n${stderrTail.trim()}`);\n return { type: \"result\", subtype: \"error\", errors };\n}\n","/**\n * OpenCodeEventSource — turns the Conveyor plugin's bus-event sink into\n * HarnessEvents for a PTY session.\n *\n * Stateful where the pure mappers in ./events.ts cannot be:\n * - roles: parts carry no author role; `message.updated` (emitted BEFORE a\n * message's parts) does. Only assistant-authored parts become events, or\n * the user's own pasted prompt would echo into card chat.\n * - turn boundaries: the bus has no `result` record. A turn is\n * busy → … → idle (`session.status`, plus a separate `session.idle` on\n * 1.18.4 — either counts, and a turn ends at most once); on idle a\n * `result` is SYNTHESIZED from the accumulated step-finish usage and\n * assistant text, which is what lets PtySession's existing\n * result-ends-turn machinery run unchanged.\n * - session identity: the first event latches opencode's `ses_…` id so the\n * session can report it (synthetic `system init`) and later spawns can\n * `--session` back into the same conversation.\n */\n\nimport type { PtyChatEventPayload } from \"@project/shared\";\nimport type { HarnessEvent } from \"../types.js\";\nimport {\n accumulateUsage,\n buildResultEvent,\n busInfoOf,\n busPartOf,\n busSessionIdOf,\n isBusyEvent,\n isIdleEvent,\n mapOpenCodeEvent,\n stringifyToolOutput,\n type OpenCodeBusEvent,\n type OpenCodeUsage,\n} from \"./events.js\";\n\n/** Bound on the messageID→role map; a session's live window never needs more. */\nconst MAX_TRACKED_MESSAGES = 200;\nconst CHAT_TEXT_MAX = 16_000;\nconst CHAT_TOOL_INPUT_MAX = 1_900;\nconst CHAT_TOOL_OUTPUT_MAX = 1_900;\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max)}…` : text;\n}\n\nfunction compactJson(value: unknown): string {\n try {\n return JSON.stringify(value ?? {}).slice(0, CHAT_TOOL_INPUT_MAX);\n } catch {\n return String(value).slice(0, CHAT_TOOL_INPUT_MAX);\n }\n}\n\nfunction partString(part: Record<string, unknown>, key: string): string | null {\n const value = part[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\ntype OpenCodeBusPart = NonNullable<ReturnType<typeof busPartOf>>;\ntype RelayedToolStatus = \"running\" | \"completed\" | \"error\";\n\nfunction relayedToolStatus(status: string | undefined): RelayedToolStatus | null {\n return status === \"running\" || status === \"completed\" || status === \"error\" ? status : null;\n}\n\nexport class OpenCodeEventSource {\n private readonly roles = new Map<string, string>();\n private usage: OpenCodeUsage = { inputTokens: 0, outputTokens: 0, totalCostUsd: 0 };\n private assistantText = \"\";\n /** Busy has been seen and idle has not — a turn is in flight on the bus. */\n private active = false;\n private latchedSessionId: string | null = null;\n private readonly relayedTextParts = new Set<string>();\n private readonly relayedToolUses = new Set<string>();\n private readonly relayedToolResults = new Set<string>();\n\n constructor(\n private readonly emit: (event: HarnessEvent) => void,\n private readonly onSessionId?: (id: string) => void,\n private readonly emitChat?: (event: PtyChatEventPayload) => void,\n ) {}\n\n /** The opencode-assigned session id, once any event has carried it. */\n get sessionId(): string | null {\n return this.latchedSessionId;\n }\n\n /**\n * Ingest one parsed sink record. Self-arming: `busy` opens a turn (resetting\n * the accumulators) whether it came from our pasted prompt or a human typing\n * into the parked TUI — the passive case is exactly why turn state cannot\n * only reset from beginTurn.\n */\n handleRecord(raw: unknown): void {\n if (typeof raw !== \"object\" || raw === null) return;\n const event = raw as OpenCodeBusEvent;\n this.latchSessionId(event);\n const info = busInfoOf(event);\n if (info?.id && info.role) this.trackRole(info.id, info.role);\n if (isBusyEvent(event)) {\n if (!this.active) this.beginBusTurn();\n return;\n }\n if (isIdleEvent(event)) {\n this.finishBusTurn();\n return;\n }\n if (event.type === \"session.error\") {\n this.finishBusTurn(describeSessionError(event));\n return;\n }\n this.handlePart(event);\n }\n\n private handlePart(event: OpenCodeBusEvent): void {\n const part = busPartOf(event);\n if (!part) return;\n // A part can arrive before any session.status (observed: the assistant's\n // first parts race the busy flip) — treat it as turn-opening too.\n if (!this.active) this.beginBusTurn();\n if (typeof part.messageID !== \"string\") return;\n const role = this.roles.get(part.messageID);\n if (role === \"user\") {\n this.relayTextPart(part, \"user_text\");\n return;\n }\n if (role !== \"assistant\") return;\n this.relayAssistantPart(part);\n accumulateUsage({ part }, this.usage);\n const mapped = mapOpenCodeEvent({ part });\n if (!mapped) return;\n this.emit(mapped);\n if (mapped.type === \"assistant\") {\n const block = mapped.message.content[0];\n if (block?.type === \"text\" && block.text) this.assistantText += block.text;\n }\n }\n\n private beginBusTurn(): void {\n this.active = true;\n this.usage = { inputTokens: 0, outputTokens: 0, totalCostUsd: 0 };\n this.assistantText = \"\";\n this.relayedTextParts.clear();\n this.relayedToolUses.clear();\n this.relayedToolResults.clear();\n }\n\n /** Idle (or an error) closes the turn exactly once. */\n private finishBusTurn(error?: string | null): void {\n if (!this.active) return;\n this.active = false;\n this.emit(\n error\n ? buildResultEvent(1, this.usage, \"\", \"\", error)\n : buildResultEvent(0, this.usage, this.assistantText.trim(), \"\"),\n );\n this.emitChat?.({ kind: \"turn_end\" });\n }\n\n private relayAssistantPart(part: OpenCodeBusPart): void {\n if (part.type === \"text\") {\n this.relayTextPart(part, \"assistant_text\");\n return;\n }\n if (part.type === \"tool\") this.relayToolPart(part);\n }\n\n private relayToolPart(part: OpenCodeBusPart): void {\n const status = relayedToolStatus(part.state?.status);\n if (!status) return;\n const callId = truncate(partString(part, \"callID\") ?? partString(part, \"id\") ?? \"\", 100);\n const key = callId || `${part.messageID}:${partString(part, \"tool\") ?? \"unknown\"}`;\n this.relayToolUse(part, key, callId);\n if (status !== \"running\") this.relayToolResult(part, status, key, callId);\n }\n\n private relayToolUse(part: OpenCodeBusPart, key: string, callId: string): void {\n if (this.relayedToolUses.has(key)) return;\n this.relayedToolUses.add(key);\n this.emitChat?.({\n kind: \"tool_use\",\n name: truncate(partString(part, \"tool\") ?? \"unknown\", 200),\n input: compactJson(part.state?.input),\n ...(callId ? { id: callId } : {}),\n });\n }\n\n private relayToolResult(\n part: OpenCodeBusPart,\n status: Exclude<RelayedToolStatus, \"running\">,\n key: string,\n callId: string,\n ): void {\n if (this.relayedToolResults.has(key)) return;\n this.relayedToolResults.add(key);\n this.emitChat?.({\n kind: \"tool_result\",\n ...(callId ? { toolUseId: callId } : {}),\n output: truncate(\n stringifyToolOutput(status === \"error\" ? part.state?.error : part.state?.output),\n CHAT_TOOL_OUTPUT_MAX,\n ),\n isError: status === \"error\",\n });\n }\n\n private relayTextPart(part: OpenCodeBusPart, kind: \"user_text\" | \"assistant_text\"): void {\n const text = typeof part.text === \"string\" ? part.text : \"\";\n if (text.trim() === \"\") return;\n const key = partString(part, \"id\") ?? `${part.messageID}:${kind}`;\n if (this.relayedTextParts.has(key)) return;\n this.relayedTextParts.add(key);\n this.emitChat?.({\n kind,\n text: truncate(kind === \"user_text\" ? text.trim() : text, CHAT_TEXT_MAX),\n });\n }\n\n private latchSessionId(event: OpenCodeBusEvent): void {\n if (this.latchedSessionId) return;\n const id = busSessionIdOf(event);\n if (!id) return;\n this.latchedSessionId = id;\n this.onSessionId?.(id);\n }\n\n private trackRole(id: string, role: string): void {\n this.roles.set(id, role);\n if (this.roles.size > MAX_TRACKED_MESSAGES) {\n const oldest = this.roles.keys().next().value;\n if (oldest !== undefined) this.roles.delete(oldest);\n }\n }\n}\n\n/** Best-effort message for a `session.error` bus event. */\nfunction describeSessionError(event: OpenCodeBusEvent): string {\n const error = (event.properties as { error?: { message?: unknown } } | undefined)?.error;\n if (error && typeof error.message === \"string\") return error.message;\n return `opencode reported a session error: ${JSON.stringify(event.properties ?? {}).slice(0, 300)}`;\n}\n","/**\n * AsyncEventQueue — bridges callback-style producers (transcript tailer, hook\n * socket) into a single async-generator consumer. Producers call `push`;\n * the consumer drains via the async generator returned by `drain()`.\n */\nexport class AsyncEventQueue<T> {\n private readonly items: T[] = [];\n private closed = false;\n private wake: (() => void) | null = null;\n\n push(item: T): void {\n if (this.closed) return;\n this.items.push(item);\n this.signal();\n }\n\n close(): void {\n this.closed = true;\n this.signal();\n }\n\n get isClosed(): boolean {\n return this.closed;\n }\n\n private signal(): void {\n const wake = this.wake;\n if (wake) {\n this.wake = null;\n wake();\n }\n }\n\n async *drain(): AsyncGenerator<T, void> {\n while (!this.closed || this.items.length > 0) {\n if (this.items.length > 0) {\n const item = this.items.shift();\n if (item !== undefined) yield item;\n continue;\n }\n await new Promise<void>((resolve) => {\n this.wake = resolve;\n });\n }\n }\n}\n","/**\n * Unix-domain socket server that receives hook envelopes from the hook helper:\n *\n * - PostToolUse progress envelopes (fire-and-forget) → `tool_progress` events\n * - PreToolUse requests (`kind: \"pre_tool_use\"`) → request/response: the\n * handler's verdict is written back on the SAME connection, correlated by\n * `id`, so the helper can print a permissionDecision for the CLI.\n *\n * Only newline-delimited JSON envelopes are parsed, and malformed lines are\n * dropped — raw PTY stdout is never parsed here.\n */\n\nimport { createServer, type Server, type Socket } from \"node:net\";\nimport { unlink } from \"node:fs/promises\";\n\nexport interface ToolProgress {\n tool_name?: string;\n elapsed_time_seconds?: number;\n}\n\nexport interface PreToolUseRequest {\n id: string;\n tool_name: string;\n tool_input: Record<string, unknown>;\n}\n\nexport interface PreToolUseVerdict {\n decision: \"allow\" | \"deny\";\n reason?: string;\n}\n\nexport type HookEnvelope =\n | { kind: \"progress\"; progress: ToolProgress }\n | { kind: \"pre_tool_use\"; request: PreToolUseRequest };\n\nexport function parseEnvelope(line: string): HookEnvelope | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const record = parsed as Record<string, unknown>;\n\n if (record.kind === \"pre_tool_use\") {\n if (typeof record.id !== \"string\" || typeof record.tool_name !== \"string\") return null;\n const toolInput =\n typeof record.tool_input === \"object\" && record.tool_input !== null\n ? (record.tool_input as Record<string, unknown>)\n : {};\n return {\n kind: \"pre_tool_use\",\n request: { id: record.id, tool_name: record.tool_name, tool_input: toolInput },\n };\n }\n\n // Legacy progress envelope: any line without a `kind` field.\n const result: ToolProgress = {};\n if (typeof record.tool_name === \"string\") result.tool_name = record.tool_name;\n if (typeof record.elapsed_time_seconds === \"number\") {\n result.elapsed_time_seconds = record.elapsed_time_seconds;\n }\n return { kind: \"progress\", progress: result };\n}\n\nexport class HookSocketServer {\n private server: Server | null = null;\n private _closed = false;\n\n constructor(\n public readonly socketPath: string,\n private readonly onProgress: (progress: ToolProgress) => void,\n private readonly onPreToolUse?: (request: PreToolUseRequest) => Promise<PreToolUseVerdict>,\n ) {}\n\n async listen(): Promise<void> {\n await unlink(this.socketPath).catch(() => undefined);\n await new Promise<void>((resolve, reject) => {\n const server = createServer((socket) => this.handleConnection(socket));\n server.on(\"error\", reject);\n server.listen(this.socketPath, () => {\n resolve();\n });\n this.server = server;\n });\n }\n\n get isClosed(): boolean {\n return this._closed;\n }\n\n async close(): Promise<void> {\n if (this._closed) return;\n this._closed = true;\n const server = this.server;\n this.server = null;\n if (server) {\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n }\n await unlink(this.socketPath).catch(() => undefined);\n }\n\n private handleConnection(socket: Socket): void {\n // Swallow connection-level errors (e.g. ECONNRESET when the hook helper is\n // killed mid-write during teardown). Without an \"error\" listener Node\n // treats it as unhandled and crashes the process.\n socket.on(\"error\", () => undefined);\n // Per-connection buffer: concurrent hook helpers each get their own\n // accumulation so interleaved chunks from separate connections can't\n // corrupt one another's lines.\n let buffer = \"\";\n socket.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString(\"utf8\");\n let index = buffer.indexOf(\"\\n\");\n while (index >= 0) {\n const line = buffer.slice(0, index);\n buffer = buffer.slice(index + 1);\n this.dispatch(line, socket);\n index = buffer.indexOf(\"\\n\");\n }\n });\n }\n\n private dispatch(line: string, socket: Socket): void {\n const envelope = parseEnvelope(line);\n if (!envelope) return;\n if (envelope.kind === \"progress\") {\n this.onProgress(envelope.progress);\n return;\n }\n void this.respondToPreToolUse(envelope.request, socket);\n }\n\n private async respondToPreToolUse(request: PreToolUseRequest, socket: Socket): Promise<void> {\n let verdict: PreToolUseVerdict;\n try {\n verdict = this.onPreToolUse\n ? await this.onPreToolUse(request)\n : { decision: \"allow\" as const };\n } catch (err) {\n verdict = {\n decision: \"deny\",\n reason: `Conveyor validation failed: ${err instanceof Error ? err.message : String(err)}. Fix the issue and try again.`,\n };\n }\n try {\n socket.write(`${JSON.stringify({ id: request.id, ...verdict })}\\n`);\n } catch {\n /* helper hung up — its own timeout fallback covers this */\n }\n }\n}\n","/**\n * Tails an NDJSON file written by another process, emitting a `HarnessEvent`\n * for each newly-appended record. Built for the Claude transcript (written by\n * the `claude` CLI under the PTY) and reused for the opencode plugin-event\n * sink — the file mechanics are identical; only the record→event mapping\n * differs, so it is a constructor parameter defaulting to the Claude one.\n *\n * All reads are serialized through a promise chain so the polling interval\n * and the final `flush()` on exit can never read overlapping byte ranges.\n */\n\nimport { open } from \"node:fs/promises\";\nimport type { HarnessEvent } from \"../types.js\";\nimport { mapTranscriptRecord } from \"./record-mapper.js\";\n\nconst POLL_INTERVAL_MS = 25;\n\nexport class JsonlTailer {\n private offset = 0;\n private buffer = \"\";\n private timer: ReturnType<typeof setInterval> | null = null;\n private chain: Promise<void> = Promise.resolve();\n private _closed = false;\n\n constructor(\n private readonly path: string,\n private readonly onEvent: (event: HarnessEvent) => void,\n /**\n * Optional raw-record hook, invoked for EVERY parsed record — including\n * ones the mapper drops (e.g. user prompts). Used by the chat PTY proxy\n * relay (which needs between-turn records too) and by the opencode event\n * source (which owns per-turn state the pure mapper cannot).\n */\n private readonly onRawRecord?: (raw: unknown) => void,\n /** Record→event mapping; defaults to the Claude transcript mapper. */\n private readonly mapRecord: (raw: unknown) => HarnessEvent | null = mapTranscriptRecord,\n ) {}\n\n /**\n * Begin tailing. Pass `fromOffset` to skip bytes already present when the\n * tail starts (used on resume so the prior session's records aren't replayed).\n */\n start(fromOffset = 0): void {\n if (this.timer) return;\n this.offset = fromOffset;\n this.timer = setInterval(() => {\n if (this._closed) return;\n void this.enqueueRead();\n }, POLL_INTERVAL_MS);\n }\n\n close(): void {\n this._closed = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n /** Read any remaining bytes and flush a trailing line without a newline. */\n async flush(): Promise<void> {\n await this.enqueueRead();\n if (this.buffer.length > 0) {\n this.emitLine(this.buffer);\n this.buffer = \"\";\n }\n }\n\n private enqueueRead(): Promise<void> {\n this.chain = this.chain.then(() => this.readOnce());\n return this.chain;\n }\n\n private async readOnce(): Promise<void> {\n let handle: Awaited<ReturnType<typeof open>> | null = null;\n try {\n handle = await open(this.path, \"r\");\n const stats = await handle.stat();\n if (stats.size <= this.offset) return;\n const length = stats.size - this.offset;\n const buf = Buffer.alloc(length);\n await handle.read(buf, 0, length, this.offset);\n this.offset = stats.size;\n this.consume(buf.toString(\"utf8\"));\n } catch {\n /* transient read error (e.g. file not yet created); retry on next poll */\n } finally {\n if (handle) await handle.close();\n }\n }\n\n private consume(chunk: string): void {\n this.buffer += chunk;\n let index = this.buffer.indexOf(\"\\n\");\n while (index >= 0) {\n const line = this.buffer.slice(0, index);\n this.buffer = this.buffer.slice(index + 1);\n this.emitLine(line);\n index = this.buffer.indexOf(\"\\n\");\n }\n }\n\n private emitLine(line: string): void {\n const trimmed = line.trim();\n if (trimmed.length === 0) return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n return;\n }\n this.onRawRecord?.(parsed);\n const event = this.mapRecord(parsed);\n if (event) this.onEvent(event);\n }\n}\n","/**\n * Pure transforms from Claude Code transcript JSONL records into\n * harness-neutral `HarnessEvent`s. This is the parity core: the events it\n * produces must match what `ClaudeCodeHarness` yields for the same logical\n * messages (see `helpers/mock-sdk.ts`).\n *\n * Transcript files are a trusted on-disk artifact written by the `claude`\n * CLI, so parsing their lines is allowed — unlike raw PTY stdout, which is\n * never parsed.\n */\n\nimport type {\n HarnessEvent,\n HarnessAssistantEvent,\n HarnessContentBlock,\n HarnessResultEvent,\n HarnessSystemInitEvent,\n} from \"../types.js\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/** Custom predicate so narrowing yields `unknown[]`, not `any[]`. */\nfunction isUnknownArray(value: unknown): value is unknown[] {\n return Array.isArray(value);\n}\n\nfunction stringField(record: Record<string, unknown>, ...keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\") return value;\n }\n return undefined;\n}\n\nfunction numberField(record: Record<string, unknown>, ...keys: string[]): number | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"number\") return value;\n }\n return undefined;\n}\n\nfunction mapSystem(record: Record<string, unknown>): HarnessEvent | null {\n if (record.subtype === \"init\") {\n const event: HarnessSystemInitEvent = {\n type: \"system\",\n subtype: \"init\",\n model: stringField(record, \"model\") ?? \"\",\n };\n const sessionId = stringField(record, \"session_id\", \"sessionId\");\n if (sessionId !== undefined) event.session_id = sessionId;\n return event;\n }\n // End-of-turn: the interactive CLI never writes the headless\n // `{\"type\":\"result\"}` record — it marks a completed turn with a\n // `turn_duration` system record (verified against live 2.1.202 transcripts,\n // where result records appear in 0 of 95 sessions). Map it to the result\n // event the harness keys every turn boundary on (endTurn/parking, idle\n // status flips); without this, PTY turns never end.\n if (record.subtype === \"turn_duration\") {\n const event: HarnessResultEvent = {\n type: \"result\",\n subtype: \"success\",\n result: \"\",\n total_cost_usd: 0,\n };\n const sessionId = stringField(record, \"session_id\", \"sessionId\");\n if (sessionId !== undefined) event.sessionId = sessionId;\n return event;\n }\n return null;\n}\n\ntype AssistantUsage = NonNullable<HarnessAssistantEvent[\"message\"][\"usage\"]>;\n\nfunction mapUsage(message: Record<string, unknown>): AssistantUsage | undefined {\n const usage = message.usage;\n if (!isRecord(usage)) return undefined;\n const result: AssistantUsage = {};\n const input = numberField(usage, \"input_tokens\");\n const cacheRead = numberField(usage, \"cache_read_input_tokens\");\n const cacheCreation = numberField(usage, \"cache_creation_input_tokens\");\n if (input !== undefined) result.input_tokens = input;\n if (cacheRead !== undefined) result.cache_read_input_tokens = cacheRead;\n if (cacheCreation !== undefined) result.cache_creation_input_tokens = cacheCreation;\n return result;\n}\n\nfunction mapContentBlock(raw: unknown): HarnessContentBlock | null {\n if (!isRecord(raw)) return null;\n const type = stringField(raw, \"type\");\n if (type === undefined) return null;\n const block: HarnessContentBlock = { type };\n const text = stringField(raw, \"text\");\n if (text !== undefined) block.text = text;\n const name = stringField(raw, \"name\");\n if (name !== undefined) block.name = name;\n const id = stringField(raw, \"id\");\n if (id !== undefined) block.id = id;\n if (\"input\" in raw) block.input = raw.input;\n return block;\n}\n\nfunction mapAssistant(record: Record<string, unknown>): HarnessAssistantEvent | null {\n const message = record.message;\n if (!isRecord(message)) return null;\n const rawContent: unknown[] = isUnknownArray(message.content) ? message.content : [];\n const content: HarnessContentBlock[] = [];\n for (const item of rawContent) {\n const block = mapContentBlock(item);\n if (block) content.push(block);\n }\n const result: HarnessAssistantEvent = {\n type: \"assistant\",\n message: { role: \"assistant\", content },\n };\n const usage = mapUsage(message);\n if (usage !== undefined) result.message.usage = usage;\n return result;\n}\n\nfunction mapResultSuccess(record: Record<string, unknown>): HarnessResultEvent {\n const event: HarnessResultEvent = {\n type: \"result\",\n subtype: \"success\",\n result: stringField(record, \"result\") ?? \"\",\n total_cost_usd: numberField(record, \"total_cost_usd\", \"totalCostUsd\") ?? 0,\n };\n const modelUsage = record.modelUsage;\n if (isRecord(modelUsage)) event.modelUsage = modelUsage;\n const sessionId = stringField(record, \"session_id\", \"sessionId\");\n if (sessionId !== undefined) event.sessionId = sessionId;\n return event;\n}\n\nfunction mapResultError(record: Record<string, unknown>): HarnessResultEvent {\n const rawErrors = isUnknownArray(record.errors) ? record.errors : [];\n const errors = rawErrors.filter((e): e is string => typeof e === \"string\");\n const event: HarnessResultEvent = { type: \"result\", subtype: \"error\", errors };\n const sessionId = stringField(record, \"session_id\", \"sessionId\");\n if (sessionId !== undefined) event.sessionId = sessionId;\n return event;\n}\n\nfunction mapResult(record: Record<string, unknown>): HarnessResultEvent | null {\n if (record.subtype === \"success\") return mapResultSuccess(record);\n if (record.subtype === \"error\") return mapResultError(record);\n return null;\n}\n\nexport function mapTranscriptRecord(raw: unknown): HarnessEvent | null {\n if (!isRecord(raw)) return null;\n switch (raw.type) {\n case \"system\":\n return mapSystem(raw);\n case \"assistant\":\n return mapAssistant(raw);\n case \"result\":\n return mapResult(raw);\n default:\n return null;\n }\n}\n","/**\n * Usage-cap banner detection for the PTY harness.\n *\n * The SDK harness surfaces hard caps as structured `rate_limit_event`s, but the\n * interactive CLI only prints a banner into the conversation, e.g.\n * \"You've hit your weekly limit · resets 7am (UTC)\"\n * This matcher recognizes that banner in transcript text so PtySession can\n * synthesize the same harness-level event and both harnesses share one\n * downstream cap-handling path (key cycle → pause fallback).\n */\n\nexport interface UsageLimitBannerMatch {\n rateLimitType: \"seven_day\" | \"five_hour\";\n /** Epoch SECONDS of the reset when the banner carried a parseable time —\n * matching the SDK event's unit (see epochSecondsToISO). */\n resetsAtEpochSeconds?: number;\n}\n\n// \"You've hit your weekly limit\", \"You've reached your session limit\",\n// \"You have hit your usage limit\", … — keep the qualifier loose; only\n// \"weekly\" changes classification.\nconst BANNER_RE = /you'?(?:ve| have) (?:hit|reached) your ([\\w-]+ )?(?:usage )?limit/i;\n\n// \"resets 7am (UTC)\", \"resets 2:30pm (UTC)\" — the CLI prints wall-clock UTC\n// with no date. Other timezone spellings are ignored (no reliable offset).\nconst RESET_RE = /resets?\\s+(\\d{1,2})(?::(\\d{2}))?\\s*(am|pm)\\s*\\(UTC\\)/i;\n\n/**\n * Next future occurrence of the banner's wall-clock UTC time. The banner\n * carries no date, so this is a floor: for a weekly cap the true reset may be\n * days later — under-holding just means the key re-trips and gets re-stamped.\n */\nfunction nextUtcOccurrenceSeconds(\n hour12: number,\n minute: number,\n meridiem: string,\n nowMs: number,\n): number {\n let hour = hour12 % 12;\n if (meridiem.toLowerCase() === \"pm\") hour += 12;\n const candidate = new Date(nowMs);\n candidate.setUTCHours(hour, minute, 0, 0);\n if (candidate.getTime() <= nowMs) candidate.setUTCDate(candidate.getUTCDate() + 1);\n return Math.floor(candidate.getTime() / 1000);\n}\n\nexport function matchUsageLimitBanner(\n text: string,\n now = Date.now(),\n): UsageLimitBannerMatch | null {\n const banner = BANNER_RE.exec(text);\n if (!banner) return null;\n const qualifier = banner[1]?.trim().toLowerCase();\n const rateLimitType = qualifier === \"weekly\" ? \"seven_day\" : \"five_hour\";\n\n const reset = RESET_RE.exec(text);\n return {\n rateLimitType,\n ...(reset\n ? {\n resetsAtEpochSeconds: nextUtcOccurrenceSeconds(\n Number(reset[1]),\n reset[2] ? Number(reset[2]) : 0,\n reset[3],\n now,\n ),\n }\n : {}),\n };\n}\n","/**\n * Pure transforms from Claude Code transcript JSONL records into compact\n * `PtyChatEventPayload`s for the experimental chat PTY proxy.\n *\n * Deliberately separate from `record-mapper.ts`: that module's output must\n * stay in SDK parity (its contract is test-pinned), while this one is a lossy,\n * chat-shaped projection — it keeps user prompts (which the harness mapper\n * drops), truncates aggressively, and filters transcript noise.\n *\n * Transcript files are a trusted on-disk artifact written by the `claude`\n * CLI, so parsing their records is allowed — unlike raw PTY stdout, which is\n * never parsed.\n */\n\nimport type { PtyChatEventPayload } from \"@project/shared\";\nimport type { HarnessUserQuestion } from \"../types.js\";\nimport { parseUserQuestions } from \"./pty-support.js\";\n\n// Headroom under the wire-schema caps (16_384) so a truncation ellipsis can\n// never push a payload over the Zod limit server-side. Generic tool previews\n// stay small on purpose — they are collapsed detail in the chat stream, and the\n// server ring holds 500 events per session. AskUserQuestion is the exception:\n// the web lifts it into an interactive card the human has to READ, so it gets\n// the full text budget.\nconst TEXT_MAX = 16_000;\nconst TOOL_INPUT_MAX = 1_900;\nconst TOOL_OUTPUT_MAX = 1_900;\nconst QUESTION_INPUT_MAX = 16_000;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isUnknownArray(value: unknown): value is unknown[] {\n return Array.isArray(value);\n}\n\nfunction stringField(record: Record<string, unknown>, ...keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\") return value;\n }\n return undefined;\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max)}…` : text;\n}\n\n/**\n * Serialize AskUserQuestion questions so the payload BOTH fits the wire cap\n * and stays parseable JSON — the web lifts it into an interactive question\n * card (`parseAskUserQuestion` in `ptyChatToolCalls.ts`) and silently falls\n * back to a plain tool group when parsing fails.\n *\n * The budget here is `QUESTION_INPUT_MAX`, not the generic `TOOL_INPUT_MAX`:\n * a human reads these option descriptions to pick an answer, so cutting them\n * short defeats the card. Real question sets fit whole. The degradation rungs\n * only exist for pathological payloads: the projection already drops unrendered\n * fields (e.g. option `preview` blocks, which alone can blow any budget), then\n * descriptions are shortened progressively and finally dropped, so the labels\n * and questions survive as parseable JSON either way.\n */\nexport function compactQuestionsJson(questions: HarnessUserQuestion[]): string {\n const serialize = (qs: HarnessUserQuestion[]): string => JSON.stringify({ questions: qs });\n const withDescriptions = (max: number): HarnessUserQuestion[] =>\n questions.map((q) => ({\n ...q,\n options: q.options.map((o) => ({ ...o, description: truncate(o.description, max) })),\n }));\n const full = serialize(questions);\n if (full.length <= QUESTION_INPUT_MAX) return full;\n for (const max of [2_000, 600, 80, 0]) {\n const shortened = serialize(withDescriptions(max));\n if (shortened.length <= QUESTION_INPUT_MAX) return shortened;\n }\n return serialize(withDescriptions(0)).slice(0, QUESTION_INPUT_MAX);\n}\n\n/** Compact tool_use `input` preview. AskUserQuestion routes through the\n * parseability-preserving projection; everything else is a blind slice. */\nfunction compactToolInput(name: string, input: unknown): string {\n if (name === \"AskUserQuestion\" && isRecord(input)) {\n const questions = parseUserQuestions(input);\n if (questions.length > 0) return compactQuestionsJson(questions);\n }\n return JSON.stringify(input ?? {}).slice(0, TOOL_INPUT_MAX);\n}\n\n/** The CLI's synthetic background-task completion turn: a `run_in_background`\n * command (or a backgrounded subagent) finishing re-injects one of these as a\n * user message. */\nconst TASK_NOTIFICATION_PREFIX = \"<task-notification>\";\n\n/**\n * Harness-injected user turns that are plumbing, not conversation, and must\n * never render as a user-sent chat bubble:\n * - `<command-name>` / `<local-command-…>` — local slash-command wrappers.\n * - `<task-notification>` — see above; without this filter it shows up as if\n * the human sent it.\n */\nfunction isNonConversationText(text: string): boolean {\n const trimmed = text.trimStart();\n return (\n trimmed.startsWith(\"<command-name>\") ||\n trimmed.startsWith(\"<local-command-\") ||\n trimmed.startsWith(TASK_NOTIFICATION_PREFIX)\n );\n}\n\n/**\n * Flatten a user record's message content to plain text. Returns undefined\n * when the record carries no prompt text (tool results, unknown shapes).\n */\nfunction userRecordText(record: Record<string, unknown>): string | undefined {\n const message = record.message;\n if (!isRecord(message)) return undefined;\n const content = message.content;\n if (typeof content === \"string\") return content;\n if (!isUnknownArray(content)) return undefined;\n // Tool results ride user-role records; they are outputs, not prompts.\n if (content.some((b) => isRecord(b) && b.type === \"tool_result\")) return undefined;\n return content\n .filter((b): b is Record<string, unknown> => isRecord(b) && b.type === \"text\")\n .map((b) => (typeof b.text === \"string\" ? b.text : \"\"))\n .filter((t) => t.length > 0)\n .join(\"\\n\");\n}\n\n/**\n * Is this transcript record the CLI's background-task completion turn?\n *\n * Shared with the chat filter above rather than re-derived, so the two can\n * never drift. The runner counts these as the completion half of its\n * outstanding-background-work tracking (`runner/background-work.ts`) — that is\n * what keeps the workspace activity clock fresh while a backgrounded gate runs\n * and the agent itself sits idle.\n */\nexport function isBackgroundTaskNotificationRecord(raw: unknown): boolean {\n if (!isRecord(raw) || raw.type !== \"user\") return false;\n if (raw.isSidechain === true || raw.isMeta === true) return false;\n const text = userRecordText(raw);\n return text !== undefined && text.trimStart().startsWith(TASK_NOTIFICATION_PREFIX);\n}\n\nfunction mapSystem(record: Record<string, unknown>): PtyChatEventPayload[] {\n if (record.subtype === \"init\") {\n const event: PtyChatEventPayload = {\n kind: \"init\",\n model: stringField(record, \"model\") ?? \"\",\n };\n const sessionId = stringField(record, \"session_id\", \"sessionId\");\n if (sessionId !== undefined) event.claudeSessionId = sessionId;\n return [event];\n }\n // The interactive CLI marks a completed turn with a `turn_duration` system\n // record, not a `result` record — same mapping as record-mapper.ts.\n if (record.subtype === \"turn_duration\") return [{ kind: \"turn_end\" }];\n return [];\n}\n\nfunction mapAssistant(record: Record<string, unknown>): PtyChatEventPayload[] {\n const message = record.message;\n if (!isRecord(message)) return [];\n const content: unknown[] = isUnknownArray(message.content) ? message.content : [];\n const events: PtyChatEventPayload[] = [];\n for (const raw of content) {\n if (!isRecord(raw)) continue;\n if (raw.type === \"text\") {\n const text = stringField(raw, \"text\");\n if (text && text.length > 0) {\n events.push({ kind: \"assistant_text\", text: truncate(text, TEXT_MAX) });\n }\n } else if (raw.type === \"tool_use\") {\n const name = stringField(raw, \"name\");\n if (name) {\n const input = \"input\" in raw ? raw.input : undefined;\n const event: PtyChatEventPayload = {\n kind: \"tool_use\",\n name: truncate(name, 200),\n input: compactToolInput(name, input),\n };\n const id = stringField(raw, \"id\");\n if (id !== undefined) event.id = id;\n events.push(event);\n }\n }\n }\n return events;\n}\n\n/** Flatten a tool_result block's content (string or text-block array) to text. */\nfunction toolResultText(block: Record<string, unknown>): string {\n const content = block.content;\n if (typeof content === \"string\") return content;\n if (isUnknownArray(content)) {\n return content\n .filter((b): b is Record<string, unknown> => isRecord(b) && b.type === \"text\")\n .map((b) => (typeof b.text === \"string\" ? b.text : \"\"))\n .filter((t) => t.length > 0)\n .join(\"\\n\");\n }\n return \"\";\n}\n\nfunction mapToolResults(content: unknown[]): PtyChatEventPayload[] {\n const events: PtyChatEventPayload[] = [];\n for (const raw of content) {\n if (!isRecord(raw) || raw.type !== \"tool_result\") continue;\n const event: PtyChatEventPayload = {\n kind: \"tool_result\",\n output: truncate(toolResultText(raw), TOOL_OUTPUT_MAX),\n isError: raw.is_error === true,\n };\n const toolUseId = stringField(raw, \"tool_use_id\");\n if (toolUseId !== undefined) event.toolUseId = toolUseId;\n events.push(event);\n }\n return events;\n}\n\nfunction mapUser(record: Record<string, unknown>): PtyChatEventPayload[] {\n const message = record.message;\n if (!isRecord(message)) return [];\n const content = message.content;\n\n if (isUnknownArray(content) && content.some((b) => isRecord(b) && b.type === \"tool_result\")) {\n return mapToolResults(content);\n }\n const text = userRecordText(record);\n if (text === undefined) return [];\n\n const trimmed = text.trim();\n if (trimmed.length === 0 || isNonConversationText(trimmed)) return [];\n return [{ kind: \"user_text\", text: truncate(trimmed, TEXT_MAX) }];\n}\n\n/**\n * Map one parsed transcript record to zero-or-more chat events (a record can\n * hold several content blocks). Unknown/noise records map to `[]`.\n */\nexport function mapChatRecords(raw: unknown): PtyChatEventPayload[] {\n if (!isRecord(raw)) return [];\n // Subagent (sidechain) traffic and meta records are transcript noise for a\n // chat surface — the main-thread records already narrate the turn.\n if (raw.isSidechain === true || raw.isMeta === true) return [];\n switch (raw.type) {\n case \"system\":\n return mapSystem(raw);\n case \"assistant\":\n return mapAssistant(raw);\n case \"user\":\n return mapUser(raw);\n case \"result\":\n return [{ kind: \"turn_end\" }];\n default:\n return [];\n }\n}\n","/**\n * Claude Code config-dir paths and per-run settings/hook materialization.\n *\n * The PTY harness writes a throwaway `settings.json` (passed via\n * `claude --settings`) wiring hooks that relay envelopes to a Unix socket:\n * - PostToolUse (all tools): fire-and-forget tool-progress envelopes.\n * - PreToolUse (ExitPlanMode): request/response — the runner's\n * `canUseTool` verdict (plan/property validation, identification trigger)\n * is returned as a permissionDecision so the plan-mode exit is gated by\n * Conveyor instead of the interactive dialog.\n * - PreToolUse (AskUserQuestion): observe-only — the session is told a\n * questionnaire is about to render (so it can report waiting_for_input)\n * and the hook always allows; the TUI collects the answer natively.\n * - PreToolUse (mcp__.*): local auto-allow — plan-permission spawns prompt\n * for MCP tools even when they're in permissions.allow, so the hook\n * answers allow without a socket round trip. The pod is the sandbox.\n *\n * ## Two PreToolUse shapes: scoped (build) vs catch-all (plan)\n *\n * `--permission-mode plan` prompts for ANY tool the CLI cannot prove is\n * read-only, and `permissions.allow` does not suppress those prompts. A card\n * agent has nobody at the terminal, so an unanswered prompt parks the session\n * until the wedge watchdog kills the turn ~30 minutes later — the \"Interactive\n * card hangs on the loading screen\" bug, seen live 2026-07-31.\n *\n * Naming the prompting tools one at a time is whack-a-mole: `Bash` was added\n * only after it produced that hang. So a plan-permission spawn\n * (`gateAllTools`) wires ONE `*` matcher and lets Conveyor answer for every\n * tool. `buildCanUseTool` already handles arbitrary tool names — read-only\n * modes allow everything except writes outside `.claude/plans/` and the\n * repo-mutating Bash set — so the read-only guarantee moves from the CLI's\n * permission engine to ours rather than disappearing.\n *\n * A single entry is required, not an extra matcher alongside the scoped ones:\n * every matching hook runs, so an overlapping `*` would fire the helper twice\n * for `ExitPlanMode` and double-run its identification trigger, chat post and\n * `requestStop`. The helper already branches per tool for fail-mode and\n * timeout, so one matcher needs no new policy.\n *\n * Build-capable spawns pass `--dangerously-skip-permissions` and never prompt,\n * so they keep the scoped matchers and pay no extra round trips.\n *\n * Writing a per-run file avoids clobbering the user's real `~/.claude/settings.json`.\n */\n\nimport { mkdir, writeFile, chmod } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport function claudeConfigHome(): string {\n return process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), \".claude\");\n}\n\nexport function projectSlug(cwd: string): string {\n return cwd.replace(/\\//g, \"-\");\n}\n\nexport function sessionTranscriptPath(cwd: string, sessionId: string): string {\n return join(claudeConfigHome(), \"projects\", projectSlug(cwd), `${sessionId}.jsonl`);\n}\n\n/**\n * Per-tool allow rules approximating \"allow everything\". The CLI rejects a\n * bare `\"*\"` rule (and an unanchored `\"mcp__conveyor\"`) as invalid — that\n * parks the TUI on a blocking \"Settings Warning\" screen at boot — so the\n * built-in tools are named explicitly and the Conveyor MCP tools matched by\n * the only valid glob form (`mcp__<server>__*`). The built-in names matter\n * for the acceptEdits continuation after an auto-mode plan exit (Bash/MCP\n * would otherwise prompt with nobody at the terminal); plan-permission spawns\n * are read-only regardless, and build-capable spawns pass\n * `--dangerously-skip-permissions` and never consult this list.\n *\n * NOTE: `mcp__conveyor__*` does NOT suppress plan-mode prompts — the CLI\n * can't classify MCP tools as read-only, so `--permission-mode plan` prompts\n * for them regardless of this list. The `mcp__.*` PreToolUse hook below is\n * what actually admits MCP calls while planning; the rule stays as\n * defense-in-depth for the acceptEdits continuation.\n */\nexport const ALLOW_RULES = [\n \"Bash\",\n \"BashOutput\",\n \"Edit\",\n \"Write\",\n \"Read\",\n \"Glob\",\n \"Grep\",\n \"WebFetch\",\n \"WebSearch\",\n \"NotebookEdit\",\n \"Task\",\n \"TodoWrite\",\n \"ToolSearch\",\n \"KillShell\",\n \"SlashCommand\",\n \"Skill\",\n \"mcp__conveyor__*\",\n];\n\n/**\n * CJS hook helper. Reads the hook payload from stdin and branches on\n * `hook_event_name`:\n *\n * - PostToolUse: relays a fire-and-forget tool-progress envelope and prints\n * `{continue:true}` so the CLI proceeds. A short fallback timer guarantees\n * exit even if the socket is unavailable.\n * - PreToolUse: writes a `pre_tool_use` request and waits for the runner's\n * correlated verdict on the same connection, printing a\n * permissionDecision allow/deny. On socket failure or timeout it fails\n * CLOSED (deny) — the model retries after fixing the reported problem,\n * and the runner's denial-escalation backstop bounds pathological loops.\n * Exception: AskUserQuestion fails OPEN (allow, short timeout) — it is\n * observed for status reporting only, and a socket blip must never deny\n * the model's questionnaire.\n * Exception: MCP tools (`mcp__*`) are allowed locally without touching\n * the socket at all — the decision is unconditional, so there is no\n * fail-mode and no latency.\n * Every other tool also fails closed, but on a much shorter budget — its\n * verdict is computed synchronously, so a slow answer means the socket died.\n */\nconst HOOK_HELPER_SOURCE = `\"use strict\";\nconst net = require(\"node:net\");\nconst crypto = require(\"node:crypto\");\n\nconst PRE_TOOL_USE_TIMEOUT_MS = 110000;\nconst ASK_USER_QUESTION_TIMEOUT_MS = 5000;\n// Ordinary tool verdicts are computed synchronously from the tool input (no\n// task lookups), so a slow answer means the socket is gone. Fail closed quickly\n// instead of stalling the turn for the full ExitPlanMode budget.\nconst DEFAULT_TOOL_TIMEOUT_MS = 15000;\n\nlet raw = \"\";\nprocess.stdin.setEncoding(\"utf8\");\nprocess.stdin.on(\"data\", (chunk) => {\n raw += chunk;\n});\nprocess.stdin.on(\"end\", () => {\n let payload = {};\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") payload = parsed;\n } catch {\n payload = {};\n }\n if (payload.hook_event_name === \"PreToolUse\") {\n preToolUse(payload);\n } else {\n relayProgress(typeof payload.tool_name === \"string\" ? payload.tool_name : \"\");\n }\n});\n\nfunction relayProgress(toolName) {\n const socketPath = process.env.CONVEYOR_HOOK_SOCKET;\n let done = false;\n const finish = () => {\n if (done) return;\n done = true;\n process.stdout.write(JSON.stringify({ continue: true }));\n process.exit(0);\n };\n const fallback = setTimeout(finish, 250);\n if (!socketPath) {\n clearTimeout(fallback);\n finish();\n return;\n }\n const client = net.connect(socketPath, () => {\n // PostToolUse does not supply tool duration, so elapsed_time_seconds is\n // omitted rather than reported as a misleading 0 (the field is optional).\n const line = JSON.stringify({ tool_name: toolName }) + \"\\\\n\";\n client.write(line, () => {\n client.end();\n });\n });\n client.on(\"close\", () => {\n clearTimeout(fallback);\n finish();\n });\n client.on(\"error\", () => {\n clearTimeout(fallback);\n finish();\n });\n}\n\nfunction preToolUse(payload) {\n const socketPath = process.env.CONVEYOR_HOOK_SOCKET;\n let done = false;\n const respond = (decision, reason) => {\n if (done) return;\n done = true;\n process.stdout.write(\n JSON.stringify({\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: decision,\n ...(reason ? { permissionDecisionReason: reason } : {}),\n },\n }),\n );\n process.exit(0);\n };\n // MCP tools are auto-allowed locally — no socket round trip, no fail-mode.\n // Plan mode prompts for them despite permissions.allow (the CLI can't\n // classify MCP tools as read-only), and the pod is the sandbox.\n if (typeof payload.tool_name === \"string\" && payload.tool_name.startsWith(\"mcp__\")) {\n respond(\"allow\");\n return;\n }\n // AskUserQuestion is observe-only (status reporting) — fail OPEN so a\n // missing/slow socket never denies the questionnaire. Everything else is a\n // Conveyor gate — fail CLOSED.\n const failOpen = payload.tool_name === \"AskUserQuestion\";\n const respondUnavailable = () =>\n failOpen\n ? respond(\"allow\")\n : respond(\n \"deny\",\n \"Conveyor validation is unavailable right now. Wait a moment and call the tool again.\",\n );\n if (!socketPath) {\n respondUnavailable();\n return;\n }\n const id = crypto.randomBytes(8).toString(\"hex\");\n const timeoutMs = failOpen\n ? ASK_USER_QUESTION_TIMEOUT_MS\n : payload.tool_name === \"ExitPlanMode\"\n ? PRE_TOOL_USE_TIMEOUT_MS\n : DEFAULT_TOOL_TIMEOUT_MS;\n const timer = setTimeout(respondUnavailable, timeoutMs);\n const client = net.connect(socketPath, () => {\n client.write(\n JSON.stringify({\n kind: \"pre_tool_use\",\n id,\n tool_name: typeof payload.tool_name === \"string\" ? payload.tool_name : \"\",\n tool_input:\n payload.tool_input && typeof payload.tool_input === \"object\" ? payload.tool_input : {},\n }) + \"\\\\n\",\n );\n });\n let buffer = \"\";\n client.on(\"data\", (chunk) => {\n buffer += chunk.toString(\"utf8\");\n let index = buffer.indexOf(\"\\\\n\");\n while (index >= 0) {\n const line = buffer.slice(0, index);\n buffer = buffer.slice(index + 1);\n try {\n const verdict = JSON.parse(line);\n if (verdict && verdict.id === id) {\n clearTimeout(timer);\n client.end();\n respond(verdict.decision === \"allow\" ? \"allow\" : \"deny\", verdict.reason);\n return;\n }\n } catch {\n /* keep scanning */\n }\n index = buffer.indexOf(\"\\\\n\");\n }\n });\n client.on(\"error\", () => {\n clearTimeout(timer);\n respondUnavailable();\n });\n client.on(\"close\", () => {\n clearTimeout(timer);\n respondUnavailable();\n });\n}\n`;\n\nexport interface HookSettingsResult {\n settingsPath: string;\n helperPath: string;\n}\n\nexport interface HookSettingsOptions {\n /**\n * Answer EVERY tool through the hook instead of the scoped matcher list.\n * Set for `--permission-mode plan` spawns, where any unnamed tool would\n * otherwise park the TUI on an approval dialog nobody can answer. See the\n * \"Two PreToolUse shapes\" section in this file's header.\n */\n gateAllTools?: boolean;\n}\n\ntype HookEntry = { matcher: string; hooks: Array<{ type: string; command: string; timeout: number }> };\n\n/** The PreToolUse matcher set for the spawn's permission mode. */\nfunction buildPreToolUseHooks(helperPath: string, gateAllTools: boolean): HookEntry[] {\n const command = `node ${JSON.stringify(helperPath)}`;\n if (gateAllTools) {\n // ONE entry, deliberately: overlapping matchers all run, which would fire\n // the helper twice for ExitPlanMode and double-run its side effects. The\n // helper branches on tool name for fail-mode and timeout, so this single\n // matcher carries the same per-tool policy the scoped list did.\n return [{ matcher: \"*\", hooks: [{ type: \"command\", command, timeout: 120 }] }];\n }\n return [\n { matcher: \"ExitPlanMode\", hooks: [{ type: \"command\", command, timeout: 120 }] },\n {\n // Observe-only: lets the session report waiting_for_input the moment\n // the planning questionnaire renders. The helper fails open for this\n // tool, so the questionnaire is never blocked by Conveyor.\n matcher: \"AskUserQuestion\",\n hooks: [{ type: \"command\", command, timeout: 30 }],\n },\n {\n // Build-capable spawns bypass prompts, so Bash is hooked here only for\n // the destructive-command guard.\n matcher: \"Bash\",\n hooks: [{ type: \"command\", command, timeout: 120 }],\n },\n {\n // A hook allow bypasses the permission engine in every mode. Loose by\n // design: the pod is the sandbox, and agents must call update_task etc.\n // The helper answers locally (no socket).\n matcher: \"mcp__.*\",\n hooks: [{ type: \"command\", command, timeout: 30 }],\n },\n ];\n}\n\nexport async function writeHookSettings(\n dir: string,\n opts: HookSettingsOptions = {},\n): Promise<HookSettingsResult> {\n const helperPath = join(dir, \"hook-helper.cjs\");\n const settingsPath = join(dir, \"settings.json\");\n await mkdir(dir, { recursive: true });\n await writeFile(helperPath, HOOK_HELPER_SOURCE, \"utf8\");\n await chmod(helperPath, 0o755);\n const settings = {\n // Pre-accept Claude Code's \"Bypass Permissions mode\" disclaimer. Build-capable\n // spawns pass `--dangerously-skip-permissions`; on a real PTY the CLI otherwise\n // parks on the interactive \"Yes, I accept / No, exit\" dialog whose default focus\n // is \"No, exit\" — so it cannot be auto-dismissed by an Enter nudge and the run\n // stalls until the auto-nudge watchdog shuts it down. The CLI reads this key\n // from the `--settings` (flagSettings) layer via its bypass-mode gate, so\n // setting it here suppresses the dialog deterministically on every spawn —\n // independent of the `bypassPermissionsModeAccepted` seed in credentials.ts,\n // which the CLI's one-time migration consumes and which is subject to\n // persistence races on the codespace user-home.\n skipDangerousModePermissionPrompt: true,\n // Auto-approve tool calls so the interactive (PTY) agent never stops to\n // prompt the viewer. This only suppresses per-tool approval prompts — it\n // does NOT relax the planning gate: in discovery/plan mode the spawn passes\n // `--permission-mode plan`, which keeps file edits blocked until the agent\n // exits plan mode regardless of this allow-list. Plan mode still prompts\n // for anything it cannot classify as read-only; the PreToolUse hooks below\n // answer those. In build mode the spawn already bypasses prompts via\n // `--dangerously-skip-permissions`.\n // NOTE: a bare \"*\" rule is INVALID (the CLI rejects it and parks the TUI on\n // a Settings Warning dialog at boot) — hence the explicit ALLOW_RULES list.\n permissions: {\n allow: ALLOW_RULES,\n },\n hooks: {\n PreToolUse: buildPreToolUseHooks(helperPath, opts.gateAllTools === true),\n PostToolUse: [\n {\n matcher: \"*\",\n hooks: [{ type: \"command\", command: `node ${JSON.stringify(helperPath)}` }],\n },\n ],\n },\n };\n await writeFile(settingsPath, JSON.stringify(settings, null, 2), \"utf8\");\n return { settingsPath, helperPath };\n}\n","/**\n * Pure, dependency-free secret redactor for tool output.\n *\n * Applied in the PostToolUse hook before forwarding `tool_result` events to\n * the API and before buffering into `pendingToolOutputs`. Defense-in-depth\n * only — server-side must still treat tool output as potentially tainted.\n *\n * Patterns are intentionally conservative: we prefer false negatives over\n * false positives because agents rely on reading tool output to do work.\n * Commit SHAs (`[a-f0-9]{7,40}`) are deliberately NOT redacted.\n */\n\nconst REDACTED = \"<redacted>\";\n\nconst BEARER_RE = /\\b(Bearer\\s+)[A-Za-z0-9_\\-.]{20,}/g;\n\nconst VENDOR_KEY_RE =\n /\\b(?:sk-[a-zA-Z0-9_-]{20,}|ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{22,}|xoxb-[A-Za-z0-9-]+|xai-[A-Za-z0-9-]{20,})\\b/g;\n\nconst AWS_ACCESS_KEY_RE = /\\bAKIA[0-9A-Z]{16}\\b/g;\n\n// JWTs: three base64url segments separated by dots, starting with the\n// ubiquitous `eyJ` header prefix.\nconst JWT_RE = /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g;\n\n// KEY=VALUE lines where KEY looks like a secret name. Matches optional\n// `export ` prefix and quoted or bare values. Captures KEY separately so we\n// preserve it in the replacement.\nconst ENV_SECRET_RE =\n /^(\\s*(?:export\\s+)?([A-Z][A-Z0-9_]*(?:TOKEN|SECRET|KEY|PASSWORD|PASS|CREDENTIAL|CREDENTIALS)[A-Z0-9_]*)\\s*=\\s*)['\"]?([^\\s'\"]+)['\"]?/gm;\n\nconst COOKIE_HEADER_RE = /(Cookie:\\s*)[^\\r\\n]+/gi;\n\n// Basic-auth URLs: keep the user visible, mask the password.\nconst BASIC_AUTH_URL_RE = /(https?:\\/\\/)([^:@\\s/]+):([^@\\s]+)@/g;\n\n// AWS secret access keys don't have a distinctive prefix. Apply only on\n// lines that mention \"secret\" / \"aws_secret\" to avoid matching commit SHAs,\n// base64 payloads, etc.\nconst AWS_SECRET_LINE_RE = /^.*(?:secret|aws_secret).*$/gim;\nconst AWS_SECRET_VALUE_RE = /\\b([A-Za-z0-9/+=]{40})\\b/g;\n\n// Strip prompt-injection attempts from tool output: we observed `<system-reminder>`\n// blocks being smuggled through bash output during discovery of this pipeline.\nconst SYSTEM_REMINDER_RE = /<system-reminder>[\\s\\S]*?<\\/system-reminder>/gi;\n\nexport interface RedactResult {\n output: string;\n redacted: number;\n}\n\nexport function redact(input: string): RedactResult {\n if (!input) return { output: input, redacted: 0 };\n\n let count = 0;\n let output = input;\n\n output = output.replace(SYSTEM_REMINDER_RE, () => {\n count++;\n return \"<!-- stripped injection -->\";\n });\n\n output = output.replace(BEARER_RE, (_match, prefix: string) => {\n count++;\n return `${prefix}${REDACTED}`;\n });\n\n output = output.replace(VENDOR_KEY_RE, () => {\n count++;\n return REDACTED;\n });\n\n output = output.replace(AWS_ACCESS_KEY_RE, () => {\n count++;\n return REDACTED;\n });\n\n output = output.replace(JWT_RE, () => {\n count++;\n return REDACTED;\n });\n\n output = output.replace(AWS_SECRET_LINE_RE, (line) =>\n line.replace(AWS_SECRET_VALUE_RE, (match) => {\n // Skip pure hex (commit SHAs, etc.) — AWS secrets use the full\n // base64 alphabet, so a match that's all-hex is almost certainly\n // not a secret.\n if (/^[a-f0-9]+$/i.test(match)) return match;\n count++;\n return REDACTED;\n }),\n );\n\n output = output.replace(ENV_SECRET_RE, (_match, prefix: string, _key: string, _value: string) => {\n count++;\n return `${prefix}${REDACTED}`;\n });\n\n output = output.replace(COOKIE_HEADER_RE, (_match, prefix: string) => {\n count++;\n return `${prefix}${REDACTED}`;\n });\n\n output = output.replace(BASIC_AUTH_URL_RE, (_match, scheme: string, user: string) => {\n count++;\n return `${scheme}${user}:${REDACTED}@`;\n });\n\n return { output, redacted: count };\n}\n","/**\n * PtyOutputCoalescer — batches raw PTY stdout before it is relayed to the S2\n * server.\n *\n * node-pty surfaces a busy TUI redraw as tens of small data events per second;\n * relaying each one as its own socket.io call made the server-side relay cost\n * (auth + ring append + room fan-out per frame) the bottleneck of the\n * Connected-TUI stream. Buffering for a short window and shipping one\n * concatenated frame preserves byte order and ANSI integrity (the relay treats\n * frames as an opaque byte stream — chunk boundaries carry no meaning) while\n * cutting the call rate by an order of magnitude.\n *\n * Flush triggers:\n * - trailing timer (`flushMs`) after the first unflushed write,\n * - synchronous size flush when the buffer reaches `maxBufferChars`\n * (kept far below the 256KB PTY_FRAME_MAX_CHARS schema cap),\n * - explicit `flush()` from the session on pty exit / teardown so the tail\n * of output (exit messages, final repaint) is never lost.\n */\n\nconst DEFAULT_FLUSH_MS = 40;\nconst DEFAULT_MAX_BUFFER_CHARS = 48 * 1024;\n\nexport class PtyOutputCoalescer {\n private buffer = \"\";\n private timer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n\n constructor(\n private readonly sink: (data: string, dims: { cols: number; rows: number }) => void,\n private readonly getDims: () => { cols: number; rows: number },\n private readonly flushMs: number = DEFAULT_FLUSH_MS,\n private readonly maxBufferChars: number = DEFAULT_MAX_BUFFER_CHARS,\n ) {}\n\n /** Buffer a chunk; flushes synchronously when the size threshold is hit. */\n write(data: string): void {\n if (this.disposed || data === \"\") return;\n this.buffer += data;\n if (this.buffer.length >= this.maxBufferChars) {\n this.flush();\n return;\n }\n if (!this.timer) {\n this.timer = setTimeout(() => {\n this.flush();\n }, this.flushMs);\n }\n }\n\n /** Ship the buffered bytes now (no-op when empty). Dims are read at flush\n * time so a mid-buffer resize stamps the frame with the dims it will render\n * under. */\n flush(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n if (this.buffer === \"\") return;\n const data = this.buffer;\n this.buffer = \"\";\n this.sink(data, this.getDims());\n }\n\n /** Final flush, then drop any future writes (session torn down). Idempotent. */\n dispose(): void {\n if (this.disposed) return;\n this.flush();\n this.disposed = true;\n }\n}\n","/**\n * In-process MCP server that exposes the agent's Conveyor tools to the spawned\n * `claude` CLI over Streamable HTTP on loopback.\n *\n * The tool handlers must run IN the agent process — they call\n * `connection.call(...)` on the live task-token `AgentConnection`. So instead of\n * spawning a separate stdio MCP child and bridging calls back over a socket, we\n * serve the same in-process handlers over an HTTP MCP transport bound to\n * `127.0.0.1`, and point `claude` at it via `--mcp-config` (type: \"http\"). This\n * is the wiring the PTY harness deferred (\"S4\"); the SDK harness already gets\n * these tools in-process.\n *\n * Sessions: one StreamableHTTPServerTransport per MCP session, created on each\n * InitializeRequest and routed by the `Mcp-Session-Id` header. A stateful\n * transport is single-session — it rejects any second initialize with 400\n * \"Server already initialized\" — so reusing one instance for the whole PTY run\n * made a CLI-side reconnect (after a tool call outlived its timeout during an\n * API socket flap) permanently unrecoverable: the CLI sat in \"MCP reconnecting\"\n * until the pod was replaced (2026-07-08 outage). Requests for an unknown or\n * expired session id get a 404, which tells the CLI to re-initialize.\n *\n * Security: bound to loopback only (never 0.0.0.0) and gated by a random\n * per-run bearer token that `claude` echoes from the generated mcp-config.\n */\n\nimport { createServer, type Server as HttpServer } from \"node:http\";\nimport { z } from \"zod\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { HarnessMcpServer, HarnessToolDefinition } from \"../types.js\";\nimport { isExternalMcpStdioServer } from \"../types.js\";\nimport { PtyMcpServer } from \"./mcp-server.js\";\n\nconst LOOPBACK = \"127.0.0.1\";\n\n/**\n * Ceiling on concurrently tracked MCP sessions. Each CLI reconnect abandons\n * its predecessor without a terminating DELETE, so evict oldest-first instead\n * of growing for the lifetime of a flappy PTY session. The live CLI holds\n * exactly one session; anything beyond a couple is already garbage.\n */\nconst MAX_SESSIONS = 16;\n\ninterface McpSession {\n transport: StreamableHTTPServerTransport;\n mcp: McpServer;\n}\n\nexport interface PtyToolServerHandle {\n /** `http://127.0.0.1:<port>/mcp` — the URL written into the mcp-config. */\n url: string;\n /** Bearer token required on every request (defense-in-depth over loopback). */\n token: string;\n}\n\nexport class PtyToolServer {\n private http: HttpServer | null = null;\n private readonly sessions = new Map<string, McpSession>();\n private readonly token = randomBytes(24).toString(\"base64url\");\n\n constructor(\n private readonly name: string,\n private readonly tools: HarnessToolDefinition[],\n ) {}\n\n async start(): Promise<PtyToolServerHandle> {\n const server = createServer((req, res) => {\n void this.handle(req, res);\n });\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, LOOPBACK, () => resolve());\n });\n\n const address = server.address();\n const port = address && typeof address === \"object\" ? address.port : 0;\n\n this.http = server;\n return { url: `http://${LOOPBACK}:${port}/mcp`, token: this.token };\n }\n\n /** Fresh McpServer with every tool registered — one per MCP session. */\n private buildMcpServer(): McpServer {\n const mcp = new McpServer({ name: this.name, version: \"1.0.0\" });\n // The SDK's `registerTool()` is heavily generic over the zod shape; our tool\n // defs are intentionally loose-typed (`schema: z.ZodRawShape`, handler\n // returns MCP content). Cast the registrar to a simpler shape to bridge the\n // boundary without widening to `any` — the SDK still validates input\n // against `inputSchema`.\n const register = mcp.registerTool.bind(mcp) as unknown as (\n name: string,\n config: { description: string; inputSchema: unknown; _meta?: Record<string, unknown> },\n cb: (args: unknown) => unknown,\n ) => void;\n for (const tool of this.tools) {\n // `strict` tools reject unknown input keys with a validation error naming\n // the key, instead of Zod's default strip — which on all-optional tools\n // turns a misspelled key into a silent no-op \"success\".\n const inputSchema = tool.strict ? z.strictObject(tool.schema) : tool.schema;\n register(\n tool.name,\n {\n description: tool.description,\n inputSchema,\n // The spawned CLI reads `_meta['anthropic/alwaysLoad']` from the\n // `tools/list` response and preloads the tool into the prompt\n // instead of deferring it behind ToolSearch. Per-tool (vs per-server\n // `alwaysLoad` in the mcp-config) so only the hot protocol tools pay\n // the prompt cost while the long tail stays deferred.\n ...(tool.alwaysLoad ? { _meta: { \"anthropic/alwaysLoad\": true } } : {}),\n },\n (args) => tool.handler(args),\n );\n }\n return mcp;\n }\n\n private async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.headers.authorization !== `Bearer ${this.token}`) {\n res.writeHead(401).end();\n return;\n }\n try {\n const sessionId = req.headers[\"mcp-session-id\"];\n if (typeof sessionId === \"string\") {\n const session = this.sessions.get(sessionId);\n if (!session) {\n // Unknown/evicted session (e.g. the CLI reconnecting with a stale\n // id) — 404 per spec so the client re-initializes.\n jsonRpcError(res, 404, -32001, \"Session not found\");\n return;\n }\n await session.transport.handleRequest(req, res);\n return;\n }\n\n // No session header: only a POSTed InitializeRequest may open a session.\n if (req.method !== \"POST\") {\n jsonRpcError(res, 400, -32600, \"Bad Request: Mcp-Session-Id header is required\");\n return;\n }\n const body: unknown = await readJsonBody(req);\n const messages = Array.isArray(body) ? body : [body];\n if (!messages.some((m) => isInitializeRequest(m))) {\n jsonRpcError(res, 400, -32600, \"Bad Request: Mcp-Session-Id header is required\");\n return;\n }\n await this.openSession(req, res, body);\n } catch {\n if (res.headersSent) res.end();\n else res.writeHead(500).end();\n }\n }\n\n /** Connect a fresh transport + McpServer pair and serve the initialize. */\n private async openSession(\n req: IncomingMessage,\n res: ServerResponse,\n parsedBody: unknown,\n ): Promise<void> {\n const mcp = this.buildMcpServer();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomBytes(16).toString(\"hex\"),\n enableJsonResponse: true,\n onsessioninitialized: (sid) => {\n this.sessions.set(sid, { transport, mcp });\n this.evictOverflow(sid);\n },\n });\n transport.onclose = () => {\n const sid = transport.sessionId;\n if (sid && this.sessions.get(sid)?.transport === transport) {\n this.sessions.delete(sid);\n }\n };\n await mcp.connect(transport);\n await transport.handleRequest(req, res, parsedBody);\n }\n\n /** Drop oldest abandoned sessions past MAX_SESSIONS (never the newest). */\n private evictOverflow(currentSid: string): void {\n for (const [sid, session] of this.sessions) {\n if (this.sessions.size <= MAX_SESSIONS) break;\n if (sid === currentSid) continue;\n this.sessions.delete(sid);\n void closeSession(session);\n }\n }\n\n async close(): Promise<void> {\n const sessions = [...this.sessions.values()];\n this.sessions.clear();\n for (const session of sessions) {\n await closeSession(session);\n }\n const http = this.http;\n this.http = null;\n if (http) {\n await new Promise<void>((resolve) => {\n http.close(() => resolve());\n });\n }\n }\n}\n\nasync function closeSession(session: McpSession): Promise<void> {\n try {\n await session.transport.close();\n } catch {\n /* already closed */\n }\n try {\n await session.mcp.close();\n } catch {\n /* already closed */\n }\n}\n\nfunction jsonRpcError(res: ServerResponse, status: number, code: number, message: string): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ jsonrpc: \"2.0\", error: { code, message }, id: null }));\n}\n\nasync function readJsonBody(req: IncomingMessage): Promise<unknown> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n return JSON.parse(Buffer.concat(chunks).toString(\"utf8\")) as unknown;\n}\n\nexport interface ToolServersResult {\n servers: PtyToolServer[];\n /** Path to the written `--mcp-config`, or null when there were no tools. */\n mcpConfigPath: string | null;\n /**\n * The same entries the `--mcp-config` file contains, keyed by server name.\n * Exposed because not every consumer wants Claude's file format: the opencode\n * headless harness translates these into its own config vocabulary and passes\n * them inline via `OPENCODE_CONFIG_CONTENT`.\n */\n entries: Record<string, McpConfigEntry>;\n}\n\nexport type McpConfigEntry =\n | { type: \"http\"; url: string; headers: Record<string, string> }\n | { type: \"stdio\"; command: string; args?: string[]; env?: Record<string, string> };\n\n/**\n * Start one loopback HTTP MCP server per harness tool group (in practice just\n * \"conveyor\"), pass external stdio entries (e.g. the baked `playwright-mcp`)\n * straight into the config, and write the `--mcp-config` the spawned `claude`\n * consumes. No-op (null config) when there is nothing to serve.\n */\nexport async function startToolServers(\n mcpServers: Record<string, HarnessMcpServer>,\n tempDir: string,\n): Promise<ToolServersResult> {\n const servers: PtyToolServer[] = [];\n const config: Record<string, McpConfigEntry> = {};\n for (const [name, handle] of Object.entries(mcpServers)) {\n if (isExternalMcpStdioServer(handle)) {\n config[name] = {\n type: \"stdio\",\n command: handle.command,\n ...(handle.args ? { args: handle.args } : {}),\n ...(handle.env ? { env: handle.env } : {}),\n };\n continue;\n }\n const tools = handle instanceof PtyMcpServer ? handle.tools : [];\n if (tools.length === 0) continue;\n const server = new PtyToolServer(name, tools);\n const { url, token } = await server.start();\n servers.push(server);\n config[name] = { type: \"http\", url, headers: { Authorization: `Bearer ${token}` } };\n }\n if (Object.keys(config).length === 0) return { servers, mcpConfigPath: null, entries: config };\n const mcpConfigPath = join(tempDir, \"mcp-config.json\");\n await writeFile(mcpConfigPath, JSON.stringify({ mcpServers: config }, null, 2), \"utf8\");\n return { servers, mcpConfigPath, entries: config };\n}\n","import type { HarnessToolDefinition } from \"../types.js\";\n\ntype ToolResult = Awaited<ReturnType<HarnessToolDefinition[\"handler\"]>>;\n\n/**\n * In-process MCP server handle for the PTY harness.\n *\n * S1 materializes tools as a directly-invokable in-process handle: callers\n * resolve a tool by name and invoke its handler. Wiring these tools to the\n * `claude` CLI over a live stdio MCP transport (via `--mcp-config`) is\n * deferred to S4 — the spawn layer already threads `mcpConfigPath` through\n * for that purpose.\n */\nexport class PtyMcpServer {\n constructor(\n public readonly name: string,\n public readonly tools: HarnessToolDefinition[],\n ) {}\n\n getTool(name: string): HarnessToolDefinition | undefined {\n return this.tools.find((tool) => tool.name === name);\n }\n\n invokeTool(name: string, input: unknown): Promise<ToolResult> {\n const tool = this.getTool(name);\n if (!tool) return Promise.reject(new Error(`Unknown tool: ${name}`));\n return tool.handler(input);\n }\n}\n","/**\n * Synthesizes `<configHome>/.credentials.json` from CLAUDE_CODE_OAUTH_TOKEN so\n * the interactive `claude` TUI starts authenticated in Conveyor-managed cloud\n * environments. The interactive TUI does NOT read CLAUDE_CODE_OAUTH_TOKEN —\n * that env var is honored only in headless/CI runs — so without a credentials\n * file a fresh pod's Connected TUI lands on the login-method picker.\n *\n * Safety policy: never clobber a credentials file a real interactive `/login`\n * wrote. Ownership is decided by a sidecar marker\n * (`<configHome>/.conveyor-credentials.json`) holding a SHA-256 of the access\n * token we last wrote: the file is ours when that hash matches.\n *\n * The marker exists because refreshToken-absence USED to be the ownership\n * signal — our synthesized file had none, a real `/login` always did. That\n * stopped being true once a `claude_oauth` key (in-app sign-in) let Conveyor\n * hold genuinely refreshable credentials, so the old rule would have failed\n * OPEN and started overwriting real logins. Absence of a refreshToken is still\n * honored as a fallback so files written by older agents stay ours.\n *\n * Decision core is pure (planCredentialsWrite) so the overwrite policy can be\n * unit-tested without fs; the effectful wrappers never throw — a GCS-FUSE\n * hiccup must not kill PtySession.start().\n */\n\nimport { chmod, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { FABLE_MODEL } from \"@project/shared\";\nimport { claudeConfigHome } from \"./settings.js\";\nimport {\n buildCredentialsMarker,\n conveyorCredentialsMarkerPath,\n parseCredentialsMarker,\n tokenFingerprint,\n} from \"./credentials-marker.js\";\n\nexport {\n buildCredentialsMarker,\n conveyorCredentialsMarkerPath,\n parseCredentialsMarker,\n tokenFingerprint,\n};\n\n// `claude setup-token` tokens are valid for ~1 year. The exact expiry is\n// unknowable from the token itself; claim a far-future expiresAt so the CLI\n// never decides the credential is expired and attempts a refresh it cannot\n// perform (no refreshToken). The file is re-synthesized on every spawn, so the\n// window slides. Only applies to the legacy `oauth_token` path — a\n// `claude_oauth` key carries a real expiry AND a refresh token.\nconst SYNTH_TOKEN_TTL_MS = 365 * 24 * 60 * 60 * 1000;\n// Rewrite our own file when it has less than this much runway left — a cheap\n// staleness guard for a long-lived file on the persistent user-home mount.\nconst REFRESH_SKEW_MS = 30 * 24 * 60 * 60 * 1000;\n\nexport function claudeCredentialsPath(): string {\n return join(claudeConfigHome(), \".credentials.json\");\n}\n\n/**\n * Only act inside Conveyor-managed cloud environments (GKE claudespace pods\n * export CLAUDESPACE_NAME in entrypoint.sh; GitHub Codespaces set\n * CODESPACE_NAME/CODESPACES) — never touch a developer's real ~/.claude.\n */\nexport function isConveyorCloudEnv(env: NodeJS.ProcessEnv = process.env): boolean {\n return Boolean(env.CLAUDESPACE_NAME || env.CODESPACE_NAME || env.CODESPACES);\n}\n\n/** Token material for the credentials file, from either key kind. */\nexport interface ClaudeOauthMaterial {\n access: string;\n /** Present only for `claude_oauth` keys (in-app sign-in). */\n refresh?: string;\n /** Epoch ms; present only for `claude_oauth` keys. */\n expires?: number;\n /** Epoch ms the refresh token itself dies (~30d), when the grant said so. */\n refreshExpires?: number;\n /**\n * Scopes the grant actually returned. A live login showed the provider\n * withholding `org:create_api_key` from the requested set, so this is\n * replayed from the grant and never assumed.\n */\n scopes?: string[];\n rateLimitTier?: string;\n}\n\n/**\n * Decode CONVEYOR_CLAUDE_OAUTH (base64 JSON of the stored key secret).\n * Returns null for anything malformed so the caller falls back to the legacy\n * single-token path rather than writing a half-formed credential.\n */\nexport function parseClaudeOauthEnv(blob: string | undefined): ClaudeOauthMaterial | null {\n if (!blob) return null;\n try {\n const parsed: unknown = JSON.parse(Buffer.from(blob, \"base64\").toString(\"utf8\"));\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const record = parsed as Record<string, unknown>;\n if (typeof record.access !== \"string\" || record.access === \"\") return null;\n const scopes = Array.isArray(record.scopes)\n ? record.scopes.filter((s): s is string => typeof s === \"string\" && s.length > 0)\n : [];\n return {\n access: record.access,\n refresh: typeof record.refresh === \"string\" && record.refresh ? record.refresh : undefined,\n expires: typeof record.expires === \"number\" ? record.expires : undefined,\n refreshExpires: typeof record.refreshExpires === \"number\" ? record.refreshExpires : undefined,\n scopes: scopes.length > 0 ? scopes : undefined,\n rateLimitTier: typeof record.rateLimitTier === \"string\" ? record.rateLimitTier : undefined,\n };\n } catch {\n return null;\n }\n}\n\nexport interface CredentialsWriteInput {\n isCloud: boolean;\n /** CLAUDE_CODE_OAUTH_TOKEN from the environment. */\n token: string | undefined;\n /** Current file contents; null when the file is missing. */\n existingRaw: string | null;\n now: number;\n /** CONVEYOR_CLAUDE_OAUTH from the environment, when a claude_oauth key won. */\n oauthBlob?: string | undefined;\n /** Current sidecar contents; null when absent. */\n markerRaw?: string | null;\n}\n\nexport type CredentialsPlan =\n | { action: \"skip\"; reason: \"not-cloud\" | \"no-token\" | \"foreign-credentials\" | \"current\" }\n | { action: \"write\"; contents: string; marker: string };\n\ninterface ParsedOauth {\n accessToken: unknown;\n refreshToken: unknown;\n expiresAt: unknown;\n}\n\nfunction parseClaudeAiOauth(raw: string | null): ParsedOauth | null {\n if (!raw || raw.trim() === \"\") return null;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const oauth = (parsed as Record<string, unknown>).claudeAiOauth;\n if (typeof oauth !== \"object\" || oauth === null) return null;\n const record = oauth as Record<string, unknown>;\n return {\n accessToken: record.accessToken,\n refreshToken: record.refreshToken,\n expiresAt: record.expiresAt,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * The synthesized shape is the empirical-iteration point: if a live pod's TUI\n * still shows the login picker, adjust scopes/subscriptionType HERE and\n * re-verify on a Claudespace diagnostic card.\n */\n/**\n * Fallback only. A `claude_oauth` key replays the scopes its grant actually\n * returned (material.scopes) — hardcoding the login set was wrong, because the\n * provider grants a NARROWER set than the CLI requests (a live login withheld\n * `org:create_api_key`), and a credentials file claiming scopes the token does\n * not carry misleads the CLI. This minimal pair stays for the legacy\n * setup-token path, whose grant tells us nothing.\n */\nconst LEGACY_SCOPES = [\"user:inference\", \"user:profile\"];\n\nexport function buildCredentialsFile(material: ClaudeOauthMaterial, now: number): string {\n const refresh = material.refresh;\n return JSON.stringify({\n claudeAiOauth: {\n accessToken: material.access,\n ...(refresh ? { refreshToken: refresh } : {}),\n // With a refresh token the CLI can recover from a real expiry, so report\n // the true one. Without, claim a far-future expiry (see SYNTH_TOKEN_TTL_MS)\n // because a refresh attempt would be unrecoverable.\n expiresAt: refresh && material.expires ? material.expires : now + SYNTH_TOKEN_TTL_MS,\n // The refresh token has its own expiry; the CLI records it, so mirror it\n // when the grant told us rather than leaving the field off.\n ...(material.refreshExpires ? { refreshTokenExpiresAt: material.refreshExpires } : {}),\n scopes: material.scopes?.length ? material.scopes : LEGACY_SCOPES,\n ...(material.rateLimitTier ? { rateLimitTier: material.rateLimitTier } : {}),\n subscriptionType: \"max\",\n },\n });\n}\n\nexport function buildSynthesizedCredentials(token: string, now: number): string {\n return buildCredentialsFile({ access: token }, now);\n}\n\n/**\n * Is the on-disk file ours to overwrite? A sidecar hash matching the file's\n * access token proves we wrote it. Absence of a refreshToken is kept as a\n * fallback so files written by older agents (which wrote no sidecar) stay ours.\n *\n * Deliberately conservative: once the CLI refreshes our credential it rotates\n * the access token, the hash stops matching, and we treat the file as foreign\n * and stop managing it. That is the safe direction — the CLI's refreshed\n * credential is strictly better than anything we would rewrite — but it does\n * mean switching keys on a pod whose CLI already refreshed needs the explicit\n * removal path (key-cycle) rather than an overwrite.\n */\nexport function isConveyorOwnedCredentials(\n existing: ParsedOauth,\n markerHashes: readonly string[],\n): boolean {\n const hasRefresh = typeof existing.refreshToken === \"string\" && existing.refreshToken.length > 0;\n if (!hasRefresh) return true;\n if (markerHashes.length === 0) return false;\n if (typeof existing.accessToken !== \"string\") return false;\n return markerHashes.includes(tokenFingerprint(existing.accessToken));\n}\n\n/** Pure overwrite-policy core — see the decision table in the tests. */\nexport function planCredentialsWrite(input: CredentialsWriteInput): CredentialsPlan {\n if (!input.isCloud) return { action: \"skip\", reason: \"not-cloud\" };\n // A claude_oauth key wins over the bare env token when both are present.\n const material =\n parseClaudeOauthEnv(input.oauthBlob) ?? (input.token ? { access: input.token } : null);\n if (!material) return { action: \"skip\", reason: \"no-token\" };\n\n const markerHashes = parseCredentialsMarker(input.markerRaw ?? null);\n const contents = buildCredentialsFile(material, input.now);\n // Carry the outgoing fingerprint forward so the file currently on disk still\n // counts as ours if the credential write below never lands.\n const marker = buildCredentialsMarker(material.access, input.now, markerHashes[0] ?? null);\n const existing = parseClaudeAiOauth(input.existingRaw);\n // Missing, empty, unparseable, or shapeless file — ours to (re)write.\n if (!existing) return { action: \"write\", contents, marker };\n if (!isConveyorOwnedCredentials(existing, markerHashes)) {\n return { action: \"skip\", reason: \"foreign-credentials\" };\n }\n // A refreshable credential's real expiry is short, so expiry is not a\n // staleness signal for it — matching the access token we hold is. The legacy\n // path keeps the runway check that guards its synthetic year-long expiry.\n const fresh = material.refresh\n ? existing.accessToken === material.access\n : existing.accessToken === material.access &&\n typeof existing.expiresAt === \"number\" &&\n existing.expiresAt > input.now + REFRESH_SKEW_MS;\n // Skip when current to avoid write churn on the GCS-FUSE mount.\n if (fresh) return { action: \"skip\", reason: \"current\" };\n return { action: \"write\", contents, marker };\n}\n\nasync function readRaw(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return null;\n }\n}\n\n// ── TUI auth readiness (login-park detection) ────────────────────────────────\n//\n// A Claudespace pod that boots with NO usable Claude credential — no\n// CLAUDE_CODE_OAUTH_TOKEN, no ANTHROPIC_API_KEY, and no interactive `/login`\n// credentials file — lands the interactive TUI on the sign-in screen (the env\n// token is honored only in headless runs; see the file header). Nothing parses\n// the raw TUI output, so that park is otherwise silent and unrecoverable: the\n// event-loop heartbeat keeps the pod \"alive\" and it is eventually slept as idle\n// with no signal to the team. `classifyTuiAuth` is the deterministic detector\n// used at spawn time (post credential synthesis) to surface an actionable\n// message instead of freezing.\n\nexport interface TuiAuthInput {\n /** Only Conveyor-managed cloud envs synthesize credentials; a dev's local\n * `~/.claude` is never our concern. */\n isCloud: boolean;\n /** CLAUDE_CODE_OAUTH_TOKEN present in the env. */\n hasOauthToken: boolean;\n /** ANTHROPIC_API_KEY present in the env (the CLI authenticates headlessly\n * with it — no login screen). */\n hasApiKey: boolean;\n /** The on-disk credentials file carries an accessToken (our synthesized file\n * or a real interactive `/login`). */\n credsHasAccessToken: boolean;\n}\n\n/**\n * Pure core: will the interactive TUI start authenticated, or park at the\n * sign-in screen? Outside a cloud env we never judge (a developer's own\n * `~/.claude` owns its auth). Inside one, any of an OAuth token, an API key, or\n * an existing accessToken on disk means the TUI boots into the REPL; the\n * absence of all three is the login-park condition.\n */\nexport function classifyTuiAuth(input: TuiAuthInput): \"ready\" | \"no-credential\" {\n if (!input.isCloud) return \"ready\";\n if (input.hasOauthToken || input.hasApiKey || input.credsHasAccessToken) return \"ready\";\n return \"no-credential\";\n}\n\nexport interface TuiAuthReadiness {\n ready: boolean;\n status: \"ready\" | \"no-credential\";\n}\n\n/**\n * Resolve TUI auth readiness from the live environment plus the on-disk\n * credentials file. Call this AFTER credential synthesis (ensureClaudeCredentials\n * in prepareEnvironment) so a freshly-written accessToken counts. `readIdentity`\n * is injectable for tests; it defaults to the real credentials-file reader.\n */\nexport async function resolveTuiAuthReadiness(\n env: NodeJS.ProcessEnv = process.env,\n readIdentity: () => Promise<CredentialsIdentity | null> = readCredentialsIdentity,\n): Promise<TuiAuthReadiness> {\n const isCloud = isConveyorCloudEnv(env);\n // Skip the fs read entirely outside a cloud env — nothing to judge.\n const credsHasAccessToken = isCloud ? Boolean((await readIdentity())?.accessToken) : false;\n const status = classifyTuiAuth({\n isCloud,\n hasOauthToken: Boolean(env.CLAUDE_CODE_OAUTH_TOKEN),\n hasApiKey: Boolean(env.ANTHROPIC_API_KEY),\n credsHasAccessToken,\n });\n return { ready: status === \"ready\", status };\n}\n\nexport interface CredentialsIdentity {\n accessToken: string | null;\n /** A refreshToken means a real interactive /login wrote the file, not us. */\n hasRefreshToken: boolean;\n}\n\n/**\n * Who is the credentials file currently authenticated as? Used by the usage\n * sampler to refuse attributing another account's gauges to this session's key\n * (the file used to be shared across the user's concurrent pods, and a manual\n * /login can still repoint it). Null when the file is missing or unparseable.\n */\nexport async function readCredentialsIdentity(): Promise<CredentialsIdentity | null> {\n const parsed = parseClaudeAiOauth(await readRaw(claudeCredentialsPath()));\n if (!parsed) return null;\n return {\n accessToken: typeof parsed.accessToken === \"string\" ? parsed.accessToken : null,\n hasRefreshToken: typeof parsed.refreshToken === \"string\" && parsed.refreshToken.length > 0,\n };\n}\n\n// ── Verified writes for network-backed homes ────────────────────────────────\n//\n// On the GCS-FUSE user-home mount a write can report success while subsequent\n// reads still serve stale content (metadata cache). The CLI's startup read\n// then sees the OLD config — re-surfacing the startup dialogs these seeds\n// exist to suppress, or (worse) a poisoned customApiKeyResponses entry the\n// sanitize pass just removed. Seen live 2026-07-12: `wrote 389B, read 309B`\n// parked a card's TUI at a startup dialog for 45 minutes. Bounded\n// rewrite-and-verify gives the cache time to converge before the TUI spawns;\n// on exhaustion callers fall through to the previous log-and-proceed behavior.\n\n/** Backoff between verify attempts; total worst-case wait ≈ 3.75s per file. */\nconst READ_BACK_DELAYS_MS = [250, 500, 1000, 2000];\n\nexport interface VerifiedWriteIo {\n write: (contents: string) => Promise<void>;\n read: () => Promise<string | null>;\n sleep?: (ms: number) => Promise<void>;\n}\n\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Write `contents`, then verify a read returns exactly what was written,\n * rewriting and re-reading with backoff until it matches or the delays are\n * exhausted. Returns true when a read-back matched.\n */\nexport async function writeWithReadBackRetry(\n io: VerifiedWriteIo,\n contents: string,\n delaysMs: readonly number[] = READ_BACK_DELAYS_MS,\n): Promise<boolean> {\n const sleep = io.sleep ?? defaultSleep;\n for (let attempt = 0; ; attempt++) {\n await io.write(contents);\n if ((await io.read()) === contents) return true;\n if (attempt >= delaysMs.length) return false;\n await sleep(delaysMs[attempt]);\n }\n}\n\nfunction fsWriteIo(path: string, mode?: number): VerifiedWriteIo {\n return {\n write: (contents) =>\n writeFile(path, contents, mode === undefined ? \"utf8\" : { encoding: \"utf8\", mode }),\n read: () => readRaw(path),\n };\n}\n\n/**\n * Materialize CLAUDE_CODE_OAUTH_TOKEN as a credentials file for the\n * interactive TUI. Best-effort: logs and returns on any failure.\n */\nexport async function ensureClaudeCredentials(env: NodeJS.ProcessEnv = process.env): Promise<void> {\n const isCloud = isConveyorCloudEnv(env);\n const token = env.CLAUDE_CODE_OAUTH_TOKEN;\n // Self-heal first: a prior ANTHROPIC_API_KEY leak may have persisted an\n // \"approved external API key\" entry for this OAuth token in the durable\n // (GCS-FUSE) ~/.claude.json — which makes the CLI send the OAuth token via\n // x-api-key → 401 forever. Drop it before synthesizing the credentials file\n // so the OAuth auth path can take over on this boot. Independent of whether\n // the credentials file itself needs rewriting.\n const material = parseClaudeOauthEnv(env.CONVEYOR_CLAUDE_OAUTH);\n const accessToken = material?.access ?? token;\n if (isCloud && accessToken) {\n await sanitizeApprovedApiKeys(accessToken);\n }\n try {\n const path = claudeCredentialsPath();\n const markerPath = conveyorCredentialsMarkerPath();\n const plan = planCredentialsWrite({\n isCloud,\n token,\n oauthBlob: env.CONVEYOR_CLAUDE_OAUTH,\n existingRaw: await readRaw(path),\n markerRaw: await readRaw(markerPath),\n now: Date.now(),\n });\n if (plan.action === \"skip\") return;\n await mkdir(claudeConfigHome(), { recursive: true });\n // Marker first: a crash between the two writes must not leave a credential\n // we cannot prove is ours (which would strand it as \"foreign\" forever).\n await writeWithReadBackRetry(fsWriteIo(markerPath, 0o600), plan.marker);\n const verified = await writeWithReadBackRetry(fsWriteIo(path, 0o600), plan.contents);\n if (!verified) {\n process.stderr.write(\n `[conveyor-agent] claude credentials read-back still stale after retries at ${path} — TUI may land on the login picker\\n`,\n );\n }\n // The GCS-FUSE CSI mount (file-mode=700) may reject chmod; it already\n // enforces owner-only access, so this is belt-and-braces for local disks.\n await chmod(path, 0o600).catch(() => {});\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] claude credentials sync failed: ${message}\\n`);\n }\n}\n\n/** Claude Code remembers an approved/rejected external API key by the last 20\n * characters of the key, stored in customApiKeyResponses. */\nexport function apiKeyApprovalSuffix(token: string): string {\n return token.slice(-20);\n}\n\n/**\n * Pure core: given the current ~/.claude.json contents and the OAuth token we\n * are injecting, drop any `customApiKeyResponses.approved` entry matching the\n * token's last-20-char suffix. Returns the sanitized JSON string, or null when\n * there is nothing to remove (no write needed).\n *\n * Such an entry can only exist through the ANTHROPIC_API_KEY leak: the pod once\n * exported the subscription OAuth token as ANTHROPIC_API_KEY and a human\n * answered \"yes, use this API key\" in the TUI. From then on the CLI sends the\n * OAuth token via `x-api-key` → 401 \"Invalid API key · Fix external API key\",\n * on every future pod for that user+project (the entry lives on the persistent\n * GCS-FUSE home). Removing it lets the synthesized OAuth credentials win again.\n */\nexport function planApprovedApiKeyCleanup(\n existingRaw: string | null,\n oauthToken: string,\n): string | null {\n if (!oauthToken) return null;\n const config = parseClaudeJson(existingRaw);\n const responses = config.customApiKeyResponses;\n if (typeof responses !== \"object\" || responses === null || Array.isArray(responses)) {\n return null;\n }\n const record = responses as Record<string, unknown>;\n const approved = record.approved;\n if (!Array.isArray(approved)) return null;\n const suffix = apiKeyApprovalSuffix(oauthToken);\n const filtered = approved.filter((entry) => entry !== suffix);\n if (filtered.length === approved.length) return null;\n record.approved = filtered;\n return JSON.stringify(config);\n}\n\n/**\n * Effectful wrapper for planApprovedApiKeyCleanup. Best-effort and isolated in\n * its own try/catch so a GCS-FUSE hiccup can never block credential synthesis.\n */\nasync function sanitizeApprovedApiKeys(oauthToken: string): Promise<void> {\n try {\n const path = claudeJsonPath();\n const cleaned = planApprovedApiKeyCleanup(await readRaw(path), oauthToken);\n if (cleaned === null) return;\n const verified = await writeWithReadBackRetry(fsWriteIo(path), cleaned);\n process.stderr.write(\n verified\n ? \"[conveyor-agent] removed poisoned customApiKeyResponses.approved entry from .claude.json\\n\"\n : `[conveyor-agent] approved-key sanitize read-back still stale after retries at ${path} — CLI may still see the poisoned entry\\n`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] claude approved-key sanitize failed: ${message}\\n`);\n }\n}\n\n/**\n * Path of the CLI's main config. Lives at $HOME/.claude.json normally; when\n * CLAUDE_CONFIG_DIR is set the CLI relocates it under that directory.\n */\nexport function claudeJsonPath(): string {\n const configDir = process.env.CLAUDE_CONFIG_DIR;\n return configDir ? join(configDir, \".claude.json\") : join(homedir(), \".claude.json\");\n}\n\n/**\n * Pure decision core for the onboarding + trust seed. Returns the contents to\n * write, or null when no write is needed.\n *\n * Unlike the entrypoint's only-if-empty seeding, this MERGES into an existing\n * config: the CLI rewrites .claude.json during a first-run wizard (cache keys,\n * firstStartTime, …) WITHOUT setting hasCompletedOnboarding until the wizard\n * finishes. On a persistent user-home (GCS-FUSE) an abandoned wizard therefore\n * leaves a config that re-triggers onboarding on every subsequent pod — seen\n * live: credentials valid (`claude auth status` → loggedIn:true) yet the TUI\n * parked at the theme picker. All CLI-owned keys are preserved.\n *\n * `trustCwd` pre-accepts the folder-trust dialog for the workspace the TUI is\n * about to run in (`projects[\"<cwd>\"].hasTrustDialogAccepted`) — the dialog is\n * the third first-run gate after theme and login, also seen parking a live\n * pod. Trusting the Conveyor-managed repo clone is definitionally correct in\n * this environment. The theme default is only applied when creating a fresh\n * config: the CLI drops unused keys on rewrite, and re-adding theme on every\n * spawn would cause a guaranteed write per spawn for zero behavior change\n * (the theme picker is gated on hasCompletedOnboarding, not theme).\n */\nfunction asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/** Parse the existing .claude.json; corrupt/non-object input becomes a fresh\n * config (the CLI treats unparseable files as fatal, so replacing is a repair). */\nfunction parseClaudeJson(existingRaw: string | null): Record<string, unknown> {\n if (!existingRaw || existingRaw.trim() === \"\") return {};\n try {\n return asRecord(JSON.parse(existingRaw));\n } catch {\n return {};\n }\n}\n\n/** Pre-accept the folder-trust dialog for `trustCwd`. Returns true if changed. */\nfunction seedWorkspaceTrust(config: Record<string, unknown>, trustCwd: string): boolean {\n const projects = asRecord(config.projects);\n const entry = asRecord(projects[trustCwd]);\n if (entry.hasTrustDialogAccepted === true) return false;\n entry.hasTrustDialogAccepted = true;\n projects[trustCwd] = entry;\n config.projects = projects;\n return true;\n}\n\n/**\n * The `/model` picker row a real interactive login receives from the CLI's\n * bootstrap fetch. Pods run on synthesized credentials whose bootstrap fetch\n * does not populate this cache, so without the seed Fable never appears in the\n * in-pod picker even though `--model claude-fable-5` spawns work. The `[1m]`\n * suffix is the CLI's 1M-context variant marker on the entitlement entry.\n */\nconst FABLE_MODEL_OPTION = {\n value: `${FABLE_MODEL}[1m]`,\n label: \"Fable\",\n description: \"Fable 5 - most capable for your hardest and longest-running tasks\",\n};\n\n/**\n * Ensure the CLI's cached model-picker options include a Fable row. Appends\n * only when no Fable-valued entry exists — a cache the CLI wrote from a real\n * bootstrap fetch is the account's actual entitlement set and is otherwise\n * left alone (the CLI rewrites it wholesale on a successful fetch anyway).\n */\nfunction seedFableModelOption(config: Record<string, unknown>): boolean {\n const cache = Array.isArray(config.additionalModelOptionsCache)\n ? (config.additionalModelOptionsCache as unknown[])\n : [];\n const hasFable = cache.some((entry) => {\n if (typeof entry !== \"object\" || entry === null) return false;\n const value = (entry as Record<string, unknown>).value;\n return typeof value === \"string\" && value.toLowerCase().includes(\"fable\");\n });\n if (hasFable) return false;\n config.additionalModelOptionsCache = [...cache, { ...FABLE_MODEL_OPTION }];\n return true;\n}\n\n/** Org/account identity the CLI keys the Fable usage-credits consent on. */\nexport interface OauthAccountIdentity {\n organizationUuid?: string;\n accountUuid?: string;\n}\n\nfunction normalizeOauthIdentity(record: Record<string, unknown>): OauthAccountIdentity | null {\n const organizationUuid =\n typeof record.organizationUuid === \"string\" && record.organizationUuid !== \"\"\n ? record.organizationUuid\n : undefined;\n const accountUuid =\n typeof record.accountUuid === \"string\" && record.accountUuid !== \"\"\n ? record.accountUuid\n : undefined;\n if (!organizationUuid && !accountUuid) return null;\n return { organizationUuid, accountUuid };\n}\n\n/** Identity from the CLI-written `oauthAccount` in ~/.claude.json, if any. */\nexport function extractOauthIdentity(config: Record<string, unknown>): OauthAccountIdentity | null {\n return normalizeOauthIdentity(asRecord(config.oauthAccount));\n}\n\n/**\n * Pre-answer the Fable usage-credits consent dialog. The CLI records consent\n * as `fableOverageConsentV2[<organizationUuid>] = true` (or `acct:<accountUuid>`\n * when the account has no org). Without it, a Fable turn parks an interactive\n * TUI at the consent dialog, and no-dialog contexts silently fall back to a\n * non-Fable model — both break auto cards. The UUID comes from the CLI-written\n * `oauthAccount` when this pod's CLI has already run, else from the marker\n * persisted in the shared config home (see `persistOauthIdentityMarker`).\n */\nfunction seedFableConsent(\n config: Record<string, unknown>,\n fallbackIdentity: OauthAccountIdentity | null,\n): boolean {\n const identity = extractOauthIdentity(config) ?? fallbackIdentity;\n if (!identity) return false;\n const consent = asRecord(config.fableOverageConsentV2);\n let changed = false;\n const keys = [\n ...(identity.organizationUuid ? [identity.organizationUuid] : []),\n ...(identity.accountUuid ? [`acct:${identity.accountUuid}`] : []),\n ];\n for (const key of keys) {\n if (consent[key] !== true) {\n consent[key] = true;\n changed = true;\n }\n }\n if (changed) config.fableOverageConsentV2 = consent;\n return changed;\n}\n\nexport function planClaudeJsonSeed(\n existingRaw: string | null,\n trustCwd?: string,\n oauthIdentity?: OauthAccountIdentity | null,\n): string | null {\n const config = parseClaudeJson(existingRaw);\n const isFresh = Object.keys(config).length === 0;\n let changed = false;\n if (config.hasCompletedOnboarding !== true) {\n config.hasCompletedOnboarding = true;\n changed = true;\n }\n // Pre-answer the \"Bypass Permissions mode\" warning dialog the CLI shows on\n // the first `--dangerously-skip-permissions` launch. Seeded unconditionally:\n // the flag is inert for plan-mode spawns, no human is at the keyboard in\n // cloud envs to press \"Yes, I accept\", and the permission mode can flip\n // between spawns sharing one persistent user-home.\n if (config.bypassPermissionsModeAccepted !== true) {\n config.bypassPermissionsModeAccepted = true;\n changed = true;\n }\n if (isFresh && typeof config.theme !== \"string\") {\n config.theme = \"dark\";\n changed = true;\n }\n if (trustCwd && seedWorkspaceTrust(config, trustCwd)) {\n changed = true;\n }\n if (seedFableModelOption(config)) {\n changed = true;\n }\n if (seedFableConsent(config, oauthIdentity ?? null)) {\n changed = true;\n }\n return changed ? JSON.stringify(config) : null;\n}\n\n/**\n * Marker persisting the CLI's `oauthAccount` identity in the SHARED config\n * home (GCS-FUSE), because ~/.claude.json is pod-local and rebuilt every boot:\n * consent recorded there — seeded or granted by a human — dies with the pod.\n * The first spawn of a fresh pod reads the marker to seed consent before the\n * CLI starts; once the CLI's bootstrap fetch writes `oauthAccount`, later\n * spawns capture it here for every future pod of this user+project.\n */\nexport function conveyorOauthMarkerPath(): string {\n return join(claudeConfigHome(), \"conveyor-oauth-account.json\");\n}\n\nfunction parseOauthIdentity(raw: string | null): OauthAccountIdentity | null {\n if (!raw || raw.trim() === \"\") return null;\n try {\n return normalizeOauthIdentity(asRecord(JSON.parse(raw)));\n } catch {\n return null;\n }\n}\n\nasync function persistOauthIdentityMarker(\n configIdentity: OauthAccountIdentity | null,\n markerIdentity: OauthAccountIdentity | null,\n): Promise<void> {\n try {\n if (!configIdentity) return;\n if (\n markerIdentity !== null &&\n markerIdentity.organizationUuid === configIdentity.organizationUuid &&\n markerIdentity.accountUuid === configIdentity.accountUuid\n ) {\n return;\n }\n await mkdir(claudeConfigHome(), { recursive: true });\n const verified = await writeWithReadBackRetry(\n fsWriteIo(conveyorOauthMarkerPath()),\n JSON.stringify(configIdentity),\n );\n if (verified) {\n process.stderr.write(\"[conveyor-agent] persisted oauth identity marker for fable consent\\n\");\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] oauth identity marker write failed: ${message}\\n`);\n }\n}\n\n/**\n * Suppress the CLI's first-run wizard, the bypass-permissions warning dialog,\n * (when `trustCwd` is given) the folder-trust dialog for that workspace, and\n * the Fable picker/consent gates in Conveyor cloud envs so the spawned TUI\n * boots straight into the REPL. Runs regardless of token presence\n * — with credentials the gates are pure friction; without them the\n * post-onboarding login screen is strictly better than the full wizard.\n * Best-effort, never throws.\n */\nexport async function ensureClaudeOnboarding(\n env: NodeJS.ProcessEnv = process.env,\n trustCwd?: string,\n): Promise<void> {\n try {\n if (!isConveyorCloudEnv(env)) return;\n const path = claudeJsonPath();\n const existingRaw = await readRaw(path);\n const markerIdentity = parseOauthIdentity(await readRaw(conveyorOauthMarkerPath()));\n // Capture the CLI-written oauthAccount into the shared-home marker so the\n // NEXT pod's first spawn can seed fable consent before its CLI ever runs.\n await persistOauthIdentityMarker(\n extractOauthIdentity(parseClaudeJson(existingRaw)),\n markerIdentity,\n );\n const contents = planClaudeJsonSeed(existingRaw, trustCwd, markerIdentity);\n if (contents === null) return;\n const verified = await writeWithReadBackRetry(fsWriteIo(path), contents);\n if (verified) {\n process.stderr.write(\n `[conveyor-agent] claude onboarding seeded${trustCwd ? ` (trust: ${trustCwd})` : \"\"}\\n`,\n );\n } else {\n const verify = await readRaw(path);\n process.stderr.write(\n `[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path} after retries: wrote ${contents.length}B, read ${verify?.length ?? 0}B — CLI may see stale config and park at a startup dialog\\n`,\n );\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] claude onboarding seed failed: ${message}\\n`);\n }\n}\n\n/**\n * Delete the credentials file only when it is ours (same ownership test as the\n * write path). Used when a runtime key update switches the agent to\n * ANTHROPIC_API_KEY — stale subscription credentials must not keep\n * authenticating the next TUI spawn.\n */\nexport async function removeConveyorCredentials(\n env: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n try {\n if (!isConveyorCloudEnv(env)) return;\n const path = claudeCredentialsPath();\n const markerPath = conveyorCredentialsMarkerPath();\n const existing = parseClaudeAiOauth(await readRaw(path));\n if (\n existing &&\n !isConveyorOwnedCredentials(existing, parseCredentialsMarker(await readRaw(markerPath)))\n ) {\n return;\n }\n await rm(path, { force: true });\n // The marker describes a file that no longer exists; leaving it would let a\n // later real /login coincidentally inherit ownership if tokens ever matched.\n await rm(markerPath, { force: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] claude credentials removal failed: ${message}\\n`);\n }\n}\n","/**\n * Sidecar marker proving which `.credentials.json` Conveyor wrote.\n *\n * Ownership used to be inferred from the ABSENCE of a refreshToken — our\n * synthesized file had none, a real interactive `/login` always did. A\n * `claude_oauth` key (in-app sign-in) makes Conveyor hold refreshable\n * credentials too, so that signal would fail OPEN and start overwriting real\n * logins. This marker replaces it; see credentials.ts for the policy that\n * consumes it.\n */\nimport { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport { claudeConfigHome } from \"./settings.js\";\n\n/** Sidecar recording which access token Conveyor last wrote. */\nexport function conveyorCredentialsMarkerPath(): string {\n return join(claudeConfigHome(), \".conveyor-credentials.json\");\n}\n\n/** Hash, never the token itself — the marker sits beside the credential. */\nexport function tokenFingerprint(accessToken: string): string {\n return createHash(\"sha256\").update(accessToken).digest(\"hex\");\n}\n\n/**\n * The marker carries the PREVIOUS fingerprint alongside the new one so both\n * count as ours. Without it, a credential write that fails its read-back (the\n * GCS-FUSE case writeWithReadBackRetry exists for) would leave a marker naming\n * a token that never landed: the file still on disk would stop matching, and\n * both the write path and removeConveyorCredentials would call it foreign\n * forever, permanently stranding the pod's own credential.\n */\nexport function buildCredentialsMarker(\n accessToken: string,\n now: number,\n previousHash?: string | null,\n): string {\n const accessTokenSha256 = tokenFingerprint(accessToken);\n return JSON.stringify({\n accessTokenSha256,\n ...(previousHash && previousHash !== accessTokenSha256\n ? { previousAccessTokenSha256: previousHash }\n : {}),\n writtenAt: now,\n });\n}\n\n/** Every fingerprint the marker vouches for, newest first. */\nexport function parseCredentialsMarker(raw: string | null): string[] {\n if (!raw || raw.trim() === \"\") return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) return [];\n const record = parsed as Record<string, unknown>;\n return [record.accessTokenSha256, record.previousAccessTokenSha256].filter(\n (hash): hash is string => typeof hash === \"string\" && hash.length > 0,\n );\n } catch {\n return [];\n }\n}\n","/**\n * ClaudeTuiAdapter — the extracted Claude-specific half of the former\n * hard-wired PtySession behavior. Pure delegation to the existing modules:\n * zero behavior change is the contract (pinned by the keep-alive and int\n * tests). resolveBinary stays deliberately lenient (never throws): claude is\n * always baked into the pod image and the exit diagnostics already explain a\n * missing binary; new adapters should fail loudly instead.\n */\nimport { buildExitErrors, buildSpawnArgs, spawnOptionsFingerprint } from \"../spawn-args.js\";\nimport { ensureClaudeCredentials, ensureClaudeOnboarding } from \"../credentials.js\";\nimport { buildPromptBytes, inheritedEnv } from \"../pty-support.js\";\nimport type {\n TuiAdapter,\n TuiCapabilities,\n TuiFingerprintInput,\n TuiSpawnInput,\n TuiSpawnSpec,\n} from \"./types.js\";\n\nexport class ClaudeTuiAdapter implements TuiAdapter {\n readonly id = \"claude-code\" as const;\n readonly capabilities: TuiCapabilities = {\n resume: true,\n structuredEvents: true,\n prefill: true,\n passiveTurns: true,\n rawPromptGate: false,\n };\n\n resolveBinary(env: NodeJS.ProcessEnv = process.env): string {\n return env.CONVEYOR_CLAUDE_BIN ?? \"claude\";\n }\n\n buildSpawn(input: TuiSpawnInput): TuiSpawnSpec {\n const { options, resume } = input;\n const args = buildSpawnArgs({\n ...(resume ? { resume } : {}),\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n model: options.model,\n permissionMode: options.permissionMode,\n settingsPath: input.settingsPath ?? \"\",\n ...(options.appendSystemPrompt ? { appendSystemPrompt: options.appendSystemPrompt } : {}),\n ...(input.mcpConfigPath ? { mcpConfigPath: input.mcpConfigPath, strictMcpConfig: true } : {}),\n });\n return {\n file: this.resolveBinary(),\n args,\n env: inheritedEnv(input.hookSocketPath),\n };\n }\n\n async prepareEnvironment(opts: { cwd: string; env?: NodeJS.ProcessEnv }): Promise<void> {\n const env = opts.env ?? process.env;\n await ensureClaudeCredentials(env);\n await ensureClaudeOnboarding(env, opts.cwd);\n }\n\n spawnFingerprint(input: TuiFingerprintInput): string {\n return spawnOptionsFingerprint(input);\n }\n\n encodePromptBytes(text: string): string {\n return buildPromptBytes(text);\n }\n\n buildExitErrors(exitCode: number, rawOutput: string): string[] {\n return buildExitErrors(exitCode, rawOutput, this.resolveBinary());\n }\n}\n","/**\n * Config-home mount health + pod-local fallback.\n *\n * In a claudespace pod, `~/.claude` is a per-user GCS FUSE mount (see\n * `.claude/rules/claude-session-persistence.md`). When the gcsfuse socket drops,\n * every fs op under it fails with `ENOTCONN: socket is not connected` — including\n * the transcript-dir `mkdir` the PTY harness runs before spawning the CLI and the\n * credentials write in `prepareEnvironment`. The turn dies with a raw ENOTCONN,\n * and because it isn't a retriable API error, re-sending to the agent just re-runs\n * against the still-dead mount: only a full pod recreate (which remounts gcsfuse)\n * recovers. Observed live as \"Builder stuck: ENOTCONN error on mkdir, restart\n * doesn't fix it\".\n *\n * This module detects that mount-disconnect class and self-heals by pointing\n * Claude's config home at a **pod-local** directory (`~/.claude-local`, on the\n * pod's real overlay disk — only `~/.claude` itself is the symlinked mount) via\n * `CLAUDE_CONFIG_DIR`. Since `claudeConfigHome()` is read by the transcript path,\n * the credentials path, onboarding (`claudeJsonPath`), and the spawned CLI's env\n * (`inheritedEnv` copies `process.env`), one flip cascades to our code and the\n * child CLI alike. Credentials + onboarding are re-synthesized every boot, so a\n * fresh pod-local config home is fully functional; the only degradation is that\n * cross-pod transcript persistence is lost for that session (a `--resume` miss is\n * already handled by the query executor's stale-session recovery). The agent keeps\n * working WITHOUT a pod restart.\n */\n\nimport { lstat, mkdir, symlink, unlink } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { claudeConfigHome, projectSlug } from \"./settings.js\";\n\n/** fs error codes a dead FUSE mount raises on any op under the mount point. */\nconst MOUNT_DISCONNECT_CODES = new Set([\"ENOTCONN\", \"EIO\", \"ESTALE\", \"ENXIO\"]);\n\nconst MOUNT_DISCONNECT_MESSAGES = [\n \"socket is not connected\",\n \"transport endpoint is not connected\",\n];\n\n/**\n * Does `err` look like the shared GCS FUSE mount having dropped its socket?\n * Matches on the fs error `code` (primary signal) or the message text (belt and\n * braces for wrappers that lose `code`).\n */\nexport function isMountDisconnectError(err: unknown): boolean {\n if (typeof err !== \"object\" || err === null) return false;\n const code = (err as { code?: unknown }).code;\n if (typeof code === \"string\" && MOUNT_DISCONNECT_CODES.has(code)) return true;\n const message = (err as { message?: unknown }).message;\n if (typeof message !== \"string\") return false;\n const lower = message.toLowerCase();\n return MOUNT_DISCONNECT_MESSAGES.some((needle) => lower.includes(needle));\n}\n\n/** Pod-local config home used when the shared `~/.claude` mount is unusable. */\nexport function podLocalConfigHome(): string {\n return join(homedir(), \".claude-local\");\n}\n\n/** The literal `~/.claude` path — in a pod, the symlink into the GCS FUSE mount. */\nexport function sharedConfigHomePath(): string {\n return join(homedir(), \".claude\");\n}\n\n/**\n * True when the pod-local fallback is already in effect — i.e. the shared\n * mount was found dead earlier this process and `CLAUDE_CONFIG_DIR` was\n * flipped. Callers use it as \"the mount is confirmed dead\" evidence before\n * escalating to a pod recycle.\n */\nexport function isConfigHomeFallbackActive(): boolean {\n return claudeConfigHome() === podLocalConfigHome();\n}\n\nexport interface ConfigHomeHealth {\n /** The config home in effect after the check (flipped to pod-local on fallback). */\n configHome: string;\n /** True when the shared mount was unusable and we fell back to pod-local. */\n fellBack: boolean;\n}\n\ntype Logger = { warn(message: string, data?: Record<string, unknown>): void };\n\n/**\n * Re-point the literal `~/.claude` symlink at the pod-local config home.\n *\n * `CLAUDE_CONFIG_DIR` only redirects paths derived from `claudeConfigHome()`.\n * The CLI (and any tooling it shells out to) still has home-relative reads that\n * resolve `~/.claude` directly, and every one of those keeps hitting the dead\n * mount — the most likely reason a respawn after a successful fallback still\n * parks with no transcript record. Re-pointing the symlink closes that gap.\n *\n * Safe by construction: the symlink is pod-local, the mount itself lives at\n * `/mnt/conveyor-users`, and the entrypoint re-creates the link against the\n * fresh mount on the next pod boot. Best-effort — never throws, and never\n * touches a `~/.claude` that is a real directory (a dev machine, not a pod).\n */\nexport async function repointSharedConfigHomeSymlink(\n fallback: string,\n log?: Logger,\n): Promise<boolean> {\n const shared = sharedConfigHomePath();\n if (shared === fallback) return false;\n try {\n const info = await lstat(shared);\n // Only a symlink is ours to move. A real directory means this is not the\n // pod mount layout, so leave the user's own ~/.claude alone.\n if (!info.isSymbolicLink()) return false;\n } catch {\n return false;\n }\n try {\n await unlink(shared);\n await symlink(fallback, shared);\n log?.warn(\"re-pointed the ~/.claude symlink at the pod-local config home\", {\n from: shared,\n to: fallback,\n });\n return true;\n } catch (err) {\n log?.warn(\"could not re-point the ~/.claude symlink; home-relative reads stay broken\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return false;\n }\n}\n\n/**\n * Cheap liveness probe of the config home — the same write the spawn path\n * performs, reported as a boolean instead of a flip. `true` means the mount is\n * disconnected. A non-mount error reports `false`: only a mount-disconnect code\n * is evidence the shared home died, and a probe must never invent one.\n *\n * Used by the mid-turn watchdog, which needs a verdict rather than a repair —\n * the repair belongs to the respawn that follows the abort.\n */\nexport async function isConfigHomeMountDead(cwd: string): Promise<boolean> {\n try {\n await mkdir(join(claudeConfigHome(), \"projects\", projectSlug(cwd)), { recursive: true });\n return false;\n } catch (err) {\n return isMountDisconnectError(err);\n }\n}\n\n/**\n * Ensure the Claude config home is writable before a spawn. Write-probes the\n * transcript's `projects/<slug>` directory (the exact op that wedges on a dead\n * mount); on a mount-disconnect error, flips `CLAUDE_CONFIG_DIR` to a pod-local\n * dir and creates it there. Non-mount errors are real bugs and rethrow.\n *\n * Idempotent: once flipped, later calls probe the pod-local dir and report\n * `fellBack: false` (the env already points there and the probe succeeds).\n */\nexport async function ensureUsableClaudeConfigHome(\n cwd: string,\n log?: Logger,\n): Promise<ConfigHomeHealth> {\n const configHome = claudeConfigHome();\n try {\n await mkdir(join(configHome, \"projects\", projectSlug(cwd)), { recursive: true });\n return { configHome, fellBack: false };\n } catch (err) {\n if (!isMountDisconnectError(err)) throw err;\n\n const fallback = podLocalConfigHome();\n log?.warn(\n \"shared ~/.claude mount is unreachable; falling back to a pod-local config home. \" +\n \"Session history will not persist across pods until the mount recovers.\",\n {\n code: (err as { code?: unknown }).code ?? null,\n from: configHome,\n to: fallback,\n },\n );\n // Cascades to our path helpers (transcript, credentials, onboarding) and to\n // the spawned CLI via inheritedEnv, which snapshots process.env at spawn.\n process.env.CLAUDE_CONFIG_DIR = fallback;\n await mkdir(join(fallback, \"projects\", projectSlug(cwd)), { recursive: true });\n // The env flip misses everything that resolves literal `~/.claude`, so move\n // the symlink too. Best-effort: a failure here degrades to the env-only\n // behavior we already had, it never fails the spawn.\n await repointSharedConfigHomeSymlink(fallback, log);\n return { configHome: fallback, fellBack: true };\n }\n}\n","/**\n * PtyHarness — drives the `claude` CLI under a pseudo-terminal behind the\n * generic `AgentHarness` interface. Selected at runtime via\n * `createHarness(\"pty\")`. It is the UNCONDITIONAL harness for the task chat\n * (cards); see `resolveHarnessKind()` in `runner/query-bridge.ts`. The only way\n * to put a card on the SDK harness is the maintainer override\n * `CONVEYOR_FORCE_SDK_CARDS=1`.\n *\n * Keep-alive: the interactive `claude` process outlives any single query. When\n * a query ends via a clean transcript `result`, the harness PARKS the\n * `PtySession` (process still running) instead of killing it, so the\n * Connected-TUI stays live and interactive while the agent is idle. The next\n * query reuses that process when its resume target + spawn options match;\n * otherwise it tears the parked one down and spawns fresh. Only a real process\n * death (crash while parked, or dispose() on shutdown/hard-stop) signals\n * `pty:ended` so the server clears the ring and the tab hides.\n */\n\nimport type {\n AgentHarness,\n HarnessEvent,\n HarnessQueryOptions,\n HarnessToolDefinition,\n HarnessMcpServer,\n HarnessUserMessage,\n PtyBridge,\n} from \"../types.js\";\nimport { PtySession } from \"./session.js\";\nimport { PtyMcpServer } from \"./mcp-server.js\";\nimport { ClaudeTuiAdapter } from \"./adapters/claude.js\";\nimport type { TuiAdapter } from \"./adapters/types.js\";\nimport { resolveSubmitRedeliveryMaxAttempts } from \"./pty-support.js\";\nimport { ensureUsableClaudeConfigHome, isConfigHomeFallbackActive } from \"./config-home-health.js\";\nimport { resolveTuiAuthReadiness } from \"./credentials.js\";\nimport { createServiceLogger } from \"../../utils/logger.js\";\n\nexport { PtySession, PtyMcpServer };\n\n// Grace window before a process death is reported as `pty:ended`. A respawn\n// (the common mid-turn abort → respawn-with-resume flow, e.g. a superseding\n// chat message) within this window cancels the signal, so the Connected-TUI tab\n// doesn't flap. Parked-death and dispose() bypass the grace and signal at once.\nconst ENDED_GRACE_MS = 4000;\n\nexport class PtyHarness implements AgentHarness {\n private static readonly log = createServiceLogger(\"pty-harness\");\n\n /**\n * `bridge` relays raw terminal I/O to/from the S2 server (and on to the S5\n * terminal). It is undefined for SDK-only callers and PTY runs that never\n * attach a relay; the session simply discards stdout in that case.\n */\n constructor(\n private readonly bridge?: PtyBridge,\n private readonly adapter: TuiAdapter = new ClaudeTuiAdapter(),\n ) {}\n\n /** Delegated to the adapter: Claude tails a transcript + hook socket, opencode\n * tails its plugin sink, and a raw-relay TUI has no trusted event source. */\n get emitsStructuredEvents(): boolean {\n return this.adapter.capabilities.structuredEvents;\n }\n\n /**\n * Does this adapter own the shared `~/.claude` config home (credentials,\n * transcripts, onboarding flags)? Claude alone does — opencode keeps its\n * state under `~/.local/share/opencode` and its event sink in the session\n * tempDir.\n *\n * Gate every `~/.claude` probe on this, NOT on\n * `capabilities.structuredEvents`. That flag meant \"is this Claude\" only by\n * accident — Claude was the sole adapter that had it. Once the opencode\n * adapter gained structured events via the plugin sink, the proxy silently\n * inverted and opencode cards began running Claude-only probes.\n */\n private get ownsClaudeConfigHome(): boolean {\n return this.adapter.id === \"claude-code\";\n }\n\n /** Fingerprint of the spawn-time options a reused process cannot change. */\n private fingerprintOf(options: HarnessQueryOptions): string {\n return this.adapter.spawnFingerprint({\n model: options.model,\n permissionMode: options.permissionMode,\n ...(options.appendSystemPrompt ? { appendSystemPrompt: options.appendSystemPrompt } : {}),\n cwd: options.cwd,\n });\n }\n\n /** The session currently streaming events, if any — repaint target. */\n private activeSession: PtySession | null = null;\n /** A completed-but-alive session kept for the next turn (keep-alive). */\n private parked: PtySession | null = null;\n /** Pending \"process died\" → `pty:ended` timer (grace window). */\n private endedTimer: ReturnType<typeof setTimeout> | null = null;\n /** Passive-activity subscriber, re-attached to whichever session is parked. */\n private passiveHandler: (() => void) | null = null;\n /** Once-per-session guard so the \"no Claude credential\" notice isn't re-posted\n * on every respawn (a fresh spawn happens on each fingerprint/lineage flip). */\n private authNoticeSent = false;\n /** Once-per-process guard on the pod-recycle escalation (see escalateToPodRecycle). */\n private recycleRequested = false;\n\n /**\n * Wiggle the live pty's size so the CLI repaints its whole screen. No-op on\n * the SDK harness. Falls back to the parked session so an API reconnect while\n * the CLI is idle still re-seeds the server's scrollback ring.\n */\n forceRepaint(): void {\n (this.activeSession ?? this.parked)?.forceRepaint();\n }\n\n /** Actionable message posted to the card when a spawn will park at the Claude\n * sign-in screen. Kept as a constant so the harness stays free of i18n deps. */\n private static readonly AUTH_NOT_READY_MESSAGE =\n \"⚠️ This pod started the Claude Code TUI with no Claude credential, so it is \" +\n \"parked on the sign-in screen and can't make progress. This usually means \" +\n \"there is no usable Claude subscription token or API key configured for this \" +\n \"project/assignee. Add or repair the Claude credential in project settings, \" +\n \"then restart the session.\";\n\n /**\n * Best-effort: if the TUI is about to spawn with no usable credential, post a\n * one-time diagnostic through the relay bridge. Never throws — a readiness\n * probe must not block or fail a spawn.\n */\n private async warnIfAuthNotReady(): Promise<void> {\n if (this.authNoticeSent || !this.bridge?.notifyAuthNotReady) return;\n try {\n const readiness = await resolveTuiAuthReadiness();\n if (readiness.ready) return;\n this.authNoticeSent = true;\n this.bridge.notifyAuthNotReady(PtyHarness.AUTH_NOT_READY_MESSAGE);\n PtyHarness.log.warn(\n \"Claude TUI spawning with no usable credential — parked at sign-in screen\",\n );\n } catch (err) {\n PtyHarness.log.warn(\"auth-readiness probe failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n async *executeQuery(opts: {\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>;\n options: HarnessQueryOptions;\n resume?: string;\n }): AsyncGenerator<HarnessEvent, void> {\n // Self-managed-lineage adapters (opencode) report their engine-assigned\n // session id via the parked session; the executor can never resolve it\n // from disk, so a respawn (fingerprint drift, dead process) falls back to\n // that id to continue the same conversation. Claude sessions never report\n // one, so their resume semantics are untouched.\n const want = opts.resume ?? opts.options.resume ?? this.parked?.reportedSessionId ?? undefined;\n const fingerprint = this.fingerprintOf(opts.options);\n\n let session: PtySession;\n if (this.parked?.canReuse(want, fingerprint) && !(await this.parkedHomeDied(opts.options))) {\n // Reuse the live process: feed the follow-up prompt into the existing pty\n // instead of respawning. A new turn means no death is imminent — cancel\n // any pending ended signal.\n session = this.parked;\n this.parked = null;\n this.cancelEndedTimer();\n await session.beginTurn(opts.prompt, opts.options);\n } else {\n // Lineage/options mismatch, no parked session, or a dead one: tear down\n // any parked process (respawn — suppress its ended signal, a fresh spawn\n // follows immediately) and start a new one.\n if (this.parked) {\n const stale = this.parked;\n this.parked = null;\n this.cancelEndedTimer();\n await stale.teardown();\n }\n session = await this.spawnSession(opts.prompt, opts.options, want);\n }\n\n yield* this.drain(session);\n yield* this.recoverFailedDelivery(session, opts.options, want);\n }\n\n /**\n * Did the shared `~/.claude` mount die while this session sat parked?\n *\n * The reuse path never touched the config home, so a mount that dropped\n * during the idle window went undetected until the reused process wedged the\n * next turn exactly like the one that died. Probing here flips\n * `CLAUDE_CONFIG_DIR` (and the `~/.claude` symlink) BEFORE the decision, then\n * reports true so the caller tears the parked process down and respawns — a\n * live process cannot adopt a new config home, its env was snapshotted at\n * spawn.\n *\n * Claude-only (opencode has no `~/.claude`), and best-effort: a probe error\n * that is not a mount disconnect is a real bug the spawn path will rethrow,\n * so here it just declines to force a respawn.\n */\n private async parkedHomeDied(options: HarnessQueryOptions): Promise<boolean> {\n if (!this.ownsClaudeConfigHome) return false;\n try {\n const { fellBack } = await ensureUsableClaudeConfigHome(options.cwd, PtyHarness.log);\n if (!fellBack) return false;\n PtyHarness.log.warn(\n \"shared ~/.claude mount died while the CLI was parked — respawning on the pod-local \" +\n \"config home instead of reusing a process bound to the dead mount\",\n );\n return true;\n } catch (err) {\n PtyHarness.log.warn(\"parked-session config-home probe failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return false;\n }\n }\n\n /**\n * Spawn a fresh CLI process for `prompt`, doing the once-per-process\n * environment preparation (config-home health, credential synthesis,\n * auth-readiness warning) and registering the parked-death watch.\n */\n private async spawnSession(\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>,\n options: HarnessQueryOptions,\n want: string | undefined,\n ): Promise<PtySession> {\n const session = new PtySession(prompt, options, want, this.bridge, this.adapter);\n // Before touching the config home (credentials, transcript dir), make sure\n // the shared ~/.claude GCS FUSE mount is writable. A dropped mount surfaces\n // as ENOTCONN on the very next mkdir and wedges the session with no in-place\n // recovery; this self-heals to a pod-local config home instead of dying and\n // re-failing on every wake. Claude-only: opencode doesn't use ~/.claude.\n if (this.ownsClaudeConfigHome) {\n await ensureUsableClaudeConfigHome(options.cwd, PtyHarness.log);\n }\n // The interactive TUI ignores CLAUDE_CODE_OAUTH_TOKEN (headless-only); in\n // Conveyor cloud envs, materialize it as `<configHome>/.credentials.json`\n // so the CLI starts authenticated instead of at the login-method picker,\n // and complete the onboarding flags + workspace trust in .claude.json so\n // neither an abandoned first-run wizard nor the folder-trust dialog can\n // park the TUI. Spawn-only — a reused process is already authenticated.\n await this.adapter.prepareEnvironment({ cwd: options.cwd });\n // Credential synthesis just ran. If the CLI is still about to spawn with\n // no usable Claude credential (cloud pod, no OAuth token/API key/on-disk\n // login), the interactive TUI will park on the sign-in screen — a silent,\n // otherwise-unrecoverable freeze (raw stdout is never parsed, and the\n // event-loop heartbeat keeps the pod looking alive). Surface it once as an\n // actionable chat message so the team can fix the credential and restart.\n // Claude-only (opencode uses env-based auth); the spawn still proceeds so a\n // human at the Connected-TUI can paste a login code.\n //\n // Gated on the adapter's IDENTITY (see `ownsClaudeConfigHome`), not on\n // `capabilities.structuredEvents`. With the old gate every opencode card\n // ran this Claude-only probe, found no CLAUDE_CODE_OAUTH_TOKEN /\n // ANTHROPIC_API_KEY / ~/.claude credentials (opencode carries its own env\n // auth), and posted \"started the Claude Code TUI with no Claude\n // credential\" on a pod that was running opencode perfectly well.\n if (this.ownsClaudeConfigHome) {\n await this.warnIfAuthNotReady();\n }\n // Register the parked-death watch once for this process's lifetime.\n session.onExit(() => this.handleSessionExit(session));\n await session.start();\n return session;\n }\n\n /**\n * The turn ended because the prompt was pasted but never submitted (the\n * nudge window expired with no turn start — see `armSubmitNudge`). Enter\n * alone cannot clear every startup dialog, so the recovery is a fresh\n * process: tear down (already done by drain) and respawn with the identical\n * pasted text, bounded by `resolveSubmitRedeliveryMaxAttempts()`.\n *\n * The redelivered prompt is the session's recorded `deliveredPromptText`,\n * not `opts.prompt` — the caller's prompt is typically a single-yield async\n * generator that the first attempt already exhausted.\n *\n * When every attempt fails, yield a terminal error result. That is what turns\n * an invisible indefinite park into a visible failed turn: the runner's event\n * pipeline mirrors it to chat and reaches its normal end-of-turn bookkeeping\n * instead of waiting on a message that, for an autonomous card, never comes.\n */\n private async *recoverFailedDelivery(\n session: PtySession,\n options: HarnessQueryOptions,\n want: string | undefined,\n ): AsyncGenerator<HarnessEvent, void> {\n if (!session.promptDeliveryFailed) return;\n const text = session.deliveredPromptText;\n // Nothing to redeliver (an empty-prompt wake): respawning would just park a\n // fresh TUI with an empty input box. Report and stop.\n const maxAttempts = text ? resolveSubmitRedeliveryMaxAttempts() : 0;\n let current = session;\n for (let attempt = 1; attempt <= maxAttempts && current.promptDeliveryFailed; attempt++) {\n PtyHarness.log.warn(\"Prompt never submitted — respawning the TUI and redelivering\", {\n attempt,\n maxAttempts,\n parkedFrame: PtyHarness.frameOf(current),\n });\n // A respawn follows immediately, so the dead process must not surface as\n // `pty:ended` and flap the Connected-TUI tab.\n this.cancelEndedTimer();\n current = await this.spawnSession(text, options, want);\n yield* this.drain(current);\n }\n if (!current.promptDeliveryFailed) return;\n const detail =\n `The agent's prompt could not be submitted to the Claude TUI after ${maxAttempts + 1} ` +\n `attempt(s) — the paste lands but the turn never starts, which usually means the CLI is ` +\n `parked on a startup dialog that Enter cannot clear. The turn is being ended so the card ` +\n `stops reporting work it is not doing.`;\n PtyHarness.log.error(\"Prompt delivery failed after all redelivery attempts\", {\n maxAttempts,\n parkedFrame: PtyHarness.frameOf(current),\n });\n this.bridge?.notifyPromptDeliveryFailure?.(`⚠️ ${detail}`);\n this.escalateToPodRecycle();\n yield { type: \"result\", subtype: \"error\", errors: [detail] };\n }\n\n /**\n * Diagnostics-only view of a session's last terminal frame. Optional-safe:\n * `recoverFailedDelivery` is unit-tested with plain stand-in objects, and a\n * missing frame must never break the recovery path it is describing.\n */\n private static frameOf(session: { diagnosticFrame?: string }): string {\n return session.diagnosticFrame ?? \"\";\n }\n\n /**\n * Last resort: ask the server to recreate this pod.\n *\n * Every in-pod recovery is exhausted at this point, and the pod-local config\n * home is active — which means the shared GCS FUSE mount is confirmed dead.\n * Nothing inside the container can remount it; only a pod recreate does. The\n * server bounds this (one recycle per workspace per cooldown window), and we\n * bound it again here at once per agent process, so a park with a non-mount\n * cause can never turn into a recycle loop.\n *\n * Fire-and-forget: the escalation must not gate ending the failed turn.\n */\n private escalateToPodRecycle(): void {\n if (this.recycleRequested || !this.bridge?.requestPodRecycle) return;\n if (!isConfigHomeFallbackActive()) return;\n this.recycleRequested = true;\n PtyHarness.log.error(\n \"Prompt delivery failed with the shared ~/.claude mount dead — requesting a pod recycle\",\n );\n this.bridge.requestPodRecycle(\n \"The shared ~/.claude mount died and the Claude CLI will not accept a prompt on this pod. \" +\n \"Only a new pod remounts it.\",\n );\n }\n\n /**\n * PTY-only: subscribe to \"the parked CLI produced transcript activity with no\n * query running\" (a human typed into the idle Connected-TUI). Attaches to the\n * currently-parked session and to any session parked later.\n */\n /**\n * PTY-only: inject a follow-up message into the turn currently streaming\n * events (the active session), so the runner can add to a running turn without\n * aborting + respawning. Returns false when no turn is active (idle/parked) or\n * the paste couldn't be delivered — the caller supersedes instead.\n */\n injectIntoRunningTurn(text: string): boolean {\n return this.activeSession?.injectIntoRunningTurn(text) ?? false;\n }\n\n onPassiveActivity(handler: () => void): () => void {\n this.passiveHandler = handler;\n const unsubParked = this.parked?.onPassiveActivity(handler);\n return () => {\n if (this.passiveHandler === handler) this.passiveHandler = null;\n unsubParked?.();\n };\n }\n\n /**\n * PTY-only: drain a passive turn against the parked process — the human\n * already submitted in the TUI, so no prompt is fed. Empty stream when nothing\n * is parked.\n */\n async *executePassiveTurn(options: HarnessQueryOptions): AsyncGenerator<HarnessEvent, void> {\n const session = this.parked;\n if (!session) return;\n this.parked = null;\n this.cancelEndedTimer();\n session.beginPassiveTurn(options);\n yield* this.drain(session);\n }\n\n /**\n * Shared query/passive-turn drain: stream the session's events, then either\n * park it (clean result → keep the process for the next turn) or tear it down\n * (abort/error/early-return → real death, schedule the ended signal).\n */\n private async *drain(session: PtySession): AsyncGenerator<HarnessEvent, void> {\n this.activeSession = session;\n let clean = false;\n try {\n for await (const event of session.events()) {\n yield event;\n }\n // The stream completed. Parkable only if it ended via a clean transcript\n // result and the process is still alive.\n clean = session.endedCleanly && !session.isToreDown && !session.hasExited;\n } finally {\n if (this.activeSession === session) this.activeSession = null;\n if (clean) {\n this.park(session);\n } else {\n await session.teardown();\n // Consumer abandoned / aborted / errored → the process is (being)\n // killed. Report ended after the grace window unless a respawn beats it.\n this.scheduleEnded();\n }\n }\n }\n\n /** Park a live, idle session for reuse and (re)wire the passive listener. */\n private park(session: PtySession): void {\n this.parked = session;\n if (this.passiveHandler) session.onPassiveActivity(this.passiveHandler);\n }\n\n /**\n * Parked/active process exited on its own (crash). A mid-turn death is\n * handled by drain()'s finally; here we only act on a death while PARKED —\n * tear down the husk and report ended immediately (no respawn is coming).\n */\n private handleSessionExit(session: PtySession): void {\n if (this.parked !== session) return;\n this.parked = null;\n void session.teardown();\n this.notifyEnded();\n }\n\n private scheduleEnded(): void {\n if (this.endedTimer) return;\n this.endedTimer = setTimeout(() => {\n this.endedTimer = null;\n this.notifyEnded();\n }, ENDED_GRACE_MS);\n }\n\n private cancelEndedTimer(): void {\n if (this.endedTimer) {\n clearTimeout(this.endedTimer);\n this.endedTimer = null;\n }\n }\n\n private notifyEnded(): void {\n this.cancelEndedTimer();\n this.bridge?.sendEnded?.();\n }\n\n /**\n * Tear down every live process (parked + active) and signal ended. Called by\n * the runner on stop/shutdown so the parked CLI never outlives the session and\n * the Connected-TUI tab hides promptly.\n */\n async dispose(): Promise<void> {\n this.cancelEndedTimer();\n const toKill = [this.parked, this.activeSession].filter((s): s is PtySession => s !== null);\n this.parked = null;\n this.activeSession = null;\n for (const session of toKill) {\n try {\n await session.teardown();\n } catch {\n /* already torn down */\n }\n }\n if (toKill.length > 0) this.notifyEnded();\n }\n\n createMcpServer(config: { name: string; tools: HarnessToolDefinition[] }): HarnessMcpServer {\n return new PtyMcpServer(config.name, config.tools);\n }\n}\n","/**\n * OpenCodeHeadlessHarness — drives `opencode run --format json`, a real\n * non-interactive mode with a structured NDJSON event stream.\n *\n * This replaces the raw-relay PTY path for CARD work. The PTY path remains\n * correct for adhoc sessions, where a human drives the terminal and raw relay is\n * the point; a card wants events, tools and a turn that ends.\n *\n * What headless buys over raw relay (all verified against opencode 1.18.15):\n * - structured events: text + tool calls, so chat mirroring and activity\n * summaries work instead of a terminal nobody can parse,\n * - the Conveyor MCP tools, served by the SAME in-process StreamableHTTP tool\n * server the Claude path uses (`opencode mcp list` reports it connected, and\n * a run called `conveyor_conveyor_ping` and got its output back),\n * - resume, via the session id opencode reports on every event,\n * - a turn that actually ends — the process exits when the run completes, so\n * no prompt-delivery probing, no bracketed paste, and no wedge watchdog.\n *\n * Two operational details are load-bearing:\n * - STDIN MUST BE CLOSED. `opencode run` with an open stdin pipe blocks\n * forever, emitting nothing on stdout or stderr — no error, no timeout.\n * Verified: a 5-minute hang with zero bytes. `stdio: \"ignore\"` for stdin.\n * - MCP config rides `OPENCODE_CONFIG_CONTENT` (inline JSON, high precedence).\n * The alternative — `opencode.json` in the workspace root — would dirty the\n * checked-out repo, and the global `~/.config/opencode` would leak between\n * concurrent sessions.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type {\n AgentHarness,\n HarnessEvent,\n HarnessMcpServer,\n HarnessQueryOptions,\n HarnessToolDefinition,\n} from \"../types.js\";\nimport { PtyMcpServer } from \"../pty/mcp-server.js\";\nimport { startToolServers, type PtyToolServer } from \"../pty/tool-server.js\";\nimport { AsyncEventQueue } from \"../pty/event-queue.js\";\nimport { sessionTempBase } from \"../pty/pty-support.js\";\nimport {\n buildOpenCodeConfigContent,\n buildOpenCodeChildEnv,\n buildRunArgs,\n prepareOpenCodeCredentials,\n resolveOpenCodeBinary,\n resolveOpenCodeModel,\n} from \"./spawn.js\";\nimport {\n accumulateUsage,\n buildResultEvent,\n errorMessageOf,\n mapOpenCodeEvent,\n parseOpenCodeLine,\n sessionIdOf,\n type OpenCodeUsage,\n} from \"./events.js\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/** Bounded stderr tail kept to explain a non-zero exit. */\nconst MAX_STDERR_TAIL = 4000;\n\nexport class OpenCodeHeadlessHarness implements AgentHarness {\n /** NDJSON from `--format json` is a trusted structured source. */\n readonly emitsStructuredEvents = true;\n\n /** opencode's session id from the last run, for `--session` on the next turn. */\n private lastSessionId: string | null = null;\n\n /** MCP tool servers started for the in-flight run. */\n private toolServers: PtyToolServer[] = [];\n private tempDir = \"\";\n\n /** The same in-process MCP handle the PTY path uses — tools are identical. */\n createMcpServer(config: { name: string; tools: HarnessToolDefinition[] }): HarnessMcpServer {\n return new PtyMcpServer(config.name, config.tools);\n }\n\n /** opencode's own session id, exposed so the runner can persist lineage. */\n get sessionId(): string | null {\n return this.lastSessionId;\n }\n\n async *executeQuery(opts: {\n prompt: string | AsyncGenerator<never, void, unknown>;\n options: HarnessQueryOptions;\n resume?: string;\n }): AsyncGenerator<HarnessEvent, void> {\n const prompt = await collectPrompt(opts.prompt);\n const binary = resolveOpenCodeBinary(process.env);\n // A deployed pod authenticates one of two ways; both are prepared here (see\n // ./credentials.ts). Without this the child inherits Conveyor's own\n // CONVEYOR_* variables, which opencode does not read — i.e. no credential.\n await prepareOpenCodeCredentials(process.env);\n\n this.tempDir = await mkdtemp(join(sessionTempBase(), \"opencode-headless-\"));\n const { servers, entries } = await startToolServers(\n opts.options.mcpServers ?? {},\n this.tempDir,\n );\n this.toolServers = servers;\n\n const args = buildRunArgs({\n prompt,\n cwd: opts.options.cwd,\n model: resolveOpenCodeModel(process.env, opts.options.model),\n // `resume` is Claude-transcript-derived, so it is always absent here (there\n // is no Claude session file for an opencode run). Falling back to the id\n // opencode itself reported is what makes a multi-turn card keep its\n // conversation instead of starting fresh on every message.\n resumeSessionId: opts.resume ?? this.lastSessionId,\n });\n // Read-only modes arrive as Claude's permissionMode \"plan\" — the flag we can\n // rely on is that the runner withholds the skip-permissions grant.\n const readOnly = opts.options.allowDangerouslySkipPermissions === false;\n const systemPromptPath = await this.writeSystemPrompt(opts.options.appendSystemPrompt);\n const configContent = buildOpenCodeConfigContent({\n entries,\n systemPromptPath,\n readOnly,\n });\n\n const queue = new AsyncEventQueue<HarnessEvent>();\n const usage: OpenCodeUsage = { inputTokens: 0, outputTokens: 0, totalCostUsd: 0 };\n let assistantText = \"\";\n let stderrTail = \"\";\n // opencode reports provider failures (401s especially) as a stdout event, so\n // this is what makes an auth failure diagnosable on the card.\n let reportedError: string | null = null;\n\n const child = spawn(binary, args, {\n cwd: opts.options.cwd,\n // stdin IGNORED — an open pipe makes `opencode run` block forever.\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: buildOpenCodeChildEnv(process.env, configContent),\n });\n\n const abort = opts.options.abortController;\n const onAbort = (): void => {\n child.kill(\"SIGTERM\");\n };\n abort?.signal.addEventListener(\"abort\", onAbort, { once: true });\n\n // NDJSON is line-delimited but arrives in arbitrary chunks.\n let carry = \"\";\n const ingest = (line: string): void => {\n const { text, error } = this.ingestLine(line, usage, queue);\n if (text) assistantText += text;\n if (error) reportedError = error;\n };\n child.stdout.setEncoding(\"utf8\");\n child.stdout.on(\"data\", (chunk: string) => {\n carry += chunk;\n const lines = carry.split(\"\\n\");\n carry = lines.pop() ?? \"\";\n for (const line of lines) ingest(line);\n });\n\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (chunk: string) => {\n stderrTail = (stderrTail + chunk).slice(-MAX_STDERR_TAIL);\n });\n\n const exited = new Promise<number>((resolve) => {\n child.once(\"error\", () => resolve(-1));\n child.once(\"close\", (code) => resolve(code ?? -1));\n });\n\n const finish = (async (): Promise<void> => {\n const code = await exited;\n // A trailing line without its newline still carries an event.\n ingest(carry);\n queue.push(buildResultEvent(code, usage, assistantText.trim(), stderrTail, reportedError));\n queue.close();\n })();\n\n try {\n for await (const event of queue.drain()) yield event;\n await finish;\n } finally {\n abort?.signal.removeEventListener(\"abort\", onAbort);\n if (!child.killed) child.kill(\"SIGTERM\");\n await this.cleanup();\n }\n }\n\n /**\n * Persist the Conveyor system prompt (task context, plan, mode instructions)\n * so it can be referenced by the config's `instructions`. opencode has no\n * `--append-system-prompt`; without this the card runs with no context at all.\n */\n private async writeSystemPrompt(text: string | undefined): Promise<string | null> {\n if (!text || text.trim() === \"\") return null;\n const path = join(this.tempDir, \"conveyor-instructions.md\");\n await writeFile(path, text, \"utf8\");\n return path;\n }\n\n /**\n * Parse one NDJSON line and push whatever it maps to. Returns assistant text so\n * the caller can accumulate the turn's summary; the session id is latched here\n * because every event carries it and any one of them will do.\n */\n private ingestLine(\n line: string,\n usage: OpenCodeUsage,\n queue: AsyncEventQueue<HarnessEvent>,\n ): { text: string; error: string | null } {\n const none = { text: \"\", error: null };\n const parsed = parseOpenCodeLine(line);\n if (!parsed) return none;\n const sid = sessionIdOf(parsed);\n if (sid) this.lastSessionId = sid;\n accumulateUsage(parsed, usage);\n const error = errorMessageOf(parsed);\n if (error) return { text: \"\", error };\n const mapped = mapOpenCodeEvent(parsed);\n if (!mapped) return none;\n queue.push(mapped);\n if (mapped.type !== \"assistant\") return none;\n const block = mapped.message.content[0];\n return { text: block?.type === \"text\" && block.text ? block.text : \"\", error: null };\n }\n\n async dispose(): Promise<void> {\n await this.cleanup();\n }\n\n private async cleanup(): Promise<void> {\n for (const server of this.toolServers) await server.close().catch(() => undefined);\n this.toolServers = [];\n if (this.tempDir) {\n await rm(this.tempDir, { recursive: true, force: true }).catch(() => undefined);\n this.tempDir = \"\";\n }\n }\n}\n\n/** The runner may pass a streaming prompt; headless takes one string. */\nasync function collectPrompt(\n prompt: string | AsyncGenerator<never, void, unknown>,\n): Promise<string> {\n if (typeof prompt === \"string\") return prompt;\n const parts: string[] = [];\n for await (const message of prompt as AsyncGenerator<\n { message?: { content?: unknown } },\n void,\n unknown\n >) {\n const content = message?.message?.content;\n if (typeof content === \"string\") parts.push(content);\n else if (Array.isArray(content)) {\n for (const block of content) {\n const b = block as { type?: string; text?: string };\n if (b?.type === \"text\" && typeof b.text === \"string\") parts.push(b.text);\n }\n }\n }\n return parts.join(\"\\n\\n\");\n}\n","/**\n * TuiAdapter — the per-TUI seam inside the PTY harness. PtySession/PtyHarness\n * own the generic machinery (node-pty spawn, output coalescing, relay bridge,\n * park/reuse, teardown); everything specific to ONE interactive CLI (binary,\n * argv, credential materialization, prompt encoding, exit diagnostics) lives\n * behind this interface. Claude's structured-event machinery (transcript\n * tailer + hook socket + tool servers) stays in PtySession, gated on\n * `capabilities.structuredEvents` — promoting it into the adapter waits for a\n * second structured-events adapter.\n */\nimport { accessSync, constants, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { TuiKind } from \"@project/shared\";\nimport type { HarnessQueryOptions } from \"../../types.js\";\n\nexport { TUI_KINDS } from \"@project/shared\";\nexport type { TuiKind } from \"@project/shared\";\n\nexport interface TuiCapabilities {\n /** Can a later spawn resume a prior session lineage (across sleeps)? */\n resume: boolean;\n /** Does a trusted structured-event source exist (transcript/hooks)?\n * Gates PtySession's tailer/hook-socket/tool-server/settings machinery,\n * the submit nudge, and the plan-dialog auto-accept. */\n structuredEvents: boolean;\n /** Is paste-without-submit prompt delivery meaningful for this TUI? */\n prefill: boolean;\n /** Can typing into a parked TUI be detected (passive turns)? */\n passiveTurns: boolean;\n /**\n * Must the first prompt write wait for the raw-TUI readiness probe?\n *\n * opencode SILENTLY DISCARDS stdin for ~2.4s while its TUI paints — a prompt\n * pasted early is lost with no trace, and no submit nudge can recover it\n * (the TEXT is gone, not just the Enter). Its own capability rather than\n * `!structuredEvents`: gaining a trusted event source (the Conveyor events\n * plugin) does not change how the TUI's input box behaves at startup.\n * Claude stays false — probing it would inject keystrokes into every card's\n * first turn, and its startup dialogs are numbered menus where stray input\n * is actively unsafe.\n */\n rawPromptGate: boolean;\n}\n\nexport interface TuiSpawnInput {\n options: HarnessQueryOptions;\n resume?: string;\n /** Per-process resources allocated by PtySession for structured-events\n * adapters only; absent otherwise. Claude's ride files/sockets: */\n settingsPath?: string;\n mcpConfigPath?: string;\n hookSocketPath?: string;\n /** opencode's ride its inline config env (OPENCODE_CONFIG_CONTENT): */\n mcpEntries?: Record<string, import(\"../tool-server.js\").McpConfigEntry>;\n eventsSinkPath?: string;\n pluginPath?: string;\n instructionsPath?: string;\n}\n\nexport interface TuiSpawnSpec {\n file: string;\n args: string[];\n env: Record<string, string>;\n}\n\nexport interface TuiFingerprintInput {\n model: string;\n permissionMode: \"plan\" | \"bypassPermissions\";\n appendSystemPrompt?: string;\n cwd: string;\n}\n\n/** Thrown by resolveBinary when the TUI cannot run here — the fail-loud path. */\nexport class TuiUnavailableError extends Error {\n constructor(\n public readonly tui: TuiKind,\n message: string,\n ) {\n super(message);\n this.name = \"TuiUnavailableError\";\n }\n}\n\nexport interface TuiAdapter {\n readonly id: TuiKind;\n readonly capabilities: TuiCapabilities;\n /** Resolve the executable. Throws TuiUnavailableError when it cannot run. */\n resolveBinary(env?: NodeJS.ProcessEnv): string;\n /** Full spawn spec (file + argv + child env) for node-pty. */\n buildSpawn(input: TuiSpawnInput): TuiSpawnSpec;\n /** One-time per-process environment prep before first spawn (credential\n * files, onboarding seeds). Never on reuse. Must not throw on best-effort\n * IO failures — log and continue, matching ensureClaudeCredentials. */\n prepareEnvironment(opts: { cwd: string; env?: NodeJS.ProcessEnv }): Promise<void>;\n /** Park/reuse invalidation key. MUST be stable for identical inputs. */\n spawnFingerprint(input: TuiFingerprintInput): string;\n /** Encode prompt text into the stdin bytes for this TUI's input box. */\n encodePromptBytes(text: string): string;\n /** errors[] for a process that died before producing a result. */\n buildExitErrors(exitCode: number, rawOutput: string): string[];\n}\n\nfunction isExecutable(path: string): boolean {\n try {\n if (!statSync(path).isFile()) return false;\n accessSync(path, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Minimal `which`: locate `binary` on env.PATH (or verify a given path when it\n * contains a slash). Returns null when not found/executable — callers turn\n * that into TuiUnavailableError.\n */\nexport function findOnPath(binary: string, env: NodeJS.ProcessEnv = process.env): string | null {\n if (binary.includes(\"/\")) {\n return isExecutable(binary) ? binary : null;\n }\n for (const dir of (env.PATH ?? \"\").split(\":\")) {\n if (!dir) continue;\n const candidate = join(dir, binary);\n if (isExecutable(candidate)) return candidate;\n }\n return null;\n}\n","/**\n * Seeds ChatGPT-subscription OAuth tokens into opencode's auth store.\n *\n * The API delivers CONVEYOR_OPENCODE_OAUTH = base64({access, refresh, expires})\n * (see apps/api project-key/methods/key-resolution.ts). We write it as the\n * `openai` entry of ~/.local/share/opencode/auth.json — the store the\n * opencode-openai-codex-auth plugin reads and lazily refreshes. That directory\n * is fuse-symlinked on GCP projects, so a refreshed store outlives the pod;\n * the seed therefore only wins when the existing entry is missing, malformed,\n * or STALER than the seed (re-sign-in on the site produces a newer seed —\n * that's the invalidation-recovery path). Best-effort like\n * ensureClaudeCredentials: IO failures log-and-continue, never throw.\n */\nimport { promises as fs } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createServiceLogger } from \"../../../utils/logger.js\";\n\nconst logger = createServiceLogger(\"opencode-auth\");\n\n/** Bump deliberately: also pre-warmed in the pod image (Dockerfile.base). */\nexport const OPENCODE_CODEX_PLUGIN = \"opencode-openai-codex-auth@4.4.0\";\nconst PLUGIN_PACKAGE = \"opencode-openai-codex-auth\";\n\nexport interface OpenCodeOauthSeed {\n access: string;\n refresh: string;\n expires: number;\n}\n\nexport function opencodeAuthPath(env: NodeJS.ProcessEnv): string {\n const dataHome = env.XDG_DATA_HOME ?? join(env.HOME ?? homedir(), \".local\", \"share\");\n return join(dataHome, \"opencode\", \"auth.json\");\n}\n\nexport function opencodeConfigPath(env: NodeJS.ProcessEnv): string {\n const configHome = env.XDG_CONFIG_HOME ?? join(env.HOME ?? homedir(), \".config\");\n return join(configHome, \"opencode\", \"opencode.json\");\n}\n\nexport function parseOauthSeed(b64: string | undefined): OpenCodeOauthSeed | null {\n if (!b64) return null;\n try {\n const parsed = JSON.parse(Buffer.from(b64, \"base64\").toString(\"utf8\")) as Record<\n string,\n unknown\n >;\n if (\n typeof parsed.access === \"string\" &&\n typeof parsed.refresh === \"string\" &&\n typeof parsed.expires === \"number\"\n ) {\n return { access: parsed.access, refresh: parsed.refresh, expires: parsed.expires };\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/** Seed only when the store entry is missing/malformed or older than the seed. */\nexport function shouldSeed(existingEntry: unknown, seed: OpenCodeOauthSeed): boolean {\n if (!existingEntry || typeof existingEntry !== \"object\") return true;\n const entry = existingEntry as Record<string, unknown>;\n if (entry.type !== \"oauth\") return true;\n if (typeof entry.access !== \"string\" || typeof entry.refresh !== \"string\") return true;\n if (typeof entry.expires !== \"number\") return true;\n return entry.expires < seed.expires;\n}\n\nasync function readJsonFile(path: string): Promise<Record<string, unknown>> {\n try {\n return JSON.parse(await fs.readFile(path, \"utf8\")) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nasync function writeJsonFile(path: string, value: Record<string, unknown>): Promise<void> {\n await fs.mkdir(dirname(path), { recursive: true });\n await fs.writeFile(path, `${JSON.stringify(value, null, 2)}\\n`, { mode: 0o600 });\n}\n\nasync function ensureAuthEntry(env: NodeJS.ProcessEnv, seed: OpenCodeOauthSeed): Promise<void> {\n const path = opencodeAuthPath(env);\n const store = await readJsonFile(path);\n if (!shouldSeed(store.openai, seed)) {\n logger.info(\"opencode oauth store is fresher than the seed; leaving it alone\");\n return;\n }\n store.openai = {\n type: \"oauth\",\n access: seed.access,\n refresh: seed.refresh,\n expires: seed.expires,\n };\n await writeJsonFile(path, store);\n logger.info(\"seeded opencode oauth store entry\");\n}\n\nasync function ensurePluginConfig(env: NodeJS.ProcessEnv): Promise<void> {\n const path = opencodeConfigPath(env);\n const config = await readJsonFile(path);\n const plugins = Array.isArray(config.plugin) ? (config.plugin as unknown[]) : [];\n const isOurs = (p: unknown): boolean =>\n typeof p === \"string\" && (p === PLUGIN_PACKAGE || p.startsWith(`${PLUGIN_PACKAGE}@`));\n const hasExactPin = plugins.includes(OPENCODE_CODEX_PLUGIN);\n const hasStalePin = plugins.some((p) => isOurs(p) && p !== OPENCODE_CODEX_PLUGIN);\n // Already correct — don't churn the fuse file.\n if (hasExactPin && !hasStalePin) return;\n const kept = plugins.filter((p) => !isOurs(p));\n config.plugin = [...kept, OPENCODE_CODEX_PLUGIN];\n await writeJsonFile(path, config);\n logger.info(\"ensured opencode codex-auth plugin in config\");\n}\n\n/**\n * Best-effort seed of opencode's oauth store + plugin config. No-op when\n * CONVEYOR_OPENCODE_OAUTH is absent or unparseable. Never throws.\n */\nexport async function seedOpenCodeOauth(env: NodeJS.ProcessEnv): Promise<void> {\n const seed = parseOauthSeed(env.CONVEYOR_OPENCODE_OAUTH);\n if (!seed) return;\n try {\n await ensureAuthEntry(env, seed);\n await ensurePluginConfig(env);\n } catch (err) {\n logger.warn(\n `failed to seed opencode oauth store: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n","/**\n * opencode credential + model resolution, shared by the headless harness (cards)\n * and the PTY adapter (adhoc sessions) so the two can never drift on how a\n * deployed pod authenticates.\n *\n * A project's `CodingAgentKey` reaches the pod through the bootstrap bundle\n * (`apps/api` project-key/methods/key-resolution.ts) in one of two shapes:\n *\n * kind: \"chatgpt_oauth\" → CONVEYOR_OPENCODE_OAUTH = base64({access,refresh,expires})\n * Seeded into opencode's own auth store by `seedOpenCodeOauth`, where the\n * opencode-openai-codex-auth plugin reads and lazily refreshes it. On GCP\n * projects that directory is fuse-symlinked, so a refreshed token outlives\n * the pod.\n *\n * kind: \"api_key\" → CONVEYOR_AGENT_KEY + CONVEYOR_AGENT_PROVIDER\n * Handed to the child under the env var that provider's SDK reads natively.\n *\n * Neither Conveyor-owned variable is passed through to the child: opencode does\n * not read them, and forwarding a raw key under an unexpected name is a leak with\n * no upside.\n */\n\nimport { seedOpenCodeOauth } from \"../pty/adapters/opencode-auth.js\";\n\n/** provider → the env var its SDK/CLI reads natively. */\nconst PROVIDER_KEY_ENV: Record<string, string> = {\n openai: \"OPENAI_API_KEY\",\n anthropic: \"ANTHROPIC_API_KEY\",\n zen: \"OPENCODE_API_KEY\",\n};\n\nexport const DEFAULT_OPENCODE_PROVIDER = \"openai\";\n\n/**\n * Env overrides that carry the resolved credential to a spawned opencode, plus\n * the removals. Returned rather than applied so it is testable without an env.\n */\nexport function buildOpenCodeCredentialEnv(source: NodeJS.ProcessEnv): {\n set: Record<string, string>;\n unset: string[];\n} {\n const set: Record<string, string> = {};\n // ChatGPT-subscription auth flows through the auth store; a provider API key\n // in the env would override it and silently bill per-token instead.\n const oauthActive = Boolean(source.CONVEYOR_OPENCODE_OAUTH);\n const key = source.CONVEYOR_AGENT_KEY;\n const provider = source.CONVEYOR_AGENT_PROVIDER ?? DEFAULT_OPENCODE_PROVIDER;\n const keyEnvVar = PROVIDER_KEY_ENV[provider];\n if (key && keyEnvVar && !oauthActive) set[keyEnvVar] = key;\n return { set, unset: [\"CONVEYOR_AGENT_KEY\", \"CONVEYOR_OPENCODE_OAUTH\"] };\n}\n\n/**\n * Prepare on-disk credentials before the first spawn. No-op unless a ChatGPT\n * OAuth seed is present. Best-effort by contract — never throws.\n */\nexport async function prepareOpenCodeCredentials(\n source: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n await seedOpenCodeOauth(source);\n}\n\n/**\n * The full child environment for a spawned `opencode run`: everything inherited,\n * minus Conveyor's own credential variables, plus the resolved credential and the\n * inline config.\n */\nexport function buildOpenCodeChildEnv(\n source: NodeJS.ProcessEnv,\n configContent: string | null,\n): Record<string, string> {\n const env: Record<string, string> = {};\n for (const [key, value] of Object.entries(source)) {\n if (typeof value === \"string\") env[key] = value;\n }\n const { set, unset } = buildOpenCodeCredentialEnv(source);\n for (const key of unset) delete env[key];\n Object.assign(env, set);\n if (configContent) env.OPENCODE_CONFIG_CONTENT = configContent;\n return env;\n}\n\n/**\n * The model to pass as `--model`. opencode expects `provider/model`, so a bare\n * name is qualified with the resolved provider — an unqualified name is not\n * resolved against the configured default and the run fails to pick a model.\n * `CONVEYOR_AGENT_MODEL` (the key's own model) wins over the task's, matching\n * the PTY adapter.\n */\nexport function resolveOpenCodeModel(\n source: NodeJS.ProcessEnv,\n optionsModel?: string,\n): string | undefined {\n const model = source.CONVEYOR_AGENT_MODEL ?? optionsModel;\n if (!model) return undefined;\n if (model.startsWith(\"zen/\")) return `opencode/${model.slice(\"zen/\".length)}`;\n if (model.includes(\"/\")) return model;\n const provider = source.CONVEYOR_AGENT_PROVIDER ?? DEFAULT_OPENCODE_PROVIDER;\n return `${provider === \"zen\" ? \"opencode\" : provider}/${model}`;\n}\n","/**\n * Pure argv + config construction for `opencode run`. Kept separate from the\n * harness so both are unit-testable without spawning anything.\n */\n\nimport { findOnPath, TuiUnavailableError } from \"../pty/adapters/types.js\";\nimport type { McpConfigEntry } from \"../pty/tool-server.js\";\n\n// Re-exported so the harness has a single import surface for spawn concerns.\nexport {\n buildOpenCodeChildEnv,\n prepareOpenCodeCredentials,\n resolveOpenCodeModel,\n} from \"./credentials.js\";\n\n/**\n * Resolve the opencode binary, honoring `CONVEYOR_OPENCODE_BIN`.\n * Throws `TuiUnavailableError` when it cannot run — the runner turns that into a\n * card-visible failure rather than a crash.\n */\nexport function resolveOpenCodeBinary(env: NodeJS.ProcessEnv = process.env): string {\n const override = env.CONVEYOR_OPENCODE_BIN;\n const found = override ? findOnPath(override, env) : findOnPath(\"opencode\", env);\n if (!found) {\n throw new TuiUnavailableError(\n \"opencode\",\n \"The opencode CLI is not available in this environment. It must be baked \" +\n \"into the pod image (see Dockerfile.base) — re-run Build Image for this \" +\n \"project, or set CONVEYOR_OPENCODE_BIN to its absolute path.\",\n );\n }\n return found;\n}\n\n/** Defensive bound on the prompt passed as argv (Linux MAX_ARG_STRLEN is 128KiB). */\nexport const PROMPT_MAX_CHARS = 96_000;\n\nexport interface RunArgsInput {\n prompt: string;\n /** The workspace to work in. Passed as `--dir`; see buildRunArgs. */\n cwd: string;\n model?: string;\n /** opencode session id to continue, or null for a fresh session. */\n resumeSessionId?: string | null;\n}\n\n/** Tools that can mutate the workspace — denied outright in read-only modes. */\nexport const MUTATING_TOOLS = [\"edit\", \"bash\", \"external_directory\"] as const;\n\n/**\n * Build the argv for `opencode run`.\n *\n * `--format json` is what makes this a structured harness at all. `--auto`\n * auto-approves permissions, matching the `bypassPermissions` posture the card\n * harness already runs under — without it a headless run would block on a\n * permission prompt that nothing can answer.\n *\n * The prompt is a positional argument, so it is truncated rather than risking\n * E2BIG. Truncation is marked so a reader can tell it happened.\n */\nexport function buildRunArgs(input: RunArgsInput): string[] {\n // `--dir` is REQUIRED, not belt-and-braces: opencode resolves its working root\n // independently of the spawned process's cwd. Passing cwd to child_process\n // alone is not enough — observed live, a run whose child cwd was the scratch\n // checkout wrote its file into the PARENT process's directory instead. An\n // opencode card would silently do its work in the wrong repo.\n // `--auto` auto-approves permissions that are not EXPLICITLY denied, so it\n // composes with the read-only denies in buildOpenCodeConfigContent: a\n // read-only run still never blocks on an approval nothing can answer.\n const args = [\"run\", \"--dir\", input.cwd, \"--format\", \"json\", \"--auto\"];\n if (input.model) {\n // opencode expects provider/model; a bare model name is passed through and\n // resolved against the configured default provider.\n args.push(\"--model\", input.model);\n }\n if (input.resumeSessionId) args.push(\"--session\", input.resumeSessionId);\n args.push(truncatePrompt(input.prompt));\n return args;\n}\n\nexport function truncatePrompt(prompt: string): string {\n if (prompt.length <= PROMPT_MAX_CHARS) return prompt;\n return `${prompt.slice(0, PROMPT_MAX_CHARS)}\\n\\n[prompt truncated at ${PROMPT_MAX_CHARS} characters]`;\n}\n\nexport interface OpenCodeConfigInput {\n /** MCP entries as Conveyor's tool server reports them. */\n entries: Record<string, McpConfigEntry>;\n /**\n * Absolute path to a file holding the Conveyor system prompt (task context,\n * plan, mode instructions), or null when there is none.\n */\n systemPromptPath?: string | null;\n /**\n * Read-only mode (Claude's `permissionMode: \"plan\"` equivalent). Denies the\n * mutating tools instead of relying on the model to behave.\n */\n readOnly?: boolean;\n /**\n * Absolute path to the staged Conveyor events plugin (see ./plugin.ts), or\n * null/absent when the caller has no event sink (the headless run path —\n * its NDJSON stdout already IS the event source).\n */\n pluginPath?: string | null;\n}\n\n/**\n * Build the inline `OPENCODE_CONFIG_CONTENT` for one run.\n *\n * Inline rather than a file because both file locations have side effects:\n * `opencode.json` in the workspace root dirties the checked-out repo, and the\n * global `~/.config/opencode` leaks between concurrent sessions.\n *\n * Three things ride it:\n * - `mcp`: Conveyor already serves its tools over loopback StreamableHTTP for\n * the Claude path, and opencode's `type: \"remote\"` connects to exactly that\n * (verified: reports `connected`, and a run invoked a tool through it).\n * External stdio entries (the baked `playwright-mcp`) map to `type: \"local\"`.\n * - `instructions`: how the system prompt reaches opencode. There is no\n * `--append-system-prompt`; a config `instructions` file is the supported\n * route (verified: a rule in that file changed the model's replies).\n * - `permission`: ALWAYS emitted. `\"*\": \"allow\"` is what keeps an agent turn\n * from parking on an approval nothing can answer — the headless run pairs\n * it with `--auto`, and the interactive TUI (which has no `--auto`) relies\n * on it alone. Read-only layers explicit denies on top; because the TUI's\n * turns run under the same config, the denies bind human-typed turns too.\n * - `plugin`: the staged Conveyor events plugin (PTY path only), loaded via\n * the probe-verified `file://` specifier.\n *\n * Returns null when there is nothing to configure — which no longer happens\n * for real callers (the permission block is unconditional), but the guard is\n * kept so a future all-optional call cannot inject an empty override.\n */\nexport function buildOpenCodeConfigContent(input: OpenCodeConfigInput): string | null {\n const { entries, systemPromptPath, readOnly, pluginPath } = input;\n const mcp: Record<string, unknown> = {};\n for (const [name, entry] of Object.entries(entries)) {\n if (entry.type === \"http\") {\n mcp[name] = {\n type: \"remote\",\n url: entry.url,\n enabled: true,\n ...(Object.keys(entry.headers).length > 0 ? { headers: entry.headers } : {}),\n };\n } else {\n mcp[name] = {\n type: \"local\",\n command: [entry.command, ...(entry.args ?? [])],\n enabled: true,\n ...(entry.env ? { environment: entry.env } : {}),\n };\n }\n }\n const config: Record<string, unknown> = {};\n if (Object.keys(mcp).length > 0) config.mcp = mcp;\n if (systemPromptPath) config.instructions = [systemPromptPath];\n if (pluginPath) config.plugin = [`file://${pluginPath}`];\n config.permission = {\n \"*\": \"allow\",\n ...(readOnly ? Object.fromEntries(MUTATING_TOOLS.map((tool) => [tool, \"deny\"])) : {}),\n };\n if (Object.keys(config).length === 0) return null;\n return JSON.stringify(config);\n}\n","export { defineTool } from \"./types.js\";\n\nexport type {\n AgentHarness,\n HarnessEvent,\n HarnessSystemEvent,\n HarnessSystemInitEvent,\n HarnessCompactBoundaryEvent,\n HarnessTaskStartedEvent,\n HarnessTaskProgressEvent,\n HarnessAssistantEvent,\n HarnessContentBlock,\n HarnessResultEvent,\n HarnessResultSuccessEvent,\n HarnessResultErrorEvent,\n HarnessRateLimitEvent,\n HarnessToolProgressEvent,\n HarnessUserQuestion,\n HarnessUserQuestionEvent,\n HarnessUserMessage,\n HarnessToolDefinition,\n HarnessToolAnnotations,\n HarnessMcpServer,\n HarnessQueryOptions,\n HarnessHookInput,\n HarnessHookOutput,\n HarnessPostToolUseHook,\n PtyBridge,\n} from \"./types.js\";\n\nexport { ClaudeCodeHarness } from \"./claude-code/index.js\";\nexport { PtyHarness } from \"./pty/index.js\";\nexport { OpenCodeHeadlessHarness } from \"./opencode/index.js\";\n\nimport { ClaudeCodeHarness } from \"./claude-code/index.js\";\nimport { PtyHarness } from \"./pty/index.js\";\nimport { OpenCodeHeadlessHarness } from \"./opencode/index.js\";\nimport type { TuiAdapter } from \"./pty/adapters/index.js\";\nimport type { AgentHarness, PtyBridge } from \"./types.js\";\n\n/**\n * Which harness drives a run.\n *\n * - `\"sdk\"` — ClaudeCodeHarness, the in-process Claude Agent SDK loop.\n * - `\"pty\"` — PtyHarness, an interactive TUI relayed to the Connected-TUI tab.\n * Opencode cards run here too: the OpenCodeTuiAdapter has a trusted\n * structured-event source (the Conveyor events plugin — see\n * harness/opencode/plugin.ts), so the card gets chat mirroring, MCP tools\n * and real turn completion while the TUI stays watchable and typable.\n * - `\"opencode\"` — OpenCodeHeadlessHarness, `opencode run --format json`.\n * UNROUTED since the PTY adapter gained structured events; kept in-tree as\n * the fallback if the TUI path hits pod trouble (it was verified live in\n * PR #3893 and its tests still pin it).\n */\nexport type HarnessKind = \"sdk\" | \"pty\" | \"opencode\";\n\n/**\n * Can this harness accept multimodal image blocks in a prompt?\n *\n * Only the SDK can. A PTY harness would paste the blocks into the TUI as text,\n * and the headless opencode harness passes its prompt as argv — so both get a\n * text-only prompt whose body links each image via the attachment tools.\n */\nexport function supportsImageBlocks(kind: HarnessKind): boolean {\n return kind === \"sdk\";\n}\n\n/**\n * Pick the harness implementation. `ptyBridge` is only consumed by the PTY\n * harness (to stream stdout to the S2 relay and receive keystrokes/resize);\n * the SDK and headless harnesses ignore it.\n *\n * `adapter` selects WHICH TUI the PTY harness drives (claude / opencode).\n * Omitting it keeps `PtyHarness`'s own ClaudeTuiAdapter default, so the no-arg\n * and `(\"pty\", bridge)` call shapes are byte-for-byte unchanged — the factory\n * default stays \"sdk\" + Claude, which the harness-selection guards lock.\n */\nexport function createHarness(\n kind: HarnessKind = \"sdk\",\n ptyBridge?: PtyBridge,\n adapter?: TuiAdapter,\n): AgentHarness {\n if (kind === \"opencode\") return new OpenCodeHeadlessHarness();\n if (kind !== \"pty\") return new ClaudeCodeHarness();\n return adapter ? new PtyHarness(ptyBridge, adapter) : new PtyHarness(ptyBridge);\n}\n","/**\n * OpenCodeTuiAdapter — drives the `opencode` TUI (https://opencode.ai) with\n * STRUCTURED EVENTS: the Conveyor events plugin (harness/opencode/plugin.ts)\n * rides the spawn config and appends the client engine's bus events to an\n * NDJSON sink the session tails — the same trusted-source pattern as Claude's\n * transcript JSONL, so a card gets chat mirroring, activity summaries, real\n * turn completion (the session.idle signal) and MCP tools while the human\n * watches and types in the live TUI.\n *\n * Config (MCP entries, instructions, permission, plugin) rides\n * OPENCODE_CONFIG_CONTENT on the child env. That works because the interactive\n * TUI runs the CLIENT engine — the same one `opencode run` uses, where all of\n * it was verified live (#3893 + the 2026-08-08 plugin probes). The permission\n * allow-all block matters doubly here: the TUI has no `--auto`, so it is the\n * only thing between an autonomous card and a permission dialog nobody\n * answers.\n *\n * Auth is env-based for api_key keys (CONVEYOR_AGENT_KEY → provider-native env\n * var) and store-based for chatgpt_oauth keys (CONVEYOR_OPENCODE_OAUTH seeded\n * into opencode's auth.json by prepareEnvironment — see opencode-auth.ts).\n */\nimport { buildPromptBytes, inheritedEnv } from \"../pty-support.js\";\nimport { cleanTerminalOutput } from \"../spawn-args.js\";\nimport {\n buildOpenCodeCredentialEnv,\n prepareOpenCodeCredentials,\n resolveOpenCodeModel,\n} from \"../../opencode/credentials.js\";\nimport { buildOpenCodeConfigContent } from \"../../opencode/spawn.js\";\nimport { OPENCODE_EVENTS_FILE_ENV } from \"../../opencode/plugin.js\";\nimport {\n findOnPath,\n TuiUnavailableError,\n type TuiAdapter,\n type TuiCapabilities,\n type TuiFingerprintInput,\n type TuiSpawnInput,\n type TuiSpawnSpec,\n} from \"./types.js\";\n\nexport class OpenCodeTuiAdapter implements TuiAdapter {\n readonly id = \"opencode\" as const;\n readonly capabilities: TuiCapabilities = {\n // `--session <ses_…>` continues the id the plugin events latched.\n resume: true,\n structuredEvents: true,\n // The input box tolerates paste-without-submit, but manual prefill has no\n // card users yet — keep the initial-query behavior unchanged for now.\n prefill: false,\n // Plugin events arriving while parked ARE the passive signal.\n passiveTurns: true,\n // opencode silently discards early stdin while the TUI paints; the pasted\n // text itself is lost, so the readiness probe must gate the first write\n // even though structured events exist now.\n rawPromptGate: true,\n };\n\n constructor(private readonly env: NodeJS.ProcessEnv = process.env) {}\n\n resolveBinary(env: NodeJS.ProcessEnv = this.env): string {\n const override = env.CONVEYOR_OPENCODE_BIN;\n const found = override ? findOnPath(override, env) : findOnPath(\"opencode\", env);\n if (!found) {\n throw new TuiUnavailableError(\n \"opencode\",\n \"The opencode CLI is not available in this environment. It must be baked \" +\n \"into the pod image (see Dockerfile.base) — re-run Build Image for this \" +\n \"project, or set CONVEYOR_OPENCODE_BIN to its absolute path.\",\n );\n }\n return found;\n }\n\n buildSpawn(input: TuiSpawnInput): TuiSpawnSpec {\n const env = { ...inheritedEnv() };\n // Credential resolution is shared with the headless card harness so the two\n // paths cannot drift on how a deployed pod authenticates.\n const credentials = buildOpenCodeCredentialEnv(this.env);\n for (const key of credentials.unset) delete env[key];\n Object.assign(env, credentials.set);\n\n // Read-only modes arrive as Claude's permissionMode \"plan\"; the config\n // denies bind the model AND human-typed turns (same engine, same config).\n const configContent = buildOpenCodeConfigContent({\n entries: input.mcpEntries ?? {},\n systemPromptPath: input.instructionsPath ?? null,\n readOnly: input.options.permissionMode === \"plan\",\n pluginPath: input.pluginPath ?? null,\n });\n if (configContent) env.OPENCODE_CONFIG_CONTENT = configContent;\n if (input.eventsSinkPath) env[OPENCODE_EVENTS_FILE_ENV] = input.eventsSinkPath;\n\n const model = resolveOpenCodeModel(this.env, input.options.model);\n const args: string[] = [];\n if (model) args.push(\"--model\", model);\n // Continue the opencode-assigned session (latched from the plugin events)\n // after a respawn/wake, instead of starting a fresh conversation.\n if (input.resume) args.push(\"--session\", input.resume);\n return { file: this.resolveBinary(), args, env };\n }\n\n async prepareEnvironment(): Promise<void> {\n // ChatGPT-subscription tokens (when present) are seeded into opencode's\n // auth store; session-state persistence stays the entrypoint's job\n // (GCS-FUSE symlinks for ~/.local/share/opencode).\n await prepareOpenCodeCredentials(this.env);\n }\n\n spawnFingerprint(input: TuiFingerprintInput): string {\n // appendSystemPrompt is spawn-time state here (it becomes the instructions\n // file baked into the child's config env), so drift must invalidate a\n // parked process — same rationale as Claude's fingerprint.\n return JSON.stringify([\n \"opencode\",\n input.model,\n input.cwd,\n input.permissionMode,\n input.appendSystemPrompt ?? \"\",\n ]);\n }\n\n encodePromptBytes(text: string): string {\n // Bracketed paste — standard for modern TUIs; revisit if live verification\n // shows opencode's input mishandles it.\n return buildPromptBytes(text);\n }\n\n buildExitErrors(exitCode: number, rawOutput: string): string[] {\n const errors = [`opencode exited (code ${exitCode}) without a result`];\n const tail = cleanTerminalOutput(rawOutput);\n if (tail) errors.push(`Last terminal output before exit:\\n${tail}`);\n return errors;\n }\n}\n","import { TUI_KINDS, type TuiAdapter, type TuiKind } from \"./types.js\";\nimport { ClaudeTuiAdapter } from \"./claude.js\";\nimport { OpenCodeTuiAdapter } from \"./opencode.js\";\n\nexport * from \"./types.js\";\nexport { ClaudeTuiAdapter } from \"./claude.js\";\nexport { OpenCodeTuiAdapter } from \"./opencode.js\";\n\n/**\n * Which TUI a pod runs, from the bootstrap bundle's CONVEYOR_TUI.\n *\n * Unknown values throw (fail loudly): a typo'd config must not silently fall\n * back to Claude while the bundle seeded some other TUI's credentials — the\n * pod would spawn `claude` and park at a sign-in prompt with no clue why.\n *\n * Shared by the adhoc-session path and the task/card path (`QueryBridge`), so\n * both honor the same value with the same contract.\n */\nexport function resolveTuiKindFromEnv(env: NodeJS.ProcessEnv): TuiKind {\n const raw = env.CONVEYOR_TUI ?? \"claude-code\";\n if ((TUI_KINDS as readonly string[]).includes(raw)) return raw as TuiKind;\n throw new Error(`Unknown TUI \"${raw}\" in CONVEYOR_TUI (expected: ${TUI_KINDS.join(\", \")})`);\n}\n\n/** Adapter factory. */\nexport function resolveTuiAdapter(kind: TuiKind = \"claude-code\"): TuiAdapter {\n switch (kind) {\n case \"claude-code\":\n return new ClaudeTuiAdapter();\n case \"opencode\":\n return new OpenCodeTuiAdapter();\n default:\n throw new Error(`Unknown TUI kind: ${kind as string}`);\n }\n}\n","/**\n * PtyStreamServer — the in-pod half of the direct PTY transport.\n *\n * A plain TCP server speaking the NDJSON frame protocol from\n * `@project/shared` (`pty-stream.ts`). The browser never talks to it directly:\n * it opens a WebSocket to the preview-router's `/workspace-tunnel`, which\n * verifies an HMAC workspace-attach token through the API and only then bridges\n * raw bytes to this port. That is why there is no in-band auth here — exactly\n * like sshd on 2222, the edge is the gate, and the port is denied on the public\n * preview allow-list (`PREVIEW_PORT_DENY_LIST`) so it can never be reached\n * without a per-viewer token.\n *\n * Responsibilities:\n * - bind the first free port in the shared stream window and report it,\n * - keep a bounded scrollback ring so a newly-attached viewer sees the\n * current screen instead of waiting for the next redraw,\n * - fan output out to every attached viewer,\n * - fan input in, and reconcile viewers' desired dims to the min box that\n * fits everyone (the same rule the server-side relay uses).\n */\n\nimport net from \"node:net\";\nimport {\n PTY_STREAM_PORT_ATTEMPTS,\n PTY_STREAM_PORT_BASE,\n PtyStreamFrameReader,\n encodePtyStreamFrame,\n type PtyStreamFrame,\n} from \"@project/shared\";\nimport { createServiceLogger } from \"../../utils/logger.js\";\n\nconst logger = createServiceLogger(\"PtyStreamServer\");\n\n/** Mirrors the server-side relay ring (`pty-methods.ts` RING_MAX_CHARS): enough\n * to replay a full TUI screen plus recent history, bounded so a long-running\n * session can't grow the agent's heap. */\nconst RING_MAX_CHARS = 256 * 1024;\n\ninterface RingChunk {\n seq: number;\n data: string;\n}\n\nexport interface PtyStreamServerOptions {\n sessionId: string;\n /** Keystrokes/paste bytes from any attached viewer. */\n onInput: (data: string) => void;\n /** Reconciled (min across viewers) dims. Only fired when the min changes. */\n onResize: (cols: number, rows: number) => void;\n /** Injectable for tests — defaults to the shared stream window. */\n portBase?: number;\n portAttempts?: number;\n}\n\ninterface StreamClient {\n socket: net.Socket;\n dims: { cols: number; rows: number } | null;\n}\n\nexport class PtyStreamServer {\n private readonly server: net.Server;\n private readonly clients = new Set<StreamClient>();\n private readonly chunks: RingChunk[] = [];\n private totalChars = 0;\n private lastSeq = 0;\n private dims: { cols: number; rows: number } | null = null;\n private lastReconciled: { cols: number; rows: number } | null = null;\n private boundPort: number | null = null;\n private closed = false;\n\n constructor(private readonly options: PtyStreamServerOptions) {\n this.server = net.createServer((socket) => this.handleConnection(socket));\n this.server.on(\"error\", (err) => {\n logger.warn(`PTY stream server error: ${err.message}`);\n });\n }\n\n /** The port the server bound to, or null while unbound. */\n get port(): number | null {\n return this.boundPort;\n }\n\n /** How many viewers are attached right now. Drives relay coalescing. */\n get clientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Bind the first free port in the window. Resolves to the bound port, or null\n * when every candidate is taken (a pod running more concurrent agent\n * processes than the window allows) — the caller then simply stays on the\n * relay transport.\n *\n * Binds on all interfaces because the router connects from the cluster\n * network by pod IP, not loopback.\n */\n async listen(): Promise<number | null> {\n const base = this.options.portBase ?? PTY_STREAM_PORT_BASE;\n const attempts = this.options.portAttempts ?? PTY_STREAM_PORT_ATTEMPTS;\n for (let i = 0; i < attempts; i += 1) {\n const port = base + i;\n const ok = await this.tryListen(port);\n if (ok) {\n this.boundPort = port;\n return port;\n }\n }\n logger.warn(`PTY stream server could not bind any port in ${base}..${base + attempts - 1}`);\n return null;\n }\n\n private tryListen(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const onError = (): void => {\n this.server.removeListener(\"listening\", onListening);\n resolve(false);\n };\n const onListening = (): void => {\n this.server.removeListener(\"error\", onError);\n resolve(true);\n };\n this.server.once(\"error\", onError);\n this.server.once(\"listening\", onListening);\n this.server.listen(port, \"0.0.0.0\");\n });\n }\n\n /** Append a frame to the ring and push it to every attached viewer. */\n broadcast(data: string, dims?: { cols: number; rows: number }): void {\n if (this.closed || data === \"\") return;\n if (dims) this.dims = dims;\n const seq = ++this.lastSeq;\n this.chunks.push({ seq, data });\n this.totalChars += data.length;\n // Always keep at least one chunk so a single oversized frame still replays.\n while (this.totalChars > RING_MAX_CHARS && this.chunks.length > 1) {\n const evicted = this.chunks.shift();\n if (evicted) this.totalChars -= evicted.data.length;\n }\n if (this.clients.size === 0) return;\n this.send({ t: \"data\", seq, data, ...(this.dims ?? {}) });\n }\n\n /** Tell every viewer the PTY died, then drop them. */\n end(): void {\n if (this.clients.size > 0) this.send({ t: \"ended\" });\n for (const client of [...this.clients]) client.socket.end();\n }\n\n /** Stop listening and drop every viewer. Idempotent. */\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.end();\n for (const client of [...this.clients]) client.socket.destroy();\n this.clients.clear();\n await new Promise<void>((resolve) => {\n this.server.close(() => resolve());\n });\n this.boundPort = null;\n }\n\n private send(frame: PtyStreamFrame): void {\n const line = encodePtyStreamFrame(frame);\n for (const client of this.clients) {\n // Write errors are the socket's problem — 'error'/'close' handle teardown.\n try {\n client.socket.write(line);\n } catch {\n /* dropped viewer; cleanup runs on close */\n }\n }\n }\n\n private handleConnection(socket: net.Socket): void {\n if (this.closed) {\n socket.destroy();\n return;\n }\n // Terminal traffic is latency-sensitive and tiny; Nagle would stall a\n // keystroke echo behind the 40ms coalescer window.\n socket.setNoDelay(true);\n const client: StreamClient = { socket, dims: null };\n this.clients.add(client);\n\n const reader = new PtyStreamFrameReader((frame) => this.handleClientFrame(client, frame));\n socket.on(\"data\", (chunk) => reader.push(chunk.toString(\"utf8\")));\n const drop = (): void => {\n if (!this.clients.delete(client)) return;\n // A departing viewer's dims must stop pinning the min box, so the\n // remaining viewers reflow up to their own size.\n this.reconcileDims();\n };\n socket.on(\"close\", drop);\n socket.on(\"error\", drop);\n\n // Hello + full ring replay, so the viewer paints the current screen\n // immediately rather than after the TUI's next redraw.\n socket.write(\n encodePtyStreamFrame({\n t: \"hello\",\n sessionId: this.options.sessionId,\n ...(this.dims ?? {}),\n }),\n );\n for (const chunk of this.chunks) {\n socket.write(\n encodePtyStreamFrame({ t: \"data\", seq: chunk.seq, data: chunk.data, ...(this.dims ?? {}) }),\n );\n }\n }\n\n private handleClientFrame(client: StreamClient, frame: PtyStreamFrame): void {\n if (frame.t === \"input\") {\n if (typeof frame.data === \"string\" && frame.data !== \"\") this.options.onInput(frame.data);\n return;\n }\n if (frame.t !== \"resize\") return;\n const { cols, rows } = frame;\n if (!Number.isInteger(cols) || !Number.isInteger(rows) || cols <= 0 || rows <= 0) return;\n client.dims = { cols, rows };\n this.reconcileDims();\n }\n\n /**\n * A PTY has one size, so multiple viewers get the smallest box that fits\n * everyone — the same min-cols × min-rows rule the server-side relay applies\n * across its attached sockets. Only fires the callback on an actual change so\n * a steady stream of identical proposals doesn't churn the pty.\n */\n private reconcileDims(): void {\n let minCols = Infinity;\n let minRows = Infinity;\n for (const client of this.clients) {\n if (!client.dims) continue;\n if (client.dims.cols < minCols) minCols = client.dims.cols;\n if (client.dims.rows < minRows) minRows = client.dims.rows;\n }\n if (minCols === Infinity || minRows === Infinity) return;\n const prev = this.lastReconciled;\n if (prev && prev.cols === minCols && prev.rows === minRows) return;\n this.lastReconciled = { cols: minCols, rows: minRows };\n this.options.onResize(minCols, minRows);\n }\n}\n","/**\n * Direct-stream decorator for a `PtyBridge`.\n *\n * Wraps the relay-backed bridge so terminal bytes reach viewers straight from\n * the pod (`PtyStreamServer`) instead of round-tripping through the API. The\n * relay is NOT removed — it stays as the fallback transport for viewers that\n * can't reach the tunnel (local dev with no preview-router, codespace-backed\n * workspaces, an older web client).\n *\n * The interesting behavior is what happens to the relay while a direct viewer\n * is attached: rather than going silent — which would freeze any fallback\n * viewer's screen — relay output is **coalesced to one frame every couple of\n * seconds**. That cuts the server's per-frame cost by ~50x while keeping the\n * relay ring live, and it keeps `bumpPtyCardActivity` firing (the server-side\n * bump is throttled to 30s anyway), so an agent working in the TUI still holds\n * its pod's activity clock open exactly as before.\n */\n\nimport type { PtyBridge } from \"../types.js\";\nimport { PtyOutputCoalescer } from \"./output-coalescer.js\";\nimport { PtyStreamServer } from \"./stream-server.js\";\nimport { createServiceLogger } from \"../../utils/logger.js\";\n\nconst logger = createServiceLogger(\"PtyDirectStream\");\n\n/** Relay flush interval while ≥1 direct viewer is attached. Slow enough to gut\n * the per-frame server cost, fast enough that a fallback viewer sees a live\n * (if less smooth) terminal rather than a frozen one. */\nconst RELAY_COALESCE_MS = 2_000;\n/** Force a relay flush at this buffer size regardless of the timer, so a burst\n * of output can't sit unrelayed (and stays under the 256KB frame cap). */\nconst RELAY_MAX_BUFFER_CHARS = 48 * 1024;\n\n/** The connection surface the decorator needs — kept minimal so tests can pass\n * a plain object and so this module never imports the connection layer. */\nexport interface PtyStreamReporter {\n readonly sessionId: string;\n reportPtyStream(port: number | null): void;\n}\n\n/** Test seam: pin the stream server's port window so a suite can't collide with\n * a real agent running on the same host. Production passes nothing. */\nexport interface DirectPtyStreamOptions {\n portBase?: number;\n portAttempts?: number;\n}\n\nexport interface DirectPtyStream {\n bridge: PtyBridge;\n /** Tear down the in-pod server and clear the reported port. Idempotent. */\n dispose: () => Promise<void>;\n}\n\ninterface Dims {\n cols: number;\n rows: number;\n}\n\n/**\n * The decorator's mutable state. A class rather than one big closure so each\n * concern — server lifecycle, relay lane switching, dims reconciliation — stays\n * a small, separately readable method.\n */\nclass DirectStreamController {\n private server: PtyStreamServer | null = null;\n private starting = false;\n private disposed = false;\n\n // Handlers registered by the harness. The direct server feeds the SAME\n // handlers the relay does, so the pty sees one merged input/resize stream.\n private inputHandler: ((data: string) => void) | null = null;\n private resizeHandler: ((cols: number, rows: number) => void) | null = null;\n\n // Dims proposed by each transport. A PTY has one size, so the pty gets the\n // min box that fits both sets of viewers — the same rule each transport\n // already applies within itself.\n private relayDims: Dims | null = null;\n private directDims: Dims | null = null;\n\n private lastDims: Dims | undefined;\n private coalescing = false;\n private readonly relayCoalescer: PtyOutputCoalescer;\n\n constructor(\n private readonly inner: PtyBridge,\n private readonly reporter: PtyStreamReporter,\n private readonly options: DirectPtyStreamOptions,\n ) {\n // Dims are read from `lastDims` at flush time (rather than through the\n // coalescer's own getter) so an un-dimensioned frame relays with no dims at\n // all instead of a fabricated 0×0, which the relay's schema would reject.\n this.relayCoalescer = new PtyOutputCoalescer(\n (data) => this.inner.sendOutput(data, this.lastDims),\n () => this.lastDims ?? { cols: 0, rows: 0 },\n RELAY_COALESCE_MS,\n RELAY_MAX_BUFFER_CHARS,\n );\n }\n\n /** Start the in-pod server on first output. A session that never produces PTY\n * output (SDK harness, a run that dies at spawn) never binds a port. */\n private ensureServer(): void {\n if (this.server || this.starting || this.disposed) return;\n this.starting = true;\n const created = new PtyStreamServer({\n sessionId: this.reporter.sessionId,\n onInput: (data) => this.inputHandler?.(data),\n onResize: (cols, rows) => {\n this.directDims = { cols, rows };\n this.applyDims();\n },\n ...this.options,\n });\n void created\n .listen()\n .then((port) => this.onListening(created, port))\n .catch((err: unknown) => {\n this.starting = false;\n logger.warn(\n `PTY stream server failed to start: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n\n private onListening(created: PtyStreamServer, port: number | null): void {\n this.starting = false;\n // Disposed mid-bind, or the whole window was taken: stay on the relay.\n if (this.disposed || port === null) {\n void created.close();\n return;\n }\n this.server = created;\n this.reporter.reportPtyStream(port);\n logger.info(`PTY stream server listening on ${port} (session ${this.reporter.sessionId})`);\n }\n\n /** Push the min box across both transports to the pty. */\n private applyDims(): void {\n const candidates = [this.relayDims, this.directDims].filter((d): d is Dims => d !== null);\n if (candidates.length === 0 || !this.resizeHandler) return;\n this.resizeHandler(\n Math.min(...candidates.map((d) => d.cols)),\n Math.min(...candidates.map((d) => d.rows)),\n );\n }\n\n sendOutput(data: string, dims?: Dims): void {\n this.ensureServer();\n this.server?.broadcast(data, dims);\n if (dims) this.lastDims = dims;\n\n if ((this.server?.clientCount ?? 0) > 0) {\n this.coalescing = true;\n this.relayCoalescer.write(data);\n return;\n }\n // Back to the fast lane: flush whatever the slow lane still holds first so\n // relay watchers never see bytes out of order.\n if (this.coalescing) {\n this.coalescing = false;\n this.relayCoalescer.flush();\n }\n this.inner.sendOutput(data, dims);\n }\n\n sendEnded(): void {\n this.relayCoalescer.flush();\n this.server?.end();\n this.reporter.reportPtyStream(null);\n this.inner.sendEnded?.();\n }\n\n onInput(handler: (data: string) => void): () => void {\n this.inputHandler = handler;\n const off = this.inner.onInput(handler);\n return () => {\n if (this.inputHandler === handler) this.inputHandler = null;\n off();\n };\n }\n\n onResize(handler: (cols: number, rows: number) => void): () => void {\n this.resizeHandler = handler;\n const off = this.inner.onResize((cols, rows) => {\n this.relayDims = { cols, rows };\n this.applyDims();\n });\n return () => {\n if (this.resizeHandler === handler) this.resizeHandler = null;\n off();\n };\n }\n\n async dispose(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n this.relayCoalescer.dispose();\n this.reporter.reportPtyStream(null);\n const current = this.server;\n this.server = null;\n if (current) await current.close();\n }\n}\n\n/** Decorate `inner` with an in-pod stream server. */\nexport function wrapBridgeWithDirectStream(\n inner: PtyBridge,\n reporter: PtyStreamReporter,\n options: DirectPtyStreamOptions = {},\n): DirectPtyStream {\n const controller = new DirectStreamController(inner, reporter, options);\n return {\n bridge: {\n ...inner,\n sendOutput: (data, dims) => controller.sendOutput(data, dims),\n sendEnded: () => controller.sendEnded(),\n onInput: (handler) => controller.onInput(handler),\n onResize: (handler) => controller.onResize(handler),\n },\n dispose: () => controller.dispose(),\n };\n}\n","/* oxlint-disable max-lines, max-dependencies -- query orchestration + retry logic is cohesive; splitting would scatter tightly-coupled control flow */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, truncateSync } from \"node:fs\";\nimport { sessionTranscriptPath } from \"../harness/pty/settings.js\";\nimport { isConfigHomeMountDead } from \"../harness/pty/config-home-health.js\";\nimport type {\n HarnessEvent,\n HarnessQueryOptions,\n HarnessHookInput,\n HarnessHookOutput,\n HarnessKind,\n} from \"../harness/index.js\";\nimport { supportsImageBlocks } from \"../harness/index.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport type { TaskContext, MultimodalBlock, AgentMode } from \"@project/shared\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../runner-types.js\";\nimport { buildInitialPrompt } from \"./prompt-builder.js\";\nimport { buildSystemPrompt } from \"./system-prompt.js\";\nimport { createConveyorMcpServer } from \"../tools/index.js\";\nimport { resolvePlaywrightMcpServer } from \"./playwright-mcp.js\";\nimport { processEvents } from \"./event-processor.js\";\nimport { applyCycledKeyEnv, syncCredentialsAfterCycle, fallbackResetIso } from \"./key-cycle.js\";\nimport { API_ERROR_PATTERN, isAuthError } from \"./event-handlers.js\";\nimport { buildCanUseTool } from \"./tool-access.js\";\nimport { collectMissingProps } from \"./task-property-utils.js\";\nimport { redact } from \"./redactor.js\";\nimport { isHeavyGateActive } from \"../runner/heavy-gate.js\";\n\nconst logger = createServiceLogger(\"QueryExecutor\");\nconst IMAGE_ERROR_PATTERN = /Could not process image/i;\nconst RETRY_DELAYS_MS = [60_000, 120_000, 180_000, 300_000];\n\nexport type { QueryHost } from \"./query-host.js\";\nimport type { QueryHost } from \"./query-host.js\";\n\n// ── Query options builder ───────────────────────────────────────────────────\n\nfunction buildHooks(host: QueryHost): HarnessQueryOptions[\"hooks\"] {\n return {\n PostToolUse: [\n {\n hooks: [\n async (input: HarnessHookInput): Promise<HarnessHookOutput> => {\n if (host.isStopped()) return await Promise.resolve({ continue: false });\n if (input.hook_event_name === \"PostToolUse\") {\n const raw =\n typeof input.tool_response === \"string\"\n ? input.tool_response\n : JSON.stringify(input.tool_response);\n const { output: redacted, redacted: redactedCount } = redact(raw);\n const output = redacted.slice(0, 500);\n host.connection.sendEvent({\n type: \"tool_result\",\n tool: input.tool_name,\n output,\n isError: false,\n ...(redactedCount > 0 ? { redactedCount } : {}),\n });\n host.pendingToolOutputs.push({ tool: input.tool_name, output });\n\n // After PR creation, nudge agent to backfill missing task properties\n if (input.tool_name === \"mcp__conveyor__create_pull_request\") {\n try {\n const props = await host.connection.getTaskProperties();\n const missing = collectMissingProps(props);\n if (missing.length > 0) {\n host.connection.postChatMessage(\n `PR created! Please backfill missing task properties: ${missing.join(\", \")}`,\n );\n }\n } catch {\n /* best-effort */\n }\n }\n }\n return await Promise.resolve({ continue: true });\n },\n ],\n timeout: 5,\n },\n ],\n };\n}\n\n/**\n * Derive a deterministic UUID v8-style from a session lineage key.\n * The Claude SDK requires UUID format for sessionId; task IDs are cuids.\n * Using sha256(key) ensures the same lineage always maps to the same session.\n */\nfunction taskIdToSessionUuid(lineageKey: string): string {\n const hash = createHash(\"sha256\").update(lineageKey).digest(\"hex\");\n // Format as UUID: xxxxxxxx-xxxx-8xxx-axxx-xxxxxxxxxxxx (v8 + RFC 4122 variant)\n return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-8${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;\n}\n\n/**\n * Conversation lineage for a task. Review runs (code review, pack-runner\n * orchestration) get their OWN session lineage so:\n * - a review never resumes the building conversation (it may use a\n * different model — this was previously \"prevented\" by the server\n * clearing `sdkSessionId`, which never actually worked because resume is\n * filesystem-driven), and\n * - flipping back to building resumes the ORIGINAL building conversation\n * untouched.\n */\nexport function sessionLineageKey(\n taskId: string,\n agentMode: AgentMode,\n runnerMode: AgentRunnerConfig[\"mode\"],\n): string {\n return agentMode === \"review\" || runnerMode === \"code-review\" ? `${taskId}:review` : taskId;\n}\n\n/**\n * Check if a Claude session file exists for the given session UUID + cwd.\n * Session files live at <config-home>/projects/<cwd-slug>/<sessionId>.jsonl\n * (the same CLAUDE_CONFIG_DIR-aware path the PTY transcript tailer uses).\n */\nfunction sessionFileExists(sessionUuid: string, cwd: string): boolean {\n try {\n return existsSync(sessionTranscriptPath(cwd, sessionUuid));\n } catch {\n return false;\n }\n}\n\n/** Does a resumable Claude session already exist for this lineage + workspace? */\nexport function hasExistingSessionFile(\n taskId: string,\n cwd: string,\n lineage: { agentMode: AgentMode; runnerMode: AgentRunnerConfig[\"mode\"] },\n): boolean {\n const key = sessionLineageKey(taskId, lineage.agentMode, lineage.runnerMode);\n return sessionFileExists(taskIdToSessionUuid(key), cwd);\n}\n\n/**\n * Resolve how a spawned CLI session should start for a `lineageKey` + workspace:\n * resume an existing on-disk transcript (repairing a torn tail first) or create\n * a fresh session under the deterministic UUID. `sessionId` and `resume` are\n * mutually exclusive (SDK/CLI contract) — exactly one is returned.\n *\n * The task-card path (keyed on the task lineage) inlines this same decision to\n * also derive `promptDelivery` from existence; the ad-hoc scratch-pod runner\n * (keyed on its ad-hoc session id) uses this helper directly, so both derive the\n * same deterministic UUID and survive pod restarts via the GCS-FUSE transcript.\n */\nexport function resolveSessionStart(\n lineageKey: string,\n cwd: string,\n): { sessionId?: string; resume?: string } {\n const sessionUuid = taskIdToSessionUuid(lineageKey);\n if (sessionFileExists(sessionUuid, cwd)) {\n repairTornSessionFile(sessionTranscriptPath(cwd, sessionUuid));\n return { resume: sessionUuid };\n }\n return { sessionId: sessionUuid };\n}\n\n/**\n * Repair a transcript whose final record was torn by an ungraceful pod death\n * (SIGKILL mid-append, gcsfuse upload cut short): truncate to the end of the\n * last complete, parseable line so `--resume` gets a well-formed JSONL.\n * Returns true when a truncation was performed.\n */\nexport function repairTornSessionFile(path: string): boolean {\n try {\n if (!existsSync(path)) return false;\n const content = readFileSync(path, \"utf8\");\n if (content.length === 0) return false;\n\n // Phase 1: drop a trailing partial line (no terminating newline).\n let keepEnd = content.length;\n if (!content.endsWith(\"\\n\")) {\n // 0 when no newline exists at all.\n keepEnd = content.lastIndexOf(\"\\n\") + 1;\n }\n // Phase 2: drop trailing terminated lines that don't parse as JSON\n // (a write torn mid-line that still got its newline flushed).\n while (keepEnd > 0) {\n const prevNewline = content.lastIndexOf(\"\\n\", keepEnd - 2);\n const line = content.slice(prevNewline + 1, keepEnd - 1).trim();\n if (line.length > 0) {\n try {\n JSON.parse(line);\n // Trailing line is whole — done.\n break;\n } catch {\n /* unparseable — trim it */\n }\n }\n keepEnd = prevNewline + 1;\n }\n\n if (keepEnd === content.length) return false;\n truncateSync(path, Buffer.byteLength(content.slice(0, keepEnd), \"utf8\"));\n logger.warn(\"Repaired torn transcript before resume\", {\n path,\n trimmedBytes: content.length - keepEnd,\n });\n return true;\n } catch {\n // Best-effort — a failed repair falls through to the CLI.\n return false;\n }\n}\n\nexport interface PromptDeliveryInputs {\n harnessKind: HarnessKind;\n runnerMode: AgentRunnerConfig[\"mode\"];\n isAuto: boolean;\n agentMode: AgentMode;\n isFollowUp: boolean;\n hasExistingSession: boolean;\n}\n\n/**\n * Decide how a query's prompt reaches the agent.\n *\n * \"prefill\" (paste into the TUI input, let the human review/edit/Enter) applies\n * only to the INITIAL instructions of a `help` task chat under the PTY harness.\n * Everything else submits immediately:\n * - SDK harness: no interactive input box exists.\n * - code-review runner: autonomous, no human at the TUI.\n * - auto tasks (isAuto or agentMode \"auto\"): full-auto is the whole point.\n * - follow-ups: the human already directed the agent via chat.\n * - resumes: the conversation exists; re-prefilling the initial\n * instructions into it would be confusing.\n * - discovery (interactive): a fresh interactive card auto-submits its\n * planner preamble so the agent starts helping plan immediately, rather\n * than parking an empty TUI and waiting on the human to press Enter.\n *\n * The pm runner mode is NOT excluded: fresh Planning-status cards boot their\n * task pod as a pm runner (computeRunnerMode server-side), so pm + `help` IS\n * the human-facing read-only assist card that should park a prefilled TUI.\n * Autonomous pm flows are already caught by the auto/isAuto check above.\n */\nexport function resolvePromptDelivery(inputs: PromptDeliveryInputs): \"submit\" | \"prefill\" {\n if (inputs.harnessKind !== \"pty\") return \"submit\";\n if (inputs.runnerMode === \"code-review\") return \"submit\";\n if (inputs.isFollowUp || inputs.hasExistingSession) return \"submit\";\n if (inputs.isAuto || inputs.agentMode === \"auto\") return \"submit\";\n // Only read-only `help` parks a prefill. discovery/building/review initial\n // queries auto-run — discovery submits its planner preamble to start helping\n // plan immediately, and a fresh-disk build boot with nobody at the terminal\n // must never stall waiting on an unsubmitted prompt.\n if (inputs.agentMode !== \"help\") return \"submit\";\n return \"prefill\";\n}\n\nfunction isReadOnlyMode(mode: AgentMode, hasExitedPlanMode: boolean): boolean {\n return mode === \"discovery\" || mode === \"help\" || (mode === \"auto\" && !hasExitedPlanMode);\n}\n\nexport function buildDisallowedTools(\n settings: { disallowedTools?: string[] },\n mode: AgentMode,\n hasExitedPlanMode: boolean,\n): string[] | undefined {\n const modeDisallowed = isReadOnlyMode(mode, hasExitedPlanMode)\n ? [\"TodoWrite\", \"TodoRead\", \"NotebookEdit\"]\n : [];\n const configured = settings.disallowedTools ?? [];\n // The harness Artifact tool publishes to an off-platform claude.ai URL.\n // Conveyor deliverables must live on the card (upload_attachment / post_to_chat),\n // so it is always blocked for pod agents regardless of mode.\n const combined = [...new Set([...configured, ...modeDisallowed, \"Artifact\"])];\n return combined.length > 0 ? combined : undefined;\n}\n\nfunction buildQueryOptions(host: QueryHost, context: TaskContext): HarnessQueryOptions {\n const settings = context.agentSettings ?? host.config.agentSettings ?? {};\n const mode = host.agentMode;\n\n // Read-only modes (discovery, help) use the SDK's native \"plan\" permission\n // mode which enforces no-execution (blocks file edits and destructive\n // commands). canUseTool is still registered to intercept ExitPlanMode for\n // custom validation (plan/SP/title checks, triggerIdentification, mode\n // restart). The auto pre-exit arm is a residual safety net: auto now boots\n // with hasExitedPlanMode=true (ModeController.canBypassPlanning), so in\n // normal flow auto is never read-only.\n const isReadOnly = isReadOnlyMode(mode, host.hasExitedPlanMode);\n const needsCanUseTool = isReadOnly;\n\n const systemPromptText = buildSystemPrompt(\n host.config.mode,\n context,\n { ...host.config, isAuto: host.isAuto },\n host.setupLog,\n mode,\n );\n const settingSources = (settings.settingSources ?? [\"user\", \"project\"]) as (\n | \"user\"\n | \"project\"\n | \"local\"\n )[];\n\n return {\n model: context.model || host.config.model,\n systemPrompt: {\n type: \"preset\",\n preset: \"claude_code\",\n append: systemPromptText || undefined,\n },\n settingSources,\n cwd: host.config.workspaceDir,\n permissionMode: needsCanUseTool ? \"plan\" : \"bypassPermissions\",\n allowDangerouslySkipPermissions: !needsCanUseTool,\n canUseTool: buildCanUseTool(host),\n // A spawned CLI never sees `systemPrompt` (an SDK-only option) — deliver the\n // same text via `appendSystemPrompt`, which each spawning harness routes its\n // own way (`claude --append-system-prompt`; opencode an `instructions` file).\n // Without this an opencode card would run with no task context at all.\n ...(host.harnessKind !== \"sdk\" && systemPromptText\n ? { appendSystemPrompt: systemPromptText }\n : {}),\n // Auto mode pre-exit (residual sessions only — auto now boots post-exit):\n // after the ExitPlanMode hook allows the call, the CLI's plan dialog still\n // renders — press Enter so the autonomous agent continues building in the\n // same session (Conveyor validated in the hook).\n planDialogAutoAccept: mode === \"auto\" && !host.hasExitedPlanMode,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers: {\n conveyor: createConveyorMcpServer(host.harness, host.connection, host.config, context, mode),\n // Baked-in browser automation (claudespace pods) — omitted when the\n // binary isn't on PATH (dev machines, legacy images).\n ...(() => {\n const playwright = resolvePlaywrightMcpServer();\n return playwright ? { playwright } : {};\n })(),\n },\n sandbox: context.useSandbox ? { enabled: true } : { enabled: false },\n hooks: buildHooks(host),\n maxTurns: settings.maxTurns,\n effort: settings.effort,\n thinking: settings.thinking,\n betas: settings.betas,\n abortController: host.abortController ?? undefined,\n disallowedTools: buildDisallowedTools(settings, mode, host.hasExitedPlanMode),\n enableFileCheckpointing: settings.enableFileCheckpointing,\n stderr: (data: string) => {\n logger.warn(\"Claude Code stderr\", { data: data.trimEnd() });\n },\n };\n}\n\n// ── Multimodal prompt builder ────────────────────────────────────────────\n\ntype ImageMediaType = \"image/gif\" | \"image/jpeg\" | \"image/png\" | \"image/webp\";\n\nfunction buildMultimodalPrompt(\n textPrompt: string,\n context: TaskContext,\n skipImages = false,\n): string | MultimodalBlock[] {\n if (skipImages) return textPrompt;\n\n const taskImages = (context.files ?? []).filter(\n (f) => f.content && f.contentEncoding === \"base64\",\n );\n const chatImages: { fileName: string; mimeType: string; content: string }[] = [];\n for (const msg of context.chatHistory) {\n for (const f of msg.files ?? []) {\n if (f.content && f.contentEncoding === \"base64\") {\n chatImages.push({ fileName: f.fileName, mimeType: f.mimeType, content: f.content });\n }\n }\n }\n\n if (taskImages.length === 0 && chatImages.length === 0) return textPrompt;\n\n const blocks: MultimodalBlock[] = [{ type: \"text\", text: textPrompt }];\n for (const file of taskImages) {\n blocks.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: file.mimeType as ImageMediaType,\n data: file.content ?? \"\",\n },\n });\n blocks.push({ type: \"text\", text: `[Attached image: ${file.fileName} (${file.mimeType})]` });\n }\n for (const file of chatImages) {\n blocks.push({\n type: \"image\",\n source: { type: \"base64\", media_type: file.mimeType as ImageMediaType, data: file.content },\n });\n blocks.push({ type: \"text\", text: `[Chat image: ${file.fileName} (${file.mimeType})]` });\n }\n return blocks;\n}\n\n// ── Follow-up prompt builder ─────────────────────────────────────────────\n\nasync function buildFollowUpPrompt(\n host: QueryHost,\n context: TaskContext,\n followUpContent: string | MultimodalBlock[],\n): Promise<string | MultimodalBlock[]> {\n const isPmMode = host.config.mode === \"pm\";\n const followUpText =\n typeof followUpContent === \"string\"\n ? followUpContent\n : followUpContent\n .filter((b): b is Extract<MultimodalBlock, { type: \"text\" }> => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\\n\");\n\n const followUpImages =\n typeof followUpContent === \"string\"\n ? []\n : followUpContent.filter(\n (b): b is Extract<MultimodalBlock, { type: \"image\" }> => b.type === \"image\",\n );\n\n const textPrompt = isPmMode\n ? `${await buildInitialPrompt(host.config.mode, context, host.isAuto, host.agentMode)}\\n\\n---\\n\\nThe team says:\\n${followUpText}`\n : followUpText;\n\n const skipImages = !supportsImageBlocks(host.harnessKind);\n if (isPmMode) {\n // Under PTY skipImages yields a string, so follow-up image blocks are not\n // appended either — they stay reachable via chat attachments (MCP).\n const prompt = buildMultimodalPrompt(textPrompt, context, skipImages);\n if (followUpImages.length > 0 && Array.isArray(prompt)) {\n prompt.push(...followUpImages);\n }\n return prompt;\n }\n if (followUpImages.length > 0) {\n if (skipImages) {\n // Image blocks carry no fileId, so point at the attachment tools.\n const refs = followUpImages.map(\n () => `[Image attachment — use list_task_files / get_attachment to view]`,\n );\n return [textPrompt, ...refs].join(\"\\n\");\n }\n return [{ type: \"text\", text: textPrompt }, ...followUpImages];\n }\n return textPrompt;\n}\n\n// ── SDK query execution ──────────────────────────────────────────────────\n\n/** Pass events through, firing `onFirst` before the first non-system event. */\nasync function* notifyOnFirstEvent(\n inner: AsyncGenerator<HarnessEvent, void>,\n onFirst: () => Promise<void>,\n): AsyncGenerator<HarnessEvent, void> {\n let fired = false;\n for await (const event of inner) {\n if (!fired && event.type !== \"system\") {\n fired = true;\n await onFirst();\n }\n yield event;\n }\n}\n\n// How long a submitted PTY query may stay silent (zero transcript events)\n// before the agent reports waiting_for_input instead of running. A healthy\n// turn writes its first transcript record well inside this window; a TUI\n// parked on an unexpected dialog (trust prompt, onboarding wizard, login\n// screen) never produces one, which previously left the card stuck on\n// \"working\" indefinitely.\nconst PARKED_TUI_GRACE_MS = 45_000;\n\n// How long a submitted PTY turn may stay COMPLETELY silent (no harness events\n// at all — transcript, hook socket, or synthetic) before the turn is treated\n// as wedged and aborted. The turn-end signal is a transcript `result` record\n// read off the tailer; when that record is lost (observed live 2026-07-30: a\n// same-pod review child's boot clobbered gcsfuse file generations under the\n// shared ~/.claude mount, and the builder's finished turn never delivered its\n// result), the turn hangs with `_state === \"running\"` forever — heartbeats\n// keep reporting active, the workspace activity clock never expires, and the\n// pod becomes immortal. The abort routes through the turn's AbortController —\n// the same path stop()/supersede use — so PtySession translates it into\n// teardown(), the event queue closes, and the runner reaches its normal\n// end-of-turn idle bookkeeping. The next message respawns with --resume; the\n// transcript on disk is durable, so nothing is lost but the wedged process.\nconst TURN_SILENCE_TIMEOUT_MS = 30 * 60_000;\n\n// After the wedge abort, teardown closes the event queue and the stream\n// completes; if even that never settles (teardown itself wedged), abandon the\n// stream so the runner can still reach idle.\nconst WEDGE_ABORT_GRACE_MS = 15_000;\n\n/** The mid-turn silence window, overridable for ops (`0`/unset → default). */\nexport function resolveTurnSilenceTimeoutMs(): number {\n const raw = Number(process.env.CONVEYOR_TURN_SILENCE_TIMEOUT_MS ?? \"\");\n return Number.isFinite(raw) && raw > 0 ? raw : TURN_SILENCE_TIMEOUT_MS;\n}\n\n// How often a silent turn probes the Claude config home for a dead GCS FUSE\n// mount. When `~/.claude` drops mid-turn every CLI fs op fails with ENOTCONN\n// and the transcript `result` can never be written, so the turn would otherwise\n// sit \"running\" for the full 30-minute wedge window (observed live 2026-07-31:\n// mount died at 16:08, the turn was not aborted until 16:39). Two minutes turns\n// that into a bounded, self-recovering stall — the abort respawns onto the\n// pod-local config home.\nconst MOUNT_PROBE_INTERVAL_MS = 2 * 60_000;\n\n/** The mid-turn mount-probe cadence, overridable for ops (`0`/unset → default). */\nexport function resolveMountProbeIntervalMs(): number {\n const raw = Number(process.env.CONVEYOR_MOUNT_PROBE_INTERVAL_MS ?? \"\");\n return Number.isFinite(raw) && raw > 0 ? raw : MOUNT_PROBE_INTERVAL_MS;\n}\n\nconst SILENCE = Symbol(\"turn-silence\");\n\n/** Race one pending pull against a silence deadline, never leaking the timer. */\nasync function raceSilence<T>(pending: Promise<T>, ms: number): Promise<T | typeof SILENCE> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const deadline = new Promise<typeof SILENCE>((resolve) => {\n timer = setTimeout(() => resolve(SILENCE), ms);\n });\n try {\n return await Promise.race([pending, deadline]);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** The slice of QueryHost the parked-TUI watchdog touches. */\ntype ParkedTuiHost = Pick<\n QueryHost,\n \"connection\" | \"callbacks\" | \"abortController\" | \"wedgeAborted\"\n>;\n\n/** Mutable silence bookkeeping shared between the loop and its silence handler. */\ninterface SilenceState {\n /** True once this turn has been aborted — the wait becomes a settle grace. */\n abortedAsWedged: boolean;\n /** Silence accumulated since the last event; probe slices sum to the deadline. */\n silentMs: number;\n}\n\ntype SilenceOutcome = \"abandon\" | \"keep_waiting\";\n\n/**\n * Abort the turn through its controller — the same path stop()/supersede use,\n * so PtySession turns it into teardown() and the runner reaches its normal\n * end-of-turn bookkeeping. `wedgeAborted` on the host is what lets the runner\n * tell a watchdog kill from a normal turn end and self-requeue an autonomous\n * card's prompt.\n */\nfunction abortWatchedTurn(host: ParkedTuiHost, stderrLine: string, chatMessage: string): void {\n host.wedgeAborted = true;\n process.stderr.write(stderrLine);\n host.connection.sendEvent({ type: \"error\", message: chatMessage });\n host.abortController?.abort();\n}\n\n/**\n * One silence slice elapsed with no harness event. Decides between abandoning\n * the stream (an abort that never settled), aborting now (dead mount, or the\n * full wedge window), and waiting another slice. Mutates `state`.\n */\nasync function handleTurnSilence(\n host: ParkedTuiHost,\n state: SilenceState,\n waitMs: number,\n silenceTimeoutMs: number,\n probeMountDead?: () => Promise<boolean>,\n disableWedgeAbort?: boolean,\n): Promise<SilenceOutcome> {\n if (state.abortedAsWedged) {\n process.stderr.write(\n \"[conveyor-agent] Wedged turn did not settle after abort — abandoning the turn stream\\n\",\n );\n return \"abandon\";\n }\n state.silentMs += waitMs;\n // The mount check runs on every slice, heavy gate or not: a gate silences the\n // transcript legitimately, but it cannot revive a dead ~/.claude, and the\n // tool calls running inside it are failing on the same mount.\n if (probeMountDead && (await probeMountDead())) {\n state.abortedAsWedged = true;\n abortWatchedTurn(\n host,\n \"[conveyor-agent] Claude config home mount is disconnected mid-turn — aborting the turn \" +\n \"so the CLI can respawn on a pod-local config home\\n\",\n \"The shared ~/.claude mount died mid-turn, so this turn could not finish. \" +\n \"Aborting it and restarting the Claude CLI on pod-local storage.\",\n );\n return \"keep_waiting\";\n }\n if (state.silentMs < silenceTimeoutMs) return \"keep_waiting\";\n // A raw-relay TUI emits no harness events between spawn and exit by design,\n // so silence is not evidence of a wedge — there is no transcript `result` to\n // lose. Re-arm forever (same idiom as the heavy gate below) rather than\n // killing a live human-driven terminal at the deadline. Layer 1's\n // waiting_for_input flip still runs, which is the honest signal here.\n if (disableWedgeAbort) {\n state.silentMs = 0;\n return \"keep_waiting\";\n }\n // A foreground heavy gate legitimately silences the turn for its runtime —\n // re-arm the full window instead of firing.\n if (isHeavyGateActive()) {\n state.silentMs = 0;\n return \"keep_waiting\";\n }\n state.abortedAsWedged = true;\n const minutes = Math.round(silenceTimeoutMs / 60_000);\n abortWatchedTurn(\n host,\n `[conveyor-agent] Turn produced no events for ${minutes}m with no heavy gate running — aborting the wedged turn\\n`,\n `Turn silent for ${minutes}m — aborting it so the agent can go idle (the conversation resumes on the next message)`,\n );\n return \"keep_waiting\";\n}\n\n/**\n * Watchdog for submitted PTY queries, two layers:\n *\n * 1. **Start-of-turn status accuracy** (display-only): a query silent for\n * PARKED_TUI_GRACE_MS reports waiting_for_input instead of running;\n * the first event flips it back. `_state` in SessionRunner is untouched,\n * so chat-message supersede and idle-timer behavior are unchanged.\n * 2. **Mid-turn wedge recovery**: a turn silent for the full\n * TURN_SILENCE_TIMEOUT_MS (see the constant's comment for the lost-result\n * failure mode this exists for) is aborted via the turn's AbortController\n * so the runner can go idle instead of holding the pod open forever.\n * While a singleton heavy gate (test/typecheck/build) is running the\n * deadline re-arms instead of firing — a foreground gate legitimately\n * silences the turn for its whole runtime.\n * 3. **Mid-turn mount-death recovery**: while the turn is silent, the config\n * home is probed every `probeIntervalMs`. A dead GCS FUSE `~/.claude` mount\n * makes the transcript `result` unwritable, so layer 2 alone would hold the\n * turn for the full 30 minutes. A confirmed mount disconnect aborts the turn\n * at once; the respawn then flips to the pod-local config home. Probing is\n * opt-in (`opts.probeMountDead`) so callers without a config home — and the\n * unit tests for layers 1 and 2 — keep the exact pre-existing timing.\n */\nexport async function* watchForParkedTui(\n inner: AsyncGenerator<HarnessEvent, void>,\n host: ParkedTuiHost,\n opts?: {\n /** Resolves true when the Claude config home's mount is disconnected. */\n probeMountDead?: () => Promise<boolean>;\n probeIntervalMs?: number;\n /** Skip layer 2 (mid-turn wedge abort) — set for raw-relay harnesses whose\n * turns are silent by design. Layers 1 and 3 are unaffected. */\n disableWedgeAbort?: boolean;\n },\n): AsyncGenerator<HarnessEvent, void> {\n let parked = false;\n // The generator body runs lazily, so the timer starts when the consumer\n // begins draining — i.e. when the spawned CLI is live and the prompt has\n // been submitted.\n const timer = setTimeout(() => {\n parked = true;\n host.connection.emitStatus(\"waiting_for_input\");\n void host.callbacks.onStatusChange(\"waiting_for_input\");\n }, PARKED_TUI_GRACE_MS);\n const silenceTimeoutMs = resolveTurnSilenceTimeoutMs();\n // No probe supplied → one full-length silence window per wait, exactly as\n // before. With a probe, the wait is sliced so the mount can be checked\n // without changing when the wedge deadline itself fires.\n const probeIntervalMs = opts?.probeMountDead\n ? (opts.probeIntervalMs ?? resolveMountProbeIntervalMs())\n : Number.POSITIVE_INFINITY;\n const state: SilenceState = { abortedAsWedged: false, silentMs: 0 };\n let pending: Promise<IteratorResult<HarnessEvent, void>> | null = null;\n try {\n while (true) {\n pending ??= inner.next();\n const waitMs = state.abortedAsWedged\n ? WEDGE_ABORT_GRACE_MS\n : Math.max(1, Math.min(probeIntervalMs, silenceTimeoutMs - state.silentMs));\n const step = await raceSilence(pending, waitMs);\n if (step === SILENCE) {\n const outcome = await handleTurnSilence(\n host,\n state,\n waitMs,\n silenceTimeoutMs,\n opts?.probeMountDead,\n opts?.disableWedgeAbort,\n );\n if (outcome === \"abandon\") return;\n continue;\n }\n pending = null;\n state.silentMs = 0;\n if (step.done) return;\n clearTimeout(timer);\n if (parked) {\n parked = false;\n host.connection.emitStatus(\"running\");\n await host.callbacks.onStatusChange(\"running\");\n }\n yield step.value;\n }\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function runSdkQuery(\n host: QueryHost,\n context: TaskContext,\n followUpContent?: string | MultimodalBlock[],\n promptDeliveryOverride?: \"submit\" | \"prefill\",\n): Promise<void> {\n if (host.isStopped()) return;\n\n const mode = host.agentMode;\n const isDiscoveryLike = mode === \"discovery\" || mode === \"help\";\n\n // Use a deterministic UUID derived from the session lineage (taskId, with a\n // \":review\" variant for review runs) as the session ID. Sessions persist via\n // GCS-FUSE, so resuming by the derived UUID works across pod restarts\n // without tracking SDK-generated session IDs. See resolveSessionStart for\n // the sessionId/resume mutual-exclusivity contract.\n const sessionStart = resolveSessionStart(\n sessionLineageKey(context.taskId, mode, host.config.mode),\n host.config.workspaceDir,\n );\n const hasExistingSession = !!sessionStart.resume;\n const promptDelivery =\n promptDeliveryOverride ??\n resolvePromptDelivery({\n harnessKind: host.harnessKind,\n runnerMode: host.config.mode,\n isAuto: host.isAuto,\n agentMode: mode,\n isFollowUp: !!followUpContent,\n hasExistingSession,\n });\n const options = {\n ...buildQueryOptions(host, context),\n promptDelivery,\n ...(sessionStart.sessionId ? { sessionId: sessionStart.sessionId } : {}),\n };\n const resume = sessionStart.resume;\n\n if (followUpContent) {\n await runFollowUpQuery(host, context, options, resume, followUpContent);\n return;\n }\n if (isDiscoveryLike && (resume || host.harnessKind === \"sdk\")) {\n // No initial query for the read-only modes here: an existing conversation\n // resumes only when a chat message arrives (never re-run the preamble into\n // it), and the SDK harness has no card surface to preamble into. Headless\n // opencode DOES run it — gating on \"not pty\" instead of \"sdk\" made a fresh\n // discovery/help opencode card boot and then never query. Fresh interactive\n // discovery/help must fall through — gating on delivery instead of these\n // two conditions once skipped EVERY fresh discovery boot (\"Launching…\"\n // cards, 2026-07-17), since discovery now resolves to \"submit\".\n return;\n }\n await runInitialQuery(host, context, options, resume, promptDelivery);\n}\n\n/** Dispatch a follow-up to the prefill or submit path per the resolved delivery. */\nasync function runFollowUpQuery(\n host: QueryHost,\n context: TaskContext,\n options: HarnessQueryOptions,\n resume: string | undefined,\n followUpContent: string | MultimodalBlock[],\n): Promise<void> {\n if (options.promptDelivery === \"prefill\") {\n await runPrefilledFollowUp(host, context, options, resume, followUpContent);\n return;\n }\n const prompt = await buildFollowUpPrompt(host, context, followUpContent);\n const agentQuery = host.harness.executeQuery({\n prompt: typeof prompt === \"string\" ? prompt : host.createInputStream(prompt),\n options: { ...options },\n resume,\n });\n await trackAndRun(host, context, options, agentQuery);\n}\n\n/**\n * A follow-up delivered as a prefill: paste ONLY the message text into the TUI\n * input (the human reviews/edits/Enters it — e.g. a Refine prompt). Context\n * parity with the submitted pm follow-up (which prepends the full initial\n * prompt) is preserved by moving that text onto `--append-system-prompt`.\n * Images in the follow-up stay reachable via chat attachments.\n */\nasync function runPrefilledFollowUp(\n host: QueryHost,\n context: TaskContext,\n options: HarnessQueryOptions,\n resume: string | undefined,\n followUpContent: string | MultimodalBlock[],\n): Promise<void> {\n const followUpText =\n typeof followUpContent === \"string\"\n ? followUpContent\n : followUpContent\n .filter((b): b is Extract<MultimodalBlock, { type: \"text\" }> => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\\n\");\n\n const queryOptions = { ...options };\n if (host.config.mode === \"pm\" && !resume) {\n // Fresh pm session: the submitted path would prepend the full initial\n // prompt — deliver that context via the system prompt instead.\n const initialPrompt = await buildInitialPrompt(\n host.config.mode,\n context,\n host.isAuto,\n host.agentMode,\n );\n queryOptions.appendSystemPrompt = [queryOptions.appendSystemPrompt, initialPrompt]\n .filter(Boolean)\n .join(\"\\n\\n\")\n .slice(0, APPEND_SYSTEM_PROMPT_MAX_CHARS);\n }\n\n let agentQuery = host.harness.executeQuery({\n prompt: followUpText,\n options: queryOptions,\n resume,\n });\n // Parked until the human submits — first transcript event flips to running.\n agentQuery = notifyOnFirstEvent(agentQuery, async () => {\n host.connection.emitStatus(\"running\");\n await host.callbacks.onStatusChange(\"running\");\n });\n await trackAndRun(host, context, queryOptions, agentQuery);\n}\n\n/**\n * Drive a PASSIVE turn: the parked CLI is already emitting transcript records\n * because a human typed into the idle Connected-TUI (no prompt from us). Process\n * those events through the same pipeline as a normal turn — status, chat mirror,\n * plan sync, completion tracking — so the intervention is reflected everywhere.\n * No retry and no parked-TUI watchdog: a passive turn is human-paced and there\n * is nothing to resubmit. No-op on a harness without a parked session.\n */\nexport async function runPassiveTurn(host: QueryHost, context: TaskContext): Promise<void> {\n if (host.isStopped()) return;\n if (!host.harness.executePassiveTurn) return;\n const options = buildQueryOptions(host, context);\n const passiveQuery = host.harness.executePassiveTurn(options);\n host.activeQuery = passiveQuery;\n try {\n await processEvents(passiveQuery, context, host);\n } finally {\n host.activeQuery = null;\n }\n}\n\n/** Track the active query while runWithRetry drains it. */\nasync function trackAndRun(\n host: QueryHost,\n context: TaskContext,\n options: HarnessQueryOptions,\n agentQuery: AsyncGenerator<HarnessEvent, void>,\n): Promise<void> {\n // Prefill queries are parked by design (already reported as\n // waiting_for_input); SDK queries emit an init event immediately. Only a\n // submitted PTY turn can silently park on an unexpected CLI dialog.\n if (host.harnessKind === \"pty\" && options.promptDelivery !== \"prefill\") {\n // A raw-relay TUI has no transcript and no hook socket: it cannot lose a\n // `result` record, and it writes nothing under the Claude config home. Both\n // the wedge abort (layer 2) and the mount probe (layer 3) are therefore\n // meaningless for it — and the abort is actively harmful, since it would\n // kill a live human-driven terminal at the silence deadline.\n //\n // Verified live: an interactive opencode answers its prompt and then keeps\n // running, so a raw turn legitimately stays open indefinitely — the result\n // only ever arrives from process exit. That does NOT recreate the\n // immortal-pod bug layer 2 exists for: layer 1 still flips the reported\n // status to `waiting_for_input` at PARKED_TUI_GRACE_MS, and\n // `loopStatusForRunnerStatus` classifies that as *idle*, so the activity\n // clock stops being renewed and the pod sleeps on the ordinary idle window.\n // Layer 2's failure mode was a turn stuck reporting `running` forever.\n const rawRelay = host.harness.emitsStructuredEvents === false;\n agentQuery = watchForParkedTui(\n agentQuery,\n host,\n rawRelay\n ? { disableWedgeAbort: true }\n : { probeMountDead: () => isConfigHomeMountDead(options.cwd) },\n );\n }\n host.activeQuery = agentQuery;\n try {\n await runWithRetry(agentQuery, context, host, options);\n } finally {\n host.activeQuery = null;\n }\n}\n\n/** Defensive bound for `--append-system-prompt` argv size (Linux MAX_ARG_STRLEN is 128KiB). */\nconst APPEND_SYSTEM_PROMPT_MAX_CHARS = 96_000;\n\n/** The most recent non-empty user chat message — the text a human actually typed. */\nexport function latestUserMessageText(context: TaskContext): string | null {\n for (let i = context.chatHistory.length - 1; i >= 0; i--) {\n const msg = context.chatHistory[i];\n if (msg.role === \"user\" && msg.content.trim()) return msg.content.trim();\n }\n return null;\n}\n\n/**\n * Pick what lands in the TUI input for the INITIAL query, and what rides\n * `--append-system-prompt`, based on the resolved delivery.\n *\n * - **submit**: paste the full `initialPrompt` body — it auto-Enters, so nothing\n * is left parked in the input.\n * - **prefill**: paste ONLY the human's latest chat message, or an EMPTY box\n * when there is none — NEVER the full task body, which would park unsubmitted\n * and block the human from typing a follow-up (the original auto-mode\n * \"re-prefill\" bug). The full instructions/context move onto the system\n * prompt so the agent still has them once the human submits. The pasted\n * prefill is text-only; images stay reachable via chat/task attachments (MCP).\n */\nexport function selectInitialPromptInput(\n promptDelivery: \"submit\" | \"prefill\",\n initialPrompt: string,\n context: TaskContext,\n baseAppendSystemPrompt: string | undefined,\n harnessKind: HarnessKind,\n): { prompt: string | MultimodalBlock[]; appendSystemPrompt: string | undefined } {\n if (promptDelivery === \"prefill\") {\n return {\n prompt: latestUserMessageText(context) ?? \"\",\n appendSystemPrompt: [baseAppendSystemPrompt, initialPrompt]\n .filter(Boolean)\n .join(\"\\n\\n\")\n .slice(0, APPEND_SYSTEM_PROMPT_MAX_CHARS),\n };\n }\n return {\n // Only the SDK takes image blocks: a PTY would paste them into the TUI as\n // text and headless opencode passes argv — the prompt body already links\n // each image (get_attachment / downloadUrl).\n prompt: buildMultimodalPrompt(initialPrompt, context, !supportsImageBlocks(harnessKind)),\n appendSystemPrompt: baseAppendSystemPrompt,\n };\n}\n\n/** Build and run the initial (non-follow-up) query for the current mode. */\nasync function runInitialQuery(\n host: QueryHost,\n context: TaskContext,\n options: HarnessQueryOptions,\n resume: string | undefined,\n promptDelivery: \"submit\" | \"prefill\",\n): Promise<void> {\n const initialPrompt = await buildInitialPrompt(\n host.config.mode,\n context,\n host.isAuto,\n host.agentMode,\n );\n\n const { prompt, appendSystemPrompt } = selectInitialPromptInput(\n promptDelivery,\n initialPrompt,\n context,\n options.appendSystemPrompt,\n host.harnessKind,\n );\n const queryOptions = { ...options, appendSystemPrompt };\n\n let agentQuery = host.harness.executeQuery({\n prompt: host.createInputStream(prompt),\n options: queryOptions,\n resume,\n });\n if (promptDelivery === \"prefill\") {\n // The prompt sits unsubmitted in the TUI; the transcript stays empty\n // until the human presses Enter, so the first non-system event is the\n // \"human engaged\" signal — report running so the runner can leave\n // waiting_for_input and stop the prefill-wait idle timer.\n agentQuery = notifyOnFirstEvent(agentQuery, async () => {\n host.connection.emitStatus(\"running\");\n await host.callbacks.onStatusChange(\"running\");\n });\n }\n await trackAndRun(host, context, queryOptions, agentQuery);\n}\n\n// ── Retry logic ──────────────────────────────────────────────────────────\n\nasync function buildRetryQuery(\n host: QueryHost,\n context: TaskContext,\n options: HarnessQueryOptions,\n lastErrorWasImage: boolean,\n): Promise<AsyncGenerator<HarnessEvent, void>> {\n if (lastErrorWasImage) {\n host.connection.postChatMessage(\n \"An attached image could not be processed. Retrying without images...\",\n );\n }\n const retryPrompt = buildMultimodalPrompt(\n await buildInitialPrompt(host.config.mode, context, host.isAuto, host.agentMode),\n context,\n lastErrorWasImage || !supportsImageBlocks(host.harnessKind),\n );\n return host.harness.executeQuery({\n prompt: host.createInputStream(retryPrompt),\n // Strip sessionId on retry — if the failing query partially created a\n // session with that ID, passing it again would error. Let the SDK\n // auto-generate on retry attempts.\n options: { ...options, sessionId: undefined },\n resume: undefined,\n });\n}\n\nexport async function handleAuthError(\n context: TaskContext,\n host: QueryHost,\n options: HarnessQueryOptions,\n): Promise<void> {\n host.connection.postChatMessage(\"Authentication expired. Re-bootstrapping credentials...\");\n\n const refreshed = await host.connection.refreshAuthToken();\n if (!refreshed) {\n // No Claude credential could be resolved (none configured, or the bootstrap\n // has no Claude token to hand back). Do NOT process.exit — that crash-loops\n // the pod, and an agent that can't run still leaves an empty workspace that\n // wedges teardown (2026-07-05 canary). Post an actionable message and return\n // so the runner falls back to its idle/dormant wait: stays connected, burns\n // no tokens, and resumes if a human configures a credential and re-sends.\n host.connection.postChatMessage(\n \"⚠️ No Claude credential is configured for this project — the agent can't run and \" +\n \"is now idle. Add a Claude Code OAuth token (or Anthropic API key) in Project \" +\n \"Settings, then resume this task.\",\n );\n host.connection.sendEvent({\n type: \"error\",\n message: \"No Claude credential available — agent idle (dormant)\",\n });\n return;\n }\n\n // Clear session since it's tied to the old token\n context.claudeSessionId = null;\n host.connection.storeSessionId(\"\");\n\n const freshPrompt = buildMultimodalPrompt(\n await buildInitialPrompt(host.config.mode, context, host.isAuto, host.agentMode),\n context,\n !supportsImageBlocks(host.harnessKind),\n );\n const freshQuery = host.harness.executeQuery({\n prompt: host.createInputStream(freshPrompt),\n options: { ...options, sessionId: undefined },\n resume: undefined,\n });\n return runWithRetry(freshQuery, context, host, options);\n}\n\nasync function handleStaleSession(\n context: TaskContext,\n host: QueryHost,\n options: HarnessQueryOptions,\n): Promise<void> {\n context.claudeSessionId = null;\n host.connection.storeSessionId(\"\");\n const freshPrompt = buildMultimodalPrompt(\n await buildInitialPrompt(host.config.mode, context, host.isAuto, host.agentMode),\n context,\n !supportsImageBlocks(host.harnessKind),\n );\n const freshQuery = host.harness.executeQuery({\n prompt: host.createInputStream(freshPrompt),\n options: { ...options, sessionId: undefined },\n resume: undefined,\n });\n return runWithRetry(freshQuery, context, host, options);\n}\n\nasync function waitForRetryDelay(host: QueryHost, delayMs: number): Promise<void> {\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, delayMs);\n const checkStopped = setInterval(() => {\n if (host.isStopped()) {\n clearTimeout(timer);\n clearInterval(checkStopped);\n resolve();\n }\n }, 1000);\n setTimeout(() => clearInterval(checkStopped), delayMs + 100);\n });\n}\n\nfunction isStaleOrExitedSession(error: unknown, context: TaskContext): boolean {\n if (!(error instanceof Error)) return false;\n if (error.message.includes(\"No conversation found with session ID\")) return true;\n return !!context.claudeSessionId && error.message.includes(\"process exited\");\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return String(error);\n}\n\nfunction isRetriableError(error: unknown): boolean {\n const message = getErrorMessage(error);\n return API_ERROR_PATTERN.test(message) || IMAGE_ERROR_PATTERN.test(message);\n}\n\nfunction classifyImageError(error: unknown): boolean {\n return IMAGE_ERROR_PATTERN.test(getErrorMessage(error));\n}\n\nasync function emitRetryStatus(host: QueryHost, attempt: number, delayMs: number): Promise<void> {\n const delayMin = Math.round(delayMs / 60_000);\n host.connection.postChatMessage(\n `API error encountered. Retrying in ${delayMin} minute${delayMin > 1 ? \"s\" : \"\"}... (attempt ${attempt + 1}/${RETRY_DELAYS_MS.length})`,\n );\n host.connection.sendEvent({\n type: \"error\",\n message: `API error, retrying in ${delayMin}m (${attempt + 1}/${RETRY_DELAYS_MS.length})`,\n });\n host.connection.emitStatus(\"waiting_for_input\");\n await host.callbacks.onStatusChange(\"waiting_for_input\");\n\n await waitForRetryDelay(host, delayMs);\n\n host.connection.emitStatus(\"running\");\n await host.callbacks.onStatusChange(\"running\");\n}\n\nfunction handleRateLimitPause(host: QueryHost, rateLimitResetsAt: string): void {\n host.wasRateLimited = true;\n host.connection.emitRateLimitPause(rateLimitResetsAt);\n host.connection.postChatMessage(\n `Rate limited. The task will be automatically re-queued and resume after ${new Date(rateLimitResetsAt).toLocaleString()}.`,\n );\n}\n\n/** Ceiling on swaps per session — bounds pathological loops (e.g. every key on\n * the same exhausted account) without a server round-trip per check. */\nconst MAX_KEY_CYCLES = 5;\n\n/**\n * A hard usage cap ended the turn. Try to cycle to another eligible key\n * (server stamps the exhausted one and returns the replacement credential);\n * fall back to the classic rate-limit pause when cycling isn't possible.\n * Mirrors handleAuthError's recover-and-re-run shape.\n */\nasync function handleUsageCapRejection(\n context: TaskContext,\n host: QueryHost,\n options: HarnessQueryOptions,\n rateLimitType: string,\n resetsAt: string | undefined,\n): Promise<void> {\n const pauseAt = resetsAt ?? fallbackResetIso(rateLimitType);\n if (host.keyCycleCount >= MAX_KEY_CYCLES) {\n handleRateLimitPause(host, pauseAt);\n return;\n }\n host.keyCycleCount += 1;\n\n let response: Awaited<ReturnType<AgentConnection[\"cycleCodingAgentKey\"]>>;\n try {\n response = await host.connection.cycleCodingAgentKey(rateLimitType, resetsAt);\n } catch (error) {\n host.connection.postChatMessage(\n `Usage cap hit and key cycling failed (${getErrorMessage(error)}) — pausing until ${new Date(pauseAt).toLocaleString()}.`,\n );\n handleRateLimitPause(host, pauseAt);\n return;\n }\n\n if (!response.cycled) {\n // The server already stamped the key and requeued the task.\n handleRateLimitPause(host, response.resetsAt);\n return;\n }\n\n applyCycledKeyEnv(response.envVars);\n await syncCredentialsAfterCycle();\n // The live/parked TUI process is still authenticated as the exhausted key,\n // and PTY reuse fingerprints don't cover the token — kill it so the next\n // spawn re-runs prepareEnvironment against the fresh credentials file.\n await host.harness.dispose?.();\n\n host.connection.postChatMessage(\n `Usage cap hit — switched to key **${response.label}** and resuming.`,\n );\n\n // Fresh session under the new key (same recovery shape as handleAuthError):\n // the rebuilt initial prompt carries the chat history, so the interrupted\n // turn re-runs without the old transcript.\n context.claudeSessionId = null;\n host.connection.storeSessionId(\"\");\n const freshPrompt = buildMultimodalPrompt(\n await buildInitialPrompt(host.config.mode, context, host.isAuto, host.agentMode),\n context,\n !supportsImageBlocks(host.harnessKind),\n );\n const freshQuery = host.harness.executeQuery({\n prompt: host.createInputStream(freshPrompt),\n options: { ...options, sessionId: undefined },\n resume: undefined,\n });\n return runWithRetry(freshQuery, context, host, options);\n}\n\ntype RetryOutcome = { action: \"return\" } | { action: \"continue\"; lastErrorWasImage: boolean };\n\nfunction handleRetryError(\n error: unknown,\n context: TaskContext,\n host: QueryHost,\n options: HarnessQueryOptions,\n prevImageError: boolean,\n): RetryOutcome | Promise<void> {\n if (isStaleOrExitedSession(error, context) && context.claudeSessionId) {\n return handleStaleSession(context, host, options);\n }\n if (isAuthError(getErrorMessage(error))) {\n return handleAuthError(context, host, options);\n }\n if (!isRetriableError(error)) throw error;\n return { action: \"continue\", lastErrorWasImage: classifyImageError(error) || prevImageError };\n}\n\ntype ProcessResult =\n | { action: \"return\" }\n | { action: \"return_promise\"; promise: Promise<void> }\n | { action: \"continue\"; lastErrorWasImage: boolean };\n\nfunction handleProcessResult(\n result: Awaited<ReturnType<typeof processEvents>>,\n context: TaskContext,\n host: QueryHost,\n options: HarnessQueryOptions,\n): ProcessResult {\n if (result.modeRestart || host.isStopped()) return { action: \"return\" };\n\n if (result.rateLimitRejectedType || result.rateLimitResetsAt) {\n return {\n action: \"return_promise\",\n promise: handleUsageCapRejection(\n context,\n host,\n options,\n result.rateLimitRejectedType ?? \"unknown\",\n result.rateLimitResetsAt,\n ),\n };\n }\n\n // Handle stale session result errors (same recovery as thrown exceptions)\n if (result.staleSession && context.claudeSessionId) {\n return { action: \"return_promise\", promise: handleStaleSession(context, host, options) };\n }\n\n // Handle auth errors — re-bootstrap token and retry\n if (result.authError) {\n return { action: \"return_promise\", promise: handleAuthError(context, host, options) };\n }\n\n if (!result.retriable) return { action: \"return\" };\n return {\n action: \"continue\",\n lastErrorWasImage: IMAGE_ERROR_PATTERN.test(result.resultSummary ?? \"\"),\n };\n}\n\nasync function runWithRetry(\n initialQuery: AsyncGenerator<HarnessEvent, void>,\n context: TaskContext,\n host: QueryHost,\n options: HarnessQueryOptions,\n): Promise<void> {\n let lastErrorWasImage = false;\n\n for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {\n if (host.isStopped()) return;\n\n const agentQuery =\n attempt === 0\n ? initialQuery\n : await buildRetryQuery(host, context, options, lastErrorWasImage);\n\n try {\n const result = await processEvents(agentQuery, context, host);\n const outcome = handleProcessResult(result, context, host, options);\n if (outcome.action === \"return\") return;\n if (outcome.action === \"return_promise\") return outcome.promise;\n lastErrorWasImage = outcome.lastErrorWasImage;\n } catch (error) {\n const outcome = handleRetryError(error, context, host, options, lastErrorWasImage);\n if (outcome instanceof Promise) return outcome;\n if (outcome.action === \"return\") return;\n lastErrorWasImage = outcome.lastErrorWasImage;\n }\n\n if (attempt >= RETRY_DELAYS_MS.length) {\n host.connection.postChatMessage(\n `Agent shutting down after ${RETRY_DELAYS_MS.length} failed retry attempts due to API errors. ` +\n `The task will resume automatically when the codespace restarts.`,\n );\n return;\n }\n\n await emitRetryStatus(host, attempt, RETRY_DELAYS_MS[attempt]);\n }\n}\n","import type { ChatMessage, TaskContext } from \"@project/shared\";\n\n/**\n * Turn instructions for a chat card — bare and conversational, with no branch,\n * no gates and no Pre-PR Protocol.\n *\n * A chat card boots Unidentified and stays a conversation until the agent\n * saves a plan. That first plan is the single escalation door: it identifies\n * the card and moves it to In Progress (maybeIdentifyOnFirstPlan, api) and it\n * unlocks the PR path (tool-access.ts gates create_pull_request and `git push`\n * on the same plan). So a plan-less card carries exactly one pointer to that\n * door, and a card that already has a plan gets build guidance instead.\n */\nexport function buildChatInstructions(\n context: TaskContext,\n scenario: \"fresh\" | \"idle_relaunch\" | \"feedback_relaunch\",\n newMessages: ChatMessage[],\n): string[] {\n const userMessages = newMessages.filter((m) => m.role === \"user\");\n const parts: string[] = [];\n\n if (scenario === \"fresh\") {\n parts.push(\n `Read the chat history above and respond to what the team asked.`,\n `Reply with post_to_chat — your turn output is NOT shown in chat, so post_to_chat is the only way the team sees your answer.`,\n `Ask clarifying questions when they help. This is a conversation, not an autonomous build.`,\n );\n } else if (userMessages.length > 0) {\n parts.push(\n `You have new messages on this card.`,\n `\\nNew messages since your last run:`,\n ...userMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nRespond to them with post_to_chat (your turn output is NOT shown in chat).`,\n );\n } else {\n parts.push(\n `You were relaunched but no new messages have arrived since your last run.`,\n `Post a brief status update with post_to_chat if you still owe the team a response, then wait for them.`,\n );\n }\n\n if (!context.plan?.trim()) {\n parts.push(\n `\\nIf this conversation turns into a development task: save a plan with update_task_plan first — that identifies the card and moves it to In Progress — then implement it and open a PR with mcp__conveyor__create_pull_request, like a normal build.`,\n );\n return parts;\n }\n\n parts.push(\n `\\nThis card has a saved plan, so it is a development task now. Implement the plan on the git branch \"${context.githubBranch}\", verify with \\`bun run check\\` and \\`bun run test:affected\\`, then open the PR with mcp__conveyor__create_pull_request.`,\n );\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n return parts;\n}\n","import {\n CRITICAL_AUTOMATED_SOURCES,\n EXTERNAL_AGENT_MESSAGE_SOURCE,\n type AgentMode,\n type ChatMessage,\n type RunnerMode,\n type TaskContext,\n} from \"@project/shared\";\n\nexport function findLastAgentMessageIndex(history: ChatMessage[]): number {\n for (let i = history.length - 1; i >= 0; i--) {\n if (history[i].role === \"assistant\") return i;\n }\n return -1;\n}\n\n/**\n * Messages newer than the relaunch cursor. The cursor is the id of the most\n * recent message in the chat at the end of the agent's last successful turn.\n *\n * - Cursor inside the visible window → everything after that index is new.\n * - Cursor older than the window (fell off the 20-msg tail) → the entire\n * window is newer than what the agent has seen, so treat all of it as new.\n * This is the bug the cursor fixes: urgent user messages outside the window\n * were previously invisible to `findLastAgentMessageIndex` and the agent\n * reported \"no new instructions.\"\n */\nexport function messagesAfterCursor(\n history: ChatMessage[],\n lastSeenMessageId: string | null | undefined,\n): ChatMessage[] {\n if (!lastSeenMessageId) return history;\n const idx = history.findIndex((m) => m.id === lastSeenMessageId);\n return idx === -1 ? history : history.slice(idx + 1);\n}\n\n/**\n * The messages a relaunch prompt treats as \"since your last run\" — cursor-based\n * when the cursor is set, else everything after the agent's own last message.\n * Unlike the slices rendered into the prompt this keeps every role: critical\n * automated posts land as `role: \"system\"`.\n */\nexport function relaunchMessageBatch(context: TaskContext): ChatMessage[] {\n if (context.lastSeenMessageId) {\n return messagesAfterCursor(context.chatHistory, context.lastSeenMessageId);\n }\n return context.chatHistory.slice(findLastAgentMessageIndex(context.chatHistory) + 1);\n}\n\n/** Mirrors the `isCodeReview` derivation in `buildInstructions`. */\nexport function isCodeReviewRun(mode: RunnerMode | undefined, agentMode?: AgentMode | null): boolean {\n return mode === \"code-review\" || (mode !== \"pm\" && agentMode === \"review\");\n}\n\nfunction isActionableRelaunchMessage(m: ChatMessage): boolean {\n if (m.source && CRITICAL_AUTOMATED_SOURCES.has(m.source)) return true;\n return m.role === \"user\" && m.source !== EXTERNAL_AGENT_MESSAGE_SOURCE;\n}\n\n/**\n * A builder woken while its PR is under review must not take an implement turn\n * unless there is genuinely something to implement.\n *\n * The platform wakes a task's primary workspace purely to HOST a code review\n * (the `wake_deferred` shape in `ensureReviewCompute`). That wake looked\n * identical to a feedback relaunch to the prompt builder — any new chat since\n * the last turn (an external worker's status post, a teammate's note) read as\n * feedback — so the builder was handed \"implement your updates and open a PR\",\n * i.e. authorization to push to a branch that is mid-review. It burned a\n * phantom work turn.\n *\n * Hold instead, unless the new batch contains something real to act on:\n *\n * - a critical automated source — a request-changes verdict (`review_trigger`)\n * or a CI failure (`ci_failure`) IS actionable, and keeps today's implement\n * behavior verbatim; or\n * - a human directive — any other `role: \"user\"` message. The exception is a\n * post made by someone's Conveyor-MCP agent (`EXTERNAL_AGENT_MESSAGE_SOURCE`),\n * which is a status update from another worker, not an instruction. Those are\n * exactly what read as \"feedback\" and triggered the phantom turn.\n *\n * Keyed on runner mode + task status + message source, never on session role —\n * same-pod review children are readers while dedicated review writers exist, so\n * role is not a usable contract (see `.claude/rules/code-review.md`, the\n * 2026-07-07 regression note).\n */\nexport function isReviewHostHold(\n context: TaskContext,\n newMessages: ChatMessage[],\n isCodeReview: boolean,\n): boolean {\n // A code-review run woken on a ReviewPR task is doing its actual job.\n if (isCodeReview) return false;\n if (context.status !== \"ReviewPR\" || !context.githubPRUrl) return false;\n return !newMessages.some((m) => isActionableRelaunchMessage(m));\n}\n\n/**\n * The hold prompt: surface what arrived, then wait. The host still connects and\n * renews liveness — which is what delivers the parked review spawn\n * (`deliverPendingReviewSpawn` rides renewal, not the agent's turn) — it just\n * does not go do work.\n */\nexport function buildReviewHostHoldParts(\n context: TaskContext,\n newMessages: ChatMessage[],\n): string[] {\n const parts = [\n `You were relaunched while this task is in review, but nothing here asks you to change the code.`,\n `Most likely this workspace was woken to HOST the code review session, not to work.`,\n `Do NOT take a work turn: do not re-review your own diff, re-run gates, commit, or push. The PR is mid-review and moving the branch now would pull it out from under the reviewer.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n ];\n if (newMessages.length > 0) {\n parts.push(\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n );\n }\n parts.push(\n `\\nReview these messages and wait for the team to provide instructions before taking action.`,\n `If the review requests changes, or CI fails, you will be woken again with that feedback — act then, not now.`,\n );\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n return parts;\n}\n","import { HUMAN_PROSE_WRITING_STYLE } from \"@project/shared\";\nimport type { TaskContext, ChatMessage } from \"@project/shared\";\n\nfunction findLastAgentMessageIndex(history: ChatMessage[]): number {\n for (let i = history.length - 1; i >= 0; i--) {\n if (history[i].role === \"assistant\") return i;\n }\n return -1;\n}\n\nfunction formatProjectAgents(projectAgents: NonNullable<TaskContext[\"projectAgents\"]>): string[] {\n const parts: string[] = [``, `## Project Agents`];\n for (const pa of projectAgents) {\n const role = pa.role ? `role: ${pa.role}` : \"role: unassigned\";\n const sp =\n pa.storyPoints === null || pa.storyPoints === undefined\n ? \"\"\n : `, story points: ${pa.storyPoints}`;\n parts.push(`- ${pa.agent.name} (${role}${sp})`);\n }\n return parts;\n}\n\nfunction formatStoryPoints(storyPoints: NonNullable<TaskContext[\"storyPoints\"]>): string[] {\n const parts: string[] = [``, `## Story Point Tiers`];\n for (const sp of storyPoints) {\n const desc = sp.description ? ` — ${sp.description}` : \"\";\n parts.push(`- Value ${sp.value}: \"${sp.name}\"${desc}`);\n }\n return parts;\n}\n\nconst PACK_RUNNER_FOOTER: string[] = [\n ``,\n `Your turn output appears ONLY in the live agent terminal — it is NOT posted to the task chat. The team does NOT see your replies unless you post them.`,\n `Use post_to_chat (omit task_id → this task's chat) to report which children you fired, status as you orchestrate, and any blocker or escalation the team needs to act on.`,\n `Pass task_id only to message a DIFFERENT task's chat (e.g. a child task).`,\n `Use read_task_chat only if you need to re-read earlier messages beyond the chat context above.`,\n ``,\n `If a Conveyor tool call fails or reports the MCP server is unavailable/disconnected, this is almost always a transient socket reconnect — RETRY the same call; it will succeed once the connection re-establishes. A tool error is NOT a reason to go idle or stop the loop. (Going idle is only correct when you are genuinely waiting on child-task status changes or CI — see the loop above.)`,\n ``,\n HUMAN_PROSE_WRITING_STYLE,\n];\n\n/**\n * Feature-branch packs only. The server merges dev into the pack branch before\n * every child launch; this teaches the runner what to do with the one outcome\n * it can't handle server-side — a conflict.\n */\nfunction formatBaseSync(packBranch: string, devBranch: string): string[] {\n return [\n ``,\n `## Pack Branch Base Sync`,\n `This is a feature-branch pack: children branch from \\`${packBranch}\\` and PR back into it, and the whole pack lands on \\`${devBranch}\\` in one final PR at the end.`,\n `YOU are the reviewer of record for child PRs — the automated code reviewer skips PRs that target \\`${packBranch}\\` (the full automated review runs on the pack's final PR into \\`${devBranch}\\`). Review each child diff properly before merging; a merged child advances to ReviewDev automatically.`,\n `Before each child launch the server merges \\`${devBranch}\\` into \\`${packBranch}\\` for you, so children start from a fresh base. You do not need to do this yourself.`,\n `When start_child_cloud_build reports a base-sync conflict, that merge could not be applied automatically. Fix it before firing more children:`,\n `1. \\`git fetch origin ${devBranch} && git checkout ${packBranch} && git pull origin ${packBranch}\\``,\n `2. \\`git merge origin/${devBranch}\\`, resolve the conflicts, commit, and push to \\`${packBranch}\\`.`,\n `3. Resume the loop.`,\n `Resolving this merge is git coordination, not code-writing — it does NOT violate the \"Do NOT attempt to write code yourself\" rule below. Keep the resolution to the conflict markers; if a conflict needs real code decisions, escalate to the team instead of authoring the fix.`,\n `The launch itself is never blocked by a conflict — the child was already started from the un-synced branch, so sync promptly.`,\n ];\n}\n\n/**\n * The branch that carries merged child work. On a feature-branch pack the\n * children PR into the pack branch itself, so `baseBranch` (dev) is the wrong\n * thing to pull after a merge — that is only right for merge-to-dev packs.\n */\nexport function resolveMergedWorkBranch(context: TaskContext): string {\n return context.featureBranch && context.githubBranch ? context.githubBranch : context.baseBranch;\n}\n\nexport function buildPackRunnerSystemPrompt(\n context: TaskContext,\n config: { instructions: string; workspaceDir: string },\n setupLog: string[],\n): string {\n const mergedWorkBranch = resolveMergedWorkBranch(context);\n const parts: string[] = [\n `You are an autonomous Pack Runner managing child tasks for the \"${context.title}\" project.`,\n `You are running locally with full access to the repository and task management tools.`,\n `Your job is to execute child tasks by firing cloud builds, reviewing their PRs, and merging them — respecting dependency chains for parallel execution.`,\n ``,\n `## Child Task Status Lifecycle`,\n `- \"Planning\" — Not ready for execution. If its plan is solid, promote it yourself: update_subtask with status \"Open\" (plus storyPointValue and agentIdOrName if unset — setting story points does NOT auto-promote). Otherwise skip it (or escalate if blocking).`,\n `- \"Open\" — Ready to execute (if dependencies are met). Use start_child_cloud_build to fire it.`,\n `- \"InProgress\" — Currently being worked on by a Task Runner. Wait — it will move to ReviewPR when done.`,\n `- \"ReviewPR\" — Task Runner finished and opened a PR. Review and merge it.`,\n `- \"ReviewDev\" — PR was merged (to dev, or into this pack's feature branch for feature-branch packs). This child is complete. Move on.`,\n `- \"Complete\" — Fully done. Move on.`,\n ``,\n `## Autonomous Loop`,\n `Follow this loop each time you are launched or relaunched:`,\n ``,\n `1. Call list_subtasks to see the current state of all child tasks.`,\n ` The response includes PR info, agent assignment, **dependency info** (dependsOn array + allDependenciesMet flag), and the **packSlots** build-slot picture.`,\n ` If list_subtasks returns NO children, this is a fresh parent card: break the work down now — explore the codebase, save a parent-level plan with update_task_plan, then create child tasks with create_subtask, each with a detailed plan (file:line citations, verification steps) and dependsOn set for any child that blocks on another. Then fire the ready children and continue the loop.`,\n ``,\n `2. Evaluate children by status and dependency readiness:`,\n ` - \"ReviewPR\": Review and merge its PR with approve_and_merge_pr. (Highest priority)`,\n ` - If merge fails due to pending CI: post a status update to chat, state you are going idle.`,\n ` - If merge fails due to failed CI: use get_execution_logs(childTaskId) to check. Escalate to team.`,\n ` - \"InProgress\": A Task Runner is actively working. Do nothing — wait.`,\n ` - \"Open\" + allDependenciesMet=true: Ready to fire. Use start_child_cloud_build.`,\n ` - \"Open\" + allDependenciesMet=false: Blocked — skip for now. Will be unblocked when deps complete.`,\n ` - \"ReviewDev\" / \"Complete\": Already done. Skip.`,\n ` - \"Planning\": Not ready. Promote it with update_subtask (status \"Open\" + story points + agent) once its plan is solid; if it genuinely isn't plannable, notify team.`,\n ``,\n `3. Fire ALL ready \"Open\" tasks whose dependencies are met, not just one — independent tasks run in parallel. There is a concurrency limit: if start_child_cloud_build returns a PACK_CHILD_LIMIT error, that is backpressure, not a failure. Check list_subtasks' packSlots to see which children hold the in-flight slots — merge or wait on them (or stop_child_build a stale holder that isn't actually running), then start more as slots free up.`,\n ` A successful start_child_cloud_build moves that child to \"InProgress\" — that status IS your confirmation the fire landed. Never re-fire a child that already reads \"InProgress\".`,\n ``,\n `4. After merging a PR: run \\`git pull origin ${mergedWorkBranch}\\` then re-check list_subtasks — previously blocked tasks may now be ready.`,\n ``,\n `5. After firing all ready tasks: report which tasks you fired to chat, then state you are going idle.`,\n ``,\n `6. When ALL children are in \"ReviewDev\" or \"Complete\" (no \"Open\", \"InProgress\", or \"ReviewPR\" remaining): do a final review, summarize results in chat, and mark this parent task complete with force_update_task_status(\"Complete\").`,\n ``,\n `## Important Rules`,\n `- When dependencies are set on children, use them to determine execution order. Fire all ready tasks in parallel (up to the PACK_CHILD_LIMIT backpressure — see the loop above).`,\n `- Dependencies are explicit card metadata (set at creation via create_subtask's dependsOn, or rewired with update_subtask). Prefer them over reading order out of plan text. When NO dependencies are set on any children, fall back to ordinal order (one at a time) — this is legacy behavior; set dependsOn when a child truly blocks on another.`,\n `- After firing builds OR when waiting on CI, explicitly state you are going idle. Go idle when waiting — the system wakes you (or relaunches this environment) when a child changes status.`,\n `- Do NOT attempt to write code yourself. Your role is coordination only.`,\n `- If a child is stuck in \"InProgress\" for an unusually long time, use get_execution_logs(childTaskId) to check its logs and escalate to the team if it appears stuck.`,\n `- stop_child_build is a signal, not an immediate teardown: it tells the child's agent to stop, but the build slot stays held until that environment actually tears down. A slot still held right after a stop is normal, NOT a wedge — re-check list_subtasks' packSlots on a later turn instead of re-firing, stopping again, or escalating.`,\n `- You can use get_task(childTaskId) to get a child's full details including PR URL and branch.`,\n `- list_subtasks (compact view, the default) returns per child: status, agent assignment (agentId), story points, PR number/state, dependency info, and holdsBuildSlot — plus a packSlots summary of in-flight environments vs the cap. Use this to verify readiness before firing builds; pass verbose:true only if you need full plan/description text.`,\n `- You can use read_task_chat to check for team messages.`,\n ];\n\n if (context.featureBranch && context.githubBranch) {\n parts.push(...formatBaseSync(context.githubBranch, context.baseBranch));\n }\n\n if (context.storyPoints && context.storyPoints.length > 0) {\n parts.push(...formatStoryPoints(context.storyPoints));\n }\n\n if (context.projectAgents && context.projectAgents.length > 0) {\n parts.push(...formatProjectAgents(context.projectAgents));\n }\n\n if (setupLog.length > 0) {\n parts.push(``, `## Environment setup log`, \"```\", ...setupLog, \"```\");\n }\n\n if (context.agentInstructions) {\n parts.push(``, `## Agent Instructions`, context.agentInstructions);\n }\n if (config.instructions) {\n parts.push(``, `## Additional Instructions`, config.instructions);\n }\n\n parts.push(...PACK_RUNNER_FOOTER);\n\n return parts.join(\"\\n\");\n}\n\nexport function buildPackRunnerInstructions(\n context: TaskContext,\n scenario: \"fresh\" | \"idle_relaunch\" | \"feedback_relaunch\",\n): string[] {\n const parts: string[] = [`\\n## Instructions`];\n\n if (scenario === \"fresh\") {\n parts.push(\n `You are the Pack Runner for this task and its subtasks.`,\n `Begin your autonomous loop immediately: call list_subtasks to assess the current state.`,\n `If there are no children yet, create them first — save a parent-level plan with update_task_plan, then create child tasks with detailed plans and dependsOn set where one blocks on another. Then fire the ready ones.`,\n `If any child is in \"ReviewPR\" status, review and merge its PR first.`,\n `Then fire the next \"Open\" child task.`,\n );\n } else if (scenario === \"idle_relaunch\") {\n parts.push(\n `You have been relaunched — a child task likely changed status.`,\n `Call list_subtasks to check the current state of all children.`,\n `Look for children in \"ReviewPR\" status first — review and merge their PRs.`,\n `Check if any previously blocked tasks now have allDependenciesMet=true — fire them.`,\n `If a child you previously fired is now in \"ReviewDev\", pull latest with \\`git pull origin ${resolveMergedWorkBranch(context)}\\`.`,\n `If no children need action, state you are going idle.`,\n );\n } else {\n const lastAgentIdx = findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory\n .slice(lastAgentIdx + 1)\n .filter((m) => m.role === \"user\");\n parts.push(\n `You have been relaunched with new messages.`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAfter addressing the feedback, resume your autonomous loop: call list_subtasks and proceed accordingly.`,\n );\n }\n\n return parts;\n}\n","import { PM_CHAT_HISTORY_LIMIT, type TaskContext } from \"@project/shared\";\n\nexport { PM_CHAT_HISTORY_LIMIT };\n\n/**\n * The diff command every prompt hands an agent for \"what did this branch\n * change\".\n *\n * Two-dot `git diff <base>..HEAD` compares against the LOCAL `<base>` ref,\n * which in a pod's single-branch clone is either absent or stale — the agent\n * then reviews a diff that includes commits already merged into the base. The\n * merge-base form fetches the base first and diffs from the true fork point,\n * which is what the repo's own guidance prescribes.\n *\n * Commit-count forms like `HEAD~3` fail the same way and are worse, because\n * they look precise: `HEAD~N` walks first-parent ancestry straight through the\n * base's own merge commits, so on a branch with fewer than N commits it\n * silently presents the base's work as the agent's. Always express \"what this\n * branch changed\" as a merge-base range, never as a commit count.\n */\nexport function baseDiffCommand(baseBranch?: string | null, flags?: string): string {\n const base = baseBranch ?? \"dev\";\n const suffix = flags ? ` ${flags}` : \"\";\n return `git fetch origin ${base} -q && git diff $(git merge-base origin/${base} HEAD)..HEAD${suffix}`;\n}\n\n/**\n * What a gate result actually means.\n *\n * Prompts used to name the gate commands and stop there, which left three\n * silent-failure modes to be rediscovered per session: a second gate evicting\n * the first (`scripts/singleton.sh` gives the heavy gates one lock on a pod),\n * a run that never reached vitest, and `--affected` selecting nothing for a\n * package that was in fact changed. All three read as success.\n *\n * Every remedy here is deliberately scoped so it cannot become a second full\n * pass. In particular, the missing-summary bullet used to say \"no vitest\n * summary → unverified, re-run it\", which was simply wrong and cost a whole\n * redundant gate whenever it fired: `turbo.json` sets `outputLogs:\n * \"errors-only\"`, so a PASSING gate prints no per-suite summary at all. The\n * captured exit code is the authority.\n */\nexport function gateFailureModes(): string[] {\n return [\n `Reading a gate result correctly is what keeps this to ONE pass:`,\n `- Capture the exit code explicitly (\\`<gate> > <log> 2>&1; echo \"EXIT:$?\" >> <log>\\`) — piping a gate through \\`tail\\` masks it. That \\`EXIT:\\` line, plus turbo's final \\`Tasks:\\` count, is the authority on pass/fail.`,\n `- A green gate that printed no per-suite summary (no \\`Test Files\\`/\\`Tests\\` line) is still green: \\`turbo.json\\` sets \\`outputLogs: \"errors-only\"\\`, so a PASSING run prints nothing per suite. Do NOT re-run a clean-exit gate to \"see the counts\" — if you genuinely need them, run one package's script directly (\\`bun run --cwd <pkg> test\\`).`,\n `- Exit 143, or \\`singleton: stopping running '<label>'\\` on stderr, means a second gate you started evicted this one (on a pod the heavy gates share one lock). 143 is never a pass — but an evicted run never finished, so re-running it alone is still your one pass, not a repeat. Run one gate at a time; \\`bun run check\\` is not lock-wrapped, so it is safe alongside a test run.`,\n `- Confirm every package your diff touches actually appears in the run. \\`--affected\\` can select nothing for a package you changed; when that happens run just that package's suite directly, e.g. \\`bun run --cwd apps/api test:unit <changed test files>\\` — not the whole gate again.`,\n ...gateWaitProtocol(),\n ];\n}\n\n/**\n * The single largest pure-waste category in the 2026-07-27 fleet audit: 73\n * log-peek calls in five sessions, one session arming FIVE redundant waiters on\n * one log before reaching Monitor, and another launching + killing a\n * byte-identical command four times over cwd anxiety.\n */\nexport function gateWaitProtocol(): string[] {\n return [\n `How to wait for a gate — one gate, one wait, no polling:`,\n `- Launch it ONCE with \\`run_in_background: true\\`, then END YOUR TURN. The completion notification re-invokes you. Do not read the output file, \\`tail\\`/\\`wc\\`/\\`pgrep\\` it, or start a second watcher on a log another run already owns — a quiet gate is still running.`,\n `- Never wrap a gate in a foreground \\`timeout\\`: killing your own run at 590s produces exit 124/143 and ZERO information, and you then have to run it again unbounded. \\`sleep N; <cmd>\\` is hard-blocked for the same reason.`,\n `- Never relaunch a command you just killed without changing something. State cwd explicitly in the command (\\`cd /workspaces/repo && …\\`, \\`--root\\`, \\`git -C\\`) rather than trusting the shell's working directory.`,\n `- The completion notification reports the WRAPPER's exit code, not the gate's. A notification saying \"exit code 0\" over a log containing \\`EXIT:1\\` is a failed gate. The \\`EXIT:\\` line in the log is the authority.`,\n `- Scope heavy gates to what you changed (\\`--filter=<pkg>\\`). An unscoped \\`check:affected\\` can pull a large web typecheck into scope for a diff touching no web files and get OOM-killed (exit 137) after minutes, where the scoped run takes seconds.`,\n `- Merge the base BEFORE the gate pass, never after (see the Pre-PR Protocol). If that merge touched \\`package.json\\`/\\`bun.lock\\`, run \\`bun install\\` before starting the gate — a changed lockfile makes gates fail for reasons unrelated to your diff.`,\n ];\n}\n\n/**\n * 4 of 5 audited sessions treated a CI red as their own bug and spent 6–12\n * calls each proving otherwise. Front-load the four checks that distinguish\n * \"my diff broke it\" from \"this was already broken\".\n */\nexport function ciTriageChecklist(baseBranch?: string): string[] {\n const base = baseBranch?.trim() || \"dev\";\n return [\n `Before treating a CI failure as yours, run these four checks first — most reported reds are not caused by the diff:`,\n `1. Is the failing run's head SHA still current? A red run against a superseded commit is stale.`,\n `2. Is the only \\`##[error]\\` a cancellation (\"The operation was canceled\", \"The runner has received a shutdown signal\")? That is a reclaimed/preempted runner, not a code failure — re-run it.`,\n `3. Is the failing file even in your diff? \\`git diff origin/${base}...HEAD --stat -- <path>\\` — empty output means you did not touch it. Check whether \\`origin/${base}\\` already fails the same way before investigating further.`,\n `4. Is \\`origin/${base}\\` itself green? A semantic merge conflict on the base branch fails every open PR at once.`,\n `Known environmental failures — recognize, do not re-diagnose: suites needing a real Elasticsearch fail without \\`RC_TEST_ES_URL\\` and cannot pass in a pod; exit 137 is a pod OOM, not a code error; \\`gh\\` returning \\`HTTP 401: Bad credentials\\` means the pod token aged out (~1h) — re-exporting it does not help, so use the Conveyor MCP CI-status tools instead of spending calls re-testing \\`gh\\`.`,\n `A Dependabot PR showing \"no checks reported\" is in \\`action_required\\` — a maintainer must approve the workflow run. That is not \"CI did not run\", and you cannot unblock it yourself.`,\n ];\n}\n\nexport function formatFileSize(bytes: number | undefined): string {\n if (bytes === undefined) return \"\";\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nexport interface FileAttachment {\n fileName: string;\n mimeType: string;\n fileSize?: number;\n content?: string;\n contentEncoding?: string;\n downloadUrl?: string;\n fileId?: string;\n}\n\nexport function formatChatFile(file: FileAttachment): string[] {\n const sizeStr = file.fileSize ? `, ${formatFileSize(file.fileSize)}` : \"\";\n if (file.content && file.contentEncoding === \"utf-8\") {\n return [\n `[Attached: ${file.fileName} (${file.mimeType}${sizeStr})]`,\n \"```\",\n file.content,\n \"```\",\n ];\n }\n if (!file.content) {\n return [`[Attached: ${file.fileName} (${file.mimeType}${sizeStr})]: ${file.downloadUrl}`];\n }\n if (file.content && file.contentEncoding === \"base64\") {\n const link = file.downloadUrl ? ` or download: ${file.downloadUrl}` : \"\";\n return [\n `[Attached image: ${file.fileName} (${file.mimeType}${sizeStr}) — use get_attachment(\"${file.fileId}\") to view${link}]`,\n ];\n }\n return [`[Attached: ${file.fileName} (${file.mimeType}${sizeStr})]`];\n}\n\nexport function formatTaskFile(file: FileAttachment): string[] {\n if (file.content && file.contentEncoding === \"utf-8\") {\n return [`\\n### ${file.fileName} (${file.mimeType})`, \"```\", file.content, \"```\"];\n }\n if (file.content && file.contentEncoding === \"base64\") {\n const size = formatFileSize(file.fileSize);\n const link = file.downloadUrl ? ` or download: ${file.downloadUrl}` : \"\";\n return [\n `- [Attached image: ${file.fileName} (${file.mimeType}${size ? `, ${size}` : \"\"}) — use get_attachment(\"${file.fileId}\") to view${link}]`,\n ];\n }\n if (!file.content) {\n return [`- **${file.fileName}** (${file.mimeType}): ${file.downloadUrl}`];\n }\n return [];\n}\n\nexport function formatChatHistory(\n chatHistory: TaskContext[\"chatHistory\"],\n limit?: number,\n): string[] {\n const relevant = chatHistory.slice(-(limit ?? PM_CHAT_HISTORY_LIMIT));\n const parts = [`\\n## Recent Chat Context`];\n for (const msg of relevant) {\n const sender = msg.userName ?? msg.role;\n parts.push(`[${sender}]: ${msg.content}`);\n if (msg.files?.length) {\n for (const file of msg.files) {\n parts.push(...formatChatFile(file));\n }\n }\n }\n return parts;\n}\n\nexport function formatRepoRefs(repoRefs: NonNullable<TaskContext[\"repoRefs\"]>): string[] {\n const parts: string[] = [];\n parts.push(`\\n## Repository References`);\n for (const ref of repoRefs) {\n const icon = ref.refType === \"folder\" ? \"folder\" : \"file\";\n parts.push(`- [${icon}] \\`${ref.path}\\``);\n }\n return parts;\n}\n\nexport function formatReferenceProjects(\n referenceProjects: NonNullable<TaskContext[\"referenceProjects\"]>,\n): string[] {\n const parts: string[] = [];\n parts.push(`\\n## Reference Projects`);\n parts.push(\n `These sibling Conveyor projects have been shallow-cloned read-only into \\`/workspaces/references/<slug>/\\` for inspiration. You MAY grep/read them to compare approaches, but you MUST NOT modify them or commit anything from them into this task's repo.\\n`,\n );\n for (const ref of referenceProjects) {\n const repo =\n ref.githubRepoOwner && ref.githubRepoName\n ? ` (${ref.githubRepoOwner}/${ref.githubRepoName})`\n : \"\";\n parts.push(`- **${ref.name}**${repo} — \\`/workspaces/references/${ref.slug}/\\``);\n }\n return parts;\n}\n\nexport function formatProjectObjectives(\n objectives: NonNullable<TaskContext[\"projectObjectives\"]>,\n): string[] {\n const parts: string[] = [];\n parts.push(`\\n## Project Objectives`);\n for (const obj of objectives) {\n const dates = `${obj.startDate.split(\"T\")[0]} to ${obj.endDate.split(\"T\")[0]}`;\n parts.push(`- **${obj.name}** (${dates})${obj.description ? \": \" + obj.description : \"\"}`);\n }\n return parts;\n}\n\nexport function formatRecentRelatedTasks(\n tasks: NonNullable<TaskContext[\"recentRelatedTasks\"]>,\n): string[] {\n const parts: string[] = [];\n parts.push(`\\n## Recently Completed Related Tasks`);\n parts.push(\n `These tasks in the same domain were recently completed. Use them for context on recent changes and patterns.\\n`,\n );\n for (const task of tasks) {\n const tags = task.tagNames.length > 0 ? ` [${task.tagNames.join(\", \")}]` : \"\";\n const pr = task.githubPRUrl ? ` — PR: ${task.githubPRUrl}` : \"\";\n parts.push(`- **${task.title}**${tags}${pr}`);\n }\n return parts;\n}\n\nexport function formatIncidents(incidents: NonNullable<TaskContext[\"incidents\"]>): string[] {\n const parts: string[] = [];\n parts.push(`\\n## Linked Incidents`);\n parts.push(\n `This task has linked incidents. Review them for context on the problem being addressed.\\n`,\n );\n for (const inc of incidents) {\n const severity = inc.severity ? ` [${inc.severity}]` : \"\";\n const status = inc.status ? ` (${inc.status})` : \"\";\n parts.push(`### ${inc.title}${severity}${status}`);\n if (inc.description) parts.push(inc.description);\n if (inc.source) parts.push(`Source: ${inc.source}`);\n }\n return parts;\n}\n","/**\n * Workspace-file access that works in both pod topologies: direct fs\n * normally, over the launcher in split-mode pods (the repo lives only in the\n * workbench container). Only conveyor-agent's OWN reads route through here —\n * Claude Code's file tools run inside the workbench and stay native.\n */\n\nimport {\n readFile as localReadFile,\n readdir as localReaddir,\n stat as localStat,\n} from \"node:fs/promises\";\nimport { getWorkbenchClient } from \"./client.js\";\nimport { workbenchEnabled } from \"./mode.js\";\n\nexport async function readWorkspaceFile(path: string): Promise<string> {\n if (workbenchEnabled()) {\n return (await getWorkbenchClient().readFile(path)).toString(\"utf8\");\n }\n return localReadFile(path, \"utf-8\");\n}\n\n/** Binary-safe read — returns the raw bytes (never utf8-decoded). Used for\n * attachment uploads, where the file may be a png/pdf/zip that must survive\n * round-tripping. Routes through the workbench in split-mode pods, so a file\n * Claude Code wrote into the workbench container is visible to the agent\n * container's upload path. */\nexport function readWorkspaceBytes(path: string): Promise<Buffer> {\n if (workbenchEnabled()) return getWorkbenchClient().readFile(path);\n return localReadFile(path);\n}\n\nexport function readWorkspaceDir(path: string): Promise<string[]> {\n if (workbenchEnabled()) return getWorkbenchClient().readdir(path);\n return localReaddir(path);\n}\n\nexport interface WorkspacePathInfo {\n exists: boolean;\n isFile: boolean;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n}\n\nexport async function statWorkspacePath(path: string): Promise<WorkspacePathInfo> {\n if (workbenchEnabled()) return getWorkbenchClient().stat(path);\n try {\n const s = await localStat(path);\n return {\n exists: true,\n isFile: s.isFile(),\n isDirectory: s.isDirectory(),\n size: s.size,\n mtimeMs: s.mtimeMs,\n };\n } catch {\n return { exists: false, isFile: false, isDirectory: false, size: 0, mtimeMs: 0 };\n }\n}\n\nexport async function workspacePathExists(path: string): Promise<boolean> {\n return (await statWorkspacePath(path)).exists;\n}\n","import {\n readWorkspaceDir,\n readWorkspaceFile,\n statWorkspacePath,\n} from \"../workbench/fs.js\";\nimport type { RunnerMode, TagContextLink, TaskContext } from \"@project/shared\";\n\ninterface ResolvedEntry {\n type: \"rule\" | \"file\" | \"folder\" | \"doc\";\n path: string;\n label?: string;\n /** One-line summary shown in the discovery blurb (never the full body). */\n summary: string | null;\n}\n\ninterface ResolvedTagContext {\n tagName: string;\n description: string | null;\n entries: ResolvedEntry[];\n /** The tag carries a full glossary overview — worth a get_tag call. */\n hasOverview?: boolean;\n /** Repo file the overview is sourced from — Read it from the checkout\n * (branch-correct) instead of get_tag (base-branch materialization). */\n overviewPath?: string | null;\n}\n\nconst TYPE_PRIORITY: Record<string, number> = { rule: 0, doc: 1, file: 2, folder: 3 };\n\n// A single reference is described by one short line — no full-file bodies are\n// ever injected. This caps how much of a file we scan to derive that line.\nconst SUMMARY_SCAN_CHARS = 4_000;\nconst SUMMARY_MAX_CHARS = 160;\n\n// Binary file extensions to skip content injection\nconst BINARY_EXTENSIONS = new Set([\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".webp\",\n \".ico\",\n \".svg\",\n \".bmp\",\n \".mp3\",\n \".mp4\",\n \".wav\",\n \".avi\",\n \".mov\",\n \".pdf\",\n \".zip\",\n \".tar\",\n \".gz\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n \".otf\",\n \".exe\",\n \".dll\",\n \".so\",\n \".dylib\",\n \".wasm\",\n]);\n\nfunction isBinaryPath(filePath: string): boolean {\n const ext = filePath.slice(filePath.lastIndexOf(\".\")).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\n}\n\n// Module-scope cache of derived summaries keyed by absolute path.\n// Entries are invalidated when mtime changes (post-merge rule updates)\n// and can be cleared wholesale on session boundaries via clearTagContextCache().\nconst fileSummaryCache = new Map<string, { mtimeMs: number; summary: string | null }>();\nconst folderListingCache = new Map<string, { mtimeMs: number; listing: string }>();\nlet fileReadCount = 0;\nlet folderReadCount = 0;\n\nexport function clearTagContextCache(): void {\n fileSummaryCache.clear();\n folderListingCache.clear();\n}\n\nexport function _getTagContextCacheStatsForTest(): {\n files: number;\n folders: number;\n fileReads: number;\n folderReads: number;\n} {\n return {\n files: fileSummaryCache.size,\n folders: folderListingCache.size,\n fileReads: fileReadCount,\n folderReads: folderReadCount,\n };\n}\n\nexport function _resetTagContextReadCountsForTest(): void {\n fileReadCount = 0;\n folderReadCount = 0;\n}\n\n/**\n * Derive a one-line description for a reference file WITHOUT injecting its body.\n * Preference order: frontmatter `description:` / `title:` → first markdown\n * heading → first non-empty content line. YAML frontmatter (loader directives\n * like `paths:`) is stripped so it never leaks into the prompt.\n */\nexport function deriveSummary(raw: string): string | null {\n let body = raw;\n let frontmatter = \"\";\n if (raw.startsWith(\"---\")) {\n const end = raw.indexOf(\"\\n---\", 3);\n if (end !== -1) {\n frontmatter = raw.slice(3, end);\n const afterClose = raw.indexOf(\"\\n\", end + 1);\n body = afterClose === -1 ? \"\" : raw.slice(afterClose + 1);\n }\n }\n\n const fmDescription = frontmatter\n .split(\"\\n\")\n .map((l) => l.trim())\n .find((l) => /^(description|title):/i.test(l));\n if (fmDescription) {\n const value = fmDescription\n .slice(fmDescription.indexOf(\":\") + 1)\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n if (value) return truncateSummary(value);\n }\n\n for (const rawLine of body.split(\"\\n\")) {\n const line = rawLine.trim();\n if (!line) continue;\n // Strip markdown heading markers / list bullets for a clean one-liner.\n const cleaned = line\n .replace(/^#+\\s*/, \"\")\n .replace(/^[-*]\\s+/, \"\")\n .trim();\n if (cleaned) return truncateSummary(cleaned);\n }\n return null;\n}\n\nfunction truncateSummary(text: string): string {\n const collapsed = text.replace(/\\s+/g, \" \").trim();\n return collapsed.length > SUMMARY_MAX_CHARS\n ? collapsed.slice(0, SUMMARY_MAX_CHARS - 1).trimEnd() + \"…\"\n : collapsed;\n}\n\nasync function readFileSummary(filePath: string): Promise<string | null> {\n try {\n if (isBinaryPath(filePath)) return null;\n const st = await statWorkspacePath(filePath);\n if (!st.exists) return null;\n const mtimeMs = st.mtimeMs;\n const cached = fileSummaryCache.get(filePath);\n if (cached && cached.mtimeMs === mtimeMs) {\n return cached.summary;\n }\n const raw = await readWorkspaceFile(filePath);\n fileReadCount++;\n // Only scan a bounded prefix — enough to find a description/heading.\n const summary = deriveSummary(raw.slice(0, SUMMARY_SCAN_CHARS));\n fileSummaryCache.set(filePath, { mtimeMs, summary });\n return summary;\n } catch {\n return null;\n }\n}\n\nasync function readFolderListing(folderPath: string): Promise<string | null> {\n try {\n const st = await statWorkspacePath(folderPath);\n if (!st.exists) return null;\n const mtimeMs = st.mtimeMs;\n const cached = folderListingCache.get(folderPath);\n if (cached && cached.mtimeMs === mtimeMs) {\n return cached.listing;\n }\n const entries = await readWorkspaceDir(folderPath);\n folderReadCount++;\n const listing = `Files: ${entries.join(\", \")}`;\n folderListingCache.set(folderPath, { mtimeMs, listing });\n return listing;\n } catch {\n return null;\n }\n}\n\nasync function resolveEntry(entry: {\n type: string;\n path: string;\n label?: string;\n}): Promise<ResolvedEntry> {\n const result: ResolvedEntry = {\n type: entry.type as ResolvedEntry[\"type\"],\n path: entry.path,\n label: entry.label,\n summary: null,\n };\n\n // A human-authored label is the best one-liner; skip disk I/O when present.\n if (entry.label) {\n result.summary = truncateSummary(entry.label);\n return result;\n }\n\n if (entry.type === \"folder\") {\n result.summary = await readFolderListing(entry.path);\n return result;\n }\n\n // rule, doc, or file — derive a one-line summary from disk (body is never\n // injected). Project docs are synced from the repo, so a doc path is a\n // workspace path too.\n result.summary = await readFileSummary(entry.path);\n return result;\n}\n\nfunction formatEntry(entry: ResolvedEntry): string {\n const suffix = entry.summary ? ` — ${entry.summary}` : \"\";\n return `- \\`${entry.path}\\`${suffix}`;\n}\n\n/**\n * Tags MENTIONED in the card's description/plan (not assigned to it): the\n * author deep-linked a glossary term — surface its meaning and where the\n * full spec lives, without auto-loading anything.\n */\nfunction formatMentionedTags(mentioned?: ResolvedTagContext[]): string[] {\n if (!mentioned || mentioned.length === 0) return [];\n const parts: string[] = [\n `\\n### Mentioned glossary terms`,\n `The card's description/plan deep-links these project tags:`,\n ];\n for (const tag of mentioned) {\n const desc = tag.description ? ` — ${tag.description}` : \"\";\n const hint = tag.overviewPath\n ? ` (full overview: Read \\`${tag.overviewPath}\\` in the checkout)`\n : tag.hasOverview\n ? ` (full overview: get_tag(\"${tag.tagName}\"))`\n : \"\";\n parts.push(`- \"${tag.tagName}\"${desc}${hint}`);\n for (const entry of tag.entries) {\n parts.push(` ${formatEntry(entry)}`);\n }\n }\n return parts;\n}\n\n/**\n * A reviewer reads far more than it edits, so the builder framing below (\"they\n * auto-load when you edit matching files\") describes a mechanism that never\n * fires for a review session and reads as \"you can skip these\". Reviews get\n * their own intro pointing at the same docs as the conventions the diff is\n * judged against.\n */\nfunction tagContextIntro(runnerMode?: RunnerMode): string {\n if (runnerMode === \"code-review\") {\n return `These docs match this card's tags — they define the domain conventions the diff under review must follow. Read the entries relevant to the diff before judging pattern consistency; skip the ones the diff does not touch.`;\n }\n return `These docs match this task's tags. They auto-load when you edit matching files, and you can Read any of them the moment you need its detail — do NOT read them all up front.`;\n}\n\nfunction formatResolvedTags(\n resolved: ResolvedTagContext[],\n subProject?: { name: string; entries: ResolvedEntry[] } | null,\n mentioned?: ResolvedTagContext[],\n runnerMode?: RunnerMode,\n): string {\n const parts: string[] = [\n `\\n## Reference Guides (load on demand)`,\n tagContextIntro(runnerMode),\n ];\n\n for (const tag of resolved) {\n if (tag.entries.length === 0 && !tag.hasOverview) continue;\n const desc = tag.description ? ` — ${tag.description}` : \"\";\n parts.push(`\\n### Tag: \"${tag.tagName}\"${desc}`);\n if (tag.overviewPath) {\n // Repo-sourced overview: the checkout copy is branch-correct and fresher\n // than the served base-branch materialization.\n parts.push(`- Full glossary overview — Read \\`${tag.overviewPath}\\` in the checkout`);\n } else if (tag.hasOverview) {\n parts.push(`- Full glossary overview available — call get_tag(\"${tag.tagName}\")`);\n }\n for (const entry of tag.entries) {\n parts.push(formatEntry(entry));\n }\n }\n\n parts.push(...formatMentionedTags(mentioned));\n\n if (subProject && subProject.entries.length > 0) {\n parts.push(`\\n### Sub-project: \"${subProject.name}\"`);\n for (const entry of subProject.entries) {\n parts.push(formatEntry(entry));\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nasync function resolveEntries(\n contextPaths: TagContextLink[] | null | undefined,\n): Promise<ResolvedEntry[]> {\n if (!contextPaths?.length) return [];\n const sorted = [...contextPaths].sort(\n (a, b) => (TYPE_PRIORITY[a.type] ?? 99) - (TYPE_PRIORITY[b.type] ?? 99),\n );\n const results: ResolvedEntry[] = [];\n for (const entry of sorted) {\n results.push(await resolveEntry(entry));\n }\n return results;\n}\n\nfunction countResolved(entries: ResolvedEntry[]): { injected: number; skipped: number } {\n const injected = entries.filter((e) => e.summary !== null).length;\n return { injected, skipped: entries.length - injected };\n}\n\nasync function resolveAssignedTags(\n assignedTags: NonNullable<TaskContext[\"projectTags\"]>,\n): Promise<{ resolved: ResolvedTagContext[]; injected: number; skipped: number }> {\n const resolved: ResolvedTagContext[] = [];\n let injected = 0;\n let skipped = 0;\n\n for (const tag of assignedTags) {\n const entries = await resolveEntries(tag.contextPaths);\n const counts = countResolved(entries);\n injected += counts.injected;\n skipped += counts.skipped;\n resolved.push({\n tagName: tag.name,\n description: tag.description,\n entries,\n hasOverview: tag.hasOverview,\n overviewPath: tag.overviewPath ?? null,\n });\n }\n\n return { resolved, injected, skipped };\n}\n\nexport async function resolveTagContext(\n projectTags: TaskContext[\"projectTags\"],\n taskTagIds: string[],\n _model: string,\n _betas?: string[],\n runnerMode?: RunnerMode,\n subProject?: { name: string; contextPaths: TagContextLink[] | null } | null,\n mentionedTagIds?: string[],\n): Promise<{ injectedSection: string; stats: { injected: number; skipped: number } }> {\n const taskTagIdSet = new Set(taskTagIds);\n const assignedTags = (projectTags ?? []).filter((t) => taskTagIdSet.has(t.id));\n // Tags deep-linked in the card body but not assigned — glossary context only.\n const mentionedIdSet = new Set(mentionedTagIds ?? []);\n const mentionedTags = (projectTags ?? []).filter(\n (t) => mentionedIdSet.has(t.id) && !taskTagIdSet.has(t.id),\n );\n const hasTagPaths = assignedTags.some((t) => t.contextPaths?.length || t.hasOverview);\n const hasSubProjectPaths = (subProject?.contextPaths?.length ?? 0) > 0;\n\n if (!hasTagPaths && !hasSubProjectPaths && mentionedTags.length === 0) {\n return { injectedSection: \"\", stats: { injected: 0, skipped: 0 } };\n }\n\n const {\n resolved,\n injected: tagInjected,\n skipped: tagSkipped,\n } = await resolveAssignedTags(assignedTags);\n const { resolved: mentionedResolved } = await resolveAssignedTags(mentionedTags);\n\n let subProjectResolved: { name: string; entries: ResolvedEntry[] } | null = null;\n let subInjected = 0;\n let subSkipped = 0;\n if (subProject && hasSubProjectPaths) {\n const entries = await resolveEntries(subProject.contextPaths);\n const counts = countResolved(entries);\n subInjected = counts.injected;\n subSkipped = counts.skipped;\n subProjectResolved = { name: subProject.name, entries };\n }\n\n return {\n injectedSection: formatResolvedTags(\n resolved,\n subProjectResolved,\n mentionedResolved,\n runnerMode,\n ),\n stats: { injected: tagInjected + subInjected, skipped: tagSkipped + subSkipped },\n };\n}\n","const PLAN_SOFT_CAP = 4000;\nconst PLAN_HEAD_CHARS = 3000;\nconst PLAN_TAIL_CHARS = 500;\nconst PLAN_TRUNCATION_MARKER =\n \"\\n\\n... plan truncated — call get_current_plan for full text ...\\n\\n\";\n\n/**\n * Soft-cap plan markdown to avoid duplicating 5–10K chars in every relaunch\n * context fetch. Agents that need the full plan can call `get_current_plan`\n * (or `get_task` with the current task's slug/id).\n */\nexport function truncatePlanForPrompt(plan: string): string {\n if (plan.length <= PLAN_SOFT_CAP) return plan;\n const head = plan.slice(0, PLAN_HEAD_CHARS);\n const tail = plan.slice(plan.length - PLAN_TAIL_CHARS);\n return `${head}${PLAN_TRUNCATION_MARKER}${tail}`;\n}\n\nexport const PLAN_TRUNCATION_CONSTANTS = {\n PLAN_SOFT_CAP,\n PLAN_HEAD_CHARS,\n PLAN_TAIL_CHARS,\n PLAN_TRUNCATION_MARKER,\n} as const;\n","import type { AgentMode, TaskContext } from \"@project/shared\";\n\nenum PmRelaunchIntent {\n Build = \"build\",\n Review = \"review\",\n AutoWithPlan = \"auto_with_plan\",\n AutoPlanning = \"auto_planning\",\n WaitForTeam = \"wait_for_team\",\n}\n\nfunction resolvePmRelaunchIntent(\n context: TaskContext,\n isAuto?: boolean,\n agentMode?: AgentMode | null,\n): PmRelaunchIntent {\n switch (agentMode) {\n case \"building\":\n return PmRelaunchIntent.Build;\n case \"review\":\n return PmRelaunchIntent.Review;\n default:\n break;\n }\n\n if (!isAuto) return PmRelaunchIntent.WaitForTeam;\n return context.plan?.trim() ? PmRelaunchIntent.AutoWithPlan : PmRelaunchIntent.AutoPlanning;\n}\n\nfunction buildRelaunchMessageSummary(context: TaskContext, lastAgentIdx: number): string[] {\n const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === \"user\");\n if (newMessages.length === 0) {\n return [`You have been relaunched. No new messages since your last session.`];\n }\n return [\n `You have been relaunched. Here are new messages since your last session:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n ];\n}\n\nfunction buildPmBuildRelaunchParts(context: TaskContext, isAuto?: boolean): string[] {\n const parts = [\n `\\nYour plan has been approved. Begin implementing it now.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `Start by reading the relevant source files mentioned in the plan, then write code.`,\n `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`,\n ];\n if (isAuto) {\n parts.push(\n `\\nCRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,\n `Your FIRST action must be reading source files from the plan, then immediately writing code.`,\n `Do NOT summarize the plan or say \"ready to implement\" — start implementing.`,\n `If you are genuinely blocked, explain the specific blocker — do not go idle silently.`,\n );\n }\n return parts;\n}\n\nfunction buildPmReviewRelaunchParts(): string[] {\n return [\n `\\nResume reviewing and coordinating this task.`,\n `Call list_subtasks to check current child-task state and progress.`,\n `Review children in ReviewPR status first, then approve and merge passing PRs.`,\n `Fire next child builds with start_child_cloud_build when ready.`,\n `Do not implement code directly or create a new PR from the PM review session.`,\n ];\n}\n\nfunction buildPmAutoWithPlanRelaunchParts(): string[] {\n return [\n `\\nYou are in auto mode. A plan already exists for this task.`,\n `Begin implementing it now — refine story points, title, and tags via update_task_properties if they look like placeholders.`,\n `Do NOT wait for team input — proceed autonomously.`,\n ];\n}\n\nfunction buildPmAutoPlanningRelaunchParts(): string[] {\n return [\n `\\nYou are in auto mode. Continue building autonomously.`,\n `No plan is saved on this card yet — save a concise plan with update_task_plan before writing further code; never pause or wait for approval.`,\n `Do NOT wait for team input — proceed autonomously.`,\n ];\n}\n\nfunction buildPmWaitForTeamRelaunchParts(): string[] {\n return [\n `\\nYou are the project manager for this task.`,\n `Review the context above and wait for the team to provide instructions before taking action.`,\n ];\n}\n\nexport function buildPmRelaunchParts(\n context: TaskContext,\n lastAgentIdx: number,\n isAuto?: boolean,\n agentMode?: AgentMode | null,\n): string[] {\n const parts = buildRelaunchMessageSummary(context, lastAgentIdx);\n const intent = resolvePmRelaunchIntent(context, isAuto, agentMode);\n const intentPartsByIntent: Record<PmRelaunchIntent, () => string[]> = {\n [PmRelaunchIntent.Build]: () => buildPmBuildRelaunchParts(context, isAuto),\n [PmRelaunchIntent.Review]: buildPmReviewRelaunchParts,\n [PmRelaunchIntent.AutoWithPlan]: buildPmAutoWithPlanRelaunchParts,\n [PmRelaunchIntent.AutoPlanning]: buildPmAutoPlanningRelaunchParts,\n [PmRelaunchIntent.WaitForTeam]: buildPmWaitForTeamRelaunchParts,\n };\n parts.push(...intentPartsByIntent[intent]());\n return parts;\n}\n","import type { AgentMode, RunnerMode, TaskContext } from \"@project/shared\";\nimport { baseDiffCommand, ciTriageChecklist, gateFailureModes } from \"./prompt-formatters.js\";\n\nconst SP_DESC_MAX_CHARS = 80;\n\nfunction truncateDescription(desc: string, maxChars: number): string {\n if (desc.length <= maxChars) return desc;\n return desc.slice(0, maxChars) + \"…\";\n}\n\ntype ProjectTag = NonNullable<TaskContext[\"projectTags\"]>[number];\n\nfunction formatTagWithContextPaths(tag: ProjectTag): string[] {\n const desc = tag.description ? ` — ${tag.description}` : \"\";\n const lines = [`- Name: \"${tag.name}\"${desc}`];\n for (const link of tag.contextPaths ?? []) {\n const label = link.label ? ` (${link.label})` : \"\";\n lines.push(` → ${link.type}: ${link.path}${label}`);\n }\n return lines;\n}\n\n/** Living-estimate framing + risk legend, shared by every phase prompt. */\nfunction buildEstimateReassessmentLines(context: TaskContext): string[] {\n const currentSp = context.taskStoryPointValue ?? \"unset\";\n const currentRisk = context.taskRiskLevel ?? \"unset\";\n return [\n `Story points and risk are LIVING estimates, not one-time labels. Reassess them at every phase — planning, building, review — against your current understanding, and adjust in EITHER direction: work that looks big early is often small once scoped, and vice versa. Lowering an inflated estimate is as valuable as raising an underestimate; a stale value is worse than a changed one.`,\n `Current values: story points ${currentSp}, risk ${currentRisk}.`,\n ``,\n `Risk levels (how much important surface the change touches):`,\n `- critical: foundational surface — auth, billing, data integrity, migrations`,\n `- high: important surface with broad blast radius`,\n `- medium: moderate, contained surface area`,\n `- low: small or isolated change`,\n ];\n}\n\nfunction buildPropertyInstructions(context: TaskContext, runnerMode?: RunnerMode): string[] {\n const isTask = runnerMode === \"task\";\n const parts: string[] = [];\n parts.push(\n ``,\n `### Proactive Property Management`,\n `As you work this task, proactively keep task properties accurate:`,\n `- Use update_task_properties to set any combination of: title, story points, risk, and tags`,\n `- You can update all properties at once or just one at a time as needed`,\n `- Icons are assigned automatically during identification — do not set icons manually`,\n ``,\n ...buildEstimateReassessmentLines(context),\n ``,\n `Don't wait for the user to ask — keep these accurate as the work takes shape.`,\n `If scope changes materially at any point, update the properties to match.`,\n );\n\n // Story point tier vocabulary — every phase agent may reassess SP, so all\n // runner modes get the tier list when the project defines one.\n if (context.storyPoints && context.storyPoints.length > 0) {\n parts.push(``, `Available story point tiers:`);\n for (const sp of context.storyPoints) {\n const desc = sp.description\n ? ` — ${truncateDescription(sp.description, SP_DESC_MAX_CHARS)}`\n : \"\";\n parts.push(`- Value ${sp.value}: \"${sp.name}\"${desc}`);\n }\n }\n\n if (context.projectTags && context.projectTags.length > 0) {\n const assignedIds = new Set(context.taskTagIds ?? []);\n const assigned = context.projectTags.filter((t) => assignedIds.has(t.id));\n const unassigned = context.projectTags.filter((t) => !assignedIds.has(t.id));\n\n if (assigned.length > 0) {\n parts.push(``, `Assigned tags:`);\n for (const tag of assigned) parts.push(...formatTagWithContextPaths(tag));\n }\n\n // Unassigned tags — PM/code-review only, include context paths so agents can see linked files\n if (!isTask && unassigned.length > 0) {\n parts.push(``, `Available project tags:`);\n for (const tag of unassigned) parts.push(...formatTagWithContextPaths(tag));\n }\n\n parts.push(\n ``,\n `Tags are the project glossary. call get_tag(\"<name>\") for a term's full spec (overview, linked files, hierarchy) whenever a tag is assigned to this card or mentioned (@[tag:id]) in chat/plans. To mention a tag yourself, write @[tag:<name>] with the tag's exact name — the server rewrites it to the id token when it stores the text, so you never need the id. An unknown name is left as plain text. When your work changes how a tagged system behaves, update that tag's overview via update_tag with a short reason — your card is stamped into the revision history.`,\n );\n }\n\n return parts;\n}\n\n/**\n * Auto tasks boot straight into building with no plan-approval step — but the\n * plan must land on the card BEFORE code is written, so the team can see the\n * intent while the build runs. This section teaches plan-then-BUILD: saving the\n * plan is a required first step, NOT the deliverable — the implemented code is.\n * The single most common auto-mode failure is treating \"posted a plan\" (or\n * opening a plan-only PR) as done, so this section is emphatic that the plan is\n * only a step on the way to writing and shipping the actual code.\n */\nfunction buildPlanDocumentationSection(context?: TaskContext): string[] {\n const hasPlan = !!context?.plan?.trim();\n return [\n ``,\n `### Plan first, then BUILD — the plan is a step, NOT the deliverable`,\n `- The card is already In Progress and advances automatically (In Progress → Review PR when you open the PR). There is no plan-approval step.`,\n ...(hasPlan\n ? [\n `- A plan is already saved on the card. Keep it current with update_task_plan if your approach diverges materially — then IMPLEMENT it in code. The saved plan is not the deliverable; the working implementation is.`,\n ]\n : [\n `- No plan is saved yet: BEFORE writing any code, investigate briefly (search first, read only critical files) and save a concise implementation plan with update_task_plan (file:line citations). Saving the plan is a planning step, not the goal — immediately move on to WRITING THE CODE that implements it; never pause for approval.`,\n ]),\n `- Your goal is to BUILD the change, not to produce a plan. After the plan is posted, actually implement it: edit source files, make the change work, then verify. Do NOT stop, go idle, or open a PR the moment the plan exists.`,\n `- Your pull request MUST contain the actual code implementation. Never open a plan-only or empty-diff PR — a PR that just records the plan is never the goal of auto mode unless the task explicitly asks ONLY for a plan. (If the task genuinely needs no code changes, don't open a PR at all — finish per the section below.)`,\n `- Identification auto-fills title, story points, and icon with quick AI guesses. After exploring, refine the title, story points, and risk with update_task_properties whenever they no longer match what the work actually is — adjust in either direction. Icons are automatic — never set them.`,\n ];\n}\n\n/**\n * Not every task produces code. Support requests, config/credential help,\n * questions, investigations, and research deliver an answer or a file — not a\n * diff. `create_pull_request` is only for tasks that change repo code, so this\n * section teaches leaf agents to NOT open an empty/throwaway PR just to satisfy\n * the workflow: deliver in chat/attachments and complete the card directly.\n */\nfunction buildNoPrWhenNoCodeSection(baseBranch?: string): string[] {\n const diffCommand = baseDiffCommand(baseBranch);\n return [\n ``,\n `### A PR is NOT required — only open one for actual code changes`,\n `\\`create_pull_request\\` is for tasks that change code in the repo. Many tasks don't: support requests, config/credential help, answering a question, investigations, or research whose deliverable is an answer or a file rather than a diff.`,\n `- If you finish the work with NO code changes (an empty \\`${diffCommand}\\`), do NOT open a PR. An empty or throwaway PR just to \"complete\" the workflow is wrong — a human then has to close it.`,\n `- Deliver the result where it belongs: post the answer/config/findings with \\`post_to_chat\\`, and attach any files the user should keep with \\`upload_attachment\\` (any file type, up to 25MB). Never publish a deliverable as a Claude artifact or off-platform link — it belongs on the card.`,\n `- Then complete the card directly with \\`force_update_task_status(\"Complete\")\\` — there is no PR or review step for a no-code task.`,\n `- When in doubt, check \\`${diffCommand}\\`: a real diff means open a PR; no diff means finish in chat and mark Complete.`,\n ];\n}\n\n/**\n * Corrects a recurring agent failure on UI/UX work: capturing a screenshot but\n * then NOT hosting it — usually excused with the false belief that \"the\n * attachment server runs in a separate pod without codespace filesystem access,\"\n * or that attachments are images-only. Both are wrong: `upload_attachment` reads\n * a codespace-local file (image OR video, ≤25MB) and hosts it on the card\n * (`tools/attachment-tools.ts`), and every pod ships headless Playwright chromium\n * for capture.\n *\n * This section makes visual proof a required, unprompted step for any\n * rendered-UI change, and it now requires TWO destinations, not one:\n * capture → attach-to-card → EMBED in the PR description. The card alone was\n * never enough — a reviewer reads the PR on GitHub, and \"see the card\" costs\n * them a context switch. This used to say there was \"no programmatic path\" to\n * put an image in a private-repo PR, which was simply wrong: `upload_attachment`\n * returns the file's capability download URL, our API serves those bytes to an\n * `<img>`, and GitHub renders (and caches) it through its image proxy.\n */\nfunction buildAttachArtifactsSection(): string[] {\n return [\n ``,\n `### Screenshots & recordings — attach to the card AND embed in the PR description`,\n `If your diff changes anything a user sees rendered (e.g. \\`apps/web/**\\`, \\`apps/sandbox/**\\`, \\`*.tsx\\`/\\`*.jsx\\`, or styling), capture visual proof BEFORE you open the PR — a **screenshot** for a static change, or a short **screen recording** (\\`.mp4\\`/\\`.webm\\`/\\`.gif\\`, ≤25MB) for an interaction, animation, or multi-step flow. For a changed screen, capture before AND after. This is part of finishing UI work — do it unprompted, not only when a human asks. (Non-visual diffs and other documenting files — diagrams, generated reports — follow the same pattern when useful.)`,\n `Capture against the running preview: every pod ships headless Playwright chromium baked at \\`~/.cache/ms-playwright/\\`. Point it at the dev-server preview URL — \\`page.screenshot({ path })\\` for an image, a browser context \\`recordVideo\\` for a \\`.webm\\`.`,\n `Then attach it with \\`upload_attachment\\` (pass a workspace path): it reads the codespace-local file and hosts it on the card. It accepts images AND video (\\`.mp4\\`/\\`.webm\\`/\\`.gif\\`), up to 25MB.`,\n `- There is NO \"separate pod / no filesystem access\" limitation, and it is NOT images-only. Never tell the team a screenshot or recording \"could not be hosted\" — attach it.`,\n `- Pass \\`tags\\` when the capture is a good example of a glossary tag in some state — a screenshot of the tags page tagged \\`tag\\`, a board capture tagged \\`task\\`. Each tag's page lists its recent tagged attachments, so the label turns your screenshot into a living example of that entity and makes visual drift easy to spot. An unmatched name is reported back and never fails the upload.`,\n ``,\n `**The PR description must show the visual proof, not just point at it.** \\`upload_attachment\\` returns a \\`downloadUrl\\` for every file it stores, plus a ready-to-paste markdown line. Copy that line into the \\`body\\` you pass to \\`create_pull_request\\`:`,\n `- Images embed inline: \\`\\`. Write a real caption in the alt text — \"before\"/\"after\", or what the shot demonstrates.`,\n `- Video and other non-image files do not render inline on GitHub. Link them instead: \\`[interaction recording](<downloadUrl>)\\`.`,\n `- Put them under a \\`## Screenshots\\` heading in the PR body, with before/after side by side (or one after the other) when you changed an existing screen.`,\n `- The URL is a signed capability our API serves; GitHub fetches and caches the image through its own proxy when the description renders, so it keeps working after the capability expires. Do NOT paste codespace-local file paths (\\`/workspaces/repo/shot.png\\`) — reviewers cannot open those.`,\n `- Keep attaching to the card as well. The card is the durable home for the capture and the only place \\`tags\\` apply; the PR description is what the reviewer actually reads. Do both — neither one replaces the other.`,\n `- If \\`upload_attachment\\` returns no \\`downloadUrl\\`, still attach to the card, and say plainly in the PR body that the embed URL was unavailable. Never silently ship a UI PR with no visual proof.`,\n ];\n}\n\n/**\n * The structured PR guide is authored by the BUILDER as part of opening the PR\n * (moved off the reviewer, 2026-07-24). This section teaches: publish it right\n * after create_pull_request, and re-publish for the new head SHA after every\n * push so the card's Guide tab never goes stale. It is best-effort — a failed\n * publish never blocks opening or updating the PR.\n */\nfunction buildPrGuideSection(): string[] {\n return [\n ``,\n `### PR Guide — publish when you open the PR, refresh it on every push`,\n `Once your PR is open, publish a structured guide that walks a reviewer through the change with \\`publish_review_guide\\`. This is part of opening a PR: call it right after \\`create_pull_request\\` succeeds, and again whenever you push more commits to the branch.`,\n `- The head SHA is resolved from the local repo for you, so never hand-expand an abbreviated hash from commit output or plan text. Publish AFTER the push that created/updated the PR has landed on the branch.`,\n `- \\`sections\\` is a real top-level array ARGUMENT, not prose inside \\`overview\\`. Keep \\`overview\\` under 3000 characters — a short intro only — and put the walkthrough in \\`sections\\`, ordered with core behavior first and tests, migrations, generated files, and configuration later unless they are central.`,\n `- Explain each section's purpose and effect in plain language, and reference ONLY files this PR's diff actually changed — never context files you merely read or discussed.`,\n `- Anchors are optional and strict: the safest \\`files\\` entry is \\`{\"path\": \"...\"}\\` alone. If you anchor, \\`hunkHeader\\` must be the byte-exact full line from \\`git diff <base>..HEAD -- <file> | grep '^@@'\\` INCLUDING the trailing context text after the second \\`@@\\`, and \\`startLine\\`/\\`endLine\\` must overlap one real hunk's new-file range. When in doubt, omit the anchor fields.`,\n `- After any later push, call \\`publish_review_guide\\` again for the NEW head SHA — the card shows a \"stale\" banner until you republish for the current head.`,\n `- Best-effort: if publication fails after one corrected retry, continue. It never blocks opening or updating the PR.`,\n ];\n}\n\n/**\n * The pre-PR gate protocol — the ONE place this guidance is injected.\n *\n * It used to be a checklist (\"verify, then open the PR\") that silently\n * contradicted the repo's own \"refresh your base right before opening the PR\"\n * rule. Agents obeyed both, in that order — gates, then merge `dev`, then\n * re-run the gates because the base had moved — so a typical leaf card paid for\n * two or three full scoped passes. The fix is ordering, not exhortation: merge\n * the base BEFORE the single pass, then forbid anything that would invalidate\n * it. The turn prompt (`prompt-builder.ts`) deliberately carries only a one-line\n * pointer to this section rather than a second copy of it.\n */\nfunction buildPrePrProtocolSection(context?: TaskContext): string[] {\n const base = context?.baseBranch?.trim() || \"dev\";\n return [\n `### Pre-PR Protocol — sync the base first, then ONE verification pass`,\n `CI runs the FULL suite (lint, typecheck, all test shards) on every PR — do not duplicate it locally. Local gates run ONCE, in this order:`,\n `1. Finish the implementation and commit it.`,\n `2. **Sync the base FIRST**: \\`git fetch origin ${base} && git merge origin/${base} --no-edit\\`. Run \\`bun install\\` afterwards only if the merge touched \\`package.json\\`/\\`bun.lock\\`. Merging before the gates is what makes one pass sufficient — merging after them is what forces a second run.`,\n `3. **One verification pass**: \\`bun run check\\` (lint + typecheck, fast, not lock-wrapped) then \\`bun run test:affected\\` (runs only the tests your diff can affect — apps/api diffs are expected to run unit tests only since CI covers the int shards; \\`packages/shared\\`/\\`packages/db\\`/root-config diffs escalate to the full suite automatically, which is still one pass, not a repeat). Selection is a heuristic — confirm it actually ran the packages you changed.`,\n `4. **Open the PR immediately** with \\`mcp__conveyor__create_pull_request\\`. Do NOT re-merge the base and do NOT re-run a gate that already passed. If \\`${base}\\` moved while the gates were running, open the PR anyway — CI validates against the merged base.`,\n `Docs/markdown/\\`.claude\\`-only diffs skip steps 2-3 entirely — open the PR and let CI validate.`,\n ``,\n `**When a gate fails: fix, re-run only the failing tests, confirm once.**`,\n `- Iterate on the failures directly with the package-local script — \\`bun run --cwd <pkg> test:unit <files>\\` (or \\`test <files>\\`). It skips turbo's dep-build and the singleton lock, so it costs seconds instead of minutes. Do NOT re-run the whole gate on each iteration.`,\n `- Pick that file set deliberately: \\`rg <ComponentName>\\` across \\`__tests__\\` to find every suite that transitively mounts what you changed, so the targeted loop is not blind to indirect mounters.`,\n `- Once the targeted files pass, run the full scoped gate ONE more time as final confirmation, then open the PR. That single confirmation run — not a full gate per iteration — is what catches a suite your targeted set missed.`,\n `- Do NOT open a PR with a known failing gate.`,\n ...gateFailureModes(),\n ``,\n `Also before you open the PR (neither one needs a gate re-run):`,\n `- Reassess story points and risk against the ACTUAL diff — the estimate was made at planning time; now you know what the work really was. Correct them with \\`update_task_properties\\` in either direction.`,\n `- **UI/UX diffs:** if you changed anything rendered (\\`apps/web\\`, \\`apps/sandbox\\`, \\`*.tsx\\`/\\`*.jsx\\`, styling), capture a screenshot (static change) or short screen recording (interaction/animation), attach it to the card with \\`upload_attachment\\`, and **embed the returned \\`downloadUrl\\` in the PR description** — both, not either — see \"Screenshots & recordings\" below. Skip only when the diff has no visual effect.`,\n `- For refactors: run \\`${baseDiffCommand(context?.baseBranch)}\\` and confirm the public API surface (exports, function signatures) has no unintended breaking changes.`,\n ``,\n `### Triaging a CI failure`,\n ...ciTriageChecklist(context?.baseBranch),\n ];\n}\n\nfunction buildExplorationMethodology(): string[] {\n return [\n ``,\n `### Exploration Methodology`,\n `Investigate efficiently — do not read files aimlessly:`,\n `- Search first, read second: use grep/glob to locate relevant code, then read only the files that matter`,\n `- Never re-read a file already in your context — you have a large context window, scroll up instead`,\n `- Start with 3-5 critical files, form a hypothesis about the approach, then validate with targeted reads`,\n `- Stop exploring when you can cite specific \\`file.ts:line\\` locations and function names for every step in your plan — that's enough`,\n ];\n}\n\nfunction buildPlanCitationFormat(): string[] {\n return [\n ``,\n `### Plan Citation Format`,\n `Plans must ground each change in the code. For every step that touches code:`,\n `- Cite the exact location as \\`path/from/repo/root.ts:lineNumber\\` (e.g. \\`packages/conveyor-agent/src/execution/mode-prompt.ts:129\\`).`,\n `- Name the specific function, class, constant, or JSX element being touched.`,\n `- When behavior hinges on a short piece of code, quote 1–3 lines inline instead of paraphrasing.`,\n `- Ranges are fine for larger edits (\\`foo.ts:120-145\\`). Do not cite whole files without a line.`,\n `- If a file doesn't exist yet, write \\`NEW: path/to/new-file.ts\\` and describe the surrounding module it fits into.`,\n ];\n}\n\nfunction buildDiscoveryPrompt(context?: TaskContext, runnerMode?: RunnerMode): string {\n const parts = [\n `\\n## Mode: Discovery`,\n `You are in Discovery mode — helping plan and scope this task.`,\n `- You have read-only codebase access (can read files, run git commands, search code)`,\n `- Shell commands run without asking for approval — the pod is a sandbox, so investigate freely (build, test, query the dev DB, read logs). Only commands that would start the work are denied: git commit/push/merge/rebase/checkout, git apply, gh pr create, and package publish`,\n `- You can write plan files in .claude/plans/ only — no other file writes. Plan files on disk are NOT synced to the task; save the plan via update_task_plan`,\n `- Do NOT attempt to edit, write, or modify source code files — these operations will be denied`,\n `- If you identify code changes needed, describe them in the plan instead of implementing them`,\n `- You can create and manage subtasks`,\n `- Goal: collaborate with the user to create a clear plan`,\n `- Proactively fill task properties (SP, tags) as the plan takes shape`,\n ``,\n `### Planning Checklist (complete ALL before calling ExitPlanMode)`,\n `Your PRIMARY goal is to create a thorough plan. Complete these steps in order:`,\n `1. Read the task description and chat history — respond to what's been discussed`,\n `2. Investigate the codebase using the methodology below — search first, read targeted files`,\n `3. Save a detailed plan via \\`update_task_plan\\``,\n `4. Set story points, risk, tags, and title via \\`update_task_properties\\` (icon is set automatically)`,\n `5. Discuss the plan with the team if they're engaged, incorporate feedback`,\n `6. THEN call ExitPlanMode — it is the LAST step, not the first`,\n ...buildExplorationMethodology(),\n ...buildPlanCitationFormat(),\n ``,\n `### Self-Identification Tools`,\n `Use these MCP tools to set your own task properties:`,\n `- \\`update_task_plan\\` — save your plan and description`,\n `- \\`update_task_properties\\` — set title, story points, risk, and tags (any combination)`,\n `Note: Icons are assigned automatically during identification after planning is complete.`,\n ``,\n `### Tags & Context`,\n `- Early in discovery, identify relevant project tags that match this task's domain`,\n `- Add matching tags using \\`update_task_properties\\` — this links relevant documentation and rules that help you plan more effectively`,\n `- Tags accelerate discovery by surfacing domain-specific context automatically`,\n ``,\n ...(context?.isParentTask\n ? [\n `### Parent Task Coordination`,\n `You are a parent task with child tasks. Focus on breaking work into child tasks with detailed plans, not planning implementation for yourself.`,\n `- Use \\`list_subtasks\\` to review existing children. Create or update child tasks using \\`create_subtask\\` / \\`update_subtask\\`.`,\n `- Each child task should be a self-contained unit of work with a clear plan.`,\n `- Set ordering as explicit **card metadata**, not prose: pass \\`dependsOn\\` (sibling ids/slugs) on \\`create_subtask\\` for any child that blocks on another. Leave independent children with no dependencies so the pack runner fans them out in parallel. Do NOT encode \"do X after Y\" only in the plan text — the runner schedules off dependsOn, not narrative.`,\n ]\n : [\n `### Self-Update vs Subtasks`,\n `- If the work fits in a single task (1-3 SP), update YOUR OWN plan and properties — do not create subtasks`,\n `- Only create subtasks when the work genuinely requires multiple independent pieces (e.g., Pack-tier work, 8+ SP)`,\n ]),\n ``,\n `### Subtask Plan Requirements`,\n `When creating subtasks, each MUST include a detailed \\`plan\\` field:`,\n `- Plans should be multi-step implementation guides, not vague descriptions`,\n `- Include concrete \\`file.ts:line\\` citations, function/symbol names, and short code snippets where relevant`,\n `- Reference existing implementations when relevant (e.g., \"follow the pattern in src/services/foo.ts\")`,\n `- Include testing requirements and acceptance criteria`,\n `- Set \\`storyPointValue\\` based on estimated complexity`,\n `- Express cross-child ordering as \\`dependsOn\\` (sibling ids/slugs) on \\`create_subtask\\` — explicit dependency metadata, not \"after task 2\" phrasing in the plan. Independent children get no dependencies so they run in parallel.`,\n ``,\n `### Plan Verification Requirements`,\n `Every plan MUST include a **Testing / Verification** section so the build agent has a clear definition of \"done\". Enumerate:`,\n `- The scoped verification for the change: \\`bun run check\\` (lint + typecheck) plus \\`bun run test:affected\\` — name the specific package suites the diff will touch. Docs-only plans should state that no local gates are needed (CI validates on the PR).`,\n `- Any task-specific end-to-end checks (manual UI walk-through, API smoke test, migration dry-run, etc.)`,\n `You are NOT expected to run these gates yourself — discovery is read-only. Just describe them in the plan.`,\n ``,\n `### Completing Planning`,\n `Once ALL checklist items above are done, call the **ExitPlanMode** tool.`,\n `- Required before ExitPlanMode will succeed: **plan** (via update_task_plan), **story points**, **risk**, and **title** (via update_task_properties)`,\n `- ExitPlanMode validates these properties and marks planning as complete`,\n `- It does NOT start building — the team controls when to switch to Build mode`,\n `- Do NOT call ExitPlanMode until you have thoroughly explored the codebase and saved a detailed plan`,\n ];\n if (context) parts.push(...buildPropertyInstructions(context, runnerMode));\n return parts.join(\"\\n\");\n}\n\nfunction buildAutoPrompt(context?: TaskContext, runnerMode?: RunnerMode): string {\n const parts = [\n `\\n## Mode: Auto`,\n `You are in Auto mode — operating autonomously through building → PR.`,\n `- You have full coding access (read, write, edit, bash, git) from the start — there is no read-only planning phase`,\n `- Safety rules: no destructive operations, use --force-with-lease instead of --force`,\n ...buildPlanDocumentationSection(context),\n ``,\n `### Subtask Plan Requirements`,\n `When creating subtasks, each MUST include a detailed \\`plan\\` field:`,\n `- Plans should be multi-step implementation guides, not vague descriptions`,\n `- Include concrete \\`file.ts:line\\` citations, function/symbol names, and short code snippets where relevant`,\n `- Reference existing implementations when relevant`,\n `- Include testing requirements and acceptance criteria`,\n `- Set \\`storyPointValue\\` based on estimated complexity`,\n `- Express cross-child ordering as \\`dependsOn\\` (sibling ids/slugs) on \\`create_subtask\\` — explicit dependency metadata, not \"after task 2\" phrasing in the plan. Independent children get no dependencies so they run in parallel.`,\n ``,\n ...buildPlanCitationFormat(),\n ``,\n ...(context?.isParentTask\n ? [\n ``,\n `### Parent Task Guidance`,\n `You are a parent task — coordinate child tasks instead of implementing directly.`,\n `If no children exist yet, break the work down now: save a parent-level plan with update_task_plan, then create child tasks with create_subtask (each with a detailed plan).`,\n `Child task status lifecycle: Open → InProgress → ReviewPR → ReviewDev → Complete.`,\n `Set child ordering with \\`dependsOn\\` (sibling ids/slugs) on \\`create_subtask\\` — explicit metadata the pack runner schedules off, not order described in plan text. Independent children get none and run in parallel.`,\n ]\n : [\n ...buildAttachArtifactsSection(),\n ...buildPrGuideSection(),\n ...buildNoPrWhenNoCodeSection(context?.baseBranch),\n ]),\n ``,\n `### Autonomous Guidelines:`,\n `- Make decisions independently — do not ask the team for approval at each step`,\n `- Only escalate when genuinely blocked (ambiguous requirements, missing access, conflicting instructions)`,\n `- Investigate efficiently: search (grep/glob) to locate code, read only critical files, form a hypothesis, validate, then plan`,\n ];\n if (context) parts.push(...buildPropertyInstructions(context, runnerMode));\n return parts.join(\"\\n\");\n}\n\nfunction buildBuildingPrompt(context?: TaskContext): string {\n const parts = [\n `\\n## Mode: Building`,\n `You are in Building mode — executing the plan.`,\n `- You have full coding access (read, write, edit, bash, git)`,\n `- Safety rules: no destructive operations, use --force-with-lease instead of --force`,\n ...(context?.isParentTask\n ? [\n `- You are a parent task. Use \\`list_subtasks\\`, \\`start_child_cloud_build\\`, and subtask management tools to coordinate children.`,\n `- Do NOT implement code directly — fire child builds and review their work.`,\n `- Goal: coordinate child task execution and ensure all children complete successfully`,\n ]\n : [\n `- If this is a leaf task (no children): execute the plan directly`,\n `- Goal: implement the plan, run scoped verification once, open a PR when done`,\n ``,\n ...buildPrePrProtocolSection(context),\n ...buildAttachArtifactsSection(),\n ...buildPrGuideSection(),\n ...buildNoPrWhenNoCodeSection(context?.baseBranch),\n ...(context?.isAuto || !context?.plan?.trim()\n ? buildPlanDocumentationSection(context)\n : []),\n ]),\n ];\n if (context) parts.push(...buildPropertyInstructions(context));\n return parts.join(\"\\n\");\n}\n\nexport function buildModePrompt(\n agentMode: AgentMode | null | undefined,\n context?: TaskContext,\n runnerMode?: RunnerMode,\n): string | null {\n switch (agentMode) {\n case \"discovery\":\n return buildDiscoveryPrompt(context, runnerMode);\n case \"building\":\n return buildBuildingPrompt(context);\n case \"review\":\n return buildReviewPrompt(context);\n case \"auto\":\n return buildAutoPrompt(context, runnerMode);\n case \"chat\":\n return buildChatPrompt(context);\n default:\n return null;\n }\n}\n\n/**\n * Chat mode: a conversational assistant on its own card. The card boots\n * Unidentified and stays that way while the work is a conversation —\n * deliverables are files attached to the card, not a PR. Saving a plan is the\n * one escalation door: the first plan identifies the card, moves it to In\n * Progress (maybeIdentifyOnFirstPlan, api) and unlocks the PR path\n * (tool-access.ts gates create_pull_request and `git push` on that same plan).\n */\nfunction buildChatPrompt(context?: TaskContext): string {\n const base = context?.baseBranch?.trim() || \"dev\";\n return [\n `\\n## Mode: Chat`,\n `You are in Chat mode — a conversational assistant working directly with the user on this card.`,\n `- Respond conversationally to the user in chat. Ask clarifying questions when useful; this is a back-and-forth, not an autonomous build.`,\n `- You have full read/write access to the workspace and can run non-destructive shell commands, so you CAN create files (notes, scripts, docs, data, diagrams, etc.) when they help the user.`,\n `- This card starts Unidentified. That is correct — it stays a conversation until the work becomes a development task (see below).`,\n ``,\n `### Deliverables — attach files to the card`,\n `- When you create a file the user should keep, attach it to the card with the \\`upload_attachment\\` tool so it shows up on the card. Mention in chat what you attached.`,\n `- \\`upload_attachment\\` accepts any file type (markdown, PDF, HTML, text, data, images) up to 25MB — this is how docs are delivered. Do NOT publish deliverables as a Claude artifact or any other off-platform link; the card is the system of record.`,\n `- For conversational work, attachments are the deliverable. Do NOT open a PR to hand over a document or an answer.`,\n ``,\n `### Turning into a development task`,\n `- If the conversation becomes a request to change the code, escalate the card first: save a plan with \\`update_task_plan\\`. That first plan identifies the card and moves it to In Progress.`,\n `- The plan is also the gate on your PR path: \\`create_pull_request\\`, \\`git push\\` and \\`gh pr\\` are DENIED until a plan is saved, and allowed afterwards. Do not try to work around a denial — save the plan.`,\n `- Once the plan is saved, work like a normal build: implement it, then run ONE verification pass (\\`bun run check\\` plus \\`bun run test:affected\\`) after syncing the base (\\`git fetch origin ${base} && git merge origin/${base} --no-edit\\`), then open the PR with \\`mcp__conveyor__create_pull_request\\`.`,\n `- Keep talking to the user while you build — this is still their card.`,\n ``,\n `### Finishing the conversation`,\n `- When the user indicates they are done (or explicitly asks to wrap up / close the card), call \\`force_update_task_status\\` with status \\`\"Complete\"\\`. It works from either status, so a card still sitting Unidentified can be completed the same way as one that reached In Progress.`,\n `- If you opened a PR, do NOT complete the card — the PR review flow takes it from there.`,\n `- If the user is still engaged, keep helping — only complete the card once the interaction has concluded.`,\n `- Do not complete the card while you still owe the user a response or an attachment.`,\n ].join(\"\\n\");\n}\n\n/**\n * The card's assigned tags, framed for a reviewer.\n *\n * Review is the only build-capable mode that never calls\n * `buildPropertyInstructions`, so without this section a reviewer sees no tag\n * listing at all — and the task brief's \"Reference Guides\" section skips any\n * tag that has no contextPaths and no overview, which makes description-only\n * tags invisible. This listing restores them and tells the reviewer what the\n * glossary is FOR when judging a diff.\n */\nfunction buildReviewTagSection(context?: TaskContext): string[] {\n const assignedIds = new Set(context?.taskTagIds ?? []);\n const assigned = (context?.projectTags ?? []).filter((t) => assignedIds.has(t.id));\n if (assigned.length === 0) return [];\n\n const parts = [`### Card Tags & Domain Context`, `This card carries these project glossary tags:`];\n for (const tag of assigned) parts.push(...formatTagWithContextPaths(tag));\n parts.push(\n ``,\n `A tag's rules and overview define the conventions the code under review must follow. Use them when you judge Pattern Consistency:`,\n `- Read the tag entries that match the files in this diff. The \"Reference Guides\" section of the task brief lists the same tags with a one-line summary of each linked doc.`,\n `- Call get_tag(\"<name>\") for a term's full spec (overview, linked files, hierarchy) when the linked docs are not enough.`,\n `- A change that contradicts a tagged system's documented conventions is a review finding, even when it reads fine on its own.`,\n `- Skip the tags this diff does not touch — do not read them all up front.`,\n `- If the diff changes how a tagged system behaves and the tag's overview is now wrong, say so in your review.`,\n ``,\n );\n return parts;\n}\n\n// oxlint-disable-next-line max-lines-per-function -- prompt construction is a single cohesive block\nfunction buildReviewPrompt(context?: TaskContext): string {\n const parts = [\n `\\n## Mode: Review`,\n `You are in Review mode — performing code review with fix capability.`,\n `- You have full write access — you can audit code, make fixes, push changes, and run tests`,\n `- Safety rules: no destructive operations, use --force-with-lease instead of --force`,\n ``,\n ];\n\n if (context?.isParentTask) {\n parts.push(\n `### Parent Task Review`,\n `You are reviewing and coordinating child tasks.`,\n `- Use \\`list_subtasks\\` to see current child task state and progress.`,\n `- For children in ReviewPR status: review their code quality and merge with \\`approve_and_merge_pr\\`.`,\n `- For children with failing CI: check with \\`get_execution_logs(childTaskId)\\` and escalate if stuck.`,\n `- Fire next child builds with \\`start_child_cloud_build\\` when ready.`,\n `- Create follow-up tasks for issues discovered during review.`,\n ``,\n `### Coordination Workflow`,\n `1. Check child task statuses with \\`list_subtasks\\``,\n `2. Review completed children — check PRs, run tests if needed`,\n `3. Approve and merge passing PRs`,\n `4. Fire builds for children that are ready`,\n `5. Create follow-up tasks for anything out of scope`,\n `6. As children complete, correct their story points with update_subtask (storyPointValue) when the actual work diverged from the estimate — either direction`,\n );\n } else {\n const tagSection = buildReviewTagSection(context);\n const patternConsistency = tagSection.length\n ? `- **Pattern Consistency**: Does the code follow existing patterns in the codebase? Check nearby files AND the card's tag rules/overviews (see \"Card Tags & Domain Context\" below).`\n : `- **Pattern Consistency**: Does the code follow existing patterns in the codebase? Check nearby files.`;\n parts.push(\n `### Code Review Process`,\n `1. Run \\`${baseDiffCommand(context?.baseBranch)}\\` to see all changes in this PR`,\n `2. Read the task plan to understand the intended changes`,\n `3. Explore the surrounding codebase to verify pattern consistency`,\n `4. Review against the criteria below`,\n ``,\n `### Review Criteria`,\n `- **Correctness**: Does the code do what the plan says? Logic errors, off-by-one, race conditions?`,\n patternConsistency,\n `- **Security**: No hardcoded secrets, no injection vulnerabilities, proper input validation at boundaries.`,\n `- **Performance**: No unnecessary loops, no N+1 queries, no blocking in async contexts.`,\n `- **Error Handling**: Appropriate error handling at system boundaries. No swallowed errors.`,\n `- **Test Coverage**: Are new code paths tested? Edge cases covered?`,\n `- **TypeScript Best Practices**: Proper typing (no unnecessary \\`any\\`), correct React patterns, proper async/await.`,\n `- **Naming & Readability**: Clear names, no misleading comments, self-documenting code.`,\n ``,\n `### Fix Capability`,\n `You have full write access. If you find issues:`,\n `- **Small fixes**: Make the fix directly, commit, and push. Then re-review.`,\n `- **Larger issues**: Use \\`request_code_changes\\` to flag them for the team.`,\n `- After pushing fixes, wait for CI to pass before approving.`,\n ``,\n `### Output — You MUST do exactly ONE of:`,\n ``,\n `#### If code passes review (or after you've fixed all issues):`,\n `Use the \\`approve_code_review\\` tool with a brief summary of what looks good.`,\n ``,\n `#### If changes are needed that you cannot fix:`,\n `Use the \\`request_code_changes\\` tool with specific issues:`,\n `- Reference specific files and line numbers`,\n `- Explain what's wrong and suggest fixes`,\n `- Focus on substantive issues, not style nitpicks (linting handles that)`,\n ``,\n `#### Risk level (required on BOTH tools):`,\n `Every verdict MUST include a \\`risk\\` level — judge it by the surface area the change touches:`,\n `- \\`critical\\`: touches critical/foundational surface (auth, billing, data integrity, migrations)`,\n `- \\`high\\`: touches important surface with broad blast radius`,\n `- \\`medium\\`: moderate, contained surface area`,\n `- \\`low\\`: small or isolated change`,\n `The task may already have a risk level set. If your review makes you disagree with it, set the level you believe is correct — you have the authority to override it in either direction.`,\n ``,\n `#### Story points (correct if wrong):`,\n `You can see the full final diff — if the story-point estimate no longer matches the actual size of the work, correct it with update_task_properties (storyPointValue), in either direction. The card should record what the work actually was, not what it looked like at planning time.`,\n ``,\n ...tagSection,\n `### Previous Review Feedback`,\n `If previous review feedback is present in the chat history, verify those specific issues were addressed before raising new concerns.`,\n ``,\n `### Rules`,\n `- Do NOT re-review things CI already validates (formatting, lint rules).`,\n `- Be concise — actionable specifics over general observations.`,\n `- Max 5-7 issues per review. Prioritize the most important ones.`,\n );\n }\n\n return parts.join(\"\\n\");\n}\n","import { HUMAN_PROSE_WRITING_STYLE } from \"@project/shared\";\nimport type { RunnerMode, AgentMode, TaskContext } from \"@project/shared\";\nimport { buildPackRunnerSystemPrompt } from \"./pack-runner-prompt.js\";\nimport { buildModePrompt } from \"./mode-prompt.js\";\n\nfunction formatProjectAgentLine(pa: NonNullable<TaskContext[\"projectAgents\"]>[number]): string {\n const role = pa.role ? `role: ${pa.role}` : \"role: unassigned\";\n const sp =\n pa.storyPoints === null || pa.storyPoints === undefined\n ? \"\"\n : `, story points: ${pa.storyPoints}`;\n return `- ${pa.agent.name} (${role}${sp})`;\n}\n\nfunction buildPmPreamble(context: TaskContext): string[] {\n const parts = [\n `You are an AI project manager helping to plan tasks for the \"${context.title}\" project.`,\n `You are running locally with full access to the repository.`,\n `You can search code (grep, glob), read files, and run shell commands (e.g. git log, git diff). Search to locate relevant code before reading files. You cannot write or edit files.`,\n `\\nEnvironment (ready, no setup required):`,\n `- Repository is cloned at your current working directory.`,\n `- The shell cwd resets between Bash calls — always use absolute paths (or \\`git -C\\`); never spend a tool call on a bare \\`cd\\`.`,\n `- You can read files and run git commands to understand the codebase before writing task plans.`,\n `- To see the state agents will branch off of, fetch the base explicitly and read it — do NOT check it out. The clone is \\`--single-branch\\`, so a bare \\`git fetch\\` does not create \\`origin/<base>\\` and \\`git checkout ${context.baseBranch ?? \"dev\"}\\` can fail outright: run \\`git fetch origin ${context.baseBranch ?? \"dev\"}:refs/remotes/origin/${context.baseBranch ?? \"dev\"}\\`, then inspect with \\`git log origin/${context.baseBranch ?? \"dev\"}\\` / \\`git show origin/${context.baseBranch ?? \"dev\"}:<path>\\`.`,\n `\\nWorkflow:`,\n `- You can draft and iterate on plans in .claude/plans/*.md, but files on disk are NOT synced to the task.`,\n `- Save the plan to the task with update_task_plan — this is the only way the plan is persisted.`,\n `- After saving the plan, call post_to_chat with a short summary for the team (your turn output is NOT posted to chat — they only see what you post), then end your turn. Do NOT attempt to execute the plan yourself.`,\n `- A separate task agent will handle execution after the team reviews and approves your plan.`,\n ];\n if (context.isParentTask) {\n parts.push(\n `\\nYou are the Project Manager for this set of tasks.`,\n `This task has child tasks (subtasks) that are tracked on the board.`,\n `Your role is to coordinate, plan, and manage the subtasks — not to write code directly.`,\n `Use the subtask tools (create_subtask, update_subtask, list_subtasks) to manage work breakdown.`,\n );\n }\n if (context.projectAgents && context.projectAgents.length > 0) {\n parts.push(`\\nProject Agents:`);\n for (const pa of context.projectAgents) {\n parts.push(formatProjectAgentLine(pa));\n }\n }\n return parts;\n}\n\nfunction buildActivePreamble(context: TaskContext, workspaceDir: string): string[] {\n return [\n `You are an AI project manager in ACTIVE mode for the \"${context.title}\" project.`,\n `You have direct coding access to the repository at ${workspaceDir}.`,\n `You can edit files, run tests, and make commits.`,\n `You still have access to all PM tools (subtasks, update_task_plan, chat).`,\n `\\nEnvironment (ready, no setup required):`,\n `- Repository is cloned at your current working directory.`,\n `- You can read, write, and edit files directly.`,\n `- You can run shell commands including git, build tools, and test runners.`,\n `- The shell cwd resets between Bash calls — always use absolute paths (or \\`git -C\\`, \\`bun run --cwd\\`); never spend a tool call on a bare \\`cd\\`.`,\n context.githubBranch ? `- You are working on branch: \\`${context.githubBranch}\\`` : \"\",\n `\\nSafety rules:`,\n `- Stay within the project directory (${workspaceDir}).`,\n `- Do NOT run \\`git push --force\\` or \\`git reset --hard\\`. Use \\`--force-with-lease\\` if needed.`,\n `- Do NOT delete \\`.env\\` files or modify \\`node_modules\\`.`,\n `- Do NOT run destructive commands like \\`rm -rf /\\`.`,\n `\\nWorkflow:`,\n `- You can make code changes, fix bugs, run tests, and commit directly.`,\n `- When done with changes, summarize what you did in your reply.`,\n `- If you toggled into active mode temporarily, mention when you're done so the team can switch you back to planning mode.`,\n ].filter(Boolean);\n}\n\nfunction buildTaskAgentPreamble(context: TaskContext): string[] {\n return [\n `You are an AI agent working on a task for the \"${context.title}\" project.`,\n `You are running inside a Claudespace pod (a Kubernetes container, NOT a GitHub Codespace) with full access to the repository.`,\n `\\nEnvironment — already built and running. These are the facts you would otherwise spend calls discovering:`,\n `- The repo is cloned at your working directory with \\`${context.githubBranch}\\` checked out, dependencies installed, database migrated, git configured, and the dev stack up. Commit and push directly to this branch.`,\n `- The web app is served on port 3050, the API on port 7090.`,\n `- Web is served from a production build, not \\`next dev\\` — your edits do NOT hot-reload. Run \\`bun run web:rebuild\\` (rebuild + restart lands in ~2s) before re-testing a UI change. The API hot-reloads on its own.`,\n `- Browser automation is the Playwright CLI (\\`playwright\\`, pinned 1.62.1), NOT an MCP server — there are no \\`mcp__playwright__*\\` tools here. Only the headless shell is baked, so a launch must name it AND disable the sandbox: \\`chromium.launch({ channel: \"chromium-headless-shell\", args: [\"--no-sandbox\"] })\\`. A bare \\`chromium.launch()\\` FAILS: since playwright 1.49 that resolves to the full browser, which is deliberately not installed (pods have no display and cannot run Chromium's sandbox). Screenshots land wherever you write them — move or delete them before committing.`,\n `- The clone is \\`--single-branch\\`, so a bare \\`git fetch origin <branch>\\` does NOT create \\`origin/<branch>\\`. To reference any other branch, use the explicit refspec: \\`git fetch origin <branch>:refs/remotes/origin/<branch>\\`.`,\n `- The shell cwd resets between Bash calls, and so does every shell variable. A var you export in one call is EMPTY in the next, which silently redirects output to \\`/\\` and loses it. Write literal absolute paths (\\`git -C\\`, \\`bun run --cwd\\`), and \\`mkdir -p\\` a directory in the SAME call as the redirect that writes to it.`,\n `- The \\`gh\\` CLI is available for READ-ONLY PR and CI state (\\`gh pr view\\`, \\`gh pr checks\\`, \\`gh pr diff\\`). Use the mcp__conveyor__* tools for anything that mutates a PR or card.`,\n `- The core mcp__conveyor__* tools are preloaded — call them directly; do NOT spend a ToolSearch call on them. For any tool that IS still deferred (schema not loaded), load ALL the schemas you expect to need in ONE ToolSearch call using fully-qualified names (query \"select:Monitor,mcp__conveyor__<name>\" — bare MCP tool names without the mcp__<server>__ prefix do not match); never guess a deferred tool's parameters.`,\n `Because the environment is already up, do not run installs, builds, database setup, dev-server starts, or exploratory \\`pwd\\`/\\`ls\\` probes to confirm any of the above. Run them only when a specific error demands it.`,\n `\\nWorking rules:`,\n `- Read a file before your first Write/Edit to it, and batch multiple changes to the same file into a single call instead of many sequential edits.`,\n `- To learn what calls a symbol or where it lives, query the prebuilt code graph before grepping: \\`graphify query \"<SymbolName>\"\\` from the repo root. Query a SYMBOL, never a sentence — \\`graphify query \"resolveTaskBaseBranch\"\\` returns the definition plus every call site, while \"how does a task get its base branch\" seeds unrelated start nodes and returns test files and loggers. Don't know the symbol yet? Grep for the name first, then query it: grep finds names, the graph finds relationships. \\`No matching nodes found\\` means \"not in this graph\" (it is prebuilt, so very recent code is absent), NOT \"not in the codebase\" — fall back to \\`git grep\\`. Skip all of this if \\`graphify-out/graph.json\\` is not present.`,\n `- When a build/lint/test run fails, capture its output to a file once and grep the file — never re-run the suite just to re-filter the same output.`,\n `- Waiting on long-running commands: if a gate finishes in under ~2 minutes, run it in the foreground with a timeout. For a longer one, launch it with run_in_background and STOP; a completion notification arrives when it finishes, and the workspace stays awake for as long as background work is outstanding, so a backgrounded gate will not be killed by an idle sleep. For the final pre-PR gate a bounded foreground run (\\`timeout 590 <gate>\\` with Bash \\`timeout: 600000\\`) is still preferred as defense in depth — it survives a pod resume, which a background job does not. Never busy-wait with sleep/pgrep/tail loops, and never re-run the suite to escape a wait that looks stalled.`,\n `\\nGit:`,\n `- Stay on \\`${context.githubBranch}\\` for the whole task: do not check out another branch and do not create one. It was cut from \\`${context.baseBranch}\\`, and PRs target that automatically.`,\n `- If \\`git push\\` is rejected as non-fast-forward, run \\`git push --force-with-lease origin ${context.githubBranch}\\`. This branch is exclusively yours, so force-with-lease is safe.`,\n ];\n}\n\nexport function buildSystemPrompt(\n mode: RunnerMode | undefined,\n context: TaskContext,\n config: { instructions: string; workspaceDir: string; isAuto?: boolean },\n setupLog: string[],\n agentMode?: AgentMode | null,\n): string {\n const isPm = mode === \"pm\";\n const isPmActive = isPm && agentMode === \"building\";\n // RunnerMode \"pack\" is the first-class gate (parent cards on v3 launch with\n // session mode \"pack\" → CONVEYOR_MODE=pack). The pm clause is the legacy\n // gate from the deleted ProjectRunner surface — kept harmless.\n const isPackRunner = mode === \"pack\" || (isPm && !!config.isAuto && !!context.isParentTask);\n\n if (isPackRunner) {\n return buildPackRunnerSystemPrompt(context, config, setupLog);\n }\n\n const parts = isPmActive\n ? buildActivePreamble(context, config.workspaceDir)\n : isPm\n ? buildPmPreamble(context)\n : buildTaskAgentPreamble(context);\n\n if (setupLog.length > 0) {\n parts.push(\n `\\nEnvironment setup log (already executed before you started — proof that setup succeeded):`,\n \"```\",\n ...setupLog,\n \"```\",\n );\n }\n\n if (context.agentInstructions) {\n parts.push(`\\nAgent Instructions:\\n${context.agentInstructions}`);\n }\n if (config.instructions) {\n parts.push(`\\nAdditional Instructions:\\n${config.instructions}`);\n }\n parts.push(\n `\\nYour turn output appears ONLY in the live agent terminal — it is NOT posted to the task chat. The team does NOT see your replies unless you post them.`,\n `Use post_to_chat (omit task_id → your own task's chat) to share meaningful status as you work, a summary when you finish, and any blocker or question you need a human to answer.`,\n `Pass task_id only to message a DIFFERENT task's chat (e.g. a parent task via get_task).`,\n `Use read_task_chat only if you need to re-read earlier messages beyond the chat context above.`,\n `\\nIf a Conveyor tool call fails or reports the MCP server is unavailable/disconnected, this is almost always a transient socket reconnect — simply RETRY the same call and it will succeed once the connection re-establishes. Do NOT stop work, go idle, or treat a tool error as a reason to end your turn. Keep making progress on the code; only post_to_chat to ask for a human if a tool keeps failing across several retries over a sustained period.`,\n `\\n${HUMAN_PROSE_WRITING_STYLE}`,\n );\n if (!isPm || isPmActive) {\n parts.push(\n `Use the mcp__conveyor__create_pull_request tool to open PRs — it automatically stages, commits, and pushes changes before creating the PR. Do NOT use gh CLI or shell commands for PR creation.`,\n );\n }\n\n const modePrompt = buildModePrompt(agentMode, context, mode);\n if (modePrompt) {\n parts.push(modePrompt);\n }\n\n return parts.join(\"\\n\");\n}\n","import {\n PM_CHAT_HISTORY_LIMIT,\n PRE_BUILD_TASK_STATUSES,\n TASK_CHAT_HISTORY_LIMIT,\n parseMentions,\n type RunnerMode,\n type AgentMode,\n type TaskContext,\n} from \"@project/shared\";\nimport { buildChatInstructions } from \"./chat-instructions.js\";\nimport {\n buildReviewHostHoldParts,\n findLastAgentMessageIndex,\n isCodeReviewRun,\n isReviewHostHold,\n messagesAfterCursor,\n relaunchMessageBatch,\n} from \"./relaunch-hold.js\";\nimport { buildPackRunnerInstructions } from \"./pack-runner-prompt.js\";\nimport {\n baseDiffCommand,\n formatChatHistory,\n formatRepoRefs,\n formatReferenceProjects,\n formatProjectObjectives,\n formatRecentRelatedTasks,\n formatIncidents,\n formatTaskFile,\n} from \"./prompt-formatters.js\";\nimport { resolveTagContext } from \"./tag-context-resolver.js\";\nimport { truncatePlanForPrompt } from \"./prompt-truncation.js\";\nimport { buildPmRelaunchParts } from \"./pm-relaunch-instructions.js\";\n\nexport { buildSystemPrompt } from \"./system-prompt.js\";\n\nfunction detectRelaunchScenario(\n context: TaskContext,\n trustChatHistory = false,\n): \"fresh\" | \"idle_relaunch\" | \"feedback_relaunch\" {\n // Cursor is the primary signal: if set, the agent has completed at least\n // one turn on this session, so this is a relaunch.\n if (context.lastSeenMessageId) {\n const newMessages = messagesAfterCursor(context.chatHistory, context.lastSeenMessageId);\n const hasNewUserMessages = newMessages.some((m) => m.role === \"user\");\n return hasNewUserMessages ? \"feedback_relaunch\" : \"idle_relaunch\";\n }\n\n // No cursor — fall back to chat-history heuristics for backward compatibility\n // with sessions that predate the cursor and for PM/Pack Runner agents whose\n // own prior chat messages are themselves a reliable \"prior work\" indicator.\n const lastAgentIdx = findLastAgentMessageIndex(context.chatHistory);\n if (lastAgentIdx === -1) return \"fresh\";\n\n // githubPRUrl signals prior work survived across restarts. claudeSessionId\n // is intentionally NOT consulted here: it persists across crashed sessions\n // and would cause a false \"prior work done\" reading on a fresh relaunch.\n const hasPriorWork = !!context.githubPRUrl || trustChatHistory;\n if (!hasPriorWork) return \"fresh\";\n\n const messagesAfterAgent = context.chatHistory.slice(lastAgentIdx + 1);\n const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === \"user\");\n return hasNewUserMessages ? \"feedback_relaunch\" : \"idle_relaunch\";\n}\n\nfunction buildRelaunchWithSession(\n mode: RunnerMode | undefined,\n context: TaskContext,\n agentMode?: AgentMode | null,\n isAuto?: boolean,\n): string | null {\n const scenario = detectRelaunchScenario(context);\n // Cursor is the authoritative relaunch signal; claudeSessionId is kept as a\n // fallback for sessions predating the cursor. Either proves the agent has\n // completed at least one turn on this session, so a \"relaunch\" prompt —\n // rather than the fresh-start prompt — is appropriate.\n const hasPriorTurn = !!context.lastSeenMessageId || !!context.claudeSessionId;\n if (!hasPriorTurn || scenario === \"fresh\") return null;\n\n const parts: string[] = [];\n const lastAgentIdx = findLastAgentMessageIndex(context.chatHistory);\n const allNew = relaunchMessageBatch(context);\n\n // Chat cards get the same bare conversational instructions on every turn —\n // never the branch/commit/PR relaunch boilerplate below.\n if (agentMode === \"chat\") {\n return buildChatInstructions(context, scenario, allNew).join(\"\\n\");\n }\n\n if (mode !== \"pm\" && isReviewHostHold(context, allNew, isCodeReviewRun(mode, agentMode))) {\n return buildReviewHostHoldParts(\n context,\n allNew.filter((m) => m.role === \"user\"),\n ).join(\"\\n\");\n }\n\n if (mode === \"pm\") {\n parts.push(...buildPmRelaunchParts(context, lastAgentIdx, isAuto, agentMode));\n } else if (scenario === \"feedback_relaunch\") {\n const newMessages = allNew.filter((m) => m.role === \"user\");\n parts.push(\n `You have been relaunched with new feedback.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAddress the requested changes. Do NOT re-investigate the codebase from scratch or write a new plan — review the feedback and implement the changes directly.`,\n `Commit and push your updates.`,\n );\n if (context.githubPRUrl) {\n parts.push(\n `An existing PR is open at ${context.githubPRUrl} — push to the same branch. Do NOT create a new PR.`,\n );\n } else {\n parts.push(\n `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`,\n );\n }\n } else {\n parts.push(\n `You were relaunched but no new instructions have been given since your last run.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `Run \\`git log --oneline -10\\` to review what you already committed.`,\n `Review the current state of the codebase and verify everything is working correctly.`,\n );\n if (agentMode === \"auto\" || agentMode === \"building\" || isAuto) {\n parts.push(\n `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,\n `Do NOT go idle or wait for instructions — you are in auto mode.`,\n );\n } else {\n parts.push(\n `Post a brief status update with post_to_chat (your turn output is NOT shown in chat — post_to_chat is how the team sees it), then wait for further instructions.`,\n );\n }\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n }\n\n return parts.join(\"\\n\");\n}\n\n/** Tag ids deep-linked (`@[tag:id]`) in the card's description/plan. */\nfunction mentionedTagIdsFrom(context: TaskContext): string[] {\n const body = `${context.description ?? \"\"}\\n${context.plan ?? \"\"}`;\n return [\n ...new Set(\n parseMentions(body)\n .filter((token) => token.type === \"tag\")\n .map((token) => token.id),\n ),\n ];\n}\n\nasync function resolveTaskTagContext(\n context: TaskContext,\n runnerMode?: RunnerMode,\n): Promise<string | null> {\n const mentionedTagIds = mentionedTagIdsFrom(context);\n const hasTags = !!context.projectTags?.length && !!context.taskTagIds?.length;\n const hasSubProjectPaths = !!context.subProject?.contextPaths?.length;\n if (!hasTags && !hasSubProjectPaths && mentionedTagIds.length === 0) return null;\n const { injectedSection } = await resolveTagContext(\n context.projectTags,\n context.taskTagIds ?? [],\n context.model,\n context.agentSettings?.betas,\n runnerMode,\n context.subProject ?? null,\n mentionedTagIds,\n );\n return injectedSection || null;\n}\n\n// oxlint-disable-next-line complexity -- simple field mapping, not real branching complexity\nasync function buildTaskBody(context: TaskContext, runnerMode?: RunnerMode): Promise<string[]> {\n const parts: string[] = [];\n parts.push(`# Task: ${context.title}`);\n if (context.projectName) {\n const descLine = context.projectDescription ? `\\n${context.projectDescription}` : \"\";\n parts.push(`\\n## Project: ${context.projectName}${descLine}`);\n }\n if (context.subProject?.rootPath) {\n parts.push(\n `\\n## Sub-project scope: ${context.subProject.name}`,\n `This task belongs to the \"${context.subProject.name}\" sub-project, which owns \\`${context.subProject.rootPath}\\`.`,\n `- Read and reference the whole repository freely.`,\n `- Substantive code changes belong under \\`${context.subProject.rootPath}\\`. Trivial wiring elsewhere (exports, route registration) is fine when required.`,\n `- If the work genuinely requires substantive changes outside that folder, do NOT make them here — create a task on the parent project board (as part of a pack with this one) describing the needed change.`,\n );\n }\n if (context.description) {\n parts.push(`\\n## Description\\n${context.description}`);\n }\n if (context.plan) {\n parts.push(`\\n## Plan\\n${truncatePlanForPrompt(context.plan)}`);\n }\n\n if (context.files && context.files.length > 0) {\n parts.push(`\\n## Attached Files`);\n for (const file of context.files) {\n parts.push(...formatTaskFile(file));\n }\n }\n\n if (context.repoRefs && context.repoRefs.length > 0) {\n parts.push(...formatRepoRefs(context.repoRefs));\n }\n\n if (context.referenceProjects && context.referenceProjects.length > 0) {\n parts.push(...formatReferenceProjects(context.referenceProjects));\n }\n\n const tagSection = await resolveTaskTagContext(context, runnerMode);\n if (tagSection) parts.push(tagSection);\n\n // Project objectives and related tasks help PM planning but are redundant for task agents\n // (task agents already have a plan that incorporates this context)\n if (runnerMode !== \"task\") {\n if (context.projectObjectives && context.projectObjectives.length > 0) {\n parts.push(...formatProjectObjectives(context.projectObjectives));\n }\n if (context.recentRelatedTasks && context.recentRelatedTasks.length > 0) {\n parts.push(...formatRecentRelatedTasks(context.recentRelatedTasks));\n }\n }\n\n if (context.incidents && context.incidents.length > 0) {\n parts.push(...formatIncidents(context.incidents));\n }\n\n if (context.chatHistory.length > 0) {\n const chatLimit = runnerMode === \"task\" ? TASK_CHAT_HISTORY_LIMIT : PM_CHAT_HISTORY_LIMIT;\n parts.push(...formatChatHistory(context.chatHistory, chatLimit));\n }\n\n return parts;\n}\n\n// Code-review runs never reach here — `buildInstructions` routes them to\n// `buildFreshCodeReviewInstructions` ahead of the scenario branching.\nfunction buildFreshInstructions(\n isPm: boolean,\n isAutoMode: boolean,\n context: TaskContext,\n agentMode?: AgentMode | null,\n): string[] {\n // After auto→building transition, agent needs building instructions\n // PM→building only happens through auto mode, so always include anti-idle guidance\n if (isPm && agentMode === \"building\") {\n return [\n `Your plan has been approved. Begin implementing it now.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `Start by reading the relevant source files mentioned in the plan, then write code.`,\n `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`,\n `\\nCRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,\n `Your FIRST action must be reading source files from the plan, then immediately writing code.`,\n `Do NOT summarize the plan or say \"ready to implement\" — start implementing.`,\n `When all changes are ready, use mcp__conveyor__create_pull_request to open a PR.`,\n `If you are genuinely blocked, explain the specific blocker — do not go idle silently.`,\n ];\n }\n if (isAutoMode && isPm) {\n if (context.plan?.trim()) {\n return [\n `You are operating autonomously. A plan already exists for this task.`,\n `Begin implementing it now — do NOT re-plan or wait for team input.`,\n `Refine story points, title, and tags via update_task_properties if they look like placeholders.`,\n ];\n }\n return [\n `You are operating autonomously. No plan is saved on this card yet.`,\n `1. Search the codebase (grep/glob) to locate relevant files, then read the critical ones`,\n `2. Save a concise plan with update_task_plan BEFORE writing any code — the plan is a record for the team, not a gate; never pause or wait for approval`,\n `3. Implement the work, keeping the plan current if your approach changes materially`,\n `4. Refine story points, tags, and title (update_task_properties) if they look like placeholders`,\n `Do NOT wait for team input — proceed autonomously.`,\n ];\n }\n if (isPm && context.isParentTask) {\n return [\n `You are the project manager for this task and its subtasks.`,\n `Review existing subtasks via \\`list_subtasks\\` and the chat history before taking action.`,\n `Read the task description and chat history carefully — the team has provided the initial context below. Acknowledge what they've asked for and respond in chat before taking silent tool actions.`,\n `Start planning now — explore the codebase, ask clarifying questions if needed, and propose a subtask breakdown. Do not wait for additional team input before engaging.`,\n `When you finish planning, save the plan with update_task_plan, post a short summary for the team with post_to_chat (your turn output is NOT shown in chat), then end your turn.`,\n ];\n }\n if (isPm) {\n return [\n `You are the project manager for this task — a thoughtful, collaborative planner, not the implementer.`,\n `Your job right now is to help the team turn this request into a clear, well-scoped plan. Be a helpful planning partner: think out loud, surface trade-offs, and keep the human in the loop.`,\n `Read the task description and chat history carefully — the team has provided the initial context below. Acknowledge what they've asked for and respond in chat before taking silent tool actions.`,\n `Start planning now — explore the codebase, ask clarifying questions if anything is ambiguous, and draft a plan. Do not wait for additional team input before engaging; the initial message IS the team engaging.`,\n `When you finish planning, save the plan with update_task_plan, post a summary of the plan for the team with post_to_chat (your turn output is NOT shown in chat), then end your turn. A separate task agent will execute the plan after review.`,\n ];\n }\n return buildFreshLeafInstructions(context, isAutoMode);\n}\n\nfunction buildFreshLeafInstructions(context: TaskContext, isAutoMode: boolean): string[] {\n const parts = context.plan?.trim()\n ? [`Start now by reading the source files the plan names, then writing code.`]\n : [\n `No plan is saved on this card yet. Investigate the task briefly (search first, read only critical files), then save a concise implementation plan with update_task_plan (file:line citations) BEFORE you start writing code.`,\n `The plan is a step, not the goal: the moment it's posted, IMPLEMENT it in code — do NOT pause, wait for approval, or treat the posted plan as the deliverable. The card is already In Progress and advances automatically.`,\n ];\n // Gate guidance lives in ONE place — the \"Pre-PR Protocol\" section of the\n // building-mode system prompt (`mode-prompt.ts`). This is a pointer, not a\n // second copy: the same ~15 lines injected twice per session read as two\n // separate instructions and invited a second gate pass.\n const base = context.baseBranch?.trim() || \"dev\";\n parts.push(\n `Post to chat when you begin implementing and again when the PR is ready.`,\n `Follow the **Pre-PR Protocol** in your system prompt: commit, then sync the base (\\`git fetch origin ${base} && git merge origin/${base} --no-edit\\`), then ONE verification pass — \\`bun run check\\` (lint + typecheck) plus \\`bun run test:affected\\` (tests scoped to your diff; docs-only changes need no local gates) — then open the PR. Do NOT re-merge the base or re-run a gate that already passed.`,\n `If a gate fails, iterate on just the failing test files (\\`bun run --cwd <pkg> test:unit <files>\\`) and confirm with a single final scoped-gate run. Do NOT open a PR with known failing gates.`,\n `Open the PR with mcp__conveyor__create_pull_request when the work is done and the gates are green.`,\n );\n if (isAutoMode) {\n parts.push(\n `\\nCRITICAL: You are in Auto mode. Your job is to BUILD the change, not to produce a plan — making a plan and opening a PR of the plan is NOT the goal. The plan is only an intermediate step; you must then write the code that implements it.`,\n `Do NOT report status, ask for confirmation, or go idle without making code changes. Do NOT summarize the plan or say \"ready to implement\" — start implementing immediately.`,\n `Your pull request MUST contain the actual code implementation. Never open a plan-only or empty-diff PR. (If the task genuinely needs no code changes, do not open a PR — deliver the result in chat and mark the card Complete.)`,\n `When the implementation is complete and verified, you MUST use mcp__conveyor__create_pull_request to open a PR before finishing.`,\n `If you are genuinely blocked, explain the specific blocker — do not go idle silently.`,\n );\n }\n return parts;\n}\n\nfunction buildFreshCodeReviewInstructions(context: TaskContext): string[] {\n const parts = [\n `Perform the automated code review for this PR.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch for the entire review. Do not checkout or create other branches.`,\n `Start by establishing what you are actually reviewing${context.githubPRUrl ? `: \\`gh pr view ${context.githubPRUrl} --json state,baseRefName,headRefOid,files\\`` : ` — the PR's own base ref, head SHA and changed-file list`}. Do this BEFORE any git diff: the PR's base is often not the project default branch, and asking the PR costs one call instead of six.`,\n `Then inspect the submitted changes with \\`${baseDiffCommand(context.baseBranch)}\\`. If that disagrees with the PR's file list, trust the PR: diff the head SHA directly (\\`git diff <headSha>^ <headSha>\\`) and review that.`,\n `Your checkout can be stale, and so can the remote branch tip — a merged PR's commit may be reachable only by SHA. If the PR reports state MERGED or CLOSED, say so and review the recorded head SHA rather than assuming your working tree matches it.`,\n `Read the code under review out of the PR's commit, NOT the working tree: \\`git show <sha>:<path>\\` and \\`git grep <pattern> <sha>\\`. Grepping the working tree when the PR is based elsewhere returns confident, wrong answers — it has produced false review findings.`,\n `Review for correctness, security, performance, error handling, test coverage, and consistency with existing patterns.`,\n `Consult the card's tag Reference Guides in the brief above for the domain rules that apply to this diff — they are the conventions the change must follow, and a contradiction of them is a review finding.`,\n `If small fixes are needed, make them directly, commit, push, and re-review the result.`,\n `Use approve_code_review when the PR passes review.`,\n `Use request_code_changes when substantive issues remain that you cannot fix directly.`,\n ];\n if (context.githubPRUrl) {\n parts.push(`The PR under review is ${context.githubPRUrl}. Do not create a new PR.`);\n }\n return parts;\n}\n\nfunction buildFeedbackInstructions(\n context: TaskContext,\n isPm: boolean,\n agentMode?: AgentMode | null,\n isAuto?: boolean,\n): string[] {\n const lastAgentIdx = findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === \"user\");\n if (isPm) {\n const parts = [\n `You were relaunched with new feedback since your last run.`,\n `You are the project manager for this task.`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n ];\n if (isAuto && (agentMode === \"building\" || agentMode === \"review\")) {\n parts.push(\n `\\nYour plan has been approved. Address the feedback above, then begin implementing.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `Start by reading the relevant source files mentioned in the plan, then write code.`,\n `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`,\n );\n } else if (isAuto) {\n parts.push(\n `\\nYou are in auto mode. Address the feedback above and continue building — update the saved plan with update_task_plan if the feedback changes your approach.`,\n `Do NOT wait for additional team input — the messages above ARE the team's input. Proceed autonomously.`,\n );\n } else {\n parts.push(\n `\\nReview these messages and wait for the team to provide instructions before taking action.`,\n );\n }\n return parts;\n }\n const parts = [\n `You have been relaunched to address feedback on your previous work.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `Start by running \\`${baseDiffCommand(context.baseBranch, \"--stat\")}\\` to review what you already committed on this branch.`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAddress the requested changes directly. Do NOT re-investigate the codebase from scratch or write a new plan — go straight to implementing the feedback.`,\n // Scoped to what the follow-up actually changed. An unconditional full\n // re-verify on every relaunch made a one-line or docs-only follow-up cost\n // the same gate time as the original build.\n `Re-verify in proportion to what THIS follow-up changed, not the whole branch: a docs/\\`.claude\\`-only change needs no local gates; a code change runs \\`bun run check\\` plus the directly-affected test files (\\`bun run --cwd <pkg> test:unit <files>\\`); escalate to a full \\`bun run test:affected\\` only when the follow-up touched \\`packages/shared\\`, \\`packages/db\\`, or root config, or when no gate has ever run on this branch. Fix any failures before pushing — relaunches are the most common place verification gets skipped.`,\n `Implement your updates and open a PR when finished.`,\n ];\n if (context.githubPRUrl) {\n parts.push(\n `An existing PR is open at ${context.githubPRUrl} — push to the same branch to update it. Do NOT create a new PR.`,\n );\n } else {\n parts.push(\n `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`,\n );\n }\n return parts;\n}\n\nfunction buildIdleRelaunchInstructions(\n context: TaskContext,\n isPm: boolean,\n agentMode?: AgentMode | null,\n isAuto?: boolean,\n): string[] {\n if (isPm && agentMode === \"auto\" && PRE_BUILD_TASK_STATUSES.has(context.status ?? \"\")) {\n if (context.plan?.trim()) {\n return [\n `You were relaunched in auto mode. A plan already exists for this task.`,\n `Begin implementing it now — refine story points, title, and tags via update_task_properties if they look like placeholders.`,\n `Do NOT wait for instructions or go idle — you are in auto mode.`,\n ];\n }\n return [\n `You were relaunched in auto mode. Continue building autonomously.`,\n `No plan is saved on this card yet — save a concise plan with update_task_plan before writing further code; never pause or wait for approval.`,\n `Do NOT wait for instructions or go idle — you are in auto mode.`,\n ];\n }\n\n if (isPm && !(agentMode === \"building\" || agentMode === \"review\" || agentMode === \"auto\")) {\n return [\n `You were relaunched but no new instructions have been given since your last run.`,\n `You are the project manager for this task.`,\n `Wait for the team to provide instructions before taking action.`,\n ];\n }\n\n // Task agent or PM in building/review/auto mode — check agentMode independently\n // of isAuto as defense-in-depth against stale isAuto values.\n const isAutoMode = agentMode === \"auto\" || agentMode === \"building\" || isAuto;\n const parts = [\n `You were relaunched but no new instructions have been given since your last run.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch — do not checkout or create other branches.`,\n `Run \\`git log --oneline -10\\` to review what you already committed, then verify the current state is correct.`,\n ];\n if (isAutoMode) {\n parts.push(\n `If work is incomplete, continue implementing the plan. When finished, use mcp__conveyor__create_pull_request to open a PR.`,\n `Do NOT go idle or wait for instructions — you are in auto mode.`,\n );\n } else {\n parts.push(\n `Post a brief status update summarizing where things stand with post_to_chat (your turn output is NOT shown in chat — post_to_chat is how the team sees it).`,\n `Then wait for further instructions — do NOT redo work that was already completed.`,\n );\n }\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n return parts;\n}\n\nfunction buildInstructions(\n mode: RunnerMode | undefined,\n context: TaskContext,\n scenario: \"fresh\" | \"idle_relaunch\" | \"feedback_relaunch\",\n agentMode?: AgentMode | null,\n isAuto?: boolean,\n): string[] {\n const parts: string[] = [`\\n## Instructions`];\n\n const isPm = mode === \"pm\";\n const isCodeReview = mode === \"code-review\" || (!isPm && agentMode === \"review\");\n\n // Chat cards route ahead of every other shape: a chat card is a conversation\n // first, so it never gets leaf-builder, PM, or review instructions.\n if (agentMode === \"chat\") {\n parts.push(...buildChatInstructions(context, scenario, relaunchMessageBatch(context)));\n return parts;\n }\n\n // A review run's first turn ALWAYS gets reviewer instructions. The scenario\n // detector reads the card's builder chat plus `githubPRUrl` as \"prior work\",\n // so on a real card it routed the reviewer's opening turn to\n // idle/feedback-relaunch builder text (\"continue implementing the plan…\").\n // Resumed review sessions never reach here — they short-circuit in\n // `buildRelaunchWithSession` — and `isReviewHostHold` requires\n // `isCodeReview === false`, so the builder-hold path is untouched. New chat\n // messages still reach the reviewer through the body's chat-history section.\n if (isCodeReview) {\n parts.push(...buildFreshCodeReviewInstructions(context));\n return parts;\n }\n\n if (scenario === \"fresh\") {\n // The mode label is \"building\" once auto resolves at boot, so key the\n // auto-specific instructions off isAuto as well.\n parts.push(\n ...buildFreshInstructions(isPm, agentMode === \"auto\" || !!isAuto, context, agentMode),\n );\n return parts;\n }\n\n // A relaunch on a task whose PR is already under review, with nothing\n // actionable in the new batch, is a review-host wake — hold rather than take\n // an implement turn. Covers both relaunch shapes: a pure host wake arrives as\n // idle_relaunch, and one that coincides with an external worker's chat post\n // arrives as feedback_relaunch.\n const newBatch = relaunchMessageBatch(context);\n if (!isPm && isReviewHostHold(context, newBatch, isCodeReview)) {\n parts.push(\n ...buildReviewHostHoldParts(\n context,\n newBatch.filter((m) => m.role === \"user\"),\n ),\n );\n return parts;\n }\n\n if (scenario === \"idle_relaunch\") {\n parts.push(...buildIdleRelaunchInstructions(context, isPm, agentMode, isAuto));\n return parts;\n }\n\n parts.push(...buildFeedbackInstructions(context, isPm, agentMode, isAuto));\n return parts;\n}\n\nexport async function buildInitialPrompt(\n mode: RunnerMode | undefined,\n context: TaskContext,\n isAuto?: boolean,\n agentMode?: AgentMode | null,\n): Promise<string> {\n // RunnerMode \"pack\" is the first-class gate (see system-prompt.ts); the pm\n // clause is the legacy ProjectRunner gate — kept harmless.\n const isPackRunner = mode === \"pack\" || (mode === \"pm\" && !!isAuto && !!context.isParentTask);\n\n if (!isPackRunner) {\n const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode, isAuto);\n if (sessionRelaunch) return sessionRelaunch;\n }\n\n const isPm = mode === \"pm\";\n let scenario = detectRelaunchScenario(context, isPm);\n\n // After auto-mode transition from planning to building, planning-phase chat\n // history causes \"idle_relaunch\" even though no building work has started.\n // Override to \"fresh\" so the agent gets \"begin implementing\" instructions.\n if (\n isPm &&\n agentMode === \"building\" &&\n isAuto &&\n !context.claudeSessionId &&\n !context.githubPRUrl &&\n scenario === \"idle_relaunch\"\n ) {\n scenario = \"fresh\";\n }\n const body = await buildTaskBody(context, mode);\n const instructions = isPackRunner\n ? buildPackRunnerInstructions(context, scenario)\n : buildInstructions(mode, context, scenario, agentMode, isAuto);\n return [...body, ...instructions].join(\"\\n\");\n}\n","import { z } from \"zod\";\nimport {\n getAttachmentContract,\n getTaskContract,\n listTaskFilesContract,\n readTaskChatContract,\n} from \"@project/shared/tool-contracts\";\nimport { defineTool } from \"../harness/index.js\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult, imageBlock, isImageMimeType, formatCliEvent } from \"./helpers.js\";\n\ntype ContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"image\"; data: string; mimeType: string };\n\nexport function buildReadTaskChatTool(connection: AgentConnection) {\n return defineContractTool(\n readTaskChatContract,\n async ({ limit, task_id }) => {\n try {\n const messages = await connection.call(\"getChatMessages\", {\n sessionId: connection.sessionId,\n limit,\n taskId: task_id,\n });\n return textResult(JSON.stringify(messages, null, 2));\n } catch {\n return textResult(\n JSON.stringify({\n note: \"Could not fetch live chat. Chat history was provided in the initial context.\",\n }),\n );\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildGetCurrentPlanTool(connection: AgentConnection) {\n return defineTool(\n \"get_current_plan\",\n \"Re-read the current task's plan. Use when the user updated the plan or asked you to re-read it — otherwise the plan is already in initial context. For task metadata use get_task.\",\n {},\n async () => {\n try {\n const ctx = await connection.call(\"getTaskContext\", {\n sessionId: connection.sessionId,\n });\n return textResult(ctx.plan ?? \"No plan available.\");\n } catch {\n return textResult(\"Could not fetch updated plan.\");\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildGetTaskTool(connection: AgentConnection) {\n return defineContractTool(\n getTaskContract,\n async ({ slug_or_id }) => {\n try {\n const task = await connection.call(\"getTask\", {\n sessionId: connection.sessionId,\n taskSlugOrId: slug_or_id,\n });\n return textResult(JSON.stringify(task, null, 2));\n } catch (error) {\n return textResult(\n `Failed to get task: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildGetExecutionLogsTool(connection: AgentConnection) {\n return defineTool(\n \"get_execution_logs\",\n \"Read CLI execution logs — agent reasoning, tool calls, and setup/dev-server output. Filter via source='agent' or 'application'. For human chat use read_task_chat.\",\n {\n task_id: z\n .string()\n .optional()\n .describe(\n \"Task ID or slug. Omit to read logs from the current task. Only the current task or one of its child tasks can be read.\",\n ),\n source: z\n .enum([\"agent\", \"application\"])\n .optional()\n .describe(\"Filter by log source. Omit for all logs.\"),\n limit: z\n .number()\n .optional()\n .describe(\"Max number of log entries to return (default 50, max 500).\"),\n },\n async ({ task_id, source, limit }) => {\n try {\n const effectiveLimit = Math.min(limit ?? 50, 500);\n const result = await connection.call(\"getCliHistory\", {\n sessionId: connection.sessionId,\n limit: effectiveLimit,\n taskId: task_id,\n source,\n });\n const formatted = (result as Array<Record<string, unknown>>)\n .map((entry) => {\n const type = entry.type as string;\n const time = entry.timestamp as string;\n return `[${time}] [${type}] ${formatCliEvent(entry as Record<string, unknown>)}`;\n })\n .join(\"\\n\");\n return textResult(formatted || \"No CLI logs found.\");\n } catch (error) {\n return textResult(\n `Failed to fetch CLI logs: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildListTaskFilesTool(connection: AgentConnection) {\n return defineContractTool(\n listTaskFilesContract,\n async () => {\n try {\n const files = await connection.call(\"getTaskFiles\", {\n sessionId: connection.sessionId,\n });\n const metadata = files.map((file) => {\n const { content: _c, ...rest } = file;\n return rest;\n });\n const content: ContentBlock[] = [\n { type: \"text\" as const, text: JSON.stringify(metadata, null, 2) },\n ];\n for (const file of files) {\n if (file.content && file.contentEncoding === \"base64\" && isImageMimeType(file.mimeType)) {\n content.push(imageBlock(file.content, file.mimeType));\n }\n }\n return { content };\n } catch {\n return textResult(\"Failed to list task files.\");\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildGetAttachmentTool(connection: AgentConnection) {\n return defineContractTool(\n getAttachmentContract,\n async ({ fileId }) => {\n try {\n const file = await connection.call(\"getTaskFile\", {\n sessionId: connection.sessionId,\n fileId,\n });\n const { content: rawContent, ...metadata } = file;\n const content: ContentBlock[] = [\n { type: \"text\" as const, text: JSON.stringify(metadata, null, 2) },\n ];\n if (rawContent && file.contentEncoding === \"base64\" && isImageMimeType(file.mimeType)) {\n content.push(imageBlock(rawContent, file.mimeType));\n } else if (rawContent) {\n content[0] = { type: \"text\" as const, text: JSON.stringify(file, null, 2) };\n }\n return { content };\n } catch (error) {\n return textResult(\n `Failed to get task file: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\n/** All read-only task context tools. */\nexport function buildTaskContextTools(connection: AgentConnection) {\n return [\n buildReadTaskChatTool(connection),\n buildGetCurrentPlanTool(connection),\n buildGetTaskTool(connection),\n buildGetExecutionLogsTool(connection),\n buildListTaskFilesTool(connection),\n buildGetAttachmentTool(connection),\n ];\n}\n","import {\n CARD_DESCRIPTION_FIELD_HINT,\n CARD_DESCRIPTION_LIMIT_MESSAGE,\n CARD_DESCRIPTION_MAX\n} from \"../chunk-6RHVH33O.js\";\n\n// src/tool-contracts/spec.ts\nvar f = {\n string(opts) {\n return { kind: \"string\", ...opts };\n },\n number(opts) {\n return { kind: \"number\", ...opts };\n },\n boolean(opts) {\n return { kind: \"boolean\", ...opts };\n },\n enum(values, opts) {\n return { kind: \"enum\", values, ...opts };\n },\n array(item, opts) {\n return { kind: \"array\", item, ...opts };\n },\n object(fields, opts) {\n return { kind: \"object\", fields, ...opts };\n },\n optional(inner) {\n return { kind: \"optional\", inner };\n },\n nullable(inner) {\n return { kind: \"nullable\", inner };\n }\n};\n\n// src/tool-contracts/compile.ts\nfunction compileString(z, spec) {\n let schema = z.string();\n if (spec.min !== void 0) schema = schema.min(spec.min);\n if (spec.max !== void 0) schema = schema.max(spec.max);\n return schema;\n}\nfunction compileNumber(z, spec) {\n let schema = z.number();\n if (spec.int) schema = schema.int();\n if (spec.positive) schema = schema.positive();\n if (spec.nonnegative) schema = schema.nonnegative();\n if (spec.min !== void 0) schema = schema.min(spec.min);\n if (spec.max !== void 0) schema = schema.max(spec.max);\n return schema;\n}\nfunction compileArray(z, spec) {\n let schema = z.array(compileField(z, spec.item));\n if (spec.min !== void 0) schema = schema.min(spec.min);\n return schema;\n}\nfunction compileBase(z, spec) {\n switch (spec.kind) {\n case \"string\":\n return compileString(z, spec);\n case \"number\":\n return compileNumber(z, spec);\n case \"boolean\":\n return z.boolean();\n case \"enum\":\n return z.enum([...spec.values]);\n case \"array\":\n return compileArray(z, spec);\n case \"object\":\n return z.object(compileShape(z, spec.fields));\n }\n}\nfunction compileField(z, spec) {\n if (spec.kind === \"optional\") {\n return compileField(z, spec.inner).optional();\n }\n if (spec.kind === \"nullable\") {\n return compileField(z, spec.inner).nullable();\n }\n const schema = compileBase(z, spec);\n return spec.desc === void 0 ? schema : schema.describe(spec.desc);\n}\nfunction compileShape(z, fields) {\n const shape = {};\n for (const [key, spec] of Object.entries(fields)) {\n shape[key] = compileField(z, spec);\n }\n return shape;\n}\n\n// src/tool-contracts/contract.ts\nfunction defineToolContract(contract) {\n return contract;\n}\n\n// src/tool-contracts/fields.ts\nvar mcpProjectId = f.optional(f.string({ desc: \"Target Conveyor project ID\" }));\nvar cardDescriptionDesc = (lead) => `${lead} \\u2014 ${CARD_DESCRIPTION_FIELD_HINT}`;\nvar storyPointValueDesc = \"Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)\";\n\n// src/tool-contracts/tasks.ts\nvar getTaskContract = defineToolContract({\n name: \"get_task\",\n agent: {\n description: \"Look up any task by slug or ID. Returns JSON with id, slug, title, description, plan, status, branch, githubPRNumber, githubPRUrl, storyPoints. For children use list_subtasks.\",\n fields: {\n slug_or_id: f.string({ desc: \"The task slug (e.g. 'my-task') or CUID\" })\n }\n },\n mcp: {\n description: \"Get full task details including plan, chat history, PR info, subtasks, and build status. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({\n desc: \"The task ID or slug (the value in a card URL, /cards/<slug>)\"\n })\n }\n }\n});\nvar postToChatContract = defineToolContract({\n name: \"post_to_chat\",\n agent: {\n description: \"Post a message to the task chat for the team to see. Your turn output is NOT shown in chat, so this is the only way the team sees your status, summaries, and questions. Omit task_id to post to the current task's chat; pass a child's ID to message its chat.\",\n fields: {\n message: f.optional(f.string({ desc: \"The message to post to the team\" })),\n content: f.optional(\n f.string({\n desc: \"Alias of `message` (the external conveyor-mcp surface names this field `content`). Provide exactly one of the two.\"\n })\n ),\n task_id: f.optional(\n f.string({\n desc: \"Child task ID to post to. Omit to post to the current task's chat.\"\n })\n ),\n milestone: f.optional(\n f.enum([\"plan_ready\", \"implementation_complete\", \"blocked\"], {\n desc: \"Declare a narrative milestone instead of a routine update. Use SPARINGLY \\u2014 only when the plan is ready, implementation is complete, or you are blocked. Milestones appear on the card's activity timeline and in Slack.\"\n })\n )\n }\n },\n mcp: {\n description: \"Post a message to a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID\" }),\n content: f.optional(f.string({ desc: \"Message content\" })),\n message: f.optional(\n f.string({\n desc: \"Alias of `content` (the in-pod agent surface names this field `message`). Provide exactly one of the two.\"\n })\n )\n }\n }\n});\nvar readTaskChatContract = defineToolContract({\n name: \"read_task_chat\",\n agent: {\n description: \"Read recent human/user chat messages for a task. Omit task_id for the current task; pass a child ID for a child's chat. For agent logs use get_execution_logs.\",\n fields: {\n limit: f.optional(f.number({ desc: \"Number of recent messages to fetch (default 20)\" })),\n task_id: f.optional(\n f.string({\n desc: \"Child task ID to read chat from. Omit to read the current task's chat.\"\n })\n )\n }\n },\n mcp: {\n description: \"Read messages from a task's chat. Pass projectId to target a specific project; otherwise the configured default project is used. For agent execution logs use get_task_logs.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID\" }),\n limit: f.optional(f.number({ desc: \"Max messages to return (default 50)\" }))\n }\n }\n});\nvar listTagsContract = defineToolContract({\n name: \"list_tags\",\n agent: {\n description: \"List the project glossary: every tag's id, name, color, description, parent/child tag ids, its contextPaths (the rule/doc/file/folder links it wires into agent context \\u2014 `[]` means none), whether it carries a full overview (fetch that with get_tag), and its attachmentCount (files labelled as examples of the term). The context links ship inline, so you only need get_tag for a term's full overview. Use the ids with get_tag / update_tag.\",\n fields: {}\n },\n mcp: {\n description: \"List all project tags with names, IDs, colors, descriptions, hierarchy (parent/child ids), contextPaths (the rule/doc/file/folder links each tag wires into agent context \\u2014 `[]` means none), a hasOverview flag, and an attachmentCount (files labelled as examples of the term \\u2014 read the tiles with list_tag_attachments). Context links ship inline; call get_tag only for a term's full overview. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId\n }\n }\n});\nvar SEARCH_STATUSES = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\"\n];\nvar SEARCH_CARD_TYPES = [\"task\", \"incident\", \"suggestion\"];\nvar searchFilterFields = {\n tagNames: f.optional(\n f.array(f.string(), {\n desc: 'Tag names to filter by, e.g. [\"agent\", \"mcp\"]. Names, not ids, and matched case-insensitively. Use list_tags to see the glossary.'\n })\n ),\n tagMatch: f.optional(\n f.enum([\"any\", \"all\"], {\n desc: 'How to combine tagNames: \"any\" (default) returns cards carrying at least one, \"all\" returns only cards carrying every one.'\n })\n ),\n includeChildTags: f.optional(\n f.boolean({\n desc: \"Also match cards carrying any descendant of the named tags in the tag hierarchy. Use this to sweep a whole area from its parent tag, e.g. cloud-build also matching release and deployment. Default false.\"\n })\n ),\n searchQuery: f.optional(f.string({ desc: \"Text search on title and description\" })),\n statusFilters: f.optional(\n f.array(f.enum(SEARCH_STATUSES), { desc: \"Filter by one or more statuses\" })\n ),\n typeFilters: f.optional(\n f.array(f.enum(SEARCH_CARD_TYPES), {\n desc: 'Card types to include (default [\"task\"]). Pass e.g. [\"incident\"] or list several to search across types.'\n })\n ),\n assigneeId: f.optional(f.string({ desc: \"Filter by assigned user ID\" })),\n unassigned: f.optional(\n f.boolean({\n desc: \"Only return cards with no assignee (mutually exclusive with assigneeId)\"\n })\n ),\n limit: f.optional(f.number({ desc: \"Max results to return (default 20)\" }))\n};\nvar searchResultNote = \"Every result lists the tags it carries, so you can see why it matched. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \\u2014 plan omitted, description truncated; use get_task for full details.\";\nvar searchTasksContract = defineToolContract({\n name: \"search_tasks\",\n agent: {\n description: `Search this project's cards by tag, text, status, type, and/or assignment. Tags are the project's glossary, so tagNames is the fastest way to find prior work in the area you are touching \\u2014 e.g. every ReviewPR card tagged \"mcp\". Searches the whole project, not just the current card. Defaults to type=task \\u2014 pass typeFilters for incidents/suggestions. ${searchResultNote}`,\n fields: searchFilterFields\n },\n mcp: {\n description: `Search cards by tag name, text query, status, type, and/or assignment. Defaults to type=task \\u2014 pass typeFilters to include incidents/suggestions. Pass projectId to target a specific project; otherwise the configured default project is used. Use tag names like 'agent-runner', not IDs. ${searchResultNote}`,\n fields: {\n projectId: mcpProjectId,\n ...searchFilterFields,\n subProjectId: f.optional(\n f.nullable(\n f.string({\n desc: \"Filter to a sub-project board. Omit to use the connection's default board (CONVEYOR_SUBPROJECT_ID) when set, else the whole project; pass null to force the whole project. Use list_accessible_subprojects to find board IDs.\"\n })\n )\n )\n }\n }\n});\nvar childTaskIdForMerge = f.string({\n desc: \"The child task ID whose PR should be approved and merged\"\n});\nvar approveAndMergePrContract = defineToolContract({\n name: \"approve_and_merge_pr\",\n agent: {\n description: \"Approve and merge a child task's PR. Preconditions: child in ReviewPR. Returns { merged }: true = merged (status\\u2192ReviewDev); false = automerge queued, wait for ReviewDev. Requires project Admin, or a sub-project merge grant covering every changed file; release PRs require Admin.\",\n fields: {\n childTaskId: childTaskIdForMerge\n }\n },\n mcp: {\n description: \"Approve a child task's pull request and QUEUE it for merge \\u2014 the merge lands asynchronously (~30s sweep) once the CI and code-review gates pass; the response says whether it merged or was queued, so verify PR state before depending on it. Pass projectId to target a specific project; otherwise the configured default project is used. The child task must be in ReviewPR status with a PR. Requires project Admin, or a sub-project merge grant covering every changed file; release PRs require Admin.\",\n fields: {\n projectId: mcpProjectId,\n childTaskId: childTaskIdForMerge\n }\n }\n});\nvar tasksContracts = [\n getTaskContract,\n postToChatContract,\n readTaskChatContract,\n listTagsContract,\n searchTasksContract,\n approveAndMergePrContract\n];\n\n// src/tool-contracts/tags.ts\nvar tagRef = f.string({\n desc: \"Tag id, or the exact tag name (case-insensitive)\",\n min: 1,\n max: 100\n});\nvar getTagContract = defineToolContract({\n name: \"get_tag\",\n agent: {\n description: \"Read one tag's full glossary entry: description, the full markdown overview (the term's spec \\u2014 philosophy, mechanics, invariants), linked files/rules (each with its verified-link status \\u2014 ok/stale/unchecked \\u2014 from the periodic repo check), parent/child tags, active-card count, attachment count (files labelled as examples of the term), and recent revisions with their reasons. Call this whenever a chat message, plan, or tag list points at a term you need the full context for. A response with `overviewPath` set means the overview is sourced from that repo file \\u2014 prefer Reading the path from your checkout (branch-correct); the served overview is materialized from the project's dev branch (the PR base; default branch when the repo has no dev branch) (`overviewSource.state`: ok/pending/stale).\",\n fields: {\n tag: tagRef\n }\n },\n mcp: {\n description: \"Read one tag's full glossary entry \\u2014 description, markdown overview, context links (each with its verified-link status: ok/stale/unchecked plus last-checked provenance), parent/child tags, active-card count, attachment count (files labelled as examples of the term \\u2014 read the tiles with list_tag_attachments), and recent revisions with provenance. A response with `overviewPath` set means the overview is sourced from that repo file at the project's dev branch (the PR base; default branch when the repo has no dev branch) (`overviewSource.state`: ok/pending/stale) \\u2014 clients with a checkout can read the path directly for the branch-correct copy. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId,\n tag: tagRef\n }\n }\n});\nvar tagsContracts = [getTagContract];\n\n// src/tool-contracts/checklists.ts\nvar mcpChecklistTaskId = f.string({ desc: \"The task ID or slug\" });\nvar testStatuses = f.optional(\n f.array(f.enum([\"open\", \"approved\", \"rejected\"]), {\n desc: \"Filter tests by status: open | approved | rejected\"\n })\n);\nvar setManualTestItems = f.array(\n f.object({ title: f.string({ min: 1, desc: \"A concise, actionable test step\" }) }),\n { min: 1, desc: \"List of manual test steps to add\" }\n);\nvar titleToEdit = f.string({ min: 1, desc: \"The current title of the manual test to edit\" });\nvar newTitle = f.string({ min: 1, desc: \"The new title for the manual test\" });\nvar titleToRemove = f.string({ min: 1, desc: \"The title of the manual test to remove\" });\nvar titleToApprove = f.string({ min: 1, desc: \"The title of the manual test to approve\" });\nvar titleToReject = f.string({ min: 1, desc: \"The title of the manual test to reject\" });\nvar rejectReason = f.string({\n min: 1,\n max: 2e3,\n desc: \"Why the test failed \\u2014 what went wrong, shown to the team\"\n});\nvar listManualTestsContract = defineToolContract({\n name: \"list_manual_tests\",\n agent: {\n description: \"List the manual test checklist items for the current task. Use to see what manual verification steps have already been recorded.\",\n fields: {}\n },\n mcp: {\n description: \"List the manual test checklist items for a task. Pass projectId to target a specific project; otherwise the configured default project is used. Use to see what manual verification steps have already been recorded.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID or slug (the value in a card URL, /cards/<slug>)\" })\n }\n }\n});\nvar queryManualTestsContract = defineToolContract({\n name: \"query_manual_tests\",\n agent: {\n description: \"Query manual tests across many tasks in this project, grouped by task. Filter by card status (ReviewDev, ReviewLive, Complete, ...) and/or test status (open | approved | rejected). Use to answer 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards.\",\n fields: {\n cardStatuses: f.optional(\n f.array(f.string(), {\n desc: 'Filter tasks by card status, e.g. [\"ReviewDev\", \"ReviewLive\"]'\n })\n ),\n testStatuses\n }\n },\n mcp: {\n description: \"Query manual tests across many tasks in a project, grouped by task. Filter by card status (e.g. ReviewDev, ReviewLive, Complete) and/or test status (open | approved | rejected). Use to answer questions like 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests in ReviewDev/ReviewLive with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId,\n cardStatuses: f.optional(\n f.array(f.string(), {\n desc: 'Filter tasks by card/column status, e.g. [\"ReviewDev\", \"ReviewLive\"]'\n })\n ),\n testStatuses\n }\n }\n});\nvar setManualTestsContract = defineToolContract({\n name: \"set_manual_tests\",\n agent: {\n description: \"Add manual test steps to the task checklist. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing this PR.\",\n fields: {\n items: setManualTestItems\n }\n },\n mcp: {\n description: \"Add manual test steps to a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing the task's PR.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpChecklistTaskId,\n items: setManualTestItems\n }\n }\n});\nvar editManualTestContract = defineToolContract({\n name: \"edit_manual_test\",\n agent: {\n description: \"Rename an existing manual test step. Identify the test by its current title (case-insensitive); pass the new title to replace it. Use to correct or refine a recorded manual verification step.\",\n fields: {\n title: titleToEdit,\n newTitle\n }\n },\n mcp: {\n description: \"Rename an existing manual test step on a task. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its current title (case-insensitive) and pass the new title to replace it.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpChecklistTaskId,\n title: titleToEdit,\n newTitle\n }\n }\n});\nvar removeManualTestContract = defineToolContract({\n name: \"remove_manual_test\",\n agent: {\n description: \"Remove an existing manual test step from the task checklist. Identify the test by its title (case-insensitive). Use to delete a stale or incorrect manual verification step.\",\n fields: {\n title: titleToRemove\n }\n },\n mcp: {\n description: \"Remove an existing manual test step from a task's checklist. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive).\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpChecklistTaskId,\n title: titleToRemove\n }\n }\n});\nvar approveManualTestContract = defineToolContract({\n name: \"approve_manual_test\",\n agent: {\n description: \"Sign off on (approve) a manual test step on behalf of your authenticated user. Identify the test by its title (case-insensitive). Use after you have verified the step passes.\",\n fields: {\n title: titleToApprove\n }\n },\n mcp: {\n description: \"Sign off on (approve) a manual test step on a task on behalf of your authenticated user. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use after you have verified the step passes.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpChecklistTaskId,\n title: titleToApprove\n }\n }\n});\nvar rejectManualTestContract = defineToolContract({\n name: \"reject_manual_test\",\n agent: {\n description: \"Flag an issue with (reject) a manual test step on behalf of your authenticated user, recording the reason. Identify the test by its title (case-insensitive). Use when the step fails verification.\",\n fields: {\n title: titleToReject,\n reason: rejectReason\n }\n },\n mcp: {\n description: \"Flag an issue with (reject) a manual test step on a task on behalf of your authenticated user, recording the reason. Pass projectId to target a specific project; otherwise the configured default project is used. Identify the test by its title (case-insensitive). Use when the step fails verification.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpChecklistTaskId,\n title: titleToReject,\n reason: rejectReason\n }\n }\n});\nvar checklistContracts = [\n listManualTestsContract,\n queryManualTestsContract,\n setManualTestsContract,\n editManualTestContract,\n removeManualTestContract,\n approveManualTestContract,\n rejectManualTestContract\n];\n\n// src/tool-contracts/dependencies.ts\nvar getDependenciesContract = defineToolContract({\n name: \"get_dependencies\",\n agent: {\n description: \"Get this task's dependencies and their met/unmet status (met = merged to dev). Use to confirm blockers merged, or see why a task cannot start. For task state use get_task.\",\n fields: {}\n },\n mcp: {\n description: \"Get a task's dependencies and their met/unmet status (met = merged to dev). Pass projectId to target a specific project; otherwise the configured default project is used. Use to confirm blockers merged, or see why a task cannot start. For task state use get_task.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID\" })\n }\n }\n});\nvar addDependencyContract = defineToolContract({\n name: \"add_dependency\",\n agent: {\n description: \"Add a blocking dependency \\u2014 this task cannot start until the named task is merged to dev. For post-task follow-ups use create_follow_up_task instead.\",\n fields: {\n depends_on_slug_or_id: f.string({ desc: \"Slug or ID of the task this task depends on\" })\n }\n },\n mcp: {\n description: \"Add a blocking dependency \\u2014 this task cannot start until the named task is merged to dev. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID that will be blocked\" }),\n dependsOnSlugOrId: f.string({ desc: \"Slug or ID of the task this one depends on\" })\n }\n }\n});\nvar removeDependencyContract = defineToolContract({\n name: \"remove_dependency\",\n agent: {\n description: \"Remove a previously added dependency from this task. When to use: the dependency was added in error or is no longer relevant. Returns: confirmation string.\",\n fields: {\n depends_on_slug_or_id: f.string({ desc: \"Slug or ID of the task to remove as dependency\" })\n }\n },\n mcp: {\n description: \"Remove a previously added dependency from a task. Pass projectId to target a specific project; otherwise the configured default project is used. The task is no longer blocked by the named task. Returns: confirmation string.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID to unblock\" }),\n dependsOnSlugOrId: f.string({ desc: \"Slug or ID of the dependency to remove\" })\n }\n }\n});\nvar dependenciesContracts = [\n getDependenciesContract,\n addDependencyContract,\n removeDependencyContract\n];\n\n// src/tool-contracts/subtasks.ts\nvar SP_DESCRIPTION = storyPointValueDesc;\nvar AGENT_FOLLOW_PARENT_STATUS = \"Child mirrors the parent task's status automatically \\u2014 for subtasks that ship on the parent's branch/PR with no build or PR of their own. Manual status writes on a follower stick only until the parent's next transition.\";\nvar MCP_FOLLOW_PARENT_STATUS = \"When true, this subtask mirrors the parent task's status automatically \\u2014 for children that ship on the parent's branch/PR and have no build or PR of their own. Manual status writes on a follower stick only until the parent's next transition.\";\nvar AGENT_DEPENDS_ON = \"Sibling subtask ids or slugs this subtask blocks on (it won't start until they merge to dev). Set explicit dependency metadata here instead of describing order in the plan text \\u2014 the pack runner schedules children off these edges. Omit / leave empty for independent children so they run in parallel.\";\nvar MCP_STATUS_ENUM = [\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\"\n];\nvar AGENT_TAGS = `Glossary tag names to label the child with, e.g. [\"agent\", \"pack\"]. Names, not ids, matched case-insensitively against this project's tags (use list_tags to see them). A name that matches nothing comes back in the result and never fails the create.`;\nvar createSubtaskContract = defineToolContract({\n name: \"create_subtask\",\n agent: {\n description: \"Create a subtask (a child card) under the CURRENT card. This is how a card becomes a pack: the first child turns this card into the pack parent, and the children build as one unit. Use when breaking the current card into smaller pieces during planning. For a sibling card that lands after this one merges, use create_follow_up_task.\",\n fields: {\n title: f.string({ desc: \"Subtask title\" }),\n description: f.optional(f.string({ desc: cardDescriptionDesc(\"Brief description\") })),\n plan: f.optional(f.string({ desc: \"Implementation plan in markdown\" })),\n ordinal: f.optional(f.number({ desc: \"Step/order number (0-based)\" })),\n storyPointValue: f.optional(f.number({ desc: SP_DESCRIPTION })),\n followParentStatus: f.optional(f.boolean({ desc: AGENT_FOLLOW_PARENT_STATUS })),\n dependsOn: f.optional(f.array(f.string(), { desc: AGENT_DEPENDS_ON })),\n tags: f.optional(f.array(f.string(), { desc: AGENT_TAGS }))\n }\n },\n mcp: {\n description: \"Create a subtask under a parent task. Pass projectId to target a specific project; otherwise the configured default project is used. Subtasks break a larger task into independently buildable pieces. For children that instead ship on the parent's own branch/PR (e.g. per-theme tracking cards for one bundled PR), set followParentStatus so their status rides the parent's automatically.\",\n fields: {\n projectId: mcpProjectId,\n parentTaskId: f.string({ desc: \"The parent task ID\" }),\n title: f.string({ desc: \"Subtask title\" }),\n description: f.optional(f.string({ desc: cardDescriptionDesc(\"Subtask description\") })),\n plan: f.optional(f.string({ desc: \"Subtask implementation plan (markdown)\" })),\n ordinal: f.optional(f.number({ desc: \"Ordering position among siblings\" })),\n storyPointValue: f.optional(f.number({ desc: SP_DESCRIPTION })),\n followParentStatus: f.optional(f.boolean({ desc: MCP_FOLLOW_PARENT_STATUS })),\n dependsOn: f.optional(\n f.array(f.string(), {\n desc: \"Sibling subtask ids or slugs this subtask blocks on (it won't start until they merge to dev). Set explicit dependency metadata here instead of describing order in the plan text. Omit / leave empty for independent children so they run in parallel.\"\n })\n ),\n tags: f.optional(\n f.array(f.string(), {\n desc: 'Tag names to assign to the subtask (e.g. [\"refactor\"]). Unknown names are rejected \\u2014 create the tag first with manage_tags. Use list_tags to see available tags.'\n })\n )\n }\n }\n});\nvar updateSubtaskContract = defineToolContract({\n name: \"update_subtask\",\n agent: {\n description: \"Update an existing subtask's fields (title, description, plan, ordinal, storyPointValue, dependsOn) \\u2014 and the sanctioned path to make a child buildable: promote it to status Open, assign its agent (agentIdOrName), and set story points. Setting story points does NOT auto-promote; set status explicitly. For the current task use update_task_plan.\",\n fields: {\n subtaskId: f.string({ desc: \"The subtask ID to update\" }),\n title: f.optional(f.string()),\n description: f.optional(f.string({ desc: cardDescriptionDesc(\"New description\") })),\n plan: f.optional(f.string()),\n status: f.optional(\n f.enum([\"Planning\", \"Open\"], {\n desc: 'Move the child between \"Planning\" and \"Open\". \"Open\" marks it ready to execute \\u2014 required before start_child_cloud_build. Execution statuses transition automatically.'\n })\n ),\n agentIdOrName: f.optional(\n f.string({\n desc: \"Assign a project agent to the child (agent id or exact name from the Project Agents list). Required before start_child_cloud_build.\"\n })\n ),\n ordinal: f.optional(f.number()),\n storyPointValue: f.optional(f.number({ desc: SP_DESCRIPTION })),\n followParentStatus: f.optional(f.boolean({ desc: AGENT_FOLLOW_PARENT_STATUS })),\n dependsOn: f.optional(\n f.array(f.string(), {\n desc: `${AGENT_DEPENDS_ON} Replaces the full dependency set \\u2014 pass [] to clear all, omit to leave unchanged.`\n })\n )\n }\n },\n mcp: {\n description: \"Update a subtask's fields: title, description, plan, status, ordering, story points, or dependencies. Pass projectId to target a specific project; otherwise the configured default project is used. Moving a subtask beyond Planning auto-fills missing story points and agent assignment \\u2014 don't spend turns on them.\",\n fields: {\n projectId: mcpProjectId,\n subtaskId: f.string({ desc: \"The subtask ID\" }),\n title: f.optional(f.string({ desc: \"New title\" })),\n description: f.optional(f.string({ desc: cardDescriptionDesc(\"New description\") })),\n plan: f.optional(f.string({ desc: \"New plan (markdown)\" })),\n status: f.optional(f.enum(MCP_STATUS_ENUM, { desc: \"New status\" })),\n ordinal: f.optional(f.number({ desc: \"New ordering position among siblings\" })),\n storyPointValue: f.optional(f.number({ desc: SP_DESCRIPTION })),\n followParentStatus: f.optional(f.boolean({ desc: MCP_FOLLOW_PARENT_STATUS })),\n dependsOn: f.optional(\n f.array(f.string(), {\n desc: \"Replace the sibling subtask ids/slugs this subtask blocks on (pass [] to clear). Omit to leave dependencies unchanged.\"\n })\n )\n }\n }\n});\nvar deleteSubtaskContract = defineToolContract({\n name: \"delete_subtask\",\n agent: {\n description: \"Delete a subtask by id. When to use: a subtask was created in error or is no longer needed. Returns: confirmation string.\",\n fields: {\n subtaskId: f.string({ desc: \"The subtask ID to delete\" })\n }\n },\n mcp: {\n description: \"Delete a subtask by ID. Pass projectId to target a specific project; otherwise the configured default project is used. This is permanent \\u2014 use update_subtask to set status to Cancelled if you only want to close it.\",\n fields: {\n projectId: mcpProjectId,\n subtaskId: f.string({ desc: \"The subtask ID to delete\" })\n }\n }\n});\nvar listSubtasksContract = defineToolContract({\n name: \"list_subtasks\",\n agent: {\n description: \"List all subtasks under the current parent task. Default compact view returns per child: status, agent, story points, PR number/state, dependencies, and holdsBuildSlot \\u2014 plus packSlots (in-flight environments vs the PACK_CHILD_LIMIT cap, and which children hold the slots). Use to coordinate child work; pass verbose:true only when you need full description/plan text (large). For non-child tasks use get_task.\",\n fields: {\n verbose: f.optional(\n f.boolean({\n desc: \"Return full task rows including description and plan text (large \\u2014 can exceed tool result limits on big packs). Default: compact orchestration view.\"\n })\n )\n }\n },\n mcp: {\n description: \"List all subtasks of a parent task with their status and ordering. Pass projectId to target a specific project; otherwise the configured default project is used.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The parent task ID\" })\n }\n }\n});\nvar subtasksContracts = [\n createSubtaskContract,\n updateSubtaskContract,\n deleteSubtaskContract,\n listSubtasksContract\n];\n\n// src/tool-contracts/attachments.ts\nvar mcpTaskIdOrSlug = f.string({ desc: \"The task ID or slug\" });\nvar listTaskFilesContract = defineToolContract({\n name: \"list_task_files\",\n agent: {\n description: \"List all files attached to this task with metadata. Use before fetching a specific file to see what is available and how large each is. For file contents use get_attachment.\",\n fields: {}\n },\n mcp: {\n description: \"List all files attached to a task with metadata (no contents \\u2014 fast and small). Pass projectId to target a specific project; otherwise the configured default project is used. Use before fetching a specific file to see what is available and how large each is. For file contents use get_attachment.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpTaskIdOrSlug\n }\n }\n});\nvar getAttachmentContract = defineToolContract({\n name: \"get_attachment\",\n agent: {\n description: \"Fetch one task file's content plus metadata by file ID. Call list_task_files first to discover IDs and check sizes \\u2014 large binaries may be truncated by the service's size limit.\",\n fields: {\n fileId: f.string({ desc: \"The file ID to retrieve\" })\n }\n },\n mcp: {\n description: \"Fetch one task file's content plus metadata by file ID (accepts task id or slug). Pass projectId to target a specific project; otherwise the configured default project is used. Images are returned as viewable image blocks. Large text files (logs, JSON) are returned in pages \\u2014 use `offset`/`maxBytes` to read more, or fetch `downloadUrl` for the whole file. Call list_task_files first to discover IDs and sizes.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpTaskIdOrSlug,\n fileId: f.string({ desc: \"The file ID to fetch\" }),\n offset: f.optional(\n f.number({\n int: true,\n nonnegative: true,\n desc: \"Byte offset into text content (paging). Default 0.\"\n })\n ),\n maxBytes: f.optional(\n f.number({\n int: true,\n positive: true,\n desc: \"Max bytes of text content to return from offset.\"\n })\n )\n }\n }\n});\nvar attachmentTags = f.optional(\n f.array(f.string(), {\n desc: `Glossary tag names this file is a relevant example of, e.g. a screenshot of the tag page tagged \"tag\". Use it when the file shows a tagged entity in a particular state: the tag's page lists its recent tagged attachments, so a reader can see what the entity looks like across the app and spot visual changes over time. Names are matched case-insensitively within the project; a name that matches no tag is reported back and never fails the upload. Max 5.`\n })\n);\nvar uploadAttachmentContract = defineToolContract({\n name: \"upload_attachment\",\n agent: {\n description: \"Upload a file (doc, notes, data, diagram, screenshot \\u2014 any file type, up to 25MB) as a task attachment AND post it to the task chat in one step \\u2014 no follow-up post_to_chat call needed. This is how you deliver a file the user should keep: it attaches to the card. Never publish deliverables as an external Claude artifact. Pass `tags` when the file is a good example of a glossary tag in some state.\",\n fields: {\n path: f.string({\n desc: \"Path to the file \\u2014 absolute, or relative to the workspace root\"\n }),\n title: f.optional(\n f.string({ desc: \"Short caption posted with the file (defaults to the file name)\" })\n ),\n tags: attachmentTags\n }\n },\n mcp: {\n description: \"Upload a local file as a task attachment (any file type, up to 25MB). Pass projectId to target a specific project; otherwise the configured default project is used. The file appears under the task's Files. Pass `comment` to also post it to the task chat in the same step, and `tags` when the file is a good example of a glossary tag in some state.\",\n fields: {\n projectId: mcpProjectId,\n taskId: mcpTaskIdOrSlug,\n path: f.string({ desc: \"Absolute path to the local file to upload\" }),\n comment: f.optional(\n f.string({ desc: \"When set, also posts the attachment to the task chat with this text\" })\n ),\n tags: attachmentTags,\n mimeType: f.optional(\n f.string({ desc: \"Override the mime type inferred from the file extension\" })\n )\n }\n }\n});\nvar attachmentsContracts = [\n listTaskFilesContract,\n getAttachmentContract,\n uploadAttachmentContract\n];\n\n// src/tool-contracts/suggestions.ts\nvar createSuggestionContract = defineToolContract({\n name: \"create_suggestion\",\n agent: {\n description: \"File a project suggestion (idea/improvement for maintainers to review). Duplicates are AI-deduped into an existing suggestion with an upvote. Returns the suggestion id.\",\n fields: {\n title: f.string({ min: 1, desc: \"Short title\" }),\n description: f.optional(\n f.string({ desc: cardDescriptionDesc(\"What should change and why\") })\n ),\n tag_names: f.optional(f.array(f.string(), { desc: \"Tag names to categorize\" }))\n }\n },\n mcp: {\n description: \"Suggest a feature, improvement, rule, or idea for the project. Pass projectId to target a specific project; otherwise the configured default project is used. Duplicates are deduped and your upvote is recorded.\",\n fields: {\n projectId: mcpProjectId,\n title: f.string({ desc: \"Suggestion title\" }),\n description: f.optional(f.string({ desc: cardDescriptionDesc(\"Suggestion details\") })),\n tagNames: f.optional(\n f.array(f.string(), {\n desc: 'Tag names to categorize the suggestion (e.g., [\"agent-runner\"])'\n })\n )\n }\n }\n});\nvar suggestionsContracts = [createSuggestionContract];\n\n// src/tool-contracts/pull-request.ts\nvar createPullRequestContract = defineToolContract({\n name: \"create_pull_request\",\n agent: {\n description: \"Create a GitHub PR for this task. Auto-stages, commits (commitMessage or title default), pushes to origin, then opens the PR. Always use this instead of gh CLI or raw git.\",\n fields: {\n title: f.string({ desc: \"The PR title\" }),\n body: f.string({\n desc: \"The PR description/body in markdown. If the diff changes anything a user sees rendered, the body MUST show the visual proof inline, not just point at the card: upload the capture with upload_attachment, then embed the downloadUrl it returns under a '## Screenshots' heading ( for images, [caption](url) for video). Attach to the card as well \\u2014 the card is the durable home, the PR body is what the reviewer reads.\"\n }),\n branch: f.optional(\n f.string({\n desc: \"The head branch name for the PR. Defaults to the workspace's current checkout, which is also the branch the commits are pushed to. Pass it explicitly if you pushed to a different branch, or if the card may have been renamed (a rename can re-slug the task's stored branch away from the one you are working on).\"\n })\n ),\n baseBranch: f.optional(\n f.string({\n desc: \"The base branch to target for the PR (e.g. 'main', 'develop'). Defaults to the project's configured dev branch.\"\n })\n ),\n commitMessage: f.optional(\n f.string({\n desc: \"Commit message for staging uncommitted changes. If not provided, a default message based on the PR title will be used.\"\n })\n ),\n skipVerify: f.optional(\n f.boolean({\n desc: \"Controls the local pre-push quality gate (lint/typecheck/test). Defaults to true (--no-verify): the push skips the local gate because you should run gates yourself before opening the PR and CI re-runs them on the resulting PR. Running the full gate synchronously during the push would block the agent's event loop long enough to drop the Conveyor socket connection. Pass false to force the local pre-push hook to run.\"\n })\n )\n }\n },\n mcp: {\n description: \"Open a GitHub pull request for a task's existing branch (the branch must already be pushed to origin). Pass projectId to target a specific project; otherwise the configured default project is used. Moves the task to ReviewPR. Returns the PR number and URL.\",\n fields: {\n projectId: mcpProjectId,\n taskId: f.string({ desc: \"The task ID whose branch should be opened as a PR\" }),\n title: f.string({ desc: \"Pull request title\" }),\n body: f.string({\n desc: \"Pull request body (markdown). For a diff that changes rendered UI, embed the visual proof inline: upload the capture with upload_attachment and paste the downloadUrl it returns as , in addition to leaving it on the card.\"\n }),\n head: f.optional(\n f.string({ desc: \"Source branch for the PR (defaults to the task's branch)\" })\n ),\n base: f.optional(\n f.string({ desc: \"Target branch for the PR (defaults to the repo default)\" })\n )\n }\n }\n});\nvar pullRequestContracts = [createPullRequestContract];\n\n// src/tool-contracts/index.ts\nvar TOOL_CONTRACTS = Object.fromEntries(\n [\n ...tasksContracts,\n ...tagsContracts,\n ...checklistContracts,\n ...dependenciesContracts,\n ...subtasksContracts,\n ...attachmentsContracts,\n ...suggestionsContracts,\n ...pullRequestContracts\n ].map((contract) => [contract.name, contract])\n);\nexport {\n CARD_DESCRIPTION_FIELD_HINT,\n CARD_DESCRIPTION_LIMIT_MESSAGE,\n CARD_DESCRIPTION_MAX,\n TOOL_CONTRACTS,\n addDependencyContract,\n approveAndMergePrContract,\n approveManualTestContract,\n attachmentsContracts,\n cardDescriptionDesc,\n checklistContracts,\n compileShape,\n createPullRequestContract,\n createSubtaskContract,\n createSuggestionContract,\n defineToolContract,\n deleteSubtaskContract,\n dependenciesContracts,\n editManualTestContract,\n f,\n getAttachmentContract,\n getDependenciesContract,\n getTagContract,\n getTaskContract,\n listManualTestsContract,\n listSubtasksContract,\n listTagsContract,\n listTaskFilesContract,\n mcpProjectId,\n postToChatContract,\n pullRequestContracts,\n queryManualTestsContract,\n readTaskChatContract,\n rejectManualTestContract,\n removeDependencyContract,\n removeManualTestContract,\n searchTasksContract,\n setManualTestsContract,\n storyPointValueDesc,\n subtasksContracts,\n suggestionsContracts,\n tagsContracts,\n tasksContracts,\n updateSubtaskContract,\n uploadAttachmentContract\n};\n","/**\n * Bridge from shared tool contracts to this package's harness tools.\n *\n * Contracts are zod-version-neutral DATA (`@project/shared/tool-contracts`);\n * this package compiles them with its OWN zod (v4 — pinned by the Claude\n * Agent SDK's `zod: ^4` peer dependency, see package-metadata.test.ts) so\n * every schema object in the harness is a genuine same-version zod v4\n * instance. Handler inputs are typed from the contract data (`InferShape`)\n * rather than through zod's object inference, which hits TS2589 on generic\n * mapped shapes.\n */\nimport { z } from \"zod\";\nimport {\n compileShape,\n type FieldMap,\n type InferField,\n type InferShape,\n type OptionalSpec,\n type ToolContract,\n type ToolSurface,\n} from \"@project/shared/tool-contracts\";\nimport type { HarnessToolAnnotations, HarnessToolDefinition } from \"../harness/index.js\";\n\n/** Precise zod-v4 shape type for a contract surface (optional specs → ZodOptional keys). */\nexport type AgentContractShape<F extends FieldMap> = {\n [K in keyof F]: F[K] extends OptionalSpec<infer I>\n ? z.ZodOptional<z.ZodType<InferField<I>>>\n : z.ZodType<InferField<F[K]>>;\n};\n\nexport function agentShape<F extends FieldMap>(surface: ToolSurface<F>): AgentContractShape<F> {\n return compileShape(z, surface.fields) as AgentContractShape<F>;\n}\n\n/**\n * `defineTool`, sourced from a shared contract's agent surface. Mirrors the\n * `defineTool` wrapper in harness/types.ts, but types the handler input from\n * the contract's field specs.\n */\nexport function defineContractTool<A extends FieldMap>(\n contract: ToolContract<A, FieldMap>,\n handler: (\n input: InferShape<A>,\n ) => Promise<{ content: { type: string; text?: string; data?: string; mimeType?: string }[] }>,\n options?: { annotations?: HarnessToolAnnotations; strict?: boolean },\n): HarnessToolDefinition {\n return {\n name: contract.name,\n description: contract.agent.description,\n schema: agentShape(contract.agent) as unknown as z.ZodRawShape,\n handler: handler as HarnessToolDefinition[\"handler\"],\n annotations: options?.annotations,\n strict: options?.strict,\n };\n}\n","/** Shared result helpers for MCP tool handlers. */\n\nexport function textResult(text: string): { content: { type: \"text\"; text: string }[] } {\n return { content: [{ type: \"text\" as const, text }] };\n}\n\nexport function imageBlock(\n data: string,\n mimeType: string,\n): { type: \"image\"; data: string; mimeType: string } {\n return { type: \"image\" as const, data, mimeType };\n}\n\nexport function isImageMimeType(mimeType: string): boolean {\n return mimeType.startsWith(\"image/\");\n}\n\n// ── Event formatting for CLI logs ─────────────────────────────────────\n\ntype EventRecord = Record<string, unknown>;\n\nconst cliEventFormatters: Record<string, (e: EventRecord) => string> = {\n thinking: (e) => (e.message as string) ?? \"\",\n tool_use: (e) => `${e.tool}: ${(e.input as string)?.slice(0, 1000) ?? \"\"}`,\n tool_result: (e) =>\n `${e.tool} → ${(e.output as string)?.slice(0, 500) ?? \"\"}${e.isError ? \" [ERROR]\" : \"\"}`,\n message: (e) => (e.content as string) ?? \"\",\n error: (e) => `ERROR: ${(e.message as string) ?? \"\"}`,\n completed: (e) =>\n `Completed: ${(e.summary as string) ?? \"\"} (duration: ${e.durationMs ?? \"?\"}ms)`,\n setup_output: (e) => `[${(e.stream as string) ?? \"stdout\"}] ${(e.data as string) ?? \"\"}`,\n start_command_output: (e) => `[${(e.stream as string) ?? \"stdout\"}] ${(e.data as string) ?? \"\"}`,\n turn_end: (e) => `Turn complete (${(e.toolCalls as unknown[])?.length ?? 0} tool calls)`,\n};\n\nexport function formatCliEvent(e: EventRecord): string {\n const formatter = cliEventFormatters[e.type as string];\n return formatter ? formatter(e) : JSON.stringify(e);\n}\n","import { z } from \"zod\";\nimport { getDependenciesContract } from \"@project/shared/tool-contracts\";\nimport { defineTool } from \"../harness/index.js\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult } from \"./helpers.js\";\n\nexport function buildGetDependenciesTool(connection: AgentConnection) {\n return defineContractTool(\n getDependenciesContract,\n async () => {\n try {\n const deps = await connection.call(\"getDependencies\", {\n sessionId: connection.sessionId,\n });\n return textResult(JSON.stringify(deps, null, 2));\n } catch (error) {\n return textResult(\n `Failed to get dependencies: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildGetSuggestionsTool(connection: AgentConnection) {\n return defineTool(\n \"get_suggestions\",\n \"List project suggestions sorted by vote score. Filter by status or cap with limit (default 20). Suggestions are project-level ideas, not tasks — use get_task for tasks.\",\n {\n status: z\n .string()\n .optional()\n .describe(\n \"Filter by status: Planning, Open, InProgress, ReviewPR, ReviewDev, ReviewLive, Complete, Cancelled\",\n ),\n limit: z.number().int().min(1).max(100).optional().describe(\"Max results (default 20)\"),\n },\n async ({ status, limit }) => {\n try {\n const suggestions = await connection.call(\"getSuggestions\", {\n sessionId: connection.sessionId,\n status,\n limit,\n });\n if (suggestions.length === 0) {\n return textResult(\"No suggestions found.\");\n }\n return textResult(JSON.stringify(suggestions, null, 2));\n } catch (error) {\n return textResult(\n `Failed to get suggestions: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n","import { z } from \"zod\";\nimport {\n addDependencyContract,\n cardDescriptionDesc,\n createPullRequestContract,\n postToChatContract,\n removeDependencyContract,\n} from \"@project/shared/tool-contracts\";\nimport { defineTool } from \"../harness/index.js\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../runner-types.js\";\nimport { textResult } from \"./helpers.js\";\nimport {\n hasUncommittedChanges,\n stageAndCommit,\n hasUnpushedCommits,\n pushToOrigin,\n getCurrentBranch,\n updateRemoteToken,\n verifyGitCredential,\n} from \"../runner/git-utils.js\";\nimport { ghHostsExternallyOwned, githubTokenFilePath } from \"../boot/git-credential.js\";\n\nexport function buildPostToChatTool(connection: AgentConnection) {\n return defineContractTool(\n postToChatContract,\n async ({ message, content, task_id, milestone }) => {\n // Cross-surface alias: the external conveyor-mcp surface calls this field\n // `content`, and models regularly carry that name over. Accept either.\n const text = message ?? content;\n if (text === undefined) {\n return textResult(\n JSON.stringify({\n posted: false,\n reason: \"missing_message\",\n hint: \"Provide `message` (or its alias `content`) with the text to post.\",\n }),\n );\n }\n try {\n if (task_id) {\n await connection.call(\"postChildChatMessage\", {\n sessionId: connection.sessionId,\n childTaskId: task_id,\n message: text,\n });\n return textResult(JSON.stringify({ posted: true, target: `child:${task_id}` }));\n }\n const dedup = connection.checkAndTrackDuplicate(text);\n if (dedup.duplicate) {\n return textResult(\n JSON.stringify({\n posted: false,\n reason: \"duplicate\",\n matchedMessagePreview: dedup.matchedMessagePreview,\n hint: \"A near-identical message (>70% word overlap) was posted within the last 30s. Rephrase with new information or skip this post.\",\n }),\n );\n }\n await connection.call(\"postToChat\", { message: text, milestone });\n return textResult(JSON.stringify({ posted: true }));\n } catch (error) {\n return textResult(\n `Failed to post message: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\nexport function buildForceUpdateTaskStatusTool(connection: AgentConnection) {\n return defineTool(\n \"force_update_task_status\",\n \"EMERGENCY ONLY: force-override a task's Kanban status. Use when an automatic transition failed and the task is wedged. Normal flow transitions status automatically.\",\n {\n status: z\n .enum([\n \"Planning\",\n \"Open\",\n \"InProgress\",\n \"ReviewPR\",\n \"ReviewDev\",\n \"ReviewLive\",\n \"Complete\",\n \"Cancelled\",\n ])\n .describe(\"The new status for the task\"),\n task_id: z\n .string()\n .optional()\n .describe(\"Child task ID to update. Omit to update the current task.\"),\n },\n async ({ status, task_id }) => {\n try {\n if (task_id) {\n await connection.call(\"updateChildStatus\", {\n sessionId: connection.sessionId,\n childTaskId: task_id,\n status,\n });\n return textResult(`Child task ${task_id} status updated to ${status}.`);\n }\n await connection.call(\"updateTaskStatus\", {\n sessionId: connection.sessionId,\n status,\n force: true,\n });\n return textResult(`Task status updated to ${status}.`);\n } catch (error) {\n return textResult(\n `Failed to update status: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\n// oxlint-disable-next-line max-lines-per-function -- PR creation involves git staging, committing, pushing, and API call\nexport function buildCreatePullRequestTool(connection: AgentConnection, config: AgentRunnerConfig) {\n return defineContractTool(\n createPullRequestContract,\n async ({ title, body, branch, baseBranch, commitMessage, skipVerify }) => {\n try {\n const cwd = config.workspaceDir;\n\n // Every git step below operates on the current checkout, so that is the\n // only branch the PR can legitimately track. Resolve it up front and send\n // it as an explicit head: when the server receives no head for a task\n // whose stored branch is missing or stale (a renamed card re-slugs\n // `githubBranch` behind our back), it mints a fresh branch from the task\n // title and opens the PR from that — a branch with zero commits, which\n // fails with \"No commits between <base> and conveyor/<title-slug>\".\n const headBranch = branch ?? (await getCurrentBranch(cwd));\n if (!headBranch) {\n return textResult(\n \"Cannot create a pull request: the workspace is on a detached HEAD, so there is no branch to open the PR from. Check out a branch (e.g. `git checkout -b <branch>`) and retry, or pass `branch` explicitly.\",\n );\n }\n\n if (await hasUncommittedChanges(cwd)) {\n const message =\n commitMessage || `${title}\\n\\nCo-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>`;\n const commitHash = await stageAndCommit(cwd, message);\n if (commitHash) {\n connection.sendEvent({\n type: \"message\",\n content: `Auto-committed changes: ${commitHash.slice(0, 7)}`,\n });\n } else {\n return textResult(\n \"Failed to stage and commit changes. Please check git status and commit manually before creating PR.\",\n );\n }\n }\n\n if (await hasUnpushedCommits(cwd)) {\n const pushSuccess = await pushToOrigin(\n cwd,\n async () => {\n try {\n const result = await connection.call(\"refreshGithubToken\", {\n sessionId: connection.sessionId,\n });\n return result.token;\n } catch {\n return undefined;\n }\n },\n skipVerify ?? true,\n );\n if (pushSuccess) {\n connection.sendEvent({\n type: \"message\",\n content: \"Auto-pushed committed changes to origin\",\n });\n } else {\n return textResult(\n \"Failed to push changes to origin. Please check git status and push manually before creating PR.\",\n );\n }\n }\n\n const result = await connection.call(\"createPullRequest\", {\n sessionId: connection.sessionId,\n title,\n body,\n head: headBranch,\n base: baseBranch,\n });\n connection.sendEvent({\n type: \"pr_created\",\n url: result.prUrl,\n number: result.prNumber,\n });\n const glossaryNote = result.glossaryNote ? `\\n\\n${result.glossaryNote}` : \"\";\n return textResult(\n `Pull request #${result.prNumber} created: ${result.prUrl}${glossaryNote}`,\n );\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(\n `Failed to create pull request: ${msg}\\n\\nTroubleshooting:\\n- Ensure all changes are committed and pushed to the remote branch\\n- Check that the branch exists on the remote (run: git push -u origin HEAD)\\n- Verify there isn't already an open PR for this branch\\n- If git auth fails, the token may have expired — retry the operation`,\n );\n }\n },\n );\n}\n\nexport function buildAddDependencyTool(connection: AgentConnection) {\n return defineContractTool(addDependencyContract, async ({ depends_on_slug_or_id }) => {\n try {\n await connection.call(\"addDependency\", {\n sessionId: connection.sessionId,\n dependsOnSlugOrId: depends_on_slug_or_id,\n });\n return textResult(`Dependency added: this task now depends on \"${depends_on_slug_or_id}\"`);\n } catch (error) {\n return textResult(\n `Failed to add dependency: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n });\n}\n\nexport function buildRemoveDependencyTool(connection: AgentConnection) {\n return defineContractTool(removeDependencyContract, async ({ depends_on_slug_or_id }) => {\n try {\n await connection.call(\"removeDependency\", {\n sessionId: connection.sessionId,\n dependsOnSlugOrId: depends_on_slug_or_id,\n });\n return textResult(\"Dependency removed\");\n } catch (error) {\n return textResult(\n `Failed to remove dependency: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n });\n}\n\nexport function buildCreateFollowUpTaskTool(connection: AgentConnection) {\n return defineTool(\n \"create_follow_up_task\",\n \"Create a follow-up task that depends on the current task. The new card is a SIBLING of this one (same parent) and is blocked until this task merges — it is NOT a child of this card. To break this card into child cards that build as a pack, use create_subtask. For blockers use add_dependency.\",\n {\n title: z.string().describe(\"Follow-up task title\"),\n description: z\n .string()\n .optional()\n .describe(cardDescriptionDesc(\"Brief description of the follow-up work\")),\n plan: z.string().optional().describe(\"Implementation plan if known\"),\n story_point_value: z\n .number()\n .optional()\n .describe(\"Story point estimate (1=Common, 2=Magic, 3=Rare, 5=Unique)\"),\n },\n async ({ title, description, plan, story_point_value }) => {\n try {\n const result = await connection.call(\"createFollowUpTask\", {\n sessionId: connection.sessionId,\n title,\n description,\n plan,\n storyPointValue: story_point_value,\n });\n return textResult(\n `Follow-up task created: \"${title}\" (slug: ${result.slug}). It depends on the current task and will be unblocked when this task is merged.`,\n );\n } catch (error) {\n return textResult(\n `Failed to create follow-up task: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\nexport function buildCreateSuggestionTool(connection: AgentConnection) {\n return defineTool(\n \"create_suggestion\",\n \"Suggest a feature, improvement, rule, or idea for the project. Duplicates are deduped and your upvote is recorded. For actionable work on this task open a follow-up task.\",\n {\n title: z.string().describe(\"Short title for the suggestion\"),\n description: z\n .string()\n .optional()\n .describe(\n \"1-2 sentence description of what should change and why. Keep concise and project-focused.\",\n ),\n tag_names: z.array(z.string()).optional().describe(\"Tag names to categorize the suggestion\"),\n },\n async ({ title, description, tag_names }) => {\n try {\n const result = await connection.call(\"createSuggestion\", {\n sessionId: connection.sessionId,\n title,\n description,\n tagNames: tag_names,\n });\n if (result.merged) {\n return textResult(\n `Your suggestion was merged into an existing one (ID: ${result.mergedIntoId ?? result.id}). Your upvote has been recorded.`,\n );\n }\n return textResult(`Suggestion created (ID: ${result.id}).`);\n } catch (error) {\n return textResult(\n `Failed to create suggestion: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\nexport function buildVoteSuggestionTool(connection: AgentConnection) {\n return defineTool(\n \"vote_suggestion\",\n \"Vote +1 or -1 on a project suggestion. Use to express support or disagreement with a specific suggestion returned by get_suggestions.\",\n {\n suggestion_id: z.string().describe(\"The suggestion ID to vote on\"),\n value: z\n .number()\n .refine((v) => v === 1 || v === -1, { message: \"Value must be 1 or -1\" })\n .describe(\"+1 to upvote, -1 to downvote\"),\n },\n async ({ suggestion_id, value }) => {\n try {\n const result = await connection.call(\"voteSuggestion\", {\n sessionId: connection.sessionId,\n suggestionId: suggestion_id,\n value: value as 1 | -1,\n });\n return textResult(`Vote recorded. Current score: ${result.score}`);\n } catch (error) {\n return textResult(\n `Failed to vote: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\nexport function buildRefreshGithubTokenTool(\n connection: AgentConnection,\n config: AgentRunnerConfig,\n) {\n return defineTool(\n \"refresh_github_token\",\n \"Mint a fresh GitHub token for this pod when git or gh fails with a 401 / 'Bad credentials'. The pod's token expires about every hour. This updates the git credential store and the gh CLI config, and returns the shell command that puts a current token in your environment.\",\n {},\n async () => {\n try {\n const result = await connection.call(\"refreshGithubToken\", {\n sessionId: connection.sessionId,\n });\n const written = await updateRemoteToken(config.workspaceDir, result.token);\n process.env.GITHUB_TOKEN = result.token;\n process.env.GH_TOKEN = result.token;\n const tokenFile = githubTokenFilePath();\n\n // Report what actually landed, not what we attempted. This tool used to\n // print \"the credential store is updated\" whenever the RPC returned —\n // it never read a file back and never asked GitHub. A pod whose store\n // was empty got two clean \"refreshed\" answers while every git and gh\n // call kept failing with 401.\n const failures: string[] = [];\n if (!written.credential.storeWritten) {\n failures.push(\n `- git credential store NOT written${written.credential.error ? `: ${written.credential.error}` : \"\"}`,\n );\n } else if (!written.credential.helperConfigured) {\n failures.push(\n `- git credential helper NOT configured${written.credential.error ? `: ${written.credential.error}` : \"\"}`,\n );\n }\n if (!written.files.tokenFile) failures.push(`- token file ${tokenFile} NOT written`);\n // Skipping a `gh` login this pod did not create is deliberate, not a\n // fault — the Codespaces backend authenticates `gh` for us. Reporting it\n // as a failure would tell the agent to escalate on every healthy refresh.\n if (!written.files.ghHosts && !ghHostsExternallyOwned()) {\n failures.push(\"- gh CLI config NOT written\");\n }\n\n const probe = await verifyGitCredential(config.workspaceDir);\n if (!probe.ok) {\n failures.push(\n `- git could not authenticate to origin: ${probe.error ?? \"unknown error\"}`,\n );\n }\n\n if (failures.length > 0) {\n return textResult(\n [\n probe.ok\n ? \"GitHub token refreshed, but some credential copies did not update.\"\n : \"GitHub token refresh did NOT produce a working git credential.\",\n ...failures,\n `A current token is available at ${tokenFile} when that file was written.`,\n \"Do not retry this tool more than once. Report the failing lines above to the team — the GitHub App install may be missing for this project, or the pod's credential directory may not be writable.\",\n ].join(\"\\n\"),\n );\n }\n\n return textResult(\n [\n \"GitHub token refreshed and verified against origin.\",\n \"- git: the credential store and helper are updated, so `git push` works now with no extra step.\",\n \"- gh: the CLI config is updated, so `gh` works now with no extra step.\",\n `- shell/scripts: read the current token from ${tokenFile}.`,\n ` For a command that needs it in the environment: GITHUB_TOKEN=$(cat ${tokenFile}) <command>`,\n \"Retry the failed command.\",\n ].join(\"\\n\"),\n );\n } catch (error) {\n return textResult(\n `Failed to refresh the GitHub token: ${error instanceof Error ? error.message : \"Unknown error\"}\\n\\nThe agent's connection to the API may be down. Wait for it to reconnect and try again.`,\n );\n }\n },\n );\n}\n\n/** All write/mutation tools (excluding PR creation which needs config). */\nexport function buildMutationTools(connection: AgentConnection, config: AgentRunnerConfig) {\n return [\n buildPostToChatTool(connection),\n buildCreatePullRequestTool(connection, config),\n buildRefreshGithubTokenTool(connection, config),\n buildAddDependencyTool(connection),\n buildRemoveDependencyTool(connection),\n buildCreateFollowUpTaskTool(connection),\n buildCreateSuggestionTool(connection),\n buildVoteSuggestionTool(connection),\n ];\n}\n","import { basename, extname, isAbsolute, join } from \"node:path\";\nimport { MAX_FILE_SIZE_BYTES } from \"@project/shared\";\nimport { uploadAttachmentContract } from \"@project/shared/tool-contracts\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../runner-types.js\";\nimport { readWorkspaceBytes, statWorkspacePath } from \"../workbench/fs.js\";\nimport { textResult } from \"./helpers.js\";\n\n// Any file type is accepted so agents deliver docs, notes, and data by\n// attaching them to the card — never by publishing an off-platform Claude\n// artifact. Mirrors conveyor-mcp's map (packages/conveyor-mcp/src/tools/\n// attachments.ts); unknown extensions fall back to application/octet-stream.\nconst MIME_BY_EXT: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n \".txt\": \"text/plain\",\n \".log\": \"text/plain\",\n \".md\": \"text/markdown\",\n \".mmd\": \"text/vnd.mermaid\",\n \".mermaid\": \"text/vnd.mermaid\",\n \".csv\": \"text/csv\",\n \".html\": \"text/html\",\n \".css\": \"text/css\",\n \".js\": \"text/javascript\",\n \".ts\": \"text/plain\",\n \".json\": \"application/json\",\n \".yaml\": \"application/yaml\",\n \".yml\": \"application/yaml\",\n \".pdf\": \"application/pdf\",\n \".zip\": \"application/zip\",\n \".gz\": \"application/gzip\",\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n};\n\nfunction inferMimeType(filePath: string): string {\n return MIME_BY_EXT[extname(filePath).toLowerCase()] ?? \"application/octet-stream\";\n}\n\n/**\n * Report which glossary tags the file was labelled with. An unmatched name is\n * surfaced rather than swallowed: the upload still succeeded, and the agent\n * needs to know the label did not stick so it can retry with the real name.\n */\nfunction describeTags(applied?: string[], unknown?: string[]): string {\n const parts: string[] = [];\n if (applied?.length) parts.push(` Tagged: ${applied.join(\", \")}.`);\n if (unknown?.length) {\n parts.push(` No tag matched: ${unknown.join(\", \")} — check the project's tag names.`);\n }\n return parts.join(\"\");\n}\n\n// Extensions GitHub renders inline from an external URL. `.svg` is deliberately\n// absent: GitHub serves markdown images through its camo image proxy, and camo\n// refuses `image/svg+xml`, so an `` embed of an SVG shows as broken. An\n// SVG capture still gets a plain link, which reviewers can open.\nconst EMBEDDABLE_IN_MARKDOWN = new Set([\".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\"]);\n\n/**\n * Hand the capability download URL back to the agent so visual proof can go in\n * the PR description as well as on the card. `confirmFileUpload` has always\n * returned it (an HMAC-signed URL our own API streams bytes for — it renders in\n * an `<img>`, unlike a Bearer-authed endpoint), but this tool used to drop it,\n * which is why the mode prompt long claimed there was \"no programmatic path\" to\n * put an image in a PR. Images get a ready-to-paste markdown line; video and\n * other types get a plain link, since GitHub does not render those inline.\n */\nfunction describeEmbed(fileName: string, downloadUrl?: string): string {\n if (!downloadUrl) return \"\";\n const isImage = EMBEDDABLE_IN_MARKDOWN.has(extname(fileName).toLowerCase());\n const snippet = isImage ? `` : `[${fileName}](${downloadUrl})`;\n return `\\n\\nPaste this into the PR description to show it inline:\\n${snippet}`;\n}\n\nexport function buildUploadAttachmentTool(connection: AgentConnection, config: AgentRunnerConfig) {\n return defineContractTool(uploadAttachmentContract, async ({ path, title, tags }) => {\n try {\n const filePath = isAbsolute(path) ? path : join(config.workspaceDir, path);\n const mimeType = inferMimeType(filePath);\n\n // Route through the workspace-fs proxy so split-mode pods can see files\n // Claude Code wrote into the workbench container — a plain node:fs stat\n // here runs in the agent container and misses them (\"File not found\" for\n // a screenshot that demonstrably exists on the Bash filesystem).\n const info = await statWorkspacePath(filePath);\n if (!info.isFile) {\n return textResult(`File not found: ${filePath}`);\n }\n if (info.size > MAX_FILE_SIZE_BYTES) {\n return textResult(\n `File is ${info.size} bytes — exceeds the ${MAX_FILE_SIZE_BYTES} byte (25MB) upload limit.`,\n );\n }\n\n const fileName = basename(filePath);\n const { fileId, uploadUrl } = await connection.call(\"requestFileUpload\", {\n sessionId: connection.sessionId,\n fileName,\n mimeType,\n fileSize: info.size,\n });\n\n const bytes = await readWorkspaceBytes(filePath);\n const res = await fetch(uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": mimeType },\n // Normalize to a plain Uint8Array: the workbench proxy hands back a\n // Buffer<ArrayBufferLike> that newer @types/node rejects as a BodyInit.\n body: new Uint8Array(bytes),\n });\n if (!res.ok) {\n return textResult(\n `Upload to storage failed: HTTP ${res.status} ${await res.text().catch(() => \"\")}`,\n );\n }\n\n const result = await connection.call(\"confirmFileUpload\", {\n sessionId: connection.sessionId,\n fileId,\n title,\n tags,\n });\n\n return textResult(\n `Uploaded ${fileName} (${info.size} bytes) and posted it to the task chat${title ? ` with caption \"${title}\"` : \"\"}. File ID: ${result.fileId}${describeTags(result.appliedTags, result.unknownTags)}${describeEmbed(fileName, result.downloadUrl)}`,\n );\n } catch (error) {\n return textResult(\n `Failed to upload attachment: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n });\n}\n","import type { TaskManualTestsGroupDTO } from \"@project/shared\";\nimport {\n approveManualTestContract,\n editManualTestContract,\n listManualTestsContract,\n queryManualTestsContract,\n rejectManualTestContract,\n removeManualTestContract,\n setManualTestsContract,\n} from \"@project/shared/tool-contracts\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport { textResult } from \"./helpers.js\";\n\nexport function buildListManualTestsTool(connection: AgentConnection) {\n return defineContractTool(\n listManualTestsContract,\n async () => {\n try {\n const items = await connection.call(\"listManualTests\", {\n sessionId: connection.sessionId,\n });\n if (items.length === 0) return textResult(\"No manual tests recorded for this task.\");\n const lines = items.flatMap((item, i) => {\n const checked = item.checked ? \"[x]\" : \"[ ]\";\n const row = [`${i + 1}. ${checked} ${item.title}`];\n for (const f of item.failures ?? []) {\n const who = f.userName ?? \"Someone\";\n const reason = f.reason ?? \"(no message)\";\n row.push(` ⚠ Failed (${who}): ${reason}`);\n }\n return row;\n });\n return textResult(lines.join(\"\\n\"));\n } catch {\n return textResult(\"Failed to list manual tests.\");\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\n/** Compact grouped rendering for cross-task manual-test queries: one header per\n * task, one line per test with a status glyph, and the failing reason indented\n * under each rejected test. */\nfunction renderManualTestGroups(groups: TaskManualTestsGroupDTO[]): string {\n const lines: string[] = [];\n for (const g of groups) {\n lines.push(`## ${g.title} [${g.status}] (${g.slug})`);\n for (const t of g.tests) {\n const mark = t.status === \"approved\" ? \"✓\" : t.status === \"rejected\" ? \"✗\" : \"○\";\n lines.push(` ${mark} ${t.title} — ${t.status}`);\n if (t.status === \"rejected\") {\n for (const f of t.failures ?? []) {\n lines.push(` ⚠ ${f.userName ?? \"Someone\"}: ${f.reason ?? \"(no message)\"}`);\n }\n }\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function buildQueryManualTestsTool(connection: AgentConnection) {\n return defineContractTool(\n queryManualTestsContract,\n async ({ cardStatuses, testStatuses }) => {\n try {\n const groups = await connection.call(\"queryManualTests\", {\n sessionId: connection.sessionId,\n cardStatuses,\n testStatuses,\n });\n if (groups.length === 0) return textResult(\"No manual tests match those filters.\");\n return textResult(renderManualTestGroups(groups));\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to query manual tests: ${msg}`);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildSetManualTestsTool(connection: AgentConnection) {\n return defineContractTool(setManualTestsContract, async ({ items }) => {\n try {\n const result = await connection.call(\"setManualTests\", {\n sessionId: connection.sessionId,\n items,\n });\n const parts = [`Created ${result.created} manual test item(s).`];\n if (result.skipped > 0) parts.push(`Skipped ${result.skipped} duplicate(s).`);\n return textResult(parts.join(\" \"));\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to set manual tests: ${msg}`);\n }\n });\n}\n\nexport function buildEditManualTestTool(connection: AgentConnection) {\n return defineContractTool(editManualTestContract, async ({ title, newTitle }) => {\n try {\n await connection.call(\"editManualTest\", {\n sessionId: connection.sessionId,\n title,\n newTitle,\n });\n return textResult(`Updated manual test to \"${newTitle}\".`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to edit manual test: ${msg}`);\n }\n });\n}\n\nexport function buildRemoveManualTestTool(connection: AgentConnection) {\n return defineContractTool(removeManualTestContract, async ({ title }) => {\n try {\n await connection.call(\"removeManualTest\", {\n sessionId: connection.sessionId,\n title,\n });\n return textResult(`Removed manual test \"${title}\".`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to remove manual test: ${msg}`);\n }\n });\n}\n\nexport function buildApproveManualTestTool(connection: AgentConnection) {\n return defineContractTool(approveManualTestContract, async ({ title }) => {\n try {\n await connection.call(\"approveManualTest\", {\n sessionId: connection.sessionId,\n title,\n });\n return textResult(`Approved manual test \"${title}\".`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to approve manual test: ${msg}`);\n }\n });\n}\n\nexport function buildRejectManualTestTool(connection: AgentConnection) {\n return defineContractTool(rejectManualTestContract, async ({ title, reason }) => {\n try {\n await connection.call(\"rejectManualTest\", {\n sessionId: connection.sessionId,\n title,\n reason,\n });\n return textResult(`Flagged an issue with manual test \"${title}\": ${reason}`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to reject manual test: ${msg}`);\n }\n });\n}\n","import type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../runner-types.js\";\nimport { buildTaskContextTools } from \"./task-context-tools.js\";\nimport {\n buildGetDependenciesTool,\n buildGetSuggestionsTool,\n} from \"./dependency-suggestion-tools.js\";\nimport { buildMutationTools } from \"./mutation-tools.js\";\nimport { buildUploadAttachmentTool } from \"./attachment-tools.js\";\nimport {\n buildApproveManualTestTool,\n buildEditManualTestTool,\n buildListManualTestsTool,\n buildQueryManualTestsTool,\n buildRejectManualTestTool,\n buildRemoveManualTestTool,\n buildSetManualTestsTool,\n} from \"./checklist-tools.js\";\n\n// Re-export individual builders for selective use\nexport {\n buildReadTaskChatTool,\n buildGetCurrentPlanTool,\n buildGetTaskTool,\n buildGetExecutionLogsTool,\n buildListTaskFilesTool,\n buildGetAttachmentTool,\n} from \"./task-context-tools.js\";\n\nexport { buildForceUpdateTaskStatusTool } from \"./mutation-tools.js\";\nexport { buildUploadAttachmentTool } from \"./attachment-tools.js\";\n\n// ── Aggregator ───────────────────────────────────────────────────────\n\nexport function buildCommonTools(connection: AgentConnection, config: AgentRunnerConfig) {\n return [\n ...buildTaskContextTools(connection),\n buildGetDependenciesTool(connection),\n buildGetSuggestionsTool(connection),\n buildListManualTestsTool(connection),\n buildQueryManualTestsTool(connection),\n buildSetManualTestsTool(connection),\n buildEditManualTestTool(connection),\n buildRemoveManualTestTool(connection),\n buildApproveManualTestTool(connection),\n buildRejectManualTestTool(connection),\n ...buildMutationTools(connection, config),\n buildUploadAttachmentTool(connection, config),\n ];\n}\n","import { z } from \"zod\";\nimport {\n approveAndMergePrContract,\n cardDescriptionDesc,\n createSubtaskContract,\n deleteSubtaskContract,\n listSubtasksContract,\n updateSubtaskContract,\n} from \"@project/shared/tool-contracts\";\nimport { defineTool } from \"../harness/index.js\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult } from \"./helpers.js\";\n\nexport function buildUpdateTaskTool(connection: AgentConnection) {\n return defineTool(\n \"update_task_plan\",\n \"Save the plan and/or description to the current task. In auto/building mode, save the plan BEFORE writing code and keep it current as the approach evolves — post it, then build; never pause the build waiting for approval. For children use update_subtask; for title/tags/PR use update_task_properties.\",\n {\n plan: z.string().optional().describe(\"The task plan in markdown\"),\n description: z\n .string()\n .optional()\n .describe(cardDescriptionDesc(\"Updated task description\")),\n },\n async ({ plan, description }) => {\n try {\n await connection.call(\"updateTaskFields\", {\n sessionId: connection.sessionId,\n plan,\n description,\n });\n return textResult(\"Task updated successfully.\");\n } catch (error) {\n // Surface the real rejection (e.g. the description cap) — a generic\n // \"Failed to update task.\" leaves the agent with nothing to act on.\n return textResult(\n `Failed to update task: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n\nexport function buildHandoffTool(connection: AgentConnection) {\n return defineTool(\n \"handoff_to_agent\",\n \"Hand this task off to an implementer agent for the build phase — mid-conversation, same session, no restart. Call this once the plan is compiled and saved (update_task_plan). The server swaps this task to the difficulty-sized implementer agent (which may run at a different model level), announces the handoff in the activity log + chat, and switches you into build mode to start implementing. Size the work with the storyPoints arg (or set it first via update_task_properties). Returns the implementer's name + model.\",\n {\n storyPoints: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n \"Difficulty sizing (1=Common, 2=Magic, 3=Rare, 5=Unique, 8=Pack) — picks which implementer agent takes over. Omit to use the task's current story points.\",\n ),\n message: z\n .string()\n .optional()\n .describe(\"Optional kickoff note posted to the chat alongside the handoff notice.\"),\n },\n async ({ storyPoints, message }) => {\n try {\n const result = await connection.handoffToImplementer({\n ...(storyPoints !== undefined && { storyPoints }),\n ...(message !== undefined && { message }),\n });\n if (!result.handedOff) {\n return textResult(`Handoff did not complete: ${result.reason ?? \"unknown reason\"}`);\n }\n return textResult(\n `Handed off to ${result.agentName} (${result.model}). Now in build mode — start implementing the plan.`,\n );\n } catch (error) {\n return textResult(\n `Failed to hand off: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\nfunction buildCreateSubtaskTool(connection: AgentConnection) {\n return defineContractTool(\n createSubtaskContract,\n async ({\n title,\n description,\n plan,\n ordinal,\n storyPointValue,\n followParentStatus,\n dependsOn,\n tags,\n }) => {\n try {\n const result = await connection.call(\"createSubtask\", {\n sessionId: connection.sessionId,\n title,\n ...(description !== undefined && { description }),\n ...(plan !== undefined && { plan }),\n ...(storyPointValue !== undefined && { storyPointValue }),\n ...(ordinal !== undefined && { ordinal }),\n ...(followParentStatus !== undefined && { followParentStatus }),\n ...(dependsOn !== undefined && { dependsOn }),\n ...(tags !== undefined && { tags }),\n });\n const unmatched = result.unmatchedTags ?? [];\n const tagNote =\n unmatched.length > 0\n ? ` These tag names matched no project tag and were skipped: ${unmatched.join(\", \")}. Use list_tags to see the glossary.`\n : \"\";\n return textResult(\n `Subtask created with ID: ${result.id} (slug: ${result.slug})${tagNote}`,\n );\n } catch (error) {\n return textResult(\n `Failed to create subtask: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\nfunction buildUpdateSubtaskTool(connection: AgentConnection) {\n return defineContractTool(\n updateSubtaskContract,\n async ({\n subtaskId,\n title,\n description,\n plan,\n status,\n agentIdOrName,\n storyPointValue,\n followParentStatus,\n dependsOn,\n }) => {\n try {\n await connection.call(\"updateSubtask\", {\n sessionId: connection.sessionId,\n subtaskId,\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(plan !== undefined && { plan }),\n ...(status !== undefined && { status }),\n ...(agentIdOrName !== undefined && { agentIdOrName }),\n ...(storyPointValue !== undefined && { storyPointValue }),\n ...(followParentStatus !== undefined && { followParentStatus }),\n ...(dependsOn !== undefined && { dependsOn }),\n });\n return textResult(\"Subtask updated.\");\n } catch (error) {\n return textResult(`Failed: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n },\n );\n}\n\nfunction buildDeleteSubtaskTool(connection: AgentConnection) {\n return defineContractTool(deleteSubtaskContract, async ({ subtaskId }) => {\n try {\n await connection.call(\"deleteSubtask\", {\n sessionId: connection.sessionId,\n subtaskId,\n });\n return textResult(\"Subtask deleted.\");\n } catch (error) {\n return textResult(`Failed: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n }\n });\n}\n\nfunction buildListSubtasksTool(connection: AgentConnection) {\n return defineContractTool(\n listSubtasksContract,\n async ({ verbose }) => {\n try {\n const subtasks = await connection.call(\"listSubtasks\", {\n sessionId: connection.sessionId,\n view: verbose ? \"full\" : \"compact\",\n });\n return textResult(JSON.stringify(subtasks, null, 2));\n } catch {\n return textResult(\"Failed to list subtasks.\");\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nfunction buildPackTools(connection: AgentConnection) {\n return [\n defineTool(\n \"start_child_cloud_build\",\n \"Start a cloud build (codespace) for a child task. Preconditions: child status is `Open`, story points set, and an agent assigned — satisfy all three with update_subtask (status/agentIdOrName/storyPointValue) first; none happen automatically. A PACK_CHILD_LIMIT error is backpressure, not failure: check list_subtasks packSlots for which children hold the in-flight slots, merge/stop one, then retry. On a feature-branch pack, dev is merged into the pack branch first so the child branches from a fresh base; a conflict is reported in the result and never blocks the launch.\",\n {\n childTaskId: z.string().describe(\"The child task ID to start a cloud build for\"),\n },\n async ({ childTaskId }) => {\n try {\n const result = await connection.call(\"startChildCloudBuild\", {\n sessionId: connection.sessionId,\n childTaskId,\n });\n const started = `Cloud build started for child task: ${result.childTaskId}`;\n const sync = result.baseSync;\n if (sync?.error) {\n return textResult(\n `${started}\\n\\nBase sync: dev → ${sync.branch} failed — ${sync.error}. ` +\n `The child was launched from the un-synced pack branch. Merge dev into ${sync.branch} ` +\n `in your local checkout, resolve the conflicts, and push before firing more children.`,\n );\n }\n return textResult(started);\n } catch (error) {\n return textResult(\n `Failed to start child cloud build: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n ),\n defineTool(\n \"stop_child_build\",\n \"Send a graceful stop signal to a running child build's agent. Not a force-kill — the agent may take a moment to wind down. Stopping a child eventually frees its PACK_CHILD_LIMIT build slot (see list_subtasks packSlots).\",\n {\n childTaskId: z.string().describe(\"The child task ID whose build should be stopped\"),\n },\n async ({ childTaskId }) => {\n try {\n await connection.call(\"stopChildBuild\", {\n sessionId: connection.sessionId,\n childTaskId,\n });\n return textResult(`Stop signal sent to child task: ${childTaskId}`);\n } catch (error) {\n return textResult(\n `Failed to stop child build: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n ),\n defineContractTool(approveAndMergePrContract, async ({ childTaskId }) => {\n try {\n const result = await connection.call(\"approveAndMergePR\", {\n sessionId: connection.sessionId,\n childTaskId,\n });\n if (result.merged) {\n return textResult(\n `PR #${result.prNumber} approved and merged for task ${result.childTaskId}. Task status updated to ReviewDev.`,\n );\n }\n return textResult(\n `PR #${result.prNumber} merge queued for task ${result.childTaskId} — CI checks still in progress. The PR will auto-merge when all checks pass. Do NOT proceed as if merged. Wait for the child task status to change to ReviewDev before continuing.`,\n );\n } catch (error) {\n return textResult(\n `Failed to approve and merge PR: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }),\n ];\n}\n\nexport function buildPmTools(\n connection: AgentConnection,\n options?: { includePackTools?: boolean },\n) {\n const tools = [\n buildUpdateTaskTool(connection),\n buildCreateSubtaskTool(connection),\n buildUpdateSubtaskTool(connection),\n buildDeleteSubtaskTool(connection),\n buildListSubtasksTool(connection),\n ];\n if (!options?.includePackTools) return tools;\n return [...tools, ...buildPackTools(connection)];\n}\n","import { z } from \"zod\";\nimport { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult } from \"./helpers.js\";\n\nconst SP_DESCRIPTION =\n \"Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique). The key is 'storyPointValue' — not 'storyPoints'.\";\n\nconst VALID_PROPERTY_KEYS = \"title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk\";\n\ninterface TaskPropertyParams {\n title?: string;\n storyPointValue?: number;\n tagNames?: string[];\n githubPRUrl?: string;\n githubBranch?: string;\n risk?: \"critical\" | \"high\" | \"medium\" | \"low\" | null;\n}\n\n/** Human-readable summary of the fields an update touched. */\nfunction describeUpdatedFields(p: TaskPropertyParams): string[] {\n const fields: string[] = [];\n if (p.title !== undefined) fields.push(`title to \"${p.title}\"`);\n if (p.storyPointValue !== undefined) fields.push(`story points to ${p.storyPointValue}`);\n if (p.tagNames !== undefined) fields.push(`tags (${p.tagNames.length} tag(s))`);\n if (p.githubPRUrl !== undefined) fields.push(`PR link to \"${p.githubPRUrl}\"`);\n if (p.githubBranch !== undefined) fields.push(`branch to \"${p.githubBranch}\"`);\n if (p.risk !== undefined) fields.push(`risk to ${p.risk ?? \"cleared\"}`);\n return fields;\n}\n\nexport function buildDiscoveryTools(connection: AgentConnection) {\n return [\n defineTool(\n \"update_task_properties\",\n \"Set one or more task properties in a single call. Valid keys: title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk. All are optional — include only the ones you want to update (at least one). Unknown keys are rejected.\",\n {\n title: z.string().optional().describe(\"The new task title\"),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n tagNames: z.array(z.string()).optional().describe(\"Array of tag names to assign\"),\n githubPRUrl: z\n .string()\n .url()\n .optional()\n .describe(\"GitHub pull request URL to link to this task\"),\n githubBranch: z\n .string()\n .optional()\n .describe(\"Set the GitHub branch name for this task (e.g. 'conveyor/my-feature-abc123')\"),\n risk: z\n .enum([\"critical\", \"high\", \"medium\", \"low\"])\n .nullable()\n .optional()\n .describe(\n \"Risk level — how much important surface the task touches (critical/high/medium/low). Pass null to clear.\",\n ),\n },\n async ({ title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk }) => {\n try {\n const params: TaskPropertyParams = {\n title,\n storyPointValue,\n tagNames,\n githubPRUrl,\n githubBranch,\n risk,\n };\n const updatedFields = describeUpdatedFields(params);\n if (updatedFields.length === 0) {\n // Zod strips unrecognized keys on harnesses that don't enforce the\n // strict schema, so a misspelled key (e.g. \"storyPoints\") arrives\n // here as an empty update. Fail loudly instead of no-oping.\n return textResult(\n `No task properties were updated: none of the recognized keys were provided. ` +\n `Valid keys: ${VALID_PROPERTY_KEYS}. ` +\n `(Story points are set via 'storyPointValue', not 'storyPoints'.)`,\n );\n }\n\n await connection.call(\"updateTaskProperties\", {\n sessionId: connection.sessionId,\n ...params,\n });\n\n return textResult(`Task properties updated: ${updatedFields.join(\", \")}`);\n } catch (error) {\n return textResult(\n `Failed to update task properties: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n // Reject unknown keys (e.g. \"storyPoints\") at validation instead of\n // stripping them into a silent no-op — every field here is optional, so\n // a stripped typo would otherwise report success while updating nothing.\n { strict: true },\n ),\n ];\n}\n","/**\n * Project-scoped tools for TASK-LESS sessions (headless audits on ad-hoc\n * pods). Everything is keyed on the projectId the runner was booted with —\n * there is no task, so none of these resolve state from the session's task.\n *\n * Two families:\n * - Tag-audit apply surface: list/create/update tags, suggestions, project chat.\n * - Task-audit evidence + reporting: cross-task reads (task, chat, execution\n * logs) and reportTaskAuditResult persistence.\n */\nimport { z } from \"zod\";\nimport type { AgentSessionServiceMethods } from \"@project/shared\";\nimport {\n CONTEXT_LINK_LOCATOR_MAX,\n TAG_DESCRIPTION_MAX,\n TAG_OVERVIEW_MAX,\n TAG_REASON_MAX,\n} from \"@project/shared\";\nimport {\n createSuggestionContract,\n getTagContract,\n listTagsContract,\n searchTasksContract,\n} from \"@project/shared/tool-contracts\";\nimport { defineTool } from \"../harness/index.js\";\nimport {\n formatContextPathProblems,\n verifyContextPaths,\n type ContextPathInput,\n} from \"../execution/context-path-verifier.js\";\nimport { defineContractTool } from \"./contract-tool.js\";\nimport { textResult } from \"./helpers.js\";\n\n/**\n * The one connection capability these tools need — satisfied by the real\n * AgentConnection and by the adhoc runner's injectable AdhocRunnerConnection.\n */\nexport interface ProjectToolsConnection {\n call<M extends keyof AgentSessionServiceMethods>(\n method: M,\n payload: AgentSessionServiceMethods[M][\"payload\"],\n ): Promise<AgentSessionServiceMethods[M][\"response\"]>;\n}\n\nconst CONTEXT_PATH_SHAPE = z\n .object({\n type: z\n .enum([\"rule\", \"doc\", \"file\", \"folder\"])\n .describe(\n \"Link kind — all paths are repo-relative; doc marks a synced project doc, which resolves from the workspace like rule/file\",\n ),\n path: z.string().min(1).max(500).describe(\"Repo-relative path\"),\n label: z.string().max(100).optional(),\n locator: z\n .string()\n .min(1)\n .max(CONTEXT_LINK_LOCATOR_MAX)\n .regex(/^[^\\r\\n]*$/, \"Locator cannot contain line breaks\")\n .optional()\n .describe(\n 'Verified-link tether: text that must keep existing in the file. With locatorType \"test\" it must appear inside a real it/test/describe TITLE; with \"code\" anywhere in the file. Validated at write time against the checkout and re-checked by the periodic sweep — a rename/delete flags the link stale. Locators containing <> are placeholders and never checked.',\n ),\n locatorType: z\n .enum([\"test\", \"code\"])\n .optional()\n .describe('How the locator must match — required iff locator is set; not valid on folder links'),\n })\n .refine((link) => (link.locator === undefined) === (link.locatorType === undefined), {\n message: \"locator and locatorType must be provided together\",\n })\n .refine((link) => link.locator === undefined || link.type !== \"folder\", {\n message: \"folder links cannot carry a locator\",\n });\n\nfunction errText(prefix: string, error: unknown): { content: { type: \"text\"; text: string }[] } {\n return textResult(`${prefix}: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n}\n\n/**\n * Gate contextPaths on the workspace checkout before they reach the API. The\n * API cannot stat the repo, so this is the only place a typo can be caught at\n * write time. Returns a rejection to hand back to the agent, or null to\n * proceed. Validation is skipped when the caller has no workspace path.\n */\nasync function rejectBadContextPaths(\n contextPaths: ContextPathInput[] | undefined,\n workspaceDir: string | undefined,\n): Promise<{ content: { type: \"text\"; text: string }[] } | null> {\n if (!workspaceDir || !contextPaths?.length) return null;\n const problems = await verifyContextPaths(contextPaths, workspaceDir);\n return problems.length > 0 ? textResult(formatContextPathProblems(problems)) : null;\n}\n\n// ── Tag audit surface ─────────────────────────────────────────────────\n\nfunction buildListTagsTool(connection: ProjectToolsConnection, projectId: string) {\n return defineContractTool(\n listTagsContract,\n async () => {\n try {\n const tags = await connection.call(\"listProjectTags\", { projectId });\n return textResult(JSON.stringify(tags, null, 2));\n } catch (error) {\n return errText(\"Failed to list tags\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nfunction buildGetTagTool(connection: ProjectToolsConnection, projectId: string) {\n return defineContractTool(\n getTagContract,\n async ({ tag }) => {\n try {\n const detail = await connection.call(\"getProjectTag\", { projectId, tag });\n return textResult(JSON.stringify(detail, null, 2));\n } catch (error) {\n return errText(\"Failed to get tag\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nfunction buildCreateTagTool(\n connection: ProjectToolsConnection,\n projectId: string,\n workspaceDir?: string,\n) {\n return defineTool(\n \"create_tag\",\n \"Create a project tag. Include a crisp description (≤255 chars — the summary) and contextPaths (rule/doc/file/folder links agents auto-load when working on matching tasks); put the full spec in overview. Set parentTagIds to place the tag in the hierarchy right away. Every contextPath is checked against the repo checkout — a path that does not exist, or whose type does not match what is on disk, rejects the whole call. Fails if the name already exists.\",\n {\n name: z.string().min(1).max(50),\n color: z\n .string()\n .regex(/^#[0-9a-fA-F]{6}$/)\n .optional()\n .describe(\"#RRGGBB (default gray)\"),\n description: z.string().max(TAG_DESCRIPTION_MAX).optional(),\n overview: z\n .string()\n .max(TAG_OVERVIEW_MAX)\n .optional()\n .describe(\"Full markdown glossary body — the term's spec\"),\n overviewPath: z\n .string()\n .min(1)\n .max(500)\n .optional()\n .describe(\n \"Repo file to source the overview from (base-branch content is served everywhere). A not-yet-merged path is fine — the tag serves the stored overview as fallback until the file lands.\",\n ),\n parentTagIds: z\n .array(z.string())\n .max(25)\n .optional()\n .describe(\"Parent tag ids from list_tags (multi-parent DAG) to link at create time\"),\n contextPaths: z.array(CONTEXT_PATH_SHAPE).max(20).optional(),\n },\n async ({ name, color, description, overview, overviewPath, parentTagIds, contextPaths }) => {\n const rejection = await rejectBadContextPaths(contextPaths, workspaceDir);\n if (rejection) return rejection;\n try {\n const result = await connection.call(\"createProjectTag\", {\n projectId,\n name,\n color,\n description,\n overview,\n overviewPath,\n parentTagIds,\n contextPaths,\n });\n return textResult(`Tag created: ${result.id}`);\n } catch (error) {\n return errText(\"Failed to create tag\", error);\n }\n },\n );\n}\n\nfunction buildUpdateTagTool(\n connection: ProjectToolsConnection,\n projectId: string,\n taskId?: string,\n workspaceDir?: string,\n) {\n return defineTool(\n \"update_tag\",\n \"Update a tag's name, color, description (≤255), markdown overview, parent tags, or contextPaths. contextPaths and parentTagIds are FULL replacements — include what you want to keep. ALWAYS pass a short reason; it lands in the tag's revision history (with your current card auto-stamped) so the team sees why the glossary changed. Every contextPath is checked against the repo checkout — a path that does not exist, or whose type does not match what is on disk, rejects the whole call and nothing is written.\",\n {\n tagId: z.string().describe(\"Tag id from list_tags\"),\n name: z.string().min(1).max(50).optional(),\n color: z\n .string()\n .regex(/^#[0-9a-fA-F]{6}$/)\n .optional(),\n description: z.string().max(TAG_DESCRIPTION_MAX).optional(),\n overview: z\n .string()\n .max(TAG_OVERVIEW_MAX)\n .nullable()\n .optional()\n .describe(\n \"Full markdown glossary body; null clears it. REJECTED while overviewPath is set — edit the sourced file in the repo instead\",\n ),\n overviewPath: z\n .string()\n .min(1)\n .max(500)\n .nullable()\n .optional()\n .describe(\n \"Repo file to source the overview from (null clears back to the stored overview). A not-yet-merged path is fine — the stored overview serves as fallback until the file lands on the base branch.\",\n ),\n parentTagIds: z\n .array(z.string())\n .max(25)\n .optional()\n .describe(\"Full-set replacement of the tag's parent tags (multi-parent DAG)\"),\n reason: z\n .string()\n .max(TAG_REASON_MAX)\n .optional()\n .describe(\"One line on why — shown in the tag's revision history\"),\n contextPaths: z.array(CONTEXT_PATH_SHAPE).max(20).optional(),\n },\n async ({\n tagId,\n name,\n color,\n description,\n overview,\n overviewPath,\n parentTagIds,\n reason,\n contextPaths,\n }) => {\n const rejection = await rejectBadContextPaths(contextPaths, workspaceDir);\n if (rejection) return rejection;\n try {\n await connection.call(\"updateProjectTag\", {\n projectId,\n tagId,\n name,\n color,\n description,\n overview,\n overviewPath,\n parentTagIds,\n reason,\n taskId,\n contextPaths,\n });\n return textResult(`Tag updated: ${tagId}`);\n } catch (error) {\n return errText(\"Failed to update tag\", error);\n }\n },\n );\n}\n\nfunction buildCreateSuggestionTool(connection: ProjectToolsConnection, projectId: string) {\n return defineContractTool(createSuggestionContract, async ({ title, description, tag_names }) => {\n try {\n const result = await connection.call(\"createProjectSuggestion\", {\n projectId,\n title,\n description,\n tagNames: tag_names,\n });\n return textResult(\n result.merged\n ? `Merged into existing suggestion ${result.mergedIntoId ?? result.id} (id: ${result.id})`\n : `Suggestion created: ${result.id}`,\n );\n } catch (error) {\n return errText(\"Failed to create suggestion\", error);\n }\n });\n}\n\nfunction buildPostToProjectChatTool(connection: ProjectToolsConnection, projectId: string) {\n return defineTool(\n \"post_to_project_chat\",\n \"Post a markdown message to the PROJECT chat — use once at the end of an audit for the summary the team reads.\",\n {\n message: z.string().min(1).max(20000),\n kind: z\n .enum([\"tag_audit_summary\"])\n .optional()\n .describe(\n \"Set to 'tag_audit_summary' when posting a tag-audit summary so it is also saved to the persistent tag history\",\n ),\n },\n async ({ message, kind }) => {\n try {\n await connection.call(\"postToProjectChat\", { projectId, content: message, kind });\n return textResult(\"Posted to project chat\");\n } catch (error) {\n return errText(\"Failed to post to project chat\", error);\n }\n },\n );\n}\n\n// ── Task audit surface ────────────────────────────────────────────────\n\nfunction buildGetProjectTaskTool(connection: ProjectToolsConnection, projectId: string) {\n return defineTool(\n \"get_project_task\",\n \"Fetch any task in the project by id or slug: title, description, plan, status, and metadata. The audit evidence trail starts here.\",\n {\n taskId: z.string().describe(\"Task id or slug\"),\n },\n async ({ taskId }) => {\n try {\n const task = await connection.call(\"getProjectTask\", { projectId, taskId });\n return textResult(JSON.stringify(task, null, 2));\n } catch (error) {\n return errText(\"Failed to get task\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nfunction buildReadProjectTaskChatTool(connection: ProjectToolsConnection, projectId: string) {\n return defineTool(\n \"read_project_task_chat\",\n \"Read any project task's chat messages (newest last). role 'user' rows are HUMAN turns; 'assistant'/'system' rows are agent posts and activity-log entries.\",\n {\n taskId: z.string().describe(\"Task id or slug\"),\n limit: z.number().int().min(1).max(200).optional().describe(\"Messages to fetch (default 50)\"),\n },\n async ({ taskId, limit }) => {\n try {\n const chat = await connection.call(\"getProjectTaskChat\", {\n projectId,\n taskId,\n limit: limit ?? 50,\n });\n return textResult(JSON.stringify(chat, null, 2));\n } catch (error) {\n return errText(\"Failed to read task chat\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nfunction buildGetProjectTaskLogsTool(connection: ProjectToolsConnection, projectId: string) {\n return defineTool(\n \"get_project_task_logs\",\n \"Read any project task's persisted agent event stream (message / tool_use / turn_end / error / completed). Turn boundaries are turn_end events. Entries are truncated to ~2KB each; max 500 per call.\",\n {\n taskId: z.string().describe(\"Task id or slug\"),\n limit: z.number().int().min(1).max(500).optional().describe(\"Entries to fetch (default 50)\"),\n source: z\n .enum([\"agent\", \"application\"])\n .optional()\n .describe(\"Filter: 'agent' = model events (default useful for grading)\"),\n },\n async ({ taskId, limit, source }) => {\n try {\n const logs = await connection.call(\"getProjectTaskCli\", {\n projectId,\n taskId,\n limit: limit ?? 50,\n source,\n });\n return textResult(JSON.stringify(logs, null, 2));\n } catch (error) {\n return errText(\"Failed to get task logs\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nconst TURN_GRADE_SHAPE = z.object({\n turnIndex: z.number().int().min(0),\n phase: z.enum([\"planning\", \"building\", \"human\"]),\n grade: z.enum([\"correct\", \"neutral\", \"blunder\"]),\n reasoning: z.string(),\n eventType: z.string().describe('e.g. \"message\", \"tool_use\", \"human_message\"'),\n eventSummary: z.string().max(200).describe(\"≤120 chars of what happened this turn\"),\n});\n\nconst HUMAN_EVAL_SHAPE = z.object({\n messageIndex: z\n .number()\n .int()\n .min(0)\n .describe(\"Index into the task's human messages, oldest first\"),\n rating: z.number().int().min(-1).max(1),\n reasoning: z.string(),\n});\n\nfunction buildReportTaskAuditResultTool(connection: ProjectToolsConnection, projectId: string) {\n return defineTool(\n \"report_task_audit_result\",\n \"Persist one audited task's grades (call once per task after grading it). Pass error instead to mark the audit failed when the evidence is unusable.\",\n {\n taskId: z.string().describe(\"The audited task's id (NOT slug)\"),\n summary: z.string().describe(\"3-6 sentences: what went well, what was wasted\"),\n turnGrades: z.array(TURN_GRADE_SHAPE),\n planningAccuracy: z.number().min(0).max(1).nullable(),\n buildingAccuracy: z.number().min(0).max(1).nullable(),\n humanAccuracy: z.number().min(0).max(1).nullable(),\n planningCorrect: z.number().int().min(0),\n planningNeutral: z.number().int().min(0),\n planningBlunder: z.number().int().min(0),\n buildingCorrect: z.number().int().min(0),\n buildingNeutral: z.number().int().min(0),\n buildingBlunder: z.number().int().min(0),\n humanCorrect: z.number().int().min(0),\n humanNeutral: z.number().int().min(0),\n humanBlunder: z.number().int().min(0),\n humanEvaluations: z.array(HUMAN_EVAL_SHAPE).optional(),\n suggestionIds: z.array(z.string()).describe(\"Suggestion ids filed for this task, or []\"),\n auditCostUsd: z.number().nullable(),\n model: z.string().nullable().describe(\"The model you are running as\"),\n error: z.string().optional().describe(\"Set ONLY to mark this task's audit failed\"),\n },\n async (input) => {\n try {\n await connection.call(\"reportTaskAuditResult\", {\n projectId,\n ...input,\n humanEvaluations: (input.humanEvaluations ?? []) as Array<{\n messageIndex: number;\n rating: -1 | 0 | 1;\n reasoning: string;\n }>,\n });\n return textResult(\n input.error\n ? `Audit for ${input.taskId} marked failed`\n : `Audit result saved for ${input.taskId}`,\n );\n } catch (error) {\n return errText(\"Failed to report audit result\", error);\n }\n },\n );\n}\n\n// ── Card search ───────────────────────────────────────────────────────\n\n/**\n * Tag-first card search across the whole project. The glossary is only useful\n * if you can go from a term to the cards that carry it, so this ships wherever\n * list_tags/get_tag do — card sessions included, not just headless audits.\n */\nfunction buildSearchTasksTool(connection: ProjectToolsConnection, projectId: string) {\n return defineContractTool(\n searchTasksContract,\n async (params) => {\n try {\n const tasks = await connection.call(\"searchProjectTasks\", { projectId, ...params });\n return textResult(JSON.stringify(tasks, null, 2));\n } catch (error) {\n return errText(\"Failed to search tasks\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\n// ── Assembly ──────────────────────────────────────────────────────────\n\n/**\n * The glossary surface for TASK-mode card agents: read the project vocabulary\n * (list_tags / get_tag), find the cards that carry a term (search_tasks), and\n * maintain the vocabulary (update_tag) — the session's card is stamped into\n * every revision for provenance.\n */\nexport function buildGlossaryTools(\n connection: ProjectToolsConnection,\n projectId: string,\n taskId?: string,\n workspaceDir?: string,\n) {\n return [\n buildListTagsTool(connection, projectId),\n buildGetTagTool(connection, projectId),\n buildSearchTasksTool(connection, projectId),\n buildUpdateTagTool(connection, projectId, taskId, workspaceDir),\n ];\n}\n\n/** The full project-scoped tool surface a headless (task-less) session gets. */\nexport function buildProjectTools(\n connection: ProjectToolsConnection,\n projectId: string,\n workspaceDir?: string,\n) {\n return [\n buildListTagsTool(connection, projectId),\n buildGetTagTool(connection, projectId),\n buildSearchTasksTool(connection, projectId),\n buildCreateTagTool(connection, projectId, workspaceDir),\n buildUpdateTagTool(connection, projectId, undefined, workspaceDir),\n buildCreateSuggestionTool(connection, projectId),\n buildPostToProjectChatTool(connection, projectId),\n buildGetProjectTaskTool(connection, projectId),\n buildReadProjectTaskChatTool(connection, projectId),\n buildGetProjectTaskLogsTool(connection, projectId),\n buildReportTaskAuditResultTool(connection, projectId),\n ];\n}\n","/**\n * Write-time validation for contextPath links (tags today, sub-projects when\n * they get a write tool).\n *\n * A contextPath is a repo-relative pointer agents auto-load. Before this, a\n * typo was only noticed at READ time, where `tag-context-resolver` maps a\n * missing path to a null summary and counts it in `stats.skipped` — the tag\n * looks fine in the UI while quietly delivering less context every session.\n *\n * The API server has no repo checkout, so the in-pod tools are the only write\n * surface that can see the tree. This module is that gate.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { isAbsolute, join, normalize } from \"node:path\";\nimport { isPlaceholderLocator, locatorMatchesContent } from \"@project/shared\";\nimport { statWorkspacePath } from \"../workbench/fs.js\";\n\nexport interface ContextPathInput {\n type: string;\n path: string;\n label?: string;\n locator?: string;\n locatorType?: \"test\" | \"code\";\n}\n\nexport type ContextPathProblemReason =\n | \"not_found\"\n | \"expected_folder\"\n | \"expected_file\"\n | \"not_repo_relative\"\n | \"locator_not_found\";\n\nexport interface ContextPathProblem {\n type: string;\n path: string;\n reason: ContextPathProblemReason;\n /** The locator that missed, on locator problems. */\n locator?: string;\n}\n\nconst PROBLEM_TEXT: Record<ContextPathProblemReason, string> = {\n not_found: \"does not exist in the repo\",\n expected_folder: \"is a file, not a folder — use type 'file', 'rule', or 'doc'\",\n expected_file: \"is a directory — use type 'folder'\",\n not_repo_relative: \"is not repo-relative (drop the leading '/' and any '..')\",\n locator_not_found: \"has a locator that does not match the file\",\n};\n\n/** Don't read pathological files into memory just to check a locator. */\nconst MAX_LOCATOR_FILE_BYTES = 2 * 1024 * 1024;\n\n/**\n * Check a link's locator against the real file. `null` = fine (matches, is a\n * placeholder, or the file could not be read — the async sweep owns judging\n * unreadable content); a problem = the locator demonstrably does not match.\n */\nasync function verifyLocator(\n link: ContextPathInput,\n absolutePath: string,\n fileSize: number | undefined,\n): Promise<ContextPathProblem | null> {\n const { locator, locatorType } = link;\n if (!locator || !locatorType || isPlaceholderLocator(locator)) return null;\n if (fileSize !== undefined && fileSize > MAX_LOCATOR_FILE_BYTES) return null;\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch {\n return null;\n }\n if (locatorMatchesContent(content, locatorType, locator)) return null;\n return { type: link.type, path: link.path, reason: \"locator_not_found\", locator };\n}\n\n/** Every link type resolves from the workspace: project docs are synced from\n * the repo, so a 'doc' path is a workspace path too. Only 'folder' expects a\n * directory; 'rule', 'doc', and 'file' all expect a regular file. */\nfunction expectsDirectory(type: string): boolean {\n return type === \"folder\";\n}\n\nfunction classifyShape(rawPath: string): ContextPathProblemReason | \"ok\" {\n const trimmed = rawPath.trim();\n if (!trimmed) return \"not_found\";\n if (isAbsolute(trimmed)) return \"not_repo_relative\";\n const normalized = normalize(trimmed);\n if (normalized === \"..\" || normalized.startsWith(\"../\")) return \"not_repo_relative\";\n return \"ok\";\n}\n\n/** Strip the noise agents commonly add around a repo-relative path. */\nfunction toRelativePath(rawPath: string): string {\n return rawPath.trim().replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\n\n/**\n * Stat every link against the workspace checkout and return the ones that do\n * not hold up. An empty array means every path is good.\n */\nexport async function verifyContextPaths(\n links: ContextPathInput[] | null | undefined,\n workspaceDir: string,\n): Promise<ContextPathProblem[]> {\n if (!links?.length) return [];\n const problems: ContextPathProblem[] = [];\n\n for (const link of links) {\n const shape = classifyShape(link.path);\n if (shape !== \"ok\") {\n problems.push({ type: link.type, path: link.path, reason: shape });\n continue;\n }\n\n const absolutePath = join(workspaceDir, toRelativePath(link.path));\n const stat = await statWorkspacePath(absolutePath);\n const wantsDirectory = expectsDirectory(link.type);\n if (!stat.exists) {\n problems.push({ type: link.type, path: link.path, reason: \"not_found\" });\n } else if (wantsDirectory && !stat.isDirectory) {\n problems.push({ type: link.type, path: link.path, reason: \"expected_folder\" });\n } else if (!wantsDirectory && stat.isDirectory) {\n problems.push({ type: link.type, path: link.path, reason: \"expected_file\" });\n } else if (!wantsDirectory) {\n const locatorProblem = await verifyLocator(link, absolutePath, stat.size);\n if (locatorProblem) problems.push(locatorProblem);\n }\n }\n\n return problems;\n}\n\n/**\n * The rejection an agent reads. It names every bad path so the agent can fix\n * them all in one turn instead of retrying one at a time.\n */\nexport function formatContextPathProblems(problems: ContextPathProblem[]): string {\n const count = problems.length;\n return [\n `Rejected — ${count} contextPath${count === 1 ? \"\" : \"s\"} failed validation against the repo checkout:`,\n ...problems.map((p) => {\n const locator = p.locator === undefined ? \"\" : ` (locator \"${p.locator}\")`;\n return `- ${p.type} \"${p.path}\"${locator} ${PROBLEM_TEXT[p.reason]}`;\n }),\n 'Nothing was written. contextPaths are repo-relative (e.g. \"apps/api/src/services/tag\"); a `test` locator must appear inside a real it/test/describe title in the file, a `code` locator anywhere in it. Check with ls/grep, then call the tool again.',\n ].join(\"\\n\");\n}\n","/**\n * Google Drive file CRUD for pod agents.\n *\n * These tools travel with every card whose project has a Google Drive folder\n * connected — that is what \"the Drive integrates automatically on pods\" means\n * in practice. The pod holds no Google credential: each tool is a thin wrapper\n * over an agent-session method, and the API resolves the project's encrypted\n * refresh token, mints a short-lived access token, and confines the operation\n * to the project's configured root folder.\n *\n * Every failure is returned as text rather than thrown, so a Drive outage or a\n * disconnected project degrades into a message the agent can read and act on.\n */\n\nimport { z } from \"zod\";\nimport type { AgentSessionServiceMethods } from \"@project/shared\";\nimport { defineTool, type HarnessToolDefinition } from \"../harness/index.js\";\nimport { textResult } from \"./helpers.js\";\n\n/** The one connection capability these tools need. */\nexport interface DriveToolsConnection {\n call<M extends keyof AgentSessionServiceMethods>(\n method: M,\n payload: AgentSessionServiceMethods[M][\"payload\"],\n ): Promise<AgentSessionServiceMethods[M][\"response\"]>;\n}\n\n/** Largest body these tools accept, matching MAX_FILE_BYTES on the API. */\nconst MAX_CONTENT_CHARS = 1_000_000;\n\n/**\n * Cap on what a read hands back to the agent, well below the API's 1 MB write\n * limit. A megabyte of text is roughly 250k tokens — more than the context\n * window of the models these pods run, so one read of a large file would end the\n * session rather than return an answer.\n */\nconst MAX_READ_CHARS = 100_000;\n\nfunction errText(prefix: string, error: unknown): { content: { type: \"text\"; text: string }[] } {\n return textResult(`${prefix}: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n}\n\nexport function buildDriveListFilesTool(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition {\n return defineTool(\n \"drive_list_files\",\n \"List files and folders in the project's connected Google Drive folder. Omit folderId to list the project's root folder. Returns id, name, mimeType, size, and modified time for each entry.\",\n {\n folderId: z\n .string()\n .optional()\n .describe(\"Folder to list. Defaults to the project's connected root folder.\"),\n search: z.string().max(200).optional().describe(\"Only return names containing this text\"),\n limit: z.number().int().min(1).max(200).optional().describe(\"Max entries (default 100)\"),\n },\n async ({ folderId, search, limit }) => {\n try {\n const result = await connection.call(\"listProjectDriveFiles\", {\n projectId,\n folderId,\n search,\n limit,\n });\n return textResult(JSON.stringify(result, null, 2));\n } catch (error) {\n return errText(\"Failed to list Google Drive files\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildDriveReadFileTool(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition {\n return defineTool(\n \"drive_read_file\",\n \"Read a file's text content from the project's connected Google Drive folder. Google Docs, Sheets, and Slides are exported to text automatically. Content over 100 KB is truncated.\",\n { fileId: z.string().describe(\"Drive file id, as returned by drive_list_files\") },\n async ({ fileId }) => {\n try {\n const result = await connection.call(\"readProjectDriveFile\", { projectId, fileId });\n const overReadCap = result.content.length > MAX_READ_CHARS;\n const content = overReadCap ? result.content.slice(0, MAX_READ_CHARS) : result.content;\n const notes = [\n result.exported ? \"(exported from a Google-native document)\" : null,\n result.truncated || overReadCap ? \"(truncated at the 100 KB read limit)\" : null,\n ].filter(Boolean);\n const header = `${result.file.name} ${notes.join(\" \")}`.trim();\n return textResult(`${header}\\n\\n${content}`);\n } catch (error) {\n return errText(\"Failed to read the Google Drive file\", error);\n }\n },\n { annotations: { readOnlyHint: true } },\n );\n}\n\nexport function buildDriveCreateFileTool(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition {\n return defineTool(\n \"drive_create_file\",\n \"Create a new file in the project's connected Google Drive folder. Use drive_update_file to change an existing file instead.\",\n {\n name: z.string().min(1).max(255).describe(\"File name, without any path separators\"),\n content: z.string().max(MAX_CONTENT_CHARS).describe(\"File content, UTF-8 text\"),\n mimeType: z.string().optional().describe(\"MIME type (default text/plain)\"),\n folderId: z\n .string()\n .optional()\n .describe(\"Destination folder. Defaults to the project's connected root folder.\"),\n },\n async ({ name, content, mimeType, folderId }) => {\n try {\n const file = await connection.call(\"createProjectDriveFile\", {\n projectId,\n name,\n content,\n mimeType,\n folderId,\n });\n return textResult(`Created \"${file.name}\" (${file.id})`);\n } catch (error) {\n return errText(\"Failed to create the Google Drive file\", error);\n }\n },\n );\n}\n\nexport function buildDriveUpdateFileTool(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition {\n return defineTool(\n \"drive_update_file\",\n \"Replace the content of an existing file in the project's connected Google Drive folder. This overwrites the whole file. Google-native documents cannot be overwritten.\",\n {\n fileId: z.string().describe(\"Drive file id, as returned by drive_list_files\"),\n content: z.string().max(MAX_CONTENT_CHARS).describe(\"Replacement content, UTF-8 text\"),\n mimeType: z.string().optional().describe(\"MIME type (defaults to the file's current type)\"),\n },\n async ({ fileId, content, mimeType }) => {\n try {\n const file = await connection.call(\"updateProjectDriveFile\", {\n projectId,\n fileId,\n content,\n mimeType,\n });\n return textResult(`Updated \"${file.name}\" (${file.id})`);\n } catch (error) {\n return errText(\"Failed to update the Google Drive file\", error);\n }\n },\n );\n}\n\nexport function buildDriveDeleteFileTool(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition {\n return defineTool(\n \"drive_delete_file\",\n \"Move a file in the project's connected Google Drive folder to the Drive trash. The file is recoverable from the trash; it is never permanently deleted.\",\n { fileId: z.string().describe(\"Drive file id, as returned by drive_list_files\") },\n async ({ fileId }) => {\n try {\n const result = await connection.call(\"deleteProjectDriveFile\", { projectId, fileId });\n return textResult(`Moved \"${result.name}\" (${result.id}) to the Google Drive trash`);\n } catch (error) {\n return errText(\"Failed to delete the Google Drive file\", error);\n }\n },\n );\n}\n\nexport function buildDriveCreateFolderTool(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition {\n return defineTool(\n \"drive_create_folder\",\n \"Create a folder inside the project's connected Google Drive folder.\",\n {\n name: z.string().min(1).max(255).describe(\"Folder name, without any path separators\"),\n folderId: z\n .string()\n .optional()\n .describe(\"Parent folder. Defaults to the project's connected root folder.\"),\n },\n async ({ name, folderId }) => {\n try {\n const folder = await connection.call(\"createProjectDriveFolder\", {\n projectId,\n name,\n folderId,\n });\n return textResult(`Created folder \"${folder.name}\" (${folder.id})`);\n } catch (error) {\n return errText(\"Failed to create the Google Drive folder\", error);\n }\n },\n );\n}\n\n/**\n * Build the `drive_*` tool set for a project. `projectId` is bound at build\n * time so an agent can never point these at another project.\n */\nexport function buildDriveTools(\n connection: DriveToolsConnection,\n projectId: string,\n): HarnessToolDefinition[] {\n return [\n buildDriveListFilesTool(connection, projectId),\n buildDriveReadFileTool(connection, projectId),\n buildDriveCreateFileTool(connection, projectId),\n buildDriveUpdateFileTool(connection, projectId),\n buildDriveDeleteFileTool(connection, projectId),\n buildDriveCreateFolderTool(connection, projectId),\n ];\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { ReviewGuideContentSchema } from \"@project/shared\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { getWorkbenchClient } from \"../workbench/client.js\";\nimport { workbenchEnabled } from \"../workbench/mode.js\";\nimport { textResult } from \"./helpers.js\";\n\nasync function endReviewSession(\n connection: AgentConnection,\n reason: \"approved\" | \"changes_requested\",\n): Promise<void> {\n await connection.call(\"endReviewSession\", {\n sessionId: connection.sessionId,\n reason,\n });\n}\n\n// Canonical risk levels — mirror RISK_LEVELS in @project/shared (conveyor-agent\n// is published standalone without the shared dep). The reviewer MUST choose one\n// on every verdict; the server applies it authoritatively (may raise OR lower an\n// already-set value).\nconst RISK_LEVELS = [\"critical\", \"high\", \"medium\", \"low\"] as const;\nconst reviewedShaSchema = z\n .string()\n .regex(/^[0-9a-f]{40}$/i)\n .describe(\"REQUIRED. The full 40-character commit SHA this verdict reviews.\");\n\nconst riskDescription =\n \"REQUIRED. The risk level this change carries, judged by the surface area it touches: \" +\n \"critical = touches critical/foundational surface, high = important surface, medium = moderate, \" +\n \"low = small/isolated. Set this on every verdict. You have authority to override a risk level \" +\n \"already set on the task if you disagree with it.\";\n\n// @project/shared uses Zod 3 while the agent MCP harness uses Zod 4. Keep the\n// MCP-facing shape local, then validate its content with the shared schema in\n// the handler before sending it over the agent-session boundary.\nconst ReviewGuideToolSchema = z.strictObject({\n reviewedSha: z\n .string()\n .regex(/^[0-9a-f]{40}$/i)\n .describe(\n \"REQUIRED. The PR's current head as a full 40-char SHA. Run `git rev-parse HEAD` \" +\n \"immediately before this call — never extend an abbreviated hash into 40 characters.\",\n ),\n overview: z\n .string()\n .min(1)\n // The real limit is 3000, enforced by ReviewGuideContentSchema after\n // flattened-payload recovery. The boundary cap is deliberately loose so a\n // mis-encoded call (see recoverFlattenedGuide) reaches the handler and can\n // be repaired, instead of dying as an opaque MCP validation error.\n .max(60_000)\n .describe(\"REQUIRED. Plain-text walkthrough intro, max 3000 characters. Keep it short.\"),\n sections: z\n .array(\n z.strictObject({\n title: z.string().min(1).max(160),\n explanation: z.string().min(1).max(2_000),\n classification: z.enum([\"core\", \"supporting\"]).optional(),\n files: z\n .array(\n z.strictObject({\n path: z\n .string()\n .min(1)\n .max(500)\n .describe(\n \"A file the PR's diff actually changed. Context files you merely read are rejected.\",\n ),\n startLine: z.number().int().positive().max(1_000_000).optional(),\n endLine: z.number().int().positive().max(1_000_000).optional(),\n hunkHeader: z\n .string()\n .min(1)\n .max(300)\n .optional()\n .describe(\n \"Optional anchor, matched byte-exactly against the full hunk header line from \" +\n \"`git diff` INCLUDING the context text after the second @@. Copy it verbatim \" +\n \"from `git diff <base>..HEAD -- <file> | grep '^@@'`, or omit anchors entirely \" +\n \"(path-only entries always validate).\",\n ),\n }),\n )\n .min(1)\n .max(20),\n }),\n )\n .min(1)\n .max(12)\n .optional()\n .describe(\n \"REQUIRED top-level array (never text appended to overview) of ordered conceptual sections.\",\n ),\n});\n\n// A malformed tool-call encoding can deliver the entire call as a single\n// `overview` string, with the following parameter's delimiter embedded\n// verbatim — e.g. `...prose</overview>\\n<parameter name=\"sections\">[{...}]`.\n// 30 of 113 fleet calls in 24h arrived this way and were rejected as\n// \"sections: expected array, received undefined\"; two sessions never managed\n// to publish at all. Recover the real arguments instead of failing, and keep\n// this defensive until the encoding defect itself is fixed upstream.\nconst FLATTENED_SECTIONS_PATTERN = /<\\/overview>\\s*<parameter name=\"sections\">/;\n\nexport function recoverFlattenedGuide(overview: string): {\n overview: string;\n sections: unknown;\n} | null {\n const match = FLATTENED_SECTIONS_PATTERN.exec(overview);\n if (!match) return null;\n const head = overview.slice(0, match.index);\n const tail = overview\n .slice(match.index + match[0].length)\n .replace(/<\\/parameter>\\s*$/, \"\")\n .trim();\n try {\n return { overview: head.trim(), sections: JSON.parse(tail) };\n } catch {\n return null;\n }\n}\n\n// Agents hand-expanded short SHAs from `git log --oneline` into 40 characters,\n// which the server rejects as \"head does not match the reviewed SHA\". Resolving\n// HEAD locally removes the failure mode rather than warning about it.\n//\n// Split-mode pods run this tool's handler in the agent (launcher) container,\n// but the actual repo checkout lives in the workbench container — a bare\n// `execFile` here would run `git rev-parse` against a directory with no repo\n// and silently fail every time. Route through the workbench client when the\n// split is enabled, mirroring `git()` in runner/git-utils.ts.\nexport async function resolveGitHeadSha(cwd: string): Promise<string | null> {\n try {\n const stdout = workbenchEnabled()\n ? (\n await getWorkbenchClient().execFile(\"git\", [\"rev-parse\", \"HEAD\"], {\n cwd,\n timeout: 10_000,\n })\n ).stdout\n : (await promisify(execFile)(\"git\", [\"rev-parse\", \"HEAD\"], { cwd, timeout: 10_000 })).stdout;\n const sha = stdout.trim();\n return /^[0-9a-f]{40}$/i.test(sha) ? sha : null;\n } catch {\n return null;\n }\n}\n\nexport interface PublishReviewGuideOptions {\n /**\n * Resolves the repo's real HEAD. Injected rather than defaulted so the tool\n * stays deterministic under test; the production call site (tools/index.ts)\n * passes `resolveGitHeadSha`. When absent, the agent-supplied SHA is used.\n */\n resolveHeadSha?: () => Promise<string | null>;\n}\n\nexport function buildPublishReviewGuideTool(\n connection: AgentConnection,\n options: PublishReviewGuideOptions = {},\n) {\n const { resolveHeadSha } = options;\n return defineTool(\n \"publish_review_guide\",\n \"Publish or update the PR guide for the CURRENT PR head commit. Call right after create_pull_request succeeds, and again after every push to the branch. The head SHA is resolved from the local repo, so never hand-expand a short hash. Best-effort — it does not gate opening or updating the PR.\",\n ReviewGuideToolSchema.shape,\n async ({ reviewedSha, overview, sections }) => {\n let resolvedOverview = overview;\n let resolvedSections: unknown = sections;\n if (resolvedSections === undefined) {\n const recovered = recoverFlattenedGuide(overview);\n if (!recovered) {\n throw new Error(\n \"publish_review_guide requires a top-level `sections` array — an ordered list of \" +\n \"conceptual sections, each with title, explanation, and files[]. Do not append the \" +\n \"sections to `overview` as text. Retry with sections as a real array argument.\",\n );\n }\n resolvedOverview = recovered.overview;\n resolvedSections = recovered.sections;\n }\n const content = ReviewGuideContentSchema.parse({\n overview: resolvedOverview,\n sections: resolvedSections,\n });\n const result = await connection.call(\"publishReviewGuide\", {\n sessionId: connection.sessionId,\n reviewedSha: (resolveHeadSha ? await resolveHeadSha() : null) ?? reviewedSha,\n ...content,\n });\n return textResult(\n `Review guide published for ${result.reviewedSha}${result.replaced ? \" (replaced)\" : \"\"}.`,\n );\n },\n { strict: true },\n );\n}\n\nfunction buildApproveCodeReviewTool(connection: AgentConnection) {\n return defineTool(\n \"approve_code_review\",\n \"Approve the code review and exit. Use when the diff passes all review criteria. Requires a summary and a risk level — for changes, use request_code_changes with a structured issues[] list.\",\n {\n reviewedSha: reviewedShaSchema,\n summary: z.string().describe(\"Brief summary of what was reviewed and why it looks good\"),\n risk: z.enum(RISK_LEVELS).describe(riskDescription),\n },\n async ({ reviewedSha, summary, risk }) => {\n const content = `**Code Review: Approved** :white_check_mark:\\n\\n${summary}`;\n const result = await connection.call(\"submitCodeReviewResult\", {\n sessionId: connection.sessionId,\n reviewedSha,\n approved: true,\n content,\n risk,\n });\n if (result.applied === false) {\n await endReviewSession(connection, \"approved\");\n return textResult(\n \"This review was superseded by a newer review cycle. No verdict was applied.\",\n );\n }\n connection.sendEvent({ type: \"code_review_complete\", result: \"approved\", summary });\n await endReviewSession(connection, \"approved\");\n return textResult(\"Code review approved. Exiting.\");\n },\n );\n}\n\nfunction buildRequestCodeChangesTool(connection: AgentConnection) {\n return defineTool(\n \"request_code_changes\",\n \"Request changes during code review and exit. Use when substantive issues must be fixed before merge. Each issue: { file, line?, severity: critical|major|minor, description }.\",\n {\n reviewedSha: reviewedShaSchema,\n issues: z\n .array(\n z.object({\n file: z.string().describe(\"File path where the issue was found\"),\n line: z.number().optional().describe(\"Line number (if applicable)\"),\n severity: z.enum([\"critical\", \"major\", \"minor\"]).describe(\"Issue severity\"),\n description: z.string().describe(\"What is wrong and how to fix it\"),\n }),\n )\n .describe(\"List of issues found during review\"),\n summary: z.string().describe(\"Brief overall summary of the review findings\"),\n risk: z.enum(RISK_LEVELS).describe(riskDescription),\n },\n async ({ reviewedSha, issues, summary, risk }) => {\n const issueLines = issues\n .map((issue) => {\n const loc = issue.line ? `:${issue.line}` : \"\";\n return `- **[${issue.severity}]** \\`${issue.file}${loc}\\`: ${issue.description}`;\n })\n .join(\"\\n\");\n const content = `**Code Review: Changes Requested** :warning:\\n\\n${summary}\\n\\n${issueLines}`;\n const result = await connection.call(\"submitCodeReviewResult\", {\n sessionId: connection.sessionId,\n reviewedSha,\n approved: false,\n content,\n risk,\n });\n if (result.applied === false) {\n await endReviewSession(connection, \"changes_requested\");\n return textResult(\n \"This review was superseded by a newer review cycle. No verdict was applied.\",\n );\n }\n connection.sendEvent({\n type: \"code_review_complete\",\n result: \"changes_requested\",\n summary,\n issues,\n });\n await endReviewSession(connection, \"changes_requested\");\n return textResult(\"Code review complete — changes requested. Exiting.\");\n },\n );\n}\n\nexport function buildCodeReviewTools(connection: AgentConnection) {\n return [buildApproveCodeReviewTool(connection), buildRequestCodeChangesTool(connection)];\n}\n","import type { AgentHarness, HarnessToolDefinition } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../runner-types.js\";\nimport type { AgentMode, TaskContext } from \"@project/shared\";\nimport { buildCommonTools, buildForceUpdateTaskStatusTool } from \"./common-tools.js\";\nimport { buildPmTools, buildHandoffTool } from \"./pm-tools.js\";\nimport { buildDiscoveryTools } from \"./discovery-tools.js\";\nimport { buildGlossaryTools } from \"./project-tools.js\";\nimport { buildDriveTools } from \"./drive-tools.js\";\nimport {\n buildCodeReviewTools,\n buildPublishReviewGuideTool,\n resolveGitHeadSha,\n} from \"./code-review-tools.js\";\n\n// Re-export helpers\nexport { textResult, imageBlock } from \"./helpers.js\";\n\n// ── Mode-based tool selection ─────────────────────────────────────────\n\nfunction getTaskModeTools(agentMode: AgentMode | undefined, connection: AgentConnection) {\n // Building is included so auto tasks (which boot straight into building)\n // can document their plan into the card via update_task_plan as they work.\n // Chat is included because saving a plan is how a chat card escalates into a\n // real dev task: the first plan identifies the card, moves it to InProgress,\n // and unlocks its PR path.\n //\n // Subtask CRUD rides along (buildPmTools leads with update_task_plan). A leaf\n // card previously had no way to create a child at all: create_subtask was\n // gated on isParentTask, which is computed from the child count, so a card\n // could never acquire its first child. An agent asked to break its card into\n // a pack fell back to create_follow_up_task, which makes unattached sibling\n // cards. Pack EXECUTION tools stay out — starting child builds and merging\n // child PRs belongs to a human or the pack runner, not a leaf builder.\n if (\n agentMode === \"discovery\" ||\n agentMode === \"auto\" ||\n agentMode === \"building\" ||\n agentMode === \"chat\"\n ) {\n return buildPmTools(connection, { includePackTools: false });\n }\n return [];\n}\n\nfunction getModeTools(\n agentMode: AgentMode | undefined,\n connection: AgentConnection,\n config: AgentRunnerConfig,\n context?: TaskContext,\n) {\n if (config.mode === \"pack\") {\n // Pack runners orchestrate children regardless of the agentMode axis:\n // subtask CRUD + start_child_cloud_build/stop_child_build/\n // approve_and_merge_pr are their whole job (they never build code).\n return buildPmTools(connection, { includePackTools: true });\n }\n if (config.mode === \"task\") return getTaskModeTools(agentMode, connection);\n\n switch (agentMode) {\n case \"building\":\n return context?.isParentTask ? buildPmTools(connection, { includePackTools: true }) : [];\n case \"review\":\n case \"auto\":\n case \"discovery\":\n case \"help\":\n return buildPmTools(connection, {\n includePackTools: !!context?.isParentTask,\n });\n default:\n return config.mode === \"pm\" ? buildPmTools(connection, { includePackTools: false }) : [];\n }\n}\n\n/**\n * The PR guide is authored by the builder as part of opening the PR (and\n * refreshed on each push), so publish_review_guide rides building/auto leaf\n * tasks — not review mode. Parent (pack) cards never open code PRs.\n */\nfunction buildPrGuideToolsFor(\n effectiveMode: AgentMode | undefined,\n connection: AgentConnection,\n config: AgentRunnerConfig,\n context?: TaskContext,\n): HarnessToolDefinition[] {\n const isLeafBuild = effectiveMode === \"building\" || effectiveMode === \"auto\";\n return isLeafBuild && !context?.isParentTask\n ? [\n buildPublishReviewGuideTool(connection, {\n resolveHeadSha: () => resolveGitHeadSha(config.workspaceDir),\n }),\n ]\n : [];\n}\n\n// ── Tool assembly ─────────────────────────────────────────────────────\n\n/**\n * Hot protocol tools preloaded into the model's prompt instead of deferred\n * behind ToolSearch. A 24h fleet transcript audit (2026-07-11) found ~350\n * ToolSearch calls/day, nearly all `select:`-loading these same conveyor\n * tools — every session paid 1–8 round trips just to load its own protocol\n * tools (and several wasted an extra call on bare names). Marking them\n * `alwaysLoad` eliminates those round trips on both harnesses.\n *\n * Keep this the intersection of \"called by virtually every session in the\n * mode that exposes it\" — the long tail (attachments, dependency CRUD,\n * per-test checklist edits) stays deferred so the prompt stays small. Names\n * not exposed in the current mode are simply absent from the built list, so\n * the set intersects with mode gating for free.\n */\nexport const ALWAYS_LOADED_TOOLS: ReadonlySet<string> = new Set([\n // Every mode/session\n \"post_to_chat\",\n \"read_task_chat\",\n \"get_task\",\n \"get_current_plan\",\n \"set_manual_tests\",\n \"create_pull_request\",\n // Planning/auto/building\n \"update_task_plan\",\n \"update_task_properties\",\n // Building/auto — the PR guide is published as part of opening the PR\n \"publish_review_guide\",\n // Review mode\n \"approve_code_review\",\n \"request_code_changes\",\n]);\n\n/**\n * Pack/parent orchestration — a 12h fleet audit (2026-07-14) found a pack\n * runner re-ToolSearching this exact set on EVERY wake (~28 redundant round\n * trips in one session). The whole orchestration loop (list → promote/assign\n * → fire → merge/stop) is called by virtually every pack session.\n *\n * Scoped to pack and project-agent (pm) sessions rather than always-loaded by\n * name. Leaf task sessions now carry the subtask CRUD tools too, but a leaf\n * card usually has no children, so those two names would be dead weight in\n * every leaf prompt. Pack and pm prompts are unchanged: before this split,\n * these five names only ever appeared in pack/pm tool lists anyway.\n */\nexport const ORCHESTRATION_PROMOTED_TOOLS: ReadonlySet<string> = new Set([\n \"list_subtasks\",\n \"update_subtask\",\n \"start_child_cloud_build\",\n \"stop_child_build\",\n \"approve_and_merge_pr\",\n]);\n\n/**\n * Mode-scoped promotions from the 72h fleet baseline (2026-07-24, 321\n * sessions): the top remaining `select:` loads after ALWAYS_LOADED_TOOLS\n * landed, hot only in the contexts that actually use them so the prompt cost\n * isn't paid fleet-wide. upload_attachment led at 56 loads/72h (the UI\n * screenshot/recording guidance made it de facto hot in building sessions),\n * create_suggestion 32, get_attachment 14, get_execution_logs 12 (pack\n * parents inspecting children), list_manual_tests 9, create_follow_up_task 8.\n * force_update_task_status (21 loads) stays deferred on purpose — ToolSearch\n * friction is a feature for the emergency status override.\n */\nexport const BUILDING_PROMOTED_TOOLS: ReadonlySet<string> = new Set([\n \"upload_attachment\",\n \"get_attachment\",\n \"create_suggestion\",\n \"create_follow_up_task\",\n \"list_manual_tests\",\n]);\nexport const REVIEW_PROMOTED_TOOLS: ReadonlySet<string> = new Set([\"create_suggestion\"]);\nexport const PACK_PROMOTED_TOOLS: ReadonlySet<string> = new Set([\"get_execution_logs\"]);\n\n/** Glossary tools travel with every card that knows its project. */\nfunction glossaryToolsFor(\n connection: AgentConnection,\n config: AgentRunnerConfig,\n context?: TaskContext,\n): HarnessToolDefinition[] {\n return context?.projectId\n ? buildGlossaryTools(connection, context.projectId, config.taskId, config.workspaceDir)\n : [];\n}\n\n/**\n * Google Drive tools travel with a card whose project connected a Drive folder.\n * Both conditions are checked server-side into `googleDriveConnected`, so a\n * project without Drive never carries these six tools in its prompt.\n */\nfunction driveToolsFor(\n connection: AgentConnection,\n context?: TaskContext,\n): HarnessToolDefinition[] {\n return context?.projectId && context.googleDriveConnected\n ? buildDriveTools(connection, context.projectId)\n : [];\n}\n\nfunction promotedToolsFor(\n effectiveMode: AgentMode | undefined,\n isPack: boolean,\n isProjectAgent: boolean,\n): ReadonlySet<string> {\n const names = new Set<string>();\n // Auto boots straight into building, so it gets the building promotions.\n if (effectiveMode === \"building\" || effectiveMode === \"auto\") {\n for (const name of BUILDING_PROMOTED_TOOLS) names.add(name);\n }\n if (effectiveMode === \"review\") {\n for (const name of REVIEW_PROMOTED_TOOLS) names.add(name);\n }\n if (isPack) {\n for (const name of PACK_PROMOTED_TOOLS) names.add(name);\n }\n // The orchestration loop is hot for the sessions that orchestrate: pack\n // runners, parent cards, and the project agent. A leaf task carries the same\n // subtask tools but reaches for them rarely, so they stay deferred there.\n if (isPack || isProjectAgent) {\n for (const name of ORCHESTRATION_PROMOTED_TOOLS) names.add(name);\n }\n return names;\n}\n\nfunction withAlwaysLoad(\n tools: HarnessToolDefinition[],\n promoted: ReadonlySet<string>,\n): HarnessToolDefinition[] {\n return tools.map((tool) =>\n ALWAYS_LOADED_TOOLS.has(tool.name) || promoted.has(tool.name)\n ? { ...tool, alwaysLoad: true }\n : tool,\n );\n}\n\n/** Collect all tools for the current mode as harness-neutral definitions. */\nexport function buildConveyorTools(\n connection: AgentConnection,\n config: AgentRunnerConfig,\n context?: TaskContext,\n agentMode?: AgentMode,\n): HarnessToolDefinition[] {\n const effectiveMode = agentMode ?? context?.agentMode ?? undefined;\n\n const commonTools = buildCommonTools(connection, config);\n const modeTools = getModeTools(effectiveMode, connection, config, context);\n\n // Building included so auto tasks (booted straight into building) can\n // refine title/story points via update_task_properties while they work.\n // Chat included so a chat card can refine its own title.\n const discoveryTools =\n effectiveMode === \"discovery\" ||\n effectiveMode === \"auto\" ||\n effectiveMode === \"building\" ||\n effectiveMode === \"chat\"\n ? buildDiscoveryTools(connection)\n : [];\n\n // Code review verdict tools available in review mode\n const codeReviewTools = effectiveMode === \"review\" ? buildCodeReviewTools(connection) : [];\n\n const prGuideTools = buildPrGuideToolsFor(effectiveMode, connection, config, context);\n\n // Mid-conversation handoff is a Dev Manager (pm runner) capability — offered\n // while it is still planning (discovery/auto) so it can hand implementation\n // off to a difficulty-sized implementer agent.\n const handoffTools =\n config.mode === \"pm\" && (effectiveMode === \"discovery\" || effectiveMode === \"auto\")\n ? [buildHandoffTool(connection)]\n : [];\n\n const emergencyTools = [buildForceUpdateTaskStatusTool(connection)];\n\n // The project glossary travels with every card: read the vocabulary\n // (list_tags/get_tag) and maintain it (update_tag, card-stamped revisions).\n const glossaryTools = glossaryToolsFor(connection, config, context);\n\n // Google Drive file CRUD, when the project connected a Drive folder.\n const driveTools = driveToolsFor(connection, context);\n\n const isPack = config.mode === \"pack\" || Boolean(context?.isParentTask);\n // create_pull_request stays in the chat toolset: a chat card that saves a\n // plan becomes a real dev task and needs it. The gate is dynamic rather than\n // structural — tool-access.ts denies the call until a plan is saved — so the\n // tool does not have to be re-added mid-session.\n return withAlwaysLoad(\n [\n ...commonTools,\n ...modeTools,\n ...discoveryTools,\n ...codeReviewTools,\n ...prGuideTools,\n ...handoffTools,\n ...glossaryTools,\n ...driveTools,\n ...emergencyTools,\n ],\n promotedToolsFor(effectiveMode, isPack, config.mode === \"pm\"),\n );\n}\n\n// ── MCP server factory ────────────────────────────────────────────────\n\n// oxlint-disable-next-line typescript/explicit-function-return-type\nexport function createConveyorMcpServer(\n harness: AgentHarness,\n connection: AgentConnection,\n config: AgentRunnerConfig,\n context?: TaskContext,\n agentMode?: AgentMode,\n) {\n return harness.createMcpServer({\n name: \"conveyor\",\n tools: buildConveyorTools(connection, config, context, agentMode),\n });\n}\n","/**\n * Playwright MCP server registration for pod sessions.\n *\n * Claudespace pods NO LONGER bake `@playwright/mcp` (`Dockerfile.toolchain`\n * dropped it for the plain `playwright` CLI + `chromium-headless-shell`, which\n * halved the baked browser payload and let consuming repos share the cache).\n * Pod agents therefore have no `mcp__playwright__*` tools and drive browsers\n * through `scripts/agent/shot.ts` or the CLI instead.\n *\n * This registration is kept for hosts that DO have the binary on PATH — dev\n * machines, legacy images, and any project that installs it itself. The launch\n * flags encode two pod-runtime constraints:\n *\n * - `--no-sandbox`: GKE pods (seccomp RuntimeDefault, non-root, no\n * unprivileged user namespaces) cannot start Chromium's sandbox — without\n * this flag every launch dies with `FATAL: No usable sandbox!`.\n * - `--isolated`: a persistent browser profile takes an exclusive lock, which\n * would collide between the builder session and a same-pod review child.\n *\n * Resolution is PATH-based so environments without the baked binary (dev\n * machines, legacy GitHub Codespaces images) silently skip the registration —\n * the CLI would otherwise fail the spawn and drop ALL MCP servers.\n */\nimport { findOnPath } from \"../harness/pty/adapters/types.js\";\nimport type { ExternalMcpStdioServer } from \"../harness/types.js\";\n\n/** Current bin name first; `mcp-server-playwright` was the pre-0.0.31 name. */\nconst PLAYWRIGHT_MCP_BINARIES = [\"playwright-mcp\", \"mcp-server-playwright\"];\n\nconst PLAYWRIGHT_MCP_ARGS = [\"--browser\", \"chromium\", \"--headless\", \"--no-sandbox\", \"--isolated\"];\n\n/**\n * Locate the baked Playwright MCP binary and build its stdio server entry, or\n * null when unavailable on this host.\n */\nexport function resolvePlaywrightMcpServer(\n env: NodeJS.ProcessEnv = process.env,\n): ExternalMcpStdioServer | null {\n for (const binary of PLAYWRIGHT_MCP_BINARIES) {\n const command = findOnPath(binary, env);\n if (command) return { type: \"stdio\", command, args: [...PLAYWRIGHT_MCP_ARGS] };\n }\n return null;\n}\n","import type {\n HarnessAssistantEvent,\n HarnessResultEvent,\n HarnessResultSuccessEvent,\n HarnessResultErrorEvent,\n HarnessSystemInitEvent,\n HarnessCompactBoundaryEvent,\n HarnessTaskStartedEvent,\n HarnessTaskProgressEvent,\n HarnessRateLimitEvent,\n} from \"../harness/index.js\";\nimport type { TaskContext, ActivityEventSummary } from \"@project/shared\";\nimport type { QueryHost } from \"./query-host.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\n\nconst logger = createServiceLogger(\"event-handlers\");\n\nfunction safeVoid(promise: void | Promise<unknown>, context: string): void {\n if (promise && typeof (promise as Promise<unknown>).catch === \"function\") {\n (promise as Promise<unknown>).catch((err) => {\n process.stderr.write(`[safeVoid] ${context}: ${err}\\n`);\n });\n }\n}\n\nexport type UsageInfo = {\n input_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n};\n\n/** Convert a resetsAt value (epoch seconds, epoch ms, or ISO string) to an ISO string. */\nfunction epochSecondsToISO(value: unknown): string | undefined {\n if (typeof value === \"string\") return value;\n if (typeof value !== \"number\" || value <= 0) return undefined;\n // Heuristic: epoch seconds for dates after 2000 are < 1e12; milliseconds are >= 1e12\n const ms = value < 1e12 ? value * 1000 : value;\n return new Date(ms).toISOString();\n}\n\nexport async function processAssistantEvent(\n event: HarnessAssistantEvent,\n host: QueryHost,\n turnToolCalls: ActivityEventSummary[],\n): Promise<void> {\n const { content } = event.message;\n const turnTextParts: string[] = [];\n\n for (const block of content) {\n if (block.type === \"text\" && block.text) {\n turnTextParts.push(block.text);\n host.connection.sendEvent({ type: \"message\", content: block.text });\n await host.callbacks.onEvent({ type: \"message\", content: block.text });\n } else if (block.type === \"tool_use\" && block.name) {\n const inputStr = typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n const isContentTool = [\"edit\", \"write\"].includes(block.name.toLowerCase());\n const inputLimit = isContentTool ? 10_000 : 500;\n const summary: ActivityEventSummary = {\n tool: block.name,\n input: inputStr.slice(0, inputLimit),\n timestamp: new Date().toISOString(),\n };\n turnToolCalls.push(summary);\n host.connection.sendEvent({ type: \"tool_use\", tool: block.name, input: inputStr });\n await host.callbacks.onEvent({ type: \"tool_use\", tool: block.name, input: inputStr });\n }\n }\n}\n\nexport const API_ERROR_PATTERN = /API Error: (?:[45]\\d\\d|terminated)/;\nconst IMAGE_ERROR_PATTERN = /Could not process image/i;\nconst AUTH_ERROR_PATTERN =\n /Not logged in|Please run \\/login|authentication failed|invalid.*token|unauthorized/i;\n\nexport function isAuthError(msg: string): boolean {\n return AUTH_ERROR_PATTERN.test(msg);\n}\n\nfunction isRetriableMessage(msg: string): boolean {\n if (IMAGE_ERROR_PATTERN.test(msg)) return true;\n if (API_ERROR_PATTERN.test(msg)) return true;\n return false;\n}\n\nfunction aggregateModelUsage(modelUsage: Record<string, unknown>): {\n queryInputTokens: number;\n contextWindow: number;\n totalInputTokens: number;\n totalCacheRead: number;\n totalCacheCreation: number;\n} {\n let queryInputTokens = 0;\n let contextWindow = 0;\n let totalInputTokens = 0;\n let totalCacheRead = 0;\n let totalCacheCreation = 0;\n for (const data of Object.values(modelUsage)) {\n const d = data as {\n inputTokens?: number;\n cacheReadInputTokens?: number;\n cacheCreationInputTokens?: number;\n };\n const input = d.inputTokens ?? 0;\n const cacheRead = d.cacheReadInputTokens ?? 0;\n const cacheCreation = d.cacheCreationInputTokens ?? 0;\n totalInputTokens += input;\n totalCacheRead += cacheRead;\n totalCacheCreation += cacheCreation;\n queryInputTokens += input + cacheRead + cacheCreation;\n const cw = (data as { contextWindow?: number }).contextWindow ?? 0;\n if (cw > contextWindow) contextWindow = cw;\n }\n return { queryInputTokens, contextWindow, totalInputTokens, totalCacheRead, totalCacheCreation };\n}\n\nfunction emitContextUpdate(\n modelUsage: Record<string, unknown>,\n host: QueryHost,\n context: TaskContext,\n lastAssistantUsage?: UsageInfo,\n): void {\n const usage = aggregateModelUsage(modelUsage);\n let { contextWindow } = usage;\n\n // Override contextWindow when 1M beta is enabled but SDK reports ≤200K\n const settings = context.agentSettings ?? host.config.agentSettings ?? {};\n const has1mBeta = (settings.betas as string[] | undefined)?.includes(\"context-1m-2025-08-07\");\n if (has1mBeta && contextWindow > 0 && contextWindow <= 200_000) {\n contextWindow = 1_000_000;\n }\n\n if (contextWindow > 0) {\n // Current context fill = last API call's input tokens (per-call, not cumulative)\n const currentContextTokens = lastAssistantUsage\n ? (lastAssistantUsage.input_tokens ?? 0) +\n (lastAssistantUsage.cache_read_input_tokens ?? 0) +\n (lastAssistantUsage.cache_creation_input_tokens ?? 0)\n : usage.queryInputTokens;\n\n host.connection.sendEvent({\n type: \"context_update\",\n contextTokens: currentContextTokens,\n contextWindow,\n inputTokens: usage.totalInputTokens,\n cacheReadInputTokens: usage.totalCacheRead,\n cacheCreationInputTokens: usage.totalCacheCreation,\n totalTokensUsed: usage.queryInputTokens,\n });\n }\n}\n\nfunction handleSuccessResult(\n event: HarnessResultSuccessEvent,\n host: QueryHost,\n context: TaskContext,\n startTime: number,\n lastAssistantUsage?: UsageInfo,\n): { retriable: boolean } {\n const durationMs = Date.now() - startTime;\n const summary = event.result || \"Task completed.\";\n const retriable = isRetriableMessage(summary);\n\n host.connection.sendEvent({ type: \"completed\", summary, durationMs });\n\n const { modelUsage } = event;\n if (modelUsage && typeof modelUsage === \"object\") {\n emitContextUpdate(modelUsage as Record<string, unknown>, host, context, lastAssistantUsage);\n }\n\n return { retriable };\n}\n\nfunction handleErrorResult(\n event: HarnessResultErrorEvent,\n host: QueryHost,\n): { retriable: boolean; staleSession?: boolean; authError?: boolean } {\n const errorMsg =\n event.errors.length > 0 ? event.errors.join(\", \") : `Agent stopped: ${event.subtype}`;\n\n // Check for stale session error pattern\n const isStaleSession = errorMsg.includes(\"No conversation found with session ID\");\n\n if (isStaleSession) {\n // Suppress the error event for stale session - this will be handled by session recovery\n return { retriable: false, staleSession: true };\n }\n\n // Check for auth error pattern — will be handled by auth recovery\n if (isAuthError(errorMsg)) {\n host.connection.sendEvent({ type: \"error\", message: errorMsg });\n return { retriable: false, authError: true };\n }\n\n const retriable = isRetriableMessage(errorMsg);\n host.connection.sendEvent({ type: \"error\", message: errorMsg });\n return { retriable };\n}\n\nfunction handleResultEvent(\n event: HarnessResultEvent,\n host: QueryHost,\n context: TaskContext,\n startTime: number,\n lastAssistantUsage?: UsageInfo,\n): {\n retriable: boolean;\n resultSummary?: string;\n staleSession?: boolean;\n authError?: boolean;\n} {\n const resultSummary =\n event.subtype === \"success\"\n ? (event as HarnessResultSuccessEvent).result\n : (event as HarnessResultErrorEvent).errors.join(\", \");\n\n if (event.subtype === \"success\") {\n const result = handleSuccessResult(\n event as HarnessResultSuccessEvent,\n host,\n context,\n startTime,\n lastAssistantUsage,\n );\n return { ...result, resultSummary };\n }\n\n const result = handleErrorResult(event as HarnessResultErrorEvent, host);\n return { ...result, resultSummary };\n}\n\nexport async function emitResultEvent(\n event: HarnessResultEvent,\n host: QueryHost,\n context: TaskContext,\n startTime: number,\n lastAssistantUsage?: UsageInfo,\n): Promise<{\n retriable: boolean;\n resultSummary?: string;\n staleSession?: boolean;\n authError?: boolean;\n}> {\n const result = handleResultEvent(event, host, context, startTime, lastAssistantUsage);\n const durationMs = Date.now() - startTime;\n\n if (event.subtype === \"success\") {\n const successEvent = event as HarnessResultSuccessEvent;\n const summary = successEvent.result || \"Task completed.\";\n await host.callbacks.onEvent({\n type: \"completed\",\n summary,\n durationMs,\n });\n } else if (!result.staleSession) {\n // Only emit error event if it's not a stale session (which is handled by recovery logic)\n const errorEvent = event as HarnessResultErrorEvent;\n const errorMsg =\n errorEvent.errors.length > 0\n ? errorEvent.errors.join(\", \")\n : `Agent stopped: ${errorEvent.subtype}`;\n await host.callbacks.onEvent({ type: \"error\", message: errorMsg });\n }\n\n return {\n retriable: result.retriable,\n resultSummary: result.resultSummary,\n staleSession: result.staleSession,\n authError: result.authError,\n };\n}\n\nexport function handleRateLimitEvent(\n event: HarnessRateLimitEvent,\n host: QueryHost,\n): string | undefined {\n const { rate_limit_info } = event;\n logger.info(\"Rate limit event received\", { rate_limit_info });\n const status = rate_limit_info.status;\n\n // Send structured rate limit update for persistence\n // On rejection without explicit utilization, default to 1.0 (fully consumed)\n const utilization = rate_limit_info.utilization ?? (status === \"rejected\" ? 1.0 : undefined);\n if (utilization !== undefined && rate_limit_info.rateLimitType) {\n host.connection.sendEvent({\n type: \"rate_limit_update\",\n rateLimitType: rate_limit_info.rateLimitType,\n utilization,\n status,\n });\n }\n\n if (status === \"rejected\") {\n const resetsAt = epochSecondsToISO(rate_limit_info.resetsAt);\n const resetsAtDisplay = resetsAt ?? \"unknown\";\n const message = `Rate limit rejected (type: ${rate_limit_info.rateLimitType ?? \"unknown\"}, resets at: ${resetsAtDisplay})`;\n host.connection.sendEvent({ type: \"error\", message });\n safeVoid(host.callbacks.onEvent({ type: \"error\", message }), \"rateLimitRejected\");\n return resetsAt;\n } else if (status === \"allowed_warning\") {\n const utilizationLabel = rate_limit_info.utilization\n ? `${Math.round(rate_limit_info.utilization * 100)}%`\n : \"high\";\n const message = `Rate limit warning: ${utilizationLabel} utilization (type: ${rate_limit_info.rateLimitType ?? \"unknown\"})`;\n host.connection.sendEvent({ type: \"thinking\", message });\n safeVoid(host.callbacks.onEvent({ type: \"thinking\", message }), \"rateLimitWarning\");\n }\n return undefined;\n}\n\nexport async function handleSystemEvent(\n event: HarnessSystemInitEvent,\n host: QueryHost,\n context: TaskContext,\n sessionIdStored: boolean,\n): Promise<boolean> {\n if (event.subtype !== \"init\") return false;\n if (event.session_id && !sessionIdStored) {\n host.connection.storeSessionId(event.session_id);\n context.claudeSessionId = event.session_id;\n }\n await host.callbacks.onEvent({\n type: \"thinking\",\n message: `Agent initialized (model: ${event.model})`,\n });\n return !!(event.session_id && !sessionIdStored);\n}\n\nexport function handleSystemSubevents(\n systemEvent: HarnessCompactBoundaryEvent | HarnessTaskStartedEvent | HarnessTaskProgressEvent,\n host: QueryHost,\n): void {\n if (systemEvent.subtype === \"compact_boundary\") {\n safeVoid(\n host.callbacks.onEvent({\n type: \"context_compacted\",\n trigger: systemEvent.compact_metadata.trigger,\n preTokens: systemEvent.compact_metadata.pre_tokens,\n }),\n \"compactBoundary\",\n );\n } else if (systemEvent.subtype === \"task_started\") {\n safeVoid(\n host.callbacks.onEvent({\n type: \"subagent_started\",\n sdkTaskId: systemEvent.task_id,\n description: systemEvent.description,\n }),\n \"taskStarted\",\n );\n } else if (systemEvent.subtype === \"task_progress\") {\n safeVoid(\n host.callbacks.onEvent({\n type: \"subagent_progress\",\n sdkTaskId: systemEvent.task_id,\n description: systemEvent.description,\n toolUses: systemEvent.usage?.tool_uses ?? 0,\n durationMs: systemEvent.usage?.duration_ms ?? 0,\n }),\n \"taskProgress\",\n );\n }\n}\n\nexport function handleToolProgressEvent(event: unknown, host: QueryHost): void {\n const msg = event as { tool_name?: string; elapsed_time_seconds?: number };\n safeVoid(\n host.callbacks.onEvent({\n type: \"tool_progress\",\n toolName: msg.tool_name ?? \"\",\n elapsedSeconds: msg.elapsed_time_seconds ?? 0,\n }),\n \"toolProgress\",\n );\n}\n\nexport async function handleAssistantCase(\n event: HarnessAssistantEvent,\n host: QueryHost,\n turnToolCalls: ActivityEventSummary[],\n): Promise<UsageInfo | undefined> {\n await processAssistantEvent(event, host, turnToolCalls);\n const msgUsage = (event.message as { usage?: UsageInfo }).usage;\n return msgUsage ?? undefined;\n}\n\nexport async function handleResultCase(\n event: HarnessResultEvent,\n host: QueryHost,\n context: TaskContext,\n startTime: number,\n isTyping: boolean,\n lastAssistantUsage: UsageInfo | undefined,\n): Promise<{\n retriable: boolean;\n resultSummary?: string;\n staleSession?: boolean;\n authError?: boolean;\n stoppedTyping: boolean;\n}> {\n let stoppedTyping = false;\n if (isTyping) {\n host.connection.sendTypingStop();\n stoppedTyping = true;\n }\n const resultInfo = await emitResultEvent(event, host, context, startTime, lastAssistantUsage);\n return {\n retriable: resultInfo.retriable,\n resultSummary: resultInfo.resultSummary,\n staleSession: resultInfo.staleSession,\n authError: resultInfo.authError,\n stoppedTyping,\n };\n}\n","import type {\n HarnessEvent,\n HarnessAssistantEvent,\n HarnessResultEvent,\n HarnessSystemInitEvent,\n HarnessCompactBoundaryEvent,\n HarnessTaskStartedEvent,\n HarnessTaskProgressEvent,\n HarnessRateLimitEvent,\n HarnessUserQuestionEvent,\n} from \"../harness/index.js\";\nimport type { TaskContext, ActivityEventSummary } from \"@project/shared\";\nimport { AGENT_STATUS_REASON_USER_QUESTION } from \"@project/shared\";\nimport type { QueryHost } from \"./query-host.js\";\nimport type { UsageInfo } from \"./event-handlers.js\";\nimport {\n API_ERROR_PATTERN,\n handleAssistantCase,\n handleResultCase,\n handleRateLimitEvent,\n handleSystemEvent,\n handleSystemSubevents,\n handleToolProgressEvent,\n} from \"./event-handlers.js\";\n\n/** Mutable state bag threaded through the event loop. */\ninterface EventLoopState {\n sessionIdStored: boolean;\n isTyping: boolean;\n retriable: boolean;\n sawApiError: boolean;\n resultSummary: string | undefined;\n rateLimitResetsAt: string | undefined;\n /** Set when a rate_limit_event arrived with status \"rejected\" — a hard cap,\n * distinct from resetsAt (which the PTY banner can't always supply). */\n rateLimitRejectedType: string | undefined;\n staleSession: boolean | undefined;\n authError: boolean | undefined;\n lastAssistantUsage: UsageInfo | undefined;\n turnToolCalls: ActivityEventSummary[];\n /**\n * A TUI AskUserQuestion questionnaire is pending (armed by the PTY\n * harness's `user_question` event). While set, the periodic \"running\"\n * re-emit is suppressed so it can't clobber the reported\n * `waiting_for_input`. Display-only — mirrors `watchForParkedTui`.\n */\n questionPending: boolean;\n}\n\n/** The arming assistant record contains the AskUserQuestion tool_use block —\n * it can arrive via the transcript tailer after the hook event and must not\n * clear the pending flag. */\nfunction hasAskUserQuestionBlock(event: HarnessAssistantEvent): boolean {\n return event.message.content.some((b) => b.type === \"tool_use\" && b.name === \"AskUserQuestion\");\n}\n\n/** Join the parked questionnaire's prompts into a single notification-friendly\n * string. Multiple sub-questions are newline-joined; the server slices to 200. */\nfunction questionTextFromEvent(event: HarnessUserQuestionEvent): string | undefined {\n const text = event.questions\n .map((q) => q.question.trim())\n .filter((q) => q.length > 0)\n .join(\"\\n\");\n return text.length > 0 ? text : undefined;\n}\n\n/** Report `waiting_for_input` for a pending TUI questionnaire. Display-only:\n * SessionRunner `_state` is untouched (same semantics as `watchForParkedTui`),\n * so idle-timer and chat-supersede behavior are unchanged. The question text\n * rides along so the server can surface it in the user-question notification. */\nasync function armQuestionPending(\n host: QueryHost,\n state: EventLoopState,\n event: HarnessUserQuestionEvent,\n): Promise<void> {\n state.questionPending = true;\n await host.connection.emitStatus(\n \"waiting_for_input\",\n AGENT_STATUS_REASON_USER_QUESTION,\n questionTextFromEvent(event),\n );\n await host.callbacks.onStatusChange(\"waiting_for_input\");\n}\n\nasync function clearQuestionPending(\n host: QueryHost,\n state: EventLoopState,\n options: { emitRunning: boolean },\n): Promise<void> {\n if (!state.questionPending) return;\n state.questionPending = false;\n if (options.emitRunning) {\n await host.connection.emitStatus(\"running\");\n await host.callbacks.onStatusChange(\"running\");\n }\n}\n\n/**\n * Question-pending transitions driven by the event stream:\n * - user_question (PTY hook observed AskUserQuestion) → arm.\n * - tool_progress for AskUserQuestion (PostToolUse fires once the user\n * answered in the TUI) → clear + running (the deterministic clear).\n * - assistant WITHOUT an AskUserQuestion block → clear + running (backstop;\n * a new assistant record only exists after the questionnaire resolved).\n * Records WITH the block are the arming tool_use arriving late via the\n * transcript tailer and must not clear.\n * - result → clear silently (the result path owns the final status; covers\n * Esc/interrupt and turn end while parked).\n */\nasync function applyQuestionTransitions(\n event: HarnessEvent,\n host: QueryHost,\n state: EventLoopState,\n): Promise<void> {\n switch (event.type) {\n case \"user_question\":\n await armQuestionPending(host, state, event as HarnessUserQuestionEvent);\n return;\n case \"assistant\":\n if (!hasAskUserQuestionBlock(event as HarnessAssistantEvent)) {\n await clearQuestionPending(host, state, { emitRunning: true });\n }\n return;\n case \"tool_progress\":\n if (event.tool_name === \"AskUserQuestion\") {\n await clearQuestionPending(host, state, { emitRunning: true });\n }\n return;\n case \"result\":\n await clearQuestionPending(host, state, { emitRunning: false });\n break;\n default:\n break;\n }\n}\n\nfunction stopTypingIfNeeded(host: QueryHost, isTyping: boolean): void {\n if (isTyping) host.connection.sendTypingStop();\n}\n\n/** Merge pending tool outputs into accumulated tool call summaries and emit turn_end. */\nfunction flushPendingToolCalls(host: QueryHost, turnToolCalls: ActivityEventSummary[]): void {\n if (turnToolCalls.length === 0) {\n // Clear any orphaned outputs that arrived without matching tool_use blocks\n host.pendingToolOutputs.length = 0;\n return;\n }\n // Match outputs to tool calls by tool name (handles duplicate names via queue)\n const outputsByTool = new Map<string, string[]>();\n for (const entry of host.pendingToolOutputs) {\n const list = outputsByTool.get(entry.tool) ?? [];\n list.push(entry.output);\n outputsByTool.set(entry.tool, list);\n }\n for (const call of turnToolCalls) {\n const list = outputsByTool.get(call.tool);\n if (list && list.length > 0) {\n call.output = list.shift();\n }\n }\n host.connection.sendEvent({ type: \"turn_end\", toolCalls: [...turnToolCalls] });\n turnToolCalls.length = 0;\n host.pendingToolOutputs.length = 0;\n}\n\nasync function processSystemCase(\n event:\n | HarnessSystemInitEvent\n | HarnessCompactBoundaryEvent\n | HarnessTaskStartedEvent\n | HarnessTaskProgressEvent,\n host: QueryHost,\n context: TaskContext,\n state: EventLoopState,\n): Promise<void> {\n if (event.subtype === \"init\") {\n const stored = await handleSystemEvent(event, host, context, state.sessionIdStored);\n if (stored) state.sessionIdStored = true;\n } else {\n handleSystemSubevents(\n event as HarnessCompactBoundaryEvent | HarnessTaskStartedEvent | HarnessTaskProgressEvent,\n host,\n );\n }\n}\n\nasync function processAssistantCase(\n event: HarnessAssistantEvent,\n host: QueryHost,\n state: EventLoopState,\n): Promise<void> {\n if (!state.isTyping) {\n setTimeout(() => host.connection.sendTypingStart(), 200);\n state.isTyping = true;\n }\n const usage = await handleAssistantCase(event, host, state.turnToolCalls);\n if (usage) state.lastAssistantUsage = usage;\n\n // Check for API error patterns in assistant message text.\n // The SDK may emit API errors as assistant message content before ending\n // with a clean success result, which would bypass the result-level retry check.\n if (!state.sawApiError) {\n const fullText = event.message.content\n .filter((b: { type: string }) => b.type === \"text\")\n .map((b: { type: string; text?: string }) => (b as { text: string }).text)\n .join(\" \");\n if (API_ERROR_PATTERN.test(fullText)) {\n state.sawApiError = true;\n }\n }\n}\n\nasync function processResultCase(\n event: HarnessResultEvent,\n host: QueryHost,\n context: TaskContext,\n startTime: number,\n state: EventLoopState,\n): Promise<void> {\n const info = await handleResultCase(\n event,\n host,\n context,\n startTime,\n state.isTyping,\n state.lastAssistantUsage,\n );\n if (info.stoppedTyping) state.isTyping = false;\n state.retriable = info.retriable;\n // If the result itself is clean (not retriable), any API error the agent\n // mentioned in assistant text was already recovered from — don't retry.\n if (!info.retriable) state.sawApiError = false;\n state.resultSummary = info.resultSummary;\n if (info.staleSession) state.staleSession = true;\n if (info.authError) state.authError = true;\n}\n\n/** Record both signals a rate_limit_event carries: the reset time (when known)\n * and whether this was a hard rejection (drives the key-cycle path). */\nfunction processRateLimitCase(\n event: HarnessRateLimitEvent,\n host: QueryHost,\n state: EventLoopState,\n): void {\n const resetsAt = handleRateLimitEvent(event, host);\n if (resetsAt) state.rateLimitResetsAt = resetsAt;\n if (event.rate_limit_info.status === \"rejected\") {\n state.rateLimitRejectedType = event.rate_limit_info.rateLimitType ?? \"unknown\";\n }\n}\n\nexport async function processEvents(\n events: AsyncGenerator<HarnessEvent, void>,\n context: TaskContext,\n host: QueryHost,\n): Promise<{\n retriable: boolean;\n resultSummary?: string;\n modeRestart?: boolean;\n rateLimitResetsAt?: string;\n rateLimitRejectedType?: string;\n staleSession?: boolean;\n authError?: boolean;\n}> {\n const startTime = Date.now();\n let lastStatusEmit = Date.now();\n const STATUS_REEMIT_INTERVAL_MS = 5_000;\n\n const state: EventLoopState = {\n sessionIdStored: false,\n isTyping: false,\n retriable: false,\n sawApiError: false,\n resultSummary: undefined,\n rateLimitResetsAt: undefined,\n rateLimitRejectedType: undefined,\n staleSession: undefined,\n authError: undefined,\n lastAssistantUsage: undefined,\n turnToolCalls: [],\n questionPending: false,\n };\n\n for await (const event of events) {\n if (host.isStopped()) break;\n\n // Flush any pending tool calls from the previous assistant turn\n // (tool outputs have been collected by PostToolUse hooks between events)\n flushPendingToolCalls(host, state.turnToolCalls);\n\n // Re-emit \"running\" periodically so missed status events self-correct.\n // Suppressed while a questionnaire is pending — a stray tool_progress\n // (e.g. a parallel tool finishing) must not clobber waiting_for_input.\n const now = Date.now();\n if (now - lastStatusEmit >= STATUS_REEMIT_INTERVAL_MS && !state.questionPending) {\n host.connection.emitStatus(\"running\");\n lastStatusEmit = now;\n }\n\n if (host.pendingModeRestart) {\n stopTypingIfNeeded(host, state.isTyping);\n return { retriable: false, modeRestart: true };\n }\n\n await applyQuestionTransitions(event, host, state);\n\n switch (event.type) {\n case \"system\":\n await processSystemCase(event as HarnessSystemInitEvent, host, context, state);\n break;\n case \"assistant\":\n await processAssistantCase(event as HarnessAssistantEvent, host, state);\n break;\n case \"result\":\n await processResultCase(event as HarnessResultEvent, host, context, startTime, state);\n break;\n case \"rate_limit_event\":\n processRateLimitCase(event as HarnessRateLimitEvent, host, state);\n break;\n case \"tool_progress\":\n handleToolProgressEvent(event, host);\n break;\n }\n }\n\n flushPendingToolCalls(host, state.turnToolCalls);\n stopTypingIfNeeded(host, state.isTyping);\n\n return {\n retriable: state.retriable || state.sawApiError,\n resultSummary: state.resultSummary,\n rateLimitResetsAt: state.rateLimitResetsAt,\n ...(state.rateLimitRejectedType && { rateLimitRejectedType: state.rateLimitRejectedType }),\n ...(state.staleSession && { staleSession: state.staleSession }),\n ...(state.authError && { authError: state.authError }),\n };\n}\n","/**\n * Env/credential application for a mid-session coding-agent key swap.\n *\n * The server's `cycleCodingAgentKey` RPC returns the replacement key's\n * credential env exactly as boot resolution shapes it (`decryptAllKeys`):\n * exactly one of CLAUDE_CODE_OAUTH_TOKEN / CONVEYOR_AGENT_KEY /\n * CONVEYOR_OPENCODE_OAUTH, plus CONVEYOR_TUI / CONVEYOR_AGENT_MODEL /\n * CONVEYOR_SUBSCRIPTION_KEY_LABEL. Applying it mirrors the existing\n * `onApiKeyUpdate` rotation handler (session-runner) — including clearing the\n * complementary auth vars so the old credential can't shadow the new one.\n */\nimport { ensureClaudeCredentials, removeConveyorCredentials } from \"../harness/pty/credentials.js\";\n\nconst FIVE_HOURS_MS = 5 * 60 * 60 * 1000;\nconst TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1000;\n\nexport function applyCycledKeyEnv(\n envVars: Record<string, string>,\n env: NodeJS.ProcessEnv = process.env,\n): void {\n for (const [key, value] of Object.entries(envVars)) {\n env[key] = value;\n }\n // A claude_oauth blob outranks CLAUDE_CODE_OAUTH_TOKEN in planCredentialsWrite,\n // so a stale one would re-synthesize the OLD subscription's credentials after\n // cycling to a different key. It must never outlive the cycle that set it.\n if (!envVars.CONVEYOR_CLAUDE_OAUTH) delete env.CONVEYOR_CLAUDE_OAUTH;\n if (envVars.CLAUDE_CODE_OAUTH_TOKEN) {\n // Subscription token auth: an env API key would win over it in the CLI.\n delete env.ANTHROPIC_API_KEY;\n if (!envVars.CONVEYOR_AGENT_KEY) delete env.CONVEYOR_AGENT_KEY;\n } else if (envVars.CONVEYOR_AGENT_KEY || envVars.CONVEYOR_OPENCODE_OAUTH) {\n delete env.CLAUDE_CODE_OAUTH_TOKEN;\n }\n}\n\n/** Bring the on-disk TUI credentials in line with the freshly applied env. */\nexport async function syncCredentialsAfterCycle(\n env: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n if (env.CLAUDE_CODE_OAUTH_TOKEN) {\n await ensureClaudeCredentials(env);\n } else {\n await removeConveyorCredentials();\n }\n}\n\n/**\n * Pause target when neither the harness banner nor the server supplied a reset\n * time: hold for the full window (5h session / 24h weekly — matching the\n * server's own `resolveLimitedUntil` fallback).\n */\nexport function fallbackResetIso(rateLimitType: string, now = Date.now()): string {\n const weekly = /weekly|seven_day/i.test(rateLimitType);\n return new Date(now + (weekly ? TWENTY_FOUR_HOURS_MS : FIVE_HOURS_MS)).toISOString();\n}\n","/**\n * Shared utility for checking missing task properties.\n * Used by both ExitPlanMode validation and post-PR backfill nudge.\n */\n\nexport function collectMissingProps(taskProps: {\n plan?: string | null;\n storyPointId?: string | null;\n title?: string | null;\n riskLevel?: string | null;\n}): string[] {\n const missing: string[] = [];\n if (!taskProps.plan?.trim()) missing.push(\"plan (save via update_task_plan)\");\n if (!taskProps.storyPointId) missing.push(\"story points (use update_task_properties)\");\n if (!taskProps.title || taskProps.title === \"Untitled\")\n missing.push(\"title (use update_task_properties)\");\n if (!taskProps.riskLevel)\n missing.push(\"risk (use update_task_properties — critical/high/medium/low)\");\n return missing;\n}\n","import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Detect a running heavy build gate (test/typecheck/build) on a Conveyor pod.\n *\n * `scripts/singleton.sh` records the session-leader pid of the currently\n * running heavy command in `$CONVEYOR_RUN_DIR/<key>.pid` (keys: `heavy` in\n * global scope, or the per-label `test`/`typecheck`/`build` in category\n * scope; `dev` is the always-on dev server and deliberately NOT a gate).\n *\n * The periodic WIP flush consults this to SKIP its tick while a gate runs:\n * a mid-gate flush hashes a tree the gate is actively churning, competes for\n * the same starved disk/CPU, and captures throwaway build artifacts — it is\n * both the slowest and the least useful moment to snapshot. The tree the\n * human cares about doesn't change while the agent is parked waiting on a\n * gate, so deferring to the next tick loses nothing.\n */\n\nconst GATE_KEYS = [\"heavy\", \"test\", \"typecheck\", \"build\"] as const;\n\nfunction runDir(): string {\n return process.env.CONVEYOR_RUN_DIR ?? \"/tmp/conveyor-run\";\n}\n\nfunction pidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/** True when a singleton-managed heavy gate is currently running on this pod.\n * Never throws; false on any read failure (off-pod there are no pidfiles). */\nexport function isHeavyGateActive(): boolean {\n for (const key of GATE_KEYS) {\n try {\n const raw = readFileSync(path.join(runDir(), `${key}.pid`), \"utf8\").trim();\n const pid = Number.parseInt(raw, 10);\n if (Number.isInteger(pid) && pid > 0 && pidAlive(pid)) return true;\n } catch {\n // no pidfile for this key — not running\n }\n }\n return false;\n}\n","/**\n * Repeated-tool-call loop breaker.\n *\n * An agent can wedge a pod by calling one identical tool over and over —\n * observed live 2026-08-05, where a card polled a background build log\n * (`tail -20 …/web-build.log`) turn after turn while its own output said it\n * would wait for the completion notification instead of polling. The prompt\n * guidance against polling already existed; nothing bounded the repetition.\n *\n * `buildCanUseTool` (tool-access.ts) already sees every one of those calls —\n * build-capable spawns wire a `Bash` PreToolUse matcher, plan-permission spawns\n * wire a catch-all — but it only bounded DENIED calls. A run of ALLOWED\n * identical calls was invisible. This module supplies the missing count.\n *\n * ## Why deny, and why only every Nth repeat\n *\n * A PreToolUse deny is the only channel back into the model from the hook, so\n * a deny carrying an explanation is what actually breaks a repetition — and it\n * ends the tool call, not the turn, so the agent can immediately do something\n * else. But denying EVERY repeat would break a legitimate workflow: iterating\n * on a failing test re-runs the exact same command with edits in between, and\n * on a build spawn those edits are invisible here (only Bash is hooked). So the\n * interrupt fires on every `REPEAT_INTERRUPT_INTERVAL`-th repeat and the calls\n * between are allowed — a real workflow always makes progress, and a genuine\n * loop still gets interrupted.\n *\n * This is NOT the auto-mode stuck-nudge that `.claude/rules/agent-runner.md`\n * says must not come back. Nothing here re-prompts, re-queues, or wakes the\n * agent; it only interrupts a call the agent already repeated.\n */\n\n/** Repeat count at which the loop is interrupted, and the interval after it. */\nexport const REPEAT_INTERRUPT_THRESHOLD = 4;\nexport const REPEAT_INTERRUPT_INTERVAL = 4;\n/** Repeat count at which the session is force-stopped instead. */\nexport const REPEAT_FORCE_STOP_THRESHOLD = 12;\n\n/**\n * Tools deliberately never counted. Both run Conveyor-owned gates with their\n * own retry semantics (ExitPlanMode is denied on purpose until the plan\n * validates, and AskUserQuestion is answered by a human), so a repeat of either\n * is expected rather than pathological.\n */\nconst UNCOUNTED_TOOLS = new Set([\"ExitPlanMode\", \"AskUserQuestion\"]);\n\nexport type LoopVerdict = \"ok\" | \"interrupt\" | \"force_stop\";\n\n/** Stable JSON: object keys sorted so key order cannot mask a repeat. */\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value) ?? \"null\";\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`);\n return `{${entries.join(\",\")}}`;\n}\n\n/**\n * A comparable identity for one tool call, or null when the tool is not\n * counted. Bash is keyed on its `command` alone: `description`, `timeout` and\n * `run_in_background` differ between attempts that are otherwise the same\n * command, and re-issuing one command as a background job is still a repeat.\n */\nexport function fingerprintToolCall(\n toolName: string,\n input: Record<string, unknown>,\n): string | null {\n if (!toolName || UNCOUNTED_TOOLS.has(toolName)) return null;\n if (toolName === \"Bash\") {\n const command = String(input.command ?? \"\")\n .trim()\n .replace(/\\s+/g, \" \");\n return command ? `Bash:${command}` : null;\n }\n return `${toolName}:${stableStringify(input)}`;\n}\n\n/**\n * Counts identical CONSECUTIVE tool calls. Lives on `QueryHost` (the\n * session-scoped QueryBridge) rather than in `buildCanUseTool`'s closure: that\n * closure is rebuilt by `buildQueryOptions` on every turn, so a loop spanning\n * turns — which is exactly what the reported card did — would reset its own\n * counter and never trip.\n */\nexport class ToolLoopTracker {\n private fingerprint: string | null = null;\n private streak = 0;\n /** True once this streak has been reported to chat — one message per streak. */\n private reported = false;\n\n /** Repeats of the current fingerprint, including the call being recorded. */\n get repeatCount(): number {\n return this.streak;\n }\n\n /** True when the current streak has already been posted to chat. */\n get alreadyReported(): boolean {\n return this.reported;\n }\n\n /** Mark the current streak as reported so the next interrupt stays quiet. */\n markReported(): void {\n this.reported = true;\n }\n\n /** Record one call and decide what to do about it. */\n record(fingerprint: string): LoopVerdict {\n if (fingerprint !== this.fingerprint) {\n this.fingerprint = fingerprint;\n this.streak = 1;\n this.reported = false;\n return \"ok\";\n }\n this.streak++;\n if (this.streak >= REPEAT_FORCE_STOP_THRESHOLD) return \"force_stop\";\n if (\n this.streak >= REPEAT_INTERRUPT_THRESHOLD &&\n (this.streak - REPEAT_INTERRUPT_THRESHOLD) % REPEAT_INTERRUPT_INTERVAL === 0\n ) {\n return \"interrupt\";\n }\n return \"ok\";\n }\n}\n\n/**\n * The deny text the model reads. It names the repeat count, because the model\n * cannot see its own loop, and branches on whether a singleton heavy gate is\n * running — a gate is the single most common thing an agent polls in a loop,\n * and the correct response to it is to end the turn.\n */\nexport function buildRepeatLoopMessage(repeatCount: number, heavyGateActive: boolean): string {\n const head =\n `Conveyor blocked this call: you have run the exact same command ${repeatCount} times in a row ` +\n `with nothing different in between. Repeating it again will return the same result.`;\n const advice = heavyGateActive\n ? `A build gate (test/typecheck/build) is running on this pod right now. Do NOT poll its log. ` +\n `End your turn — the completion notification re-invokes you when the gate finishes.`\n : `If you are waiting on a background job, end your turn instead of polling; the completion ` +\n `notification re-invokes you. If you are stuck, change your approach: read a different file, ` +\n `run a different command, or post to chat and ask the team.`;\n return `${head} ${advice} Call a different tool now.`;\n}\n\n/** The chat message a human reads when a loop is detected. */\nexport function buildRepeatLoopChatMessage(repeatCount: number, forceStopped: boolean): string {\n if (forceStopped) {\n return (\n `Agent force-stopped after repeating the same tool call ${repeatCount} times in a row. ` +\n `It appears stuck — send a message to resume.`\n );\n }\n return (\n `⚠️ The agent repeated the same tool call ${repeatCount} times in a row. ` +\n `Conveyor blocked the repeat and asked it to change approach.`\n );\n}\n","import type { QueryHost } from \"./query-host.js\";\nimport { collectMissingProps } from \"./task-property-utils.js\";\nimport { isHeavyGateActive } from \"../runner/heavy-gate.js\";\nimport {\n ToolLoopTracker,\n buildRepeatLoopChatMessage,\n buildRepeatLoopMessage,\n fingerprintToolCall,\n} from \"./tool-loop-tracker.js\";\n\nconst PM_PLAN_FILE_TOOLS = new Set([\"Write\", \"Edit\", \"MultiEdit\"]);\n\nconst DESTRUCTIVE_PATTERNS: { name: string; re: RegExp }[] = [\n {\n name: \"git push --force (without --force-with-lease)\",\n re: /git\\s+push\\s+(?:-f\\b|--force(?!-with-lease))/,\n },\n { name: \"git push --delete\", re: /git\\s+push\\s+(?:-d\\b|--delete\\b)/ },\n { name: \"git reset --hard\", re: /git\\s+reset\\s+--hard\\b/ },\n {\n name: \"rm -rf /\",\n re: /rm\\s+(?:-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r|--recursive\\s+--force)\\s+\\/(?!\\S)/,\n },\n { name: \"sudo rm\", re: /\\bsudo\\s+rm\\b/ },\n { name: \"chmod world-writable\", re: /\\bchmod\\s+(?:-R\\s+)?[0-7]*7{2,3}\\b/ },\n { name: \"dd to device\", re: /\\bdd\\s+.*\\bof=\\/dev\\// },\n { name: \"redirect to block device\", re: />\\s*\\/dev\\/(?:sd[a-z]|nvme\\d|xvd[a-z])/ },\n { name: \"mkfs filesystem creation\", re: /\\bmkfs(?:\\.|\\s)/ },\n { name: \"shutdown/poweroff/halt/reboot\", re: /\\b(?:shutdown|poweroff|halt|reboot)\\b/ },\n { name: \"fork bomb\", re: /:\\(\\)\\s*\\{\\s*:\\|\\s*:&\\s*\\}\\s*;\\s*:/ },\n];\n\nfunction matchesDestructive(cmd: string): string | null {\n for (const { name, re } of DESTRUCTIVE_PATTERNS) {\n if (re.test(cmd)) return name;\n }\n return null;\n}\n\ntype ToolResult =\n | { behavior: \"allow\"; updatedInput?: Record<string, unknown> }\n | { behavior: \"deny\"; message: string };\n\nfunction isPlanFile(input: Record<string, unknown>): boolean {\n const filePath = String(input.file_path ?? input.path ?? \"\");\n return filePath.includes(\".claude/plans/\");\n}\n\n// Read-only modes (discovery/help, and residual pre-exit auto) run their shell\n// commands WITHOUT an approval dialog — the pod is the sandbox, and a planning\n// agent that stops to ask has nobody at the terminal to answer. What stays\n// blocked is the narrow set of commands that would turn planning into\n// building: anything that writes history, moves the checkout, or publishes.\n// Read-only investigation (git log/diff/status, DB queries, test runs) is free.\nconst READ_ONLY_BLOCKED_BASH: { name: string; re: RegExp }[] = [\n { name: \"git commit\", re: /\\bgit\\s+(?:-\\S+\\s+)*commit\\b/ },\n { name: \"git push\", re: /\\bgit\\s+(?:-\\S+\\s+)*push\\b/ },\n { name: \"git merge\", re: /\\bgit\\s+(?:-\\S+\\s+)*merge\\b/ },\n { name: \"git rebase\", re: /\\bgit\\s+(?:-\\S+\\s+)*rebase\\b/ },\n { name: \"git checkout/switch\", re: /\\bgit\\s+(?:-\\S+\\s+)*(?:checkout|switch)\\b/ },\n { name: \"git apply/am\", re: /\\bgit\\s+(?:-\\S+\\s+)*(?:apply|am)\\b/ },\n { name: \"gh pr create\", re: /\\bgh\\s+pr\\s+(?:create|merge)\\b/ },\n { name: \"package publish\", re: /\\b(?:npm|bun|pnpm|yarn)\\s+publish\\b/ },\n];\n\nfunction matchesReadOnlyBlocked(cmd: string): string | null {\n for (const { name, re } of READ_ONLY_BLOCKED_BASH) {\n if (re.test(cmd)) return name;\n }\n return null;\n}\n\nfunction handleReadOnlyToolAccess(toolName: string, input: Record<string, unknown>): ToolResult {\n if (PM_PLAN_FILE_TOOLS.has(toolName)) {\n if (isPlanFile(input)) {\n return { behavior: \"allow\", updatedInput: input };\n }\n return {\n behavior: \"deny\",\n message: \"Discovery mode is read-only. File writes are restricted to plan files.\",\n };\n }\n if (toolName === \"Bash\") {\n const cmd = String(input.command ?? \"\");\n const destructive = matchesDestructive(cmd);\n if (destructive) {\n return {\n behavior: \"deny\",\n message: `Destructive operation blocked (${destructive}). Use safer alternatives.`,\n };\n }\n const blocked = matchesReadOnlyBlocked(cmd);\n if (blocked) {\n return {\n behavior: \"deny\",\n message:\n `Planning mode does not run \\`${blocked}\\` — it is read-only. ` +\n `Every other command runs without asking for approval, so investigate freely. ` +\n `Finish the plan and call ExitPlanMode when the work should start.`,\n };\n }\n }\n return { behavior: \"allow\", updatedInput: input };\n}\n\nfunction handleBuildingToolAccess(toolName: string, input: Record<string, unknown>): ToolResult {\n if (toolName === \"Bash\") {\n const cmd = String(input.command ?? \"\");\n const matched = matchesDestructive(cmd);\n if (matched) {\n return {\n behavior: \"deny\",\n message: `Destructive operation blocked (${matched}). Use safer alternatives.`,\n };\n }\n }\n return { behavior: \"allow\", updatedInput: input };\n}\n\nfunction handleReviewToolAccess(toolName: string, input: Record<string, unknown>): ToolResult {\n // Review mode has full write access — reviewer can make direct fixes\n return handleBuildingToolAccess(toolName, input);\n}\n\n// Chat mode is a conversational assistant: full FILE write (so it can create\n// files and attach them to the card) but its PR path is PLAN-GATED. Until the\n// card has a saved plan it is a conversation, not a dev task, so every\n// remote-pushing / PR-opening command is denied on top of the standard\n// destructive guards. Saving a plan identifies the card, moves it to\n// InProgress (maybeIdentifyOnFirstPlan, api) and opens these back up.\nconst CHAT_BLOCKED_BASH = /\\bgit\\s+push\\b|\\bgh\\s+pr\\b|\\bhub\\s+pull-request\\b/;\n\n/** Matches the PR tool prefixed or bare — names are unprefixed inside MCP. */\nconst CREATE_PR_TOOL = /(^|__)create_pull_request$/;\n\nconst CHAT_PLAN_GATE_MESSAGE = [\n \"This chat card has no saved plan, so it has no PR path yet.\",\n \"If the conversation has turned into a development task, save a plan with update_task_plan first — that identifies the card and moves it to In Progress — then commit, push, and open the PR.\",\n \"If it is still a conversation, deliver the work by attaching files to the card with upload_attachment instead.\",\n].join(\" \");\n\n/** Is this the PR-opening path that a chat card must have a plan to use? */\nfunction isChatPrTool(toolName: string, input: Record<string, unknown>): boolean {\n if (CREATE_PR_TOOL.test(toolName)) return true;\n return toolName === \"Bash\" && CHAT_BLOCKED_BASH.test(String(input.command ?? \"\"));\n}\n\n/**\n * Live-read the card's plan. Fails closed: a chat card whose plan cannot be\n * read stays conversational rather than gaining a PR path by accident.\n */\nasync function chatCardHasPlan(host: QueryHost): Promise<boolean> {\n try {\n const props = await host.connection.getTaskProperties();\n return !!props.plan?.trim();\n } catch {\n return false;\n }\n}\n\nfunction handleAutoToolAccess(\n toolName: string,\n input: Record<string, unknown>,\n hasExitedPlanMode: boolean,\n isParentTask: boolean,\n): ToolResult {\n if (hasExitedPlanMode) {\n return isParentTask\n ? handleReviewToolAccess(toolName, input)\n : handleBuildingToolAccess(toolName, input);\n }\n // Pre-ExitPlanMode: trust the SDK's native plan mode for restrictions.\n // (Residual sessions only — auto now boots post-exit.)\n return { behavior: \"allow\", updatedInput: input };\n}\n\nfunction enforceMissingProps(\n host: QueryHost,\n input: Record<string, unknown>,\n missingProps: string[],\n): ToolResult | null {\n if (missingProps.length === 0) return null;\n if (input.bypassValidation !== true) {\n return {\n behavior: \"deny\" as const,\n message: [\n \"Cannot exit plan mode. Required task properties are missing:\",\n ...missingProps.map((p) => `- ${p}`),\n \"\",\n \"Fill these in using MCP tools (e.g. update_task_plan, update_task_properties), then call ExitPlanMode again.\",\n \"\",\n \"If you have a deliberate reason to proceed without them, you must explicitly bypass validation by calling ExitPlanMode with `bypassValidation: true` as a tool argument. Do not bypass unless the team has asked you to — it will be surfaced in chat.\",\n ].join(\"\\n\"),\n };\n }\n host.connection.postChatMessage(\n `⚠️ [BYPASS] ExitPlanMode forced through with \\`bypassValidation: true\\` despite missing required properties: ${missingProps.join(\", \")}. Please backfill these.`,\n );\n return null;\n}\n\nasync function handleExitPlanMode(\n host: QueryHost,\n input: Record<string, unknown>,\n): Promise<ToolResult> {\n if (host.hasExitedPlanMode) {\n return { behavior: \"allow\" as const, updatedInput: input };\n }\n\n try {\n const taskProps = await host.connection.getTaskProperties();\n const missingProps = collectMissingProps(taskProps);\n\n // Validate subtasks have plans if this is a parent task\n if (host.isParentTask) {\n try {\n const result = await host.connection.call(\"listSubtasks\", {\n sessionId: host.connection.sessionId,\n });\n // No `view` in the payload → the server returns the full array\n // (the compact view is an object and carries no plan text anyway).\n const subtasks = Array.isArray(result) ? result : [];\n const subtasksWithoutPlans = subtasks.filter(\n (s: { plan?: string | null; title: string }) => !s.plan?.trim(),\n );\n if (subtasksWithoutPlans.length > 0) {\n const names = subtasksWithoutPlans.map((s: { title: string }) => s.title).join(\", \");\n missingProps.push(\n `subtask plans — these subtasks are missing plans: ${names} (use update_subtask with plan field)`,\n );\n }\n } catch {\n // If we can't list subtasks, skip this validation\n }\n }\n\n const gate = enforceMissingProps(host, input, missingProps);\n if (gate) return gate;\n\n if (host.agentMode === \"discovery\") {\n // Discovery planning is complete. The card moves to Open (Identified)\n // and this session parks here for human review — it does NOT hand off\n // to auto or continue into building on its own. triggerIdentification\n // fires the identification pass but leaves agentMode/status alone\n // beyond that (see identification-methods.ts's Open-pause behavior).\n // hasExitedPlanMode stays false: this session never gains build access:\n // the human's explicit Build action (or a fresh session after it) is\n // what starts implementation.\n try {\n await host.connection.triggerIdentification();\n } catch (triggerErr) {\n host.connection.postChatMessage(\n `Identification trigger encountered an issue (${triggerErr instanceof Error ? triggerErr.message : \"unknown error\"}). Icon assignment may use fallbacks.`,\n );\n }\n await host.connection.postChatMessageAwait(\n \"Plan posted and card moved to Open — waiting for review. Use Build (or switch modes) when you're ready to start implementation.\",\n );\n host.discoveryCompleted = true;\n host.requestStop();\n return { behavior: \"allow\" as const, updatedInput: input };\n }\n\n // Auto mode: trigger identification but don't let it block ExitPlanMode.\n // Identification runs asynchronously server-side with fallbacks,\n // and the agent should proceed to building mode regardless.\n try {\n await host.connection.triggerIdentification();\n } catch (triggerErr) {\n host.connection.postChatMessage(\n `Identification trigger encountered an issue (${triggerErr instanceof Error ? triggerErr.message : \"unknown error\"}). Proceeding to build phase — identification will use fallbacks.`,\n );\n }\n\n host.hasExitedPlanMode = true;\n\n // Same-session continuation on BOTH harnesses: the SDK upgrades plan→build\n // permissions natively; under PTY the session presses Enter on the residual\n // plan dialog (planDialogAutoAccept) and continues in acceptEdits with the\n // settings allow-list covering the rest. The mode_changed event below is\n // deliberately unhandled server-side — DB task.agentMode must stay \"auto\"\n // so computeRunnerMode/canBypassPlanning resolve correctly on pod restarts.\n const newMode = host.isParentTask ? \"review\" : \"building\";\n host.connection.sendEvent({ type: \"mode_transition\", from: \"auto\", to: newMode });\n host.connection.emitModeChanged(newMode);\n\n return { behavior: \"allow\" as const, updatedInput: input };\n } catch (err) {\n return {\n behavior: \"deny\" as const,\n message: `Identification failed: ${err instanceof Error ? err.message : String(err)}. Fix the issue and try again.`,\n };\n }\n}\n\nasync function handleAskUserQuestion(\n host: QueryHost,\n input: Record<string, unknown>,\n): Promise<ToolResult> {\n const QUESTION_TIMEOUT_MS = 5 * 60 * 1000;\n const questions = input.questions as {\n question: string;\n header: string;\n options: { label: string; description: string; preview?: string }[];\n multiSelect?: boolean;\n }[];\n\n host.connection.emitStatus(\"waiting_for_input\");\n host.connection.sendEvent({\n type: \"tool_use\",\n tool: \"AskUserQuestion\",\n input: JSON.stringify(input),\n });\n\n const answerPromise = host.connection.askUserQuestion(questions);\n const timeoutPromise = new Promise<null>((resolve) => {\n setTimeout(() => resolve(null), QUESTION_TIMEOUT_MS);\n });\n\n const answers = await Promise.race([answerPromise, timeoutPromise]);\n host.connection.emitStatus(\"running\");\n\n if (!answers || Object.keys(answers).length === 0) {\n return {\n behavior: \"deny\",\n message:\n \"User did not respond to clarifying questions in time. Proceed with your best judgment.\",\n };\n }\n\n return { behavior: \"allow\", updatedInput: { questions: input.questions, answers } };\n}\n\nconst DENIAL_WARNING_THRESHOLD = 3;\nconst DENIAL_FORCE_STOP_THRESHOLD = 8;\n\nfunction handleDenialEscalation(host: QueryHost, consecutiveDenials: number): void {\n if (consecutiveDenials === DENIAL_WARNING_THRESHOLD) {\n host.connection.postChatMessage(\n `⚠️ Multiple tool denials detected. You are in ${host.agentMode} mode — ` +\n `file writes outside .claude/plans/ are not permitted. ` +\n `Focus on creating a plan instead of implementing code changes.`,\n );\n }\n if (consecutiveDenials >= DENIAL_FORCE_STOP_THRESHOLD) {\n host.connection.postChatMessage(\n `Agent force-stopped after ${DENIAL_FORCE_STOP_THRESHOLD} consecutive tool denials. ` +\n `The agent appears stuck — send a message to resume.`,\n );\n host.requestStop();\n }\n}\n\n/**\n * Break a run of identical tool calls. Returns a deny when the repeat must be\n * interrupted, null when the call may proceed.\n *\n * The tracker lives on the host, not on `buildCanUseTool`'s closure, because\n * that closure is rebuilt every turn (`buildQueryOptions`) — and the loop this\n * exists for spanned turns.\n */\nfunction checkToolLoop(\n host: QueryHost,\n toolName: string,\n input: Record<string, unknown>,\n): ToolResult | null {\n const fingerprint = fingerprintToolCall(toolName, input);\n if (!fingerprint) return null;\n const tracker = (host.toolLoop ??= new ToolLoopTracker());\n const verdict = tracker.record(fingerprint);\n if (verdict === \"ok\") return null;\n\n const repeats = tracker.repeatCount;\n if (verdict === \"force_stop\") {\n host.connection.postChatMessage(buildRepeatLoopChatMessage(repeats, true));\n host.requestStop();\n return {\n behavior: \"deny\",\n message: `Stopped after repeating this call ${repeats} times in a row.`,\n };\n }\n if (!tracker.alreadyReported) {\n tracker.markReported();\n host.connection.postChatMessage(buildRepeatLoopChatMessage(repeats, false));\n }\n return { behavior: \"deny\", message: buildRepeatLoopMessage(repeats, isHeavyGateActive()) };\n}\n\nfunction resolveToolAccess(\n host: QueryHost,\n toolName: string,\n input: Record<string, unknown>,\n): ToolResult {\n switch (host.agentMode) {\n case \"discovery\":\n case \"help\":\n return handleReadOnlyToolAccess(toolName, input);\n case \"building\":\n return handleBuildingToolAccess(toolName, input);\n case \"review\":\n return handleReviewToolAccess(toolName, input);\n case \"auto\":\n return handleAutoToolAccess(toolName, input, host.hasExitedPlanMode, host.isParentTask);\n case \"chat\":\n // The chat-specific PR gate runs ahead of this in buildCanUseTool.\n return handleBuildingToolAccess(toolName, input);\n default:\n return { behavior: \"allow\", updatedInput: input };\n }\n}\n\nexport function buildCanUseTool(\n host: QueryHost,\n): (toolName: string, input: Record<string, unknown>) => Promise<ToolResult> {\n let consecutiveDenials = 0;\n // Cached once true — a plan never un-lands mid-session, so the gate costs at\n // most one round trip per PR attempt before it opens permanently.\n let chatHasPlan = false;\n\n return async (toolName, input) => {\n if (\n toolName === \"ExitPlanMode\" &&\n (host.agentMode === \"auto\" || host.agentMode === \"discovery\") &&\n !host.hasExitedPlanMode\n ) {\n return await handleExitPlanMode(host, input);\n }\n\n // Repeated ExitPlanMode calls after plan mode was already exited in discovery\n // mode should be denied to prevent burning budget without triggering force-stop.\n // (In practice unreachable in a single session — handleExitPlanMode's discovery\n // branch calls requestStop() — kept as defense-in-depth for a queued call racing\n // the stop.)\n if (toolName === \"ExitPlanMode\" && host.agentMode === \"discovery\" && host.hasExitedPlanMode) {\n return {\n behavior: \"deny\" as const,\n message: \"Plan mode has already been exited.\",\n };\n }\n\n if (toolName === \"AskUserQuestion\") {\n return await handleAskUserQuestion(host, input);\n }\n\n // Loop breaker runs before per-mode policy: a repeat is worth interrupting\n // whether or not the call would have been allowed.\n const loopResult = checkToolLoop(host, toolName, input);\n if (loopResult) return loopResult;\n\n // Chat mode's PR path is plan-gated: a plan-less chat card is still a\n // conversation, so pushing a branch or opening a PR is denied.\n if (host.agentMode === \"chat\" && isChatPrTool(toolName, input)) {\n if (!chatHasPlan) chatHasPlan = await chatCardHasPlan(host);\n if (!chatHasPlan) {\n consecutiveDenials++;\n handleDenialEscalation(host, consecutiveDenials);\n return { behavior: \"deny\" as const, message: CHAT_PLAN_GATE_MESSAGE };\n }\n }\n\n const result = resolveToolAccess(host, toolName, input);\n\n if (result.behavior === \"deny\") {\n consecutiveDenials++;\n handleDenialEscalation(host, consecutiveDenials);\n } else {\n consecutiveDenials = 0;\n }\n\n return result;\n };\n}\n","/**\n * QueryBridge — wires SessionRunner lifecycle state to QueryExecutor execution.\n *\n * SessionRunner handles connect/idle/message lifecycle.\n * QueryExecutor handles Claude SDK query orchestration.\n * QueryBridge adapts between them by constructing the QueryHost interface\n * that QueryExecutor expects, using live references to ModeController state.\n */\n\nimport type { HarnessEvent, HarnessUserMessage, PtyBridge } from \"../harness/index.js\";\nimport { createHarness, type HarnessKind } from \"../harness/index.js\";\nimport {\n resolveTuiAdapter,\n resolveTuiKindFromEnv,\n type TuiKind,\n} from \"../harness/pty/adapters/index.js\";\nimport { wrapBridgeWithDirectStream, type DirectPtyStream } from \"../harness/pty/direct-stream.js\";\nimport {\n runSdkQuery,\n runPassiveTurn,\n resolvePromptDelivery,\n hasExistingSessionFile,\n type QueryHost,\n} from \"../execution/query-executor.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { ModeController } from \"./mode-controller.js\";\nimport type { AgentRunnerConfig, AgentRunnerCallbacks } from \"../runner-types.js\";\nimport type { TaskContext, AgentMode, MultimodalBlock, RunnerMode } from \"@project/shared\";\nimport { createServiceLogger } from \"../utils/logger.js\";\n\nconst logger = createServiceLogger(\"QueryBridge\");\n\n/**\n * Pick the harness implementation for the task chat path.\n *\n * Card/task chat is ALWAYS the PTY harness (drives the `claude` CLI under a\n * pseudo-terminal, rendered as the Connected TUI). This is unconditional: the\n * env var `CONVEYOR_HARNESS` is deliberately NOT consulted, so a stale value\n * (a leftover codespace secret, or one applied via the bootstrap envVars) can\n * never route a card to the headless SDK loop — the failure mode that left\n * auto-mode cards running SDK with no Connected-TUI tab.\n *\n * The ONLY way to put a card on the SDK harness is an explicit maintainer\n * override, `CONVEYOR_FORCE_SDK_CARDS=1`. It is a distinct name that is never\n * pushed as a codespace secret nor emitted in the bootstrap env, so it cannot\n * be triggered accidentally — it exists solely for emergency local debugging.\n *\n * Scope: this governs ONLY the task chat. The audit and project-chat paths\n * construct the SDK harness directly via `createHarness()` (no-arg) and never\n * call this function, so they stay on SDK regardless.\n */\nexport function resolveHarnessKind(): HarnessKind {\n if (process.env.CONVEYOR_FORCE_SDK_CARDS === \"1\") return \"sdk\";\n // Cards are unconditionally PTY — for opencode too. The opencode adapter\n // gained a trusted structured-event source (the Conveyor events plugin\n // tailing the client engine's bus — see harness/opencode/plugin.ts), so an\n // opencode card mirrors chat, mounts the Conveyor MCP tools, opens PRs and\n // ends turns WHILE the human watches and types in the live Connected-TUI\n // tab. The headless `opencode run` harness (`HarnessKind \"opencode\"`) is\n // kept in-tree but unrouted, as the fallback if the TUI path hits pod\n // trouble.\n return \"pty\";\n}\n\n/**\n * Which TUI a card's PTY harness drives.\n *\n * The card's `Task.codingAgentTui` reaches the pod as `CONVEYOR_TUI` (via\n * `key-resolution.ts` → the bootstrap bundle), alongside that TUI's\n * credentials. Before this existed the card path hard-wired Claude, so an\n * opencode card booted with opencode credentials and then spawned the `claude`\n * binary — parking at a sign-in prompt it had no key for.\n *\n * `code-review` is pinned to Claude regardless: the reviewer's verdict comes\n * from the MCP tools (`approve_code_review` / `request_code_changes`), which\n * only mount on an adapter with structured events. A raw-relay reviewer would\n * run, produce no verdict, and park until the stale sweep auto-approved it.\n */\nexport function resolveCardTui(mode: RunnerMode | undefined): TuiKind {\n if (mode === \"code-review\") return \"claude-code\";\n return resolveTuiKindFromEnv(process.env);\n}\n\n/**\n * Adapt an AgentConnection into the harness-neutral PtyBridge consumed by the\n * PTY harness. Keeps the harness package free of any connection-layer import.\n */\nfunction buildPtyBridge(connection: AgentConnection, onBackgroundTaskDone: () => void): PtyBridge {\n return {\n sendOutput: (data, dims) => connection.sendPtyOutput(data, dims),\n sendChatEvent: (event) => connection.sendPtyChatEvent(event),\n sendEnded: () => connection.sendPtyEnded(),\n notifyBackgroundTaskDone: onBackgroundTaskDone,\n notifyAuthNotReady: (detail) => connection.postChatMessage(detail),\n notifyPromptDeliveryFailure: (detail) => connection.postChatMessage(detail),\n requestPodRecycle: (reason) => connection.requestWorkspaceRecycle(reason),\n onInput: (handler) => connection.onPtyInput(handler),\n onResize: (handler) => connection.onPtyResize(handler),\n };\n}\n\nexport class QueryBridge {\n private readonly harness;\n /** In-pod PTY stream server + its bridge decorator (PTY harness only). */\n private readonly directStream: DirectPtyStream | null = null;\n /** Which harness drives this bridge (\"pty\" task chat; \"sdk\" only under the\n * CONVEYOR_FORCE_SDK_CARDS maintainer override). */\n readonly harnessKind: HarnessKind;\n private readonly sessionIds = new Map<string, string>();\n private activeQuery: AsyncGenerator<HarnessEvent, void> | null = null;\n private readonly pendingToolOutputs: { tool: string; output: string }[] = [];\n private _stopped = false;\n private _discoveryCompleted = false;\n private _isParentTask = false;\n private _wasRateLimited = false;\n private _wedgeAborted = false;\n private _keyCycleCount = 0;\n private _abortController: AbortController | null = null;\n\n /** Called by SessionRunner when ExitPlanMode triggers a mode transition. */\n onModeTransition?: (newMode: AgentMode) => void;\n\n /** Called by tool handlers to soft-stop (abort query, keep session alive). */\n onSoftStop?: () => void;\n\n /** Called when the CLI injects a background-task completion notification —\n * one `run_in_background` command / backgrounded subagent finished. Set by\n * SessionRunner (post-construction, like onSoftStop) and read lazily, so the\n * bridge built in the constructor can already close over it. */\n onBackgroundTaskDone?: () => void;\n\n constructor(\n private readonly connection: AgentConnection,\n private readonly mode: ModeController,\n private readonly runnerConfig: AgentRunnerConfig,\n private readonly callbacks: AgentRunnerCallbacks,\n ) {\n const harnessKind = resolveHarnessKind();\n this.harnessKind = harnessKind;\n let bridge: PtyBridge | undefined;\n if (harnessKind === \"pty\") {\n // The relay bridge is wrapped, never replaced: viewers that can reach the\n // pod stream from it directly, and anything that can't keeps working over\n // the `pty:*` relay underneath.\n this.directStream = wrapBridgeWithDirectStream(\n buildPtyBridge(connection, () => this.onBackgroundTaskDone?.()),\n connection,\n );\n bridge = this.directStream.bridge;\n }\n this.harness = createHarness(\n harnessKind,\n bridge,\n harnessKind === \"pty\" ? resolveTuiAdapter(resolveCardTui(runnerConfig.mode)) : undefined,\n );\n }\n\n get isStopped(): boolean {\n return this._stopped;\n }\n\n get isDiscoveryCompleted(): boolean {\n return this._discoveryCompleted;\n }\n\n set isDiscoveryCompleted(val: boolean) {\n this._discoveryCompleted = val;\n }\n\n get isParentTask(): boolean {\n return this._isParentTask;\n }\n\n set isParentTask(val: boolean) {\n this._isParentTask = val;\n }\n\n get wasRateLimited(): boolean {\n return this._wasRateLimited;\n }\n\n /**\n * Whether the turn that just ran was aborted by the mid-turn wedge watchdog\n * (30 minutes of complete event silence). Reset at the start of every\n * execute(); SessionRunner reads it to decide whether an autonomous initial\n * query should self-requeue.\n */\n get lastTurnWedgeAborted(): boolean {\n return this._wedgeAborted;\n }\n\n /**\n * Ask the live terminal (PTY harness only) to redraw its full screen.\n * Safe no-op on the SDK harness or between queries.\n */\n forceRepaint(): void {\n this.harness.forceRepaint?.();\n }\n\n stop(): void {\n this._stopped = true;\n this._abortController?.abort();\n }\n\n resume(): void {\n this._stopped = false;\n }\n\n /**\n * Inject a follow-up message into the turn currently running under the harness\n * (PTY keep-alive) instead of aborting it. Returns true when the harness fed\n * the message into the live TUI; false when there is no running turn to inject\n * into or the harness has no live terminal (SDK) — the caller then supersedes\n * via stop() + respawn.\n */\n injectIntoRunningTurn(content: string): boolean {\n return this.harness.injectIntoRunningTurn?.(content) ?? false;\n }\n\n /**\n * Tear down any parked/active CLI process the harness is keeping alive between\n * turns (PTY keep-alive). Called by SessionRunner on stop/shutdown so the\n * process never outlives the session and the Connected-TUI tab hides. No-op on\n * the SDK harness.\n */\n async dispose(): Promise<void> {\n await this.harness.dispose?.();\n // After the harness, so a final `sendEnded` still reaches attached viewers\n // before the in-pod server stops listening.\n await this.directStream?.dispose();\n }\n\n /**\n * Subscribe to \"a human typed into the parked, idle TUI\" (PTY keep-alive).\n * SessionRunner uses this to wake a passive turn. Returns unsubscribe; no-op\n * (returns a noop unsubscribe) on the SDK harness.\n */\n onPassiveActivity(handler: () => void): () => void {\n return this.harness.onPassiveActivity?.(handler) ?? (() => {});\n }\n\n /**\n * How the INITIAL instructions for this task would be delivered — \"prefill\"\n * means the TUI input is pre-filled but unsubmitted, awaiting the human.\n * Mirrors the decision runSdkQuery makes for the initial (non-follow-up)\n * query so SessionRunner can pick the matching state/timers.\n */\n initialPromptDelivery(context: TaskContext): \"submit\" | \"prefill\" {\n return resolvePromptDelivery({\n harnessKind: this.harnessKind,\n runnerMode: this.runnerConfig.mode,\n isAuto: this.mode.isAuto,\n agentMode: this.mode.effectiveMode,\n isFollowUp: false,\n hasExistingSession: hasExistingSessionFile(context.taskId, this.runnerConfig.workspaceDir, {\n agentMode: this.mode.effectiveMode,\n runnerMode: this.runnerConfig.mode,\n }),\n });\n }\n\n /**\n * Execute a Claude SDK query.\n * Without followUpContent: runs initial mode execution (build/plan).\n * With followUpContent: processes a follow-up user message.\n * `promptDelivery` overrides the executor's submit-vs-prefill resolution —\n * SessionRunner forces \"submit\" when pending chat messages already direct\n * the agent (prefilling would park them until a human touched the TUI).\n */\n async execute(\n context: TaskContext,\n followUpContent?: string | MultimodalBlock[],\n promptDelivery?: \"submit\" | \"prefill\",\n ): Promise<void> {\n this._stopped = false;\n this._wasRateLimited = false;\n this._wedgeAborted = false;\n this._abortController = new AbortController();\n const host = this.buildHost();\n try {\n await runSdkQuery(host, context, followUpContent, promptDelivery);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isAbort = this._stopped || /abort/i.test(msg);\n if (isAbort) {\n logger.info(\"Query stopped by user\", { error: msg });\n } else {\n logger.error(\"Query execution failed\", { error: msg });\n this.connection.sendEvent({ type: \"error\", message: msg });\n }\n } finally {\n this.mode.pendingModeRestart = false;\n this._abortController = null;\n }\n }\n\n /**\n * Drive a passive turn: the parked CLI is producing transcript records because\n * a human typed into the idle Connected-TUI. Mirrors execute()'s setup (fresh\n * abort controller so a superseding chat message can abort, host construction,\n * error classification) but runs the promptless passive drain instead of a\n * full query.\n */\n async executePassive(context: TaskContext): Promise<void> {\n this._stopped = false;\n this._wasRateLimited = false;\n this._abortController = new AbortController();\n const host = this.buildHost();\n try {\n await runPassiveTurn(host, context);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isAbort = this._stopped || /abort/i.test(msg);\n if (isAbort) {\n logger.info(\"Passive turn stopped\", { error: msg });\n } else {\n logger.error(\"Passive turn failed\", { error: msg });\n this.connection.sendEvent({ type: \"error\", message: msg });\n }\n } finally {\n this.mode.pendingModeRestart = false;\n this._abortController = null;\n }\n }\n\n // ── QueryHost construction ──────────────────────────────────────────\n\n private buildHost(): QueryHost {\n // oxlint-disable-next-line no-this-alias -- closure needed for live getter/setter delegation\n const bridge = this;\n return {\n config: this.runnerConfig,\n connection: this.connection,\n callbacks: this.callbacks,\n harness: this.harness,\n harnessKind: this.harnessKind,\n setupLog: [],\n sessionIds: this.sessionIds,\n pendingToolOutputs: this.pendingToolOutputs,\n\n // Live getters/setters delegating to ModeController + bridge state\n get agentMode() {\n return bridge.mode.effectiveMode;\n },\n get isAuto() {\n return bridge.mode.isAuto;\n },\n get isParentTask() {\n return bridge._isParentTask;\n },\n get hasExitedPlanMode() {\n return bridge.mode.hasExitedPlanMode;\n },\n set hasExitedPlanMode(val: boolean) {\n bridge.mode.hasExitedPlanMode = val;\n },\n get pendingModeRestart() {\n return bridge.mode.pendingModeRestart;\n },\n set pendingModeRestart(val: boolean) {\n bridge.mode.pendingModeRestart = val;\n },\n get discoveryCompleted() {\n return bridge._discoveryCompleted;\n },\n set discoveryCompleted(val: boolean) {\n bridge._discoveryCompleted = val;\n },\n get wasRateLimited() {\n return bridge._wasRateLimited;\n },\n set wasRateLimited(val: boolean) {\n bridge._wasRateLimited = val;\n },\n get wedgeAborted() {\n return bridge._wedgeAborted;\n },\n set wedgeAborted(val: boolean) {\n bridge._wedgeAborted = val;\n },\n get keyCycleCount() {\n return bridge._keyCycleCount;\n },\n set keyCycleCount(val: number) {\n bridge._keyCycleCount = val;\n },\n get activeQuery() {\n return bridge.activeQuery;\n },\n set activeQuery(val: AsyncGenerator<HarnessEvent, void> | null) {\n bridge.activeQuery = val;\n },\n get abortController() {\n return bridge._abortController;\n },\n\n isStopped: () => bridge._stopped,\n requestStop: () => bridge.stop(),\n requestSoftStop: () => {\n if (bridge.onSoftStop) bridge.onSoftStop();\n },\n createInputStream: (prompt) => bridge.createInputStream(prompt),\n onModeTransition: bridge.onModeTransition,\n };\n }\n\n // ── Input stream for Claude SDK ─────────────────────────────────────\n\n private async *createInputStream(\n prompt: string | MultimodalBlock[],\n ): AsyncGenerator<HarnessUserMessage, void, unknown> {\n yield {\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content: prompt },\n parent_tool_use_id: null,\n };\n }\n}\n","/**\n * Claude subscription-key usage sampler.\n *\n * Reports the session/weekly rate-limit utilization of the key the pod runs\n * under. The numbers come from the Claude CLI's own `/usage` panel (driven under\n * a PTY — see run-probe.ts) — the authoritative, account-wide gauges the CLI\n * itself shows. Mapped into the `rate_limit_update` events the API already\n * persists (`persistRateLimitSnapshot` →\n * ClaudeSubscriptionKey.sessionUsage/weeklyUsage + usageGauges), which keeps\n * User Settings, the usage widget, and `selectBestKey` rotation honest.\n *\n * Attribution guard: the probe authenticates from `.credentials.json`, but the\n * server attributes samples to the key stamped on THIS session. If the file is\n * authenticated as someone else — a real interactive /login (refreshToken\n * present) or a token that doesn't match the session's own — reporting would\n * write another account's gauges onto this key's row, so the sample is skipped.\n *\n * Best-effort: any probe/parse failure yields `[]`, never throws.\n */\nimport { existsSync } from \"node:fs\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport {\n claudeCredentialsPath,\n readCredentialsIdentity,\n type CredentialsIdentity,\n} from \"../harness/pty/credentials.js\";\nimport { parseUsageGauges, type UsageGaugeReading } from \"../usage/parse-usage.js\";\nimport { runUsageProbe } from \"../usage/run-probe.js\";\n\nconst logger = createServiceLogger(\"usage-sampler\");\n\nexport interface KeyUsageSample {\n rateLimitType: string;\n /** 0..1 utilization fraction (matches UsageBar / getRateLimitColor). */\n utilization: number;\n status: string;\n /** Absolute ISO instant this rate limit resets at, or null if unparseable/absent. */\n resetsAt: string | null;\n /** Full labeled gauge set from the probe (session + per-model weeklies). */\n gauges: UsageGaugeReading[];\n}\n\n/**\n * Decide whether the credentials file's identity may be attributed to this\n * session's key. Pure so the skip rules are unit-testable.\n */\nexport function isAttributable(\n identity: CredentialsIdentity | null,\n sessionToken: string | undefined,\n): { ok: boolean; reason?: string } {\n if (!identity) return { ok: true };\n if (identity.hasRefreshToken) {\n // A real /login owns the file; we cannot know which key row (if any) that\n // account corresponds to.\n return { ok: false, reason: \"manual-login-credentials\" };\n }\n if (sessionToken && identity.accessToken && identity.accessToken !== sessionToken) {\n return { ok: false, reason: \"credentials-token-mismatch\" };\n }\n return { ok: true };\n}\n\n/**\n * Sample the current key's usage via the `/usage` panel and map it to rate-limit\n * samples. Sampling runs only on **subscription** pods: an API-key pod has no\n * `/usage` gauges, so it no-ops.\n *\n * The subscription signal is an OAuth token in env OR a synthesized\n * `~/.claude/.credentials.json`. Gating on the env token ALONE silently disabled\n * this on v3 Claudespace pods, where auth is the credentials file and\n * `CLAUDE_CODE_OAUTH_TOKEN` is NOT in the agent env — the direct cause of usage\n * stats never updating there.\n *\n * `probe`/`hasSubscriptionCredentials`/`readIdentity` are injectable for tests;\n * production callers pass only `token`. Best-effort — never throws.\n */\nexport async function sampleKeyUsage(\n token: string | undefined,\n probe: () => Promise<string> = () => runUsageProbe(),\n hasSubscriptionCredentials: () => boolean = () => existsSync(claudeCredentialsPath()),\n readIdentity: () => Promise<CredentialsIdentity | null> = readCredentialsIdentity,\n): Promise<KeyUsageSample[]> {\n if (!token && !hasSubscriptionCredentials()) return [];\n try {\n const attributable = isAttributable(await readIdentity(), token);\n if (!attributable.ok) {\n logger.info(\"usage sample skipped — credentials not attributable to this session's key\", {\n reason: attributable.reason,\n });\n return [];\n }\n\n const stdout = await probe();\n const { sessionUsage, weeklyUsage, sessionResetsAt, weeklyResetsAt, gauges } =\n parseUsageGauges(stdout);\n const samples: KeyUsageSample[] = [];\n if (sessionUsage !== null) {\n samples.push({\n rateLimitType: \"five_hour\",\n utilization: sessionUsage,\n status: \"allowed\",\n resetsAt: sessionResetsAt,\n gauges,\n });\n }\n if (weeklyUsage !== null) {\n samples.push({\n rateLimitType: \"seven_day\",\n utilization: weeklyUsage,\n status: \"allowed\",\n resetsAt: weeklyResetsAt,\n gauges,\n });\n }\n if (samples.length === 0) {\n // Log a head of the actual output — a deterministic no-gauge reply (e.g.\n // the CLI refusing /usage under env-token auth) is invisible from the\n // length alone and left this pipeline silently dead for months.\n logger.info(\"usage sample produced no gauges\", {\n stdoutLength: stdout.length,\n stdoutHead: stdout.slice(0, 200).replaceAll(\"\\n\", \" \"),\n });\n }\n return samples;\n } catch (error) {\n logger.info(\"usage sample failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return [];\n }\n}\n","const MONTHS = [\"jan\", \"feb\", \"mar\", \"apr\", \"may\", \"jun\", \"jul\", \"aug\", \"sep\", \"oct\", \"nov\", \"dec\"];\n\n/** Offset (ms) of an IANA zone from UTC at a given instant: localWallClock - utc. */\nfunction tzOffsetMs(utcMs: number, tz: string): number {\n const dtf = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n hour12: false,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n });\n const map: Record<string, string> = {};\n for (const part of dtf.formatToParts(new Date(utcMs))) {\n if (part.type !== \"literal\") map[part.type] = part.value;\n }\n const hour = map.hour === \"24\" ? 0 : Number(map.hour);\n const asUtc = Date.UTC(\n Number(map.year),\n Number(map.month) - 1,\n Number(map.day),\n hour,\n Number(map.minute),\n Number(map.second),\n );\n return asUtc - utcMs;\n}\n\n/** UTC epoch ms for a wall-clock time in an IANA zone (or \"UTC\"). DST-safe. */\nfunction zonedWallClockToUtc(\n y: number,\n mo: number,\n d: number,\n h: number,\n mi: number,\n tz: string,\n): number {\n if (tz === \"UTC\" || tz === \"Etc/UTC\") return Date.UTC(y, mo, d, h, mi);\n const naiveUtc = Date.UTC(y, mo, d, h, mi);\n const firstGuess = naiveUtc - tzOffsetMs(naiveUtc, tz);\n return naiveUtc - tzOffsetMs(firstGuess, tz);\n}\n\n/** The IANA zone the Claude CLI renders reset times in when the /usage panel\n * omits the parenthetical: the machine's own local zone (the CLI formats the\n * epoch `resets_at` in local time). On a Claudespace pod that is UTC, so the\n * default is exact there; elsewhere it's off by at most the local↔account tz\n * offset — still far better than a permanent \"reset —\". */\nfunction localTimeZone(): string {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || \"UTC\";\n } catch {\n return \"UTC\";\n }\n}\n\n/**\n * Parse the trailing \"resets …\" phrase of one /usage row into an absolute ISO\n * instant. Handles: \"resets Jul 15 at 2am (America/Chicago)\",\n * \"Resets Jul 20, 7pm (UTC)\", \"Resets 4:40am (UTC)\" (time-only session), and\n * the timezone-less forms the CLI renders when the reset is today —\n * \"Resets 2pm\", \"Resets by 6:00am\" — which fall back to `defaultTz`.\n * Year is inferred as the next occurrence at/after `now`. Best-effort — returns\n * null on any unrecognized shape (never throws).\n */\nexport function parseResetInstant(\n rowText: string,\n now: number,\n defaultTz: string = localTimeZone(),\n): string | null {\n const m =\n /resets\\s+(?:by\\s+)?(?:([a-z]{3})\\s+(\\d{1,2})(?:,|\\s+at)?\\s+)?(\\d{1,2})(?::(\\d{2}))?\\s*(am|pm)(?:\\s*\\(([^)]+)\\))?/i.exec(\n rowText,\n );\n if (!m) return null;\n const [, monStr, dayStr, hourStr, minStr, meridiem, tzRaw] = m;\n const tz = tzRaw ? tzRaw.trim() : defaultTz;\n let hour = Number(hourStr) % 12;\n if (/pm/i.test(meridiem)) hour += 12;\n const minute = minStr ? Number(minStr) : 0;\n const nowDate = new Date(now);\n\n try {\n if (monStr && dayStr) {\n const month = MONTHS.indexOf(monStr.toLowerCase());\n if (month < 0) return null;\n const day = Number(dayStr);\n let utc = zonedWallClockToUtc(nowDate.getUTCFullYear(), month, day, hour, minute, tz);\n // Handle Dec→Jan rollover: a parsed date well in the past means next year.\n if (utc < now - 24 * 60 * 60 * 1000) {\n utc = zonedWallClockToUtc(nowDate.getUTCFullYear() + 1, month, day, hour, minute, tz);\n }\n return new Date(utc).toISOString();\n }\n\n // Time-only (session): next occurrence of this clock time in tz at/after now.\n let utc = zonedWallClockToUtc(\n nowDate.getUTCFullYear(),\n nowDate.getUTCMonth(),\n nowDate.getUTCDate(),\n hour,\n minute,\n tz,\n );\n if (utc <= now) {\n utc = zonedWallClockToUtc(\n nowDate.getUTCFullYear(),\n nowDate.getUTCMonth(),\n nowDate.getUTCDate() + 1,\n hour,\n minute,\n tz,\n );\n }\n return new Date(utc).toISOString();\n } catch {\n // Malformed/unknown timezone (e.g. non-IANA text captured verbatim from CLI\n // output) throws RangeError from Intl.DateTimeFormat. Best-effort: never throws.\n return null;\n }\n}\n","import { parseResetInstant } from \"./reset-parse.js\";\n\nexport interface UsageGaugeReading {\n /** Panel label as rendered, e.g. \"Current session\", \"Current week (Fable)\". */\n label: string;\n /** 0–1 utilization fraction. */\n utilization: number;\n /** Absolute ISO instant this gauge resets at, or null if unparseable/absent. */\n resetsAt?: string | null;\n}\n\nexport interface UsageGauges {\n /** 0–1 utilization for the current 5-hour session window, or null if absent. */\n sessionUsage: number | null;\n /** 0–1 utilization; max across all weekly gauges (all-models + per-model), or null. */\n weeklyUsage: number | null;\n /** Absolute ISO instant the session gauge resets at, or null. */\n sessionResetsAt: string | null;\n /** Soonest absolute ISO instant among weekly gauges, or null. */\n weeklyResetsAt: string | null;\n /** Every gauge the panel rendered, labels preserved (session + each weekly row). */\n gauges: UsageGaugeReading[];\n}\n\n// ANSI CSI (colors / cursor moves) + OSC sequences left in the raw TUI capture.\n// Built via RegExp from the ESC codepoint so no literal control char is embedded\n// in the source (which would trip no-control-regex / confuse editors).\nconst ESC = \"\\\\u001b\";\nconst ANSI_CSI = new RegExp(`${ESC}\\\\[[0-9;?]*[ -/]*[@-~]`, \"g\");\nconst ANSI_OSC = new RegExp(`${ESC}\\\\][^\\\\u0007${ESC}]*(?:\\\\u0007|${ESC}\\\\\\\\)`, \"g\");\n// Box-drawing + block/bar glyphs (U+2500–U+259F) the panel draws its gauges with.\nconst BAR_GLYPHS = /[─-▟]/g;\n\n/**\n * Normalize `/usage` output into plain, gauge-parseable text.\n *\n * The interactive `/usage` panel — the only place the CLI renders the session /\n * weekly gauges (`claude -p /usage` omits them entirely as of CLI 2.x) — is\n * drawn with ANSI escapes and Unicode progress-bar glyphs that glue directly\n * onto the percentage (e.g. `Current session███…30%used`). Stripping them\n * leaves the label and number separated by plain whitespace, which also matches\n * the older `claude -p \"/usage\"` plain-text layout.\n */\nfunction normalizeUsageText(stdout: string): string {\n return stdout\n .replace(ANSI_CSI, \"\")\n .replace(ANSI_OSC, \"\")\n .replace(BAR_GLYPHS, \" \")\n .replace(/\\r/g, \"\");\n}\n\n/**\n * Parse the text of `/usage` into the two gauge numbers we store. Best-effort:\n * any gauge that isn't present becomes null so the poller can skip reporting\n * (e.g. API-key pods have no subscription gauges).\n *\n * Handles both layouts:\n * - legacy `claude -p \"/usage\"`: `Current session: 30% used`\n * - current interactive panel: `Current session … 30%used` (no colon,\n * percentage optionally glued to `used`).\n */\nexport function parseUsageGauges(\n stdout: string,\n now = Date.now(),\n defaultTz?: string,\n): UsageGauges {\n const text = normalizeUsageText(stdout);\n // One pattern for every gauge row: the kind (session/week), an optional\n // parenthetical model qualifier (\"(all models)\", \"(Fable)\"), then the\n // percentage, then the trailing reset phrase (if any). The qualifier must\n // be captured BEFORE the lazy filler so per-model weekly rows keep their\n // identity instead of collapsing. The trailing reset-phrase capture is\n // bounded by a lookahead for the next \"Current session|week\" row, a\n // newline, or end of string — the interactive panel glues consecutive\n // rows onto the same line with no newline separator, so an unbounded\n // `[^\\n]*` would swallow every row after the first.\n const rows = [\n ...text.matchAll(\n /Current (session|week)\\s*(\\([^)\\n]*\\))?[^%\\n]*?(\\d+(?:\\.\\d+)?)\\s*%(?:\\s*used)?([^\\n]*?)(?=Current\\s+(?:session|week)\\b|\\n|$)/gi,\n ),\n ];\n\n const gauges: UsageGaugeReading[] = rows.map((m) => ({\n label: `Current ${m[1].toLowerCase()}${m[2] ? ` ${m[2]}` : \"\"}`,\n utilization: Number(m[3]) / 100,\n resetsAt: parseResetInstant(m[4] ?? \"\", now, defaultTz),\n }));\n\n const session = gauges.find((g) => g.label.startsWith(\"Current session\"));\n const weekly = gauges.filter((g) => g.label.startsWith(\"Current week\"));\n const weeklyResets = weekly.map((g) => g.resetsAt).filter((r): r is string => r !== null);\n return {\n sessionUsage: session ? session.utilization : null,\n weeklyUsage: weekly.length ? Math.max(...weekly.map((g) => g.utilization)) : null,\n sessionResetsAt: session?.resetsAt ?? null,\n // Soonest weekly reset (all weekly rows share one instant in practice).\n weeklyResetsAt: weeklyResets.length\n ? new Date(Math.min(...weeklyResets.map((r) => new Date(r).getTime()))).toISOString()\n : null,\n gauges,\n };\n}\n","import { resolveClaudeBinary } from \"../harness/pty/spawn-args.js\";\nimport {\n killPtyWithEscalation,\n resolvePtySpawn,\n type PtyProcess,\n type PtySpawn,\n} from \"../harness/pty/pty-support.js\";\n\nconst PROBE_TIMEOUT_MS = 30_000;\n// Give the TUI time to boot before typing `/usage`, then keep retrying until the\n// panel renders (first boot on a cold pod can be slow).\nconst FIRST_SEND_MS = 5_000;\nconst RESEND_INTERVAL_MS = 4_000;\nconst MAX_SENDS = 5;\n// Once the gauge panel starts drawing, let it finish painting before capturing.\nconst RENDER_SETTLE_MS = 900;\n\ninterface ProbeTiming {\n firstSendMs: number;\n resendIntervalMs: number;\n settleMs: number;\n}\n\n/**\n * Env for the probe child. CLAUDE_CODE_OAUTH_TOKEN and ANTHROPIC_API_KEY are\n * STRIPPED: with either set, the CLI authenticates from the env var and `/usage`\n * has no subscription gauges to report. Without them the CLI falls back to the\n * synthesized `~/.claude/.credentials.json` — the same auth the interactive TUI\n * uses, where `/usage` renders the session/weekly gauges.\n */\nexport function buildProbeEnv(env: NodeJS.ProcessEnv = process.env): Record<string, string> {\n const clean: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (typeof value === \"string\") clean[key] = value;\n }\n delete clean.CLAUDE_CODE_OAUTH_TOKEN;\n delete clean.ANTHROPIC_API_KEY;\n return clean;\n}\n\n/** The gauge panel has started rendering once the session label + a percent appear. */\nfunction panelRendering(buf: string): boolean {\n return /Current session/i.test(buf) && /%/.test(buf);\n}\n\n/**\n * One `/usage` probe run: drives an interactive `claude` under a PTY, types\n * `/usage`, and captures the rendered panel. Encapsulated so the timers, resend\n * loop, and single-resolve guard stay tidy.\n */\nclass UsageProbeRun {\n private buf = \"\";\n private settled = false;\n private sends = 0;\n private child: PtyProcess | null = null;\n private childExited = false;\n private hardTimer: ReturnType<typeof setTimeout> | null = null;\n private resendTimer: ReturnType<typeof setInterval> | null = null;\n private settleTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n private readonly resolve: (out: string) => void,\n private readonly timing: ProbeTiming,\n ) {}\n\n start(child: PtyProcess, timeoutMs: number): void {\n this.child = child;\n child.onData((data) => this.onData(data));\n child.onExit(() => {\n this.childExited = true;\n this.finishBestEffort();\n });\n this.hardTimer = setTimeout(() => this.finishBestEffort(), timeoutMs);\n this.hardTimer.unref?.();\n const first = setTimeout(() => this.trySend(), this.timing.firstSendMs);\n first.unref?.();\n this.resendTimer = setInterval(() => this.trySend(), this.timing.resendIntervalMs);\n this.resendTimer.unref?.();\n }\n\n private trySend(): void {\n if (this.settled || this.sends >= MAX_SENDS) return;\n this.sends += 1;\n try {\n this.child?.write(\"/usage\\r\");\n } catch {\n /* pty gone — the hard timeout will resolve */\n }\n }\n\n private onData(chunk: string): void {\n this.buf += chunk;\n if (this.settleTimer || !panelRendering(this.buf)) return;\n // Panel is painting — capture once it settles.\n this.settleTimer = setTimeout(() => this.finish(this.buf), this.timing.settleMs);\n }\n\n private finishBestEffort(): void {\n this.finish(panelRendering(this.buf) ? this.buf : \"\");\n }\n\n private finish(out: string): void {\n if (this.settled) return;\n this.settled = true;\n if (this.hardTimer) clearTimeout(this.hardTimer);\n if (this.resendTimer) clearInterval(this.resendTimer);\n if (this.settleTimer) clearTimeout(this.settleTimer);\n if (this.child) killPtyWithEscalation(this.child, () => this.childExited);\n this.resolve(out);\n }\n}\n\nexport interface UsageProbeDeps {\n /** Injectable for tests; production resolves via resolvePtySpawn() — the\n * workbench-aware seam, so split-mode pods run the probe CLI in the\n * workbench container, never the 1Gi agent sidecar. */\n spawn?: PtySpawn;\n binary?: string;\n cwd?: string;\n timeoutMs?: number;\n firstSendMs?: number;\n resendIntervalMs?: number;\n settleMs?: number;\n /**\n * Base environment for the probe child (before OAuth/API-key stripping).\n * Defaults to `process.env`. The multi-key refresh passes a per-key env with\n * `CLAUDE_CONFIG_DIR` pointed at an isolated credentials dir so probing key B\n * never disturbs the pod's own `~/.claude/.credentials.json`.\n */\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Drive `claude` under a PTY, type `/usage`, and resolve the captured panel text\n * (raw, ANSI included — `parseUsageGauges` normalizes it).\n *\n * Why a PTY and not `claude -p \"/usage\"`: as of CLI 2.x, print mode emits only\n * the \"what's contributing to your limits\" insights — the session/weekly\n * utilization gauges render ONLY in the interactive `/usage` panel. Print mode\n * therefore never yields gauges, which is why the sampler produced nothing.\n *\n * Best-effort: resolves \"\" on spawn error, missing node-pty, or timeout without\n * a rendered panel — never rejects.\n */\nexport async function runUsageProbe(deps: UsageProbeDeps = {}): Promise<string> {\n let spawn = deps.spawn;\n if (!spawn) {\n try {\n spawn = await resolvePtySpawn();\n } catch {\n return \"\";\n }\n }\n const binary = deps.binary ?? resolveClaudeBinary();\n const cwd = deps.cwd ?? process.cwd();\n const timeoutMs = deps.timeoutMs ?? PROBE_TIMEOUT_MS;\n const timing: ProbeTiming = {\n firstSendMs: deps.firstSendMs ?? FIRST_SEND_MS,\n resendIntervalMs: deps.resendIntervalMs ?? RESEND_INTERVAL_MS,\n settleMs: deps.settleMs ?? RENDER_SETTLE_MS,\n };\n\n return new Promise<string>((resolve) => {\n let child: PtyProcess;\n try {\n child = spawn(binary, [], {\n name: \"xterm-256color\",\n cols: 120,\n rows: 45,\n cwd,\n env: buildProbeEnv(deps.env),\n });\n } catch {\n resolve(\"\");\n return;\n }\n new UsageProbeRun(resolve, timing).start(child, timeoutMs);\n });\n}\n","import {\n CLONE_TIMEOUT_MS,\n DEFAULT_RETRY_DELAY_MS,\n FETCH_TIMEOUT_MS,\n GIT_PREP_MAX_RETRIES,\n} from \"../boot/git-prep.js\";\nimport { getWorkbenchClient } from \"../workbench/client.js\";\nimport { WorkbenchError } from \"../workbench/errors.js\";\nimport { workbenchEnabled } from \"../workbench/mode.js\";\nimport type { GitStatusFrame } from \"../workbench/protocol.js\";\n\n/**\n * Result of the agent-side git-readiness gate.\n *\n * - `\"ready\"` — the workbench daemon's `GitPrepJob` reported `ready`; the\n * task repo is up to date.\n * - `\"failed\"` — the daemon reported `failed` (all retries exhausted). The\n * caller must NOT operate on the repo.\n * - `\"timeout\"` — the daemon never reported `ready`/`failed` before the\n * deadline, or the wait was aborted.\n * - `\"not-gated\"` — the workbench split is not enabled for this pod (GitHub\n * Codespaces, local dev, or the workbench container itself),\n * so there is no daemon to gate on.\n */\nexport type GitReadyState = \"ready\" | \"failed\" | \"timeout\" | \"not-gated\";\n\nexport interface AwaitGitReadyOptions {\n /** Overall deadline. See DEFAULT_TIMEOUT_MS for why this defaults so high. */\n timeoutMs?: number;\n /** Poll interval. Defaults to 200ms. */\n pollMs?: number;\n /** Optional log sink for progress messages. */\n onLog?: (msg: string) => void;\n /** Optional shutdown signal. Aborting resolves promptly with \"timeout\"\n * rather than rejecting — callers (session/supervisor shutdown paths)\n * treat an aborted wait as just another way of not becoming ready. */\n signal?: AbortSignal;\n /** Test seam; defaults to getWorkbenchClient(). */\n clientFn?: () => { gitStatus(): Promise<GitStatusFrame> };\n}\n\n/** Extra headroom past the daemon's theoretical worst case. */\nconst GATE_MARGIN_MS = 5 * 60_000;\n\n/**\n * DERIVED from the daemon's retry envelope, not hand-picked: `GitPrepJob`\n * can legitimately stay \"pending\" through `GIT_PREP_MAX_RETRIES` attempts,\n * each bounded by a clone timeout plus a fetch timeout, with a retry delay\n * between attempts — before it either reports \"ready\" or gives up and\n * reports \"failed\". Timing out this gate before that envelope elapses would\n * misreport a slow-but-recovering prep (e.g. a hung clone the daemon's own\n * retry loop is still working through) as a failure — exactly the misreport\n * this gate exists to prevent. Deriving the ceiling means a future change to\n * the git-prep timeouts automatically moves the gate with it.\n * (= 3_020_000 ms ≈ 50 min with today's numbers.)\n */\nexport const DEFAULT_TIMEOUT_MS =\n GIT_PREP_MAX_RETRIES * (CLONE_TIMEOUT_MS + FETCH_TIMEOUT_MS) +\n (GIT_PREP_MAX_RETRIES - 1) * DEFAULT_RETRY_DELAY_MS +\n GATE_MARGIN_MS;\nconst DEFAULT_POLL_MS = 200;\n\n/**\n * Block until the workbench daemon's background git preparation reports\n * ready or failed over the `gitStatus` loopback op — the agent-side gate:\n * Claude must not spawn on a stale branch, and setup/start scripts need the\n * repo present.\n *\n * When the workbench split is not enabled for this pod (GitHub Codespaces,\n * local dev, or the workbench container itself), returns `\"not-gated\"`\n * immediately — those environments have no daemon-owned background git prep\n * to wait on. The agent's own authoritative checkout (session-runner phase\n * 3.5b) runs unconditionally afterward regardless of which state resolved.\n *\n * Never throws and always resolves to a `GitReadyState` — an explicit\n * shutdown abort resolves promptly with `\"timeout\"` instead of rejecting.\n */\nexport function awaitGitReady(opts: AwaitGitReadyOptions = {}): Promise<GitReadyState> {\n if (!workbenchEnabled()) {\n return Promise.resolve(\"not-gated\");\n }\n const clientFn = opts.clientFn ?? getWorkbenchClient;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;\n\n opts.onLog?.(\"waiting for workspace git (workbench daemon)\");\n return pollDaemon(clientFn, timeoutMs, pollMs, opts.onLog, opts.signal);\n}\n\n/** Resolves after `ms`, or early (without rejecting) if `signal` aborts —\n * the poll loop's own abort check on the next iteration is what turns an\n * early wake into a prompt \"timeout\" resolution. */\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n }\n if (signal.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve();\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * One `gitStatus` poll. A null `state` means \"keep polling\"; a non-null one is\n * terminal. `log`, when present, is the message the caller should surface.\n */\ninterface PollOutcome {\n state: GitReadyState | null;\n log?: string;\n}\n\n/** `reportError` gates the transient-error log to the FIRST occurrence — a\n * daemon mid-restart must not spam the pod log every poll interval. */\nasync function pollOnce(\n clientFn: () => { gitStatus(): Promise<GitStatusFrame> },\n reportError: boolean,\n): Promise<PollOutcome> {\n try {\n const frame = await clientFn().gitStatus();\n if (frame.state === \"ready\") return { state: \"ready\", log: \"workspace git ready\" };\n if (frame.state === \"failed\") {\n return {\n state: \"failed\",\n log: `workspace git preparation failed: ${frame.reason ?? \"unknown reason\"}`,\n };\n }\n // \"pending\" — the daemon is still working; poll again.\n return { state: null };\n } catch (err) {\n // The daemon rejected us outright: a missing/invalid workbench token is\n // deterministic, so every remaining poll would be rejected identically.\n // Retrying it is what turned a token regression into a silent ~50-minute\n // wedge — fail fast and loud instead.\n if (err instanceof WorkbenchError && err.code === \"unauthorized\") {\n return {\n state: \"failed\",\n log: \"workspace git gate unauthorized — workbench token missing or invalid, giving up\",\n };\n }\n // Anything else is potentially transient (daemon mid-restart), so keep\n // polling — but leave a trace in the pod log instead of failing silently.\n const message = err instanceof Error ? err.message : String(err);\n return reportError\n ? { state: null, log: `workspace git poll error (retrying): ${message}` }\n : { state: null };\n }\n}\n\nasync function pollDaemon(\n clientFn: () => { gitStatus(): Promise<GitStatusFrame> },\n timeoutMs: number,\n pollMs: number,\n onLog?: (msg: string) => void,\n signal?: AbortSignal,\n): Promise<GitReadyState> {\n const deadline = Date.now() + timeoutMs;\n let loggedError = false;\n for (;;) {\n if (signal?.aborted) {\n onLog?.(\"workspace git wait aborted — giving up\");\n return \"timeout\";\n }\n const outcome = await pollOnce(clientFn, !loggedError);\n if (outcome.log !== undefined) {\n loggedError = true;\n onLog?.(outcome.log);\n }\n if (outcome.state !== null) return outcome.state;\n if (Date.now() >= deadline) {\n onLog?.(`workspace git not ready after ${timeoutMs}ms — giving up`);\n return \"timeout\";\n }\n await delay(pollMs, signal);\n }\n}\n","/**\n * Runtime preview-port discovery (Claudespace v3).\n *\n * Polls the pod's listening TCP sockets and reports the delta vs a baseline\n * scan taken at startup — i.e. before the start command has had a chance to\n * bind anything — so sshd (2222), the agent's own internals, and sidecar\n * services are never reported. The confirmed set is pushed to the API via\n * `reportDiscoveredPorts` only when it CHANGES (full-replacement semantics),\n * where it lands on `WorkspaceSession.discoveredPorts` and feeds the\n * workspace-attach preview-port list.\n *\n * Bind addresses matter: the preview-router proxies to `http://{podIp}:{port}`,\n * never to loopback, so a listener bound only to 127.0.0.1/::1 is unreachable\n * from outside the pod by construction. Loopback-only listeners are therefore\n * excluded from the report (they'd render a dead eyeball entry that 502s) and\n * logged once so the \"bind 0.0.0.0\" fix is discoverable from the agent log.\n *\n * Source of truth is /proc/net/tcp + /proc/net/tcp6 — present on every Linux\n * pod, needs no binaries (the base image has no `ss`/`netstat` from iproute2).\n * A `netstat` fallback exists for darwin so the real-listener test runs on\n * developer machines; production pods are always Linux.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { execFile } from \"node:child_process\";\nimport type { WorkspaceDiscoveredPort } from \"@project/shared\";\n\n// ── Scanning ────────────────────────────────────────────────────────────────\n\n/** TCP state 0A = LISTEN in /proc/net/tcp[6]. */\nconst PROC_TCP_LISTEN_STATE = \"0A\";\n\n/** One LISTEN socket: its local port and whether the bind is loopback-only. */\nexport interface ListeningSocket {\n port: number;\n loopback: boolean;\n}\n\n/**\n * Scan result: every LISTEN port, plus the subset whose listeners are ALL\n * bound to loopback (unreachable via the pod IP). A port with both a loopback\n * and a wildcard/external listener is NOT loopback-only.\n */\nexport interface ListeningPortScan {\n ports: Set<number>;\n loopbackOnly: Set<number>;\n}\n\n/**\n * Is a /proc/net/tcp[6] hex local address a loopback bind?\n * - tcp (8 hex chars): a little-endian 32-bit word — the LAST byte pair is the\n * first octet, so 127.0.0.0/8 ⇒ trailing \"7F\" (e.g. 127.0.0.1 = \"0100007F\").\n * - tcp6 (32 hex chars): four little-endian 32-bit words. `::1` is all-zero\n * with a final word of \"01000000\"; a v4-mapped `::ffff:127.x.x.x` has word 3\n * \"FFFF0000\" and a 127/8 v4 word. The wildcards (0.0.0.0 / ::) are all-zero\n * and NOT loopback. Unrecognized shapes count as non-loopback so a parse gap\n * over-reports rather than silently hiding a reachable port.\n */\nexport function isLoopbackHexAddress(hex: string): boolean {\n const addr = hex.toUpperCase();\n if (addr.length === 8) {\n return addr.slice(6, 8) === \"7F\";\n }\n if (addr.length === 32) {\n // ::1\n if (addr === \"00000000000000000000000001000000\") return true;\n // v4-mapped: ::ffff:a.b.c.d — check the embedded v4 word for 127/8.\n if (addr.slice(0, 16) === \"0000000000000000\" && addr.slice(16, 24) === \"FFFF0000\") {\n return addr.slice(30, 32) === \"7F\";\n }\n return false;\n }\n return false;\n}\n\n/**\n * Parse /proc/net/tcp or /proc/net/tcp6 content into the LISTEN sockets with\n * their bind class. Format (fixed columns, header line first):\n * sl local_address rem_address st ...\n * 0: 0100007F:0BB8 00000000:0000 0A ...\n * local_address is hex ip:port; st is the hex socket state.\n */\nexport function parseProcNetTcpListeners(content: string): ListeningSocket[] {\n const sockets: ListeningSocket[] = [];\n const lines = content.split(\"\\n\");\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n const cols = line.trim().split(/\\s+/);\n // cols: [sl, local_address, rem_address, st, ...]\n if (cols.length < 4 || cols[3] !== PROC_TCP_LISTEN_STATE) continue;\n const local = cols[1];\n if (!local) continue;\n const [addrHex, portHex] = local.split(\":\");\n if (!addrHex || !portHex) continue;\n const port = Number.parseInt(portHex, 16);\n if (!Number.isInteger(port) || port < 1 || port > 65535) continue;\n sockets.push({ port, loopback: isLoopbackHexAddress(addrHex) });\n }\n return sockets;\n}\n\n/** Fold per-socket rows into the scan shape (loopback-only = no non-loopback\n * listener exists for that port across every source scanned). */\nexport function collectScan(sockets: readonly ListeningSocket[]): ListeningPortScan {\n const ports = new Set<number>();\n const hasExternal = new Set<number>();\n for (const { port, loopback } of sockets) {\n ports.add(port);\n if (!loopback) hasExternal.add(port);\n }\n const loopbackOnly = new Set<number>();\n for (const port of ports) {\n if (!hasExternal.has(port)) loopbackOnly.add(port);\n }\n return { ports, loopbackOnly };\n}\n\nconst DEFAULT_PROC_PATHS = [\"/proc/net/tcp\", \"/proc/net/tcp6\"];\n\n/** Union of LISTEN sockets across the /proc sources. Null when none is\n * readable (non-Linux host) so the poller can disable itself. */\nexport async function readProcListeningPorts(\n procPaths: readonly string[] = DEFAULT_PROC_PATHS,\n): Promise<ListeningPortScan | null> {\n const sockets: ListeningSocket[] = [];\n let readable = false;\n for (const path of procPaths) {\n try {\n const content = await readFile(path, \"utf8\");\n readable = true;\n sockets.push(...parseProcNetTcpListeners(content));\n } catch {\n // Missing tcp6 (or non-Linux) — try the next source.\n }\n }\n return readable ? collectScan(sockets) : null;\n}\n\n/** darwin fallback for local dev/tests: parse `netstat -an -p tcp` LISTEN\n * rows (local address column ends in `.<port>`). Never used on pods. */\nasync function readNetstatListeningPorts(): Promise<ListeningPortScan | null> {\n const output = await new Promise<string | null>((resolve) => {\n execFile(\"netstat\", [\"-an\", \"-p\", \"tcp\"], { timeout: 5000 }, (err, stdout) => {\n resolve(err ? null : stdout);\n });\n });\n if (output === null) return null;\n const sockets: ListeningSocket[] = [];\n for (const line of output.split(\"\\n\")) {\n if (!line.includes(\"LISTEN\")) continue;\n const cols = line.trim().split(/\\s+/);\n const local = cols[3];\n if (!local) continue;\n const lastDot = local.lastIndexOf(\".\");\n if (lastDot < 0) continue;\n const host = local.slice(0, lastDot);\n const port = Number(local.slice(lastDot + 1));\n if (!Number.isInteger(port) || port < 1 || port > 65535) continue;\n const loopback = host.startsWith(\"127.\") || host === \"::1\" || host === \"localhost\";\n sockets.push({ port, loopback });\n }\n return collectScan(sockets);\n}\n\n/** Platform-appropriate scan: /proc on Linux, netstat elsewhere (dev only). */\nexport async function readListeningPorts(): Promise<ListeningPortScan | null> {\n const proc = await readProcListeningPorts();\n if (proc !== null) return proc;\n if (process.platform !== \"linux\") return readNetstatListeningPorts();\n return null;\n}\n\n// ── Poller ──────────────────────────────────────────────────────────────────\n\n/** Ports that are never preview candidates even when bound after baseline:\n * pod sshd (2222) plus the DB/cache sidecars the API also deny-lists\n * (authoritative filter is server-side; this is defense in depth). */\nconst DEFAULT_EXCLUDED_PORTS: readonly number[] = [2222, 5432, 6379, 9200];\n\n/** Linux's default ip_local_port_range lower bound. LISTEN sockets up here\n * are almost always transient auto-assigned ports (debug adapters, test\n * runners binding :0), not dev servers a human wants previewed. */\nconst DEFAULT_EPHEMERAL_PORT_MIN = 32768;\n\nconst DEFAULT_DISCOVERY_INTERVAL_MS = 15_000;\nconst DEFAULT_MAX_PORTS = 16;\n/** A port must survive this many consecutive scans to be reported, and be\n * absent this many to be dropped — filters processes that bind briefly. */\nconst CONFIRM_SCANS = 2;\n\nexport interface PortDiscoveryOptions {\n /** Push the FULL current confirmed set (called only on change). */\n report: (ports: WorkspaceDiscoveredPort[]) => Promise<void>;\n /** Ran after a SUCCESSFUL report with the full confirmed set. Used for the\n * codespace forwarded-port visibility flip; failures are swallowed so a\n * side effect can never break the poller. */\n onReported?: (ports: WorkspaceDiscoveredPort[]) => Promise<void> | void;\n intervalMs?: number;\n maxPorts?: number;\n excludedPorts?: readonly number[];\n /** Ports >= this are ignored as transient/ephemeral. Tests override. */\n ephemeralPortMin?: number;\n /** Scan override for tests; defaults to the platform scanner. */\n scan?: () => Promise<ListeningPortScan | null>;\n now?: () => Date;\n log?: (message: string) => void;\n}\n\ninterface TrackedPort {\n /** Consecutive scans the port has been present (seen) or absent (missed). */\n seen: number;\n missed: number;\n confirmed: boolean;\n detectedAt: string;\n}\n\nexport class PortDiscovery {\n private readonly opts: Required<Pick<PortDiscoveryOptions, \"report\">> & PortDiscoveryOptions;\n private readonly intervalMs: number;\n private readonly maxPorts: number;\n private readonly excluded: Set<number>;\n private readonly ephemeralPortMin: number;\n private readonly scan: () => Promise<ListeningPortScan | null>;\n private readonly now: () => Date;\n private readonly log: (message: string) => void;\n\n private baseline: Set<number> | null = null;\n private readonly tracked = new Map<number, TrackedPort>();\n /** Loopback-only candidates already warned about (once per port). */\n private readonly warnedLoopback = new Set<number>();\n private timer: ReturnType<typeof setInterval> | null = null;\n private ticking = false;\n private disabled = false;\n private stopped = false;\n /** Set when the confirmed set changed (or a report failed) — cleared only\n * after a successful report, so transient RPC failures retry next tick. */\n private reportPending = false;\n private lastReportedKey = \"\";\n\n constructor(options: PortDiscoveryOptions) {\n this.opts = options;\n this.intervalMs = options.intervalMs ?? DEFAULT_DISCOVERY_INTERVAL_MS;\n this.maxPorts = options.maxPorts ?? DEFAULT_MAX_PORTS;\n this.excluded = new Set(options.excludedPorts ?? DEFAULT_EXCLUDED_PORTS);\n this.ephemeralPortMin = options.ephemeralPortMin ?? DEFAULT_EPHEMERAL_PORT_MIN;\n this.scan = options.scan ?? readListeningPorts;\n this.now = options.now ?? (() => new Date());\n this.log = options.log ?? ((m) => process.stderr.write(`[conveyor-agent] ${m}\\n`));\n }\n\n /** Take the baseline scan and start polling. Safe to call once. */\n async start(): Promise<void> {\n if (this.timer || this.disabled || this.stopped) return;\n const baseline = await this.scanSafe();\n if (this.stopped) return;\n if (baseline === null) {\n // No readable socket source on this host — permanently disable.\n this.disabled = true;\n this.log(\"Port discovery disabled: no listening-socket source available\");\n return;\n }\n // Everything already bound (loopback or not) predates the start command\n // and is never a preview candidate.\n this.baseline = baseline.ports;\n this.timer = setInterval(() => void this.tick(), this.intervalMs);\n // Do not hold the process open for the poller.\n this.timer.unref?.();\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n /** One poll cycle. Exposed for tests (deterministic, no timers needed). */\n async tick(): Promise<void> {\n if (this.ticking || this.disabled || !this.baseline) return;\n this.ticking = true;\n try {\n const current = await this.scanSafe();\n // Transient read failure — retry next tick.\n if (current === null) return;\n this.updateTracking(current);\n if (this.reportPending) await this.flushReport();\n } finally {\n this.ticking = false;\n }\n }\n\n private async scanSafe(): Promise<ListeningPortScan | null> {\n try {\n return await this.scan();\n } catch {\n return null;\n }\n }\n\n private isCandidate(port: number): boolean {\n if (this.baseline?.has(port)) return false;\n if (this.excluded.has(port)) return false;\n if (port >= this.ephemeralPortMin) return false;\n return true;\n }\n\n private updateTracking(current: ListeningPortScan): void {\n // Reachable = has at least one non-loopback listener. Loopback-only\n // candidates are unreachable via the pod IP — never track them, but\n // leave a breadcrumb so \"why doesn't my preview work\" is answerable.\n const reachable = new Set<number>();\n for (const port of current.ports) {\n if (!this.isCandidate(port)) continue;\n if (current.loopbackOnly.has(port)) {\n if (!this.warnedLoopback.has(port)) {\n this.warnedLoopback.add(port);\n this.log(\n `Port ${port} is listening on loopback only and cannot be previewed — ` +\n `bind 0.0.0.0 (or the pod IP) to make it reachable through the preview proxy`,\n );\n }\n continue;\n }\n reachable.add(port);\n }\n\n for (const port of reachable) {\n const entry = this.tracked.get(port);\n if (!entry) {\n this.tracked.set(port, { seen: 1, missed: 0, confirmed: false, detectedAt: \"\" });\n continue;\n }\n entry.seen += 1;\n entry.missed = 0;\n if (!entry.confirmed && entry.seen >= CONFIRM_SCANS) {\n entry.confirmed = true;\n entry.detectedAt = this.now().toISOString();\n }\n }\n for (const [port, entry] of this.tracked) {\n if (reachable.has(port)) continue;\n entry.missed += 1;\n entry.seen = 0;\n if (entry.missed >= CONFIRM_SCANS || !entry.confirmed) this.tracked.delete(port);\n }\n const key = this.confirmedKey();\n if (key !== this.lastReportedKey) this.reportPending = true;\n }\n\n private confirmedPorts(): WorkspaceDiscoveredPort[] {\n const confirmed = [...this.tracked.entries()]\n .filter(([, entry]) => entry.confirmed)\n .sort(([a], [b]) => a - b)\n .slice(0, this.maxPorts);\n return confirmed.map(([port, entry]) => ({\n port,\n protocol: \"tcp\" as const,\n detectedAt: entry.detectedAt,\n }));\n }\n\n private confirmedKey(): string {\n return this.confirmedPorts()\n .map(({ port }) => port)\n .join(\",\");\n }\n\n private async flushReport(): Promise<void> {\n const ports = this.confirmedPorts();\n const key = ports.map(({ port }) => port).join(\",\");\n try {\n await this.opts.report(ports);\n this.lastReportedKey = key;\n this.reportPending = false;\n this.log(`Discovered preview ports: [${key || \"none\"}]`);\n } catch {\n // Keep reportPending set — retried on the next tick.\n return;\n }\n try {\n await this.opts.onReported?.(ports);\n } catch {\n // Post-report side effects are best-effort by contract.\n }\n }\n}\n","/**\n * Codespace forwarded-port visibility (GitHub backend only).\n *\n * GitHub auto-forwards a port the moment something binds it, but a port that\n * isn't declared in devcontainer.json is forwarded **private** — the\n * `{codespaceName}-{port}.app.github.dev` URL the preview endpoint hands a\n * teammate 404s until the visibility is flipped. Runtime-discovered ports are\n * by definition not declared, so every port the poller reports needs one\n * best-effort `gh codespace ports visibility` call.\n *\n * Rules this module holds to:\n * - No-op unless we are actually inside a codespace (`CODESPACES=true` and\n * `CODESPACE_NAME` set). On a GKE pod there is nothing to flip.\n * - `org` first, `public` as the fallback — some orgs forbid org-visible ports,\n * and `public` is what `scripts/load-env.sh` already does for 3050/7090.\n * - One attempt per port per process, and NEVER throw: this runs off the\n * port-discovery poller, which must not be broken by a missing `gh` binary.\n */\nimport { execFile } from \"node:child_process\";\n\n/** Result of one `gh` invocation. `ok` false carries stderr for the log line. */\nexport interface VisibilityCommandResult {\n ok: boolean;\n stderr: string;\n}\n\nexport interface CodespacePortVisibilityOptions {\n env?: NodeJS.ProcessEnv;\n /** Command runner override for tests (no spawn). */\n run?: (args: readonly string[]) => Promise<VisibilityCommandResult>;\n log?: (message: string) => void;\n}\n\nconst GH_TIMEOUT_MS = 15_000;\n/** Tried in order; the first that succeeds wins. */\nconst VISIBILITIES = [\"org\", \"public\"] as const;\n\nfunction runGh(args: readonly string[]): Promise<VisibilityCommandResult> {\n return new Promise((resolve) => {\n execFile(\"gh\", [...args], { timeout: GH_TIMEOUT_MS }, (error, _stdout, stderr) => {\n resolve({ ok: !error, stderr: (stderr || (error ? String(error.message) : \"\")).trim() });\n });\n });\n}\n\n/** Are we running inside a GitHub Codespace (vs a GKE claudespace pod)? */\nexport function isCodespaceEnvironment(env: NodeJS.ProcessEnv = process.env): boolean {\n return env.CODESPACES === \"true\" && !!env.CODESPACE_NAME;\n}\n\n/**\n * Best-effort flipper for runtime-discovered forwarded ports. Construct once\n * and call `ensureVisible` after every successful discovered-ports report.\n */\nexport class CodespacePortVisibility {\n private readonly env: NodeJS.ProcessEnv;\n private readonly run: (args: readonly string[]) => Promise<VisibilityCommandResult>;\n private readonly log: (message: string) => void;\n /** Ports already attempted (success or failure) — one try per process. */\n private readonly attempted = new Set<number>();\n\n constructor(options: CodespacePortVisibilityOptions = {}) {\n this.env = options.env ?? process.env;\n this.run = options.run ?? runGh;\n this.log = options.log ?? ((m) => process.stderr.write(`[conveyor-agent] ${m}\\n`));\n }\n\n /** Flip every not-yet-attempted port. Resolves even when everything fails. */\n async ensureVisible(ports: readonly number[]): Promise<void> {\n if (!isCodespaceEnvironment(this.env)) return;\n const codespaceName = this.env.CODESPACE_NAME as string;\n for (const port of ports) {\n if (this.attempted.has(port)) continue;\n this.attempted.add(port);\n await this.flip(port, codespaceName);\n }\n }\n\n private async flip(port: number, codespaceName: string): Promise<void> {\n let lastError = \"\";\n for (const visibility of VISIBILITIES) {\n const result = await this.run([\n \"codespace\",\n \"ports\",\n \"visibility\",\n `${port}:${visibility}`,\n \"-c\",\n codespaceName,\n ]).catch((error: unknown) => ({\n ok: false,\n stderr: error instanceof Error ? error.message : String(error),\n }));\n if (result.ok) {\n this.log(`Forwarded port ${port} set to ${visibility} visibility`);\n return;\n }\n lastError = result.stderr;\n }\n this.log(\n `Could not change visibility of forwarded port ${port} — the preview URL may 404 ` +\n `for other users${lastError ? `: ${lastError}` : \"\"}`,\n );\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { getCurrentBranch, hasUncommittedChanges } from \"./git-utils.js\";\n\n// Async git (execFile, no shell) — synchronous child processes freeze the\n// agent's event loop and starve the socket heartbeat; see git-utils.ts.\nconst execFileAsync = promisify(execFile);\n\n/**\n * Handler for `session:pullBranch` events. Fired against a parent task's\n * connected session when a child PR merges into the parent's branch (feature\n * branch packs). Performs a fast-forward `git pull` of the parent's own\n * branch so the workspace and preview reflect merged child work.\n *\n * No-op (with a warning) if the workspace is dirty or on a different branch —\n * we never want to surprise the agent or the user by overwriting in-flight work.\n */\nexport async function handlePullBranch(workDir: string, branch: string): Promise<void> {\n if (!branch) return;\n\n const current = await getCurrentBranch(workDir);\n if (current !== branch) {\n process.stderr.write(\n `[conveyor-agent] pull_branch ignored — current branch ${current ?? \"(detached)\"} != ${branch}\\n`,\n );\n return;\n }\n\n if (await hasUncommittedChanges(workDir)) {\n process.stderr.write(\n `[conveyor-agent] pull_branch ignored — uncommitted changes on ${branch}\\n`,\n );\n return;\n }\n\n try {\n await execFileAsync(\"git\", [\"fetch\", \"origin\", branch], { cwd: workDir, timeout: 60_000 });\n } catch {\n process.stderr.write(`[conveyor-agent] pull_branch: fetch failed for ${branch}\\n`);\n return;\n }\n\n try {\n await execFileAsync(\"git\", [\"pull\", \"--ff-only\", \"origin\", branch], {\n cwd: workDir,\n timeout: 60_000,\n });\n process.stderr.write(`[conveyor-agent] pull_branch: pulled origin/${branch}\\n`);\n } catch {\n process.stderr.write(\n `[conveyor-agent] pull_branch: ff-only pull failed for ${branch} (likely diverged)\\n`,\n );\n }\n}\n","/**\n * Outstanding background work — the runner's answer to \"the turn ended but the\n * pod is still busy\".\n *\n * A `run_in_background` Bash gate (or a backgrounded subagent) keeps running in\n * the pod after the agent's turn ends. The runner reported `idle` the instant\n * the turn finished, and an idle heartbeat does NOT bump\n * `Workspace.activityExpiresAt` — `heartbeatBumps`\n * (apps/api/src/services/workspace/activity-clock.ts) is `status !== \"idle\"` —\n * so the reconciler slept the pod at the activity window (default 5 min) and\n * killed the gate mid-run. This tracker is the mechanism that replaces the old\n * prompt-level advice (\"the final gate must not use run_in_background\"): while\n * it reports pending work the runner heartbeats non-idle and the clock stays\n * fresh.\n *\n * Two ends:\n * - **Launch** is read off the turn's `tool_use` events. The harness stream\n * has no background-task lifecycle event to prefer instead (`HarnessEvent`\n * has no such member; the SDK's `task_started`/`task_progress` describe\n * subagent progress *inside* a turn, not work that outlives it), so the\n * tool input is the signal.\n * - **Completion** is the CLI's synthetic `<task-notification>` user turn,\n * read off the trusted transcript\n * (`isBackgroundTaskNotificationRecord`, harness/pty/chat-record-mapper.ts).\n *\n * Correlating by task id is not possible from either end — the tool_use input\n * carries no id (the CLI mints it) and the notification text is prose — so the\n * tracker counts rather than pairs, and clamps at zero so a double\n * notification can never underflow into \"pending forever\".\n *\n * Safety cap: every entry carries an absolute deadline, so a notification that\n * never arrives (a lost record, the SDK harness, a child killed out from under\n * the CLI) cannot hold a pod awake indefinitely — the entry expires and the\n * runner falls back to reporting idle.\n */\n\n/** How long one background launch may hold the runner non-idle. */\nexport const BACKGROUND_WORK_MAX_MS = 45 * 60 * 1000;\n\n/**\n * Tools that can start work outliving the turn, and whether they do so by\n * default. `Bash` is foreground unless `run_in_background: true`; the subagent\n * tool is the inverse — it backgrounds unless told otherwise. `Task` is the\n * subagent tool's older name, accepted so the check survives a rename.\n */\nconst BACKGROUND_DEFAULT_BY_TOOL: Record<string, boolean> = {\n bash: false,\n agent: true,\n task: true,\n};\n\nfunction asRecord(input: unknown): Record<string, unknown> | null {\n if (typeof input === \"string\") {\n try {\n const parsed: unknown = JSON.parse(input);\n return typeof parsed === \"object\" && parsed !== null\n ? (parsed as Record<string, unknown>)\n : null;\n } catch {\n return null;\n }\n }\n return typeof input === \"object\" && input !== null ? (input as Record<string, unknown>) : null;\n}\n\n/**\n * Does this `tool_use` start work that outlives the turn? `input` arrives as\n * the JSON string the event pipeline serializes (event-handlers.ts), but a raw\n * object is accepted too.\n */\nexport function isBackgroundLaunch(tool: string, input: unknown): boolean {\n const byDefault = BACKGROUND_DEFAULT_BY_TOOL[tool.toLowerCase()];\n if (byDefault === undefined) return false;\n const flag = asRecord(input)?.run_in_background;\n return typeof flag === \"boolean\" ? flag : byDefault;\n}\n\nexport interface BackgroundWorkTrackerOptions {\n /** Per-entry safety cap. Defaults to `BACKGROUND_WORK_MAX_MS`. */\n maxMs?: number;\n /** Fired whenever the pending set changes, so the caller can refresh the\n * status it reports without waiting for the next heartbeat tick. */\n onChange?: () => void;\n /** Diagnostics sink (stderr in production). */\n log?: (message: string) => void;\n}\n\n/** Counts background launches that have not reported completion yet. */\nexport class BackgroundWorkTracker {\n /** Absolute expiry (epoch ms) of each outstanding launch, oldest first. */\n private readonly deadlines: number[] = [];\n private readonly maxMs: number;\n private readonly onChange: (() => void) | undefined;\n private readonly log: (message: string) => void;\n\n constructor(options: BackgroundWorkTrackerOptions = {}) {\n this.maxMs = options.maxMs ?? BACKGROUND_WORK_MAX_MS;\n this.onChange = options.onChange;\n this.log = options.log ?? ((message) => process.stderr.write(message));\n }\n\n /**\n * Feed one `tool_use` from the turn stream. Returns true when it registered\n * a background launch (test/diagnostic signal; callers can ignore it).\n */\n noteToolUse(tool: string, input: unknown, now: number = Date.now()): boolean {\n if (!isBackgroundLaunch(tool, input)) return false;\n this.deadlines.push(now + this.maxMs);\n this.log(\n `[conveyor-agent] background work started (${tool}); ` +\n `${this.deadlines.length} outstanding — heartbeats stay non-idle\\n`,\n );\n this.onChange?.();\n return true;\n }\n\n /**\n * Feed one background-task completion notification. Clamped at zero: the\n * count is unpaired, so a notification with no matching launch (a launch the\n * runner never saw, a re-injected record) must be a no-op, never a negative\n * balance that would keep the pod awake after the real work finished.\n */\n noteCompletion(now: number = Date.now()): void {\n this.prune(now);\n if (this.deadlines.length === 0) return;\n // Oldest first: with no ids to pair on, FIFO is the best available guess\n // and keeps the surviving deadlines the ones with the most time left.\n this.deadlines.shift();\n this.log(\n `[conveyor-agent] background work finished; ${this.deadlines.length} outstanding\\n`,\n );\n this.onChange?.();\n }\n\n /** Is any non-expired background work outstanding? */\n hasPending(now: number = Date.now()): boolean {\n this.prune(now);\n return this.deadlines.length > 0;\n }\n\n /** Outstanding, non-expired launches. */\n pendingCount(now: number = Date.now()): number {\n this.prune(now);\n return this.deadlines.length;\n }\n\n /** Drop everything (shutdown / session teardown). */\n clear(): void {\n if (this.deadlines.length === 0) return;\n this.deadlines.length = 0;\n this.onChange?.();\n }\n\n /** Expire entries past the safety cap, loudly — a tripped cap means a\n * completion notification never arrived, which is worth seeing in the log. */\n private prune(now: number): void {\n let expired = 0;\n while (this.deadlines.length > 0 && this.deadlines[0] <= now) {\n this.deadlines.shift();\n expired++;\n }\n if (expired === 0) return;\n this.log(\n `[conveyor-agent] background work cap reached (${this.maxMs}ms) for ${expired} ` +\n `outstanding task(s) with no completion notification — reporting idle again\\n`,\n );\n this.onChange?.();\n }\n}\n","/* oxlint-disable max-lines, import/max-dependencies -- lifecycle orchestrator, splitting would scatter tightly-coupled control flow; the WorkPreservation import pushes it one over the dependency cap */\nimport type {\n AgentRunnerStatus,\n AgentMode,\n RunnerMode,\n TaskContext,\n TaskContextDTO,\n} from \"@project/shared\";\nimport { DEFAULT_SONNET_MODEL, PRE_BUILD_TASK_STATUSES, hasTaskPlan } from \"@project/shared\";\nimport {\n AgentConnection,\n type AgentConnectionConfig,\n type IncomingMessage,\n} from \"../connection/agent-connection.js\";\nimport { isPermissionDeniedError } from \"../connection/auth-errors.js\";\nimport { ModeController, type ModeTaskContext } from \"./mode-controller.js\";\nimport { Lifecycle, DEFAULT_LIFECYCLE_CONFIG, type LifecycleConfig } from \"./lifecycle.js\";\nimport { QueryBridge } from \"./query-bridge.js\";\nimport type { AgentRunnerConfig } from \"../runner-types.js\";\nimport {\n ensureOnTaskBranch,\n flushAllPendingWork,\n flushPendingChanges,\n restoreWipSnapshot,\n updateRemoteToken,\n} from \"./git-utils.js\";\nimport { mapChatHistory, readAgentVersion } from \"./session-runner-helpers.js\";\nimport { sampleKeyUsage } from \"../execution/usage-sampler.js\";\nimport { awaitGitReady } from \"../setup/git-ready.js\";\nimport {\n registerBootMilestoneSocketFallback,\n reportBootMilestone,\n} from \"../setup/boot-milestone.js\";\nimport { PortDiscovery } from \"./port-discovery.js\";\nimport { CodespacePortVisibility } from \"./codespace-port-visibility.js\";\nimport { handlePullBranch } from \"./parent-pull-handler.js\";\nimport { isHeavyGateActive } from \"./heavy-gate.js\";\nimport {\n LoopLagMonitor,\n loopStatusForRunnerStatus,\n type LoopStatus,\n} from \"../connection/loop-lag.js\";\nimport { BackgroundWorkTracker } from \"./background-work.js\";\nimport { ensureClaudeCredentials, removeConveyorCredentials } from \"../harness/pty/credentials.js\";\n\n// ── Configuration ──────────────────────────────────────────────────────────\n\n/** Modes whose initial instructions auto-run (submit) at session start. */\nconst AUTO_RUN_MODES = new Set<string>([\"building\", \"auto\", \"review\", \"discovery\", \"chat\"]);\n\n/**\n * Runner modes that drive themselves with no human at the terminal and no\n * follow-up message queued behind the initial turn. When one of these stalls,\n * nothing external will un-park it — see `requeueWedgedInitialQuery`.\n */\nconst AUTONOMOUS_RUNNER_MODES = new Set<string>([\"pack\", \"pm\", \"code-review\"]);\n\nexport interface SessionRunnerConfig {\n connection: AgentConnectionConfig;\n agentMode?: AgentMode;\n runnerMode?: RunnerMode;\n isAuto?: boolean;\n workspaceDir: string;\n model?: string;\n lifecycle?: Partial<LifecycleConfig>;\n}\n\nexport interface SessionRunnerCallbacks {\n onStatusChange: (status: AgentRunnerStatus) => void | Promise<void>;\n onEvent: (event: Record<string, unknown>) => void | Promise<void>;\n}\n\nexport interface SessionRunnerPortDiscovery {\n start(): Promise<void>;\n stop(): void;\n}\n\n/** Duck-typed handle onto the boot supervisor — just enough surface for the\n * runner to release the app's start command once the core loop is live.\n * Avoids importing the concrete WorkspaceCommandSupervisor class here. */\nexport interface SessionRunnerWorkspaceCommands {\n notifyLoopReady(): void;\n}\n\nexport interface SessionRunnerDependencies {\n portDiscovery?: SessionRunnerPortDiscovery;\n}\n\n// ── SessionRunner: main lifecycle orchestrator ─────────────────────────────\n\nexport class SessionRunner {\n readonly connection: AgentConnection;\n readonly mode: ModeController;\n readonly lifecycle: Lifecycle;\n\n private readonly config: SessionRunnerConfig;\n private readonly callbacks: SessionRunnerCallbacks;\n private _state: AgentRunnerStatus = \"connecting\";\n private stopped = false;\n private interrupted = false;\n /** Defense-in-depth: set when the agent emits a \"completed\" event.\n * Prevents the core loop from processing any further messages. */\n private completedThisTurn = false;\n /** Absolute deadline (ms epoch) at which the dormant idle wait must time\n * out. Set on the FIRST entry into dormant idle for a given completion\n * cycle and preserved across iterations so inbound critical messages\n * cannot extend the bound past the configured `dormantTimeoutMs`. Reset\n * to null when the agent transitions out of dormant idle (a wake actually\n * promotes it back to a working turn). */\n private dormantDeadline: number | null = null;\n\n private taskContext: ModeTaskContext | null = null;\n private fullContext: TaskContext | null = null;\n /** getTaskContext promise started in connect() so the longest server\n * roundtrip overlaps the room join + port scan; run() awaits it. */\n private contextPrefetch: Promise<TaskContextDTO> | null = null;\n private queryBridge: QueryBridge | null = null;\n private inputResolver: ((msg: IncomingMessage | null) => void) | null = null;\n private pendingMessages: IncomingMessage[] = [];\n /** Guards overlapping runs of the periodic git flush. */\n private periodicFlushInFlight = false;\n /** Consecutive flush ticks skipped because a heavy gate was running. */\n private gateSkipCount = 0;\n /** Max consecutive gate-deferred ticks (~2 min each) before flushing anyway. */\n private static readonly MAX_GATE_SKIPS = 10;\n /** Runtime preview-port poller (v3 dynamic port discovery). */\n private readonly portDiscovery: SessionRunnerPortDiscovery;\n /** Main event-loop lag measurement, shared with the heartbeat worker. */\n private readonly loopLag = new LoopLagMonitor();\n /** Background work (a `run_in_background` gate, a backgrounded subagent) the\n * turn launched that is still running in the pod after the turn ended. While\n * it reports pending, heartbeats go out non-idle so the workspace activity\n * clock keeps being bumped and the reconciler can't sleep the pod mid-gate. */\n private readonly backgroundWork = new BackgroundWorkTracker({\n onChange: () => this.refreshLoopStatus(),\n });\n /** Boot supervisor handle, set post-construction once it's known (it is\n * started alongside connect(), before the runner itself exists in some\n * call sites) — notified when the core loop goes live so it can release\n * the app's start command. Optional: never set in tests/paths that don't\n * wire a supervisor. */\n private workspaceCommands: SessionRunnerWorkspaceCommands | null = null;\n /** Guards the one-shot `agent_live` boot-milestone report — fired on the\n * first harness event (createQueryBridge's onEvent hook). */\n private agentLiveReported = false;\n\n constructor(\n config: SessionRunnerConfig,\n callbacks: SessionRunnerCallbacks,\n deps: SessionRunnerDependencies = {},\n ) {\n this.config = config;\n this.callbacks = callbacks;\n\n // Compose components\n this.connection = new AgentConnection(config.connection);\n // On the codespace backend a runtime-discovered port is forwarded PRIVATE,\n // so its app.github.dev preview URL 404s for anyone else until visibility\n // is flipped. Best-effort, no-op off-codespace, never throws.\n const portVisibility = new CodespacePortVisibility();\n this.portDiscovery =\n deps.portDiscovery ??\n new PortDiscovery({\n report: (ports) => this.connection.reportDiscoveredPorts(ports),\n onReported: (ports) => portVisibility.ensureVisible(ports.map(({ port }) => port)),\n });\n\n const initialMode =\n config.agentMode ??\n (config.runnerMode === \"pm\" ? (config.isAuto ? \"auto\" : \"discovery\") : \"building\");\n this.mode = new ModeController(initialMode, config.runnerMode, config.isAuto);\n\n const lifecycleConfig = { ...DEFAULT_LIFECYCLE_CONFIG, ...config.lifecycle };\n this.lifecycle = new Lifecycle(lifecycleConfig, {\n onHeartbeat: () => {\n // Re-resolve every beat, not just on state changes: an outstanding\n // background task can finish — or hit its safety cap — while the\n // runner sits idle, and nothing else would flip the status back.\n const loopStatus = this.refreshLoopStatus();\n this.connection.sendHeartbeat(this.loopLag.takeMaxLagMs(), loopStatus);\n },\n onIdleTimeout: () => {\n process.stderr.write(\"[conveyor-agent] Idle timeout reached, stopping agent\\n\");\n this.stopped = true;\n // A prefilled initial query parks inside executeQuery (no\n // inputResolver) — abort it so the wait actually ends.\n this.queryBridge?.stop();\n if (this.inputResolver) {\n const resolver = this.inputResolver;\n this.inputResolver = null;\n resolver(null);\n }\n },\n onDormantTimeout: () => {\n process.stderr.write(\"[conveyor-agent] Dormant idle timeout reached, shutting down\\n\");\n this.stopped = true;\n this.queryBridge?.stop();\n if (this.inputResolver) {\n const resolver = this.inputResolver;\n this.inputResolver = null;\n resolver(null);\n }\n },\n onTokenRefresh: () => void this.refreshGithubToken(),\n onGitFlush: () => void this.periodicGitFlush(),\n onUsageSample: () => void this.sampleAndReportKeyUsage(),\n });\n }\n\n get state(): AgentRunnerStatus {\n return this._state;\n }\n\n get sessionId(): string {\n return this.connection.sessionId;\n }\n\n get isStopped(): boolean {\n return this.stopped;\n }\n\n /** Wire the boot supervisor handle post-construction — cli.ts constructs it\n * via startWorkspaceCommandsAfterConnect() (which needs connect() to already\n * be callable), so it can't be a constructor dependency. */\n setWorkspaceCommands(supervisor: SessionRunnerWorkspaceCommands | null): void {\n this.workspaceCommands = supervisor;\n }\n\n // ── Main lifecycle ─────────────────────────────────────────────────\n\n /**\n * Establish the API connection, wire callbacks, and join the session room.\n * Call this before run() when you need to send events (e.g. setup/start\n * command output) before the main agent lifecycle begins.\n */\n async connect(): Promise<boolean> {\n await this.setState(\"connecting\");\n\n // 1. Connect\n await this.connection.connect();\n await this.setState(\"connected\");\n this.connection.sendEvent({ type: \"connected\", sessionId: this.sessionId });\n\n // 2. Wire callbacks\n this.wireConnectionCallbacks();\n // Off-pod (codespace) boot milestones ride the socket — register the\n // fallback as soon as the authenticated connection exists so the\n // supervisor's start_command_launched (and friends) reach the meter.\n registerBootMilestoneSocketFallback((key) => this.connection.reportBootMilestone(key));\n this.lifecycle.startHeartbeat();\n // Loop-lag measurement + the starvation-proof heartbeat worker: a stalled\n // main loop must not silence liveness (lease TTL 150s + 120s grace) — the\n // worker keeps beating with `loopLagMs` so the API can tell busy from dead.\n this.loopLag.start();\n this.connection.startHeartbeatWorker(this.loopLag.sharedBuffer);\n this.lifecycle.startTokenRefresh();\n // Report the running subscription key's usage right away, then periodically.\n // Read-only `claude -p \"/usage\"` subprocess — safe to start pre-`run()`,\n // unlike the git-flush timer below.\n this.lifecycle.startUsageSample();\n // NOTE: the periodic git-flush timer is NOT started here. It touches the\n // repo (git add/stash/reset + force-push conveyor-wip/<branch>) with no\n // git-ready guard of its own, so starting it before `run()`'s\n // `awaitGitReady` gate resolves could race entrypoint.sh's backgrounded\n // checkout/merge (index.lock contention, or a force-push over a\n // not-yet-restored WIP snapshot). It is started in `run()` instead, only\n // once git prep is confirmed ready.\n\n // 2.4. Prefetch the task context CONCURRENTLY with the room join and the\n // port-baseline scan below — it needs only the authenticated socket, and\n // it is the longest server roundtrip on the boot path (history included).\n // run() awaits this promise; the branch-catch suppresses an unhandled\n // rejection if connect() bails (stop/shutdown) before run() consumes it —\n // awaiting the original promise still surfaces the error.\n this.contextPrefetch = this.connection.call(\"getTaskContext\", {\n sessionId: this.sessionId,\n includeHistory: true,\n });\n this.contextPrefetch.catch(() => {});\n\n // 2.5. Join session room + retrieve pending messages, and establish the\n // preview-port baseline, concurrently — they are independent. The baseline\n // must exist before releasing the caller to launch setup/start commands:\n // anything already listening (sshd 2222, sidecars, agent internals)\n // belongs in the baseline; application ports opened by workspace commands\n // must be observed by a later poll instead. Unsupported hosts remain\n // non-fatal (a host without /proc/net/tcp disables preview discovery),\n // but a stop while the baseline is pending closes this startup gate so\n // callers cannot launch commands.\n const serverMessages = await this.connectAgentSession();\n // A persistent authorization denial (the session's user is not a project\n // member) can never be fixed by a retry or token refresh — every agent RPC\n // fails ACL. Park cleanly instead of letting the rejection crash the\n // process into the supervisor's 3× restart loop. connect() returning false\n // routes the CLI to its graceful stop-before-commands exit (code 0).\n if (serverMessages === null) return false;\n for (const msg of serverMessages) {\n if (msg.content) {\n this.pendingMessages.push({ content: msg.content, userId: msg.userId });\n }\n }\n if (this.stopped) return false;\n\n // 2.6. Fire-and-forget: tell the API our agent version. If a newer\n // @rallycry/conveyor-agent is on NPM, the API will queue a base image\n // rebuild for the project (deduped per-project across concurrent agents).\n // We continue running with the current version regardless.\n const agentVersion = readAgentVersion();\n if (agentVersion) {\n this.connection\n .call(\"notifyAgentVersion\", { sessionId: this.sessionId, agentVersion })\n .catch(() => {\n // Best-effort — don't block agent startup if NPM lookup or rebuild fails\n });\n }\n return true;\n }\n\n /**\n * The `connectAgent` handshake (joins the session room, drains pending\n * messages), run concurrently with the preview-port baseline scan. Returns\n * the server's pending messages, or `null` when the session is not authorized\n * for the project — a permission denial no retry or token refresh can fix, so\n * the caller parks cleanly rather than crash-looping. Any other error is\n * rethrown (transient — the normal startup-failure path handles it).\n */\n private async connectAgentSession(): Promise<Array<{\n content: string;\n userId: string;\n createdAt: string;\n }> | null> {\n try {\n const [{ pendingMessages }] = await Promise.all([\n this.connection.call(\"connectAgent\", { sessionId: this.sessionId }),\n this.portDiscovery.start().catch(() => {}),\n ]);\n return pendingMessages;\n } catch (err) {\n if (!isPermissionDeniedError(err)) throw err;\n process.stderr.write(\n `[conveyor-agent] Not authorized for this project (session ${this.sessionId}) — ` +\n `the session user lacks project access; parking instead of retrying.\\n`,\n );\n return null;\n }\n }\n\n /**\n * Run the main agent lifecycle: fetch context, resolve mode, execute, loop.\n * Requires connect() to have been called first.\n */\n // oxlint-disable-next-line max-lines-per-function, complexity -- lifecycle orchestration is inherently sequential\n async run(): Promise<void> {\n // 3. Fetch context — normally already in flight since connect() (the\n // prefetch overlaps the room join + port scan); the direct call is the\n // fallback for callers that drive run() without connect() (tests).\n await this.setState(\"fetching_context\");\n try {\n const ctx = await (this.contextPrefetch ??\n this.connection.call(\"getTaskContext\", {\n sessionId: this.sessionId,\n includeHistory: true,\n }));\n this.fullContext = this.buildFullContext(ctx);\n this.taskContext = {\n status: ctx.status,\n plan: ctx.plan,\n storyPointId:\n ctx.storyPoints === null || ctx.storyPoints === undefined\n ? null\n : String(ctx.storyPoints),\n model: ctx.model,\n githubPRUrl: ctx.githubPRUrl,\n isParentTask: this.fullContext.isParentTask,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to fetch task context\";\n this.connection.sendEvent({ type: \"error\", message });\n await this.callbacks.onEvent({ type: \"error\", message });\n await this.shutdown(\"error\");\n return;\n }\n\n // 3.5. Initial git setup. In split-mode pods, the workbench daemon runs\n // git prep (fetch + checkout) in the BACKGROUND (so the card lights up\n // before git finishes) and reports its state over the `gitStatus`\n // loopback op. Gate Claude on that state: it must never spawn on a stale\n // branch. `awaitGitReady` returns \"not-gated\" immediately when the\n // workbench split isn't enabled (GitHub Codespaces / local), preserving\n // those environments' own git-sync below.\n const gitState = await awaitGitReady({\n onLog: (m) => process.stderr.write(`[conveyor-agent] ${m}\\n`),\n });\n if (gitState === \"failed\" || gitState === \"timeout\") {\n const message =\n gitState === \"failed\"\n ? \"Workspace git preparation failed (see pod logs)\"\n : \"Workspace git preparation timed out (see pod logs)\";\n this.connection.sendEvent({ type: \"error\", message });\n await this.callbacks.onEvent({ type: \"error\", message });\n // Do NOT spawn Claude on a broken/absent repo — mirror the context-fetch\n // failure handling above.\n await this.shutdown(\"error\");\n return;\n }\n\n // 3.5b. Authoritative checkout — the entrypoint only guarantees a repo dir\n // with an origin remote; the agent owns branch selection + wip restore.\n // We do NOT merge origin/<base> here: WIP restores cleanly onto the exact\n // HEAD it was cut from, and the agent merges base when it chooses to.\n if (this.fullContext?.githubBranch) {\n const ok = await ensureOnTaskBranch(\n this.config.workspaceDir,\n this.fullContext.githubBranch,\n this.fullContext.baseBranch ?? undefined,\n );\n if (!ok) {\n process.stderr.write(\"[conveyor-agent] WARNING: task-branch checkout failed\\n\");\n }\n if (ok) void reportBootMilestone({ key: \"branch_ready\" });\n }\n\n // Git prep is confirmed ready — the workbench daemon's GitPrepJob reported\n // \"ready\" over the gitStatus op (the state awaitGitReady polls for), and\n // the authoritative checkout above has now finished — so it is finally\n // safe to arm the periodic WIP flush timer. Starting it any earlier (e.g.\n // in connect(), or before the block above) races either the daemon's\n // backgrounded git prep or the checkout above: the flush takes\n // .git/index.lock and force-pushes conveyor-wip/<branch> with no\n // git-ready guard of its own. Skip arming it\n // if the runner is already stopping (e.g. idle/dormant timeout fired while\n // we were gated on git). `startGitFlush()` internally stops any prior timer\n // first, so even if this were reached twice there is no double-start.\n if (!this.stopped) {\n this.lifecycle.startGitFlush();\n }\n\n // 3.6. Recover uncommitted work a previous pod pushed to conveyor-wip.\n if (this.fullContext?.githubBranch) {\n const restored = await restoreWipSnapshot(\n this.config.workspaceDir,\n this.fullContext.githubBranch,\n );\n if (restored !== \"none\") {\n process.stderr.write(`[conveyor-agent] WIP snapshot restore: ${restored}\\n`);\n }\n }\n\n // 4. Reconcile mode from server context (overrides env-var defaults)\n this.mode.applyServerMode(this.fullContext?.agentMode, this.fullContext?.isAuto);\n this.mode.resolveInitialMode(this.taskContext);\n\n // 4.1. Belt-and-braces recovery for auto cards that already HAVE a plan\n // but are stuck in a pre-build status (crash/relaunch that missed the\n // server-side bump): fire the InProgress advance + identification. A\n // plan-less card deliberately stays put — the card advances when its\n // first plan lands (server-side maybeIdentifyOnFirstPlan), never at boot,\n // so a fresh auto card is not identified/moved before any plan exists.\n // Fire-and-forget — best-effort.\n if (\n this.fullContext?.isAuto &&\n PRE_BUILD_TASK_STATUSES.has(this.taskContext.status) &&\n this.mode.isBuildCapable &&\n hasTaskPlan(this.fullContext.plan)\n ) {\n void this.connection.triggerIdentification().catch(() => {});\n }\n\n // 4.5. Create query bridge for SDK execution\n this.queryBridge = this.createQueryBridge();\n\n // 5. Log initialization\n this.logInitialization();\n\n // 6. Execute initial mode\n const staleBatch = [...this.pendingMessages];\n const didExecuteInitialQuery = await this.executeInitialMode();\n\n // Clear stale pending messages from connectAgent — they were already\n // included in the initial task context (chat history). Any messages\n // that arrived via live socket events DURING initial mode are not in\n // the snapshot, so they survive. Removal is by object identity because\n // executeInitialMode may itself consume/fold entries (prefill paths).\n // Only splice when the initial mode actually ran a query (auto/building/\n // review/pack/discovery/prefill) — a parked `help` prefill skips the query,\n // so its pending messages must be retained for the core loop to process. A\n // stale entry whose content is NOT in the chat-history snapshot (e.g. a\n // queued message that never got a chat row) is kept — silently dropping it\n // would lose the message; the core loop delivers it as a follow-up.\n if (staleBatch.length > 0 && didExecuteInitialQuery) {\n // Non-assistant roles mirror the connect-time chat scan's filter — a\n // pending message always originates from a user/system chat row.\n const historyContents = new Set(\n (this.fullContext?.chatHistory ?? [])\n .filter((m) => m.role !== \"assistant\" && m.content.trim())\n .map((m) => m.content.trim()),\n );\n for (const stale of staleBatch) {\n if (stale.content.trim() && !historyContents.has(stale.content.trim())) continue;\n const idx = this.pendingMessages.indexOf(stale);\n if (idx !== -1) this.pendingMessages.splice(idx, 1);\n }\n }\n\n // Discovery ExitPlanMode during the (prefilled) initial query: planning is\n // done and the runner falls through to the normal idle wait below. Clear\n // the flag so a later follow-up's completion isn't mistaken for a fresh\n // discovery completion (which would drain pending messages in coreLoop).\n if (this.queryBridge?.isDiscoveryCompleted) {\n process.stderr.write(\n \"[conveyor-agent] Discovery completed during initial query — entering idle\\n\",\n );\n this.queryBridge.isDiscoveryCompleted = false;\n }\n\n // 7. Core loop: idle → message → execute → idle\n if (!this.stopped) {\n process.stderr.write(\n `[conveyor-agent] Listening for messages (mode: ${this.mode.effectiveMode})\\n`,\n );\n }\n // Fallback release for paths that never ran an initial query (e.g. a\n // non-auto-run mode that fell through to the core loop). The primary\n // release fires much earlier — on the first harness event of the initial\n // query, or when a prefill parks (see createQueryBridge/onEvent and the\n // prefill branches) — so the app's start command is NOT held behind the\n // entire first turn. Idempotent: notifyLoopReady resolves a settled\n // promise as a no-op.\n this.workspaceCommands?.notifyLoopReady();\n while (!this.stopped) {\n if (this._state !== \"idle\") await this.setState(\"idle\");\n await this.coreLoop();\n }\n\n // 8. Shutdown\n await this.shutdown(\"finished\");\n }\n\n /** Convenience wrapper: connect() then run(). */\n async start(): Promise<void> {\n if (!(await this.connect())) return;\n await this.run();\n }\n\n // ── Core loop ──────────────────────────────────────────────────────\n\n // oxlint-disable-next-line complexity -- dormant idle paths add branches but are tightly coupled to the loop\n private async coreLoop(): Promise<void> {\n while (!this.stopped) {\n // Defense-in-depth: if the agent already emitted a \"completed\" event,\n // stop the loop. The server-side guard should prevent messages from\n // reaching us, but if one leaks through, this prevents the completion\n // cycle (agent says \"done\" → system message → agent says \"done\" → …).\n if (this.completedThisTurn) {\n const resumed = await this.handleDormantIdle();\n if (!resumed) break;\n continue;\n }\n if (this._state === \"idle\") {\n this.lifecycle.startIdleTimer();\n const msg = await this.waitForMessage();\n this.lifecycle.cancelIdleTimer();\n\n if (!msg) {\n if (this.interrupted && !this.stopped) {\n this.interrupted = false;\n continue;\n }\n break;\n }\n\n this.interrupted = false;\n\n if (msg.source === \"pty_passive\") {\n // Keep-alive PTY: a human typed into the parked, idle Connected-TUI.\n // Drain the passive turn (no prompt fed, no synthetic user_message) so\n // status flips to running and the exchange mirrors into chat.\n await this.setState(\"running\");\n await this.executePassive();\n } else {\n await this.callbacks.onEvent({\n type: \"user_message\",\n content: msg.content,\n userId: msg.userId,\n });\n\n // Execute the Claude SDK query with the user's message. A hinted\n // refine message parks in the TUI input for the human instead of\n // auto-submitting.\n if (this.prefillEligible(msg)) {\n await this.runPrefilledMessage(msg, this.mode.effectiveMode);\n } else {\n await this.setState(\"running\");\n await this.executeQuery(msg.content);\n }\n }\n\n // Discovery ExitPlanMode: agent completed its plan — shut down cleanly.\n // No idle state, no message waiting, no chance of being re-woken.\n if (this.queryBridge?.isDiscoveryCompleted) {\n process.stderr.write(\n \"[conveyor-agent] Discovery completed — entering dormant idle (staying connected)\\n\",\n );\n this.pendingMessages.length = 0;\n if (this._state !== \"idle\") await this.setState(\"idle\");\n const discoveryMsg = await this.waitForMessage();\n if (!discoveryMsg) break;\n process.stderr.write(\n \"[conveyor-agent] Received message while discovery-dormant, resuming\\n\",\n );\n this.queryBridge.isDiscoveryCompleted = false;\n this.completedThisTurn = false;\n this.pendingMessages.unshift(discoveryMsg);\n continue;\n }\n\n if (this.stopped) break;\n if (this.interrupted) {\n this.interrupted = false;\n continue;\n }\n\n await this.flushWipNow(\"WIP: end of turn\");\n if (!this.stopped) await this.setState(\"idle\");\n } else if (this._state === \"error\") {\n await this.setState(\"idle\");\n } else {\n break;\n }\n }\n }\n\n /**\n * Handle dormant-after-completed idle. Returns true if a critical message\n * woke us (caller should `continue` the loop), false if we should break\n * (stop signal or dormant timeout fired).\n *\n * The absolute deadline is set on first entry per completion cycle and\n * preserved across re-entries: an inbound critical message cannot extend\n * the bound past `dormantTimeoutMs`. Only a genuine wake (clearing\n * `completedThisTurn`) resets the deadline so the next dormant entry\n * starts a fresh window.\n */\n private async handleDormantIdle(): Promise<boolean> {\n if (this.dormantDeadline === null) {\n this.dormantDeadline = Date.now() + this.lifecycle.config.dormantTimeoutMs;\n process.stderr.write(\n \"[conveyor-agent] Completed — entering dormant idle (staying connected)\\n\",\n );\n }\n await this.flushWipNow(\"WIP: turn complete\");\n this.pendingMessages.length = 0;\n if (this._state !== \"idle\") await this.setState(\"idle\");\n const remainingMs = Math.max(0, this.dormantDeadline - Date.now());\n this.lifecycle.startDormantTimer(remainingMs);\n const dormantMsg = await this.waitForMessage();\n this.lifecycle.cancelDormantTimer();\n if (!dormantMsg) return false;\n const contentPreview =\n dormantMsg.content.length > 80 ? `${dormantMsg.content.slice(0, 80)}...` : dormantMsg.content;\n process.stderr.write(\n `[conveyor-agent] Received message while dormant, resuming: ` +\n `userId=${dormantMsg.userId}, source=${dormantMsg.source || \"unknown\"}, ` +\n `content=\"${contentPreview.replace(/\\n/g, \"\\\\n\")}\"\\n`,\n );\n this.completedThisTurn = false;\n this.dormantDeadline = null;\n this.pendingMessages.unshift(dormantMsg);\n return true;\n }\n\n // ── Initial mode execution ─────────────────────────────────────────\n\n /** Returns true if an initial query was executed, false otherwise. */\n private async executeInitialMode(): Promise<boolean> {\n if (!this.taskContext || !this.fullContext) return false;\n const effectiveMode = this.mode.effectiveMode;\n\n const intrinsicDelivery = this.queryBridge?.initialPromptDelivery(this.fullContext) ?? \"submit\";\n\n // A single hinted message (Refine → Discovery/Review while the pod was\n // down) parks in the TUI input instead of auto-submitting.\n const hinted = this.prepareInitialPendingMessages(intrinsicDelivery);\n if (hinted) {\n await this.runPrefilledMessage(hinted, effectiveMode);\n return true;\n }\n\n // Remaining pending chat messages already direct the agent (they arrived\n // before it booted) — force submit semantics so they aren't parked behind\n // an unsubmitted prefill: building/review run the initial query as before,\n // discovery falls through to the core loop which processes them.\n const delivery = this.pendingMessages.length > 0 ? \"submit\" : intrinsicDelivery;\n\n // Submit modes auto-run their initial instructions. Interactive discovery\n // now auto-submits too: a fresh interactive card presses Enter on its\n // planner preamble instead of parking an empty TUI. Prefill (PTY task chat,\n // fresh session) still spawns a parked TUI for `help` — the only remaining\n // read-only mode that waits on the human.\n const shouldRun = AUTO_RUN_MODES.has(effectiveMode) || delivery === \"prefill\";\n\n if (!shouldRun) {\n await this.setState(\"idle\");\n return false;\n }\n\n if (delivery === \"prefill\") {\n // The query parks until the human submits in the TUI. Report\n // waiting_for_input (not running) and bound the wait with the idle\n // timer; the first harness event flips state to running via the\n // onStatusChange hook in createQueryBridge, cancelling the timer.\n await this.setState(\"waiting_for_input\");\n // A parked prefill emits no harness events until the human submits —\n // release the start command now so the app isn't held behind a human.\n this.workspaceCommands?.notifyLoopReady();\n await this.callbacks.onEvent({ type: \"execute_mode\", mode: effectiveMode, delivery });\n // A chat message may have raced the awaits above — let coreLoop process\n // it instead of parking it behind an unsubmitted prefill.\n if (this.pendingMessages.length > 0) {\n if (!this.stopped) await this.setState(\"idle\");\n return false;\n }\n this.lifecycle.startIdleTimer();\n try {\n await this.executeQuery(undefined, delivery);\n } finally {\n this.lifecycle.cancelIdleTimer();\n }\n } else {\n await this.setState(\"running\");\n await this.callbacks.onEvent({ type: \"execute_mode\", mode: effectiveMode });\n await this.executeQuery(undefined, delivery);\n await this.requeueWedgedInitialQuery(delivery);\n }\n if (!this.stopped) await this.setState(\"idle\");\n return true;\n }\n\n /**\n * The mid-turn wedge watchdog aborts a turn that produced no events for 30\n * minutes. Its documented recovery — \"the next message respawns with\n * `--resume`\" — assumes a human or a follow-up is coming, which is exactly\n * what an autonomous card does NOT have: after the abort the runner goes\n * idle and the card parks until a pack watchdog or a human notices.\n *\n * So for an autonomous card whose INITIAL query was killed as wedged, re-run\n * that initial query once against the (durable, on-disk) resumed session.\n * Bounded to a single retry: a second wedge is a real failure that should\n * surface as a parked card rather than loop the pod. Skipped when a pending\n * message already exists — the core loop delivers that instead, which is the\n * path the watchdog's original recovery assumed.\n */\n private async requeueWedgedInitialQuery(delivery: \"submit\" | \"prefill\"): Promise<void> {\n if (!this.queryBridge?.lastTurnWedgeAborted) return;\n if (this.stopped || this.interrupted || this.completedThisTurn) return;\n if (this.pendingMessages.length > 0) return;\n if (!this.mode.isAuto && !AUTONOMOUS_RUNNER_MODES.has(this.config.runnerMode ?? \"\")) return;\n process.stderr.write(\n \"[conveyor-agent] Initial query was aborted as wedged with nothing queued behind it — \" +\n \"re-running it once (an autonomous card has no follow-up message coming)\\n\",\n );\n this.connection.sendEvent({\n type: \"error\",\n message:\n \"The first turn stalled and was aborted — retrying it automatically (the conversation resumes from the on-disk session).\",\n });\n await this.setState(\"running\");\n await this.executeQuery(undefined, delivery);\n }\n\n // ── Prefill-delivery helpers ───────────────────────────────────────\n\n /**\n * Startup-queue preamble: the card's initial message reaches a fresh pod\n * twice — inside the task context (chat history) AND as a queued pending\n * message. When the intrinsic delivery is prefill (manual-mode fresh TUI)\n * or a hinted message is queued (Refine), drop those context-duplicates so\n * they don't force submit semantics — a genuinely-new live message still\n * does. Returns the lone hinted message to park, if any.\n */\n private prepareInitialPendingMessages(\n intrinsicDelivery: \"submit\" | \"prefill\",\n ): IncomingMessage | null {\n const hasHintedPending = this.pendingMessages.some((m) => m.delivery === \"prefill\");\n if (this.pendingMessages.length > 0 && (intrinsicDelivery === \"prefill\" || hasHintedPending)) {\n this.foldContextDuplicatePendingMessages();\n }\n return this.takePrefillHintedMessage();\n }\n\n /**\n * Drop pending messages whose content is already present as a user message\n * in the task-context chat history (the card's initial message is delivered\n * both ways). Hinted (prefill) messages are kept — they are consumed by the\n * dedicated prefill path.\n */\n private foldContextDuplicatePendingMessages(): void {\n const userContents = new Set(\n (this.fullContext?.chatHistory ?? [])\n .filter((m) => m.role === \"user\" && m.content.trim())\n .map((m) => m.content.trim()),\n );\n const kept = this.pendingMessages.filter(\n (m) => m.delivery === \"prefill\" || !m.content.trim() || !userContents.has(m.content.trim()),\n );\n const dropped = this.pendingMessages.length - kept.length;\n if (dropped > 0) {\n this.pendingMessages.length = 0;\n this.pendingMessages.push(...kept);\n process.stderr.write(\n `[conveyor-agent] Folded ${dropped} pending message(s) already present in chat context\\n`,\n );\n }\n }\n\n /**\n * Honor a prefill hint only when it is unambiguous: PTY harness, a manual\n * (human-facing) agent mode, no other message queued behind it, and not an\n * automated-critical source. Everything else keeps submit semantics.\n */\n private prefillEligible(msg: IncomingMessage): boolean {\n if (msg.delivery !== \"prefill\") return false;\n if (this.pendingMessages.length > 0) return false;\n if (this.queryBridge?.harnessKind !== \"pty\") return false;\n // Auto cards must never park a prefill in the TUI — the whole point of auto\n // is to submit and keep working, and a parked prefill blocks the human from\n // typing a follow-up. Submit instead.\n if (this.mode.isAuto) return false;\n // \"user\" is the queue-flush default source; \"mode_change\" is the refine\n // wake. Anything else (system/ci_failure/review_trigger/…) must submit.\n if (msg.source && msg.source !== \"mode_change\" && msg.source !== \"user\") return false;\n // Manual modes only.\n const m = this.mode.effectiveMode;\n return m === \"discovery\" || m === \"review\" || m === \"help\";\n }\n\n /** Consume the sole pending message when it should park as a prefill. */\n private takePrefillHintedMessage(): IncomingMessage | null {\n if (this.pendingMessages.length !== 1) return null;\n const [first] = this.pendingMessages;\n if (!first || first.delivery !== \"prefill\") return null;\n this.pendingMessages.length = 0;\n if (this.prefillEligible(first)) return first;\n this.pendingMessages.push(first);\n return null;\n }\n\n /**\n * Park a message in the Connected-TUI input (prefill) and wait for the human\n * to submit. Empty content prefills the mode's initial prompt instead (the\n * latest user chat message — e.g. a Refine wake on a dormant agent). The\n * caller restores the idle state afterwards.\n */\n private async runPrefilledMessage(msg: IncomingMessage, effectiveMode: AgentMode): Promise<void> {\n await this.setState(\"waiting_for_input\");\n // Parked on the human — no harness events until submit; release the\n // start command so the app isn't held behind an unsubmitted TUI.\n this.workspaceCommands?.notifyLoopReady();\n await this.callbacks.onEvent({\n type: \"execute_mode\",\n mode: effectiveMode,\n delivery: \"prefill\",\n });\n this.lifecycle.startIdleTimer();\n try {\n await this.executeQuery(msg.content.trim() ? msg.content : undefined, \"prefill\");\n } finally {\n this.lifecycle.cancelIdleTimer();\n }\n }\n\n // ── Message waiting ────────────────────────────────────────────────\n\n private waitForMessage(): Promise<IncomingMessage | null> {\n if (this.pendingMessages.length > 0) {\n return Promise.resolve(this.pendingMessages.shift() ?? null);\n }\n return new Promise<IncomingMessage | null>((resolve) => {\n this.inputResolver = resolve;\n });\n }\n\n /** Inject a message (from connection callback or external source) */\n injectMessage(msg: IncomingMessage): void {\n if (this.inputResolver) {\n const resolve = this.inputResolver;\n this.inputResolver = null;\n resolve(msg);\n return;\n }\n // A plain same-mode user follow-up arriving mid-turn: paste it into the LIVE\n // running TUI (the CLI queues it and picks it up at the next turn boundary)\n // instead of aborting the turn — which killed the running `claude` process\n // and respawned it. Only for genuine user messages on a running PTY turn;\n // mode changes, prefills, passive sentinels, and system/critical sources\n // still supersede via stop() + respawn below.\n if (\n this._state === \"running\" &&\n this.canInjectIntoRunningTurn(msg) &&\n this.queryBridge?.injectIntoRunningTurn(msg.content)\n ) {\n void this.callbacks.onEvent({\n type: \"user_message\",\n content: msg.content,\n userId: msg.userId,\n });\n return;\n }\n this.pendingMessages.push(msg);\n // Interrupt running query so the new message is processed quickly.\n // waiting_for_input covers a prefilled-but-unsubmitted TUI: the chat\n // message supersedes the prefill (teardown + respawn as follow-up).\n if (this._state === \"running\" || this._state === \"waiting_for_input\") {\n this.queryBridge?.stop();\n }\n }\n\n /**\n * Whether a mid-turn message may be pasted into the live running TUI rather\n * than superseding the turn. Restricted to genuine same-mode user follow-ups:\n * a pending mode restart, an empty body, a prefill hint, or any non-\"user\"\n * source (mode_change / pty_passive / system / ci_failure / review_trigger)\n * must take the abort+respawn path — a mode/fingerprint change needs a fresh\n * spawn, and a prefill must park unsubmitted for the human.\n */\n private canInjectIntoRunningTurn(msg: IncomingMessage): boolean {\n if (this.mode.pendingModeRestart) return false;\n if (!msg.content.trim()) return false;\n if (msg.delivery === \"prefill\") return false;\n if (msg.source && msg.source !== \"user\") return false;\n return true;\n }\n\n // ── Query execution with abort handling ────────────────────────────\n\n /** Run queryBridge.execute, swallowing abort errors from stop/softStop. */\n private async executeQuery(\n followUpContent?: string,\n promptDelivery?: \"submit\" | \"prefill\",\n ): Promise<void> {\n if (!this.fullContext || !this.queryBridge) return;\n try {\n await this.queryBridge.execute(this.fullContext, followUpContent, promptDelivery);\n } catch (err) {\n if (this.interrupted || this.stopped) {\n process.stderr.write(\"[conveyor-agent] Query aborted by stop/softStop signal\\n\");\n return;\n }\n throw err;\n }\n }\n\n /**\n * A human typed into the parked, idle Connected-TUI (keep-alive PTY). Wake the\n * core loop with a sentinel so it drains a passive turn. No-op once stopped.\n */\n private onPassiveTuiActivity(): void {\n if (this.stopped) return;\n this.injectMessage({ content: \"\", userId: \"human\", source: \"pty_passive\" });\n }\n\n /** Run queryBridge.executePassive, swallowing abort errors from stop/softStop. */\n private async executePassive(): Promise<void> {\n if (!this.fullContext || !this.queryBridge) return;\n try {\n await this.queryBridge.executePassive(this.fullContext);\n } catch (err) {\n if (this.interrupted || this.stopped) {\n process.stderr.write(\"[conveyor-agent] Passive turn aborted by stop/softStop signal\\n\");\n return;\n }\n throw err;\n }\n }\n\n // ── Stop / soft-stop ───────────────────────────────────────────────\n\n /** Shared token-refresh closure for the git-flush call sites (periodic\n * backstop + per-turn flush). Never throws — returns undefined so the\n * caller falls back to its existing remote credentials. */\n private async refreshGithubTokenForFlush(): Promise<string | undefined> {\n try {\n const res = await this.connection.call(\"refreshGithubToken\", {\n sessionId: this.connection.sessionId,\n });\n return res.token;\n } catch {\n return undefined;\n }\n }\n\n /** Push uncommitted work to the conveyor-wip ref after a turn. Git-only (no\n * GCS). Primary-branch only — cheap enough to run every turn. Shares the\n * in-flight guard with the periodic backstop so a turn-end flush and a\n * timer tick never overlap. Best-effort, never throws. */\n private async flushWipNow(wipMessage: string): Promise<void> {\n if (this.periodicFlushInFlight || this.stopped) return;\n this.periodicFlushInFlight = true;\n try {\n await flushPendingChanges(this.config.workspaceDir, {\n wipMessage,\n refreshToken: () => this.refreshGithubTokenForFlush(),\n });\n } catch {\n // best effort — the next turn or the backstop timer retries\n } finally {\n this.periodicFlushInFlight = false;\n }\n }\n\n /** Periodic best-effort WIP commit + push during normal agent execution.\n * Covers ungraceful pod termination (OOMKilled, node crash/eviction) where\n * the preStop hook + SIGTERM flush don't get a chance to run. No-ops on a\n * clean tree. Guarded so two ticks can't overlap. Never throws. */\n private async periodicGitFlush(): Promise<void> {\n if (this.periodicFlushInFlight || this.stopped) return;\n // A running heavy gate (test/typecheck/build via singleton.sh) owns the\n // disk and churns the tree — flushing mid-gate snapshots build garbage\n // while competing for the exact IO the gate is starving on. Defer to the\n // next tick, but never indefinitely: a wedged gate must not disable crash\n // protection, so after MAX_GATE_SKIPS consecutive skips we flush anyway.\n if (isHeavyGateActive() && this.gateSkipCount < SessionRunner.MAX_GATE_SKIPS) {\n this.gateSkipCount++;\n if (this.gateSkipCount === 1) {\n process.stderr.write(\"[conveyor-agent] Periodic git flush deferred — heavy gate running\\n\");\n }\n return;\n }\n this.gateSkipCount = 0;\n this.periodicFlushInFlight = true;\n try {\n const result = await flushAllPendingWork(this.config.workspaceDir, {\n wipMessage: \"WIP: periodic auto-commit\",\n refreshToken: () => this.refreshGithubTokenForFlush(),\n });\n if (result.hadWork) {\n process.stderr.write(\n `[conveyor-agent] Periodic git flush: branchesBackedUp=${result.branchesBackedUp} worktreesSnapshotted=${result.worktreesSnapshotted}\\n`,\n );\n }\n } catch {\n // best effort — next tick will retry\n } finally {\n this.periodicFlushInFlight = false;\n }\n }\n\n /** Sample the running Claude subscription key's rate-limit utilization from\n * the Claude CLI `/usage` command and report it as `rate_limit_update` events.\n * The API (`persistRateLimitSnapshot`) attributes them to the key this session\n * launched under, keeping User Settings + the PtY-tab usage widget fresh and\n * `selectBestKey` rotation honest. Best-effort — never throws, no-op when the\n * pod has no OAuth token (e.g. API-key projects). */\n private async sampleAndReportKeyUsage(): Promise<void> {\n if (this.stopped) return;\n const samples = await sampleKeyUsage(process.env.CLAUDE_CODE_OAUTH_TOKEN);\n for (const sample of samples) {\n this.connection.sendEvent({\n type: \"rate_limit_update\",\n rateLimitType: sample.rateLimitType,\n utilization: sample.utilization,\n status: sample.status,\n resetsAt: sample.resetsAt ?? undefined,\n gauges: sample.gauges,\n });\n }\n }\n\n /** Wait (bounded) for any in-flight periodic/turn flush to release the shared\n * guard, so a shutdown flush never races it on `.git/index.lock`. */\n private async waitForFlushSlot(maxWaitMs = 5000): Promise<void> {\n const start = Date.now();\n while (this.periodicFlushInFlight && Date.now() - start < maxWaitMs) {\n await new Promise<void>((resolve) => {\n setTimeout(resolve, 50);\n });\n }\n }\n\n /** Best-effort WIP commit + push on shutdown so in-flight work isn't lost\n * when a claudespace pod is killed. Must be called BEFORE stop() so the\n * connection is still alive for token refresh. Shares the in-flight guard\n * with the periodic/turn flushes (waits one out, then claims the slot) so a\n * SIGTERM mid-flush can't run two concurrent flushes racing the index lock.\n * Never throws. */\n async flushGitOnShutdown(): Promise<void> {\n await this.waitForFlushSlot();\n if (this.periodicFlushInFlight) {\n // Still busy after the wait — skip rather than race the lock. Whatever is\n // running already captured recent state.\n process.stderr.write(\"[conveyor-agent] Shutdown git flush skipped — flush still in flight\\n\");\n return;\n }\n this.periodicFlushInFlight = true;\n try {\n const result = await flushAllPendingWork(this.config.workspaceDir, {\n wipMessage: \"WIP: auto-commit on conveyor-agent shutdown\",\n refreshToken: async () => {\n try {\n const res = await this.connection.call(\"refreshGithubToken\", {\n sessionId: this.connection.sessionId,\n });\n return res.token;\n } catch {\n return undefined;\n }\n },\n });\n if (result.hadWork) {\n process.stderr.write(\n `[conveyor-agent] Shutdown git flush: branchesBackedUp=${result.branchesBackedUp} worktreesSnapshotted=${result.worktreesSnapshotted}\\n`,\n );\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] Shutdown git flush failed: ${msg}\\n`);\n } finally {\n this.periodicFlushInFlight = false;\n }\n }\n\n /** Server-pushed `session:stop`: flush WIP BEFORE tearing down. Plain `stop()`\n * sets `stopped=true` and disconnects with no flush, losing everything since\n * the last periodic flush (≤2 min, up to ~20 min behind a gate-skipping\n * backstop). Flush while the connection is still alive (token refresh), then\n * stop. Idempotent + best-effort; `stop()` always runs. */\n private async stopWithFlush(): Promise<void> {\n if (this.stopped) return;\n // Halt the running turn immediately (the server asked us to stop) but keep\n // the connection alive so the flush can refresh the push token.\n this.queryBridge?.stop();\n try {\n await this.flushGitOnShutdown();\n } finally {\n this.stop();\n }\n }\n\n stop(): void {\n this.stopped = true;\n this.queryBridge?.stop();\n // Keep-alive PTY: kill any parked/active CLI process (fire-and-forget — the\n // server also clears the ring on terminal session status, so a lost ended\n // signal here is covered).\n void this.queryBridge?.dispose().catch(() => {});\n this.portDiscovery.stop();\n // Nothing this session backgrounded outlives the pod's agent process —\n // drop the entries so a stale one can't skew the final status.\n this.backgroundWork.clear();\n this.loopLag.stop();\n this.lifecycle.destroy();\n this.connection.disconnect();\n if (this.inputResolver) {\n const resolver = this.inputResolver;\n this.inputResolver = null;\n resolver(null);\n }\n }\n\n softStop(): void {\n this.interrupted = true;\n this.queryBridge?.stop();\n // Only null-resolve if no flushed messages are already pending — a message\n // arriving via injectMessage() before the soft stop signal means the agent\n // should process it instead of discarding with a null resolution.\n if (this.inputResolver && this.pendingMessages.length === 0) {\n const resolver = this.inputResolver;\n this.inputResolver = null;\n resolver(null);\n }\n }\n\n // ── Context & bridge construction ────────────────────────────────\n\n // oxlint-disable-next-line complexity\n private buildFullContext(ctx: TaskContextDTO): TaskContext {\n const chatHistory = mapChatHistory(ctx.chatHistory);\n\n return {\n taskId: ctx.id,\n projectId: ctx.projectId ?? \"\",\n title: ctx.title,\n description: ctx.description,\n plan: ctx.plan,\n status: ctx.status,\n chatHistory,\n agentId: ctx.agentId ?? null,\n _runnerSessionId: this.sessionId,\n agentInstructions: ctx.agentInstructions ?? \"\",\n model: ctx.model,\n githubBranch: ctx.githubBranch ?? \"\",\n baseBranch: ctx.baseBranch ?? \"\",\n projectName: ctx.projectName ?? null,\n projectDescription: ctx.projectDescription ?? null,\n githubPRUrl: ctx.githubPRUrl,\n claudeSessionId: ctx.claudeSessionId ?? null,\n lastSeenMessageId: ctx.lastSeenMessageId ?? null,\n isParentTask: ctx.isParentTask ?? false,\n storyPoints: ctx.storyPoints ?? undefined,\n projectAgents: ctx.projectAgents ?? undefined,\n projectTags: ctx.projectTags ?? undefined,\n taskTagIds: ctx.taskTagIds ?? undefined,\n projectObjectives: ctx.projectObjectives ?? undefined,\n incidents: ctx.incidents ?? undefined,\n recentRelatedTasks: ctx.recentRelatedTasks ?? undefined,\n agentSettings: ctx.agentSettings ?? null,\n agentMode: ctx.agentMode ?? undefined,\n isAuto: ctx.isAuto,\n };\n }\n\n private createQueryBridge(): QueryBridge {\n const runnerConfig: AgentRunnerConfig = {\n conveyorApiUrl: this.config.connection.apiUrl,\n taskToken: this.config.connection.taskToken,\n taskId: this.fullContext?.taskId ?? \"\",\n model: this.fullContext?.model ?? DEFAULT_SONNET_MODEL,\n instructions: this.fullContext?.agentInstructions ?? \"\",\n workspaceDir: this.config.workspaceDir,\n mode: this.config.runnerMode,\n isAuto: this.config.isAuto,\n };\n\n const bridge = new QueryBridge(this.connection, this.mode, runnerConfig, {\n onStatusChange: (status) => {\n // A prefilled initial query reports running when the human submits\n // in the TUI (first harness event) — leave waiting_for_input and\n // stop the prefill-wait idle timer so a long working turn isn't\n // killed by it.\n if (status === \"running\" && this._state === \"waiting_for_input\") {\n this._state = \"running\";\n this.lifecycle.cancelIdleTimer();\n }\n return this.callbacks.onStatusChange(status as AgentRunnerStatus);\n },\n onEvent: (event) => {\n // A harness event means the PTY is spawned and emitting — release the\n // app's start command now instead of holding it through the whole\n // first turn (idempotent; see workspace-command-supervisor.ts), and\n // report the \"agent working\" boot milestone once per process.\n this.workspaceCommands?.notifyLoopReady();\n if (!this.agentLiveReported) {\n this.agentLiveReported = true;\n void reportBootMilestone({ key: \"agent_live\" });\n }\n // A backgrounded gate/subagent launched in this turn outlives it —\n // remember it so the end-of-turn heartbeat doesn't report idle and let\n // the pod's activity clock expire while it runs.\n this.noteToolUseForBackgroundWork(event as Record<string, unknown>);\n // Track completion for the agent-side guard — once the agent emits\n // \"completed\", the core loop will stop accepting further messages.\n if ((event as Record<string, unknown>).type === \"completed\") {\n this.completedThisTurn = true;\n // Immediately refresh the server's heartbeat timestamp so\n // lastHeartbeatAt can't drift stale while the agent sits dormant\n // waiting for a critical wake-up (e.g. review_trigger). The\n // periodic 30s timer would otherwise leave up to a ~29s gap\n // between the `completed` event and the next heartbeat.\n void this.connection.sendHeartbeat();\n }\n return this.callbacks.onEvent(event);\n },\n });\n\n bridge.isParentTask = this.fullContext?.isParentTask ?? false;\n // The CLI's `<task-notification>` turn — one backgrounded gate/subagent\n // finished, so one outstanding entry retires (PTY harness only; on the SDK\n // harness entries expire on the tracker's safety cap instead).\n bridge.onBackgroundTaskDone = () => this.backgroundWork.noteCompletion();\n\n bridge.onSoftStop = () => {\n process.stderr.write(\"[conveyor-agent] Soft stop requested (discovery ExitPlanMode)\\n\");\n this.softStop();\n };\n\n bridge.onModeTransition = (newMode: AgentMode) => {\n const oldMode = this.mode.effectiveMode;\n process.stderr.write(`[conveyor-agent] Mode transition: ${oldMode} → ${newMode}\\n`);\n this.connection.sendEvent({ type: \"mode_transition\", from: oldMode, to: newMode });\n this.mode.pendingModeRestart = true;\n this.connection.emitModeChanged(newMode);\n this.softStop();\n };\n\n // Keep-alive PTY: a human typing into the parked, idle Connected-TUI wakes a\n // passive turn (no-op on the SDK harness).\n bridge.onPassiveActivity(() => this.onPassiveTuiActivity());\n\n return bridge;\n }\n\n // ── Private helpers ────────────────────────────────────────────────\n\n private wireConnectionCallbacks(): void {\n this.connection.onMessage((msg) => this.injectMessage(msg));\n this.connection.onStop(() => void this.stopWithFlush());\n this.connection.onSoftStop(() => this.softStop());\n // After a reconnect the API process may be a fresh instance (deploy,\n // restart) whose PTY scrollback ring is empty — force a repaint so the\n // Connected-TUI terminal re-seeds instead of staying blank/hidden until\n // the CLI happens to draw again.\n this.connection.onReconnected = () => this.queryBridge?.forceRepaint();\n this.connection.onModeChange((data) => {\n const action = this.mode.handleModeChange(data.agentMode, this.taskContext);\n if (action.type === \"start_auto\") {\n this.connection.emitModeChanged(this.mode.effectiveMode);\n this.softStop();\n } else if (action.type === \"restart_query\") {\n // Server-initiated mode transition (e.g., CI-triggered review).\n // Clear claudeSessionId to prevent SDK resume across model changes\n // (reviewer agent may use a different model than the task agent).\n if (this.fullContext && action.newMode === \"review\") {\n this.fullContext.claudeSessionId = null;\n }\n // On building transition, re-fetch context to pick up the newly created\n // branch (branch creation is deferred until building mode).\n // Also refresh for \"auto\" post-exit (defense-in-depth if \"auto\" leaks through).\n if (\n this.fullContext &&\n (action.newMode === \"building\" ||\n (action.newMode === \"auto\" && this.mode.hasExitedPlanMode))\n ) {\n void this.refreshBranchForBuilding();\n }\n // Exit dormant idle so the review_trigger message that follows\n // is processed in the normal idle path (which handles interrupted\n // correctly without draining pendingMessages).\n this.completedThisTurn = false;\n this.connection.emitModeChanged(action.newMode);\n this.softStop();\n }\n });\n this.connection.onApiKeyUpdate((data) => {\n // A rotation delivers a bare token, never a claude_oauth blob — and the\n // blob wins in planCredentialsWrite, so a stale one would re-synthesize\n // the previous subscription's credentials on both branches below.\n delete process.env.CONVEYOR_CLAUDE_OAUTH;\n if (data.isSubscription) {\n process.env.CLAUDE_CODE_OAUTH_TOKEN = data.apiKey;\n delete process.env.ANTHROPIC_API_KEY;\n // The interactive TUI reads credentials from disk, not the env var —\n // refresh the synthesized file so the next PTY spawn (and any on-401\n // re-read by a live CLI) picks up the rotated subscription token.\n void ensureClaudeCredentials();\n } else {\n process.env.ANTHROPIC_API_KEY = data.apiKey;\n delete process.env.CLAUDE_CODE_OAUTH_TOKEN;\n // Drop our synthesized subscription credentials so a stale token\n // can't keep authenticating future TUI spawns over the API key.\n void removeConveyorCredentials();\n }\n });\n this.connection.onPullBranch(({ branch }) => {\n void handlePullBranch(this.config.workspaceDir, branch);\n });\n }\n\n /** Proactively refresh the GitHub token before the 1-hour expiry. */\n private async refreshGithubToken(): Promise<void> {\n try {\n const res = await this.connection.call(\"refreshGithubToken\", {\n sessionId: this.connection.sessionId,\n });\n const written = await updateRemoteToken(this.config.workspaceDir, res.token);\n process.env.GITHUB_TOKEN = res.token;\n process.env.GH_TOKEN = res.token;\n if (written.credential.ok) {\n process.stderr.write(\"[conveyor-agent] Proactively refreshed GitHub token\\n\");\n } else {\n // A refresh that writes nothing used to be invisible: the credential\n // update swallowed its own error and this line still claimed success.\n process.stderr.write(\n `[conveyor-agent] Warning: refreshed GitHub token but the git credential did not update: ${written.credential.error ?? \"unknown error\"}\\n`,\n );\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[conveyor-agent] Warning: proactive token refresh failed: ${msg}\\n`);\n }\n }\n\n /** Re-fetch task context to pick up a newly created branch and check it out. */\n private async refreshBranchForBuilding(): Promise<void> {\n try {\n const ctx = await this.connection.call(\"getTaskContext\", {\n sessionId: this.sessionId,\n includeHistory: false,\n });\n if (ctx?.githubBranch && this.fullContext) {\n this.fullContext.githubBranch = ctx.githubBranch;\n await ensureOnTaskBranch(this.config.workspaceDir, ctx.githubBranch);\n }\n } catch {\n process.stderr.write(\n \"[conveyor-agent] Warning: failed to refresh branch for building transition\\n\",\n );\n }\n }\n\n /**\n * The loop status the heartbeats should carry right now.\n *\n * `idle` requires BOTH a quiet runner and a quiet pod: an idle runner with a\n * `run_in_background` gate still running reports `waiting`, which reaches the\n * API as `active` and therefore bumps `Workspace.activityExpiresAt` (an idle\n * heartbeat does not — `heartbeatBumps` is `status !== \"idle\"`). Without this\n * the reconciler sleeps the pod one activity window after the turn ends and\n * kills the gate. Note the runner's own `AgentRunnerStatus` stays `idle`:\n * this is a liveness signal, not a UI one, so cards still read as idle.\n *\n * \"Quiet runner\" is `loopStatusForRunnerStatus`, NOT `_state === \"idle\"`.\n * The old `_state !== \"idle\" → active` test made every parked state report\n * work — above all `waiting_for_input`, a prefilled TUI sitting on a human,\n * which renewed the clock on every beat and kept the card \"active\" on the\n * board for the runner's whole 30-minute idle timer regardless of the\n * project's inactivity window. See connection/loop-lag.ts for the table and\n * for why an unknown status still fails open to `active`.\n */\n private resolveLoopStatus(): LoopStatus {\n if (loopStatusForRunnerStatus(this._state) === \"active\") return \"active\";\n return this.backgroundWork.hasPending() ? \"waiting\" : \"idle\";\n }\n\n /** Mirror the resolved status into the loop-lag buffer so the starvation-proof\n * heartbeat worker reports it too. Returns what it wrote. */\n private refreshLoopStatus(): LoopStatus {\n const loopStatus = this.resolveLoopStatus();\n this.loopLag.setStatus(loopStatus);\n return loopStatus;\n }\n\n /** One `tool_use` from the turn stream — registers a background launch when\n * the tool starts work that outlives the turn. */\n private noteToolUseForBackgroundWork(event: Record<string, unknown>): void {\n if (event.type !== \"tool_use\" || typeof event.tool !== \"string\") return;\n this.backgroundWork.noteToolUse(event.tool, event.input);\n }\n\n private async setState(status: AgentRunnerStatus): Promise<void> {\n this._state = status;\n this.refreshLoopStatus();\n await this.connection.emitStatus(status);\n await this.callbacks.onStatusChange(status);\n }\n\n private async shutdown(finalState: AgentRunnerStatus): Promise<void> {\n process.stderr.write(`[conveyor-agent] Shutdown: reason=${finalState}\\n`);\n this.connection.sendEvent({ type: \"shutdown\", reason: finalState });\n this.portDiscovery.stop();\n // Nothing this session backgrounded outlives the pod's agent process —\n // drop the entries so a stale one can't skew the final status.\n this.backgroundWork.clear();\n this.loopLag.stop();\n this.lifecycle.destroy();\n // Keep-alive PTY: tear down the parked/active CLI process before we drop the\n // socket, so the ended signal (ring teardown → tab hides) can go out.\n try {\n await this.queryBridge?.dispose();\n } catch {\n /* best effort */\n }\n try {\n await this.setState(finalState);\n } catch {\n // Best effort — when stop() already tore down the connection the status\n // RPC rejects. A stopped agent should still finish run() cleanly so the\n // process exits 0 instead of taking the error path.\n }\n this.connection.disconnect();\n this._finalState = finalState;\n }\n\n private _finalState: AgentRunnerStatus | null = null;\n\n /** The final status after run() completes. Use to determine exit code. */\n get finalState(): AgentRunnerStatus | null {\n return this._finalState;\n }\n\n private buildTaskContextSnapshot(): Record<string, unknown> {\n return {\n isParentTask: this.fullContext?.isParentTask ?? false,\n status: this.taskContext?.status,\n taskTitle: this.fullContext?.title,\n hasExistingPR: !!this.fullContext?.githubPRUrl,\n hasExistingSession: !!this.fullContext?.claudeSessionId,\n chatHistoryLength: this.fullContext?.chatHistory?.length ?? 0,\n tagIds: this.fullContext?.taskTagIds ?? [],\n };\n }\n\n private buildInitializationContext(): Record<string, unknown> {\n return {\n mode: this.mode.effectiveMode,\n runnerMode: this.config.runnerMode ?? \"task\",\n sessionId: this.sessionId,\n ...this.buildTaskContextSnapshot(),\n model: this.taskContext?.model,\n isAuto: this.config.isAuto ?? false,\n subscriptionKeyLabel: process.env.CONVEYOR_SUBSCRIPTION_KEY_LABEL ?? null,\n };\n }\n\n private logInitialization(): void {\n const context = this.buildInitializationContext();\n process.stderr.write(`[conveyor-agent] Initialized: ${JSON.stringify(context)}\\n`);\n this.connection.sendEvent({ type: \"session_manifest\", ...context });\n }\n}\n","import { join } from \"node:path\";\nimport type { SessionPreviewPort } from \"@project/shared\";\nimport { readWorkspaceFile } from \"../workbench/fs.js\";\n\nexport interface ConveyorConfig {\n startCommand?: string;\n}\n\nexport interface ForwardPortsResult {\n ports: number[];\n attributes: Record<string, { label?: string; visibility?: \"public\" | \"private\" }>;\n}\n\nconst DEVCONTAINER_PATH = \".devcontainer/conveyor/devcontainer.json\";\n\n/** Ports bound by sidecars (postgres/redis/elasticsearch) — never expose. */\nconst DEVCONTAINER_PORT_DENY_LIST = new Set([5432, 6379, 9200]);\n\nexport async function loadForwardPorts(workspaceDir: string): Promise<ForwardPortsResult> {\n try {\n const raw = await readWorkspaceFile(join(workspaceDir, DEVCONTAINER_PATH));\n const parsed = JSON.parse(raw) as {\n forwardPorts?: number[];\n portsAttributes?: Record<string, { label?: string; visibility?: string }>;\n };\n const ports = (parsed.forwardPorts ?? []).filter(\n (p) => typeof p === \"number\" && !DEVCONTAINER_PORT_DENY_LIST.has(p),\n );\n const attributes: ForwardPortsResult[\"attributes\"] = {};\n for (const [key, value] of Object.entries(parsed.portsAttributes ?? {})) {\n if (!value || typeof value !== \"object\") continue;\n const entry: { label?: string; visibility?: \"public\" | \"private\" } = {};\n if (typeof value.label === \"string\") entry.label = value.label;\n if (value.visibility === \"public\" || value.visibility === \"private\") {\n entry.visibility = value.visibility;\n }\n attributes[key] = entry;\n }\n return { ports, attributes };\n } catch {\n return { ports: [], attributes: {} };\n }\n}\n\n/** Merge forwardPorts + portsAttributes into a SessionPreviewPort[] the API\n * can persist directly onto CodespaceSession.previewPorts. Deny-listed\n * ports are filtered (defense-in-depth; authoritative filter lives API-side). */\nexport function buildSessionPreviewPorts(result: ForwardPortsResult): SessionPreviewPort[] {\n return result.ports\n .filter((port) => !DEVCONTAINER_PORT_DENY_LIST.has(port))\n .map((port) => {\n const attr = result.attributes[String(port)];\n const entry: SessionPreviewPort = { port };\n if (attr?.label) entry.label = attr.label;\n if (attr?.visibility) entry.visibility = attr.visibility;\n return entry;\n });\n}\n\n/** Load config from env vars (project-level settings injected via bootstrap).\n * Note: the project's setupCommand runs at image-bake time (server-side Cloud\n * Build) and is never delivered to pods — only startCommand arrives via env. */\nexport function loadConveyorConfig(): ConveyorConfig | null {\n const envStart = process.env.CONVEYOR_START_COMMAND;\n if (envStart) {\n return { startCommand: envStart };\n }\n return null;\n}\n","import { execSync } from \"node:child_process\";\n\n/** Fetch full git history if the repo was cloned with --depth=1. */\nexport function unshallowRepo(workspaceDir: string): void {\n try {\n execSync(\"git fetch --unshallow\", {\n cwd: workspaceDir,\n timeout: 60_000,\n stdio: \"ignore\",\n });\n } catch {\n // Already unshallowed or not a shallow clone\n }\n}\n"],"mappings":"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","names":["delay","stdout","delay","z","mkdir","rm","writeFile","join","isRecord","path","isRecord","isUnknownArray","stringField","truncate","mapSystem","mapAssistant","writeFile","join","createServer","z","writeFile","join","tool","createServer","tool","z","join","writeFile","chmod","mkdir","writeFile","homedir","join","join","join","join","path","io","sleep","writeFile","mkdir","chmod","homedir","join","writeFile","mkdir","rm","spawn","mkdir","unlink","homedir","join","join","homedir","unlink","mkdir","join","path","dirname","join","homedir","join","homedir","path","dirname","tool","mkdtemp","rm","writeFile","join","path","logger","logger","createHash","existsSync","readFileSync","findLastAgentMessageIndex","path","hasNewUserMessages","parts","z","z","z","z","z","z","z","z","z","result","join","path","join","f","testStatuses","newTitle","z","z","z","SP_DESCRIPTION","z","z","readFile","isAbsolute","join","readFile","isAbsolute","join","z","buildCreateSuggestionTool","z","errText","z","execFile","promisify","z","RISK_LEVELS","z","promisify","execFile","tool","logger","isAuthError","result","logger","IMAGE_ERROR_PATTERN","RETRY_DELAYS_MS","createHash","existsSync","path","readFileSync","f","isAuthError","logger","existsSync","utc","spawn","logger","existsSync","readFile","execFile","path","execFile","execFile","promisify","execFileAsync","promisify","execFile","asRecord","tool","join","join"]}
|