@bubblebrain-ai/bubble 0.0.52 → 0.0.53
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/README.md +4 -12
- package/dist/agent/routing-catalog.js +3 -2
- package/dist/agent/subagent/router.js +5 -0
- package/dist/agent/subagent/runtime.d.ts +1 -0
- package/dist/agent/subagent/runtime.js +13 -1
- package/dist/agent/subagent-control.d.ts +4 -0
- package/dist/agent/subagent-control.js +1 -0
- package/dist/agent/subagent-store.js +2 -0
- package/dist/agent/workflow/control.d.ts +2 -0
- package/dist/agent/workflow/runs.d.ts +1 -0
- package/dist/agent/workflow/runs.js +3 -0
- package/dist/agent.d.ts +11 -1
- package/dist/agent.js +158 -57
- package/dist/bin.js +2 -44
- package/dist/config.d.ts +14 -1
- package/dist/config.js +45 -4
- package/dist/context/budget.d.ts +7 -1
- package/dist/context/budget.js +25 -2
- package/dist/context/compact-llm.d.ts +1 -1
- package/dist/context/compact-llm.js +5 -2
- package/dist/context/overflow.js +2 -0
- package/dist/context/projector.d.ts +8 -0
- package/dist/context/projector.js +55 -6
- package/dist/context/tool-output-truncate.d.ts +17 -1
- package/dist/context/tool-output-truncate.js +171 -49
- package/dist/feishu/agent-host/run-driver.js +3 -0
- package/dist/feishu/serve.js +2 -0
- package/dist/goal/command.d.ts +1 -1
- package/dist/goal/command.js +7 -2
- package/dist/main.d.ts +1 -1
- package/dist/main.js +38 -8
- package/dist/memory/db.js +0 -7
- package/dist/model-catalog.js +25 -6
- package/dist/model-config.js +3 -2
- package/dist/model-pricing.d.ts +24 -5
- package/dist/model-pricing.js +0 -0
- package/dist/model-selection.js +13 -4
- package/dist/network/chatgpt-transport.js +0 -34
- package/dist/network/errors.d.ts +19 -0
- package/dist/network/errors.js +24 -0
- package/dist/network/provider-transport.d.ts +0 -4
- package/dist/network/provider-transport.js +3 -35
- package/dist/network/retry.d.ts +6 -1
- package/dist/network/retry.js +9 -0
- package/dist/provider-model-policy.d.ts +16 -0
- package/dist/provider-model-policy.js +33 -0
- package/dist/provider-registry.d.ts +1 -1
- package/dist/provider-registry.js +73 -10
- package/dist/provider-transform.js +32 -4
- package/dist/provider.d.ts +6 -2
- package/dist/provider.js +95 -6
- package/dist/question/controller.js +5 -4
- package/dist/question/normalize.d.ts +6 -0
- package/dist/question/normalize.js +11 -0
- package/dist/rewind.d.ts +20 -0
- package/dist/rewind.js +29 -0
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +11 -3
- package/dist/session.d.ts +7 -0
- package/dist/session.js +20 -0
- package/dist/skills/discovery.js +18 -0
- package/dist/skills/registry.d.ts +12 -2
- package/dist/skills/registry.js +40 -5
- package/dist/skills/types.d.ts +2 -0
- package/dist/slash-commands/commands.js +120 -81
- package/dist/slash-commands/registry.d.ts +2 -1
- package/dist/slash-commands/registry.js +3 -0
- package/dist/slash-commands/types.d.ts +22 -4
- package/dist/stats/usage.d.ts +3 -1
- package/dist/stats/usage.js +22 -13
- package/dist/tasks/manager.d.ts +4 -2
- package/dist/tasks/manager.js +34 -9
- package/dist/tasks/promotion.d.ts +2 -2
- package/dist/tasks/promotion.js +2 -2
- package/dist/tools/agent-lifecycle.js +4 -0
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.js +13 -2
- package/dist/tools/grep.d.ts +5 -1
- package/dist/tools/grep.js +318 -69
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/question.js +5 -4
- package/dist/tools/read.js +40 -21
- package/dist/tui/animation-clock.d.ts +14 -0
- package/dist/tui/animation-clock.js +34 -0
- package/dist/tui/app.d.ts +176 -0
- package/dist/tui/app.js +1647 -0
- package/dist/tui/components/approval-dialog.d.ts +43 -0
- package/dist/tui/components/approval-dialog.js +247 -0
- package/dist/tui/components/bottom-sheet.d.ts +9 -0
- package/dist/tui/components/bottom-sheet.js +32 -0
- package/dist/tui/components/context-info.d.ts +54 -0
- package/dist/tui/components/context-info.js +388 -0
- package/dist/tui/components/feedback-dialog.d.ts +56 -0
- package/dist/tui/components/feedback-dialog.js +262 -0
- package/dist/tui/components/feishu-setup-dialog.d.ts +65 -0
- package/dist/tui/components/feishu-setup-dialog.js +332 -0
- package/dist/tui/components/image-preview.d.ts +32 -0
- package/dist/tui/components/image-preview.js +130 -0
- package/dist/tui/components/plan-dialog.d.ts +34 -0
- package/dist/tui/components/plan-dialog.js +196 -0
- package/dist/tui/components/provider-key-input.d.ts +18 -0
- package/dist/tui/components/provider-key-input.js +49 -0
- package/dist/tui/components/question-dialog.d.ts +25 -0
- package/dist/tui/components/question-dialog.js +263 -0
- package/dist/tui/components/responsive-transcript.d.ts +31 -0
- package/dist/tui/components/responsive-transcript.js +77 -0
- package/dist/tui/components/rewind-picker.d.ts +62 -0
- package/dist/tui/components/rewind-picker.js +317 -0
- package/dist/tui/components/session-picker.d.ts +49 -0
- package/dist/tui/components/session-picker.js +303 -0
- package/dist/tui/components/skills-panel.d.ts +59 -0
- package/dist/tui/components/skills-panel.js +568 -0
- package/dist/tui/components/stats-panel.d.ts +40 -0
- package/dist/tui/components/stats-panel.js +301 -0
- package/dist/tui/components/streaming-message.d.ts +69 -0
- package/dist/tui/components/streaming-message.js +393 -0
- package/dist/tui/components/subagent-inspector.d.ts +28 -0
- package/dist/tui/components/subagent-inspector.js +127 -0
- package/dist/tui/components/task-inspector.d.ts +26 -0
- package/dist/tui/components/task-inspector.js +70 -0
- package/dist/tui/components/tasks-pane.d.ts +88 -0
- package/dist/tui/components/tasks-pane.js +416 -0
- package/dist/tui/components/transcript.d.ts +96 -0
- package/dist/tui/components/transcript.js +771 -0
- package/dist/tui/components/welcome.d.ts +20 -0
- package/dist/tui/components/welcome.js +133 -0
- package/dist/tui/components/workflow-inspector.d.ts +30 -0
- package/dist/tui/components/workflow-inspector.js +136 -0
- package/dist/tui/composer-autocomplete.d.ts +61 -0
- package/dist/tui/composer-autocomplete.js +383 -0
- package/dist/tui/composer-style.d.ts +7 -0
- package/dist/tui/composer-style.js +29 -0
- package/dist/tui/controller/agent-event-reducer.d.ts +75 -0
- package/dist/tui/controller/agent-event-reducer.js +238 -0
- package/dist/tui/controller/composer-controller.d.ts +95 -0
- package/dist/tui/controller/composer-controller.js +502 -0
- package/dist/tui/controller/controller.d.ts +194 -0
- package/dist/tui/controller/controller.js +1035 -0
- package/dist/tui/controller/effects.d.ts +71 -0
- package/dist/tui/controller/effects.js +1 -0
- package/dist/tui/controller/goal-runtime-controller.d.ts +47 -0
- package/dist/tui/controller/goal-runtime-controller.js +202 -0
- package/dist/tui/controller/input-queue-machine.d.ts +71 -0
- package/dist/tui/controller/input-queue-machine.js +121 -0
- package/dist/tui/controller/intents.d.ts +56 -0
- package/dist/tui/controller/intents.js +6 -0
- package/dist/tui/controller/overlay-controller.d.ts +64 -0
- package/dist/tui/controller/overlay-controller.js +129 -0
- package/dist/tui/controller/ports.d.ts +57 -0
- package/dist/tui/controller/ports.js +9 -0
- package/dist/tui/controller/session-transition.d.ts +54 -0
- package/dist/tui/controller/session-transition.js +68 -0
- package/dist/tui/controller/state.d.ts +14 -0
- package/dist/tui/controller/state.js +36 -0
- package/dist/tui/controller/task-runtime-controller.d.ts +66 -0
- package/dist/tui/controller/task-runtime-controller.js +158 -0
- package/dist/tui/footer.d.ts +37 -0
- package/dist/tui/footer.js +80 -0
- package/dist/{tui-ink → tui/formatting}/edit-diff.d.ts +1 -1
- package/dist/{tui-ink → tui/formatting}/edit-diff.js +1 -1
- package/dist/{tui-ink/app-helpers.d.ts → tui/formatting/summary.d.ts} +4 -4
- package/dist/{tui-ink/app-helpers.js → tui/formatting/summary.js} +2 -2
- package/dist/tui/fullscreen.d.ts +48 -0
- package/dist/tui/fullscreen.js +255 -0
- package/dist/tui/image-display.d.ts +4 -0
- package/dist/tui/image-display.js +30 -12
- package/dist/tui/markdown-style.d.ts +5 -0
- package/dist/tui/markdown-style.js +23 -0
- package/dist/{tui-ink → tui/model}/composer-buffer.js +1 -1
- package/dist/tui/model/composer-types.d.ts +17 -0
- package/dist/tui/model/composer-types.js +1 -0
- package/dist/{tui-ink → tui/model}/display-history.d.ts +7 -1
- package/dist/{tui-ink → tui/model}/display-reconstruct.d.ts +1 -1
- package/dist/{tui-ink → tui/model}/display-reconstruct.js +54 -6
- package/dist/{tui-ink → tui/model}/file-mentions.d.ts +2 -0
- package/dist/{tui-ink → tui/model}/file-mentions.js +4 -0
- package/dist/tui/model/image-attachment.d.ts +15 -0
- package/dist/tui/model/image-attachment.js +1 -0
- package/dist/{tui-ink → tui/model}/image-paste.d.ts +7 -1
- package/dist/{tui-ink → tui/model}/image-paste.js +46 -0
- package/dist/tui/model/input-history.d.ts +1 -0
- package/dist/tui/model/input-history.js +1 -0
- package/dist/{tui-ink → tui/model}/input-queue.d.ts +1 -1
- package/dist/{tui-ink → tui/model}/recent-activity.js +1 -1
- package/dist/{tui-ink → tui/model}/subagent-view.d.ts +17 -2
- package/dist/{tui-ink → tui/model}/subagent-view.js +125 -4
- package/dist/{tui-ink → tui/model}/submit-dedupe.d.ts +1 -1
- package/dist/tui/model/theme-style.d.ts +10 -0
- package/dist/tui/model/theme-style.js +79 -0
- package/dist/{tui-ink → tui/model}/theme.d.ts +11 -23
- package/dist/{tui-ink → tui/model}/theme.js +23 -38
- package/dist/{tui-ink → tui/model}/trace-groups.d.ts +2 -0
- package/dist/{tui-ink → tui/model}/trace-groups.js +91 -30
- package/dist/tui/model/trace-interaction.d.ts +63 -0
- package/dist/tui/model/trace-interaction.js +87 -0
- package/dist/tui/model-picker-data.d.ts +1 -2
- package/dist/tui/model-picker-data.js +8 -1
- package/dist/tui/model-switch.js +2 -0
- package/dist/{tui-ink → tui}/run-session-picker.d.ts +2 -3
- package/dist/tui/run-session-picker.js +64 -0
- package/dist/tui/run.d.ts +72 -0
- package/dist/tui/run.js +139 -0
- package/dist/tui/terminal/multiplexer.d.ts +5 -0
- package/dist/tui/terminal/multiplexer.js +14 -0
- package/dist/tui/testing/fake-agent.d.ts +24 -0
- package/dist/tui/testing/fake-agent.js +22 -0
- package/dist/tui/testing/spy-host.d.ts +21 -0
- package/dist/tui/testing/spy-host.js +55 -0
- package/dist/tui/trace-groups.js +27 -6
- package/dist/types.d.ts +7 -0
- package/node_modules/@bubblebrain-ai/pi-tui/LICENSE +21 -0
- package/node_modules/@bubblebrain-ai/pi-tui/README.md +854 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts +26 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js +121 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts +86 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js +649 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts +13 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js +36 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts +22 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js +99 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts +22 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js +36 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts +330 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js +2344 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts +7 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js +43 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts +28 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js +82 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts +48 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js +390 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts +31 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js +67 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts +103 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js +797 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts +56 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js +179 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts +53 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js +175 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts +50 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js +174 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts +12 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js +22 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts +32 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js +109 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts +19 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js +81 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts +13 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js +48 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts +8 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js +26 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts +39 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js +2 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts +16 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js +110 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts +31 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js +42 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts +273 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js +231 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts +184 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js +1174 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts +28 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js +46 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts +10 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js +1268 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts +40 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js +6 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts +42 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js +335 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts +3 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js +60 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts +56 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js +363 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts +10 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js +59 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts +116 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js +518 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts +142 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js +544 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts +11 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js +11 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts +140 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js +1334 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts +39 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js +536 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts +338 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js +1016 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts +17 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js +27 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts +96 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js +1193 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts +25 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js +96 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts +73 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js +188 -0
- package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js.map +1 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/README.md +20 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/build.sh +62 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/src/darwin-modifiers.c +70 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/win32/README.md +22 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/win32/build.mjs +229 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/node_modules/@bubblebrain-ai/pi-tui/native/win32/src/win32-console-mode.c +119 -0
- package/node_modules/@bubblebrain-ai/pi-tui/package.json +66 -0
- package/node_modules/get-east-asian-width/index.d.ts +60 -0
- package/node_modules/get-east-asian-width/index.js +30 -0
- package/node_modules/get-east-asian-width/license +9 -0
- package/node_modules/get-east-asian-width/lookup-data.js +21 -0
- package/node_modules/get-east-asian-width/lookup.js +138 -0
- package/node_modules/get-east-asian-width/package.json +71 -0
- package/node_modules/get-east-asian-width/readme.md +65 -0
- package/node_modules/get-east-asian-width/utilities.js +24 -0
- package/package.json +23 -10
- package/packages/pi-tui/node_modules/marked/LICENSE +44 -0
- package/packages/pi-tui/node_modules/marked/README.md +115 -0
- package/packages/pi-tui/node_modules/marked/bin/main.js +284 -0
- package/packages/pi-tui/node_modules/marked/bin/marked.js +16 -0
- package/packages/pi-tui/node_modules/marked/lib/marked.d.ts +760 -0
- package/packages/pi-tui/node_modules/marked/lib/marked.esm.js +77 -0
- package/packages/pi-tui/node_modules/marked/lib/marked.esm.js.map +7 -0
- package/packages/pi-tui/node_modules/marked/lib/marked.umd.js +79 -0
- package/packages/pi-tui/node_modules/marked/lib/marked.umd.js.map +7 -0
- package/packages/pi-tui/node_modules/marked/man/marked.1 +113 -0
- package/packages/pi-tui/node_modules/marked/man/marked.1.md +93 -0
- package/packages/pi-tui/node_modules/marked/package.json +103 -0
- package/dist/tui-ink/app.d.ts +0 -76
- package/dist/tui-ink/app.js +0 -2377
- package/dist/tui-ink/approval/approval-dialog.d.ts +0 -13
- package/dist/tui-ink/approval/approval-dialog.js +0 -184
- package/dist/tui-ink/approval/diff-view.d.ts +0 -7
- package/dist/tui-ink/approval/diff-view.js +0 -44
- package/dist/tui-ink/approval/select.d.ts +0 -35
- package/dist/tui-ink/approval/select.js +0 -98
- package/dist/tui-ink/code-highlight.d.ts +0 -8
- package/dist/tui-ink/code-highlight.js +0 -121
- package/dist/tui-ink/command-palette.d.ts +0 -32
- package/dist/tui-ink/command-palette.js +0 -158
- package/dist/tui-ink/compaction-progress.d.ts +0 -19
- package/dist/tui-ink/compaction-progress.js +0 -74
- package/dist/tui-ink/detect-theme.d.ts +0 -1
- package/dist/tui-ink/detect-theme.js +0 -1
- package/dist/tui-ink/feedback-dialog.d.ts +0 -19
- package/dist/tui-ink/feedback-dialog.js +0 -133
- package/dist/tui-ink/feishu-setup-picker.d.ts +0 -5
- package/dist/tui-ink/feishu-setup-picker.js +0 -271
- package/dist/tui-ink/footer.d.ts +0 -26
- package/dist/tui-ink/footer.js +0 -51
- package/dist/tui-ink/input-box.d.ts +0 -189
- package/dist/tui-ink/input-box.js +0 -1279
- package/dist/tui-ink/input-history.d.ts +0 -1
- package/dist/tui-ink/input-history.js +0 -1
- package/dist/tui-ink/markdown.d.ts +0 -103
- package/dist/tui-ink/markdown.js +0 -747
- package/dist/tui-ink/message-list.d.ts +0 -49
- package/dist/tui-ink/message-list.js +0 -841
- package/dist/tui-ink/model-picker.d.ts +0 -143
- package/dist/tui-ink/model-picker.js +0 -966
- package/dist/tui-ink/plan-confirm.d.ts +0 -7
- package/dist/tui-ink/plan-confirm.js +0 -115
- package/dist/tui-ink/question-dialog.d.ts +0 -8
- package/dist/tui-ink/question-dialog.js +0 -135
- package/dist/tui-ink/rewind-picker.d.ts +0 -8
- package/dist/tui-ink/rewind-picker.js +0 -102
- package/dist/tui-ink/run-session-picker.js +0 -22
- package/dist/tui-ink/run.d.ts +0 -62
- package/dist/tui-ink/run.js +0 -103
- package/dist/tui-ink/session-picker.d.ts +0 -10
- package/dist/tui-ink/session-picker.js +0 -113
- package/dist/tui-ink/stats-panel.d.ts +0 -11
- package/dist/tui-ink/stats-panel.js +0 -65
- package/dist/tui-ink/subagent-inspector.d.ts +0 -21
- package/dist/tui-ink/subagent-inspector.js +0 -205
- package/dist/tui-ink/use-terminal-size.d.ts +0 -4
- package/dist/tui-ink/use-terminal-size.js +0 -48
- package/dist/tui-ink/waiting-indicator.d.ts +0 -12
- package/dist/tui-ink/waiting-indicator.js +0 -129
- package/dist/tui-ink/welcome.d.ts +0 -25
- package/dist/tui-ink/welcome.js +0 -88
- package/dist/tui-ink/wordmark.d.ts +0 -8
- package/dist/tui-ink/wordmark.js +0 -103
- /package/dist/{tui-ink → tui/model}/composer-buffer.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/display-history.js +0 -0
- /package/dist/{tui-ink → tui/model}/input-queue.js +0 -0
- /package/dist/{tui-ink → tui/model}/key-events.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/key-events.js +0 -0
- /package/dist/{tui-ink → tui/model}/paste-operation-tracker.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/paste-operation-tracker.js +0 -0
- /package/dist/{tui-ink → tui/model}/recent-activity.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/submit-dedupe.js +0 -0
- /package/dist/{tui-ink → tui/model}/sync-output.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/sync-output.js +0 -0
- /package/dist/{tui-ink → tui/model}/terminal-env.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/terminal-env.js +0 -0
- /package/dist/{tui-ink → tui/model}/terminal-mouse.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/terminal-mouse.js +0 -0
- /package/dist/{tui-ink → tui/model}/width.d.ts +0 -0
- /package/dist/{tui-ink → tui/model}/width.js +0 -0
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcript row renderer (Phase 5): DisplayMessage[] -> styled terminal
|
|
3
|
+
* rows. Pure — no pi-tui/Ink imports; the pi app feeds rows into Text
|
|
4
|
+
* components and unit tests assert the strings directly.
|
|
5
|
+
*
|
|
6
|
+
* Visual parity targets from the legacy renderer (message-list.tsx):
|
|
7
|
+
* - user message: highlighted card, '›' marker, vertical padding
|
|
8
|
+
* - assistant: plain wrapped text, blank-line separated
|
|
9
|
+
* - reasoning: dim, collapsed to one line unless expanded
|
|
10
|
+
* - tool calls: single-line trace with status glyph, name, arg preview,
|
|
11
|
+
* error result preview
|
|
12
|
+
* - synthetic rows (interrupt, compaction, notices) rendered as notices
|
|
13
|
+
*/
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import stringWidth from "string-width";
|
|
16
|
+
import { truncateVisual } from "../../text-display.js";
|
|
17
|
+
import { darkTheme } from "../model/theme.js";
|
|
18
|
+
import { themeBackground, themeDim, themeForeground } from "../model/theme-style.js";
|
|
19
|
+
import { buildTraceGroups, formatTracePath } from "../model/trace-groups.js";
|
|
20
|
+
import { splitImageDisplayContent } from "../image-display.js";
|
|
21
|
+
function toolTraceLabel(tool) {
|
|
22
|
+
return tool.name;
|
|
23
|
+
}
|
|
24
|
+
function plainProjection(rows) {
|
|
25
|
+
return {
|
|
26
|
+
rows: [...rows],
|
|
27
|
+
traceTargets: rows.map(() => undefined),
|
|
28
|
+
leadingSpacer: rows.length > 0 && stringWidth(rows[0] ?? "") === 0,
|
|
29
|
+
trailingSpacer: rows.length > 0 && stringWidth(rows.at(-1) ?? "") === 0,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function joinTranscriptProjections(blocks) {
|
|
33
|
+
const rows = [];
|
|
34
|
+
const traceTargets = [];
|
|
35
|
+
let leadingSpacer = false;
|
|
36
|
+
let trailingSpacer = false;
|
|
37
|
+
for (const block of blocks) {
|
|
38
|
+
let start = 0;
|
|
39
|
+
let end = block.rows.length;
|
|
40
|
+
while (start < end && block.rows[start] === "")
|
|
41
|
+
start += 1;
|
|
42
|
+
while (end > start && block.rows[end - 1] === "")
|
|
43
|
+
end -= 1;
|
|
44
|
+
if (start === end)
|
|
45
|
+
continue;
|
|
46
|
+
const blockHasLeadingSpacer = start === 0
|
|
47
|
+
? (block.leadingSpacer ?? stringWidth(block.rows[start] ?? "") === 0)
|
|
48
|
+
: stringWidth(block.rows[start] ?? "") === 0;
|
|
49
|
+
if (rows.length === 0)
|
|
50
|
+
leadingSpacer = blockHasLeadingSpacer;
|
|
51
|
+
const previousHasSpacer = rows.length > 0 && trailingSpacer;
|
|
52
|
+
if (rows.length > 0 && !previousHasSpacer && !blockHasLeadingSpacer) {
|
|
53
|
+
rows.push("");
|
|
54
|
+
traceTargets.push(undefined);
|
|
55
|
+
}
|
|
56
|
+
rows.push(...block.rows.slice(start, end));
|
|
57
|
+
traceTargets.push(...block.traceTargets.slice(start, end));
|
|
58
|
+
trailingSpacer = end === block.rows.length
|
|
59
|
+
? (block.trailingSpacer ?? stringWidth(block.rows[end - 1] ?? "") === 0)
|
|
60
|
+
: stringWidth(block.rows[end - 1] ?? "") === 0;
|
|
61
|
+
}
|
|
62
|
+
return { rows, traceTargets, leadingSpacer, trailingSpacer };
|
|
63
|
+
}
|
|
64
|
+
export function createTranscriptTheme(getTheme) {
|
|
65
|
+
return {
|
|
66
|
+
userBg: (text) => themeBackground(getTheme().userMessageBg, text),
|
|
67
|
+
userText: (text) => themeForeground(getTheme().userMessageText, text),
|
|
68
|
+
accent: (text) => themeForeground(getTheme().accent, text),
|
|
69
|
+
dim: (text) => themeDim(getTheme().dim, text),
|
|
70
|
+
error: (text) => themeForeground(getTheme().error, text),
|
|
71
|
+
success: (text) => themeForeground(getTheme().success, text),
|
|
72
|
+
hoverBorder: (text) => themeDim(getTheme().border, text),
|
|
73
|
+
selectionBorder: (text) => themeForeground(getTheme().border, text),
|
|
74
|
+
hoverBackground: (text) => themeBackground(getTheme().traceHoverBg, text),
|
|
75
|
+
selectionBackground: (text) => themeBackground(getTheme().traceSelectedBg, text),
|
|
76
|
+
imageChip: (text, active) => themeForeground(getTheme().inputText, themeBackground(active ? getTheme().traceSelectedBg : getTheme().backgroundElement, text)),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export const defaultTranscriptTheme = createTranscriptTheme(() => darkTheme);
|
|
80
|
+
const TRACE_BORDER_MIN_COLUMNS = 4;
|
|
81
|
+
const IMAGE_LABEL_SPACE_SENTINEL = "\uE000";
|
|
82
|
+
const TRACE_CONTENT_LEFT_PAD = 2;
|
|
83
|
+
const TRACE_RESERVED_COLUMNS = 4; // left border + content pad + right border
|
|
84
|
+
// Keep a zero-width row in projection joins without painting a terminal cell.
|
|
85
|
+
// The row exists in layout at rest, so hover can add corners without reflow.
|
|
86
|
+
const TRACE_IDLE_VPAD = "\x1b[0m";
|
|
87
|
+
/** Visible-width-preserving truncation (input is unstyled at this point). */
|
|
88
|
+
function truncateVisible(text, maxColumns) {
|
|
89
|
+
return truncateVisual(text, maxColumns);
|
|
90
|
+
}
|
|
91
|
+
export function renderUserCard(content, options, images = [], messageKey = "user") {
|
|
92
|
+
const theme = options.theme ?? defaultTranscriptTheme;
|
|
93
|
+
const terminalWidth = Math.max(1, Math.floor(options.columns));
|
|
94
|
+
// Leave two terminal cells unpainted. Painting the physical last column can
|
|
95
|
+
// trigger an automatic wrap in several terminals and leaves a broken bg
|
|
96
|
+
// patch at the right edge. At one or two columns there is no room to reserve
|
|
97
|
+
// that margin, so use every available cell.
|
|
98
|
+
const width = terminalWidth > 2 ? terminalWidth - 2 : terminalWidth;
|
|
99
|
+
// The normal card gutter is four cells (marker + trailing pad). On an
|
|
100
|
+
// extremely narrow terminal, degrade to a plain painted row; forcing the
|
|
101
|
+
// historical 20-column minimum is what made settled rows overflow after a
|
|
102
|
+
// 20x5 resize even though the live trace itself was width-safe.
|
|
103
|
+
if (width < 5) {
|
|
104
|
+
return wrapPlain(content, width).map((line) => theme.userBg(truncateVisible(line, width)));
|
|
105
|
+
}
|
|
106
|
+
const textWidth = width - 4; // " › " + trailing pad
|
|
107
|
+
const split = images.length > 0 ? splitImageDisplayContent(content) : undefined;
|
|
108
|
+
const body = split?.bodyLines.join("\n") ?? content;
|
|
109
|
+
// Preserve the label's visible width while preventing the generic word
|
|
110
|
+
// wrapper from splitting `[Image #1]` at its internal ASCII space.
|
|
111
|
+
const protectedBody = images.reduce((value, image) => value.replaceAll(image.label, image.label.replaceAll(" ", IMAGE_LABEL_SPACE_SENTINEL)), body);
|
|
112
|
+
const lines = body.length > 0
|
|
113
|
+
? wrapPlain(protectedBody, textWidth).map((line) => line.replaceAll(IMAGE_LABEL_SPACE_SENTINEL, " "))
|
|
114
|
+
: [];
|
|
115
|
+
if (split) {
|
|
116
|
+
for (const reference of split.referenceLines) {
|
|
117
|
+
if (images.some((image) => reference === `└ ${image.label}`))
|
|
118
|
+
lines.push(reference);
|
|
119
|
+
else
|
|
120
|
+
lines.push(...wrapPlain(reference, textWidth));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const rows = [];
|
|
124
|
+
const pad = " ".repeat(width);
|
|
125
|
+
rows.push(theme.userBg(pad));
|
|
126
|
+
lines.forEach((line, index) => {
|
|
127
|
+
// JS length/padEnd counts code units, not terminal cells: CJK characters
|
|
128
|
+
// occupy two columns. Visual padding prevents the line from overflowing,
|
|
129
|
+
// hard-wrapping, and resetting the painted background before the edge.
|
|
130
|
+
let renderedLine = line;
|
|
131
|
+
for (const image of images) {
|
|
132
|
+
if (!renderedLine.includes(image.label))
|
|
133
|
+
continue;
|
|
134
|
+
const groupKey = `image:${messageKey}:${image.label}`;
|
|
135
|
+
const chip = (theme.imageChip ?? ((text) => text))(image.label, options.traceInteraction?.isGroupHovered(groupKey) === true
|
|
136
|
+
|| options.traceInteraction?.isGroupSelected(groupKey) === true);
|
|
137
|
+
renderedLine = renderedLine.replace(image.label, chip);
|
|
138
|
+
}
|
|
139
|
+
const padded = `${renderedLine}${" ".repeat(Math.max(0, textWidth - stringWidth(renderedLine)))}`;
|
|
140
|
+
const filled = (index === 0 ? theme.accent(" › ") : " ") + theme.userText(padded) + " ";
|
|
141
|
+
rows.push(theme.userBg(filled));
|
|
142
|
+
});
|
|
143
|
+
// Keep the painted padding symmetric so the message body is vertically
|
|
144
|
+
// centered. Separation from the following trace belongs outside the card;
|
|
145
|
+
// removing only the bottom pad shifts every message down by half a row.
|
|
146
|
+
rows.push(theme.userBg(pad));
|
|
147
|
+
return rows;
|
|
148
|
+
}
|
|
149
|
+
function projectUserCard(message, options) {
|
|
150
|
+
const rows = renderUserCard(message.content, options, message.images ?? [], message.key ?? "user");
|
|
151
|
+
const targets = rows.map(() => undefined);
|
|
152
|
+
if (!message.images?.length)
|
|
153
|
+
return { rows, traceTargets: targets };
|
|
154
|
+
// User-card geometry is top padding + wrapped source lines + bottom padding.
|
|
155
|
+
// Inline chips retain their composer row; legacy reconstructed attachments
|
|
156
|
+
// may still occupy standalone reference rows.
|
|
157
|
+
for (let index = 0; index < message.images.length; index += 1) {
|
|
158
|
+
const image = message.images[index];
|
|
159
|
+
const row = rows.findIndex((line) => line.includes(image.label));
|
|
160
|
+
// At widths too narrow to show the complete atomic label, do not attach an
|
|
161
|
+
// action to an unrelated wrapped fragment.
|
|
162
|
+
if (row <= 0 || row >= rows.length - 1)
|
|
163
|
+
continue;
|
|
164
|
+
const messageKey = message.key ?? "user";
|
|
165
|
+
const groupKey = `image:${messageKey}:${image.label}`;
|
|
166
|
+
// The current interaction model is row-oriented. If multiple chips share
|
|
167
|
+
// one row, keep the first stable target rather than changing action order.
|
|
168
|
+
targets[row] ??= {
|
|
169
|
+
kind: "image",
|
|
170
|
+
key: groupKey,
|
|
171
|
+
groupKey,
|
|
172
|
+
imageLabel: image.label,
|
|
173
|
+
foldable: false,
|
|
174
|
+
action: { kind: "open-image", messageKey, imageLabel: image.label },
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return { rows, traceTargets: targets };
|
|
178
|
+
}
|
|
179
|
+
export function wrapPlain(text, columns) {
|
|
180
|
+
const out = [];
|
|
181
|
+
const splitToken = (token) => {
|
|
182
|
+
const chunks = [];
|
|
183
|
+
let chunk = "";
|
|
184
|
+
let width = 0;
|
|
185
|
+
for (const char of token) {
|
|
186
|
+
const charWidth = stringWidth(char);
|
|
187
|
+
if (chunk && width + charWidth > columns) {
|
|
188
|
+
chunks.push(chunk);
|
|
189
|
+
chunk = "";
|
|
190
|
+
width = 0;
|
|
191
|
+
}
|
|
192
|
+
chunk += char;
|
|
193
|
+
width += charWidth;
|
|
194
|
+
}
|
|
195
|
+
if (chunk)
|
|
196
|
+
chunks.push(chunk);
|
|
197
|
+
return chunks;
|
|
198
|
+
};
|
|
199
|
+
for (const paragraph of text.split("\n")) {
|
|
200
|
+
if (paragraph === "") {
|
|
201
|
+
out.push("");
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
let line = "";
|
|
205
|
+
for (const word of paragraph.split(/\s+/)) {
|
|
206
|
+
for (const chunk of splitToken(word)) {
|
|
207
|
+
const candidate = line ? `${line} ${chunk}` : chunk;
|
|
208
|
+
if (line && stringWidth(candidate) > columns) {
|
|
209
|
+
out.push(line);
|
|
210
|
+
line = chunk;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
line = candidate;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (line)
|
|
218
|
+
out.push(line);
|
|
219
|
+
}
|
|
220
|
+
return out;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Project assistant prose without transcript spacing. Live streaming and
|
|
224
|
+
* settled history both call this function, so completing a turn cannot change
|
|
225
|
+
* the answer gutter or wrapping width.
|
|
226
|
+
*/
|
|
227
|
+
export function projectAssistantRows(content, options) {
|
|
228
|
+
const terminalWidth = Math.max(1, Math.floor(options.columns));
|
|
229
|
+
const width = Math.max(1, terminalWidth - 2);
|
|
230
|
+
if (options.markdownRenderer) {
|
|
231
|
+
return options.markdownRenderer(content, width)
|
|
232
|
+
.map((row) => truncateVisible(row, terminalWidth));
|
|
233
|
+
}
|
|
234
|
+
return wrapPlain(content, width)
|
|
235
|
+
.map((row) => truncateVisible(row, terminalWidth));
|
|
236
|
+
}
|
|
237
|
+
export function renderAssistant(content, options) {
|
|
238
|
+
return [...projectAssistantRows(content, options), ""];
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Join reasoning, tool, and prose surfaces with one semantic separator.
|
|
242
|
+
* Individual projectors own only their visible rows; this composition layer
|
|
243
|
+
* owns vertical rhythm, so live and settled timelines cannot drift apart.
|
|
244
|
+
*/
|
|
245
|
+
export function joinTranscriptBlocks(blocks) {
|
|
246
|
+
const rows = [];
|
|
247
|
+
for (const block of blocks) {
|
|
248
|
+
let start = 0;
|
|
249
|
+
let end = block.length;
|
|
250
|
+
while (start < end && block[start] === "")
|
|
251
|
+
start += 1;
|
|
252
|
+
while (end > start && block[end - 1] === "")
|
|
253
|
+
end -= 1;
|
|
254
|
+
if (start === end)
|
|
255
|
+
continue;
|
|
256
|
+
if (rows.length > 0 && rows.at(-1) !== "")
|
|
257
|
+
rows.push("");
|
|
258
|
+
rows.push(...block.slice(start, end));
|
|
259
|
+
}
|
|
260
|
+
return rows;
|
|
261
|
+
}
|
|
262
|
+
/** Grok minimal mode keeps the same rolling reasoning surface live/settled. */
|
|
263
|
+
export const MINIMAL_REASONING_BODY_ROWS = 5;
|
|
264
|
+
/**
|
|
265
|
+
* Grok-style reasoning surface. Reasoning alone owns a one-cell rail; normal
|
|
266
|
+
* assistant prose never inherits this gutter. The same projection is used by
|
|
267
|
+
* the live row pool and committed transcript.
|
|
268
|
+
*/
|
|
269
|
+
export function projectReasoningRows(content, options, projection = {}) {
|
|
270
|
+
const theme = options.theme ?? defaultTranscriptTheme;
|
|
271
|
+
const columns = Math.max(1, Math.floor(options.columns));
|
|
272
|
+
const bodyWidth = Math.max(1, columns - 1);
|
|
273
|
+
const body = content
|
|
274
|
+
.split("\n")
|
|
275
|
+
.filter((line) => line.trim() !== "")
|
|
276
|
+
.flatMap((line) => wrapPlain(line, bodyWidth));
|
|
277
|
+
if (body.length === 0)
|
|
278
|
+
return [];
|
|
279
|
+
const limit = Math.max(0, projection.maxBodyRows ?? (options.showReasoning ? body.length : MINIMAL_REASONING_BODY_ROWS));
|
|
280
|
+
const fromEnd = projection.fromEnd ?? !options.showReasoning;
|
|
281
|
+
const visible = limit === 0
|
|
282
|
+
? []
|
|
283
|
+
: fromEnd
|
|
284
|
+
? body.slice(-limit)
|
|
285
|
+
: body.slice(0, limit);
|
|
286
|
+
const style = (text) => theme.dim(chalk.italic(text));
|
|
287
|
+
const rows = [style(truncateVisible(`┃◆ Thinking${projection.running ? "…" : ""}`, columns))];
|
|
288
|
+
for (const line of visible) {
|
|
289
|
+
rows.push(style(truncateVisible(`┃${line}`, columns)));
|
|
290
|
+
}
|
|
291
|
+
if (body.length > visible.length) {
|
|
292
|
+
const suffix = options.showReasoning ? "┃…" : "┃… (Ctrl+T to expand)";
|
|
293
|
+
rows.push(style(truncateVisible(suffix, columns)));
|
|
294
|
+
}
|
|
295
|
+
return rows;
|
|
296
|
+
}
|
|
297
|
+
export function renderReasoning(content, options) {
|
|
298
|
+
const rows = projectReasoningRows(content, options);
|
|
299
|
+
if (rows.length === 0)
|
|
300
|
+
return [];
|
|
301
|
+
rows.push("");
|
|
302
|
+
return rows;
|
|
303
|
+
}
|
|
304
|
+
function argPreview(tool) {
|
|
305
|
+
const args = tool.args;
|
|
306
|
+
const firstString = ["command", "path", "pattern", "file_path", "url", "query"].find((key) => typeof args?.[key] === "string");
|
|
307
|
+
if (firstString)
|
|
308
|
+
return String(args[firstString]);
|
|
309
|
+
const raw = Object.keys(args ?? {})[0];
|
|
310
|
+
return raw ? String(args[raw]).slice(0, 40) : "";
|
|
311
|
+
}
|
|
312
|
+
export function renderToolTrace(tool, options) {
|
|
313
|
+
const theme = options.theme ?? defaultTranscriptTheme;
|
|
314
|
+
const label = toolTraceLabel(tool) || tool.name;
|
|
315
|
+
const preview = argPreview(tool);
|
|
316
|
+
const columns = Math.max(1, Math.floor(options.columns));
|
|
317
|
+
const text = truncateVisible(`◆ ${label}${preview ? ` ${preview}` : ""}`, columns);
|
|
318
|
+
const parts = [tool.isError ? theme.error(text) : `${theme.accent("◆")}${text.slice(1)}`];
|
|
319
|
+
if (tool.isError && tool.result !== undefined && options.verboseTrace) {
|
|
320
|
+
const errPreview = String(tool.result).split("\n")[0] ?? "";
|
|
321
|
+
parts.push(`\n${theme.error(truncateVisible(` ↳ ${errPreview}`, columns))}`);
|
|
322
|
+
}
|
|
323
|
+
else if (!tool.isError && options.verboseTrace && tool.result !== undefined) {
|
|
324
|
+
const okPreview = String(tool.result).split("\n")[0] ?? "";
|
|
325
|
+
parts.push(`\n${theme.dim(truncateVisible(` ↳ ${okPreview}`, columns))}`);
|
|
326
|
+
}
|
|
327
|
+
return parts.join("");
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Render the same semantic trace groups used by the Ink TUI. This is shared
|
|
331
|
+
* by the live row pool and settled transcript so tool_start/tool_update/
|
|
332
|
+
* tool_end cannot change from a rich trace into an unrelated one-line row at
|
|
333
|
+
* the commit boundary.
|
|
334
|
+
*/
|
|
335
|
+
export function renderToolTraceGroups(toolCalls, options, renderOptions = {}) {
|
|
336
|
+
return projectToolTraceGroups(toolCalls, options, renderOptions).rows;
|
|
337
|
+
}
|
|
338
|
+
export function projectToolTraceGroups(toolCalls, options, renderOptions = {}) {
|
|
339
|
+
const groups = buildTraceGroups([...toolCalls]);
|
|
340
|
+
const rows = [];
|
|
341
|
+
const traceTargets = [];
|
|
342
|
+
// `showActivity` remains part of the call contract, but Grok expresses
|
|
343
|
+
// activity by mutating the tool entry itself (`running`) instead of adding
|
|
344
|
+
// a second Working heading with a different marker.
|
|
345
|
+
void renderOptions.showActivity;
|
|
346
|
+
for (const group of groups) {
|
|
347
|
+
const projected = projectTraceGroup(group, options);
|
|
348
|
+
rows.push(...projected.rows);
|
|
349
|
+
traceTargets.push(...projected.traceTargets);
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
rows,
|
|
353
|
+
traceTargets,
|
|
354
|
+
leadingSpacer: groups.length > 0,
|
|
355
|
+
trailingSpacer: groups.length > 0,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function projectTraceGroup(group, options) {
|
|
359
|
+
const theme = options.theme ?? defaultTranscriptTheme;
|
|
360
|
+
const columns = Math.max(1, options.columns);
|
|
361
|
+
const frameColumns = columns > 2 ? columns - 2 : columns;
|
|
362
|
+
const contentColumns = frameColumns >= TRACE_BORDER_MIN_COLUMNS
|
|
363
|
+
? Math.max(1, frameColumns - TRACE_RESERVED_COLUMNS)
|
|
364
|
+
: frameColumns;
|
|
365
|
+
const interaction = options.traceInteraction;
|
|
366
|
+
const groupKey = interaction?.groupKey(group);
|
|
367
|
+
const readInteraction = group.kind === "read" ? interaction : undefined;
|
|
368
|
+
const singleRead = readInteraction && groupKey && group.raw.length === 1 ? group.raw[0] : undefined;
|
|
369
|
+
const singleItemKey = singleRead && interaction ? interaction.itemKey(group, singleRead.id) : undefined;
|
|
370
|
+
const interactive = interaction !== undefined && groupKey !== undefined;
|
|
371
|
+
const groupFoldable = isTraceGroupFoldable(group);
|
|
372
|
+
const singleItemFoldable = singleRead ? isTraceItemFoldable(singleRead) : false;
|
|
373
|
+
const expanded = interactive
|
|
374
|
+
? singleItemKey
|
|
375
|
+
? interaction.isItemExpanded(singleItemKey)
|
|
376
|
+
: interaction.isGroupExpanded(groupKey)
|
|
377
|
+
: false;
|
|
378
|
+
const selected = interaction?.isSelected(singleItemKey ?? groupKey ?? "") ?? false;
|
|
379
|
+
const marker = expanded ? "⌄" : selected ? "›" : "◆";
|
|
380
|
+
const status = group.pending
|
|
381
|
+
? " running"
|
|
382
|
+
: group.statusLabel
|
|
383
|
+
? ` ${group.statusLabel}`
|
|
384
|
+
: group.hasError
|
|
385
|
+
? ` ${group.errorCount || 1} error${(group.errorCount || 1) === 1 ? "" : "s"}`
|
|
386
|
+
: "";
|
|
387
|
+
const detail = singleRead
|
|
388
|
+
? ` ${readTraceLabel(singleRead)}`
|
|
389
|
+
: group.description
|
|
390
|
+
? ` ${group.description}`
|
|
391
|
+
: group.command
|
|
392
|
+
? ` ${group.command.replace(/\s+/g, " ")}`
|
|
393
|
+
: group.count !== undefined && group.noun
|
|
394
|
+
? ` ${group.count} ${group.noun}`
|
|
395
|
+
: "";
|
|
396
|
+
const header = `${marker} ${group.title}${detail}${status}`;
|
|
397
|
+
const rows = [group.hasError
|
|
398
|
+
? theme.error(truncateVisible(header, contentColumns))
|
|
399
|
+
: `${theme.accent(marker)}${truncateVisible(header.slice(marker.length), Math.max(0, contentColumns - stringWidth(marker)))}`];
|
|
400
|
+
const subagentIds = group.kind === "subagent"
|
|
401
|
+
? group.raw[0]?.metadata?.subagents
|
|
402
|
+
?.map((member) => typeof member?.subAgentId === "string" ? member.subAgentId : "")
|
|
403
|
+
.filter(Boolean) ?? []
|
|
404
|
+
: [];
|
|
405
|
+
const groupAction = subagentIds.length === 1
|
|
406
|
+
? { kind: "open-subagent", subAgentId: subagentIds[0] }
|
|
407
|
+
: typeof group.raw[0]?.metadata?.taskId === "string"
|
|
408
|
+
? { kind: "open-task", taskId: group.raw[0].metadata.taskId }
|
|
409
|
+
: undefined;
|
|
410
|
+
const groupTarget = groupKey
|
|
411
|
+
? { kind: "group", key: groupKey, groupKey, foldable: groupFoldable, action: groupAction }
|
|
412
|
+
: undefined;
|
|
413
|
+
const singleTarget = singleItemKey && groupKey && singleRead
|
|
414
|
+
? { kind: "item", key: singleItemKey, groupKey, toolId: singleRead.id, foldable: singleItemFoldable }
|
|
415
|
+
: undefined;
|
|
416
|
+
const traceTargets = [singleTarget ?? groupTarget];
|
|
417
|
+
const finish = () => decorateTraceGroup({ rows, traceTargets }, singleTarget ?? groupTarget, groupKey, frameColumns, theme, interaction);
|
|
418
|
+
// Interactive Read groups follow Grok's scrollback model: the summary row
|
|
419
|
+
// is collapsed by default; double-click reveals member rows. Individual
|
|
420
|
+
// members then own their file preview fold without changing the whole group.
|
|
421
|
+
if (readInteraction && groupKey) {
|
|
422
|
+
if (singleRead && singleTarget) {
|
|
423
|
+
if (expanded)
|
|
424
|
+
appendReadPreview(rows, traceTargets, singleRead, singleTarget, contentColumns, theme, " ");
|
|
425
|
+
return finish();
|
|
426
|
+
}
|
|
427
|
+
if (!expanded)
|
|
428
|
+
return finish();
|
|
429
|
+
for (const tool of group.raw) {
|
|
430
|
+
const itemKey = readInteraction.itemKey(group, tool.id);
|
|
431
|
+
const itemExpanded = readInteraction.isItemExpanded(itemKey);
|
|
432
|
+
const itemSelected = readInteraction.isSelected(itemKey);
|
|
433
|
+
const itemMarker = itemExpanded ? "⌄" : itemSelected ? "›" : "◆";
|
|
434
|
+
const label = readTraceLabel(tool);
|
|
435
|
+
const itemText = truncateVisible(` ${itemMarker} ${label}`, contentColumns);
|
|
436
|
+
rows.push(tool.isError ? theme.error(itemText) : theme.dim(itemText));
|
|
437
|
+
const itemTarget = {
|
|
438
|
+
kind: "item",
|
|
439
|
+
key: itemKey,
|
|
440
|
+
groupKey,
|
|
441
|
+
toolId: tool.id,
|
|
442
|
+
foldable: isTraceItemFoldable(tool),
|
|
443
|
+
};
|
|
444
|
+
traceTargets.push(itemTarget);
|
|
445
|
+
if (itemExpanded) {
|
|
446
|
+
appendReadPreview(rows, traceTargets, tool, itemTarget, contentColumns, theme, " ");
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return finish();
|
|
450
|
+
}
|
|
451
|
+
// Grok tool blocks are collapsed by default. A single click selects the
|
|
452
|
+
// entry; a double-click reveals the detail surface only when the block has
|
|
453
|
+
// something meaningful to reveal. Failed List/Search blocks are deliberately
|
|
454
|
+
// non-foldable and keep their error detail visible in-place.
|
|
455
|
+
if (interactive && groupFoldable && !expanded)
|
|
456
|
+
return finish();
|
|
457
|
+
// While Execute is running, retain the command's own lines just like Ink.
|
|
458
|
+
// The header is only a summary and may be truncated on a narrow terminal.
|
|
459
|
+
const commandLines = group.commandLines ?? [];
|
|
460
|
+
const commandNeedsBlock = group.kind === "execute"
|
|
461
|
+
&& (!!group.description
|
|
462
|
+
|| commandLines.length > 1
|
|
463
|
+
|| stringWidth(`◆ ${group.title} ${group.command ?? ""}`) > contentColumns);
|
|
464
|
+
if (commandNeedsBlock) {
|
|
465
|
+
const wrappedCommand = commandLines.flatMap((line) => wrapPlain(line || " ", Math.max(1, contentColumns - 2)));
|
|
466
|
+
for (const line of wrappedCommand.slice(0, 4)) {
|
|
467
|
+
rows.push(theme.dim(truncateVisible(` ${line}`, contentColumns)));
|
|
468
|
+
traceTargets.push(groupTarget);
|
|
469
|
+
}
|
|
470
|
+
if (wrappedCommand.length > 4) {
|
|
471
|
+
rows.push(theme.dim(truncateVisible(` … ${wrappedCommand.length - 4} more lines`, contentColumns)));
|
|
472
|
+
traceTargets.push(groupTarget);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const collapseSuccessfulExecute = !interactive
|
|
476
|
+
&& group.kind === "execute"
|
|
477
|
+
&& !group.pending
|
|
478
|
+
&& !group.hasError
|
|
479
|
+
&& !options.verboseTrace;
|
|
480
|
+
const details = group.kind === "search"
|
|
481
|
+
? [...group.items, ...group.previewLines]
|
|
482
|
+
: group.previewLines.length > 0
|
|
483
|
+
? group.previewLines
|
|
484
|
+
: group.items;
|
|
485
|
+
if (collapseSuccessfulExecute) {
|
|
486
|
+
const outputLines = group.previewLines.length + group.omitted;
|
|
487
|
+
rows.push(theme.dim(truncateVisible(` ⎿ ${outputLines > 0
|
|
488
|
+
? `${outputLines} line${outputLines === 1 ? "" : "s"} output · Ctrl+O to view`
|
|
489
|
+
: "no output"}`, contentColumns)));
|
|
490
|
+
traceTargets.push(groupTarget);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
for (let index = 0; index < details.length; index += 1) {
|
|
494
|
+
const prefix = index === 0 ? " ↳ " : " ";
|
|
495
|
+
const line = truncateVisible(`${prefix}${details[index] ?? ""}`, contentColumns);
|
|
496
|
+
rows.push(group.hasError ? theme.error(line) : theme.dim(line));
|
|
497
|
+
traceTargets.push(groupTarget);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
for (let index = 0; index < group.errorLines.length; index += 1) {
|
|
501
|
+
const prefix = index === 0 ? " ↳ " : " ";
|
|
502
|
+
rows.push(theme.error(truncateVisible(`${prefix}${group.errorLines[index] ?? ""}`, contentColumns)));
|
|
503
|
+
traceTargets.push(groupTarget);
|
|
504
|
+
}
|
|
505
|
+
if (group.omitted > 0) {
|
|
506
|
+
rows.push(theme.dim(truncateVisible(` … ${group.omitted} more`, contentColumns)));
|
|
507
|
+
traceTargets.push(groupTarget);
|
|
508
|
+
}
|
|
509
|
+
return finish();
|
|
510
|
+
}
|
|
511
|
+
function decorateTraceGroup(projection, target, groupKey, columns, theme, interaction) {
|
|
512
|
+
const selected = groupKey !== undefined && interaction?.isGroupSelected(groupKey) === true;
|
|
513
|
+
const hovered = groupKey !== undefined
|
|
514
|
+
&& interaction?.isGroupHovered(groupKey) === true
|
|
515
|
+
&& !selected;
|
|
516
|
+
const active = selected || hovered;
|
|
517
|
+
const border = selected
|
|
518
|
+
? (theme.selectionBorder ?? theme.hoverBorder ?? theme.dim)
|
|
519
|
+
: (theme.hoverBorder ?? theme.dim);
|
|
520
|
+
const background = selected
|
|
521
|
+
? (theme.selectionBackground ?? theme.hoverBackground ?? ((text) => text))
|
|
522
|
+
: (theme.hoverBackground ?? ((text) => text));
|
|
523
|
+
if (columns < TRACE_BORDER_MIN_COLUMNS) {
|
|
524
|
+
return {
|
|
525
|
+
rows: [
|
|
526
|
+
TRACE_IDLE_VPAD,
|
|
527
|
+
...projection.rows.map((row) => {
|
|
528
|
+
if (!active)
|
|
529
|
+
return row;
|
|
530
|
+
const clipped = truncateVisible(row, columns);
|
|
531
|
+
return background(`${clipped}${" ".repeat(Math.max(0, columns - stringWidth(clipped)))}`);
|
|
532
|
+
}),
|
|
533
|
+
TRACE_IDLE_VPAD,
|
|
534
|
+
],
|
|
535
|
+
traceTargets: [target, ...projection.traceTargets, target],
|
|
536
|
+
leadingSpacer: true,
|
|
537
|
+
trailingSpacer: true,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
const top = active
|
|
541
|
+
? border(`┌${" ".repeat(columns - 2)}┐`)
|
|
542
|
+
: TRACE_IDLE_VPAD;
|
|
543
|
+
const bottom = active
|
|
544
|
+
? border(`└${" ".repeat(columns - 2)}┘`)
|
|
545
|
+
: TRACE_IDLE_VPAD;
|
|
546
|
+
const rows = projection.rows.map((row) => {
|
|
547
|
+
if (!active)
|
|
548
|
+
return `${" ".repeat(TRACE_CONTENT_LEFT_PAD + 1)}${row}`;
|
|
549
|
+
const interior = `${" ".repeat(TRACE_CONTENT_LEFT_PAD)}${row}`;
|
|
550
|
+
const padding = " ".repeat(Math.max(0, columns - 2 - stringWidth(interior)));
|
|
551
|
+
return `${border("│")}${background(`${interior}${padding}`)}${border("│")}`;
|
|
552
|
+
});
|
|
553
|
+
return {
|
|
554
|
+
rows: [top, ...rows, bottom],
|
|
555
|
+
traceTargets: [target, ...projection.traceTargets, target],
|
|
556
|
+
leadingSpacer: true,
|
|
557
|
+
trailingSpacer: true,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function isTraceItemFoldable(tool) {
|
|
561
|
+
return typeof tool.result === "string" && tool.result.trim().length > 0;
|
|
562
|
+
}
|
|
563
|
+
function isTraceGroupFoldable(group) {
|
|
564
|
+
switch (group.kind) {
|
|
565
|
+
case "read":
|
|
566
|
+
return group.raw.length > 1 || group.raw.some(isTraceItemFoldable);
|
|
567
|
+
case "list":
|
|
568
|
+
return !group.hasError && (group.items.length > 0 || group.omitted > 0);
|
|
569
|
+
case "search":
|
|
570
|
+
// Grok keeps successful Search entries foldable even for zero results so
|
|
571
|
+
// the expanded view can still reveal the query metadata / no-result state.
|
|
572
|
+
return !group.hasError;
|
|
573
|
+
case "execute":
|
|
574
|
+
return !!group.description
|
|
575
|
+
|| (group.commandLines?.length ?? 0) > 1
|
|
576
|
+
|| group.previewLines.length > 0
|
|
577
|
+
|| group.errorLines.length > 0
|
|
578
|
+
|| group.omitted > 0;
|
|
579
|
+
default:
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function readTraceLabel(tool) {
|
|
584
|
+
const value = tool.args.path ?? tool.args.file ?? tool.metadata?.path ?? argPreview(tool);
|
|
585
|
+
return formatTracePath(value || tool.name);
|
|
586
|
+
}
|
|
587
|
+
function appendReadPreview(rows, traceTargets, tool, target, columns, theme, indent) {
|
|
588
|
+
if (tool.result === undefined)
|
|
589
|
+
return;
|
|
590
|
+
const normalized = tool.result.replace(/\r\n/g, "\n");
|
|
591
|
+
const source = tool.name === "bash" && normalized.startsWith("stdout:\n")
|
|
592
|
+
? normalized.slice("stdout:\n".length)
|
|
593
|
+
: normalized;
|
|
594
|
+
const preview = source
|
|
595
|
+
.split("\n")
|
|
596
|
+
.filter((line) => line.trim() !== "")
|
|
597
|
+
.flatMap((line) => wrapPlain(line, Math.max(1, columns - indent.length)));
|
|
598
|
+
for (const line of preview.slice(0, 8)) {
|
|
599
|
+
rows.push((tool.isError ? theme.error : theme.dim)(truncateVisible(`${indent}${line}`, columns)));
|
|
600
|
+
traceTargets.push(target);
|
|
601
|
+
}
|
|
602
|
+
if (preview.length > 8) {
|
|
603
|
+
rows.push(theme.dim(truncateVisible(`${indent}… ${preview.length - 8} more lines`, columns)));
|
|
604
|
+
traceTargets.push(target);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Manual Compact keeps its terminal event deliberately terse, but the summary
|
|
609
|
+
* that replaced the old context remains inspectable. Treat the event as the
|
|
610
|
+
* same scrollback surface as a settled tool trace: hover/select paint the
|
|
611
|
+
* complete row and double-click folds the real summary in place.
|
|
612
|
+
*/
|
|
613
|
+
function projectCompactionSummary(message, options) {
|
|
614
|
+
const theme = options.theme ?? defaultTranscriptTheme;
|
|
615
|
+
const columns = Math.max(1, options.columns);
|
|
616
|
+
const frameColumns = columns > 2 ? columns - 2 : columns;
|
|
617
|
+
const contentColumns = frameColumns >= TRACE_BORDER_MIN_COLUMNS
|
|
618
|
+
? Math.max(1, frameColumns - TRACE_RESERVED_COLUMNS)
|
|
619
|
+
: frameColumns;
|
|
620
|
+
const interaction = options.traceInteraction;
|
|
621
|
+
const groupKey = `compact:${message.key ?? `${message.content}:${message.compactionSummary ?? ""}`}`;
|
|
622
|
+
const target = {
|
|
623
|
+
kind: "group",
|
|
624
|
+
key: groupKey,
|
|
625
|
+
groupKey,
|
|
626
|
+
foldable: true,
|
|
627
|
+
};
|
|
628
|
+
const expanded = interaction?.isGroupExpanded(groupKey) ?? false;
|
|
629
|
+
const selected = interaction?.isSelected(groupKey) ?? false;
|
|
630
|
+
const marker = expanded ? "⌄" : selected ? "›" : "◆";
|
|
631
|
+
const label = message.content.trim() || "Compaction completed.";
|
|
632
|
+
const header = `${marker} ${label}`;
|
|
633
|
+
const rows = [
|
|
634
|
+
`${theme.accent(marker)}${truncateVisible(header.slice(marker.length), Math.max(0, contentColumns - stringWidth(marker)))}`,
|
|
635
|
+
];
|
|
636
|
+
const traceTargets = [target];
|
|
637
|
+
if (expanded) {
|
|
638
|
+
const summary = message.compactionSummary?.trim() ?? "";
|
|
639
|
+
const bodyWidth = Math.max(1, contentColumns - 2);
|
|
640
|
+
const bodyRows = options.markdownRenderer
|
|
641
|
+
? options.markdownRenderer(summary, bodyWidth)
|
|
642
|
+
: wrapPlain(summary, bodyWidth);
|
|
643
|
+
for (const row of bodyRows) {
|
|
644
|
+
rows.push(theme.dim(truncateVisible(` ${row}`, contentColumns)));
|
|
645
|
+
traceTargets.push(target);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return decorateTraceGroup({ rows, traceTargets }, target, groupKey, frameColumns, theme, interaction);
|
|
649
|
+
}
|
|
650
|
+
export function renderMessage(message, options) {
|
|
651
|
+
return projectMessage(message, options).rows;
|
|
652
|
+
}
|
|
653
|
+
export function projectMessage(message, options) {
|
|
654
|
+
const theme = options.theme ?? defaultTranscriptTheme;
|
|
655
|
+
if (message.role === "user") {
|
|
656
|
+
return projectUserCard(message, options);
|
|
657
|
+
}
|
|
658
|
+
if (message.role === "error") {
|
|
659
|
+
return plainProjection([...projectAssistantRows(message.content, options).map(theme.error), ""]);
|
|
660
|
+
}
|
|
661
|
+
if (message.syntheticKind === "ui_compact_summary" && message.compactionSummary?.trim()) {
|
|
662
|
+
return projectCompactionSummary(message, options);
|
|
663
|
+
}
|
|
664
|
+
if (message.syntheticKind) {
|
|
665
|
+
return plainProjection([
|
|
666
|
+
...projectAssistantRows(message.content, { ...options, markdownRenderer: undefined }).map(theme.dim),
|
|
667
|
+
"",
|
|
668
|
+
]);
|
|
669
|
+
}
|
|
670
|
+
const blocks = [];
|
|
671
|
+
if (message.reasoning)
|
|
672
|
+
blocks.push(plainProjection(projectReasoningRows(message.reasoning, options)));
|
|
673
|
+
if (message.toolCalls?.length)
|
|
674
|
+
blocks.push(projectToolTraceGroups(message.toolCalls, options));
|
|
675
|
+
if (message.content?.trim())
|
|
676
|
+
blocks.push(plainProjection(projectAssistantRows(message.content, options)));
|
|
677
|
+
const projection = joinTranscriptProjections(blocks);
|
|
678
|
+
if (projection.rows.length === 0)
|
|
679
|
+
return plainProjection([""]);
|
|
680
|
+
projection.rows.push("");
|
|
681
|
+
projection.traceTargets.push(undefined);
|
|
682
|
+
projection.trailingSpacer = true;
|
|
683
|
+
return projection;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Render one assistant provider-turn as part of the surrounding user request.
|
|
687
|
+
*
|
|
688
|
+
* One agent run may contain many provider turns (`turn_end.willContinue`) —
|
|
689
|
+
* normally one before every tool call. Rendering every turn independently
|
|
690
|
+
* exposes the implementation boundary as `thinking → tool → thinking → tool`.
|
|
691
|
+
* The user-facing tool trace is grouped into one request lifecycle, while
|
|
692
|
+
* every provider turn's reasoning remains visible. Live rendering exposes
|
|
693
|
+
* each new reasoning segment, so suppressing later segments only after settle
|
|
694
|
+
* would create another disappear-at-finalize jump.
|
|
695
|
+
*
|
|
696
|
+
* Thinking
|
|
697
|
+
* ◆ tool
|
|
698
|
+
* Thinking (a later provider turn, if present)
|
|
699
|
+
* tool
|
|
700
|
+
* final answer
|
|
701
|
+
*
|
|
702
|
+
* Expanded mode still retains every reasoning segment for diagnostics.
|
|
703
|
+
*/
|
|
704
|
+
function projectAssistantInRequest(message, options) {
|
|
705
|
+
const blocks = [];
|
|
706
|
+
if (message.reasoning) {
|
|
707
|
+
blocks.push(plainProjection(projectReasoningRows(message.reasoning, options)));
|
|
708
|
+
}
|
|
709
|
+
const appendTools = (tools) => {
|
|
710
|
+
blocks.push(projectToolTraceGroups(tools, options));
|
|
711
|
+
};
|
|
712
|
+
// Preserve the model's real commentary/tool timeline. `parts` is the
|
|
713
|
+
// canonical ordered stream; the top-level fields are only the fallback for
|
|
714
|
+
// restored/legacy messages. Rendering toolCalls first and content second
|
|
715
|
+
// inverted commentary that was emitted before a tool call.
|
|
716
|
+
if (message.parts?.length) {
|
|
717
|
+
for (const part of message.parts) {
|
|
718
|
+
if (part.type === "tools") {
|
|
719
|
+
appendTools(part.toolCalls);
|
|
720
|
+
}
|
|
721
|
+
else if (part.content.trim()) {
|
|
722
|
+
blocks.push(plainProjection(projectAssistantRows(part.content, options)));
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
if (message.toolCalls?.length)
|
|
728
|
+
appendTools(message.toolCalls);
|
|
729
|
+
if (message.content?.trim())
|
|
730
|
+
blocks.push(plainProjection(projectAssistantRows(message.content, options)));
|
|
731
|
+
}
|
|
732
|
+
return joinTranscriptProjections(blocks);
|
|
733
|
+
}
|
|
734
|
+
export function renderTranscript(messages, options) {
|
|
735
|
+
return projectTranscript(messages, options).rows;
|
|
736
|
+
}
|
|
737
|
+
export function projectTranscript(messages, options) {
|
|
738
|
+
const messageBlocks = [];
|
|
739
|
+
for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
|
|
740
|
+
const message = messages[messageIndex];
|
|
741
|
+
let block;
|
|
742
|
+
if (message.role === "user") {
|
|
743
|
+
block = projectUserCard(message, options);
|
|
744
|
+
}
|
|
745
|
+
else if (message.role === "assistant" && !message.syntheticKind) {
|
|
746
|
+
block = projectAssistantInRequest(message, options);
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
block = projectMessage(message, options);
|
|
750
|
+
}
|
|
751
|
+
if (options.dimFromMessageIndex !== undefined && messageIndex >= options.dimFromMessageIndex) {
|
|
752
|
+
block = {
|
|
753
|
+
...block,
|
|
754
|
+
rows: block.rows.map((row) => row ? chalk.dim(row) : row),
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
messageBlocks.push(block);
|
|
758
|
+
}
|
|
759
|
+
const projection = joinTranscriptProjections(messageBlocks);
|
|
760
|
+
// The transcript owns the sole separator before a live assistant surface.
|
|
761
|
+
// When that surface settles, the same row becomes the transcript's trailing
|
|
762
|
+
// separator, so user -> Thinking geometry cannot change at commit time.
|
|
763
|
+
if (projection.rows.length === 0)
|
|
764
|
+
return projection;
|
|
765
|
+
if (options.trailingSpacer !== false) {
|
|
766
|
+
projection.rows.push("");
|
|
767
|
+
projection.traceTargets.push(undefined);
|
|
768
|
+
projection.trailingSpacer = true;
|
|
769
|
+
}
|
|
770
|
+
return projection;
|
|
771
|
+
}
|