plugsuits 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +3 -0
- package/dist/agent-reasoning-default.test.d.ts +2 -0
- package/dist/agent-reasoning-default.test.d.ts.map +1 -0
- package/dist/agent-reasoning-default.test.js +38 -0
- package/dist/agent-reasoning-default.test.js.map +1 -0
- package/dist/agent.d.ts +61 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +308 -0
- package/dist/agent.js.map +1 -0
- package/dist/agent.test.d.ts +2 -0
- package/dist/agent.test.d.ts.map +1 -0
- package/dist/agent.test.js +38 -0
- package/dist/agent.test.js.map +1 -0
- package/dist/cli-args.d.ts +15 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +63 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-args.test.d.ts +2 -0
- package/dist/cli-args.test.d.ts.map +1 -0
- package/dist/cli-args.test.js +105 -0
- package/dist/cli-args.test.js.map +1 -0
- package/dist/commands/aliases-and-tool-fallback.test.d.ts +2 -0
- package/dist/commands/aliases-and-tool-fallback.test.d.ts.map +1 -0
- package/dist/commands/aliases-and-tool-fallback.test.js +132 -0
- package/dist/commands/aliases-and-tool-fallback.test.js.map +1 -0
- package/dist/commands/clear.d.ts +3 -0
- package/dist/commands/clear.d.ts.map +1 -0
- package/dist/commands/clear.js +12 -0
- package/dist/commands/clear.js.map +1 -0
- package/dist/commands/factories/create-toggle-command.d.ts +13 -0
- package/dist/commands/factories/create-toggle-command.d.ts.map +1 -0
- package/dist/commands/factories/create-toggle-command.js +38 -0
- package/dist/commands/factories/create-toggle-command.js.map +1 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +23 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +82 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/model.d.ts +15 -0
- package/dist/commands/model.d.ts.map +1 -0
- package/dist/commands/model.js +100 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/reasoning-mode.d.ts +3 -0
- package/dist/commands/reasoning-mode.d.ts.map +1 -0
- package/dist/commands/reasoning-mode.js +47 -0
- package/dist/commands/reasoning-mode.js.map +1 -0
- package/dist/commands/render.d.ts +19 -0
- package/dist/commands/render.d.ts.map +1 -0
- package/dist/commands/render.js +140 -0
- package/dist/commands/render.js.map +1 -0
- package/dist/commands/render.test.d.ts +2 -0
- package/dist/commands/render.test.d.ts.map +1 -0
- package/dist/commands/render.test.js +36 -0
- package/dist/commands/render.test.js.map +1 -0
- package/dist/commands/tool-fallback.d.ts +3 -0
- package/dist/commands/tool-fallback.d.ts.map +1 -0
- package/dist/commands/tool-fallback.js +38 -0
- package/dist/commands/tool-fallback.js.map +1 -0
- package/dist/commands/translate.d.ts +3 -0
- package/dist/commands/translate.d.ts.map +1 -0
- package/dist/commands/translate.js +12 -0
- package/dist/commands/translate.js.map +1 -0
- package/dist/commands/translate.test.d.ts +2 -0
- package/dist/commands/translate.test.d.ts.map +1 -0
- package/dist/commands/translate.test.js +49 -0
- package/dist/commands/translate.test.js.map +1 -0
- package/dist/commands/types.d.ts +17 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/context/environment-context.d.ts +2 -0
- package/dist/context/environment-context.d.ts.map +1 -0
- package/dist/context/environment-context.js +11 -0
- package/dist/context/environment-context.js.map +1 -0
- package/dist/context/paths.d.ts +3 -0
- package/dist/context/paths.d.ts.map +1 -0
- package/dist/context/paths.js +3 -0
- package/dist/context/paths.js.map +1 -0
- package/dist/context/session.d.ts +4 -0
- package/dist/context/session.d.ts.map +1 -0
- package/dist/context/session.js +16 -0
- package/dist/context/session.js.map +1 -0
- package/dist/context/skill-command-prefix.d.ts +4 -0
- package/dist/context/skill-command-prefix.d.ts.map +1 -0
- package/dist/context/skill-command-prefix.js +15 -0
- package/dist/context/skill-command-prefix.js.map +1 -0
- package/dist/context/skills-integration.test.d.ts +2 -0
- package/dist/context/skills-integration.test.d.ts.map +1 -0
- package/dist/context/skills-integration.test.js +87 -0
- package/dist/context/skills-integration.test.js.map +1 -0
- package/dist/context/skills.d.ts +18 -0
- package/dist/context/skills.d.ts.map +1 -0
- package/dist/context/skills.js +431 -0
- package/dist/context/skills.js.map +1 -0
- package/dist/context/skills.test.d.ts +2 -0
- package/dist/context/skills.test.d.ts.map +1 -0
- package/dist/context/skills.test.js +20 -0
- package/dist/context/skills.test.js.map +1 -0
- package/dist/context/system-prompt.d.ts +2 -0
- package/dist/context/system-prompt.d.ts.map +1 -0
- package/dist/context/system-prompt.js +100 -0
- package/dist/context/system-prompt.js.map +1 -0
- package/dist/context/translation-integration.test.d.ts +2 -0
- package/dist/context/translation-integration.test.d.ts.map +1 -0
- package/dist/context/translation-integration.test.js +138 -0
- package/dist/context/translation-integration.test.js.map +1 -0
- package/dist/context/translation.d.ts +21 -0
- package/dist/context/translation.d.ts.map +1 -0
- package/dist/context/translation.js +82 -0
- package/dist/context/translation.js.map +1 -0
- package/dist/context/translation.test.d.ts +2 -0
- package/dist/context/translation.test.d.ts.map +1 -0
- package/dist/context/translation.test.js +129 -0
- package/dist/context/translation.test.js.map +1 -0
- package/dist/entrypoints/cli-input-rendering.test.d.ts +2 -0
- package/dist/entrypoints/cli-input-rendering.test.d.ts.map +1 -0
- package/dist/entrypoints/cli-input-rendering.test.js +192 -0
- package/dist/entrypoints/cli-input-rendering.test.js.map +1 -0
- package/dist/entrypoints/cli.d.ts +3 -0
- package/dist/entrypoints/cli.d.ts.map +1 -0
- package/dist/entrypoints/cli.js +1268 -0
- package/dist/entrypoints/cli.js.map +1 -0
- package/dist/entrypoints/headless-agent-config.d.ts +21 -0
- package/dist/entrypoints/headless-agent-config.d.ts.map +1 -0
- package/dist/entrypoints/headless-agent-config.js +15 -0
- package/dist/entrypoints/headless-agent-config.js.map +1 -0
- package/dist/entrypoints/headless-agent-config.test.d.ts +2 -0
- package/dist/entrypoints/headless-agent-config.test.d.ts.map +1 -0
- package/dist/entrypoints/headless-agent-config.test.js +63 -0
- package/dist/entrypoints/headless-agent-config.test.js.map +1 -0
- package/dist/entrypoints/headless.d.ts +3 -0
- package/dist/entrypoints/headless.d.ts.map +1 -0
- package/dist/entrypoints/headless.js +396 -0
- package/dist/entrypoints/headless.js.map +1 -0
- package/dist/env.d.ts +8 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +14 -0
- package/dist/env.js.map +1 -0
- package/dist/friendli-models.d.ts +21 -0
- package/dist/friendli-models.d.ts.map +1 -0
- package/dist/friendli-models.js +57 -0
- package/dist/friendli-models.js.map +1 -0
- package/dist/friendli-reasoning.d.ts +10 -0
- package/dist/friendli-reasoning.d.ts.map +1 -0
- package/dist/friendli-reasoning.js +181 -0
- package/dist/friendli-reasoning.js.map +1 -0
- package/dist/friendli-reasoning.test.d.ts +2 -0
- package/dist/friendli-reasoning.test.d.ts.map +1 -0
- package/dist/friendli-reasoning.test.js +77 -0
- package/dist/friendli-reasoning.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/colors.d.ts +22 -0
- package/dist/interaction/colors.d.ts.map +1 -0
- package/dist/interaction/colors.js +24 -0
- package/dist/interaction/colors.js.map +1 -0
- package/dist/interaction/pi-tui-stream-renderer.d.ts +19 -0
- package/dist/interaction/pi-tui-stream-renderer.d.ts.map +1 -0
- package/dist/interaction/pi-tui-stream-renderer.js +1509 -0
- package/dist/interaction/pi-tui-stream-renderer.js.map +1 -0
- package/dist/interaction/pi-tui-stream-renderer.test.d.ts +2 -0
- package/dist/interaction/pi-tui-stream-renderer.test.d.ts.map +1 -0
- package/dist/interaction/pi-tui-stream-renderer.test.js +1314 -0
- package/dist/interaction/pi-tui-stream-renderer.test.js.map +1 -0
- package/dist/interaction/spinner.d.ts +13 -0
- package/dist/interaction/spinner.d.ts.map +1 -0
- package/dist/interaction/spinner.js +51 -0
- package/dist/interaction/spinner.js.map +1 -0
- package/dist/middleware/index.d.ts +7 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +15 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/todo-continuation.d.ts +11 -0
- package/dist/middleware/todo-continuation.d.ts.map +1 -0
- package/dist/middleware/todo-continuation.js +103 -0
- package/dist/middleware/todo-continuation.js.map +1 -0
- package/dist/middleware/trim-leading-newlines.d.ts +3 -0
- package/dist/middleware/trim-leading-newlines.d.ts.map +1 -0
- package/dist/middleware/trim-leading-newlines.js +49 -0
- package/dist/middleware/trim-leading-newlines.js.map +1 -0
- package/dist/reasoning-mode.d.ts +5 -0
- package/dist/reasoning-mode.d.ts.map +1 -0
- package/dist/reasoning-mode.js +30 -0
- package/dist/reasoning-mode.js.map +1 -0
- package/dist/reasoning-mode.test.d.ts +2 -0
- package/dist/reasoning-mode.test.d.ts.map +1 -0
- package/dist/reasoning-mode.test.js +22 -0
- package/dist/reasoning-mode.test.js.map +1 -0
- package/dist/tool-fallback-mode.d.ts +6 -0
- package/dist/tool-fallback-mode.d.ts.map +1 -0
- package/dist/tool-fallback-mode.js +25 -0
- package/dist/tool-fallback-mode.js.map +1 -0
- package/dist/tools/execute/shell-execute.d.ts +17 -0
- package/dist/tools/execute/shell-execute.d.ts.map +1 -0
- package/dist/tools/execute/shell-execute.js +55 -0
- package/dist/tools/execute/shell-execute.js.map +1 -0
- package/dist/tools/execute/shell-execute.test.d.ts +2 -0
- package/dist/tools/execute/shell-execute.test.d.ts.map +1 -0
- package/dist/tools/execute/shell-execute.test.js +86 -0
- package/dist/tools/execute/shell-execute.test.js.map +1 -0
- package/dist/tools/execute/shell-interact.d.ts +10 -0
- package/dist/tools/execute/shell-interact.d.ts.map +1 -0
- package/dist/tools/execute/shell-interact.js +122 -0
- package/dist/tools/execute/shell-interact.js.map +1 -0
- package/dist/tools/execute/shell-interact.test.d.ts +2 -0
- package/dist/tools/execute/shell-interact.test.d.ts.map +1 -0
- package/dist/tools/execute/shell-interact.test.js +175 -0
- package/dist/tools/execute/shell-interact.test.js.map +1 -0
- package/dist/tools/explore/glob.d.ts +15 -0
- package/dist/tools/explore/glob.d.ts.map +1 -0
- package/dist/tools/explore/glob.js +107 -0
- package/dist/tools/explore/glob.js.map +1 -0
- package/dist/tools/explore/glob.test.d.ts +2 -0
- package/dist/tools/explore/glob.test.d.ts.map +1 -0
- package/dist/tools/explore/glob.test.js +183 -0
- package/dist/tools/explore/glob.test.js.map +1 -0
- package/dist/tools/explore/grep.d.ts +27 -0
- package/dist/tools/explore/grep.d.ts.map +1 -0
- package/dist/tools/explore/grep.js +203 -0
- package/dist/tools/explore/grep.js.map +1 -0
- package/dist/tools/explore/grep.test.d.ts +2 -0
- package/dist/tools/explore/grep.test.d.ts.map +1 -0
- package/dist/tools/explore/grep.test.js +132 -0
- package/dist/tools/explore/grep.test.js.map +1 -0
- package/dist/tools/explore/read-file.d.ts +23 -0
- package/dist/tools/explore/read-file.d.ts.map +1 -0
- package/dist/tools/explore/read-file.js +84 -0
- package/dist/tools/explore/read-file.js.map +1 -0
- package/dist/tools/explore/read-file.test.d.ts +2 -0
- package/dist/tools/explore/read-file.test.d.ts.map +1 -0
- package/dist/tools/explore/read-file.test.js +278 -0
- package/dist/tools/explore/read-file.test.js.map +1 -0
- package/dist/tools/index.d.ts +71 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +26 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/modify/delete-file.d.ts +19 -0
- package/dist/tools/modify/delete-file.d.ts.map +1 -0
- package/dist/tools/modify/delete-file.js +71 -0
- package/dist/tools/modify/delete-file.js.map +1 -0
- package/dist/tools/modify/delete-file.test.d.ts +2 -0
- package/dist/tools/modify/delete-file.test.d.ts.map +1 -0
- package/dist/tools/modify/delete-file.test.js +136 -0
- package/dist/tools/modify/delete-file.test.js.map +1 -0
- package/dist/tools/modify/edit-file-diagnostics.d.ts +17 -0
- package/dist/tools/modify/edit-file-diagnostics.d.ts.map +1 -0
- package/dist/tools/modify/edit-file-diagnostics.js +157 -0
- package/dist/tools/modify/edit-file-diagnostics.js.map +1 -0
- package/dist/tools/modify/edit-file-repair.d.ts +13 -0
- package/dist/tools/modify/edit-file-repair.d.ts.map +1 -0
- package/dist/tools/modify/edit-file-repair.js +135 -0
- package/dist/tools/modify/edit-file-repair.js.map +1 -0
- package/dist/tools/modify/edit-file-stress.test.d.ts +2 -0
- package/dist/tools/modify/edit-file-stress.test.d.ts.map +1 -0
- package/dist/tools/modify/edit-file-stress.test.js +163 -0
- package/dist/tools/modify/edit-file-stress.test.js.map +1 -0
- package/dist/tools/modify/edit-file-validation.d.ts +9 -0
- package/dist/tools/modify/edit-file-validation.d.ts.map +1 -0
- package/dist/tools/modify/edit-file-validation.js +86 -0
- package/dist/tools/modify/edit-file-validation.js.map +1 -0
- package/dist/tools/modify/edit-file-whitespace.test.d.ts +2 -0
- package/dist/tools/modify/edit-file-whitespace.test.d.ts.map +1 -0
- package/dist/tools/modify/edit-file-whitespace.test.js +90 -0
- package/dist/tools/modify/edit-file-whitespace.test.js.map +1 -0
- package/dist/tools/modify/edit-file.d.ts +33 -0
- package/dist/tools/modify/edit-file.d.ts.map +1 -0
- package/dist/tools/modify/edit-file.js +177 -0
- package/dist/tools/modify/edit-file.js.map +1 -0
- package/dist/tools/modify/edit-file.test.d.ts +2 -0
- package/dist/tools/modify/edit-file.test.d.ts.map +1 -0
- package/dist/tools/modify/edit-file.test.js +948 -0
- package/dist/tools/modify/edit-file.test.js.map +1 -0
- package/dist/tools/modify/write-file.d.ts +17 -0
- package/dist/tools/modify/write-file.d.ts.map +1 -0
- package/dist/tools/modify/write-file.js +39 -0
- package/dist/tools/modify/write-file.js.map +1 -0
- package/dist/tools/modify/write-file.test.d.ts +2 -0
- package/dist/tools/modify/write-file.test.d.ts.map +1 -0
- package/dist/tools/modify/write-file.test.js +168 -0
- package/dist/tools/modify/write-file.test.js.map +1 -0
- package/dist/tools/planning/load-skill.d.ts +13 -0
- package/dist/tools/planning/load-skill.d.ts.map +1 -0
- package/dist/tools/planning/load-skill.js +101 -0
- package/dist/tools/planning/load-skill.js.map +1 -0
- package/dist/tools/planning/load-skill.test.d.ts +2 -0
- package/dist/tools/planning/load-skill.test.d.ts.map +1 -0
- package/dist/tools/planning/load-skill.test.js +37 -0
- package/dist/tools/planning/load-skill.test.js.map +1 -0
- package/dist/tools/planning/todo-write.d.ts +49 -0
- package/dist/tools/planning/todo-write.d.ts.map +1 -0
- package/dist/tools/planning/todo-write.js +118 -0
- package/dist/tools/planning/todo-write.js.map +1 -0
- package/dist/tools/planning/todo-write.test.d.ts +2 -0
- package/dist/tools/planning/todo-write.test.d.ts.map +1 -0
- package/dist/tools/planning/todo-write.test.js +82 -0
- package/dist/tools/planning/todo-write.test.js.map +1 -0
- package/dist/tools/utils/execute/format-utils.d.ts +4 -0
- package/dist/tools/utils/execute/format-utils.d.ts.map +1 -0
- package/dist/tools/utils/execute/format-utils.js +31 -0
- package/dist/tools/utils/execute/format-utils.js.map +1 -0
- package/dist/tools/utils/execute/format-utils.test.d.ts +2 -0
- package/dist/tools/utils/execute/format-utils.test.d.ts.map +1 -0
- package/dist/tools/utils/execute/format-utils.test.js +40 -0
- package/dist/tools/utils/execute/format-utils.test.js.map +1 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.d.ts +12 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.d.ts.map +1 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.js +269 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.js.map +1 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.test.d.ts +2 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.test.d.ts.map +1 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.test.js +233 -0
- package/dist/tools/utils/execute/noninteractive-wrapper.test.js.map +1 -0
- package/dist/tools/utils/execute/output-handler.d.ts +14 -0
- package/dist/tools/utils/execute/output-handler.d.ts.map +1 -0
- package/dist/tools/utils/execute/output-handler.js +71 -0
- package/dist/tools/utils/execute/output-handler.js.map +1 -0
- package/dist/tools/utils/execute/output-handler.test.d.ts +2 -0
- package/dist/tools/utils/execute/output-handler.test.d.ts.map +1 -0
- package/dist/tools/utils/execute/output-handler.test.js +58 -0
- package/dist/tools/utils/execute/output-handler.test.js.map +1 -0
- package/dist/tools/utils/execute/process-manager.d.ts +17 -0
- package/dist/tools/utils/execute/process-manager.d.ts.map +1 -0
- package/dist/tools/utils/execute/process-manager.js +229 -0
- package/dist/tools/utils/execute/process-manager.js.map +1 -0
- package/dist/tools/utils/execute/process-manager.test.d.ts +2 -0
- package/dist/tools/utils/execute/process-manager.test.d.ts.map +1 -0
- package/dist/tools/utils/execute/process-manager.test.js +139 -0
- package/dist/tools/utils/execute/process-manager.test.js.map +1 -0
- package/dist/tools/utils/execute/shell-detection.d.ts +3 -0
- package/dist/tools/utils/execute/shell-detection.d.ts.map +1 -0
- package/dist/tools/utils/execute/shell-detection.js +56 -0
- package/dist/tools/utils/execute/shell-detection.js.map +1 -0
- package/dist/tools/utils/execute/shell-detection.test.d.ts +2 -0
- package/dist/tools/utils/execute/shell-detection.test.d.ts.map +1 -0
- package/dist/tools/utils/execute/shell-detection.test.js +86 -0
- package/dist/tools/utils/execute/shell-detection.test.js.map +1 -0
- package/dist/tools/utils/hashline/autocorrect-replacement-lines.d.ts +5 -0
- package/dist/tools/utils/hashline/autocorrect-replacement-lines.d.ts.map +1 -0
- package/dist/tools/utils/hashline/autocorrect-replacement-lines.js +113 -0
- package/dist/tools/utils/hashline/autocorrect-replacement-lines.js.map +1 -0
- package/dist/tools/utils/hashline/constants.d.ts +5 -0
- package/dist/tools/utils/hashline/constants.d.ts.map +1 -0
- package/dist/tools/utils/hashline/constants.js +11 -0
- package/dist/tools/utils/hashline/constants.js.map +1 -0
- package/dist/tools/utils/hashline/diff-utils.d.ts +7 -0
- package/dist/tools/utils/hashline/diff-utils.d.ts.map +1 -0
- package/dist/tools/utils/hashline/diff-utils.js +50 -0
- package/dist/tools/utils/hashline/diff-utils.js.map +1 -0
- package/dist/tools/utils/hashline/diff-utils.test.d.ts +2 -0
- package/dist/tools/utils/hashline/diff-utils.test.d.ts.map +1 -0
- package/dist/tools/utils/hashline/diff-utils.test.js +46 -0
- package/dist/tools/utils/hashline/diff-utils.test.js.map +1 -0
- package/dist/tools/utils/hashline/edit-deduplication.d.ts +6 -0
- package/dist/tools/utils/hashline/edit-deduplication.d.ts.map +1 -0
- package/dist/tools/utils/hashline/edit-deduplication.js +32 -0
- package/dist/tools/utils/hashline/edit-deduplication.js.map +1 -0
- package/dist/tools/utils/hashline/edit-operation-primitives.d.ts +11 -0
- package/dist/tools/utils/hashline/edit-operation-primitives.d.ts.map +1 -0
- package/dist/tools/utils/hashline/edit-operation-primitives.js +93 -0
- package/dist/tools/utils/hashline/edit-operation-primitives.js.map +1 -0
- package/dist/tools/utils/hashline/edit-operations.d.ts +9 -0
- package/dist/tools/utils/hashline/edit-operations.d.ts.map +1 -0
- package/dist/tools/utils/hashline/edit-operations.js +101 -0
- package/dist/tools/utils/hashline/edit-operations.js.map +1 -0
- package/dist/tools/utils/hashline/edit-operations.test.d.ts +2 -0
- package/dist/tools/utils/hashline/edit-operations.test.d.ts.map +1 -0
- package/dist/tools/utils/hashline/edit-operations.test.js +135 -0
- package/dist/tools/utils/hashline/edit-operations.test.js.map +1 -0
- package/dist/tools/utils/hashline/edit-ordering.d.ts +5 -0
- package/dist/tools/utils/hashline/edit-ordering.d.ts.map +1 -0
- package/dist/tools/utils/hashline/edit-ordering.js +54 -0
- package/dist/tools/utils/hashline/edit-ordering.js.map +1 -0
- package/dist/tools/utils/hashline/edit-text-normalization.d.ts +9 -0
- package/dist/tools/utils/hashline/edit-text-normalization.d.ts.map +1 -0
- package/dist/tools/utils/hashline/edit-text-normalization.js +135 -0
- package/dist/tools/utils/hashline/edit-text-normalization.js.map +1 -0
- package/dist/tools/utils/hashline/file-text-canonicalization.d.ts +8 -0
- package/dist/tools/utils/hashline/file-text-canonicalization.d.ts.map +1 -0
- package/dist/tools/utils/hashline/file-text-canonicalization.js +42 -0
- package/dist/tools/utils/hashline/file-text-canonicalization.js.map +1 -0
- package/dist/tools/utils/hashline/hash-computation.d.ts +14 -0
- package/dist/tools/utils/hashline/hash-computation.d.ts.map +1 -0
- package/dist/tools/utils/hashline/hash-computation.js +158 -0
- package/dist/tools/utils/hashline/hash-computation.js.map +1 -0
- package/dist/tools/utils/hashline/hash-computation.test.d.ts +2 -0
- package/dist/tools/utils/hashline/hash-computation.test.d.ts.map +1 -0
- package/dist/tools/utils/hashline/hash-computation.test.js +63 -0
- package/dist/tools/utils/hashline/hash-computation.test.js.map +1 -0
- package/dist/tools/utils/hashline/hashline-chunk-formatter.d.ts +11 -0
- package/dist/tools/utils/hashline/hashline-chunk-formatter.d.ts.map +1 -0
- package/dist/tools/utils/hashline/hashline-chunk-formatter.js +41 -0
- package/dist/tools/utils/hashline/hashline-chunk-formatter.js.map +1 -0
- package/dist/tools/utils/hashline/hashline-edit-diff.d.ts +2 -0
- package/dist/tools/utils/hashline/hashline-edit-diff.d.ts.map +1 -0
- package/dist/tools/utils/hashline/hashline-edit-diff.js +27 -0
- package/dist/tools/utils/hashline/hashline-edit-diff.js.map +1 -0
- package/dist/tools/utils/hashline/index.d.ts +14 -0
- package/dist/tools/utils/hashline/index.d.ts.map +1 -0
- package/dist/tools/utils/hashline/index.js +11 -0
- package/dist/tools/utils/hashline/index.js.map +1 -0
- package/dist/tools/utils/hashline/merge-expansion.d.ts +4 -0
- package/dist/tools/utils/hashline/merge-expansion.d.ts.map +1 -0
- package/dist/tools/utils/hashline/merge-expansion.js +105 -0
- package/dist/tools/utils/hashline/merge-expansion.js.map +1 -0
- package/dist/tools/utils/hashline/normalize-edits.d.ts +11 -0
- package/dist/tools/utils/hashline/normalize-edits.d.ts.map +1 -0
- package/dist/tools/utils/hashline/normalize-edits.js +81 -0
- package/dist/tools/utils/hashline/normalize-edits.js.map +1 -0
- package/dist/tools/utils/hashline/types.d.ts +18 -0
- package/dist/tools/utils/hashline/types.d.ts.map +1 -0
- package/dist/tools/utils/hashline/types.js +2 -0
- package/dist/tools/utils/hashline/types.js.map +1 -0
- package/dist/tools/utils/hashline/validation.d.ts +19 -0
- package/dist/tools/utils/hashline/validation.d.ts.map +1 -0
- package/dist/tools/utils/hashline/validation.js +161 -0
- package/dist/tools/utils/hashline/validation.js.map +1 -0
- package/dist/tools/utils/hashline/validation.test.d.ts +2 -0
- package/dist/tools/utils/hashline/validation.test.d.ts.map +1 -0
- package/dist/tools/utils/hashline/validation.test.js +86 -0
- package/dist/tools/utils/hashline/validation.test.js.map +1 -0
- package/dist/tools/utils/safety-utils.d.ts +66 -0
- package/dist/tools/utils/safety-utils.d.ts.map +1 -0
- package/dist/tools/utils/safety-utils.js +681 -0
- package/dist/tools/utils/safety-utils.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +16 -0
- package/dist/utils/tools-manager.d.ts.map +1 -0
- package/dist/utils/tools-manager.js +257 -0
- package/dist/utils/tools-manager.js.map +1 -0
- package/package.json +49 -0
- package/src/AGENTS.md +52 -0
- package/src/agent-reasoning-default.test.ts +48 -0
- package/src/agent.test.ts +49 -0
- package/src/agent.ts +455 -0
- package/src/cli-args.test.ts +152 -0
- package/src/cli-args.ts +90 -0
- package/src/commands/aliases-and-tool-fallback.test.ts +172 -0
- package/src/commands/clear.ts +14 -0
- package/src/commands/factories/create-toggle-command.ts +68 -0
- package/src/commands/help.ts +30 -0
- package/src/commands/index.ts +125 -0
- package/src/commands/model.ts +146 -0
- package/src/commands/reasoning-mode.ts +55 -0
- package/src/commands/render.test.ts +47 -0
- package/src/commands/render.ts +205 -0
- package/src/commands/tool-fallback.ts +47 -0
- package/src/commands/translate.test.ts +62 -0
- package/src/commands/translate.ts +14 -0
- package/src/commands/types.ts +18 -0
- package/src/context/environment-context.ts +11 -0
- package/src/context/paths.ts +2 -0
- package/src/context/session.ts +18 -0
- package/src/context/skill-command-prefix.ts +18 -0
- package/src/context/skills-integration.test.ts +113 -0
- package/src/context/skills.test.ts +25 -0
- package/src/context/skills.ts +566 -0
- package/src/context/system-prompt.ts +100 -0
- package/src/context/translation-integration.test.ts +194 -0
- package/src/context/translation.test.ts +186 -0
- package/src/context/translation.ts +122 -0
- package/src/entrypoints/AGENTS.md +33 -0
- package/src/entrypoints/cli-input-rendering.test.ts +236 -0
- package/src/entrypoints/cli.ts +1845 -0
- package/src/entrypoints/headless-agent-config.test.ts +82 -0
- package/src/entrypoints/headless-agent-config.ts +42 -0
- package/src/entrypoints/headless.ts +622 -0
- package/src/env.ts +14 -0
- package/src/friendli-models.ts +81 -0
- package/src/friendli-reasoning.test.ts +147 -0
- package/src/friendli-reasoning.ts +280 -0
- package/src/index.ts +3 -0
- package/src/interaction/colors.ts +24 -0
- package/src/interaction/pi-tui-stream-renderer.test.ts +1471 -0
- package/src/interaction/pi-tui-stream-renderer.ts +2150 -0
- package/src/interaction/spinner.ts +61 -0
- package/src/middleware/index.ts +32 -0
- package/src/middleware/todo-continuation.ts +128 -0
- package/src/middleware/trim-leading-newlines.ts +66 -0
- package/src/reasoning-mode.test.ts +24 -0
- package/src/reasoning-mode.ts +40 -0
- package/src/skills/example/SKILL.md +44 -0
- package/src/skills/example/references/api.md +37 -0
- package/src/skills/example/scripts/setup.sh +13 -0
- package/src/skills/git-workflow.md +405 -0
- package/src/tool-fallback-mode.ts +34 -0
- package/src/tools/AGENTS.md +44 -0
- package/src/tools/execute/shell-execute.test.ts +114 -0
- package/src/tools/execute/shell-execute.ts +74 -0
- package/src/tools/execute/shell-execute.txt +27 -0
- package/src/tools/execute/shell-interact.test.ts +236 -0
- package/src/tools/execute/shell-interact.ts +151 -0
- package/src/tools/execute/shell-interact.txt +15 -0
- package/src/tools/explore/glob-files.txt +8 -0
- package/src/tools/explore/glob.test.ts +217 -0
- package/src/tools/explore/glob.ts +137 -0
- package/src/tools/explore/grep-files.txt +12 -0
- package/src/tools/explore/grep.test.ts +183 -0
- package/src/tools/explore/grep.ts +266 -0
- package/src/tools/explore/read-file.test.ts +355 -0
- package/src/tools/explore/read-file.ts +102 -0
- package/src/tools/explore/read-file.txt +24 -0
- package/src/tools/index.ts +29 -0
- package/src/tools/modify/AGENTS.md +38 -0
- package/src/tools/modify/delete-file.test.ts +200 -0
- package/src/tools/modify/delete-file.ts +95 -0
- package/src/tools/modify/delete-file.txt +9 -0
- package/src/tools/modify/edit-file-diagnostics.ts +210 -0
- package/src/tools/modify/edit-file-repair.ts +183 -0
- package/src/tools/modify/edit-file-stress.test.ts +200 -0
- package/src/tools/modify/edit-file-validation.ts +134 -0
- package/src/tools/modify/edit-file-whitespace.test.ts +117 -0
- package/src/tools/modify/edit-file.test.ts +1231 -0
- package/src/tools/modify/edit-file.ts +252 -0
- package/src/tools/modify/edit-file.txt +73 -0
- package/src/tools/modify/write-file.test.ts +240 -0
- package/src/tools/modify/write-file.ts +56 -0
- package/src/tools/modify/write-file.txt +9 -0
- package/src/tools/planning/load-skill.test.ts +48 -0
- package/src/tools/planning/load-skill.ts +136 -0
- package/src/tools/planning/load-skill.txt +6 -0
- package/src/tools/planning/todo-write.test.ts +91 -0
- package/src/tools/planning/todo-write.ts +141 -0
- package/src/tools/planning/todo-write.txt +7 -0
- package/src/tools/utils/execute/format-utils.test.ts +53 -0
- package/src/tools/utils/execute/format-utils.ts +37 -0
- package/src/tools/utils/execute/noninteractive-wrapper.test.ts +306 -0
- package/src/tools/utils/execute/noninteractive-wrapper.ts +314 -0
- package/src/tools/utils/execute/output-handler.test.ts +72 -0
- package/src/tools/utils/execute/output-handler.ts +101 -0
- package/src/tools/utils/execute/process-manager.test.ts +175 -0
- package/src/tools/utils/execute/process-manager.ts +310 -0
- package/src/tools/utils/execute/shell-detection.test.ts +112 -0
- package/src/tools/utils/execute/shell-detection.ts +72 -0
- package/src/tools/utils/hashline/autocorrect-replacement-lines.ts +159 -0
- package/src/tools/utils/hashline/constants.ts +13 -0
- package/src/tools/utils/hashline/diff-utils.test.ts +61 -0
- package/src/tools/utils/hashline/diff-utils.ts +64 -0
- package/src/tools/utils/hashline/edit-deduplication.ts +40 -0
- package/src/tools/utils/hashline/edit-operation-primitives.ts +149 -0
- package/src/tools/utils/hashline/edit-operations.test.ts +154 -0
- package/src/tools/utils/hashline/edit-operations.ts +132 -0
- package/src/tools/utils/hashline/edit-ordering.ts +60 -0
- package/src/tools/utils/hashline/edit-text-normalization.ts +180 -0
- package/src/tools/utils/hashline/file-text-canonicalization.ts +58 -0
- package/src/tools/utils/hashline/hash-computation.test.ts +82 -0
- package/src/tools/utils/hashline/hash-computation.ts +199 -0
- package/src/tools/utils/hashline/hashline-chunk-formatter.ts +61 -0
- package/src/tools/utils/hashline/hashline-edit-diff.ts +35 -0
- package/src/tools/utils/hashline/index.ts +55 -0
- package/src/tools/utils/hashline/merge-expansion.ts +120 -0
- package/src/tools/utils/hashline/normalize-edits.ts +127 -0
- package/src/tools/utils/hashline/types.ts +20 -0
- package/src/tools/utils/hashline/validation.test.ts +109 -0
- package/src/tools/utils/hashline/validation.ts +212 -0
- package/src/tools/utils/safety-utils.ts +938 -0
- package/src/utils/tools-manager.ts +353 -0
|
@@ -0,0 +1,1509 @@
|
|
|
1
|
+
import { Container, Markdown, Spacer, Text, truncateToWidth, visibleWidth, } from "@mariozechner/pi-tui";
|
|
2
|
+
import { parsePartialJson } from "ai";
|
|
3
|
+
const addChatComponent = (chatContainer, component, options = {}) => {
|
|
4
|
+
if (options.addLeadingSpacer ?? true) {
|
|
5
|
+
chatContainer.addChild(new Spacer(1));
|
|
6
|
+
}
|
|
7
|
+
chatContainer.addChild(component);
|
|
8
|
+
};
|
|
9
|
+
const safeStringify = (value) => {
|
|
10
|
+
if (typeof value === "string") {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return JSON.stringify(value, null, 2);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const isPlainEmptyObject = (value) => {
|
|
21
|
+
if (typeof value !== "object" || value === null) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return Object.keys(value).length === 0;
|
|
28
|
+
};
|
|
29
|
+
const renderCodeBlock = (language, value) => {
|
|
30
|
+
const text = safeStringify(value).replace(TRAILING_NEWLINES, "");
|
|
31
|
+
const longestFenceRun = Array.from(text.matchAll(BACKTICK_FENCE_PATTERN)).reduce((max, match) => Math.max(max, match[0].length), 2);
|
|
32
|
+
const fence = "`".repeat(longestFenceRun + 1);
|
|
33
|
+
return `${fence}${language}\n${text}\n${fence}`;
|
|
34
|
+
};
|
|
35
|
+
const READ_FILE_SUCCESS_PREFIX = "OK - read file";
|
|
36
|
+
const GLOB_SUCCESS_PREFIX = "OK - glob";
|
|
37
|
+
const GREP_SUCCESS_PREFIX = "OK - grep";
|
|
38
|
+
const SHELL_EXECUTE_TOOL_NAMES = new Set(["shell_execute", "bash"]);
|
|
39
|
+
const SHELL_TOOL_NAMES = new Set(["shell_execute", "bash", "shell_interact"]);
|
|
40
|
+
const UNKNOWN_TOOL_NAME = "tool";
|
|
41
|
+
const READ_FILE_BLOCK_PREFIX = "======== ";
|
|
42
|
+
const READ_FILE_BLOCK_SUFFIX = " ========";
|
|
43
|
+
const READ_FILE_BLOCK_END = "======== end ========";
|
|
44
|
+
const BACKTICK_FENCE_PATTERN = /`{3,}/g;
|
|
45
|
+
const READ_FILE_LINE_SPLIT_PATTERN = /^(\s*\d+(?:#[^\s|]+)?\s*\|\s*)(.*)$/;
|
|
46
|
+
const READ_FILE_LINES_WITH_RETURNED_PATTERN = /^(\d+)\s+\(returned:\s*(\d+)\)$/;
|
|
47
|
+
const READ_FILE_MARKDOWN_FENCE_PATTERN = /^(?:`{3,}|~{3,}).*$/;
|
|
48
|
+
const SURROUNDED_BY_DOUBLE_QUOTES_PATTERN = /^"(.*)"$/;
|
|
49
|
+
const TAB_PATTERN = /\t/g;
|
|
50
|
+
const MAX_READ_PREVIEW_LINES = 10;
|
|
51
|
+
const MAX_WRITE_FILE_PREVIEW_LINES = 200;
|
|
52
|
+
const MAX_WRITE_FILE_PREVIEW_CHARS = 100_000;
|
|
53
|
+
const TOOL_PENDING_MESSAGE = "Executing..";
|
|
54
|
+
const TOOL_PENDING_MARKER = "__tool_pending_status__";
|
|
55
|
+
const TOOL_PENDING_SPINNER_FRAMES = ["-", "\\", "|", "/"];
|
|
56
|
+
const HASHLINE_TAG_ONLY_PATTERN = /^(.*\d+#[ZPMQVRWSNKTXJBYH]{2})\s*$/;
|
|
57
|
+
const HASHLINE_PIPE_ONLY_PATTERN = /^\|\s*(.*)$/;
|
|
58
|
+
const HASHLINE_TAG_PIPE_ONLY_PATTERN = /^(.*\d+#[ZPMQVRWSNKTXJBYH]{2})\s*\|\s*$/;
|
|
59
|
+
const HASHLINE_COMPACT_LINE_PATTERN = /^\s*\d+#[ZPMQVRWSNKTXJBYH]{2}\|.*$/;
|
|
60
|
+
const isTruthyEnvFlag = (value) => {
|
|
61
|
+
if (!value) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const normalized = value.trim().toLowerCase();
|
|
65
|
+
return (normalized === "1" ||
|
|
66
|
+
normalized === "true" ||
|
|
67
|
+
normalized === "yes" ||
|
|
68
|
+
normalized === "on");
|
|
69
|
+
};
|
|
70
|
+
const isRawToolIoEnabledByEnv = () => {
|
|
71
|
+
return isTruthyEnvFlag(process.env.DEBUG_SHOW_RAW_TOOL_IO);
|
|
72
|
+
};
|
|
73
|
+
const extractStringField = (input, field) => {
|
|
74
|
+
if (typeof input !== "object" || input === null) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const record = input;
|
|
78
|
+
return typeof record[field] === "string" ? record[field] : null;
|
|
79
|
+
};
|
|
80
|
+
const extractNumberField = (input, field) => {
|
|
81
|
+
if (typeof input !== "object" || input === null) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const record = input;
|
|
85
|
+
const value = record[field];
|
|
86
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
87
|
+
};
|
|
88
|
+
const extractBooleanField = (input, field) => {
|
|
89
|
+
if (typeof input !== "object" || input === null) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const record = input;
|
|
93
|
+
return typeof record[field] === "boolean" ? record[field] : null;
|
|
94
|
+
};
|
|
95
|
+
const buildTextPreviewLines = (text, emptyText = "(empty)", maxPreviewLines = MAX_READ_PREVIEW_LINES) => {
|
|
96
|
+
const normalized = text.replaceAll("\r\n", "\n").trimEnd();
|
|
97
|
+
if (normalized.length === 0) {
|
|
98
|
+
return [emptyText];
|
|
99
|
+
}
|
|
100
|
+
const allLines = normalized.split("\n");
|
|
101
|
+
const omittedLines = Math.max(0, allLines.length - maxPreviewLines);
|
|
102
|
+
const visibleLines = omittedLines > 0 ? allLines.slice(0, maxPreviewLines) : allLines;
|
|
103
|
+
const preview = [...visibleLines];
|
|
104
|
+
if (omittedLines > 0) {
|
|
105
|
+
const lineLabel = `line${omittedLines === 1 ? "" : "s"}`;
|
|
106
|
+
preview.push("");
|
|
107
|
+
preview.push(`... (${omittedLines} more ${lineLabel})`);
|
|
108
|
+
}
|
|
109
|
+
return preview;
|
|
110
|
+
};
|
|
111
|
+
const buildPrettyHeader = (title, target) => {
|
|
112
|
+
return `**${title}** \`${target}\``;
|
|
113
|
+
};
|
|
114
|
+
const normalizeHashlineBreakArtifacts = (lines) => {
|
|
115
|
+
const normalized = [];
|
|
116
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
117
|
+
const current = lines[index].replaceAll("\r", "");
|
|
118
|
+
const next = lines[index + 1]?.replaceAll("\r", "");
|
|
119
|
+
const nextNext = lines[index + 2]?.replaceAll("\r", "");
|
|
120
|
+
const currentTagOnly = current.match(HASHLINE_TAG_ONLY_PATTERN);
|
|
121
|
+
const nextPipeOnly = next?.match(HASHLINE_PIPE_ONLY_PATTERN);
|
|
122
|
+
const nextLooksLikeHashline = next !== undefined && HASHLINE_COMPACT_LINE_PATTERN.test(next);
|
|
123
|
+
const nextNextLooksLikeHashline = nextNext !== undefined && HASHLINE_COMPACT_LINE_PATTERN.test(nextNext);
|
|
124
|
+
if (currentTagOnly && nextPipeOnly) {
|
|
125
|
+
const pipedContent = nextPipeOnly[1].trim();
|
|
126
|
+
if (pipedContent.length > 0) {
|
|
127
|
+
normalized.push(`${currentTagOnly[1]}|${pipedContent}`);
|
|
128
|
+
index += 1;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (nextNext !== undefined && !nextNextLooksLikeHashline) {
|
|
132
|
+
normalized.push(`${currentTagOnly[1]}|${nextNext.trimStart()}`);
|
|
133
|
+
index += 2;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const currentTagPipeOnly = current.match(HASHLINE_TAG_PIPE_ONLY_PATTERN);
|
|
138
|
+
if (currentTagPipeOnly && next !== undefined && !nextLooksLikeHashline) {
|
|
139
|
+
normalized.push(`${currentTagPipeOnly[1]}|${next.trimStart()}`);
|
|
140
|
+
index += 1;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
normalized.push(current);
|
|
144
|
+
}
|
|
145
|
+
return normalized;
|
|
146
|
+
};
|
|
147
|
+
const shouldIncludeReadFilePreviewLine = (line) => {
|
|
148
|
+
const match = line.match(READ_FILE_LINE_SPLIT_PATTERN);
|
|
149
|
+
const content = (match?.[2] ?? line).trim();
|
|
150
|
+
return !READ_FILE_MARKDOWN_FENCE_PATTERN.test(content);
|
|
151
|
+
};
|
|
152
|
+
const stripSurroundedDoubleQuotes = (value) => {
|
|
153
|
+
const trimmed = value.trim();
|
|
154
|
+
const matched = trimmed.match(SURROUNDED_BY_DOUBLE_QUOTES_PATTERN);
|
|
155
|
+
return matched?.[1] ?? trimmed;
|
|
156
|
+
};
|
|
157
|
+
const parseReadFileMetadataLine = (line) => {
|
|
158
|
+
const separatorIndex = line.indexOf(":");
|
|
159
|
+
if (separatorIndex <= 0) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
163
|
+
if (key.length === 0) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
key,
|
|
168
|
+
value: line.slice(separatorIndex + 1).trim(),
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
const parseNumberedBlockToolOutput = (output, successPrefix) => {
|
|
172
|
+
const normalized = output.replaceAll("\r\n", "\n");
|
|
173
|
+
if (!normalized.startsWith(successPrefix)) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const lines = normalized.split("\n");
|
|
177
|
+
const metadata = new Map();
|
|
178
|
+
let blockStartIndex = -1;
|
|
179
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
180
|
+
const line = lines[index];
|
|
181
|
+
if (line.startsWith(READ_FILE_BLOCK_PREFIX) &&
|
|
182
|
+
line.endsWith(READ_FILE_BLOCK_SUFFIX) &&
|
|
183
|
+
line !== READ_FILE_BLOCK_END) {
|
|
184
|
+
blockStartIndex = index;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
if (line.trim().length === 0) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const parsed = parseReadFileMetadataLine(line);
|
|
191
|
+
if (!parsed) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
metadata.set(parsed.key, parsed.value);
|
|
195
|
+
}
|
|
196
|
+
if (blockStartIndex < 0) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
const blockEndIndex = lines.findIndex((line, index) => index > blockStartIndex && line === READ_FILE_BLOCK_END);
|
|
200
|
+
if (blockEndIndex < 0) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const blockTitle = lines[blockStartIndex]
|
|
204
|
+
.slice(READ_FILE_BLOCK_PREFIX.length, -READ_FILE_BLOCK_SUFFIX.length)
|
|
205
|
+
.trim();
|
|
206
|
+
const blockBody = lines.slice(blockStartIndex + 1, blockEndIndex).join("\n");
|
|
207
|
+
return {
|
|
208
|
+
metadata,
|
|
209
|
+
blockTitle,
|
|
210
|
+
blockBody,
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
const parseReadFileOutput = (output) => {
|
|
214
|
+
return parseNumberedBlockToolOutput(output, READ_FILE_SUCCESS_PREFIX);
|
|
215
|
+
};
|
|
216
|
+
const parseGlobOutput = (output) => {
|
|
217
|
+
return parseNumberedBlockToolOutput(output, GLOB_SUCCESS_PREFIX);
|
|
218
|
+
};
|
|
219
|
+
const parseGrepOutput = (output) => {
|
|
220
|
+
return parseNumberedBlockToolOutput(output, GREP_SUCCESS_PREFIX);
|
|
221
|
+
};
|
|
222
|
+
const resolveReadPath = (parsed) => {
|
|
223
|
+
const pathValue = parsed.metadata.get("path") ?? "";
|
|
224
|
+
return pathValue.trim() || parsed.blockTitle || "(unknown)";
|
|
225
|
+
};
|
|
226
|
+
const getToolOmittedLineCount = (metadata) => {
|
|
227
|
+
const linesMetadata = metadata.get("lines");
|
|
228
|
+
if (!linesMetadata) {
|
|
229
|
+
return 0;
|
|
230
|
+
}
|
|
231
|
+
const matchedCounts = linesMetadata.match(READ_FILE_LINES_WITH_RETURNED_PATTERN);
|
|
232
|
+
if (!matchedCounts) {
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
const totalLines = Number.parseInt(matchedCounts[1], 10);
|
|
236
|
+
const returnedLines = Number.parseInt(matchedCounts[2], 10);
|
|
237
|
+
if (!(Number.isFinite(totalLines) && Number.isFinite(returnedLines))) {
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
const isTruncated = metadata.get("truncated")?.toLowerCase() === "true";
|
|
241
|
+
if (!isTruncated) {
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
return Math.max(0, totalLines - returnedLines);
|
|
245
|
+
};
|
|
246
|
+
const buildReadPreviewLines = (visibleLines, totalOmitted, isModelTruncated) => {
|
|
247
|
+
const previewLines = visibleLines.length > 0 && visibleLines.some((line) => line.length > 0)
|
|
248
|
+
? [...visibleLines]
|
|
249
|
+
: ["(empty)"];
|
|
250
|
+
if (totalOmitted <= 0) {
|
|
251
|
+
return previewLines;
|
|
252
|
+
}
|
|
253
|
+
const lineLabel = `line${totalOmitted === 1 ? "" : "s"}`;
|
|
254
|
+
previewLines.push("");
|
|
255
|
+
previewLines.push(isModelTruncated
|
|
256
|
+
? `... (${totalOmitted} more ${lineLabel}, truncated)`
|
|
257
|
+
: `... (${totalOmitted} more ${lineLabel})`);
|
|
258
|
+
return previewLines;
|
|
259
|
+
};
|
|
260
|
+
const parseIntegerMetadataValue = (rawValue) => {
|
|
261
|
+
if (!rawValue) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const parsed = Number.parseInt(rawValue, 10);
|
|
265
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
266
|
+
};
|
|
267
|
+
const buildGlobPreviewLines = (visibleLines, totalOmitted, metadata) => {
|
|
268
|
+
const previewLines = visibleLines.length > 0 && visibleLines.some((line) => line.length > 0)
|
|
269
|
+
? [...visibleLines]
|
|
270
|
+
: ["(no matches)"];
|
|
271
|
+
if (totalOmitted <= 0) {
|
|
272
|
+
return previewLines;
|
|
273
|
+
}
|
|
274
|
+
const lineLabel = `line${totalOmitted === 1 ? "" : "s"}`;
|
|
275
|
+
previewLines.push("");
|
|
276
|
+
previewLines.push(metadata.truncated
|
|
277
|
+
? `... (${totalOmitted} more ${lineLabel}, truncated)`
|
|
278
|
+
: `... (${totalOmitted} more ${lineLabel})`);
|
|
279
|
+
return previewLines;
|
|
280
|
+
};
|
|
281
|
+
const buildGrepPreviewLines = (visibleLines, totalOmitted, metadata) => {
|
|
282
|
+
const previewLines = visibleLines.length > 0 && visibleLines.some((line) => line.length > 0)
|
|
283
|
+
? [...visibleLines]
|
|
284
|
+
: ["(no matches)"];
|
|
285
|
+
if (totalOmitted <= 0) {
|
|
286
|
+
return previewLines;
|
|
287
|
+
}
|
|
288
|
+
const lineLabel = `line${totalOmitted === 1 ? "" : "s"}`;
|
|
289
|
+
const metadataParts = [`path: ${metadata.path ?? "."}`];
|
|
290
|
+
if (metadata.matchCount) {
|
|
291
|
+
metadataParts.push(`match_count (${metadata.matchCount})`);
|
|
292
|
+
}
|
|
293
|
+
if (metadata.truncated) {
|
|
294
|
+
metadataParts.push("truncated: true");
|
|
295
|
+
}
|
|
296
|
+
previewLines.push("");
|
|
297
|
+
previewLines.push(metadata.truncated
|
|
298
|
+
? `... (${totalOmitted} more ${lineLabel}, truncated)`
|
|
299
|
+
: `... (${totalOmitted} more ${lineLabel})`);
|
|
300
|
+
previewLines.push(metadataParts.join(", "));
|
|
301
|
+
return previewLines;
|
|
302
|
+
};
|
|
303
|
+
const renderReadFileOutput = (output) => {
|
|
304
|
+
const parsed = parseReadFileOutput(output);
|
|
305
|
+
if (!parsed) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
const readPath = resolveReadPath(parsed);
|
|
309
|
+
const contentBody = parsed.blockBody.trim().length > 0 ? parsed.blockBody : "(empty)";
|
|
310
|
+
const allLines = normalizeHashlineBreakArtifacts(contentBody.split("\n").filter(shouldIncludeReadFilePreviewLine));
|
|
311
|
+
const omittedFromPreview = Math.max(0, allLines.length - MAX_READ_PREVIEW_LINES);
|
|
312
|
+
const visibleLines = omittedFromPreview > 0
|
|
313
|
+
? allLines.slice(0, MAX_READ_PREVIEW_LINES)
|
|
314
|
+
: allLines;
|
|
315
|
+
const omittedFromTool = getToolOmittedLineCount(parsed.metadata);
|
|
316
|
+
const isModelTruncated = parsed.metadata.get("truncated")?.toLowerCase() === "true";
|
|
317
|
+
const totalOmitted = omittedFromPreview + omittedFromTool;
|
|
318
|
+
const previewLines = buildReadPreviewLines(visibleLines, totalOmitted, isModelTruncated);
|
|
319
|
+
const rangeValue = parsed.metadata.get("range")?.trim() || null;
|
|
320
|
+
return {
|
|
321
|
+
path: readPath,
|
|
322
|
+
range: rangeValue,
|
|
323
|
+
body: previewLines.join("\n"),
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
const renderGlobOutput = (output) => {
|
|
327
|
+
const parsed = parseGlobOutput(output);
|
|
328
|
+
if (!parsed) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
const contentBody = parsed.blockBody.trim();
|
|
332
|
+
const allLines = contentBody.length > 0
|
|
333
|
+
? contentBody.split("\n").filter((line) => line.trim().length > 0)
|
|
334
|
+
: [];
|
|
335
|
+
const omittedFromPreview = Math.max(0, allLines.length - MAX_READ_PREVIEW_LINES);
|
|
336
|
+
const visibleLines = omittedFromPreview > 0
|
|
337
|
+
? allLines.slice(0, MAX_READ_PREVIEW_LINES)
|
|
338
|
+
: allLines;
|
|
339
|
+
const fileCountRaw = parsed.metadata.get("file_count");
|
|
340
|
+
const fileCount = parseIntegerMetadataValue(fileCountRaw);
|
|
341
|
+
const isToolTruncated = parsed.metadata.get("truncated")?.toLowerCase() === "true";
|
|
342
|
+
const omittedFromTool = isToolTruncated && fileCount !== null
|
|
343
|
+
? Math.max(0, fileCount - allLines.length)
|
|
344
|
+
: 0;
|
|
345
|
+
const totalOmitted = omittedFromPreview + omittedFromTool;
|
|
346
|
+
const metadata = {
|
|
347
|
+
truncated: isToolTruncated,
|
|
348
|
+
};
|
|
349
|
+
const previewLines = buildGlobPreviewLines(visibleLines, totalOmitted, metadata);
|
|
350
|
+
const patternValue = stripSurroundedDoubleQuotes(parsed.metadata.get("pattern") ?? "") ||
|
|
351
|
+
parsed.blockTitle ||
|
|
352
|
+
"(unknown)";
|
|
353
|
+
return {
|
|
354
|
+
pattern: patternValue,
|
|
355
|
+
body: previewLines.join("\n"),
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
const renderGrepOutput = (output) => {
|
|
359
|
+
const parsed = parseGrepOutput(output);
|
|
360
|
+
if (!parsed) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
const contentBody = parsed.blockBody.trim();
|
|
364
|
+
const allLines = contentBody.length > 0
|
|
365
|
+
? normalizeHashlineBreakArtifacts(contentBody.split("\n"))
|
|
366
|
+
: [];
|
|
367
|
+
const omittedFromPreview = Math.max(0, allLines.length - MAX_READ_PREVIEW_LINES);
|
|
368
|
+
const visibleLines = omittedFromPreview > 0
|
|
369
|
+
? allLines.slice(0, MAX_READ_PREVIEW_LINES)
|
|
370
|
+
: allLines;
|
|
371
|
+
const matchCountRaw = parsed.metadata.get("match_count");
|
|
372
|
+
const matchCount = parseIntegerMetadataValue(matchCountRaw);
|
|
373
|
+
const isToolTruncated = parsed.metadata.get("truncated")?.toLowerCase() === "true";
|
|
374
|
+
const omittedFromTool = isToolTruncated && matchCount !== null
|
|
375
|
+
? Math.max(0, matchCount - allLines.length)
|
|
376
|
+
: 0;
|
|
377
|
+
const totalOmitted = omittedFromPreview + omittedFromTool;
|
|
378
|
+
const metadata = {
|
|
379
|
+
path: parsed.metadata.get("path") ?? null,
|
|
380
|
+
matchCount: matchCountRaw ?? null,
|
|
381
|
+
truncated: isToolTruncated,
|
|
382
|
+
};
|
|
383
|
+
const previewLines = buildGrepPreviewLines(visibleLines, totalOmitted, metadata);
|
|
384
|
+
const patternValue = stripSurroundedDoubleQuotes(parsed.metadata.get("pattern") ?? "") ||
|
|
385
|
+
parsed.blockTitle ||
|
|
386
|
+
"(unknown)";
|
|
387
|
+
return {
|
|
388
|
+
pattern: patternValue,
|
|
389
|
+
body: previewLines.join("\n"),
|
|
390
|
+
};
|
|
391
|
+
};
|
|
392
|
+
const renderPendingOutput = () => {
|
|
393
|
+
return TOOL_PENDING_MARKER;
|
|
394
|
+
};
|
|
395
|
+
const buildPendingSpinnerText = (frame) => {
|
|
396
|
+
return `${frame} ${TOOL_PENDING_MESSAGE}`;
|
|
397
|
+
};
|
|
398
|
+
const renderToolOutput = (_toolName, output) => {
|
|
399
|
+
return renderCodeBlock("text", output);
|
|
400
|
+
};
|
|
401
|
+
const ANSI_RESET = "\x1b[0m";
|
|
402
|
+
const ANSI_DIM = "\x1b[2m";
|
|
403
|
+
const ANSI_ITALIC = "\x1b[3m";
|
|
404
|
+
const ANSI_GRAY = "\x1b[90m";
|
|
405
|
+
const ANSI_BG_GRAY = "\x1b[100m";
|
|
406
|
+
const LEADING_NEWLINES = /^\n+/;
|
|
407
|
+
const TRAILING_NEWLINES = /\n+$/;
|
|
408
|
+
const applyReadPreviewBackground = (text) => {
|
|
409
|
+
return `${ANSI_BG_GRAY}${text}${ANSI_RESET}`;
|
|
410
|
+
};
|
|
411
|
+
const styleThinkingText = (text) => {
|
|
412
|
+
return `${ANSI_DIM}${ANSI_ITALIC}${ANSI_GRAY}${text}${ANSI_RESET}`;
|
|
413
|
+
};
|
|
414
|
+
class TrimmedMarkdown extends Markdown {
|
|
415
|
+
render(width) {
|
|
416
|
+
const lines = super.render(width);
|
|
417
|
+
let end = lines.length;
|
|
418
|
+
while (end > 0 && lines[end - 1].trim().length === 0) {
|
|
419
|
+
end -= 1;
|
|
420
|
+
}
|
|
421
|
+
return lines.slice(0, end);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
class TruncatedReadBody {
|
|
425
|
+
cachedLines;
|
|
426
|
+
cachedText;
|
|
427
|
+
cachedWidth;
|
|
428
|
+
background;
|
|
429
|
+
backgroundEnabled = true;
|
|
430
|
+
paddingX;
|
|
431
|
+
text;
|
|
432
|
+
constructor(text, paddingX, background) {
|
|
433
|
+
this.text = text;
|
|
434
|
+
this.paddingX = paddingX;
|
|
435
|
+
this.background = background;
|
|
436
|
+
}
|
|
437
|
+
setText(text) {
|
|
438
|
+
this.text = text;
|
|
439
|
+
this.cachedText = undefined;
|
|
440
|
+
this.cachedWidth = undefined;
|
|
441
|
+
this.cachedLines = undefined;
|
|
442
|
+
}
|
|
443
|
+
setBackgroundEnabled(enabled) {
|
|
444
|
+
if (this.backgroundEnabled === enabled) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
this.backgroundEnabled = enabled;
|
|
448
|
+
this.invalidate();
|
|
449
|
+
}
|
|
450
|
+
invalidate() {
|
|
451
|
+
this.cachedText = undefined;
|
|
452
|
+
this.cachedWidth = undefined;
|
|
453
|
+
this.cachedLines = undefined;
|
|
454
|
+
}
|
|
455
|
+
render(width) {
|
|
456
|
+
if (this.cachedLines &&
|
|
457
|
+
this.cachedText === this.text &&
|
|
458
|
+
this.cachedWidth === width) {
|
|
459
|
+
return this.cachedLines;
|
|
460
|
+
}
|
|
461
|
+
if (!this.text || this.text.trim().length === 0) {
|
|
462
|
+
this.cachedText = this.text;
|
|
463
|
+
this.cachedWidth = width;
|
|
464
|
+
this.cachedLines = [];
|
|
465
|
+
return [];
|
|
466
|
+
}
|
|
467
|
+
const normalizedText = this.text.replace(TAB_PATTERN, " ");
|
|
468
|
+
const contentWidth = Math.max(1, width - this.paddingX * 2);
|
|
469
|
+
const leftMargin = " ".repeat(this.paddingX);
|
|
470
|
+
const rightMargin = " ".repeat(this.paddingX);
|
|
471
|
+
const renderedLines = normalizedText.split("\n").map((line) => {
|
|
472
|
+
const truncatedLine = truncateToWidth(line, contentWidth, "");
|
|
473
|
+
const lineWithMargins = `${leftMargin}${truncatedLine}${rightMargin}`;
|
|
474
|
+
const visibleLength = visibleWidth(lineWithMargins);
|
|
475
|
+
const paddedLine = `${lineWithMargins}${" ".repeat(Math.max(0, width - visibleLength))}`;
|
|
476
|
+
return this.background && this.backgroundEnabled
|
|
477
|
+
? this.background(paddedLine)
|
|
478
|
+
: paddedLine;
|
|
479
|
+
});
|
|
480
|
+
this.cachedText = this.text;
|
|
481
|
+
this.cachedWidth = width;
|
|
482
|
+
this.cachedLines = renderedLines;
|
|
483
|
+
return renderedLines;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
const MAX_DIFF_MATRIX_CELLS = 60_000;
|
|
487
|
+
const MAX_DIFF_RENDER_LINES = 160;
|
|
488
|
+
const buildSimpleDiff = (before, after) => {
|
|
489
|
+
const beforeLines = before.split("\n");
|
|
490
|
+
const afterLines = after.split("\n");
|
|
491
|
+
const lines = [];
|
|
492
|
+
const maxLength = Math.max(beforeLines.length, afterLines.length);
|
|
493
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
494
|
+
const oldLine = beforeLines[index];
|
|
495
|
+
const newLine = afterLines[index];
|
|
496
|
+
if (oldLine === undefined && newLine !== undefined) {
|
|
497
|
+
lines.push({ type: "add", text: newLine });
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (newLine === undefined && oldLine !== undefined) {
|
|
501
|
+
lines.push({ type: "delete", text: oldLine });
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (oldLine === newLine && oldLine !== undefined) {
|
|
505
|
+
lines.push({ type: "context", text: oldLine });
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
if (oldLine !== undefined) {
|
|
509
|
+
lines.push({ type: "delete", text: oldLine });
|
|
510
|
+
}
|
|
511
|
+
if (newLine !== undefined) {
|
|
512
|
+
lines.push({ type: "add", text: newLine });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return lines;
|
|
516
|
+
};
|
|
517
|
+
const buildLcsDiff = (before, after) => {
|
|
518
|
+
const beforeLines = before.split("\n");
|
|
519
|
+
const afterLines = after.split("\n");
|
|
520
|
+
if (beforeLines.length === 0 && afterLines.length === 0) {
|
|
521
|
+
return [];
|
|
522
|
+
}
|
|
523
|
+
const matrixCells = (beforeLines.length + 1) * (afterLines.length + 1);
|
|
524
|
+
if (matrixCells > MAX_DIFF_MATRIX_CELLS) {
|
|
525
|
+
return buildSimpleDiff(before, after);
|
|
526
|
+
}
|
|
527
|
+
const lcs = new Array(beforeLines.length + 1)
|
|
528
|
+
.fill(undefined)
|
|
529
|
+
.map(() => new Array(afterLines.length + 1).fill(0));
|
|
530
|
+
for (let i = beforeLines.length - 1; i >= 0; i -= 1) {
|
|
531
|
+
for (let j = afterLines.length - 1; j >= 0; j -= 1) {
|
|
532
|
+
if (beforeLines[i] === afterLines[j]) {
|
|
533
|
+
lcs[i][j] = lcs[i + 1][j + 1] + 1;
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
lcs[i][j] = Math.max(lcs[i + 1][j], lcs[i][j + 1]);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
const lines = [];
|
|
541
|
+
let i = 0;
|
|
542
|
+
let j = 0;
|
|
543
|
+
while (i < beforeLines.length && j < afterLines.length) {
|
|
544
|
+
if (beforeLines[i] === afterLines[j]) {
|
|
545
|
+
lines.push({ type: "context", text: beforeLines[i] });
|
|
546
|
+
i += 1;
|
|
547
|
+
j += 1;
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (lcs[i + 1][j] >= lcs[i][j + 1]) {
|
|
551
|
+
lines.push({ type: "delete", text: beforeLines[i] });
|
|
552
|
+
i += 1;
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
lines.push({ type: "add", text: afterLines[j] });
|
|
556
|
+
j += 1;
|
|
557
|
+
}
|
|
558
|
+
while (i < beforeLines.length) {
|
|
559
|
+
lines.push({ type: "delete", text: beforeLines[i] });
|
|
560
|
+
i += 1;
|
|
561
|
+
}
|
|
562
|
+
while (j < afterLines.length) {
|
|
563
|
+
lines.push({ type: "add", text: afterLines[j] });
|
|
564
|
+
j += 1;
|
|
565
|
+
}
|
|
566
|
+
return lines;
|
|
567
|
+
};
|
|
568
|
+
const renderDiffBlock = (before, after) => {
|
|
569
|
+
const diffLines = buildLcsDiff(before, after);
|
|
570
|
+
const rendered = ["```diff"];
|
|
571
|
+
for (let index = 0; index < diffLines.length; index += 1) {
|
|
572
|
+
if (index >= MAX_DIFF_RENDER_LINES) {
|
|
573
|
+
rendered.push("... diff truncated ...");
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
const line = diffLines[index];
|
|
577
|
+
if (line.type === "add") {
|
|
578
|
+
rendered.push(`+${line.text}`);
|
|
579
|
+
}
|
|
580
|
+
else if (line.type === "delete") {
|
|
581
|
+
rendered.push(`-${line.text}`);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
rendered.push(` ${line.text}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
rendered.push("```");
|
|
588
|
+
return rendered.join("\n");
|
|
589
|
+
};
|
|
590
|
+
const tryExtractEditPayload = (toolName, input) => {
|
|
591
|
+
if (toolName !== "edit_file") {
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
if (typeof input !== "object" || input === null) {
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
const record = input;
|
|
598
|
+
const oldStr = record.old_str;
|
|
599
|
+
const newStr = record.new_str;
|
|
600
|
+
const path = record.path;
|
|
601
|
+
if (typeof oldStr !== "string" || typeof newStr !== "string") {
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
oldStr,
|
|
606
|
+
newStr,
|
|
607
|
+
path: typeof path === "string" ? path : undefined,
|
|
608
|
+
};
|
|
609
|
+
};
|
|
610
|
+
class AssistantStreamView extends Container {
|
|
611
|
+
markdownTheme;
|
|
612
|
+
segments = [];
|
|
613
|
+
constructor(markdownTheme) {
|
|
614
|
+
super();
|
|
615
|
+
this.markdownTheme = markdownTheme;
|
|
616
|
+
this.refresh();
|
|
617
|
+
}
|
|
618
|
+
appendReasoning(delta) {
|
|
619
|
+
this.appendSegment("reasoning", delta);
|
|
620
|
+
}
|
|
621
|
+
appendText(delta) {
|
|
622
|
+
this.appendSegment("text", delta);
|
|
623
|
+
}
|
|
624
|
+
appendSegment(type, delta) {
|
|
625
|
+
if (delta.length === 0) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const lastSegment = this.segments.at(-1);
|
|
629
|
+
if (lastSegment && lastSegment.type === type) {
|
|
630
|
+
lastSegment.content += delta;
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
this.segments.push({
|
|
634
|
+
type,
|
|
635
|
+
content: delta,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
this.refresh();
|
|
639
|
+
}
|
|
640
|
+
refresh() {
|
|
641
|
+
this.clear();
|
|
642
|
+
const visibleSegments = this.segments
|
|
643
|
+
.map((segment) => {
|
|
644
|
+
const normalizedContent = segment.type === "reasoning"
|
|
645
|
+
? segment.content.replace(LEADING_NEWLINES, "").trimEnd()
|
|
646
|
+
: segment.content.trim();
|
|
647
|
+
return {
|
|
648
|
+
...segment,
|
|
649
|
+
content: normalizedContent,
|
|
650
|
+
};
|
|
651
|
+
})
|
|
652
|
+
.filter((segment) => segment.content.trim().length > 0);
|
|
653
|
+
if (visibleSegments.length === 0) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
for (let index = 0; index < visibleSegments.length; index += 1) {
|
|
657
|
+
const segment = visibleSegments[index];
|
|
658
|
+
const text = segment.content;
|
|
659
|
+
if (segment.type === "text") {
|
|
660
|
+
this.addChild(new Markdown(text, 1, 0, this.markdownTheme));
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
this.addChild(new Markdown(text, 1, 0, this.markdownTheme, {
|
|
664
|
+
color: styleThinkingText,
|
|
665
|
+
italic: true,
|
|
666
|
+
}));
|
|
667
|
+
}
|
|
668
|
+
if (index < visibleSegments.length - 1) {
|
|
669
|
+
this.addChild(new Spacer(1));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
class ToolCallView extends Container {
|
|
675
|
+
callId;
|
|
676
|
+
content;
|
|
677
|
+
readBlock;
|
|
678
|
+
readBody;
|
|
679
|
+
readHeader;
|
|
680
|
+
requestRender;
|
|
681
|
+
showRawToolIo;
|
|
682
|
+
error;
|
|
683
|
+
finalInput;
|
|
684
|
+
inputBuffer = "";
|
|
685
|
+
output;
|
|
686
|
+
outputDenied = false;
|
|
687
|
+
pendingSpinnerFrameIndex = 0;
|
|
688
|
+
pendingSpinnerInterval = null;
|
|
689
|
+
pendingTemplate = null;
|
|
690
|
+
parsedInput;
|
|
691
|
+
readMode = false;
|
|
692
|
+
toolName;
|
|
693
|
+
constructor(callId, toolName, markdownTheme, requestRender, showRawToolIo) {
|
|
694
|
+
super();
|
|
695
|
+
this.callId = callId;
|
|
696
|
+
this.toolName = toolName;
|
|
697
|
+
this.requestRender = requestRender;
|
|
698
|
+
this.showRawToolIo = showRawToolIo;
|
|
699
|
+
this.content = new TrimmedMarkdown("", 1, 0, markdownTheme);
|
|
700
|
+
this.readHeader = new TrimmedMarkdown("", 1, 0, markdownTheme);
|
|
701
|
+
this.readBody = new TruncatedReadBody("", 1, applyReadPreviewBackground);
|
|
702
|
+
this.readBlock = new Container();
|
|
703
|
+
this.readBlock.addChild(this.readHeader);
|
|
704
|
+
this.readBlock.addChild(new Spacer(1));
|
|
705
|
+
this.readBlock.addChild(this.readBody);
|
|
706
|
+
this.addChild(this.content);
|
|
707
|
+
this.refresh();
|
|
708
|
+
}
|
|
709
|
+
dispose() {
|
|
710
|
+
this.stopPendingSpinner();
|
|
711
|
+
}
|
|
712
|
+
setReadMode(enabled) {
|
|
713
|
+
if (this.readMode === enabled) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
this.readMode = enabled;
|
|
717
|
+
this.clear();
|
|
718
|
+
this.addChild(enabled ? this.readBlock : this.content);
|
|
719
|
+
}
|
|
720
|
+
stopPendingSpinner() {
|
|
721
|
+
this.pendingTemplate = null;
|
|
722
|
+
if (!this.pendingSpinnerInterval) {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
clearInterval(this.pendingSpinnerInterval);
|
|
726
|
+
this.pendingSpinnerInterval = null;
|
|
727
|
+
}
|
|
728
|
+
applyPendingSpinnerFrame() {
|
|
729
|
+
if (!this.pendingTemplate) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const frame = TOOL_PENDING_SPINNER_FRAMES[this.pendingSpinnerFrameIndex];
|
|
733
|
+
this.readBody.setText(this.pendingTemplate.replaceAll(TOOL_PENDING_MARKER, buildPendingSpinnerText(frame)));
|
|
734
|
+
}
|
|
735
|
+
startPendingSpinner(template) {
|
|
736
|
+
this.pendingTemplate = template;
|
|
737
|
+
this.pendingSpinnerFrameIndex = 0;
|
|
738
|
+
this.applyPendingSpinnerFrame();
|
|
739
|
+
if (this.pendingSpinnerInterval) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
this.pendingSpinnerInterval = setInterval(() => {
|
|
743
|
+
this.pendingSpinnerFrameIndex =
|
|
744
|
+
(this.pendingSpinnerFrameIndex + 1) %
|
|
745
|
+
TOOL_PENDING_SPINNER_FRAMES.length;
|
|
746
|
+
this.applyPendingSpinnerFrame();
|
|
747
|
+
this.requestRender();
|
|
748
|
+
}, 80);
|
|
749
|
+
}
|
|
750
|
+
async appendInputChunk(chunk) {
|
|
751
|
+
this.inputBuffer += chunk;
|
|
752
|
+
const { value, state } = await parsePartialJson(this.inputBuffer);
|
|
753
|
+
const shouldSuppressTransientEmptyObject = state !== "successful-parse" && isPlainEmptyObject(value);
|
|
754
|
+
if (!shouldSuppressTransientEmptyObject) {
|
|
755
|
+
this.parsedInput = value;
|
|
756
|
+
}
|
|
757
|
+
this.refresh();
|
|
758
|
+
}
|
|
759
|
+
setError(error) {
|
|
760
|
+
this.error = error;
|
|
761
|
+
this.refresh();
|
|
762
|
+
}
|
|
763
|
+
setFinalInput(input) {
|
|
764
|
+
this.finalInput = input;
|
|
765
|
+
this.refresh();
|
|
766
|
+
}
|
|
767
|
+
setOutput(output) {
|
|
768
|
+
this.output = output;
|
|
769
|
+
this.refresh();
|
|
770
|
+
}
|
|
771
|
+
setOutputDenied() {
|
|
772
|
+
this.outputDenied = true;
|
|
773
|
+
this.refresh();
|
|
774
|
+
}
|
|
775
|
+
setToolName(toolName) {
|
|
776
|
+
this.toolName = toolName;
|
|
777
|
+
this.refresh();
|
|
778
|
+
}
|
|
779
|
+
resolveBestInput() {
|
|
780
|
+
if (this.finalInput !== undefined) {
|
|
781
|
+
return this.finalInput;
|
|
782
|
+
}
|
|
783
|
+
if (this.parsedInput !== undefined) {
|
|
784
|
+
return this.parsedInput;
|
|
785
|
+
}
|
|
786
|
+
if (this.inputBuffer.length > 0) {
|
|
787
|
+
return this.inputBuffer;
|
|
788
|
+
}
|
|
789
|
+
return undefined;
|
|
790
|
+
}
|
|
791
|
+
canRenderPrettyTool(toolName) {
|
|
792
|
+
if (this.error !== undefined || this.outputDenied) {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
if (typeof toolName === "string") {
|
|
796
|
+
return this.toolName === toolName;
|
|
797
|
+
}
|
|
798
|
+
return toolName.has(this.toolName);
|
|
799
|
+
}
|
|
800
|
+
resolveInputStringField(field) {
|
|
801
|
+
const bestInput = this.resolveBestInput();
|
|
802
|
+
const fromObject = extractStringField(bestInput, field);
|
|
803
|
+
if (fromObject) {
|
|
804
|
+
return fromObject;
|
|
805
|
+
}
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
resolveInputNumberField(field) {
|
|
809
|
+
const bestInput = this.resolveBestInput();
|
|
810
|
+
const fromObject = extractNumberField(bestInput, field);
|
|
811
|
+
if (fromObject !== null) {
|
|
812
|
+
return fromObject;
|
|
813
|
+
}
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
816
|
+
setPrettyBlock(header, body, options) {
|
|
817
|
+
this.setReadMode(true);
|
|
818
|
+
this.readBody.setBackgroundEnabled(options?.useBackground ?? true);
|
|
819
|
+
this.readHeader.setText(header);
|
|
820
|
+
if (options?.isPending) {
|
|
821
|
+
this.startPendingSpinner(body);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
this.stopPendingSpinner();
|
|
825
|
+
this.readBody.setText(body);
|
|
826
|
+
}
|
|
827
|
+
renderOutputPreviewBody(output, emptyText = "(no output)") {
|
|
828
|
+
if (typeof output === "string") {
|
|
829
|
+
return buildTextPreviewLines(output, emptyText).join("\n");
|
|
830
|
+
}
|
|
831
|
+
return buildTextPreviewLines(safeStringify(output), emptyText).join("\n");
|
|
832
|
+
}
|
|
833
|
+
tryRenderReadFileMode() {
|
|
834
|
+
if (this.toolName !== "read_file" ||
|
|
835
|
+
this.error !== undefined ||
|
|
836
|
+
this.outputDenied) {
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
const readPath = this.resolveInputStringField("path");
|
|
840
|
+
if (typeof this.output === "string") {
|
|
841
|
+
const renderedReadFile = renderReadFileOutput(this.output);
|
|
842
|
+
if (renderedReadFile) {
|
|
843
|
+
const pathWithRange = renderedReadFile.range
|
|
844
|
+
? `${renderedReadFile.path} ${renderedReadFile.range}`
|
|
845
|
+
: renderedReadFile.path;
|
|
846
|
+
this.setPrettyBlock(`**Read** \`${pathWithRange}\``, renderedReadFile.body, {
|
|
847
|
+
useBackground: true,
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
else {
|
|
851
|
+
const fallbackPath = readPath ?? "(unknown)";
|
|
852
|
+
this.setPrettyBlock(`**Read** \`${fallbackPath}\``, safeStringify(this.output), {
|
|
853
|
+
useBackground: true,
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
if (!readPath) {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
this.setPrettyBlock(`**Read** \`${readPath}\``, renderPendingOutput(), {
|
|
862
|
+
useBackground: false,
|
|
863
|
+
isPending: true,
|
|
864
|
+
});
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
tryRenderGlobMode() {
|
|
868
|
+
if (this.toolName !== "glob_files" ||
|
|
869
|
+
this.error !== undefined ||
|
|
870
|
+
this.outputDenied) {
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
const globPattern = this.resolveInputStringField("pattern");
|
|
874
|
+
if (typeof this.output === "string") {
|
|
875
|
+
const renderedGlob = renderGlobOutput(this.output);
|
|
876
|
+
if (renderedGlob) {
|
|
877
|
+
this.setPrettyBlock(`**Glob** \`${renderedGlob.pattern}\``, renderedGlob.body, {
|
|
878
|
+
useBackground: true,
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
else {
|
|
882
|
+
const fallbackPattern = globPattern ?? "(unknown)";
|
|
883
|
+
this.setPrettyBlock(`**Glob** \`${fallbackPattern}\``, safeStringify(this.output), {
|
|
884
|
+
useBackground: true,
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
if (!globPattern) {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
this.setPrettyBlock(`**Glob** \`${globPattern}\``, renderPendingOutput(), {
|
|
893
|
+
useBackground: false,
|
|
894
|
+
isPending: true,
|
|
895
|
+
});
|
|
896
|
+
return true;
|
|
897
|
+
}
|
|
898
|
+
tryRenderGrepMode() {
|
|
899
|
+
if (this.toolName !== "grep_files" ||
|
|
900
|
+
this.error !== undefined ||
|
|
901
|
+
this.outputDenied) {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
const grepPattern = this.resolveInputStringField("pattern");
|
|
905
|
+
if (typeof this.output === "string") {
|
|
906
|
+
const renderedGrep = renderGrepOutput(this.output);
|
|
907
|
+
if (renderedGrep) {
|
|
908
|
+
this.setPrettyBlock(`**Grep** \`${renderedGrep.pattern}\``, renderedGrep.body, {
|
|
909
|
+
useBackground: true,
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
else {
|
|
913
|
+
const fallbackPattern = grepPattern ?? "(unknown)";
|
|
914
|
+
this.setPrettyBlock(`**Grep** \`${fallbackPattern}\``, safeStringify(this.output), {
|
|
915
|
+
useBackground: true,
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
return true;
|
|
919
|
+
}
|
|
920
|
+
if (!grepPattern) {
|
|
921
|
+
return false;
|
|
922
|
+
}
|
|
923
|
+
this.setPrettyBlock(`**Grep** \`${grepPattern}\``, renderPendingOutput(), {
|
|
924
|
+
useBackground: false,
|
|
925
|
+
isPending: true,
|
|
926
|
+
});
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
tryRenderShellExecuteMode() {
|
|
930
|
+
if (!this.canRenderPrettyTool(SHELL_EXECUTE_TOOL_NAMES)) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
const command = this.resolveInputStringField("command") ?? "(command)";
|
|
934
|
+
const header = buildPrettyHeader("Shell", command);
|
|
935
|
+
if (this.output === undefined) {
|
|
936
|
+
this.setPrettyBlock(header, renderPendingOutput(), {
|
|
937
|
+
isPending: true,
|
|
938
|
+
useBackground: false,
|
|
939
|
+
});
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
942
|
+
const exitCode = extractNumberField(this.output, "exit_code");
|
|
943
|
+
const shellOutput = extractStringField(this.output, "output");
|
|
944
|
+
const workdir = this.resolveInputStringField("workdir");
|
|
945
|
+
const timeoutMs = this.resolveInputNumberField("timeout_ms");
|
|
946
|
+
const bodyLines = [];
|
|
947
|
+
if (exitCode !== null) {
|
|
948
|
+
bodyLines.push(`exit_code: ${exitCode}`);
|
|
949
|
+
}
|
|
950
|
+
if (workdir) {
|
|
951
|
+
bodyLines.push(`workdir: ${workdir}`);
|
|
952
|
+
}
|
|
953
|
+
if (timeoutMs !== null) {
|
|
954
|
+
bodyLines.push(`timeout_ms: ${timeoutMs}`);
|
|
955
|
+
}
|
|
956
|
+
if (bodyLines.length > 0) {
|
|
957
|
+
bodyLines.push("");
|
|
958
|
+
}
|
|
959
|
+
bodyLines.push(...buildTextPreviewLines(shellOutput ?? safeStringify(this.output), "(no output)"));
|
|
960
|
+
this.setPrettyBlock(header, bodyLines.join("\n"));
|
|
961
|
+
return true;
|
|
962
|
+
}
|
|
963
|
+
tryRenderShellInteractMode() {
|
|
964
|
+
if (!this.canRenderPrettyTool("shell_interact")) {
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
const keystrokes = this.resolveInputStringField("keystrokes") ?? "(keystrokes)";
|
|
968
|
+
const header = buildPrettyHeader("Interact", keystrokes);
|
|
969
|
+
if (this.output === undefined) {
|
|
970
|
+
this.setPrettyBlock(header, renderPendingOutput(), {
|
|
971
|
+
isPending: true,
|
|
972
|
+
useBackground: false,
|
|
973
|
+
});
|
|
974
|
+
return true;
|
|
975
|
+
}
|
|
976
|
+
const success = extractBooleanField(this.output, "success");
|
|
977
|
+
const interactOutput = extractStringField(this.output, "output");
|
|
978
|
+
const bodyLines = [];
|
|
979
|
+
if (success !== null) {
|
|
980
|
+
bodyLines.push(`success: ${success}`);
|
|
981
|
+
bodyLines.push("");
|
|
982
|
+
}
|
|
983
|
+
bodyLines.push(...buildTextPreviewLines(interactOutput ?? safeStringify(this.output), "(no output)"));
|
|
984
|
+
this.setPrettyBlock(header, bodyLines.join("\n"));
|
|
985
|
+
return true;
|
|
986
|
+
}
|
|
987
|
+
tryRenderWriteFileMode() {
|
|
988
|
+
if (!this.canRenderPrettyTool("write_file")) {
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
const bestInput = this.resolveBestInput();
|
|
992
|
+
const path = extractStringField(bestInput, "path") ?? "(unknown)";
|
|
993
|
+
const fileContent = extractStringField(bestInput, "content");
|
|
994
|
+
const header = buildPrettyHeader("Write", path);
|
|
995
|
+
const hasVisibleFileContent = fileContent !== null && fileContent.trim().length > 0;
|
|
996
|
+
if (hasVisibleFileContent) {
|
|
997
|
+
const boundedContent = fileContent.length > MAX_WRITE_FILE_PREVIEW_CHARS
|
|
998
|
+
? fileContent.slice(0, MAX_WRITE_FILE_PREVIEW_CHARS)
|
|
999
|
+
: fileContent;
|
|
1000
|
+
const previewBody = buildTextPreviewLines(boundedContent, "(empty)", MAX_WRITE_FILE_PREVIEW_LINES).join("\n");
|
|
1001
|
+
this.setPrettyBlock(header, previewBody, {
|
|
1002
|
+
useBackground: true,
|
|
1003
|
+
});
|
|
1004
|
+
return true;
|
|
1005
|
+
}
|
|
1006
|
+
if (this.output === undefined) {
|
|
1007
|
+
this.setPrettyBlock(header, renderPendingOutput(), {
|
|
1008
|
+
isPending: true,
|
|
1009
|
+
useBackground: false,
|
|
1010
|
+
});
|
|
1011
|
+
return true;
|
|
1012
|
+
}
|
|
1013
|
+
this.setPrettyBlock(header, this.renderOutputPreviewBody(this.output));
|
|
1014
|
+
return true;
|
|
1015
|
+
}
|
|
1016
|
+
tryRenderEditFileMode() {
|
|
1017
|
+
if (!this.canRenderPrettyTool("edit_file")) {
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
1020
|
+
const bestInput = this.resolveBestInput();
|
|
1021
|
+
const path = this.resolveInputStringField("path") ?? "(unknown)";
|
|
1022
|
+
const header = buildPrettyHeader("Edit", path);
|
|
1023
|
+
const bodyLines = [];
|
|
1024
|
+
if (typeof bestInput === "object" && bestInput !== null) {
|
|
1025
|
+
const record = bestInput;
|
|
1026
|
+
if (Array.isArray(record.edits)) {
|
|
1027
|
+
bodyLines.push(`edits: ${record.edits.length}`);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
if (this.output === undefined) {
|
|
1031
|
+
if (bodyLines.length > 0) {
|
|
1032
|
+
bodyLines.push("");
|
|
1033
|
+
}
|
|
1034
|
+
bodyLines.push(renderPendingOutput());
|
|
1035
|
+
}
|
|
1036
|
+
else {
|
|
1037
|
+
if (bodyLines.length > 0) {
|
|
1038
|
+
bodyLines.push("");
|
|
1039
|
+
}
|
|
1040
|
+
bodyLines.push(...buildTextPreviewLines(safeStringify(this.output)));
|
|
1041
|
+
}
|
|
1042
|
+
const editPayload = tryExtractEditPayload(this.toolName, bestInput);
|
|
1043
|
+
if (editPayload) {
|
|
1044
|
+
bodyLines.push("");
|
|
1045
|
+
bodyLines.push("Live diff preview:");
|
|
1046
|
+
bodyLines.push(renderDiffBlock(editPayload.oldStr, editPayload.newStr));
|
|
1047
|
+
}
|
|
1048
|
+
this.setPrettyBlock(header, bodyLines.join("\n"), {
|
|
1049
|
+
isPending: this.output === undefined,
|
|
1050
|
+
useBackground: this.output !== undefined,
|
|
1051
|
+
});
|
|
1052
|
+
return true;
|
|
1053
|
+
}
|
|
1054
|
+
tryRenderDeleteFileMode() {
|
|
1055
|
+
if (!this.canRenderPrettyTool("delete_file")) {
|
|
1056
|
+
return false;
|
|
1057
|
+
}
|
|
1058
|
+
const path = this.resolveInputStringField("path") ?? "(unknown)";
|
|
1059
|
+
const header = buildPrettyHeader("Delete", path);
|
|
1060
|
+
if (this.output === undefined) {
|
|
1061
|
+
this.setPrettyBlock(header, renderPendingOutput(), {
|
|
1062
|
+
isPending: true,
|
|
1063
|
+
useBackground: false,
|
|
1064
|
+
});
|
|
1065
|
+
return true;
|
|
1066
|
+
}
|
|
1067
|
+
this.setPrettyBlock(header, this.renderOutputPreviewBody(this.output));
|
|
1068
|
+
return true;
|
|
1069
|
+
}
|
|
1070
|
+
tryRenderLoadSkillMode() {
|
|
1071
|
+
if (!this.canRenderPrettyTool("load_skill")) {
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
const skillName = this.resolveInputStringField("skillName") ?? "(unknown)";
|
|
1075
|
+
const relativePath = this.resolveInputStringField("relativePath");
|
|
1076
|
+
const target = relativePath ? `${skillName}/${relativePath}` : skillName;
|
|
1077
|
+
const header = buildPrettyHeader("Skill", target);
|
|
1078
|
+
if (this.output === undefined) {
|
|
1079
|
+
this.setPrettyBlock(header, renderPendingOutput(), {
|
|
1080
|
+
isPending: true,
|
|
1081
|
+
useBackground: false,
|
|
1082
|
+
});
|
|
1083
|
+
return true;
|
|
1084
|
+
}
|
|
1085
|
+
this.setPrettyBlock(header, this.renderOutputPreviewBody(this.output));
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
tryRenderTodoWriteMode() {
|
|
1089
|
+
if (!this.canRenderPrettyTool("todo_write")) {
|
|
1090
|
+
return false;
|
|
1091
|
+
}
|
|
1092
|
+
const bestInput = this.resolveBestInput();
|
|
1093
|
+
const todoItems = typeof bestInput === "object" && bestInput !== null
|
|
1094
|
+
? bestInput.todos
|
|
1095
|
+
: undefined;
|
|
1096
|
+
const todos = Array.isArray(todoItems)
|
|
1097
|
+
? todoItems.filter((item) => {
|
|
1098
|
+
return typeof item === "object" && item !== null;
|
|
1099
|
+
})
|
|
1100
|
+
: [];
|
|
1101
|
+
const totalTodos = todos.length;
|
|
1102
|
+
const headerTarget = `${totalTodos} task${totalTodos === 1 ? "" : "s"}`;
|
|
1103
|
+
const header = buildPrettyHeader("Todo", headerTarget);
|
|
1104
|
+
if (this.output === undefined) {
|
|
1105
|
+
this.setPrettyBlock(header, renderPendingOutput(), {
|
|
1106
|
+
isPending: true,
|
|
1107
|
+
useBackground: false,
|
|
1108
|
+
});
|
|
1109
|
+
return true;
|
|
1110
|
+
}
|
|
1111
|
+
const counts = {
|
|
1112
|
+
completed: 0,
|
|
1113
|
+
inProgress: 0,
|
|
1114
|
+
pending: 0,
|
|
1115
|
+
cancelled: 0,
|
|
1116
|
+
};
|
|
1117
|
+
for (const todo of todos) {
|
|
1118
|
+
const status = typeof todo.status === "string" ? todo.status.toLowerCase() : "";
|
|
1119
|
+
if (status === "completed") {
|
|
1120
|
+
counts.completed += 1;
|
|
1121
|
+
}
|
|
1122
|
+
else if (status === "in_progress") {
|
|
1123
|
+
counts.inProgress += 1;
|
|
1124
|
+
}
|
|
1125
|
+
else if (status === "pending") {
|
|
1126
|
+
counts.pending += 1;
|
|
1127
|
+
}
|
|
1128
|
+
else if (status === "cancelled") {
|
|
1129
|
+
counts.cancelled += 1;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
const bodyLines = [
|
|
1133
|
+
`total: ${totalTodos}`,
|
|
1134
|
+
`completed: ${counts.completed}`,
|
|
1135
|
+
`in_progress: ${counts.inProgress}`,
|
|
1136
|
+
`pending: ${counts.pending}`,
|
|
1137
|
+
`cancelled: ${counts.cancelled}`,
|
|
1138
|
+
"",
|
|
1139
|
+
...buildTextPreviewLines(safeStringify(this.output)),
|
|
1140
|
+
];
|
|
1141
|
+
this.setPrettyBlock(header, bodyLines.join("\n"));
|
|
1142
|
+
return true;
|
|
1143
|
+
}
|
|
1144
|
+
tryRenderPrettyMode() {
|
|
1145
|
+
return (this.tryRenderReadFileMode() ||
|
|
1146
|
+
this.tryRenderGlobMode() ||
|
|
1147
|
+
this.tryRenderGrepMode() ||
|
|
1148
|
+
this.tryRenderShellExecuteMode() ||
|
|
1149
|
+
this.tryRenderShellInteractMode() ||
|
|
1150
|
+
this.tryRenderWriteFileMode() ||
|
|
1151
|
+
this.tryRenderEditFileMode() ||
|
|
1152
|
+
this.tryRenderDeleteFileMode() ||
|
|
1153
|
+
this.tryRenderLoadSkillMode() ||
|
|
1154
|
+
this.tryRenderTodoWriteMode());
|
|
1155
|
+
}
|
|
1156
|
+
shouldSuppressRawFallback() {
|
|
1157
|
+
if (this.showRawToolIo) {
|
|
1158
|
+
return false;
|
|
1159
|
+
}
|
|
1160
|
+
return (this.finalInput === undefined &&
|
|
1161
|
+
this.output === undefined &&
|
|
1162
|
+
this.error === undefined &&
|
|
1163
|
+
!this.outputDenied &&
|
|
1164
|
+
this.inputBuffer.length > 0);
|
|
1165
|
+
}
|
|
1166
|
+
refresh() {
|
|
1167
|
+
if (!this.showRawToolIo && this.tryRenderPrettyMode()) {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
this.stopPendingSpinner();
|
|
1171
|
+
if (this.shouldSuppressRawFallback()) {
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
this.setReadMode(false);
|
|
1175
|
+
const includeCallIdInRawHeader = !SHELL_TOOL_NAMES.has(this.toolName);
|
|
1176
|
+
const rawHeader = includeCallIdInRawHeader
|
|
1177
|
+
? `**Tool** \`${this.toolName}\` (\`${this.callId}\`)`
|
|
1178
|
+
: `**Tool** \`${this.toolName}\``;
|
|
1179
|
+
const blocks = [rawHeader];
|
|
1180
|
+
const bestInput = this.resolveBestInput();
|
|
1181
|
+
if (bestInput !== undefined) {
|
|
1182
|
+
blocks.push(`**Input**\n\n${renderCodeBlock("json", bestInput)}`);
|
|
1183
|
+
const editPayload = tryExtractEditPayload(this.toolName, bestInput);
|
|
1184
|
+
if (editPayload) {
|
|
1185
|
+
const heading = editPayload.path
|
|
1186
|
+
? `**Live diff preview** (\`${editPayload.path}\`)`
|
|
1187
|
+
: "**Live diff preview**";
|
|
1188
|
+
blocks.push(`${heading}\n\n${renderDiffBlock(editPayload.oldStr, editPayload.newStr)}`);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
if (this.output !== undefined) {
|
|
1192
|
+
blocks.push(`**Output**\n\n${renderToolOutput(this.toolName, this.output)}`);
|
|
1193
|
+
}
|
|
1194
|
+
if (this.error !== undefined) {
|
|
1195
|
+
blocks.push(`**Error**\n\n${renderCodeBlock("text", this.error)}`);
|
|
1196
|
+
}
|
|
1197
|
+
if (this.outputDenied) {
|
|
1198
|
+
blocks.push("**Output** denied by model/policy");
|
|
1199
|
+
}
|
|
1200
|
+
this.content.setText(blocks.join("\n\n"));
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
const getToolInputId = (part) => {
|
|
1204
|
+
return part.id ?? part.toolCallId;
|
|
1205
|
+
};
|
|
1206
|
+
const getToolInputChunk = (part) => {
|
|
1207
|
+
if (typeof part.delta === "string") {
|
|
1208
|
+
return part.delta;
|
|
1209
|
+
}
|
|
1210
|
+
if (typeof part.inputTextDelta === "string") {
|
|
1211
|
+
return part.inputTextDelta;
|
|
1212
|
+
}
|
|
1213
|
+
return null;
|
|
1214
|
+
};
|
|
1215
|
+
const createToolInputState = (toolName) => {
|
|
1216
|
+
return {
|
|
1217
|
+
toolName,
|
|
1218
|
+
hasContent: false,
|
|
1219
|
+
inputBuffer: "",
|
|
1220
|
+
renderedInputLength: 0,
|
|
1221
|
+
};
|
|
1222
|
+
};
|
|
1223
|
+
const syncToolInputToView = async (state, toolCallId, toolState) => {
|
|
1224
|
+
const hasKnownToolName = toolState.toolName !== UNKNOWN_TOOL_NAME;
|
|
1225
|
+
if (!(state.flags.showRawToolIo || hasKnownToolName)) {
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
const existingView = state.getToolView(toolCallId);
|
|
1229
|
+
const pendingInput = toolState.inputBuffer.slice(toolState.renderedInputLength);
|
|
1230
|
+
if (!existingView && pendingInput.length === 0) {
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
state.resetAssistantView(true);
|
|
1234
|
+
const toolView = existingView ?? state.ensureToolView(toolCallId, toolState.toolName);
|
|
1235
|
+
if (pendingInput.length === 0) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
await toolView.appendInputChunk(pendingInput);
|
|
1239
|
+
toolState.renderedInputLength = toolState.inputBuffer.length;
|
|
1240
|
+
};
|
|
1241
|
+
const createInfoMessage = (title, value) => {
|
|
1242
|
+
return new Text(`${title}\n${safeStringify(value)}`, 1, 0);
|
|
1243
|
+
};
|
|
1244
|
+
const handleTextStart = (_part, state) => {
|
|
1245
|
+
state.ensureAssistantView();
|
|
1246
|
+
};
|
|
1247
|
+
const handleTextDelta = (part, state) => {
|
|
1248
|
+
const textPart = part;
|
|
1249
|
+
state.ensureAssistantView().appendText(textPart.text);
|
|
1250
|
+
};
|
|
1251
|
+
const handleReasoningStart = (_part, state) => {
|
|
1252
|
+
if (state.flags.showReasoning) {
|
|
1253
|
+
state.ensureAssistantView();
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
const handleReasoningDelta = (part, state) => {
|
|
1257
|
+
if (!state.flags.showReasoning) {
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
const reasoningPart = part;
|
|
1261
|
+
state.ensureAssistantView().appendReasoning(reasoningPart.text);
|
|
1262
|
+
};
|
|
1263
|
+
const handleToolInputStart = async (part, state) => {
|
|
1264
|
+
const toolInputStartPart = part;
|
|
1265
|
+
const toolCallId = getToolInputId(toolInputStartPart);
|
|
1266
|
+
if (!toolCallId) {
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
const existingState = state.activeToolInputs.get(toolCallId);
|
|
1270
|
+
const toolState = existingState ?? createToolInputState(toolInputStartPart.toolName);
|
|
1271
|
+
toolState.toolName = toolInputStartPart.toolName;
|
|
1272
|
+
state.activeToolInputs.set(toolCallId, toolState);
|
|
1273
|
+
state.streamedToolCallIds.add(toolCallId);
|
|
1274
|
+
await syncToolInputToView(state, toolCallId, toolState);
|
|
1275
|
+
};
|
|
1276
|
+
const handleToolInputDelta = async (part, state) => {
|
|
1277
|
+
const toolInputDeltaPart = part;
|
|
1278
|
+
const toolCallId = getToolInputId(toolInputDeltaPart);
|
|
1279
|
+
if (!toolCallId) {
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
if (!state.activeToolInputs.has(toolCallId)) {
|
|
1283
|
+
state.activeToolInputs.set(toolCallId, createToolInputState(UNKNOWN_TOOL_NAME));
|
|
1284
|
+
}
|
|
1285
|
+
const toolState = state.activeToolInputs.get(toolCallId);
|
|
1286
|
+
const chunk = getToolInputChunk(toolInputDeltaPart);
|
|
1287
|
+
if (chunk && toolState) {
|
|
1288
|
+
toolState.inputBuffer += chunk;
|
|
1289
|
+
toolState.hasContent = true;
|
|
1290
|
+
await syncToolInputToView(state, toolCallId, toolState);
|
|
1291
|
+
}
|
|
1292
|
+
state.streamedToolCallIds.add(toolCallId);
|
|
1293
|
+
};
|
|
1294
|
+
const handleToolInputEnd = (part, state) => {
|
|
1295
|
+
const toolInputEndPart = part;
|
|
1296
|
+
const toolCallId = getToolInputId(toolInputEndPart);
|
|
1297
|
+
if (toolCallId) {
|
|
1298
|
+
state.streamedToolCallIds.add(toolCallId);
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
const handleToolCall = (part, state) => {
|
|
1302
|
+
const toolCallPart = part;
|
|
1303
|
+
const inputState = state.activeToolInputs.get(toolCallPart.toolCallId);
|
|
1304
|
+
const shouldSkipToolCallRender = state.streamedToolCallIds.has(toolCallPart.toolCallId) &&
|
|
1305
|
+
inputState?.hasContent === true;
|
|
1306
|
+
state.activeToolInputs.delete(toolCallPart.toolCallId);
|
|
1307
|
+
state.streamedToolCallIds.delete(toolCallPart.toolCallId);
|
|
1308
|
+
state.resetAssistantView(true);
|
|
1309
|
+
const view = state.ensureToolView(toolCallPart.toolCallId, toolCallPart.toolName);
|
|
1310
|
+
view.setFinalInput(toolCallPart.input);
|
|
1311
|
+
if (!shouldSkipToolCallRender) {
|
|
1312
|
+
view.setToolName(toolCallPart.toolName);
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
const handleToolResult = (part, state) => {
|
|
1316
|
+
if (!state.flags.showToolResults) {
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
const toolResultPart = part;
|
|
1320
|
+
state.resetAssistantView(true);
|
|
1321
|
+
const view = state.ensureToolView(toolResultPart.toolCallId, toolResultPart.toolName);
|
|
1322
|
+
view.setOutput(toolResultPart.output);
|
|
1323
|
+
};
|
|
1324
|
+
const handleToolError = (part, state) => {
|
|
1325
|
+
const toolErrorPart = part;
|
|
1326
|
+
state.resetAssistantView(true);
|
|
1327
|
+
const view = state.ensureToolView(toolErrorPart.toolCallId, toolErrorPart.toolName);
|
|
1328
|
+
view.setError(toolErrorPart.error);
|
|
1329
|
+
};
|
|
1330
|
+
const handleToolOutputDenied = (part, state) => {
|
|
1331
|
+
const deniedPart = part;
|
|
1332
|
+
state.resetAssistantView(true);
|
|
1333
|
+
const view = state.ensureToolView(deniedPart.toolCallId, deniedPart.toolName);
|
|
1334
|
+
view.setOutputDenied();
|
|
1335
|
+
};
|
|
1336
|
+
const handleStartStep = (_part, state) => {
|
|
1337
|
+
if (!state.flags.showSteps) {
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
state.resetAssistantView();
|
|
1341
|
+
addChatComponent(state.chatContainer, createInfoMessage("[step start]", ""));
|
|
1342
|
+
};
|
|
1343
|
+
const handleFinishStep = (part, state) => {
|
|
1344
|
+
if (!state.flags.showSteps) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
const finishStepPart = part;
|
|
1348
|
+
state.resetAssistantView();
|
|
1349
|
+
addChatComponent(state.chatContainer, createInfoMessage("[step finish]", finishStepPart.finishReason));
|
|
1350
|
+
};
|
|
1351
|
+
const handleSource = (part, state) => {
|
|
1352
|
+
if (!state.flags.showSources) {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
state.resetAssistantView();
|
|
1356
|
+
addChatComponent(state.chatContainer, createInfoMessage("[source]", part));
|
|
1357
|
+
};
|
|
1358
|
+
const handleFile = (part, state) => {
|
|
1359
|
+
if (!state.flags.showFiles) {
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
const filePart = part;
|
|
1363
|
+
state.resetAssistantView();
|
|
1364
|
+
addChatComponent(state.chatContainer, createInfoMessage("[file]", filePart.file));
|
|
1365
|
+
};
|
|
1366
|
+
const handleFinish = (part, state) => {
|
|
1367
|
+
if (!state.flags.showFinishReason) {
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
const finishPart = part;
|
|
1371
|
+
state.resetAssistantView();
|
|
1372
|
+
addChatComponent(state.chatContainer, createInfoMessage("[finish]", finishPart.finishReason ?? "unknown"));
|
|
1373
|
+
};
|
|
1374
|
+
const STREAM_HANDLERS = {
|
|
1375
|
+
"text-start": handleTextStart,
|
|
1376
|
+
"text-delta": handleTextDelta,
|
|
1377
|
+
"reasoning-start": handleReasoningStart,
|
|
1378
|
+
"reasoning-delta": handleReasoningDelta,
|
|
1379
|
+
"tool-input-start": handleToolInputStart,
|
|
1380
|
+
"tool-input-delta": handleToolInputDelta,
|
|
1381
|
+
"tool-input-end": handleToolInputEnd,
|
|
1382
|
+
"tool-call": handleToolCall,
|
|
1383
|
+
"tool-result": handleToolResult,
|
|
1384
|
+
"tool-error": handleToolError,
|
|
1385
|
+
"tool-output-denied": handleToolOutputDenied,
|
|
1386
|
+
"start-step": handleStartStep,
|
|
1387
|
+
"finish-step": handleFinishStep,
|
|
1388
|
+
source: handleSource,
|
|
1389
|
+
file: handleFile,
|
|
1390
|
+
finish: handleFinish,
|
|
1391
|
+
};
|
|
1392
|
+
const IGNORE_PART_TYPES = new Set([
|
|
1393
|
+
"abort",
|
|
1394
|
+
"text-end",
|
|
1395
|
+
"reasoning-end",
|
|
1396
|
+
"start",
|
|
1397
|
+
"tool-approval-request",
|
|
1398
|
+
]);
|
|
1399
|
+
const isVisibleStreamPart = (part, flags) => {
|
|
1400
|
+
switch (part.type) {
|
|
1401
|
+
case "abort":
|
|
1402
|
+
case "text-end":
|
|
1403
|
+
case "reasoning-end":
|
|
1404
|
+
case "start":
|
|
1405
|
+
case "tool-approval-request":
|
|
1406
|
+
case "text-start":
|
|
1407
|
+
case "reasoning-start":
|
|
1408
|
+
case "tool-input-end":
|
|
1409
|
+
return false;
|
|
1410
|
+
case "reasoning-delta":
|
|
1411
|
+
return flags.showReasoning;
|
|
1412
|
+
case "tool-result":
|
|
1413
|
+
return flags.showToolResults;
|
|
1414
|
+
case "start-step":
|
|
1415
|
+
case "finish-step":
|
|
1416
|
+
return flags.showSteps;
|
|
1417
|
+
case "source":
|
|
1418
|
+
return flags.showSources;
|
|
1419
|
+
case "file":
|
|
1420
|
+
return flags.showFiles;
|
|
1421
|
+
case "finish":
|
|
1422
|
+
return flags.showFinishReason;
|
|
1423
|
+
default:
|
|
1424
|
+
return true;
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1427
|
+
const handleStreamPart = async (part, state) => {
|
|
1428
|
+
const handler = STREAM_HANDLERS[part.type];
|
|
1429
|
+
if (handler) {
|
|
1430
|
+
await handler(part, state);
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (IGNORE_PART_TYPES.has(part.type)) {
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
state.resetAssistantView();
|
|
1437
|
+
addChatComponent(state.chatContainer, createInfoMessage("[unknown part]", part));
|
|
1438
|
+
};
|
|
1439
|
+
export const renderFullStreamWithPiTui = async (stream, options) => {
|
|
1440
|
+
const flags = {
|
|
1441
|
+
showReasoning: options.showReasoning ?? true,
|
|
1442
|
+
showSteps: options.showSteps ?? false,
|
|
1443
|
+
showFinishReason: options.showFinishReason ?? false,
|
|
1444
|
+
showRawToolIo: options.showRawToolIo ?? isRawToolIoEnabledByEnv(),
|
|
1445
|
+
showToolResults: options.showToolResults ?? true,
|
|
1446
|
+
showSources: options.showSources ?? false,
|
|
1447
|
+
showFiles: options.showFiles ?? false,
|
|
1448
|
+
};
|
|
1449
|
+
const activeToolInputs = new Map();
|
|
1450
|
+
const streamedToolCallIds = new Set();
|
|
1451
|
+
const toolViews = new Map();
|
|
1452
|
+
let assistantView = null;
|
|
1453
|
+
let suppressAssistantLeadingSpacer = false;
|
|
1454
|
+
let firstVisiblePartSeen = false;
|
|
1455
|
+
const resetAssistantView = (suppressLeadingSpacer = false) => {
|
|
1456
|
+
if (suppressLeadingSpacer) {
|
|
1457
|
+
suppressAssistantLeadingSpacer = true;
|
|
1458
|
+
}
|
|
1459
|
+
assistantView = null;
|
|
1460
|
+
};
|
|
1461
|
+
const ensureAssistantView = () => {
|
|
1462
|
+
if (!assistantView) {
|
|
1463
|
+
assistantView = new AssistantStreamView(options.markdownTheme);
|
|
1464
|
+
addChatComponent(options.chatContainer, assistantView, {
|
|
1465
|
+
addLeadingSpacer: !suppressAssistantLeadingSpacer,
|
|
1466
|
+
});
|
|
1467
|
+
suppressAssistantLeadingSpacer = false;
|
|
1468
|
+
}
|
|
1469
|
+
return assistantView;
|
|
1470
|
+
};
|
|
1471
|
+
const ensureToolView = (toolCallId, toolName) => {
|
|
1472
|
+
const existing = toolViews.get(toolCallId);
|
|
1473
|
+
if (existing) {
|
|
1474
|
+
existing.setToolName(toolName);
|
|
1475
|
+
return existing;
|
|
1476
|
+
}
|
|
1477
|
+
const view = new ToolCallView(toolCallId, toolName, options.markdownTheme, () => options.ui.requestRender(), flags.showRawToolIo);
|
|
1478
|
+
toolViews.set(toolCallId, view);
|
|
1479
|
+
addChatComponent(options.chatContainer, view);
|
|
1480
|
+
return view;
|
|
1481
|
+
};
|
|
1482
|
+
const state = {
|
|
1483
|
+
flags,
|
|
1484
|
+
activeToolInputs,
|
|
1485
|
+
streamedToolCallIds,
|
|
1486
|
+
resetAssistantView,
|
|
1487
|
+
ensureAssistantView,
|
|
1488
|
+
ensureToolView,
|
|
1489
|
+
getToolView: (toolCallId) => toolViews.get(toolCallId),
|
|
1490
|
+
chatContainer: options.chatContainer,
|
|
1491
|
+
};
|
|
1492
|
+
try {
|
|
1493
|
+
for await (const rawPart of stream) {
|
|
1494
|
+
const part = rawPart;
|
|
1495
|
+
if (!firstVisiblePartSeen && isVisibleStreamPart(part, flags)) {
|
|
1496
|
+
firstVisiblePartSeen = true;
|
|
1497
|
+
options.onFirstVisiblePart?.();
|
|
1498
|
+
}
|
|
1499
|
+
await handleStreamPart(part, state);
|
|
1500
|
+
options.ui.requestRender();
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
finally {
|
|
1504
|
+
for (const view of toolViews.values()) {
|
|
1505
|
+
view.dispose();
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
//# sourceMappingURL=pi-tui-stream-renderer.js.map
|