@rallycry/conveyor-agent 8.0.0 → 8.1.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.
@@ -388,6 +388,38 @@ function buildSpawnArgs(input) {
388
388
  }
389
389
  return args;
390
390
  }
391
+ var ANSI_CSI = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`, "g");
392
+ function cleanTerminalOutput(raw, maxChars = 1200) {
393
+ const noAnsi = raw.replace(ANSI_CSI, "");
394
+ let out = "";
395
+ for (const ch of noAnsi) {
396
+ const code = ch.charCodeAt(0);
397
+ if (ch === "\r" || ch === "\n") out += "\n";
398
+ else if (ch === " ") out += ch;
399
+ else if (code < 32 || code === 127) continue;
400
+ else out += ch;
401
+ }
402
+ const lines = out.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
403
+ const text = lines.join("\n").trim();
404
+ return text.length > maxChars ? `\u2026${text.slice(-maxChars)}` : text;
405
+ }
406
+ function isMissingBinaryFailure(tail) {
407
+ return /execvp\(\d+\) failed|no such file or directory|command not found/i.test(tail);
408
+ }
409
+ function buildExitErrors(exitCode, rawOutput, binary) {
410
+ const errors = [`claude exited (code ${exitCode}) without a result`];
411
+ const tail = cleanTerminalOutput(rawOutput);
412
+ if (isMissingBinaryFailure(tail)) {
413
+ errors.push(
414
+ `The \`${binary}\` CLI could not be started \u2014 it is not installed or not on PATH. Install the Claude Code CLI in this environment (npm i -g @anthropic-ai/claude-code) or set CONVEYOR_CLAUDE_BIN to its absolute path.`
415
+ );
416
+ }
417
+ if (tail) {
418
+ errors.push(`Last terminal output before exit:
419
+ ${tail}`);
420
+ }
421
+ return errors;
422
+ }
391
423
 
392
424
  // src/harness/pty/settings.ts
393
425
  import { mkdir, writeFile, chmod } from "fs/promises";
@@ -599,6 +631,7 @@ async function startToolServers(mcpServers, tempDir) {
599
631
  }
600
632
 
601
633
  // src/harness/pty/session.ts
634
+ var MAX_DIAGNOSTIC_OUTPUT = 4e3;
602
635
  function isRecord2(value) {
603
636
  return typeof value === "object" && value !== null;
604
637
  }
@@ -647,6 +680,10 @@ var PtySession = class {
647
680
  pty = null;
648
681
  tempDir = "";
649
682
  sawResult = false;
683
+ // Rolling tail of raw PTY output, retained only to enrich the error when the
684
+ // CLI exits before emitting a result (the bytes are otherwise relayed to S5
685
+ // and never become events). Trimmed to MAX_DIAGNOSTIC_OUTPUT on every write.
686
+ recentOutput = "";
650
687
  _toreDown = false;
651
688
  exitListeners = [];
652
689
  idleListeners = [];
@@ -802,6 +839,7 @@ var PtySession = class {
802
839
  });
803
840
  pty.onData((data) => {
804
841
  this.bridge?.sendOutput(data, { cols: this.cols, rows: this.rows });
842
+ this.recentOutput = (this.recentOutput + data).slice(-MAX_DIAGNOSTIC_OUTPUT);
805
843
  });
806
844
  pty.onExit((event) => {
807
845
  void this.finalizeOnExit(event.exitCode);
@@ -844,7 +882,7 @@ var PtySession = class {
844
882
  this.queue.push({
845
883
  type: "result",
846
884
  subtype: "error",
847
- errors: [`claude exited (code ${exitCode}) without a result`]
885
+ errors: buildExitErrors(exitCode, this.recentOutput, resolveClaudeBinary())
848
886
  });
849
887
  }
850
888
  for (const listener of this.exitListeners) listener(exitCode);
@@ -916,4 +954,4 @@ export {
916
954
  createHarness,
917
955
  createServiceLogger
918
956
  };
919
- //# sourceMappingURL=chunk-3X63JL6C.js.map
957
+ //# sourceMappingURL=chunk-KTNGU2WU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../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/spawn-args.ts","../src/harness/pty/settings.ts","../src/harness/pty/tool-server.ts","../src/harness/pty/mcp-server.ts","../src/harness/pty/index.ts","../src/harness/index.ts","../src/utils/logger.ts"],"sourcesContent":["/**\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\";\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 type HarnessEvent =\n | HarnessSystemEvent\n | HarnessAssistantEvent\n | HarnessResultEvent\n | HarnessRateLimitEvent\n | HarnessToolProgressEvent;\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/* 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// ── 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 /** 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 maxBudgetUsd?: 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\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 },\n): HarnessToolDefinition {\n return {\n name,\n description,\n schema,\n handler: handler as HarnessToolDefinition[\"handler\"],\n annotations: options?.annotations,\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 * 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","/**\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, stat } 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 { HookSocketServer, type ToolProgress } from \"./hook-socket.js\";\nimport { JsonlTailer } from \"./jsonl-tailer.js\";\nimport { buildSpawnArgs, resolveClaudeBinary, buildExitErrors } from \"./spawn-args.js\";\nimport { writeHookSettings, sessionTranscriptPath } from \"./settings.js\";\nimport { PtyToolServer, startToolServers } from \"./tool-server.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.\nconst MAX_DIAGNOSTIC_OUTPUT = 4000;\n\ninterface 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\ninterface PtySpawnOptions {\n name: string;\n cols: number;\n rows: number;\n cwd: string;\n env: Record<string, string>;\n}\n\ntype 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\nasync 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 env.CONVEYOR_HOOK_SOCKET = socketPath;\n return env;\n}\n\n/** Current size of the transcript, or 0 if it does not exist yet. */\nasync function transcriptSize(path: string): Promise<number> {\n try {\n return (await stat(path)).size;\n } catch {\n return 0;\n }\n}\n\nexport class PtySession {\n private readonly queue = new AsyncEventQueue<HarnessEvent>();\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 _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\n constructor(\n private readonly prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>,\n private readonly options: HarnessQueryOptions,\n private readonly resume?: string,\n private readonly bridge?: PtyBridge,\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 get isToreDown(): boolean {\n return this._toreDown;\n }\n\n get hookSocketPath(): string | null {\n return this.socket ? this.socket.socketPath : null;\n }\n\n events(): AsyncGenerator<HarnessEvent, void> {\n return this.queue.drain();\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 // 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.options.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 this.tempDir = await mkdtemp(join(tmpdir(), \"conveyor-pty-\"));\n const socketPath = join(this.tempDir, \"hook.sock\");\n this.socket = new HookSocketServer(socketPath, (progress) => this.handleProgress(progress));\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 this.tailer = new JsonlTailer(transcriptPath, (event) => this.handleTranscriptEvent(event));\n this.tailer.start(startOffset);\n await this.spawn(settingsPath, socketPath);\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 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 async teardown(): Promise<void> {\n if (this._toreDown) return;\n this._toreDown = true;\n this.unsubInput?.();\n this.unsubInput = null;\n this.unsubResize?.();\n this.unsubResize = null;\n if (this.abortHandler) {\n this.options.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.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.queue.close();\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 args = buildSpawnArgs({\n resume: this.resume,\n sessionId: this.options.sessionId,\n model: this.options.model,\n permissionMode: this.options.permissionMode,\n settingsPath,\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, strictMcpConfig: true } : {}),\n });\n const spawn = await loadPtySpawn();\n const pty = spawn(resolveClaudeBinary(), args, {\n name: \"xterm-color\",\n cols: this.cols,\n rows: this.rows,\n cwd: this.options.cwd,\n env: inheritedEnv(socketPath),\n });\n // Mirror raw terminal output to the relay (and on to the S5 terminal). The\n // first chunk 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. Stdout is intentionally NOT turned into HarnessEvents.\n pty.onData((data) => {\n this.bridge?.sendOutput(data, { cols: this.cols, rows: this.rows });\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 feedPrompt(): Promise<void> {\n if (typeof this.prompt === \"string\") {\n this.writeStdin(`${this.prompt}\\r`);\n return;\n }\n for await (const message of this.prompt) {\n const content = message.message.content;\n const text = typeof content === \"string\" ? content : JSON.stringify(content);\n this.writeStdin(`${text}\\r`);\n }\n }\n\n private handleProgress(progress: ToolProgress): void {\n this.queue.push({\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 private handleTranscriptEvent(event: HarnessEvent): void {\n this.queue.push(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-query. Close the stream so the\n // generator completes — mirroring the SDK harness's per-query model.\n // Interactive `claude` does not exit after a result, so we must not wait\n // for process exit to terminate the event stream.\n this.queue.close();\n }\n }\n\n private async finalizeOnExit(exitCode: number): Promise<void> {\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.sawResult) {\n // Fold the swallowed terminal tail into the error so a bare exit (missing\n // `claude` binary, auth stop, unknown flag) is diagnosable from the logs\n // rather than only from the live S5 terminal.\n this.queue.push({\n type: \"result\",\n subtype: \"error\",\n errors: buildExitErrors(exitCode, this.recentOutput, resolveClaudeBinary()),\n });\n }\n for (const listener of this.exitListeners) listener(exitCode);\n this.queue.close();\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 PostToolUse progress envelopes from\n * the hook helper and surfaces them as `tool_progress` events.\n *\n * Only the newline-delimited JSON envelope is parsed (in `parseEnvelope`),\n * and malformed lines are 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 function parseEnvelope(line: string): ToolProgress | 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 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 result;\n}\n\nexport class HookSocketServer {\n private server: Server | null = null;\n private buffer = \"\";\n private _closed = false;\n\n constructor(\n public readonly socketPath: string,\n private readonly onProgress: (progress: ToolProgress) => void,\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 socket.on(\"data\", (chunk: Buffer) => {\n this.buffer += chunk.toString(\"utf8\");\n this.ingest();\n });\n }\n\n private ingest(): void {\n let index = this.buffer.indexOf(\"\\n\");\n while (index >= 0) {\n const line = this.buffer.slice(0, index);\n this.buffer = this.buffer.slice(index + 1);\n const progress = parseEnvelope(line);\n if (progress) this.onProgress(progress);\n index = this.buffer.indexOf(\"\\n\");\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\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 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>): HarnessSystemInitEvent | null {\n if (record.subtype !== \"init\") return null;\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\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 * 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 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.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// ─── 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 * 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 a PostToolUse hook that relays tool-progress\n * envelopes to a Unix socket. Writing a per-run file avoids clobbering the\n * 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 * CJS PostToolUse hook helper. Reads the hook payload from stdin, relays a\n * tool-progress envelope to the harness socket, and prints `{continue:true}`\n * so the CLI proceeds. A short fallback timer guarantees the process exits\n * even if the socket is unavailable.\n */\nconst HOOK_HELPER_SOURCE = `\"use strict\";\nconst net = require(\"node:net\");\n\nlet raw = \"\";\nprocess.stdin.setEncoding(\"utf8\");\nprocess.stdin.on(\"data\", (chunk) => {\n raw += chunk;\n});\nprocess.stdin.on(\"end\", () => {\n let toolName = \"\";\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed.tool_name === \"string\") toolName = parsed.tool_name;\n } catch {\n toolName = \"\";\n }\n relay(toolName);\n});\n\nfunction relay(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`;\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 // Auto-approve every tool call so the interactive (PTY) agent never stops to\n // prompt the viewer. This only suppresses the per-tool approval prompt — 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 // `mcp__conveyor` is listed explicitly so the agent's Conveyor tools are\n // covered even if the `*` wildcard doesn't match MCP tool names.\n permissions: {\n allow: [\"*\", \"mcp__conveyor\"],\n },\n hooks: {\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 * 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 * 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 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 type { HarnessMcpServer, HarnessToolDefinition } from \"../types.js\";\nimport { PtyMcpServer } from \"./mcp-server.js\";\n\nconst LOOPBACK = \"127.0.0.1\";\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 transport: StreamableHTTPServerTransport | null = null;\n private mcp: McpServer | null = null;\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 mcp = new McpServer({ name: this.name, version: \"1.0.0\" });\n // The SDK's `tool()` is heavily generic over the zod shape; our tool defs are\n // intentionally loose-typed (`schema: z.ZodRawShape`, handler returns MCP\n // content). Cast the registrar to a simpler shape to bridge the boundary\n // without widening to `any` — the SDK still validates input against `schema`.\n const register = mcp.tool.bind(mcp) as unknown as (\n name: string,\n description: string,\n schema: unknown,\n cb: (args: unknown) => unknown,\n ) => void;\n for (const tool of this.tools) {\n register(tool.name, tool.description, tool.schema, (args) => tool.handler(args));\n }\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomBytes(16).toString(\"hex\"),\n enableJsonResponse: true,\n });\n await mcp.connect(transport);\n\n const server = createServer((req, res) => {\n void this.handle(req, res, transport);\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 this.transport = transport;\n this.mcp = mcp;\n return { url: `http://${LOOPBACK}:${port}/mcp`, token: this.token };\n }\n\n private async handle(\n req: IncomingMessage,\n res: ServerResponse,\n transport: StreamableHTTPServerTransport,\n ): Promise<void> {\n if (req.headers.authorization !== `Bearer ${this.token}`) {\n res.writeHead(401).end();\n return;\n }\n try {\n await transport.handleRequest(req, res);\n } catch {\n if (res.headersSent) res.end();\n else res.writeHead(500).end();\n }\n }\n\n async close(): Promise<void> {\n try {\n await this.transport?.close();\n } catch {\n /* already closed */\n }\n this.transport = null;\n try {\n await this.mcp?.close();\n } catch {\n /* already closed */\n }\n this.mcp = null;\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\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\n/**\n * Start one loopback HTTP MCP server per harness tool group (in practice just\n * \"conveyor\") and write the `--mcp-config` the spawned `claude` consumes. No-op\n * (null config) when the harness was constructed without tools.\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, { type: \"http\"; url: string; headers: Record<string, string> }> = {};\n for (const [name, handle] of Object.entries(mcpServers)) {\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 * PtyHarness — drives the `claude` CLI under a pseudo-terminal behind the\n * generic `AgentHarness` interface. Selected at runtime via\n * `createHarness(\"pty\")`. As of conveyor-agent v8 this is the default for the\n * task chat path; set `CONVEYOR_HARNESS=sdk` to roll back to the SDK harness.\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\";\n\nexport { PtySession, PtyMcpServer };\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(private readonly bridge?: PtyBridge) {}\n\n async *executeQuery(opts: {\n prompt: string | AsyncGenerator<HarnessUserMessage, void, unknown>;\n options: HarnessQueryOptions;\n resume?: string;\n }): AsyncGenerator<HarnessEvent, void> {\n const session = new PtySession(\n opts.prompt,\n opts.options,\n opts.resume ?? opts.options.resume,\n this.bridge,\n );\n await session.start();\n try {\n for await (const event of session.events()) {\n yield event;\n }\n } finally {\n await session.teardown();\n }\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 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","/** 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"],"mappings":"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","names":["mkdir","join","createServer","writeFile","join","tool","tool","createServer","join","writeFile","isRecord","join","mkdir"]}