@oh-my-pi/pi-tui 18.2.4 → 18.2.6
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 +23 -0
- package/README.md +43 -0
- package/dist/types/app-keybindings.d.ts +395 -0
- package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
- package/dist/types/apps/autoresearch-data.d.ts +15 -0
- package/dist/types/apps/cleanse-board.d.ts +66 -0
- package/dist/types/apps/cleanse-picker.d.ts +23 -0
- package/dist/types/apps/debug/log-formatting.d.ts +6 -0
- package/dist/types/apps/debug/log-viewer.d.ts +81 -0
- package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
- package/dist/types/apps/debug/raw-sse.d.ts +26 -0
- package/dist/types/apps/debug/terminal-info.d.ts +34 -0
- package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
- package/dist/types/apps/git/avatar.d.ts +9 -0
- package/dist/types/apps/git/colors.d.ts +49 -0
- package/dist/types/apps/git/diff-pane.d.ts +188 -0
- package/dist/types/apps/git/git-tui.d.ts +66 -0
- package/dist/types/apps/git/sidebar.d.ts +149 -0
- package/dist/types/apps/git/state.d.ts +117 -0
- package/dist/types/apps/if-bench-board.d.ts +75 -0
- package/dist/types/apps/live-visualizer.d.ts +33 -0
- package/dist/types/apps/ps-data.d.ts +51 -0
- package/dist/types/apps/ps-top.d.ts +33 -0
- package/dist/types/apps/session-picker.d.ts +26 -0
- package/dist/types/apps/setup-model-picker.d.ts +13 -0
- package/dist/types/apps/standalone-picker.d.ts +42 -0
- package/dist/types/autocomplete.d.ts +4 -0
- package/dist/types/chat/advisor-message.d.ts +11 -0
- package/dist/types/chat/assistant-message.d.ts +106 -0
- package/dist/types/chat/background-tan-message.d.ts +9 -0
- package/dist/types/chat/bash-execution.d.ts +47 -0
- package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
- package/dist/types/chat/collab-prompt-message.d.ts +10 -0
- package/dist/types/chat/compaction-summary-message.d.ts +54 -0
- package/dist/types/chat/custom-message.d.ts +10 -0
- package/dist/types/chat/display-preferences.d.ts +13 -0
- package/dist/types/chat/eval-execution.d.ts +29 -0
- package/dist/types/chat/execution-shared.d.ts +51 -0
- package/dist/types/chat/extension-types.d.ts +28 -0
- package/dist/types/chat/hook-message.d.ts +10 -0
- package/dist/types/chat/image-loading.d.ts +46 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
- package/dist/types/chat/messages.d.ts +189 -0
- package/dist/types/chat/reaction.d.ts +30 -0
- package/dist/types/chat/read-target.d.ts +4 -0
- package/dist/types/chat/read-tool-group.d.ts +67 -0
- package/dist/types/chat/served-model-marker.d.ts +47 -0
- package/dist/types/chat/skill-message.d.ts +33 -0
- package/dist/types/chat/skill-title-input.d.ts +14 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/chat/thinking-display.d.ts +12 -0
- package/dist/types/chat/todo-reminder.d.ts +13 -0
- package/dist/types/chat/tool-execution.d.ts +138 -0
- package/dist/types/chat/transcript-browser.d.ts +93 -0
- package/dist/types/chat/transcript-entry.d.ts +45 -0
- package/dist/types/chat/transcript-outline.d.ts +86 -0
- package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
- package/dist/types/chat/ttsr-notification.d.ts +23 -0
- package/dist/types/chat/user-message.d.ts +52 -0
- package/dist/types/chrome/chat-block.d.ts +64 -0
- package/dist/types/chrome/collab-qrcode.d.ts +28 -0
- package/dist/types/chrome/context-thresholds.d.ts +10 -0
- package/dist/types/chrome/countdown-timer.d.ts +14 -0
- package/dist/types/chrome/diff.d.ts +14 -0
- package/dist/types/chrome/dynamic-border.d.ts +16 -0
- package/dist/types/chrome/error-block.d.ts +17 -0
- package/dist/types/chrome/form-theme.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +12 -0
- package/dist/types/chrome/index.d.ts +20 -0
- package/dist/types/chrome/keybinding-hints.d.ts +40 -0
- package/dist/types/chrome/live-board.d.ts +23 -0
- package/dist/types/chrome/local-date.d.ts +4 -0
- package/dist/types/chrome/message-divider.d.ts +22 -0
- package/dist/types/chrome/message-frame.d.ts +52 -0
- package/dist/types/chrome/message-notice.d.ts +35 -0
- package/dist/types/chrome/overlay-box.d.ts +74 -0
- package/dist/types/chrome/qrcode.d.ts +48 -0
- package/dist/types/chrome/segment-track.d.ts +27 -0
- package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
- package/dist/types/chrome/selector-helpers.d.ts +52 -0
- package/dist/types/chrome/shared.d.ts +5 -0
- package/dist/types/chrome/streaming-panel.d.ts +19 -0
- package/dist/types/chrome/tool-activity.d.ts +17 -0
- package/dist/types/chrome/transcript-container.d.ts +129 -0
- package/dist/types/chrome/transcript-status.d.ts +12 -0
- package/dist/types/chrome/visual-truncate.d.ts +19 -0
- package/dist/types/components/disclosure.d.ts +42 -0
- package/dist/types/components/form.d.ts +130 -0
- package/dist/types/components/key-value-list.d.ts +24 -0
- package/dist/types/components/layout/geometry.d.ts +73 -0
- package/dist/types/components/layout/row.d.ts +55 -0
- package/dist/types/components/layout/split-pane.d.ts +80 -0
- package/dist/types/components/layout/stack.d.ts +50 -0
- package/dist/types/components/menu-selection.d.ts +71 -0
- package/dist/types/components/metric.d.ts +44 -0
- package/dist/types/components/progress-bar.d.ts +36 -0
- package/dist/types/components/scroll-view.d.ts +53 -19
- package/dist/types/components/scroll-viewport.d.ts +46 -0
- package/dist/types/components/section.d.ts +19 -0
- package/dist/types/components/select-list.d.ts +46 -2
- package/dist/types/components/settings-list.d.ts +20 -0
- package/dist/types/components/table.d.ts +32 -0
- package/dist/types/components/tree-view.d.ts +130 -0
- package/dist/types/components/wizard-step.d.ts +60 -0
- package/dist/types/hotkeys-markdown.d.ts +7 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/keybinding-matchers.d.ts +35 -0
- package/dist/types/keys.d.ts +2 -2
- package/dist/types/lang-from-path.d.ts +9 -0
- package/dist/types/overlays/advisor-config.d.ts +114 -0
- package/dist/types/overlays/agent-activity.d.ts +41 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
- package/dist/types/overlays/agent-hub-types.d.ts +99 -0
- package/dist/types/overlays/agent-hub.d.ts +126 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
- package/dist/types/overlays/agents-hub.d.ts +72 -0
- package/dist/types/overlays/ask-dialog.d.ts +88 -0
- package/dist/types/overlays/bordered-loader.d.ts +11 -0
- package/dist/types/overlays/btw-history-panel.d.ts +29 -0
- package/dist/types/overlays/btw-history.d.ts +17 -0
- package/dist/types/overlays/btw-panel.d.ts +26 -0
- package/dist/types/overlays/cleanse-panel.d.ts +36 -0
- package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
- package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
- package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
- package/dist/types/overlays/copy-selector.d.ts +48 -0
- package/dist/types/overlays/copy-targets.d.ts +63 -0
- package/dist/types/overlays/error-banner.d.ts +13 -0
- package/dist/types/overlays/extensions/display-text.d.ts +10 -0
- package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
- package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
- package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
- package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
- package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
- package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
- package/dist/types/overlays/extensions/types.d.ts +165 -0
- package/dist/types/overlays/history-search.d.ts +16 -0
- package/dist/types/overlays/hook-editor.d.ts +44 -0
- package/dist/types/overlays/hook-input.d.ts +20 -0
- package/dist/types/overlays/hook-selector.d.ts +71 -0
- package/dist/types/overlays/hub-frame.d.ts +77 -0
- package/dist/types/overlays/login-dialog.d.ts +43 -0
- package/dist/types/overlays/logout-account-selector.d.ts +15 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
- package/dist/types/overlays/model-browser.d.ts +213 -0
- package/dist/types/overlays/model-hub.d.ts +72 -0
- package/dist/types/overlays/model-picker.d.ts +74 -0
- package/dist/types/overlays/model-selector.d.ts +52 -0
- package/dist/types/overlays/move-overlay.d.ts +39 -0
- package/dist/types/overlays/oauth-selector.d.ts +41 -0
- package/dist/types/overlays/omfg-panel.d.ts +20 -0
- package/dist/types/overlays/pause-screen.d.ts +43 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
- package/dist/types/overlays/plan-toc.d.ts +41 -0
- package/dist/types/overlays/plugin-selector.d.ts +28 -0
- package/dist/types/overlays/plugin-settings.d.ts +180 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
- package/dist/types/overlays/rewind-selector.d.ts +61 -0
- package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
- package/dist/types/overlays/session-account-selector.d.ts +24 -0
- package/dist/types/overlays/session-info-overlay.d.ts +17 -0
- package/dist/types/overlays/session-observer-registry.d.ts +77 -0
- package/dist/types/overlays/session-selector.d.ts +131 -0
- package/dist/types/overlays/settings-defs.d.ts +119 -0
- package/dist/types/overlays/settings-selector.d.ts +73 -0
- package/dist/types/overlays/show-images-selector.d.ts +11 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
- package/dist/types/overlays/theme-selector.d.ts +12 -0
- package/dist/types/overlays/thinking-selector.d.ts +12 -0
- package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
- package/dist/types/overlays/tree-selector.d.ts +92 -0
- package/dist/types/overlays/usage-dashboard.d.ts +94 -0
- package/dist/types/overlays/usage-display.d.ts +5 -0
- package/dist/types/overlays/usage-row.d.ts +17 -0
- package/dist/types/prompt/attachment-chips.d.ts +19 -0
- package/dist/types/prompt/composer-attachments.d.ts +71 -0
- package/dist/types/prompt/composer-cache.d.ts +37 -0
- package/dist/types/prompt/composer.d.ts +159 -0
- package/dist/types/prompt/custom-editor.d.ts +261 -0
- package/dist/types/prompt/editor-top-gap.d.ts +18 -0
- package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
- package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
- package/dist/types/prompt/gradient-highlight.d.ts +32 -0
- package/dist/types/prompt/image-format.d.ts +4 -0
- package/dist/types/prompt/image-references.d.ts +26 -0
- package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
- package/dist/types/prompt/macos-spelling.d.ts +44 -0
- package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/prompt/magic-keywords.d.ts +26 -0
- package/dist/types/prompt/markdown-prose.d.ts +15 -0
- package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
- package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
- package/dist/types/prompt/orchestrate.d.ts +13 -0
- package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
- package/dist/types/prompt/queue-input.d.ts +8 -0
- package/dist/types/prompt/skill-tokens.d.ts +13 -0
- package/dist/types/prompt/tools-markdown.d.ts +12 -0
- package/dist/types/prompt/ultrathink.d.ts +13 -0
- package/dist/types/prompt/usage-amounts.d.ts +26 -0
- package/dist/types/prompt/video.d.ts +18 -0
- package/dist/types/prompt/welcome.d.ts +83 -0
- package/dist/types/prompt/workflow.d.ts +13 -0
- package/dist/types/render/code-cell.d.ts +51 -0
- package/dist/types/render/file-list.d.ts +22 -0
- package/dist/types/render/hyperlink.d.ts +80 -0
- package/dist/types/render/index.d.ts +16 -0
- package/dist/types/render/output-block.d.ts +54 -0
- package/dist/types/render/output-pane.d.ts +80 -0
- package/dist/types/render/render-utils.d.ts +312 -0
- package/dist/types/render/sixel.d.ts +21 -0
- package/dist/types/render/status-line.d.ts +23 -0
- package/dist/types/render/tool-card.d.ts +71 -0
- package/dist/types/render/tree-list.d.ts +29 -0
- package/dist/types/render/types.d.ts +17 -0
- package/dist/types/render/utils.d.ts +43 -0
- package/dist/types/render/width-aware-text.d.ts +23 -0
- package/dist/types/setup/lazy.d.ts +3 -0
- package/dist/types/setup/scenes/composer.d.ts +3 -0
- package/dist/types/setup/scenes/glyph.d.ts +3 -0
- package/dist/types/setup/scenes/model.d.ts +3 -0
- package/dist/types/setup/scenes/outro.d.ts +2 -0
- package/dist/types/setup/scenes/providers.d.ts +3 -0
- package/dist/types/setup/scenes/sign-in.d.ts +21 -0
- package/dist/types/setup/scenes/splash.d.ts +11 -0
- package/dist/types/setup/scenes/theme.d.ts +3 -0
- package/dist/types/setup/scenes/types.d.ts +110 -0
- package/dist/types/setup/scenes/web-search.d.ts +22 -0
- package/dist/types/setup/setup-version.d.ts +11 -0
- package/dist/types/setup/startup-splash.d.ts +9 -0
- package/dist/types/setup/wizard-overlay.d.ts +16 -0
- package/dist/types/setup/wizard.d.ts +25 -0
- package/dist/types/status-line/component.d.ts +182 -0
- package/dist/types/status-line/context-usage.d.ts +156 -0
- package/dist/types/status-line/footer.d.ts +30 -0
- package/dist/types/status-line/git-utils.d.ts +22 -0
- package/dist/types/status-line/host.d.ts +129 -0
- package/dist/types/status-line/index.d.ts +6 -0
- package/dist/types/status-line/loop.d.ts +18 -0
- package/dist/types/status-line/metrics.d.ts +21 -0
- package/dist/types/status-line/presets.d.ts +3 -0
- package/dist/types/status-line/schema.d.ts +15 -0
- package/dist/types/status-line/segments.d.ts +5 -0
- package/dist/types/status-line/separators.d.ts +3 -0
- package/dist/types/status-line/types.d.ts +236 -0
- package/dist/types/stdin-buffer.d.ts +4 -0
- package/dist/types/theme/color.d.ts +24 -0
- package/dist/types/theme/defaults/index.d.ts +9489 -0
- package/dist/types/theme/index.d.ts +4 -0
- package/dist/types/theme/loader.d.ts +23 -0
- package/dist/types/theme/mermaid-cache.d.ts +26 -0
- package/dist/types/theme/schema-validation.d.ts +3 -0
- package/dist/types/theme/schema.d.ts +25 -0
- package/dist/types/theme/session-color.d.ts +43 -0
- package/dist/types/theme/shimmer.d.ts +44 -0
- package/dist/types/theme/symbols.d.ts +34 -0
- package/dist/types/theme/theme-class.d.ts +299 -0
- package/dist/types/theme/theme.d.ts +111 -0
- package/dist/types/theme/tui-adapters.d.ts +30 -0
- package/dist/types/thinking.d.ts +165 -0
- package/dist/types/tools/agent-tree.d.ts +36 -0
- package/dist/types/tools/ask.d.ts +67 -0
- package/dist/types/tools/ast-edit.d.ts +53 -0
- package/dist/types/tools/ast-grep.d.ts +52 -0
- package/dist/types/tools/autoresearch.d.ts +156 -0
- package/dist/types/tools/bash-interactive.d.ts +28 -0
- package/dist/types/tools/bash.d.ts +103 -0
- package/dist/types/tools/conflict-detect.d.ts +43 -0
- package/dist/types/tools/debug.d.ts +60 -0
- package/dist/types/tools/default-renderer.d.ts +24 -0
- package/dist/types/tools/edit.d.ts +158 -0
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
- package/dist/types/tools/eval-format/index.d.ts +5 -0
- package/dist/types/tools/eval-format/javascript.d.ts +2 -0
- package/dist/types/tools/eval-format/python.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +94 -0
- package/dist/types/tools/fetch.d.ts +42 -0
- package/dist/types/tools/gh-format.d.ts +8 -0
- package/dist/types/tools/github.d.ts +144 -0
- package/dist/types/tools/glob.d.ts +44 -0
- package/dist/types/tools/goal.d.ts +42 -0
- package/dist/types/tools/grep.d.ts +64 -0
- package/dist/types/tools/grouped-file-output.d.ts +71 -0
- package/dist/types/tools/hashline-format.d.ts +28 -0
- package/dist/types/tools/hub.d.ts +340 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/json-tree.d.ts +59 -0
- package/dist/types/tools/line-ranges.d.ts +29 -0
- package/dist/types/tools/list-limit.d.ts +15 -0
- package/dist/types/tools/lsp.d.ts +72 -0
- package/dist/types/tools/match-line-format.d.ts +11 -0
- package/dist/types/tools/mcp.d.ts +81 -0
- package/dist/types/tools/memory.d.ts +67 -0
- package/dist/types/tools/output-meta.d.ts +151 -0
- package/dist/types/tools/read.d.ts +139 -0
- package/dist/types/tools/renderer.d.ts +98 -0
- package/dist/types/tools/report-tool-issue.d.ts +8 -0
- package/dist/types/tools/resolve.d.ts +47 -0
- package/dist/types/tools/streaming-output.d.ts +282 -0
- package/dist/types/tools/subprocess.d.ts +24 -0
- package/dist/types/tools/task-repair-args.d.ts +53 -0
- package/dist/types/tools/task-yield-assembly.d.ts +20 -0
- package/dist/types/tools/task.d.ts +425 -0
- package/dist/types/tools/terminal-output.d.ts +8 -0
- package/dist/types/tools/think.d.ts +13 -0
- package/dist/types/tools/todo.d.ts +118 -0
- package/dist/types/tools/tool-errors.d.ts +7 -0
- package/dist/types/tools/vibe.d.ts +120 -0
- package/dist/types/tools/web-search.d.ts +195 -0
- package/dist/types/tools/write.d.ts +76 -0
- package/dist/types/tools/xd-url.d.ts +13 -0
- package/dist/types/tools/xdev.d.ts +52 -0
- package/dist/types/tui.d.ts +18 -0
- package/dist/types/utils.d.ts +2 -0
- package/package.json +37 -3
- package/src/app-keybindings.ts +760 -0
- package/src/apps/autoresearch-dashboard.ts +500 -0
- package/src/apps/autoresearch-data.ts +64 -0
- package/src/apps/cleanse-board.ts +341 -0
- package/src/apps/cleanse-picker.ts +57 -0
- package/src/apps/debug/log-formatting.ts +53 -0
- package/src/apps/debug/log-viewer.ts +868 -0
- package/src/apps/debug/protocol-probe.ts +267 -0
- package/src/apps/debug/raw-sse-buffer.ts +449 -0
- package/src/apps/debug/raw-sse.ts +282 -0
- package/src/apps/debug/terminal-info.ts +115 -0
- package/src/apps/debug/viewer-frame.ts +174 -0
- package/src/apps/git/avatar.ts +52 -0
- package/src/apps/git/colors.ts +109 -0
- package/src/apps/git/diff-pane.ts +1512 -0
- package/src/apps/git/git-tui.ts +889 -0
- package/src/apps/git/sidebar.ts +1204 -0
- package/src/apps/git/state.ts +113 -0
- package/src/apps/if-bench-board.ts +324 -0
- package/src/apps/live-visualizer.ts +238 -0
- package/src/apps/ps-data.ts +116 -0
- package/src/apps/ps-top.ts +422 -0
- package/src/apps/session-picker.ts +95 -0
- package/src/apps/setup-model-picker.ts +21 -0
- package/src/apps/standalone-picker.ts +111 -0
- package/src/autocomplete.ts +9 -13
- package/src/chat/advisor-message.ts +175 -0
- package/src/chat/assistant-message.ts +1214 -0
- package/src/chat/background-tan-message.ts +35 -0
- package/src/chat/bash-execution.ts +394 -0
- package/src/chat/cache-invalidation-marker.ts +94 -0
- package/src/chat/chat-transcript-builder.ts +593 -0
- package/src/chat/collab-prompt-message.ts +34 -0
- package/src/chat/compaction-summary-message.ts +261 -0
- package/src/chat/custom-message.ts +23 -0
- package/src/chat/display-preferences.ts +24 -0
- package/src/chat/eval-execution.ts +172 -0
- package/src/chat/execution-shared.ts +113 -0
- package/src/chat/extension-types.ts +46 -0
- package/src/chat/hook-message.ts +20 -0
- package/src/chat/image-loading.ts +122 -0
- package/src/chat/late-diagnostics-message.ts +92 -0
- package/src/chat/messages.ts +305 -0
- package/src/chat/reaction.ts +65 -0
- package/src/chat/read-target.ts +7 -0
- package/src/chat/read-tool-group.ts +873 -0
- package/src/chat/served-model-marker.ts +91 -0
- package/src/chat/skill-message.ts +220 -0
- package/src/chat/skill-title-input.ts +41 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
- package/src/chat/thinking-display.ts +312 -0
- package/src/chat/todo-reminder.ts +33 -0
- package/src/chat/tool-execution.ts +1395 -0
- package/src/chat/transcript-browser.ts +268 -0
- package/src/chat/transcript-entry.ts +96 -0
- package/src/chat/transcript-outline.ts +260 -0
- package/src/chat/transcript-render-helpers.ts +315 -0
- package/src/chat/ttsr-notification.ts +123 -0
- package/src/chat/user-message.ts +287 -0
- package/src/chrome/chat-block.ts +110 -0
- package/src/chrome/collab-qrcode.ts +74 -0
- package/src/chrome/context-thresholds.ts +85 -0
- package/src/chrome/countdown-timer.ts +74 -0
- package/src/chrome/diff.ts +266 -0
- package/src/chrome/dynamic-border.ts +36 -0
- package/src/chrome/error-block.ts +63 -0
- package/src/chrome/form-theme.ts +10 -0
- package/src/chrome/format.ts +66 -0
- package/src/chrome/index.ts +21 -0
- package/src/chrome/keybinding-hints.ts +55 -0
- package/src/chrome/live-board.ts +123 -0
- package/src/chrome/local-date.ts +20 -0
- package/src/chrome/message-divider.ts +51 -0
- package/src/chrome/message-frame.ts +164 -0
- package/src/chrome/message-notice.ts +103 -0
- package/src/chrome/overlay-box.ts +301 -0
- package/src/chrome/qrcode.ts +539 -0
- package/src/chrome/segment-track.ts +86 -0
- package/src/chrome/select-list-mouse-routing.ts +11 -0
- package/src/chrome/selector-helpers.ts +119 -0
- package/src/chrome/shared.ts +27 -0
- package/src/chrome/streaming-panel.ts +72 -0
- package/src/chrome/tool-activity.ts +44 -0
- package/src/chrome/transcript-container.ts +902 -0
- package/src/chrome/transcript-status.ts +27 -0
- package/src/chrome/visual-truncate.ts +70 -0
- package/src/components/disclosure.ts +235 -0
- package/src/components/editor.ts +10 -12
- package/src/components/form.ts +566 -0
- package/src/components/input.ts +6 -27
- package/src/components/key-value-list.ts +88 -0
- package/src/components/layout/geometry.ts +202 -0
- package/src/components/layout/row.ts +283 -0
- package/src/components/layout/split-pane.ts +349 -0
- package/src/components/layout/stack.ts +261 -0
- package/src/components/markdown.ts +16 -12
- package/src/components/menu-selection.ts +248 -0
- package/src/components/metric.ts +132 -0
- package/src/components/progress-bar.ts +140 -0
- package/src/components/scroll-view.ts +372 -70
- package/src/components/scroll-viewport.ts +154 -0
- package/src/components/section.ts +77 -0
- package/src/components/select-list.ts +238 -159
- package/src/components/settings-list.ts +103 -80
- package/src/components/table.ts +127 -0
- package/src/components/tree-view.ts +481 -0
- package/src/components/wizard-step.ts +229 -0
- package/src/deccara.ts +1 -3
- package/src/hotkeys-markdown.ts +100 -0
- package/src/index.ts +18 -0
- package/src/keybinding-matchers.ts +99 -0
- package/src/keys.ts +2 -2
- package/src/lang-from-path.ts +252 -0
- package/src/overlays/advisor-config.ts +761 -0
- package/src/overlays/agent-activity.ts +113 -0
- package/src/overlays/agent-hub-projection.ts +250 -0
- package/src/overlays/agent-hub-renderer.ts +281 -0
- package/src/overlays/agent-hub-types.ts +74 -0
- package/src/overlays/agent-hub.ts +1562 -0
- package/src/overlays/agent-transcript-viewer.ts +669 -0
- package/src/overlays/agents-hub.ts +1203 -0
- package/src/overlays/ask-dialog.ts +1202 -0
- package/src/overlays/bordered-loader.ts +41 -0
- package/src/overlays/btw-history-panel.ts +591 -0
- package/src/overlays/btw-history.ts +33 -0
- package/src/overlays/btw-panel.ts +167 -0
- package/src/overlays/cleanse-panel.ts +167 -0
- package/src/overlays/codex-reset-fireworks.ts +375 -0
- package/src/overlays/composer-shape-preview.ts +137 -0
- package/src/overlays/composer-shape-registry.ts +82 -0
- package/src/overlays/copy-selector.ts +618 -0
- package/src/overlays/copy-targets.ts +210 -0
- package/src/overlays/error-banner.ts +39 -0
- package/src/overlays/extensions/display-text.ts +39 -0
- package/src/overlays/extensions/extension-dashboard.ts +645 -0
- package/src/overlays/extensions/extension-list.ts +667 -0
- package/src/overlays/extensions/inspector-model.ts +484 -0
- package/src/overlays/extensions/inspector-panel.ts +669 -0
- package/src/overlays/extensions/live-tool-session.ts +67 -0
- package/src/overlays/extensions/mcp-runtime.ts +289 -0
- package/src/overlays/extensions/state-manager.ts +337 -0
- package/src/overlays/extensions/types.ts +208 -0
- package/src/overlays/history-search.ts +268 -0
- package/src/overlays/hook-editor.ts +272 -0
- package/src/overlays/hook-input.ts +84 -0
- package/src/overlays/hook-selector.ts +635 -0
- package/src/overlays/hub-frame.ts +262 -0
- package/src/overlays/login-dialog.ts +231 -0
- package/src/overlays/logout-account-selector.ts +115 -0
- package/src/overlays/mcp-add-wizard.ts +1436 -0
- package/src/overlays/model-browser.ts +1176 -0
- package/src/overlays/model-hub.ts +2279 -0
- package/src/overlays/model-picker.ts +285 -0
- package/src/overlays/model-selector.ts +107 -0
- package/src/overlays/move-overlay.ts +197 -0
- package/src/overlays/oauth-selector.ts +446 -0
- package/src/overlays/omfg-panel.ts +136 -0
- package/src/overlays/pause-screen.ts +198 -0
- package/src/overlays/plan-review-overlay.ts +1227 -0
- package/src/overlays/plan-save-overlay.ts +74 -0
- package/src/overlays/plan-toc.ts +139 -0
- package/src/overlays/plugin-selector.ts +97 -0
- package/src/overlays/plugin-settings.ts +839 -0
- package/src/overlays/queue-mode-selector.ts +55 -0
- package/src/overlays/reset-usage-selector.ts +170 -0
- package/src/overlays/rewind-selector.ts +499 -0
- package/src/overlays/running-subagent-badge.ts +19 -0
- package/src/overlays/session-account-selector.ts +68 -0
- package/src/overlays/session-info-overlay.ts +96 -0
- package/src/overlays/session-observer-registry.ts +289 -0
- package/src/overlays/session-selector.ts +1137 -0
- package/src/overlays/settings-defs.ts +315 -0
- package/src/overlays/settings-selector.ts +1415 -0
- package/src/overlays/show-images-selector.ts +44 -0
- package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
- package/src/overlays/snapcompact-shape-preview.ts +192 -0
- package/src/overlays/theme-selector.ts +62 -0
- package/src/overlays/thinking-selector.ts +51 -0
- package/src/overlays/tiny-title-download-progress.ts +102 -0
- package/src/overlays/tree-selector.ts +1121 -0
- package/src/overlays/usage-dashboard.ts +629 -0
- package/src/overlays/usage-display.ts +45 -0
- package/src/overlays/usage-row.ts +118 -0
- package/src/prompt/attachment-chips.ts +201 -0
- package/src/prompt/composer-attachments.ts +280 -0
- package/src/prompt/composer-cache.ts +304 -0
- package/src/prompt/composer.ts +934 -0
- package/src/prompt/custom-editor.ts +1392 -0
- package/src/prompt/data/emojis.json +1 -0
- package/src/prompt/editor-top-gap.ts +28 -0
- package/src/prompt/emoji-autocomplete.ts +285 -0
- package/src/prompt/github-ref-autocomplete.ts +75 -0
- package/src/prompt/gradient-highlight.ts +101 -0
- package/src/prompt/image-format.ts +28 -0
- package/src/prompt/image-references.ts +102 -0
- package/src/prompt/interactive-context-helpers.ts +126 -0
- package/src/prompt/internal-url-autocomplete.ts +155 -0
- package/src/prompt/macos-spelling.ts +456 -0
- package/src/prompt/magic-keyword-boundary.ts +23 -0
- package/src/prompt/magic-keywords.ts +42 -0
- package/src/prompt/markdown-prose.ts +245 -0
- package/src/prompt/model-mention-autocomplete.ts +94 -0
- package/src/prompt/model-mention-syntax.ts +41 -0
- package/src/prompt/orchestrate.ts +26 -0
- package/src/prompt/prompt-action-autocomplete.ts +337 -0
- package/src/prompt/queue-input.ts +132 -0
- package/src/prompt/skill-tokens.ts +36 -0
- package/src/prompt/tips.txt +27 -0
- package/src/prompt/tools-markdown.ts +29 -0
- package/src/prompt/ultrathink.ts +26 -0
- package/src/prompt/usage-amounts.ts +99 -0
- package/src/prompt/video.ts +47 -0
- package/src/prompt/welcome.ts +605 -0
- package/src/prompt/workflow.ts +26 -0
- package/src/render/code-cell.ts +244 -0
- package/src/render/file-list.ts +58 -0
- package/src/render/hyperlink.ts +192 -0
- package/src/render/index.ts +17 -0
- package/src/render/output-block.ts +267 -0
- package/src/render/output-pane.ts +299 -0
- package/src/render/render-utils.ts +1182 -0
- package/src/render/sixel.ts +69 -0
- package/src/render/status-line.ts +55 -0
- package/src/render/tool-card.ts +272 -0
- package/src/render/tree-list.ts +188 -0
- package/src/render/types.ts +19 -0
- package/src/render/utils.ts +109 -0
- package/src/render/width-aware-text.ts +60 -0
- package/src/setup/lazy.ts +17 -0
- package/src/setup/scenes/composer.ts +127 -0
- package/src/setup/scenes/glyph.ts +120 -0
- package/src/setup/scenes/model.ts +138 -0
- package/src/setup/scenes/outro.ts +24 -0
- package/src/setup/scenes/providers.ts +107 -0
- package/src/setup/scenes/sign-in.ts +373 -0
- package/src/setup/scenes/splash.ts +192 -0
- package/src/setup/scenes/theme.ts +343 -0
- package/src/setup/scenes/types.ts +111 -0
- package/src/setup/scenes/web-search.ts +165 -0
- package/src/setup/setup-version.ts +11 -0
- package/src/setup/startup-splash.ts +107 -0
- package/src/setup/wizard-overlay.ts +319 -0
- package/src/setup/wizard.ts +101 -0
- package/src/status-line/component.ts +3003 -0
- package/src/status-line/context-usage.ts +688 -0
- package/src/status-line/footer.ts +323 -0
- package/src/status-line/git-utils.ts +42 -0
- package/src/status-line/host.ts +97 -0
- package/src/status-line/index.ts +6 -0
- package/src/status-line/loop.ts +28 -0
- package/src/status-line/metrics.ts +94 -0
- package/src/status-line/presets.ts +107 -0
- package/src/status-line/schema.ts +57 -0
- package/src/status-line/segments.ts +934 -0
- package/src/status-line/separators.ts +55 -0
- package/src/status-line/types.ts +227 -0
- package/src/stdin-buffer.ts +4 -2
- package/src/theme/color.ts +95 -0
- package/src/theme/dark.json +95 -0
- package/src/theme/defaults/alabaster.json +93 -0
- package/src/theme/defaults/amethyst.json +96 -0
- package/src/theme/defaults/anthracite.json +93 -0
- package/src/theme/defaults/basalt.json +91 -0
- package/src/theme/defaults/birch.json +95 -0
- package/src/theme/defaults/dark-abyss.json +91 -0
- package/src/theme/defaults/dark-arctic.json +104 -0
- package/src/theme/defaults/dark-aurora.json +95 -0
- package/src/theme/defaults/dark-catppuccin.json +107 -0
- package/src/theme/defaults/dark-cavern.json +91 -0
- package/src/theme/defaults/dark-celestial.json +106 -0
- package/src/theme/defaults/dark-copper.json +95 -0
- package/src/theme/defaults/dark-cosmos.json +90 -0
- package/src/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/theme/defaults/dark-dracula.json +98 -0
- package/src/theme/defaults/dark-eclipse.json +91 -0
- package/src/theme/defaults/dark-ember.json +95 -0
- package/src/theme/defaults/dark-equinox.json +90 -0
- package/src/theme/defaults/dark-forest.json +96 -0
- package/src/theme/defaults/dark-github.json +105 -0
- package/src/theme/defaults/dark-gruvbox.json +112 -0
- package/src/theme/defaults/dark-lavender.json +95 -0
- package/src/theme/defaults/dark-lunar.json +89 -0
- package/src/theme/defaults/dark-midnight.json +95 -0
- package/src/theme/defaults/dark-monochrome.json +94 -0
- package/src/theme/defaults/dark-monokai.json +98 -0
- package/src/theme/defaults/dark-nebula.json +90 -0
- package/src/theme/defaults/dark-nord.json +98 -0
- package/src/theme/defaults/dark-ocean.json +101 -0
- package/src/theme/defaults/dark-one.json +100 -0
- package/src/theme/defaults/dark-poimandres.json +115 -0
- package/src/theme/defaults/dark-rainforest.json +91 -0
- package/src/theme/defaults/dark-reef.json +91 -0
- package/src/theme/defaults/dark-retro.json +92 -0
- package/src/theme/defaults/dark-rose-pine.json +96 -0
- package/src/theme/defaults/dark-sakura.json +95 -0
- package/src/theme/defaults/dark-slate.json +95 -0
- package/src/theme/defaults/dark-solarized.json +97 -0
- package/src/theme/defaults/dark-solstice.json +90 -0
- package/src/theme/defaults/dark-starfall.json +91 -0
- package/src/theme/defaults/dark-sunset.json +99 -0
- package/src/theme/defaults/dark-swamp.json +90 -0
- package/src/theme/defaults/dark-synthwave.json +103 -0
- package/src/theme/defaults/dark-taiga.json +91 -0
- package/src/theme/defaults/dark-terminal.json +95 -0
- package/src/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/theme/defaults/dark-tundra.json +91 -0
- package/src/theme/defaults/dark-twilight.json +91 -0
- package/src/theme/defaults/dark-volcanic.json +91 -0
- package/src/theme/defaults/graphite.json +92 -0
- package/src/theme/defaults/index.ts +201 -0
- package/src/theme/defaults/light-arctic.json +107 -0
- package/src/theme/defaults/light-aurora-day.json +91 -0
- package/src/theme/defaults/light-canyon.json +91 -0
- package/src/theme/defaults/light-catppuccin.json +106 -0
- package/src/theme/defaults/light-cirrus.json +90 -0
- package/src/theme/defaults/light-coral.json +95 -0
- package/src/theme/defaults/light-cyberpunk.json +96 -0
- package/src/theme/defaults/light-dawn.json +90 -0
- package/src/theme/defaults/light-dunes.json +91 -0
- package/src/theme/defaults/light-eucalyptus.json +95 -0
- package/src/theme/defaults/light-forest.json +100 -0
- package/src/theme/defaults/light-frost.json +95 -0
- package/src/theme/defaults/light-github.json +115 -0
- package/src/theme/defaults/light-glacier.json +91 -0
- package/src/theme/defaults/light-gruvbox.json +108 -0
- package/src/theme/defaults/light-haze.json +90 -0
- package/src/theme/defaults/light-honeycomb.json +95 -0
- package/src/theme/defaults/light-lagoon.json +91 -0
- package/src/theme/defaults/light-lavender.json +95 -0
- package/src/theme/defaults/light-meadow.json +91 -0
- package/src/theme/defaults/light-mint.json +95 -0
- package/src/theme/defaults/light-monochrome.json +101 -0
- package/src/theme/defaults/light-ocean.json +99 -0
- package/src/theme/defaults/light-one.json +99 -0
- package/src/theme/defaults/light-opal.json +91 -0
- package/src/theme/defaults/light-orchard.json +91 -0
- package/src/theme/defaults/light-paper.json +95 -0
- package/src/theme/defaults/light-poimandres.json +115 -0
- package/src/theme/defaults/light-prism.json +90 -0
- package/src/theme/defaults/light-retro.json +98 -0
- package/src/theme/defaults/light-sand.json +95 -0
- package/src/theme/defaults/light-savanna.json +91 -0
- package/src/theme/defaults/light-solarized.json +102 -0
- package/src/theme/defaults/light-soleil.json +90 -0
- package/src/theme/defaults/light-sunset.json +99 -0
- package/src/theme/defaults/light-synthwave.json +98 -0
- package/src/theme/defaults/light-tokyo-night.json +111 -0
- package/src/theme/defaults/light-wetland.json +91 -0
- package/src/theme/defaults/light-zenith.json +89 -0
- package/src/theme/defaults/limestone.json +94 -0
- package/src/theme/defaults/mahogany.json +97 -0
- package/src/theme/defaults/marble.json +93 -0
- package/src/theme/defaults/obsidian.json +91 -0
- package/src/theme/defaults/onyx.json +91 -0
- package/src/theme/defaults/pearl.json +93 -0
- package/src/theme/defaults/porcelain.json +91 -0
- package/src/theme/defaults/quartz.json +96 -0
- package/src/theme/defaults/sandstone.json +95 -0
- package/src/theme/defaults/titanium.json +90 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/light.json +93 -0
- package/src/theme/loader.ts +200 -0
- package/src/theme/mermaid-cache.ts +92 -0
- package/src/theme/schema-validation.ts +119 -0
- package/src/theme/schema.ts +168 -0
- package/src/theme/session-color.ts +253 -0
- package/src/theme/shimmer.ts +307 -0
- package/src/theme/symbols.ts +1433 -0
- package/src/theme/theme-class.ts +787 -0
- package/src/theme/theme-schema.json +463 -0
- package/src/theme/theme.ts +810 -0
- package/src/theme/tui-adapters.ts +339 -0
- package/src/thinking.ts +380 -0
- package/src/tools/agent-tree.ts +128 -0
- package/src/tools/ask.ts +482 -0
- package/src/tools/ast-edit.ts +210 -0
- package/src/tools/ast-grep.ts +171 -0
- package/src/tools/autoresearch.ts +287 -0
- package/src/tools/bash-interactive.ts +295 -0
- package/src/tools/bash.ts +468 -0
- package/src/tools/conflict-detect.ts +77 -0
- package/src/tools/debug.ts +167 -0
- package/src/tools/default-renderer.ts +172 -0
- package/src/tools/edit.ts +1258 -0
- package/src/tools/eval-format/code-mode-declarations.ts +61 -0
- package/src/tools/eval-format/index.ts +16 -0
- package/src/tools/eval-format/javascript.ts +952 -0
- package/src/tools/eval-format/python.ts +544 -0
- package/src/tools/eval.ts +835 -0
- package/src/tools/fetch.ts +226 -0
- package/src/tools/gh-format.ts +18 -0
- package/src/tools/github.ts +686 -0
- package/src/tools/glob.ts +213 -0
- package/src/tools/goal.ts +153 -0
- package/src/tools/grep.ts +385 -0
- package/src/tools/grouped-file-output.ts +211 -0
- package/src/tools/hashline-format.ts +59 -0
- package/src/tools/hub.ts +1488 -0
- package/src/tools/index.ts +71 -0
- package/src/tools/json-tree.ts +388 -0
- package/src/tools/line-ranges.ts +98 -0
- package/src/tools/list-limit.ts +43 -0
- package/src/tools/lsp.ts +702 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/mcp.ts +309 -0
- package/src/tools/memory.ts +220 -0
- package/src/tools/output-meta.ts +367 -0
- package/src/tools/read.ts +628 -0
- package/src/tools/renderer.ts +107 -0
- package/src/tools/report-tool-issue.ts +13 -0
- package/src/tools/resolve.ts +139 -0
- package/src/tools/streaming-output.ts +1576 -0
- package/src/tools/subprocess.ts +39 -0
- package/src/tools/task-repair-args.ts +118 -0
- package/src/tools/task-yield-assembly.ts +147 -0
- package/src/tools/task.ts +2110 -0
- package/src/tools/terminal-output.ts +153 -0
- package/src/tools/think.ts +28 -0
- package/src/tools/todo.ts +580 -0
- package/src/tools/tool-errors.ts +15 -0
- package/src/tools/vibe.ts +420 -0
- package/src/tools/web-search.ts +409 -0
- package/src/tools/write.ts +511 -0
- package/src/tools/xd-url.ts +28 -0
- package/src/tools/xdev.ts +201 -0
- package/src/tui.ts +57 -4
- package/src/utils.ts +8 -0
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
import { type Component, Container, type HistoryBatch } from "../tui";
|
|
2
|
+
import * as logger from "@oh-my-pi/pi-utils/logger";
|
|
3
|
+
import { isToolActivityComponent } from "./tool-activity";
|
|
4
|
+
|
|
5
|
+
/** Shared animation time supplied by the constrained transcript root. */
|
|
6
|
+
export interface AnimationFrame {
|
|
7
|
+
readonly tick: number;
|
|
8
|
+
readonly now: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Lets an active block adapt its presentation to its allocated viewport rows. */
|
|
12
|
+
export interface TranscriptPresentationTarget {
|
|
13
|
+
setTranscriptAllocation?(rows: number, frame: AnimationFrame): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Presentation declaration captured permanently when a block is added. */
|
|
17
|
+
export type TranscriptBlockMode = "mutable" | "appendOnly";
|
|
18
|
+
|
|
19
|
+
/** Immutable width-independent identity for one stable semantic row. */
|
|
20
|
+
export interface TranscriptStableRow {
|
|
21
|
+
readonly key: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Explicit semantic-row contract for a block whose stable head may enter native
|
|
26
|
+
* history before finalization. Every later array must extend the prior keys
|
|
27
|
+
* exactly; each row renderer is deterministic for its width.
|
|
28
|
+
* A publication that breaks these invariants (e.g. a mid-stream theme change
|
|
29
|
+
* re-coloring already-emitted bytes) freezes further stable-row emission for
|
|
30
|
+
* that block instead of failing the render — see {@link TranscriptContainer}.
|
|
31
|
+
*/
|
|
32
|
+
export interface AppendOnlyTranscriptBlock {
|
|
33
|
+
readonly transcriptBlockMode: "appendOnly";
|
|
34
|
+
getTranscriptStableRows(): readonly TranscriptStableRow[];
|
|
35
|
+
/**
|
|
36
|
+
* Render the first `count` semantic rows at the requested current width.
|
|
37
|
+
* Counts are monotonic identities, not physical row counts; this output must
|
|
38
|
+
* prefix the block's full render at the same width.
|
|
39
|
+
*/
|
|
40
|
+
renderTranscriptStableRows(count: number, width: number): readonly string[];
|
|
41
|
+
/**
|
|
42
|
+
* Discard every published stable row so the block re-renders its head from
|
|
43
|
+
* scratch. Called only alongside a destructive display reset (e.g. a
|
|
44
|
+
* thinking-visibility toggle) that clears the native scrollback those rows
|
|
45
|
+
* occupied — the sole context in which the append-only "published bytes never
|
|
46
|
+
* change" contract may be retracted. Optional: blocks whose stable-row
|
|
47
|
+
* presentation never changes may omit it.
|
|
48
|
+
*/
|
|
49
|
+
resetTranscriptStableRows?(): void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface FinalizableBlock {
|
|
53
|
+
isTranscriptBlockFinalized?(): boolean;
|
|
54
|
+
/** Render the row that must remain represented under emergency viewport pressure. */
|
|
55
|
+
renderTranscriptBlockEmergencyRow?(width: number): string | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Block lifecycle:
|
|
60
|
+
* - `active`: still mutating; renders live and counts against tool admission.
|
|
61
|
+
* - `settled`: finalized but retained in the mutable viewport until pressure.
|
|
62
|
+
* - `committed`: logically retired; replay never rewinds this state.
|
|
63
|
+
*/
|
|
64
|
+
type BlockState = "active" | "settled" | "committed";
|
|
65
|
+
|
|
66
|
+
interface TranscriptEntry {
|
|
67
|
+
component: Component;
|
|
68
|
+
state: BlockState;
|
|
69
|
+
mode: TranscriptBlockMode;
|
|
70
|
+
stableRows: readonly TranscriptStableRow[];
|
|
71
|
+
renderedStableByWidth: Map<number, readonly string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Rendered row counts per `(width, snapshot count)`: lets the projected
|
|
74
|
+
* length skip the re-render when the same prefix was already rendered.
|
|
75
|
+
* Keyed on both dimensions because one snapshot commonly renders to
|
|
76
|
+
* multiple physical rows (Markdown wrap).
|
|
77
|
+
*/
|
|
78
|
+
stableRowCountByWidth: Map<number, Map<number, number>>;
|
|
79
|
+
emitted: number;
|
|
80
|
+
/**
|
|
81
|
+
* Set when a published stable row drifted (retraction, byte change within a
|
|
82
|
+
* width epoch, or no longer a render prefix). Rows already in native
|
|
83
|
+
* scrollback cannot be retracted, so the entry keeps its last good stable
|
|
84
|
+
* state for emitted-row slicing but never emits another mid-stream row.
|
|
85
|
+
*/
|
|
86
|
+
stableFrozen: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type RetirementPolicy = "pressure" | "flush";
|
|
90
|
+
type Offered =
|
|
91
|
+
| { batch: HistoryBatch; kind: "append"; entry: number; emittedEnd: number }
|
|
92
|
+
| { batch: HistoryBatch; kind: "commit"; end: number }
|
|
93
|
+
| { batch: HistoryBatch; kind: "replay" };
|
|
94
|
+
|
|
95
|
+
const MAX_LIVE_BLOCKS = 256;
|
|
96
|
+
/** Grace before a pressure-blocked frontier is reported; a streaming block may legitimately hold it briefly. */
|
|
97
|
+
const PINNED_FRONTIER_WARN_MS = 30_000;
|
|
98
|
+
const EMPTY_ROWS: readonly string[] = [];
|
|
99
|
+
const EMPTY_STABLE_ROWS: readonly TranscriptStableRow[] = [];
|
|
100
|
+
|
|
101
|
+
function isFinalized(component: Component): boolean {
|
|
102
|
+
const block = component as Component & FinalizableBlock;
|
|
103
|
+
return block.isTranscriptBlockFinalized?.() ?? true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function blockMode(component: Component): TranscriptBlockMode {
|
|
107
|
+
return (component as Component & Partial<AppendOnlyTranscriptBlock>).transcriptBlockMode === "appendOnly"
|
|
108
|
+
? "appendOnly"
|
|
109
|
+
: "mutable";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isPlainBlank(line: string): boolean {
|
|
113
|
+
return !/\S/.test(line);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Whether `prefix` matches `rows` byte-for-byte from the top. */
|
|
117
|
+
export function isRowPrefix(prefix: readonly string[], rows: readonly string[]): boolean {
|
|
118
|
+
if (prefix.length > rows.length) return false;
|
|
119
|
+
for (let index = 0; index < prefix.length; index++) {
|
|
120
|
+
if (prefix[index] !== rows[index]) return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isStablePrefix(prefix: readonly TranscriptStableRow[], rows: readonly TranscriptStableRow[]): boolean {
|
|
126
|
+
if (prefix.length > rows.length) return false;
|
|
127
|
+
for (let index = 0; index < prefix.length; index++) {
|
|
128
|
+
if (prefix[index]!.key !== rows[index]!.key) return false;
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Strip leading/trailing all-blank rows; the viewport allocator measures blocks by this trimmed height. */
|
|
134
|
+
export function trimBlankEdges(rows: readonly string[]): readonly string[] {
|
|
135
|
+
let start = 0;
|
|
136
|
+
let end = rows.length;
|
|
137
|
+
while (start < end && isPlainBlank(rows[start]!)) start++;
|
|
138
|
+
while (end > start && isPlainBlank(rows[end - 1]!)) end--;
|
|
139
|
+
return start === 0 && end === rows.length ? rows : rows.slice(start, end);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** One live block's row span in the last `renderViewport` output (half-open `[start, end)`). */
|
|
143
|
+
export interface TranscriptViewportSpan {
|
|
144
|
+
component: Component;
|
|
145
|
+
start: number;
|
|
146
|
+
end: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Owns transcript order, live capacity, and ordered immutable retirement. */
|
|
150
|
+
export class TranscriptContainer extends Container {
|
|
151
|
+
#entries: TranscriptEntry[] = [];
|
|
152
|
+
#frontier = 0;
|
|
153
|
+
#nextBatchId = 1;
|
|
154
|
+
#offered: Offered | undefined;
|
|
155
|
+
#replayPending = false;
|
|
156
|
+
#replayRequested = false;
|
|
157
|
+
#toolActivityVisible = true;
|
|
158
|
+
#lastFrame: AnimationFrame = { tick: 0, now: 0 };
|
|
159
|
+
// Start rows from the last full render(), keyed by child component (transcript deep-links).
|
|
160
|
+
#childStartRows = new Map<Component, number>();
|
|
161
|
+
// Watchdog for the wedge where an unfinalized frontier block pins pressure
|
|
162
|
+
// retirement: everything behind it stays live and degrades to one-line
|
|
163
|
+
// allocations. Logs once per pinned episode after a grace period.
|
|
164
|
+
#pinnedFrontier: { index: number; since: number; logged: boolean } | undefined;
|
|
165
|
+
/** Block spans of the last `renderViewport` output, for click hit-testing. */
|
|
166
|
+
#lastViewportSpans: TranscriptViewportSpan[] = [];
|
|
167
|
+
override addChild(component: Component): void {
|
|
168
|
+
if (isToolActivityComponent(component)) component.setToolActivityVisible(this.#toolActivityVisible);
|
|
169
|
+
super.addChild(component);
|
|
170
|
+
this.#entries.push({
|
|
171
|
+
component,
|
|
172
|
+
state: "active",
|
|
173
|
+
mode: blockMode(component),
|
|
174
|
+
stableRows: EMPTY_STABLE_ROWS,
|
|
175
|
+
renderedStableByWidth: new Map(),
|
|
176
|
+
stableRowCountByWidth: new Map(),
|
|
177
|
+
emitted: 0,
|
|
178
|
+
stableFrozen: false,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
override removeChild(component: Component): void {
|
|
183
|
+
if (this.children.indexOf(component) < 0 || !this.canRemoveBlock(component)) return;
|
|
184
|
+
super.removeChild(component);
|
|
185
|
+
this.#entries = this.#entries.filter(candidate => candidate.component !== component);
|
|
186
|
+
this.#frontier = Math.min(this.#frontier, this.#entries.length);
|
|
187
|
+
this.#childStartRows.delete(component);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
override clear(): void {
|
|
191
|
+
super.clear();
|
|
192
|
+
this.#entries = [];
|
|
193
|
+
this.#frontier = 0;
|
|
194
|
+
this.#offered = undefined;
|
|
195
|
+
this.#childStartRows.clear();
|
|
196
|
+
this.#pinnedFrontier = undefined;
|
|
197
|
+
this.#replayPending = false;
|
|
198
|
+
this.#replayRequested = false;
|
|
199
|
+
this.#lastViewportSpans = [];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
setToolActivityVisible(visible: boolean): void {
|
|
203
|
+
if (this.#toolActivityVisible === visible) return;
|
|
204
|
+
this.#toolActivityVisible = visible;
|
|
205
|
+
for (const child of this.children) {
|
|
206
|
+
if (isToolActivityComponent(child)) child.setToolActivityVisible(visible);
|
|
207
|
+
}
|
|
208
|
+
this.invalidate();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Forget the append-only emission ledger — emitted counts, published stable
|
|
213
|
+
* rows, per-width render cache, and freeze state — for every block, and ask
|
|
214
|
+
* each append-only block to drop its own published rows. The next replay then
|
|
215
|
+
* re-renders each block from its current {@link Component.render}, applying a
|
|
216
|
+
* changed presentation (e.g. a thinking-visibility toggle) to rows that were
|
|
217
|
+
* already emitted as stable heads while streaming (#10177).
|
|
218
|
+
*
|
|
219
|
+
* Callers MUST pair this with a scrollback-clearing {@link resetDisplay}: the
|
|
220
|
+
* emitted rows it forgets still sit in native history until that clear
|
|
221
|
+
* rewrites them, so unpaired use would duplicate them on the next retirement.
|
|
222
|
+
*/
|
|
223
|
+
resetStableEmission(): void {
|
|
224
|
+
this.#syncEntries();
|
|
225
|
+
if (this.#offered?.kind === "append") this.#offered = undefined;
|
|
226
|
+
for (const entry of this.#entries) {
|
|
227
|
+
entry.emitted = 0;
|
|
228
|
+
entry.stableRows = EMPTY_STABLE_ROWS;
|
|
229
|
+
entry.renderedStableByWidth = new Map();
|
|
230
|
+
entry.stableRowCountByWidth = new Map();
|
|
231
|
+
entry.stableFrozen = false;
|
|
232
|
+
if (entry.mode === "appendOnly") {
|
|
233
|
+
(entry.component as Component & AppendOnlyTranscriptBlock).resetTranscriptStableRows?.();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Whether a transient block may be discarded without leaving tape history. */
|
|
239
|
+
canRemoveBlock(component: Component): boolean {
|
|
240
|
+
this.#syncEntries();
|
|
241
|
+
const index = this.#entries.findIndex(entry => entry.component === component);
|
|
242
|
+
if (index < 0) return false;
|
|
243
|
+
const entry = this.#entries[index]!;
|
|
244
|
+
if (entry.state === "committed" || entry.emitted > 0) return false;
|
|
245
|
+
if (this.#offered?.kind === "commit" && index < this.#offered.end) return false;
|
|
246
|
+
if (this.#offered?.kind === "append" && index === this.#offered.entry) return false;
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Lifecycle state per block in transcript order (diagnostics and tests). */
|
|
251
|
+
blockStates(): readonly BlockState[] {
|
|
252
|
+
this.#syncEntries();
|
|
253
|
+
return this.#entries.map(entry => entry.state);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Permanently captured presentation mode per block (diagnostics and tests). */
|
|
257
|
+
blockModes(): readonly TranscriptBlockMode[] {
|
|
258
|
+
this.#syncEntries();
|
|
259
|
+
return this.#entries.map(entry => entry.mode);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Emitted stable semantic-row counts in transcript order. */
|
|
263
|
+
emittedStableRows(): readonly number[] {
|
|
264
|
+
this.#syncEntries();
|
|
265
|
+
return this.#entries.map(entry => entry.emitted);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Whether visible active capacity and live-block memory permit another admission. */
|
|
269
|
+
canAdmit(rows: number): boolean {
|
|
270
|
+
const active = this.#entries.filter(entry => entry.state === "active").length;
|
|
271
|
+
return Math.max(0, Math.trunc(rows)) > active && this.#liveCount() < MAX_LIVE_BLOCKS;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Prepares one atomic replay of the committed ledger and an emitted active-head prefix. */
|
|
275
|
+
beginReplay(): void {
|
|
276
|
+
this.#syncEntries();
|
|
277
|
+
if (this.#offered !== undefined) {
|
|
278
|
+
this.#replayRequested = true;
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.#startReplay();
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Drop a not-yet-offered replay so a shutdown flush emits only un-retired
|
|
285
|
+
* rows. The terminal already holds the committed ledger; re-streaming it at
|
|
286
|
+
* quit is pure write volume. An already offered replay batch stays valid.
|
|
287
|
+
*/
|
|
288
|
+
cancelReplay(): void {
|
|
289
|
+
this.#replayPending = false;
|
|
290
|
+
this.#replayRequested = false;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Total rows the live, un-emitted tail occupies at `width`. */
|
|
294
|
+
liveRowCount(width: number): number {
|
|
295
|
+
this.#syncEntries();
|
|
296
|
+
this.#settleFinalized();
|
|
297
|
+
let total = 0;
|
|
298
|
+
for (const { entry, index } of this.#liveEntries()) {
|
|
299
|
+
this.#setAllocation(entry.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
300
|
+
const rendered = this.#renderEntry(entry, width);
|
|
301
|
+
const block = rendered.slice(this.#projectedEmittedRowCount(entry, index, width));
|
|
302
|
+
if (block.length > 0) total += block.length + (total > 0 ? 1 : 0);
|
|
303
|
+
}
|
|
304
|
+
return total;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Block spans of the last `renderViewport` output, in output coordinates. Empty when the tail is empty. */
|
|
308
|
+
getLastViewportSpans(): readonly TranscriptViewportSpan[] {
|
|
309
|
+
return this.#lastViewportSpans;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Collapse a per-line owner list into run-length block spans, clamped to `length`. */
|
|
313
|
+
#commitViewportSpans(owners: readonly (Component | undefined)[], length: number = owners.length): void {
|
|
314
|
+
const spans: TranscriptViewportSpan[] = [];
|
|
315
|
+
let index = 0;
|
|
316
|
+
while (index < length) {
|
|
317
|
+
const component = owners[index];
|
|
318
|
+
if (component === undefined) {
|
|
319
|
+
index++;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
let end = index + 1;
|
|
323
|
+
while (end < length && owners[end] === component) end++;
|
|
324
|
+
spans.push({ component, start: index, end });
|
|
325
|
+
index = end;
|
|
326
|
+
}
|
|
327
|
+
this.#lastViewportSpans = spans;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Render the live tail, constrained to the supplied transcript height. */
|
|
331
|
+
renderViewport(width: number, rows: number, frame: AnimationFrame): readonly string[] {
|
|
332
|
+
this.#lastFrame = frame;
|
|
333
|
+
this.#syncEntries();
|
|
334
|
+
this.#settleFinalized();
|
|
335
|
+
const live = this.#liveEntries();
|
|
336
|
+
const capacity = Math.max(0, Math.trunc(rows));
|
|
337
|
+
if (live.length === 0 || capacity === 0) {
|
|
338
|
+
this.#lastViewportSpans = [];
|
|
339
|
+
return EMPTY_ROWS;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const shown: Array<{ entry: TranscriptEntry; index: number }> = [];
|
|
343
|
+
const blocks: (readonly string[])[] = [];
|
|
344
|
+
let total = 0;
|
|
345
|
+
for (const candidate of live) {
|
|
346
|
+
this.#setAllocation(candidate.entry.component, Number.MAX_SAFE_INTEGER, frame);
|
|
347
|
+
const rendered = this.#renderEntry(candidate.entry, width);
|
|
348
|
+
const block = rendered.slice(this.#projectedEmittedRowCount(candidate.entry, candidate.index, width));
|
|
349
|
+
if (block.length === 0) continue;
|
|
350
|
+
total += block.length + (shown.length > 0 ? 1 : 0);
|
|
351
|
+
shown.push(candidate);
|
|
352
|
+
blocks.push(block);
|
|
353
|
+
}
|
|
354
|
+
if (shown.length === 0) {
|
|
355
|
+
this.#lastViewportSpans = [];
|
|
356
|
+
return EMPTY_ROWS;
|
|
357
|
+
}
|
|
358
|
+
if (shown.length > capacity) return this.#renderEmergency(shown, width, capacity, frame);
|
|
359
|
+
if (total <= capacity) {
|
|
360
|
+
const output: string[] = [];
|
|
361
|
+
const owners: (Component | undefined)[] = [];
|
|
362
|
+
for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) {
|
|
363
|
+
if (output.length > 0) {
|
|
364
|
+
output.push("");
|
|
365
|
+
owners.push(undefined);
|
|
366
|
+
}
|
|
367
|
+
const component = shown[blockIndex]!.entry.component;
|
|
368
|
+
for (const line of blocks[blockIndex]!) {
|
|
369
|
+
output.push(line);
|
|
370
|
+
owners.push(component);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
this.#commitViewportSpans(owners, output.length);
|
|
374
|
+
return output;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
378
|
+
const allocation: number[] = new Array(shown.length).fill(1);
|
|
379
|
+
let surplus = capacity - shown.length;
|
|
380
|
+
// Surplus rows favor ordinary transcript blocks over dynamic tool-activity
|
|
381
|
+
// cards (newest-first within each class), so a growing tool card collapses to
|
|
382
|
+
// its compact form instead of clipping already-visible assistant text (#9718).
|
|
383
|
+
const order: number[] = [];
|
|
384
|
+
for (let index = shown.length - 1; index >= 0; index--) {
|
|
385
|
+
if (!isToolActivityComponent(shown[index]!.entry.component)) order.push(index);
|
|
386
|
+
}
|
|
387
|
+
for (let index = shown.length - 1; index >= 0; index--) {
|
|
388
|
+
if (isToolActivityComponent(shown[index]!.entry.component)) order.push(index);
|
|
389
|
+
}
|
|
390
|
+
for (const index of order) {
|
|
391
|
+
if (surplus <= 0) break;
|
|
392
|
+
const extra = Math.min(Math.max(0, blocks[index]!.length - 1), surplus);
|
|
393
|
+
allocation[index] += extra;
|
|
394
|
+
surplus -= extra;
|
|
395
|
+
}
|
|
396
|
+
const output: string[] = [];
|
|
397
|
+
const owners: (Component | undefined)[] = [];
|
|
398
|
+
for (let index = 0; index < shown.length; index++) {
|
|
399
|
+
const candidate = shown[index]!;
|
|
400
|
+
const allocated = allocation[index]!;
|
|
401
|
+
this.#setAllocation(candidate.entry.component, allocated, frame);
|
|
402
|
+
const rendered = this.#renderEntry(candidate.entry, width).slice(
|
|
403
|
+
this.#projectedEmittedRowCount(candidate.entry, candidate.index, width),
|
|
404
|
+
);
|
|
405
|
+
const visible = rendered.length <= allocated ? rendered : rendered.slice(rendered.length - allocated);
|
|
406
|
+
for (const line of visible) {
|
|
407
|
+
output.push(line);
|
|
408
|
+
owners.push(candidate.entry.component);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const drop = Math.max(0, output.length - capacity);
|
|
412
|
+
this.#commitViewportSpans(owners.slice(drop), output.length - drop);
|
|
413
|
+
return drop > 0 ? output.slice(drop) : output;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/** Offers stable-head emission or the shortest finalized prefix needed under pressure. */
|
|
417
|
+
peekFinalizedBatch(width: number, capacity: number): HistoryBatch | undefined {
|
|
418
|
+
return this.#peekBatch(width, capacity, "pressure");
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** Returns only a prepared complete replay, never a normal retirement offer. */
|
|
422
|
+
peekReplayBatch(width: number): HistoryBatch | undefined {
|
|
423
|
+
this.#syncEntries();
|
|
424
|
+
this.#settleFinalized();
|
|
425
|
+
return this.#peekReplayBatch(width);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
#peekReplayBatch(width: number): HistoryBatch | undefined {
|
|
429
|
+
if (this.#offered !== undefined) {
|
|
430
|
+
return this.#offered.kind === "replay" ? this.#offered.batch : undefined;
|
|
431
|
+
}
|
|
432
|
+
if (!this.#replayPending) return undefined;
|
|
433
|
+
const rows = this.#renderReplay(width);
|
|
434
|
+
this.#replayPending = false;
|
|
435
|
+
if (rows.length === 0) return undefined;
|
|
436
|
+
const batch: HistoryBatch = { id: this.#nextBatchId++, rows, kind: "replay" };
|
|
437
|
+
this.#offered = { batch, kind: "replay" };
|
|
438
|
+
return batch;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Offers the complete currently eligible prefix for graceful shutdown. */
|
|
442
|
+
peekFlushBatch(width: number): HistoryBatch | undefined {
|
|
443
|
+
return this.#peekBatch(width, 0, "flush");
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/** Recompose the unacknowledged batch so a discarded TUI frame can be rendered again. */
|
|
447
|
+
rerenderOfferedBatch(width: number): HistoryBatch | undefined {
|
|
448
|
+
const offered = this.#offered;
|
|
449
|
+
if (offered === undefined) return undefined;
|
|
450
|
+
let rows: readonly string[];
|
|
451
|
+
if (offered.kind === "append") {
|
|
452
|
+
const entry = this.#entries[offered.entry];
|
|
453
|
+
if (entry === undefined) return undefined;
|
|
454
|
+
const before = this.#renderStablePrefix(entry, entry.emitted, width);
|
|
455
|
+
const after = this.#renderStablePrefix(entry, offered.emittedEnd, width);
|
|
456
|
+
rows = after.slice(before.length);
|
|
457
|
+
} else if (offered.kind === "commit") {
|
|
458
|
+
rows = this.#renderRange(this.#frontier, offered.end, width, true);
|
|
459
|
+
} else {
|
|
460
|
+
rows = this.#renderReplay(width);
|
|
461
|
+
}
|
|
462
|
+
offered.batch = { id: offered.batch.id, rows, kind: offered.batch.kind };
|
|
463
|
+
return offered.batch;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
#peekBatch(width: number, capacity: number, policy: RetirementPolicy): HistoryBatch | undefined {
|
|
467
|
+
this.#syncEntries();
|
|
468
|
+
this.#settleFinalized();
|
|
469
|
+
if (this.#offered !== undefined) return this.#offered.batch;
|
|
470
|
+
const replay = this.#peekReplayBatch(width);
|
|
471
|
+
if (replay !== undefined) return replay;
|
|
472
|
+
|
|
473
|
+
this.#completeFullyEmittedHeads(width);
|
|
474
|
+
const room = Math.max(0, Math.trunc(capacity));
|
|
475
|
+
const live = this.#liveEntries();
|
|
476
|
+
if (live.length === 0) return undefined;
|
|
477
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
478
|
+
const rendered: (readonly string[])[] = new Array(live.length);
|
|
479
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
480
|
+
const heights: number[] = new Array(live.length);
|
|
481
|
+
let total = 0;
|
|
482
|
+
let visible = 0;
|
|
483
|
+
for (let index = 0; index < live.length; index++) {
|
|
484
|
+
const candidate = live[index]!;
|
|
485
|
+
this.#setAllocation(candidate.entry.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
486
|
+
const renderedEntry = this.#renderEntry(candidate.entry, width);
|
|
487
|
+
const rows = renderedEntry.slice(
|
|
488
|
+
this.#renderStablePrefix(candidate.entry, candidate.entry.emitted, width).length,
|
|
489
|
+
);
|
|
490
|
+
rendered[index] = rows;
|
|
491
|
+
heights[index] = rows.length;
|
|
492
|
+
if (rows.length > 0) total += rows.length + (visible++ > 0 ? 1 : 0);
|
|
493
|
+
}
|
|
494
|
+
const overflowing = total > room || this.#liveCount() >= MAX_LIVE_BLOCKS;
|
|
495
|
+
if (policy === "pressure" && !overflowing) {
|
|
496
|
+
this.#pinnedFrontier = undefined;
|
|
497
|
+
return undefined;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const head = this.#entries[this.#frontier];
|
|
501
|
+
if (
|
|
502
|
+
policy === "pressure" &&
|
|
503
|
+
total > room &&
|
|
504
|
+
head?.mode === "appendOnly" &&
|
|
505
|
+
!head.stableFrozen &&
|
|
506
|
+
head.state !== "committed" &&
|
|
507
|
+
head.emitted < head.stableRows.length
|
|
508
|
+
) {
|
|
509
|
+
// Emit as many finished rows as the overflow needs, in one batch. A
|
|
510
|
+
// fast stream adds finished rows quicker than one per pressure cycle,
|
|
511
|
+
// and the live region has to fall back under `room` to stay readable:
|
|
512
|
+
// rows left behind here are rows dropped from the top of the viewport.
|
|
513
|
+
const overflow = total - room;
|
|
514
|
+
const before = this.#renderStablePrefix(head, head.emitted, width);
|
|
515
|
+
let emittedEnd = head.emitted;
|
|
516
|
+
let rows: readonly string[] = EMPTY_ROWS;
|
|
517
|
+
while (emittedEnd < head.stableRows.length && rows.length < overflow) {
|
|
518
|
+
const after = this.#renderStablePrefix(head, emittedEnd + 1, width);
|
|
519
|
+
if (!isRowPrefix(before, after) || after.length === before.length) {
|
|
520
|
+
if (emittedEnd === head.emitted) {
|
|
521
|
+
this.#freezeStableRows(head, EMPTY_ROWS, "semantic row render added no suffix");
|
|
522
|
+
}
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
rows = after.slice(before.length);
|
|
526
|
+
emittedEnd += 1;
|
|
527
|
+
}
|
|
528
|
+
if (emittedEnd > head.emitted) {
|
|
529
|
+
const batch: HistoryBatch = {
|
|
530
|
+
id: this.#nextBatchId++,
|
|
531
|
+
rows,
|
|
532
|
+
kind: "append",
|
|
533
|
+
};
|
|
534
|
+
this.#offered = { batch, kind: "append", entry: this.#frontier, emittedEnd };
|
|
535
|
+
this.#pinnedFrontier = undefined;
|
|
536
|
+
return batch;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
let end = this.#frontier;
|
|
541
|
+
let freed = 0;
|
|
542
|
+
let index = 0;
|
|
543
|
+
while (end < this.#entries.length && this.#entries[end]!.state === "settled") {
|
|
544
|
+
if (
|
|
545
|
+
policy === "pressure" &&
|
|
546
|
+
total - freed <= room &&
|
|
547
|
+
this.#liveCount() - (end - this.#frontier) < MAX_LIVE_BLOCKS
|
|
548
|
+
)
|
|
549
|
+
break;
|
|
550
|
+
freed += heights[index]! > 0 ? heights[index]! + 1 : 0;
|
|
551
|
+
end++;
|
|
552
|
+
index++;
|
|
553
|
+
}
|
|
554
|
+
if (end === this.#frontier) {
|
|
555
|
+
if (policy === "pressure") this.#notePinnedFrontier();
|
|
556
|
+
return undefined;
|
|
557
|
+
}
|
|
558
|
+
this.#pinnedFrontier = undefined;
|
|
559
|
+
const batch: HistoryBatch = {
|
|
560
|
+
id: this.#nextBatchId++,
|
|
561
|
+
rows: this.#renderRange(this.#frontier, end, width, true),
|
|
562
|
+
kind: "append",
|
|
563
|
+
};
|
|
564
|
+
this.#offered = { batch, end, kind: "commit" };
|
|
565
|
+
return batch;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** Acknowledges exactly the most recently offered append, commit, or replay transaction. */
|
|
569
|
+
acknowledgeFinalizedBatch(id: number): void {
|
|
570
|
+
const offered = this.#offered;
|
|
571
|
+
if (offered === undefined || offered.batch.id !== id) return;
|
|
572
|
+
if (offered.kind === "append") {
|
|
573
|
+
const entry = this.#entries[offered.entry];
|
|
574
|
+
// The offered end must still extend this entry's emitted prefix: a
|
|
575
|
+
// stale offer (already-advanced entry) or a retraction (entry reset to
|
|
576
|
+
// zero with the offer still live) must not move it backwards.
|
|
577
|
+
if (entry === undefined || offered.entry !== this.#frontier || offered.emittedEnd <= entry.emitted) return;
|
|
578
|
+
entry.emitted = offered.emittedEnd;
|
|
579
|
+
} else if (offered.kind === "commit") {
|
|
580
|
+
for (let index = this.#frontier; index < offered.end; index++) {
|
|
581
|
+
this.#entries[index]!.state = "committed";
|
|
582
|
+
this.#entries[index]!.emitted = 0;
|
|
583
|
+
}
|
|
584
|
+
this.#frontier = offered.end;
|
|
585
|
+
}
|
|
586
|
+
this.#offered = undefined;
|
|
587
|
+
if (this.#replayRequested) this.#startReplay();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Render only the trailing `maxRows` semantic rows, walking blocks bottom-up.
|
|
592
|
+
* Used by the transient resize-buffer repaint, which needs one viewport of
|
|
593
|
+
* tail rows per resize event — never the full committed ledger.
|
|
594
|
+
*/
|
|
595
|
+
renderTail(width: number, maxRows: number): readonly string[] {
|
|
596
|
+
this.#syncEntries();
|
|
597
|
+
const cap = Math.max(0, Math.trunc(maxRows));
|
|
598
|
+
if (cap === 0) return EMPTY_ROWS;
|
|
599
|
+
const rows: string[] = [];
|
|
600
|
+
for (let index = this.#entries.length - 1; index >= 0; index--) {
|
|
601
|
+
const entry = this.#entries[index]!;
|
|
602
|
+
this.#setAllocation(entry.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
603
|
+
const block = trimBlankEdges(entry.component.render(width));
|
|
604
|
+
if (block.length === 0) continue;
|
|
605
|
+
if (rows.length > 0) rows.unshift("");
|
|
606
|
+
rows.unshift(...block);
|
|
607
|
+
if (rows.length >= cap) break;
|
|
608
|
+
}
|
|
609
|
+
return rows.length > cap ? rows.slice(rows.length - cap) : rows;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** Full semantic render used by exports and non-terminal commands. */
|
|
613
|
+
override render(width: number): readonly string[] {
|
|
614
|
+
this.#syncEntries();
|
|
615
|
+
this.#childStartRows.clear();
|
|
616
|
+
const rows: string[] = [];
|
|
617
|
+
for (const entry of this.#entries) {
|
|
618
|
+
this.#setAllocation(entry.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
619
|
+
const block = this.#renderEntry(entry, width);
|
|
620
|
+
if (block.length === 0) continue;
|
|
621
|
+
if (rows.length > 0) rows.push("");
|
|
622
|
+
this.#childStartRows.set(entry.component, rows.length);
|
|
623
|
+
rows.push(...block);
|
|
624
|
+
}
|
|
625
|
+
return rows;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** Rendered row where a child's block begins in the last full render() (transcript deep-links). */
|
|
629
|
+
getChildStartRow(child: Component): number | undefined {
|
|
630
|
+
return this.#childStartRows.get(child);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
#renderEntry(entry: TranscriptEntry, width: number): readonly string[] {
|
|
634
|
+
const rendered = trimBlankEdges(entry.component.render(width));
|
|
635
|
+
if (entry.mode === "mutable" || entry.stableFrozen) return rendered;
|
|
636
|
+
const appendOnly = entry.component as Component & AppendOnlyTranscriptBlock;
|
|
637
|
+
const stable = appendOnly.getTranscriptStableRows();
|
|
638
|
+
if (!isStablePrefix(entry.stableRows, stable)) {
|
|
639
|
+
return this.#freezeStableRows(entry, rendered, "publication retracted the published prefix");
|
|
640
|
+
}
|
|
641
|
+
if (entry.emitted > stable.length) {
|
|
642
|
+
return this.#freezeStableRows(entry, rendered, "publication retracted emitted history");
|
|
643
|
+
}
|
|
644
|
+
const published =
|
|
645
|
+
stable.length > entry.stableRows.length
|
|
646
|
+
? [...entry.stableRows, ...stable.slice(entry.stableRows.length)]
|
|
647
|
+
: entry.stableRows;
|
|
648
|
+
const stableRendered = appendOnly.renderTranscriptStableRows(published.length, width);
|
|
649
|
+
if (!isRowPrefix(stableRendered, rendered)) {
|
|
650
|
+
return this.#freezeStableRows(entry, rendered, "stable rows no longer render as a prefix of the block");
|
|
651
|
+
}
|
|
652
|
+
const priorRender = entry.renderedStableByWidth.get(width);
|
|
653
|
+
if (priorRender && !isRowPrefix(priorRender, stableRendered)) {
|
|
654
|
+
return this.#freezeStableRows(entry, rendered, "stable rows changed within a width epoch");
|
|
655
|
+
}
|
|
656
|
+
entry.stableRows = published;
|
|
657
|
+
// Slice only when the rendered rows actually changed: same length
|
|
658
|
+
// plus prefix-equality in both directions means byte-identical, so
|
|
659
|
+
// the stored array can be reused (callers only slice/read it).
|
|
660
|
+
const priorRows = entry.renderedStableByWidth.get(width);
|
|
661
|
+
if (
|
|
662
|
+
priorRows === undefined ||
|
|
663
|
+
priorRows.length !== stableRendered.length ||
|
|
664
|
+
!isRowPrefix(priorRows, stableRendered)
|
|
665
|
+
) {
|
|
666
|
+
entry.renderedStableByWidth.set(width, stableRendered.slice());
|
|
667
|
+
}
|
|
668
|
+
let perCount = entry.stableRowCountByWidth.get(width);
|
|
669
|
+
if (perCount === undefined) {
|
|
670
|
+
perCount = new Map();
|
|
671
|
+
entry.stableRowCountByWidth.set(width, perCount);
|
|
672
|
+
}
|
|
673
|
+
perCount.set(published.length, stableRendered.length);
|
|
674
|
+
return rendered;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Demote a drifting append-only publication: rows already written to native
|
|
679
|
+
* scrollback cannot be retracted, so keep the last good stable state for
|
|
680
|
+
* emitted-row slicing and stop mid-stream emission for this block. The block
|
|
681
|
+
* still renders and retires whole on finalization; worst case is the old
|
|
682
|
+
* finalize-time behavior plus a possible stale-byte seam in scrollback.
|
|
683
|
+
*/
|
|
684
|
+
#freezeStableRows(entry: TranscriptEntry, rendered: readonly string[], reason: string): readonly string[] {
|
|
685
|
+
entry.stableFrozen = true;
|
|
686
|
+
logger.warn("Append-only transcript block frozen", { reason, emitted: entry.emitted });
|
|
687
|
+
return rendered;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
#renderStablePrefix(entry: TranscriptEntry, count: number, width: number): readonly string[] {
|
|
691
|
+
if (count === 0) return EMPTY_ROWS;
|
|
692
|
+
const appendOnly = entry.component as Component & AppendOnlyTranscriptBlock;
|
|
693
|
+
return appendOnly.renderTranscriptStableRows(Math.min(count, entry.stableRows.length), width);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Length-only variant of `#renderStablePrefix`: answers the projected
|
|
698
|
+
* emitted row count without re-rendering the prefix. The container only
|
|
699
|
+
* needs the length for slicing; the render call it replaced existed
|
|
700
|
+
* purely to read `.length` off the result.
|
|
701
|
+
*/
|
|
702
|
+
#projectedEmittedRowCount(entry: TranscriptEntry, index: number, width: number): number {
|
|
703
|
+
const offered = this.#offered;
|
|
704
|
+
const count = offered?.kind === "append" && offered.entry === index ? offered.emittedEnd : entry.emitted;
|
|
705
|
+
if (count === 0) return 0;
|
|
706
|
+
const perCount = entry.stableRowCountByWidth.get(width);
|
|
707
|
+
const memo = perCount?.get(Math.min(count, entry.stableRows.length));
|
|
708
|
+
if (memo !== undefined) return memo;
|
|
709
|
+
return this.#renderStablePrefix(entry, count, width).length;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Record that pressure retirement is blocked behind a not-yet-settled
|
|
713
|
+
* frontier block, and log its identity once the episode outlives the grace
|
|
714
|
+
* period. A block that never finalizes (a dropped terminal event) pins the
|
|
715
|
+
* whole live region here with no visible symptom other than degraded
|
|
716
|
+
* one-line layout, so the log line is the only forensic trail.
|
|
717
|
+
*/
|
|
718
|
+
#notePinnedFrontier(): void {
|
|
719
|
+
const entry = this.#entries[this.#frontier];
|
|
720
|
+
if (entry === undefined) return;
|
|
721
|
+
const now = Date.now();
|
|
722
|
+
if (this.#pinnedFrontier?.index !== this.#frontier) {
|
|
723
|
+
this.#pinnedFrontier = { index: this.#frontier, since: now, logged: false };
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
if (this.#pinnedFrontier.logged || now - this.#pinnedFrontier.since < PINNED_FRONTIER_WARN_MS) return;
|
|
727
|
+
this.#pinnedFrontier.logged = true;
|
|
728
|
+
logger.warn("Transcript retirement pinned by unfinalized frontier block", {
|
|
729
|
+
component: entry.component.constructor.name,
|
|
730
|
+
state: entry.state,
|
|
731
|
+
mode: entry.mode,
|
|
732
|
+
liveBlocks: this.#liveCount(),
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
#renderRange(start: number, end: number, width: number, trailingBlank: boolean): readonly string[] {
|
|
737
|
+
const rows: string[] = [];
|
|
738
|
+
for (let index = start; index < end; index++) {
|
|
739
|
+
const entry = this.#entries[index]!;
|
|
740
|
+
this.#setAllocation(entry.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
741
|
+
// Only the range head is sliced by its emitted stable prefix; every other
|
|
742
|
+
// entry renders whole, so the append-only verification pass (a second
|
|
743
|
+
// full render of the block's stable prefix) is skipped for them. This
|
|
744
|
+
// keeps a complete-ledger replay at one render per block.
|
|
745
|
+
const rendered =
|
|
746
|
+
index === start ? this.#renderEntry(entry, width) : trimBlankEdges(entry.component.render(width));
|
|
747
|
+
const emittedRows = index === start ? this.#renderStablePrefix(entry, entry.emitted, width).length : 0;
|
|
748
|
+
const block = rendered.slice(emittedRows);
|
|
749
|
+
if (block.length === 0) continue;
|
|
750
|
+
if (rows.length > 0) rows.push("");
|
|
751
|
+
rows.push(...block);
|
|
752
|
+
}
|
|
753
|
+
if (trailingBlank && rows.length > 0) rows.push("");
|
|
754
|
+
return rows;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
#renderReplay(width: number): readonly string[] {
|
|
758
|
+
const rows = Array.from(this.#renderRange(0, this.#frontier, width, true));
|
|
759
|
+
const head = this.#entries[this.#frontier];
|
|
760
|
+
if (head?.mode === "appendOnly" && head.emitted > 0) {
|
|
761
|
+
this.#setAllocation(head.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
762
|
+
this.#renderEntry(head, width);
|
|
763
|
+
rows.push(...this.#renderStablePrefix(head, head.emitted, width));
|
|
764
|
+
}
|
|
765
|
+
return rows;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
#completeFullyEmittedHeads(width: number): void {
|
|
769
|
+
while (this.#frontier < this.#entries.length) {
|
|
770
|
+
const entry = this.#entries[this.#frontier]!;
|
|
771
|
+
if (entry.mode !== "appendOnly" || entry.state !== "settled") return;
|
|
772
|
+
this.#setAllocation(entry.component, Number.MAX_SAFE_INTEGER, this.#lastFrame);
|
|
773
|
+
const rendered = this.#renderEntry(entry, width);
|
|
774
|
+
if (entry.emitted !== entry.stableRows.length) return;
|
|
775
|
+
if (this.#renderStablePrefix(entry, entry.emitted, width).length !== rendered.length) return;
|
|
776
|
+
entry.state = "committed";
|
|
777
|
+
entry.emitted = 0;
|
|
778
|
+
this.#frontier++;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
#startReplay(): void {
|
|
783
|
+
const head = this.#entries[this.#frontier];
|
|
784
|
+
this.#replayPending = this.#frontier > 0 || (head?.mode === "appendOnly" && head.emitted > 0);
|
|
785
|
+
this.#replayRequested = false;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
#renderEmergency(
|
|
789
|
+
shown: readonly { entry: TranscriptEntry; index: number }[],
|
|
790
|
+
width: number,
|
|
791
|
+
rows: number,
|
|
792
|
+
frame: AnimationFrame,
|
|
793
|
+
): readonly string[] {
|
|
794
|
+
let visibleRows = rows;
|
|
795
|
+
let visible: { entry: TranscriptEntry; index: number }[] = [];
|
|
796
|
+
let emergencyCandidate: { entry: TranscriptEntry; index: number } | undefined;
|
|
797
|
+
let emergencyRow: string | undefined;
|
|
798
|
+
let hiddenActive = 0;
|
|
799
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
800
|
+
visible = visibleRows > 0 ? shown.slice(-visibleRows) : [];
|
|
801
|
+
emergencyCandidate = undefined;
|
|
802
|
+
emergencyRow = undefined;
|
|
803
|
+
const visibleStart = shown.length - visibleRows;
|
|
804
|
+
for (let index = visibleStart - 1; index >= 0; index--) {
|
|
805
|
+
const candidate = shown[index]!;
|
|
806
|
+
const block = candidate.entry.component as Component & FinalizableBlock;
|
|
807
|
+
const row =
|
|
808
|
+
candidate.entry.state === "settled" ? block.renderTranscriptBlockEmergencyRow?.(width) : undefined;
|
|
809
|
+
if (row === undefined) continue;
|
|
810
|
+
emergencyCandidate = candidate;
|
|
811
|
+
emergencyRow = row;
|
|
812
|
+
visible = [candidate, ...visible.slice(1)];
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
let activeTotal = 0;
|
|
817
|
+
for (const candidate of shown) {
|
|
818
|
+
if (candidate.entry.state === "active") activeTotal++;
|
|
819
|
+
}
|
|
820
|
+
hiddenActive = activeTotal;
|
|
821
|
+
for (const candidate of visible) {
|
|
822
|
+
if (candidate.entry.state === "active") hiddenActive--;
|
|
823
|
+
}
|
|
824
|
+
// The summary row itself represents the newest active block when no
|
|
825
|
+
// active row fits beside it; report only the additional backlog.
|
|
826
|
+
if (hiddenActive === activeTotal && hiddenActive > 0) hiddenActive--;
|
|
827
|
+
if (attempt === 0 && hiddenActive > 0) {
|
|
828
|
+
visibleRows = Math.max(0, rows - 1);
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const output = hiddenActive > 0 ? [`${hiddenActive} more transcript blocks active`] : [];
|
|
835
|
+
const owners: (Component | undefined)[] = hiddenActive > 0 ? [undefined] : [];
|
|
836
|
+
for (const candidate of visible) {
|
|
837
|
+
if (candidate === emergencyCandidate) {
|
|
838
|
+
output.push(emergencyRow ?? "");
|
|
839
|
+
owners.push(candidate.entry.component);
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
this.#setAllocation(candidate.entry.component, 1, frame);
|
|
843
|
+
const rendered = this.#renderEntry(candidate.entry, width).slice(
|
|
844
|
+
this.#projectedEmittedRowCount(candidate.entry, candidate.index, width),
|
|
845
|
+
);
|
|
846
|
+
output.push(rendered[0] ?? "");
|
|
847
|
+
owners.push(candidate.entry.component);
|
|
848
|
+
}
|
|
849
|
+
const visibleOutput = output.slice(0, rows);
|
|
850
|
+
this.#commitViewportSpans(owners, visibleOutput.length);
|
|
851
|
+
return visibleOutput;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
#setAllocation(component: Component, rows: number, frame: AnimationFrame): void {
|
|
855
|
+
(component as Component & TranscriptPresentationTarget).setTranscriptAllocation?.(rows, frame);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
#settleFinalized(): void {
|
|
859
|
+
for (let index = this.#frontier; index < this.#entries.length; index++) {
|
|
860
|
+
const entry = this.#entries[index]!;
|
|
861
|
+
if (entry.state === "active" && isFinalized(entry.component)) entry.state = "settled";
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
#liveEntries(): Array<{ entry: TranscriptEntry; index: number }> {
|
|
866
|
+
const start = this.#offered?.kind === "commit" ? this.#offered.end : this.#frontier;
|
|
867
|
+
const live: Array<{ entry: TranscriptEntry; index: number }> = [];
|
|
868
|
+
for (let index = start; index < this.#entries.length; index++) live.push({ entry: this.#entries[index]!, index });
|
|
869
|
+
return live;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
#liveCount(): number {
|
|
873
|
+
return this.#entries.length - this.#frontier;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
#syncEntries(): void {
|
|
877
|
+
if (
|
|
878
|
+
this.#entries.length === this.children.length &&
|
|
879
|
+
this.#entries.every((entry, index) => entry.component === this.children[index])
|
|
880
|
+
)
|
|
881
|
+
return;
|
|
882
|
+
const existing = new Map(this.#entries.map(entry => [entry.component, entry]));
|
|
883
|
+
this.#entries = this.children.map(
|
|
884
|
+
component =>
|
|
885
|
+
existing.get(component) ?? {
|
|
886
|
+
component,
|
|
887
|
+
state: "active",
|
|
888
|
+
mode: blockMode(component),
|
|
889
|
+
stableRows: EMPTY_STABLE_ROWS,
|
|
890
|
+
renderedStableByWidth: new Map(),
|
|
891
|
+
stableRowCountByWidth: new Map(),
|
|
892
|
+
emitted: 0,
|
|
893
|
+
stableFrozen: false,
|
|
894
|
+
},
|
|
895
|
+
);
|
|
896
|
+
this.#frontier = this.#entries.findIndex(entry => entry.state !== "committed");
|
|
897
|
+
if (this.#frontier < 0) this.#frontier = this.#entries.length;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/** Groups sibling rows into one conservative mutable semantic transcript block. */
|
|
902
|
+
export class TranscriptBlock extends Container {}
|