lsd-pi 1.2.3 → 1.3.2

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 (254) 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/mac-tools/index.js +19 -34
  27. package/dist/resources/extensions/memory/index.js +20 -2
  28. package/dist/resources/extensions/shared/interview-ui.js +103 -20
  29. package/dist/resources/extensions/slash-commands/plan.js +18 -17
  30. package/dist/resources/extensions/slash-commands/tools.js +40 -4
  31. package/dist/resources/extensions/subagent/agent-switcher-component.js +208 -0
  32. package/dist/resources/extensions/subagent/agent-switcher-model.js +107 -0
  33. package/dist/resources/extensions/subagent/agents.js +2 -1
  34. package/dist/resources/extensions/subagent/background-job-manager.js +11 -6
  35. package/dist/resources/extensions/subagent/background-runner.js +4 -0
  36. package/dist/resources/extensions/subagent/index.js +714 -21
  37. package/dist/resources/extensions/subagent/launch-helpers.js +21 -6
  38. package/dist/shared-paths.d.ts +4 -0
  39. package/dist/shared-paths.js +4 -0
  40. package/dist/shared-preferences.d.ts +4 -0
  41. package/dist/shared-preferences.js +4 -0
  42. package/dist/startup-model-validation.d.ts +1 -1
  43. package/dist/startup-timings.d.ts +4 -0
  44. package/dist/startup-timings.js +4 -0
  45. package/dist/update-check.d.ts +4 -0
  46. package/dist/update-check.js +4 -0
  47. package/dist/update-cmd.d.ts +4 -0
  48. package/dist/update-cmd.js +4 -0
  49. package/dist/welcome-screen.js +4 -4
  50. package/dist/wizard.d.ts +4 -0
  51. package/dist/wizard.js +4 -0
  52. package/package.json +1 -1
  53. package/packages/pi-agent-core/dist/agent.d.ts +9 -0
  54. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  55. package/packages/pi-agent-core/dist/agent.js +89 -5
  56. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  57. package/packages/pi-agent-core/dist/types.d.ts +13 -2
  58. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  59. package/packages/pi-agent-core/dist/types.js.map +1 -1
  60. package/packages/pi-agent-core/src/agent.ts +110 -4
  61. package/packages/pi-agent-core/src/types.ts +12 -3
  62. package/packages/pi-ai/dist/adaptive/classifier.d.ts +29 -0
  63. package/packages/pi-ai/dist/adaptive/classifier.d.ts.map +1 -0
  64. package/packages/pi-ai/dist/adaptive/classifier.js +72 -0
  65. package/packages/pi-ai/dist/adaptive/classifier.js.map +1 -0
  66. package/packages/pi-ai/dist/adaptive/classifier.test.d.ts +2 -0
  67. package/packages/pi-ai/dist/adaptive/classifier.test.d.ts.map +1 -0
  68. package/packages/pi-ai/dist/adaptive/classifier.test.js +32 -0
  69. package/packages/pi-ai/dist/adaptive/classifier.test.js.map +1 -0
  70. package/packages/pi-ai/dist/index.d.ts +1 -0
  71. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  72. package/packages/pi-ai/dist/index.js +1 -0
  73. package/packages/pi-ai/dist/index.js.map +1 -1
  74. package/packages/pi-ai/dist/providers/amazon-bedrock.js +0 -2
  75. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  76. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  77. package/packages/pi-ai/dist/providers/anthropic-shared.js +11 -3
  78. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  79. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
  80. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  81. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  82. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  83. package/packages/pi-ai/dist/providers/google-gemini-cli.js +0 -4
  84. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  85. package/packages/pi-ai/dist/providers/google-vertex.js +0 -5
  86. package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
  87. package/packages/pi-ai/dist/providers/google.js +0 -5
  88. package/packages/pi-ai/dist/providers/google.js.map +1 -1
  89. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
  90. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  91. package/packages/pi-ai/dist/providers/openai-codex-responses.js +0 -2
  92. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  93. package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
  94. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  95. package/packages/pi-ai/dist/providers/openai-completions.js +0 -1
  96. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  97. package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
  98. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  99. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  100. package/packages/pi-ai/dist/providers/openai-shared.d.ts +0 -1
  101. package/packages/pi-ai/dist/providers/openai-shared.d.ts.map +1 -1
  102. package/packages/pi-ai/dist/providers/openai-shared.js +0 -4
  103. package/packages/pi-ai/dist/providers/openai-shared.js.map +1 -1
  104. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  105. package/packages/pi-ai/dist/providers/simple-options.js +0 -1
  106. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  107. package/packages/pi-ai/dist/types.d.ts +1 -2
  108. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  109. package/packages/pi-ai/dist/types.js.map +1 -1
  110. package/packages/pi-ai/src/adaptive/classifier.test.ts +38 -0
  111. package/packages/pi-ai/src/adaptive/classifier.ts +107 -0
  112. package/packages/pi-ai/src/index.ts +1 -0
  113. package/packages/pi-ai/src/providers/amazon-bedrock.ts +0 -2
  114. package/packages/pi-ai/src/providers/anthropic-shared.ts +12 -3
  115. package/packages/pi-ai/src/providers/azure-openai-responses.ts +1 -1
  116. package/packages/pi-ai/src/providers/google-gemini-cli.ts +0 -4
  117. package/packages/pi-ai/src/providers/google-vertex.ts +0 -5
  118. package/packages/pi-ai/src/providers/google.ts +0 -5
  119. package/packages/pi-ai/src/providers/openai-codex-responses.ts +1 -3
  120. package/packages/pi-ai/src/providers/openai-completions.ts +1 -2
  121. package/packages/pi-ai/src/providers/openai-responses.ts +1 -1
  122. package/packages/pi-ai/src/providers/openai-shared.ts +0 -3
  123. package/packages/pi-ai/src/providers/simple-options.ts +0 -1
  124. package/packages/pi-ai/src/types.ts +1 -2
  125. package/packages/pi-coding-agent/dist/cli/args.js +2 -2
  126. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +7 -2
  128. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/agent-session.js +62 -23
  130. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/lsp/lsp.md +3 -1
  132. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  133. package/packages/pi-coding-agent/dist/core/sdk.js +32 -6
  134. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/sdk.test.js +37 -0
  136. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +8 -0
  138. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/session-manager.js +4 -0
  140. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +12 -7
  142. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/settings-manager.js +20 -2
  144. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  147. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -1
  149. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -2
  152. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/tools/grep.js +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
  156. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/tools/index.js +2 -0
  158. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +10 -1
  160. package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/tools/pty.js +29 -3
  162. package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +1 -1
  164. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -1
  165. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  166. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +12 -2
  167. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +7 -2
  169. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +23 -4
  171. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js +1 -2
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +9 -0
  177. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  179. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +53 -2
  180. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +2 -2
  182. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -6
  184. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +1 -1
  186. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  188. package/packages/pi-coding-agent/dist/modes/print-mode.js +6 -0
  189. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +20 -0
  192. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/tests/path-display.test.js +15 -0
  194. package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -1
  195. package/packages/pi-coding-agent/package.json +1 -1
  196. package/packages/pi-coding-agent/src/cli/args.ts +2 -2
  197. package/packages/pi-coding-agent/src/core/agent-session.ts +67 -25
  198. package/packages/pi-coding-agent/src/core/lsp/lsp.md +3 -1
  199. package/packages/pi-coding-agent/src/core/sdk.test.ts +45 -0
  200. package/packages/pi-coding-agent/src/core/sdk.ts +35 -6
  201. package/packages/pi-coding-agent/src/core/session-manager.ts +12 -0
  202. package/packages/pi-coding-agent/src/core/settings-manager.ts +32 -9
  203. package/packages/pi-coding-agent/src/core/skills.ts +4 -1
  204. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -1
  205. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -2
  206. package/packages/pi-coding-agent/src/core/tools/grep.ts +1 -1
  207. package/packages/pi-coding-agent/src/core/tools/index.ts +3 -0
  208. package/packages/pi-coding-agent/src/core/tools/pty.ts +45 -6
  209. package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +1 -1
  210. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +10 -2
  211. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +31 -7
  212. package/packages/pi-coding-agent/src/modes/interactive/components/thinking-selector.ts +1 -2
  213. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +9 -0
  214. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +65 -3
  215. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +11 -7
  216. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +1 -1
  217. package/packages/pi-coding-agent/src/modes/print-mode.ts +6 -0
  218. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +29 -0
  219. package/packages/pi-coding-agent/src/tests/path-display.test.ts +17 -0
  220. package/packages/pi-tui/dist/components/loader.d.ts +5 -2
  221. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  222. package/packages/pi-tui/dist/components/loader.js +33 -3
  223. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  224. package/packages/pi-tui/src/components/loader.ts +31 -3
  225. package/packages/rpc-client/src/index.ts +1 -1
  226. package/packages/rpc-client/src/rpc-client.ts +29 -0
  227. package/packages/rpc-client/src/rpc-types.ts +1 -1
  228. package/pkg/dist/modes/interactive/theme/theme.d.ts +2 -2
  229. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  230. package/pkg/dist/modes/interactive/theme/theme.js +10 -6
  231. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  232. package/pkg/dist/modes/interactive/theme/themes.js +1 -1
  233. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  234. package/pkg/package.json +1 -1
  235. package/src/resources/agents/generic.md +1 -0
  236. package/src/resources/agents/scout.md +8 -1
  237. package/src/resources/agents/worker.md +1 -0
  238. package/src/resources/extensions/ask-user-questions.ts +88 -0
  239. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +6 -16
  240. package/src/resources/extensions/mac-tools/index.ts +19 -34
  241. package/src/resources/extensions/memory/index.ts +22 -2
  242. package/src/resources/extensions/shared/interview-ui.ts +108 -15
  243. package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +61 -0
  244. package/src/resources/extensions/shared/tests/custom-ui-fallbacks.test.ts +46 -0
  245. package/src/resources/extensions/slash-commands/plan.ts +18 -19
  246. package/src/resources/extensions/slash-commands/tools.ts +43 -4
  247. package/src/resources/extensions/subagent/agent-switcher-component.ts +228 -0
  248. package/src/resources/extensions/subagent/agent-switcher-model.ts +160 -0
  249. package/src/resources/extensions/subagent/agents.ts +2 -1
  250. package/src/resources/extensions/subagent/background-job-manager.ts +29 -6
  251. package/src/resources/extensions/subagent/background-runner.ts +8 -0
  252. package/src/resources/extensions/subagent/background-types.ts +4 -0
  253. package/src/resources/extensions/subagent/index.ts +834 -19
  254. package/src/resources/extensions/subagent/launch-helpers.ts +16 -4
@@ -173,9 +173,7 @@ export default function (pi) {
173
173
  description: "List all running macOS applications. Returns an array of { name, bundleId, pid, isActive } " +
174
174
  "for user-facing apps (regular activation policy). Set includeBackground to true to also " +
175
175
  "include accessory/background apps.",
176
- promptGuidelines: [
177
- "Use to discover what apps are running before interacting with them.",
178
- ],
176
+ promptGuidelines: [],
179
177
  parameters: Type.Object({
180
178
  includeBackground: Type.Optional(Type.Boolean({ description: "Include background/accessory apps (default: false)" })),
181
179
  }),
@@ -201,9 +199,6 @@ export default function (pi) {
201
199
  description: "Launch a macOS application by name or bundle ID. " +
202
200
  "Returns { launched, name, bundleId, pid } on success. " +
203
201
  "Provide either 'name' (e.g. 'TextEdit') or 'bundleId' (e.g. 'com.apple.TextEdit').",
204
- promptGuidelines: [
205
- "Use app name for well-known apps; use bundleId when the name is ambiguous.",
206
- ],
207
202
  parameters: Type.Object({
208
203
  name: Type.Optional(Type.String({ description: "Application name (e.g. 'TextEdit', 'Safari')" })),
209
204
  bundleId: Type.Optional(Type.String({ description: "Bundle identifier (e.g. 'com.apple.TextEdit')" })),
@@ -272,9 +267,7 @@ export default function (pi) {
272
267
  description: "Quit a running macOS application. " +
273
268
  "Returns { quit, name } on success. Errors if the app is not running. " +
274
269
  "Provide either 'name' or 'bundleId'.",
275
- promptGuidelines: [
276
- "Use to clean up apps launched during automation — don't leave apps running unnecessarily.",
277
- ],
270
+ promptGuidelines: [],
278
271
  parameters: Type.Object({
279
272
  name: Type.Optional(Type.String({ description: "Application name" })),
280
273
  bundleId: Type.Optional(Type.String({ description: "Bundle identifier" })),
@@ -309,9 +302,7 @@ export default function (pi) {
309
302
  "The windowId can be used with getWindowInfo for detailed inspection or with screenshotWindow for capture. " +
310
303
  "Returns an empty array (not error) if the app is running but has no visible windows. " +
311
304
  "Errors if the app is not running.",
312
- promptGuidelines: [
313
- "Use to get windowId values needed by mac_screenshot.",
314
- ],
305
+ promptGuidelines: [],
315
306
  parameters: Type.Object({
316
307
  app: Type.String({ description: "Application name (e.g. 'TextEdit') or bundle identifier (e.g. 'com.apple.TextEdit')" }),
317
308
  }),
@@ -348,8 +339,7 @@ export default function (pi) {
348
339
  "The 'app' param accepts an app name (e.g. 'Finder') or bundle ID (e.g. 'com.apple.Finder').",
349
340
  promptGuidelines: [
350
341
  "Prefer for targeted element search — use role/title/value criteria to narrow results.",
351
- "Use mode:focused to check the current focus target without search criteria.",
352
- "Use mac_get_tree instead of mode:tree when you just need to understand app structure.",
342
+ "Use mac_get_tree instead of mode:tree for quick structure inspection.",
353
343
  ],
354
344
  parameters: Type.Object({
355
345
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -470,9 +460,7 @@ export default function (pi) {
470
460
  "Each line: `role \"title\" [value]` with 2-space indent per depth level. " +
471
461
  "Omits title/value when nil or empty.",
472
462
  promptGuidelines: [
473
- "Use for understanding app UI structure — start with low limits and increase if needed.",
474
463
  "Prefer mac_find search mode when you know what you're looking for.",
475
- "Check the truncation note to know if the tree was cut short.",
476
464
  ],
477
465
  parameters: Type.Object({
478
466
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -522,8 +510,7 @@ export default function (pi) {
522
510
  "Finds the first element matching the given criteria (role, title, value, identifier) and clicks it. " +
523
511
  "At least one criterion is required. Returns the clicked element's attributes.",
524
512
  promptGuidelines: [
525
- "Verify the click worked by reading the resulting state with mac_find or mac_read.",
526
- "Use mac_find first to discover the right role/title/value criteria before clicking.",
513
+ "Use mac_find first to discover the right criteria before clicking.",
527
514
  ],
528
515
  parameters: Type.Object({
529
516
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -573,8 +560,7 @@ export default function (pi) {
573
560
  "Returns the actual value after setting (read-back verification). " +
574
561
  "At least one criterion is required.",
575
562
  promptGuidelines: [
576
- "Read back the value after typing to verify — the return value includes actual content.",
577
- "Target text fields/areas by role (AXTextArea, AXTextField) for reliability.",
563
+ "Target text fields by role (AXTextArea, AXTextField) for reliability.",
578
564
  ],
579
565
  parameters: Type.Object({
580
566
  app: Type.String({ description: "Application name or bundle identifier" }),
@@ -625,9 +611,7 @@ export default function (pi) {
625
611
  "Returns the screenshot as an image content block for visual analysis, alongside text metadata " +
626
612
  "(dimensions and format). Requires Screen Recording permission — use mac_check_permissions to verify.",
627
613
  promptGuidelines: [
628
- "Use for visual verification when accessibility attributes aren't sufficient.",
629
- "Prefer nominal resolution unless retina detail is needed — retina doubles payload size.",
630
- "Requires Screen Recording permission — run mac_check_permissions first if screenshot fails.",
614
+ "Prefer nominal resolution; retina doubles payload. Run mac_check_permissions if it fails.",
631
615
  ],
632
616
  parameters: Type.Object({
633
617
  windowId: Type.Number({ description: "Window ID from mac_list_windows output" }),
@@ -672,9 +656,7 @@ export default function (pi) {
672
656
  "Finds the first element matching the given criteria and reads the named attribute(s). " +
673
657
  "AXValue subtypes (CGPoint, CGSize, CGRect, CFRange) are automatically unpacked to structured dicts. " +
674
658
  "Use 'attribute' for a single attribute or 'attributes' for multiple. At least one search criterion is required.",
675
- promptGuidelines: [
676
- "Use to verify state after actions — read AXValue to confirm text was typed, AXEnabled to check if a button is active.",
677
- ],
659
+ promptGuidelines: [],
678
660
  parameters: Type.Object({
679
661
  app: Type.String({ description: "Application name or bundle identifier" }),
680
662
  attribute: Type.Optional(Type.String({ description: "Single attribute name to read (e.g. 'AXValue', 'AXPosition', 'AXRole')" })),
@@ -741,8 +723,13 @@ export default function (pi) {
741
723
  });
742
724
  // -----------------------------------------------------------------
743
725
  // System prompt injection — mac-tools usage guidelines
726
+ // Only inject when mac tools are actually active.
744
727
  // -----------------------------------------------------------------
745
728
  pi.on("before_agent_start", async (event) => {
729
+ const activeTools = new Set(pi.getActiveTools());
730
+ const hasMacTools = [...activeTools].some((name) => name.startsWith("mac_"));
731
+ if (!hasMacTools)
732
+ return;
746
733
  const guidelines = `
747
734
 
748
735
  [SYSTEM CONTEXT — Mac Tools]
@@ -751,18 +738,16 @@ export default function (pi) {
751
738
 
752
739
  You have mac-tools for controlling native macOS applications (Finder, TextEdit, Safari, Xcode, etc.) via Accessibility APIs.
753
740
 
754
- **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.
741
+ **Mac-tools vs browser-tools:** Use mac-tools for native macOS apps. Use browser-tools for web pages inside a browser.
755
742
 
756
- **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.
743
+ **Permissions:** If any mac tool returns a permission error, run \`mac_check_permissions\` to diagnose.
757
744
 
758
745
  **Interaction pattern — discover → act → verify:**
759
- 1. **Discover** the UI structure with \`mac_find\` (search for specific elements) or \`mac_get_tree\` (see overall layout)
760
- 2. **Act** with \`mac_click\` (press buttons/menus) or \`mac_type\` (enter text into fields)
761
- 3. **Verify** the result with \`mac_read\` (check attribute values) or \`mac_screenshot\` (visual confirmation)
762
-
763
- **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.
746
+ 1. **Discover** with \`mac_find\` or \`mac_get_tree\`
747
+ 2. **Act** with \`mac_click\` or \`mac_type\`
748
+ 3. **Verify** with \`mac_read\` or \`mac_screenshot\`
764
749
 
765
- **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.`;
750
+ Start with default tree limits (maxDepth:3, maxCount:50). Use \`mac_screenshot\` sparingly — the payload is large.`;
766
751
  return { systemPrompt: event.systemPrompt + guidelines };
767
752
  });
768
753
  }
@@ -63,8 +63,26 @@ function truncateEntrypointContent(raw) {
63
63
  * @param memoryDir Absolute path to the project's memory directory.
64
64
  * @param entrypointContent The (possibly truncated) contents of MEMORY.md.
65
65
  */
66
- function buildMemoryPrompt(memoryDir, entrypointContent) {
66
+ function buildMemoryPrompt(memoryDir, entrypointContent, hasMemories) {
67
67
  const sections = [];
68
+ if (!hasMemories) {
69
+ // Slim prompt when no memories exist — just enough to know the system is there
70
+ // and how to save the first memory. Full instructions are deferred until needed.
71
+ sections.push(`# Memory
72
+
73
+ You have a persistent, file-based memory system at \`${memoryDir}\`.
74
+ This directory already exists — write to it directly with the file write tool.
75
+
76
+ If the user explicitly asks you to remember something, save it immediately. If they ask you to forget, find and remove it.
77
+
78
+ To save a memory:
79
+ 1. Write a markdown file to the memory directory with YAML frontmatter (name, description, type: user|feedback|project|reference)
80
+ 2. Add a one-line pointer to MEMORY.md: \`- [Title](file.md) — one-line hook\`
81
+
82
+ Your MEMORY.md is currently empty.`);
83
+ return sections.join('\n\n');
84
+ }
85
+ // ── Full prompt when memories exist ──
68
86
  // ── Header ──
69
87
  sections.push(`# Memory
70
88
 
@@ -151,7 +169,7 @@ export default function memoryExtension(pi) {
151
169
  const { content } = truncateEntrypointContent(entrypointContent);
152
170
  entrypointContent = content;
153
171
  }
154
- const prompt = buildMemoryPrompt(memoryDir, entrypointContent);
172
+ const prompt = buildMemoryPrompt(memoryDir, entrypointContent, !!entrypointContent.trim());
155
173
  return {
156
174
  systemPrompt: event.systemPrompt + '\n\n' + prompt,
157
175
  };
@@ -29,9 +29,23 @@ import { makeUI, INDENT } from "./ui.js";
29
29
  // ─── Constants ────────────────────────────────────────────────────────────────
30
30
  const OTHER_OPTION_LABEL = "None of the above";
31
31
  const OTHER_OPTION_DESCRIPTION = "Select to type your own answer.";
32
+ function matchesShowWhen(question, answers) {
33
+ if (!question.showWhen)
34
+ return true;
35
+ const controlling = answers[question.showWhen.questionId];
36
+ if (!controlling)
37
+ return false;
38
+ const selected = Array.isArray(controlling.selected)
39
+ ? controlling.selected
40
+ : [controlling.selected];
41
+ return selected.some((value) => question.showWhen?.selectedAnyOf.includes(value));
42
+ }
32
43
  async function runSequentialInterviewFallback(questions, ctx) {
33
44
  const answers = {};
34
45
  for (const q of questions) {
46
+ if (!matchesShowWhen(q, answers)) {
47
+ continue;
48
+ }
35
49
  const options = q.options.map((o) => o.label);
36
50
  if (!q.allowMultiple) {
37
51
  options.push(OTHER_OPTION_LABEL);
@@ -147,7 +161,6 @@ export async function showInterviewRound(questions, opts, ctx) {
147
161
  notes: "",
148
162
  notesVisible: false,
149
163
  }));
150
- const isMultiQuestion = questions.length > 1;
151
164
  let currentIdx = 0;
152
165
  let focusNotes = false;
153
166
  let showingReview = false;
@@ -181,13 +194,65 @@ export async function showInterviewRound(questions, opts, ctx) {
181
194
  function loadStateToEditor() {
182
195
  getEditor().setText(states[currentIdx].notes);
183
196
  }
197
+ function selectedLabelsForIndex(idx) {
198
+ if (isMultiSelect(idx)) {
199
+ return Array.from(states[idx].checkedIndices).sort((a, b) => a - b).map((optionIdx) => questions[idx].options[optionIdx]?.label).filter((v) => !!v);
200
+ }
201
+ const committed = states[idx].committedIndex;
202
+ if (committed === null)
203
+ return [];
204
+ if (committed < questions[idx].options.length)
205
+ return [questions[idx].options[committed]?.label].filter((v) => !!v);
206
+ if (committed === noneOrDoneIdx(idx))
207
+ return [OTHER_OPTION_LABEL];
208
+ return [];
209
+ }
210
+ function visibleQuestionIndices() {
211
+ const visible = [];
212
+ for (let i = 0; i < questions.length; i++) {
213
+ const q = questions[i];
214
+ if (!q.showWhen) {
215
+ visible.push(i);
216
+ continue;
217
+ }
218
+ const controllingIdx = questions.findIndex((candidate) => candidate.id === q.showWhen?.questionId);
219
+ if (controllingIdx < 0 || !visible.includes(controllingIdx))
220
+ continue;
221
+ const selected = selectedLabelsForIndex(controllingIdx);
222
+ if (selected.some((label) => q.showWhen?.selectedAnyOf.includes(label))) {
223
+ visible.push(i);
224
+ }
225
+ }
226
+ return visible;
227
+ }
184
228
  function isQuestionAnswered(idx) {
185
229
  if (isMultiSelect(idx))
186
230
  return states[idx].checkedIndices.size > 0;
187
231
  return states[idx].committedIndex !== null;
188
232
  }
189
233
  function allAnswered() {
190
- return questions.every((_, i) => isQuestionAnswered(i));
234
+ const visible = visibleQuestionIndices();
235
+ return visible.length > 0 && visible.every((i) => isQuestionAnswered(i));
236
+ }
237
+ function clearQuestionState(idx) {
238
+ states[idx].cursorIndex = 0;
239
+ states[idx].committedIndex = null;
240
+ states[idx].checkedIndices.clear();
241
+ states[idx].notes = "";
242
+ states[idx].notesVisible = false;
243
+ }
244
+ function reconcileVisibility() {
245
+ const visible = new Set(visibleQuestionIndices());
246
+ for (let i = 0; i < questions.length; i++) {
247
+ if (!visible.has(i))
248
+ clearQuestionState(i);
249
+ }
250
+ if (!visible.has(currentIdx)) {
251
+ const fallback = visibleQuestionIndices()[0] ?? 0;
252
+ currentIdx = fallback;
253
+ loadStateToEditor();
254
+ focusNotes = false;
255
+ }
191
256
  }
192
257
  function switchQuestion(newIdx) {
193
258
  if (newIdx === currentIdx)
@@ -200,7 +265,10 @@ export async function showInterviewRound(questions, opts, ctx) {
200
265
  }
201
266
  function buildResult() {
202
267
  const answers = {};
268
+ const visible = new Set(visibleQuestionIndices());
203
269
  for (let i = 0; i < questions.length; i++) {
270
+ if (!visible.has(i))
271
+ continue;
204
272
  const q = questions[i];
205
273
  const st = states[i];
206
274
  const notes = st.notes.trim();
@@ -234,6 +302,7 @@ export async function showInterviewRound(questions, opts, ctx) {
234
302
  if (!isMultiSelect(currentIdx)) {
235
303
  states[currentIdx].committedIndex = states[currentIdx].cursorIndex;
236
304
  }
305
+ reconcileVisibility();
237
306
  // Auto-open the notes field when "None of the above" is selected
238
307
  // so the user can immediately provide a free-text explanation
239
308
  // instead of being trapped in a re-asking loop (bug #2715).
@@ -245,10 +314,13 @@ export async function showInterviewRound(questions, opts, ctx) {
245
314
  refresh();
246
315
  return;
247
316
  }
248
- if (isMultiQuestion && currentIdx < questions.length - 1) {
249
- let next = currentIdx + 1;
250
- for (let i = 0; i < questions.length; i++) {
251
- const candidate = (currentIdx + 1 + i) % questions.length;
317
+ const visible = visibleQuestionIndices();
318
+ const currentVisiblePos = visible.indexOf(currentIdx);
319
+ const isMultiQuestion = visible.length > 1;
320
+ if (isMultiQuestion && currentVisiblePos >= 0 && currentVisiblePos < visible.length - 1) {
321
+ let next = visible[currentVisiblePos + 1] ?? visible[0] ?? currentIdx;
322
+ for (let i = 0; i < visible.length; i++) {
323
+ const candidate = visible[(currentVisiblePos + 1 + i) % visible.length] ?? currentIdx;
252
324
  if (!isQuestionAnswered(candidate)) {
253
325
  next = candidate;
254
326
  break;
@@ -306,7 +378,8 @@ export async function showInterviewRound(questions, opts, ctx) {
306
378
  if (showingReview) {
307
379
  if (matchesKey(data, Key.escape) || matchesKey(data, Key.left)) {
308
380
  showingReview = false;
309
- switchQuestion(questions.length - 1);
381
+ const visible = visibleQuestionIndices();
382
+ switchQuestion(visible[visible.length - 1] ?? 0);
310
383
  return;
311
384
  }
312
385
  if (matchesKey(data, Key.enter) || matchesKey(data, Key.right) || matchesKey(data, Key.space)) {
@@ -355,14 +428,19 @@ export async function showInterviewRound(questions, opts, ctx) {
355
428
  return;
356
429
  }
357
430
  // ── Multi-question navigation ────────────────────────────────
431
+ const visible = visibleQuestionIndices();
432
+ const isMultiQuestion = visible.length > 1;
358
433
  if (isMultiQuestion) {
359
- if (matchesKey(data, Key.left)) {
360
- switchQuestion((currentIdx - 1 + questions.length) % questions.length);
361
- return;
362
- }
363
- if (matchesKey(data, Key.right)) {
364
- switchQuestion((currentIdx + 1) % questions.length);
365
- return;
434
+ const visiblePos = visible.indexOf(currentIdx);
435
+ if (visiblePos >= 0) {
436
+ if (matchesKey(data, Key.left)) {
437
+ switchQuestion(visible[(visiblePos - 1 + visible.length) % visible.length] ?? currentIdx);
438
+ return;
439
+ }
440
+ if (matchesKey(data, Key.right)) {
441
+ switchQuestion(visible[(visiblePos + 1) % visible.length] ?? currentIdx);
442
+ return;
443
+ }
366
444
  }
367
445
  }
368
446
  // ── Cursor navigation ────────────────────────────────────────
@@ -435,7 +513,8 @@ export async function showInterviewRound(questions, opts, ctx) {
435
513
  const push = (...rows) => { for (const r of rows)
436
514
  lines.push(...r); };
437
515
  push(ui.bar(), ui.blank(), ui.header(` ${opts.reviewHeadline ?? "Review your answers"}`), ui.blank());
438
- for (let i = 0; i < questions.length; i++) {
516
+ const visible = visibleQuestionIndices();
517
+ for (const i of visible) {
439
518
  const q = questions[i];
440
519
  const st = states[i];
441
520
  push(ui.subtitle(` ${q.question}`));
@@ -501,19 +580,23 @@ export async function showInterviewRound(questions, opts, ctx) {
501
580
  const lines = [];
502
581
  const push = (...rows) => { for (const r of rows)
503
582
  lines.push(...r); };
583
+ reconcileVisibility();
584
+ const visible = visibleQuestionIndices();
585
+ const isMultiQuestion = visible.length > 1;
586
+ const visiblePos = Math.max(visible.indexOf(currentIdx), 0);
504
587
  const q = questions[currentIdx];
505
588
  const st = states[currentIdx];
506
589
  const multiSel = isMultiSelect(currentIdx);
507
590
  push(ui.bar());
508
591
  // ── Progress header ────────────────────────────────────────────
509
592
  if (isMultiQuestion) {
510
- const unanswered = questions.filter((_, i) => !isQuestionAnswered(i)).length;
511
- const answeredSet = new Set(questions.map((_, i) => i).filter(i => isQuestionAnswered(i)));
512
- push(ui.questionTabs(questions.map(q => q.header), currentIdx, answeredSet));
593
+ const unanswered = visible.filter((i) => !isQuestionAnswered(i)).length;
594
+ const answeredSet = new Set(visible.map((i, visibleIndex) => (isQuestionAnswered(i) ? visibleIndex : -1)).filter((i) => i >= 0));
595
+ push(ui.questionTabs(visible.map((i) => questions[i]?.header ?? ""), visiblePos, answeredSet));
513
596
  push(ui.blank());
514
597
  const progressParts = [
515
598
  opts.progress,
516
- `Question ${currentIdx + 1}/${questions.length}`,
599
+ `Question ${visiblePos + 1}/${visible.length}`,
517
600
  unanswered > 0 ? `${unanswered} unanswered` : null,
518
601
  ].filter(Boolean).join(" • ");
519
602
  if (progressParts)
@@ -582,7 +665,7 @@ export async function showInterviewRound(questions, opts, ctx) {
582
665
  }
583
666
  // ── Footer hints ───────────────────────────────────────────────
584
667
  push(ui.blank());
585
- const isLast = !isMultiQuestion || currentIdx === questions.length - 1;
668
+ const isLast = !isMultiQuestion || visiblePos === visible.length - 1;
586
669
  const hints = [];
587
670
  if (focusNotes) {
588
671
  hints.push("enter to confirm");
@@ -395,25 +395,18 @@ function buildNewSessionOptionLabel() {
395
395
  return `${APPROVE_LABEL} — ${APPROVE_NEW_SESSION_LABEL} (${suffix})`;
396
396
  }
397
397
  function buildApprovalActionInstructions() {
398
- return [
399
- "Ask for plan approval now using ask_user_questions.",
400
- `One single-select question with id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\". Ask what to do next with the plan.`,
401
- `Options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}.`,
402
- `Do not include \"${CANCEL_LABEL}\" as an explicit option — if the user wants to cancel they should choose \"None of the above\" and type \"${CANCEL_LABEL}\" in the note.`,
403
- "Do not restate the plan. Just show the question.",
404
- ].join(" ");
405
- }
406
- function buildApprovalModeInstructions() {
407
398
  const autoSwitchEnabled = readAutoSwitchPlanModelSetting();
408
399
  const showNewSessionOption = autoSwitchEnabled;
409
400
  const newSessionLabel = buildNewSessionOptionLabel();
410
- const options = showNewSessionOption
411
- ? `${APPROVE_AUTO_LABEL}, ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}, ${newSessionLabel}`
412
- : `${APPROVE_AUTO_LABEL}, ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}`;
413
401
  return [
414
- "Plan approved. Now ask which execution mode to use via ask_user_questions.",
415
- `One single-select question with id \"${PLAN_APPROVAL_PERMISSION_QUESTION_ID}\".`,
416
- `Options: ${options}.`,
402
+ "Ask for plan approval now via exactly one ask_user_questions tool call.",
403
+ `Question 1 (single-select) id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\": ask what to do next with the plan.`,
404
+ `Question 1 options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}. Put "${APPROVE_LABEL}" first with a "(Recommended)" suffix in the description, not in the label.`,
405
+ `Do not include \"${CANCEL_LABEL}\" as an explicit option — if the user wants to cancel they should choose \"None of the above\" and type \"${CANCEL_LABEL}\" in the note.`,
406
+ `Question 2 (single-select) id \"${PLAN_APPROVAL_PERMISSION_QUESTION_ID}\": ask which execution mode to use.`,
407
+ `Question 2 options: ${APPROVE_AUTO_LABEL} (Recommended), ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}${showNewSessionOption ? `, ${newSessionLabel}` : ""}.`,
408
+ `Set question 2 showWhen.questionId to \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\" and showWhen.selectedAnyOf to [\"${APPROVE_LABEL}\"] so it appears only when the user selects Approve plan.`,
409
+ "Do not restate the plan in a normal assistant response. Just call ask_user_questions.",
417
410
  ].join(" ");
418
411
  }
419
412
  // Keep for external callers that reference the combined form (headless path)
@@ -679,8 +672,16 @@ export default function planCommand(pi) {
679
672
  if (!actionSelection)
680
673
  return;
681
674
  if (actionSelection.includes(APPROVE_LABEL)) {
682
- // Steer the second question — handle in the next tool_result cycle
683
- pi.sendUserMessage(buildApprovalModeInstructions(), { deliverAs: "steer" });
675
+ const executionMode = approvalSelectionToExecutionMode(permissionValues[0]) ?? {
676
+ permissionMode: DEFAULT_APPROVAL_PERMISSION_MODE,
677
+ executeWithSubagent: false,
678
+ };
679
+ state = { ...state, targetPermissionMode: executionMode.permissionMode };
680
+ if (executionMode.executeWithSubagent) {
681
+ const modeLabel = executionMode.permissionMode === "danger-full-access" ? "bypass" : "auto";
682
+ ctx.ui?.notify?.(`Plan approved: subagent(${modeLabel})`, "info");
683
+ }
684
+ await approvePlan(pi, ctx, executionMode.permissionMode, executionMode.executeWithSubagent);
684
685
  return;
685
686
  }
686
687
  if (actionSelection.includes(REVIEW_LABEL)) {
@@ -37,6 +37,30 @@ function getBalancedToolNames(activeToolNames) {
37
37
  "ask_user_questions",
38
38
  ];
39
39
  }
40
+ const STANDARD_TOOLS = [
41
+ // Core
42
+ "read", "bash", "edit", "write", "lsp", "grep", "find", "ls",
43
+ // Background
44
+ "bg_shell",
45
+ // Search
46
+ "web_search", "fetch_page",
47
+ // Docs
48
+ "resolve_library", "get_library_docs",
49
+ // Agent
50
+ "subagent", "await_subagent", "Skill",
51
+ // User interaction
52
+ "ask_user_questions", "secure_env_collect",
53
+ // Browser (essential)
54
+ "browser_navigate", "browser_click", "browser_type", "browser_screenshot",
55
+ "browser_scroll", "browser_key_press", "browser_evaluate",
56
+ "browser_find", "browser_wait_for", "browser_close",
57
+ "browser_assert", "browser_batch",
58
+ // Tool management
59
+ "tool_search", "tool_enable",
60
+ ];
61
+ function getStandardToolNames() {
62
+ return [...STANDARD_TOOLS];
63
+ }
40
64
  function getFullToolNames(pi) {
41
65
  return pi.getAllTools().map((tool) => tool.name).filter((name) => Boolean(name));
42
66
  }
@@ -168,7 +192,8 @@ export default function toolSearchExtension(pi) {
168
192
  currentActive.length > 0 ? currentActive.join(", ") : "(none)",
169
193
  "",
170
194
  "Usage:",
171
- " /tools balanced Switch to the balanced tool profile",
195
+ " /tools balanced Switch to the balanced tool profile (12 tools)",
196
+ " /tools standard Switch to the standard tool profile (~32 tools)",
172
197
  " /tools full Switch to the full tool profile (all available tools)",
173
198
  " /tools on Alias for /tools full",
174
199
  " /tools off Alias for /tools balanced",
@@ -183,7 +208,18 @@ export default function toolSearchExtension(pi) {
183
208
  pi.setActiveTools(nextActive);
184
209
  pi.sendMessage({
185
210
  customType: "tools:mode",
186
- content: `Balanced tool profile active: ${pi.getActiveTools().join(", ")}`,
211
+ content: `Balanced tool profile active (${pi.getActiveTools().length} tools): ${pi.getActiveTools().join(", ")}`,
212
+ display: true,
213
+ });
214
+ return;
215
+ }
216
+ if (input === "standard") {
217
+ settings.setToolProfile("standard");
218
+ const nextActive = getStandardToolNames();
219
+ pi.setActiveTools(nextActive);
220
+ pi.sendMessage({
221
+ customType: "tools:mode",
222
+ content: `Standard tool profile active (${pi.getActiveTools().length} tools): ${pi.getActiveTools().join(", ")}`,
187
223
  display: true,
188
224
  });
189
225
  return;
@@ -194,14 +230,14 @@ export default function toolSearchExtension(pi) {
194
230
  pi.setActiveTools(nextActive);
195
231
  pi.sendMessage({
196
232
  customType: "tools:mode",
197
- content: `Full tool profile active: ${pi.getActiveTools().join(", ")}`,
233
+ content: `Full tool profile active (${pi.getActiveTools().length} tools): ${pi.getActiveTools().join(", ")}`,
198
234
  display: true,
199
235
  });
200
236
  return;
201
237
  }
202
238
  pi.sendMessage({
203
239
  customType: "tools:help",
204
- content: `Unknown /tools subcommand: ${input}\n\nTry /tools, /tools balanced, /tools full, /tools on, or /tools off.`,
240
+ content: `Unknown /tools subcommand: ${input}\n\nTry /tools, /tools balanced, /tools standard, /tools full, /tools on, or /tools off.`,
205
241
  display: true,
206
242
  });
207
243
  },