@rallycry/conveyor-agent 10.4.4 → 10.5.0

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/setup/bootstrap.ts","../src/connection/agent-connection.ts","../src/setup/bootstrap-poll.ts","../src/utils/logger.ts","../src/runner/git-utils.ts","../src/setup/git-ready.ts","../src/runner/work-preservation/index.ts","../src/runner/work-preservation/restore-precedence.ts","../src/runner/work-preservation/snapshot-tar.ts","../src/runner/work-preservation/snapshot-artifact.ts","../src/runner/work-preservation/snapshot-transfer.ts","../../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/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/chat-record-mapper.ts","../src/harness/pty/settings.ts","../src/harness/pty/output-coalescer.ts","../src/harness/pty/tool-server.ts","../src/harness/pty/mcp-server.ts","../src/harness/pty/spawn-args.ts","../src/harness/pty/credentials.ts","../src/harness/pty/pty-support.ts","../src/harness/pty/adapters/claude.ts","../src/harness/pty/index.ts","../src/harness/index.ts","../src/execution/query-executor.ts","../src/execution/pack-runner-prompt.ts","../src/execution/prompt-formatters.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","../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/code-review-tools.ts","../src/tools/index.ts","../src/harness/pty/adapters/types.ts","../src/execution/playwright-mcp.ts","../src/execution/event-handlers.ts","../src/execution/event-processor.ts","../src/execution/task-property-utils.ts","../src/execution/tool-access.ts","../src/execution/redactor.ts","../src/execution/exploration-tracker.ts","../src/runner/query-bridge.ts","../src/runner/session-runner-helpers.ts","../src/usage/parse-usage.ts","../src/usage/run-probe.ts","../src/execution/usage-sampler.ts","../src/runner/port-discovery.ts","../src/runner/parent-pull-handler.ts","../src/runner/heavy-gate.ts","../src/runner/session-runner.ts","../src/setup/config.ts","../src/setup/commands.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 */\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\nasync function sleep(ms: number): Promise<void> {\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\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 SocketResponse,\n WorkspaceDiscoveredPort,\n} from \"@project/shared\";\nimport { fetchBootstrap, applyBootstrapToEnv } from \"../setup/bootstrap.js\";\nimport { pollUntilBound, PollUntilBoundHttpError } from \"../setup/bootstrap-poll.js\";\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 (SEC-9).\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// ── Connection class ───────────────────────────────────────────────────────\n\nconst EVENT_BATCH_MS = 500;\nconst MAX_EVENT_BUFFER = 5000;\n\n// Task JWTs are minted with a 24h TTL (api: createTaskToken → createJWT(…, \"24h\")).\n// Proactively re-mint from the bootstrap endpoint well inside that window so a\n// long-running or restart-heavy task never reaches the API with an expired\n// token (which surfaces to the agent as \"Session not found\" on its next RPC).\n// 6h — comfortably inside the 24h TTL, with room for a few retries before expiry.\nconst TOKEN_REFRESH_INTERVAL_MS = 6 * 60 * 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 finalizeSnapshotCallback: (() => 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\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 if (socket.connected) return Promise.resolve();\n return new Promise((resolve, reject) => {\n const cleanup = (): void => {\n clearTimeout(timer);\n socket.off(\"connect\", onConnect);\n };\n const onConnect = (): void => {\n cleanup();\n resolve();\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(\n 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 }, timeoutMs);\n socket.once(\"connect\", onConnect);\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 new Promise((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n reject(\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 );\n }, AgentConnection.CALL_ACK_TIMEOUT_MS);\n socket.emit(\n `agentSessionService:${String(method)}`,\n payload,\n (response: SocketResponse<AgentSessionServiceMethods[M][\"response\"]>) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (response.success && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? `Service call failed: ${String(method)}`));\n }\n },\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(this.config.apiUrl, {\n auth: {\n taskToken: this.config.taskToken,\n runnerMode: this.config.runnerMode ?? \"task\",\n },\n transports: [\"websocket\"],\n reconnection: true,\n reconnectionAttempts: Infinity,\n reconnectionDelay: 2000,\n reconnectionDelayMax: 30000,\n randomizationFactor: 0.3,\n extraHeaders: { \"ngrok-skip-browser-warning\": \"true\" },\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 // The reconciler signals an imminent sleep so the agent captures its\n // finalize snapshot (pg_dump + working tree) NOW — the sleep confirms on\n // this eager capture instead of waiting for the ~2min periodic flush. No\n // early-buffer: if no capture callback is registered yet the pod isn't\n // ready to snapshot, and the shutdown/periodic path is the fallback.\n this.socket.on(\"session:finalizeSnapshot\", () => {\n this.finalizeSnapshotCallback?.();\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\". The token may be stale — try refreshing\n // before Socket.IO's transport-level reconnect kicks in.\n if (reason === \"io server disconnect\" || reason === \"server namespace disconnect\") {\n void this.refreshTaskTokenFromBootstrap()\n .then((refreshed) => {\n if (refreshed && this.socket) {\n // socket.io's `io server disconnect` does NOT auto-reconnect\n // — we have to nudge it manually after refreshing the token.\n this.socket.connect();\n }\n })\n .catch(() => {});\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\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 // Capped exponential backoff: 2s, 4s, 8s, 16s, 32s, then 60s steady.\n const delayMs = Math.min(\n AgentConnection.RECONNECT_BASE_DELAY_MS * 2 ** Math.min(attempt - 1, 5),\n AgentConnection.RECONNECT_MAX_DELAY_MS,\n );\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 new Promise<void>((resolve) => {\n setTimeout(resolve, delayMs);\n });\n }\n }\n } finally {\n this.isReconnecting = false;\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 SEC-9 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 onFinalizeSnapshot(callback: () => void): void {\n this.finalizeSnapshotCallback = callback;\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 /** 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): 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 }).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): 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 });\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 sendHeartbeat(loopLagMs?: number): void {\n if (!this.socket) return;\n const statusMap: Record<string, \"active\" | \"idle\" | \"building\"> = {\n running: \"active\",\n fetching_context: \"active\",\n connected: \"active\",\n connecting: \"active\",\n idle: \"idle\",\n };\n const heartbeatStatus = statusMap[this.lastEmittedStatus ?? \"idle\"] ?? \"active\";\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) => {\n process.stderr.write(`[conveyor-agent] heartbeat worker error: ${err.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 // ── 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 emitCodeReviewResult(content: string, approved: boolean): void {\n if (!this.socket) return;\n void this.call(\"submitCodeReviewResult\", {\n sessionId: this.config.sessionId,\n content,\n approved,\n }).catch(() => {});\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 }> {\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 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 || process.env.CLAUDESPACE_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 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) process.env.CONVEYOR_GITHUB_TOKEN = bundle.githubToken;\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 // Cap the buffer so a long disconnect can't accumulate an unbounded\n // replay storm. Drop oldest on overflow (keeps the most recent state).\n if (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 this.eventBuffer.push({ event });\n if (!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 events = this.eventBuffer.map((entry) => entry.event);\n this.eventBuffer = [];\n // Await so callers (emitStatus) can guarantee ordering\n await this.call(\"emitAgentEvent\", { sessionId: this.config.sessionId, events }).catch(() => {});\n }\n}\n","import type { BootstrapBundle } from \"./bootstrap-bundle-types.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\nasync function sleep(ms: number): Promise<void> {\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\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","/** 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\";\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\nconst 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. */\nasync function git(cwd: string, args: string[], timeoutMs = GIT_TIMEOUT_MS): Promise<string> {\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/** Fetch and merge the latest base branch to prevent stale-base merge conflicts.\n * Returns true on success or no-op (empty baseBranch), false on failure. */\nexport async function syncWithBaseBranch(cwd: string, baseBranch: string): Promise<boolean> {\n if (!baseBranch) return true;\n\n try {\n await git(cwd, [\"fetch\", \"origin\", baseBranch]);\n } catch {\n process.stderr.write(\n `[conveyor-agent] Warning: git fetch origin ${baseBranch} failed, continuing with current base\\n`,\n );\n return false;\n }\n\n try {\n await git(cwd, [\"merge\", `origin/${baseBranch}`, \"--no-edit\"], 30_000);\n } catch {\n process.stderr.write(\n `[conveyor-agent] Warning: merge origin/${baseBranch} failed, aborting merge and continuing\\n`,\n );\n try {\n await git(cwd, [\"merge\", \"--abort\"], 30_000);\n } catch {\n // merge --abort can fail if there's nothing to abort\n }\n return false;\n }\n\n process.stderr.write(`[conveyor-agent] Synced with latest origin/${baseBranch}\\n`);\n return true;\n}\n\n/** Ensure the repo is on the expected task branch. No-op if already correct.\n * Returns true on success, false on failure. */\nexport async function ensureOnTaskBranch(cwd: string, taskBranch: string): Promise<boolean> {\n if (!taskBranch) return true;\n\n const current = await getCurrentBranch(cwd);\n if (current === taskBranch) return true;\n\n try {\n await git(cwd, [\"fetch\", \"origin\", taskBranch]);\n } catch {\n process.stderr.write(`[conveyor-agent] Warning: git fetch origin ${taskBranch} failed\\n`);\n return false;\n }\n\n // Use `checkout -B` which creates or resets the local branch to track origin.\n // This handles the detached-HEAD case (entrypoint.sh leaves the repo detached\n // after `git reset --hard origin/<branch>`) and the case where a stale local\n // branch exists pointing at a different SHA.\n try {\n await git(cwd, [\"checkout\", \"-B\", taskBranch, `origin/${taskBranch}`], 30_000);\n } catch {\n process.stderr.write(`[conveyor-agent] Warning: git checkout ${taskBranch} failed\\n`);\n return false;\n }\n\n process.stderr.write(`[conveyor-agent] Checked out task branch ${taskBranch}\\n`);\n return true;\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\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 {\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 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}\n\n/** Update the git remote URL with a fresh token. */\nexport async function updateRemoteToken(cwd: string, token: string): Promise<void> {\n try {\n const url = await git(cwd, [\"remote\", \"get-url\", \"origin\"]);\n const match = url.match(/github\\.com[/:]([^/]+\\/[^/.]+)/);\n if (match) {\n const repo = match[1].replace(/\\.git$/, \"\");\n await git(cwd, [\n \"remote\",\n \"set-url\",\n \"origin\",\n `https://x-access-token:${token}@github.com/${repo}.git`,\n ]);\n }\n } catch {\n // silently fail — push retry will surface the real error\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 that have (or may have) a live remote WIP ref to clean up. */\nconst wipRefPushed = 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 is unchanged.\n */\nasync function createWipSnapshot(cwd: string, message: string): Promise<string | null> {\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 await git(cwd, [\"reset\", \"-q\"], GIT_SLOW_TIMEOUT_MS);\n } catch {\n /* nothing staged */\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 {\n // Ref doesn't exist remotely (or fetch failed) — nothing to restore.\n return \"none\";\n }\n // A remote ref exists — remember to clean it up once the tree is clean.\n wipRefPushed.add(cwd);\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 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 return \"stale\";\n }\n }\n await git(cwd, [\"stash\", \"apply\", sha], GIT_SLOW_TIMEOUT_MS);\n return \"applied\";\n } catch {\n return \"failed\";\n }\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) {\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 if (!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","import { access, stat } from \"node:fs/promises\";\n\n/**\n * Result of awaiting the entrypoint's background git preparation.\n *\n * - `\"ready\"` — the ready marker appeared; the task repo is up to date.\n * - `\"failed\"` — the failed marker appeared; git preparation errored (stale\n * image, fetch/checkout/clone failure). The caller must NOT\n * operate on the repo.\n * - `\"timeout\"` — neither marker appeared before the deadline.\n * - `\"not-gated\"` — no marker path is configured (GitHub Codespaces / local),\n * so this environment does not gate on the bash git block.\n */\nexport type GitReadyState = \"ready\" | \"failed\" | \"timeout\" | \"not-gated\";\n\nexport interface AwaitGitReadyOptions {\n /** Path to the ready marker. Defaults to `CONVEYOR_GIT_READY_MARKER` env. */\n markerPath?: string;\n /** Path to the failed marker. Defaults to `CONVEYOR_GIT_FAILED_MARKER` env\n * then `/workspaces/.conveyor-git-failed`. */\n failedPath?: string;\n /** Overall deadline. Defaults to ~10m to match the entrypoint's historical\n * fail-loud provision window. */\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}\n\nconst DEFAULT_FAILED_PATH = \"/workspaces/.conveyor-git-failed\";\nconst DEFAULT_TIMEOUT_MS = 600_000;\nconst DEFAULT_POLL_MS = 200;\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n // A directory would never be our marker file; stat guards against a stale\n // dir of the same name from a prior pod on the baked image.\n const s = await stat(path);\n return s.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Block until the pod entrypoint's backgrounded git preparation writes either\n * the ready or the failed marker.\n *\n * The v3 pod entrypoint launches `conveyor-agent` immediately (so the card\n * lights up) while `prepare_workspace_git` runs in the background. It exports\n * `CONVEYOR_GIT_READY_MARKER` and writes exactly one of the ready/failed\n * markers on completion. This helper is the agent-side gate: Claude must not\n * spawn on a stale branch, and setup/start scripts need the repo present.\n *\n * When no marker path is configured (GitHub Codespaces / local), returns\n * `\"not-gated\"` immediately so those environments keep their own git-sync\n * fallback (session-runner phase 3.5, guarded by `CONVEYOR_GIT_READY !== \"1\"`).\n *\n * Never throws — always resolves to a `GitReadyState`.\n */\nexport function awaitGitReady(opts: AwaitGitReadyOptions = {}): Promise<GitReadyState> {\n const markerPath = opts.markerPath ?? process.env.CONVEYOR_GIT_READY_MARKER;\n if (!markerPath) {\n return Promise.resolve(\"not-gated\");\n }\n const failedPath =\n opts.failedPath ?? process.env.CONVEYOR_GIT_FAILED_MARKER ?? DEFAULT_FAILED_PATH;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;\n\n opts.onLog?.(`waiting for workspace git (marker=${markerPath})`);\n return pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, opts.onLog);\n}\n\nasync function pollForMarkers(\n markerPath: string,\n failedPath: string,\n timeoutMs: number,\n pollMs: number,\n onLog?: (msg: string) => void,\n): Promise<GitReadyState> {\n const deadline = Date.now() + timeoutMs;\n // Loop: check ready first, then failed, then deadline. Checking ready first\n // means that if the background writer somehow set both (it never should), the\n // benign \"ready\" wins over the destructive \"failed\".\n for (;;) {\n if (await fileExists(markerPath)) {\n onLog?.(\"workspace git ready\");\n return \"ready\";\n }\n if (await fileExists(failedPath)) {\n onLog?.(\"workspace git preparation failed (marker present)\");\n return \"failed\";\n }\n if (Date.now() >= deadline) {\n onLog?.(`workspace git not ready after ${timeoutMs}ms — giving up`);\n return \"timeout\";\n }\n await new Promise((resolve) => {\n setTimeout(resolve, pollMs);\n });\n }\n}\n","import { rm } from \"node:fs/promises\";\nimport type { BootstrapBundle } from \"../../setup/bootstrap-bundle-types.js\";\nimport { flushPendingChanges, restoreWipSnapshot } from \"../git-utils.js\";\nimport { selectRestoreSource } from \"./restore-precedence.js\";\nimport { buildSnapshotTar, extractSnapshotTar, type SnapshotTarResult } from \"./snapshot-tar.js\";\nimport { downloadSnapshotToTemp, putSnapshotToGcs } from \"./snapshot-transfer.js\";\n\nexport { SNAPSHOT_CAPTURED_AT_HEADER } from \"./snapshot-transfer.js\";\n\nexport interface CaptureContext {\n cwd: string;\n branch: string;\n snapshotUploadUrl?: string;\n refreshToken?: () => Promise<string | undefined>;\n wipMessage?: string;\n /** Force the GCS PUT even when the tar is empty (sizeBytes === 0). Used by the\n * sleep FINALIZE path so `snapshotAt` is stamped and the reconciler's\n * teardown confirm lands immediately — an empty workspace is a valid (empty)\n * snapshot; on wake the restore's manifest check falls back to a clean\n * checkout. The periodic path leaves this false so a racing empty capture\n * never clobbers a good snapshot. */\n forceUpload?: boolean;\n}\n\nexport interface SnapshotArtifact {\n fileCount: number;\n deletionCount: number;\n sizeBytes: number;\n gcsUploaded: boolean;\n wipPushed: boolean;\n}\n\nexport interface RestoreResult {\n source: \"gcs\" | \"wip\" | \"clean\";\n fileCount?: number;\n}\n\nlet periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n/** The in-flight periodic capture, shared as a PROMISE so finalizeForSleep can\n * await it — a boolean guard only prevented overlap, it could not stop a slow\n * pre-finalize capture from PUTting a stale tar AFTER the finalize PUT. */\nlet inFlightCapture: Promise<SnapshotArtifact> | null = null;\n\n/** Serializes GCS PUTs process-wide: every upload (periodic tick, session\n * runner flush, finalize) waits for the previous one, so two captures can\n * never land on the fixed per-workspace GCS object out of order. */\nlet inFlightGcsUpload: Promise<GcsUploadResult> | null = null;\n\nexport interface GcsUploadResult {\n uploaded: boolean;\n fileCount: number;\n deletionCount: number;\n sizeBytes: number;\n}\n\nconst EMPTY_GCS_RESULT: GcsUploadResult = {\n uploaded: false,\n fileCount: 0,\n deletionCount: 0,\n sizeBytes: 0,\n};\n\nasync function doUploadSnapshotToGcs(\n cwd: string,\n uploadUrl: string | undefined,\n opts?: { forceUpload?: boolean },\n): Promise<GcsUploadResult> {\n let tarResult: SnapshotTarResult;\n try {\n tarResult = await buildSnapshotTar(cwd);\n } catch {\n // Never PUT anything on a failed build — the GCS path is fixed per\n // workspace, so a bogus upload would clobber the last good snapshot.\n return EMPTY_GCS_RESULT;\n }\n\n try {\n // Normally skip the PUT for an empty tar (nothing changed) so a periodic\n // capture never clobbers a good snapshot. The finalize path forces it so\n // `snapshotAt` is stamped and teardown confirms without waiting the cap.\n const uploaded =\n (opts?.forceUpload || tarResult.sizeBytes > 0) && uploadUrl\n ? await putSnapshotToGcs(uploadUrl, tarResult)\n : false;\n return {\n uploaded,\n fileCount: tarResult.fileCount,\n deletionCount: tarResult.deletionCount,\n sizeBytes: tarResult.sizeBytes,\n };\n } finally {\n await tarResult.cleanup();\n }\n}\n\n/**\n * The GCS sink on its own: assemble the snapshot tar (the single capture\n * path) and PUT it to the capability URL. Exposed so a runner whose git-tier\n * flush is driven elsewhere (SessionRunner's periodic flushAllPendingWork)\n * can add the GCS sink to the SAME trigger instead of running a second,\n * racing snapshotter. Calls are serialized: a later capture always PUTs\n * after any earlier in-flight one has settled.\n */\nexport async function uploadSnapshotToGcs(\n cwd: string,\n uploadUrl: string | undefined,\n opts?: { forceUpload?: boolean },\n): Promise<GcsUploadResult> {\n const previous = inFlightGcsUpload;\n const run = (async () => {\n if (previous) await previous.catch(() => {});\n return doUploadSnapshotToGcs(cwd, uploadUrl, opts);\n })();\n inFlightGcsUpload = run;\n try {\n return await run;\n } finally {\n if (inFlightGcsUpload === run) inFlightGcsUpload = null;\n }\n}\n\nexport async function captureSnapshot(ctx: CaptureContext): Promise<SnapshotArtifact> {\n // GCS failure is non-fatal; the wip push below still preserves this\n // generation.\n const gcs = await uploadSnapshotToGcs(ctx.cwd, ctx.snapshotUploadUrl, {\n forceUpload: ctx.forceUpload,\n });\n\n const wipResult = await flushPendingChanges(ctx.cwd, {\n wipMessage: ctx.wipMessage ?? \"WIP: WorkPreservation periodic snapshot\",\n refreshToken: ctx.refreshToken,\n });\n\n return {\n fileCount: gcs.fileCount,\n deletionCount: gcs.deletionCount,\n sizeBytes: gcs.sizeBytes,\n gcsUploaded: gcs.uploaded,\n wipPushed: wipResult.committed || wipResult.pushed,\n };\n}\n\nexport function startPeriodic(intervalMs: number, ctx: CaptureContext): void {\n stop();\n periodicTimer = setInterval(() => {\n if (inFlightCapture) return;\n const run = captureSnapshot(ctx);\n inFlightCapture = run;\n void run\n .catch(() => {})\n .finally(() => {\n if (inFlightCapture === run) inFlightCapture = null;\n });\n }, intervalMs);\n}\n\nexport function stop(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n}\n\nexport async function finalizeForSleep(ctx: CaptureContext): Promise<SnapshotArtifact> {\n stop();\n // Await any in-flight periodic capture BEFORE capturing: both PUT the same\n // fixed GCS object, and a slow pre-finalize upload landing after the\n // finalize upload would leave a stale tar as the \"confirmed\" snapshot.\n if (inFlightCapture) await inFlightCapture.catch(() => {});\n\n // Sidecar state (postgres et al.) is no longer durable across sleep/wake\n // (#2623): the durable PVC hosts ONLY the agent's /workspace, and postgres\n // re-seeds from its baked overlayfs seed on wake. So finalize just captures\n // the workspace — no pg_dump. Only /workspace rides the snapshot.\n return captureSnapshot({\n ...ctx,\n wipMessage: ctx.wipMessage ?? \"WIP: WorkPreservation sleep finalize snapshot\",\n // Always stamp snapshotAt on sleep — even an empty workspace must confirm\n // the finalize so teardown doesn't wait out the reconciler's cap.\n forceUpload: true,\n });\n}\n\n/**\n * Restore precedence at boot: GCS snapshot (tracked+untracked+deletions),\n * else the conveyor-wip ref, else a clean checkout. Accepts the narrow slice\n * of the bundle it reads so v3 pods can call it from env-derived values\n * (CONVEYOR_SNAPSHOT_URL + the task branch) as well as from a full bundle.\n *\n * GCS is only authoritative when the archive's manifest HEAD matches the\n * current clone (checked BEFORE any tree mutation) — a stale or invalid\n * snapshot leaves the tree untouched and falls through to the wip ref, whose\n * own parent-HEAD guard handles staleness.\n */\nexport async function restoreOnBoot(\n bundle: Pick<BootstrapBundle, \"snapshotUrl\"> & {\n gitPlan: Pick<BootstrapBundle[\"gitPlan\"], \"branch\">;\n },\n cwd: string,\n): Promise<RestoreResult> {\n let gcsAvailable = false;\n let gcsFileCount: number | undefined;\n\n if (bundle.snapshotUrl) {\n // Streamed to disk — never hold the whole archive in memory.\n const tmpTar = await downloadSnapshotToTemp(bundle.snapshotUrl);\n if (tmpTar) {\n try {\n const result = await extractSnapshotTar(cwd, tmpTar);\n // Success is EXTRACTION success, not a non-zero deletion count — a\n // valid snapshot with zero files/deletions is still authoritative.\n if (result.status === \"extracted\") {\n gcsAvailable = true;\n gcsFileCount = result.filesExtracted;\n }\n } catch {\n gcsAvailable = false;\n } finally {\n await rm(tmpTar, { force: true }).catch(() => {});\n }\n }\n }\n\n const wipRestoreResult = gcsAvailable\n ? \"none\"\n : await restoreWipSnapshot(cwd, bundle.gitPlan.branch);\n const source = selectRestoreSource({ gcsAvailable, wipRestoreResult });\n return source === \"gcs\" ? { source, fileCount: gcsFileCount } : { source };\n}\n","export type RestoreSource = \"gcs\" | \"wip\" | \"clean\";\n\nexport interface RestoreProbe {\n gcsAvailable: boolean;\n wipRestoreResult: \"applied\" | \"stale\" | \"none\" | \"failed\";\n}\n\nexport function selectRestoreSource(probe: RestoreProbe): RestoreSource {\n if (probe.gcsAvailable) return \"gcs\";\n if (probe.wipRestoreResult === \"applied\") return \"wip\";\n return \"clean\";\n}\n","import { execFile } from \"node:child_process\";\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { mkdtemp, rm, stat, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { promisify } from \"node:util\";\nimport { createGzip } from \"node:zlib\";\nimport * as tar from \"tar\";\nimport { planSnapshotFiles, type GitSurface } from \"./snapshot-artifact.js\";\n\n/**\n * In-archive manifest binding a snapshot to the HEAD it was captured on and\n * carrying the deletion list. Lives ONLY inside the tar (assembled in a temp\n * staging dir) — never written into the workspace tree.\n */\nexport const SNAPSHOT_MANIFEST_NAME = \".conveyor-snapshot-manifest.json\";\n\n/**\n * Legacy in-archive name for the postgres dump that pre-#2623 agents bundled\n * into the snapshot tar. Sidecar state is no longer durable, so we neither\n * write nor restore this anymore — but a snapshot captured by an OLDER agent\n * (still sitting on the fixed per-workspace GCS object until the next finalize)\n * can carry one. Extraction must keep SKIPPING this name so the stale dump can\n * never land in the worktree and ride the wip stash's `git add -A` to GitHub.\n */\nconst LEGACY_PG_DUMP_FILENAME = \".conveyor-pgdump.sql\";\n\nexport interface SnapshotManifest {\n /** `git rev-parse HEAD` at capture time — restore refuses to extract over a\n * different HEAD (a stale delta over a newer clone clobbers newer work). */\n head: string;\n /** Repo-relative paths restore must delete after extraction. */\n deletions: string[];\n /** Epoch ms when the tar was BUILT (not uploaded) — also sent as the\n * `x-snapshot-captured-at` header so the API can refuse out-of-order PUTs. */\n capturedAt: number;\n}\n\n// git status --porcelain=v1 -z default maxBuffer (1MB) is too small for large\n// dirty trees; 64MB of NUL-delimited paths covers any realistic worktree.\nconst STATUS_MAX_BUFFER = 64 * 1024 * 1024;\n\n/**\n * Parse `git status --porcelain=v1 -z -uall` output. NUL-delimited and\n * unquoted, so unicode/space/quote filenames arrive verbatim (the LF-based\n * parse broke them via C-style quoting). Rename/copy entries deliver TWO\n * NUL-separated fields — `XY <new>\\0<orig>\\0`; the NEW path is included and,\n * for renames, the ORIGINAL path joins the deletion list (it exists in HEAD\n * but no longer on disk).\n */\nexport function parseStatusPorcelainZ(raw: string): { includes: string[]; deletions: string[] } {\n const includes: string[] = [];\n const deletions: string[] = [];\n const tokens = raw.split(\"\\0\");\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (!token || token.length < 4) continue;\n const x = token[0];\n const y = token[1];\n const filePath = token.slice(3);\n if (x === \"R\" || x === \"C\") {\n const origPath = tokens[++i];\n if (x === \"R\" && origPath) deletions.push(origPath);\n }\n // Ignored entries (only present with --ignored) never enter the plan.\n if (x === \"!\") continue;\n // The file is absent from the worktree when the worktree (Y) column is D\n // (covers ` D`, `AD`, `MD`, `RD`, `DD`), or on a staged-only deletion\n // (`D ` — deleted from index, gone from disk, worktree column blank).\n const missingFromWorktree = y === \"D\" || (x === \"D\" && y === \" \");\n if (missingFromWorktree) deletions.push(filePath);\n else includes.push(filePath);\n }\n return { includes, deletions };\n}\n\n// Async git (execFile, no shell): a synchronous status/rev-parse here would\n// freeze the agent's event loop for the duration — on an IO-starved pod (the\n// exact moment snapshots run) that starves the socket heartbeat and gets the\n// session restarted. See runner/git-utils.ts for the full rationale.\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT_MS = 120_000;\n\n/** Single `git status --porcelain=v1 -z -uall` read feeding both GitSurface\n * views — includes and deletions must come from one consistent status read.\n * Loaded up-front (async); the returned surface serves it synchronously. */\nasync function realGitSurface(cwd: string): Promise<GitSurface> {\n const { stdout } = await execFileAsync(\"git\", [\"status\", \"--porcelain=v1\", \"-z\", \"-uall\"], {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n maxBuffer: STATUS_MAX_BUFFER,\n });\n const cached = parseStatusPorcelainZ(stdout.toString());\n return {\n trackedAndUntracked: () => cached.includes,\n deletedSinceHead: () => cached.deletions,\n };\n}\n\nasync function gitHead(cwd: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"HEAD\"], {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n });\n return stdout.toString().trim() || null;\n } catch {\n return null;\n }\n}\n\nexport interface SnapshotTarResult {\n /** Gzipped tar on disk inside a private temp staging dir. Callers stream it\n * (never buffer the whole archive) and MUST call cleanup() when done. */\n tarPath: string;\n sizeBytes: number;\n fileCount: number;\n deletionCount: number;\n /** Epoch ms the tar was built — the capture generation marker. */\n capturedAt: number;\n cleanup(): Promise<void>;\n}\n\n/**\n * Assemble the snapshot archive: the manifest staged in a temp dir, worktree\n * files appended from the repo. The archive is written to disk and returned as\n * a path so upload can stream it — the tar is never held in memory (pods have\n * an OOM history; a single whole-tar Buffer was up to 500MB).\n */\nexport async function buildSnapshotTar(cwd: string): Promise<SnapshotTarResult> {\n const staging = await mkdtemp(path.join(tmpdir(), \"conveyor-snapshot-\"));\n const cleanup = async (): Promise<void> => {\n await rm(staging, { recursive: true, force: true }).catch(() => {});\n };\n\n try {\n const plan = planSnapshotFiles(await realGitSurface(cwd));\n const head = await gitHead(cwd);\n if (!head) throw new Error(\"cannot snapshot a repo without a resolvable HEAD\");\n const capturedAt = Date.now();\n\n const manifest: SnapshotManifest = {\n head,\n deletions: plan.deletions,\n capturedAt,\n };\n await writeFile(path.join(staging, SNAPSHOT_MANIFEST_NAME), JSON.stringify(manifest), \"utf8\");\n\n const stagedEntries = [SNAPSHOT_MANIFEST_NAME];\n\n // tar.replace can't operate on a compressed archive, so: create the\n // uncompressed tar from the staging entries, append the repo files with\n // cwd = the repo, then gzip file-to-file (all streaming).\n const rawTarPath = path.join(staging, \"snapshot.tar\");\n await tar.create({ cwd: staging, file: rawTarPath, portable: true }, stagedEntries);\n if (plan.include.length > 0) {\n await tar.replace({ file: rawTarPath, cwd, portable: true }, plan.include);\n }\n\n const tarPath = path.join(staging, \"snapshot.tar.gz\");\n await pipeline(createReadStream(rawTarPath), createGzip(), createWriteStream(tarPath));\n await rm(rawTarPath, { force: true });\n\n const { size } = await stat(tarPath);\n return {\n tarPath,\n sizeBytes: size,\n fileCount: plan.include.length,\n deletionCount: plan.deletions.length,\n capturedAt,\n cleanup,\n };\n } catch (err) {\n await cleanup();\n throw err;\n }\n}\n\nexport type SnapshotExtractResult =\n | {\n status: \"extracted\";\n filesExtracted: number;\n deletionsApplied: number;\n }\n /** Manifest HEAD differs from the current clone's HEAD — extracting would\n * smear an old delta over newer commits. The tree is NOT touched. */\n | { status: \"stale-head\"; snapshotHead: string; currentHead: string | null }\n /** Missing/unreadable manifest — not a trustworthy snapshot. Tree untouched. */\n | { status: \"invalid\" };\n\n/** Repo-relative deletion entries must resolve inside the workspace — a\n * malicious/corrupt manifest must never delete outside cwd. */\nfunction isWithinWorkspace(cwd: string, rel: string): boolean {\n if (!rel || path.isAbsolute(rel)) return false;\n const root = path.resolve(cwd);\n const abs = path.resolve(root, rel);\n return abs !== root && abs.startsWith(root + path.sep);\n}\n\n/**\n * Single `tar.list` pass over the archive to parse the manifest. Returns the\n * validated manifest, or null when it is missing/unreadable/lacks a HEAD.\n */\nasync function readSnapshotArchive(tarPath: string): Promise<SnapshotManifest | null> {\n let manifestRaw: Buffer | null = null;\n\n try {\n await tar.list({\n file: tarPath,\n onReadEntry: (entry) => {\n if (entry.path === SNAPSHOT_MANIFEST_NAME) {\n const chunks: Buffer[] = [];\n entry.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n entry.on(\"end\", () => {\n manifestRaw = Buffer.concat(chunks);\n });\n }\n },\n });\n } catch {\n return null;\n }\n\n if (!manifestRaw) return null;\n try {\n const parsed = JSON.parse((manifestRaw as Buffer).toString(\"utf8\")) as SnapshotManifest;\n if (typeof parsed.head !== \"string\" || !parsed.head) return null;\n return {\n head: parsed.head,\n deletions: Array.isArray(parsed.deletions) ? parsed.deletions : [],\n capturedAt: typeof parsed.capturedAt === \"number\" ? parsed.capturedAt : 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Extract a snapshot archive (path to a .tar.gz on disk) into the workspace.\n * Order matters: the manifest is read and the HEAD binding checked BEFORE any\n * tree mutation — a stale or invalid snapshot leaves the tree byte-identical.\n * A valid snapshot with zero files/deletions is still a SUCCESS (a clean tree\n * at capture time is a legitimate snapshot, not a failure).\n */\nexport async function extractSnapshotTar(\n cwd: string,\n tarPath: string,\n): Promise<SnapshotExtractResult> {\n const manifest = await readSnapshotArchive(tarPath);\n if (!manifest) return { status: \"invalid\" };\n\n const currentHead = await gitHead(cwd);\n if (manifest.head !== currentHead) {\n return { status: \"stale-head\", snapshotHead: manifest.head, currentHead };\n }\n\n let filesExtracted = 0;\n await tar.extract({\n file: tarPath,\n cwd,\n filter: (entryPath) => {\n // Manifest is archive metadata and never lands in cwd. A legacy pg dump\n // (bundled by pre-#2623 agents) is likewise skipped — sidecar state is no\n // longer restored, and a dump in the worktree would ride the next wip\n // stash's `git add -A` to GitHub.\n if (entryPath === SNAPSHOT_MANIFEST_NAME || entryPath === LEGACY_PG_DUMP_FILENAME) {\n return false;\n }\n filesExtracted++;\n return true;\n },\n });\n\n let deletionsApplied = 0;\n for (const rel of manifest.deletions) {\n if (typeof rel !== \"string\" || !isWithinWorkspace(cwd, rel)) continue;\n await rm(path.resolve(cwd, rel), { recursive: true, force: true });\n deletionsApplied++;\n }\n\n return { status: \"extracted\", filesExtracted, deletionsApplied };\n}\n\n/** Test seam: read a manifest back out of an archive without extracting. */\nexport function readSnapshotManifest(tarPath: string): Promise<SnapshotManifest | null> {\n return readSnapshotArchive(tarPath);\n}\n\n/** Test seam: list entry paths in an archive without extracting. */\nexport async function listSnapshotEntries(tarPath: string): Promise<string[]> {\n const entries: string[] = [];\n await tar.list({\n file: tarPath,\n onReadEntry: (entry) => {\n entries.push(String(entry.path));\n },\n });\n return entries;\n}\n","/**\n * Pure planning logic for the WorkPreservation source-tree snapshot:\n * tracked + untracked files are included in the archive, while deleted paths\n * are recorded separately for restore-time removal.\n */\n\nexport interface GitSurface {\n trackedAndUntracked(): string[];\n deletedSinceHead(): string[];\n}\n\nexport interface SnapshotFilePlan {\n include: string[];\n deletions: string[];\n}\n\nexport function planSnapshotFiles(git: GitSurface): SnapshotFilePlan {\n const include = git.trackedAndUntracked();\n const includeSet = new Set(include);\n const deletions = [...new Set(git.deletedSinceHead())].filter((path) => !includeSet.has(path));\n return { include, deletions };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport type { SnapshotTarResult } from \"./snapshot-tar.js\";\n\n// A hung upload/download must not stall capture forever (which would leave\n// the in-flight promise stuck and silently stop all periodic snapshots).\nexport const SNAPSHOT_HTTP_TIMEOUT_MS = 60_000;\n\n/** Header carrying the tar's BUILD time so the API can refuse to overwrite a\n * newer capture with a slower, older PUT (see snapshot-routes.ts). */\nexport const SNAPSHOT_CAPTURED_AT_HEADER = \"x-snapshot-captured-at\";\n\nexport async function putSnapshotToGcs(\n url: string,\n tarResult: SnapshotTarResult,\n): Promise<boolean> {\n try {\n // Stream the tar file straight into the request body — the archive is\n // never buffered whole in memory (pods have an OOM history; tars can hit\n // the 500MB route cap). `duplex: \"half\"` is required by undici for stream\n // bodies and ignored by runtimes that don't need it.\n const body = Readable.toWeb(createReadStream(tarResult.tarPath)) as ReadableStream;\n const res = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/gzip\",\n \"Content-Length\": String(tarResult.sizeBytes),\n [SNAPSHOT_CAPTURED_AT_HEADER]: String(tarResult.capturedAt),\n },\n body,\n duplex: \"half\",\n signal: AbortSignal.timeout(SNAPSHOT_HTTP_TIMEOUT_MS),\n } as RequestInit);\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Download a snapshot archive to a temp file, streaming (never buffering the\n * whole tar). Returns the temp path on success, null on any failure — the\n * caller owns removing the file.\n */\nexport async function downloadSnapshotToTemp(url: string): Promise<string | null> {\n const tmpTar = path.join(tmpdir(), `conveyor-snapshot-restore-${randomUUID()}.tar.gz`);\n try {\n const res = await fetch(url, {\n method: \"GET\",\n signal: AbortSignal.timeout(SNAPSHOT_HTTP_TIMEOUT_MS),\n });\n if (!res.ok || !res.body) return null;\n await pipeline(\n Readable.fromWeb(res.body as import(\"node:stream/web\").ReadableStream),\n createWriteStream(tmpTar),\n );\n return tmpTar;\n } catch {\n await rm(tmpTar, { force: true }).catch(() => {});\n return null;\n }\n}\n","// src/types/common.ts\nfunction isCuid(str) {\n return /^c[a-z0-9]{24}$/.test(str);\n}\n\n// src/constants/models.ts\nvar DEFAULT_SONNET_MODEL = \"claude-sonnet-5\";\nvar DEFAULT_OPUS_MODEL = \"claude-opus-4-8\";\nvar DEFAULT_HAIKU_MODEL = \"claude-haiku-4-5-20251001\";\nvar FABLE_MODEL = \"claude-fable-5\";\nvar PREVIOUS_SONNET_MODEL = \"claude-sonnet-4-6\";\nvar RETIRED_SONNET_MODEL = \"claude-sonnet-4-20250514\";\n\n// src/types/project-settings-types.ts\nvar PREVIEW_PORT_DENY_LIST = [5432, 6379, 9200];\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}\nvar PROJECT_FUNCTION_DEFAULTS = {\n identification: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"low\",\n thinking: { type: \"adaptive\" }\n },\n suggestionHandler: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"high\",\n thinking: { type: \"adaptive\" }\n },\n prReview: {\n model: DEFAULT_SONNET_MODEL,\n effort: \"low\",\n thinking: { type: \"adaptive\" }\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 const s = settings ?? {};\n if (s.codeReviewMode) return s.codeReviewMode;\n if (s.codeReviewEnabled === true) return \"blocking\";\n return \"off\";\n}\nfunction resolveGcpEnvResources(settings) {\n const s = settings ?? {};\n if (s.gcpEnvResources) return s.gcpEnvResources;\n if (s.gcpCloudRunServices?.length || s.gcpCloudSqlInstances?.length) {\n return {\n prod: {\n cloudRunServices: s.gcpCloudRunServices,\n cloudSqlInstances: s.gcpCloudSqlInstances\n }\n };\n }\n return {};\n}\n\n// src/types/gcp-types.ts\nvar GCP_ENVS = [\"prod\", \"dev\", \"claudespace\"];\n\n// src/types/coding-agent.ts\nvar TUI_KINDS = [\"claude-code\", \"opencode\"];\nvar AGENT_PROVIDERS = [\"anthropic\", \"openai\"];\nvar AGENT_KEY_KINDS = [\"oauth_token\", \"api_key\", \"chatgpt_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/task-types.ts\nvar CARD_TYPE_VALUES = [\"task\", \"incident\", \"suggestion\", \"ephemeral\"];\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 // Ephemeral cards (e.g. automated code review) are created past Planning and\n // only ever live in InProgress → Complete/Cancelled, but reuse the unified set\n // so status validation never rejects a shared transition.\n ephemeral: UNIFIED_STATUSES\n};\nfunction validateStatusForType(type, status) {\n return CARD_TYPE_STATUSES[type].includes(status);\n}\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 \"application/pdf\"\n];\nvar MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024;\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 \"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-session-requests.ts\nimport { z } from \"zod\";\nvar AgentHeartbeatSchema = z.object({\n sessionId: z.string().optional(),\n timestamp: z.string(),\n status: z.enum([\"active\", \"idle\", \"building\"]),\n currentAction: z.string().optional(),\n /** Sender-observed main event-loop lag (ms) — see AgentHeartbeat.loopLagMs. */\n loopLagMs: z.number().nonnegative().optional()\n});\nvar CreatePRInputSchema = z.object({\n title: z.string().min(1),\n body: z.string(),\n head: z.string().optional(),\n base: z.string().optional()\n});\nvar PostToChatInputSchema = z.object({\n message: z.string().min(1),\n type: z.enum([\"message\", \"question\", \"update\"]).optional().default(\"message\")\n});\nvar GetTaskContextRequestSchema = z.object({\n sessionId: z.string(),\n includeHistory: z.boolean().optional().default(false)\n});\nvar GetChatMessagesRequestSchema = z.object({\n sessionId: z.string(),\n limit: z.number().int().positive().optional().default(50),\n offset: z.number().int().nonnegative().optional().default(0)\n});\nvar GetTaskFilesRequestSchema = z.object({\n sessionId: z.string()\n});\nvar GetTaskFileRequestSchema = z.object({\n sessionId: z.string(),\n fileId: z.string()\n});\nvar GetTaskRequestSchema = z.object({\n sessionId: z.string(),\n taskSlugOrId: z.string()\n});\nvar GetCliHistoryRequestSchema = z.object({\n sessionId: z.string(),\n limit: z.number().int().positive().optional().default(100),\n source: z.enum([\"agent\", \"application\"]).optional()\n});\nvar ListSubtasksRequestSchema = z.object({\n sessionId: z.string()\n});\nvar GetDependenciesRequestSchema = z.object({\n sessionId: z.string()\n});\nvar GetSuggestionsRequestSchema = z.object({\n sessionId: z.string(),\n status: z.string().optional(),\n limit: z.number().int().min(1).max(100).optional()\n});\nvar ListManualTestsRequestSchema = z.object({\n sessionId: z.string()\n});\nvar QueryManualTestsRequestSchema = z.object({\n sessionId: z.string(),\n cardStatuses: z.array(z.string()).optional(),\n testStatuses: z.array(z.enum([\"open\", \"approved\", \"rejected\"])).optional()\n});\nvar PostToChatRequestSchema = PostToChatInputSchema;\nvar CreatePullRequestRequestSchema = CreatePRInputSchema.extend({ sessionId: z.string() });\nvar RequestFileUploadRequestSchema = z.object({\n sessionId: z.string(),\n fileName: z.string().min(1).max(255),\n mimeType: z.string().min(1).max(128),\n fileSize: z.number().int().positive().max(MAX_FILE_SIZE_BYTES)\n});\nvar ConfirmFileUploadRequestSchema = z.object({\n sessionId: z.string(),\n fileId: z.string(),\n title: z.string().max(500).optional()\n});\nvar UpdateTaskStatusRequestSchema = z.object({\n sessionId: z.string(),\n status: z.string(),\n force: z.boolean().optional().default(false)\n});\nvar StoreSessionIdRequestSchema = z.object({\n sessionId: z.string(),\n sdkSessionId: z.string()\n});\nvar SetManualTestsRequestSchema = z.object({\n sessionId: z.string(),\n items: z.array(z.object({ title: z.string().min(1) })).min(1)\n});\nvar EditManualTestRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1),\n newTitle: z.string().min(1)\n});\nvar RemoveManualTestRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1)\n});\nvar ApproveManualTestRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1)\n});\nvar RejectManualTestRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1),\n reason: z.string().min(1).max(2e3)\n});\nvar TrackSpendingRequestSchema = z.object({\n sessionId: z.string(),\n inputTokens: z.number().int().nonnegative(),\n outputTokens: z.number().int().nonnegative(),\n costUsd: z.number().nonnegative(),\n model: z.string()\n});\nvar HeartbeatRequestSchema = AgentHeartbeatSchema;\nvar SessionStartRequestSchema = z.object({\n sessionId: z.string(),\n agentVersion: z.string(),\n capabilities: z.array(z.string())\n});\nvar SessionStopRequestSchema = z.object({\n sessionId: z.string(),\n reason: z.string().optional()\n});\nvar EndReviewSessionRequestSchema = z.object({\n sessionId: z.string(),\n reason: z.enum([\"approved\", \"changes_requested\", \"finished\"]).optional()\n});\nvar ConnectAgentRequestSchema = z.object({\n sessionId: z.string()\n});\nvar ReportAgentStatusRequestSchema = z.object({\n sessionId: z.string(),\n status: z.string(),\n /** Why the agent reports this status (e.g. \"user_question\" while an AskUserQuestion questionnaire is pending in the TUI). */\n reason: z.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: z.string().optional()\n});\nvar NotifyAgentVersionRequestSchema = z.object({\n sessionId: z.string(),\n agentVersion: z.string()\n});\nvar DiscoveredPortSchema = z.object({\n port: z.number().int().min(1).max(65535),\n label: z.string().min(1).max(64).optional(),\n protocol: z.enum([\"http\", \"tcp\"]).optional(),\n detectedAt: z.string()\n});\nvar ReportDiscoveredPortsRequestSchema = z.object({\n sessionId: z.string(),\n ports: z.array(DiscoveredPortSchema).max(64)\n});\nvar CreateSubtaskRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1),\n description: z.string().optional(),\n plan: z.string().optional(),\n storyPointValue: z.number().int().positive().optional(),\n ordinal: z.number().int().nonnegative().optional(),\n followParentStatus: z.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: z.array(z.string().min(1)).max(32).optional()\n});\nvar UpdateSubtaskRequestSchema = z.object({\n sessionId: z.string(),\n subtaskId: z.string(),\n title: z.string().min(1).optional(),\n description: z.string().optional(),\n plan: z.string().optional(),\n status: z.string().optional(),\n storyPointValue: z.number().int().positive().optional(),\n followParentStatus: z.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: z.array(z.string().min(1)).max(32).optional()\n});\nvar DeleteSubtaskRequestSchema = z.object({\n sessionId: z.string(),\n subtaskId: z.string()\n});\nvar GetTaskPropertiesRequestSchema = z.object({\n sessionId: z.string()\n});\nvar GetCumulativeSpendingRequestSchema = z.object({\n sessionId: z.string()\n});\nvar ModelUsageEntrySchema = z.object({\n model: z.string(),\n inputTokens: z.number().nonnegative(),\n outputTokens: z.number().nonnegative(),\n cacheReadInputTokens: z.number().nonnegative(),\n cacheCreationInputTokens: z.number().nonnegative(),\n costUSD: z.number().nonnegative()\n});\nvar GetCumulativeSpendingResponseSchema = z.object({\n totalCostUsd: z.number().nonnegative(),\n modelUsage: z.array(ModelUsageEntrySchema)\n});\nvar UpdateTaskFieldsRequestSchema = z.object({\n sessionId: z.string(),\n plan: z.string().optional(),\n description: z.string().optional()\n});\nvar UpdateTaskPropertiesRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().optional(),\n storyPointValue: z.number().int().positive().optional(),\n tagIds: z.array(z.string()).optional(),\n tagNames: z.array(z.string()).optional(),\n githubPRUrl: z.string().url().optional(),\n githubBranch: z.string().optional()\n});\nvar ListIconsRequestSchema = z.object({\n sessionId: z.string()\n});\nvar GenerateTaskIconRequestSchema = z.object({\n sessionId: z.string(),\n prompt: z.string().min(1),\n aspectRatio: z.string().optional()\n});\nvar SearchFaIconsRequestSchema = z.object({\n sessionId: z.string(),\n query: z.string().min(1),\n first: z.number().int().positive().optional()\n});\nvar PickFaIconRequestSchema = z.object({\n sessionId: z.string(),\n fontAwesomeId: z.string().min(1),\n fontAwesomeStyle: z.string().optional()\n});\nvar CreateFollowUpTaskRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1),\n description: z.string().optional(),\n plan: z.string().optional(),\n storyPointValue: z.number().int().positive().optional()\n});\nvar AddDependencyRequestSchema = z.object({\n sessionId: z.string(),\n dependsOnSlugOrId: z.string()\n});\nvar RemoveDependencyRequestSchema = z.object({\n sessionId: z.string(),\n dependsOnSlugOrId: z.string()\n});\nvar CreateSuggestionRequestSchema = z.object({\n sessionId: z.string(),\n title: z.string().min(1),\n description: z.string().optional(),\n tagNames: z.array(z.string()).optional()\n});\nvar VoteSuggestionRequestSchema = z.object({\n sessionId: z.string(),\n suggestionId: z.string(),\n value: z.union([z.literal(1), z.literal(-1)])\n});\nvar TriggerIdentificationRequestSchema = z.object({\n sessionId: z.string()\n});\nvar SubmitCodeReviewResultRequestSchema = z.object({\n sessionId: z.string(),\n approved: z.boolean(),\n content: z.string()\n});\nvar StartChildCloudBuildRequestSchema = z.object({\n sessionId: z.string(),\n childTaskId: z.string()\n});\nvar StopChildBuildRequestSchema = z.object({\n sessionId: z.string(),\n childTaskId: z.string()\n});\nvar ApproveAndMergePRRequestSchema = z.object({\n sessionId: z.string(),\n childTaskId: z.string()\n});\nvar PostChildChatMessageRequestSchema = z.object({\n sessionId: z.string(),\n childTaskId: z.string(),\n message: z.string().min(1)\n});\nvar UpdateChildStatusRequestSchema = z.object({\n sessionId: z.string(),\n childTaskId: z.string(),\n status: z.string()\n});\nvar GetAgentStatusRequestSchema = z.object({\n taskId: z.string()\n});\nvar GetUiCliHistoryRequestSchema = z.object({\n taskId: z.string()\n});\nvar GetActivePtySessionRequestSchema = z.object({\n taskId: z.string()\n});\nvar ListActivePtySessionsRequestSchema = z.object({\n taskId: z.string()\n});\nvar SendSoftStopRequestSchema = z.object({\n taskId: z.string()\n});\nvar StopTaskSessionRequestSchema = z.object({\n taskId: z.string(),\n sessionId: z.string()\n});\nvar FlushTaskQueueRequestSchema = z.object({\n taskId: z.string(),\n softStop: z.boolean().optional()\n});\nvar CancelTaskQueuedMessageRequestSchema = z.object({\n taskId: z.string(),\n messageId: z.string()\n});\nvar FlushSingleQueuedMessageRequestSchema = z.object({\n taskId: z.string(),\n messageId: z.string(),\n softStop: z.boolean().optional()\n});\nvar AnswerAgentQuestionRequestSchema = z.object({\n taskId: z.string(),\n requestId: z.string(),\n answers: z.record(z.string(), z.string())\n});\nvar ClearAgentTodosRequestSchema = z.object({\n taskId: z.string()\n});\nvar AgentQuestionOptionSchema = z.object({\n label: z.string(),\n description: z.string(),\n preview: z.string().optional()\n});\nvar AgentQuestionSchema = z.object({\n question: z.string(),\n header: z.string(),\n options: z.array(AgentQuestionOptionSchema),\n multiSelect: z.boolean().optional()\n});\nvar AskUserQuestionRequestSchema = z.object({\n sessionId: z.string(),\n question: z.string().min(1),\n requestId: z.string().min(1),\n questions: z.array(AgentQuestionSchema).min(1)\n});\nvar AgentEventSchema = z.object({\n type: z.string().min(1)\n}).catchall(z.unknown());\nvar EmitAgentEventRequestSchema = z.object({\n sessionId: z.string(),\n events: z.array(AgentEventSchema).max(500)\n});\nvar RefreshGithubTokenRequestSchema = z.object({\n sessionId: z.string()\n});\nvar ReportReviewSpawnFailureRequestSchema = z.object({\n sessionId: z.string(),\n reviewSessionId: z.string(),\n error: z.string().max(2e3).optional()\n});\nvar RefreshGithubTokenResponseSchema = z.object({\n token: z.string()\n});\nvar PTY_FRAME_MAX_CHARS = 256 * 1024;\nvar PTY_MAX_DIMENSION = 1e3;\nvar PtyOutputRequestSchema = z.object({\n sessionId: z.string(),\n data: z.string().max(PTY_FRAME_MAX_CHARS),\n cols: z.number().int().positive().max(PTY_MAX_DIMENSION).optional(),\n rows: z.number().int().positive().max(PTY_MAX_DIMENSION).optional()\n});\nvar PtyEndedRequestSchema = z.object({\n sessionId: z.string()\n});\nvar PtyInputRequestSchema = z.object({\n sessionId: z.string(),\n data: z.string().max(PTY_FRAME_MAX_CHARS)\n});\nvar PtyResizeRequestSchema = z.object({\n sessionId: z.string(),\n cols: z.number().int().positive().max(PTY_MAX_DIMENSION),\n rows: z.number().int().positive().max(PTY_MAX_DIMENSION)\n});\nvar PtyAttachRequestSchema = z.object({\n sessionId: z.string()\n});\nvar PtyChatEventPayloadSchema = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"init\"),\n model: z.string().max(200),\n claudeSessionId: z.string().max(100).optional()\n }),\n z.object({ kind: z.literal(\"user_text\"), text: z.string().max(16384) }),\n z.object({ kind: z.literal(\"assistant_text\"), text: z.string().max(16384) }),\n z.object({\n kind: z.literal(\"tool_use\"),\n name: z.string().max(200),\n // Compact preview: JSON.stringify(input) truncated agent-side.\n input: z.string().max(2e3)\n }),\n z.object({ kind: z.literal(\"turn_end\") })\n]);\nvar PtyChatEventRequestSchema = z.object({\n sessionId: z.string(),\n event: PtyChatEventPayloadSchema\n});\nvar PtyChatAttachRequestSchema = z.object({\n sessionId: z.string()\n});\nvar CreatePRResponseSchema = z.object({\n prNumber: z.number().int().positive(),\n prUrl: z.string().url()\n});\nvar PostToChatResponseSchema = z.object({\n messageId: z.string()\n});\nvar UpdateTaskStatusResponseSchema = z.object({\n taskId: z.string(),\n status: z.string()\n});\nvar StoreSessionIdResponseSchema = z.object({\n success: z.boolean()\n});\nvar HeartbeatResponseSchema = z.object({\n acknowledged: z.boolean()\n});\nvar SessionStartResponseSchema = z.object({\n sessionId: z.string(),\n startedAt: z.string()\n});\nvar SessionStopResponseSchema = z.object({\n sessionId: z.string(),\n stoppedAt: z.string()\n});\nvar DeleteSubtaskResponseSchema = z.object({\n deleted: z.boolean()\n});\n\n// src/types/agent-session-project-requests.ts\nimport { z as z2 } from \"zod\";\nvar ListAccessibleProjectsRequestSchema = z2.object({\n pageSize: z2.number().int().positive().max(100).optional().default(100)\n});\nvar ListProjectTasksRequestSchema = z2.object({\n projectId: z2.string(),\n status: z2.string().optional(),\n assigneeId: z2.string().optional(),\n unassigned: z2.boolean().optional(),\n limit: z2.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 = z2.object({\n projectId: z2.string(),\n taskId: z2.string()\n});\nvar SearchProjectTasksRequestSchema = z2.object({\n projectId: z2.string(),\n tagNames: z2.array(z2.string()).optional(),\n searchQuery: z2.string().optional(),\n statusFilters: z2.array(z2.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: z2.array(z2.string()).optional(),\n assigneeId: z2.string().optional(),\n unassigned: z2.boolean().optional(),\n limit: z2.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 = z2.object({\n projectId: z2.string()\n});\nvar GetProjectSummaryRequestSchema = z2.object({\n projectId: z2.string()\n});\nvar CreateProjectTaskRequestSchema = z2.object({\n projectId: z2.string(),\n title: z2.string().min(1),\n description: z2.string().optional(),\n plan: z2.string().optional(),\n status: z2.string().optional(),\n requestingUserId: z2.string().optional()\n});\nvar UpdateProjectTaskRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n title: z2.string().optional(),\n description: z2.string().optional(),\n plan: z2.string().optional(),\n status: z2.string().optional(),\n assignedUserId: z2.string().nullish(),\n requestingUserId: z2.string().optional()\n});\nvar PostToProjectTaskChatRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n content: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar GetProjectTaskCliRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n limit: z2.number().int().positive().optional().default(50),\n source: z2.string().optional()\n});\nvar GetProjectTaskSessionsRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string()\n});\nvar QueryProjectGcpLogsRequestSchema = z2.object({\n projectId: z2.string(),\n env: z2.enum([\"prod\", \"dev\", \"claudespace\"]).optional(),\n severity: z2.enum([\"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\", \"CRITICAL\", \"ALERT\", \"EMERGENCY\"]).optional(),\n services: z2.array(z2.string().min(1).max(200)).max(25).optional(),\n sqlInstances: z2.array(z2.string().min(1).max(200)).max(25).optional(),\n allServices: z2.boolean().optional(),\n search: z2.string().max(256).optional(),\n filter: z2.string().max(1e3).optional(),\n startTime: z2.string().optional(),\n endTime: z2.string().optional(),\n limit: z2.number().int().min(1).max(200).optional().default(50),\n pageToken: z2.string().max(4096).optional()\n});\nvar StartProjectBuildRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar StopProjectBuildRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar StartProjectWorkspaceRequestSchema = z2.object({\n projectId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar StopProjectWorkspaceRequestSchema = z2.object({\n projectId: z2.string(),\n destroy: z2.boolean().optional(),\n requestingUserId: z2.string().optional()\n});\nvar ListMyLiveSessionsRequestSchema = z2.object({\n projectId: z2.string(),\n /** Admin-only: list another member's sessions instead of the caller's. */\n targetUserId: z2.string().optional()\n});\nvar GetProjectAvailableTuisRequestSchema = z2.object({\n projectId: z2.string()\n});\nvar StartAdhocSessionRequestSchema = z2.object({\n projectId: z2.string(),\n label: z2.string().max(200).optional(),\n /** Coding-agent key to launch under — validated pick-time (ownership + TUI availability) in the handler. */\n codingAgentKeyId: z2.string().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: z2.enum([\"adhoc\", \"pm\"]).optional(),\n /** Base branch to check out (defaults to the project's dev branch). */\n branch: z2.string().max(300).optional(),\n requestingUserId: z2.string().optional()\n});\nvar StopAdhocSessionRequestSchema = z2.object({\n projectId: z2.string(),\n workspaceId: z2.string(),\n destroy: z2.boolean().optional(),\n requestingUserId: z2.string().optional()\n});\nvar ResumeAdhocSessionRequestSchema = z2.object({\n projectId: z2.string(),\n workspaceId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar CreateProjectReleaseRequestSchema = z2.object({\n projectId: z2.string(),\n taskIds: z2.array(z2.string()).optional(),\n requestingUserId: z2.string().optional()\n});\nvar ApproveProjectMergePRRequestSchema = z2.object({\n projectId: z2.string(),\n childTaskId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar ListProjectSubtasksRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string()\n});\nvar CreateProjectSubtaskRequestSchema = z2.object({\n projectId: z2.string(),\n parentTaskId: z2.string(),\n title: z2.string().min(1),\n description: z2.string().optional(),\n plan: z2.string().optional(),\n ordinal: z2.number().int().nonnegative().optional(),\n storyPointValue: z2.number().int().positive().optional(),\n followParentStatus: z2.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: z2.array(z2.string().min(1)).max(32).optional(),\n requestingUserId: z2.string().optional()\n});\nvar UpdateProjectSubtaskRequestSchema = z2.object({\n projectId: z2.string(),\n subtaskId: z2.string(),\n title: z2.string().optional(),\n description: z2.string().optional(),\n plan: z2.string().optional(),\n status: z2.string().optional(),\n ordinal: z2.number().int().nonnegative().optional(),\n storyPointValue: z2.number().int().positive().optional(),\n followParentStatus: z2.boolean().optional(),\n requestingUserId: z2.string().optional()\n});\nvar DeleteProjectSubtaskRequestSchema = z2.object({\n projectId: z2.string(),\n subtaskId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar GetProjectTaskChatRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n limit: z2.number().int().positive().optional().default(20)\n});\nvar AddProjectTaskDependencyRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n dependsOnSlugOrId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar RemoveProjectTaskDependencyRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n dependsOnSlugOrId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar VoteProjectSuggestionRequestSchema = z2.object({\n projectId: z2.string(),\n suggestionId: z2.string(),\n value: z2.union([z2.literal(1), z2.literal(-1)]),\n requestingUserId: z2.string().optional()\n});\nvar GetProjectTaskDependenciesRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string()\n});\nvar ListProjectTaskFilesRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string()\n});\nvar GetProjectAttachmentRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n fileId: z2.string(),\n /** Byte offset into text content (paging large logs/JSON). Default 0. */\n offset: z2.number().int().nonnegative().optional(),\n /** Max bytes of text content to return from `offset`. Server default applies. */\n maxBytes: z2.number().int().positive().optional()\n});\nvar RequestProjectFileUploadRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n fileName: z2.string().min(1).max(255),\n mimeType: z2.string().min(1).max(128),\n fileSize: z2.number().int().positive().max(MAX_FILE_SIZE_BYTES),\n requestingUserId: z2.string().optional()\n});\nvar ConfirmProjectFileUploadRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n fileId: z2.string(),\n /** When set, the attachment is also posted to the task chat with this text. */\n comment: z2.string().max(2e3).optional(),\n requestingUserId: z2.string().optional()\n});\nvar CreateProjectPullRequestRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n title: z2.string().min(1),\n body: z2.string(),\n head: z2.string().optional(),\n base: z2.string().optional(),\n requestingUserId: z2.string().optional()\n});\nvar ListProjectMembersRequestSchema = z2.object({\n projectId: z2.string()\n});\nvar AddProjectTaskReviewerRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n userId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar RemoveProjectTaskReviewerRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n userId: z2.string(),\n requestingUserId: z2.string().optional()\n});\nvar ListProjectManualTestsRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string()\n});\nvar QueryProjectManualTestsRequestSchema = z2.object({\n projectId: z2.string(),\n cardStatuses: z2.array(z2.string()).optional(),\n testStatuses: z2.array(z2.enum([\"open\", \"approved\", \"rejected\"])).optional()\n});\nvar SetProjectManualTestsRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n items: z2.array(z2.object({ title: z2.string().min(1) })).min(1),\n requestingUserId: z2.string().optional()\n});\nvar EditProjectManualTestRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n title: z2.string().min(1),\n newTitle: z2.string().min(1),\n requestingUserId: z2.string().optional()\n});\nvar RemoveProjectManualTestRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n title: z2.string().min(1),\n requestingUserId: z2.string().optional()\n});\nvar ApproveProjectManualTestRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n title: z2.string().min(1),\n requestingUserId: z2.string().optional()\n});\nvar RejectProjectManualTestRequestSchema = z2.object({\n projectId: z2.string(),\n taskId: z2.string(),\n title: z2.string().min(1),\n reason: z2.string().min(1).max(2e3),\n requestingUserId: z2.string().optional()\n});\nvar CreateProjectSuggestionRequestSchema = z2.object({\n projectId: z2.string(),\n title: z2.string().min(1),\n description: z2.string().optional(),\n tagNames: z2.array(z2.string()).optional(),\n requestingUserId: z2.string().optional()\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 \"Terminating\",\n \"Gone\",\n \"Failed\"\n];\nvar WORKSPACE_SESSION_ROLES = [\"writer\", \"reader\"];\nvar WORKSPACE_SESSION_MODES = [\"build\", \"review\", \"pm\", \"help\", \"adhoc\", \"pack\"];\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/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 an image file (e.g. a Playwright screenshot) as a task attachment AND post it to the task chat in one step \\u2014 no follow-up post_to_chat call needed. Supports png/jpg/gif/webp.\",\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. Takes only a summary \\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. 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: \"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. Use for out-of-scope work or cleanup that should land after this task merges. 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: \"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.\",\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 under the current parent task. Use when breaking a complex parent into smaller pieces during planning. For post-task follow-ups 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: \"review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require 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: \"review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require parent task.\"\n },\n {\n name: \"list_subtasks\",\n description: \"List all subtasks under the current parent task. Use to coordinate child work \\u2014 check who is running, ready for review, or blocked. 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: \"review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require parent task.\"\n },\n {\n name: \"start_child_cloud_build\",\n description: \"Start a cloud build (codespace) for a child task. Preconditions: child is in Open status, has a story point value, and has an agent assigned.\",\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.\",\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). Use when refining a child's plan, reordering, or rewiring dependencies. 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: \"review, auto, discovery, help; building (parent task only). Pack tools (start_child_cloud_build, stop_child_build, approve_and_merge_pr) require parent task.\"\n },\n {\n name: \"update_task_plan\",\n description: \"Save the finalized plan and/or description to the current task. Use in Plan mode after alignment. 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 only. PM/agent modes: review, auto, discovery, help; building (parent task only).\"\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: \"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.\",\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: \"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: \"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>'. 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: \"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, or story points. 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 and merge a child task's pull request. Pass projectId to target a specific project; otherwise the configured default project is used. Only succeeds if all CI/CD checks are passing. The child task must be in ReviewPR status with a PR.\",\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_logs\",\n description: \"Read CLI execution logs from a task. Pass projectId to target a specific project; otherwise the configured default project is used. Returns agent reasoning, tool calls, setup output, and other execution events. For human chat use read_task_chat.\",\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 their names, IDs, and colors. 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_tasks\",\n description: \"List project tasks, optionally filtered by status or assignment (a specific assignee, or unassigned tasks). Pass projectId to target a specific project; otherwise the configured default project is used. 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: \"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. 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, or assignment. 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.\",\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/room-helpers.ts\nfunction serviceRoom(service, entityId) {\n return `${service}:${entityId}`;\n}\nfunction userRoom(userId) {\n return `user:${userId}`;\n}\nfunction notificationUserRoom(userId) {\n return `notificationService:user:${userId}`;\n}\nfunction cliRoom(taskId) {\n return `task:${taskId}:cli`;\n}\nfunction projectCliRoom(projectId, userId) {\n return `project:${projectId}:cli:${userId}`;\n}\nfunction projectEventsRoom(projectId) {\n return `project:${projectId}:events`;\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 resolveStatDateRange(statDate, fallbackDays) {\n const today = todayInProjectTZ();\n if (statDate) {\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}\nfunction generateDateRange(sinceStr, untilStr) {\n const dates = [];\n const [sy, sm, sd] = sinceStr.split(\"-\").map(Number);\n const [uy, um, ud] = untilStr.split(\"-\").map(Number);\n let current = Date.UTC(sy, sm - 1, sd);\n const end = Date.UTC(uy, um - 1, ud);\n while (current <= end) {\n const d = new Date(current);\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 dates.push(`${yyyy}-${mm}-${dd}`);\n current += 24 * 60 * 60 * 1e3;\n }\n return dates;\n}\n\n// src/utils/message-filter.ts\nfunction messageMatchesFilters(msg, channelFilters) {\n if (!channelFilters || channelFilters.length === 0) return true;\n if (msg.role === \"user\") return true;\n const filterSet = new Set(channelFilters);\n const isToolCall = msg.metadata?.type === \"activity_block\";\n if (isToolCall) return filterSet.has(\"tools\");\n return filterSet.has(msg.channel ?? \"agent\");\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 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/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/sidecar-overhead.ts\nvar SIDECAR_OVERHEAD = {\n postgresql: {\n // 50m\n cpu: 0.05,\n // 128Mi\n memoryGi: 0.125\n },\n redis: {\n // 25m\n cpu: 0.025,\n // 32Mi\n memoryGi: 0.03125\n },\n elasticsearch: {\n // 100m\n cpu: 0.1,\n // 256Mi\n memoryGi: 0.25\n },\n lgtm: {\n // 250m — bundles Grafana + Loki + Tempo + Mimir + OTEL Collector\n cpu: 0.25,\n // 1Gi\n memoryGi: 1\n },\n \"firebase-auth-emulator\": {\n // 100m\n cpu: 0.1,\n // 256Mi\n memoryGi: 0.25\n }\n};\nfunction sidecarRequestTotals(deps) {\n let totalCpu = 0;\n let totalMemoryGi = 0;\n for (const dep of deps) {\n const overhead = SIDECAR_OVERHEAD[dep];\n if (overhead) {\n totalCpu += overhead.cpu;\n totalMemoryGi += overhead.memoryGi;\n }\n }\n return { cpu: totalCpu, memoryGi: totalMemoryGi };\n}\n\n// src/utils/xp.ts\nvar SP_XP_RATE = 10;\nvar REPORT_XP_RATE = 10;\nvar REVIEW_XP_RATE = 5;\nvar MAX_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.min(MAX_LEVEL, Math.max(1, level));\n if (level >= MAX_LEVEL) {\n return {\n level: MAX_LEVEL,\n xpIntoLevel: xp - xpToReachLevel(MAX_LEVEL),\n xpForNextLevel: 0,\n progress: 1\n };\n }\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/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}\nfunction podSizeNameForLegacyTier(tier) {\n if (tier?.cpu === 2 && tier.memory === 8) return \"small\";\n if (tier?.cpu === 4 && tier.memory === 16) return \"medium\";\n if (tier?.cpu === 8 && tier.memory === 32) return \"large\";\n return null;\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}\nfunction taskNeedsPlanning(task) {\n return !hasTaskPlan(task.plan) && PRE_BUILD_TASK_STATUSES.has(task.status) && !task.githubPRUrl;\n}\nexport {\n AGENT_CHAT_HISTORY_FETCH_LIMIT,\n AGENT_KEY_KINDS,\n AGENT_PROVIDERS,\n AGENT_STATUS_REASON_USER_QUESTION,\n ALLOWED_FILE_MIME_TYPES,\n AUTOPILOT_RATIO_MAX,\n AUTOPILOT_RATIO_MIN,\n AddDependencyRequestSchema,\n AddProjectTaskDependencyRequestSchema,\n AddProjectTaskReviewerRequestSchema,\n AgentEventSchema,\n AgentHeartbeatSchema,\n AgentQuestionOptionSchema,\n AgentQuestionSchema,\n AnswerAgentQuestionRequestSchema,\n ApproveAndMergePRRequestSchema,\n ApproveManualTestRequestSchema,\n ApproveProjectManualTestRequestSchema,\n ApproveProjectMergePRRequestSchema,\n AskUserQuestionRequestSchema,\n CARD_TYPE_STATUSES,\n CARD_TYPE_VALUES,\n CODESPACE_SESSION_ACTIVE_RUNNER_STATUSES,\n CRITICAL_AUTOMATED_SOURCES,\n CancelTaskQueuedMessageRequestSchema,\n ClearAgentTodosRequestSchema,\n ConfirmFileUploadRequestSchema,\n ConfirmProjectFileUploadRequestSchema,\n ConnectAgentRequestSchema,\n CreateFollowUpTaskRequestSchema,\n CreatePRInputSchema,\n CreatePRResponseSchema,\n CreateProjectPullRequestRequestSchema,\n CreateProjectReleaseRequestSchema,\n CreateProjectSubtaskRequestSchema,\n CreateProjectSuggestionRequestSchema,\n CreateProjectTaskRequestSchema,\n CreatePullRequestRequestSchema,\n CreateSubtaskRequestSchema,\n CreateSuggestionRequestSchema,\n DEFAULT_HAIKU_MODEL,\n DEFAULT_OPUS_MODEL,\n DEFAULT_POD_SIZE,\n DEFAULT_SONNET_MODEL,\n DEPLOYMENT_TARGET_ENVIRONMENTS,\n DEPLOYMENT_TARGET_PROVIDERS,\n DeleteProjectSubtaskRequestSchema,\n DeleteSubtaskRequestSchema,\n DeleteSubtaskResponseSchema,\n DiscoveredPortSchema,\n EMBEDDABLE_IMAGE_TYPES,\n EditManualTestRequestSchema,\n EditProjectManualTestRequestSchema,\n EmitAgentEventRequestSchema,\n EndReviewSessionRequestSchema,\n FABLE_MODEL,\n FlushSingleQueuedMessageRequestSchema,\n FlushTaskQueueRequestSchema,\n GCP_ENVS,\n GenerateTaskIconRequestSchema,\n GetActivePtySessionRequestSchema,\n GetAgentStatusRequestSchema,\n GetChatMessagesRequestSchema,\n GetCliHistoryRequestSchema,\n GetCumulativeSpendingRequestSchema,\n GetCumulativeSpendingResponseSchema,\n GetDependenciesRequestSchema,\n GetProjectAttachmentRequestSchema,\n GetProjectAvailableTuisRequestSchema,\n GetProjectSummaryRequestSchema,\n GetProjectTaskChatRequestSchema,\n GetProjectTaskCliRequestSchema,\n GetProjectTaskDependenciesRequestSchema,\n GetProjectTaskRequestSchema,\n GetProjectTaskSessionsRequestSchema,\n GetSuggestionsRequestSchema,\n GetTaskContextRequestSchema,\n GetTaskFileRequestSchema,\n GetTaskFilesRequestSchema,\n GetTaskPropertiesRequestSchema,\n GetTaskRequestSchema,\n GetUiCliHistoryRequestSchema,\n HeartbeatRequestSchema,\n HeartbeatResponseSchema,\n IDLE_HEARTBEAT_MS,\n ListAccessibleProjectsRequestSchema,\n ListActivePtySessionsRequestSchema,\n ListIconsRequestSchema,\n ListManualTestsRequestSchema,\n ListMyLiveSessionsRequestSchema,\n ListProjectManualTestsRequestSchema,\n ListProjectMembersRequestSchema,\n ListProjectSubtasksRequestSchema,\n ListProjectTagsRequestSchema,\n ListProjectTaskFilesRequestSchema,\n ListProjectTasksRequestSchema,\n ListSubtasksRequestSchema,\n MAX_AGENT_FLAVOR_LENGTH,\n MAX_DISCOVERED_PORTS,\n MAX_FILE_SIZE_BYTES,\n MAX_LEVEL,\n MCP_TOOL_REGISTRY,\n MENTION_TOKEN_REGEX,\n ModelUsageEntrySchema,\n NotifyAgentVersionRequestSchema,\n PM_CHAT_HISTORY_LIMIT,\n POD_SIZE_NAMES,\n POD_SIZE_PRESETS,\n PREVIEW_PORT_DENY_LIST,\n PREVIOUS_SONNET_MODEL,\n PRE_BUILD_TASK_STATUSES,\n PROJECT_FUNCTION_DEFAULTS,\n PROJECT_TIMEZONE,\n PickFaIconRequestSchema,\n PostChildChatMessageRequestSchema,\n PostToChatInputSchema,\n PostToChatRequestSchema,\n PostToChatResponseSchema,\n PostToProjectTaskChatRequestSchema,\n PtyAttachRequestSchema,\n PtyChatAttachRequestSchema,\n PtyChatEventPayloadSchema,\n PtyChatEventRequestSchema,\n PtyEndedRequestSchema,\n PtyInputRequestSchema,\n PtyOutputRequestSchema,\n PtyResizeRequestSchema,\n QueryManualTestsRequestSchema,\n QueryProjectGcpLogsRequestSchema,\n QueryProjectManualTestsRequestSchema,\n REPORT_XP_RATE,\n RETIRED_SONNET_MODEL,\n REVIEW_XP_RATE,\n RefreshGithubTokenRequestSchema,\n RefreshGithubTokenResponseSchema,\n RejectManualTestRequestSchema,\n RejectProjectManualTestRequestSchema,\n RemoveDependencyRequestSchema,\n RemoveManualTestRequestSchema,\n RemoveProjectManualTestRequestSchema,\n RemoveProjectTaskDependencyRequestSchema,\n RemoveProjectTaskReviewerRequestSchema,\n ReportAgentStatusRequestSchema,\n ReportDiscoveredPortsRequestSchema,\n ReportReviewSpawnFailureRequestSchema,\n RequestFileUploadRequestSchema,\n RequestProjectFileUploadRequestSchema,\n ResumeAdhocSessionRequestSchema,\n SIDECAR_OVERHEAD,\n SP_XP_RATE,\n STRANDED_RUNNER_STATUSES,\n SearchFaIconsRequestSchema,\n SearchProjectTasksRequestSchema,\n SendSoftStopRequestSchema,\n SessionStartRequestSchema,\n SessionStartResponseSchema,\n SessionStopRequestSchema,\n SessionStopResponseSchema,\n SetManualTestsRequestSchema,\n SetProjectManualTestsRequestSchema,\n StartAdhocSessionRequestSchema,\n StartChildCloudBuildRequestSchema,\n StartProjectBuildRequestSchema,\n StartProjectWorkspaceRequestSchema,\n StopAdhocSessionRequestSchema,\n StopChildBuildRequestSchema,\n StopProjectBuildRequestSchema,\n StopProjectWorkspaceRequestSchema,\n StopTaskSessionRequestSchema,\n StoreSessionIdRequestSchema,\n StoreSessionIdResponseSchema,\n SubmitCodeReviewResultRequestSchema,\n TASK_CHAT_HISTORY_LIMIT,\n TASK_LESS_WORKSPACE_PURPOSES,\n TASK_STATUS_ORDER,\n TERMINAL_TASK_STATUSES,\n TUI_KINDS,\n TrackSpendingRequestSchema,\n TriggerIdentificationRequestSchema,\n UpdateChildStatusRequestSchema,\n UpdateProjectSubtaskRequestSchema,\n UpdateProjectTaskRequestSchema,\n UpdateSubtaskRequestSchema,\n UpdateTaskFieldsRequestSchema,\n UpdateTaskPropertiesRequestSchema,\n UpdateTaskStatusRequestSchema,\n UpdateTaskStatusResponseSchema,\n VoteProjectSuggestionRequestSchema,\n VoteSuggestionRequestSchema,\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 applyAgentFlavor,\n buildMentionKey,\n cliRoom,\n computeMemoryBounds,\n computePodRatio,\n computeTotalXp,\n createAgentSessionRoom,\n createProjectRoom,\n deriveConnectionState,\n formatHeartbeatAge,\n generateDateRange,\n getToolsByCategory,\n hasTaskPlan,\n isAllowablePreviewPort,\n isCuid,\n isEmbeddableFile,\n isPodSizeName,\n isValidAutopilotConfig,\n levelFromXp,\n messageMatchesFilters,\n notificationUserRoom,\n parseMentions,\n podSizeNameForLegacyTier,\n projectCliRoom,\n projectEventsRoom,\n resolveAllowedPreviewPorts,\n resolveCodeReviewMode,\n resolveGcpEnvResources,\n resolveMentions,\n resolveProjectFunctionConfig,\n resolveStatDateRange,\n sanitizeDiscoveredPorts,\n sanitizeSessionPreviewPorts,\n serializeMention,\n serviceRoom,\n sidecarRequestTotals,\n taskNeedsPlanning,\n todayInProjectTZ,\n userRoom,\n validateStatusForType,\n xpToReachLevel\n};\n","import { taskNeedsPlanning, type AgentMode, type 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 m === \"building\" || m === \"review\" || (m === \"auto\" && this._hasExitedPlanMode);\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: fresh tasks stay in read-only plan mode; only tasks already\n // past the fresh stage (build underway, PR open, restart) bypass planning.\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 * An auto task that still NEEDS PLANNING (no plan saved, pre-build status, no\n * PR — see `taskNeedsPlanning` in @project/shared) runs the read-only plan turn\n * first (`--permission-mode plan`): resolveInitialMode leaves it in `auto` with\n * `_hasExitedPlanMode = false`, and once the agent finishes it calls\n * ExitPlanMode → building. Everything else bypasses planning and builds\n * immediately with `--dangerously-skip-permissions`:\n *\n * - a plan already on the card (e.g. a Planning card planned by a human/PM),\n * - a build already underway (status past `Planning`/`Open` — releases booted\n * `InProgress`, pod restarts mid-build where DB `agentMode` stays `\"auto\"`),\n * - a PR already open (safety net if status lags).\n *\n * Runtime Build-after-Discovery never reaches this gate as `auto` — the server's\n * `resolveModeToSend` rewrites it to `\"building\"` for any task with a plan.\n */\n canBypassPlanning(context: ModeTaskContext): boolean {\n if (this._mode !== \"auto\") return false;\n return !taskNeedsPlanning(context);\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 discovery).\n // A card that still needs planning (no plan saved yet) keeps the read-only\n // plan turn instead of jumping straight to building; without context we\n // preserve the legacy build-immediately behavior.\n if (this._runnerMode === \"task\" && newMode === \"auto\") {\n this._mode = newMode;\n this._isAuto = true;\n this._hasExitedPlanMode = !context || !taskNeedsPlanning(context);\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}\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};\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 // Sample once at startup so the running key's usage is fresh immediately\n // (mirrors startTokenRefresh), then on the interval.\n this.callbacks.onUsageSample();\n this.usageSampleTimer = setInterval(() => {\n this.callbacks.onUsageSample();\n }, this.config.usageSampleIntervalMs);\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\n/* eslint-disable @typescript-eslint/no-explicit-any -- generic tool handler */\nexport interface HarnessToolDefinition {\n name: string;\n description: string;\n schema: z.ZodRawShape;\n 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 the PTY tool server\n * (`z.strictObject`); the SDK harness ignores it, so pair it with a\n * handler-side empty-input guard.\n */\n strict?: boolean;\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\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 /** 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 /** 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 * 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 type {\n AgentHarness,\n HarnessEvent,\n HarnessQueryOptions,\n HarnessToolDefinition,\n HarnessMcpServer,\n HarnessUserMessage,\n} from \"../types.js\";\n\nexport class ClaudeCodeHarness implements AgentHarness {\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 tool(\n t.name,\n t.description,\n t.schema,\n t.handler as Parameters<typeof tool>[3],\n t.annotations ? { annotations: t.annotations } : undefined,\n ),\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 { mkdtemp, mkdir, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport type { HarnessEvent, HarnessQueryOptions, HarnessUserMessage, PtyBridge } 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 { mapChatRecords } from \"./chat-record-mapper.js\";\nimport { writeHookSettings, sessionTranscriptPath } from \"./settings.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 loadPtySpawn,\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 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 private pty: PtyProcess | null = null;\n private tempDir = \"\";\n private sawResult = 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 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\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 /** The deterministic session UUID this process is bound to. */\n get sessionUuid(): string | undefined {\n return this.resume ?? this.options.sessionId;\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 canReuse(resume: string | undefined, fingerprint: string): boolean {\n return (\n !this._toreDown &&\n !this.exited &&\n this.activeQueue === null &&\n resume !== undefined &&\n resume === this.sessionUuid &&\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.disarmSubmitNudge();\n this.disarmPlanDialogAutoAccept();\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 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) {\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(tmpdir(), \"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 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(tmpdir(), \"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 const { settingsPath } = await writeHookSettings(this.tempDir);\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.\n const sendChat = this.bridge?.sendChatEvent?.bind(this.bridge);\n this.tailer = new JsonlTailer(\n transcriptPath,\n (event) => this.handleTranscriptEvent(event),\n sendChat\n ? (raw) => {\n for (const chatEvent of mapChatRecords(raw)) sendChat(chatEvent);\n }\n : undefined,\n );\n this.tailer.start(startOffset);\n return { settingsPath, socketPath };\n }\n\n writeStdin(text: string): void {\n this.pty?.write(text);\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 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 try {\n this.pty?.kill();\n } catch {\n /* pty already exited */\n }\n this.pty = null;\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(settingsPath?: string, socketPath?: string): Promise<void> {\n const spec = this.adapter.buildSpawn({\n options: this.options,\n ...(this.resume ? { resume: this.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 });\n const spawn = await loadPtySpawn();\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 // 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.pty = pty;\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 this.writeStdin(this.adapter.encodePromptBytes(text));\n if (this.turn.promptDelivery === \"prefill\") return;\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 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 || Date.now() - startedAt >= windowMs) {\n this.disarmSubmitNudge();\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 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 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); AskUserQuestion is\n * observed and always allowed. Absent callback → allow (mirrors the SDK\n * default).\n */\n private async handlePreToolUse(request: PreToolUseRequest): Promise<PreToolUseVerdict> {\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 this.pushEvent({\n type: \"user_question\",\n questions: parseUserQuestions(request.tool_input),\n });\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 // Any new transcript record proves the submitted prompt started a turn —\n // the submit nudge has done its job.\n if (this.pendingSubmitNudge) this.disarmSubmitNudge();\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 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 * 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 a Claude Code transcript JSONL file, emitting a `HarnessEvent` for\n * each newly-appended record. Polls on a short interval because the file is\n * written by a separate process (the `claude` CLI under the PTY).\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 `mapTranscriptRecord` drops (e.g. user prompts). Used by the chat\n * PTY proxy relay, which needs between-turn records too.\n */\n private readonly onRawRecord?: (raw: unknown) => void,\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 = mapTranscriptRecord(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, stuck-auto nudges); 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 * 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\";\n\n// Headroom under the wire-schema caps (16_384 / 2_000) so a truncation\n// ellipsis can never push a payload over the Zod limit server-side.\nconst TEXT_MAX = 16_000;\nconst TOOL_INPUT_MAX = 1_900;\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/** Local slash-command wrapper records — TUI plumbing, not conversation. */\nfunction isCommandWrapperText(text: string): boolean {\n const trimmed = text.trimStart();\n return trimmed.startsWith(\"<command-name>\") || trimmed.startsWith(\"<local-command-\");\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 events.push({\n kind: \"tool_use\",\n name: truncate(name, 200),\n input: JSON.stringify(input ?? {}).slice(0, TOOL_INPUT_MAX),\n });\n }\n }\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 let text: string;\n if (typeof content === \"string\") {\n text = content;\n } else if (isUnknownArray(content)) {\n // Tool results ride user-role records; they are outputs, not prompts.\n const hasToolResult = content.some((b) => isRecord(b) && b.type === \"tool_result\");\n if (hasToolResult) return [];\n text = 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 } else {\n return [];\n }\n\n const trimmed = text.trim();\n if (trimmed.length === 0 || isCommandWrapperText(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 two 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 * 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 */\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\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\n // (ExitPlanMode) is a 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 timer = setTimeout(\n respondUnavailable,\n failOpen ? ASK_USER_QUESTION_TIMEOUT_MS : PRE_TOOL_USE_TIMEOUT_MS,\n );\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 async function writeHookSettings(dir: string): 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 the agent read-only (no edits/commits\n // until it exits plan mode) regardless of this allow-list. In build mode the\n // spawn already bypasses prompts via `--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: [\n {\n matcher: \"ExitPlanMode\",\n hooks: [{ type: \"command\", command: `node ${JSON.stringify(helperPath)}`, timeout: 120 }],\n },\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: `node ${JSON.stringify(helperPath)}`, timeout: 30 }],\n },\n {\n // Plan-permission spawns prompt for MCP tools even when they're in\n // permissions.allow — the CLI can't classify them as read-only. A\n // hook allow bypasses the permission engine in every mode. Loose by\n // design: the pod is the sandbox, and planning agents must call\n // update_task etc. The helper answers locally (no socket).\n matcher: \"mcp__.*\",\n hooks: [{ type: \"command\", command: `node ${JSON.stringify(helperPath)}`, timeout: 30 }],\n },\n ],\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 * 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 },\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(tool.name, { description: tool.description, inputSchema }, (args) =>\n 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\ntype 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 };\n const mcpConfigPath = join(tempDir, \"mcp-config.json\");\n await writeFile(mcpConfigPath, JSON.stringify({ mcpServers: config }, null, 2), \"utf8\");\n return { servers, mcpConfigPath };\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 * The `claude` CLI process boundary: resolve the binary, build its argv, and\n * interpret its exit when it dies before producing a result. Kept pure so it\n * can be unit-tested without a real spawn.\n */\n\nexport interface SpawnArgsInput {\n resume?: string;\n sessionId?: string;\n model: string;\n permissionMode: \"plan\" | \"bypassPermissions\";\n settingsPath: string;\n /** Extra system-prompt text appended via `--append-system-prompt`. */\n appendSystemPrompt?: string;\n mcpConfigPath?: string;\n /** When set with mcpConfigPath, the CLI uses ONLY that config and ignores the\n * user's `~/.claude.json` / project `.mcp.json` servers. */\n strictMcpConfig?: boolean;\n}\n\nexport function resolveClaudeBinary(): string {\n return process.env.CONVEYOR_CLAUDE_BIN ?? \"claude\";\n}\n\nexport function buildSpawnArgs(input: SpawnArgsInput): string[] {\n const args: string[] = [];\n if (input.resume) {\n args.push(\"--resume\", input.resume);\n } else if (input.sessionId) {\n args.push(\"--session-id\", input.sessionId);\n }\n args.push(\"--model\", input.model);\n if (input.permissionMode === \"bypassPermissions\") {\n args.push(\"--dangerously-skip-permissions\");\n } else {\n args.push(\"--permission-mode\", \"plan\");\n }\n args.push(\"--settings\", input.settingsPath);\n if (input.appendSystemPrompt) {\n args.push(\"--append-system-prompt\", input.appendSystemPrompt);\n }\n if (input.mcpConfigPath) {\n args.push(\"--mcp-config\", input.mcpConfigPath);\n if (input.strictMcpConfig) {\n args.push(\"--strict-mcp-config\");\n }\n }\n return args;\n}\n\n/**\n * A stable fingerprint of the spawn arguments that a REUSED (kept-alive) CLI\n * process cannot change — model, permission mode, appended system prompt, and\n * cwd are all baked into the live `claude` process at spawn. When a follow-up\n * turn would spawn with different values (most commonly a drifted\n * `appendSystemPrompt` after a plan/status edit), the parked process cannot\n * serve it, so the harness respawns instead of reusing. Keeping this beside\n * `buildSpawnArgs` ensures the two can't silently diverge.\n *\n * `settingsPath`, `mcpConfigPath`, and the hook socket path are deliberately\n * excluded: they are per-process resources that stay stable for the process's\n * whole life, so they never differentiate one turn from the next.\n */\nexport function spawnOptionsFingerprint(input: {\n model: string;\n permissionMode: \"plan\" | \"bypassPermissions\";\n appendSystemPrompt?: string;\n cwd: string;\n}): string {\n return JSON.stringify([\n input.model,\n input.permissionMode,\n input.appendSystemPrompt ?? \"\",\n input.cwd,\n ]);\n}\n\n// ─── Exit diagnostics ──────────────────────────────────────────────────────\n// The PTY harness never turns raw `claude` stdout/stderr into HarnessEvents —\n// it relays them to the S5 terminal instead. So when `claude` dies before\n// emitting a transcript result, the captured agent logs show only the generic\n// \"claude exited (code N) without a result\"; the real reason (a missing binary,\n// an auth/onboarding stop, an unknown CLI flag) scrolled past in the live\n// terminal only. These helpers fold a bounded, ANSI-stripped tail of that\n// scrollback back into the error so the failure is self-describing in the logs.\n\n// ESC (0x1B) built via fromCharCode so no control char appears as a source\n// literal (keeps the no-control-regex lint rule happy). Matches CSI sequences\n// (ESC [ ... final-byte) — the bulk of TUI escape noise; any stray ESC bytes\n// from other sequences are removed by the control-char pass below.\nconst ANSI_CSI = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;?]*[ -/]*[@-~]`, \"g\");\n\n/**\n * Strip ANSI escapes + terminal control noise and collapse to the last few\n * readable lines, capped at `maxChars`. Returns \"\" when nothing printable\n * remains (e.g. the process produced no output at all).\n */\nexport function cleanTerminalOutput(raw: string, maxChars = 1200): string {\n const noAnsi = raw.replace(ANSI_CSI, \"\");\n // Drop C0 control chars (and DEL) except tab; fold CR into newline.\n let out = \"\";\n for (const ch of noAnsi) {\n const code = ch.charCodeAt(0);\n if (ch === \"\\r\" || ch === \"\\n\") out += \"\\n\";\n else if (ch === \"\\t\") out += ch;\n else if (code < 0x20 || code === 0x7f) continue;\n else out += ch;\n }\n const lines = out\n .split(\"\\n\")\n .map((line) => line.trimEnd())\n .filter((line) => line.trim().length > 0);\n const text = lines.join(\"\\n\").trim();\n return text.length > maxChars ? `…${text.slice(-maxChars)}` : text;\n}\n\n/**\n * True when the terminal tail shows node-pty failed to exec the target binary\n * (missing `claude` CLI on PATH). node-pty prints `execvp(3) failed.: No such\n * file or directory` to the pty and the child exits with code 1.\n */\nexport function isMissingBinaryFailure(tail: string): boolean {\n return /execvp\\(\\d+\\) failed|no such file or directory|command not found/i.test(tail);\n}\n\n/**\n * Build the `errors[]` for a `claude` process that exited before emitting a\n * transcript result. The first entry is kept byte-for-byte stable so existing\n * consumers/log scrapers that key off it keep working; richer context is\n * appended after it.\n */\nexport function buildExitErrors(exitCode: number, rawOutput: string, binary: string): string[] {\n const errors = [`claude exited (code ${exitCode}) without a result`];\n const tail = cleanTerminalOutput(rawOutput);\n if (isMissingBinaryFailure(tail)) {\n errors.push(\n `The \\`${binary}\\` CLI could not be started — it is not installed or not on PATH. ` +\n `Install the Claude Code CLI in this environment (npm i -g @anthropic-ai/claude-code) ` +\n `or set CONVEYOR_CLAUDE_BIN to its absolute path.`,\n );\n }\n if (tail) {\n errors.push(`Last terminal output before exit:\\n${tail}`);\n }\n return errors;\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: a credentials file whose `claudeAiOauth` carries a\n * refreshToken was written by a real interactive `/login` (the OAuth code flow\n * always issues one) and is never touched. Our synthesized file never has one —\n * that absence IS the \"written by Conveyor\" marker. If live verification ever\n * disproves that assumption, the fallback hardening is a sidecar marker file\n * (e.g. `<configHome>/.conveyor-credentials.json` holding a hash of the token\n * we wrote) — noted here so the next person doesn't reinvent the policy.\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 { claudeConfigHome } from \"./settings.js\";\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.\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\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}\n\nexport type CredentialsPlan =\n | { action: \"skip\"; reason: \"not-cloud\" | \"no-token\" | \"foreign-credentials\" | \"current\" }\n | { action: \"write\"; contents: 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 */\nfunction buildSynthesizedCredentials(token: string, now: number): string {\n return JSON.stringify({\n claudeAiOauth: {\n accessToken: token,\n expiresAt: now + SYNTH_TOKEN_TTL_MS,\n scopes: [\"user:inference\", \"user:profile\"],\n subscriptionType: \"max\",\n },\n });\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 if (!input.token) return { action: \"skip\", reason: \"no-token\" };\n\n const contents = buildSynthesizedCredentials(input.token, input.now);\n const existing = parseClaudeAiOauth(input.existingRaw);\n // Missing, empty, unparseable, or shapeless file — ours to (re)write.\n if (!existing) return { action: \"write\", contents };\n // A refreshToken means a genuine interactive /login — never clobber.\n if (typeof existing.refreshToken === \"string\" && existing.refreshToken.length > 0) {\n return { action: \"skip\", reason: \"foreign-credentials\" };\n }\n const fresh =\n existing.accessToken === input.token &&\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 };\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/**\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 try {\n const path = claudeCredentialsPath();\n const plan = planCredentialsWrite({\n isCloud: isConveyorCloudEnv(env),\n token: env.CLAUDE_CODE_OAUTH_TOKEN,\n existingRaw: await readRaw(path),\n now: Date.now(),\n });\n if (plan.action === \"skip\") return;\n await mkdir(claudeConfigHome(), { recursive: true });\n await writeFile(path, plan.contents, { encoding: \"utf8\", mode: 0o600 });\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/**\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\nexport function planClaudeJsonSeed(existingRaw: string | null, trustCwd?: string): 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 return changed ? JSON.stringify(config) : null;\n}\n\n/**\n * Suppress the CLI's first-run wizard, the bypass-permissions warning dialog,\n * and (when `trustCwd` is given) the folder-trust dialog for that workspace\n * in Conveyor cloud envs so the spawned TUI 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 contents = planClaudeJsonSeed(await readRaw(path), trustCwd);\n if (contents === null) return;\n await writeFile(path, contents, \"utf8\");\n // Read-back check: on network-backed homes (GCS-FUSE) a write can report\n // success while a subsequent read still serves stale content — which the\n // CLI's startup read would too, re-surfacing the dialogs this seed exists\n // to suppress (seen live 2026-07-02: seed wrote silently, the folder-trust\n // dialog parked a code review anyway). Log both outcomes so pod logs show\n // what the CLI is about to read.\n const verify = await readRaw(path);\n if (verify === contents) {\n process.stderr.write(\n `[conveyor-agent] claude onboarding seeded${trustCwd ? ` (trust: ${trustCwd})` : \"\"}\\n`,\n );\n } else {\n process.stderr.write(\n `[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path}: 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 (no refreshToken). Used\n * when a runtime key update switches the agent to ANTHROPIC_API_KEY — stale\n * subscription credentials must not keep 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 existing = parseClaudeAiOauth(await readRaw(path));\n if (existing && typeof existing.refreshToken === \"string\" && existing.refreshToken.length > 0) {\n return;\n }\n await rm(path, { 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 * Pure support helpers for PtySession — node-pty process loading, prompt-byte\n * encoding, the per-turn options projection, and the AskUserQuestion parser.\n * Extracted from `session.ts` so the orchestrator stays focused on lifecycle;\n * everything here is side-effect-free (or a thin wrapper over one) and unit\n * tested in isolation.\n */\n\nimport { stat } from \"node:fs/promises\";\nimport type { HarnessQueryOptions, HarnessUserQuestion } from \"../types.js\";\n\n// Cap on the rolling tail of raw terminal output retained for diagnostics when\n// `claude` exits without a result. Bounded so a long-running session can't grow\n// this unboundedly; only the most recent bytes (where a failure surfaces) matter.\nexport const MAX_DIAGNOSTIC_OUTPUT = 4000;\n\n// Cap on transcript events buffered while no turn is draining (the parked\n// window between a completed turn and the next beginTurn / a passive turn).\n// Bounded, drop-oldest — a stale buffered `result` must never terminate a\n// fresh turn, and beginTurn clears the buffer anyway.\nexport const MAX_BETWEEN_TURN_BUFFER = 500;\n\n/** Settle window between the paste write and the submitting Enter write. */\nexport const SUBMIT_SETTLE_MS = 300;\n// Re-press cadence/bounds for the submit nudge (see armSubmitNudge). Fast\n// presses cover the Enter-swallowed-at-startup race; the slow phase covers\n// startup dialogs that render tens of seconds in on a cold pod (folder\n// trust, onboarding) — observed live 2026-07-02 parking code reviews ~13min+\n// when the trust dialog mounted after the fast window had expired.\nexport const SUBMIT_NUDGE_INTERVAL_MS = 2000;\nexport const SUBMIT_NUDGE_MAX_PRESSES = 5;\nexport const SUBMIT_NUDGE_SLOW_INTERVAL_MS = 5000;\nexport const SUBMIT_NUDGE_WINDOW_MS = 90_000;\n\n// Plan-dialog auto-accept press cadence/bounds (see armPlanDialogAutoAccept).\n// The dialog usually renders within a second of the ExitPlanMode hook verdict,\n// but the window is deliberately wide: the only stop signal is the ExitPlanMode\n// PostToolUse envelope, and a missed dialog parks an auto card indefinitely\n// (observed live 2026-07-07: an approval dialog sat 42 minutes until a human\n// pressed Enter).\nexport const PLAN_DIALOG_FIRST_PRESS_MS = 700;\nexport const PLAN_DIALOG_INTERVAL_MS = 1500;\nexport const PLAN_DIALOG_SLOW_INTERVAL_MS = 5000;\nexport const PLAN_DIALOG_FAST_WINDOW_MS = 10_000;\nexport const PLAN_DIALOG_WINDOW_MS = 90_000;\n\nfunction envMs(name: string, fallback: number): number {\n const raw = Number(process.env[name]);\n return Number.isFinite(raw) && raw > 0 ? raw : fallback;\n}\n\nexport function resolveSubmitSettleMs(): number {\n return envMs(\"CONVEYOR_PTY_SUBMIT_SETTLE_MS\", SUBMIT_SETTLE_MS);\n}\n\n/**\n * Effective submit-nudge timing. The exported constants above are the production\n * defaults; `CONVEYOR_PTY_NUDGE_INTERVAL_MS` / `_SLOW_INTERVAL_MS` / `_WINDOW_MS`\n * override them. Resolved at nudge-arm time (not import) so an integration test\n * can drive the two-phase fast→slow behavior in milliseconds instead of ~15s of\n * real wall-clock. `maxPresses` is deliberately NOT overridable — the fast→slow\n * phase-boundary count is the behavior under test.\n */\nexport function resolveSubmitNudgeTiming(): {\n intervalMs: number;\n slowIntervalMs: number;\n maxPresses: number;\n windowMs: number;\n} {\n return {\n intervalMs: envMs(\"CONVEYOR_PTY_NUDGE_INTERVAL_MS\", SUBMIT_NUDGE_INTERVAL_MS),\n slowIntervalMs: envMs(\"CONVEYOR_PTY_NUDGE_SLOW_INTERVAL_MS\", SUBMIT_NUDGE_SLOW_INTERVAL_MS),\n maxPresses: SUBMIT_NUDGE_MAX_PRESSES,\n windowMs: envMs(\"CONVEYOR_PTY_NUDGE_WINDOW_MS\", SUBMIT_NUDGE_WINDOW_MS),\n };\n}\n\nexport function resolvePlanDialogTiming(): {\n firstPressMs: number;\n intervalMs: number;\n slowIntervalMs: number;\n fastWindowMs: number;\n windowMs: number;\n} {\n return {\n firstPressMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_FIRST_PRESS_MS\", PLAN_DIALOG_FIRST_PRESS_MS),\n intervalMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_INTERVAL_MS\", PLAN_DIALOG_INTERVAL_MS),\n slowIntervalMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_SLOW_INTERVAL_MS\", PLAN_DIALOG_SLOW_INTERVAL_MS),\n fastWindowMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_FAST_WINDOW_MS\", PLAN_DIALOG_FAST_WINDOW_MS),\n windowMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_WINDOW_MS\", PLAN_DIALOG_WINDOW_MS),\n };\n}\n\n/**\n * The per-turn subset of HarnessQueryOptions — everything that legitimately\n * changes from one turn to the next while the same `claude` process serves them\n * all. The process-level fields (model, cwd, sessionId, appendSystemPrompt, …)\n * are fixed at spawn and captured separately in the spawn options.\n */\nexport interface TurnOptions {\n canUseTool?: HarnessQueryOptions[\"canUseTool\"];\n promptDelivery?: \"submit\" | \"prefill\";\n planDialogAutoAccept?: boolean;\n abortController?: AbortController;\n}\n\nexport function turnOptionsFrom(options: HarnessQueryOptions): TurnOptions {\n return {\n canUseTool: options.canUseTool,\n promptDelivery: options.promptDelivery,\n planDialogAutoAccept: options.planDialogAutoAccept,\n abortController: options.abortController,\n };\n}\n\nexport interface PtyProcess {\n onData(listener: (data: string) => void): void;\n onExit(listener: (event: { exitCode: number }) => void): void;\n write(data: string): void;\n resize(cols: number, rows: number): void;\n kill(signal?: string): void;\n}\n\nexport interface PtySpawnOptions {\n name: string;\n cols: number;\n rows: number;\n cwd: string;\n env: Record<string, string>;\n}\n\nexport type PtySpawn = (file: string, args: string[], options: PtySpawnOptions) => PtyProcess;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction extractSpawn(mod: unknown): PtySpawn | null {\n if (!isRecord(mod)) return null;\n if (typeof mod.spawn === \"function\") return mod.spawn as PtySpawn;\n const def = mod.default;\n if (isRecord(def) && typeof def.spawn === \"function\") return def.spawn as PtySpawn;\n return null;\n}\n\nexport async function loadPtySpawn(): Promise<PtySpawn> {\n const mod: unknown = await import(\"node-pty\");\n const spawn = extractSpawn(mod);\n if (!spawn) throw new Error(\"node-pty: spawn export not found\");\n return spawn;\n}\n\nexport function inheritedEnv(socketPath?: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (typeof value === \"string\") env[key] = value;\n }\n // Do NOT force CLAUDE_CONFIG_DIR. Forcing it to ~/.claude makes the CLI read\n // <dir>/.claude.json — a fresh, un-onboarded config — instead of the user's\n // real ~/.claude.json, which re-triggers the first-run theme picker + login\n // even though valid credentials already exist in ~/.claude/. The loop above\n // already propagates an explicitly-set CLAUDE_CONFIG_DIR (pods/codespaces),\n // and the config dir is unchanged either way, so transcript tailing (which\n // uses claudeConfigHome()) still resolves to the same projects/ directory.\n if (socketPath) {\n env.CONVEYOR_HOOK_SOCKET = socketPath;\n }\n // The conveyor MCP tool handlers proxy over the agent's API socket, and a\n // mid-flap call can block up to ~50s (20s reconnect-wait + 30s ack) before\n // failing with a retryable error. The CLI's default MCP timeouts are\n // shorter — hitting them made it abandon the MCP session mid-flap\n // (2026-07-08 wedge). Default both timeouts past the worst-case hang;\n // operator-set values win via the inherit loop above.\n env.MCP_TIMEOUT ??= \"60000\";\n env.MCP_TOOL_TIMEOUT ??= \"180000\";\n return env;\n}\n\n/**\n * The bracketed-paste bytes written to the CLI's stdin to deliver a prompt.\n * The text is wrapped in paste markers so embedded newlines land as literal\n * lines in the input box instead of submitting it early. The submitting Enter\n * is deliberately NOT part of these bytes: deliverPrompt() sends it as a\n * separate write after a settle window, because an Enter folded into the same\n * chunk as the paste can be swallowed by the CLI's paste-burst handling —\n * observed in production as an auto-mode prompt parked unsubmitted in the\n * input box. \"prefill\" delivery never sends an Enter at all.\n */\nexport function buildPromptBytes(text: string): string {\n return `\\x1b[200~${text}\\x1b[201~`;\n}\n\n/**\n * Render structured (multimodal) prompt content as pasteable text. Image\n * blocks are replaced with a tool reference — their base64 payload must NEVER\n * be pasted into the TUI input box. Upstream prompt builders already skip\n * image blocks for the PTY harness; this is the last line of defense.\n */\nexport function renderPromptContentText(content: unknown[]): string {\n return content\n .map((block) => {\n const b = block as { type?: string; text?: string };\n if (b?.type === \"text\" && typeof b.text === \"string\") return b.text;\n if (b?.type === \"image\") {\n return `[Image attachment — use list_task_files / get_attachment to view]`;\n }\n return JSON.stringify(block);\n })\n .join(\"\\n\\n\");\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/** Current size of the transcript, or 0 if it does not exist yet. */\nexport async function transcriptSize(path: string): Promise<number> {\n try {\n return (await stat(path)).size;\n } catch {\n return 0;\n }\n}\n\n/**\n * Defensive extraction of AskUserQuestion's `questions` input from the hook\n * payload. Malformed entries are dropped rather than thrown — the event is\n * observe-only, so an empty list still arms the waiting_for_input report.\n */\nexport function parseUserQuestions(input: Record<string, unknown>): HarnessUserQuestion[] {\n if (!Array.isArray(input.questions)) return [];\n const questions: HarnessUserQuestion[] = [];\n for (const entry of input.questions) {\n if (!isRecord(entry)) continue;\n if (typeof entry.question !== \"string\") continue;\n const options = Array.isArray(entry.options)\n ? entry.options\n .filter(isRecord)\n .filter((o) => typeof o.label === \"string\")\n .map((o) => ({\n label: o.label as string,\n description: typeof o.description === \"string\" ? o.description : \"\",\n }))\n : [];\n questions.push({\n question: entry.question,\n header: typeof entry.header === \"string\" ? entry.header : \"\",\n options,\n ...(typeof entry.multiSelect === \"boolean\" ? { multiSelect: entry.multiSelect } : {}),\n });\n }\n return questions;\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 };\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 * 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\";\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 /**\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 /** 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\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 async *executeQuery(opts: {\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>;\n options: HarnessQueryOptions;\n resume?: string;\n }): AsyncGenerator<HarnessEvent, void> {\n const want = opts.resume ?? opts.options.resume;\n const fingerprint = this.fingerprintOf(opts.options);\n\n let session: PtySession;\n if (this.parked?.canReuse(want, fingerprint)) {\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 = new PtySession(opts.prompt, opts.options, want, this.bridge, this.adapter);\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: opts.options.cwd });\n // Register the parked-death watch once for this process's lifetime.\n session.onExit(() => this.handleSessionExit(session));\n await session.start();\n }\n\n yield* this.drain(session);\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 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","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\";\n\nimport { ClaudeCodeHarness } from \"./claude-code/index.js\";\nimport { PtyHarness } from \"./pty/index.js\";\nimport type { AgentHarness, PtyBridge } from \"./types.js\";\n\nexport type HarnessKind = \"sdk\" | \"pty\";\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 harness ignores it.\n */\nexport function createHarness(kind: HarnessKind = \"sdk\", ptyBridge?: PtyBridge): AgentHarness {\n return kind === \"pty\" ? new PtyHarness(ptyBridge) : new ClaudeCodeHarness();\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 type {\n AgentHarness,\n HarnessEvent,\n HarnessUserMessage,\n HarnessQueryOptions,\n HarnessHookInput,\n HarnessHookOutput,\n HarnessKind,\n} from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport type { TaskContext, MultimodalBlock, AgentMode } from \"@project/shared\";\nimport type { AgentRunnerConfig, AgentRunnerCallbacks } from \"../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 { API_ERROR_PATTERN, isAuthError } from \"./event-handlers.js\";\nimport type { ExplorationTracker } from \"./exploration-tracker.js\";\nimport { buildCanUseTool } from \"./tool-access.js\";\nimport { collectMissingProps } from \"./task-property-utils.js\";\nimport { redact } from \"./redactor.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 interface QueryHost {\n config: AgentRunnerConfig;\n connection: AgentConnection;\n callbacks: AgentRunnerCallbacks;\n harness: AgentHarness;\n harnessKind: HarnessKind;\n setupLog: string[];\n explorationTracker: ExplorationTracker | null;\n agentMode: AgentMode;\n isAuto: boolean;\n isParentTask: boolean;\n hasExitedPlanMode: boolean;\n pendingModeRestart: boolean;\n discoveryCompleted: boolean;\n wasRateLimited: boolean;\n sessionIds: Map<string, string>;\n activeQuery: AsyncGenerator<HarnessEvent, void> | null;\n pendingToolOutputs: { tool: string; output: string }[];\n abortController: AbortController | null;\n isStopped(): boolean;\n requestStop(): void;\n requestSoftStop(): void;\n createInputStream(\n prompt: string | MultimodalBlock[],\n ): AsyncGenerator<HarnessUserMessage, void, unknown>;\n onModeTransition?: (newMode: AgentMode) => void;\n}\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 manual-mode task chat under the PTY\n * harness. 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 *\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 + manual\n * agentMode (discovery/help) IS the human-facing discovery card — exactly the\n * flow that should park a prefilled TUI. Autonomous pm flows are already\n * 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 the human-facing planning modes park a prefill. building/review\n // initial queries must auto-run — a fresh-disk building boot with nobody at\n // the terminal would otherwise stall the build.\n if (inputs.agentMode !== \"discovery\" && 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\nfunction 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 const combined = [...configured, ...modeDisallowed];\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 (auto pre-exit, discovery, help) use the SDK's native \"plan\"\n // permission mode which enforces no-execution (blocks file edits and destructive commands).\n // canUseTool is still registered to intercept ExitPlanMode for custom validation\n // (plan/SP/title checks, triggerIdentification, mode restart).\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 // The spawned CLI never sees `systemPrompt` (an SDK-only option) — deliver\n // the same text via `--append-system-prompt`. PTY-only: the SDK harness\n // already receives it through systemPrompt.append.\n ...(host.harnessKind === \"pty\" && systemPromptText\n ? { appendSystemPrompt: systemPromptText }\n : {}),\n // Auto mode pre-exit: after the ExitPlanMode hook allows the call, the\n // CLI's plan dialog still renders — press Enter so the autonomous agent\n // continues building in the 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 isPty = host.harnessKind === \"pty\";\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, isPty);\n if (followUpImages.length > 0 && Array.isArray(prompt)) {\n prompt.push(...followUpImages);\n }\n return prompt;\n }\n if (followUpImages.length > 0) {\n if (isPty) {\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/**\n * Status-accuracy watchdog for submitted PTY queries. Display-only: the\n * query keeps draining either way, `_state` in SessionRunner is untouched\n * (so chat-message supersede and idle-timer behavior are unchanged), and the\n * first event flips the reported status back to running.\n */\nexport async function* watchForParkedTui(\n inner: AsyncGenerator<HarnessEvent, void>,\n host: Pick<QueryHost, \"connection\" | \"callbacks\">,\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 try {\n for await (const event of inner) {\n clearTimeout(timer);\n if (parked) {\n parked = false;\n host.connection.emitStatus(\"running\");\n await host.callbacks.onStatusChange(\"running\");\n }\n yield event;\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 && promptDelivery !== \"prefill\") {\n // SDK harness (or a resumed session): there is no TUI input box to\n // pre-fill, and discovery must not auto-run — wait for a chat message.\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 agentQuery = watchForParkedTui(agentQuery, host);\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 // On the PTY harness image blocks would be pasted into the TUI as text —\n // the prompt body already links each image (get_attachment / downloadUrl).\n prompt: buildMultimodalPrompt(initialPrompt, context, harnessKind === \"pty\"),\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 || host.harnessKind === \"pty\",\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 host.harnessKind === \"pty\",\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 host.harnessKind === \"pty\",\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\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.rateLimitResetsAt) {\n handleRateLimitPause(host, result.rateLimitResetsAt);\n return { action: \"return\" };\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 { 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\nexport function buildPackRunnerSystemPrompt(\n context: TaskContext,\n config: { instructions: string; workspaceDir: string },\n setupLog: string[],\n): string {\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. 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. 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, and **dependency info** (dependencies array + allDependenciesMet flag).`,\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. If blocking progress, 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. Merge or wait on in-flight children, then start more as slots free up.`,\n ``,\n `4. After merging a PR: run \\`git pull origin ${context.baseBranch}\\` 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 `- You can use get_task(childTaskId) to get a child's full details including PR URL and branch.`,\n `- list_subtasks returns PR info (githubPRNumber, githubPRUrl), agent assignment (agentId), and dependency info for each child — use this to verify readiness before firing builds.`,\n `- You can use read_task_chat to check for team messages.`,\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(\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\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 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 ${context.baseBranch}\\`.`,\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\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","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport type { RunnerMode, TaskContext } from \"@project/shared\";\n\ninterface ResolvedEntry {\n type: \"rule\" | \"file\" | \"folder\" | \"doc\";\n path: string;\n label?: string;\n content: string | null;\n charCount: number;\n}\n\ninterface ResolvedTagContext {\n tagName: string;\n description: string | null;\n entries: ResolvedEntry[];\n}\n\nconst TYPE_PRIORITY: Record<string, number> = { rule: 0, file: 1, folder: 2, doc: 3 };\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 rule/file contents 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 fileContentCache = new Map<string, { mtimeMs: number; content: string }>();\nconst folderListingCache = new Map<string, { mtimeMs: number; listing: string }>();\nlet fileReadCount = 0;\nlet folderReadCount = 0;\n\nexport function clearTagContextCache(): void {\n fileContentCache.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: fileContentCache.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\nfunction getContextBudgetChars(_model: string, betas?: string[], runnerMode?: RunnerMode): number {\n const contextWindow = betas?.some((b) => b.includes(\"context-1m\")) ? 1_000_000 : 200_000;\n // Task agents get 15% budget (plan already captures key context); PM/code-review get 25%\n const budgetPct = runnerMode === \"task\" ? 0.15 : 0.25;\n // ~4 chars per token\n return contextWindow * budgetPct * 4;\n}\n\nasync function readFileContent(filePath: string, maxChars: number): Promise<string | null> {\n try {\n if (isBinaryPath(filePath)) return null;\n let rawContent: string;\n let mtimeMs: number;\n try {\n const st = await stat(filePath);\n mtimeMs = st.mtimeMs;\n } catch {\n return null;\n }\n const cached = fileContentCache.get(filePath);\n if (cached && cached.mtimeMs === mtimeMs) {\n rawContent = cached.content;\n } else {\n rawContent = await readFile(filePath, \"utf-8\");\n fileReadCount++;\n fileContentCache.set(filePath, { mtimeMs, content: rawContent });\n }\n if (rawContent.length > maxChars) {\n const omitted = rawContent.length - maxChars;\n return rawContent.slice(0, maxChars) + `\\n[... truncated, ${omitted} chars omitted]`;\n }\n return rawContent;\n } catch {\n return null;\n }\n}\n\nasync function readFolderListing(folderPath: string): Promise<string | null> {\n try {\n let mtimeMs: number;\n try {\n const st = await stat(folderPath);\n mtimeMs = st.mtimeMs;\n } catch {\n return null;\n }\n const cached = folderListingCache.get(folderPath);\n if (cached && cached.mtimeMs === mtimeMs) {\n return cached.listing;\n }\n const entries = await readdir(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(\n entry: { type: string; path: string; label?: string },\n budget: { remaining: number },\n): Promise<ResolvedEntry> {\n const result: ResolvedEntry = {\n type: entry.type as ResolvedEntry[\"type\"],\n path: entry.path,\n label: entry.label,\n content: null,\n charCount: 0,\n };\n\n if (budget.remaining <= 0) return result;\n\n if (entry.type === \"doc\") {\n // doc type references project documents in DB — skip content injection\n return result;\n }\n\n if (entry.type === \"folder\") {\n const listing = await readFolderListing(entry.path);\n if (listing) {\n result.content = listing;\n result.charCount = listing.length;\n budget.remaining -= listing.length;\n }\n return result;\n }\n\n // rule or file — read from disk\n // Single file cap: 50% of remaining budget\n const maxChars = Math.floor(budget.remaining * 0.5) || budget.remaining;\n const content = await readFileContent(entry.path, maxChars);\n if (content) {\n result.content = content;\n result.charCount = content.length;\n budget.remaining -= content.length;\n }\n return result;\n}\n\nfunction formatEntry(entry: ResolvedEntry): string {\n const label = entry.label ? ` (${entry.label})` : \"\";\n const header = `#### ${entry.path}${label} (${entry.type})`;\n\n if (entry.content === null) {\n return `> ${entry.type}: ${entry.path}${label}`;\n }\n\n if (entry.type === \"folder\") {\n return `${header}\\n${entry.content}`;\n }\n\n // rule or file — wrap in code fence\n return `${header}\\n\\`\\`\\`\\n${entry.content}\\n\\`\\`\\``;\n}\n\nfunction formatResolvedTags(resolved: ResolvedTagContext[]): string {\n const parts: string[] = [`\\n## Tag Context`];\n\n for (const tag of resolved) {\n if (tag.entries.length === 0) continue;\n const desc = tag.description ? ` — ${tag.description}` : \"\";\n parts.push(`\\n### Tag: \"${tag.tagName}\"${desc}`);\n\n const contentEntries = tag.entries.filter((e) => e.content !== null);\n const pointerEntries = tag.entries.filter((e) => e.content === null);\n\n for (const entry of contentEntries) {\n parts.push(`\\n${formatEntry(entry)}`);\n }\n\n if (pointerEntries.length > 0) {\n parts.push(``);\n parts.push(`> Budget limit reached. Remaining linked files (read manually if needed):`);\n for (const entry of pointerEntries) {\n parts.push(formatEntry(entry));\n }\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nexport async function resolveTagContext(\n projectTags: TaskContext[\"projectTags\"],\n taskTagIds: string[],\n model: string,\n betas?: string[],\n runnerMode?: RunnerMode,\n): Promise<{ injectedSection: string; stats: { injected: number; skipped: number } }> {\n if (!projectTags?.length || !taskTagIds.length) {\n return { injectedSection: \"\", stats: { injected: 0, skipped: 0 } };\n }\n\n const taskTagIdSet = new Set(taskTagIds);\n const assignedTags = projectTags.filter((t) => taskTagIdSet.has(t.id));\n\n if (assignedTags.length === 0) {\n return { injectedSection: \"\", stats: { injected: 0, skipped: 0 } };\n }\n\n // Collect all entries across tags, sorted by type priority\n const allEntries: { tagIndex: number; entry: { type: string; path: string; label?: string } }[] =\n [];\n for (let i = 0; i < assignedTags.length; i++) {\n const tag = assignedTags[i];\n if (!tag.contextPaths?.length) continue;\n const sorted = [...tag.contextPaths].sort(\n (a, b) => (TYPE_PRIORITY[a.type] ?? 99) - (TYPE_PRIORITY[b.type] ?? 99),\n );\n for (const entry of sorted) {\n allEntries.push({ tagIndex: i, entry });\n }\n }\n\n if (allEntries.length === 0) {\n return { injectedSection: \"\", stats: { injected: 0, skipped: 0 } };\n }\n\n const budgetChars = getContextBudgetChars(model, betas, runnerMode);\n const budget = { remaining: budgetChars };\n let injected = 0;\n let skipped = 0;\n\n // Resolve all entries\n const resolved: ResolvedTagContext[] = assignedTags.map((t) => ({\n tagName: t.name,\n description: t.description,\n entries: [],\n }));\n\n for (const { tagIndex, entry } of allEntries) {\n const result = await resolveEntry(entry, budget);\n resolved[tagIndex].entries.push(result);\n if (result.content === null) {\n skipped++;\n } else {\n injected++;\n }\n }\n\n return {\n injectedSection: formatResolvedTags(resolved),\n stats: { injected, skipped },\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 `Verify that story points, title, and tags are set via get_current_plan, then call ExitPlanMode immediately to transition to building.`,\n `Do NOT wait for team input — proceed autonomously.`,\n ];\n}\n\nfunction buildPmAutoPlanningRelaunchParts(): string[] {\n return [\n `\\nYou are in auto mode. Continue planning autonomously.`,\n `When the plan and all required properties are set, call ExitPlanMode to transition to building.`,\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\";\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\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 plan this task, proactively fill in task properties when you have enough context:`,\n `- Use update_task_properties to set any combination of: title, story points, 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 `Don't wait for the user to ask — fill these in naturally as the plan takes shape.`,\n `If the user adjusts the plan significantly, update the properties to match.`,\n );\n\n // Story points — PM/code-review only\n if (!isTask && 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\n return parts;\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 `- 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, 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, 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** (via update_task_properties), **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 planning → building → PR.`,\n ``,\n `### Phase 1: Discovery & Planning (current)`,\n `- You are in the SDK's plan mode — read-only access is enforced automatically`,\n `- You have MCP tools for task properties: update_task_plan, update_task_properties`,\n ``,\n `### Required before transitioning:`,\n `Before calling ExitPlanMode, you MUST fill in ALL of these:`,\n `1. **Plan** — Save a clear implementation plan using update_task_plan`,\n `2. **Story Points** — Assign via update_task_properties`,\n `3. **Title** — Set an accurate title via update_task_properties (if the current one is vague or \"Untitled\")`,\n ``,\n `### Transitioning to Building:`,\n `When your plan is complete and all required properties are set, call the **ExitPlanMode** tool.`,\n `- If any required properties are missing, ExitPlanMode will be denied with details on what's missing`,\n `- Once ExitPlanMode succeeds, you will seamlessly transition to full build access within the same session`,\n `- Continue directly with implementation — no restart or waiting is needed`,\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. Your plan should define child tasks with detailed plans, not direct implementation steps.`,\n `After ExitPlanMode, you'll transition to Review mode to coordinate child task execution.`,\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 ``,\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\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 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, open a PR when done`,\n ``,\n `### Pre-PR Verification Checklist`,\n `CI runs the FULL suite (lint, typecheck, all test shards) on every PR — do not duplicate it locally. Before calling \\`mcp__conveyor__create_pull_request\\`, scope verification to your diff:`,\n `1. \\`bun run check\\` — lint + typecheck (fast; run whenever you changed code)`,\n `2. \\`bun run test:affected\\` — runs only the tests your diff can affect (docs-only diffs run nothing; apps/api diffs run unit tests only since CI covers the int shards; shared/db diffs escalate to the full suite automatically)`,\n `Docs/markdown/.claude-only changes need NO local gates — open the PR and let CI validate.`,\n `If a gate fails, fix it before opening the PR. Do NOT open PRs with known failing gates. Never run the full \\`bun run test\\` for a diff confined to one package.`,\n `For refactors: also run \\`git diff ${context?.baseBranch ?? \"dev\"}..HEAD\\` and confirm the public API surface (exports, function signatures) has no unintended breaking changes.`,\n ]),\n ];\n return parts.join(\"\\n\");\n }\n case \"review\":\n return buildReviewPrompt(context);\n case \"auto\":\n return buildAutoPrompt(context, runnerMode);\n default:\n return null;\n }\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 );\n } else {\n parts.push(\n `### Code Review Process`,\n `1. Run \\`git diff ${context?.baseBranch ?? \"dev\"}..HEAD\\` 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 `- **Pattern Consistency**: Does the code follow existing patterns in the codebase? Check nearby files.`,\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 `### 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 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 `- Check the dev branch (e.g. run: git fetch && git checkout dev || git checkout main) to understand the current state of the codebase that agents will branch off of.`,\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 GitHub Codespace with full access to the repository.`,\n `\\nEnvironment (fully ready — do NOT verify or set up):`,\n `- Repository is cloned at your current working directory.`,\n `- Branch \\`${context.githubBranch}\\` is already checked out.`,\n `- All dependencies are installed, database is migrated, and the dev server is running.`,\n `- Git is configured. Commit and push directly to this branch.`,\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 `- 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. Anything longer: launch it with run_in_background and STOP — a completion notification arrives when it finishes. Never busy-wait with sleep/pgrep/tail loops (foreground shell commands are killed at ~2 minutes), and never re-run the suite to escape a wait that looks stalled.`,\n `- Deferred tools have no schema loaded until fetched — before first use, load it via ToolSearch (query \"select:<ToolName>\", e.g. \"select:Monitor\"); never guess a deferred tool's parameters.`,\n `- The \\`gh\\` CLI may not be installed — use the mcp__conveyor__* tools for PR and task state.`,\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 `\\nIMPORTANT — Skip all environment verification. Do NOT run any of the following:`,\n `- bun/npm install, pip install, or any dependency installation`,\n `- bun build, bun lint, bun test, bun typecheck, or any build/check commands as a \"first step\"`,\n `- bun db:generate, bun db:push, prisma migrate, or any database setup`,\n `- bun dev, npm start, or any dev server startup commands`,\n `- pwd, ls, echo, or exploratory shell commands to \"check\" the environment`,\n `Only run these if you encounter a specific error that requires it.`,\n `Start reading the task plan and writing code immediately.`,\n `\\nGit safety — STRICT rules:`,\n `- NEVER run \\`git checkout main\\`, \\`git checkout dev\\`, or switch to any branch other than \\`${context.githubBranch}\\`.`,\n `- NEVER create new branches (no \\`git checkout -b\\`, \\`git switch -c\\`, etc.).`,\n `- This branch was created from \\`${context.baseBranch}\\`. PRs will automatically target that branch.`,\n `- If \\`git push\\` fails with \"non-fast-forward\", run \\`git push --force-with-lease origin ${context.githubBranch}\\`. This branch is exclusively yours — 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 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 type RunnerMode,\n type AgentMode,\n type TaskContext,\n type ChatMessage,\n} from \"@project/shared\";\nimport { buildPackRunnerInstructions } from \"./pack-runner-prompt.js\";\nimport {\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 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 */\nfunction 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\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\n if (mode === \"pm\") {\n parts.push(...buildPmRelaunchParts(context, lastAgentIdx, isAuto, agentMode));\n } else if (scenario === \"feedback_relaunch\") {\n const newMessages = (\n context.lastSeenMessageId\n ? messagesAfterCursor(context.chatHistory, context.lastSeenMessageId)\n : context.chatHistory.slice(lastAgentIdx + 1)\n ).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\nasync function resolveTaskTagContext(\n context: TaskContext,\n runnerMode?: RunnerMode,\n): Promise<string | null> {\n if (!context.projectTags?.length || !context.taskTagIds?.length) return null;\n const { injectedSection } = await resolveTagContext(\n context.projectTags,\n context.taskTagIds,\n context.model,\n context.agentSettings?.betas,\n runnerMode,\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.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\nfunction buildFreshInstructions(\n isPm: boolean,\n isCodeReview: boolean,\n isAutoMode: boolean,\n context: TaskContext,\n agentMode?: AgentMode | null,\n): string[] {\n if (isCodeReview) {\n return buildFreshCodeReviewInstructions(context);\n }\n\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 `Verify that story points, title, and tags are set, then call ExitPlanMode immediately to transition to building.`,\n `Do NOT re-plan or wait for team input — proceed autonomously.`,\n ];\n }\n return [\n `You are operating autonomously. Begin planning immediately.`,\n `1. Search the codebase (grep/glob) to locate relevant files, then read the critical ones`,\n `2. Draft a clear implementation plan and save it with update_task_plan`,\n `3. Set story points, tags, and title (update_task_properties)`,\n `4. When the plan and all required properties are set, call ExitPlanMode to transition to building`,\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.`,\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 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 const parts = [\n `Begin executing the task plan above immediately.`,\n `Your FIRST action should be reading the relevant source files mentioned in the plan, then writing code. Do NOT run install, build, lint, test, or dev server commands first — the environment is already set up.`,\n `Work on the git branch \"${context.githubBranch}\". Stay on this branch for the entire task. Do not checkout or create other branches.`,\n `Use post_to_chat to keep the team informed (your turn output is NOT shown in chat — post_to_chat is the only way they see it): briefly post what you're doing when you begin meaningful implementation, and again when the PR is ready.`,\n `Before opening the PR, verify with \\`bun run check\\` (lint + typecheck) and \\`bun run test:affected\\` (tests scoped to your diff — docs-only changes need no local gates). Fix any failures. Do NOT open a PR with known failing gates. CI runs the full suite on the PR — never run the full \\`bun run test\\` for a diff confined to one package.`,\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 if (isAutoMode) {\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 `Do NOT summarize the plan or say \"ready to implement\" — start implementing immediately.`,\n `When all changes are ready, 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 running \\`git diff ${context.baseBranch ?? \"dev\"}..HEAD\\` to inspect the submitted changes, then read the task plan and surrounding code as needed.`,\n `Review for correctness, security, performance, error handling, test coverage, and consistency with existing patterns.`,\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 — update the plan accordingly using update_task_plan.`,\n `When the plan and all required properties are set, call ExitPlanMode to transition to building.`,\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 \\`git log --oneline -10\\` and \\`git diff HEAD~3 HEAD --stat\\` to review what you already committed.`,\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 `Before pushing or opening a PR, re-verify with \\`bun run check\\` and \\`bun run test:affected\\`. Fix any failures — relaunches are the most common place verification gets skipped. CI runs the full suite on the PR; keep local runs scoped to your diff.`,\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 `Verify that story points, title, and tags are set, then call ExitPlanMode immediately to transition to building.`,\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 planning autonomously.`,\n `When the plan and all required properties are set, call ExitPlanMode to transition to building.`,\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 if (scenario === \"fresh\") {\n parts.push(\n ...buildFreshInstructions(isPm, isCodeReview, agentMode === \"auto\", context, agentMode),\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 =\n 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 { defineTool } from \"../harness/index.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 defineTool(\n \"read_task_chat\",\n \"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 {\n limit: z.number().optional().describe(\"Number of recent messages to fetch (default 20)\"),\n task_id: z\n .string()\n .optional()\n .describe(\"Child task ID to read chat from. Omit to read the current task's chat.\"),\n },\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 defineTool(\n \"get_task\",\n \"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 {\n slug_or_id: z.string().describe(\"The task slug (e.g. 'my-task') or CUID\"),\n },\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(\"Task ID or slug. Omit to read logs from the current task.\"),\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 defineTool(\n \"list_task_files\",\n \"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 {},\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 defineTool(\n \"get_attachment\",\n \"Fetch one task file's content plus metadata by file ID. Call list_task_files first to discover IDs and check sizes — large binaries may be truncated by the service's size limit.\",\n { fileId: z.string().describe(\"The file ID to retrieve\") },\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","/** 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 { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult } from \"./helpers.js\";\n\nexport function buildGetDependenciesTool(connection: AgentConnection) {\n return defineTool(\n \"get_dependencies\",\n \"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 {},\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 { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../types.js\";\nimport { textResult } from \"./helpers.js\";\nimport {\n hasUncommittedChanges,\n stageAndCommit,\n hasUnpushedCommits,\n pushToOrigin,\n} from \"../runner/git-utils.js\";\n\nexport function buildPostToChatTool(connection: AgentConnection) {\n return defineTool(\n \"post_to_chat\",\n \"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 {\n message: z.string().describe(\"The message to post to the team\"),\n task_id: z\n .string()\n .optional()\n .describe(\"Child task ID to post to. Omit to post to the current task's chat.\"),\n },\n async ({ message, task_id }) => {\n try {\n if (task_id) {\n await connection.call(\"postChildChatMessage\", {\n sessionId: connection.sessionId,\n childTaskId: task_id,\n message,\n });\n return textResult(JSON.stringify({ posted: true, target: `child:${task_id}` }));\n }\n const dedup = connection.checkAndTrackDuplicate(message);\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 });\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([\"InProgress\", \"ReviewPR\", \"ReviewDev\", \"Complete\"])\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 defineTool(\n \"create_pull_request\",\n \"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 {\n title: z.string().describe(\"The PR title\"),\n body: z.string().describe(\"The PR description/body in markdown\"),\n branch: z\n .string()\n .optional()\n .describe(\n \"The head branch name for the PR. If the task doesn't have a branch set, this will be used. Defaults to the task's existing branch.\",\n ),\n baseBranch: z\n .string()\n .optional()\n .describe(\n \"The base branch to target for the PR (e.g. 'main', 'develop'). Defaults to the project's configured dev branch.\",\n ),\n commitMessage: z\n .string()\n .optional()\n .describe(\n \"Commit message for staging uncommitted changes. If not provided, a default message based on the PR title will be used.\",\n ),\n skipVerify: z\n .boolean()\n .optional()\n .describe(\n \"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 async ({ title, body, branch, baseBranch, commitMessage, skipVerify }) => {\n try {\n const cwd = config.workspaceDir;\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: branch,\n base: baseBranch,\n });\n connection.sendEvent({\n type: \"pr_created\",\n url: result.prUrl,\n number: result.prNumber,\n });\n return textResult(`Pull request #${result.prNumber} created: ${result.prUrl}`);\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 defineTool(\n \"add_dependency\",\n \"Add a blocking dependency — this task cannot start until the named task is merged to dev. For post-task follow-ups use create_follow_up_task instead.\",\n {\n depends_on_slug_or_id: z.string().describe(\"Slug or ID of the task this task depends on\"),\n },\n 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}\n\nexport function buildRemoveDependencyTool(connection: AgentConnection) {\n return defineTool(\n \"remove_dependency\",\n \"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 {\n depends_on_slug_or_id: z.string().describe(\"Slug or ID of the task to remove as dependency\"),\n },\n 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}\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. Use for out-of-scope work or cleanup that should land after this task merges. For blockers use add_dependency.\",\n {\n title: z.string().describe(\"Follow-up task title\"),\n description: z.string().optional().describe(\"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\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 buildAddDependencyTool(connection),\n buildRemoveDependencyTool(connection),\n buildCreateFollowUpTaskTool(connection),\n buildCreateSuggestionTool(connection),\n buildVoteSuggestionTool(connection),\n ];\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { basename, extname, isAbsolute, join } from \"node:path\";\nimport { z } from \"zod\";\nimport { MAX_FILE_SIZE_BYTES } from \"@project/shared\";\nimport { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../types.js\";\nimport { textResult } from \"./helpers.js\";\n\nconst IMAGE_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};\n\nexport function buildUploadAttachmentTool(connection: AgentConnection, config: AgentRunnerConfig) {\n return defineTool(\n \"upload_attachment\",\n \"Upload an image file (e.g. a Playwright screenshot) as a task attachment AND post it to the task chat in one step — no follow-up post_to_chat call needed. Supports png/jpg/gif/webp.\",\n {\n path: z\n .string()\n .describe(\"Path to the image file — absolute, or relative to the workspace root\"),\n title: z\n .string()\n .optional()\n .describe(\"Short caption posted with the image (defaults to the file name)\"),\n },\n async ({ path, title }) => {\n try {\n const filePath = isAbsolute(path) ? path : join(config.workspaceDir, path);\n const mimeType = IMAGE_MIME_BY_EXT[extname(filePath).toLowerCase()];\n if (!mimeType) {\n return textResult(\n `Unsupported file type \"${extname(filePath) || \"(none)\"}\". Supported: ${Object.keys(IMAGE_MIME_BY_EXT).join(\", \")}`,\n );\n }\n\n const info = await stat(filePath).catch(() => null);\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 upload limit. Resize or crop the image first.`,\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 body = await readFile(filePath);\n const res = await fetch(uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": mimeType },\n body,\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 });\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}`,\n );\n } catch (error) {\n return textResult(\n `Failed to upload attachment: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n","import { z } from \"zod\";\nimport type { TaskManualTestsGroupDTO } from \"@project/shared\";\nimport { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult } from \"./helpers.js\";\n\nexport function buildListManualTestsTool(connection: AgentConnection) {\n return defineTool(\n \"list_manual_tests\",\n \"List the manual test checklist items for the current task. Use to see what manual verification steps have already been recorded.\",\n {},\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 defineTool(\n \"query_manual_tests\",\n \"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 {\n cardStatuses: z\n .array(z.string())\n .optional()\n .describe('Filter tasks by card status, e.g. [\"ReviewDev\", \"ReviewLive\"]'),\n testStatuses: z\n .array(z.enum([\"open\", \"approved\", \"rejected\"]))\n .optional()\n .describe(\"Filter tests by status: open | approved | rejected\"),\n },\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 defineTool(\n \"set_manual_tests\",\n \"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 {\n items: z\n .array(z.object({ title: z.string().min(1).describe(\"A concise, actionable test step\") }))\n .min(1)\n .describe(\"List of manual test steps to add\"),\n },\n 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}\n\nexport function buildEditManualTestTool(connection: AgentConnection) {\n return defineTool(\n \"edit_manual_test\",\n \"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 {\n title: z.string().min(1).describe(\"The current title of the manual test to edit\"),\n newTitle: z.string().min(1).describe(\"The new title for the manual test\"),\n },\n 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}\n\nexport function buildRemoveManualTestTool(connection: AgentConnection) {\n return defineTool(\n \"remove_manual_test\",\n \"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 {\n title: z.string().min(1).describe(\"The title of the manual test to remove\"),\n },\n 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}\n\nexport function buildApproveManualTestTool(connection: AgentConnection) {\n return defineTool(\n \"approve_manual_test\",\n \"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 {\n title: z.string().min(1).describe(\"The title of the manual test to approve\"),\n },\n 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}\n\nexport function buildRejectManualTestTool(connection: AgentConnection) {\n return defineTool(\n \"reject_manual_test\",\n \"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 {\n title: z.string().min(1).describe(\"The title of the manual test to reject\"),\n reason: z\n .string()\n .min(1)\n .max(2000)\n .describe(\"Why the test failed — what went wrong, shown to the team\"),\n },\n 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}\n","import type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../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 { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport { textResult } from \"./helpers.js\";\n\nconst SP_DESCRIPTION = \"Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)\";\nconst FOLLOW_PARENT_STATUS_DESCRIPTION =\n \"Child mirrors the parent task's status automatically — 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.\";\nconst DEPENDS_ON_DESCRIPTION =\n \"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 — the pack runner schedules children off these edges. Omit / leave empty for independent children so they run in parallel.\";\n\nexport function buildUpdateTaskTool(connection: AgentConnection) {\n return defineTool(\n \"update_task_plan\",\n \"Save the finalized plan and/or description to the current task. Use in Plan mode after alignment. 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.string().optional().describe(\"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 {\n return textResult(\"Failed to update task.\");\n }\n },\n );\n}\n\nfunction buildCreateSubtaskTool(connection: AgentConnection) {\n return defineTool(\n \"create_subtask\",\n \"Create a subtask under the current parent task. Use when breaking a complex parent into smaller pieces during planning. For post-task follow-ups use create_follow_up_task.\",\n {\n title: z.string().describe(\"Subtask title\"),\n description: z.string().optional().describe(\"Brief description\"),\n plan: z.string().optional().describe(\"Implementation plan in markdown\"),\n ordinal: z.number().optional().describe(\"Step/order number (0-based)\"),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n followParentStatus: z.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),\n dependsOn: z.array(z.string()).optional().describe(DEPENDS_ON_DESCRIPTION),\n },\n async ({\n title,\n description,\n plan,\n ordinal,\n storyPointValue,\n followParentStatus,\n dependsOn,\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 });\n return textResult(`Subtask created with ID: ${result.id} (slug: ${result.slug})`);\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 defineTool(\n \"update_subtask\",\n \"Update an existing subtask's fields (title, description, plan, ordinal, storyPointValue, dependsOn). Use when refining a child's plan, reordering, or rewiring dependencies. For the current task use update_task_plan.\",\n {\n subtaskId: z.string().describe(\"The subtask ID to update\"),\n title: z.string().optional(),\n description: z.string().optional(),\n plan: z.string().optional(),\n ordinal: z.number().optional(),\n storyPointValue: z.number().optional().describe(SP_DESCRIPTION),\n followParentStatus: z.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),\n dependsOn: z\n .array(z.string())\n .optional()\n .describe(\n `${DEPENDS_ON_DESCRIPTION} Replaces the full dependency set — pass [] to clear all, omit to leave unchanged.`,\n ),\n },\n async ({\n subtaskId,\n title,\n description,\n plan,\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 ...(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 defineTool(\n \"delete_subtask\",\n \"Delete a subtask by id. When to use: a subtask was created in error or is no longer needed. Returns: confirmation string.\",\n { subtaskId: z.string().describe(\"The subtask ID to delete\") },\n 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}\n\nfunction buildListSubtasksTool(connection: AgentConnection) {\n return defineTool(\n \"list_subtasks\",\n \"List all subtasks under the current parent task. Use to coordinate child work — check who is running, ready for review, or blocked. For non-child tasks use get_task.\",\n {},\n async () => {\n try {\n const subtasks = await connection.call(\"listSubtasks\", {\n sessionId: connection.sessionId,\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 is in Open status, has a story point value, and has an agent assigned.\",\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 return textResult(`Cloud build started for child task: ${result.childTaskId}`);\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.\",\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 defineTool(\n \"approve_and_merge_pr\",\n \"Approve and merge a child task's PR. Preconditions: child in ReviewPR. Returns { merged }: true = merged (status→ReviewDev); false = automerge queued, wait for ReviewDev.\",\n {\n childTaskId: z\n .string()\n .describe(\"The child task ID whose PR should be approved and merged\"),\n },\n 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}\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\";\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. 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 },\n async ({ title, storyPointValue, tagNames, githubPRUrl, githubBranch }) => {\n try {\n const nothingToUpdate =\n title === undefined &&\n storyPointValue === undefined &&\n tagNames === undefined &&\n githubPRUrl === undefined &&\n githubBranch === undefined;\n if (nothingToUpdate) {\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 title,\n storyPointValue,\n tagNames,\n githubPRUrl,\n githubBranch,\n });\n\n const updatedFields = [];\n if (title !== undefined) updatedFields.push(`title to \"${title}\"`);\n if (storyPointValue !== undefined)\n updatedFields.push(`story points to ${storyPointValue}`);\n if (tagNames !== undefined) updatedFields.push(`tags (${tagNames.length} tag(s))`);\n if (githubPRUrl !== undefined) updatedFields.push(`PR link to \"${githubPRUrl}\"`);\n if (githubBranch !== undefined) updatedFields.push(`branch to \"${githubBranch}\"`);\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","import { z } from \"zod\";\nimport { defineTool } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.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\nexport function buildCodeReviewTools(connection: AgentConnection) {\n return [\n defineTool(\n \"approve_code_review\",\n \"Approve the code review and exit. Use when the diff passes all review criteria. Takes only a summary — for changes, use request_code_changes with a structured issues[] list.\",\n {\n summary: z.string().describe(\"Brief summary of what was reviewed and why it looks good\"),\n },\n async ({ summary }) => {\n const content = `**Code Review: Approved** :white_check_mark:\\n\\n${summary}`;\n await connection.call(\"submitCodeReviewResult\", {\n sessionId: connection.sessionId,\n approved: true,\n content,\n });\n connection.sendEvent({\n type: \"code_review_complete\",\n result: \"approved\",\n summary,\n });\n await endReviewSession(connection, \"approved\");\n return textResult(\"Code review approved. Exiting.\");\n },\n ),\n 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 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 },\n async ({ issues, summary }) => {\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\n const content = `**Code Review: Changes Requested** :warning:\\n\\n${summary}\\n\\n${issueLines}`;\n await connection.call(\"submitCodeReviewResult\", {\n sessionId: connection.sessionId,\n approved: false,\n content,\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}\n","import type { AgentHarness, HarnessToolDefinition } from \"../harness/index.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { AgentRunnerConfig } from \"../types.js\";\nimport type { AgentMode, TaskContext } from \"@project/shared\";\nimport { buildCommonTools, buildForceUpdateTaskStatusTool } from \"./common-tools.js\";\nimport { buildPmTools, buildUpdateTaskTool } from \"./pm-tools.js\";\nimport { buildDiscoveryTools } from \"./discovery-tools.js\";\nimport { buildCodeReviewTools } 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 if (agentMode === \"discovery\" || agentMode === \"auto\") {\n return [buildUpdateTaskTool(connection)];\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// ── Tool assembly ─────────────────────────────────────────────────────\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 const discoveryTools =\n effectiveMode === \"discovery\" || effectiveMode === \"auto\"\n ? buildDiscoveryTools(connection)\n : [];\n\n // Code review tools available in review mode\n const codeReviewTools = effectiveMode === \"review\" ? buildCodeReviewTools(connection) : [];\n\n const emergencyTools = [buildForceUpdateTaskStatusTool(connection)];\n\n return [...commonTools, ...modeTools, ...discoveryTools, ...codeReviewTools, ...emergencyTools];\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 * 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\nexport interface TuiSpawnInput {\n options: HarnessQueryOptions;\n resume?: string;\n /** Per-process resources allocated by PtySession for structured-events\n * adapters only; absent otherwise. */\n settingsPath?: string;\n mcpConfigPath?: string;\n hookSocketPath?: 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 * Playwright MCP server registration for pod sessions.\n *\n * Claudespace pods bake `@playwright/mcp` + Chromium into the base image\n * (`Dockerfile.base`) so agents can drive the locally running app in a real\n * browser (`mcp__playwright__*` — see the `playwright-mcp-repro` skill). Two\n * pod-runtime constraints shape the launch flags:\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-executor.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-executor.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 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 return;\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\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 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 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 const resetsAt = handleRateLimitEvent(event as HarnessRateLimitEvent, host);\n if (resetsAt) state.rateLimitResetsAt = resetsAt;\n break;\n }\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.staleSession && { staleSession: state.staleSession }),\n ...(state.authError && { authError: state.authError }),\n };\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}): 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 return missing;\n}\n","import type { QueryHost } from \"./query-executor.js\";\nimport { collectMissingProps } from \"./task-property-utils.js\";\nimport type { ExplorationTracker, StalenessSignal } from \"./exploration-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\nfunction handleDiscoveryToolAccess(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 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\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 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 subtasks = await host.connection.call(\"listSubtasks\", {\n sessionId: host.connection.sessionId,\n });\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 host.hasExitedPlanMode = true;\n host.discoveryCompleted = true;\n // Await both the identification trigger and the confirmation chat post\n // before requesting stop. Previously these were fire-and-forget, so a\n // connection drop between the ExitPlanMode call and the stop could lose\n // either the identification event or the confirmation message, leaving\n // the agent with no visible signal that planning actually completed.\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 and agent assignment may use fallbacks.`,\n );\n }\n await host.connection.postChatMessageAwait(\n \"Planning complete — awaiting team approval. Icon and agent assignment will be set automatically.\",\n );\n // requestStop aborts the SDK event loop only after the above acks land,\n // guaranteeing the team sees a confirmation message for this session.\n // Under the PTY harness this verdict travels back to the CLI over the\n // hook socket — defer the stop a tick so the allow response is written\n // before teardown closes the socket and kills the CLI. (The CLI dies at\n // its plan-approval dialog; the session resumes cleanly on Build.)\n if (host.harnessKind === \"pty\") {\n setTimeout(() => host.requestStop(), 250);\n } else {\n host.requestStop();\n }\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 EXPLORATION_TOOLS = new Set([\"Read\", \"Grep\", \"Glob\"]);\n\nfunction trackExploration(\n tracker: ExplorationTracker,\n toolName: string,\n input: Record<string, unknown>,\n): StalenessSignal | null {\n if (!EXPLORATION_TOOLS.has(toolName)) return null;\n\n if (toolName === \"Read\") {\n const filePath = String(input.file_path ?? \"\");\n if (filePath) return tracker.recordFileRead(filePath);\n }\n\n if (toolName === \"Grep\" || toolName === \"Glob\") {\n const pattern = String(input.pattern ?? \"\");\n if (pattern) return tracker.recordSearch(pattern);\n }\n\n return null;\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\nfunction resolveToolAccess(\n host: QueryHost,\n toolName: string,\n input: Record<string, unknown>,\n): ToolResult {\n switch (host.agentMode) {\n case \"discovery\":\n return handleDiscoveryToolAccess(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 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\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 if (toolName === \"ExitPlanMode\" && host.agentMode === \"discovery\" && host.hasExitedPlanMode) {\n return {\n behavior: \"deny\" as const,\n message:\n \"Plan mode has already been exited. The team will transition you to Building mode when ready.\",\n };\n }\n\n if (toolName === \"AskUserQuestion\") {\n return await handleAskUserQuestion(host, input);\n }\n\n const result = resolveToolAccess(host, toolName, input);\n\n // Track exploration patterns during planning to detect analysis paralysis.\n // Only active when tracker exists (discovery/auto-planning) and plan mode hasn't been exited.\n if (result.behavior === \"allow\" && host.explorationTracker && !host.hasExitedPlanMode) {\n const signal = trackExploration(host.explorationTracker, toolName, input);\n if (signal) {\n host.connection.postChatMessage(signal.message);\n }\n }\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 * 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 * ExplorationTracker — detects repetitive file reads and search patterns\n * during planning-mode queries to nudge agents past analysis paralysis.\n *\n * Follows the CostTracker pattern: stateful accumulator with read-only getters.\n * Instantiated per-query in QueryBridge.buildHost() for discovery/auto-planning\n * modes only. Building/review modes set this to null on QueryHost.\n */\n\nexport type NudgeLevel = 1 | 2;\n\nexport interface StalenessSignal {\n level: NudgeLevel;\n message: string;\n}\n\n// Base thresholds (before complexity scaling)\nconst FILE_REREAD_NUDGE_L1 = 3;\nconst FILE_REREAD_NUDGE_L2 = 5;\nconst SEARCH_REPEAT_NUDGE_L1 = 3;\nconst SEARCH_REPEAT_NUDGE_L2 = 5;\nconst RATIO_MIN_READS_L1 = 10;\nconst RATIO_THRESHOLD_L1 = 0.4;\nconst RATIO_MIN_READS_L2 = 15;\nconst RATIO_THRESHOLD_L2 = 0.3;\n\nfunction normalizePath(filePath: string): string {\n // Strip leading ./ for consistent tracking\n let normalized = filePath.replace(/^\\.\\//, \"\");\n // Collapse consecutive slashes\n normalized = normalized.replace(/\\/+/g, \"/\");\n return normalized;\n}\n\nexport class ExplorationTracker {\n private fileReadCounts = new Map<string, number>();\n private searchCounts = new Map<string, number>();\n private totalReads = 0;\n private highestNudgeEmitted: NudgeLevel | 0 = 0;\n private readonly complexityMultiplier: number;\n\n constructor(isParentTask: boolean) {\n this.complexityMultiplier = isParentTask ? 1.5 : 1.0;\n }\n\n /** Record a file read and return a staleness signal if thresholds are crossed. */\n recordFileRead(filePath: string): StalenessSignal | null {\n const normalized = normalizePath(filePath);\n const count = (this.fileReadCounts.get(normalized) ?? 0) + 1;\n this.fileReadCounts.set(normalized, count);\n this.totalReads++;\n\n // Check file re-read thresholds (higher level first for priority)\n return this.checkFileRereadSignal(normalized, count) ?? this.checkExplorationRatio();\n }\n\n /** Record a search pattern and return a staleness signal if thresholds are crossed. */\n recordSearch(pattern: string): StalenessSignal | null {\n const count = (this.searchCounts.get(pattern) ?? 0) + 1;\n this.searchCounts.set(pattern, count);\n\n return this.checkSearchRepeatSignal(pattern, count);\n }\n\n private scaledThreshold(base: number): number {\n return Math.ceil(base * this.complexityMultiplier);\n }\n\n private checkFileRereadSignal(filePath: string, count: number): StalenessSignal | null {\n const l2 = this.scaledThreshold(FILE_REREAD_NUDGE_L2);\n const l1 = this.scaledThreshold(FILE_REREAD_NUDGE_L1);\n\n if (count >= l2 && this.highestNudgeEmitted < 2) {\n this.highestNudgeEmitted = 2;\n return {\n level: 2,\n message:\n `⚠️ Exploration warning: You've read \"${filePath}\" ${count} times, suggesting analysis paralysis. ` +\n `Write your plan with the context you have and call ExitPlanMode. ` +\n `If something specific is blocking you, describe the blocker in your plan.`,\n };\n }\n\n if (count >= l1 && this.highestNudgeEmitted < 1) {\n this.highestNudgeEmitted = 1;\n return {\n level: 1,\n message:\n `Exploration note: You've read \"${filePath}\" ${count} times. ` +\n `Consider whether you have enough context to start writing your plan. ` +\n `If you're still exploring, try looking at different files.`,\n };\n }\n\n return null;\n }\n\n private checkSearchRepeatSignal(pattern: string, count: number): StalenessSignal | null {\n const l2 = this.scaledThreshold(SEARCH_REPEAT_NUDGE_L2);\n const l1 = this.scaledThreshold(SEARCH_REPEAT_NUDGE_L1);\n\n // Truncate pattern for display\n const displayPattern = pattern.length > 60 ? pattern.slice(0, 57) + \"...\" : pattern;\n\n if (count >= l2 && this.highestNudgeEmitted < 2) {\n this.highestNudgeEmitted = 2;\n return {\n level: 2,\n message:\n `⚠️ Exploration warning: You've searched for \"${displayPattern}\" ${count} times. ` +\n `Repeated searches for the same pattern suggest you may be stuck. ` +\n `Proceed with the information you have.`,\n };\n }\n\n if (count >= l1 && this.highestNudgeEmitted < 1) {\n this.highestNudgeEmitted = 1;\n return {\n level: 1,\n message:\n `Exploration note: You've searched for \"${displayPattern}\" ${count} times. ` +\n `If you're not finding what you need, try a different approach or broader pattern.`,\n };\n }\n\n return null;\n }\n\n private checkExplorationRatio(): StalenessSignal | null {\n const uniqueReads = this.fileReadCounts.size;\n const ratio = this.totalReads > 0 ? uniqueReads / this.totalReads : 1;\n\n const minReadsL2 = this.scaledThreshold(RATIO_MIN_READS_L2);\n if (\n this.totalReads >= minReadsL2 &&\n ratio < RATIO_THRESHOLD_L2 &&\n this.highestNudgeEmitted < 2\n ) {\n this.highestNudgeEmitted = 2;\n return {\n level: 2,\n message:\n `⚠️ Exploration warning: Only ${Math.round(ratio * 100)}% of your ${this.totalReads} file reads are unique. ` +\n `This indicates significant re-reading. Write your plan with the context you have.`,\n };\n }\n\n const minReadsL1 = this.scaledThreshold(RATIO_MIN_READS_L1);\n if (\n this.totalReads >= minReadsL1 &&\n ratio < RATIO_THRESHOLD_L1 &&\n this.highestNudgeEmitted < 1\n ) {\n this.highestNudgeEmitted = 1;\n return {\n level: 1,\n message:\n `Exploration note: ${Math.round(ratio * 100)}% of your ${this.totalReads} file reads are unique. ` +\n `You're re-reading files more than exploring new ones. Consider starting your plan.`,\n };\n }\n\n return null;\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 runSdkQuery,\n runPassiveTurn,\n resolvePromptDelivery,\n hasExistingSessionFile,\n type QueryHost,\n} from \"../execution/query-executor.js\";\nimport { ExplorationTracker } from \"../execution/exploration-tracker.js\";\nimport type { AgentConnection } from \"../connection/agent-connection.js\";\nimport type { ModeController } from \"./mode-controller.js\";\nimport type { AgentRunnerConfig, AgentRunnerCallbacks } from \"../types.js\";\nimport type { TaskContext, AgentMode, MultimodalBlock } 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 return process.env.CONVEYOR_FORCE_SDK_CARDS === \"1\" ? \"sdk\" : \"pty\";\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): PtyBridge {\n return {\n sendOutput: (data, dims) => connection.sendPtyOutput(data, dims),\n sendChatEvent: (event) => connection.sendPtyChatEvent(event),\n sendEnded: () => connection.sendPtyEnded(),\n onInput: (handler) => connection.onPtyInput(handler),\n onResize: (handler) => connection.onPtyResize(handler),\n };\n}\n\nexport class QueryBridge {\n private readonly harness;\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 _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 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 this.harness = createHarness(\n harnessKind,\n harnessKind === \"pty\" ? buildPtyBridge(connection) : 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 * 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 * 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 }\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._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 explorationTracker:\n bridge.mode.effectiveMode === \"discovery\" ||\n (bridge.mode.effectiveMode === \"auto\" && !bridge.mode.hasExitedPlanMode)\n ? new ExplorationTracker(bridge._isParentTask)\n : null,\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 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","import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ChatMessage, TaskContextDTO } from \"@project/shared\";\n\nexport function mapChatHistory(\n messages: TaskContextDTO[\"chatHistory\"] | undefined | null,\n): ChatMessage[] {\n if (!messages) return [];\n return messages.map((m) => ({\n id: m.id,\n role: (m.role ?? \"user\") as \"user\" | \"assistant\" | \"system\",\n content: m.content ?? \"\",\n userId: m.userId,\n userName: m.user?.name ?? undefined,\n createdAt: m.createdAt,\n ...(m.files && m.files.length > 0\n ? {\n files: m.files.map((f) => ({\n fileId: f.id,\n fileName: f.fileName,\n mimeType: f.mimeType,\n fileSize: f.fileSize,\n downloadUrl: f.downloadUrl ?? \"\",\n content: f.content,\n contentEncoding: f.contentEncoding,\n })),\n }\n : {}),\n }));\n}\n\n/** Read this agent's version from its bundled package.json. */\nexport function readAgentVersion(): string | null {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n // Walk up: dist/runner/session-runner.js → dist/ → package.json\n for (const rel of [\"../package.json\", \"../../package.json\"]) {\n try {\n const pkg = JSON.parse(readFileSync(join(here, rel), \"utf-8\")) as { version?: string };\n if (pkg.version) return pkg.version;\n } catch {\n /* try next candidate */\n }\n }\n } catch {\n /* ignore */\n }\n return null;\n}\n","export 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}\n\n/**\n * Parse the plain-text output of `claude -p \"/usage\"` into the two gauge\n * numbers we store. Best-effort: any gauge that isn't present becomes null so\n * the poller can skip reporting (e.g. API-key pods have no subscription gauges).\n */\nexport function parseUsageGauges(stdout: string): UsageGauges {\n const session = stdout.match(/Current session:\\s*(\\d+(?:\\.\\d+)?)%\\s*used/i);\n const weekly = [...stdout.matchAll(/Current week[^:\\n]*:\\s*(\\d+(?:\\.\\d+)?)%\\s*used/gi)];\n return {\n sessionUsage: session ? Number(session[1]) / 100 : null,\n weeklyUsage: weekly.length ? Math.max(...weekly.map((m) => Number(m[1]))) / 100 : null,\n };\n}\n","import { spawn } from \"node:child_process\";\nimport { resolveClaudeBinary } from \"../harness/pty/spawn-args.js\";\n\nconst PROBE_TIMEOUT_MS = 15_000;\n\n/**\n * Run `<binary> -p \"/usage\"` and resolve its stdout. Best-effort: resolves an\n * empty string on spawn error, non-zero exit, or timeout — never rejects. The\n * `binary`/`args` params exist for testability; production callers use the defaults.\n */\nexport function runUsageProbe(\n binary = resolveClaudeBinary(),\n args: string[] = [\"-p\", \"/usage\"],\n): Promise<string> {\n return new Promise((resolve) => {\n let stdout = \"\";\n let settled = false;\n const finish = (out: string): void => {\n if (settled) return;\n settled = true;\n resolve(out);\n };\n\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(binary, args, { stdio: [\"ignore\", \"pipe\", \"ignore\"] });\n } catch {\n finish(\"\");\n return;\n }\n\n const timer = setTimeout(() => {\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* already gone */\n }\n finish(\"\");\n }, PROBE_TIMEOUT_MS);\n timer.unref?.();\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n stdout += d.toString();\n });\n child.on(\"error\", () => {\n clearTimeout(timer);\n finish(\"\");\n });\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n finish(code === 0 ? stdout : \"\");\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` command\n * (`claude -p \"/usage\"`, plain-text, client-side) — the authoritative,\n * account-wide gauges the CLI itself shows. Mapped into the `rate_limit_update`\n * events the API already persists (`persistRateLimitSnapshot` →\n * ClaudeSubscriptionKey.sessionUsage/weeklyUsage), which keeps User Settings,\n * the usage widget, and `selectBestKey` rotation honest.\n *\n * Best-effort: any probe/parse failure yields `[]`, never throws.\n */\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport { parseUsageGauges } 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}\n\n/**\n * Sample the current key's usage via `claude -p \"/usage\"` and map it to\n * rate-limit samples. `token` presence gates sampling: an API-key pod (no OAuth\n * subscription token) has no `/usage` gauges, so it no-ops. `probe` is\n * injectable for tests; production callers pass only `token`. Best-effort —\n * never throws.\n */\nexport async function sampleKeyUsage(\n token: string | undefined,\n probe: () => Promise<string> = runUsageProbe,\n): Promise<KeyUsageSample[]> {\n if (!token) return [];\n try {\n const stdout = await probe();\n const { sessionUsage, weeklyUsage } = parseUsageGauges(stdout);\n const samples: KeyUsageSample[] = [];\n if (sessionUsage !== null) {\n samples.push({ rateLimitType: \"five_hour\", utilization: sessionUsage, status: \"allowed\" });\n }\n if (weeklyUsage !== null) {\n samples.push({ rateLimitType: \"seven_day\", utilization: weeklyUsage, status: \"allowed\" });\n }\n if (samples.length === 0) {\n logger.info(\"usage sample produced no gauges\", { stdoutLength: stdout.length });\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","/**\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_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 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 /** 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_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) return;\n const baseline = await this.scanSafe();\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 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 }\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","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","/* 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 } from \"@project/shared\";\nimport {\n AgentConnection,\n type AgentConnectionConfig,\n type IncomingMessage,\n} from \"../connection/agent-connection.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 \"../types.js\";\nimport {\n syncWithBaseBranch,\n ensureOnTaskBranch,\n flushAllPendingWork,\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 { PortDiscovery } from \"./port-discovery.js\";\nimport { restoreOnBoot, uploadSnapshotToGcs, finalizeForSleep } from \"./work-preservation/index.js\";\nimport { handlePullBranch } from \"./parent-pull-handler.js\";\nimport { isHeavyGateActive } from \"./heavy-gate.js\";\nimport { LoopLagMonitor, type LoopStatus } from \"../connection/loop-lag.js\";\nimport { ensureClaudeCredentials, removeConveyorCredentials } from \"../harness/pty/credentials.js\";\n\n// ── Configuration ──────────────────────────────────────────────────────────\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\n/** True for the `post_to_chat` tool by either its bare name or its MCP-namespaced\n * form (`mcp__conveyor__post_to_chat`), so detection is harness-agnostic. */\nexport function isPostToChatTool(name: unknown): boolean {\n return typeof name === \"string\" && (name === \"post_to_chat\" || name.endsWith(\"__post_to_chat\"));\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 private queryBridge: QueryBridge | null = null;\n private inputResolver: ((msg: IncomingMessage | null) => void) | null = null;\n private pendingMessages: IncomingMessage[] = [];\n private prNudgeCount = 0;\n /** Set when the agent posts a substantive message to the task chat (the\n * `post_to_chat` tool) during the current turn; reset at the start of every\n * query. Read by the stuck-detection: an auto agent that finished without a\n * PR but DID explain itself / ask for help in chat is waiting on a human,\n * not silently stuck, so it is left attached rather than nudged. */\n private agentSpokeThisTurn = false;\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 portDiscovery: PortDiscovery | null = null;\n /** Main event-loop lag measurement, shared with the heartbeat worker. */\n private readonly loopLag = new LoopLagMonitor();\n\n constructor(config: SessionRunnerConfig, callbacks: SessionRunnerCallbacks) {\n this.config = config;\n this.callbacks = callbacks;\n\n // Compose components\n this.connection = new AgentConnection(config.connection);\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: () => this.connection.sendHeartbeat(this.loopLag.takeMaxLagMs()),\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 // ── 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<void> {\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 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.5. Join session room and retrieve pending messages\n const { pendingMessages: serverMessages } = await this.connection.call(\"connectAgent\", {\n sessionId: this.sessionId,\n });\n for (const msg of serverMessages) {\n if (msg.content) {\n this.pendingMessages.push({ content: msg.content, userId: msg.userId });\n }\n }\n\n // 2.55. Start the preview-port discovery poller. The baseline scan runs\n // NOW — cli.ts kicks off the setup/start commands only after connect()\n // returns, so anything already listening (sshd 2222, sidecars, agent\n // internals) lands in the baseline and is never reported. Fire-and-forget:\n // a host without /proc/net/tcp disables itself.\n this.portDiscovery = new PortDiscovery({\n report: (ports) => this.connection.reportDiscoveredPorts(ports),\n });\n void this.portDiscovery.start().catch(() => {});\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 }\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\n await this.setState(\"fetching_context\");\n try {\n const ctx = await 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 claudespace v3, entrypoint.sh runs the\n // fetch + checkout + merge in the BACKGROUND (so the card lights up before\n // git finishes) and signals completion via a marker file. Gate Claude on\n // that marker: it must never spawn on a stale branch. `awaitGitReady`\n // returns \"not-gated\" immediately when no marker is configured (GitHub\n // Codespaces / local), preserving 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 // Entrypoint sets CONVEYOR_GIT_READY=1 when bash owns the git block. For\n // GitHub Codespaces / local dev (not gated), fall through and sync here.\n // This in-line checkout/merge must run BEFORE the WIP flush timer is armed\n // (below): the flush takes .git/index.lock and force-pushes\n // conveyor-wip/<branch> with no git-ready guard of its own, so a tick\n // firing mid-`git checkout -B` / merge would contend for index.lock —\n // exactly the race the git-ready reordering was meant to prevent.\n if (process.env.CONVEYOR_GIT_READY !== \"1\") {\n if (this.fullContext?.githubBranch) {\n await ensureOnTaskBranch(this.config.workspaceDir, this.fullContext.githubBranch);\n }\n if (this.fullContext?.baseBranch) {\n await syncWithBaseBranch(this.config.workspaceDir, this.fullContext.baseBranch);\n }\n }\n\n // Git prep is confirmed ready — the gated (v3) path had its entrypoint git\n // block complete before CONVEYOR_GIT_READY=1 (the invariant awaitGitReady\n // waits on), and the non-gated in-line checkout/merge above has now\n // finished — so it is finally safe to arm the periodic WIP flush timer.\n // Starting it any earlier (e.g. in connect(), or before the block above)\n // races either entrypoint.sh's backgrounded checkout/merge or the in-line\n // sync: the flush takes .git/index.lock and force-pushes\n // conveyor-wip/<branch> with no 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 snapshotted before dying.\n // v3 pods (CONVEYOR_SNAPSHOT_URL from the bootstrap bundle) restore with\n // GCS-then-wip precedence via WorkPreservation; otherwise the wip ref\n // alone (the parent-HEAD guard makes a stale snapshot a no-op).\n if (this.fullContext?.githubBranch) {\n const snapshotUrl = process.env.CONVEYOR_SNAPSHOT_URL;\n if (snapshotUrl) {\n const restore = await restoreOnBoot(\n { snapshotUrl, gitPlan: { branch: this.fullContext.githubBranch } },\n this.config.workspaceDir,\n );\n if (restore.source !== \"clean\") {\n process.stderr.write(\n `[conveyor-agent] WorkPreservation restore: source=${restore.source}${\n restore.fileCount === undefined ? \"\" : ` files=${restore.fileCount}`\n }\\n`,\n );\n }\n } else {\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\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. If an auto task bypassed planning while still in a pre-build status\n // (i.e. it is already build-capable at boot — e.g. a plan is on the card or\n // a PR is open), advance it toward InProgress. An auto task that still\n // needs planning instead stays in read-only plan mode (not build-capable),\n // so this is skipped and the status advances later when the agent calls\n // ExitPlanMode. 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 ) {\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/prefill) — modes like discovery skip the query, so pending\n // messages must be retained for the core loop to process. A stale entry\n // whose content is NOT in the chat-history snapshot (e.g. a queued\n // 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 // 6.5. Auto-mode stuck check: if the agent finished without a PR and didn't\n // explain itself in chat, nudge it (or stay attached for a human).\n // Skip if a user message arrived during initial execution (it interrupted the query)\n if (!this.stopped && this.pendingMessages.length === 0) {\n await this.maybeHandleStuckAuto();\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 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 await this.connect();\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 // After user message execution, run the auto-mode stuck check.\n // Skip if a new message arrived during execution (it interrupted the query)\n if (!this.stopped && this.pendingMessages.length === 0) {\n await this.maybeHandleStuckAuto();\n }\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 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. Prefill (PTY task\n // chat, manual mode, fresh session) spawns the TUI for ALL modes —\n // including discovery/help, which never auto-run — with the instructions\n // pre-filled and unsubmitted for the human.\n const shouldRun =\n effectiveMode === \"building\" ||\n effectiveMode === \"auto\" ||\n effectiveMode === \"review\" ||\n 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 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 }\n if (!this.stopped) await this.setState(\"idle\");\n return true;\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 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 } else {\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 // ── 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 // Reset the per-turn \"agent communicated in chat\" signal so the\n // stuck-detection only sees post_to_chat activity from THIS turn.\n this.agentSpokeThisTurn = false;\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 this.agentSpokeThisTurn = false;\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 /** 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: 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] Periodic git flush: branchesBackedUp=${result.branchesBackedUp} worktreesSnapshotted=${result.worktreesSnapshotted}\\n`,\n );\n }\n // v3 GCS tier rides the SAME trigger as the git tier (one capture\n // cadence, two sinks — never two racing snapshotters).\n await this.uploadGcsSnapshotIfConfigured();\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 });\n }\n }\n\n /** PUT the WorkPreservation snapshot tar to the bundle's capability URL\n * when this pod is v3 (CONVEYOR_SNAPSHOT_UPLOAD_URL set). Never throws. */\n private async uploadGcsSnapshotIfConfigured(): Promise<void> {\n const uploadUrl = process.env.CONVEYOR_SNAPSHOT_UPLOAD_URL;\n if (!uploadUrl) return;\n try {\n const gcs = await uploadSnapshotToGcs(this.config.workspaceDir, uploadUrl);\n if (gcs.uploaded) {\n process.stderr.write(\n `[conveyor-agent] WorkPreservation GCS snapshot: files=${gcs.fileCount} bytes=${gcs.sizeBytes}\\n`,\n );\n }\n } catch {\n // best effort — the wip tier already preserved this generation\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. Never throws. */\n async flushGitOnShutdown(): Promise<void> {\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 // Final GCS capture so a stopping v3 pod leaves a restorable snapshot.\n await this.uploadGcsSnapshotIfConfigured();\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 }\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 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 // ── Auto-mode stuck detection & nudge ───────────────────────────────\n\n private static readonly MAX_STUCK_NUDGES = 3;\n\n /** The build-phase nudge (In Progress, no PR). Offers BOTH escape routes so\n * the agent never just goes idle. */\n private static readonly STUCK_PROMPT =\n \"You are in Auto mode, your task is still In Progress, and there is no open pull request. \" +\n \"Do ONE of these right now: (1) open a pull request with the create_pull_request tool, OR \" +\n \"(2) call post_to_chat to explain exactly where you are stuck and what you need from a human. \" +\n \"Do not finish or go idle silently.\";\n\n /** The planning-phase nudge (still Planning, identification/plan unfinished).\n * Same two-escape-route shape, aimed at finishing discovery instead of a PR. */\n private static readonly STUCK_PROMPT_PLANNING =\n \"You are in Auto mode and still in the Planning phase — identification and/or the plan are not finished. \" +\n \"Do ONE of these right now: (1) finish identifying the task (set the story points) and save the plan with the update_task_plan tool, then call ExitPlanMode to begin building, OR \" +\n \"(2) call post_to_chat to explain exactly where you are stuck and what you need from a human. \" +\n \"Do not finish or go idle silently.\";\n\n /**\n * Classify how an auto task is \"stuck\" after its turn ended (call sites run\n * post-turn, so the TUI is no longer working), or null if it isn't. Shared\n * guards: only auto, not rate-limited, under the nudge cap, and the agent\n * stayed silent this turn — if it posted to chat (explained itself / asked for\n * help) it's waiting on a human, not silently stuck.\n *\n * - \"pr\": In Progress with no open PR (build finished without shipping).\n * - \"planning\": still in a pre-build status (Planning/Open) without\n * (identified + saved plan). A fresh auto agent that finishes its plan turn\n * WITHOUT ExitPlanMode would otherwise idle → clean-exit → its session Ends\n * → the workspace is reaped \"agent_gone\" before a plan ever landed. Nudging\n * (and, on exhaustion, going dormant) keeps the session Active so the pod\n * is never prematurely slept.\n */\n private autoStuckKind(): \"pr\" | \"planning\" | null {\n if (!this.mode.isAuto || this.stopped) return null;\n if (this.queryBridge?.wasRateLimited) return null;\n if (this.prNudgeCount > SessionRunner.MAX_STUCK_NUDGES) return null;\n if (this.agentSpokeThisTurn) return null;\n if (!this.taskContext) return null;\n\n const { status, storyPointId, plan, githubPRUrl } = this.taskContext;\n if (status === \"InProgress\" && !githubPRUrl) return \"pr\";\n if (PRE_BUILD_TASK_STATUSES.has(status) && !(storyPointId !== null && !!plan?.trim())) {\n return \"planning\";\n }\n return null;\n }\n\n private isAutoStuck(): boolean {\n return this.autoStuckKind() !== null;\n }\n\n /**\n * Stop driving the agent and route the core loop into dormant idle —\n * connected and attachable, but NOT running (so no tokens are spent while it\n * waits). A human reply (chat or TUI keystroke after the next wake) resumes\n * it. This replaces the old hard `stop()`: the auto agent must never kill its\n * own session, so a person can always take over.\n */\n private enterDormantForHumanTakeover(message: string): void {\n this.connection.postChatMessage(message);\n this.completedThisTurn = true;\n void this.connection.sendHeartbeat();\n }\n\n private async refreshTaskContext(): Promise<void> {\n try {\n const ctx = await this.connection.call(\"getTaskContext\", {\n sessionId: this.sessionId,\n includeHistory: false,\n });\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 };\n // Keep fullContext in sync for PR nudge execution\n if (this.fullContext) {\n this.fullContext.status = ctx.status;\n this.fullContext.plan = ctx.plan;\n this.fullContext.githubPRUrl = ctx.githubPRUrl;\n this.fullContext.model = ctx.model;\n }\n } catch {\n // Continue with stale context\n }\n }\n\n /** Prompt + chat-message label for a stuck-nudge of the given kind. */\n private stuckNudgeContent(kind: \"pr\" | \"planning\" | null): {\n prompt: string;\n situation: string;\n } {\n if (kind === \"planning\") {\n return {\n prompt: SessionRunner.STUCK_PROMPT_PLANNING,\n situation: \"still Planning with no identified plan\",\n };\n }\n return { prompt: SessionRunner.STUCK_PROMPT, situation: \"still no PR\" };\n }\n\n private async maybeHandleStuckAuto(): Promise<void> {\n await this.refreshTaskContext();\n if (!this.isAutoStuck()) return;\n\n while (!this.stopped && !this.interrupted && this.isAutoStuck()) {\n this.prNudgeCount++;\n\n if (this.prNudgeCount > SessionRunner.MAX_STUCK_NUDGES) {\n // Out of nudges and still unfinished — DON'T shut down. Stay attached\n // and ask for a human; the agent goes dormant (not running, but still\n // connected + heartbeating) until someone replies in chat or the TUI.\n // Dormant keeps the session Active, so the workspace is never\n // agent_gone-slept out from under half-done work.\n this.enterDormantForHumanTakeover(\n `Auto-mode: I couldn't finish or get unstuck after ${SessionRunner.MAX_STUCK_NUDGES} attempts. ` +\n \"Staying connected — reply here or in the terminal and I'll keep working.\",\n );\n return;\n }\n\n // Recompute each iteration — the kind can change (e.g. Planning →\n // InProgress once the agent finishes discovery and calls ExitPlanMode).\n const { prompt, situation } = this.stuckNudgeContent(this.autoStuckKind());\n\n const attempt = this.prNudgeCount;\n const chatMsg =\n attempt === 1\n ? `Auto-nudge: ${situation} — prompting the agent to finish or explain where it's stuck...`\n : `Auto-nudge (attempt ${attempt}/${SessionRunner.MAX_STUCK_NUDGES}): ${situation} — prompting the agent again...`;\n\n this.connection.postChatMessage(chatMsg);\n await this.setState(\"running\");\n // The nudge is delivered to the live TUI via executeQuery so the agent\n // keeps working; the event lets the API/UI surface the nudge too.\n await this.callbacks.onEvent({ type: \"pr_nudge\", prompt });\n\n if (this.interrupted || this.stopped) return;\n await this.executeQuery(prompt);\n if (this.interrupted || this.stopped) return;\n\n await this.refreshTaskContext();\n\n // The agent explained itself / asked for help in chat this turn (and still\n // has no PR) → it's waiting on a human. Stop nudging and stay attached.\n if (this.agentSpokeThisTurn && !this.taskContext?.githubPRUrl) {\n this.enterDormantForHumanTakeover(\n \"Auto-mode: the agent posted an update and is waiting for input. \" +\n \"Staying connected — reply here or in the terminal to continue.\",\n );\n return;\n }\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 // Track when the agent posts a substantive message to chat this turn\n // (the `post_to_chat` MCP tool — namespaced `mcp__conveyor__post_to_chat`\n // under the PTY harness). This is the \"Chat has a recent message from\n // the Agent\" signal the stuck-detection uses; the runner's own system\n // nudges go via a different path (postChatMessage) and never appear here.\n const evt = event as { type?: string; tool?: string };\n if (evt.type === \"tool_use\" && isPostToChatTool(evt.tool)) {\n this.agentSpokeThisTurn = true;\n }\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 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(() => this.stop());\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 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 this.connection.onFinalizeSnapshot(() => void this.finalizeSnapshotNow());\n }\n\n /** Eager finalize snapshot triggered by the reconciler's sleep signal\n * (session:finalizeSnapshot). Runs a full workspace capture and uploads it\n * NOW so the sleep confirms on this snapshot instead of waiting for the\n * ~2min periodic flush. Sidecar DB state is intentionally NOT captured — it\n * is no longer durable across sleep/wake (#2623); only the agent's\n * /workspace rides the snapshot. Best-effort: on failure the\n * periodic/shutdown path stays the fallback. No-op on non-v3 pods. */\n private async finalizeSnapshotNow(): Promise<void> {\n const uploadUrl = process.env.CONVEYOR_SNAPSHOT_UPLOAD_URL;\n if (!uploadUrl || this.stopped) return;\n try {\n await finalizeForSleep({\n cwd: this.config.workspaceDir,\n branch: this.fullContext?.githubBranch ?? \"\",\n snapshotUploadUrl: uploadUrl,\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 process.stderr.write(\"[conveyor-agent] Finalize snapshot uploaded on sleep signal\\n\");\n } catch {\n // best-effort — periodic/shutdown snapshot remains the fallback\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 await updateRemoteToken(this.config.workspaceDir, res.token);\n process.env.GITHUB_TOKEN = res.token;\n process.env.GH_TOKEN = res.token;\n process.stderr.write(\"[conveyor-agent] Proactively refreshed GitHub token\\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 private async setState(status: AgentRunnerStatus): Promise<void> {\n this._state = status;\n // Mirror into the loop-lag buffer so the heartbeat worker reports the\n // runner's real status (same mapping as AgentConnection.sendHeartbeat).\n const loopStatus: LoopStatus = status === \"idle\" ? \"idle\" : \"active\";\n this.loopLag.setStatus(loopStatus);\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 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 { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { SessionPreviewPort } from \"@project/shared\";\n\nexport interface ConveyorConfig {\n setupCommand?: string;\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 readFile(join(workspaceDir, DEVCONTAINER_PATH), \"utf-8\");\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). */\nexport function loadConveyorConfig(): ConveyorConfig | null {\n const envSetup = process.env.CONVEYOR_SETUP_COMMAND;\n const envStart = process.env.CONVEYOR_START_COMMAND;\n if (envSetup || envStart) {\n return {\n setupCommand: envSetup,\n startCommand: envStart,\n };\n }\n return null;\n}\n","import { spawn, execSync, type ChildProcess } from \"node:child_process\";\n\nexport function runSetupCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Setup command exited with code ${code}`));\n }\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\nconst AUTH_TOKEN_TIMEOUT_MS = 30_000;\n\nexport function runAuthTokenCommand(cmd: string, userEmail: string, cwd: string): string | null {\n try {\n const output = execSync(`${cmd} ${JSON.stringify(userEmail)}`, {\n cwd,\n timeout: AUTH_TOKEN_TIMEOUT_MS,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n env: { ...process.env },\n });\n const token = output.toString().trim();\n return token || null;\n } catch {\n return null;\n }\n}\n\nexport function runStartCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): ChildProcess {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.unref();\n return child;\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":["sleep","path","rm","execFile","stat","promisify","git","path","execFileAsync","promisify","execFile","GIT_TIMEOUT_MS","stat","createReadStream","createWriteStream","rm","tmpdir","path","pipeline","rm","mkdtemp","mkdir","rm","tmpdir","join","path","isRecord","isUnknownArray","stringField","mapSystem","mapAssistant","writeFile","createServer","z","writeFile","join","tool","createServer","tool","z","join","writeFile","chmod","mkdir","rm","writeFile","homedir","join","join","path","mkdir","writeFile","chmod","homedir","rm","stat","isRecord","spawn","sleep","path","mkdtemp","join","tmpdir","mkdir","rm","spawn","sleep","existsSync","readFile","stat","stat","readFile","findLastAgentMessageIndex","hasNewUserMessages","parts","z","z","z","z","z","z","result","readFile","stat","join","z","z","path","join","stat","readFile","z","z","z","z","z","SP_DESCRIPTION","z","z","z","join","path","isAuthError","result","list","logger","IMAGE_ERROR_PATTERN","RETRY_DELAYS_MS","existsSync","path","isAuthError","logger","readFileSync","dirname","join","fileURLToPath","logger","readFile","execFile","path","execFile","promisify","execFileAsync","promisify","execFile","readFileSync","path","readFile","join","spawn","execSync"]}