@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,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-line editor component for extensions.
|
|
3
|
+
* Supports Ctrl+G for external editor.
|
|
4
|
+
*/
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import * as fs from "node:fs";
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { Container, Editor, getKeybindings, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
10
|
+
import { getEditorTheme, theme } from "../theme/theme.js";
|
|
11
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
12
|
+
import { keyHint } from "./keybinding-hints.js";
|
|
13
|
+
export class ExtensionEditorComponent extends Container {
|
|
14
|
+
get focused() {
|
|
15
|
+
return this._focused;
|
|
16
|
+
}
|
|
17
|
+
set focused(value) {
|
|
18
|
+
this._focused = value;
|
|
19
|
+
this.editor.focused = value;
|
|
20
|
+
}
|
|
21
|
+
constructor(tui, keybindings, title, prefill, onSubmit, onCancel, options) {
|
|
22
|
+
super();
|
|
23
|
+
this._focused = false;
|
|
24
|
+
this.tui = tui;
|
|
25
|
+
this.keybindings = keybindings;
|
|
26
|
+
this.onSubmitCallback = onSubmit;
|
|
27
|
+
this.onCancelCallback = onCancel;
|
|
28
|
+
// Add top border
|
|
29
|
+
this.addChild(new DynamicBorder());
|
|
30
|
+
this.addChild(new Spacer(1));
|
|
31
|
+
// Add title
|
|
32
|
+
this.addChild(new Text(theme.fg("accent", title), 1, 0));
|
|
33
|
+
this.addChild(new Spacer(1));
|
|
34
|
+
// Create editor
|
|
35
|
+
this.editor = new Editor(tui, getEditorTheme(), options);
|
|
36
|
+
if (prefill) {
|
|
37
|
+
this.editor.setText(prefill);
|
|
38
|
+
}
|
|
39
|
+
// Wire up Enter to submit (Shift+Enter for newlines, like the main editor)
|
|
40
|
+
this.editor.onSubmit = (text) => {
|
|
41
|
+
this.onSubmitCallback(text);
|
|
42
|
+
};
|
|
43
|
+
this.addChild(this.editor);
|
|
44
|
+
this.addChild(new Spacer(1));
|
|
45
|
+
// Add hint
|
|
46
|
+
const hasExternalEditor = !!(process.env.VISUAL || process.env.EDITOR);
|
|
47
|
+
const hint = keyHint("tui.select.confirm", "submit") +
|
|
48
|
+
" " +
|
|
49
|
+
keyHint("tui.input.newLine", "newline") +
|
|
50
|
+
" " +
|
|
51
|
+
keyHint("tui.select.cancel", "cancel") +
|
|
52
|
+
(hasExternalEditor ? ` ${keyHint("app.editor.external", "external editor")}` : "");
|
|
53
|
+
this.addChild(new Text(hint, 1, 0));
|
|
54
|
+
this.addChild(new Spacer(1));
|
|
55
|
+
// Add bottom border
|
|
56
|
+
this.addChild(new DynamicBorder());
|
|
57
|
+
}
|
|
58
|
+
handleInput(keyData) {
|
|
59
|
+
const kb = getKeybindings();
|
|
60
|
+
// Escape or Ctrl+C to cancel
|
|
61
|
+
if (kb.matches(keyData, "tui.select.cancel")) {
|
|
62
|
+
this.onCancelCallback();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// External editor (app keybinding)
|
|
66
|
+
if (this.keybindings.matches(keyData, "app.editor.external")) {
|
|
67
|
+
this.openExternalEditor();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Forward to editor
|
|
71
|
+
this.editor.handleInput(keyData);
|
|
72
|
+
}
|
|
73
|
+
openExternalEditor() {
|
|
74
|
+
const editorCmd = process.env.VISUAL || process.env.EDITOR;
|
|
75
|
+
if (!editorCmd) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const currentText = this.editor.getText();
|
|
79
|
+
const tmpFile = path.join(os.tmpdir(), `pizza-extension-editor-${Date.now()}.md`);
|
|
80
|
+
try {
|
|
81
|
+
fs.writeFileSync(tmpFile, currentText, "utf-8");
|
|
82
|
+
this.tui.stop();
|
|
83
|
+
const [editor, ...editorArgs] = editorCmd.split(" ");
|
|
84
|
+
const result = spawnSync(editor, [...editorArgs, tmpFile], {
|
|
85
|
+
stdio: "inherit",
|
|
86
|
+
shell: process.platform === "win32",
|
|
87
|
+
});
|
|
88
|
+
if (result.status === 0) {
|
|
89
|
+
const newContent = fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "");
|
|
90
|
+
this.editor.setText(newContent);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
try {
|
|
95
|
+
fs.unlinkSync(tmpFile);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Ignore cleanup errors
|
|
99
|
+
}
|
|
100
|
+
this.tui.start();
|
|
101
|
+
// Force full re-render since external editor uses alternate screen
|
|
102
|
+
this.tui.requestRender(true);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple text input component for extensions.
|
|
3
|
+
*/
|
|
4
|
+
import { Container, type Focusable, type TUI } from "@earendil-works/pi-tui";
|
|
5
|
+
export interface ExtensionInputOptions {
|
|
6
|
+
tui?: TUI;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class ExtensionInputComponent extends Container implements Focusable {
|
|
10
|
+
private input;
|
|
11
|
+
private onSubmitCallback;
|
|
12
|
+
private onCancelCallback;
|
|
13
|
+
private titleText;
|
|
14
|
+
private baseTitle;
|
|
15
|
+
private countdown;
|
|
16
|
+
private _focused;
|
|
17
|
+
get focused(): boolean;
|
|
18
|
+
set focused(value: boolean);
|
|
19
|
+
constructor(title: string, _placeholder: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, opts?: ExtensionInputOptions);
|
|
20
|
+
handleInput(keyData: string): void;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple text input component for extensions.
|
|
3
|
+
*/
|
|
4
|
+
import { Container, getKeybindings, Input, Spacer, Text } from "@earendil-works/pi-tui";
|
|
5
|
+
import { theme } from "../theme/theme.js";
|
|
6
|
+
import { CountdownTimer } from "./countdown-timer.js";
|
|
7
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
8
|
+
import { keyHint } from "./keybinding-hints.js";
|
|
9
|
+
export class ExtensionInputComponent extends Container {
|
|
10
|
+
get focused() {
|
|
11
|
+
return this._focused;
|
|
12
|
+
}
|
|
13
|
+
set focused(value) {
|
|
14
|
+
this._focused = value;
|
|
15
|
+
this.input.focused = value;
|
|
16
|
+
}
|
|
17
|
+
constructor(title, _placeholder, onSubmit, onCancel, opts) {
|
|
18
|
+
super();
|
|
19
|
+
// Focusable implementation - propagate to input for IME cursor positioning
|
|
20
|
+
this._focused = false;
|
|
21
|
+
this.onSubmitCallback = onSubmit;
|
|
22
|
+
this.onCancelCallback = onCancel;
|
|
23
|
+
this.baseTitle = title;
|
|
24
|
+
this.addChild(new DynamicBorder());
|
|
25
|
+
this.addChild(new Spacer(1));
|
|
26
|
+
this.titleText = new Text(theme.fg("accent", title), 1, 0);
|
|
27
|
+
this.addChild(this.titleText);
|
|
28
|
+
this.addChild(new Spacer(1));
|
|
29
|
+
if (opts?.timeout && opts.timeout > 0 && opts.tui) {
|
|
30
|
+
this.countdown = new CountdownTimer(opts.timeout, opts.tui, (s) => this.titleText.setText(theme.fg("accent", `${this.baseTitle} (${s}s)`)), () => this.onCancelCallback());
|
|
31
|
+
}
|
|
32
|
+
this.input = new Input();
|
|
33
|
+
this.addChild(this.input);
|
|
34
|
+
this.addChild(new Spacer(1));
|
|
35
|
+
this.addChild(new Text(`${keyHint("tui.select.confirm", "submit")} ${keyHint("tui.select.cancel", "cancel")}`, 1, 0));
|
|
36
|
+
this.addChild(new Spacer(1));
|
|
37
|
+
this.addChild(new DynamicBorder());
|
|
38
|
+
}
|
|
39
|
+
handleInput(keyData) {
|
|
40
|
+
const kb = getKeybindings();
|
|
41
|
+
if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
|
|
42
|
+
this.onSubmitCallback(this.input.getValue());
|
|
43
|
+
}
|
|
44
|
+
else if (kb.matches(keyData, "tui.select.cancel")) {
|
|
45
|
+
this.onCancelCallback();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.input.handleInput(keyData);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
dispose() {
|
|
52
|
+
this.countdown?.dispose();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic selector component for extensions.
|
|
3
|
+
* Displays a list of string options with keyboard navigation.
|
|
4
|
+
*/
|
|
5
|
+
import { Container, type TUI } from "@earendil-works/pi-tui";
|
|
6
|
+
export interface ExtensionSelectorOptions {
|
|
7
|
+
tui?: TUI;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class ExtensionSelectorComponent extends Container {
|
|
11
|
+
private options;
|
|
12
|
+
private selectedIndex;
|
|
13
|
+
private listContainer;
|
|
14
|
+
private onSelectCallback;
|
|
15
|
+
private onCancelCallback;
|
|
16
|
+
private titleText;
|
|
17
|
+
private baseTitle;
|
|
18
|
+
private countdown;
|
|
19
|
+
constructor(title: string, options: string[], onSelect: (option: string) => void, onCancel: () => void, opts?: ExtensionSelectorOptions);
|
|
20
|
+
private updateList;
|
|
21
|
+
handleInput(keyData: string): void;
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic selector component for extensions.
|
|
3
|
+
* Displays a list of string options with keyboard navigation.
|
|
4
|
+
*/
|
|
5
|
+
import { Container, getKeybindings, Spacer, Text } from "@earendil-works/pi-tui";
|
|
6
|
+
import { theme } from "../theme/theme.js";
|
|
7
|
+
import { CountdownTimer } from "./countdown-timer.js";
|
|
8
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
9
|
+
import { keyHint, rawKeyHint } from "./keybinding-hints.js";
|
|
10
|
+
export class ExtensionSelectorComponent extends Container {
|
|
11
|
+
constructor(title, options, onSelect, onCancel, opts) {
|
|
12
|
+
super();
|
|
13
|
+
this.selectedIndex = 0;
|
|
14
|
+
this.options = options;
|
|
15
|
+
this.onSelectCallback = onSelect;
|
|
16
|
+
this.onCancelCallback = onCancel;
|
|
17
|
+
this.baseTitle = title;
|
|
18
|
+
this.addChild(new DynamicBorder());
|
|
19
|
+
this.addChild(new Spacer(1));
|
|
20
|
+
this.titleText = new Text(theme.fg("accent", title), 1, 0);
|
|
21
|
+
this.addChild(this.titleText);
|
|
22
|
+
this.addChild(new Spacer(1));
|
|
23
|
+
if (opts?.timeout && opts.timeout > 0 && opts.tui) {
|
|
24
|
+
this.countdown = new CountdownTimer(opts.timeout, opts.tui, (s) => this.titleText.setText(theme.fg("accent", `${this.baseTitle} (${s}s)`)), () => this.onCancelCallback());
|
|
25
|
+
}
|
|
26
|
+
this.listContainer = new Container();
|
|
27
|
+
this.addChild(this.listContainer);
|
|
28
|
+
this.addChild(new Spacer(1));
|
|
29
|
+
this.addChild(new Text(rawKeyHint("↑↓", "navigate") +
|
|
30
|
+
" " +
|
|
31
|
+
keyHint("tui.select.confirm", "select") +
|
|
32
|
+
" " +
|
|
33
|
+
keyHint("tui.select.cancel", "cancel"), 1, 0));
|
|
34
|
+
this.addChild(new Spacer(1));
|
|
35
|
+
this.addChild(new DynamicBorder());
|
|
36
|
+
this.updateList();
|
|
37
|
+
}
|
|
38
|
+
updateList() {
|
|
39
|
+
this.listContainer.clear();
|
|
40
|
+
for (let i = 0; i < this.options.length; i++) {
|
|
41
|
+
const isSelected = i === this.selectedIndex;
|
|
42
|
+
const text = isSelected
|
|
43
|
+
? theme.fg("accent", "→ ") + theme.fg("accent", this.options[i])
|
|
44
|
+
: ` ${theme.fg("text", this.options[i])}`;
|
|
45
|
+
this.listContainer.addChild(new Text(text, 1, 0));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
handleInput(keyData) {
|
|
49
|
+
const kb = getKeybindings();
|
|
50
|
+
if (kb.matches(keyData, "tui.select.up") || keyData === "k") {
|
|
51
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
52
|
+
this.updateList();
|
|
53
|
+
}
|
|
54
|
+
else if (kb.matches(keyData, "tui.select.down") || keyData === "j") {
|
|
55
|
+
this.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);
|
|
56
|
+
this.updateList();
|
|
57
|
+
}
|
|
58
|
+
else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
|
|
59
|
+
const selected = this.options[this.selectedIndex];
|
|
60
|
+
if (selected)
|
|
61
|
+
this.onSelectCallback(selected);
|
|
62
|
+
}
|
|
63
|
+
else if (kb.matches(keyData, "tui.select.cancel")) {
|
|
64
|
+
this.onCancelCallback();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
dispose() {
|
|
68
|
+
this.countdown?.dispose();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { ContextUsage } from "../../../core/extensions/index.js";
|
|
3
|
+
import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.js";
|
|
4
|
+
/**
|
|
5
|
+
* Minimal interface for footer data access.
|
|
6
|
+
* Supported by SessionFacade-based adapters.
|
|
7
|
+
*/
|
|
8
|
+
export interface FooterSessionInfo {
|
|
9
|
+
/** Model info: id, provider, reasoning, contextWindow */
|
|
10
|
+
getModel(): {
|
|
11
|
+
id: string;
|
|
12
|
+
provider: string;
|
|
13
|
+
reasoning?: boolean;
|
|
14
|
+
contextWindow?: number;
|
|
15
|
+
} | undefined;
|
|
16
|
+
/** Current thinking level */
|
|
17
|
+
getThinkingLevel(): string | undefined;
|
|
18
|
+
/** Cumulative token usage from all assistant messages */
|
|
19
|
+
getTokenUsage(): {
|
|
20
|
+
totalInput: number;
|
|
21
|
+
totalOutput: number;
|
|
22
|
+
totalCacheRead: number;
|
|
23
|
+
totalCacheWrite: number;
|
|
24
|
+
totalCost: number;
|
|
25
|
+
};
|
|
26
|
+
/** Context window usage */
|
|
27
|
+
getContextUsage(): ContextUsage | undefined;
|
|
28
|
+
/** Working directory */
|
|
29
|
+
getCwd(): string;
|
|
30
|
+
/** Whether the current model uses OAuth subscription */
|
|
31
|
+
isUsingOAuthSubscription(): boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Footer component that shows pwd, token stats, and context usage.
|
|
35
|
+
* Computes token/context stats from session, gets git branch and extension statuses from provider.
|
|
36
|
+
*/
|
|
37
|
+
export declare class FooterComponent implements Component {
|
|
38
|
+
private session;
|
|
39
|
+
private footerData;
|
|
40
|
+
private autoCompactEnabled;
|
|
41
|
+
constructor(session: FooterSessionInfo, footerData: ReadonlyFooterDataProvider);
|
|
42
|
+
setSession(session: FooterSessionInfo): void;
|
|
43
|
+
setAutoCompactEnabled(enabled: boolean): void;
|
|
44
|
+
/**
|
|
45
|
+
* No-op: git branch caching now handled by provider.
|
|
46
|
+
* Kept for compatibility with existing call sites in interactive-mode.
|
|
47
|
+
*/
|
|
48
|
+
invalidate(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Clean up resources.
|
|
51
|
+
* Git watcher cleanup now handled by provider.
|
|
52
|
+
*/
|
|
53
|
+
dispose(): void;
|
|
54
|
+
render(width: number): string[];
|
|
55
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
import { theme } from "../theme/theme.js";
|
|
3
|
+
/**
|
|
4
|
+
* Sanitize text for display in a single-line status.
|
|
5
|
+
* Removes newlines, tabs, carriage returns, and other control characters.
|
|
6
|
+
*/
|
|
7
|
+
function sanitizeStatusText(text) {
|
|
8
|
+
// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces
|
|
9
|
+
return text
|
|
10
|
+
.replace(/[\r\n\t]/g, " ")
|
|
11
|
+
.replace(/ +/g, " ")
|
|
12
|
+
.trim();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Format token counts (similar to web-ui)
|
|
16
|
+
*/
|
|
17
|
+
function formatTokens(count) {
|
|
18
|
+
if (count < 1000)
|
|
19
|
+
return count.toString();
|
|
20
|
+
if (count < 10000)
|
|
21
|
+
return `${(count / 1000).toFixed(1)}k`;
|
|
22
|
+
if (count < 1000000)
|
|
23
|
+
return `${Math.round(count / 1000)}k`;
|
|
24
|
+
if (count < 10000000)
|
|
25
|
+
return `${(count / 1000000).toFixed(1)}M`;
|
|
26
|
+
return `${Math.round(count / 1000000)}M`;
|
|
27
|
+
}
|
|
28
|
+
function renderSegments(segments) {
|
|
29
|
+
return segments.map((segment) => theme.fg(segment.color, segment.text)).join("");
|
|
30
|
+
}
|
|
31
|
+
function renderRightSide(text, provider) {
|
|
32
|
+
if (!text)
|
|
33
|
+
return "";
|
|
34
|
+
const providerPrefix = provider ? `(${provider}) ` : undefined;
|
|
35
|
+
if (providerPrefix && text.startsWith(providerPrefix)) {
|
|
36
|
+
return theme.fg("dim", providerPrefix) + renderRightSide(text.slice(providerPrefix.length));
|
|
37
|
+
}
|
|
38
|
+
const separator = " • ";
|
|
39
|
+
const separatorIndex = text.indexOf(separator);
|
|
40
|
+
if (separatorIndex === -1) {
|
|
41
|
+
return theme.fg("accent", text);
|
|
42
|
+
}
|
|
43
|
+
return (theme.fg("accent", text.slice(0, separatorIndex)) +
|
|
44
|
+
theme.fg("dim", separator) +
|
|
45
|
+
theme.fg("muted", text.slice(separatorIndex + separator.length)));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Footer component that shows pwd, token stats, and context usage.
|
|
49
|
+
* Computes token/context stats from session, gets git branch and extension statuses from provider.
|
|
50
|
+
*/
|
|
51
|
+
export class FooterComponent {
|
|
52
|
+
constructor(session, footerData) {
|
|
53
|
+
this.session = session;
|
|
54
|
+
this.footerData = footerData;
|
|
55
|
+
this.autoCompactEnabled = true;
|
|
56
|
+
}
|
|
57
|
+
setSession(session) {
|
|
58
|
+
this.session = session;
|
|
59
|
+
}
|
|
60
|
+
setAutoCompactEnabled(enabled) {
|
|
61
|
+
this.autoCompactEnabled = enabled;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* No-op: git branch caching now handled by provider.
|
|
65
|
+
* Kept for compatibility with existing call sites in interactive-mode.
|
|
66
|
+
*/
|
|
67
|
+
invalidate() {
|
|
68
|
+
// No-op: git branch is cached/invalidated by provider
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clean up resources.
|
|
72
|
+
* Git watcher cleanup now handled by provider.
|
|
73
|
+
*/
|
|
74
|
+
dispose() {
|
|
75
|
+
// Git watcher cleanup handled by provider
|
|
76
|
+
}
|
|
77
|
+
render(width) {
|
|
78
|
+
// Extract session info
|
|
79
|
+
const modelInfo = this.session.getModel();
|
|
80
|
+
const thinkingLevel = this.session.getThinkingLevel();
|
|
81
|
+
const tokenUsage = this.session.getTokenUsage();
|
|
82
|
+
const contextUsage = this.session.getContextUsage();
|
|
83
|
+
const pwd = this.session.getCwd();
|
|
84
|
+
const usingSubscription = this.session.isUsingOAuthSubscription();
|
|
85
|
+
// Cyber-style prefix and content width (prefix takes 2 columns)
|
|
86
|
+
const prefix = theme.fg("accent", "❯ ");
|
|
87
|
+
const contentWidth = Math.max(1, width - 2);
|
|
88
|
+
const contextWindow = contextUsage?.contextWindow ?? modelInfo?.contextWindow ?? 0;
|
|
89
|
+
const contextPercentValue = contextUsage?.percent ?? 0;
|
|
90
|
+
const contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : "?";
|
|
91
|
+
// Replace home directory with ~
|
|
92
|
+
let displayPwd = pwd;
|
|
93
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
94
|
+
if (home && displayPwd.startsWith(home)) {
|
|
95
|
+
displayPwd = `~${displayPwd.slice(home.length)}`;
|
|
96
|
+
}
|
|
97
|
+
const pathSegments = [{ text: displayPwd, color: "muted" }];
|
|
98
|
+
// Add git branch if available
|
|
99
|
+
const branch = this.footerData.getGitBranch();
|
|
100
|
+
if (branch) {
|
|
101
|
+
displayPwd = `${displayPwd} (${branch})`;
|
|
102
|
+
pathSegments.push({ text: " (", color: "dim" });
|
|
103
|
+
pathSegments.push({ text: branch, color: "accent" });
|
|
104
|
+
pathSegments.push({ text: ")", color: "dim" });
|
|
105
|
+
}
|
|
106
|
+
// Build stats line
|
|
107
|
+
const statsParts = [];
|
|
108
|
+
if (tokenUsage.totalInput)
|
|
109
|
+
statsParts.push({ text: `↑${formatTokens(tokenUsage.totalInput)}`, color: "accent" });
|
|
110
|
+
if (tokenUsage.totalOutput)
|
|
111
|
+
statsParts.push({ text: `↓${formatTokens(tokenUsage.totalOutput)}`, color: "mdLink" });
|
|
112
|
+
if (tokenUsage.totalCacheRead)
|
|
113
|
+
statsParts.push({ text: `R${formatTokens(tokenUsage.totalCacheRead)}`, color: "muted" });
|
|
114
|
+
if (tokenUsage.totalCacheWrite)
|
|
115
|
+
statsParts.push({ text: `W${formatTokens(tokenUsage.totalCacheWrite)}`, color: "muted" });
|
|
116
|
+
// Show cost with "(sub)" indicator if using OAuth subscription
|
|
117
|
+
if (tokenUsage.totalCost || usingSubscription) {
|
|
118
|
+
const costStr = `$${tokenUsage.totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
|
|
119
|
+
statsParts.push({ text: costStr, color: "success" });
|
|
120
|
+
}
|
|
121
|
+
// Colorize context percentage based on usage
|
|
122
|
+
let contextColor;
|
|
123
|
+
const autoIndicator = this.autoCompactEnabled ? " (auto)" : "";
|
|
124
|
+
const contextPercentDisplay = contextPercent === "?"
|
|
125
|
+
? `?/${formatTokens(contextWindow)}${autoIndicator}`
|
|
126
|
+
: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;
|
|
127
|
+
if (contextPercentValue > 90) {
|
|
128
|
+
contextColor = "error";
|
|
129
|
+
}
|
|
130
|
+
else if (contextPercentValue > 70) {
|
|
131
|
+
contextColor = "warning";
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
contextColor = "success";
|
|
135
|
+
}
|
|
136
|
+
statsParts.push({ text: contextPercentDisplay, color: contextColor });
|
|
137
|
+
let statsLeft = statsParts.map((part) => part.text).join("│");
|
|
138
|
+
// Add model name on the right side, plus thinking level if model supports it
|
|
139
|
+
const modelName = modelInfo?.id || "no-model";
|
|
140
|
+
let statsLeftWidth = visibleWidth(statsLeft);
|
|
141
|
+
// If statsLeft is too wide, truncate it
|
|
142
|
+
if (statsLeftWidth > contentWidth) {
|
|
143
|
+
statsLeft = truncateToWidth(statsLeft, contentWidth, "...");
|
|
144
|
+
statsLeftWidth = visibleWidth(statsLeft);
|
|
145
|
+
}
|
|
146
|
+
// Calculate available space for padding (minimum 2 spaces between stats and model)
|
|
147
|
+
const minPadding = 2;
|
|
148
|
+
// Add thinking level indicator if model supports reasoning
|
|
149
|
+
let rightSideWithoutProvider = modelName;
|
|
150
|
+
if (modelInfo?.reasoning) {
|
|
151
|
+
const level = thinkingLevel || "off";
|
|
152
|
+
rightSideWithoutProvider =
|
|
153
|
+
level === "off" ? `${modelName} • thinking off` : `${modelName} • ${level}`;
|
|
154
|
+
}
|
|
155
|
+
// Prepend the provider in parentheses if there are multiple providers and there's enough room
|
|
156
|
+
let rightSide = rightSideWithoutProvider;
|
|
157
|
+
if (this.footerData.getAvailableProviderCount() > 1 && modelInfo) {
|
|
158
|
+
rightSide = `(${modelInfo.provider}) ${rightSideWithoutProvider}`;
|
|
159
|
+
if (statsLeftWidth + minPadding + visibleWidth(rightSide) > contentWidth) {
|
|
160
|
+
// Too wide, fall back
|
|
161
|
+
rightSide = rightSideWithoutProvider;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const rightSideWidth = visibleWidth(rightSide);
|
|
165
|
+
const totalNeeded = statsLeftWidth + minPadding + rightSideWidth;
|
|
166
|
+
let renderedStatsLeft;
|
|
167
|
+
if (visibleWidth(statsLeft) === statsParts.reduce((sum, part) => sum + visibleWidth(part.text), 0) + Math.max(0, statsParts.length - 1)) {
|
|
168
|
+
renderedStatsLeft = statsParts.map((part) => theme.fg(part.color, part.text)).join(theme.fg("borderMuted", "│"));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
renderedStatsLeft = theme.fg("dim", statsLeft);
|
|
172
|
+
}
|
|
173
|
+
let statsLine;
|
|
174
|
+
if (totalNeeded <= contentWidth) {
|
|
175
|
+
// Both fit - add padding to right-align model
|
|
176
|
+
const padding = " ".repeat(contentWidth - statsLeftWidth - rightSideWidth);
|
|
177
|
+
statsLine = renderedStatsLeft + theme.fg("dim", padding) + renderRightSide(rightSide, modelInfo?.provider);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// Need to truncate right side
|
|
181
|
+
const availableForRight = contentWidth - statsLeftWidth - minPadding;
|
|
182
|
+
if (availableForRight > 0) {
|
|
183
|
+
const truncatedRight = truncateToWidth(rightSide, availableForRight, "");
|
|
184
|
+
const truncatedRightWidth = visibleWidth(truncatedRight);
|
|
185
|
+
const padding = " ".repeat(Math.max(0, contentWidth - statsLeftWidth - truncatedRightWidth));
|
|
186
|
+
statsLine = renderedStatsLeft + theme.fg("dim", padding) + renderRightSide(truncatedRight, modelInfo?.provider);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// Not enough space for right side at all
|
|
190
|
+
statsLine = renderedStatsLeft;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const pwdContent = truncateToWidth(renderSegments(pathSegments), contentWidth, theme.fg("dim", "..."));
|
|
194
|
+
const lines = [prefix + pwdContent, prefix + statsLine];
|
|
195
|
+
// Add extension statuses on a single line, sorted by key alphabetically
|
|
196
|
+
const extensionStatuses = this.footerData.getExtensionStatuses();
|
|
197
|
+
if (extensionStatuses.size > 0) {
|
|
198
|
+
const sortedStatuses = Array.from(extensionStatuses.entries())
|
|
199
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
200
|
+
.map(([, text]) => sanitizeStatusText(text));
|
|
201
|
+
const statusLine = sortedStatuses.join(" ");
|
|
202
|
+
// Truncate to terminal width with dim ellipsis for consistency with footer style
|
|
203
|
+
lines.push(prefix + truncateToWidth(theme.fg("muted", statusLine), contentWidth, theme.fg("dim", "...")));
|
|
204
|
+
}
|
|
205
|
+
return lines;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { ArminComponent } from "./armin.js";
|
|
2
|
+
export { AssistantMessageComponent } from "./assistant-message.js";
|
|
3
|
+
export { BashExecutionComponent } from "./bash-execution.js";
|
|
4
|
+
export { BorderedLoader } from "./bordered-loader.js";
|
|
5
|
+
export { BranchSummaryMessageComponent } from "./branch-summary-message.js";
|
|
6
|
+
export { BrandHeaderComponent } from "./brand-header.js";
|
|
7
|
+
export { CompactionSummaryMessageComponent } from "./compaction-summary-message.js";
|
|
8
|
+
export { CustomEditor } from "./custom-editor.js";
|
|
9
|
+
export { CustomMessageComponent } from "./custom-message.js";
|
|
10
|
+
export { DaxnutsComponent } from "./daxnuts.js";
|
|
11
|
+
export { type RenderDiffOptions, renderDiff } from "./diff.js";
|
|
12
|
+
export { DynamicBorder } from "./dynamic-border.js";
|
|
13
|
+
export { ExtensionEditorComponent } from "./extension-editor.js";
|
|
14
|
+
export { ExtensionInputComponent } from "./extension-input.js";
|
|
15
|
+
export { ExtensionSelectorComponent } from "./extension-selector.js";
|
|
16
|
+
export { FooterComponent } from "./footer.js";
|
|
17
|
+
export { keyHint, keyText, rawKeyHint } from "./keybinding-hints.js";
|
|
18
|
+
export { LoginDialogComponent } from "./login-dialog.js";
|
|
19
|
+
export { ModelSelectorComponent } from "./model-selector.js";
|
|
20
|
+
export { OAuthSelectorComponent } from "./oauth-selector.js";
|
|
21
|
+
export { type SettingsCallbacks, type SettingsConfig, SettingsSelectorComponent } from "./settings-selector.js";
|
|
22
|
+
export { ShowImagesSelectorComponent } from "./show-images-selector.js";
|
|
23
|
+
export { SkillInvocationMessageComponent } from "./skill-invocation-message.js";
|
|
24
|
+
export { ThemeSelectorComponent } from "./theme-selector.js";
|
|
25
|
+
export { ThinkingSelectorComponent } from "./thinking-selector.js";
|
|
26
|
+
export { TimelineViewComponent, type TimelineViewOptions } from "./timeline-view.js";
|
|
27
|
+
export { ToolExecutionComponent, type ToolExecutionOptions } from "./tool-execution.js";
|
|
28
|
+
export { TreeSelectorComponent } from "./tree-selector.js";
|
|
29
|
+
export { UserMessageComponent } from "./user-message.js";
|
|
30
|
+
export { UserMessageSelectorComponent } from "./user-message-selector.js";
|
|
31
|
+
export { truncateToVisualLines, type VisualTruncateResult } from "./visual-truncate.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// UI Components for extensions
|
|
2
|
+
export { ArminComponent } from "./armin.js";
|
|
3
|
+
export { AssistantMessageComponent } from "./assistant-message.js";
|
|
4
|
+
export { BashExecutionComponent } from "./bash-execution.js";
|
|
5
|
+
export { BorderedLoader } from "./bordered-loader.js";
|
|
6
|
+
export { BranchSummaryMessageComponent } from "./branch-summary-message.js";
|
|
7
|
+
export { BrandHeaderComponent } from "./brand-header.js";
|
|
8
|
+
export { CompactionSummaryMessageComponent } from "./compaction-summary-message.js";
|
|
9
|
+
export { CustomEditor } from "./custom-editor.js";
|
|
10
|
+
export { CustomMessageComponent } from "./custom-message.js";
|
|
11
|
+
export { DaxnutsComponent } from "./daxnuts.js";
|
|
12
|
+
export { renderDiff } from "./diff.js";
|
|
13
|
+
export { DynamicBorder } from "./dynamic-border.js";
|
|
14
|
+
export { ExtensionEditorComponent } from "./extension-editor.js";
|
|
15
|
+
export { ExtensionInputComponent } from "./extension-input.js";
|
|
16
|
+
export { ExtensionSelectorComponent } from "./extension-selector.js";
|
|
17
|
+
export { FooterComponent } from "./footer.js";
|
|
18
|
+
export { keyHint, keyText, rawKeyHint } from "./keybinding-hints.js";
|
|
19
|
+
export { LoginDialogComponent } from "./login-dialog.js";
|
|
20
|
+
export { ModelSelectorComponent } from "./model-selector.js";
|
|
21
|
+
export { OAuthSelectorComponent } from "./oauth-selector.js";
|
|
22
|
+
export { SettingsSelectorComponent } from "./settings-selector.js";
|
|
23
|
+
export { ShowImagesSelectorComponent } from "./show-images-selector.js";
|
|
24
|
+
export { SkillInvocationMessageComponent } from "./skill-invocation-message.js";
|
|
25
|
+
export { ThemeSelectorComponent } from "./theme-selector.js";
|
|
26
|
+
export { ThinkingSelectorComponent } from "./thinking-selector.js";
|
|
27
|
+
export { TimelineViewComponent } from "./timeline-view.js";
|
|
28
|
+
export { ToolExecutionComponent } from "./tool-execution.js";
|
|
29
|
+
export { TreeSelectorComponent } from "./tree-selector.js";
|
|
30
|
+
export { UserMessageComponent } from "./user-message.js";
|
|
31
|
+
export { UserMessageSelectorComponent } from "./user-message-selector.js";
|
|
32
|
+
export { truncateToVisualLines } from "./visual-truncate.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for formatting keybinding hints in the UI.
|
|
3
|
+
*/
|
|
4
|
+
import { type Keybinding } from "@earendil-works/pi-tui";
|
|
5
|
+
export declare function keyText(keybinding: Keybinding): string;
|
|
6
|
+
export declare function keyHint(keybinding: Keybinding, description: string): string;
|
|
7
|
+
export declare function rawKeyHint(key: string, description: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for formatting keybinding hints in the UI.
|
|
3
|
+
*/
|
|
4
|
+
import { getKeybindings } from "@earendil-works/pi-tui";
|
|
5
|
+
import { theme } from "../theme/theme.js";
|
|
6
|
+
function formatKeys(keys) {
|
|
7
|
+
if (keys.length === 0)
|
|
8
|
+
return "";
|
|
9
|
+
if (keys.length === 1)
|
|
10
|
+
return keys[0];
|
|
11
|
+
return keys.join("/");
|
|
12
|
+
}
|
|
13
|
+
export function keyText(keybinding) {
|
|
14
|
+
return formatKeys(getKeybindings().getKeys(keybinding));
|
|
15
|
+
}
|
|
16
|
+
export function keyHint(keybinding, description) {
|
|
17
|
+
return theme.fg("dim", keyText(keybinding)) + theme.fg("muted", ` ${description}`);
|
|
18
|
+
}
|
|
19
|
+
export function rawKeyHint(key, description) {
|
|
20
|
+
return theme.fg("dim", key) + theme.fg("muted", ` ${description}`);
|
|
21
|
+
}
|