lsd-pi 1.2.4 → 1.3.6

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 (357) hide show
  1. package/README.md +22 -16
  2. package/dist/app-paths.d.ts +4 -0
  3. package/dist/app-paths.js +4 -0
  4. package/dist/bedrock-auth.d.ts +4 -0
  5. package/dist/bedrock-auth.js +4 -0
  6. package/dist/bundled-extension-paths.d.ts +4 -0
  7. package/dist/bundled-extension-paths.js +4 -0
  8. package/dist/cli-theme.d.ts +2 -2
  9. package/dist/cli-theme.js +13 -14
  10. package/dist/cli.js +43 -3
  11. package/dist/codex-rotate-settings.d.ts +4 -0
  12. package/dist/codex-rotate-settings.js +4 -0
  13. package/dist/help-text.d.ts +4 -0
  14. package/dist/help-text.js +4 -0
  15. package/dist/lsd-brand.d.ts +4 -0
  16. package/dist/lsd-brand.js +4 -0
  17. package/dist/onboarding-llm.d.ts +5 -0
  18. package/dist/onboarding-llm.js +5 -0
  19. package/dist/project-sessions.d.ts +4 -0
  20. package/dist/project-sessions.js +4 -0
  21. package/dist/resources/agents/generic.md +1 -0
  22. package/dist/resources/agents/scout.md +8 -1
  23. package/dist/resources/agents/worker.md +1 -0
  24. package/dist/resources/extensions/ask-user-questions.js +70 -0
  25. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +6 -16
  26. package/dist/resources/extensions/browser-tools/tools/codegen.js +5 -5
  27. package/dist/resources/extensions/browser-tools/tools/navigation.js +107 -178
  28. package/dist/resources/extensions/browser-tools/tools/network-mock.js +112 -167
  29. package/dist/resources/extensions/browser-tools/tools/pages.js +182 -234
  30. package/dist/resources/extensions/browser-tools/tools/refs.js +202 -461
  31. package/dist/resources/extensions/browser-tools/tools/session.js +176 -323
  32. package/dist/resources/extensions/browser-tools/tools/state-persistence.js +91 -154
  33. package/dist/resources/extensions/browser-tools/utils.js +1 -1
  34. package/dist/resources/extensions/mac-tools/index.js +19 -34
  35. package/dist/resources/extensions/memory/index.js +20 -2
  36. package/dist/resources/extensions/shared/interview-ui.js +103 -20
  37. package/dist/resources/extensions/slash-commands/extension-manifest.json +2 -2
  38. package/dist/resources/extensions/slash-commands/fast.js +73 -0
  39. package/dist/resources/extensions/slash-commands/index.js +2 -0
  40. package/dist/resources/extensions/slash-commands/plan.js +54 -28
  41. package/dist/resources/extensions/slash-commands/tools.js +40 -4
  42. package/dist/resources/extensions/subagent/agent-switcher-component.js +208 -0
  43. package/dist/resources/extensions/subagent/agent-switcher-model.js +107 -0
  44. package/dist/resources/extensions/subagent/background-job-manager.js +24 -6
  45. package/dist/resources/extensions/subagent/background-runner.js +4 -0
  46. package/dist/resources/extensions/subagent/in-process-runner.js +387 -0
  47. package/dist/resources/extensions/subagent/index.js +715 -370
  48. package/dist/resources/extensions/subagent/launch-helpers.js +19 -5
  49. package/dist/resources/extensions/subagent/legacy-runner.js +503 -0
  50. package/dist/resources/extensions/voice/index.js +96 -36
  51. package/dist/resources/extensions/voice/push-to-talk.js +26 -0
  52. package/dist/shared-paths.d.ts +4 -0
  53. package/dist/shared-paths.js +4 -0
  54. package/dist/shared-preferences.d.ts +4 -0
  55. package/dist/shared-preferences.js +4 -0
  56. package/dist/startup-model-validation.d.ts +1 -1
  57. package/dist/startup-timings.d.ts +4 -0
  58. package/dist/startup-timings.js +4 -0
  59. package/dist/update-check.d.ts +4 -0
  60. package/dist/update-check.js +4 -0
  61. package/dist/update-cmd.d.ts +4 -0
  62. package/dist/update-cmd.js +4 -0
  63. package/dist/welcome-screen.js +4 -4
  64. package/dist/wizard.d.ts +4 -0
  65. package/dist/wizard.js +4 -0
  66. package/package.json +1 -1
  67. package/packages/pi-agent-core/dist/agent.d.ts +28 -0
  68. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  69. package/packages/pi-agent-core/dist/agent.js +105 -5
  70. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  71. package/packages/pi-agent-core/dist/types.d.ts +13 -2
  72. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  73. package/packages/pi-agent-core/dist/types.js.map +1 -1
  74. package/packages/pi-agent-core/src/agent.ts +142 -6
  75. package/packages/pi-agent-core/src/types.ts +12 -3
  76. package/packages/pi-ai/dist/adaptive/classifier.d.ts +29 -0
  77. package/packages/pi-ai/dist/adaptive/classifier.d.ts.map +1 -0
  78. package/packages/pi-ai/dist/adaptive/classifier.js +72 -0
  79. package/packages/pi-ai/dist/adaptive/classifier.js.map +1 -0
  80. package/packages/pi-ai/dist/adaptive/classifier.test.d.ts +2 -0
  81. package/packages/pi-ai/dist/adaptive/classifier.test.d.ts.map +1 -0
  82. package/packages/pi-ai/dist/adaptive/classifier.test.js +32 -0
  83. package/packages/pi-ai/dist/adaptive/classifier.test.js.map +1 -0
  84. package/packages/pi-ai/dist/index.d.ts +1 -0
  85. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  86. package/packages/pi-ai/dist/index.js +1 -0
  87. package/packages/pi-ai/dist/index.js.map +1 -1
  88. package/packages/pi-ai/dist/providers/amazon-bedrock.js +0 -2
  89. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  90. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  91. package/packages/pi-ai/dist/providers/anthropic-shared.js +0 -2
  92. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  93. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
  94. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  95. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  96. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/providers/google-gemini-cli.js +0 -4
  98. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  99. package/packages/pi-ai/dist/providers/google-vertex.js +0 -5
  100. package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
  101. package/packages/pi-ai/dist/providers/google.js +0 -5
  102. package/packages/pi-ai/dist/providers/google.js.map +1 -1
  103. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +35 -2
  104. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  105. package/packages/pi-ai/dist/providers/openai-codex-responses.js +32 -6
  106. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  107. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +127 -16
  108. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -1
  109. package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
  110. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  111. package/packages/pi-ai/dist/providers/openai-completions.js +0 -1
  112. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  113. package/packages/pi-ai/dist/providers/openai-responses.d.ts +9 -2
  114. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  115. package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.d.ts +2 -0
  116. package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.d.ts.map +1 -0
  117. package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.js +67 -0
  118. package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.js.map +1 -0
  119. package/packages/pi-ai/dist/providers/openai-responses.js +21 -3
  120. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  121. package/packages/pi-ai/dist/providers/openai-shared.d.ts +0 -1
  122. package/packages/pi-ai/dist/providers/openai-shared.d.ts.map +1 -1
  123. package/packages/pi-ai/dist/providers/openai-shared.js +0 -4
  124. package/packages/pi-ai/dist/providers/openai-shared.js.map +1 -1
  125. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/providers/simple-options.js +2 -1
  127. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  128. package/packages/pi-ai/dist/types.d.ts +6 -2
  129. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  130. package/packages/pi-ai/dist/types.js.map +1 -1
  131. package/packages/pi-ai/src/adaptive/classifier.test.ts +38 -0
  132. package/packages/pi-ai/src/adaptive/classifier.ts +107 -0
  133. package/packages/pi-ai/src/index.ts +1 -0
  134. package/packages/pi-ai/src/providers/amazon-bedrock.ts +0 -2
  135. package/packages/pi-ai/src/providers/anthropic-shared.ts +0 -2
  136. package/packages/pi-ai/src/providers/azure-openai-responses.ts +1 -1
  137. package/packages/pi-ai/src/providers/google-gemini-cli.ts +0 -4
  138. package/packages/pi-ai/src/providers/google-vertex.ts +0 -5
  139. package/packages/pi-ai/src/providers/google.ts +0 -5
  140. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +143 -20
  141. package/packages/pi-ai/src/providers/openai-codex-responses.ts +48 -7
  142. package/packages/pi-ai/src/providers/openai-completions.ts +1 -2
  143. package/packages/pi-ai/src/providers/openai-responses.fast-mode.test.ts +73 -0
  144. package/packages/pi-ai/src/providers/openai-responses.ts +27 -4
  145. package/packages/pi-ai/src/providers/openai-shared.ts +0 -3
  146. package/packages/pi-ai/src/providers/simple-options.ts +2 -1
  147. package/packages/pi-ai/src/types.ts +6 -2
  148. package/packages/pi-coding-agent/dist/cli/args.js +2 -2
  149. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +7 -2
  151. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/agent-session.js +53 -20
  153. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
  155. package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
  157. package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/lsp/lsp.md +3 -1
  159. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/sdk.js +36 -8
  161. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/sdk.test.js +37 -0
  163. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +8 -0
  165. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/session-manager.js +4 -0
  167. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +18 -7
  169. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.d.ts +2 -0
  171. package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.d.ts.map +1 -0
  172. package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.js +35 -0
  173. package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.js.map +1 -0
  174. package/packages/pi-coding-agent/dist/core/settings-manager.js +32 -2
  175. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  178. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  180. package/packages/pi-coding-agent/dist/core/slash-commands.js +2 -1
  181. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/system-prompt.js +12 -3
  184. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/tool-priority.d.ts +4 -0
  186. package/packages/pi-coding-agent/dist/core/tool-priority.d.ts.map +1 -0
  187. package/packages/pi-coding-agent/dist/core/tool-priority.js +18 -0
  188. package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -0
  189. package/packages/pi-coding-agent/dist/core/tool-priority.test.d.ts +2 -0
  190. package/packages/pi-coding-agent/dist/core/tool-priority.test.d.ts.map +1 -0
  191. package/packages/pi-coding-agent/dist/core/tool-priority.test.js +27 -0
  192. package/packages/pi-coding-agent/dist/core/tool-priority.test.js.map +1 -0
  193. package/packages/pi-coding-agent/dist/core/tools/grep.js +1 -1
  194. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  195. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
  196. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/tools/index.js +2 -0
  198. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +10 -1
  200. package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -1
  201. package/packages/pi-coding-agent/dist/core/tools/pty.js +29 -3
  202. package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.d.ts +2 -0
  204. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.d.ts.map +1 -0
  205. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +26 -0
  206. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -0
  207. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.d.ts +45 -0
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.d.ts.map +1 -0
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.js +314 -0
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.js.map +1 -0
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.d.ts +2 -0
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.d.ts.map +1 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.js +122 -0
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.js.map +1 -0
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +2 -0
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  219. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +19 -2
  220. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +11 -2
  222. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +49 -6
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js +1 -2
  227. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -0
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +18 -4
  231. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +13 -0
  233. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -0
  234. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +49 -0
  235. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.d.ts +2 -0
  237. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.d.ts.map +1 -0
  238. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +197 -0
  239. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js.map +1 -0
  240. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  241. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +106 -0
  242. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  243. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  244. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +7 -0
  245. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  248. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  249. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  250. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +88 -2
  252. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  253. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +41 -0
  255. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +2 -2
  257. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -6
  259. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/print-mode.js +6 -0
  264. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +20 -0
  267. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/tests/path-display.test.js +15 -0
  269. package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -1
  270. package/packages/pi-coding-agent/package.json +1 -1
  271. package/packages/pi-coding-agent/src/cli/args.ts +2 -2
  272. package/packages/pi-coding-agent/src/core/agent-session.ts +58 -21
  273. package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
  274. package/packages/pi-coding-agent/src/core/lsp/lsp.md +3 -1
  275. package/packages/pi-coding-agent/src/core/sdk.test.ts +45 -0
  276. package/packages/pi-coding-agent/src/core/sdk.ts +39 -8
  277. package/packages/pi-coding-agent/src/core/session-manager.ts +12 -0
  278. package/packages/pi-coding-agent/src/core/settings-manager.fast-mode.test.ts +46 -0
  279. package/packages/pi-coding-agent/src/core/settings-manager.ts +50 -9
  280. package/packages/pi-coding-agent/src/core/skills.ts +4 -1
  281. package/packages/pi-coding-agent/src/core/slash-commands.ts +2 -1
  282. package/packages/pi-coding-agent/src/core/system-prompt.ts +14 -3
  283. package/packages/pi-coding-agent/src/core/tool-priority.test.ts +30 -0
  284. package/packages/pi-coding-agent/src/core/tool-priority.ts +17 -0
  285. package/packages/pi-coding-agent/src/core/tools/grep.ts +1 -1
  286. package/packages/pi-coding-agent/src/core/tools/index.ts +3 -0
  287. package/packages/pi-coding-agent/src/core/tools/pty.ts +45 -6
  288. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +31 -0
  289. package/packages/pi-coding-agent/src/modes/interactive/components/btw-overlay.test.ts +172 -0
  290. package/packages/pi-coding-agent/src/modes/interactive/components/btw-overlay.ts +402 -0
  291. package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +1 -1
  292. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +18 -2
  293. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +63 -9
  294. package/packages/pi-coding-agent/src/modes/interactive/components/thinking-selector.ts +1 -2
  295. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1154 -1136
  296. package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +64 -0
  297. package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +228 -0
  298. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +494 -389
  299. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +7 -0
  300. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
  301. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +103 -3
  302. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +60 -1
  303. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +11 -7
  304. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +1 -1
  305. package/packages/pi-coding-agent/src/modes/print-mode.ts +6 -0
  306. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +29 -0
  307. package/packages/pi-coding-agent/src/tests/path-display.test.ts +17 -0
  308. package/packages/pi-tui/dist/components/loader.d.ts +5 -2
  309. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  310. package/packages/pi-tui/dist/components/loader.js +33 -3
  311. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  312. package/packages/pi-tui/src/components/loader.ts +31 -3
  313. package/packages/rpc-client/src/index.ts +1 -1
  314. package/packages/rpc-client/src/rpc-client.ts +29 -0
  315. package/packages/rpc-client/src/rpc-types.ts +1 -1
  316. package/pkg/dist/modes/interactive/theme/theme.d.ts +2 -2
  317. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  318. package/pkg/dist/modes/interactive/theme/theme.js +10 -6
  319. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  320. package/pkg/dist/modes/interactive/theme/themes.js +1 -1
  321. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  322. package/pkg/package.json +1 -1
  323. package/src/resources/agents/generic.md +1 -0
  324. package/src/resources/agents/scout.md +8 -1
  325. package/src/resources/agents/worker.md +1 -0
  326. package/src/resources/extensions/ask-user-questions.ts +88 -0
  327. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +6 -16
  328. package/src/resources/extensions/browser-tools/tools/codegen.ts +5 -5
  329. package/src/resources/extensions/browser-tools/tools/navigation.ts +118 -196
  330. package/src/resources/extensions/browser-tools/tools/network-mock.ts +114 -205
  331. package/src/resources/extensions/browser-tools/tools/pages.ts +183 -237
  332. package/src/resources/extensions/browser-tools/tools/refs.ts +193 -507
  333. package/src/resources/extensions/browser-tools/tools/session.ts +182 -321
  334. package/src/resources/extensions/browser-tools/tools/state-persistence.ts +94 -172
  335. package/src/resources/extensions/browser-tools/utils.ts +1 -1
  336. package/src/resources/extensions/mac-tools/index.ts +19 -34
  337. package/src/resources/extensions/memory/index.ts +22 -2
  338. package/src/resources/extensions/shared/interview-ui.ts +108 -15
  339. package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +61 -0
  340. package/src/resources/extensions/shared/tests/custom-ui-fallbacks.test.ts +46 -0
  341. package/src/resources/extensions/slash-commands/extension-manifest.json +2 -2
  342. package/src/resources/extensions/slash-commands/fast.ts +89 -0
  343. package/src/resources/extensions/slash-commands/index.ts +2 -0
  344. package/src/resources/extensions/slash-commands/plan.ts +59 -30
  345. package/src/resources/extensions/slash-commands/tools.ts +43 -4
  346. package/src/resources/extensions/subagent/agent-switcher-component.ts +228 -0
  347. package/src/resources/extensions/subagent/agent-switcher-model.ts +160 -0
  348. package/src/resources/extensions/subagent/background-job-manager.ts +57 -6
  349. package/src/resources/extensions/subagent/background-runner.ts +8 -0
  350. package/src/resources/extensions/subagent/background-types.ts +4 -0
  351. package/src/resources/extensions/subagent/in-process-runner.ts +534 -0
  352. package/src/resources/extensions/subagent/index.ts +998 -493
  353. package/src/resources/extensions/subagent/launch-helpers.ts +15 -4
  354. package/src/resources/extensions/subagent/legacy-runner.ts +607 -0
  355. package/src/resources/extensions/voice/index.ts +308 -238
  356. package/src/resources/extensions/voice/push-to-talk.ts +42 -0
  357. package/src/resources/extensions/voice/tests/push-to-talk.test.ts +109 -0
@@ -29,9 +29,23 @@ import { makeUI, INDENT } from "./ui.js";
29
29
  // ─── Constants ────────────────────────────────────────────────────────────────
30
30
  const OTHER_OPTION_LABEL = "None of the above";
31
31
  const OTHER_OPTION_DESCRIPTION = "Select to type your own answer.";
32
+ function matchesShowWhen(question, answers) {
33
+ if (!question.showWhen)
34
+ return true;
35
+ const controlling = answers[question.showWhen.questionId];
36
+ if (!controlling)
37
+ return false;
38
+ const selected = Array.isArray(controlling.selected)
39
+ ? controlling.selected
40
+ : [controlling.selected];
41
+ return selected.some((value) => question.showWhen?.selectedAnyOf.includes(value));
42
+ }
32
43
  async function runSequentialInterviewFallback(questions, ctx) {
33
44
  const answers = {};
34
45
  for (const q of questions) {
46
+ if (!matchesShowWhen(q, answers)) {
47
+ continue;
48
+ }
35
49
  const options = q.options.map((o) => o.label);
36
50
  if (!q.allowMultiple) {
37
51
  options.push(OTHER_OPTION_LABEL);
@@ -147,7 +161,6 @@ export async function showInterviewRound(questions, opts, ctx) {
147
161
  notes: "",
148
162
  notesVisible: false,
149
163
  }));
150
- const isMultiQuestion = questions.length > 1;
151
164
  let currentIdx = 0;
152
165
  let focusNotes = false;
153
166
  let showingReview = false;
@@ -181,13 +194,65 @@ export async function showInterviewRound(questions, opts, ctx) {
181
194
  function loadStateToEditor() {
182
195
  getEditor().setText(states[currentIdx].notes);
183
196
  }
197
+ function selectedLabelsForIndex(idx) {
198
+ if (isMultiSelect(idx)) {
199
+ return Array.from(states[idx].checkedIndices).sort((a, b) => a - b).map((optionIdx) => questions[idx].options[optionIdx]?.label).filter((v) => !!v);
200
+ }
201
+ const committed = states[idx].committedIndex;
202
+ if (committed === null)
203
+ return [];
204
+ if (committed < questions[idx].options.length)
205
+ return [questions[idx].options[committed]?.label].filter((v) => !!v);
206
+ if (committed === noneOrDoneIdx(idx))
207
+ return [OTHER_OPTION_LABEL];
208
+ return [];
209
+ }
210
+ function visibleQuestionIndices() {
211
+ const visible = [];
212
+ for (let i = 0; i < questions.length; i++) {
213
+ const q = questions[i];
214
+ if (!q.showWhen) {
215
+ visible.push(i);
216
+ continue;
217
+ }
218
+ const controllingIdx = questions.findIndex((candidate) => candidate.id === q.showWhen?.questionId);
219
+ if (controllingIdx < 0 || !visible.includes(controllingIdx))
220
+ continue;
221
+ const selected = selectedLabelsForIndex(controllingIdx);
222
+ if (selected.some((label) => q.showWhen?.selectedAnyOf.includes(label))) {
223
+ visible.push(i);
224
+ }
225
+ }
226
+ return visible;
227
+ }
184
228
  function isQuestionAnswered(idx) {
185
229
  if (isMultiSelect(idx))
186
230
  return states[idx].checkedIndices.size > 0;
187
231
  return states[idx].committedIndex !== null;
188
232
  }
189
233
  function allAnswered() {
190
- return questions.every((_, i) => isQuestionAnswered(i));
234
+ const visible = visibleQuestionIndices();
235
+ return visible.length > 0 && visible.every((i) => isQuestionAnswered(i));
236
+ }
237
+ function clearQuestionState(idx) {
238
+ states[idx].cursorIndex = 0;
239
+ states[idx].committedIndex = null;
240
+ states[idx].checkedIndices.clear();
241
+ states[idx].notes = "";
242
+ states[idx].notesVisible = false;
243
+ }
244
+ function reconcileVisibility() {
245
+ const visible = new Set(visibleQuestionIndices());
246
+ for (let i = 0; i < questions.length; i++) {
247
+ if (!visible.has(i))
248
+ clearQuestionState(i);
249
+ }
250
+ if (!visible.has(currentIdx)) {
251
+ const fallback = visibleQuestionIndices()[0] ?? 0;
252
+ currentIdx = fallback;
253
+ loadStateToEditor();
254
+ focusNotes = false;
255
+ }
191
256
  }
192
257
  function switchQuestion(newIdx) {
193
258
  if (newIdx === currentIdx)
@@ -200,7 +265,10 @@ export async function showInterviewRound(questions, opts, ctx) {
200
265
  }
201
266
  function buildResult() {
202
267
  const answers = {};
268
+ const visible = new Set(visibleQuestionIndices());
203
269
  for (let i = 0; i < questions.length; i++) {
270
+ if (!visible.has(i))
271
+ continue;
204
272
  const q = questions[i];
205
273
  const st = states[i];
206
274
  const notes = st.notes.trim();
@@ -234,6 +302,7 @@ export async function showInterviewRound(questions, opts, ctx) {
234
302
  if (!isMultiSelect(currentIdx)) {
235
303
  states[currentIdx].committedIndex = states[currentIdx].cursorIndex;
236
304
  }
305
+ reconcileVisibility();
237
306
  // Auto-open the notes field when "None of the above" is selected
238
307
  // so the user can immediately provide a free-text explanation
239
308
  // instead of being trapped in a re-asking loop (bug #2715).
@@ -245,10 +314,13 @@ export async function showInterviewRound(questions, opts, ctx) {
245
314
  refresh();
246
315
  return;
247
316
  }
248
- if (isMultiQuestion && currentIdx < questions.length - 1) {
249
- let next = currentIdx + 1;
250
- for (let i = 0; i < questions.length; i++) {
251
- const candidate = (currentIdx + 1 + i) % questions.length;
317
+ const visible = visibleQuestionIndices();
318
+ const currentVisiblePos = visible.indexOf(currentIdx);
319
+ const isMultiQuestion = visible.length > 1;
320
+ if (isMultiQuestion && currentVisiblePos >= 0 && currentVisiblePos < visible.length - 1) {
321
+ let next = visible[currentVisiblePos + 1] ?? visible[0] ?? currentIdx;
322
+ for (let i = 0; i < visible.length; i++) {
323
+ const candidate = visible[(currentVisiblePos + 1 + i) % visible.length] ?? currentIdx;
252
324
  if (!isQuestionAnswered(candidate)) {
253
325
  next = candidate;
254
326
  break;
@@ -306,7 +378,8 @@ export async function showInterviewRound(questions, opts, ctx) {
306
378
  if (showingReview) {
307
379
  if (matchesKey(data, Key.escape) || matchesKey(data, Key.left)) {
308
380
  showingReview = false;
309
- switchQuestion(questions.length - 1);
381
+ const visible = visibleQuestionIndices();
382
+ switchQuestion(visible[visible.length - 1] ?? 0);
310
383
  return;
311
384
  }
312
385
  if (matchesKey(data, Key.enter) || matchesKey(data, Key.right) || matchesKey(data, Key.space)) {
@@ -355,14 +428,19 @@ export async function showInterviewRound(questions, opts, ctx) {
355
428
  return;
356
429
  }
357
430
  // ── Multi-question navigation ────────────────────────────────
431
+ const visible = visibleQuestionIndices();
432
+ const isMultiQuestion = visible.length > 1;
358
433
  if (isMultiQuestion) {
359
- if (matchesKey(data, Key.left)) {
360
- switchQuestion((currentIdx - 1 + questions.length) % questions.length);
361
- return;
362
- }
363
- if (matchesKey(data, Key.right)) {
364
- switchQuestion((currentIdx + 1) % questions.length);
365
- return;
434
+ const visiblePos = visible.indexOf(currentIdx);
435
+ if (visiblePos >= 0) {
436
+ if (matchesKey(data, Key.left)) {
437
+ switchQuestion(visible[(visiblePos - 1 + visible.length) % visible.length] ?? currentIdx);
438
+ return;
439
+ }
440
+ if (matchesKey(data, Key.right)) {
441
+ switchQuestion(visible[(visiblePos + 1) % visible.length] ?? currentIdx);
442
+ return;
443
+ }
366
444
  }
367
445
  }
368
446
  // ── Cursor navigation ────────────────────────────────────────
@@ -435,7 +513,8 @@ export async function showInterviewRound(questions, opts, ctx) {
435
513
  const push = (...rows) => { for (const r of rows)
436
514
  lines.push(...r); };
437
515
  push(ui.bar(), ui.blank(), ui.header(` ${opts.reviewHeadline ?? "Review your answers"}`), ui.blank());
438
- for (let i = 0; i < questions.length; i++) {
516
+ const visible = visibleQuestionIndices();
517
+ for (const i of visible) {
439
518
  const q = questions[i];
440
519
  const st = states[i];
441
520
  push(ui.subtitle(` ${q.question}`));
@@ -501,19 +580,23 @@ export async function showInterviewRound(questions, opts, ctx) {
501
580
  const lines = [];
502
581
  const push = (...rows) => { for (const r of rows)
503
582
  lines.push(...r); };
583
+ reconcileVisibility();
584
+ const visible = visibleQuestionIndices();
585
+ const isMultiQuestion = visible.length > 1;
586
+ const visiblePos = Math.max(visible.indexOf(currentIdx), 0);
504
587
  const q = questions[currentIdx];
505
588
  const st = states[currentIdx];
506
589
  const multiSel = isMultiSelect(currentIdx);
507
590
  push(ui.bar());
508
591
  // ── Progress header ────────────────────────────────────────────
509
592
  if (isMultiQuestion) {
510
- const unanswered = questions.filter((_, i) => !isQuestionAnswered(i)).length;
511
- const answeredSet = new Set(questions.map((_, i) => i).filter(i => isQuestionAnswered(i)));
512
- push(ui.questionTabs(questions.map(q => q.header), currentIdx, answeredSet));
593
+ const unanswered = visible.filter((i) => !isQuestionAnswered(i)).length;
594
+ const answeredSet = new Set(visible.map((i, visibleIndex) => (isQuestionAnswered(i) ? visibleIndex : -1)).filter((i) => i >= 0));
595
+ push(ui.questionTabs(visible.map((i) => questions[i]?.header ?? ""), visiblePos, answeredSet));
513
596
  push(ui.blank());
514
597
  const progressParts = [
515
598
  opts.progress,
516
- `Question ${currentIdx + 1}/${questions.length}`,
599
+ `Question ${visiblePos + 1}/${visible.length}`,
517
600
  unanswered > 0 ? `${unanswered} unanswered` : null,
518
601
  ].filter(Boolean).join(" • ");
519
602
  if (progressParts)
@@ -582,7 +665,7 @@ export async function showInterviewRound(questions, opts, ctx) {
582
665
  }
583
666
  // ── Footer hints ───────────────────────────────────────────────
584
667
  push(ui.blank());
585
- const isLast = !isMultiQuestion || currentIdx === questions.length - 1;
668
+ const isLast = !isMultiQuestion || visiblePos === visible.length - 1;
586
669
  const hints = [];
587
670
  if (focusNotes) {
588
671
  hints.push("enter to confirm");
@@ -2,11 +2,11 @@
2
2
  "id": "slash-commands",
3
3
  "name": "Slash Commands",
4
4
  "version": "1.0.0",
5
- "description": "Bundled slash commands for context inspection, planning, and lazy tool search",
5
+ "description": "Bundled slash commands for context inspection, planning, fast mode, and lazy tool search",
6
6
  "tier": "bundled",
7
7
  "requires": { "platform": ">=2.29.0" },
8
8
  "provides": {
9
- "commands": ["audit", "clear", "context", "plan", "execute", "cancel-plan", "tools"],
9
+ "commands": ["audit", "clear", "context", "fast", "plan", "execute", "cancel-plan", "tools"],
10
10
  "tools": ["tool_search", "tool_enable"],
11
11
  "flags": ["plan"]
12
12
  }
@@ -0,0 +1,73 @@
1
+ import { getAgentDir, SettingsManager } from "@gsd/pi-coding-agent";
2
+ function parseFastCommandAction(args) {
3
+ const normalized = args.trim().toLowerCase();
4
+ if (!normalized)
5
+ return "toggle";
6
+ if (normalized === "on")
7
+ return "on";
8
+ if (normalized === "off")
9
+ return "off";
10
+ if (normalized === "status")
11
+ return "status";
12
+ return "invalid";
13
+ }
14
+ function supportsFastMode(model) {
15
+ if (!model)
16
+ return false;
17
+ if (model.api === "openai-codex-responses")
18
+ return true;
19
+ if (model.api !== "openai-responses")
20
+ return false;
21
+ if (model.provider !== "openai")
22
+ return false;
23
+ return model.capabilities?.supportsServiceTier === true;
24
+ }
25
+ function getModelLabel(model) {
26
+ if (!model)
27
+ return "no active model";
28
+ return `${model.provider}/${model.id}`;
29
+ }
30
+ function getSettingsManager() {
31
+ return SettingsManager.create(process.cwd(), getAgentDir());
32
+ }
33
+ export const __testing = {
34
+ parseFastCommandAction,
35
+ supportsFastMode,
36
+ };
37
+ export default function fastCommand(pi) {
38
+ pi.registerCommand("fast", {
39
+ description: "Toggle fast mode for OpenAI/Codex models (service_tier=priority)",
40
+ getArgumentCompletions(prefix) {
41
+ const options = [
42
+ { value: "on", label: "on", description: "Enable fast mode" },
43
+ { value: "off", label: "off", description: "Disable fast mode" },
44
+ { value: "status", label: "status", description: "Show current fast-mode status" },
45
+ ];
46
+ const query = prefix.trim().toLowerCase();
47
+ return options.filter((item) => item.value.startsWith(query));
48
+ },
49
+ async handler(args, ctx) {
50
+ const settings = getSettingsManager();
51
+ const current = settings.getFastMode();
52
+ const action = parseFastCommandAction(args);
53
+ const model = ctx.model;
54
+ const supported = supportsFastMode(model);
55
+ const modelLabel = getModelLabel(model);
56
+ if (action === "invalid") {
57
+ ctx.ui.notify("Usage: /fast [on|off|status]", "warning");
58
+ return;
59
+ }
60
+ if (action === "status") {
61
+ ctx.ui.notify(`Fast mode: ${current ? "ON" : "OFF"} · model ${modelLabel} is ${supported ? "supported" : "unsupported"}`, "info");
62
+ return;
63
+ }
64
+ const next = action === "toggle" ? !current : action === "on";
65
+ settings.setFastMode(next);
66
+ if (!supported) {
67
+ ctx.ui.notify(`Fast mode: ${next ? "ON" : "OFF"} (saved). Current model ${modelLabel} does not support fast mode.`, "warning");
68
+ return;
69
+ }
70
+ ctx.ui.notify(`Fast mode: ${next ? "ON" : "OFF"} (saved). ${next ? "Requests will include service_tier=priority." : "Requests will omit service_tier."}`, "info");
71
+ },
72
+ });
73
+ }
@@ -1,6 +1,7 @@
1
1
  import auditCommand from "./audit.js";
2
2
  import clearCommand from "./clear.js";
3
3
  import contextCommand from "./context.js";
4
+ import fastCommand from "./fast.js";
4
5
  import initCommand from "./init.js";
5
6
  import planCommand from "./plan.js";
6
7
  import toolSearchExtension from "./tools.js";
@@ -8,6 +9,7 @@ export default function slashCommands(pi) {
8
9
  auditCommand(pi);
9
10
  clearCommand(pi);
10
11
  contextCommand(pi);
12
+ fastCommand(pi);
11
13
  initCommand(pi);
12
14
  planCommand(pi);
13
15
  toolSearchExtension(pi);
@@ -28,9 +28,8 @@ const BLOCKED_TOOLS = new Set([
28
28
  "async_bash",
29
29
  "bg_shell",
30
30
  "browser_navigate",
31
- "browser_go_back",
32
- "browser_go_forward",
33
- "browser_reload",
31
+ "browser_pages",
32
+ "browser_frames",
34
33
  "browser_click",
35
34
  "browser_drag",
36
35
  "browser_type",
@@ -41,18 +40,13 @@ const BLOCKED_TOOLS = new Set([
41
40
  "browser_select_option",
42
41
  "browser_set_checked",
43
42
  "browser_set_viewport",
44
- "browser_click_ref",
45
- "browser_hover_ref",
46
- "browser_fill_ref",
43
+ "browser_ref",
47
44
  "browser_act",
48
45
  "browser_batch",
49
46
  "browser_fill_form",
50
- "browser_mock_route",
51
- "browser_block_urls",
52
- "browser_clear_routes",
47
+ "browser_network",
53
48
  "browser_emulate_device",
54
- "browser_save_state",
55
- "browser_restore_state",
49
+ "browser_state",
56
50
  "browser_generate_test",
57
51
  "browser_verify",
58
52
  "write",
@@ -70,6 +64,7 @@ const REVISE_LABEL = "Revise plan";
70
64
  const CANCEL_LABEL = "Cancel";
71
65
  const DEFAULT_PLAN_REVIEW_AGENT = "generic";
72
66
  const DEFAULT_PLAN_CODING_AGENT = "worker";
67
+ const MIN_PLAN_CONFIDENCE = 8;
73
68
  const INITIAL_STATE = {
74
69
  active: false,
75
70
  task: "",
@@ -366,6 +361,9 @@ function buildPlanModeSystemPrompt() {
366
361
  "You are currently in plan mode.",
367
362
  "Investigate, clarify scope, and produce a persisted execution plan before making source changes.",
368
363
  "If requirements are ambiguous or constraints are missing, ask concise clarifying questions before drafting or saving a plan.",
364
+ `Before writing or updating a plan artifact, make sure your confidence is at least ${MIN_PLAN_CONFIDENCE}/10. If confidence is lower, investigate more or ask clarifying questions first.`,
365
+ "Include an explicit confidence line in every saved plan, for example: \"Confidence: 8/10\" or higher.",
366
+ "When adjusting an existing saved plan, prefer the edit tool for targeted changes. Rewrite the whole file only when the structure changes substantially or an exact edit is impractical.",
369
367
  "Do not modify source files or run side-effect commands while plan mode is active.",
370
368
  "Persist plan artifacts under .lsd/plan/.",
371
369
  ];
@@ -395,25 +393,18 @@ function buildNewSessionOptionLabel() {
395
393
  return `${APPROVE_LABEL} — ${APPROVE_NEW_SESSION_LABEL} (${suffix})`;
396
394
  }
397
395
  function buildApprovalActionInstructions() {
398
- return [
399
- "Ask for plan approval now using ask_user_questions.",
400
- `One single-select question with id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\". Ask what to do next with the plan.`,
401
- `Options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}.`,
402
- `Do not include \"${CANCEL_LABEL}\" as an explicit option — if the user wants to cancel they should choose \"None of the above\" and type \"${CANCEL_LABEL}\" in the note.`,
403
- "Do not restate the plan. Just show the question.",
404
- ].join(" ");
405
- }
406
- function buildApprovalModeInstructions() {
407
396
  const autoSwitchEnabled = readAutoSwitchPlanModelSetting();
408
397
  const showNewSessionOption = autoSwitchEnabled;
409
398
  const newSessionLabel = buildNewSessionOptionLabel();
410
- const options = showNewSessionOption
411
- ? `${APPROVE_AUTO_LABEL}, ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}, ${newSessionLabel}`
412
- : `${APPROVE_AUTO_LABEL}, ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}`;
413
399
  return [
414
- "Plan approved. Now ask which execution mode to use via ask_user_questions.",
415
- `One single-select question with id \"${PLAN_APPROVAL_PERMISSION_QUESTION_ID}\".`,
416
- `Options: ${options}.`,
400
+ "Ask for plan approval now via exactly one ask_user_questions tool call.",
401
+ `Question 1 (single-select) id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\": ask what to do next with the plan. In the question text, tell the user that if they choose \"${REVISE_LABEL}\" they should type exact requested changes in the dialog notes field before submitting.`,
402
+ `Question 1 options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}. Put "${APPROVE_LABEL}" first with a "(Recommended)" suffix in the description, not in the label.`,
403
+ `Do not include \"${CANCEL_LABEL}\" as an explicit option — if the user wants to cancel they should choose \"None of the above\" and type \"${CANCEL_LABEL}\" in the note.`,
404
+ `Question 2 (single-select) id \"${PLAN_APPROVAL_PERMISSION_QUESTION_ID}\": ask which execution mode to use.`,
405
+ `Question 2 options: ${APPROVE_AUTO_LABEL} (Recommended), ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}${showNewSessionOption ? `, ${newSessionLabel}` : ""}.`,
406
+ `Set question 2 showWhen.questionId to \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\" and showWhen.selectedAnyOf to [\"${APPROVE_LABEL}\"] so it appears only when the user selects Approve plan.`,
407
+ "Do not restate the plan in a normal assistant response. Just call ask_user_questions.",
417
408
  ].join(" ");
418
409
  }
419
410
  // Keep for external callers that reference the combined form (headless path)
@@ -461,6 +452,23 @@ function buildReviewSteeringMessage(planPath, planMarkdown) {
461
452
  details.push("After the subagent responds, summarize its feedback for the user, present the current plan again, and then ask for approval again.", buildApprovalActionInstructions());
462
453
  return details.join("\n\n");
463
454
  }
455
+ function buildRevisionSteeringMessage(planPath, requestedChanges) {
456
+ const details = [
457
+ `The user selected \"${REVISE_LABEL}\" for ${planPath}.`,
458
+ "Revise the existing saved plan instead of drafting a fresh replacement unless a full rewrite is genuinely necessary.",
459
+ "Prefer the edit tool for targeted adjustments to the current plan artifact. Use write only if the structure changes substantially or an exact edit is impractical.",
460
+ `Before saving the revised plan, make sure confidence is at least ${MIN_PLAN_CONFIDENCE}/10. If lower, investigate more or ask clarifying questions first.`,
461
+ "Keep an explicit confidence line in the plan, for example: \"Confidence: 8/10\" or higher.",
462
+ ];
463
+ if (requestedChanges) {
464
+ details.push(`User-requested changes: ${requestedChanges}`);
465
+ }
466
+ else {
467
+ details.push("No concrete revision note was provided yet. Ask one concise clarifying question about what should change before editing the plan.");
468
+ }
469
+ details.push("After revising the saved plan artifact, ask for approval again.");
470
+ return details.join("\n\n");
471
+ }
464
472
  function approvalSelectionToExecutionMode(selected) {
465
473
  if (!selected)
466
474
  return undefined;
@@ -489,6 +497,12 @@ function getAnswerValues(answer) {
489
497
  }
490
498
  return values;
491
499
  }
500
+ function getAnswerNote(answer) {
501
+ if (typeof answer?.notes !== "string")
502
+ return undefined;
503
+ const note = answer.notes.trim();
504
+ return note.length > 0 ? note : undefined;
505
+ }
492
506
  function selectionRequestsCancel(selected) {
493
507
  return selected.some((value) => {
494
508
  if (typeof value !== "string")
@@ -513,6 +527,8 @@ export const __testing = {
513
527
  buildApprovalSteeringMessage,
514
528
  buildPlanPreviewMessage,
515
529
  buildReviewSteeringMessage,
530
+ buildRevisionSteeringMessage,
531
+ buildPlanModeSystemPrompt,
516
532
  buildAutoSuggestPlanModeSystemPrompt,
517
533
  readAutoSuggestPlanModeSetting,
518
534
  PLAN_SUGGEST_QUESTION_ID,
@@ -679,8 +695,16 @@ export default function planCommand(pi) {
679
695
  if (!actionSelection)
680
696
  return;
681
697
  if (actionSelection.includes(APPROVE_LABEL)) {
682
- // Steer the second question — handle in the next tool_result cycle
683
- pi.sendUserMessage(buildApprovalModeInstructions(), { deliverAs: "steer" });
698
+ const executionMode = approvalSelectionToExecutionMode(permissionValues[0]) ?? {
699
+ permissionMode: DEFAULT_APPROVAL_PERMISSION_MODE,
700
+ executeWithSubagent: false,
701
+ };
702
+ state = { ...state, targetPermissionMode: executionMode.permissionMode };
703
+ if (executionMode.executeWithSubagent) {
704
+ const modeLabel = executionMode.permissionMode === "danger-full-access" ? "bypass" : "auto";
705
+ ctx.ui?.notify?.(`Plan approved: subagent(${modeLabel})`, "info");
706
+ }
707
+ await approvePlan(pi, ctx, executionMode.permissionMode, executionMode.executeWithSubagent);
684
708
  return;
685
709
  }
686
710
  if (actionSelection.includes(REVIEW_LABEL)) {
@@ -695,9 +719,11 @@ export default function planCommand(pi) {
695
719
  return;
696
720
  }
697
721
  if (actionSelection.includes(REVISE_LABEL)) {
722
+ const requestedChanges = getAnswerNote(actionAnswer);
698
723
  enablePlanMode(pi, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, {
699
724
  approvalStatus: "revising",
700
725
  });
726
+ pi.sendUserMessage(buildRevisionSteeringMessage(state.latestPlanPath ?? "the latest plan", requestedChanges), { deliverAs: "steer" });
701
727
  }
702
728
  });
703
729
  pi.registerCommand("plan", {
@@ -37,6 +37,30 @@ function getBalancedToolNames(activeToolNames) {
37
37
  "ask_user_questions",
38
38
  ];
39
39
  }
40
+ const STANDARD_TOOLS = [
41
+ // Core
42
+ "read", "bash", "edit", "write", "lsp", "grep", "find", "ls",
43
+ // Background
44
+ "bg_shell",
45
+ // Search
46
+ "web_search", "fetch_page",
47
+ // Docs
48
+ "resolve_library", "get_library_docs",
49
+ // Agent
50
+ "subagent", "await_subagent", "Skill",
51
+ // User interaction
52
+ "ask_user_questions", "secure_env_collect",
53
+ // Browser (essential)
54
+ "browser_navigate", "browser_click", "browser_type", "browser_screenshot",
55
+ "browser_scroll", "browser_key_press", "browser_evaluate",
56
+ "browser_find", "browser_wait_for", "browser_close",
57
+ "browser_assert", "browser_batch",
58
+ // Tool management
59
+ "tool_search", "tool_enable",
60
+ ];
61
+ function getStandardToolNames() {
62
+ return [...STANDARD_TOOLS];
63
+ }
40
64
  function getFullToolNames(pi) {
41
65
  return pi.getAllTools().map((tool) => tool.name).filter((name) => Boolean(name));
42
66
  }
@@ -168,7 +192,8 @@ export default function toolSearchExtension(pi) {
168
192
  currentActive.length > 0 ? currentActive.join(", ") : "(none)",
169
193
  "",
170
194
  "Usage:",
171
- " /tools balanced Switch to the balanced tool profile",
195
+ " /tools balanced Switch to the balanced tool profile (12 tools)",
196
+ " /tools standard Switch to the standard tool profile (~32 tools)",
172
197
  " /tools full Switch to the full tool profile (all available tools)",
173
198
  " /tools on Alias for /tools full",
174
199
  " /tools off Alias for /tools balanced",
@@ -183,7 +208,18 @@ export default function toolSearchExtension(pi) {
183
208
  pi.setActiveTools(nextActive);
184
209
  pi.sendMessage({
185
210
  customType: "tools:mode",
186
- content: `Balanced tool profile active: ${pi.getActiveTools().join(", ")}`,
211
+ content: `Balanced tool profile active (${pi.getActiveTools().length} tools): ${pi.getActiveTools().join(", ")}`,
212
+ display: true,
213
+ });
214
+ return;
215
+ }
216
+ if (input === "standard") {
217
+ settings.setToolProfile("standard");
218
+ const nextActive = getStandardToolNames();
219
+ pi.setActiveTools(nextActive);
220
+ pi.sendMessage({
221
+ customType: "tools:mode",
222
+ content: `Standard tool profile active (${pi.getActiveTools().length} tools): ${pi.getActiveTools().join(", ")}`,
187
223
  display: true,
188
224
  });
189
225
  return;
@@ -194,14 +230,14 @@ export default function toolSearchExtension(pi) {
194
230
  pi.setActiveTools(nextActive);
195
231
  pi.sendMessage({
196
232
  customType: "tools:mode",
197
- content: `Full tool profile active: ${pi.getActiveTools().join(", ")}`,
233
+ content: `Full tool profile active (${pi.getActiveTools().length} tools): ${pi.getActiveTools().join(", ")}`,
198
234
  display: true,
199
235
  });
200
236
  return;
201
237
  }
202
238
  pi.sendMessage({
203
239
  customType: "tools:help",
204
- content: `Unknown /tools subcommand: ${input}\n\nTry /tools, /tools balanced, /tools full, /tools on, or /tools off.`,
240
+ content: `Unknown /tools subcommand: ${input}\n\nTry /tools, /tools balanced, /tools standard, /tools full, /tools on, or /tools off.`,
205
241
  display: true,
206
242
  });
207
243
  },