@linxiraos/pi-tui 1.1.26 → 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 +51 -491
- package/README.md +13 -7
- package/dist/types/active-terminal.d.ts +30 -0
- package/dist/types/app-keybindings.d.ts +7 -2
- 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 +5 -4
- 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 +11 -1
- package/dist/types/chat/chat-transcript-builder.d.ts +3 -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 +17 -4
- package/dist/types/chrome/shared.d.ts +9 -0
- package/dist/types/chrome/status-notice.d.ts +15 -3
- 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 +23 -5
- package/dist/types/components/form.d.ts +1 -0
- package/dist/types/components/image.d.ts +26 -44
- package/dist/types/components/input.d.ts +2 -1
- 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/loader.d.ts +5 -6
- package/dist/types/components/markdown.d.ts +47 -5
- 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 +9 -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/apply.d.ts +4 -3
- package/dist/types/native/backend.d.ts +5 -4
- package/dist/types/native/blobs.d.ts +7 -3
- package/dist/types/native/encode.d.ts +8 -6
- package/dist/types/native/node.d.ts +36 -5
- package/dist/types/native/overlay.d.ts +8 -3
- package/dist/types/native/settle.d.ts +4 -3
- 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 +3 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +12 -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/btw-history-panel.d.ts +13 -1
- package/dist/types/overlays/copy-selector.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/hub-frame.d.ts +4 -1
- 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 +37 -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/report-panel.d.ts +68 -0
- package/dist/types/overlays/rewind-selector.d.ts +1 -0
- 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/thinking-selector.d.ts +2 -2
- package/dist/types/overlays/usage-dashboard.d.ts +12 -8
- package/dist/types/overlays/usage-display.d.ts +3 -1
- package/dist/types/prompt/composer-cache.d.ts +0 -16
- package/dist/types/prompt/composer.d.ts +18 -3
- package/dist/types/prompt/custom-editor.d.ts +25 -13
- package/dist/types/prompt/image-source.d.ts +2 -1
- package/dist/types/prompt/interactive-context-helpers.d.ts +5 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/prompt/welcome.d.ts +7 -2
- 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/space-hold.d.ts +40 -25
- package/dist/types/status-line/component.d.ts +3 -0
- package/dist/types/status-line/context-usage.d.ts +7 -5
- 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 +41 -36
- package/dist/types/terminal-multiplexer.d.ts +127 -14
- package/dist/types/terminal.d.ts +23 -16
- 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/thinking.d.ts +1 -1
- package/dist/types/tmux.d.ts +11 -4
- package/dist/types/tools/bash.d.ts +7 -2
- 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 +2 -3
- package/dist/types/tools/write.d.ts +9 -2
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +36 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vim.d.ts +19 -5
- package/dist/types/windows-input-mode.d.ts +33 -1
- package/package.json +13 -9
- package/src/active-terminal.d.ts +30 -0
- package/src/active-terminal.ts +80 -0
- package/src/app-keybindings.d.ts +7 -2
- package/src/app-keybindings.ts +7 -2
- 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 +96 -23
- package/src/apps/git/git-tui.ts +23 -16
- package/src/apps/git/help.ts +29 -20
- package/src/apps/git/sidebar.ts +8 -3
- 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/bracketed-paste.ts +10 -3
- 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 +11 -1
- package/src/chat/assistant-message.ts +245 -54
- package/src/chat/chat-transcript-builder.d.ts +3 -0
- package/src/chat/chat-transcript-builder.ts +9 -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 +86 -7
- package/src/chat/user-message.d.ts +17 -4
- package/src/chat/user-message.ts +71 -8
- package/src/chrome/shared.ts +53 -0
- package/src/chrome/status-notice.ts +25 -7
- package/src/chrome/transcript-container.d.ts +6 -0
- package/src/chrome/transcript-container.ts +162 -19
- 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 +23 -5
- package/src/components/editor.ts +316 -47
- package/src/components/form.d.ts +1 -0
- package/src/components/form.ts +8 -0
- package/src/components/image.d.ts +26 -44
- package/src/components/image.ts +115 -152
- package/src/components/input.d.ts +2 -1
- package/src/components/input.ts +17 -7
- 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/loader.d.ts +5 -6
- package/src/components/loader.ts +10 -17
- package/src/components/markdown.d.ts +47 -5
- package/src/components/markdown.ts +786 -303
- 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 +3 -2
- package/src/fuzzy.d.ts +29 -1
- package/src/fuzzy.ts +115 -30
- package/src/hotkeys-markdown.ts +9 -2
- package/src/key-hint-format.d.ts +9 -1
- package/src/key-hint-format.ts +26 -11
- 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 +11 -5
- 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/apply.d.ts +4 -3
- package/src/native/apply.ts +4 -3
- package/src/native/backend.d.ts +5 -4
- package/src/native/backend.ts +199 -22
- package/src/native/blobs.d.ts +7 -3
- package/src/native/blobs.ts +47 -12
- package/src/native/encode.d.ts +8 -6
- package/src/native/encode.ts +76 -34
- package/src/native/node.d.ts +36 -5
- package/src/native/node.ts +31 -5
- package/src/native/overlay.d.ts +8 -3
- package/src/native/overlay.ts +17 -4
- package/src/native/reconcile.ts +16 -4
- package/src/native/settle.d.ts +4 -3
- package/src/native/settle.ts +4 -3
- 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 +48 -29
- package/src/overlays/agent-transcript-viewer.ts +93 -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 +10 -17
- package/src/overlays/btw-history-panel.ts +136 -39
- package/src/overlays/copy-selector.d.ts +1 -0
- package/src/overlays/copy-selector.ts +32 -8
- package/src/overlays/extensions/extension-dashboard.ts +4 -4
- 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/hub-frame.ts +19 -1
- package/src/overlays/jobs-panel.ts +33 -52
- package/src/overlays/model-browser.ts +367 -122
- package/src/overlays/model-hub.ts +435 -59
- package/src/overlays/move-overlay.ts +28 -14
- package/src/overlays/oauth-selector.ts +54 -70
- package/src/overlays/pause-screen.ts +2 -2
- package/src/overlays/plan-review-overlay.ts +208 -70
- package/src/overlays/plugin-settings.ts +3 -3
- package/src/overlays/report-panel.ts +191 -0
- package/src/overlays/rewind-selector.ts +88 -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 +5 -4
- 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/thinking-selector.ts +11 -10
- package/src/overlays/tree-selector.ts +41 -20
- package/src/overlays/usage-dashboard.ts +117 -58
- package/src/overlays/usage-display.ts +10 -4
- package/src/overlays/usage-row.ts +22 -8
- package/src/prompt/attachment-chips.ts +15 -11
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer-cache.ts +7 -86
- package/src/prompt/composer.ts +37 -26
- package/src/prompt/custom-editor.ts +282 -105
- package/src/prompt/image-source.ts +2 -1
- package/src/prompt/interactive-context-helpers.ts +32 -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/queued-messages.ts +6 -4
- package/src/prompt/tips.txt +13 -9
- package/src/prompt/welcome.ts +64 -46
- 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 +16 -1
- 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/space-hold.d.ts +40 -25
- package/src/space-hold.ts +156 -52
- package/src/status-line/component.ts +292 -78
- package/src/status-line/context-usage.ts +21 -46
- 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 +41 -36
- package/src/terminal-capabilities.ts +137 -213
- package/src/terminal-multiplexer.d.ts +127 -14
- package/src/terminal-multiplexer.ts +112 -33
- package/src/terminal.d.ts +23 -16
- package/src/terminal.ts +203 -99
- 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 +11 -4
- 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/thinking.d.ts +1 -1
- package/src/thinking.ts +1 -1
- 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.d.ts +7 -2
- package/src/tools/bash.ts +116 -47
- 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 +154 -50
- package/src/tools/task.d.ts +2 -3
- package/src/tools/task.ts +115 -62
- 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 +36 -0
- package/src/tui.ts +666 -217
- 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.d.ts +33 -1
- package/src/windows-input-mode.ts +212 -6
package/src/native/blobs.ts
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Content-addressed binary blobs (images) for `image` nodes.
|
|
3
3
|
*
|
|
4
4
|
* `describe()` registers the bytes and puts the returned id in `image.p.blob`;
|
|
5
|
-
* the native backend
|
|
6
|
-
*
|
|
5
|
+
* the native backend delivers each referenced blob once per terminal
|
|
6
|
+
* connection (asking the terminal first which it holds, or through its blob
|
|
7
|
+
* cache), else uploads it with verb `b` before the frame that first
|
|
8
|
+
* references it.
|
|
7
9
|
*/
|
|
8
10
|
import type { TspProps } from "@linxiraos/pi-wire";
|
|
9
11
|
import { getImageDimensions } from "../terminal-capabilities";
|
|
@@ -16,7 +18,13 @@ export interface NativeBlob {
|
|
|
16
18
|
readonly bytes: Uint8Array;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
const blobs = new Map<string, NativeBlob
|
|
21
|
+
const blobs = new Map<string, WeakRef<NativeBlob>>();
|
|
22
|
+
const registeredBlobs = new Map<string, NativeBlob>();
|
|
23
|
+
const releasedBlobs = new FinalizationRegistry<{ id: string; reference: WeakRef<NativeBlob> }>(({ id, reference }) => {
|
|
24
|
+
if (blobs.get(id) === reference) blobs.delete(id);
|
|
25
|
+
});
|
|
26
|
+
// Props spreads preserve ownership; wire serialization omits symbol keys.
|
|
27
|
+
const kBlob = Symbol("native.blob");
|
|
20
28
|
// Registration usually repeats with the same bytes object on every describe;
|
|
21
29
|
// the tag skips rehashing it.
|
|
22
30
|
const kBlobId = Symbol("native.blobId");
|
|
@@ -25,19 +33,42 @@ interface BlobTagged {
|
|
|
25
33
|
[kBlobId]?: string;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
export function registerNativeBlob(bytes: Uint8Array, mime: string): string {
|
|
36
|
+
function getOrCreateBlob(bytes: Uint8Array, mime: string): NativeBlob {
|
|
30
37
|
const known = (bytes as BlobTagged)[kBlobId];
|
|
31
|
-
|
|
32
|
-
const id = new Bun.CryptoHasher("sha256").update(bytes).digest("hex");
|
|
38
|
+
const id = known ?? new Bun.CryptoHasher("sha256").update(bytes).digest("hex");
|
|
33
39
|
(bytes as BlobTagged)[kBlobId] = id;
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
let blob = blobs.get(id)?.deref();
|
|
41
|
+
if (!blob) {
|
|
42
|
+
blob = { id, mime, bytes };
|
|
43
|
+
const reference = new WeakRef(blob);
|
|
44
|
+
blobs.set(id, reference);
|
|
45
|
+
releasedBlobs.register(blob, { id, reference });
|
|
46
|
+
}
|
|
47
|
+
return blob;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Register bytes for process-lifetime, id-only use. Prefer {@link nativeImageNode} for owned images. */
|
|
51
|
+
export function registerNativeBlob(bytes: Uint8Array, mime: string): string {
|
|
52
|
+
const blob = getOrCreateBlob(bytes, mime);
|
|
53
|
+
registeredBlobs.set(blob.id, blob);
|
|
54
|
+
return blob.id;
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
/** A registered blob by id. */
|
|
39
58
|
export function getNativeBlob(id: string): NativeBlob | undefined {
|
|
40
|
-
return blobs.get(id);
|
|
59
|
+
return blobs.get(id)?.deref();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** An image whose props own its bytes, including while hidden, unmounted, or awaiting upload. */
|
|
63
|
+
export function nativeImageNode(
|
|
64
|
+
bytes: Uint8Array,
|
|
65
|
+
mime: string,
|
|
66
|
+
p?: Omit<TspProps<"image">, "blob" | "builtin">,
|
|
67
|
+
key?: string,
|
|
68
|
+
): NativeNode {
|
|
69
|
+
const blob = getOrCreateBlob(bytes, mime);
|
|
70
|
+
const props = { ...p, blob: blob.id, [kBlob]: blob };
|
|
71
|
+
return node("image", props, undefined, key);
|
|
41
72
|
}
|
|
42
73
|
|
|
43
74
|
/**
|
|
@@ -51,9 +82,13 @@ export function base64ImageNode(
|
|
|
51
82
|
p?: Omit<TspProps<"image">, "blob" | "builtin" | "w" | "h">,
|
|
52
83
|
key?: string,
|
|
53
84
|
): NativeNode {
|
|
54
|
-
const blob = registerNativeBlob(Buffer.from(data, "base64"), mimeType);
|
|
55
85
|
const size = getImageDimensions(data, mimeType);
|
|
56
|
-
return
|
|
86
|
+
return nativeImageNode(
|
|
87
|
+
Buffer.from(data, "base64"),
|
|
88
|
+
mimeType,
|
|
89
|
+
size ? { ...p, w: size.widthPx, h: size.heightPx } : p,
|
|
90
|
+
key,
|
|
91
|
+
);
|
|
57
92
|
}
|
|
58
93
|
|
|
59
94
|
/** `image` nodes for base64 payloads, one per slot key, rebuilt only when the slot's payload changes. */
|
package/src/native/encode.d.ts
CHANGED
|
@@ -15,19 +15,21 @@ export type TspIncoming = {
|
|
|
15
15
|
};
|
|
16
16
|
/** Message parameters (`k=v`, ASCII, never containing `;`). */
|
|
17
17
|
export type TspParams = Readonly<Record<string, string | number>>;
|
|
18
|
-
/** Split `body` into pieces of at most `limit` UTF-8 bytes, never inside a code point. */
|
|
19
|
-
export declare function splitUtf8(body: string, limit: number): string[];
|
|
20
18
|
/**
|
|
21
|
-
* Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes
|
|
22
|
-
*
|
|
19
|
+
* Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes:
|
|
20
|
+
* the first chunk carries `params`, every chunk `c=<id>` and all but the last
|
|
21
|
+
* `m=1`. Returns the complete byte string to write (all chunks, in order).
|
|
23
22
|
*/
|
|
24
23
|
export declare function encodeTspMessage(verb: TspVerb, body: string, params?: TspParams, limit?: number): string;
|
|
25
24
|
/** Encode a JSON message body. */
|
|
26
25
|
export declare function encodeTspJson(verb: TspVerb, value: unknown, params?: TspParams, limit?: number): string;
|
|
27
26
|
/**
|
|
28
27
|
* The `hello` query; callers follow it with a DA1 sentinel. `features: ["edit"]`
|
|
29
|
-
|
|
30
|
-
* native selection in zeta's editors;
|
|
28
|
+
#1: * tells the terminal that zeta applies its `edit` events (Tern SDK,
|
|
29
|
+
* `protocol/input.md`), so it may keep a native selection in zeta's editors;
|
|
30
|
+
* without it, every key stays zeta's. `"undo"` says zeta applies `undo` events,
|
|
31
|
+
* so the terminal may turn ⌃Z in a field into one.
|
|
32
|
+
* `"send"` accepts an explicit prompt for a live composer without simulating keys.
|
|
31
33
|
*/
|
|
32
34
|
export declare function encodeTspHelloQuery(version?: string): string;
|
|
33
35
|
/** One decoded APC message: verb, parameters and raw body. */
|
package/src/native/encode.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* negotiated `apc` limit is split across messages with the same verb, tagged
|
|
7
7
|
* `c=<chunk-id>`, with `m=1` on every chunk but the last; the receiver joins
|
|
8
8
|
* the bodies byte-wise. Chunks split on code-point boundaries, so every chunk
|
|
9
|
-
* is valid UTF-8 on its own and the joined bytes equal the original body
|
|
9
|
+
* is valid UTF-8 on its own and the joined bytes equal the original body, and
|
|
10
|
+
* never where the next chunk would lead with a `key=value;` segment the
|
|
11
|
+
* receiver would read as a parameter (Tern's `tsp_chunks`).
|
|
10
12
|
*/
|
|
11
13
|
import { isRecord } from "@linxiraos/pi-utils/type-guards";
|
|
12
14
|
import {
|
|
@@ -34,36 +36,58 @@ export type TspParams = Readonly<Record<string, string | number>>;
|
|
|
34
36
|
|
|
35
37
|
let nextChunkId = 1;
|
|
36
38
|
|
|
37
|
-
/**
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
/** Whether `bytes` from `at` leads with a `key=value;` segment, which a receiver reads as one more parameter. */
|
|
40
|
+
function leadsWithParameter(bytes: Uint8Array, at: number): boolean {
|
|
41
|
+
let i = at;
|
|
42
|
+
// Key bytes: `[A-Za-z0-9_-]`.
|
|
43
|
+
for (; i < bytes.length; i++) {
|
|
44
|
+
const b = bytes[i]!;
|
|
45
|
+
if (
|
|
46
|
+
!((b >= 0x30 && b <= 0x39) || (b >= 0x41 && b <= 0x5a) || (b >= 0x61 && b <= 0x7a) || b === 0x5f || b === 0x2d)
|
|
47
|
+
)
|
|
48
|
+
break;
|
|
45
49
|
}
|
|
46
|
-
|
|
50
|
+
if (i === at || bytes[i] !== 0x3d) return false;
|
|
51
|
+
i++;
|
|
52
|
+
// Value bytes: printable ASCII other than `;`.
|
|
53
|
+
while (i < bytes.length && bytes[i]! >= 0x21 && bytes[i]! <= 0x7e && bytes[i] !== 0x3b) i++;
|
|
54
|
+
return bytes[i] === 0x3b;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Where the chunk of `bytes` starting at `start` ends: the safe cut nearest
|
|
59
|
+
* below `start + limit` (above `start`), else the nearest above it, else the
|
|
60
|
+
* end. A cut is safe on a UTF-8 character boundary where the rest doesn't
|
|
61
|
+
* lead with a parameter-shaped segment.
|
|
62
|
+
*/
|
|
63
|
+
function chunkEnd(bytes: Uint8Array, start: number, limit: number): number {
|
|
64
|
+
const target = start + limit;
|
|
65
|
+
if (target >= bytes.length) return bytes.length;
|
|
66
|
+
const safe = (at: number): boolean => (bytes[at]! & 0xc0) !== 0x80 && !leadsWithParameter(bytes, at);
|
|
67
|
+
for (let at = target; at > start; at--) if (safe(at)) return at;
|
|
68
|
+
for (let at = target + 1; at < bytes.length; at++) if (safe(at)) return at;
|
|
69
|
+
return bytes.length;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Chunk bodies for `body` of `byteLength` UTF-8 bytes, cut as Tern's
|
|
74
|
+
* `tsp_chunks` cuts. Pure ASCII without `;` (every base64 blob) has no
|
|
75
|
+
* parameter-shaped segment and no multibyte character, so it is cut every
|
|
76
|
+
* `limit` characters.
|
|
77
|
+
*/
|
|
78
|
+
function chunkBodies(body: string, byteLength: number, limit: number): string[] {
|
|
79
|
+
const max = Math.max(1, Math.trunc(limit));
|
|
52
80
|
const pieces: string[] = [];
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
bytes += step.bytes;
|
|
64
|
-
i += step.units;
|
|
81
|
+
if (byteLength === body.length && !body.includes(";")) {
|
|
82
|
+
for (let at = 0; at < body.length; at += max) pieces.push(body.slice(at, at + max));
|
|
83
|
+
return pieces;
|
|
84
|
+
}
|
|
85
|
+
const bytes = Buffer.from(body, "utf8");
|
|
86
|
+
for (let start = 0; start < bytes.length;) {
|
|
87
|
+
const end = chunkEnd(bytes, start, max);
|
|
88
|
+
pieces.push(bytes.toString("utf8", start, end));
|
|
89
|
+
start = end;
|
|
65
90
|
}
|
|
66
|
-
pieces.push(body.slice(start));
|
|
67
91
|
return pieces;
|
|
68
92
|
}
|
|
69
93
|
|
|
@@ -79,8 +103,9 @@ function encodeParams(params: TspParams | undefined): string {
|
|
|
79
103
|
}
|
|
80
104
|
|
|
81
105
|
/**
|
|
82
|
-
* Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes
|
|
83
|
-
*
|
|
106
|
+
* Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes:
|
|
107
|
+
* the first chunk carries `params`, every chunk `c=<id>` and all but the last
|
|
108
|
+
* `m=1`. Returns the complete byte string to write (all chunks, in order).
|
|
84
109
|
*/
|
|
85
110
|
export function encodeTspMessage(
|
|
86
111
|
verb: TspVerb,
|
|
@@ -90,13 +115,15 @@ export function encodeTspMessage(
|
|
|
90
115
|
): string {
|
|
91
116
|
const base = encodeParams(params);
|
|
92
117
|
// Fast path: ASCII-length bound first, exact byte count only near the limit.
|
|
93
|
-
if (body.length * 3 <= limit
|
|
118
|
+
if (body.length * 3 <= limit) return frame(verb, base, body);
|
|
119
|
+
const byteLength = Buffer.byteLength(body, "utf8");
|
|
120
|
+
if (byteLength <= limit) return frame(verb, base, body);
|
|
94
121
|
const chunkId = (nextChunkId++).toString(36);
|
|
95
|
-
const pieces =
|
|
122
|
+
const pieces = chunkBodies(body, byteLength, limit);
|
|
96
123
|
let out = "";
|
|
97
124
|
for (let i = 0; i < pieces.length; i++) {
|
|
98
125
|
const more = i < pieces.length - 1 ? ";m=1" : "";
|
|
99
|
-
out += frame(verb, `${base};c=${chunkId}${more}`, pieces[i]!);
|
|
126
|
+
out += frame(verb, `${i === 0 ? base : ""};c=${chunkId}${more}`, pieces[i]!);
|
|
100
127
|
}
|
|
101
128
|
return out;
|
|
102
129
|
}
|
|
@@ -108,11 +135,20 @@ export function encodeTspJson(verb: TspVerb, value: unknown, params?: TspParams,
|
|
|
108
135
|
|
|
109
136
|
/**
|
|
110
137
|
* The `hello` query; callers follow it with a DA1 sentinel. `features: ["edit"]`
|
|
111
|
-
|
|
112
|
-
* native selection in zeta's editors;
|
|
138
|
+
#1: * tells the terminal that zeta applies its `edit` events (Tern SDK,
|
|
139
|
+
* `protocol/input.md`), so it may keep a native selection in zeta's editors;
|
|
140
|
+
* without it, every key stays zeta's. `"undo"` says zeta applies `undo` events,
|
|
141
|
+
* so the terminal may turn ⌃Z in a field into one.
|
|
142
|
+
* `"send"` accepts an explicit prompt for a live composer without simulating keys.
|
|
113
143
|
*/
|
|
114
144
|
export function encodeTspHelloQuery(version?: string): string {
|
|
115
|
-
return encodeTspJson("q", {
|
|
145
|
+
return encodeTspJson("q", {
|
|
146
|
+
q: "hello",
|
|
147
|
+
v: [TSP_VERSION],
|
|
148
|
+
app: "zeta",
|
|
149
|
+
features: ["edit", "undo", "send"],
|
|
150
|
+
ver: version,
|
|
151
|
+
});
|
|
116
152
|
}
|
|
117
153
|
|
|
118
154
|
/** One decoded APC message: verb, parameters and raw body. */
|
|
@@ -172,6 +208,7 @@ const EVENT_REQUIRED: Readonly<Record<string, Readonly<Record<string, "string" |
|
|
|
172
208
|
// `value` varies by control (boolean, number, string, string[], null): the handler checks it.
|
|
173
209
|
change: { id: "string", item: "string" },
|
|
174
210
|
edit: { id: "string", from: "number", to: "number", text: "string", cursor: "number", len: "number" },
|
|
211
|
+
undo: { id: "string" },
|
|
175
212
|
focus: { id: "string" },
|
|
176
213
|
error: { msg: "string" },
|
|
177
214
|
gone: { ids: "array" },
|
|
@@ -179,6 +216,11 @@ const EVENT_REQUIRED: Readonly<Record<string, Readonly<Record<string, "string" |
|
|
|
179
216
|
|
|
180
217
|
function decodeEvent(value: Record<string, unknown>): TspEvent | null {
|
|
181
218
|
if (typeof value.ev !== "string") return null;
|
|
219
|
+
if (value.ev === "send") {
|
|
220
|
+
const { sf, id, text } = value;
|
|
221
|
+
if (typeof sf !== "string" || !sf || typeof id !== "string" || !id || typeof text !== "string") return null;
|
|
222
|
+
return { ev: "send", sf, id, text };
|
|
223
|
+
}
|
|
182
224
|
const required = EVENT_REQUIRED[value.ev];
|
|
183
225
|
if (!required) return null;
|
|
184
226
|
for (const key in required) {
|
package/src/native/node.d.ts
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* `rows` fallback node rendered through `render(cx.cols)`.
|
|
12
12
|
*
|
|
13
13
|
* See `packages/wire/src/tsp.ts` for the wire vocabulary and
|
|
14
|
-
* `
|
|
14
|
+
* the Tern SDK's Surface Protocol reference (`docs/sdk/src/protocol` in the
|
|
15
|
+
* Stencil repository, https://docs.stencil.so/tern/protocol/) for the spec.
|
|
15
16
|
*/
|
|
16
17
|
import type { TspEvent, TspKind, TspProps, TspScrollBy, TspSpan } from "@linxiraos/pi-wire";
|
|
17
18
|
import type { Component } from "../tui";
|
|
@@ -28,10 +29,12 @@ export type NativeNode = {
|
|
|
28
29
|
*/
|
|
29
30
|
readonly key?: string;
|
|
30
31
|
/**
|
|
31
|
-
* Scroll the node into view, placed like the `reveal` op
|
|
32
|
-
* added
|
|
32
|
+
* Scroll the node into view, placed like the `reveal` op. A placement
|
|
33
|
+
* reveals it when it is added: key a node by what it points at to
|
|
34
|
+
* reveal it again on a move. A {@link NativeReveal} reveals it whenever
|
|
35
|
+
* its `n` differs from the previous description of the same node.
|
|
33
36
|
*/
|
|
34
|
-
readonly reveal?:
|
|
37
|
+
readonly reveal?: NativeRevealAt | NativeReveal;
|
|
35
38
|
/**
|
|
36
39
|
* Keyboard scrolling forwarded to the terminal (PgUp/PgDn/End reach the
|
|
37
40
|
* program): moves the scroller at or above the node by `by` whenever
|
|
@@ -42,6 +45,17 @@ export type NativeNode = {
|
|
|
42
45
|
readonly scroll?: NativeScroll;
|
|
43
46
|
};
|
|
44
47
|
}[TspKind];
|
|
48
|
+
/** Where a revealed node lands in its scroller. */
|
|
49
|
+
export type NativeRevealAt = "start" | "end" | "nearest";
|
|
50
|
+
/**
|
|
51
|
+
* A repeatable {@link NativeNode.reveal}: bump `n` to bring an existing node
|
|
52
|
+
* into view again (a Contents entry jumping to its section). A freshly added
|
|
53
|
+
* node is not revealed.
|
|
54
|
+
*/
|
|
55
|
+
export interface NativeReveal {
|
|
56
|
+
readonly at: NativeRevealAt;
|
|
57
|
+
readonly n: number;
|
|
58
|
+
}
|
|
45
59
|
/** A {@link NativeNode.scroll} request. */
|
|
46
60
|
export interface NativeScroll {
|
|
47
61
|
readonly by: TspScrollBy;
|
|
@@ -57,6 +71,12 @@ export interface DescribeContext {
|
|
|
57
71
|
readonly reduceMotion: boolean;
|
|
58
72
|
/** The terminal's appearance is dark. */
|
|
59
73
|
readonly dark: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The user's system reads a 12-hour clock (`false`: 24-hour); `undefined`
|
|
76
|
+
* when the terminal doesn't say. Pass it as `hour12` when formatting times:
|
|
77
|
+
* the process's own default locale may not know.
|
|
78
|
+
*/
|
|
79
|
+
readonly hour12?: boolean;
|
|
60
80
|
/** Whether the terminal renders `kind` natively (else describe something simpler or let it fall back). */
|
|
61
81
|
supports(kind: TspKind): boolean;
|
|
62
82
|
/**
|
|
@@ -117,7 +137,18 @@ export type NativeUiEvent = {
|
|
|
117
137
|
| ({
|
|
118
138
|
readonly type: "edit";
|
|
119
139
|
readonly key: string;
|
|
120
|
-
} & NativeTextEdit)
|
|
140
|
+
} & NativeTextEdit)
|
|
141
|
+
/** Undo the last change to an `editor`/`input` node's text (the terminal's ⌃Z); a no-op with no history. */
|
|
142
|
+
| {
|
|
143
|
+
readonly type: "undo";
|
|
144
|
+
readonly key: string;
|
|
145
|
+
}
|
|
146
|
+
/** Submit an explicit prompt through the composer's normal path, preserving the previous draft for recall. */
|
|
147
|
+
| {
|
|
148
|
+
readonly type: "send";
|
|
149
|
+
readonly key: string;
|
|
150
|
+
readonly text: string;
|
|
151
|
+
};
|
|
121
152
|
/**
|
|
122
153
|
* A primitive edit the terminal made over its own text selection (cut,
|
|
123
154
|
* typing, Backspace/Delete or paste over it, or collapsing it). Offsets are
|
package/src/native/node.ts
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* `rows` fallback node rendered through `render(cx.cols)`.
|
|
12
12
|
*
|
|
13
13
|
* See `packages/wire/src/tsp.ts` for the wire vocabulary and
|
|
14
|
-
* `
|
|
14
|
+
* the Tern SDK's Surface Protocol reference (`docs/sdk/src/protocol` in the
|
|
15
|
+
* Stencil repository, https://docs.stencil.so/tern/protocol/) for the spec.
|
|
15
16
|
*/
|
|
16
17
|
import type { TspEvent, TspKind, TspProps, TspScrollBy, TspSpan } from "@linxiraos/pi-wire";
|
|
17
18
|
import type { Component } from "../tui";
|
|
@@ -29,10 +30,12 @@ export type NativeNode = {
|
|
|
29
30
|
*/
|
|
30
31
|
readonly key?: string;
|
|
31
32
|
/**
|
|
32
|
-
* Scroll the node into view, placed like the `reveal` op
|
|
33
|
-
* added
|
|
33
|
+
* Scroll the node into view, placed like the `reveal` op. A placement
|
|
34
|
+
* reveals it when it is added: key a node by what it points at to
|
|
35
|
+
* reveal it again on a move. A {@link NativeReveal} reveals it whenever
|
|
36
|
+
* its `n` differs from the previous description of the same node.
|
|
34
37
|
*/
|
|
35
|
-
readonly reveal?:
|
|
38
|
+
readonly reveal?: NativeRevealAt | NativeReveal;
|
|
36
39
|
/**
|
|
37
40
|
* Keyboard scrolling forwarded to the terminal (PgUp/PgDn/End reach the
|
|
38
41
|
* program): moves the scroller at or above the node by `by` whenever
|
|
@@ -44,6 +47,19 @@ export type NativeNode = {
|
|
|
44
47
|
};
|
|
45
48
|
}[TspKind];
|
|
46
49
|
|
|
50
|
+
/** Where a revealed node lands in its scroller. */
|
|
51
|
+
export type NativeRevealAt = "start" | "end" | "nearest";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A repeatable {@link NativeNode.reveal}: bump `n` to bring an existing node
|
|
55
|
+
* into view again (a Contents entry jumping to its section). A freshly added
|
|
56
|
+
* node is not revealed.
|
|
57
|
+
*/
|
|
58
|
+
export interface NativeReveal {
|
|
59
|
+
readonly at: NativeRevealAt;
|
|
60
|
+
readonly n: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
/** A {@link NativeNode.scroll} request. */
|
|
48
64
|
export interface NativeScroll {
|
|
49
65
|
readonly by: TspScrollBy;
|
|
@@ -61,6 +77,12 @@ export interface DescribeContext {
|
|
|
61
77
|
readonly reduceMotion: boolean;
|
|
62
78
|
/** The terminal's appearance is dark. */
|
|
63
79
|
readonly dark: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The user's system reads a 12-hour clock (`false`: 24-hour); `undefined`
|
|
82
|
+
* when the terminal doesn't say. Pass it as `hour12` when formatting times:
|
|
83
|
+
* the process's own default locale may not know.
|
|
84
|
+
*/
|
|
85
|
+
readonly hour12?: boolean;
|
|
64
86
|
/** Whether the terminal renders `kind` natively (else describe something simpler or let it fall back). */
|
|
65
87
|
supports(kind: TspKind): boolean;
|
|
66
88
|
/**
|
|
@@ -113,7 +135,11 @@ export type NativeUiEvent =
|
|
|
113
135
|
readonly value: boolean | number | string | readonly string[] | null;
|
|
114
136
|
}
|
|
115
137
|
/** An edit over the terminal's own selection in an `editor`/`input` node (see {@link NativeTextEdit}). */
|
|
116
|
-
| ({ readonly type: "edit"; readonly key: string } & NativeTextEdit)
|
|
138
|
+
| ({ readonly type: "edit"; readonly key: string } & NativeTextEdit)
|
|
139
|
+
/** Undo the last change to an `editor`/`input` node's text (the terminal's ⌃Z); a no-op with no history. */
|
|
140
|
+
| { readonly type: "undo"; readonly key: string }
|
|
141
|
+
/** Submit an explicit prompt through the composer's normal path, preserving the previous draft for recall. */
|
|
142
|
+
| { readonly type: "send"; readonly key: string; readonly text: string };
|
|
117
143
|
|
|
118
144
|
/**
|
|
119
145
|
* A primitive edit the terminal made over its own text selection (cut,
|
package/src/native/overlay.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* component's root is a `card` whose `head` carries the title.
|
|
8
8
|
*/
|
|
9
9
|
import type { TspProps, TspSpan, TspText } from "@linxiraos/pi-wire";
|
|
10
|
-
import type
|
|
10
|
+
import { type KeyName } from "../key-hint-format";
|
|
11
11
|
import { type Keybinding } from "../keybindings";
|
|
12
12
|
import type { NativeChild, NativeNode } from "./node";
|
|
13
13
|
/** One footer hint: the keys that trigger it and what it does. */
|
|
@@ -44,10 +44,10 @@ export interface ActionButtonOptions {
|
|
|
44
44
|
/** Sibling identity key (defaults to the action id); `leafKey(event.key)` reports it back. */
|
|
45
45
|
readonly key?: string;
|
|
46
46
|
/** Key id of the keyboard path the button mirrors, drawn as a keycap inside it (`"r"`, `"ctrl+g"`). */
|
|
47
|
-
readonly keys?:
|
|
47
|
+
readonly keys?: KeyName;
|
|
48
48
|
/** `accent` = the view's hero action, `error` = destructive. */
|
|
49
49
|
readonly tone?: "accent" | "error";
|
|
50
|
-
/** Tooltip; defaults to the label plus the keycap (`"Refresh r"
|
|
50
|
+
/** Tooltip; defaults to the label plus the keycap (`"Refresh r"`, see {@link formatTooltipKey}). */
|
|
51
51
|
readonly title?: string;
|
|
52
52
|
/** Target of an `open` action (URL or `file://` path). */
|
|
53
53
|
readonly href?: string;
|
|
@@ -58,6 +58,11 @@ export interface ActionButtonOptions {
|
|
|
58
58
|
* which the component routes to the same code path as the key.
|
|
59
59
|
*/
|
|
60
60
|
export declare function actionButton(label: string, act: string, options?: ActionButtonOptions): NativeNode;
|
|
61
|
+
/**
|
|
62
|
+
* A bare `esc` keycap button for a view's top-right corner: a click sends
|
|
63
|
+
* `act` (default `close`), which the component routes to its Esc path.
|
|
64
|
+
*/
|
|
65
|
+
export declare function escCloseButton(act?: string, key?: string): NativeNode;
|
|
61
66
|
/** A row of {@link actionButton}s (role `zeta.actions`); `null` entries become the spacer that end-aligns what follows. */
|
|
62
67
|
export declare function actionBar(buttons: readonly (NativeNode | null)[], key?: string): NativeNode;
|
|
63
68
|
/** Spans of an annotation callout: a dim `label:` then the note. */
|
package/src/native/overlay.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* component's root is a `card` whose `head` carries the title.
|
|
8
8
|
*/
|
|
9
9
|
import type { TspProps, TspSpan, TspText } from "@linxiraos/pi-wire";
|
|
10
|
-
import type
|
|
10
|
+
import { formatTooltipKey, type KeyName } from "../key-hint-format";
|
|
11
11
|
import { getKeybindings, type Keybinding } from "../keybindings";
|
|
12
12
|
import { card, kbd, list, node, row, span, text } from "./describe";
|
|
13
13
|
import type { NativeChild, NativeNode } from "./node";
|
|
@@ -86,10 +86,10 @@ export interface ActionButtonOptions {
|
|
|
86
86
|
/** Sibling identity key (defaults to the action id); `leafKey(event.key)` reports it back. */
|
|
87
87
|
readonly key?: string;
|
|
88
88
|
/** Key id of the keyboard path the button mirrors, drawn as a keycap inside it (`"r"`, `"ctrl+g"`). */
|
|
89
|
-
readonly keys?:
|
|
89
|
+
readonly keys?: KeyName;
|
|
90
90
|
/** `accent` = the view's hero action, `error` = destructive. */
|
|
91
91
|
readonly tone?: "accent" | "error";
|
|
92
|
-
/** Tooltip; defaults to the label plus the keycap (`"Refresh r"
|
|
92
|
+
/** Tooltip; defaults to the label plus the keycap (`"Refresh r"`, see {@link formatTooltipKey}). */
|
|
93
93
|
readonly title?: string;
|
|
94
94
|
/** Target of an `open` action (URL or `file://` path). */
|
|
95
95
|
readonly href?: string;
|
|
@@ -110,7 +110,7 @@ export function actionButton(label: string, act: string, options: ActionButtonOp
|
|
|
110
110
|
gap: "xs",
|
|
111
111
|
align: "center",
|
|
112
112
|
actions: { click: act },
|
|
113
|
-
title: options.title ?? (options.keys ? `${label} ${options.keys}` : label),
|
|
113
|
+
title: options.title ?? (options.keys ? `${label} ${formatTooltipKey(options.keys)}` : label),
|
|
114
114
|
...(options.tone ? { tone: options.tone } : {}),
|
|
115
115
|
...(options.href ? { href: options.href } : {}),
|
|
116
116
|
},
|
|
@@ -119,6 +119,19 @@ export function actionButton(label: string, act: string, options: ActionButtonOp
|
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* A bare `esc` keycap button for a view's top-right corner: a click sends
|
|
124
|
+
* `act` (default `close`), which the component routes to its Esc path.
|
|
125
|
+
*/
|
|
126
|
+
export function escCloseButton(act = "close", key = "esc-close"): NativeNode {
|
|
127
|
+
return node(
|
|
128
|
+
"row",
|
|
129
|
+
{ role: "zeta.btn", align: "center", actions: { click: act }, title: `Close ${formatTooltipKey("escape")}` },
|
|
130
|
+
[kbd("escape")],
|
|
131
|
+
key,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
122
135
|
/** A row of {@link actionButton}s (role `zeta.actions`); `null` entries become the spacer that end-aligns what follows. */
|
|
123
136
|
export function actionBar(buttons: readonly (NativeNode | null)[], key = "actions"): NativeNode {
|
|
124
137
|
const children = buttons.map(button => button ?? node("spacer", { grow: 1 }));
|
package/src/native/reconcile.ts
CHANGED
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
import * as logger from "@linxiraos/pi-utils/logger";
|
|
31
31
|
import { TSP_TEXT_KINDS, type TspKind, type TspNode, type TspOp, type TspScrollBy } from "@linxiraos/pi-wire";
|
|
32
32
|
import { type Component, Container, CURSOR_MARKER } from "../tui";
|
|
33
|
+
import { getNativeBlob } from "./blobs";
|
|
33
34
|
import { normalizeIconProps } from "./icons";
|
|
34
|
-
import type { DescribeContext, NativeChild, NativeNode } from "./node";
|
|
35
|
+
import type { DescribeContext, NativeChild, NativeNode, NativeRevealAt } from "./node";
|
|
35
36
|
import { isNativeSettled } from "./settle";
|
|
36
37
|
|
|
37
38
|
/** The regions a frame fills. */
|
|
@@ -213,8 +214,11 @@ export class Reconciler {
|
|
|
213
214
|
#ops: TspOp[] = [];
|
|
214
215
|
#dels: Entry[] = [];
|
|
215
216
|
#settles: string[] = [];
|
|
216
|
-
/**
|
|
217
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Selected list items, added `reveal` nodes and nodes whose reveal `n` moved this frame,
|
|
219
|
+
* revealed once the frame's adds have landed.
|
|
220
|
+
*/
|
|
221
|
+
#reveals: [id: string, at: NativeRevealAt][] = [];
|
|
218
222
|
/** `scroll` requests whose `n` moved this frame, sent after the reveals. */
|
|
219
223
|
#scrolls: [id: string, by: TspScrollBy][] = [];
|
|
220
224
|
/** Wire ids `list.selected` keys resolved to (an unresolved key names no node to reveal). */
|
|
@@ -288,6 +292,7 @@ export class Reconciler {
|
|
|
288
292
|
this.#prevPortals = portals;
|
|
289
293
|
this.#regions = next;
|
|
290
294
|
for (const entry of this.#dels) this.#deleteEntry(entry);
|
|
295
|
+
this.#dels = [];
|
|
291
296
|
// Parked to survive a parent/child swap but absent from the new description.
|
|
292
297
|
for (const state of this.#parked) {
|
|
293
298
|
if (!state.parked) continue;
|
|
@@ -595,6 +600,11 @@ export class Reconciler {
|
|
|
595
600
|
this.#revisitNode(next, inner);
|
|
596
601
|
return;
|
|
597
602
|
}
|
|
603
|
+
const reveal = next.node.reveal;
|
|
604
|
+
if (typeof reveal === "object") {
|
|
605
|
+
const was = old.node.reveal;
|
|
606
|
+
if (reveal.n !== (typeof was === "object" ? was.n : undefined)) this.#reveals.push([next.id, reveal.at]);
|
|
607
|
+
}
|
|
598
608
|
if (old.node.k !== next.node.k) {
|
|
599
609
|
this.#dropSubtree(old);
|
|
600
610
|
this.#ops.push(["del", next.id]);
|
|
@@ -703,6 +713,8 @@ export class Reconciler {
|
|
|
703
713
|
owner: Owner,
|
|
704
714
|
entries: readonly Entry[],
|
|
705
715
|
): Readonly<Record<string, unknown>> | undefined {
|
|
716
|
+
// Dereferencing pins the blob through this synchronous reconcile/upload job, even after settling drops its node.
|
|
717
|
+
if (node.k === "image" && node.p?.blob) getNativeBlob(node.p.blob);
|
|
706
718
|
return normalizeIconProps(node.k, this.#resolveRefs(node, owner, entries));
|
|
707
719
|
}
|
|
708
720
|
|
|
@@ -743,7 +755,7 @@ export class Reconciler {
|
|
|
743
755
|
|
|
744
756
|
/** A full wire subtree for an entry; nested components get states (or pending moves when mounted elsewhere). */
|
|
745
757
|
#materialize(entry: NodeEntry, walk: Walk): TspNode {
|
|
746
|
-
if (entry.node.reveal) this.#reveals.push([entry.id, entry.node.reveal]);
|
|
758
|
+
if (typeof entry.node.reveal === "string") this.#reveals.push([entry.id, entry.node.reveal]);
|
|
747
759
|
const entries = this.#entries(entry.node.c, entry.keypath, entry.owner, entry.hoist, walk);
|
|
748
760
|
const children: TspNode[] = [];
|
|
749
761
|
for (let i = 0; i < entries.length; i++) {
|
package/src/native/settle.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Settling: the frame provider marks finalized transcript blocks so the
|
|
3
|
-
* native reconciler stops keeping their description (
|
|
4
|
-
*
|
|
5
|
-
* targeted ops by id, followed by a fresh `settle`
|
|
3
|
+
* native reconciler stops keeping their description (Tern SDK,
|
|
4
|
+
* `protocol/operations.md`, "Settling"). A settled block stays editable: a
|
|
5
|
+
* later change is sent as targeted ops by id, followed by a fresh `settle`
|
|
6
|
+
* hint.
|
|
6
7
|
*/
|
|
7
8
|
import type { Component } from "../tui";
|
|
8
9
|
/** Mark `component` (and everything it describes) as finalized. Idempotent; a no-op outside a TSP terminal. */
|
package/src/native/settle.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Settling: the frame provider marks finalized transcript blocks so the
|
|
3
|
-
* native reconciler stops keeping their description (
|
|
4
|
-
*
|
|
5
|
-
* targeted ops by id, followed by a fresh `settle`
|
|
3
|
+
* native reconciler stops keeping their description (Tern SDK,
|
|
4
|
+
* `protocol/operations.md`, "Settling"). A settled block stays editable: a
|
|
5
|
+
* later change is sent as targeted ops by id, followed by a fresh `settle`
|
|
6
|
+
* hint.
|
|
6
7
|
*/
|
|
7
8
|
import type { Component } from "../tui";
|
|
8
9
|
|
|
@@ -15,11 +15,12 @@ interface AgentTreeProjection<TRecord extends AgentRecordLike> {
|
|
|
15
15
|
export declare const STATUS_ORDER: Record<AgentStatus, number>;
|
|
16
16
|
/** Exact observer usage for one roster entry. */
|
|
17
17
|
export declare function progressMetrics(observed: ObservableSession | undefined): AgentMetrics | undefined;
|
|
18
|
-
/** Live session
|
|
18
|
+
/** Live session used to cache a row's direct assistant usage, including with observer progress. */
|
|
19
19
|
export declare function hubFallbackStatsSession<TRecord extends AgentRecordLike>(ref: TRecord, observed: ObservableSession | undefined): NonNullable<TRecord["session"]> | undefined;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Preserve progress/history for non-cost metrics, overlaying cumulative direct-session cost.
|
|
22
|
+
* Persisted `history.metrics.cost` is a leaf-scoped snapshot, so it never overrides live
|
|
23
|
+
* progress; only the cumulative direct-cost sources do.
|
|
23
24
|
*/
|
|
24
25
|
export declare function hubRowMetrics<TRecord extends AgentRecordLike>(ref: TRecord, observed: ObservableSession | undefined, sessionMetrics: WeakMap<object, {
|
|
25
26
|
metrics: AgentMetrics | undefined;
|
|
@@ -37,6 +38,6 @@ export declare function aggregateMetrics<TRecord extends AgentRecordLike>(args:
|
|
|
37
38
|
metrics: AggregateMetrics;
|
|
38
39
|
hasFallbackLiveSessions: boolean;
|
|
39
40
|
};
|
|
40
|
-
/** Parent-before-child projection preserving
|
|
41
|
-
export declare function projectAgentTree<TRecord extends AgentRecordLike>(refs: readonly TRecord[]): AgentTreeProjection<TRecord>;
|
|
41
|
+
/** Parent-before-child projection preserving initial subtree rank and prepending new siblings. */
|
|
42
|
+
export declare function projectAgentTree<TRecord extends AgentRecordLike>(refs: readonly TRecord[], rosterRank: ReadonlyMap<TRecord, number> | undefined): AgentTreeProjection<TRecord>;
|
|
42
43
|
export {};
|