zidane 6.0.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +27 -0
  2. package/dist/{acp-Irby04Us.js → acp-cfR8T19u.js} +8 -8
  3. package/dist/{acp-Irby04Us.js.map → acp-cfR8T19u.js.map} +1 -1
  4. package/dist/acp-cli.js +7 -7
  5. package/dist/acp-cli.js.map +1 -1
  6. package/dist/acp.d.ts +1 -1
  7. package/dist/acp.js +1 -1
  8. package/dist/{agent-DkSmGkDM.js → agent-DZRA7wip.js} +377 -61
  9. package/dist/agent-DZRA7wip.js.map +1 -0
  10. package/dist/agent.d.ts +1 -1
  11. package/dist/agent.js +1 -1
  12. package/dist/{anthropic-CTHsdFG9.js → anthropic-DNJbRMUK.js} +7 -7
  13. package/dist/anthropic-DNJbRMUK.js.map +1 -0
  14. package/dist/atomic-write-B7zr1ddF.js.map +1 -1
  15. package/dist/{auth-BDSu_0t3.js → auth-B3cB5K6d.js} +7 -7
  16. package/dist/auth-B3cB5K6d.js.map +1 -0
  17. package/dist/cache-telemetry-BKAwsNxm.js.map +1 -1
  18. package/dist/chat/pure.d.ts +4 -4
  19. package/dist/chat/pure.js +3 -3
  20. package/dist/chat.d.ts +44 -21
  21. package/dist/chat.d.ts.map +1 -1
  22. package/dist/chat.js +7 -7
  23. package/dist/chat.js.map +1 -1
  24. package/dist/completion-core-CXYSVhZo.js.map +1 -1
  25. package/dist/context-breakdown-Dzo25N45.js.map +1 -1
  26. package/dist/contexts/daytona.d.ts +3 -1
  27. package/dist/contexts/daytona.d.ts.map +1 -1
  28. package/dist/contexts/daytona.js +2 -2
  29. package/dist/contexts/daytona.js.map +1 -1
  30. package/dist/contexts/docker.d.ts.map +1 -1
  31. package/dist/contexts/docker.js +2 -2
  32. package/dist/contexts/docker.js.map +1 -1
  33. package/dist/contexts/e2b.d.ts +3 -1
  34. package/dist/contexts/e2b.d.ts.map +1 -1
  35. package/dist/contexts/e2b.js +1 -1
  36. package/dist/contexts/e2b.js.map +1 -1
  37. package/dist/{contexts-Vone3qQQ.js → contexts-BIbcfBFH.js} +2 -2
  38. package/dist/contexts-BIbcfBFH.js.map +1 -0
  39. package/dist/contexts.js +1 -1
  40. package/dist/edit-utils-EGosADZq.js.map +1 -1
  41. package/dist/eval.d.ts +1 -1
  42. package/dist/eval.js +4 -3
  43. package/dist/eval.js.map +1 -1
  44. package/dist/exec-file-size-PXkr-MGA.js.map +1 -1
  45. package/dist/extensions.d.ts +1 -1
  46. package/dist/extensions.js +1 -1
  47. package/dist/{fetch-url-CWE8X5OD.js → fetch-url-_5WKWpbQ.js} +2 -2
  48. package/dist/{fetch-url-CWE8X5OD.js.map → fetch-url-_5WKWpbQ.js.map} +1 -1
  49. package/dist/{format-BNOXpl-1.js → format-BF745pLL.js} +9 -2
  50. package/dist/format-BF745pLL.js.map +1 -0
  51. package/dist/generate-data-WL_yGVL6.js.map +1 -1
  52. package/dist/hash-DJRzmcPI.js.map +1 -1
  53. package/dist/headless.d.ts +1 -1
  54. package/dist/headless.js +4 -4
  55. package/dist/headless.js.map +1 -1
  56. package/dist/{index-B8UtiZy7.d.ts → index-BGpM2YaU.d.ts} +378 -5
  57. package/dist/index-BGpM2YaU.d.ts.map +1 -0
  58. package/dist/index.d.ts +2 -2
  59. package/dist/index.js +11 -11
  60. package/dist/index.js.map +1 -1
  61. package/dist/logger-DBX9uYOw.js.map +1 -1
  62. package/dist/{login-DOF8pMVM.js → login-DZLG__2f.js} +4 -3
  63. package/dist/{login-DOF8pMVM.js.map → login-DZLG__2f.js.map} +1 -1
  64. package/dist/mcp-CcvuVXB9.js.map +1 -1
  65. package/dist/mcp.d.ts +1 -1
  66. package/dist/media-sniff-Bn76JxAu.js.map +1 -1
  67. package/dist/{messages-CwujiS74.js → messages-C5BDOjUG.js} +2 -2
  68. package/dist/{messages-CwujiS74.js.map → messages-C5BDOjUG.js.map} +1 -1
  69. package/dist/oauth-8LqbeI_Q.js.map +1 -1
  70. package/dist/{openai-compat-BvgYGSR1.js → openai-compat-B0kqvZqN.js} +2 -2
  71. package/dist/openai-compat-B0kqvZqN.js.map +1 -0
  72. package/dist/output/stream-json.d.ts +1 -1
  73. package/dist/output/terminal.d.ts +1 -1
  74. package/dist/output/terminal.js +1 -1
  75. package/dist/output/terminal.js.map +1 -1
  76. package/dist/output-cap-kBUHBlnq.js.map +1 -1
  77. package/dist/presets.d.ts +1 -1
  78. package/dist/presets.js +1 -1
  79. package/dist/providers/anthropic.d.ts +1 -1
  80. package/dist/providers/anthropic.js +1 -1
  81. package/dist/providers/arcee.d.ts +1 -1
  82. package/dist/providers/arcee.js +1 -1
  83. package/dist/providers/baseten.d.ts +1 -1
  84. package/dist/providers/baseten.js +2 -2
  85. package/dist/providers/baseten.js.map +1 -1
  86. package/dist/providers/cerebras.d.ts +1 -1
  87. package/dist/providers/cerebras.js +1 -1
  88. package/dist/providers/local.d.ts +1 -1
  89. package/dist/providers/local.js +1 -1
  90. package/dist/providers/openai-compat.d.ts +1 -1
  91. package/dist/providers/openai-compat.js +1 -1
  92. package/dist/providers/openai.d.ts +1 -1
  93. package/dist/providers/openai.js +8 -8
  94. package/dist/providers/openai.js.map +1 -1
  95. package/dist/providers/openrouter.d.ts +1 -1
  96. package/dist/providers/openrouter.js +1 -1
  97. package/dist/providers/xai.d.ts +1 -1
  98. package/dist/providers/xai.js +1 -1
  99. package/dist/{providers-z6LDMAr3.js → providers-BMlrTr6a.js} +3 -3
  100. package/dist/{providers-z6LDMAr3.js.map → providers-BMlrTr6a.js.map} +1 -1
  101. package/dist/providers.d.ts +1 -1
  102. package/dist/providers.js +4 -4
  103. package/dist/read-state-Dq_TXUX1.js.map +1 -1
  104. package/dist/{resolve-Cr8JSL_O.js → resolve-CC8Lmwcj.js} +3 -3
  105. package/dist/{resolve-Cr8JSL_O.js.map → resolve-CC8Lmwcj.js.map} +1 -1
  106. package/dist/restate.d.ts +1 -1
  107. package/dist/restate.d.ts.map +1 -1
  108. package/dist/restate.js.map +1 -1
  109. package/dist/session/sqlite.d.ts +1 -1
  110. package/dist/session/sqlite.d.ts.map +1 -1
  111. package/dist/session/sqlite.js +75 -20
  112. package/dist/session/sqlite.js.map +1 -1
  113. package/dist/{session-CsdDIPY8.js → session-CsKzK8-P.js} +3 -3
  114. package/dist/session-CsKzK8-P.js.map +1 -0
  115. package/dist/session.d.ts +2 -2
  116. package/dist/session.js +2 -2
  117. package/dist/{skills-Bsb0rvWI.js → skills-BjeXSRlQ.js} +2 -2
  118. package/dist/{skills-Bsb0rvWI.js.map → skills-BjeXSRlQ.js.map} +1 -1
  119. package/dist/skills.d.ts +1 -1
  120. package/dist/skills.js +2 -2
  121. package/dist/stdio-loader-Ce68wUmM.js.map +1 -1
  122. package/dist/{tool-formatters-DY0TDb1r.d.ts → tool-formatters-CMwjDvkp.d.ts} +2 -2
  123. package/dist/tool-formatters-CMwjDvkp.d.ts.map +1 -0
  124. package/dist/tools/fetch-url.d.ts +1 -1
  125. package/dist/tools/fetch-url.d.ts.map +1 -1
  126. package/dist/tools/fetch-url.js +1 -1
  127. package/dist/tools/web-search.d.ts +1 -1
  128. package/dist/tools/web-search.js +1 -1
  129. package/dist/tools/web-search.js.map +1 -1
  130. package/dist/tools.d.ts +2 -2
  131. package/dist/tools.js +2 -2
  132. package/dist/{transcript-anchors-DSRPWjiH.js → transcript-anchors-BTNe1OJi.js} +346 -89
  133. package/dist/transcript-anchors-BTNe1OJi.js.map +1 -0
  134. package/dist/{transcript-anchors-Cb-bDbNH.d.ts → transcript-anchors-D5wvdKQQ.d.ts} +37 -3
  135. package/dist/transcript-anchors-D5wvdKQQ.d.ts.map +1 -0
  136. package/dist/tui.d.ts +21 -6
  137. package/dist/tui.d.ts.map +1 -1
  138. package/dist/tui.js +497 -83
  139. package/dist/tui.js.map +1 -1
  140. package/dist/{turn-operations-Dq9Kx7m2.js → turn-operations-CEt_l3fy.js} +23 -8
  141. package/dist/turn-operations-CEt_l3fy.js.map +1 -0
  142. package/dist/{turn-operations-CgMROLsr.d.ts → turn-operations-JO5MYM9_.d.ts} +27 -9
  143. package/dist/turn-operations-JO5MYM9_.d.ts.map +1 -0
  144. package/dist/types-BIarq1qE.js.map +1 -1
  145. package/dist/types.d.ts +1 -1
  146. package/dist/{xai-B_e6TOA8.js → xai-C_aq671K.js} +3 -3
  147. package/dist/{xai-B_e6TOA8.js.map → xai-C_aq671K.js.map} +1 -1
  148. package/docs/ARCHITECTURE.md +4 -0
  149. package/docs/CHAT.md +12 -10
  150. package/docs/SKILL.md +1 -1
  151. package/docs/TUI.md +3 -3
  152. package/package.json +2 -2
  153. package/dist/agent-DkSmGkDM.js.map +0 -1
  154. package/dist/anthropic-CTHsdFG9.js.map +0 -1
  155. package/dist/auth-BDSu_0t3.js.map +0 -1
  156. package/dist/contexts-Vone3qQQ.js.map +0 -1
  157. package/dist/format-BNOXpl-1.js.map +0 -1
  158. package/dist/index-B8UtiZy7.d.ts.map +0 -1
  159. package/dist/openai-compat-BvgYGSR1.js.map +0 -1
  160. package/dist/session-CsdDIPY8.js.map +0 -1
  161. package/dist/tool-formatters-DY0TDb1r.d.ts.map +0 -1
  162. package/dist/transcript-anchors-Cb-bDbNH.d.ts.map +0 -1
  163. package/dist/transcript-anchors-DSRPWjiH.js.map +0 -1
  164. package/dist/turn-operations-CgMROLsr.d.ts.map +0 -1
  165. package/dist/turn-operations-Dq9Kx7m2.js.map +0 -1
@@ -1,17 +1,17 @@
1
1
  import { l as toolResultToText } from "./types-BIarq1qE.js";
2
- import { Ct as listFiles, Dt as edit, Et as glob, Ht as readKeybindingsRaw, I as EMPTY_EXTENSION_REGISTRY, St as multiEdit, Tt as grep, Ut as resolveExtensionKeybindings, Y as buildExtensionPreset, at as definePreset, ct as writeFile$1, ft as createSpawnTool, it as composePresets, kt as resolveStorageDirs, xt as readFile$1, yt as shell, zt as mergeKeybindings } from "./agent-DkSmGkDM.js";
3
- import { c as shortId, r as fmtTokens, s as previewLine } from "./format-BNOXpl-1.js";
2
+ import { At as grep, Ct as readFile$1, Jt as resolveExtensionKeybindings, Mt as edit, Ot as listFiles, Pt as resolveStorageDirs, R as EMPTY_EXTENSION_REGISTRY, Wt as mergeKeybindings, Z as buildExtensionPreset, ft as waitTask, jt as glob, mt as createSpawnTool, ot as composePresets, qt as readKeybindingsRaw, st as definePreset, ut as writeFile$1, wt as multiEdit, xt as shell, yt as shellKill } from "./agent-DZRA7wip.js";
3
+ import { c as previewLine, i as fmtTokens, l as shortId } from "./format-BF745pLL.js";
4
4
  import { l as errorMessage } from "./errors-DJUxZg9b.js";
5
- import { M as findGitRoot$1, i as discoverSkills, j as projectUserPaths } from "./resolve-Cr8JSL_O.js";
5
+ import { M as findGitRoot$1, i as discoverSkills, j as projectUserPaths } from "./resolve-CC8Lmwcj.js";
6
6
  import { t as writeFileAtomic } from "./atomic-write-B7zr1ddF.js";
7
7
  import { r as formatTokenUsage } from "./stats-DAKBEKjc.js";
8
8
  import { joinSystemPrompt } from "./prompt.js";
9
9
  import { a as normalizeMcpServers, n as connectMcpServers } from "./mcp-CcvuVXB9.js";
10
10
  import { i as findActiveTriggers, n as collectReferences, o as mergeSuggestions, t as applyInsert } from "./completion-core-CXYSVhZo.js";
11
- import { r as fetchUrl } from "./fetch-url-CWE8X5OD.js";
11
+ import { r as fetchUrl } from "./fetch-url-_5WKWpbQ.js";
12
12
  import { webSearch } from "./tools/web-search.js";
13
- import { C as restoreModelOptions, l as BUILTIN_PROVIDERS, n as applyApiKeyEnv, r as credentialsPath, t as detectAuth, v as modelSupportsReasoning, y as modelsForDescriptor } from "./auth-BDSu_0t3.js";
14
- import { H as extractEditPayload, Z as parseEditOutcomesFromResult, p as ownerOf, rt as chatReferenceTokensFromText, u as capTranscriptEvents } from "./turn-operations-Dq9Kx7m2.js";
13
+ import { C as restoreModelOptions, l as BUILTIN_PROVIDERS, n as applyApiKeyEnv, r as credentialsPath, t as detectAuth, v as modelSupportsReasoning, y as modelsForDescriptor } from "./auth-B3cB5K6d.js";
14
+ import { H as extractEditPayload, Z as parseEditOutcomesFromResult, p as ownerOf, rt as chatReferenceTokensFromText, u as capTranscriptEvents } from "./turn-operations-CEt_l3fy.js";
15
15
  import { createRequire } from "node:module";
16
16
  import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
17
17
  import { Buffer as Buffer$1 } from "node:buffer";
@@ -24,7 +24,7 @@ import { createGunzip } from "node:zlib";
24
24
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
25
25
  import { jsx } from "react/jsx-runtime";
26
26
  //#region \0rolldown/runtime.js
27
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
27
+ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
28
28
  //#endregion
29
29
  //#region src/chat/store.ts
30
30
  function ensureStateDir(path) {
@@ -65,6 +65,22 @@ function saveState(path, state) {
65
65
  * a stderr line is emitted under `ZIDANE_DEBUG` for diagnosis.
66
66
  */
67
67
  async function listSessionMeta(store, filter) {
68
+ if (store.listMeta) try {
69
+ return (await store.listMeta(filter)).map((row) => ({
70
+ id: row.id,
71
+ title: deriveSessionTitle(row.firstUserTurn ? [row.firstUserTurn] : [], row.metadata),
72
+ turnCount: row.turnCount,
73
+ userMessageCount: row.userMessageCount,
74
+ runCount: row.runCount,
75
+ ...row.projectRoot ? { projectRoot: row.projectRoot } : {},
76
+ updatedAt: row.updatedAt
77
+ }));
78
+ } catch (err) {
79
+ if (process.env.ZIDANE_DEBUG) {
80
+ const cause = err instanceof Error ? err.message : String(err);
81
+ process.stderr.write(`[zidane/chat] store.listMeta failed, falling back to full loads: ${cause}\n`);
82
+ }
83
+ }
68
84
  const ids = await store.list(filter);
69
85
  const settled = await Promise.allSettled(ids.map(async (id) => {
70
86
  const data = await store.load(id);
@@ -252,11 +268,13 @@ function eventsFromTurns(turns, runs = []) {
252
268
  };
253
269
  const pushSpawnStart = (run) => {
254
270
  const taskPreview = previewLine(run.prompt, 80);
271
+ const model = run.turnUsage?.find((u) => u.modelId)?.modelId;
255
272
  events.push({
256
273
  kind: "spawn-start",
257
274
  text: taskPreview,
258
275
  childId: labelFor(run.id),
259
- depth: run.depth ?? 1
276
+ depth: run.depth ?? 1,
277
+ ...model ? { model } : {}
260
278
  });
261
279
  };
262
280
  for (let i = 0; i < turns.length; i++) {
@@ -621,7 +639,7 @@ const MARGIN_TOP = {
621
639
  "task-notification": 1,
622
640
  "custom": 1
623
641
  };
624
- const TOOL_KINDS = new Set(["tool", "tool-result"]);
642
+ const TOOL_KINDS = /* @__PURE__ */ new Set(["tool", "tool-result"]);
625
643
  /**
626
644
  * Resolve the top margin (in rows) for an event given the one rendered
627
645
  * just before it. Context-aware rules:
@@ -699,6 +717,42 @@ function sumRunCosts(runs) {
699
717
  for (const run of runs) if (run.cost) total += run.cost;
700
718
  return total;
701
719
  }
720
+ /**
721
+ * Aggregate per-model token + spend totals across every run in a session.
722
+ * Parent and subagent runs alike: each turn carries its own `modelId`, so
723
+ * cost-tiered delegation (cheap spawn workers) shows up as separate rows
724
+ * priced at their own rates. Sorted by cost (desc), then total tokens, so
725
+ * the biggest spender reads first.
726
+ */
727
+ function usageByModel(runs) {
728
+ const byModel = /* @__PURE__ */ new Map();
729
+ for (const run of runs) for (const u of run.turnUsage ?? []) {
730
+ const key = u.modelId ?? "unknown";
731
+ let row = byModel.get(key);
732
+ if (!row) {
733
+ row = {
734
+ modelId: key,
735
+ turns: 0,
736
+ input: 0,
737
+ output: 0,
738
+ cacheRead: 0,
739
+ cacheCreation: 0,
740
+ cost: 0,
741
+ costComplete: true
742
+ };
743
+ byModel.set(key, row);
744
+ }
745
+ row.turns += 1;
746
+ row.input += u.input;
747
+ row.output += u.output;
748
+ row.cacheRead += u.cacheRead ?? 0;
749
+ row.cacheCreation += u.cacheCreation ?? 0;
750
+ if (u.cost !== void 0) row.cost += u.cost;
751
+ else row.costComplete = false;
752
+ }
753
+ const totalTokens = (r) => r.input + r.output + r.cacheRead + r.cacheCreation;
754
+ return [...byModel.values()].sort((a, b) => b.cost - a.cost || totalTokens(b) - totalTokens(a));
755
+ }
702
756
  //#endregion
703
757
  //#region src/tools/read-chat-turns.ts
704
758
  const DEFAULT_TURN_LIMIT = 12;
@@ -858,11 +912,12 @@ function escapeAttr(value) {
858
912
  * for the lifetime of the run.
859
913
  */
860
914
  /**
861
- * Lead line — short, version-stable, written in the same key as Claude Code's
862
- * identity prefix (`constants/system.ts:10` in claude-code). Models trained
863
- * on similar prefixes anchor faster; keep this immutable across releases.
915
+ * Lead line — short, version-stable. The first sentence matches the key of
916
+ * Claude Code's identity prefix (models anchor faster on familiar shapes);
917
+ * the second sets the action bias every other fragment leans on. Keep
918
+ * changes rare — each one costs a cache miss across active sessions.
864
919
  */
865
- const IDENTITY_PREFIX = "You are zidane, a terminal-based coding agent that helps the user with software-engineering tasks.";
920
+ const IDENTITY_PREFIX = "You are zidane, a terminal-based coding agent that helps the user with software-engineering tasks. Bias to action: get to the task immediately, no filler or hedging, keep every response token-lean.";
866
921
  /**
867
922
  * Render the env anchor block. Plain text — XML tags only because models
868
923
  * lean on them as structural cues, not because we parse them anywhere.
@@ -897,12 +952,33 @@ function envSection(opts) {
897
952
  * - Verify before claiming done — prevents false-positive reports that force a follow-up turn.
898
953
  */
899
954
  const DOING_TASKS_DOCTRINE = `# Doing tasks
900
- - Stick to the scope you were asked for. Don't add features, refactor unrelated code, or "improve" things beyond the request. A bug fix doesn't need surrounding cleanup; a small feature doesn't need extra configurability.
901
- - Don't add comments, docstrings, or type annotations to code you didn't change. Only comment where the WHY is non-obvious (hidden constraint, subtle invariant, workaround). Never narrate WHAT the code does — well-named identifiers already do that.
902
- - Trust internal code and framework guarantees. Validate at system boundaries (user input, external APIs), not everywhere. Skip backwards-compat shims unless asked.
903
- - Don't create helpers, utilities, or abstractions for one-time operations. Three similar lines beat a premature abstraction. The right amount of complexity is what the task actually requires.
904
- - Before reporting a task complete, verify it actually works: run the test, execute the script, check the output. Report outcomes faithfully — if tests fail, say so with the relevant output. Never claim "all tests pass" when output shows failures.
905
- - If you spot a bug adjacent to what was asked, or notice the request is based on a misconception, say so. You are a collaborator, not just an executor.`;
955
+ - Do exactly what was asked no unrequested features, refactors, or cleanup.
956
+ - Don't add comments, docstrings, or type annotations to code you didn't change. Comment only non-obvious WHY, never WHAT.
957
+ - Validate at system boundaries (user input, external APIs), not everywhere; trust internal code. No backwards-compat shims unless asked.
958
+ - No helpers or abstractions for one-time operations three similar lines beat a premature abstraction.
959
+ - Verify before reporting done: run the test or script and report the real outcome, including failures.
960
+ - If you spot an adjacent bug or a flawed assumption in the request, say so.`;
961
+ /**
962
+ * Codebase-conventions doctrine. Mirrors claude-code's "following
963
+ * conventions" section — the single most common quality failure in build
964
+ * agents is inventing a dependency or style the repo doesn't use. Kept
965
+ * separate from {@link DOING_TASKS_DOCTRINE} so read-only profiles can
966
+ * drop it (plan mode proposes but doesn't write).
967
+ */
968
+ const CONVENTIONS_DOCTRINE = `# Codebase conventions
969
+ - Mimic the surrounding code: style, naming, error handling, test framework.
970
+ - Never assume a library is available — confirm it's already used (manifest, sibling imports) before importing it.
971
+ - Model new components and modules on an existing one in the repo.`;
972
+ /**
973
+ * Git doctrine. {@link ACTIONS_WITH_CARE_DOCTRINE} covers force-push as a
974
+ * destructive action; this fragment covers the everyday cases — users ask
975
+ * TUI agents to commit constantly and unguided models over-stage, commit
976
+ * unprompted, or rewrite shared history.
977
+ */
978
+ const GIT_DOCTRINE = `# Git
979
+ - Never commit, push, branch, or open PRs unless explicitly asked.
980
+ - When committing: stage only files relevant to the change (no blanket \`git add -A\`); write a concise message focused on the WHY.
981
+ - Never rewrite history you didn't author this session (amend / rebase / force-push) without confirmation. Don't modify the git config.`;
906
982
  /**
907
983
  * zidane-specific token-economy doctrine. No claude-code analog — this is
908
984
  * the prose half of the `behavior.{compactStrategy, elideStaleReads,
@@ -911,27 +987,35 @@ const DOING_TASKS_DOCTRINE = `# Doing tasks
911
987
  * the access patterns that defeat them.
912
988
  */
913
989
  const TOKEN_DISCIPLINE_DOCTRINE = `# Working efficiently
914
- - Don't re-read a file while its result is still visible above — that wastes context. But tool output CAN be compacted away as the session grows (you'll see a short \`[…elided…]\` stub where the result used to be); when the content you need is no longer visible, just read it again. A re-read of compacted-away content returns the full file, not a dedup stub so you never need to "chunk" a file to get around missing content.
915
- - Narrow before you read. \`grep\` / \`glob\` to locate, then \`read_file\` on the specific file. Don't open a 2000-line file when you only need one function.
916
- - Prefer \`edit\` / \`multi_edit\` over \`write_file\` for surgical changes — full overwrites are larger payloads and easier to get wrong.
917
- - Spawn a subagent (\`spawn\`) for self-contained research dives or codegen passes that don't need the parent's context. The child runs in its own context window — you only get its final report back.
918
- - Don't grep for things already shown to you, list directories you already saw, or re-execute commands whose output is still above. Tool budgets nudge against runaway exploration but the cheaper fix is to not start the loop.
919
-
920
- Tool results may be elided, persisted, or replaced as the conversation grows: stale \`read_file\` outputs become short stubs after the file is edited, older tool results may be tail-compacted, and large outputs are written to disk and replaced inline with a \`<persisted-output tool="…" bytes="…" path="…">\` block carrying a 2 KiB head preview plus the filesystem path. Copy load-bearing data into your own response text before you'd need to recover it later — and when you see a \`<persisted-output>\` block whose preview isn't enough, call \`read_file\` on the persisted path to retrieve the full payload.`;
990
+ - Search first (\`grep\` / \`glob\`), then \`read_file\` the specific file — don't open a 2000-line file for one function.
991
+ - Don't re-read files, re-list directories, or re-run commands whose output is still visible above. When earlier output shows an \`[…elided…]\` stub, just read it again — you'll get the full content back.
992
+ - Prefer \`edit\` / \`multi_edit\` over \`write_file\` for changes to existing files.
993
+ - Use \`spawn\` for self-contained research or codegen that doesn't need your context; only its final report comes back.
994
+ - Large outputs may be replaced inline by a \`<persisted-output path="…">\` block with a short preview \`read_file\` that path when the preview isn't enough. Copy load-bearing data into your response text before it can scroll away.`;
995
+ /**
996
+ * Read-only variant of {@link TOKEN_DISCIPLINE_DOCTRINE} for plan-mode
997
+ * profiles. Drops the \`edit\`/\`multi_edit\`/\`write_file\` bullet and the
998
+ * \`spawn\` bullet — none of those tools exist in the read-only tool set,
999
+ * and recommending \`spawn\` directly contradicted PLAN_MODE_DOCTRINE's
1000
+ * "you CANNOT … spawn subagents". Retained bullets mirror the Build
1001
+ * fragment ("re-run searches" instead of "re-run commands" — plan mode
1002
+ * has no shell) so the two profiles stay consistent in tone.
1003
+ */
1004
+ const TOKEN_DISCIPLINE_DOCTRINE_READ_ONLY = `# Working efficiently
1005
+ - Search first (\`grep\` / \`glob\`), then \`read_file\` the specific file — don't open a 2000-line file for one function.
1006
+ - Don't re-read files, re-list directories, or re-run searches whose output is still visible above. When earlier output shows an \`[…elided…]\` stub, just read it again — you'll get the full content back.
1007
+ - Large outputs may be replaced inline by a \`<persisted-output … path="…">\` block with a short preview — \`read_file\` that path when the preview isn't enough. Copy load-bearing data into your response text before it can scroll away.`;
921
1008
  /**
922
1009
  * User-facing communication style. Lifted from claude-code's
923
1010
  * `# Communicating with the user` + `# Tone and style` sections (~404-442).
924
- * The "no colon before tool calls" rule matters because models often
925
- * generate "Let me check this file:" right before a tool call that the
926
- * user never sees rendered.
1011
+ * The "no colon before tool calls" rule matters because the TUI renders
1012
+ * the model's text and the tool call as separate blocks a trailing
1013
+ * colon reads as a broken sentence.
927
1014
  */
928
1015
  const COMMUNICATION_DOCTRINE = `# Communicating with the user
929
- - You're writing for a person, not logging to a console. Tool calls and reasoning are not visible only your text output is. Before your first tool call, briefly state what you're about to do.
930
- - Give short updates at load-bearing moments: root cause found, direction change, real progress. Skip play-by-play.
931
- - Write in flowing prose. Avoid excessive em dashes, fragments, symbols, or notation. Tables when they help, not by default.
932
- - Don't use a colon before tool calls. "Let me read the file:" + tool call reads as broken — write "Let me read the file." with a period.
933
- - Reference code as \`file:line\` so the user can navigate (e.g. \`src/agent.ts:1213\`).
934
- - No emojis unless the user explicitly asks.`;
1016
+ - Your text output is what the user reads; your reasoning and full tool payloads are not shown. Briefly state what you're doing before the first tool call, then update only at load-bearing moments — root cause found, direction change, real progress. No play-by-play.
1017
+ - Keep responses short and concrete, in flowing prose — not em-dash-chained fragments or notation. Reference code as \`file:line\` (e.g. \`src/agent.ts:1213\`). Tables only when they help. No emojis unless asked.
1018
+ - End the sentence before a tool call with a period, not a colon.`;
935
1019
  /**
936
1020
  * Reversibility / blast-radius doctrine. Mirrors claude-code's `# Executing
937
1021
  * actions with care` (255-267). The TUI's safe-mode already gates risky
@@ -940,9 +1024,7 @@ const COMMUNICATION_DOCTRINE = `# Communicating with the user
940
1024
  * before reaching for destructive shortcuts.
941
1025
  */
942
1026
  const ACTIONS_WITH_CARE_DOCTRINE = `# Executing actions with care
943
- Reversibility scales the required caution. Local edits, tests, and reads are free to take. Destructive or shared-state actions need explicit user confirmation — \`rm -rf\`, dropping tables, force-pushing, modifying CI, sending messages, posting to external services. A user approving an action once does NOT mean they approve it in all contexts.
944
-
945
- When you hit an obstacle, do not use destructive actions as a shortcut to make it go away. Measure twice, cut once.`;
1027
+ Local edits, tests, and reads are free to take. Destructive or shared-state actions (\`rm -rf\`, dropping tables, force-pushing, modifying CI, posting to external services) need explicit user confirmation each time prior approval doesn't carry over. Never use a destructive action as a shortcut around an obstacle.`;
946
1028
  /**
947
1029
  * How to brief a subagent. Spawning a child agent is the highest-leverage
948
1030
  * token move in zidane — a 5k-token research dive becomes a 200-token
@@ -953,14 +1035,8 @@ When you hit an obstacle, do not use destructive actions as a shortcut to make i
953
1035
  * (`tools/AgentTool/prompt.ts:99-113`).
954
1036
  */
955
1037
  const SUBAGENT_GUIDANCE = `# When spawning subagents
956
- Brief the child agent like a smart colleague who just walked in — it has not seen this conversation and doesn't know what you've tried or why this matters.
957
- - Explain what you're trying to accomplish and why.
958
- - Describe what you've already learned or ruled out.
959
- - Give enough context that the child can make judgment calls, not just follow narrow steps.
960
- - For investigations, hand over the question. For lookups, hand over the exact command.
961
- - Never delegate understanding ("based on your findings, fix the bug"). Synthesize yourself — include file paths, line numbers, and the specific change you want.
962
-
963
- Terse command-style prompts produce shallow, generic work.`;
1038
+ The child has not seen this conversation. Brief it like a colleague who just walked in: the goal and why, what you've learned or ruled out, and enough context for judgment calls. Never delegate understanding synthesize yourself and hand over file paths, line numbers, and the specific change you want. Terse prompts produce shallow work.
1039
+ When spawn offers a \`model\` field, cost-tier your delegation: mechanical, parallelizable, or high-volume search work belongs on cheaper/faster models; keep synthesis and final judgment on your own model.`;
964
1040
  /**
965
1041
  * Plan-mode framing. Replaces the previous one-liner with explicit phases
966
1042
  * (explore → propose → submit), drawing on claude-code's iterative-plan
@@ -968,19 +1044,13 @@ Terse command-style prompts produce shallow, generic work.`;
968
1044
  * tool set in {@link PLAN_AGENT}.
969
1045
  */
970
1046
  const PLAN_MODE_DOCTRINE = `# Plan mode — read-only
971
- You are in PLAN mode. You can read files, list directories, and search the codebasebut you CANNOT modify files, run shell commands, or spawn subagents. Use this mode to investigate, understand, and design a proposal.
972
-
973
- ## Loop
974
- 1. **Explore** — Read code. Look for existing functions, utilities, and patterns to reuse.
975
- 2. **Ask** — When you hit an ambiguity only the user can resolve (requirements, preferences, tradeoffs), call \`ask_user\` with the full batch of questions.
976
- 3. **Propose** — When the plan is ready, submit it via \`present_plan\` with a concrete title, the markdown body, and optional structured steps. The user approves, rejects, or asks for revisions.
1047
+ You are in PLAN mode: investigate and design a proposal. You can read files, search the codebase, and search the web — you CANNOT modify files, run shell commands, or spawn subagents.
977
1048
 
978
- ## Good plans
979
- - Cover what to change, which files to modify, what existing code to reuse (with file paths), and how to verify the change end-to-end.
980
- - Reference real symbols and line numbers from your exploration.
981
- - Surface only your recommended approach, not every alternative.
1049
+ 1. **Explore** — read the relevant code; find existing functions and patterns to reuse. Check current docs via web search when the plan depends on external libraries.
1050
+ 2. **Ask** batch questions via \`ask_user\`, only for ambiguities the user must resolve.
1051
+ 3. **Propose** — submit via \`present_plan\`: what to change, which files, what to reuse (real paths, symbols, line numbers), how to verify end-to-end. Recommend one approach, not every alternative.
982
1052
 
983
- The user will switch to Build mode to execute an approved plan.`;
1053
+ The user switches to Build mode to execute an approved plan.`;
984
1054
  /**
985
1055
  * How to use `present_plan` / `ask_user`. Kept short — the tool descriptions
986
1056
  * carry the schema details; this prompt covers the cross-cutting *when*.
@@ -989,9 +1059,9 @@ The user will switch to Build mode to execute an approved plan.`;
989
1059
  * Moved here so a custom profile can pull it in independently.
990
1060
  */
991
1061
  const INTERACTION_GUIDANCE = `# Interacting with the user
992
- - Call \`present_plan\` when you have a concrete proposal that materially changes the workspace and want explicit confirmation before executing.
993
- - Call \`ask_user\` when clarifying answers materially change the next steps. Batch related questions into one call — every call pauses the conversation.
994
- - Use both sparingly. Don't ask what you could find out by reading the code.`;
1062
+ - \`present_plan\`: only for a concrete proposal that materially changes the workspace and needs sign-off before executing.
1063
+ - \`ask_user\`: only when the answer materially changes next steps; batch related questions into one call.
1064
+ - Don't ask what you can find out by reading the code.`;
995
1065
  /**
996
1066
  * Variant of {@link INTERACTION_GUIDANCE} for the no-interactive-prompts
997
1067
  * configuration (`Settings.allowInteraction = false`). The two tools are
@@ -1000,7 +1070,7 @@ const INTERACTION_GUIDANCE = `# Interacting with the user
1000
1070
  * final prose message rather than via tool calls.
1001
1071
  */
1002
1072
  const INTERACTION_GUIDANCE_NO_PROMPTS = `# No interactive prompts
1003
- You don't have \`ask_user\` or \`present_plan\` available — interactive prompts are disabled. When you hit ambiguity, state your assumption in plain prose and proceed. Surface decisions, tradeoffs, and open questions in your final message rather than pausing mid-task.`;
1073
+ \`ask_user\` / \`present_plan\` are unavailable. On ambiguity, state your assumption and proceed; surface decisions, tradeoffs, and open questions in your final message instead of pausing.`;
1004
1074
  /**
1005
1075
  * Variant of {@link PLAN_MODE_DOCTRINE} for the no-interactive-prompts
1006
1076
  * configuration. The "Ask" step is removed; "Propose" no longer calls
@@ -1008,19 +1078,12 @@ You don't have \`ask_user\` or \`present_plan\` available — interactive prompt
1008
1078
  * directly in its final message.
1009
1079
  */
1010
1080
  const PLAN_MODE_DOCTRINE_NO_PROMPTS = `# Plan mode — read-only
1011
- You are in PLAN mode. You can read files, list directories, and search the codebasebut you CANNOT modify files, run shell commands, or spawn subagents. Use this mode to investigate, understand, and design a proposal.
1081
+ You are in PLAN mode: investigate and design a proposal. You can read files, search the codebase, and search the web — you CANNOT modify files, run shell commands, or spawn subagents.
1012
1082
 
1013
- ## Loop
1014
- 1. **Explore** — Read code. Look for existing functions, utilities, and patterns to reuse.
1015
- 2. **Propose** — When the plan is ready, write it directly in your final response. Cover what to change, which files to modify, what existing code to reuse (with file paths), and how to verify the change end-to-end.
1083
+ 1. **Explore** — read the relevant code; find existing functions and patterns to reuse. Check current docs via web search when the plan depends on external libraries.
1084
+ 2. **Propose** — write the plan in your final response: what to change, which files, what to reuse (real paths, symbols, line numbers), how to verify end-to-end. Recommend one approach, not every alternative. Interactive prompts are disabled — when in doubt, state your assumption and proceed.
1016
1085
 
1017
- ## Good plans
1018
- - Cover what to change, which files to modify, what existing code to reuse (with file paths), and how to verify the change end-to-end.
1019
- - Reference real symbols and line numbers from your exploration.
1020
- - Surface only your recommended approach, not every alternative.
1021
- - Don't pause for clarification — interactive prompts are disabled. When in doubt, state your assumption and proceed.
1022
-
1023
- The user will switch to Build mode to execute the plan.`;
1086
+ The user switches to Build mode to execute the plan.`;
1024
1087
  function buildEnvSectionFromOpts(opts) {
1025
1088
  if (!opts.cwd) return null;
1026
1089
  return envSection({
@@ -1054,7 +1117,9 @@ function buildBuildSystem(opts = {}) {
1054
1117
  static: [
1055
1118
  IDENTITY_PREFIX,
1056
1119
  DOING_TASKS_DOCTRINE,
1120
+ CONVENTIONS_DOCTRINE,
1057
1121
  ACTIONS_WITH_CARE_DOCTRINE,
1122
+ GIT_DOCTRINE,
1058
1123
  TOKEN_DISCIPLINE_DOCTRINE,
1059
1124
  SUBAGENT_GUIDANCE,
1060
1125
  COMMUNICATION_DOCTRINE,
@@ -1076,7 +1141,7 @@ function buildPlanSystem(opts = {}) {
1076
1141
  static: [
1077
1142
  IDENTITY_PREFIX,
1078
1143
  noPrompts ? PLAN_MODE_DOCTRINE_NO_PROMPTS : PLAN_MODE_DOCTRINE,
1079
- TOKEN_DISCIPLINE_DOCTRINE,
1144
+ TOKEN_DISCIPLINE_DOCTRINE_READ_ONLY,
1080
1145
  COMMUNICATION_DOCTRINE,
1081
1146
  noPrompts ? INTERACTION_GUIDANCE_NO_PROMPTS : INTERACTION_GUIDANCE,
1082
1147
  opts.userInstructions || null
@@ -1749,9 +1814,19 @@ const READ_ONLY_TOOLS = {
1749
1814
  webSearch,
1750
1815
  fetchUrl
1751
1816
  };
1752
- /** Full build-mode tool slice — read + write + shell + spawn. */
1817
+ /**
1818
+ * Full build-mode tool slice — read + write + shell + spawn.
1819
+ *
1820
+ * `shellKill` / `waitTask` ride along with `shell`: the shell tool's
1821
+ * description (and the `<task-notification>` stall hint in the agent
1822
+ * loop) instruct the model to call `shell_kill` / `wait_task` for
1823
+ * background tasks, so omitting them produces tool-not-found loops the
1824
+ * moment a `run_in_background` task needs terminating or blocking on.
1825
+ */
1753
1826
  const BUILD_TOOLS = {
1754
1827
  shell,
1828
+ shellKill,
1829
+ waitTask,
1755
1830
  readFile: readFile$1,
1756
1831
  writeFile: writeFile$1,
1757
1832
  listFiles,
@@ -3180,6 +3255,139 @@ function useCompletion(input, providers, options = {}) {
3180
3255
  ]);
3181
3256
  }
3182
3257
  //#endregion
3258
+ //#region src/chat/model-chain.ts
3259
+ /**
3260
+ * Toggle `entry` in `chain`: absent → appended (it takes the next
3261
+ * position number), present → removed (later entries renumber by
3262
+ * shifting down). Pure — returns a new array.
3263
+ */
3264
+ function toggleChainEntry(chain, entry) {
3265
+ const idx = chain.findIndex((e) => e.provider === entry.provider && e.model === entry.model);
3266
+ if (idx === -1) return [...chain, entry];
3267
+ return [...chain.slice(0, idx), ...chain.slice(idx + 1)];
3268
+ }
3269
+ /**
3270
+ * 1-based position of a pair in the chain, or `null` when absent.
3271
+ * Drives the numbered markers in the picker rows.
3272
+ */
3273
+ function chainPositionOf(chain, provider, model) {
3274
+ const idx = chain.findIndex((e) => e.provider === provider && e.model === model);
3275
+ return idx === -1 ? null : idx + 1;
3276
+ }
3277
+ /** Order-sensitive equality — a reordered chain is a different chain. */
3278
+ function chainsEqual(a, b) {
3279
+ if (a.length !== b.length) return false;
3280
+ return a.every((e, i) => e.provider === b[i].provider && e.model === b[i].model);
3281
+ }
3282
+ /**
3283
+ * Did the SET of provider keys change between two chains? The agent is
3284
+ * built with one provider instance per distinct chain key, so a set
3285
+ * change requires a session re-activation (rebuild); a pure model /
3286
+ * order change within the same providers does not.
3287
+ */
3288
+ function providerKeySetChanged(prev, next) {
3289
+ const prevKeys = new Set(prev.map((e) => e.provider));
3290
+ const nextKeys = new Set(next.map((e) => e.provider));
3291
+ if (prevKeys.size !== nextKeys.size) return true;
3292
+ for (const k of nextKeys) if (!prevKeys.has(k)) return true;
3293
+ return false;
3294
+ }
3295
+ /**
3296
+ * Assemble the `agent.run` `model` option from a chain.
3297
+ *
3298
+ * - Single-entry chain → the bare model id string (byte-identical to the
3299
+ * pre-chain behavior).
3300
+ * - Multi-entry chain → pinned `{ provider, model }` targets, where
3301
+ * `provider` is the runtime `Provider.name` resolved via
3302
+ * `providerNameFor` (chain entries carry chat-level `ProviderKey`s,
3303
+ * which need not equal the instance names the agent loop matches on).
3304
+ *
3305
+ * Throws only on an empty chain — a programmer error, since chains
3306
+ * always carry a primary. Stale or unresolvable entries degrade
3307
+ * defensively instead (never throw, never produce an entry the agent
3308
+ * would reject):
3309
+ * - Entries whose key has no resolvable name (provider not constructed
3310
+ * into the current agent) are dropped.
3311
+ * - If the PRIMARY itself doesn't resolve, or fewer than two entries
3312
+ * survive, fall back to the bare primary model string.
3313
+ *
3314
+ * `contextWindowFor` (optional) stamps each target with its model's
3315
+ * context window from the host catalog, so the loop re-bases the
3316
+ * auto-compact trigger when a fallback advances onto it (the host's
3317
+ * explicit window is sized for the PRIMARY otherwise).
3318
+ */
3319
+ function buildRunModel(chain, providerNameFor, contextWindowFor) {
3320
+ const primary = chain[0];
3321
+ if (!primary) throw new Error("buildRunModel: chain must not be empty");
3322
+ if (chain.length === 1 || providerNameFor(primary.provider) === void 0) return primary.model;
3323
+ const resolved = [];
3324
+ for (const entry of chain) {
3325
+ const name = providerNameFor(entry.provider);
3326
+ if (name === void 0) continue;
3327
+ const contextWindow = contextWindowFor?.(entry);
3328
+ resolved.push({
3329
+ provider: name,
3330
+ model: entry.model,
3331
+ ...typeof contextWindow === "number" && contextWindow > 0 ? { contextWindow } : {}
3332
+ });
3333
+ }
3334
+ return resolved.length > 1 ? resolved : primary.model;
3335
+ }
3336
+ /**
3337
+ * Validate a persisted chain read back from `state.json`. The state file
3338
+ * is user-editable JSON, so the value can be arbitrarily malformed —
3339
+ * return only the well-shaped `{ provider, model }` entries (both
3340
+ * non-empty strings), or `[]` for anything else. Never throws.
3341
+ */
3342
+ function sanitizeModelChain(value) {
3343
+ if (!Array.isArray(value)) return [];
3344
+ const entries = [];
3345
+ for (const item of value) {
3346
+ if (typeof item !== "object" || item === null || !("provider" in item) || !("model" in item)) continue;
3347
+ const { provider, model } = item;
3348
+ if (typeof provider === "string" && provider.length > 0 && typeof model === "string" && model.length > 0) entries.push({
3349
+ provider,
3350
+ model
3351
+ });
3352
+ }
3353
+ return entries;
3354
+ }
3355
+ /**
3356
+ * Restore the fallback tail of a persisted chain for a resolved primary
3357
+ * pair. Returns entries 1+ only when the persisted chain's entry 0
3358
+ * matches `primary` — a divergent chain belongs to a different selection
3359
+ * (e.g. a `--model` launch override) and silently attaching it would
3360
+ * surprise. Entries whose provider isn't registered, entries equal to
3361
+ * the primary, and exact duplicates drop. Accepts the raw persisted
3362
+ * value (`state.json` is user-editable) — shape validation included.
3363
+ */
3364
+ function restoreChainFallbacks(saved, primary, isRegistered) {
3365
+ const chain = sanitizeModelChain(saved);
3366
+ const head = chain[0];
3367
+ if (chain.length < 2 || !head || head.provider !== primary.provider || head.model !== primary.model) return [];
3368
+ return filterChainFallbacks(chain.slice(1), primary, isRegistered);
3369
+ }
3370
+ /**
3371
+ * Filter candidate fallback entries against a primary pair, preserving
3372
+ * picked order: entries whose provider `isAvailable` rejects, entries
3373
+ * equal to the primary, and exact duplicates drop. Shared by the
3374
+ * picker's apply path (live-auth availability) and persisted-chain
3375
+ * restore (registry availability).
3376
+ */
3377
+ function filterChainFallbacks(entries, primary, isAvailable) {
3378
+ const fallbacks = [];
3379
+ for (const entry of entries) {
3380
+ if (!isAvailable(entry.provider)) continue;
3381
+ if (entry.provider === primary.provider && entry.model === primary.model) continue;
3382
+ if (fallbacks.some((f) => f.provider === entry.provider && f.model === entry.model)) continue;
3383
+ fallbacks.push({
3384
+ provider: entry.provider,
3385
+ model: entry.model
3386
+ });
3387
+ }
3388
+ return fallbacks;
3389
+ }
3390
+ //#endregion
3183
3391
  //#region src/chat/user-config.ts
3184
3392
  /**
3185
3393
  * User-level config at `~/.{prefix}/config.json`. Holds global flags
@@ -3486,9 +3694,14 @@ function pickInitial(auth, providers, state, overrides = {}) {
3486
3694
  if (!model) return null;
3487
3695
  const effort = overrides.thinking ?? (modelSupportsReasoning(descriptor, model) ? state.lastEffortByModel?.[model] ?? "medium" : void 0);
3488
3696
  const modelOptions = restoreModelOptions(descriptor, model, state.lastModelOptionsByModel);
3697
+ const fallbacks = restoreChainFallbacks(state.lastModelChain, {
3698
+ provider: auth.key,
3699
+ model
3700
+ }, (k) => providers[k] !== void 0);
3489
3701
  return {
3490
3702
  provider: auth,
3491
3703
  model,
3704
+ ...fallbacks.length > 0 ? { fallbacks } : {},
3492
3705
  ...effort ? { effort } : {},
3493
3706
  ...modelOptions ? { modelOptions } : {}
3494
3707
  };
@@ -4815,6 +5028,7 @@ const DEFAULT_SETTINGS = {
4815
5028
  safeMode: true,
4816
5029
  loadProjectExtensions: false,
4817
5030
  hideSubagentOutput: true,
5031
+ subagentModels: true,
4818
5032
  theme: DEFAULT_THEME.id,
4819
5033
  showAllProjects: false,
4820
5034
  resumeLastSession: true,
@@ -4843,6 +5057,7 @@ const DEFAULT_SETTINGS = {
4843
5057
  ctrlCBehavior: "quit",
4844
5058
  terminalTitle: "off",
4845
5059
  sessionIcon: "",
5060
+ attentionIcon: "",
4846
5061
  attachmentsEnabled: true,
4847
5062
  externalEditor: true
4848
5063
  };
@@ -4967,6 +5182,12 @@ const SETTINGS_TOGGLES = [
4967
5182
  label: "Auto-compact",
4968
5183
  description: "summarize the conversation when context fills past the threshold below"
4969
5184
  },
5185
+ {
5186
+ category: "agent",
5187
+ key: "subagentModels",
5188
+ label: "Allow subagents to use different models",
5189
+ description: "spawn gains a `model` field + `model_search` so the agent can delegate to cheaper models (off = children inherit your model)"
5190
+ },
4970
5191
  {
4971
5192
  category: "agent",
4972
5193
  key: "resumeOnMaxTokens",
@@ -5356,6 +5577,12 @@ const SETTINGS_INPUTS = [{
5356
5577
  label: "Session icon",
5357
5578
  description: "icon prefixed before the session title when \"Terminal title\" is set to icon + session (empty = ⚽)",
5358
5579
  placeholder: "⚽"
5580
+ }, {
5581
+ category: "ui",
5582
+ key: "attentionIcon",
5583
+ label: "Attention icon",
5584
+ description: "replaces the session icon while zidane waits on your input — tool approvals and question forms (empty = ⚠️)",
5585
+ placeholder: "⚠️"
5359
5586
  }];
5360
5587
  //#endregion
5361
5588
  //#region src/chat/enabled-toggle-set.ts
@@ -5410,7 +5637,8 @@ function useEnabledToggleSet(opts) {
5410
5637
  const next = new Set(enabledSet);
5411
5638
  if (next.has(name)) next.delete(name);
5412
5639
  else next.add(name);
5413
- setSetting(settingKey, [...next].filter((n) => catalogKeys.has(n)).sort());
5640
+ const persisted = [...next].filter((n) => catalogKeys.has(n)).sort();
5641
+ setSetting(settingKey, persisted);
5414
5642
  }, [
5415
5643
  enabledSet,
5416
5644
  catalogKeys,
@@ -5434,7 +5662,7 @@ const DEFAULT_MAX_FILES = 1e4;
5434
5662
  * `node_modules`, `dist`, build caches — plus the `.git` dir itself.
5435
5663
  * Best-effort; the git path is the authoritative one.
5436
5664
  */
5437
- const FS_WALK_SKIP = new Set([
5665
+ const FS_WALK_SKIP = /* @__PURE__ */ new Set([
5438
5666
  ".git",
5439
5667
  ".hg",
5440
5668
  ".svn",
@@ -5461,9 +5689,10 @@ const FS_WALK_SKIP = new Set([
5461
5689
  ".vscode-test"
5462
5690
  ]);
5463
5691
  /**
5464
- * Discover every non-ignored file under `cwd`. Tries `git ls-files` first;
5465
- * on failure (no git, not a repo, abort) walks the fs with a hand-rolled
5466
- * skip list.
5692
+ * Discover every non-ignored file under `cwd`, plus the directories that
5693
+ * contain them (derived from the file paths, `kind: 'dir'`). Tries
5694
+ * `git ls-files` first; on failure (no git, not a repo, abort) walks the
5695
+ * fs with a hand-rolled skip list.
5467
5696
  *
5468
5697
  * Errors are not thrown — the function always returns an array (possibly
5469
5698
  * empty). Callers wanting failure diagnostics can opt into them via
@@ -5601,10 +5830,32 @@ function toEntries(paths, source, maxFiles) {
5601
5830
  out.push({
5602
5831
  path,
5603
5832
  name,
5604
- source
5833
+ source,
5834
+ kind: "file"
5605
5835
  });
5606
5836
  if (out.length >= maxFiles) break;
5607
5837
  }
5838
+ const dirs = /* @__PURE__ */ new Set();
5839
+ for (const entry of out) {
5840
+ let p = entry.path;
5841
+ for (let idx = p.lastIndexOf("/"); idx > 0; idx = p.lastIndexOf("/")) {
5842
+ p = p.slice(0, idx);
5843
+ if (dirs.has(p)) break;
5844
+ dirs.add(p);
5845
+ }
5846
+ }
5847
+ let dirCount = 0;
5848
+ for (const path of dirs) {
5849
+ const lastSlash = path.lastIndexOf("/");
5850
+ const name = lastSlash >= 0 ? path.slice(lastSlash + 1) : path;
5851
+ out.push({
5852
+ path,
5853
+ name,
5854
+ source,
5855
+ kind: "dir"
5856
+ });
5857
+ if (++dirCount >= maxFiles) break;
5858
+ }
5608
5859
  return out;
5609
5860
  }
5610
5861
  //#endregion
@@ -6197,7 +6448,7 @@ function createQuestionTool({ requestInteraction }) {
6197
6448
  },
6198
6449
  choices: {
6199
6450
  type: "array",
6200
- description: "For `select`: the available choices. Required.",
6451
+ description: "The available choices. Required when `type` is `select`; omit for other types.",
6201
6452
  items: {
6202
6453
  type: "object",
6203
6454
  properties: {
@@ -6608,7 +6859,8 @@ function buildToolToggle(args) {
6608
6859
  const nextMap = { ...persistedDenyAll ?? {} };
6609
6860
  if (nextForServer.length === 0) delete nextMap[serverName];
6610
6861
  else nextMap[serverName] = nextForServer;
6611
- setDisabledMcpTools(Object.keys(nextMap).length === 0 ? void 0 : nextMap);
6862
+ const next = Object.keys(nextMap).length === 0 ? void 0 : nextMap;
6863
+ setDisabledMcpTools(next);
6612
6864
  };
6613
6865
  return {
6614
6866
  enabledSet,
@@ -6876,7 +7128,7 @@ function parseMcpsFile(text) {
6876
7128
  * a single space). Replacements happen ONLY outside string literals so a
6877
7129
  * user's intentional NBSP inside a `url` or display name is left alone.
6878
7130
  */
6879
- const PROBLEMATIC_WHITESPACE = new Set([
7131
+ const PROBLEMATIC_WHITESPACE = /* @__PURE__ */ new Set([
6880
7132
  65279,
6881
7133
  160,
6882
7134
  8203,
@@ -7106,7 +7358,7 @@ async function runOAuthLogin(descriptor, options) {
7106
7358
  * an arbitrary user-pasted URL from inside the agent process would be a
7107
7359
  * trivial SSRF.
7108
7360
  */
7109
- const LOOPBACK_HOSTS = new Set([
7361
+ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
7110
7362
  "127.0.0.1",
7111
7363
  "localhost",
7112
7364
  "::1",
@@ -7389,7 +7641,8 @@ var ShellParser = class ShellParser {
7389
7641
  btick() {
7390
7642
  this.i++;
7391
7643
  const close = this.s.indexOf("`", this.i);
7392
- const sub = new ShellParser(close < 0 ? this.s.slice(this.i) : this.s.slice(this.i, close));
7644
+ const inner = close < 0 ? this.s.slice(this.i) : this.s.slice(this.i, close);
7645
+ const sub = new ShellParser(inner);
7393
7646
  sub.list();
7394
7647
  this.heads.push(...sub.heads);
7395
7648
  this.i = close < 0 ? this.s.length : close + 1;
@@ -8202,8 +8455,12 @@ function tagEvent(evt, owner, depth, turnId) {
8202
8455
  function smoothCpsForBacklog(backlog) {
8203
8456
  if (backlog <= 0) return 0;
8204
8457
  if (backlog >= SMOOTH_MAX_BACKLOG_CHARS) return SMOOTH_MAX_CPS;
8205
- if (backlog <= SMOOTH_BURST_BACKLOG_CHARS) return SMOOTH_BASE_CPS + backlog / SMOOTH_BURST_BACKLOG_CHARS * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS);
8206
- return SMOOTH_BURST_CPS + (backlog - SMOOTH_BURST_BACKLOG_CHARS) / (SMOOTH_MAX_BACKLOG_CHARS - SMOOTH_BURST_BACKLOG_CHARS) * (SMOOTH_MAX_CPS - SMOOTH_BURST_CPS);
8458
+ if (backlog <= SMOOTH_BURST_BACKLOG_CHARS) {
8459
+ const t = backlog / SMOOTH_BURST_BACKLOG_CHARS;
8460
+ return SMOOTH_BASE_CPS + t * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS);
8461
+ }
8462
+ const t = (backlog - SMOOTH_BURST_BACKLOG_CHARS) / (SMOOTH_MAX_BACKLOG_CHARS - SMOOTH_BURST_BACKLOG_CHARS);
8463
+ return SMOOTH_BURST_CPS + t * (SMOOTH_MAX_CPS - SMOOTH_BURST_CPS);
8207
8464
  }
8208
8465
  /**
8209
8466
  * Number of characters to drain on the next smooth-mode tick + the
@@ -8514,6 +8771,6 @@ function computeTurnAnchors(items) {
8514
8771
  };
8515
8772
  }
8516
8773
  //#endregion
8517
- export { useMcpAuthState as $, eventsFromTurns as $n, useUpdateCheck as $t, runOAuthLogin as A, pruneTodosByRun as An, DEFAULT_THEME as At, saveMcpToolsCache as B, PLAN_MODE_DOCTRINE as Bn, createDiscoverySlot as Bt, projectsFilePath as C, TODO_STATUS_GLYPHS as Cn, SETTINGS_CHOICES as Ct, formatPathForCwd as D, getTodosForRun as Dn, clampFps as Dt, writeProjects as E, getArchivedTodosForRun as En, SettingsProvider as Et, parseMcpsFile as F, COMMUNICATION_DOCTRINE as Fn, GRUVBOX_LIGHT as Ft, buildVisibleMcpRows as G, buildPlanSystem as Gn, useConfig as Gt, buildToolToggle as H, SUBAGENT_GUIDANCE as Hn, useDiscovery as Ht, clearMcpToolsCache as I, DOING_TASKS_DOCTRINE as In, CATPPUCCIN_FRAPPE as It, createFileMcpCredentialStore as J, createChatTurnsReadTool as Jn, useCompletion as Jt, indexOfServerRow as K, envSection as Kn, resolveConfig as Kt, loadMcpToolsCache as L, IDENTITY_PREFIX as Ln, CATPPUCCIN_LATTE as Lt, buildMcpServers as M, setTodosForRun as Mn, resolveTheme as Mt, defaultMcpsConfigPaths as N, useActiveTodos as Nn, VAPORWAVE_THEME as Nt, fetchOAuthRedirect as O, isTodoTool as On, useSettings as Ot, discoverProjectMcps as P, ACTIONS_WITH_CARE_DOCTRINE as Pn, GRUVBOX_DARK as Pt, useMcpAuthDispatch as Q, deriveSessionTitle as Qn, buildUpdateHint as Qt, mcpToolsCachePath as R, INTERACTION_GUIDANCE as Rn, CATPPUCCIN_MACCHIATO as Rt, matchesSafelistEntry as S, TODOWRITE_TOOL as Sn, SETTINGS_CATEGORIES as St, suggestSafelistEntries as T, createTodoTools as Tn, SETTINGS_TOGGLES as Tt, useMcpToolToggleMap as U, TOKEN_DISCIPLINE_DOCTRINE as Un, useDiscoveryOptional as Ut, subscribeMcpToolsCache as V, PLAN_MODE_DOCTRINE_NO_PROMPTS as Vn, DiscoveryProvider as Vt, useMcpToolToggleSet as W, buildBuildSystem as Wn, ConfigProvider as Wt, patchMcpCredential as X, compactSummaryEvent as Xn, bootProfileEnabled as Xt, mcpCredentialsPath as Y, DEFAULT_SESSION_TITLE as Yn, tryOpenBrowser as Yt, McpAuthProvider as Z, createStateStore as Zn, bootTick as Zt, useSafeModeQueue as _, accentColor as _n, buildHints as _t, useSurfaces as a, performInPlaceSelfUpdate as an, serverToolResultSummary as ar, buildResumedToolResultsTurn as at, getSafelist as b, TODOREAD_TOOL as bn, useEnabledToggleSet as bt, useStreamBuffer as c, chatAutoCompactBehavior as cn, titleFromTurns as cr, makeRequestInteraction as ct, discoverProjectSkills as d, BUILD_AGENT as dn, updateToolEventOutcomes as dr, useInteractionsActions as dt, checkForUpdate as en, lastContextSizeFromTurns as er, getMcpAuthStatus as et, renderSession as f, BUILTIN_AGENTS as fn, useInteractionsQueue as ft, useSafeModeActions as g, PLAN_AGENT as gn, truncateTrailing as gt, SafeModeProvider as h, DEFAULT_PERSIST_EXCLUDE_TOOLS as hn, hintsLength as ht, useSelectStyle as i, parseSemver as in, saveState as ir, PRESENT_PLAN_TOOL as it, supportsOAuth as j, selectActiveTodos as jn, resolveChipColor as jt, oauthUsesManualCodePaste as k, pickActiveRunId as kn, BUILTIN_THEMES as kt, buildSkillsConfig as l, discoverAgentsMd as ln, toolCallPreview as lr, pendingInteractionsFromTurns as lt, writeSessionExport as m, DEFAULT_BUDGET_EXCLUDE_TOOLS as mn, clipHintsToWidth as mt, ThemeProvider as n, detectLibc as nn, loadState as nr, ASK_USER_TOOL as nt, useSyntaxStyles as o, performSelfUpdate as on, stripSpawnTokensLine as or, createInteractionTools as ot, resolveSessionExportTarget as p, DEFAULT_AGENT_ID as pn, EMPTY_HINTS as pt, parentServerName as q, chatReferenceTokensForPrompt as qn, resolveStoragePaths as qt, useColors as r, detectPackageManager as rn, marginTopFor as rr, InteractionsProvider as rt, useTheme as s, resolvePlatformPackage as sn, sumRunCosts as sr, isInteractionTool as st, computeTurnAnchors as t, compareSemver as tn, listSessionMeta as tr, reduceMcpAuth as tt, defaultSkillScanPaths as u, renderAgentsMdBlock as un, toolResultText as ur, serializeInteractionResponse as ut, IMPLICITLY_SAFE_TOOLS as v, resolveAgentId as vn, shortChord as vt, readProjects as w, TODO_WRITE_COUNTS_METADATA_KEY as wn, SETTINGS_INPUTS as wt, isOnSafelist as x, TODOS_METADATA_KEY as xn, DEFAULT_SETTINGS as xt, addToSafelist as y, singleAgentRegistry as yn, listProjectFiles as yt, refreshMcpToolsCatalog as z, INTERACTION_GUIDANCE_NO_PROMPTS as zn, CATPPUCCIN_MOCHA as zt };
8774
+ export { useMcpAuthState as $, buildPlanSystem as $n, restoreChainFallbacks as $t, runOAuthLogin as A, TODOWRITE_TOOL as An, DEFAULT_THEME as At, saveMcpToolsCache as B, setTodosForRun as Bn, createDiscoverySlot as Bt, projectsFilePath as C, DEFAULT_PERSIST_EXCLUDE_TOOLS as Cn, SETTINGS_CHOICES as Ct, formatPathForCwd as D, singleAgentRegistry as Dn, clampFps as Dt, writeProjects as E, resolveAgentId as En, SettingsProvider as Et, parseMcpsFile as F, getTodosForRun as Fn, GRUVBOX_LIGHT as Ft, buildVisibleMcpRows as G, IDENTITY_PREFIX as Gn, useConfig as Gt, buildToolToggle as H, ACTIONS_WITH_CARE_DOCTRINE as Hn, useDiscovery as Ht, clearMcpToolsCache as I, isTodoTool as In, CATPPUCCIN_FRAPPE as It, createFileMcpCredentialStore as J, PLAN_MODE_DOCTRINE as Jn, buildRunModel as Jt, indexOfServerRow as K, INTERACTION_GUIDANCE as Kn, resolveConfig as Kt, loadMcpToolsCache as L, pickActiveRunId as Ln, CATPPUCCIN_LATTE as Lt, buildMcpServers as M, TODO_WRITE_COUNTS_METADATA_KEY as Mn, resolveTheme as Mt, defaultMcpsConfigPaths as N, createTodoTools as Nn, VAPORWAVE_THEME as Nt, fetchOAuthRedirect as O, TODOREAD_TOOL as On, useSettings as Ot, discoverProjectMcps as P, getArchivedTodosForRun as Pn, GRUVBOX_DARK as Pt, useMcpAuthDispatch as Q, buildBuildSystem as Qn, providerKeySetChanged as Qt, mcpToolsCachePath as R, pruneTodosByRun as Rn, CATPPUCCIN_MACCHIATO as Rt, matchesSafelistEntry as S, DEFAULT_BUDGET_EXCLUDE_TOOLS as Sn, SETTINGS_CATEGORIES as St, suggestSafelistEntries as T, accentColor as Tn, SETTINGS_TOGGLES as Tt, useMcpToolToggleMap as U, COMMUNICATION_DOCTRINE as Un, useDiscoveryOptional as Ut, subscribeMcpToolsCache as V, useActiveTodos as Vn, DiscoveryProvider as Vt, useMcpToolToggleSet as W, DOING_TASKS_DOCTRINE as Wn, ConfigProvider as Wt, patchMcpCredential as X, SUBAGENT_GUIDANCE as Xn, chainsEqual as Xt, mcpCredentialsPath as Y, PLAN_MODE_DOCTRINE_NO_PROMPTS as Yn, chainPositionOf as Yt, McpAuthProvider as Z, TOKEN_DISCIPLINE_DOCTRINE as Zn, filterChainFallbacks as Zt, useSafeModeQueue as _, discoverAgentsMd as _n, toolCallPreview as _r, buildHints as _t, useSurfaces as a, bootTick as an, createStateStore as ar, buildResumedToolResultsTurn as at, getSafelist as b, BUILTIN_AGENTS as bn, usageByModel as br, useEnabledToggleSet as bt, useStreamBuffer as c, checkForUpdate as cn, lastContextSizeFromTurns as cr, makeRequestInteraction as ct, discoverProjectSkills as d, detectPackageManager as dn, marginTopFor as dr, useInteractionsActions as dt, sanitizeModelChain as en, envSection as er, getMcpAuthStatus as et, renderSession as f, parseSemver as fn, saveState as fr, useInteractionsQueue as ft, useSafeModeActions as g, chatAutoCompactBehavior as gn, titleFromTurns as gr, truncateTrailing as gt, SafeModeProvider as h, resolvePlatformPackage as hn, sumRunCosts as hr, hintsLength as ht, useSelectStyle as i, bootProfileEnabled as in, compactSummaryEvent as ir, PRESENT_PLAN_TOOL as it, supportsOAuth as j, TODO_STATUS_GLYPHS as jn, resolveChipColor as jt, oauthUsesManualCodePaste as k, TODOS_METADATA_KEY as kn, BUILTIN_THEMES as kt, buildSkillsConfig as l, compareSemver as ln, listSessionMeta as lr, pendingInteractionsFromTurns as lt, writeSessionExport as m, performSelfUpdate as mn, stripSpawnTokensLine as mr, clipHintsToWidth as mt, ThemeProvider as n, useCompletion as nn, createChatTurnsReadTool as nr, ASK_USER_TOOL as nt, useSyntaxStyles as o, buildUpdateHint as on, deriveSessionTitle as or, createInteractionTools as ot, resolveSessionExportTarget as p, performInPlaceSelfUpdate as pn, serverToolResultSummary as pr, EMPTY_HINTS as pt, parentServerName as q, INTERACTION_GUIDANCE_NO_PROMPTS as qn, resolveStoragePaths as qt, useColors as r, tryOpenBrowser as rn, DEFAULT_SESSION_TITLE as rr, InteractionsProvider as rt, useTheme as s, useUpdateCheck as sn, eventsFromTurns as sr, isInteractionTool as st, computeTurnAnchors as t, toggleChainEntry as tn, chatReferenceTokensForPrompt as tr, reduceMcpAuth as tt, defaultSkillScanPaths as u, detectLibc as un, loadState as ur, serializeInteractionResponse as ut, IMPLICITLY_SAFE_TOOLS as v, renderAgentsMdBlock as vn, toolResultText as vr, shortChord as vt, readProjects as w, PLAN_AGENT as wn, SETTINGS_INPUTS as wt, isOnSafelist as x, DEFAULT_AGENT_ID as xn, DEFAULT_SETTINGS as xt, addToSafelist as y, BUILD_AGENT as yn, updateToolEventOutcomes as yr, listProjectFiles as yt, refreshMcpToolsCatalog as z, selectActiveTodos as zn, CATPPUCCIN_MOCHA as zt };
8518
8775
 
8519
- //# sourceMappingURL=transcript-anchors-DSRPWjiH.js.map
8776
+ //# sourceMappingURL=transcript-anchors-BTNe1OJi.js.map