@tomsun28/pizza 0.0.9 → 0.1.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/README.md +20 -143
- package/README.zh-CN.md +36 -0
- package/dist/bun/cli.d.ts +2 -0
- package/dist/bun/cli.js +6 -0
- package/dist/bun/register-bedrock.d.ts +1 -0
- package/dist/bun/register-bedrock.js +3 -0
- package/dist/cli/args.d.ts +48 -0
- package/dist/cli/args.js +330 -0
- package/dist/cli/config-selector.d.ts +13 -0
- package/dist/cli/config-selector.js +30 -0
- package/dist/cli/file-processor.d.ts +14 -0
- package/dist/cli/file-processor.js +82 -0
- package/dist/cli/initial-message.d.ts +17 -0
- package/dist/cli/initial-message.js +21 -0
- package/dist/cli/list-models.d.ts +8 -0
- package/dist/cli/list-models.js +96 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +68 -0
- package/dist/config.d.ts +79 -0
- package/dist/config.js +223 -0
- package/dist/core/agent/index.d.ts +6 -0
- package/dist/core/agent/index.js +6 -0
- package/dist/core/agent/types.d.ts +202 -0
- package/dist/core/agent/types.js +51 -0
- package/dist/core/auth-storage.d.ts +135 -0
- package/dist/core/auth-storage.js +417 -0
- package/dist/core/bash-executor.d.ts +31 -0
- package/dist/core/bash-executor.js +107 -0
- package/dist/core/compaction/branch-summarization.d.ts +87 -0
- package/dist/core/compaction/branch-summarization.js +242 -0
- package/dist/core/compaction/compaction-engine.d.ts +40 -0
- package/dist/core/compaction/compaction-engine.js +292 -0
- package/dist/core/compaction/compaction.d.ts +106 -0
- package/dist/core/compaction/compaction.js +295 -0
- package/dist/core/compaction/index.d.ts +7 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/utils.d.ts +37 -0
- package/dist/core/compaction/utils.js +152 -0
- package/dist/core/defaults.d.ts +2 -0
- package/dist/core/defaults.js +1 -0
- package/dist/core/diagnostics.d.ts +14 -0
- package/dist/core/diagnostics.js +1 -0
- package/dist/core/event-bus.d.ts +8 -0
- package/dist/core/event-bus.js +24 -0
- package/dist/core/event-store/events.d.ts +465 -0
- package/dist/core/event-store/events.js +6 -0
- package/dist/core/event-store/index.d.ts +10 -0
- package/dist/core/event-store/index.js +10 -0
- package/dist/core/event-store/sqlite-store.d.ts +27 -0
- package/dist/core/event-store/sqlite-store.js +275 -0
- package/dist/core/event-store/store.d.ts +91 -0
- package/dist/core/event-store/store.js +7 -0
- package/dist/core/event-store/thread-scoped-store.d.ts +29 -0
- package/dist/core/event-store/thread-scoped-store.js +50 -0
- package/dist/core/event-store/types.d.ts +70 -0
- package/dist/core/event-store/types.js +7 -0
- package/dist/core/event-store/workspace.d.ts +37 -0
- package/dist/core/event-store/workspace.js +71 -0
- package/dist/core/exec.d.ts +28 -0
- package/dist/core/exec.js +74 -0
- package/dist/core/export-html/ansi-to-html.d.ts +21 -0
- package/dist/core/export-html/ansi-to-html.js +248 -0
- package/dist/core/export-html/index.d.ts +29 -0
- package/dist/core/export-html/index.js +186 -0
- package/dist/core/export-html/template.css +1017 -0
- package/dist/core/export-html/template.html +55 -0
- package/dist/core/export-html/template.js +1742 -0
- package/dist/core/export-html/tool-renderer.d.ts +39 -0
- package/dist/core/export-html/tool-renderer.js +94 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +6 -0
- package/dist/core/extensions/index.d.ts +12 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/loader.d.ts +24 -0
- package/dist/core/extensions/loader.js +492 -0
- package/dist/core/extensions/runner.d.ts +167 -0
- package/dist/core/extensions/runner.js +898 -0
- package/dist/core/extensions/session-context.d.ts +67 -0
- package/dist/core/extensions/session-context.js +272 -0
- package/dist/core/extensions/types.d.ts +1147 -0
- package/dist/core/extensions/types.js +44 -0
- package/dist/core/extensions/wrapper.d.ts +19 -0
- package/dist/core/extensions/wrapper.js +21 -0
- package/dist/core/footer-data-provider.d.ts +47 -0
- package/dist/core/footer-data-provider.js +321 -0
- package/dist/core/goal/index.d.ts +3 -0
- package/dist/core/goal/index.js +1 -0
- package/dist/core/goal/scheduler.d.ts +83 -0
- package/dist/core/goal/scheduler.js +154 -0
- package/dist/core/goal/types.d.ts +182 -0
- package/dist/core/goal/types.js +11 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.js +8 -0
- package/dist/core/intent/classifier.d.ts +53 -0
- package/dist/core/intent/classifier.js +353 -0
- package/dist/core/intent/index.d.ts +8 -0
- package/dist/core/intent/index.js +8 -0
- package/dist/core/intent/tool-adapter.d.ts +31 -0
- package/dist/core/intent/tool-adapter.js +168 -0
- package/dist/core/intent/types.d.ts +71 -0
- package/dist/core/intent/types.js +6 -0
- package/dist/core/keybindings.d.ts +297 -0
- package/dist/core/keybindings.js +250 -0
- package/dist/core/messages.d.ts +30 -0
- package/dist/core/messages.js +134 -0
- package/dist/core/model-registry.d.ts +131 -0
- package/dist/core/model-registry.js +634 -0
- package/dist/core/model-resolver.d.ts +109 -0
- package/dist/core/model-resolver.js +486 -0
- package/dist/core/output-guard.d.ts +5 -0
- package/dist/core/output-guard.js +58 -0
- package/dist/core/package-manager.d.ts +196 -0
- package/dist/core/package-manager.js +1873 -0
- package/dist/core/projection/boundary-inferrer.d.ts +58 -0
- package/dist/core/projection/boundary-inferrer.js +122 -0
- package/dist/core/projection/event-to-message.d.ts +35 -0
- package/dist/core/projection/event-to-message.js +253 -0
- package/dist/core/projection/goal-projection.d.ts +67 -0
- package/dist/core/projection/goal-projection.js +339 -0
- package/dist/core/projection/index.d.ts +13 -0
- package/dist/core/projection/index.js +13 -0
- package/dist/core/projection/session-manager.d.ts +100 -0
- package/dist/core/projection/session-manager.js +331 -0
- package/dist/core/projection/session-projection.d.ts +58 -0
- package/dist/core/projection/session-projection.js +257 -0
- package/dist/core/projection/task-history.d.ts +13 -0
- package/dist/core/projection/task-history.js +61 -0
- package/dist/core/projection/timeline-projection.d.ts +82 -0
- package/dist/core/projection/timeline-projection.js +276 -0
- package/dist/core/projection/types.d.ts +69 -0
- package/dist/core/projection/types.js +6 -0
- package/dist/core/prompt-templates.d.ts +51 -0
- package/dist/core/prompt-templates.js +249 -0
- package/dist/core/resolve-config-value.d.ts +22 -0
- package/dist/core/resolve-config-value.js +125 -0
- package/dist/core/resource-loader.d.ts +193 -0
- package/dist/core/resource-loader.js +685 -0
- package/dist/core/runtime/ai-client.d.ts +12 -0
- package/dist/core/runtime/ai-client.js +153 -0
- package/dist/core/runtime/checkpoint.d.ts +12 -0
- package/dist/core/runtime/checkpoint.js +78 -0
- package/dist/core/runtime/index.d.ts +12 -0
- package/dist/core/runtime/index.js +12 -0
- package/dist/core/runtime/llm-types.d.ts +99 -0
- package/dist/core/runtime/llm-types.js +6 -0
- package/dist/core/runtime/local-runtime.d.ts +23 -0
- package/dist/core/runtime/local-runtime.js +59 -0
- package/dist/core/runtime/policies.d.ts +72 -0
- package/dist/core/runtime/policies.js +37 -0
- package/dist/core/runtime/reactor.d.ts +213 -0
- package/dist/core/runtime/reactor.js +992 -0
- package/dist/core/runtime/runtime.d.ts +191 -0
- package/dist/core/runtime/runtime.js +449 -0
- package/dist/core/runtime/types.d.ts +42 -0
- package/dist/core/runtime/types.js +1 -0
- package/dist/core/sdk.d.ts +12 -0
- package/dist/core/sdk.js +10 -0
- package/dist/core/session-context-builder.d.ts +9 -0
- package/dist/core/session-context-builder.js +87 -0
- package/dist/core/session-cwd.d.ts +18 -0
- package/dist/core/session-cwd.js +36 -0
- package/dist/core/session-facade-factory.d.ts +79 -0
- package/dist/core/session-facade-factory.js +460 -0
- package/dist/core/session-facade.d.ts +57 -0
- package/dist/core/session-facade.js +91 -0
- package/dist/core/session-listing.d.ts +30 -0
- package/dist/core/session-listing.js +168 -0
- package/dist/core/session-reader.d.ts +19 -0
- package/dist/core/session-reader.js +101 -0
- package/dist/core/session-ref.d.ts +7 -0
- package/dist/core/session-ref.js +25 -0
- package/dist/core/session-services.d.ts +51 -0
- package/dist/core/session-services.js +90 -0
- package/dist/core/session-stats.d.ts +43 -0
- package/dist/core/session-stats.js +41 -0
- package/dist/core/settings-manager.d.ts +236 -0
- package/dist/core/settings-manager.js +706 -0
- package/dist/core/skill-block-parser.d.ts +12 -0
- package/dist/core/skill-block-parser.js +15 -0
- package/dist/core/skills.d.ts +59 -0
- package/dist/core/skills.js +408 -0
- package/dist/core/slash-commands.d.ts +13 -0
- package/dist/core/slash-commands.js +17 -0
- package/dist/core/source-info.d.ts +17 -0
- package/dist/core/source-info.js +18 -0
- package/dist/core/system-prompt.d.ts +27 -0
- package/dist/core/system-prompt.js +179 -0
- package/dist/core/timings.d.ts +7 -0
- package/dist/core/timings.js +30 -0
- package/dist/core/tools/bash.d.ts +95 -0
- package/dist/core/tools/bash.js +513 -0
- package/dist/core/tools/builtin-commands.d.ts +75 -0
- package/dist/core/tools/builtin-commands.js +503 -0
- package/dist/core/tools/compat-commands.d.ts +12 -0
- package/dist/core/tools/compat-commands.js +1280 -0
- package/dist/core/tools/edit-diff.d.ts +59 -0
- package/dist/core/tools/edit-diff.js +263 -0
- package/dist/core/tools/edit.d.ts +49 -0
- package/dist/core/tools/edit.js +340 -0
- package/dist/core/tools/file-mutation-queue.d.ts +5 -0
- package/dist/core/tools/file-mutation-queue.js +36 -0
- package/dist/core/tools/find.d.ts +34 -0
- package/dist/core/tools/find.js +459 -0
- package/dist/core/tools/grep.d.ts +36 -0
- package/dist/core/tools/grep.js +422 -0
- package/dist/core/tools/index.d.ts +70 -0
- package/dist/core/tools/index.js +129 -0
- package/dist/core/tools/line-anchors.d.ts +33 -0
- package/dist/core/tools/line-anchors.js +151 -0
- package/dist/core/tools/ls.d.ts +36 -0
- package/dist/core/tools/ls.js +268 -0
- package/dist/core/tools/path-utils.d.ts +7 -0
- package/dist/core/tools/path-utils.js +80 -0
- package/dist/core/tools/read.d.ts +35 -0
- package/dist/core/tools/read.js +244 -0
- package/dist/core/tools/render-utils.d.ts +20 -0
- package/dist/core/tools/render-utils.js +48 -0
- package/dist/core/tools/session-split.d.ts +9 -0
- package/dist/core/tools/session-split.js +77 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +13 -0
- package/dist/core/tools/tool-definition-wrapper.js +32 -0
- package/dist/core/tools/truncate.d.ts +69 -0
- package/dist/core/tools/truncate.js +204 -0
- package/dist/core/tools/write.d.ts +25 -0
- package/dist/core/tools/write.js +211 -0
- package/dist/core/types/session-types.d.ts +123 -0
- package/dist/core/types/session-types.js +8 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +38 -0
- package/dist/main.d.ts +11 -2
- package/dist/main.js +577 -149
- package/dist/modes/event-mapper.d.ts +115 -0
- package/dist/modes/event-mapper.js +200 -0
- package/dist/modes/gui/server.d.ts +14 -0
- package/dist/modes/gui/server.js +1032 -0
- package/dist/modes/index.d.ts +10 -0
- package/dist/modes/index.js +9 -0
- package/dist/modes/interactive/assets/clankolas.png +0 -0
- package/dist/modes/interactive/components/armin.d.ts +33 -0
- package/dist/modes/interactive/components/armin.js +328 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +19 -0
- package/dist/modes/interactive/components/assistant-message.js +115 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +33 -0
- package/dist/modes/interactive/components/bash-execution.js +169 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts +15 -0
- package/dist/modes/interactive/components/bordered-loader.js +50 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts +15 -0
- package/dist/modes/interactive/components/branch-summary-message.js +41 -0
- package/dist/modes/interactive/components/brand-header.d.ts +33 -0
- package/dist/modes/interactive/components/brand-header.js +235 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +15 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +42 -0
- package/dist/modes/interactive/components/config-selector.d.ts +70 -0
- package/dist/modes/interactive/components/config-selector.js +469 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts +13 -0
- package/dist/modes/interactive/components/countdown-timer.js +27 -0
- package/dist/modes/interactive/components/custom-editor.d.ts +27 -0
- package/dist/modes/interactive/components/custom-editor.js +94 -0
- package/dist/modes/interactive/components/custom-message.d.ts +19 -0
- package/dist/modes/interactive/components/custom-message.js +73 -0
- package/dist/modes/interactive/components/daxnuts.d.ts +22 -0
- package/dist/modes/interactive/components/daxnuts.js +137 -0
- package/dist/modes/interactive/components/diff.d.ts +11 -0
- package/dist/modes/interactive/components/diff.js +132 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +14 -0
- package/dist/modes/interactive/components/dynamic-border.js +19 -0
- package/dist/modes/interactive/components/earendil-announcement.d.ts +4 -0
- package/dist/modes/interactive/components/earendil-announcement.js +39 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +19 -0
- package/dist/modes/interactive/components/extension-editor.js +105 -0
- package/dist/modes/interactive/components/extension-input.d.ts +22 -0
- package/dist/modes/interactive/components/extension-input.js +54 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +23 -0
- package/dist/modes/interactive/components/extension-selector.js +70 -0
- package/dist/modes/interactive/components/footer.d.ts +55 -0
- package/dist/modes/interactive/components/footer.js +207 -0
- package/dist/modes/interactive/components/index.d.ts +31 -0
- package/dist/modes/interactive/components/index.js +32 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts +7 -0
- package/dist/modes/interactive/components/keybinding-hints.js +21 -0
- package/dist/modes/interactive/components/login-dialog.d.ts +41 -0
- package/dist/modes/interactive/components/login-dialog.js +138 -0
- package/dist/modes/interactive/components/model-selector.d.ts +32 -0
- package/dist/modes/interactive/components/model-selector.js +209 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts +18 -0
- package/dist/modes/interactive/components/oauth-selector.js +91 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +57 -0
- package/dist/modes/interactive/components/settings-selector.js +299 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts +9 -0
- package/dist/modes/interactive/components/show-images-selector.js +37 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +16 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +44 -0
- package/dist/modes/interactive/components/theme-selector.d.ts +10 -0
- package/dist/modes/interactive/components/theme-selector.js +47 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +10 -0
- package/dist/modes/interactive/components/thinking-selector.js +50 -0
- package/dist/modes/interactive/components/timeline-view.d.ts +31 -0
- package/dist/modes/interactive/components/timeline-view.js +81 -0
- package/dist/modes/interactive/components/tool-execution.d.ts +64 -0
- package/dist/modes/interactive/components/tool-execution.js +305 -0
- package/dist/modes/interactive/components/tree-selector.d.ts +88 -0
- package/dist/modes/interactive/components/tree-selector.js +1072 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +29 -0
- package/dist/modes/interactive/components/user-message-selector.js +110 -0
- package/dist/modes/interactive/components/user-message.d.ts +9 -0
- package/dist/modes/interactive/components/user-message.js +27 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts +23 -0
- package/dist/modes/interactive/components/visual-truncate.js +32 -0
- package/dist/modes/interactive/interactive-mode.d.ts +394 -0
- package/dist/modes/interactive/interactive-mode.js +4116 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +84 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.d.ts +80 -0
- package/dist/modes/interactive/theme/theme.js +973 -0
- package/dist/modes/print-mode.d.ts +27 -0
- package/dist/modes/print-mode.js +102 -0
- package/dist/modes/rpc/jsonl.d.ts +16 -0
- package/dist/modes/rpc/jsonl.js +48 -0
- package/dist/modes/rpc/rpc-client.d.ts +219 -0
- package/dist/modes/rpc/rpc-client.js +405 -0
- package/dist/modes/rpc/rpc-mode.d.ts +19 -0
- package/dist/modes/rpc/rpc-mode.js +381 -0
- package/dist/modes/rpc/rpc-types.d.ts +406 -0
- package/dist/modes/rpc/rpc-types.js +7 -0
- package/dist/package-manager-cli.d.ts +3 -0
- package/dist/package-manager-cli.js +233 -0
- package/dist/utils/changelog.d.ts +20 -0
- package/dist/utils/changelog.js +86 -0
- package/dist/utils/child-process.d.ts +10 -0
- package/dist/utils/child-process.js +77 -0
- package/dist/utils/clipboard-image.d.ts +10 -0
- package/dist/utils/clipboard-image.js +244 -0
- package/dist/utils/clipboard-native.d.ts +7 -0
- package/dist/utils/clipboard-native.js +13 -0
- package/dist/utils/clipboard.d.ts +1 -0
- package/dist/utils/clipboard.js +77 -0
- package/dist/utils/exif-orientation.d.ts +4 -0
- package/dist/utils/exif-orientation.js +157 -0
- package/dist/utils/frontmatter.d.ts +7 -0
- package/dist/utils/frontmatter.js +25 -0
- package/dist/utils/git.d.ts +25 -0
- package/dist/utils/git.js +162 -0
- package/dist/utils/image-convert.d.ts +8 -0
- package/dist/utils/image-convert.js +38 -0
- package/dist/utils/image-resize.d.ts +35 -0
- package/dist/utils/image-resize.js +136 -0
- package/dist/utils/mime.d.ts +1 -0
- package/dist/utils/mime.js +25 -0
- package/dist/utils/path-shims.d.ts +1 -0
- package/dist/utils/path-shims.js +90 -0
- package/dist/utils/paths.d.ts +6 -0
- package/dist/utils/paths.js +18 -0
- package/dist/utils/photon.d.ts +20 -0
- package/dist/utils/photon.js +120 -0
- package/dist/utils/shell.d.ts +29 -0
- package/dist/utils/shell.js +189 -0
- package/dist/utils/sleep.d.ts +4 -0
- package/dist/utils/sleep.js +16 -0
- package/dist/utils/tools-manager.d.ts +3 -0
- package/dist/utils/tools-manager.js +101 -0
- package/dist/vendor/bin/darwin-arm64/fd +0 -0
- package/dist/vendor/bin/darwin-arm64/rg +0 -0
- package/dist/vendor/bin/darwin-x64/fd +0 -0
- package/dist/vendor/bin/darwin-x64/rg +0 -0
- package/dist/vendor/bin/linux-arm64/fd +0 -0
- package/dist/vendor/bin/linux-arm64/rg +0 -0
- package/dist/vendor/bin/linux-x64/fd +0 -0
- package/dist/vendor/bin/linux-x64/rg +0 -0
- package/dist/vendor/bin/win32-arm64/fd.exe +0 -0
- package/dist/vendor/bin/win32-arm64/rg.exe +0 -0
- package/dist/vendor/bin/win32-x64/fd.exe +0 -0
- package/dist/vendor/bin/win32-x64/rg.exe +0 -0
- package/package.json +90 -26
- package/dist/extension/core.d.ts +0 -69
- package/dist/extension/core.js +0 -270
- package/dist/extension/core.js.map +0 -1
- package/dist/extension/index.d.ts +0 -25
- package/dist/extension/index.js +0 -303
- package/dist/extension/index.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/themes/pizza.json +0 -87
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component for displaying bash command execution with streaming output.
|
|
3
|
+
*/
|
|
4
|
+
import { Container, Loader, Spacer, Text } from "@earendil-works/pi-tui";
|
|
5
|
+
import stripAnsi from "strip-ansi";
|
|
6
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail, } from "../../../core/tools/truncate.js";
|
|
7
|
+
import { theme } from "../theme/theme.js";
|
|
8
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
9
|
+
import { keyHint, keyText } from "./keybinding-hints.js";
|
|
10
|
+
import { truncateToVisualLines } from "./visual-truncate.js";
|
|
11
|
+
// Preview line limit when not expanded (matches tool execution behavior)
|
|
12
|
+
const PREVIEW_LINES = 20;
|
|
13
|
+
export class BashExecutionComponent extends Container {
|
|
14
|
+
constructor(command, ui, excludeFromContext = false) {
|
|
15
|
+
super();
|
|
16
|
+
this.outputLines = [];
|
|
17
|
+
this.status = "running";
|
|
18
|
+
this.exitCode = undefined;
|
|
19
|
+
this.expanded = false;
|
|
20
|
+
this.command = command;
|
|
21
|
+
// Use dim border for excluded-from-context commands (!! prefix)
|
|
22
|
+
const colorKey = excludeFromContext ? "dim" : "bashMode";
|
|
23
|
+
const borderColor = (str) => theme.fg(colorKey, str);
|
|
24
|
+
// Add spacer
|
|
25
|
+
this.addChild(new Spacer(1));
|
|
26
|
+
// Top border
|
|
27
|
+
this.addChild(new DynamicBorder(borderColor));
|
|
28
|
+
// Content container (holds dynamic content between borders)
|
|
29
|
+
this.contentContainer = new Container();
|
|
30
|
+
this.addChild(this.contentContainer);
|
|
31
|
+
// Command header
|
|
32
|
+
const header = new Text(theme.fg(colorKey, theme.bold(`$ ${command}`)), 1, 0);
|
|
33
|
+
this.contentContainer.addChild(header);
|
|
34
|
+
// Loader
|
|
35
|
+
this.loader = new Loader(ui, (spinner) => theme.fg(colorKey, spinner), (text) => theme.fg("muted", text), `Running... (${keyText("tui.select.cancel")} to cancel)`);
|
|
36
|
+
this.contentContainer.addChild(this.loader);
|
|
37
|
+
// Bottom border
|
|
38
|
+
this.addChild(new DynamicBorder(borderColor));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Set whether the output is expanded (shows full output) or collapsed (preview only).
|
|
42
|
+
*/
|
|
43
|
+
setExpanded(expanded) {
|
|
44
|
+
this.expanded = expanded;
|
|
45
|
+
this.updateDisplay();
|
|
46
|
+
}
|
|
47
|
+
invalidate() {
|
|
48
|
+
super.invalidate();
|
|
49
|
+
this.updateDisplay();
|
|
50
|
+
}
|
|
51
|
+
appendOutput(chunk) {
|
|
52
|
+
// Strip ANSI codes and normalize line endings
|
|
53
|
+
// Note: binary data is already sanitized in tui-renderer.ts executeBashCommand
|
|
54
|
+
const clean = stripAnsi(chunk).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
55
|
+
// Append to output lines
|
|
56
|
+
const newLines = clean.split("\n");
|
|
57
|
+
if (this.outputLines.length > 0 && newLines.length > 0) {
|
|
58
|
+
// Append first chunk to last line (incomplete line continuation)
|
|
59
|
+
this.outputLines[this.outputLines.length - 1] += newLines[0];
|
|
60
|
+
this.outputLines.push(...newLines.slice(1));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.outputLines.push(...newLines);
|
|
64
|
+
}
|
|
65
|
+
this.updateDisplay();
|
|
66
|
+
}
|
|
67
|
+
setComplete(exitCode, cancelled, truncationResult, fullOutputPath) {
|
|
68
|
+
this.exitCode = exitCode;
|
|
69
|
+
this.status = cancelled
|
|
70
|
+
? "cancelled"
|
|
71
|
+
: exitCode !== 0 && exitCode !== undefined && exitCode !== null
|
|
72
|
+
? "error"
|
|
73
|
+
: "complete";
|
|
74
|
+
this.truncationResult = truncationResult;
|
|
75
|
+
this.fullOutputPath = fullOutputPath;
|
|
76
|
+
// Stop loader
|
|
77
|
+
this.loader.stop();
|
|
78
|
+
this.updateDisplay();
|
|
79
|
+
}
|
|
80
|
+
updateDisplay() {
|
|
81
|
+
// Apply truncation for LLM context limits (same limits as cli tool)
|
|
82
|
+
const fullOutput = this.outputLines.join("\n");
|
|
83
|
+
const contextTruncation = truncateTail(fullOutput, {
|
|
84
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
85
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
86
|
+
});
|
|
87
|
+
// Get the lines to potentially display (after context truncation)
|
|
88
|
+
const availableLines = contextTruncation.content ? contextTruncation.content.split("\n") : [];
|
|
89
|
+
// Apply preview truncation based on expanded state
|
|
90
|
+
const previewLogicalLines = availableLines.slice(-PREVIEW_LINES);
|
|
91
|
+
const hiddenLineCount = availableLines.length - previewLogicalLines.length;
|
|
92
|
+
// Rebuild content container
|
|
93
|
+
this.contentContainer.clear();
|
|
94
|
+
// Command header
|
|
95
|
+
const header = new Text(theme.fg("bashMode", theme.bold(`$ ${this.command}`)), 1, 0);
|
|
96
|
+
this.contentContainer.addChild(header);
|
|
97
|
+
// Output
|
|
98
|
+
if (availableLines.length > 0) {
|
|
99
|
+
if (this.expanded) {
|
|
100
|
+
// Show all lines
|
|
101
|
+
const displayText = availableLines.map((line) => theme.fg("muted", line)).join("\n");
|
|
102
|
+
this.contentContainer.addChild(new Text(`\n${displayText}`, 1, 0));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Use shared visual truncation utility with width-aware caching
|
|
106
|
+
const styledOutput = previewLogicalLines.map((line) => theme.fg("muted", line)).join("\n");
|
|
107
|
+
const styledInput = `\n${styledOutput}`;
|
|
108
|
+
let cachedWidth;
|
|
109
|
+
let cachedLines;
|
|
110
|
+
this.contentContainer.addChild({
|
|
111
|
+
render: (width) => {
|
|
112
|
+
if (cachedLines === undefined || cachedWidth !== width) {
|
|
113
|
+
const result = truncateToVisualLines(styledInput, PREVIEW_LINES, width, 1);
|
|
114
|
+
cachedLines = result.visualLines;
|
|
115
|
+
cachedWidth = width;
|
|
116
|
+
}
|
|
117
|
+
return cachedLines ?? [];
|
|
118
|
+
},
|
|
119
|
+
invalidate: () => {
|
|
120
|
+
cachedWidth = undefined;
|
|
121
|
+
cachedLines = undefined;
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Loader or status
|
|
127
|
+
if (this.status === "running") {
|
|
128
|
+
this.contentContainer.addChild(this.loader);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const statusParts = [];
|
|
132
|
+
// Show how many lines are hidden (collapsed preview)
|
|
133
|
+
if (hiddenLineCount > 0) {
|
|
134
|
+
if (this.expanded) {
|
|
135
|
+
statusParts.push(`(${keyHint("app.tools.expand", "to collapse")})`);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
statusParts.push(`${theme.fg("muted", `... ${hiddenLineCount} more lines`)} (${keyHint("app.tools.expand", "to expand")})`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (this.status === "cancelled") {
|
|
142
|
+
statusParts.push(theme.fg("warning", "(cancelled)"));
|
|
143
|
+
}
|
|
144
|
+
else if (this.status === "error") {
|
|
145
|
+
statusParts.push(theme.fg("error", `(exit ${this.exitCode})`));
|
|
146
|
+
}
|
|
147
|
+
// Add truncation warning (context truncation, not preview truncation)
|
|
148
|
+
const wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;
|
|
149
|
+
if (wasTruncated && this.fullOutputPath) {
|
|
150
|
+
statusParts.push(theme.fg("warning", `Output truncated. Full output: ${this.fullOutputPath}`));
|
|
151
|
+
}
|
|
152
|
+
if (statusParts.length > 0) {
|
|
153
|
+
this.contentContainer.addChild(new Text(`\n${statusParts.join("\n")}`, 1, 0));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the raw output for creating BashExecutionMessage.
|
|
159
|
+
*/
|
|
160
|
+
getOutput() {
|
|
161
|
+
return this.outputLines.join("\n");
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get the command that was executed.
|
|
165
|
+
*/
|
|
166
|
+
getCommand() {
|
|
167
|
+
return this.command;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Container, type TUI } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { Theme } from "../theme/theme.js";
|
|
3
|
+
/** Loader wrapped with borders for extension UI */
|
|
4
|
+
export declare class BorderedLoader extends Container {
|
|
5
|
+
private loader;
|
|
6
|
+
private cancellable;
|
|
7
|
+
private signalController?;
|
|
8
|
+
constructor(tui: TUI, theme: Theme, message: string, options?: {
|
|
9
|
+
cancellable?: boolean;
|
|
10
|
+
});
|
|
11
|
+
get signal(): AbortSignal;
|
|
12
|
+
set onAbort(fn: (() => void) | undefined);
|
|
13
|
+
handleInput(data: string): void;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CancellableLoader, Container, Loader, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
3
|
+
import { keyHint } from "./keybinding-hints.js";
|
|
4
|
+
/** Loader wrapped with borders for extension UI */
|
|
5
|
+
export class BorderedLoader extends Container {
|
|
6
|
+
constructor(tui, theme, message, options) {
|
|
7
|
+
super();
|
|
8
|
+
this.cancellable = options?.cancellable ?? true;
|
|
9
|
+
const borderColor = (s) => theme.fg("border", s);
|
|
10
|
+
this.addChild(new DynamicBorder(borderColor));
|
|
11
|
+
if (this.cancellable) {
|
|
12
|
+
this.loader = new CancellableLoader(tui, (s) => theme.fg("accent", s), (s) => theme.fg("muted", s), message);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this.signalController = new AbortController();
|
|
16
|
+
this.loader = new Loader(tui, (s) => theme.fg("accent", s), (s) => theme.fg("muted", s), message);
|
|
17
|
+
}
|
|
18
|
+
this.addChild(this.loader);
|
|
19
|
+
if (this.cancellable) {
|
|
20
|
+
this.addChild(new Spacer(1));
|
|
21
|
+
this.addChild(new Text(keyHint("tui.select.cancel", "cancel"), 1, 0));
|
|
22
|
+
}
|
|
23
|
+
this.addChild(new Spacer(1));
|
|
24
|
+
this.addChild(new DynamicBorder(borderColor));
|
|
25
|
+
}
|
|
26
|
+
get signal() {
|
|
27
|
+
if (this.cancellable) {
|
|
28
|
+
return this.loader.signal;
|
|
29
|
+
}
|
|
30
|
+
return this.signalController?.signal ?? new AbortController().signal;
|
|
31
|
+
}
|
|
32
|
+
set onAbort(fn) {
|
|
33
|
+
if (this.cancellable) {
|
|
34
|
+
this.loader.onAbort = fn;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
handleInput(data) {
|
|
38
|
+
if (this.cancellable) {
|
|
39
|
+
this.loader.handleInput(data);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
dispose() {
|
|
43
|
+
if ("dispose" in this.loader && typeof this.loader.dispose === "function") {
|
|
44
|
+
this.loader.dispose();
|
|
45
|
+
}
|
|
46
|
+
else if ("stop" in this.loader && typeof this.loader.stop === "function") {
|
|
47
|
+
this.loader.stop();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Box, type MarkdownTheme } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { BranchSummaryMessage } from "../../../core/messages.js";
|
|
3
|
+
/**
|
|
4
|
+
* Component that renders a branch summary message with collapsed/expanded state.
|
|
5
|
+
* Uses same background color as custom messages for visual consistency.
|
|
6
|
+
*/
|
|
7
|
+
export declare class BranchSummaryMessageComponent extends Box {
|
|
8
|
+
private expanded;
|
|
9
|
+
private message;
|
|
10
|
+
private markdownTheme;
|
|
11
|
+
constructor(message: BranchSummaryMessage, markdownTheme?: MarkdownTheme);
|
|
12
|
+
setExpanded(expanded: boolean): void;
|
|
13
|
+
invalidate(): void;
|
|
14
|
+
private updateDisplay;
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Box, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
|
+
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
|
+
import { keyText } from "./keybinding-hints.js";
|
|
4
|
+
/**
|
|
5
|
+
* Component that renders a branch summary message with collapsed/expanded state.
|
|
6
|
+
* Uses same background color as custom messages for visual consistency.
|
|
7
|
+
*/
|
|
8
|
+
export class BranchSummaryMessageComponent extends Box {
|
|
9
|
+
constructor(message, markdownTheme = getMarkdownTheme()) {
|
|
10
|
+
super(1, 1, (t) => theme.bg("customMessageBg", t));
|
|
11
|
+
this.expanded = false;
|
|
12
|
+
this.message = message;
|
|
13
|
+
this.markdownTheme = markdownTheme;
|
|
14
|
+
this.updateDisplay();
|
|
15
|
+
}
|
|
16
|
+
setExpanded(expanded) {
|
|
17
|
+
this.expanded = expanded;
|
|
18
|
+
this.updateDisplay();
|
|
19
|
+
}
|
|
20
|
+
invalidate() {
|
|
21
|
+
super.invalidate();
|
|
22
|
+
this.updateDisplay();
|
|
23
|
+
}
|
|
24
|
+
updateDisplay() {
|
|
25
|
+
this.clear();
|
|
26
|
+
const label = theme.fg("customMessageLabel", `\x1b[1m[branch]\x1b[22m`);
|
|
27
|
+
this.addChild(new Text(label, 0, 0));
|
|
28
|
+
this.addChild(new Spacer(1));
|
|
29
|
+
if (this.expanded) {
|
|
30
|
+
const header = "**Branch Summary**\n\n";
|
|
31
|
+
this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
|
|
32
|
+
color: (text) => theme.fg("customMessageText", text),
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.addChild(new Text(theme.fg("customMessageText", "Branch summary (") +
|
|
37
|
+
theme.fg("dim", keyText("app.tools.expand")) +
|
|
38
|
+
theme.fg("customMessageText", " to expand)"), 0, 0));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { TaskHistoryItem } from "../../../core/projection/task-history.js";
|
|
3
|
+
export declare class BrandHeaderComponent implements Component {
|
|
4
|
+
private readonly appName;
|
|
5
|
+
private readonly version;
|
|
6
|
+
private expanded;
|
|
7
|
+
private cachedWidth?;
|
|
8
|
+
private cachedExpanded?;
|
|
9
|
+
private cachedLines?;
|
|
10
|
+
private taskHistory;
|
|
11
|
+
constructor(appName: string, version: string, expanded?: boolean);
|
|
12
|
+
setExpanded(expanded: boolean): void;
|
|
13
|
+
setTaskHistory(taskHistory: TaskHistoryItem[]): void;
|
|
14
|
+
invalidate(): void;
|
|
15
|
+
render(width: number): string[];
|
|
16
|
+
private renderFull;
|
|
17
|
+
private renderLogoBody;
|
|
18
|
+
private taskPanelRows;
|
|
19
|
+
private formatTaskLine;
|
|
20
|
+
private taskStatusLabel;
|
|
21
|
+
private renderBoxedCompact;
|
|
22
|
+
private renderTiny;
|
|
23
|
+
private expandedShortcutLines;
|
|
24
|
+
private shortcutHints;
|
|
25
|
+
private compactShortcuts;
|
|
26
|
+
private brandText;
|
|
27
|
+
private brandLabel;
|
|
28
|
+
private displayName;
|
|
29
|
+
private splitLine;
|
|
30
|
+
private boxedLine;
|
|
31
|
+
private rule;
|
|
32
|
+
private fit;
|
|
33
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
import { theme } from "../theme/theme.js";
|
|
3
|
+
import { keyHint, keyText, rawKeyHint } from "./keybinding-hints.js";
|
|
4
|
+
const LOGO_LINES = [
|
|
5
|
+
" ██████╗ ██╗███████╗███████╗ █████╗ ",
|
|
6
|
+
" ██╔══██╗██║╚══███╔╝╚══███╔╝██╔══██╗",
|
|
7
|
+
" ██████╔╝██║ ███╔╝ ███╔╝ ███████║",
|
|
8
|
+
" ██╔═══╝ ██║ ███╔╝ ███╔╝ ██╔══██║",
|
|
9
|
+
" ██║ ██║███████╗███████╗██║ ██║",
|
|
10
|
+
" ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝",
|
|
11
|
+
];
|
|
12
|
+
export class BrandHeaderComponent {
|
|
13
|
+
constructor(appName, version, expanded = false) {
|
|
14
|
+
this.appName = appName;
|
|
15
|
+
this.version = version;
|
|
16
|
+
this.taskHistory = [];
|
|
17
|
+
this.expanded = expanded;
|
|
18
|
+
}
|
|
19
|
+
setExpanded(expanded) {
|
|
20
|
+
if (this.expanded === expanded)
|
|
21
|
+
return;
|
|
22
|
+
this.expanded = expanded;
|
|
23
|
+
this.invalidate();
|
|
24
|
+
}
|
|
25
|
+
setTaskHistory(taskHistory) {
|
|
26
|
+
this.taskHistory = taskHistory.slice(0, 3);
|
|
27
|
+
this.invalidate();
|
|
28
|
+
}
|
|
29
|
+
invalidate() {
|
|
30
|
+
this.cachedWidth = undefined;
|
|
31
|
+
this.cachedExpanded = undefined;
|
|
32
|
+
this.cachedLines = undefined;
|
|
33
|
+
}
|
|
34
|
+
render(width) {
|
|
35
|
+
const safeWidth = Math.max(1, width);
|
|
36
|
+
if (this.cachedLines && this.cachedWidth === safeWidth && this.cachedExpanded === this.expanded) {
|
|
37
|
+
return this.cachedLines;
|
|
38
|
+
}
|
|
39
|
+
const lines = safeWidth >= 68
|
|
40
|
+
? this.renderFull(safeWidth)
|
|
41
|
+
: safeWidth >= 46
|
|
42
|
+
? this.renderBoxedCompact(safeWidth)
|
|
43
|
+
: this.renderTiny(safeWidth);
|
|
44
|
+
this.cachedWidth = safeWidth;
|
|
45
|
+
this.cachedExpanded = this.expanded;
|
|
46
|
+
this.cachedLines = lines;
|
|
47
|
+
return lines;
|
|
48
|
+
}
|
|
49
|
+
renderFull(width) {
|
|
50
|
+
const lines = [
|
|
51
|
+
this.rule(width, "╭", "─", "╮"),
|
|
52
|
+
this.boxedLine(this.splitLine(this.brandText(), theme.fg("muted", "terminal coding agent"), width - 4), width),
|
|
53
|
+
this.rule(width, "├", "─", "┤"),
|
|
54
|
+
...this.renderLogoBody(width),
|
|
55
|
+
this.boxedLine("", width),
|
|
56
|
+
this.boxedLine(theme.fg("muted", `Create together with ${this.displayName()}.`), width),
|
|
57
|
+
this.boxedLine(theme.fg("dim", "Read code · edit files · run commands · keep context"), width),
|
|
58
|
+
this.boxedLine(this.compactShortcuts(), width),
|
|
59
|
+
];
|
|
60
|
+
if (this.expanded) {
|
|
61
|
+
lines.push(this.rule(width, "├", "─", "┤"));
|
|
62
|
+
lines.push(this.boxedLine(theme.fg("dim", "Shortcuts"), width));
|
|
63
|
+
lines.push(...this.expandedShortcutLines(width));
|
|
64
|
+
}
|
|
65
|
+
lines.push(this.rule(width, "╰", "─", "╯"));
|
|
66
|
+
return lines;
|
|
67
|
+
}
|
|
68
|
+
renderLogoBody(width) {
|
|
69
|
+
if (this.taskHistory.length === 0 || width < 100) {
|
|
70
|
+
return LOGO_LINES.map((line) => this.boxedLine(theme.fg("accent", line), width));
|
|
71
|
+
}
|
|
72
|
+
const innerWidth = Math.max(1, width - 4);
|
|
73
|
+
const taskWidth = Math.min(44, Math.max(32, Math.floor(innerWidth * 0.38)));
|
|
74
|
+
const separator = theme.fg("borderMuted", "│");
|
|
75
|
+
const separatorWidth = 3;
|
|
76
|
+
const logoWidth = Math.max(1, innerWidth - taskWidth - separatorWidth);
|
|
77
|
+
const taskRows = this.taskPanelRows(taskWidth);
|
|
78
|
+
return LOGO_LINES.map((line, index) => {
|
|
79
|
+
const logo = this.fit(theme.fg("accent", line), logoWidth);
|
|
80
|
+
const task = this.fit(taskRows[index] ?? "", taskWidth);
|
|
81
|
+
return this.boxedLine(`${logo} ${separator} ${task}`, width);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
taskPanelRows(width) {
|
|
85
|
+
const rows = [
|
|
86
|
+
theme.bold(theme.fg("muted", "Recent tasks")),
|
|
87
|
+
...this.taskHistory.map((task) => this.formatTaskLine(task, width)),
|
|
88
|
+
];
|
|
89
|
+
while (rows.length < LOGO_LINES.length) {
|
|
90
|
+
rows.push("");
|
|
91
|
+
}
|
|
92
|
+
return rows;
|
|
93
|
+
}
|
|
94
|
+
formatTaskLine(task, width) {
|
|
95
|
+
const label = this.taskStatusLabel(task.status);
|
|
96
|
+
const summaryWidth = Math.max(1, width - visibleWidth(label) - 1);
|
|
97
|
+
const summary = truncateToWidth(task.summary, summaryWidth, "", true);
|
|
98
|
+
return `${label} ${summary}`;
|
|
99
|
+
}
|
|
100
|
+
taskStatusLabel(status) {
|
|
101
|
+
switch (status) {
|
|
102
|
+
case "accepted":
|
|
103
|
+
case "completed":
|
|
104
|
+
return theme.fg("success", "done");
|
|
105
|
+
case "started":
|
|
106
|
+
case "in_progress":
|
|
107
|
+
return theme.fg("accent", "run ");
|
|
108
|
+
case "failed":
|
|
109
|
+
return theme.fg("error", "fail");
|
|
110
|
+
case "rework":
|
|
111
|
+
return theme.fg("warning", "redo");
|
|
112
|
+
case "cancelled":
|
|
113
|
+
return theme.fg("muted", "stop");
|
|
114
|
+
case "assigned":
|
|
115
|
+
return theme.fg("muted", "asgn");
|
|
116
|
+
case "created":
|
|
117
|
+
return theme.fg("muted", "todo");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
renderBoxedCompact(width) {
|
|
121
|
+
const lines = [
|
|
122
|
+
this.rule(width, "╭", "─", "╮"),
|
|
123
|
+
this.boxedLine(this.brandText(), width),
|
|
124
|
+
this.boxedLine(theme.fg("muted", "Terminal coding agent"), width),
|
|
125
|
+
this.boxedLine(theme.fg("dim", "Read code · edit files · run commands"), width),
|
|
126
|
+
this.boxedLine(this.compactShortcuts(), width),
|
|
127
|
+
];
|
|
128
|
+
if (this.expanded) {
|
|
129
|
+
lines.push(this.rule(width, "├", "─", "┤"));
|
|
130
|
+
lines.push(...this.expandedShortcutLines(width));
|
|
131
|
+
}
|
|
132
|
+
lines.push(this.rule(width, "╰", "─", "╯"));
|
|
133
|
+
return lines;
|
|
134
|
+
}
|
|
135
|
+
renderTiny(width) {
|
|
136
|
+
const lines = [
|
|
137
|
+
this.fit(this.brandText(), width),
|
|
138
|
+
this.fit(theme.fg("muted", "Terminal coding agent"), width),
|
|
139
|
+
this.fit(this.compactShortcuts(), width),
|
|
140
|
+
];
|
|
141
|
+
if (this.expanded) {
|
|
142
|
+
lines.push(...this.shortcutHints().map((line) => this.fit(line, width)));
|
|
143
|
+
}
|
|
144
|
+
return lines;
|
|
145
|
+
}
|
|
146
|
+
expandedShortcutLines(width) {
|
|
147
|
+
const hints = this.shortcutHints();
|
|
148
|
+
const innerWidth = Math.max(1, width - 4);
|
|
149
|
+
if (innerWidth >= 62) {
|
|
150
|
+
const columnWidth = Math.floor((innerWidth - 3) / 2);
|
|
151
|
+
const rows = [];
|
|
152
|
+
for (let i = 0; i < hints.length; i += 2) {
|
|
153
|
+
const left = this.fit(hints[i] ?? "", columnWidth);
|
|
154
|
+
const right = this.fit(hints[i + 1] ?? "", columnWidth);
|
|
155
|
+
rows.push(this.boxedLine(`${left} ${theme.fg("borderMuted", "│")} ${right}`, width));
|
|
156
|
+
}
|
|
157
|
+
return rows;
|
|
158
|
+
}
|
|
159
|
+
return hints.map((line) => this.boxedLine(line, width));
|
|
160
|
+
}
|
|
161
|
+
shortcutHints() {
|
|
162
|
+
const hint = (keybinding, description) => keyHint(keybinding, description);
|
|
163
|
+
return [
|
|
164
|
+
hint("app.interrupt", "to interrupt"),
|
|
165
|
+
hint("app.clear", "to clear"),
|
|
166
|
+
rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
|
|
167
|
+
hint("app.exit", "to exit (empty)"),
|
|
168
|
+
hint("app.suspend", "to suspend"),
|
|
169
|
+
keyHint("tui.editor.deleteToLineEnd", "to delete to end"),
|
|
170
|
+
hint("app.thinking.cycle", "to cycle thinking level"),
|
|
171
|
+
rawKeyHint(`${keyText("app.model.cycleForward")}/${keyText("app.model.cycleBackward")}`, "to cycle models"),
|
|
172
|
+
hint("app.model.select", "to select model"),
|
|
173
|
+
hint("app.tools.expand", "to expand tools"),
|
|
174
|
+
hint("app.thinking.toggle", "to expand thinking"),
|
|
175
|
+
hint("app.editor.external", "for external editor"),
|
|
176
|
+
rawKeyHint("/", "for commands"),
|
|
177
|
+
rawKeyHint("!", "to run bash"),
|
|
178
|
+
rawKeyHint("!!", "to run bash (no context)"),
|
|
179
|
+
hint("app.message.followUp", "to queue follow-up"),
|
|
180
|
+
hint("app.message.dequeue", "to edit all queued messages"),
|
|
181
|
+
hint("app.clipboard.pasteImage", "to paste image"),
|
|
182
|
+
rawKeyHint("drop files", "to attach"),
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
compactShortcuts() {
|
|
186
|
+
return [
|
|
187
|
+
theme.fg("dim", "/help"),
|
|
188
|
+
theme.fg("muted", "commands"),
|
|
189
|
+
theme.fg("dim", keyText("app.model.cycleForward")),
|
|
190
|
+
theme.fg("muted", "model"),
|
|
191
|
+
theme.fg("dim", keyText("app.thinking.cycle")),
|
|
192
|
+
theme.fg("muted", "think"),
|
|
193
|
+
theme.fg("dim", keyText("app.interrupt")),
|
|
194
|
+
theme.fg("muted", "stop"),
|
|
195
|
+
].join(" ");
|
|
196
|
+
}
|
|
197
|
+
brandText() {
|
|
198
|
+
return `${theme.bold(theme.fg("accent", this.brandLabel()))}${theme.fg("dim", ` v${this.version}`)}`;
|
|
199
|
+
}
|
|
200
|
+
brandLabel() {
|
|
201
|
+
return (this.appName.trim() || "pizza").toUpperCase();
|
|
202
|
+
}
|
|
203
|
+
displayName() {
|
|
204
|
+
const normalized = this.appName.trim() || "pizza";
|
|
205
|
+
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
206
|
+
}
|
|
207
|
+
splitLine(left, right, width) {
|
|
208
|
+
const safeWidth = Math.max(1, width);
|
|
209
|
+
const maxRightWidth = Math.max(0, safeWidth - visibleWidth(left) - 1);
|
|
210
|
+
const fittedRight = maxRightWidth > 0 ? truncateToWidth(right, maxRightWidth, "") : "";
|
|
211
|
+
const maxLeftWidth = Math.max(1, safeWidth - visibleWidth(fittedRight) - (fittedRight ? 1 : 0));
|
|
212
|
+
const fittedLeft = truncateToWidth(left, maxLeftWidth, "");
|
|
213
|
+
const gap = Math.max(1, safeWidth - visibleWidth(fittedLeft) - visibleWidth(fittedRight));
|
|
214
|
+
return fittedRight ? `${fittedLeft}${" ".repeat(gap)}${fittedRight}` : this.fit(fittedLeft, safeWidth);
|
|
215
|
+
}
|
|
216
|
+
boxedLine(content, width) {
|
|
217
|
+
if (width < 4) {
|
|
218
|
+
return this.fit(content, width);
|
|
219
|
+
}
|
|
220
|
+
const border = (text) => theme.fg("border", text);
|
|
221
|
+
const inner = this.fit(content, width - 4);
|
|
222
|
+
return `${border("│")} ${inner} ${border("│")}`;
|
|
223
|
+
}
|
|
224
|
+
rule(width, left, fill, right) {
|
|
225
|
+
if (width <= 1) {
|
|
226
|
+
return theme.fg("border", fill.slice(0, 1));
|
|
227
|
+
}
|
|
228
|
+
return theme.fg("border", `${left}${fill.repeat(Math.max(0, width - 2))}${right}`);
|
|
229
|
+
}
|
|
230
|
+
fit(text, width) {
|
|
231
|
+
if (width <= 0)
|
|
232
|
+
return "";
|
|
233
|
+
return truncateToWidth(text, width, "", true);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Box, type MarkdownTheme } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { CompactionSummaryMessage } from "../../../core/messages.js";
|
|
3
|
+
/**
|
|
4
|
+
* Component that renders a compaction message with collapsed/expanded state.
|
|
5
|
+
* Uses same background color as custom messages for visual consistency.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CompactionSummaryMessageComponent extends Box {
|
|
8
|
+
private expanded;
|
|
9
|
+
private message;
|
|
10
|
+
private markdownTheme;
|
|
11
|
+
constructor(message: CompactionSummaryMessage, markdownTheme?: MarkdownTheme);
|
|
12
|
+
setExpanded(expanded: boolean): void;
|
|
13
|
+
invalidate(): void;
|
|
14
|
+
private updateDisplay;
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Box, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
|
+
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
|
+
import { keyText } from "./keybinding-hints.js";
|
|
4
|
+
/**
|
|
5
|
+
* Component that renders a compaction message with collapsed/expanded state.
|
|
6
|
+
* Uses same background color as custom messages for visual consistency.
|
|
7
|
+
*/
|
|
8
|
+
export class CompactionSummaryMessageComponent extends Box {
|
|
9
|
+
constructor(message, markdownTheme = getMarkdownTheme()) {
|
|
10
|
+
super(1, 1, (t) => theme.bg("customMessageBg", t));
|
|
11
|
+
this.expanded = false;
|
|
12
|
+
this.message = message;
|
|
13
|
+
this.markdownTheme = markdownTheme;
|
|
14
|
+
this.updateDisplay();
|
|
15
|
+
}
|
|
16
|
+
setExpanded(expanded) {
|
|
17
|
+
this.expanded = expanded;
|
|
18
|
+
this.updateDisplay();
|
|
19
|
+
}
|
|
20
|
+
invalidate() {
|
|
21
|
+
super.invalidate();
|
|
22
|
+
this.updateDisplay();
|
|
23
|
+
}
|
|
24
|
+
updateDisplay() {
|
|
25
|
+
this.clear();
|
|
26
|
+
const tokenStr = this.message.tokensBefore.toLocaleString();
|
|
27
|
+
const label = theme.fg("customMessageLabel", `\x1b[1m[compaction]\x1b[22m`);
|
|
28
|
+
this.addChild(new Text(label, 0, 0));
|
|
29
|
+
this.addChild(new Spacer(1));
|
|
30
|
+
if (this.expanded) {
|
|
31
|
+
const header = `**Compacted from ${tokenStr} tokens**\n\n`;
|
|
32
|
+
this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
|
|
33
|
+
color: (text) => theme.fg("customMessageText", text),
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.addChild(new Text(theme.fg("customMessageText", `Compacted from ${tokenStr} tokens (`) +
|
|
38
|
+
theme.fg("dim", keyText("app.tools.expand")) +
|
|
39
|
+
theme.fg("customMessageText", " to expand)"), 0, 0));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|