@bubblebrain-ai/bubble 0.0.51 → 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 +80 -11
- package/dist/provider-transform.js +32 -4
- package/dist/provider.d.ts +6 -2
- package/dist/provider.js +100 -11
- 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
package/dist/tools/bash.d.ts
CHANGED
|
@@ -15,7 +15,9 @@ export interface BashToolOptions {
|
|
|
15
15
|
*/
|
|
16
16
|
processManager?: ProcessManager;
|
|
17
17
|
allowBackgroundTasks?: boolean;
|
|
18
|
-
/** Ctrl+
|
|
18
|
+
/** Ctrl+B send-to-background requests, keyed by toolCall id (design §2.5). */
|
|
19
19
|
promotionChannel?: PromotionChannel;
|
|
20
|
+
/** Move a still-running foreground command into Tasks after this budget. */
|
|
21
|
+
autoBackgroundAfterMs?: number | false;
|
|
20
22
|
}
|
|
21
23
|
export declare function createBashTool(cwd: string, approval?: ApprovalController, _fileState?: FileStateTracker, options?: BashToolOptions): ToolRegistryEntry;
|
package/dist/tools/bash.js
CHANGED
|
@@ -126,6 +126,7 @@ export function createBashTool(cwd, approval, _fileState, options = {}) {
|
|
|
126
126
|
let terminalError;
|
|
127
127
|
let resolved = false;
|
|
128
128
|
let timeoutHandle;
|
|
129
|
+
let autoBackgroundHandle;
|
|
129
130
|
let forceKillHandle;
|
|
130
131
|
let settleHandle;
|
|
131
132
|
let postExitHandle;
|
|
@@ -174,6 +175,8 @@ export function createBashTool(cwd, approval, _fileState, options = {}) {
|
|
|
174
175
|
const cleanup = () => {
|
|
175
176
|
if (timeoutHandle)
|
|
176
177
|
clearTimeout(timeoutHandle);
|
|
178
|
+
if (autoBackgroundHandle)
|
|
179
|
+
clearTimeout(autoBackgroundHandle);
|
|
177
180
|
if (forceKillHandle)
|
|
178
181
|
clearTimeout(forceKillHandle);
|
|
179
182
|
if (settleHandle)
|
|
@@ -208,7 +211,7 @@ export function createBashTool(cwd, approval, _fileState, options = {}) {
|
|
|
208
211
|
resolved = true;
|
|
209
212
|
cleanup();
|
|
210
213
|
if (terminal === "promoted") {
|
|
211
|
-
// Ctrl+
|
|
214
|
+
// Ctrl+B/automatic promotion (design §2.5): the process lives on under the
|
|
212
215
|
// task manager — skip the group kill AND the stream destruction
|
|
213
216
|
// (the manager attached its own data listeners in adoptTask).
|
|
214
217
|
resolve({
|
|
@@ -347,7 +350,7 @@ export function createBashTool(cwd, approval, _fileState, options = {}) {
|
|
|
347
350
|
terminal = "exit";
|
|
348
351
|
finish();
|
|
349
352
|
};
|
|
350
|
-
// Ctrl+
|
|
353
|
+
// Ctrl+B/automatic promotion (design §2.5): flag-flip into the task manager.
|
|
351
354
|
// Registered only for background-capable hosts; a no-op once any
|
|
352
355
|
// terminal state is set (benign race with exit/timeout/cancel).
|
|
353
356
|
const promoteToBackground = () => {
|
|
@@ -381,6 +384,14 @@ export function createBashTool(cwd, approval, _fileState, options = {}) {
|
|
|
381
384
|
if (backgroundEnabled && options.promotionChannel && ctx.toolCall?.id) {
|
|
382
385
|
unregisterPromotion = options.promotionChannel.register(ctx.toolCall.id, promoteToBackground);
|
|
383
386
|
}
|
|
387
|
+
if (backgroundEnabled
|
|
388
|
+
&& options.autoBackgroundAfterMs !== false
|
|
389
|
+
&& typeof options.autoBackgroundAfterMs === "number"
|
|
390
|
+
&& options.autoBackgroundAfterMs > 0
|
|
391
|
+
&& options.autoBackgroundAfterMs < timeoutSec * 1000) {
|
|
392
|
+
autoBackgroundHandle = setTimeout(promoteToBackground, options.autoBackgroundAfterMs);
|
|
393
|
+
autoBackgroundHandle.unref?.();
|
|
394
|
+
}
|
|
384
395
|
timeoutHandle = setTimeout(timeoutChild, timeoutSec * 1000);
|
|
385
396
|
if (ctx.abortSignal?.aborted)
|
|
386
397
|
abortChild();
|
package/dist/tools/grep.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Grep tool -
|
|
2
|
+
* Grep tool - bounded, streaming search using ripgrep.
|
|
3
|
+
*
|
|
4
|
+
* The limits in this file are model-context safety boundaries, not UI-only
|
|
5
|
+
* truncation. We stop rg as soon as a global budget is filled so a repository
|
|
6
|
+
* search can never materialize a multi-megabyte tool result in memory/history.
|
|
3
7
|
*/
|
|
4
8
|
import type { ToolRegistryEntry } from "../types.js";
|
|
5
9
|
export declare function createGrepTool(cwd: string): ToolRegistryEntry;
|
package/dist/tools/grep.js
CHANGED
|
@@ -1,30 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Grep tool -
|
|
2
|
+
* Grep tool - bounded, streaming search using ripgrep.
|
|
3
|
+
*
|
|
4
|
+
* The limits in this file are model-context safety boundaries, not UI-only
|
|
5
|
+
* truncation. We stop rg as soon as a global budget is filled so a repository
|
|
6
|
+
* search can never materialize a multi-megabyte tool result in memory/history.
|
|
3
7
|
*/
|
|
4
|
-
import {
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
5
9
|
import { resolve as resolvePath } from "node:path";
|
|
10
|
+
import { StringDecoder } from "node:string_decoder";
|
|
6
11
|
import { isSensitivePath } from "./sensitive-paths.js";
|
|
7
12
|
import { analyzeToolIntent } from "../agent/tool-intent.js";
|
|
8
13
|
import { resolveToolPath } from "./path-utils.js";
|
|
9
|
-
const
|
|
14
|
+
const DEFAULT_MATCH_LIMIT = 100;
|
|
15
|
+
const MAX_MATCH_LIMIT = 1_000;
|
|
16
|
+
const MAX_RENDERED_LINE_CODE_POINTS = 1_000;
|
|
17
|
+
const MAX_RESULT_BYTES = 40 * 1024;
|
|
18
|
+
const MAX_RAW_STDOUT_BYTES = 5 * 1024 * 1024;
|
|
19
|
+
const MAX_STDERR_BYTES = 64 * 1024;
|
|
20
|
+
const MAX_FILE_SIZE = "5M";
|
|
21
|
+
const MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
22
|
+
const GREP_TIMEOUT_MS = 30_000;
|
|
23
|
+
const KILL_GRACE_MS = 250;
|
|
24
|
+
const RESULT_NOTICE_RESERVE_BYTES = 1_024;
|
|
10
25
|
export function createGrepTool(cwd) {
|
|
11
26
|
return {
|
|
12
27
|
name: "grep",
|
|
13
28
|
readOnly: true,
|
|
14
29
|
effect: "read",
|
|
15
|
-
description:
|
|
30
|
+
description: [
|
|
31
|
+
"Search file contents using regex (via ripgrep).",
|
|
32
|
+
`Returns at most ${DEFAULT_MATCH_LIMIT} matches by default (explicit limit is capped at ${MAX_MATCH_LIMIT}),`,
|
|
33
|
+
`${MAX_RESULT_BYTES / 1024}KiB total, and ${MAX_RENDERED_LINE_CODE_POINTS} Unicode characters per rendered match.`,
|
|
34
|
+
`Files larger than ${MAX_FILE_SIZE} are skipped. Narrow path/glob/pattern when a result is marked truncated.`,
|
|
35
|
+
].join(" "),
|
|
16
36
|
parameters: {
|
|
17
37
|
type: "object",
|
|
18
38
|
properties: {
|
|
19
39
|
pattern: { type: "string", description: "Regex pattern to search for" },
|
|
20
40
|
path: { type: "string", description: "Directory or file to search in (optional, default: cwd)" },
|
|
21
41
|
glob: { type: "string", description: "Glob pattern to filter files (optional, e.g. '*.ts')" },
|
|
42
|
+
limit: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: `Maximum matches to return (default ${DEFAULT_MATCH_LIMIT}, hard maximum ${MAX_MATCH_LIMIT})`,
|
|
45
|
+
},
|
|
22
46
|
},
|
|
23
47
|
required: ["pattern"],
|
|
24
48
|
},
|
|
25
|
-
async execute(args) {
|
|
49
|
+
async execute(args, ctx) {
|
|
26
50
|
const searchPath = args.path ? resolveToolPath(cwd, args.path) : cwd;
|
|
27
51
|
const pattern = String(args.pattern);
|
|
52
|
+
const matchLimit = normalizeMatchLimit(args.limit);
|
|
28
53
|
const intent = analyzeToolIntent({
|
|
29
54
|
name: "grep",
|
|
30
55
|
parsedArgs: {
|
|
@@ -48,72 +73,296 @@ export function createGrepTool(cwd) {
|
|
|
48
73
|
},
|
|
49
74
|
};
|
|
50
75
|
}
|
|
51
|
-
const rgArgs = [
|
|
52
|
-
|
|
76
|
+
const rgArgs = [
|
|
77
|
+
"--json",
|
|
78
|
+
"--line-number",
|
|
79
|
+
"--color=never",
|
|
80
|
+
"--max-columns",
|
|
81
|
+
String(MAX_RENDERED_LINE_CODE_POINTS),
|
|
82
|
+
"--max-columns-preview",
|
|
83
|
+
"--max-filesize",
|
|
84
|
+
MAX_FILE_SIZE,
|
|
85
|
+
];
|
|
86
|
+
if (args.glob)
|
|
53
87
|
rgArgs.push("--glob", String(args.glob));
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
matchedPaths.add(resolvePath(cwd, path));
|
|
71
|
-
}
|
|
72
|
-
matches.push(`${path}:${lineNum}: ${text}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
// ignore parse errors
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (matches.length === 0) {
|
|
80
|
-
resolve({
|
|
81
|
-
content: "No matches found.",
|
|
82
|
-
status: "no_match",
|
|
83
|
-
metadata: {
|
|
84
|
-
kind: "search",
|
|
85
|
-
path: searchPath,
|
|
86
|
-
pattern,
|
|
87
|
-
matches: 0,
|
|
88
|
-
truncated: false,
|
|
89
|
-
searchSignature: intent.search?.signature,
|
|
90
|
-
searchFamily: intent.search?.familyKey,
|
|
91
|
-
paths: [],
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
let output = matches.join("\n");
|
|
97
|
-
const truncated = matches.length >= MAX_MATCHES;
|
|
98
|
-
if (matches.length >= MAX_MATCHES) {
|
|
99
|
-
output += `\n[More than ${MAX_MATCHES} matches, output truncated]`;
|
|
100
|
-
}
|
|
101
|
-
resolve({
|
|
102
|
-
content: output,
|
|
103
|
-
status: truncated ? "partial" : "success",
|
|
104
|
-
metadata: {
|
|
105
|
-
kind: "search",
|
|
106
|
-
path: searchPath,
|
|
107
|
-
pattern,
|
|
108
|
-
matches: matches.length,
|
|
109
|
-
truncated,
|
|
110
|
-
searchSignature: intent.search?.signature,
|
|
111
|
-
searchFamily: intent.search?.familyKey,
|
|
112
|
-
paths: [...matchedPaths],
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
});
|
|
88
|
+
rgArgs.push("--", pattern, searchPath);
|
|
89
|
+
return executeBoundedGrep({
|
|
90
|
+
cwd,
|
|
91
|
+
searchPath,
|
|
92
|
+
pattern,
|
|
93
|
+
rgArgs,
|
|
94
|
+
matchLimit,
|
|
95
|
+
abortSignal: ctx.abortSignal,
|
|
96
|
+
baseMetadata: {
|
|
97
|
+
kind: "search",
|
|
98
|
+
path: searchPath,
|
|
99
|
+
pattern,
|
|
100
|
+
searchSignature: intent.search?.signature,
|
|
101
|
+
searchFamily: intent.search?.familyKey,
|
|
102
|
+
maxFileSizeBytes: MAX_FILE_SIZE_BYTES,
|
|
103
|
+
},
|
|
116
104
|
});
|
|
117
105
|
},
|
|
118
106
|
};
|
|
119
107
|
}
|
|
108
|
+
function executeBoundedGrep(options) {
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
const child = spawn("rg", options.rgArgs, {
|
|
111
|
+
cwd: options.cwd,
|
|
112
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
113
|
+
});
|
|
114
|
+
const decoder = new StringDecoder("utf8");
|
|
115
|
+
const matches = [];
|
|
116
|
+
let stdoutBuffer = "";
|
|
117
|
+
let stdoutBytes = 0;
|
|
118
|
+
let stderrBytes = 0;
|
|
119
|
+
let stderr = "";
|
|
120
|
+
let stopReason;
|
|
121
|
+
let spawnError;
|
|
122
|
+
let settled = false;
|
|
123
|
+
let killTimer;
|
|
124
|
+
const requestStop = (reason) => {
|
|
125
|
+
if (stopReason)
|
|
126
|
+
return;
|
|
127
|
+
stopReason = reason;
|
|
128
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
129
|
+
child.kill("SIGTERM");
|
|
130
|
+
killTimer = setTimeout(() => {
|
|
131
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
132
|
+
child.kill("SIGKILL");
|
|
133
|
+
}, KILL_GRACE_MS);
|
|
134
|
+
killTimer.unref?.();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const processJsonLine = (line) => {
|
|
138
|
+
if (!line.trim() || stopReason)
|
|
139
|
+
return;
|
|
140
|
+
try {
|
|
141
|
+
const event = JSON.parse(line);
|
|
142
|
+
if (event.type !== "match")
|
|
143
|
+
return;
|
|
144
|
+
const rawPath = decodeRgField(event.data?.path);
|
|
145
|
+
const lineNumber = event.data?.line_number;
|
|
146
|
+
const rawText = decodeRgField(event.data?.lines, "[non-UTF-8 match bytes omitted]") ?? "";
|
|
147
|
+
const displayPath = rawPath || "<non-UTF-8 path>";
|
|
148
|
+
const normalizedText = rawText.replace(/\r\n/g, "\n").replace(/\r/g, "").replace(/\n$/, "");
|
|
149
|
+
const rendered = truncateCodePoints(`${displayPath}:${typeof lineNumber === "number" ? lineNumber : "?"}: ${normalizedText}`, MAX_RENDERED_LINE_CODE_POINTS);
|
|
150
|
+
matches.push({
|
|
151
|
+
rendered,
|
|
152
|
+
...(rawPath ? { absolutePath: resolvePath(options.cwd, rawPath) } : {}),
|
|
153
|
+
});
|
|
154
|
+
// We stop at N rather than pretending we proved there are N+1 matches.
|
|
155
|
+
// The notice says "limit reached / may be incomplete", which is honest
|
|
156
|
+
// even for the exact-fit case and avoids continuing a huge tree walk.
|
|
157
|
+
if (matches.length >= options.matchLimit)
|
|
158
|
+
requestStop("match_limit");
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// A truncated/invalid JSON event is not useful to the model. Raw byte
|
|
162
|
+
// accounting remains authoritative and will stop pathological lines.
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const processDecodedText = (text) => {
|
|
166
|
+
stdoutBuffer += text;
|
|
167
|
+
while (!stopReason) {
|
|
168
|
+
const newline = stdoutBuffer.indexOf("\n");
|
|
169
|
+
if (newline < 0)
|
|
170
|
+
break;
|
|
171
|
+
const line = stdoutBuffer.slice(0, newline);
|
|
172
|
+
stdoutBuffer = stdoutBuffer.slice(newline + 1);
|
|
173
|
+
processJsonLine(line);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
child.stdout.on("data", (value) => {
|
|
177
|
+
if (stopReason)
|
|
178
|
+
return;
|
|
179
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
180
|
+
const remaining = Math.max(0, MAX_RAW_STDOUT_BYTES - stdoutBytes);
|
|
181
|
+
const accepted = chunk.subarray(0, remaining);
|
|
182
|
+
stdoutBytes += accepted.length;
|
|
183
|
+
if (accepted.length > 0)
|
|
184
|
+
processDecodedText(decoder.write(accepted));
|
|
185
|
+
if (accepted.length < chunk.length || stdoutBytes >= MAX_RAW_STDOUT_BYTES) {
|
|
186
|
+
requestStop("stdout_limit");
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
child.stdout.on("end", () => {
|
|
190
|
+
if (stopReason)
|
|
191
|
+
return;
|
|
192
|
+
processDecodedText(decoder.end());
|
|
193
|
+
if (stdoutBuffer) {
|
|
194
|
+
processJsonLine(stdoutBuffer);
|
|
195
|
+
stdoutBuffer = "";
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
child.stderr.on("data", (value) => {
|
|
199
|
+
if (stopReason)
|
|
200
|
+
return;
|
|
201
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
202
|
+
const remaining = Math.max(0, MAX_STDERR_BYTES - stderrBytes);
|
|
203
|
+
const accepted = chunk.subarray(0, remaining);
|
|
204
|
+
stderrBytes += accepted.length;
|
|
205
|
+
if (accepted.length > 0)
|
|
206
|
+
stderr += accepted.toString("utf8");
|
|
207
|
+
if (accepted.length < chunk.length || stderrBytes >= MAX_STDERR_BYTES) {
|
|
208
|
+
requestStop("stderr_limit");
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const timeout = setTimeout(() => requestStop("timeout"), GREP_TIMEOUT_MS);
|
|
212
|
+
timeout.unref?.();
|
|
213
|
+
const onAbort = () => requestStop("aborted");
|
|
214
|
+
options.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
215
|
+
if (options.abortSignal?.aborted)
|
|
216
|
+
onAbort();
|
|
217
|
+
child.on("error", (error) => {
|
|
218
|
+
spawnError = error;
|
|
219
|
+
});
|
|
220
|
+
child.on("close", (code) => {
|
|
221
|
+
if (settled)
|
|
222
|
+
return;
|
|
223
|
+
settled = true;
|
|
224
|
+
clearTimeout(timeout);
|
|
225
|
+
if (killTimer)
|
|
226
|
+
clearTimeout(killTimer);
|
|
227
|
+
options.abortSignal?.removeEventListener("abort", onAbort);
|
|
228
|
+
if (stopReason === "aborted") {
|
|
229
|
+
resolve({
|
|
230
|
+
content: "Search cancelled.",
|
|
231
|
+
isError: true,
|
|
232
|
+
status: "cancelled",
|
|
233
|
+
metadata: { ...options.baseMetadata, matches: 0, truncated: false, paths: [] },
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (spawnError) {
|
|
238
|
+
resolve({
|
|
239
|
+
content: `Error calling grep: ${spawnError.message}`,
|
|
240
|
+
isError: true,
|
|
241
|
+
status: "command_error",
|
|
242
|
+
metadata: { ...options.baseMetadata, matches: 0, truncated: false, paths: [] },
|
|
243
|
+
});
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const naturalCommandError = !stopReason && code !== 0 && code !== 1;
|
|
247
|
+
const stoppedWithoutMatches = !!stopReason && matches.length === 0;
|
|
248
|
+
if (matches.length === 0 && !stoppedWithoutMatches && !naturalCommandError) {
|
|
249
|
+
resolve({
|
|
250
|
+
content: "No matches found.",
|
|
251
|
+
status: "no_match",
|
|
252
|
+
metadata: { ...options.baseMetadata, matches: 0, truncated: false, paths: [] },
|
|
253
|
+
});
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (naturalCommandError && matches.length === 0) {
|
|
257
|
+
resolve({
|
|
258
|
+
content: `Error calling grep: ${stderr.trim() || `ripgrep exited with code ${code}`}`,
|
|
259
|
+
isError: true,
|
|
260
|
+
status: "command_error",
|
|
261
|
+
metadata: { ...options.baseMetadata, matches: 0, truncated: false, paths: [] },
|
|
262
|
+
});
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const formatted = formatMatches(matches, options.matchLimit, stopReason, naturalCommandError ? stderr.trim() : "");
|
|
266
|
+
const truncated = !!stopReason || formatted.byteTruncated || naturalCommandError;
|
|
267
|
+
const paths = [...new Set(formatted.emittedMatches.flatMap((match) => match.absolutePath ? [match.absolutePath] : []))];
|
|
268
|
+
resolve({
|
|
269
|
+
content: formatted.content,
|
|
270
|
+
...(naturalCommandError && matches.length === 0 ? { isError: true } : {}),
|
|
271
|
+
status: stopReason === "timeout" && matches.length === 0
|
|
272
|
+
? "timeout"
|
|
273
|
+
: truncated
|
|
274
|
+
? "partial"
|
|
275
|
+
: "success",
|
|
276
|
+
metadata: {
|
|
277
|
+
...options.baseMetadata,
|
|
278
|
+
matches: formatted.emittedMatches.length,
|
|
279
|
+
collectedMatches: matches.length,
|
|
280
|
+
truncated,
|
|
281
|
+
truncationReason: stopReason ?? (formatted.byteTruncated ? "result_bytes" : naturalCommandError ? "command_error" : undefined),
|
|
282
|
+
rawStdoutBytes: stdoutBytes,
|
|
283
|
+
paths,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function formatMatches(matches, matchLimit, stopReason, commandWarning) {
|
|
290
|
+
const emitted = [];
|
|
291
|
+
let bodyBytes = 0;
|
|
292
|
+
const bodyBudget = MAX_RESULT_BYTES - RESULT_NOTICE_RESERVE_BYTES;
|
|
293
|
+
for (const match of matches) {
|
|
294
|
+
const lineBytes = Buffer.byteLength(match.rendered, "utf8") + (emitted.length > 0 ? 1 : 0);
|
|
295
|
+
if (bodyBytes + lineBytes > bodyBudget)
|
|
296
|
+
break;
|
|
297
|
+
emitted.push(match);
|
|
298
|
+
bodyBytes += lineBytes;
|
|
299
|
+
}
|
|
300
|
+
const byteTruncated = emitted.length < matches.length;
|
|
301
|
+
const notices = [];
|
|
302
|
+
if (stopReason === "match_limit") {
|
|
303
|
+
notices.push(`Search stopped after reaching the global limit of ${matchLimit} matches; results may be incomplete. Narrow path/glob/pattern to continue.`);
|
|
304
|
+
}
|
|
305
|
+
else if (stopReason === "stdout_limit") {
|
|
306
|
+
notices.push(`Raw ripgrep output reached ${formatBytes(MAX_RAW_STDOUT_BYTES)}; results are incomplete. Narrow the search.`);
|
|
307
|
+
}
|
|
308
|
+
else if (stopReason === "stderr_limit") {
|
|
309
|
+
notices.push(`ripgrep diagnostics reached ${formatBytes(MAX_STDERR_BYTES)}; results are incomplete.`);
|
|
310
|
+
}
|
|
311
|
+
else if (stopReason === "timeout") {
|
|
312
|
+
notices.push(`Search timed out after ${GREP_TIMEOUT_MS / 1000}s; results are incomplete. Narrow the search.`);
|
|
313
|
+
}
|
|
314
|
+
if (byteTruncated) {
|
|
315
|
+
notices.push(`Showing ${emitted.length} of ${matches.length} collected matches because tool output is capped at ${formatBytes(MAX_RESULT_BYTES)}.`);
|
|
316
|
+
}
|
|
317
|
+
if (commandWarning)
|
|
318
|
+
notices.push(`ripgrep also reported: ${truncateCodePoints(commandWarning, 300)}`);
|
|
319
|
+
let content = emitted.map((match) => match.rendered).join("\n");
|
|
320
|
+
if (notices.length > 0)
|
|
321
|
+
content += `${content ? "\n" : ""}[${notices.join(" ")}]`;
|
|
322
|
+
// The reserve above normally guarantees this. Keep an exact byte backstop so
|
|
323
|
+
// future notice copy cannot accidentally violate the model-facing contract.
|
|
324
|
+
if (Buffer.byteLength(content, "utf8") > MAX_RESULT_BYTES) {
|
|
325
|
+
content = truncateUtf8Prefix(content, MAX_RESULT_BYTES);
|
|
326
|
+
}
|
|
327
|
+
return { content, emittedMatches: emitted, byteTruncated };
|
|
328
|
+
}
|
|
329
|
+
function normalizeMatchLimit(value) {
|
|
330
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
331
|
+
return DEFAULT_MATCH_LIMIT;
|
|
332
|
+
return Math.min(MAX_MATCH_LIMIT, Math.max(1, Math.floor(value)));
|
|
333
|
+
}
|
|
334
|
+
function decodeRgField(value, invalidBytesFallback) {
|
|
335
|
+
if (!value || typeof value !== "object")
|
|
336
|
+
return undefined;
|
|
337
|
+
const record = value;
|
|
338
|
+
if (typeof record.text === "string")
|
|
339
|
+
return record.text;
|
|
340
|
+
if (typeof record.bytes === "string") {
|
|
341
|
+
try {
|
|
342
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(Buffer.from(record.bytes, "base64"));
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return invalidBytesFallback;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
function truncateCodePoints(value, maxCodePoints) {
|
|
351
|
+
const points = Array.from(value);
|
|
352
|
+
if (points.length <= maxCodePoints)
|
|
353
|
+
return value;
|
|
354
|
+
const marker = "... [truncated]";
|
|
355
|
+
return `${points.slice(0, Math.max(0, maxCodePoints - Array.from(marker).length)).join("")}${marker}`;
|
|
356
|
+
}
|
|
357
|
+
function truncateUtf8Prefix(value, maxBytes) {
|
|
358
|
+
const bytes = Buffer.from(value, "utf8");
|
|
359
|
+
if (bytes.length <= maxBytes)
|
|
360
|
+
return value;
|
|
361
|
+
let end = maxBytes;
|
|
362
|
+
while (end > 0 && (bytes[end] & 0xc0) === 0x80)
|
|
363
|
+
end -= 1;
|
|
364
|
+
return bytes.subarray(0, end).toString("utf8");
|
|
365
|
+
}
|
|
366
|
+
function formatBytes(bytes) {
|
|
367
|
+
return bytes % 1024 === 0 ? `${bytes / 1024}KiB` : `${bytes} bytes`;
|
|
368
|
+
}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -55,7 +55,9 @@ export interface CreateAllToolsOptions {
|
|
|
55
55
|
*/
|
|
56
56
|
processManager?: ProcessManager;
|
|
57
57
|
allowBackgroundTasks?: boolean;
|
|
58
|
-
/** Ctrl+
|
|
58
|
+
/** Ctrl+B send-to-background requests from the TUI (design §2.5). */
|
|
59
59
|
promotionChannel?: PromotionChannel;
|
|
60
|
+
/** Grok-style foreground wait budget before a Bash Execute is demoted. */
|
|
61
|
+
autoBackgroundAfterMs?: number | false;
|
|
60
62
|
}
|
|
61
63
|
export declare function createAllTools(cwd: string, skillRegistry?: SkillRegistry, options?: CreateAllToolsOptions): ToolRegistryEntry[];
|
package/dist/tools/index.js
CHANGED
|
@@ -51,6 +51,7 @@ export function createAllTools(cwd, skillRegistry, options = {}) {
|
|
|
51
51
|
processManager: options.processManager,
|
|
52
52
|
allowBackgroundTasks: backgroundTasks,
|
|
53
53
|
promotionChannel: backgroundTasks ? options.promotionChannel : undefined,
|
|
54
|
+
autoBackgroundAfterMs: backgroundTasks ? options.autoBackgroundAfterMs : false,
|
|
54
55
|
}),
|
|
55
56
|
...(backgroundTasks ? createBackgroundTaskTools(options.processManager) : []),
|
|
56
57
|
...createManagedServerTools(cwd, approval),
|
package/dist/tools/question.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { QuestionRejectedError } from "../question/index.js";
|
|
2
|
+
import { normalizeQuestionInlineText } from "../question/normalize.js";
|
|
2
3
|
export function createQuestionTool(controller) {
|
|
3
4
|
return {
|
|
4
5
|
name: "question",
|
|
@@ -127,8 +128,8 @@ function normalizeQuestions(input) {
|
|
|
127
128
|
return { error: `Error: question at index ${index} must be an object.` };
|
|
128
129
|
}
|
|
129
130
|
const q = raw;
|
|
130
|
-
const header = typeof q.header === "string" ? q.header
|
|
131
|
-
const question = typeof q.question === "string" ? q.question
|
|
131
|
+
const header = typeof q.header === "string" ? normalizeQuestionInlineText(q.header) : "";
|
|
132
|
+
const question = typeof q.question === "string" ? normalizeQuestionInlineText(q.question) : "";
|
|
132
133
|
const options = q.options;
|
|
133
134
|
if (!header)
|
|
134
135
|
return { error: `Error: question at index ${index} has an empty header.` };
|
|
@@ -147,8 +148,8 @@ function normalizeQuestions(input) {
|
|
|
147
148
|
return { error: `Error: option ${optIndex + 1} for "${header}" must be an object.` };
|
|
148
149
|
}
|
|
149
150
|
const value = opt;
|
|
150
|
-
const label = typeof value.label === "string" ? value.label
|
|
151
|
-
const description = typeof value.description === "string" ? value.description
|
|
151
|
+
const label = typeof value.label === "string" ? normalizeQuestionInlineText(value.label) : "";
|
|
152
|
+
const description = typeof value.description === "string" ? normalizeQuestionInlineText(value.description) : "";
|
|
152
153
|
if (!label)
|
|
153
154
|
return { error: `Error: option ${optIndex + 1} for "${header}" has empty label.` };
|
|
154
155
|
if (!description)
|
package/dist/tools/read.js
CHANGED
|
@@ -7,8 +7,9 @@ import { basename, dirname, extname, join, relative } from "node:path";
|
|
|
7
7
|
import { isSensitivePath } from "./sensitive-paths.js";
|
|
8
8
|
import { FileStateTracker } from "./file-state.js";
|
|
9
9
|
import { resolveToolPath } from "./path-utils.js";
|
|
10
|
+
import { utf8Prefix } from "../context/tool-output-truncate.js";
|
|
10
11
|
const MAX_LINES = 2500;
|
|
11
|
-
const MAX_BYTES =
|
|
12
|
+
const MAX_BYTES = 64 * 1024;
|
|
12
13
|
const FILE_UNCHANGED_STUB = "File unchanged since last read. The earlier read tool_result in this conversation is still current — refer to that instead of re-reading. If you need a different range, call read again with explicit offset/limit; if the file has actually changed, edit or write will refresh this cache automatically.";
|
|
13
14
|
const END_OF_FILE_STUB = (totalLines) => `End of file reached. All ${totalLines} lines of this file have already been returned by previous read tool_results in this conversation. Refer to those results, or pass an explicit offset to re-read a specific range.`;
|
|
14
15
|
export function createReadTool(cwd, approval, lsp, fileState) {
|
|
@@ -126,32 +127,46 @@ export function createReadTool(cwd, approval, lsp, fileState) {
|
|
|
126
127
|
const lines = content.split("\n");
|
|
127
128
|
const totalLines = lines.length;
|
|
128
129
|
const effectiveLimit = argLimit !== undefined ? argLimit : totalLines;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
let
|
|
136
|
-
|
|
137
|
-
if (byteLength > MAX_BYTES) {
|
|
138
|
-
result = Buffer.from(result, "utf-8").subarray(0, MAX_BYTES).toString("utf-8");
|
|
139
|
-
truncated = true;
|
|
140
|
-
}
|
|
141
|
-
if (autoAdvanceNote) {
|
|
142
|
-
result = `${autoAdvanceNote}\n${result}`;
|
|
143
|
-
}
|
|
130
|
+
const requestedLines = lines.slice(effectiveOffset, effectiveOffset + effectiveLimit);
|
|
131
|
+
const lineLimited = requestedLines.length > MAX_LINES;
|
|
132
|
+
const candidates = requestedLines.slice(0, MAX_LINES);
|
|
133
|
+
const prefix = autoAdvanceNote ? `${autoAdvanceNote}\n` : "";
|
|
134
|
+
let returnedLines = candidates.length;
|
|
135
|
+
let partialFirstLine = false;
|
|
136
|
+
let body = candidates.join("\n");
|
|
137
|
+
let truncated = lineLimited || Buffer.byteLength(`${prefix}${body}`, "utf8") > MAX_BYTES;
|
|
144
138
|
if (truncated) {
|
|
145
|
-
const
|
|
146
|
-
|
|
139
|
+
const accepted = [];
|
|
140
|
+
for (const line of candidates) {
|
|
141
|
+
const next = accepted.length === 0 ? line : `${accepted.join("\n")}\n${line}`;
|
|
142
|
+
const nextReturnedLines = accepted.length + 1;
|
|
143
|
+
const marker = readTruncationMarker(effectiveOffset + nextReturnedLines, totalLines);
|
|
144
|
+
if (Buffer.byteLength(`${prefix}${next}${marker}`, "utf8") > MAX_BYTES)
|
|
145
|
+
break;
|
|
146
|
+
accepted.push(line);
|
|
147
|
+
}
|
|
148
|
+
returnedLines = accepted.length;
|
|
149
|
+
body = accepted.join("\n");
|
|
150
|
+
// A pathological single line can exceed the whole page. Preserve a
|
|
151
|
+
// UTF-8-safe prefix and advance by exactly that represented line so
|
|
152
|
+
// auto-pagination never loops forever or skips multiple unseen lines.
|
|
153
|
+
if (returnedLines === 0 && candidates.length > 0) {
|
|
154
|
+
returnedLines = 1;
|
|
155
|
+
partialFirstLine = true;
|
|
156
|
+
const marker = readTruncationMarker(effectiveOffset + returnedLines, totalLines);
|
|
157
|
+
const available = Math.max(0, MAX_BYTES - Buffer.byteLength(`${prefix}${marker}`, "utf8"));
|
|
158
|
+
body = utf8Prefix(candidates[0], available);
|
|
159
|
+
}
|
|
160
|
+
body += readTruncationMarker(effectiveOffset + returnedLines, totalLines);
|
|
147
161
|
}
|
|
162
|
+
const result = `${prefix}${body}`;
|
|
148
163
|
if (currentMtimeMs !== undefined) {
|
|
149
164
|
setHistory(filePath, {
|
|
150
165
|
argOffset,
|
|
151
166
|
argLimit,
|
|
152
167
|
effectiveOffset,
|
|
153
168
|
effectiveLimit,
|
|
154
|
-
returnedLines
|
|
169
|
+
returnedLines,
|
|
155
170
|
totalLines,
|
|
156
171
|
mtimeMs: currentMtimeMs,
|
|
157
172
|
truncated,
|
|
@@ -159,7 +174,7 @@ export function createReadTool(cwd, approval, lsp, fileState) {
|
|
|
159
174
|
}
|
|
160
175
|
const isFullRead = effectiveOffset === 0
|
|
161
176
|
&& !truncated
|
|
162
|
-
&& effectiveOffset +
|
|
177
|
+
&& effectiveOffset + returnedLines >= totalLines;
|
|
163
178
|
if (isFullRead) {
|
|
164
179
|
await fileState?.observe(filePath, "read", content).catch(() => undefined);
|
|
165
180
|
}
|
|
@@ -171,15 +186,19 @@ export function createReadTool(cwd, approval, lsp, fileState) {
|
|
|
171
186
|
kind: "read",
|
|
172
187
|
path: filePath,
|
|
173
188
|
offset: effectiveOffset + 1,
|
|
174
|
-
lines:
|
|
189
|
+
lines: returnedLines,
|
|
175
190
|
total: totalLines,
|
|
176
191
|
...(autoAdvanceNote ? { autoAdvanced: true } : {}),
|
|
177
192
|
...(truncated ? { truncated: true } : {}),
|
|
193
|
+
...(partialFirstLine ? { partialFirstLine: true } : {}),
|
|
178
194
|
},
|
|
179
195
|
};
|
|
180
196
|
},
|
|
181
197
|
};
|
|
182
198
|
}
|
|
199
|
+
function readTruncationMarker(lastLine, totalLines) {
|
|
200
|
+
return `\n[Output truncated at line ${lastLine} of ${totalLines}. Call read again on the same path to auto-advance to the next page, or pass explicit offset/limit.]`;
|
|
201
|
+
}
|
|
183
202
|
async function readFileNotFoundMessage(filePath, cwd, error) {
|
|
184
203
|
const message = [`Error: Cannot read file: ${filePath}`];
|
|
185
204
|
const code = typeof error?.code === "string" ? error.code : undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One clock owns all decorative TUI animation. Components expose pure frame
|
|
3
|
+
* advancement; they never create timers or request renders independently.
|
|
4
|
+
*/
|
|
5
|
+
export declare class TuiAnimationClock {
|
|
6
|
+
private readonly onTick;
|
|
7
|
+
private readonly intervalMs;
|
|
8
|
+
private timer;
|
|
9
|
+
constructor(onTick: (elapsedMs: number) => void, intervalMs?: number);
|
|
10
|
+
setActive(active: boolean): void;
|
|
11
|
+
isActive(): boolean;
|
|
12
|
+
dispose(): void;
|
|
13
|
+
private stop;
|
|
14
|
+
}
|