@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
|
@@ -53,11 +53,15 @@ export function matchesSelectPageDown(data: string): boolean {
|
|
|
53
53
|
return getKeybindings().matches(data, "tui.select.pageDown");
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/** Effective external-editor key: the first bound key, or Ctrl+G when unbound. */
|
|
57
|
+
export function appExternalEditorKey(): KeyId {
|
|
58
|
+
return getKeybindings().getKeys("app.editor.external")[0] ?? "ctrl+g";
|
|
59
|
+
}
|
|
60
|
+
|
|
56
61
|
/** Match the external-editor keybinding, falling back to Ctrl+G when unbound. */
|
|
57
62
|
export function matchesAppExternalEditor(data: string): boolean {
|
|
58
63
|
const keybindings = getKeybindings();
|
|
59
|
-
|
|
60
|
-
if (externalEditorKeys.length > 0) {
|
|
64
|
+
if (keybindings.getKeys("app.editor.external").length > 0) {
|
|
61
65
|
return keybindings.matches(data, "app.editor.external");
|
|
62
66
|
}
|
|
63
67
|
return matchesKey(data, "ctrl+g");
|
package/src/keybindings.d.ts
CHANGED
|
@@ -107,7 +107,7 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
107
107
|
readonly description: "Delete word backward";
|
|
108
108
|
};
|
|
109
109
|
readonly "tui.editor.deleteWordForward": {
|
|
110
|
-
readonly defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+alt+d"];
|
|
110
|
+
readonly defaultKeys: ["alt+delete", "alt+d", "ctrl+delete", "super+alt+delete", "super+alt+d"];
|
|
111
111
|
readonly description: "Delete word forward";
|
|
112
112
|
};
|
|
113
113
|
readonly "tui.editor.deleteToLineStart": {
|
package/src/keybindings.ts
CHANGED
|
@@ -105,7 +105,7 @@ export const TUI_KEYBINDINGS = {
|
|
|
105
105
|
description: "Delete word backward",
|
|
106
106
|
},
|
|
107
107
|
"tui.editor.deleteWordForward": {
|
|
108
|
-
defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+alt+d"],
|
|
108
|
+
defaultKeys: ["alt+delete", "alt+d", "ctrl+delete", "super+alt+delete", "super+alt+d"],
|
|
109
109
|
description: "Delete word forward",
|
|
110
110
|
},
|
|
111
111
|
"tui.editor.deleteToLineStart": {
|
package/src/kitty-graphics.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export interface KittyGraphicsFeatures {
|
|
|
30
30
|
* cannot use cursor-positioned placements because the outer terminal does not
|
|
31
31
|
* know pane scroll/reflow state. An explicit `PI_FORCE_IMAGE_PROTOCOL=kitty`
|
|
32
32
|
* opts into placeholders under any multiplexer — matching `timg -pk`.
|
|
33
|
-
* Automatic
|
|
34
|
-
* that
|
|
33
|
+
* Automatic fallback stays off inside multiplexers whose pane marker does not
|
|
34
|
+
* prove that a Kitty renderer is enabled (Herdr's is experimental).
|
|
35
35
|
*
|
|
36
36
|
* `PI_NO_KITTY_PLACEHOLDERS=1` and `PI_KITTY_PLACEHOLDERS=0` remain hard
|
|
37
37
|
* opt-outs; `PI_KITTY_PLACEHOLDERS=1` explicitly opts in anywhere else.
|
package/src/kitty-graphics.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* forms. Protocol gating (`imageProtocol === Kitty`) lives in the caller.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { isInsideTerminalMultiplexer, terminalMultiplexerSessions } from "./terminal-multiplexer";
|
|
19
19
|
import { wrapTmuxPassthroughIfNeeded } from "./tmux";
|
|
20
20
|
|
|
21
21
|
/** Kitty Unicode placeholder base character (U+10EEEE, Plane 16 PUA). */
|
|
@@ -67,8 +67,8 @@ export interface KittyGraphicsFeatures {
|
|
|
67
67
|
* cannot use cursor-positioned placements because the outer terminal does not
|
|
68
68
|
* know pane scroll/reflow state. An explicit `PI_FORCE_IMAGE_PROTOCOL=kitty`
|
|
69
69
|
* opts into placeholders under any multiplexer — matching `timg -pk`.
|
|
70
|
-
* Automatic
|
|
71
|
-
* that
|
|
70
|
+
* Automatic fallback stays off inside multiplexers whose pane marker does not
|
|
71
|
+
* prove that a Kitty renderer is enabled (Herdr's is experimental).
|
|
72
72
|
*
|
|
73
73
|
* `PI_NO_KITTY_PLACEHOLDERS=1` and `PI_KITTY_PLACEHOLDERS=0` remain hard
|
|
74
74
|
* opt-outs; `PI_KITTY_PLACEHOLDERS=1` explicitly opts in anywhere else.
|
|
@@ -81,8 +81,14 @@ export function detectKittyUnicodePlaceholdersSupport(terminalId: string, env: N
|
|
|
81
81
|
if (force === "0" || force === "false" || force === "off" || force === "no" || force === "n") return false;
|
|
82
82
|
const insideMultiplexer = isInsideTerminalMultiplexer(env);
|
|
83
83
|
if (insideMultiplexer && env.PI_FORCE_IMAGE_PROTOCOL?.trim().toLowerCase() === "kitty") return true;
|
|
84
|
-
if (
|
|
85
|
-
return
|
|
84
|
+
if (terminalMultiplexerSessions(env).some(multiplexer => multiplexer.imagesRequireOverride)) return false;
|
|
85
|
+
return (
|
|
86
|
+
terminalId === "kitty" ||
|
|
87
|
+
terminalId === "ghostty" ||
|
|
88
|
+
terminalId === "monstar" ||
|
|
89
|
+
terminalId === "otty" ||
|
|
90
|
+
terminalId === "rio"
|
|
91
|
+
);
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
let features: KittyGraphicsFeatures = {
|
package/src/loop-watchdog.d.ts
CHANGED
|
@@ -21,13 +21,14 @@ interface LoopWatchdogTimer {
|
|
|
21
21
|
cancel?(): void;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead
|
|
25
|
-
*
|
|
26
|
-
* the loop was blocked that long. The overshoot is
|
|
27
|
-
* edge (one block ⇒ one line, deduped via
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
24
|
+
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead,
|
|
25
|
+
* with that target recorded as its deadline; a tick that fires `thresholdMs`
|
|
26
|
+
* past its deadline means the loop was blocked that long. The overshoot is
|
|
27
|
+
* logged once on the rising edge (one block ⇒ one line, deduped via
|
|
28
|
+
* `#wasBlocked`). Attribution via
|
|
29
|
+
* {@link takeLoopPhaseAttribution} totals each innermost phase only after the tick's
|
|
30
|
+
* deadline. A phase is named, with `phaseMs`, only when its total outweighs all
|
|
31
|
+
* unlabeled time in that late window; otherwise the block remains "unknown".
|
|
31
32
|
*
|
|
32
33
|
* The handle is `unref`'d so the probe never keeps the process alive, and stop()
|
|
33
34
|
* cancels the armed timer when the handle exposes `cancel` (the default
|
package/src/loop-watchdog.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { performance } from "node:perf_hooks";
|
|
2
|
-
import { logger,
|
|
2
|
+
import { logger, resetLoopPhaseWindow, takeLoopPhaseAttribution } from "@linxiraos/pi-utils";
|
|
3
3
|
|
|
4
4
|
export interface LoopWatchdogOptions {
|
|
5
5
|
/** How far ahead each probe tick is scheduled, in ms. Default 250. */
|
|
@@ -35,13 +35,14 @@ interface LoopWatchdogTimer {
|
|
|
35
35
|
const CPU_BUSY_RATIO = 0.01;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead
|
|
39
|
-
*
|
|
40
|
-
* the loop was blocked that long. The overshoot is
|
|
41
|
-
* edge (one block ⇒ one line, deduped via
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
38
|
+
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead,
|
|
39
|
+
* with that target recorded as its deadline; a tick that fires `thresholdMs`
|
|
40
|
+
* past its deadline means the loop was blocked that long. The overshoot is
|
|
41
|
+
* logged once on the rising edge (one block ⇒ one line, deduped via
|
|
42
|
+
* `#wasBlocked`). Attribution via
|
|
43
|
+
* {@link takeLoopPhaseAttribution} totals each innermost phase only after the tick's
|
|
44
|
+
* deadline. A phase is named, with `phaseMs`, only when its total outweighs all
|
|
45
|
+
* unlabeled time in that late window; otherwise the block remains "unknown".
|
|
45
46
|
*
|
|
46
47
|
* The handle is `unref`'d so the probe never keeps the process alive, and stop()
|
|
47
48
|
* cancels the armed timer when the handle exposes `cancel` (the default
|
|
@@ -101,12 +102,15 @@ export class LoopWatchdog {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
stop(): void {
|
|
105
|
+
// Attribution state is process-global: a watchdog that is not running must not disarm another's window.
|
|
106
|
+
if (!this.#running) return;
|
|
104
107
|
this.#running = false;
|
|
105
108
|
this.#wasBlocked = false;
|
|
106
109
|
this.#stallEndedAt = Number.NEGATIVE_INFINITY;
|
|
107
110
|
this.#generation++;
|
|
108
111
|
this.#handle?.cancel?.();
|
|
109
112
|
this.#handle = undefined;
|
|
113
|
+
resetLoopPhaseWindow();
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
/**
|
|
@@ -133,6 +137,7 @@ export class LoopWatchdog {
|
|
|
133
137
|
#armTick(): void {
|
|
134
138
|
const generation = this.#generation;
|
|
135
139
|
this.#expected = this.#now() + this.#intervalMs;
|
|
140
|
+
resetLoopPhaseWindow(this.#expected, this.#now);
|
|
136
141
|
this.#expectedCpu = this.#cpuNow();
|
|
137
142
|
this.#handle = this.#schedule(() => this.#tick(generation), this.#intervalMs);
|
|
138
143
|
this.#handle.unref?.();
|
|
@@ -143,10 +148,9 @@ export class LoopWatchdog {
|
|
|
143
148
|
const now = this.#now();
|
|
144
149
|
const blockedMs = now - this.#expected;
|
|
145
150
|
const cpuMs = this.#cpuNow() - this.#expectedCpu;
|
|
146
|
-
// Consume
|
|
147
|
-
//
|
|
148
|
-
|
|
149
|
-
const phase = takeRecentLoopPhase();
|
|
151
|
+
// Consume every valid tick, even without a warning, so no phase carries
|
|
152
|
+
// forward into a later, phase-less block.
|
|
153
|
+
const phase = takeLoopPhaseAttribution(now);
|
|
150
154
|
if (blockedMs > this.#thresholdMs) {
|
|
151
155
|
if (this.#isSuspension(blockedMs, cpuMs)) {
|
|
152
156
|
this.#wasBlocked = false;
|
|
@@ -157,7 +161,8 @@ export class LoopWatchdog {
|
|
|
157
161
|
logger.warn("ui.loop-blocked", {
|
|
158
162
|
blockedMs: Math.round(blockedMs),
|
|
159
163
|
cpuMs: Math.round(cpuMs),
|
|
160
|
-
phase: phase ?? "unknown",
|
|
164
|
+
phase: phase?.label ?? "unknown",
|
|
165
|
+
...(phase ? { phaseMs: Math.round(phase.ms) } : {}),
|
|
161
166
|
});
|
|
162
167
|
}
|
|
163
168
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const cmuxMultiplexer: {
|
|
2
|
+
readonly id: "cmux";
|
|
3
|
+
readonly precedence: "session";
|
|
4
|
+
readonly sessionEnvKeys: readonly ["CMUX_WORKSPACE_ID", "CMUX_SURFACE_ID", "CMUX_REMOTE_TRANSPORT"];
|
|
5
|
+
readonly ownsScreenGrid: true;
|
|
6
|
+
readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Workspace/socket state alone is not enough: only the injected surface UUID
|
|
9
|
+
* identifies the pane that should receive the notification. Without a valid
|
|
10
|
+
* surface, or without the binary, delivery falls through unchanged.
|
|
11
|
+
*/
|
|
12
|
+
readonly notifier: {
|
|
13
|
+
readonly tier: "surface";
|
|
14
|
+
readonly send: ({ message, env }: import("./types").TerminalMultiplexerNotificationRequest) => boolean;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { notificationTitleAndBody, spawnNotifier } from "./notify";
|
|
2
|
+
import type { TerminalMultiplexerModule } from "./types";
|
|
3
|
+
|
|
4
|
+
const CMUX_SURFACE_ID_PATTERN = /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/iu;
|
|
5
|
+
|
|
6
|
+
export const cmuxMultiplexer = {
|
|
7
|
+
id: "cmux",
|
|
8
|
+
precedence: "session",
|
|
9
|
+
// CMUX_SOCKET_PATH is a CLI socket override and can be set outside a CMUX terminal.
|
|
10
|
+
sessionEnvKeys: ["CMUX_WORKSPACE_ID", "CMUX_SURFACE_ID", "CMUX_REMOTE_TRANSPORT"],
|
|
11
|
+
ownsScreenGrid: true,
|
|
12
|
+
isInside(env: NodeJS.ProcessEnv = Bun.env): boolean {
|
|
13
|
+
return Boolean(env.CMUX_WORKSPACE_ID || env.CMUX_SURFACE_ID || env.CMUX_REMOTE_TRANSPORT);
|
|
14
|
+
},
|
|
15
|
+
/**
|
|
16
|
+
* Workspace/socket state alone is not enough: only the injected surface UUID
|
|
17
|
+
* identifies the pane that should receive the notification. Without a valid
|
|
18
|
+
* surface, or without the binary, delivery falls through unchanged.
|
|
19
|
+
*/
|
|
20
|
+
notifier: {
|
|
21
|
+
tier: "surface",
|
|
22
|
+
send({ message, env }) {
|
|
23
|
+
const surfaceId = env.CMUX_SURFACE_ID?.trim();
|
|
24
|
+
if (!surfaceId || !CMUX_SURFACE_ID_PATTERN.test(surfaceId)) return false;
|
|
25
|
+
const { title, body } = notificationTitleAndBody(message);
|
|
26
|
+
return spawnNotifier(["cmux", "notify", "--surface", surfaceId, "--title", title, "--body", body]);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
} as const satisfies TerminalMultiplexerModule;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const herdrMultiplexer: {
|
|
2
|
+
readonly id: "herdr";
|
|
3
|
+
readonly precedence: "session";
|
|
4
|
+
readonly sessionEnvKeys: readonly ["HERDR_ENV", "HERDR_PANE_ID", "HERDR_TAB_ID", "HERDR_WORKSPACE_ID"];
|
|
5
|
+
readonly ownsScreenGrid: true;
|
|
6
|
+
readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Herdr multiplexes panes like tmux but swallows bare OSC 9 / OSC 99 and has
|
|
9
|
+
* no DCS passthrough envelope, and its bell relay does not flag a
|
|
10
|
+
* backgrounded tab — so without its CLI a backgrounded pane gets no signal
|
|
11
|
+
* at all that the agent finished or is waiting for input.
|
|
12
|
+
*
|
|
13
|
+
* `sound` maps the notification kind onto what Herdr offers: a question
|
|
14
|
+
* waiting on the user and a turn that stopped with an error both need the
|
|
15
|
+
* human and ring `request`, a settled turn rings `done`, anything else stays
|
|
16
|
+
* silent. The exact pane ID addresses the CLI call; without a valid one, or
|
|
17
|
+
* without the binary, delivery falls through.
|
|
18
|
+
*/
|
|
19
|
+
readonly notifier: {
|
|
20
|
+
readonly tier: "pane";
|
|
21
|
+
readonly send: ({ message, env }: import("./types").TerminalMultiplexerNotificationRequest) => boolean;
|
|
22
|
+
};
|
|
23
|
+
readonly hyperlinks: "render";
|
|
24
|
+
readonly honorsSynchronizedOutput: true;
|
|
25
|
+
readonly imagesRequireOverride: true;
|
|
26
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { DEFAULT_NOTIFICATION_TITLE, notificationTitleAndBody, spawnNotifier } from "./notify";
|
|
2
|
+
import type { TerminalMultiplexerModule } from "./types";
|
|
3
|
+
|
|
4
|
+
const HERDR_PANE_ID_PATTERN = /^[0-9A-Za-z:_-]{1,64}$/u;
|
|
5
|
+
/**
|
|
6
|
+
* `herdr notification show` takes the title as its first positional and reads
|
|
7
|
+
* exactly these three values there as a help request; it has no `--`
|
|
8
|
+
* terminator. Any other text, including one starting with `-`, is a title.
|
|
9
|
+
*/
|
|
10
|
+
const HERDR_USAGE_TOKENS: Record<string, true> = { help: true, "--help": true, "-h": true };
|
|
11
|
+
|
|
12
|
+
export const herdrMultiplexer = {
|
|
13
|
+
id: "herdr",
|
|
14
|
+
precedence: "session",
|
|
15
|
+
sessionEnvKeys: ["HERDR_ENV", "HERDR_PANE_ID", "HERDR_TAB_ID", "HERDR_WORKSPACE_ID"],
|
|
16
|
+
ownsScreenGrid: true,
|
|
17
|
+
isInside(env: NodeJS.ProcessEnv = Bun.env): boolean {
|
|
18
|
+
// Identity vars survive env-sanitizing launchers that drop HERDR_ENV.
|
|
19
|
+
// Client-only socket, binary, session, and config overrides are not proof
|
|
20
|
+
// that this process runs inside a pane.
|
|
21
|
+
return env.HERDR_ENV === "1" || Boolean(env.HERDR_PANE_ID || env.HERDR_TAB_ID || env.HERDR_WORKSPACE_ID);
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* Herdr multiplexes panes like tmux but swallows bare OSC 9 / OSC 99 and has
|
|
25
|
+
* no DCS passthrough envelope, and its bell relay does not flag a
|
|
26
|
+
* backgrounded tab — so without its CLI a backgrounded pane gets no signal
|
|
27
|
+
* at all that the agent finished or is waiting for input.
|
|
28
|
+
*
|
|
29
|
+
* `sound` maps the notification kind onto what Herdr offers: a question
|
|
30
|
+
* waiting on the user and a turn that stopped with an error both need the
|
|
31
|
+
* human and ring `request`, a settled turn rings `done`, anything else stays
|
|
32
|
+
* silent. The exact pane ID addresses the CLI call; without a valid one, or
|
|
33
|
+
* without the binary, delivery falls through.
|
|
34
|
+
*/
|
|
35
|
+
notifier: {
|
|
36
|
+
tier: "pane",
|
|
37
|
+
send({ message, env }) {
|
|
38
|
+
const paneId = env.HERDR_PANE_ID?.trim();
|
|
39
|
+
if (!paneId || !HERDR_PANE_ID_PATTERN.test(paneId)) return false;
|
|
40
|
+
|
|
41
|
+
const parsed = notificationTitleAndBody(message);
|
|
42
|
+
const title = Object.hasOwn(HERDR_USAGE_TOKENS, parsed.title) ? DEFAULT_NOTIFICATION_TITLE : parsed.title;
|
|
43
|
+
const kinds = typeof message === "string" ? [] : [message.type ?? []].flat();
|
|
44
|
+
const sound =
|
|
45
|
+
kinds.includes("ask") || kinds.includes("error")
|
|
46
|
+
? "request"
|
|
47
|
+
: kinds.includes("completion")
|
|
48
|
+
? "done"
|
|
49
|
+
: "none";
|
|
50
|
+
return spawnNotifier(["herdr", "notification", "show", title, "--body", parsed.body, "--sound", sound]);
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
// Herdr hides the outer terminal (`TERM=xterm-256color`, no `TERM_PROGRAM`),
|
|
54
|
+
// but renders OSC 8 in its own grid and opens links itself on Ctrl+click.
|
|
55
|
+
hyperlinks: "render",
|
|
56
|
+
// The pane VTE is libghostty and suppresses compositing while DEC 2026 is
|
|
57
|
+
// set. Without sync, CUP-diff paints and split write(2) chunks composite as
|
|
58
|
+
// dirty-row patches: the live viewport tears, its top frozen while only the
|
|
59
|
+
// bottom refreshes.
|
|
60
|
+
honorsSynchronizedOutput: true,
|
|
61
|
+
// The pane marker does not prove the client enabled Herdr's experimental
|
|
62
|
+
// Kitty renderer, and leaked outer-terminal identities cannot either.
|
|
63
|
+
imagesRequireOverride: true,
|
|
64
|
+
} as const satisfies TerminalMultiplexerModule;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TerminalNotification } from "../terminal-capabilities";
|
|
2
|
+
/** Title for out-of-band multiplexer notifications that carry none of their own. */
|
|
3
|
+
export declare const DEFAULT_NOTIFICATION_TITLE = "omp";
|
|
4
|
+
/** Title and body for an out-of-band multiplexer notification (cmux, Herdr). */
|
|
5
|
+
export declare function notificationTitleAndBody(message: string | TerminalNotification): {
|
|
6
|
+
title: string;
|
|
7
|
+
body: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Start a notifier CLI without waiting for or pinning it. Returns false when
|
|
11
|
+
* the binary cannot be spawned, which leaves delivery to the terminal fallback.
|
|
12
|
+
*/
|
|
13
|
+
export declare function spawnNotifier(cmd: string[]): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TerminalNotification } from "../terminal-capabilities";
|
|
2
|
+
|
|
3
|
+
/** Title for out-of-band multiplexer notifications that carry none of their own. */
|
|
4
|
+
export const DEFAULT_NOTIFICATION_TITLE = "omp";
|
|
5
|
+
|
|
6
|
+
/** Title and body for an out-of-band multiplexer notification (cmux, Herdr). */
|
|
7
|
+
export function notificationTitleAndBody(message: string | TerminalNotification): { title: string; body: string } {
|
|
8
|
+
if (typeof message === "string") return { title: DEFAULT_NOTIFICATION_TITLE, body: message };
|
|
9
|
+
return { title: message.title?.trim() || DEFAULT_NOTIFICATION_TITLE, body: message.body ?? "" };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Start a notifier CLI without waiting for or pinning it. Returns false when
|
|
14
|
+
* the binary cannot be spawned, which leaves delivery to the terminal fallback.
|
|
15
|
+
*/
|
|
16
|
+
export function spawnNotifier(cmd: string[]): boolean {
|
|
17
|
+
try {
|
|
18
|
+
const child = Bun.spawn({ cmd, stdin: "ignore", stdout: "ignore", stderr: "ignore" });
|
|
19
|
+
child.unref();
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orca is an xterm.js-based IDE whose terminals expose paired pane/worktree IDs.
|
|
3
|
+
* It is recognized for launches, but it ranks below nested multiplexers and keeps
|
|
4
|
+
* the direct-terminal render path it used before it was recognized.
|
|
5
|
+
*/
|
|
6
|
+
export declare const orcaMultiplexer: {
|
|
7
|
+
readonly id: "orca";
|
|
8
|
+
readonly precedence: "outerApp";
|
|
9
|
+
readonly sessionEnvKeys: readonly ["ORCA_PANE_KEY", "ORCA_WORKTREE_ID"];
|
|
10
|
+
readonly ownsScreenGrid: false;
|
|
11
|
+
readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
|
|
12
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TerminalMultiplexerModule } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Orca is an xterm.js-based IDE whose terminals expose paired pane/worktree IDs.
|
|
5
|
+
* It is recognized for launches, but it ranks below nested multiplexers and keeps
|
|
6
|
+
* the direct-terminal render path it used before it was recognized.
|
|
7
|
+
*/
|
|
8
|
+
export const orcaMultiplexer = {
|
|
9
|
+
id: "orca",
|
|
10
|
+
precedence: "outerApp",
|
|
11
|
+
sessionEnvKeys: ["ORCA_PANE_KEY", "ORCA_WORKTREE_ID"],
|
|
12
|
+
ownsScreenGrid: false,
|
|
13
|
+
isInside(env: NodeJS.ProcessEnv = Bun.env): boolean {
|
|
14
|
+
return Boolean(env.ORCA_PANE_KEY?.trim() && env.ORCA_WORKTREE_ID?.trim());
|
|
15
|
+
},
|
|
16
|
+
} as const satisfies TerminalMultiplexerModule;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const screenMultiplexer: {
|
|
2
|
+
readonly id: "screen";
|
|
3
|
+
readonly precedence: "session";
|
|
4
|
+
readonly sessionEnvKeys: readonly ["STY"];
|
|
5
|
+
readonly termPrefix: "screen";
|
|
6
|
+
readonly ownsScreenGrid: true;
|
|
7
|
+
readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
|
|
8
|
+
readonly hyperlinks: "drop";
|
|
9
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TerminalMultiplexerModule } from "./types";
|
|
2
|
+
|
|
3
|
+
export const screenMultiplexer = {
|
|
4
|
+
id: "screen",
|
|
5
|
+
precedence: "session",
|
|
6
|
+
sessionEnvKeys: ["STY"],
|
|
7
|
+
termPrefix: "screen",
|
|
8
|
+
ownsScreenGrid: true,
|
|
9
|
+
isInside(env: NodeJS.ProcessEnv = Bun.env): boolean {
|
|
10
|
+
return Boolean(env.STY);
|
|
11
|
+
},
|
|
12
|
+
// GNU screen never gained OSC 8 support, so a screen layer anywhere in the
|
|
13
|
+
// path vetoes hyperlinks, even under a nested tmux.
|
|
14
|
+
hyperlinks: "drop",
|
|
15
|
+
} as const satisfies TerminalMultiplexerModule;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Wrap a control sequence in tmux's DCS passthrough envelope. */
|
|
2
|
+
export declare function wrapTmuxPassthrough(payload: string): string;
|
|
3
|
+
export declare const tmuxMultiplexer: {
|
|
4
|
+
readonly id: "tmux";
|
|
5
|
+
readonly precedence: "session";
|
|
6
|
+
readonly sessionEnvKeys: readonly ["TMUX"];
|
|
7
|
+
readonly termPrefix: "tmux";
|
|
8
|
+
readonly ownsScreenGrid: true;
|
|
9
|
+
readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
|
|
10
|
+
readonly notifier: {
|
|
11
|
+
readonly tier: "inBand";
|
|
12
|
+
readonly send: ({ sequence, write }: import("./types").TerminalMultiplexerNotificationRequest) => boolean;
|
|
13
|
+
};
|
|
14
|
+
readonly hyperlinks: {
|
|
15
|
+
readonly forward: {
|
|
16
|
+
readonly termProgram: "tmux";
|
|
17
|
+
readonly major: 3;
|
|
18
|
+
readonly minor: 4;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
readonly backgroundColorCache: {
|
|
22
|
+
readonly passthrough: typeof wrapTmuxPassthrough;
|
|
23
|
+
readonly settleMs: 100;
|
|
24
|
+
};
|
|
25
|
+
readonly expandsRepPadding: true;
|
|
26
|
+
readonly expiresSynchronizedOutput: true;
|
|
27
|
+
readonly altRestoreEndsSynchronizedOutput: true;
|
|
28
|
+
readonly growsBeforeSigwinch: true;
|
|
29
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { TerminalMultiplexerModule } from "./types";
|
|
2
|
+
|
|
3
|
+
/** Wrap a control sequence in tmux's DCS passthrough envelope. */
|
|
4
|
+
export function wrapTmuxPassthrough(payload: string): string {
|
|
5
|
+
return `\x1bPtmux;${payload.replaceAll("\x1b", "\x1b\x1b")}\x1b\\`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const tmuxMultiplexer = {
|
|
9
|
+
id: "tmux",
|
|
10
|
+
precedence: "session",
|
|
11
|
+
sessionEnvKeys: ["TMUX"],
|
|
12
|
+
termPrefix: "tmux",
|
|
13
|
+
ownsScreenGrid: true,
|
|
14
|
+
isInside(env: NodeJS.ProcessEnv = Bun.env): boolean {
|
|
15
|
+
return Boolean(env.TMUX);
|
|
16
|
+
},
|
|
17
|
+
notifier: {
|
|
18
|
+
tier: "inBand",
|
|
19
|
+
// tmux swallows bare OSCs; passthrough preserves the toast and BEL flags
|
|
20
|
+
// the pane. Bell notifications already provide that signal. One write
|
|
21
|
+
// keeps a concurrent renderer from interleaving between the two.
|
|
22
|
+
send({ sequence, write }) {
|
|
23
|
+
if (sequence === null) return false;
|
|
24
|
+
write(`${wrapTmuxPassthrough(sequence)}\x07`);
|
|
25
|
+
return true;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
// tmux 3.4 stores OSC 8 as a cell attribute and forwards it to outer
|
|
29
|
+
// terminals whose `terminal-features` include `hyperlinks`; it self-reports
|
|
30
|
+
// via TERM_PROGRAM/TERM_PROGRAM_VERSION since 3.2a.
|
|
31
|
+
hyperlinks: { forward: { termProgram: "tmux", major: 3, minor: 4 } },
|
|
32
|
+
// An explicit appearance refresh passes OSC 11 to the outer terminal, then
|
|
33
|
+
// re-reads tmux's cache once it has consumed the reply.
|
|
34
|
+
backgroundColorCache: { passthrough: wrapTmuxPassthrough, settleMs: 100 },
|
|
35
|
+
expandsRepPadding: true,
|
|
36
|
+
// tmux expires synchronized output after one second.
|
|
37
|
+
expiresSynchronizedOutput: true,
|
|
38
|
+
altRestoreEndsSynchronizedOutput: true,
|
|
39
|
+
growsBeforeSigwinch: true,
|
|
40
|
+
} as const satisfies TerminalMultiplexerModule;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { TerminalNotification } from "../terminal-capabilities";
|
|
2
|
+
/**
|
|
3
|
+
* Classification tier. `session` markers outrank the TERM fallback; `outerApp`
|
|
4
|
+
* hosts rank below it so a multiplexer nested inside them still wins.
|
|
5
|
+
*/
|
|
6
|
+
export type TerminalMultiplexerPrecedence = "session" | "outerApp";
|
|
7
|
+
/**
|
|
8
|
+
* Notification delivery tier, tried in this order so the innermost target wins:
|
|
9
|
+
* a `pane` notifier addresses the exact pane through the multiplexer's CLI, a
|
|
10
|
+
* `surface` notifier addresses the containing app surface, and an `inBand`
|
|
11
|
+
* notifier rewrites the terminal's own notification sequence.
|
|
12
|
+
*/
|
|
13
|
+
export type TerminalMultiplexerNotificationTier = "pane" | "surface" | "inBand";
|
|
14
|
+
/** One notification offered to a multiplexer notifier. */
|
|
15
|
+
export interface TerminalMultiplexerNotificationRequest {
|
|
16
|
+
readonly message: string | TerminalNotification;
|
|
17
|
+
readonly env: NodeJS.ProcessEnv;
|
|
18
|
+
/** The host terminal's formatted OSC notification, or `null` when it notifies with a bare BEL. */
|
|
19
|
+
readonly sequence: string | null;
|
|
20
|
+
/** Write a sequence through the active terminal. */
|
|
21
|
+
write(data: string): void;
|
|
22
|
+
}
|
|
23
|
+
export interface TerminalMultiplexerNotifier {
|
|
24
|
+
readonly tier: TerminalMultiplexerNotificationTier;
|
|
25
|
+
/** Deliver the notification. `false` leaves it to the next notifier and then the terminal fallback. */
|
|
26
|
+
send(request: TerminalMultiplexerNotificationRequest): boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* OSC 8 handling inside a multiplexer session:
|
|
30
|
+
* - `render`: the multiplexer draws and opens links itself, so links work
|
|
31
|
+
* whatever the outer terminal supports, unless another session with a
|
|
32
|
+
* hyperlink policy sits in the path.
|
|
33
|
+
* - `drop`: never forwards OSC 8; its session anywhere in the path disables links.
|
|
34
|
+
* - `forward`: forwards OSC 8 once it self-reports (`TERM_PROGRAM`/`TERM_PROGRAM_VERSION`)
|
|
35
|
+
* at least `major.minor`; older or unreported versions stay off.
|
|
36
|
+
*/
|
|
37
|
+
export type TerminalMultiplexerHyperlinks = "render" | "drop" | {
|
|
38
|
+
readonly forward: {
|
|
39
|
+
/** Lowercase `TERM_PROGRAM` the multiplexer sets inside its panes. */
|
|
40
|
+
readonly termProgram: string;
|
|
41
|
+
readonly major: number;
|
|
42
|
+
readonly minor: number;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** A multiplexer that answers OSC 11 from a cached copy of the outer terminal's background color. */
|
|
46
|
+
export interface TerminalMultiplexerBackgroundColorCache {
|
|
47
|
+
/** Wrap a query so it reaches the outer terminal and refreshes the cache. */
|
|
48
|
+
passthrough(query: string): string;
|
|
49
|
+
/** How long the multiplexer needs to store the outer reply before the cache is re-read. */
|
|
50
|
+
readonly settleMs: number;
|
|
51
|
+
}
|
|
52
|
+
/** Everything omp needs to recognize one terminal multiplexer and adapt to it. */
|
|
53
|
+
export interface TerminalMultiplexerModule<Id extends string = string> {
|
|
54
|
+
readonly id: Id;
|
|
55
|
+
readonly precedence: TerminalMultiplexerPrecedence;
|
|
56
|
+
/** Every environment variable `isInside()` reads. */
|
|
57
|
+
readonly sessionEnvKeys: readonly string[];
|
|
58
|
+
/** Lowercase TERM prefix that identifies the multiplexer when its session markers were stripped. */
|
|
59
|
+
readonly termPrefix?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Whether the multiplexer owns the screen grid. When true, rendering takes the
|
|
62
|
+
* multiplexer path (no scrollback rebuild, anchored resize, skipped probes).
|
|
63
|
+
*/
|
|
64
|
+
readonly ownsScreenGrid: boolean;
|
|
65
|
+
isInside(env?: NodeJS.ProcessEnv): boolean;
|
|
66
|
+
/** Routes notifications the multiplexer would otherwise swallow. */
|
|
67
|
+
readonly notifier?: TerminalMultiplexerNotifier;
|
|
68
|
+
/** OSC 8 policy inside a session; unset defers to the outer terminal. */
|
|
69
|
+
readonly hyperlinks?: TerminalMultiplexerHyperlinks;
|
|
70
|
+
/**
|
|
71
|
+
* The pane's VTE honors DEC 2026 even when DECRQM is unanswered or reports
|
|
72
|
+
* the mode unrecognized (status 0): synchronized output starts on inside a
|
|
73
|
+
* session, and an unrecognized report does not turn it off.
|
|
74
|
+
*/
|
|
75
|
+
readonly honorsSynchronizedOutput?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The session does not reveal whether its client renders graphics while
|
|
78
|
+
* outer-terminal identity variables leak in, so images and Kitty
|
|
79
|
+
* placeholders stay off unless the user forces them.
|
|
80
|
+
*/
|
|
81
|
+
readonly imagesRequireOverride?: boolean;
|
|
82
|
+
/** Platforms where the multiplexer breaks OSC 11 passthrough, so host appearance is used instead. */
|
|
83
|
+
readonly backgroundQueryBrokenOn?: readonly NodeJS.Platform[];
|
|
84
|
+
/** Present when OSC 11 replies come from a cache an explicit refresh must update first. */
|
|
85
|
+
readonly backgroundColorCache?: TerminalMultiplexerBackgroundColorCache;
|
|
86
|
+
/** Expands REP into identical styled cells, so destructive replays REP-encode their padding. */
|
|
87
|
+
readonly expandsRepPadding?: boolean;
|
|
88
|
+
/** Expires a synchronized update after a deadline, so large rebuild replays renew DEC 2026 as they stream. */
|
|
89
|
+
readonly expiresSynchronizedOutput?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Restoring the alternate buffer schedules a redraw that ends a synchronized
|
|
92
|
+
* update early, so a synchronized resize rebuild stays on the main buffer.
|
|
93
|
+
*/
|
|
94
|
+
readonly altRestoreEndsSynchronizedOutput?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* May grow its grid before SIGWINCH reaches the app, so a rebuild-mode grow
|
|
97
|
+
* whose full viewport no longer reaches the bottom replays history.
|
|
98
|
+
*/
|
|
99
|
+
readonly growsBeforeSigwinch?: boolean;
|
|
100
|
+
}
|