@wahack/pi-coding-agent 15.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10031 -0
- package/README.md +36 -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 +142 -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/thinking-note.ts +13 -0
- package/examples/extensions/tools.ts +145 -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 +17 -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/12-redis-sessions.ts +54 -0
- package/examples/sdk/13-sql-sessions.ts +61 -0
- package/examples/sdk/README.md +172 -0
- package/package.json +554 -0
- package/scripts/build-binary.ts +100 -0
- package/scripts/bundle-dist.ts +90 -0
- package/scripts/format-prompts.ts +68 -0
- package/scripts/generate-docs-index.ts +40 -0
- package/scripts/generate-template.ts +33 -0
- package/scripts/omp +42 -0
- package/scripts/omp.ts +19 -0
- package/src/async/index.ts +1 -0
- package/src/async/job-manager.ts +625 -0
- package/src/auto-thinking/classifier.ts +185 -0
- package/src/autoresearch/command-resume.md +14 -0
- package/src/autoresearch/dashboard.ts +436 -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 +407 -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 +117 -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-buckets.ts +66 -0
- package/src/capability/rule.ts +261 -0
- package/src/capability/settings.ts +34 -0
- package/src/capability/skill.ts +63 -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 +340 -0
- package/src/cli/auth-broker-cli.ts +895 -0
- package/src/cli/auth-gateway-cli.ts +611 -0
- package/src/cli/classify-install-target.ts +76 -0
- package/src/cli/claude-trace-cli.ts +795 -0
- package/src/cli/commands/init-xdg.ts +27 -0
- package/src/cli/completion-gen.ts +550 -0
- package/src/cli/config-cli.ts +418 -0
- package/src/cli/dry-balance-cli.ts +856 -0
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/file-processor.ts +133 -0
- package/src/cli/gallery-cli.ts +230 -0
- package/src/cli/gallery-fixtures/agentic.ts +407 -0
- package/src/cli/gallery-fixtures/codeintel.ts +187 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +220 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +250 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +57 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli/grep-cli.ts +160 -0
- package/src/cli/grievances-cli.ts +256 -0
- package/src/cli/initial-message.ts +58 -0
- package/src/cli/list-models.ts +194 -0
- package/src/cli/plugin-cli.ts +996 -0
- package/src/cli/read-cli.ts +57 -0
- package/src/cli/session-picker.ts +79 -0
- package/src/cli/setup-cli.ts +231 -0
- package/src/cli/shell-cli.ts +176 -0
- package/src/cli/ssh-cli.ts +179 -0
- package/src/cli/startup-cwd.ts +68 -0
- package/src/cli/stats-cli.ts +238 -0
- package/src/cli/tiny-models-cli.ts +127 -0
- package/src/cli/update-cli.ts +611 -0
- package/src/cli/usage-cli.ts +603 -0
- package/src/cli/web-search-cli.ts +132 -0
- package/src/cli/worktree-cli.ts +291 -0
- package/src/cli-commands.ts +79 -0
- package/src/cli.ts +200 -0
- package/src/commands/acp.ts +24 -0
- package/src/commands/agents.ts +57 -0
- package/src/commands/auth-broker.ts +99 -0
- package/src/commands/auth-gateway.ts +69 -0
- package/src/commands/commit.ts +46 -0
- package/src/commands/complete.ts +66 -0
- package/src/commands/completions.ts +60 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/dry-balance.ts +43 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/grep.ts +48 -0
- package/src/commands/grievances.ts +51 -0
- package/src/commands/install.ts +107 -0
- package/src/commands/launch.ts +169 -0
- package/src/commands/plugin.ts +78 -0
- package/src/commands/read.ts +38 -0
- package/src/commands/setup.ts +67 -0
- package/src/commands/shell.ts +29 -0
- package/src/commands/ssh.ts +60 -0
- package/src/commands/stats.ts +29 -0
- package/src/commands/tiny-models.ts +36 -0
- package/src/commands/update.ts +21 -0
- package/src/commands/usage.ts +35 -0
- package/src/commands/web-search.ts +42 -0
- package/src/commands/worktree.ts +56 -0
- package/src/commit/agentic/agent.ts +317 -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 +146 -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 +245 -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 +92 -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/api-key-resolver.ts +60 -0
- package/src/config/append-only-context-mode.ts +31 -0
- package/src/config/config-file.ts +317 -0
- package/src/config/file-lock.ts +164 -0
- package/src/config/keybindings.ts +628 -0
- package/src/config/mcp-schema.json +230 -0
- package/src/config/model-discovery.ts +554 -0
- package/src/config/model-registry.ts +2090 -0
- package/src/config/model-resolver.ts +1502 -0
- package/src/config/model-roles.ts +74 -0
- package/src/config/models-config-schema.ts +226 -0
- package/src/config/models-config.ts +129 -0
- package/src/config/prompt-templates.ts +185 -0
- package/src/config/resolve-config-value.ts +94 -0
- package/src/config/settings-schema.ts +3530 -0
- package/src/config/settings.ts +1178 -0
- package/src/config.ts +242 -0
- package/src/cursor.ts +340 -0
- package/src/dap/client.ts +760 -0
- package/src/dap/config.ts +189 -0
- package/src/dap/defaults.json +212 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1441 -0
- package/src/dap/types.ts +610 -0
- package/src/debug/index.ts +515 -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/protocol-probe.ts +267 -0
- package/src/debug/raw-sse-buffer.ts +273 -0
- package/src/debug/raw-sse.ts +292 -0
- package/src/debug/report-bundle.ts +374 -0
- package/src/debug/system-info.ts +111 -0
- package/src/debug/terminal-info.ts +124 -0
- package/src/discovery/agents-md.ts +67 -0
- package/src/discovery/agents.ts +230 -0
- package/src/discovery/at-imports.ts +273 -0
- package/src/discovery/builtin-defaults.ts +39 -0
- package/src/discovery/builtin-rules/index.ts +54 -0
- package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
- package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
- package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
- package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
- package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
- package/src/discovery/builtin-rules/rs-result-type.md +19 -0
- package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
- package/src/discovery/builtin-rules/ts-import-type.md +42 -0
- package/src/discovery/builtin-rules/ts-no-any.md +56 -0
- package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
- package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
- package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
- package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
- package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
- package/src/discovery/builtin-rules/ts-set-map.md +28 -0
- package/src/discovery/builtin.ts +906 -0
- package/src/discovery/claude-plugins.ts +386 -0
- package/src/discovery/claude.ts +584 -0
- package/src/discovery/cline.ts +83 -0
- package/src/discovery/codex.ts +522 -0
- package/src/discovery/cursor.ts +220 -0
- package/src/discovery/gemini.ts +383 -0
- package/src/discovery/github.ts +154 -0
- package/src/discovery/helpers.ts +1016 -0
- package/src/discovery/index.ts +81 -0
- package/src/discovery/mcp-json.ts +171 -0
- package/src/discovery/omp-extension-roots.ts +190 -0
- package/src/discovery/omp-plugins.ts +383 -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 +999 -0
- package/src/edit/file-snapshot-store.ts +91 -0
- package/src/edit/hashline/block-resolver.ts +33 -0
- package/src/edit/hashline/diff.ts +290 -0
- package/src/edit/hashline/execute.ts +242 -0
- package/src/edit/hashline/filesystem.ts +130 -0
- package/src/edit/hashline/index.ts +5 -0
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/edit/hashline/params.ts +18 -0
- package/src/edit/index.ts +571 -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 +1891 -0
- package/src/edit/modes/replace.ts +1137 -0
- package/src/edit/normalize.ts +345 -0
- package/src/edit/notebook.ts +242 -0
- package/src/edit/read-file.ts +25 -0
- package/src/edit/renderer.ts +769 -0
- package/src/edit/streaming.ts +517 -0
- package/src/eval/__tests__/agent-bridge.test.ts +708 -0
- package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
- package/src/eval/__tests__/budget-bridge.test.ts +69 -0
- package/src/eval/__tests__/completion-bridge.test.ts +412 -0
- package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
- package/src/eval/__tests__/idle-timeout.test.ts +80 -0
- package/src/eval/__tests__/js-context-manager.test.ts +241 -0
- package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
- package/src/eval/agent-bridge.ts +319 -0
- package/src/eval/backend.ts +71 -0
- package/src/eval/bridge-timeout.ts +44 -0
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/completion-bridge.ts +207 -0
- package/src/eval/concurrency-bridge.ts +34 -0
- package/src/eval/idle-timeout.ts +91 -0
- package/src/eval/index.ts +4 -0
- package/src/eval/js/context-manager.ts +502 -0
- package/src/eval/js/executor.ts +173 -0
- package/src/eval/js/index.ts +51 -0
- package/src/eval/js/shared/helpers.ts +283 -0
- package/src/eval/js/shared/indirect-eval.ts +30 -0
- package/src/eval/js/shared/local-module-loader.ts +342 -0
- package/src/eval/js/shared/prelude.ts +2 -0
- package/src/eval/js/shared/prelude.txt +246 -0
- package/src/eval/js/shared/rewrite-imports.ts +532 -0
- package/src/eval/js/shared/runtime.ts +352 -0
- package/src/eval/js/shared/types.ts +18 -0
- package/src/eval/js/tool-bridge.ts +162 -0
- package/src/eval/js/worker-core.ts +132 -0
- package/src/eval/js/worker-entry.ts +30 -0
- package/src/eval/js/worker-protocol.ts +47 -0
- package/src/eval/py/__tests__/prelude.test.ts +19 -0
- package/src/eval/py/display.ts +71 -0
- package/src/eval/py/executor.ts +742 -0
- package/src/eval/py/index.ts +68 -0
- package/src/eval/py/kernel.ts +748 -0
- package/src/eval/py/prelude.py +658 -0
- package/src/eval/py/prelude.ts +3 -0
- package/src/eval/py/runner.py +1133 -0
- package/src/eval/py/runtime.ts +276 -0
- package/src/eval/py/spawn-options.ts +126 -0
- package/src/eval/py/tool-bridge.ts +182 -0
- package/src/eval/session-id.ts +8 -0
- package/src/eval/types.ts +48 -0
- package/src/exa/index.ts +2 -0
- package/src/exa/mcp-client.ts +370 -0
- package/src/exa/types.ts +69 -0
- package/src/exec/bash-executor.ts +419 -0
- package/src/exec/exec.ts +53 -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 +1051 -0
- package/src/export/html/template.generated.ts +2 -0
- package/src/export/html/template.html +46 -0
- package/src/export/html/template.js +2271 -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 +583 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
- package/src/extensibility/custom-commands/bundled/review/index.ts +489 -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 +269 -0
- package/src/extensibility/custom-tools/types.ts +270 -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 +78 -0
- package/src/extensibility/extensions/index.ts +16 -0
- package/src/extensibility/extensions/loader.ts +572 -0
- package/src/extensibility/extensions/runner.ts +922 -0
- package/src/extensibility/extensions/types.ts +1322 -0
- package/src/extensibility/extensions/wrapper.ts +223 -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 +606 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +24 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +15 -0
- package/src/extensibility/plugins/doctor.ts +65 -0
- package/src/extensibility/plugins/git-url.ts +367 -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 +682 -0
- package/src/extensibility/plugins/loader.ts +313 -0
- package/src/extensibility/plugins/manager.ts +827 -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/marketplace-auto-update.ts +49 -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 +312 -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/goals/index.ts +3 -0
- package/src/goals/runtime.ts +528 -0
- package/src/goals/state.ts +37 -0
- package/src/goals/tools/goal-tool.ts +251 -0
- package/src/hindsight/backend.ts +354 -0
- package/src/hindsight/bank.ts +156 -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 +429 -0
- package/src/hindsight/seeds.json +32 -0
- package/src/hindsight/state.ts +488 -0
- package/src/hindsight/transcript.ts +71 -0
- package/src/index.ts +59 -0
- package/src/internal-urls/agent-protocol.ts +146 -0
- package/src/internal-urls/artifact-protocol.ts +107 -0
- package/src/internal-urls/docs-index.generated.ts +106 -0
- package/src/internal-urls/history-protocol.ts +113 -0
- package/src/internal-urls/index.ts +25 -0
- package/src/internal-urls/issue-pr-protocol.ts +584 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/local-protocol.ts +287 -0
- package/src/internal-urls/mcp-protocol.ts +151 -0
- package/src/internal-urls/memory-protocol.ts +169 -0
- package/src/internal-urls/omp-protocol.ts +93 -0
- package/src/internal-urls/parse.ts +72 -0
- package/src/internal-urls/registry-helpers.ts +25 -0
- package/src/internal-urls/router.ts +105 -0
- package/src/internal-urls/rule-protocol.ts +45 -0
- package/src/internal-urls/skill-protocol.ts +96 -0
- package/src/internal-urls/types.ts +152 -0
- package/src/internal-urls/vault-protocol.ts +936 -0
- package/src/irc/bus.ts +292 -0
- package/src/lib/xai-http.ts +124 -0
- package/src/lsp/client.ts +1193 -0
- package/src/lsp/clients/biome-client.ts +264 -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 +502 -0
- package/src/lsp/defaults.json +493 -0
- package/src/lsp/diagnostics-ledger.ts +51 -0
- package/src/lsp/edits.ts +267 -0
- package/src/lsp/index.ts +2477 -0
- package/src/lsp/lspmux.ts +233 -0
- package/src/lsp/render.ts +694 -0
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +455 -0
- package/src/lsp/utils.ts +718 -0
- package/src/main.ts +1325 -0
- package/src/mcp/client.ts +484 -0
- package/src/mcp/config-writer.ts +225 -0
- package/src/mcp/config.ts +365 -0
- package/src/mcp/index.ts +29 -0
- package/src/mcp/json-rpc.ts +122 -0
- package/src/mcp/loader.ts +124 -0
- package/src/mcp/manager.ts +1275 -0
- package/src/mcp/oauth-discovery.ts +442 -0
- package/src/mcp/oauth-flow.ts +442 -0
- package/src/mcp/render.ts +132 -0
- package/src/mcp/smithery-auth.ts +104 -0
- package/src/mcp/smithery-connect.ts +145 -0
- package/src/mcp/smithery-registry.ts +477 -0
- package/src/mcp/timeout.ts +59 -0
- package/src/mcp/tool-bridge.ts +426 -0
- package/src/mcp/tool-cache.ts +117 -0
- package/src/mcp/transports/http.ts +519 -0
- package/src/mcp/transports/index.ts +6 -0
- package/src/mcp/transports/stdio.ts +528 -0
- package/src/mcp/types.ts +423 -0
- package/src/memories/index.ts +1150 -0
- package/src/memories/storage.ts +577 -0
- package/src/memory-backend/index.ts +18 -0
- package/src/memory-backend/local-backend.ts +39 -0
- package/src/memory-backend/off-backend.ts +25 -0
- package/src/memory-backend/resolve.ts +25 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +166 -0
- package/src/mnemopi/backend.ts +547 -0
- package/src/mnemopi/config.ts +160 -0
- package/src/mnemopi/index.ts +3 -0
- package/src/mnemopi/state.ts +584 -0
- package/src/modes/acp/acp-agent.ts +2407 -0
- package/src/modes/acp/acp-client-bridge.ts +154 -0
- package/src/modes/acp/acp-event-mapper.ts +929 -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 +1206 -0
- package/src/modes/components/agent-hub.ts +1071 -0
- package/src/modes/components/assistant-message.ts +307 -0
- package/src/modes/components/bash-execution.ts +220 -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/chat-block.ts +111 -0
- package/src/modes/components/compaction-summary-message.ts +87 -0
- package/src/modes/components/copy-selector.ts +206 -0
- package/src/modes/components/countdown-timer.ts +75 -0
- package/src/modes/components/custom-editor.ts +398 -0
- package/src/modes/components/custom-message.ts +63 -0
- package/src/modes/components/diff.ts +277 -0
- package/src/modes/components/dynamic-border.ts +34 -0
- package/src/modes/components/error-banner.ts +33 -0
- package/src/modes/components/eval-execution.ts +158 -0
- package/src/modes/components/execution-shared.ts +101 -0
- package/src/modes/components/extensions/extension-dashboard.ts +399 -0
- package/src/modes/components/extensions/extension-list.ts +502 -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 +627 -0
- package/src/modes/components/extensions/types.ts +186 -0
- package/src/modes/components/footer.ts +274 -0
- package/src/modes/components/history-search.ts +280 -0
- package/src/modes/components/hook-editor.ts +167 -0
- package/src/modes/components/hook-input.ts +87 -0
- package/src/modes/components/hook-message.ts +66 -0
- package/src/modes/components/hook-selector.ts +660 -0
- package/src/modes/components/index.ts +38 -0
- package/src/modes/components/keybinding-hints.ts +65 -0
- package/src/modes/components/late-diagnostics-message.ts +60 -0
- package/src/modes/components/login-dialog.ts +164 -0
- package/src/modes/components/mcp-add-wizard.ts +1340 -0
- package/src/modes/components/message-frame.ts +88 -0
- package/src/modes/components/model-selector.ts +1271 -0
- package/src/modes/components/oauth-selector.ts +368 -0
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +820 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/plugin-selector.ts +95 -0
- package/src/modes/components/plugin-settings.ts +722 -0
- package/src/modes/components/queue-mode-selector.ts +56 -0
- package/src/modes/components/read-tool-group.ts +670 -0
- package/src/modes/components/segment-track.ts +52 -0
- package/src/modes/components/session-selector.ts +625 -0
- package/src/modes/components/settings-defs.ts +189 -0
- package/src/modes/components/settings-selector.ts +651 -0
- package/src/modes/components/show-images-selector.ts +45 -0
- package/src/modes/components/skill-message.ts +89 -0
- package/src/modes/components/status-line/component.ts +869 -0
- package/src/modes/components/status-line/context-thresholds.ts +79 -0
- package/src/modes/components/status-line/git-utils.ts +42 -0
- package/src/modes/components/status-line/index.ts +5 -0
- package/src/modes/components/status-line/presets.ts +106 -0
- package/src/modes/components/status-line/segments.ts +584 -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 +108 -0
- package/src/modes/components/theme-selector.ts +63 -0
- package/src/modes/components/thinking-selector.ts +52 -0
- package/src/modes/components/tiny-title-download-progress.ts +90 -0
- package/src/modes/components/tips.txt +19 -0
- package/src/modes/components/todo-reminder.ts +38 -0
- package/src/modes/components/tool-execution.ts +1024 -0
- package/src/modes/components/transcript-container.ts +608 -0
- package/src/modes/components/tree-selector.ts +978 -0
- package/src/modes/components/ttsr-notification.ts +122 -0
- package/src/modes/components/user-message-selector.ts +227 -0
- package/src/modes/components/user-message.ts +66 -0
- package/src/modes/components/visual-truncate.ts +63 -0
- package/src/modes/components/welcome.ts +493 -0
- package/src/modes/controllers/btw-controller.ts +105 -0
- package/src/modes/controllers/command-controller-shared.ts +109 -0
- package/src/modes/controllers/command-controller.ts +1566 -0
- package/src/modes/controllers/event-controller.ts +1054 -0
- package/src/modes/controllers/extension-ui-controller.ts +886 -0
- package/src/modes/controllers/input-controller.ts +1073 -0
- package/src/modes/controllers/mcp-command-controller.ts +2017 -0
- package/src/modes/controllers/omfg-controller.ts +283 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +1108 -0
- package/src/modes/controllers/ssh-command-controller.ts +384 -0
- package/src/modes/controllers/streaming-reveal.ts +279 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -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/gradient-highlight.ts +87 -0
- package/src/modes/image-references.ts +117 -0
- package/src/modes/index.ts +17 -0
- package/src/modes/interactive-mode.ts +3370 -0
- package/src/modes/internal-url-autocomplete.ts +143 -0
- package/src/modes/loop-limit.ts +140 -0
- package/src/modes/magic-keywords.ts +20 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/oauth-manual-input.ts +69 -0
- package/src/modes/orchestrate.ts +42 -0
- package/src/modes/print-mode.ts +126 -0
- package/src/modes/prompt-action-autocomplete.ts +260 -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 +963 -0
- package/src/modes/rpc/rpc-mode.ts +947 -0
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +458 -0
- package/src/modes/runtime-init.ts +116 -0
- package/src/modes/session-observer-registry.ts +146 -0
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +99 -0
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
- package/src/modes/setup-wizard/scenes/outro.ts +35 -0
- package/src/modes/setup-wizard/scenes/providers.ts +69 -0
- package/src/modes/setup-wizard/scenes/sign-in.ts +205 -0
- package/src/modes/setup-wizard/scenes/splash.ts +201 -0
- package/src/modes/setup-wizard/scenes/theme.ts +299 -0
- package/src/modes/setup-wizard/scenes/types.ts +48 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +129 -0
- package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
- package/src/modes/shared.ts +47 -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 +199 -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/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 +235 -0
- package/src/modes/theme/theme-schema.json +459 -0
- package/src/modes/theme/theme.ts +2676 -0
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +359 -0
- package/src/modes/ultrathink.ts +41 -0
- package/src/modes/utils/context-usage.ts +339 -0
- package/src/modes/utils/copy-targets.ts +360 -0
- package/src/modes/utils/hotkeys-markdown.ts +61 -0
- package/src/modes/utils/keybinding-matchers.ts +51 -0
- package/src/modes/utils/tools-markdown.ts +27 -0
- package/src/modes/utils/ui-helpers.ts +801 -0
- package/src/modes/workflow.ts +42 -0
- package/src/plan-mode/approved-plan.ts +186 -0
- package/src/plan-mode/plan-handoff.ts +37 -0
- package/src/plan-mode/plan-protection.ts +31 -0
- package/src/plan-mode/state.ts +6 -0
- package/src/priority.json +41 -0
- package/src/prompts/agents/designer.md +66 -0
- package/src/prompts/agents/explore.md +58 -0
- package/src/prompts/agents/frontmatter.md +11 -0
- package/src/prompts/agents/init.md +33 -0
- package/src/prompts/agents/librarian.md +119 -0
- package/src/prompts/agents/oracle.md +55 -0
- package/src/prompts/agents/plan.md +48 -0
- package/src/prompts/agents/reviewer.md +140 -0
- package/src/prompts/agents/task.md +16 -0
- package/src/prompts/ci-green-request.md +36 -0
- package/src/prompts/dry-balance-bench.md +8 -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-custom-request.md +22 -0
- package/src/prompts/review-headless-request.md +16 -0
- package/src/prompts/review-request.md +69 -0
- package/src/prompts/steering/user-interjection.md +10 -0
- package/src/prompts/system/agent-creation-architect.md +50 -0
- package/src/prompts/system/agent-creation-user.md +6 -0
- package/src/prompts/system/auto-continue.md +1 -0
- package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
- package/src/prompts/system/auto-thinking-difficulty.md +12 -0
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/btw-user.md +8 -0
- package/src/prompts/system/commit-message-system.md +14 -0
- package/src/prompts/system/custom-system-prompt.md +64 -0
- package/src/prompts/system/eager-todo.md +13 -0
- package/src/prompts/system/empty-stop-retry.md +6 -0
- package/src/prompts/system/irc-incoming.md +7 -0
- package/src/prompts/system/manual-continue.md +7 -0
- package/src/prompts/system/memory-consolidation-system.md +8 -0
- package/src/prompts/system/memory-extraction-system.md +26 -0
- package/src/prompts/system/omfg-user.md +50 -0
- package/src/prompts/system/orchestrate-notice.md +40 -0
- package/src/prompts/system/plan-mode-active.md +109 -0
- package/src/prompts/system/plan-mode-approved.md +25 -0
- package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
- package/src/prompts/system/plan-mode-reference.md +11 -0
- package/src/prompts/system/plan-mode-subagent.md +33 -0
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
- package/src/prompts/system/project-prompt.md +52 -0
- package/src/prompts/system/subagent-system-prompt.md +64 -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 +258 -0
- package/src/prompts/system/tiny-title-system.md +8 -0
- package/src/prompts/system/title-system.md +16 -0
- package/src/prompts/system/ttsr-interrupt.md +7 -0
- package/src/prompts/system/ttsr-tool-reminder.md +5 -0
- package/src/prompts/system/ultrathink-notice.md +3 -0
- package/src/prompts/system/web-search.md +25 -0
- package/src/prompts/system/workflow-notice.md +70 -0
- package/src/prompts/tools/apply-patch.md +65 -0
- package/src/prompts/tools/ask.md +30 -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 +46 -0
- package/src/prompts/tools/browser.md +73 -0
- package/src/prompts/tools/checkpoint.md +16 -0
- package/src/prompts/tools/debug.md +34 -0
- package/src/prompts/tools/eval.md +92 -0
- package/src/prompts/tools/find.md +36 -0
- package/src/prompts/tools/github.md +21 -0
- package/src/prompts/tools/goal.md +18 -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 +59 -0
- package/src/prompts/tools/job.md +19 -0
- package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
- package/src/prompts/tools/lsp.md +42 -0
- package/src/prompts/tools/memory-edit.md +8 -0
- package/src/prompts/tools/patch.md +70 -0
- package/src/prompts/tools/read.md +84 -0
- package/src/prompts/tools/recall.md +5 -0
- package/src/prompts/tools/reflect.md +5 -0
- package/src/prompts/tools/render-mermaid.md +9 -0
- package/src/prompts/tools/replace.md +30 -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 +32 -0
- package/src/prompts/tools/search.md +24 -0
- package/src/prompts/tools/ssh.md +31 -0
- package/src/prompts/tools/task-summary.md +17 -0
- package/src/prompts/tools/task.md +88 -0
- package/src/prompts/tools/todo.md +62 -0
- package/src/prompts/tools/web-search.md +10 -0
- package/src/prompts/tools/write.md +14 -0
- package/src/registry/agent-lifecycle.ts +218 -0
- package/src/registry/agent-registry.ts +151 -0
- package/src/sdk.ts +2558 -0
- package/src/secrets/index.ts +123 -0
- package/src/secrets/obfuscator.ts +298 -0
- package/src/secrets/regex.ts +21 -0
- package/src/session/agent-session.ts +10121 -0
- package/src/session/agent-storage.ts +455 -0
- package/src/session/artifacts.ts +135 -0
- package/src/session/auth-broker-config.ts +131 -0
- package/src/session/auth-storage.ts +29 -0
- package/src/session/blob-store.ts +255 -0
- package/src/session/client-bridge.ts +85 -0
- package/src/session/history-storage.ts +348 -0
- package/src/session/indexed-session-storage.ts +430 -0
- package/src/session/messages.ts +541 -0
- package/src/session/redis-session-storage.ts +170 -0
- package/src/session/session-dump-format.ts +209 -0
- package/src/session/session-history-format.ts +246 -0
- package/src/session/session-manager.ts +3676 -0
- package/src/session/session-storage.ts +529 -0
- package/src/session/shake-types.ts +43 -0
- package/src/session/sql-session-storage.ts +314 -0
- package/src/session/streaming-output.ts +1330 -0
- package/src/session/tool-choice-queue.ts +213 -0
- package/src/session/yield-queue.ts +173 -0
- package/src/slash-commands/acp-builtins.ts +70 -0
- package/src/slash-commands/builtin-registry.ts +1798 -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/marketplace-manager.ts +25 -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/stats-dashboard.ts +85 -0
- package/src/slash-commands/helpers/todo.ts +279 -0
- package/src/slash-commands/helpers/usage-report.ts +95 -0
- package/src/slash-commands/marketplace-install-parser.ts +99 -0
- package/src/slash-commands/types.ts +135 -0
- package/src/ssh/config-writer.ts +183 -0
- package/src/ssh/connection-manager.ts +509 -0
- package/src/ssh/ssh-executor.ts +189 -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/stubs/natives/index.ts +814 -0
- package/src/stubs/natives/package.json +7 -0
- package/src/stubs/tui/index.ts +282 -0
- package/src/stubs/tui/package.json +7 -0
- package/src/system-prompt.ts +611 -0
- package/src/task/agents.ts +167 -0
- package/src/task/commands.ts +132 -0
- package/src/task/discovery.ts +122 -0
- package/src/task/executor.ts +2133 -0
- package/src/task/index.ts +1419 -0
- package/src/task/name-generator.ts +1577 -0
- package/src/task/omp-command.ts +26 -0
- package/src/task/output-manager.ts +88 -0
- package/src/task/parallel.ts +116 -0
- package/src/task/render.ts +1381 -0
- package/src/task/repair-args.ts +129 -0
- package/src/task/subprocess-tool-registry.ts +88 -0
- package/src/task/types.ts +336 -0
- package/src/task/worktree.ts +514 -0
- package/src/telemetry-export.ts +144 -0
- package/src/thinking.ts +167 -0
- package/src/tiny/compiled-runtime.ts +179 -0
- package/src/tiny/device.ts +111 -0
- package/src/tiny/dtype.ts +101 -0
- package/src/tiny/models.ts +242 -0
- package/src/tiny/text.ts +165 -0
- package/src/tiny/title-client.ts +543 -0
- package/src/tiny/title-protocol.ts +56 -0
- package/src/tiny/worker.ts +568 -0
- package/src/tool-discovery/mode.ts +24 -0
- package/src/tool-discovery/tool-index.ts +256 -0
- package/src/tools/approval.ts +189 -0
- package/src/tools/archive-reader.ts +721 -0
- package/src/tools/ask.ts +928 -0
- package/src/tools/ast-edit.ts +642 -0
- package/src/tools/ast-grep.ts +452 -0
- package/src/tools/auto-generated-guard.ts +322 -0
- package/src/tools/bash-command-fixup.ts +37 -0
- package/src/tools/bash-interactive.ts +408 -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 +1386 -0
- package/src/tools/browser/attach.ts +175 -0
- package/src/tools/browser/launch.ts +660 -0
- package/src/tools/browser/readable.ts +112 -0
- package/src/tools/browser/registry.ts +197 -0
- package/src/tools/browser/render.ts +216 -0
- package/src/tools/browser/tab-protocol.ts +105 -0
- package/src/tools/browser/tab-supervisor.ts +628 -0
- package/src/tools/browser/tab-worker-entry.ts +21 -0
- package/src/tools/browser/tab-worker.ts +1226 -0
- package/src/tools/browser.ts +343 -0
- package/src/tools/checkpoint.ts +136 -0
- package/src/tools/conflict-detect.ts +718 -0
- package/src/tools/context.ts +39 -0
- package/src/tools/debug.ts +1067 -0
- package/src/tools/eval-backends.ts +27 -0
- package/src/tools/eval-render.ts +752 -0
- package/src/tools/eval.ts +577 -0
- package/src/tools/fetch.ts +1926 -0
- package/src/tools/file-recorder.ts +35 -0
- package/src/tools/find.ts +609 -0
- package/src/tools/fs-cache-invalidation.ts +28 -0
- package/src/tools/gh-cache-invalidation.ts +255 -0
- package/src/tools/gh-format.ts +12 -0
- package/src/tools/gh-renderer.ts +481 -0
- package/src/tools/gh.ts +3720 -0
- package/src/tools/github-cache.ts +637 -0
- package/src/tools/grouped-file-output.ts +210 -0
- package/src/tools/image-gen.ts +1517 -0
- package/src/tools/index.ts +599 -0
- package/src/tools/inspect-image-renderer.ts +132 -0
- package/src/tools/inspect-image.ts +174 -0
- package/src/tools/irc.ts +723 -0
- package/src/tools/job.ts +557 -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 +20 -0
- package/src/tools/memory-edit.ts +59 -0
- package/src/tools/memory-recall.ts +100 -0
- package/src/tools/memory-reflect.ts +88 -0
- package/src/tools/memory-render.ts +202 -0
- package/src/tools/memory-retain.ts +91 -0
- package/src/tools/output-meta.ts +754 -0
- package/src/tools/output-schema-validator.ts +132 -0
- package/src/tools/path-utils.ts +1054 -0
- package/src/tools/plan-mode-guard.ts +108 -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 +2929 -0
- package/src/tools/render-mermaid.ts +69 -0
- package/src/tools/render-utils.ts +838 -0
- package/src/tools/renderers.ts +77 -0
- package/src/tools/report-tool-issue.ts +534 -0
- package/src/tools/resolve.ts +276 -0
- package/src/tools/review.ts +253 -0
- package/src/tools/search-tool-bm25.ts +351 -0
- package/src/tools/search.ts +1580 -0
- package/src/tools/sqlite-reader.ts +828 -0
- package/src/tools/ssh.ts +349 -0
- package/src/tools/todo.ts +982 -0
- package/src/tools/tool-errors.ts +62 -0
- package/src/tools/tool-result.ts +94 -0
- package/src/tools/tool-timeouts.ts +30 -0
- package/src/tools/tts.ts +133 -0
- package/src/tools/write.ts +1217 -0
- package/src/tools/yield.ts +269 -0
- package/src/tui/code-cell.ts +216 -0
- package/src/tui/file-list.ts +55 -0
- package/src/tui/hyperlink.ts +175 -0
- package/src/tui/index.ts +12 -0
- package/src/tui/output-block.ts +240 -0
- package/src/tui/status-line.ts +54 -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/block-context.ts +312 -0
- package/src/utils/changelog.ts +132 -0
- package/src/utils/clipboard.ts +193 -0
- package/src/utils/command-args.ts +76 -0
- package/src/utils/commit-message-generator.ts +151 -0
- package/src/utils/edit-mode.ts +41 -0
- package/src/utils/enhanced-paste.ts +230 -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 +281 -0
- package/src/utils/git.ts +1833 -0
- package/src/utils/image-loading.ts +132 -0
- package/src/utils/image-resize.ts +309 -0
- package/src/utils/jj.ts +248 -0
- package/src/utils/lang-from-path.ts +239 -0
- package/src/utils/markit.ts +89 -0
- package/src/utils/open.ts +55 -0
- package/src/utils/session-color.ts +68 -0
- package/src/utils/shell-snapshot.ts +187 -0
- package/src/utils/sixel.ts +69 -0
- package/src/utils/title-generator.ts +373 -0
- package/src/utils/tool-choice.ts +33 -0
- package/src/utils/tools-manager.ts +363 -0
- package/src/web/kagi.ts +305 -0
- package/src/web/parallel.ts +353 -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 +704 -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 +94 -0
- package/src/web/scrapers/types.ts +397 -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 +325 -0
- package/src/web/search/index.ts +292 -0
- package/src/web/search/provider.ts +157 -0
- package/src/web/search/providers/anthropic.ts +318 -0
- package/src/web/search/providers/base.ts +89 -0
- package/src/web/search/providers/brave.ts +152 -0
- package/src/web/search/providers/codex.ts +591 -0
- package/src/web/search/providers/exa.ts +400 -0
- package/src/web/search/providers/gemini.ts +460 -0
- package/src/web/search/providers/jina.ts +111 -0
- package/src/web/search/providers/kagi.ts +86 -0
- package/src/web/search/providers/kimi.ts +196 -0
- package/src/web/search/providers/parallel.ts +225 -0
- package/src/web/search/providers/perplexity.ts +730 -0
- package/src/web/search/providers/searxng.ts +313 -0
- package/src/web/search/providers/synthetic.ts +114 -0
- package/src/web/search/providers/tavily.ts +176 -0
- package/src/web/search/providers/utils.ts +128 -0
- package/src/web/search/providers/zai.ts +333 -0
- package/src/web/search/render.ts +262 -0
- package/src/web/search/types.ts +482 -0
- package/src/web/search/utils.ts +17 -0
- package/src/workspace-tree.ts +286 -0
|
@@ -0,0 +1,1054 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import * as url from "node:url";
|
|
5
|
+
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
6
|
+
import { InternalUrlRouter, type LocalProtocolOptions } from "../internal-urls";
|
|
7
|
+
import { ToolError } from "./tool-errors";
|
|
8
|
+
|
|
9
|
+
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
10
|
+
// A single line-range chunk: `N`, `N-M`, `N+K`, or open-ended `N-`. `..` is
|
|
11
|
+
// accepted everywhere `-` is, as a forgiving alias for Rust/Python-style ranges
|
|
12
|
+
// (e.g. `2724..2727` == `2724-2727`, `2724..` == `2724-`); it is normalized to
|
|
13
|
+
// `-` in parseLineRangeChunk. Keep this fragment and LINE_RANGE_CHUNK_RE in sync.
|
|
14
|
+
const RANGE_CHUNK_SRC = String.raw`L?\d+(?:(?:[-+]|\.\.)L?\d+|-|\.\.)?`;
|
|
15
|
+
const RANGE_LIST_SRC = `${RANGE_CHUNK_SRC}(?:,${RANGE_CHUNK_SRC})*`;
|
|
16
|
+
const FILE_LINE_RANGE_RE = new RegExp(`^(?:${RANGE_LIST_SRC}|raw|conflicts)$`, "i");
|
|
17
|
+
const FILE_LINE_RANGE_ONLY_RE = new RegExp(`^${RANGE_LIST_SRC}$`, "i");
|
|
18
|
+
const FILE_RAW_ONLY_RE = /^raw$/i;
|
|
19
|
+
// Permissive selector chunk for internal URLs — accepts well-formed selectors
|
|
20
|
+
// plus common malformed shapes (e.g. `:-N`) so the read tool peels the entire
|
|
21
|
+
// selector chain off before dispatching to a protocol handler.
|
|
22
|
+
const INTERNAL_URL_SELECTOR_PART_RE = new RegExp(
|
|
23
|
+
String.raw`^(?:raw|conflicts|${RANGE_LIST_SRC}|-\d+(?:[-+]\d+)?)$`,
|
|
24
|
+
"i",
|
|
25
|
+
);
|
|
26
|
+
// Schemes whose host grammar is identifier-shaped, so any trailing
|
|
27
|
+
// `:<selector-chunk>` is unambiguously a read-tool selector. `mcp://` is
|
|
28
|
+
// excluded because mcp resource URIs may legitimately contain colons.
|
|
29
|
+
const INTERNAL_SCHEMES_WITH_SELECTORS: Record<string, true> = {
|
|
30
|
+
agent: true,
|
|
31
|
+
artifact: true,
|
|
32
|
+
issue: true,
|
|
33
|
+
local: true,
|
|
34
|
+
memory: true,
|
|
35
|
+
omp: true,
|
|
36
|
+
pr: true,
|
|
37
|
+
rule: true,
|
|
38
|
+
skill: true,
|
|
39
|
+
vault: true,
|
|
40
|
+
};
|
|
41
|
+
// Schemes whose resource URIs are server-defined and may legitimately end
|
|
42
|
+
// with selector-shaped tails (e.g. `:raw`, `:conflicts`, `:1-50`, `/:raw`).
|
|
43
|
+
// `McpProtocolHandler` resolves by exact URI match (`r.uri === uri`), so
|
|
44
|
+
// peeling syntactically can make valid resources unreachable. Keep these
|
|
45
|
+
// schemes opaque; selector support for them needs a resolver-aware path that
|
|
46
|
+
// tries the exact URI before interpreting any suffix as a read selector.
|
|
47
|
+
const OPAQUE_RESOURCE_SCHEMES: ReadonlySet<string> = new Set(["mcp"]);
|
|
48
|
+
const INTERNAL_URL_SCHEME_RE = /^([a-z][a-z0-9+.-]*):\/\//i;
|
|
49
|
+
const NARROW_NO_BREAK_SPACE = "\u202F";
|
|
50
|
+
const TOP_LEVEL_INTERNAL_URL_PREFIXES = [
|
|
51
|
+
"agent://",
|
|
52
|
+
"artifact://",
|
|
53
|
+
"skill://",
|
|
54
|
+
"rule://",
|
|
55
|
+
"local://",
|
|
56
|
+
"mcp://",
|
|
57
|
+
"vault://",
|
|
58
|
+
] as const;
|
|
59
|
+
|
|
60
|
+
function normalizeUnicodeSpaces(str: string): string {
|
|
61
|
+
return str.replace(UNICODE_SPACES, " ");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function tryMacOSScreenshotPath(filePath: string): string {
|
|
65
|
+
return filePath.replace(/ (AM|PM)\./g, `${NARROW_NO_BREAK_SPACE}$1.`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function tryNFDVariant(filePath: string): string {
|
|
69
|
+
// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD
|
|
70
|
+
return filePath.normalize("NFD");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function tryCurlyQuoteVariant(filePath: string): string {
|
|
74
|
+
// macOS uses U+2019 (right single quotation mark) in screenshot names like "Capture d'écran"
|
|
75
|
+
// Users typically type U+0027 (straight apostrophe)
|
|
76
|
+
return filePath.replace(/'/g, "\u2019");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function tryShellEscapedPath(filePath: string): string {
|
|
80
|
+
if (!filePath.includes("\\") || !filePath.includes("/")) return filePath;
|
|
81
|
+
return filePath.replace(/\\([ \t"'(){}[\]])/g, "$1");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function fileExists(filePath: string): boolean {
|
|
85
|
+
try {
|
|
86
|
+
fs.accessSync(filePath, fs.constants.F_OK);
|
|
87
|
+
return true;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function normalizeAtPrefix(filePath: string): string {
|
|
94
|
+
if (!filePath.startsWith("@")) return filePath;
|
|
95
|
+
|
|
96
|
+
const withoutAt = filePath.slice(1);
|
|
97
|
+
|
|
98
|
+
// We only treat a leading "@" as a shorthand for a small set of well-known
|
|
99
|
+
// syntaxes. This avoids mangling literal paths like "@my-file.txt".
|
|
100
|
+
if (
|
|
101
|
+
withoutAt.startsWith("/") ||
|
|
102
|
+
withoutAt === "~" ||
|
|
103
|
+
withoutAt.startsWith("~/") ||
|
|
104
|
+
// Windows absolute paths (drive letters / UNC / root-relative)
|
|
105
|
+
path.win32.isAbsolute(withoutAt) ||
|
|
106
|
+
// Internal URL shorthands
|
|
107
|
+
withoutAt.startsWith("agent://") ||
|
|
108
|
+
withoutAt.startsWith("artifact://") ||
|
|
109
|
+
withoutAt.startsWith("skill://") ||
|
|
110
|
+
withoutAt.startsWith("rule://") ||
|
|
111
|
+
withoutAt.startsWith("local:") ||
|
|
112
|
+
withoutAt.startsWith("mcp://")
|
|
113
|
+
) {
|
|
114
|
+
return withoutAt;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return filePath;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function stripFileUrl(filePath: string): string {
|
|
121
|
+
if (!filePath.toLowerCase().startsWith("file://")) return filePath;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
return url.fileURLToPath(filePath);
|
|
125
|
+
} catch {
|
|
126
|
+
return filePath;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function expandTilde(filePath: string, home?: string): string {
|
|
131
|
+
const h = home ?? os.homedir();
|
|
132
|
+
if (filePath === "~") return h;
|
|
133
|
+
if (filePath.startsWith("~/") || filePath.startsWith("~\\")) {
|
|
134
|
+
return h + filePath.slice(1);
|
|
135
|
+
}
|
|
136
|
+
if (filePath.startsWith("~")) {
|
|
137
|
+
return path.join(h, filePath.slice(1));
|
|
138
|
+
}
|
|
139
|
+
return filePath;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function expandPath(filePath: string): string {
|
|
143
|
+
const normalized = stripFileUrl(normalizeUnicodeSpaces(normalizeAtPrefix(filePath)));
|
|
144
|
+
return expandTilde(normalized);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Inclusive line range describing one selector segment (e.g. `50-100`,
|
|
148
|
+
* `301-`, or `50+10`). `endLine` is `undefined` for open-ended ranges.
|
|
149
|
+
*/
|
|
150
|
+
export interface LineRange {
|
|
151
|
+
startLine: number;
|
|
152
|
+
endLine: number | undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const LINE_RANGE_CHUNK_RE = /^L?(\d+)(?:(\.\.|[-+])L?(\d+)?)?$/i;
|
|
156
|
+
|
|
157
|
+
/** Parse a single `N`, `N-M`, `N-`, `N+K`, or `..`-aliased (`N..M`, `N..`) chunk. Throws via {@link ToolError} on invalid bounds. */
|
|
158
|
+
export function parseLineRangeChunk(sel: string): LineRange | null {
|
|
159
|
+
const lineMatch = LINE_RANGE_CHUNK_RE.exec(sel);
|
|
160
|
+
if (!lineMatch) return null;
|
|
161
|
+
const rawStart = Number.parseInt(lineMatch[1]!, 10);
|
|
162
|
+
if (rawStart < 1) {
|
|
163
|
+
throw new ToolError("Line selector 0 is invalid; lines are 1-indexed. Use :1.");
|
|
164
|
+
}
|
|
165
|
+
// `..` is a forgiving alias for `-` (e.g. `2724..2727` == `2724-2727`).
|
|
166
|
+
const sep = lineMatch[2] === ".." ? "-" : lineMatch[2];
|
|
167
|
+
const rhs = lineMatch[3] ? Number.parseInt(lineMatch[3], 10) : undefined;
|
|
168
|
+
let rawEnd: number | undefined;
|
|
169
|
+
if (sep === "+") {
|
|
170
|
+
if (rhs === undefined || rhs < 1) {
|
|
171
|
+
throw new ToolError(`Invalid range ${rawStart}+${rhs ?? 0}: count must be >= 1.`);
|
|
172
|
+
}
|
|
173
|
+
rawEnd = rawStart + rhs - 1;
|
|
174
|
+
} else if (sep === "-") {
|
|
175
|
+
// `301-` is shorthand for "from 301 onward" — equivalent to bare `301`.
|
|
176
|
+
if (rhs !== undefined) {
|
|
177
|
+
if (rhs < rawStart) {
|
|
178
|
+
throw new ToolError(`Invalid range ${rawStart}-${rhs}: end must be >= start.`);
|
|
179
|
+
}
|
|
180
|
+
rawEnd = rhs;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { startLine: rawStart, endLine: rawEnd };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Parse a comma-separated list of line ranges (e.g. `5-16,960-973`). Returns
|
|
188
|
+
* the ranges in ascending order with overlapping/adjacent ranges merged so
|
|
189
|
+
* downstream consumers can stream the file in a single forward pass per range.
|
|
190
|
+
*/
|
|
191
|
+
export function parseLineRanges(sel: string): [LineRange, ...LineRange[]] | null {
|
|
192
|
+
const chunks = sel.split(",");
|
|
193
|
+
const parsed: LineRange[] = [];
|
|
194
|
+
for (const chunk of chunks) {
|
|
195
|
+
const range = parseLineRangeChunk(chunk);
|
|
196
|
+
if (!range) return null;
|
|
197
|
+
parsed.push(range);
|
|
198
|
+
}
|
|
199
|
+
if (parsed.length === 0) return null;
|
|
200
|
+
parsed.sort((a, b) => a.startLine - b.startLine);
|
|
201
|
+
|
|
202
|
+
const merged: LineRange[] = [parsed[0]];
|
|
203
|
+
for (let i = 1; i < parsed.length; i++) {
|
|
204
|
+
const current = parsed[i];
|
|
205
|
+
const last = merged[merged.length - 1];
|
|
206
|
+
// Open-ended (endLine undefined) means "to EOF" — any later range is absorbed.
|
|
207
|
+
if (last.endLine === undefined) continue;
|
|
208
|
+
// Merge when current starts within (or immediately after) the last range.
|
|
209
|
+
if (current.startLine <= last.endLine + 1) {
|
|
210
|
+
if (current.endLine === undefined || current.endLine > last.endLine) {
|
|
211
|
+
merged[merged.length - 1] = { startLine: last.startLine, endLine: current.endLine };
|
|
212
|
+
}
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
merged.push(current);
|
|
216
|
+
}
|
|
217
|
+
return merged as [LineRange, ...LineRange[]];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Extract the line-range component from a read-tool selector that may also
|
|
222
|
+
* carry a verbatim/index display mode (`raw`, `conflicts`) — alone or compounded
|
|
223
|
+
* with a range (`raw:50-100`, `50-100:raw`). Returns the parsed ranges when the
|
|
224
|
+
* selector names any, otherwise `undefined` (pure `raw`/`conflicts`/none).
|
|
225
|
+
*
|
|
226
|
+
* Used by content search, which honors line ranges as a match filter but has no
|
|
227
|
+
* use for verbatim/conflict display modes — so those selectors are accepted and
|
|
228
|
+
* treated as an unfiltered, whole-resource search rather than rejected.
|
|
229
|
+
*/
|
|
230
|
+
export function selectorLineRanges(sel: string | undefined): [LineRange, ...LineRange[]] | undefined {
|
|
231
|
+
if (!sel) return undefined;
|
|
232
|
+
for (const chunk of sel.split(":")) {
|
|
233
|
+
const lower = chunk.toLowerCase();
|
|
234
|
+
if (lower === "raw" || lower === "conflicts") continue;
|
|
235
|
+
const ranges = parseLineRanges(chunk);
|
|
236
|
+
if (ranges) return ranges;
|
|
237
|
+
}
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Return `true` when `lineNumber` (1-indexed) falls in any of the supplied ranges. */
|
|
242
|
+
export function isLineInRanges(lineNumber: number, ranges: readonly LineRange[]): boolean {
|
|
243
|
+
for (const range of ranges) {
|
|
244
|
+
if (lineNumber < range.startLine) continue;
|
|
245
|
+
if (range.endLine === undefined || lineNumber <= range.endLine) return true;
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function splitPathAndSel(rawPath: string): { path: string; sel?: string } {
|
|
251
|
+
const colon = rawPath.lastIndexOf(":");
|
|
252
|
+
if (colon <= 0) return { path: rawPath };
|
|
253
|
+
|
|
254
|
+
const candidate = rawPath.slice(colon + 1);
|
|
255
|
+
if (!FILE_LINE_RANGE_RE.test(candidate)) return { path: rawPath };
|
|
256
|
+
|
|
257
|
+
let basePath = rawPath.slice(0, colon);
|
|
258
|
+
let sel = candidate;
|
|
259
|
+
|
|
260
|
+
// Allow a compound trailing selector: `path:1-50:raw` or `path:raw:1-50`.
|
|
261
|
+
// The two chunks must be one line-range plus one `raw`, in either order.
|
|
262
|
+
const innerColon = basePath.lastIndexOf(":");
|
|
263
|
+
if (innerColon > 0) {
|
|
264
|
+
const innerCandidate = basePath.slice(innerColon + 1);
|
|
265
|
+
const innerIsRaw = FILE_RAW_ONLY_RE.test(innerCandidate);
|
|
266
|
+
const outerIsRaw = FILE_RAW_ONLY_RE.test(candidate);
|
|
267
|
+
const innerIsRange = FILE_LINE_RANGE_ONLY_RE.test(innerCandidate);
|
|
268
|
+
const outerIsRange = FILE_LINE_RANGE_ONLY_RE.test(candidate);
|
|
269
|
+
if ((innerIsRaw && outerIsRange) || (innerIsRange && outerIsRaw)) {
|
|
270
|
+
sel = `${innerCandidate}:${candidate}`;
|
|
271
|
+
basePath = basePath.slice(0, innerColon);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return { path: basePath, sel };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Variant of {@link splitPathAndSel} for internal URLs (`scheme://...`).
|
|
280
|
+
*
|
|
281
|
+
* The filesystem-path splitter is intentionally conservative: it refuses to
|
|
282
|
+
* peel a trailing `:<chunk>` unless that chunk matches the strict selector
|
|
283
|
+
* grammar. That rule is right for filesystem paths (a file named `a:1-50` is
|
|
284
|
+
* legal) but wrong for internal URLs, where any trailing `:<chunk>` after the
|
|
285
|
+
* scheme is unambiguously a read-tool selector — even if malformed (e.g.
|
|
286
|
+
* `artifact://3:raw:-100`).
|
|
287
|
+
*
|
|
288
|
+
* This function iteratively peels selector-shaped chunks (well-formed plus
|
|
289
|
+
* common malformed shapes like `:-N`) so the rest of the read tool can pass a
|
|
290
|
+
* clean URL to the protocol handler and surface selector errors via parseSel
|
|
291
|
+
* instead of as misleading "host invalid" errors from the handler. Schemes
|
|
292
|
+
* whose resource URIs may legitimately contain colons (`mcp://`) are skipped.
|
|
293
|
+
*
|
|
294
|
+
* Falls back to the input unchanged when nothing matches.
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
export function splitInternalUrlSel(rawPath: string): { path: string; sel?: string } {
|
|
298
|
+
const schemeMatch = rawPath.match(INTERNAL_URL_SCHEME_RE);
|
|
299
|
+
if (!schemeMatch) return { path: rawPath };
|
|
300
|
+
const scheme = schemeMatch[1].toLowerCase();
|
|
301
|
+
// Opaque schemes (mcp://, etc.) carry server-defined resource URIs that may
|
|
302
|
+
// legitimately end in selector-shaped tails. Forward verbatim — see
|
|
303
|
+
// OPAQUE_RESOURCE_SCHEMES.
|
|
304
|
+
if (OPAQUE_RESOURCE_SCHEMES.has(scheme)) return { path: rawPath };
|
|
305
|
+
if (!INTERNAL_SCHEMES_WITH_SELECTORS[scheme]) return { path: rawPath };
|
|
306
|
+
|
|
307
|
+
const schemeEnd = schemeMatch[0].length;
|
|
308
|
+
let path = rawPath;
|
|
309
|
+
const chunks: string[] = [];
|
|
310
|
+
while (true) {
|
|
311
|
+
const colon = path.lastIndexOf(":");
|
|
312
|
+
// Stop before crossing into the scheme separator `://`.
|
|
313
|
+
if (colon < schemeEnd) break;
|
|
314
|
+
const tail = path.slice(colon + 1);
|
|
315
|
+
if (!INTERNAL_URL_SELECTOR_PART_RE.test(tail)) break;
|
|
316
|
+
chunks.unshift(tail);
|
|
317
|
+
path = path.slice(0, colon);
|
|
318
|
+
}
|
|
319
|
+
if (chunks.length === 0) return { path: rawPath };
|
|
320
|
+
return { path, sel: chunks.join(":") };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function assertNotInternalUrl(expanded: string, original: string): void {
|
|
324
|
+
for (const prefix of TOP_LEVEL_INTERNAL_URL_PREFIXES) {
|
|
325
|
+
if (expanded.startsWith(prefix)) {
|
|
326
|
+
throw new Error(
|
|
327
|
+
`Path "${original}" uses internal scheme "${prefix}" and must be resolved through the proper protocol handler, not as a filesystem path.`,
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function normalizeLocalScheme(filePath: string): string {
|
|
334
|
+
return filePath.replace(/^(local:)\/(?!\/)/, "$1//");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function isInternalUrlPath(filePath: string): boolean {
|
|
338
|
+
const normalized = normalizeLocalScheme(filePath);
|
|
339
|
+
const expandedAndNormalized = normalizeLocalScheme(expandPath(normalized));
|
|
340
|
+
for (const prefix of TOP_LEVEL_INTERNAL_URL_PREFIXES) {
|
|
341
|
+
if (expandedAndNormalized.startsWith(prefix)) return true;
|
|
342
|
+
}
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Resolve a path relative to the given cwd.
|
|
348
|
+
* Handles ~ expansion and absolute paths.
|
|
349
|
+
*
|
|
350
|
+
* A bare root slash is treated as a workspace-root alias for tool inputs. Users
|
|
351
|
+
* often pass `/` to mean “search from here”, and letting tools escape to the
|
|
352
|
+
* filesystem root is almost never what they intended.
|
|
353
|
+
*/
|
|
354
|
+
export function resolveToCwd(filePath: string, cwd: string): string {
|
|
355
|
+
const normalized = normalizeLocalScheme(filePath);
|
|
356
|
+
const expanded = expandPath(normalized);
|
|
357
|
+
const expandedAndNormalized = normalizeLocalScheme(expanded);
|
|
358
|
+
|
|
359
|
+
assertNotInternalUrl(expandedAndNormalized, normalized);
|
|
360
|
+
|
|
361
|
+
if (/^\/+$/.test(expanded)) {
|
|
362
|
+
return cwd;
|
|
363
|
+
}
|
|
364
|
+
if (path.isAbsolute(expanded)) {
|
|
365
|
+
return expanded;
|
|
366
|
+
}
|
|
367
|
+
return path.resolve(cwd, expanded);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function formatPathRelativeToCwd(
|
|
371
|
+
filePath: string,
|
|
372
|
+
cwd: string,
|
|
373
|
+
options: { trailingSlash?: boolean } = {},
|
|
374
|
+
): string {
|
|
375
|
+
const resolvedCwd = path.resolve(cwd);
|
|
376
|
+
const normalized = normalizeLocalScheme(filePath);
|
|
377
|
+
if (isInternalUrlPath(normalized)) {
|
|
378
|
+
return normalized;
|
|
379
|
+
}
|
|
380
|
+
const expanded = expandPath(normalized);
|
|
381
|
+
const resolvedPath = path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(cwd, expanded);
|
|
382
|
+
const relative = path.relative(resolvedCwd, resolvedPath);
|
|
383
|
+
const isWithinCwd = relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
384
|
+
let displayPath = normalizePosixPath(isWithinCwd ? relative || "." : resolvedPath);
|
|
385
|
+
if (options.trailingSlash && displayPath !== "." && !displayPath.endsWith("/")) {
|
|
386
|
+
displayPath += "/";
|
|
387
|
+
}
|
|
388
|
+
return displayPath;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Strip matching surrounding double quotes from a path string.
|
|
393
|
+
* Common when users paste quoted paths from Windows Explorer or shell copy-paste.
|
|
394
|
+
* Only double quotes — single quotes are valid POSIX filename characters.
|
|
395
|
+
* Tradeoff: a POSIX path literally starting AND ending with " would also be unquoted.
|
|
396
|
+
* Accepted because such names are virtually nonexistent in practice.
|
|
397
|
+
*/
|
|
398
|
+
export function stripOuterDoubleQuotes(input: string): string {
|
|
399
|
+
return input.startsWith('"') && input.endsWith('"') && input.length > 1 ? input.slice(1, -1) : input;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function normalizePathLikeInput(input: string): string {
|
|
403
|
+
return stripOuterDoubleQuotes(input.trim());
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const GLOB_PATH_CHARS = ["*", "?", "[", "{"] as const;
|
|
407
|
+
|
|
408
|
+
export function hasGlobPathChars(filePath: string): boolean {
|
|
409
|
+
return GLOB_PATH_CHARS.some(char => filePath.includes(char));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
type PathEntrySplitter = (item: string) => { basePath: string };
|
|
413
|
+
|
|
414
|
+
const TOP_LEVEL_WHITESPACE_RE = /\s/;
|
|
415
|
+
|
|
416
|
+
type DelimitedPathSplitMode = "comma" | "semicolon" | "whitespace" | "mixed";
|
|
417
|
+
|
|
418
|
+
function isDelimitedPathSeparator(ch: string, mode: DelimitedPathSplitMode): boolean {
|
|
419
|
+
if (mode === "comma") return ch === ",";
|
|
420
|
+
if (mode === "semicolon") return ch === ";";
|
|
421
|
+
if (mode === "whitespace") return TOP_LEVEL_WHITESPACE_RE.test(ch);
|
|
422
|
+
return ch === "," || ch === ";" || TOP_LEVEL_WHITESPACE_RE.test(ch);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function hasTopLevelPathDelimiter(entry: string): boolean {
|
|
426
|
+
let braceDepth = 0;
|
|
427
|
+
for (let i = 0; i < entry.length; i++) {
|
|
428
|
+
const ch = entry[i];
|
|
429
|
+
if (ch === "\\" && i + 1 < entry.length) {
|
|
430
|
+
i++;
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (ch === "{") {
|
|
434
|
+
braceDepth++;
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if (ch === "}") {
|
|
438
|
+
if (braceDepth > 0) braceDepth--;
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (braceDepth === 0 && (ch === "," || ch === ";" || TOP_LEVEL_WHITESPACE_RE.test(ch))) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function splitTopLevelDelimitedPath(entry: string, mode: DelimitedPathSplitMode): string[] {
|
|
449
|
+
const parts: string[] = [];
|
|
450
|
+
let braceDepth = 0;
|
|
451
|
+
let start = 0;
|
|
452
|
+
for (let i = 0; i < entry.length; i++) {
|
|
453
|
+
const ch = entry[i];
|
|
454
|
+
if (ch === "\\" && i + 1 < entry.length) {
|
|
455
|
+
i++;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (ch === "{") {
|
|
459
|
+
braceDepth++;
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
if (ch === "}") {
|
|
463
|
+
if (braceDepth > 0) braceDepth--;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (braceDepth !== 0 || !isDelimitedPathSeparator(ch, mode)) continue;
|
|
467
|
+
parts.push(entry.slice(start, i));
|
|
468
|
+
start = i + 1;
|
|
469
|
+
}
|
|
470
|
+
parts.push(entry.slice(start));
|
|
471
|
+
return parts;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function delimitedPathPartResolves(entry: string, cwd: string, splitter: PathEntrySplitter): Promise<boolean> {
|
|
475
|
+
if (isInternalUrlPath(entry)) return true;
|
|
476
|
+
const peeled = splitPathAndSel(entry).path;
|
|
477
|
+
const { basePath } = splitter(peeled);
|
|
478
|
+
const absoluteBasePath = resolveToCwd(basePath, cwd);
|
|
479
|
+
try {
|
|
480
|
+
await fs.promises.stat(absoluteBasePath);
|
|
481
|
+
return true;
|
|
482
|
+
} catch (err) {
|
|
483
|
+
if (isEnoent(err)) return false;
|
|
484
|
+
throw err;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async function tryDelimitedPathSplit(
|
|
489
|
+
entry: string,
|
|
490
|
+
cwd: string,
|
|
491
|
+
splitter: PathEntrySplitter,
|
|
492
|
+
mode: DelimitedPathSplitMode,
|
|
493
|
+
requireAllParts: boolean,
|
|
494
|
+
): Promise<string[] | null> {
|
|
495
|
+
const rawParts = splitTopLevelDelimitedPath(entry, mode);
|
|
496
|
+
if (rawParts.length < 2) return null;
|
|
497
|
+
|
|
498
|
+
const parts = rawParts.map(normalizePathLikeInput).filter(part => part.length > 0);
|
|
499
|
+
if (parts.length === 0) return null;
|
|
500
|
+
if (parts.length < 2 && rawParts.length === parts.length) return null;
|
|
501
|
+
|
|
502
|
+
const resolved = await Promise.all(parts.map(part => delimitedPathPartResolves(part, cwd, splitter)));
|
|
503
|
+
const valid = requireAllParts ? resolved.every(Boolean) : resolved.some(Boolean);
|
|
504
|
+
return valid ? parts : null;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Split one path-like entry whose multiple targets were flattened into one
|
|
509
|
+
* string. Existing paths are kept intact, so real filenames containing spaces,
|
|
510
|
+
* commas, or semicolons win over delimiter recovery.
|
|
511
|
+
*/
|
|
512
|
+
export async function splitDelimitedPathEntry(
|
|
513
|
+
entry: string,
|
|
514
|
+
cwd: string,
|
|
515
|
+
options: { splitter?: PathEntrySplitter } = {},
|
|
516
|
+
): Promise<string[] | null> {
|
|
517
|
+
const normalizedEntry = normalizePathLikeInput(entry);
|
|
518
|
+
if (!hasTopLevelPathDelimiter(normalizedEntry)) return null;
|
|
519
|
+
if (isInternalUrlPath(normalizedEntry)) return null;
|
|
520
|
+
|
|
521
|
+
const splitter = options.splitter ?? parseSearchPath;
|
|
522
|
+
const peeledEntry = splitPathAndSel(normalizedEntry).path;
|
|
523
|
+
if (!hasGlobPathChars(peeledEntry) && (await delimitedPathPartResolves(normalizedEntry, cwd, splitter))) {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return (
|
|
528
|
+
(await tryDelimitedPathSplit(normalizedEntry, cwd, splitter, "comma", false)) ??
|
|
529
|
+
(await tryDelimitedPathSplit(normalizedEntry, cwd, splitter, "semicolon", false)) ??
|
|
530
|
+
(await tryDelimitedPathSplit(normalizedEntry, cwd, splitter, "whitespace", true)) ??
|
|
531
|
+
(await tryDelimitedPathSplit(normalizedEntry, cwd, splitter, "mixed", true))
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/** Expand delimited entries in-place while preserving unsplit entries. */
|
|
536
|
+
export async function expandDelimitedPathEntries(
|
|
537
|
+
entries: readonly string[],
|
|
538
|
+
cwd: string,
|
|
539
|
+
options: { splitter?: PathEntrySplitter } = {},
|
|
540
|
+
): Promise<string[]> {
|
|
541
|
+
const expanded: string[] = [];
|
|
542
|
+
for (const entry of entries) {
|
|
543
|
+
const normalizedEntry = normalizePathLikeInput(entry);
|
|
544
|
+
const split = await splitDelimitedPathEntry(normalizedEntry, cwd, options);
|
|
545
|
+
if (split) expanded.push(...split);
|
|
546
|
+
else expanded.push(normalizedEntry);
|
|
547
|
+
}
|
|
548
|
+
return expanded;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export interface ParsedSearchPath {
|
|
552
|
+
basePath: string;
|
|
553
|
+
glob?: string;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export interface ParsedFindPattern {
|
|
557
|
+
basePath: string;
|
|
558
|
+
globPattern: string;
|
|
559
|
+
hasGlob: boolean;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export interface ResolvedSearchTarget {
|
|
563
|
+
basePath: string;
|
|
564
|
+
glob?: string;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export interface ResolvedMultiSearchPath {
|
|
568
|
+
basePath: string;
|
|
569
|
+
glob?: string;
|
|
570
|
+
scopePath: string;
|
|
571
|
+
exactFilePaths?: string[];
|
|
572
|
+
targets?: ResolvedSearchTarget[];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export interface ResolvedFindTarget {
|
|
576
|
+
basePath: string;
|
|
577
|
+
globPattern: string;
|
|
578
|
+
hasGlob: boolean;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
export interface ResolvedMultiFindPattern {
|
|
582
|
+
targets: ResolvedFindTarget[];
|
|
583
|
+
scopePath: string;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Split a user path into a base path + glob pattern for tools that delegate to
|
|
588
|
+
* APIs accepting separate `path` and `glob` arguments.
|
|
589
|
+
*/
|
|
590
|
+
export function parseSearchPath(filePath: string): ParsedSearchPath {
|
|
591
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
592
|
+
if (!hasGlobPathChars(normalizedPath)) {
|
|
593
|
+
return { basePath: filePath };
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const segments = normalizedPath.split("/");
|
|
597
|
+
const firstGlobIndex = segments.findIndex(segment => hasGlobPathChars(segment));
|
|
598
|
+
|
|
599
|
+
if (firstGlobIndex <= 0) {
|
|
600
|
+
return { basePath: ".", glob: normalizedPath };
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return {
|
|
604
|
+
basePath: segments.slice(0, firstGlobIndex).join("/"),
|
|
605
|
+
glob: segments.slice(firstGlobIndex).join("/"),
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Async sibling of {@link parseSearchPath} that prefers literal interpretation
|
|
611
|
+
* when a path containing glob metacharacters resolves to an existing entry on
|
|
612
|
+
* disk. Disambiguates Next.js/SvelteKit routes like `apps/[id]/page.tsx` —
|
|
613
|
+
* without this, `[id]` is parsed as a glob character class and silently
|
|
614
|
+
* matches nothing.
|
|
615
|
+
*/
|
|
616
|
+
export async function parseSearchPathPreferringLiteral(filePath: string, cwd: string): Promise<ParsedSearchPath> {
|
|
617
|
+
if (!hasGlobPathChars(filePath) || isInternalUrlPath(filePath)) return parseSearchPath(filePath);
|
|
618
|
+
try {
|
|
619
|
+
await fs.promises.stat(resolveToCwd(filePath, cwd));
|
|
620
|
+
return { basePath: filePath };
|
|
621
|
+
} catch {
|
|
622
|
+
return parseSearchPath(filePath);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Parse a find pattern into a base directory path and a glob pattern.
|
|
627
|
+
// Examples:
|
|
628
|
+
// src/app/**/\*.tsx -> { basePath: "src/app", globPattern: "**/*.tsx", hasGlob: true }
|
|
629
|
+
// src/app/\*.tsx -> { basePath: "src/app", globPattern: "*.tsx", hasGlob: true }
|
|
630
|
+
// \*.ts -> { basePath: ".", globPattern: "**/*.ts", hasGlob: true }
|
|
631
|
+
// **/\*.json -> { basePath: ".", globPattern: "**/*.json", hasGlob: true }
|
|
632
|
+
// /abs/path/**/\*.ts -> { basePath: "/abs/path", globPattern: "**/*.ts", hasGlob: true }
|
|
633
|
+
// src/app -> { basePath: "src/app", globPattern: "**/*", hasGlob: false }
|
|
634
|
+
export function parseFindPattern(pattern: string): ParsedFindPattern {
|
|
635
|
+
const segments = pattern.split("/");
|
|
636
|
+
let firstGlobIndex = -1;
|
|
637
|
+
for (let i = 0; i < segments.length; i++) {
|
|
638
|
+
if (hasGlobPathChars(segments[i])) {
|
|
639
|
+
firstGlobIndex = i;
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (firstGlobIndex === -1) {
|
|
645
|
+
return { basePath: pattern, globPattern: "**/*", hasGlob: false };
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (firstGlobIndex === 0) {
|
|
649
|
+
const needsRecursive = !pattern.startsWith("**/");
|
|
650
|
+
return {
|
|
651
|
+
basePath: ".",
|
|
652
|
+
globPattern: needsRecursive ? `**/${pattern}` : pattern,
|
|
653
|
+
hasGlob: true,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return {
|
|
658
|
+
basePath: segments.slice(0, firstGlobIndex).join("/"),
|
|
659
|
+
globPattern: segments.slice(firstGlobIndex).join("/"),
|
|
660
|
+
hasGlob: true,
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export function combineSearchGlobs(prefixGlob?: string, suffixGlob?: string): string | undefined {
|
|
665
|
+
if (!prefixGlob) return suffixGlob;
|
|
666
|
+
if (!suffixGlob) return prefixGlob;
|
|
667
|
+
|
|
668
|
+
const normalizedPrefix = prefixGlob.replace(/\/+$/, "");
|
|
669
|
+
const normalizedSuffix = suffixGlob.replace(/^\/+/, "");
|
|
670
|
+
|
|
671
|
+
return `${normalizedPrefix}/${normalizedSuffix}`;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function normalizePosixPath(filePath: string): string {
|
|
675
|
+
return filePath.replace(/\\/g, "/");
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function joinRelativeGlob(basePath: string | undefined, globPattern: string): string {
|
|
679
|
+
if (!basePath || basePath === ".") return normalizePosixPath(globPattern).replace(/^\/+/, "");
|
|
680
|
+
const normalizedBase = normalizePosixPath(basePath).replace(/\/+$/, "");
|
|
681
|
+
const normalizedGlob = normalizePosixPath(globPattern).replace(/^\/+/, "");
|
|
682
|
+
return `${normalizedBase}/${normalizedGlob}`;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function buildBraceUnion(patterns: string[]): string | undefined {
|
|
686
|
+
const uniquePatterns = [...new Set(patterns.map(pattern => normalizePosixPath(pattern).trim()).filter(Boolean))];
|
|
687
|
+
if (uniquePatterns.length === 0) return undefined;
|
|
688
|
+
if (uniquePatterns.length === 1) return uniquePatterns[0];
|
|
689
|
+
return `{${uniquePatterns.join(",")}}`;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function findCommonBasePath(paths: string[]): string {
|
|
693
|
+
if (paths.length === 0) return ".";
|
|
694
|
+
let commonParts = path.resolve(paths[0]).split(path.sep);
|
|
695
|
+
for (const candidatePath of paths.slice(1)) {
|
|
696
|
+
const candidateParts = path.resolve(candidatePath).split(path.sep);
|
|
697
|
+
let sharedCount = 0;
|
|
698
|
+
const maxShared = Math.min(commonParts.length, candidateParts.length);
|
|
699
|
+
while (sharedCount < maxShared && commonParts[sharedCount] === candidateParts[sharedCount]) {
|
|
700
|
+
sharedCount += 1;
|
|
701
|
+
}
|
|
702
|
+
commonParts = commonParts.slice(0, sharedCount);
|
|
703
|
+
}
|
|
704
|
+
if (commonParts.length === 0) {
|
|
705
|
+
return path.parse(path.resolve(paths[0])).root;
|
|
706
|
+
}
|
|
707
|
+
const joined = commonParts.join(path.sep);
|
|
708
|
+
return joined || path.parse(path.resolve(paths[0])).root;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function toScopeDisplay(items: string[], cwd: string): string {
|
|
712
|
+
return items
|
|
713
|
+
.map(item =>
|
|
714
|
+
formatPathRelativeToCwd(item, cwd, {
|
|
715
|
+
trailingSlash: item.endsWith("/") || item.endsWith("\\"),
|
|
716
|
+
}),
|
|
717
|
+
)
|
|
718
|
+
.join(", ");
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
async function resolveSearchPathItems(
|
|
722
|
+
pathItems: string[],
|
|
723
|
+
cwd: string,
|
|
724
|
+
suffixGlob?: string,
|
|
725
|
+
): Promise<ResolvedMultiSearchPath | undefined> {
|
|
726
|
+
if (pathItems.length < 1) {
|
|
727
|
+
return undefined;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const parsedItems = await Promise.all(
|
|
731
|
+
pathItems.map(async item => {
|
|
732
|
+
const parsedPath = await parseSearchPathPreferringLiteral(item, cwd);
|
|
733
|
+
const absoluteBasePath = resolveToCwd(parsedPath.basePath, cwd);
|
|
734
|
+
const stat = await fs.promises.stat(absoluteBasePath);
|
|
735
|
+
return { raw: item, parsedPath, absoluteBasePath, stat };
|
|
736
|
+
}),
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
const allExactFiles = !suffixGlob && parsedItems.every(item => !item.parsedPath.glob && item.stat.isFile());
|
|
740
|
+
const commonBasePath = findCommonBasePath(parsedItems.map(item => item.absoluteBasePath));
|
|
741
|
+
const combinedPatterns = parsedItems.map(item => {
|
|
742
|
+
const relativeBasePath = normalizePosixPath(path.relative(commonBasePath, item.absoluteBasePath)) || ".";
|
|
743
|
+
if (item.parsedPath.glob) {
|
|
744
|
+
const pathGlob = joinRelativeGlob(relativeBasePath, item.parsedPath.glob);
|
|
745
|
+
return combineSearchGlobs(pathGlob, suffixGlob) ?? pathGlob;
|
|
746
|
+
}
|
|
747
|
+
if (suffixGlob) {
|
|
748
|
+
const pathPrefix = relativeBasePath === "." ? undefined : relativeBasePath;
|
|
749
|
+
return combineSearchGlobs(pathPrefix, suffixGlob) ?? suffixGlob;
|
|
750
|
+
}
|
|
751
|
+
if (item.stat.isDirectory()) {
|
|
752
|
+
return joinRelativeGlob(relativeBasePath, "**/*");
|
|
753
|
+
}
|
|
754
|
+
return relativeBasePath === "." ? path.basename(item.absoluteBasePath) : relativeBasePath;
|
|
755
|
+
});
|
|
756
|
+
const rootPath = path.parse(commonBasePath).root;
|
|
757
|
+
const isDegenerateRoot = commonBasePath === rootPath && parsedItems.length > 1;
|
|
758
|
+
const targets = isDegenerateRoot
|
|
759
|
+
? parsedItems.map(item => ({
|
|
760
|
+
basePath: item.absoluteBasePath,
|
|
761
|
+
glob: item.parsedPath.glob ? combineSearchGlobs(item.parsedPath.glob, suffixGlob) : suffixGlob,
|
|
762
|
+
}))
|
|
763
|
+
: undefined;
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
basePath: commonBasePath,
|
|
767
|
+
glob: buildBraceUnion(combinedPatterns),
|
|
768
|
+
scopePath: toScopeDisplay(pathItems, cwd),
|
|
769
|
+
exactFilePaths: allExactFiles ? parsedItems.map(item => item.absoluteBasePath) : undefined,
|
|
770
|
+
targets,
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export async function resolveExplicitSearchPaths(
|
|
775
|
+
pathItems: string[],
|
|
776
|
+
cwd: string,
|
|
777
|
+
suffixGlob?: string,
|
|
778
|
+
): Promise<ResolvedMultiSearchPath | undefined> {
|
|
779
|
+
return resolveSearchPathItems([...new Set(pathItems)], cwd, suffixGlob);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
async function resolveFindPatternItems(
|
|
783
|
+
patternItems: string[],
|
|
784
|
+
cwd: string,
|
|
785
|
+
): Promise<ResolvedMultiFindPattern | undefined> {
|
|
786
|
+
if (patternItems.length <= 1) {
|
|
787
|
+
return undefined;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Each path becomes its own walk root. Collapsing to a shared common ancestor
|
|
791
|
+
// (and filtering with a brace-union glob) would force the walker to traverse
|
|
792
|
+
// and stat every unrelated sibling under that ancestor — two paths under
|
|
793
|
+
// $HOME would scan all of $HOME. The find tool fans these targets out in
|
|
794
|
+
// parallel instead, so every scan stays bounded to exactly one requested path.
|
|
795
|
+
const targets = patternItems.map(item => {
|
|
796
|
+
const parsedPattern = parseFindPattern(item);
|
|
797
|
+
return {
|
|
798
|
+
basePath: resolveToCwd(parsedPattern.basePath, cwd),
|
|
799
|
+
globPattern: parsedPattern.globPattern,
|
|
800
|
+
hasGlob: parsedPattern.hasGlob,
|
|
801
|
+
};
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
return {
|
|
805
|
+
targets,
|
|
806
|
+
scopePath: toScopeDisplay(patternItems, cwd),
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
export async function resolveExplicitFindPatterns(
|
|
811
|
+
patternItems: string[],
|
|
812
|
+
cwd: string,
|
|
813
|
+
): Promise<ResolvedMultiFindPattern | undefined> {
|
|
814
|
+
return resolveFindPatternItems([...new Set(patternItems)], cwd);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Result of partitioning a list of user-supplied paths/globs into entries whose
|
|
819
|
+
* base directory currently exists on disk versus those that do not.
|
|
820
|
+
*
|
|
821
|
+
* Used by multi-path tools (search, find, ast_grep, ast_edit) to tolerate one
|
|
822
|
+
* or more missing entries in a multi-path call: the surviving entries should
|
|
823
|
+
* still be searched, with the missing entries surfaced as a non-fatal warning.
|
|
824
|
+
*/
|
|
825
|
+
export interface PartitionedPaths {
|
|
826
|
+
/** Raw input strings whose resolved base path exists. */
|
|
827
|
+
valid: string[];
|
|
828
|
+
/** Raw input strings whose resolved base path is missing (ENOENT). */
|
|
829
|
+
missing: string[];
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Stat each input's base path concurrently; return entries split by existence.
|
|
834
|
+
*
|
|
835
|
+
* `splitter` is expected to be {@link parseFindPattern} or
|
|
836
|
+
* {@link parseSearchPath}: both return a `basePath` field that this helper
|
|
837
|
+
* resolves against `cwd` and stats. ENOENT is the only swallowed error — every
|
|
838
|
+
* other stat failure (permission, IO, etc.) propagates so callers do not silently
|
|
839
|
+
* skip paths that exist but are unreadable.
|
|
840
|
+
*
|
|
841
|
+
* Order of `valid` and `missing` follows the input order, so callers can rely
|
|
842
|
+
* on `valid[0]` matching the first surviving user-supplied entry.
|
|
843
|
+
*/
|
|
844
|
+
export async function partitionExistingPaths(
|
|
845
|
+
items: string[],
|
|
846
|
+
cwd: string,
|
|
847
|
+
splitter: (item: string) => { basePath: string },
|
|
848
|
+
): Promise<PartitionedPaths> {
|
|
849
|
+
const settled = await Promise.all(
|
|
850
|
+
items.map(async item => {
|
|
851
|
+
const { basePath } = splitter(item);
|
|
852
|
+
const absoluteBasePath = resolveToCwd(basePath, cwd);
|
|
853
|
+
try {
|
|
854
|
+
await fs.promises.stat(absoluteBasePath);
|
|
855
|
+
return { item, exists: true } as const;
|
|
856
|
+
} catch (err) {
|
|
857
|
+
if (isEnoent(err)) return { item, exists: false } as const;
|
|
858
|
+
throw err;
|
|
859
|
+
}
|
|
860
|
+
}),
|
|
861
|
+
);
|
|
862
|
+
const valid: string[] = [];
|
|
863
|
+
const missing: string[] = [];
|
|
864
|
+
for (const entry of settled) {
|
|
865
|
+
if (entry.exists) valid.push(entry.item);
|
|
866
|
+
else missing.push(entry.item);
|
|
867
|
+
}
|
|
868
|
+
return { valid, missing };
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
export function resolveReadPath(filePath: string, cwd: string): string {
|
|
872
|
+
const resolved = resolveToCwd(filePath, cwd);
|
|
873
|
+
const shellEscapedVariant = tryShellEscapedPath(resolved);
|
|
874
|
+
const baseCandidates = shellEscapedVariant !== resolved ? [resolved, shellEscapedVariant] : [resolved];
|
|
875
|
+
|
|
876
|
+
for (const baseCandidate of baseCandidates) {
|
|
877
|
+
if (fileExists(baseCandidate)) {
|
|
878
|
+
return baseCandidate;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
for (const baseCandidate of baseCandidates) {
|
|
883
|
+
// Try macOS AM/PM variant (narrow no-break space before AM/PM)
|
|
884
|
+
const amPmVariant = tryMacOSScreenshotPath(baseCandidate);
|
|
885
|
+
if (amPmVariant !== baseCandidate && fileExists(amPmVariant)) {
|
|
886
|
+
return amPmVariant;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// Try NFD variant (macOS stores filenames in NFD form)
|
|
890
|
+
const nfdVariant = tryNFDVariant(baseCandidate);
|
|
891
|
+
if (nfdVariant !== baseCandidate && fileExists(nfdVariant)) {
|
|
892
|
+
return nfdVariant;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Try curly quote variant (macOS uses U+2019 in screenshot names)
|
|
896
|
+
const curlyVariant = tryCurlyQuoteVariant(baseCandidate);
|
|
897
|
+
if (curlyVariant !== baseCandidate && fileExists(curlyVariant)) {
|
|
898
|
+
return curlyVariant;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// Try combined NFD + curly quote (for French macOS screenshots like "Capture d'écran")
|
|
902
|
+
const nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);
|
|
903
|
+
if (nfdCurlyVariant !== baseCandidate && fileExists(nfdCurlyVariant)) {
|
|
904
|
+
return nfdCurlyVariant;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
return resolved;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// =============================================================================
|
|
912
|
+
// Tool-scope resolution (search/ast tools)
|
|
913
|
+
// =============================================================================
|
|
914
|
+
|
|
915
|
+
export interface ToolScopeOptions {
|
|
916
|
+
rawPaths: string[];
|
|
917
|
+
cwd: string;
|
|
918
|
+
/** Verb used in the "Cannot {action} internal URL without a backing file: …" message. */
|
|
919
|
+
internalUrlAction: string;
|
|
920
|
+
/** Collect absolute paths flagged immutable by their internal-URL handler. */
|
|
921
|
+
trackImmutableSources?: boolean;
|
|
922
|
+
/** Honor `exactFilePaths` from {@link resolveExplicitSearchPaths} (search-only). */
|
|
923
|
+
surfaceExactFilePaths?: boolean;
|
|
924
|
+
/** Extra hint appended to "Path not found" when stat fails and the user supplied multiple paths. */
|
|
925
|
+
multipathStatHint?: string;
|
|
926
|
+
/** Calling session's settings — forwarded to the internal-URL router so caller-aware handlers (issue://, pr://) honor it. */
|
|
927
|
+
settings?: unknown;
|
|
928
|
+
/** Caller's abort signal — forwarded to the internal-URL router. */
|
|
929
|
+
signal?: AbortSignal;
|
|
930
|
+
/** Calling session's `local://` root mapping — pins resolutions to the calling session. */
|
|
931
|
+
localProtocolOptions?: LocalProtocolOptions;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
export interface ToolScopeResolution {
|
|
935
|
+
searchPath: string;
|
|
936
|
+
scopePath: string;
|
|
937
|
+
globFilter: string | undefined;
|
|
938
|
+
isDirectory: boolean;
|
|
939
|
+
multiTargets?: ResolvedSearchTarget[];
|
|
940
|
+
exactFilePaths?: string[];
|
|
941
|
+
missingPaths: string[];
|
|
942
|
+
immutableSourcePaths: Set<string>;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Shared path-input pipeline for `search`, `ast_grep`, and `ast_edit`:
|
|
947
|
+
* 1. normalize + reject empty paths,
|
|
948
|
+
* 2. resolve internal URLs through {@link InternalUrlRouter} to backing files,
|
|
949
|
+
* 3. partition existing vs missing when multiple paths are supplied,
|
|
950
|
+
* 4. derive a single search base path / glob, or a multi-target list,
|
|
951
|
+
* 5. stat the resolved base path so callers can branch on directory vs file scope.
|
|
952
|
+
*/
|
|
953
|
+
export async function resolveToolSearchScope(opts: ToolScopeOptions): Promise<ToolScopeResolution> {
|
|
954
|
+
const { rawPaths: inputs, cwd, internalUrlAction } = opts;
|
|
955
|
+
const normalizedRawPaths = inputs.map(normalizePathLikeInput);
|
|
956
|
+
if (normalizedRawPaths.some(rawPath => rawPath.length === 0)) {
|
|
957
|
+
throw new ToolError("`paths` must contain non-empty paths or globs");
|
|
958
|
+
}
|
|
959
|
+
const rawPaths = await expandDelimitedPathEntries(normalizedRawPaths, cwd);
|
|
960
|
+
if (rawPaths.some(rawPath => rawPath.length === 0)) {
|
|
961
|
+
throw new ToolError("`paths` must contain non-empty paths or globs");
|
|
962
|
+
}
|
|
963
|
+
// External (http/https/ftp/file) URLs are not searchable; route the caller
|
|
964
|
+
// to `read` instead of letting the path-resolver surface a confusing
|
|
965
|
+
// "Path not found" for a slash-stripped URL.
|
|
966
|
+
const externalUrl = rawPaths.find(rawPath => /^(?:https?|ftp|file|ws|wss):\/\//i.test(rawPath));
|
|
967
|
+
if (externalUrl) {
|
|
968
|
+
throw new ToolError(
|
|
969
|
+
`Cannot ${internalUrlAction} external URL: ${externalUrl}. Use \`read\` to fetch web content, then search the returned text.`,
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
const internalRouter = InternalUrlRouter.instance();
|
|
973
|
+
const resolvedPathInputs: string[] = [];
|
|
974
|
+
const immutableSourcePaths = new Set<string>();
|
|
975
|
+
for (const rawPath of rawPaths) {
|
|
976
|
+
if (!internalRouter.canHandle(rawPath)) {
|
|
977
|
+
resolvedPathInputs.push(rawPath);
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
if (hasGlobPathChars(rawPath)) {
|
|
981
|
+
throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPath}`);
|
|
982
|
+
}
|
|
983
|
+
const resource = await internalRouter.resolve(rawPath, {
|
|
984
|
+
cwd,
|
|
985
|
+
settings: opts.settings,
|
|
986
|
+
signal: opts.signal,
|
|
987
|
+
localProtocolOptions: opts.localProtocolOptions,
|
|
988
|
+
});
|
|
989
|
+
if (!resource.sourcePath) {
|
|
990
|
+
throw new ToolError(`Cannot ${internalUrlAction} internal URL without a backing file: ${rawPath}`);
|
|
991
|
+
}
|
|
992
|
+
if (opts.trackImmutableSources && resource.immutable) {
|
|
993
|
+
immutableSourcePaths.add(path.resolve(resource.sourcePath));
|
|
994
|
+
}
|
|
995
|
+
resolvedPathInputs.push(resource.sourcePath);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
let missingPaths: string[] = [];
|
|
999
|
+
let effectivePaths = resolvedPathInputs;
|
|
1000
|
+
if (resolvedPathInputs.length > 1) {
|
|
1001
|
+
const partition = await partitionExistingPaths(resolvedPathInputs, cwd, parseSearchPath);
|
|
1002
|
+
if (partition.valid.length === 0) {
|
|
1003
|
+
throw new ToolError(`Path not found: ${partition.missing.join(", ")}`);
|
|
1004
|
+
}
|
|
1005
|
+
effectivePaths = partition.valid;
|
|
1006
|
+
missingPaths = partition.missing;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
let searchPath: string;
|
|
1010
|
+
let scopePath: string;
|
|
1011
|
+
let globFilter: string | undefined;
|
|
1012
|
+
let multiTargets: ResolvedSearchTarget[] | undefined;
|
|
1013
|
+
let exactFilePaths: string[] | undefined;
|
|
1014
|
+
if (effectivePaths.length === 1) {
|
|
1015
|
+
const parsedPath = await parseSearchPathPreferringLiteral(effectivePaths[0] ?? ".", cwd);
|
|
1016
|
+
searchPath = resolveToCwd(parsedPath.basePath, cwd);
|
|
1017
|
+
globFilter = parsedPath.glob;
|
|
1018
|
+
scopePath = formatPathRelativeToCwd(searchPath, cwd);
|
|
1019
|
+
} else {
|
|
1020
|
+
const multiSearchPath = await resolveExplicitSearchPaths(effectivePaths, cwd);
|
|
1021
|
+
if (!multiSearchPath) {
|
|
1022
|
+
throw new ToolError("`paths` must contain at least one path or glob");
|
|
1023
|
+
}
|
|
1024
|
+
searchPath = multiSearchPath.basePath;
|
|
1025
|
+
multiTargets = multiSearchPath.targets;
|
|
1026
|
+
if (opts.surfaceExactFilePaths) {
|
|
1027
|
+
exactFilePaths = multiSearchPath.exactFilePaths;
|
|
1028
|
+
globFilter = exactFilePaths || multiTargets ? undefined : multiSearchPath.glob;
|
|
1029
|
+
} else {
|
|
1030
|
+
globFilter = multiTargets ? undefined : multiSearchPath.glob;
|
|
1031
|
+
}
|
|
1032
|
+
scopePath = multiSearchPath.scopePath;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
let isDirectory: boolean;
|
|
1036
|
+
try {
|
|
1037
|
+
const stat = await Bun.file(searchPath).stat();
|
|
1038
|
+
isDirectory = stat.isDirectory();
|
|
1039
|
+
} catch {
|
|
1040
|
+
const hint = opts.multipathStatHint && rawPaths.length > 1 ? opts.multipathStatHint : "";
|
|
1041
|
+
throw new ToolError(`Path not found: ${scopePath}${hint}`);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return {
|
|
1045
|
+
searchPath,
|
|
1046
|
+
scopePath,
|
|
1047
|
+
globFilter,
|
|
1048
|
+
isDirectory,
|
|
1049
|
+
multiTargets,
|
|
1050
|
+
exactFilePaths,
|
|
1051
|
+
missingPaths,
|
|
1052
|
+
immutableSourcePaths,
|
|
1053
|
+
};
|
|
1054
|
+
}
|