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
@@ -54,6 +54,13 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
54
54
  }
55
55
 
56
56
  if (host.session.isStreaming) {
57
+ if (text === "/btw" || text.startsWith("/btw ")) {
58
+ const handled = await dispatchSlashCommand(text, host.getSlashCommandContext());
59
+ if (handled) {
60
+ host.editor.setText("");
61
+ return;
62
+ }
63
+ }
57
64
  host.editor.addToHistory?.(text);
58
65
  host.editor.setText("");
59
66
  host.recordLastSentPrompt?.(text);
@@ -11,8 +11,11 @@ export interface InteractiveModeStateHost {
11
11
  chatContainer: any;
12
12
  settingsManager: any;
13
13
  pendingTools: Map<string, any>;
14
+ collapsedToolSummaryLine?: any;
14
15
  toolOutputExpanded: boolean;
15
16
  hideThinkingBlock: boolean;
17
+ notificationSoundEnabled: boolean;
18
+ playNotificationSoundOnAgentEnd: boolean;
16
19
  isBashMode: boolean;
17
20
  onInputCallback?: (text: string) => void;
18
21
  isInitialized: boolean;
@@ -69,6 +69,7 @@ import {
69
69
  type PermissionMode,
70
70
  } from "../../core/tool-approval.js";
71
71
  import type { TruncationResult } from "../../core/tools/truncate.js";
72
+ import { writeToPtySession } from "../../core/tools/index.js";
72
73
  import { isPtyAvailable } from "../../core/pty-executor.js";
73
74
  import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
74
75
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
@@ -98,6 +99,7 @@ import { SessionSelectorComponent } from "./components/session-selector.js";
98
99
  import { SettingsSelectorComponent } from "./components/settings-selector.js";
99
100
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
100
101
  import { ToolExecutionComponent } from "./components/tool-execution.js";
102
+ import { ToolSummaryLine } from "./components/tool-summary-line.js";
101
103
  import { TreeSelectorComponent } from "./components/tree-selector.js";
102
104
  import { UserMessageComponent } from "./components/user-message.js";
103
105
  import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
@@ -179,14 +181,32 @@ export interface InteractiveModeOptions {
179
181
  }
180
182
 
181
183
  function getToolNamesForProfile(
182
- profile: "balanced" | "full",
184
+ profile: "balanced" | "standard" | "full",
183
185
  editMode: "standard" | "hashline",
184
186
  availableToolNames: string[],
185
187
  ): string[] {
186
188
  const balancedToolNames = editMode === "hashline"
187
189
  ? ["hashline_read", "bash", "hashline_edit", "write", "lsp", "bg_shell", "tool_search", "tool_enable", "Skill", "subagent", "await_subagent", "ask_user_questions"]
188
190
  : ["read", "bash", "edit", "write", "lsp", "bg_shell", "tool_search", "tool_enable", "Skill", "subagent", "await_subagent", "ask_user_questions"];
189
- return profile === "full" ? availableToolNames : balancedToolNames;
191
+ const standardToolNames = [
192
+ "read", "bash", "edit", "write", "lsp", "grep", "find", "ls",
193
+ "bg_shell",
194
+ "web_search", "fetch_page",
195
+ "resolve_library", "get_library_docs",
196
+ "subagent", "await_subagent", "Skill",
197
+ "ask_user_questions", "secure_env_collect",
198
+ "browser_navigate", "browser_click", "browser_type", "browser_screenshot",
199
+ "browser_scroll", "browser_key_press", "browser_evaluate",
200
+ "browser_find", "browser_wait_for", "browser_close",
201
+ "browser_assert", "browser_batch",
202
+ "tool_search", "tool_enable",
203
+ ];
204
+ if (profile === "full") return availableToolNames;
205
+ if (profile === "standard") {
206
+ const available = new Set(availableToolNames);
207
+ return standardToolNames.filter((name) => available.has(name));
208
+ }
209
+ return balancedToolNames;
190
210
  }
191
211
 
192
212
  export class InteractiveMode {
@@ -301,6 +321,7 @@ export class InteractiveMode {
301
321
 
302
322
  // Tool execution tracking: toolCallId -> component
303
323
  private pendingTools = new Map<string, ToolExecutionComponent>();
324
+ private collapsedToolSummaryLine: ToolSummaryLine | undefined = undefined;
304
325
  private agentPtyComponents = new Map<string, EmbeddedTerminalComponent>();
305
326
 
306
327
  // Tool output expansion state
@@ -309,6 +330,10 @@ export class InteractiveMode {
309
330
  // Thinking block visibility state
310
331
  private hideThinkingBlock = false;
311
332
 
333
+ // Notification sound (terminal bell on completed agent response)
334
+ notificationSoundEnabled = false;
335
+ playNotificationSoundOnAgentEnd = false;
336
+
312
337
  // Pin last prompt feature
313
338
  private pinLastPromptEnabled = false;
314
339
  private lastSentPromptText: string | undefined = undefined;
@@ -416,6 +441,10 @@ export class InteractiveMode {
416
441
  // Load pin last prompt setting
417
442
  this.pinLastPromptEnabled = this.settingsManager.getPinLastPrompt();
418
443
 
444
+ // Load notification sound setting
445
+ this.notificationSoundEnabled = this.settingsManager.getNotificationSound();
446
+ this.footer.setNotificationSoundEnabled(this.notificationSoundEnabled);
447
+
419
448
  // Register themes from resource loader and initialize
420
449
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
421
450
  initTheme(this.settingsManager.getTheme(), true, this.settingsManager.getThemeAccent());
@@ -465,7 +494,6 @@ export class InteractiveMode {
465
494
  thinkingCommand.getArgumentCompletions = (prefix: string): AutocompleteItem[] | null => {
466
495
  const levels = [
467
496
  { value: "off", label: "off", description: "Disable extended thinking" },
468
- { value: "minimal", label: "minimal", description: "Minimal thinking budget" },
469
497
  { value: "low", label: "low", description: "Low thinking budget" },
470
498
  { value: "medium", label: "medium", description: "Medium thinking budget" },
471
499
  { value: "high", label: "high", description: "High thinking budget" },
@@ -2309,6 +2337,7 @@ export class InteractiveMode {
2309
2337
  this.defaultEditor.onAction("cyclePermissionMode", () => this.cyclePermissionMode());
2310
2338
  this.defaultEditor.onAction("showHotkeys", () => showHotkeys(this.getSlashCommandContext()));
2311
2339
  this.defaultEditor.onAction("terminalFocus", () => this.toggleEmbeddedTerminalFocus());
2340
+ this.defaultEditor.onAction("toggleNotificationSound", () => this.toggleNotificationSound());
2312
2341
 
2313
2342
  // Global debug handler on TUI (works regardless of focus)
2314
2343
  this.ui.onDebug = () => this.handleDebugCommand();
@@ -3017,6 +3046,14 @@ export class InteractiveMode {
3017
3046
  }
3018
3047
  }
3019
3048
 
3049
+ private toggleNotificationSound(): void {
3050
+ this.notificationSoundEnabled = !this.notificationSoundEnabled;
3051
+ this.settingsManager.setNotificationSound(this.notificationSoundEnabled);
3052
+ this.footer.setNotificationSoundEnabled(this.notificationSoundEnabled);
3053
+ this.ui.requestRender();
3054
+ this.showStatus(`Notification sound: ${this.notificationSoundEnabled ? "enabled" : "disabled"}`);
3055
+ }
3056
+
3020
3057
  private async cycleModel(direction: "forward" | "backward"): Promise<void> {
3021
3058
  try {
3022
3059
  const result = await this.session.cycleModel(direction);
@@ -3045,6 +3082,12 @@ export class InteractiveMode {
3045
3082
  if (isExpandable(child)) {
3046
3083
  child.setExpanded(expanded);
3047
3084
  }
3085
+ if (child instanceof ToolExecutionComponent) {
3086
+ child.setHidden(!expanded && child.shouldHideWhenCollapsed());
3087
+ }
3088
+ if (child instanceof ToolSummaryLine) {
3089
+ child.setHidden(expanded);
3090
+ }
3048
3091
  }
3049
3092
  if (this.bashComponent) {
3050
3093
  this.bashComponent.setExpanded(expanded);
@@ -3423,6 +3466,7 @@ export class InteractiveMode {
3423
3466
  autoCompactThresholdPercent: this.settingsManager.getCompactionThresholdPercent(),
3424
3467
  defaultModel: defaultModelRef,
3425
3468
  classifierModel: this.settingsManager.getClassifierModel() ?? "default",
3469
+ adaptiveClassifierModel: this.settingsManager.getAdaptiveClassifierModel() ?? "default",
3426
3470
  budgetSubagentModel: this.settingsManager.getBudgetSubagentModel() ?? "default",
3427
3471
  planModeReasoningModel: this.settingsManager.getPlanModeReasoningModel() ?? "default",
3428
3472
  planModeReviewModel: this.settingsManager.getPlanModeReviewModel() ?? "default",
@@ -3435,6 +3479,7 @@ export class InteractiveMode {
3435
3479
  enableSkillCommands: this.settingsManager.getEnableSkillCommands(),
3436
3480
  toolProfile: this.settingsManager.getToolProfile(),
3437
3481
  codexRotate: this.settingsManager.getCodexRotate(),
3482
+ fastMode: this.settingsManager.getFastMode(),
3438
3483
  cacheTimer: this.settingsManager.getCacheTimer(),
3439
3484
  pinLastPrompt: this.settingsManager.getPinLastPrompt(),
3440
3485
  steeringMode: this.session.steeringMode,
@@ -3442,6 +3487,7 @@ export class InteractiveMode {
3442
3487
  transport: this.settingsManager.getTransport(),
3443
3488
  thinkingLevel: this.session.thinkingLevel,
3444
3489
  anthropicAdaptiveByDefault: this.settingsManager.getAnthropicAdaptiveByDefault(),
3490
+ clientAdaptiveByDefault: this.settingsManager.getClientAdaptiveByDefault(),
3445
3491
  availableThinkingLevels: this.session.getAvailableThinkingLevels(),
3446
3492
  currentTheme: this.settingsManager.getTheme() || "dark",
3447
3493
  currentThemeAccent: this.settingsManager.getThemeAccent() || "default",
@@ -3463,6 +3509,7 @@ export class InteractiveMode {
3463
3509
  editorScheme: this.settingsManager.getEditorScheme(),
3464
3510
  autoDream: this.settingsManager.getAutoDream(),
3465
3511
  autoMemory: this.settingsManager.getAutoMemory(),
3512
+ notificationSound: this.notificationSoundEnabled,
3466
3513
  telegramLiveRelayAutoConnect: this.settingsManager.getTelegramLiveRelayAutoConnect(),
3467
3514
  sandboxEnabled: this.settingsManager.getSandboxSettings().enabled ?? true,
3468
3515
  sandboxNetworkMode: this.settingsManager.getSandboxSettings().networkMode
@@ -3487,6 +3534,16 @@ export class InteractiveMode {
3487
3534
  (model) => submenuDone(`${model.provider}/${model.id}`),
3488
3535
  () => submenuDone(),
3489
3536
  ),
3537
+ adaptiveClassifierModelSubmenu: (_currentValue, submenuDone) =>
3538
+ new ModelSelectorComponent(
3539
+ this.ui,
3540
+ undefined,
3541
+ this.settingsManager,
3542
+ this.session.modelRegistry,
3543
+ [],
3544
+ (model) => submenuDone(`${model.provider}/${model.id}`),
3545
+ () => submenuDone(),
3546
+ ),
3490
3547
  budgetSubagentModelSubmenu: (_currentValue, submenuDone) =>
3491
3548
  new ModelSelectorComponent(
3492
3549
  this.ui,
@@ -3552,6 +3609,16 @@ export class InteractiveMode {
3552
3609
  this.settingsManager.setClassifierModel(modelRef);
3553
3610
  this.showStatus(`Classifier model: ${modelRef}`);
3554
3611
  },
3612
+ onAdaptiveClassifierModelChange: (modelRef) => {
3613
+ this.settingsManager.setAdaptiveClassifierModel(modelRef === "default" ? undefined : modelRef);
3614
+ // Live-update the agent so the change takes effect immediately
3615
+ const parts = modelRef && modelRef !== "default" ? modelRef.split("/") : [];
3616
+ const resolved = parts.length === 2
3617
+ ? this.session.modelRegistry.find(parts[0]!, parts[1]!) ?? undefined
3618
+ : undefined;
3619
+ this.session.agent.setAdaptiveClassifierModel(resolved);
3620
+ this.showStatus(`Adaptive classifier model: ${modelRef === "default" ? "not set" : modelRef}`);
3621
+ },
3555
3622
  onBudgetSubagentModelChange: (modelRef) => {
3556
3623
  this.settingsManager.setBudgetSubagentModel(modelRef === "default" ? undefined : modelRef);
3557
3624
  this.showStatus(
@@ -3613,6 +3680,10 @@ export class InteractiveMode {
3613
3680
  this.settingsManager.setCodexRotate(enabled);
3614
3681
  this.showStatus(`Codex rotate: ${enabled ? "enabled" : "disabled"} (restart required)`);
3615
3682
  },
3683
+ onFastModeChange: (enabled) => {
3684
+ this.settingsManager.setFastMode(enabled);
3685
+ this.showStatus(`Fast mode: ${enabled ? "enabled" : "disabled"}`);
3686
+ },
3616
3687
  onCacheTimerChange: (enabled) => {
3617
3688
  this.settingsManager.setCacheTimer(enabled);
3618
3689
  this.showStatus(`Cache timer: ${enabled ? "enabled" : "disabled"}`);
@@ -3635,6 +3706,13 @@ export class InteractiveMode {
3635
3706
  this.settingsManager.setAutoMemory(enabled);
3636
3707
  this.showStatus(`Auto memory: ${enabled ? "enabled" : "disabled"}`);
3637
3708
  },
3709
+ onNotificationSoundChange: (enabled) => {
3710
+ this.notificationSoundEnabled = enabled;
3711
+ this.settingsManager.setNotificationSound(enabled);
3712
+ this.footer.setNotificationSoundEnabled(enabled);
3713
+ this.ui.requestRender();
3714
+ this.showStatus(`Notification sound: ${enabled ? "enabled" : "disabled"}`);
3715
+ },
3638
3716
  onTelegramLiveRelayAutoConnectChange: (enabled) => {
3639
3717
  this.settingsManager.setTelegramLiveRelayAutoConnect(enabled);
3640
3718
  this.showStatus(`Telegram autoconnect: ${enabled ? "enabled" : "disabled"}`);
@@ -3658,6 +3736,10 @@ export class InteractiveMode {
3658
3736
  this.settingsManager.setAnthropicAdaptiveByDefault(enabled);
3659
3737
  this.showStatus(`Anthropic adaptive default: ${enabled ? "enabled" : "disabled"}`);
3660
3738
  },
3739
+ onClientAdaptiveByDefaultChange: (enabled) => {
3740
+ this.settingsManager.setClientAdaptiveByDefault(enabled);
3741
+ this.showStatus(`Adaptive default: ${enabled ? "enabled" : "disabled"}`);
3742
+ },
3661
3743
  onThemeChange: (themeName) => {
3662
3744
  const result = setTheme(themeName, true, this.settingsManager.getThemeAccent());
3663
3745
  this.settingsManager.setTheme(themeName);
@@ -4525,6 +4607,17 @@ export class InteractiveMode {
4525
4607
  appKey(this.keybindings, "terminalFocus"),
4526
4608
  false,
4527
4609
  );
4610
+ // Wire up a handle shim so the user can focus and type into the agent PTY
4611
+ component.setHandle(
4612
+ {
4613
+ pid: 0,
4614
+ write: (data: string) => writeToPtySession(sessionId, data),
4615
+ resize: () => {},
4616
+ kill: () => {},
4617
+ isActive: () => true,
4618
+ },
4619
+ () => this.releaseEmbeddedTerminalFocus(),
4620
+ );
4528
4621
  component.setStatusOverride(theme.fg("muted", "Agent-controlled terminal session"));
4529
4622
  component.setExpanded(true);
4530
4623
  this.chatContainer.addChild(component);
@@ -4579,6 +4672,13 @@ export class InteractiveMode {
4579
4672
  }
4580
4673
  if (this.bashComponent instanceof EmbeddedTerminalComponent) {
4581
4674
  this.focusEmbeddedTerminal(this.bashComponent);
4675
+ return;
4676
+ }
4677
+ // Fall back to the most recently created agent PTY component
4678
+ const agentComponents = [...this.agentPtyComponents.values()];
4679
+ const last = agentComponents[agentComponents.length - 1];
4680
+ if (last) {
4681
+ this.focusEmbeddedTerminal(last);
4582
4682
  }
4583
4683
  }
4584
4684
 
@@ -17,6 +17,9 @@ import type {
17
17
  EditorComponent,
18
18
  MarkdownTheme,
19
19
  } from "@gsd/pi-tui";
20
+ import {
21
+ streamSimple,
22
+ } from "@gsd/pi-ai";
20
23
  import {
21
24
  type Component,
22
25
  Container,
@@ -32,17 +35,19 @@ import type { AgentSession } from "../../core/agent-session.js";
32
35
  import type { AppAction, KeybindingsManager } from "../../core/keybindings.js";
33
36
  import type { SessionManager } from "../../core/session-manager.js";
34
37
  import type { SettingsManager } from "../../core/settings-manager.js";
38
+ import { convertToLlm } from "../../core/messages.js";
35
39
  import { copyToClipboard } from "../../utils/clipboard.js";
36
40
  import { getChangelogPath, parseChangelog } from "../../utils/changelog.js";
37
41
  import { ArminComponent } from "./components/armin.js";
38
42
  import { BorderedLoader } from "./components/bordered-loader.js";
43
+ import { BtwOverlayComponent } from "./components/btw-overlay.js";
39
44
  import { DynamicBorder } from "./components/dynamic-border.js";
40
45
  import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
41
46
  import { appKey, editorKey, formatKeyForDisplay } from "./components/keybinding-hints.js";
42
47
  import { SelectSubmenu, THINKING_DESCRIPTIONS } from "./components/settings-selector.js";
43
48
  import { theme } from "./theme/theme.js";
44
49
 
45
- import type { TUI } from "@gsd/pi-tui";
50
+ import type { OverlayHandle, TUI } from "@gsd/pi-tui";
46
51
 
47
52
  // ---------------------------------------------------------------------------
48
53
  // Context interface — the subset of InteractiveMode needed by slash commands
@@ -173,6 +178,15 @@ export async function dispatchSlashCommand(
173
178
  showHotkeys(ctx);
174
179
  return true;
175
180
  }
181
+ if (text === "/btw" || text.startsWith("/btw ")) {
182
+ const question = text.startsWith("/btw ") ? text.slice(5).trim() : "";
183
+ if (!question) {
184
+ ctx.showWarning("Usage: /btw <question>");
185
+ return true;
186
+ }
187
+ await handleBtwCommand(question, ctx);
188
+ return true;
189
+ }
176
190
  if (text === "/fork") {
177
191
  ctx.showUserMessageSelector();
178
192
  return true;
@@ -704,6 +718,7 @@ export function showHotkeys(ctx: SlashCommandContext): void {
704
718
  const externalEditor = getAppKeyDisplay(ctx.keybindings, "externalEditor");
705
719
  const followUp = getAppKeyDisplay(ctx.keybindings, "followUp");
706
720
  const dequeue = getAppKeyDisplay(ctx.keybindings, "dequeue");
721
+ const toggleNotificationSound = getAppKeyDisplay(ctx.keybindings, "toggleNotificationSound");
707
722
 
708
723
  let hotkeys = `
709
724
  **Navigation**
@@ -746,6 +761,7 @@ export function showHotkeys(ctx: SlashCommandContext): void {
746
761
  | \`${externalEditor}\` | Edit message in external editor |
747
762
  | \`${followUp}\` | Queue follow-up message |
748
763
  | \`${dequeue}\` | Restore queued messages |
764
+ | \`${toggleNotificationSound}\` | Toggle notification sound |
749
765
  | \`Ctrl+V\` | Paste image from clipboard |
750
766
  | \`/\` | Slash commands |
751
767
  | \`!\` | Run bash command |
@@ -779,6 +795,49 @@ export function showHotkeys(ctx: SlashCommandContext): void {
779
795
  ctx.requestRender();
780
796
  }
781
797
 
798
+ async function handleBtwCommand(question: string, ctx: SlashCommandContext): Promise<void> {
799
+ const model = ctx.session.model;
800
+ if (!model) {
801
+ ctx.showWarning("No model selected. Cannot use /btw.");
802
+ return;
803
+ }
804
+
805
+ if (!ctx.session.modelRegistry.isProviderRequestReady(model.provider)) {
806
+ ctx.showWarning(`No API key available for provider: ${model.provider}`);
807
+ return;
808
+ }
809
+
810
+ const systemPrompt = ctx.session.systemPrompt;
811
+ const messages = convertToLlm(ctx.session.messages);
812
+ const sessionId = ctx.session.sessionId;
813
+ const apiKey = await ctx.session.modelRegistry.getApiKey(model, sessionId);
814
+ let handle: OverlayHandle | undefined;
815
+
816
+ const overlay = new BtwOverlayComponent(
817
+ question,
818
+ model,
819
+ systemPrompt,
820
+ messages,
821
+ ctx.getMarkdownThemeWithSettings(),
822
+ ctx.ui,
823
+ () => {
824
+ handle?.hide();
825
+ },
826
+ () => {
827
+ ctx.requestRender();
828
+ },
829
+ streamSimple,
830
+ { apiKey, sessionId },
831
+ );
832
+
833
+ handle = ctx.ui.showOverlay(overlay, {
834
+ width: "80%",
835
+ maxHeight: "70%",
836
+ anchor: "center",
837
+ margin: { top: 2, bottom: 2, left: 4, right: 4 },
838
+ });
839
+ }
840
+
782
841
  async function handleCompactCommand(customInstructions: string | undefined, ctx: SlashCommandContext): Promise<void> {
783
842
  const entries = ctx.sessionManager.getEntries();
784
843
  const messageCount = entries.filter((e) => e.type === "message").length;
@@ -165,7 +165,7 @@ export type ThemeBg =
165
165
 
166
166
  type ColorMode = "truecolor" | "256color";
167
167
 
168
- export const THEME_ACCENT_PRESETS = ["default", "golden-yellow", "blue", "green", "violet", "red"] as const;
168
+ export const THEME_ACCENT_PRESETS = ["default", "claude", "golden-yellow", "blue", "green", "violet", "red"] as const;
169
169
 
170
170
  export type ThemeAccentPreset = (typeof THEME_ACCENT_PRESETS)[number];
171
171
 
@@ -181,10 +181,16 @@ type ResolvedThemeAccentPreset = Exclude<ThemeAccentPreset, "default">;
181
181
  const THEME_ACCENT_INFO: Record<ThemeAccentPreset, ThemeAccentInfo> = {
182
182
  default: {
183
183
  label: "Default",
184
- description: "Use the active themes native accent colors.",
184
+ description: "Use the active theme's native accent colors.",
185
185
  accent: undefined,
186
186
  thinking: undefined,
187
187
  },
188
+ claude: {
189
+ label: "Claude orange",
190
+ description: "Warm orange Claude accent (#F97316).",
191
+ accent: "#F97316",
192
+ thinking: ["#7C2D12", "#C2410C", "#EA580C", "#F97316", "#FB923C", "#FDBA74"],
193
+ },
188
194
  "golden-yellow": {
189
195
  label: "Golden yellow",
190
196
  description: "Warm amber accent (#F59E0B).",
@@ -500,15 +506,13 @@ export class Theme {
500
506
  return this.mode;
501
507
  }
502
508
 
503
- getThinkingBorderColor(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive"): (str: string) => string {
509
+ getThinkingBorderColor(level: "off" | "low" | "medium" | "high" | "xhigh" | "adaptive"): (str: string) => string {
504
510
  // Map thinking levels to dedicated theme colors
505
511
  switch (level) {
506
512
  case "off":
507
513
  return (str: string) => this.fg("thinkingOff", str);
508
514
  case "adaptive":
509
- return (str: string) => this.fg("thinkingHigh", str);
510
- case "minimal":
511
- return (str: string) => this.fg("thinkingMinimal", str);
515
+ return (str: string) => this.fg("accent", str);
512
516
  case "low":
513
517
  return (str: string) => this.fg("thinkingLow", str);
514
518
  case "medium":
@@ -1171,7 +1175,7 @@ export function getLanguageFromPath(filePath: string): string | undefined {
1171
1175
  return extToLang[ext];
1172
1176
  }
1173
1177
 
1174
- // File path detection regex matches strings that look like file paths:
1178
+ // File path detection regex - matches strings that look like file paths:
1175
1179
  // - Contains a `/` or `\` separator, OR
1176
1180
  // - Ends with a known file extension
1177
1181
  const FILE_PATH_PATTERN = /^(?:\.{0,2}\/|~\/|[a-zA-Z]:\\)[\w\-./\\]+$|^[\w\-./]+\.(?:ts|tsx|js|jsx|json|md|yaml|yml|toml|css|scss|html|py|rs|go|rb|java|c|cpp|h|hpp|sh|bash|zsh|sql|graphql|proto|xml|svg|txt|env|lock|cfg|ini|conf|log|gitignore|dockerignore|editorconfig|prettierrc|eslintrc)$/;
@@ -35,7 +35,7 @@ const dark: ThemeJson = {
35
35
  blueHigh: "#60a5fa",
36
36
  blueXhigh: "#93c5fd",
37
37
  selectedBg: "#323640",
38
- userMsgBg: "#252930",
38
+ userMsgBg: "#272727",
39
39
  toolPendingBg: "#1e2230",
40
40
  toolSuccessBg: "#1a2330",
41
41
  toolErrorBg: "#2a1e30",
@@ -45,6 +45,12 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
45
45
  if (header) {
46
46
  console.log(JSON.stringify(header));
47
47
  }
48
+ console.log(JSON.stringify({
49
+ type: "subagent_session_info",
50
+ sessionFile: session.sessionManager.getSessionFile() ?? null,
51
+ sessionId: session.sessionManager.getSessionId(),
52
+ parentSessionFile: header?.parentSession ?? null,
53
+ }));
48
54
  }
49
55
  const permMode = getPermissionMode();
50
56
  if (permMode === "accept-on-edit") registerStdioApprovalHandler();
@@ -20,6 +20,16 @@ import type {
20
20
  } from "../../core/extensions/index.js";
21
21
  import { InteractiveMode } from "../interactive/interactive-mode.js";
22
22
  import { type Theme, theme } from "../interactive/theme/theme.js";
23
+ import {
24
+ getPermissionMode,
25
+ registerStdioApprovalHandler,
26
+ registerStdioClassifierHandler,
27
+ registerStdioNetworkApprovalHandler,
28
+ resolveApprovalResponse,
29
+ resolveClassifierResponse,
30
+ resolveNetworkApprovalResponse,
31
+ type NetworkApprovalDecision,
32
+ } from "../../core/tool-approval.js";
23
33
  import { createDefaultCommandContextActions } from "../shared/command-context-actions.js";
24
34
  import { attachJsonlLineReader, serializeJsonLine } from "./jsonl.js";
25
35
  import { RemoteTerminal } from "./remote-terminal.js";
@@ -50,6 +60,11 @@ export type {
50
60
  * Listens for JSON commands on stdin, outputs events and responses on stdout.
51
61
  */
52
62
  export async function runRpcMode(session: AgentSession): Promise<never> {
63
+ const permMode = getPermissionMode();
64
+ if (permMode === "accept-on-edit") registerStdioApprovalHandler();
65
+ if (permMode === "auto") registerStdioClassifierHandler();
66
+ registerStdioNetworkApprovalHandler();
67
+
53
68
  const output = (obj: RpcResponse | RpcExtensionUIRequest | object) => {
54
69
  process.stdout.write(serializeJsonLine(obj));
55
70
  };
@@ -845,6 +860,20 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
845
860
  return;
846
861
  }
847
862
 
863
+ // Handle raw approval/classifier/network responses from RPC hosts.
864
+ if (parsed.type === "approval_response") {
865
+ resolveApprovalResponse(parsed.id, Boolean(parsed.approved));
866
+ return;
867
+ }
868
+ if (parsed.type === "classifier_response") {
869
+ resolveClassifierResponse(parsed.id, Boolean(parsed.approved));
870
+ return;
871
+ }
872
+ if (parsed.type === "network_approval_response" && typeof parsed.decision === "string") {
873
+ resolveNetworkApprovalResponse(parsed.id, parsed.decision as NetworkApprovalDecision);
874
+ return;
875
+ }
876
+
848
877
  const command = parsed as RpcCommand;
849
878
 
850
879
  // Protocol version detection: first non-UI-response command locks the version
@@ -9,6 +9,7 @@ import test from "node:test";
9
9
  import assert from "node:assert/strict";
10
10
  import { toPosixPath } from "../utils/path-display.js";
11
11
  import { buildSystemPrompt } from "../core/system-prompt.js";
12
+ import { createGrepTool } from "../core/tools/grep.js";
12
13
 
13
14
  // ─── toPosixPath ────────────────────────────────────────────────────────────
14
15
 
@@ -77,6 +78,22 @@ test("buildSystemPrompt: encourages scout-first reconnaissance when subagent is
77
78
  assert.match(prompt, /When the user names a subagent such as scout, worker, reviewer, or planner, invoke the subagent tool directly/i);
78
79
  });
79
80
 
81
+ test("buildSystemPrompt: prefers lsp over grep for typed code navigation when available", () => {
82
+ const prompt = buildSystemPrompt({
83
+ cwd: "/home/user/project",
84
+ selectedTools: ["read", "grep", "find", "ls", "lsp"],
85
+ });
86
+ assert.match(prompt, /use lsp first for symbols/i);
87
+ assert.match(prompt, /Do not use grep\/find as a substitute for symbol navigation when LSP is available/i);
88
+ assert.match(prompt, /If LSP is unavailable or failing, say so briefly and then fall back to grep\/read/i);
89
+ });
90
+
91
+ test("createGrepTool: description steers semantic code navigation to lsp", () => {
92
+ const tool = createGrepTool(process.cwd());
93
+ assert.match(tool.description, /Use this for raw text search, not semantic code navigation/i);
94
+ assert.match(tool.description, /use the `lsp` tool instead when available/i);
95
+ });
96
+
80
97
  // ─── Regression: no backslash paths in LLM-visible text ────────────────────
81
98
 
82
99
  /**
@@ -19,8 +19,9 @@ export declare class Loader extends Text {
19
19
  private phase;
20
20
  private visibleChars;
21
21
  private wordAnimId;
22
- private readonly gradStart;
23
- private readonly gradEnd;
22
+ private gradStart;
23
+ private gradEnd;
24
+ private gradParsed;
24
25
  private shimmerTick;
25
26
  private shimmerIntervalId;
26
27
  constructor(ui: TUI, spinnerColorFn: (str: string) => string, _messageColorFn: (str: string) => string, message?: string);
@@ -36,6 +37,8 @@ export declare class Loader extends Text {
36
37
  private stopWordAnimation;
37
38
  private scheduleWordTick;
38
39
  private currentWord;
40
+ /** Parse the accent color from the theme's messageColorFn and build a shimmer gradient. */
41
+ private parseGradient;
39
42
  private renderAnimatedWord;
40
43
  private updateDisplay;
41
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqCjC;;;;;GAKG;AACH,qBAAa,MAAO,SAAQ,IAAI;IA2B9B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,eAAe;IA1BxB,OAAO,CAAC,MAAM,CAAsD;IACpE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,EAAE,CAAoB;IAG9B,OAAO,CAAC,OAAO,CAAc;IAG7B,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAA+B;IAGjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+C;IAGvE,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,iBAAiB,CAA+B;gBAGvD,EAAE,EAAE,GAAG,EACC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAChD,OAAO,GAAE,MAAmB;IAQ7B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAM/B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,WAAW,SAAO;IAUvD,kBAAkB;IAKlB,UAAU,CAAC,OAAO,EAAE,MAAM;IAS1B,WAAW;IAMX,KAAK;IAqBL,IAAI;IAMJ,OAAO;IAOP,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,aAAa;CASrB"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqCjC;;;;;GAKG;AACH,qBAAa,MAAO,SAAQ,IAAI;IA6B9B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,eAAe;IA5BxB,OAAO,CAAC,MAAM,CAAsD;IACpE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,EAAE,CAAoB;IAG9B,OAAO,CAAC,OAAO,CAAc;IAG7B,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAA+B;IAIjD,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,OAAO,CAA+C;IAC9D,OAAO,CAAC,UAAU,CAAS;IAG3B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,iBAAiB,CAA+B;gBAGvD,EAAE,EAAE,GAAG,EACC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAChD,OAAO,GAAE,MAAmB;IAQ7B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAM/B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,WAAW,SAAO;IAUvD,kBAAkB;IAKlB,UAAU,CAAC,OAAO,EAAE,MAAM;IAS1B,WAAW;IAMX,KAAK;IAqBL,IAAI;IAMJ,OAAO;IAOP,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,WAAW;IAMnB,2FAA2F;IAC3F,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,aAAa;CASrB"}
@@ -44,9 +44,11 @@ export class Loader extends Text {
44
44
  this.phase = "typing";
45
45
  this.visibleChars = 0;
46
46
  this.wordAnimId = null;
47
- // ── shimmer gradient: theme blueHigh blueXhigh ─────────────────────────
48
- this.gradStart = [147, 197, 253]; // #93c5fd (blue-300)
49
- this.gradEnd = [191, 219, 254]; // #bfdbfe (blue-200)
47
+ // ── shimmer gradient: derived from messageColorFn accent ─────────────────
48
+ // Parsed lazily from a sample render of _messageColorFn so it tracks the live theme.
49
+ this.gradStart = [147, 197, 253]; // fallback blue-300
50
+ this.gradEnd = [191, 219, 254]; // fallback blue-200
51
+ this.gradParsed = false;
50
52
  // Shimmer ticks independently at ~40ms for smooth gradient movement
51
53
  this.shimmerTick = 0;
52
54
  this.shimmerIntervalId = null;
@@ -176,7 +178,35 @@ export class Loader extends Text {
176
178
  return this.message;
177
179
  }
178
180
  // ── rendering ─────────────────────────────────────────────────────────────
181
+ /** Parse the accent color from the theme's messageColorFn and build a shimmer gradient. */
182
+ parseGradient() {
183
+ try {
184
+ // Render a single char through the accent color function and extract the RGB escape
185
+ const sample = this._messageColorFn("x");
186
+ const m = sample.match(/\x1b\[38;2;(\d+);(\d+);(\d+)m/);
187
+ if (!m)
188
+ return;
189
+ const r = parseInt(m[1]), g = parseInt(m[2]), b = parseInt(m[3]);
190
+ // gradStart = accent lightened slightly, gradEnd = accent lightened more
191
+ this.gradStart = [
192
+ Math.min(255, Math.round(r + (255 - r) * 0.15)),
193
+ Math.min(255, Math.round(g + (255 - g) * 0.15)),
194
+ Math.min(255, Math.round(b + (255 - b) * 0.15)),
195
+ ];
196
+ this.gradEnd = [
197
+ Math.min(255, Math.round(r + (255 - r) * 0.40)),
198
+ Math.min(255, Math.round(g + (255 - g) * 0.40)),
199
+ Math.min(255, Math.round(b + (255 - b) * 0.40)),
200
+ ];
201
+ this.gradParsed = true;
202
+ }
203
+ catch {
204
+ // keep fallback blue gradient
205
+ }
206
+ }
179
207
  renderAnimatedWord() {
208
+ if (!this.gradParsed)
209
+ this.parseGradient();
180
210
  const word = this.currentWord();
181
211
  const visible = word.slice(0, this.visibleChars);
182
212
  if (!visible)