@linxiraos/pi-tui 1.1.27 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -461
- package/README.md +7 -5
- package/dist/types/app-keybindings.d.ts +1 -1
- package/dist/types/apps/cleanse-board.d.ts +1 -1
- package/dist/types/apps/debug/log-viewer.d.ts +4 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
- package/dist/types/apps/git/git-tui.d.ts +2 -2
- package/dist/types/apps/git/help.d.ts +3 -1
- package/dist/types/apps/if-bench-board.d.ts +2 -2
- package/dist/types/apps/setup-model-picker.d.ts +1 -1
- package/dist/types/autocomplete.d.ts +5 -2
- package/dist/types/charts/chart-plan.d.ts +674 -0
- package/dist/types/charts/chart-svg.d.ts +59 -0
- package/dist/types/charts/table-data.d.ts +175 -0
- package/dist/types/chat/assistant-message.d.ts +5 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +2 -0
- package/dist/types/chat/compaction-summary-message.d.ts +1 -0
- package/dist/types/chat/execution-shared.d.ts +6 -5
- package/dist/types/chat/fence-figure.d.ts +42 -0
- package/dist/types/chat/figure-markdown.d.ts +42 -0
- package/dist/types/chat/messages.d.ts +1 -1
- package/dist/types/chat/svg-figure.d.ts +33 -0
- package/dist/types/chat/svg-source.d.ts +49 -0
- package/dist/types/chat/table-chart.d.ts +89 -0
- package/dist/types/chat/tool-execution.d.ts +2 -0
- package/dist/types/chat/user-message.d.ts +15 -2
- package/dist/types/chrome/shared.d.ts +9 -0
- package/dist/types/chrome/transcript-container.d.ts +6 -0
- package/dist/types/components/box.d.ts +1 -0
- package/dist/types/components/disclosure.d.ts +1 -0
- package/dist/types/components/editor.d.ts +15 -4
- package/dist/types/components/form.d.ts +1 -0
- package/dist/types/components/image.d.ts +12 -44
- package/dist/types/components/key-value-list.d.ts +1 -0
- package/dist/types/components/layout/row.d.ts +1 -0
- package/dist/types/components/layout/stack.d.ts +1 -0
- package/dist/types/components/markdown.d.ts +36 -3
- package/dist/types/components/scroll-view.d.ts +1 -0
- package/dist/types/components/section.d.ts +1 -0
- package/dist/types/components/table.d.ts +1 -0
- package/dist/types/components/text.d.ts +1 -0
- package/dist/types/components/tree-view.d.ts +7 -0
- package/dist/types/components/truncated-text.d.ts +1 -0
- package/dist/types/fuzzy.d.ts +29 -1
- package/dist/types/key-hint-format.d.ts +1 -1
- package/dist/types/keybinding-matchers.d.ts +3 -0
- package/dist/types/keybindings.d.ts +1 -1
- package/dist/types/kitty-graphics.d.ts +2 -2
- package/dist/types/loop-watchdog.d.ts +8 -7
- package/dist/types/multiplexers/cmux.d.ts +16 -0
- package/dist/types/multiplexers/herdr.d.ts +26 -0
- package/dist/types/multiplexers/notify.d.ts +13 -0
- package/dist/types/multiplexers/orca.d.ts +12 -0
- package/dist/types/multiplexers/screen.d.ts +9 -0
- package/dist/types/multiplexers/tmux.d.ts +29 -0
- package/dist/types/multiplexers/types.d.ts +100 -0
- package/dist/types/multiplexers/wmux.d.ts +12 -0
- package/dist/types/multiplexers/zellij.d.ts +12 -0
- package/dist/types/native/backend.d.ts +3 -2
- package/dist/types/native/blobs.d.ts +7 -3
- package/dist/types/native/encode.d.ts +3 -4
- package/dist/types/native/overlay.d.ts +5 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
- package/dist/types/overlays/agent-hub-types.d.ts +9 -0
- package/dist/types/overlays/agent-hub.d.ts +2 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +11 -2
- package/dist/types/overlays/agents-hub.d.ts +9 -0
- package/dist/types/overlays/annotation-overlay.d.ts +19 -2
- package/dist/types/overlays/annotation-types.d.ts +2 -0
- package/dist/types/overlays/ask-dialog.d.ts +5 -2
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/jobs-panel.d.ts +1 -7
- package/dist/types/overlays/model-browser.d.ts +54 -7
- package/dist/types/overlays/model-hub.d.ts +23 -0
- package/dist/types/overlays/oauth-selector.d.ts +0 -1
- package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
- package/dist/types/overlays/session-observer-registry.d.ts +2 -0
- package/dist/types/overlays/session-selector.d.ts +6 -2
- package/dist/types/overlays/settings-defs.d.ts +1 -0
- package/dist/types/overlays/usage-dashboard.d.ts +8 -4
- package/dist/types/overlays/usage-display.d.ts +3 -1
- package/dist/types/prompt/composer.d.ts +2 -7
- package/dist/types/prompt/custom-editor.d.ts +11 -8
- package/dist/types/prompt/image-source.d.ts +2 -1
- package/dist/types/prompt/interactive-context-helpers.d.ts +4 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/prompt/welcome.d.ts +19 -42
- package/dist/types/render/composite.d.ts +2 -0
- package/dist/types/render/output-pane.d.ts +1 -0
- package/dist/types/render/render-utils.d.ts +1 -0
- package/dist/types/render/tool-card.d.ts +6 -0
- package/dist/types/render/width-aware-text.d.ts +2 -0
- package/dist/types/setup/scenes/splash.d.ts +1 -1
- package/dist/types/setup/scenes/types.d.ts +1 -0
- package/dist/types/status-line/component.d.ts +3 -0
- package/dist/types/status-line/host.d.ts +4 -1
- package/dist/types/status-line/segments.d.ts +2 -0
- package/dist/types/status-line/types.d.ts +14 -3
- package/dist/types/terminal-capabilities.d.ts +27 -35
- package/dist/types/terminal-multiplexer.d.ts +127 -14
- package/dist/types/terminal.d.ts +22 -6
- package/dist/types/theme/active-symbols.d.ts +1 -1
- package/dist/types/theme/schema.d.ts +11 -2
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme-class.d.ts +7 -0
- package/dist/types/theme/theme.d.ts +1 -1
- package/dist/types/theme/tui-adapters.d.ts +3 -0
- package/dist/types/tmux.d.ts +11 -4
- package/dist/types/tools/daemon.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +22 -3
- package/dist/types/tools/glob.d.ts +4 -0
- package/dist/types/tools/native-view.d.ts +47 -0
- package/dist/types/tools/output-meta.d.ts +11 -1
- package/dist/types/tools/renderer.d.ts +37 -2
- package/dist/types/tools/streaming-output.d.ts +20 -1
- package/dist/types/tools/task.d.ts +0 -4
- package/dist/types/tools/write.d.ts +9 -2
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +31 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vim.d.ts +19 -5
- package/package.json +13 -9
- package/src/app-keybindings.d.ts +1 -1
- package/src/app-keybindings.ts +1 -1
- package/src/apps/autoresearch-dashboard.ts +7 -3
- package/src/apps/cleanse-board.ts +2 -2
- package/src/apps/cleanse-picker.ts +1 -1
- package/src/apps/debug/log-viewer.ts +188 -72
- package/src/apps/debug/raw-sse-buffer.ts +8 -0
- package/src/apps/debug/raw-sse.ts +39 -5
- package/src/apps/git/diff-pane.ts +26 -5
- package/src/apps/git/git-tui.ts +2 -2
- package/src/apps/git/help.ts +29 -20
- package/src/apps/if-bench-board.ts +2 -2
- package/src/apps/ps-top.ts +2 -2
- package/src/apps/setup-model-picker.ts +1 -1
- package/src/autocomplete.d.ts +5 -2
- package/src/autocomplete.ts +67 -43
- package/src/charts/chart-plan.d.ts +674 -0
- package/src/charts/chart-plan.ts +5081 -0
- package/src/charts/chart-svg.d.ts +59 -0
- package/src/charts/chart-svg.ts +4657 -0
- package/src/charts/table-data.d.ts +175 -0
- package/src/charts/table-data.ts +1478 -0
- package/src/chat/advisor-message.ts +11 -0
- package/src/chat/assistant-message.d.ts +5 -0
- package/src/chat/assistant-message.ts +219 -50
- package/src/chat/chat-transcript-builder.d.ts +2 -0
- package/src/chat/chat-transcript-builder.ts +5 -3
- package/src/chat/compaction-summary-message.d.ts +1 -0
- package/src/chat/compaction-summary-message.ts +8 -0
- package/src/chat/execution-shared.d.ts +6 -5
- package/src/chat/execution-shared.ts +42 -25
- package/src/chat/fence-figure.d.ts +42 -0
- package/src/chat/fence-figure.ts +80 -0
- package/src/chat/figure-markdown.d.ts +42 -0
- package/src/chat/figure-markdown.ts +174 -0
- package/src/chat/messages.d.ts +1 -1
- package/src/chat/messages.ts +1 -1
- package/src/chat/read-tool-group.ts +6 -4
- package/src/chat/skill-message.ts +6 -0
- package/src/chat/svg-figure.d.ts +33 -0
- package/src/chat/svg-figure.ts +399 -0
- package/src/chat/svg-source.d.ts +49 -0
- package/src/chat/svg-source.ts +188 -0
- package/src/chat/table-chart.d.ts +89 -0
- package/src/chat/table-chart.ts +294 -0
- package/src/chat/tool-execution.d.ts +2 -0
- package/src/chat/tool-execution.ts +80 -6
- package/src/chat/user-message.d.ts +15 -2
- package/src/chat/user-message.ts +55 -3
- package/src/chrome/shared.ts +53 -0
- package/src/chrome/transcript-container.d.ts +6 -0
- package/src/chrome/transcript-container.ts +93 -13
- package/src/components/box.d.ts +1 -0
- package/src/components/box.ts +5 -0
- package/src/components/disclosure.d.ts +1 -0
- package/src/components/disclosure.ts +8 -0
- package/src/components/editor.d.ts +15 -4
- package/src/components/editor.ts +294 -46
- package/src/components/form.d.ts +1 -0
- package/src/components/form.ts +8 -0
- package/src/components/image.d.ts +12 -44
- package/src/components/image.ts +47 -151
- package/src/components/key-value-list.d.ts +1 -0
- package/src/components/key-value-list.ts +4 -0
- package/src/components/layout/row.d.ts +1 -0
- package/src/components/layout/row.ts +7 -0
- package/src/components/layout/stack.d.ts +1 -0
- package/src/components/layout/stack.ts +7 -0
- package/src/components/markdown.d.ts +36 -3
- package/src/components/markdown.ts +433 -318
- package/src/components/scroll-view.d.ts +1 -0
- package/src/components/scroll-view.ts +5 -0
- package/src/components/section.d.ts +1 -0
- package/src/components/section.ts +5 -0
- package/src/components/settings-list.ts +2 -0
- package/src/components/table.d.ts +1 -0
- package/src/components/table.ts +4 -0
- package/src/components/text.d.ts +1 -0
- package/src/components/text.ts +7 -0
- package/src/components/tree-view.d.ts +7 -0
- package/src/components/tree-view.ts +38 -8
- package/src/components/truncated-text.d.ts +1 -0
- package/src/components/truncated-text.ts +5 -0
- package/src/desktop-notify.ts +1 -1
- package/src/fuzzy.d.ts +29 -1
- package/src/fuzzy.ts +115 -30
- package/src/key-hint-format.d.ts +1 -1
- package/src/key-hint-format.ts +1 -1
- package/src/keybinding-matchers.d.ts +3 -0
- package/src/keybinding-matchers.ts +6 -2
- package/src/keybindings.d.ts +1 -1
- package/src/keybindings.ts +1 -1
- package/src/kitty-graphics.d.ts +2 -2
- package/src/kitty-graphics.ts +4 -4
- package/src/loop-watchdog.d.ts +8 -7
- package/src/loop-watchdog.ts +18 -13
- package/src/multiplexers/cmux.d.ts +16 -0
- package/src/multiplexers/cmux.ts +29 -0
- package/src/multiplexers/herdr.d.ts +26 -0
- package/src/multiplexers/herdr.ts +64 -0
- package/src/multiplexers/notify.d.ts +13 -0
- package/src/multiplexers/notify.ts +24 -0
- package/src/multiplexers/orca.d.ts +12 -0
- package/src/multiplexers/orca.ts +16 -0
- package/src/multiplexers/screen.d.ts +9 -0
- package/src/multiplexers/screen.ts +15 -0
- package/src/multiplexers/tmux.d.ts +29 -0
- package/src/multiplexers/tmux.ts +40 -0
- package/src/multiplexers/types.d.ts +100 -0
- package/src/multiplexers/types.ts +110 -0
- package/src/multiplexers/wmux.d.ts +12 -0
- package/src/multiplexers/wmux.ts +16 -0
- package/src/multiplexers/zellij.d.ts +12 -0
- package/src/multiplexers/zellij.ts +24 -0
- package/src/native/backend.d.ts +3 -2
- package/src/native/backend.ts +174 -18
- package/src/native/blobs.d.ts +7 -3
- package/src/native/blobs.ts +47 -12
- package/src/native/encode.d.ts +3 -4
- package/src/native/encode.ts +58 -31
- package/src/native/overlay.d.ts +5 -0
- package/src/native/overlay.ts +13 -0
- package/src/native/reconcile.ts +4 -0
- package/src/overlays/agent-hub-projection.d.ts +6 -5
- package/src/overlays/agent-hub-projection.ts +124 -13
- package/src/overlays/agent-hub-types.d.ts +9 -0
- package/src/overlays/agent-hub-types.ts +6 -0
- package/src/overlays/agent-hub.ts +46 -31
- package/src/overlays/agent-transcript-viewer.ts +91 -23
- package/src/overlays/agents-hub.ts +28 -8
- package/src/overlays/annotation-overlay.ts +293 -90
- package/src/overlays/annotation-types.ts +2 -0
- package/src/overlays/ask-dialog.ts +7 -10
- package/src/overlays/btw-history-panel.ts +12 -1
- package/src/overlays/copy-selector.ts +30 -8
- package/src/overlays/extensions/state-manager.ts +52 -12
- package/src/overlays/history-search.ts +100 -7
- package/src/overlays/hook-selector.ts +12 -5
- package/src/overlays/jobs-panel.ts +28 -46
- package/src/overlays/model-browser.ts +341 -110
- package/src/overlays/model-hub.ts +300 -49
- package/src/overlays/move-overlay.ts +28 -14
- package/src/overlays/oauth-selector.ts +54 -70
- package/src/overlays/plan-review-overlay.ts +194 -70
- package/src/overlays/plugin-settings.ts +11 -5
- package/src/overlays/report-panel.ts +2 -2
- package/src/overlays/rewind-selector.ts +86 -17
- package/src/overlays/session-observer-registry.d.ts +2 -0
- package/src/overlays/session-observer-registry.ts +10 -2
- package/src/overlays/session-selector.ts +64 -26
- package/src/overlays/settings-defs.ts +4 -3
- package/src/overlays/settings-selector.ts +33 -8
- package/src/overlays/snapcompact-shape-preview.ts +2 -3
- package/src/overlays/stats-notice.ts +1 -1
- package/src/overlays/tree-selector.ts +41 -20
- package/src/overlays/usage-dashboard.ts +100 -50
- package/src/overlays/usage-display.ts +10 -4
- package/src/prompt/attachment-chips.ts +15 -11
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer-cache.ts +4 -6
- package/src/prompt/composer.ts +6 -37
- package/src/prompt/custom-editor.ts +54 -26
- package/src/prompt/image-source.ts +2 -1
- package/src/prompt/interactive-context-helpers.ts +30 -18
- package/src/prompt/macos-spelling.ts +7 -0
- package/src/prompt/magic-keywords.ts +11 -2
- package/src/prompt/model-mention-autocomplete.ts +14 -14
- package/src/prompt/tips.txt +6 -5
- package/src/prompt/welcome.ts +235 -411
- package/src/prompt/word-completion.ts +38 -5
- package/src/render/composite.d.ts +2 -0
- package/src/render/composite.ts +64 -0
- package/src/render/output-pane.d.ts +1 -0
- package/src/render/output-pane.ts +6 -0
- package/src/render/render-utils.d.ts +1 -0
- package/src/render/render-utils.ts +11 -0
- package/src/render/tool-card.d.ts +6 -0
- package/src/render/tool-card.ts +15 -0
- package/src/render/width-aware-text.d.ts +2 -0
- package/src/render/width-aware-text.ts +5 -0
- package/src/setup/scenes/model.ts +2 -1
- package/src/setup/scenes/splash.ts +116 -53
- package/src/setup/scenes/types.ts +1 -0
- package/src/status-line/component.ts +292 -78
- package/src/status-line/host.ts +4 -1
- package/src/status-line/segments.ts +40 -22
- package/src/status-line/types.ts +15 -3
- package/src/terminal-capabilities.d.ts +27 -35
- package/src/terminal-capabilities.ts +75 -189
- package/src/terminal-multiplexer.d.ts +127 -14
- package/src/terminal-multiplexer.ts +112 -33
- package/src/terminal.d.ts +22 -6
- package/src/terminal.ts +139 -37
- package/src/theme/active-symbols.d.ts +1 -1
- package/src/theme/active-symbols.ts +1 -1
- package/src/theme/schema-validation.ts +1 -0
- package/src/theme/schema.d.ts +11 -2
- package/src/theme/schema.ts +14 -1
- package/src/theme/session-color.ts +1 -7
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +6 -1
- package/src/theme/theme-class.d.ts +7 -0
- package/src/theme/theme-class.ts +26 -1
- package/src/theme/theme-schema.json +5 -1
- package/src/theme/theme.d.ts +1 -1
- package/src/theme/theme.ts +8 -4
- package/src/theme/tui-adapters.d.ts +3 -0
- package/src/theme/tui-adapters.ts +68 -0
- package/src/tmux.d.ts +11 -4
- package/src/tmux.ts +47 -11
- package/src/tools/ast-edit.ts +59 -35
- package/src/tools/ast-grep.ts +35 -16
- package/src/tools/bash.ts +92 -42
- package/src/tools/daemon.d.ts +1 -1
- package/src/tools/daemon.ts +1 -1
- package/src/tools/default-renderer.ts +35 -19
- package/src/tools/edit.ts +142 -120
- package/src/tools/eval-format/index.ts +28 -2
- package/src/tools/eval-format/javascript.ts +7 -5
- package/src/tools/eval.d.ts +22 -3
- package/src/tools/eval.ts +364 -208
- package/src/tools/fetch.ts +5 -6
- package/src/tools/glob.d.ts +4 -0
- package/src/tools/glob.ts +33 -65
- package/src/tools/grep.ts +81 -48
- package/src/tools/index.ts +2 -0
- package/src/tools/lsp.ts +81 -59
- package/src/tools/mcp.ts +111 -68
- package/src/tools/native-view.d.ts +47 -0
- package/src/tools/native-view.ts +102 -1
- package/src/tools/output-meta.d.ts +11 -1
- package/src/tools/output-meta.ts +23 -3
- package/src/tools/read.ts +7 -5
- package/src/tools/renderer.d.ts +37 -2
- package/src/tools/renderer.ts +42 -2
- package/src/tools/streaming-output.d.ts +20 -1
- package/src/tools/streaming-output.ts +149 -50
- package/src/tools/task.d.ts +0 -4
- package/src/tools/task.ts +112 -59
- package/src/tools/todo.ts +119 -30
- package/src/tools/wait.ts +34 -24
- package/src/tools/web-search.ts +1 -1
- package/src/tools/write.d.ts +9 -2
- package/src/tools/write.ts +147 -95
- package/src/tools/yield.d.ts +22 -0
- package/src/tools/yield.ts +225 -0
- package/src/tui.d.ts +31 -0
- package/src/tui.ts +309 -160
- package/src/utils.d.ts +6 -0
- package/src/utils.ts +19 -0
- package/src/vim.d.ts +19 -5
- package/src/vim.ts +333 -18
- package/src/windows-input-mode.ts +8 -0
|
@@ -56,9 +56,20 @@ interface WordQuery extends WordCompletionQuery {
|
|
|
56
56
|
|
|
57
57
|
/** Editor text before the word starting at `start`, truncated to its last {@link BEFORE_LIMIT} code units. */
|
|
58
58
|
function textBefore(lines: readonly string[], cursorLine: number, start: number): string {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
const head = (lines[cursorLine] ?? "").slice(0, start);
|
|
60
|
+
// Find the first line the capped tail reaches, then join once.
|
|
61
|
+
let length = head.length;
|
|
62
|
+
let first = cursorLine;
|
|
63
|
+
while (first > 0 && length < BEFORE_LIMIT) {
|
|
64
|
+
first--;
|
|
65
|
+
length += (lines[first] ?? "").length + 1;
|
|
66
|
+
}
|
|
67
|
+
let text = head;
|
|
68
|
+
if (first < cursorLine) {
|
|
69
|
+
const parts: string[] = [];
|
|
70
|
+
for (let line = first; line < cursorLine; line++) parts.push(lines[line] ?? "");
|
|
71
|
+
parts.push(head);
|
|
72
|
+
text = parts.join("\n");
|
|
62
73
|
}
|
|
63
74
|
if (text.length <= BEFORE_LIMIT) return text;
|
|
64
75
|
let cut = text.length - BEFORE_LIMIT;
|
|
@@ -111,6 +122,16 @@ export class WordCompletionProvider implements EditorTextAssistProvider {
|
|
|
111
122
|
#lastShown: { before: string; word: string } | undefined;
|
|
112
123
|
/** What the last `getWordCompletion` returned, so a fetch repaints only when it changes that. */
|
|
113
124
|
#displayed: { key: string; suffix: string | null } | undefined;
|
|
125
|
+
/** Last {@link #query} input snapshot (lines are copied: the editor mutates its array in place). */
|
|
126
|
+
#queryMemo:
|
|
127
|
+
| {
|
|
128
|
+
method: WordCompletionMethod;
|
|
129
|
+
lines: readonly string[];
|
|
130
|
+
cursorLine: number;
|
|
131
|
+
cursorCol: number;
|
|
132
|
+
query: WordQuery | undefined;
|
|
133
|
+
}
|
|
134
|
+
| undefined;
|
|
114
135
|
|
|
115
136
|
/** Invoked when an asynchronous answer changes the rendered ghost text. */
|
|
116
137
|
onUpdate: (() => void) | undefined;
|
|
@@ -171,11 +192,23 @@ export class WordCompletionProvider implements EditorTextAssistProvider {
|
|
|
171
192
|
|
|
172
193
|
#query(lines: readonly string[], cursorLine: number, cursorCol: number): WordQuery | undefined {
|
|
173
194
|
if (this.#method === "off") return undefined;
|
|
195
|
+
// Rendering asks every frame; reuse the answer until the buffer, caret, or engine changes.
|
|
196
|
+
const memo = this.#queryMemo;
|
|
197
|
+
if (
|
|
198
|
+
memo?.method === this.#method &&
|
|
199
|
+
memo.cursorLine === cursorLine &&
|
|
200
|
+
memo.cursorCol === cursorCol &&
|
|
201
|
+
memo.lines.length === lines.length &&
|
|
202
|
+
memo.lines.every((line, index) => line === lines[index])
|
|
203
|
+
) {
|
|
204
|
+
return memo.query;
|
|
205
|
+
}
|
|
174
206
|
const query = wordCompletionQuery(lines, cursorLine, cursorCol, this.#prose);
|
|
175
|
-
if (!query) return undefined;
|
|
176
207
|
// The method keeps a request still in flight for the previous engine from
|
|
177
208
|
// shadowing the same word state on the new one.
|
|
178
|
-
|
|
209
|
+
const result = query && { key: `${this.#method}\u0000${query.prefix}\u0000${query.before}`, ...query };
|
|
210
|
+
this.#queryMemo = { method: this.#method, lines: lines.slice(), cursorLine, cursorCol, query: result };
|
|
211
|
+
return result;
|
|
179
212
|
}
|
|
180
213
|
|
|
181
214
|
#project(query: WordQuery): string | null {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { TERMINAL } from "../terminal-capabilities";
|
|
2
|
+
import { extractSegments, sliceByColumn, sliceWithWidth, visibleWidth } from "../utils";
|
|
3
|
+
|
|
4
|
+
const SEGMENT_RESET = "\x1b[0m";
|
|
5
|
+
|
|
6
|
+
/** Splice overlay content into a base line at a specific column. Single-pass optimized. */
|
|
7
|
+
export function compositeLineAt(
|
|
8
|
+
baseLine: string,
|
|
9
|
+
overlayLine: string,
|
|
10
|
+
startCol: number,
|
|
11
|
+
overlayWidth: number,
|
|
12
|
+
totalWidth: number,
|
|
13
|
+
): string {
|
|
14
|
+
// A full-width image row owns its terminal row; the writer must see its exact placement shape.
|
|
15
|
+
if (startCol === 0 && overlayWidth >= totalWidth && TERMINAL.isImageLine(overlayLine)) return overlayLine;
|
|
16
|
+
if (TERMINAL.isImageLine(baseLine)) {
|
|
17
|
+
// Full-width overlays such as /switch are opaque: replace the
|
|
18
|
+
// Unicode placeholder cells so the image cannot cover the modal.
|
|
19
|
+
// Partial overlays cannot safely splice placement control sequences.
|
|
20
|
+
if (startCol !== 0 || overlayWidth < totalWidth) return baseLine;
|
|
21
|
+
const overlay = sliceWithWidth(overlayLine, 0, totalWidth, true);
|
|
22
|
+
return SEGMENT_RESET + overlay.text + " ".repeat(Math.max(0, totalWidth - overlay.width));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Single pass through baseLine extracts both before and after segments
|
|
26
|
+
const afterStart = startCol + overlayWidth;
|
|
27
|
+
const base = extractSegments(baseLine, startCol, afterStart, totalWidth - afterStart, true);
|
|
28
|
+
|
|
29
|
+
// Extract overlay with width tracking (strict=true to exclude wide chars at boundary)
|
|
30
|
+
const overlay = sliceWithWidth(overlayLine, 0, overlayWidth, true);
|
|
31
|
+
|
|
32
|
+
// Pad segments to target widths
|
|
33
|
+
const beforePad = Math.max(0, startCol - base.beforeWidth);
|
|
34
|
+
const overlayPad = Math.max(0, overlayWidth - overlay.width);
|
|
35
|
+
const actualBeforeWidth = Math.max(startCol, base.beforeWidth);
|
|
36
|
+
const actualOverlayWidth = Math.max(overlayWidth, overlay.width);
|
|
37
|
+
const afterTarget = Math.max(0, totalWidth - actualBeforeWidth - actualOverlayWidth);
|
|
38
|
+
const afterPad = Math.max(0, afterTarget - base.afterWidth);
|
|
39
|
+
|
|
40
|
+
// Compose result
|
|
41
|
+
const r = SEGMENT_RESET;
|
|
42
|
+
const result =
|
|
43
|
+
base.before +
|
|
44
|
+
" ".repeat(beforePad) +
|
|
45
|
+
r +
|
|
46
|
+
overlay.text +
|
|
47
|
+
" ".repeat(overlayPad) +
|
|
48
|
+
r +
|
|
49
|
+
base.after +
|
|
50
|
+
" ".repeat(afterPad);
|
|
51
|
+
|
|
52
|
+
// CRITICAL: Always verify and truncate to terminal width.
|
|
53
|
+
// This is the final safeguard against width overflow which would crash the TUI.
|
|
54
|
+
// Width tracking can drift from actual visible width due to:
|
|
55
|
+
// - Complex ANSI/OSC sequences (hyperlinks, colors)
|
|
56
|
+
// - Wide characters at segment boundaries
|
|
57
|
+
// - Edge cases in segment extraction
|
|
58
|
+
const resultWidth = visibleWidth(result);
|
|
59
|
+
if (resultWidth <= totalWidth) {
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
// Truncate with strict=true to ensure we don't exceed totalWidth
|
|
63
|
+
return sliceByColumn(result, 0, totalWidth, true);
|
|
64
|
+
}
|
|
@@ -92,6 +92,7 @@ export declare class OutputPane implements Component {
|
|
|
92
92
|
describe(_cx: DescribeContext): NativeNode;
|
|
93
93
|
render(width: number): readonly string[];
|
|
94
94
|
invalidate(): void;
|
|
95
|
+
releaseRenderCaches(): void;
|
|
95
96
|
}
|
|
96
97
|
/** Default styling for plain tool output while preserving existing ANSI. */
|
|
97
98
|
export declare function styleToolOutputLine(line: string, theme: Theme): string;
|
|
@@ -302,6 +302,12 @@ export class OutputPane implements Component {
|
|
|
302
302
|
this.#text.invalidate();
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
releaseRenderCaches(): void {
|
|
306
|
+
this.#renderKey = "";
|
|
307
|
+
this.#text.setText("");
|
|
308
|
+
this.#text.releaseRenderCaches();
|
|
309
|
+
}
|
|
310
|
+
|
|
305
311
|
#appendToTail(text: string): void {
|
|
306
312
|
if (!text) return;
|
|
307
313
|
if (this.#lines.length === 0) this.#lines.push("");
|
|
@@ -298,6 +298,7 @@ export interface RenderedStringCache {
|
|
|
298
298
|
export declare function createRenderedStringCache(): RenderedStringCache;
|
|
299
299
|
/** Drop the memo so the next lookup re-renders (e.g. the render function identity changed). */
|
|
300
300
|
export declare function invalidateRenderedStringCache(cache: RenderedStringCache): void;
|
|
301
|
+
export declare function releaseRenderedStringCache(cache: RenderedStringCache): void;
|
|
301
302
|
/** Reuse a rendered string while its theme, expansion, content, and salt match. */
|
|
302
303
|
export declare function cachedRenderedString(cache: RenderedStringCache | undefined, theme: Theme, expanded: boolean, salt: string, content: string, render: () => string): string;
|
|
303
304
|
/**
|
|
@@ -1128,6 +1128,9 @@ export function createCachedComponent(
|
|
|
1128
1128
|
invalidate() {
|
|
1129
1129
|
cached = undefined;
|
|
1130
1130
|
},
|
|
1131
|
+
releaseRenderCaches() {
|
|
1132
|
+
cached = undefined;
|
|
1133
|
+
},
|
|
1131
1134
|
};
|
|
1132
1135
|
}
|
|
1133
1136
|
|
|
@@ -1160,6 +1163,14 @@ export function invalidateRenderedStringCache(cache: RenderedStringCache): void
|
|
|
1160
1163
|
cache.theme = null;
|
|
1161
1164
|
}
|
|
1162
1165
|
|
|
1166
|
+
export function releaseRenderedStringCache(cache: RenderedStringCache): void {
|
|
1167
|
+
cache.theme = null;
|
|
1168
|
+
cache.expanded = false;
|
|
1169
|
+
cache.salt = "";
|
|
1170
|
+
cache.content = "";
|
|
1171
|
+
cache.value = "";
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1163
1174
|
/** Reuse a rendered string while its theme, expansion, content, and salt match. */
|
|
1164
1175
|
export function cachedRenderedString(
|
|
1165
1176
|
cache: RenderedStringCache | undefined,
|
|
@@ -46,6 +46,11 @@ export interface ToolCardOptions {
|
|
|
46
46
|
paddingY?: number;
|
|
47
47
|
ignoreTight?: boolean;
|
|
48
48
|
onInvalidate?: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Drop builder-owned memos the next build recomputes. Called by
|
|
51
|
+
* {@link ToolCard.releaseRenderCaches}, which never calls `onInvalidate`.
|
|
52
|
+
*/
|
|
53
|
+
onReleaseRenderCaches?: () => void;
|
|
49
54
|
onDispose?: () => void;
|
|
50
55
|
}
|
|
51
56
|
/** Map transcript lifecycle terminology onto the output frame's visual states. */
|
|
@@ -71,6 +76,7 @@ export declare class ToolCard implements Component {
|
|
|
71
76
|
handleInput(data: string): void;
|
|
72
77
|
setIgnoreTight(ignore: boolean): void;
|
|
73
78
|
invalidate(): void;
|
|
79
|
+
releaseRenderCaches(): void;
|
|
74
80
|
dispose(): void;
|
|
75
81
|
}
|
|
76
82
|
/** Construct a lazy framed tool card. */
|
package/src/render/tool-card.ts
CHANGED
|
@@ -69,6 +69,11 @@ export interface ToolCardOptions {
|
|
|
69
69
|
paddingY?: number;
|
|
70
70
|
ignoreTight?: boolean;
|
|
71
71
|
onInvalidate?: () => void;
|
|
72
|
+
/**
|
|
73
|
+
* Drop builder-owned memos the next build recomputes. Called by
|
|
74
|
+
* {@link ToolCard.releaseRenderCaches}, which never calls `onInvalidate`.
|
|
75
|
+
*/
|
|
76
|
+
onReleaseRenderCaches?: () => void;
|
|
72
77
|
onDispose?: () => void;
|
|
73
78
|
}
|
|
74
79
|
|
|
@@ -381,6 +386,16 @@ export class ToolCard implements Component {
|
|
|
381
386
|
this.#options.onInvalidate?.();
|
|
382
387
|
}
|
|
383
388
|
|
|
389
|
+
releaseRenderCaches(): void {
|
|
390
|
+
this.#block.invalidate();
|
|
391
|
+
this.#lastBlockOptions = undefined;
|
|
392
|
+
this.#plainKey = "";
|
|
393
|
+
this.#plainText.setText("");
|
|
394
|
+
this.#plainText.releaseRenderCaches();
|
|
395
|
+
for (const child of this.#renderedChildren) child.releaseRenderCaches?.();
|
|
396
|
+
this.#options.onReleaseRenderCaches?.();
|
|
397
|
+
}
|
|
398
|
+
|
|
384
399
|
dispose(): void {
|
|
385
400
|
if (this.#disposed) return;
|
|
386
401
|
this.#disposed = true;
|
|
@@ -20,6 +20,8 @@ export declare class WidthAwareText implements Component {
|
|
|
20
20
|
setCustomBgFn(customBgFn?: (text: string) => string): void;
|
|
21
21
|
setIgnoreTight(ignore: boolean): this;
|
|
22
22
|
invalidate(): void;
|
|
23
|
+
/** The formatted text stays: the inner `Text` renders from it, so dropping it would free nothing. */
|
|
24
|
+
releaseRenderCaches(): void;
|
|
23
25
|
/**
|
|
24
26
|
* Re-run the formatter on the next render because its inputs changed.
|
|
25
27
|
* Unlike {@link invalidate}, the inner `Text` keeps its wrap cache, so a
|
|
@@ -51,6 +51,11 @@ export class WidthAwareText implements Component {
|
|
|
51
51
|
this.#inner.invalidate();
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/** The formatted text stays: the inner `Text` renders from it, so dropping it would free nothing. */
|
|
55
|
+
releaseRenderCaches(): void {
|
|
56
|
+
this.#inner.releaseRenderCaches();
|
|
57
|
+
}
|
|
58
|
+
|
|
54
59
|
/**
|
|
55
60
|
* Re-run the formatter on the next render because its inputs changed.
|
|
56
61
|
* Unlike {@link invalidate}, the inner `Text` keeps its wrap cache, so a
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Model } from "@linxiraos/pi-ai";
|
|
2
|
+
import { modelKind } from "@linxiraos/pi-catalog/types";
|
|
2
3
|
import type { SgrMouseEvent } from "../../mouse";
|
|
3
4
|
import { Text } from "../../components/text";
|
|
4
5
|
import { WizardStep } from "../../components/wizard-step";
|
|
@@ -114,7 +115,7 @@ class ModelSceneController implements SetupSceneController {
|
|
|
114
115
|
const { available, all, current } = this.#host.ctx.getModels();
|
|
115
116
|
const source = this.#host.ctx.modelSource;
|
|
116
117
|
const roles = resolveRoleAssignments(source, all, available);
|
|
117
|
-
const items = buildBrowserItems(available);
|
|
118
|
+
const items = buildBrowserItems(available.filter(model => modelKind(model) === "chat"));
|
|
118
119
|
sortModelItems(items, { roles, mruOrder: source.mruOrder });
|
|
119
120
|
this.#browser.setRoles(roles);
|
|
120
121
|
this.#browser.setMruOrder(source.mruOrder);
|
|
@@ -27,18 +27,11 @@ const RESET = "\x1b[0m";
|
|
|
27
27
|
const MIN_SCENE_WIDTH = 56;
|
|
28
28
|
const MIN_SCENE_HEIGHT = 22;
|
|
29
29
|
|
|
30
|
+
/** Skip affordance; built at render time so it follows the live symbol preset. */
|
|
30
31
|
function skipHint(): string {
|
|
31
|
-
return
|
|
32
|
+
return tuiText("setupSkipHint", "press {key} to skip").replace("{key}", formatKeyHint("enter"));
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
/** Density ramp for the rippling water, lightest → heaviest. */
|
|
35
|
-
const WATER_RAMP = [
|
|
36
|
-
{ min: 0.62, char: "█" },
|
|
37
|
-
{ min: 0.5, char: "▓" },
|
|
38
|
-
{ min: 0.36, char: "▒" },
|
|
39
|
-
{ min: 0.24, char: "░" },
|
|
40
|
-
];
|
|
41
|
-
|
|
42
35
|
function starAt(x: number, y: number, frame: number): string {
|
|
43
36
|
const hash = (x * 73856093) ^ (y * 19349663) ^ (frame * 83492791);
|
|
44
37
|
const bucket = Math.abs(hash) % 97;
|
|
@@ -85,35 +78,88 @@ function waterJitter(x: number, y: number): number {
|
|
|
85
78
|
}
|
|
86
79
|
|
|
87
80
|
/**
|
|
88
|
-
*
|
|
89
|
-
* interfere, then a radial edge falloff and a downward
|
|
90
|
-
* ripples beneath the mark and dissolve them toward the
|
|
91
|
-
*
|
|
81
|
+
* Time-invariant terms of the rippling water for one screen size: three
|
|
82
|
+
* travelling sine waves interfere, then a radial edge falloff and a downward
|
|
83
|
+
* fade concentrate the ripples beneath the mark and dissolve them toward the
|
|
84
|
+
* edges/bottom. Only the sine phases move per tick, so everything else is
|
|
85
|
+
* computed once per size.
|
|
92
86
|
*/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
waterTop:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
87
|
+
interface WaterField {
|
|
88
|
+
readonly width: number;
|
|
89
|
+
readonly height: number;
|
|
90
|
+
readonly waterTop: number;
|
|
91
|
+
/** Per cell (row-major from `waterTop`): `dist * 0.55`. */
|
|
92
|
+
readonly radial: Float64Array;
|
|
93
|
+
/** Per cell: `x * 0.22 + y * 0.45`. */
|
|
94
|
+
readonly diagonal: Float64Array;
|
|
95
|
+
/** Per cell: `|dx| * 0.8 + dy * 0.5`. */
|
|
96
|
+
readonly cross: Float64Array;
|
|
97
|
+
/** Per cell: `(waterJitter(x, y) - 0.5) * 0.06`. */
|
|
98
|
+
readonly jitter: Float64Array;
|
|
99
|
+
/** Per column: `edge ** 0.7`. */
|
|
100
|
+
readonly edge: Float64Array;
|
|
101
|
+
/** Per water row: downward fade. */
|
|
102
|
+
readonly fade: Float64Array;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let waterField: WaterField | undefined;
|
|
106
|
+
|
|
107
|
+
function getWaterField(width: number, height: number, cx: number, waterTop: number): WaterField {
|
|
108
|
+
const cached = waterField;
|
|
109
|
+
if (cached && cached.width === width && cached.height === height && cached.waterTop === waterTop) return cached;
|
|
110
|
+
const waterHeight = Math.max(1, height - waterTop);
|
|
111
|
+
const rows = Math.max(0, height - waterTop);
|
|
112
|
+
const radial = new Float64Array(rows * width);
|
|
113
|
+
const diagonal = new Float64Array(rows * width);
|
|
114
|
+
const cross = new Float64Array(rows * width);
|
|
115
|
+
const jitter = new Float64Array(rows * width);
|
|
116
|
+
const edge = new Float64Array(width);
|
|
117
|
+
const fade = new Float64Array(rows);
|
|
118
|
+
for (let x = 0; x < width; x++) edge[x] = Math.max(0, 1 - Math.abs(x - cx) / (width * 0.5)) ** 0.7;
|
|
119
|
+
for (let row = 0; row < rows; row++) {
|
|
120
|
+
const y = waterTop + row;
|
|
121
|
+
const dy = y - waterTop;
|
|
122
|
+
fade[row] = Math.max(0, 1 - (dy / waterHeight) * 0.55);
|
|
123
|
+
for (let x = 0; x < width; x++) {
|
|
124
|
+
const i = row * width + x;
|
|
125
|
+
const dx = (x - cx) / 2;
|
|
126
|
+
radial[i] = Math.sqrt(dx * dx + dy * dy) * 0.55;
|
|
127
|
+
diagonal[i] = x * 0.22 + y * 0.45;
|
|
128
|
+
cross[i] = Math.abs(dx) * 0.8 + dy * 0.5;
|
|
129
|
+
jitter[i] = (waterJitter(x, y) - 0.5) * 0.06;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
waterField = { width, height, waterTop, radial, diagonal, cross, jitter, edge, fade };
|
|
133
|
+
return waterField;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Water glyph for an amplitude, lightest → heaviest density ramp; undefined below the floor. */
|
|
137
|
+
function waterChar(amp: number): string | undefined {
|
|
138
|
+
if (amp > 0.62) return "█";
|
|
139
|
+
if (amp > 0.5) return "▓";
|
|
140
|
+
if (amp > 0.36) return "▒";
|
|
141
|
+
if (amp > 0.24) return "░";
|
|
142
|
+
return undefined;
|
|
113
143
|
}
|
|
114
144
|
|
|
145
|
+
/** Reused cell grid; resized when the screen changes. */
|
|
146
|
+
let splashCells: string[][] = [];
|
|
147
|
+
|
|
148
|
+
function resetCells(width: number, height: number): string[][] {
|
|
149
|
+
if (splashCells.length !== height || splashCells[0]?.length !== width) {
|
|
150
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
151
|
+
splashCells = Array.from({ length: height }, () => new Array<string>(width).fill(" "));
|
|
152
|
+
} else {
|
|
153
|
+
for (const row of splashCells) row.fill(" ");
|
|
154
|
+
}
|
|
155
|
+
return splashCells;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Per-frame gradient escapes, one per screen diagonal (the gradient only varies along it). */
|
|
159
|
+
let diagonalEscapes: (string | undefined)[] = [];
|
|
160
|
+
|
|
115
161
|
/**
|
|
116
|
-
* Animated setup splash, in the spirit of the
|
|
162
|
+
* Animated setup splash, in the spirit of the Zeta visual identity: the brand ζ
|
|
117
163
|
* mark rendered with the live diagonal gradient + shine sweep, rising out of a
|
|
118
164
|
* rippling, gradient-lit water surface, under a faint twinkling starfield. The
|
|
119
165
|
* mark and water share one continuous gradient so the sweep reads across the
|
|
@@ -132,23 +178,46 @@ export function renderSetupSplash(width: number, height: number, elapsedMs: numb
|
|
|
132
178
|
const cx = Math.floor(w / 2);
|
|
133
179
|
const surfaceTime = frame * 0.13;
|
|
134
180
|
|
|
135
|
-
|
|
136
|
-
const cells: string[][] = Array.from({ length: h }, () => new Array<string>(w).fill(" "));
|
|
181
|
+
const cells = resetCells(w, h);
|
|
137
182
|
const put = (x: number, y: number, glyph: string): void => {
|
|
138
183
|
if (y >= 0 && y < h && x >= 0 && x < w) cells[y][x] = glyph;
|
|
139
184
|
};
|
|
185
|
+
// Every cell on a diagonal shares one gradient position, so resolve each
|
|
186
|
+
// escape once per frame instead of once per cell.
|
|
187
|
+
const diagonals = w + h - 1;
|
|
188
|
+
if (diagonalEscapes.length !== diagonals) diagonalEscapes = Array.from({ length: diagonals });
|
|
189
|
+
else diagonalEscapes.fill(undefined);
|
|
190
|
+
const escapes = diagonalEscapes;
|
|
191
|
+
const gradient = (x: number, y: number): string => {
|
|
192
|
+
const d = x + (h - 1 - y);
|
|
193
|
+
let escape = escapes[d];
|
|
194
|
+
if (escape === undefined) {
|
|
195
|
+
escape = gradientEscape(screenGradientT(x, y, w, h, phase), shine);
|
|
196
|
+
escapes[d] = escape;
|
|
197
|
+
}
|
|
198
|
+
return escape;
|
|
199
|
+
};
|
|
140
200
|
|
|
141
201
|
const hx = Math.floor((w - LOGO_WIDTH) / 2);
|
|
142
202
|
const hy = Math.max(2, Math.floor(h * 0.16));
|
|
143
203
|
const waterTop = hy + LOGO_HEIGHT;
|
|
144
|
-
const waterHeight = Math.max(1, h - waterTop);
|
|
145
204
|
|
|
146
205
|
// 1. rippling water surface (shares the screen-wide gradient with the mark)
|
|
206
|
+
const field = getWaterField(w, h, cx, waterTop);
|
|
207
|
+
const tDiagonal = surfaceTime * 0.7;
|
|
208
|
+
const tCross = surfaceTime * 1.4;
|
|
147
209
|
for (let y = waterTop; y < h; y++) {
|
|
210
|
+
const row = y - waterTop;
|
|
211
|
+
const fade = field.fade[row];
|
|
148
212
|
for (let x = 0; x < w; x++) {
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
|
|
213
|
+
const i = row * w + x;
|
|
214
|
+
const wave =
|
|
215
|
+
0.5 * Math.sin(field.radial[i] - surfaceTime) +
|
|
216
|
+
0.3 * Math.sin(field.diagonal[i] - tDiagonal) +
|
|
217
|
+
0.2 * Math.sin(field.cross[i] - tCross);
|
|
218
|
+
const level = 0.5 + 0.5 * wave;
|
|
219
|
+
const char = waterChar(level * field.edge[x] * fade + field.jitter[i]);
|
|
220
|
+
if (char) cells[y][x] = gradient(x, y) + char + RESET;
|
|
152
221
|
}
|
|
153
222
|
}
|
|
154
223
|
// 2. twinkling starfield in the sky above the water
|
|
@@ -162,18 +231,15 @@ export function renderSetupSplash(width: number, height: number, elapsedMs: numb
|
|
|
162
231
|
LARGE_LOGO.forEach((line, row) => {
|
|
163
232
|
let col = 0;
|
|
164
233
|
for (const ch of line) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
hy + row,
|
|
169
|
-
gradientEscape(screenGradientT(hx + col, hy + row, w, h, phase), shine) + ch + RESET,
|
|
170
|
-
);
|
|
171
|
-
}
|
|
234
|
+
const x = hx + col;
|
|
235
|
+
const y = hy + row;
|
|
236
|
+
if (ch !== " " && y >= 0 && y < h && x >= 0 && x < w) cells[y][x] = gradient(x, y) + ch + RESET;
|
|
172
237
|
col++;
|
|
173
238
|
}
|
|
174
239
|
});
|
|
175
|
-
// 4. skip hint on a cleared strip at the bottom so it stays legible over the water
|
|
176
|
-
|
|
240
|
+
// 4. skip hint on a cleared strip at the bottom so it stays legible over the water.
|
|
241
|
+
// `formatKeyHint` yields plain glyphs (no ANSI), so per-character dim styling is safe.
|
|
242
|
+
const hint = skipHint();
|
|
177
243
|
const hintWidth = visibleWidth(hint);
|
|
178
244
|
const hintStart = Math.floor((w - hintWidth) / 2);
|
|
179
245
|
const hintRow = h - 1;
|
|
@@ -219,9 +285,6 @@ function renderCompactSplash(width: number, height: number, phase: number, shine
|
|
|
219
285
|
lines.push(width > 0 ? padToWidth(item !== undefined ? centerLine(item, width) : "", width) : "");
|
|
220
286
|
}
|
|
221
287
|
if (height > 2)
|
|
222
|
-
lines[height - 2] =
|
|
223
|
-
width > 0
|
|
224
|
-
? padToWidth(centerLine(theme.fg("dim", tuiText("setupSkipHint", "press enter to skip")), width), width)
|
|
225
|
-
: "";
|
|
288
|
+
lines[height - 2] = width > 0 ? padToWidth(centerLine(theme.fg("dim", skipHint()), width), width) : "";
|
|
226
289
|
return lines;
|
|
227
290
|
}
|
|
@@ -29,6 +29,7 @@ export interface SetupHost extends SetupUiHost {
|
|
|
29
29
|
readonly disabledProviders: readonly string[];
|
|
30
30
|
readonly authStorage: AuthStorage;
|
|
31
31
|
readonly modelSource: ModelBrowserSource;
|
|
32
|
+
/** Available and catalog models of every kind; role chips resolve over all of them, rows list chat models. */
|
|
32
33
|
getModels(): { available: Model[]; all: Model[]; current: Model | undefined };
|
|
33
34
|
refreshModels(): Promise<void>;
|
|
34
35
|
selectModel(model: Model, selector: string): Promise<void>;
|