@herbertgao/pi-extensions 2026.8.6 → 2026.8.8
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 +8 -6
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +999 -0
- package/node_modules/pi-lens/README.md +117 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
- package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +61407 -48577
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +27 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +37 -0
- package/node_modules/pi-web-access/README.md +32 -13
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +40 -5
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +60 -61
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/package.json +14 -14
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import stripJsonComments from "strip-json-comments";
|
|
4
|
+
import { getAgentDir, getConfigDirName } from "./agent-dir.ts";
|
|
5
|
+
import type { McpConfig, ServerEntry } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
interface PackageSetting {
|
|
8
|
+
source: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface PackageManifest {
|
|
12
|
+
name?: unknown;
|
|
13
|
+
pi?: { mcp?: unknown };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function loadPackageMcpConfigs(cwd = process.cwd()): McpConfig {
|
|
17
|
+
const mcpServers: Record<string, ServerEntry> = {};
|
|
18
|
+
const seen = new Set<string>();
|
|
19
|
+
|
|
20
|
+
for (const packageRoot of getConfiguredPackageRoots(cwd)) {
|
|
21
|
+
const manifest = readPackageManifest(packageRoot);
|
|
22
|
+
if (!manifest || typeof manifest.name !== "string" || !manifest.name) continue;
|
|
23
|
+
const paths = getManifestMcpPaths(manifest.pi?.mcp, manifest.name);
|
|
24
|
+
if (!paths) continue;
|
|
25
|
+
|
|
26
|
+
const packagePrefix = formatPackageName(manifest.name);
|
|
27
|
+
const packageServers = new Set<string>();
|
|
28
|
+
for (const path of paths) {
|
|
29
|
+
const configPath = resolvePackageConfigPath(packageRoot, path);
|
|
30
|
+
if (!configPath) {
|
|
31
|
+
console.warn(`Pi package ${manifest.name} skips MCP config ${path}: file must stay inside the package`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const config = readMcpConfig(configPath, manifest.name);
|
|
36
|
+
if (!config) continue;
|
|
37
|
+
for (const [serverName, server] of Object.entries(config.mcpServers)) {
|
|
38
|
+
const normalizedName = `${packagePrefix}__${formatServerName(serverName)}`;
|
|
39
|
+
if (packageServers.has(normalizedName) || seen.has(normalizedName)) {
|
|
40
|
+
console.warn(`Pi package ${manifest.name} skips duplicate normalized MCP server ${normalizedName}`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
packageServers.add(normalizedName);
|
|
44
|
+
seen.add(normalizedName);
|
|
45
|
+
mcpServers[normalizedName] = server;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { mcpServers };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getConfiguredPackageRoots(cwd: string): string[] {
|
|
54
|
+
const roots: string[] = [];
|
|
55
|
+
for (const [settingsPath, scope] of [
|
|
56
|
+
[join(cwd, getConfigDirName(), "settings.json"), "project"],
|
|
57
|
+
[join(getAgentDir(), "settings.json"), "user"],
|
|
58
|
+
] as const) {
|
|
59
|
+
const settings = readOptionalJson(settingsPath, `${scope} Pi settings`);
|
|
60
|
+
if (settings === undefined) continue;
|
|
61
|
+
if (typeof settings !== "object" || settings === null || Array.isArray(settings)) {
|
|
62
|
+
throw new Error(`${scope} Pi settings ${settingsPath} must be a JSON object`);
|
|
63
|
+
}
|
|
64
|
+
const packages = (settings as { packages?: unknown }).packages;
|
|
65
|
+
if (packages === undefined) continue;
|
|
66
|
+
if (!Array.isArray(packages)) throw new Error(`${scope} Pi settings ${settingsPath} packages must be an array`);
|
|
67
|
+
for (const entry of packages) {
|
|
68
|
+
const source = typeof entry === "string"
|
|
69
|
+
? entry
|
|
70
|
+
: entry && typeof entry === "object" && !Array.isArray(entry) && typeof (entry as PackageSetting).source === "string"
|
|
71
|
+
? (entry as PackageSetting).source
|
|
72
|
+
: undefined;
|
|
73
|
+
if (!source) throw new Error(`${scope} Pi settings ${settingsPath} package entries must be strings or objects with a string source`);
|
|
74
|
+
const root = resolvePackageRoot(source, scope, cwd);
|
|
75
|
+
if (root && !roots.includes(root)) roots.push(root);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return roots;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolvePackageRoot(source: string, scope: "user" | "project", cwd: string): string | null {
|
|
82
|
+
const baseDir = scope === "user" ? getAgentDir() : join(cwd, getConfigDirName());
|
|
83
|
+
if (source.startsWith("npm:")) {
|
|
84
|
+
const name = source.slice(4).trim().match(/^(@?[^@]+(?:\/[^@]+)?)/)?.[1];
|
|
85
|
+
return name ? resolveContainedPath(join(baseDir, "npm", "node_modules"), name) : null;
|
|
86
|
+
}
|
|
87
|
+
const gitSource = source.startsWith("git:")
|
|
88
|
+
? source.slice(4).trim()
|
|
89
|
+
: /^(?:(?:https?|ssh):\/\/|git@[^:]+:)/.test(source) ? source : null;
|
|
90
|
+
if (gitSource) {
|
|
91
|
+
const value = gitSource
|
|
92
|
+
.replace(/^ssh:\/\/git@/, "")
|
|
93
|
+
.replace(/^git@([^:]+):/, "$1/")
|
|
94
|
+
.replace(/^[a-z]+:\/\//i, "");
|
|
95
|
+
const path = value.replace(/@[^/]+$/, "").replace(/\.git$/, "");
|
|
96
|
+
return path && !path.startsWith("/") ? resolveContainedPath(join(baseDir, "git"), path) : null;
|
|
97
|
+
}
|
|
98
|
+
return isAbsolute(source) ? resolve(source) : resolve(baseDir, source);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function readPackageManifest(packageRoot: string): PackageManifest | null {
|
|
102
|
+
const manifest = readOptionalJson(join(packageRoot, "package.json"), `Pi package manifest ${packageRoot}`);
|
|
103
|
+
return manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest as PackageManifest : null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getManifestMcpPaths(value: unknown, packageName: string): string[] | null {
|
|
107
|
+
const paths = typeof value === "string" ? [value] : Array.isArray(value) && value.every((path): path is string => typeof path === "string") ? value : null;
|
|
108
|
+
if (value !== undefined && !paths) console.warn(`Pi package ${packageName} ignores invalid pi.mcp manifest entry`);
|
|
109
|
+
return paths;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function readMcpConfig(path: string, packageName: string): McpConfig | null {
|
|
113
|
+
const config = readRequiredJson(path, `Pi package ${packageName} MCP config`);
|
|
114
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
115
|
+
throw new Error(`Pi package ${packageName} MCP config ${path} must be a JSON object`);
|
|
116
|
+
}
|
|
117
|
+
const servers = (config as { mcpServers?: unknown }).mcpServers;
|
|
118
|
+
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
119
|
+
throw new Error(`Pi package ${packageName} MCP config ${path} must contain a JSON object mcpServers field`);
|
|
120
|
+
}
|
|
121
|
+
const mcpServers: Record<string, ServerEntry> = {};
|
|
122
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
123
|
+
if (!server || typeof server !== "object" || Array.isArray(server)) {
|
|
124
|
+
throw new Error(`Pi package ${packageName} MCP config ${path} server ${name} must be a JSON object`);
|
|
125
|
+
}
|
|
126
|
+
mcpServers[name] = server as ServerEntry;
|
|
127
|
+
}
|
|
128
|
+
return { mcpServers };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function readRequiredJson(path: string, description: string): unknown {
|
|
132
|
+
try {
|
|
133
|
+
return JSON.parse(stripJsonComments(readFileSync(path, "utf8"), { trailingCommas: true }));
|
|
134
|
+
} catch (error) {
|
|
135
|
+
throw new Error(`${description} ${path} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function readOptionalJson(path: string, description: string): unknown | undefined {
|
|
140
|
+
if (!existsSync(path)) return undefined;
|
|
141
|
+
return readRequiredJson(path, description);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function resolveContainedPath(root: string, path: string): string | null {
|
|
145
|
+
const resolved = resolve(root, path);
|
|
146
|
+
const rel = relative(root, resolved);
|
|
147
|
+
return rel === "" || (!rel.startsWith("..") && !rel.startsWith(sep) && !isAbsolute(rel)) ? resolved : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function resolvePackageConfigPath(packageRoot: string, path: string): string | null {
|
|
151
|
+
const lexicalPath = resolveContainedPath(packageRoot, path);
|
|
152
|
+
if (!lexicalPath || !existsSync(lexicalPath) || !statSync(lexicalPath).isFile()) return null;
|
|
153
|
+
try {
|
|
154
|
+
const realPackageRoot = realpathSync(packageRoot);
|
|
155
|
+
const realConfigPath = realpathSync(lexicalPath);
|
|
156
|
+
return resolveContainedPath(realPackageRoot, realConfigPath);
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function formatPackageName(name: string): string {
|
|
163
|
+
return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "package";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function formatServerName(name: string): string {
|
|
167
|
+
return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "server";
|
|
168
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mcp-adapter",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.27.0",
|
|
4
4
|
"description": "MCP (Model Context Protocol) adapter extension for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.ts",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"ui-tool-visibility.ts",
|
|
89
89
|
"ui-app-bridge-helpers.ts",
|
|
90
90
|
"config.ts",
|
|
91
|
+
"package-mcp-loader.ts",
|
|
91
92
|
"server-manager.ts",
|
|
92
93
|
"request-headers-command.ts",
|
|
93
94
|
"unix-socket-transport.ts",
|
|
@@ -115,6 +116,7 @@
|
|
|
115
116
|
"oauth-handler.ts",
|
|
116
117
|
"oauth.ts",
|
|
117
118
|
"mcp-auth.ts",
|
|
119
|
+
"mcp-bearer-store.ts",
|
|
118
120
|
"mcp-keyring-helper.cjs",
|
|
119
121
|
"mcp-oauth-provider.ts",
|
|
120
122
|
"mcp-callback-server.ts",
|
|
@@ -13,7 +13,7 @@ import { reconstructPromptMetadata } from "./metadata-cache.ts";
|
|
|
13
13
|
import { resolveMcpResultContent, transformMcpContent, transformMcpResourceContents } from "./tool-registrar.ts";
|
|
14
14
|
import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions } from "./mcp-output-guard.ts";
|
|
15
15
|
import { maybeStartUiSession, summarizeUiSessionResult, type UiSessionRuntime } from "./ui-session.ts";
|
|
16
|
-
import { formatAuthRequiredMessage, formatMcpStatus, resolveServerUrl, truncateAtWord } from "./utils.ts";
|
|
16
|
+
import { formatAuthRequiredMessage, formatMcpStatus, normalizeToolArguments, resolveServerUrl, truncateAtWord } from "./utils.ts";
|
|
17
17
|
import { authenticate, completeAuthFromInput, startAuth, supportsOAuth } from "./mcp-auth-flow.ts";
|
|
18
18
|
import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.ts";
|
|
19
19
|
import { paginate, rankSuggestions, rankToolMatches, resolveSearchKeywords } from "./search-ranking.ts";
|
|
@@ -1136,11 +1136,12 @@ export async function executeCall(
|
|
|
1136
1136
|
return disabledCallResult(serverName, toolMeta);
|
|
1137
1137
|
}
|
|
1138
1138
|
|
|
1139
|
+
const normalizedArgs = toolMeta.resourceUri ? args ?? {} : normalizeToolArguments(args);
|
|
1139
1140
|
const approval = await ensureToolCallApproved(
|
|
1140
1141
|
state,
|
|
1141
1142
|
serverName,
|
|
1142
1143
|
toolMeta,
|
|
1143
|
-
|
|
1144
|
+
normalizedArgs,
|
|
1144
1145
|
ownedSignal,
|
|
1145
1146
|
origin ?? (toolMeta.resourceUri ? "resource" : "proxy"),
|
|
1146
1147
|
);
|
|
@@ -1217,7 +1218,7 @@ export async function executeCall(
|
|
|
1217
1218
|
? await maybeStartUiSession(state, {
|
|
1218
1219
|
serverName,
|
|
1219
1220
|
toolName: toolMeta.originalName,
|
|
1220
|
-
toolArgs:
|
|
1221
|
+
toolArgs: normalizedArgs,
|
|
1221
1222
|
uiResourceUri: toolMeta.uiResourceUri,
|
|
1222
1223
|
...(toolMeta.uiStreamMode !== undefined ? { streamMode: toolMeta.uiStreamMode } : {}),
|
|
1223
1224
|
...(signal ? { signal } : {}),
|
|
@@ -1235,7 +1236,7 @@ export async function executeCall(
|
|
|
1235
1236
|
serverName,
|
|
1236
1237
|
(conn) => abortable(conn.client.callTool({
|
|
1237
1238
|
name: toolMeta.originalName,
|
|
1238
|
-
arguments:
|
|
1239
|
+
arguments: normalizedArgs,
|
|
1239
1240
|
_meta: uiSession?.requestMeta,
|
|
1240
1241
|
}, requestOptions), ownedSignal),
|
|
1241
1242
|
);
|
|
@@ -8,64 +8,62 @@ const DEFAULT_TIMEOUT_MS = 10_000;
|
|
|
8
8
|
const MAX_OUTPUT_BYTES = 64 * 1024;
|
|
9
9
|
const USE_PROCESS_GROUP = process.platform !== "win32";
|
|
10
10
|
const CLEANUP_TOKEN_ENV = "PI_MCP_REQUEST_HEADERS_CLEANUP_TOKEN";
|
|
11
|
+
// Busy hosts can exceed spawnSync's 1 MiB default when `ps axeww` dumps each
|
|
12
|
+
// process environment. Keep discovery below a bounded cap instead of letting
|
|
13
|
+
// `ps` get SIGTERM'd and reporting a false cleanup failure.
|
|
14
|
+
const PS_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
|
|
11
15
|
|
|
12
16
|
function isNoSuchProcessError(error: unknown): boolean {
|
|
13
17
|
return typeof error === "object" && error !== null && "code" in error && (error as NodeJS.ErrnoException).code === "ESRCH";
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
function runPosixPs(args: string[]): { status: number | null; stdout: string } {
|
|
17
|
-
if (process.env.PI_MCP_ADAPTER_TEST_FAIL_PS === "1") return { status: 1, stdout: "" };
|
|
18
|
-
|
|
20
|
+
function runPosixPs(args: string[]): { status: number | null; signal: NodeJS.Signals | null; stdout: string } {
|
|
21
|
+
if (process.env.PI_MCP_ADAPTER_TEST_FAIL_PS === "1") return { status: 1, signal: null, stdout: "" };
|
|
22
|
+
const result = spawnSync("ps", args, { encoding: "utf8", maxBuffer: PS_MAX_BUFFER_BYTES });
|
|
23
|
+
return { status: result.status, signal: result.signal, stdout: result.stdout };
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
function
|
|
22
|
-
|
|
26
|
+
function psFailureReason(result: { status: number | null; signal: NodeJS.Signals | null }): string {
|
|
27
|
+
return result.status === null
|
|
28
|
+
? `ps was killed by signal ${result.signal ?? "unknown"}`
|
|
29
|
+
: `ps exited with code ${result.status}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function collectPosixProcessPids(rootPid: number, cleanupToken?: string): number[] {
|
|
33
|
+
const result = runPosixPs(["axeww", "-o", "pid=,ppid=,command="]);
|
|
23
34
|
if (result.status !== 0) {
|
|
24
|
-
throw new Error(`HTTP request headers command cleanup failed:
|
|
35
|
+
throw new Error(`HTTP request headers command cleanup failed: ${psFailureReason(result)}`);
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
const childrenByParent = new Map<number, number[]>();
|
|
39
|
+
const processPids = new Set<number>();
|
|
40
|
+
const needle = cleanupToken ? `${CLEANUP_TOKEN_ENV}=${cleanupToken}` : undefined;
|
|
28
41
|
for (const line of result.stdout.split("\n")) {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const
|
|
42
|
+
const match = /^\s*(\d+)\s+(\d+)(?:\s+(.*))?$/.exec(line);
|
|
43
|
+
if (!match) continue;
|
|
44
|
+
const pid = Number(match[1]);
|
|
45
|
+
const ppid = Number(match[2]);
|
|
32
46
|
if (!Number.isInteger(pid) || !Number.isInteger(ppid)) continue;
|
|
33
47
|
const children = childrenByParent.get(ppid);
|
|
34
48
|
if (children) children.push(pid);
|
|
35
49
|
else childrenByParent.set(ppid, [pid]);
|
|
50
|
+
if (needle && pid !== process.pid && match[3]?.includes(needle)) processPids.add(pid);
|
|
36
51
|
}
|
|
37
52
|
|
|
38
|
-
const descendants: number[] = [];
|
|
39
53
|
const stack = [...(childrenByParent.get(rootPid) ?? [])];
|
|
40
54
|
while (stack.length > 0) {
|
|
41
55
|
const pid = stack.pop()!;
|
|
42
|
-
|
|
56
|
+
processPids.add(pid);
|
|
43
57
|
stack.push(...(childrenByParent.get(pid) ?? []));
|
|
44
58
|
}
|
|
45
|
-
return
|
|
59
|
+
return [...processPids];
|
|
46
60
|
}
|
|
47
61
|
|
|
48
|
-
function
|
|
49
|
-
const result = runPosixPs(["axeww", "-o", "pid=,command="]);
|
|
62
|
+
function assertPosixProcessDiscoveryAvailable(): void {
|
|
63
|
+
const result = runPosixPs(["axeww", "-o", "pid=,ppid=,command="]);
|
|
50
64
|
if (result.status !== 0) {
|
|
51
|
-
throw new Error(`HTTP request headers command cleanup failed:
|
|
65
|
+
throw new Error(`HTTP request headers command cleanup failed: ${psFailureReason(result)}`);
|
|
52
66
|
}
|
|
53
|
-
|
|
54
|
-
const needle = `${CLEANUP_TOKEN_ENV}=${cleanupToken}`;
|
|
55
|
-
const pids: number[] = [];
|
|
56
|
-
for (const line of result.stdout.split("\n")) {
|
|
57
|
-
const trimmed = line.trim();
|
|
58
|
-
if (!trimmed.includes(needle)) continue;
|
|
59
|
-
const [pidText] = trimmed.split(/\s+/, 1);
|
|
60
|
-
const pid = Number(pidText);
|
|
61
|
-
if (Number.isInteger(pid) && pid !== process.pid) pids.push(pid);
|
|
62
|
-
}
|
|
63
|
-
return pids;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function assertPosixProcessDiscoveryAvailable(): void {
|
|
67
|
-
collectPosixDescendantPids(process.pid);
|
|
68
|
-
collectPosixCleanupTokenPids(`${process.pid}-preflight`);
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
function isTaskkillNoSuchProcess(result: ReturnType<typeof spawnSync>): boolean {
|
|
@@ -109,10 +107,7 @@ function killRequestHeadersCommand(child: ChildProcess, trackedPosixDescendantPi
|
|
|
109
107
|
}
|
|
110
108
|
let stablePasses = 0;
|
|
111
109
|
for (let pass = 0; pass < 16; pass++) {
|
|
112
|
-
const candidates =
|
|
113
|
-
...collectPosixDescendantPids(child.pid),
|
|
114
|
-
...(cleanupToken ? collectPosixCleanupTokenPids(cleanupToken) : []),
|
|
115
|
-
];
|
|
110
|
+
const candidates = collectPosixProcessPids(child.pid, cleanupToken);
|
|
116
111
|
const newPids = candidates.filter(pid => !frozenPids.has(pid));
|
|
117
112
|
if (newPids.length === 0) {
|
|
118
113
|
stablePasses++;
|
|
@@ -212,8 +207,7 @@ async function invokeRequestHeadersCommand(
|
|
|
212
207
|
const trackPosixDescendants = () => {
|
|
213
208
|
if (!USE_PROCESS_GROUP || child.pid === undefined || settled || trackingError) return;
|
|
214
209
|
try {
|
|
215
|
-
for (const pid of
|
|
216
|
-
for (const pid of collectPosixCleanupTokenPids(cleanupToken)) trackedPosixDescendantPids.add(pid);
|
|
210
|
+
for (const pid of collectPosixProcessPids(child.pid, cleanupToken)) trackedPosixDescendantPids.add(pid);
|
|
217
211
|
} catch (error) {
|
|
218
212
|
trackingError = error instanceof Error ? error : new Error(String(error));
|
|
219
213
|
}
|
|
@@ -23,6 +23,26 @@ export interface RankedToolMatch {
|
|
|
23
23
|
score: number;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
type SearchField = Exclude<keyof typeof FIELD_WEIGHTS, "keywords">;
|
|
27
|
+
|
|
28
|
+
interface PreparedToolSearch {
|
|
29
|
+
tool: ToolMetadata;
|
|
30
|
+
fields: Array<[SearchField, string, string[]]>;
|
|
31
|
+
nameTokens: string[];
|
|
32
|
+
keywordPhrases: string[];
|
|
33
|
+
keywordTokens: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface CachedServerSearch {
|
|
37
|
+
metadata: ToolMetadata[];
|
|
38
|
+
searchKeywords: ServerEntry["searchKeywords"];
|
|
39
|
+
toolPrefix: ReturnType<typeof resolveToolPrefix>;
|
|
40
|
+
withKeywords?: PreparedToolSearch[];
|
|
41
|
+
withoutKeywords?: PreparedToolSearch[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const searchCache = new WeakMap<McpExtensionState, Map<string, CachedServerSearch>>();
|
|
45
|
+
|
|
26
46
|
/**
|
|
27
47
|
* Resolve the configured searchKeywords entries that apply to a tool.
|
|
28
48
|
* Keys match by original name, prefixed name, or glob — the same candidate
|
|
@@ -64,25 +84,37 @@ export function tokenize(value: string): string[] {
|
|
|
64
84
|
return normalizeSearchText(value).split(/[^a-z0-9]+/).filter(Boolean);
|
|
65
85
|
}
|
|
66
86
|
|
|
67
|
-
|
|
68
|
-
const normalizedQuery = normalizeSearchText(query).trim();
|
|
69
|
-
const queryTokens = tokenize(query);
|
|
70
|
-
if (queryTokens.length === 0) return null;
|
|
71
|
-
|
|
87
|
+
function prepareToolSearch(tool: ToolMetadata, server: string, keywords?: string[]): PreparedToolSearch {
|
|
72
88
|
const fields = {
|
|
73
89
|
name: normalizeSearchText(tool.name),
|
|
74
90
|
originalName: normalizeSearchText(tool.originalName),
|
|
75
91
|
server: normalizeSearchText(server),
|
|
76
92
|
description: normalizeSearchText(tool.description),
|
|
77
93
|
};
|
|
94
|
+
const preparedFields = (Object.entries(fields) as Array<[SearchField, string]>)
|
|
95
|
+
.map(([field, value]): [SearchField, string, string[]] => [field, value, tokenize(value)]);
|
|
96
|
+
const keywordPhrases = keywords?.map(keyword => normalizeSearchText(keyword).trim()).filter(Boolean) ?? [];
|
|
97
|
+
return {
|
|
98
|
+
tool,
|
|
99
|
+
fields: preparedFields,
|
|
100
|
+
nameTokens: preparedFields[0]![2],
|
|
101
|
+
keywordPhrases,
|
|
102
|
+
keywordTokens: keywordPhrases.flatMap(tokenize),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function scorePreparedToolMatch(
|
|
107
|
+
prepared: PreparedToolSearch,
|
|
108
|
+
normalizedQuery: string,
|
|
109
|
+
queryTokens: string[],
|
|
110
|
+
): number | null {
|
|
78
111
|
let score = 0;
|
|
79
112
|
let phraseMatched = false;
|
|
80
113
|
let wholeFieldExact = false;
|
|
81
114
|
const matchedTokens = new Set<string>();
|
|
82
115
|
|
|
83
|
-
for (const [field, value] of
|
|
116
|
+
for (const [field, value, fieldTokens] of prepared.fields) {
|
|
84
117
|
const weight = FIELD_WEIGHTS[field];
|
|
85
|
-
const fieldTokens = tokenize(value);
|
|
86
118
|
if (value === normalizedQuery) {
|
|
87
119
|
score += weight * 14;
|
|
88
120
|
phraseMatched = true;
|
|
@@ -112,11 +144,10 @@ export function scoreToolMatch(tool: ToolMetadata, server: string, query: string
|
|
|
112
144
|
// Configured keywords are discrete phrases, so the phrase-level bonus is
|
|
113
145
|
// computed per phrase (best match wins) rather than on a joined string,
|
|
114
146
|
// which would phrase-match queries spanning two unrelated keywords.
|
|
115
|
-
if (
|
|
147
|
+
if (prepared.keywordPhrases.length > 0) {
|
|
116
148
|
const weight = FIELD_WEIGHTS.keywords;
|
|
117
|
-
const phrases = keywords.map(keyword => normalizeSearchText(keyword).trim()).filter(Boolean);
|
|
118
149
|
let phraseScore = 0;
|
|
119
|
-
for (const phrase of
|
|
150
|
+
for (const phrase of prepared.keywordPhrases) {
|
|
120
151
|
if (phrase === normalizedQuery) {
|
|
121
152
|
phraseScore = Math.max(phraseScore, weight * 14);
|
|
122
153
|
phraseMatched = true;
|
|
@@ -131,15 +162,14 @@ export function scoreToolMatch(tool: ToolMetadata, server: string, query: string
|
|
|
131
162
|
}
|
|
132
163
|
score += phraseScore;
|
|
133
164
|
|
|
134
|
-
const keywordTokens = phrases.flatMap(tokenize);
|
|
135
165
|
for (const token of queryTokens) {
|
|
136
|
-
if (keywordTokens.includes(token)) {
|
|
166
|
+
if (prepared.keywordTokens.includes(token)) {
|
|
137
167
|
score += weight * 4;
|
|
138
168
|
matchedTokens.add(token);
|
|
139
|
-
} else if (keywordTokens.some(keywordToken => keywordToken.startsWith(token) || (keywordToken.length >= MIN_STEM_LENGTH && token.startsWith(keywordToken)))) {
|
|
169
|
+
} else if (prepared.keywordTokens.some(keywordToken => keywordToken.startsWith(token) || (keywordToken.length >= MIN_STEM_LENGTH && token.startsWith(keywordToken)))) {
|
|
140
170
|
score += weight * 2;
|
|
141
171
|
matchedTokens.add(token);
|
|
142
|
-
} else if (
|
|
172
|
+
} else if (prepared.keywordPhrases.some(phrase => phrase.includes(token))) {
|
|
143
173
|
score += weight;
|
|
144
174
|
matchedTokens.add(token);
|
|
145
175
|
}
|
|
@@ -151,11 +181,52 @@ export function scoreToolMatch(tool: ToolMetadata, server: string, query: string
|
|
|
151
181
|
|
|
152
182
|
score += coverage === 1 ? 25 : Math.round(coverage * 10);
|
|
153
183
|
const firstQueryToken = queryTokens[0];
|
|
154
|
-
if (firstQueryToken !== undefined &&
|
|
184
|
+
if (firstQueryToken !== undefined && prepared.nameTokens.includes(firstQueryToken)) score += 8;
|
|
155
185
|
if (wholeFieldExact) score += 20;
|
|
156
186
|
return score;
|
|
157
187
|
}
|
|
158
188
|
|
|
189
|
+
export function scoreToolMatch(tool: ToolMetadata, server: string, query: string, keywords?: string[]): number | null {
|
|
190
|
+
const normalizedQuery = normalizeSearchText(query).trim();
|
|
191
|
+
const queryTokens = tokenize(query);
|
|
192
|
+
if (queryTokens.length === 0) return null;
|
|
193
|
+
return scorePreparedToolMatch(prepareToolSearch(tool, server, keywords), normalizedQuery, queryTokens);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function getPreparedTools(
|
|
197
|
+
state: McpExtensionState,
|
|
198
|
+
serverName: string,
|
|
199
|
+
metadata: ToolMetadata[],
|
|
200
|
+
definition: ServerEntry | undefined,
|
|
201
|
+
globalPrefix: ToolPrefix,
|
|
202
|
+
includeKeywords: boolean,
|
|
203
|
+
): PreparedToolSearch[] {
|
|
204
|
+
let stateCache = searchCache.get(state);
|
|
205
|
+
if (!stateCache) {
|
|
206
|
+
stateCache = new Map();
|
|
207
|
+
searchCache.set(state, stateCache);
|
|
208
|
+
}
|
|
209
|
+
const toolPrefix = resolveToolPrefix(definition, globalPrefix);
|
|
210
|
+
let cached = stateCache.get(serverName);
|
|
211
|
+
if (cached?.metadata !== metadata || cached.searchKeywords !== definition?.searchKeywords || cached.toolPrefix !== toolPrefix) {
|
|
212
|
+
cached = { metadata, searchKeywords: definition?.searchKeywords, toolPrefix };
|
|
213
|
+
stateCache.set(serverName, cached);
|
|
214
|
+
}
|
|
215
|
+
const cacheKey = includeKeywords ? "withKeywords" : "withoutKeywords";
|
|
216
|
+
let prepared = cached[cacheKey];
|
|
217
|
+
if (!prepared) {
|
|
218
|
+
prepared = metadata.map(tool => prepareToolSearch(
|
|
219
|
+
tool,
|
|
220
|
+
serverName,
|
|
221
|
+
includeKeywords && definition?.searchKeywords !== undefined
|
|
222
|
+
? resolveSearchKeywords(definition, tool.originalName, serverName, globalPrefix)
|
|
223
|
+
: undefined,
|
|
224
|
+
));
|
|
225
|
+
cached[cacheKey] = prepared;
|
|
226
|
+
}
|
|
227
|
+
return prepared;
|
|
228
|
+
}
|
|
229
|
+
|
|
159
230
|
export function rankToolMatches(
|
|
160
231
|
state: McpExtensionState,
|
|
161
232
|
query: string,
|
|
@@ -163,18 +234,17 @@ export function rankToolMatches(
|
|
|
163
234
|
includeKeywords = true,
|
|
164
235
|
): RankedToolMatch[] {
|
|
165
236
|
const matches: RankedToolMatch[] = [];
|
|
237
|
+
const normalizedQuery = normalizeSearchText(query).trim();
|
|
238
|
+
const queryTokens = tokenize(query);
|
|
239
|
+
if (queryTokens.length === 0) return matches;
|
|
166
240
|
const globalPrefix = state.config.settings?.toolPrefix ?? "server";
|
|
167
241
|
for (const [serverName, metadata] of state.toolMetadata.entries()) {
|
|
168
242
|
if (server && serverName !== server) continue;
|
|
169
243
|
const definition = state.config.mcpServers[serverName];
|
|
170
244
|
if (isServerDisabled(definition)) continue;
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
? resolveSearchKeywords(definition, tool.originalName, serverName, globalPrefix)
|
|
175
|
-
: undefined;
|
|
176
|
-
const score = scoreToolMatch(tool, serverName, query, keywords);
|
|
177
|
-
if (score !== null) matches.push({ server: serverName, tool, score });
|
|
245
|
+
for (const prepared of getPreparedTools(state, serverName, metadata, definition, globalPrefix, includeKeywords)) {
|
|
246
|
+
const score = scorePreparedToolMatch(prepared, normalizedQuery, queryTokens);
|
|
247
|
+
if (score !== null) matches.push({ server: serverName, tool: prepared.tool, score });
|
|
178
248
|
}
|
|
179
249
|
}
|
|
180
250
|
return matches.sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name));
|