@linxiraos/pi-tui 1.1.27 → 1.2.0
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 +47 -463
- 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 +1 -1
- 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 +6 -1
- 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/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 +44 -29
- 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 +3 -3
- 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.ts +4 -15
- 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 +55 -12
- 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/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
package/dist/types/vim.d.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* This is a usable subset of Vim, not a reimplementation of it (see issue #3299): Normal and Visual
|
|
9
9
|
* modes, the common motions, and operators built from those motions.
|
|
10
10
|
*/
|
|
11
|
-
export type VimMode = "insert" | "normal" | "visual" | "visual-line";
|
|
12
|
-
export type VimOperator = "d" | "y" | "c";
|
|
11
|
+
export type VimMode = "insert" | "normal" | "visual" | "visual-line" | "replace";
|
|
12
|
+
export type VimOperator = "d" | "y" | "c" | ">" | "<";
|
|
13
13
|
export interface VimPosition {
|
|
14
14
|
line: number;
|
|
15
15
|
col: number;
|
|
@@ -50,6 +50,20 @@ export type VimCommand = {
|
|
|
50
50
|
count: number;
|
|
51
51
|
} | {
|
|
52
52
|
kind: "undo";
|
|
53
|
+
} | {
|
|
54
|
+
kind: "replace";
|
|
55
|
+
from: VimPosition;
|
|
56
|
+
to: VimPosition;
|
|
57
|
+
text: string;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "join";
|
|
60
|
+
fromLine: number;
|
|
61
|
+
lines: number;
|
|
62
|
+
} | {
|
|
63
|
+
kind: "indent";
|
|
64
|
+
fromLine: number;
|
|
65
|
+
toLine: number;
|
|
66
|
+
out: boolean;
|
|
53
67
|
};
|
|
54
68
|
/** Start offset of the grapheme after `col`, clamped to `text.length`. */
|
|
55
69
|
export declare function nextGraphemeStart(text: string, col: number): number;
|
|
@@ -62,11 +76,11 @@ export declare class VimState {
|
|
|
62
76
|
mode: VimMode;
|
|
63
77
|
/** Fixed end of a Visual selection; the cursor is the moving end. */
|
|
64
78
|
anchor: VimPosition | null;
|
|
65
|
-
/** True while a count, operator, `g`,
|
|
79
|
+
/** True while a count, operator, `g`, text-object, find, or `r` prefix is half-typed — Escape cancels it. */
|
|
66
80
|
get pending(): boolean;
|
|
67
81
|
/**
|
|
68
|
-
* The half-typed command as Vim would echo it (`"2"`, `"d"`, `"2d"`, `"di"`) — empty
|
|
69
|
-
* nothing is pending. Hosts render this next to the mode so a partially entered operator is
|
|
82
|
+
* The half-typed command as Vim would echo it (`"2"`, `"d"`, `"2d"`, `"di"`, `"df"`, `"r"`) — empty
|
|
83
|
+
* when nothing is pending. Hosts render this next to the mode so a partially entered operator is
|
|
70
84
|
* visible instead of silently swallowing the next keystroke.
|
|
71
85
|
*/
|
|
72
86
|
get pendingText(): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@linxiraos/pi-tui",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://linxira-os.github.io/zeta/",
|
|
7
7
|
"author": "Linxira-OS",
|
|
@@ -38,14 +38,14 @@
|
|
|
38
38
|
"gen:glyphs": "bun scripts/gen-glyphs.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@linxiraos/pi-omptype": "1.
|
|
42
|
-
"@linxiraos/pi-agent-core": "1.
|
|
43
|
-
"@linxiraos/pi-ai": "1.
|
|
44
|
-
"@linxiraos/pi-catalog": "1.
|
|
45
|
-
"@linxiraos/pi-natives": "1.
|
|
46
|
-
"@linxiraos/pi-utils": "1.
|
|
47
|
-
"@linxiraos/pi-wire": "1.
|
|
48
|
-
"@linxiraos/pi-snapcompact": "1.
|
|
41
|
+
"@linxiraos/pi-omptype": "1.2.0",
|
|
42
|
+
"@linxiraos/pi-agent-core": "1.2.0",
|
|
43
|
+
"@linxiraos/pi-ai": "1.2.0",
|
|
44
|
+
"@linxiraos/pi-catalog": "1.2.0",
|
|
45
|
+
"@linxiraos/pi-natives": "1.2.0",
|
|
46
|
+
"@linxiraos/pi-utils": "1.2.0",
|
|
47
|
+
"@linxiraos/pi-wire": "1.2.0",
|
|
48
|
+
"@linxiraos/pi-snapcompact": "1.2.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -102,6 +102,10 @@
|
|
|
102
102
|
"types": "./dist/types/components/*.d.ts",
|
|
103
103
|
"import": "./src/components/*.ts"
|
|
104
104
|
},
|
|
105
|
+
"./native/*": {
|
|
106
|
+
"types": "./dist/types/native/*.d.ts",
|
|
107
|
+
"import": "./src/native/*.ts"
|
|
108
|
+
},
|
|
105
109
|
"./*.js": "./src/*.ts"
|
|
106
110
|
}
|
|
107
111
|
}
|
package/src/app-keybindings.d.ts
CHANGED
|
@@ -119,7 +119,7 @@ export declare const KEYBINDINGS: {
|
|
|
119
119
|
readonly description: "Delete word backward";
|
|
120
120
|
};
|
|
121
121
|
readonly "tui.editor.deleteWordForward": {
|
|
122
|
-
readonly defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+alt+d"];
|
|
122
|
+
readonly defaultKeys: ["alt+delete", "alt+d", "ctrl+delete", "super+alt+delete", "super+alt+d"];
|
|
123
123
|
readonly description: "Delete word forward";
|
|
124
124
|
};
|
|
125
125
|
readonly "tui.editor.deleteToLineStart": {
|
package/src/app-keybindings.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
// Subpaths, not the `@linxiraos/pi-utils` barrel: the barrel loads the native
|
|
4
4
|
// addon (file-lock), and key-hint formatting runs on addon-free CLI paths
|
|
5
|
-
// (`
|
|
5
|
+
// (`zetacode --version`, help) through cli/command-help.ts.
|
|
6
6
|
import { getActiveProfile, getAgentDir, getProfileRootDir } from "@linxiraos/pi-utils/dirs";
|
|
7
7
|
import { isEnoent } from "@linxiraos/pi-utils/fs-error";
|
|
8
8
|
import * as logger from "@linxiraos/pi-utils/logger";
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
import { formatNum, type ExperimentResult, type ExperimentState } from "../tools/autoresearch";
|
|
18
18
|
import type { TspSpan, TspTableColumn, TspText } from "@linxiraos/pi-wire";
|
|
19
19
|
import { card, col, elapsed, keyed, node, row, span, text } from "../native/describe";
|
|
20
|
-
import type { DescribeContext, NativeNode } from "../native/node";
|
|
21
|
-
import { hintsRow } from "../native/overlay";
|
|
20
|
+
import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node";
|
|
21
|
+
import { actionBar, actionButton, hintsRow } from "../native/overlay";
|
|
22
22
|
import { Memo } from "../native/memo";
|
|
23
23
|
import { isNativeRendering } from "../native/state";
|
|
24
24
|
|
|
@@ -190,9 +190,9 @@ export function createDashboardController(): DashboardController {
|
|
|
190
190
|
{ keys: ["up", "down", "j", "k"], label: "scroll" },
|
|
191
191
|
{ keys: ["pageUp", "pageDown"], label: "page" },
|
|
192
192
|
{ keys: ["g", "shift+g"], label: "top/bottom" },
|
|
193
|
-
{ keys: ["escape"], label: "close" },
|
|
194
193
|
]),
|
|
195
194
|
);
|
|
195
|
+
children.push(actionBar([null, actionButton("Close", "close", { keys: "escape" })]));
|
|
196
196
|
return col(children, { gap: "md", role: "zeta.app.autoresearch" });
|
|
197
197
|
},
|
|
198
198
|
);
|
|
@@ -214,6 +214,10 @@ export function createDashboardController(): DashboardController {
|
|
|
214
214
|
scrollView.setHeight(viewportRows);
|
|
215
215
|
return [header, ...scrollView.render(width), renderOverlayFooter(width, theme)];
|
|
216
216
|
},
|
|
217
|
+
/** The Close button runs Esc's path. */
|
|
218
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
219
|
+
if (event.type === "action" && event.act === "close") done(undefined);
|
|
220
|
+
},
|
|
217
221
|
handleInput(data: string): void {
|
|
218
222
|
if (matchesKey(data, "escape") || matchesKey(data, "esc") || data === "q") {
|
|
219
223
|
done(undefined);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Live status board for `
|
|
2
|
+
* Live status board for `zetacode cleanse`.
|
|
3
3
|
*
|
|
4
4
|
* Interactive terminals get a transient board repainted in place: a phase
|
|
5
5
|
* spinner (model resolution, checker discovery), one row per running checker,
|
|
@@ -59,7 +59,7 @@ const REPAIR_BAR_STYLE: ProgressBarStyle = {
|
|
|
59
59
|
styleEmpty: text => fgOrPlain("dim", text),
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
/** Rendering surface for one `
|
|
62
|
+
/** Rendering surface for one `zetacode cleanse` run. */
|
|
63
63
|
export interface CleanseStatusBoard {
|
|
64
64
|
readonly interactive: boolean;
|
|
65
65
|
/** Print a permanent line above the live area (plain write when non-TTY). */
|
|
@@ -10,7 +10,7 @@ import { Input } from "../../components/input";
|
|
|
10
10
|
import { routeSgrMouseInput, type SgrMouseEvent } from "../../mouse";
|
|
11
11
|
import { padding, truncateToWidth, visibleWidth } from "../../utils";
|
|
12
12
|
import { isRecord, sanitizeText } from "@linxiraos/pi-utils";
|
|
13
|
-
import { theme } from "../../theme/theme";
|
|
13
|
+
import { getThemeEpoch, theme } from "../../theme/theme";
|
|
14
14
|
import { sanitizeDisplayText } from "../../overlays/extensions/display-text";
|
|
15
15
|
import { DebugViewerFrame, type DebugViewerFrameContent, type DebugViewerFrameContext } from "./viewer-frame";
|
|
16
16
|
import { formatDebugLogExpandedLines, parseDebugLogPid, parseDebugLogTimestampMs } from "./log-formatting";
|
|
@@ -28,6 +28,12 @@ export const LOAD_OLDER_LABEL = "### MOVE UP TO LOAD MORE...";
|
|
|
28
28
|
|
|
29
29
|
const INITIAL_LOG_CHUNK = 50;
|
|
30
30
|
const LOAD_OLDER_CHUNK = 50;
|
|
31
|
+
/**
|
|
32
|
+
* Default for {@link DebugLogViewerModelOptions.maxLogEntries}. Once this many
|
|
33
|
+
* entries are loaded, older history stops loading; the newest entries (the
|
|
34
|
+
* current session) are never evicted.
|
|
35
|
+
*/
|
|
36
|
+
const MAX_LOG_ENTRIES = 50_000;
|
|
31
37
|
const MIN_LOG_VIEWER_WIDTH = 48;
|
|
32
38
|
/** Picker item id of the "load older entries" row. */
|
|
33
39
|
const OLDER_ITEM = "older";
|
|
@@ -43,6 +49,24 @@ type LogEntry = {
|
|
|
43
49
|
rawLine: string;
|
|
44
50
|
timestampMs: number | undefined;
|
|
45
51
|
pid: number | undefined;
|
|
52
|
+
/** Lowercased {@link rawLine}, filled on first filter match. */
|
|
53
|
+
lowerLine?: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type SelectionState = {
|
|
57
|
+
rows: readonly ViewerRow[];
|
|
58
|
+
cursor: number;
|
|
59
|
+
anchor: number | undefined;
|
|
60
|
+
indices: number[];
|
|
61
|
+
set: Set<number>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type CachedLogRow = {
|
|
65
|
+
width: number;
|
|
66
|
+
selected: boolean;
|
|
67
|
+
active: boolean;
|
|
68
|
+
expanded: boolean;
|
|
69
|
+
lines: string[];
|
|
46
70
|
};
|
|
47
71
|
|
|
48
72
|
type CursorToken = { kind: "log"; logIndex: number } | { kind: "load-older" };
|
|
@@ -52,6 +76,8 @@ type DebugLogViewerModelOptions = {
|
|
|
52
76
|
processPid?: number;
|
|
53
77
|
hasOlderLogs?: () => boolean;
|
|
54
78
|
loadOlderLogs?: (limitDays?: number) => Promise<string>;
|
|
79
|
+
/** Most entries kept; older history beyond it is not loaded. Defaults to {@link MAX_LOG_ENTRIES}. */
|
|
80
|
+
maxLogEntries?: number;
|
|
55
81
|
};
|
|
56
82
|
|
|
57
83
|
/**
|
|
@@ -111,6 +137,17 @@ function getProcessStartMs(): number {
|
|
|
111
137
|
return Date.now() - process.uptime() * 1000;
|
|
112
138
|
}
|
|
113
139
|
|
|
140
|
+
function parseLogEntries(logText: string): LogEntry[] {
|
|
141
|
+
return logText
|
|
142
|
+
.split("\n")
|
|
143
|
+
.filter(line => line.length > 0)
|
|
144
|
+
.map(rawLine => ({
|
|
145
|
+
rawLine,
|
|
146
|
+
timestampMs: parseDebugLogTimestampMs(rawLine),
|
|
147
|
+
pid: parseDebugLogPid(rawLine),
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
|
|
114
151
|
/** Split raw log text into nonempty entries. */
|
|
115
152
|
export function splitLogText(logText: string): string[] {
|
|
116
153
|
return logText.split("\n").filter(line => line.length > 0);
|
|
@@ -126,12 +163,18 @@ export function buildLogCopyPayload(lines: string[]): string {
|
|
|
126
163
|
|
|
127
164
|
/** Filter, paginate, expand, and select captured log entries. */
|
|
128
165
|
export class DebugLogViewerModel {
|
|
166
|
+
/**
|
|
167
|
+
* Loaded entries, newest first, so loading older history appends instead of
|
|
168
|
+
* copying the whole array. Log index `i` (0 = oldest) lives at `length - 1 - i`.
|
|
169
|
+
*/
|
|
129
170
|
#entries: LogEntry[];
|
|
171
|
+
readonly #maxLogEntries: number;
|
|
130
172
|
#rows: ViewerRow[];
|
|
131
173
|
#visibleLogIndices: number[];
|
|
132
174
|
#selectableRowIndices: number[];
|
|
133
175
|
#cursorSelectableIndex = 0;
|
|
134
176
|
#selectionAnchorSelectableIndex: number | undefined;
|
|
177
|
+
#selection: SelectionState | undefined;
|
|
135
178
|
#expandedLogIndices = new Set<number>();
|
|
136
179
|
#filterQuery = "";
|
|
137
180
|
#processStartMs: number;
|
|
@@ -142,12 +185,17 @@ export class DebugLogViewerModel {
|
|
|
142
185
|
#loadOlderLogs?: (limitDays?: number) => Promise<string>;
|
|
143
186
|
|
|
144
187
|
constructor(logText: string, options: DebugLogViewerModelOptions = {}) {
|
|
145
|
-
const {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
188
|
+
const {
|
|
189
|
+
processStartMs = getProcessStartMs(),
|
|
190
|
+
processPid = process.pid,
|
|
191
|
+
hasOlderLogs,
|
|
192
|
+
loadOlderLogs,
|
|
193
|
+
maxLogEntries = MAX_LOG_ENTRIES,
|
|
194
|
+
} = options;
|
|
195
|
+
this.#maxLogEntries = Math.max(1, maxLogEntries);
|
|
196
|
+
this.#entries = parseLogEntries(logText).reverse();
|
|
197
|
+
// Newest first: truncating keeps the newest entries and drops the oldest.
|
|
198
|
+
if (this.#entries.length > this.#maxLogEntries) this.#entries.length = this.#maxLogEntries;
|
|
151
199
|
this.#processStartMs = processStartMs;
|
|
152
200
|
this.#processPid = processPid;
|
|
153
201
|
this.#hasOlderLogs = hasOlderLogs;
|
|
@@ -163,6 +211,11 @@ export class DebugLogViewerModel {
|
|
|
163
211
|
return this.#entries.length;
|
|
164
212
|
}
|
|
165
213
|
|
|
214
|
+
/** True once the entry cap is reached, so older history no longer loads. */
|
|
215
|
+
get historyLimitReached(): boolean {
|
|
216
|
+
return this.#entries.length >= this.#maxLogEntries;
|
|
217
|
+
}
|
|
218
|
+
|
|
166
219
|
get visibleLogCount(): number {
|
|
167
220
|
return this.#visibleLogIndices.length;
|
|
168
221
|
}
|
|
@@ -201,7 +254,7 @@ export class DebugLogViewerModel {
|
|
|
201
254
|
}
|
|
202
255
|
|
|
203
256
|
getRawLine(logIndex: number): string {
|
|
204
|
-
return this.#
|
|
257
|
+
return this.#entryAt(logIndex)?.rawLine ?? "";
|
|
205
258
|
}
|
|
206
259
|
|
|
207
260
|
setFilterQuery(query: string): void {
|
|
@@ -269,38 +322,15 @@ export class DebugLogViewerModel {
|
|
|
269
322
|
}
|
|
270
323
|
|
|
271
324
|
getSelectedLogIndices(): number[] {
|
|
272
|
-
|
|
273
|
-
return [];
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const cursorRow = this.#getCursorRow();
|
|
277
|
-
if (this.#selectionAnchorSelectableIndex === undefined) {
|
|
278
|
-
if (cursorRow?.kind !== "log") {
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
return [cursorRow.logIndex];
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const min = Math.min(this.#selectionAnchorSelectableIndex, this.#cursorSelectableIndex);
|
|
285
|
-
const max = Math.max(this.#selectionAnchorSelectableIndex, this.#cursorSelectableIndex);
|
|
286
|
-
const selected: number[] = [];
|
|
287
|
-
for (let i = min; i <= max; i++) {
|
|
288
|
-
const rowIndex = this.#selectableRowIndices[i];
|
|
289
|
-
const row = rowIndex === undefined ? undefined : this.#rows[rowIndex];
|
|
290
|
-
if (row?.kind === "log") {
|
|
291
|
-
selected.push(row.logIndex);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return selected;
|
|
325
|
+
return this.#selectionState().indices.slice();
|
|
295
326
|
}
|
|
296
327
|
|
|
297
328
|
getSelectedCount(): number {
|
|
298
|
-
return this
|
|
329
|
+
return this.#selectionState().indices.length;
|
|
299
330
|
}
|
|
300
331
|
|
|
301
332
|
isSelected(logIndex: number): boolean {
|
|
302
|
-
|
|
303
|
-
return selected.includes(logIndex);
|
|
333
|
+
return this.#selectionState().set.has(logIndex);
|
|
304
334
|
}
|
|
305
335
|
|
|
306
336
|
isExpanded(logIndex: number): boolean {
|
|
@@ -320,8 +350,7 @@ export class DebugLogViewerModel {
|
|
|
320
350
|
}
|
|
321
351
|
|
|
322
352
|
getSelectedRawLines(): string[] {
|
|
323
|
-
|
|
324
|
-
return selectedIndices.map(index => this.getRawLine(index));
|
|
353
|
+
return this.#selectionState().indices.map(index => this.getRawLine(index));
|
|
325
354
|
}
|
|
326
355
|
|
|
327
356
|
selectAllVisible(): void {
|
|
@@ -381,16 +410,17 @@ export class DebugLogViewerModel {
|
|
|
381
410
|
prependLogs(logText: string): number {
|
|
382
411
|
const previousCursor = this.#getCursorToken();
|
|
383
412
|
const previousAnchorLogIndex = this.#getAnchorLogIndex();
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}));
|
|
413
|
+
const room = this.#maxLogEntries - this.#entries.length;
|
|
414
|
+
const parsed = room > 0 ? parseLogEntries(logText) : [];
|
|
415
|
+
// Chronological order: past the cap, keep the chunk's newest entries (nearest the loaded history).
|
|
416
|
+
const newEntries = parsed.length > room ? parsed.slice(parsed.length - room) : parsed;
|
|
389
417
|
if (newEntries.length === 0) {
|
|
390
418
|
return 0;
|
|
391
419
|
}
|
|
392
420
|
const offset = newEntries.length;
|
|
393
|
-
|
|
421
|
+
for (let i = offset - 1; i >= 0; i--) {
|
|
422
|
+
this.#entries.push(newEntries[i]!);
|
|
423
|
+
}
|
|
394
424
|
this.#loadedStartIndex += offset;
|
|
395
425
|
this.#expandedLogIndices = new Set([...this.#expandedLogIndices].map(logIndex => logIndex + offset));
|
|
396
426
|
const adjustedCursor: CursorToken | undefined =
|
|
@@ -421,7 +451,7 @@ export class DebugLogViewerModel {
|
|
|
421
451
|
const query = this.#filterQuery.toLowerCase();
|
|
422
452
|
const visible: number[] = [];
|
|
423
453
|
for (let i = this.#loadedStartIndex; i < this.#entries.length; i++) {
|
|
424
|
-
const entry = this.#
|
|
454
|
+
const entry = this.#entryAt(i);
|
|
425
455
|
if (!entry) {
|
|
426
456
|
continue;
|
|
427
457
|
}
|
|
@@ -438,7 +468,7 @@ export class DebugLogViewerModel {
|
|
|
438
468
|
let olderSeen = false;
|
|
439
469
|
let warningInserted = false;
|
|
440
470
|
for (const logIndex of visible) {
|
|
441
|
-
const timestampMs = this.#
|
|
471
|
+
const timestampMs = this.#entryAt(logIndex)?.timestampMs;
|
|
442
472
|
if (timestampMs !== undefined) {
|
|
443
473
|
if (timestampMs < this.#processStartMs) {
|
|
444
474
|
olderSeen = true;
|
|
@@ -486,7 +516,7 @@ export class DebugLogViewerModel {
|
|
|
486
516
|
}
|
|
487
517
|
|
|
488
518
|
#matchesFilters(entry: LogEntry, query: string): boolean {
|
|
489
|
-
if (query.length > 0 && !entry.rawLine.toLowerCase().includes(query)) {
|
|
519
|
+
if (query.length > 0 && !(entry.lowerLine ??= entry.rawLine.toLowerCase()).includes(query)) {
|
|
490
520
|
return false;
|
|
491
521
|
}
|
|
492
522
|
if (!this.#processFilterEnabled) {
|
|
@@ -503,7 +533,7 @@ export class DebugLogViewerModel {
|
|
|
503
533
|
return false;
|
|
504
534
|
}
|
|
505
535
|
for (let i = 0; i < this.#loadedStartIndex; i++) {
|
|
506
|
-
const entry = this.#
|
|
536
|
+
const entry = this.#entryAt(i);
|
|
507
537
|
if (entry && this.#matchesFilters(entry, query)) {
|
|
508
538
|
return true;
|
|
509
539
|
}
|
|
@@ -512,7 +542,60 @@ export class DebugLogViewerModel {
|
|
|
512
542
|
}
|
|
513
543
|
|
|
514
544
|
#hasExternalOlderLogs(): boolean {
|
|
515
|
-
return this.#hasOlderLogs?.() ?? false;
|
|
545
|
+
return !this.historyLimitReached && (this.#hasOlderLogs?.() ?? false);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
#entryAt(logIndex: number): LogEntry | undefined {
|
|
549
|
+
return this.#entries[this.#entries.length - 1 - logIndex];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Selected log indices, memoized until the rows, cursor or anchor change. */
|
|
553
|
+
#selectionState(): SelectionState {
|
|
554
|
+
const cached = this.#selection;
|
|
555
|
+
if (
|
|
556
|
+
cached &&
|
|
557
|
+
cached.rows === this.#rows &&
|
|
558
|
+
cached.cursor === this.#cursorSelectableIndex &&
|
|
559
|
+
cached.anchor === this.#selectionAnchorSelectableIndex
|
|
560
|
+
) {
|
|
561
|
+
return cached;
|
|
562
|
+
}
|
|
563
|
+
const indices = this.#computeSelectedLogIndices();
|
|
564
|
+
const state: SelectionState = {
|
|
565
|
+
rows: this.#rows,
|
|
566
|
+
cursor: this.#cursorSelectableIndex,
|
|
567
|
+
anchor: this.#selectionAnchorSelectableIndex,
|
|
568
|
+
indices,
|
|
569
|
+
set: new Set(indices),
|
|
570
|
+
};
|
|
571
|
+
this.#selection = state;
|
|
572
|
+
return state;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
#computeSelectedLogIndices(): number[] {
|
|
576
|
+
if (this.#selectableRowIndices.length === 0) {
|
|
577
|
+
return [];
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const cursorRow = this.#getCursorRow();
|
|
581
|
+
if (this.#selectionAnchorSelectableIndex === undefined) {
|
|
582
|
+
if (cursorRow?.kind !== "log") {
|
|
583
|
+
return [];
|
|
584
|
+
}
|
|
585
|
+
return [cursorRow.logIndex];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const min = Math.min(this.#selectionAnchorSelectableIndex, this.#cursorSelectableIndex);
|
|
589
|
+
const max = Math.max(this.#selectionAnchorSelectableIndex, this.#cursorSelectableIndex);
|
|
590
|
+
const selected: number[] = [];
|
|
591
|
+
for (let i = min; i <= max; i++) {
|
|
592
|
+
const rowIndex = this.#selectableRowIndices[i];
|
|
593
|
+
const row = rowIndex === undefined ? undefined : this.#rows[rowIndex];
|
|
594
|
+
if (row?.kind === "log") {
|
|
595
|
+
selected.push(row.logIndex);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return selected;
|
|
516
599
|
}
|
|
517
600
|
|
|
518
601
|
#getCursorRow(): ViewerRow | undefined {
|
|
@@ -572,9 +655,13 @@ export class DebugLogViewerComponent implements Component {
|
|
|
572
655
|
#loadingOlder = false;
|
|
573
656
|
#bodyLineToRowIndex: Array<number | undefined> = [];
|
|
574
657
|
readonly #native = new Memo();
|
|
575
|
-
/** Picker rows by log index, valid
|
|
658
|
+
/** Picker rows by log index, valid for {@link #nativeItemsGeneration} (a prepend shifts indices). */
|
|
576
659
|
#nativeItems = new Map<number, TspPickerItem>();
|
|
577
|
-
#
|
|
660
|
+
#nativeItemsGeneration = 0;
|
|
661
|
+
/** Formatted ANSI log rows by log index, valid for {@link #rowCacheGeneration} and {@link #rowCacheThemeEpoch}. */
|
|
662
|
+
#rowCache = new Map<number, CachedLogRow>();
|
|
663
|
+
#rowCacheGeneration = 0;
|
|
664
|
+
#rowCacheThemeEpoch = -1;
|
|
578
665
|
|
|
579
666
|
constructor(options: DebugLogViewerComponentOptions) {
|
|
580
667
|
this.#deps = options.deps;
|
|
@@ -744,6 +831,7 @@ export class DebugLogViewerComponent implements Component {
|
|
|
744
831
|
invalidate(): void {
|
|
745
832
|
this.#frame.invalidate();
|
|
746
833
|
this.#native.clear();
|
|
834
|
+
this.#rowCache.clear();
|
|
747
835
|
}
|
|
748
836
|
|
|
749
837
|
dispose(): void {
|
|
@@ -774,6 +862,7 @@ export class DebugLogViewerComponent implements Component {
|
|
|
774
862
|
model.cursorRowIndex,
|
|
775
863
|
selected.join(","),
|
|
776
864
|
model.logCount,
|
|
865
|
+
model.historyLimitReached,
|
|
777
866
|
model.isProcessFilterEnabled(),
|
|
778
867
|
model.canLoadOlder(),
|
|
779
868
|
query,
|
|
@@ -782,9 +871,11 @@ export class DebugLogViewerComponent implements Component {
|
|
|
782
871
|
this.#statusMessage,
|
|
783
872
|
],
|
|
784
873
|
() => {
|
|
785
|
-
|
|
874
|
+
// Entries only grow, and every prepend shifts log indices, so the count keys the item cache.
|
|
875
|
+
const generation = model.logCount;
|
|
876
|
+
if (this.#nativeItemsGeneration !== generation) {
|
|
786
877
|
this.#nativeItems = new Map();
|
|
787
|
-
this.#
|
|
878
|
+
this.#nativeItemsGeneration = generation;
|
|
788
879
|
}
|
|
789
880
|
const items: TspPickerItem[] = [];
|
|
790
881
|
const order: (string | TspPickerGroup)[] = [];
|
|
@@ -817,6 +908,7 @@ export class DebugLogViewerComponent implements Component {
|
|
|
817
908
|
const subtitle = [
|
|
818
909
|
`${model.visibleLogCount}/${model.logCount} entries`,
|
|
819
910
|
selected.length > 1 ? `${selected.length} selected` : undefined,
|
|
911
|
+
model.historyLimitReached ? "history limit reached" : undefined,
|
|
820
912
|
this.#loadingOlder ? "loading older…" : undefined,
|
|
821
913
|
]
|
|
822
914
|
.filter(part => part !== undefined)
|
|
@@ -853,7 +945,11 @@ export class DebugLogViewerComponent implements Component {
|
|
|
853
945
|
pickerAction("all", "Select all", "ctrl+a"),
|
|
854
946
|
pickerAction("pid", "This process", "ctrl+p", { on: model.isProcessFilterEnabled() }),
|
|
855
947
|
pickerAction("older", "Load older", "ctrl+o", {
|
|
856
|
-
disabled: model.canLoadOlder()
|
|
948
|
+
disabled: model.canLoadOlder()
|
|
949
|
+
? undefined
|
|
950
|
+
: model.historyLimitReached
|
|
951
|
+
? "Log history limit reached"
|
|
952
|
+
: "No older log entries",
|
|
857
953
|
}),
|
|
858
954
|
CLOSE_ACTION,
|
|
859
955
|
],
|
|
@@ -945,7 +1041,8 @@ export class DebugLogViewerComponent implements Component {
|
|
|
945
1041
|
#summaryText(): string {
|
|
946
1042
|
const selected = this.#model.getSelectedCount();
|
|
947
1043
|
const expanded = this.#model.expandedCount;
|
|
948
|
-
|
|
1044
|
+
const limitText = this.#model.historyLimitReached ? ` ${theme.fg("warning", "history limit reached")}` : "";
|
|
1045
|
+
return `${theme.fg("muted", "showing")} ${theme.fg("accent", `${this.#model.visibleLogCount}/${this.#model.logCount}`)} ${theme.fg("muted", "selected")} ${theme.fg(selected > 0 ? "accent" : "muted", String(selected))} ${theme.fg("muted", "expanded")} ${theme.fg(expanded > 0 ? "accent" : "muted", String(expanded))}${limitText}`;
|
|
949
1046
|
}
|
|
950
1047
|
|
|
951
1048
|
#controlsText(): string {
|
|
@@ -1017,10 +1114,21 @@ export class DebugLogViewerComponent implements Component {
|
|
|
1017
1114
|
}
|
|
1018
1115
|
|
|
1019
1116
|
#renderRows(innerWidth: number): Array<{ lines: string[]; rowIndex: number }> {
|
|
1117
|
+
const model = this.#model;
|
|
1020
1118
|
const rendered: Array<{ lines: string[]; rowIndex: number }> = [];
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1119
|
+
// Entries only grow, and every prepend shifts log indices, so the count keys the row cache.
|
|
1120
|
+
const generation = model.logCount;
|
|
1121
|
+
const themeEpoch = getThemeEpoch();
|
|
1122
|
+
if (this.#rowCacheGeneration !== generation || this.#rowCacheThemeEpoch !== themeEpoch) {
|
|
1123
|
+
this.#rowCache.clear();
|
|
1124
|
+
this.#rowCacheGeneration = generation;
|
|
1125
|
+
this.#rowCacheThemeEpoch = themeEpoch;
|
|
1126
|
+
}
|
|
1127
|
+
const cursorRowIndex = model.cursorRowIndex;
|
|
1128
|
+
const cursorLogIndex = model.cursorLogIndex;
|
|
1129
|
+
|
|
1130
|
+
for (let rowIndex = 0; rowIndex < model.rows.length; rowIndex++) {
|
|
1131
|
+
const row = model.rows[rowIndex];
|
|
1024
1132
|
if (!row) {
|
|
1025
1133
|
continue;
|
|
1026
1134
|
}
|
|
@@ -1034,7 +1142,7 @@ export class DebugLogViewerComponent implements Component {
|
|
|
1034
1142
|
}
|
|
1035
1143
|
|
|
1036
1144
|
if (row.kind === "load-older") {
|
|
1037
|
-
const active =
|
|
1145
|
+
const active = cursorRowIndex === rowIndex;
|
|
1038
1146
|
const marker = active ? theme.fg("accent", "❯") : " ";
|
|
1039
1147
|
const prefix = `${marker} `;
|
|
1040
1148
|
const contentWidth = Math.max(1, innerWidth - visibleWidth(prefix));
|
|
@@ -1047,32 +1155,40 @@ export class DebugLogViewerComponent implements Component {
|
|
|
1047
1155
|
}
|
|
1048
1156
|
|
|
1049
1157
|
const logIndex = row.logIndex;
|
|
1050
|
-
const selected =
|
|
1051
|
-
const cursorLogIndex = this.#model.cursorLogIndex;
|
|
1158
|
+
const selected = model.isSelected(logIndex);
|
|
1052
1159
|
const active = cursorLogIndex !== undefined && cursorLogIndex === logIndex;
|
|
1053
|
-
const expanded =
|
|
1160
|
+
const expanded = model.isExpanded(logIndex);
|
|
1161
|
+
const cached = this.#rowCache.get(logIndex);
|
|
1162
|
+
if (
|
|
1163
|
+
cached &&
|
|
1164
|
+
cached.width === innerWidth &&
|
|
1165
|
+
cached.selected === selected &&
|
|
1166
|
+
cached.active === active &&
|
|
1167
|
+
cached.expanded === expanded
|
|
1168
|
+
) {
|
|
1169
|
+
rendered.push({ rowIndex, lines: cached.lines });
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1054
1173
|
const marker = active ? theme.fg("accent", "❯") : selected ? theme.fg("accent", "•") : " ";
|
|
1055
1174
|
const fold = expanded ? theme.fg("accent", "▾") : theme.fg("muted", "▸");
|
|
1056
1175
|
const prefix = `${marker}${fold} `;
|
|
1057
1176
|
const contentWidth = Math.max(1, innerWidth - visibleWidth(prefix));
|
|
1058
|
-
|
|
1177
|
+
let lines: string[];
|
|
1059
1178
|
if (expanded) {
|
|
1060
|
-
const wrapped = formatDebugLogExpandedLines(
|
|
1179
|
+
const wrapped = formatDebugLogExpandedLines(model.getRawLine(logIndex), contentWidth);
|
|
1061
1180
|
const indent = padding(visibleWidth(prefix));
|
|
1062
|
-
|
|
1181
|
+
lines = wrapped.map((segment, index) => {
|
|
1063
1182
|
const content = selected ? theme.bold(segment) : segment;
|
|
1064
1183
|
return truncateToWidth(`${index === 0 ? prefix : indent}${content}`, innerWidth);
|
|
1065
1184
|
});
|
|
1066
|
-
|
|
1067
|
-
|
|
1185
|
+
} else {
|
|
1186
|
+
const preview = truncateToWidth(sanitizeDisplayText(model.getRawLine(logIndex)), contentWidth);
|
|
1187
|
+
const content = selected ? theme.bold(preview) : preview;
|
|
1188
|
+
lines = [truncateToWidth(`${prefix}${content}`, innerWidth)];
|
|
1068
1189
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
sanitizeDisplayText(this.#model.getRawLine(logIndex)),
|
|
1072
|
-
Math.max(1, contentWidth),
|
|
1073
|
-
);
|
|
1074
|
-
const content = selected ? theme.bold(preview) : preview;
|
|
1075
|
-
rendered.push({ rowIndex, lines: [truncateToWidth(`${prefix}${content}`, innerWidth)] });
|
|
1190
|
+
this.#rowCache.set(logIndex, { width: innerWidth, selected, active, expanded, lines });
|
|
1191
|
+
rendered.push({ rowIndex, lines });
|
|
1076
1192
|
}
|
|
1077
1193
|
|
|
1078
1194
|
return rendered;
|
|
@@ -271,9 +271,15 @@ export class RawSseDebugBuffer {
|
|
|
271
271
|
#totalEvents = 0;
|
|
272
272
|
#lastUpdatedAt: number | undefined;
|
|
273
273
|
#nextSequence = 1;
|
|
274
|
+
#revision = 0;
|
|
274
275
|
#listeners = new Set<() => void>();
|
|
275
276
|
#emitScheduled = false;
|
|
276
277
|
|
|
278
|
+
/** Bumped on every change to the captured window (append, eviction, clear); equal revisions mean equal snapshots. */
|
|
279
|
+
get revision(): number {
|
|
280
|
+
return this.#revision;
|
|
281
|
+
}
|
|
282
|
+
|
|
277
283
|
subscribe(listener: () => void): () => void {
|
|
278
284
|
this.#listeners.add(listener);
|
|
279
285
|
return () => this.#listeners.delete(listener);
|
|
@@ -359,6 +365,7 @@ export class RawSseDebugBuffer {
|
|
|
359
365
|
this.#droppedChars = 0;
|
|
360
366
|
this.#totalEvents = 0;
|
|
361
367
|
this.#lastUpdatedAt = undefined;
|
|
368
|
+
this.#revision += 1;
|
|
362
369
|
this.#emit();
|
|
363
370
|
}
|
|
364
371
|
|
|
@@ -368,6 +375,7 @@ export class RawSseDebugBuffer {
|
|
|
368
375
|
this.#totalChars += chars;
|
|
369
376
|
this.#lastUpdatedAt = record.timestamp;
|
|
370
377
|
this.#enforceLimits();
|
|
378
|
+
this.#revision += 1;
|
|
371
379
|
this.#emit();
|
|
372
380
|
}
|
|
373
381
|
|