@herbertgao/pi-extensions 2026.8.5 → 2026.8.7
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 +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 +272 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +48 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -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 +16 -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 +22 -15
- 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 +34 -10
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +29 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +46 -10
- 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 +8 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -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 +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
- package/node_modules/@narumitw/pi-btw/README.md +119 -103
- 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 +13 -9
- package/node_modules/@narumitw/pi-btw/src/btw.ts +40 -42
- 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 +78 -15
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/pi-lens/CHANGELOG.md +1004 -0
- package/node_modules/pi-lens/README.md +11 -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 +427 -0
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +79 -16
- 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 +285 -8
- package/node_modules/pi-lens/dist/clients/biome-client.js +176 -37
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -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 +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 +11 -3
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +76 -2
- 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/console-guard-install.js +16 -4
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +249 -52
- 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 +62 -13
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +43 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +153 -37
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +165 -11
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +325 -72
- 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/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/helm-render.js +895 -0
- 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 +81 -41
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
- 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 +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
- 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 +488 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +84 -0
- 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 +943 -93
- 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 +72 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +106 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +317 -3
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +39 -8
- 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 +49 -21
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/go-client.js +21 -39
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +219 -10
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +9 -1
- package/node_modules/pi-lens/dist/clients/installer/index.js +1119 -101
- 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 +86 -15
- package/node_modules/pi-lens/dist/clients/knip-client.js +361 -24
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +487 -9
- 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-events.js +56 -25
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +45 -2
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +160 -20
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1666 -148
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +111 -0
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2496 -171
- 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 +517 -69
- 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 +172 -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 +61 -3
- 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/analyze.js +4 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +39 -18
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
- 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 +178 -30
- 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 +85 -15
- 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/runner-findings.js +23 -2
- 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 +5 -0
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- 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 +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +184 -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/query.js +76 -4
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +248 -13
- package/node_modules/pi-lens/dist/clients/runtime-context.js +112 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +472 -61
- package/node_modules/pi-lens/dist/clients/runtime-session.js +359 -13
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +269 -22
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +948 -87
- package/node_modules/pi-lens/dist/clients/rust-client.js +21 -37
- 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 +224 -8
- package/node_modules/pi-lens/dist/clients/sg-runner.js +249 -37
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +18 -11
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-timing.js +26 -2
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +574 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +127 -20
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- 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-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/warm-attach.js +17 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/word-index.js +305 -33
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +64677 -49484
- package/node_modules/pi-lens/dist/mcp/server.js +8 -2
- 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/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +469 -56
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +190 -46
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +44 -14
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +518 -501
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +33 -6
- package/node_modules/pi-lens/docs/globalconfig.md +14 -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 +25 -1
- package/node_modules/pi-lens/docs/usage.md +24 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -6
- 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 +22 -0
- 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-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-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 +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +9 -0
- 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-laundering-test.yml +11 -0
- 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 +66 -0
- 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-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-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 +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +42 -0
- 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 +32 -0
- 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 +132 -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/skills/pi-lens-ast-grep/SKILL.md +12 -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 +87 -116
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +170 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +49 -0
- package/node_modules/pi-mcp-adapter/README.md +51 -6
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/cli.js +188 -5
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +28 -10
- package/node_modules/pi-mcp-adapter/direct-tools.ts +23 -19
- 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/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +46 -25
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +4 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +330 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +145 -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-metadata.ts +38 -18
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +95 -10
- 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 +38 -14
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +8 -3
- package/node_modules/pi-web-access/curator-server.ts +5 -1
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +134 -37
- 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 +33 -7
- package/node_modules/pi-web-access/index.ts +160 -104
- package/node_modules/pi-web-access/package.json +2 -2
- 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/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +51 -23
- 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/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +13 -13
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { spawn, spawnSync, type ChildProcess } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import type { FetchLike } from "@modelcontextprotocol/client";
|
|
4
|
+
import type { HttpRequestHeadersCommand } from "./types.ts";
|
|
5
|
+
import { interpolateEnvVars } from "./utils.ts";
|
|
6
|
+
|
|
7
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
8
|
+
const MAX_OUTPUT_BYTES = 64 * 1024;
|
|
9
|
+
const USE_PROCESS_GROUP = process.platform !== "win32";
|
|
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;
|
|
15
|
+
|
|
16
|
+
function isNoSuchProcessError(error: unknown): boolean {
|
|
17
|
+
return typeof error === "object" && error !== null && "code" in error && (error as NodeJS.ErrnoException).code === "ESRCH";
|
|
18
|
+
}
|
|
19
|
+
|
|
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 };
|
|
24
|
+
}
|
|
25
|
+
|
|
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="]);
|
|
34
|
+
if (result.status !== 0) {
|
|
35
|
+
throw new Error(`HTTP request headers command cleanup failed: ${psFailureReason(result)}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const childrenByParent = new Map<number, number[]>();
|
|
39
|
+
const processPids = new Set<number>();
|
|
40
|
+
const needle = cleanupToken ? `${CLEANUP_TOKEN_ENV}=${cleanupToken}` : undefined;
|
|
41
|
+
for (const line of result.stdout.split("\n")) {
|
|
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]);
|
|
46
|
+
if (!Number.isInteger(pid) || !Number.isInteger(ppid)) continue;
|
|
47
|
+
const children = childrenByParent.get(ppid);
|
|
48
|
+
if (children) children.push(pid);
|
|
49
|
+
else childrenByParent.set(ppid, [pid]);
|
|
50
|
+
if (needle && pid !== process.pid && match[3]?.includes(needle)) processPids.add(pid);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const stack = [...(childrenByParent.get(rootPid) ?? [])];
|
|
54
|
+
while (stack.length > 0) {
|
|
55
|
+
const pid = stack.pop()!;
|
|
56
|
+
processPids.add(pid);
|
|
57
|
+
stack.push(...(childrenByParent.get(pid) ?? []));
|
|
58
|
+
}
|
|
59
|
+
return [...processPids];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function assertPosixProcessDiscoveryAvailable(): void {
|
|
63
|
+
const result = runPosixPs(["axeww", "-o", "pid=,ppid=,command="]);
|
|
64
|
+
if (result.status !== 0) {
|
|
65
|
+
throw new Error(`HTTP request headers command cleanup failed: ${psFailureReason(result)}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isTaskkillNoSuchProcess(result: ReturnType<typeof spawnSync>): boolean {
|
|
70
|
+
return `${result.stdout ?? ""}\n${result.stderr ?? ""}`.toLowerCase().includes("not found");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function signalPid(pid: number, signal: NodeJS.Signals): void {
|
|
74
|
+
try {
|
|
75
|
+
process.kill(pid, signal);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (!isNoSuchProcessError(error)) throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function signalProcessGroup(pid: number, signal: NodeJS.Signals): void {
|
|
82
|
+
try {
|
|
83
|
+
process.kill(-pid, signal);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (!isNoSuchProcessError(error)) throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function killRequestHeadersCommand(child: ChildProcess, trackedPosixDescendantPids = new Set<number>(), cleanupToken?: string): void {
|
|
90
|
+
if (process.platform === "win32" && child.pid !== undefined) {
|
|
91
|
+
const result = spawnSync("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
92
|
+
encoding: "utf8",
|
|
93
|
+
windowsHide: true,
|
|
94
|
+
});
|
|
95
|
+
if (result.status === 0 || isTaskkillNoSuchProcess(result)) return;
|
|
96
|
+
throw new Error(`HTTP request headers command cleanup failed: taskkill exited with code ${result.status ?? "unknown"}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (USE_PROCESS_GROUP && child.pid !== undefined) {
|
|
100
|
+
const frozenPids = new Set<number>();
|
|
101
|
+
let cleanupError: Error | undefined;
|
|
102
|
+
try {
|
|
103
|
+
signalProcessGroup(child.pid, "SIGSTOP");
|
|
104
|
+
for (const pid of trackedPosixDescendantPids) {
|
|
105
|
+
signalPid(pid, "SIGSTOP");
|
|
106
|
+
frozenPids.add(pid);
|
|
107
|
+
}
|
|
108
|
+
let stablePasses = 0;
|
|
109
|
+
for (let pass = 0; pass < 16; pass++) {
|
|
110
|
+
const candidates = collectPosixProcessPids(child.pid, cleanupToken);
|
|
111
|
+
const newPids = candidates.filter(pid => !frozenPids.has(pid));
|
|
112
|
+
if (newPids.length === 0) {
|
|
113
|
+
stablePasses++;
|
|
114
|
+
if (stablePasses >= 2) return;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
stablePasses = 0;
|
|
118
|
+
for (const pid of newPids) {
|
|
119
|
+
signalPid(pid, "SIGSTOP");
|
|
120
|
+
frozenPids.add(pid);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
cleanupError = new Error("HTTP request headers command cleanup failed: descendant process tree did not stabilize");
|
|
124
|
+
} catch (error) {
|
|
125
|
+
cleanupError = error instanceof Error ? error : new Error(String(error));
|
|
126
|
+
} finally {
|
|
127
|
+
signalProcessGroup(child.pid, "SIGKILL");
|
|
128
|
+
for (const pid of frozenPids) signalPid(pid, "SIGKILL");
|
|
129
|
+
}
|
|
130
|
+
if (cleanupError) throw cleanupError;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
child.kill("SIGKILL");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface HttpRequestCommandEnvelope {
|
|
138
|
+
version: 1;
|
|
139
|
+
method: string;
|
|
140
|
+
url: string;
|
|
141
|
+
bodyBase64: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
type CommandResult =
|
|
145
|
+
| { status: "error"; error: Error }
|
|
146
|
+
| { status: "success"; headers: Headers };
|
|
147
|
+
|
|
148
|
+
function resolvedCommand(config: HttpRequestHeadersCommand): {
|
|
149
|
+
command: string;
|
|
150
|
+
args: string[];
|
|
151
|
+
env: NodeJS.ProcessEnv;
|
|
152
|
+
timeoutMs: number;
|
|
153
|
+
} {
|
|
154
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
155
|
+
throw new Error("HTTP request headers command must be an object");
|
|
156
|
+
}
|
|
157
|
+
if (typeof config.command !== "string" || config.command.trim() === "") {
|
|
158
|
+
throw new Error("HTTP request headers command requires a non-empty command");
|
|
159
|
+
}
|
|
160
|
+
if (config.args !== undefined && (!Array.isArray(config.args) || config.args.some(arg => typeof arg !== "string"))) {
|
|
161
|
+
throw new Error("HTTP request headers command args must be strings");
|
|
162
|
+
}
|
|
163
|
+
if (config.env !== undefined && (
|
|
164
|
+
typeof config.env !== "object"
|
|
165
|
+
|| Array.isArray(config.env)
|
|
166
|
+
|| Object.values(config.env).some(value => typeof value !== "string")
|
|
167
|
+
)) {
|
|
168
|
+
throw new Error("HTTP request headers command env values must be strings");
|
|
169
|
+
}
|
|
170
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
171
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 60_000) {
|
|
172
|
+
throw new Error("HTTP request headers command timeoutMs must be an integer between 1 and 60000");
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
command: interpolateEnvVars(config.command),
|
|
176
|
+
args: (config.args ?? []).map(interpolateEnvVars),
|
|
177
|
+
env: {
|
|
178
|
+
...process.env,
|
|
179
|
+
...Object.fromEntries(
|
|
180
|
+
Object.entries(config.env ?? {}).map(([key, value]) => [key, interpolateEnvVars(value)]),
|
|
181
|
+
),
|
|
182
|
+
},
|
|
183
|
+
timeoutMs,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function invokeRequestHeadersCommand(
|
|
188
|
+
config: HttpRequestHeadersCommand,
|
|
189
|
+
envelope: HttpRequestCommandEnvelope,
|
|
190
|
+
signal: AbortSignal,
|
|
191
|
+
): Promise<Headers> {
|
|
192
|
+
const resolved = resolvedCommand(config);
|
|
193
|
+
if (USE_PROCESS_GROUP) assertPosixProcessDiscoveryAvailable();
|
|
194
|
+
return new Promise<Headers>((resolve, reject) => {
|
|
195
|
+
let stdout = Buffer.alloc(0);
|
|
196
|
+
let settled = false;
|
|
197
|
+
const cleanupToken = randomUUID();
|
|
198
|
+
const child = spawn(resolved.command, resolved.args, {
|
|
199
|
+
env: { ...resolved.env, [CLEANUP_TOKEN_ENV]: cleanupToken },
|
|
200
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
201
|
+
windowsHide: true,
|
|
202
|
+
detached: USE_PROCESS_GROUP,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const trackedPosixDescendantPids = new Set<number>();
|
|
206
|
+
let trackingError: Error | undefined;
|
|
207
|
+
const trackPosixDescendants = () => {
|
|
208
|
+
if (!USE_PROCESS_GROUP || child.pid === undefined || settled || trackingError) return;
|
|
209
|
+
try {
|
|
210
|
+
for (const pid of collectPosixProcessPids(child.pid, cleanupToken)) trackedPosixDescendantPids.add(pid);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
trackingError = error instanceof Error ? error : new Error(String(error));
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const descendantTracker = USE_PROCESS_GROUP ? setInterval(trackPosixDescendants, 50) : undefined;
|
|
216
|
+
descendantTracker?.unref();
|
|
217
|
+
|
|
218
|
+
const finish = (result: CommandResult) => {
|
|
219
|
+
if (settled) return;
|
|
220
|
+
settled = true;
|
|
221
|
+
clearTimeout(timer);
|
|
222
|
+
if (descendantTracker) clearInterval(descendantTracker);
|
|
223
|
+
signal.removeEventListener("abort", abort);
|
|
224
|
+
if (result.status === "error") reject(result.error);
|
|
225
|
+
else resolve(result.headers);
|
|
226
|
+
};
|
|
227
|
+
const finishAfterKill = (result: CommandResult) => {
|
|
228
|
+
try {
|
|
229
|
+
killRequestHeadersCommand(child, trackedPosixDescendantPids, cleanupToken);
|
|
230
|
+
finish(result);
|
|
231
|
+
} catch (cleanupError) {
|
|
232
|
+
finish({ status: "error", error: cleanupError instanceof Error ? cleanupError : new Error(String(cleanupError)) });
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const failAfterKill = (message: string) => {
|
|
236
|
+
finishAfterKill({ status: "error", error: trackingError ?? new Error(message) });
|
|
237
|
+
};
|
|
238
|
+
const abort = () => {
|
|
239
|
+
failAfterKill("HTTP request headers command aborted");
|
|
240
|
+
};
|
|
241
|
+
const timer = setTimeout(() => {
|
|
242
|
+
failAfterKill(`HTTP request headers command timed out after ${resolved.timeoutMs}ms`);
|
|
243
|
+
}, resolved.timeoutMs);
|
|
244
|
+
|
|
245
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
246
|
+
if (signal.aborted) {
|
|
247
|
+
abort();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
child.on("error", () => finish({ status: "error", error: new Error("HTTP request headers command failed to start") }));
|
|
252
|
+
child.stdout.on("data", (chunk: Buffer | string) => {
|
|
253
|
+
if (settled) return;
|
|
254
|
+
stdout = Buffer.concat([stdout, Buffer.from(chunk)]);
|
|
255
|
+
if (stdout.byteLength > MAX_OUTPUT_BYTES) {
|
|
256
|
+
failAfterKill("HTTP request headers command output exceeded 64 KiB");
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
child.on("close", code => {
|
|
260
|
+
if (settled) return;
|
|
261
|
+
if (trackingError) {
|
|
262
|
+
failAfterKill(trackingError.message);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (code !== 0) {
|
|
266
|
+
failAfterKill(`HTTP request headers command exited with code ${code ?? "unknown"}`);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
let parsed: unknown;
|
|
270
|
+
try {
|
|
271
|
+
parsed = JSON.parse(stdout.toString("utf8"));
|
|
272
|
+
} catch {
|
|
273
|
+
finishAfterKill({ status: "error", error: new Error("HTTP request headers command returned invalid JSON") });
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
277
|
+
finishAfterKill({ status: "error", error: new Error("HTTP request headers command must return a JSON object") });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const entries = Object.entries(parsed);
|
|
281
|
+
if (entries.some(([, value]) => typeof value !== "string")) {
|
|
282
|
+
finishAfterKill({ status: "error", error: new Error("HTTP request headers command values must be strings") });
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
finishAfterKill({ status: "success", headers: new Headers(entries as Array<[string, string]>) });
|
|
287
|
+
} catch {
|
|
288
|
+
finishAfterKill({ status: "error", error: new Error("HTTP request headers command returned an invalid header") });
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
child.stdin.on("error", () => {});
|
|
293
|
+
child.stdin.end(JSON.stringify(envelope));
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Wrap fetch so a trusted command can derive headers from the exact request. */
|
|
298
|
+
export function createRequestHeadersCommandFetch(
|
|
299
|
+
config: HttpRequestHeadersCommand,
|
|
300
|
+
delegate: FetchLike = globalThis.fetch,
|
|
301
|
+
): FetchLike {
|
|
302
|
+
// Validate static configuration before the first request.
|
|
303
|
+
resolvedCommand(config);
|
|
304
|
+
return async (input: URL | RequestInfo, init?: RequestInit): Promise<Response> => {
|
|
305
|
+
const request = new Request(input, init);
|
|
306
|
+
const body = Buffer.from(await request.clone().arrayBuffer());
|
|
307
|
+
const derived = await invokeRequestHeadersCommand(config, {
|
|
308
|
+
version: 1,
|
|
309
|
+
method: request.method.toUpperCase(),
|
|
310
|
+
url: request.url,
|
|
311
|
+
bodyBase64: body.toString("base64"),
|
|
312
|
+
}, request.signal);
|
|
313
|
+
const headers = new Headers(request.headers);
|
|
314
|
+
derived.forEach((value, name) => headers.set(name, value));
|
|
315
|
+
return delegate(new URL(request.url), {
|
|
316
|
+
method: request.method,
|
|
317
|
+
headers,
|
|
318
|
+
...(request.method === "GET" || request.method === "HEAD" ? {} : { body }),
|
|
319
|
+
signal: request.signal,
|
|
320
|
+
cache: request.cache,
|
|
321
|
+
credentials: request.credentials,
|
|
322
|
+
integrity: request.integrity,
|
|
323
|
+
keepalive: request.keepalive,
|
|
324
|
+
mode: request.mode,
|
|
325
|
+
redirect: request.redirect,
|
|
326
|
+
referrer: request.referrer,
|
|
327
|
+
referrerPolicy: request.referrerPolicy,
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
}
|
|
@@ -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));
|