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.
- package/README.md +22 -16
- package/dist/app-paths.d.ts +4 -0
- package/dist/app-paths.js +4 -0
- package/dist/bedrock-auth.d.ts +4 -0
- package/dist/bedrock-auth.js +4 -0
- package/dist/bundled-extension-paths.d.ts +4 -0
- package/dist/bundled-extension-paths.js +4 -0
- package/dist/cli-theme.d.ts +2 -2
- package/dist/cli-theme.js +13 -14
- package/dist/cli.js +43 -3
- package/dist/codex-rotate-settings.d.ts +4 -0
- package/dist/codex-rotate-settings.js +4 -0
- package/dist/help-text.d.ts +4 -0
- package/dist/help-text.js +4 -0
- package/dist/lsd-brand.d.ts +4 -0
- package/dist/lsd-brand.js +4 -0
- package/dist/onboarding-llm.d.ts +5 -0
- package/dist/onboarding-llm.js +5 -0
- package/dist/project-sessions.d.ts +4 -0
- package/dist/project-sessions.js +4 -0
- package/dist/resources/agents/generic.md +1 -0
- package/dist/resources/agents/scout.md +8 -1
- package/dist/resources/agents/worker.md +1 -0
- package/dist/resources/extensions/ask-user-questions.js +70 -0
- package/dist/resources/extensions/bg-shell/bg-shell-tool.js +6 -16
- package/dist/resources/extensions/browser-tools/tools/codegen.js +5 -5
- package/dist/resources/extensions/browser-tools/tools/navigation.js +107 -178
- package/dist/resources/extensions/browser-tools/tools/network-mock.js +112 -167
- package/dist/resources/extensions/browser-tools/tools/pages.js +182 -234
- package/dist/resources/extensions/browser-tools/tools/refs.js +202 -461
- package/dist/resources/extensions/browser-tools/tools/session.js +176 -323
- package/dist/resources/extensions/browser-tools/tools/state-persistence.js +91 -154
- package/dist/resources/extensions/browser-tools/utils.js +1 -1
- package/dist/resources/extensions/mac-tools/index.js +19 -34
- package/dist/resources/extensions/memory/index.js +20 -2
- package/dist/resources/extensions/shared/interview-ui.js +103 -20
- package/dist/resources/extensions/slash-commands/extension-manifest.json +2 -2
- package/dist/resources/extensions/slash-commands/fast.js +73 -0
- package/dist/resources/extensions/slash-commands/index.js +2 -0
- package/dist/resources/extensions/slash-commands/plan.js +54 -28
- package/dist/resources/extensions/slash-commands/tools.js +40 -4
- package/dist/resources/extensions/subagent/agent-switcher-component.js +208 -0
- package/dist/resources/extensions/subagent/agent-switcher-model.js +107 -0
- package/dist/resources/extensions/subagent/background-job-manager.js +24 -6
- package/dist/resources/extensions/subagent/background-runner.js +4 -0
- package/dist/resources/extensions/subagent/in-process-runner.js +387 -0
- package/dist/resources/extensions/subagent/index.js +715 -370
- package/dist/resources/extensions/subagent/launch-helpers.js +19 -5
- package/dist/resources/extensions/subagent/legacy-runner.js +503 -0
- package/dist/resources/extensions/voice/index.js +96 -36
- package/dist/resources/extensions/voice/push-to-talk.js +26 -0
- package/dist/shared-paths.d.ts +4 -0
- package/dist/shared-paths.js +4 -0
- package/dist/shared-preferences.d.ts +4 -0
- package/dist/shared-preferences.js +4 -0
- package/dist/startup-model-validation.d.ts +1 -1
- package/dist/startup-timings.d.ts +4 -0
- package/dist/startup-timings.js +4 -0
- package/dist/update-check.d.ts +4 -0
- package/dist/update-check.js +4 -0
- package/dist/update-cmd.d.ts +4 -0
- package/dist/update-cmd.js +4 -0
- package/dist/welcome-screen.js +4 -4
- package/dist/wizard.d.ts +4 -0
- package/dist/wizard.js +4 -0
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +28 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +105 -5
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +13 -2
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent.ts +142 -6
- package/packages/pi-agent-core/src/types.ts +12 -3
- package/packages/pi-ai/dist/adaptive/classifier.d.ts +29 -0
- package/packages/pi-ai/dist/adaptive/classifier.d.ts.map +1 -0
- package/packages/pi-ai/dist/adaptive/classifier.js +72 -0
- package/packages/pi-ai/dist/adaptive/classifier.js.map +1 -0
- package/packages/pi-ai/dist/adaptive/classifier.test.d.ts +2 -0
- package/packages/pi-ai/dist/adaptive/classifier.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/adaptive/classifier.test.js +32 -0
- package/packages/pi-ai/dist/adaptive/classifier.test.js.map +1 -0
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +0 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +0 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +0 -4
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js +0 -5
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/google.js +0 -5
- package/packages/pi-ai/dist/providers/google.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +35 -2
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +32 -6
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +127 -16
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +0 -1
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +9 -2
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.js +67 -0
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-responses.js +21 -3
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-shared.d.ts +0 -1
- package/packages/pi-ai/dist/providers/openai-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-shared.js +0 -4
- package/packages/pi-ai/dist/providers/openai-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +2 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +6 -2
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/adaptive/classifier.test.ts +38 -0
- package/packages/pi-ai/src/adaptive/classifier.ts +107 -0
- package/packages/pi-ai/src/index.ts +1 -0
- package/packages/pi-ai/src/providers/amazon-bedrock.ts +0 -2
- package/packages/pi-ai/src/providers/anthropic-shared.ts +0 -2
- package/packages/pi-ai/src/providers/azure-openai-responses.ts +1 -1
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +0 -4
- package/packages/pi-ai/src/providers/google-vertex.ts +0 -5
- package/packages/pi-ai/src/providers/google.ts +0 -5
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +143 -20
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +48 -7
- package/packages/pi-ai/src/providers/openai-completions.ts +1 -2
- package/packages/pi-ai/src/providers/openai-responses.fast-mode.test.ts +73 -0
- package/packages/pi-ai/src/providers/openai-responses.ts +27 -4
- package/packages/pi-ai/src/providers/openai-shared.ts +0 -3
- package/packages/pi-ai/src/providers/simple-options.ts +2 -1
- package/packages/pi-ai/src/types.ts +6 -2
- package/packages/pi-coding-agent/dist/cli/args.js +2 -2
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +7 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +53 -20
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp.md +3 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +36 -8
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.js +37 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +4 -0
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +18 -7
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.js +35 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js +32 -2
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +4 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +2 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +12 -3
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-priority.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.js +18 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.js +27 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/grep.js +1 -1
- package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +2 -0
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +10 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.js +29 -3
- package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.d.ts +45 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.js +314 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.js +122 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +19 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +11 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +49 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js +1 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +18 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +49 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +197 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +106 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +7 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +88 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +41 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -6
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/print-mode.js +6 -0
- package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +20 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/path-display.test.js +15 -0
- package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +2 -2
- package/packages/pi-coding-agent/src/core/agent-session.ts +58 -21
- package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
- package/packages/pi-coding-agent/src/core/lsp/lsp.md +3 -1
- package/packages/pi-coding-agent/src/core/sdk.test.ts +45 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +39 -8
- package/packages/pi-coding-agent/src/core/session-manager.ts +12 -0
- package/packages/pi-coding-agent/src/core/settings-manager.fast-mode.test.ts +46 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +50 -9
- package/packages/pi-coding-agent/src/core/skills.ts +4 -1
- package/packages/pi-coding-agent/src/core/slash-commands.ts +2 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +14 -3
- package/packages/pi-coding-agent/src/core/tool-priority.test.ts +30 -0
- package/packages/pi-coding-agent/src/core/tool-priority.ts +17 -0
- package/packages/pi-coding-agent/src/core/tools/grep.ts +1 -1
- package/packages/pi-coding-agent/src/core/tools/index.ts +3 -0
- package/packages/pi-coding-agent/src/core/tools/pty.ts +45 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +31 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/btw-overlay.test.ts +172 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/btw-overlay.ts +402 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +18 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +63 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/thinking-selector.ts +1 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1154 -1136
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +64 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +228 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +494 -389
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +7 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +103 -3
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +60 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +11 -7
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +1 -1
- package/packages/pi-coding-agent/src/modes/print-mode.ts +6 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +29 -0
- package/packages/pi-coding-agent/src/tests/path-display.test.ts +17 -0
- package/packages/pi-tui/dist/components/loader.d.ts +5 -2
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +33 -3
- package/packages/pi-tui/dist/components/loader.js.map +1 -1
- package/packages/pi-tui/src/components/loader.ts +31 -3
- package/packages/rpc-client/src/index.ts +1 -1
- package/packages/rpc-client/src/rpc-client.ts +29 -0
- package/packages/rpc-client/src/rpc-types.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +2 -2
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +10 -6
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/agents/generic.md +1 -0
- package/src/resources/agents/scout.md +8 -1
- package/src/resources/agents/worker.md +1 -0
- package/src/resources/extensions/ask-user-questions.ts +88 -0
- package/src/resources/extensions/bg-shell/bg-shell-tool.ts +6 -16
- package/src/resources/extensions/browser-tools/tools/codegen.ts +5 -5
- package/src/resources/extensions/browser-tools/tools/navigation.ts +118 -196
- package/src/resources/extensions/browser-tools/tools/network-mock.ts +114 -205
- package/src/resources/extensions/browser-tools/tools/pages.ts +183 -237
- package/src/resources/extensions/browser-tools/tools/refs.ts +193 -507
- package/src/resources/extensions/browser-tools/tools/session.ts +182 -321
- package/src/resources/extensions/browser-tools/tools/state-persistence.ts +94 -172
- package/src/resources/extensions/browser-tools/utils.ts +1 -1
- package/src/resources/extensions/mac-tools/index.ts +19 -34
- package/src/resources/extensions/memory/index.ts +22 -2
- package/src/resources/extensions/shared/interview-ui.ts +108 -15
- package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +61 -0
- package/src/resources/extensions/shared/tests/custom-ui-fallbacks.test.ts +46 -0
- package/src/resources/extensions/slash-commands/extension-manifest.json +2 -2
- package/src/resources/extensions/slash-commands/fast.ts +89 -0
- package/src/resources/extensions/slash-commands/index.ts +2 -0
- package/src/resources/extensions/slash-commands/plan.ts +59 -30
- package/src/resources/extensions/slash-commands/tools.ts +43 -4
- package/src/resources/extensions/subagent/agent-switcher-component.ts +228 -0
- package/src/resources/extensions/subagent/agent-switcher-model.ts +160 -0
- package/src/resources/extensions/subagent/background-job-manager.ts +57 -6
- package/src/resources/extensions/subagent/background-runner.ts +8 -0
- package/src/resources/extensions/subagent/background-types.ts +4 -0
- package/src/resources/extensions/subagent/in-process-runner.ts +534 -0
- package/src/resources/extensions/subagent/index.ts +998 -493
- package/src/resources/extensions/subagent/launch-helpers.ts +15 -4
- package/src/resources/extensions/subagent/legacy-runner.ts +607 -0
- package/src/resources/extensions/voice/index.ts +308 -238
- package/src/resources/extensions/voice/push-to-talk.ts +42 -0
- package/src/resources/extensions/voice/tests/push-to-talk.test.ts +109 -0
|
@@ -43,6 +43,11 @@ export interface QuestionOption {
|
|
|
43
43
|
description: string;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
export interface QuestionShowWhen {
|
|
47
|
+
questionId: string;
|
|
48
|
+
selectedAnyOf: string[];
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
export interface Question {
|
|
47
52
|
id: string;
|
|
48
53
|
header: string;
|
|
@@ -50,6 +55,8 @@ export interface Question {
|
|
|
50
55
|
options: QuestionOption[];
|
|
51
56
|
/** If true, user can toggle multiple options with SPACE, confirm with ENTER */
|
|
52
57
|
allowMultiple?: boolean;
|
|
58
|
+
/** Show this question only when a prior question matches one of selectedAnyOf labels */
|
|
59
|
+
showWhen?: QuestionShowWhen;
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
export interface RoundResult {
|
|
@@ -107,6 +114,19 @@ export interface WrapUpOptions {
|
|
|
107
114
|
const OTHER_OPTION_LABEL = "None of the above";
|
|
108
115
|
const OTHER_OPTION_DESCRIPTION = "Select to type your own answer.";
|
|
109
116
|
|
|
117
|
+
function matchesShowWhen(
|
|
118
|
+
question: Question,
|
|
119
|
+
answers: Record<string, { selected: string | string[]; notes: string }>,
|
|
120
|
+
): boolean {
|
|
121
|
+
if (!question.showWhen) return true;
|
|
122
|
+
const controlling = answers[question.showWhen.questionId];
|
|
123
|
+
if (!controlling) return false;
|
|
124
|
+
const selected = Array.isArray(controlling.selected)
|
|
125
|
+
? controlling.selected
|
|
126
|
+
: [controlling.selected];
|
|
127
|
+
return selected.some((value) => question.showWhen?.selectedAnyOf.includes(value));
|
|
128
|
+
}
|
|
129
|
+
|
|
110
130
|
async function runSequentialInterviewFallback(
|
|
111
131
|
questions: Question[],
|
|
112
132
|
ctx: ExtensionCommandContext,
|
|
@@ -114,6 +134,9 @@ async function runSequentialInterviewFallback(
|
|
|
114
134
|
const answers: Record<string, { selected: string | string[]; notes: string }> = {};
|
|
115
135
|
|
|
116
136
|
for (const q of questions) {
|
|
137
|
+
if (!matchesShowWhen(q, answers)) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
117
140
|
const options = q.options.map((o) => o.label);
|
|
118
141
|
if (!q.allowMultiple) {
|
|
119
142
|
options.push(OTHER_OPTION_LABEL);
|
|
@@ -252,7 +275,6 @@ export async function showInterviewRound(
|
|
|
252
275
|
notesVisible: false,
|
|
253
276
|
}));
|
|
254
277
|
|
|
255
|
-
const isMultiQuestion = questions.length > 1;
|
|
256
278
|
let currentIdx = 0;
|
|
257
279
|
let focusNotes = false;
|
|
258
280
|
let showingReview = false;
|
|
@@ -295,13 +317,64 @@ export async function showInterviewRound(
|
|
|
295
317
|
getEditor().setText(states[currentIdx].notes);
|
|
296
318
|
}
|
|
297
319
|
|
|
320
|
+
function selectedLabelsForIndex(idx: number): string[] {
|
|
321
|
+
if (isMultiSelect(idx)) {
|
|
322
|
+
return Array.from(states[idx].checkedIndices).sort((a, b) => a - b).map((optionIdx) => questions[idx].options[optionIdx]?.label).filter((v): v is string => !!v);
|
|
323
|
+
}
|
|
324
|
+
const committed = states[idx].committedIndex;
|
|
325
|
+
if (committed === null) return [];
|
|
326
|
+
if (committed < questions[idx].options.length) return [questions[idx].options[committed]?.label].filter((v): v is string => !!v);
|
|
327
|
+
if (committed === noneOrDoneIdx(idx)) return [OTHER_OPTION_LABEL];
|
|
328
|
+
return [];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function visibleQuestionIndices(): number[] {
|
|
332
|
+
const visible: number[] = [];
|
|
333
|
+
for (let i = 0; i < questions.length; i++) {
|
|
334
|
+
const q = questions[i];
|
|
335
|
+
if (!q.showWhen) {
|
|
336
|
+
visible.push(i);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const controllingIdx = questions.findIndex((candidate) => candidate.id === q.showWhen?.questionId);
|
|
340
|
+
if (controllingIdx < 0 || !visible.includes(controllingIdx)) continue;
|
|
341
|
+
const selected = selectedLabelsForIndex(controllingIdx);
|
|
342
|
+
if (selected.some((label) => q.showWhen?.selectedAnyOf.includes(label))) {
|
|
343
|
+
visible.push(i);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return visible;
|
|
347
|
+
}
|
|
348
|
+
|
|
298
349
|
function isQuestionAnswered(idx: number): boolean {
|
|
299
350
|
if (isMultiSelect(idx)) return states[idx].checkedIndices.size > 0;
|
|
300
351
|
return states[idx].committedIndex !== null;
|
|
301
352
|
}
|
|
302
353
|
|
|
303
354
|
function allAnswered(): boolean {
|
|
304
|
-
|
|
355
|
+
const visible = visibleQuestionIndices();
|
|
356
|
+
return visible.length > 0 && visible.every((i) => isQuestionAnswered(i));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function clearQuestionState(idx: number) {
|
|
360
|
+
states[idx].cursorIndex = 0;
|
|
361
|
+
states[idx].committedIndex = null;
|
|
362
|
+
states[idx].checkedIndices.clear();
|
|
363
|
+
states[idx].notes = "";
|
|
364
|
+
states[idx].notesVisible = false;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function reconcileVisibility() {
|
|
368
|
+
const visible = new Set(visibleQuestionIndices());
|
|
369
|
+
for (let i = 0; i < questions.length; i++) {
|
|
370
|
+
if (!visible.has(i)) clearQuestionState(i);
|
|
371
|
+
}
|
|
372
|
+
if (!visible.has(currentIdx)) {
|
|
373
|
+
const fallback = visibleQuestionIndices()[0] ?? 0;
|
|
374
|
+
currentIdx = fallback;
|
|
375
|
+
loadStateToEditor();
|
|
376
|
+
focusNotes = false;
|
|
377
|
+
}
|
|
305
378
|
}
|
|
306
379
|
|
|
307
380
|
function switchQuestion(newIdx: number) {
|
|
@@ -315,7 +388,9 @@ export async function showInterviewRound(
|
|
|
315
388
|
|
|
316
389
|
function buildResult(): RoundResult {
|
|
317
390
|
const answers: Record<string, { selected: string | string[]; notes: string }> = {};
|
|
391
|
+
const visible = new Set(visibleQuestionIndices());
|
|
318
392
|
for (let i = 0; i < questions.length; i++) {
|
|
393
|
+
if (!visible.has(i)) continue;
|
|
319
394
|
const q = questions[i];
|
|
320
395
|
const st = states[i];
|
|
321
396
|
const notes = st.notes.trim();
|
|
@@ -348,6 +423,8 @@ export async function showInterviewRound(
|
|
|
348
423
|
states[currentIdx].committedIndex = states[currentIdx].cursorIndex;
|
|
349
424
|
}
|
|
350
425
|
|
|
426
|
+
reconcileVisibility();
|
|
427
|
+
|
|
351
428
|
// Auto-open the notes field when "None of the above" is selected
|
|
352
429
|
// so the user can immediately provide a free-text explanation
|
|
353
430
|
// instead of being trapped in a re-asking loop (bug #2715).
|
|
@@ -360,10 +437,14 @@ export async function showInterviewRound(
|
|
|
360
437
|
return;
|
|
361
438
|
}
|
|
362
439
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
440
|
+
const visible = visibleQuestionIndices();
|
|
441
|
+
const currentVisiblePos = visible.indexOf(currentIdx);
|
|
442
|
+
const isMultiQuestion = visible.length > 1;
|
|
443
|
+
|
|
444
|
+
if (isMultiQuestion && currentVisiblePos >= 0 && currentVisiblePos < visible.length - 1) {
|
|
445
|
+
let next = visible[currentVisiblePos + 1] ?? visible[0] ?? currentIdx;
|
|
446
|
+
for (let i = 0; i < visible.length; i++) {
|
|
447
|
+
const candidate = visible[(currentVisiblePos + 1 + i) % visible.length] ?? currentIdx;
|
|
367
448
|
if (!isQuestionAnswered(candidate)) { next = candidate; break; }
|
|
368
449
|
}
|
|
369
450
|
switchQuestion(next);
|
|
@@ -396,7 +477,8 @@ export async function showInterviewRound(
|
|
|
396
477
|
if (showingReview) {
|
|
397
478
|
if (matchesKey(data, Key.escape) || matchesKey(data, Key.left)) {
|
|
398
479
|
showingReview = false;
|
|
399
|
-
|
|
480
|
+
const visible = visibleQuestionIndices();
|
|
481
|
+
switchQuestion(visible[visible.length - 1] ?? 0);
|
|
400
482
|
return;
|
|
401
483
|
}
|
|
402
484
|
if (matchesKey(data, Key.enter) || matchesKey(data, Key.right) || matchesKey(data, Key.space)) {
|
|
@@ -447,9 +529,14 @@ export async function showInterviewRound(
|
|
|
447
529
|
}
|
|
448
530
|
|
|
449
531
|
// ── Multi-question navigation ────────────────────────────────
|
|
532
|
+
const visible = visibleQuestionIndices();
|
|
533
|
+
const isMultiQuestion = visible.length > 1;
|
|
450
534
|
if (isMultiQuestion) {
|
|
451
|
-
|
|
452
|
-
if (
|
|
535
|
+
const visiblePos = visible.indexOf(currentIdx);
|
|
536
|
+
if (visiblePos >= 0) {
|
|
537
|
+
if (matchesKey(data, Key.left)) { switchQuestion(visible[(visiblePos - 1 + visible.length) % visible.length] ?? currentIdx); return; }
|
|
538
|
+
if (matchesKey(data, Key.right)) { switchQuestion(visible[(visiblePos + 1) % visible.length] ?? currentIdx); return; }
|
|
539
|
+
}
|
|
453
540
|
}
|
|
454
541
|
|
|
455
542
|
// ── Cursor navigation ────────────────────────────────────────
|
|
@@ -488,7 +575,8 @@ export async function showInterviewRound(
|
|
|
488
575
|
|
|
489
576
|
push(ui.bar(), ui.blank(), ui.header(` ${opts.reviewHeadline ?? "Review your answers"}`), ui.blank());
|
|
490
577
|
|
|
491
|
-
|
|
578
|
+
const visible = visibleQuestionIndices();
|
|
579
|
+
for (const i of visible) {
|
|
492
580
|
const q = questions[i];
|
|
493
581
|
const st = states[i];
|
|
494
582
|
|
|
@@ -571,6 +659,11 @@ export async function showInterviewRound(
|
|
|
571
659
|
const lines: string[] = [];
|
|
572
660
|
const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
|
|
573
661
|
|
|
662
|
+
reconcileVisibility();
|
|
663
|
+
const visible = visibleQuestionIndices();
|
|
664
|
+
const isMultiQuestion = visible.length > 1;
|
|
665
|
+
const visiblePos = Math.max(visible.indexOf(currentIdx), 0);
|
|
666
|
+
|
|
574
667
|
const q = questions[currentIdx];
|
|
575
668
|
const st = states[currentIdx];
|
|
576
669
|
const multiSel = isMultiSelect(currentIdx);
|
|
@@ -579,13 +672,13 @@ export async function showInterviewRound(
|
|
|
579
672
|
|
|
580
673
|
// ── Progress header ────────────────────────────────────────────
|
|
581
674
|
if (isMultiQuestion) {
|
|
582
|
-
const unanswered =
|
|
583
|
-
const answeredSet = new Set(
|
|
584
|
-
push(ui.questionTabs(
|
|
675
|
+
const unanswered = visible.filter((i) => !isQuestionAnswered(i)).length;
|
|
676
|
+
const answeredSet = new Set(visible.map((i, visibleIndex) => (isQuestionAnswered(i) ? visibleIndex : -1)).filter((i) => i >= 0));
|
|
677
|
+
push(ui.questionTabs(visible.map((i) => questions[i]?.header ?? ""), visiblePos, answeredSet));
|
|
585
678
|
push(ui.blank());
|
|
586
679
|
const progressParts = [
|
|
587
680
|
opts.progress,
|
|
588
|
-
`Question ${
|
|
681
|
+
`Question ${visiblePos + 1}/${visible.length}`,
|
|
589
682
|
unanswered > 0 ? `${unanswered} unanswered` : null,
|
|
590
683
|
].filter(Boolean).join(" • ");
|
|
591
684
|
if (progressParts) push(ui.meta(` ${progressParts}`));
|
|
@@ -647,7 +740,7 @@ export async function showInterviewRound(
|
|
|
647
740
|
|
|
648
741
|
// ── Footer hints ───────────────────────────────────────────────
|
|
649
742
|
push(ui.blank());
|
|
650
|
-
const isLast = !isMultiQuestion ||
|
|
743
|
+
const isLast = !isMultiQuestion || visiblePos === visible.length - 1;
|
|
651
744
|
const hints: string[] = [];
|
|
652
745
|
if (focusNotes) {
|
|
653
746
|
hints.push("enter to confirm");
|
|
@@ -131,6 +131,67 @@ describe("ask-user-questions RPC fallback free-text", () => {
|
|
|
131
131
|
assert.deepStrictEqual(parsed.answers.q1.answers, ["Option A"]);
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
it("skips conditional follow-up when controlling answer does not match", async () => {
|
|
135
|
+
const tool = captureTool();
|
|
136
|
+
const { ctx, selectCalls } = makeMockCtx({
|
|
137
|
+
selectReturns: ["Review plan"],
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const result = await tool.execute(
|
|
141
|
+
"call-conditional-skip",
|
|
142
|
+
{
|
|
143
|
+
questions: [
|
|
144
|
+
makeQuestion("plan_mode_approval_action", ["Approve plan", "Review plan"]),
|
|
145
|
+
{
|
|
146
|
+
...makeQuestion("plan_mode_approval_permission", ["Auto mode", "Bypass mode"]),
|
|
147
|
+
showWhen: {
|
|
148
|
+
questionId: "plan_mode_approval_action",
|
|
149
|
+
selectedAnyOf: ["Approve plan"],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
undefined,
|
|
155
|
+
undefined,
|
|
156
|
+
ctx,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
assert.equal(selectCalls.length, 1);
|
|
160
|
+
const parsed = JSON.parse(result.content[0]?.text ?? "{}");
|
|
161
|
+
assert.ok(parsed.answers.plan_mode_approval_action);
|
|
162
|
+
assert.equal(parsed.answers.plan_mode_approval_permission, undefined);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("asks conditional follow-up when controlling answer matches", async () => {
|
|
166
|
+
const tool = captureTool();
|
|
167
|
+
const { ctx, selectCalls } = makeMockCtx({
|
|
168
|
+
selectReturns: ["Approve plan", "Auto mode"],
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const result = await tool.execute(
|
|
172
|
+
"call-conditional-show",
|
|
173
|
+
{
|
|
174
|
+
questions: [
|
|
175
|
+
makeQuestion("plan_mode_approval_action", ["Approve plan", "Review plan"]),
|
|
176
|
+
{
|
|
177
|
+
...makeQuestion("plan_mode_approval_permission", ["Auto mode", "Bypass mode"]),
|
|
178
|
+
showWhen: {
|
|
179
|
+
questionId: "plan_mode_approval_action",
|
|
180
|
+
selectedAnyOf: ["Approve plan"],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
undefined,
|
|
186
|
+
undefined,
|
|
187
|
+
ctx,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
assert.equal(selectCalls.length, 2);
|
|
191
|
+
const parsed = JSON.parse(result.content[0]?.text ?? "{}");
|
|
192
|
+
assert.deepStrictEqual(parsed.answers.plan_mode_approval_permission.answers, ["Auto mode"]);
|
|
193
|
+
});
|
|
194
|
+
|
|
134
195
|
it("handles cancelled free-text input gracefully", async () => {
|
|
135
196
|
const tool = captureTool();
|
|
136
197
|
const { ctx, inputCalls } = makeMockCtx({
|
|
@@ -73,6 +73,52 @@ describe("custom UI fallback paths", () => {
|
|
|
73
73
|
assert.equal(result.answers.q1?.notes, "My custom answer");
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it("showInterviewRound skips conditional question when condition is not met", async () => {
|
|
77
|
+
const selectCalls: Array<{ title: string; options: string[] }> = [];
|
|
78
|
+
const ctx = {
|
|
79
|
+
hasUI: true,
|
|
80
|
+
ui: {
|
|
81
|
+
custom: async () => undefined,
|
|
82
|
+
select: async (title: string, options: string[]) => {
|
|
83
|
+
selectCalls.push({ title, options });
|
|
84
|
+
if (title.startsWith("Q1:")) return "Review";
|
|
85
|
+
return options[0];
|
|
86
|
+
},
|
|
87
|
+
input: async () => "",
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const result = await showInterviewRound(
|
|
92
|
+
[
|
|
93
|
+
{
|
|
94
|
+
id: "q1",
|
|
95
|
+
header: "Q1",
|
|
96
|
+
question: "Approve?",
|
|
97
|
+
options: [
|
|
98
|
+
{ label: "Approve", description: "approve" },
|
|
99
|
+
{ label: "Review", description: "review" },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: "q2",
|
|
104
|
+
header: "Q2",
|
|
105
|
+
question: "Mode?",
|
|
106
|
+
options: [
|
|
107
|
+
{ label: "Auto", description: "auto" },
|
|
108
|
+
{ label: "Bypass", description: "bypass" },
|
|
109
|
+
],
|
|
110
|
+
showWhen: { questionId: "q1", selectedAnyOf: ["Approve"] },
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
{},
|
|
114
|
+
ctx as any,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
assert.equal(selectCalls.length, 1, "conditional question should be skipped in fallback mode");
|
|
118
|
+
assert.equal(result.answers.q1?.selected, "Review");
|
|
119
|
+
assert.equal(result.answers.q2, undefined);
|
|
120
|
+
});
|
|
121
|
+
|
|
76
122
|
it("collectOneSecret respects null from secure UI and does not fall back to plaintext input", async () => {
|
|
77
123
|
let inputCalls = 0;
|
|
78
124
|
const notifications: Array<{ message: string; type?: string }> = [];
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"id": "slash-commands",
|
|
3
3
|
"name": "Slash Commands",
|
|
4
4
|
"version": "1.0.0",
|
|
5
|
-
"description": "Bundled slash commands for context inspection, planning, and lazy tool search",
|
|
5
|
+
"description": "Bundled slash commands for context inspection, planning, fast mode, and lazy tool search",
|
|
6
6
|
"tier": "bundled",
|
|
7
7
|
"requires": { "platform": ">=2.29.0" },
|
|
8
8
|
"provides": {
|
|
9
|
-
"commands": ["audit", "clear", "context", "plan", "execute", "cancel-plan", "tools"],
|
|
9
|
+
"commands": ["audit", "clear", "context", "fast", "plan", "execute", "cancel-plan", "tools"],
|
|
10
10
|
"tools": ["tool_search", "tool_enable"],
|
|
11
11
|
"flags": ["plan"]
|
|
12
12
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getAgentDir, SettingsManager, type ExtensionAPI, type ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
type FastCommandAction = "toggle" | "on" | "off" | "status" | "invalid";
|
|
4
|
+
|
|
5
|
+
function parseFastCommandAction(args: string): FastCommandAction {
|
|
6
|
+
const normalized = args.trim().toLowerCase();
|
|
7
|
+
if (!normalized) return "toggle";
|
|
8
|
+
if (normalized === "on") return "on";
|
|
9
|
+
if (normalized === "off") return "off";
|
|
10
|
+
if (normalized === "status") return "status";
|
|
11
|
+
return "invalid";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function supportsFastMode(model: ExtensionCommandContext["model"]): boolean {
|
|
15
|
+
if (!model) return false;
|
|
16
|
+
if (model.api === "openai-codex-responses") return true;
|
|
17
|
+
if (model.api !== "openai-responses") return false;
|
|
18
|
+
if (model.provider !== "openai") return false;
|
|
19
|
+
return model.capabilities?.supportsServiceTier === true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getModelLabel(model: ExtensionCommandContext["model"]): string {
|
|
23
|
+
if (!model) return "no active model";
|
|
24
|
+
return `${model.provider}/${model.id}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getSettingsManager(): SettingsManager {
|
|
28
|
+
return SettingsManager.create(process.cwd(), getAgentDir());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const __testing = {
|
|
32
|
+
parseFastCommandAction,
|
|
33
|
+
supportsFastMode,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default function fastCommand(pi: ExtensionAPI) {
|
|
37
|
+
pi.registerCommand("fast", {
|
|
38
|
+
description: "Toggle fast mode for OpenAI/Codex models (service_tier=priority)",
|
|
39
|
+
getArgumentCompletions(prefix: string) {
|
|
40
|
+
const options = [
|
|
41
|
+
{ value: "on", label: "on", description: "Enable fast mode" },
|
|
42
|
+
{ value: "off", label: "off", description: "Disable fast mode" },
|
|
43
|
+
{ value: "status", label: "status", description: "Show current fast-mode status" },
|
|
44
|
+
];
|
|
45
|
+
const query = prefix.trim().toLowerCase();
|
|
46
|
+
return options.filter((item) => item.value.startsWith(query));
|
|
47
|
+
},
|
|
48
|
+
async handler(args: string, ctx: ExtensionCommandContext) {
|
|
49
|
+
const settings = getSettingsManager() as SettingsManager & {
|
|
50
|
+
getFastMode: () => boolean;
|
|
51
|
+
setFastMode: (enabled: boolean) => void;
|
|
52
|
+
};
|
|
53
|
+
const current = settings.getFastMode();
|
|
54
|
+
const action = parseFastCommandAction(args);
|
|
55
|
+
const model = ctx.model;
|
|
56
|
+
const supported = supportsFastMode(model);
|
|
57
|
+
const modelLabel = getModelLabel(model);
|
|
58
|
+
|
|
59
|
+
if (action === "invalid") {
|
|
60
|
+
ctx.ui.notify("Usage: /fast [on|off|status]", "warning");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (action === "status") {
|
|
65
|
+
ctx.ui.notify(
|
|
66
|
+
`Fast mode: ${current ? "ON" : "OFF"} · model ${modelLabel} is ${supported ? "supported" : "unsupported"}`,
|
|
67
|
+
"info",
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const next = action === "toggle" ? !current : action === "on";
|
|
73
|
+
settings.setFastMode(next);
|
|
74
|
+
|
|
75
|
+
if (!supported) {
|
|
76
|
+
ctx.ui.notify(
|
|
77
|
+
`Fast mode: ${next ? "ON" : "OFF"} (saved). Current model ${modelLabel} does not support fast mode.`,
|
|
78
|
+
"warning",
|
|
79
|
+
);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ctx.ui.notify(
|
|
84
|
+
`Fast mode: ${next ? "ON" : "OFF"} (saved). ${next ? "Requests will include service_tier=priority." : "Requests will omit service_tier."}`,
|
|
85
|
+
"info",
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
|
2
2
|
import auditCommand from "./audit.js";
|
|
3
3
|
import clearCommand from "./clear.js";
|
|
4
4
|
import contextCommand from "./context.js";
|
|
5
|
+
import fastCommand from "./fast.js";
|
|
5
6
|
import initCommand from "./init.js";
|
|
6
7
|
import planCommand from "./plan.js";
|
|
7
8
|
import toolSearchExtension from "./tools.js";
|
|
@@ -10,6 +11,7 @@ export default function slashCommands(pi: ExtensionAPI) {
|
|
|
10
11
|
auditCommand(pi);
|
|
11
12
|
clearCommand(pi);
|
|
12
13
|
contextCommand(pi);
|
|
14
|
+
fastCommand(pi);
|
|
13
15
|
initCommand(pi);
|
|
14
16
|
planCommand(pi);
|
|
15
17
|
toolSearchExtension(pi);
|
|
@@ -38,9 +38,8 @@ const BLOCKED_TOOLS = new Set([
|
|
|
38
38
|
"async_bash",
|
|
39
39
|
"bg_shell",
|
|
40
40
|
"browser_navigate",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"browser_reload",
|
|
41
|
+
"browser_pages",
|
|
42
|
+
"browser_frames",
|
|
44
43
|
"browser_click",
|
|
45
44
|
"browser_drag",
|
|
46
45
|
"browser_type",
|
|
@@ -51,18 +50,13 @@ const BLOCKED_TOOLS = new Set([
|
|
|
51
50
|
"browser_select_option",
|
|
52
51
|
"browser_set_checked",
|
|
53
52
|
"browser_set_viewport",
|
|
54
|
-
"
|
|
55
|
-
"browser_hover_ref",
|
|
56
|
-
"browser_fill_ref",
|
|
53
|
+
"browser_ref",
|
|
57
54
|
"browser_act",
|
|
58
55
|
"browser_batch",
|
|
59
56
|
"browser_fill_form",
|
|
60
|
-
"
|
|
61
|
-
"browser_block_urls",
|
|
62
|
-
"browser_clear_routes",
|
|
57
|
+
"browser_network",
|
|
63
58
|
"browser_emulate_device",
|
|
64
|
-
"
|
|
65
|
-
"browser_restore_state",
|
|
59
|
+
"browser_state",
|
|
66
60
|
"browser_generate_test",
|
|
67
61
|
"browser_verify",
|
|
68
62
|
"write",
|
|
@@ -80,6 +74,7 @@ const REVISE_LABEL = "Revise plan";
|
|
|
80
74
|
const CANCEL_LABEL = "Cancel";
|
|
81
75
|
const DEFAULT_PLAN_REVIEW_AGENT = "generic";
|
|
82
76
|
const DEFAULT_PLAN_CODING_AGENT = "worker";
|
|
77
|
+
const MIN_PLAN_CONFIDENCE = 8;
|
|
83
78
|
|
|
84
79
|
type PlanApprovalStatus = "pending" | "approved" | "revising" | "cancelled";
|
|
85
80
|
type RestorablePermissionMode = Exclude<PermissionMode, "plan">;
|
|
@@ -455,6 +450,9 @@ function buildPlanModeSystemPrompt(): string {
|
|
|
455
450
|
"You are currently in plan mode.",
|
|
456
451
|
"Investigate, clarify scope, and produce a persisted execution plan before making source changes.",
|
|
457
452
|
"If requirements are ambiguous or constraints are missing, ask concise clarifying questions before drafting or saving a plan.",
|
|
453
|
+
`Before writing or updating a plan artifact, make sure your confidence is at least ${MIN_PLAN_CONFIDENCE}/10. If confidence is lower, investigate more or ask clarifying questions first.`,
|
|
454
|
+
"Include an explicit confidence line in every saved plan, for example: \"Confidence: 8/10\" or higher.",
|
|
455
|
+
"When adjusting an existing saved plan, prefer the edit tool for targeted changes. Rewrite the whole file only when the structure changes substantially or an exact edit is impractical.",
|
|
458
456
|
"Do not modify source files or run side-effect commands while plan mode is active.",
|
|
459
457
|
"Persist plan artifacts under .lsd/plan/.",
|
|
460
458
|
];
|
|
@@ -483,28 +481,19 @@ function buildNewSessionOptionLabel(): string {
|
|
|
483
481
|
}
|
|
484
482
|
|
|
485
483
|
function buildApprovalActionInstructions(): string {
|
|
486
|
-
return [
|
|
487
|
-
"Ask for plan approval now using ask_user_questions.",
|
|
488
|
-
`One single-select question with id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\". Ask what to do next with the plan.`,
|
|
489
|
-
`Options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}.`,
|
|
490
|
-
`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.`,
|
|
491
|
-
"Do not restate the plan. Just show the question.",
|
|
492
|
-
].join(" ");
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function buildApprovalModeInstructions(): string {
|
|
496
484
|
const autoSwitchEnabled = readAutoSwitchPlanModelSetting();
|
|
497
485
|
const showNewSessionOption = autoSwitchEnabled;
|
|
498
486
|
const newSessionLabel = buildNewSessionOptionLabel();
|
|
499
487
|
|
|
500
|
-
const options = showNewSessionOption
|
|
501
|
-
? `${APPROVE_AUTO_LABEL}, ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}, ${newSessionLabel}`
|
|
502
|
-
: `${APPROVE_AUTO_LABEL}, ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}`;
|
|
503
|
-
|
|
504
488
|
return [
|
|
505
|
-
"
|
|
506
|
-
`
|
|
507
|
-
`
|
|
489
|
+
"Ask for plan approval now via exactly one ask_user_questions tool call.",
|
|
490
|
+
`Question 1 (single-select) id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\": ask what to do next with the plan. In the question text, tell the user that if they choose \"${REVISE_LABEL}\" they should type exact requested changes in the dialog notes field before submitting.`,
|
|
491
|
+
`Question 1 options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}. Put "${APPROVE_LABEL}" first with a "(Recommended)" suffix in the description, not in the label.`,
|
|
492
|
+
`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.`,
|
|
493
|
+
`Question 2 (single-select) id \"${PLAN_APPROVAL_PERMISSION_QUESTION_ID}\": ask which execution mode to use.`,
|
|
494
|
+
`Question 2 options: ${APPROVE_AUTO_LABEL} (Recommended), ${APPROVE_BYPASS_LABEL}, ${APPROVE_AUTO_SUBAGENT_LABEL}, ${APPROVE_BYPASS_SUBAGENT_LABEL}${showNewSessionOption ? `, ${newSessionLabel}` : ""}.`,
|
|
495
|
+
`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.`,
|
|
496
|
+
"Do not restate the plan in a normal assistant response. Just call ask_user_questions.",
|
|
508
497
|
].join(" ");
|
|
509
498
|
}
|
|
510
499
|
|
|
@@ -569,6 +558,25 @@ function buildReviewSteeringMessage(planPath: string, planMarkdown?: string): st
|
|
|
569
558
|
return details.join("\n\n");
|
|
570
559
|
}
|
|
571
560
|
|
|
561
|
+
function buildRevisionSteeringMessage(planPath: string, requestedChanges?: string): string {
|
|
562
|
+
const details = [
|
|
563
|
+
`The user selected \"${REVISE_LABEL}\" for ${planPath}.`,
|
|
564
|
+
"Revise the existing saved plan instead of drafting a fresh replacement unless a full rewrite is genuinely necessary.",
|
|
565
|
+
"Prefer the edit tool for targeted adjustments to the current plan artifact. Use write only if the structure changes substantially or an exact edit is impractical.",
|
|
566
|
+
`Before saving the revised plan, make sure confidence is at least ${MIN_PLAN_CONFIDENCE}/10. If lower, investigate more or ask clarifying questions first.`,
|
|
567
|
+
"Keep an explicit confidence line in the plan, for example: \"Confidence: 8/10\" or higher.",
|
|
568
|
+
];
|
|
569
|
+
|
|
570
|
+
if (requestedChanges) {
|
|
571
|
+
details.push(`User-requested changes: ${requestedChanges}`);
|
|
572
|
+
} else {
|
|
573
|
+
details.push("No concrete revision note was provided yet. Ask one concise clarifying question about what should change before editing the plan.");
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
details.push("After revising the saved plan artifact, ask for approval again.");
|
|
577
|
+
return details.join("\n\n");
|
|
578
|
+
}
|
|
579
|
+
|
|
572
580
|
function approvalSelectionToExecutionMode(
|
|
573
581
|
selected: string | undefined,
|
|
574
582
|
): { permissionMode: RestorablePermissionMode; executeWithSubagent: boolean } | undefined {
|
|
@@ -598,6 +606,12 @@ function getAnswerValues(answer: AskUserAnswer | undefined): string[] {
|
|
|
598
606
|
return values;
|
|
599
607
|
}
|
|
600
608
|
|
|
609
|
+
function getAnswerNote(answer: AskUserAnswer | undefined): string | undefined {
|
|
610
|
+
if (typeof answer?.notes !== "string") return undefined;
|
|
611
|
+
const note = answer.notes.trim();
|
|
612
|
+
return note.length > 0 ? note : undefined;
|
|
613
|
+
}
|
|
614
|
+
|
|
601
615
|
function selectionRequestsCancel(selected: string[]): boolean {
|
|
602
616
|
return selected.some((value) => {
|
|
603
617
|
if (typeof value !== "string") return false;
|
|
@@ -621,6 +635,8 @@ export const __testing = {
|
|
|
621
635
|
buildApprovalSteeringMessage,
|
|
622
636
|
buildPlanPreviewMessage,
|
|
623
637
|
buildReviewSteeringMessage,
|
|
638
|
+
buildRevisionSteeringMessage,
|
|
639
|
+
buildPlanModeSystemPrompt,
|
|
624
640
|
buildAutoSuggestPlanModeSystemPrompt,
|
|
625
641
|
readAutoSuggestPlanModeSetting,
|
|
626
642
|
PLAN_SUGGEST_QUESTION_ID,
|
|
@@ -813,8 +829,16 @@ export default function planCommand(pi: ExtensionAPI) {
|
|
|
813
829
|
if (!actionSelection) return;
|
|
814
830
|
|
|
815
831
|
if (actionSelection.includes(APPROVE_LABEL)) {
|
|
816
|
-
|
|
817
|
-
|
|
832
|
+
const executionMode = approvalSelectionToExecutionMode(permissionValues[0]) ?? {
|
|
833
|
+
permissionMode: DEFAULT_APPROVAL_PERMISSION_MODE,
|
|
834
|
+
executeWithSubagent: false,
|
|
835
|
+
};
|
|
836
|
+
state = { ...state, targetPermissionMode: executionMode.permissionMode };
|
|
837
|
+
if (executionMode.executeWithSubagent) {
|
|
838
|
+
const modeLabel = executionMode.permissionMode === "danger-full-access" ? "bypass" : "auto";
|
|
839
|
+
ctx.ui?.notify?.(`Plan approved: subagent(${modeLabel})`, "info");
|
|
840
|
+
}
|
|
841
|
+
await approvePlan(pi, ctx, executionMode.permissionMode, executionMode.executeWithSubagent);
|
|
818
842
|
return;
|
|
819
843
|
}
|
|
820
844
|
|
|
@@ -831,9 +855,14 @@ export default function planCommand(pi: ExtensionAPI) {
|
|
|
831
855
|
}
|
|
832
856
|
|
|
833
857
|
if (actionSelection.includes(REVISE_LABEL)) {
|
|
858
|
+
const requestedChanges = getAnswerNote(actionAnswer);
|
|
834
859
|
enablePlanMode(pi, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, {
|
|
835
860
|
approvalStatus: "revising",
|
|
836
861
|
});
|
|
862
|
+
pi.sendUserMessage(
|
|
863
|
+
buildRevisionSteeringMessage(state.latestPlanPath ?? "the latest plan", requestedChanges),
|
|
864
|
+
{ deliverAs: "steer" },
|
|
865
|
+
);
|
|
837
866
|
}
|
|
838
867
|
});
|
|
839
868
|
|