@gajae-code/coding-agent 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8662 -0
- package/README.md +37 -0
- package/dist/types/async/index.d.ts +2 -0
- package/dist/types/async/job-manager.d.ts +101 -0
- package/dist/types/async/support.d.ts +2 -0
- package/dist/types/autoresearch/dashboard.d.ts +4 -0
- package/dist/types/autoresearch/git.d.ts +36 -0
- package/dist/types/autoresearch/helpers.d.ts +24 -0
- package/dist/types/autoresearch/index.d.ts +2 -0
- package/dist/types/autoresearch/state.d.ts +17 -0
- package/dist/types/autoresearch/storage.d.ts +142 -0
- package/dist/types/autoresearch/tools/init-experiment.d.ts +31 -0
- package/dist/types/autoresearch/tools/log-experiment.d.ts +23 -0
- package/dist/types/autoresearch/tools/run-experiment.d.ts +8 -0
- package/dist/types/autoresearch/tools/update-notes.d.ts +12 -0
- package/dist/types/autoresearch/types.d.ts +154 -0
- package/dist/types/capability/context-file.d.ts +17 -0
- package/dist/types/capability/extension-module.d.ts +15 -0
- package/dist/types/capability/extension.d.ts +28 -0
- package/dist/types/capability/fs.d.ts +20 -0
- package/dist/types/capability/hook.d.ts +19 -0
- package/dist/types/capability/index.d.ts +80 -0
- package/dist/types/capability/instruction.d.ts +17 -0
- package/dist/types/capability/mcp.d.ts +45 -0
- package/dist/types/capability/prompt.d.ts +15 -0
- package/dist/types/capability/rule.d.ts +61 -0
- package/dist/types/capability/settings.d.ts +15 -0
- package/dist/types/capability/skill.d.ts +36 -0
- package/dist/types/capability/slash-command.d.ts +17 -0
- package/dist/types/capability/ssh.d.ts +23 -0
- package/dist/types/capability/system-prompt.d.ts +15 -0
- package/dist/types/capability/tool.d.ts +19 -0
- package/dist/types/capability/types.d.ts +154 -0
- package/dist/types/cli/agents-cli.d.ts +12 -0
- package/dist/types/cli/args.d.ts +53 -0
- package/dist/types/cli/auth-broker-cli.d.ts +25 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +18 -0
- package/dist/types/cli/classify-install-target.d.ts +18 -0
- package/dist/types/cli/commands/init-xdg.d.ts +1 -0
- package/dist/types/cli/config-cli.d.ts +22 -0
- package/dist/types/cli/file-processor.d.ts +11 -0
- package/dist/types/cli/grep-cli.d.ts +17 -0
- package/dist/types/cli/initial-message.d.ts +17 -0
- package/dist/types/cli/list-models.d.ts +30 -0
- package/dist/types/cli/plugin-cli.d.ts +32 -0
- package/dist/types/cli/read-cli.d.ts +4 -0
- package/dist/types/cli/session-picker.d.ts +3 -0
- package/dist/types/cli/setup-cli.d.ts +31 -0
- package/dist/types/cli/shell-cli.d.ts +8 -0
- package/dist/types/cli/ssh-cli.d.ts +21 -0
- package/dist/types/cli/stats-cli.d.ts +17 -0
- package/dist/types/cli/update-cli.d.ts +38 -0
- package/dist/types/cli/web-search-cli.d.ts +20 -0
- package/dist/types/cli/worktree-cli.d.ts +26 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/acp.d.ts +12 -0
- package/dist/types/commands/agents.d.ts +34 -0
- package/dist/types/commands/auth-broker.d.ts +54 -0
- package/dist/types/commands/auth-gateway.d.ts +32 -0
- package/dist/types/commands/codex-native-hook.d.ts +6 -0
- package/dist/types/commands/commit.d.ts +27 -0
- package/dist/types/commands/config.d.ts +30 -0
- package/dist/types/commands/deep-interview.d.ts +7 -0
- package/dist/types/commands/gjc-runtime-bridge.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +42 -0
- package/dist/types/commands/launch.d.ts +121 -0
- package/dist/types/commands/plugin.d.ts +52 -0
- package/dist/types/commands/question.d.ts +7 -0
- package/dist/types/commands/ralplan.d.ts +7 -0
- package/dist/types/commands/read.d.ts +15 -0
- package/dist/types/commands/setup.d.ts +48 -0
- package/dist/types/commands/shell.d.ts +21 -0
- package/dist/types/commands/ssh.d.ts +48 -0
- package/dist/types/commands/state.d.ts +7 -0
- package/dist/types/commands/stats.d.ts +25 -0
- package/dist/types/commands/team.d.ts +24 -0
- package/dist/types/commands/ultragoal.d.ts +7 -0
- package/dist/types/commands/update.d.ts +20 -0
- package/dist/types/commands/web-search.d.ts +33 -0
- package/dist/types/commands/worktree.d.ts +34 -0
- package/dist/types/commit/agentic/agent.d.ts +31 -0
- package/dist/types/commit/agentic/fallback.d.ts +5 -0
- package/dist/types/commit/agentic/index.d.ts +2 -0
- package/dist/types/commit/agentic/state.d.ts +58 -0
- package/dist/types/commit/agentic/tools/analyze-file.d.ts +19 -0
- package/dist/types/commit/agentic/tools/git-file-diff.d.ts +10 -0
- package/dist/types/commit/agentic/tools/git-hunk.d.ts +9 -0
- package/dist/types/commit/agentic/tools/git-overview.d.ts +9 -0
- package/dist/types/commit/agentic/tools/index.d.ts +16 -0
- package/dist/types/commit/agentic/tools/propose-changelog.d.ts +28 -0
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +36 -0
- package/dist/types/commit/agentic/tools/recent-commits.d.ts +7 -0
- package/dist/types/commit/agentic/tools/schemas.d.ts +27 -0
- package/dist/types/commit/agentic/tools/split-commit.d.ts +53 -0
- package/dist/types/commit/agentic/topo-sort.d.ts +4 -0
- package/dist/types/commit/agentic/trivial.d.ts +7 -0
- package/dist/types/commit/agentic/validation.d.ts +20 -0
- package/dist/types/commit/analysis/conventional.d.ts +22 -0
- package/dist/types/commit/analysis/index.d.ts +4 -0
- package/dist/types/commit/analysis/scope.d.ts +6 -0
- package/dist/types/commit/analysis/summary.d.ts +19 -0
- package/dist/types/commit/analysis/validation.d.ts +8 -0
- package/dist/types/commit/changelog/detect.d.ts +2 -0
- package/dist/types/commit/changelog/generate.d.ts +30 -0
- package/dist/types/commit/changelog/index.d.ts +30 -0
- package/dist/types/commit/changelog/parse.d.ts +2 -0
- package/dist/types/commit/cli.d.ts +3 -0
- package/dist/types/commit/git/diff.d.ts +5 -0
- package/dist/types/commit/index.d.ts +4 -0
- package/dist/types/commit/map-reduce/index.d.ts +28 -0
- package/dist/types/commit/map-reduce/map-phase.d.ts +17 -0
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +13 -0
- package/dist/types/commit/map-reduce/utils.d.ts +2 -0
- package/dist/types/commit/message.d.ts +2 -0
- package/dist/types/commit/model-selection.d.ts +15 -0
- package/dist/types/commit/pipeline.d.ts +5 -0
- package/dist/types/commit/shared-llm.d.ts +54 -0
- package/dist/types/commit/types.d.ts +78 -0
- package/dist/types/commit/utils/exclusions.d.ts +4 -0
- package/dist/types/commit/utils.d.ts +20 -0
- package/dist/types/config/config-file.d.ts +58 -0
- package/dist/types/config/file-lock.d.ts +6 -0
- package/dist/types/config/keybindings.d.ts +334 -0
- package/dist/types/config/model-equivalence.d.ts +24 -0
- package/dist/types/config/model-registry.d.ts +390 -0
- package/dist/types/config/model-resolver.d.ts +230 -0
- package/dist/types/config/models-config-schema.d.ts +504 -0
- package/dist/types/config/prompt-templates.d.ts +32 -0
- package/dist/types/config/resolve-config-value.d.ts +17 -0
- package/dist/types/config/settings-schema.d.ts +3337 -0
- package/dist/types/config/settings.d.ts +132 -0
- package/dist/types/config/skill-settings-defaults.d.ts +14 -0
- package/dist/types/config.d.ts +66 -0
- package/dist/types/cursor.d.ts +24 -0
- package/dist/types/dap/client.d.ts +38 -0
- package/dist/types/dap/config.d.ts +6 -0
- package/dist/types/dap/index.d.ts +4 -0
- package/dist/types/dap/session.d.ts +108 -0
- package/dist/types/dap/types.d.ts +524 -0
- package/dist/types/debug/index.d.ts +15 -0
- package/dist/types/debug/log-formatting.d.ts +4 -0
- package/dist/types/debug/log-viewer.d.ts +68 -0
- package/dist/types/debug/profiler.d.ts +24 -0
- package/dist/types/debug/raw-sse-buffer.d.ts +44 -0
- package/dist/types/debug/raw-sse.d.ts +16 -0
- package/dist/types/debug/report-bundle.d.ts +55 -0
- package/dist/types/debug/system-info.d.ts +26 -0
- package/dist/types/defaults/gjc-defaults.d.ts +44 -0
- package/dist/types/discovery/agents-md.d.ts +1 -0
- package/dist/types/discovery/agents.d.ts +12 -0
- package/dist/types/discovery/builtin.d.ts +1 -0
- package/dist/types/discovery/claude-plugins.d.ts +1 -0
- package/dist/types/discovery/claude.d.ts +1 -0
- package/dist/types/discovery/cline.d.ts +1 -0
- package/dist/types/discovery/codex.d.ts +1 -0
- package/dist/types/discovery/cursor.d.ts +16 -0
- package/dist/types/discovery/gemini.d.ts +1 -0
- package/dist/types/discovery/github.d.ts +1 -0
- package/dist/types/discovery/helpers.d.ts +268 -0
- package/dist/types/discovery/index.d.ts +48 -0
- package/dist/types/discovery/mcp-json.d.ts +1 -0
- package/dist/types/discovery/opencode.d.ts +1 -0
- package/dist/types/discovery/plugin-dir-roots.d.ts +15 -0
- package/dist/types/discovery/ssh.d.ts +1 -0
- package/dist/types/discovery/substitute-plugin-root.d.ts +5 -0
- package/dist/types/discovery/vscode.d.ts +1 -0
- package/dist/types/discovery/windsurf.d.ts +13 -0
- package/dist/types/edit/apply-patch/index.d.ts +35 -0
- package/dist/types/edit/apply-patch/parser.d.ts +34 -0
- package/dist/types/edit/diff.d.ts +59 -0
- package/dist/types/edit/file-read-cache.d.ts +25 -0
- package/dist/types/edit/index.d.ts +58 -0
- package/dist/types/edit/modes/apply-patch.d.ts +24 -0
- package/dist/types/edit/modes/patch.d.ts +99 -0
- package/dist/types/edit/modes/replace.d.ts +142 -0
- package/dist/types/edit/normalize.d.ts +43 -0
- package/dist/types/edit/notebook.d.ts +23 -0
- package/dist/types/edit/read-file.d.ts +2 -0
- package/dist/types/edit/renderer.d.ts +110 -0
- package/dist/types/edit/streaming.d.ts +66 -0
- package/dist/types/eval/backend.d.ts +40 -0
- package/dist/types/eval/index.d.ts +4 -0
- package/dist/types/eval/js/context-manager.d.ts +24 -0
- package/dist/types/eval/js/executor.d.ts +28 -0
- package/dist/types/eval/js/index.d.ts +10 -0
- package/dist/types/eval/js/shared/helpers.d.ts +38 -0
- package/dist/types/eval/js/shared/indirect-eval.d.ts +14 -0
- package/dist/types/eval/js/shared/prelude.d.ts +1 -0
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -0
- package/dist/types/eval/js/shared/runtime.d.ts +47 -0
- package/dist/types/eval/js/shared/types.d.ts +24 -0
- package/dist/types/eval/js/tool-bridge.d.ts +18 -0
- package/dist/types/eval/js/worker-core.d.ts +5 -0
- package/dist/types/eval/js/worker-entry.d.ts +1 -0
- package/dist/types/eval/js/worker-protocol.d.ts +77 -0
- package/dist/types/eval/py/display.d.ts +25 -0
- package/dist/types/eval/py/executor.d.ts +83 -0
- package/dist/types/eval/py/index.d.ts +10 -0
- package/dist/types/eval/py/kernel.d.ts +61 -0
- package/dist/types/eval/py/prelude.d.ts +1 -0
- package/dist/types/eval/py/runtime.d.ts +21 -0
- package/dist/types/eval/py/tool-bridge.d.ts +20 -0
- package/dist/types/eval/types.d.ts +52 -0
- package/dist/types/exa/factory.d.ts +13 -0
- package/dist/types/exa/index.d.ts +20 -0
- package/dist/types/exa/mcp-client.d.ts +45 -0
- package/dist/types/exa/render.d.ts +19 -0
- package/dist/types/exa/researcher.d.ts +9 -0
- package/dist/types/exa/search.d.ts +9 -0
- package/dist/types/exa/types.d.ts +155 -0
- package/dist/types/exa/websets.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +41 -0
- package/dist/types/exec/exec.d.ts +25 -0
- package/dist/types/exec/idle-timeout-watchdog.d.ts +18 -0
- package/dist/types/exec/non-interactive-env.d.ts +1 -0
- package/dist/types/export/custom-share.d.ts +20 -0
- package/dist/types/export/html/index.d.ts +10 -0
- package/dist/types/export/html/template.generated.d.ts +1 -0
- package/dist/types/export/html/template.macro.d.ts +5 -0
- package/dist/types/export/ttsr.d.ts +44 -0
- package/dist/types/extensibility/custom-commands/bundled/ci-green/index.d.ts +9 -0
- package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +10 -0
- package/dist/types/extensibility/custom-commands/index.d.ts +2 -0
- package/dist/types/extensibility/custom-commands/loader.d.ts +29 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +106 -0
- package/dist/types/extensibility/custom-tools/index.d.ts +6 -0
- package/dist/types/extensibility/custom-tools/loader.d.ts +69 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +226 -0
- package/dist/types/extensibility/custom-tools/wrapper.d.ts +23 -0
- package/dist/types/extensibility/extensions/compact-handler.d.ts +26 -0
- package/dist/types/extensibility/extensions/get-commands-handler.d.ts +29 -0
- package/dist/types/extensibility/extensions/index.d.ts +8 -0
- package/dist/types/extensibility/extensions/loader.d.ts +43 -0
- package/dist/types/extensibility/extensions/runner.d.ts +134 -0
- package/dist/types/extensibility/extensions/types.d.ts +864 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +54 -0
- package/dist/types/extensibility/hooks/index.d.ts +5 -0
- package/dist/types/extensibility/hooks/loader.d.ts +89 -0
- package/dist/types/extensibility/hooks/runner.d.ts +126 -0
- package/dist/types/extensibility/hooks/tool-wrapper.d.ts +25 -0
- package/dist/types/extensibility/hooks/types.d.ts +431 -0
- package/dist/types/extensibility/plugins/doctor.d.ts +3 -0
- package/dist/types/extensibility/plugins/git-url.d.ts +34 -0
- package/dist/types/extensibility/plugins/index.d.ts +7 -0
- package/dist/types/extensibility/plugins/installer.d.ts +5 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/extensibility/plugins/loader.d.ts +31 -0
- package/dist/types/extensibility/plugins/manager.d.ts +65 -0
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +41 -0
- package/dist/types/extensibility/plugins/marketplace/fetcher.d.ts +48 -0
- package/dist/types/extensibility/plugins/marketplace/index.d.ts +6 -0
- package/dist/types/extensibility/plugins/marketplace/manager.d.ts +57 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +34 -0
- package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +28 -0
- package/dist/types/extensibility/plugins/marketplace/types.d.ts +130 -0
- package/dist/types/extensibility/plugins/parser.d.ts +52 -0
- package/dist/types/extensibility/plugins/types.d.ts +149 -0
- package/dist/types/extensibility/shared-events.d.ts +279 -0
- package/dist/types/extensibility/skills.d.ts +74 -0
- package/dist/types/extensibility/slash-commands.d.ts +48 -0
- package/dist/types/extensibility/tool-proxy.d.ts +4 -0
- package/dist/types/extensibility/typebox.d.ts +155 -0
- package/dist/types/extensibility/utils.d.ts +12 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +46 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +45 -0
- package/dist/types/gjc-runtime/launch-worktree.d.ts +46 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +204 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +85 -0
- package/dist/types/goals/index.d.ts +3 -0
- package/dist/types/goals/runtime.d.ts +68 -0
- package/dist/types/goals/state.d.ts +35 -0
- package/dist/types/goals/tools/goal-tool.d.ts +128 -0
- package/dist/types/hashline/anchors.d.ts +20 -0
- package/dist/types/hashline/apply.d.ts +14 -0
- package/dist/types/hashline/constants.d.ts +19 -0
- package/dist/types/hashline/diff-preview.d.ts +2 -0
- package/dist/types/hashline/diff.d.ts +17 -0
- package/dist/types/hashline/execute.d.ts +4 -0
- package/dist/types/hashline/hash.d.ts +123 -0
- package/dist/types/hashline/index.d.ts +13 -0
- package/dist/types/hashline/input.d.ts +11 -0
- package/dist/types/hashline/parser.d.ts +7 -0
- package/dist/types/hashline/prefixes.d.ts +7 -0
- package/dist/types/hashline/recovery.d.ts +27 -0
- package/dist/types/hashline/stream.d.ts +2 -0
- package/dist/types/hashline/types.d.ts +77 -0
- package/dist/types/hindsight/backend.d.ts +13 -0
- package/dist/types/hindsight/bank.d.ts +54 -0
- package/dist/types/hindsight/client.d.ts +224 -0
- package/dist/types/hindsight/config.d.ts +51 -0
- package/dist/types/hindsight/content.d.ts +70 -0
- package/dist/types/hindsight/index.d.ts +8 -0
- package/dist/types/hindsight/mental-models.d.ts +125 -0
- package/dist/types/hindsight/state.d.ts +99 -0
- package/dist/types/hindsight/transcript.d.ts +28 -0
- package/dist/types/hooks/codex-native-hooks-config.d.ts +29 -0
- package/dist/types/hooks/native-skill-hook.d.ts +16 -0
- package/dist/types/hooks/skill-keywords.d.ts +17 -0
- package/dist/types/hooks/skill-state.d.ts +80 -0
- package/dist/types/index.d.ts +33 -0
- package/dist/types/internal-urls/agent-protocol.d.ts +12 -0
- package/dist/types/internal-urls/artifact-protocol.d.ts +6 -0
- package/dist/types/internal-urls/docs-index.generated.d.ts +2 -0
- package/dist/types/internal-urls/gjc-protocol.d.ts +12 -0
- package/dist/types/internal-urls/index.d.ts +20 -0
- package/dist/types/internal-urls/issue-pr-protocol.d.ts +17 -0
- package/dist/types/internal-urls/json-query.d.ts +30 -0
- package/dist/types/internal-urls/local-protocol.d.ts +39 -0
- package/dist/types/internal-urls/mcp-protocol.d.ts +12 -0
- package/dist/types/internal-urls/memory-protocol.d.ts +23 -0
- package/dist/types/internal-urls/parse.d.ts +19 -0
- package/dist/types/internal-urls/registry-helpers.d.ts +10 -0
- package/dist/types/internal-urls/router.d.ts +14 -0
- package/dist/types/internal-urls/rule-protocol.d.ts +6 -0
- package/dist/types/internal-urls/skill-protocol.d.ts +13 -0
- package/dist/types/internal-urls/types.d.ts +105 -0
- package/dist/types/lsp/client.d.ts +65 -0
- package/dist/types/lsp/clients/biome-client.d.ts +16 -0
- package/dist/types/lsp/clients/index.d.ts +19 -0
- package/dist/types/lsp/clients/lsp-linter-client.d.ts +16 -0
- package/dist/types/lsp/clients/swiftlint-client.d.ts +20 -0
- package/dist/types/lsp/config.d.ts +65 -0
- package/dist/types/lsp/edits.d.ts +23 -0
- package/dist/types/lsp/index.d.ts +130 -0
- package/dist/types/lsp/lspmux.d.ts +58 -0
- package/dist/types/lsp/render.d.ts +32 -0
- package/dist/types/lsp/startup-events.d.ts +11 -0
- package/dist/types/lsp/types.d.ts +302 -0
- package/dist/types/lsp/utils.d.ts +108 -0
- package/dist/types/main.d.ts +50 -0
- package/dist/types/memories/index.d.ts +28 -0
- package/dist/types/memories/storage.d.ts +110 -0
- package/dist/types/memory-backend/index.d.ts +4 -0
- package/dist/types/memory-backend/local-backend.d.ts +9 -0
- package/dist/types/memory-backend/off-backend.d.ts +7 -0
- package/dist/types/memory-backend/resolve.d.ts +15 -0
- package/dist/types/memory-backend/types.d.ts +61 -0
- package/dist/types/modes/acp/acp-agent.d.ts +61 -0
- package/dist/types/modes/acp/acp-client-bridge.d.ts +9 -0
- package/dist/types/modes/acp/acp-event-mapper.d.ts +32 -0
- package/dist/types/modes/acp/acp-mode.d.ts +5 -0
- package/dist/types/modes/acp/index.d.ts +2 -0
- package/dist/types/modes/acp/terminal-auth.d.ts +6 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +21 -0
- package/dist/types/modes/components/assistant-message.d.ts +16 -0
- package/dist/types/modes/components/bash-execution.d.ts +29 -0
- package/dist/types/modes/components/bordered-loader.d.ts +11 -0
- package/dist/types/modes/components/branch-summary-message.d.ts +13 -0
- package/dist/types/modes/components/btw-panel.d.ts +16 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +13 -0
- package/dist/types/modes/components/countdown-timer.d.ts +14 -0
- package/dist/types/modes/components/custom-editor.d.ts +47 -0
- package/dist/types/modes/components/custom-message.d.ts +15 -0
- package/dist/types/modes/components/diff.d.ts +11 -0
- package/dist/types/modes/components/dynamic-border.d.ts +14 -0
- package/dist/types/modes/components/eval-execution.d.ts +23 -0
- package/dist/types/modes/components/execution-shared.d.ts +46 -0
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +26 -0
- package/dist/types/modes/components/extensions/extension-list.d.ts +39 -0
- package/dist/types/modes/components/extensions/index.d.ts +8 -0
- package/dist/types/modes/components/extensions/inspector-panel.d.ts +8 -0
- package/dist/types/modes/components/extensions/state-manager.d.ts +50 -0
- package/dist/types/modes/components/extensions/types.d.ts +151 -0
- package/dist/types/modes/components/footer.d.ts +30 -0
- package/dist/types/modes/components/history-search.d.ts +7 -0
- package/dist/types/modes/components/hook-editor.d.ts +18 -0
- package/dist/types/modes/components/hook-input.d.ts +15 -0
- package/dist/types/modes/components/hook-message.d.ts +15 -0
- package/dist/types/modes/components/hook-selector.d.ts +23 -0
- package/dist/types/modes/components/index.d.ts +35 -0
- package/dist/types/modes/components/keybinding-hints.d.ts +40 -0
- package/dist/types/modes/components/login-dialog.d.ts +32 -0
- package/dist/types/modes/components/message-frame.d.ts +42 -0
- package/dist/types/modes/components/model-selector.d.ts +26 -0
- package/dist/types/modes/components/oauth-selector.d.ts +14 -0
- package/dist/types/modes/components/plugin-selector.d.ts +26 -0
- package/dist/types/modes/components/plugin-settings.d.ts +66 -0
- package/dist/types/modes/components/provider-onboarding-selector.d.ts +7 -0
- package/dist/types/modes/components/queue-mode-selector.d.ts +9 -0
- package/dist/types/modes/components/read-tool-group.d.ts +30 -0
- package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +25 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +11 -0
- package/dist/types/modes/components/session-selector.d.ts +30 -0
- package/dist/types/modes/components/settings-defs.d.ts +50 -0
- package/dist/types/modes/components/settings-selector.d.ts +54 -0
- package/dist/types/modes/components/show-images-selector.d.ts +9 -0
- package/dist/types/modes/components/skill-hud/render.d.ts +2 -0
- package/dist/types/modes/components/skill-message.d.ts +9 -0
- package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -0
- package/dist/types/modes/components/status-line/git-utils.d.ts +22 -0
- package/dist/types/modes/components/status-line/index.d.ts +4 -0
- package/dist/types/modes/components/status-line/presets.d.ts +3 -0
- package/dist/types/modes/components/status-line/segments.d.ts +5 -0
- package/dist/types/modes/components/status-line/separators.d.ts +3 -0
- package/dist/types/modes/components/status-line/token-rate.d.ts +10 -0
- package/dist/types/modes/components/status-line/types.d.ts +80 -0
- package/dist/types/modes/components/status-line.d.ts +80 -0
- package/dist/types/modes/components/theme-selector.d.ts +10 -0
- package/dist/types/modes/components/thinking-selector.d.ts +10 -0
- package/dist/types/modes/components/todo-reminder.d.ts +13 -0
- package/dist/types/modes/components/tool-execution.d.ts +53 -0
- package/dist/types/modes/components/tree-selector.d.ts +31 -0
- package/dist/types/modes/components/ttsr-notification.d.ts +13 -0
- package/dist/types/modes/components/user-message-selector.d.ts +28 -0
- package/dist/types/modes/components/user-message.d.ts +7 -0
- package/dist/types/modes/components/visual-truncate.d.ts +19 -0
- package/dist/types/modes/components/welcome.d.ts +34 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +10 -0
- package/dist/types/modes/controllers/command-controller-shared.d.ts +47 -0
- package/dist/types/modes/controllers/command-controller.d.ts +36 -0
- package/dist/types/modes/controllers/event-controller.d.ts +12 -0
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +80 -0
- package/dist/types/modes/controllers/input-controller.d.ts +35 -0
- package/dist/types/modes/controllers/runtime-mcp-command-controller.d.ts +10 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +46 -0
- package/dist/types/modes/controllers/ssh-command-controller.d.ts +10 -0
- package/dist/types/modes/controllers/todo-command-controller.d.ts +7 -0
- package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
- package/dist/types/modes/index.d.ts +9 -0
- package/dist/types/modes/interactive-mode.d.ts +271 -0
- package/dist/types/modes/loop-limit.d.ts +22 -0
- package/dist/types/modes/oauth-manual-input.d.ts +8 -0
- package/dist/types/modes/print-mode.d.ts +27 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +46 -0
- package/dist/types/modes/rpc/host-tools.d.ts +16 -0
- package/dist/types/modes/rpc/host-uris.d.ts +38 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +249 -0
- package/dist/types/modes/rpc/rpc-mode.d.ts +17 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +586 -0
- package/dist/types/modes/runtime-init.d.ts +21 -0
- package/dist/types/modes/session-observer-registry.d.ts +26 -0
- package/dist/types/modes/shared.d.ts +15 -0
- package/dist/types/modes/theme/defaults/index.d.ts +9559 -0
- package/dist/types/modes/theme/mermaid-cache.d.ts +9 -0
- package/dist/types/modes/theme/shimmer.d.ts +38 -0
- package/dist/types/modes/theme/theme.d.ts +273 -0
- package/dist/types/modes/types.d.ts +278 -0
- package/dist/types/modes/utils/context-usage.d.ts +47 -0
- package/dist/types/modes/utils/hotkeys-markdown.d.ts +5 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +10 -0
- package/dist/types/modes/utils/tools-markdown.d.ts +5 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +53 -0
- package/dist/types/plan-mode/approved-plan.d.ts +49 -0
- package/dist/types/plan-mode/state.d.ts +6 -0
- package/dist/types/registry/agent-registry.d.ts +62 -0
- package/dist/types/runtime-mcp/client.d.ts +74 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +53 -0
- package/dist/types/runtime-mcp/config.d.ts +75 -0
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +7 -0
- package/dist/types/runtime-mcp/index.d.ts +18 -0
- package/dist/types/runtime-mcp/json-rpc.d.ts +22 -0
- package/dist/types/runtime-mcp/loader.d.ts +43 -0
- package/dist/types/runtime-mcp/manager.d.ts +193 -0
- package/dist/types/runtime-mcp/oauth-discovery.d.ts +40 -0
- package/dist/types/runtime-mcp/oauth-flow.d.ts +59 -0
- package/dist/types/runtime-mcp/render.d.ts +25 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +16 -0
- package/dist/types/runtime-mcp/smithery-connect.d.ts +38 -0
- package/dist/types/runtime-mcp/smithery-registry.d.ts +51 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +86 -0
- package/dist/types/runtime-mcp/tool-cache.d.ts +8 -0
- package/dist/types/runtime-mcp/transports/http.d.ts +36 -0
- package/dist/types/runtime-mcp/transports/index.d.ts +5 -0
- package/dist/types/runtime-mcp/transports/stdio.d.ts +32 -0
- package/dist/types/runtime-mcp/types.d.ts +333 -0
- package/dist/types/sdk.d.ts +216 -0
- package/dist/types/secrets/index.d.ts +9 -0
- package/dist/types/secrets/obfuscator.d.ts +23 -0
- package/dist/types/secrets/regex.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +930 -0
- package/dist/types/session/agent-storage.d.ts +100 -0
- package/dist/types/session/artifacts.d.ts +61 -0
- package/dist/types/session/auth-broker-config.d.ts +13 -0
- package/dist/types/session/auth-storage.d.ts +6 -0
- package/dist/types/session/blob-store.d.ts +63 -0
- package/dist/types/session/client-bridge.d.ts +88 -0
- package/dist/types/session/history-storage.d.ts +16 -0
- package/dist/types/session/messages.d.ts +162 -0
- package/dist/types/session/session-dump-format.d.ts +22 -0
- package/dist/types/session/session-manager.d.ts +549 -0
- package/dist/types/session/session-storage.d.ts +82 -0
- package/dist/types/session/streaming-output.d.ts +185 -0
- package/dist/types/session/tool-choice-queue.d.ts +78 -0
- package/dist/types/session/yield-queue.d.ts +24 -0
- package/dist/types/setup/model-onboarding-guidance.d.ts +8 -0
- package/dist/types/setup/provider-onboarding.d.ts +28 -0
- package/dist/types/skill-state/active-state.d.ts +50 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +18 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +23 -0
- package/dist/types/slash-commands/helpers/context-report.d.ts +7 -0
- package/dist/types/slash-commands/helpers/format.d.ts +10 -0
- package/dist/types/slash-commands/helpers/mcp.d.ts +3 -0
- package/dist/types/slash-commands/helpers/parse.d.ts +33 -0
- package/dist/types/slash-commands/helpers/ssh.d.ts +3 -0
- package/dist/types/slash-commands/helpers/todo.d.ts +3 -0
- package/dist/types/slash-commands/helpers/usage-report.d.ts +7 -0
- package/dist/types/slash-commands/types.d.ts +118 -0
- package/dist/types/ssh/config-writer.d.ts +49 -0
- package/dist/types/ssh/connection-manager.d.ts +33 -0
- package/dist/types/ssh/ssh-executor.d.ts +37 -0
- package/dist/types/ssh/sshfs-mount.d.ts +6 -0
- package/dist/types/ssh/utils.d.ts +2 -0
- package/dist/types/stt/downloader.d.ts +9 -0
- package/dist/types/stt/index.d.ts +3 -0
- package/dist/types/stt/recorder.d.ts +13 -0
- package/dist/types/stt/setup.d.ts +18 -0
- package/dist/types/stt/stt-controller.d.ts +16 -0
- package/dist/types/stt/transcriber.d.ts +16 -0
- package/dist/types/system-prompt.d.ts +93 -0
- package/dist/types/task/agents.d.ts +28 -0
- package/dist/types/task/commands.d.ts +35 -0
- package/dist/types/task/discovery.d.ts +19 -0
- package/dist/types/task/executor.d.ts +106 -0
- package/dist/types/task/gjc-command.d.ts +7 -0
- package/dist/types/task/index.d.ts +38 -0
- package/dist/types/task/name-generator.d.ts +16 -0
- package/dist/types/task/output-manager.d.ts +36 -0
- package/dist/types/task/parallel.d.ts +34 -0
- package/dist/types/task/render.d.ts +22 -0
- package/dist/types/task/simple-mode.d.ts +8 -0
- package/dist/types/task/subprocess-tool-registry.d.ts +72 -0
- package/dist/types/task/types.d.ts +295 -0
- package/dist/types/task/worktree.d.ts +94 -0
- package/dist/types/thinking.d.ts +30 -0
- package/dist/types/tool-discovery/tool-index.d.ts +112 -0
- package/dist/types/tools/archive-reader.d.ts +40 -0
- package/dist/types/tools/ask.d.ts +109 -0
- package/dist/types/tools/ast-edit.d.ts +77 -0
- package/dist/types/tools/ast-grep.d.ts +69 -0
- package/dist/types/tools/auto-generated-guard.d.ts +17 -0
- package/dist/types/tools/bash-command-fixup.d.ts +11 -0
- package/dist/types/tools/bash-interactive.d.ts +16 -0
- package/dist/types/tools/bash-interceptor.d.ts +24 -0
- package/dist/types/tools/bash-pty-selection.d.ts +7 -0
- package/dist/types/tools/bash-skill-urls.d.ts +31 -0
- package/dist/types/tools/bash.d.ts +130 -0
- package/dist/types/tools/browser/attach.d.ts +34 -0
- package/dist/types/tools/browser/launch.d.ts +62 -0
- package/dist/types/tools/browser/readable.d.ts +17 -0
- package/dist/types/tools/browser/registry.d.ts +42 -0
- package/dist/types/tools/browser/render.d.ts +50 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +144 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +63 -0
- package/dist/types/tools/browser/tab-worker-entry.d.ts +1 -0
- package/dist/types/tools/browser/tab-worker.d.ts +19 -0
- package/dist/types/tools/browser.d.ts +114 -0
- package/dist/types/tools/calculator.d.ts +76 -0
- package/dist/types/tools/checkpoint.d.ts +63 -0
- package/dist/types/tools/conflict-detect.d.ts +205 -0
- package/dist/types/tools/context.d.ts +19 -0
- package/dist/types/tools/debug.d.ts +209 -0
- package/dist/types/tools/eval.d.ts +108 -0
- package/dist/types/tools/fetch.d.ts +61 -0
- package/dist/types/tools/file-recorder.d.ts +13 -0
- package/dist/types/tools/find.d.ts +95 -0
- package/dist/types/tools/fs-cache-invalidation.d.ts +15 -0
- package/dist/types/tools/gh-format.d.ts +6 -0
- package/dist/types/tools/gh-renderer.d.ts +25 -0
- package/dist/types/tools/gh.d.ts +356 -0
- package/dist/types/tools/github-cache.d.ts +103 -0
- package/dist/types/tools/grouped-file-output.d.ts +36 -0
- package/dist/types/tools/hindsight-recall.d.ts +23 -0
- package/dist/types/tools/hindsight-reflect.d.ts +25 -0
- package/dist/types/tools/hindsight-retain.d.ts +29 -0
- package/dist/types/tools/image-gen.d.ts +78 -0
- package/dist/types/tools/index.d.ts +242 -0
- package/dist/types/tools/inspect-image-renderer.d.ts +26 -0
- package/dist/types/tools/inspect-image.d.ts +31 -0
- package/dist/types/tools/irc.d.ts +79 -0
- package/dist/types/tools/job.d.ts +65 -0
- package/dist/types/tools/json-tree.d.ts +23 -0
- package/dist/types/tools/jtd-to-json-schema.d.ts +29 -0
- package/dist/types/tools/jtd-to-typescript.d.ts +26 -0
- package/dist/types/tools/jtd-utils.d.ts +42 -0
- package/dist/types/tools/list-limit.d.ts +12 -0
- package/dist/types/tools/match-line-format.d.ts +11 -0
- package/dist/types/tools/output-meta.d.ts +204 -0
- package/dist/types/tools/path-utils.d.ts +146 -0
- package/dist/types/tools/plan-mode-guard.d.ts +18 -0
- package/dist/types/tools/read.d.ts +85 -0
- package/dist/types/tools/recipe/index.d.ts +45 -0
- package/dist/types/tools/recipe/render.d.ts +36 -0
- package/dist/types/tools/recipe/runner.d.ts +60 -0
- package/dist/types/tools/recipe/runners/cargo.d.ts +16 -0
- package/dist/types/tools/recipe/runners/index.d.ts +2 -0
- package/dist/types/tools/recipe/runners/just.d.ts +2 -0
- package/dist/types/tools/recipe/runners/make.d.ts +2 -0
- package/dist/types/tools/recipe/runners/pkg.d.ts +2 -0
- package/dist/types/tools/recipe/runners/task.d.ts +2 -0
- package/dist/types/tools/render-mermaid.d.ts +37 -0
- package/dist/types/tools/render-utils.d.ts +158 -0
- package/dist/types/tools/renderers.d.ts +26 -0
- package/dist/types/tools/resolve.d.ts +90 -0
- package/dist/types/tools/review.d.ts +63 -0
- package/dist/types/tools/search-tool-bm25.d.ts +65 -0
- package/dist/types/tools/search.d.ts +93 -0
- package/dist/types/tools/sqlite-reader.d.ts +93 -0
- package/dist/types/tools/ssh.d.ts +67 -0
- package/dist/types/tools/subagent.d.ts +58 -0
- package/dist/types/tools/todo-write.d.ts +120 -0
- package/dist/types/tools/tool-errors.d.ts +33 -0
- package/dist/types/tools/tool-result.d.ts +30 -0
- package/dist/types/tools/tool-timeouts.d.ts +51 -0
- package/dist/types/tools/vim.d.ts +58 -0
- package/dist/types/tools/write.d.ts +59 -0
- package/dist/types/tools/yield.d.ts +25 -0
- package/dist/types/tui/code-cell.d.ts +32 -0
- package/dist/types/tui/file-list.d.ts +22 -0
- package/dist/types/tui/hyperlink.d.ts +42 -0
- package/dist/types/tui/index.d.ts +11 -0
- package/dist/types/tui/output-block.d.ts +28 -0
- package/dist/types/tui/status-line.d.ts +18 -0
- package/dist/types/tui/tree-list.d.ts +19 -0
- package/dist/types/tui/types.d.ts +13 -0
- package/dist/types/tui/utils.d.ts +36 -0
- package/dist/types/utils/changelog.d.ts +20 -0
- package/dist/types/utils/clipboard.d.ts +22 -0
- package/dist/types/utils/command-args.d.ts +9 -0
- package/dist/types/utils/commit-message-generator.d.ts +7 -0
- package/dist/types/utils/edit-mode.d.ts +13 -0
- package/dist/types/utils/event-bus.d.ts +6 -0
- package/dist/types/utils/external-editor.d.ts +17 -0
- package/dist/types/utils/file-display-mode.d.ts +27 -0
- package/dist/types/utils/file-mentions.d.ts +11 -0
- package/dist/types/utils/git.d.ts +361 -0
- package/dist/types/utils/image-loading.d.ts +26 -0
- package/dist/types/utils/image-resize.d.ts +39 -0
- package/dist/types/utils/lang-from-path.d.ts +8 -0
- package/dist/types/utils/markit.d.ts +7 -0
- package/dist/types/utils/open.d.ts +2 -0
- package/dist/types/utils/session-color.d.ts +10 -0
- package/dist/types/utils/shell-snapshot.d.ts +5 -0
- package/dist/types/utils/sixel.d.ts +21 -0
- package/dist/types/utils/title-generator.d.ts +31 -0
- package/dist/types/utils/tool-choice.d.ts +7 -0
- package/dist/types/utils/tools-manager.d.ts +9 -0
- package/dist/types/vim/buffer.d.ts +41 -0
- package/dist/types/vim/commands.d.ts +6 -0
- package/dist/types/vim/engine.d.ts +47 -0
- package/dist/types/vim/parser.d.ts +3 -0
- package/dist/types/vim/render.d.ts +25 -0
- package/dist/types/vim/types.d.ts +182 -0
- package/dist/types/web/kagi.d.ts +23 -0
- package/dist/types/web/parallel.d.ts +58 -0
- package/dist/types/web/scrapers/artifacthub.d.ts +6 -0
- package/dist/types/web/scrapers/arxiv.d.ts +5 -0
- package/dist/types/web/scrapers/aur.d.ts +5 -0
- package/dist/types/web/scrapers/biorxiv.d.ts +5 -0
- package/dist/types/web/scrapers/bluesky.d.ts +5 -0
- package/dist/types/web/scrapers/brew.d.ts +5 -0
- package/dist/types/web/scrapers/cheatsh.d.ts +8 -0
- package/dist/types/web/scrapers/chocolatey.d.ts +5 -0
- package/dist/types/web/scrapers/choosealicense.d.ts +2 -0
- package/dist/types/web/scrapers/cisa-kev.d.ts +5 -0
- package/dist/types/web/scrapers/clojars.d.ts +5 -0
- package/dist/types/web/scrapers/coingecko.d.ts +5 -0
- package/dist/types/web/scrapers/crates-io.d.ts +5 -0
- package/dist/types/web/scrapers/crossref.d.ts +2 -0
- package/dist/types/web/scrapers/devto.d.ts +5 -0
- package/dist/types/web/scrapers/discogs.d.ts +8 -0
- package/dist/types/web/scrapers/discourse.d.ts +5 -0
- package/dist/types/web/scrapers/dockerhub.d.ts +5 -0
- package/dist/types/web/scrapers/docs-rs.d.ts +2 -0
- package/dist/types/web/scrapers/fdroid.d.ts +5 -0
- package/dist/types/web/scrapers/firefox-addons.d.ts +2 -0
- package/dist/types/web/scrapers/flathub.d.ts +2 -0
- package/dist/types/web/scrapers/github-gist.d.ts +5 -0
- package/dist/types/web/scrapers/github.d.ts +12 -0
- package/dist/types/web/scrapers/gitlab.d.ts +5 -0
- package/dist/types/web/scrapers/go-pkg.d.ts +5 -0
- package/dist/types/web/scrapers/hackage.d.ts +5 -0
- package/dist/types/web/scrapers/hackernews.d.ts +2 -0
- package/dist/types/web/scrapers/hex.d.ts +5 -0
- package/dist/types/web/scrapers/huggingface.d.ts +2 -0
- package/dist/types/web/scrapers/iacr.d.ts +5 -0
- package/dist/types/web/scrapers/index.d.ts +84 -0
- package/dist/types/web/scrapers/jetbrains-marketplace.d.ts +2 -0
- package/dist/types/web/scrapers/lemmy.d.ts +2 -0
- package/dist/types/web/scrapers/lobsters.d.ts +5 -0
- package/dist/types/web/scrapers/mastodon.d.ts +5 -0
- package/dist/types/web/scrapers/maven.d.ts +6 -0
- package/dist/types/web/scrapers/mdn.d.ts +2 -0
- package/dist/types/web/scrapers/metacpan.d.ts +5 -0
- package/dist/types/web/scrapers/musicbrainz.d.ts +5 -0
- package/dist/types/web/scrapers/npm.d.ts +5 -0
- package/dist/types/web/scrapers/nuget.d.ts +5 -0
- package/dist/types/web/scrapers/nvd.d.ts +5 -0
- package/dist/types/web/scrapers/ollama.d.ts +2 -0
- package/dist/types/web/scrapers/open-vsx.d.ts +5 -0
- package/dist/types/web/scrapers/opencorporates.d.ts +5 -0
- package/dist/types/web/scrapers/openlibrary.d.ts +5 -0
- package/dist/types/web/scrapers/orcid.d.ts +5 -0
- package/dist/types/web/scrapers/osv.d.ts +5 -0
- package/dist/types/web/scrapers/packagist.d.ts +5 -0
- package/dist/types/web/scrapers/pub-dev.d.ts +5 -0
- package/dist/types/web/scrapers/pubmed.d.ts +5 -0
- package/dist/types/web/scrapers/pypi.d.ts +5 -0
- package/dist/types/web/scrapers/rawg.d.ts +2 -0
- package/dist/types/web/scrapers/readthedocs.d.ts +2 -0
- package/dist/types/web/scrapers/reddit.d.ts +5 -0
- package/dist/types/web/scrapers/repology.d.ts +5 -0
- package/dist/types/web/scrapers/rfc.d.ts +5 -0
- package/dist/types/web/scrapers/rubygems.d.ts +5 -0
- package/dist/types/web/scrapers/searchcode.d.ts +2 -0
- package/dist/types/web/scrapers/sec-edgar.d.ts +5 -0
- package/dist/types/web/scrapers/semantic-scholar.d.ts +2 -0
- package/dist/types/web/scrapers/snapcraft.d.ts +2 -0
- package/dist/types/web/scrapers/sourcegraph.d.ts +2 -0
- package/dist/types/web/scrapers/spdx.d.ts +5 -0
- package/dist/types/web/scrapers/spotify.d.ts +8 -0
- package/dist/types/web/scrapers/stackoverflow.d.ts +6 -0
- package/dist/types/web/scrapers/terraform.d.ts +5 -0
- package/dist/types/web/scrapers/tldr.d.ts +7 -0
- package/dist/types/web/scrapers/twitter.d.ts +5 -0
- package/dist/types/web/scrapers/types.d.ts +78 -0
- package/dist/types/web/scrapers/utils.d.ts +26 -0
- package/dist/types/web/scrapers/vimeo.d.ts +5 -0
- package/dist/types/web/scrapers/vscode-marketplace.d.ts +5 -0
- package/dist/types/web/scrapers/w3c.d.ts +2 -0
- package/dist/types/web/scrapers/wikidata.d.ts +5 -0
- package/dist/types/web/scrapers/wikipedia.d.ts +5 -0
- package/dist/types/web/scrapers/youtube.d.ts +5 -0
- package/dist/types/web/search/index.d.ts +84 -0
- package/dist/types/web/search/provider.d.ts +21 -0
- package/dist/types/web/search/providers/anthropic.d.ts +32 -0
- package/dist/types/web/search/providers/base.d.ts +67 -0
- package/dist/types/web/search/providers/brave.d.ts +27 -0
- package/dist/types/web/search/providers/codex.d.ts +35 -0
- package/dist/types/web/search/providers/exa.d.ts +52 -0
- package/dist/types/web/search/providers/gemini.d.ts +57 -0
- package/dist/types/web/search/providers/jina.d.ts +26 -0
- package/dist/types/web/search/providers/kagi.d.ts +24 -0
- package/dist/types/web/search/providers/kimi.d.ts +27 -0
- package/dist/types/web/search/providers/parallel.d.ts +15 -0
- package/dist/types/web/search/providers/perplexity.d.ts +38 -0
- package/dist/types/web/search/providers/searxng.d.ts +44 -0
- package/dist/types/web/search/providers/synthetic.d.ts +21 -0
- package/dist/types/web/search/providers/tavily.d.ts +29 -0
- package/dist/types/web/search/providers/utils.d.ts +52 -0
- package/dist/types/web/search/providers/zai.d.ts +28 -0
- package/dist/types/web/search/render.d.ts +35 -0
- package/dist/types/web/search/types.d.ts +344 -0
- package/dist/types/web/search/utils.d.ts +4 -0
- package/dist/types/workspace-tree.d.ts +42 -0
- package/examples/README.md +21 -0
- package/examples/custom-tools/README.md +104 -0
- package/examples/custom-tools/hello/index.ts +20 -0
- package/examples/extensions/README.md +141 -0
- package/examples/extensions/api-demo.ts +79 -0
- package/examples/extensions/chalk-logger.ts +25 -0
- package/examples/extensions/hello.ts +31 -0
- package/examples/extensions/pirate.ts +43 -0
- package/examples/extensions/plan-mode.ts +549 -0
- package/examples/extensions/reload-runtime.ts +38 -0
- package/examples/extensions/tools.ts +144 -0
- package/examples/extensions/with-deps/index.ts +36 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +16 -0
- package/examples/hooks/README.md +56 -0
- package/examples/hooks/auto-commit-on-exit.ts +48 -0
- package/examples/hooks/confirm-destructive.ts +58 -0
- package/examples/hooks/custom-compaction.ts +115 -0
- package/examples/hooks/dirty-repo-guard.ts +51 -0
- package/examples/hooks/file-trigger.ts +40 -0
- package/examples/hooks/git-checkpoint.ts +52 -0
- package/examples/hooks/handoff.ts +149 -0
- package/examples/hooks/permission-gate.ts +33 -0
- package/examples/hooks/protected-paths.ts +29 -0
- package/examples/hooks/qna.ts +118 -0
- package/examples/hooks/status-line.ts +39 -0
- package/examples/sdk/01-minimal.ts +21 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +46 -0
- package/examples/sdk/04-skills.ts +43 -0
- package/examples/sdk/06-extensions.ts +82 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +35 -0
- package/examples/sdk/08-prompt-templates.ts +41 -0
- package/examples/sdk/08-slash-commands.ts +46 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
- package/examples/sdk/11-sessions.ts +47 -0
- package/examples/sdk/README.md +172 -0
- package/package.json +533 -0
- package/scripts/build-binary.ts +77 -0
- package/scripts/format-prompts.ts +68 -0
- package/scripts/generate-docs-index.ts +71 -0
- package/scripts/generate-template.ts +33 -0
- package/src/async/index.ts +2 -0
- package/src/async/job-manager.ts +586 -0
- package/src/async/support.ts +6 -0
- package/src/autoresearch/command-resume.md +14 -0
- package/src/autoresearch/dashboard.ts +446 -0
- package/src/autoresearch/git.ts +319 -0
- package/src/autoresearch/helpers.ts +218 -0
- package/src/autoresearch/index.ts +536 -0
- package/src/autoresearch/prompt-setup.md +43 -0
- package/src/autoresearch/prompt.md +103 -0
- package/src/autoresearch/resume-message.md +10 -0
- package/src/autoresearch/state.ts +273 -0
- package/src/autoresearch/storage.ts +699 -0
- package/src/autoresearch/tools/init-experiment.ts +272 -0
- package/src/autoresearch/tools/log-experiment.ts +524 -0
- package/src/autoresearch/tools/run-experiment.ts +475 -0
- package/src/autoresearch/tools/update-notes.ts +109 -0
- package/src/autoresearch/types.ts +168 -0
- package/src/bun-imports.d.ts +28 -0
- package/src/capability/context-file.ts +44 -0
- package/src/capability/extension-module.ts +34 -0
- package/src/capability/extension.ts +47 -0
- package/src/capability/fs.ts +107 -0
- package/src/capability/hook.ts +40 -0
- package/src/capability/index.ts +436 -0
- package/src/capability/instruction.ts +37 -0
- package/src/capability/mcp.ts +74 -0
- package/src/capability/prompt.ts +35 -0
- package/src/capability/rule.ts +244 -0
- package/src/capability/settings.ts +34 -0
- package/src/capability/skill.ts +56 -0
- package/src/capability/slash-command.ts +40 -0
- package/src/capability/ssh.ts +41 -0
- package/src/capability/system-prompt.ts +34 -0
- package/src/capability/tool.ts +38 -0
- package/src/capability/types.ts +168 -0
- package/src/cli/agents-cli.ts +138 -0
- package/src/cli/args.ts +269 -0
- package/src/cli/auth-broker-cli.ts +746 -0
- package/src/cli/auth-gateway-cli.ts +411 -0
- package/src/cli/classify-install-target.ts +50 -0
- package/src/cli/commands/init-xdg.ts +27 -0
- package/src/cli/config-cli.ts +418 -0
- package/src/cli/file-processor.ts +123 -0
- package/src/cli/grep-cli.ts +160 -0
- package/src/cli/initial-message.ts +58 -0
- package/src/cli/list-models.ts +194 -0
- package/src/cli/plugin-cli.ts +942 -0
- package/src/cli/read-cli.ts +57 -0
- package/src/cli/session-picker.ts +52 -0
- package/src/cli/setup-cli.ts +433 -0
- package/src/cli/shell-cli.ts +176 -0
- package/src/cli/ssh-cli.ts +179 -0
- package/src/cli/stats-cli.ts +238 -0
- package/src/cli/update-cli.ts +408 -0
- package/src/cli/web-search-cli.ts +133 -0
- package/src/cli/worktree-cli.ts +291 -0
- package/src/cli.ts +99 -0
- package/src/commands/acp.ts +24 -0
- package/src/commands/agents.ts +57 -0
- package/src/commands/auth-broker.ts +96 -0
- package/src/commands/auth-gateway.ts +63 -0
- package/src/commands/codex-native-hook.ts +11 -0
- package/src/commands/commit.ts +46 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/deep-interview.ts +12 -0
- package/src/commands/gjc-runtime-bridge.ts +81 -0
- package/src/commands/grep.ts +48 -0
- package/src/commands/launch.ts +161 -0
- package/src/commands/plugin.ts +78 -0
- package/src/commands/question.ts +12 -0
- package/src/commands/ralplan.ts +12 -0
- package/src/commands/read.ts +35 -0
- package/src/commands/setup.ts +52 -0
- package/src/commands/shell.ts +29 -0
- package/src/commands/ssh.ts +60 -0
- package/src/commands/state.ts +12 -0
- package/src/commands/stats.ts +29 -0
- package/src/commands/team.ts +130 -0
- package/src/commands/ultragoal.ts +32 -0
- package/src/commands/update.ts +21 -0
- package/src/commands/web-search.ts +42 -0
- package/src/commands/worktree.ts +56 -0
- package/src/commit/agentic/agent.ts +316 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +355 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +25 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +38 -0
- package/src/commit/agentic/state.ts +60 -0
- package/src/commit/agentic/tools/analyze-file.ts +127 -0
- package/src/commit/agentic/tools/git-file-diff.ts +191 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +81 -0
- package/src/commit/agentic/tools/index.ts +54 -0
- package/src/commit/agentic/tools/propose-changelog.ts +144 -0
- package/src/commit/agentic/tools/propose-commit.ts +109 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/schemas.ts +23 -0
- package/src/commit/agentic/tools/split-commit.ts +238 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +183 -0
- package/src/commit/analysis/conventional.ts +64 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +105 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +40 -0
- package/src/commit/changelog/generate.ts +97 -0
- package/src/commit/changelog/index.ts +234 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +85 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/index.ts +69 -0
- package/src/commit/map-reduce/map-phase.ts +193 -0
- package/src/commit/map-reduce/reduce-phase.ts +49 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +66 -0
- package/src/commit/pipeline.ts +243 -0
- package/src/commit/prompts/analysis-system.md +148 -0
- package/src/commit/prompts/analysis-user.md +38 -0
- package/src/commit/prompts/changelog-system.md +50 -0
- package/src/commit/prompts/changelog-user.md +18 -0
- package/src/commit/prompts/file-observer-system.md +24 -0
- package/src/commit/prompts/file-observer-user.md +8 -0
- package/src/commit/prompts/reduce-system.md +50 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +3 -0
- package/src/commit/prompts/summary-system.md +38 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/shared-llm.ts +77 -0
- package/src/commit/types.ts +118 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/commit/utils.ts +58 -0
- package/src/config/config-file.ts +232 -0
- package/src/config/file-lock.ts +121 -0
- package/src/config/keybindings.ts +493 -0
- package/src/config/mcp-schema.json +230 -0
- package/src/config/model-equivalence.ts +811 -0
- package/src/config/model-registry.ts +2384 -0
- package/src/config/model-resolver.ts +1398 -0
- package/src/config/models-config-schema.ts +175 -0
- package/src/config/prompt-templates.ts +310 -0
- package/src/config/resolve-config-value.ts +94 -0
- package/src/config/settings-schema.ts +2939 -0
- package/src/config/settings.ts +919 -0
- package/src/config/skill-settings-defaults.ts +27 -0
- package/src/config.ts +212 -0
- package/src/cursor.ts +350 -0
- package/src/dap/client.ts +675 -0
- package/src/dap/config.ts +150 -0
- package/src/dap/defaults.json +211 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1306 -0
- package/src/dap/types.ts +600 -0
- package/src/debug/index.ts +459 -0
- package/src/debug/log-formatting.ts +58 -0
- package/src/debug/log-viewer.ts +908 -0
- package/src/debug/profiler.ts +162 -0
- package/src/debug/raw-sse-buffer.ts +270 -0
- package/src/debug/raw-sse.ts +213 -0
- package/src/debug/report-bundle.ts +365 -0
- package/src/debug/system-info.ts +111 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +795 -0
- package/src/defaults/gjc/skills/ralplan/SKILL.md +142 -0
- package/src/defaults/gjc/skills/team/SKILL.md +373 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +176 -0
- package/src/defaults/gjc-defaults.ts +151 -0
- package/src/discovery/agents-md.ts +67 -0
- package/src/discovery/agents.ts +230 -0
- package/src/discovery/builtin.ts +932 -0
- package/src/discovery/claude-plugins.ts +387 -0
- package/src/discovery/claude.ts +313 -0
- package/src/discovery/cline.ts +83 -0
- package/src/discovery/codex.ts +330 -0
- package/src/discovery/cursor.ts +220 -0
- package/src/discovery/gemini.ts +383 -0
- package/src/discovery/github.ts +118 -0
- package/src/discovery/helpers.ts +964 -0
- package/src/discovery/index.ts +76 -0
- package/src/discovery/mcp-json.ts +171 -0
- package/src/discovery/opencode.ts +398 -0
- package/src/discovery/plugin-dir-roots.ts +28 -0
- package/src/discovery/ssh.ts +153 -0
- package/src/discovery/substitute-plugin-root.ts +29 -0
- package/src/discovery/vscode.ts +105 -0
- package/src/discovery/windsurf.ts +147 -0
- package/src/edit/apply-patch/index.ts +87 -0
- package/src/edit/apply-patch/parser.ts +174 -0
- package/src/edit/diff.ts +810 -0
- package/src/edit/file-read-cache.ts +95 -0
- package/src/edit/index.ts +528 -0
- package/src/edit/modes/apply-patch.lark +19 -0
- package/src/edit/modes/apply-patch.ts +53 -0
- package/src/edit/modes/patch.ts +1835 -0
- package/src/edit/modes/replace.ts +1103 -0
- package/src/edit/normalize.ts +375 -0
- package/src/edit/notebook.ts +222 -0
- package/src/edit/read-file.ts +25 -0
- package/src/edit/renderer.ts +683 -0
- package/src/edit/streaming.ts +561 -0
- package/src/eval/backend.ts +43 -0
- package/src/eval/index.ts +4 -0
- package/src/eval/js/context-manager.ts +414 -0
- package/src/eval/js/executor.ts +134 -0
- package/src/eval/js/index.ts +46 -0
- package/src/eval/js/shared/helpers.ts +237 -0
- package/src/eval/js/shared/indirect-eval.ts +30 -0
- package/src/eval/js/shared/prelude.ts +2 -0
- package/src/eval/js/shared/prelude.txt +70 -0
- package/src/eval/js/shared/rewrite-imports.ts +416 -0
- package/src/eval/js/shared/runtime.ts +301 -0
- package/src/eval/js/shared/types.ts +18 -0
- package/src/eval/js/tool-bridge.ts +144 -0
- package/src/eval/js/worker-core.ts +146 -0
- package/src/eval/js/worker-entry.ts +24 -0
- package/src/eval/js/worker-protocol.ts +41 -0
- package/src/eval/py/display.ts +71 -0
- package/src/eval/py/executor.ts +602 -0
- package/src/eval/py/index.ts +58 -0
- package/src/eval/py/kernel.ts +668 -0
- package/src/eval/py/prelude.py +462 -0
- package/src/eval/py/prelude.ts +3 -0
- package/src/eval/py/runner.py +910 -0
- package/src/eval/py/runtime.ts +210 -0
- package/src/eval/py/tool-bridge.ts +137 -0
- package/src/eval/types.ts +48 -0
- package/src/exa/factory.ts +60 -0
- package/src/exa/index.ts +27 -0
- package/src/exa/mcp-client.ts +364 -0
- package/src/exa/render.ts +244 -0
- package/src/exa/researcher.ts +36 -0
- package/src/exa/search.ts +47 -0
- package/src/exa/types.ts +166 -0
- package/src/exa/websets.ts +248 -0
- package/src/exec/bash-executor.ts +309 -0
- package/src/exec/exec.ts +53 -0
- package/src/exec/idle-timeout-watchdog.ts +126 -0
- package/src/exec/non-interactive-env.ts +48 -0
- package/src/export/custom-share.ts +65 -0
- package/src/export/html/index.ts +164 -0
- package/src/export/html/template.css +1060 -0
- package/src/export/html/template.generated.ts +2 -0
- package/src/export/html/template.html +47 -0
- package/src/export/html/template.js +2268 -0
- package/src/export/html/template.macro.ts +25 -0
- package/src/export/html/vendor/highlight.min.js +1213 -0
- package/src/export/html/vendor/marked.min.js +6 -0
- package/src/export/ttsr.ts +434 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +25 -0
- package/src/extensibility/custom-commands/bundled/review/index.ts +456 -0
- package/src/extensibility/custom-commands/index.ts +2 -0
- package/src/extensibility/custom-commands/loader.ts +238 -0
- package/src/extensibility/custom-commands/types.ts +113 -0
- package/src/extensibility/custom-tools/index.ts +7 -0
- package/src/extensibility/custom-tools/loader.ts +245 -0
- package/src/extensibility/custom-tools/types.ts +254 -0
- package/src/extensibility/custom-tools/wrapper.ts +47 -0
- package/src/extensibility/extensions/compact-handler.ts +40 -0
- package/src/extensibility/extensions/get-commands-handler.ts +80 -0
- package/src/extensibility/extensions/index.ts +15 -0
- package/src/extensibility/extensions/loader.ts +545 -0
- package/src/extensibility/extensions/runner.ts +900 -0
- package/src/extensibility/extensions/types.ts +1259 -0
- package/src/extensibility/extensions/wrapper.ts +189 -0
- package/src/extensibility/hooks/index.ts +5 -0
- package/src/extensibility/hooks/loader.ts +257 -0
- package/src/extensibility/hooks/runner.ts +425 -0
- package/src/extensibility/hooks/tool-wrapper.ts +107 -0
- package/src/extensibility/hooks/types.ts +599 -0
- package/src/extensibility/plugins/doctor.ts +66 -0
- package/src/extensibility/plugins/git-url.ts +281 -0
- package/src/extensibility/plugins/index.ts +9 -0
- package/src/extensibility/plugins/installer.ts +192 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +336 -0
- package/src/extensibility/plugins/loader.ts +288 -0
- package/src/extensibility/plugins/manager.ts +731 -0
- package/src/extensibility/plugins/marketplace/cache.ts +136 -0
- package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
- package/src/extensibility/plugins/marketplace/index.ts +6 -0
- package/src/extensibility/plugins/marketplace/manager.ts +770 -0
- package/src/extensibility/plugins/marketplace/registry.ts +196 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
- package/src/extensibility/plugins/marketplace/types.ts +191 -0
- package/src/extensibility/plugins/parser.ts +105 -0
- package/src/extensibility/plugins/types.ts +194 -0
- package/src/extensibility/shared-events.ts +343 -0
- package/src/extensibility/skills.ts +391 -0
- package/src/extensibility/slash-commands.ts +227 -0
- package/src/extensibility/tool-proxy.ts +25 -0
- package/src/extensibility/typebox.ts +418 -0
- package/src/extensibility/utils.ts +44 -0
- package/src/gjc-runtime/goal-mode-request.ts +212 -0
- package/src/gjc-runtime/launch-tmux.ts +162 -0
- package/src/gjc-runtime/launch-worktree.ts +291 -0
- package/src/gjc-runtime/team-runtime.ts +2025 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +564 -0
- package/src/goals/index.ts +3 -0
- package/src/goals/runtime.ts +524 -0
- package/src/goals/state.ts +37 -0
- package/src/goals/tools/goal-tool.ts +371 -0
- package/src/hashline/anchors.ts +113 -0
- package/src/hashline/apply.ts +737 -0
- package/src/hashline/bigrams.json +649 -0
- package/src/hashline/constants.ts +25 -0
- package/src/hashline/diff-preview.ts +43 -0
- package/src/hashline/diff.ts +56 -0
- package/src/hashline/execute.ts +267 -0
- package/src/hashline/grammar.lark +21 -0
- package/src/hashline/hash.ts +173 -0
- package/src/hashline/index.ts +13 -0
- package/src/hashline/input.ts +130 -0
- package/src/hashline/parser.ts +246 -0
- package/src/hashline/prefixes.ts +101 -0
- package/src/hashline/recovery.ts +113 -0
- package/src/hashline/stream.ts +123 -0
- package/src/hashline/types.ts +68 -0
- package/src/hindsight/backend.ts +205 -0
- package/src/hindsight/bank.ts +131 -0
- package/src/hindsight/client.ts +598 -0
- package/src/hindsight/config.ts +175 -0
- package/src/hindsight/content.ts +210 -0
- package/src/hindsight/index.ts +8 -0
- package/src/hindsight/mental-models.ts +382 -0
- package/src/hindsight/seeds.json +32 -0
- package/src/hindsight/state.ts +469 -0
- package/src/hindsight/transcript.ts +71 -0
- package/src/hooks/codex-native-hooks-config.ts +143 -0
- package/src/hooks/native-skill-hook.ts +279 -0
- package/src/hooks/skill-keywords.ts +86 -0
- package/src/hooks/skill-state.ts +416 -0
- package/src/index.ts +56 -0
- package/src/internal-urls/agent-protocol.ts +129 -0
- package/src/internal-urls/artifact-protocol.ts +80 -0
- package/src/internal-urls/docs-index.generated.ts +81 -0
- package/src/internal-urls/gjc-protocol.ts +83 -0
- package/src/internal-urls/index.ts +21 -0
- package/src/internal-urls/issue-pr-protocol.ts +577 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/local-protocol.ts +249 -0
- package/src/internal-urls/mcp-protocol.ts +151 -0
- package/src/internal-urls/memory-protocol.ts +164 -0
- package/src/internal-urls/parse.ts +72 -0
- package/src/internal-urls/registry-helpers.ts +25 -0
- package/src/internal-urls/router.ts +78 -0
- package/src/internal-urls/rule-protocol.ts +38 -0
- package/src/internal-urls/skill-protocol.ts +103 -0
- package/src/internal-urls/types.ts +110 -0
- package/src/lsp/client.ts +951 -0
- package/src/lsp/clients/biome-client.ts +202 -0
- package/src/lsp/clients/index.ts +50 -0
- package/src/lsp/clients/lsp-linter-client.ts +93 -0
- package/src/lsp/clients/swiftlint-client.ts +120 -0
- package/src/lsp/config.ts +492 -0
- package/src/lsp/defaults.json +493 -0
- package/src/lsp/edits.ts +166 -0
- package/src/lsp/index.ts +2282 -0
- package/src/lsp/lspmux.ts +233 -0
- package/src/lsp/render.ts +692 -0
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +443 -0
- package/src/lsp/utils.ts +678 -0
- package/src/main.ts +961 -0
- package/src/memories/index.ts +1135 -0
- package/src/memories/storage.ts +577 -0
- package/src/memory-backend/index.ts +4 -0
- package/src/memory-backend/local-backend.ts +30 -0
- package/src/memory-backend/off-backend.ts +16 -0
- package/src/memory-backend/resolve.ts +24 -0
- package/src/memory-backend/types.ts +79 -0
- package/src/modes/acp/acp-agent.ts +2170 -0
- package/src/modes/acp/acp-client-bridge.ts +154 -0
- package/src/modes/acp/acp-event-mapper.ts +879 -0
- package/src/modes/acp/acp-mode.ts +23 -0
- package/src/modes/acp/index.ts +2 -0
- package/src/modes/acp/terminal-auth.ts +37 -0
- package/src/modes/components/agent-dashboard.ts +1120 -0
- package/src/modes/components/assistant-message.ts +231 -0
- package/src/modes/components/bash-execution.ts +228 -0
- package/src/modes/components/bordered-loader.ts +41 -0
- package/src/modes/components/branch-summary-message.ts +45 -0
- package/src/modes/components/btw-panel.ts +104 -0
- package/src/modes/components/compaction-summary-message.ts +51 -0
- package/src/modes/components/countdown-timer.ts +75 -0
- package/src/modes/components/custom-editor.ts +237 -0
- package/src/modes/components/custom-message.ts +65 -0
- package/src/modes/components/diff.ts +266 -0
- package/src/modes/components/dynamic-border.ts +25 -0
- package/src/modes/components/eval-execution.ts +164 -0
- package/src/modes/components/execution-shared.ts +102 -0
- package/src/modes/components/extensions/extension-dashboard.ts +350 -0
- package/src/modes/components/extensions/extension-list.ts +492 -0
- package/src/modes/components/extensions/index.ts +9 -0
- package/src/modes/components/extensions/inspector-panel.ts +317 -0
- package/src/modes/components/extensions/state-manager.ts +628 -0
- package/src/modes/components/extensions/types.ts +191 -0
- package/src/modes/components/footer.ts +270 -0
- package/src/modes/components/history-search.ts +158 -0
- package/src/modes/components/hook-editor.ts +151 -0
- package/src/modes/components/hook-input.ts +79 -0
- package/src/modes/components/hook-message.ts +68 -0
- package/src/modes/components/hook-selector.ts +190 -0
- package/src/modes/components/index.ts +36 -0
- package/src/modes/components/keybinding-hints.ts +65 -0
- package/src/modes/components/login-dialog.ts +164 -0
- package/src/modes/components/message-frame.ts +88 -0
- package/src/modes/components/model-selector.ts +794 -0
- package/src/modes/components/oauth-selector.ts +248 -0
- package/src/modes/components/plugin-selector.ts +95 -0
- package/src/modes/components/plugin-settings.ts +488 -0
- package/src/modes/components/provider-onboarding-selector.ts +88 -0
- package/src/modes/components/queue-mode-selector.ts +56 -0
- package/src/modes/components/read-tool-group.ts +267 -0
- package/src/modes/components/runtime-mcp-add-wizard.ts +1341 -0
- package/src/modes/components/session-observer-overlay.ts +839 -0
- package/src/modes/components/session-selector.ts +343 -0
- package/src/modes/components/settings-defs.ts +175 -0
- package/src/modes/components/settings-selector.ts +635 -0
- package/src/modes/components/show-images-selector.ts +45 -0
- package/src/modes/components/skill-hud/render.ts +47 -0
- package/src/modes/components/skill-message.ts +90 -0
- package/src/modes/components/status-line/context-thresholds.ts +68 -0
- package/src/modes/components/status-line/git-utils.ts +42 -0
- package/src/modes/components/status-line/index.ts +4 -0
- package/src/modes/components/status-line/presets.ts +105 -0
- package/src/modes/components/status-line/segments.ts +560 -0
- package/src/modes/components/status-line/separators.ts +55 -0
- package/src/modes/components/status-line/token-rate.ts +66 -0
- package/src/modes/components/status-line/types.ts +93 -0
- package/src/modes/components/status-line.ts +839 -0
- package/src/modes/components/theme-selector.ts +63 -0
- package/src/modes/components/thinking-selector.ts +52 -0
- package/src/modes/components/todo-reminder.ts +40 -0
- package/src/modes/components/tool-execution.ts +830 -0
- package/src/modes/components/tree-selector.ts +930 -0
- package/src/modes/components/ttsr-notification.ts +80 -0
- package/src/modes/components/user-message-selector.ts +141 -0
- package/src/modes/components/user-message.ts +51 -0
- package/src/modes/components/visual-truncate.ts +63 -0
- package/src/modes/components/welcome.ts +389 -0
- package/src/modes/controllers/btw-controller.ts +105 -0
- package/src/modes/controllers/command-controller-shared.ts +108 -0
- package/src/modes/controllers/command-controller.ts +1630 -0
- package/src/modes/controllers/event-controller.ts +786 -0
- package/src/modes/controllers/extension-ui-controller.ts +927 -0
- package/src/modes/controllers/input-controller.ts +858 -0
- package/src/modes/controllers/runtime-mcp-command-controller.ts +1934 -0
- package/src/modes/controllers/selector-controller.ts +1039 -0
- package/src/modes/controllers/ssh-command-controller.ts +384 -0
- package/src/modes/controllers/todo-command-controller.ts +485 -0
- package/src/modes/data/emojis.json +1 -0
- package/src/modes/emoji-autocomplete.ts +285 -0
- package/src/modes/index.ts +34 -0
- package/src/modes/interactive-mode.ts +2756 -0
- package/src/modes/loop-limit.ts +140 -0
- package/src/modes/oauth-manual-input.ts +42 -0
- package/src/modes/print-mode.ts +121 -0
- package/src/modes/prompt-action-autocomplete.ts +345 -0
- package/src/modes/rpc/host-tools.ts +186 -0
- package/src/modes/rpc/host-uris.ts +235 -0
- package/src/modes/rpc/rpc-client.ts +810 -0
- package/src/modes/rpc/rpc-mode.ts +851 -0
- package/src/modes/rpc/rpc-types.ts +378 -0
- package/src/modes/runtime-init.ts +116 -0
- package/src/modes/session-observer-registry.ts +146 -0
- package/src/modes/shared.ts +55 -0
- package/src/modes/theme/dark.json +95 -0
- package/src/modes/theme/defaults/alabaster.json +93 -0
- package/src/modes/theme/defaults/amethyst.json +96 -0
- package/src/modes/theme/defaults/anthracite.json +93 -0
- package/src/modes/theme/defaults/basalt.json +91 -0
- package/src/modes/theme/defaults/birch.json +95 -0
- package/src/modes/theme/defaults/dark-abyss.json +91 -0
- package/src/modes/theme/defaults/dark-arctic.json +104 -0
- package/src/modes/theme/defaults/dark-aurora.json +95 -0
- package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
- package/src/modes/theme/defaults/dark-cavern.json +91 -0
- package/src/modes/theme/defaults/dark-copper.json +95 -0
- package/src/modes/theme/defaults/dark-cosmos.json +90 -0
- package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/modes/theme/defaults/dark-dracula.json +98 -0
- package/src/modes/theme/defaults/dark-eclipse.json +91 -0
- package/src/modes/theme/defaults/dark-ember.json +95 -0
- package/src/modes/theme/defaults/dark-equinox.json +90 -0
- package/src/modes/theme/defaults/dark-forest.json +96 -0
- package/src/modes/theme/defaults/dark-github.json +105 -0
- package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
- package/src/modes/theme/defaults/dark-lavender.json +95 -0
- package/src/modes/theme/defaults/dark-lunar.json +89 -0
- package/src/modes/theme/defaults/dark-midnight.json +95 -0
- package/src/modes/theme/defaults/dark-monochrome.json +94 -0
- package/src/modes/theme/defaults/dark-monokai.json +98 -0
- package/src/modes/theme/defaults/dark-nebula.json +90 -0
- package/src/modes/theme/defaults/dark-nord.json +97 -0
- package/src/modes/theme/defaults/dark-ocean.json +101 -0
- package/src/modes/theme/defaults/dark-one.json +100 -0
- package/src/modes/theme/defaults/dark-poimandres.json +142 -0
- package/src/modes/theme/defaults/dark-rainforest.json +91 -0
- package/src/modes/theme/defaults/dark-reef.json +91 -0
- package/src/modes/theme/defaults/dark-retro.json +92 -0
- package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
- package/src/modes/theme/defaults/dark-sakura.json +95 -0
- package/src/modes/theme/defaults/dark-slate.json +95 -0
- package/src/modes/theme/defaults/dark-solarized.json +97 -0
- package/src/modes/theme/defaults/dark-solstice.json +90 -0
- package/src/modes/theme/defaults/dark-starfall.json +91 -0
- package/src/modes/theme/defaults/dark-sunset.json +99 -0
- package/src/modes/theme/defaults/dark-swamp.json +90 -0
- package/src/modes/theme/defaults/dark-synthwave.json +103 -0
- package/src/modes/theme/defaults/dark-taiga.json +91 -0
- package/src/modes/theme/defaults/dark-terminal.json +95 -0
- package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/modes/theme/defaults/dark-tundra.json +91 -0
- package/src/modes/theme/defaults/dark-twilight.json +91 -0
- package/src/modes/theme/defaults/dark-volcanic.json +91 -0
- package/src/modes/theme/defaults/graphite.json +92 -0
- package/src/modes/theme/defaults/index.ts +201 -0
- package/src/modes/theme/defaults/light-arctic.json +107 -0
- package/src/modes/theme/defaults/light-aurora-day.json +91 -0
- package/src/modes/theme/defaults/light-canyon.json +91 -0
- package/src/modes/theme/defaults/light-catppuccin.json +106 -0
- package/src/modes/theme/defaults/light-cirrus.json +90 -0
- package/src/modes/theme/defaults/light-coral.json +95 -0
- package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
- package/src/modes/theme/defaults/light-dawn.json +90 -0
- package/src/modes/theme/defaults/light-dunes.json +91 -0
- package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
- package/src/modes/theme/defaults/light-forest.json +100 -0
- package/src/modes/theme/defaults/light-frost.json +95 -0
- package/src/modes/theme/defaults/light-github.json +115 -0
- package/src/modes/theme/defaults/light-glacier.json +91 -0
- package/src/modes/theme/defaults/light-gruvbox.json +108 -0
- package/src/modes/theme/defaults/light-haze.json +90 -0
- package/src/modes/theme/defaults/light-honeycomb.json +95 -0
- package/src/modes/theme/defaults/light-lagoon.json +91 -0
- package/src/modes/theme/defaults/light-lavender.json +95 -0
- package/src/modes/theme/defaults/light-meadow.json +91 -0
- package/src/modes/theme/defaults/light-mint.json +95 -0
- package/src/modes/theme/defaults/light-monochrome.json +101 -0
- package/src/modes/theme/defaults/light-ocean.json +99 -0
- package/src/modes/theme/defaults/light-one.json +99 -0
- package/src/modes/theme/defaults/light-opal.json +91 -0
- package/src/modes/theme/defaults/light-orchard.json +91 -0
- package/src/modes/theme/defaults/light-paper.json +95 -0
- package/src/modes/theme/defaults/light-poimandres.json +142 -0
- package/src/modes/theme/defaults/light-prism.json +90 -0
- package/src/modes/theme/defaults/light-retro.json +98 -0
- package/src/modes/theme/defaults/light-sand.json +95 -0
- package/src/modes/theme/defaults/light-savanna.json +91 -0
- package/src/modes/theme/defaults/light-solarized.json +102 -0
- package/src/modes/theme/defaults/light-soleil.json +90 -0
- package/src/modes/theme/defaults/light-sunset.json +99 -0
- package/src/modes/theme/defaults/light-synthwave.json +98 -0
- package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
- package/src/modes/theme/defaults/light-wetland.json +91 -0
- package/src/modes/theme/defaults/light-zenith.json +89 -0
- package/src/modes/theme/defaults/limestone.json +94 -0
- package/src/modes/theme/defaults/mahogany.json +97 -0
- package/src/modes/theme/defaults/marble.json +93 -0
- package/src/modes/theme/defaults/obsidian.json +91 -0
- package/src/modes/theme/defaults/onyx.json +91 -0
- package/src/modes/theme/defaults/pearl.json +93 -0
- package/src/modes/theme/defaults/porcelain.json +91 -0
- package/src/modes/theme/defaults/quartz.json +96 -0
- package/src/modes/theme/defaults/red-claw.json +123 -0
- package/src/modes/theme/defaults/sandstone.json +95 -0
- package/src/modes/theme/defaults/titanium.json +90 -0
- package/src/modes/theme/light.json +93 -0
- package/src/modes/theme/mermaid-cache.ts +29 -0
- package/src/modes/theme/shimmer.ts +219 -0
- package/src/modes/theme/theme-schema.json +429 -0
- package/src/modes/theme/theme.ts +2413 -0
- package/src/modes/types.ts +313 -0
- package/src/modes/utils/context-usage.ts +335 -0
- package/src/modes/utils/hotkeys-markdown.ts +59 -0
- package/src/modes/utils/keybinding-matchers.ts +30 -0
- package/src/modes/utils/tools-markdown.ts +27 -0
- package/src/modes/utils/ui-helpers.ts +741 -0
- package/src/plan-mode/approved-plan.ts +163 -0
- package/src/plan-mode/state.ts +6 -0
- package/src/priority.json +37 -0
- package/src/prompts/agents/architect.md +79 -0
- package/src/prompts/agents/critic.md +55 -0
- package/src/prompts/agents/executor.md +45 -0
- package/src/prompts/agents/explore.md +58 -0
- package/src/prompts/agents/frontmatter.md +12 -0
- package/src/prompts/agents/init.md +34 -0
- package/src/prompts/agents/plan.md +49 -0
- package/src/prompts/agents/planner.md +49 -0
- package/src/prompts/agents/reviewer.md +141 -0
- package/src/prompts/agents/task.md +16 -0
- package/src/prompts/ci-green-request.md +36 -0
- package/src/prompts/commands/orchestrate.md +49 -0
- package/src/prompts/goals/goal-budget-limit.md +16 -0
- package/src/prompts/goals/goal-continuation.md +28 -0
- package/src/prompts/goals/goal-mode-active.md +23 -0
- package/src/prompts/memories/consolidation.md +30 -0
- package/src/prompts/memories/read-path.md +11 -0
- package/src/prompts/memories/stage_one_input.md +6 -0
- package/src/prompts/memories/stage_one_system.md +21 -0
- package/src/prompts/review-request.md +70 -0
- package/src/prompts/system/agent-creation-architect.md +75 -0
- package/src/prompts/system/agent-creation-user.md +6 -0
- package/src/prompts/system/auto-continue.md +1 -0
- package/src/prompts/system/btw-user.md +8 -0
- package/src/prompts/system/commit-message-system.md +2 -0
- package/src/prompts/system/custom-system-prompt.md +64 -0
- package/src/prompts/system/eager-todo.md +13 -0
- package/src/prompts/system/irc-incoming.md +8 -0
- package/src/prompts/system/plan-mode-active.md +116 -0
- package/src/prompts/system/plan-mode-approved.md +28 -0
- package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
- package/src/prompts/system/plan-mode-reference.md +14 -0
- package/src/prompts/system/plan-mode-subagent.md +34 -0
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
- package/src/prompts/system/project-prompt.md +46 -0
- package/src/prompts/system/subagent-system-prompt.md +54 -0
- package/src/prompts/system/subagent-user-prompt.md +3 -0
- package/src/prompts/system/subagent-yield-reminder.md +12 -0
- package/src/prompts/system/system-prompt.md +267 -0
- package/src/prompts/system/title-system.md +2 -0
- package/src/prompts/system/ttsr-interrupt.md +7 -0
- package/src/prompts/system/ttsr-tool-reminder.md +5 -0
- package/src/prompts/system/web-search.md +25 -0
- package/src/prompts/tools/apply-patch.md +65 -0
- package/src/prompts/tools/ask.md +29 -0
- package/src/prompts/tools/ast-edit.md +39 -0
- package/src/prompts/tools/ast-grep.md +42 -0
- package/src/prompts/tools/async-result.md +8 -0
- package/src/prompts/tools/bash.md +39 -0
- package/src/prompts/tools/browser.md +70 -0
- package/src/prompts/tools/calculator.md +10 -0
- package/src/prompts/tools/checkpoint.md +16 -0
- package/src/prompts/tools/create-goal.md +3 -0
- package/src/prompts/tools/debug.md +33 -0
- package/src/prompts/tools/eval.md +75 -0
- package/src/prompts/tools/find.md +34 -0
- package/src/prompts/tools/get-goal.md +3 -0
- package/src/prompts/tools/github.md +20 -0
- package/src/prompts/tools/goal.md +18 -0
- package/src/prompts/tools/hashline.md +130 -0
- package/src/prompts/tools/image-gen.md +7 -0
- package/src/prompts/tools/inspect-image-system.md +20 -0
- package/src/prompts/tools/inspect-image.md +32 -0
- package/src/prompts/tools/irc.md +49 -0
- package/src/prompts/tools/job.md +19 -0
- package/src/prompts/tools/lsp.md +42 -0
- package/src/prompts/tools/patch.md +70 -0
- package/src/prompts/tools/read.md +82 -0
- package/src/prompts/tools/recall.md +5 -0
- package/src/prompts/tools/recipe.md +16 -0
- package/src/prompts/tools/reflect.md +5 -0
- package/src/prompts/tools/render-mermaid.md +9 -0
- package/src/prompts/tools/replace.md +36 -0
- package/src/prompts/tools/resolve.md +9 -0
- package/src/prompts/tools/retain.md +6 -0
- package/src/prompts/tools/rewind.md +13 -0
- package/src/prompts/tools/search-tool-bm25.md +33 -0
- package/src/prompts/tools/search.md +25 -0
- package/src/prompts/tools/ssh.md +35 -0
- package/src/prompts/tools/subagent.md +21 -0
- package/src/prompts/tools/task-summary.md +28 -0
- package/src/prompts/tools/task.md +79 -0
- package/src/prompts/tools/todo-write.md +50 -0
- package/src/prompts/tools/update-goal.md +3 -0
- package/src/prompts/tools/vim.md +98 -0
- package/src/prompts/tools/web-search.md +10 -0
- package/src/prompts/tools/write.md +14 -0
- package/src/registry/agent-registry.ts +140 -0
- package/src/runtime-mcp/client.ts +482 -0
- package/src/runtime-mcp/config-writer.ts +225 -0
- package/src/runtime-mcp/config.ts +365 -0
- package/src/runtime-mcp/discoverable-tool-metadata.ts +25 -0
- package/src/runtime-mcp/index.ts +29 -0
- package/src/runtime-mcp/json-rpc.ts +84 -0
- package/src/runtime-mcp/loader.ts +124 -0
- package/src/runtime-mcp/manager.ts +1172 -0
- package/src/runtime-mcp/oauth-discovery.ts +349 -0
- package/src/runtime-mcp/oauth-flow.ts +407 -0
- package/src/runtime-mcp/render.ts +123 -0
- package/src/runtime-mcp/smithery-auth.ts +104 -0
- package/src/runtime-mcp/smithery-connect.ts +145 -0
- package/src/runtime-mcp/smithery-registry.ts +477 -0
- package/src/runtime-mcp/tool-bridge.ts +416 -0
- package/src/runtime-mcp/tool-cache.ts +117 -0
- package/src/runtime-mcp/transports/http.ts +477 -0
- package/src/runtime-mcp/transports/index.ts +6 -0
- package/src/runtime-mcp/transports/stdio.ts +325 -0
- package/src/runtime-mcp/types.ts +423 -0
- package/src/sdk.ts +2064 -0
- package/src/secrets/index.ts +116 -0
- package/src/secrets/obfuscator.ts +277 -0
- package/src/secrets/regex.ts +21 -0
- package/src/session/agent-session.ts +8794 -0
- package/src/session/agent-storage.ts +466 -0
- package/src/session/artifacts.ts +135 -0
- package/src/session/auth-broker-config.ts +102 -0
- package/src/session/auth-storage.ts +23 -0
- package/src/session/blob-store.ts +168 -0
- package/src/session/client-bridge.ts +85 -0
- package/src/session/history-storage.ts +311 -0
- package/src/session/messages.ts +403 -0
- package/src/session/session-dump-format.ts +209 -0
- package/src/session/session-manager.ts +3333 -0
- package/src/session/session-storage.ts +389 -0
- package/src/session/streaming-output.ts +1093 -0
- package/src/session/tool-choice-queue.ts +213 -0
- package/src/session/yield-queue.ts +155 -0
- package/src/setup/model-onboarding-guidance.ts +36 -0
- package/src/setup/provider-onboarding.ts +195 -0
- package/src/skill-state/active-state.ts +272 -0
- package/src/slash-commands/acp-builtins.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +955 -0
- package/src/slash-commands/helpers/context-report.ts +39 -0
- package/src/slash-commands/helpers/format.ts +46 -0
- package/src/slash-commands/helpers/mcp.ts +532 -0
- package/src/slash-commands/helpers/parse.ts +85 -0
- package/src/slash-commands/helpers/ssh.ts +195 -0
- package/src/slash-commands/helpers/todo.ts +279 -0
- package/src/slash-commands/helpers/usage-report.ts +91 -0
- package/src/slash-commands/types.ts +125 -0
- package/src/ssh/config-writer.ts +183 -0
- package/src/ssh/connection-manager.ts +482 -0
- package/src/ssh/ssh-executor.ts +133 -0
- package/src/ssh/sshfs-mount.ts +140 -0
- package/src/ssh/utils.ts +8 -0
- package/src/stt/downloader.ts +71 -0
- package/src/stt/index.ts +3 -0
- package/src/stt/recorder.ts +351 -0
- package/src/stt/setup.ts +52 -0
- package/src/stt/stt-controller.ts +160 -0
- package/src/stt/transcribe.py +70 -0
- package/src/stt/transcriber.ts +91 -0
- package/src/system-prompt.ts +581 -0
- package/src/task/agents.ts +162 -0
- package/src/task/commands.ts +135 -0
- package/src/task/discovery.ts +130 -0
- package/src/task/executor.ts +1564 -0
- package/src/task/gjc-command.ts +26 -0
- package/src/task/index.ts +1366 -0
- package/src/task/name-generator.ts +1577 -0
- package/src/task/output-manager.ts +107 -0
- package/src/task/parallel.ts +116 -0
- package/src/task/render.ts +1136 -0
- package/src/task/simple-mode.ts +27 -0
- package/src/task/subprocess-tool-registry.ts +88 -0
- package/src/task/types.ts +315 -0
- package/src/task/worktree.ts +506 -0
- package/src/thinking.ts +87 -0
- package/src/tool-discovery/tool-index.ts +400 -0
- package/src/tools/archive-reader.ts +321 -0
- package/src/tools/ask.ts +790 -0
- package/src/tools/ast-edit.ts +542 -0
- package/src/tools/ast-grep.ts +423 -0
- package/src/tools/auto-generated-guard.ts +305 -0
- package/src/tools/bash-command-fixup.ts +37 -0
- package/src/tools/bash-interactive.ts +388 -0
- package/src/tools/bash-interceptor.ts +67 -0
- package/src/tools/bash-pty-selection.ts +14 -0
- package/src/tools/bash-skill-urls.ts +248 -0
- package/src/tools/bash.ts +1061 -0
- package/src/tools/browser/attach.ts +175 -0
- package/src/tools/browser/launch.ts +651 -0
- package/src/tools/browser/readable.ts +95 -0
- package/src/tools/browser/registry.ts +194 -0
- package/src/tools/browser/render.ts +212 -0
- package/src/tools/browser/tab-protocol.ts +105 -0
- package/src/tools/browser/tab-supervisor.ts +577 -0
- package/src/tools/browser/tab-worker-entry.ts +21 -0
- package/src/tools/browser/tab-worker.ts +1054 -0
- package/src/tools/browser.ts +301 -0
- package/src/tools/calculator.ts +540 -0
- package/src/tools/checkpoint.ts +134 -0
- package/src/tools/conflict-detect.ts +672 -0
- package/src/tools/context.ts +39 -0
- package/src/tools/debug.ts +1014 -0
- package/src/tools/eval.ts +1101 -0
- package/src/tools/fetch.ts +1482 -0
- package/src/tools/file-recorder.ts +35 -0
- package/src/tools/find.ts +540 -0
- package/src/tools/fs-cache-invalidation.ts +28 -0
- package/src/tools/gh-format.ts +12 -0
- package/src/tools/gh-renderer.ts +428 -0
- package/src/tools/gh.ts +3499 -0
- package/src/tools/github-cache.ts +548 -0
- package/src/tools/grouped-file-output.ts +96 -0
- package/src/tools/hindsight-recall.ts +68 -0
- package/src/tools/hindsight-reflect.ts +57 -0
- package/src/tools/hindsight-retain.ts +56 -0
- package/src/tools/image-gen.ts +1248 -0
- package/src/tools/index.ts +519 -0
- package/src/tools/inspect-image-renderer.ts +103 -0
- package/src/tools/inspect-image.ts +165 -0
- package/src/tools/irc.ts +239 -0
- package/src/tools/job.ts +520 -0
- package/src/tools/json-tree.ts +243 -0
- package/src/tools/jtd-to-json-schema.ts +219 -0
- package/src/tools/jtd-to-typescript.ts +136 -0
- package/src/tools/jtd-utils.ts +102 -0
- package/src/tools/list-limit.ts +40 -0
- package/src/tools/match-line-format.ts +22 -0
- package/src/tools/output-meta.ts +754 -0
- package/src/tools/path-utils.ts +739 -0
- package/src/tools/plan-mode-guard.ts +68 -0
- package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
- package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
- package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
- package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
- package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
- package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
- package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
- package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
- package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
- package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
- package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
- package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
- package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
- package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
- package/src/tools/read.ts +2332 -0
- package/src/tools/recipe/index.ts +80 -0
- package/src/tools/recipe/render.ts +19 -0
- package/src/tools/recipe/runner.ts +219 -0
- package/src/tools/recipe/runners/cargo.ts +131 -0
- package/src/tools/recipe/runners/index.ts +8 -0
- package/src/tools/recipe/runners/just.ts +73 -0
- package/src/tools/recipe/runners/make.ts +101 -0
- package/src/tools/recipe/runners/pkg.ts +167 -0
- package/src/tools/recipe/runners/task.ts +72 -0
- package/src/tools/render-mermaid.ts +68 -0
- package/src/tools/render-utils.ts +774 -0
- package/src/tools/renderers.ts +75 -0
- package/src/tools/resolve.ts +258 -0
- package/src/tools/review.ts +252 -0
- package/src/tools/search-tool-bm25.ts +360 -0
- package/src/tools/search.ts +786 -0
- package/src/tools/sqlite-reader.ts +736 -0
- package/src/tools/ssh.ts +310 -0
- package/src/tools/subagent.ts +312 -0
- package/src/tools/todo-write.ts +695 -0
- package/src/tools/tool-errors.ts +62 -0
- package/src/tools/tool-result.ts +86 -0
- package/src/tools/tool-timeouts.ts +30 -0
- package/src/tools/vim.ts +949 -0
- package/src/tools/write.ts +953 -0
- package/src/tools/yield.ts +268 -0
- package/src/tui/code-cell.ts +201 -0
- package/src/tui/file-list.ts +55 -0
- package/src/tui/hyperlink.ts +126 -0
- package/src/tui/index.ts +12 -0
- package/src/tui/output-block.ts +150 -0
- package/src/tui/status-line.ts +39 -0
- package/src/tui/tree-list.ts +84 -0
- package/src/tui/types.ts +15 -0
- package/src/tui/utils.ts +103 -0
- package/src/utils/changelog.ts +98 -0
- package/src/utils/clipboard.ts +156 -0
- package/src/utils/command-args.ts +76 -0
- package/src/utils/commit-message-generator.ts +142 -0
- package/src/utils/edit-mode.ts +42 -0
- package/src/utils/event-bus.ts +33 -0
- package/src/utils/external-editor.ts +65 -0
- package/src/utils/file-display-mode.ts +45 -0
- package/src/utils/file-mentions.ts +376 -0
- package/src/utils/git.ts +1536 -0
- package/src/utils/image-loading.ts +102 -0
- package/src/utils/image-resize.ts +309 -0
- package/src/utils/lang-from-path.ts +239 -0
- package/src/utils/markit.ts +89 -0
- package/src/utils/open.ts +20 -0
- package/src/utils/session-color.ts +43 -0
- package/src/utils/shell-snapshot.ts +187 -0
- package/src/utils/sixel.ts +69 -0
- package/src/utils/title-generator.ts +223 -0
- package/src/utils/tool-choice.ts +33 -0
- package/src/utils/tools-manager.ts +363 -0
- package/src/vim/buffer.ts +309 -0
- package/src/vim/commands.ts +382 -0
- package/src/vim/engine.ts +2409 -0
- package/src/vim/parser.ts +134 -0
- package/src/vim/render.ts +252 -0
- package/src/vim/types.ts +197 -0
- package/src/web/kagi.ts +183 -0
- package/src/web/parallel.ts +349 -0
- package/src/web/scrapers/artifacthub.ts +207 -0
- package/src/web/scrapers/arxiv.ts +83 -0
- package/src/web/scrapers/aur.ts +162 -0
- package/src/web/scrapers/biorxiv.ts +133 -0
- package/src/web/scrapers/bluesky.ts +262 -0
- package/src/web/scrapers/brew.ts +172 -0
- package/src/web/scrapers/cheatsh.ts +68 -0
- package/src/web/scrapers/chocolatey.ts +196 -0
- package/src/web/scrapers/choosealicense.ts +95 -0
- package/src/web/scrapers/cisa-kev.ts +87 -0
- package/src/web/scrapers/clojars.ts +154 -0
- package/src/web/scrapers/coingecko.ts +177 -0
- package/src/web/scrapers/crates-io.ts +97 -0
- package/src/web/scrapers/crossref.ts +136 -0
- package/src/web/scrapers/devto.ts +147 -0
- package/src/web/scrapers/discogs.ts +306 -0
- package/src/web/scrapers/discourse.ts +197 -0
- package/src/web/scrapers/dockerhub.ts +138 -0
- package/src/web/scrapers/docs-rs.ts +653 -0
- package/src/web/scrapers/fdroid.ts +134 -0
- package/src/web/scrapers/firefox-addons.ts +191 -0
- package/src/web/scrapers/flathub.ts +223 -0
- package/src/web/scrapers/github-gist.ts +58 -0
- package/src/web/scrapers/github.ts +452 -0
- package/src/web/scrapers/gitlab.ts +401 -0
- package/src/web/scrapers/go-pkg.ts +266 -0
- package/src/web/scrapers/hackage.ts +140 -0
- package/src/web/scrapers/hackernews.ts +189 -0
- package/src/web/scrapers/hex.ts +105 -0
- package/src/web/scrapers/huggingface.ts +321 -0
- package/src/web/scrapers/iacr.ts +89 -0
- package/src/web/scrapers/index.ts +252 -0
- package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
- package/src/web/scrapers/lemmy.ts +203 -0
- package/src/web/scrapers/lobsters.ts +175 -0
- package/src/web/scrapers/mastodon.ts +292 -0
- package/src/web/scrapers/maven.ts +138 -0
- package/src/web/scrapers/mdn.ts +173 -0
- package/src/web/scrapers/metacpan.ts +222 -0
- package/src/web/scrapers/musicbrainz.ts +250 -0
- package/src/web/scrapers/npm.ts +98 -0
- package/src/web/scrapers/nuget.ts +183 -0
- package/src/web/scrapers/nvd.ts +222 -0
- package/src/web/scrapers/ollama.ts +239 -0
- package/src/web/scrapers/open-vsx.ts +106 -0
- package/src/web/scrapers/opencorporates.ts +292 -0
- package/src/web/scrapers/openlibrary.ts +336 -0
- package/src/web/scrapers/orcid.ts +286 -0
- package/src/web/scrapers/osv.ts +176 -0
- package/src/web/scrapers/packagist.ts +160 -0
- package/src/web/scrapers/pub-dev.ts +143 -0
- package/src/web/scrapers/pubmed.ts +211 -0
- package/src/web/scrapers/pypi.ts +112 -0
- package/src/web/scrapers/rawg.ts +110 -0
- package/src/web/scrapers/readthedocs.ts +120 -0
- package/src/web/scrapers/reddit.ts +95 -0
- package/src/web/scrapers/repology.ts +251 -0
- package/src/web/scrapers/rfc.ts +201 -0
- package/src/web/scrapers/rubygems.ts +103 -0
- package/src/web/scrapers/searchcode.ts +189 -0
- package/src/web/scrapers/sec-edgar.ts +261 -0
- package/src/web/scrapers/semantic-scholar.ts +171 -0
- package/src/web/scrapers/snapcraft.ts +187 -0
- package/src/web/scrapers/sourcegraph.ts +336 -0
- package/src/web/scrapers/spdx.ts +108 -0
- package/src/web/scrapers/spotify.ts +198 -0
- package/src/web/scrapers/stackoverflow.ts +120 -0
- package/src/web/scrapers/terraform.ts +277 -0
- package/src/web/scrapers/tldr.ts +47 -0
- package/src/web/scrapers/twitter.ts +93 -0
- package/src/web/scrapers/types.ts +318 -0
- package/src/web/scrapers/utils.ts +109 -0
- package/src/web/scrapers/vimeo.ts +133 -0
- package/src/web/scrapers/vscode-marketplace.ts +187 -0
- package/src/web/scrapers/w3c.ts +156 -0
- package/src/web/scrapers/wikidata.ts +344 -0
- package/src/web/scrapers/wikipedia.ts +84 -0
- package/src/web/scrapers/youtube.ts +319 -0
- package/src/web/search/index.ts +288 -0
- package/src/web/search/provider.ts +173 -0
- package/src/web/search/providers/anthropic.ts +302 -0
- package/src/web/search/providers/base.ts +71 -0
- package/src/web/search/providers/brave.ts +149 -0
- package/src/web/search/providers/codex.ts +556 -0
- package/src/web/search/providers/exa.ts +193 -0
- package/src/web/search/providers/gemini.ts +455 -0
- package/src/web/search/providers/jina.ts +101 -0
- package/src/web/search/providers/kagi.ts +75 -0
- package/src/web/search/providers/kimi.ts +171 -0
- package/src/web/search/providers/parallel.ts +210 -0
- package/src/web/search/providers/perplexity.ts +575 -0
- package/src/web/search/providers/searxng.ts +309 -0
- package/src/web/search/providers/synthetic.ts +108 -0
- package/src/web/search/providers/tavily.ts +173 -0
- package/src/web/search/providers/utils.ts +128 -0
- package/src/web/search/providers/zai.ts +320 -0
- package/src/web/search/render.ts +299 -0
- package/src/web/search/types.ts +436 -0
- package/src/web/search/utils.ts +17 -0
- package/src/workspace-tree.ts +286 -0
|
@@ -0,0 +1,2332 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
|
|
5
|
+
import type { ImageContent, TextContent } from "@gajae-code/ai";
|
|
6
|
+
import { glob, type SummaryResult, summarizeCode } from "@gajae-code/natives";
|
|
7
|
+
import type { Component } from "@gajae-code/tui";
|
|
8
|
+
import { Text } from "@gajae-code/tui";
|
|
9
|
+
import { getRemoteDir, logger, prompt, readImageMetadata, untilAborted } from "@gajae-code/utils";
|
|
10
|
+
import * as z from "zod/v4";
|
|
11
|
+
import { getFileReadCache } from "../edit/file-read-cache";
|
|
12
|
+
import { isNotebookPath, readEditableNotebookText } from "../edit/notebook";
|
|
13
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
14
|
+
import { formatHashLine, formatHashLines, formatLineHash, HL_BODY_SEP } from "../hashline/hash";
|
|
15
|
+
import { InternalUrlRouter } from "../internal-urls";
|
|
16
|
+
import { parseInternalUrl } from "../internal-urls/parse";
|
|
17
|
+
import type { InternalUrl } from "../internal-urls/types";
|
|
18
|
+
import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
|
|
19
|
+
import readDescription from "../prompts/tools/read.md" with { type: "text" };
|
|
20
|
+
import type { ToolSession } from "../sdk";
|
|
21
|
+
import {
|
|
22
|
+
DEFAULT_MAX_BYTES,
|
|
23
|
+
DEFAULT_MAX_LINES,
|
|
24
|
+
noTruncResult,
|
|
25
|
+
type TruncationResult,
|
|
26
|
+
truncateHead,
|
|
27
|
+
truncateHeadBytes,
|
|
28
|
+
truncateLine,
|
|
29
|
+
} from "../session/streaming-output";
|
|
30
|
+
import { fileHyperlink, renderCodeCell, renderMarkdownCell, renderStatusLine, tryResolveInternalUrlSync } from "../tui";
|
|
31
|
+
import { CachedOutputBlock } from "../tui/output-block";
|
|
32
|
+
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
33
|
+
import { ImageInputTooLargeError, loadImageInput, MAX_IMAGE_INPUT_BYTES } from "../utils/image-loading";
|
|
34
|
+
import { convertFileWithMarkit } from "../utils/markit";
|
|
35
|
+
import { buildDirectoryTree, type DirectoryTree } from "../workspace-tree";
|
|
36
|
+
import { type ArchiveReader, openArchive, parseArchivePathCandidates } from "./archive-reader";
|
|
37
|
+
import {
|
|
38
|
+
type ConflictEntry,
|
|
39
|
+
type ConflictScope,
|
|
40
|
+
formatConflictSummary,
|
|
41
|
+
formatConflictWarning,
|
|
42
|
+
getConflictHistory,
|
|
43
|
+
parseConflictUri,
|
|
44
|
+
renderConflictRegion,
|
|
45
|
+
scanConflictLines,
|
|
46
|
+
scanFileForConflicts,
|
|
47
|
+
} from "./conflict-detect";
|
|
48
|
+
import {
|
|
49
|
+
executeReadUrl,
|
|
50
|
+
isReadableUrlPath,
|
|
51
|
+
loadReadUrlCacheEntry,
|
|
52
|
+
parseReadUrlTarget,
|
|
53
|
+
type ReadUrlToolDetails,
|
|
54
|
+
renderReadUrlCall,
|
|
55
|
+
renderReadUrlResult,
|
|
56
|
+
} from "./fetch";
|
|
57
|
+
import { applyListLimit } from "./list-limit";
|
|
58
|
+
import {
|
|
59
|
+
formatFullOutputReference,
|
|
60
|
+
formatStyledTruncationWarning,
|
|
61
|
+
type OutputMeta,
|
|
62
|
+
resolveOutputMaxColumns,
|
|
63
|
+
stripOutputNotice,
|
|
64
|
+
} from "./output-meta";
|
|
65
|
+
import {
|
|
66
|
+
expandPath,
|
|
67
|
+
formatPathRelativeToCwd,
|
|
68
|
+
resolveReadPath,
|
|
69
|
+
splitInternalUrlSel,
|
|
70
|
+
splitPathAndSel,
|
|
71
|
+
} from "./path-utils";
|
|
72
|
+
import { formatBytes, replaceTabs, shortenPath, wrapBrackets } from "./render-utils";
|
|
73
|
+
import {
|
|
74
|
+
executeReadQuery,
|
|
75
|
+
getRowByKey,
|
|
76
|
+
getRowByRowId,
|
|
77
|
+
getTableSchema,
|
|
78
|
+
isSqliteFile,
|
|
79
|
+
listTables,
|
|
80
|
+
parseSqlitePathCandidates,
|
|
81
|
+
parseSqliteSelector,
|
|
82
|
+
queryRows,
|
|
83
|
+
renderRow,
|
|
84
|
+
renderSchema,
|
|
85
|
+
renderTable,
|
|
86
|
+
renderTableList,
|
|
87
|
+
resolveTableRowLookup,
|
|
88
|
+
} from "./sqlite-reader";
|
|
89
|
+
import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
|
|
90
|
+
import { toolResult } from "./tool-result";
|
|
91
|
+
|
|
92
|
+
// Document types converted to markdown via markit.
|
|
93
|
+
const CONVERTIBLE_EXTENSIONS = new Set([".pdf", ".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx", ".rtf", ".epub"]);
|
|
94
|
+
|
|
95
|
+
const MAX_SUMMARY_BYTES = 2 * 1024 * 1024;
|
|
96
|
+
const MAX_SUMMARY_LINES = 20_000;
|
|
97
|
+
/**
|
|
98
|
+
* Per-line column cap for file reads. Lines wider than the value of
|
|
99
|
+
* `tools.outputMaxColumns` are ellipsis-truncated at display time; the file
|
|
100
|
+
* on disk is unchanged. Shared with the streaming sink path so one setting
|
|
101
|
+
* covers `bash`/`ssh`/`python`/`js eval` and `read` uniformly.
|
|
102
|
+
*/
|
|
103
|
+
const PROSE_SUMMARY_EXTENSIONS = new Set([".md", ".txt"]);
|
|
104
|
+
// Remote mount path prefix (sshfs mounts) - skip fuzzy matching to avoid hangs
|
|
105
|
+
const REMOTE_MOUNT_PREFIX = getRemoteDir() + path.sep;
|
|
106
|
+
|
|
107
|
+
function isRemoteMountPath(absolutePath: string): boolean {
|
|
108
|
+
return absolutePath.startsWith(REMOTE_MOUNT_PREFIX);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function prependLineNumbers(text: string, startNum: number): string {
|
|
112
|
+
const textLines = text.split("\n");
|
|
113
|
+
return textLines.map((line, i) => `${startNum + i}|${line}`).join("\n");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function formatTextWithMode(
|
|
117
|
+
text: string,
|
|
118
|
+
startNum: number,
|
|
119
|
+
shouldAddHashLines: boolean,
|
|
120
|
+
shouldAddLineNumbers: boolean,
|
|
121
|
+
): string {
|
|
122
|
+
if (shouldAddHashLines) return formatHashLines(text, startNum);
|
|
123
|
+
if (shouldAddLineNumbers) return prependLineNumbers(text, startNum);
|
|
124
|
+
return text;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const BRACE_PAIRS: Record<string, string> = { "{": "}", "(": ")", "[": "]" };
|
|
128
|
+
const BRACE_TAIL_TRAILING_RE = /^[;,)\]}]*$/;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Decide whether the kept lines surrounding an elided range collapse to a
|
|
132
|
+
* single brace-pair line in the rendered summary. Returns true when the head
|
|
133
|
+
* line ends with `{` / `(` / `[` and the tail line is the matching closer
|
|
134
|
+
* (optionally followed by terminating punctuation like `;`, `,`, or further
|
|
135
|
+
* closers — e.g. `};`, `})`, `]);`).
|
|
136
|
+
*/
|
|
137
|
+
function canMergeBracePair(headLine: string, tailLine: string): boolean {
|
|
138
|
+
const head = headLine.trimEnd();
|
|
139
|
+
const tail = tailLine.trim();
|
|
140
|
+
const opener = head.slice(-1);
|
|
141
|
+
const closer = BRACE_PAIRS[opener];
|
|
142
|
+
if (!closer) return false;
|
|
143
|
+
if (!tail.startsWith(closer)) return false;
|
|
144
|
+
return BRACE_TAIL_TRAILING_RE.test(tail.slice(closer.length));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function formatSingleLine(
|
|
148
|
+
line: number,
|
|
149
|
+
text: string,
|
|
150
|
+
shouldAddHashLines: boolean,
|
|
151
|
+
shouldAddLineNumbers: boolean,
|
|
152
|
+
): string {
|
|
153
|
+
if (shouldAddHashLines) return formatHashLine(line, text);
|
|
154
|
+
if (shouldAddLineNumbers) return `${line}|${text}`;
|
|
155
|
+
return text;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function formatMergedBraceLine(
|
|
159
|
+
startLine: number,
|
|
160
|
+
endLine: number,
|
|
161
|
+
headText: string,
|
|
162
|
+
tailText: string,
|
|
163
|
+
shouldAddHashLines: boolean,
|
|
164
|
+
shouldAddLineNumbers: boolean,
|
|
165
|
+
): { model: string; display: string } {
|
|
166
|
+
const merged = `${headText.trimEnd()} .. ${tailText.trim()}`;
|
|
167
|
+
if (shouldAddHashLines) {
|
|
168
|
+
const start = formatLineHash(startLine, headText);
|
|
169
|
+
const end = formatLineHash(endLine, tailText);
|
|
170
|
+
return { model: `${start}-${end}${HL_BODY_SEP}${merged}`, display: merged };
|
|
171
|
+
}
|
|
172
|
+
if (shouldAddLineNumbers) {
|
|
173
|
+
return { model: `${startLine}-${endLine}|${merged}`, display: merged };
|
|
174
|
+
}
|
|
175
|
+
return { model: merged, display: merged };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function countTextLines(text: string): number {
|
|
179
|
+
if (text.length === 0) return 0;
|
|
180
|
+
return text.split("\n").length;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Footer appended to summarized reads telling the model how to recover the
|
|
185
|
+
* elided body. Without this hint, agents either ignore the `...`/`{ .. }`
|
|
186
|
+
* markers or burn a turn guessing the right selector (see issue #1046).
|
|
187
|
+
*/
|
|
188
|
+
function formatSummaryElisionFooter(readPath: string, elidedSpans: number, elidedLines: number): string {
|
|
189
|
+
if (elidedSpans <= 0) return "";
|
|
190
|
+
const spanWord = elidedSpans === 1 ? "region" : "regions";
|
|
191
|
+
const lineWord = elidedLines === 1 ? "line" : "lines";
|
|
192
|
+
const linePart = elidedLines > 0 ? `${elidedLines} ${lineWord} across ` : "";
|
|
193
|
+
return `[${linePart}${elidedSpans} elided ${spanWord}; read ${readPath}:raw or a line range like ${readPath}:1-9999 for verbatim content]`;
|
|
194
|
+
}
|
|
195
|
+
const READ_CHUNK_SIZE = 8 * 1024;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Context lines added around an explicit range read. Anchor-stale failures
|
|
199
|
+
* cluster on edits whose anchors land just outside the most recent read
|
|
200
|
+
* window, but the data (`scripts/session-stats/analyze_selector_reads.py`)
|
|
201
|
+
* shows most follow-up reads are disjoint hops, not adjacent extensions —
|
|
202
|
+
* so symmetric padding rarely pays for itself.
|
|
203
|
+
*
|
|
204
|
+
* Leading=1 catches accidental single-line reads where the anchor is the
|
|
205
|
+
* line immediately above the requested start. Trailing=3 buffers the
|
|
206
|
+
* common case where the agent asks for a narrow range and then needs the
|
|
207
|
+
* next few lines to disambiguate an anchor.
|
|
208
|
+
*/
|
|
209
|
+
const RANGE_LEADING_CONTEXT_LINES = 1;
|
|
210
|
+
const RANGE_TRAILING_CONTEXT_LINES = 3;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Expand a [start, end) range with leading/trailing context lines on the
|
|
214
|
+
* sides where the user actually constrained the range. A start of 0 (no
|
|
215
|
+
* explicit offset) does not get leading context — that's already an
|
|
216
|
+
* open-ended read from the top.
|
|
217
|
+
*/
|
|
218
|
+
function expandRangeWithContext(
|
|
219
|
+
requestedStart: number,
|
|
220
|
+
requestedEnd: number,
|
|
221
|
+
totalLines: number,
|
|
222
|
+
expandStart: boolean,
|
|
223
|
+
expandEnd: boolean,
|
|
224
|
+
): { startLine: number; endLine: number } {
|
|
225
|
+
return {
|
|
226
|
+
startLine: expandStart ? Math.max(0, requestedStart - RANGE_LEADING_CONTEXT_LINES) : requestedStart,
|
|
227
|
+
endLine: expandEnd ? Math.min(totalLines, requestedEnd + RANGE_TRAILING_CONTEXT_LINES) : requestedEnd,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function streamLinesFromFile(
|
|
232
|
+
filePath: string,
|
|
233
|
+
startLine: number,
|
|
234
|
+
maxLinesToCollect: number,
|
|
235
|
+
maxBytes: number,
|
|
236
|
+
selectedLineLimit: number | null,
|
|
237
|
+
signal?: AbortSignal,
|
|
238
|
+
): Promise<{
|
|
239
|
+
lines: string[];
|
|
240
|
+
totalFileLines: number;
|
|
241
|
+
collectedBytes: number;
|
|
242
|
+
stoppedByByteLimit: boolean;
|
|
243
|
+
firstLinePreview?: { text: string; bytes: number };
|
|
244
|
+
firstLineByteLength?: number;
|
|
245
|
+
selectedBytesTotal: number;
|
|
246
|
+
}> {
|
|
247
|
+
const bufferChunk = Buffer.allocUnsafe(READ_CHUNK_SIZE);
|
|
248
|
+
const collectedLines: string[] = [];
|
|
249
|
+
let lineIndex = 0;
|
|
250
|
+
let collectedBytes = 0;
|
|
251
|
+
let stoppedByByteLimit = false;
|
|
252
|
+
let doneCollecting = false;
|
|
253
|
+
let fileHandle: fs.FileHandle | null = null;
|
|
254
|
+
let currentLineLength = 0;
|
|
255
|
+
let currentLineChunks: Buffer[] = [];
|
|
256
|
+
let sawAnyByte = false;
|
|
257
|
+
let endedWithNewline = false;
|
|
258
|
+
let firstLinePreviewBytes = 0;
|
|
259
|
+
const firstLinePreviewChunks: Buffer[] = [];
|
|
260
|
+
let firstLineByteLength: number | undefined;
|
|
261
|
+
let selectedBytesTotal = 0;
|
|
262
|
+
let selectedLinesSeen = 0;
|
|
263
|
+
let captureLine = false;
|
|
264
|
+
let discardLineChunks = false;
|
|
265
|
+
let lineCaptureLimit = 0;
|
|
266
|
+
|
|
267
|
+
const setupLineState = () => {
|
|
268
|
+
captureLine = !doneCollecting && lineIndex >= startLine;
|
|
269
|
+
discardLineChunks = !captureLine;
|
|
270
|
+
if (captureLine) {
|
|
271
|
+
const separatorBytes = collectedLines.length > 0 ? 1 : 0;
|
|
272
|
+
lineCaptureLimit = maxBytes - collectedBytes - separatorBytes;
|
|
273
|
+
if (lineCaptureLimit <= 0) {
|
|
274
|
+
discardLineChunks = true;
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
lineCaptureLimit = 0;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const decodeLine = (): string => {
|
|
282
|
+
if (currentLineLength === 0) return "";
|
|
283
|
+
if (currentLineChunks.length === 1 && currentLineChunks[0]?.length === currentLineLength) {
|
|
284
|
+
return currentLineChunks[0].toString("utf-8");
|
|
285
|
+
}
|
|
286
|
+
return Buffer.concat(currentLineChunks, currentLineLength).toString("utf-8");
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const maybeCapturePreview = (segment: Uint8Array) => {
|
|
290
|
+
if (doneCollecting || lineIndex < startLine || collectedLines.length !== 0) return;
|
|
291
|
+
if (firstLinePreviewBytes >= maxBytes || segment.length === 0) return;
|
|
292
|
+
const remaining = maxBytes - firstLinePreviewBytes;
|
|
293
|
+
const slice = segment.length > remaining ? segment.subarray(0, remaining) : segment;
|
|
294
|
+
if (slice.length === 0) return;
|
|
295
|
+
firstLinePreviewChunks.push(Buffer.from(slice));
|
|
296
|
+
firstLinePreviewBytes += slice.length;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const appendSegment = (segment: Uint8Array) => {
|
|
300
|
+
currentLineLength += segment.length;
|
|
301
|
+
maybeCapturePreview(segment);
|
|
302
|
+
if (!captureLine || discardLineChunks || segment.length === 0) return;
|
|
303
|
+
if (currentLineLength <= lineCaptureLimit) {
|
|
304
|
+
currentLineChunks.push(Buffer.from(segment));
|
|
305
|
+
} else {
|
|
306
|
+
discardLineChunks = true;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const finalizeLine = () => {
|
|
311
|
+
if (lineIndex >= startLine && (selectedLineLimit === null || selectedLinesSeen < selectedLineLimit)) {
|
|
312
|
+
selectedBytesTotal += currentLineLength + (selectedLinesSeen > 0 ? 1 : 0);
|
|
313
|
+
selectedLinesSeen++;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!doneCollecting && lineIndex >= startLine) {
|
|
317
|
+
const separatorBytes = collectedLines.length > 0 ? 1 : 0;
|
|
318
|
+
if (collectedLines.length >= maxLinesToCollect) {
|
|
319
|
+
doneCollecting = true;
|
|
320
|
+
} else if (collectedLines.length === 0 && currentLineLength > maxBytes) {
|
|
321
|
+
stoppedByByteLimit = true;
|
|
322
|
+
doneCollecting = true;
|
|
323
|
+
if (firstLineByteLength === undefined) {
|
|
324
|
+
firstLineByteLength = currentLineLength;
|
|
325
|
+
}
|
|
326
|
+
} else if (collectedLines.length > 0 && collectedBytes + separatorBytes + currentLineLength > maxBytes) {
|
|
327
|
+
stoppedByByteLimit = true;
|
|
328
|
+
doneCollecting = true;
|
|
329
|
+
} else {
|
|
330
|
+
const lineText = decodeLine();
|
|
331
|
+
collectedLines.push(lineText);
|
|
332
|
+
collectedBytes += separatorBytes + currentLineLength;
|
|
333
|
+
if (firstLineByteLength === undefined) {
|
|
334
|
+
firstLineByteLength = currentLineLength;
|
|
335
|
+
}
|
|
336
|
+
if (collectedBytes > maxBytes) {
|
|
337
|
+
stoppedByByteLimit = true;
|
|
338
|
+
doneCollecting = true;
|
|
339
|
+
} else if (collectedLines.length >= maxLinesToCollect) {
|
|
340
|
+
doneCollecting = true;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} else if (lineIndex >= startLine && firstLineByteLength === undefined) {
|
|
344
|
+
firstLineByteLength = currentLineLength;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
lineIndex++;
|
|
348
|
+
currentLineLength = 0;
|
|
349
|
+
currentLineChunks = [];
|
|
350
|
+
setupLineState();
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
setupLineState();
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
fileHandle = await fs.open(filePath, "r");
|
|
357
|
+
|
|
358
|
+
while (true) {
|
|
359
|
+
throwIfAborted(signal);
|
|
360
|
+
const { bytesRead } = await fileHandle.read(bufferChunk, 0, bufferChunk.length, null);
|
|
361
|
+
if (bytesRead === 0) break;
|
|
362
|
+
|
|
363
|
+
sawAnyByte = true;
|
|
364
|
+
const chunk = bufferChunk.subarray(0, bytesRead);
|
|
365
|
+
endedWithNewline = chunk[bytesRead - 1] === 0x0a;
|
|
366
|
+
|
|
367
|
+
let start = 0;
|
|
368
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
369
|
+
if (chunk[i] === 0x0a) {
|
|
370
|
+
const segment = chunk.subarray(start, i);
|
|
371
|
+
if (segment.length > 0) {
|
|
372
|
+
appendSegment(segment);
|
|
373
|
+
}
|
|
374
|
+
finalizeLine();
|
|
375
|
+
start = i + 1;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (start < chunk.length) {
|
|
380
|
+
appendSegment(chunk.subarray(start));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
} finally {
|
|
384
|
+
if (fileHandle) {
|
|
385
|
+
await fileHandle.close();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (endedWithNewline || currentLineLength > 0 || !sawAnyByte) {
|
|
390
|
+
finalizeLine();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
let firstLinePreview: { text: string; bytes: number } | undefined;
|
|
394
|
+
if (firstLinePreviewBytes > 0) {
|
|
395
|
+
const { text, bytes } = truncateHeadBytes(Buffer.concat(firstLinePreviewChunks, firstLinePreviewBytes), maxBytes);
|
|
396
|
+
firstLinePreview = { text, bytes };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
lines: collectedLines,
|
|
401
|
+
totalFileLines: lineIndex,
|
|
402
|
+
collectedBytes,
|
|
403
|
+
stoppedByByteLimit,
|
|
404
|
+
firstLinePreview,
|
|
405
|
+
firstLineByteLength,
|
|
406
|
+
selectedBytesTotal,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Maximum image file size (20MB) - larger images will be rejected to prevent OOM during serialization
|
|
411
|
+
const MAX_IMAGE_SIZE = MAX_IMAGE_INPUT_BYTES;
|
|
412
|
+
const GLOB_TIMEOUT_MS = 5000;
|
|
413
|
+
|
|
414
|
+
function isNotFoundError(error: unknown): boolean {
|
|
415
|
+
if (!error || typeof error !== "object") return false;
|
|
416
|
+
const code = (error as { code?: string }).code;
|
|
417
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Attempt to resolve a non-existent path by finding a unique suffix match within the workspace.
|
|
422
|
+
* Uses a glob suffix pattern so the native engine handles matching directly.
|
|
423
|
+
* Returns null when 0 or >1 candidates match (ambiguous = no auto-resolution).
|
|
424
|
+
*/
|
|
425
|
+
async function findUniqueSuffixMatch(
|
|
426
|
+
rawPath: string,
|
|
427
|
+
cwd: string,
|
|
428
|
+
signal?: AbortSignal,
|
|
429
|
+
): Promise<{ absolutePath: string; displayPath: string } | null> {
|
|
430
|
+
const normalized = rawPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
431
|
+
if (!normalized) return null;
|
|
432
|
+
|
|
433
|
+
const timeoutSignal = AbortSignal.timeout(GLOB_TIMEOUT_MS);
|
|
434
|
+
const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
435
|
+
|
|
436
|
+
let matches: string[];
|
|
437
|
+
try {
|
|
438
|
+
const result = await untilAborted(combinedSignal, () =>
|
|
439
|
+
glob({
|
|
440
|
+
pattern: `**/${normalized}`,
|
|
441
|
+
path: cwd,
|
|
442
|
+
// No fileType filter: matches both files and directories
|
|
443
|
+
hidden: true,
|
|
444
|
+
}),
|
|
445
|
+
);
|
|
446
|
+
matches = result.matches.map(m => m.path);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
449
|
+
if (!signal?.aborted) return null; // timeout — give up silently
|
|
450
|
+
throw new ToolAbortError();
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (matches.length !== 1) return null;
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
absolutePath: path.resolve(cwd, matches[0]),
|
|
459
|
+
displayPath: matches[0],
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function decodeUtf8Text(bytes: Uint8Array): string | null {
|
|
464
|
+
for (const byte of bytes) {
|
|
465
|
+
if (byte === 0) return null;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
470
|
+
} catch {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function prependSuffixResolutionNotice(text: string, suffixResolution?: { from: string; to: string }): string {
|
|
476
|
+
if (!suffixResolution) return text;
|
|
477
|
+
|
|
478
|
+
const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
|
|
479
|
+
return text ? `${notice}\n${text}` : notice;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const readSchema = z
|
|
483
|
+
.object({
|
|
484
|
+
path: z.string().describe('path or url; append :<sel> for line ranges or raw mode (e.g. "src/foo.ts:50-100")'),
|
|
485
|
+
})
|
|
486
|
+
.strict();
|
|
487
|
+
|
|
488
|
+
export type ReadToolInput = z.infer<typeof readSchema>;
|
|
489
|
+
|
|
490
|
+
export interface ReadToolDetails {
|
|
491
|
+
kind?: "file" | "url";
|
|
492
|
+
truncation?: TruncationResult;
|
|
493
|
+
isDirectory?: boolean;
|
|
494
|
+
resolvedPath?: string;
|
|
495
|
+
suffixResolution?: { from: string; to: string };
|
|
496
|
+
url?: string;
|
|
497
|
+
finalUrl?: string;
|
|
498
|
+
contentType?: string;
|
|
499
|
+
method?: string;
|
|
500
|
+
notes?: string[];
|
|
501
|
+
meta?: OutputMeta;
|
|
502
|
+
/** Raw text + start line for user-visible TUI rendering, set when content is text-like.
|
|
503
|
+
* Mirrors the same lines the model receives but without hashline/line-number prefixes,
|
|
504
|
+
* so the TUI can render the file content with its own gutter without re-parsing the formatted text. */
|
|
505
|
+
displayContent?: { text: string; startLine: number };
|
|
506
|
+
summary?: { lines: number; elidedSpans: number; elidedLines: number };
|
|
507
|
+
/** Number of unresolved git conflicts surfaced by this read (TUI uses for inline `⚠ N` badge). */
|
|
508
|
+
conflictCount?: number;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
type ReadParams = ReadToolInput;
|
|
512
|
+
|
|
513
|
+
/** Parsed representation of a path-embedded selector. */
|
|
514
|
+
type LineRange = { startLine: number; endLine: number | undefined };
|
|
515
|
+
|
|
516
|
+
type ParsedSelector =
|
|
517
|
+
| { kind: "none" }
|
|
518
|
+
| { kind: "raw" }
|
|
519
|
+
| { kind: "conflicts" }
|
|
520
|
+
| { kind: "lines"; ranges: [LineRange, ...LineRange[]]; raw?: boolean };
|
|
521
|
+
|
|
522
|
+
const LINE_RANGE_RE = /^L?(\d+)(?:([-+])L?(\d+)?)?$/i;
|
|
523
|
+
|
|
524
|
+
/** Returns true when the selector requested verbatim/raw output (alone or combined with a range). */
|
|
525
|
+
function isRawSelector(parsed: ParsedSelector): boolean {
|
|
526
|
+
return parsed.kind === "raw" || (parsed.kind === "lines" && parsed.raw === true);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/** Returns true when the selector requested multiple line ranges. */
|
|
530
|
+
function isMultiRange(parsed: ParsedSelector): boolean {
|
|
531
|
+
return parsed.kind === "lines" && parsed.ranges.length > 1;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function parseLineRangeChunk(sel: string): LineRange | null {
|
|
535
|
+
const lineMatch = LINE_RANGE_RE.exec(sel);
|
|
536
|
+
if (!lineMatch) return null;
|
|
537
|
+
const rawStart = Number.parseInt(lineMatch[1]!, 10);
|
|
538
|
+
if (rawStart < 1) {
|
|
539
|
+
throw new ToolError("Line selector 0 is invalid; lines are 1-indexed. Use :1.");
|
|
540
|
+
}
|
|
541
|
+
const sep = lineMatch[2];
|
|
542
|
+
const rhs = lineMatch[3] ? Number.parseInt(lineMatch[3], 10) : undefined;
|
|
543
|
+
let rawEnd: number | undefined;
|
|
544
|
+
if (sep === "+") {
|
|
545
|
+
if (rhs === undefined || rhs < 1) {
|
|
546
|
+
throw new ToolError(`Invalid range ${rawStart}+${rhs ?? 0}: count must be >= 1.`);
|
|
547
|
+
}
|
|
548
|
+
rawEnd = rawStart + rhs - 1;
|
|
549
|
+
} else if (sep === "-") {
|
|
550
|
+
// `301-` is shorthand for "from 301 onward" — equivalent to bare `301`.
|
|
551
|
+
if (rhs !== undefined) {
|
|
552
|
+
if (rhs < rawStart) {
|
|
553
|
+
throw new ToolError(`Invalid range ${rawStart}-${rhs}: end must be >= start.`);
|
|
554
|
+
}
|
|
555
|
+
rawEnd = rhs;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return { startLine: rawStart, endLine: rawEnd };
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Parse a comma-separated list of line ranges (e.g. `5-16,960-973`). Returns
|
|
563
|
+
* the ranges in ascending order with overlapping/adjacent ranges merged so
|
|
564
|
+
* downstream consumers can stream the file in a single forward pass per range.
|
|
565
|
+
*/
|
|
566
|
+
function parseLineRanges(sel: string): [LineRange, ...LineRange[]] | null {
|
|
567
|
+
const chunks = sel.split(",");
|
|
568
|
+
const parsed: LineRange[] = [];
|
|
569
|
+
for (const chunk of chunks) {
|
|
570
|
+
const range = parseLineRangeChunk(chunk);
|
|
571
|
+
if (!range) return null;
|
|
572
|
+
parsed.push(range);
|
|
573
|
+
}
|
|
574
|
+
if (parsed.length === 0) return null;
|
|
575
|
+
parsed.sort((a, b) => a.startLine - b.startLine);
|
|
576
|
+
|
|
577
|
+
const merged: LineRange[] = [parsed[0]];
|
|
578
|
+
for (let i = 1; i < parsed.length; i++) {
|
|
579
|
+
const current = parsed[i];
|
|
580
|
+
const last = merged[merged.length - 1];
|
|
581
|
+
// Open-ended (endLine undefined) means "to EOF" — any later range is absorbed.
|
|
582
|
+
if (last.endLine === undefined) continue;
|
|
583
|
+
// Merge when current starts within (or immediately after) the last range.
|
|
584
|
+
if (current.startLine <= last.endLine + 1) {
|
|
585
|
+
if (current.endLine === undefined || current.endLine > last.endLine) {
|
|
586
|
+
merged[merged.length - 1] = { startLine: last.startLine, endLine: current.endLine };
|
|
587
|
+
}
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
merged.push(current);
|
|
591
|
+
}
|
|
592
|
+
return merged as [LineRange, ...LineRange[]];
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function parseSel(sel: string | undefined): ParsedSelector {
|
|
596
|
+
if (!sel || sel.length === 0) return { kind: "none" };
|
|
597
|
+
|
|
598
|
+
// Compound selector: `1-50:raw` or `raw:1-50`. Split into chunks and accept
|
|
599
|
+
// any combination of one line range (possibly multi) and the literal `raw`.
|
|
600
|
+
if (sel.includes(":")) {
|
|
601
|
+
const chunks = sel.split(":");
|
|
602
|
+
if (chunks.length === 2) {
|
|
603
|
+
const [a, b] = chunks as [string, string];
|
|
604
|
+
const aIsRaw = a.toLowerCase() === "raw";
|
|
605
|
+
const bIsRaw = b.toLowerCase() === "raw";
|
|
606
|
+
const rangeChunk = aIsRaw ? b : bIsRaw ? a : null;
|
|
607
|
+
const rawChunk = aIsRaw ? a : bIsRaw ? b : null;
|
|
608
|
+
if (rangeChunk !== null && rawChunk !== null) {
|
|
609
|
+
const ranges = parseLineRanges(rangeChunk);
|
|
610
|
+
if (ranges) {
|
|
611
|
+
return { kind: "lines", ranges, raw: true };
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// Unrecognized compound — fall through (sqlite/archive/url consume their own colon syntax).
|
|
616
|
+
return { kind: "none" };
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (sel.toLowerCase() === "raw") return { kind: "raw" };
|
|
620
|
+
if (sel.toLowerCase() === "conflicts") return { kind: "conflicts" };
|
|
621
|
+
const ranges = parseLineRanges(sel);
|
|
622
|
+
if (ranges) {
|
|
623
|
+
return { kind: "lines", ranges };
|
|
624
|
+
}
|
|
625
|
+
// Unrecognized selectors fall through; sqlite/archive/url readers consume their own colon syntax.
|
|
626
|
+
return { kind: "none" };
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Convert a single-range selector to the offset/limit pair used by internal pagination.
|
|
631
|
+
* Returns the FIRST range only — multi-range callers MUST branch on `isMultiRange` before
|
|
632
|
+
* calling this helper.
|
|
633
|
+
*/
|
|
634
|
+
function selToOffsetLimit(parsed: ParsedSelector): { offset?: number; limit?: number } {
|
|
635
|
+
if (parsed.kind === "lines") {
|
|
636
|
+
const first = parsed.ranges[0];
|
|
637
|
+
const limit = first.endLine !== undefined ? first.endLine - first.startLine + 1 : undefined;
|
|
638
|
+
return { offset: first.startLine, limit };
|
|
639
|
+
}
|
|
640
|
+
return {};
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
interface ResolvedArchiveReadPath {
|
|
644
|
+
absolutePath: string;
|
|
645
|
+
archiveSubPath: string;
|
|
646
|
+
suffixResolution?: { from: string; to: string };
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
interface ResolvedSqliteReadPath {
|
|
650
|
+
absolutePath: string;
|
|
651
|
+
sqliteSubPath: string;
|
|
652
|
+
queryString: string;
|
|
653
|
+
suffixResolution?: { from: string; to: string };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Read tool implementation.
|
|
658
|
+
*
|
|
659
|
+
* Reads files with support for images, converted documents (via markit), and text.
|
|
660
|
+
* Directories return a formatted listing with modification times.
|
|
661
|
+
*/
|
|
662
|
+
export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
663
|
+
readonly name = "read";
|
|
664
|
+
readonly label = "Read";
|
|
665
|
+
readonly loadMode = "essential";
|
|
666
|
+
readonly description: string;
|
|
667
|
+
readonly parameters = readSchema;
|
|
668
|
+
readonly nonAbortable = true;
|
|
669
|
+
readonly strict = true;
|
|
670
|
+
|
|
671
|
+
readonly #autoResizeImages: boolean;
|
|
672
|
+
readonly #defaultLimit: number;
|
|
673
|
+
readonly #inspectImageEnabled: boolean;
|
|
674
|
+
|
|
675
|
+
constructor(private readonly session: ToolSession) {
|
|
676
|
+
const displayMode = resolveFileDisplayMode(session);
|
|
677
|
+
this.#autoResizeImages = session.settings.get("images.autoResize");
|
|
678
|
+
this.#defaultLimit = Math.max(
|
|
679
|
+
1,
|
|
680
|
+
Math.min(session.settings.get("read.defaultLimit") ?? DEFAULT_MAX_LINES, DEFAULT_MAX_LINES),
|
|
681
|
+
);
|
|
682
|
+
this.#inspectImageEnabled = session.settings.get("inspect_image.enabled");
|
|
683
|
+
this.description = prompt.render(readDescription, {
|
|
684
|
+
DEFAULT_LIMIT: String(this.#defaultLimit),
|
|
685
|
+
DEFAULT_MAX_LINES: String(DEFAULT_MAX_LINES),
|
|
686
|
+
IS_HL_MODE: displayMode.hashLines,
|
|
687
|
+
IS_LINE_NUMBER_MODE: !displayMode.hashLines && displayMode.lineNumbers,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
async #resolveArchiveReadPath(readPath: string, signal?: AbortSignal): Promise<ResolvedArchiveReadPath | null> {
|
|
692
|
+
const candidates = parseArchivePathCandidates(readPath);
|
|
693
|
+
for (const candidate of candidates) {
|
|
694
|
+
let absolutePath = resolveReadPath(candidate.archivePath, this.session.cwd);
|
|
695
|
+
let suffixResolution: { from: string; to: string } | undefined;
|
|
696
|
+
|
|
697
|
+
try {
|
|
698
|
+
const stat = await Bun.file(absolutePath).stat();
|
|
699
|
+
if (stat.isDirectory()) continue;
|
|
700
|
+
return {
|
|
701
|
+
absolutePath,
|
|
702
|
+
archiveSubPath: candidate.archivePath === readPath ? "" : candidate.subPath,
|
|
703
|
+
suffixResolution,
|
|
704
|
+
};
|
|
705
|
+
} catch (error) {
|
|
706
|
+
if (!isNotFoundError(error) || isRemoteMountPath(absolutePath)) continue;
|
|
707
|
+
|
|
708
|
+
const suffixMatch = await findUniqueSuffixMatch(candidate.archivePath, this.session.cwd, signal);
|
|
709
|
+
if (!suffixMatch) continue;
|
|
710
|
+
|
|
711
|
+
try {
|
|
712
|
+
const retryStat = await Bun.file(suffixMatch.absolutePath).stat();
|
|
713
|
+
if (retryStat.isDirectory()) continue;
|
|
714
|
+
|
|
715
|
+
absolutePath = suffixMatch.absolutePath;
|
|
716
|
+
suffixResolution = { from: candidate.archivePath, to: suffixMatch.displayPath };
|
|
717
|
+
return {
|
|
718
|
+
absolutePath,
|
|
719
|
+
archiveSubPath: candidate.archivePath === readPath ? "" : candidate.subPath,
|
|
720
|
+
suffixResolution,
|
|
721
|
+
};
|
|
722
|
+
} catch (retryError) {
|
|
723
|
+
if (!isNotFoundError(retryError)) {
|
|
724
|
+
throw retryError;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
async #resolveSqliteReadPath(readPath: string, signal?: AbortSignal): Promise<ResolvedSqliteReadPath | null> {
|
|
734
|
+
const candidates = parseSqlitePathCandidates(readPath);
|
|
735
|
+
for (const candidate of candidates) {
|
|
736
|
+
let absolutePath = resolveReadPath(candidate.sqlitePath, this.session.cwd);
|
|
737
|
+
let suffixResolution: { from: string; to: string } | undefined;
|
|
738
|
+
|
|
739
|
+
try {
|
|
740
|
+
const stat = await Bun.file(absolutePath).stat();
|
|
741
|
+
if (stat.isDirectory()) continue;
|
|
742
|
+
if (!(await isSqliteFile(absolutePath))) continue;
|
|
743
|
+
|
|
744
|
+
return {
|
|
745
|
+
absolutePath,
|
|
746
|
+
sqliteSubPath: candidate.subPath,
|
|
747
|
+
queryString: candidate.queryString,
|
|
748
|
+
suffixResolution,
|
|
749
|
+
};
|
|
750
|
+
} catch (error) {
|
|
751
|
+
if (!isNotFoundError(error) || isRemoteMountPath(absolutePath)) continue;
|
|
752
|
+
|
|
753
|
+
const suffixMatch = await findUniqueSuffixMatch(candidate.sqlitePath, this.session.cwd, signal);
|
|
754
|
+
if (!suffixMatch) continue;
|
|
755
|
+
|
|
756
|
+
try {
|
|
757
|
+
const retryStat = await Bun.file(suffixMatch.absolutePath).stat();
|
|
758
|
+
if (retryStat.isDirectory()) continue;
|
|
759
|
+
if (!(await isSqliteFile(suffixMatch.absolutePath))) continue;
|
|
760
|
+
|
|
761
|
+
absolutePath = suffixMatch.absolutePath;
|
|
762
|
+
suffixResolution = { from: candidate.sqlitePath, to: suffixMatch.displayPath };
|
|
763
|
+
return {
|
|
764
|
+
absolutePath,
|
|
765
|
+
sqliteSubPath: candidate.subPath,
|
|
766
|
+
queryString: candidate.queryString,
|
|
767
|
+
suffixResolution,
|
|
768
|
+
};
|
|
769
|
+
} catch (retryError) {
|
|
770
|
+
if (!isNotFoundError(retryError)) {
|
|
771
|
+
throw retryError;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
#buildInMemoryTextResult(
|
|
781
|
+
text: string,
|
|
782
|
+
offset: number | undefined,
|
|
783
|
+
limit: number | undefined,
|
|
784
|
+
options: {
|
|
785
|
+
details?: ReadToolDetails;
|
|
786
|
+
sourcePath?: string;
|
|
787
|
+
sourceUrl?: string;
|
|
788
|
+
sourceInternal?: string;
|
|
789
|
+
entityLabel: string;
|
|
790
|
+
ignoreResultLimits?: boolean;
|
|
791
|
+
raw?: boolean;
|
|
792
|
+
immutable?: boolean;
|
|
793
|
+
},
|
|
794
|
+
): AgentToolResult<ReadToolDetails> {
|
|
795
|
+
const displayMode = resolveFileDisplayMode(this.session, { raw: options.raw, immutable: options.immutable });
|
|
796
|
+
const details = options.details ?? {};
|
|
797
|
+
const allLines = text.split("\n");
|
|
798
|
+
const totalLines = allLines.length;
|
|
799
|
+
// User-requested 0-indexed range start. Lines BEFORE this are leading
|
|
800
|
+
// context (added below if offset is explicit).
|
|
801
|
+
const requestedStart = offset ? Math.max(0, offset - 1) : 0;
|
|
802
|
+
const ignoreResultLimits = options.ignoreResultLimits ?? false;
|
|
803
|
+
const requestedEnd = limit !== undefined ? Math.min(requestedStart + limit, allLines.length) : allLines.length;
|
|
804
|
+
// Expand only on sides the user actually constrained: leading context
|
|
805
|
+
// when offset>1, trailing context when a finite limit was set.
|
|
806
|
+
const expanded = expandRangeWithContext(
|
|
807
|
+
requestedStart,
|
|
808
|
+
requestedEnd,
|
|
809
|
+
allLines.length,
|
|
810
|
+
offset !== undefined && offset > 1,
|
|
811
|
+
limit !== undefined,
|
|
812
|
+
);
|
|
813
|
+
const startLine = expanded.startLine;
|
|
814
|
+
const endLineExpanded = expanded.endLine;
|
|
815
|
+
const startLineDisplay = startLine + 1;
|
|
816
|
+
|
|
817
|
+
const resultBuilder = toolResult(details);
|
|
818
|
+
if (options.sourcePath) {
|
|
819
|
+
resultBuilder.sourcePath(options.sourcePath);
|
|
820
|
+
}
|
|
821
|
+
if (options.sourceUrl) {
|
|
822
|
+
resultBuilder.sourceUrl(options.sourceUrl);
|
|
823
|
+
}
|
|
824
|
+
if (options.sourceInternal) {
|
|
825
|
+
resultBuilder.sourceInternal(options.sourceInternal);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (requestedStart >= allLines.length) {
|
|
829
|
+
const suggestion =
|
|
830
|
+
allLines.length === 0
|
|
831
|
+
? `The ${options.entityLabel} is empty.`
|
|
832
|
+
: `Use :1 to read from the start, or :${allLines.length} to read the last line.`;
|
|
833
|
+
return resultBuilder
|
|
834
|
+
.text(
|
|
835
|
+
`Line ${requestedStart + 1} is beyond end of ${options.entityLabel} (${allLines.length} lines total). ${suggestion}`,
|
|
836
|
+
)
|
|
837
|
+
.done();
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
const endLine = endLineExpanded;
|
|
841
|
+
const selectedContent = allLines.slice(startLine, endLine).join("\n");
|
|
842
|
+
const userLimitedLines = limit !== undefined ? endLine - startLine : undefined;
|
|
843
|
+
const truncation = ignoreResultLimits ? noTruncResult(selectedContent) : truncateHead(selectedContent);
|
|
844
|
+
|
|
845
|
+
const shouldAddHashLines = displayMode.hashLines;
|
|
846
|
+
const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
|
|
847
|
+
const formatText = (content: string, startNum: number): string => {
|
|
848
|
+
details.displayContent = { text: content, startLine: startNum };
|
|
849
|
+
return formatTextWithMode(content, startNum, shouldAddHashLines, shouldAddLineNumbers);
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
let outputText: string;
|
|
853
|
+
let truncationInfo:
|
|
854
|
+
| { result: TruncationResult; options: { direction: "head"; startLine?: number; totalFileLines?: number } }
|
|
855
|
+
| undefined;
|
|
856
|
+
|
|
857
|
+
if (truncation.firstLineExceedsLimit) {
|
|
858
|
+
const firstLine = allLines[startLine] ?? "";
|
|
859
|
+
const firstLineBytes = Buffer.byteLength(firstLine, "utf-8");
|
|
860
|
+
const snippet = truncateHeadBytes(firstLine, DEFAULT_MAX_BYTES);
|
|
861
|
+
|
|
862
|
+
if (shouldAddHashLines) {
|
|
863
|
+
outputText = `[Line ${startLineDisplay} is ${formatBytes(
|
|
864
|
+
firstLineBytes,
|
|
865
|
+
)}, exceeds ${formatBytes(DEFAULT_MAX_BYTES)} limit. Hashline output requires full lines; cannot compute hashes for a truncated preview.]`;
|
|
866
|
+
} else {
|
|
867
|
+
outputText = formatText(snippet.text, startLineDisplay);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (snippet.text.length === 0) {
|
|
871
|
+
outputText = `[Line ${startLineDisplay} is ${formatBytes(
|
|
872
|
+
firstLineBytes,
|
|
873
|
+
)}, exceeds ${formatBytes(DEFAULT_MAX_BYTES)} limit. Unable to display a valid UTF-8 snippet.]`;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
details.truncation = truncation;
|
|
877
|
+
truncationInfo = {
|
|
878
|
+
result: truncation,
|
|
879
|
+
options: { direction: "head", startLine: startLineDisplay, totalFileLines: totalLines },
|
|
880
|
+
};
|
|
881
|
+
} else if (truncation.truncated) {
|
|
882
|
+
outputText = formatText(truncation.content, startLineDisplay);
|
|
883
|
+
details.truncation = truncation;
|
|
884
|
+
truncationInfo = {
|
|
885
|
+
result: truncation,
|
|
886
|
+
options: { direction: "head", startLine: startLineDisplay, totalFileLines: totalLines },
|
|
887
|
+
};
|
|
888
|
+
} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
|
|
889
|
+
const remaining = allLines.length - (startLine + userLimitedLines);
|
|
890
|
+
const nextOffset = startLine + userLimitedLines + 1;
|
|
891
|
+
|
|
892
|
+
outputText = formatText(selectedContent, startLineDisplay);
|
|
893
|
+
outputText += `\n\n[${remaining} more lines in ${options.entityLabel}. Use :${nextOffset} to continue]`;
|
|
894
|
+
} else {
|
|
895
|
+
outputText = formatText(truncation.content, startLineDisplay);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
resultBuilder.text(outputText);
|
|
899
|
+
if (truncationInfo) {
|
|
900
|
+
resultBuilder.truncation(truncationInfo.result, truncationInfo.options);
|
|
901
|
+
}
|
|
902
|
+
return resultBuilder.done();
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Render a multi-range read against in-memory text. Each range emits a
|
|
907
|
+
* formatted block with its own anchors / line numbers, blocks are joined
|
|
908
|
+
* with an elision separator, and ranges past EOF surface as `[…]` notices
|
|
909
|
+
* so the model can correct the next call. No leading/trailing context is
|
|
910
|
+
* added — multi-range callers always specify exact bounds.
|
|
911
|
+
*/
|
|
912
|
+
#buildInMemoryMultiRangeResult(
|
|
913
|
+
text: string,
|
|
914
|
+
ranges: readonly LineRange[],
|
|
915
|
+
options: {
|
|
916
|
+
details?: ReadToolDetails;
|
|
917
|
+
sourcePath?: string;
|
|
918
|
+
sourceUrl?: string;
|
|
919
|
+
sourceInternal?: string;
|
|
920
|
+
entityLabel: string;
|
|
921
|
+
raw?: boolean;
|
|
922
|
+
immutable?: boolean;
|
|
923
|
+
},
|
|
924
|
+
): AgentToolResult<ReadToolDetails> {
|
|
925
|
+
const displayMode = resolveFileDisplayMode(this.session, { raw: options.raw, immutable: options.immutable });
|
|
926
|
+
const details = options.details ?? {};
|
|
927
|
+
const allLines = text.split("\n");
|
|
928
|
+
const totalLines = allLines.length;
|
|
929
|
+
const shouldAddHashLines = displayMode.hashLines;
|
|
930
|
+
const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
|
|
931
|
+
|
|
932
|
+
const resultBuilder = toolResult(details);
|
|
933
|
+
if (options.sourcePath) resultBuilder.sourcePath(options.sourcePath);
|
|
934
|
+
if (options.sourceUrl) resultBuilder.sourceUrl(options.sourceUrl);
|
|
935
|
+
if (options.sourceInternal) resultBuilder.sourceInternal(options.sourceInternal);
|
|
936
|
+
|
|
937
|
+
const parts: string[] = [];
|
|
938
|
+
const outOfBounds: LineRange[] = [];
|
|
939
|
+
for (const range of ranges) {
|
|
940
|
+
if (range.startLine > totalLines) {
|
|
941
|
+
outOfBounds.push(range);
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
const effectiveEnd = Math.min(range.endLine ?? totalLines, totalLines);
|
|
945
|
+
const sliced = allLines.slice(range.startLine - 1, effectiveEnd).join("\n");
|
|
946
|
+
parts.push(formatTextWithMode(sliced, range.startLine, shouldAddHashLines, shouldAddLineNumbers));
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
const outputText = parts.length > 0 ? parts.join("\n\n…\n\n") : "";
|
|
950
|
+
const notices: string[] = [];
|
|
951
|
+
for (const range of outOfBounds) {
|
|
952
|
+
const bound = range.endLine !== undefined ? `${range.startLine}-${range.endLine}` : `${range.startLine}`;
|
|
953
|
+
notices.push(`[Range ${bound} is beyond end of ${options.entityLabel} (${totalLines} lines total); skipped]`);
|
|
954
|
+
}
|
|
955
|
+
const finalText =
|
|
956
|
+
notices.length > 0 ? (outputText ? `${outputText}\n${notices.join("\n")}` : notices.join("\n")) : outputText;
|
|
957
|
+
resultBuilder.text(finalText);
|
|
958
|
+
return resultBuilder.done();
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Stream multiple non-contiguous ranges from a local file. ACP bridge takes
|
|
963
|
+
* priority when present (editor buffer is source of truth); otherwise each
|
|
964
|
+
* range is streamed independently with its own line/byte budget. Out-of-bounds
|
|
965
|
+
* ranges surface as inline notices rather than aborting the read.
|
|
966
|
+
*/
|
|
967
|
+
async #readLocalFileMultiRange(
|
|
968
|
+
absolutePath: string,
|
|
969
|
+
ranges: readonly LineRange[],
|
|
970
|
+
parsed: ParsedSelector,
|
|
971
|
+
displayMode: { hashLines: boolean; lineNumbers: boolean },
|
|
972
|
+
suffixResolution: { from: string; to: string } | undefined,
|
|
973
|
+
signal: AbortSignal | undefined,
|
|
974
|
+
): Promise<{
|
|
975
|
+
outputText: string;
|
|
976
|
+
columnTruncated: number;
|
|
977
|
+
bridgeResult?: AgentToolResult<ReadToolDetails>;
|
|
978
|
+
}> {
|
|
979
|
+
const rawSelector = isRawSelector(parsed);
|
|
980
|
+
|
|
981
|
+
// ACP bridge first — the editor's in-memory buffer is source of truth.
|
|
982
|
+
const bridgePromise = this.#routeReadThroughBridge(absolutePath);
|
|
983
|
+
if (bridgePromise !== undefined) {
|
|
984
|
+
try {
|
|
985
|
+
const bridgeText = await bridgePromise;
|
|
986
|
+
const bridgeResult = this.#buildInMemoryMultiRangeResult(bridgeText, ranges, {
|
|
987
|
+
details: { resolvedPath: absolutePath, suffixResolution },
|
|
988
|
+
sourcePath: absolutePath,
|
|
989
|
+
entityLabel: "file",
|
|
990
|
+
raw: rawSelector,
|
|
991
|
+
});
|
|
992
|
+
if (suffixResolution) {
|
|
993
|
+
const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
|
|
994
|
+
const firstText = bridgeResult.content.find((c): c is TextContent => c.type === "text");
|
|
995
|
+
if (firstText) firstText.text = `${notice}\n${firstText.text}`;
|
|
996
|
+
}
|
|
997
|
+
return { outputText: "", columnTruncated: 0, bridgeResult };
|
|
998
|
+
} catch (error) {
|
|
999
|
+
logger.warn("ACP fs readTextFile failed; falling back to disk", { path: absolutePath, error });
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const shouldAddHashLines = !rawSelector && displayMode.hashLines;
|
|
1004
|
+
const shouldAddLineNumbers = rawSelector ? false : shouldAddHashLines ? false : displayMode.lineNumbers;
|
|
1005
|
+
const maxColumns = resolveOutputMaxColumns(this.session.settings);
|
|
1006
|
+
|
|
1007
|
+
const blocks: string[] = [];
|
|
1008
|
+
const notices: string[] = [];
|
|
1009
|
+
let columnTruncated = 0;
|
|
1010
|
+
|
|
1011
|
+
for (const range of ranges) {
|
|
1012
|
+
const rangeStart = range.startLine - 1; // 0-indexed
|
|
1013
|
+
const requestedLength = range.endLine !== undefined ? range.endLine - range.startLine + 1 : this.#defaultLimit;
|
|
1014
|
+
const maxLines = Math.min(requestedLength, DEFAULT_MAX_LINES);
|
|
1015
|
+
const maxBytesForRead = Math.max(DEFAULT_MAX_BYTES, maxLines * 512);
|
|
1016
|
+
|
|
1017
|
+
const streamResult = await streamLinesFromFile(
|
|
1018
|
+
absolutePath,
|
|
1019
|
+
rangeStart,
|
|
1020
|
+
maxLines,
|
|
1021
|
+
maxBytesForRead,
|
|
1022
|
+
maxLines,
|
|
1023
|
+
signal,
|
|
1024
|
+
);
|
|
1025
|
+
const totalFileLines = streamResult.totalFileLines;
|
|
1026
|
+
|
|
1027
|
+
if (rangeStart >= totalFileLines) {
|
|
1028
|
+
const bound = range.endLine !== undefined ? `${range.startLine}-${range.endLine}` : `${range.startLine}`;
|
|
1029
|
+
notices.push(`[Range ${bound} is beyond end of file (${totalFileLines} lines total); skipped]`);
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const collectedLines = streamResult.lines;
|
|
1034
|
+
if (!rawSelector && maxColumns > 0) {
|
|
1035
|
+
for (let i = 0; i < collectedLines.length; i++) {
|
|
1036
|
+
const { text, wasTruncated } = truncateLine(collectedLines[i], maxColumns);
|
|
1037
|
+
if (wasTruncated) {
|
|
1038
|
+
collectedLines[i] = text;
|
|
1039
|
+
columnTruncated = maxColumns;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if (collectedLines.length > 0) {
|
|
1045
|
+
getFileReadCache(this.session).recordContiguous(absolutePath, range.startLine, collectedLines);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const blockText = collectedLines.join("\n");
|
|
1049
|
+
blocks.push(formatTextWithMode(blockText, range.startLine, shouldAddHashLines, shouldAddLineNumbers));
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
let outputText = blocks.join("\n\n…\n\n");
|
|
1053
|
+
if (notices.length > 0) {
|
|
1054
|
+
outputText = outputText ? `${outputText}\n${notices.join("\n")}` : notices.join("\n");
|
|
1055
|
+
}
|
|
1056
|
+
return { outputText, columnTruncated };
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async #readArchiveDirectory(
|
|
1060
|
+
archive: ArchiveReader,
|
|
1061
|
+
archivePath: string,
|
|
1062
|
+
subPath: string,
|
|
1063
|
+
limit: number | undefined,
|
|
1064
|
+
details: ReadToolDetails,
|
|
1065
|
+
signal?: AbortSignal,
|
|
1066
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
1067
|
+
const DEFAULT_LIMIT = 500;
|
|
1068
|
+
const effectiveLimit = limit ?? DEFAULT_LIMIT;
|
|
1069
|
+
const entries = archive.listDirectory(subPath);
|
|
1070
|
+
|
|
1071
|
+
const listLimit = applyListLimit(entries, { limit: effectiveLimit });
|
|
1072
|
+
const limitedEntries = listLimit.items;
|
|
1073
|
+
const limitMeta = listLimit.meta;
|
|
1074
|
+
|
|
1075
|
+
const results: string[] = [];
|
|
1076
|
+
for (const entry of limitedEntries) {
|
|
1077
|
+
throwIfAborted(signal);
|
|
1078
|
+
if (entry.isDirectory) {
|
|
1079
|
+
results.push(`${entry.name}/`);
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
const sizeSuffix = entry.size > 0 ? ` (${formatBytes(entry.size)})` : "";
|
|
1084
|
+
results.push(`${entry.name}${sizeSuffix}`);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const output = results.length > 0 ? results.join("\n") : "(empty archive directory)";
|
|
1088
|
+
const text = prependSuffixResolutionNotice(output, details.suffixResolution);
|
|
1089
|
+
const truncation = truncateHead(text, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
1090
|
+
const directoryDetails: ReadToolDetails = { ...details, isDirectory: true };
|
|
1091
|
+
const resultBuilder = toolResult<ReadToolDetails>(directoryDetails).text(truncation.content);
|
|
1092
|
+
resultBuilder.sourcePath(archivePath).limits({ resultLimit: limitMeta.resultLimit?.reached });
|
|
1093
|
+
if (truncation.truncated) {
|
|
1094
|
+
directoryDetails.truncation = truncation;
|
|
1095
|
+
resultBuilder.truncation(truncation, { direction: "head" });
|
|
1096
|
+
}
|
|
1097
|
+
return resultBuilder.done();
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
async #readArchive(
|
|
1101
|
+
readPath: string,
|
|
1102
|
+
parsedSel: ParsedSelector,
|
|
1103
|
+
resolvedArchivePath: ResolvedArchiveReadPath,
|
|
1104
|
+
signal?: AbortSignal,
|
|
1105
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
1106
|
+
throwIfAborted(signal);
|
|
1107
|
+
const archive = await openArchive(resolvedArchivePath.absolutePath);
|
|
1108
|
+
throwIfAborted(signal);
|
|
1109
|
+
|
|
1110
|
+
const details: ReadToolDetails = {
|
|
1111
|
+
resolvedPath: resolvedArchivePath.absolutePath,
|
|
1112
|
+
suffixResolution: resolvedArchivePath.suffixResolution,
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
const node = archive.getNode(resolvedArchivePath.archiveSubPath);
|
|
1116
|
+
if (!node) {
|
|
1117
|
+
throw new ToolError(`Path '${readPath}' not found inside archive`);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (node.isDirectory) {
|
|
1121
|
+
if (isMultiRange(parsedSel)) {
|
|
1122
|
+
throw new ToolError("Multi-range line selectors are not supported for archive directory listings.");
|
|
1123
|
+
}
|
|
1124
|
+
const { limit } = selToOffsetLimit(parsedSel);
|
|
1125
|
+
return this.#readArchiveDirectory(
|
|
1126
|
+
archive,
|
|
1127
|
+
resolvedArchivePath.absolutePath,
|
|
1128
|
+
resolvedArchivePath.archiveSubPath,
|
|
1129
|
+
limit,
|
|
1130
|
+
details,
|
|
1131
|
+
signal,
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const entry = await archive.readFile(resolvedArchivePath.archiveSubPath);
|
|
1136
|
+
const text = decodeUtf8Text(entry.bytes);
|
|
1137
|
+
if (text === null) {
|
|
1138
|
+
return toolResult<ReadToolDetails>(details)
|
|
1139
|
+
.text(
|
|
1140
|
+
prependSuffixResolutionNotice(
|
|
1141
|
+
`[Cannot read binary archive entry '${entry.path}' (${formatBytes(entry.size)})]`,
|
|
1142
|
+
resolvedArchivePath.suffixResolution,
|
|
1143
|
+
),
|
|
1144
|
+
)
|
|
1145
|
+
.sourcePath(resolvedArchivePath.absolutePath)
|
|
1146
|
+
.done();
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
const raw = isRawSelector(parsedSel);
|
|
1150
|
+
const result =
|
|
1151
|
+
isMultiRange(parsedSel) && parsedSel.kind === "lines"
|
|
1152
|
+
? this.#buildInMemoryMultiRangeResult(text, parsedSel.ranges, {
|
|
1153
|
+
details,
|
|
1154
|
+
sourcePath: resolvedArchivePath.absolutePath,
|
|
1155
|
+
entityLabel: "archive entry",
|
|
1156
|
+
raw,
|
|
1157
|
+
})
|
|
1158
|
+
: this.#buildInMemoryTextResult(
|
|
1159
|
+
text,
|
|
1160
|
+
selToOffsetLimit(parsedSel).offset,
|
|
1161
|
+
selToOffsetLimit(parsedSel).limit,
|
|
1162
|
+
{
|
|
1163
|
+
details,
|
|
1164
|
+
sourcePath: resolvedArchivePath.absolutePath,
|
|
1165
|
+
entityLabel: "archive entry",
|
|
1166
|
+
raw,
|
|
1167
|
+
},
|
|
1168
|
+
);
|
|
1169
|
+
const firstText = result.content.find((content): content is TextContent => content.type === "text");
|
|
1170
|
+
if (firstText) {
|
|
1171
|
+
firstText.text = prependSuffixResolutionNotice(firstText.text, resolvedArchivePath.suffixResolution);
|
|
1172
|
+
}
|
|
1173
|
+
return result;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
async #readSqlite(
|
|
1177
|
+
resolvedSqlitePath: ResolvedSqliteReadPath,
|
|
1178
|
+
signal?: AbortSignal,
|
|
1179
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
1180
|
+
throwIfAborted(signal);
|
|
1181
|
+
|
|
1182
|
+
const selectorInput = {
|
|
1183
|
+
subPath: resolvedSqlitePath.sqliteSubPath,
|
|
1184
|
+
queryString: resolvedSqlitePath.queryString,
|
|
1185
|
+
};
|
|
1186
|
+
const selector = parseSqliteSelector(selectorInput.subPath, selectorInput.queryString);
|
|
1187
|
+
const details: ReadToolDetails = {
|
|
1188
|
+
resolvedPath: resolvedSqlitePath.absolutePath,
|
|
1189
|
+
suffixResolution: resolvedSqlitePath.suffixResolution,
|
|
1190
|
+
};
|
|
1191
|
+
|
|
1192
|
+
let db: Database | null = null;
|
|
1193
|
+
try {
|
|
1194
|
+
db = new Database(resolvedSqlitePath.absolutePath, { readonly: true, strict: true });
|
|
1195
|
+
db.run("PRAGMA busy_timeout = 3000");
|
|
1196
|
+
throwIfAborted(signal);
|
|
1197
|
+
|
|
1198
|
+
switch (selector.kind) {
|
|
1199
|
+
case "list": {
|
|
1200
|
+
const listLimit = applyListLimit(listTables(db), { limit: 500 });
|
|
1201
|
+
const output = prependSuffixResolutionNotice(
|
|
1202
|
+
renderTableList(listLimit.items),
|
|
1203
|
+
resolvedSqlitePath.suffixResolution,
|
|
1204
|
+
);
|
|
1205
|
+
const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
1206
|
+
details.truncation = truncation.truncated ? truncation : undefined;
|
|
1207
|
+
const resultBuilder = toolResult<ReadToolDetails>(details)
|
|
1208
|
+
.text(truncation.content)
|
|
1209
|
+
.sourcePath(resolvedSqlitePath.absolutePath)
|
|
1210
|
+
.limits({ resultLimit: listLimit.meta.resultLimit?.reached });
|
|
1211
|
+
if (truncation.truncated) {
|
|
1212
|
+
resultBuilder.truncation(truncation, { direction: "head" });
|
|
1213
|
+
}
|
|
1214
|
+
return resultBuilder.done();
|
|
1215
|
+
}
|
|
1216
|
+
case "schema": {
|
|
1217
|
+
const sampleRows = queryRows(db, selector.table, { limit: selector.sampleLimit, offset: 0 });
|
|
1218
|
+
let output = renderSchema(getTableSchema(db, selector.table), {
|
|
1219
|
+
columns: sampleRows.columns,
|
|
1220
|
+
rows: sampleRows.rows,
|
|
1221
|
+
});
|
|
1222
|
+
if (sampleRows.rows.length < sampleRows.totalCount) {
|
|
1223
|
+
const remaining = sampleRows.totalCount - sampleRows.rows.length;
|
|
1224
|
+
output += `\n[${remaining} more rows; append :${selector.table}?limit=20&offset=${sampleRows.rows.length} to the database path to continue]`;
|
|
1225
|
+
}
|
|
1226
|
+
return toolResult<ReadToolDetails>(details)
|
|
1227
|
+
.text(prependSuffixResolutionNotice(output, resolvedSqlitePath.suffixResolution))
|
|
1228
|
+
.sourcePath(resolvedSqlitePath.absolutePath)
|
|
1229
|
+
.done();
|
|
1230
|
+
}
|
|
1231
|
+
case "row": {
|
|
1232
|
+
const lookup = resolveTableRowLookup(db, selector.table);
|
|
1233
|
+
const row =
|
|
1234
|
+
lookup.kind === "pk"
|
|
1235
|
+
? getRowByKey(db, selector.table, lookup, selector.key)
|
|
1236
|
+
: getRowByRowId(db, selector.table, selector.key);
|
|
1237
|
+
if (!row) {
|
|
1238
|
+
return toolResult<ReadToolDetails>(details)
|
|
1239
|
+
.text(
|
|
1240
|
+
prependSuffixResolutionNotice(
|
|
1241
|
+
`No row found in table '${selector.table}' for key '${selector.key}'.`,
|
|
1242
|
+
resolvedSqlitePath.suffixResolution,
|
|
1243
|
+
),
|
|
1244
|
+
)
|
|
1245
|
+
.sourcePath(resolvedSqlitePath.absolutePath)
|
|
1246
|
+
.done();
|
|
1247
|
+
}
|
|
1248
|
+
return toolResult<ReadToolDetails>(details)
|
|
1249
|
+
.text(prependSuffixResolutionNotice(renderRow(row), resolvedSqlitePath.suffixResolution))
|
|
1250
|
+
.sourcePath(resolvedSqlitePath.absolutePath)
|
|
1251
|
+
.done();
|
|
1252
|
+
}
|
|
1253
|
+
case "query": {
|
|
1254
|
+
const page = queryRows(db, selector.table, selector);
|
|
1255
|
+
return toolResult<ReadToolDetails>(details)
|
|
1256
|
+
.text(
|
|
1257
|
+
prependSuffixResolutionNotice(
|
|
1258
|
+
renderTable(page.columns, page.rows, {
|
|
1259
|
+
totalCount: page.totalCount,
|
|
1260
|
+
offset: selector.offset,
|
|
1261
|
+
limit: selector.limit,
|
|
1262
|
+
table: selector.table,
|
|
1263
|
+
dbPath: resolvedSqlitePath.absolutePath,
|
|
1264
|
+
}),
|
|
1265
|
+
resolvedSqlitePath.suffixResolution,
|
|
1266
|
+
),
|
|
1267
|
+
)
|
|
1268
|
+
.sourcePath(resolvedSqlitePath.absolutePath)
|
|
1269
|
+
.done();
|
|
1270
|
+
}
|
|
1271
|
+
case "raw": {
|
|
1272
|
+
const result = executeReadQuery(db, selector.sql);
|
|
1273
|
+
return toolResult<ReadToolDetails>(details)
|
|
1274
|
+
.text(
|
|
1275
|
+
prependSuffixResolutionNotice(
|
|
1276
|
+
renderTable(result.columns, result.rows, {
|
|
1277
|
+
totalCount: result.rows.length,
|
|
1278
|
+
offset: 0,
|
|
1279
|
+
limit: result.rows.length || DEFAULT_MAX_LINES,
|
|
1280
|
+
table: "query",
|
|
1281
|
+
dbPath: resolvedSqlitePath.absolutePath,
|
|
1282
|
+
}),
|
|
1283
|
+
resolvedSqlitePath.suffixResolution,
|
|
1284
|
+
),
|
|
1285
|
+
)
|
|
1286
|
+
.sourcePath(resolvedSqlitePath.absolutePath)
|
|
1287
|
+
.done();
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
throw new ToolError("Unsupported SQLite selector");
|
|
1292
|
+
} catch (error) {
|
|
1293
|
+
if (error instanceof ToolError) {
|
|
1294
|
+
throw error;
|
|
1295
|
+
}
|
|
1296
|
+
throw new ToolError(error instanceof Error ? error.message : String(error));
|
|
1297
|
+
} finally {
|
|
1298
|
+
db?.close();
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
#routeReadThroughBridge(
|
|
1303
|
+
absolutePath: string,
|
|
1304
|
+
options?: { line?: number; limit?: number },
|
|
1305
|
+
): Promise<string> | undefined {
|
|
1306
|
+
const bridge = this.session.getClientBridge?.();
|
|
1307
|
+
if (!bridge?.capabilities.readTextFile || !bridge.readTextFile) return undefined;
|
|
1308
|
+
return bridge.readTextFile({ path: absolutePath, ...options });
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
async #trySummarize(absolutePath: string, fileSize: number, signal?: AbortSignal): Promise<SummaryResult | null> {
|
|
1312
|
+
if (fileSize > MAX_SUMMARY_BYTES) return null;
|
|
1313
|
+
|
|
1314
|
+
try {
|
|
1315
|
+
throwIfAborted(signal);
|
|
1316
|
+
const bridgePromise = this.#routeReadThroughBridge(absolutePath);
|
|
1317
|
+
const code =
|
|
1318
|
+
bridgePromise !== undefined
|
|
1319
|
+
? await bridgePromise.catch(() => Bun.file(absolutePath).text())
|
|
1320
|
+
: await Bun.file(absolutePath).text();
|
|
1321
|
+
throwIfAborted(signal);
|
|
1322
|
+
if (countTextLines(code) > MAX_SUMMARY_LINES) return null;
|
|
1323
|
+
|
|
1324
|
+
return summarizeCode({
|
|
1325
|
+
code,
|
|
1326
|
+
path: absolutePath,
|
|
1327
|
+
minBodyLines: this.session.settings.get("read.summarize.minBodyLines"),
|
|
1328
|
+
minCommentLines: this.session.settings.get("read.summarize.minCommentLines"),
|
|
1329
|
+
});
|
|
1330
|
+
} catch {
|
|
1331
|
+
return null;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
#renderSummary(summary: SummaryResult): {
|
|
1336
|
+
text: string;
|
|
1337
|
+
displayText: string;
|
|
1338
|
+
elidedSpans: number;
|
|
1339
|
+
elidedLines: number;
|
|
1340
|
+
} {
|
|
1341
|
+
const displayMode = resolveFileDisplayMode(this.session);
|
|
1342
|
+
const shouldAddHashLines = displayMode.hashLines;
|
|
1343
|
+
const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
|
|
1344
|
+
|
|
1345
|
+
// Flatten segments into per-line units so we can merge a kept-head /
|
|
1346
|
+
// elided / kept-tail sandwich into a single brace-pair line when the
|
|
1347
|
+
// boundary lines look like `… {` and `}` (or matching variants).
|
|
1348
|
+
type Unit =
|
|
1349
|
+
| { kind: "line"; line: number; text: string }
|
|
1350
|
+
| { kind: "elided"; startLine: number; endLine: number }
|
|
1351
|
+
| {
|
|
1352
|
+
kind: "merged";
|
|
1353
|
+
startLine: number;
|
|
1354
|
+
endLine: number;
|
|
1355
|
+
headText: string;
|
|
1356
|
+
tailText: string;
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
const raw: Unit[] = [];
|
|
1360
|
+
for (const segment of summary.segments) {
|
|
1361
|
+
if (segment.kind === "elided") {
|
|
1362
|
+
raw.push({ kind: "elided", startLine: segment.startLine, endLine: segment.endLine });
|
|
1363
|
+
continue;
|
|
1364
|
+
}
|
|
1365
|
+
const text = segment.text ?? "";
|
|
1366
|
+
if (text.length === 0) continue;
|
|
1367
|
+
const lines = text.split("\n");
|
|
1368
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1369
|
+
raw.push({ kind: "line", line: segment.startLine + i, text: lines[i] });
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
const units: Unit[] = [];
|
|
1374
|
+
let i = 0;
|
|
1375
|
+
while (i < raw.length) {
|
|
1376
|
+
const cur = raw[i];
|
|
1377
|
+
if (cur.kind === "elided") {
|
|
1378
|
+
const prev = units.length > 0 ? units[units.length - 1] : null;
|
|
1379
|
+
const next = i + 1 < raw.length ? raw[i + 1] : null;
|
|
1380
|
+
if (prev?.kind === "line" && next?.kind === "line" && canMergeBracePair(prev.text, next.text)) {
|
|
1381
|
+
units.pop();
|
|
1382
|
+
units.push({
|
|
1383
|
+
kind: "merged",
|
|
1384
|
+
startLine: prev.line,
|
|
1385
|
+
endLine: next.line,
|
|
1386
|
+
headText: prev.text,
|
|
1387
|
+
tailText: next.text,
|
|
1388
|
+
});
|
|
1389
|
+
i += 2;
|
|
1390
|
+
continue;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
units.push(cur);
|
|
1394
|
+
i++;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
const modelParts: string[] = [];
|
|
1398
|
+
const displayParts: string[] = [];
|
|
1399
|
+
let elidedSpans = 0;
|
|
1400
|
+
let elidedLines = 0;
|
|
1401
|
+
for (const unit of units) {
|
|
1402
|
+
if (unit.kind === "elided") {
|
|
1403
|
+
modelParts.push("...");
|
|
1404
|
+
displayParts.push("...");
|
|
1405
|
+
elidedSpans++;
|
|
1406
|
+
elidedLines += unit.endLine - unit.startLine + 1;
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
if (unit.kind === "merged") {
|
|
1410
|
+
const formatted = formatMergedBraceLine(
|
|
1411
|
+
unit.startLine,
|
|
1412
|
+
unit.endLine,
|
|
1413
|
+
unit.headText,
|
|
1414
|
+
unit.tailText,
|
|
1415
|
+
shouldAddHashLines,
|
|
1416
|
+
shouldAddLineNumbers,
|
|
1417
|
+
);
|
|
1418
|
+
modelParts.push(formatted.model);
|
|
1419
|
+
displayParts.push(formatted.display);
|
|
1420
|
+
elidedSpans++;
|
|
1421
|
+
// Merged brace pair encloses (start+1)..(end-1) as elided.
|
|
1422
|
+
elidedLines += Math.max(0, unit.endLine - unit.startLine - 1);
|
|
1423
|
+
continue;
|
|
1424
|
+
}
|
|
1425
|
+
modelParts.push(formatSingleLine(unit.line, unit.text, shouldAddHashLines, shouldAddLineNumbers));
|
|
1426
|
+
displayParts.push(unit.text);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
return { text: modelParts.join("\n"), displayText: displayParts.join("\n"), elidedSpans, elidedLines };
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
async execute(
|
|
1433
|
+
_toolCallId: string,
|
|
1434
|
+
params: ReadParams,
|
|
1435
|
+
signal?: AbortSignal,
|
|
1436
|
+
_onUpdate?: AgentToolUpdateCallback<ReadToolDetails>,
|
|
1437
|
+
_toolContext?: AgentToolContext,
|
|
1438
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
1439
|
+
let { path: readPath } = params;
|
|
1440
|
+
if (readPath.startsWith("file://")) {
|
|
1441
|
+
readPath = expandPath(readPath);
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
const conflictUri = parseConflictUri(readPath);
|
|
1445
|
+
if (conflictUri) {
|
|
1446
|
+
if (conflictUri.id === "*") {
|
|
1447
|
+
throw new ToolError(
|
|
1448
|
+
"Reading `conflict://*` is not supported — wildcards are write-only. Use the `<path>:conflicts` read selector for the full list of conflicts in a file, or read `conflict://<N>` to inspect a single block.",
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
return this.#readConflictRegion(conflictUri.id, conflictUri.scope);
|
|
1452
|
+
}
|
|
1453
|
+
const displayMode = resolveFileDisplayMode(this.session);
|
|
1454
|
+
|
|
1455
|
+
const parsedUrlTarget = parseReadUrlTarget(readPath);
|
|
1456
|
+
if (parsedUrlTarget) {
|
|
1457
|
+
if (!this.session.settings.get("fetch.enabled")) {
|
|
1458
|
+
throw new ToolError("URL reads are disabled by settings.");
|
|
1459
|
+
}
|
|
1460
|
+
if (parsedUrlTarget.offset !== undefined || parsedUrlTarget.limit !== undefined) {
|
|
1461
|
+
const cached = await loadReadUrlCacheEntry(
|
|
1462
|
+
this.session,
|
|
1463
|
+
{ path: parsedUrlTarget.path, raw: parsedUrlTarget.raw },
|
|
1464
|
+
signal,
|
|
1465
|
+
{
|
|
1466
|
+
ensureArtifact: true,
|
|
1467
|
+
preferCached: true,
|
|
1468
|
+
},
|
|
1469
|
+
);
|
|
1470
|
+
return this.#buildInMemoryTextResult(cached.output, parsedUrlTarget.offset, parsedUrlTarget.limit, {
|
|
1471
|
+
details: { ...cached.details },
|
|
1472
|
+
sourceUrl: cached.details.finalUrl,
|
|
1473
|
+
entityLabel: "URL output",
|
|
1474
|
+
immutable: true,
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
return executeReadUrl(this.session, { path: parsedUrlTarget.path, raw: parsedUrlTarget.raw }, signal);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// Handle internal URLs (agent://, artifact://, memory://, rule://, local://, gjc://, issue://, pr://).
|
|
1481
|
+
// Use the internal-URL-aware splitter so malformed selectors are peeled
|
|
1482
|
+
// off the URL and surfaced via parseSel rather than confusing handlers.
|
|
1483
|
+
const internalRouter = InternalUrlRouter.instance();
|
|
1484
|
+
if (internalRouter.canHandle(readPath)) {
|
|
1485
|
+
const internalTarget = splitInternalUrlSel(readPath);
|
|
1486
|
+
const parsed = parseSel(internalTarget.sel);
|
|
1487
|
+
return this.#handleInternalUrl(internalTarget.path, parsed, signal);
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
const archivePath = await this.#resolveArchiveReadPath(readPath, signal);
|
|
1491
|
+
if (archivePath) {
|
|
1492
|
+
const archiveSubPath = splitPathAndSel(archivePath.archiveSubPath);
|
|
1493
|
+
const archiveParsed = parseSel(archiveSubPath.sel);
|
|
1494
|
+
return this.#readArchive(
|
|
1495
|
+
readPath,
|
|
1496
|
+
archiveParsed,
|
|
1497
|
+
{ ...archivePath, archiveSubPath: archiveSubPath.path },
|
|
1498
|
+
signal,
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
const sqlitePath = await this.#resolveSqliteReadPath(readPath, signal);
|
|
1503
|
+
if (sqlitePath) {
|
|
1504
|
+
return this.#readSqlite(sqlitePath, signal);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
const localTarget = splitPathAndSel(readPath);
|
|
1508
|
+
const localReadPath = localTarget.path;
|
|
1509
|
+
const parsed = parseSel(localTarget.sel);
|
|
1510
|
+
|
|
1511
|
+
let absolutePath = resolveReadPath(localReadPath, this.session.cwd);
|
|
1512
|
+
let suffixResolution: { from: string; to: string } | undefined;
|
|
1513
|
+
|
|
1514
|
+
let isDirectory = false;
|
|
1515
|
+
let fileSize = 0;
|
|
1516
|
+
try {
|
|
1517
|
+
const stat = await Bun.file(absolutePath).stat();
|
|
1518
|
+
fileSize = stat.size;
|
|
1519
|
+
isDirectory = stat.isDirectory();
|
|
1520
|
+
} catch (error) {
|
|
1521
|
+
if (isNotFoundError(error)) {
|
|
1522
|
+
// Attempt unique suffix resolution before falling back to fuzzy suggestions
|
|
1523
|
+
if (!isRemoteMountPath(absolutePath)) {
|
|
1524
|
+
const suffixMatch = await findUniqueSuffixMatch(localReadPath, this.session.cwd, signal);
|
|
1525
|
+
if (suffixMatch) {
|
|
1526
|
+
try {
|
|
1527
|
+
const retryStat = await Bun.file(suffixMatch.absolutePath).stat();
|
|
1528
|
+
absolutePath = suffixMatch.absolutePath;
|
|
1529
|
+
fileSize = retryStat.size;
|
|
1530
|
+
isDirectory = retryStat.isDirectory();
|
|
1531
|
+
suffixResolution = { from: localReadPath, to: suffixMatch.displayPath };
|
|
1532
|
+
} catch {
|
|
1533
|
+
// Suffix match candidate no longer stats — fall through to error path
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
if (!suffixResolution) {
|
|
1539
|
+
throw new ToolError(`Path '${localReadPath}' not found`);
|
|
1540
|
+
}
|
|
1541
|
+
} else {
|
|
1542
|
+
throw error;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
if (isDirectory) {
|
|
1547
|
+
if (isMultiRange(parsed)) {
|
|
1548
|
+
throw new ToolError("Multi-range line selectors are not supported for directory listings.");
|
|
1549
|
+
}
|
|
1550
|
+
const dirResult = await this.#readDirectory(absolutePath, selToOffsetLimit(parsed).limit, signal);
|
|
1551
|
+
if (suffixResolution) {
|
|
1552
|
+
dirResult.details ??= {};
|
|
1553
|
+
dirResult.details.suffixResolution = suffixResolution;
|
|
1554
|
+
}
|
|
1555
|
+
return dirResult;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
if (parsed.kind === "conflicts") {
|
|
1559
|
+
return this.#readFileConflicts(absolutePath, suffixResolution, signal);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
const imageMetadata = await readImageMetadata(absolutePath);
|
|
1563
|
+
const mimeType = imageMetadata?.mimeType;
|
|
1564
|
+
const ext = path.extname(absolutePath).toLowerCase();
|
|
1565
|
+
const shouldConvertWithMarkit = CONVERTIBLE_EXTENSIONS.has(ext);
|
|
1566
|
+
// Read the file based on type
|
|
1567
|
+
let content: Array<TextContent | ImageContent> | undefined;
|
|
1568
|
+
let details: ReadToolDetails = {};
|
|
1569
|
+
let sourcePath: string | undefined;
|
|
1570
|
+
let columnTruncated = 0;
|
|
1571
|
+
let truncationInfo:
|
|
1572
|
+
| { result: TruncationResult; options: { direction: "head"; startLine?: number; totalFileLines?: number } }
|
|
1573
|
+
| undefined;
|
|
1574
|
+
|
|
1575
|
+
if (mimeType) {
|
|
1576
|
+
if (this.#inspectImageEnabled) {
|
|
1577
|
+
const metadata = imageMetadata;
|
|
1578
|
+
const outputMime = metadata?.mimeType ?? mimeType;
|
|
1579
|
+
const outputBytes = fileSize;
|
|
1580
|
+
const metadataLines = [
|
|
1581
|
+
"Image metadata:",
|
|
1582
|
+
`- MIME: ${outputMime}`,
|
|
1583
|
+
`- Bytes: ${outputBytes} (${formatBytes(outputBytes)})`,
|
|
1584
|
+
metadata?.width !== undefined && metadata.height !== undefined
|
|
1585
|
+
? `- Dimensions: ${metadata.width}x${metadata.height}`
|
|
1586
|
+
: "- Dimensions: unknown",
|
|
1587
|
+
metadata?.channels !== undefined ? `- Channels: ${metadata.channels}` : "- Channels: unknown",
|
|
1588
|
+
metadata?.hasAlpha === true
|
|
1589
|
+
? "- Alpha: yes"
|
|
1590
|
+
: metadata?.hasAlpha === false
|
|
1591
|
+
? "- Alpha: no"
|
|
1592
|
+
: "- Alpha: unknown",
|
|
1593
|
+
"",
|
|
1594
|
+
`If you want to analyze the image, call inspect_image with path="${formatPathRelativeToCwd(
|
|
1595
|
+
absolutePath,
|
|
1596
|
+
this.session.cwd,
|
|
1597
|
+
)}" and a question describing what to inspect and the desired output format.`,
|
|
1598
|
+
];
|
|
1599
|
+
content = [{ type: "text", text: metadataLines.join("\n") }];
|
|
1600
|
+
details = {};
|
|
1601
|
+
sourcePath = absolutePath;
|
|
1602
|
+
} else {
|
|
1603
|
+
if (fileSize > MAX_IMAGE_SIZE) {
|
|
1604
|
+
const sizeStr = formatBytes(fileSize);
|
|
1605
|
+
const maxStr = formatBytes(MAX_IMAGE_SIZE);
|
|
1606
|
+
throw new ToolError(`Image file too large: ${sizeStr} exceeds ${maxStr} limit.`);
|
|
1607
|
+
}
|
|
1608
|
+
try {
|
|
1609
|
+
const imageInput = await loadImageInput({
|
|
1610
|
+
path: readPath,
|
|
1611
|
+
cwd: this.session.cwd,
|
|
1612
|
+
autoResize: this.#autoResizeImages,
|
|
1613
|
+
maxBytes: MAX_IMAGE_SIZE,
|
|
1614
|
+
resolvedPath: absolutePath,
|
|
1615
|
+
detectedMimeType: mimeType,
|
|
1616
|
+
});
|
|
1617
|
+
if (!imageInput) {
|
|
1618
|
+
throw new ToolError(`Read image file [${mimeType}] failed: unsupported image format.`);
|
|
1619
|
+
}
|
|
1620
|
+
content = [
|
|
1621
|
+
{ type: "text", text: imageInput.textNote },
|
|
1622
|
+
{ type: "image", data: imageInput.data, mimeType: imageInput.mimeType },
|
|
1623
|
+
];
|
|
1624
|
+
details = {};
|
|
1625
|
+
sourcePath = imageInput.resolvedPath;
|
|
1626
|
+
} catch (error) {
|
|
1627
|
+
if (error instanceof ImageInputTooLargeError) {
|
|
1628
|
+
throw new ToolError(error.message);
|
|
1629
|
+
}
|
|
1630
|
+
throw error;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
} else if (isNotebookPath(absolutePath) && !isRawSelector(parsed)) {
|
|
1634
|
+
const notebookText = await readEditableNotebookText(absolutePath, localReadPath);
|
|
1635
|
+
if (isMultiRange(parsed) && parsed.kind === "lines") {
|
|
1636
|
+
return this.#buildInMemoryMultiRangeResult(notebookText, parsed.ranges, {
|
|
1637
|
+
details: { resolvedPath: absolutePath },
|
|
1638
|
+
sourcePath: absolutePath,
|
|
1639
|
+
entityLabel: "notebook",
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
const { offset, limit } = selToOffsetLimit(parsed);
|
|
1643
|
+
return this.#buildInMemoryTextResult(notebookText, offset, limit, {
|
|
1644
|
+
details: { resolvedPath: absolutePath },
|
|
1645
|
+
sourcePath: absolutePath,
|
|
1646
|
+
entityLabel: "notebook",
|
|
1647
|
+
});
|
|
1648
|
+
} else if (shouldConvertWithMarkit) {
|
|
1649
|
+
// Convert document via markit.
|
|
1650
|
+
const result = await convertFileWithMarkit(absolutePath, signal);
|
|
1651
|
+
if (result.ok) {
|
|
1652
|
+
// Apply truncation to converted content
|
|
1653
|
+
const truncation = truncateHead(result.content);
|
|
1654
|
+
const outputText = truncation.content;
|
|
1655
|
+
|
|
1656
|
+
details = { truncation };
|
|
1657
|
+
sourcePath = absolutePath;
|
|
1658
|
+
truncationInfo = { result: truncation, options: { direction: "head", startLine: 1 } };
|
|
1659
|
+
|
|
1660
|
+
content = [{ type: "text", text: outputText }];
|
|
1661
|
+
} else if (result.error) {
|
|
1662
|
+
content = [{ type: "text", text: `[Cannot read ${ext} file: ${result.error || "conversion failed"}]` }];
|
|
1663
|
+
} else {
|
|
1664
|
+
content = [{ type: "text", text: `[Cannot read ${ext} file: conversion failed]` }];
|
|
1665
|
+
}
|
|
1666
|
+
} else {
|
|
1667
|
+
if (
|
|
1668
|
+
parsed.kind === "none" &&
|
|
1669
|
+
this.session.settings.get("read.summarize.enabled") &&
|
|
1670
|
+
(this.session.settings.get("read.summarize.prose") || !PROSE_SUMMARY_EXTENSIONS.has(ext))
|
|
1671
|
+
) {
|
|
1672
|
+
const summary = await this.#trySummarize(absolutePath, fileSize, signal);
|
|
1673
|
+
if (summary?.parsed && summary.elided) {
|
|
1674
|
+
const renderedSummary = this.#renderSummary(summary);
|
|
1675
|
+
const footer = formatSummaryElisionFooter(
|
|
1676
|
+
localReadPath,
|
|
1677
|
+
renderedSummary.elidedSpans,
|
|
1678
|
+
renderedSummary.elidedLines,
|
|
1679
|
+
);
|
|
1680
|
+
const modelText = footer ? `${renderedSummary.text}\n\n${footer}` : renderedSummary.text;
|
|
1681
|
+
details = {
|
|
1682
|
+
displayContent: { text: renderedSummary.displayText, startLine: 1 },
|
|
1683
|
+
summary: {
|
|
1684
|
+
lines: countTextLines(renderedSummary.text),
|
|
1685
|
+
elidedSpans: renderedSummary.elidedSpans,
|
|
1686
|
+
elidedLines: renderedSummary.elidedLines,
|
|
1687
|
+
},
|
|
1688
|
+
};
|
|
1689
|
+
|
|
1690
|
+
sourcePath = absolutePath;
|
|
1691
|
+
content = [{ type: "text", text: modelText }];
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
if (!content) {
|
|
1696
|
+
if (isMultiRange(parsed) && parsed.kind === "lines") {
|
|
1697
|
+
const multiResult = await this.#readLocalFileMultiRange(
|
|
1698
|
+
absolutePath,
|
|
1699
|
+
parsed.ranges,
|
|
1700
|
+
parsed,
|
|
1701
|
+
displayMode,
|
|
1702
|
+
suffixResolution,
|
|
1703
|
+
signal,
|
|
1704
|
+
);
|
|
1705
|
+
if (multiResult.bridgeResult) return multiResult.bridgeResult;
|
|
1706
|
+
content = [{ type: "text", text: multiResult.outputText }];
|
|
1707
|
+
sourcePath = absolutePath;
|
|
1708
|
+
details = {};
|
|
1709
|
+
if (multiResult.columnTruncated > 0) {
|
|
1710
|
+
columnTruncated = multiResult.columnTruncated;
|
|
1711
|
+
}
|
|
1712
|
+
} else {
|
|
1713
|
+
// Raw text or line-range mode
|
|
1714
|
+
const { offset, limit } = selToOffsetLimit(parsed);
|
|
1715
|
+
// Try ACP bridge first — editor's in-memory buffer is source of truth.
|
|
1716
|
+
// Request full text so local range rendering keeps normal context and line numbers.
|
|
1717
|
+
const bridgePromise = this.#routeReadThroughBridge(absolutePath);
|
|
1718
|
+
if (bridgePromise !== undefined) {
|
|
1719
|
+
try {
|
|
1720
|
+
const bridgeText = await bridgePromise;
|
|
1721
|
+
const bridgeResult = this.#buildInMemoryTextResult(bridgeText, offset, limit, {
|
|
1722
|
+
details: { resolvedPath: absolutePath, suffixResolution },
|
|
1723
|
+
sourcePath: absolutePath,
|
|
1724
|
+
entityLabel: "file",
|
|
1725
|
+
raw: isRawSelector(parsed),
|
|
1726
|
+
});
|
|
1727
|
+
if (suffixResolution) {
|
|
1728
|
+
const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
|
|
1729
|
+
const firstText = bridgeResult.content.find((c): c is TextContent => c.type === "text");
|
|
1730
|
+
if (firstText) firstText.text = `${notice}\n${firstText.text}`;
|
|
1731
|
+
}
|
|
1732
|
+
return bridgeResult;
|
|
1733
|
+
} catch (error) {
|
|
1734
|
+
logger.warn("ACP fs readTextFile failed; falling back to disk", { path: absolutePath, error });
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// User-requested 0-indexed range start. Lines BEFORE this become
|
|
1739
|
+
// leading context (added below if offset is explicit).
|
|
1740
|
+
const requestedStart = offset ? Math.max(0, offset - 1) : 0;
|
|
1741
|
+
const expandStart = offset !== undefined && offset > 1;
|
|
1742
|
+
const expandEnd = limit !== undefined;
|
|
1743
|
+
const leadingContext = expandStart ? Math.min(requestedStart, RANGE_LEADING_CONTEXT_LINES) : 0;
|
|
1744
|
+
const trailingContext = expandEnd ? RANGE_TRAILING_CONTEXT_LINES : 0;
|
|
1745
|
+
const startLine = requestedStart - leadingContext;
|
|
1746
|
+
const startLineDisplay = startLine + 1;
|
|
1747
|
+
|
|
1748
|
+
const DEFAULT_LIMIT = this.#defaultLimit;
|
|
1749
|
+
const effectiveLimit = limit ?? DEFAULT_LIMIT;
|
|
1750
|
+
const maxLinesToCollect = Math.min(effectiveLimit + leadingContext + trailingContext, DEFAULT_MAX_LINES);
|
|
1751
|
+
const selectedLineLimit = effectiveLimit + leadingContext + trailingContext;
|
|
1752
|
+
// Scale byte budget with line limit so the configured line count actually fits.
|
|
1753
|
+
// Assume ~512 bytes/line average; never go below the shared default.
|
|
1754
|
+
const maxBytesForRead = Math.max(DEFAULT_MAX_BYTES, maxLinesToCollect * 512);
|
|
1755
|
+
|
|
1756
|
+
const streamResult = await streamLinesFromFile(
|
|
1757
|
+
absolutePath,
|
|
1758
|
+
startLine,
|
|
1759
|
+
maxLinesToCollect,
|
|
1760
|
+
maxBytesForRead,
|
|
1761
|
+
selectedLineLimit,
|
|
1762
|
+
signal,
|
|
1763
|
+
);
|
|
1764
|
+
|
|
1765
|
+
const {
|
|
1766
|
+
lines: collectedLines,
|
|
1767
|
+
totalFileLines,
|
|
1768
|
+
collectedBytes,
|
|
1769
|
+
stoppedByByteLimit,
|
|
1770
|
+
firstLinePreview,
|
|
1771
|
+
firstLineByteLength,
|
|
1772
|
+
} = streamResult;
|
|
1773
|
+
|
|
1774
|
+
// Check if offset is out of bounds - return graceful message instead of throwing
|
|
1775
|
+
if (requestedStart >= totalFileLines) {
|
|
1776
|
+
const suggestion =
|
|
1777
|
+
totalFileLines === 0
|
|
1778
|
+
? "The file is empty."
|
|
1779
|
+
: `Use :1 to read from the start, or :${totalFileLines} to read the last line.`;
|
|
1780
|
+
return toolResult<ReadToolDetails>({ resolvedPath: absolutePath, suffixResolution })
|
|
1781
|
+
.text(
|
|
1782
|
+
`Line ${requestedStart + 1} is beyond end of file (${totalFileLines} lines total). ${suggestion}`,
|
|
1783
|
+
)
|
|
1784
|
+
.done();
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// Per-line column cap. Skipped in raw mode so `:raw` always returns
|
|
1788
|
+
// verbatim bytes for paste-back-into-tool workflows. Total byte/line
|
|
1789
|
+
// counts in `truncation` keep reflecting the source, not the trimmed
|
|
1790
|
+
// view — column truncation surfaces separately via `.limits()`.
|
|
1791
|
+
const rawSelector = isRawSelector(parsed);
|
|
1792
|
+
const maxColumns = resolveOutputMaxColumns(this.session.settings);
|
|
1793
|
+
if (!rawSelector && maxColumns > 0) {
|
|
1794
|
+
for (let i = 0; i < collectedLines.length; i++) {
|
|
1795
|
+
const { text, wasTruncated } = truncateLine(collectedLines[i], maxColumns);
|
|
1796
|
+
if (wasTruncated) {
|
|
1797
|
+
collectedLines[i] = text;
|
|
1798
|
+
columnTruncated = maxColumns;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
const selectedContent = collectedLines.join("\n");
|
|
1804
|
+
const userLimitedLines = collectedLines.length;
|
|
1805
|
+
|
|
1806
|
+
const totalSelectedLines = totalFileLines - startLine;
|
|
1807
|
+
const totalSelectedBytes = collectedBytes;
|
|
1808
|
+
const wasTruncated = collectedLines.length < totalSelectedLines || stoppedByByteLimit;
|
|
1809
|
+
const firstLineExceedsLimit = firstLineByteLength !== undefined && firstLineByteLength > maxBytesForRead;
|
|
1810
|
+
|
|
1811
|
+
const truncation: TruncationResult = {
|
|
1812
|
+
content: selectedContent,
|
|
1813
|
+
truncated: wasTruncated,
|
|
1814
|
+
truncatedBy: stoppedByByteLimit ? "bytes" : wasTruncated ? "lines" : undefined,
|
|
1815
|
+
totalLines: totalSelectedLines,
|
|
1816
|
+
totalBytes: totalSelectedBytes,
|
|
1817
|
+
outputLines: collectedLines.length,
|
|
1818
|
+
outputBytes: collectedBytes,
|
|
1819
|
+
lastLinePartial: false,
|
|
1820
|
+
firstLineExceedsLimit,
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
if (collectedLines.length > 0 && !firstLineExceedsLimit) {
|
|
1824
|
+
getFileReadCache(this.session).recordContiguous(absolutePath, startLineDisplay, collectedLines);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
const shouldAddHashLines = !rawSelector && displayMode.hashLines;
|
|
1828
|
+
const shouldAddLineNumbers = rawSelector ? false : shouldAddHashLines ? false : displayMode.lineNumbers;
|
|
1829
|
+
let capturedDisplayContent: { text: string; startLine: number } | undefined;
|
|
1830
|
+
const formatText = (text: string, startNum: number): string => {
|
|
1831
|
+
capturedDisplayContent = { text, startLine: startNum };
|
|
1832
|
+
return formatTextWithMode(text, startNum, shouldAddHashLines, shouldAddLineNumbers);
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
let outputText: string;
|
|
1836
|
+
|
|
1837
|
+
if (truncation.firstLineExceedsLimit) {
|
|
1838
|
+
const firstLineBytes = firstLineByteLength ?? 0;
|
|
1839
|
+
const snippet = firstLinePreview ?? { text: "", bytes: 0 };
|
|
1840
|
+
|
|
1841
|
+
if (shouldAddHashLines) {
|
|
1842
|
+
outputText = `[Line ${startLineDisplay} is ${formatBytes(
|
|
1843
|
+
firstLineBytes,
|
|
1844
|
+
)}, exceeds ${formatBytes(maxBytesForRead)} limit. Hashline output requires full lines; cannot compute hashes for a truncated preview.]`;
|
|
1845
|
+
} else {
|
|
1846
|
+
outputText = formatText(snippet.text, startLineDisplay);
|
|
1847
|
+
}
|
|
1848
|
+
if (snippet.text.length === 0) {
|
|
1849
|
+
outputText = `[Line ${startLineDisplay} is ${formatBytes(
|
|
1850
|
+
firstLineBytes,
|
|
1851
|
+
)}, exceeds ${formatBytes(maxBytesForRead)} limit. Unable to display a valid UTF-8 snippet.]`;
|
|
1852
|
+
}
|
|
1853
|
+
details = { truncation };
|
|
1854
|
+
sourcePath = absolutePath;
|
|
1855
|
+
truncationInfo = {
|
|
1856
|
+
result: truncation,
|
|
1857
|
+
options: { direction: "head", startLine: startLineDisplay, totalFileLines },
|
|
1858
|
+
};
|
|
1859
|
+
} else if (truncation.truncated) {
|
|
1860
|
+
outputText = formatText(truncation.content, startLineDisplay);
|
|
1861
|
+
details = { truncation };
|
|
1862
|
+
sourcePath = absolutePath;
|
|
1863
|
+
truncationInfo = {
|
|
1864
|
+
result: truncation,
|
|
1865
|
+
options: { direction: "head", startLine: startLineDisplay, totalFileLines },
|
|
1866
|
+
};
|
|
1867
|
+
} else if (startLine + userLimitedLines < totalFileLines) {
|
|
1868
|
+
const remaining = totalFileLines - (startLine + userLimitedLines);
|
|
1869
|
+
const nextOffset = startLine + userLimitedLines + 1;
|
|
1870
|
+
|
|
1871
|
+
outputText = formatText(truncation.content, startLineDisplay);
|
|
1872
|
+
outputText += `\n\n[${remaining} more lines in file. Use :${nextOffset} to continue]`;
|
|
1873
|
+
details = {};
|
|
1874
|
+
sourcePath = absolutePath;
|
|
1875
|
+
} else {
|
|
1876
|
+
// No truncation, no user limit exceeded
|
|
1877
|
+
outputText = formatText(truncation.content, startLineDisplay);
|
|
1878
|
+
details = {};
|
|
1879
|
+
sourcePath = absolutePath;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
if (capturedDisplayContent) {
|
|
1883
|
+
details.displayContent = capturedDisplayContent;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
if (!firstLineExceedsLimit && collectedLines.length > 0) {
|
|
1887
|
+
const blocks = scanConflictLines(collectedLines, startLineDisplay);
|
|
1888
|
+
if (blocks.length > 0) {
|
|
1889
|
+
const history = getConflictHistory(this.session);
|
|
1890
|
+
const displayPathForWarning = formatPathRelativeToCwd(absolutePath, this.session.cwd);
|
|
1891
|
+
const entries = blocks.map(block =>
|
|
1892
|
+
history.register({
|
|
1893
|
+
absolutePath,
|
|
1894
|
+
displayPath: displayPathForWarning,
|
|
1895
|
+
...block,
|
|
1896
|
+
}),
|
|
1897
|
+
);
|
|
1898
|
+
// Cheap full-file scan only when the window already showed
|
|
1899
|
+
// at least one conflict — otherwise pay nothing on clean files.
|
|
1900
|
+
let totalInFile = entries.length;
|
|
1901
|
+
let scanTruncated = false;
|
|
1902
|
+
try {
|
|
1903
|
+
const fileScan = await scanFileForConflicts(absolutePath);
|
|
1904
|
+
totalInFile = Math.max(entries.length, fileScan.blocks.length);
|
|
1905
|
+
scanTruncated = fileScan.scanTruncated;
|
|
1906
|
+
} catch {
|
|
1907
|
+
// Best-effort enrichment; fall back to window-only count.
|
|
1908
|
+
}
|
|
1909
|
+
outputText += formatConflictWarning(entries, {
|
|
1910
|
+
totalInFile,
|
|
1911
|
+
displayPath: displayPathForWarning,
|
|
1912
|
+
scanTruncated,
|
|
1913
|
+
});
|
|
1914
|
+
details.conflictCount = entries.length;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
content = [{ type: "text", text: outputText }];
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
if (suffixResolution) {
|
|
1924
|
+
details.suffixResolution = suffixResolution;
|
|
1925
|
+
// Inline resolution notice into first text block so the model sees the actual path
|
|
1926
|
+
const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
|
|
1927
|
+
const firstText = content.find((c): c is TextContent => c.type === "text");
|
|
1928
|
+
if (firstText) {
|
|
1929
|
+
firstText.text = `${notice}\n${firstText.text}`;
|
|
1930
|
+
} else {
|
|
1931
|
+
content = [{ type: "text", text: notice }, ...content];
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
const resultBuilder = toolResult(details).content(content);
|
|
1935
|
+
if (sourcePath) {
|
|
1936
|
+
resultBuilder.sourcePath(sourcePath);
|
|
1937
|
+
}
|
|
1938
|
+
if (truncationInfo) {
|
|
1939
|
+
resultBuilder.truncation(truncationInfo.result, truncationInfo.options);
|
|
1940
|
+
}
|
|
1941
|
+
if (columnTruncated > 0) {
|
|
1942
|
+
resultBuilder.limits({ columnMax: columnTruncated });
|
|
1943
|
+
}
|
|
1944
|
+
return resultBuilder.done();
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/**
|
|
1948
|
+
* Render a `conflict://<N>` (or `conflict://<N>/<scope>`) region as
|
|
1949
|
+
* regular file content. The lines are emitted with their original
|
|
1950
|
+
* file line numbers so hashline anchors line up with the source
|
|
1951
|
+
* file, and no truncation footer is appended.
|
|
1952
|
+
*/
|
|
1953
|
+
async #readConflictRegion(id: number, scope: ConflictScope | undefined): Promise<AgentToolResult<ReadToolDetails>> {
|
|
1954
|
+
const entry: ConflictEntry | undefined = getConflictHistory(this.session).get(id);
|
|
1955
|
+
if (!entry) {
|
|
1956
|
+
throw new ToolError(
|
|
1957
|
+
`Conflict #${id} not found. Conflict ids are registered when \`read\` surfaces a marker block; re-read the file to get a current id.`,
|
|
1958
|
+
);
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
const region = renderConflictRegion(entry, scope);
|
|
1962
|
+
const displayMode = resolveFileDisplayMode(this.session);
|
|
1963
|
+
const shouldAddHashLines = displayMode.hashLines;
|
|
1964
|
+
const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
|
|
1965
|
+
|
|
1966
|
+
const rawText = region.lines.join("\n");
|
|
1967
|
+
const formattedText = formatTextWithMode(rawText, region.startLine, shouldAddHashLines, shouldAddLineNumbers);
|
|
1968
|
+
|
|
1969
|
+
const details: ReadToolDetails = {
|
|
1970
|
+
resolvedPath: entry.absolutePath,
|
|
1971
|
+
displayContent: { text: rawText, startLine: region.startLine },
|
|
1972
|
+
};
|
|
1973
|
+
return toolResult<ReadToolDetails>(details).text(formattedText).sourcePath(entry.absolutePath).done();
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* Implement the `<path>:conflicts` read selector: scan the whole file once, register
|
|
1978
|
+
* every block in the session's conflict history, and return a compact
|
|
1979
|
+
* `#N L_a-L_b` index instead of file content. Designed for heavily
|
|
1980
|
+
* conflicted files where dumping every body would be wasteful.
|
|
1981
|
+
*/
|
|
1982
|
+
async #readFileConflicts(
|
|
1983
|
+
absolutePath: string,
|
|
1984
|
+
suffixResolution: { from: string; to: string } | undefined,
|
|
1985
|
+
signal: AbortSignal | undefined,
|
|
1986
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
1987
|
+
throwIfAborted(signal);
|
|
1988
|
+
const scan = await scanFileForConflicts(absolutePath);
|
|
1989
|
+
const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
|
|
1990
|
+
const history = getConflictHistory(this.session);
|
|
1991
|
+
const entries = scan.blocks.map(block =>
|
|
1992
|
+
history.register({
|
|
1993
|
+
absolutePath,
|
|
1994
|
+
displayPath,
|
|
1995
|
+
...block,
|
|
1996
|
+
}),
|
|
1997
|
+
);
|
|
1998
|
+
|
|
1999
|
+
const summary =
|
|
2000
|
+
entries.length === 0
|
|
2001
|
+
? `No unresolved git merge conflicts in ${displayPath}.`
|
|
2002
|
+
: formatConflictSummary(entries, { displayPath, scanTruncated: scan.scanTruncated });
|
|
2003
|
+
|
|
2004
|
+
const details: ReadToolDetails = {
|
|
2005
|
+
resolvedPath: absolutePath,
|
|
2006
|
+
suffixResolution,
|
|
2007
|
+
conflictCount: entries.length,
|
|
2008
|
+
};
|
|
2009
|
+
return toolResult<ReadToolDetails>(details).text(summary).sourcePath(absolutePath).done();
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
/**
|
|
2013
|
+
* Handle internal URLs (agent://, artifact://, memory://, rule://, local://).
|
|
2014
|
+
* Supports pagination via offset/limit but rejects them when query extraction is used.
|
|
2015
|
+
*/
|
|
2016
|
+
async #handleInternalUrl(
|
|
2017
|
+
url: string,
|
|
2018
|
+
parsedSel: ParsedSelector,
|
|
2019
|
+
signal?: AbortSignal,
|
|
2020
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
2021
|
+
const internalRouter = InternalUrlRouter.instance();
|
|
2022
|
+
|
|
2023
|
+
// Check if URL has query extraction (agent:// only).
|
|
2024
|
+
// Use parseInternalUrl which handles colons in host (namespaced skills).
|
|
2025
|
+
let urlMeta: InternalUrl;
|
|
2026
|
+
try {
|
|
2027
|
+
urlMeta = parseInternalUrl(url);
|
|
2028
|
+
} catch (e) {
|
|
2029
|
+
throw new ToolError(e instanceof Error ? e.message : String(e));
|
|
2030
|
+
}
|
|
2031
|
+
const scheme = urlMeta.protocol.replace(/:$/, "").toLowerCase();
|
|
2032
|
+
let hasExtraction = false;
|
|
2033
|
+
if (scheme === "agent") {
|
|
2034
|
+
const hasPathExtraction = urlMeta.pathname && urlMeta.pathname !== "/" && urlMeta.pathname !== "";
|
|
2035
|
+
const queryParam = urlMeta.searchParams.get("q");
|
|
2036
|
+
const hasQueryExtraction = queryParam !== null && queryParam !== "";
|
|
2037
|
+
hasExtraction = hasPathExtraction || hasQueryExtraction;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// Reject line selectors when query extraction is used
|
|
2041
|
+
if (hasExtraction && parsedSel.kind !== "none" && parsedSel.kind !== "raw") {
|
|
2042
|
+
throw new ToolError("Cannot combine query extraction with line selectors");
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
// Resolve the internal URL
|
|
2046
|
+
const resource = await internalRouter.resolve(url, {
|
|
2047
|
+
cwd: this.session.cwd,
|
|
2048
|
+
settings: this.session.settings,
|
|
2049
|
+
signal,
|
|
2050
|
+
});
|
|
2051
|
+
const details: ReadToolDetails = { resolvedPath: resource.sourcePath, contentType: resource.contentType };
|
|
2052
|
+
|
|
2053
|
+
// If extraction was used, return directly (no pagination)
|
|
2054
|
+
if (hasExtraction) {
|
|
2055
|
+
return toolResult(details).text(resource.content).sourceInternal(url).done();
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
const raw = isRawSelector(parsedSel);
|
|
2059
|
+
if (isMultiRange(parsedSel) && parsedSel.kind === "lines") {
|
|
2060
|
+
return this.#buildInMemoryMultiRangeResult(resource.content, parsedSel.ranges, {
|
|
2061
|
+
details,
|
|
2062
|
+
sourcePath: resource.sourcePath,
|
|
2063
|
+
sourceInternal: url,
|
|
2064
|
+
entityLabel: "resource",
|
|
2065
|
+
immutable: resource.immutable,
|
|
2066
|
+
raw,
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
const { offset, limit } = selToOffsetLimit(parsedSel);
|
|
2071
|
+
return this.#buildInMemoryTextResult(resource.content, offset, limit, {
|
|
2072
|
+
details,
|
|
2073
|
+
sourcePath: resource.sourcePath,
|
|
2074
|
+
sourceInternal: url,
|
|
2075
|
+
entityLabel: "resource",
|
|
2076
|
+
ignoreResultLimits: scheme === "skill",
|
|
2077
|
+
immutable: resource.immutable,
|
|
2078
|
+
raw,
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
/** Read directory contents as a formatted listing */
|
|
2083
|
+
async #readDirectory(
|
|
2084
|
+
absolutePath: string,
|
|
2085
|
+
limit: number | undefined,
|
|
2086
|
+
signal?: AbortSignal,
|
|
2087
|
+
): Promise<AgentToolResult<ReadToolDetails>> {
|
|
2088
|
+
const READ_DIRECTORY_MAX_DEPTH = 2;
|
|
2089
|
+
const READ_DIRECTORY_CHILD_LIMIT = 12;
|
|
2090
|
+
|
|
2091
|
+
throwIfAborted(signal);
|
|
2092
|
+
let tree: DirectoryTree;
|
|
2093
|
+
try {
|
|
2094
|
+
tree = await buildDirectoryTree(absolutePath, {
|
|
2095
|
+
maxDepth: READ_DIRECTORY_MAX_DEPTH,
|
|
2096
|
+
perDirLimit: READ_DIRECTORY_CHILD_LIMIT,
|
|
2097
|
+
rootLimit: null,
|
|
2098
|
+
lineCap: limit ?? null,
|
|
2099
|
+
});
|
|
2100
|
+
} catch (error) {
|
|
2101
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2102
|
+
throw new ToolError(`Cannot read directory: ${message}`);
|
|
2103
|
+
}
|
|
2104
|
+
throwIfAborted(signal);
|
|
2105
|
+
|
|
2106
|
+
const output = tree.totalLines <= 1 ? "(empty directory)" : tree.rendered;
|
|
2107
|
+
const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
2108
|
+
const details: ReadToolDetails = {
|
|
2109
|
+
isDirectory: true,
|
|
2110
|
+
resolvedPath: tree.rootPath,
|
|
2111
|
+
};
|
|
2112
|
+
|
|
2113
|
+
const resultBuilder = toolResult(details).text(truncation.content).sourcePath(tree.rootPath);
|
|
2114
|
+
if (tree.truncated) {
|
|
2115
|
+
resultBuilder.limits({ resultLimit: 1 });
|
|
2116
|
+
}
|
|
2117
|
+
if (truncation.truncated) {
|
|
2118
|
+
resultBuilder.truncation(truncation, { direction: "head" });
|
|
2119
|
+
details.truncation = truncation;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
return resultBuilder.done();
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
// =============================================================================
|
|
2127
|
+
// TUI Renderer
|
|
2128
|
+
// =============================================================================
|
|
2129
|
+
|
|
2130
|
+
interface ReadRenderArgs {
|
|
2131
|
+
path?: string;
|
|
2132
|
+
file_path?: string;
|
|
2133
|
+
sel?: string;
|
|
2134
|
+
// Legacy fields from old schema — tolerated for in-flight tool calls during transition
|
|
2135
|
+
offset?: number;
|
|
2136
|
+
limit?: number;
|
|
2137
|
+
raw?: boolean;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
export const readToolRenderer = {
|
|
2141
|
+
renderCall(args: ReadRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
2142
|
+
if (isReadableUrlPath(args.file_path || args.path || "")) {
|
|
2143
|
+
return renderReadUrlCall(args, _options, uiTheme);
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
const rawPath = args.file_path || args.path || "";
|
|
2147
|
+
const shortPath = shortenPath(rawPath);
|
|
2148
|
+
const linkTarget = tryResolveInternalUrlSync(rawPath);
|
|
2149
|
+
const filePath = linkTarget ? fileHyperlink(linkTarget, shortPath) : shortPath;
|
|
2150
|
+
const offset = args.offset;
|
|
2151
|
+
const limit = args.limit;
|
|
2152
|
+
|
|
2153
|
+
let pathDisplay = filePath || "…";
|
|
2154
|
+
if (offset !== undefined || limit !== undefined) {
|
|
2155
|
+
const startLine = offset ?? 1;
|
|
2156
|
+
const endLine = limit !== undefined ? startLine + limit - 1 : "";
|
|
2157
|
+
pathDisplay += `:${startLine}${endLine ? `-${endLine}` : ""}`;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
const text = renderStatusLine({ icon: "pending", title: "Read", description: pathDisplay }, uiTheme);
|
|
2161
|
+
return new Text(text, 0, 0);
|
|
2162
|
+
},
|
|
2163
|
+
|
|
2164
|
+
renderResult(
|
|
2165
|
+
result: { content: Array<{ type: string; text?: string }>; details?: ReadToolDetails; isError?: boolean },
|
|
2166
|
+
options: RenderResultOptions,
|
|
2167
|
+
uiTheme: Theme,
|
|
2168
|
+
args?: ReadRenderArgs,
|
|
2169
|
+
): Component {
|
|
2170
|
+
const urlDetails = result.details as ReadUrlToolDetails | undefined;
|
|
2171
|
+
if (urlDetails?.kind === "url" || isReadableUrlPath(args?.file_path || args?.path || "")) {
|
|
2172
|
+
return renderReadUrlResult(
|
|
2173
|
+
result as {
|
|
2174
|
+
content: Array<{ type: string; text?: string }>;
|
|
2175
|
+
details?: ReadUrlToolDetails;
|
|
2176
|
+
isError?: boolean;
|
|
2177
|
+
},
|
|
2178
|
+
options,
|
|
2179
|
+
uiTheme,
|
|
2180
|
+
);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
if (result.isError) {
|
|
2184
|
+
const rawErrorText = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
2185
|
+
const errorText = (rawErrorText || "Unknown error").replace(/^Error:\s*/, "");
|
|
2186
|
+
const rawPath = args?.file_path || args?.path || "";
|
|
2187
|
+
const filePath = shortenPath(rawPath);
|
|
2188
|
+
let title = filePath ? `Read ${filePath}` : "Read";
|
|
2189
|
+
if (args?.offset !== undefined || args?.limit !== undefined) {
|
|
2190
|
+
const startLine = args.offset ?? 1;
|
|
2191
|
+
const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
|
|
2192
|
+
title += `:${startLine}${endLine ? `-${endLine}` : ""}`;
|
|
2193
|
+
}
|
|
2194
|
+
const header = renderStatusLine({ icon: "error", title }, uiTheme);
|
|
2195
|
+
const errorLines = errorText.split("\n").map(line => uiTheme.fg("error", replaceTabs(line)));
|
|
2196
|
+
const outputBlock = new CachedOutputBlock();
|
|
2197
|
+
return {
|
|
2198
|
+
render: (width: number) =>
|
|
2199
|
+
outputBlock.render({ header, state: "error", sections: [{ lines: errorLines }], width }, uiTheme),
|
|
2200
|
+
invalidate: () => outputBlock.invalidate(),
|
|
2201
|
+
};
|
|
2202
|
+
}
|
|
2203
|
+
const details = result.details;
|
|
2204
|
+
const rawText = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
2205
|
+
// Prefer structured `displayContent` from details when available so the TUI
|
|
2206
|
+
// shows clean file content (no model-only hashline anchors) without parsing the formatted text.
|
|
2207
|
+
// Fall back to the raw text, but strip the LLM-facing notice so it doesn't
|
|
2208
|
+
// echo next to the styled warning line below.
|
|
2209
|
+
const contentText = details?.displayContent?.text ?? stripOutputNotice(rawText, details?.meta);
|
|
2210
|
+
const imageContent = result.content?.find(c => c.type === "image");
|
|
2211
|
+
const rawPath = args?.file_path || args?.path || "";
|
|
2212
|
+
const filePath = shortenPath(rawPath);
|
|
2213
|
+
const lang = getLanguageFromPath(splitPathAndSel(rawPath).path);
|
|
2214
|
+
|
|
2215
|
+
const warningLines: string[] = [];
|
|
2216
|
+
const truncation = details?.meta?.truncation;
|
|
2217
|
+
const fallback = details?.truncation;
|
|
2218
|
+
if (details?.resolvedPath) {
|
|
2219
|
+
warningLines.push(uiTheme.fg("dim", wrapBrackets(`Resolved path: ${details.resolvedPath}`, uiTheme)));
|
|
2220
|
+
}
|
|
2221
|
+
if (truncation) {
|
|
2222
|
+
if (fallback?.firstLineExceedsLimit) {
|
|
2223
|
+
let warning = `First line exceeds ${formatBytes(fallback.outputBytes ?? fallback.totalBytes)} limit`;
|
|
2224
|
+
if (truncation.artifactId) {
|
|
2225
|
+
warning += `. ${formatFullOutputReference(truncation.artifactId)}`;
|
|
2226
|
+
}
|
|
2227
|
+
warningLines.push(uiTheme.fg("warning", wrapBrackets(warning, uiTheme)));
|
|
2228
|
+
} else {
|
|
2229
|
+
const warning = formatStyledTruncationWarning(details?.meta, uiTheme);
|
|
2230
|
+
if (warning) warningLines.push(warning);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
if (imageContent) {
|
|
2235
|
+
const suffix = details?.suffixResolution;
|
|
2236
|
+
const displayPath = suffix ? shortenPath(suffix.to) : filePath || rawPath || "image";
|
|
2237
|
+
const correction = suffix ? ` ${uiTheme.fg("dim", `(corrected from ${shortenPath(suffix.from)})`)}` : "";
|
|
2238
|
+
const header = renderStatusLine(
|
|
2239
|
+
{ icon: suffix ? "warning" : "success", title: "Read", description: `${displayPath}${correction}` },
|
|
2240
|
+
uiTheme,
|
|
2241
|
+
);
|
|
2242
|
+
const detailLines = contentText ? contentText.split("\n").map(line => uiTheme.fg("toolOutput", line)) : [];
|
|
2243
|
+
const lines = [...detailLines, ...warningLines];
|
|
2244
|
+
const outputBlock = new CachedOutputBlock();
|
|
2245
|
+
return {
|
|
2246
|
+
render: (width: number) =>
|
|
2247
|
+
outputBlock.render(
|
|
2248
|
+
{
|
|
2249
|
+
header,
|
|
2250
|
+
state: "success",
|
|
2251
|
+
sections: [
|
|
2252
|
+
{
|
|
2253
|
+
label: uiTheme.fg("toolTitle", "Details"),
|
|
2254
|
+
lines: lines.length > 0 ? lines : [uiTheme.fg("dim", "(image)")],
|
|
2255
|
+
},
|
|
2256
|
+
],
|
|
2257
|
+
width,
|
|
2258
|
+
},
|
|
2259
|
+
uiTheme,
|
|
2260
|
+
),
|
|
2261
|
+
invalidate: () => outputBlock.invalidate(),
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
const suffix = details?.suffixResolution;
|
|
2266
|
+
const plainDisplayPath = suffix ? shortenPath(suffix.to) : filePath;
|
|
2267
|
+
// resolvedPath is the absolute fs path for fs-backed reads (regular files plus
|
|
2268
|
+
// local:// / memory:// / artifact:// resources). Fall back to a sync
|
|
2269
|
+
// resolver for fs-backed internal URLs so the title is clickable even before the
|
|
2270
|
+
// result lands or if the handler didn't populate resolvedPath.
|
|
2271
|
+
const absForLink = details?.resolvedPath ?? tryResolveInternalUrlSync(rawPath);
|
|
2272
|
+
const displayPath = absForLink ? fileHyperlink(absForLink, plainDisplayPath) : plainDisplayPath;
|
|
2273
|
+
const correction = suffix ? ` ${uiTheme.fg("dim", `(corrected from ${shortenPath(suffix.from)})`)}` : "";
|
|
2274
|
+
let title = displayPath ? `Read ${displayPath}${correction}` : "Read";
|
|
2275
|
+
if (args?.offset !== undefined || args?.limit !== undefined) {
|
|
2276
|
+
const startLine = args.offset ?? 1;
|
|
2277
|
+
const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
|
|
2278
|
+
title += `:${startLine}${endLine ? `-${endLine}` : ""}`;
|
|
2279
|
+
}
|
|
2280
|
+
if (details?.summary) {
|
|
2281
|
+
title += ` (summary: ${details.summary.elidedSpans} elided span${details.summary.elidedSpans === 1 ? "" : "s"})`;
|
|
2282
|
+
}
|
|
2283
|
+
if (details?.conflictCount && details.conflictCount > 0) {
|
|
2284
|
+
const n = details.conflictCount;
|
|
2285
|
+
title += ` ${uiTheme.fg("warning", `(⚠ ${n} conflict${n === 1 ? "" : "s"})`)}`;
|
|
2286
|
+
}
|
|
2287
|
+
const rawRequested = args?.raw === true || isRawSelector(parseSel(splitPathAndSel(rawPath).sel));
|
|
2288
|
+
const isMarkdown = details?.contentType === "text/markdown" && !rawRequested;
|
|
2289
|
+
let cachedWidth: number | undefined;
|
|
2290
|
+
let cachedExpanded: boolean | undefined;
|
|
2291
|
+
let cachedLines: string[] | undefined;
|
|
2292
|
+
return {
|
|
2293
|
+
render: (width: number) => {
|
|
2294
|
+
const expanded = options.expanded;
|
|
2295
|
+
if (cachedLines && cachedWidth === width && cachedExpanded === expanded) return cachedLines;
|
|
2296
|
+
cachedLines = isMarkdown
|
|
2297
|
+
? renderMarkdownCell(
|
|
2298
|
+
{
|
|
2299
|
+
content: contentText,
|
|
2300
|
+
title,
|
|
2301
|
+
status: "complete",
|
|
2302
|
+
output: warningLines.length > 0 ? warningLines.join("\n") : undefined,
|
|
2303
|
+
expanded,
|
|
2304
|
+
width,
|
|
2305
|
+
},
|
|
2306
|
+
uiTheme,
|
|
2307
|
+
)
|
|
2308
|
+
: renderCodeCell(
|
|
2309
|
+
{
|
|
2310
|
+
code: contentText,
|
|
2311
|
+
language: lang,
|
|
2312
|
+
title,
|
|
2313
|
+
status: "complete",
|
|
2314
|
+
output: warningLines.length > 0 ? warningLines.join("\n") : undefined,
|
|
2315
|
+
expanded,
|
|
2316
|
+
width,
|
|
2317
|
+
},
|
|
2318
|
+
uiTheme,
|
|
2319
|
+
);
|
|
2320
|
+
cachedWidth = width;
|
|
2321
|
+
cachedExpanded = expanded;
|
|
2322
|
+
return cachedLines;
|
|
2323
|
+
},
|
|
2324
|
+
invalidate: () => {
|
|
2325
|
+
cachedWidth = undefined;
|
|
2326
|
+
cachedExpanded = undefined;
|
|
2327
|
+
cachedLines = undefined;
|
|
2328
|
+
},
|
|
2329
|
+
};
|
|
2330
|
+
},
|
|
2331
|
+
mergeCallAndResult: true,
|
|
2332
|
+
};
|