zidane 8.2.3 → 8.2.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.
- package/dist/{acp-oYRjlh71.js → acp-BIInKhVI.js} +6 -6
- package/dist/{acp-oYRjlh71.js.map → acp-BIInKhVI.js.map} +1 -1
- package/dist/acp-cli.js +4 -4
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-CBQglXtH.js → agent-CmhCOmyO.js} +10 -5
- package/dist/{agent-CBQglXtH.js.map → agent-CmhCOmyO.js.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +7 -7
- package/dist/chat.d.ts +3 -3
- package/dist/chat.js +16 -16
- package/dist/{cli-shared-E5m_pI8A.js → cli-shared-GOehTeqk.js} +2 -2
- package/dist/{cli-shared-E5m_pI8A.js.map → cli-shared-GOehTeqk.js.map} +1 -1
- package/dist/{client-core-EEEX_u6D.d.ts → client-core-Dz8hELs4.d.ts} +15 -5
- package/dist/client-core-Dz8hELs4.d.ts.map +1 -0
- package/dist/codemode-worker.js +1 -1
- package/dist/codemode.js +1 -1
- package/dist/{connection-loop-CpgfUmuw.d.ts → connection-loop-dm_TN-QD.d.ts} +3 -3
- package/dist/{connection-loop-CpgfUmuw.d.ts.map → connection-loop-dm_TN-QD.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/{credentials-B9DfBJP9.js → credentials-DxOQmset.js} +2 -2
- package/dist/{credentials-B9DfBJP9.js.map → credentials-DxOQmset.js.map} +1 -1
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-Bv9-c6I2.js → dispatcher-Dclv6HXn.js} +22 -18
- package/dist/dispatcher-Dclv6HXn.js.map +1 -0
- package/dist/{engine-XmoPPB6U.js → engine-C_U6kDfA.js} +6 -6
- package/dist/{engine-XmoPPB6U.js.map → engine-C_U6kDfA.js.map} +1 -1
- package/dist/{eval-CfQlBR81.js → eval-CIHIF_Ns.js} +3 -3
- package/dist/{eval-CfQlBR81.js.map → eval-CIHIF_Ns.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-BhthPE1q.js → executor-BFaR2nfc.js} +3 -3
- package/dist/{executor-BhthPE1q.js.map → executor-BFaR2nfc.js.map} +1 -1
- package/dist/{extensions-BgBwogRW.js → extensions-DIbpUj5R.js} +3 -3
- package/dist/{extensions-BgBwogRW.js.map → extensions-DIbpUj5R.js.map} +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{fold-rules-DSypi36k.d.ts → fold-rules-CMpWNPqk.d.ts} +2 -2
- package/dist/{fold-rules-DSypi36k.d.ts.map → fold-rules-CMpWNPqk.d.ts.map} +1 -1
- package/dist/{headless-R4pbpTkm.js → headless-Bs9Lb4vs.js} +4 -4
- package/dist/{headless-R4pbpTkm.js.map → headless-Bs9Lb4vs.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/history-worker.js +1 -1
- package/dist/{host-scoped-settings-C-Nmb6vr.js → host-scoped-settings-DxxI_yRo.js} +2 -2
- package/dist/{host-scoped-settings-C-Nmb6vr.js.map → host-scoped-settings-DxxI_yRo.js.map} +1 -1
- package/dist/{host-signals-BFudPyCT.js → host-signals-CQ2jZR-2.js} +5 -5
- package/dist/{host-signals-BFudPyCT.js.map → host-signals-CQ2jZR-2.js.map} +1 -1
- package/dist/{index-DyQyDLX1.d.ts → index-4mDRyTGJ.d.ts} +1722 -1691
- package/dist/index-4mDRyTGJ.d.ts.map +1 -0
- package/dist/{index-CDS7YdUC.d.ts → index-Dlmu8HnG.d.ts} +5 -5
- package/dist/{index-CDS7YdUC.d.ts.map → index-Dlmu8HnG.d.ts.map} +1 -1
- package/dist/{index-AqRZ3gEz.d.ts → index-QsAN9yjZ.d.ts} +3 -3
- package/dist/{index-AqRZ3gEz.d.ts.map → index-QsAN9yjZ.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +8 -8
- package/dist/ipc/remote.d.ts +5 -5
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +9 -9
- package/dist/{links-rFaWqS2Y.js → links-D5itfH8P.js} +10 -10
- package/dist/{links-rFaWqS2Y.js.map → links-D5itfH8P.js.map} +1 -1
- package/dist/{mcp-allowlist-CLXweyxk.js → mcp-allowlist-BbnTBKNN.js} +2 -2
- package/dist/{mcp-allowlist-CLXweyxk.js.map → mcp-allowlist-BbnTBKNN.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{oauth-7_48zR7n.js → oauth-Ck3wQX4Q.js} +66 -32
- package/dist/oauth-Ck3wQX4Q.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{prelude-HzY_JEGq.js → prelude-qjPUkw4f.js} +26 -2
- package/dist/prelude-qjPUkw4f.js.map +1 -0
- package/dist/{presets-DXeHsd24.js → presets-C4hkykN-.js} +2 -2
- package/dist/{presets-DXeHsd24.js.map → presets-C4hkykN-.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{protocol-BIv1Yuvl.js → protocol-Do_i6Ras.js} +3 -1
- package/dist/protocol-Do_i6Ras.js.map +1 -0
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/{registry-eourRLY2.js → registry-DxPP_tAt.js} +3 -3
- package/dist/{registry-eourRLY2.js.map → registry-DxPP_tAt.js.map} +1 -1
- package/dist/{remote-hosts-DY2J07ut.js → remote-hosts-BkOwRszu.js} +4 -4
- package/dist/{remote-hosts-DY2J07ut.js.map → remote-hosts-BkOwRszu.js.map} +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/{secret-shapes-BjW4l6U0.js → secret-shapes-HvaYVzwc.js} +10 -2
- package/dist/secret-shapes-HvaYVzwc.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-7TUHs42_.js → session-CCsKXID6.js} +6 -2
- package/dist/session-CCsKXID6.js.map +1 -0
- package/dist/{session-factory-CMwIXE-7.js → session-factory-Ct7J9CK1.js} +6 -6
- package/dist/{session-factory-CMwIXE-7.js.map → session-factory-Ct7J9CK1.js.map} +1 -1
- package/dist/session.d.ts +2 -2
- package/dist/session.js +1 -1
- package/dist/{settings-keys-CPdmkTz7.js → settings-keys-QoGJ5n3e.js} +4 -4
- package/dist/{settings-keys-CPdmkTz7.js.map → settings-keys-QoGJ5n3e.js.map} +1 -1
- package/dist/{shell-path-B8b3EOtK.js → shell-path-BXXtRmEA.js} +4 -4
- package/dist/{shell-path-B8b3EOtK.js.map → shell-path-BXXtRmEA.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/{spaces-CyjMh5Zf.js → spaces-C_x2bvEl.js} +14 -4
- package/dist/spaces-C_x2bvEl.js.map +1 -0
- package/dist/{store-L01W0gGI.js → store-BpkWIaSH.js} +10 -30
- package/dist/store-BpkWIaSH.js.map +1 -0
- package/dist/{todo-edits-BERpCRPj.js → todo-edits-DKoxu7Ss.js} +3 -3
- package/dist/{todo-edits-BERpCRPj.js.map → todo-edits-DKoxu7Ss.js.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-pZVFIJ_K.js → tools-FHEIKGkh.js} +2 -2
- package/dist/{tools-pZVFIJ_K.js.map → tools-FHEIKGkh.js.map} +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +2 -2
- package/dist/{transcript-anchors-jHrg-r-H.js → transcript-anchors-D8jWLpe5.js} +10 -10
- package/dist/{transcript-anchors-jHrg-r-H.js.map → transcript-anchors-D8jWLpe5.js.map} +1 -1
- package/dist/{transcript-cache-DXdgVuoy.js → transcript-cache-CdHKtx9y.js} +4 -4
- package/dist/{transcript-cache-DXdgVuoy.js.map → transcript-cache-CdHKtx9y.js.map} +1 -1
- package/dist/{transcript-reconcile-CPdrNbbR.js → transcript-reconcile-D_SWw6dX.js} +11 -3
- package/dist/transcript-reconcile-D_SWw6dX.js.map +1 -0
- package/dist/tui.d.ts +7 -7
- package/dist/tui.js +24 -23
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-DuGtKuc_.d.ts → turn-operations-Dbk3xPKu.d.ts} +11 -3
- package/dist/{turn-operations-DuGtKuc_.d.ts.map → turn-operations-Dbk3xPKu.d.ts.map} +1 -1
- package/dist/{types-C0PJmBaO.d.ts → types-CMXR7A0b.d.ts} +2 -2
- package/dist/{types-C0PJmBaO.d.ts.map → types-CMXR7A0b.d.ts.map} +1 -1
- package/dist/types-CzmghX7C.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/{url-D8KZ7Edw.js → url-D4vG7lzO.js} +2 -2
- package/dist/{url-D8KZ7Edw.js.map → url-D4vG7lzO.js.map} +1 -1
- package/dist/{version-bd3DQJkc.js → version-DDRBX7K6.js} +2 -2
- package/dist/{version-bd3DQJkc.js.map → version-DDRBX7K6.js.map} +1 -1
- package/dist/{workspace-exec-stream-CyfYgqAh.js → workspace-exec-stream-iHv9cooF.js} +5 -5
- package/dist/{workspace-exec-stream-CyfYgqAh.js.map → workspace-exec-stream-iHv9cooF.js.map} +1 -1
- package/dist/{write-file-QYrcDdl3.js → write-file-ChtRPdEL.js} +3 -3
- package/dist/{write-file-QYrcDdl3.js.map → write-file-ChtRPdEL.js.map} +1 -1
- package/dist/{ws-CURQ2igk.js → ws-B2HB87nz.js} +6 -6
- package/dist/{ws-CURQ2igk.js.map → ws-B2HB87nz.js.map} +1 -1
- package/dist/{ws-client-BVljYbdb.js → ws-client-DPC9ZJHr.js} +4 -4
- package/dist/{ws-client-BVljYbdb.js.map → ws-client-DPC9ZJHr.js.map} +1 -1
- package/docs/CODEMODE.md +6 -0
- package/docs/IPC.md +2 -0
- package/docs/ONBOARDING.md +1 -1
- package/package.json +1 -1
- package/dist/client-core-EEEX_u6D.d.ts.map +0 -1
- package/dist/dispatcher-Bv9-c6I2.js.map +0 -1
- package/dist/index-DyQyDLX1.d.ts.map +0 -1
- package/dist/oauth-7_48zR7n.js.map +0 -1
- package/dist/prelude-HzY_JEGq.js.map +0 -1
- package/dist/protocol-BIv1Yuvl.js.map +0 -1
- package/dist/secret-shapes-BjW4l6U0.js.map +0 -1
- package/dist/session-7TUHs42_.js.map +0 -1
- package/dist/spaces-CyjMh5Zf.js.map +0 -1
- package/dist/store-L01W0gGI.js.map +0 -1
- package/dist/transcript-reconcile-CPdrNbbR.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-reconcile-CPdrNbbR.js","names":["fzfByCatalog","fzfFor","fzfByCatalog"],"sources":["../src/chat/todo-glyphs.ts","../src/chat/agent-accent.ts","../src/chat/cache-hint.ts","../src/chat/color-gradient.ts","../src/chat/completion-commands.ts","../src/chat/completion-files.ts","../src/chat/completion-skills.ts","../src/chat/daemon-health.ts","../src/chat/onboarding/brands.ts","../src/chat/onboarding/native-extensions.ts","../src/chat/markdown-segments.ts","../src/chat/mcp-auth-state.ts","../src/chat/mcp-test-outcome.ts","../src/chat/model-catalog.ts","../src/chat/onboarding/connectors.ts","../src/chat/onboarding/features.ts","../src/chat/onboarding/presets.ts","../src/chat/onboarding/steps.ts","../src/chat/onboarding/flow.ts","../src/chat/onboarding/imports.ts","../src/chat/onboarding/preview.ts","../src/chat/onboarding/tutorials.ts","../src/chat/onboarding/words.ts","../src/chat/onboarding/recap.ts","../src/chat/onboarding/result.ts","../src/chat/onboarding/run.ts","../src/chat/onboarding/tradeoffs.ts","../src/chat/provider-usage-format.ts","../src/chat/run-activity.ts","../src/chat/spawn-tree.ts","../src/chat/streaming-pure.ts","../src/chat/tool-formatters.ts","../src/chat/transcript-reconcile.ts"],"sourcesContent":["import type { TodoStatus } from './todos'\n\n// Status glyphs — single source of truth for every UI surface that\n// renders a todo. Both the modal and the inline indicator import these\n// so the two read as the same visual language. Glyphs are intentionally\n// monochrome / single-cell so they line up cleanly in a column.\n//\n// pending ☐ empty box — \"queued\"\n// in_progress ◐ half-filled circle — \"currently working\"\n// completed ☑ checked box — \"done\"\n// cancelled ☒ crossed box — \"no longer relevant\"\n//\n// The inline indicator uses the `in_progress` glyph as its prefix so a\n// quick glance at the bar matches the modal's row marker. Renderer-\n// agnostic by design — a GUI shell can reuse the same map verbatim.\n/** Glyph shown for each todo status. */\nexport const TODO_STATUS_GLYPHS: Readonly<Record<TodoStatus, string>> = {\n pending: '☐',\n in_progress: '◐',\n completed: '☑',\n cancelled: '☒',\n}\n","/**\n * Agent profile accent tokens, split from `./agents` (which pulls the tool\n * runtime) so the GUI renderer resolves them through `zidane/chat/pure`.\n */\n\n/**\n * Theme color token used to accent the active profile in the UI (footer\n * badge, picker highlight). Resolved against `ThemeColors` via\n * `useColors()`; falls back to `accent` when omitted.\n */\nexport type AgentAccent = 'brand' | 'accent' | 'warn' | 'model'\n\n/**\n * Resolve a profile's `accent` token to a concrete hex color via the\n * caller's color palette. Renderer-agnostic — accepts the four-role\n * subset of `ThemeColors` that's relevant to accent surfaces, so this\n * helper composes against either `useColors()` (TUI) or a CSS-variable\n * lookup (GUI). Omitted / unknown tokens fall back to `accent`.\n *\n * @param accent - Accent token from an agent profile. Unknown or missing tokens use `accent`.\n * @param COLOR - Palette that supplies the `brand`, `accent`, `warn` and `model` colors.\n */\nexport function accentColor(\n accent: AgentAccent | (string & {}) | undefined,\n COLOR: { brand: string, accent: string, warn: string, model: string },\n): string {\n switch (accent) {\n case 'brand': return COLOR.brand\n case 'warn': return COLOR.warn\n case 'model': return COLOR.model\n case 'accent':\n default:\n return COLOR.accent\n }\n}\n","/**\n * The cache-cost hint a model, effort or agent picker shows next to an\n * option: one wording and one floor for the TUI and the desktop app.\n */\nimport type { CacheImpact } from './host/cache-view'\nimport { formatCount } from './format'\n\n/** Below this many re-read tokens a switch is cheap: short sessions show no hint. */\nexport const CACHE_HINT_MIN_TOKENS = 20_000\n\n/**\n * The hint for an option: `re-reads ~452k tokens` when picking it would\n * re-read a long prompt. Nothing for the current option, a switch that keeps\n * the cache, a cache already expired (it is gone anyway), a short prompt, or\n * an unknown estimate.\n *\n * @param impact - The host's estimate for the option (`ChatHost.cacheImpact`), `null` / `undefined` when unknown.\n * @param current - The option is the one in force: picking it changes nothing.\n */\nexport function cacheHintText(impact: CacheImpact | null | undefined, current = false): string | undefined {\n if (current || !impact || impact.keepsCache || impact.expired || impact.tokens < CACHE_HINT_MIN_TOKENS)\n return undefined\n return `re-reads ~${formatCount(impact.tokens)} tokens`\n}\n","// ---------------------------------------------------------------------------\n// HSL color gradient helpers — shared between the Crush throbber (cycling\n// per-frame paint) and the title overlay (static per-character paint).\n//\n// Renderer-agnostic on purpose: a future GUI shell wants the same ramp\n// math against the same hex strings the theme palette already stores, so\n// this lives in `zidane/chat` next to the theme definition rather than\n// inside the TUI's OpenTUI layer.\n//\n// We blend in HSL with shortest-path hue interpolation rather than\n// straight sRGB lerp because saturated palette pairs (e.g. Charple →\n// Dolly = purple → magenta) would muddy through grey when interpolated\n// componentwise in RGB. HSL keeps the path along the hue ring, so the\n// gradient stays vivid.\n// ---------------------------------------------------------------------------\n\n/** Parse `#rrggbb` (case-insensitive) into `[r, g, b]` 0–255 integers. */\nfunction parseHex(hex: string): [number, number, number] {\n const h = hex.replace('#', '')\n return [\n Number.parseInt(h.slice(0, 2), 16),\n Number.parseInt(h.slice(2, 4), 16),\n Number.parseInt(h.slice(4, 6), 16),\n ]\n}\n\n/** Convert sRGB 0–255 → HSL 0–1. */\nfunction rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n r /= 255\n g /= 255\n b /= 255\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const l = (max + min) / 2\n if (max === min)\n return [0, 0, l]\n const d = max - min\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n let h: number\n if (max === r)\n h = (g - b) / d + (g < b ? 6 : 0)\n else if (max === g)\n h = (b - r) / d + 2\n else\n h = (r - g) / d + 4\n return [h / 6, s, l]\n}\n\n/** Convert HSL 0–1 → sRGB 0–255. Standard piecewise formula. */\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n if (s === 0)\n return [l * 255, l * 255, l * 255]\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0)\n t += 1\n if (t > 1)\n t -= 1\n if (t < 1 / 6)\n return p + (q - p) * 6 * t\n if (t < 1 / 2)\n return q\n if (t < 2 / 3)\n return p + (q - p) * (2 / 3 - t) * 6\n return p\n }\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n return [\n hue2rgb(p, q, h + 1 / 3) * 255,\n hue2rgb(p, q, h) * 255,\n hue2rgb(p, q, h - 1 / 3) * 255,\n ]\n}\n\nfunction toHex(rgb: readonly [number, number, number]): string {\n const pad = (v: number) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, '0')\n return `#${pad(rgb[0])}${pad(rgb[1])}${pad(rgb[2])}`\n}\n\n/**\n * Blend two hex colors in HSL space with shortest-path hue interpolation.\n * `t` ∈ [0, 1]; `t=0` returns `from`, `t=1` returns `to`.\n *\n * @param from - Start color as a hex string.\n * @param to - End color as a hex string.\n * @param t - Blend position from 0 to 1.\n */\nexport function blendHsl(from: string, to: string, t: number): string {\n const [r1, g1, b1] = parseHex(from)\n const [r2, g2, b2] = parseHex(to)\n const [h1, s1, l1] = rgbToHsl(r1, g1, b1)\n const [h2, s2, l2] = rgbToHsl(r2, g2, b2)\n // Shortest path around the hue wheel — purple→pink shouldn't detour\n // through cyan just because the raw subtraction is positive.\n let dh = h2 - h1\n if (dh > 0.5)\n dh -= 1\n else if (dh < -0.5)\n dh += 1\n const h = (h1 + dh * t + 1) % 1\n const s = s1 + (s2 - s1) * t\n const l = l1 + (l2 - l1) * t\n return toHex(hslToRgb(h, s, l))\n}\n\n/**\n * Static gradient ramp of length `n` going from `from` (index 0) to\n * `to` (index n-1) in HSL space. For the cycling A→B→A→B ramp the\n * throbber uses, see `buildCycleRamp` in `src/tui/crush-throbber.tsx`.\n *\n * @param from - Start color as a hex string.\n * @param to - End color as a hex string.\n * @param n - Number of colors in the ramp. A value of 0 or less returns an empty ramp.\n */\nexport function buildLinearRamp(from: string, to: string, n: number): string[] {\n if (n <= 0)\n return []\n if (n === 1)\n return [blendHsl(from, to, 0.5)]\n const ramp: string[] = []\n for (let i = 0; i < n; i++)\n ramp.push(blendHsl(from, to, i / (n - 1)))\n return ramp\n}\n","/**\n * Completion provider exposing `/` commands in the popover, as a peer to the\n * skills provider on the same trigger (the engine merges both via\n * {@link mergeSuggestions}, tagging each with its `label` section).\n *\n * Suggest-only: commands are invoked as the WHOLE prompt (`/name …`), so\n * they're not inline \"references\". `parseReferences` returns none; the host's\n * submit path detects command invocations via `parseCommandInvocation`.\n */\n\nimport type { Command } from './commands'\nimport type { CompletionItem, CompletionProvider } from './completion-core'\nimport { Fzf } from 'fzf'\n\n/** Trigger character — shared with skills. */\nexport const COMMANDS_TRIGGER = '/'\n\n/**\n * Per-catalog fzf instance, keyed on catalog reference identity —\n * `suggest()` runs per keystroke and `new Fzf(...)` walks the whole\n * command list to build its match structures. The getter returns a\n * stable array until a registry rebuild swaps it.\n */\nconst fzfByCatalog = new WeakMap<readonly Command[], Fzf<readonly Command[]>>()\n\nfunction fzfFor(catalog: readonly Command[]): Fzf<readonly Command[]> {\n let fzf = fzfByCatalog.get(catalog)\n if (!fzf) {\n fzf = new Fzf(catalog, { selector: c => c.name, casing: 'case-insensitive' })\n fzfByCatalog.set(catalog, fzf)\n }\n return fzf\n}\n\n/** Filter + rank commands against a query: name or alias prefix, then name, alias or group substring, then description, then fuzzy on name. */\nfunction scoreCommands(catalog: readonly Command[], query: string): CompletionItem<Command>[] {\n const q = query.trim().toLowerCase()\n const fuzzyHits = q.length > 0\n ? new Set(fzfFor(catalog).find(q).map(r => r.item))\n : null\n const scored: { command: Command, rank: number }[] = []\n for (const command of catalog) {\n const name = command.name.toLowerCase()\n const aliases = (command.aliases ?? []).map(a => a.toLowerCase())\n const group = command.group?.toLowerCase()\n const desc = command.description.toLowerCase()\n if (q.length === 0)\n scored.push({ command, rank: 4 })\n else if (name.startsWith(q) || aliases.some(a => a.startsWith(q)))\n scored.push({ command, rank: 0 })\n // Group (source extension) match — `/git-flow` lists every command the\n // git-flow extension contributes. Ranked with name-substring hits so\n // they sit above description/fuzzy noise. Requires ≥2 typed chars so a\n // single letter (`/g`) doesn't flood every command of a same-initial\n // extension above ordinary matches.\n else if (name.includes(q) || aliases.some(a => a.includes(q)) || (group !== undefined && q.length >= 2 && group.startsWith(q)))\n scored.push({ command, rank: 1 })\n else if (desc.includes(q))\n scored.push({ command, rank: 2 })\n else if (fuzzyHits?.has(command))\n scored.push({ command, rank: 3 })\n }\n scored.sort((a, b) => a.rank !== b.rank ? a.rank - b.rank : a.command.name.localeCompare(b.command.name))\n return scored.map<CompletionItem<Command>>(({ command }) => ({\n id: command.name,\n label: command.name,\n description: command.aliases?.length\n ? `${command.description} (alias: ${command.aliases.map(a => `/${a}`).join(', ')})`\n : command.description,\n insertText: `${COMMANDS_TRIGGER}${command.name} `,\n data: command,\n }))\n}\n\n/**\n * Build a commands completion provider against a *live* command list. The\n * getter is re-evaluated per `suggest` so registry toggles / cwd rebuilds\n * take effect without re-instantiating the provider.\n *\n * @param opts - Options. `getCommands` returns the current command list and is re-read on every suggestion.\n */\nexport function createCommandsCompletionProvider(opts: {\n getCommands: () => readonly Command[]\n}): CompletionProvider<Command> {\n return {\n id: 'commands',\n trigger: COMMANDS_TRIGGER,\n label: 'Commands',\n // Stay active across spaces so `/deploy stag▌` reaches us with query\n // `deploy stag` for ARGUMENT completion (see `allowSpacesInQuery`).\n allowSpacesInQuery: true,\n suggest(query, ctx) {\n // Argument position: `<name> <argsPrefix>` where <name> is a known\n // command that offers completions — and only when the invocation is\n // the whole prompt (leading token), matching submit semantics.\n const spaceIdx = query.search(/\\s/)\n if (spaceIdx !== -1) {\n if (ctx.text.trimStart()[0] !== COMMANDS_TRIGGER)\n return []\n const typed = query.slice(0, spaceIdx).toLowerCase()\n const command = opts.getCommands().find(c =>\n c.name.toLowerCase() === typed || c.aliases?.some(a => a.toLowerCase() === typed))\n if (!command?.completeArgs)\n return []\n const argsPrefix = query.slice(spaceIdx + 1).replace(/^\\s+/, '')\n return Promise.resolve(command.completeArgs(argsPrefix)).then(suggestions =>\n (suggestions ?? []).map(s => ({\n id: `${command.name}:${s.value}`,\n label: s.label ?? s.value,\n ...(s.description !== undefined ? { description: s.description } : {}),\n insertText: `${COMMANDS_TRIGGER}${command.name} ${s.value} `,\n data: command,\n })),\n )\n }\n return scoreCommands(opts.getCommands(), query)\n },\n // Commands are whole-prompt invocations, not inline references.\n parseReferences() {\n return []\n },\n }\n}\n","/**\n * Completion provider that exposes the discovered project file catalog\n * (files AND directories — see `FileEntry.kind`) as `@`-prefixed\n * mentions. Trigger: `@`. Filtering: case-insensitive substring match against\n * name and path, with an fzf fuzzy fallback on the basename. Inserted text is `@{path} ` (`@{path}/ ` for\n * directories) so the cursor lands ready for the next token.\n *\n * Provider is pure UI — file *attachment* (reading bytes, injecting into\n * the prompt) happens at the submission boundary, where the host walks\n * `state.references` and decides what to do with each `FileEntry`.\n */\n\nimport type {\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n} from './completion-core'\nimport type { FileEntry } from './files-discovery'\nimport { Fzf } from 'fzf'\n\n/** Trigger character — `@` is the conventional file-mention prefix in chat UIs. */\nexport const FILES_TRIGGER = '@'\n\n/** Cap on returned items. Keeps the popover compact + render-cheap. */\nconst DEFAULT_RESULT_LIMIT = 50\n\n/** Identity formatter — preserves the discovery path verbatim. */\nconst IDENTITY_FORMAT = (entry: FileEntry): string => entry.path\n\n/**\n * Per-catalog fzf instance, keyed on catalog reference identity.\n * `suggest()` runs on every keystroke and `new Fzf(...)` walks the whole\n * catalog (up to ~10k entries on monorepos) to build its match structures\n * — rebuilding that per keystroke dominated the popover's latency. The\n * catalog getter returns a stable array until a re-scan swaps it, so a\n * WeakMap on the array reference invalidates exactly when it should.\n */\nconst fzfByCatalog = new WeakMap<readonly FileEntry[], Fzf<readonly FileEntry[]>>()\n\nfunction fzfFor(catalog: readonly FileEntry[]): Fzf<readonly FileEntry[]> {\n let fzf = fzfByCatalog.get(catalog)\n if (!fzf) {\n fzf = new Fzf(catalog, {\n selector: f => f.name,\n casing: 'case-insensitive',\n })\n fzfByCatalog.set(catalog, fzf)\n }\n return fzf\n}\n\n/**\n * Displayed/inserted form of a catalog entry. Directories carry a\n * trailing `/` so the emitted mention (`@src/chat/`) is visually and\n * semantically unambiguous — both to the user and to the agent's\n * path-resolving tools.\n */\nfunction displayOf(entry: FileEntry, formatPath: (entry: FileEntry) => string): string {\n const base = formatPath(entry)\n return entry.kind === 'dir' && !base.endsWith('/') ? `${base}/` : base\n}\n\n/**\n * Rank-and-slice a file catalog against a query. Hoisted to a module\n * helper so both the sync and async branches of `suggest()` share one\n * implementation (the async branch hits this once the lazy directory\n * walk resolves; sync branch hits it on every keystroke thereafter).\n *\n * `formatPath` rewrites the catalog's project-root-relative path into\n * the form the host wants emitted into the prompt (typically CWD-rel\n * or absolute when launched from a project subdir — see\n * `formatPathForCwd` in `path-display.ts`). Falls back to the raw\n * `entry.path` when omitted.\n */\nfunction scoreFiles(\n catalog: readonly FileEntry[],\n query: string,\n limit: number,\n formatPath: (entry: FileEntry) => string,\n): CompletionItem<FileEntry>[] {\n const q = query.trim().toLowerCase()\n // Pre-pass: fzf over the catalog's basenames feeds the rank-4 fuzzy\n // tier, catching small typos / omissions (`lop.ts` → `loop.ts`).\n // Scoped to basename — a path-wide fuzzy match would surface\n // near-random files on short queries. fzf enforces in-order\n // (subsequence) matching, so the fuzzy tier never degenerates into a\n // bag-of-chars filter. We keep only set membership (not fzf's score):\n // within-tier ordering stays alphabetical, and the Set keeps the loop\n // below O(1) per file.\n const fuzzyHits = q.length > 0\n ? new Set(fzfFor(catalog).find(q).map(r => r.item))\n : null\n const scored: { entry: FileEntry, display: string, rank: number }[] = []\n for (const file of catalog) {\n const display = displayOf(file, formatPath)\n const name = file.name.toLowerCase()\n const path = display.toLowerCase()\n if (q.length === 0) {\n scored.push({ entry: file, display, rank: 5 })\n continue\n }\n if (name === q) {\n scored.push({ entry: file, display, rank: 0 })\n continue\n }\n if (name.startsWith(q)) {\n scored.push({ entry: file, display, rank: 1 })\n continue\n }\n if (name.includes(q)) {\n scored.push({ entry: file, display, rank: 2 })\n continue\n }\n if (path.includes(q)) {\n scored.push({ entry: file, display, rank: 3 })\n continue\n }\n if (fuzzyHits?.has(file)) {\n scored.push({ entry: file, display, rank: 4 })\n continue\n }\n }\n scored.sort((a, b) => {\n if (a.rank !== b.rank)\n return a.rank - b.rank\n return a.display.localeCompare(b.display)\n })\n return scored.slice(0, limit).map<CompletionItem<FileEntry>>(({ entry, display }) => ({\n id: display,\n // Directories carry the trailing `/` on the label too so rows are\n // distinguishable at a glance in the popover.\n label: entry.kind === 'dir' ? `${entry.name}/` : entry.name,\n // Description is the parent directory — gives the user disambiguation\n // signal when multiple files share a basename (`index.ts` × 12).\n //\n // Uses the catalog's RAW project-root-relative path, NOT the\n // cwd-formatted `display`. The cwd-formatted path flips a file's\n // visible shape based on whether it sits above or below\n // `process.cwd()` (absolute parent vs cwd-relative parent vs\n // empty for \"right here\"), which produces a popover that looks\n // half-broken when the same basename exists in multiple project\n // locations: `EDIT_THIS.md /Users/…/zidane` next to plain\n // `EDIT_THIS.md` for a sibling under the cwd. Anchoring the\n // description on `file.path` keeps the disambiguation column\n // stable + project-shaped regardless of where the user launched\n // the TUI from; the inserted text still uses `display` so the\n // tools can resolve it.\n description: parentDir(entry.path),\n insertText: `${FILES_TRIGGER}${display} `,\n data: entry,\n }))\n}\n\n/**\n * Build an `@`-prefixed files completion provider against a *live* catalog.\n *\n * The factory captures a getter so the catalog can be re-scanned (cwd\n * change, manual refresh) without re-instantiating the provider — the\n * App keeps one provider for the lifetime of the prompt block and just\n * mutates the underlying state.\n *\n * `limit` caps the result list so the popover stays bounded on huge\n * monorepos. Filtering is substring on `path` + `name`, case-insensitive,\n * with an fzf-scored basename fuzzy fallback so small typos / omissions\n * (`lop.ts` → `loop.ts`) still surface results; ranking prefers (in\n * order): exact name match, name prefix, name substring, path substring,\n * basename fuzzy match, alphabetical.\n *\n * @param opts - Options: the live file catalog, an optional lazy catalog loader, a result limit and a path rewriter.\n */\nexport function createFilesCompletionProvider(opts: {\n /** Live file catalog. Re-evaluated per call so refreshes take effect immediately. */\n getCatalog: () => readonly FileEntry[]\n /**\n * Optional hook called the first time the host needs the catalog —\n * e.g. when the user opens the `@` popover. Hosts wire this to a\n * lazy directory walk so boot doesn't pay for it in monorepos\n * where the popover may never open. Idempotent contract: callers\n * may invoke it on every `suggest`; the host caches internally.\n *\n * When provided, `suggest()` returns a Promise on the very first\n * invocation if the catalog is still empty — the popover's loading\n * state surfaces while the walk completes; subsequent calls are\n * sync because `getCatalog()` then returns the populated state.\n */\n ensureCatalog?: () => Promise<readonly FileEntry[]>\n /** Max items returned to the popover. Default: 50. */\n limit?: number\n /**\n * Rewrite the catalog's project-root-relative path into the form\n * inserted into the prompt + matched by `parseReferences`. Wire this\n * to `formatPathForCwd` so paths emitted into the buffer line up\n * with the agent's CWD-resolving tools when the TUI launches from a\n * project subdirectory. Default: identity.\n *\n * Stable identity expected — `parseReferences` calls it once per\n * catalog entry per keystroke for the highlight pass; a pure-function\n * shape keeps the popover responsive on huge repos.\n */\n formatPath?: (entry: FileEntry) => string\n}): CompletionProvider<FileEntry> {\n const limit = opts.limit ?? DEFAULT_RESULT_LIMIT\n const formatPath = opts.formatPath ?? IDENTITY_FORMAT\n return {\n id: 'files',\n trigger: FILES_TRIGGER,\n label: 'Files',\n suggest(query) {\n // Kick off lazy discovery (no-op on subsequent calls). If the\n // host wired a thunk and the catalog isn't ready yet, hand the\n // popover a Promise — it already supports `loading` and refreshes\n // `items` when the promise resolves.\n if (opts.ensureCatalog) {\n const pending = opts.ensureCatalog()\n const current = opts.getCatalog()\n if (current.length === 0) {\n return pending.then(loaded => scoreFiles(loaded, query, limit, formatPath))\n }\n }\n return scoreFiles(opts.getCatalog(), query, limit, formatPath)\n },\n parseReferences(text, _ctx: CompletionContext) {\n const catalog = opts.getCatalog()\n if (catalog.length === 0)\n return []\n // Keyed by the DISPLAYED path (what `insertText` emitted) so a\n // post-format buffer still resolves back to its `FileEntry`.\n // Directories are additionally keyed by their slash-less form so a\n // hand-typed `@src/chat` resolves like the inserted `@src/chat/`\n // (no collision risk — a file and a dir can't share a path).\n const byPath = new Map<string, FileEntry>()\n for (const file of catalog) {\n const display = displayOf(file, formatPath)\n byPath.set(display, file)\n if (file.kind === 'dir')\n byPath.set(formatPath(file), file)\n }\n const refs: CompletionReference<FileEntry>[] = []\n // Match `@<path>` at start-of-buffer or after whitespace. Paths are\n // non-whitespace sequences — files contain `/`, `.`, `-`, etc., so a\n // word-boundary rule won't do. We greedy-match `\\S+` then trim\n // trailing punctuation that's almost never part of the intended\n // reference (sentence end). The trimmed candidate must exist in the\n // catalog for the span to be highlighted — typos don't produce\n // false-positive references.\n // Capture groups: 1 = leading boundary (start-of-buffer or whitespace),\n // 2 = path body without the `@` sigil. `@` itself is matched but not\n // captured because the consumer only needs the raw path to look up\n // the catalog entry.\n const rx = /(^|\\s)@(\\S+)/g\n for (const m of text.matchAll(rx)) {\n const rawCandidate = m[2]\n // Strip trailing `.`, `,`, `;`, `:`, `)` , `]`, `}`, `!`, `?` — when\n // the exact candidate isn't in the catalog but a shorter prefix is,\n // the user almost certainly mentioned the file in regular prose.\n // Single regex replace + slice instead of a per-char loop keeps this\n // O(n) in candidate length rather than O(n²) on pathological tails.\n const stripped = byPath.has(rawCandidate)\n ? rawCandidate\n : rawCandidate.replace(/[.,;:)\\]}!?]+$/, '')\n const file = byPath.get(stripped)\n if (!file)\n continue\n const start = m.index + m[1].length\n // `trimmed` matches the visible \"@<stripped>\" span — recompute its\n // length from `stripped` so we don't over-paint on the trailing punct.\n const trimmedLen = 1 + stripped.length // `@` + path\n refs.push({\n providerId: 'files',\n start,\n end: start + trimmedLen,\n // `itemId` mirrors `suggest()`'s `id` (the displayed path)\n // so the engine's reference ↔ item correlation stays\n // consistent on either side of the formatter. `data.path`\n // still carries the raw project-root-relative path for\n // downstream consumers (`uniqueFilesFromReferences`,\n // submission attach hooks, …). Canonicalized through\n // `displayOf` so a slash-less dir mention still correlates\n // with the suggestion item's id (which carries the `/`).\n itemId: displayOf(file, formatPath),\n data: file,\n })\n }\n return refs\n },\n }\n}\n\n/** Return the parent directory of a forward-slashed path, or `''` for root entries. */\nfunction parentDir(path: string): string {\n const lastSlash = path.lastIndexOf('/')\n return lastSlash <= 0 ? '' : path.slice(0, lastSlash)\n}\n\n/**\n * Walk a reference list and return the deduplicated set of files in\n * first-mention order — input to \"attach these files to the prompt\"\n * downstream logic.\n *\n * @param references - References collected from a prompt.\n */\nexport function uniqueFilesFromReferences(\n references: readonly CompletionReference<unknown>[],\n): FileEntry[] {\n const out: FileEntry[] = []\n const seen = new Set<string>()\n for (const ref of references) {\n if (ref.providerId !== 'files')\n continue\n if (seen.has(ref.itemId))\n continue\n seen.add(ref.itemId)\n out.push(ref.data as FileEntry)\n }\n return out\n}\n","/**\n * Completion provider that exposes the discovered skills catalog as\n * slash-commands. Trigger: `/`. Filtering: case-insensitive name prefix and\n * substring, description substring, then an fzf fuzzy fallback on the name.\n * Inserted text is `/{name} ` so the\n * cursor lands ready for the next token.\n *\n * Skill activation is **not** performed here — the provider is pure UI.\n * Submission flow at the host (TUI `onSubmitPrompt`) walks the prompt for\n * skill references via `parseReferences` and calls `agent.activateSkill`\n * before `agent.run`.\n */\n\nimport type { SkillConfig } from '../skills'\nimport type {\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n} from './completion-core'\nimport { Fzf } from 'fzf'\n\n/** Trigger character — slash-commands convention. */\nexport const SKILLS_TRIGGER = '/'\n\n/** Valid skill-name shape (matches the parser): lowercase alnum + dashes. */\nconst SKILL_NAME_RX = /^[a-z0-9][a-z0-9-]*$/\n\n/**\n * Per-catalog valid-set + fzf instance, keyed on catalog reference\n * identity — `suggest()` runs per keystroke and both the name filter and\n * `new Fzf(...)` walk the whole catalog. The getter returns a stable\n * array until a reload/toggle swaps it.\n */\nconst fzfByCatalog = new WeakMap<readonly SkillConfig[], { valid: SkillConfig[], fzf: Fzf<SkillConfig[]> }>()\n\nfunction validAndFzfFor(catalog: readonly SkillConfig[]): { valid: SkillConfig[], fzf: Fzf<SkillConfig[]> } {\n let cached = fzfByCatalog.get(catalog)\n if (!cached) {\n const valid = catalog.filter(skill => SKILL_NAME_RX.test(skill.name))\n cached = {\n valid,\n fzf: new Fzf(valid, {\n selector: s => s.name,\n casing: 'case-insensitive',\n }),\n }\n fzfByCatalog.set(catalog, cached)\n }\n return cached\n}\n\n/**\n * Filter + rank visible skills against a query. Hoisted to a module\n * helper so the sync and async branches of `suggest()` share one\n * implementation (the async branch hits this once the lazy SKILL.md\n * scan resolves; sync branch hits it on every keystroke thereafter).\n */\nfunction scoreSkills(\n catalog: readonly SkillConfig[],\n query: string,\n): CompletionItem<SkillConfig>[] {\n const q = query.trim().toLowerCase()\n const { valid, fzf } = validAndFzfFor(catalog)\n // fzf pre-pass over skill *names* so the rank-3 fuzzy tier catches\n // small typos (`reseach` → `research`). Scoped to name only — fuzzy\n // matching against descriptions (free-form sentences) would surface\n // near-random skills on short queries.\n const fuzzyHits = q.length > 0\n ? new Set(fzf.find(q).map(r => r.item))\n : null\n const scored: { skill: SkillConfig, rank: number }[] = []\n for (const skill of valid) {\n const name = skill.name.toLowerCase()\n const desc = skill.description.toLowerCase()\n if (q.length === 0) {\n scored.push({ skill, rank: 4 })\n continue\n }\n if (name.startsWith(q)) {\n scored.push({ skill, rank: 0 })\n continue\n }\n if (name.includes(q)) {\n scored.push({ skill, rank: 1 })\n continue\n }\n if (desc.includes(q)) {\n scored.push({ skill, rank: 2 })\n continue\n }\n if (fuzzyHits?.has(skill)) {\n scored.push({ skill, rank: 3 })\n continue\n }\n }\n scored.sort((a, b) => {\n if (a.rank !== b.rank)\n return a.rank - b.rank\n return a.skill.name.localeCompare(b.skill.name)\n })\n return scored.map<CompletionItem<SkillConfig>>(({ skill }) => ({\n id: skill.name,\n label: skill.name,\n description: skill.description,\n insertText: `${SKILLS_TRIGGER}${skill.name} `,\n data: skill,\n }))\n}\n\n/**\n * Build a slash-command completion provider against a *live* skills\n * catalog. The factory captures a getter so the catalog can change across\n * renders (toggles, reload) without re-instantiating the provider.\n *\n * Pass `getEnabled` to additionally hide skills the user has toggled off\n * — when undefined, every catalog entry is offered.\n *\n * @param opts - Options: the live skill catalog, an optional enabled-skills filter and an optional lazy catalog loader.\n */\nexport function createSkillsCompletionProvider(opts: {\n /** Live catalog. Re-evaluated per call so toggles take effect immediately. */\n getCatalog: () => readonly SkillConfig[]\n /** Optional enable-set filter; when undefined every catalog skill is offered. */\n getEnabled?: () => readonly string[] | undefined\n /**\n * Optional hook called the first time the host needs the catalog —\n * typically when the user opens the `/` popover. Mirror of the\n * files provider's `ensureCatalog`; same idempotent contract.\n *\n * Hosts wire this to a lazy SKILL.md scan so the boot path stays\n * free of disk reads in deeply-nested skill trees. Returns a Promise\n * on the very first `suggest()` call when the catalog is still\n * empty so the popover surfaces its loading state.\n */\n ensureCatalog?: () => Promise<readonly SkillConfig[]>\n}): CompletionProvider<SkillConfig> {\n const visible = (): SkillConfig[] => {\n const all = opts.getCatalog()\n const enabled = opts.getEnabled?.()\n if (enabled === undefined)\n return [...all]\n const allow = new Set(enabled)\n return all.filter(s => allow.has(s.name))\n }\n return {\n id: 'skills',\n trigger: SKILLS_TRIGGER,\n label: 'Skills',\n suggest(query) {\n // Lazy-load on first suggest if the host wired a thunk. Same\n // pattern as the files provider — popover loading state covers\n // the gap, subsequent suggests are sync.\n if (opts.ensureCatalog) {\n const pending = opts.ensureCatalog()\n if (opts.getCatalog().length === 0) {\n return pending.then(() => scoreSkills(visible(), query))\n }\n }\n return scoreSkills(visible(), query)\n },\n parseReferences(text, _ctx: CompletionContext) {\n const catalog = visible()\n if (catalog.length === 0)\n return []\n const byName = new Map<string, SkillConfig>()\n for (const skill of catalog) byName.set(skill.name, skill)\n const refs: CompletionReference<SkillConfig>[] = []\n // Match `/name` at start-of-buffer or after whitespace. The lookbehind\n // is implemented manually (no regex `\\b` because `/` isn't a word\n // character) so we work in environments that lack lookbehind support.\n // Grammar must match `SKILL_NAME_RX` — `[a-z0-9-]` only, no `_`. Using\n // `\\w` here would parse `/foo_bar` as a candidate, only for the catalog\n // lookup to drop it; aligning the two grammars keeps the parser honest.\n const rx = /(^|\\s)(\\/([a-z0-9][a-z0-9-]*))/g\n for (const m of text.matchAll(rx)) {\n const name = m[3]\n const skill = byName.get(name)\n if (!skill)\n continue\n const start = m.index + m[1].length\n refs.push({\n providerId: 'skills',\n start,\n end: start + m[2].length,\n itemId: skill.name,\n data: skill,\n })\n }\n return refs\n },\n }\n}\n\n/**\n * Walk a parsed prompt for skill references and return the deduplicated\n * list of skill names — input to `agent.activateSkill(name)` calls on\n * submit.\n *\n * @param references - References collected from a prompt.\n */\nexport function uniqueSkillNamesFromReferences(\n references: readonly CompletionReference<unknown>[],\n): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n for (const ref of references) {\n if (ref.providerId !== 'skills')\n continue\n if (seen.has(ref.itemId))\n continue\n seen.add(ref.itemId)\n out.push(ref.itemId)\n }\n return out\n}\n","/**\n * Daemon connection health — the one model behind the status dot in both\n * clients' footers.\n *\n * Three states, because \"connected: boolean\" cannot express the one users\n * actually want to see: a daemon that is being spawned or reconnected is not\n * DOWN, and painting it red for the seconds that takes teaches people to\n * ignore red. So:\n *\n * - `connected` — handshake done, signals live. green (accent)\n * - `connecting` — spawning / reconnecting / first attempt. amber (warn)\n * - `disconnected` — reachable daemon absent, last attempt failed. red (error)\n *\n * Tones are theme SLOTS, not colors, so the dot recolors with the palette on\n * both surfaces. Node-free; re-exported from `zidane/chat/pure`.\n */\nexport type DaemonHealth = 'connected' | 'connecting' | 'disconnected'\n\n/** Theme tone used to color the daemon health dot. */\nexport type DaemonHealthTone = 'accent' | 'warn' | 'error'\n\n/** How the daemon health dot is styled. */\nexport interface DaemonHealthStyle {\n /** Theme tone of the dot. */\n tone: DaemonHealthTone\n /** Tooltip / accessibility text. The dot itself carries no words. */\n label: string\n}\n\n/** Glyph drawn for the daemon health dot. */\nexport const DAEMON_HEALTH_GLYPH = '●'\n\n/** Tone and label to use for each {@link DaemonHealth} state. */\nexport const DAEMON_HEALTH_STYLE: Readonly<Record<DaemonHealth, DaemonHealthStyle>> = {\n connected: { tone: 'accent', label: 'daemon connected' },\n connecting: { tone: 'warn', label: 'connecting to daemon…' },\n disconnected: { tone: 'error', label: 'daemon unreachable' },\n}\n","/**\n * The logos of the services the wizard names, as slugs of the kit's logo set\n * (`BrandMark` in `@zidane/ui`: Simple Icons, plus LobeHub Icons for the\n * model providers that Simple Icons lacks). Connectors and native extensions\n * carry theirs in their catalog entry. The providers, the other agents and the\n * local model servers have theirs here. A service with no slug shows a letter,\n * such as Pi, Context7, DeepWiki and Playwright.\n */\nimport type { OnboardingAgentId, OnboardingLocalServer } from './types'\n\n/** The logo of each built-in provider, by provider key. */\nexport const PROVIDER_BRANDS: Readonly<Record<string, string>> = {\n 'anthropic': 'anthropic',\n 'arcee': 'arcee',\n 'baseten': 'baseten',\n 'cerebras': 'cerebras',\n 'openai': 'openai',\n 'xai': 'xai',\n 'zai': 'zai',\n 'google': 'googlegemini',\n 'google-vertex': 'googlecloud',\n 'openrouter': 'openrouter',\n 'mistral': 'mistralai',\n 'cursor': 'cursor',\n}\n\n/** The logo of each agent whose setup the wizard reads. Pi has none. */\nexport const ONBOARDING_AGENT_BRANDS: Readonly<Record<OnboardingAgentId, string | undefined>> = {\n 'claude-code': 'claudecode',\n 'codex': 'codex',\n 'pi': undefined,\n}\n\n/** The logo of each local model server the wizard looks for. */\nexport const LOCAL_SERVER_BRANDS: Readonly<Record<OnboardingLocalServer['kind'], string>> = {\n 'ollama': 'ollama',\n 'lm-studio': 'lmstudio',\n 'vllm': 'vllm',\n}\n\n/**\n * The logo of a provider, as a Simple Icons slug.\n *\n * @param key - The provider key.\n * @example\n * ```ts\n * import { providerBrand } from 'zidane/chat/pure'\n *\n * providerBrand('google') // 'googlegemini'\n * ```\n */\nexport function providerBrand(key: string): string | undefined {\n return PROVIDER_BRANDS[key]\n}\n","/**\n * The native extensions: the user-facing folders of the zidane repository's\n * `extensions/`, installable from the wizard in one click. Each installs from\n * the repository at the running version's tag, so it matches the app's API.\n * `test/chat/onboarding-native-extensions.test.ts` keeps this list and the\n * folder in sync.\n */\nimport type { NativeExtensionEntry, NativeExtensionGroup } from './types'\n\n/** The GitHub repository native extensions install from. */\nexport const NATIVE_EXTENSIONS_REPO = 'Tahul/zidane'\n\n/** Every native extension, in display order within each group. */\nexport const NATIVE_EXTENSIONS: readonly NativeExtensionEntry[] = [\n {\n name: 'git-flow',\n label: 'Git flow',\n description: 'Adds /commit, /review, /fix, /pr and /ticket. The agent writes your commits and pull requests, and reviews code with several models.',\n group: 'workflows',\n needs: [\n { kind: 'command', name: 'git', why: 'commits and branches' },\n { kind: 'command', name: 'gh', why: 'pull requests and review comments', optional: true },\n ],\n brand: 'git',\n },\n {\n name: 'goal',\n label: 'Goal',\n description: 'Adds /goal. The agent keeps working until the goal is done, for up to 10 runs. Esc stops it.',\n group: 'workflows',\n needs: [{ kind: 'decisions' }],\n },\n {\n name: 'linear',\n label: 'Linear',\n description: 'Shows Linear issues and projects as badges in prompts and replies, and links them to the chats that use them.',\n group: 'integrations',\n needs: [{ kind: 'connector', id: 'linear' }],\n brand: 'linear',\n },\n {\n name: 'ai-autocomplete',\n label: 'AI autocomplete',\n description: 'Suggests the end of your prompt as you type, from a local Ollama model. Press Tab to accept.',\n group: 'composer',\n needs: [\n { kind: 'command', name: 'ollama', why: 'serves the model', optional: true },\n { kind: 'command', name: 'docker', why: 'runs Ollama for you when it is not installed', optional: true },\n ],\n brand: 'ollama',\n },\n {\n name: 'bolt',\n label: 'Bolt',\n description: 'Adds Bolt as a provider. Sign in with your Bolt account to use its models.',\n group: 'providers',\n needs: [{ kind: 'account', label: 'Bolt' }],\n provider: 'bolt',\n },\n]\n\n/**\n * Folders of `extensions/` left out of the wizard on purpose, with the reason.\n * Every folder is either listed above or here.\n */\nexport const EXCLUDED_NATIVE_EXTENSIONS: Readonly<Record<string, string>> = {\n 'plugin-host': 'A demo of ctx.loadAgentPlugin for the repository\\'s own tests, not something to install.',\n 'headroom': 'Not offered in the setup wizard for now.',\n 'pxpipe': 'Not offered in the setup wizard for now.',\n 'antigravity': 'Not offered in the setup wizard for now. It is not official.',\n}\n\n/** A section of the Extensions step. */\nexport interface NativeExtensionGroupMeta {\n /** The section. */\n id: NativeExtensionGroup\n /** Its heading. */\n label: string\n}\n\n/** The step's sections, in display order. */\nexport const NATIVE_EXTENSION_GROUPS: readonly NativeExtensionGroupMeta[] = [\n { id: 'workflows', label: 'Workflows' },\n { id: 'integrations', label: 'Integrations' },\n { id: 'composer', label: 'Composer' },\n { id: 'providers', label: 'Providers' },\n]\n\n/**\n * A native extension by name, or `undefined`.\n *\n * @param name - The extension name.\n */\nexport function nativeExtensionByName(name: string): NativeExtensionEntry | undefined {\n return NATIVE_EXTENSIONS.find(entry => entry.name === name)\n}\n\n/**\n * The install source of a native extension, pinned to a release tag:\n * `Tahul/zidane#v<version>:extensions/<name>`, the grammar\n * `installExtensionFromSpec` takes.\n *\n * @param entry - The extension.\n * @param version - The running zidane version (`ZIDANE_VERSION`), without the `v`.\n * @example\n * ```ts\n * import { nativeExtensionByName, nativeExtensionSource } from 'zidane/chat/pure'\n *\n * nativeExtensionSource(nativeExtensionByName('goal')!, '8.1.0')\n * // 'Tahul/zidane#v8.1.0:extensions/goal'\n * ```\n */\nexport function nativeExtensionSource(entry: NativeExtensionEntry, version: string): string {\n return `${NATIVE_EXTENSIONS_REPO}#v${version.replace(/^v/, '')}:extensions/${entry.name}`\n}\n","// ---------------------------------------------------------------------------\n// Renderer-agnostic markdown text segmenter.\n//\n// `splitMarkdownCodeBlocks` walks a markdown string once and emits an\n// ordered list of prose / fenced-code segments. Useful for any consumer\n// that wants to render fenced code differently from prose (a TUI that\n// wraps fences with a copy header, a GUI that hands fenced bodies to a\n// Monaco-style editor, a renderer that pipes prose through `marked` and\n// fences through Shiki, etc).\n//\n// Lives in `zidane/chat` so future renderer shells get the same\n// segmenter — no OpenTUI dependency, no React dependency, pure\n// string-in / array-out.\n// ---------------------------------------------------------------------------\n\n/**\n * One block returned by {@link splitMarkdownCodeBlocks}. Prose segments\n * carry their original markdown (including blank lines that bracketed\n * the fence) so the surrounding paragraph spacing stays faithful to the\n * original input. Code segments carry the raw body — fence markers and\n * info-string stripped — so a \"copy code\" action lands what the user\n * actually sees, byte-for-byte.\n */\nexport interface MarkdownSegment {\n /** Whether the segment is markdown prose or a fenced code body. */\n kind: 'prose' | 'code'\n /** Prose markdown, or the raw code body without fence markers. */\n content: string\n /** Info-string (e.g. `ts`, `python`). Empty when the fence had none. */\n lang?: string\n /**\n * Meant for a code segment whose closing fence hasn't arrived yet.\n * {@link splitMarkdownCodeBlocks} never sets it: it returns an unclosed\n * fence as prose instead.\n */\n open?: boolean\n}\n\n/**\n * Split markdown text into alternating prose / fenced-code segments.\n *\n * Recognizes both ` ``` ` and `~~~` fences, with arbitrary length ≥ 3,\n * matching CommonMark's \"fence indicator must be at least as long to\n * close\" rule. Info-strings (the bit after the opening fence) are kept\n * as the `lang` hint; any trailing whitespace is trimmed. Closing\n * fences are detected on a line of their own (whitespace tolerated).\n *\n * Unclosed fences fall back to emitting the would-be-code body as a\n * trailing prose segment so no content is dropped — finalized markdown\n * isn't expected to ship one, but the fallback keeps the renderer\n * truthful when the model produces malformed output.\n *\n * Exported for unit tests.\n *\n * @param text - Markdown, possibly mid-stream with an unclosed fence.\n * @example\n * ```ts\n * import { splitMarkdownCodeBlocks } from 'zidane/chat/pure'\n *\n * const segments = splitMarkdownCodeBlocks('Run:\\n~~~bash\\nls\\n~~~')\n * segments.map(s => s.kind) // ['prose', 'code']\n * ```\n */\nexport function splitMarkdownCodeBlocks(text: string): MarkdownSegment[] {\n const lines = text.split('\\n')\n const segments: MarkdownSegment[] = []\n let prose: string[] = []\n let code: string[] = []\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n let lang = ''\n\n // Drop a single trailing/leading blank line off each emitted prose\n // segment. Markdown convention puts a blank line between a paragraph\n // and the fence that follows; without trimming, that blank stacks\n // with the code panel's `marginTop: 1` (and symmetrically with\n // `marginBottom: 1` on the post-fence side), producing a double-blank\n // gap when the renderer adds its own panel margins.\n const flushProse = () => {\n if (prose.length > 0 && prose[prose.length - 1] === '')\n prose.pop()\n if (prose.length > 0) {\n segments.push({ kind: 'prose', content: prose.join('\\n') })\n prose = []\n }\n }\n\n let trimLeadingProseBlank = false\n\n for (const line of lines) {\n if (!inFence) {\n const open = line.match(/^(`{3,}|~{3,})([^\\n`~]*)$/)\n if (open) {\n flushProse()\n inFence = true\n fenceChar = open[1]![0]!\n fenceLen = open[1]!.length\n lang = open[2]!.trim()\n code = []\n continue\n }\n if (trimLeadingProseBlank) {\n trimLeadingProseBlank = false\n if (line === '' && prose.length === 0)\n continue\n }\n prose.push(line)\n }\n else {\n const close = line.match(/^(`{3,}|~{3,})\\s*$/)\n if (close && close[1]![0]! === fenceChar && close[1]!.length >= fenceLen) {\n segments.push({ kind: 'code', content: code.join('\\n'), lang })\n inFence = false\n code = []\n trimLeadingProseBlank = true\n continue\n }\n code.push(line)\n }\n }\n\n if (inFence) {\n prose.push(`${fenceChar.repeat(fenceLen)}${lang}`, ...code)\n }\n flushProse()\n return segments\n}\n\n/**\n * Remove HTML comments from markdown PROSE while leaving fenced code and\n * inline code spans untouched (`<!-- -->` inside a fence or backticks is\n * legitimate content the user must see). Comments may span lines; a line\n * reduced to whitespace by comment removal is dropped entirely so no\n * phantom paragraph gap remains.\n */\nexport function stripHtmlCommentsOutsideCode(text: string): string {\n // Without an opener the scan below rebuilds `text` unchanged; a streaming\n // reply re-runs this on every tick, so skip the O(L) walk.\n if (!text.includes('<!--'))\n return text\n const lines = text.split('\\n')\n const out: string[] = []\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n let inComment = false\n\n for (const line of lines) {\n if (inFence) {\n out.push(line)\n if (isFenceClose(line, fenceChar, fenceLen))\n inFence = false\n continue\n }\n if (!inComment) {\n const open = parseFenceOpen(line)\n if (open) {\n out.push(line)\n inFence = true\n fenceChar = open.char\n fenceLen = open.length\n continue\n }\n }\n\n // Prose line: char scan tracking inline code spans (`…`) and the\n // cross-line comment state.\n let result = ''\n let i = 0\n let spanTicks = 0\n let dropped = false\n while (i < line.length) {\n if (inComment) {\n const end = line.indexOf('-->', i)\n if (end === -1) {\n i = line.length\n break\n }\n i = end + 3\n inComment = false\n continue\n }\n const ch = line[i]!\n if (ch === '`') {\n let run = 1\n while (line[i + run] === '`')\n run++\n if (spanTicks === 0)\n spanTicks = run\n else if (run === spanTicks)\n spanTicks = 0\n result += line.slice(i, i + run)\n i += run\n continue\n }\n if (spanTicks === 0 && line.startsWith('<!--', i)) {\n inComment = true\n dropped = true\n i += 4\n continue\n }\n result += ch\n i++\n }\n\n // A line that held only comment content vanishes with it.\n if (dropped && result.trim() === '' && line.trim() !== '')\n continue\n if (inComment && result.trim() === '' && line.trim() !== '')\n continue\n out.push(result)\n }\n return out.join('\\n')\n}\n\nconst LIST_ITEM_RE = /^( *)(?:[-+*]|\\d+[.)]) +/\n\n/**\n * Lift indented fenced code blocks to column 0 while preserving the code\n * body's relative indentation.\n *\n * OpenTUI's markdown renderNode hook only receives top-level code tokens.\n * A common assistant shape is:\n *\n * - Run this:\n * ```bash\n * command\n * ```\n *\n * Marked parses that as code inside a list token, so the TUI loses the\n * code-panel wrapper and copy affordance. Normalizing just the fence's list\n * indentation keeps the prose readable while routing the snippet through\n * the same top-level renderer as ordinary fences.\n *\n * @param text - Markdown that may hold indented fenced code blocks.\n */\nexport function normalizeMarkdownCodeFences(text: string): string {\n const lines = text.split('\\n')\n const out: string[] = []\n const listIndents: number[] = []\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n let lift = 0\n\n for (const line of lines) {\n if (inFence) {\n const normalized = stripFenceIndent(line, lift)\n out.push(normalized)\n\n if (isFenceClose(normalized, fenceChar, fenceLen)) {\n inFence = false\n fenceChar = ''\n fenceLen = 0\n lift = 0\n }\n continue\n }\n\n updateListIndentStack(listIndents, line)\n\n const open = parseFenceOpen(line)\n if (!open) {\n out.push(line)\n continue\n }\n\n const activeListIndent = [...listIndents].reverse().find(i => i <= open.indent)\n lift = activeListIndent ?? (open.indent <= 3 ? open.indent : 0)\n\n const normalized = stripFenceIndent(line, lift)\n out.push(normalized)\n inFence = true\n fenceChar = open.char\n fenceLen = open.length\n }\n\n return out.join('\\n')\n}\n\n/**\n * Default per-chunk target for {@link chunkMarkdownForRender}. Chosen from\n * measurement: marked's lexer (which OpenTUI's `<markdown>` runs\n * internally) is O(n²) over paragraph-heavy input — ~500ms at 64KiB,\n * ~2s at 128KiB, ~6s at 256KiB on an M-series laptop — while staying\n * comfortably in the linear zone below ~32KiB (≤ ~200ms). Chunking a\n * large document into ≤24KiB pieces keeps the total render linear in\n * document size with a small constant.\n */\nexport const MARKDOWN_RENDER_CHUNK_TARGET_BYTES = 24_576\n\n/**\n * A blank-line split is only safe when the next block clearly STARTS a\n * new top-level construct. Lines that continue a multi-block construct —\n * list items (loose lists put blank lines between items; splitting would\n * restart ordered-list numbering), blockquote lines, table rows, and\n * indented continuations / indented code — are unsafe, so a chunk grows\n * past the target rather than splitting one of these. Worst case (one\n * giant list) degrades to a single chunk, the same as not chunking.\n */\nfunction isUnsafeChunkBoundary(line: string): boolean {\n return LIST_ITEM_RE.test(line)\n || /^ *>/.test(line)\n || /^ *\\|/.test(line)\n || /^ {4,}/.test(line)\n}\n\n/**\n * Split a large markdown document into render-safe chunks at blank-line\n * boundaries outside code fences, each roughly `targetBytes` long.\n *\n * Rendering the chunks as SIBLING markdown renderables (with a one-row\n * gap standing in for the consumed blank line) is visually equivalent to\n * one renderable, but sidesteps the quadratic lexer cost documented on\n * {@link MARKDOWN_RENDER_CHUNK_TARGET_BYTES}. Chunk boundaries are\n * prefix-stable: appending text (streaming) can only ever change the\n * LAST chunk, so keyed-by-index consumers reconcile cheaply.\n *\n * Returns `[text]` untouched for anything at or under the target.\n *\n * @param text - Markdown document.\n * @param targetBytes - Approximate chunk size. Counted in string length.\n */\nexport function chunkMarkdownForRender(text: string, targetBytes: number = MARKDOWN_RENDER_CHUNK_TARGET_BYTES): string[] {\n if (text.length <= targetBytes)\n return [text]\n\n const lines = text.split('\\n')\n const chunks: string[] = []\n let current: string[] = []\n let currentBytes = 0\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n\n const push = (line: string): void => {\n current.push(line)\n currentBytes += line.length + 1\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] as string\n\n if (inFence) {\n push(line)\n if (isFenceClose(line, fenceChar, fenceLen))\n inFence = false\n continue\n }\n\n const open = parseFenceOpen(line)\n if (open) {\n push(line)\n inFence = true\n fenceChar = open.char\n fenceLen = open.length\n continue\n }\n\n // Split point: a blank-line run outside a fence, once the current\n // chunk is big enough and the next content starts a safe new block.\n if (line.trim() === '' && currentBytes >= targetBytes && current.length > 0) {\n let next = i + 1\n while (next < lines.length && (lines[next] as string).trim() === '')\n next++\n if (next < lines.length && !isUnsafeChunkBoundary(lines[next] as string)) {\n chunks.push(current.join('\\n'))\n current = []\n currentBytes = 0\n i = next - 1 // consume the blank run; the renderer restores the gap\n continue\n }\n }\n\n push(line)\n }\n\n if (current.length > 0)\n chunks.push(current.join('\\n'))\n return chunks.length > 0 ? chunks : [text]\n}\n\n/** A fenced code block's opening line: its indent, marker character and marker length. */\nexport interface FenceOpen {\n /** Spaces before the marker. */\n indent: number\n /** The marker character: a backtick or `~`. */\n char: string\n /** How many marker characters open the fence; a closer needs at least as many. */\n length: number\n}\n\n/**\n * The fence `line` opens, or `null`: three or more backticks or tildes, and a\n * backtick fence's info string holds no backtick. Every markdown scanner that\n * must agree on where code blocks are (here, and the desktop app's chunker)\n * reads fences through this and {@link isFenceClose}.\n *\n * @param line - One line of markdown.\n */\nexport function parseFenceOpen(line: string): FenceOpen | null {\n const indent = leadingSpaces(line)\n const char = line[indent]\n if (char !== '`' && char !== '~')\n return null\n\n const length = countRun(line, indent, char)\n if (length < 3)\n return null\n\n const info = line.slice(indent + length)\n if (char === '`' && info.includes('`'))\n return null\n\n return { indent, char, length }\n}\n\n/**\n * `line` closes the fence opened with `fenceChar` × `fenceLen`: the same\n * character, at least as many, and nothing but spaces after (an info string\n * makes it a line of code, as in CommonMark).\n *\n * @param line - One line inside the fence.\n * @param fenceChar - The opener's marker character.\n * @param fenceLen - The opener's marker length.\n */\nexport function isFenceClose(line: string, fenceChar: string, fenceLen: number): boolean {\n const indent = leadingSpaces(line)\n if (line[indent] !== fenceChar)\n return false\n\n const length = countRun(line, indent, fenceChar)\n if (length < fenceLen)\n return false\n\n return onlySpaces(line, indent + length)\n}\n\nfunction updateListIndentStack(listIndents: number[], line: string): void {\n const contentIndent = leadingSpaces(line)\n if (line.trim().length > 0) {\n while (listIndents.length > 0 && contentIndent < listIndents[listIndents.length - 1]!)\n listIndents.pop()\n }\n\n const item = line.match(LIST_ITEM_RE)\n if (!item)\n return\n\n const indent = item[0]!.length\n if (indent > (listIndents[listIndents.length - 1] ?? 0))\n listIndents.push(indent)\n}\n\nfunction leadingSpaces(line: string): number {\n let i = 0\n while (i < line.length && line[i] === ' ')\n i++\n return i\n}\n\nfunction countRun(line: string, start: number, char: string): number {\n let i = start\n while (i < line.length && line[i] === char)\n i++\n return i - start\n}\n\nfunction onlySpaces(line: string, start: number): boolean {\n for (let i = start; i < line.length; i++) {\n if (line[i] !== ' ')\n return false\n }\n return true\n}\n\nfunction stripFenceIndent(line: string, columns: number): string {\n if (columns <= 0)\n return line\n let i = 0\n while (i < columns && line[i] === ' ')\n i++\n return line.slice(i)\n}\n\n/**\n * Terminate a code fence left open at the end of `text`.\n *\n * A model whose run ends mid-fence (cancelled, truncated, out of tokens) leaves\n * an unterminated fence, and the TUI keys the fenced-code chrome off whether the\n * fence closed — an open one stays a bare body so streaming updates can land in\n * place. Closing it at finalization is what lets the `[lang] … [copy]` header\n * appear on a fence the model never closed.\n *\n * Returns `text` unchanged when nothing is open, which is the common case.\n */\nexport function closeDanglingCodeFence(text: string): string {\n const lines = text.split('\\n')\n let fenceChar = ''\n let fenceLen = 0\n\n for (const line of lines) {\n if (fenceChar) {\n if (isFenceClose(line, fenceChar, fenceLen)) {\n fenceChar = ''\n fenceLen = 0\n }\n continue\n }\n\n const open = parseFenceOpen(line)\n if (open) {\n fenceChar = open.char\n fenceLen = open.length\n }\n }\n\n if (!fenceChar)\n return text\n\n return `${text.endsWith('\\n') ? text : `${text}\\n`}${fenceChar.repeat(fenceLen)}`\n}\n\n/**\n * Whether a marked `code` token's raw text carries its closing fence.\n *\n * marked keeps the closing delimiter in `token.raw` only once the fence has\n * terminated, so this separates \"still streaming the body\" from \"done\". Callers\n * use it to decide whether a fenced block is safe to decorate — see the\n * fenced-code chrome in the TUI, which has to stay off an open fence so the\n * renderer can keep updating it in place.\n *\n * Indented (non-fenced) code blocks have no delimiter to wait for and report as\n * closed.\n *\n * Hot path: runs per code token per streamed delta, so it scans in place rather\n * than building a regex or trimming a copy of the whole token.\n */\nexport function codeTokenHasClosingFence(raw: string): boolean {\n const char = raw[0]\n if (char !== '`' && char !== '~')\n return true\n\n let openLen = 0\n while (raw[openLen] === char)\n openLen++\n\n // marked leaves a trailing newline on a fence that ends the input, so walk\n // back over trailing whitespace before locating the closing line.\n let end = raw.length\n while (end > 0 && isSpaceOrBreak(raw[end - 1] as string))\n end--\n\n let start = end\n while (start > 0 && raw[start - 1] !== '\\n')\n start--\n\n // The opening delimiter is not a closing one.\n if (start === 0)\n return false\n\n // CommonMark allows the closing fence up to three spaces of indent.\n while (start < end && (raw[start] === ' ' || raw[start] === '\\t'))\n start++\n\n if (end - start < openLen)\n return false\n\n for (let i = start; i < end; i++) {\n if (raw[i] !== char)\n return false\n }\n return true\n}\n\nfunction isSpaceOrBreak(ch: string): boolean {\n return ch === '\\n' || ch === '\\r' || ch === ' ' || ch === '\\t'\n}\n","/**\n * Per-server MCP OAuth status tracking, decoupled from the renderer.\n *\n * The TUI keeps a `Record<serverName, McpAuthStatus>` so it can render a\n * \"needs-auth\" / \"authorizing\" / \"error\" badge in the MCP picker. The\n * status map is driven entirely by hooks fired from the agent's MCP\n * bootstrap + the interactive `loginMcpServer` flow — the reducer below\n * is pure, makes no FS or network calls, and is shared between the live\n * TUI store and the test harness.\n *\n * Status lifecycle:\n *\n * needs-auth | authorizing | authed ──mcp:connect──▶ authed\n * (bootstrap succeeded with stored tokens; a server\n * that was never OAuth-tracked stays idle)\n * needs-auth (reason 'refused') ──mcp:connect──▶ idle\n * bootstrap-error | key-refused ──mcp:connect──▶ idle\n *\n * idle ──mcp:auth:required──▶ needs-auth\n * (bootstrap saw no/invalid tokens)\n *\n * idle ──401/403, no key of its own──▶ needs-auth (reason 'refused')\n * idle ──401/403 on its own header key──▶ key-refused\n * (see `classifyMcpTest`)\n *\n * needs-auth ──login()──▶ authorizing ──mcp:auth:url──▶ authorizing(url)\n * ──mcp:auth:success──▶ authed\n * ──mcp:auth:error──▶ error\n *\n * any ──logout──▶ idle\n *\n * Multiple servers progress through the lifecycle independently; the map\n * is keyed by `McpServerConfig.name`.\n */\n\nexport type McpAuthStatus\n // Default — never heard anything about this server. Includes both pure\n // stdio servers (no auth concept) and HTTP servers we haven't bootstrapped yet.\n = | { kind: 'idle' }\n // OAuth-required, no usable tokens. Reason maps to the bootstrap signal:\n // - 'no-tokens' — explicit `auth: 'oauth'` config + empty store.\n // - 'auto-promoted' — server returned 401 + RFC 9728 metadata, eligible\n // for OAuth because the user did not set a static Authorization header.\n // - 'refused' — the server answered 401/403 without that metadata (an\n // expired or never finished sign-in, a config without `auth: 'oauth'`).\n | { kind: 'needs-auth', reason: McpNeedsAuthReason }\n // Login flow in flight. `url` is populated as soon as the SDK builds the\n // authorization URL — the modal renders it so the user can re-open the\n // browser tab manually if the automatic open failed (no GUI, restricted\n // sandbox).\n | { kind: 'authorizing', url?: string }\n // Tokens are stored and (most recently) usable. Surface as a check mark.\n | { kind: 'authed' }\n // Last login attempt failed. `error` is the user-facing message — the\n // TUI shows it verbatim so a network blip or revoked token is debuggable\n // without `ZIDANE_DEBUG`.\n | { kind: 'error', error: string }\n // Bootstrap failed for a NON-auth reason — stdio command missing/crashed,\n // http endpoint unreachable. Kept distinct from `error` (login failed) so\n // the picker doesn't offer login/logout on servers where auth is not the\n // problem. Cleared back to idle by a later successful `mcp:connect`.\n | { kind: 'bootstrap-error', error: string }\n // The server refused the key its config sends in headers (401/403 on a\n // server with `headers`). Fixed in mcps.json, not by signing in, so no\n // login is offered. Cleared by a later successful `mcp:connect`.\n | { kind: 'key-refused', error: string }\n\n/** Why a server needs sign-in: no stored tokens, a server answer that promoted it to OAuth, or a refused request. */\nexport type McpNeedsAuthReason = 'no-tokens' | 'auto-promoted' | 'refused'\n\n/**\n * The status words both apps show for a server, so the desktop app's badge\n * and the TUI's read the same. `idle` says nothing.\n */\nexport const MCP_STATUS_LABEL: Readonly<Record<Exclude<McpAuthStatus['kind'], 'idle'>, string>> = {\n 'authed': 'Signed in',\n 'needs-auth': 'Needs sign-in',\n 'authorizing': 'Signing in…',\n 'error': 'Sign-in failed',\n 'bootstrap-error': 'Couldn\\'t connect',\n 'key-refused': 'Key refused',\n}\n\n/**\n * Map of server name → status. `idle` is the implicit default for any\n * server NOT present in the map, so the renderer treats `undefined` as\n * `{ kind: 'idle' }` and the map can stay sparse.\n */\nexport type McpAuthStateMap = Readonly<Record<string, McpAuthStatus>>\n\n/**\n * Events the reducer accepts. Most names mirror the agent hooks\n * (`mcp:connect`, `mcp:auth:*`). `login:start` / `login:cancel` / `logout` /\n * `reset` are UI-only verbs: `login:start` lets the renderer\n * optimistically flip a row to `authorizing` before the SDK has emitted\n * `mcp:auth:url` — useful when the loopback callback is slow to bind.\n */\nexport type McpAuthEvent\n = | { type: 'auth-required', name: string, reason: McpNeedsAuthReason }\n | { type: 'auth-url', name: string, url: string }\n | { type: 'auth-success', name: string }\n | { type: 'auth-error', name: string, error: string }\n | { type: 'bootstrap-error', name: string, error: string }\n | { type: 'key-refused', name: string, error: string }\n | { type: 'connected', name: string }\n | { type: 'login:start', name: string }\n | { type: 'login:cancel', name: string }\n | { type: 'logout', name: string }\n | { type: 'reset', name: string }\n\n/**\n * Apply one event to the state map. Pure, immutable — returns a new map\n * with only the affected key reassigned.\n *\n * State transitions are simple \"last write wins\"; we don't gate (e.g.) a\n * `login:start` from overriding `authorizing` because the loop layer\n * never doubles those up — interactive login is serialized in the TUI.\n *\n * @param state - The current state map.\n * @param event - The event to apply.\n */\nexport function reduceMcpAuth(state: McpAuthStateMap, event: McpAuthEvent): McpAuthStateMap {\n const next = (status: McpAuthStatus): McpAuthStateMap => ({ ...state, [event.name]: status })\n switch (event.type) {\n case 'auth-required':\n return next({ kind: 'needs-auth', reason: event.reason })\n case 'auth-url':\n return next({ kind: 'authorizing', url: event.url })\n case 'auth-success':\n return next({ kind: 'authed' })\n case 'auth-error':\n return next({ kind: 'error', error: event.error })\n case 'bootstrap-error':\n return next({ kind: 'bootstrap-error', error: event.error })\n case 'key-refused':\n return next({ kind: 'key-refused', error: event.error })\n case 'connected':\n // Only flip to `authed` when this server was OAuth-tracked. A plain\n // stdio bootstrap shouldn't paint every server with a green badge —\n // `idle` means \"nothing to say about auth here\". This matters for\n // the MCP picker's badge column staying signal-dense.\n // A refusal that cleared up without a sign-in (the server let us in\n // after all) has nothing to say about auth: back to idle.\n if (state[event.name]?.kind === 'needs-auth' && (state[event.name] as { reason?: string }).reason === 'refused') {\n const { [event.name]: _, ...rest } = state\n return rest\n }\n if (state[event.name]?.kind === 'authorizing'\n || state[event.name]?.kind === 'needs-auth'\n || state[event.name]?.kind === 'authed') {\n return next({ kind: 'authed' })\n }\n // A successful bootstrap clears a previous bootstrap failure — the\n // server was fixed (file restored, endpoint back up). Back to the\n // sparse-map default rather than a green badge: `idle` means\n // \"nothing to say about auth here\", which is true for stdio.\n if (state[event.name]?.kind === 'bootstrap-error' || state[event.name]?.kind === 'key-refused') {\n const { [event.name]: _, ...rest } = state\n return rest\n }\n return state\n case 'login:start':\n return next({ kind: 'authorizing' })\n case 'login:cancel':\n // Cancellation is treated as \"back to needs-auth\" — the user dismissed\n // the browser flow but the underlying requirement still stands.\n return next({ kind: 'needs-auth', reason: 'no-tokens' })\n case 'logout':\n case 'reset': {\n const { [event.name]: _, ...rest } = state\n return rest\n }\n }\n}\n\n/**\n * The status a failed connection leaves, from `classifyMcpTest`'s answer\n * (never called with `ok`: a connection that worked leaves no failure).\n * A server that asked for OAuth keeps \"sign-in failed\" for an unexplained\n * failure (its tokens are the likely cause, and sign-in stays offered).\n *\n * @param name - Server name.\n * @param outcome - The classified test result. Pass any kind except `ok`.\n * @param oauthTagged - Whether the server's config asks for OAuth.\n */\nexport function mcpFailureEvent(\n name: string,\n outcome: { kind: 'ok' | 'needs-auth' | 'token-rejected' | 'error', message?: string },\n oauthTagged: boolean,\n): McpAuthEvent {\n if (outcome.kind === 'needs-auth')\n return { type: 'auth-required', name, reason: 'refused' }\n if (outcome.kind === 'token-rejected')\n return { type: 'key-refused', name, error: outcome.message ?? '' }\n return oauthTagged\n ? { type: 'auth-error', name, error: outcome.message ?? '' }\n : { type: 'bootstrap-error', name, error: outcome.message ?? '' }\n}\n\n/**\n * Convenience getter — treats `undefined` as `idle`.\n *\n * @param state - The auth state map.\n * @param name - Server name to look up.\n */\nexport function getMcpAuthStatus(state: McpAuthStateMap, name: string): McpAuthStatus {\n return state[name] ?? { kind: 'idle' }\n}\n","/**\n * How an MCP server answered a connection attempt, in the words both apps\n * show. Shared by the desktop app's Test (Settings › Agent › MCP servers) and the TUI's\n * bootstrap / test, so the same server reads the same way in either.\n *\n * ok connected and listed its tools;\n * needs-auth 401/403 with no key of its own: a browser sign-in fixes it\n * (an expired or never finished sign-in included);\n * token-rejected 401/403 on a server that sends its own headers: the key\n * in mcps.json is wrong, a browser sign-in won't help;\n * error anything else (refused, timed out, bad command).\n *\n * Pure: no I/O.\n */\nimport type { McpServerConfig } from '../types'\n\n/** Classification of an MCP connection attempt. */\nexport type McpTestOutcomeKind = 'ok' | 'needs-auth' | 'token-rejected' | 'error'\n\n/** Classified result of one MCP connection test. */\nexport interface McpTestResult {\n /** How the server answered. */\n kind: McpTestOutcomeKind\n /** Number of tools listed. Set for `ok`. */\n tools?: number\n /** User-facing explanation for non-`ok` kinds. */\n message?: string\n}\n\n/** What to do about a refused key, under the \"Key refused\" headline. */\nexport const MCP_KEY_REFUSED_HINT = 'Check the headers in mcps.json.'\n\n/**\n * A refusal for want of credentials: HTTP 401 / 403, however the SDK words it.\n *\n * @param error - The error thrown by a connection attempt.\n */\nexport function isMcpAuthRefusal(error: unknown): boolean {\n const code = (error as { code?: unknown } | null)?.code\n if (code === 401 || code === 403)\n return true\n const message = error instanceof Error ? error.message : String(error ?? '')\n return /\\b(?:401|403)\\b|unauthori[sz]ed|forbidden|invalid_token/i.test(message)\n}\n\n/**\n * The first line of a failure, never empty.\n *\n * @param error - The error thrown by a connection attempt.\n */\nexport function mcpFailureLine(error: unknown): string {\n const code = (error as { code?: unknown } | null)?.code\n const message = error instanceof Error && error.message\n ? error.message\n : code !== undefined\n ? `The server answered ${String(code)}.`\n : typeof error === 'string'\n ? error\n : ''\n return message.split('\\n')[0]?.trim() || 'Couldn\\'t connect.'\n}\n\n/**\n * Classifies a connection attempt. HTTP servers that required auth or answered\n * 401/403 become `token-rejected` when the config sends its own headers, else\n * `needs-auth`. Any other error becomes `error`. A clean connection is `ok`.\n *\n * @param config - The server's transport and headers.\n * @param result - Whether auth was required, the error if any, and the tool count.\n */\nexport function classifyMcpTest(\n config: Pick<McpServerConfig, 'transport' | 'headers'>,\n result: { authRequired: boolean, error?: unknown, tools?: number },\n): McpTestResult {\n const http = config.transport !== 'stdio'\n const ownKey = Object.keys(config.headers ?? {}).length > 0\n if (http && (result.authRequired || (result.error !== undefined && isMcpAuthRefusal(result.error)))) {\n return ownKey\n ? { kind: 'token-rejected', message: MCP_KEY_REFUSED_HINT }\n : { kind: 'needs-auth', message: 'Sign in to connect.' }\n }\n if (result.error !== undefined)\n return { kind: 'error', message: mcpFailureLine(result.error) }\n return { kind: 'ok', tools: result.tools ?? 0 }\n}\n","/**\n * Cross-provider model catalog — assembly + fuzzy filtering.\n *\n * Renderer-agnostic helpers consumed by `ModelPickerModal` (TUI) and any\n * future UI that wants a unified \"pick a model across all available\n * providers\" experience. Pure: no React, no I/O, no provider construction.\n *\n * The catalog is the flat union of every available provider's models,\n * each entry tagged with the provider it belongs to so the picker can\n * re-issue a `Picked` tuple `{ providerKey, modelId }` on commit.\n */\n\nimport type { ProviderAccount, ProviderAuth, ProviderKey } from './auth'\nimport type { ModelInfo } from './providers'\n\n/** A model entry as displayed in the cross-provider picker. */\nexport interface CatalogEntry {\n /** Key of the provider that serves the model. */\n providerKey: ProviderKey\n /** Display name of the provider. */\n providerLabel: string\n /**\n * The stored account of the provider this row runs on, when the provider\n * has several (`ProviderAuth.accounts`): one row per account, so the same\n * model on \"Work\" and \"Personal\" are two picks. Absent: the provider's\n * only account.\n */\n account?: Pick<ProviderAccount, 'id' | 'label' | 'active'>\n /** Metadata of the model. An off-catalog entry carries only `id` and a `contextWindow` of `0`. */\n model: ModelInfo\n /**\n * The provider does not (or no longer) list this model: the entry was\n * synthesized from an `include` pair, so `model` is a stub carrying the id\n * and nothing else. Renderers should say so rather than print stub\n * metadata as if it were real.\n */\n offCatalog?: boolean\n /**\n * Pre-computed lowercase corpus for substring search across the\n * provider key, label, account label, model id, and display name. Built once at\n * catalog-assembly time so filtering on every keystroke is\n * O(catalogSize × queryLength), not O(catalogSize × fieldCount ×\n * lowercase-overhead × queryLength).\n */\n searchCorpus: string\n}\n\n/**\n * Build the unified catalog from a list of available providers.\n *\n * Provider order is preserved (callers typically pass the picker order\n * — alphabetical, auth-detection order, etc.); model order inside each\n * provider matches whatever `modelsFor` returns. The current selection\n * (when set) is bubbled to the top of its provider's section so it\n * shows first without disturbing relative ordering elsewhere.\n *\n * `modelsFor` is injected (not imported from `./providers`) so the same\n * helper works with hosts that supply their own model resolver via\n * `ResolvedConfig.modelsFor`.\n *\n * `include` guarantees a pair is listed even when the provider stopped\n * serving it. Persisted picks outlive catalogs (a provider retires an id, a\n * user typed one by hand), and an entry that isn't in the list can't be\n * selected away from, and the picker would keep re-persisting it. Synthesized\n * entries carry `offCatalog: true` and a stub `ModelInfo`.\n *\n * @param opts - Providers to list, a models lookup per provider key, the current pick to float to the top of its section, and extra picks to show even when the provider does not list them.\n */\nexport function buildModelCatalog(opts: {\n providers: readonly ProviderAuth[]\n modelsFor: (key: ProviderKey) => readonly ModelInfo[]\n /** Optional currently-selected pair — promoted to the top of its provider group. */\n current?: { providerKey: ProviderKey, modelId: string } | null\n /** Pairs that must appear even if unserved, e.g. the active pick + fallback chain. */\n include?: readonly { providerKey: ProviderKey, modelId: string }[]\n}): CatalogEntry[] {\n const entries: CatalogEntry[] = []\n for (const provider of opts.providers) {\n // A provider with several accounts lists its models once per account, active first.\n const accounts: readonly (ProviderAccount | undefined)[] = provider.accounts && provider.accounts.length > 1 ? provider.accounts : [undefined]\n for (const account of accounts)\n entries.push(...providerSection(provider, account, opts))\n }\n return entries\n}\n\nfunction providerSection(\n provider: ProviderAuth,\n account: ProviderAccount | undefined,\n opts: Parameters<typeof buildModelCatalog>[0],\n): CatalogEntry[] {\n const entries: CatalogEntry[] = []\n const tag = account ? { account: { id: account.id, label: account.label, active: account.active } } : {}\n {\n const models = opts.modelsFor(provider.key)\n const missing = missingIdsFor(provider.key, models, opts.include)\n if (models.length === 0 && missing.length === 0)\n return entries\n // Promote the currently-selected model to position 0 inside its\n // own provider section so the picker doesn't bury the user's\n // active row at the bottom of a long provider list.\n let ordered: readonly ModelInfo[] = models\n if (opts.current?.providerKey === provider.key) {\n const idx = models.findIndex(m => m.id === opts.current?.modelId)\n if (idx > 0) {\n const next = models.slice()\n const [active] = next.splice(idx, 1)\n next.unshift(active)\n ordered = next\n }\n }\n // Unserved pairs lead their provider's section: they are either the\n // active pick or a chain entry, so burying them under a long served list\n // would defeat the point of listing them at all.\n for (const modelId of missing) {\n const model: ModelInfo = { id: modelId, contextWindow: 0 }\n entries.push({\n providerKey: provider.key,\n providerLabel: provider.label,\n ...tag,\n model,\n offCatalog: true,\n searchCorpus: buildSearchCorpus(provider, model, account),\n })\n }\n for (const model of ordered) {\n entries.push({\n providerKey: provider.key,\n providerLabel: provider.label,\n ...tag,\n model,\n searchCorpus: buildSearchCorpus(provider, model, account),\n })\n }\n }\n return entries\n}\n\n/** Ids `include` asks for on this provider that its own list doesn't serve. */\nfunction missingIdsFor(\n providerKey: ProviderKey,\n models: readonly ModelInfo[],\n include: readonly { providerKey: ProviderKey, modelId: string }[] | undefined,\n): string[] {\n if (!include || include.length === 0)\n return []\n const served = new Set(models.map(m => m.id))\n const out: string[] = []\n for (const pair of include) {\n if (pair.providerKey !== providerKey || !pair.modelId || served.has(pair.modelId) || out.includes(pair.modelId))\n continue\n out.push(pair.modelId)\n }\n return out\n}\n\n/**\n * Filter `catalog` by a user query. Empty / whitespace-only queries\n * pass every entry through (a copy of `catalog`). Multi-term\n * queries (space-separated) require EVERY term to appear somewhere in\n * the entry's search corpus — so `\"claude opus\"` matches `claude-opus-4`\n * regardless of how the words are interleaved with provider names.\n *\n * Match is case-insensitive (the corpus is pre-lowercased; the query\n * is lowercased once per call).\n *\n * Generic over the entry shape so the GUI renderer filters its flat IPC\n * wire rows (which carry the same main-built `searchCorpus`) with this\n * one implementation.\n *\n * @param catalog - Entries to filter.\n * @param query - Space-separated terms. An entry matches when every term appears in its search corpus.\n */\nexport function filterModelCatalog<E extends { searchCorpus: string }>(\n catalog: readonly E[],\n query: string,\n): E[] {\n const trimmed = query.trim().toLowerCase()\n if (!trimmed)\n return catalog.slice()\n const terms = trimmed.split(/\\s+/)\n return catalog.filter(entry => terms.every(t => entry.searchCorpus.includes(t)))\n}\n\n/**\n * Find a catalog entry's index by its `{providerKey, modelId}` tuple.\n * Returns `-1` when not present. Useful when re-rendering the picker\n * (a query just narrowed the list, where did the selection land?).\n *\n * @param catalog - Entries to search.\n * @param target - Provider and model to find.\n */\nexport function indexOfEntry(\n catalog: readonly CatalogEntry[],\n target: { providerKey: ProviderKey, modelId: string } | null | undefined,\n): number {\n if (!target)\n return -1\n return catalog.findIndex(\n e => e.providerKey === target.providerKey && e.model.id === target.modelId,\n )\n}\n\n/**\n * Read a query that matched nothing as \"use this model id anyway\".\n *\n * A bare id is meaningless without a provider, so the first term is checked\n * against every provider's key and label (case-insensitive): `xai grok-9` and\n * `Anthropic claude-next` name their provider explicitly, anything else is\n * attributed to `fallbackProviderKey` (the picker's current pick). Returns\n * `null` when nothing usable is left, including when the whole query is just a\n * provider name.\n *\n * @param query - Free text, optionally starting with a provider key or label.\n * @param providers - Known providers to match a prefix against.\n * @param fallbackProviderKey - Provider used when the query names none.\n */\nexport function parseCustomModelQuery(\n query: string,\n // Only `key` + `label` are read. Narrowed so the GUI, which holds providers\n // as a flattened wire shape rather than `ProviderAuth`, can share the parser.\n providers: readonly Pick<ProviderAuth, 'key' | 'label'>[],\n fallbackProviderKey: ProviderKey | null,\n): CustomModelTarget | null {\n const { modelId, named } = splitProviderPrefix(query, providers)\n const provider = named ?? providers.find(p => p.key === fallbackProviderKey)\n if (!provider || !modelId)\n return null\n return { providerKey: provider.key, providerLabel: provider.label, modelId }\n}\n\n/** A provider and model id a free-text query resolves to. */\nexport interface CustomModelTarget {\n /** Provider the model id would run on. */\n providerKey: ProviderKey\n /** Display name of the provider. */\n providerLabel: string\n /** Model id taken from the query, without any provider prefix. */\n modelId: string\n /** The query named this provider (`xai grok-9`). */\n named?: boolean\n}\n\n/**\n * Every route for a typed model id, one per provider: the provider the query\n * names first (`xai grok-9`), then `fallbackProviderKey` (the current pick),\n * then the rest in the given order. Lets a picker offer \"use this id via…\"\n * for each signed-in provider instead of guessing one. Empty when the query\n * names no model id.\n *\n * @param query - Free text, optionally starting with a provider key or label.\n * @param providers - Providers to offer, ranked with the named one first and the fallback second.\n * @param fallbackProviderKey - Provider to rank second when the query names none.\n */\nexport function customModelTargets(\n query: string,\n providers: readonly Pick<ProviderAuth, 'key' | 'label'>[],\n fallbackProviderKey: ProviderKey | null,\n): CustomModelTarget[] {\n const { modelId, named } = splitProviderPrefix(query, providers)\n if (!modelId)\n return []\n const rank = (p: Pick<ProviderAuth, 'key'>): number =>\n p.key === named?.key ? 0 : p.key === fallbackProviderKey ? 1 : 2\n return providers\n .map((p, i) => ({ p, i }))\n .sort((a, b) => rank(a.p) - rank(b.p) || a.i - b.i)\n .map(({ p }) => ({\n providerKey: p.key,\n providerLabel: p.label,\n modelId,\n ...(p.key === named?.key ? { named: true } : {}),\n }))\n}\n\n/**\n * Split an optional leading provider name off a typed query. Longest prefix\n * wins, so a multi-word label (\"OpenAI Codex gpt-9\") beats the bare key it\n * starts with. The trailing space is required: a query that is only a\n * provider name has no id in it and reads as an id itself. Only the prefix\n * is dropped; the rest is kept verbatim, so an id with spaces round-trips.\n */\nfunction splitProviderPrefix<P extends Pick<ProviderAuth, 'key' | 'label'>>(\n query: string,\n providers: readonly P[],\n): { modelId: string, named: P | undefined } {\n const trimmed = query.trim().replace(/\\s+/g, ' ')\n if (!trimmed)\n return { modelId: '', named: undefined }\n const lower = trimmed.toLowerCase()\n const match = providers\n .flatMap(p => [{ provider: p, token: p.label.toLowerCase() }, { provider: p, token: p.key.toLowerCase() }])\n .filter(candidate => lower.startsWith(`${candidate.token} `))\n .sort((a, b) => b.token.length - a.token.length)[0]\n return {\n modelId: match ? trimmed.slice(match.token.length).trim() : trimmed,\n named: match?.provider,\n }\n}\n\nfunction buildSearchCorpus(provider: ProviderAuth, model: ModelInfo, account?: ProviderAccount): string {\n const parts = [\n provider.key,\n provider.label,\n account?.label ?? '',\n model.id,\n model.name ?? '',\n model.provider ?? '',\n ]\n return parts.join(' ').toLowerCase()\n}\n","/**\n * Connectors: services that the agent reaches through an MCP server, added in\n * one step. Each entry becomes a server in the user's `mcps.json` (never a\n * project file), named by its id. Browser sign-in goes through the MCP OAuth\n * of zidane. The server must accept new clients, which is called dynamic client\n * registration. Before a release, `scripts/check-connectors.ts` checks every\n * OAuth endpoint and every docs link.\n */\nimport type { McpServerConfig } from '../../types'\nimport type { ConnectorCategory, ConnectorEntry, ConnectorInput } from './types'\n\nconst BEARER = 'Bearer '\n\n/** Every connector, in display order within each category. */\nexport const CONNECTORS: readonly ConnectorEntry[] = [\n {\n id: 'github',\n label: 'GitHub',\n description: 'Repositories, issues, pull requests and Actions.',\n category: 'code',\n transport: { kind: 'http', url: 'https://api.githubcopilot.com/mcp/' },\n auth: { kind: 'token', header: 'Authorization', prefix: BEARER, createUrl: 'https://github.com/settings/personal-access-tokens/new', placeholder: 'github_pat_…', reuse: 'github' },\n docsUrl: 'https://github.com/github/github-mcp-server',\n brand: 'github',\n },\n {\n id: 'linear',\n label: 'Linear',\n description: 'Issues, projects and cycles.',\n category: 'work',\n transport: { kind: 'http', url: 'https://mcp.linear.app/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://linear.app/docs/mcp',\n brand: 'linear',\n },\n {\n id: 'notion',\n label: 'Notion',\n description: 'Pages, databases and comments.',\n category: 'work',\n transport: { kind: 'http', url: 'https://mcp.notion.com/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://developers.notion.com/docs/mcp',\n brand: 'notion',\n },\n {\n id: 'atlassian',\n label: 'Atlassian',\n description: 'Jira work items and Confluence pages.',\n category: 'work',\n transport: { kind: 'http', url: 'https://mcp.atlassian.com/v2/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://support.atlassian.com/atlassian-rovo-mcp-server/docs/getting-started-with-the-atlassian-remote-mcp-server/',\n brand: 'atlassian',\n },\n {\n id: 'cloudflare',\n label: 'Cloudflare',\n description: 'Workers, DNS, storage and the rest of the Cloudflare API.',\n category: 'cloud',\n transport: { kind: 'http', url: 'https://mcp.cloudflare.com/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/',\n brand: 'cloudflare',\n },\n {\n id: 'supabase',\n label: 'Supabase',\n description: 'Projects, Postgres queries, migrations and edge functions.',\n category: 'cloud',\n transport: { kind: 'http', url: 'https://mcp.supabase.com/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://supabase.com/docs/guides/ai-tools/mcp',\n brand: 'supabase',\n },\n {\n id: 'neon',\n label: 'Neon',\n description: 'Serverless Postgres projects, branches and queries.',\n category: 'cloud',\n transport: { kind: 'http', url: 'https://mcp.neon.tech/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://neon.com/docs/ai/neon-mcp-server',\n brand: 'neon',\n },\n {\n id: 'stripe',\n label: 'Stripe',\n description: 'Customers, payments, invoices and the Stripe docs.',\n category: 'cloud',\n transport: { kind: 'http', url: 'https://mcp.stripe.com' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://docs.stripe.com/mcp',\n brand: 'stripe',\n },\n {\n id: 'sentry',\n label: 'Sentry',\n description: 'Errors, issues and performance data, with Seer analysis.',\n category: 'observability',\n transport: { kind: 'http', url: 'https://mcp.sentry.dev/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://docs.sentry.io/product/sentry-mcp/',\n brand: 'sentry',\n },\n {\n id: 'braintrust',\n label: 'Braintrust',\n description: 'Experiments, logs, datasets and evaluations.',\n category: 'observability',\n transport: { kind: 'http', url: 'https://api.braintrust.dev/mcp' },\n auth: { kind: 'oauth' },\n docsUrl: 'https://www.braintrust.dev/docs/reference/mcp',\n brand: 'braintrust',\n },\n {\n id: 'context7',\n label: 'Context7',\n description: 'Up-to-date documentation for libraries and frameworks.',\n category: 'docs',\n transport: { kind: 'http', url: 'https://mcp.context7.com/mcp' },\n auth: { kind: 'token', header: 'CONTEXT7_API_KEY', optional: true, createUrl: 'https://context7.com/dashboard', placeholder: 'ctx7sk-…' },\n docsUrl: 'https://github.com/upstash/context7',\n },\n {\n id: 'deepwiki',\n label: 'DeepWiki',\n description: 'Ask questions about any public GitHub repository.',\n category: 'docs',\n transport: { kind: 'http', url: 'https://mcp.deepwiki.com/mcp' },\n auth: { kind: 'none' },\n docsUrl: 'https://mcp.deepwiki.com/',\n },\n {\n id: 'huggingface',\n label: 'Hugging Face',\n description: 'Models, datasets, Spaces and papers.',\n category: 'docs',\n transport: { kind: 'http', url: 'https://huggingface.co/mcp' },\n auth: { kind: 'token', header: 'Authorization', prefix: BEARER, optional: true, createUrl: 'https://huggingface.co/settings/tokens', placeholder: 'hf_…' },\n docsUrl: 'https://huggingface.co/docs/hub/agents-mcp',\n brand: 'huggingface',\n },\n {\n id: 'playwright',\n label: 'Playwright',\n description: 'A browser that the agent controls. It opens pages, clicks, types and reads. Needs Node.js.',\n category: 'browser',\n transport: { kind: 'stdio', command: 'npx', args: ['@playwright/mcp@latest'] },\n auth: { kind: 'none' },\n docsUrl: 'https://github.com/microsoft/playwright-mcp',\n },\n]\n\n/** A section of the Connectors step. */\nexport interface ConnectorCategoryMeta {\n /** The section. */\n id: ConnectorCategory\n /** Its heading. */\n label: string\n}\n\n/** The step's sections, in display order. */\nexport const CONNECTOR_CATEGORIES: readonly ConnectorCategoryMeta[] = [\n { id: 'code', label: 'Code' },\n { id: 'work', label: 'Work' },\n { id: 'cloud', label: 'Cloud and data' },\n { id: 'observability', label: 'Observability' },\n { id: 'docs', label: 'Docs and research' },\n { id: 'browser', label: 'Browser' },\n]\n\n/**\n * A connector by id, or `undefined`.\n *\n * @param id - The connector id.\n */\nexport function connectorById(id: string): ConnectorEntry | undefined {\n return CONNECTORS.find(entry => entry.id === id)\n}\n\n/**\n * Why zidane cannot add a connector with this input, or `undefined` when it\n * can. The one reason is a missing token that the connector needs.\n *\n * @param entry - The connector.\n * @param input - What the user typed.\n */\nexport function connectorInputError(entry: ConnectorEntry, input: ConnectorInput = {}): string | undefined {\n if (entry.auth.kind === 'token' && !entry.auth.optional && !input.token?.trim())\n return `Paste a ${entry.label} token first.`\n return undefined\n}\n\n/**\n * The MCP server a connector writes to `mcps.json`.\n *\n * @param entry - The connector.\n * @param input - What the user typed: the token, for token sign-in.\n * @throws When a required token is missing ({@link connectorInputError}).\n * @example\n * ```ts\n * import { connectorById, connectorServerConfig } from 'zidane/chat/pure'\n *\n * connectorServerConfig(connectorById('linear')!)\n * // { name: 'linear', transport: 'streamable-http', url: 'https://mcp.linear.app/mcp' }\n * ```\n */\nexport function connectorServerConfig(entry: ConnectorEntry, input: ConnectorInput = {}): McpServerConfig {\n const error = connectorInputError(entry, input)\n if (error)\n throw new Error(error)\n if (entry.transport.kind === 'stdio')\n return { name: entry.id, transport: 'stdio', command: entry.transport.command, args: [...entry.transport.args] }\n const token = input.token?.trim()\n const headers = entry.auth.kind === 'token' && token\n ? { [entry.auth.header]: `${entry.auth.prefix ?? ''}${token}` }\n : undefined\n return { name: entry.id, transport: 'streamable-http', url: entry.transport.url, ...(headers ? { headers } : {}) }\n}\n\n/** The fields of an installed MCP server a connector is matched on. */\nexport interface InstalledServerRef {\n /** Server name. */\n name: string\n /** Endpoint, for an HTTP server. */\n url?: string\n /** Command, for a stdio server. */\n command?: string\n /** Command arguments, for a stdio server. */\n args?: readonly string[]\n}\n\nconst sameUrl = (a: string, b: string): boolean => a.replace(/\\/+$/, '').toLowerCase() === b.replace(/\\/+$/, '').toLowerCase()\n\n/**\n * Whether a connector is already installed: a server with its name, its\n * endpoint, or its command and arguments.\n *\n * @param entry - The connector.\n * @param servers - The servers already configured.\n */\nexport function connectorInstalled(entry: ConnectorEntry, servers: readonly InstalledServerRef[]): boolean {\n const transport = entry.transport\n return servers.some((server) => {\n if (server.name === entry.id)\n return true\n if (transport.kind === 'http')\n return server.url !== undefined && sameUrl(server.url, transport.url)\n return server.command === transport.command && (server.args ?? []).join(' ') === transport.args.join(' ')\n })\n}\n","/**\n * The toggles that the Features step offers, picked from the settings\n * catalog. Labels and descriptions are the ones that Settings shows\n * (`SETTINGS_TOGGLES`), so the step and Settings say the same thing. Each\n * feature also has an example, one sentence that shows it at work, and what\n * it unlocks and prevents. A feature's parts turn on with it (`includes`),\n * such as the agent's use of the browser tab, so the step has one switch per\n * feature.\n */\nimport type { BooleanSettingKey } from '../settings-catalog'\nimport type { OnboardingFeature, OnboardingFeatureGroup, OnboardingMode, OnboardingSurface } from './types'\nimport { SETTINGS_TOGGLES } from '../settings-catalog'\n\nconst BOTH: readonly OnboardingSurface[] = ['tui', 'desktop']\nconst DESKTOP: readonly OnboardingSurface[] = ['desktop']\n\n/** Every feature the step can offer, in display order. */\nexport const ONBOARDING_FEATURES: readonly OnboardingFeature[] = [\n {\n key: 'codemode',\n group: 'work',\n surfaces: BOTH,\n badges: ['experimental'],\n example: 'For example, to read 12 files, the model writes one script that reads all of them, instead of 12 tool calls.',\n unlocks: 'Many tool calls in one step. Long tasks take fewer turns, so runs finish faster and cost less.',\n prevents: 'A context full of small tool results. Only what the script prints goes back to the model.',\n },\n {\n key: 'inlineAutocomplete',\n group: 'work',\n surfaces: BOTH,\n example: 'For example, you type `src/comp`, and `onents/` shows in gray after it.',\n unlocks: 'Press Tab to finish a path, a command or a prompt that you type often.',\n prevents: 'Typing the same long paths and prompts again and again.',\n },\n {\n key: 'autoTitle',\n group: 'work',\n surfaces: BOTH,\n badges: ['billed'],\n example: 'For example, after your first message about a failed login, the session gets the title \"Fix the login redirect\".',\n unlocks: 'Session titles that follow what each session is about, so you find it again.',\n prevents: 'A session list where every title reads the same.',\n },\n {\n key: 'spaces',\n group: 'work',\n surfaces: BOTH,\n example: 'For example, a Work space starts sessions on Opus, and a Personal space starts them on a local model.',\n unlocks: 'Separate session lists, each with its own default model, such as Work and Personal.',\n prevents: 'Work and personal sessions mixed in one long list.',\n },\n {\n key: 'checkForUpdates',\n group: 'background',\n surfaces: BOTH,\n example: 'For example, when a new version comes out, the footer tells you that an update is ready.',\n unlocks: 'A note in the footer when a new version is out.',\n prevents: 'Running an old version without knowing it.',\n },\n {\n key: 'subscriptionUsage',\n group: 'background',\n surfaces: BOTH,\n example: 'For example, zidane shows how much of your weekly Claude limit you used.',\n unlocks: 'Your plan usage in the footer, such as the share of your weekly limit.',\n prevents: 'A surprise stop when you reach your plan limit.',\n },\n {\n key: 'useDaemon',\n group: 'background',\n surfaces: DESKTOP,\n example: 'For example, you close the window during a long run. The run keeps going, and the next window shows it.',\n unlocks: 'Runs that keep going after you close the window, and one session open in several windows.',\n prevents: 'Losing a long run when its window closes.',\n },\n {\n key: 'browser',\n group: 'desktop',\n surfaces: DESKTOP,\n includes: ['browserAgent'],\n example: 'For example, you open your app at `localhost:5173` next to the chat. After an edit, the agent clicks the new button and checks the result.',\n unlocks: 'A browser tab next to the chat. The agent opens pages, clicks and reads them to check its own work.',\n prevents: 'Switching to another app to check your work, and changes that the agent never saw on screen.',\n },\n {\n key: 'terminal',\n group: 'desktop',\n surfaces: DESKTOP,\n includes: ['terminalAgent'],\n example: 'For example, you run your dev server in a terminal next to the chat. The agent reads its errors and asks you before it types.',\n unlocks: 'A terminal next to the chat. The agent reads its output, such as an error from your dev server.',\n prevents: 'Switching to another app to run a command, and commands that the agent types without your approval.',\n },\n {\n key: 'notifications',\n group: 'desktop',\n surfaces: DESKTOP,\n includes: ['notificationSound'],\n example: 'For example, you work in another app. A notification and a short sound tell you that a run finished.',\n unlocks: 'A system notification with a short sound when a run finishes or needs your answer.',\n prevents: 'A run that waits for you while you work in another app or look away.',\n },\n {\n key: 'loadProjectExtensions',\n group: 'trust',\n surfaces: BOTH,\n example: 'For example, a project adds a `/deploy` command in its `.zidane/extensions` folder.',\n unlocks: 'Extensions that a project ships load when you open it, such as its own commands.',\n prevents: 'Off, code from a repository that you clone never runs on its own.',\n },\n]\n\n/** A section of the Features step. */\nexport interface OnboardingFeatureGroupMeta {\n /** The section. */\n id: OnboardingFeatureGroup\n /** Its heading. */\n label: string\n}\n\n/** The step's sections, in display order. */\nexport const ONBOARDING_FEATURE_GROUPS: readonly OnboardingFeatureGroupMeta[] = [\n { id: 'desktop', label: 'Desktop' },\n { id: 'work', label: 'Work' },\n { id: 'trust', label: 'Trust' },\n { id: 'background', label: 'In the background' },\n]\n\n/**\n * The features that a run offers: the ones of its app. An `extras` run offers\n * only the ones that no other app offers, because the other app set the\n * shared ones.\n *\n * @param surface - The app that runs the wizard.\n * @param mode - The run's mode.\n */\nexport function onboardingFeatures(surface: OnboardingSurface, mode: OnboardingMode): OnboardingFeature[] {\n return ONBOARDING_FEATURES.filter((feature) => {\n if (!feature.surfaces.includes(surface))\n return false\n return mode !== 'extras' || feature.surfaces.length === 1\n })\n}\n\n/** A feature's label and description: the setting's own. */\nexport interface OnboardingFeatureCopy {\n /** Row label. */\n label: string\n /** One line on what it does. */\n description: string\n}\n\n/**\n * The label and description of a feature, from the settings catalog.\n *\n * @param key - The setting the feature flips.\n */\nexport function onboardingFeatureCopy(key: BooleanSettingKey): OnboardingFeatureCopy {\n const row = SETTINGS_TOGGLES.find(toggle => toggle.key === key)\n if (!row)\n throw new Error(`onboarding feature \"${key}\" has no row in SETTINGS_TOGGLES`)\n return { label: row.label, description: row.description }\n}\n","/**\n * Conversation presets: how much of the agent's work the transcript shows.\n * Balanced is the defaults themselves, so a change to `DEFAULT_SETTINGS`\n * moves it too and choosing it writes nothing. Both apps also offer the\n * presets in their command palette, through the entry built here.\n */\nimport type { PaletteItem, PaletteRunResult } from '../palette'\nimport type { Settings } from '../types'\nimport type { TranscriptPreset, TranscriptPresetId, TranscriptPresetKey, TranscriptPresetSettings } from './types'\nimport { DEFAULT_SETTINGS } from '../settings-defaults'\n\n/** Every setting a conversation preset sets, in the order the fine-tuning lists them. */\nexport const TRANSCRIPT_PRESET_KEYS: readonly TranscriptPresetKey[] = [\n 'transcriptDensity',\n 'showRowIcons',\n 'showThinking',\n 'thinkingAutoExpand',\n 'toolCallDisplay',\n 'showToolResults',\n 'groupToolCalls',\n 'showEditDiffs',\n 'editDiffDisplay',\n 'showRunReceipt',\n 'hideSubagentOutput',\n 'showCacheNotices',\n 'showFullShellOutput',\n 'showCompactionSummary',\n]\n\nfunction presetValues(settings: Settings): TranscriptPresetSettings {\n return Object.fromEntries(TRANSCRIPT_PRESET_KEYS.map(key => [key, settings[key]])) as TranscriptPresetSettings\n}\n\nconst BALANCED = presetValues(DEFAULT_SETTINGS)\n\n/** The three presets, from the quietest to the most complete. */\nexport const TRANSCRIPT_PRESETS: readonly TranscriptPreset[] = [\n {\n id: 'focused',\n label: 'Focused',\n description: 'Shows the answers. The work shows as one short row. Thinking and run costs are hidden.',\n settings: {\n ...BALANCED,\n transcriptDensity: 'compact',\n // The plainest look: no icon before each row (the desktop app's).\n showRowIcons: false,\n showThinking: false,\n thinkingAutoExpand: false,\n groupToolCalls: true,\n editDiffDisplay: 'compact',\n showRunReceipt: false,\n hideSubagentOutput: true,\n showCacheNotices: false,\n showFullShellOutput: false,\n showCompactionSummary: false,\n },\n },\n {\n id: 'balanced',\n label: 'Balanced',\n description: 'Shows the answers, one short row for the work, diffs and the cost of each run. The default.',\n settings: BALANCED,\n },\n {\n id: 'detailed',\n label: 'Detailed',\n description: 'Shows every step and its output, with thinking open and full diffs.',\n settings: {\n ...BALANCED,\n transcriptDensity: 'full',\n showRowIcons: true,\n showThinking: true,\n thinkingAutoExpand: true,\n groupToolCalls: false,\n editDiffDisplay: 'full',\n showRunReceipt: true,\n hideSubagentOutput: false,\n showCacheNotices: true,\n showFullShellOutput: true,\n showCompactionSummary: true,\n },\n },\n]\n\n/**\n * A preset by id.\n *\n * @param id - The preset.\n */\nexport function transcriptPreset(id: TranscriptPresetId): TranscriptPreset {\n return TRANSCRIPT_PRESETS.find(preset => preset.id === id)!\n}\n\n/**\n * The preset a set of settings matches, or `custom` when it matches none.\n * Keys left out take their default value.\n *\n * @param settings - Settings to read, such as the stored ones or a draft.\n * @example\n * ```ts\n * import { transcriptPresetOf } from 'zidane/chat/pure'\n *\n * transcriptPresetOf({}) // 'balanced'\n * transcriptPresetOf({ showThinking: false }) // 'custom'\n * ```\n */\nexport function transcriptPresetOf(settings: Partial<Settings>): TranscriptPresetId | 'custom' {\n const value = (key: TranscriptPresetKey): unknown => settings[key] ?? DEFAULT_SETTINGS[key]\n const match = TRANSCRIPT_PRESETS.find(preset => TRANSCRIPT_PRESET_KEYS.every(key => value(key) === preset.settings[key]))\n return match?.id ?? 'custom'\n}\n\n/** The id of the palette entry for the conversation preset. Both apps use it. */\nexport const TRANSCRIPT_PRESET_PALETTE_ID = 'setting:conversation-preset'\n\nconst PALETTE_CHOICE = `${TRANSCRIPT_PRESET_PALETTE_ID}:`\nconst PALETTE_TITLE = 'Conversation preset'\n\n/**\n * The palette entry for the conversation preset. It names the preset in\n * effect, and running it opens the presets ({@link transcriptPresetPalettePicker}).\n *\n * @param settings - The settings in effect.\n * @param source - The id of the palette provider that owns the entry.\n */\nexport function transcriptPresetPaletteItem(settings: Partial<Settings>, source: string): PaletteItem {\n const current = transcriptPresetOf(settings)\n return {\n id: TRANSCRIPT_PRESET_PALETTE_ID,\n title: PALETTE_TITLE,\n description: current === 'custom' ? 'Custom' : transcriptPreset(current).label,\n group: 'Settings',\n kind: 'picker',\n icon: { gui: 'i-ph-chats-circle' },\n keywords: ['conversation', 'transcript', 'output', 'focused', 'balanced', 'detailed', 'thinking', 'tool calls'],\n source,\n }\n}\n\n/**\n * The list that the palette entry opens: the three presets, the one in effect checked.\n *\n * @param settings - The settings in effect.\n * @param source - The id of the palette provider that owns the rows.\n */\nexport function transcriptPresetPalettePicker(settings: Partial<Settings>, source: string): Extract<PaletteRunResult, { kind: 'items' }> {\n const current = transcriptPresetOf(settings)\n return {\n kind: 'items',\n title: PALETTE_TITLE,\n items: TRANSCRIPT_PRESETS.map(preset => ({\n id: `${PALETTE_CHOICE}${preset.id}`,\n title: preset.label,\n description: preset.description,\n group: PALETTE_TITLE,\n kind: 'toggle',\n checked: current === preset.id,\n source,\n })),\n }\n}\n\n/**\n * The preset that a row of {@link transcriptPresetPalettePicker} applies.\n *\n * @param itemId - The id of the palette row that ran.\n * @returns The preset, or `undefined` for any other row.\n * @example\n * ```ts\n * import { transcriptPresetOfPaletteItem } from 'zidane/chat/pure'\n *\n * transcriptPresetOfPaletteItem('setting:conversation-preset:detailed') // 'detailed'\n * ```\n */\nexport function transcriptPresetOfPaletteItem(itemId: string): TranscriptPresetId | undefined {\n if (!itemId.startsWith(PALETTE_CHOICE))\n return undefined\n const id = itemId.slice(PALETTE_CHOICE.length)\n return TRANSCRIPT_PRESETS.find(preset => preset.id === id)?.id\n}\n\n/**\n * The line that the palette shows once a preset applies.\n *\n * @param id - The preset that applied.\n */\nexport function transcriptPresetNotice(id: TranscriptPresetId): string {\n return `${PALETTE_TITLE}: ${transcriptPreset(id).label}`\n}\n","/**\n * The setup wizard's steps: their order, scope and copy, which of them a run\n * shows, and the palette entry that opens the wizard again. Pure data and\n * functions, shared by every renderer.\n */\nimport type { OnboardingPlanContext, OnboardingStepId, OnboardingStepMeta } from './types'\n\n/**\n * Version of the wizard, stored in each record it writes. A record from an\n * older version still counts as done: existing users open new steps from\n * Settings or the palette, never on their own.\n */\nexport const ONBOARDING_VERSION = 1\n\n/** Every step in flow order, with what it writes and its copy. */\nexport const ONBOARDING_STEPS: readonly OnboardingStepMeta[] = [\n { id: 'welcome', scope: 'none', label: 'Welcome', title: 'Set up zidane', lede: 'This takes about two minutes. You can change every choice later in Settings.' },\n { id: 'connect', scope: 'shared', label: 'Connect', title: 'Choose an AI provider', lede: 'The provider runs the model that answers you. Your keys stay on this computer, in a file that only you can read.' },\n { id: 'import', scope: 'shared', label: 'Bring your setup', title: 'Use your setup from other agents', lede: 'zidane copies what you pick. It does not change the files of the other agent.' },\n { id: 'connectors', scope: 'shared', label: 'Connectors', title: 'Connect your tools', lede: 'The agent can read and change data in these services. Most of them ask you to sign in through your browser.' },\n { id: 'skills', scope: 'shared', label: 'Skills', title: 'Teach zidane how you work', lede: 'A skill is a folder of instructions. The agent reads one when a task needs it.' },\n { id: 'extensions', scope: 'shared', label: 'Extensions', title: 'Add extensions', lede: 'Extensions add commands and features. zidane installs them for you from its repository.' },\n { id: 'look', scope: 'surface', label: 'Look', title: 'Choose how zidane looks', lede: 'The preview shows each choice at once.' },\n { id: 'conversation', scope: 'shared', label: 'Conversation', title: 'How much detail do you want to see?', lede: 'Pick a preset. The preview shows a sample conversation with it.' },\n { id: 'autonomy', scope: 'shared', label: 'Autonomy', title: 'What can zidane do without asking?', lede: 'Commands in your safelist always run, whatever you pick. Your safelist holds the commands that you allowed with Always allow.' },\n { id: 'features', scope: 'shared', label: 'Features', title: 'Turn on what you want', lede: 'You can change these, and more, in Settings.' },\n { id: 'ready', scope: 'none', label: 'Ready', title: 'You are ready', lede: 'Type a task and press Enter to start.' },\n]\n\nconst STEP_ORDER: readonly OnboardingStepId[] = ONBOARDING_STEPS.map(step => step.id)\n\n/**\n * The display data of a step.\n *\n * @param id - The step.\n */\nexport function onboardingStep(id: OnboardingStepId): OnboardingStepMeta {\n return ONBOARDING_STEPS.find(step => step.id === id)!\n}\n\n/**\n * The steps that a run shows, in order. It starts from the steps of the mode.\n * It leaves out Bring your setup when zidane found no other agent, and\n * Connectors, Skills and Extensions when installs do not run on this computer. It\n * also leaves out the steps that the host excludes. A `connect` run always\n * has Connect.\n *\n * @param ctx - The run's mode, surface and what was found.\n * @example\n * ```ts\n * import { planOnboarding } from 'zidane/chat/pure'\n *\n * planOnboarding({ mode: 'quick', surface: 'tui', importAvailable: false, installsAvailable: true })\n * // ['welcome', 'connect', 'ready']\n * ```\n */\nexport function planOnboarding(ctx: OnboardingPlanContext): OnboardingStepId[] {\n const applies = (id: OnboardingStepId): boolean => {\n if (ctx.exclude?.includes(id))\n return false\n if (id === 'import')\n return ctx.importAvailable\n if (id === 'connectors' || id === 'skills' || id === 'extensions')\n return ctx.installsAvailable\n return true\n }\n switch (ctx.mode) {\n case 'full':\n return STEP_ORDER.filter(applies)\n case 'rerun':\n return STEP_ORDER.filter(id => id !== 'welcome' && applies(id))\n case 'quick':\n return (['welcome', 'connect', 'import', 'ready'] as const).filter(applies)\n case 'extras':\n return (['look', 'features', 'ready'] as const).filter(applies)\n case 'connect':\n return ['connect']\n }\n}\n\n/** The command palette's entry for the wizard. */\nexport interface SetupPaletteItem {\n /** Palette item id, the same in both apps. */\n id: string\n /** Row title. */\n title: string\n /** Text beside the title. */\n description: string\n /** Extra search terms. */\n keywords: readonly string[]\n}\n\n/** \"Run setup\", the palette entry both apps list to open the wizard again. */\nexport const SETUP_PALETTE_ITEM: SetupPaletteItem = {\n id: 'app:setup',\n title: 'Run setup',\n description: 'Open the setup wizard: provider, connectors, skills, extensions, look, conversation, autonomy and features.',\n keywords: ['setup', 'onboarding', 'wizard', 'welcome', 'get started', 'provider', 'theme', 'connectors', 'skills', 'extensions'],\n}\n","import type { SkillPick } from '../../skills/sources'\n/**\n * The setup wizard's state machine: which step is current, what has been\n * picked, and the background tasks the steps started. One reducer, driven by\n * the TUI and by `@zidane/ui` alike, so both walk the steps the same way.\n */\nimport type { BooleanSettingKey } from '../settings-catalog'\nimport type { Settings } from '../types'\nimport type {\n OnboardingAppearance,\n OnboardingDraft,\n OnboardingImportSelection,\n OnboardingPlanContext,\n OnboardingProviderPick,\n OnboardingStepId,\n OnboardingTask,\n TranscriptPresetId,\n} from './types'\nimport { enforceSettingsInvariants, SETTINGS_TOGGLES } from '../settings-catalog'\nimport { ONBOARDING_FEATURES } from './features'\nimport { TRANSCRIPT_PRESET_KEYS, transcriptPreset } from './presets'\nimport { planOnboarding } from './steps'\n\nfunction toggleRequires(key: string): BooleanSettingKey | undefined {\n return SETTINGS_TOGGLES.find(toggle => toggle.key === key)?.requires\n}\n\nfunction featureIncludes(key: string): readonly BooleanSettingKey[] {\n return ONBOARDING_FEATURES.find(feature => feature.key === key)?.includes ?? []\n}\n\n/** The settings of the Features step: each feature, what it includes, and what those need. */\nfunction featureStepSettings(): BooleanSettingKey[] {\n const keys = ONBOARDING_FEATURES.flatMap(feature => [feature.key, ...(feature.includes ?? [])])\n return [...new Set([...keys, ...keys.flatMap(key => toggleRequires(key) ?? [])])]\n}\n\n/** The settings each step edits. Skipping a step puts them back. */\nexport const ONBOARDING_STEP_SETTINGS: Partial<Record<OnboardingStepId, readonly (keyof Settings)[]>> = {\n import: ['importForeignConfigs'],\n look: ['theme', 'mouseInteractions'],\n conversation: TRANSCRIPT_PRESET_KEYS,\n autonomy: ['approvalMode', 'sandbox', 'sandboxNetwork', 'maxCostUsd'],\n features: featureStepSettings(),\n}\n\n/** Every setting the wizard can change. */\nexport const ONBOARDING_SETTING_KEYS: readonly (keyof Settings)[] = [...new Set(Object.values(ONBOARDING_STEP_SETTINGS).flatMap(keys => keys ?? []))]\n\n/** Where a run is. */\nexport interface OnboardingFlowState {\n /** What decides the steps. `mode` is the mode the run opened in. */\n context: OnboardingPlanContext\n /** The steps of this run, in order. */\n steps: readonly OnboardingStepId[]\n /** Index of the current step in `steps`. */\n index: number\n /** Everything picked so far. */\n draft: OnboardingDraft\n /** The draft the run started from: what Skip goes back to, and what the result diffs against. */\n initial: OnboardingDraft\n /** Imports and installs the steps started. */\n tasks: readonly OnboardingTask[]\n /** The last step was passed: the run is finished. */\n done: boolean\n}\n\n/**\n * What can happen in a run.\n *\n * - `next` / `back`: move one step. `next` on the last step finishes the run.\n * - `goto`: jump to a step of the run, such as from Ready's recap.\n * - `skip`: put the current step's picks back, then move on.\n * - `finish`: end the run now, keeping what was picked (Skip setup).\n * - `choose-path`: Welcome's choice. Quick start cuts the run down to Connect, Bring your setup and Ready.\n * - `set-context`: the detection finished. The steps are planned again and the current one kept.\n * - `set-settings`: change settings. Turning a setting on also turns on what it needs and, for a feature, what it includes. Turning one off turns off what needs it.\n * - `apply-preset`: set every transcript setting to a preset's values.\n * - `set-provider`, `set-imports`, `set-appearance`: Connect's, Bring your setup's and Look's picks.\n * - `toggle-connector`, `toggle-extension`: pick or unpick a connector or a native extension.\n * - `toggle-skills`: pick or unpick skills, one or a whole listing at once.\n * - `task`: add or update a background task, matched by id.\n */\nexport type OnboardingAction\n = | { type: 'next' }\n | { type: 'back' }\n | { type: 'goto', step: OnboardingStepId }\n | { type: 'skip' }\n | { type: 'finish' }\n | { type: 'choose-path', path: OnboardingDraft['path'] }\n | { type: 'set-context', context: Partial<OnboardingPlanContext> }\n | { type: 'set-settings', settings: Partial<Settings> }\n | { type: 'apply-preset', preset: TranscriptPresetId }\n | { type: 'set-provider', provider: OnboardingProviderPick | undefined }\n | { type: 'set-imports', imports: OnboardingImportSelection | undefined }\n | { type: 'set-appearance', appearance: OnboardingAppearance | undefined }\n | { type: 'toggle-connector', id: string, on: boolean }\n | { type: 'toggle-extension', name: string, on: boolean }\n | { type: 'toggle-skills', picks: readonly SkillPick[], on: boolean }\n | { type: 'task', task: OnboardingTask }\n\n/** The draft a run starts from. */\nexport interface OnboardingStart {\n /** The settings in effect now: the stored ones over the defaults. */\n settings: Settings\n /** The desktop app's current look, for the desktop app. */\n appearance?: OnboardingAppearance\n /** The provider in use now, for a re-run. */\n provider?: OnboardingProviderPick\n}\n\nfunction stepsFor(context: OnboardingPlanContext, path: OnboardingDraft['path']): OnboardingStepId[] {\n const mode = context.mode === 'full' && path === 'quick' ? 'quick' : context.mode\n return planOnboarding({ ...context, mode })\n}\n\n/**\n * A new run at its first step.\n *\n * @param context - The run's mode, surface and what was found so far.\n * @param start - The settings, look and provider in effect now.\n */\nexport function createOnboardingFlow(context: OnboardingPlanContext, start: OnboardingStart): OnboardingFlowState {\n const draft: OnboardingDraft = {\n path: 'custom',\n connectors: [],\n skills: [],\n extensions: [],\n settings: { ...start.settings },\n ...(start.provider ? { provider: start.provider } : {}),\n ...(start.appearance ? { appearance: start.appearance } : {}),\n }\n return { context, steps: stepsFor(context, draft.path), index: 0, draft, initial: draft, tasks: [], done: false }\n}\n\n/**\n * Settings with a change applied. A setting that turns on also turns on the\n * one that it needs, so Session titles turns on Decisions, and a feature\n * turns on what it includes, so Browser tab turns on Agent can use the\n * browser. A setting that turns off also turns off the ones that need it.\n *\n * @param settings - The settings before the change.\n * @param patch - The settings to change.\n */\nexport function applySettingsPatch(settings: Partial<Settings>, patch: Partial<Settings>): Partial<Settings> {\n const next: Partial<Settings> = { ...settings, ...patch }\n for (const [key, value] of Object.entries(patch)) {\n if (value !== true)\n continue\n const requires = toggleRequires(key)\n if (requires && next[requires] !== true)\n next[requires] = true\n for (const included of featureIncludes(key))\n next[included] = true\n }\n return enforceSettingsInvariants(next)\n}\n\n/**\n * The current step.\n *\n * @param state - The run.\n */\nexport function currentOnboardingStep(state: OnboardingFlowState): OnboardingStepId {\n return state.steps[state.index]!\n}\n\n/**\n * Whether the user can skip the current step. Welcome and Ready have nothing\n * to skip, and the TUI cannot run without a provider.\n *\n * @param state - The run.\n */\nexport function canSkipOnboardingStep(state: OnboardingFlowState): boolean {\n const step = currentOnboardingStep(state)\n if (step === 'welcome' || step === 'ready')\n return false\n return !(step === 'connect' && state.context.surface === 'tui')\n}\n\nfunction restoreStep(state: OnboardingFlowState, step: OnboardingStepId): OnboardingDraft {\n const { draft, initial } = state\n const keys = ONBOARDING_STEP_SETTINGS[step] ?? []\n const settings = keys.length ? { ...draft.settings, ...Object.fromEntries(keys.map(key => [key, initial.settings[key]])) } : draft.settings\n const next: OnboardingDraft = { ...draft, settings }\n if (step === 'connect')\n next.provider = initial.provider\n if (step === 'import')\n next.imports = initial.imports\n if (step === 'connectors')\n next.connectors = initial.connectors\n if (step === 'skills')\n next.skills = initial.skills\n if (step === 'extensions')\n next.extensions = initial.extensions\n if (step === 'look')\n next.appearance = initial.appearance\n return next\n}\n\nfunction toggledSkills(list: readonly SkillPick[], picks: readonly SkillPick[], on: boolean): readonly SkillPick[] {\n const keys = new Set(picks.map(pick => pick.key))\n const without = list.filter(pick => !keys.has(pick.key))\n return on ? [...without, ...picks.filter((pick, i) => picks.findIndex(other => other.key === pick.key) === i)] : without\n}\n\nfunction toggled(list: readonly string[], item: string, on: boolean): readonly string[] {\n const without = list.filter(entry => entry !== item)\n return on ? [...without, item] : without\n}\n\nfunction move(state: OnboardingFlowState, delta: 1 | -1): OnboardingFlowState {\n const index = state.index + delta\n if (index >= state.steps.length)\n return { ...state, done: true }\n return index < 0 ? state : { ...state, index }\n}\n\nfunction replan(state: OnboardingFlowState, context: OnboardingPlanContext, path: OnboardingDraft['path']): OnboardingFlowState {\n const current = currentOnboardingStep(state)\n const steps = stepsFor(context, path)\n const kept = steps.indexOf(current)\n return { ...state, context, steps, index: kept >= 0 ? kept : Math.min(state.index, steps.length - 1) }\n}\n\nfunction withDraft(state: OnboardingFlowState, draft: Partial<OnboardingDraft>): OnboardingFlowState {\n return { ...state, draft: { ...state.draft, ...draft } }\n}\n\n/**\n * The next state of a run.\n *\n * @param state - The run now.\n * @param action - What happened.\n * @example\n * ```ts\n * import { createOnboardingFlow, currentOnboardingStep, DEFAULT_SETTINGS, onboardingReducer } from 'zidane/chat/pure'\n *\n * let flow = createOnboardingFlow(\n * { mode: 'full', surface: 'tui', importAvailable: false, installsAvailable: true },\n * { settings: DEFAULT_SETTINGS },\n * )\n * flow = onboardingReducer(flow, { type: 'next' })\n * currentOnboardingStep(flow) // 'connect'\n * ```\n */\nexport function onboardingReducer(state: OnboardingFlowState, action: OnboardingAction): OnboardingFlowState {\n switch (action.type) {\n case 'next':\n return move(state, 1)\n case 'back':\n return move(state, -1)\n case 'goto': {\n const index = state.steps.indexOf(action.step)\n return index < 0 ? state : { ...state, index, done: false }\n }\n case 'skip':\n return move({ ...state, draft: restoreStep(state, currentOnboardingStep(state)) }, 1)\n case 'finish':\n return { ...state, done: true }\n case 'choose-path':\n return replan(withDraft(state, { path: action.path }), state.context, action.path)\n case 'set-context':\n return replan(state, { ...state.context, ...action.context }, state.draft.path)\n case 'set-settings':\n return withDraft(state, { settings: applySettingsPatch(state.draft.settings, action.settings) })\n case 'apply-preset':\n return withDraft(state, { settings: applySettingsPatch(state.draft.settings, transcriptPreset(action.preset).settings) })\n case 'set-provider':\n return withDraft(state, { provider: action.provider })\n case 'set-imports':\n return withDraft(state, { imports: action.imports })\n case 'set-appearance':\n return withDraft(state, { appearance: action.appearance })\n case 'toggle-connector':\n return withDraft(state, { connectors: toggled(state.draft.connectors, action.id, action.on) })\n case 'toggle-extension':\n return withDraft(state, { extensions: toggled(state.draft.extensions, action.name, action.on) })\n case 'toggle-skills':\n return withDraft(state, { skills: toggledSkills(state.draft.skills, action.picks, action.on) })\n case 'task': {\n const exists = state.tasks.some(task => task.id === action.task.id)\n const tasks = exists ? state.tasks.map(task => (task.id === action.task.id ? action.task : task)) : [...state.tasks, action.task]\n return { ...state, tasks }\n }\n }\n}\n\n/** How far a run is: the current step's position and the number of steps. */\nexport interface OnboardingProgress {\n /** Zero-based position of the current step. */\n index: number\n /** Number of steps in the run. */\n count: number\n}\n\n/**\n * How far a run is.\n *\n * @param state - The run.\n */\nexport function onboardingProgress(state: OnboardingFlowState): OnboardingProgress {\n return { index: state.index, count: state.steps.length }\n}\n","/**\n * Bring your setup's selection: what it starts on, and whether it brings\n * anything over. Shared by every renderer, so the terminal app and the\n * desktop app start on the same boxes.\n */\nimport type { OnboardingImportPreview, OnboardingImportSelection } from './types'\n\n/**\n * The selection that Bring your setup starts on. It has every piece with\n * something new to copy. It has the sessions of this project, or of every\n * project when this project has none.\n *\n * @param preview - What an import brings over.\n * @example\n * ```ts\n * import { defaultImportSelection } from 'zidane/chat/pure'\n *\n * const none = { copy: [], skip: [] }\n * defaultImportSelection({ sessions: { project: 0, all: 3 }, mcps: { copy: ['github'], skip: [] }, skills: none, commands: none, agents: none, notes: [] })\n * // { sessions: true, allProjects: true, mcps: true, skills: false, commands: false, agents: false }\n * ```\n */\nexport function defaultImportSelection(preview: OnboardingImportPreview): OnboardingImportSelection {\n const { sessions } = preview\n return {\n sessions: sessions.all > 0,\n allProjects: sessions.project === 0 && sessions.all > 0,\n mcps: preview.mcps.copy.length > 0,\n skills: preview.skills.copy.length > 0,\n commands: preview.commands.copy.length > 0,\n agents: preview.agents.copy.length > 0,\n }\n}\n\n/**\n * Whether a selection brings anything over.\n *\n * @param selection - The selection, or `undefined` when none was made.\n */\nexport function importsSomething(selection: OnboardingImportSelection | undefined): boolean {\n return Boolean(selection && (selection.sessions || selection.mcps || selection.skills || selection.commands || selection.agents))\n}\n","/**\n * The conversation that the Conversation step shows, in both apps. It is one\n * short run: a prompt with a chart and a notes file attached, thinking, two\n * short replies while it works, a search, a read, an edit with its diff, a\n * test run, the answer and its receipt. Every transcript setting changes how\n * some of it shows, and the two short replies fold as earlier messages in\n * compact mode. Nothing in it is real.\n */\nimport type { StreamEvent } from '../types'\n\nconst ROUTE_BEFORE = `export const chat = route('/chat', async (req) => {\n return stream(await agent.run(req.body))\n})`\n\nconst ROUTE_AFTER = `const limit = slidingWindow({ perMinute: 20 })\n\nexport const chat = route('/chat', async (req) => {\n const verdict = limit.take(req.ip)\n if (!verdict.ok)\n return tooMany(verdict.retryAfterMs)\n return stream(await agent.run(req.body))\n})`\n\nconst TURN = 'preview-1'\n\n/**\n * The files attached to the preview prompt: a chart of the traffic and the\n * team's notes. The events carry their names. An app that draws them supplies\n * the bytes, matched by name.\n */\nexport const ONBOARDING_PREVIEW_ATTACHMENTS: readonly { name: string, mediaType: string, size: number }[] = [\n { name: 'traffic.svg', mediaType: 'image/svg+xml', size: 2_480 },\n { name: 'limits.md', mediaType: 'text/markdown', size: 412 },\n]\n\n/** The preview conversation, as the transcript renders it. */\nexport const ONBOARDING_PREVIEW_EVENTS: readonly StreamEvent[] = [\n {\n kind: 'user-prompt',\n turnId: TURN,\n text: 'Rate limit /chat to 20 requests a minute per IP, and tell clients how long to wait. The chart shows the spike from last night.',\n attachments: ONBOARDING_PREVIEW_ATTACHMENTS,\n },\n { kind: 'thinking', turnId: TURN, text: 'A sliding window per IP keeps this simple. First, check whether the server already has a limiter I can reuse.' },\n { kind: 'markdown', turnId: TURN, text: 'The chart peaks at 340 requests a minute from one IP. First, I check whether the server already has a limiter.' },\n { kind: 'tool', turnId: TURN, tool: 'grep', callId: 'p1', text: 'grep(limit|window)', input: { pattern: 'limit|window', path: 'src' } },\n { kind: 'tool-result', turnId: TURN, tool: 'grep', callId: 'p1', text: 'src/limits.ts:4: export function slidingWindow(opts: { perMinute: number })' },\n { kind: 'tool', turnId: TURN, tool: 'read_file', callId: 'p2', text: 'read_file(src/routes/chat.ts)', input: { path: 'src/routes/chat.ts' } },\n { kind: 'tool-result', turnId: TURN, tool: 'read_file', callId: 'p2', text: ROUTE_BEFORE },\n { kind: 'markdown', turnId: TURN, text: 'There is a `slidingWindow` helper in `src/limits.ts`. I use it in the route, with the rules from `limits.md`.' },\n {\n kind: 'tool',\n turnId: TURN,\n tool: 'edit',\n callId: 'p3',\n text: 'edit(src/routes/chat.ts)',\n input: { path: 'src/routes/chat.ts', old_string: ROUTE_BEFORE, new_string: ROUTE_AFTER },\n edit: { tool: 'edit', path: 'src/routes/chat.ts', hunks: [{ oldString: ROUTE_BEFORE, newString: ROUTE_AFTER }] },\n },\n { kind: 'tool-result', turnId: TURN, tool: 'edit', callId: 'p3', text: 'Edited src/routes/chat.ts' },\n { kind: 'tool', turnId: TURN, tool: 'shell', callId: 'p4', text: 'shell(bun test)', input: { command: 'bun test' } },\n { kind: 'tool-result', turnId: TURN, tool: 'shell', callId: 'p4', text: ' 12 pass\\n 0 fail\\nRan 12 tests across 3 files. [0.41s]' },\n {\n kind: 'markdown',\n turnId: TURN,\n text: 'The route now checks a sliding window per IP:\\n\\n- **20 requests a minute** for each IP\\n- Over the limit, a **429** with a `Retry-After` header, so clients know how long to wait\\n\\nAll 12 tests pass.',\n },\n {\n kind: 'run-summary',\n turnId: TURN,\n text: '',\n runSummary: { modelId: 'claude-opus-5-5', providerKey: 'anthropic', durationMs: 21_400, turns: 4, costUsd: 0.042, tokensIn: 9_800, tokensOut: 640 },\n },\n]\n","/**\n * The tutorials of the apps: how a part of zidane works, in a title and three\n * steps. The wizard's Connectors and Skills steps open with one, and so do\n * the desktop app's Settings pages. The kit draws each one beside a scene\n * that plays the three steps in turn (`Tutorial` in `@zidane/ui/onboarding`).\n * The terminal app shows the steps of Skills as plain lines.\n */\n\n/** What a tutorial explains. */\nexport type TutorialTopic\n = | 'connectors'\n | 'skills'\n | 'mcp'\n | 'instructions'\n | 'extensions'\n | 'environments'\n | 'files'\n | 'accounts'\n | 'hosts'\n\n/** One step of a tutorial. */\nexport interface TutorialStep {\n /** What happens, in a few words. */\n title: string\n /** One or two sentences more. */\n detail: string\n}\n\n/** The words of a tutorial: its title and its three steps, in order. */\nexport interface TutorialWords {\n /** The title, such as \"How skills work\". */\n title: string\n /** The steps. A scene plays them in turn, one third of its cycle each. */\n steps: readonly [TutorialStep, TutorialStep, TutorialStep]\n}\n\n/** Every tutorial, in the order the docs list them. */\nexport const TUTORIAL_TOPICS: readonly TutorialTopic[] = ['connectors', 'skills', 'mcp', 'instructions', 'extensions', 'environments', 'files', 'accounts', 'hosts']\n\n/** The words of each tutorial. */\nexport const TUTORIALS: Readonly<Record<TutorialTopic, TutorialWords>> = {\n connectors: {\n title: 'How connectors work',\n steps: [\n { title: 'Pick a service', detail: 'zidane adds its MCP server to your mcps.json file.' },\n { title: 'Sign in once', detail: 'Most services open your browser. The token stays on this computer.' },\n { title: 'The agent uses its tools', detail: 'When a task needs the service, the agent calls its tools. Your approval mode still applies.' },\n ],\n },\n skills: {\n title: 'How skills work',\n steps: [\n { title: 'Pick skills', detail: 'A skill is a folder with a SKILL.md file of instructions. zidane copies it to your skills folder.' },\n { title: 'The agent sees the list', detail: 'Each run starts with the name and the description of every skill.' },\n { title: 'It reads a skill when a task fits', detail: 'The agent then follows the full instructions of that skill.' },\n ],\n },\n mcp: {\n title: 'How MCP servers work',\n steps: [\n { title: 'Add a server', detail: 'A server is a command or a URL in your mcps.json file. A project can add its own.' },\n { title: 'Sign in if it asks', detail: 'A server that needs an account opens your browser once. The token stays on this computer.' },\n { title: 'The agent calls its tools', detail: 'When a task needs the service, the agent calls a tool of the server. Your approval mode applies.' },\n ],\n },\n instructions: {\n title: 'How instructions work',\n steps: [\n { title: 'zidane builds one system prompt', detail: 'It joins its own rules, your AGENTS.md files, the instructions of your MCP servers and the list of your skills.' },\n { title: 'A SYSTEM.md replaces its rules', detail: 'Your own SYSTEM.md takes the place of the built-in prompt. Your AGENTS.md files still load.' },\n { title: 'Each run starts with it', detail: 'This page shows each part, where it comes from and its size in tokens.' },\n ],\n },\n extensions: {\n title: 'How extensions work',\n steps: [\n { title: 'An extension is a TypeScript module', detail: 'Its folder sits in ~/.zidane/extensions, or in .zidane/extensions of a project. You can also install one from GitHub or npm.' },\n { title: 'It adds what you need', detail: 'It can add commands, tools, side panels, badges or a model provider. Both apps load it at startup.' },\n { title: 'You choose what runs', detail: 'Turn each one on or off here. A project\\'s extensions also need your trust.' },\n ],\n },\n environments: {\n title: 'How environments work',\n steps: [\n { title: 'A session runs its commands somewhere', detail: 'By default, it runs them on this computer, in the folder of the session.' },\n { title: 'A worktree gives it a branch of its own', detail: 'zidane makes a git worktree, so two sessions can change one repository at once.' },\n { title: 'A sandbox limits what commands touch', detail: 'The OS sandbox lets commands write only to the project and the folders you add. Docker runs them in a container. E2B and Daytona run them in the cloud.' },\n ],\n },\n files: {\n title: 'How files open',\n steps: [\n { title: 'Click a path in the chat', detail: 'It works for a file, a folder or a diff.' },\n { title: 'It opens where you choose', detail: 'The setting below picks the Files panel or your $EDITOR. ⌘-click opens the other one.' },\n { title: 'The Files panel edits and checks', detail: 'It saves your edits to disk. The project\\'s tools, such as tsc or ESLint, mark the problem lines.' },\n ],\n },\n accounts: {\n title: 'How accounts work',\n steps: [\n { title: 'Sign in, or paste an API key', detail: 'Sign in with your Claude or ChatGPT plan, or paste a key from the provider.' },\n { title: 'zidane keeps them on this computer', detail: 'They stay in ~/.zidane/credentials.json, which only you can read.' },\n { title: 'Every app uses them', detail: 'The terminal app reads the same file. A key in your environment works too.' },\n ],\n },\n hosts: {\n title: 'Run zidane on a server',\n steps: [\n { title: 'Start zidane-server on a machine', detail: 'It runs zidane with no window, on a VPS, a home server or a container.' },\n { title: 'Create a device token', detail: 'On the server, zidane server token create prints a token for one device.' },\n { title: 'Add the server here', detail: 'Paste its address and the token. Its sessions run there, and a run keeps going when you close this window.' },\n ],\n },\n}\n","/**\n * The words that both apps say in the setup wizard: the names of the agents\n * and of the local model servers, how a list of names reads, and the\n * sentences that the terminal app (`src/tui/onboarding/copy.ts`) and the\n * kit's labels (`DEFAULT_ONBOARDING_LABELS`) share word for word. Each app\n * adds its own words on top: the terminal app writes its badges in lower case,\n * the kit in sentence case. The helpers take the words that they need, so an\n * app that translates its labels passes its own.\n */\nimport type { ConnectorEntry, NativeExtensionNeed, OnboardingAgentId, OnboardingLocalServer } from './types'\nimport { connectorById } from './connectors'\nimport { TUTORIALS } from './tutorials'\n\n/** The name of each agent whose setup the wizard reads. */\nexport const ONBOARDING_AGENT_NAMES: Readonly<Record<OnboardingAgentId, string>> = {\n 'claude-code': 'Claude Code',\n 'codex': 'Codex',\n 'pi': 'Pi',\n}\n\n/** The name of each local model server that the wizard finds. */\nexport const LOCAL_SERVER_NAMES: Readonly<Record<OnboardingLocalServer['kind'], string>> = {\n 'ollama': 'Ollama',\n 'lm-studio': 'LM Studio',\n 'vllm': 'vLLM',\n}\n\n/**\n * A list of names as a sentence reads it: \"A\", \"A and B\", \"A, B and C\".\n *\n * @param list - The names.\n * @example\n * ```ts\n * import { joinNames } from 'zidane/chat/pure'\n *\n * joinNames(['GitHub', 'Linear', 'Sentry']) // 'GitHub, Linear and Sentry'\n * ```\n */\nexport function joinNames(list: readonly string[]): string {\n return list.length < 2 ? (list[0] ?? '') : `${list.slice(0, -1).join(', ')} and ${list[list.length - 1]}`\n}\n\n/**\n * Up to two names, then a count: \"A and B\", \"A, B and 3 more\".\n *\n * @param list - The names.\n */\nexport function joinFewNames(list: readonly string[]): string {\n return list.length <= 2 ? joinNames(list) : `${list.slice(0, 2).join(', ')} and ${list.length - 2} more`\n}\n\n/** The sentences that both apps say word for word, in English. */\nexport const ONBOARDING_WORDS = {\n agentName: (agent: OnboardingAgentId) => ONBOARDING_AGENT_NAMES[agent],\n detecting: 'Looking at this computer…',\n // Welcome\n fullSetup: 'Full setup',\n quickStart: 'Quick start',\n found: 'Found on this computer',\n foundEnvKey: (envKey: string) => `${envKey} in your environment`,\n foundSignedIn: (provider: string) => `Signed in to ${provider}`,\n foundSaved: (provider: string) => `${provider} is set up`,\n foundAgent: (agent: OnboardingAgentId) => `${ONBOARDING_AGENT_NAMES[agent]} setup`,\n foundGithub: (login: string | undefined, source: string) => login ? `Signed in to GitHub as @${login}` : `A GitHub token from ${source}`,\n foundLocalServer: (server: OnboardingLocalServer) => `${LOCAL_SERVER_NAMES[server.kind]} at ${server.url}`,\n // Connect\n moreProviders: 'More providers',\n localFound: (server: OnboardingLocalServer) => `${LOCAL_SERVER_NAMES[server.kind]} is running`,\n model: 'Model',\n effort: 'Effort',\n effortHint: 'More effort thinks longer and costs more.',\n testing: 'Sending a test message…',\n credentialsAt: (path: string) => `zidane saves keys in ${path}. Only you can read this file.`,\n // Bring your setup\n importSessions: 'Sessions',\n importSessionsDetail: (project: number, all: number) => project === all ? `${all} conversations` : `${project} in this project, ${all} in all projects`,\n importAllProjects: 'Include all projects',\n importMcps: 'MCP servers',\n importSkills: 'Skills',\n importCommands: 'Commands',\n importAgents: 'Subagents',\n importNames: (list: readonly string[]) => list.length > 4 ? `${list.slice(0, 4).join(', ')} and ${list.length - 4} more` : list.join(', '),\n importSkipped: (count: number) => `${count} already in zidane`,\n readInPlaceDetail: 'zidane reads their MCP servers, skills, commands and subagents where they are. Those servers run commands from files zidane does not own.',\n // Tutorials: the wizard's Connectors and Skills steps, and the desktop app's Settings pages\n tutorials: TUTORIALS,\n // Skills\n recommendedSources: 'Recommended sources',\n /** Every form that the source field takes, as one list. A field cuts it with an ellipsis. */\n sourcePlaceholder: 'owner/repo, GitHub link, skills.sh link, npx skills add, npm package',\n browsing: (source: string) => `Reading ${source}…`,\n browseFailed: (message: string) => `The source did not load. ${message}`,\n skillCount: (count: number) => (count === 1 ? '1 skill' : `${count} skills`),\n noSkills: 'No skills here',\n noSkillsHint: 'A skill is a folder with a SKILL.md file. This source has none.',\n packHint: 'A pack lists skills from several repositories. Each skill installs from its own repository.',\n fromRepo: (repo: string) => `from ${repo}`,\n listingTruncated: 'GitHub cut the file list short, so some skills are missing.',\n // Extensions\n needsCommand: (name: string, optional: boolean) => optional ? `${name} (optional)` : name,\n needsConnector: (connector: string) => `the ${connector} connector`,\n needsDecisions: 'the decision model',\n needsAccount: (account: string) => `a ${account} account`,\n // Conversation\n custom: 'Custom',\n preview: 'Preview',\n // Autonomy\n spendCap: 'Spend limit per run',\n spendCapDetail: 'Stops a run that costs more than this. Only API keys charge per token.',\n // What a choice gives you and what it guards against\n unlocks: 'Gives you',\n prevents: 'Prevents',\n // Ready\n background: 'Background work',\n recapNone: 'None',\n recapProvider: (provider: string, model?: string) => model ? `${provider}, ${model}` : provider,\n recapSwitched: (on: readonly string[], off: readonly string[]) =>\n [on.length > 0 && `On: ${joinFewNames(on)}`, off.length > 0 && `Off: ${joinFewNames(off)}`].filter(Boolean).join('. ') || 'No changes',\n sandboxed: 'with the sandbox',\n changeLater: 'You can change every choice in Settings. To open this setup again, use Run setup in the command palette.',\n}\n\n/** The shape of {@link ONBOARDING_WORDS}. */\nexport type OnboardingWords = typeof ONBOARDING_WORDS\n\n/** The words that {@link nativeExtensionNeedText} uses. */\nexport type NativeExtensionNeedWords = Pick<OnboardingWords, 'needsCommand' | 'needsConnector' | 'needsDecisions' | 'needsAccount'>\n\n/**\n * What a native extension needs, in words: \"gh (optional)\", \"the Linear connector\".\n *\n * @param need - The need.\n * @param words - The words to use. Defaults to {@link ONBOARDING_WORDS}.\n */\nexport function nativeExtensionNeedText(need: NativeExtensionNeed, words: NativeExtensionNeedWords = ONBOARDING_WORDS): string {\n switch (need.kind) {\n case 'command':\n return words.needsCommand(need.name, need.optional === true)\n case 'connector':\n return words.needsConnector(connectorById(need.id)?.label ?? need.id)\n case 'decisions':\n return words.needsDecisions\n case 'account':\n return words.needsAccount(need.label)\n }\n}\n\n/** The words that {@link connectorAuthText} uses. Each app writes them its own way. */\nexport interface ConnectorAuthWords {\n /** The connector needs no account. */\n noAccount: string\n /** It takes a token, or the user's `gh` login. */\n tokenOrGhLogin: string\n /** A token is optional. */\n tokenOptionalAuth: string\n /** It needs a token. */\n tokenSignIn: string\n}\n\n/**\n * How a connector signs in, when it is not the usual browser sign-in.\n *\n * @param entry - The connector.\n * @param ghLogin - A `gh` login was found, so a GitHub token can come from it.\n * @param words - The words to use.\n * @returns The words, or `null` for a browser sign-in.\n */\nexport function connectorAuthText(entry: ConnectorEntry, ghLogin: boolean, words: ConnectorAuthWords): string | null {\n if (entry.auth.kind === 'oauth')\n return null\n if (entry.auth.kind === 'none')\n return words.noAccount\n if (entry.auth.reuse === 'github' && ghLogin)\n return words.tokenOrGhLogin\n return entry.auth.optional ? words.tokenOptionalAuth : words.tokenSignIn\n}\n","/**\n * What Ready recaps, in words: the parts of an import that the user picked,\n * and the features that the run switched. Each app lays them out its own\n * way, with its own words.\n */\nimport type { OnboardingFlowState } from './flow'\nimport type { OnboardingImportSelection } from './types'\nimport type { OnboardingWords } from './words'\nimport { onboardingFeatureCopy, onboardingFeatures } from './features'\nimport { ONBOARDING_WORDS } from './words'\n\n/** The words that {@link onboardingImportParts} uses. */\nexport type OnboardingImportWords = Pick<OnboardingWords, 'importSessions' | 'importMcps' | 'importSkills' | 'importCommands' | 'importAgents'>\n\n/**\n * The parts of an import that the user picked, in words, in the order of the step.\n *\n * @param selection - The picks. Absent: nothing to import.\n * @param words - The words to use. Defaults to {@link ONBOARDING_WORDS}.\n */\nexport function onboardingImportParts(selection: OnboardingImportSelection | undefined, words: OnboardingImportWords = ONBOARDING_WORDS): string[] {\n if (!selection)\n return []\n const parts: [boolean, string][] = [\n [selection.sessions, words.importSessions],\n [selection.mcps, words.importMcps],\n [selection.skills, words.importSkills],\n [selection.commands, words.importCommands],\n [selection.agents, words.importAgents],\n ]\n return parts.flatMap(([picked, word]) => (picked ? [word] : []))\n}\n\n/** The features a run switched, by their Settings label. */\nexport interface OnboardingSwitchedFeatures {\n /** The ones it turned on. */\n on: string[]\n /** The ones it turned off. */\n off: string[]\n}\n\n/**\n * The features that a run switched on and off. Only the ones it changed:\n * the defaults are not news.\n *\n * @param state - The run.\n */\nexport function onboardingSwitchedFeatures(state: OnboardingFlowState): OnboardingSwitchedFeatures {\n const { draft, initial, context } = state\n const changed = onboardingFeatures(context.surface, context.mode)\n .filter(feature => Boolean(draft.settings[feature.key]) !== Boolean(initial.settings[feature.key]))\n const named = (on: boolean): string[] => changed\n .filter(feature => Boolean(draft.settings[feature.key]) === on)\n .map(feature => onboardingFeatureCopy(feature.key).label)\n return { on: named(true), off: named(false) }\n}\n","/**\n * What a run writes, and when an app opens the wizard: the sparse settings\n * change, the records in the state file, and the launch gate.\n */\nimport type { Settings } from '../types'\nimport type { OnboardingFlowState } from './flow'\nimport type {\n OnboardingGate,\n OnboardingInstallSignals,\n OnboardingMode,\n OnboardingRecord,\n OnboardingResult,\n OnboardingSettingsChange,\n OnboardingState,\n OnboardingSurface,\n} from './types'\nimport { requirementMet, SETTINGS_TOGGLES } from '../settings-catalog'\nimport { DEFAULT_SETTINGS } from '../settings-defaults'\nimport { ONBOARDING_SETTING_KEYS } from './flow'\nimport { ONBOARDING_VERSION } from './steps'\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (Object.is(a, b))\n return true\n return typeof a === 'object' && a !== null && typeof b === 'object' && b !== null && JSON.stringify(a) === JSON.stringify(b)\n}\n\n/** Off only because the setting it needs is off, such as Agent can use your terminals with Terminals off. */\nfunction forcedOff(settings: Partial<Settings>, key: keyof Settings): boolean {\n const requires = SETTINGS_TOGGLES.find(toggle => toggle.key === key)?.requires\n return settings[key] === false && requires !== undefined && !requirementMet(settings, requires)\n}\n\n/**\n * The settings that a run writes. Only the keys that the run changed count. A\n * value that equals the default is not stored, so it keeps following the\n * default. If the key is stored, the run resets it instead of pinning it. A\n * setting that is off only because the one it needs is off is not written:\n * it comes back as it was when that one turns on again.\n *\n * @param draft - The settings the run ends with.\n * @param initial - The settings the run started with.\n * @param stored - The settings slice stored now (explicit choices only, without defaults).\n * @example\n * ```ts\n * import { DEFAULT_SETTINGS, onboardingSettingsChange } from 'zidane/chat/pure'\n *\n * onboardingSettingsChange({ ...DEFAULT_SETTINGS, spaces: true }, DEFAULT_SETTINGS, {})\n * // { set: { spaces: true }, reset: [] }\n * ```\n */\nexport function onboardingSettingsChange(draft: Partial<Settings>, initial: Partial<Settings>, stored: Partial<Settings>): OnboardingSettingsChange {\n const set: Partial<Settings> = {}\n const reset: (keyof Settings)[] = []\n for (const key of ONBOARDING_SETTING_KEYS) {\n if (!(key in draft) || sameValue(draft[key], initial[key]) || forcedOff(draft, key))\n continue\n if (sameValue(draft[key], DEFAULT_SETTINGS[key])) {\n if (key in stored)\n reset.push(key)\n continue\n }\n Object.assign(set, { [key]: draft[key] })\n }\n return { set, reset }\n}\n\n/**\n * Whether the install existed before the wizard: it has stored settings,\n * credentials, sessions or a last-used provider.\n *\n * @param signals - What the app read from this machine.\n */\nexport function isExistingInstall(signals: OnboardingInstallSignals): boolean {\n return signals.storedSettings || signals.credentials || signals.sessions || signals.lastProvider\n}\n\n/** What {@link needsOnboarding} reads. */\nexport interface OnboardingGateInput {\n /** The records in the state file. */\n state: OnboardingState | undefined\n /** What the app read from this machine. */\n signals: OnboardingInstallSignals\n /** The app asking. */\n surface: OnboardingSurface\n /** The wizard is turned off: `ZIDANE_NO_ONBOARDING=1`, an embedder's `onboarding: false`, a headless run. */\n disabled?: boolean\n}\n\n/**\n * What an app does at launch about the wizard (`docs/ONBOARDING.md`, When it opens).\n *\n * @param input - The records, the machine's signals and the app.\n * @example\n * ```ts\n * import { needsOnboarding } from 'zidane/chat/pure'\n *\n * const signals = { storedSettings: false, credentials: false, sessions: false, lastProvider: false, surfaceFirstRun: true }\n * needsOnboarding({ state: undefined, signals, surface: 'tui' }) // { kind: 'run', mode: 'full' }\n * ```\n */\nexport function needsOnboarding(input: OnboardingGateInput): OnboardingGate {\n if (input.disabled)\n return { kind: 'none' }\n const state = input.state ?? {}\n if (!state.shared) {\n if (state.inProgress || !isExistingInstall(input.signals))\n return { kind: 'run', mode: 'full' }\n return { kind: 'migrate' }\n }\n if (state[input.surface] || state.shared.migrated || state.shared.surface === input.surface)\n return { kind: 'none' }\n return input.signals.surfaceFirstRun ? { kind: 'run', mode: 'extras' } : { kind: 'none' }\n}\n\n/**\n * A record for a run that just ended.\n *\n * @param surface - The app it ran in.\n * @param now - When it ended.\n * @param migrated - Written for an install that predates the wizard.\n */\nexport function onboardingRecord(surface: OnboardingSurface, now: Date = new Date(), migrated = false): OnboardingRecord {\n return { version: ONBOARDING_VERSION, completedAt: now.toISOString(), surface, ...(migrated ? { migrated: true as const } : {}) }\n}\n\n/**\n * The records that a finished run writes. A full, quick or repeated run writes\n * the shared record and the record of this app. An extras run writes only the\n * record of this app. Connect alone writes none.\n *\n * @param mode - The mode the run ended in.\n * @param surface - The app it ran in.\n * @param now - When it ended.\n */\nexport function onboardingRecords(mode: OnboardingMode, surface: OnboardingSurface, now: Date = new Date()): OnboardingState {\n if (mode === 'connect')\n return {}\n const record = onboardingRecord(surface, now)\n const own = surfaceRecord(surface, record)\n return mode === 'extras' ? own : { shared: record, ...own }\n}\n\nfunction surfaceRecord(surface: OnboardingSurface, record: OnboardingRecord): OnboardingState {\n return surface === 'tui' ? { tui: record } : { desktop: record }\n}\n\n/**\n * The records an install that predates the wizard gets, so it never opens on its own.\n *\n * @param surface - The app that noticed.\n * @param now - When.\n */\nexport function migratedOnboardingRecords(surface: OnboardingSurface, now: Date = new Date()): OnboardingState {\n const record = onboardingRecord(surface, now, true)\n return { shared: record, ...surfaceRecord(surface, record) }\n}\n\n/**\n * Stored records with new ones merged in. A finished run (any record) clears\n * the in-progress marker.\n *\n * @param stored - The records in the state file now.\n * @param records - The records to add, such as {@link OnboardingResult.records} or an `inProgress` marker.\n */\nexport function mergeOnboardingState(stored: OnboardingState | undefined, records: OnboardingState): OnboardingState {\n const next: OnboardingState = { ...stored, ...records }\n if (records.shared || records.tui || records.desktop)\n delete next.inProgress\n return next\n}\n\n/**\n * The mode a run ends in: Quick start turns a full run into a quick one.\n *\n * @param state - The run.\n */\nexport function effectiveOnboardingMode(state: OnboardingFlowState): OnboardingMode {\n return state.context.mode === 'full' && state.draft.path === 'quick' ? 'quick' : state.context.mode\n}\n\n/**\n * What a finished run writes: the settings change, the provider pick, the\n * look and the records.\n *\n * @param state - The finished run.\n * @param stored - The settings slice stored now.\n * @param now - When it finished.\n */\nexport function buildOnboardingResult(state: OnboardingFlowState, stored: Partial<Settings>, now: Date = new Date()): OnboardingResult {\n const mode = effectiveOnboardingMode(state)\n const { draft, initial } = state\n const provider = draft.provider && !sameValue(draft.provider, initial.provider) ? draft.provider : undefined\n const appearance = draft.appearance && !sameValue(draft.appearance, initial.appearance) ? draft.appearance : undefined\n return {\n mode,\n surface: state.context.surface,\n settings: onboardingSettingsChange(draft.settings, initial.settings, stored),\n ...(provider ? { provider } : {}),\n ...(appearance ? { appearance } : {}),\n records: onboardingRecords(mode, state.context.surface, now),\n }\n}\n","/**\n * A run of the setup wizard outside any UI: the reducer, plus the work that its\n * steps start. When the user passes a step, the run starts the imports and\n * installs picked there, in the background. Each kind of work has its own\n * lane, so a long import never holds up an extension. Passing the last step\n * saves the result through the host. A run that ends without a save puts the\n * previewed look back. The run also loads, once, what an import from Claude\n * Code brings over.\n *\n * The TUI reads a run with its own hooks. `@zidane/ui/onboarding/headless`\n * wraps it as `createOnboardingController`.\n */\nimport type { Settings } from '../types'\nimport type { OnboardingAction, OnboardingFlowState } from './flow'\nimport type {\n ConnectorInput,\n OnboardingAppearance,\n OnboardingImportPreview,\n OnboardingImportSelection,\n OnboardingPlanContext,\n OnboardingProviderPick,\n OnboardingResult,\n OnboardingStepId,\n OnboardingTask,\n OnboardingTaskKind,\n OnboardingTaskStatus,\n} from './types'\nimport { groupSkillPicks } from '../../skills/sources'\nimport { DEFAULT_SETTINGS } from '../settings-defaults'\nimport { connectorById } from './connectors'\nimport { createOnboardingFlow, currentOnboardingStep, onboardingReducer } from './flow'\nimport { importsSomething } from './imports'\nimport { nativeExtensionByName } from './native-extensions'\nimport { buildOnboardingResult } from './result'\nimport { ONBOARDING_AGENT_NAMES } from './words'\n\n/** A value that a UI reads and watches. It has the shape of `Readable` in `@zidane/ui`. */\nexport interface OnboardingReadable<T> {\n /** Returns the current value. */\n get: () => T\n /** Calls `onChange` after the value changes. Returns a function that stops the calls. */\n subscribe: (onChange: () => void) => () => void\n}\n\n/**\n * Where a run is in its life.\n *\n * - `running`: the user is going through the steps.\n * - `saving`: the last step was passed, and the host is writing the result.\n * - `saved`: the result is written. The app closes the wizard.\n * - `failed`: writing failed. The run is back on its step, and moving on again tries again.\n */\nexport type OnboardingPhase\n = | { kind: 'running' }\n | { kind: 'saving' }\n | { kind: 'saved', result: OnboardingResult }\n | { kind: 'failed', message: string }\n\n/**\n * What an import from Claude Code brings over.\n *\n * - `none`: the run offers no import, because there is no Claude Code setup or no import.\n * - `loading`: the host is reading it.\n * - `ready`: the preview.\n * - `failed`: the host failed to read it.\n */\nexport type OnboardingImportPreviewState\n = | { kind: 'none' }\n | { kind: 'loading' }\n | { kind: 'ready', preview: OnboardingImportPreview }\n | { kind: 'failed', message: string }\n\n/**\n * The connectors that an import brings over: the MCP servers that it copies\n * and that have the id of a connector. The Connectors step marks them, and the\n * run does not add them twice.\n *\n * @param preview - What the import brings over.\n * @param selection - What the user picked to import.\n * @example\n * ```ts\n * import { connectorsFromImport } from 'zidane/chat/pure'\n *\n * const none = { copy: [], skip: [] }\n * const preview = { sessions: { project: 0, all: 0 }, mcps: { copy: ['github', 'my-db'], skip: [] }, skills: none, commands: none, agents: none, notes: [] }\n * const selection = { sessions: false, allProjects: false, mcps: true, skills: false, commands: false, agents: false }\n * connectorsFromImport({ kind: 'ready', preview }, selection) // ['github']\n * ```\n */\nexport function connectorsFromImport(preview: OnboardingImportPreviewState, selection: OnboardingImportSelection | undefined): readonly string[] {\n if (preview.kind !== 'ready' || !selection?.mcps)\n return []\n return preview.preview.mcps.copy.filter(name => connectorById(name) !== undefined)\n}\n\n/** The work that a run asks the app to do. If a member is left out, that work does not run. */\nexport interface OnboardingRunHost {\n /** The import from Claude Code. Leave it out when there is no Claude Code setup. */\n imports?: {\n /** Reads what the import brings over. */\n preview: () => Promise<OnboardingImportPreview>\n /** Imports the selection. */\n run: (selection: OnboardingImportSelection) => Promise<void>\n }\n /** Connectors. */\n connectors?: {\n /** Ids of the connectors that are installed now. */\n installed: () => readonly string[]\n /** Adds the MCP server of a connector. */\n add: (id: string, input?: ConnectorInput) => Promise<void>\n /** The app offers the browser sign-in on Ready, so a browser connector ends as `needs-sign-in`. */\n signInLater?: boolean\n }\n /** Skills. */\n skills?: {\n /** Names of the skills that are installed now. */\n installed: () => readonly string[]\n /** Installs the picked skills of one source (`rels`, as `installSkillFromSpec` takes them), and reports progress lines. */\n install: (source: string, rels: readonly string[], onProgress?: (line: string) => void) => Promise<void>\n }\n /** Native extensions. */\n extensions?: {\n /** Names of the extensions that are installed or loaded now. */\n installed: () => readonly string[]\n /** Installs a native extension and reports progress lines. */\n install: (name: string, onProgress?: (line: string) => void) => Promise<void>\n }\n /** Shows a look of the desktop app live. `null` puts the current look back. */\n previewLook?: (appearance: OnboardingAppearance | null) => void\n /** Writes what a finished run decided. */\n commit: (result: OnboardingResult) => Promise<void>\n}\n\n/** What a run starts from. */\nexport interface OnboardingRunSetup {\n /** The mode, the app, and what was found. */\n context: OnboardingPlanContext\n /** The stored settings: explicit choices only, without the defaults. */\n settings: Partial<Settings>\n /** The look of the desktop app now. */\n appearance?: OnboardingAppearance\n /** The provider, model and effort in use now, for a re-run. */\n provider?: OnboardingProviderPick\n}\n\n/** Options of {@link createOnboardingRun}. */\nexport interface OnboardingRunOptions {\n /** Opens the run at this step instead of its first one, when the run has it. */\n start?: OnboardingStepId\n /** The clock of the records. It defaults to the current time. */\n now?: () => Date\n}\n\n/** A run and the work that it starts. */\nexport interface OnboardingRun {\n /** The steps, the picks and the background tasks. */\n state: OnboardingReadable<OnboardingFlowState>\n /** Where the run is in its life. */\n phase: OnboardingReadable<OnboardingPhase>\n /** What an import from Claude Code brings over. */\n importPreview: OnboardingReadable<OnboardingImportPreviewState>\n /**\n * Applies an action. Picking an extension that works through a connector\n * also picks the connector, unless it is installed, imported or picked.\n * Passing a step starts what the user picked there. Passing the last step\n * saves the result.\n */\n dispatch: (action: OnboardingAction) => void\n /** Keeps what the user typed for a connector, such as a token. A token is a secret, so it stays out of the draft. */\n setConnectorInput: (id: string, input: ConnectorInput) => void\n /** Returns what the user typed for a connector. */\n connectorInput: (id: string) => ConnectorInput\n /** Runs a failed task again. */\n retry: (taskId: string) => void\n /** Ends the run. A run that never saved puts the previewed look back. */\n dispose: () => void\n}\n\ninterface Box<T> extends OnboardingReadable<T> {\n set: (next: T) => void\n}\n\nfunction box<T>(initial: T): Box<T> {\n let value = initial\n const listeners = new Set<() => void>()\n return {\n get: () => value,\n set(next) {\n if (Object.is(next, value))\n return\n value = next\n for (const listener of [...listeners])\n listener()\n },\n subscribe(onChange) {\n listeners.add(onChange)\n return () => {\n listeners.delete(onChange)\n }\n },\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/**\n * Starts a run of the setup wizard.\n *\n * @param host - The work that the app does for the run.\n * @param setup - What the run starts from.\n * @param options - The step to open at, and the clock.\n * @returns The run. Call `dispose` when the wizard closes.\n * @example\n * ```ts\n * import { createOnboardingRun } from 'zidane/chat/pure'\n *\n * const run = createOnboardingRun(\n * { commit: async result => console.log(result.settings) },\n * { context: { mode: 'full', surface: 'tui', importAvailable: false, installsAvailable: false }, settings: {} },\n * )\n * run.dispatch({ type: 'set-settings', settings: { spaces: true } })\n * run.dispatch({ type: 'finish' }) // logs { set: { spaces: true }, reset: [] }\n * ```\n */\nexport function createOnboardingRun(host: OnboardingRunHost, setup: OnboardingRunSetup, options: OnboardingRunOptions = {}): OnboardingRun {\n const now = options.now ?? (() => new Date())\n let flow = createOnboardingFlow(setup.context, {\n settings: { ...DEFAULT_SETTINGS, ...setup.settings },\n ...(setup.appearance ? { appearance: setup.appearance } : {}),\n ...(setup.provider ? { provider: setup.provider } : {}),\n })\n if (options.start)\n flow = onboardingReducer(flow, { type: 'goto', step: options.start })\n const state = box(flow)\n const phase = box<OnboardingPhase>({ kind: 'running' })\n const importPreview = box<OnboardingImportPreviewState>({ kind: 'none' })\n const inputs = new Map<string, ConnectorInput>()\n const runners = new Map<string, () => Promise<OnboardingTaskStatus | void>>()\n const lanes: Record<OnboardingTaskKind, Promise<void>> = {\n import: Promise.resolve(),\n connector: Promise.resolve(),\n skill: Promise.resolve(),\n extension: Promise.resolve(),\n }\n // The skills that a task already covers: a later pick from the same source gets a task of its own.\n const skillsStarted = new Set<string>()\n\n if (host.imports) {\n importPreview.set({ kind: 'loading' })\n host.imports.preview().then(\n preview => importPreview.set({ kind: 'ready', preview }),\n (error: unknown) => importPreview.set({ kind: 'failed', message: errorMessage(error) }),\n )\n }\n\n const report = (task: OnboardingTask): void => state.set(onboardingReducer(state.get(), { type: 'task', task }))\n const taskOf = (id: string): OnboardingTask | undefined => state.get().tasks.find(task => task.id === id)\n\n const enqueue = (task: Omit<OnboardingTask, 'status'>): void => {\n const run = runners.get(task.id)\n if (!run)\n return\n report({ ...task, status: 'queued' })\n lanes[task.kind] = lanes[task.kind].then(async () => {\n report({ ...task, status: 'running' })\n try {\n report({ ...task, status: (await run()) ?? 'done' })\n }\n catch (error) {\n report({ ...task, status: 'failed', message: errorMessage(error) })\n }\n })\n }\n\n const progress = (id: string) => (line: string): void => {\n const task = taskOf(id)\n if (task?.status === 'running')\n report({ ...task, message: line })\n }\n\n const startPassed = (s: OnboardingFlowState): void => {\n const passed = new Set(s.done ? s.steps : s.steps.slice(0, s.index))\n const started = (id: string): boolean => s.tasks.some(task => task.id === id)\n const { imports, connectors, skills, extensions } = host\n if (imports && passed.has('import') && importsSomething(s.draft.imports) && !started('import:claude-code')) {\n const selection = s.draft.imports!\n runners.set('import:claude-code', () => imports.run(selection))\n enqueue({ id: 'import:claude-code', kind: 'import', label: ONBOARDING_AGENT_NAMES['claude-code'] })\n }\n if (connectors && (passed.has('connectors') || passed.has('extensions'))) {\n const installed = connectors.installed()\n const imported = connectorsFromImport(importPreview.get(), s.draft.imports)\n for (const id of s.draft.connectors) {\n const entry = connectorById(id)\n if (!entry || installed.includes(id) || imported.includes(id) || started(`connector:${id}`))\n continue\n runners.set(`connector:${id}`, async () => {\n await connectors.add(id, inputs.get(id))\n return entry.auth.kind === 'oauth' && connectors.signInLater ? 'needs-sign-in' : 'done'\n })\n enqueue({ id: `connector:${id}`, kind: 'connector', label: entry.label })\n }\n }\n if (skills && passed.has('skills')) {\n const installed = skills.installed()\n const fresh = s.draft.skills.filter(pick => !skillsStarted.has(pick.key) && !installed.includes(pick.name))\n for (const group of groupSkillPicks(fresh)) {\n const id = `skill:${group.source}:${skillsStarted.size}`\n for (const pick of fresh.filter(p => p.install.source === group.source))\n skillsStarted.add(pick.key)\n runners.set(id, () => skills.install(group.source, group.rels, progress(id)))\n enqueue({ id, kind: 'skill', label: group.label })\n }\n }\n if (extensions && passed.has('extensions')) {\n const installed = extensions.installed()\n for (const name of s.draft.extensions) {\n const entry = nativeExtensionByName(name)\n if (!entry || installed.includes(name) || started(`extension:${name}`))\n continue\n runners.set(`extension:${name}`, () => extensions.install(name, progress(`extension:${name}`)))\n enqueue({ id: `extension:${name}`, kind: 'extension', label: entry.label })\n }\n }\n }\n\n /** The connectors an extension works through that the run does not bring yet. */\n const missingConnectors = (name: string, s: OnboardingFlowState): string[] => {\n const entry = nativeExtensionByName(name)\n if (!entry || !host.connectors)\n return []\n const installed = host.connectors.installed()\n const imported = connectorsFromImport(importPreview.get(), s.draft.imports)\n return entry.needs.flatMap(need =>\n need.kind === 'connector' && ![installed, imported, s.draft.connectors].some(list => list.includes(need.id)) ? [need.id] : [])\n }\n\n const reduce = (s: OnboardingFlowState, action: OnboardingAction): OnboardingFlowState => {\n const next = onboardingReducer(s, action)\n if (action.type !== 'toggle-extension' || !action.on || next === s)\n return next\n return missingConnectors(action.name, s).reduce((flow, id) => onboardingReducer(flow, { type: 'toggle-connector', id, on: true }), next)\n }\n\n const save = (): void => {\n const result = buildOnboardingResult(state.get(), setup.settings, now())\n phase.set({ kind: 'saving' })\n host.commit(result).then(\n () => phase.set({ kind: 'saved', result }),\n (error: unknown) => {\n phase.set({ kind: 'failed', message: errorMessage(error) })\n state.set(onboardingReducer(state.get(), { type: 'goto', step: currentOnboardingStep(state.get()) }))\n },\n )\n }\n\n return {\n state,\n phase,\n importPreview,\n dispatch(action) {\n const life = phase.get().kind\n if (life === 'saving' || life === 'saved')\n return\n const before = state.get()\n const after = reduce(before, action)\n if (after === before)\n return\n state.set(after)\n if (after.draft.appearance !== before.draft.appearance)\n host.previewLook?.(after.draft.appearance ?? null)\n if (after.done || after.index > before.index)\n startPassed(after)\n if (after.done)\n save()\n },\n setConnectorInput(id, input) {\n inputs.set(id, input)\n },\n connectorInput(id) {\n return inputs.get(id) ?? {}\n },\n retry(taskId) {\n const task = taskOf(taskId)\n if (task?.status === 'failed')\n enqueue({ id: task.id, kind: task.kind, label: task.label })\n },\n dispose() {\n if (phase.get().kind !== 'saved')\n host.previewLook?.(null)\n },\n }\n}\n","/**\n * What each Autonomy choice gives you and what it guards against: the\n * approval modes, the sandbox and its network, the spend limit, and reading\n * the setup of other agents in place. The features carry theirs in\n * `ONBOARDING_FEATURES`. Both apps show the two sentences side by side.\n */\nimport type { ApprovalMode, Settings } from '../types'\nimport type { OnboardingTradeoff } from './types'\n\n/** What each approval mode gives you and guards against. */\nexport const APPROVAL_MODE_TRADEOFFS: Readonly<Record<ApprovalMode, OnboardingTradeoff>> = {\n ask: {\n unlocks: 'You see each tool call before it runs, and you decide.',\n prevents: 'Commands and edits that you did not expect.',\n },\n decide: {\n unlocks: 'Long runs that stop only for risky calls. Safe calls run at once.',\n prevents: 'Risky calls. The decision model blocks them, or asks you when it is not sure.',\n },\n off: {\n unlocks: 'The fastest runs, with no stops at all.',\n prevents: 'Nothing. Turn on the sandbox, or work in a folder that you can throw away.',\n },\n}\n\n/** What the safety settings of Autonomy and Bring your setup give you and guard against. */\nexport const SETTING_TRADEOFFS: Readonly<Partial<Record<keyof Settings, OnboardingTradeoff>>> = {\n sandbox: {\n unlocks: 'More freedom for the agent, with less risk to your computer.',\n prevents: 'Edits outside the project, and reads of your credentials and keys.',\n },\n sandboxNetwork: {\n unlocks: 'With Allow, commands in the sandbox install packages and fetch pages.',\n prevents: 'With Deny, no command in the sandbox reaches the internet.',\n },\n maxCostUsd: {\n unlocks: 'Long runs on an API key, without watching the cost.',\n prevents: 'A run that costs more than the limit. It stops there.',\n },\n importForeignConfigs: {\n unlocks: 'The MCP servers, skills and commands of your other agents, with no copy to keep in sync.',\n prevents: 'Off, zidane never runs servers from files that it does not own.',\n },\n}\n","/**\n * Node-free half of provider usage: the wire types and the two presentation\n * helpers every surface needs to RENDER a snapshot.\n *\n * Split out of `provider-usage.ts` because that module reads\n * `credentials.json` and so cannot be reached from `zidane/chat/pure`. The\n * Electron renderer receives snapshots over IPC (main does the fetching) and\n * must draw them with the same rounding and the same \"which window bites\n * first\" rule as the TUI — a renderer that re-derived either would be the\n * duplication that let the TUI and GUI report different facts about one event.\n *\n * `provider-usage.ts` re-exports everything here, so importers keep a\n * single import path.\n */\n\nimport { formatResetDelay } from '../errors'\n\n/** One rate-limit window on a subscription (e.g. \"5h\", \"weekly\"). */\nexport interface ProviderUsageWindow {\n /** Stable id from the provider, used as a React / list key. */\n id: string\n /** Human label as the provider names it. */\n label: string\n /** 0..100, may be fractional. */\n usedPercent: number\n /** Epoch ms when the window resets, or `null` when the provider omits it. */\n resetsAt: number | null\n}\n\n/** Remaining credits for pay-as-you-go style providers. */\nexport interface ProviderUsageCredits {\n /** Credits left. */\n remaining: number\n /** Credits granted in total, or `null` when the provider reports no total. */\n total: number | null\n}\n\n/** Outcome of a usage probe: `ok`, `unauthorized` when the credential is missing or rejected, or `unavailable` on any other failure. */\nexport type ProviderUsageStatus = 'ok' | 'unauthorized' | 'unavailable'\n\n/** Usage of one credential of a provider, as probed at one moment. */\nexport interface ProviderUsageSnapshot {\n /** Registry key (`anthropic`, `openai`, …). */\n providerKey: string\n /** Display label for the provider. */\n label: string\n /**\n * Credentials-file key of the credential this snapshot was probed with. A\n * provider holding several OAuth accounts yields one snapshot per account;\n * this is what tells them apart (and the stable list key).\n */\n credentialKey: string\n /**\n * Stable id of that credential (`ProviderCredential.id`): unlike\n * {@link credentialKey} it does not move when another account is promoted,\n * so a session pinned to an account finds its snapshot by it. Absent for\n * an env-only key or an entry written before ids.\n */\n credentialId?: string\n /**\n * Account name for OAuth-backed snapshots (`Default`, `work`, …); `null` for\n * API-key probes. Surfaces show it only when the provider has more than one\n * snapshot, so a single-account provider stays quiet.\n */\n account: string | null\n /** True when this credential is the one requests use (the canonical slot). */\n activeCredential: boolean\n /** Outcome of the probe. */\n status: ProviderUsageStatus\n /** Plan name when the provider reports one. */\n plan: string | null\n /** Rate-limit windows with their usage. */\n windows: readonly ProviderUsageWindow[]\n /** Credit balance, or `null` when the provider reports none. */\n credits: ProviderUsageCredits | null\n /** Epoch milliseconds when the snapshot was taken. */\n fetchedAt: number\n /** Short failure reason when `status` is not `ok`. */\n error: string | null\n /** A short hint shown under the windows (GitHub's \"anonymous: run `gh auth login`\"). */\n note?: string\n}\n\n/**\n * Whether a snapshot should show its account name: only when another snapshot\n * in the same list belongs to the same provider. One account is the provider.\n *\n * @param snapshot - The snapshot to label.\n * @param all - Every snapshot on screen.\n */\nexport function showsAccount(snapshot: ProviderUsageSnapshot, all: readonly ProviderUsageSnapshot[]): boolean {\n return snapshot.account !== null && all.some(s => s !== snapshot && s.providerKey === snapshot.providerKey)\n}\n\n/**\n * The snapshot the footer indicator shows for a provider: the one probed with\n * the credential requests use — the session's pinned `account` when it has\n * one, else the provider's active credential — else the first reported.\n * `null` when none.\n *\n * @param all - Snapshots for every provider and account.\n * @param providerKey - Provider to pick a snapshot for.\n * @param account - Optional account id. Falls back to the active credential, then the first snapshot.\n */\nexport function activeSnapshotFor(all: readonly ProviderUsageSnapshot[], providerKey: string, account?: string | null): ProviderUsageSnapshot | null {\n const mine = all.filter(s => s.providerKey === providerKey)\n return (account ? mine.find(s => s.credentialId === account) : undefined) ?? mine.find(s => s.activeCredential) ?? mine[0] ?? null\n}\n\n/**\n * The window closest to its ceiling, which is the one that will bite first and\n * the only one a single-line indicator has room for. `null` when the snapshot\n * carries no windows.\n *\n * @param snapshot - The snapshot to inspect.\n */\nexport function mostConstrainedWindow(snapshot: ProviderUsageSnapshot): ProviderUsageWindow | null {\n let worst: ProviderUsageWindow | null = null\n for (const win of snapshot.windows) {\n if (!worst || win.usedPercent > worst.usedPercent)\n worst = win\n }\n return worst\n}\n\n/**\n * Percent for display: integers print bare, fractions keep one decimal (so a\n * status bar never reads `100%` for `99.9`).\n *\n * @param usedPercent - Percent used, from 0 to 100.\n */\nexport function formatUsagePercent(usedPercent: number): string {\n return Number.isInteger(usedPercent) ? String(usedPercent) : usedPercent.toFixed(1)\n}\n\n// ---------------------------------------------------------------------------\n// Presentation rules shared by the TUI panel / footer and the GUI panel /\n// footer. Kept here so the two surfaces cannot drift on thresholds or\n// rounding — a `1d` on one screen and `2d` on the other for the same window\n// would be reporting different facts about one subscription.\n// ---------------------------------------------------------------------------\n\n/**\n * Severity tone for a usage percent. `error` ≥ 85, `warn` ≥ 60, else `ok`.\n * Surfaces map tones to their own palette.\n */\nexport type UsageTone = 'ok' | 'warn' | 'error'\n\n/**\n * Maps a usage percent to a {@link UsageTone}.\n *\n * @param usedPercent - Percent used, from 0 to 100.\n */\nexport function usageTone(usedPercent: number): UsageTone {\n if (usedPercent >= 85)\n return 'error'\n if (usedPercent >= 60)\n return 'warn'\n return 'ok'\n}\n\n/**\n * Time to reset, worded like a provider error's (`resets in 1 h 45 min`,\n * see `formatResetDelay`), so the panel and a rate-limit line agree.\n * `null` when the provider reported no reset, `resetting` once it is due.\n *\n * @param resetsAt - Epoch milliseconds of the reset, or `null` when unknown.\n * @param now - Epoch milliseconds to measure from.\n */\nexport function resetLabel(resetsAt: number | null, now: number = Date.now()): string | null {\n if (resetsAt === null)\n return null\n const remaining = resetsAt - now\n return remaining > 0 ? `resets in ${formatResetDelay(remaining)}` : 'resetting'\n}\n\n/**\n * `updated 12s ago` / `updated 3m ago` for the newest snapshot in a list, so a\n * refresh that returns identical numbers is still visibly a refresh. `null`\n * when the list is empty.\n *\n * @param snapshots - Snapshots to age.\n * @param now - Epoch milliseconds to measure from.\n */\nexport function updatedLabel(snapshots: readonly ProviderUsageSnapshot[], now: number = Date.now()): string | null {\n let newest = -Infinity\n for (const s of snapshots)\n newest = Math.max(newest, s.fetchedAt)\n if (!Number.isFinite(newest))\n return null\n const seconds = Math.max(0, Math.floor((now - newest) / 1000))\n if (seconds < 60)\n return `updated ${seconds}s ago`\n return `updated ${Math.floor(seconds / 60)}m ago`\n}\n\n/**\n * Balances are dollars for OpenRouter and opaque units elsewhere.\n *\n * @param value - Credit amount. Values of 100 or more show no decimals, others show two.\n */\nexport function formatCredits(value: number): string {\n return value >= 100 ? value.toFixed(0) : value.toFixed(2)\n}\n\n/**\n * `20.00 / 25.00`, or just the remainder when no total is reported.\n *\n * @param credits - Credit balance to format.\n */\nexport function formatBalance(credits: ProviderUsageCredits): string {\n const remaining = formatCredits(credits.remaining)\n return credits.total === null ? remaining : `${remaining} / ${formatCredits(credits.total)}`\n}\n","/**\n * What a live run is doing, read from its transcript, so a surface can tell\n * \"the model is visibly working\" from \"nothing is moving\" and name it in\n * the live work row's header (\"Waiting for the model\", \"Retrying 2/3\"),\n * with how long it has lasted. Pure: the TUI and the desktop app read the\n * same answer, in the same words, from the same events.\n */\nimport type { StreamEvent } from './types'\n\n/**\n * What the transcript's tail shows during a run:\n * - `streaming`: a reply is streaming in.\n * - `thinking`: reasoning text is streaming in.\n * - `tool`: a tool call (a subagent, a question to the user, a command) is running.\n * - `waiting`: nothing live is on screen; the run is waiting on the model.\n */\nexport type RunTailActivity = 'streaming' | 'thinking' | 'tool' | 'waiting'\n\n/**\n * How long the tail must read `waiting` before a surface says so, so the\n * gap between a tool call and the next turn never flashes it. The TUI and\n * the desktop app use the same value.\n */\nexport const RUN_WAITING_DELAY_MS = 1500\n\n/** How far back the scan for an unanswered tool call goes; a run's live calls sit near its tail. */\nconst MAX_SCAN = 2000\n\n/**\n * Classify the tail of a live transcript. Only meaningful while a run is in\n * flight: an idle transcript reads as `waiting` too.\n *\n * Reasoning that is only whitespace counts as nothing (transcripts hide it),\n * and a tool call counts as running until its result arrives, back to the\n * run's prompt.\n *\n * @param events - Transcript events, oldest first.\n */\nexport function runTailActivity(events: readonly StreamEvent[]): RunTailActivity {\n const last = events.at(-1)\n if (last?.kind === 'markdown' && last.streaming)\n return 'streaming'\n if (last?.kind === 'thinking') {\n // Reasoning streams as one event per line: the lane is live when any line of it has text.\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]!\n if (event.kind !== 'thinking' || event.childId !== last.childId)\n break\n if (event.text.trim() !== '')\n return 'thinking'\n }\n }\n const answered = new Set<string>()\n const stop = Math.max(0, events.length - MAX_SCAN)\n for (let i = events.length - 1; i >= stop; i--) {\n const event = events[i]!\n if (event.kind === 'user-prompt' && event.childId === undefined)\n break\n if (event.kind === 'tool-result' && event.callId !== undefined)\n answered.add(event.callId)\n else if (event.kind === 'tool' && event.callId !== undefined && !answered.has(event.callId))\n return 'tool'\n }\n return 'waiting'\n}\n\n/** A provider retry in flight: the attempt, out of how many, and whose stream (`parent` or absent for the session's own, else a subagent id). */\nexport interface RunRetry {\n /** The attempt in flight, counting from 1. */\n attempt: number\n /** How many attempts the run allows. */\n max: number\n /** Whose stream is retried: `parent` (or absent) for the session's own, else a subagent id. */\n source?: string\n}\n\n/**\n * What the live work row's header says while a run is in flight:\n * - `retrying`: a provider call is being retried.\n * - `waiting`: nothing has moved on screen for {@link RUN_WAITING_DELAY_MS}; the run waits on the model.\n * - `working`: anything else. The surface names the work its usual way.\n */\nexport type RunFoldStatus\n = | { kind: 'retrying', retry: RunRetry }\n | { kind: 'waiting' }\n | { kind: 'working' }\n\n/**\n * What a transcript passes its live work row so the row can name the run's\n * status: the provider retry in flight, and whether nothing live is on\n * screen ({@link runTailActivity} reads `waiting`).\n */\nexport interface LiveRunStatus {\n /** The provider retry in flight, if any. */\n retry: RunRetry | null\n /** Nothing live is on screen: the run waits on the model. */\n waiting: boolean\n}\n\n/**\n * The status a surface times, as a key: one per retry attempt and one per\n * wait, `null` while nothing is timed. A surface restarts its clock when\n * the key changes.\n *\n * @param status - The live run's status.\n */\nexport function runStatusKey(status: LiveRunStatus): string | null {\n if (status.retry)\n return `retry:${status.retry.source ?? 'parent'}:${status.retry.attempt}`\n return status.waiting ? 'waiting' : null\n}\n\n/**\n * From when a status shows how long it has lasted. Shorter waits are\n * routine (a model's first token often takes a few seconds), so they show\n * no clock.\n */\nexport const RUN_STATUS_TIME_MS = 5000\n\n/**\n * The live work row's status: a retry wins, then a wait that has lasted\n * {@link RUN_WAITING_DELAY_MS}, else working.\n *\n * @param input - What the surface knows.\n * @param input.retry - The provider retry in flight, if any.\n * @param input.waitedMs - How long the tail has read `waiting`, or `null` while something moves.\n */\nexport function runFoldStatus({ retry, waitedMs }: { retry: RunRetry | null, waitedMs: number | null }): RunFoldStatus {\n if (retry)\n return { kind: 'retrying', retry }\n if (waitedMs !== null && waitedMs >= RUN_WAITING_DELAY_MS)\n return { kind: 'waiting' }\n return { kind: 'working' }\n}\n\n/** The header text while the run waits on the model. Both apps show these words. */\nexport const RUN_WAITING_LABEL = 'Waiting for the model'\n\n/**\n * The header text while a provider call is retried: `Retrying 2/3`, naming\n * the subagent when it is not the session's own stream. Both apps show these words.\n *\n * @param retry - The retry in flight.\n */\nexport function runRetryingLabel(retry: RunRetry): string {\n const source = retry.source && retry.source !== 'parent' ? ` in ${retry.source}` : ''\n return `Retrying ${retry.attempt}/${retry.max}${source}`\n}\n","/**\n * Spawn-tree ownership for transcript renderers (TUI partition, GUI\n * timeline). A nested worker's lifecycle markers name their spawner in\n * `spawn.parentChildId`; these helpers turn that into \"which worker does\n * this row belong under\", so a grandchild's rows nest inside its spawner\n * instead of reading as a separate worker of the main transcript.\n *\n * Generic over the row shape so the GUI's own `Row` type works too.\n */\n\n/**\n * What the helpers read off a transcript row / event.\n * The slice of a transcript row needed to build the spawn tree.\n */\nexport interface SpawnTreeRow {\n /** Row kind. Only `spawn-start` and `spawn-end` rows contribute parents. */\n kind: string\n /** Subagent the row belongs to. */\n childId?: string\n /** Spawn details. `parentChildId` names the spawning subagent. */\n spawn?: { parentChildId?: string }\n}\n\n/**\n * Worker id → the worker that spawned it, from nested spawn markers.\n *\n * @param rows - Transcript rows.\n */\nexport function spawnParents(rows: Iterable<SpawnTreeRow>): Map<string, string> {\n const parents = new Map<string, string>()\n for (const row of rows) {\n const parent = row.spawn?.parentChildId\n if (row.childId !== undefined && parent !== undefined && (row.kind === 'spawn-start' || row.kind === 'spawn-end'))\n parents.set(row.childId, parent)\n }\n return parents\n}\n\n/**\n * The worker `childId`'s rows belong under: its outermost ancestor that is\n * itself one of the `present` workers (the ones owning rows in this view).\n * A view that already re-based its owner's rows (a worker opened in a fold)\n * leaves that owner out of `present`, so the owner's direct children become\n * the lanes there. `childId` itself when no ancestor is present.\n *\n * @param childId - The subagent to place.\n * @param parents - Child-to-parent map from {@link spawnParents}.\n * @param present - Ids of subagents that have rows.\n */\nexport function spawnLane(childId: string, parents: ReadonlyMap<string, string>, present: ReadonlySet<string>): string {\n let lane = childId\n const seen = new Set([lane])\n for (let parent = parents.get(lane); parent !== undefined && present.has(parent) && !seen.has(parent); parent = parents.get(lane)) {\n lane = parent\n seen.add(lane)\n }\n return lane\n}\n\n/**\n * Lane resolver over one view's rows: precomputes the parent map and the\n * present-worker set, then maps a row's `childId` to its lane.\n *\n * @param rows - Transcript rows.\n */\nexport function spawnLaneResolver(rows: readonly SpawnTreeRow[]): (childId: string) => string {\n const parents = spawnParents(rows)\n if (parents.size === 0)\n return childId => childId\n const present = new Set<string>()\n for (const row of rows) {\n if (row.childId !== undefined)\n present.add(row.childId)\n }\n return childId => spawnLane(childId, parents, present)\n}\n","/**\n * Streaming finalize reducers + context-window math — pure transforms.\n *\n * No React, no node — so a browser-context renderer imports these via\n * `zidane/chat/pure`. The `useStreamBuffer` React hook + its smooth-stream\n * ticker live in `./streaming` (main barrel), which re-exports these.\n * A renderer owns its own ticker against the same reducers.\n */\n\nimport type { TurnUsage } from '../types'\nimport type { Owner, StreamEvent } from './types'\nimport { effectiveInputFromTurn } from '../stats'\nimport { chunkMarkdownForRender } from './markdown-segments'\n\nconst PARENT_OWNER: Owner = 'parent'\n\n/**\n * Returns the owner of an event: its `childId`, or `parent`.\n *\n * @param event - The event to inspect.\n */\nexport function ownerOf(event: StreamEvent): Owner {\n return event.childId ?? PARENT_OWNER\n}\n\n/** Is this event owned by a subagent (rather than the top-level agent)? */\nfunction isChildOwned(event: StreamEvent): boolean {\n return event.childId !== undefined || (event.depth ?? 0) > 0\n}\n\n/**\n * Index of the event `owner`'s next delta may coalesce into, or `-1` when the\n * owner has no open lane at the tail.\n *\n * Walks backwards over events owned by OTHER subagents — concurrent siblings\n * whose rows carry no ordering relation to this owner's output, and which a\n * per-owner drain interleaves at ~60Hz — and stops at the first event that is\n * either this owner's or a real ordering boundary (parent output, user\n * prompts, banners). The caller decides whether the event found is mergeable\n * for its kind. A tail-only check splits every concurrent child's message\n * into fragments braided with its siblings'.\n *\n * @param events - Transcript events in order.\n * @param owner - `parent` or the subagent's spawn id.\n */\nexport function mergeTargetIndex(events: readonly StreamEvent[], owner: Owner): number {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]!\n if (ownerOf(event) === owner)\n return i\n if (!isChildOwned(event))\n return -1\n }\n return -1\n}\n\n// ---------------------------------------------------------------------------\n// Streaming-delta merging — the ONE implementation every host shares (the\n// TUI's `useStreamBuffer`, the GUI renderer's stream store).\n//\n// Each event is owned by either the parent agent or a specific subagent\n// (`childId`). Same-owner same-kind text/thinking chunks coalesce into one\n// growing event so a renderer allocates one row per stream, not per delta.\n// The owner's event need not sit at the tail — see {@link mergeTargetIndex}.\n//\n// Generic over the host's event type: rows the reducers rebuild keep every\n// extra field (spread), and rows they mint carry only the base stream fields,\n// so `E`'s additional fields must be optional. `E` is never inferred from\n// `prev` (a bare `[]` would infer `never`): it defaults to `StreamEvent`, and\n// a host with a richer type names it (`appendMarkdownDelta<GuiStreamEvent>`).\n// ---------------------------------------------------------------------------\n\n/**\n * Default segment bound for a growing streaming markdown event. Coalescing\n * copies the ENTIRE accumulated string into fresh state on every drain tick,\n * so one long streamed message costs O(L²) aggregate — past this threshold\n * the event is split and the copy re-bounded. The split reuses\n * {@link chunkMarkdownForRender} (blank-line boundaries outside fences,\n * unsafe-continuation guard), so the finalized segments are byte-identical\n * to the chunks the renderer would have produced inside a single event, and\n * the one-row markdown/markdown margin stands in for the consumed blank line\n * exactly like the renderer's inter-chunk gap. When no safe boundary exists\n * (one giant fence/list) the event keeps growing until one arrives.\n */\nexport const STREAMING_MARKDOWN_SEGMENT_CHARS = 64 * 1024\n\n/**\n * Backoff for over-threshold events `chunkMarkdownForRender` could not\n * split (one giant fence/list): records the text length at the last failed\n * attempt, keyed on the streaming event object (re-keyed onto each tick's\n * replacement). Without it a single unsplittable segment re-runs the full\n * O(L) chunk walk on every drain tick. Growth is geometric (retry at +25%),\n * so total re-chunk work stays O(L) amortized.\n */\nconst unsplittableAtLength = new WeakMap<StreamEvent, number>()\nconst SEGMENT_SPLIT_RETRY_GROWTH = 1.25\n\n/**\n * Arrays the reducers below made by only growing the LAST event's text, mapped\n * to the first array of that chain: two arrays with the same root differ at\n * most in their last slot. Lets a renderer tell a streaming-tail tick from a\n * structural change in O(1) instead of comparing every event.\n */\nconst tailDeltaRoots = new WeakMap<readonly StreamEvent[], readonly StreamEvent[]>()\n\nfunction recordTailDelta(prev: readonly StreamEvent[], next: readonly StreamEvent[]): void {\n tailDeltaRoots.set(next, tailDeltaRoots.get(prev) ?? prev)\n}\n\n/**\n * The array `events` was grown from by tail-text-only merges\n * ({@link appendMarkdownDelta}, {@link appendThinkingLines}), or `events`\n * itself. Equal roots mean equal length and the same event objects in every\n * slot but the last.\n *\n * @param events - Transcript events in order.\n */\nexport function streamTailRoot(events: readonly StreamEvent[]): readonly StreamEvent[] {\n return tailDeltaRoots.get(events) ?? events\n}\n\n/** Options for {@link appendMarkdownDelta}. */\nexport interface MarkdownDeltaOptions {\n /**\n * Split threshold for a growing block (default\n * {@link STREAMING_MARKDOWN_SEGMENT_CHARS}). `Infinity` keeps one event per\n * streamed message — for a host whose reloaded transcript shows messages\n * whole and whose renderer chunks long text itself.\n */\n segmentChars?: number\n}\n\n/** Options for {@link appendThinkingLines}. */\nexport interface ThinkingDeltaOptions<E> {\n /** Decorate the first row of a newly opened thinking lane (e.g. stamp its start time). */\n onLaneOpen?: (row: E) => E\n}\n\n/**\n * Stamp owner (parent vs subagent) + depth + optional `turnId` onto a\n * freshly-minted event so consumers can identify the producer and the\n * source turn. Parent-owned events leave `childId` / `depth` off; `depth` is\n * also left off when the source never named one.\n */\nfunction tagEvent<E extends StreamEvent>(evt: StreamEvent, owner: Owner, depth: number | undefined, turnId: string | undefined): E {\n const withTurn = turnId ? { ...evt, turnId } : evt\n if (owner === PARENT_OWNER)\n return withTurn as E\n return { ...withTurn, childId: owner, ...(depth !== undefined ? { depth } : {}) } as E\n}\n\n/**\n * Coalesce a markdown delta into `owner`'s open streaming block, or open one.\n *\n * @param prev - Current transcript events.\n * @param delta - Streamed markdown text.\n * @param owner - `parent` or the subagent's spawn id.\n * @param depth - Nesting depth, or `undefined` when the source named none.\n * @param turnId - Turn the delta belongs to.\n * @param options - Split threshold for a growing block.\n */\nexport function appendMarkdownDelta<E extends StreamEvent = StreamEvent>(\n prev: NoInfer<E>[],\n delta: string,\n owner: Owner,\n depth: number | undefined,\n turnId: string | undefined,\n options: MarkdownDeltaOptions = {},\n): E[] {\n const segmentChars = options.segmentChars ?? STREAMING_MARKDOWN_SEGMENT_CHARS\n const at = mergeTargetIndex(prev, owner)\n const target = at >= 0 ? prev[at]! : undefined\n if (target && target.kind === 'markdown' && target.streaming) {\n const merged = target.text + delta\n const next = prev.slice()\n if (merged.length > segmentChars) {\n const lastFailed = unsplittableAtLength.get(target)\n if (lastFailed === undefined || merged.length > lastFailed * SEGMENT_SPLIT_RETRY_GROWTH) {\n const chunks = chunkMarkdownForRender(merged)\n if (chunks.length > 1) {\n // All segments inherit `target`'s tags (owner/depth/turnId) — they\n // are one coalesced stream, split for memory, not a new source.\n const segments = chunks.map((chunk, i) => i === chunks.length - 1\n ? { ...target, text: chunk }\n : { ...target, text: chunk, streaming: false })\n next.splice(at, 1, ...segments)\n return next\n }\n const grown = { ...target, text: merged }\n unsplittableAtLength.set(grown, merged.length)\n next[at] = grown\n if (at === prev.length - 1)\n recordTailDelta(prev, next)\n return next\n }\n // Within the backoff window — merge without re-chunking, carrying\n // the failure marker onto the replacement event.\n const grown = { ...target, text: merged }\n unsplittableAtLength.set(grown, lastFailed)\n next[at] = grown\n if (at === prev.length - 1)\n recordTailDelta(prev, next)\n return next\n }\n next[at] = { ...target, text: merged }\n if (at === prev.length - 1)\n recordTailDelta(prev, next)\n return next\n }\n return [\n ...prev,\n tagEvent<E>({ kind: 'markdown', text: delta, streaming: true }, owner, depth, turnId),\n ]\n}\n\n/**\n * Coalesce a thinking delta into `owner`'s open lane, one row per line.\n *\n * @param prev - Current transcript events.\n * @param delta - Streamed thinking text. Each line becomes one row.\n * @param owner - `parent` or the subagent's spawn id.\n * @param depth - Nesting depth, or `undefined` when the source named none.\n * @param turnId - Turn the delta belongs to.\n * @param options - Hook for decorating the first row of a new lane.\n */\nexport function appendThinkingLines<E extends StreamEvent = StreamEvent>(\n prev: NoInfer<E>[],\n delta: string,\n owner: Owner,\n depth: number | undefined,\n turnId: string | undefined,\n options: ThinkingDeltaOptions<E> = {},\n): E[] {\n const lines = delta.split('\\n')\n const at = mergeTargetIndex(prev, owner)\n const target = at >= 0 ? prev[at]! : undefined\n const row = (text: string) => tagEvent<E>({ kind: 'thinking', text }, owner, depth, turnId)\n\n // Extra lines land right after the merged row rather than at the tail so\n // the owner's thinking lane stays contiguous while siblings stream. A new\n // turn's reasoning starts its own row: merged, its first line would carry\n // the previous turn's id (and go wherever that row goes).\n if (target && target.kind === 'thinking' && (turnId === undefined || target.turnId === undefined || target.turnId === turnId)) {\n const next = prev.slice()\n next[at] = { ...target, text: target.text + lines[0] }\n if (lines.length > 1)\n next.splice(at + 1, 0, ...lines.slice(1).map(row))\n else if (at === prev.length - 1)\n recordTailDelta(prev, next)\n return next\n }\n\n const result = [...prev]\n if (lines[0] || lines.length > 1) {\n const first = row(lines[0]!)\n result.push(options.onLaneOpen ? options.onLaneOpen(first) : first)\n }\n\n for (let i = 1; i < lines.length; i++)\n result.push(row(lines[i]!))\n\n return result\n}\n\n/**\n * Drop one owner's reasoning lane for a turn: the reasoning of a provider\n * attempt the loop abandoned (a stalled stream retried, or moved to the next\n * model), which the next attempt replaces and the saved turn never holds.\n * Returns the same array when there is nothing to drop.\n *\n * @param events - Transcript events in order.\n * @param owner - Whose lane: `'parent'` or a subagent id.\n * @param turnId - The turn whose reasoning goes. Rows without a turn id are kept.\n */\nexport function discardThinking<E extends StreamEvent = StreamEvent>(events: E[], owner: Owner, turnId: string): E[] {\n const kept = events.filter(e => !(e.kind === 'thinking' && e.turnId === turnId && ownerOf(e) === owner))\n return kept.length === events.length ? events : kept\n}\n\n/**\n * Flip any trailing streaming markdown blocks (any owner) to finalized.\n *\n * @param events - Transcript events in order.\n */\nexport function finalizeStreamingMarkdown(events: StreamEvent[]): StreamEvent[] {\n let changed = false\n const next = events.map((e) => {\n if (e.kind === 'markdown' && e.streaming) {\n changed = true\n return { ...e, streaming: false }\n }\n return e\n })\n return changed ? next : events\n}\n\n/**\n * Flip the trailing streaming markdown block for one specific owner.\n *\n * @param events - Transcript events in order.\n * @param owner - `parent` or the subagent's spawn id.\n */\nexport function finalizeStreamingMarkdownForOwner(events: StreamEvent[], owner: Owner): StreamEvent[] {\n for (let i = events.length - 1; i >= 0; i--) {\n const e = events[i]\n if (e.kind !== 'markdown')\n continue\n if (!e.streaming)\n continue\n if (ownerOf(e) !== owner)\n continue\n const next = events.slice()\n next[i] = { ...e, streaming: false }\n return next\n }\n return events\n}\n\n/**\n * Effective context size for a single turn.\n *\n * `usage.input` is misleading on its own when prompt caching is active: providers\n * (Anthropic, OpenRouter→Anthropic, Gemini) report `input` as the *new uncached*\n * tokens only — the cached prefix shows up in `cacheRead`, and newly-cached\n * tokens in `cacheCreation`. The model still saw all three buckets, so the real\n * context-window utilization is their sum.\n *\n * Non-caching providers leave `cacheRead`/`cacheCreation` undefined, so this\n * collapses to plain `input` for them.\n *\n * @param usage - Token usage of the turn, if recorded.\n */\nexport function turnContextSize(usage: TurnUsage | undefined): number {\n return effectiveInputFromTurn(usage)\n}\n\n// ---------------------------------------------------------------------------\n// Transcript memory cap\n// ---------------------------------------------------------------------------\n\n/**\n * Display-layer transcript bounds. Each rendered event holds live React\n * fibers + OpenTUI renderables + native text buffers even when scrolled\n * off-screen — measured at roughly 0.13 MB RSS per markdown-heavy event —\n * so an uncapped multi-thousand-event session (a normal working day with\n * tool calls) climbs into the hundreds of MB and eventually OOM/thrash.\n *\n * The cap bounds ONLY what is materialized on screen: session turns on\n * disk are complete, and switching sessions / re-activating replays the\n * most recent window again. Trimming happens at TURN boundaries so a\n * turn's rows are never orphaned, and re-caps fold into one cumulative\n * marker rather than stacking markers.\n */\nexport const MAX_TRANSCRIPT_EVENTS = 1_500\n/** Post-trim size — the hysteresis gap keeps re-trims O(rare), not per-append. */\nexport const TRANSCRIPT_TRIM_TO_EVENTS = 1_200\n/**\n * A trim keeps at least this many of the user's own prompts when it can:\n * one long agent run (thousands of tool and subagent events, folded into a\n * single row) would otherwise leave a transcript that opens on one exchange.\n */\nexport const TRANSCRIPT_KEEP_PROMPTS = 10\n\n/**\n * What one event costs the display, in rows, from 0 to 1. A client that\n * folds events away (the TUI's compact density draws a run's hundreds of\n * tool calls as one line) weighs them less, so its caps and pages count\n * what it lays out. Without one, every event is a row.\n */\nexport type TranscriptWeight = (event: StreamEvent) => number\n\n/**\n * Raw events a weighted transcript never keeps past, whatever they weigh:\n * folded events still cost memory and every pass over the transcript.\n */\nexport const MAX_WEIGHTED_TRANSCRIPT_EVENTS = 12_000\n\nfunction weightBetween(events: readonly StreamEvent[], from: number, to: number, weigh: TranscriptWeight | undefined): number {\n if (!weigh)\n return to - from\n let weight = 0\n for (let i = from; i < to; i++)\n weight += weigh(events[i]!)\n return weight\n}\n\n/** Over `max` rows or, weighted, over the raw ceiling. Weights are at most 1, so a short transcript is never over. */\nfunction overCap(events: readonly StreamEvent[], max: number, weigh: TranscriptWeight | undefined): boolean {\n if (events.length <= max)\n return false\n return !weigh || events.length > MAX_WEIGHTED_TRANSCRIPT_EVENTS || weightBetween(events, 0, events.length, weigh) > max\n}\n\n/**\n * Where the part of `events` ending at `end` that weighs at most `budget`\n * starts: never before `floor`, and holding at most `ceiling` events.\n */\nfunction startForWeight(events: readonly StreamEvent[], end: number, floor: number, budget: number, weigh: TranscriptWeight | undefined, ceiling = Number.POSITIVE_INFINITY): number {\n if (!weigh)\n return Math.max(floor, end - Math.min(budget, ceiling))\n let weight = 0\n let i = end\n while (i > floor && end - i < ceiling) {\n const next = weight + weigh(events[i - 1]!)\n if (next > budget)\n break\n weight = next\n i--\n }\n return i\n}\n\n/**\n * The cumulative count rides IN the marker's display text and is parsed\n * back out on re-cap — deliberately text-as-protocol rather than a new\n * StreamEvent kind or field: 'info' renders everywhere for free (no\n * renderer changes, no persistence shape change — markers are display\n * state and never persisted), and producer + consumer live side by\n * side in this file. Same precedent as task-notification re-synthesis.\n * If markers ever need richer data, THAT is the moment for a dedicated\n * event kind.\n */\nconst HIDDEN_MARKER_RE = /^… (\\d+) earlier transcript items hidden/\n\n/**\n * Events a cap hid, read from the marker at the head of `events`. `0` when the\n * transcript does not start with one.\n *\n * @param events - Transcript events in order.\n */\nexport function hiddenEarlierTranscriptCount(events: readonly StreamEvent[]): number {\n const first = events[0]\n return first?.kind === 'info' ? Number(HIDDEN_MARKER_RE.exec(first.text)?.[1] ?? 0) : 0\n}\n\n/** The \"… N earlier transcript items hidden\" marker a cap puts in front. */\nexport function isEarlierHiddenMarker(event: StreamEvent): boolean {\n return event.kind === 'info' && event.notice === undefined && HIDDEN_MARKER_RE.test(event.text)\n}\n\nfunction hiddenMarkerEvent(count: number): StreamEvent {\n // Copy stays host-neutral: this helper is shared SDK surface, and only\n // the TUI wires a scroll-to-load affordance — promising \"scroll up\" on\n // hosts without one would be a false affordance.\n return {\n kind: 'info',\n text: `… ${count} earlier transcript items hidden to bound memory. The full history stays in the session.`,\n }\n}\n\n/**\n * Swap one turn's rows for its rebuilt ones, in place; `null` when the turn\n * is not on show.\n */\nexport function replaceTranscriptTurnEvents(\n displayed: readonly StreamEvent[],\n rebuilt: readonly StreamEvent[],\n turnId: string,\n): StreamEvent[] | null {\n const replacements = rebuilt.filter(event => event.turnId === turnId)\n let inserted = false\n const patched = displayed.flatMap((event) => {\n if (event.turnId !== turnId)\n return [event]\n if (inserted)\n return []\n inserted = true\n return replacements\n })\n return inserted ? patched : null\n}\n\n/**\n * A run in the transcript: everything from one of the user's own prompts\n * up to the next one. Revealing and capping move in whole runs, so the top\n * of the transcript always opens on a prompt, not halfway through what the\n * agent did for it.\n */\nfunction isRunStart(e: StreamEvent | undefined): boolean {\n return e !== undefined && isTopLevelPrompt(e)\n}\n\n/** A run longer than this many reveal pages on its own is revealed in pieces of that size. */\nconst WHOLE_RUN_REVEAL_PAGES = 5\n\n/**\n * Reveal the earlier history while keeping everything on show: the whole\n * run right before it, and the runs before that while they fit `pageSize`\n * events together (several small runs at once, never part of one). A run\n * longer than {@link WHOLE_RUN_REVEAL_PAGES} pages on its own comes in\n * pieces that size, cut at a turn boundary so a tool call keeps its result.\n * The default transcript is memory-bounded; memory grows only when the user\n * deliberately scrolls into the marker. With `weigh`, pages count rows.\n */\nexport function revealEarlierTranscriptEvents(\n all: readonly StreamEvent[],\n displayed: readonly StreamEvent[],\n pageSize: number = 600,\n weigh?: TranscriptWeight,\n): StreamEvent[] {\n const hidden = hiddenEarlierTranscriptCount(displayed)\n if (hidden <= 0)\n return displayed as StreamEvent[]\n // Tail preserved by reference — it may include transient live rows that\n // are never persisted (task-notification banners, warn lines).\n const tail = displayed.slice(1)\n // Seam: where the visible tail begins inside the re-materialized history.\n // The marker count was minted against the LIVE display array — which\n // holds those transient rows — so it is NOT a reliable index into `all`.\n // Anchor structurally on the tail's first turn instead (the cap cuts at\n // turn boundaries and never ON a turn-less row, so the tail's head IS\n // that turn's first event); the count is only a fallback for tails\n // without any turn-tagged event.\n const anchorTurnId = tail.find(e => e.turnId !== undefined)?.turnId\n const anchorIndex = anchorTurnId !== undefined ? all.findIndex(e => e.turnId === anchorTurnId) : -1\n const seam = anchorIndex >= 0 ? anchorIndex : Math.min(hidden, all.length)\n if (seam <= 0)\n return displayed as StreamEvent[]\n const page = Math.max(1, pageSize)\n /** Where the run holding `all[end - 1]` starts (0 when no prompt precedes it). */\n const runStart = (end: number): number => {\n let i = end - 1\n while (i > 0 && !isRunStart(all[i]))\n i--\n return i\n }\n let from = runStart(seam)\n let weight = weightBetween(all, from, seam, weigh)\n if (weight > page * WHOLE_RUN_REVEAL_PAGES) {\n // One run too long to bring whole: its last part, from a turn boundary.\n from = startForWeight(all, seam, 0, page * WHOLE_RUN_REVEAL_PAGES, weigh)\n while (from < seam - 1 && all[from]?.turnId !== undefined && all[from]?.turnId === all[from - 1]?.turnId)\n from++\n }\n else {\n while (from > 0) {\n const previous = runStart(from)\n const more = weightBetween(all, previous, from, weigh)\n if (weight + more > page)\n break\n weight += more\n from = previous\n }\n }\n const out = [...all.slice(from, seam), ...tail]\n if (from > 0)\n out.unshift(hiddenMarkerEvent(from))\n return out\n}\n\n/** The user's own prompt, not a subagent's. */\nfunction isTopLevelPrompt(e: StreamEvent): boolean {\n return e.kind === 'user-prompt' && !e.depth && (!e.childId || e.childId === 'parent')\n}\n\n/** Index of the `n`-th last top-level user prompt at or after `from` (the earliest one when fewer); -1 with none. */\nfunction nthLastPrompt(events: readonly StreamEvent[], n: number, from: number): number {\n let seen = 0\n let at = -1\n for (let i = events.length - 1; i >= from; i--) {\n const e = events[i]!\n if (isTopLevelPrompt(e)) {\n at = i\n if (++seen >= n)\n break\n }\n }\n return at\n}\n\n/**\n * A transcript's end, with `earlier` events of the whole replay before it:\n * the hidden-count marker in front, as a cap would have left it.\n */\nexport function withEarlierHidden(events: StreamEvent[], earlier: number): StreamEvent[] {\n return earlier > 0 ? [hiddenMarkerEvent(earlier), ...events] : events\n}\n\n/**\n * Whether the end of a transcript (from a turn boundary) is enough for\n * {@link capTranscriptEvents} at the default bounds (or at `max`, with the\n * default trim): capping it behind its hidden-count marker cuts exactly\n * where capping the whole transcript would. Over the cap, and holding the\n * prompts the cut reaches back to.\n */\nexport function coversTranscriptCap(events: readonly StreamEvent[], weigh?: TranscriptWeight, max: number = MAX_TRANSCRIPT_EVENTS): boolean {\n if (!overCap(events, max, weigh))\n return false\n let prompts = 0\n for (const e of events) {\n if (isTopLevelPrompt(e) && ++prompts >= TRANSCRIPT_KEEP_PROMPTS)\n return true\n }\n return false\n}\n\n/**\n * Bound a transcript event array for display. Identity below the cap\n * (no re-render churn on the hot append path); above it, drops the\n * oldest events down to {@link TRANSCRIPT_TRIM_TO_EVENTS} — extended to\n * the next turn boundary — and prepends a cumulative hidden-count\n * marker. Callers: the stream buffer's drain commit and every\n * `eventsFromTurns` replay site.\n *\n * @param events - Transcript events in order.\n * @param max - Length above which the transcript is capped.\n * @param trimTo - Length to trim to. Clamped to 80% of `max`.\n * @param weigh - Count rows instead of events ({@link TranscriptWeight}); the\n * raw events then stay under {@link MAX_WEIGHTED_TRANSCRIPT_EVENTS}.\n */\nexport function capTranscriptEvents(\n events: StreamEvent[],\n max: number = MAX_TRANSCRIPT_EVENTS,\n trimTo: number = TRANSCRIPT_TRIM_TO_EVENTS,\n weigh?: TranscriptWeight,\n): StreamEvent[] {\n if (!overCap(events, max, weigh))\n return events\n // A custom `max` below the default `trimTo` must still cap: clamp the\n // keep-size to 80% of the cap so the hysteresis gap scales with it.\n // (Without this, `maxTranscriptEvents: 500` would compute a cut point\n // before the array even starts and silently return it uncapped.)\n const keep = Math.max(1, Math.min(trimTo, Math.floor(max * 0.8)))\n\n // Fold a prior marker into the cumulative count instead of stacking.\n let previouslyHidden = 0\n let start = 0\n const first = events[0]\n if (first && first.kind === 'info') {\n const match = HIDDEN_MARKER_RE.exec(first.text)\n if (match) {\n previouslyHidden = Number(match[1]) || 0\n start = 1\n }\n }\n\n // Aim to keep the newest `trimTo` events, then extend the cut forward\n // to the next turn boundary so no turn is ever split mid-rows. Events\n // without a turnId (separators, banners) are boundaries themselves.\n // Weighted, the raw events keep the same hysteresis under their ceiling.\n const ceiling = weigh ? MAX_WEIGHTED_TRANSCRIPT_EVENTS : Number.POSITIVE_INFINITY\n let cut = startForWeight(events, events.length, start, keep, weigh, Math.floor(ceiling * 0.8))\n if (cut <= start)\n return events\n // Reach back to the user's last few prompts, up to halfway to the cap:\n // the rest of the gap keeps re-trims rare on the append path.\n const promptAt = nthLastPrompt(events, TRANSCRIPT_KEEP_PROMPTS, start)\n if (promptAt >= 0 && promptAt < cut)\n cut = Math.max(promptAt, startForWeight(events, events.length, start, Math.floor((max + keep) / 2), weigh, ceiling), start + 1)\n const turnAtCut = (i: number): string | undefined => events[i]?.turnId\n // Keep whole runs: start what stays on the next prompt (a run that is all\n // of the tail on its own stays, cut at a turn boundary instead).\n if (!isRunStart(events[cut])) {\n let next = cut + 1\n while (next < events.length && !isRunStart(events[next]))\n next++\n if (next < events.length)\n cut = next\n }\n while (cut < events.length) {\n const turn = turnAtCut(cut)\n if (turn === undefined || turn !== turnAtCut(cut - 1))\n break\n cut++\n }\n // Never cut ON a turn-less row (spawn markers, banners): the reveal seam\n // anchors on the tail's first turn-tagged event, so a turn-less tail head\n // would be re-included from the re-materialized history and render twice\n // (worst case an unpaired spawn-start that reads as a phantom live child).\n // Turn-less rows are boundaries themselves, so skipping them keeps the\n // no-split-turn invariant intact.\n while (cut < events.length && turnAtCut(cut) === undefined)\n cut++\n if (cut >= events.length)\n cut = events.length - 1 // pathological turn-less/single-turn flood: keep the last event\n\n const hidden = previouslyHidden + (cut - start)\n return [hiddenMarkerEvent(hidden), ...events.slice(cut)]\n}\n\n/**\n * Most events one {@link stepTranscriptCap} drops. A cap that has thousands\n * of rows to cut (the history a reveal brought in, once the viewport is back\n * at the bottom) unmounts them over several commits of this size instead of\n * freezing one frame on all of them.\n */\nexport const TRANSCRIPT_TRIM_STEP_EVENTS = 300\n\n/**\n * {@link capTranscriptEvents}, at most `step` events (extended to the next\n * turn boundary) at a time. Applied again and again it trims until the\n * transcript is back within `max`, then returns `events` itself; it stops\n * there rather than at the cap's hysteresis floor, so the end keeps at least\n * what one full cap keeps. Each cut keeps the cap's seams (no split turn,\n * never starting on a turn-less row), so a reveal anchors on it like on a\n * full cap.\n *\n * @param events - The transcript, possibly already headed by a hidden-rows marker.\n * @param max - Cap to trim down to.\n * @param step - Most events (or weight, with `weigh`) to drop in this call.\n * @param weigh - How many rows an event counts for; each counts 1 when omitted.\n */\nexport function stepTranscriptCap(\n events: StreamEvent[],\n max: number = MAX_TRANSCRIPT_EVENTS,\n step: number = TRANSCRIPT_TRIM_STEP_EVENTS,\n weigh?: TranscriptWeight,\n): StreamEvent[] {\n const capped = capTranscriptEvents(events, max, undefined, weigh)\n if (capped === events)\n return events\n const hidden = hiddenEarlierTranscriptCount(events)\n const start = hidden > 0 ? 1 : 0\n // Where the full cap's kept tail starts in `events`.\n const finalCut = events.length - (capped.length - 1)\n // A step's worth of rows from the front (weighted: folded events go many at a time).\n let cut = start + 1\n for (let weight = weigh ? weigh(events[start]!) : 1; cut < finalCut && weight < Math.max(1, step); cut++)\n weight += weigh ? weigh(events[cut]!) : 1\n if (cut >= finalCut)\n return capped\n while (cut < finalCut && events[cut]!.turnId !== undefined && events[cut]!.turnId === events[cut - 1]!.turnId)\n cut++\n while (cut < finalCut && events[cut]!.turnId === undefined)\n cut++\n if (cut >= finalCut)\n return capped\n return [hiddenMarkerEvent(hidden + (cut - start)), ...events.slice(cut)]\n}\n\n/*\n * Smooth-streaming display rate, in characters per second: the one pace the\n * TUI (`useStreamBuffer`) and the desktop app (`@zidane/ui` smooth-stream)\n * reveal streamed reply text at.\n *\n * Three-segment continuous ramp (no step functions, no cliff) so the\n * typewriter cadence never visibly \"jumps\" mid-stream:\n *\n * - SMOOTH_BASE_CPS: calm-state floor. ~200 CPS is a fast typist's pace;\n * comfortably readable without feeling like a deliberate performance.\n * - SMOOTH_BURST_CPS at SMOOTH_BURST_BACKLOG_CHARS: moderate catch-up speed\n * once the buffer is one paragraph behind the provider.\n * - SMOOTH_MAX_CPS at SMOOTH_MAX_BACKLOG_CHARS: bounded ceiling. Past this we\n * plateau at max-cps rather than instant-draining; max-cps is already well\n * above any human reading rate so even a 10K-char dump completes in ~2.5s\n * of fast typewriter instead of a single-frame teleport.\n *\n * There is no instant-drain failsafe: an instant drain would be a step from\n * ~10 chars/frame to \"everything in one frame\", the worst jump in the smooth\n * pipeline. The ramp keeps latency bounded instead, since CPS keeps growing\n * with backlog up to the cap.\n */\n/** Smooth reveal rate (chars a second) while almost nothing waits. */\nexport const SMOOTH_BASE_CPS = 200\nconst SMOOTH_BURST_CPS = 600\nconst SMOOTH_BURST_BACKLOG_CHARS = 400\n/** Smooth reveal rate (chars a second) once the backlog reaches {@link SMOOTH_MAX_BACKLOG_CHARS}. */\nexport const SMOOTH_MAX_CPS = 4000\n/** Backlog (chars) at and past which the smooth reveal runs at {@link SMOOTH_MAX_CPS}. */\nexport const SMOOTH_MAX_BACKLOG_CHARS = 4000\n\n/**\n * Target chars-per-second for the next smooth-mode tick given the\n * current bucket backlog. Two linear segments (base→burst over the\n * first 400 chars, burst→max over the rest of the ramp) so the function\n * is continuous everywhere and plateaus (rather than cliffs) once backlog\n * passes {@link SMOOTH_MAX_BACKLOG_CHARS}.\n *\n * @param backlog - Chars waiting to reveal.\n */\nexport function smoothCpsForBacklog(backlog: number): number {\n if (backlog <= 0)\n return 0\n if (backlog >= SMOOTH_MAX_BACKLOG_CHARS)\n return SMOOTH_MAX_CPS\n if (backlog <= SMOOTH_BURST_BACKLOG_CHARS) {\n const t = backlog / SMOOTH_BURST_BACKLOG_CHARS\n return SMOOTH_BASE_CPS + t * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS)\n }\n const t = (backlog - SMOOTH_BURST_BACKLOG_CHARS)\n / (SMOOTH_MAX_BACKLOG_CHARS - SMOOTH_BURST_BACKLOG_CHARS)\n return SMOOTH_BURST_CPS + t * (SMOOTH_MAX_CPS - SMOOTH_BURST_CPS)\n}\n\n/**\n * Number of characters to drain on the next smooth-mode tick + the\n * fractional remainder to carry into the next tick.\n *\n * Combining the CPS curve with a fractional accumulator means the\n * effective draining rate matches the target CPS exactly. Rounding up\n * on every tick (`Math.ceil(cps * dt)`) would give 4 chars/tick at\n * 200 CPS / 16ms (= 250 CPS effective), a 25 % speed-up, and visible\n * step transitions (4 → 5 → 7 → 8 → 10 as backlog grew) that read as\n * the typewriter cadence jumping.\n *\n * @param backlog - Chars waiting to reveal.\n * @param carry - The fraction the previous tick left over.\n * @param dtMs - Milliseconds since the previous tick.\n */\nexport function smoothCharsForTick(\n backlog: number,\n carry: number,\n dtMs: number,\n): { take: number, carry: number } {\n if (backlog <= 0)\n return { take: 0, carry: 0 }\n const cps = smoothCpsForBacklog(backlog)\n const want = cps * dtMs / 1000 + carry\n const take = Math.floor(want)\n if (take <= 0)\n return { take: 0, carry: want }\n if (take >= backlog) {\n // Drained the bucket — drop the leftover. Holding it across a\n // bucket boundary would invent a head-start for the next stream.\n return { take: backlog, carry: 0 }\n }\n // Don't clamp `take` to 1: with `dtMs * cps / 1000 < 1`, the carry\n // accumulates over the next tick(s) and the char lands when math\n // says it should. The ticker stays alive because the bucket still\n // has content, so the next tick fires regardless.\n return { take, carry: want - take }\n}\n\n/**\n * Slice `n` chars off the front of `buf` without splitting a UTF-16\n * surrogate pair. Most LLM text is ASCII and never trips this; the guard\n * matters for emoji / extended planes where halving the pair would emit\n * an isolated half-character.\n *\n * @param buf - The text to cut.\n * @param n - How many code units to take; `n <= 0` takes nothing.\n */\nexport function takeChars(buf: string, n: number): { taken: string, rest: string } {\n if (buf.length <= n)\n return { taken: buf, rest: '' }\n if (n <= 0)\n return { taken: '', rest: buf }\n let end = n\n const last = buf.charCodeAt(end - 1)\n // High surrogate at the slice boundary → pull the following low\n // surrogate in too. Going one char over budget on a single tick is\n // strictly better than emitting half a code point.\n if (last >= 0xD800 && last <= 0xDBFF && end < buf.length)\n end++\n return { taken: buf.slice(0, end), rest: buf.slice(end) }\n}\n","/**\n * Per-tool display metadata + one-line formatters consumed by any\n * surface that renders a `tool` event in `'formatted'` mode (see\n * `Settings.toolCallDisplay`).\n *\n * Each native tool gets a curated entry — a `displayName` verb that\n * reads in sentence case (e.g. \"Read\", \"Shell\") and a `format` callback\n * that pulls the most informative bits out of the model's raw input to\n * a single scannable line. Unknown tools (MCP servers, host-added\n * tools, future zidane additions) fall back to {@link formatToolCall}\n * returning `null` — the renderer then shows a minimal `↳ <name>` line.\n *\n * Renderer-agnostic: returns plain data (`{ target, meta }`) so the\n * TUI's React/OpenTUI surface and any future GUI consumer can paint\n * the same shape in their own style. Lives in `zidane/chat` because\n * it has no rendering concerns; the TUI just consumes it.\n */\n\nimport { utf8ByteLength } from '../compact/utils'\nimport { formatBytes } from '../format-bytes'\nimport { readFileInputPaths } from '../tools/read-file-targets'\nimport { previewLine } from './format'\nimport { shortSessionId } from './orchestration'\n\n/** The pieces of a one-line tool call summary. */\nexport interface ToolFormatLine {\n /**\n * Primary target — typically a path, command, pattern, or\n * task description. Renderer paints this in the model accent color\n * so the eye lands on it first.\n */\n target?: string\n /**\n * Secondary annotations shown after the target, each as its own\n * segment. Use for line ranges (`L10-25`), limits, flags,\n * or any short suffix that adds context without bloating the line.\n */\n meta?: readonly string[]\n /**\n * Optional SECOND line — the payload behind the action (a prompt sent to\n * another session). Renderers paint it dimmed under the header and clamp\n * it (two lines in the GUI, one terminal row in the TUI); it is never\n * squeezed into the header line, which stays single-line.\n */\n detail?: string\n /**\n * The session this call targets, when the tool addresses one. `target`\n * carries the short id as a fallback; a renderer with the session list in\n * scope shows the session's TITLE instead.\n */\n sessionId?: string\n}\n\n/** How one tool is labeled and summarized in the transcript. */\nexport interface ToolDisplayMeta {\n /**\n * Sentence-case display verb (e.g. `Read`, `Shell`, `Edit`). When the\n * label depends on an input field (e.g. `skills_use`'s\n * `mode: 'activate' | 'deactivate'` → `Enable` / `Disable`), supply\n * a function instead and read the field defensively. The function\n * form is called whenever {@link displayNameFor} has the call's\n * input in scope; callers without input fall back to the function's\n * `input: undefined` branch, which should return a stable default.\n */\n displayName: string | ((input: Record<string, unknown> | undefined) => string)\n /**\n * Pull a {@link ToolFormatLine} out of the raw model input. Returns\n * `null` when the shape isn't what the tool expects (typed defensively\n * — we never want a malformed call to crash the transcript).\n */\n format: (input: Record<string, unknown>) => ToolFormatLine | null\n}\n\n// ---------------------------------------------------------------------------\n// Tool registry\n// ---------------------------------------------------------------------------\n\nconst SESSIONS_VERB_LABEL: Readonly<Record<string, string>> = {\n create: 'Create session',\n send: 'Send to session',\n steer: 'Steer session',\n cancel: 'Cancel session',\n read: 'Read session',\n transcript: 'Session transcript',\n list: 'List sessions',\n}\n\n/** Display metadata for the built-in tools, keyed by tool name. */\nexport const TOOL_DISPLAY: Readonly<Record<string, ToolDisplayMeta>> = {\n // ---- Pure reads ----\n read_file: {\n displayName: 'Read',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path) {\n // `paths` batch: first file as the target, the rest as a count.\n const paths = readFileInputPaths(input)\n if (paths.length === 0)\n return null\n return { target: paths[0], meta: paths.length > 1 ? [`+${paths.length - 1} more`] : [] }\n }\n const meta: string[] = []\n const offset = numberField(input, 'offset')\n const limit = numberField(input, 'limit')\n if (offset !== undefined && limit !== undefined && limit > 0)\n meta.push(`L${offset}–${offset + limit - 1}`)\n else if (offset !== undefined)\n meta.push(`from L${offset}`)\n else if (limit !== undefined && limit > 0)\n meta.push(`${limit} lines`)\n return { target: path, meta }\n },\n },\n list_files: {\n displayName: 'List',\n format: (input) => {\n const path = stringField(input, 'path') ?? '.'\n return { target: path }\n },\n },\n glob: {\n displayName: 'Glob',\n format: (input) => {\n const pattern = stringField(input, 'pattern')\n if (!pattern)\n return null\n const meta: string[] = []\n const limit = numberField(input, 'limit')\n if (limit !== undefined)\n meta.push(`limit ${limit}`)\n return { target: pattern, meta }\n },\n },\n grep: {\n displayName: 'Grep',\n format: (input) => {\n const pattern = stringField(input, 'pattern')\n if (!pattern)\n return null\n const target = `/${pattern}/`\n const meta: string[] = []\n const path = stringField(input, 'path')\n if (path && path !== '.')\n meta.push(`in ${path}`)\n const glob = stringField(input, 'glob')\n if (glob)\n meta.push(glob)\n const type = stringField(input, 'type')\n if (type)\n meta.push(`type:${type}`)\n if (input['-i'] === true)\n meta.push('case-insensitive')\n const mode = stringField(input, 'output_mode')\n if (mode && mode !== 'files_with_matches')\n meta.push(mode)\n return { target, meta }\n },\n },\n\n // ---- Shell ----\n shell: {\n // Verb switches when the model dispatches a background task — same\n // pattern `skills_use` uses for activate/deactivate. The transcript\n // reads as `↳ Shell (background): npm run dev` so the user can spot\n // backgrounded invocations at a glance without reading the args.\n //\n // With the model's `description` (\"Run the GUI typecheck\"), that is the\n // label, as for Codemode: it says what the call does, and the command\n // itself is the call's (highlighted) input. Without one, the command is\n // the target.\n displayName: (input) => {\n const label = descriptionLabel(input)\n if (label)\n return label\n return input?.run_in_background === true ? 'Shell (background)' : 'Shell'\n },\n format: (input) => {\n const command = stringField(input, 'command')\n if (!command)\n return null\n if (stringField(input, 'description')?.trim())\n return input.run_in_background === true ? { meta: ['background'] } : {}\n return { target: previewLine(command, 200) }\n },\n },\n shell_kill: {\n displayName: 'Kill task',\n format: (input) => {\n const taskId = stringField(input, 'task_id')\n if (!taskId)\n return null\n return { target: taskId }\n },\n },\n wait_task: {\n displayName: 'Wait for task',\n format: (input) => {\n const taskId = stringField(input, 'task_id')\n if (!taskId)\n return null\n const timeoutMs = input.timeout_ms\n return {\n target: taskId,\n meta: typeof timeoutMs === 'number' ? [`${Math.round(timeoutMs / 1000)}s timeout`] : [],\n }\n },\n },\n\n // ---- Edits (renderer falls through to EditDiffBlock when showEditDiffs is on) ----\n edit: {\n displayName: 'Edit',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path)\n return null\n return {\n target: path,\n meta: input.replace_all === true ? ['replace all'] : [],\n }\n },\n },\n multi_edit: {\n displayName: 'Multi-edit',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path)\n return null\n const edits = Array.isArray(input.edits) ? input.edits.length : 0\n return {\n target: path,\n meta: edits > 0 ? [`${edits} hunk${edits === 1 ? '' : 's'}`] : [],\n }\n },\n },\n write_file: {\n displayName: 'Write',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path)\n return null\n const content = stringField(input, 'content')\n const meta: string[] = []\n if (content !== undefined) {\n // Show byte count instead of line count — write_file's main\n // failure mode is \"did you mean to overwrite a 10KB file with\n // a 4-byte one?\", so bytes catch it faster than lines do.\n const bytes = utf8ByteLength(content)\n meta.push(`${formatBytes(bytes)}`)\n }\n return { target: path, meta }\n },\n },\n\n // ---- Spawn / orchestration ----\n spawn: {\n displayName: 'Agent',\n format: (input) => {\n const task = stringField(input, 'task')\n if (!task)\n return null\n // Continuation of a stopped/failed child (`resume: 'child-N'`) —\n // tag the line so a resume is distinguishable from a fresh spawn.\n const resume = stringField(input, 'resume')\n // Generous cap — a pathology guard, not layout: both renderers\n // width-truncate (TUI by terminal columns, GUI by CSS), and a tight\n // char cap here would waste horizontal room on wide windows.\n return { target: previewLine(task, 200), ...(resume ? { meta: [`resumed ${resume}`] } : {}) }\n },\n },\n\n // ---- Images ----\n generate_image: {\n displayName: input => input?.list === true ? 'Image models' : 'Generate image',\n format: (input) => {\n if (input.list === true)\n return { target: 'list' }\n const prompt = stringField(input, 'prompt')\n if (!prompt)\n return null\n const model = stringField(input, 'model')\n const ratio = stringField(input, 'aspect_ratio')\n const n = typeof input.n === 'number' && input.n > 1 ? `${Math.floor(input.n)} images` : undefined\n const meta = [model, ratio, n].filter((v): v is string => typeof v === 'string' && v !== '')\n return { target: previewLine(prompt, 200), ...(meta.length ? { meta } : {}) }\n },\n },\n\n // ---- Codemode ----\n codemode: {\n // The model's one-line `description` IS the label, in place of the verb:\n // the row reads \"Rank open issues by frustration\", not \"Codemode Rank …\".\n // Without input (group summaries, the context breakdown) or without a\n // description (older sessions) it stays \"Codemode\".\n displayName: (input) => {\n return descriptionLabel(input) ?? 'Codemode'\n },\n format: (input) => {\n const description = stringField(input, 'description')?.trim()\n const code = stringField(input, 'code')\n const lines = code ? code.split('\\n').filter(line => line.trim() !== '' && !line.trimStart().startsWith('// @options:')) : []\n const meta = lines.length > 0 ? [`${lines.length} line${lines.length === 1 ? '' : 's'}`] : []\n if (description)\n return { meta }\n if (lines.length === 0)\n return null\n // No description: the first line of code stands in as the target.\n return { target: previewLine(lines[0]!.trim(), 120), meta }\n },\n },\n\n // ---- Dev browser ----\n browser_open: {\n displayName: 'Browser',\n format: input => ({ target: stringField(input, 'url') ?? 'open' }),\n },\n browser_navigate: {\n displayName: 'Navigate',\n format: input => ({ target: stringField(input, 'url') ?? stringField(input, 'action') ?? '' }),\n },\n browser_snapshot: { displayName: 'Snapshot', format: () => ({ target: 'page' }) },\n browser_screenshot: {\n displayName: 'Screenshot',\n format: input => ({ target: stringField(input, 'ref') ?? 'viewport' }),\n },\n browser_click: {\n displayName: 'Click',\n format: input => ({ target: browserTarget(input) }),\n },\n browser_type: {\n displayName: 'Type',\n format: (input) => {\n const text = stringField(input, 'text') ?? ''\n const where = browserTarget(input)\n return { target: previewLine(JSON.stringify(text), 80), ...(where ? { meta: [`into ${where}`] } : {}) }\n },\n },\n browser_press: {\n displayName: 'Press',\n format: (input) => {\n const mods = Array.isArray(input.modifiers) ? (input.modifiers as unknown[]).map(String) : []\n return { target: [...mods, stringField(input, 'key') ?? ''].join('+') }\n },\n },\n browser_scroll: {\n displayName: 'Scroll',\n format: input => ({ target: `${numberField(input, 'dx') ?? 0}, ${numberField(input, 'dy') ?? 0}` }),\n },\n browser_wait_for: {\n displayName: 'Wait for',\n format: input => ({\n target: stringField(input, 'text') ?? stringField(input, 'selector') ?? stringField(input, 'urlIncludes') ?? '',\n }),\n },\n browser_evaluate: {\n displayName: 'Evaluate',\n format: input => ({ target: previewLine(stringField(input, 'expression') ?? '', 120) }),\n },\n browser_console: {\n displayName: 'Console',\n format: input => ({ target: stringField(input, 'level') ?? 'all' }),\n },\n\n // ---- Terminals (the session's, shared with the user) ----\n terminal_list: { displayName: 'Terminals', format: () => ({ target: 'list' }) },\n terminal_read: {\n displayName: 'Read terminal',\n format: input => ({ target: stringField(input, 'id') ?? '' }),\n },\n terminal_write: {\n displayName: 'Type in terminal',\n // What goes into the terminal is the point: the text, then the keys.\n format: (input) => {\n const text = stringField(input, 'text')\n const keys = Array.isArray(input.keys) ? (input.keys as unknown[]).map(String).filter(Boolean) : []\n const typed = [text ? previewLine(JSON.stringify(text), 80) : '', ...keys].filter(Boolean).join(' + ')\n const id = stringField(input, 'id')\n return { target: typed || (id ?? ''), ...(id && typed ? { meta: [id] } : {}) }\n },\n },\n\n // ---- Tool search (lazy-tool discovery) ----\n tool_search: {\n displayName: 'Search tools',\n format: (input) => {\n const query = stringField(input, 'query')\n const names = Array.isArray(input.names) ? input.names.length : 0\n if (query)\n return { target: `“${query}”` }\n if (names > 0)\n return { target: `${names} tool${names === 1 ? '' : 's'}` }\n return null\n },\n },\n\n // ---- Stable-tools dispatcher ----\n // Only ever rendered for a MALFORMED envelope: a well-formed `call_tool`\n // is unwrapped before the `tool` event is emitted (live) or replayed\n // (`eventsFromTurns`), so it shows up as the inner tool. This entry keeps\n // the rare shape error readable instead of a bare `↳ call_tool`.\n call_tool: {\n displayName: 'Call tool',\n format: (input) => {\n const name = stringField(input, 'name')\n return name ? { target: name, meta: ['malformed call'] } : null\n },\n },\n\n // ---- Skills ----\n skills_use: {\n // `skills_use` straddles two intents — activation (default) and\n // deactivation (`mode: 'deactivate'`, the zidane extension that lets\n // the model recover from `AgentToolNotAllowedError`). The verb comes from\n // `input.mode`, so the transcript shows the deactivation; absent or\n // unexpected values fall back to \"Enable skill\", the spec's\n // activate-only semantics.\n displayName: (input) => {\n const mode = input ? stringField(input, 'mode') : undefined\n return mode === 'deactivate' ? 'Disable skill' : 'Enable skill'\n },\n format: (input) => {\n const name = stringField(input, 'name')\n if (!name)\n return null\n return { target: name }\n },\n },\n skills_read: {\n displayName: 'Read skill',\n format: (input) => {\n const name = stringField(input, 'name')\n const path = stringField(input, 'path')\n if (!name)\n return null\n return { target: path ? `${name}/${path}` : name }\n },\n },\n skills_run_script: {\n displayName: 'Run script',\n format: (input) => {\n const name = stringField(input, 'name')\n const script = stringField(input, 'script')\n if (!name || !script)\n return null\n const meta: string[] = [`skill ${name}`]\n const args = Array.isArray(input.args) ? input.args : null\n if (args && args.length > 0)\n meta.push(previewLine(args.map(String).join(' '), 80))\n return { target: script, meta }\n },\n },\n\n // ---- Todos ----\n todowrite: {\n displayName: 'Todos',\n format: (input) => {\n const todos = Array.isArray(input.todos) ? input.todos : null\n if (!todos)\n return null\n // Show item count + per-status tally — same shape the tool's\n // `tool_result` summary line uses, so the call line and result\n // line read consistently in the transcript.\n const counts = { pending: 0, in_progress: 0, completed: 0, cancelled: 0 }\n for (const t of todos) {\n if (!t || typeof t !== 'object')\n continue\n const status = (t as Record<string, unknown>).status\n if (typeof status === 'string' && status in counts)\n counts[status as keyof typeof counts] += 1\n }\n const meta: string[] = []\n if (counts.completed)\n meta.push(`${counts.completed} done`)\n if (counts.in_progress)\n meta.push(`${counts.in_progress} in progress`)\n if (counts.pending)\n meta.push(`${counts.pending} pending`)\n if (counts.cancelled)\n meta.push(`${counts.cancelled} cancelled`)\n return { target: `${todos.length} item${todos.length === 1 ? '' : 's'}`, meta }\n },\n },\n todoread: {\n displayName: 'Todos',\n format: () => ({ target: 'read' }),\n },\n\n // ---- Interactions (already surfaced as wizards, but the call line still renders) ----\n ask_user: {\n displayName: 'Ask user',\n format: (input) => {\n const questions = Array.isArray(input.questions) ? input.questions.length : 0\n if (questions === 0)\n return null\n return { target: `${questions} question${questions === 1 ? '' : 's'}` }\n },\n },\n present_plan: {\n displayName: 'Present plan',\n format: (input) => {\n const title = stringField(input, 'title')\n if (!title)\n return null\n return { target: title }\n },\n },\n\n // ---- Orchestration (main session only) ----\n // Reads like the session-event cards: line one is the ACTION and WHO it went\n // to (the session's title when the renderer knows it, short id otherwise);\n // line two is the message itself, clamped — prompts can be paragraphs long.\n sessions: {\n displayName: input => SESSIONS_VERB_LABEL[stringField(input ?? {}, 'verb') ?? ''] ?? 'Sessions',\n format: (input) => {\n const verb = stringField(input, 'verb')\n const id = stringField(input, 'sessionId')\n const limit = numberField(input, 'limit')\n // Every id-bearing verb: the short id is the target's FALLBACK text —\n // renderers that know the session swap in its title via `sessionId`.\n const ref = id ? { target: shortSessionId(id), sessionId: id } : null\n switch (verb) {\n case 'create': {\n const prompt = stringField(input, 'prompt')\n if (!prompt)\n return null\n const cwd = stringField(input, 'cwd')\n return { target: stringField(input, 'title') ?? 'new worker', meta: cwd ? [`in ${cwd}`] : [], detail: prompt }\n }\n case 'send':\n case 'steer': {\n const text = stringField(input, verb === 'send' ? 'prompt' : 'message')\n if (!text || !ref)\n return null\n return { ...ref, detail: text }\n }\n case 'cancel':\n case 'read':\n return ref\n case 'transcript':\n return ref ? { ...ref, meta: limit !== undefined ? [`last ${limit} turns`] : [] } : null\n case 'list':\n return { target: 'all sessions', meta: limit !== undefined ? [`limit ${limit}`] : [] }\n default:\n return null\n }\n },\n },\n}\n\n// ---------------------------------------------------------------------------\n// Public helpers\n// ---------------------------------------------------------------------------\n\n/** A plain lowercase word: the label reads as a sentence (`rank open issues` → `Rank open issues`). */\nconst SENTENCE_WORD = /^[a-z][a-z']*$/\n/**\n * A word with an English prefix (`re-profile`, `co-locate`, `non-blocking`).\n * Other hyphenated words stay as written: they are usually names\n * (`zidane-tui`, `eslint-plugin`).\n */\nconst PREFIXED_WORD = /^(?:anti|auto|co|counter|cross|de|mid|multi|non|out|over|post|pre|re|self|semi|sub|un|under)-[a-z][a-z'-]*$/\n\n/**\n * A model-written `description` as a row label: one line, capped, and in\n * sentence case like every other label (\"Check how…\", not \"check how…\").\n * A first word that looks like an identifier or a path (`package.json`,\n * `zidane-tui`, `useEffect`) keeps its case.\n */\nexport function descriptionLabel(input: Record<string, unknown> | undefined): string | undefined {\n const description = input ? stringField(input, 'description')?.trim() : undefined\n if (!description)\n return undefined\n const line = previewLine(description, 120)\n const first = line.split(/\\s/, 1)[0]!\n return SENTENCE_WORD.test(first) || PREFIXED_WORD.test(first) ? line.charAt(0).toUpperCase() + line.slice(1) : line\n}\n\n/**\n * Resolve the display verb for a tool. Native tools use their curated\n * entry from {@link TOOL_DISPLAY}; everything else gets a sentence-case\n * version of the raw name (`my_host_tool` → `My host tool`) so an MCP /\n * host tool still reads cleanly in the transcript without shouting\n * Title Case at every word.\n *\n * MCP convention: every tool surfaced by `mcp/connectMcpServers` is\n * namespaced as `mcp_<server>_<tool>` (see `src/mcp/index.ts`). The\n * `mcp_` prefix is plumbing — strip it before casing so the label\n * reads as `Github create issue` instead of `Mcp github create issue`.\n * The server name leads, which doubles as a free visual grouping\n * affordance (\"everything starting with `Github` came from the github\n * MCP server\").\n *\n * @param name - Tool name.\n * @param input - The call's input, for tools whose label depends on it.\n */\nexport function displayNameFor(\n name: string,\n input?: Record<string, unknown>,\n): string {\n const entry = TOOL_DISPLAY[name]\n if (entry) {\n return typeof entry.displayName === 'function'\n ? entry.displayName(input)\n : entry.displayName\n }\n const stripped = name.startsWith('mcp_') ? name.slice(4) : name\n return sentenceCase(stripped)\n}\n\n/**\n * The source code a tool call runs, for renderers that show it highlighted\n * instead of the raw JSON input: Codemode's script as JavaScript, a `shell`\n * / `bash` command as bash (the command alone: the label carries the\n * description, the rest is plumbing). `null` for\n * every other tool and for calls without the code field. `language` is a\n * fence-style name both highlighters accept (Shiki in the GUI, OpenTUI's\n * tree-sitter in the TUI).\n *\n * @param name - Tool name.\n * @param input - The call's input.\n */\nexport function toolInputCode(\n name: string,\n input: Record<string, unknown> | undefined,\n): { code: string, language: string } | null {\n if (!input)\n return null\n if (name === 'codemode') {\n const code = stringField(input, 'code')\n if (!code || code.trim() === '')\n return null\n return { code: code.replace(/^\\n+|\\s+$/g, ''), language: 'javascript' }\n }\n if (name === 'shell' || name === 'bash') {\n const command = stringField(input, 'command')\n if (!command || command.trim() === '')\n return null\n return { code: command.replace(/^\\n+|\\s+$/g, ''), language: 'bash' }\n }\n return null\n}\n\n/**\n * Run a tool's curated formatter and return the result, or `null` when\n * no formatter is registered / the input shape doesn't match. Renderer\n * decides what to do with `null` — typically: show `↳ <displayName>`\n * with no target / meta tail.\n *\n * @param name - Tool name.\n * @param input - The call's input.\n */\nexport function formatToolCall(name: string, input: Record<string, unknown>): ToolFormatLine | null {\n const entry = TOOL_DISPLAY[name]\n if (!entry)\n return null\n try {\n return entry.format(input)\n }\n catch {\n // Defensive — a misshapen `input` should never crash the\n // transcript. Fall back to the unformatted line.\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** A browser tool's target as written: ref, selector, or point. */\nfunction browserTarget(input: Record<string, unknown>): string {\n const x = numberField(input, 'x')\n const y = numberField(input, 'y')\n return stringField(input, 'ref') ?? stringField(input, 'selector') ?? (x !== undefined && y !== undefined ? `${x}, ${y}` : '')\n}\n\nfunction stringField(input: Record<string, unknown>, key: string): string | undefined {\n const v = input[key]\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\n\nfunction numberField(input: Record<string, unknown>, key: string): number | undefined {\n const v = input[key]\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined\n}\n\n/** `snake_case` / `kebab-case` / lowercase → `Sentence case`. */\nfunction sentenceCase(s: string): string {\n const words = s.split(/[-_\\s]+/).filter(Boolean).map(w => w.toLowerCase())\n if (words.length === 0)\n return ''\n words[0] = (words[0][0]?.toUpperCase() ?? '') + words[0].slice(1)\n return words.join(' ')\n}\n","/**\n * Re-convergence without remounts. A client that replaces its transcript\n * with the host's replay (at run end, on `sessions:changed`, on reconnect)\n * gets fresh objects for events it already shows, and every renderer keys\n * its rows' work on event identity: replacing them re-renders every row,\n * re-highlights code and snaps open rows shut. These keep the objects\n * already on show for every event that did not change.\n *\n * Shared by the TUI and the GUI (`zidane/chat/pure`): React-free and\n * node-free, so the GUI renderer can import it.\n */\nimport type { StreamEvent } from './types'\nimport { hiddenEarlierTranscriptCount } from './streaming-pure'\n\n/** What reconciling reads off an event: a `StreamEvent`, or a client's wire copy of one. */\nexport interface ReconcilableEvent {\n /** Event kind (`tool`, `text`, …). */\n kind: string\n /** Row text; a string's length is part of the match key. */\n text?: unknown\n /** Turn the event belongs to. */\n turnId?: string\n /** Tool call the event belongs to. */\n callId?: string\n /** Subagent that produced the event. */\n childId?: string\n /** A display-only prompt marker the user never typed; compared along with `text`. */\n synthetic?: boolean\n}\n\n/**\n * `next`, with every event structurally equal to one of `prev` replaced by\n * that object (matched one to one, so an event repeated twice keeps two\n * objects). Hands back `prev` itself when the result is positionally\n * identical, so a store keyed on the array sees no change at all.\n *\n * @param prev - Events on show now.\n * @param next - The replacement transcript.\n */\nexport function reconcileEvents<E extends ReconcilableEvent>(prev: readonly E[], next: readonly E[]): E[] {\n if (prev.length === 0)\n return [...next]\n\n const pool = new Map<string, E[]>()\n for (const event of prev) {\n const key = bucketKey(event)\n const bucket = pool.get(key)\n if (bucket)\n bucket.push(event)\n else\n pool.set(key, [event])\n }\n\n const out = next.map((event) => {\n const bucket = pool.get(bucketKey(event))\n if (!bucket)\n return event\n // First structural match in the bucket, consumed so a repeated event\n // (same text twice) still maps one-to-one.\n const hit = bucket.findIndex(candidate => sameEvent(candidate, event))\n return hit === -1 ? event : bucket.splice(hit, 1)[0]!\n })\n\n // Positional identity, not a hit count: a page whose splice position moved\n // (a docked run receipt, a re-paired tool result) can reuse every object\n // in a different order, and that new order must win.\n return out.length === prev.length && out.every((event, i) => event === prev[i]) ? prev as E[] : out\n}\n\n/**\n * The transcript after a re-convergence: `canonical` (the host's replay of\n * the end, behind its hidden-count marker) with the objects already on show\n * kept ({@link reconcileEvents}), and the transcript's start left where it\n * is: history the window revealed above the replayed end stays, and a\n * replay that reaches further back than what's shown starts where the shown\n * transcript starts (the rest stays behind the marker). A run that ends\n * while the user reads that history moves nothing under them. `displayed`\n * itself when nothing changed.\n */\nexport function convergeTranscript(displayed: readonly StreamEvent[], canonical: readonly StreamEvent[]): StreamEvent[] {\n const marked = hiddenEarlierTranscriptCount(displayed) > 0\n const shown = marked ? displayed.slice(1) : displayed\n const tail = hiddenEarlierTranscriptCount(canonical) > 0 ? canonical.slice(1) : canonical\n // Where the canonical tail starts in what's shown: its first turn. Shown\n // from the start (or not at all) means nothing revealed sits above it.\n const firstTurn = (events: readonly StreamEvent[]) => events.find(event => event.turnId !== undefined)?.turnId\n const head = marked ? [displayed[0]!] : []\n const anchor = firstTurn(tail)\n const seam = anchor === undefined ? -1 : shown.findIndex(event => event.turnId === anchor)\n let out: StreamEvent[]\n if (seam > 0) {\n out = [...head, ...shown.slice(0, seam), ...reconcileEvents(shown.slice(seam), tail)]\n }\n else {\n const shownStart = firstTurn(shown)\n const start = shownStart === undefined ? -1 : tail.findIndex(event => event.turnId === shownStart)\n if (start <= 0)\n return reconcileEvents(displayed, canonical)\n out = [...head, ...reconcileEvents(shown, tail.slice(start))]\n }\n return out.length === displayed.length && out.every((event, i) => event === displayed[i]) ? displayed as StreamEvent[] : out\n}\n\n/**\n * Cheap grouping key: discriminators only, no payload serialization. This\n * runs over the whole window at every convergence, and tool events carry\n * kilobytes of result text. Collisions are harmless: they only widen the\n * candidate set {@link sameEvent} then decides.\n */\nfunction bucketKey(event: ReconcilableEvent): string {\n const text = typeof event.text === 'string' ? event.text.length : 0\n return `${event.kind}\\u0000${event.turnId ?? ''}\\u0000${event.callId ?? ''}\\u0000${event.childId ?? ''}\\u0000${text}`\n}\n\n/**\n * Timing a live tool event carries that its replayed twin lacks or measured\n * apart: a client's arrival stamp (`receivedAt`), the host's call start\n * (`startedAt`, live only), a duration the host and the loop each read off\n * their own clock (`durationMs`).\n */\nconst TIMING_KEYS: ReadonlySet<string> = new Set(['receivedAt', 'startedAt', 'durationMs'])\n\n/**\n * Structural equality over everything a row renders, without a field list\n * that drifts from `StreamEvent`. Two deliberate normalizations:\n *\n * - The {@link TIMING_KEYS} are excluded: counting them made a live event\n * unequal to its replayed twin, and every convergence remounted the tool\n * rows. Excluded, the live object wins and the times it shows survive.\n * - Key order is irrelevant: the live broadcast and the replay build their\n * events in different field orders.\n */\nfunction sameEvent(a: ReconcilableEvent, b: ReconcilableEvent): boolean {\n if (a === b)\n return true\n\n // A prompt is the same prompt when its words are. The live copy knows more\n // than the persisted one (the completion refs it was typed with, image\n // bytes behind thumbnails), and swapping it for the disk copy dropped chips.\n if (a.kind === 'user-prompt' && b.kind === 'user-prompt')\n return a.text === b.text && Boolean(a.synthetic) === Boolean(b.synthetic)\n\n return deepEqual(a, b, TIMING_KEYS)\n}\n\n/** `ignore` skips those keys of the top-level objects only. */\nfunction deepEqual(a: unknown, b: unknown, ignore?: ReadonlySet<string>): boolean {\n if (a === b)\n return true\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)\n return false\n if (Array.isArray(a) || Array.isArray(b))\n return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, i) => deepEqual(item, b[i]))\n const objA = a as Record<string, unknown>\n const objB = b as Record<string, unknown>\n const keys = Object.keys(objA).filter(key => !ignore?.has(key))\n return keys.length === Object.keys(objB).filter(key => !ignore?.has(key)).length\n && keys.every(key => key in objB && deepEqual(objA[key], objB[key]))\n}\n"],"mappings":"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"}
|