@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.5

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 (319) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-q2w43aw3.md} +51 -0
  3. package/dist/cli.js +4148 -3717
  4. package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
  5. package/dist/types/cli/args.d.ts +4 -1
  6. package/dist/types/cli/browser-relay-cli.d.ts +15 -0
  7. package/dist/types/cli/command-help.d.ts +99 -0
  8. package/dist/types/cli/help-extra.d.ts +2 -0
  9. package/dist/types/cli/thinking-levels.d.ts +5 -0
  10. package/dist/types/cli/update-cli.d.ts +13 -0
  11. package/dist/types/commands/browser-relay.d.ts +38 -0
  12. package/dist/types/commands/commit.d.ts +3 -0
  13. package/dist/types/commands/complete.d.ts +1 -1
  14. package/dist/types/commands/completions.d.ts +6 -0
  15. package/dist/types/commands/grep.d.ts +3 -0
  16. package/dist/types/commands/join.d.ts +4 -0
  17. package/dist/types/commands/launch-help.d.ts +171 -0
  18. package/dist/types/commands/launch.d.ts +5 -1
  19. package/dist/types/commands/models.d.ts +3 -0
  20. package/dist/types/commands/say.d.ts +10 -0
  21. package/dist/types/commands/worktree.d.ts +3 -0
  22. package/dist/types/config/keybindings.d.ts +5 -0
  23. package/dist/types/config/model-discovery.d.ts +2 -2
  24. package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
  25. package/dist/types/config/models-config-schema.d.ts +2 -0
  26. package/dist/types/config/models-config.d.ts +1 -0
  27. package/dist/types/config/service-tier.d.ts +2 -0
  28. package/dist/types/config/settings-schema.d.ts +69 -21
  29. package/dist/types/cursor-bridge-tools.d.ts +1 -1
  30. package/dist/types/cursor.d.ts +7 -4
  31. package/dist/types/edit/index.d.ts +3 -3
  32. package/dist/types/edit/modes/replace.d.ts +22 -15
  33. package/dist/types/edit/renderer.d.ts +1 -1
  34. package/dist/types/eval/py/kernel.d.ts +3 -1
  35. package/dist/types/eval/py/spawn-options.d.ts +12 -16
  36. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
  37. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
  38. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  39. package/dist/types/launch/broker.d.ts +1 -1
  40. package/dist/types/launch/client.d.ts +6 -3
  41. package/dist/types/launch/ensure.d.ts +8 -0
  42. package/dist/types/launch/paths.d.ts +1 -1
  43. package/dist/types/launch/protocol.d.ts +2 -2
  44. package/dist/types/lsp/client.d.ts +2 -0
  45. package/dist/types/lsp/mux/daemon.d.ts +15 -0
  46. package/dist/types/lsp/mux/protocol.d.ts +57 -0
  47. package/dist/types/lsp/mux/server.d.ts +18 -0
  48. package/dist/types/lsp/types.d.ts +22 -2
  49. package/dist/types/main.d.ts +2 -0
  50. package/dist/types/mnemopi/embed-client.d.ts +1 -1
  51. package/dist/types/mnemopi/state.d.ts +0 -23
  52. package/dist/types/modes/components/assistant-message.d.ts +2 -0
  53. package/dist/types/modes/components/custom-editor.d.ts +2 -1
  54. package/dist/types/modes/components/read-tool-group.d.ts +2 -0
  55. package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
  56. package/dist/types/modes/components/tool-execution.d.ts +2 -0
  57. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  58. package/dist/types/modes/interactive-mode.d.ts +1 -0
  59. package/dist/types/modes/types.d.ts +1 -0
  60. package/dist/types/modes/workflow.d.ts +2 -1
  61. package/dist/types/sdk.d.ts +3 -1
  62. package/dist/types/secrets/index.d.ts +1 -1
  63. package/dist/types/session/agent-session-types.d.ts +3 -1
  64. package/dist/types/session/indexed-session-storage.d.ts +1 -0
  65. package/dist/types/session/session-advisors.d.ts +1 -1
  66. package/dist/types/session/session-context.d.ts +2 -1
  67. package/dist/types/session/session-maintenance.d.ts +1 -0
  68. package/dist/types/session/session-manager.d.ts +16 -11
  69. package/dist/types/session/session-stats.d.ts +10 -0
  70. package/dist/types/session/session-storage.d.ts +15 -3
  71. package/dist/types/system-prompt.d.ts +4 -1
  72. package/dist/types/task/index.d.ts +2 -1
  73. package/dist/types/task/spawn-policy.d.ts +5 -0
  74. package/dist/types/thinking.d.ts +1 -7
  75. package/dist/types/tools/ast-grep.d.ts +1 -1
  76. package/dist/types/tools/browser/registry.d.ts +2 -1
  77. package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
  78. package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
  79. package/dist/types/tools/browser/relay/kind.d.ts +19 -0
  80. package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
  81. package/dist/types/tools/browser/relay/server.d.ts +35 -0
  82. package/dist/types/tools/browser/render.d.ts +1 -0
  83. package/dist/types/tools/browser.d.ts +3 -0
  84. package/dist/types/tools/computer/exposure.d.ts +9 -7
  85. package/dist/types/tools/computer/protocol.d.ts +70 -17
  86. package/dist/types/tools/computer/supervisor.d.ts +23 -10
  87. package/dist/types/tools/computer/worker-entry.d.ts +1 -0
  88. package/dist/types/tools/computer/worker.d.ts +42 -7
  89. package/dist/types/tools/computer-renderer.d.ts +7 -5
  90. package/dist/types/tools/computer.d.ts +25 -44
  91. package/dist/types/tools/context.d.ts +3 -0
  92. package/dist/types/tools/glob.d.ts +1 -1
  93. package/dist/types/tools/grep.d.ts +1 -1
  94. package/dist/types/tools/render-utils.d.ts +2 -0
  95. package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
  96. package/dist/types/tools/tool-timeouts.d.ts +5 -0
  97. package/dist/types/tools/xdev.d.ts +8 -0
  98. package/dist/types/utils/clipboard.d.ts +2 -2
  99. package/dist/types/web/kagi.d.ts +1 -0
  100. package/dist/types/web/search/index.d.ts +1 -1
  101. package/dist/types/web/search/providers/anthropic.d.ts +1 -0
  102. package/dist/types/web/search/providers/base.d.ts +2 -0
  103. package/dist/types/web/search/providers/brave.d.ts +1 -0
  104. package/dist/types/web/search/providers/browser-page.d.ts +1 -0
  105. package/dist/types/web/search/providers/codex.d.ts +1 -0
  106. package/dist/types/web/search/providers/exa.d.ts +1 -0
  107. package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
  108. package/dist/types/web/search/providers/gemini.d.ts +1 -0
  109. package/dist/types/web/search/providers/jina.d.ts +1 -0
  110. package/dist/types/web/search/providers/kagi.d.ts +1 -0
  111. package/dist/types/web/search/providers/kimi.d.ts +1 -0
  112. package/dist/types/web/search/providers/parallel.d.ts +1 -0
  113. package/dist/types/web/search/providers/perplexity.d.ts +1 -0
  114. package/dist/types/web/search/providers/searxng.d.ts +1 -0
  115. package/dist/types/web/search/providers/tavily.d.ts +1 -0
  116. package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
  117. package/dist/types/web/search/providers/utils.d.ts +6 -9
  118. package/dist/types/web/search/providers/zai.d.ts +1 -0
  119. package/dist/types/web/search/types.d.ts +4 -0
  120. package/package.json +12 -12
  121. package/src/cli/args.ts +7 -87
  122. package/src/cli/browser-relay-cli.ts +119 -0
  123. package/src/cli/command-help.ts +103 -0
  124. package/src/cli/completion-gen.ts +5 -5
  125. package/src/cli/flag-tables.ts +9 -0
  126. package/src/cli/help-extra.ts +89 -0
  127. package/src/cli/setup-cli.ts +13 -21
  128. package/src/cli/thinking-levels.ts +7 -0
  129. package/src/cli/update-cli.ts +26 -7
  130. package/src/cli-commands.ts +170 -33
  131. package/src/cli.ts +17 -5
  132. package/src/commands/acp.ts +3 -1
  133. package/src/commands/agents.ts +3 -2
  134. package/src/commands/auth-broker.ts +3 -2
  135. package/src/commands/auth-gateway.ts +3 -2
  136. package/src/commands/bench.ts +2 -3
  137. package/src/commands/browser-relay.ts +53 -0
  138. package/src/commands/cleanse.ts +2 -2
  139. package/src/commands/commit.ts +3 -2
  140. package/src/commands/complete.ts +2 -1
  141. package/src/commands/completions.ts +3 -2
  142. package/src/commands/config.ts +3 -2
  143. package/src/commands/dry-balance.ts +2 -2
  144. package/src/commands/gallery.ts +3 -2
  145. package/src/commands/gc.ts +3 -2
  146. package/src/commands/grep.ts +3 -2
  147. package/src/commands/grievances.ts +3 -2
  148. package/src/commands/install.ts +2 -2
  149. package/src/commands/join.ts +3 -2
  150. package/src/commands/launch-help.ts +116 -0
  151. package/src/commands/launch.ts +7 -191
  152. package/src/commands/models.ts +3 -2
  153. package/src/commands/plugin.ts +3 -2
  154. package/src/commands/read.ts +3 -2
  155. package/src/commands/say.ts +3 -2
  156. package/src/commands/setup.ts +3 -2
  157. package/src/commands/shell.ts +3 -2
  158. package/src/commands/ssh.ts +3 -2
  159. package/src/commands/stats.ts +3 -2
  160. package/src/commands/tiny-models.ts +2 -2
  161. package/src/commands/token.ts +2 -2
  162. package/src/commands/ttsr.ts +2 -2
  163. package/src/commands/update.ts +3 -2
  164. package/src/commands/usage.ts +3 -2
  165. package/src/commands/web-search.ts +3 -2
  166. package/src/commands/worktree.ts +3 -2
  167. package/src/config/keybindings.ts +5 -0
  168. package/src/config/model-discovery.ts +30 -13
  169. package/src/config/model-registry.ts +9 -5
  170. package/src/config/models-config-schema-bundle.ts +9 -0
  171. package/src/config/resolve-config-value.ts +2 -1
  172. package/src/config/service-tier.ts +5 -0
  173. package/src/config/settings-schema.ts +72 -20
  174. package/src/cursor-bridge-tools.ts +1 -1
  175. package/src/cursor.ts +10 -14
  176. package/src/edit/diff.ts +17 -8
  177. package/src/edit/index.ts +20 -7
  178. package/src/edit/modes/replace.ts +93 -40
  179. package/src/edit/renderer.ts +1 -1
  180. package/src/edit/streaming.ts +14 -17
  181. package/src/eval/py/kernel.ts +2 -1
  182. package/src/eval/py/spawn-options.ts +24 -29
  183. package/src/export/html/template.js +8 -26
  184. package/src/extensibility/extensions/wrapper.ts +1 -0
  185. package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
  186. package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
  187. package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
  188. package/src/extensibility/skills.ts +11 -0
  189. package/src/extensibility/utils.ts +10 -2
  190. package/src/launch/broker.ts +1 -1
  191. package/src/launch/client.ts +32 -13
  192. package/src/launch/ensure.ts +73 -0
  193. package/src/launch/paths.ts +1 -1
  194. package/src/launch/protocol.ts +2 -2
  195. package/src/lsp/client.ts +23 -2
  196. package/src/lsp/index.ts +8 -0
  197. package/src/lsp/mux/daemon.ts +348 -0
  198. package/src/lsp/mux/protocol.ts +96 -0
  199. package/src/lsp/mux/server.ts +797 -0
  200. package/src/lsp/types.ts +28 -2
  201. package/src/main.ts +7 -2
  202. package/src/mcp/oauth-flow.ts +11 -1
  203. package/src/mnemopi/embed-client.ts +49 -2
  204. package/src/mnemopi/state.ts +57 -23
  205. package/src/modes/components/assistant-message.ts +11 -0
  206. package/src/modes/components/chat-transcript-builder.ts +4 -0
  207. package/src/modes/components/custom-editor.ts +9 -0
  208. package/src/modes/components/read-tool-group.ts +10 -0
  209. package/src/modes/components/status-line/component.ts +1 -1
  210. package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
  211. package/src/modes/components/tool-execution.ts +8 -0
  212. package/src/modes/components/tree-selector.ts +46 -48
  213. package/src/modes/controllers/event-controller.ts +17 -0
  214. package/src/modes/controllers/input-controller.ts +39 -1
  215. package/src/modes/controllers/mcp-command-controller.ts +11 -5
  216. package/src/modes/controllers/selector-controller.ts +20 -0
  217. package/src/modes/interactive-mode.ts +2 -0
  218. package/src/modes/types.ts +1 -0
  219. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  220. package/src/modes/utils/interactive-context-helpers.ts +1 -0
  221. package/src/modes/utils/ui-helpers.ts +6 -10
  222. package/src/modes/workflow.ts +8 -2
  223. package/src/prompts/agents/init.md +1 -1
  224. package/src/prompts/system/plan-mode-active.md +2 -2
  225. package/src/prompts/system/system-prompt.md +26 -52
  226. package/src/prompts/system/workflow-notice.md +3 -3
  227. package/src/prompts/tools/ast-grep.md +1 -1
  228. package/src/prompts/tools/bash.md +1 -1
  229. package/src/prompts/tools/browser.md +1 -0
  230. package/src/prompts/tools/computer.md +21 -21
  231. package/src/prompts/tools/glob.md +1 -1
  232. package/src/prompts/tools/grep.md +1 -1
  233. package/src/prompts/tools/replace.md +5 -4
  234. package/src/prompts/tools/task.md +4 -4
  235. package/src/sdk.ts +34 -6
  236. package/src/secrets/index.ts +1 -1
  237. package/src/session/agent-session-types.ts +3 -1
  238. package/src/session/agent-session.ts +13 -1
  239. package/src/session/indexed-session-storage.ts +9 -0
  240. package/src/session/prewalk.ts +24 -2
  241. package/src/session/session-advisors.ts +2 -2
  242. package/src/session/session-context.ts +16 -12
  243. package/src/session/session-dump-format.ts +1 -1
  244. package/src/session/session-maintenance.ts +38 -4
  245. package/src/session/session-manager.ts +102 -67
  246. package/src/session/session-paths.ts +118 -55
  247. package/src/session/session-stats.ts +48 -3
  248. package/src/session/session-storage.ts +30 -22
  249. package/src/session/stream-guards.ts +1 -1
  250. package/src/slash-commands/builtin-registry.ts +27 -24
  251. package/src/system-prompt.ts +8 -3
  252. package/src/task/index.ts +23 -8
  253. package/src/task/spawn-policy.ts +14 -0
  254. package/src/thinking.ts +2 -8
  255. package/src/tools/ast-grep.ts +10 -4
  256. package/src/tools/browser/cmux/cmux-tab.ts +5 -10
  257. package/src/tools/browser/cmux/rpc.ts +2 -8
  258. package/src/tools/browser/registry.ts +53 -2
  259. package/src/tools/browser/relay/bridge.ts +945 -0
  260. package/src/tools/browser/relay/daemon.ts +117 -0
  261. package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
  262. package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
  263. package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
  264. package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
  265. package/src/tools/browser/relay/kind.ts +41 -0
  266. package/src/tools/browser/relay/protocol.ts +54 -0
  267. package/src/tools/browser/relay/server.ts +141 -0
  268. package/src/tools/browser/render.ts +4 -1
  269. package/src/tools/browser/shared-daemon.ts +7 -58
  270. package/src/tools/browser/tab-supervisor.ts +5 -4
  271. package/src/tools/browser/tab-worker.ts +33 -12
  272. package/src/tools/browser.ts +26 -1
  273. package/src/tools/computer/exposure.ts +11 -35
  274. package/src/tools/computer/protocol.ts +51 -10
  275. package/src/tools/computer/supervisor.ts +227 -124
  276. package/src/tools/computer/worker-entry.ts +11 -6
  277. package/src/tools/computer/worker.ts +695 -81
  278. package/src/tools/computer-renderer.ts +104 -65
  279. package/src/tools/computer.ts +134 -428
  280. package/src/tools/context.ts +3 -0
  281. package/src/tools/glob.ts +9 -2
  282. package/src/tools/grep.ts +12 -6
  283. package/src/tools/inspect-image.ts +32 -6
  284. package/src/tools/render-utils.ts +2 -0
  285. package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
  286. package/src/tools/tool-timeouts.ts +1 -0
  287. package/src/tools/xdev.ts +29 -2
  288. package/src/utils/clipboard.ts +40 -14
  289. package/src/utils/command-args.ts +26 -28
  290. package/src/utils/tool-choice.ts +0 -13
  291. package/src/web/kagi.ts +2 -1
  292. package/src/web/search/index.ts +18 -2
  293. package/src/web/search/providers/anthropic.ts +4 -1
  294. package/src/web/search/providers/base.ts +2 -0
  295. package/src/web/search/providers/brave.ts +3 -1
  296. package/src/web/search/providers/browser-page.ts +6 -4
  297. package/src/web/search/providers/codex.ts +4 -1
  298. package/src/web/search/providers/duckduckgo.ts +2 -1
  299. package/src/web/search/providers/ecosia.ts +2 -1
  300. package/src/web/search/providers/exa.ts +4 -2
  301. package/src/web/search/providers/firecrawl.ts +3 -1
  302. package/src/web/search/providers/gemini.ts +8 -2
  303. package/src/web/search/providers/google.ts +2 -1
  304. package/src/web/search/providers/jina.ts +12 -2
  305. package/src/web/search/providers/kagi.ts +3 -0
  306. package/src/web/search/providers/kimi.ts +5 -1
  307. package/src/web/search/providers/mojeek.ts +2 -1
  308. package/src/web/search/providers/parallel.ts +5 -1
  309. package/src/web/search/providers/perplexity.ts +6 -3
  310. package/src/web/search/providers/public.ts +1 -1
  311. package/src/web/search/providers/searxng.ts +11 -5
  312. package/src/web/search/providers/startpage.ts +10 -4
  313. package/src/web/search/providers/synthetic.ts +11 -5
  314. package/src/web/search/providers/tavily.ts +3 -1
  315. package/src/web/search/providers/tinyfish.ts +3 -1
  316. package/src/web/search/providers/utils.ts +12 -10
  317. package/src/web/search/providers/xai.ts +2 -2
  318. package/src/web/search/providers/zai.ts +18 -3
  319. package/src/web/search/types.ts +6 -0
@@ -13,7 +13,13 @@ import {
13
13
  } from "@oh-my-pi/pi-tui";
14
14
  import type { TreeFilterMode } from "../../config/settings-schema";
15
15
  import { theme } from "../../modes/theme/theme";
16
- import { matchesAppInterrupt, matchesSelectDown, matchesSelectUp } from "../../modes/utils/keybinding-matchers";
16
+ import {
17
+ matchesAppInterrupt,
18
+ matchesSelectDown,
19
+ matchesSelectPageDown,
20
+ matchesSelectPageUp,
21
+ matchesSelectUp,
22
+ } from "../../modes/utils/keybinding-matchers";
17
23
  import type { SessionTreeNode } from "../../session/session-entries";
18
24
  import { toPathList } from "../../tools/path-utils";
19
25
  import { shortenPath } from "../../tools/render-utils";
@@ -144,13 +150,12 @@ class TreeList implements Component {
144
150
  const result: FlatNode[] = [];
145
151
  this.#toolCallMap.clear();
146
152
 
147
- // Indentation rules:
148
- // - At indent 0: stay at 0 unless parent has >1 children (then +1)
149
- // - At indent 1: children always go to indent 2 (visual grouping of subtree)
150
- // - At indent 2+: stay flat for single-child chains, +1 only if parent branches
153
+ // A real branch point adds one indentation level. Linear conversation
154
+ // chains retain that level so their text stays aligned with the branch
155
+ // head instead of drifting right after every fork.
151
156
 
152
- // Stack items: [node, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild]
153
- type StackItem = [SessionTreeNode, number, boolean, boolean, boolean, GutterInfo[], boolean];
157
+ // Stack items: [node, indent, showConnector, isLast, gutters, isVirtualRootChild]
158
+ type StackItem = [SessionTreeNode, number, boolean, boolean, GutterInfo[], boolean];
154
159
  const stack: StackItem[] = [];
155
160
 
156
161
  // Determine which subtrees contain the active leaf (to sort current branch first)
@@ -188,11 +193,11 @@ class TreeList implements Component {
188
193
  const orderedRoots = [...roots].sort((a, b) => Number(containsActive.get(b)) - Number(containsActive.get(a)));
189
194
  for (let i = orderedRoots.length - 1; i >= 0; i--) {
190
195
  const isLast = i === orderedRoots.length - 1;
191
- stack.push([orderedRoots[i], multipleRoots ? 1 : 0, multipleRoots, multipleRoots, isLast, [], multipleRoots]);
196
+ stack.push([orderedRoots[i], multipleRoots ? 1 : 0, multipleRoots, isLast, [], multipleRoots]);
192
197
  }
193
198
 
194
199
  while (stack.length > 0) {
195
- const [node, indent, justBranched, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop()!;
200
+ const [node, indent, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop()!;
196
201
 
197
202
  // Extract tool calls from assistant messages for later lookup
198
203
  const entry = node.entry;
@@ -227,18 +232,10 @@ class TreeList implements Component {
227
232
  return [...prioritized, ...rest];
228
233
  })();
229
234
 
230
- // Calculate child indent
231
- let childIndent: number;
232
- if (multipleChildren) {
233
- // Parent branches: children get +1
234
- childIndent = indent + 1;
235
- } else if (justBranched && indent > 0) {
236
- // First generation after a branch: +1 for visual grouping
237
- childIndent = indent + 1;
238
- } else {
239
- // Single-child chain: stay flat
240
- childIndent = indent;
241
- }
235
+ // Real branch points add visual depth, and a virtual root's direct
236
+ // children (the session roots) nest one level under the shared column-0
237
+ // root. Linear continuations otherwise stay aligned with their head.
238
+ const childIndent = multipleChildren || isVirtualRootChild ? indent + 1 : indent;
242
239
 
243
240
  // Build gutters for children
244
241
  // If this node showed a connector, add a gutter entry for descendants
@@ -255,15 +252,7 @@ class TreeList implements Component {
255
252
  // Add children in reverse order
256
253
  for (let i = orderedChildren.length - 1; i >= 0; i--) {
257
254
  const childIsLast = i === orderedChildren.length - 1;
258
- stack.push([
259
- orderedChildren[i],
260
- childIndent,
261
- multipleChildren,
262
- multipleChildren,
263
- childIsLast,
264
- childGutters,
265
- false,
266
- ]);
255
+ stack.push([orderedChildren[i], childIndent, multipleChildren, childIsLast, childGutters, false]);
267
256
  }
268
257
  }
269
258
 
@@ -516,16 +505,8 @@ class TreeList implements Component {
516
505
  const renderedIndent = Math.min(displayIndent, maxIndentLevels);
517
506
  const scrollOffset = displayIndent - renderedIndent;
518
507
  const connectorPositionDisplay = hasConnector ? renderedIndent - 1 : -1;
519
- // Chain rows (no connector of their own) under a last-sibling (`└─`)
520
- // branch stay anchored by a vertical drawn one level RIGHT of the
521
- // suppressed gutter — the column where the row's own connector would
522
- // sit, directly below the branch head's content. Drawing it in the
523
- // `└─` column itself contradicts the corner and leaves dangling,
524
- // drifting verticals once the chain branches deeper (#2298, #2325).
525
- // Chains under `├─` heads need no extra anchor: the sibling line
526
- // (`show: true` gutter) already ties them to their branch.
527
- const nearestGutter = !hasConnector ? flatNode.gutters[flatNode.gutters.length - 1] : undefined;
528
- const chainAnchorLevel = nearestGutter && !nearestGutter.show ? nearestGutter.position + 1 : -1;
508
+ // Linear rows reuse their branch head's depth. Existing sibling
509
+ // gutters remain visible; terminal gutters remain terminated.
529
510
 
530
511
  // Build prefix char by char, placing gutters and connector at their positions
531
512
  const totalChars = renderedIndent * 3;
@@ -545,9 +526,6 @@ class TreeList implements Component {
545
526
  } else {
546
527
  prefixChars.push(" ");
547
528
  }
548
- } else if (originalLevel === chainAnchorLevel) {
549
- // Chain anchor for rows under a `└─` branch head.
550
- prefixChars.push(posInLevel === 0 ? theme.tree.vertical : " ");
551
529
  } else if (hasConnector && level === connectorPositionDisplay) {
552
530
  // Connector at this level
553
531
  if (posInLevel === 0) {
@@ -781,16 +759,36 @@ class TreeList implements Component {
781
759
  }
782
760
  }
783
761
 
762
+ #moveToAdjacentTurn(direction: -1 | 1): void {
763
+ for (
764
+ let index = this.#selectedIndex + direction;
765
+ index >= 0 && index < this.#filteredNodes.length;
766
+ index += direction
767
+ ) {
768
+ const entry = this.#filteredNodes[index]?.node.entry;
769
+ if (entry?.type === "message" && (entry.message.role === "user" || entry.message.role === "assistant")) {
770
+ this.#selectedIndex = index;
771
+ return;
772
+ }
773
+ }
774
+ }
775
+
784
776
  handleInput(keyData: string): void {
785
777
  if (matchesSelectUp(keyData)) {
786
778
  this.#selectedIndex = this.#selectedIndex === 0 ? this.#filteredNodes.length - 1 : this.#selectedIndex - 1;
787
779
  } else if (matchesSelectDown(keyData)) {
788
780
  this.#selectedIndex = this.#selectedIndex === this.#filteredNodes.length - 1 ? 0 : this.#selectedIndex + 1;
789
- } else if (matchesKey(keyData, "left")) {
790
- // Page up
781
+ } else if (matchesKey(keyData, "alt+up")) {
782
+ this.#moveToAdjacentTurn(-1);
783
+ } else if (matchesKey(keyData, "alt+down")) {
784
+ this.#moveToAdjacentTurn(1);
785
+ } else if (matchesKey(keyData, "home")) {
786
+ this.#selectedIndex = 0;
787
+ } else if (matchesKey(keyData, "end")) {
788
+ this.#selectedIndex = Math.max(0, this.#filteredNodes.length - 1);
789
+ } else if (matchesSelectPageUp(keyData) || matchesKey(keyData, "left")) {
791
790
  this.#selectedIndex = Math.max(0, this.#selectedIndex - this.maxVisibleLines);
792
- } else if (matchesKey(keyData, "right")) {
793
- // Page down
791
+ } else if (matchesSelectPageDown(keyData) || matchesKey(keyData, "right")) {
794
792
  this.#selectedIndex = Math.min(this.#filteredNodes.length - 1, this.#selectedIndex + this.maxVisibleLines);
795
793
  } else if (matchesKey(keyData, "shift+enter") || matchesKey(keyData, "shift+return")) {
796
794
  // Summarize-and-switch: fork with a branch summary without the extra prompt.
@@ -954,7 +952,7 @@ export class TreeSelectorComponent extends Container {
954
952
  new TruncatedText(
955
953
  theme.fg(
956
954
  "muted",
957
- "Enter: switch. Shift+Enter: summarize & switch. Shift+L: label. Ctrl+O: filter. Alt+D/T/U/L/A: filter. Type to search",
955
+ "Enter: switch. Alt+↑/↓: previous/next turn. PgUp/PgDn (←/→): page. Home/End: first/last item. Shift+Enter: summarize & switch. Shift+L: label. Ctrl+O: filter. Alt+D/T/U/L/A: filter. Type to search",
958
956
  ),
959
957
  0,
960
958
  0,
@@ -276,6 +276,7 @@ export class EventController {
276
276
  showContentPreview: this.ctx.settings.get("read.toolResultPreview"),
277
277
  });
278
278
  group.setExpanded(this.ctx.toolOutputExpanded);
279
+ group.setToolActivityVisible(!this.ctx.hideToolActivity);
279
280
  this.ctx.chatContainer.addChild(group);
280
281
  this.#lastReadGroup = group;
281
282
  }
@@ -927,6 +928,7 @@ export class EventController {
927
928
  content.id,
928
929
  );
929
930
  component.setExpanded(this.ctx.toolOutputExpanded);
931
+ component.setToolActivityVisible(!this.ctx.hideToolActivity);
930
932
  this.ctx.chatContainer.addChild(component);
931
933
  this.ctx.pendingTools.set(content.id, component);
932
934
  this.#toolTimelineComponents.set(content.id, component);
@@ -1176,6 +1178,7 @@ export class EventController {
1176
1178
  event.toolCallId,
1177
1179
  );
1178
1180
  component.setExpanded(this.ctx.toolOutputExpanded);
1181
+ component.setToolActivityVisible(!this.ctx.hideToolActivity);
1179
1182
  this.ctx.chatContainer.addChild(component);
1180
1183
  this.ctx.pendingTools.set(event.toolCallId, component);
1181
1184
  this.#toolTimelineComponents.set(event.toolCallId, component);
@@ -1464,6 +1467,20 @@ export class EventController {
1464
1467
  // the loader and finalizes it at its own agent_end (isStreaming === false by
1465
1468
  // then). Mirrors the collab guest's !isStreaming loader reconciler.
1466
1469
  if (this.ctx.session.isStreaming) return;
1470
+ // A non-terminal settle (`isTerminal: false`) is a scheduling pause, not the
1471
+ // end of the run: an unsuppressed async job (a `/vibe` worker turn, a bash
1472
+ // `async` job, etc.) will re-wake the loop when its result is delivered.
1473
+ // `AgentSession` tags this on the deferred event (see `#hasPendingAsyncWake`
1474
+ // in agent-session.ts). Skip the idle title/loader teardown so the tab keeps
1475
+ // reading "working"; the later terminal `agent_end` performs it. Still flush
1476
+ // a deferred model switch — the plan-mode reconciler queues it to apply once
1477
+ // the current stream ends, and `#finishAgentEnd` is otherwise its only flush
1478
+ // site, so the automatic continuation would otherwise run on the old
1479
+ // model/thinking level until the terminal settle.
1480
+ if (event.isTerminal === false) {
1481
+ await this.ctx.flushPendingModelSwitch();
1482
+ return;
1483
+ }
1467
1484
  setTerminalTitleState("idle");
1468
1485
 
1469
1486
  await this.#finishAgentEnd(event);
@@ -8,8 +8,11 @@ import { isSettingsInitialized, settings } from "../../config/settings";
8
8
  import { resolveLocalRoot } from "../../internal-urls";
9
9
  import { AssistantMessageComponent } from "../../modes/components/assistant-message";
10
10
  import { extractImagePathFromText } from "../../modes/components/custom-editor";
11
+ import { ReadToolGroupComponent } from "../../modes/components/read-tool-group";
11
12
  import { renderSegmentTrack } from "../../modes/components/segment-track";
13
+ import { StrippedToolCallsPlaceholder } from "../../modes/components/stripped-tool-calls-placeholder";
12
14
  import { TinyTitleDownloadProgressComponent } from "../../modes/components/tiny-title-download-progress";
15
+ import { ToolExecutionComponent } from "../../modes/components/tool-execution";
13
16
  import { expandEmoticons } from "../../modes/emoji-autocomplete";
14
17
  import { materializeImageReferenceLinks, shiftImageMarkers } from "../../modes/image-references";
15
18
  import { createPromptActionAutocompleteProvider } from "../../modes/prompt-action-autocomplete";
@@ -327,10 +330,10 @@ export class InputController {
327
330
  }
328
331
 
329
332
  if (this.ctx.loopModeEnabled) {
330
- this.ctx.pauseLoop();
331
333
  if (this.ctx.session.isStreaming) {
332
334
  this.#abortStreamingTurn();
333
335
  } else {
336
+ this.ctx.pauseLoop();
334
337
  this.ctx.cancelPendingSubmission();
335
338
  }
336
339
  return;
@@ -455,6 +458,11 @@ export class InputController {
455
458
  this.ctx.editor.onCopyPrompt = () => this.handleCopyPrompt();
456
459
  this.ctx.editor.setActionKeys("app.tools.expand", this.ctx.keybindings.getKeys("app.tools.expand"));
457
460
  this.ctx.editor.onExpandTools = () => this.toggleToolOutputExpansion();
461
+ this.ctx.editor.setActionKeys(
462
+ "app.tools.toggleVisibility",
463
+ this.ctx.keybindings.getKeys("app.tools.toggleVisibility"),
464
+ );
465
+ this.ctx.editor.onToggleToolActivity = () => this.toggleToolActivityVisibility();
458
466
  this.ctx.editor.setActionKeys("app.message.dequeue", this.ctx.keybindings.getKeys("app.message.dequeue"));
459
467
  this.ctx.editor.onDequeue = () => this.handleDequeue();
460
468
  this.ctx.editor.setActionKeys("app.retry", this.ctx.keybindings.getKeys("app.retry"));
@@ -1845,9 +1853,39 @@ export class InputController {
1845
1853
  }
1846
1854
 
1847
1855
  toggleToolOutputExpansion(): void {
1856
+ if (this.ctx.hideToolActivity) {
1857
+ const visibilityKey = this.ctx.keybindings.getDisplayString("app.tools.toggleVisibility");
1858
+ const visibilityHint = visibilityKey ? `${visibilityKey} or /settings` : "/settings";
1859
+ this.ctx.showStatus(`Tool activity is hidden — show it with ${visibilityHint} before expanding`);
1860
+ return;
1861
+ }
1848
1862
  this.setToolsExpanded(!this.ctx.toolOutputExpanded);
1849
1863
  }
1850
1864
 
1865
+ toggleToolActivityVisibility(): void {
1866
+ this.ctx.hideToolActivity = !this.ctx.hideToolActivity;
1867
+ this.ctx.settings.set("display.hideToolActivity", this.ctx.hideToolActivity);
1868
+
1869
+ if (!this.ctx.hideToolActivity) {
1870
+ this.ctx.toolOutputExpanded = false;
1871
+ }
1872
+
1873
+ for (const child of this.ctx.chatContainer.children) {
1874
+ if (child instanceof ToolExecutionComponent || child instanceof ReadToolGroupComponent) {
1875
+ if (!this.ctx.hideToolActivity) child.setExpanded(false);
1876
+ child.setToolActivityVisible(!this.ctx.hideToolActivity);
1877
+ } else if (child instanceof AssistantMessageComponent) {
1878
+ child.setToolResultImagesVisible(!this.ctx.hideToolActivity);
1879
+ } else if (child instanceof StrippedToolCallsPlaceholder) {
1880
+ child.setToolActivityVisible(!this.ctx.hideToolActivity);
1881
+ }
1882
+ }
1883
+
1884
+ if (this.ctx.hideToolActivity) this.ctx.ui.clearInlineImages();
1885
+ this.ctx.ui.resetDisplay();
1886
+ this.ctx.showStatus(`Tool activity: ${this.ctx.hideToolActivity ? "hidden" : "visible"}`);
1887
+ }
1888
+
1851
1889
  setToolsExpanded(expanded: boolean): void {
1852
1890
  this.ctx.toolOutputExpanded = expanded;
1853
1891
  for (const child of this.ctx.chatContainer.children) {
@@ -1793,16 +1793,22 @@ export class MCPCommandController {
1793
1793
  const oauth = await this.#resolveOAuthEndpointsFromServer(runtimeBaseConfig, options.authChallenge);
1794
1794
  const serverUrl =
1795
1795
  runtimeBaseConfig.type === "http" || runtimeBaseConfig.type === "sse" ? runtimeBaseConfig.url : undefined;
1796
- // A user-supplied client secret may live in either block (the wizard
1797
- // writes it to auth.clientSecret); DCR secrets are embedded in the
1798
- // stored credential and never echoed back into config files.
1799
- const configuredClientId = found.config.oauth?.clientId ?? currentAuth?.clientId;
1796
+ // Client credentials drive the token exchange, so they must come from the
1797
+ // env-expanded runtime config; `found.config`/`currentAuth` may still hold
1798
+ // `${...}` placeholders (the wizard writes the secret to auth.clientSecret).
1799
+ // DCR secrets are embedded in the stored credential and never echoed back
1800
+ // into config files.
1801
+ const runtimeAuth = currentAuth ? expandEnvVarsDeep(currentAuth) : undefined;
1802
+ const configuredClientId = runtimeBaseConfig.oauth?.clientId ?? runtimeAuth?.clientId;
1800
1803
  const existingCredential = lookupMcpOAuthCredentialForServer(authStorage, currentAuth, serverUrl)?.credential;
1801
1804
  const flowClientId = oauth.clientId ?? configuredClientId ?? existingCredential?.clientId ?? "";
1802
1805
  const storedClientSecret =
1803
1806
  existingCredential?.clientId === flowClientId ? existingCredential.clientSecret : undefined;
1807
+ const flowClientSecret =
1808
+ runtimeBaseConfig.oauth?.clientSecret ?? runtimeAuth?.clientSecret ?? storedClientSecret ?? "";
1809
+ // Persisted separately below: keep the raw `${...}` placeholder in the file
1810
+ // rather than writing the resolved secret back to (possibly shared) config.
1804
1811
  const userClientSecret = found.config.oauth?.clientSecret ?? currentAuth?.clientSecret;
1805
- const flowClientSecret = userClientSecret ?? storedClientSecret ?? "";
1806
1812
 
1807
1813
  if (!options.silent) {
1808
1814
  this.#showMessage(["", theme.fg("muted", `Reauthorizing "${name}"...`), ""].join("\n"));
@@ -92,11 +92,13 @@ import { ModelHubComponent, type ModelRoleSelectionScope } from "../components/m
92
92
  import { ModelPickerComponent } from "../components/model-picker";
93
93
  import { OAuthSelectorComponent } from "../components/oauth-selector";
94
94
  import { PluginSelectorComponent } from "../components/plugin-selector";
95
+ import { ReadToolGroupComponent } from "../components/read-tool-group";
95
96
  import { ResetUsageSelectorComponent } from "../components/reset-usage-selector";
96
97
  import { renderSegmentTrack } from "../components/segment-track";
97
98
  import { SessionAccountSelectorComponent } from "../components/session-account-selector";
98
99
  import { SessionSelectorComponent, type SessionSelectorOptions } from "../components/session-selector";
99
100
  import { SettingsSelectorComponent } from "../components/settings-selector";
101
+ import { StrippedToolCallsPlaceholder } from "../components/stripped-tool-calls-placeholder";
100
102
  import { ToolExecutionComponent } from "../components/tool-execution";
101
103
  import { TranscriptBlock } from "../components/transcript-container";
102
104
  import { TreeSelectorComponent } from "../components/tree-selector";
@@ -474,6 +476,24 @@ export class SelectorController {
474
476
  break;
475
477
 
476
478
  // Settings with UI side effects
479
+ case "display.hideToolActivity": {
480
+ const hidden = value as boolean;
481
+ this.ctx.hideToolActivity = hidden;
482
+ if (!hidden) this.ctx.toolOutputExpanded = false;
483
+ for (const child of this.ctx.chatContainer.children) {
484
+ if (child instanceof ToolExecutionComponent || child instanceof ReadToolGroupComponent) {
485
+ if (!hidden) child.setExpanded(false);
486
+ child.setToolActivityVisible(!hidden);
487
+ } else if (child instanceof AssistantMessageComponent) {
488
+ child.setToolResultImagesVisible(!hidden);
489
+ } else if (child instanceof StrippedToolCallsPlaceholder) {
490
+ child.setToolActivityVisible(!hidden);
491
+ }
492
+ }
493
+ if (hidden) this.ctx.ui.clearInlineImages();
494
+ this.ctx.ui.resetDisplay();
495
+ break;
496
+ }
477
497
  case "terminal.showImages":
478
498
  case "showImages": {
479
499
  const visible = value as boolean;
@@ -460,6 +460,7 @@ export class InteractiveMode implements InteractiveModeContext {
460
460
  initialChatRendered = false;
461
461
  isBashMode = false;
462
462
  toolOutputExpanded = false;
463
+ hideToolActivity = false;
463
464
  todoExpanded = false;
464
465
  planModeEnabled = false;
465
466
  planModePaused = false;
@@ -778,6 +779,7 @@ export class InteractiveMode implements InteractiveModeContext {
778
779
  // hot path where the render never gets to paint the result.
779
780
  this.editor.setTopBorderProvider(availableWidth => this.statusLine.getTopBorder(availableWidth));
780
781
 
782
+ this.hideToolActivity = settings.get("display.hideToolActivity");
781
783
  this.hideThinkingBlock = settings.get("hideThinkingBlock");
782
784
  this.proseOnlyThinking = settings.get("proseOnlyThinking");
783
785
 
@@ -162,6 +162,7 @@ export interface InteractiveModeContext {
162
162
  initialChatRendered: boolean;
163
163
  isBashMode: boolean;
164
164
  toolOutputExpanded: boolean;
165
+ hideToolActivity: boolean;
165
166
  todoExpanded: boolean;
166
167
  planModeEnabled: boolean;
167
168
  vibeModeEnabled: boolean;
@@ -46,6 +46,7 @@ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string
46
46
  `| \`${appKey(bindings, "app.plan.toggle")}\` | Toggle plan mode |`,
47
47
  `| \`${appKey(bindings, "app.history.search")}\` | Search prompt history |`,
48
48
  `| \`${appKey(bindings, "app.tools.expand")}\` | Toggle tool output expansion |`,
49
+ `| \`${appKey(bindings, "app.tools.toggleVisibility")}\` | Toggle tool activity visibility |`,
49
50
  `| \`${appKey(bindings, "app.thinking.toggle")}\` | Toggle thinking block visibility |`,
50
51
  `| \`${appKey(bindings, "app.editor.external")}\` | Edit message in external editor |`,
51
52
  `| \`${appKey(bindings, "app.retry")}\` | Retry last failed assistant turn |`,
@@ -25,6 +25,7 @@ export function createAssistantMessageComponent(
25
25
  ctx.proseOnlyThinking,
26
26
  );
27
27
  component.setImagesVisible(ctx.settings.get("terminal.showImages"));
28
+ component.setToolResultImagesVisible(!ctx.hideToolActivity);
28
29
  component.setExpanded(ctx.toolOutputExpanded);
29
30
  return component;
30
31
  }
@@ -31,6 +31,7 @@ import {
31
31
  readArgsCollapseIntoGroup,
32
32
  } from "../../modes/components/read-tool-group";
33
33
  import { SkillMessageComponent } from "../../modes/components/skill-message";
34
+ import { StrippedToolCallsPlaceholder } from "../../modes/components/stripped-tool-calls-placeholder";
34
35
  import { ToolExecutionComponent } from "../../modes/components/tool-execution";
35
36
  import { TranscriptBlock } from "../../modes/components/transcript-container";
36
37
  import { createUsageRowBlock } from "../../modes/components/usage-row";
@@ -444,6 +445,7 @@ export class UiHelpers {
444
445
  showContentPreview: this.ctx.settings.get("read.toolResultPreview"),
445
446
  });
446
447
  readGroup.setExpanded(this.ctx.toolOutputExpanded);
448
+ readGroup.setToolActivityVisible(!this.ctx.hideToolActivity);
447
449
  this.ctx.chatContainer.addChild(readGroup);
448
450
  }
449
451
  readGroup.updateArgs(content.arguments, content.id);
@@ -458,6 +460,7 @@ export class UiHelpers {
458
460
  showContentPreview: this.ctx.settings.get("read.toolResultPreview"),
459
461
  });
460
462
  readGroup.setExpanded(this.ctx.toolOutputExpanded);
463
+ readGroup.setToolActivityVisible(!this.ctx.hideToolActivity);
461
464
  this.ctx.chatContainer.addChild(readGroup);
462
465
  }
463
466
  readGroup.updateArgs(content.arguments, content.id);
@@ -510,6 +513,7 @@ export class UiHelpers {
510
513
  content.id,
511
514
  );
512
515
  component.setExpanded(this.ctx.toolOutputExpanded);
516
+ component.setToolActivityVisible(!this.ctx.hideToolActivity);
513
517
  this.ctx.chatContainer.addChild(component);
514
518
 
515
519
  if (hasErrorStop && errorMessage) {
@@ -531,16 +535,7 @@ export class UiHelpers {
531
535
  const strippedToolCalls = (message as AgentMessage & StrippedToolCallsMarker).strippedToolCalls ?? 0;
532
536
  if (strippedToolCalls > 0) {
533
537
  this.ctx.chatContainer.addChild(
534
- new Text(
535
- theme.fg(
536
- "dim",
537
- theme.italic(
538
- `${strippedToolCalls} tool call${strippedToolCalls === 1 ? "" : "s"} elided — no result on this branch`,
539
- ),
540
- ),
541
- 1,
542
- 0,
543
- ),
538
+ new StrippedToolCallsPlaceholder(strippedToolCalls, !this.ctx.hideToolActivity),
544
539
  );
545
540
  }
546
541
  pendingUsage =
@@ -578,6 +573,7 @@ export class UiHelpers {
578
573
  showContentPreview: this.ctx.settings.get("read.toolResultPreview"),
579
574
  });
580
575
  readGroup.setExpanded(this.ctx.toolOutputExpanded);
576
+ readGroup.setToolActivityVisible(!this.ctx.hideToolActivity);
581
577
  this.ctx.chatContainer.addChild(readGroup);
582
578
  }
583
579
  const args = readToolCallArgs.get(message.toolCallId);
@@ -23,8 +23,14 @@ const WORKFLOW_WORD = magicKeywordRegex("workflowz");
23
23
  export const WORKFLOW_NOTICE: string = renderWorkflowNotice({ taskBatch: true });
24
24
 
25
25
  /** renderWorkflowNotice renders the workflow notice for the active task schema. */
26
- export function renderWorkflowNotice({ taskBatch }: { taskBatch: boolean }): string {
27
- return prompt.render(workflowNoticeTemplate, { taskBatch }).trim();
26
+ export function renderWorkflowNotice({
27
+ taskBatch,
28
+ scoutAvailable,
29
+ }: {
30
+ taskBatch: boolean;
31
+ scoutAvailable?: boolean;
32
+ }): string {
33
+ return prompt.render(workflowNoticeTemplate, { taskBatch, scoutAvailable: scoutAvailable ?? true }).trim();
28
34
  }
29
35
 
30
36
  /**
@@ -4,7 +4,7 @@ description: Generate AGENTS.md for current codebase
4
4
  thinking-level: medium
5
5
  ---
6
6
 
7
- Generate AGENTS.md by launching multiple `scout` agents in parallel (via `task` tool) scanning different areas (core src, tests, configs/build, scripts/docs), then synthesize findings into a single file.
7
+ Generate AGENTS.md by launching multiple research agents in parallel (via `task` tool) to scan different areas (core src, tests, configs/build, scripts/docs), then synthesize findings into a single file.
8
8
 
9
9
  <structure>
10
10
  - **Project Overview**: Brief description of project purpose
@@ -40,7 +40,7 @@ Write each section together with its body — `N*` needs a multi-line section; a
40
40
 
41
41
  You eliminate unknowns by discovering facts, not by asking.
42
42
 
43
- - **Discoverable facts** (file locations, current behavior, signatures, configs): you MUST find them yourself with `glob`, `grep`, `read`, or parallel `scout` subagents. Every path, symbol, signature, and behavior the plan states as fact MUST come from something you actually read this session. Anything you could not confirm you mark inline (`unverified — confirm first`); you NEVER present a guess as settled. Ask only when several real candidates survive exploration — then present them with a recommendation.
43
+ - **Discoverable facts** (file locations, current behavior, signatures, configs): you MUST find them yourself with `glob`, `grep`, `read`,{{#if scoutAvailable}} or parallel `scout` subagents{{/if}}. Every path, symbol, signature, and behavior the plan states as fact MUST come from something you actually read this session. Anything you could not confirm you mark inline (`unverified — confirm first`); you NEVER present a guess as settled. Ask only when several real candidates survive exploration — then present them with a recommendation.
44
44
  - **Preferences and tradeoffs** (intent, UX, scope edges, performance-vs-simplicity): not derivable from code. Surface these early via `{{askToolName}}` with 2–4 mutually exclusive options and a recommended default. Left unanswered → proceed with the default and record it under Assumptions.
45
45
 
46
46
  Every question MUST change the plan or settle a load-bearing choice. Batch them. You NEVER ask what exploration answers, and you NEVER ask filler.
@@ -72,7 +72,7 @@ You are re-entering plan mode with a NEW request. That new request is the primar
72
72
  ## Workflow — parallel
73
73
 
74
74
  <procedure>
75
- 1. **Understand** — focus on the request and the code behind it. Launch parallel `scout` subagents (via `task`) when scope spans areas; give each a distinct focus (existing implementations, related components, test patterns). Hunt for reusable code before proposing new.
75
+ 1. **Understand** — focus on the request and the code behind it.{{#if scoutAvailable}} Launch parallel `scout` subagents (via `task`) when scope spans areas; give each a distinct focus (existing implementations, related components, test patterns).{{/if}} Hunt for reusable code before proposing new.
76
76
  2. **Design** — draft one approach from what you found, weigh tradeoffs briefly, then commit. For large or cross-cutting work you MAY spawn a critique subagent to pressure-test it before committing.
77
77
  3. **Review** — read the files you intend to touch and confirm the approach holds against the real code; confirm the plan still answers the literal request; use `{{askToolName}}` to close any remaining preference questions.
78
78
  4. **Write** — write the plan per **Plan contents** below.