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