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
@@ -3,93 +3,36 @@ import { Type } from "@sinclair/typebox";
3
3
  import type { ToolDeps } from "../state.js";
4
4
 
5
5
  /**
6
- * State persistence tools — save/restore cookies, localStorage, sessionStorage.
6
+ * State persistence — save/restore cookies, localStorage, sessionStorage.
7
7
  */
8
8
 
9
9
  const STATE_DIR = ".gsd/browser-state";
10
10
 
11
11
  export function registerStatePersistenceTools(pi: ExtensionAPI, deps: ToolDeps): void {
12
- // -------------------------------------------------------------------------
13
- // browser_save_state
14
- // -------------------------------------------------------------------------
15
12
  pi.registerTool({
16
- name: "browser_save_state",
17
- label: "Browser Save State",
13
+ name: "browser_state",
14
+ label: "Browser State",
18
15
  description:
19
- "Save cookies, localStorage, and sessionStorage to disk so authenticated sessions survive browser restarts. " +
20
- "State files are written to .gsd/browser-state/ and should be gitignored (may contain auth tokens). " +
21
- "Never displays secret values in output.",
16
+ "Save or restore browser state (cookies, localStorage, sessionStorage) to persist sessions across browser restarts. " +
17
+ "State files written to .gsd/browser-state/ (should be gitignored).",
22
18
  parameters: Type.Object({
23
- name: Type.Optional(
24
- Type.String({ description: "Name for the state file (default: 'default'). Used as the filename stem." }),
25
- ),
19
+ action: Type.Union([
20
+ Type.Literal("save"),
21
+ Type.Literal("restore"),
22
+ ], { description: "'save' — persist current state, 'restore' — load previously saved state" }),
23
+ name: Type.Optional(Type.String({ description: "State file name (default: 'default'). Used as filename stem." })),
26
24
  }),
27
25
 
28
26
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
29
27
  try {
30
- const { context: ctx, page: p } = await deps.ensureBrowser();
31
- const name = deps.sanitizeArtifactName(params.name ?? "default", "default");
32
-
33
- const { mkdir, writeFile } = await import("node:fs/promises");
34
- const path = await import("node:path");
35
- const stateDir = path.resolve(process.cwd(), STATE_DIR);
36
- await mkdir(stateDir, { recursive: true });
37
-
38
- // 1. Playwright storageState: cookies + localStorage
39
- const storageState = await ctx.storageState();
40
-
41
- // 2. sessionStorage: must be extracted per-origin via page.evaluate
42
- const sessionStorageData: Record<string, Record<string, string>> = {};
43
- try {
44
- const origin = new URL(p.url()).origin;
45
- const ssData = await p.evaluate(() => {
46
- const data: Record<string, string> = {};
47
- for (let i = 0; i < sessionStorage.length; i++) {
48
- const key = sessionStorage.key(i);
49
- if (key) data[key] = sessionStorage.getItem(key) ?? "";
50
- }
51
- return data;
52
- });
53
- if (Object.keys(ssData).length > 0) {
54
- sessionStorageData[origin] = ssData;
55
- }
56
- } catch {
57
- // Page may not have a valid origin (about:blank, etc.)
28
+ if (params.action === "save") {
29
+ return await saveState(deps, params.name ?? "default");
30
+ } else {
31
+ return await restoreState(deps, params.name ?? "default");
58
32
  }
59
-
60
- const combined = {
61
- storageState,
62
- sessionStorage: sessionStorageData,
63
- savedAt: new Date().toISOString(),
64
- url: p.url(),
65
- };
66
-
67
- const filePath = path.join(stateDir, `${name}.json`);
68
- await writeFile(filePath, JSON.stringify(combined, null, 2));
69
-
70
- // Ensure .gitignore covers the state dir
71
- const gitignorePath = path.resolve(process.cwd(), STATE_DIR, ".gitignore");
72
- await writeFile(gitignorePath, "*\n!.gitignore\n").catch(() => { /* best-effort — .gitignore may already exist or dir may be read-only */ });
73
-
74
- const cookieCount = storageState.cookies?.length ?? 0;
75
- const localStorageOrigins = storageState.origins?.length ?? 0;
76
- const sessionStorageOrigins = Object.keys(sessionStorageData).length;
77
-
78
- return {
79
- content: [{
80
- type: "text",
81
- text: `State saved: ${filePath}\nCookies: ${cookieCount}\nlocalStorage origins: ${localStorageOrigins}\nsessionStorage origins: ${sessionStorageOrigins}`,
82
- }],
83
- details: {
84
- path: filePath,
85
- cookieCount,
86
- localStorageOrigins,
87
- sessionStorageOrigins,
88
- },
89
- };
90
33
  } catch (err: any) {
91
34
  return {
92
- content: [{ type: "text", text: `Save state failed: ${err.message}` }],
35
+ content: [{ type: "text" as const, text: `State '${params.action}' failed: ${err.message}` }],
93
36
  details: { error: err.message },
94
37
  isError: true,
95
38
  };
@@ -97,106 +40,85 @@ export function registerStatePersistenceTools(pi: ExtensionAPI, deps: ToolDeps):
97
40
  },
98
41
  });
99
42
 
100
- // -------------------------------------------------------------------------
101
- // browser_restore_state
102
- // -------------------------------------------------------------------------
103
- pi.registerTool({
104
- name: "browser_restore_state",
105
- label: "Browser Restore State",
106
- description:
107
- "Restore cookies, localStorage, and sessionStorage from a previously saved state file. " +
108
- "Injects cookies via context.addCookies() and storage via page.evaluate(). " +
109
- "For full fidelity, restore before navigating to the target site.",
110
- parameters: Type.Object({
111
- name: Type.Optional(
112
- Type.String({ description: "Name of the state file to restore (default: 'default')." }),
113
- ),
114
- }),
115
-
116
- async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
117
- try {
118
- const { context: ctx, page: p } = await deps.ensureBrowser();
119
- const name = deps.sanitizeArtifactName(params.name ?? "default", "default");
120
-
121
- const { readFile } = await import("node:fs/promises");
122
- const path = await import("node:path");
123
- const filePath = path.join(process.cwd(), STATE_DIR, `${name}.json`);
124
-
125
- let raw: string;
126
- try {
127
- raw = await readFile(filePath, "utf-8");
128
- } catch {
129
- return {
130
- content: [{ type: "text", text: `State file not found: ${filePath}` }],
131
- details: { error: "file_not_found", path: filePath },
132
- isError: true,
133
- };
134
- }
135
-
136
- const combined = JSON.parse(raw);
137
- const storageState = combined.storageState;
138
- const sessionStorageData: Record<string, Record<string, string>> = combined.sessionStorage ?? {};
139
-
140
- // 1. Restore cookies
141
- let cookieCount = 0;
142
- if (storageState?.cookies?.length) {
143
- await ctx.addCookies(storageState.cookies);
144
- cookieCount = storageState.cookies.length;
145
- }
146
-
147
- // 2. Restore localStorage via page.evaluate
148
- let localStorageOrigins = 0;
149
- if (storageState?.origins?.length) {
150
- for (const origin of storageState.origins) {
151
- try {
152
- await p.evaluate((items: Array<{ name: string; value: string }>) => {
153
- for (const { name, value } of items) {
154
- localStorage.setItem(name, value);
155
- }
156
- }, origin.localStorage ?? []);
157
- localStorageOrigins++;
158
- } catch {
159
- // Origin mismatch — localStorage can only be set on matching origin
160
- }
161
- }
43
+ async function saveState(deps: ToolDeps, name: string) {
44
+ const { context: ctx, page: p } = await deps.ensureBrowser();
45
+ name = deps.sanitizeArtifactName(name, "default");
46
+ const { mkdir, writeFile } = await import("node:fs/promises");
47
+ const path = await import("node:path");
48
+ const stateDir = path.resolve(process.cwd(), STATE_DIR);
49
+ await mkdir(stateDir, { recursive: true });
50
+
51
+ const storageState = await ctx.storageState();
52
+ const sessionStorageData: Record<string, Record<string, string>> = {};
53
+ try {
54
+ const origin = new URL(p.url()).origin;
55
+ const ssData = await p.evaluate(() => {
56
+ const data: Record<string, string> = {};
57
+ for (let i = 0; i < sessionStorage.length; i++) {
58
+ const key = sessionStorage.key(i);
59
+ if (key) data[key] = sessionStorage.getItem(key) ?? "";
162
60
  }
163
-
164
- // 3. Restore sessionStorage via page.evaluate
165
- let sessionStorageOrigins = 0;
166
- for (const [_origin, data] of Object.entries(sessionStorageData)) {
167
- try {
168
- await p.evaluate((items: Record<string, string>) => {
169
- for (const [key, value] of Object.entries(items)) {
170
- sessionStorage.setItem(key, value);
171
- }
172
- }, data);
173
- sessionStorageOrigins++;
174
- } catch {
175
- // Origin mismatch
176
- }
177
- }
178
-
179
- return {
180
- content: [{
181
- type: "text",
182
- text: `State restored from: ${filePath}\nCookies: ${cookieCount}\nlocalStorage origins: ${localStorageOrigins}\nsessionStorage origins: ${sessionStorageOrigins}\nSaved at: ${combined.savedAt ?? "unknown"}`,
183
- }],
184
- details: {
185
- path: filePath,
186
- cookieCount,
187
- localStorageOrigins,
188
- sessionStorageOrigins,
189
- savedAt: combined.savedAt,
190
- savedUrl: combined.url,
191
- },
192
- };
193
- } catch (err: any) {
194
- return {
195
- content: [{ type: "text", text: `Restore state failed: ${err.message}` }],
196
- details: { error: err.message },
197
- isError: true,
198
- };
61
+ return data;
62
+ });
63
+ if (Object.keys(ssData).length > 0) sessionStorageData[origin] = ssData;
64
+ } catch { /* Page may not have a valid origin */ }
65
+
66
+ const combined = { storageState, sessionStorage: sessionStorageData, savedAt: new Date().toISOString(), url: p.url() };
67
+ const filePath = path.join(stateDir, `${name}.json`);
68
+ await writeFile(filePath, JSON.stringify(combined, null, 2));
69
+
70
+ const gitignorePath = path.resolve(process.cwd(), STATE_DIR, ".gitignore");
71
+ await writeFile(gitignorePath, "*\n!.gitignore\n").catch(() => { /* best-effort */ });
72
+
73
+ return {
74
+ content: [{ type: "text" as const, text: `State saved: ${filePath}\nCookies: ${storageState.cookies?.length ?? 0}\nlocalStorage origins: ${storageState.origins?.length ?? 0}\nsessionStorage origins: ${Object.keys(sessionStorageData).length}` }],
75
+ details: { path: filePath, cookieCount: storageState.cookies?.length ?? 0, localStorageOrigins: storageState.origins?.length ?? 0, sessionStorageOrigins: Object.keys(sessionStorageData).length },
76
+ };
77
+ }
78
+
79
+ async function restoreState(deps: ToolDeps, name: string) {
80
+ const { context: ctx, page: p } = await deps.ensureBrowser();
81
+ name = deps.sanitizeArtifactName(name, "default");
82
+ const { readFile } = await import("node:fs/promises");
83
+ const path = await import("node:path");
84
+ const filePath = path.join(process.cwd(), STATE_DIR, `${name}.json`);
85
+
86
+ let raw: string;
87
+ try { raw = await readFile(filePath, "utf-8"); } catch {
88
+ return { content: [{ type: "text" as const, text: `State file not found: ${filePath}` }], details: { error: "file_not_found", path: filePath }, isError: true };
89
+ }
90
+
91
+ const combined = JSON.parse(raw);
92
+ const storageState = combined.storageState;
93
+ const sessionStorageData: Record<string, Record<string, string>> = combined.sessionStorage ?? {};
94
+
95
+ let cookieCount = 0;
96
+ if (storageState?.cookies?.length) {
97
+ await ctx.addCookies(storageState.cookies);
98
+ cookieCount = storageState.cookies.length;
99
+ }
100
+
101
+ let localStorageOrigins = 0;
102
+ if (storageState?.origins?.length) {
103
+ for (const origin of storageState.origins) {
104
+ try {
105
+ await p.evaluate((items: Array<{ name: string; value: string }>) => { for (const { name, value } of items) localStorage.setItem(name, value); }, origin.localStorage ?? []);
106
+ localStorageOrigins++;
107
+ } catch { /* Origin mismatch */ }
199
108
  }
200
- },
201
- });
109
+ }
110
+
111
+ let sessionStorageOrigins = 0;
112
+ for (const [_origin, data] of Object.entries(sessionStorageData)) {
113
+ try {
114
+ await p.evaluate((items: Record<string, string>) => { for (const [key, value] of Object.entries(items)) sessionStorage.setItem(key, value); }, data);
115
+ sessionStorageOrigins++;
116
+ } catch { /* Origin mismatch */ }
117
+ }
118
+
119
+ return {
120
+ content: [{ type: "text" as const, text: `State restored from: ${filePath}\nCookies: ${cookieCount}\nlocalStorage origins: ${localStorageOrigins}\nsessionStorage origins: ${sessionStorageOrigins}` }],
121
+ details: { path: filePath, cookieCount, localStorageOrigins, sessionStorageOrigins, savedAt: combined.savedAt, savedUrl: combined.url },
122
+ };
123
+ }
202
124
  }
@@ -625,7 +625,7 @@ export function formatVersionedRef(version: number, key: string): string {
625
625
  }
626
626
 
627
627
  export function staleRefGuidance(refDisplay: string, reason: string): string {
628
- return `Ref ${refDisplay} could not be resolved (${reason}). The ref is likely stale after DOM/navigation changes. Call browser_snapshot_refs again to refresh refs.`;
628
+ return `Ref ${refDisplay} could not be resolved (${reason}). The ref is likely stale after DOM/navigation changes. Call browser_ref with action='snapshot' to refresh refs.`;
629
629
  }
630
630
 
631
631
  // ---------------------------------------------------------------------------
@@ -204,9 +204,7 @@ export default function (pi: ExtensionAPI) {
204
204
  "List all running macOS applications. Returns an array of { name, bundleId, pid, isActive } " +
205
205
  "for user-facing apps (regular activation policy). Set includeBackground to true to also " +
206
206
  "include accessory/background apps.",
207
- promptGuidelines: [
208
- "Use to discover what apps are running before interacting with them.",
209
- ],
207
+ promptGuidelines: [] as string[],
210
208
  parameters: Type.Object({
211
209
  includeBackground: Type.Optional(Type.Boolean({ description: "Include background/accessory apps (default: false)" })),
212
210
  }),
@@ -235,9 +233,6 @@ export default function (pi: ExtensionAPI) {
235
233
  "Launch a macOS application by name or bundle ID. " +
236
234
  "Returns { launched, name, bundleId, pid } on success. " +
237
235
  "Provide either 'name' (e.g. 'TextEdit') or 'bundleId' (e.g. 'com.apple.TextEdit').",
238
- promptGuidelines: [
239
- "Use app name for well-known apps; use bundleId when the name is ambiguous.",
240
- ],
241
236
  parameters: Type.Object({
242
237
  name: Type.Optional(Type.String({ description: "Application name (e.g. 'TextEdit', 'Safari')" })),
243
238
  bundleId: Type.Optional(Type.String({ description: "Bundle identifier (e.g. 'com.apple.TextEdit')" })),
@@ -310,9 +305,7 @@ export default function (pi: ExtensionAPI) {
310
305
  "Quit a running macOS application. " +
311
306
  "Returns { quit, name } on success. Errors if the app is not running. " +
312
307
  "Provide either 'name' or 'bundleId'.",
313
- promptGuidelines: [
314
- "Use to clean up apps launched during automation — don't leave apps running unnecessarily.",
315
- ],
308
+ promptGuidelines: [] as string[],
316
309
  parameters: Type.Object({
317
310
  name: Type.Optional(Type.String({ description: "Application name" })),
318
311
  bundleId: Type.Optional(Type.String({ description: "Bundle identifier" })),
@@ -349,9 +342,7 @@ export default function (pi: ExtensionAPI) {
349
342
  "The windowId can be used with getWindowInfo for detailed inspection or with screenshotWindow for capture. " +
350
343
  "Returns an empty array (not error) if the app is running but has no visible windows. " +
351
344
  "Errors if the app is not running.",
352
- promptGuidelines: [
353
- "Use to get windowId values needed by mac_screenshot.",
354
- ],
345
+ promptGuidelines: [] as string[],
355
346
  parameters: Type.Object({
356
347
  app: Type.String({ description: "Application name (e.g. 'TextEdit') or bundle identifier (e.g. 'com.apple.TextEdit')" }),
357
348
  }),
@@ -393,8 +384,7 @@ export default function (pi: ExtensionAPI) {
393
384
  "The 'app' param accepts an app name (e.g. 'Finder') or bundle ID (e.g. 'com.apple.Finder').",
394
385
  promptGuidelines: [
395
386
  "Prefer for targeted element search — use role/title/value criteria to narrow results.",
396
- "Use mode:focused to check the current focus target without search criteria.",
397
- "Use mac_get_tree instead of mode:tree when you just need to understand app structure.",
387
+ "Use mac_get_tree instead of mode:tree for quick structure inspection.",
398
388
  ],
399
389
  parameters: Type.Object({
400
390
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -524,9 +514,7 @@ export default function (pi: ExtensionAPI) {
524
514
  "Each line: `role \"title\" [value]` with 2-space indent per depth level. " +
525
515
  "Omits title/value when nil or empty.",
526
516
  promptGuidelines: [
527
- "Use for understanding app UI structure — start with low limits and increase if needed.",
528
517
  "Prefer mac_find search mode when you know what you're looking for.",
529
- "Check the truncation note to know if the tree was cut short.",
530
518
  ],
531
519
  parameters: Type.Object({
532
520
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -581,8 +569,7 @@ export default function (pi: ExtensionAPI) {
581
569
  "Finds the first element matching the given criteria (role, title, value, identifier) and clicks it. " +
582
570
  "At least one criterion is required. Returns the clicked element's attributes.",
583
571
  promptGuidelines: [
584
- "Verify the click worked by reading the resulting state with mac_find or mac_read.",
585
- "Use mac_find first to discover the right role/title/value criteria before clicking.",
572
+ "Use mac_find first to discover the right criteria before clicking.",
586
573
  ],
587
574
  parameters: Type.Object({
588
575
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -638,8 +625,7 @@ export default function (pi: ExtensionAPI) {
638
625
  "Returns the actual value after setting (read-back verification). " +
639
626
  "At least one criterion is required.",
640
627
  promptGuidelines: [
641
- "Read back the value after typing to verify — the return value includes actual content.",
642
- "Target text fields/areas by role (AXTextArea, AXTextField) for reliability.",
628
+ "Target text fields by role (AXTextArea, AXTextField) for reliability.",
643
629
  ],
644
630
  parameters: Type.Object({
645
631
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -697,9 +683,7 @@ export default function (pi: ExtensionAPI) {
697
683
  "Returns the screenshot as an image content block for visual analysis, alongside text metadata " +
698
684
  "(dimensions and format). Requires Screen Recording permission — use mac_check_permissions to verify.",
699
685
  promptGuidelines: [
700
- "Use for visual verification when accessibility attributes aren't sufficient.",
701
- "Prefer nominal resolution unless retina detail is needed — retina doubles payload size.",
702
- "Requires Screen Recording permission — run mac_check_permissions first if screenshot fails.",
686
+ "Prefer nominal resolution; retina doubles payload. Run mac_check_permissions if it fails.",
703
687
  ],
704
688
  parameters: Type.Object({
705
689
  windowId: Type.Number({ description: "Window ID from mac_list_windows output" }),
@@ -747,9 +731,7 @@ export default function (pi: ExtensionAPI) {
747
731
  "Finds the first element matching the given criteria and reads the named attribute(s). " +
748
732
  "AXValue subtypes (CGPoint, CGSize, CGRect, CFRange) are automatically unpacked to structured dicts. " +
749
733
  "Use 'attribute' for a single attribute or 'attributes' for multiple. At least one search criterion is required.",
750
- promptGuidelines: [
751
- "Use to verify state after actions — read AXValue to confirm text was typed, AXEnabled to check if a button is active.",
752
- ],
734
+ promptGuidelines: [] as string[],
753
735
  parameters: Type.Object({
754
736
  app: Type.String({ description: "Application name or bundle identifier" }),
755
737
  attribute: Type.Optional(Type.String({ description: "Single attribute name to read (e.g. 'AXValue', 'AXPosition', 'AXRole')" })),
@@ -824,8 +806,13 @@ export default function (pi: ExtensionAPI) {
824
806
 
825
807
  // -----------------------------------------------------------------
826
808
  // System prompt injection — mac-tools usage guidelines
809
+ // Only inject when mac tools are actually active.
827
810
  // -----------------------------------------------------------------
828
811
  pi.on("before_agent_start", async (event) => {
812
+ const activeTools = new Set(pi.getActiveTools());
813
+ const hasMacTools = [...activeTools].some((name) => name.startsWith("mac_"));
814
+ if (!hasMacTools) return;
815
+
829
816
  const guidelines = `
830
817
 
831
818
  [SYSTEM CONTEXT — Mac Tools]
@@ -834,18 +821,16 @@ export default function (pi: ExtensionAPI) {
834
821
 
835
822
  You have mac-tools for controlling native macOS applications (Finder, TextEdit, Safari, Xcode, etc.) via Accessibility APIs.
836
823
 
837
- **Mac-tools vs browser-tools:** Use mac-tools for native macOS apps. Use browser-tools for web pages inside a browser. If you need to interact with a website in Safari or Chrome, use browser-tools — mac-tools controls the browser's native UI chrome (menus, tabs, address bar), not web page content.
824
+ **Mac-tools vs browser-tools:** Use mac-tools for native macOS apps. Use browser-tools for web pages inside a browser.
838
825
 
839
- **Permissions:** If any mac tool returns a permission error, run \`mac_check_permissions\` to diagnose. Accessibility and Screen Recording permissions are granted in System Settings > Privacy & Security.
826
+ **Permissions:** If any mac tool returns a permission error, run \`mac_check_permissions\` to diagnose.
840
827
 
841
828
  **Interaction pattern — discover → act → verify:**
842
- 1. **Discover** the UI structure with \`mac_find\` (search for specific elements) or \`mac_get_tree\` (see overall layout)
843
- 2. **Act** with \`mac_click\` (press buttons/menus) or \`mac_type\` (enter text into fields)
844
- 3. **Verify** the result with \`mac_read\` (check attribute values) or \`mac_screenshot\` (visual confirmation)
845
-
846
- **Tree queries:** Start with default limits (mac_get_tree: maxDepth:3, maxCount:50). Increase only if the element you need isn't visible in the output. Large trees waste context.
829
+ 1. **Discover** with \`mac_find\` or \`mac_get_tree\`
830
+ 2. **Act** with \`mac_click\` or \`mac_type\`
831
+ 3. **Verify** with \`mac_read\` or \`mac_screenshot\`
847
832
 
848
- **Screenshots:** Use \`mac_screenshot\` only when visual verification is genuinely needed — the image payload is large. Prefer \`mac_read\` or \`mac_find\` for checking text values and element state.`;
833
+ Start with default tree limits (maxDepth:3, maxCount:50). Use \`mac_screenshot\` sparingly — the payload is large.`;
849
834
 
850
835
  return { systemPrompt: event.systemPrompt + guidelines };
851
836
  });
@@ -93,9 +93,29 @@ function truncateEntrypointContent(raw: string): {
93
93
  * @param memoryDir Absolute path to the project's memory directory.
94
94
  * @param entrypointContent The (possibly truncated) contents of MEMORY.md.
95
95
  */
96
- function buildMemoryPrompt(memoryDir: string, entrypointContent: string): string {
96
+ function buildMemoryPrompt(memoryDir: string, entrypointContent: string, hasMemories: boolean): string {
97
97
  const sections: string[] = [];
98
98
 
99
+ if (!hasMemories) {
100
+ // Slim prompt when no memories exist — just enough to know the system is there
101
+ // and how to save the first memory. Full instructions are deferred until needed.
102
+ sections.push(`# Memory
103
+
104
+ You have a persistent, file-based memory system at \`${memoryDir}\`.
105
+ This directory already exists — write to it directly with the file write tool.
106
+
107
+ If the user explicitly asks you to remember something, save it immediately. If they ask you to forget, find and remove it.
108
+
109
+ To save a memory:
110
+ 1. Write a markdown file to the memory directory with YAML frontmatter (name, description, type: user|feedback|project|reference)
111
+ 2. Add a one-line pointer to MEMORY.md: \`- [Title](file.md) — one-line hook\`
112
+
113
+ Your MEMORY.md is currently empty.`);
114
+ return sections.join('\n\n');
115
+ }
116
+
117
+ // ── Full prompt when memories exist ──
118
+
99
119
  // ── Header ──
100
120
  sections.push(`# Memory
101
121
 
@@ -196,7 +216,7 @@ export default function memoryExtension(pi: ExtensionAPI) {
196
216
  entrypointContent = content;
197
217
  }
198
218
 
199
- const prompt = buildMemoryPrompt(memoryDir, entrypointContent);
219
+ const prompt = buildMemoryPrompt(memoryDir, entrypointContent, !!entrypointContent.trim());
200
220
 
201
221
  return {
202
222
  systemPrompt: event.systemPrompt + '\n\n' + prompt,