@herbertgao/pi-extensions 2026.8.4 → 2026.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +32 -24
- package/node_modules/@narumitw/pi-btw/package.json +6 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/pi-lens/CHANGELOG.md +2535 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
- package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
- package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
- package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
- package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
- package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
- package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +51785 -36118
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +219 -46
- package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +40 -15
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +45 -3
- package/node_modules/pi-lens/docs/globalconfig.md +56 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +18 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +41 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
- package/node_modules/pi-mcp-adapter/README.md +38 -4
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/cli.js +25 -4
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/config.ts +4 -4
- package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +4 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +176 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/node_modules/pi-web-access/CHANGELOG.md +14 -0
- package/node_modules/pi-web-access/README.md +18 -12
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +5 -3
- package/node_modules/pi-web-access/curator-server.ts +2 -1
- package/node_modules/pi-web-access/extract.ts +106 -34
- package/node_modules/pi-web-access/fetch-params.ts +17 -3
- package/node_modules/pi-web-access/firecrawl.ts +172 -12
- package/node_modules/pi-web-access/gemini-search.ts +18 -4
- package/node_modules/pi-web-access/index.ts +120 -48
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/summary-review.ts +11 -5
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +12 -13
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# pi-lens ast-grep Rule Reference
|
|
2
|
+
|
|
3
|
+
Deep-dive companion to `SKILL.md`. Read this when you're debugging a rule
|
|
4
|
+
that isn't matching (or over-matching) the way you expect: ReDoS-safe regex
|
|
5
|
+
authoring, string-escape quirks in node text, `has`/`inside` `stopBy`
|
|
6
|
+
defaults and when to override them, boolean-parameter matching across two
|
|
7
|
+
grammars, and precision-over-recall heuristics for denylist-shaped rules.
|
|
8
|
+
|
|
9
|
+
## Hard-won gotchas (NAPI runner specifics — verified)
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
⚠ `has`/`inside` default to DIRECT child/parent — add `stopBy: end` for a recursive search.
|
|
13
|
+
This cuts BOTH ways, so think about where the target node actually lives:
|
|
14
|
+
- Target is a grandchild+ → you MUST add `stopBy: end` or the `has` never matches.
|
|
15
|
+
`switch-without-default` = `switch_statement` not has `switch_default`: the default
|
|
16
|
+
lives under `switch_body`, so without `stopBy: end` it matches nothing and every
|
|
17
|
+
switch (even ones WITH a default) is flagged. Same for `nested-ternary` catching a
|
|
18
|
+
parenthesized `a ? (b ? c : d) : e`.
|
|
19
|
+
- Target is the direct child → leave it at `neighbor` (default). Adding `stopBy: end`
|
|
20
|
+
OVER-reports: `throw_statement` has `string` + `stopBy: end` flags `throw new
|
|
21
|
+
Error("x")` (the string is nested), and `expression_statement` has `new_expression`
|
|
22
|
+
+ `stopBy: end` flags `fn(new Error())` as a discarded error. Keep these direct.
|
|
23
|
+
napi's `has` never matches the node itself, so a self-referential `kind: X` has
|
|
24
|
+
`kind: X` (with `stopBy: end`) correctly flags only genuinely-nested X.
|
|
25
|
+
|
|
26
|
+
✅ Prefer `regex` on the matched node's OWN text over `has` when you only need to
|
|
27
|
+
inspect the node — avoids recursive-descendant false positives:
|
|
28
|
+
kind: export_statement
|
|
29
|
+
regex: '^export\s+(let|var)\b' # precise; no has-recursion FP
|
|
30
|
+
(NAPI evaluates `regex` with JS RegExp on node.text() — keep it LINEAR so the
|
|
31
|
+
detector can't itself ReDoS.)
|
|
32
|
+
|
|
33
|
+
⚠ String-literal regexes match SOURCE text, not the runtime string value.
|
|
34
|
+
Inspect the exact node text before writing constraints:
|
|
35
|
+
ast-grep run --kind string --lang ts sample.ts --json=compact
|
|
36
|
+
Example: source `"\\|"` is node text `"\\\\|"` in JSON; to match a
|
|
37
|
+
source-level escaped backslash (`\\`) followed by a non-backslash, the rule
|
|
38
|
+
regex needs FOUR regex backslashes, preferably in a YAML block scalar:
|
|
39
|
+
regex: >-
|
|
40
|
+
^["'`]\\\\[^\\A-Za-z0-9$]
|
|
41
|
+
This is how `incomplete-string-escaping` catches both `"\\|"` and
|
|
42
|
+
`'\\"'`. Avoid shell here-doc probes for this class — shell/JSON escaping
|
|
43
|
+
can silently eat a backslash and make the rule look broken.
|
|
44
|
+
|
|
45
|
+
⚠ `-js` twins: remember there are TWO execution surfaces.
|
|
46
|
+
<!-- verified: clients/dispatch/runners/ast-grep-napi.ts:205-216,450-455, c170d94b -->
|
|
47
|
+
- ast-grep CLI/LSP language-gates by `language:`. A `language: TypeScript`
|
|
48
|
+
rule is not enough for standalone `.js` coverage, so shipped user-facing
|
|
49
|
+
TS/JS rules that should fire under the ast-grep LSP usually need a `-js`
|
|
50
|
+
twin with `language: JavaScript` plus its own fixture.
|
|
51
|
+
- the in-process NAPI fallback (`ast-grep-napi.ts` — pi-lens source checkout
|
|
52
|
+
only, not present in the installed package) already DEDUPES by grammar
|
|
53
|
+
(#657): `ruleLanguageForFile` (`ast-grep-napi.ts:205-216`) maps each file
|
|
54
|
+
extension to its actual grammar, and the matcher (`:450-455`) skips any
|
|
55
|
+
`language:`-tagged rule whose tag doesn't match that grammar. A TS rule
|
|
56
|
+
and its JS twin no longer double-fire on the same file in fallback mode.
|
|
57
|
+
- **`-js` twins are needed only when the rule body itself is
|
|
58
|
+
grammar-divergent** (different node kinds/fields between the TS and JS
|
|
59
|
+
grammars). A grammar-agnostic body doesn't need a twin for fallback
|
|
60
|
+
coverage — the dedup above already scopes it correctly; ship a twin only
|
|
61
|
+
when standalone `.js` coverage through the ast-grep CLI/LSP baseline is
|
|
62
|
+
required (see the first bullet).
|
|
63
|
+
- **Grammar-divergent bodies** still need separate variants regardless:
|
|
64
|
+
e.g. `no-flag-argument` uses `required_parameter` in TS and
|
|
65
|
+
`assignment_pattern` in JS.
|
|
66
|
+
|
|
67
|
+
✅ Node-kind facts (tree-sitter-typescript grammar — NOT the TS compiler / Roslyn):
|
|
68
|
+
- let / const → `lexical_declaration` (var is NOT here)
|
|
69
|
+
- var → `variable_declaration`
|
|
70
|
+
- a regex literal's pattern text → `regex_pattern`
|
|
71
|
+
- x[i] index access → `subscript_expression` (NOT element_access_expression)
|
|
72
|
+
- obj.prop access → `member_expression` (NOT property_access_expression)
|
|
73
|
+
- !x / -x / typeof x → `unary_expression`
|
|
74
|
+
- a ? b : c → `ternary_expression`
|
|
75
|
+
|
|
76
|
+
❌ Wrong-grammar kind names = silent dead rule. `element_access_expression`,
|
|
77
|
+
`property_access_expression`, `binary_operator`, etc. are TS-compiler/Roslyn names, not
|
|
78
|
+
tree-sitter's. napi REJECTS the whole rule ("invalid kind matcher") so it never runs.
|
|
79
|
+
Verify a kind exists before shipping:
|
|
80
|
+
node -e 'import("@ast-grep/napi").then(s=>{const r=s.ts.parse("x[i]").root();
|
|
81
|
+
const f=(n,k)=>{let c=n.kind()===k?1:0;for(const x of n.children())c+=f(x,k);return c};
|
|
82
|
+
console.log(f(r,"subscript_expression"))})' # >0 means the kind is real
|
|
83
|
+
|
|
84
|
+
✅ Test through the REAL runner from the pi-lens source checkout's repo root — it loads the actual shipped
|
|
85
|
+
rules from rules/ast-grep-rules/rules. Assert on diagnostic `rule` ids:
|
|
86
|
+
const res = await runner.run(ctx); // ctx.filePath = temp .ts, cwd = repo (pi-lens source checkout only — not present in the installed package)
|
|
87
|
+
For pattern/kind/regex-only rules (CLI-identical semantics) `ast-grep scan` is fine.
|
|
88
|
+
|
|
89
|
+
✅ Before shipping any text/regex detector, FP-scan the codebase:
|
|
90
|
+
ast-grep scan -r <rule>.yml clients tools
|
|
91
|
+
Real safe variants bite (e.g. ReDoS: (ba+)+ is safe — a mandatory prefix makes
|
|
92
|
+
the partition unique; flag only a single quantified atom inside the group).
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Matching things a pattern can't express (#305)
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
❌ A parameter default is NOT a `$X = false` pattern. `pattern: $FLAG = false` parses as
|
|
99
|
+
an `assignment_expression` (statement context) and never matches a function parameter.
|
|
100
|
+
Match the PARAM NODE + its child literal instead, capturing the name for reuse:
|
|
101
|
+
# TS grammar
|
|
102
|
+
- kind: required_parameter
|
|
103
|
+
all:
|
|
104
|
+
- has: { field: pattern, pattern: $FLAG }
|
|
105
|
+
- has: { any: [ { kind: "true" }, { kind: "false" } ] }
|
|
106
|
+
# JS grammar (assignment_pattern, with fields left/right)
|
|
107
|
+
- kind: assignment_pattern
|
|
108
|
+
all:
|
|
109
|
+
- has: { field: left, pattern: $FLAG }
|
|
110
|
+
- has: { field: right, any: [ { kind: "true" }, { kind: "false" } ] }
|
|
111
|
+
|
|
112
|
+
✅ Metavar consistency works ACROSS sibling clauses of an `all` — a metavar bound in one
|
|
113
|
+
`has` must match the SAME text everywhere it reappears. Use it to CORRELATE nodes, which
|
|
114
|
+
is what makes a structural rule precise:
|
|
115
|
+
all:
|
|
116
|
+
- has: { stopBy: end, kind: required_parameter, has: { field: pattern, pattern: $FLAG } }
|
|
117
|
+
- has: { stopBy: end, any: [ { pattern: "if ($FLAG) $$$" }, { pattern: "if (!$FLAG) $$$" } ] }
|
|
118
|
+
This fires ONLY when the function branches on the SAME param it declared boolean — a
|
|
119
|
+
boolean default that's never branched on, or a branch on a different var, won't match.
|
|
120
|
+
|
|
121
|
+
❌ Two `has:` keys in one mapping silently OVERWRITE (YAML: last key wins). For multiple
|
|
122
|
+
descendant constraints use `all:` with a LIST of `has` entries, never repeated `has:`.
|
|
123
|
+
|
|
124
|
+
✅ Prefer a high-precision structural guard over an unbounded denylist. Message-chain
|
|
125
|
+
(Demeter) floods on fluent/promise/builder chains; rather than denylist every fluent
|
|
126
|
+
method name, REQUIRE the chain's first calls to be accessors (`get*`/`is*`/`has*`) via
|
|
127
|
+
`constraints` regex — promise/fluent/builder methods aren't accessor-named, so they're
|
|
128
|
+
excluded by construction. Precision over recall.
|
|
129
|
+
```
|
|
@@ -6,7 +6,7 @@ description: Use when writing a new pi-lens tree-sitter query rule YAML file —
|
|
|
6
6
|
# Writing a pi-lens tree-sitter Rule
|
|
7
7
|
|
|
8
8
|
Drop path: `rules/tree-sitter-queries/<language>/<id>.yml`
|
|
9
|
-
Language dir is **lowercase**: `typescript` `javascript` `tsx` `python` `go` `rust` `java` `csharp` `kotlin` `ruby` `cpp` `c` `css`
|
|
9
|
+
Language dir is **lowercase**: `typescript` `javascript` `tsx` `python` `go` `rust` `java` `csharp` `kotlin` `php` `ruby` `cpp` `c` `css`
|
|
10
10
|
|
|
11
11
|
Project rules merge with built-ins (both run). To disable a language's built-ins: rename dir to `<lang>-disabled/`.
|
|
12
12
|
|
|
@@ -115,6 +115,8 @@ predicates:
|
|
|
115
115
|
treeSitterRunner.run() via makeRealRunnerCtx (tests/support/real-runner-ctx.ts) —
|
|
116
116
|
runQueryOnFile bypasses dispatch (skip_test_files, tiers, delta, rule cache).
|
|
117
117
|
Template: tests/clients/dispatch/runners/tree-sitter-skip-test-files.test.ts.
|
|
118
|
+
(These test paths exist only in a pi-lens source checkout — the installed
|
|
119
|
+
npm package ships no tests/ directory.)
|
|
118
120
|
|
|
119
121
|
✅ JS files also run typescript/ rules (shared grammar) — one rule in
|
|
120
122
|
rules/tree-sitter-queries/typescript/ covers BOTH .ts and .js. No -js copy needed.
|
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.26.0] - 2026-08-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Added per-server `requestHeadersCommand` support for deriving fail-closed HTTP headers from the exact outbound request on every Streamable HTTP or SSE call. Thanks @kgreen18 for PR #353.
|
|
14
|
+
- Added `settings.warnOnLargeDirectTools` to suppress the advisory for 75 or more resolved direct tools. Thanks @Roshvan for issue #358.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Refined request-header command result handling types without changing runtime behavior.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- Matched adapter-owned config and state paths to the host agent directory when Pi is rebranded, including its environment override and config directory. Thanks @mindplay-dk for issue #356.
|
|
21
|
+
- Avoided O(tools²) cross-server tool-name collision scans at startup by skipping collision candidates when selectors are absent and sharing one indexed candidate set when `includeTools` or `excludeTools` is configured. Thanks @mjlbach for PR #357 and @cataldoc for issue #354.
|
|
22
|
+
|
|
23
|
+
## [2.25.0] - 2026-08-13
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Added `settings.notifyOnStartupConnect` to suppress successful MCP startup connection notices. Thanks @pierre-mgmt for issue #341.
|
|
27
|
+
- Added compact self-rendered MCP proxy and direct-tool result rows by default, with `settings.toolResultRendering: "boxed"` for the legacy boxed row and `settings.collapsedResultLines` for 1-3 collapsed result lines. Thanks @pierre-mgmt for issue #349.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Removed unused TypeScript declarations found by stricter compiler checks.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- Kept `mcpScript` tool-call replies flowing when Pi runs as a Bun-compiled binary by starting worker execution without module-level top-level await. Thanks @AndreiKopylov for issue #340 and @thesobercoder for the verified fix.
|
|
34
|
+
- Fixed direct-tool server prefixes to preserve provider-valid underscores and hyphens, including `codebase-memory-mcp`, while retaining safe escaping, collision handling, and exact proxy routing. Thanks @mightymatth for issue #342 and @JasonLandbridge for issue #343.
|
|
35
|
+
|
|
36
|
+
## [2.24.0] - 2026-08-13
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- Added per-server `searchKeywords` so `mcp({ search })` and `mcpScript` `tools.search` understand user-defined synonyms and aliases for tools. Keywords are keyed by tool name or glob and boost ranked and regex search only. They never appear in tool schemas, describe output, or the metadata cache. Thanks @Serisium for PR #336.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- Interpolated environment placeholders in stdio server arguments. Thanks @vjik for issue #333.
|
|
43
|
+
- Kept remote `/mcp-auth` authorization links reachable before the callback input opens. Thanks @trevorleibert-mixpanel for PR #331.
|
|
44
|
+
- Cached OAuth credentials in memory and refreshed them after OAuth-backed 401 responses. Thanks @daniel-sampliner for PR #335.
|
|
45
|
+
- Sanitized MCP server-name prefixes for provider-safe tool names while preserving server resolution. Thanks @triple-dex for issue #334.
|
|
46
|
+
- Validated persisted npx resolver cache entries before reuse, including malformed and prototype-sensitive persisted keys.
|
|
47
|
+
|
|
10
48
|
## [2.23.0] - 2026-08-11
|
|
11
49
|
|
|
12
50
|
### Added
|
|
@@ -207,6 +207,7 @@ In the configuration examples below, `30000` is illustrative only. If `requestTi
|
|
|
207
207
|
| `cwd` | Working directory; supports `${VAR}`, `$env:VAR`, and `~` expansion |
|
|
208
208
|
| `url` | HTTP endpoint (StreamableHTTP with SSE fallback); supports raw `${VAR}` and `$env:VAR` interpolation, and missing URL variables fail before any request is sent |
|
|
209
209
|
| `headers` | HTTP headers; supports `${VAR}` and `$env:VAR` interpolation. A value beginning with `!` runs a command when the HTTP server connects or OAuth authenticates; use `!!` for a literal leading `!`. |
|
|
210
|
+
| `requestHeadersCommand` | Trusted executable run for every HTTP request. It receives a versioned JSON envelope containing `method`, `url`, and the exact `bodyBase64` on stdin, and must return a JSON object of headers on stdout. `command`, `args`, and `env` support environment interpolation. Use for caller-bound request signatures; failures stop the request. |
|
|
210
211
|
| `auth` | `"bearer"` or `"oauth"` |
|
|
211
212
|
| `oauth.grantType` | `"authorization_code"` (default) or `"client_credentials"` for non-interactive machine auth |
|
|
212
213
|
| `oauth.clientId` | Pre-registered OAuth client ID. MCP 2026 prefers pre-registered clients or Client ID Metadata Documents; this adapter falls back to Dynamic Client Registration when the ID is omitted and the server supports it. |
|
|
@@ -227,6 +228,7 @@ In the configuration examples below, `30000` is illustrative only. If `requestTi
|
|
|
227
228
|
| `toolPrefix` | Override global `settings.toolPrefix` for this server (`"server"`, `"short"`, `"none"`, or `"mcp"`) |
|
|
228
229
|
| `includeTools` | `string[]` of tool names or glob patterns to expose (matches original names like `get_screenshot`, generated resource names like `read_figjam`, and prefixed names like `figma_get_screenshot`) |
|
|
229
230
|
| `excludeTools` | `string[]` of tool names or glob patterns to hide (applied after `includeTools`) |
|
|
231
|
+
| `searchKeywords` | `{ "tool-or-glob": ["keyword", ...] }` — extra keywords that boost `mcp({ search })` ranking for matching tools; never shown to the model |
|
|
230
232
|
| `debug` | Show server stderr (default: false) |
|
|
231
233
|
| `trace` | Enable metadata-only JSONL protocol tracing for this server; payloads, prompts, tool arguments/results, authorization data, and URLs are never persisted |
|
|
232
234
|
| `disabled` | Keep the server visible in config and status, but prevent connections, authentication, tools, and resource calls (only literal `true` disables it) |
|
|
@@ -265,7 +267,7 @@ The adapter owns only its client socket and closes that connection when the Pi r
|
|
|
265
267
|
|
|
266
268
|
### Remote/headless OAuth
|
|
267
269
|
|
|
268
|
-
If Pi is running on a remote server, `/mcp-auth <server>`
|
|
270
|
+
If Pi is running on a remote server, `/mcp-auth <server>` shows a clickable authorization URL first. Open it in your local browser and approve access, then select **Yes** in Pi to open the callback input. The browser may fail to load the localhost callback page because localhost refers to your workstation; copy the full URL from its address bar and paste it into Pi. The authorization screen closes automatically instead when the browser can reach Pi's callback directly.
|
|
269
271
|
|
|
270
272
|
The same flow is available through the proxy tool for non-interactive clients. Persistent OAuth still requires an available OS credential store; on headless Linux that usually means an unlocked Secret Service/libsecret keyring. The adapter fails closed instead of falling back to plaintext credentials when the secure store is unavailable.
|
|
271
273
|
|
|
@@ -306,6 +308,10 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
|
|
|
306
308
|
"requestTimeoutMs": 30000,
|
|
307
309
|
"showStatusIcon": true,
|
|
308
310
|
"mcpFooterStatus": "full",
|
|
311
|
+
"toolResultRendering": "compact",
|
|
312
|
+
"collapsedResultLines": 1,
|
|
313
|
+
"notifyOnStartupConnect": true,
|
|
314
|
+
"warnOnLargeDirectTools": true,
|
|
309
315
|
"hostConfigDiscovery": "off",
|
|
310
316
|
"approveTools": ["github_delete_*", "notion_update_*"],
|
|
311
317
|
"oauthDir": ".pi/mcp-oauth",
|
|
@@ -327,12 +333,16 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
|
|
|
327
333
|
| `requestTimeoutMs` | Global request timeout in milliseconds for live MCP calls (if omitted or `<= 0`, the MCP SDK default timeout is used) |
|
|
328
334
|
| `showStatusIcon` | Show the plug icon in MCP status and connection text (default: `true`). Set to `false` for plain `MCP: ...` text. |
|
|
329
335
|
| `mcpFooterStatus` | MCP footer verbosity: `"full"` (default), `"compact"` for `MCP connected/enabled`, or `"off"` to clear the persistent footer status. `/mcp status` remains available. |
|
|
336
|
+
| `toolResultRendering` | MCP tool result row style: `"compact"` (default) uses self-rendered rows, or `"boxed"` restores the legacy Pi boxed tool row. |
|
|
337
|
+
| `collapsedResultLines` | Number of result text lines to show before expansion: `1`, `2`, or `3`. Defaults to `1` in compact mode and `3` in boxed mode. |
|
|
338
|
+
| `notifyOnStartupConnect` | Show successful startup connection notices (default: `true`). Set to `false` to suppress routine `MCP: N servers connected (M tools)` notices. Connection errors and authentication warnings remain visible. |
|
|
330
339
|
| `hostConfigDiscovery` | Host-specific config policy: `"off"` (default), `"prompt"` (detect/report only), or `"on"` (explicitly load detected host configs as the lowest-precedence fallback) |
|
|
331
340
|
| `agentPluginPaths` | Agent Plugins package directories to load MCP servers from. Relative paths resolve from the active project cwd. |
|
|
332
341
|
| `approveTools` | `true` to require approval before every MCP tool call, or an array of glob patterns such as `["github_delete_*", "notion_update_*"]`. Per-server `approveTools` overrides this. |
|
|
333
342
|
| `oauthDir` | Legacy OAuth `tokens.json` import directory for this MCP config. Relative paths resolve from the active project cwd. `MCP_OAUTH_DIR` still wins when set. Persistent OAuth credentials are stored in the OS credential store, not this directory. |
|
|
334
343
|
| `mcpServers.<name>.oauth.authorizationParams` | Extra authorization URL parameters for provider-specific OAuth extensions. Flow-owned parameters such as `client_id`, `redirect_uri`, `scope`, `state`, `code_challenge`, `response_type`, and `resource` cannot be overridden. |
|
|
335
344
|
| `directTools` | Global default for all servers (default: false). Per-server overrides this. |
|
|
345
|
+
| `warnOnLargeDirectTools` | Show the advisory when 75 or more direct tools resolve (default: `true`). Set to `false` to suppress only this advisory. |
|
|
336
346
|
| `freezeDirectTools` | Keep direct-tool registration stable after the initial sync so automatic reconnects and list-change notifications do not rebuild the system prompt. Use `mcp({ connect: "server" })` or `/mcp reconnect <server>` to refresh deliberately. Default: false. |
|
|
337
347
|
| `scriptMode` | Register the MCP-only `mcpScript` plain-JavaScript tool (default: true). Set to `false` to hide it. |
|
|
338
348
|
| `disableProxyTool` | Hide the `mcp` proxy tool once configured direct tools are fully available from cache. |
|
|
@@ -537,7 +547,7 @@ To hide specific tools while still using `directTools: true`, add `excludeTools`
|
|
|
537
547
|
|
|
538
548
|
`includeTools` and `excludeTools` filter direct tools, proxy search/list/describe, and the `/mcp` panel view.
|
|
539
549
|
|
|
540
|
-
Each direct tool costs ~150-300 tokens in the system prompt (name + description + schema). Good for targeted sets of 5-20 tools. For servers with 75+ tools, stick with the proxy or pick specific tools with a `string[]`. If 75+ direct tools resolve, the adapter prints
|
|
550
|
+
Each direct tool costs ~150-300 tokens in the system prompt (name + description + schema). Good for targeted sets of 5-20 tools. For servers with 75+ tools, stick with the proxy or pick specific tools with a `string[]`. If 75+ direct tools resolve, the adapter prints an advisory but still registers the tools you configured. Set `settings.warnOnLargeDirectTools` to `false` to suppress this advisory.
|
|
541
551
|
|
|
542
552
|
Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup. On the first session after adding `directTools` to a new server, the cache won't exist yet — tools fall back to proxy-only while the cache populates, then the extension hot-loads the refreshed direct tools into the current session. Servers that advertise MCP list-change notifications refresh the current session when their tool or resource list changes. On Pi versions that expose `pi.unregisterTool()`, stale direct tools are removed from the registry during refresh; older Pi versions still deactivate them from the active tool set. To force a refresh: `/mcp reconnect <server>`.
|
|
543
553
|
|
|
@@ -648,12 +658,35 @@ Prefer `.mcp.json` for project-local shared MCP config. Use `.pi/mcp.json` only
|
|
|
648
658
|
|
|
649
659
|
`mcp({ connect: "server-name" })` refreshes an already connected server, so new tools, resources, prompts, and instructions can load without restarting Pi.
|
|
650
660
|
|
|
651
|
-
MCP proxy and direct-tool results
|
|
661
|
+
MCP proxy and direct-tool results use compact self-rendered rows by default. Collapsed success output shows the call title and the first result line, with a `Ctrl+O to expand` hint when more text is hidden. The full result remains available when expanded and is still returned unchanged to the model. Set `settings.toolResultRendering` to `"boxed"` to restore the legacy boxed Pi row, or set `settings.collapsedResultLines` to `2` or `3` when you want more collapsed text.
|
|
652
662
|
|
|
653
|
-
Search includes both MCP tools and Pi tools (from extensions). Pi tools appear first with `[pi tool]` prefix. Space-separated words are ranked by weighted matches across name, server,
|
|
663
|
+
Search includes both MCP tools and Pi tools (from extensions). Pi tools appear first with `[pi tool]` prefix. Space-separated words are ranked by weighted matches across name, server, description, and any configured `searchKeywords`, then returned one page at a time (`limit` defaults to 12). Use `details.nextOffset` for the next page. Regex search is still available with `regex: true`, but regex results are paginated without ranking.
|
|
654
664
|
|
|
655
665
|
Tool names are fuzzy-matched on hyphens and underscores — `context7_resolve_library_id` finds `context7_resolve-library-id`. When `describe` or `tool` cannot resolve a name, the result includes top suggestions so the agent can correct a typo or missing prefix in the same turn.
|
|
656
666
|
|
|
667
|
+
### Search keywords
|
|
668
|
+
|
|
669
|
+
Search uses literal matching so a tool whose name and description use different vocabulary than the query won't be found. Per-server `searchKeywords` adds extra vocabulary for matching tools:
|
|
670
|
+
|
|
671
|
+
```json
|
|
672
|
+
{
|
|
673
|
+
"mcpServers": {
|
|
674
|
+
"github": {
|
|
675
|
+
"command": "npx",
|
|
676
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
677
|
+
"searchKeywords": {
|
|
678
|
+
"search_code": ["grep"],
|
|
679
|
+
"*": ["gh"]
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
With this config, `mcp({ search: "grep" })` finds `github_search_code` even though neither its name nor description contains that word. Similarly, `mcp({ search: "gh" })` finds all tools provided by the github server.
|
|
687
|
+
|
|
688
|
+
Keys match a tool's original name, prefixed name, or a glob (`*` applies to every tool on the server) and all matching entries combine. Keywords are weighted like description text, with an extra boost when the query exactly matches a configured phrase. They affect ranked and regex search only (including `tools.search` in `mcpScript`): they never appear in tool schemas, `describe` output, direct-tool registration, or the metadata cache, and search with keywords works offline from cached metadata.
|
|
689
|
+
|
|
657
690
|
When `includeSchemas` is enabled, search and describe render common JSON Schema parameters as compact TypeScript shapes like `{ query: string; limit?: number; }`, with the older schema formatter retained as a fallback for unsupported schemas.
|
|
658
691
|
|
|
659
692
|
For HTTP servers, failed connects run a one-request shape probe that can turn opaque transport errors into setup hints such as `endpoint returned HTML (200) — this URL does not appear to speak MCP`. Healthy connections are not probed.
|
|
@@ -699,4 +732,5 @@ Advertised tool `outputSchema` values support JSON Schema draft-07 and 2020-12.
|
|
|
699
732
|
|
|
700
733
|
- Cross-session server sharing not yet implemented (each Pi session runs its own server processes)
|
|
701
734
|
- Compact MCP result rendering summarizes text, but inline images are still controlled by Pi's image display settings and may render below the compact text summary.
|
|
735
|
+
- Pi still owns one separator row before self-rendered tool output, so compact mode reduces adapter rendering height but cannot promise true zero-gap rows.
|
|
702
736
|
- MCP sampling support is text-only; context inclusion, tools, stop sequences, audio, and image content are rejected with explicit errors.
|
|
@@ -2,10 +2,18 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
|
|
5
|
+
export function getConfigDirName(): string {
|
|
6
|
+
const configDir = readPiConfig()?.configDir;
|
|
7
|
+
return typeof configDir === "string" && configDir.trim() ? configDir.trim() : ".pi";
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
export function getAgentDir(): string {
|
|
6
|
-
const
|
|
11
|
+
const piConfig = readPiConfig();
|
|
12
|
+
const name = piConfig?.name;
|
|
13
|
+
const appName = typeof name === "string" && name.trim() ? name.trim() : "pi";
|
|
14
|
+
const configured = process.env[`${appName.toUpperCase()}_CODING_AGENT_DIR`]?.trim();
|
|
7
15
|
if (!configured) {
|
|
8
|
-
return join(homedir(),
|
|
16
|
+
return join(homedir(), getConfigDirName(), "agent");
|
|
9
17
|
}
|
|
10
18
|
if (configured === "~") {
|
|
11
19
|
return homedir();
|
|
@@ -31,12 +39,12 @@ export function getAgentPath(...segments: string[]): string {
|
|
|
31
39
|
*
|
|
32
40
|
* Falls back to "pi", which is what pi's own APP_NAME resolves to.
|
|
33
41
|
*/
|
|
34
|
-
function readPiConfig(): { name?: unknown; clientUri?: unknown } | undefined {
|
|
42
|
+
function readPiConfig(): { name?: unknown; configDir?: unknown; clientUri?: unknown } | undefined {
|
|
35
43
|
const dir = process.env.PI_PACKAGE_DIR?.trim()
|
|
36
44
|
if (!dir) return undefined
|
|
37
45
|
try {
|
|
38
46
|
const manifest = JSON.parse(readFileSync(join(resolve(dir), "package.json"), "utf8")) as {
|
|
39
|
-
piConfig?: { name?: unknown; clientUri?: unknown }
|
|
47
|
+
piConfig?: { name?: unknown; configDir?: unknown; clientUri?: unknown }
|
|
40
48
|
}
|
|
41
49
|
return manifest.piConfig
|
|
42
50
|
} catch {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync,
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { getAgentPath } from "./agent-dir.ts";
|
|
4
4
|
import type { McpConfig, ServerEntry } from "./types.ts";
|
|
@@ -14,15 +14,36 @@ function expandHome(input) {
|
|
|
14
14
|
return path.resolve(input);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
function readPiConfig() {
|
|
18
|
+
const dir = process.env.PI_PACKAGE_DIR?.trim();
|
|
19
|
+
if (!dir) return undefined;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(fs.readFileSync(path.join(path.resolve(dir), "package.json"), "utf8")).piConfig;
|
|
22
|
+
} catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getConfigDirName() {
|
|
28
|
+
const configDir = readPiConfig()?.configDir;
|
|
29
|
+
return typeof configDir === "string" && configDir.trim() ? configDir.trim() : ".pi";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getAgentDir() {
|
|
33
|
+
const piConfig = readPiConfig();
|
|
34
|
+
const appName = typeof piConfig?.name === "string" && piConfig.name.trim() ? piConfig.name.trim() : "pi";
|
|
35
|
+
const configured = process.env[`${appName.toUpperCase()}_CODING_AGENT_DIR`]?.trim();
|
|
36
|
+
if (configured) return expandHome(configured);
|
|
37
|
+
return path.join(HOME, getConfigDirName(), "agent");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const AGENT_DIR = getAgentDir();
|
|
20
41
|
const PI_CONFIG_PATH = path.join(AGENT_DIR, "mcp.json");
|
|
21
42
|
const GENERIC_GLOBAL_CONFIG_PATH = path.join(HOME, ".config", "mcp", "mcp.json");
|
|
22
43
|
const AGENTS_GLOBAL_CONFIG_PATH = path.join(HOME, ".agents", "mcp.json");
|
|
23
44
|
const AGENTS_NESTED_GLOBAL_CONFIG_PATH = path.join(HOME, ".agents", "mcp", "mcp.json");
|
|
24
45
|
const PROJECT_CONFIG_PATH = path.resolve(process.cwd(), ".mcp.json");
|
|
25
|
-
const PROJECT_PI_CONFIG_PATH = path.resolve(process.cwd(),
|
|
46
|
+
const PROJECT_PI_CONFIG_PATH = path.resolve(process.cwd(), getConfigDirName(), "mcp.json");
|
|
26
47
|
|
|
27
48
|
const IMPORT_PATHS = {
|
|
28
49
|
cursor: [path.join(HOME, ".cursor", "mcp.json")],
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
previewSharedServerEntry,
|
|
13
13
|
previewStarterProjectConfig,
|
|
14
14
|
writeDirectToolsConfig,
|
|
15
|
-
writeProjectServerDisabledOverride,
|
|
16
15
|
writeSharedServerEntry,
|
|
17
16
|
writeStarterProjectConfig,
|
|
18
17
|
} from "./config.ts";
|
|
@@ -170,7 +169,7 @@ export async function reconnectServer(
|
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
const prefix = state.config.settings?.toolPrefix ?? "server";
|
|
173
|
-
const { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix);
|
|
172
|
+
const { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix, state.config.mcpServers, state.toolMetadata);
|
|
174
173
|
state.toolMetadata.set(name, metadata);
|
|
175
174
|
if (!connection.promptDiscoveryFailed) {
|
|
176
175
|
state.promptMetadata?.set(name, reconstructPromptMetadata(name, connection.prompts ?? [], prefix, definition));
|
|
@@ -283,11 +282,20 @@ export async function authenticateServer(
|
|
|
283
282
|
"info"
|
|
284
283
|
);
|
|
285
284
|
},
|
|
286
|
-
onAuthorizationInput: (
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
285
|
+
onAuthorizationInput: async (authorizationUrl, inputSignal) => {
|
|
286
|
+
const readyToPaste = await ui.confirm(
|
|
287
|
+
`Authorize ${serverName}`,
|
|
288
|
+
`Open this link in your browser:\n${terminalHyperlink(authorizationUrl, authorizationUrl)}\n\n` +
|
|
289
|
+
"After approving access, select Yes to paste the callback URL.",
|
|
290
|
+
{ signal: inputSignal },
|
|
291
|
+
);
|
|
292
|
+
if (!readyToPaste || inputSignal.aborted) return undefined;
|
|
293
|
+
return ui.input(
|
|
294
|
+
`Complete ${serverName} OAuth`,
|
|
295
|
+
"Paste the full callback URL",
|
|
296
|
+
{ signal: inputSignal },
|
|
297
|
+
);
|
|
298
|
+
},
|
|
291
299
|
...(signal ? { signal } : {}),
|
|
292
300
|
...(runtime ? { runtime } : {}),
|
|
293
301
|
});
|
|
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { parse as parseToml } from "smol-toml";
|
|
6
6
|
import stripJsonComments from "strip-json-comments";
|
|
7
|
-
import { getAgentPath } from "./agent-dir.ts";
|
|
7
|
+
import { getAgentPath, getConfigDirName } from "./agent-dir.ts";
|
|
8
8
|
import { getAgentPluginSummaries, loadAgentPluginConfigs, type AgentPluginSummary } from "./agent-plugin-loader.ts";
|
|
9
9
|
import { isServerDisabled, type HostConfigDiscovery, type McpConfig, type ServerEntry, type McpSettings, type ImportKind, type ServerProvenance } from "./types.ts";
|
|
10
10
|
import { toStringRecord } from "./utils.ts";
|
|
@@ -15,7 +15,7 @@ const AGENTS_GLOBAL_CONFIG_PATHS = [
|
|
|
15
15
|
join(homedir(), ".agents", "mcp", "mcp.json"),
|
|
16
16
|
] as const;
|
|
17
17
|
const PROJECT_CONFIG_NAME = ".mcp.json";
|
|
18
|
-
const PROJECT_PI_CONFIG_NAME = "
|
|
18
|
+
const PROJECT_PI_CONFIG_NAME = "mcp.json";
|
|
19
19
|
const REPOPROMPT_BINARY_CANDIDATES = [
|
|
20
20
|
join(homedir(), "RepoPrompt", "repoprompt_cli"),
|
|
21
21
|
"/Applications/Repo Prompt.app/Contents/MacOS/repoprompt-mcp",
|
|
@@ -177,7 +177,7 @@ export function getProjectConfigPath(cwd = process.cwd()): string {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
export function getProjectPiConfigPath(cwd = process.cwd()): string {
|
|
180
|
-
return resolve(cwd, PROJECT_PI_CONFIG_NAME);
|
|
180
|
+
return resolve(cwd, getConfigDirName(), PROJECT_PI_CONFIG_NAME);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
export function getConfigDiscoveryPaths(overridePath?: string, cwd = process.cwd()): ConfigDiscoveryPath[] {
|
|
@@ -471,7 +471,7 @@ function mergeConfigs(base: McpConfig, next: McpConfig): McpConfig {
|
|
|
471
471
|
// different url, these MUST NOT be inherited from the lower-precedence entry —
|
|
472
472
|
// otherwise the original endpoint's credentials would be shipped to the new
|
|
473
473
|
// url. See the SECURITY note in mergeServerMaps.
|
|
474
|
-
const URL_BOUND_AUTH_FIELDS = ["headers", "bearerToken", "bearerTokenEnv"] as const;
|
|
474
|
+
const URL_BOUND_AUTH_FIELDS = ["headers", "bearerToken", "bearerTokenEnv", "requestHeadersCommand"] as const;
|
|
475
475
|
|
|
476
476
|
function mergeServerMaps(
|
|
477
477
|
base: Record<string, ServerEntry>,
|
|
@@ -11,7 +11,8 @@ import { formatSchema } from "./tool-metadata.ts";
|
|
|
11
11
|
import { resolveMcpResultContent, transformMcpContent, transformMcpResourceContents } from "./tool-registrar.ts";
|
|
12
12
|
import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions } from "./mcp-output-guard.ts";
|
|
13
13
|
import { maybeStartUiSession, summarizeUiSessionResult, type UiSessionRuntime } from "./ui-session.ts";
|
|
14
|
-
import { formatToolName, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.ts";
|
|
14
|
+
import { createToolSelectorCandidateIndex, formatToolName, getToolNameCandidates, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.ts";
|
|
15
|
+
import { isUiToolVisibleToModel } from "./ui-tool-visibility.ts";
|
|
15
16
|
import { resourceNameToToolName } from "./resource-tools.ts";
|
|
16
17
|
import { authenticate, supportsOAuth } from "./mcp-auth-flow.ts";
|
|
17
18
|
import { formatAuthRequiredMessage, resolveServerUrl, truncateAtWord } from "./utils.ts";
|
|
@@ -149,10 +150,33 @@ export function resolveDirectTools(
|
|
|
149
150
|
if (!toolFilter) continue;
|
|
150
151
|
|
|
151
152
|
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
153
|
+
const hasToolFilters =
|
|
154
|
+
(Array.isArray(definition.includeTools) && definition.includeTools.length > 0) ||
|
|
155
|
+
(Array.isArray(definition.excludeTools) && definition.excludeTools.length > 0);
|
|
156
|
+
const selectorCandidateIndex = hasToolFilters ? (() => {
|
|
157
|
+
const candidates = new Set<string>();
|
|
158
|
+
for (const [otherServerName, otherDefinition] of Object.entries(config.mcpServers)) {
|
|
159
|
+
const otherCache = cache.servers[otherServerName];
|
|
160
|
+
if (!otherCache || !isServerCacheValid(otherCache, otherDefinition) || isServerDisabled(otherDefinition)) continue;
|
|
161
|
+
const otherPrefix = resolveToolPrefix(otherDefinition, prefix);
|
|
162
|
+
for (const otherTool of otherCache.tools ?? []) {
|
|
163
|
+
if (!isUiToolVisibleToModel(otherTool.uiVisibility)) continue;
|
|
164
|
+
for (const candidate of getToolNameCandidates(otherTool.name, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
165
|
+
}
|
|
166
|
+
if (otherDefinition.exposeResources !== false) {
|
|
167
|
+
for (const resource of otherCache.resources ?? []) {
|
|
168
|
+
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
169
|
+
for (const candidate of getToolNameCandidates(baseName, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return createToolSelectorCandidateIndex(candidates);
|
|
174
|
+
})() : undefined;
|
|
152
175
|
|
|
153
176
|
for (const tool of serverCache.tools ?? []) {
|
|
177
|
+
if (!isUiToolVisibleToModel(tool.uiVisibility)) continue;
|
|
154
178
|
if (toolFilter !== true && !toolFilter.includes(tool.name)) continue;
|
|
155
|
-
if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) continue;
|
|
179
|
+
if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex)) continue;
|
|
156
180
|
const prefixedName = formatToolName(tool.name, serverName, effectivePrefix);
|
|
157
181
|
if (BUILTIN_NAMES.has(prefixedName)) {
|
|
158
182
|
console.warn(`MCP: skipping direct tool "${prefixedName}" (collides with builtin)`);
|
|
@@ -178,7 +202,7 @@ export function resolveDirectTools(
|
|
|
178
202
|
for (const resource of serverCache.resources ?? []) {
|
|
179
203
|
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
180
204
|
if (toolFilter !== true && !toolFilter.includes(baseName)) continue;
|
|
181
|
-
if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) continue;
|
|
205
|
+
if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex)) continue;
|
|
182
206
|
const prefixedName = formatToolName(baseName, serverName, effectivePrefix);
|
|
183
207
|
if (BUILTIN_NAMES.has(prefixedName)) {
|
|
184
208
|
console.warn(`MCP: skipping direct resource tool "${prefixedName}" (collides with builtin)`);
|
|
@@ -200,7 +224,7 @@ export function resolveDirectTools(
|
|
|
200
224
|
}
|
|
201
225
|
}
|
|
202
226
|
|
|
203
|
-
if (specs.length >= DIRECT_TOOLS_ADVISORY_THRESHOLD) {
|
|
227
|
+
if (config.settings?.warnOnLargeDirectTools !== false && specs.length >= DIRECT_TOOLS_ADVISORY_THRESHOLD) {
|
|
204
228
|
console.warn(`MCP: ${specs.length} direct tools resolved. Each direct tool adds prompt context; README guidance recommends targeted sets of 5-20 tools and using the proxy or an explicit string[] when 75+ direct tools would be registered.`);
|
|
205
229
|
}
|
|
206
230
|
|
|
@@ -230,15 +254,39 @@ export function buildProxyDescription(
|
|
|
230
254
|
for (const serverName of Object.keys(config.mcpServers)) {
|
|
231
255
|
const definition = config.mcpServers[serverName];
|
|
232
256
|
if (!definition || isServerDisabled(definition)) continue;
|
|
233
|
-
const
|
|
257
|
+
const cachedEntry = cache?.servers?.[serverName];
|
|
258
|
+
const entry = cachedEntry && isServerCacheValid(cachedEntry, definition) ? cachedEntry : undefined;
|
|
234
259
|
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
260
|
+
const hasToolFilters =
|
|
261
|
+
(Array.isArray(definition.includeTools) && definition.includeTools.length > 0) ||
|
|
262
|
+
(Array.isArray(definition.excludeTools) && definition.excludeTools.length > 0);
|
|
263
|
+
const selectorCandidateIndex = hasToolFilters && cache ? (() => {
|
|
264
|
+
const candidates = new Set<string>();
|
|
265
|
+
for (const [otherServerName, otherDefinition] of Object.entries(config.mcpServers)) {
|
|
266
|
+
const otherEntry = cache.servers[otherServerName];
|
|
267
|
+
if (!otherEntry || !isServerCacheValid(otherEntry, otherDefinition) || isServerDisabled(otherDefinition)) continue;
|
|
268
|
+
const otherPrefix = resolveToolPrefix(otherDefinition, prefix);
|
|
269
|
+
for (const otherTool of otherEntry.tools ?? []) {
|
|
270
|
+
if (!isUiToolVisibleToModel(otherTool.uiVisibility)) continue;
|
|
271
|
+
for (const candidate of getToolNameCandidates(otherTool.name, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
272
|
+
}
|
|
273
|
+
if (otherDefinition.exposeResources !== false) {
|
|
274
|
+
for (const resource of otherEntry.resources ?? []) {
|
|
275
|
+
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
276
|
+
for (const candidate of getToolNameCandidates(baseName, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return createToolSelectorCandidateIndex(candidates);
|
|
281
|
+
})() : undefined;
|
|
235
282
|
const toolCount = (entry?.tools ?? []).filter(
|
|
236
|
-
(tool) =>
|
|
283
|
+
(tool) => isUiToolVisibleToModel(tool.uiVisibility)
|
|
284
|
+
&& isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex),
|
|
237
285
|
).length;
|
|
238
286
|
const resourceCount = definition?.exposeResources !== false
|
|
239
287
|
? (entry?.resources ?? []).filter((resource) => {
|
|
240
288
|
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
241
|
-
return isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools);
|
|
289
|
+
return isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex);
|
|
242
290
|
}).length
|
|
243
291
|
: 0;
|
|
244
292
|
const totalItems = toolCount + resourceCount;
|
|
@@ -264,7 +312,9 @@ export function buildProxyDescription(
|
|
|
264
312
|
const instructionSummaries: string[] = [];
|
|
265
313
|
for (const serverName of Object.keys(config.mcpServers)) {
|
|
266
314
|
if (isServerDisabled(config.mcpServers[serverName])) continue;
|
|
267
|
-
const
|
|
315
|
+
const definition = config.mcpServers[serverName];
|
|
316
|
+
const entry = definition && cache?.servers?.[serverName];
|
|
317
|
+
const instructions = entry && definition && isServerCacheValid(entry, definition) ? entry.instructions : undefined;
|
|
268
318
|
if (!instructions) continue;
|
|
269
319
|
const snippet = truncateAtWord(instructions.replace(/\s+/g, " ").trim(), INSTRUCTIONS_SNIPPET_LENGTH);
|
|
270
320
|
instructionSummaries.push(` ${serverName}: ${snippet}`);
|
|
@@ -459,11 +459,3 @@ function escapeHtml(value: string): string {
|
|
|
459
459
|
.replace(/"/g, """)
|
|
460
460
|
.replace(/'/g, "'");
|
|
461
461
|
}
|
|
462
|
-
|
|
463
|
-
function escapeHtmlAttribute(value: string): string {
|
|
464
|
-
return value
|
|
465
|
-
.replace(/&/g, "&")
|
|
466
|
-
.replace(/"/g, """)
|
|
467
|
-
.replace(/</g, "<")
|
|
468
|
-
.replace(/>/g, ">");
|
|
469
|
-
}
|