@ashx-j/lunr 0.2.26 → 0.2.27
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 +16 -1
- package/LICENSE +22 -0
- package/dist/builtin-extensions/ashxj-thinking.d.ts +1 -1
- package/dist/builtin-extensions/ashxj-thinking.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts +11 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +6 -10
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/lunr-cron.d.ts +4 -5
- package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-cron.js +94 -108
- package/dist/builtin-extensions/lunr-cron.js.map +1 -1
- package/dist/builtin-extensions/lunr-local-providers/local-servers.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-local-providers/local-servers.js +3 -1
- package/dist/builtin-extensions/lunr-local-providers/local-servers.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js +2 -2
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.js +2 -2
- package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.d.ts +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.js +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js +1 -15
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.d.ts +6 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.js +187 -132
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.d.ts +8 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.js +142 -112
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.d.ts +12 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.js +14 -7
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.d.ts +11 -3
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.js +67 -41
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.d.ts +4 -2
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.js +3 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/commands.d.ts +2 -1
- package/dist/builtin-extensions/pi-mcp-adapter/commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/commands.js +6 -6
- package/dist/builtin-extensions/pi-mcp-adapter/commands.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/config.d.ts +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/config.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/config.js +11 -5
- package/dist/builtin-extensions/pi-mcp-adapter/config.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js +2 -2
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/host-html-template.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/host-html-template.js +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/host-html-template.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.js +48 -40
- package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.js +3 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.d.ts +12 -40
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.js +166 -235
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.d.ts +5 -0
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.js +43 -13
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.d.ts +14 -3
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.js +73 -21
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/proxy-modes.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/proxy-modes.js +4 -4
- package/dist/builtin-extensions/pi-mcp-adapter/proxy-modes.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js +2 -2
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/state.d.ts +2 -0
- package/dist/builtin-extensions/pi-mcp-adapter/state.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/state.js.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.d.ts +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.js +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.js.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/models.d.ts +11 -5
- package/dist/builtin-extensions/pi-ollama-cloud/models.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/models.js +12 -32
- package/dist/builtin-extensions/pi-ollama-cloud/models.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/index.js +5 -3
- package/dist/builtin-extensions/pi-prompt-template-model/index.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts +2 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js +21 -12
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js +7 -24
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +39 -77
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js +15 -31
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js +7 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +10 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +8 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +106 -24
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +25 -5
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +7 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js +60 -32
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.js +15 -5
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +4 -3
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +17 -8
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js.map +1 -1
- package/dist/builtin-extensions/pi-tps.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-tps.js +20 -17
- package/dist/builtin-extensions/pi-tps.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/activity.d.ts +1 -0
- package/dist/builtin-extensions/pi-web-access/activity.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/activity.js +27 -5
- package/dist/builtin-extensions/pi-web-access/activity.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/bounded-body.d.ts +3 -0
- package/dist/builtin-extensions/pi-web-access/bounded-body.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/bounded-body.js +43 -0
- package/dist/builtin-extensions/pi-web-access/bounded-body.js.map +1 -0
- package/dist/builtin-extensions/pi-web-access/content-page.d.ts +24 -0
- package/dist/builtin-extensions/pi-web-access/content-page.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/content-page.js +57 -0
- package/dist/builtin-extensions/pi-web-access/content-page.js.map +1 -0
- package/dist/builtin-extensions/pi-web-access/extract.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/extract.js +7 -2
- package/dist/builtin-extensions/pi-web-access/extract.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.d.ts +0 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.js +147 -36
- package/dist/builtin-extensions/pi-web-access/github-extract.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +48 -73
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts +12 -4
- package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/session-cleanup.js +35 -12
- package/dist/builtin-extensions/pi-web-access/session-cleanup.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/storage.d.ts +9 -6
- package/dist/builtin-extensions/pi-web-access/storage.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/storage.js +36 -24
- package/dist/builtin-extensions/pi-web-access/storage.js.map +1 -1
- package/dist/builtin-extensions/simple-pi-memory.d.ts +1 -1
- package/dist/builtin-extensions/simple-pi-memory.d.ts.map +1 -1
- package/dist/builtin-extensions/simple-pi-memory.js +1 -1
- package/dist/builtin-extensions/simple-pi-memory.js.map +1 -1
- package/dist/cli/install-cli.d.ts.map +1 -1
- package/dist/cli/install-cli.js +38 -30
- package/dist/cli/install-cli.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +13 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +75 -11
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +40 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +309 -76
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/browser/runtime.d.ts +2 -0
- package/dist/core/browser/runtime.d.ts.map +1 -1
- package/dist/core/browser/runtime.js +80 -45
- package/dist/core/browser/runtime.js.map +1 -1
- package/dist/core/browser/setup.d.ts.map +1 -1
- package/dist/core/browser/setup.js +12 -1
- package/dist/core/browser/setup.js.map +1 -1
- package/dist/core/computer-use/adapter.d.ts.map +1 -1
- package/dist/core/computer-use/adapter.js +7 -2
- package/dist/core/computer-use/adapter.js.map +1 -1
- package/dist/core/computer-use/image.d.ts.map +1 -1
- package/dist/core/computer-use/image.js +17 -5
- package/dist/core/computer-use/image.js.map +1 -1
- package/dist/core/computer-use/schemas.d.ts.map +1 -1
- package/dist/core/computer-use/schemas.js +23 -6
- package/dist/core/computer-use/schemas.js.map +1 -1
- package/dist/core/computer-use/workflow.d.ts.map +1 -1
- package/dist/core/computer-use/workflow.js +459 -119
- package/dist/core/computer-use/workflow.js.map +1 -1
- package/dist/core/cron/jobs.d.ts +26 -8
- package/dist/core/cron/jobs.d.ts.map +1 -1
- package/dist/core/cron/jobs.js +357 -232
- package/dist/core/cron/jobs.js.map +1 -1
- package/dist/core/cron/origin-context.d.ts +1 -0
- package/dist/core/cron/origin-context.d.ts.map +1 -1
- package/dist/core/cron/origin-context.js.map +1 -1
- package/dist/core/cron/scheduler.d.ts +22 -17
- package/dist/core/cron/scheduler.d.ts.map +1 -1
- package/dist/core/cron/scheduler.js +153 -73
- package/dist/core/cron/scheduler.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +8 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +4 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +22 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/large-subagent-launch.d.ts +1 -1
- package/dist/core/large-subagent-launch.d.ts.map +1 -1
- package/dist/core/large-subagent-launch.js +7 -7
- package/dist/core/large-subagent-launch.js.map +1 -1
- package/dist/core/model-registry.d.ts +2 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +5 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts +4 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +40 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions.d.ts +3 -3
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +11 -35
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts +5 -13
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +126 -116
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/prompt-resource-bridge.d.ts +12 -0
- package/dist/core/prompt-resource-bridge.d.ts.map +1 -0
- package/dist/core/prompt-resource-bridge.js +9 -0
- package/dist/core/prompt-resource-bridge.js.map +1 -0
- package/dist/core/protected-targets.d.ts +6 -0
- package/dist/core/protected-targets.d.ts.map +1 -0
- package/dist/core/protected-targets.js +45 -0
- package/dist/core/protected-targets.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/rollback.d.ts +19 -3
- package/dist/core/rollback.d.ts.map +1 -1
- package/dist/core/rollback.js +172 -56
- package/dist/core/rollback.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +3 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +14 -1
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +95 -32
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-ownership.d.ts.map +1 -1
- package/dist/core/session-ownership.js +8 -3
- package/dist/core/session-ownership.js.map +1 -1
- package/dist/core/session-retention.d.ts.map +1 -1
- package/dist/core/session-retention.js +18 -7
- package/dist/core/session-retention.js.map +1 -1
- package/dist/core/session-startup-settings.d.ts +10 -0
- package/dist/core/session-startup-settings.d.ts.map +1 -0
- package/dist/core/session-startup-settings.js +70 -0
- package/dist/core/session-startup-settings.js.map +1 -0
- package/dist/core/subscriptions.d.ts +16 -7
- package/dist/core/subscriptions.d.ts.map +1 -1
- package/dist/core/subscriptions.js +96 -55
- package/dist/core/subscriptions.js.map +1 -1
- package/dist/core/trust-manager.d.ts +2 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +6 -1
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/update-check.d.ts.map +1 -1
- package/dist/core/update-check.js.map +1 -1
- package/dist/core/usage-adapters/kimi-coding.d.ts +2 -2
- package/dist/core/usage-adapters/kimi-coding.d.ts.map +1 -1
- package/dist/core/usage-adapters/kimi-coding.js +2 -2
- package/dist/core/usage-adapters/kimi-coding.js.map +1 -1
- package/dist/core/usage-adapters/openai-codex.d.ts +3 -2
- package/dist/core/usage-adapters/openai-codex.d.ts.map +1 -1
- package/dist/core/usage-adapters/openai-codex.js +3 -3
- package/dist/core/usage-adapters/openai-codex.js.map +1 -1
- package/dist/core/usage-adapters/xai.d.ts +2 -2
- package/dist/core/usage-adapters/xai.d.ts.map +1 -1
- package/dist/core/usage-adapters/xai.js +3 -3
- package/dist/core/usage-adapters/xai.js.map +1 -1
- package/dist/core/usage-adapters/zai.d.ts +2 -2
- package/dist/core/usage-adapters/zai.d.ts.map +1 -1
- package/dist/core/usage-adapters/zai.js +2 -2
- package/dist/core/usage-adapters/zai.js.map +1 -1
- package/dist/core/usage-service.d.ts +9 -2
- package/dist/core/usage-service.d.ts.map +1 -1
- package/dist/core/usage-service.js +95 -50
- package/dist/core/usage-service.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +9 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +91 -37
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/buttons.d.ts +8 -1
- package/dist/gateway/buttons.d.ts.map +1 -1
- package/dist/gateway/buttons.js +76 -18
- package/dist/gateway/buttons.js.map +1 -1
- package/dist/gateway/commands.d.ts +1 -0
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +10 -4
- package/dist/gateway/commands.js.map +1 -1
- package/dist/gateway/cron.d.ts +12 -11
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +65 -56
- package/dist/gateway/cron.js.map +1 -1
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +2 -1
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/mobile-commands.d.ts +1 -0
- package/dist/gateway/mobile-commands.d.ts.map +1 -1
- package/dist/gateway/mobile-commands.js +56 -14
- package/dist/gateway/mobile-commands.js.map +1 -1
- package/dist/gateway/presenter.d.ts +12 -2
- package/dist/gateway/presenter.d.ts.map +1 -1
- package/dist/gateway/presenter.js +73 -38
- package/dist/gateway/presenter.js.map +1 -1
- package/dist/gateway/router.d.ts +2 -2
- package/dist/gateway/router.d.ts.map +1 -1
- package/dist/gateway/router.js +17 -2
- package/dist/gateway/router.js.map +1 -1
- package/dist/gateway/service.d.ts +2 -0
- package/dist/gateway/service.d.ts.map +1 -1
- package/dist/gateway/service.js +153 -0
- package/dist/gateway/service.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +86 -33
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +6 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -1
- package/dist/modes/interactive/components/copyable-text.js +3 -2
- package/dist/modes/interactive/components/copyable-text.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +1 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +96 -109
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/smooth-streaming.d.ts.map +1 -1
- package/dist/modes/interactive/smooth-streaming.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/node-runtime/{adapter-VFG7WNPX.js → adapter-247RTYLS.js} +4 -5
- package/dist/node-runtime/agent-session-services-KDMSPQDY.js +53 -0
- package/dist/node-runtime/{brave-UWDA3I22.js → brave-2AFFAXNN.js} +1 -1
- package/dist/node-runtime/{builtin-extensions-I2HIFEMY.js → builtin-extensions-OX6KELNX.js} +8 -7
- package/dist/node-runtime/{chunk-QH6YL7VK.js → chunk-252ZVPPF.js} +3 -3
- package/dist/node-runtime/{chunk-PCEW76PM.js → chunk-2OIPYKLZ.js} +6 -6
- package/dist/node-runtime/{chunk-XBWPBZBN.js → chunk-2SWW7KMW.js} +1 -1
- package/dist/node-runtime/{chunk-UQUCFAJ3.js → chunk-2VIW3IMF.js} +40 -7
- package/dist/node-runtime/{chunk-UOEDI7RP.js → chunk-4KNKQGHM.js} +2 -2
- package/dist/node-runtime/{chunk-FQMM2EZ2.js → chunk-64XTQNLA.js} +29 -7
- package/dist/node-runtime/{chunk-SPVDBUOS.js → chunk-6O3IW3IA.js} +2 -2
- package/dist/node-runtime/{chunk-5ZQXRPMC.js → chunk-6ZZHGUSA.js} +2 -2
- package/dist/node-runtime/chunk-A2WO6WIN.js +1197 -0
- package/dist/node-runtime/{chunk-WIF24I7G.js → chunk-APVM5NEU.js} +149 -144
- package/dist/node-runtime/{chunk-RCR3XAQY.js → chunk-AYHH7YSD.js} +177 -144
- package/dist/node-runtime/{chunk-LWYIVUGV.js → chunk-B2IBAXNX.js} +48 -31
- package/dist/node-runtime/{chunk-M3LZLQW2.js → chunk-BDRGN3L2.js} +1 -0
- package/dist/node-runtime/{chunk-GJ2RDBRL.js → chunk-BYC6RKCN.js} +4 -2
- package/dist/node-runtime/{chunk-UVWCDQYF.js → chunk-C3P6Q3B2.js} +455 -278
- package/dist/node-runtime/{chunk-SN2KSMPQ.js → chunk-DQSCFU7R.js} +13 -7
- package/dist/node-runtime/{chunk-4SBQAI4T.js → chunk-EBLAZVSA.js} +2058 -73
- package/dist/node-runtime/{chunk-2KIPT4HJ.js → chunk-EPR2F3GU.js} +68 -20
- package/dist/node-runtime/{chunk-CSFI6YXL.js → chunk-ES6PBSIE.js} +1 -1
- package/dist/node-runtime/{chunk-IF24A3FH.js → chunk-EVM653DD.js} +4 -4
- package/dist/node-runtime/{chunk-HTFRRDSF.js → chunk-F2SMQ6ES.js} +3 -2
- package/dist/node-runtime/chunk-F2V2F4ZG.js +114 -0
- package/dist/node-runtime/{chunk-IKU6Y7DL.js → chunk-FE3WZI7F.js} +9 -6
- package/dist/node-runtime/{chunk-GYIXXQAO.js → chunk-FIRA54AC.js} +2 -5
- package/dist/node-runtime/{chunk-6VYZ5UFP.js → chunk-FLGEEH27.js} +1 -1
- package/dist/node-runtime/{chunk-5EFIU3OM.js → chunk-FTKEZL27.js} +1 -1
- package/dist/node-runtime/{chunk-RGQAEOM5.js → chunk-FYIFPFXE.js} +23 -6
- package/dist/node-runtime/{chunk-HMBGROQK.js → chunk-GLDXBBL6.js} +3 -3
- package/dist/node-runtime/{chunk-KWA4OC2J.js → chunk-H6YBCWKG.js} +1 -1
- package/dist/node-runtime/{chunk-2MI5OPMN.js → chunk-HNNHHJAB.js} +68 -50
- package/dist/node-runtime/{chunk-I74LN5JG.js → chunk-HUD2RFJW.js} +2 -2
- package/dist/node-runtime/{chunk-I54LGHWM.js → chunk-I2H5QMWW.js} +3 -3
- package/dist/node-runtime/{chunk-XHIRAZ26.js → chunk-IAZSK7KK.js} +1 -1
- package/dist/node-runtime/{chunk-X3PGBLQ7.js → chunk-IHHTWSXN.js} +9 -9
- package/dist/node-runtime/{chunk-DAPBPCBP.js → chunk-IPP5BIV5.js} +25 -3
- package/dist/node-runtime/{chunk-QFWG2RVL.js → chunk-IXG6F4NT.js} +11 -0
- package/dist/node-runtime/{chunk-RDDAZOMU.js → chunk-JL4HYQXK.js} +1 -1
- package/dist/node-runtime/{chunk-CDVHZOOK.js → chunk-JQYNHAKX.js} +1 -1
- package/dist/node-runtime/{chunk-L24TPBS4.js → chunk-JWEVT363.js} +37 -29
- package/dist/node-runtime/{chunk-2HMIRK7W.js → chunk-LHV3V67B.js} +5 -5
- package/dist/node-runtime/{chunk-UAEOTO52.js → chunk-MNQXDFPV.js} +6 -2
- package/dist/node-runtime/{chunk-T4DA4XE7.js → chunk-MQPKUHRN.js} +162 -82
- package/dist/node-runtime/{chunk-MPKSOJBT.js → chunk-NHATCSOI.js} +4 -7
- package/dist/node-runtime/{chunk-RMQZU2YU.js → chunk-NNNR3QIY.js} +1 -1
- package/dist/node-runtime/{chunk-RWTKOC3B.js → chunk-QBTJG3UM.js} +1 -1
- package/dist/node-runtime/{chunk-P7XBVXGT.js → chunk-QNVMKNNN.js} +18 -14
- package/dist/node-runtime/{chunk-GS42T6MX.js → chunk-QW3AAHWN.js} +1 -1
- package/dist/node-runtime/{chunk-DVQSHCVP.js → chunk-R4WSB2MQ.js} +5 -5
- package/dist/node-runtime/{chunk-B4HP6ZWM.js → chunk-RHCGYWO7.js} +1 -1
- package/dist/node-runtime/{chunk-2CFDTH5B.js → chunk-RLGY2QIL.js} +45 -59
- package/dist/node-runtime/{chunk-KKUTQQV7.js → chunk-RYRGL7P4.js} +1 -1
- package/dist/node-runtime/{chunk-5Q4A37RB.js → chunk-TCT6PCUR.js} +32 -11
- package/dist/node-runtime/{chunk-D5UCKPBQ.js → chunk-UBWW2PID.js} +1 -1
- package/dist/node-runtime/{chunk-E75WFZ33.js → chunk-UNUZICC4.js} +3 -3
- package/dist/node-runtime/{chunk-RAK2QA2B.js → chunk-UYRKUKFE.js} +4 -4
- package/dist/node-runtime/{chunk-LWJXTA6Z.js → chunk-VSUEAI7O.js} +1377 -45
- package/dist/node-runtime/{chunk-NAY6UUQZ.js → chunk-WDIVLMOH.js} +1 -1
- package/dist/node-runtime/{chunk-E24EO34J.js → chunk-WPXUR3HE.js} +1 -1
- package/dist/node-runtime/{chunk-SLVOAQOY.js → chunk-WXYNALHD.js} +113 -1
- package/dist/node-runtime/{chunk-KJ6DWS3K.js → chunk-XEOCUEUJ.js} +121 -60
- package/dist/node-runtime/chunk-YD3IZAZ7.js +47 -0
- package/dist/node-runtime/chunk-YSB6URMT.js +41 -0
- package/dist/node-runtime/{chunk-LJTIVM7I.js → chunk-ZDJUR45D.js} +427 -126
- package/dist/node-runtime/{chunk-YWOJIGFY.js → chunk-ZEVFBFNF.js} +95 -142
- package/dist/node-runtime/{chunk-5B6VKFEV.js → chunk-ZIQUS5QO.js} +1 -1
- package/dist/node-runtime/cli-runtime.js +4 -4
- package/dist/node-runtime/{command-FSBU2EVZ.js → command-3HMSY6W2.js} +5 -5
- package/dist/node-runtime/{commands-EMBQQVVT.js → commands-D6A6H4TS.js} +11 -18
- package/dist/node-runtime/{commands-NAAL7KNT.js → commands-OCSSEEWJ.js} +16 -16
- package/dist/node-runtime/{config-QDD5PUE2.js → config-CU7M7BTK.js} +1 -1
- package/dist/node-runtime/{config-D4QUPAHX.js → config-DS7XLMEM.js} +2 -2
- package/dist/node-runtime/{direct-tool-executor-4D7UXYU4.js → direct-tool-executor-2QJXVQD2.js} +6 -11
- package/dist/node-runtime/{exa-LL64QZR2.js → exa-6VBZNPGE.js} +1 -1
- package/dist/node-runtime/{export-html-VM4J2MNR.js → export-html-BRWF5AHI.js} +4 -4
- package/dist/node-runtime/{extension-input-E7BJZ35H.js → extension-input-VBBMX7YV.js} +5 -5
- package/dist/node-runtime/{extension-selector-WU42XDTU.js → extension-selector-T5AOG5XB.js} +5 -5
- package/dist/node-runtime/{extract-EQJE7FZZ.js → extract-BFX2N35A.js} +3 -3
- package/dist/node-runtime/{gateway-DQM333YV.js → gateway-6623C2U3.js} +51 -42
- package/dist/node-runtime/{gemini-search-35OCRFLN.js → gemini-search-C66QHDT6.js} +2 -2
- package/dist/node-runtime/{gemini-url-context-UQY3PHHW.js → gemini-url-context-T7DEK73R.js} +3 -3
- package/dist/node-runtime/{github-extract-F64RZOEA.js → github-extract-HOGE3D6F.js} +107 -38
- package/dist/node-runtime/{goal-NJEE5CTU.js → goal-AIHEDUYA.js} +5 -5
- package/dist/node-runtime/index.js +50 -48
- package/dist/node-runtime/{init-P5AUV77I.js → init-JBQJIPYI.js} +3 -6
- package/dist/node-runtime/{install-cli-NN4YAU44.js → install-cli-INGHIVBY.js} +30 -25
- package/dist/node-runtime/interactive-mode-FM5DNUSW.js +74 -0
- package/dist/node-runtime/{interactive-view-NGFAMHPW.js → interactive-view-K33PM4OS.js} +8 -8
- package/dist/node-runtime/{lsp-manager-3ASUSO4T.js → lsp-manager-S554V5HR.js} +240 -155
- package/dist/node-runtime/{lunr-browser-IR7TL3J7.js → lunr-browser-H4FDOR3C.js} +7 -7
- package/dist/node-runtime/{lunr-computer-use-Y23CCDIJ.js → lunr-computer-use-VDP2QNRQ.js} +9 -9
- package/dist/node-runtime/{lunr-cron-USHC4LXH.js → lunr-cron-LKVA5CZZ.js} +93 -80
- package/dist/node-runtime/main.js +42 -41
- package/dist/node-runtime/{mobile-commands-O5LCHL32.js → mobile-commands-XT3NQXLD.js} +12 -12
- package/dist/node-runtime/{model-runtime-OO5HFLWE.js → model-runtime-MZ2JMDV4.js} +4 -4
- package/dist/node-runtime/{openai-search-B3MSNCQA.js → openai-search-K72LJDYN.js} +1 -1
- package/dist/node-runtime/{package-manager-cli-Q7BL6KZO.js → package-manager-cli-CYM262SI.js} +20 -20
- package/dist/node-runtime/{parallel-AI2MNSCU.js → parallel-X724NCNU.js} +1 -1
- package/dist/node-runtime/{perplexity-QVJW3I35.js → perplexity-RDHQHVMK.js} +2 -2
- package/dist/node-runtime/{pi-intercom-QM53RLTS.js → pi-intercom-NHHEPBMI.js} +2 -2
- package/dist/node-runtime/{pi-mcp-adapter-3PHF4KZ4.js → pi-mcp-adapter-PP3GQJQ2.js} +98 -94
- package/dist/node-runtime/{pi-ollama-cloud-2F3Y2QNM.js → pi-ollama-cloud-4MNWIMFN.js} +11 -24
- package/dist/node-runtime/{pi-prompt-template-model-QWTCGLJU.js → pi-prompt-template-model-FTGELLS5.js} +32 -36
- package/dist/node-runtime/{pi-subagents-7IBSSGEW.js → pi-subagents-LT3CTO4E.js} +98 -106
- package/dist/node-runtime/{pi-web-access-WTGMNZ32.js → pi-web-access-Z3LP246C.js} +144 -108
- package/dist/node-runtime/{print-mode-XQ76CYMT.js → print-mode-2XHN5SUA.js} +3 -3
- package/dist/node-runtime/{process-registry-4FAKZQOL.js → process-registry-Q4QWIU33.js} +3 -3
- package/dist/node-runtime/{proxy-modes-5FAPSZEZ.js → proxy-modes-VEGC6QG5.js} +8 -15
- package/dist/node-runtime/rpc-entry.js +42 -41
- package/dist/node-runtime/{rpc-mode-O3XV4SID.js → rpc-mode-32DHJPEJ.js} +4 -4
- package/dist/node-runtime/{runtime-4VA6JKNF.js → runtime-EDUUGAQD.js} +56 -46
- package/dist/node-runtime/{runtime-EFPPD2UW.js → runtime-UGXM4NPQ.js} +2 -2
- package/dist/node-runtime/{runtime-bridges-7WVCLI76.js → runtime-bridges-DNKMNJCF.js} +7 -7
- package/dist/node-runtime/{service-MDQIPQ26.js → service-IHLGFLBT.js} +6 -4
- package/dist/node-runtime/{session-handoff-GWARVEWT.js → session-handoff-LNSPDTKY.js} +4 -4
- package/dist/node-runtime/{session-manager-JB5J6XBN.js → session-manager-YIFIAVGC.js} +3 -3
- package/dist/node-runtime/{session-selector-GIM4DHQ2.js → session-selector-I73U3EIO.js} +7 -7
- package/dist/node-runtime/{settings-manager-DJDM5AHM.js → settings-manager-P2TKGYTR.js} +5 -5
- package/dist/node-runtime/{setup-JBKOLJ6F.js → setup-H7CCELIL.js} +15 -1
- package/dist/node-runtime/{setup-PFBWRNUI.js → setup-OLQ4GXWS.js} +17 -17
- package/dist/node-runtime/{src-IVPNZ2BX.js → src-6RV4PXKJ.js} +64 -36
- package/dist/node-runtime/{subagent-executor-LPZ4BHWE.js → subagent-executor-Q5F7DBVM.js} +119 -58
- package/dist/node-runtime/{tavily-WEZFVFP7.js → tavily-KZBFYQB6.js} +1 -1
- package/dist/node-runtime/{theme-UOO5RVFN.js → theme-YLVZKKZD.js} +2 -2
- package/dist/node-runtime/{trust-manager-MMISNCYO.js → trust-manager-ZCU76D23.js} +2 -2
- package/dist/node-runtime/{update-cli-HNMOTNGX.js → update-cli-F3XXJANQ.js} +6 -6
- package/dist/node-runtime/{usage-service-LFB2SWYV.js → usage-service-CPAGBED5.js} +1 -1
- package/dist/node-runtime/{video-extract-OOZHR7SU.js → video-extract-UPKYIBW3.js} +3 -3
- package/dist/node-runtime/{workflow-OHPBEFO4.js → workflow-ICDI4N3J.js} +208 -78
- package/dist/node-runtime/{youtube-extract-FNPAUNHU.js → youtube-extract-77NT7FWH.js} +4 -4
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js +25 -10
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js +2 -0
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/paths.d.ts +4 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +33 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/sanitize-terminal-text.d.ts +7 -0
- package/dist/utils/sanitize-terminal-text.d.ts.map +1 -0
- package/dist/utils/sanitize-terminal-text.js +67 -0
- package/dist/utils/sanitize-terminal-text.js.map +1 -0
- package/docs/browser.md +1 -1
- package/docs/custom-provider.md +3 -3
- package/docs/extensions.md +8 -4
- package/docs/features.md +15 -7
- package/docs/keybindings.md +1 -1
- package/docs/models.md +5 -5
- package/docs/packages.md +1 -1
- package/docs/providers.md +2 -2
- package/docs/rpc.md +7 -7
- package/docs/security.md +10 -5
- package/docs/sessions.md +2 -2
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +7 -7
- package/docs/themes.md +1 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/auto-commit-on-exit.ts +1 -1
- package/examples/extensions/bash-spawn-hook.ts +1 -1
- package/examples/extensions/built-in-tool-renderer.ts +1 -1
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/custom-compaction.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +3 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/index.ts +1 -1
- package/examples/extensions/git-merge-and-resolve.ts +2 -2
- package/examples/extensions/gondolin/index.ts +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +2 -2
- package/examples/extensions/input-transform-streaming.ts +2 -2
- package/examples/extensions/input-transform.ts +2 -2
- package/examples/extensions/interactive-shell.ts +1 -1
- package/examples/extensions/kimi-deferred-tools.ts +1 -1
- package/examples/extensions/mac-system-theme.ts +1 -1
- package/examples/extensions/minimal-mode.ts +1 -1
- package/examples/extensions/modal-editor.ts +1 -1
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/notify.ts +3 -3
- package/examples/extensions/overlay-qa-tests.ts +1 -1
- package/examples/extensions/overlay-test.ts +1 -1
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/preset.ts +3 -3
- package/examples/extensions/project-trust.ts +4 -4
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/rpc-demo.ts +1 -1
- package/examples/extensions/sandbox/index.ts +7 -7
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/shutdown-command.ts +5 -5
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/subagent/README.md +3 -3
- package/examples/extensions/subagent/index.ts +2 -2
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/extensions/working-indicator.ts +1 -1
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/03-custom-prompt.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/06-extensions.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +1 -1
- package/install-lock/package-lock.json +24 -24
- package/install-lock/package.json +2 -2
- package/npm-shrinkwrap.json +60 -24
- package/package.json +9 -9
- package/dist/modes/interactive/components/exit-card.d.ts +0 -22
- package/dist/modes/interactive/components/exit-card.d.ts.map +0 -1
- package/dist/modes/interactive/components/exit-card.js +0 -69
- package/dist/modes/interactive/components/exit-card.js.map +0 -1
- package/dist/node-runtime/agent-session-services-5YXS2PLF.js +0 -51
- package/dist/node-runtime/chunk-2IDTZAG5.js +0 -1415
- package/dist/node-runtime/chunk-3MISGG4S.js +0 -769
- package/dist/node-runtime/chunk-4HXHDDCF.js +0 -16
- package/dist/node-runtime/chunk-5B5QN3ZQ.js +0 -356
- package/dist/node-runtime/chunk-7IQGBKBJ.js +0 -2033
- package/dist/node-runtime/chunk-AUXVGBO4.js +0 -19
- package/dist/node-runtime/chunk-PTFBPO3C.js +0 -50
- package/dist/node-runtime/interactive-mode-YOHZVMKX.js +0 -74
- package/dist/node-runtime/mcp-auth-flow-QVLFVLEO.js +0 -33
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
/**
|
|
3
2
|
* Rewrite Engine — apply structural replacements using matched patterns.
|
|
4
3
|
*
|
|
5
4
|
* Takes search matches and a replacement template with metavariable references,
|
|
6
5
|
* substitutes captured values, and applies the text changes.
|
|
7
6
|
*/
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { dirname } from "node:path";
|
|
9
|
+
import { protectedTargetWriteReason } from "../../../../core/protected-targets.js";
|
|
10
|
+
import { withFileMutationQueue } from "../../../../core/tools/file-mutation-queue.js";
|
|
8
11
|
import { readFile, writeFile } from "node:fs/promises";
|
|
9
12
|
// ── Replacement template substitution ───────────────────────────────────────
|
|
10
13
|
const METAVAR_REF_RE = /\$\$\$([A-Z_][A-Z0-9_]*)|\$([A-Z_][A-Z0-9_]*)/g;
|
|
@@ -50,53 +53,76 @@ export function computeRewrites(matches, replacementTemplate) {
|
|
|
50
53
|
});
|
|
51
54
|
}
|
|
52
55
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
56
|
+
* Preflight every protected destination, then queue each file's read/validate/write.
|
|
57
|
+
* Stop on the first failure and retain an accurate partial result. This is not a
|
|
58
|
+
* multi-file transaction; earlier successful files remain changed.
|
|
55
59
|
*/
|
|
56
|
-
export async function applyRewrites(matches, replacementTemplate) {
|
|
57
|
-
// Group matches by file
|
|
60
|
+
export async function applyRewrites(matches, replacementTemplate, cwd) {
|
|
58
61
|
const byFile = new Map();
|
|
59
|
-
for (const
|
|
60
|
-
const existing = byFile.get(
|
|
61
|
-
if (existing)
|
|
62
|
-
existing.push(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
for (const match of matches) {
|
|
63
|
+
const existing = byFile.get(match.file);
|
|
64
|
+
if (existing)
|
|
65
|
+
existing.push(match);
|
|
66
|
+
else
|
|
67
|
+
byFile.set(match.file, [match]);
|
|
68
|
+
}
|
|
69
|
+
const result = { changes: [], filesModified: 0, modifiedFiles: [], failures: [], skippedFiles: [] };
|
|
70
|
+
const files = [...byFile.keys()];
|
|
71
|
+
// An allowed directory scope never authorizes a protected matched file.
|
|
72
|
+
for (const file of files) {
|
|
73
|
+
const reason = protectedTargetWriteReason(file, cwd ?? dirname(file));
|
|
74
|
+
if (reason)
|
|
75
|
+
result.failures.push({ file, reason });
|
|
76
|
+
}
|
|
77
|
+
if (result.failures.length) {
|
|
78
|
+
result.skippedFiles = files.filter((file) => !result.failures.some((failure) => failure.file === file));
|
|
79
|
+
return result;
|
|
67
80
|
}
|
|
68
|
-
const changes = [];
|
|
69
|
-
let filesModified = 0;
|
|
70
81
|
for (const [file, fileMatches] of byFile) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
let writeAttempted = false;
|
|
83
|
+
try {
|
|
84
|
+
const applied = await withFileMutationQueue(file, async () => {
|
|
85
|
+
const reason = protectedTargetWriteReason(file, cwd ?? dirname(file));
|
|
86
|
+
if (reason)
|
|
87
|
+
throw new Error(reason);
|
|
88
|
+
const source = await readFile(file, "utf-8");
|
|
89
|
+
const sourceHash = createHash("sha256").update(source).digest("hex");
|
|
90
|
+
const sorted = [...fileMatches].sort((a, b) => b.startIndex - a.startIndex);
|
|
91
|
+
let nextStart = source.length;
|
|
92
|
+
for (const match of sorted) {
|
|
93
|
+
if (match.sourceHash !== sourceHash || !Number.isInteger(match.startIndex) ||
|
|
94
|
+
!Number.isInteger(match.endIndex) || match.startIndex < 0 || match.endIndex > nextStart ||
|
|
95
|
+
match.startIndex > match.endIndex || source.slice(match.startIndex, match.endIndex) !== match.matchedText) {
|
|
96
|
+
throw new Error("Source changed or match offsets are invalid. Search again before applying a rewrite.");
|
|
97
|
+
}
|
|
98
|
+
nextStart = match.startIndex;
|
|
99
|
+
}
|
|
100
|
+
let content = source;
|
|
101
|
+
const changes = [];
|
|
102
|
+
for (const match of sorted) {
|
|
103
|
+
const raw = substituteCaptures(replacementTemplate, match.captures);
|
|
104
|
+
const replacement = preserveTrailingSemicolon(match.matchedText, raw);
|
|
105
|
+
content = content.slice(0, match.startIndex) + replacement + content.slice(match.endIndex);
|
|
106
|
+
changes.push({ file, line: match.line, column: match.column, before: match.matchedText, after: replacement });
|
|
107
|
+
}
|
|
108
|
+
const modified = content !== source;
|
|
109
|
+
if (modified) {
|
|
110
|
+
writeAttempted = true;
|
|
111
|
+
await writeFile(file, content, "utf-8");
|
|
112
|
+
}
|
|
113
|
+
return { changes: changes.reverse(), modified };
|
|
91
114
|
});
|
|
115
|
+
result.changes.push(...applied.changes);
|
|
116
|
+
if (applied.modified)
|
|
117
|
+
result.modifiedFiles.push(file);
|
|
92
118
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
catch (error) {
|
|
120
|
+
result.failures.push({ file, reason: error instanceof Error ? error.message : String(error), writeAttempted });
|
|
121
|
+
result.skippedFiles = files.slice(files.indexOf(file) + 1);
|
|
122
|
+
break;
|
|
96
123
|
}
|
|
97
124
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return { changes, filesModified };
|
|
125
|
+
result.filesModified = result.modifiedFiles.length;
|
|
126
|
+
return result;
|
|
101
127
|
}
|
|
102
128
|
//# sourceMappingURL=rewrite-engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rewrite-engine.js","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\n/**\n * Rewrite Engine — apply structural replacements using matched patterns.\n *\n * Takes search matches and a replacement template with metavariable references,\n * substitutes captured values, and applies the text changes.\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport type { SearchMatch } from \"./search-engine.js\";\n\n// ── Result types ────────────────────────────────────────────────────────────\n\nexport interface RewriteChange {\n file: string;\n line: number;\n column: number;\n before: string;\n after: string;\n}\n\nexport interface RewriteResult {\n changes: RewriteChange[];\n filesModified: number;\n}\n\n// ── Replacement template substitution ───────────────────────────────────────\n\nconst METAVAR_REF_RE = /\\$\\$\\$([A-Z_][A-Z0-9_]*)|\\$([A-Z_][A-Z0-9_]*)/g;\n\n/**\n * Substitute metavariable references in a replacement template with captured values.\n */\nexport function substituteCaptures(\n template: string,\n captures: Record<string, string>,\n): string {\n return template.replace(METAVAR_REF_RE, (match, variadicName, singleName) => {\n const name = variadicName ?? singleName;\n if (name in captures) return captures[name];\n return match; // Leave unmatched references as-is\n });\n}\n\n/**\n * If the original matched text ends with a semicolon (possibly preceded by whitespace)\n * and the replacement doesn't, append the semicolon. This preserves statement terminators\n * that are part of the AST node but not part of the pattern/replacement.\n */\nfunction preserveTrailingSemicolon(original: string, replacement: string): string {\n const trailingMatch = original.match(/(\\s*;)\\s*$/);\n if (trailingMatch && !replacement.trimEnd().endsWith(\";\")) {\n return replacement + trailingMatch[1];\n }\n return replacement;\n}\n\n// ── Rewrite application ─────────────────────────────────────────────────────\n\n/**\n * Compute rewrite changes from matches and a replacement template.\n * Returns the list of changes without applying them.\n */\nexport function computeRewrites(\n matches: SearchMatch[],\n replacementTemplate: string,\n): RewriteChange[] {\n return matches.map((m) => {\n const raw = substituteCaptures(replacementTemplate, m.captures);\n const after = preserveTrailingSemicolon(m.matchedText, raw);\n return {\n file: m.file,\n line: m.line,\n column: m.column,\n before: m.matchedText,\n after,\n };\n });\n}\n\n/**\n * Apply rewrite changes to files. Modifies files in-place.\n * Applies changes bottom-up (last offset first) within each file to preserve byte offsets.\n */\nexport async function applyRewrites(\n matches: SearchMatch[],\n replacementTemplate: string,\n): Promise<RewriteResult> {\n // Group matches by file\n const byFile = new Map<string, SearchMatch[]>();\n for (const m of matches) {\n const existing = byFile.get(m.file);\n if (existing) {\n existing.push(m);\n } else {\n byFile.set(m.file, [m]);\n }\n }\n\n const changes: RewriteChange[] = [];\n let filesModified = 0;\n\n for (const [file, fileMatches] of byFile) {\n // Sort by startIndex descending — apply from bottom to top\n const sorted = [...fileMatches].sort((a, b) => b.startIndex - a.startIndex);\n\n let content = await readFile(file, \"utf-8\");\n let modified = false;\n\n for (const m of sorted) {\n const raw = substituteCaptures(replacementTemplate, m.captures);\n const replacement = preserveTrailingSemicolon(m.matchedText, raw);\n if (replacement !== m.matchedText) {\n content =\n content.slice(0, m.startIndex) +\n replacement +\n content.slice(m.endIndex);\n modified = true;\n }\n changes.push({\n file,\n line: m.line,\n column: m.column,\n before: m.matchedText,\n after: replacement,\n });\n }\n\n if (modified) {\n await writeFile(file, content, \"utf-8\");\n filesModified++;\n }\n }\n\n // Reverse so changes appear top-to-bottom\n changes.reverse();\n\n return { changes, filesModified };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rewrite-engine.js","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Rewrite Engine — apply structural replacements using matched patterns.\n *\n * Takes search matches and a replacement template with metavariable references,\n * substitutes captured values, and applies the text changes.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { dirname } from \"node:path\";\nimport { protectedTargetWriteReason } from \"../../../../core/protected-targets.js\";\nimport { withFileMutationQueue } from \"../../../../core/tools/file-mutation-queue.js\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport type { SearchMatch } from \"./search-engine.js\";\n\n// ── Result types ────────────────────────────────────────────────────────────\n\nexport interface RewriteChange {\n file: string;\n line: number;\n column: number;\n before: string;\n after: string;\n}\n\nexport interface RewriteResult {\n changes: RewriteChange[];\n filesModified: number;\n modifiedFiles: string[];\n failures: { file: string; reason: string; writeAttempted?: boolean }[];\n skippedFiles: string[];\n}\n\n// ── Replacement template substitution ───────────────────────────────────────\n\nconst METAVAR_REF_RE = /\\$\\$\\$([A-Z_][A-Z0-9_]*)|\\$([A-Z_][A-Z0-9_]*)/g;\n\n/**\n * Substitute metavariable references in a replacement template with captured values.\n */\nexport function substituteCaptures(\n template: string,\n captures: Record<string, string>,\n): string {\n return template.replace(METAVAR_REF_RE, (match, variadicName, singleName) => {\n const name = variadicName ?? singleName;\n if (name in captures) return captures[name];\n return match; // Leave unmatched references as-is\n });\n}\n\n/**\n * If the original matched text ends with a semicolon (possibly preceded by whitespace)\n * and the replacement doesn't, append the semicolon. This preserves statement terminators\n * that are part of the AST node but not part of the pattern/replacement.\n */\nfunction preserveTrailingSemicolon(original: string, replacement: string): string {\n const trailingMatch = original.match(/(\\s*;)\\s*$/);\n if (trailingMatch && !replacement.trimEnd().endsWith(\";\")) {\n return replacement + trailingMatch[1];\n }\n return replacement;\n}\n\n// ── Rewrite application ─────────────────────────────────────────────────────\n\n/**\n * Compute rewrite changes from matches and a replacement template.\n * Returns the list of changes without applying them.\n */\nexport function computeRewrites(\n matches: SearchMatch[],\n replacementTemplate: string,\n): RewriteChange[] {\n return matches.map((m) => {\n const raw = substituteCaptures(replacementTemplate, m.captures);\n const after = preserveTrailingSemicolon(m.matchedText, raw);\n return {\n file: m.file,\n line: m.line,\n column: m.column,\n before: m.matchedText,\n after,\n };\n });\n}\n\n/**\n * Preflight every protected destination, then queue each file's read/validate/write.\n * Stop on the first failure and retain an accurate partial result. This is not a\n * multi-file transaction; earlier successful files remain changed.\n */\nexport async function applyRewrites(\n matches: SearchMatch[],\n replacementTemplate: string,\n cwd?: string,\n): Promise<RewriteResult> {\n const byFile = new Map<string, SearchMatch[]>();\n for (const match of matches) {\n const existing = byFile.get(match.file);\n if (existing) existing.push(match);\n else byFile.set(match.file, [match]);\n }\n const result: RewriteResult = { changes: [], filesModified: 0, modifiedFiles: [], failures: [], skippedFiles: [] };\n const files = [...byFile.keys()];\n // An allowed directory scope never authorizes a protected matched file.\n for (const file of files) {\n const reason = protectedTargetWriteReason(file, cwd ?? dirname(file));\n if (reason) result.failures.push({ file, reason });\n }\n if (result.failures.length) {\n result.skippedFiles = files.filter((file) => !result.failures.some((failure) => failure.file === file));\n return result;\n }\n\n for (const [file, fileMatches] of byFile) {\n let writeAttempted = false;\n try {\n const applied = await withFileMutationQueue(file, async () => {\n const reason = protectedTargetWriteReason(file, cwd ?? dirname(file));\n if (reason) throw new Error(reason);\n const source = await readFile(file, \"utf-8\");\n const sourceHash = createHash(\"sha256\").update(source).digest(\"hex\");\n const sorted = [...fileMatches].sort((a, b) => b.startIndex - a.startIndex);\n let nextStart = source.length;\n for (const match of sorted) {\n if (match.sourceHash !== sourceHash || !Number.isInteger(match.startIndex) ||\n !Number.isInteger(match.endIndex) || match.startIndex < 0 || match.endIndex > nextStart ||\n match.startIndex > match.endIndex || source.slice(match.startIndex, match.endIndex) !== match.matchedText) {\n throw new Error(\"Source changed or match offsets are invalid. Search again before applying a rewrite.\");\n }\n nextStart = match.startIndex;\n }\n let content = source;\n const changes: RewriteChange[] = [];\n for (const match of sorted) {\n const raw = substituteCaptures(replacementTemplate, match.captures);\n const replacement = preserveTrailingSemicolon(match.matchedText, raw);\n content = content.slice(0, match.startIndex) + replacement + content.slice(match.endIndex);\n changes.push({ file, line: match.line, column: match.column, before: match.matchedText, after: replacement });\n }\n const modified = content !== source;\n if (modified) {\n writeAttempted = true;\n await writeFile(file, content, \"utf-8\");\n }\n return { changes: changes.reverse(), modified };\n });\n result.changes.push(...applied.changes);\n if (applied.modified) result.modifiedFiles.push(file);\n } catch (error) {\n result.failures.push({ file, reason: error instanceof Error ? error.message : String(error), writeAttempted });\n result.skippedFiles = files.slice(files.indexOf(file) + 1);\n break;\n }\n }\n result.filesModified = result.modifiedFiles.length;\n return result;\n}\n"]}
|
|
@@ -17,9 +17,11 @@ export interface SearchMatch {
|
|
|
17
17
|
column: number;
|
|
18
18
|
/** The matched source text */
|
|
19
19
|
matchedText: string;
|
|
20
|
-
/**
|
|
20
|
+
/** SHA-256 of the full source snapshot used to find this match. */
|
|
21
|
+
sourceHash: string;
|
|
22
|
+
/** Text offset of match start */
|
|
21
23
|
startIndex: number;
|
|
22
|
-
/**
|
|
24
|
+
/** Text offset of match end */
|
|
23
25
|
endIndex: number;
|
|
24
26
|
/** Metavariable bindings: name → captured text */
|
|
25
27
|
captures: Record<string, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-engine.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,WAAW,WAAW;IAC1B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAQD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,iBAAiB,EAC7B,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB,GACL,OAAO,CAAC,WAAW,EAAE,CAAC,CA0CxB;AAID;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,iBAAiB,EAC7B,SAAS,GAAE,MAAM,EAAO,EACxB,QAAQ,GAAE,MAAwB,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB","sourcesContent":["// @ts-nocheck\n/**\n * Search Engine — run compiled patterns against source files and collect matches.\n *\n * Uses a recursive AST matcher: the target file's tree-sitter AST is walked\n * depth-first, and at each node we attempt to match the compiled pattern tree.\n * Metavariable nodes capture any single AST node; variadic nodes capture\n * zero-or-more siblings.\n */\n\nimport { resolve } from \"node:path\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport type Parser from \"web-tree-sitter\";\nimport type { TreeSitterManager } from \"./parser-manager.js\";\nimport type {\n CompiledPattern,\n PatternNode,\n} from \"./pattern-compiler.js\";\nimport { SKIP_DIRS, MAX_FILE_SIZE, MAX_INDEX_FILES } from \"../shared/constants.js\";\n\ntype SyntaxNode = Parser.SyntaxNode;\n\n// ── Result types ────────────────────────────────────────────────────────────\n\nexport interface SearchMatch {\n /** Absolute file path */\n file: string;\n /** 1-indexed line number */\n line: number;\n /** 1-indexed column */\n column: number;\n /** The matched source text */\n matchedText: string;\n /** Byte offset of match start */\n startIndex: number;\n /** Byte offset of match end */\n endIndex: number;\n /** Metavariable bindings: name → captured text */\n captures: Record<string, string>;\n}\n\n// ── Directories to skip ─────────────────────────────────────────────────────\n\n// Shared constants imported from ../shared/constants.ts\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Search files for matches against a compiled pattern.\n */\nexport async function searchFiles(\n pattern: CompiledPattern,\n rootDir: string,\n treeSitter: TreeSitterManager,\n options: {\n path?: string;\n maxResults?: number;\n } = {},\n): Promise<SearchMatch[]> {\n const searchRoot = options.path ? resolve(rootDir, options.path) : rootDir;\n const maxResults = options.maxResults ?? 50;\n\n // Determine if searchRoot is a file or directory\n const stats = await stat(searchRoot);\n let files: string[];\n if (stats.isFile()) {\n files = [searchRoot];\n } else {\n files = await collectFilesByLanguage(searchRoot, pattern.languageId, treeSitter);\n }\n\n const matches: SearchMatch[] = [];\n\n for (const file of files) {\n if (matches.length >= maxResults) break;\n\n try {\n const content = await readFile(file, \"utf-8\");\n const tree = await treeSitter.parseWithLanguage(file, content, pattern.languageId);\n if (!tree) continue;\n\n const fileMatches = findMatches(tree.rootNode, pattern.root);\n for (const m of fileMatches) {\n if (matches.length >= maxResults) break;\n matches.push({\n file,\n line: m.node.startPosition.row + 1,\n column: m.node.startPosition.column + 1,\n matchedText: m.node.text,\n startIndex: m.node.startIndex,\n endIndex: m.node.endIndex,\n captures: m.captures,\n });\n }\n } catch {\n // Skip unreadable files\n }\n }\n\n return matches;\n}\n\n// ── File collection ─────────────────────────────────────────────────────────\n\n/**\n * Collect all files matching a given language under a directory.\n */\nexport async function collectFilesByLanguage(\n dir: string,\n languageId: string,\n treeSitter: TreeSitterManager,\n collected: string[] = [],\n maxFiles: number = MAX_INDEX_FILES,\n): Promise<string[]> {\n if (collected.length >= maxFiles) return collected;\n\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (collected.length >= maxFiles) break;\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(\".\")) continue;\n await collectFilesByLanguage(resolve(dir, entry.name), languageId, treeSitter, collected, maxFiles);\n } else if (entry.isFile()) {\n const fileLang = treeSitter.getLanguageId(entry.name);\n if (fileLang === languageId) {\n const filePath = resolve(dir, entry.name);\n try {\n const s = await stat(filePath);\n if (s.size <= MAX_FILE_SIZE) {\n collected.push(filePath);\n }\n } catch {}\n }\n }\n }\n } catch {\n // Permission denied or other IO error — skip\n }\n\n return collected;\n}\n\n// ── Matching engine ─────────────────────────────────────────────────────────\n\ninterface RawMatch {\n node: SyntaxNode;\n captures: Record<string, string>;\n}\n\n/**\n * Find all non-overlapping matches of the pattern in the target AST.\n * Walks the tree depth-first, attempting to match at each node.\n */\nfunction findMatches(root: SyntaxNode, pattern: PatternNode): RawMatch[] {\n const matches: RawMatch[] = [];\n const visited = new Set<number>(); // node ids already part of a match\n\n function walk(node: SyntaxNode): void {\n if (visited.has(node.id)) return;\n\n const captures: Record<string, string> = {};\n if (matchNode(node, pattern, captures)) {\n matches.push({ node, captures });\n // Mark all descendant nodes as visited to prevent overlapping matches\n markDescendants(node, visited);\n return; // Don't recurse into matched subtree\n }\n\n // Recurse into children\n for (const child of node.namedChildren) {\n walk(child);\n }\n }\n\n walk(root);\n return matches;\n}\n\nfunction markDescendants(node: SyntaxNode, visited: Set<number>): void {\n visited.add(node.id);\n for (const child of node.namedChildren) {\n markDescendants(child, visited);\n }\n}\n\n/**\n * Try to match a target AST node against a pattern node.\n * Returns true if matched, populating `captures` with metavariable bindings.\n */\nfunction matchNode(\n target: SyntaxNode,\n pattern: PatternNode,\n captures: Record<string, string>,\n): boolean {\n switch (pattern.kind) {\n case \"metavar\": {\n // A metavar matches any single node\n const name = pattern.name;\n if (name in captures) {\n // Already captured — must match same text\n return captures[name] === target.text;\n }\n captures[name] = target.text;\n return true;\n }\n\n case \"variadic\": {\n // Variadic at the top level matches any single node\n // (variadic is really only meaningful in a children-list context)\n const name = pattern.name;\n if (name && name in captures) {\n return captures[name] === target.text;\n }\n if (name) captures[name] = target.text;\n return true;\n }\n\n case \"literal\": {\n // Must match node type\n if (target.type !== pattern.nodeType) return false;\n\n // Leaf node: must match text exactly\n if (pattern.text !== undefined) {\n return target.text === pattern.text;\n }\n\n // Branch node: use field-aware matching\n // Pattern children that have field names → match against target children with same field name\n // This allows the target to have extra children not mentioned in the pattern\n return matchChildrenFieldAware(target, pattern.children, captures);\n }\n }\n}\n\n/**\n * Match pattern children against target node's children using field-name-aware matching.\n *\n * Strategy:\n * 1. Pattern children WITH field names: find the target child with the same field name and match\n * 2. Pattern children WITHOUT field names: match positionally against unmatched target children\n * 3. Extra target children not mentioned in the pattern are allowed (implicit wildcards)\n */\nfunction matchChildrenFieldAware(\n targetNode: SyntaxNode,\n patternChildren: PatternNode[],\n captures: Record<string, string>,\n): boolean {\n // Separate pattern children into field-named and positional\n const fieldPatterns: PatternNode[] = [];\n const positionalPatterns: PatternNode[] = [];\n\n for (const pc of patternChildren) {\n if (pc.fieldName) {\n fieldPatterns.push(pc);\n } else {\n positionalPatterns.push(pc);\n }\n }\n\n // First, match all field-named pattern children\n for (const fp of fieldPatterns) {\n const targetChild = targetNode.childForFieldName(fp.fieldName!);\n if (!targetChild) return false;\n if (!matchNode(targetChild, fp, captures)) return false;\n }\n\n // If there are positional patterns, match them against the remaining unnamed target children\n if (positionalPatterns.length > 0) {\n // Get target children that aren't already matched by field names\n const matchedFieldNames = new Set(fieldPatterns.map(fp => fp.fieldName));\n const remainingTargets: SyntaxNode[] = [];\n for (const child of targetNode.namedChildren) {\n const childField = getChildFieldName(targetNode, child);\n if (!childField || !matchedFieldNames.has(childField)) {\n remainingTargets.push(child);\n }\n }\n\n return matchChildrenPositional(remainingTargets, 0, positionalPatterns, 0, captures);\n }\n\n return true;\n}\n\n/** Get the field name of a child node within its parent */\nfunction getChildFieldName(parent: SyntaxNode, child: SyntaxNode): string | null {\n for (let i = 0; i < parent.childCount; i++) {\n const c = parent.child(i);\n if (c && c.id === child.id) {\n return parent.fieldNameForChild(i);\n }\n }\n return null;\n}\n\n/**\n * Match pattern children positionally against target children.\n * Handles variadic patterns that can match zero or more consecutive children.\n * Extra target children at the end are allowed (pattern doesn't need to cover all children).\n */\nfunction matchChildrenPositional(\n targets: SyntaxNode[],\n ti: number,\n patterns: PatternNode[],\n pi: number,\n captures: Record<string, string>,\n): boolean {\n // All patterns consumed — success (extra targets are OK)\n if (pi >= patterns.length) return true;\n\n const pat = patterns[pi];\n\n // Variadic pattern: try matching 0, 1, 2, ... consecutive target nodes\n if (pat.kind === \"variadic\") {\n const isLast = pi === patterns.length - 1;\n\n // Optimization: if this is the last pattern, consume all remaining\n if (isLast) {\n const remainingText = targets.slice(ti).map(t => t.text).join(\", \");\n if (pat.name) {\n if (pat.name in captures && captures[pat.name] !== remainingText) return false;\n captures[pat.name] = remainingText;\n }\n return true;\n }\n\n // Try consuming 0..N target nodes\n for (let take = 0; take <= targets.length - ti; take++) {\n const captureSnapshot = { ...captures };\n const consumedText = targets.slice(ti, ti + take).map(t => t.text).join(\", \");\n\n if (pat.name) {\n if (pat.name in captureSnapshot && captureSnapshot[pat.name] !== consumedText) continue;\n captureSnapshot[pat.name] = consumedText;\n }\n\n if (matchChildrenPositional(targets, ti + take, patterns, pi + 1, captureSnapshot)) {\n // Success — commit captures\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n return false;\n }\n\n // Non-variadic pattern: must match the current target\n if (ti >= targets.length) return false;\n\n const captureSnapshot = { ...captures };\n if (matchNode(targets[ti], pat, captureSnapshot)) {\n if (matchChildrenPositional(targets, ti + 1, patterns, pi + 1, captureSnapshot)) {\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n\n return false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"search-engine.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,WAAW,WAAW;IAC1B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAQD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,iBAAiB,EAC7B,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB,GACL,OAAO,CAAC,WAAW,EAAE,CAAC,CA4CxB;AAID;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,iBAAiB,EAC7B,SAAS,GAAE,MAAM,EAAO,EACxB,QAAQ,GAAE,MAAwB,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB","sourcesContent":["// @ts-nocheck\n/**\n * Search Engine — run compiled patterns against source files and collect matches.\n *\n * Uses a recursive AST matcher: the target file's tree-sitter AST is walked\n * depth-first, and at each node we attempt to match the compiled pattern tree.\n * Metavariable nodes capture any single AST node; variadic nodes capture\n * zero-or-more siblings.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { resolve } from \"node:path\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport type Parser from \"web-tree-sitter\";\nimport type { TreeSitterManager } from \"./parser-manager.js\";\nimport type {\n CompiledPattern,\n PatternNode,\n} from \"./pattern-compiler.js\";\nimport { SKIP_DIRS, MAX_FILE_SIZE, MAX_INDEX_FILES } from \"../shared/constants.js\";\n\ntype SyntaxNode = Parser.SyntaxNode;\n\n// ── Result types ────────────────────────────────────────────────────────────\n\nexport interface SearchMatch {\n /** Absolute file path */\n file: string;\n /** 1-indexed line number */\n line: number;\n /** 1-indexed column */\n column: number;\n /** The matched source text */\n matchedText: string;\n /** SHA-256 of the full source snapshot used to find this match. */\n sourceHash: string;\n /** Text offset of match start */\n startIndex: number;\n /** Text offset of match end */\n endIndex: number;\n /** Metavariable bindings: name → captured text */\n captures: Record<string, string>;\n}\n\n// ── Directories to skip ─────────────────────────────────────────────────────\n\n// Shared constants imported from ../shared/constants.ts\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Search files for matches against a compiled pattern.\n */\nexport async function searchFiles(\n pattern: CompiledPattern,\n rootDir: string,\n treeSitter: TreeSitterManager,\n options: {\n path?: string;\n maxResults?: number;\n } = {},\n): Promise<SearchMatch[]> {\n const searchRoot = options.path ? resolve(rootDir, options.path) : rootDir;\n const maxResults = options.maxResults ?? 50;\n\n // Determine if searchRoot is a file or directory\n const stats = await stat(searchRoot);\n let files: string[];\n if (stats.isFile()) {\n files = [searchRoot];\n } else {\n files = await collectFilesByLanguage(searchRoot, pattern.languageId, treeSitter);\n }\n\n const matches: SearchMatch[] = [];\n\n for (const file of files) {\n if (matches.length >= maxResults) break;\n\n try {\n const content = await readFile(file, \"utf-8\");\n const tree = await treeSitter.parseWithLanguage(file, content, pattern.languageId);\n if (!tree) continue;\n\n const sourceHash = createHash(\"sha256\").update(content).digest(\"hex\");\n const fileMatches = findMatches(tree.rootNode, pattern.root);\n for (const m of fileMatches) {\n if (matches.length >= maxResults) break;\n matches.push({\n file,\n sourceHash,\n line: m.node.startPosition.row + 1,\n column: m.node.startPosition.column + 1,\n matchedText: m.node.text,\n startIndex: m.node.startIndex,\n endIndex: m.node.endIndex,\n captures: m.captures,\n });\n }\n } catch {\n // Skip unreadable files\n }\n }\n\n return matches;\n}\n\n// ── File collection ─────────────────────────────────────────────────────────\n\n/**\n * Collect all files matching a given language under a directory.\n */\nexport async function collectFilesByLanguage(\n dir: string,\n languageId: string,\n treeSitter: TreeSitterManager,\n collected: string[] = [],\n maxFiles: number = MAX_INDEX_FILES,\n): Promise<string[]> {\n if (collected.length >= maxFiles) return collected;\n\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (collected.length >= maxFiles) break;\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(\".\")) continue;\n await collectFilesByLanguage(resolve(dir, entry.name), languageId, treeSitter, collected, maxFiles);\n } else if (entry.isFile()) {\n const fileLang = treeSitter.getLanguageId(entry.name);\n if (fileLang === languageId) {\n const filePath = resolve(dir, entry.name);\n try {\n const s = await stat(filePath);\n if (s.size <= MAX_FILE_SIZE) {\n collected.push(filePath);\n }\n } catch {}\n }\n }\n }\n } catch {\n // Permission denied or other IO error — skip\n }\n\n return collected;\n}\n\n// ── Matching engine ─────────────────────────────────────────────────────────\n\ninterface RawMatch {\n node: SyntaxNode;\n captures: Record<string, string>;\n}\n\n/**\n * Find all non-overlapping matches of the pattern in the target AST.\n * Walks the tree depth-first, attempting to match at each node.\n */\nfunction findMatches(root: SyntaxNode, pattern: PatternNode): RawMatch[] {\n const matches: RawMatch[] = [];\n const visited = new Set<number>(); // node ids already part of a match\n\n function walk(node: SyntaxNode): void {\n if (visited.has(node.id)) return;\n\n const captures: Record<string, string> = {};\n if (matchNode(node, pattern, captures)) {\n matches.push({ node, captures });\n // Mark all descendant nodes as visited to prevent overlapping matches\n markDescendants(node, visited);\n return; // Don't recurse into matched subtree\n }\n\n // Recurse into children\n for (const child of node.namedChildren) {\n walk(child);\n }\n }\n\n walk(root);\n return matches;\n}\n\nfunction markDescendants(node: SyntaxNode, visited: Set<number>): void {\n visited.add(node.id);\n for (const child of node.namedChildren) {\n markDescendants(child, visited);\n }\n}\n\n/**\n * Try to match a target AST node against a pattern node.\n * Returns true if matched, populating `captures` with metavariable bindings.\n */\nfunction matchNode(\n target: SyntaxNode,\n pattern: PatternNode,\n captures: Record<string, string>,\n): boolean {\n switch (pattern.kind) {\n case \"metavar\": {\n // A metavar matches any single node\n const name = pattern.name;\n if (name in captures) {\n // Already captured — must match same text\n return captures[name] === target.text;\n }\n captures[name] = target.text;\n return true;\n }\n\n case \"variadic\": {\n // Variadic at the top level matches any single node\n // (variadic is really only meaningful in a children-list context)\n const name = pattern.name;\n if (name && name in captures) {\n return captures[name] === target.text;\n }\n if (name) captures[name] = target.text;\n return true;\n }\n\n case \"literal\": {\n // Must match node type\n if (target.type !== pattern.nodeType) return false;\n\n // Leaf node: must match text exactly\n if (pattern.text !== undefined) {\n return target.text === pattern.text;\n }\n\n // Branch node: use field-aware matching\n // Pattern children that have field names → match against target children with same field name\n // This allows the target to have extra children not mentioned in the pattern\n return matchChildrenFieldAware(target, pattern.children, captures);\n }\n }\n}\n\n/**\n * Match pattern children against target node's children using field-name-aware matching.\n *\n * Strategy:\n * 1. Pattern children WITH field names: find the target child with the same field name and match\n * 2. Pattern children WITHOUT field names: match positionally against unmatched target children\n * 3. Extra target children not mentioned in the pattern are allowed (implicit wildcards)\n */\nfunction matchChildrenFieldAware(\n targetNode: SyntaxNode,\n patternChildren: PatternNode[],\n captures: Record<string, string>,\n): boolean {\n // Separate pattern children into field-named and positional\n const fieldPatterns: PatternNode[] = [];\n const positionalPatterns: PatternNode[] = [];\n\n for (const pc of patternChildren) {\n if (pc.fieldName) {\n fieldPatterns.push(pc);\n } else {\n positionalPatterns.push(pc);\n }\n }\n\n // First, match all field-named pattern children\n for (const fp of fieldPatterns) {\n const targetChild = targetNode.childForFieldName(fp.fieldName!);\n if (!targetChild) return false;\n if (!matchNode(targetChild, fp, captures)) return false;\n }\n\n // If there are positional patterns, match them against the remaining unnamed target children\n if (positionalPatterns.length > 0) {\n // Get target children that aren't already matched by field names\n const matchedFieldNames = new Set(fieldPatterns.map(fp => fp.fieldName));\n const remainingTargets: SyntaxNode[] = [];\n for (const child of targetNode.namedChildren) {\n const childField = getChildFieldName(targetNode, child);\n if (!childField || !matchedFieldNames.has(childField)) {\n remainingTargets.push(child);\n }\n }\n\n return matchChildrenPositional(remainingTargets, 0, positionalPatterns, 0, captures);\n }\n\n return true;\n}\n\n/** Get the field name of a child node within its parent */\nfunction getChildFieldName(parent: SyntaxNode, child: SyntaxNode): string | null {\n for (let i = 0; i < parent.childCount; i++) {\n const c = parent.child(i);\n if (c && c.id === child.id) {\n return parent.fieldNameForChild(i);\n }\n }\n return null;\n}\n\n/**\n * Match pattern children positionally against target children.\n * Handles variadic patterns that can match zero or more consecutive children.\n * Extra target children at the end are allowed (pattern doesn't need to cover all children).\n */\nfunction matchChildrenPositional(\n targets: SyntaxNode[],\n ti: number,\n patterns: PatternNode[],\n pi: number,\n captures: Record<string, string>,\n): boolean {\n // All patterns consumed — success (extra targets are OK)\n if (pi >= patterns.length) return true;\n\n const pat = patterns[pi];\n\n // Variadic pattern: try matching 0, 1, 2, ... consecutive target nodes\n if (pat.kind === \"variadic\") {\n const isLast = pi === patterns.length - 1;\n\n // Optimization: if this is the last pattern, consume all remaining\n if (isLast) {\n const remainingText = targets.slice(ti).map(t => t.text).join(\", \");\n if (pat.name) {\n if (pat.name in captures && captures[pat.name] !== remainingText) return false;\n captures[pat.name] = remainingText;\n }\n return true;\n }\n\n // Try consuming 0..N target nodes\n for (let take = 0; take <= targets.length - ti; take++) {\n const captureSnapshot = { ...captures };\n const consumedText = targets.slice(ti, ti + take).map(t => t.text).join(\", \");\n\n if (pat.name) {\n if (pat.name in captureSnapshot && captureSnapshot[pat.name] !== consumedText) continue;\n captureSnapshot[pat.name] = consumedText;\n }\n\n if (matchChildrenPositional(targets, ti + take, patterns, pi + 1, captureSnapshot)) {\n // Success — commit captures\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n return false;\n }\n\n // Non-variadic pattern: must match the current target\n if (ti >= targets.length) return false;\n\n const captureSnapshot = { ...captures };\n if (matchNode(targets[ti], pat, captureSnapshot)) {\n if (matchChildrenPositional(targets, ti + 1, patterns, pi + 1, captureSnapshot)) {\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n\n return false;\n}\n"]}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Metavariable nodes capture any single AST node; variadic nodes capture
|
|
8
8
|
* zero-or-more siblings.
|
|
9
9
|
*/
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
10
11
|
import { resolve } from "node:path";
|
|
11
12
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
12
13
|
import { SKIP_DIRS, MAX_FILE_SIZE, MAX_INDEX_FILES } from "../shared/constants.js";
|
|
@@ -37,12 +38,14 @@ export async function searchFiles(pattern, rootDir, treeSitter, options = {}) {
|
|
|
37
38
|
const tree = await treeSitter.parseWithLanguage(file, content, pattern.languageId);
|
|
38
39
|
if (!tree)
|
|
39
40
|
continue;
|
|
41
|
+
const sourceHash = createHash("sha256").update(content).digest("hex");
|
|
40
42
|
const fileMatches = findMatches(tree.rootNode, pattern.root);
|
|
41
43
|
for (const m of fileMatches) {
|
|
42
44
|
if (matches.length >= maxResults)
|
|
43
45
|
break;
|
|
44
46
|
matches.push({
|
|
45
47
|
file,
|
|
48
|
+
sourceHash,
|
|
46
49
|
line: m.node.startPosition.row + 1,
|
|
47
50
|
column: m.node.startPosition.column + 1,
|
|
48
51
|
matchedText: m.node.text,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-engine.js","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\n/**\n * Search Engine — run compiled patterns against source files and collect matches.\n *\n * Uses a recursive AST matcher: the target file's tree-sitter AST is walked\n * depth-first, and at each node we attempt to match the compiled pattern tree.\n * Metavariable nodes capture any single AST node; variadic nodes capture\n * zero-or-more siblings.\n */\n\nimport { resolve } from \"node:path\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport type Parser from \"web-tree-sitter\";\nimport type { TreeSitterManager } from \"./parser-manager.js\";\nimport type {\n CompiledPattern,\n PatternNode,\n} from \"./pattern-compiler.js\";\nimport { SKIP_DIRS, MAX_FILE_SIZE, MAX_INDEX_FILES } from \"../shared/constants.js\";\n\ntype SyntaxNode = Parser.SyntaxNode;\n\n// ── Result types ────────────────────────────────────────────────────────────\n\nexport interface SearchMatch {\n /** Absolute file path */\n file: string;\n /** 1-indexed line number */\n line: number;\n /** 1-indexed column */\n column: number;\n /** The matched source text */\n matchedText: string;\n /** Byte offset of match start */\n startIndex: number;\n /** Byte offset of match end */\n endIndex: number;\n /** Metavariable bindings: name → captured text */\n captures: Record<string, string>;\n}\n\n// ── Directories to skip ─────────────────────────────────────────────────────\n\n// Shared constants imported from ../shared/constants.ts\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Search files for matches against a compiled pattern.\n */\nexport async function searchFiles(\n pattern: CompiledPattern,\n rootDir: string,\n treeSitter: TreeSitterManager,\n options: {\n path?: string;\n maxResults?: number;\n } = {},\n): Promise<SearchMatch[]> {\n const searchRoot = options.path ? resolve(rootDir, options.path) : rootDir;\n const maxResults = options.maxResults ?? 50;\n\n // Determine if searchRoot is a file or directory\n const stats = await stat(searchRoot);\n let files: string[];\n if (stats.isFile()) {\n files = [searchRoot];\n } else {\n files = await collectFilesByLanguage(searchRoot, pattern.languageId, treeSitter);\n }\n\n const matches: SearchMatch[] = [];\n\n for (const file of files) {\n if (matches.length >= maxResults) break;\n\n try {\n const content = await readFile(file, \"utf-8\");\n const tree = await treeSitter.parseWithLanguage(file, content, pattern.languageId);\n if (!tree) continue;\n\n const fileMatches = findMatches(tree.rootNode, pattern.root);\n for (const m of fileMatches) {\n if (matches.length >= maxResults) break;\n matches.push({\n file,\n line: m.node.startPosition.row + 1,\n column: m.node.startPosition.column + 1,\n matchedText: m.node.text,\n startIndex: m.node.startIndex,\n endIndex: m.node.endIndex,\n captures: m.captures,\n });\n }\n } catch {\n // Skip unreadable files\n }\n }\n\n return matches;\n}\n\n// ── File collection ─────────────────────────────────────────────────────────\n\n/**\n * Collect all files matching a given language under a directory.\n */\nexport async function collectFilesByLanguage(\n dir: string,\n languageId: string,\n treeSitter: TreeSitterManager,\n collected: string[] = [],\n maxFiles: number = MAX_INDEX_FILES,\n): Promise<string[]> {\n if (collected.length >= maxFiles) return collected;\n\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (collected.length >= maxFiles) break;\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(\".\")) continue;\n await collectFilesByLanguage(resolve(dir, entry.name), languageId, treeSitter, collected, maxFiles);\n } else if (entry.isFile()) {\n const fileLang = treeSitter.getLanguageId(entry.name);\n if (fileLang === languageId) {\n const filePath = resolve(dir, entry.name);\n try {\n const s = await stat(filePath);\n if (s.size <= MAX_FILE_SIZE) {\n collected.push(filePath);\n }\n } catch {}\n }\n }\n }\n } catch {\n // Permission denied or other IO error — skip\n }\n\n return collected;\n}\n\n// ── Matching engine ─────────────────────────────────────────────────────────\n\ninterface RawMatch {\n node: SyntaxNode;\n captures: Record<string, string>;\n}\n\n/**\n * Find all non-overlapping matches of the pattern in the target AST.\n * Walks the tree depth-first, attempting to match at each node.\n */\nfunction findMatches(root: SyntaxNode, pattern: PatternNode): RawMatch[] {\n const matches: RawMatch[] = [];\n const visited = new Set<number>(); // node ids already part of a match\n\n function walk(node: SyntaxNode): void {\n if (visited.has(node.id)) return;\n\n const captures: Record<string, string> = {};\n if (matchNode(node, pattern, captures)) {\n matches.push({ node, captures });\n // Mark all descendant nodes as visited to prevent overlapping matches\n markDescendants(node, visited);\n return; // Don't recurse into matched subtree\n }\n\n // Recurse into children\n for (const child of node.namedChildren) {\n walk(child);\n }\n }\n\n walk(root);\n return matches;\n}\n\nfunction markDescendants(node: SyntaxNode, visited: Set<number>): void {\n visited.add(node.id);\n for (const child of node.namedChildren) {\n markDescendants(child, visited);\n }\n}\n\n/**\n * Try to match a target AST node against a pattern node.\n * Returns true if matched, populating `captures` with metavariable bindings.\n */\nfunction matchNode(\n target: SyntaxNode,\n pattern: PatternNode,\n captures: Record<string, string>,\n): boolean {\n switch (pattern.kind) {\n case \"metavar\": {\n // A metavar matches any single node\n const name = pattern.name;\n if (name in captures) {\n // Already captured — must match same text\n return captures[name] === target.text;\n }\n captures[name] = target.text;\n return true;\n }\n\n case \"variadic\": {\n // Variadic at the top level matches any single node\n // (variadic is really only meaningful in a children-list context)\n const name = pattern.name;\n if (name && name in captures) {\n return captures[name] === target.text;\n }\n if (name) captures[name] = target.text;\n return true;\n }\n\n case \"literal\": {\n // Must match node type\n if (target.type !== pattern.nodeType) return false;\n\n // Leaf node: must match text exactly\n if (pattern.text !== undefined) {\n return target.text === pattern.text;\n }\n\n // Branch node: use field-aware matching\n // Pattern children that have field names → match against target children with same field name\n // This allows the target to have extra children not mentioned in the pattern\n return matchChildrenFieldAware(target, pattern.children, captures);\n }\n }\n}\n\n/**\n * Match pattern children against target node's children using field-name-aware matching.\n *\n * Strategy:\n * 1. Pattern children WITH field names: find the target child with the same field name and match\n * 2. Pattern children WITHOUT field names: match positionally against unmatched target children\n * 3. Extra target children not mentioned in the pattern are allowed (implicit wildcards)\n */\nfunction matchChildrenFieldAware(\n targetNode: SyntaxNode,\n patternChildren: PatternNode[],\n captures: Record<string, string>,\n): boolean {\n // Separate pattern children into field-named and positional\n const fieldPatterns: PatternNode[] = [];\n const positionalPatterns: PatternNode[] = [];\n\n for (const pc of patternChildren) {\n if (pc.fieldName) {\n fieldPatterns.push(pc);\n } else {\n positionalPatterns.push(pc);\n }\n }\n\n // First, match all field-named pattern children\n for (const fp of fieldPatterns) {\n const targetChild = targetNode.childForFieldName(fp.fieldName!);\n if (!targetChild) return false;\n if (!matchNode(targetChild, fp, captures)) return false;\n }\n\n // If there are positional patterns, match them against the remaining unnamed target children\n if (positionalPatterns.length > 0) {\n // Get target children that aren't already matched by field names\n const matchedFieldNames = new Set(fieldPatterns.map(fp => fp.fieldName));\n const remainingTargets: SyntaxNode[] = [];\n for (const child of targetNode.namedChildren) {\n const childField = getChildFieldName(targetNode, child);\n if (!childField || !matchedFieldNames.has(childField)) {\n remainingTargets.push(child);\n }\n }\n\n return matchChildrenPositional(remainingTargets, 0, positionalPatterns, 0, captures);\n }\n\n return true;\n}\n\n/** Get the field name of a child node within its parent */\nfunction getChildFieldName(parent: SyntaxNode, child: SyntaxNode): string | null {\n for (let i = 0; i < parent.childCount; i++) {\n const c = parent.child(i);\n if (c && c.id === child.id) {\n return parent.fieldNameForChild(i);\n }\n }\n return null;\n}\n\n/**\n * Match pattern children positionally against target children.\n * Handles variadic patterns that can match zero or more consecutive children.\n * Extra target children at the end are allowed (pattern doesn't need to cover all children).\n */\nfunction matchChildrenPositional(\n targets: SyntaxNode[],\n ti: number,\n patterns: PatternNode[],\n pi: number,\n captures: Record<string, string>,\n): boolean {\n // All patterns consumed — success (extra targets are OK)\n if (pi >= patterns.length) return true;\n\n const pat = patterns[pi];\n\n // Variadic pattern: try matching 0, 1, 2, ... consecutive target nodes\n if (pat.kind === \"variadic\") {\n const isLast = pi === patterns.length - 1;\n\n // Optimization: if this is the last pattern, consume all remaining\n if (isLast) {\n const remainingText = targets.slice(ti).map(t => t.text).join(\", \");\n if (pat.name) {\n if (pat.name in captures && captures[pat.name] !== remainingText) return false;\n captures[pat.name] = remainingText;\n }\n return true;\n }\n\n // Try consuming 0..N target nodes\n for (let take = 0; take <= targets.length - ti; take++) {\n const captureSnapshot = { ...captures };\n const consumedText = targets.slice(ti, ti + take).map(t => t.text).join(\", \");\n\n if (pat.name) {\n if (pat.name in captureSnapshot && captureSnapshot[pat.name] !== consumedText) continue;\n captureSnapshot[pat.name] = consumedText;\n }\n\n if (matchChildrenPositional(targets, ti + take, patterns, pi + 1, captureSnapshot)) {\n // Success — commit captures\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n return false;\n }\n\n // Non-variadic pattern: must match the current target\n if (ti >= targets.length) return false;\n\n const captureSnapshot = { ...captures };\n if (matchNode(targets[ti], pat, captureSnapshot)) {\n if (matchChildrenPositional(targets, ti + 1, patterns, pi + 1, captureSnapshot)) {\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n\n return false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"search-engine.js","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.ts"],"names":[],"mappings":"AAAA,cAAc;AACd;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAO3D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAyBnF,6LAA+E;AAE/E,wDAAwD;AAExD,+MAA+E;AAE/E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAwB,EACxB,OAAe,EACf,UAA6B,EAC7B,OAAO,GAGH,EAAE,EACkB;IACxB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC3E,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAE5C,iDAAiD;IACjD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,KAAe,CAAC;IACpB,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACnB,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,MAAM,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;YAAE,MAAM;QAExC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YACnF,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACtE,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7D,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;gBAC5B,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;oBAAE,MAAM;gBACxC,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI;oBACJ,UAAU;oBACV,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC;oBAClC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;oBACvC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;oBACxB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU;oBAC7B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;oBACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ;iBACrB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AAAA,CAChB;AAED,qMAA+E;AAE/E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,GAAW,EACX,UAAkB,EAClB,UAA6B,EAC7B,SAAS,GAAa,EAAE,EACxB,QAAQ,GAAW,eAAe,EACf;IACnB,IAAI,SAAS,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,SAAS,CAAC,MAAM,IAAI,QAAQ;gBAAE,MAAM;YAExC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,SAAS;gBACtE,MAAM,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;YACtG,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACtD,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;oBAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC1C,IAAI,CAAC;wBACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;wBAC/B,IAAI,CAAC,CAAC,IAAI,IAAI,aAAa,EAAE,CAAC;4BAC5B,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;wBAC3B,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+CAA6C;IAC/C,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CAClB;AASD;;;GAGG;AACH,SAAS,WAAW,CAAC,IAAgB,EAAE,OAAoB,EAAc;IACvE,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC,CAAC,mCAAmC;IAEtE,SAAS,IAAI,CAAC,IAAgB,EAAQ;QACpC,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO;QAEjC,MAAM,QAAQ,GAA2B,EAAE,CAAC;QAC5C,IAAI,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YACjC,sEAAsE;YACtE,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC/B,OAAO,CAAC,qCAAqC;QAC/C,CAAC;QAED,wBAAwB;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IAAA,CACF;IAED,IAAI,CAAC,IAAI,CAAC,CAAC;IACX,OAAO,OAAO,CAAC;AAAA,CAChB;AAED,SAAS,eAAe,CAAC,IAAgB,EAAE,OAAoB,EAAQ;IACrE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC;AAAA,CACF;AAED;;;GAGG;AACH,SAAS,SAAS,CAChB,MAAkB,EAClB,OAAoB,EACpB,QAAgC,EACvB;IACT,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,SAAS,EAAE,CAAC;YACf,oCAAoC;YACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;gBACrB,4CAA0C;gBAC1C,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC;YACxC,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,UAAU,EAAE,CAAC;YAChB,oDAAoD;YACpD,kEAAkE;YAClE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,IAAI,IAAI,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC7B,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC;YACxC,CAAC;YACD,IAAI,IAAI;gBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,SAAS,EAAE,CAAC;YACf,uBAAuB;YACvB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAEnD,qCAAqC;YACrC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;YACtC,CAAC;YAED,wCAAwC;YACxC,gGAA8F;YAC9F,6EAA6E;YAC7E,OAAO,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;AAAA,CACF;AAED;;;;;;;GAOG;AACH,SAAS,uBAAuB,CAC9B,UAAsB,EACtB,eAA8B,EAC9B,QAAgC,EACvB;IACT,4DAA4D;IAC5D,MAAM,aAAa,GAAkB,EAAE,CAAC;IACxC,MAAM,kBAAkB,GAAkB,EAAE,CAAC;IAE7C,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;YACjB,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC,SAAU,CAAC,CAAC;QAChE,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,EAAE,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;IAC1D,CAAC;IAED,6FAA6F;IAC7F,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,iEAAiE;QACjE,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QACzE,MAAM,gBAAgB,GAAiB,EAAE,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;YAC7C,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,UAAU,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBACtD,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,OAAO,uBAAuB,CAAC,gBAAgB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvF,CAAC;IAED,OAAO,IAAI,CAAC;AAAA,CACb;AAED,2DAA2D;AAC3D,SAAS,iBAAiB,CAAC,MAAkB,EAAE,KAAiB,EAAiB;IAC/E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,EAAE,CAAC;YAC3B,OAAO,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACb;AAED;;;;GAIG;AACH,SAAS,uBAAuB,CAC9B,OAAqB,EACrB,EAAU,EACV,QAAuB,EACvB,EAAU,EACV,QAAgC,EACvB;IACT,2DAAyD;IACzD,IAAI,EAAE,IAAI,QAAQ,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEzB,uEAAuE;IACvE,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,EAAE,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QAE1C,mEAAmE;QACnE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpE,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBACb,IAAI,GAAG,CAAC,IAAI,IAAI,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,aAAa;oBAAE,OAAO,KAAK,CAAC;gBAC/E,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC;YACrC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kCAAkC;QAClC,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;YACvD,MAAM,eAAe,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YACxC,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE9E,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBACb,IAAI,GAAG,CAAC,IAAI,IAAI,eAAe,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,YAAY;oBAAE,SAAS;gBACxF,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC;YAC3C,CAAC;YAED,IAAI,uBAAuB,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;gBACnF,8BAA4B;gBAC5B,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;gBACzC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sDAAsD;IACtD,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEvC,MAAM,eAAe,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IACxC,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,eAAe,CAAC,EAAE,CAAC;QACjD,IAAI,uBAAuB,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;YAChF,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACd","sourcesContent":["// @ts-nocheck\n/**\n * Search Engine — run compiled patterns against source files and collect matches.\n *\n * Uses a recursive AST matcher: the target file's tree-sitter AST is walked\n * depth-first, and at each node we attempt to match the compiled pattern tree.\n * Metavariable nodes capture any single AST node; variadic nodes capture\n * zero-or-more siblings.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { resolve } from \"node:path\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport type Parser from \"web-tree-sitter\";\nimport type { TreeSitterManager } from \"./parser-manager.js\";\nimport type {\n CompiledPattern,\n PatternNode,\n} from \"./pattern-compiler.js\";\nimport { SKIP_DIRS, MAX_FILE_SIZE, MAX_INDEX_FILES } from \"../shared/constants.js\";\n\ntype SyntaxNode = Parser.SyntaxNode;\n\n// ── Result types ────────────────────────────────────────────────────────────\n\nexport interface SearchMatch {\n /** Absolute file path */\n file: string;\n /** 1-indexed line number */\n line: number;\n /** 1-indexed column */\n column: number;\n /** The matched source text */\n matchedText: string;\n /** SHA-256 of the full source snapshot used to find this match. */\n sourceHash: string;\n /** Text offset of match start */\n startIndex: number;\n /** Text offset of match end */\n endIndex: number;\n /** Metavariable bindings: name → captured text */\n captures: Record<string, string>;\n}\n\n// ── Directories to skip ─────────────────────────────────────────────────────\n\n// Shared constants imported from ../shared/constants.ts\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Search files for matches against a compiled pattern.\n */\nexport async function searchFiles(\n pattern: CompiledPattern,\n rootDir: string,\n treeSitter: TreeSitterManager,\n options: {\n path?: string;\n maxResults?: number;\n } = {},\n): Promise<SearchMatch[]> {\n const searchRoot = options.path ? resolve(rootDir, options.path) : rootDir;\n const maxResults = options.maxResults ?? 50;\n\n // Determine if searchRoot is a file or directory\n const stats = await stat(searchRoot);\n let files: string[];\n if (stats.isFile()) {\n files = [searchRoot];\n } else {\n files = await collectFilesByLanguage(searchRoot, pattern.languageId, treeSitter);\n }\n\n const matches: SearchMatch[] = [];\n\n for (const file of files) {\n if (matches.length >= maxResults) break;\n\n try {\n const content = await readFile(file, \"utf-8\");\n const tree = await treeSitter.parseWithLanguage(file, content, pattern.languageId);\n if (!tree) continue;\n\n const sourceHash = createHash(\"sha256\").update(content).digest(\"hex\");\n const fileMatches = findMatches(tree.rootNode, pattern.root);\n for (const m of fileMatches) {\n if (matches.length >= maxResults) break;\n matches.push({\n file,\n sourceHash,\n line: m.node.startPosition.row + 1,\n column: m.node.startPosition.column + 1,\n matchedText: m.node.text,\n startIndex: m.node.startIndex,\n endIndex: m.node.endIndex,\n captures: m.captures,\n });\n }\n } catch {\n // Skip unreadable files\n }\n }\n\n return matches;\n}\n\n// ── File collection ─────────────────────────────────────────────────────────\n\n/**\n * Collect all files matching a given language under a directory.\n */\nexport async function collectFilesByLanguage(\n dir: string,\n languageId: string,\n treeSitter: TreeSitterManager,\n collected: string[] = [],\n maxFiles: number = MAX_INDEX_FILES,\n): Promise<string[]> {\n if (collected.length >= maxFiles) return collected;\n\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (collected.length >= maxFiles) break;\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(\".\")) continue;\n await collectFilesByLanguage(resolve(dir, entry.name), languageId, treeSitter, collected, maxFiles);\n } else if (entry.isFile()) {\n const fileLang = treeSitter.getLanguageId(entry.name);\n if (fileLang === languageId) {\n const filePath = resolve(dir, entry.name);\n try {\n const s = await stat(filePath);\n if (s.size <= MAX_FILE_SIZE) {\n collected.push(filePath);\n }\n } catch {}\n }\n }\n }\n } catch {\n // Permission denied or other IO error — skip\n }\n\n return collected;\n}\n\n// ── Matching engine ─────────────────────────────────────────────────────────\n\ninterface RawMatch {\n node: SyntaxNode;\n captures: Record<string, string>;\n}\n\n/**\n * Find all non-overlapping matches of the pattern in the target AST.\n * Walks the tree depth-first, attempting to match at each node.\n */\nfunction findMatches(root: SyntaxNode, pattern: PatternNode): RawMatch[] {\n const matches: RawMatch[] = [];\n const visited = new Set<number>(); // node ids already part of a match\n\n function walk(node: SyntaxNode): void {\n if (visited.has(node.id)) return;\n\n const captures: Record<string, string> = {};\n if (matchNode(node, pattern, captures)) {\n matches.push({ node, captures });\n // Mark all descendant nodes as visited to prevent overlapping matches\n markDescendants(node, visited);\n return; // Don't recurse into matched subtree\n }\n\n // Recurse into children\n for (const child of node.namedChildren) {\n walk(child);\n }\n }\n\n walk(root);\n return matches;\n}\n\nfunction markDescendants(node: SyntaxNode, visited: Set<number>): void {\n visited.add(node.id);\n for (const child of node.namedChildren) {\n markDescendants(child, visited);\n }\n}\n\n/**\n * Try to match a target AST node against a pattern node.\n * Returns true if matched, populating `captures` with metavariable bindings.\n */\nfunction matchNode(\n target: SyntaxNode,\n pattern: PatternNode,\n captures: Record<string, string>,\n): boolean {\n switch (pattern.kind) {\n case \"metavar\": {\n // A metavar matches any single node\n const name = pattern.name;\n if (name in captures) {\n // Already captured — must match same text\n return captures[name] === target.text;\n }\n captures[name] = target.text;\n return true;\n }\n\n case \"variadic\": {\n // Variadic at the top level matches any single node\n // (variadic is really only meaningful in a children-list context)\n const name = pattern.name;\n if (name && name in captures) {\n return captures[name] === target.text;\n }\n if (name) captures[name] = target.text;\n return true;\n }\n\n case \"literal\": {\n // Must match node type\n if (target.type !== pattern.nodeType) return false;\n\n // Leaf node: must match text exactly\n if (pattern.text !== undefined) {\n return target.text === pattern.text;\n }\n\n // Branch node: use field-aware matching\n // Pattern children that have field names → match against target children with same field name\n // This allows the target to have extra children not mentioned in the pattern\n return matchChildrenFieldAware(target, pattern.children, captures);\n }\n }\n}\n\n/**\n * Match pattern children against target node's children using field-name-aware matching.\n *\n * Strategy:\n * 1. Pattern children WITH field names: find the target child with the same field name and match\n * 2. Pattern children WITHOUT field names: match positionally against unmatched target children\n * 3. Extra target children not mentioned in the pattern are allowed (implicit wildcards)\n */\nfunction matchChildrenFieldAware(\n targetNode: SyntaxNode,\n patternChildren: PatternNode[],\n captures: Record<string, string>,\n): boolean {\n // Separate pattern children into field-named and positional\n const fieldPatterns: PatternNode[] = [];\n const positionalPatterns: PatternNode[] = [];\n\n for (const pc of patternChildren) {\n if (pc.fieldName) {\n fieldPatterns.push(pc);\n } else {\n positionalPatterns.push(pc);\n }\n }\n\n // First, match all field-named pattern children\n for (const fp of fieldPatterns) {\n const targetChild = targetNode.childForFieldName(fp.fieldName!);\n if (!targetChild) return false;\n if (!matchNode(targetChild, fp, captures)) return false;\n }\n\n // If there are positional patterns, match them against the remaining unnamed target children\n if (positionalPatterns.length > 0) {\n // Get target children that aren't already matched by field names\n const matchedFieldNames = new Set(fieldPatterns.map(fp => fp.fieldName));\n const remainingTargets: SyntaxNode[] = [];\n for (const child of targetNode.namedChildren) {\n const childField = getChildFieldName(targetNode, child);\n if (!childField || !matchedFieldNames.has(childField)) {\n remainingTargets.push(child);\n }\n }\n\n return matchChildrenPositional(remainingTargets, 0, positionalPatterns, 0, captures);\n }\n\n return true;\n}\n\n/** Get the field name of a child node within its parent */\nfunction getChildFieldName(parent: SyntaxNode, child: SyntaxNode): string | null {\n for (let i = 0; i < parent.childCount; i++) {\n const c = parent.child(i);\n if (c && c.id === child.id) {\n return parent.fieldNameForChild(i);\n }\n }\n return null;\n}\n\n/**\n * Match pattern children positionally against target children.\n * Handles variadic patterns that can match zero or more consecutive children.\n * Extra target children at the end are allowed (pattern doesn't need to cover all children).\n */\nfunction matchChildrenPositional(\n targets: SyntaxNode[],\n ti: number,\n patterns: PatternNode[],\n pi: number,\n captures: Record<string, string>,\n): boolean {\n // All patterns consumed — success (extra targets are OK)\n if (pi >= patterns.length) return true;\n\n const pat = patterns[pi];\n\n // Variadic pattern: try matching 0, 1, 2, ... consecutive target nodes\n if (pat.kind === \"variadic\") {\n const isLast = pi === patterns.length - 1;\n\n // Optimization: if this is the last pattern, consume all remaining\n if (isLast) {\n const remainingText = targets.slice(ti).map(t => t.text).join(\", \");\n if (pat.name) {\n if (pat.name in captures && captures[pat.name] !== remainingText) return false;\n captures[pat.name] = remainingText;\n }\n return true;\n }\n\n // Try consuming 0..N target nodes\n for (let take = 0; take <= targets.length - ti; take++) {\n const captureSnapshot = { ...captures };\n const consumedText = targets.slice(ti, ti + take).map(t => t.text).join(\", \");\n\n if (pat.name) {\n if (pat.name in captureSnapshot && captureSnapshot[pat.name] !== consumedText) continue;\n captureSnapshot[pat.name] = consumedText;\n }\n\n if (matchChildrenPositional(targets, ti + take, patterns, pi + 1, captureSnapshot)) {\n // Success — commit captures\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n return false;\n }\n\n // Non-variadic pattern: must match the current target\n if (ti >= targets.length) return false;\n\n const captureSnapshot = { ...captures };\n if (matchNode(targets[ti], pat, captureSnapshot)) {\n if (matchChildrenPositional(targets, ti + 1, patterns, pi + 1, captureSnapshot)) {\n Object.assign(captures, captureSnapshot);\n return true;\n }\n }\n\n return false;\n}\n"]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@ashx-j/lunr";
|
|
2
2
|
import type { McpExtensionState } from "./state.ts";
|
|
3
3
|
import type { McpAuthResult, McpConfig } from "./types.ts";
|
|
4
|
+
import { type McpAuthFlow } from "./mcp-auth-flow.ts";
|
|
4
5
|
export declare function showStatus(state: McpExtensionState, ctx: ExtensionContext): Promise<void>;
|
|
5
6
|
export declare function showTools(state: McpExtensionState, ctx: ExtensionContext): Promise<void>;
|
|
6
7
|
export declare function reconnectServers(state: McpExtensionState, ctx: ExtensionContext, targetServer?: string): Promise<void>;
|
|
7
|
-
export declare function authenticateServer(serverName: string, config: McpConfig, ctx: ExtensionContext): Promise<McpAuthResult>;
|
|
8
|
+
export declare function authenticateServer(serverName: string, config: McpConfig, ctx: ExtensionContext, authFlow: McpAuthFlow): Promise<McpAuthResult>;
|
|
8
9
|
export declare function logoutServer(serverName: string, state: McpExtensionState, ctx: ExtensionContext): Promise<{
|
|
9
10
|
ok: boolean;
|
|
10
11
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/builtin-extensions/pi-mcp-adapter/commands.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAA8D,MAAM,YAAY,CAAC;AAoBvH,wBAAsB,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC/F;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB9F;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,gBAAgB,EACrB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,aAAa,CAAC,CA0DxB;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAe3C;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,OAAO,CAAC;CACxB;AAoBD,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,gBAAgB,EACrB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,IAAI,GAAE,OAAO,GAAG,OAAiB,GAChC,OAAO,CAAC,eAAe,CAAC,CAsD1B;AAwCD,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,gBAAgB,EACrB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,eAAe,CAAC,CAsC1B;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,iBAAiB,EACxB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,gBAAgB,EACrB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,eAAe,CAAC,CAiC1B","sourcesContent":["// @ts-nocheck\nimport type { ExtensionAPI, ExtensionContext } from \"@ashx-j/lunr\";\nimport type { McpExtensionState } from \"./state.ts\";\nimport type { McpAuthResult, McpConfig, ServerEntry, McpPanelCallbacks, McpPanelResult, ImportKind } from \"./types.ts\";\nimport {\n ensureCompatibilityImports,\n getMcpDiscoverySummary,\n getServerProvenance,\n previewCompatibilityImports,\n previewSharedServerEntry,\n previewStarterProjectConfig,\n writeDirectToolsConfig,\n writeSharedServerEntry,\n writeStarterProjectConfig,\n} from \"./config.ts\";\nimport { lazyConnect, updateMetadataCache, updateStatusBar, getFailureAgeSeconds } from \"./init.ts\";\nimport { loadMetadataCache } from \"./metadata-cache.ts\";\nimport { buildToolMetadata } from \"./tool-metadata.ts\";\nimport { supportsOAuth, authenticate, removeAuth } from \"./mcp-auth-flow.ts\";\nimport { getAuthForUrl } from \"./mcp-auth.ts\";\nimport { loadOnboardingState, markSetupCompleted as persistSetupCompleted, markSharedConfigHintShown } from \"./onboarding-state.ts\";\nimport { openPath } from \"./utils.ts\";\n\nexport async function showStatus(state: McpExtensionState, ctx: ExtensionContext): Promise<void> {\n if (!ctx.hasUI) return;\n\n const lines: string[] = [\"MCP Server Status:\", \"\"];\n\n for (const name of Object.keys(state.config.mcpServers)) {\n const connection = state.manager.getConnection(name);\n const metadata = state.toolMetadata.get(name);\n const toolCount = metadata?.length ?? 0;\n const failedAgo = getFailureAgeSeconds(state, name);\n let status = \"not connected\";\n let statusIcon = \"○\";\n let failed = false;\n\n if (connection?.status === \"connected\") {\n status = \"connected\";\n statusIcon = \"✓\";\n } else if (connection?.status === \"needs-auth\") {\n status = \"needs auth\";\n statusIcon = \"⚠\";\n } else if (failedAgo !== null) {\n status = `failed ${failedAgo}s ago`;\n statusIcon = \"✗\";\n failed = true;\n } else if (metadata !== undefined) {\n status = \"cached\";\n }\n\n const toolSuffix = failed ? \"\" : ` (${toolCount} tools${status === \"cached\" ? \", cached\" : \"\"})`;\n lines.push(`${statusIcon} ${name}: ${status}${toolSuffix}`);\n }\n\n if (Object.keys(state.config.mcpServers).length === 0) {\n lines.push(\"No MCP servers configured\");\n lines.push(\"Run /mcp setup to adopt imports or scaffold a starter .mcp.json\");\n }\n\n ctx.ui.notify(lines.join(\"\\n\"), \"info\");\n}\n\nexport async function showTools(state: McpExtensionState, ctx: ExtensionContext): Promise<void> {\n if (!ctx.hasUI) return;\n\n const allTools = [...state.toolMetadata.values()].flat().map(m => m.name);\n\n if (allTools.length === 0) {\n ctx.ui.notify(\"No MCP tools available\", \"info\");\n return;\n }\n\n const lines = [\n \"MCP Tools:\",\n \"\",\n ...allTools.map(t => ` ${t}`),\n \"\",\n `Total: ${allTools.length} tools`,\n ];\n\n ctx.ui.notify(lines.join(\"\\n\"), \"info\");\n}\n\nexport async function reconnectServers(\n state: McpExtensionState,\n ctx: ExtensionContext,\n targetServer?: string\n): Promise<void> {\n if (targetServer && !state.config.mcpServers[targetServer]) {\n if (ctx.hasUI) {\n ctx.ui.notify(`Server \"${targetServer}\" not found in config`, \"error\");\n }\n return;\n }\n\n const entries = targetServer\n ? [[targetServer, state.config.mcpServers[targetServer]] as [string, ServerEntry]]\n : Object.entries(state.config.mcpServers);\n\n for (const [name, definition] of entries) {\n try {\n await state.manager.close(name);\n\n const connection = await state.manager.connect(name, definition);\n if (connection.status === \"needs-auth\") {\n if (ctx.hasUI) {\n ctx.ui.notify(`MCP: ${name} requires OAuth. Run /mcp-auth ${name} first.`, \"warning\");\n }\n continue;\n }\n const prefix = state.config.settings?.toolPrefix ?? \"server\";\n\n const { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix);\n state.toolMetadata.set(name, metadata);\n updateMetadataCache(state, name);\n state.failureTracker.delete(name);\n\n if (ctx.hasUI) {\n ctx.ui.notify(\n `MCP: Reconnected to ${name} (${connection.tools.length} tools, ${connection.resources.length} resources)`,\n \"info\"\n );\n if (failedTools.length > 0) {\n ctx.ui.notify(`MCP: ${name} - ${failedTools.length} tools skipped`, \"warning\");\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n state.failureTracker.set(name, Date.now());\n if (ctx.hasUI) {\n ctx.ui.notify(`MCP: Failed to reconnect to ${name}: ${message}`, \"error\");\n }\n }\n }\n\n updateStatusBar(state);\n}\n\nexport async function authenticateServer(\n serverName: string,\n config: McpConfig,\n ctx: ExtensionContext\n): Promise<McpAuthResult> {\n if (!ctx.hasUI) return { ok: false, message: \"OAuth authentication requires an interactive session.\" };\n\n const definition = config.mcpServers[serverName];\n if (!definition) {\n const message = `Server \"${serverName}\" not found in config`;\n ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n }\n\n if (!supportsOAuth(definition)) {\n const message = `Server \"${serverName}\" does not use OAuth authentication. Set \"auth\": \"oauth\" or omit auth for auto-detection.`;\n ctx.ui.notify(\n `Server \"${serverName}\" does not use OAuth authentication.\\n` +\n `Set \"auth\": \"oauth\" or omit auth for auto-detection.`,\n \"error\"\n );\n return { ok: false, message };\n }\n\n if (!definition.url) {\n const message = `Server \"${serverName}\" has no URL configured (OAuth requires HTTP transport)`;\n ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n }\n\n try {\n ctx.ui.setStatus(\"mcp-auth\", `Authenticating ${serverName}...`);\n const status = await authenticate(serverName, definition.url, definition, {\n onAuthorizationUrl: (authorizationUrl) => {\n ctx.ui.notify(\n `Open this URL to authenticate ${serverName}:\\n\\n${authorizationUrl}\\n\\n` +\n \"After approving, return to Pi; the local callback will complete automatically.\",\n \"info\"\n );\n },\n });\n\n if (status === \"authenticated\") {\n const message = `OAuth authentication successful for \"${serverName}\"! Run /mcp reconnect ${serverName} to connect with the new token.`;\n ctx.ui.notify(\n `OAuth authentication successful for \"${serverName}\"!\\n` +\n `Run /mcp reconnect ${serverName} to connect with the new token.`,\n \"info\"\n );\n return { ok: true, message };\n }\n\n const message = `OAuth authentication failed for \"${serverName}\".`;\n ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n ctx.ui.notify(`Failed to authenticate \"${serverName}\": ${message}`, \"error\");\n return { ok: false, message };\n } finally {\n ctx.ui.setStatus(\"mcp-auth\", undefined);\n }\n}\n\nexport async function logoutServer(\n serverName: string,\n state: McpExtensionState,\n ctx: ExtensionContext\n): Promise<{ ok: boolean; message: string }> {\n const definition = state.config.mcpServers[serverName];\n if (!definition) {\n const message = `Server \"${serverName}\" not found in config`;\n if (ctx.hasUI) ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n }\n\n await removeAuth(serverName);\n await state.manager.close(serverName);\n updateStatusBar(state);\n\n const message = `OAuth credentials cleared for \"${serverName}\". Run /mcp-auth ${serverName} to authenticate again.`;\n if (ctx.hasUI) ctx.ui.notify(message, \"info\");\n return { ok: true, message };\n}\n\nexport interface PanelFlowResult {\n configChanged: boolean;\n}\n\nfunction buildSharedConfigNoticeLines(configOverridePath: string | undefined, cwd: string): { lines: string[]; fingerprint: string | null } {\n const discovery = getMcpDiscoverySummary(configOverridePath, cwd);\n const onboardingState = loadOnboardingState();\n if (!discovery.hasSharedServers || onboardingState.sharedConfigHintShown) {\n return { lines: [], fingerprint: null };\n }\n\n const sharedSources = discovery.sources.filter((source) => source.kind === \"shared\" && source.serverCount > 0);\n const sourceList = sharedSources.map((source) => source.path).join(\", \");\n return {\n lines: [\n `Using standard MCP config from ${sourceList}.`,\n \"Pi only writes compatibility imports and adapter-specific overrides into Pi-owned files when needed.\",\n ],\n fingerprint: discovery.fingerprint,\n };\n}\n\nexport async function openMcpSetup(\n _state: McpExtensionState,\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n configOverridePath?: string,\n mode: \"empty\" | \"setup\" = \"setup\",\n): Promise<PanelFlowResult> {\n if (!ctx.hasUI) return { configChanged: false };\n\n const discovery = getMcpDiscoverySummary(configOverridePath, ctx.cwd);\n const onboardingState = loadOnboardingState();\n const { createMcpSetupPanel } = await import(\"./mcp-setup-panel.ts\");\n let configChanged = false;\n\n const callbacks = {\n previewImports: (imports: ImportKind[]) => previewCompatibilityImports(imports, configOverridePath),\n previewStarterProject: () => previewStarterProjectConfig(ctx.cwd),\n previewRepoPrompt: () => {\n const repoPrompt = getMcpDiscoverySummary(configOverridePath, ctx.cwd).repoPrompt;\n if (!repoPrompt.entry || !repoPrompt.targetPath || !repoPrompt.serverName) return null;\n return previewSharedServerEntry(repoPrompt.targetPath, repoPrompt.serverName, repoPrompt.entry);\n },\n adoptImports: async (imports: ImportKind[]) => {\n const result = ensureCompatibilityImports(imports, configOverridePath);\n if (result.added.length > 0) configChanged = true;\n return result;\n },\n scaffoldProjectConfig: async () => {\n const path = writeStarterProjectConfig(ctx.cwd);\n configChanged = true;\n return { path };\n },\n addRepoPrompt: async () => {\n const repoPrompt = getMcpDiscoverySummary(configOverridePath, ctx.cwd).repoPrompt;\n if (!repoPrompt.entry || !repoPrompt.targetPath || !repoPrompt.serverName) {\n throw new Error(\"RepoPrompt is not available to add from this setup screen.\");\n }\n const path = writeSharedServerEntry(repoPrompt.targetPath, repoPrompt.serverName, repoPrompt.entry);\n configChanged = true;\n return { path, serverName: repoPrompt.serverName };\n },\n openPath: async (targetPath: string) => {\n await openPath(pi, targetPath);\n },\n markSetupCompleted: () => {\n persistSetupCompleted(discovery.fingerprint);\n },\n };\n\n return new Promise<PanelFlowResult>((resolve) => {\n ctx.ui.custom(\n (tui, _theme, keybindings, done) => {\n return createMcpSetupPanel(discovery, callbacks, { mode, onboardingState, keybindings }, tui, () => {\n done(undefined);\n resolve({ configChanged });\n });\n },\n { overlay: true, overlayOptions: { anchor: \"center\", width: 92 } },\n );\n });\n}\n\nfunction buildMcpPanelCallbacks(\n state: McpExtensionState,\n config: McpConfig,\n ctx: ExtensionContext,\n): McpPanelCallbacks {\n return {\n reconnect: (serverName: string) => lazyConnect(state, serverName),\n canAuthenticate: (serverName: string) => {\n const definition = config.mcpServers[serverName];\n return definition ? supportsOAuth(definition) : false;\n },\n authenticate: (serverName: string) => authenticateServer(serverName, config, ctx),\n getConnectionStatus: (serverName: string) => {\n const definition = config.mcpServers[serverName];\n const connection = state.manager.getConnection(serverName);\n if (connection?.status === \"needs-auth\") {\n return \"needs-auth\";\n }\n if (\n definition?.auth === \"oauth\"\n && definition.url\n && definition.oauth !== false\n && definition.oauth?.grantType !== \"client_credentials\"\n && !getAuthForUrl(serverName, definition.url)?.tokens\n ) {\n return \"needs-auth\";\n }\n if (connection?.status === \"connected\") return \"connected\";\n if (getFailureAgeSeconds(state, serverName) !== null) return \"failed\";\n return \"idle\";\n },\n refreshCacheAfterReconnect: (serverName: string) => {\n const freshCache = loadMetadataCache();\n return freshCache?.servers?.[serverName] ?? null;\n },\n };\n}\n\nexport async function openMcpPanel(\n state: McpExtensionState,\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n configOverridePath?: string,\n): Promise<PanelFlowResult> {\n if (Object.keys(state.config.mcpServers).length === 0) {\n return openMcpSetup(state, pi, ctx, configOverridePath, \"empty\");\n }\n\n const config = state.config;\n const cache = loadMetadataCache();\n const configPath = pi.getFlag(\"mcp-config\") as string | undefined ?? configOverridePath;\n const provenanceMap = getServerProvenance(configPath, ctx.cwd);\n const { lines: noticeLines, fingerprint } = buildSharedConfigNoticeLines(configPath, ctx.cwd);\n\n const callbacks = buildMcpPanelCallbacks(state, config, ctx);\n\n const { createMcpPanel } = await import(\"./mcp-panel.ts\");\n let configChanged = false;\n\n await new Promise<void>((resolve) => {\n ctx.ui.custom(\n (tui, _theme, keybindings, done) => {\n return createMcpPanel(config, cache, provenanceMap, callbacks, tui, (result: McpPanelResult) => {\n if (!result.cancelled && result.changes.size > 0) {\n writeDirectToolsConfig(result.changes, provenanceMap, config);\n configChanged = true;\n ctx.ui.notify(\"Direct tools updated. Pi will reload after this panel closes.\", \"info\");\n }\n done(undefined);\n resolve();\n }, { noticeLines, keybindings });\n },\n { overlay: true, overlayOptions: { anchor: \"center\", width: 82 } },\n );\n });\n\n if (noticeLines.length > 0 && fingerprint) {\n markSharedConfigHintShown(fingerprint);\n }\n\n return { configChanged };\n}\n\nexport async function openMcpAuthPanel(\n state: McpExtensionState,\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n configOverridePath?: string,\n): Promise<PanelFlowResult> {\n if (!ctx.hasUI) return { configChanged: false };\n\n const config = state.config;\n const oauthServers = Object.entries(config.mcpServers).filter(([, definition]) => supportsOAuth(definition));\n if (oauthServers.length === 0) {\n ctx.ui.notify(\"No OAuth-capable MCP servers are configured.\", \"warning\");\n return { configChanged: false };\n }\n\n const cache = loadMetadataCache();\n const configPath = pi.getFlag(\"mcp-config\") as string | undefined ?? configOverridePath;\n const provenanceMap = getServerProvenance(configPath, ctx.cwd);\n const callbacks = buildMcpPanelCallbacks(state, config, ctx);\n const { createMcpPanel } = await import(\"./mcp-panel.ts\");\n\n await new Promise<void>((resolve) => {\n ctx.ui.custom(\n (tui, _theme, keybindings, done) => {\n return createMcpPanel(config, cache, provenanceMap, callbacks, tui, () => {\n done(undefined);\n resolve();\n }, {\n authOnly: true,\n keybindings,\n noticeLines: [\"Select an OAuth MCP server and press Enter or ctrl+a to authenticate.\"],\n });\n },\n { overlay: true, overlayOptions: { anchor: \"center\", width: 82 } },\n );\n });\n\n return { configChanged: false };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/builtin-extensions/pi-mcp-adapter/commands.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAA8D,MAAM,YAAY,CAAC;AAevH,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKrE,wBAAsB,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC/F;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB9F;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,gBAAgB,EACrB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,WAAW,GACpB,OAAO,CAAC,aAAa,CAAC,CA0DxB;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAe3C;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,OAAO,CAAC;CACxB;AAoBD,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,gBAAgB,EACrB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,IAAI,GAAE,OAAO,GAAG,OAAiB,GAChC,OAAO,CAAC,eAAe,CAAC,CAsD1B;AAwCD,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,gBAAgB,EACrB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,eAAe,CAAC,CAsC1B;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,iBAAiB,EACxB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,gBAAgB,EACrB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,eAAe,CAAC,CAiC1B","sourcesContent":["// @ts-nocheck\nimport type { ExtensionAPI, ExtensionContext } from \"@ashx-j/lunr\";\nimport type { McpExtensionState } from \"./state.ts\";\nimport type { McpAuthResult, McpConfig, ServerEntry, McpPanelCallbacks, McpPanelResult, ImportKind } from \"./types.ts\";\nimport {\n ensureCompatibilityImports,\n getMcpDiscoverySummary,\n getServerProvenance,\n previewCompatibilityImports,\n previewSharedServerEntry,\n previewStarterProjectConfig,\n writeDirectToolsConfig,\n writeSharedServerEntry,\n writeStarterProjectConfig,\n} from \"./config.ts\";\nimport { lazyConnect, updateMetadataCache, updateStatusBar, getFailureAgeSeconds } from \"./init.ts\";\nimport { loadMetadataCache } from \"./metadata-cache.ts\";\nimport { buildToolMetadata } from \"./tool-metadata.ts\";\nimport { supportsOAuth, type McpAuthFlow } from \"./mcp-auth-flow.ts\";\nimport { getAuthForUrl } from \"./mcp-auth.ts\";\nimport { loadOnboardingState, markSetupCompleted as persistSetupCompleted, markSharedConfigHintShown } from \"./onboarding-state.ts\";\nimport { openPath } from \"./utils.ts\";\n\nexport async function showStatus(state: McpExtensionState, ctx: ExtensionContext): Promise<void> {\n if (!ctx.hasUI) return;\n\n const lines: string[] = [\"MCP Server Status:\", \"\"];\n\n for (const name of Object.keys(state.config.mcpServers)) {\n const connection = state.manager.getConnection(name);\n const metadata = state.toolMetadata.get(name);\n const toolCount = metadata?.length ?? 0;\n const failedAgo = getFailureAgeSeconds(state, name);\n let status = \"not connected\";\n let statusIcon = \"○\";\n let failed = false;\n\n if (connection?.status === \"connected\") {\n status = \"connected\";\n statusIcon = \"✓\";\n } else if (connection?.status === \"needs-auth\") {\n status = \"needs auth\";\n statusIcon = \"⚠\";\n } else if (failedAgo !== null) {\n status = `failed ${failedAgo}s ago`;\n statusIcon = \"✗\";\n failed = true;\n } else if (metadata !== undefined) {\n status = \"cached\";\n }\n\n const toolSuffix = failed ? \"\" : ` (${toolCount} tools${status === \"cached\" ? \", cached\" : \"\"})`;\n lines.push(`${statusIcon} ${name}: ${status}${toolSuffix}`);\n }\n\n if (Object.keys(state.config.mcpServers).length === 0) {\n lines.push(\"No MCP servers configured\");\n lines.push(\"Run /mcp setup to adopt imports or scaffold a starter .mcp.json\");\n }\n\n ctx.ui.notify(lines.join(\"\\n\"), \"info\");\n}\n\nexport async function showTools(state: McpExtensionState, ctx: ExtensionContext): Promise<void> {\n if (!ctx.hasUI) return;\n\n const allTools = [...state.toolMetadata.values()].flat().map(m => m.name);\n\n if (allTools.length === 0) {\n ctx.ui.notify(\"No MCP tools available\", \"info\");\n return;\n }\n\n const lines = [\n \"MCP Tools:\",\n \"\",\n ...allTools.map(t => ` ${t}`),\n \"\",\n `Total: ${allTools.length} tools`,\n ];\n\n ctx.ui.notify(lines.join(\"\\n\"), \"info\");\n}\n\nexport async function reconnectServers(\n state: McpExtensionState,\n ctx: ExtensionContext,\n targetServer?: string\n): Promise<void> {\n if (targetServer && !state.config.mcpServers[targetServer]) {\n if (ctx.hasUI) {\n ctx.ui.notify(`Server \"${targetServer}\" not found in config`, \"error\");\n }\n return;\n }\n\n const entries = targetServer\n ? [[targetServer, state.config.mcpServers[targetServer]] as [string, ServerEntry]]\n : Object.entries(state.config.mcpServers);\n\n for (const [name, definition] of entries) {\n try {\n await state.manager.close(name);\n\n const connection = await state.manager.connect(name, definition);\n if (connection.status === \"needs-auth\") {\n if (ctx.hasUI) {\n ctx.ui.notify(`MCP: ${name} requires OAuth. Run /mcp-auth ${name} first.`, \"warning\");\n }\n continue;\n }\n const prefix = state.config.settings?.toolPrefix ?? \"server\";\n\n const { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix);\n state.toolMetadata.set(name, metadata);\n updateMetadataCache(state, name);\n state.failureTracker.delete(name);\n\n if (ctx.hasUI) {\n ctx.ui.notify(\n `MCP: Reconnected to ${name} (${connection.tools.length} tools, ${connection.resources.length} resources)`,\n \"info\"\n );\n if (failedTools.length > 0) {\n ctx.ui.notify(`MCP: ${name} - ${failedTools.length} tools skipped`, \"warning\");\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n state.failureTracker.set(name, Date.now());\n if (ctx.hasUI) {\n ctx.ui.notify(`MCP: Failed to reconnect to ${name}: ${message}`, \"error\");\n }\n }\n }\n\n updateStatusBar(state);\n}\n\nexport async function authenticateServer(\n serverName: string,\n config: McpConfig,\n ctx: ExtensionContext,\n authFlow: McpAuthFlow,\n): Promise<McpAuthResult> {\n if (!ctx.hasUI) return { ok: false, message: \"OAuth authentication requires an interactive session.\" };\n\n const definition = config.mcpServers[serverName];\n if (!definition) {\n const message = `Server \"${serverName}\" not found in config`;\n ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n }\n\n if (!supportsOAuth(definition)) {\n const message = `Server \"${serverName}\" does not use OAuth authentication. Set \"auth\": \"oauth\" or omit auth for auto-detection.`;\n ctx.ui.notify(\n `Server \"${serverName}\" does not use OAuth authentication.\\n` +\n `Set \"auth\": \"oauth\" or omit auth for auto-detection.`,\n \"error\"\n );\n return { ok: false, message };\n }\n\n if (!definition.url) {\n const message = `Server \"${serverName}\" has no URL configured (OAuth requires HTTP transport)`;\n ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n }\n\n try {\n ctx.ui.setStatus(\"mcp-auth\", `Authenticating ${serverName}...`);\n const status = await authFlow.authenticate(serverName, definition.url, definition, {\n onAuthorizationUrl: (authorizationUrl) => {\n ctx.ui.notify(\n `Open this URL to authenticate ${serverName}:\\n\\n${authorizationUrl}\\n\\n` +\n \"After approving, return to lunR; the local callback will complete automatically.\",\n \"info\"\n );\n },\n });\n\n if (status === \"authenticated\") {\n const message = `OAuth authentication successful for \"${serverName}\"! Run /mcp reconnect ${serverName} to connect with the new token.`;\n ctx.ui.notify(\n `OAuth authentication successful for \"${serverName}\"!\\n` +\n `Run /mcp reconnect ${serverName} to connect with the new token.`,\n \"info\"\n );\n return { ok: true, message };\n }\n\n const message = `OAuth authentication failed for \"${serverName}\".`;\n ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n ctx.ui.notify(`Failed to authenticate \"${serverName}\": ${message}`, \"error\");\n return { ok: false, message };\n } finally {\n ctx.ui.setStatus(\"mcp-auth\", undefined);\n }\n}\n\nexport async function logoutServer(\n serverName: string,\n state: McpExtensionState,\n ctx: ExtensionContext\n): Promise<{ ok: boolean; message: string }> {\n const definition = state.config.mcpServers[serverName];\n if (!definition) {\n const message = `Server \"${serverName}\" not found in config`;\n if (ctx.hasUI) ctx.ui.notify(message, \"error\");\n return { ok: false, message };\n }\n\n await state.authFlow.removeAuth(serverName);\n await state.manager.close(serverName);\n updateStatusBar(state);\n\n const message = `OAuth credentials cleared for \"${serverName}\". Run /mcp-auth ${serverName} to authenticate again.`;\n if (ctx.hasUI) ctx.ui.notify(message, \"info\");\n return { ok: true, message };\n}\n\nexport interface PanelFlowResult {\n configChanged: boolean;\n}\n\nfunction buildSharedConfigNoticeLines(configOverridePath: string | undefined, cwd: string): { lines: string[]; fingerprint: string | null } {\n const discovery = getMcpDiscoverySummary(configOverridePath, cwd);\n const onboardingState = loadOnboardingState();\n if (!discovery.hasSharedServers || onboardingState.sharedConfigHintShown) {\n return { lines: [], fingerprint: null };\n }\n\n const sharedSources = discovery.sources.filter((source) => source.kind === \"shared\" && source.serverCount > 0);\n const sourceList = sharedSources.map((source) => source.path).join(\", \");\n return {\n lines: [\n `Using standard MCP config from ${sourceList}.`,\n \"Pi only writes compatibility imports and adapter-specific overrides into Pi-owned files when needed.\",\n ],\n fingerprint: discovery.fingerprint,\n };\n}\n\nexport async function openMcpSetup(\n _state: McpExtensionState,\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n configOverridePath?: string,\n mode: \"empty\" | \"setup\" = \"setup\",\n): Promise<PanelFlowResult> {\n if (!ctx.hasUI) return { configChanged: false };\n\n const discovery = getMcpDiscoverySummary(configOverridePath, ctx.cwd);\n const onboardingState = loadOnboardingState();\n const { createMcpSetupPanel } = await import(\"./mcp-setup-panel.ts\");\n let configChanged = false;\n\n const callbacks = {\n previewImports: (imports: ImportKind[]) => previewCompatibilityImports(imports, configOverridePath),\n previewStarterProject: () => previewStarterProjectConfig(ctx.cwd),\n previewRepoPrompt: () => {\n const repoPrompt = getMcpDiscoverySummary(configOverridePath, ctx.cwd).repoPrompt;\n if (!repoPrompt.entry || !repoPrompt.targetPath || !repoPrompt.serverName) return null;\n return previewSharedServerEntry(repoPrompt.targetPath, repoPrompt.serverName, repoPrompt.entry);\n },\n adoptImports: async (imports: ImportKind[]) => {\n const result = ensureCompatibilityImports(imports, configOverridePath);\n if (result.added.length > 0) configChanged = true;\n return result;\n },\n scaffoldProjectConfig: async () => {\n const path = writeStarterProjectConfig(ctx.cwd);\n configChanged = true;\n return { path };\n },\n addRepoPrompt: async () => {\n const repoPrompt = getMcpDiscoverySummary(configOverridePath, ctx.cwd).repoPrompt;\n if (!repoPrompt.entry || !repoPrompt.targetPath || !repoPrompt.serverName) {\n throw new Error(\"RepoPrompt is not available to add from this setup screen.\");\n }\n const path = writeSharedServerEntry(repoPrompt.targetPath, repoPrompt.serverName, repoPrompt.entry);\n configChanged = true;\n return { path, serverName: repoPrompt.serverName };\n },\n openPath: async (targetPath: string) => {\n await openPath(pi, targetPath);\n },\n markSetupCompleted: () => {\n persistSetupCompleted(discovery.fingerprint);\n },\n };\n\n return new Promise<PanelFlowResult>((resolve) => {\n ctx.ui.custom(\n (tui, _theme, keybindings, done) => {\n return createMcpSetupPanel(discovery, callbacks, { mode, onboardingState, keybindings }, tui, () => {\n done(undefined);\n resolve({ configChanged });\n });\n },\n { overlay: true, overlayOptions: { anchor: \"center\", width: 92 } },\n );\n });\n}\n\nfunction buildMcpPanelCallbacks(\n state: McpExtensionState,\n config: McpConfig,\n ctx: ExtensionContext,\n): McpPanelCallbacks {\n return {\n reconnect: (serverName: string) => lazyConnect(state, serverName),\n canAuthenticate: (serverName: string) => {\n const definition = config.mcpServers[serverName];\n return definition ? supportsOAuth(definition) : false;\n },\n authenticate: (serverName: string) => authenticateServer(serverName, config, ctx, state.authFlow),\n getConnectionStatus: (serverName: string) => {\n const definition = config.mcpServers[serverName];\n const connection = state.manager.getConnection(serverName);\n if (connection?.status === \"needs-auth\") {\n return \"needs-auth\";\n }\n if (\n definition?.auth === \"oauth\"\n && definition.url\n && definition.oauth !== false\n && definition.oauth?.grantType !== \"client_credentials\"\n && !getAuthForUrl(serverName, definition.url)?.tokens\n ) {\n return \"needs-auth\";\n }\n if (connection?.status === \"connected\") return \"connected\";\n if (getFailureAgeSeconds(state, serverName) !== null) return \"failed\";\n return \"idle\";\n },\n refreshCacheAfterReconnect: (serverName: string) => {\n const freshCache = loadMetadataCache();\n return freshCache?.servers?.[serverName] ?? null;\n },\n };\n}\n\nexport async function openMcpPanel(\n state: McpExtensionState,\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n configOverridePath?: string,\n): Promise<PanelFlowResult> {\n if (Object.keys(state.config.mcpServers).length === 0) {\n return openMcpSetup(state, pi, ctx, configOverridePath, \"empty\");\n }\n\n const config = state.config;\n const cache = loadMetadataCache();\n const configPath = pi.getFlag(\"mcp-config\") as string | undefined ?? configOverridePath;\n const provenanceMap = getServerProvenance(configPath, ctx.cwd);\n const { lines: noticeLines, fingerprint } = buildSharedConfigNoticeLines(configPath, ctx.cwd);\n\n const callbacks = buildMcpPanelCallbacks(state, config, ctx);\n\n const { createMcpPanel } = await import(\"./mcp-panel.ts\");\n let configChanged = false;\n\n await new Promise<void>((resolve) => {\n ctx.ui.custom(\n (tui, _theme, keybindings, done) => {\n return createMcpPanel(config, cache, provenanceMap, callbacks, tui, (result: McpPanelResult) => {\n if (!result.cancelled && result.changes.size > 0) {\n writeDirectToolsConfig(result.changes, provenanceMap, config);\n configChanged = true;\n ctx.ui.notify(\"Direct tools updated. Pi will reload after this panel closes.\", \"info\");\n }\n done(undefined);\n resolve();\n }, { noticeLines, keybindings });\n },\n { overlay: true, overlayOptions: { anchor: \"center\", width: 82 } },\n );\n });\n\n if (noticeLines.length > 0 && fingerprint) {\n markSharedConfigHintShown(fingerprint);\n }\n\n return { configChanged };\n}\n\nexport async function openMcpAuthPanel(\n state: McpExtensionState,\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n configOverridePath?: string,\n): Promise<PanelFlowResult> {\n if (!ctx.hasUI) return { configChanged: false };\n\n const config = state.config;\n const oauthServers = Object.entries(config.mcpServers).filter(([, definition]) => supportsOAuth(definition));\n if (oauthServers.length === 0) {\n ctx.ui.notify(\"No OAuth-capable MCP servers are configured.\", \"warning\");\n return { configChanged: false };\n }\n\n const cache = loadMetadataCache();\n const configPath = pi.getFlag(\"mcp-config\") as string | undefined ?? configOverridePath;\n const provenanceMap = getServerProvenance(configPath, ctx.cwd);\n const callbacks = buildMcpPanelCallbacks(state, config, ctx);\n const { createMcpPanel } = await import(\"./mcp-panel.ts\");\n\n await new Promise<void>((resolve) => {\n ctx.ui.custom(\n (tui, _theme, keybindings, done) => {\n return createMcpPanel(config, cache, provenanceMap, callbacks, tui, () => {\n done(undefined);\n resolve();\n }, {\n authOnly: true,\n keybindings,\n noticeLines: [\"Select an OAuth MCP server and press Enter or ctrl+a to authenticate.\"],\n });\n },\n { overlay: true, overlayOptions: { anchor: \"center\", width: 82 } },\n );\n });\n\n return { configChanged: false };\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import { ensureCompatibilityImports, getMcpDiscoverySummary, getServerProvenance
|
|
|
2
2
|
import { lazyConnect, updateMetadataCache, updateStatusBar, getFailureAgeSeconds } from "./init.js";
|
|
3
3
|
import { loadMetadataCache } from "./metadata-cache.js";
|
|
4
4
|
import { buildToolMetadata } from "./tool-metadata.js";
|
|
5
|
-
import { supportsOAuth
|
|
5
|
+
import { supportsOAuth } from "./mcp-auth-flow.js";
|
|
6
6
|
import { getAuthForUrl } from "./mcp-auth.js";
|
|
7
7
|
import { loadOnboardingState, markSetupCompleted as persistSetupCompleted, markSharedConfigHintShown } from "./onboarding-state.js";
|
|
8
8
|
import { openPath } from "./utils.js";
|
|
@@ -102,7 +102,7 @@ export async function reconnectServers(state, ctx, targetServer) {
|
|
|
102
102
|
}
|
|
103
103
|
updateStatusBar(state);
|
|
104
104
|
}
|
|
105
|
-
export async function authenticateServer(serverName, config, ctx) {
|
|
105
|
+
export async function authenticateServer(serverName, config, ctx, authFlow) {
|
|
106
106
|
if (!ctx.hasUI)
|
|
107
107
|
return { ok: false, message: "OAuth authentication requires an interactive session." };
|
|
108
108
|
const definition = config.mcpServers[serverName];
|
|
@@ -124,10 +124,10 @@ export async function authenticateServer(serverName, config, ctx) {
|
|
|
124
124
|
}
|
|
125
125
|
try {
|
|
126
126
|
ctx.ui.setStatus("mcp-auth", `Authenticating ${serverName}...`);
|
|
127
|
-
const status = await authenticate(serverName, definition.url, definition, {
|
|
127
|
+
const status = await authFlow.authenticate(serverName, definition.url, definition, {
|
|
128
128
|
onAuthorizationUrl: (authorizationUrl) => {
|
|
129
129
|
ctx.ui.notify(`Open this URL to authenticate ${serverName}:\n\n${authorizationUrl}\n\n` +
|
|
130
|
-
"After approving, return to
|
|
130
|
+
"After approving, return to lunR; the local callback will complete automatically.", "info");
|
|
131
131
|
},
|
|
132
132
|
});
|
|
133
133
|
if (status === "authenticated") {
|
|
@@ -157,7 +157,7 @@ export async function logoutServer(serverName, state, ctx) {
|
|
|
157
157
|
ctx.ui.notify(message, "error");
|
|
158
158
|
return { ok: false, message };
|
|
159
159
|
}
|
|
160
|
-
await removeAuth(serverName);
|
|
160
|
+
await state.authFlow.removeAuth(serverName);
|
|
161
161
|
await state.manager.close(serverName);
|
|
162
162
|
updateStatusBar(state);
|
|
163
163
|
const message = `OAuth credentials cleared for "${serverName}". Run /mcp-auth ${serverName} to authenticate again.`;
|
|
@@ -240,7 +240,7 @@ function buildMcpPanelCallbacks(state, config, ctx) {
|
|
|
240
240
|
const definition = config.mcpServers[serverName];
|
|
241
241
|
return definition ? supportsOAuth(definition) : false;
|
|
242
242
|
},
|
|
243
|
-
authenticate: (serverName) => authenticateServer(serverName, config, ctx),
|
|
243
|
+
authenticate: (serverName) => authenticateServer(serverName, config, ctx, state.authFlow),
|
|
244
244
|
getConnectionStatus: (serverName) => {
|
|
245
245
|
const definition = config.mcpServers[serverName];
|
|
246
246
|
const connection = state.manager.getConnection(serverName);
|