@herbertgao/pi-extensions 2026.9.0 → 2026.9.1
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/node_modules/@czottmann/pi-automode/CHANGELOG.md +13 -1
- package/node_modules/@czottmann/pi-automode/README.md +20 -0
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +1 -1
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +2 -1
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +3 -2
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +38 -2
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +5 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +11 -3
- package/node_modules/@czottmann/pi-automode/package.json +1 -1
- package/node_modules/@pi-plugins/fast-mode/README.md +5 -3
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +20 -55
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +1 -1
- package/node_modules/pi-lens/CHANGELOG.md +988 -0
- package/node_modules/pi-lens/README.md +3 -0
- package/node_modules/pi-lens/config/biome/core.jsonc +11 -2
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +13 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +13 -4
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +123 -3
- package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +60 -5
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +1 -3
- package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +509 -73
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +152 -12
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -4
- package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +31 -4
- package/node_modules/pi-lens/dist/clients/cache-manager.js +105 -6
- package/node_modules/pi-lens/dist/clients/cache-observability.js +44 -18
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +13 -3
- package/node_modules/pi-lens/dist/clients/complexity-client.js +16 -5
- package/node_modules/pi-lens/dist/clients/config-core/deny.js +221 -0
- package/node_modules/pi-lens/dist/clients/config-core/index.js +47 -0
- package/node_modules/pi-lens/dist/clients/config-core/merge.js +357 -0
- package/node_modules/pi-lens/dist/clients/config-core/normalize.js +340 -0
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +248 -0
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +171 -0
- package/node_modules/pi-lens/dist/clients/config-core/records.js +218 -0
- package/node_modules/pi-lens/dist/clients/config-core/resolve.js +125 -0
- package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +78 -0
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +167 -0
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +281 -0
- package/node_modules/pi-lens/dist/clients/config-locations.js +160 -0
- package/node_modules/pi-lens/dist/clients/config-resolve.js +789 -0
- package/node_modules/pi-lens/dist/clients/config-schema.js +197 -0
- package/node_modules/pi-lens/dist/clients/config-warn.js +407 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -14
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +178 -0
- package/node_modules/pi-lens/dist/clients/debug-handles.js +2 -2
- package/node_modules/pi-lens/dist/clients/debug-heap.js +3 -3
- package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +106 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +113 -7
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +8 -19
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -18
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +380 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +13 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +194 -80
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +84 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -3
- package/node_modules/pi-lens/dist/clients/effective-config.js +403 -0
- package/node_modules/pi-lens/dist/clients/error-class.js +23 -0
- package/node_modules/pi-lens/dist/clients/event-loop-hold.js +274 -0
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -2
- package/node_modules/pi-lens/dist/clients/feature-hints.js +2 -1
- package/node_modules/pi-lens/dist/clients/file-time.js +6 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +112 -9
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
- package/node_modules/pi-lens/dist/clients/format-service.js +6 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +276 -102
- package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +114 -19
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
- package/node_modules/pi-lens/dist/clients/git-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/go-client.js +39 -0
- package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +252 -0
- package/node_modules/pi-lens/dist/clients/hashline-anchor.js +424 -0
- package/node_modules/pi-lens/dist/clients/hook-budgets.js +76 -0
- package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +5 -2
- package/node_modules/pi-lens/dist/clients/host-ports.js +1 -1
- package/node_modules/pi-lens/dist/clients/installer/index.js +71 -52
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +104 -230
- package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
- package/node_modules/pi-lens/dist/clients/language-registry.js +595 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +160 -2
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +13 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +141 -30
- package/node_modules/pi-lens/dist/clients/lens-engine.js +30 -37
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +59 -6
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -2
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +168 -30
- package/node_modules/pi-lens/dist/clients/lsp/config.js +483 -158
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +15 -2
- package/node_modules/pi-lens/dist/clients/lsp/index.js +676 -71
- package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -169
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -16
- package/node_modules/pi-lens/dist/clients/lsp/server.js +284 -147
- package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +116 -23
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +2 -7
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +9 -2
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +163 -21
- package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +36 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +33 -4
- package/node_modules/pi-lens/dist/clients/mcp/session.js +5 -16
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +8 -3
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +2 -4
- package/node_modules/pi-lens/dist/clients/module-report.js +20 -45
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +651 -0
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +368 -0
- package/node_modules/pi-lens/dist/clients/mutation-bridge.js +240 -0
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +247 -20
- package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +101 -0
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +1215 -0
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +68 -22
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +4 -0
- package/node_modules/pi-lens/dist/clients/package-manager.js +195 -26
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +359 -80
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +23 -7
- package/node_modules/pi-lens/dist/clients/path-keyed-map.js +21 -2
- package/node_modules/pi-lens/dist/clients/path-utils.js +428 -13
- package/node_modules/pi-lens/dist/clients/persist-debounce.js +8 -1
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +114 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +77 -16
- package/node_modules/pi-lens/dist/clients/probe-home-state.js +228 -0
- package/node_modules/pi-lens/dist/clients/process-bridge.js +66 -0
- package/node_modules/pi-lens/dist/clients/process-snapshot.js +68 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +393 -122
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +52 -24
- package/node_modules/pi-lens/dist/clients/python-environment.js +217 -0
- package/node_modules/pi-lens/dist/clients/python-provenance.js +639 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +6 -1
- package/node_modules/pi-lens/dist/clients/read-bridge.js +13 -21
- package/node_modules/pi-lens/dist/clients/read-expansion.js +9 -46
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +15 -4
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
- package/node_modules/pi-lens/dist/clients/read-guard.js +21 -0
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +152 -109
- package/node_modules/pi-lens/dist/clients/review-graph/service.js +55 -3
- package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +7 -15
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +10 -74
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +9 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +18 -2
- package/node_modules/pi-lens/dist/clients/runtime-context.js +49 -16
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +25 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +139 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +168 -35
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +797 -243
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +1028 -53
- package/node_modules/pi-lens/dist/clients/rust-client.js +31 -0
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +33 -10
- package/node_modules/pi-lens/dist/clients/sanitize.js +7 -1
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +1 -3
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +3 -0
- package/node_modules/pi-lens/dist/clients/session-lifecycle.js +1 -1
- package/node_modules/pi-lens/dist/clients/session-start-observability.js +79 -0
- package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
- package/node_modules/pi-lens/dist/clients/sgconfig.js +6 -1
- package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/string-utils.js +13 -0
- package/node_modules/pi-lens/dist/clients/subagent-mode.js +17 -4
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +176 -39
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +239 -0
- package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
- package/node_modules/pi-lens/dist/clients/tool-policy.js +91 -21
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +86 -48
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +81 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +51 -46
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +28 -0
- package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +6 -2
- package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/word-index-store.js +20 -5
- package/node_modules/pi-lens/dist/clients/word-index.js +243 -31
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +3 -0
- package/node_modules/pi-lens/dist/index.js +64335 -54300
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
- package/node_modules/pi-lens/dist/mcp/server.js +127 -5
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +583 -0
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +129 -0
- package/node_modules/pi-lens/dist/tools/effective-config.js +89 -0
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +95 -24
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +67 -80
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
- package/node_modules/pi-lens/dist/tools/shared.js +0 -1
- package/node_modules/pi-lens/docs/agent-guide.md +64 -1
- package/node_modules/pi-lens/docs/configuration.md +222 -0
- package/node_modules/pi-lens/docs/dependencies.md +3 -3
- package/node_modules/pi-lens/docs/features.md +44 -5
- package/node_modules/pi-lens/docs/language-coverage.md +2 -2
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +25 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +25 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +27 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +38 -0
- package/node_modules/pi-lens/docs/pi-lens-warden.md +55 -0
- package/node_modules/pi-lens/docs/public-api-stability.md +359 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +182 -0
- package/node_modules/pi-lens/docs/subagent-compat.md +110 -30
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +2 -2
- package/node_modules/pi-lens/package.json +15 -23
- package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
- package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
- package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +192 -1
- package/node_modules/pi-lens/scripts/install-selftest.mjs +58 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +129 -0
- package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
- package/node_modules/pi-web-access/CHANGELOG.md +28 -0
- package/node_modules/pi-web-access/README.md +62 -15
- package/node_modules/pi-web-access/curator-page.ts +3 -1
- package/node_modules/pi-web-access/curator-server.ts +5 -1
- package/node_modules/pi-web-access/gemini-search.ts +8 -4
- package/node_modules/pi-web-access/github-extract.ts +242 -1
- package/node_modules/pi-web-access/index.ts +118 -64
- package/node_modules/pi-web-access/mistral-search.ts +281 -0
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/perplexity.ts +14 -1
- package/node_modules/pi-web-access/utils.ts +23 -6
- package/node_modules/pi-web-access/xai-search.ts +96 -33
- package/package.json +5 -5
|
@@ -11,10 +11,14 @@ import { access, readFile, readdir, stat } from "node:fs/promises";
|
|
|
11
11
|
import os from "node:os";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { getGlobalPiLensDir, getProjectIgnoreGlobs, isPathIgnoredByProject, } from "../file-utils.js";
|
|
14
|
+
import { augmentPythonEnvironment, detectPythonEnvironment, detectPythonVenv, pythonEnvironmentToolCandidates, } from "../python-environment.js";
|
|
15
|
+
export { detectPythonVenv };
|
|
14
16
|
import { STAGE_TMP_PATTERN } from "../atomic-write-staging.js";
|
|
15
17
|
import { DOTNET_CSHARP_ROOT_MARKERS, DOTNET_FSHARP_ROOT_MARKERS, KIND_EXTENSIONS, } from "../file-kinds.js";
|
|
16
|
-
import { direntsHaveMarkerGlobMatch, isAtOrAboveHomeDir, isFullyQualified, isWindowsPath, pathsEqual, } from "../path-utils.js";
|
|
18
|
+
import { CARGO_WORKSPACE_MEMBER_DIALECT, direntsHaveMarkerGlobMatch, isAtOrAboveHomeDir, isFullyQualified, isWindowsPath, matchesWorkspaceMemberPattern, pathsEqual, } from "../path-utils.js";
|
|
17
19
|
import { ensureTool, findManagedToolBinary, getToolEnvironment, getToolPath, } from "../installer/index.js";
|
|
20
|
+
import * as installer from "../installer/index.js";
|
|
21
|
+
import { classifyProbeFailure, describeInstallAttempt, logAvailabilityDecision, } from "../dispatch/runners/utils/availability-policy.js";
|
|
18
22
|
import { resolveOpengrepConfig } from "../opengrep-config.js";
|
|
19
23
|
import { isZizmorAuditTarget, resolveZizmorGitHubToken, } from "../zizmor-config.js";
|
|
20
24
|
import { logLatency } from "../latency-logger.js";
|
|
@@ -22,6 +26,7 @@ import { logSessionStart } from "../sessionstart-logger.js";
|
|
|
22
26
|
import { findLocalSgconfig, resolveBaselineSgconfig } from "../sgconfig.js";
|
|
23
27
|
import { findLocalTyposConfig } from "../typos-config.js";
|
|
24
28
|
import { resolvePackagePath } from "../package-root.js";
|
|
29
|
+
import { hasCargoWorkspaceTable, readCargoWorkspaceExclude, readCargoWorkspaceMembers, readTextFileOrUndefined, } from "../cargo-manifest.js";
|
|
25
30
|
import { resolveAstGrepNativeExe } from "./wait-policy/index.js";
|
|
26
31
|
import { hasSpawnFailureKind, isCommandAvailableAsync, safeSpawnAsync, } from "../safe-spawn.js";
|
|
27
32
|
import { launchLSP } from "./launch.js";
|
|
@@ -30,6 +35,7 @@ import { resolveJavaRuntimeEnv } from "./jvm-runtime.js";
|
|
|
30
35
|
import { normalizeMapKey } from "./path-utils.js";
|
|
31
36
|
import { getRubyVersionDirNamesSync } from "./ruby-drive-dirs.js";
|
|
32
37
|
import { getProcessSingleton } from "../process-singletons.js";
|
|
38
|
+
import { createGenerationSource, } from "../generation-guard.js";
|
|
33
39
|
const FIXTURE_ROOT_SEGMENTS = new Set(["__fixtures__", "testdata"]);
|
|
34
40
|
const FALLBACK_PROJECT_MARKERS = [
|
|
35
41
|
".git",
|
|
@@ -252,6 +258,49 @@ function canInstall(allowInstall) {
|
|
|
252
258
|
const DIRECT_LSP_NEGATIVE_TTL_MS = Math.max(30_000, Number.parseInt(process.env.PI_LENS_DIRECT_LSP_NEGATIVE_TTL_MS ?? "600000", 10) || 600_000);
|
|
253
259
|
const directLspCommandUnavailableUntil = new Map();
|
|
254
260
|
const directLspCommandSkipLoggedUntil = new Map();
|
|
261
|
+
// Availability rows are emitted from the same async launch path that owns the
|
|
262
|
+
// live LSP generation. A session reset can retire that generation while a
|
|
263
|
+
// managed lookup, install, or launch is still awaiting; stale work must not
|
|
264
|
+
// publish into the replacement session (#2351, shape 22).
|
|
265
|
+
const lspLaunchAvailabilityGeneration = createGenerationSource("lsp-launch-availability");
|
|
266
|
+
export function resetLspLaunchAvailabilityGeneration() {
|
|
267
|
+
lspLaunchAvailabilityGeneration.bump();
|
|
268
|
+
}
|
|
269
|
+
function staleLaunch(generation, subject, proc) {
|
|
270
|
+
if (generation.isCurrent())
|
|
271
|
+
return false;
|
|
272
|
+
try {
|
|
273
|
+
proc?.process?.kill();
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
// Best-effort cleanup for a process returned after service retirement.
|
|
277
|
+
}
|
|
278
|
+
generation.guardedWrite(subject, () => undefined);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
async function installEvidenceForLaunch(toolId, installed, attempt) {
|
|
282
|
+
const evidence = describeInstallAttempt(attempt);
|
|
283
|
+
const confirmedManagedPath = await findManagedToolBinary(toolId);
|
|
284
|
+
return {
|
|
285
|
+
...evidence,
|
|
286
|
+
binary: path.basename(installed),
|
|
287
|
+
...(confirmedManagedPath !== undefined &&
|
|
288
|
+
pathsEqual(confirmedManagedPath, installed) && {
|
|
289
|
+
source: "managed-dir",
|
|
290
|
+
}),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function captureInstallAttempt(toolId) {
|
|
294
|
+
try {
|
|
295
|
+
// Capture synchronously after ensureTool resolves. Reading this later, after
|
|
296
|
+
// launch/evidence awaits, can observe another concurrent ensure's outcome.
|
|
297
|
+
return installer.getInstallAttempt?.(toolId);
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// Older test doubles do not expose this production export.
|
|
301
|
+
}
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
255
304
|
/** Re-arm direct-command availability for the next session. */
|
|
256
305
|
export function resetDirectLspCommandAvailability() {
|
|
257
306
|
directLspCommandUnavailableUntil.clear();
|
|
@@ -301,6 +350,7 @@ function markDirectLspCommandUnavailable(command) {
|
|
|
301
350
|
}
|
|
302
351
|
const PI_LENS_BIN_DIR = path.join(getGlobalPiLensDir(), "bin");
|
|
303
352
|
export async function resolveAndLaunch(spec, allowInstall) {
|
|
353
|
+
const generation = lspLaunchAvailabilityGeneration.capture();
|
|
304
354
|
const toolLabel = spec.managedToolId ??
|
|
305
355
|
spec.candidates[spec.candidates.length - 1] ??
|
|
306
356
|
"unknown";
|
|
@@ -323,9 +373,13 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
323
373
|
// `findManagedNodeToolBinary`'s npm-managed fast path (runner-helpers.ts)
|
|
324
374
|
// and `SecurityScanClient.probeVersion`'s equivalent fix for the CLI-scan
|
|
325
375
|
// half of this same issue (#2140, landed in PR #2148/#2137).
|
|
376
|
+
const managedProbeStartedAt = Date.now();
|
|
326
377
|
const managedCandidate = spec.managedToolId
|
|
327
378
|
? await findManagedToolBinary(spec.managedToolId)
|
|
328
379
|
: undefined;
|
|
380
|
+
if (staleLaunch(generation, `${toolLabel}:findManagedToolBinary`)) {
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
329
383
|
const candidates = managedCandidate && !spec.candidates.includes(managedCandidate)
|
|
330
384
|
? [managedCandidate, ...spec.candidates]
|
|
331
385
|
: spec.candidates;
|
|
@@ -356,6 +410,9 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
356
410
|
cwd: spec.cwd,
|
|
357
411
|
env: spec.env,
|
|
358
412
|
});
|
|
413
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:${command}`, proc)) {
|
|
414
|
+
return undefined;
|
|
415
|
+
}
|
|
359
416
|
logLatency({
|
|
360
417
|
type: "phase",
|
|
361
418
|
phase: "lsp_launch_candidate_success",
|
|
@@ -369,9 +426,36 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
369
426
|
},
|
|
370
427
|
});
|
|
371
428
|
logSessionStart(`lsp launch candidate success tool=${toolLabel} idx=${index} command=${command} source=direct`);
|
|
429
|
+
// The managed-dir fast path (#2140) IS the availability probe for a
|
|
430
|
+
// release-managed tool: a real spawn just confirmed the binary
|
|
431
|
+
// findManagedToolBinary resolved actually launches. Gated on the exact
|
|
432
|
+
// managed candidate (never a later bare-PATH fallback), so a session
|
|
433
|
+
// start with the binary present emits exactly one decision and a
|
|
434
|
+
// developer-PATH-resolved copy (no managed binary at all) emits none —
|
|
435
|
+
// unchanged from before this fix.
|
|
436
|
+
if (managedCandidate !== undefined && command === managedCandidate) {
|
|
437
|
+
logAvailabilityDecision({
|
|
438
|
+
tool: toolLabel,
|
|
439
|
+
verdict: "available",
|
|
440
|
+
outcome: "success",
|
|
441
|
+
cause: "ok",
|
|
442
|
+
elapsedMs: Date.now() - managedProbeStartedAt,
|
|
443
|
+
latched: false,
|
|
444
|
+
producer: "lsp-launch",
|
|
445
|
+
classifiedBy: "probe",
|
|
446
|
+
evidence: {
|
|
447
|
+
binary: path.basename(managedCandidate),
|
|
448
|
+
source: "managed-dir",
|
|
449
|
+
correctsLatchedRow: false,
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
}
|
|
372
453
|
return { process: proc, source: "direct" };
|
|
373
454
|
}
|
|
374
455
|
catch (err) {
|
|
456
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:${command}`)) {
|
|
457
|
+
return undefined;
|
|
458
|
+
}
|
|
375
459
|
const message = err instanceof Error ? err.message : String(err);
|
|
376
460
|
// Defer logging: only a failure if no later candidate/install succeeds.
|
|
377
461
|
candidateFailures.push({ index, command, message, err });
|
|
@@ -419,8 +503,40 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
419
503
|
}
|
|
420
504
|
// Step 3 — managed install via installer registry
|
|
421
505
|
if (spec.managedToolId) {
|
|
506
|
+
// Neither the managed-dir stat (#2140) nor any bare-PATH candidate
|
|
507
|
+
// resolved this tool — the negative counterpart to the fast-path
|
|
508
|
+
// "available" decision above, mirroring `SecurityScanClient.probeVersion`'s
|
|
509
|
+
// failure record so the negative case is visible in latency.log rather
|
|
510
|
+
// than swallowed by going straight to the install attempt.
|
|
511
|
+
const failedCandidate = candidateFailures.at(-1);
|
|
512
|
+
const classifiedFailure = classifyProbeFailure({
|
|
513
|
+
error: failedCandidate?.err instanceof Error
|
|
514
|
+
? failedCandidate.err
|
|
515
|
+
: undefined,
|
|
516
|
+
spawnFailure: {
|
|
517
|
+
kind: hasSpawnFailureKind(failedCandidate?.err, "tool-not-found")
|
|
518
|
+
? "tool-not-found"
|
|
519
|
+
: undefined,
|
|
520
|
+
},
|
|
521
|
+
}, { command: failedCandidate?.command });
|
|
522
|
+
logAvailabilityDecision({
|
|
523
|
+
tool: spec.managedToolId,
|
|
524
|
+
verdict: "unavailable",
|
|
525
|
+
outcome: classifiedFailure.outcome,
|
|
526
|
+
cause: classifiedFailure.cause,
|
|
527
|
+
elapsedMs: Date.now() - managedProbeStartedAt,
|
|
528
|
+
latched: false,
|
|
529
|
+
classifiedBy: "probe",
|
|
530
|
+
producer: "lsp-launch",
|
|
531
|
+
evidence: classifiedFailure.evidence,
|
|
532
|
+
});
|
|
422
533
|
logSessionStart(`lsp launch ensure-tool start tool=${spec.managedToolId} cwd=${spec.cwd}`);
|
|
534
|
+
const installStartedAt = Date.now();
|
|
423
535
|
const installed = await ensureTool(spec.managedToolId);
|
|
536
|
+
const installAttempt = captureInstallAttempt(spec.managedToolId);
|
|
537
|
+
if (staleLaunch(generation, `${toolLabel}:ensureTool`)) {
|
|
538
|
+
return undefined;
|
|
539
|
+
}
|
|
424
540
|
logSessionStart(`lsp launch ensure-tool result tool=${spec.managedToolId} installed=${installed ? "yes" : "no"} path=${installed ?? ""}`);
|
|
425
541
|
logLatency({
|
|
426
542
|
type: "phase",
|
|
@@ -439,6 +555,9 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
439
555
|
cwd: spec.cwd,
|
|
440
556
|
env: spec.env,
|
|
441
557
|
});
|
|
558
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:managed`, proc)) {
|
|
559
|
+
return undefined;
|
|
560
|
+
}
|
|
442
561
|
logSessionStart(`lsp launch managed success tool=${spec.managedToolId} command=${installed} source=managed`);
|
|
443
562
|
logLatency({
|
|
444
563
|
type: "phase",
|
|
@@ -450,9 +569,37 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
450
569
|
command: installed,
|
|
451
570
|
},
|
|
452
571
|
});
|
|
572
|
+
// Compensating row for the "unavailable" decision logged above (#1606
|
|
573
|
+
// shape): the install fixed exactly what the fast path found missing,
|
|
574
|
+
// so the durable record must not be left saying the tool is off.
|
|
575
|
+
// `source` is only asserted when a fresh managed-dir lookup confirms
|
|
576
|
+
// the install actually landed in ~/.pi-lens/bin (github/maven/archive
|
|
577
|
+
// strategies) rather than an npm/pip/gem install elsewhere, so the
|
|
578
|
+
// evidence never claims a resolution this call didn't derive.
|
|
579
|
+
const evidence = await installEvidenceForLaunch(spec.managedToolId, installed, installAttempt);
|
|
580
|
+
if (staleLaunch(generation, `${toolLabel}:managed-evidence`, proc)) {
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
logAvailabilityDecision({
|
|
584
|
+
tool: spec.managedToolId,
|
|
585
|
+
verdict: "available",
|
|
586
|
+
outcome: "success",
|
|
587
|
+
cause: "ok",
|
|
588
|
+
elapsedMs: Date.now() - installStartedAt,
|
|
589
|
+
latched: false,
|
|
590
|
+
classifiedBy: "caller",
|
|
591
|
+
producer: "lsp-launch",
|
|
592
|
+
evidence: {
|
|
593
|
+
...evidence,
|
|
594
|
+
correctsLatchedRow: false,
|
|
595
|
+
},
|
|
596
|
+
});
|
|
453
597
|
return { process: proc, source: "managed" };
|
|
454
598
|
}
|
|
455
599
|
catch (err) {
|
|
600
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:managed-rejection`)) {
|
|
601
|
+
return undefined;
|
|
602
|
+
}
|
|
456
603
|
const message = err instanceof Error ? err.message : String(err);
|
|
457
604
|
logSessionStart(`lsp launch managed failed tool=${spec.managedToolId} command=${installed} error=${message}`);
|
|
458
605
|
logLatency({
|
|
@@ -476,12 +623,19 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
476
623
|
const reinstalled = await ensureTool(spec.managedToolId, {
|
|
477
624
|
forceReinstall: true,
|
|
478
625
|
});
|
|
626
|
+
const reinstallAttempt = captureInstallAttempt(spec.managedToolId);
|
|
627
|
+
if (staleLaunch(generation, `${toolLabel}:forceReinstall`)) {
|
|
628
|
+
return undefined;
|
|
629
|
+
}
|
|
479
630
|
if (reinstalled) {
|
|
480
631
|
try {
|
|
481
632
|
const proc = await launchLSP(reinstalled, spec.args, {
|
|
482
633
|
cwd: spec.cwd,
|
|
483
634
|
env: spec.env,
|
|
484
635
|
});
|
|
636
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:forceReinstall`, proc)) {
|
|
637
|
+
return undefined;
|
|
638
|
+
}
|
|
485
639
|
logSessionStart(`lsp launch managed force-reinstall success tool=${spec.managedToolId} command=${reinstalled}`);
|
|
486
640
|
logLatency({
|
|
487
641
|
type: "phase",
|
|
@@ -493,6 +647,24 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
493
647
|
command: reinstalled,
|
|
494
648
|
},
|
|
495
649
|
});
|
|
650
|
+
const evidence = await installEvidenceForLaunch(spec.managedToolId, reinstalled, reinstallAttempt);
|
|
651
|
+
if (staleLaunch(generation, `${toolLabel}:forceReinstall-evidence`, proc)) {
|
|
652
|
+
return undefined;
|
|
653
|
+
}
|
|
654
|
+
logAvailabilityDecision({
|
|
655
|
+
tool: spec.managedToolId,
|
|
656
|
+
verdict: "available",
|
|
657
|
+
outcome: "success",
|
|
658
|
+
cause: "ok",
|
|
659
|
+
elapsedMs: Date.now() - installStartedAt,
|
|
660
|
+
latched: false,
|
|
661
|
+
classifiedBy: "caller",
|
|
662
|
+
producer: "lsp-launch",
|
|
663
|
+
evidence: {
|
|
664
|
+
...evidence,
|
|
665
|
+
correctsLatchedRow: false,
|
|
666
|
+
},
|
|
667
|
+
});
|
|
496
668
|
return { process: proc, source: "managed" };
|
|
497
669
|
}
|
|
498
670
|
catch (retryErr) {
|
|
@@ -505,20 +677,35 @@ export async function resolveAndLaunch(spec, allowInstall) {
|
|
|
505
677
|
}
|
|
506
678
|
}
|
|
507
679
|
// Step 4 — language-native runtime install (go install, gem install, …)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
680
|
+
const runtimeInstall = spec.runtimeInstall;
|
|
681
|
+
const runtimeAvailable = runtimeInstall
|
|
682
|
+
? await isOnPath(runtimeInstall.runtimeCommand)
|
|
683
|
+
: false;
|
|
684
|
+
if (staleLaunch(generation, `${toolLabel}:runtimeAvailability`)) {
|
|
685
|
+
return undefined;
|
|
686
|
+
}
|
|
687
|
+
if (runtimeInstall && runtimeAvailable) {
|
|
688
|
+
const ok = await runtimeInstall.install();
|
|
689
|
+
if (staleLaunch(generation, `${toolLabel}:runtimeInstall`)) {
|
|
690
|
+
return undefined;
|
|
691
|
+
}
|
|
511
692
|
if (ok) {
|
|
512
|
-
const retry =
|
|
693
|
+
const retry = runtimeInstall.retryCandidates ?? spec.candidates;
|
|
513
694
|
for (const command of retry) {
|
|
514
695
|
try {
|
|
515
696
|
const proc = await launchLSP(command, spec.args, {
|
|
516
697
|
cwd: spec.cwd,
|
|
517
698
|
env: spec.env,
|
|
518
699
|
});
|
|
700
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:runtime`, proc)) {
|
|
701
|
+
return undefined;
|
|
702
|
+
}
|
|
519
703
|
return { process: proc, source: "managed" };
|
|
520
704
|
}
|
|
521
705
|
catch (err) {
|
|
706
|
+
if (staleLaunch(generation, `${toolLabel}:launchLSP:runtime`)) {
|
|
707
|
+
return undefined;
|
|
708
|
+
}
|
|
522
709
|
trackRuntimeFailure(err);
|
|
523
710
|
// try next
|
|
524
711
|
}
|
|
@@ -629,12 +816,15 @@ async function resolveAndLaunchTreeBinary(spec, allowInstall) {
|
|
|
629
816
|
return undefined;
|
|
630
817
|
}
|
|
631
818
|
}
|
|
632
|
-
function
|
|
819
|
+
function nodeBinLocalCandidates(root, baseName) {
|
|
633
820
|
const localBase = path.join(root, "node_modules", ".bin", baseName);
|
|
634
821
|
if (process.platform === "win32") {
|
|
635
|
-
return [`${localBase}.cmd`, `${localBase}.exe
|
|
822
|
+
return [`${localBase}.cmd`, `${localBase}.exe`];
|
|
636
823
|
}
|
|
637
|
-
return [localBase
|
|
824
|
+
return [localBase];
|
|
825
|
+
}
|
|
826
|
+
function nodeBinCandidates(root, baseName) {
|
|
827
|
+
return [...nodeBinLocalCandidates(root, baseName), baseName];
|
|
638
828
|
}
|
|
639
829
|
function normalizeSlashKey(value) {
|
|
640
830
|
const normalized = path.resolve(value).replace(/\\/g, "/");
|
|
@@ -689,6 +879,7 @@ function createInteractiveServer(spec) {
|
|
|
689
879
|
name: spec.name,
|
|
690
880
|
extensions: spec.extensions,
|
|
691
881
|
root: spec.root,
|
|
882
|
+
fallbackFor: spec.fallbackFor,
|
|
692
883
|
availabilityKey: typeof spec.command === "string" && isSimpleCommand(spec.command)
|
|
693
884
|
? spec.command
|
|
694
885
|
: undefined,
|
|
@@ -1260,33 +1451,6 @@ export function DenoExcludeRoot(primary) {
|
|
|
1260
1451
|
return primary(file);
|
|
1261
1452
|
};
|
|
1262
1453
|
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Find the active Python interpreter inside the nearest virtual environment.
|
|
1265
|
-
* Search order: VIRTUAL_ENV → CONDA_PREFIX → .venv → venv (all under root).
|
|
1266
|
-
* Returns undefined when no venv python binary is found.
|
|
1267
|
-
*/
|
|
1268
|
-
export async function detectPythonVenv(root) {
|
|
1269
|
-
const isWin = process.platform === "win32";
|
|
1270
|
-
const candidates = [
|
|
1271
|
-
process.env.VIRTUAL_ENV,
|
|
1272
|
-
process.env.CONDA_PREFIX,
|
|
1273
|
-
path.join(root, ".venv"),
|
|
1274
|
-
path.join(root, "venv"),
|
|
1275
|
-
].filter((v) => Boolean(v));
|
|
1276
|
-
for (const venv of candidates) {
|
|
1277
|
-
const pythonPath = isWin
|
|
1278
|
-
? path.join(venv, "Scripts", "python.exe")
|
|
1279
|
-
: path.join(venv, "bin", "python");
|
|
1280
|
-
try {
|
|
1281
|
-
await access(pythonPath);
|
|
1282
|
-
return pythonPath;
|
|
1283
|
-
}
|
|
1284
|
-
catch {
|
|
1285
|
-
// not found — try next candidate
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
return undefined;
|
|
1289
|
-
}
|
|
1290
1454
|
// --- Server Definitions ---
|
|
1291
1455
|
const JS_TS_LSP_EXTENSIONS = KIND_EXTENSIONS["jsts"].filter((ext) => ext !== ".svelte" && ext !== ".vue");
|
|
1292
1456
|
// TypeScript identity and tooling discovery deliberately use separate marker
|
|
@@ -1518,6 +1682,7 @@ export const TypeScriptServer = {
|
|
|
1518
1682
|
export const DenoServer = {
|
|
1519
1683
|
id: "deno",
|
|
1520
1684
|
name: "Deno Language Server",
|
|
1685
|
+
fallbackFor: "typescript",
|
|
1521
1686
|
extensions: JS_TS_LSP_EXTENSIONS,
|
|
1522
1687
|
autoPropagateDiagnostics: true,
|
|
1523
1688
|
root: createRootDetector(["deno.json", "deno.jsonc"]),
|
|
@@ -1544,7 +1709,8 @@ export const PythonServer = {
|
|
|
1544
1709
|
"poetry.lock",
|
|
1545
1710
|
])),
|
|
1546
1711
|
async spawn(root, options) {
|
|
1547
|
-
const
|
|
1712
|
+
const pythonEnvironment = await detectPythonEnvironment(root);
|
|
1713
|
+
const env = augmentPythonEnvironment(await getToolEnvironment(), pythonEnvironment);
|
|
1548
1714
|
let source = "direct";
|
|
1549
1715
|
// openFilesOnly: true — analyse only open files rather than the full workspace.
|
|
1550
1716
|
// Avoids the 5–14 s cold-start on large projects caused by workspace-wide
|
|
@@ -1554,36 +1720,65 @@ export const PythonServer = {
|
|
|
1554
1720
|
...(pythonPath ? { pythonPath } : {}),
|
|
1555
1721
|
openFilesOnly: true,
|
|
1556
1722
|
});
|
|
1557
|
-
//
|
|
1558
|
-
//
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1723
|
+
// Project ownership outranks checker preference: exhaust explicit project
|
|
1724
|
+
// candidates before a bare command can resolve to pi-lens's managed bin or
|
|
1725
|
+
// the host PATH. Within the project tier, preserve the established
|
|
1726
|
+
// pyright → basedpyright → ty preference.
|
|
1727
|
+
const projectPyright = await resolveAndLaunch({
|
|
1728
|
+
candidates: [
|
|
1729
|
+
...pythonEnvironmentToolCandidates(pythonEnvironment, "pyright-langserver"),
|
|
1730
|
+
...nodeBinLocalCandidates(root, "pyright-langserver"),
|
|
1731
|
+
...pythonEnvironmentToolCandidates(pythonEnvironment, "basedpyright-langserver"),
|
|
1732
|
+
...nodeBinLocalCandidates(root, "basedpyright-langserver"),
|
|
1733
|
+
],
|
|
1734
|
+
args: ["--stdio"],
|
|
1735
|
+
cwd: root,
|
|
1736
|
+
env,
|
|
1737
|
+
}, false);
|
|
1738
|
+
if (projectPyright) {
|
|
1566
1739
|
return {
|
|
1567
|
-
process:
|
|
1568
|
-
source:
|
|
1569
|
-
initialization: pyrightInit(pythonPath),
|
|
1740
|
+
process: projectPyright.process,
|
|
1741
|
+
source: projectPyright.source,
|
|
1742
|
+
initialization: pyrightInit(pythonEnvironment?.pythonPath),
|
|
1570
1743
|
};
|
|
1571
1744
|
}
|
|
1572
|
-
// ty
|
|
1573
|
-
//
|
|
1574
|
-
//
|
|
1575
|
-
//
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1745
|
+
// ty uses `ty server`, so it needs a separate launch phase from the
|
|
1746
|
+
// Pyright-compatible servers. It has no stable initializationOptions
|
|
1747
|
+
// equivalent to pyright's `pythonPath` (astral-sh/ty#2032); the child
|
|
1748
|
+
// environment and cwd provide interpreter discovery instead.
|
|
1749
|
+
const projectTy = await resolveAndLaunch({
|
|
1750
|
+
candidates: pythonEnvironmentToolCandidates(pythonEnvironment, "ty"),
|
|
1751
|
+
args: ["server"],
|
|
1752
|
+
cwd: root,
|
|
1753
|
+
env,
|
|
1754
|
+
}, false);
|
|
1755
|
+
if (projectTy) {
|
|
1756
|
+
return { process: projectTy.process, source: projectTy.source };
|
|
1757
|
+
}
|
|
1758
|
+
// With no project-owned checker, retain the existing PATH preference and
|
|
1759
|
+
// keep ty opt-in: pyright, then basedpyright, then ty. The augmented child
|
|
1760
|
+
// PATH includes pi-lens-managed bins before the inherited global PATH.
|
|
1761
|
+
const pathPyright = await resolveAndLaunch({
|
|
1762
|
+
candidates: ["pyright-langserver", "basedpyright-langserver"],
|
|
1763
|
+
args: ["--stdio"],
|
|
1764
|
+
cwd: root,
|
|
1765
|
+
env,
|
|
1766
|
+
}, false);
|
|
1767
|
+
if (pathPyright) {
|
|
1768
|
+
return {
|
|
1769
|
+
process: pathPyright.process,
|
|
1770
|
+
source: pathPyright.source,
|
|
1771
|
+
initialization: pyrightInit(pythonEnvironment?.pythonPath),
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
const pathTy = await resolveAndLaunch({
|
|
1775
|
+
candidates: ["ty"],
|
|
1776
|
+
args: ["server"],
|
|
1777
|
+
cwd: root,
|
|
1778
|
+
env,
|
|
1779
|
+
}, false);
|
|
1780
|
+
if (pathTy) {
|
|
1781
|
+
return { process: pathTy.process, source: pathTy.source };
|
|
1587
1782
|
}
|
|
1588
1783
|
// Discover a globally-installed pyright even when install is disabled;
|
|
1589
1784
|
// only the download is gated by canInstall.
|
|
@@ -1605,17 +1800,17 @@ export const PythonServer = {
|
|
|
1605
1800
|
const resolved = await resolveAndLaunch({ candidates: managedCandidates, args: ["--stdio"], cwd: root, env }, false);
|
|
1606
1801
|
if (!resolved)
|
|
1607
1802
|
return undefined;
|
|
1608
|
-
const pythonPath = await detectPythonVenv(root);
|
|
1609
1803
|
return {
|
|
1610
1804
|
process: resolved.process,
|
|
1611
1805
|
source,
|
|
1612
|
-
initialization: pyrightInit(pythonPath),
|
|
1806
|
+
initialization: pyrightInit(pythonEnvironment?.pythonPath),
|
|
1613
1807
|
};
|
|
1614
1808
|
},
|
|
1615
1809
|
};
|
|
1616
1810
|
export const PythonJediServer = {
|
|
1617
1811
|
id: "python-jedi",
|
|
1618
1812
|
name: "Jedi Language Server",
|
|
1813
|
+
fallbackFor: "python",
|
|
1619
1814
|
extensions: KIND_EXTENSIONS["python"],
|
|
1620
1815
|
root: RootWithFallback(createRootDetector([
|
|
1621
1816
|
".git",
|
|
@@ -1667,79 +1862,6 @@ export const GoServer = {
|
|
|
1667
1862
|
return { ...result, initialization: { ui: { semanticTokens: true } } };
|
|
1668
1863
|
},
|
|
1669
1864
|
};
|
|
1670
|
-
async function readTextFileOrUndefined(filePath) {
|
|
1671
|
-
try {
|
|
1672
|
-
return await readFile(filePath, "utf-8");
|
|
1673
|
-
}
|
|
1674
|
-
catch {
|
|
1675
|
-
return undefined;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
/**
|
|
1679
|
-
* Slice out ONE top-level TOML table's raw body — from its `[name]` heading
|
|
1680
|
-
* to the next top-level `[...]`/`[[...]]` heading or EOF. `members`/`exclude`
|
|
1681
|
-
* must be read from the `[workspace]` table specifically: `[package]` has its
|
|
1682
|
-
* OWN `exclude` key (the standard cargo-publish exclude list, conventionally
|
|
1683
|
-
* written above `[workspace]` in a virtual-manifest-less root crate), and a
|
|
1684
|
-
* whole-file regex would misread it as workspace membership (#1671 F4).
|
|
1685
|
-
*/
|
|
1686
|
-
function extractTomlTableSection(content, tableName) {
|
|
1687
|
-
const heading = new RegExp(`^\\[${tableName}\\][ \\t]*(?:#.*)?$`, "m");
|
|
1688
|
-
const match = heading.exec(content);
|
|
1689
|
-
if (!match)
|
|
1690
|
-
return "";
|
|
1691
|
-
const rest = content.slice(match.index + match[0].length);
|
|
1692
|
-
const nextHeading = rest.match(/^\[{1,2}[^\]]+\]{1,2}[ \t]*(?:#.*)?$/m);
|
|
1693
|
-
return nextHeading?.index !== undefined
|
|
1694
|
-
? rest.slice(0, nextHeading.index)
|
|
1695
|
-
: rest;
|
|
1696
|
-
}
|
|
1697
|
-
function parseTomlStringArray(content, key) {
|
|
1698
|
-
const match = content.match(new RegExp(`^[ \\t]*${key}[ \\t]*=[ \\t]*\\[([\\s\\S]*?)\\]`, "m"));
|
|
1699
|
-
if (!match)
|
|
1700
|
-
return [];
|
|
1701
|
-
return [...match[1].matchAll(/"([^"]*)"|'([^']*)'/g)].map((m) => (m[1] ?? m[2] ?? "").trim());
|
|
1702
|
-
}
|
|
1703
|
-
/** Turn one `/`-delimited glob SEGMENT into a regex source: `*` matches any
|
|
1704
|
-
* run of characters within the segment, `?` matches exactly one character,
|
|
1705
|
-
* everything else is escaped and literal. */
|
|
1706
|
-
function segmentGlobToRegExpSource(segment) {
|
|
1707
|
-
let out = "";
|
|
1708
|
-
for (const ch of segment) {
|
|
1709
|
-
if (ch === "*")
|
|
1710
|
-
out += "[^/]*";
|
|
1711
|
-
else if (ch === "?")
|
|
1712
|
-
out += "[^/]";
|
|
1713
|
-
else
|
|
1714
|
-
out += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
1715
|
-
}
|
|
1716
|
-
return out;
|
|
1717
|
-
}
|
|
1718
|
-
/**
|
|
1719
|
-
* A `members`/`exclude` entry names a path exactly, or globs it segment by
|
|
1720
|
-
* segment: `*` and `?` inside a segment work at any depth — one wildcard
|
|
1721
|
-
* segment (`crates/*`), a bare `*`, or several chained together for a
|
|
1722
|
-
* deeper fixed-depth layout — matching cargo's own `glob`-crate semantics
|
|
1723
|
-
* for a fixed number of path components.
|
|
1724
|
-
*
|
|
1725
|
-
* KNOWN LIMITATION (#1671 F6, documented rather than implemented): a
|
|
1726
|
-
* recursive `**` segment (matching a variable number of path components) is
|
|
1727
|
-
* NOT supported and never matches — cargo workspaces that rely on `**` to
|
|
1728
|
-
* pull in an arbitrarily-nested crate tree will under-hoist (the crate stays
|
|
1729
|
-
* independently rooted instead of joining the workspace). This is
|
|
1730
|
-
* deliberately out of #1671's scope: the common, and the issue's fixture,
|
|
1731
|
-
* shape is an explicit fixed-depth `members` list.
|
|
1732
|
-
*/
|
|
1733
|
-
function matchesCargoWorkspacePattern(pattern, relativePath) {
|
|
1734
|
-
const normalized = pattern.replace(/\/+$/, "");
|
|
1735
|
-
if (normalized.includes("**"))
|
|
1736
|
-
return false;
|
|
1737
|
-
const patternSegments = normalized.split("/");
|
|
1738
|
-
const pathSegments = relativePath.split("/");
|
|
1739
|
-
if (patternSegments.length !== pathSegments.length)
|
|
1740
|
-
return false;
|
|
1741
|
-
return patternSegments.every((segment, i) => new RegExp(`^${segmentGlobToRegExpSource(segment)}$`).test(pathSegments[i]));
|
|
1742
|
-
}
|
|
1743
1865
|
/**
|
|
1744
1866
|
* Given an ancestor Cargo.toml's raw contents that already contains a
|
|
1745
1867
|
* `[workspace]` table, decide whether it actually claims `childDir` as a
|
|
@@ -1766,13 +1888,21 @@ function cargoWorkspaceDeclaresMember(workspaceContent, parentDir, childDir) {
|
|
|
1766
1888
|
.join("/");
|
|
1767
1889
|
if (relativePath === "" || relativePath.startsWith(".."))
|
|
1768
1890
|
return false;
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1891
|
+
// Reuse the shared, `[workspace]`-scoped readers (review round 2, F4)
|
|
1892
|
+
// instead of hand-composing `extractTomlTableSection` +
|
|
1893
|
+
// `parseTomlStringArray` here — that hand-composition duplicated exactly
|
|
1894
|
+
// what `readCargoWorkspaceMembers`/`readCargoWorkspaceExclude` do, the
|
|
1895
|
+
// single-source-of-truth violation #2473 was filed to close for the OTHER
|
|
1896
|
+
// two Cargo.toml readers. Pattern matching goes through the ONE
|
|
1897
|
+
// workspace-member matcher for the same reason (#2591); cargo's dialect —
|
|
1898
|
+
// `**` never matches (#1671 F6), wildcards confined to one component, so
|
|
1899
|
+
// pattern and path must have the same component count — is
|
|
1900
|
+
// `CARGO_WORKSPACE_MEMBER_DIALECT`, not a private compiler here.
|
|
1901
|
+
const matches = (pattern) => matchesWorkspaceMemberPattern(pattern, relativePath, CARGO_WORKSPACE_MEMBER_DIALECT);
|
|
1902
|
+
const excluded = readCargoWorkspaceExclude(workspaceContent);
|
|
1903
|
+
if (excluded.some(matches))
|
|
1772
1904
|
return false;
|
|
1773
|
-
|
|
1774
|
-
const members = parseTomlStringArray(workspaceSection, "members");
|
|
1775
|
-
return members.some((pattern) => matchesCargoWorkspacePattern(pattern, relativePath));
|
|
1905
|
+
return readCargoWorkspaceMembers(workspaceContent).some(matches);
|
|
1776
1906
|
}
|
|
1777
1907
|
/**
|
|
1778
1908
|
* Bound a monorepo-hoist walk-up by the session ceiling: when `file` is inside
|
|
@@ -1811,7 +1941,7 @@ function RustWorkspaceRoot() {
|
|
|
1811
1941
|
const parentCargoPath = path.join(parent, "Cargo.toml");
|
|
1812
1942
|
const parentCargoContent = await readTextFileOrUndefined(parentCargoPath);
|
|
1813
1943
|
if (parentCargoContent !== undefined &&
|
|
1814
|
-
|
|
1944
|
+
hasCargoWorkspaceTable(parentCargoContent)) {
|
|
1815
1945
|
// Test membership against the ORIGINAL crate dir (`root`), never the
|
|
1816
1946
|
// walk cursor (`current`, which may already have climbed through
|
|
1817
1947
|
// gap directories that have no Cargo.toml of their own) — a
|
|
@@ -2119,6 +2249,7 @@ export const CSharpServer = {
|
|
|
2119
2249
|
export const OmniSharpServer = createInteractiveServer({
|
|
2120
2250
|
id: "omnisharp",
|
|
2121
2251
|
name: "OmniSharp",
|
|
2252
|
+
fallbackFor: "csharp",
|
|
2122
2253
|
extensions: KIND_EXTENSIONS["csharp"],
|
|
2123
2254
|
root: createRootDetector([...DOTNET_CSHARP_ROOT_MARKERS]),
|
|
2124
2255
|
language: "csharp",
|
|
@@ -2285,6 +2416,7 @@ export const ElixirServer = createInteractiveServer({
|
|
|
2285
2416
|
export const ElixirExpertServer = {
|
|
2286
2417
|
id: "expert",
|
|
2287
2418
|
name: "Expert",
|
|
2419
|
+
fallbackFor: "elixir",
|
|
2288
2420
|
extensions: KIND_EXTENSIONS["elixir"],
|
|
2289
2421
|
root: RootWithFallback(createRootDetector(["mix.exs"])),
|
|
2290
2422
|
availabilityKey: "expert",
|
|
@@ -2758,7 +2890,13 @@ export const OpengrepServer = {
|
|
|
2758
2890
|
// Gate B). NOTE: the napi runner is NOT a subset — it delegates to napi's native
|
|
2759
2891
|
// engine via root.findAll({rule}) (#206), the SAME Rust core as this LSP and the
|
|
2760
2892
|
// ast-grep CLI, so rule semantics are identical across all three. The LSP's edge
|
|
2761
|
-
// is engine-driven codeAction fixes, not faithfulness of matching.
|
|
2893
|
+
// is engine-driven codeAction fixes, not faithfulness of matching. #2347 closed
|
|
2894
|
+
// the one known divergence under Gate B: the LSP/CLI resolve embedded `<script>`
|
|
2895
|
+
// bodies in HTML and run `language: JavaScript` rules inside them, and the napi
|
|
2896
|
+
// fallback now mirrors that (each script body is reparsed as JS and findings are
|
|
2897
|
+
// translated back to file coordinates). A future ast-grep embedded-content
|
|
2898
|
+
// surface (for example `<style>` bodies, which 0.45.1 does NOT inject) must land
|
|
2899
|
+
// on both routes together or be recorded here as an accepted divergence.
|
|
2762
2900
|
const AST_GREP_KINDS = [
|
|
2763
2901
|
"csharp",
|
|
2764
2902
|
"cxx",
|
|
@@ -2779,7 +2917,6 @@ const AST_GREP_KINDS = [
|
|
|
2779
2917
|
"rust",
|
|
2780
2918
|
"scala",
|
|
2781
2919
|
"shell",
|
|
2782
|
-
"solidity",
|
|
2783
2920
|
"swift",
|
|
2784
2921
|
"yaml",
|
|
2785
2922
|
];
|