apex-code 0.5.0 → 0.5.1
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/CHANGELOG.md +257 -5
- package/README.md +624 -0
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +3 -9
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/runtime-setup.d.ts +2 -0
- package/dist/bun/runtime-setup.d.ts.map +1 -0
- package/dist/bun/runtime-setup.js +9 -0
- package/dist/bun/runtime-setup.js.map +1 -0
- package/dist/bun/sandbox-env-setup.d.ts +2 -0
- package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
- package/dist/bun/sandbox-env-setup.js +4 -0
- package/dist/bun/sandbox-env-setup.js.map +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +16 -5
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +2 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.d.ts +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +13 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +16 -8
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +85 -15
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +685 -266
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +55 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bug-report.d.ts +176 -0
- package/dist/core/bug-report.d.ts.map +1 -0
- package/dist/core/bug-report.js +291 -0
- package/dist/core/bug-report.js.map +1 -0
- package/dist/core/cache-stats.d.ts.map +1 -1
- package/dist/core/cache-stats.js +12 -1
- package/dist/core/cache-stats.js.map +1 -1
- package/dist/core/cache-warmer.d.ts +103 -0
- package/dist/core/cache-warmer.d.ts.map +1 -0
- package/dist/core/cache-warmer.js +356 -0
- package/dist/core/cache-warmer.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +4 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +5 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +163 -66
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context/pipeline.d.ts +8 -8
- package/dist/core/context/pipeline.d.ts.map +1 -1
- package/dist/core/context/pipeline.js +21 -12
- package/dist/core/context/pipeline.js.map +1 -1
- package/dist/core/crash-log.d.ts +27 -0
- package/dist/core/crash-log.d.ts.map +1 -0
- package/dist/core/crash-log.js +139 -0
- package/dist/core/crash-log.js.map +1 -0
- package/dist/core/export-html/template.js +6 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/jiti-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-loader.js +4 -0
- package/dist/core/extensions/jiti-loader.js.map +1 -0
- package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-static-loader.js +4 -0
- package/dist/core/extensions/jiti-static-loader.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +40 -59
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +24 -8
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +195 -72
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +142 -55
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts +3 -0
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/virtual-modules.js +41 -0
- package/dist/core/extensions/virtual-modules.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +1 -20
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +2 -0
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +6 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +5 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +168 -20
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +44 -18
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +8 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +1 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +12 -6
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/permissions/store.d.ts.map +1 -1
- package/dist/core/permissions/store.js +11 -8
- package/dist/core/permissions/store.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +6 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +61 -35
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-composer.d.ts +4 -2
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +29 -2
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/radius.d.ts +3 -0
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +6 -0
- package/dist/core/radius.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +6 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +63 -42
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +6 -2
- package/dist/core/session-export.d.ts.map +1 -1
- package/dist/core/session-export.js +14 -13
- package/dist/core/session-export.js.map +1 -1
- package/dist/core/session-manager.d.ts +66 -15
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +295 -115
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +27 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +55 -7
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +5 -4
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +49 -6
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +140 -79
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +7 -8
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +20 -115
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +1 -12
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +6 -204
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +4 -55
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +4 -60
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +4 -49
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +4 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +10 -125
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts +18 -0
- package/dist/core/tools/renderers/bash.d.ts.map +1 -0
- package/dist/core/tools/renderers/bash.js +126 -0
- package/dist/core/tools/renderers/bash.js.map +1 -0
- package/dist/core/tools/renderers/edit.d.ts +23 -0
- package/dist/core/tools/renderers/edit.d.ts.map +1 -0
- package/dist/core/tools/renderers/edit.js +207 -0
- package/dist/core/tools/renderers/edit.js.map +1 -0
- package/dist/core/tools/renderers/find.d.ts +10 -0
- package/dist/core/tools/renderers/find.d.ts.map +1 -0
- package/dist/core/tools/renderers/find.js +64 -0
- package/dist/core/tools/renderers/find.js.map +1 -0
- package/dist/core/tools/renderers/grep.d.ts +10 -0
- package/dist/core/tools/renderers/grep.d.ts.map +1 -0
- package/dist/core/tools/renderers/grep.js +69 -0
- package/dist/core/tools/renderers/grep.js.map +1 -0
- package/dist/core/tools/renderers/index.d.ts +34 -0
- package/dist/core/tools/renderers/index.d.ts.map +1 -0
- package/dist/core/tools/renderers/index.js +47 -0
- package/dist/core/tools/renderers/index.js.map +1 -0
- package/dist/core/tools/renderers/ls.d.ts +10 -0
- package/dist/core/tools/renderers/ls.d.ts.map +1 -0
- package/dist/core/tools/renderers/ls.js +58 -0
- package/dist/core/tools/renderers/ls.js.map +1 -0
- package/dist/core/tools/renderers/read.d.ts +11 -0
- package/dist/core/tools/renderers/read.d.ts.map +1 -0
- package/dist/core/tools/renderers/read.js +132 -0
- package/dist/core/tools/renderers/read.js.map +1 -0
- package/dist/core/tools/renderers/write.d.ts +10 -0
- package/dist/core/tools/renderers/write.d.ts.map +1 -0
- package/dist/core/tools/renderers/write.js +152 -0
- package/dist/core/tools/renderers/write.js.map +1 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +6 -146
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/usage-totals.d.ts +1 -1
- package/dist/core/usage-totals.d.ts.map +1 -1
- package/dist/core/usage-totals.js +5 -1
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/extensions/llama/client.d.ts +2 -0
- package/dist/extensions/llama/client.d.ts.map +1 -1
- package/dist/extensions/llama/client.js +7 -3
- package/dist/extensions/llama/client.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +20 -5
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +21 -13
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/bug-report.d.ts +16 -0
- package/dist/modes/interactive/bug-report.d.ts.map +1 -0
- package/dist/modes/interactive/bug-report.js +167 -0
- package/dist/modes/interactive/bug-report.js.map +1 -0
- package/dist/modes/interactive/chat-viewport.d.ts +20 -0
- package/dist/modes/interactive/chat-viewport.d.ts.map +1 -0
- package/dist/modes/interactive/chat-viewport.js +28 -0
- package/dist/modes/interactive/chat-viewport.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +7 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +63 -17
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +12 -5
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +12 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +38 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/error-summary.d.ts +11 -0
- package/dist/modes/interactive/components/error-summary.d.ts.map +1 -0
- package/dist/modes/interactive/components/error-summary.js +31 -0
- package/dist/modes/interactive/components/error-summary.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +6 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +6 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +2 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +3 -3
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +13 -15
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +74 -48
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +5 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +35 -10
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +10 -3
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +6 -6
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +27 -5
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +64 -42
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +9 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/trust-selector.js +2 -2
- package/dist/modes/interactive/components/trust-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +43 -29
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +431 -166
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +5 -0
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
- package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-json.js +130 -0
- package/dist/modes/interactive/theme/theme-json.js.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.json +6 -2
- package/dist/modes/interactive/theme/theme.d.ts +14 -5
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +18 -119
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/interactive/tui-renderer.d.ts +21 -0
- package/dist/modes/interactive/tui-renderer.d.ts.map +1 -0
- package/dist/modes/interactive/tui-renderer.js +66 -0
- package/dist/modes/interactive/tui-renderer.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/testing/replay/recorded-provider.d.ts +2 -2
- package/dist/testing/replay/recorded-provider.d.ts.map +1 -1
- package/dist/testing/replay/recorded-provider.js +2 -5
- package/dist/testing/replay/recorded-provider.js.map +1 -1
- package/dist/testing/replay/runner.d.ts.map +1 -1
- package/dist/testing/replay/runner.js +0 -1
- package/dist/testing/replay/runner.js.map +1 -1
- package/dist/utils/clipboard-command.d.ts +7 -0
- package/dist/utils/clipboard-command.d.ts.map +1 -0
- package/dist/utils/clipboard-command.js +45 -0
- package/dist/utils/clipboard-command.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +53 -81
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +111 -121
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js +2 -3
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +21 -21
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tool-result-images.d.ts +3 -1
- package/dist/utils/tool-result-images.d.ts.map +1 -1
- package/dist/utils/tool-result-images.js +4 -1
- package/dist/utils/tool-result-images.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +11 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/wsl.d.ts +3 -0
- package/dist/utils/wsl.d.ts.map +1 -0
- package/dist/utils/wsl.js +15 -0
- package/dist/utils/wsl.js.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/dist/utils/zip.js +60 -0
- package/dist/utils/zip.js.map +1 -0
- package/docs/cli-integration.md +107 -0
- package/docs/cli.md +269 -0
- package/docs/compaction.md +73 -24
- package/docs/configuration.md +45 -0
- package/docs/containerization.md +22 -21
- package/docs/custom-provider.md +21 -12
- package/docs/development.md +19 -0
- package/docs/docs.json +139 -95
- package/docs/extensions.md +243 -371
- package/docs/how-pi-works.md +49 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/index.md +3 -3
- package/docs/json.md +7 -3
- package/docs/keybindings.md +57 -54
- package/docs/llama-cpp.md +2 -2
- package/docs/message-types.md +261 -0
- package/docs/models.md +103 -49
- package/docs/packages.md +49 -47
- package/docs/prompt-templates.md +29 -56
- package/docs/providers.md +91 -139
- package/docs/quickstart.md +42 -14
- package/docs/rpc-commands.md +854 -0
- package/docs/rpc-extension-ui.md +200 -0
- package/docs/rpc.md +121 -223
- package/docs/sdk.md +99 -124
- package/docs/security.md +7 -7
- package/docs/session-format.md +85 -82
- package/docs/sessions.md +41 -57
- package/docs/settings.md +94 -87
- package/docs/shell-aliases.md +68 -3
- package/docs/skills.md +62 -49
- package/docs/slash-commands.md +60 -0
- package/docs/terminal-setup.md +86 -55
- package/docs/termux.md +65 -75
- package/docs/themes.md +64 -86
- package/docs/tmux.md +29 -7
- package/docs/tui.md +67 -122
- package/docs/usage.md +31 -42
- package/docs/windows.md +41 -13
- package/examples/README.md +16 -2
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +2 -0
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/prompt-customizer.ts +19 -67
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/plugins/pi-example-plugin/README.md +38 -0
- package/examples/plugins/pi-example-plugin/package.json +10 -0
- package/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
- package/examples/plugins/pi-example-plugin/src/session.ts +24 -0
- package/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
- package/examples/rpc-client.ts +35 -0
- package/examples/rpc-extension-ui.ts +25 -5
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +861 -513
- package/package.json +27 -18
- package/dist/bun/register-bedrock.d.ts +0 -2
- package/dist/bun/register-bedrock.d.ts.map +0 -1
- package/dist/bun/register-bedrock.js +0 -4
- package/dist/bun/register-bedrock.js.map +0 -1
- package/dist/cli/experimental/auth.d.ts +0 -16
- package/dist/cli/experimental/auth.d.ts.map +0 -1
- package/dist/cli/experimental/auth.js +0 -13
- package/dist/cli/experimental/auth.js.map +0 -1
- package/dist/cli/experimental/cli.d.ts +0 -6
- package/dist/cli/experimental/cli.d.ts.map +0 -1
- package/dist/cli/experimental/cli.js +0 -5
- package/dist/cli/experimental/cli.js.map +0 -1
- package/dist/cli/experimental/command-options.d.ts +0 -17
- package/dist/cli/experimental/command-options.d.ts.map +0 -1
- package/dist/cli/experimental/command-options.js +0 -35
- package/dist/cli/experimental/command-options.js.map +0 -1
- package/dist/cli/experimental/command.d.ts +0 -63
- package/dist/cli/experimental/command.d.ts.map +0 -1
- package/dist/cli/experimental/command.js +0 -130
- package/dist/cli/experimental/command.js.map +0 -1
- package/dist/cli/experimental/commands/client.d.ts +0 -13
- package/dist/cli/experimental/commands/client.d.ts.map +0 -1
- package/dist/cli/experimental/commands/client.js +0 -25
- package/dist/cli/experimental/commands/client.js.map +0 -1
- package/dist/cli/experimental/commands/pi.d.ts +0 -15
- package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
- package/dist/cli/experimental/commands/pi.js +0 -28
- package/dist/cli/experimental/commands/pi.js.map +0 -1
- package/dist/cli/experimental/commands/server.d.ts +0 -13
- package/dist/cli/experimental/commands/server.d.ts.map +0 -1
- package/dist/cli/experimental/commands/server.js +0 -25
- package/dist/cli/experimental/commands/server.js.map +0 -1
- package/dist/cli/experimental/transport-address.d.ts +0 -10
- package/dist/cli/experimental/transport-address.d.ts.map +0 -1
- package/dist/cli/experimental/transport-address.js +0 -38
- package/dist/cli/experimental/transport-address.js.map +0 -1
- package/dist/client/index.d.ts +0 -3
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -3
- package/dist/client/index.js.map +0 -1
- package/dist/client/remote-session.d.ts +0 -53
- package/dist/client/remote-session.d.ts.map +0 -1
- package/dist/client/remote-session.js +0 -340
- package/dist/client/remote-session.js.map +0 -1
- package/dist/client/transcript.d.ts +0 -12
- package/dist/client/transcript.d.ts.map +0 -1
- package/dist/client/transcript.js +0 -98
- package/dist/client/transcript.js.map +0 -1
- package/dist/utils/clipboard-native.d.ts +0 -11
- package/dist/utils/clipboard-native.d.ts.map +0 -1
- package/dist/utils/clipboard-native.js +0 -20
- package/dist/utils/clipboard-native.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Container, fuzzyFilter, getKeybindings,
|
|
1
|
+
import { Container, fuzzyFilter, getKeybindings, SelectList, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { getSelectListTheme } from "../theme/theme.js";
|
|
3
3
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
4
4
|
import { hintRow, keyDisplayText } from "./keybinding-hints.js";
|
|
@@ -42,7 +42,7 @@ export class ThinkingSelectorComponent extends Container {
|
|
|
42
42
|
this.onSelectAsDefault = onSelectAsDefault;
|
|
43
43
|
this.allItems = availableLevels.map((level) => ({
|
|
44
44
|
value: level,
|
|
45
|
-
label: level
|
|
45
|
+
label: `${level === currentLevel ? "✓ " : " "}${level}`,
|
|
46
46
|
description: level === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],
|
|
47
47
|
}));
|
|
48
48
|
// Add top border
|
|
@@ -63,7 +63,7 @@ export class ThinkingSelectorComponent extends Container {
|
|
|
63
63
|
this.addChild(new Spacer(1));
|
|
64
64
|
this.addChild(new Text(hintRow([
|
|
65
65
|
["tui.select.confirm", "select"],
|
|
66
|
-
[
|
|
66
|
+
["app.thinking.save", "set as default"],
|
|
67
67
|
["tui.select.cancel", "close"],
|
|
68
68
|
]), 0, 0));
|
|
69
69
|
// Add bottom border
|
|
@@ -81,7 +81,7 @@ export class ThinkingSelectorComponent extends Container {
|
|
|
81
81
|
}
|
|
82
82
|
applyFilter(query) {
|
|
83
83
|
const filtered = query
|
|
84
|
-
? fuzzyFilter(this.allItems, query, (item) => `${item.
|
|
84
|
+
? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? ""}`)
|
|
85
85
|
: this.allItems;
|
|
86
86
|
const selectedValue = this.selectList.getSelectedItem()?.value;
|
|
87
87
|
const newList = this.buildSelectList(filtered, selectedValue);
|
|
@@ -89,13 +89,13 @@ export class ThinkingSelectorComponent extends Container {
|
|
|
89
89
|
this.selectList = newList;
|
|
90
90
|
}
|
|
91
91
|
handleInput(keyData) {
|
|
92
|
-
|
|
92
|
+
const kb = getKeybindings();
|
|
93
|
+
if (kb.matches(keyData, "app.thinking.save") && this.onSelectAsDefault) {
|
|
93
94
|
const item = this.selectList.getSelectedItem();
|
|
94
95
|
if (item)
|
|
95
96
|
this.onSelectAsDefault(item.value);
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
98
|
-
const kb = getKeybindings();
|
|
99
99
|
const isNav = kb.matches(keyData, "tui.select.up") ||
|
|
100
100
|
kb.matches(keyData, "tui.select.down") ||
|
|
101
101
|
kb.matches(keyData, "tui.select.confirm") ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thinking-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,SAAS,EAET,WAAW,EACX,cAAc,
|
|
1
|
+
{"version":3,"file":"thinking-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\ttype Input,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport type { ThinkingLevel } from \"apex-code-agent-core\";\nimport { getSelectListTheme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { hintRow, keyDisplayText } from \"./keybinding-hints.ts\";\nimport { PromptInput } from \"./prompt-input.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: `${level === currentLevel ? \"✓ \" : \" \"}${level}`,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new PromptInput();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\thintRow([\n\t\t\t\t\t[\"tui.select.confirm\", \"select\"],\n\t\t\t\t\t[\"app.thinking.save\", \"set as default\"],\n\t\t\t\t\t[\"tui.select.cancel\", \"close\"],\n\t\t\t\t]),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.thinking.save\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import { Container, type TUI } from "@earendil-works/pi-tui";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import { type Component, Container, type TUI, type TuiMouseEvent } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { AgentToolResult } from "apex-code-agent-core";
|
|
3
|
+
import type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from "../../../core/extensions/types.ts";
|
|
4
|
+
import type { Theme } from "../theme/theme.ts";
|
|
5
|
+
/**
|
|
6
|
+
* What this component needs from a tool: how to draw it. It neither executes tools nor reads their
|
|
7
|
+
* parameter schemas, so a definition and a bare renderer pair are equally acceptable.
|
|
8
|
+
*
|
|
9
|
+
* The renderer parameters are `any` on purpose: a `ToolDefinition` types them from its schema, and
|
|
10
|
+
* narrowing them here would make those definitions unassignable.
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolRenderers {
|
|
13
|
+
renderShell?: "default" | "self";
|
|
14
|
+
renderCall?: (args: any, theme: Theme, context: ToolRenderContext<any, any>) => Component;
|
|
15
|
+
renderResult?: (result: AgentToolResult<any>, options: ToolRenderResultOptions, theme: Theme, context: ToolRenderContext<any, any>) => Component;
|
|
16
|
+
}
|
|
4
17
|
import { type ToolSymbolPreset } from "./tool-panel.ts";
|
|
5
18
|
export interface ToolExecutionOptions {
|
|
6
19
|
showImages?: boolean;
|
|
@@ -11,6 +24,7 @@ export interface ToolExecutionOptions {
|
|
|
11
24
|
export declare class ToolExecutionComponent extends Container {
|
|
12
25
|
private contentBox;
|
|
13
26
|
private contentText;
|
|
27
|
+
private contentTextRegion;
|
|
14
28
|
private selfRenderContainer;
|
|
15
29
|
private callRendererComponent?;
|
|
16
30
|
private resultRendererComponent?;
|
|
@@ -26,7 +40,6 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
26
40
|
private imageWidthCells;
|
|
27
41
|
private isPartial;
|
|
28
42
|
private toolDefinition?;
|
|
29
|
-
private builtInToolDefinition?;
|
|
30
43
|
private ui;
|
|
31
44
|
private cwd;
|
|
32
45
|
private executionStarted;
|
|
@@ -40,7 +53,7 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
40
53
|
private result?;
|
|
41
54
|
private convertedImages;
|
|
42
55
|
private hideComponent;
|
|
43
|
-
constructor(toolName: string, toolCallId: string, args: any, options: ToolExecutionOptions | undefined, toolDefinition: ToolDefinition<any, any
|
|
56
|
+
constructor(toolName: string, toolCallId: string, args: any, options: ToolExecutionOptions | undefined, toolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined, ui: TUI, cwd: string);
|
|
44
57
|
private getCallRenderer;
|
|
45
58
|
private getResultRenderer;
|
|
46
59
|
private hasRendererDefinition;
|
|
@@ -48,6 +61,7 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
48
61
|
private getRenderContext;
|
|
49
62
|
private createCallFallback;
|
|
50
63
|
private createResultFallback;
|
|
64
|
+
private createResultRegion;
|
|
51
65
|
updateArgs(args: any): void;
|
|
52
66
|
markExecutionStarted(): void;
|
|
53
67
|
setArgsComplete(): void;
|
|
@@ -85,6 +99,14 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
85
99
|
*/
|
|
86
100
|
private renderCacheKey;
|
|
87
101
|
private compose;
|
|
102
|
+
/**
|
|
103
|
+
* A left click on the panel toggles the result, as upstream's per-region
|
|
104
|
+
* handlers do. Apex composes the panel itself (lifecycle header, spine,
|
|
105
|
+
* padding, the separator row it inserts), so rendered rows do not line up
|
|
106
|
+
* with the children's rows and the inherited child-by-child dispatch would
|
|
107
|
+
* resolve the wrong region. Row 0 is the leading spacer and is inert.
|
|
108
|
+
*/
|
|
109
|
+
handleMouse(event: TuiMouseEvent): ReturnType<Container["handleMouse"]>;
|
|
88
110
|
private updateDisplay;
|
|
89
111
|
private getTextOutput;
|
|
90
112
|
private formatToolExecution;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { Box, type Component, Container, getCapabilities, Image, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport type { ToolDefinition, ToolRenderContext } from \"../../../core/extensions/types.ts\";\nimport type { ApexToolDefinition } from \"../../../core/tools/contract.ts\";\nimport { createAllToolDefinitions, type ToolName } from \"../../../core/tools/index.ts\";\nimport { getTextOutput as getRenderedTextOutput } from \"../../../core/tools/render-utils.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatHiddenLines, previewLineCount } from \"./keybinding-hints.ts\";\nimport {\n\ttype ToolLifecycle,\n\tToolPanelComponent,\n\tToolStatusLineComponent,\n\ttype ToolSymbolPreset,\n} from \"./tool-panel.ts\";\n\nconst COLLAPSED_ERROR_VISUAL_LINE_LIMIT = 3;\n\nconst FALLBACK_PREVIEW_LINES = 10;\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n\tsymbolPreset?: ToolSymbolPreset;\n}\n\n/** The phrase every expand affordance ends with, here and in each tool's own renderer. */\n\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box;\n\tprivate contentText: Text;\n\tprivate selfRenderContainer: Container;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate editDiffsExpanded = true;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolDefinition<any, any> | ApexToolDefinition<any, any>;\n\tprivate builtInToolDefinition?: ToolDefinition<any, any> | ApexToolDefinition<any, any>;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate executionStartedAt?: number;\n\tprivate executionEndedAt?: number;\n\tprivate elapsedTimer?: ReturnType<typeof setInterval>;\n\tprivate argsComplete = false;\n\tprivate symbolPreset: ToolSymbolPreset;\n\t// Composed-line cache. Recomposing the panel (ANSI-aware truncation, width\n\t// measurement, background paint per content line) on every frame made\n\t// per-frame cost grow with the number of tools on screen; see\n\t// test/tool-execution-render-cache.test.ts.\n\tprivate displayVersion = 0;\n\tprivate cachedRender?: { key: string; width: number; lines: string[] };\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages: Map<number, { data: string; mimeType: string }> = new Map();\n\tprivate hideComponent = false;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolDefinition<any, any> | ApexToolDefinition<any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.builtInToolDefinition = createAllToolDefinitions(cwd)[toolName as ToolName];\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.symbolPreset = options.symbolPreset ?? \"unicode\";\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Always create all shell variants. contentBox is used for default renderer-based composition.\n\t\t// selfRenderContainer is used when the tool renders its own framing.\n\t\t// contentText is reserved for generic fallback rendering when no tool definition exists.\n\t\tthis.contentBox = new Box(0, 0);\n\t\tthis.contentText = new Text(\"\", 0, 0);\n\t\tthis.selfRenderContainer = new Container();\n\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tthis.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentText);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderCall;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderCall;\n\t\t}\n\t\treturn this.toolDefinition.renderCall ?? this.builtInToolDefinition.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderResult;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderResult;\n\t\t}\n\t\treturn this.toolDefinition.renderResult ?? this.builtInToolDefinition.renderResult;\n\t}\n\n\tprivate hasRendererDefinition(): boolean {\n\t\treturn this.builtInToolDefinition !== undefined || this.toolDefinition !== undefined;\n\t}\n\n\tprivate getRenderShell(): \"default\" | \"self\" {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderShell ?? \"default\";\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderShell ?? \"default\";\n\t\t}\n\t\treturn this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? \"default\";\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\teditDiffsExpanded: this.editDiffsExpanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t};\n\t}\n\n\tprivate createCallFallback(): Component {\n\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0);\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst displayLines = this.expanded\n\t\t\t? lines\n\t\t\t: lines.slice(0, previewLineCount(lines.length, FALLBACK_PREVIEW_LINES));\n\t\tconst remaining = lines.length - displayLines.length;\n\t\tlet text = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\tif (remaining > 0) text += `\\n${formatHiddenLines(remaining, \"more\")}`;\n\t\treturn new Text(text, 0, 0);\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tthis.executionStarted = true;\n\t\tthis.executionStartedAt ??= Date.now();\n\t\tthis.startElapsedTimer();\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.executionEndedAt ??= Date.now();\n\t\t\tthis.stopElapsedTimer();\n\t\t}\n\t\tthis.updateDisplay();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tdispose(): void {\n\t\tthis.stopElapsedTimer();\n\t\tthis.cachedRender = undefined;\n\t}\n\n\tprivate startElapsedTimer(): void {\n\t\tif (this.elapsedTimer) return;\n\t\tthis.elapsedTimer = setInterval(() => this.ui.requestRender(), 1000);\n\t}\n\n\tprivate stopElapsedTimer(): void {\n\t\tif (!this.elapsedTimer) return;\n\t\tclearInterval(this.elapsedTimer);\n\t\tthis.elapsedTimer = undefined;\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\tif (img.mimeType === \"image/png\") continue;\n\t\t\tif (this.convertedImages.has(i)) continue;\n\n\t\t\tconst index = i;\n\t\t\tconvertToPng(img.data, img.mimeType).then((converted) => {\n\t\t\t\tif (converted) {\n\t\t\t\t\tthis.convertedImages.set(index, converted);\n\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tsetEditDiffsExpanded(expanded: boolean): void {\n\t\tif (this.editDiffsExpanded === expanded) return;\n\t\tthis.editDiffsExpanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getLifecycle(): ToolLifecycle {\n\t\tif (this.result && !this.isPartial) return this.result.isError ? \"error\" : \"done\";\n\t\treturn this.executionStarted ? \"running\" : \"queued\";\n\t}\n\n\tprivate getDurationMs(): number | undefined {\n\t\tif (this.executionStartedAt === undefined) return undefined;\n\t\treturn (this.executionEndedAt ?? Date.now()) - this.executionStartedAt;\n\t}\n\n\tprivate renderWithStatus(component: Component, width: number): string[] {\n\t\tconst options = {\n\t\t\tlifecycle: this.getLifecycle(),\n\t\t\tsymbolPreset: this.symbolPreset,\n\t\t\tdurationMs: this.getDurationMs(),\n\t\t};\n\t\tif (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n\t\t\treturn new ToolStatusLineComponent(component, options).render(width);\n\t\t}\n\t\treturn new ToolPanelComponent(component, options).render(width);\n\t}\n\n\tprivate renderCollapsedError(contentLines: string[], width: number): string[] {\n\t\tconst errorText = this.getTextOutput();\n\t\tif (!errorText || contentLines.length === 0) return contentLines;\n\n\t\tconst errorLines = new Text(theme.fg(\"toolOutput\", errorText), 0, 0).render(width);\n\t\tconst previewLines = errorLines.slice(0, previewLineCount(errorLines.length, COLLAPSED_ERROR_VISUAL_LINE_LIMIT));\n\t\tconst omittedLines = errorLines.length - previewLines.length;\n\t\tif (omittedLines === 0) return [...contentLines.slice(0, 1), ...previewLines];\n\n\t\treturn [...contentLines.slice(0, 1), ...previewLines, formatHiddenLines(omittedLines, \"more\")];\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent || width <= 0) return [];\n\t\tconst key = this.renderCacheKey();\n\t\tconst cached = this.cachedRender;\n\t\tif (cached && cached.key === key && cached.width === width) return cached.lines;\n\t\tconst lines = this.compose(width);\n\t\tthis.cachedRender = { key, width, lines };\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Cache key for the composed lines. Every state change funnels through\n\t * updateDisplay(), which bumps displayVersion; the elapsed readout is the\n\t * one input that advances without a state change, so it is bucketed at\n\t * 250 ms while running (matching the 1 s elapsed timer's cadence closely\n\t * enough that the readout never looks stale, while bounding recomposition\n\t * to at most four per second for the one running tool).\n\t */\n\tprivate renderCacheKey(): string {\n\t\tconst lifecycle = this.getLifecycle();\n\t\tconst durationMs = this.getDurationMs();\n\t\tconst durationKey = lifecycle === \"running\" ? Math.floor((durationMs ?? 0) / 250) : (durationMs ?? -1);\n\t\treturn `${this.displayVersion}:${lifecycle}:${durationKey}`;\n\t}\n\n\tprivate compose(width: number): string[] {\n\t\tconst shell = this.hasRendererDefinition()\n\t\t\t? this.getRenderShell() === \"self\"\n\t\t\t\t? this.selfRenderContainer\n\t\t\t\t: this.contentBox\n\t\t\t: this.contentText;\n\t\tconst selfRendered = this.hasRendererDefinition() && this.getRenderShell() === \"self\";\n\t\tconst panelContent: Component = selfRendered\n\t\t\t? shell\n\t\t\t: {\n\t\t\t\t\trender: (innerWidth: number) => {\n\t\t\t\t\t\tconst contentLines = shell.render(innerWidth);\n\t\t\t\t\t\tconst visibleLines =\n\t\t\t\t\t\t\tthis.result?.isError && !this.isPartial && !this.expanded\n\t\t\t\t\t\t\t\t? this.renderCollapsedError(contentLines, innerWidth)\n\t\t\t\t\t\t\t\t: contentLines;\n\t\t\t\t\t\treturn visibleLines;\n\t\t\t\t\t},\n\t\t\t\t\tinvalidate: () => shell.invalidate?.(),\n\t\t\t\t};\n\t\tconst visibleContentLines = this.renderWithStatus(panelContent, width);\n\t\tif (visibleContentLines.length === 0 && this.imageComponents.length === 0) return [];\n\n\t\tconst lines: string[] = [];\n\t\tif (visibleContentLines.length > 0) {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(...visibleContentLines);\n\t\t}\n\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\tif (spacer) lines.push(...spacer.render(width));\n\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\tif (imageComponent) lines.push(...imageComponent.render(width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.displayVersion += 1;\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tconst renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n\t\t\trenderContainer.clear();\n\n\t\t\tconst callRenderer = this.getCallRenderer();\n\t\t\tif (!callRenderer) {\n\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\thasContent = true;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\thasContent = true;\n\t\t\t\t} catch {\n\t\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\t\tif (!resultRenderer) {\n\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\tif (component) {\n\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\thasContent = true;\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst converted = this.convertedImages.get(i);\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\tif (content) {\n\t\t\ttext += `\\n\\n${content}`;\n\t\t}\n\t\tconst output = this.getTextOutput();\n\t\tif (output) {\n\t\t\ttext += `\\n${output}`;\n\t\t}\n\t\treturn text;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tBox,\n\ttype Component,\n\tContainer,\n\tgetCapabilities,\n\tImage,\n\tMouseRegion,\n\tSpacer,\n\tText,\n\ttype TUI,\n\ttype TuiMouseEvent,\n} from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from \"../../../core/extensions/types.ts\";\nimport type { Theme } from \"../theme/theme.ts\";\n\n/**\n * What this component needs from a tool: how to draw it. It neither executes tools nor reads their\n * parameter schemas, so a definition and a bare renderer pair are equally acceptable.\n *\n * The renderer parameters are `any` on purpose: a `ToolDefinition` types them from its schema, and\n * narrowing them here would make those definitions unassignable.\n */\nexport interface ToolRenderers {\n\trenderShell?: \"default\" | \"self\";\n\trenderCall?: (args: any, theme: Theme, context: ToolRenderContext<any, any>) => Component;\n\trenderResult?: (\n\t\tresult: AgentToolResult<any>,\n\t\toptions: ToolRenderResultOptions,\n\t\ttheme: Theme,\n\t\tcontext: ToolRenderContext<any, any>,\n\t) => Component;\n}\n\nimport { getTextOutput as getRenderedTextOutput } from \"../../../core/tools/render-utils.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatHiddenLines, previewLineCount } from \"./keybinding-hints.ts\";\nimport {\n\ttype ToolLifecycle,\n\tToolPanelComponent,\n\tToolStatusLineComponent,\n\ttype ToolSymbolPreset,\n} from \"./tool-panel.ts\";\n\nconst COLLAPSED_ERROR_VISUAL_LINE_LIMIT = 3;\n\nconst FALLBACK_PREVIEW_LINES = 10;\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n\tsymbolPreset?: ToolSymbolPreset;\n}\n\n/** The phrase every expand affordance ends with, here and in each tool's own renderer. */\n\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box;\n\tprivate contentText: Text;\n\tprivate contentTextRegion: MouseRegion;\n\tprivate selfRenderContainer: Container;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate editDiffsExpanded = true;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolRenderers;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate executionStartedAt?: number;\n\tprivate executionEndedAt?: number;\n\tprivate elapsedTimer?: ReturnType<typeof setInterval>;\n\tprivate argsComplete = false;\n\tprivate symbolPreset: ToolSymbolPreset;\n\t// Composed-line cache. Recomposing the panel (ANSI-aware truncation, width\n\t// measurement, background paint per content line) on every frame made\n\t// per-frame cost grow with the number of tools on screen; see\n\t// test/tool-execution-render-cache.test.ts.\n\tprivate displayVersion = 0;\n\tprivate cachedRender?: { key: string; width: number; lines: string[] };\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages: Map<\n\t\tnumber,\n\t\t{ sourceData: string; sourceMimeType: string; data: string; mimeType: string }\n\t> = new Map();\n\tprivate hideComponent = false;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.symbolPreset = options.symbolPreset ?? \"unicode\";\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Always create all shell variants. contentBox is used for default renderer-based composition.\n\t\t// selfRenderContainer is used when the tool renders its own framing.\n\t\t// contentText is reserved for generic fallback rendering when no tool definition exists.\n\t\tthis.contentBox = new Box(0, 0);\n\t\tthis.contentText = new Text(\"\", 0, 0);\n\t\tthis.contentTextRegion = this.createResultRegion(this.contentText);\n\t\tthis.selfRenderContainer = new Container();\n\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tthis.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentTextRegion);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\treturn this.toolDefinition?.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\treturn this.toolDefinition?.renderResult;\n\t}\n\n\tprivate hasRendererDefinition(): boolean {\n\t\treturn this.toolDefinition !== undefined;\n\t}\n\n\tprivate getRenderShell(): \"default\" | \"self\" {\n\t\treturn this.toolDefinition?.renderShell ?? \"default\";\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\teditDiffsExpanded: this.editDiffsExpanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t};\n\t}\n\n\tprivate createCallFallback(): Component {\n\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0);\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst displayLines = this.expanded\n\t\t\t? lines\n\t\t\t: lines.slice(0, previewLineCount(lines.length, FALLBACK_PREVIEW_LINES));\n\t\tconst remaining = lines.length - displayLines.length;\n\t\tlet text = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\tif (remaining > 0) text += `\\n${formatHiddenLines(remaining, \"more\")}`;\n\t\treturn new Text(text, 0, 0);\n\t}\n\n\tprivate createResultRegion(component: Component): MouseRegion {\n\t\treturn new MouseRegion(component, (event) => {\n\t\t\tif (!this.result || event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\tthis.setExpanded(!this.expanded);\n\t\t\treturn { handled: true };\n\t\t});\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tthis.executionStarted = true;\n\t\tthis.executionStartedAt ??= Date.now();\n\t\tthis.startElapsedTimer();\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.executionEndedAt ??= Date.now();\n\t\t\tthis.stopElapsedTimer();\n\t\t}\n\t\tthis.updateDisplay();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tdispose(): void {\n\t\tthis.stopElapsedTimer();\n\t\tthis.cachedRender = undefined;\n\t}\n\n\tprivate startElapsedTimer(): void {\n\t\tif (this.elapsedTimer) return;\n\t\tthis.elapsedTimer = setInterval(() => this.ui.requestRender(), 1000);\n\t}\n\n\tprivate stopElapsedTimer(): void {\n\t\tif (!this.elapsedTimer) return;\n\t\tclearInterval(this.elapsedTimer);\n\t\tthis.elapsedTimer = undefined;\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\tconst sourceData = img.data;\n\t\t\tconst sourceMimeType = img.mimeType;\n\t\t\tif (sourceMimeType === \"image/png\") continue;\n\t\t\tconst cached = this.convertedImages.get(i);\n\t\t\tif (cached?.sourceData === sourceData && cached.sourceMimeType === sourceMimeType) continue;\n\n\t\t\tconst index = i;\n\t\t\tconvertToPng(sourceData, sourceMimeType).then((converted) => {\n\t\t\t\tconst currentImage = this.result?.content.filter((content) => content.type === \"image\")[index];\n\t\t\t\tif (!converted || currentImage?.data !== sourceData || currentImage.mimeType !== sourceMimeType) return;\n\t\t\t\tthis.convertedImages.set(index, {\n\t\t\t\t\tsourceData,\n\t\t\t\t\tsourceMimeType,\n\t\t\t\t\t...converted,\n\t\t\t\t});\n\t\t\t\tthis.updateDisplay();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t});\n\t\t}\n\t}\n\n\tsetEditDiffsExpanded(expanded: boolean): void {\n\t\tif (this.editDiffsExpanded === expanded) return;\n\t\tthis.editDiffsExpanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getLifecycle(): ToolLifecycle {\n\t\tif (this.result && !this.isPartial) return this.result.isError ? \"error\" : \"done\";\n\t\treturn this.executionStarted ? \"running\" : \"queued\";\n\t}\n\n\tprivate getDurationMs(): number | undefined {\n\t\tif (this.executionStartedAt === undefined) return undefined;\n\t\treturn (this.executionEndedAt ?? Date.now()) - this.executionStartedAt;\n\t}\n\n\tprivate renderWithStatus(component: Component, width: number): string[] {\n\t\tconst options = {\n\t\t\tlifecycle: this.getLifecycle(),\n\t\t\tsymbolPreset: this.symbolPreset,\n\t\t\tdurationMs: this.getDurationMs(),\n\t\t};\n\t\tif (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n\t\t\treturn new ToolStatusLineComponent(component, options).render(width);\n\t\t}\n\t\treturn new ToolPanelComponent(component, options).render(width);\n\t}\n\n\tprivate renderCollapsedError(contentLines: string[], width: number): string[] {\n\t\tconst errorText = this.getTextOutput();\n\t\tif (!errorText || contentLines.length === 0) return contentLines;\n\n\t\tconst errorLines = new Text(theme.fg(\"toolOutput\", errorText), 0, 0).render(width);\n\t\tconst previewLines = errorLines.slice(0, previewLineCount(errorLines.length, COLLAPSED_ERROR_VISUAL_LINE_LIMIT));\n\t\tconst omittedLines = errorLines.length - previewLines.length;\n\t\tif (omittedLines === 0) return [...contentLines.slice(0, 1), ...previewLines];\n\n\t\treturn [...contentLines.slice(0, 1), ...previewLines, formatHiddenLines(omittedLines, \"more\")];\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent || width <= 0) return [];\n\t\tconst key = this.renderCacheKey();\n\t\tconst cached = this.cachedRender;\n\t\tif (cached && cached.key === key && cached.width === width) return cached.lines;\n\t\tconst lines = this.compose(width);\n\t\tthis.cachedRender = { key, width, lines };\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Cache key for the composed lines. Every state change funnels through\n\t * updateDisplay(), which bumps displayVersion; the elapsed readout is the\n\t * one input that advances without a state change, so it is bucketed at\n\t * 250 ms while running (matching the 1 s elapsed timer's cadence closely\n\t * enough that the readout never looks stale, while bounding recomposition\n\t * to at most four per second for the one running tool).\n\t */\n\tprivate renderCacheKey(): string {\n\t\tconst lifecycle = this.getLifecycle();\n\t\tconst durationMs = this.getDurationMs();\n\t\tconst durationKey = lifecycle === \"running\" ? Math.floor((durationMs ?? 0) / 250) : (durationMs ?? -1);\n\t\treturn `${this.displayVersion}:${lifecycle}:${durationKey}`;\n\t}\n\n\tprivate compose(width: number): string[] {\n\t\tconst shell = this.hasRendererDefinition()\n\t\t\t? this.getRenderShell() === \"self\"\n\t\t\t\t? this.selfRenderContainer\n\t\t\t\t: this.contentBox\n\t\t\t: this.contentText;\n\t\tconst selfRendered = this.hasRendererDefinition() && this.getRenderShell() === \"self\";\n\t\tconst panelContent: Component = selfRendered\n\t\t\t? shell\n\t\t\t: {\n\t\t\t\t\trender: (innerWidth: number) => {\n\t\t\t\t\t\tconst contentLines = shell.render(innerWidth);\n\t\t\t\t\t\tconst visibleLines =\n\t\t\t\t\t\t\tthis.result?.isError && !this.isPartial && !this.expanded\n\t\t\t\t\t\t\t\t? this.renderCollapsedError(contentLines, innerWidth)\n\t\t\t\t\t\t\t\t: contentLines;\n\t\t\t\t\t\treturn visibleLines;\n\t\t\t\t\t},\n\t\t\t\t\tinvalidate: () => shell.invalidate?.(),\n\t\t\t\t};\n\t\tconst visibleContentLines = this.renderWithStatus(panelContent, width);\n\t\tif (visibleContentLines.length === 0 && this.imageComponents.length === 0) return [];\n\n\t\tconst lines: string[] = [];\n\t\tif (visibleContentLines.length > 0) {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(...visibleContentLines);\n\t\t}\n\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\tif (spacer) lines.push(...spacer.render(width));\n\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\tif (imageComponent) lines.push(...imageComponent.render(width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\t/**\n\t * A left click on the panel toggles the result, as upstream's per-region\n\t * handlers do. Apex composes the panel itself (lifecycle header, spine,\n\t * padding, the separator row it inserts), so rendered rows do not line up\n\t * with the children's rows and the inherited child-by-child dispatch would\n\t * resolve the wrong region. Row 0 is the leading spacer and is inert.\n\t */\n\toverride handleMouse(event: TuiMouseEvent): ReturnType<Container[\"handleMouse\"]> {\n\t\tif (this.hideComponent || event.y <= 0 || event.y >= event.height) return undefined;\n\t\tif (!this.result || event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\tthis.setExpanded(!this.expanded);\n\t\treturn {\n\t\t\thandled: true,\n\t\t\ttarget: {\n\t\t\t\tcomponent: this,\n\t\t\t\toriginX: event.screenX - event.x,\n\t\t\t\toriginY: event.screenY - event.y,\n\t\t\t\twidth: event.width,\n\t\t\t\theight: event.height,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.displayVersion += 1;\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tconst renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n\t\t\trenderContainer.clear();\n\n\t\t\tconst callRenderer = this.getCallRenderer();\n\t\t\tif (!callRenderer) {\n\t\t\t\trenderContainer.addChild(this.createResultRegion(this.createCallFallback()));\n\t\t\t\thasContent = true;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\thasContent = true;\n\t\t\t\t} catch {\n\t\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\t\trenderContainer.addChild(this.createResultRegion(this.createCallFallback()));\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\t\tif (!resultRenderer) {\n\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\tif (component) {\n\t\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\thasContent = true;\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst cached = this.convertedImages.get(i);\n\t\t\t\t\tconst converted =\n\t\t\t\t\t\tcached?.sourceData === img.data && cached.sourceMimeType === img.mimeType ? cached : undefined;\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\tif (content) {\n\t\t\ttext += `\\n\\n${content}`;\n\t\t}\n\t\tconst output = this.getTextOutput();\n\t\tif (output) {\n\t\t\ttext += `\\n${output}`;\n\t\t}\n\t\treturn text;\n\t}\n}\n"]}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Box, Container, getCapabilities, Image, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
|
-
import { createAllToolDefinitions } from "../../../core/tools/index.js";
|
|
1
|
+
import { Box, Container, getCapabilities, Image, MouseRegion, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
3
2
|
import { getTextOutput as getRenderedTextOutput } from "../../../core/tools/render-utils.js";
|
|
4
3
|
import { convertToPng } from "../../../utils/image-convert.js";
|
|
5
4
|
import { theme } from "../theme/theme.js";
|
|
@@ -11,6 +10,7 @@ const FALLBACK_PREVIEW_LINES = 10;
|
|
|
11
10
|
export class ToolExecutionComponent extends Container {
|
|
12
11
|
contentBox;
|
|
13
12
|
contentText;
|
|
13
|
+
contentTextRegion;
|
|
14
14
|
selfRenderContainer;
|
|
15
15
|
callRendererComponent;
|
|
16
16
|
resultRendererComponent;
|
|
@@ -26,7 +26,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
26
26
|
imageWidthCells;
|
|
27
27
|
isPartial = true;
|
|
28
28
|
toolDefinition;
|
|
29
|
-
builtInToolDefinition;
|
|
30
29
|
ui;
|
|
31
30
|
cwd;
|
|
32
31
|
executionStarted = false;
|
|
@@ -50,7 +49,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
50
49
|
this.toolCallId = toolCallId;
|
|
51
50
|
this.args = args;
|
|
52
51
|
this.toolDefinition = toolDefinition;
|
|
53
|
-
this.builtInToolDefinition = createAllToolDefinitions(cwd)[toolName];
|
|
54
52
|
this.showImages = options.showImages ?? true;
|
|
55
53
|
this.imageWidthCells = options.imageWidthCells ?? 60;
|
|
56
54
|
this.symbolPreset = options.symbolPreset ?? "unicode";
|
|
@@ -62,44 +60,27 @@ export class ToolExecutionComponent extends Container {
|
|
|
62
60
|
// contentText is reserved for generic fallback rendering when no tool definition exists.
|
|
63
61
|
this.contentBox = new Box(0, 0);
|
|
64
62
|
this.contentText = new Text("", 0, 0);
|
|
63
|
+
this.contentTextRegion = this.createResultRegion(this.contentText);
|
|
65
64
|
this.selfRenderContainer = new Container();
|
|
66
65
|
if (this.hasRendererDefinition()) {
|
|
67
66
|
this.addChild(this.getRenderShell() === "self" ? this.selfRenderContainer : this.contentBox);
|
|
68
67
|
}
|
|
69
68
|
else {
|
|
70
|
-
this.addChild(this.
|
|
69
|
+
this.addChild(this.contentTextRegion);
|
|
71
70
|
}
|
|
72
71
|
this.updateDisplay();
|
|
73
72
|
}
|
|
74
73
|
getCallRenderer() {
|
|
75
|
-
|
|
76
|
-
return this.toolDefinition?.renderCall;
|
|
77
|
-
}
|
|
78
|
-
if (!this.toolDefinition) {
|
|
79
|
-
return this.builtInToolDefinition.renderCall;
|
|
80
|
-
}
|
|
81
|
-
return this.toolDefinition.renderCall ?? this.builtInToolDefinition.renderCall;
|
|
74
|
+
return this.toolDefinition?.renderCall;
|
|
82
75
|
}
|
|
83
76
|
getResultRenderer() {
|
|
84
|
-
|
|
85
|
-
return this.toolDefinition?.renderResult;
|
|
86
|
-
}
|
|
87
|
-
if (!this.toolDefinition) {
|
|
88
|
-
return this.builtInToolDefinition.renderResult;
|
|
89
|
-
}
|
|
90
|
-
return this.toolDefinition.renderResult ?? this.builtInToolDefinition.renderResult;
|
|
77
|
+
return this.toolDefinition?.renderResult;
|
|
91
78
|
}
|
|
92
79
|
hasRendererDefinition() {
|
|
93
|
-
return this.
|
|
80
|
+
return this.toolDefinition !== undefined;
|
|
94
81
|
}
|
|
95
82
|
getRenderShell() {
|
|
96
|
-
|
|
97
|
-
return this.toolDefinition?.renderShell ?? "default";
|
|
98
|
-
}
|
|
99
|
-
if (!this.toolDefinition) {
|
|
100
|
-
return this.builtInToolDefinition.renderShell ?? "default";
|
|
101
|
-
}
|
|
102
|
-
return this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? "default";
|
|
83
|
+
return this.toolDefinition?.renderShell ?? "default";
|
|
103
84
|
}
|
|
104
85
|
getRenderContext(lastComponent) {
|
|
105
86
|
return {
|
|
@@ -139,6 +120,14 @@ export class ToolExecutionComponent extends Container {
|
|
|
139
120
|
text += `\n${formatHiddenLines(remaining, "more")}`;
|
|
140
121
|
return new Text(text, 0, 0);
|
|
141
122
|
}
|
|
123
|
+
createResultRegion(component) {
|
|
124
|
+
return new MouseRegion(component, (event) => {
|
|
125
|
+
if (!this.result || event.type !== "click" || event.button !== "left")
|
|
126
|
+
return undefined;
|
|
127
|
+
this.setExpanded(!this.expanded);
|
|
128
|
+
return { handled: true };
|
|
129
|
+
});
|
|
130
|
+
}
|
|
142
131
|
updateArgs(args) {
|
|
143
132
|
this.args = args;
|
|
144
133
|
this.updateDisplay();
|
|
@@ -191,17 +180,25 @@ export class ToolExecutionComponent extends Container {
|
|
|
191
180
|
const img = imageBlocks[i];
|
|
192
181
|
if (!img.data || !img.mimeType)
|
|
193
182
|
continue;
|
|
194
|
-
|
|
183
|
+
const sourceData = img.data;
|
|
184
|
+
const sourceMimeType = img.mimeType;
|
|
185
|
+
if (sourceMimeType === "image/png")
|
|
195
186
|
continue;
|
|
196
|
-
|
|
187
|
+
const cached = this.convertedImages.get(i);
|
|
188
|
+
if (cached?.sourceData === sourceData && cached.sourceMimeType === sourceMimeType)
|
|
197
189
|
continue;
|
|
198
190
|
const index = i;
|
|
199
|
-
convertToPng(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
191
|
+
convertToPng(sourceData, sourceMimeType).then((converted) => {
|
|
192
|
+
const currentImage = this.result?.content.filter((content) => content.type === "image")[index];
|
|
193
|
+
if (!converted || currentImage?.data !== sourceData || currentImage.mimeType !== sourceMimeType)
|
|
194
|
+
return;
|
|
195
|
+
this.convertedImages.set(index, {
|
|
196
|
+
sourceData,
|
|
197
|
+
sourceMimeType,
|
|
198
|
+
...converted,
|
|
199
|
+
});
|
|
200
|
+
this.updateDisplay();
|
|
201
|
+
this.ui.requestRender();
|
|
205
202
|
});
|
|
206
203
|
}
|
|
207
204
|
}
|
|
@@ -321,6 +318,30 @@ export class ToolExecutionComponent extends Container {
|
|
|
321
318
|
}
|
|
322
319
|
return lines;
|
|
323
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* A left click on the panel toggles the result, as upstream's per-region
|
|
323
|
+
* handlers do. Apex composes the panel itself (lifecycle header, spine,
|
|
324
|
+
* padding, the separator row it inserts), so rendered rows do not line up
|
|
325
|
+
* with the children's rows and the inherited child-by-child dispatch would
|
|
326
|
+
* resolve the wrong region. Row 0 is the leading spacer and is inert.
|
|
327
|
+
*/
|
|
328
|
+
handleMouse(event) {
|
|
329
|
+
if (this.hideComponent || event.y <= 0 || event.y >= event.height)
|
|
330
|
+
return undefined;
|
|
331
|
+
if (!this.result || event.type !== "click" || event.button !== "left")
|
|
332
|
+
return undefined;
|
|
333
|
+
this.setExpanded(!this.expanded);
|
|
334
|
+
return {
|
|
335
|
+
handled: true,
|
|
336
|
+
target: {
|
|
337
|
+
component: this,
|
|
338
|
+
originX: event.screenX - event.x,
|
|
339
|
+
originY: event.screenY - event.y,
|
|
340
|
+
width: event.width,
|
|
341
|
+
height: event.height,
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
}
|
|
324
345
|
updateDisplay() {
|
|
325
346
|
this.displayVersion += 1;
|
|
326
347
|
let hasContent = false;
|
|
@@ -330,19 +351,19 @@ export class ToolExecutionComponent extends Container {
|
|
|
330
351
|
renderContainer.clear();
|
|
331
352
|
const callRenderer = this.getCallRenderer();
|
|
332
353
|
if (!callRenderer) {
|
|
333
|
-
renderContainer.addChild(this.createCallFallback());
|
|
354
|
+
renderContainer.addChild(this.createResultRegion(this.createCallFallback()));
|
|
334
355
|
hasContent = true;
|
|
335
356
|
}
|
|
336
357
|
else {
|
|
337
358
|
try {
|
|
338
359
|
const component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));
|
|
339
360
|
this.callRendererComponent = component;
|
|
340
|
-
renderContainer.addChild(component);
|
|
361
|
+
renderContainer.addChild(this.createResultRegion(component));
|
|
341
362
|
hasContent = true;
|
|
342
363
|
}
|
|
343
364
|
catch {
|
|
344
365
|
this.callRendererComponent = undefined;
|
|
345
|
-
renderContainer.addChild(this.createCallFallback());
|
|
366
|
+
renderContainer.addChild(this.createResultRegion(this.createCallFallback()));
|
|
346
367
|
hasContent = true;
|
|
347
368
|
}
|
|
348
369
|
}
|
|
@@ -351,7 +372,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
351
372
|
if (!resultRenderer) {
|
|
352
373
|
const component = this.createResultFallback();
|
|
353
374
|
if (component) {
|
|
354
|
-
renderContainer.addChild(component);
|
|
375
|
+
renderContainer.addChild(this.createResultRegion(component));
|
|
355
376
|
hasContent = true;
|
|
356
377
|
}
|
|
357
378
|
}
|
|
@@ -359,14 +380,14 @@ export class ToolExecutionComponent extends Container {
|
|
|
359
380
|
try {
|
|
360
381
|
const component = resultRenderer({ content: this.result.content, details: this.result.details }, { expanded: this.expanded, isPartial: this.isPartial }, theme, this.getRenderContext(this.resultRendererComponent));
|
|
361
382
|
this.resultRendererComponent = component;
|
|
362
|
-
renderContainer.addChild(component);
|
|
383
|
+
renderContainer.addChild(this.createResultRegion(component));
|
|
363
384
|
hasContent = true;
|
|
364
385
|
}
|
|
365
386
|
catch {
|
|
366
387
|
this.resultRendererComponent = undefined;
|
|
367
388
|
const component = this.createResultFallback();
|
|
368
389
|
if (component) {
|
|
369
|
-
renderContainer.addChild(component);
|
|
390
|
+
renderContainer.addChild(this.createResultRegion(component));
|
|
370
391
|
hasContent = true;
|
|
371
392
|
}
|
|
372
393
|
}
|
|
@@ -391,7 +412,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
391
412
|
for (let i = 0; i < imageBlocks.length; i++) {
|
|
392
413
|
const img = imageBlocks[i];
|
|
393
414
|
if (caps.images && this.showImages && img.data && img.mimeType) {
|
|
394
|
-
const
|
|
415
|
+
const cached = this.convertedImages.get(i);
|
|
416
|
+
const converted = cached?.sourceData === img.data && cached.sourceMimeType === img.mimeType ? cached : undefined;
|
|
395
417
|
const imageData = converted?.data ?? img.data;
|
|
396
418
|
const imageMimeType = converted?.mimeType ?? img.mimeType;
|
|
397
419
|
if (caps.images === "kitty" && imageMimeType !== "image/png")
|