zidane 6.1.2 → 6.1.4

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.
Files changed (78) hide show
  1. package/dist/{acp-d1OjXjtH.js → acp-CO1EGSwh.js} +3 -3
  2. package/dist/{acp-d1OjXjtH.js.map → acp-CO1EGSwh.js.map} +1 -1
  3. package/dist/acp-cli.js +3 -3
  4. package/dist/acp.d.ts +1 -1
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-5mbViwQE.js → agent-CZKpBI1X.js} +3 -3
  7. package/dist/{agent-5mbViwQE.js.map → agent-CZKpBI1X.js.map} +1 -1
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/chat/pure.d.ts +3 -3
  11. package/dist/chat/pure.js +1 -1
  12. package/dist/chat.d.ts +5 -5
  13. package/dist/chat.d.ts.map +1 -1
  14. package/dist/chat.js +3 -3
  15. package/dist/contexts/daytona.d.ts +1 -1
  16. package/dist/contexts/e2b.d.ts +1 -1
  17. package/dist/{contexts-BIbcfBFH.js → contexts-A4ep-iJs.js} +2 -2
  18. package/dist/contexts-A4ep-iJs.js.map +1 -0
  19. package/dist/contexts.js +1 -1
  20. package/dist/eval.d.ts +1 -1
  21. package/dist/eval.js +1 -1
  22. package/dist/extensions.d.ts +1 -1
  23. package/dist/extensions.js +1 -1
  24. package/dist/headless.d.ts +1 -1
  25. package/dist/headless.js +2 -2
  26. package/dist/{index-C6Il4kBD.d.ts → index-DC9Iy3Vn.d.ts} +17 -2
  27. package/dist/{index-C6Il4kBD.d.ts.map → index-DC9Iy3Vn.d.ts.map} +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +4 -4
  30. package/dist/{login-DZLG__2f.js → login-DhnmYiia.js} +16 -8
  31. package/dist/{login-DZLG__2f.js.map → login-DhnmYiia.js.map} +1 -1
  32. package/dist/{mcp-CcvuVXB9.js → mcp-CkHUripi.js} +61 -4
  33. package/dist/mcp-CkHUripi.js.map +1 -0
  34. package/dist/mcp.d.ts +1 -1
  35. package/dist/mcp.js +1 -1
  36. package/dist/output/stream-json.d.ts +1 -1
  37. package/dist/output/terminal.d.ts +1 -1
  38. package/dist/presets.d.ts +1 -1
  39. package/dist/presets.js +1 -1
  40. package/dist/providers/anthropic.d.ts +1 -1
  41. package/dist/providers/arcee.d.ts +1 -1
  42. package/dist/providers/baseten.d.ts +1 -1
  43. package/dist/providers/cerebras.d.ts +1 -1
  44. package/dist/providers/local.d.ts +1 -1
  45. package/dist/providers/openai-compat.d.ts +1 -1
  46. package/dist/providers/openai.d.ts +1 -1
  47. package/dist/providers/openrouter.d.ts +1 -1
  48. package/dist/providers/xai.d.ts +1 -1
  49. package/dist/providers.d.ts +1 -1
  50. package/dist/restate.d.ts +1 -1
  51. package/dist/session/sqlite.d.ts +1 -1
  52. package/dist/session.d.ts +1 -1
  53. package/dist/skills.d.ts +1 -1
  54. package/dist/{tool-formatters-ETbcC9DM.d.ts → tool-formatters-D7AQW80Z.d.ts} +2 -2
  55. package/dist/tool-formatters-D7AQW80Z.d.ts.map +1 -0
  56. package/dist/tools/fetch-url.d.ts +1 -1
  57. package/dist/tools/web-search.d.ts +1 -1
  58. package/dist/tools.d.ts +1 -1
  59. package/dist/tools.js +1 -1
  60. package/dist/{transcript-anchors-e_30Kvk0.d.ts → transcript-anchors-ClIlrGxh.d.ts} +2 -2
  61. package/dist/{transcript-anchors-e_30Kvk0.d.ts.map → transcript-anchors-ClIlrGxh.d.ts.map} +1 -1
  62. package/dist/{transcript-anchors-DoOWooFn.js → transcript-anchors-hv97ejJn.js} +6 -4
  63. package/dist/transcript-anchors-hv97ejJn.js.map +1 -0
  64. package/dist/tui.d.ts +3 -3
  65. package/dist/tui.d.ts.map +1 -1
  66. package/dist/tui.js +298 -25
  67. package/dist/tui.js.map +1 -1
  68. package/dist/{turn-operations-CEt_l3fy.js → turn-operations-BWTB2So4.js} +32 -4
  69. package/dist/turn-operations-BWTB2So4.js.map +1 -0
  70. package/dist/{turn-operations-D-aaiUOo.d.ts → turn-operations-mvM38tP-.d.ts} +3 -3
  71. package/dist/{turn-operations-D-aaiUOo.d.ts.map → turn-operations-mvM38tP-.d.ts.map} +1 -1
  72. package/dist/types.d.ts +1 -1
  73. package/package.json +1 -1
  74. package/dist/contexts-BIbcfBFH.js.map +0 -1
  75. package/dist/mcp-CcvuVXB9.js.map +0 -1
  76. package/dist/tool-formatters-ETbcC9DM.d.ts.map +0 -1
  77. package/dist/transcript-anchors-DoOWooFn.js.map +0 -1
  78. package/dist/turn-operations-CEt_l3fy.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"contexts-BIbcfBFH.js","names":[],"sources":["../src/contexts/process.ts","../src/contexts/types.ts"],"sourcesContent":["/**\n * In-process execution context.\n *\n * Runs everything in the current Node/Bun process.\n * No isolation — fastest, used as the default.\n */\n\nimport type { Buffer } from 'node:buffer'\nimport type { ChildProcess } from 'node:child_process'\nimport type { WriteStream } from 'node:fs'\nimport type { CappedSlot } from './output-cap'\nimport type { ContextCapabilities, ExecResult, ExecutionContext, ExecutionHandle, ListFilesEntry, SpawnConfig, TaskEntry, TaskExitInfo, TaskHandle, TaskStallInfo } from './types'\nimport { createWriteStream } from 'node:fs'\nimport { mkdir, readdir, readFile, realpath, stat, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, relative, resolve } from 'node:path'\nimport { lazyAsync } from '../lazy'\nimport { globFilesLocal, globLiteralPrefix } from './glob'\nimport { appendCapped, DEFAULT_MAX_OUTPUT_BUFFER, outputExceededMessage } from './output-cap'\n\n/**\n * Lazily load `node:child_process`'s `spawn` (memoized after first use).\n *\n * Deliberately NOT a static top-level import. `createAgent` pulls this module\n * into the graph as the default execution context, so a static\n * `import … from 'node:child_process'` would make merely importing zidane\n * depend on subprocess support. Runtimes that gate that builtin at import time\n * — Supabase Edge Functions, Cloudflare `nodejs_compat`, other shell-less V8\n * isolates — would then fail to load the package at all. Deferring the import\n * to the first `exec` keeps `import 'zidane'` + the provider loop runnable\n * there; only actually invoking a shell command touches subprocess, which is\n * exactly where an unsupported host should fail (the agent loop turns that\n * throw into a clean tool-result error).\n */\nconst loadSpawn = lazyAsync(async () => (await import('node:child_process')).spawn)\n\n/**\n * Whether the host supports POSIX process groups (the `detached: true` +\n * `process.kill(-pid)` combination). Windows doesn't — its job-object\n * model is shaped differently — so on win32 we fall back to killing the\n * shell wrapper alone (matches pre-fix behavior; better than nothing).\n */\nconst SUPPORTS_PROCESS_GROUPS = process.platform !== 'win32'\n\n/**\n * Default cap on captured stdout / stderr per child. Matches the\n * pre-fix `child_process.exec` setting so existing callers see the\n * same buffer envelope. Output beyond this is truncated and a\n * marker is appended to stderr.\n */\n\n/**\n * How long `destroy()` waits for a SIGTERM'd background task to settle\n * before escalating to SIGKILL and abandoning the wait. Matches the MCP\n * connection's default `closeTimeout` so `agent.destroy()` stays bounded\n * by a single grace period regardless of which leg is slowest.\n */\nconst DESTROY_SIGTERM_GRACE_MS = 5_000\n\n/**\n * How long after the child's `exit` event we keep waiting for `close`\n * before settling with the output collected so far.\n *\n * `close` fires only once every stdio pipe has closed — and a\n * daemonized grandchild that inherited stdout/stderr (a dev server\n * started with `&`, `nohup` without redirection, simulator helpers, …)\n * keeps those pipes open indefinitely. Pre-fix, a foreground `exec`\n * whose command finished in milliseconds would hang until its timeout,\n * then `killProcessGroup` took the intentionally-backgrounded daemon\n * down with it. The process itself is done at `exit`; this grace only\n * exists to let normally-closing pipes flush their tail bytes.\n */\nconst EXIT_PIPE_DRAIN_GRACE_MS = 1_500\n\n/**\n * Sanitize a task id before it's joined into a filesystem path.\n *\n * We mint `bash_<n>` ids ourselves (no user input flows into the path\n * for `ProcessContext`), so this is defensive — but third-party contexts\n * MAY accept caller-provided ids, so the helper exists for them too.\n * Anything that doesn't match the expected shape is rejected — never\n * coerced — so the call site sees a clear error rather than a\n * traversal-shaped path.\n */\nconst TASK_ID_RE = /^[a-z][\\w-]*$/i\n\nfunction assertSafeTaskId(taskId: string): void {\n if (!TASK_ID_RE.test(taskId))\n throw new Error(`Invalid task id \"${taskId}\" — must match ${TASK_ID_RE}.`)\n}\n\n/**\n * Format `date` as `YYYYMMDD-HHMMSS-mmm` in UTC.\n *\n * Pinned to UTC so the lexical sort of two timestamps always matches\n * their chronological order (local time + DST does not). Used as the\n * per-context suffix on background-task log filenames; see the field\n * doc on `contextTimestamp` for the why.\n */\nexport function formatContextTimestamp(date: Date): string {\n const pad2 = (n: number): string => n.toString().padStart(2, '0')\n const pad3 = (n: number): string => n.toString().padStart(3, '0')\n const y = date.getUTCFullYear()\n const M = pad2(date.getUTCMonth() + 1)\n const d = pad2(date.getUTCDate())\n const h = pad2(date.getUTCHours())\n const m = pad2(date.getUTCMinutes())\n const s = pad2(date.getUTCSeconds())\n const ms = pad3(date.getUTCMilliseconds())\n return `${y}${M}${d}-${h}${m}${s}-${ms}`\n}\n\n/** Pattern of a background-task log filename. Used by tests + tooling. */\nexport const TASK_LOG_FILENAME_RE = /^(bash_\\d+)\\.(\\d{8}-\\d{6}-\\d{3})\\.log$/\n\n/** Copy only the named keys (when present) from an env object. */\nfunction pickEnv(env: NodeJS.ProcessEnv, keys: string[]): NodeJS.ProcessEnv {\n const out: NodeJS.ProcessEnv = {}\n for (const key of keys) {\n if (env[key] !== undefined)\n out[key] = env[key]\n }\n return out\n}\n\nexport function createProcessContext(config?: SpawnConfig): ExecutionContext {\n let counter = 0\n const handles = new Map<string, ExecutionHandle>()\n const defaultCwd = config?.cwd ?? process.cwd()\n const defaultEnv = config?.env\n const destroyGraceMs = config?.destroyGraceMs ?? DESTROY_SIGTERM_GRACE_MS\n\n // Base environment children inherit. Defaults to the full parent env\n // (back-compat); when `inheritEnv: false`, only a minimal allow-list is\n // forwarded so parent secrets (e.g. API keys Bun loaded from `.env`) aren't\n // exposed to tool commands. Explicit `env` / per-call env always apply on top.\n const baseEnv: NodeJS.ProcessEnv = config?.inheritEnv === false\n ? pickEnv(process.env, ['PATH', 'HOME', 'SHELL', 'LANG', 'LC_ALL', 'USER', 'TERM', 'TMPDIR'])\n : process.env\n\n // Optional workspace containment for the file methods. Unset = no checks.\n const workspaceRoot = config?.workspaceRoot !== undefined\n ? resolve(defaultCwd, config.workspaceRoot)\n : undefined\n\n /** True when `target` is the root itself or lives under it. */\n function isWithinRoot(root: string, target: string): boolean {\n const rel = relative(root, target)\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))\n }\n\n /**\n * Resolve `path` against the handle cwd and, when a `workspaceRoot` is\n * configured, reject anything that escapes it. Uses `realpath` on the\n * nearest existing ancestor so symlink escapes (and `..`) are caught for\n * both existing and not-yet-created targets.\n */\n async function resolveContained(handle: ExecutionHandle, path: string): Promise<string> {\n const full = resolve(handle.cwd, path)\n if (workspaceRoot === undefined)\n return full\n\n // Canonicalize the deepest existing ancestor to defeat symlink escapes;\n // the non-existent tail (for writes) is appended back verbatim.\n let existing = full\n const tail: string[] = []\n while (true) {\n try {\n existing = await realpath(existing)\n break\n }\n catch {\n const parent = dirname(existing)\n if (parent === existing) {\n // Reached the filesystem root without an existing ancestor.\n existing = parent\n break\n }\n // `relative` (not slice) so the segment is correct even on Windows\n // drive roots where `dirname('C:\\\\foo')` is `C:\\\\` (no 1-char sep).\n tail.unshift(relative(parent, existing))\n existing = parent\n }\n }\n const canonical = tail.length ? resolve(existing, ...tail) : existing\n const canonicalRoot = await realpath(workspaceRoot).catch(() => workspaceRoot)\n if (!isWithinRoot(canonicalRoot, canonical)) {\n throw new Error(\n `Path escapes the workspace root: ${path} (resolved outside ${canonicalRoot})`,\n )\n }\n return full\n }\n\n /**\n * Per-context background-task registry. Entries live for the context's\n * lifetime — even after the child exits — so the model can read output\n * of completed tasks until `destroy()` tears everything down. Kept as\n * a plain Map (not a class) per code-quality checklist #7: no premature\n * abstraction. The state and the operations on it live inline.\n */\n const tasks = new Map<string, TaskState>()\n let taskCounter = 0\n\n /**\n * Per-context UTC timestamp segment baked into every background task's\n * log filename. Same `taskCounter` value across two contexts (e.g. a\n * TUI restart) would otherwise re-open the SAME `bash_<n>.log` file —\n * we open with `flags: 'a'` so the new task would APPEND into the old\n * log, producing scrambled output. The timestamp guarantees each\n * context owns a distinct log filename without forcing the\n * model-facing task id (`bash_<n>`) to grow longer.\n *\n * Format: `YYYYMMDD-HHMMSS-mmm` in UTC.\n * - Sortable (lexical sort = chronological sort).\n * - Unambiguous (UTC sidesteps DST / locale shifts).\n * - Filesystem-safe (digits + hyphens only).\n * - Millisecond precision avoids same-second-restart collisions.\n *\n * The timestamp is computed once per context, NOT per task — all of a\n * context's tasks share the same suffix so a directory listing groups\n * cleanly by \"which run produced these\".\n */\n const contextTimestamp = formatContextTimestamp(new Date())\n\n /**\n * Last-resort orphan reaper. With `detached: true`, background tasks\n * are in their OWN process group — when the parent (zidane TUI) dies,\n * the OS does NOT send them SIGHUP and they keep running indefinitely.\n * The user's \"Ctrl+C the TUI\" intent is \"stop everything I started\",\n * not \"leak a `sleep 60` into the background\".\n *\n * `process.on('exit')` fires SYNCHRONOUSLY on `process.exit()` AND on\n * natural shutdown — exactly the seam we need. The handler can only\n * do synchronous work (Node ignores async), but `process.kill` IS\n * synchronous, so a SIGTERM-the-group sweep lands cleanly. The kill\n * is best-effort: already-dead children throw ESRCH (swallowed).\n *\n * Registered lazily on first `execBackground` so contexts that never\n * background a task don't pay the listener cost. Deregistered in\n * `destroy()` so reconstructed contexts don't accumulate listeners\n * (Node warns past 10 — a long-running session that switches sessions\n * frequently would otherwise hit that).\n */\n let exitHandlerRegistered = false\n const exitHandler = (): void => {\n for (const task of tasks.values()) {\n if (task.status !== 'running')\n continue\n const pid = task.child.pid\n if (pid === undefined)\n continue\n try {\n if (SUPPORTS_PROCESS_GROUPS)\n process.kill(-pid, 'SIGTERM')\n else\n process.kill(pid, 'SIGTERM')\n }\n catch {\n // ESRCH (already dead) / EPERM (lost ownership). Swallow —\n // the process either won't kill cleanly OR is already gone,\n // both acceptable at shutdown.\n }\n }\n }\n\n return {\n type: 'process',\n\n capabilities: {\n shell: true,\n filesystem: true,\n glob: true,\n network: true,\n gpu: false,\n // Background tasks are OS children of this process's machine —\n // they survive `agent.destroy()` reassignment games but NOT a\n // host machine reboot, and the orphan reaper kills them on\n // process exit. That's the 'process-lifetime' tier.\n detachedTasks: 'process-lifetime',\n } satisfies ContextCapabilities,\n\n async spawn(overrides?: SpawnConfig): Promise<ExecutionHandle> {\n const id = `process-${++counter}`\n const cwd = overrides?.cwd ?? defaultCwd\n\n // Only create `cwd` when it is genuinely missing. An unconditional\n // `mkdir(cwd, { recursive: true })` on an already-existing directory is a\n // wasted write that needlessly demands FS-write permission — which breaks\n // read-only / no-write runtimes (Supabase Edge Functions write only to\n // `/tmp`; Deno edge isolates) where the cwd already exists. `stat` is a\n // read (permitted there); the write is attempted only on a confirmed\n // ENOENT. Any other stat failure (e.g. EACCES on a sandbox-restricted\n // path) must NOT escalate to a mkdir we'd also be denied — assume present\n // and let a later file op surface a precise error if it truly isn't.\n let needsCreate = false\n try {\n await stat(cwd)\n }\n catch (err) {\n needsCreate = (err as NodeJS.ErrnoException)?.code === 'ENOENT'\n }\n if (needsCreate)\n await mkdir(cwd, { recursive: true })\n\n const handle: ExecutionHandle = { id, type: 'process', cwd }\n handles.set(id, handle)\n return handle\n },\n\n async exec(\n handle: ExecutionHandle,\n command: string,\n options?: { cwd?: string, env?: Record<string, string>, timeout?: number, signal?: AbortSignal },\n ): Promise<ExecResult> {\n const cwd = options?.cwd ? resolve(handle.cwd, options.cwd) : handle.cwd\n\n // Pre-aborted fast path: skip the spawn entirely and synthesize a\n // killed-by-signal result. Saves a spawn round-trip + dodges Node\n // emitting an immediate `AbortError`.\n if (options?.signal?.aborted) {\n return { stdout: '', stderr: 'aborted by signal before spawn', exitCode: 143 }\n }\n\n const timeoutMs = (options?.timeout ?? config?.limits?.timeout ?? 30) * 1000\n const maxBuffer = DEFAULT_MAX_OUTPUT_BUFFER\n\n // Lazy subprocess load (see `loadSpawn`) — awaited before the Promise\n // executor so the spawn primitive is ready synchronously inside it.\n const spawnChild = await loadSpawn()\n\n return new Promise<ExecResult>((resolveP) => {\n // Spawn as a NEW process group leader so we can kill the whole\n // subtree on abort. Without `detached: true`, sending SIGTERM to\n // the shell's pid only kills the shell wrapper — its child\n // processes (the actual `sleep`, `npm`, `python`, …) get\n // reparented to init and keep running. `process.kill(-pid, …)`\n // with a NEGATIVE pid targets the whole process group; that's\n // the POSIX idiom for \"shut down everything I started\".\n //\n // On Windows there are no process groups in the POSIX sense, so\n // we leave `detached` off and accept the shell-only kill — the\n // platform's job-object machinery is the path forward there if\n // we ever need it, but it's not the bug zidane's users are\n // hitting today.\n const child = spawnChild('/bin/sh', ['-c', command], {\n cwd,\n env: { ...baseEnv, ...defaultEnv, ...options?.env },\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: SUPPORTS_PROCESS_GROUPS,\n })\n\n // Byte-capped accumulation via the shared exec-transport primitive\n // (see contexts/output-cap.ts) — byte accounting + codepoint-safe\n // cuts. Overflow orchestration (kill the process group, matching\n // `execAsync`'s maxBuffer behavior) stays here.\n const stdoutSlot: CappedSlot = { text: '', bytes: 0 }\n const stderrSlot: CappedSlot = { text: '', bytes: 0 }\n let bufferTruncated = false\n let timedOut = false\n let killedByAbort = false\n let settled = false\n\n const onChunk = (slot: CappedSlot, chunk: Buffer): void => {\n const outcome = appendCapped(slot, chunk, maxBuffer)\n if (outcome !== 'ok' && !bufferTruncated) {\n bufferTruncated = true\n killProcessGroup(child, 'SIGTERM')\n }\n }\n\n child.stdout?.on('data', chunk => onChunk(stdoutSlot, chunk as Buffer))\n child.stderr?.on('data', chunk => onChunk(stderrSlot, chunk as Buffer))\n\n const timeoutTimer = timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true\n killProcessGroup(child, 'SIGTERM')\n }, timeoutMs)\n : undefined\n\n const onAbort = (): void => {\n killedByAbort = true\n killProcessGroup(child, 'SIGTERM')\n }\n const userSignal = options?.signal\n if (userSignal)\n userSignal.addEventListener('abort', onAbort, { once: true })\n\n let exitGraceTimer: NodeJS.Timeout | undefined\n\n const settle = (exitCode: number, extraStderr?: string): void => {\n if (settled)\n return\n settled = true\n if (timeoutTimer)\n clearTimeout(timeoutTimer)\n if (exitGraceTimer)\n clearTimeout(exitGraceTimer)\n if (userSignal)\n userSignal.removeEventListener('abort', onAbort)\n const finalStderr = extraStderr\n ? (stderrSlot.text ? `${stderrSlot.text}\\n${extraStderr}` : extraStderr)\n : stderrSlot.text\n resolveP({ stdout: stdoutSlot.text, stderr: finalStderr, exitCode })\n }\n\n // Shared classification ladder for `close` (fast path: pipes\n // drained normally) and the post-`exit` grace (pipes held open\n // by a daemonized grandchild). Order matters: killed-by-our-\n // abort wins over timeout wins over natural exit, because the\n // abort listener fires first when the user cancels mid-\n // timeout-window.\n const settleFromStatus = (code: number | null, signal: NodeJS.Signals | null): void => {\n if (killedByAbort) {\n settle(143, 'aborted by signal')\n return\n }\n if (timedOut) {\n settle(124, `command timed out after ${timeoutMs}ms`)\n return\n }\n if (bufferTruncated) {\n settle(143, outputExceededMessage(maxBuffer, 'process killed'))\n return\n }\n if (signal) {\n // Killed by some other signal we didn't issue. Treat as\n // signal-killed for consumer compat.\n settle(128 + 15, `terminated by signal ${signal}`)\n return\n }\n settle(typeof code === 'number' ? code : 1)\n }\n\n child.on('error', (err) => {\n // Spawn failure (ENOENT on `/bin/sh`, EACCES, …). Mirror\n // `execAsync`'s \"rejects with an Error\" shape by surfacing\n // the message on stderr and a non-zero exit.\n settle(1, err.message)\n })\n\n child.on('close', (code, signal) => settleFromStatus(code, signal))\n\n child.on('exit', (code, signal) => {\n // The command is DONE here — `close` only adds \"every stdio\n // pipe closed\", which a daemonized grandchild can block\n // forever (see EXIT_PIPE_DRAIN_GRACE_MS). Give the pipes a\n // short drain grace, then settle with what we have and\n // release them. The daemon keeps running — that was the\n // command's intent; killing the group here would be wrong.\n exitGraceTimer = setTimeout(() => {\n if (settled)\n return\n child.stdout?.destroy()\n child.stderr?.destroy()\n settleFromStatus(code, signal)\n }, EXIT_PIPE_DRAIN_GRACE_MS)\n exitGraceTimer.unref?.()\n })\n })\n },\n\n async readFile(handle: ExecutionHandle, path: string): Promise<string> {\n return readFile(await resolveContained(handle, path), 'utf-8')\n },\n\n async fileSize(handle: ExecutionHandle, path: string): Promise<number | null> {\n try {\n // Same containment as every other file method. `stat` (NOT lstat):\n // the caller wants the TARGET's size — an lstat of a symlink\n // reports the link itself and a link to a 10GB file would sail\n // past the whole-read guard this probe exists to feed.\n const info = await stat(await resolveContained(handle, path))\n return info.isFile() ? info.size : null\n }\n catch {\n return null\n }\n },\n\n async readFileBinary(handle: ExecutionHandle, path: string): Promise<Uint8Array> {\n // No encoding → returns a Buffer (which is a Uint8Array). Used by\n // read_file to ferry image / binary content into the multimodal route.\n const buf = await readFile(await resolveContained(handle, path))\n return new Uint8Array(buf)\n },\n\n async writeFile(handle: ExecutionHandle, path: string, content: string): Promise<void> {\n const fullPath = await resolveContained(handle, path)\n await mkdir(dirname(fullPath), { recursive: true })\n await writeFile(fullPath, content, 'utf-8')\n },\n\n async listFiles(handle: ExecutionHandle, path: string, options): Promise<ListFilesEntry[]> {\n if (options?.glob) {\n await resolveContained(handle, globLiteralPrefix(path) || '.')\n const entries = await globFilesLocal(path, handle.cwd, {\n limit: options?.limit ?? 1000,\n metadata: options?.metadata,\n gitignore: options?.gitignore,\n signal: options?.signal,\n })\n if (workspaceRoot === undefined)\n return entries\n const contained: ListFilesEntry[] = []\n for (const entry of entries) {\n try {\n await resolveContained(handle, entry.path)\n contained.push(entry)\n }\n catch {\n // Symlink escapes can be discovered by broad globs like `**/*`.\n // Keep the process context's workspaceRoot invariant by filtering\n // them exactly as read/write paths are filtered.\n }\n }\n return contained\n }\n // Literal listing — suffix directories with `/` so consumers (the\n // `list_files` tool, path suggestions) can tell files from dirs\n // without a second probe. Mirrors `ls -p` in the docker context.\n const dirents = await readdir(await resolveContained(handle, path), { withFileTypes: true })\n return dirents.map(d => (d.isDirectory() ? `${d.name}/` : d.name))\n },\n\n async execBackground(\n handle: ExecutionHandle,\n command: string,\n options: {\n cwd?: string\n env?: Record<string, string>\n outputDir: string\n onExit?: (info: TaskExitInfo) => void\n maxOutputBytes?: number\n stallTimeoutMs?: number\n onStall?: (info: TaskStallInfo) => void\n },\n ): Promise<TaskHandle> {\n const cwd = options.cwd ? resolve(handle.cwd, options.cwd) : handle.cwd\n\n // Resolve the subprocess primitive up front (see `loadSpawn`) so a runtime\n // without `node:child_process` fails BEFORE we allocate the log dir +\n // output stream — no orphaned fd / log file on an unsupported host.\n const spawnChild = await loadSpawn()\n\n await mkdir(options.outputDir, { recursive: true })\n\n // Mint id + path. The id is sequential per context (model-facing,\n // short, ergonomic for `shell_kill`). The log FILENAME embeds the\n // context's start timestamp so two contexts sharing an `outputDir`\n // (TUI restart on the same session, concurrent zidane instances,\n // …) never resolve to the same file — we open with `flags: 'a'`\n // and a name collision would interleave their output. Path\n // validation is defensive — we mint our own ids so it never trips\n // today, but it pins the invariant for forks / third parties.\n const taskId = `bash_${++taskCounter}`\n assertSafeTaskId(taskId)\n const outputPath = resolve(options.outputDir, `${taskId}.${contextTimestamp}.log`)\n\n // Install the orphan reaper on first task. See `exitHandler`'s\n // JSDoc for the kill-on-shutdown rationale.\n if (!exitHandlerRegistered) {\n process.on('exit', exitHandler)\n exitHandlerRegistered = true\n }\n\n // Open the output file. The timestamped path is unique per context\n // so a brand-new file is the expected outcome; `flags: 'a'` is kept\n // as the safe default (preserves bytes if the path collides for any\n // reason — same-millisecond context creation, manual pre-population,\n // etc.) rather than blindly truncating. Streams are opened BEFORE\n // the spawn to avoid a race where the child writes before the stream\n // is ready — `child_process` buffers stdio until the consumer\n // attaches, but the FS handle has to exist either way for our pipe.\n const outputStream: WriteStream = createWriteStream(outputPath, { flags: 'a' })\n // Surface FS errors (ENOSPC, EACCES on a remounted FS, etc.)\n // under ZIDANE_DEBUG instead of crashing the host via an\n // unhandled 'error' event. Without a listener Node escalates\n // any stream-level error to an uncaughtException and the whole\n // process exits — the model and the user would lose every\n // unrelated in-flight piece of work to one bad task's disk\n // hiccup. Swallow + log is the safer default for a fire-and-\n // forget log writer; the task's exit code still reports.\n outputStream.on('error', (err) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/contexts] task ${taskId} log stream error: ${err.message}\\n`)\n })\n\n // Spawn as a NEW process group leader so we can kill the whole\n // subtree on demand. Same primitive `exec` uses for foreground\n // shells — see the long comment in that method for the\n // process-group rationale.\n const child = spawnChild('/bin/sh', ['-c', command], {\n cwd,\n env: { ...baseEnv, ...defaultEnv, ...options.env },\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: SUPPORTS_PROCESS_GROUPS,\n })\n\n const state: TaskState = {\n taskId,\n handleId: handle.id,\n pid: child.pid ?? -1,\n command,\n cwd,\n startedAt: Date.now(),\n outputPath,\n outputStream,\n child,\n status: 'running',\n bytesWritten: 0,\n settled: false,\n onExit: options.onExit,\n }\n tasks.set(taskId, state)\n\n // Output cap (optional). Beyond the cap the process keeps\n // running — head-priority retention: bytes already on disk stay,\n // subsequent bytes are counted but dropped, and a structured\n // truncation marker is appended at settle so the model can\n // pattern-match the loss. Killing on overflow (what the\n // foreground `exec` does) would be wrong here: long-running\n // servers legitimately log forever.\n const maxOutputBytes = typeof options.maxOutputBytes === 'number' && options.maxOutputBytes > 0\n ? options.maxOutputBytes\n : undefined\n let droppedBytes = 0\n // Latched on the first overflowing chunk. Without it, a codepoint-\n // boundary backoff (below) leaves a few bytes of \"room\" that later\n // chunks would dribble into — appending disjoint fragments from\n // much-later output right after the cut point.\n let capExhausted = false\n\n // Stall watchdog (optional). One-shot per quiet period: fires\n // `onStall` after `stallTimeoutMs` of no output, then stays quiet\n // until fresh output re-arms it. `unref()` so a pending timer\n // never holds the host process open.\n const stallTimeoutMs = typeof options.stallTimeoutMs === 'number' && options.stallTimeoutMs > 0\n ? options.stallTimeoutMs\n : undefined\n const onStall = options.onStall\n let stallTimer: NodeJS.Timeout | undefined\n let lastOutputAt = Date.now()\n const armStallTimer = (): void => {\n if (!stallTimeoutMs || !onStall)\n return\n if (stallTimer)\n clearTimeout(stallTimer)\n stallTimer = setTimeout(() => {\n stallTimer = undefined\n if (state.settled)\n return\n try {\n onStall({\n taskId,\n command,\n outputPath,\n stalledForMs: Date.now() - lastOutputAt,\n bytesWritten: state.bytesWritten,\n })\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/contexts] task ${taskId} onStall threw: ${err instanceof Error ? err.message : String(err)}\\n`)\n }\n }, stallTimeoutMs)\n stallTimer.unref?.()\n }\n const clearStallTimer = (): void => {\n if (stallTimer) {\n clearTimeout(stallTimer)\n stallTimer = undefined\n }\n }\n armStallTimer()\n\n // Pipe both streams into the same file. Order between stdout and\n // stderr is preserved per-stream; cross-stream ordering depends on\n // Node's event loop — acceptable interleaving for log-shaped\n // output. Tracked-bytes is updated on every chunk for the\n // listBackground UX (counted even past the cap, so the UX shows\n // the task's TRUE output volume).\n const appendChunk = (chunk: Buffer): void => {\n state.bytesWritten += chunk.length\n lastOutputAt = Date.now()\n armStallTimer()\n if (maxOutputBytes !== undefined) {\n const onDisk = state.bytesWritten - droppedBytes - chunk.length\n if (capExhausted || onDisk >= maxOutputBytes) {\n capExhausted = true\n droppedBytes += chunk.length\n return\n }\n const room = maxOutputBytes - onDisk\n if (chunk.length > room) {\n capExhausted = true\n // Cut on a UTF-8 codepoint boundary, same as the foreground\n // exec cap: back off while the byte after the cut is a\n // continuation byte (0b10xxxxxx) so the log never ends in a\n // mangled half-codepoint right before the truncation marker.\n let end = room\n while (end > 0 && (chunk[end] & 0xC0) === 0x80)\n end--\n droppedBytes += chunk.length - end\n if (end > 0)\n outputStream.write(chunk.subarray(0, end))\n return\n }\n }\n outputStream.write(chunk)\n }\n child.stdout?.on('data', chunk => appendChunk(chunk as Buffer))\n child.stderr?.on('data', chunk => appendChunk(chunk as Buffer))\n\n // Settle path — at-most-once via `settled` flag (checklist #14).\n // Three trigger sources: `close` (natural OR signal-killed),\n // `error` (spawn failure), explicit `killBackground` (which\n // routes through `close` itself after the SIGTERM lands).\n const settle = (cause: 'close' | 'error', code: number | null, signal: NodeJS.Signals | null, errMessage?: string): void => {\n if (state.settled)\n return\n state.settled = true\n clearStallTimer()\n state.endedAt = Date.now()\n\n // Determine final status from cause + signal.\n const status: TaskExitInfo['status']\n = signal === 'SIGTERM' || state.killRequested\n ? 'killed'\n : 'exited'\n // Signal-killed children report null `code` from Node; map back\n // to the POSIX `128 + signum` convention so consumers can read\n // an integer either way.\n const exitCode = code !== null\n ? code\n : signal === 'SIGTERM'\n ? 143\n : signal\n ? 128\n : 1\n state.status = status\n state.exitCode = exitCode\n if (signal)\n state.signal = signal\n\n // Flush + close the WriteStream BEFORE firing onExit — model\n // may read the file in the same turn it receives the\n // notification, and a still-open stream can hold tail bytes\n // back from disk. `stream.end(callback)` is the documented\n // \"all queued writes are flushed when this fires\" idiom.\n //\n // ORDER MATTERS: any error preamble we want in the log file\n // (spawn failures with no stdout, buffer overflows) MUST be\n // written BEFORE `end()` — once `end()` is called the stream\n // is closed for writing and subsequent `.write()` calls are\n // dropped. Earlier revisions had this reversed and silently\n // lost ENOENT-on-`/bin/sh` messages.\n if (errMessage) {\n try {\n outputStream.write(`\\n${errMessage}\\n`)\n }\n catch {\n // Stream may have errored before this — best-effort only.\n }\n }\n if (droppedBytes > 0) {\n try {\n // Structured + loud — the model can pattern-match the tag\n // rather than misread a truncated log as the full output.\n outputStream.write(`\\n<output-truncated bytes-dropped=\"${droppedBytes}\"/>\\n`)\n }\n catch {\n // Best-effort only, same as the error preamble above.\n }\n }\n outputStream.end(() => {\n // `stateToTaskExitInfo` reads the same fields we just set\n // on `state`, so the snapshot the consumer gets matches the\n // post-settle state exactly. `onExit` is optional — pull-based\n // consumers reconcile via `listBackground` instead.\n try {\n state.onExit?.(stateToTaskExitInfo(state))\n }\n catch (err) {\n // Defensive — a buggy onExit callback shouldn't crash the\n // host. Surface via stderr under ZIDANE_DEBUG; otherwise\n // swallow. Matches the spawn-tool's bubbleError pattern.\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/contexts] task ${taskId} onExit threw: ${err instanceof Error ? err.message : String(err)}\\n`)\n }\n })\n }\n\n child.on('close', (code, signal) => settle('close', code, signal))\n child.on('error', err => settle('error', null, null, `[spawn error] ${err.message}`))\n\n child.on('exit', (code, signal) => {\n // Same pipe-hostage hazard as foreground `exec`: a grandchild\n // that inherited the pipes blocks `close` forever, leaving the\n // task `running` (and any waiter parked) long after the\n // command exited. Settle after a short drain grace; `settle`'s\n // latch makes this a no-op when `close` already fired.\n const exitGraceTimer = setTimeout(() => {\n if (state.settled)\n return\n child.stdout?.destroy()\n child.stderr?.destroy()\n settle('close', code, signal)\n }, EXIT_PIPE_DRAIN_GRACE_MS)\n exitGraceTimer.unref?.()\n })\n\n return { taskId, pid: state.pid, outputPath }\n },\n\n async killBackground(handle: ExecutionHandle, taskId: string): Promise<TaskExitInfo | null> {\n const state = tasks.get(taskId)\n // Two miss cases collapse into one `null` return: unknown id, AND\n // known-id-but-not-owned-by-this-handle. The second case is the\n // subagent-can't-kill-parent-tasks defense; surfacing it as a\n // distinct error would leak the existence of the parent's task\n // to the subagent's model, which violates the per-handle\n // isolation contract.\n if (!state || state.handleId !== handle.id)\n return null\n // Already exited — return the cached info. We don't keep a\n // separate cached exit; the state itself carries every field\n // `TaskExitInfo` needs and `stateToTaskExitInfo` projects it.\n if (state.status !== 'running')\n return stateToTaskExitInfo(state)\n\n // Mark the intent BEFORE issuing the kill so the close handler\n // classifies the exit as `'killed'` even on platforms where the\n // SIGTERM-via-group lands faster than the close event drains.\n // (Checklist #14: at-most-once settle, plus correct status\n // classification regardless of event ordering.)\n state.killRequested = true\n\n // Wait for the existing close listener to fire — `settle()` does\n // all the flushing + onExit work. We just sit on a one-shot\n // promise tied to the `child.on('close')` we already registered\n // at spawn time.\n const closed = new Promise<void>((resolveP) => {\n if (state.settled) {\n resolveP()\n return\n }\n const originalOnExit = state.onExit\n state.onExit = (info) => {\n originalOnExit?.(info)\n resolveP()\n }\n })\n\n killProcessGroup(state.child, 'SIGTERM')\n await closed\n return stateToTaskExitInfo(state)\n },\n\n async waitBackground(\n handle: ExecutionHandle,\n taskId: string,\n options?: { timeoutMs?: number, signal?: AbortSignal },\n ): Promise<TaskExitInfo | null> {\n const state = tasks.get(taskId)\n // Same two-misses-collapse-to-null contract as `killBackground`:\n // unknown id AND known-but-other-handle both return `null` so a\n // subagent can't observe the parent's tasks through the wait seam.\n if (!state || state.handleId !== handle.id)\n return null\n if (state.settled)\n return stateToTaskExitInfo(state)\n\n return new Promise<TaskExitInfo | null>((resolveP) => {\n let done = false\n let timer: NodeJS.Timeout | undefined\n const signal = options?.signal\n const finish = (value: TaskExitInfo | null): void => {\n if (done)\n return\n done = true\n if (timer)\n clearTimeout(timer)\n signal?.removeEventListener('abort', onAbort)\n resolveP(value)\n }\n function onAbort(): void {\n finish(null)\n }\n\n // Chain onto the live exit callback rather than replacing it —\n // the original (notification enqueue, kill-waiter, a sibling\n // waiter) must keep firing. The `done` latch makes a late exit\n // after timeout a no-op for THIS waiter.\n const originalOnExit = state.onExit\n state.onExit = (info) => {\n originalOnExit?.(info)\n finish(stateToTaskExitInfo(state))\n }\n\n if (signal) {\n if (signal.aborted) {\n finish(null)\n return\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }\n const timeoutMs = options?.timeoutMs\n if (typeof timeoutMs === 'number' && Number.isFinite(timeoutMs) && timeoutMs > 0) {\n timer = setTimeout(finish, timeoutMs, null)\n timer.unref?.()\n }\n })\n },\n\n async reassignBackgroundTasks(\n fromHandle: ExecutionHandle,\n toHandle: ExecutionHandle,\n newOnExit?: (info: TaskExitInfo) => void,\n ): Promise<readonly TaskEntry[]> {\n // No-op when source = destination — keeps the spawn.ts call site\n // unconditional without forcing it to dedupe.\n if (fromHandle.id === toHandle.id)\n return []\n const promoted: TaskEntry[] = []\n for (const state of tasks.values()) {\n if (state.handleId !== fromHandle.id || state.status !== 'running')\n continue\n state.handleId = toHandle.id\n // Replace the natural-exit callback. The original closed over\n // the spawning agent's hook bus, which is about to be destroyed\n // — without rewiring, the task's eventual `background:exit`\n // fires into a torn-down hookable and the parent never learns.\n if (newOnExit)\n state.onExit = newOnExit\n promoted.push(stateToTaskEntry(state))\n }\n return promoted\n },\n\n async listBackground(handle: ExecutionHandle): Promise<readonly TaskEntry[]> {\n // Snapshot — callers must not assume the returned array stays\n // in sync with the live registry. Sorted by startedAt so the\n // model / UI sees consistent ordering across calls. Scoped to\n // the calling handle so subagents don't see the parent's tasks\n // (and vice versa) in their listing.\n return [...tasks.values()]\n .filter(s => s.handleId === handle.id)\n .sort((a, b) => a.startedAt - b.startedAt)\n .map(stateToTaskEntry)\n },\n\n async destroy(handle: ExecutionHandle): Promise<void> {\n // Kill every still-running background task SPAWNED THROUGH THIS\n // HANDLE before tearing the handle down. SIGTERM the groups,\n // await the close + flush, THEN drop the registry entries.\n // Sequential — destroy is one-shot teardown, the few ms of extra\n // latency aren't worth the synchronization complexity.\n //\n // The handle scope matters when the same `ExecutionContext` is\n // shared across a parent agent and its `spawn`-ed subagents (the\n // default — `spawn.ts` passes `execution: ctx.execution`). Each\n // agent mints its own `ExecutionHandle` and registers its\n // background tasks under that handle's id. Without the filter,\n // a child agent's `destroy()` (fired by `spawn.ts`'s `finally`\n // when the subagent finishes / is cancelled) would walk the\n // shared registry and SIGTERM the parent's tasks too. So\n // cancelling a subagent that has its own background shells now\n // correctly kills JUST those subagent shells, leaving the\n // parent's intact.\n const survivors = [...tasks.values()].filter(s => s.handleId === handle.id && !s.settled)\n await Promise.all(survivors.map(async (state) => {\n state.killRequested = true\n await new Promise<void>((resolveP) => {\n let graceTimer: NodeJS.Timeout | undefined\n const originalOnExit = state.onExit\n state.onExit = (info) => {\n originalOnExit?.(info)\n if (graceTimer)\n clearTimeout(graceTimer)\n resolveP()\n }\n killProcessGroup(state.child, 'SIGTERM')\n // Bounded drain: a task that traps/ignores SIGTERM — or whose\n // `close` event is held back by an escaped grandchild (setsid'd\n // out of the process group) keeping the inherited stdio pipe\n // open — must not wedge `agent.destroy()` forever. After the\n // grace period, SIGKILL the group and stop waiting: `close`\n // may STILL never fire (the pipe holder isn't in the group),\n // so resolving here is the only way destroy() stays bounded.\n graceTimer = setTimeout(() => {\n killProcessGroup(state.child, 'SIGKILL')\n // settle() normally flushes + ends the log stream, but it\n // only runs off `close` — which we just gave up on. Tear the\n // stream down so the fd doesn't leak into a long-lived host.\n state.outputStream.destroy()\n resolveP()\n }, destroyGraceMs)\n graceTimer.unref?.()\n })\n }))\n // Drop only this handle's tasks from the registry. Other handles\n // (siblings, parent) keep their entries.\n for (const [taskId, state] of tasks) {\n if (state.handleId === handle.id)\n tasks.delete(taskId)\n }\n handles.delete(handle.id)\n // Drop the orphan reaper ONLY when no handles remain — otherwise\n // a child's `destroy()` would strip the parent's safety net. The\n // reaper protects every still-tracked task in the context, so it\n // sticks around until the LAST handle is gone.\n //\n // Without this guard, the spawn-tool sequence\n // parent.spawn(child) → child.run() → child.destroy() (auto)\n // would deregister the handler mid-parent-lifetime. The parent's\n // own subsequent Ctrl+C orphan-kill safety would silently degrade.\n if (exitHandlerRegistered && handles.size === 0) {\n process.off('exit', exitHandler)\n exitHandlerRegistered = false\n }\n },\n }\n}\n\n/**\n * Per-task state. Lives in the context's `tasks` registry. Fields are\n * mutated in place by the spawn / close / kill / destroy code paths —\n * the registry isn't immutable. Treat the type as a record-of-cells,\n * not a value.\n */\ninterface TaskState {\n taskId: string\n /**\n * `ExecutionHandle.id` of the spawning agent. The registry is\n * context-scoped (one Map shared across all handles a context minted),\n * so a per-task owner tag is what scopes `listBackground` /\n * `killBackground` / `destroy` to the calling handle's slice.\n *\n * Without this, a subagent spawned via `spawn` tool — which inherits\n * the parent's `ExecutionContext` but mints its OWN handle — would\n * see (and accidentally kill on `destroy()`) every task the parent\n * had running. Came up the first time the model spawned a subagent\n * that ran a background task: the subagent's run-end `destroy()`\n * SIGTERMed the parent's `npm run dev` mid-flight.\n */\n handleId: string\n pid: number\n command: string\n cwd: string\n startedAt: number\n outputPath: string\n outputStream: WriteStream\n child: ChildProcess\n status: 'running' | 'exited' | 'killed'\n exitCode?: number\n signal?: NodeJS.Signals\n bytesWritten: number\n /**\n * `at-most-once` settle latch. Multiple trigger sources (`close`,\n * `error`, `kill`) can race; the flag dedupes so `onExit` fires\n * exactly once per task (checklist #14).\n */\n settled: boolean\n /**\n * Set by `killBackground` / `destroy` before issuing SIGTERM so the\n * close handler classifies the exit as `'killed'` even when the\n * platform delivers the close event ahead of our intent record.\n */\n killRequested?: boolean\n /**\n * `Date.now()` at settle time. Lets `durationMs` (and pull-based\n * reconcile consumers reading `TaskEntry.endedAt`) report the task's\n * real lifetime instead of a projection-time delta.\n */\n endedAt?: number\n /**\n * Optional push-style exit callback. Undefined for pull-based\n * consumers (remote / durable hosts reconcile via `listBackground`).\n * Mutated in place by the kill / destroy / wait chains.\n */\n onExit?: (info: TaskExitInfo) => void\n}\n\n/**\n * Send `signal` to the child's whole process group. Falls back to a\n * single-process kill on Windows (no POSIX process groups). Shared\n * across the foreground `exec` path, the background spawn / kill\n * paths, and the shutdown-time orphan reaper — keeping one definition\n * so the kill semantics can't drift between them.\n */\nfunction killProcessGroup(child: ChildProcess, signal: NodeJS.Signals): void {\n const pid = child.pid\n if (pid === undefined)\n return\n try {\n if (SUPPORTS_PROCESS_GROUPS)\n process.kill(-pid, signal)\n else\n process.kill(pid, signal)\n }\n catch {\n // ESRCH / EPERM — process is already gone (race with natural exit)\n // or we lost the right to kill it. Both are safe to swallow.\n }\n}\n\n/**\n * Project a `TaskState` to the `TaskEntry` shape `listBackground` and\n * `reassignBackgroundTasks` return. Single helper keeps the shape\n * consistent across both call sites (and a future addition of fields\n * to `TaskEntry` only needs to land here).\n */\nfunction stateToTaskEntry(state: TaskState): TaskEntry {\n return {\n taskId: state.taskId,\n pid: state.pid,\n command: state.command,\n cwd: state.cwd,\n startedAt: state.startedAt,\n ...(state.endedAt !== undefined ? { endedAt: state.endedAt } : {}),\n outputPath: state.outputPath,\n status: state.status,\n ...(state.exitCode !== undefined ? { exitCode: state.exitCode } : {}),\n ...(state.signal ? { signal: state.signal } : {}),\n bytesWritten: state.bytesWritten,\n }\n}\n\n/**\n * Project a settled `TaskState` to the `TaskExitInfo` shape `settle()`\n * fires from `onExit` and `killBackground` returns on the\n * cached-exit path. Pre-condition: `state.status !== 'running'`\n * (callers gate on this).\n */\nfunction stateToTaskExitInfo(state: TaskState): TaskExitInfo {\n return {\n taskId: state.taskId,\n status: state.status as Exclude<TaskState['status'], 'running'>,\n exitCode: state.exitCode ?? 0,\n ...(state.signal ? { signal: state.signal } : {}),\n outputPath: state.outputPath,\n // Settle-time delta when available (always set since `endedAt` was\n // introduced); the `Date.now()` fallback covers defensive callers\n // projecting an unsettled state.\n durationMs: (state.endedAt ?? Date.now()) - state.startedAt,\n command: state.command,\n }\n}\n","/**\n * Execution context types.\n *\n * An execution context defines *where* and *how* an agent's tools run.\n * The agent loop and tools interact through this interface without knowing\n * whether they're running in-process, in a Docker container, or in a\n * remote sandbox.\n */\n\n// ---------------------------------------------------------------------------\n// Capabilities\n// ---------------------------------------------------------------------------\n\n/**\n * Lifetime guarantee of background tasks started through\n * {@link ExecutionContext.execBackground}.\n *\n * - `'none'` — the context cannot detach tasks at all.\n * - `'process-lifetime'` — tasks live as long as the HOST process; a\n * crash/restart of the host orphans or kills them (`ProcessContext`).\n * - `'durable'` — tasks live on a remote runner and survive host process\n * death (remote execution contexts driven by durable runtimes).\n *\n * Durable-execution adapters (e.g. `zidane/restate`) consult this to\n * decide whether backgrounding is safe to expose: a `'durable'` context\n * keeps its tasks across worker crashes, so there is no reason to strip\n * the capability from the model.\n */\nexport type DetachedTasksCapability = 'none' | 'process-lifetime' | 'durable'\n\nexport interface ContextCapabilities {\n /** Can execute shell commands */\n shell: boolean\n /** Can read/write files in a workspace */\n filesystem: boolean\n /** Can enumerate glob matches through `ExecutionContext.listFiles(..., { glob: true })`. */\n glob?: boolean\n /** Can make outbound network requests */\n network: boolean\n /** Has GPU access */\n gpu: boolean\n /**\n * Background-task lifetime guarantee. Optional for backward\n * compatibility — when absent, callers infer `'process-lifetime'`\n * if the context implements `execBackground`, `'none'` otherwise\n * (see {@link resolveDetachedTasksCapability}).\n */\n detachedTasks?: DetachedTasksCapability\n}\n\n/**\n * Effective {@link DetachedTasksCapability} of a context, with the\n * backward-compatible inference for contexts that predate the field.\n */\nexport function resolveDetachedTasksCapability(context: ExecutionContext): DetachedTasksCapability {\n return context.capabilities.detachedTasks\n ?? (context.execBackground ? 'process-lifetime' : 'none')\n}\n\n// ---------------------------------------------------------------------------\n// Execution handle\n// ---------------------------------------------------------------------------\n\n/** Opaque handle to a running execution context instance */\nexport interface ExecutionHandle {\n id: string\n type: ContextType\n /** Working directory within the context */\n cwd: string\n}\n\n// ---------------------------------------------------------------------------\n// Exec result\n// ---------------------------------------------------------------------------\n\nexport interface ExecResult {\n stdout: string\n stderr: string\n exitCode: number\n}\n\nexport interface ListFileMetadata {\n path: string\n size?: number\n mtimeMs?: number\n}\n\nexport type ListFilesEntry = string | ListFileMetadata\n\nexport interface ListFilesOptions {\n /** Treat `path` as a glob match pattern instead of a literal directory path. */\n glob?: boolean\n limit?: number\n metadata?: boolean\n /**\n * Skip git-ignored files when globbing. Default `true`. Contexts that can\n * resolve git's ignore rules (e.g. the local process context) honor it; the\n * rest treat it as a no-op. Set `false` to match every file, ignored or not.\n */\n gitignore?: boolean\n /** Abort the listing early — forwarded from the calling tool's `ctx.signal`. */\n signal?: AbortSignal\n}\n\n// ---------------------------------------------------------------------------\n// Spawn config\n// ---------------------------------------------------------------------------\n\nexport interface SpawnConfig {\n /** Working directory (created if it doesn't exist) */\n cwd?: string\n /**\n * Optional workspace-containment root for the file methods (`readFile`,\n * `writeFile`, `listFiles`) of the process context.\n *\n * When set, a resolved path that escapes this root (via absolute path,\n * `..`, or a symlink pointing outside) is rejected before any I/O. Default\n * unset = no containment (back-compat; the agent can read/write anywhere\n * the host process can). Set this for untrusted workloads to confine file\n * tools to a directory. Shell commands are not covered — use a sandbox /\n * docker context for full isolation.\n */\n workspaceRoot?: string\n /** Environment variables */\n env?: Record<string, string>\n /**\n * Whether spawned shells inherit the parent `process.env` (process context).\n *\n * Default `true` (preserves existing behavior — children see the parent\n * environment including anything Bun auto-loaded from `.env`). Set `false`\n * for untrusted workloads so secrets in the parent environment aren't\n * readable by tool commands; only `env` / per-call env plus a minimal base\n * (`PATH`, `HOME`, `SHELL`, `LANG`, `LC_ALL`, `USER`, `TERM`, `TMPDIR`) are\n * passed through.\n */\n inheritEnv?: boolean\n /** Docker image (only for 'docker' context) */\n image?: string\n /** Docker container name prefix (only for 'docker' context) */\n name?: string\n /** Host paths mounted into the context (only for 'docker' context today) */\n mounts?: ContextMount[]\n /** Resource limits */\n limits?: {\n /** Memory limit in MB */\n memory?: number\n /** CPU limit (e.g. '1.0' = 1 core) */\n cpu?: string\n /** Timeout in seconds for the entire context lifetime */\n timeout?: number\n }\n /** Sandbox provider config (only for 'sandbox' context) */\n sandbox?: {\n provider: string\n apiKey?: string\n /**\n * Attach to a pre-existing sandbox by id rather than creating one\n * (provider-specific; E2B maps it to `Sandbox.connect`). The provider\n * leaves a connected sandbox running on teardown.\n */\n sandboxId?: string\n [key: string]: unknown\n }\n\n /**\n * How long `destroy()` waits for a SIGTERM'd background task to settle\n * before escalating to SIGKILL and abandoning the wait (process context\n * only). Bounds `agent.destroy()` against tasks that trap SIGTERM or\n * whose stdio pipes are held open by escaped grandchildren.\n *\n * Default: `5000`.\n */\n destroyGraceMs?: number\n\n /**\n * Publish container ports on the host (docker context only).\n *\n * Each entry maps a container port to either an explicit host port or\n * (when `host` is omitted) a Docker-assigned random port. Retrieve the\n * actual host port at runtime via `getMappedPort(container)` on the\n * docker context.\n */\n ports?: Array<{ container: number, host?: number, proto?: 'tcp' | 'udp' }>\n\n /**\n * UID/GID the container should run as (docker context only).\n *\n * Accepts the same forms Docker's `--user` does: `uid`, `uid:gid`, or a\n * named user that exists in the image. Default is the image's default\n * user (typically root). Setting this to the host user's `uid:gid`\n * avoids the EACCES-on-cleanup problem when sharing a workspace via\n * a `shared` mount.\n */\n user?: string\n\n /**\n * User-defined Docker network to join (docker context only).\n *\n * Defaults to Docker's default bridge. Use a user network when you\n * need multiple sibling containers (e.g. agent + database + dev\n * server) to discover each other by name.\n */\n network?: string\n\n /**\n * Docker labels to attach to the container (docker context only).\n *\n * Useful for ownership tracking — callers can sweep abandoned\n * containers (e.g. from a crashed parent process) by filtering on\n * a label they own: `docker ps -aq --filter label=my-app=true`.\n */\n labels?: Record<string, string>\n\n /**\n * Container hardening options (docker context only).\n *\n * All fields are opt-in and OFF by default to preserve existing behavior\n * (containers run with the image's default user/capabilities). Enable them\n * for untrusted workloads. `dropAllCapabilities` and a non-root `user`\n * (see {@link SpawnConfig.user}) can break images that expect root or\n * specific capabilities, so they are not applied unless requested.\n */\n hardening?: ContextHardening\n}\n\n/**\n * Opt-in container hardening for the docker context. Every field defaults to\n * \"unset\" so an omitted `hardening` (or omitted field) reproduces the prior,\n * unrestricted behavior — this keeps the option purely additive.\n */\nexport interface ContextHardening {\n /**\n * Drop all Linux capabilities (`CapDrop: ['ALL']`). Strong isolation, but\n * breaks images needing capabilities (e.g. binding low ports, `ping`).\n * Default: `false`.\n */\n dropAllCapabilities?: boolean\n /**\n * Set `no-new-privileges` so processes can't gain privileges via setuid\n * binaries. Low blast radius; safe for most workloads. Default: `false`.\n */\n noNewPrivileges?: boolean\n /**\n * Mount the container root filesystem read-only. Pair with writable mounts\n * for scratch space. Default: `false`.\n */\n readonlyRootfs?: boolean\n /**\n * Max number of processes (`PidsLimit`) — caps fork-bombs. Default: unset\n * (no limit). A few hundred is usually plenty for an agent sandbox.\n */\n pidsLimit?: number\n}\n\nexport interface ContextMount {\n /** Absolute host path to mount. */\n source: string\n /** Absolute path inside the execution context. */\n target: string\n /** Mount read-only. Defaults to false for Docker's native bind behavior. */\n readonly?: boolean\n /**\n * Apply the SELinux shared label (`:z`) so the host user and the container\n * user can both read/write the mount (docker context only). No-op on\n * non-SELinux hosts. Combine with `SpawnConfig.user` to avoid root-owned\n * files leaking onto the host. Mutually exclusive with `readonly`.\n */\n shared?: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Execution context interface\n// ---------------------------------------------------------------------------\n\nexport type ContextType = 'process' | 'docker' | 'sandbox'\n\nexport interface ExecutionContext {\n /** Context type identifier */\n readonly type: ContextType\n\n /** What this context supports */\n readonly capabilities: ContextCapabilities\n\n /** Spawn a new execution environment */\n spawn: (config?: SpawnConfig) => Promise<ExecutionHandle>\n\n /**\n * Execute a shell command in the context.\n *\n * `signal` propagates abort all the way down to the underlying child\n * process — the implementation is expected to wire it into whatever\n * spawn primitive it uses so the OS receives a SIGTERM (or equivalent)\n * when the caller aborts. Without it, a cancelled tool returns its\n * cancellation marker to the model but the underlying process keeps\n * running in the background, orphaning compute / locks / IO. Pass\n * `ctx.signal` from a tool body to inherit the per-call + run-level\n * abort union; pass a freshly-built one for a host-driven kill.\n *\n * Implementations are free to ignore `signal` (the contract degrades\n * gracefully — the process simply won't be killed), but the in-process\n * default DOES honor it via `child_process.exec`'s native `signal`\n * option.\n */\n /**\n * Run a shell command. `timeout` is in SECONDS (default 30) — every\n * implementation converts internally (process ×1000 to ms, docker wraps\n * with coreutils `timeout`, sandbox SDKs take seconds/ms per their API).\n * Documented here because the unit is invisible at call sites and a\n * caller assuming milliseconds would set an instant-kill timeout.\n */\n exec: (handle: ExecutionHandle, command: string, options?: { cwd?: string, env?: Record<string, string>, timeout?: number, signal?: AbortSignal }) => Promise<ExecResult>\n\n /**\n * Start a process in the background. Settles as soon as `spawn` returns\n * — does NOT wait for the child to exit. Stdout + stderr stream\n * interleaved to the file at the returned `outputPath`. The caller\n * (typically the agent) reads incremental output via the regular\n * {@link ExecutionContext.readFile} seam.\n *\n * Optional — contexts without background support (some remote sandboxes)\n * just don't implement it. The shell tool surfaces a clean\n * \"background mode is not supported in this execution context\" error\n * when this is undefined.\n *\n * `onExit` is called once when the child terminates (natural, killed,\n * or error). The same instance that called `execBackground` is the\n * exclusive owner of the callback — it's not a multi-cast bus. Hosts\n * wire this to the agent's pending-notification queue so the model\n * gets a `<task-notification>` on its next turn.\n *\n * `onExit` is OPTIONAL: remote / durable contexts may have no legal\n * way to push a callback from a timer back into the host (a Restate\n * journal, for instance, forbids out-of-band writes). Such contexts\n * simply record the exit in their registry; the agent loop reconciles\n * by polling {@link ExecutionContext.listBackground} at run\n * boundaries, where a host journal wrapper is legal (the\n * `background:reconcile` hook is the journalable seam).\n *\n * See `docs/RUN_IN_BACKGROUND.md` for the broader design contract\n * (file location, replay semantics, suppression rules).\n */\n execBackground?: (\n handle: ExecutionHandle,\n command: string,\n options: {\n cwd?: string\n env?: Record<string, string>\n /**\n * Absolute directory the context appends `<task-id>.log` to. The\n * agent owns this path because it carries session-shaped knowledge\n * (`<userDir>/<sessionId>/tasks/`) the context can't synthesize.\n * Must already exist OR be creatable by the context — the\n * implementation handles `mkdir -p` defensively.\n */\n outputDir: string\n /** Push-style exit callback. Optional — see the method doc. */\n onExit?: (info: TaskExitInfo) => void\n /**\n * Cap on bytes written to the output file. Beyond the cap the\n * process KEEPS RUNNING; further output is counted but dropped,\n * and a `<output-truncated bytes-dropped=\"N\"/>` marker is\n * appended when the task settles. Unset / non-positive = no cap.\n */\n maxOutputBytes?: number\n /**\n * Stall watchdog: when the task produces no output for this many\n * milliseconds, `onStall` fires ONCE (one-shot — re-arms only\n * after fresh output arrives). The process is NOT killed; the\n * consumer decides (typically by telling the model the task may\n * be stuck at an interactive prompt). Unset = no watchdog.\n */\n stallTimeoutMs?: number\n /** One-shot stall callback — see `stallTimeoutMs`. */\n onStall?: (info: TaskStallInfo) => void\n },\n ) => Promise<TaskHandle>\n\n /**\n * SIGTERM the whole process group of a running background task.\n * Idempotent — second call returns `null` (or the cached exit info).\n * Resolves once the process has exited AND its output stream has\n * been flushed + closed.\n *\n * `null` return on miss (unknown id, already cleaned up) so the\n * shell_kill tool can surface a clean \"no such task\" message\n * without throwing.\n */\n killBackground?: (\n handle: ExecutionHandle,\n taskId: string,\n ) => Promise<TaskExitInfo | null>\n\n /**\n * Snapshot of every task in the context's registry — running AND\n * terminated (entries remain until the next context destroy, so\n * the model can still read output of exited tasks).\n */\n listBackground?: (\n handle: ExecutionHandle,\n ) => Promise<readonly TaskEntry[]>\n\n /**\n * Block until a background task terminates, then resolve with its\n * exit info. Resolves immediately for already-terminated tasks.\n *\n * Returns `null` when:\n * - the task id is unknown (or owned by another handle — same\n * isolation contract as `killBackground`), OR\n * - `timeoutMs` elapsed / `signal` aborted before the task exited.\n *\n * Callers that need to distinguish \"unknown\" from \"still running\"\n * should consult `listBackground` first (the `wait_task` tool does).\n *\n * This is the injectable wait seam for the `wait_task` tool:\n * in-process contexts implement it on the existing `onExit`\n * machinery; durable hosts implement it as an awakeable park\n * (runner fires task-exit over their bridge → resolveAwakeable).\n */\n waitBackground?: (\n handle: ExecutionHandle,\n taskId: string,\n options?: { timeoutMs?: number, signal?: AbortSignal },\n ) => Promise<TaskExitInfo | null>\n\n /**\n * Transfer ownership of every still-running task from `fromHandle`\n * to `toHandle`. Used by the spawn tool to \"promote\" a subagent's\n * background tasks up to the parent's handle so they outlive the\n * subagent's destroy() — matching shell semantics, where a `&`-ed\n * command outlives the parent process.\n *\n * Side effects:\n * - The task's `handleId` is rewritten, so subsequent\n * `listBackground(toHandle)` / `killBackground(toHandle, …)` /\n * `destroy(toHandle)` see it (and `fromHandle`-scoped operations\n * don't).\n * - When `newOnExit` is provided, the original `onExit` is\n * REPLACED with it. Critical: the task's natural exit callback\n * was captured against the spawning agent's hook bus, which is\n * about to be destroyed; without rewiring, the parent never\n * learns when the task terminates. Pass a closure that fires\n * the parent agent's `background:exit` hook.\n *\n * Returns the entries that were actually reassigned (running tasks\n * only; terminated ones stay where they are). Implementations that\n * don't support reassignment can leave this undefined; the caller\n * (spawn.ts) falls back to the current behavior of killing child\n * tasks at subagent shutdown.\n */\n reassignBackgroundTasks?: (\n fromHandle: ExecutionHandle,\n toHandle: ExecutionHandle,\n newOnExit?: (info: TaskExitInfo) => void,\n ) => Promise<readonly TaskEntry[]>\n\n /** Read a file from the context's filesystem */\n readFile: (handle: ExecutionHandle, path: string) => Promise<string>\n\n /**\n * Read a file from the context's filesystem as raw bytes.\n *\n * Used by `read_file` to dispatch image / binary files into the multimodal\n * `ToolResultContent[]` route. Optional — when not implemented, the tool\n * falls back to `base64 < path` via the `exec` seam, which works in any\n * shell-capable context. Implementations that already have a native\n * binary read (in-process `fs.readFile` without encoding, container API,\n * sandbox SDK) should override for the latency win.\n */\n readFileBinary?: (handle: ExecutionHandle, path: string) => Promise<Uint8Array>\n\n /**\n * Cheap size probe for a file in the context's filesystem, in bytes.\n * `null` = unknowable (missing file, not a regular file, probe failed,\n * or containment rejected the path — a probe must not leak even the\n * size of files outside the workspace root).\n *\n * Exists because `readFile` has no partial-read form: tools that must\n * materialize a whole file (read_file's text path, edit/multi_edit,\n * grep's no-rg fallback) consult this first to refuse multi-GB targets\n * instead of OOMing the HOST — the read lands in host memory no matter\n * where the file lives. Per-context posture:\n *\n * - `process` — implements it (local stat, µs).\n * - `docker` — implements it via `wc -c` through its exec; its\n * `readFile` gets transport headroom above the tool ceiling so\n * the probe (tool policy), not the 10MB exec cap, decides read\n * limits — same experience as every other context.\n * - `sandbox` (and the e2b / daytona providers behind it) —\n * implements it via `wc -c` through the provider's exec: one extra\n * round-trip per whole-read tool call, paid so a multi-GB sandbox\n * file is refused BEFORE the SDK transfers it into host memory.\n *\n * KNOWN RESIDUAL (sandbox providers): this guards the `readFile` path\n * only. Their `exec` output is buffered inside the provider SDKs\n * (e2b `commands.run`, daytona `executeCommand`), which we cannot cap\n * from this side — a command that streams GBs to stdout within its\n * timeout window can still balloon host memory. Docker doesn't share\n * the residual (we own its transport; see `output-cap.ts`). A shell\n * wrapper (`| head -c`) was considered and rejected: preserving exit\n * codes, stderr separation, and timeout semantics through a pipe for\n * EVERY command is fragile, and the timeout already time-bounds the\n * exposure.\n */\n fileSize?: (handle: ExecutionHandle, path: string) => Promise<number | null>\n\n /** Write a file to the context's filesystem */\n writeFile: (handle: ExecutionHandle, path: string, content: string) => Promise<void>\n\n /**\n * List files in the context filesystem.\n *\n * Plain paths list immediate directory entries (legacy behavior). Paths that\n * contain glob metacharacters (`*`, `?`, `[]`, `{}`) request matched file\n * enumeration inside the target context. Contexts that cannot support\n * globbing should throw a clear error rather than silently returning no\n * matches. `metadata` is best-effort and only required when the context can\n * provide it without expensive per-file shell calls.\n */\n listFiles: (handle: ExecutionHandle, path: string, options?: ListFilesOptions) => Promise<ListFilesEntry[]>\n\n /**\n * Resolve the host-side port that a container port was published on\n * (docker context only, and only when the matching entry was created\n * with `host` omitted in `SpawnConfig.ports`).\n *\n * Resolves to `null` if the container port isn't published. Other\n * contexts (process, sandbox) don't implement this; they don't have\n * a port-mapping concept.\n */\n getMappedPort?: (handle: ExecutionHandle, containerPort: number) => Promise<number | null>\n\n /** Destroy the execution environment and clean up resources */\n destroy: (handle: ExecutionHandle) => Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// Background task types\n// ---------------------------------------------------------------------------\n\n/**\n * Lifecycle status of a background task.\n *\n * - `'running'` — process is still live; `exitCode` / `signal` unset.\n * - `'exited'` — process terminated on its own (clean or non-zero exit).\n * - `'killed'` — the host issued `killBackground` (SIGTERM to the group).\n *\n * The status is a coarse-grained signal; the exit code carries the\n * fine-grained detail (e.g. `143 = SIGTERM` for `'killed'`).\n */\nexport type BackgroundTaskStatus = 'running' | 'exited' | 'killed'\n\n/**\n * Returned synchronously by `execBackground` — the handle the model and\n * the framework use to refer to the task until it terminates.\n *\n * `outputPath` is an absolute path to the log file the context is\n * appending stdout + stderr to (interleaved by emit order). The model\n * reads it via the normal `read_file` tool; no special tool is required.\n */\nexport interface TaskHandle {\n /**\n * Stable id minted by the context — typically `bash_<n>` for\n * `ProcessContext`. Sequential within a single context instance,\n * resets when a new context is constructed. Forwarded to `killBackground` /\n * `listBackground` and stamped into every `<task-notification>` block.\n */\n taskId: string\n /** OS pid of the spawned shell wrapper (process-group leader on POSIX). */\n pid: number\n /** Absolute path to the log file the context is streaming output into. */\n outputPath: string\n}\n\n/**\n * Fired exactly once per task when the child process terminates, via\n * `execBackground`'s `onExit` callback. The agent layer translates this\n * into a queued `<task-notification>` for the next turn.\n *\n * `signal` is set when the child was terminated by a signal (e.g.\n * SIGTERM from our own kill-tree, SIGKILL from oom-killer); absent on\n * natural exit. `exitCode` is `128 + signal-number` on signal-killed\n * children, matching POSIX shell conventions — `143` for SIGTERM, etc.\n */\nexport interface TaskExitInfo {\n taskId: string\n status: Exclude<BackgroundTaskStatus, 'running'>\n exitCode: number\n signal?: NodeJS.Signals\n outputPath: string\n /** `Date.now()` delta between spawn and exit. */\n durationMs: number\n /** The original command string the model invoked — useful for telemetry / banner summary. */\n command: string\n}\n\n/**\n * One row in `listBackground`'s snapshot. Living entries (status `'running'`)\n * have `exitCode` / `signal` / `endedAt` unset; terminated entries carry the\n * same data `TaskExitInfo` returned at exit time.\n */\nexport interface TaskEntry {\n taskId: string\n pid: number\n command: string\n cwd: string\n startedAt: number\n /**\n * Set when the task terminated. Lets pull-based consumers (the agent's\n * run-boundary reconcile) derive `durationMs = endedAt - startedAt`\n * without depending on when the snapshot was taken.\n */\n endedAt?: number\n outputPath: string\n status: BackgroundTaskStatus\n exitCode?: number\n signal?: NodeJS.Signals\n /** Total bytes written to the output file so far — useful for \"task X has produced N KB\" UX hints. */\n bytesWritten: number\n}\n\n/**\n * Fired by the optional stall watchdog (see `execBackground`'s\n * `stallTimeoutMs`) when a running task has produced no output for the\n * configured window. The process is still alive — this is a signal, not\n * a state transition.\n */\nexport interface TaskStallInfo {\n taskId: string\n command: string\n outputPath: string\n /** Milliseconds since the last output chunk (>= the configured window). */\n stalledForMs: number\n /** Total bytes the task has written so far. */\n bytesWritten: number\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-CcvuVXB9.js","names":[],"sources":["../src/mcp/oauth-provider.ts","../src/mcp/sse-to-json-fetch.ts","../src/mcp/tolerant-client.ts","../src/mcp/index.ts"],"sourcesContent":["/**\n * OAuth 2.1 client provider for MCP servers.\n *\n * Implements the MCP SDK's `OAuthClientProvider` interface — the SDK handles\n * the protocol (PKCE, RFC 9728 protected-resource discovery, RFC 8414 / OIDC\n * authorization-server metadata, RFC 7591 dynamic client registration, token\n * refresh). This class provides the two halves the SDK delegates to consumers:\n *\n * - **Persistence** — tokens, registered client info, optional discovery\n * state cache, and PKCE code verifier. Storage is injected via the\n * `McpCredentialStore` interface so the SDK adapter has no FS dependency;\n * the chat layer wires a file-backed store, tests use the in-memory one.\n *\n * - **Redirect** — when the SDK wants the user agent to navigate to the\n * authorization URL, we hand the URL to the host (the TUI opens a\n * browser + surfaces the URL in a status row). The PKCE code verifier\n * stays in process memory for the lifetime of the flow; persisting it\n * across process restarts would expose it on disk for no real benefit\n * since the loopback callback server is also process-local.\n *\n * Two modes by `redirectUri`:\n *\n * - **Non-interactive** (`redirectUri: undefined`) — used during bootstrap.\n * The SDK will use stored tokens, auto-refresh on expiry, but cannot\n * trigger a browser flow. Missing tokens cause the SDK to throw\n * `UnauthorizedError`, which the caller catches and converts to a\n * `mcp:auth:required` signal.\n *\n * - **Interactive** (`redirectUri: 'http://127.0.0.1:<port>/callback'`) —\n * used when the user explicitly triggers login. The caller has already\n * stood up a loopback callback server (see `oauth-callback.ts`) and\n * orchestrates: `client.connect()` → catches `UnauthorizedError` →\n * waits on the callback for the `code` → `transport.finishAuth(code)`\n * → retry `client.connect()`.\n */\n\nimport type {\n OAuthClientProvider,\n OAuthDiscoveryState,\n} from '@modelcontextprotocol/sdk/client/auth.js'\nimport type {\n OAuthClientInformationMixed,\n OAuthClientMetadata,\n OAuthTokens,\n} from '@modelcontextprotocol/sdk/shared/auth.js'\n\n/**\n * Per-server persisted state. Subfields are optional so a partial save\n * (e.g. `saveCodeVerifier` arriving before `saveTokens`) doesn't blow away\n * earlier subfields — the provider always patches, never replaces.\n */\nexport interface McpCredentialEntry {\n tokens?: OAuthTokens\n clientInformation?: OAuthClientInformationMixed\n discoveryState?: OAuthDiscoveryState\n}\n\nexport interface McpCredentialStore {\n load: (name: string) => McpCredentialEntry | undefined\n save: (name: string, entry: McpCredentialEntry) => void\n delete: (name: string) => void\n}\n\n/**\n * In-memory store — primarily for tests, but valid as a no-persistence option\n * (tokens evaporate on process exit, the user re-auths every cold start).\n */\nexport function createMemoryMcpCredentialStore(seed?: Record<string, McpCredentialEntry>): McpCredentialStore {\n const state = new Map<string, McpCredentialEntry>(Object.entries(seed ?? {}))\n return {\n load: name => state.get(name),\n save: (name, entry) => { state.set(name, entry) },\n delete: (name) => { state.delete(name) },\n }\n}\n\nexport interface McpOAuthProviderOptions {\n /** Server name — used as the storage key. */\n name: string\n /** Persistence backend. */\n store: McpCredentialStore\n /**\n * Loopback callback URI. Pass `undefined` for bootstrap (non-interactive\n * mode — stored tokens + refresh only, never opens a browser).\n */\n redirectUri?: string\n /**\n * Invoked when the SDK wants the user agent to navigate to the authorization\n * URL. Typically the host opens the browser AND emits a hook so the TUI can\n * render the URL in a status row. No-op in non-interactive mode (the SDK\n * still calls this before throwing `UnauthorizedError` from connect).\n */\n onAuthorizationUrl?: (url: URL) => void | Promise<void>\n /**\n * `client_name` used in dynamic client registration. Defaults to `'zidane'`.\n * Some servers display this string to the user on the consent screen.\n */\n clientName?: string\n /**\n * Override the requested OAuth scope. Default: unset (the SDK negotiates\n * via the server's metadata).\n */\n scope?: string\n}\n\nconst DEFAULT_CLIENT_NAME = 'zidane'\n\nexport class McpOAuthProvider implements OAuthClientProvider {\n private readonly name: string\n private readonly store: McpCredentialStore\n private readonly _redirectUri?: string\n private readonly onAuthorizationUrl?: (url: URL) => void | Promise<void>\n private readonly clientName: string\n private readonly _scope?: string\n // PKCE verifier is process-local — see file header. Module-scoped Map would\n // leak across concurrent flows for different servers; per-instance is the\n // right granularity.\n private codeVerifierValue: string | undefined\n\n constructor(opts: McpOAuthProviderOptions) {\n this.name = opts.name\n this.store = opts.store\n this._redirectUri = opts.redirectUri\n this.onAuthorizationUrl = opts.onAuthorizationUrl\n this.clientName = opts.clientName ?? DEFAULT_CLIENT_NAME\n this._scope = opts.scope\n }\n\n get redirectUrl(): string | URL | undefined {\n return this._redirectUri\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n // The SDK validates `redirect_uris` non-empty; we use a placeholder\n // when running non-interactively (no callback server is up). The\n // server won't actually redirect anywhere because the SDK throws\n // `UnauthorizedError` before any browser navigation in that mode.\n redirect_uris: [this._redirectUri ?? 'http://127.0.0.1:0/callback'],\n client_name: this.clientName,\n // PKCE-only public client — no client_secret. RFC 8252 native-app pattern.\n token_endpoint_auth_method: 'none',\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n ...(this._scope ? { scope: this._scope } : {}),\n }\n }\n\n tokens(): OAuthTokens | undefined {\n return this.store.load(this.name)?.tokens\n }\n\n saveTokens(tokens: OAuthTokens): void {\n this.patch({ tokens })\n }\n\n clientInformation(): OAuthClientInformationMixed | undefined {\n return this.store.load(this.name)?.clientInformation\n }\n\n saveClientInformation(info: OAuthClientInformationMixed): void {\n this.patch({ clientInformation: info })\n }\n\n discoveryState(): OAuthDiscoveryState | undefined {\n return this.store.load(this.name)?.discoveryState\n }\n\n saveDiscoveryState(state: OAuthDiscoveryState): void {\n this.patch({ discoveryState: state })\n }\n\n saveCodeVerifier(verifier: string): void {\n this.codeVerifierValue = verifier\n }\n\n codeVerifier(): string {\n if (!this.codeVerifierValue) {\n // Spec-correct error — the SDK would otherwise complete the code\n // exchange with an empty verifier and the auth server would 400.\n throw new Error(\n `MCP OAuth: code verifier missing for \"${this.name}\" — `\n + 'the flow must call saveCodeVerifier() before the redirect',\n )\n }\n return this.codeVerifierValue\n }\n\n async redirectToAuthorization(url: URL): Promise<void> {\n await this.onAuthorizationUrl?.(url)\n }\n\n /**\n * Wipe stored credentials when the server reports the cached state is no\n * longer valid. The SDK calls this with a scope hint:\n * - `'tokens'` → access/refresh revoked, keep client registration\n * - `'client'` → client registration invalidated, reset everything\n * - `'verifier'`→ PKCE state stale (e.g. mismatched state param)\n * - `'discovery'` → discovery metadata stale (servers re-keyed)\n * - `'all'` → full reset\n */\n async invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise<void> {\n if (scope === 'verifier') {\n this.codeVerifierValue = undefined\n return\n }\n const current = this.store.load(this.name)\n if (!current)\n return\n if (scope === 'all') {\n this.codeVerifierValue = undefined\n this.store.delete(this.name)\n return\n }\n const next: McpCredentialEntry = { ...current }\n if (scope === 'tokens')\n delete next.tokens\n if (scope === 'client') {\n delete next.clientInformation\n // Client identity changed; previously-issued tokens and discovery\n // are no longer valid against the new registration.\n delete next.tokens\n delete next.discoveryState\n }\n if (scope === 'discovery')\n delete next.discoveryState\n this.store.save(this.name, next)\n }\n\n private patch(updates: Partial<McpCredentialEntry>): void {\n const existing = this.store.load(this.name) ?? {}\n this.store.save(this.name, { ...existing, ...updates })\n }\n}\n\n/**\n * True when an HTTP transport's auth headers already include an explicit\n * Authorization. Used by the bootstrap escape-hatch: a user who provided\n * their own bearer token shouldn't be auto-promoted to OAuth on a 401.\n *\n * Case-insensitive — Node normalizes outgoing headers to lowercase but\n * users hand-write `Authorization` in configs.\n */\nexport function hasAuthorizationHeader(headers: Record<string, string> | undefined): boolean {\n if (!headers)\n return false\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === 'authorization')\n return true\n }\n return false\n}\n","/**\n * `fetch` shim that converts streamable-http POST responses with\n * `Content-Type: text/event-stream` into synthetic `application/json`\n * responses, preserving every original header (notably `mcp-session-id`).\n *\n * Why this exists\n * ----------------\n * The MCP SDK's streamable-http transport handles POST responses two ways\n * depending on `content-type`:\n *\n * - `application/json` → `await response.json()` (works on every runtime).\n * - `text/event-stream` → `body.pipeThrough(TextDecoderStream)\n * .pipeThrough(EventSourceParserStream)`\n * and forward each parsed event to `onmessage`.\n *\n * On Bun + MCP SDK 1.29.x the second pipeline silently drops the parsed\n * event: the full `event: message\\ndata: {...}\\n\\n` arrives intact, the\n * stream closes, but `onmessage` is never called. Bootstrap then waits the\n * full `bootstrapTimeout` (10s default) and the agent loses every tool the\n * server would have exposed.\n *\n * The MCP spec lets clients accept either content type\n * (`Accept: application/json, text/event-stream`), so flipping the stream\n * to JSON at the boundary is a transparent, server-agnostic workaround.\n *\n * Scope of the shim\n * -----------------\n * - POST + `text/event-stream` → drain, parse SSE message events, return\n * a synthetic `application/json` response. Single event becomes a JSON\n * object (matching the shape the SDK expects from non-streaming\n * servers); multiple events become a JSON array (the SDK already\n * iterates `Array.isArray(data)` from a JSON response).\n * - GET (long-lived `_startOrAuthSse` listener) → untouched. Per-event\n * latency matters there and the SSE pipeline isn't always broken on\n * GET in the same way (different code path inside Bun's stream impl).\n * - 202 / non-SSE / malformed SSE / no body → passthrough.\n *\n * Runtime gating\n * --------------\n * `sseToJsonFetchIfNeeded()` only returns a wrapper on Bun. Node + browser\n * runtimes get `undefined` and the SDK uses global `fetch` directly — no\n * extra buffer-and-redrain on the happy path, and no risk of collapsing a\n * future progress-streaming response into a single batched array. If you\n * need to apply the shim unconditionally (testing, custom hosts), call\n * `sseToJsonFetch()` directly.\n *\n * Cleanup\n * -------\n * Remove this file and its `fetch:` injection in `createTransport` once\n * either Bun fixes the `pipeThrough` chain or the SDK switches off the\n * streaming pipeline by default.\n */\n\n/**\n * Detect whether we're running on Bun. The `Bun` global is set by the\n * runtime itself and isn't faked by Bun's Node-compat layer.\n */\nfunction isBunRuntime(): boolean {\n return typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined'\n}\n\n/**\n * Returns the `sseToJsonFetch` wrapper only on runtimes that need it\n * (currently Bun). Returns `undefined` everywhere else, which makes the\n * SDK fall back to the global `fetch` and keeps the streaming pipeline\n * intact on Node where it works correctly.\n *\n * Designed as the value to pass directly to `StreamableHTTPClientTransport`'s\n * `fetch` option:\n *\n * new StreamableHTTPClientTransport(url, {\n * fetch: sseToJsonFetchIfNeeded(),\n * })\n */\nexport function sseToJsonFetchIfNeeded(): typeof fetch | undefined {\n return isBunRuntime() ? sseToJsonFetch() : undefined\n}\n\n/**\n * Wrap a `fetch` implementation so streamable-http POST responses that come\n * back as `text/event-stream` are converted to JSON. Pass the result as\n * `opts.fetch` to `StreamableHTTPClientTransport`.\n *\n * Always-on (i.e. unconditional) — for the runtime-gated entry point,\n * use {@link sseToJsonFetchIfNeeded} instead.\n */\nexport function sseToJsonFetch(baseFetch: typeof fetch = fetch): typeof fetch {\n return async function sseToJsonWrappedFetch(input, init) {\n const response = await baseFetch(input, init)\n\n // Only intercept POSTs. The SDK's GET path opens a long-lived SSE\n // listener (`_startOrAuthSse`) that we must not buffer-drain.\n const method = (init?.method ?? 'GET').toString().toUpperCase()\n if (method !== 'POST')\n return response\n\n const contentType = response.headers.get('content-type')\n if (!contentType || !contentType.includes('text/event-stream'))\n return response\n\n if (!response.body)\n return response\n\n let raw: string\n try {\n raw = await response.text()\n }\n catch {\n // Bun edge case: if even .text() fails, surrender — the original\n // response is already drained, so we can't recover. Return it; the\n // SDK will surface the underlying read error.\n return response\n }\n\n const events = parseSseDataEvents(raw)\n // Single event → bare object; multi-event or zero → array. The SDK's\n // JSON branch handles both shapes (`Array.isArray(data) ? data.map(…) : …`).\n const payload = events.length === 1 ? events[0] : events\n return synthesizeJsonResponse(response, payload)\n } as typeof fetch\n}\n\n/**\n * Parse a buffered SSE body into the JSON payloads of its `message` events.\n *\n * Skips:\n * - SSE comments (lines starting with `:`).\n * - Non-default event types (`event: foo` ≠ `message`). The MCP server\n * only ever emits `message` events for JSON-RPC; anything else is out of\n * band and the SDK wouldn't have surfaced it to `onmessage` either.\n * - Malformed `data:` payloads (anything that fails `JSON.parse`).\n */\nfunction parseSseDataEvents(raw: string): unknown[] {\n const events: unknown[] = []\n for (const block of raw.split(/\\r?\\n\\r?\\n/)) {\n if (!block.trim())\n continue\n\n const dataLines: string[] = []\n let isMessageEvent = true\n for (const line of block.split(/\\r?\\n/)) {\n if (line.startsWith(':'))\n continue\n if (line.startsWith('event:')) {\n const eventType = line.slice('event:'.length).trim()\n if (eventType && eventType !== 'message')\n isMessageEvent = false\n }\n else if (line.startsWith('data:')) {\n // Per SSE spec: a single leading space after `data:` is part of the\n // separator, not the payload. Anything beyond it is.\n const value = line.slice('data:'.length)\n dataLines.push(value.startsWith(' ') ? value.slice(1) : value)\n }\n }\n\n if (!isMessageEvent || dataLines.length === 0)\n continue\n\n try {\n events.push(JSON.parse(dataLines.join('\\n')))\n }\n catch {\n // Drop malformed events. The SDK's broken pipe would have dropped\n // them too — staying silent here matches that baseline.\n }\n }\n return events\n}\n\n/**\n * Build a `Response` mirroring the original's status / statusText / headers\n * but with a JSON body and `content-type: application/json`. Header\n * preservation is the whole point — `mcp-session-id` is set by the server\n * on the initialize POST and must round-trip into the SDK's\n * `_sessionId` capture (`response.headers.get('mcp-session-id')`).\n */\nfunction synthesizeJsonResponse(original: Response, payload: unknown): Response {\n const headers = new Headers(original.headers)\n headers.set('content-type', 'application/json')\n return new Response(JSON.stringify(payload), {\n status: original.status,\n statusText: original.statusText,\n headers,\n })\n}\n","/**\n * Drop-in `Client` subclass whose `connect()` mirrors the upstream MCP SDK\n * sequence but treats `notifications/initialized` as best-effort.\n *\n * The MCP spec marks that notification fire-and-forget, but the SDK awaits\n * the underlying transport `send()` and rethrows on any HTTP 4xx. Several\n * real-world streamable-http servers (e.g. browser-codemode, custom MCPs\n * that gate non-initialize routes on a session id that didn't yet exist when\n * the notification posted) reject the notification with a 4xx and still\n * accept every subsequent request. The base `Client.connect()` then closes\n * the transport, the bootstrap fails, and the agent silently loses every\n * tool the server would have exposed.\n *\n * This module changes only that single step — log + continue if the\n * notification throws. Initialize, capability/version capture,\n * `setProtocolVersion`, listChanged handler wiring, and the close-on-failure\n * path for everything else are preserved verbatim from the SDK.\n *\n * Lazy SDK load: `@modelcontextprotocol/sdk` is an *optional* peer dep, so\n * the class is built inside `createTolerantClient()` via dynamic imports.\n * Importing this module does NOT trigger SDK resolution — callers only\n * incur the cost when they actually instantiate a client.\n *\n * Should be removed when the SDK lands an opt-in tolerance flag upstream.\n */\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { errorMessage } from '../errors'\n\n// Private fields the override needs to read/write to mirror upstream behavior.\n// Cast surface is isolated to this one type so the rest of the file stays clean.\ninterface ClientPrivates {\n _capabilities: unknown\n _clientInfo: unknown\n _serverCapabilities: unknown\n _serverVersion: unknown\n _instructions: unknown\n _pendingListChangedConfig?: unknown\n _setupListChangedHandlers: (config: unknown) => void\n}\n\ninterface MaybeSessionedTransport {\n sessionId?: unknown\n setProtocolVersion?: (v: string) => void\n}\n\n/**\n * Options forwarded to the upstream `Client` constructor. Mirrors the\n * publicly-observable shape so we don't have to re-export `Client`'s\n * private `ClientOptions` type (which would force consumers of the lazy\n * factory below to install the SDK at type-check time too).\n */\nexport interface TolerantClientOptions {\n /** Capabilities advertised to the server on `initialize`. */\n capabilities?: Record<string, unknown>\n /** When true, the SDK rejects requests for methods the server didn't advertise. */\n enforceStrictCapabilities?: boolean\n /** Per-request timeout in ms; the SDK falls back to its own default when unset. */\n defaultRequestTimeout?: number\n /**\n * Best-effort notification sink. Fires once if the server rejected\n * `notifications/initialized` with a 4xx — the connection survived but\n * the client wants to know it deviated from the spec. Default: no-op.\n *\n * Routing this through a callback (instead of a hard-coded\n * `console.warn`) is what lets `connectMcpServers` collect the warning,\n * include it on the `mcp:bootstrap:end` payload, and keep hosts that\n * don't care from seeing stray stderr.\n */\n onWarning?: (message: string) => void\n}\n\n/**\n * Async factory — builds an instance of the tolerant MCP client. The\n * actual `Client` subclass definition lives inside the factory so the\n * `@modelcontextprotocol/sdk` import only resolves when MCP is in use.\n *\n * Second `options` arg forwards directly into the upstream `Client`\n * constructor so tests / advanced consumers can supply capabilities,\n * `enforceStrictCapabilities`, etc.\n */\nexport async function createTolerantClient(\n info: { name: string, version: string },\n options?: TolerantClientOptions,\n): Promise<Client> {\n const { Client } = await import('@modelcontextprotocol/sdk/client/index.js')\n const { Protocol } = await import('@modelcontextprotocol/sdk/shared/protocol.js')\n const { InitializeResultSchema, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } = await import('@modelcontextprotocol/sdk/types.js')\n\n // Capture once; the override below mustn't re-read `options.onWarning` per\n // connect because hosts may not consider `options` long-lived.\n const onWarning = options?.onWarning\n\n class TolerantMcpClient extends Client {\n async connect(\n transport: Parameters<Client['connect']>[0],\n options?: Parameters<Client['connect']>[1],\n ): Promise<void> {\n // Wire the transport (Protocol.connect — onmessage/onclose/onerror hooks\n // and transport.start) without sending any messages. We MUST NOT call\n // `super.connect()` here — that's `Client.connect`, which would\n // re-execute the very initialize+notification dance we're overriding.\n await Protocol.prototype.connect.call(this as never, transport)\n\n // Reconnect path: the upstream client short-circuits on a transport that\n // already carries a session id, so do we.\n if ((transport as MaybeSessionedTransport).sessionId !== undefined)\n return\n\n const self = this as unknown as ClientPrivates\n\n try {\n const result = await this.request(\n {\n method: 'initialize',\n params: {\n protocolVersion: LATEST_PROTOCOL_VERSION,\n capabilities: self._capabilities,\n clientInfo: self._clientInfo,\n },\n },\n InitializeResultSchema,\n options,\n )\n\n if (result === undefined)\n throw new Error(`Server sent invalid initialize result: ${result}`)\n if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion))\n throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`)\n\n self._serverCapabilities = result.capabilities\n self._serverVersion = result.serverInfo\n\n const setProtocolVersion = (transport as MaybeSessionedTransport).setProtocolVersion\n if (setProtocolVersion)\n setProtocolVersion.call(transport, result.protocolVersion)\n\n self._instructions = result.instructions\n\n // Best-effort. The session id (if any) is already captured by the\n // transport from the `initialize` response headers, so subsequent\n // requests like `tools/list` still authenticate. Don't bring down the\n // whole connection on a 4xx for a fire-and-forget notification.\n try {\n await this.notification({ method: 'notifications/initialized' })\n }\n catch (notifyError) {\n // Hosts opt in to the signal via `onWarning`; default is silent\n // so a plain `new Client()` doesn't leak stderr into every host.\n onWarning?.(`server rejected notifications/initialized (continuing): ${errorMessage(notifyError)}`)\n }\n\n if (self._pendingListChangedConfig) {\n self._setupListChangedHandlers(self._pendingListChangedConfig)\n self._pendingListChangedConfig = undefined\n }\n }\n catch (error) {\n // Same failure path as upstream Client — anything *other* than the\n // tolerated notification failure tears the transport down so the\n // bootstrap surfaces a clear error.\n void this.close().catch(() => {})\n throw error\n }\n }\n }\n\n return new TolerantMcpClient(info, options)\n}\n","/**\n * MCP (Model Context Protocol) server support.\n *\n * Connects to one or more MCP servers, discovers their tools,\n * and wraps them as zidane ToolDefs for use in agent loops.\n */\n\nimport type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks, McpToolMeta, McpToolWrap } from '../agent'\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { McpServerConfig, McpToolHookContext, McpToolSchema, ToolResultContent } from '../types'\nimport { Buffer } from 'node:buffer'\nimport { errorMessage } from '../errors'\nimport { reconcileImageMediaType, reconcileMediaType, sniffImageMediaTypeFromBase64, sniffMediaTypeFromBase64 } from '../tools/media-sniff'\nimport { toolOutputByteLength, toolResultToText } from '../types'\nimport { hasAuthorizationHeader } from './oauth-provider'\nimport { sseToJsonFetchIfNeeded } from './sse-to-json-fetch'\nimport { createTolerantClient } from './tolerant-client'\n\n/**\n * Subset of the MCP SDK's `Transport` interface that `bootstrapServer` needs\n * to clean up. Typed structurally so a failed `createTransport()` doesn't\n * force us to pull the SDK's full transport type into our static graph.\n */\ninterface ClosableTransport {\n close: () => void | Promise<void>\n}\n\n// NOTE: `@modelcontextprotocol/sdk` is an *optional* peer dependency\n// (see package.json). Static imports here would force every consumer of\n// `zidane` to install the SDK even if they never wire any MCP servers —\n// which fails on install with `--no-optional` or in restricted CI\n// environments. All runtime imports are inside `createTransport` /\n// `loadTolerantClient` below so the SDK is only resolved when MCP is\n// actually used. Type-only imports above are erased at compile time.\n\nexport type { McpServerConfig, McpToolSchema } from '../types'\n\nexport interface McpConnection {\n tools: Record<string, ToolDef>\n /**\n * Per-server `instructions` payload from the MCP `initialize` handshake,\n * keyed by server name. Each server may return free-form guidance the\n * model is meant to read alongside the tool catalog — typical content\n * is \"the database is already provisioned, use `apply_migration`\n * directly\" or \"always wrap SELECTs in a transaction\". The agent\n * renders these into a system-prompt section when\n * `behavior.surfaceMcpInstructions` is on (default).\n *\n * Servers that omit the field, return an empty string, or fail to\n * connect contribute no entry. Lazy-connected servers contribute an\n * entry only once their first connect resolves — until then the model\n * never sees their instructions, matching the schema-loading semantics\n * of `lazyConnect`.\n *\n * Map (not Record) so insertion order matches server config order and\n * the rendered section is byte-stable for the cache breakpoint.\n *\n * Optional so custom `mcpConnector` implementations from before this\n * field existed still type-check; the framework's own\n * `connectMcpServers` always returns a Map (possibly empty).\n */\n instructions?: Map<string, string>\n close: () => Promise<void>\n}\n\n/**\n * Recover a discovered tool's `{ server, toolName }` from its namespaced name\n * (`mcp_<server>_<tool>`). Both server and tool names can contain underscores,\n * so this matches against the known server list by longest server-name prefix\n * rather than splitting blindly. Tools that match no configured server (custom\n * connectors with a different naming scheme) fall back to\n * `{ server: '', toolName: <namespacedName> }`.\n */\nexport function deriveMcpToolMeta(namespacedName: string, servers: readonly McpServerConfig[]): McpToolMeta {\n let best: McpServerConfig | undefined\n for (const server of servers) {\n const prefix = `mcp_${server.name}_`\n if (namespacedName.startsWith(prefix) && (!best || server.name.length > best.name.length))\n best = server\n }\n if (best)\n return { server: best.name, toolName: namespacedName.slice(`mcp_${best.name}_`.length) }\n return { server: '', toolName: namespacedName }\n}\n\n/**\n * Apply an {@link McpToolWrap} to every entry of a discovered-tool map,\n * resolving each tool's {@link McpToolMeta} from `servers`. Returns a fresh\n * map; the input is untouched. Used by the agent to apply the\n * `AgentOptions.mcpToolWrap` hook to discovered tools.\n */\nexport function wrapDiscoveredMcpTools(\n tools: Record<string, ToolDef>,\n wrap: McpToolWrap,\n servers: readonly McpServerConfig[],\n): Record<string, ToolDef> {\n const wrapped: Record<string, ToolDef> = {}\n for (const [name, def] of Object.entries(tools))\n wrapped[name] = wrap(def, deriveMcpToolMeta(name, servers))\n return wrapped\n}\n\n// ---------------------------------------------------------------------------\n// Shape normalization\n// ---------------------------------------------------------------------------\n\ninterface RawServerShape {\n name?: string\n transport?: string\n type?: string\n command?: string\n args?: string[]\n env?: Record<string, string>\n strictEnv?: boolean\n cwd?: string\n url?: string\n httpUrl?: string\n sseUrl?: string\n headers?: Record<string, string>\n bootstrapTimeout?: number\n toolTimeout?: number\n closeTimeout?: number\n enabledTools?: string[]\n disabledTools?: string[]\n toolFilter?: McpServerConfig['toolFilter']\n disclosure?: McpServerConfig['disclosure']\n cachedTools?: McpServerConfig['cachedTools']\n lazyConnect?: boolean\n /** Canonical OAuth flag. */\n auth?: McpServerConfig['auth']\n /** Cursor runtime-state alias for `auth: 'oauth'`. */\n authMethod?: string\n [key: string]: unknown\n}\n\nconst DEFAULT_MCP_BOOTSTRAP_TIMEOUT_MS = 10_000\nconst DEFAULT_MCP_CLOSE_TIMEOUT_MS = 5_000\n\n// ---------------------------------------------------------------------------\n// Bootstrap-internal helpers (hook safety + cleanup + error hints)\n//\n// These keep `bootstrapServer` and `connectMcpServers` readable while\n// providing three guarantees the bootstrap contract relies on:\n//\n// 1. A misbehaving hook handler MUST NOT take down the whole batch — the\n// partial-failure tolerance (`Promise.allSettled` in the caller plus\n// this safe-fire helper) means one bad listener degrades to a debug\n// log instead of \"no MCP tools at all\".\n// 2. A timed-out / failed bootstrap MUST close its transport explicitly,\n// not just the SDK client. Until `Protocol.connect(transport)` has\n// wired the transport into the client, `client.close()` doesn't know\n// about it and the underlying stdio subprocess / HTTP connection\n// lingers until GC.\n// 3. Transport-mismatch failures (the common `type: 'http'` vs SSE-only\n// server case from downstream reports) MUST surface an actionable\n// hint in the error message, not just `HTTP 405`.\n// ---------------------------------------------------------------------------\n\n/**\n * Fire a hook without letting a listener's rejection escape. A throwing\n * listener used to bring down the whole `Promise.all` in\n * `connectMcpServers`, defeating the batch's partial-failure tolerance.\n *\n * Failures are swallowed; under `ZIDANE_DEBUG` they're traced to stderr\n * so the misbehaving listener is still discoverable when a host opts in.\n *\n * `args` is variadic to match `Hookable.callHook`'s spread shape; in\n * practice every `AgentHooks` event takes a single context object.\n */\nasync function safeCallHook<K extends keyof AgentHooks & string>(\n hooks: Hookable<AgentHooks> | undefined,\n event: K,\n ...args: Parameters<AgentHooks[K]>\n): Promise<void> {\n if (!hooks)\n return\n try {\n await hooks.callHook(event, ...args)\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/mcp] hook \"${event}\" listener rejected: ${errorMessage(err)}\\n`)\n }\n}\n\n/**\n * Close a transport best-effort. The catch swallows everything — by the\n * time we're closing, the bootstrap has already failed and the only thing\n * worse than a leaked transport is a leaked transport AND a new error\n * masking the original cause.\n */\nasync function closeTransportQuietly(transport: ClosableTransport | null): Promise<void> {\n if (!transport)\n return\n try {\n await transport.close()\n }\n catch {\n // Original bootstrap error is more actionable.\n }\n}\n\n/**\n * Read the child PID off a stdio transport. Structural — only\n * `StdioClientTransport` exposes `pid`; HTTP/SSE transports return `null`.\n * Returns `null` once the child has exited (the SDK clears its process\n * reference on the child's `close` event), so a kill based on this value\n * never targets a recycled PID.\n */\nfunction stdioPidOf(transport: unknown): number | null {\n const pid = (transport as { pid?: unknown } | null | undefined)?.pid\n return typeof pid === 'number' ? pid : null\n}\n\n/**\n * Last-resort reaper for a stdio child whose transport close wedged. By the\n * time this runs, the graceful path (stdin EOF → SIGTERM escalation inside\n * the SDK, where the installed version implements it) has been abandoned —\n * SIGKILL is the only signal a hung child can't ignore. ESRCH (already\n * exited) is swallowed.\n */\nfunction killStdioChild(pid: number | null): void {\n if (pid == null)\n return\n try {\n process.kill(pid, 'SIGKILL')\n }\n catch {\n // Child already exited between PID capture and the kill.\n }\n}\n\n/**\n * Detect failure signatures that point at a transport mismatch and return\n * an actionable hint string. Conservative — only matches the signals we've\n * actually observed in the wild against MCP servers, so a real outage on\n * the right transport doesn't get misdiagnosed.\n *\n * Streamable-HTTP against an SSE-only endpoint:\n * - The transport opens an `initialize` POST. SSE-only servers respond\n * with `405 Method Not Allowed` or `404 Not Found` (their `/sse` GET\n * endpoint is the only handler). The SDK wraps these as\n * `Error POSTing to endpoint (HTTP 40X): ...`.\n * - Some proxies return `400` with a `text/event-stream` mismatch on\n * POST; same root cause, same fix.\n */\nfunction buildTransportMismatchHint(transport: McpServerConfig['transport'], err: Error): string | null {\n const msg = err.message\n if (transport === 'streamable-http') {\n if (/\\bHTTP\\s*40[45]\\b/i.test(msg) || /\\(40[45]\\)/.test(msg))\n return 'This server may not implement the streamable-HTTP transport. Try `transport: \\'sse\\'` (or `sseUrl` instead of `url`) on this server\\'s config.'\n }\n return null\n}\n\n/**\n * Wrap a bootstrap failure so the surfaced `Error` carries an actionable\n * hint while preserving the original message + stack + cause. Returns the\n * input error verbatim when no hint applies.\n *\n * `cause` (ES2022) gives hosts that introspect a way back to the raw SDK\n * error; the human-readable hint is the new message body that lands in\n * logs / hook payloads.\n */\nfunction withTransportMismatchHint(transport: McpServerConfig['transport'], err: Error): Error {\n const hint = buildTransportMismatchHint(transport, err)\n if (!hint)\n return err\n const augmented = new Error(`${err.message}\\nHint: ${hint}`, { cause: err })\n if (err.stack)\n augmented.stack = err.stack\n return augmented\n}\n\nfunction inferTransport(raw: RawServerShape): McpServerConfig['transport'] {\n if (raw.transport === 'stdio' || raw.transport === 'sse' || raw.transport === 'streamable-http')\n return raw.transport\n if (raw.type === 'stdio' || raw.type === 'sse' || raw.type === 'streamable-http' || raw.type === 'http')\n return raw.type === 'http' ? 'streamable-http' : raw.type\n if (raw.command)\n return 'stdio'\n if (raw.httpUrl)\n return 'streamable-http'\n if (raw.sseUrl)\n return 'sse'\n if (raw.url)\n return 'streamable-http'\n throw new Error(`Cannot infer MCP transport from config: ${JSON.stringify(raw)}`)\n}\n\nfunction normalizeOne(name: string, raw: RawServerShape): McpServerConfig {\n const transport = inferTransport(raw)\n const url = raw.url ?? raw.httpUrl ?? raw.sseUrl\n\n const config: McpServerConfig = { name, transport }\n if (raw.command)\n config.command = raw.command\n if (raw.args)\n config.args = raw.args\n if (raw.env)\n config.env = raw.env\n if (raw.strictEnv === true)\n config.strictEnv = true\n if (typeof raw.cwd === 'string' && raw.cwd.length > 0)\n config.cwd = raw.cwd\n if (url)\n config.url = url\n if (raw.headers)\n config.headers = raw.headers\n if (typeof raw.bootstrapTimeout === 'number')\n config.bootstrapTimeout = raw.bootstrapTimeout\n if (typeof raw.toolTimeout === 'number')\n config.toolTimeout = raw.toolTimeout\n if (typeof raw.closeTimeout === 'number')\n config.closeTimeout = raw.closeTimeout\n if (Array.isArray(raw.enabledTools))\n config.enabledTools = raw.enabledTools\n if (Array.isArray(raw.disabledTools))\n config.disabledTools = raw.disabledTools\n if (typeof raw.toolFilter === 'function')\n config.toolFilter = raw.toolFilter\n if (raw.disclosure === 'eager' || raw.disclosure === 'lazy')\n config.disclosure = raw.disclosure\n if (Array.isArray(raw.cachedTools))\n config.cachedTools = raw.cachedTools\n if (raw.lazyConnect === true)\n config.lazyConnect = true\n // Canonical `auth` field; also recognize Cursor's `authMethod: 'mcpOAuth'`\n // runtime-state shape so pasted ~/.cursor/mcp.json entries Just Work.\n if (raw.auth === 'oauth' || raw.authMethod === 'mcpOAuth')\n config.auth = 'oauth'\n\n return config\n}\n\n/**\n * True when the input looks like a single config object (flat fields like `command`,\n * `transport`, `url`) rather than a record whose values are configs.\n */\nfunction looksLikeSingleConfig(obj: Record<string, unknown>): boolean {\n const singleConfigKeys = ['transport', 'type', 'command', 'url', 'httpUrl', 'sseUrl']\n return singleConfigKeys.some(key => typeof obj[key] === 'string')\n}\n\n/**\n * Normalize MCP server configs from any common shape to `McpServerConfig[]`.\n *\n * Accepts:\n * - `McpServerConfig[]` — zidane native (pass-through).\n * - `McpServerConfig` — a single config object (wrapped to a 1-element array).\n * - `Record<string, RawShape>` — name-keyed map (common in host-SDK configs), where the key is the server name.\n * - Mixed shapes with `type` vs `transport`, `httpUrl`/`sseUrl` vs `url`.\n *\n * Returns `[]` when `input` is nullish. Throws a descriptive error when the transport\n * cannot be inferred from a given entry, or when the input shape is unsupported.\n */\nexport function normalizeMcpServers(input: unknown): McpServerConfig[] {\n if (input == null)\n return []\n\n if (Array.isArray(input)) {\n return input.map((raw, idx) => {\n const obj = raw as RawServerShape\n const name = obj.name ?? `mcp_${idx}`\n return normalizeOne(name, obj)\n })\n }\n\n if (typeof input === 'object') {\n const obj = input as Record<string, unknown>\n // Single-config heuristic: flat fields like `transport`/`command`/`url` at the top\n // level indicate a single McpServerConfig, not a record of configs.\n if (looksLikeSingleConfig(obj)) {\n const raw = obj as RawServerShape\n const name = raw.name ?? 'mcp_0'\n return [normalizeOne(name, raw)]\n }\n return Object.entries(obj as Record<string, RawServerShape>).map(\n ([name, raw]) => normalizeOne(name, raw ?? {}),\n )\n }\n\n throw new Error(`Unsupported MCP server config shape: ${typeof input}`)\n}\n\n/**\n * Lossy flattener — converts MCP `CallToolResult.content` blocks to a single\n * string. Text blocks are extracted; non-text blocks are JSON-stringified.\n *\n * Use this only at UI / log boundaries that require a string. The agent\n * loop itself routes through {@link normalizeMcpBlocks} so image blocks\n * survive into provider-native tool_result content (Anthropic blocks,\n * OpenAI companion-user-message).\n */\nexport function resultToString(content: unknown): string {\n if (!content || !Array.isArray(content))\n return ''\n return content\n .map((block) => {\n if (block && typeof block === 'object' && (block as { type?: unknown }).type === 'text') {\n const text = (block as { text?: unknown }).text\n if (typeof text === 'string')\n return text\n }\n return JSON.stringify(block)\n })\n .join('\\n')\n}\n\n/**\n * Resolve the media type for an audio/video content block whose `data` we have.\n *\n * MCP declares `mimeType` on these blocks, but it's frequently missing or\n * imprecise. Strategy: when the declared type is a recognized member of the\n * kind's family, reconcile it against the bytes (override only on a positive\n * different match); otherwise sniff from scratch; otherwise fall back to a\n * sensible default for the kind.\n */\nfunction resolveMediaType(kind: 'audio' | 'video', declared: unknown, b64: string): string {\n const prefix = `${kind}/`\n const fallback = kind === 'audio' ? 'audio/wav' : 'video/mp4'\n if (typeof declared === 'string' && declared.startsWith(prefix))\n return reconcileMediaType(kind, declared, b64)\n return sniffMediaTypeFromBase64(kind, b64) ?? fallback\n}\n\n/**\n * Turn an embedded-resource blob into the matching media block, choosing the\n * kind from the declared `mimeType` prefix when recognized, else by sniffing\n * the bytes (image → audio → video). Returns `null` when nothing identifies it\n * as media, so the caller can fall back to the JSON-stringify path.\n */\nfunction mediaBlockFromBlob(mimeType: string | undefined, b64: string): ToolResultContent | null {\n // Sniff each family up front. This lets bytes correct a wrong declared\n // family (e.g. `image/png` metadata around an MP3 blob) while still keeping\n // declared metadata when no positive identification is possible.\n const image = sniffImageMediaTypeFromBase64(b64)\n const audio = sniffMediaTypeFromBase64('audio', b64)\n const video = sniffMediaTypeFromBase64('video', b64)\n\n if (mimeType?.startsWith('image/')) {\n if (image)\n return { type: 'image', mediaType: image, data: b64 }\n if (audio)\n return { type: 'audio', mediaType: audio, data: b64 }\n if (video)\n return { type: 'video', mediaType: video, data: b64 }\n return { type: 'image', mediaType: mimeType, data: b64 }\n }\n if (mimeType?.startsWith('audio/')) {\n if (audio)\n return { type: 'audio', mediaType: reconcileMediaType('audio', mimeType, b64), data: b64 }\n if (image)\n return { type: 'image', mediaType: image, data: b64 }\n if (video)\n return { type: 'video', mediaType: video, data: b64 }\n return { type: 'audio', mediaType: mimeType, data: b64 }\n }\n if (mimeType?.startsWith('video/')) {\n if (video)\n return { type: 'video', mediaType: reconcileMediaType('video', mimeType, b64), data: b64 }\n if (image)\n return { type: 'image', mediaType: image, data: b64 }\n if (audio)\n return { type: 'audio', mediaType: audio, data: b64 }\n return { type: 'video', mediaType: mimeType, data: b64 }\n }\n\n // No usable declared type — route by sniffed bytes.\n if (image)\n return { type: 'image', mediaType: image, data: b64 }\n if (audio)\n return { type: 'audio', mediaType: audio, data: b64 }\n if (video)\n return { type: 'video', mediaType: video, data: b64 }\n return null\n}\n\n/**\n * Normalize MCP `CallToolResult.content` to zidane's {@link ToolResultContent[]} shape.\n *\n * Handles the MCP content block types:\n * - `text` → preserved as `{type:'text', text}`\n * - `image` → preserved as `{type:'image', mediaType, data}` (MCP uses `mimeType`)\n * - `audio` → `{type:'audio', mediaType, data}`; mediaType reconciled/sniffed when\n * the declared `mimeType` is missing or not an `audio/*` type\n * - `video` → `{type:'video', mediaType, data}` (non-standard, by analogy)\n * - `resource` with embedded text → flattened to a text block\n * - `resource` with embedded blob → routed to image/audio/video by sniffing bytes\n * first, with declared `mimeType` as a fallback when bytes are unidentifiable\n * (it's OPTIONAL on EmbeddedResource per the MCP spec, and often imprecise)\n * - Any unrecognized block → JSON-stringified fallback text block (lossy but safe)\n *\n * Returns `null` when the input is not an array — callers should fall back to an empty\n * result in that case.\n */\nexport function normalizeMcpBlocks(content: unknown): ToolResultContent[] | null {\n if (!Array.isArray(content))\n return null\n\n const out: ToolResultContent[] = []\n for (const raw of content) {\n if (!raw || typeof raw !== 'object')\n continue\n const block = raw as Record<string, unknown>\n\n if (block.type === 'text' && typeof block.text === 'string') {\n out.push({ type: 'text', text: block.text })\n continue\n }\n\n if (block.type === 'image' && typeof block.data === 'string') {\n const declared = typeof block.mimeType === 'string'\n ? block.mimeType\n : (typeof block.mediaType === 'string' ? block.mediaType : 'image/png')\n // Anthropic rejects the request when `media_type` disagrees with the\n // magic bytes. Some MCP servers (browser/screenshot bridges) declare\n // `image/webp` while actually serving JPEG; reconcile here so the\n // wrong label never reaches the provider.\n const mediaType = reconcileImageMediaType(declared, block.data)\n out.push({ type: 'image', mediaType, data: block.data })\n continue\n }\n\n // MCP `audio` blocks mirror `image`: { type, data (base64), mimeType }.\n if (block.type === 'audio' && typeof block.data === 'string') {\n out.push({ type: 'audio', mediaType: resolveMediaType('audio', block.mimeType ?? block.mediaType, block.data), data: block.data })\n continue\n }\n\n // Non-standard `video` blocks (some servers emit them by analogy to audio).\n if (block.type === 'video' && typeof block.data === 'string') {\n out.push({ type: 'video', mediaType: resolveMediaType('video', block.mimeType ?? block.mediaType, block.data), data: block.data })\n continue\n }\n\n if (block.type === 'resource' && block.resource && typeof block.resource === 'object') {\n const res = block.resource as Record<string, unknown>\n if (typeof res.text === 'string') {\n out.push({ type: 'text', text: res.text })\n continue\n }\n if (typeof res.blob === 'string') {\n // `mimeType` is OPTIONAL on EmbeddedResource per the MCP spec, and even\n // when present it's frequently wrong/imprecise. Pick the kind by the\n // declared prefix when it's a recognized media family; otherwise sniff\n // the bytes so a valid but unlabeled media blob isn't lost to the\n // JSON-stringify fallback below.\n const mediaBlock = mediaBlockFromBlob(typeof res.mimeType === 'string' ? res.mimeType : undefined, res.blob)\n if (mediaBlock) {\n out.push(mediaBlock)\n continue\n }\n }\n }\n\n // resource_link, non-media blobs, and unknown block shapes — fall back to a\n // JSON-stringified text block. Lossy but keeps the info addressable.\n out.push({ type: 'text', text: JSON.stringify(block) })\n }\n\n return out\n}\n\n/**\n * Route the MCP result content through the narrowest appropriate zidane shape:\n *\n * - All blocks are `text` → return a joined string (smaller wire payload,\n * string-friendly for hook consumers that don't need structured access).\n * - Any block is non-text → return a structured `ToolResultContent[]`.\n * - Empty / non-array input → return `''`.\n */\nfunction packMcpResult(content: unknown): string | ToolResultContent[] {\n const normalized = normalizeMcpBlocks(content)\n if (!normalized || normalized.length === 0)\n return ''\n\n // Single pass: build the joined string as we go. Bail to the structured array\n // the moment we hit a non-text block.\n const parts: string[] = []\n for (const block of normalized) {\n if (block.type !== 'text')\n return normalized\n parts.push(block.text)\n }\n return parts.join('\\n')\n}\n\n/**\n * Create the appropriate MCP transport for a server config.\n *\n * For stdio: when `config.env` is provided, it is merged on top of the MCP SDK's\n * `getDefaultEnvironment()` whitelist (`PATH`, `HOME`, `LANG`, `SHELL`, `USER` on\n * POSIX; `APPDATA`, `PATH`, ... on Win32). Without this defensive merge, older\n * MCP SDK versions strip `PATH` the moment a consumer sets any env, breaking\n * `spawn('node', ...)` with ENOENT. Pass `strictEnv: true` to opt out and send\n * `env` verbatim.\n *\n * `config.cwd` is forwarded to `StdioClientTransport` (→ `spawn`'s `cwd`).\n * Without this, the child inherits the agent's cwd, breaking servers that\n * resolve paths relative to their own working directory (e.g. project-root\n * MCPs reading `<root>/db/migrations/...`).\n */\nasync function createTransport(\n config: McpServerConfig,\n authProvider?: OAuthClientProvider,\n hooks?: Hookable<AgentHooks>,\n) {\n switch (config.transport) {\n case 'stdio': {\n // Routed through `./stdio-loader.ts` so the SDK's stdio transport\n // lives in zidane's static module graph at build time. That lets the\n // `cross-spawn` → shim alias in `tsdown.config.ts` fire and removes\n // the bare `require('child_process')` from the chunk that downstream\n // consumers re-bundle. See `./stdio-loader.ts` for the full story.\n const { StdioClientTransport, getDefaultEnvironment } = await import('./stdio-loader')\n const mergedEnv = config.env && !config.strictEnv\n ? { ...getDefaultEnvironment(), ...config.env }\n : config.env\n const transport = new StdioClientTransport({\n command: config.command!,\n args: config.args,\n env: mergedEnv,\n // By default `inherit` prints stdio from server into TUI framebuffer\n // and breaks UI, we'll pipe output to `mcp:warn` hook\n stderr: 'pipe',\n ...(config.cwd ? { cwd: config.cwd } : {}),\n })\n attachStderrWarnPump(transport, config.name, hooks)\n return transport\n }\n case 'sse': {\n const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js')\n return new SSEClientTransport(new URL(config.url!), {\n requestInit: config.headers ? { headers: config.headers } : undefined,\n authProvider,\n })\n }\n case 'streamable-http': {\n // `fetch: sseToJsonFetchIfNeeded()` works around a Bun + MCP SDK\n // 1.29.x bug where `text/event-stream` POST responses are buffered\n // correctly but never surface to `onmessage`, dead-locking bootstrap.\n // The helper returns the wrapper only on Bun and `undefined` on Node\n // (so the SDK's streaming pipeline stays intact where it works).\n // See ./sse-to-json-fetch.ts.\n const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js')\n return new StreamableHTTPClientTransport(new URL(config.url!), {\n requestInit: config.headers ? { headers: config.headers } : undefined,\n fetch: sseToJsonFetchIfNeeded(),\n authProvider,\n })\n }\n default:\n throw new Error(`Unknown MCP transport: ${config.transport}`)\n }\n}\n\n/**\n * Split a stdio-transport child's stderr into lines and surface them via `mcp:warn`.\n */\nconst MAX_MCP_STDERR_LINE_CHARS = 64 * 1024\n\nexport function attachStderrWarnPump(\n // Structural: SDK types `stderr` as Node's generic `Stream`, but at runtime\n // it's a `Readable`. Loose-typed listener so this matches the SDK shape.\n transport: { stderr?: { on: (event: string, listener: (...args: unknown[]) => void) => unknown } | null },\n serverName: string,\n hooks: Hookable<AgentHooks> | undefined,\n): void {\n const stream = transport.stderr\n if (!stream)\n return\n let buffer = ''\n const emitLine = (line: string): void => {\n const trimmed = line.replace(/\\r$/, '').trim()\n if (trimmed.length === 0)\n return\n // Don't await — a slow handler must not backpressure the child.\n // Also swallow listener failures; stderr capture is diagnostic-only.\n const pending = hooks?.callHook('mcp:warn', { name: serverName, message: trimmed })\n void pending?.catch(() => {})\n }\n const flush = (): void => {\n if (buffer.length === 0)\n return\n emitLine(buffer)\n buffer = ''\n }\n // Must consume — leaving the stream unread hangs the child once the\n // OS pipe (~64 KiB) fills.\n stream.on('data', (chunk: unknown) => {\n // Node stream `data` events deliver Buffer | string (non-objectMode).\n buffer += typeof chunk === 'string' ? chunk : (chunk as Buffer).toString('utf8')\n let nl = buffer.indexOf('\\n')\n while (nl !== -1) {\n const line = buffer.slice(0, nl)\n buffer = buffer.slice(nl + 1)\n emitLine(line)\n nl = buffer.indexOf('\\n')\n }\n while (buffer.length >= MAX_MCP_STDERR_LINE_CHARS) {\n emitLine(buffer.slice(0, MAX_MCP_STDERR_LINE_CHARS))\n buffer = buffer.slice(MAX_MCP_STDERR_LINE_CHARS)\n }\n })\n // Connection liveness flows through the SDK's own onclose/onerror → `mcp:error`.\n stream.on('end', flush)\n stream.on('close', flush)\n stream.on('error', flush)\n}\n\n/**\n * True when an error from `client.connect()` indicates the user needs to\n * (re-)authenticate against the MCP server. Two signal families:\n *\n * 1. **SDK-formal** — the MCP SDK confirmed the resource is OAuth-protected\n * (RFC 9728 metadata advertised) and threw `UnauthorizedError`. Detected\n * by class name + \"Unauthorized\" message prefix, since the SDK's\n * `UnauthorizedError` class isn't a stable export across versions.\n *\n * 2. **Raw HTTP 401 with token-rejection signal** — some real-world servers\n * (Linear is one) skip the RFC 9728 dance and just return `HTTP 401`\n * with an OAuth-style JSON body (`{\"error\":\"invalid_token\"}` /\n * `\"invalid_grant\"` / `\"insufficient_scope\"`). The MCP SDK wraps that\n * into `\"Error POSTing to endpoint (HTTP 401): { ... }\"`. Without\n * promotion, a stale Linear token reads as a generic `mcp:error`\n * bootstrap failure instead of \"needs login\" — the user gets a noisy\n * red banner instead of a re-login affordance.\n *\n * Promotion to the skip+auth-required path is still gated on\n * `explicitAuth || eligibleAutoPromote` in the caller, so a server that\n * legitimately requires a static `Authorization: Bearer …` header (no\n * `auth: 'oauth'` flag, host-provided header) won't be mis-promoted into\n * a doomed OAuth flow.\n */\nfunction isUnauthorizedError(err: unknown): boolean {\n if (!err || typeof err !== 'object')\n return false\n const e = err as { name?: string, message?: string, constructor?: { name?: string } }\n if (e.name === 'UnauthorizedError' || e.constructor?.name === 'UnauthorizedError')\n return true\n const message = typeof e.message === 'string' ? e.message : ''\n if (message.toLowerCase().startsWith('unauthorized'))\n return true\n // Raw HTTP 401 with an OAuth-style token-rejection body — the\n // streamable-http transport surfaces these as `Error POSTing to endpoint\n // (HTTP 401): {\"error\":\"invalid_token\",\"error_description\":\"…\"}`.\n if (/\\bHTTP\\s*401\\b/i.test(message) || /\\b\\(401\\)/.test(message)) {\n if (/\"error\"\\s*:\\s*\"(?:invalid_token|invalid_grant|insufficient_scope|invalid_client)\"/i.test(message))\n return true\n }\n return false\n}\n\n/**\n * Optional knobs threaded into per-server bootstrap. Reserved for runtime\n * concerns the agent shell injects (credential storage, OAuth providers);\n * the `McpServerConfig` shape stays pure data.\n */\nexport interface ConnectMcpServersOptions {\n /**\n * Build a non-interactive `OAuthClientProvider` for a given server. Called\n * lazily — only invoked when the bootstrap actually needs auth (explicit\n * `auth: 'oauth'` flag, or a UnauthorizedError that meets the auto-detect\n * criteria). Return `undefined` to opt this server out of OAuth even if it\n * was requested (e.g. the host doesn't have a credential store for it).\n *\n * \"Non-interactive\" — the provider must NOT trigger a browser flow during\n * bootstrap. Use a `redirectUri` of `undefined` so the SDK reads stored\n * tokens, refreshes on expiry, and throws `UnauthorizedError` if tokens\n * are missing or refresh fails. The host then surfaces an\n * `mcp:auth:required` event so the user can opt in to interactive login.\n */\n buildAuthProvider?: (config: McpServerConfig) => OAuthClientProvider | undefined\n}\n\n/**\n * Internal: shape received by the `_clientFactory` test-injection seam.\n * Mirrors the subset of `TolerantClientOptions` the bootstrap path forwards\n * so a mock client can opt into the same lifecycle wiring (warning sink,\n * future seams) instead of silently bypassing it.\n */\ninterface McpClientFactoryOptions {\n /** See `TolerantClientOptions.onWarning`. */\n onWarning?: (message: string) => void\n}\n\ntype McpClientFactory = (opts?: McpClientFactoryOptions) => Client\n\n/**\n * Connect to MCP servers and discover their tools.\n *\n * Each tool is namespaced as `mcp_{serverName}_{toolName}` to avoid\n * collisions with agent tools or tools from other servers.\n *\n * @param configs - Array of MCP server configurations\n * @param _clientFactory - Internal: override client construction for testing\n * @param hooks - Optional agent hooks for firing mcp:connect, mcp:error, mcp:close events\n * @param options - Optional bootstrap knobs (e.g. OAuth provider injection)\n */\nexport async function connectMcpServers(\n configs: McpServerConfig[],\n _clientFactory?: McpClientFactory,\n hooks?: Hookable<AgentHooks>,\n options?: ConnectMcpServersOptions,\n): Promise<McpConnection> {\n // Per-server cleanup closure. Eager entries always have a live client; lazy\n // entries may or may not have connected — `closeIfConnected` short-circuits\n // when nothing was opened, and awaits any in-flight connect to avoid\n // leaking the resulting client past `close()`.\n //\n // `stdioPid` exposes the live stdio child's PID so the bounded `close()`\n // below can SIGKILL a child whose transport close wedged. It must be read\n // BEFORE initiating the close — the SDK's stdio transport clears its\n // process reference the moment `close()` starts, so there is nothing left\n // to read once the close has hung.\n const connections: {\n name: string\n closeTimeout: number\n closeIfConnected: () => Promise<void>\n stdioPid?: () => number | null\n }[] = []\n const tools: Record<string, ToolDef> = {}\n // Insertion-ordered (config order) so the rendered system-prompt section is\n // byte-stable across runs. Only populated from eager-connect successes;\n // `lazyConnect: true` servers do NOT contribute here because pulling their\n // instructions would force the connection the host asked to defer.\n const instructions = new Map<string, string>()\n const errors: { name: string, error: Error }[] = []\n let closed = false\n\n // Bootstrap every server in parallel. Previously this was a sequential for-loop,\n // which meant a single slow server (GitHub MCP, cold streamable-http endpoints,\n // anything on a flaky network) blocked the whole first `agent.run()` for up to\n // N × bootstrapTimeout.\n //\n // `Promise.allSettled` (not `Promise.all`) is the final safety net for the\n // partial-failure tolerance: `bootstrapServer` already internalises every\n // expected throw, but a future regression (or a misbehaving hook that\n // sneaks past `safeCallHook`) would otherwise reject the whole batch and\n // wipe out every other server's connection. Converting a rejection back\n // into an `{ ok: false }` result keeps the batch alive.\n const settled = await Promise.allSettled(configs.map(config => bootstrapServer(config, _clientFactory, hooks, options)))\n const bootstrapResults: BootstrapResult[] = settled.map((result, idx) => {\n if (result.status === 'fulfilled')\n return result.value\n const error = result.reason instanceof Error ? result.reason : new Error(String(result.reason))\n return { ok: false, name: configs[idx]!.name, error, durationMs: 0 }\n })\n\n // Deterministic batch aggregate. The per-server `mcp:bootstrap:end`\n // events above fire in network-completion order inside the parallel\n // bootstrap — fine for live dashboards, hostile to durable-execution\n // hosts that journal hook payloads. One name-sorted event per batch\n // gives them a replay-stable summary without buffer-and-sort glue.\n if (configs.length > 0) {\n const settledResults = bootstrapResults\n .map((result, idx) => {\n const transport = configs[idx]!.transport\n if (result.ok) {\n return {\n name: result.name,\n transport,\n durationMs: result.durationMs,\n ok: true as const,\n toolCount: result.tools.length,\n ...(result.lazy ? { lazy: true } : {}),\n }\n }\n return {\n name: result.name,\n transport,\n durationMs: result.durationMs,\n ok: false as const,\n ...(result.skipped ? { skipped: true } : {}),\n ...('error' in result && result.error ? { error: result.error } : {}),\n }\n })\n .sort((a, b) => a.name.localeCompare(b.name))\n await safeCallHook(hooks, 'mcp:bootstrap:settled', { results: settledResults })\n }\n\n for (const result of bootstrapResults) {\n if (result.skipped) {\n // Auth required but no tokens — already emitted `mcp:auth:required`.\n // Bootstrap continues with the other servers; the user opts in via\n // the host's interactive login path (`loginMcpServer`).\n continue\n }\n if (!result.ok) {\n errors.push({ name: result.name, error: result.error })\n await safeCallHook(hooks, 'mcp:error', { name: result.name, error: result.error })\n continue\n }\n\n const toolNames: string[] = result.tools.map(t => `mcp_${result.config.name}_${t.name}`)\n // Build a per-server `getClient` resolver before assembling the tool\n // defs. Lazy servers wrap it with a one-shot `mcp:connect` emitter so\n // the hook fires on the first successful connect (concurrent first\n // calls converge on the same connector — the wrapper guards against\n // double-fires). Eager servers fire `mcp:connect` synchronously below.\n const getClient = result.lazy\n ? wrapConnectWithHookFire(\n () => result.handle.connect(),\n onceFireConnect(result.name, result.config.transport, toolNames, hooks),\n )\n : (() => {\n const client = result.client\n return () => Promise.resolve(client)\n })()\n\n for (let i = 0; i < result.tools.length; i++) {\n tools[toolNames[i]!] = buildMcpToolDef(result.config, getClient, result.tools[i]!, toolNames[i]!, hooks)\n }\n\n const closeTimeout = result.config.closeTimeout ?? DEFAULT_MCP_CLOSE_TIMEOUT_MS\n if (result.lazy) {\n // No `mcp:connect` here — fires on first call via the wrapper above.\n const handle = result.handle\n const name = result.name\n connections.push({\n name,\n closeTimeout,\n closeIfConnected: async () => {\n // Probe lazy state BEFORE emitting `mcp:close` so a server that\n // was never used produces no close-noise. The handle's\n // `closeIfConnected` is a no-op when nothing was started; we\n // emit the hook only when a real close is about to happen.\n await safeCallHook(hooks, 'mcp:close', { name })\n await handle.closeIfConnected()\n },\n ...(result.config.transport === 'stdio' ? { stdioPid: handle.stdioPid } : {}),\n })\n }\n else {\n const eagerClient = result.client\n const eagerTransport = result.transport\n connections.push({\n name: result.name,\n closeTimeout,\n closeIfConnected: async () => {\n await safeCallHook(hooks, 'mcp:close', { name: result.name })\n await eagerClient.close()\n },\n ...(result.config.transport === 'stdio' ? { stdioPid: () => stdioPidOf(eagerTransport) } : {}),\n })\n // Eager-only — see `instructions` declaration above for the lazy\n // exclusion rationale.\n if (result.instructions !== undefined)\n instructions.set(result.name, result.instructions)\n await safeCallHook(hooks, 'mcp:connect', {\n name: result.name,\n transport: result.config.transport,\n tools: toolNames,\n })\n }\n }\n\n // Total failure is tolerated the same way partial failure is — every server\n // already fired `mcp:error` (and `mcp:bootstrap:end` with `ok: false`), so\n // the host can render status / re-auth UI from the hook stream. Throwing\n // here used to wedge `agent.run()` on the user's first message whenever a\n // single misconfigured / expired-token server was the only MCP configured\n // (e.g. Linear's stored token expired → HTTP 401 doesn't match our\n // \"Unauthorized\" prefix check → all-failed → throw → chat shows red bubble\n // instead of the assistant reply). Returning an empty toolset lets the\n // run proceed with no MCP tools; the next bootstrap retries automatically\n // (see `mcpWarmupPromise` reset in `agent.ts`).\n\n return {\n tools,\n instructions,\n close: async () => {\n // Idempotent — double-close on `agent.destroy()` retry should not\n // re-fire the hook or call `client.close()` twice (the stdio transport\n // treats a second close as a no-op but some transports throw).\n if (closed)\n return\n closed = true\n // Bounded per server (`closeTimeout`, default 5s; servers close in\n // parallel so the whole batch is bounded by the slowest one). An\n // unbounded close can wedge `agent.destroy()` indefinitely: a hung\n // `mcp:close` hook listener, a stdio child ignoring stdin EOF, or an\n // SDK version whose transport close awaits child exit forever.\n await Promise.allSettled(connections.map(async (c) => {\n // Capture before closing — see `stdioPid` doc on `connections`.\n const pid = c.stdioPid?.() ?? null\n try {\n await raceWithTimeout(\n () => c.closeIfConnected(),\n c.closeTimeout,\n `MCP server \"${c.name}\" close timed out after ${c.closeTimeout}ms (configurable via \\`closeTimeout\\`).`,\n )\n }\n catch (err) {\n // The abandoned close promise may still be holding a hung stdio\n // child — reap it so destroy() never leaks a subprocess into a\n // long-lived host process.\n killStdioChild(pid)\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/mcp] close \"${c.name}\" failed: ${errorMessage(err)}\\n`)\n }\n }))\n },\n }\n}\n\n/**\n * Build a one-shot `mcp:connect` emitter for a lazy server. The wrapper\n * around the connector calls this on the first successful connect;\n * concurrent first calls converge on the connector's in-flight promise\n * so the hook still fires exactly once.\n */\nfunction onceFireConnect(\n name: string,\n transport: McpServerConfig['transport'],\n toolNames: string[],\n hooks: Hookable<AgentHooks> | undefined,\n): () => Promise<void> {\n let fired = false\n return async () => {\n if (fired)\n return\n fired = true\n await safeCallHook(hooks, 'mcp:connect', { name, transport, tools: toolNames, lazy: true })\n }\n}\n\n/**\n * Wrap a lazy connector so the first successful resolution fires\n * `mcp:connect` exactly once. Failures don't fire the hook — the\n * connection isn't live yet and a retry will eventually run through the\n * wrapper again. Both the eager and lazy paths reach the tool builder\n * through this resolver shape so `buildMcpToolDef` stays mode-agnostic.\n */\nfunction wrapConnectWithHookFire(\n connect: () => Promise<Client>,\n fire: () => Promise<void>,\n): () => Promise<Client> {\n return async () => {\n const client = await connect()\n await fire()\n return client\n }\n}\n\n/**\n * Discriminated result returned by `bootstrapServer` so `connectMcpServers` can\n * aggregate successes + failures without letting a rejected promise tear down\n * the whole parallel batch.\n *\n * `skipped` is the third state: server needs OAuth login but has no tokens.\n * Not an error (we don't want a noisy `mcp:error`), not a success (no\n * connection). Caller already heard `mcp:auth:required` and decides whether\n * to surface a status row, prompt for login, etc.\n */\n/**\n * Discriminated result returned by `bootstrapServer`. Success carries either\n * an already-connected `client` (the eager path) or a `connect` thunk that\n * builds + connects a fresh client on first call (the `lazyConnect: true`\n * path). The collector translates both into a uniform `getClient` closure\n * for the tool builder so the call-site stays branch-free.\n */\ntype BootstrapResult\n = | { ok: true, skipped?: false, name: string, config: McpServerConfig, lazy: false, client: Client, transport: ClosableTransport, tools: Array<{ name: string, description?: string | null, inputSchema?: unknown }>, instructions?: string, durationMs: number }\n | { ok: true, skipped?: false, name: string, config: McpServerConfig, lazy: true, handle: LazyConnectHandle, tools: Array<{ name: string, description?: string | null, inputSchema?: unknown }>, durationMs: number }\n | { ok: false, skipped?: false, name: string, error: Error, durationMs: number }\n | { ok: false, skipped: true, name: string, durationMs: number }\n\n/**\n * Connect one MCP server and list its tools, wrapped in a single race against\n * `config.bootstrapTimeout` (default 10s). Always emits `mcp:bootstrap:start`\n * before network I/O and `mcp:bootstrap:end` with `durationMs` + outcome, so a\n * host can build a timing view even when every server succeeds.\n *\n * Errors are captured into the `{ ok: false }` result rather than thrown — the\n * parent uses `Promise.all` across every server and we can't let one rejection\n * short-circuit the batch.\n */\nasync function bootstrapServer(\n config: McpServerConfig,\n _clientFactory: McpClientFactory | undefined,\n hooks: Hookable<AgentHooks> | undefined,\n options: ConnectMcpServersOptions | undefined,\n): Promise<BootstrapResult> {\n const start = Date.now()\n // Validate mutually-exclusive filter fields up-front so the consumer gets a\n // typed `mcp:bootstrap:end` failure rather than a silent later-stage drop.\n if (config.enabledTools && config.disabledTools) {\n return emitConfigFailure(\n config,\n hooks,\n `MCP server \"${config.name}\": enabledTools and disabledTools are mutually exclusive — set one or the other, not both.`,\n )\n }\n // Lazy connect requires schemas in hand — without them there's nothing to\n // advertise to the model, so deferring the connection has no purpose.\n if (config.lazyConnect && (!config.cachedTools || config.cachedTools.length === 0)) {\n return emitConfigFailure(\n config,\n hooks,\n `MCP server \"${config.name}\": lazyConnect requires cachedTools (the host must pre-populate the tool schemas so they can be advertised without a connection).`,\n )\n }\n // OAuth + lazy is rejected — see `McpServerConfig.lazyConnect` for the\n // rationale. Surfacing this at bootstrap (rather than at first-call) is\n // load-bearing: the host needs the failure proximate to the misconfig\n // so it can render an auth affordance before the model commits to a\n // tool call that would fail mid-run.\n if (config.lazyConnect && config.auth === 'oauth') {\n return emitConfigFailure(\n config,\n hooks,\n `MCP server \"${config.name}\": lazyConnect is not compatible with auth: 'oauth' — OAuth servers must complete the handshake at bootstrap so a login affordance can surface before the model commits to a tool call.`,\n )\n }\n\n await safeCallHook(hooks, 'mcp:bootstrap:start', { name: config.name, transport: config.transport })\n\n // Build an auth provider when the config asks for OAuth and the host\n // wired a factory. Non-interactive — the SDK uses stored tokens / refresh,\n // never opens a browser during bootstrap. Missing tokens surface as\n // `UnauthorizedError` from `connect()`, which we convert to a skip below.\n const explicitAuth = config.auth === 'oauth'\n const authProvider = explicitAuth ? options?.buildAuthProvider?.(config) : undefined\n\n // Soft warnings emitted by the tolerant client (e.g. a 4xx on\n // `notifications/initialized`). Surfaced on the success arm of\n // `mcp:bootstrap:end` so hosts can render a \"connected with caveats\"\n // status instead of having to subscribe to stderr.\n const warnings: string[] = []\n const onWarning = (message: string) => { warnings.push(message) }\n\n // Lazy fast-path — defer transport + connect to `getClient()`. Schemas\n // come from `cachedTools`; the host owns invalidation. We still emit\n // `mcp:bootstrap:end ok: true, lazy: true` so timing dashboards stay\n // honest (the row appears, just with a near-zero `durationMs`).\n if (config.lazyConnect) {\n const cachedSchemas = config.cachedTools!\n const filteredTools = await applyMcpToolFilters(config, cachedSchemas, hooks)\n const handle = makeLazyConnector(config, _clientFactory, authProvider, hooks)\n const durationMs = Date.now() - start\n await safeCallHook(hooks, 'mcp:bootstrap:end', {\n name: config.name,\n transport: config.transport,\n durationMs,\n ok: true,\n toolCount: filteredTools.length,\n lazy: true,\n cached: true,\n })\n return { ok: true, name: config.name, config, lazy: true, handle, tools: filteredTools, durationMs }\n }\n\n let client: Client | null = null\n let transport: ClosableTransport | null = null\n try {\n // TolerantMcpClient is a drop-in subclass that survives a 4xx on the\n // `notifications/initialized` post (some real-world servers reject it\n // without that breaking subsequent `tools/list` etc.). See\n // ./tolerant-client.ts for the exact semantics.\n client = _clientFactory\n ? _clientFactory({ onWarning })\n : await createTolerantClient({ name: 'zidane', version: '1.0.0' }, { onWarning })\n const currentClient = client\n\n transport = await createTransport(config, authProvider, hooks) as ClosableTransport\n const bootstrapTimeout = config.bootstrapTimeout ?? DEFAULT_MCP_BOOTSTRAP_TIMEOUT_MS\n // When `cachedTools` is provided we still establish the connection\n // (the SDK needs it for `tools/call`) but skip the `tools/list`\n // round-trip — that's the cheaper of the two networking costs on\n // a fast server, but on a slow / chatty one it's the dominant one.\n const cachedSchemas = config.cachedTools\n const mcpTools = await raceWithTimeout(\n async () => {\n await currentClient.connect(transport as Parameters<Client['connect']>[0])\n return cachedSchemas ?? (await currentClient.listTools()).tools\n },\n bootstrapTimeout,\n `MCP server \"${config.name}\" bootstrap timed out after ${bootstrapTimeout}ms (configurable via \\`bootstrapTimeout\\`).`,\n )\n\n // Expose the raw, pre-filter tool list to hosts so a settings UI or\n // a tool-catalog persistence layer can capture every advertised\n // tool — including ones the config's `disabledTools` / `toolFilter`\n // is about to drop. Read-only; mutation goes through\n // `mcp:tools:filter` below. See AgentHooks['mcp:tools:list'] doc.\n await safeCallHook(hooks, 'mcp:tools:list', {\n name: config.name,\n transport: config.transport,\n tools: mcpTools as McpToolSchema[],\n })\n\n // Per-tool filtering — config-side first (static host policy), then the\n // `mcp:tools:filter` hook (runtime / dynamic decisions). Both compose AND-\n // style: a tool needs to pass every stage to land in the agent registry.\n const filteredTools = await applyMcpToolFilters(config, mcpTools, hooks)\n\n // Capture the server-issued `instructions` from the initialize handshake.\n // The SDK stored them on the client during `connect()` (see\n // `tolerant-client.ts`); the public `getInstructions()` returns the\n // string or `undefined`. We trim + nullable-coerce here so the agent's\n // system-prompt builder gets one normalized shape, and a server that\n // sends `\"\"` (empty string) is treated identically to \"no instructions\"\n // rather than emitting a section with an empty body.\n //\n // Defensive: older `_clientFactory` test mocks don't implement\n // `getInstructions` (the method was added to the SDK after the mocks\n // were written). Guard so an unknown function shape degrades to\n // \"no instructions\" instead of crashing bootstrap.\n let rawInstructions: unknown\n if (typeof (currentClient as { getInstructions?: unknown }).getInstructions === 'function') {\n try {\n rawInstructions = (currentClient as { getInstructions: () => unknown }).getInstructions()\n }\n catch {\n rawInstructions = undefined\n }\n }\n const instructions = typeof rawInstructions === 'string' && rawInstructions.trim().length > 0\n ? rawInstructions\n : undefined\n\n const durationMs = Date.now() - start\n await safeCallHook(hooks, 'mcp:bootstrap:end', {\n name: config.name,\n transport: config.transport,\n durationMs,\n ok: true,\n toolCount: filteredTools.length,\n ...(cachedSchemas ? { cached: true } : {}),\n ...(warnings.length > 0 ? { warnings } : {}),\n })\n return {\n ok: true,\n name: config.name,\n config,\n lazy: false,\n client: currentClient,\n transport,\n tools: filteredTools,\n ...(instructions !== undefined ? { instructions } : {}),\n durationMs,\n }\n }\n catch (err) {\n // Close in order: transport first (may not yet be wired into the\n // client when connect() hadn't completed), then client (close()\n // is a no-op on transports that already closed).\n await closeTransportQuietly(transport)\n await closeClientQuietly(client)\n const rawError = err instanceof Error ? err : new Error(String(err))\n const error = withTransportMismatchHint(config.transport, rawError)\n const durationMs = Date.now() - start\n\n // OAuth path — convert \"needs login\" into a skip instead of an error.\n // Two cases reach here:\n // 1. Explicit `auth: 'oauth'` with no stored tokens (provider built,\n // SDK threw UnauthorizedError when none could be refreshed).\n // 2. No auth flag, but the server returned 401 + RFC 9728 metadata\n // AND the user did not provide a static Authorization header\n // (the headers escape hatch — see McpServerConfig.auth docs).\n // The auto-promote path requires `buildAuthProvider` so the host\n // can complete the login. Without it, this falls through as a\n // regular bootstrap error.\n if (isUnauthorizedError(err)) {\n const eligibleAutoPromote = !explicitAuth\n && !hasAuthorizationHeader(config.headers)\n && !!options?.buildAuthProvider\n if (explicitAuth || eligibleAutoPromote) {\n await safeCallHook(hooks, 'mcp:bootstrap:end', {\n name: config.name,\n transport: config.transport,\n durationMs,\n ok: false,\n error,\n })\n await safeCallHook(hooks, 'mcp:auth:required', {\n name: config.name,\n transport: config.transport,\n reason: explicitAuth ? 'no-tokens' : 'auto-promoted',\n })\n return { ok: false, skipped: true, name: config.name, durationMs }\n }\n }\n\n await safeCallHook(hooks, 'mcp:bootstrap:end', {\n name: config.name,\n transport: config.transport,\n durationMs,\n ok: false,\n error,\n })\n return { ok: false, name: config.name, error, durationMs }\n }\n}\n\n/**\n * Emit the start/end hooks for a config-level failure and return the error\n * result. Centralised so the various validation branches (enabled/disabled\n * mutex, lazyConnect-without-cachedTools, lazyConnect+OAuth) stay readable.\n */\nasync function emitConfigFailure(\n config: McpServerConfig,\n hooks: Hookable<AgentHooks> | undefined,\n message: string,\n): Promise<BootstrapResult> {\n const error = new Error(message)\n await safeCallHook(hooks, 'mcp:bootstrap:start', { name: config.name, transport: config.transport })\n await safeCallHook(hooks, 'mcp:bootstrap:end', {\n name: config.name,\n transport: config.transport,\n durationMs: 0,\n ok: false,\n error,\n })\n return { ok: false, name: config.name, error, durationMs: 0 }\n}\n\n/**\n * Per-server lazy bootstrap handle returned by {@link makeLazyConnector}.\n *\n * - `connect()` triggers (or reuses the in-flight) transport build +\n * `client.connect()`. Concurrent callers converge on a single promise;\n * a rejection drops the cached promise so the next call retries.\n * - `closeIfConnected()` closes the live client when one exists and\n * short-circuits when the server was never used. Always awaits a\n * pending connect first so a `destroy()` racing with a first\n * `tools/call` cannot leak the freshly-built client.\n */\ninterface LazyConnectHandle {\n connect: () => Promise<Client>\n closeIfConnected: () => Promise<void>\n /**\n * PID of the live stdio child, or `null` when not connected / not stdio /\n * already exited. Read by the bounded `close()` before initiating the\n * close (the SDK's stdio transport drops its process reference the moment\n * its own close starts).\n */\n stdioPid: () => number | null\n}\n\n/**\n * Build a memoized lazy connector + matching close handle for a\n * `lazyConnect: true` server. State lives in the closure: the connector\n * tracks its own in-flight and resolved-client state so the close path\n * can reason about \"never connected\" vs \"in flight\" vs \"live\" without\n * forcing a connect from inside `close()`.\n *\n * Concurrency contract:\n * - First `connect()` builds + connects a fresh client. Concurrent\n * callers converge on the same in-flight promise.\n * - On rejection, the cached promise is dropped so the next caller\n * retries with a fresh client instance.\n * - `closeIfConnected()` awaits any pending connect, closes the\n * resulting client, and marks the handle destroyed. Any subsequent\n * `connect()` rejects synchronously so a tool call racing the\n * shutdown can't leak a freshly-built client past the close.\n */\nfunction makeLazyConnector(\n config: McpServerConfig,\n _clientFactory: McpClientFactory | undefined,\n authProvider: OAuthClientProvider | undefined,\n hooks: Hookable<AgentHooks> | undefined,\n): LazyConnectHandle {\n let inFlight: Promise<Client> | null = null\n let live: Client | null = null\n let liveTransport: ClosableTransport | null = null\n let destroyed = false\n\n const connect = (): Promise<Client> => {\n if (destroyed) {\n return Promise.reject(new Error(\n `MCP server \"${config.name}\": cannot connect after close()`,\n ))\n }\n if (live)\n return Promise.resolve(live)\n if (inFlight)\n return inFlight\n const pending = (async () => {\n // Match the eager path's timeout — a lazy connect that hangs\n // would wedge a tool call indefinitely without it.\n const bootstrapTimeout = config.bootstrapTimeout ?? DEFAULT_MCP_BOOTSTRAP_TIMEOUT_MS\n const client = _clientFactory\n ? _clientFactory()\n : await createTolerantClient({ name: 'zidane', version: '1.0.0' })\n let transport: ClosableTransport | null = null\n try {\n transport = await createTransport(config, authProvider, hooks) as ClosableTransport\n await raceWithTimeout(\n () => client.connect(transport as Parameters<Client['connect']>[0]),\n bootstrapTimeout,\n `MCP server \"${config.name}\" lazy connect timed out after ${bootstrapTimeout}ms (configurable via \\`bootstrapTimeout\\`).`,\n )\n // Shutdown ran while we were connecting — close the freshly\n // built client right here so it doesn't leak past destroy().\n if (destroyed) {\n await closeTransportQuietly(transport)\n await closeClientQuietly(client)\n throw new Error(`MCP server \"${config.name}\": closed during connect`)\n }\n live = client\n liveTransport = transport\n return client\n }\n catch (err) {\n // Close in order: transport first (may not be wired into the\n // client yet on a connect failure), then client.\n await closeTransportQuietly(transport)\n await closeClientQuietly(client)\n throw err instanceof Error\n ? withTransportMismatchHint(config.transport, err)\n : err\n }\n })()\n inFlight = pending\n // Clear the in-flight cache on either outcome — success leaves the\n // resolved client cached on `live`; failure drops the slot so the\n // next caller retries against a fresh client instance, matching the\n // bootstrap-level retry behavior in `agent.ts`'s `mcpWarmupPromise`.\n pending.then(\n () => { inFlight = null },\n () => { inFlight = null },\n )\n return pending\n }\n\n const closeIfConnected = async (): Promise<void> => {\n destroyed = true\n // Race-safe drain: if a connect is in flight, wait for it to settle\n // before deciding whether to close. Successful resolution promotes\n // the client to `live`; failure leaves both `live` and `inFlight`\n // null. Either way, after the await the state is terminal and the\n // close decision is unambiguous.\n if (inFlight) {\n try { await inFlight }\n catch { /* connect failed; nothing to close */ }\n }\n if (live) {\n const client = live\n live = null\n await client.close()\n }\n }\n\n return {\n connect,\n closeIfConnected,\n stdioPid: () => stdioPidOf(liveTransport),\n }\n}\n\n/**\n * Apply config-side filters (`enabledTools` / `disabledTools` / `toolFilter`)\n * and then the `mcp:tools:filter` hook to the upstream tool list.\n *\n * Composition order — narrowest-to-widest:\n * 1. Allow-list (`enabledTools`) — keep only listed tools.\n * 2. Deny-list (`disabledTools`) — drop listed tools.\n * 3. Predicate (`toolFilter`) — fine-grained metadata filtering.\n * 4. Hook (`mcp:tools:filter`) — runtime / per-host decisions.\n *\n * The mutual exclusion of `enabledTools` and `disabledTools` is checked in\n * `bootstrapServer` so this stays a pure data transform.\n */\nasync function applyMcpToolFilters(\n config: McpServerConfig,\n tools: Array<{ name: string, description?: string | null, inputSchema?: unknown }>,\n hooks: Hookable<AgentHooks> | undefined,\n): Promise<Array<{ name: string, description?: string | null, inputSchema?: unknown }>> {\n let filtered = tools\n\n if (config.enabledTools && config.enabledTools.length > 0) {\n const allow = new Set(config.enabledTools)\n filtered = filtered.filter(t => allow.has(t.name))\n }\n\n if (config.disabledTools && config.disabledTools.length > 0) {\n const deny = new Set(config.disabledTools)\n filtered = filtered.filter(t => !deny.has(t.name))\n }\n\n if (config.toolFilter) {\n const predicate = config.toolFilter\n filtered = filtered.filter(t => predicate(t))\n }\n\n if (hooks) {\n // Pass a fresh array so handlers cannot retroactively mutate the caller's\n // upstream list; mutations they make to `ctx.tools` are scoped to this turn.\n const ctx = { server: config.name, transport: config.transport, tools: [...filtered] }\n await hooks.callHook('mcp:tools:filter', ctx)\n filtered = ctx.tools\n }\n\n return filtered\n}\n\n/**\n * Build the zidane `ToolDef` that wraps a single MCP tool. Extracted so the\n * parallel bootstrap path can assemble tools from a results array without\n * inlining a 70-line closure inside the collector loop.\n *\n * `getClient` resolves to a live `Client` ready for `tools/call`. For\n * eagerly-bootstrapped servers it's a constant resolved promise; for\n * `lazyConnect: true` servers it's the memoized connector built by\n * {@link makeLazyConnector} — the first invocation pays the connect cost,\n * concurrent / subsequent calls observe the cached client. Reconnects /\n * swap-outs go through a fresh `connectMcpServers` call rather than\n * rewiring the tool in place.\n */\n/**\n * Coerce an MCP-advertised `inputSchema` to a plain object schema. The value is\n * `unknown` (live `listTools` is zod-checked upstream, but `cachedTools` and the\n * tolerant client bypass that), so a server/cache that serialized a string,\n * array or null would otherwise be cast verbatim and poison the whole provider\n * request (`tools[n].input_schema: expected object`). Degrade that one tool to\n * a fresh empty object schema instead of failing the run. (Fresh per call so a\n * downstream in-place mutation can't bleed across degraded tools.)\n */\nfunction toObjectSchema(schema: unknown): Record<string, unknown> {\n if (typeof schema === 'object' && schema !== null && !Array.isArray(schema))\n return schema as Record<string, unknown>\n return { type: 'object', properties: {} }\n}\n\nfunction buildMcpToolDef(\n config: McpServerConfig,\n getClient: () => Promise<Client>,\n tool: { name: string, description?: string | null, inputSchema?: unknown },\n namespacedName: string,\n hooks: Hookable<AgentHooks> | undefined,\n): ToolDef {\n return {\n spec: {\n name: namespacedName,\n description: tool.description || '',\n inputSchema: toObjectSchema(tool.inputSchema),\n },\n execute: async (input: Record<string, unknown>, ctx: ToolContext) => {\n const { turnId, callId, signal } = ctx\n const displayName = ctx.toolAliases?.[namespacedName] ?? namespacedName\n\n // Shared identity fields for every `mcp:tool:*` hook ctx the\n // wrapper fires. Mirrors `runId / parentRunId / depth` from the\n // tool context so subagent observability stays consistent\n // between `tool:*` and `mcp:tool:*` events.\n const identity = {\n ...(ctx.runId !== undefined ? { runId: ctx.runId } : {}),\n ...(ctx.parentRunId !== undefined ? { parentRunId: ctx.parentRunId } : {}),\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n }\n\n // Gate — block MCP tool execution or substitute a synthetic result.\n const gateCtx: McpToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n } = {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input,\n ...identity,\n block: false,\n reason: 'MCP tool execution was blocked',\n }\n await hooks?.callHook('mcp:tool:gate', gateCtx)\n\n // Conflict resolution mirrors the loop's `tool:gate`: when both `block`\n // and `result` are set (e.g. a policy gate refuses on top of a consumer\n // cache substitute), `block` wins.\n if (gateCtx.block)\n return `Blocked: ${gateCtx.reason}`\n\n const effectiveInput = gateCtx.input\n\n // MCP gate `result` substitute — skip the upstream callTool, fire the\n // transform + after hooks so consumers see the substitute consistently\n // with normally-executed calls.\n if (gateCtx.result !== undefined) {\n let substitute: string | ToolResultContent[] = gateCtx.result\n const transformCtx = {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n result: substitute,\n outputBytes: toolOutputByteLength(substitute),\n }\n await hooks?.callHook('mcp:tool:transform', transformCtx)\n substitute = transformCtx.result\n await hooks?.callHook('mcp:tool:after', {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n result: substitute,\n outputBytes: toolOutputByteLength(substitute),\n })\n return substitute\n }\n await hooks?.callHook('mcp:tool:before', {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n })\n // Per-tool override > per-server default > 30s. Slow-but-legitimate\n // operations (DDL migrations, deploys) need more headroom than fast\n // metadata calls on the same server.\n const timeout = config.toolTimeouts?.[tool.name] ?? config.toolTimeout ?? 30_000\n try {\n // Resolve the live client. For eager servers this is a no-op\n // (constant resolved promise); for `lazyConnect: true` servers\n // this triggers the deferred connect on first call and reuses\n // the cached client afterward.\n const client = await getClient()\n // Race the call against the configured timeout AND the run-level\n // abort signal. Aborting the run has to propagate into MCP calls\n // — otherwise a hung stdio server keeps the tool call alive\n // until `destroy()` eventually closes the client, which can be\n // minutes if the agent is waiting on `waitForIdle()`.\n const result = await raceWithTimeoutAndSignal(\n // The SDK's `RequestOptions.signal` sends a `notifications/cancelled`\n // to the server and rejects the in-flight RPC — so a timeout / run\n // abort actually cancels the remote call instead of orphaning it\n // (matters for streamable-http transports, where there is no\n // subprocess to kill on `close()`).\n rpcSignal => client.callTool({ name: tool.name, arguments: effectiveInput }, undefined, { timeout, signal: rpcSignal }),\n timeout,\n // The steering tail matters: a bare \"timed out\" reads as a transient\n // failure and models immediately retry the identical call — which\n // for non-idempotent operations (migrations, deploys) compounds the\n // damage and feeds retry loops.\n `MCP tool \"${tool.name}\" on server \"${config.name}\" timed out after ${timeout}ms. `\n + `The server may still be processing the request — verify its effect before retrying, `\n + `and do not immediately retry the identical call.`,\n signal,\n )\n let output: string | ToolResultContent[] = packMcpResult(result.content)\n\n // In-band MCP failure: per spec, servers report tool-level errors via\n // `CallToolResult.isError` with the diagnostic in `content`. Throw so\n // the failure routes through the same `mcp:tool:error` + loop error\n // paths as a transport-level failure — otherwise the model sees the\n // error text as a *successful* tool result.\n if (result.isError === true) {\n const detail = (typeof output === 'string' ? output : toolResultToText(output)).trim()\n throw new Error(detail || `MCP tool \"${tool.name}\" on server \"${config.name}\" reported an error with no diagnostic content`)\n }\n\n // Transform — mutate result before returning. `outputBytes` reflects\n // the size before any consumer mutation so a truncation hook can size-budget.\n const transformCtx = {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n result: output,\n outputBytes: toolOutputByteLength(output),\n }\n await hooks?.callHook('mcp:tool:transform', transformCtx)\n output = transformCtx.result\n\n await hooks?.callHook('mcp:tool:after', {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n result: output,\n outputBytes: toolOutputByteLength(output),\n })\n return output\n }\n catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n // Route through safeCallHook so a throwing listener can't mask the\n // original tool error (which we rethrow below).\n await safeCallHook(hooks, 'mcp:tool:error', {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n error,\n })\n await safeCallHook(hooks, 'mcp:tool:after', {\n turnId,\n callId,\n server: config.name,\n tool: tool.name,\n displayName,\n input: effectiveInput,\n ...identity,\n result: error.message,\n outputBytes: Buffer.byteLength(error.message),\n })\n throw error\n }\n },\n }\n}\n\nasync function closeClientQuietly(client: Pick<Client, 'close'> | null | undefined): Promise<void> {\n if (!client)\n return\n try {\n await client.close()\n }\n catch {\n // Best-effort cleanup — original bootstrap error is more actionable.\n }\n}\n\nasync function raceWithTimeout<T>(\n task: () => Promise<T>,\n timeoutMs: number,\n timeoutMessage: string,\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await new Promise<T>((resolvePromise, rejectPromise) => {\n timer = setTimeout(() => rejectPromise(new Error(timeoutMessage)), timeoutMs)\n task().then(resolvePromise, rejectPromise)\n })\n }\n finally {\n if (timer)\n clearTimeout(timer)\n }\n}\n\n/**\n * Race a promise-returning task against (a) a timeout and (b) an optional\n * abort signal. Cleans up its timer and abort listener on every exit path.\n *\n * The task receives a dedicated `AbortSignal` that fires on either trigger.\n * Callers thread it into the MCP SDK's `RequestOptions.signal` so a timeout\n * or run-abort cancels the underlying RPC (the SDK sends\n * `notifications/cancelled`) instead of leaving it running server-side —\n * which matters for streamable-http transports, where `connection.close()`\n * has no subprocess to kill.\n */\nasync function raceWithTimeoutAndSignal<T>(\n task: (signal: AbortSignal) => Promise<T>,\n timeoutMs: number,\n timeoutMessage: string,\n signal: AbortSignal | undefined,\n): Promise<T> {\n if (signal?.aborted)\n throw new Error('MCP tool call aborted')\n\n const rpcAbort = new AbortController()\n let timer: ReturnType<typeof setTimeout> | undefined\n let onAbort: (() => void) | undefined\n try {\n return await new Promise<T>((resolvePromise, rejectPromise) => {\n timer = setTimeout(() => {\n rejectPromise(new Error(timeoutMessage))\n rpcAbort.abort()\n }, timeoutMs)\n if (signal) {\n onAbort = () => {\n rejectPromise(new Error('MCP tool call aborted'))\n rpcAbort.abort()\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }\n task(rpcAbort.signal).then(resolvePromise, rejectPromise)\n })\n }\n finally {\n if (timer)\n clearTimeout(timer)\n if (signal && onAbort)\n signal.removeEventListener('abort', onAbort)\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-formatters-ETbcC9DM.d.ts","names":[],"sources":["../src/chat/turn-selection.ts","../src/chat/safe-mode-context.tsx","../src/chat/markdown-segments.ts","../src/chat/prompt-segments.ts","../src/chat/tool-formatters.ts"],"mappings":";;;;;cAaa,eAAA,EAAiB,WAAW;;AAAzC;;;;AAAyC;AAmBzC;;;;AAA8C;AA+B9C;;;;;;iBA/BgB,iBAAA,CAAkB,IAAY;;;AA+BkB;AAuDhE;;;;;;;;AAA2E;AAiD3E;iBAxGgB,SAAA,CAAU,KAAA,EAAO,WAAA,EAAa,QAAA,EAAU,QAAQ;;;;;;;;;;;;;;AA2GxB;AA6BxC;;;;;;;;;AAEqB;;;;iBAnFL,sBAAA,CAAuB,MAAA,WAAiB,WAAA,KAAgB,GAAG;;;;AC9E9C;AAQ7B;;;;;;;iBDuHgB,iBAAA,CACd,KAAA,EAAO,IAAA,CAAK,WAAA,aACZ,cAAA,iBACA,SAAA,EAAW,WAAA;ACxHe;AAE5B;;;;;;;;;;;;;;;;;;AAMiC;AARL,iBDqJZ,iBAAA,CACd,MAAA,WAAiB,WAAA,IACjB,QAAA,GAAW,QAAQ;;;;;AA1I2C;AAuDhE;;;;;;;;KCnFY,gBAAA;EAKJ,IAAA;EAAiB,IAAI;AAAA;;;;;;;KAQjB,kBAAA;EACJ,IAAA;AAAA;EACA,IAAA;EAAe,KAAA;AAAA;AAAA,UAEN,eAAA;EACf,EAAA;EACA,IAAA;EACA,KAAA,EAAO,MAAA;EACP,OAAA,GAAU,QAAA,EAAU,gBAAA;EDgJH;EC9IjB,UAAA,GAAa,kBAAA;AAAA;;KAIH,eAAA,IACV,IAAA,UACA,KAAA,EAAO,MAAA,mBACP,UAAA,GAAa,kBAAA,KACV,OAAA,CAAQ,gBAAA;AAAA,UAEI,eAAA;;EAEf,eAAA,EAAiB,eAAA;;EAEjB,WAAA,GAAc,QAAA,EAAU,gBAAgB;EArCd;EAuC1B,OAAA;AAAA;AAlC2B;AAQ7B;;;AAR6B,iBAqDb,gBAAA;EAAmB;AAAA;EAAc,QAAA,EAAU,SAAS;AAAA,gCAAE,GAAA,CAAA,OAAA;AAAA,iBAqEtD,gBAAA,aAA6B,eAAe;AAAA,iBAI5C,kBAAA,IAAsB,eAAe;;;;;;;ADzJrD;;;;UEUiB,eAAA;EACf,IAAA;EACA,OAAA;;EAEA,IAAA;EFK4C;AA+B9C;;;;;EE7BE,IAAA;AAAA;;;AF6B8D;AAuDhE;;;;;;;;AAA2E;AAiD3E;;;;iBElHgB,uBAAA,CAAwB,IAAA,WAAe,eAAe;;;;;;;;;;;AFqH9B;AA6BxC;;;;;;iBE7DgB,2BAAA,CAA4B,IAAY;;;AF+DnC;;;;ACtKrB;;;cC4Ja,kCAAA;ADvJgB;AAQ7B;;;;;;;;AAE4B;AAE5B;;;AAZ6B,iBCsLb,sBAAA,CAAuB,IAAA,UAAc,WAAwD;;;;;;;AFjN7G;;;;AAAyC;AAmBzC;;;;AAA8C;AA+B9C;;UG9CiB,gBAAA;EACf,KAAA;EACA,GAAA;EH4CwB;EG1CxB,UAAA;AAAA;;AH0C8D;AAuDhE;;;;KGxFY,aAAA;EACJ,IAAA;EAAe,IAAA;AAAA;EACf,IAAA;EAAc,IAAA;EAAc,UAAA;AAAA;;;;;;;;;;;;;AH0II;AA6BxC;;;;;;;;;iBG/IgB,mBAAA,CACd,IAAA,UACA,IAAA,WAAe,gBAAA,KACd,aAAa;;;;;;;AH9ChB;;;;AAAyC;AAmBzC;;;;AAA8C;AA+B9C;;;UI3CiB,cAAA;EJ2CgB;;;;;EIrC/B,MAAA;EJ4Fc;;;;;EItFd,IAAI;AAAA;AAAA,UAGW,eAAA;EJmF0D;AAiD3E;;;;;;;;EI1HE,WAAA,aAAwB,KAAA,EAAO,MAAA;EJ2HnB;;;;;EIrHZ,MAAA,GAAS,KAAA,EAAO,MAAA,sBAA4B,cAAA;AAAA;AAAA,cAOjC,YAAA,EAAc,QAAA,CAAS,MAAA,SAAe,eAAA;;;;;;;;;AJ+I9B;;;;ACtKrB;;;iBGoUgB,cAAA,CACd,IAAA,UACA,KAAA,GAAQ,MAAM;AHjUa;AAQ7B;;;;;AAR6B,iBGmVb,cAAA,CAAe,IAAA,UAAc,KAAA,EAAO,MAAA,oBAA0B,cAAc"}