@herbertgao/pi-extensions 2026.9.0 → 2026.9.2
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/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +466 -41
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +15 -1
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- 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 +1072 -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 -9
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- 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 -9
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -3
- package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -6
- 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-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -9
- package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +3 -11
- 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 +40 -19
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -9
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- 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 +50 -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 +164 -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 +165 -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 +234 -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 -6
- 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-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +15 -5
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -44
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +27 -8
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- 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 +383 -27
- 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 +4 -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 +1 -2
- 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 +14 -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 +6 -3
- 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 +1 -2
- 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 +1 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +4 -3
- 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 -67
- 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/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -10
- 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/event-loop-monitor.js +2 -2
- 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-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-time.js +7 -2
- package/node_modules/pi-lens/dist/clients/file-utils.js +117 -10
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
- package/node_modules/pi-lens/dist/clients/format-service.js +6 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +385 -104
- package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +116 -22
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
- package/node_modules/pi-lens/dist/clients/git-guard.js +6 -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/grammar-source.js +3 -3
- 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 +289 -59
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +110 -236
- package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
- package/node_modules/pi-lens/dist/clients/language-profile.js +0 -9
- package/node_modules/pi-lens/dist/clients/language-registry.js +599 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +165 -9
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +34 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +160 -30
- package/node_modules/pi-lens/dist/clients/lens-engine.js +33 -41
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +77 -6
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -38
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +172 -33
- package/node_modules/pi-lens/dist/clients/lsp/config.js +484 -158
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +18 -5
- package/node_modules/pi-lens/dist/clients/lsp/index.js +892 -96
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -177
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -18
- 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/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +14 -7
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.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/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +3 -5
- package/node_modules/pi-lens/dist/clients/module-report.js +21 -46
- 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 -24
- 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 +70 -28
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +5 -1
- 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 +451 -15
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- 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 +79 -18
- 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-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- 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/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +28 -4
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +438 -122
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- 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 +16 -5
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
- package/node_modules/pi-lens/dist/clients/read-guard.js +26 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +155 -114
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- 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 +19 -3
- 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 +184 -32
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +179 -36
- 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 -12
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- 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/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
- package/node_modules/pi-lens/dist/clients/sgconfig.js +7 -6
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +4 -4
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- 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 +244 -0
- package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
- package/node_modules/pi-lens/dist/clients/tool-policy.js +92 -22
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +87 -100
- 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/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +6 -6
- package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -9
- package/node_modules/pi-lens/dist/clients/word-index-store.js +23 -12
- package/node_modules/pi-lens/dist/clients/word-index.js +252 -47
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +4 -1
- package/node_modules/pi-lens/dist/index.js +65899 -55340
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -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 +96 -25
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +104 -86
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/render-compact.js +1 -1
- package/node_modules/pi-lens/dist/tools/shared.js +0 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -2
- 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/globalconfig.md +20 -0
- package/node_modules/pi-lens/docs/language-coverage.md +2 -2
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- 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 +33 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +49 -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 +190 -0
- package/node_modules/pi-lens/docs/servercapabilities.md +7 -3
- 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/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +18 -35
- 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/rules/typos/_typos.toml +4 -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/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- 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 +6 -6
|
@@ -15,9 +15,10 @@ import { getGlobalPiLensDir } from "../../../file-utils.js";
|
|
|
15
15
|
import { createGenerationSource, } from "../../../generation-guard.js";
|
|
16
16
|
import { PathKeyedMap } from "../../../path-keyed-map.js";
|
|
17
17
|
import { normalizeEphemeralMapKey, normalizeMapKey, } from "../../../path-utils.js";
|
|
18
|
-
import { ensureTool, getInstallAttempt, getLastEnsureResolutionSource, getToolInstallStrategy, isSpawnableCommand, resetPathWalkMemo, } from "../../../installer/index.js";
|
|
18
|
+
import { ensureTool, findManagedToolBinary, getInstallAttempt, getLastEnsureResolutionSource, getToolInstallStrategy, isSpawnableCommand, resetPathWalkMemo, } from "../../../installer/index.js";
|
|
19
19
|
import { getServersForFileWithConfig, isServerDisabled, } from "../../../lsp/config.js";
|
|
20
|
-
import { findGlobalBinary } from "../../../package-manager.js";
|
|
20
|
+
import { findGlobalBinary, findLocalBinAt, findLocalBinsUpwards, findLocalBinUpwards, VENDOR_BIN_DIRS, VENV_BIN_DIRS, } from "../../../package-manager.js";
|
|
21
|
+
import { logLatency } from "../../../latency-logger.js";
|
|
21
22
|
import { safeSpawnAsync } from "../../../safe-spawn.js";
|
|
22
23
|
import { compareOrdinal } from "../../../string-utils.js";
|
|
23
24
|
import { getToolCommandSpec, shouldAutoInstallTool, } from "../../../tool-policy.js";
|
|
@@ -45,29 +46,21 @@ export function lspPrimaryCoversFile(ctx, serverId) {
|
|
|
45
46
|
const primary = getServersForFileWithConfig(ctx.filePath).find((s) => s.role !== "auxiliary");
|
|
46
47
|
return primary?.id === serverId;
|
|
47
48
|
}
|
|
49
|
+
const _realThisDir = (() => {
|
|
50
|
+
if (typeof __dirname !== "undefined")
|
|
51
|
+
return __dirname;
|
|
52
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
})();
|
|
54
|
+
let _thisDir = _realThisDir;
|
|
48
55
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
56
|
+
* Test-only override for pi-lens's OWN install-tree root (#2544 round 4 F1).
|
|
57
|
+
* `_thisDir` is fixed at module load from the running file's own location, so
|
|
58
|
+
* a test cannot otherwise place it under a synthetic HOME to prove the
|
|
59
|
+
* own-install walk's `ceiling: false` exemption without writing into this
|
|
60
|
+
* process's REAL, shared `node_modules` tree.
|
|
52
61
|
*/
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
let current = startDir;
|
|
56
|
-
const fsRoot = path.parse(current).root;
|
|
57
|
-
while (current !== fsRoot) {
|
|
58
|
-
if (fs.existsSync(path.join(current, "node_modules", ".bin"))) {
|
|
59
|
-
roots.push(current);
|
|
60
|
-
}
|
|
61
|
-
const parent = path.dirname(current);
|
|
62
|
-
if (parent === current)
|
|
63
|
-
break;
|
|
64
|
-
current = parent;
|
|
65
|
-
}
|
|
66
|
-
return roots;
|
|
67
|
-
}
|
|
68
|
-
let _thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
69
|
-
if (typeof __dirname !== "undefined") {
|
|
70
|
-
_thisDir = __dirname;
|
|
62
|
+
export function _setThisDirForTests(dir) {
|
|
63
|
+
_thisDir = dir ?? _realThisDir;
|
|
71
64
|
}
|
|
72
65
|
// Managed tools directory (~/.pi-lens/tools) — where ensureTool() installs binaries
|
|
73
66
|
const _managedToolsDir = path.join(getGlobalPiLensDir(), "tools");
|
|
@@ -89,9 +82,10 @@ function managedNodeToolCandidates(tool) {
|
|
|
89
82
|
* Verification verdicts for managed shims, keyed by path + mtime + size, so a
|
|
90
83
|
* reinstall re-verifies and a session start re-arms.
|
|
91
84
|
*
|
|
92
|
-
* A plain `Map`, not a `PathKeyedMap`:
|
|
93
|
-
*
|
|
94
|
-
*
|
|
85
|
+
* A plain `Map`, not a `PathKeyedMap`: every path keyed here is produced by
|
|
86
|
+
* `path.join` from one of two producers — `managedNodeToolCandidates` and the
|
|
87
|
+
* installer's `findManagedToolBinary` (#2140) — so the write and read forms are
|
|
88
|
+
* the same string by construction and cannot diverge on case or separator.
|
|
95
89
|
*/
|
|
96
90
|
const managedBinaryVerdicts = new Map();
|
|
97
91
|
/**
|
|
@@ -229,6 +223,32 @@ export async function findManagedNodeToolBinary(tool, verificationArgs = ["--ver
|
|
|
229
223
|
}
|
|
230
224
|
return null;
|
|
231
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* The release-managed binary for a tool (`~/.pi-lens/bin/<tool>`), or null when
|
|
228
|
+
* the registry does not put this tool there / nothing on disk actually runs.
|
|
229
|
+
*
|
|
230
|
+
* `findManagedToolBinary` is the INSTALLER's own lookup — the one `getToolPath`
|
|
231
|
+
* runs before PATH for every github/maven/archive-strategy tool, and the one
|
|
232
|
+
* `getToolEnvironment` puts at the front of a spawn's PATH. Calling it here is
|
|
233
|
+
* what makes probe and spawn resolve through a single definition instead of two
|
|
234
|
+
* (#2140): before this, the probe fell straight to the bare command name, missed
|
|
235
|
+
* PATH, and latched `missing` — while the install fallback a few hundred ms
|
|
236
|
+
* later handed the caller the very binary sitting in that directory. Every
|
|
237
|
+
* session, for every tool the user already had (7 unavailable/available pairs in
|
|
238
|
+
* one 3h dogfood window).
|
|
239
|
+
*
|
|
240
|
+
* Verification is the same `verifyManagedCandidate` the npm-shim rung above
|
|
241
|
+
* uses, for the same reason (#1657): `findManagedToolBinary` answers from a bare
|
|
242
|
+
* `fs.access`, and an on-disk binary that cannot run must not shadow a working
|
|
243
|
+
* PATH binary — it falls through instead.
|
|
244
|
+
*/
|
|
245
|
+
async function findManagedReleaseBinary(tool, verificationArgs = ["--version"]) {
|
|
246
|
+
const candidate = await findManagedToolBinary(tool);
|
|
247
|
+
if (!candidate)
|
|
248
|
+
return null;
|
|
249
|
+
const verdict = await verifyManagedCandidate(candidate, verificationArgs);
|
|
250
|
+
return verdict === "ok" || verdict === "unverified" ? candidate : null;
|
|
251
|
+
}
|
|
232
252
|
// =============================================================================
|
|
233
253
|
// VENV-AWARE COMMAND FINDER
|
|
234
254
|
// =============================================================================
|
|
@@ -239,21 +259,30 @@ export async function findManagedNodeToolBinary(tool, verificationArgs = ["--ver
|
|
|
239
259
|
* The resolved path is returned verbatim: every spawn consumer runs with
|
|
240
260
|
* `shell: false` (safe-spawn, #817), so wrapping it in quotes would make it
|
|
241
261
|
* a literal filename that ENOENTs on every platform (#1508).
|
|
262
|
+
*
|
|
263
|
+
* The venv directory list is `VENV_BIN_DIRS` (`package-manager.ts`), shared
|
|
264
|
+
* with `formatters.ts`'s `findInVenv` and `dead-code-client.ts`'s vulture
|
|
265
|
+
* candidates — three independent spellings of the same four directories before
|
|
266
|
+
* #2544 review F1.
|
|
267
|
+
*
|
|
268
|
+
* Resolution is a fixed lookup at `cwd` ONLY (`findLocalBinAt`, no ancestor
|
|
269
|
+
* walk). #2544 review round 3 folded this onto the shared ANCESTOR walker,
|
|
270
|
+
* on the reasoning that a monorepo package should find its repo-root venv —
|
|
271
|
+
* but that was an unrequested behaviour change with no #2514 defect behind
|
|
272
|
+
* it (#2514 is about the HOME ceiling, not about climbing at all), and the
|
|
273
|
+
* inversion is real: `~/code/app` with no venv of its own would resolve
|
|
274
|
+
* `~/code/.venv/bin/ruff` — an unrelated SIBLING project's interpreter —
|
|
275
|
+
* ahead of PATH. Reverted in round 4 F2. The HOME ceiling is moot here: a
|
|
276
|
+
* lookup at exactly `cwd` can never climb past it.
|
|
242
277
|
*/
|
|
243
278
|
export function createVenvFinder(command, windowsExt = "", verificationArgs = ["--version"]) {
|
|
244
279
|
return async (cwd) => {
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
for (const venvPath of venvPaths) {
|
|
252
|
-
const fullPath = path.join(cwd, venvPath);
|
|
253
|
-
if (fs.existsSync(fullPath)) {
|
|
254
|
-
return fullPath;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
280
|
+
const venvBin = findLocalBinAt(command, cwd, {
|
|
281
|
+
windowsExt,
|
|
282
|
+
binDirs: VENV_BIN_DIRS,
|
|
283
|
+
});
|
|
284
|
+
if (venvBin)
|
|
285
|
+
return venvBin;
|
|
257
286
|
// Managed-dir install (~/.pi-lens/tools/node_modules/.bin/<command>) — the
|
|
258
287
|
// same shim `ensureTool()` installs npm-strategy tools into. Checked BEFORE
|
|
259
288
|
// the bare-name PATH fallback (#1638): without this, a tool that only
|
|
@@ -267,6 +296,12 @@ export function createVenvFinder(command, windowsExt = "", verificationArgs = ["
|
|
|
267
296
|
const managed = await findManagedNodeToolBinary(command, verificationArgs);
|
|
268
297
|
if (managed)
|
|
269
298
|
return managed;
|
|
299
|
+
// Release-managed install (`~/.pi-lens/bin/<command>`) — where `ensureTool`
|
|
300
|
+
// puts every github/maven/archive-strategy tool. Same rung, same reason as
|
|
301
|
+
// the npm shim above, for the other half of the managed families (#2140).
|
|
302
|
+
const release = await findManagedReleaseBinary(command, verificationArgs);
|
|
303
|
+
if (release)
|
|
304
|
+
return release;
|
|
270
305
|
// Fall back to global
|
|
271
306
|
return command;
|
|
272
307
|
};
|
|
@@ -504,6 +539,41 @@ function sourceTagForToolId(toolId) {
|
|
|
504
539
|
return undefined;
|
|
505
540
|
}
|
|
506
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* `binary`/`source` for a probe that resolved through one of pi-lens's OWN
|
|
544
|
+
* managed installs rather than through PATH or a project venv (#2140). A reader
|
|
545
|
+
* of latency.log could otherwise not tell the two apart, and the whole point of
|
|
546
|
+
* the fix is that the managed directories now answer where PATH used to miss.
|
|
547
|
+
*
|
|
548
|
+
* BOTH managed rungs are asked, in the order `createVenvFinder` walks them
|
|
549
|
+
* (#2140 review F1). The first version asked only about the release directory,
|
|
550
|
+
* so every npm-shim hit — knip, jscpd, madge, pyright, biome, htmlhint,
|
|
551
|
+
* stylelint — logged an evidence-free row indistinguishable from a PATH hit,
|
|
552
|
+
* while the doc claimed the opposite. Each rung is asked of THE function that
|
|
553
|
+
* produced its own paths (`managedNodeToolCandidates`, `findManagedToolBinary`)
|
|
554
|
+
* and settled by string identity, never by a path-prefix predicate over a
|
|
555
|
+
* directory: a second opinion about which paths are managed is exactly the
|
|
556
|
+
* parallel-list drift `sourceTagForToolId` exists to avoid, and it would answer
|
|
557
|
+
* differently for case or separator variants.
|
|
558
|
+
*
|
|
559
|
+
* `binary` present IS the managed hit; `source` names the family whenever the
|
|
560
|
+
* command is a registry id (`sourceTagForToolId` reads the registry's own
|
|
561
|
+
* `installStrategy`). A managed shim whose COMMAND is not itself a registry id
|
|
562
|
+
* — `markdownlint-cli2`, installed under registry id `markdownlint` — carries
|
|
563
|
+
* `binary` alone rather than a guessed family. `binary` is a BASENAME, never
|
|
564
|
+
* the absolute path — same rule as every other evidence field (#1568 review).
|
|
565
|
+
*/
|
|
566
|
+
async function describeManagedResolution(tool, resolved) {
|
|
567
|
+
const managed = managedNodeToolCandidates(tool).includes(resolved) ||
|
|
568
|
+
(await findManagedToolBinary(tool)) === resolved;
|
|
569
|
+
if (!managed)
|
|
570
|
+
return {};
|
|
571
|
+
const source = sourceTagForToolId(tool);
|
|
572
|
+
return {
|
|
573
|
+
binary: path.basename(resolved),
|
|
574
|
+
...(source !== undefined && { source }),
|
|
575
|
+
};
|
|
576
|
+
}
|
|
507
577
|
/**
|
|
508
578
|
* How to tag a not-fresh install resolution in the compensating row's
|
|
509
579
|
* evidence (#1636 review, carried over from #1615's verify). `getInstallAttempt`
|
|
@@ -799,7 +869,16 @@ export function createAvailabilityChecker(command, windowsExt = "", versionArgs
|
|
|
799
869
|
});
|
|
800
870
|
return false;
|
|
801
871
|
}
|
|
872
|
+
// Resolution is measured separately from the spawn (#2140 review F2).
|
|
873
|
+
// It is no longer free — the managed rungs stat two directories and,
|
|
874
|
+
// on a first touch, pay their own verification spawn — and it runs
|
|
875
|
+
// BEFORE `startedAt`, so neither `durationMs` nor
|
|
876
|
+
// `recordAvailabilityProbeOverrun` can see it. Folding it into
|
|
877
|
+
// `durationMs` would instead charge the probe budget for work that
|
|
878
|
+
// budget does not govern, so the two spans are reported side by side.
|
|
879
|
+
const resolveStartedAt = Date.now();
|
|
802
880
|
const cmd = await findCommand(resolvedCwd);
|
|
881
|
+
const resolveMs = Date.now() - resolveStartedAt;
|
|
803
882
|
// #1995: a command cooling down after a RUNTIME timeout (lint or
|
|
804
883
|
// autofix lane blew its real budget) must not re-probe on every
|
|
805
884
|
// edit - the positive verdict is effectively cooled. Consult-only:
|
|
@@ -854,7 +933,11 @@ export function createAvailabilityChecker(command, windowsExt = "", versionArgs
|
|
|
854
933
|
elapsedMs,
|
|
855
934
|
hostStallMs,
|
|
856
935
|
classifiedBy: probeJoined ? "joined" : "probe",
|
|
857
|
-
evidence:
|
|
936
|
+
evidence: {
|
|
937
|
+
...describeProbeEvidence(result),
|
|
938
|
+
...(await describeManagedResolution(command, cmd)),
|
|
939
|
+
resolveMs,
|
|
940
|
+
},
|
|
858
941
|
});
|
|
859
942
|
return true;
|
|
860
943
|
}
|
|
@@ -1105,30 +1188,20 @@ export function resolveToolCommand(cwd, toolId) {
|
|
|
1105
1188
|
return null;
|
|
1106
1189
|
return resolveNodeToolCommand(cwd, spec.command, spec.windowsExt ?? ".cmd");
|
|
1107
1190
|
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Composer's `vendor/bin/<tool>` from the nearest ancestor that has one.
|
|
1193
|
+
*
|
|
1194
|
+
* Delegates to THE shared bin walker (#2544 review F1): this was a fifth
|
|
1195
|
+
* private copy of that climb, unceilinged, so a `vendor/bin` at or above
|
|
1196
|
+
* `$HOME` — which can never be this project's own Composer install — was
|
|
1197
|
+
* resolved as the project's tool (#2514, same class as `findInVendorBin`,
|
|
1198
|
+
* which had already been folded).
|
|
1199
|
+
*/
|
|
1108
1200
|
export function resolveVendorToolCommand(cwd, toolName, windowsExt = ".bat") {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
path.join("vendor", "bin", toolName),
|
|
1114
|
-
]
|
|
1115
|
-
: [path.join("vendor", "bin", toolName)];
|
|
1116
|
-
let dir = cwd;
|
|
1117
|
-
const root = path.parse(dir).root;
|
|
1118
|
-
while (true) {
|
|
1119
|
-
for (const candidate of candidates) {
|
|
1120
|
-
const full = path.join(dir, candidate);
|
|
1121
|
-
if (fs.existsSync(full))
|
|
1122
|
-
return full;
|
|
1123
|
-
}
|
|
1124
|
-
if (dir === root)
|
|
1125
|
-
break;
|
|
1126
|
-
const parent = path.dirname(dir);
|
|
1127
|
-
if (parent === dir)
|
|
1128
|
-
break;
|
|
1129
|
-
dir = parent;
|
|
1130
|
-
}
|
|
1131
|
-
return null;
|
|
1201
|
+
return (findLocalBinUpwards(toolName, cwd, {
|
|
1202
|
+
windowsExt,
|
|
1203
|
+
binDirs: VENDOR_BIN_DIRS,
|
|
1204
|
+
}) ?? null);
|
|
1132
1205
|
}
|
|
1133
1206
|
export async function resolveToolCommandWithInstallFallback(cwd, toolId, timeout = 5000) {
|
|
1134
1207
|
const spec = getToolCommandSpec(toolId);
|
|
@@ -1355,17 +1428,40 @@ function buildSgLocalBins() {
|
|
|
1355
1428
|
: [".cmd", ".exe", ""]
|
|
1356
1429
|
: [""];
|
|
1357
1430
|
const binaryCandidates = ["ast-grep", "sg"].flatMap((base) => extensions.map((ext) => `${base}${ext}`));
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1431
|
+
// THE shared bin walk (#2544 review F1). This used to be a private
|
|
1432
|
+
// `findNodeBinRoots` climb with no HOME ceiling, so on a box with a
|
|
1433
|
+
// home-level `node_modules` (the pi-extensions manifest installs its own
|
|
1434
|
+
// bins, #2514) `$HOME` itself came back as a bin root and an unrelated
|
|
1435
|
+
// ast-grep was probed as if it were this project's. `windowsExt: ""`
|
|
1436
|
+
// because the candidate names already carry their extensions — in a
|
|
1437
|
+
// shell-dependent ORDER (`hasBash` above) that a single `windowsExt`
|
|
1438
|
+
// cannot express.
|
|
1439
|
+
//
|
|
1440
|
+
// The PROJECT walk (from `process.cwd()`) keeps the default HOME ceiling —
|
|
1441
|
+
// a `node_modules/.bin/ast-grep` at or above `$HOME` can never be THIS
|
|
1442
|
+
// project's own dependency. pi-lens's OWN install-tree walk (from
|
|
1443
|
+
// `_thisDir`) is exempt (`ceiling: false`, #2544 round 4 F1): `pi install
|
|
1444
|
+
// npm:pi-lens` installs into the HOME-level manifest
|
|
1445
|
+
// (`~/package.json` → `~/node_modules/pi-lens`), so pi-lens's bundled
|
|
1446
|
+
// `@ast-grep/cli` shim can sit AT `~/node_modules/.bin/ast-grep` — exactly
|
|
1447
|
+
// the directory the PROJECT ceiling exists to stop at. A previous version
|
|
1448
|
+
// of this comment claimed the own install always lives "under"
|
|
1449
|
+
// `~/.pi/extensions/…`, below the ceiling; that is false for the
|
|
1450
|
+
// HOME-level manifest layout, and the round-2 ceiling silently made this
|
|
1451
|
+
// walk return nothing for it (PATH, `findGlobalBinary` and npx do not
|
|
1452
|
+
// cover this location either). `_managedToolsDir` (`~/.pi-lens/tools`) is
|
|
1453
|
+
// a fixed location, not a walk, so it is checked directly as before —
|
|
1454
|
+
// also own-install, since `ensureTool()` puts npm-strategy installs there.
|
|
1455
|
+
const projectWalkOptions = { windowsExt: "" };
|
|
1456
|
+
const ownInstallWalkOptions = { windowsExt: "", ceiling: false };
|
|
1457
|
+
const bins = [
|
|
1458
|
+
...findLocalBinsUpwards(binaryCandidates, _thisDir, ownInstallWalkOptions).map((binPath) => ({ path: binPath, source: "own-install" })),
|
|
1459
|
+
...findLocalBinsUpwards(binaryCandidates, process.cwd(), projectWalkOptions).map((binPath) => ({ path: binPath, source: "project" })),
|
|
1362
1460
|
];
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
if (fs.existsSync(localBin))
|
|
1368
|
-
bins.push(localBin);
|
|
1461
|
+
for (const candidate of binaryCandidates) {
|
|
1462
|
+
const managedBin = path.join(_managedToolsDir, "node_modules", ".bin", candidate);
|
|
1463
|
+
if (fs.existsSync(managedBin)) {
|
|
1464
|
+
bins.push({ path: managedBin, source: "own-install" });
|
|
1369
1465
|
}
|
|
1370
1466
|
}
|
|
1371
1467
|
return bins;
|
|
@@ -1397,12 +1493,12 @@ export async function isSgAvailableAsync() {
|
|
|
1397
1493
|
sgSweepHostStallMs = 0;
|
|
1398
1494
|
sgSweepUnreachable = [];
|
|
1399
1495
|
sgSweepDurablyMissing = [];
|
|
1400
|
-
// 1. Local node_modules/.bin
|
|
1401
|
-
for (const
|
|
1402
|
-
if (await probeAstGrepCommandAsync(
|
|
1403
|
-
sgCmd =
|
|
1496
|
+
// 1. Local node_modules/.bin (own-install tree, then project tree)
|
|
1497
|
+
for (const candidate of buildSgLocalBins()) {
|
|
1498
|
+
if (await probeAstGrepCommandAsync(candidate.path)) {
|
|
1499
|
+
sgCmd = candidate.path;
|
|
1404
1500
|
sgCmdArgs = [];
|
|
1405
|
-
noteSgAvailable(startedAt);
|
|
1501
|
+
noteSgAvailable(startedAt, { source: candidate.source });
|
|
1406
1502
|
return true;
|
|
1407
1503
|
}
|
|
1408
1504
|
}
|
|
@@ -1411,7 +1507,7 @@ export async function isSgAvailableAsync() {
|
|
|
1411
1507
|
if (await probeAstGrepCommandAsync(cmd)) {
|
|
1412
1508
|
sgCmd = cmd;
|
|
1413
1509
|
sgCmdArgs = [];
|
|
1414
|
-
noteSgAvailable(startedAt);
|
|
1510
|
+
noteSgAvailable(startedAt, { source: "global" });
|
|
1415
1511
|
return true;
|
|
1416
1512
|
}
|
|
1417
1513
|
}
|
|
@@ -1422,7 +1518,7 @@ export async function isSgAvailableAsync() {
|
|
|
1422
1518
|
if (globalBin && (await probeAstGrepCommandAsync(globalBin))) {
|
|
1423
1519
|
sgCmd = globalBin;
|
|
1424
1520
|
sgCmdArgs = [];
|
|
1425
|
-
noteSgAvailable(startedAt);
|
|
1521
|
+
noteSgAvailable(startedAt, { source: "global" });
|
|
1426
1522
|
return true;
|
|
1427
1523
|
}
|
|
1428
1524
|
}
|
|
@@ -1430,7 +1526,7 @@ export async function isSgAvailableAsync() {
|
|
|
1430
1526
|
if (await probeAstGrepCommandAsync("npx", ["--no", "--", "ast-grep"])) {
|
|
1431
1527
|
sgCmd = "npx";
|
|
1432
1528
|
sgCmdArgs = ["--no", "--", "ast-grep"];
|
|
1433
|
-
noteSgAvailable(startedAt);
|
|
1529
|
+
noteSgAvailable(startedAt, { source: "npx" });
|
|
1434
1530
|
return true;
|
|
1435
1531
|
}
|
|
1436
1532
|
// Nothing answered, and nothing answered TRANSIENTLY, while the verdict we
|
|
@@ -1479,6 +1575,11 @@ export async function isSgAvailableAsync() {
|
|
|
1479
1575
|
* `retained` marks the other provisional case (#1568 review F1): no candidate
|
|
1480
1576
|
* answered at all, so the winner being reported is the one the previous sweep
|
|
1481
1577
|
* found, kept rather than discarded on a timeout.
|
|
1578
|
+
*
|
|
1579
|
+
* `source` (omitted for a `retained` win, which resolved nothing new this
|
|
1580
|
+
* sweep) logs one `tool_bin_resolved` phase so F1's own-install-vs-project
|
|
1581
|
+
* ceiling distinction is visible in `latency.log` instead of only inferable
|
|
1582
|
+
* from a bin's absence (#2544 round 4 F4).
|
|
1482
1583
|
*/
|
|
1483
1584
|
function noteSgAvailable(startedAt, opts = {}) {
|
|
1484
1585
|
const provisional = sgSweepSawTransient;
|
|
@@ -1489,6 +1590,19 @@ function noteSgAvailable(startedAt, opts = {}) {
|
|
|
1489
1590
|
else {
|
|
1490
1591
|
sgLatch.noteAvailable();
|
|
1491
1592
|
}
|
|
1593
|
+
if (opts.source) {
|
|
1594
|
+
logLatency({
|
|
1595
|
+
type: "phase",
|
|
1596
|
+
phase: "tool_bin_resolved",
|
|
1597
|
+
filePath: "<pi-lens>",
|
|
1598
|
+
durationMs: Math.round(Date.now() - startedAt),
|
|
1599
|
+
metadata: {
|
|
1600
|
+
tool: "ast-grep",
|
|
1601
|
+
source: opts.source,
|
|
1602
|
+
ceilingApplied: opts.source === "project",
|
|
1603
|
+
},
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1492
1606
|
logAvailabilityDecision({
|
|
1493
1607
|
tool: "ast-grep",
|
|
1494
1608
|
verdict: "available",
|
|
@@ -14,8 +14,39 @@
|
|
|
14
14
|
import { createAvailabilityLatch, logAvailabilityDecision, } from "./availability-policy.js";
|
|
15
15
|
import { probeAvailabilityCandidates } from "./candidate-probe.js";
|
|
16
16
|
import { createAvailabilityProbeFlight } from "../../../availability-probe-flight.js";
|
|
17
|
+
import { createGenerationSource } from "../../../generation-guard.js";
|
|
17
18
|
import { createSingleFlight } from "../../../single-flight.js";
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Session generation for toolchain-availability resets (#2455 fix round 3, F2).
|
|
21
|
+
*
|
|
22
|
+
* `reset()` clears the memo and the latch, but a probe that was ALREADY in
|
|
23
|
+
* flight when it ran knows nothing about that. Without a generation, a
|
|
24
|
+
* post-reset caller joins the pre-reset flight and, worse, that flight's own
|
|
25
|
+
* settlement writes its stale verdict back into the freshly cleared latch — so
|
|
26
|
+
* a tool installed between sessions still read "missing" for the whole new
|
|
27
|
+
* session. That is #1674's defect read from both the sharing side and the
|
|
28
|
+
* settle side, and the reason `SingleFlightOptions.generation` exists.
|
|
29
|
+
*
|
|
30
|
+
* This is the repo's extracted primitive (`clients/generation-guard.ts`, #1754)
|
|
31
|
+
* rather than a hand-rolled counter (#2455 fix round 4, F1). Two things come
|
|
32
|
+
* with it that the hand-rolled form did not have: the source is declared by
|
|
33
|
+
* construction, so the #1754 ratchet can see it; and `guardedWrite` puts every
|
|
34
|
+
* superseded write in the degradation ledger as a bounded
|
|
35
|
+
* `generation-guard-stale-write` record per (source, subject), so a dogfood
|
|
36
|
+
* session can tell "the guard is working" from "the guard never fires" instead
|
|
37
|
+
* of watching superseded writes vanish silently (F4).
|
|
38
|
+
*
|
|
39
|
+
* A module-level source rather than a per-instance one, deliberately. It is a
|
|
40
|
+
* counter, so nothing has to be hand-maintained and no flight is retained for
|
|
41
|
+
* the sake of superseding it. And `toolchainProbeFlights` is itself shared
|
|
42
|
+
* ACROSS instances (#2131: two clients probing the same candidate list run one
|
|
43
|
+
* sweep), so its supersede signal cannot live on any one instance. The cost is
|
|
44
|
+
* that resetting one toolchain also supersedes another's in-flight sweep; that
|
|
45
|
+
* is at worst one extra probe, never a wrong verdict, and every registered
|
|
46
|
+
* reset fires in the same `session_start` block anyway.
|
|
47
|
+
*/
|
|
48
|
+
const toolchainGenerations = createGenerationSource("toolchain-availability");
|
|
49
|
+
const toolchainProbeFlights = createAvailabilityProbeFlight({ generation: toolchainGenerations.current });
|
|
19
50
|
/**
|
|
20
51
|
* Own one toolchain's availability: sweep the platform candidate list, memoize
|
|
21
52
|
* the path that answered, and park the verdict behind the shared latch so a
|
|
@@ -31,34 +62,61 @@ export function createToolchainAvailability(config) {
|
|
|
31
62
|
let sweepHostStallMs = 0;
|
|
32
63
|
/** What the last classified candidate returned, for the decision record. */
|
|
33
64
|
let sweepEvidence;
|
|
34
|
-
const ensureFlight = createSingleFlight(
|
|
65
|
+
const ensureFlight = createSingleFlight({
|
|
66
|
+
generation: toolchainGenerations.current,
|
|
67
|
+
});
|
|
35
68
|
async function findPath() {
|
|
36
69
|
if (toolPath)
|
|
37
70
|
return toolPath;
|
|
38
71
|
const paths = process.platform === "win32" ? config.windowsPaths : config.unixPaths;
|
|
72
|
+
const handle = toolchainGenerations.capture();
|
|
39
73
|
const shared = toolchainProbeFlights.run(`toolchain:${config.tool}|${config.probeArgs.join("|")}|${config.windowsPaths.join("|")}|${config.unixPaths.join("|")}`, () => probeAvailabilityCandidates(paths, config.probeArgs, config.budgetMs));
|
|
40
74
|
const sweep = await shared.promise;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
75
|
+
// A reset may have landed while this sweep was running. Its answer then
|
|
76
|
+
// describes the session that just ended, so it must not write itself back
|
|
77
|
+
// into the memo `reset()` just cleared, nor into the classification fields
|
|
78
|
+
// the replacement flight reads to build ITS verdict. The memo is the
|
|
79
|
+
// sharper half: a superseded sweep that writes `foundPath` latches a path
|
|
80
|
+
// the reset may have been called BECAUSE it went away, so the seam that
|
|
81
|
+
// exists to un-latch a false "missing" would instead latch a false
|
|
82
|
+
// "found". Callers already holding this promise still get what the sweep
|
|
83
|
+
// actually found.
|
|
84
|
+
handle.guardedWrite(`findPath:${config.tool}`, () => {
|
|
85
|
+
sweepSawTransient = sweep.sawTransient;
|
|
86
|
+
sweepTransientCause = sweep.transientCause;
|
|
87
|
+
sweepHostStallMs = sweep.hostStallMs;
|
|
88
|
+
sweepEvidence = sweep.evidence;
|
|
89
|
+
if (sweep.foundPath)
|
|
90
|
+
toolPath = sweep.foundPath;
|
|
91
|
+
});
|
|
47
92
|
return sweep.foundPath;
|
|
48
93
|
}
|
|
49
94
|
async function resolveAvailability() {
|
|
50
95
|
const startedAt = Date.now();
|
|
51
|
-
const
|
|
96
|
+
const handle = toolchainGenerations.capture();
|
|
97
|
+
const resolvedPath = await findPath();
|
|
98
|
+
const found = resolvedPath !== null;
|
|
99
|
+
// #2455 fix round 3, F2: a reset during the probe opened a NEW session.
|
|
100
|
+
// This flight answers the OLD one, so writing its verdict into the
|
|
101
|
+
// freshly cleared latch would re-latch a stale "missing" for the whole
|
|
102
|
+
// new session — the bug the reset exists to prevent, reintroduced by the
|
|
103
|
+
// reset's own timing. Report the verdict to this flight's own callers;
|
|
104
|
+
// do not latch it, and say so in the decision record's `latched`.
|
|
105
|
+
const superseded = !handle.isCurrent();
|
|
52
106
|
if (found) {
|
|
53
|
-
availabilityLatch.noteAvailable();
|
|
54
|
-
|
|
107
|
+
handle.guardedWrite(`latch:${config.tool}`, () => availabilityLatch.noteAvailable());
|
|
108
|
+
// The RESOLVED path, not the memo (#2455 fix round 4, F6). A superseded
|
|
109
|
+
// sweep is forbidden from writing `toolPath`, so reading the memo here
|
|
110
|
+
// logged `Go found: null` on exactly the branch this line exists to
|
|
111
|
+
// explain.
|
|
112
|
+
config.log(`${config.label} found: ${resolvedPath}`);
|
|
55
113
|
logAvailabilityDecision({
|
|
56
114
|
tool: config.tool,
|
|
57
115
|
verdict: "available",
|
|
58
116
|
outcome: "success",
|
|
59
117
|
cause: "ok",
|
|
60
118
|
elapsedMs: Date.now() - startedAt,
|
|
61
|
-
latched:
|
|
119
|
+
latched: !superseded,
|
|
62
120
|
hostStallMs: sweepHostStallMs,
|
|
63
121
|
budgetMs: config.budgetMs,
|
|
64
122
|
classifiedBy: "probe",
|
|
@@ -70,14 +128,14 @@ export function createToolchainAvailability(config) {
|
|
|
70
128
|
// whether the toolchain is installed; it expires instead of latching.
|
|
71
129
|
const outcome = sweepSawTransient ? "transient" : "missing";
|
|
72
130
|
const cause = sweepSawTransient ? sweepTransientCause : "not-found";
|
|
73
|
-
const retryAfterMs = availabilityLatch.noteUnavailable(outcome, cause);
|
|
131
|
+
const retryAfterMs = handle.guardedWrite(`latch:${config.tool}`, () => availabilityLatch.noteUnavailable(outcome, cause)) ?? 0;
|
|
74
132
|
logAvailabilityDecision({
|
|
75
133
|
tool: config.tool,
|
|
76
134
|
verdict: "unavailable",
|
|
77
135
|
outcome,
|
|
78
136
|
cause,
|
|
79
137
|
elapsedMs: Date.now() - startedAt,
|
|
80
|
-
latched: outcome !== "transient",
|
|
138
|
+
latched: !superseded && outcome !== "transient",
|
|
81
139
|
hostStallMs: sweepHostStallMs,
|
|
82
140
|
...(retryAfterMs > 0 && { retryAfterMs }),
|
|
83
141
|
budgetMs: config.budgetMs,
|
|
@@ -96,5 +154,16 @@ export function createToolchainAvailability(config) {
|
|
|
96
154
|
return memo;
|
|
97
155
|
return ensureFlight.run("availability", resolveAvailability);
|
|
98
156
|
}
|
|
99
|
-
|
|
157
|
+
function reset() {
|
|
158
|
+
toolPath = null;
|
|
159
|
+
availabilityLatch.reset();
|
|
160
|
+
// Supersede every sweep and availability flight already running, in this
|
|
161
|
+
// instance and in the shared registry. No `clear()`: the generation bump
|
|
162
|
+
// is what makes a stale flight unjoinable and unable to re-latch, and
|
|
163
|
+
// `SingleFlight.release`'s identity check already stops it from evicting
|
|
164
|
+
// its successor. Clearing the SHARED registry here would additionally
|
|
165
|
+
// drop another toolchain's live claim and cost it a duplicate sweep.
|
|
166
|
+
toolchainGenerations.bump();
|
|
167
|
+
}
|
|
168
|
+
return { findPath, isAvailable, reset };
|
|
100
169
|
}
|
|
@@ -13,24 +13,3 @@ export function readFileContent(filePath) {
|
|
|
13
13
|
return undefined;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Parse common tool output line into a diagnostic
|
|
18
|
-
* Format: file:line:col message (category)
|
|
19
|
-
*/
|
|
20
|
-
export function parseToolLine(line, toolName, filePath) {
|
|
21
|
-
const match = line.match(/^(.+?):(\d+):(\d+)\s+(.+?)\s*\((.+?)\)/);
|
|
22
|
-
if (!match)
|
|
23
|
-
return null;
|
|
24
|
-
return {
|
|
25
|
-
id: `${toolName}-${match[2]}-${match[5]}`,
|
|
26
|
-
message: `${match[5]}: ${match[4]}`,
|
|
27
|
-
filePath,
|
|
28
|
-
line: parseInt(match[2], 10),
|
|
29
|
-
column: parseInt(match[3], 10),
|
|
30
|
-
severity: line.includes("error") ? "error" : "warning",
|
|
31
|
-
semantic: "warning",
|
|
32
|
-
tool: toolName,
|
|
33
|
-
rule: match[5],
|
|
34
|
-
fixable: false,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
@@ -19,14 +19,7 @@ import { BoundedLruCache } from "../../bounded-cache.js";
|
|
|
19
19
|
import { compareOrdinal } from "../../string-utils.js";
|
|
20
20
|
// --- Constants ---
|
|
21
21
|
/** Overly broad patterns that match everything (cause false positive explosions) */
|
|
22
|
-
|
|
23
|
-
"$NAME",
|
|
24
|
-
"$FIELD",
|
|
25
|
-
"$_",
|
|
26
|
-
"$X",
|
|
27
|
-
"$VAR",
|
|
28
|
-
"$EXPR",
|
|
29
|
-
];
|
|
22
|
+
const OVERLY_BROAD_PATTERNS = ["$NAME", "$FIELD", "$_", "$X", "$VAR", "$EXPR"];
|
|
30
23
|
/** Maximum complexity score for rules in blockingOnly mode */
|
|
31
24
|
export const MAX_BLOCKING_RULE_COMPLEXITY = 8;
|
|
32
25
|
/**
|
|
@@ -126,7 +119,7 @@ export function loadYamlRulesFresh(ruleDir, severityFilter) {
|
|
|
126
119
|
cache.set(ruleDir, { rules, signature });
|
|
127
120
|
return rules;
|
|
128
121
|
}
|
|
129
|
-
|
|
122
|
+
function getCachedRules(ruleDir, severityFilter) {
|
|
130
123
|
if (!fs.existsSync(ruleDir)) {
|
|
131
124
|
return [];
|
|
132
125
|
}
|
|
@@ -179,17 +172,6 @@ export function isOverlyBroadPattern(pattern) {
|
|
|
179
172
|
return true;
|
|
180
173
|
return /^\$[A-Z_]+$/i.test(pattern.trim());
|
|
181
174
|
}
|
|
182
|
-
export function isValidCondition(condition) {
|
|
183
|
-
if (!condition)
|
|
184
|
-
return false;
|
|
185
|
-
if (condition.all !== undefined && condition.all.length === 0)
|
|
186
|
-
return false;
|
|
187
|
-
if (condition.any !== undefined && condition.any.length === 0)
|
|
188
|
-
return false;
|
|
189
|
-
if (isOverlyBroadPattern(condition.pattern))
|
|
190
|
-
return false;
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
175
|
export function isStructuredRule(rule) {
|
|
194
176
|
if (!rule.rule)
|
|
195
177
|
return false;
|
|
@@ -33,7 +33,6 @@ const yamllintRunner = {
|
|
|
33
33
|
id: "yamllint",
|
|
34
34
|
appliesTo: ["yaml"],
|
|
35
35
|
priority: PRIORITY.YAML_LINT,
|
|
36
|
-
enabledByDefault: true,
|
|
37
36
|
skipTestFiles: false,
|
|
38
37
|
async run(ctx) {
|
|
39
38
|
const cwd = ctx.cwd || process.cwd();
|
|
@@ -55,6 +54,7 @@ const yamllintRunner = {
|
|
|
55
54
|
if (!cmd)
|
|
56
55
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
57
56
|
const result = await safeSpawnAsync(cmd, ["-f", "parsable", ctx.filePath], {
|
|
57
|
+
cwd,
|
|
58
58
|
timeout: 15000,
|
|
59
59
|
});
|
|
60
60
|
// #1816: this runner read `result.status` zero times, so a yamllint
|