@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
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - On non-Windows: return path as-is (case-sensitive filesystem)
|
|
11
11
|
* - Always convert backslashes to forward slashes for Map key consistency
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, realpathSync } from "node:fs";
|
|
13
|
+
import { existsSync, readFileSync, realpathSync, statSync, } from "node:fs";
|
|
14
14
|
import * as os from "node:os";
|
|
15
15
|
import * as path from "node:path";
|
|
16
16
|
import { win32 } from "node:path";
|
|
@@ -61,6 +61,26 @@ export function isFullyQualified(filePath) {
|
|
|
61
61
|
? isFullyQualifiedWin32(filePath)
|
|
62
62
|
: isFullyQualifiedPosix(filePath);
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Shape-based absolute check (mirrors `toProjectRelativePath`'s idiom): a
|
|
66
|
+
* Windows-shaped path (drive-letter/UNC) is parsed with `win32.isAbsolute`
|
|
67
|
+
* regardless of host OS, since the host-default `path.isAbsolute` returns
|
|
68
|
+
* FALSE for a Windows-shaped path on POSIX (#1150 class) and would let a
|
|
69
|
+
* cross-platform-persisted relative path slip past this guard on Linux CI.
|
|
70
|
+
* MUST run on the RAW `filePath`, before `normalizeMapKey`: on Windows,
|
|
71
|
+
* `normalizeMapKey`'s nonexistent-path fallback (`resolveNonExisting`) calls
|
|
72
|
+
* `win32.resolve`, which silently makes any relative path absolute against
|
|
73
|
+
* `process.cwd()` — checking the normalized value would defeat this guard
|
|
74
|
+
* entirely on Windows.
|
|
75
|
+
*
|
|
76
|
+
* Promoted from a private copy in `clients/review-graph/service.ts` (#2477)
|
|
77
|
+
* so `clients/dispatch/dispatcher.ts`'s baseline-key guard (#2489) can share
|
|
78
|
+
* the same sanctioned check instead of hand-rolling a second one.
|
|
79
|
+
*/
|
|
80
|
+
export function isAbsoluteFilePath(filePath) {
|
|
81
|
+
const p = isWindowsPath(filePath) ? win32 : path;
|
|
82
|
+
return p.isAbsolute(filePath);
|
|
83
|
+
}
|
|
64
84
|
/**
|
|
65
85
|
* Split a path into its non-empty segments on EITHER separator (`\` or `/`),
|
|
66
86
|
* regardless of the running OS — the shape-safe form of `p.split(path.sep)` /
|
|
@@ -346,7 +366,30 @@ export function findNearestContaining(startDir, candidates) {
|
|
|
346
366
|
* directory in `names` order. Single source of truth for the "walk up
|
|
347
367
|
* looking for one of these config filenames" loop that `opengrep-config.ts`,
|
|
348
368
|
* `typos-config.ts`, `zizmor-config.ts`, and `sgconfig.ts` each hand-rolled
|
|
349
|
-
* independently (refs #680).
|
|
369
|
+
* independently (refs #680), and that `php-cs-fixer-config.ts` now delegates
|
|
370
|
+
* to as well (refs #2472 review F2).
|
|
371
|
+
*
|
|
372
|
+
* UNCEILINGED by default (refs #2472 review round 3, F1) — `options.homeDir`
|
|
373
|
+
* is opt-in, not default-on. A prior version applied the SAME `$HOME`
|
|
374
|
+
* ceiling as `findNearestMarkerRoot` unconditionally, which broke every one
|
|
375
|
+
* of these tools' actual discovery contract: each of them treats a config
|
|
376
|
+
* living directly at `$HOME` (`~/typos.toml`, `~/sgconfig.yml`, …) as the
|
|
377
|
+
* user's legitimate GLOBAL config, and reads it itself regardless of pi-lens
|
|
378
|
+
* — the ceiling didn't stop pi-lens from seeing an unrelated ancestor
|
|
379
|
+
* config, it stopped pi-lens from seeing the SAME config the tool was about
|
|
380
|
+
* to read on its own, so pi-lens silently fell back to (or, for typos,
|
|
381
|
+
* injected and let its own shipped `_typos.toml` merge over) the user's
|
|
382
|
+
* config where the tool's own resolver would have honored it. `php-cs-fixer`
|
|
383
|
+
* makes the same mismatch concrete: its detection gates
|
|
384
|
+
* (`hasPhpCsFixerConfig` via `findNearestContaining`, `phpCsFixerFormatter
|
|
385
|
+
* .detect` via its own `findUp`) are both unceilinged, so a ceilinged
|
|
386
|
+
* carriage here disagreed with its own gate — "config exists" from the gate,
|
|
387
|
+
* "config not found" from the resolver — and dropped the very `--config`
|
|
388
|
+
* argv #2472 exists to carry. Pass `options.homeDir` only when a caller
|
|
389
|
+
* affirmatively wants the ceiling (a config found at or above THAT directory
|
|
390
|
+
* is never returned); omitting it walks all the way to the filesystem root,
|
|
391
|
+
* matching `findNearestContaining`'s unceilinged behavior and every
|
|
392
|
+
* underlying tool's own discovery.
|
|
350
393
|
*
|
|
351
394
|
* Distinct from `findNearestContaining`, which returns the containing
|
|
352
395
|
* directory rather than the matched file path — use that one when the caller
|
|
@@ -356,8 +399,12 @@ export function findNearestContaining(startDir, candidates) {
|
|
|
356
399
|
* findLocalToolConfig(cwd, ["typos.toml", "_typos.toml", ".typos.toml"]);
|
|
357
400
|
* // → "/repo/typos.toml" if present, else undefined
|
|
358
401
|
*/
|
|
359
|
-
export function findLocalToolConfig(startDir, names) {
|
|
402
|
+
export function findLocalToolConfig(startDir, names, options = {}) {
|
|
403
|
+
const homeDir = options.homeDir !== undefined ? path.resolve(options.homeDir) : undefined;
|
|
360
404
|
for (const dir of walkUpDirs(startDir || process.cwd())) {
|
|
405
|
+
if (homeDir !== undefined && isAtOrAboveHomeDir(dir, homeDir)) {
|
|
406
|
+
return undefined;
|
|
407
|
+
}
|
|
361
408
|
for (const name of names) {
|
|
362
409
|
const candidate = path.join(dir, name);
|
|
363
410
|
if (existsSync(candidate))
|
|
@@ -366,6 +413,25 @@ export function findLocalToolConfig(startDir, names) {
|
|
|
366
413
|
}
|
|
367
414
|
return undefined;
|
|
368
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* Accept only a real Git repository marker: a directory with HEAD, or a
|
|
418
|
+
* worktree/submodule marker file whose first line starts with `gitdir:`.
|
|
419
|
+
*/
|
|
420
|
+
export function isRealGitMarker(markerPath) {
|
|
421
|
+
try {
|
|
422
|
+
const marker = statSync(markerPath);
|
|
423
|
+
if (marker.isDirectory())
|
|
424
|
+
return existsSync(path.join(markerPath, "HEAD"));
|
|
425
|
+
if (!marker.isFile())
|
|
426
|
+
return false;
|
|
427
|
+
return readFileSync(markerPath, "utf8")
|
|
428
|
+
.split(/\r?\n/, 1)[0]
|
|
429
|
+
.startsWith("gitdir:");
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
369
435
|
/**
|
|
370
436
|
* Walk up from `startDir` looking for a directory containing any of
|
|
371
437
|
* `markers`, the same containment-aware climb `knip-client.ts` and
|
|
@@ -391,11 +457,13 @@ export function findLocalToolConfig(startDir, names) {
|
|
|
391
457
|
export function findNearestMarkerRoot(startDir, markers, options = {}) {
|
|
392
458
|
const boundaries = options.boundaries ?? [];
|
|
393
459
|
const homeDir = path.resolve(options.homeDir ?? os.homedir());
|
|
460
|
+
const markerPredicate = options.markerPredicate ?? (() => true);
|
|
394
461
|
let current = path.resolve(startDir);
|
|
395
462
|
for (let depth = 0; depth < 64; depth++) {
|
|
396
463
|
if (isAtOrAboveHomeDir(current, homeDir))
|
|
397
464
|
return null;
|
|
398
|
-
if (markers.some((m) => existsSync(path.join(current, m))
|
|
465
|
+
if (markers.some((m) => existsSync(path.join(current, m)) &&
|
|
466
|
+
markerPredicate(path.join(current, m))))
|
|
399
467
|
return current;
|
|
400
468
|
if (boundaries.some((m) => existsSync(path.join(current, m))))
|
|
401
469
|
return null;
|
|
@@ -415,17 +483,74 @@ export function findNearestMarkerRoot(startDir, markers, options = {}) {
|
|
|
415
483
|
* `=== os.homedir()` check (which a marker found *above* `$HOME` slips past).
|
|
416
484
|
* A normal project *under* home (e.g. `~/code/app`) is NOT at-or-above home,
|
|
417
485
|
* so it still resolves fine. Refs #253.
|
|
486
|
+
*
|
|
487
|
+
* ONE expression, deliberately: `path.relative` alone answers "is home inside
|
|
488
|
+
* `dir`, or the same directory as `dir`", and it answers with the PLATFORM's
|
|
489
|
+
* path-equality semantics — case-folding on win32, case-sensitive on POSIX.
|
|
490
|
+
* The `resolvedDir === resolvedHome` shortcut that used to precede it was
|
|
491
|
+
* case-SENSITIVE on every platform, so `c:\Users\jane` (the lowercase-drive
|
|
492
|
+
* form VS Code URIs produce, and the form 46 records in a real `latency.log`
|
|
493
|
+
* carry) missed the equality test AND was then rejected by a `rel !== ""`
|
|
494
|
+
* clause — reporting "not at home" for the home directory itself and letting
|
|
495
|
+
* every ceilinged walker climb straight past HOME (#2544 review F1).
|
|
496
|
+
*
|
|
497
|
+
* rel === "" ⇢ `dir` IS home
|
|
498
|
+
* rel relative, no leading `..` ⇢ home is INSIDE `dir` (an ancestor)
|
|
499
|
+
* rel starts with `..` ⇢ home is elsewhere — sibling, or the
|
|
500
|
+
* prefix trap `C:\Users\jane2` → home
|
|
501
|
+
* `C:\Users\jane` gives `..\jane`
|
|
502
|
+
* rel absolute ⇢ different Windows drive
|
|
503
|
+
*
|
|
504
|
+
* Same shape as `isUnderDir` above; keep the two in step.
|
|
505
|
+
*
|
|
506
|
+
* `pathImpl` exists so the ubuntu Unit tests lane — the authoritative one —
|
|
507
|
+
* can exercise the WIN32 semantics this helper's whole bug was about. Every
|
|
508
|
+
* assertion that matters here (drive-letter folding, cross-drive `rel`) is
|
|
509
|
+
* win32-only, so with the ambient `path` hardcoded the ceiling was enforced
|
|
510
|
+
* only on a maintainer's dev box and CI's diff was structurally zero (#2544
|
|
511
|
+
* review F2). Production never passes it; `path.win32`/`path.posix` are pure,
|
|
512
|
+
* host-independent implementations, so `tests/clients/path-utils.test.ts` runs
|
|
513
|
+
* the same table under both on every lane. Lane-level fix tracked as #2536.
|
|
418
514
|
*/
|
|
419
|
-
export function isAtOrAboveHomeDir(dir, homeDir = os.homedir()) {
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
515
|
+
export function isAtOrAboveHomeDir(dir, homeDir = os.homedir(), pathImpl = path) {
|
|
516
|
+
const rel = pathImpl.relative(pathImpl.resolve(dir), pathImpl.resolve(homeDir));
|
|
517
|
+
return !rel.startsWith("..") && !pathImpl.isAbsolute(rel);
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Rewrite a `$HOME`-anchored path to its `~` form for a DIAGNOSTIC surface.
|
|
521
|
+
*
|
|
522
|
+
* `~/.pi-lens/config.json` says everything an operator needs about which file
|
|
523
|
+
* won, and `C:/Users/jane.doe/.pi-lens/config.json` says that plus the
|
|
524
|
+
* account name. The second is the shape a global config path always has, so any
|
|
525
|
+
* projection that names one leaks an identifier by default rather than by
|
|
526
|
+
* accident (#2440 review finding F5).
|
|
527
|
+
*
|
|
528
|
+
* Deliberately NOT built on `normalizeFilePath`/`isUnderDir`: those resolve
|
|
529
|
+
* through `realpathSync`, and a redaction helper on a diagnostic path must be
|
|
530
|
+
* pure, total, and unable to throw for a file that no longer exists. This is a
|
|
531
|
+
* string rewrite and nothing else.
|
|
532
|
+
*
|
|
533
|
+
* A path that is not under home is returned UNCHANGED — separators included.
|
|
534
|
+
* Normalizing unrelated paths on the way past would make the helper's blast
|
|
535
|
+
* radius every path any projection ever carries, for no redaction benefit.
|
|
536
|
+
*/
|
|
537
|
+
export function homeRelativePath(filePath, homeDir = os.homedir()) {
|
|
538
|
+
if (filePath.length === 0)
|
|
539
|
+
return filePath;
|
|
540
|
+
const candidate = toPosix(filePath);
|
|
541
|
+
const home = toPosix(homeDir).replace(/\/+$/, "");
|
|
542
|
+
if (home.length === 0)
|
|
543
|
+
return filePath;
|
|
544
|
+
// Windows paths are case-insensitive, so the COMPARISON folds case there
|
|
545
|
+
// while the returned tail keeps the caller's own casing.
|
|
546
|
+
const fold = (text) => process.platform === "win32" ? text.toLowerCase() : text;
|
|
547
|
+
const foldedHome = fold(home);
|
|
548
|
+
const foldedCandidate = fold(candidate);
|
|
549
|
+
if (foldedCandidate === foldedHome)
|
|
550
|
+
return "~";
|
|
551
|
+
if (!foldedCandidate.startsWith(`${foldedHome}/`))
|
|
552
|
+
return filePath;
|
|
553
|
+
return `~${candidate.slice(home.length)}`;
|
|
429
554
|
}
|
|
430
555
|
export function isUnderDir(child, parent) {
|
|
431
556
|
const normChild = normalizeFilePath(child);
|
|
@@ -484,6 +609,317 @@ export function direntsHaveMarkerGlobMatch(entries, pattern) {
|
|
|
484
609
|
return entries.some((entry) => (entry.isFile() || entry.isSymbolicLink()) &&
|
|
485
610
|
nameMatchesMarkerGlob(entry.name, pattern));
|
|
486
611
|
}
|
|
612
|
+
/**
|
|
613
|
+
* Cargo `[workspace] members`/`exclude` entries.
|
|
614
|
+
*
|
|
615
|
+
* KNOWN LIMITATION (#1671 F6, documented rather than implemented, preserved
|
|
616
|
+
* byte-for-byte by #2591's fold): a recursive `**` component is NOT supported
|
|
617
|
+
* and a pattern containing one never matches — cargo workspaces that rely on
|
|
618
|
+
* `**` to pull in an arbitrarily-nested crate tree under-hoist (the crate stays
|
|
619
|
+
* independently rooted instead of joining the workspace). Folding cargo onto
|
|
620
|
+
* uv's `crosses-components` globstar would silently change Rust-LSP root
|
|
621
|
+
* selection, so the divergence is kept as a dialect value, not resolved.
|
|
622
|
+
*
|
|
623
|
+
* `characterClasses: false` is likewise a preserved divergence, not a
|
|
624
|
+
* considered choice: cargo's pre-fold segment compiler escaped `[` and `]`
|
|
625
|
+
* into literals, so `crates/[ab]` names a directory literally called `[ab]`.
|
|
626
|
+
* Real cargo (the `glob` crate) would read it as a class; changing that here
|
|
627
|
+
* would be the same unreviewed Rust-hoisting change.
|
|
628
|
+
*/
|
|
629
|
+
export const CARGO_WORKSPACE_MEMBER_DIALECT = {
|
|
630
|
+
name: "cargo",
|
|
631
|
+
globstar: "pattern-never-matches",
|
|
632
|
+
wildcardCrossesSeparator: false,
|
|
633
|
+
characterClasses: false,
|
|
634
|
+
normalizePattern: (pattern) => pattern.replace(/\/+$/, ""),
|
|
635
|
+
};
|
|
636
|
+
/**
|
|
637
|
+
* uv `[tool.uv.workspace] members`, pinned to
|
|
638
|
+
* `astral-sh/uv@3c979abda4530fe9bf3d92e9bcf5c5575e3b3126`,
|
|
639
|
+
* `crates/uv-workspace/src/workspace.rs` `is_included_in_workspace`: the glob is
|
|
640
|
+
* `normalize_path`d first (so a leading `./` and any interior `.` component are
|
|
641
|
+
* not part of the pattern) and matched with
|
|
642
|
+
* `MatchOptions { require_literal_separator: true, ..MatchOptions::new() }`.
|
|
643
|
+
*/
|
|
644
|
+
export const UV_WORKSPACE_MEMBERS_DIALECT = {
|
|
645
|
+
name: "uv-members",
|
|
646
|
+
globstar: "crosses-components",
|
|
647
|
+
wildcardCrossesSeparator: false,
|
|
648
|
+
characterClasses: true,
|
|
649
|
+
normalizePattern: (pattern) => path.posix.normalize(toPosix(pattern)),
|
|
650
|
+
};
|
|
651
|
+
/**
|
|
652
|
+
* uv `[tool.uv.workspace] exclude`, same upstream file and SHA
|
|
653
|
+
* (`WorkspaceExclusions::matches`): an exclusion is matched with
|
|
654
|
+
* `Pattern::matches_path`, i.e. `MatchOptions::new()` defaults, where
|
|
655
|
+
* `require_literal_separator` is FALSE — so a `*` in an exclusion DOES cross
|
|
656
|
+
* `/` (`exclude = ['packages/a*c']` excludes `packages/a/b/c`). Two different
|
|
657
|
+
* option sets inside one tool, which is why the dialect is an object and the
|
|
658
|
+
* two uv constants are not one.
|
|
659
|
+
*
|
|
660
|
+
* Before #2591 this was a documented limitation: minimatch cannot express a
|
|
661
|
+
* separator-crossing `*`, so pi-lens under-excluded. The dialect object can, so
|
|
662
|
+
* it is now implemented rather than documented.
|
|
663
|
+
*/
|
|
664
|
+
export const UV_WORKSPACE_EXCLUDE_DIALECT = {
|
|
665
|
+
name: "uv-exclude",
|
|
666
|
+
globstar: "crosses-components",
|
|
667
|
+
wildcardCrossesSeparator: true,
|
|
668
|
+
characterClasses: true,
|
|
669
|
+
normalizePattern: (pattern) => path.posix.normalize(toPosix(pattern)),
|
|
670
|
+
};
|
|
671
|
+
/**
|
|
672
|
+
* Index of the `]` closing the character class opened at `open`, or `-1` when
|
|
673
|
+
* the run is unterminated (in which case the `[` is a literal). A leading `!`
|
|
674
|
+
* or `^` negates, and a `]` in first position is a literal class member — the
|
|
675
|
+
* shape both minimatch and rust `glob` accept.
|
|
676
|
+
*/
|
|
677
|
+
function findCharacterClassEnd(segment, open) {
|
|
678
|
+
let i = open + 1;
|
|
679
|
+
if (segment[i] === "!" || segment[i] === "^")
|
|
680
|
+
i += 1;
|
|
681
|
+
if (segment[i] === "]")
|
|
682
|
+
i += 1;
|
|
683
|
+
for (; i < segment.length; i += 1)
|
|
684
|
+
if (segment[i] === "]")
|
|
685
|
+
return i;
|
|
686
|
+
return -1;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* May a wildcard with this separator policy consume `ch`?
|
|
690
|
+
*
|
|
691
|
+
* A separator-confined wildcard (`[^/]` in the regex this replaced) takes
|
|
692
|
+
* anything but `/`. A separator-CROSSING one — uv `exclude`'s `*`/`?`, and
|
|
693
|
+
* every `**` in either uv dialect — spelled `.` in that regex, which is every
|
|
694
|
+
* code unit EXCEPT the four line terminators. That exclusion is preserved
|
|
695
|
+
* deliberately rather than "fixed": minimatch's globstar is `.`-based too, so
|
|
696
|
+
* a `\n` inside a directory name has never matched across a `**` in either
|
|
697
|
+
* implementation, and the differential oracle would flag a change here as a
|
|
698
|
+
* divergence rather than an improvement (#2603).
|
|
699
|
+
*/
|
|
700
|
+
function stepAcceptsChar(crossesSeparator, ch) {
|
|
701
|
+
return crossesSeparator
|
|
702
|
+
? ch !== "\n" && ch !== "\r" && ch !== "\u2028" && ch !== "\u2029"
|
|
703
|
+
: ch !== "/";
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Compile a normalized workspace-member pattern into a step list, or
|
|
707
|
+
* `undefined` when it cannot be compiled at all.
|
|
708
|
+
*
|
|
709
|
+
* A `**` component consumes zero or more path components — except as the LAST
|
|
710
|
+
* component, where it requires at least one (`a/**` matches `a/b`, not `a`),
|
|
711
|
+
* reproducing both minimatch's and rust `glob`'s answer. It is emitted as
|
|
712
|
+
* `split → one → star → literal "/"`, i.e. "nothing, or one-or-more characters
|
|
713
|
+
* followed by the `/` that ends them", after the separator that precedes it.
|
|
714
|
+
* That is the same language as the `(?:/.+)?/` group the previous compiler
|
|
715
|
+
* emitted — `X(?:/.+)?/Y` and `X/(?:.+/)?Y` both denote `X/Y` ∪ `X/.+/Y` — in a
|
|
716
|
+
* form with no nested quantifier.
|
|
717
|
+
*/
|
|
718
|
+
function compileWorkspaceMemberPattern(pattern, dialect) {
|
|
719
|
+
const isGlobstar = (component) => component === "**" && dialect.globstar === "crosses-components";
|
|
720
|
+
const components = pattern.split("/");
|
|
721
|
+
const steps = [];
|
|
722
|
+
let needSeparator = false;
|
|
723
|
+
for (let c = 0; c < components.length; c += 1) {
|
|
724
|
+
if (needSeparator)
|
|
725
|
+
steps.push({ kind: "literal", char: "/" });
|
|
726
|
+
needSeparator = false;
|
|
727
|
+
const component = components[c];
|
|
728
|
+
if (isGlobstar(component)) {
|
|
729
|
+
if (c === components.length - 1) {
|
|
730
|
+
// `.+` — a trailing `**` requires at least one character.
|
|
731
|
+
steps.push({ kind: "one", crossesSeparator: true });
|
|
732
|
+
steps.push({ kind: "star", crossesSeparator: true });
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
// `(?:.+/)?` — zero or more whole components. The group already ends
|
|
736
|
+
// at a `/`, so the next component must NOT emit one.
|
|
737
|
+
const split = { kind: "split", alternative: -1 };
|
|
738
|
+
steps.push(split);
|
|
739
|
+
steps.push({ kind: "one", crossesSeparator: true });
|
|
740
|
+
steps.push({ kind: "star", crossesSeparator: true });
|
|
741
|
+
steps.push({ kind: "literal", char: "/" });
|
|
742
|
+
split.alternative = steps.length;
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
for (let i = 0; i < component.length; i += 1) {
|
|
746
|
+
const ch = component[i];
|
|
747
|
+
if (ch === "*") {
|
|
748
|
+
steps.push({
|
|
749
|
+
kind: "star",
|
|
750
|
+
crossesSeparator: dialect.wildcardCrossesSeparator,
|
|
751
|
+
});
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
if (ch === "?") {
|
|
755
|
+
steps.push({
|
|
756
|
+
kind: "one",
|
|
757
|
+
crossesSeparator: dialect.wildcardCrossesSeparator,
|
|
758
|
+
});
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (ch === "[" && dialect.characterClasses) {
|
|
762
|
+
const close = findCharacterClassEnd(component, i);
|
|
763
|
+
if (close !== -1) {
|
|
764
|
+
// `\` and a first-position `]` are literal class MEMBERS in glob;
|
|
765
|
+
// left alone they would be a regex escape and an empty-class
|
|
766
|
+
// terminator (`[]ab]` is `[]` + `ab]` in JS), so both are escaped.
|
|
767
|
+
const body = component.slice(i + 1, close).replace(/[\\\]]/g, "\\$&");
|
|
768
|
+
const source = body.startsWith("!")
|
|
769
|
+
? `[^${body.slice(1)}]`
|
|
770
|
+
: `[${body}]`;
|
|
771
|
+
let match;
|
|
772
|
+
try {
|
|
773
|
+
match = new RegExp(`^${source}$`);
|
|
774
|
+
}
|
|
775
|
+
catch {
|
|
776
|
+
// A glob character class is not a JS character class: `[z-a]`
|
|
777
|
+
// is a legal glob (matching nothing, since the range is empty)
|
|
778
|
+
// and an illegal RegExp ("Range out of order"). Fail CLOSED —
|
|
779
|
+
// an uncompilable pattern declares no member and excludes
|
|
780
|
+
// nothing — which is also the answer the deleted minimatch call
|
|
781
|
+
// gave (#2591 review round 2, F2).
|
|
782
|
+
return undefined;
|
|
783
|
+
}
|
|
784
|
+
steps.push({ kind: "class", match });
|
|
785
|
+
i = close;
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
steps.push({ kind: "literal", char: ch });
|
|
790
|
+
}
|
|
791
|
+
needSeparator = true;
|
|
792
|
+
}
|
|
793
|
+
return steps;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Does the whole of `subject` match the whole of `steps`?
|
|
797
|
+
*
|
|
798
|
+
* A memoized (step index, path index) table, filled once, bottom-up:
|
|
799
|
+
* `table[s][p]` is "steps `s…` match `subject[p…]`". Every cell reads only
|
|
800
|
+
* cells with a larger step index or a larger path index, so one backward
|
|
801
|
+
* double loop fills the table with no recursion and no re-entry — the match is
|
|
802
|
+
* O(steps x characters) in time and space, with no path through it that can
|
|
803
|
+
* take exponential time (#2603).
|
|
804
|
+
*
|
|
805
|
+
* The compiled whole-path regex this replaced was correct but backtracking:
|
|
806
|
+
* every `**` emitted its own nullable `.+`, and N of them explored 2^N splits
|
|
807
|
+
* of a non-matching subject. #2591 collapsed CONSECUTIVE `**`s, which is a
|
|
808
|
+
* normalization that cannot fire across a separating component, so
|
|
809
|
+
* `("**\/*" x12)/zzz` against a 40-component path still took 124900 ms (#2603);
|
|
810
|
+
* the same shapes are microseconds here. There is nothing left to collapse for
|
|
811
|
+
* speed, so no collapse is done: `a/**\/**\/b` compiles to two adjacent
|
|
812
|
+
* `(?:.+/)?` groups, which denote the same language as one and cost the same
|
|
813
|
+
* table.
|
|
814
|
+
*/
|
|
815
|
+
function matchesWorkspaceMemberSteps(steps, subject) {
|
|
816
|
+
const stepCount = steps.length;
|
|
817
|
+
const width = subject.length + 1;
|
|
818
|
+
// One byte per (step, position) cell; `1` means "the rest matches from here".
|
|
819
|
+
const table = new Uint8Array((stepCount + 1) * width);
|
|
820
|
+
for (let p = subject.length; p >= 0; p -= 1) {
|
|
821
|
+
const atEnd = p === subject.length;
|
|
822
|
+
// The empty step list matches only the empty remainder.
|
|
823
|
+
table[stepCount * width + p] = atEnd ? 1 : 0;
|
|
824
|
+
for (let s = stepCount - 1; s >= 0; s -= 1) {
|
|
825
|
+
const step = steps[s];
|
|
826
|
+
const next = (s + 1) * width;
|
|
827
|
+
let matched = 0;
|
|
828
|
+
switch (step.kind) {
|
|
829
|
+
case "literal":
|
|
830
|
+
matched =
|
|
831
|
+
!atEnd && subject[p] === step.char ? table[next + p + 1] : 0;
|
|
832
|
+
break;
|
|
833
|
+
case "one":
|
|
834
|
+
matched =
|
|
835
|
+
!atEnd && stepAcceptsChar(step.crossesSeparator, subject[p])
|
|
836
|
+
? table[next + p + 1]
|
|
837
|
+
: 0;
|
|
838
|
+
break;
|
|
839
|
+
case "class":
|
|
840
|
+
matched =
|
|
841
|
+
!atEnd && step.match.test(subject[p]) ? table[next + p + 1] : 0;
|
|
842
|
+
break;
|
|
843
|
+
case "star":
|
|
844
|
+
// Consume nothing, or one more character and stay on this step.
|
|
845
|
+
matched =
|
|
846
|
+
table[next + p] === 1 ||
|
|
847
|
+
(!atEnd &&
|
|
848
|
+
stepAcceptsChar(step.crossesSeparator, subject[p]) &&
|
|
849
|
+
table[s * width + p + 1] === 1)
|
|
850
|
+
? 1
|
|
851
|
+
: 0;
|
|
852
|
+
break;
|
|
853
|
+
case "split":
|
|
854
|
+
matched =
|
|
855
|
+
table[step.alternative * width + p] === 1 || table[next + p] === 1
|
|
856
|
+
? 1
|
|
857
|
+
: 0;
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
table[s * width + p] = matched;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return table[0] === 1;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Does `relativePath` — a `/`-separated path relative to the workspace root —
|
|
867
|
+
* match one declared workspace-member (or workspace-exclude) `pattern` under
|
|
868
|
+
* `dialect`?
|
|
869
|
+
*
|
|
870
|
+
* This is the ONE workspace-member matcher (#2591). `clients/lsp/server.ts`'s
|
|
871
|
+
* `cargoWorkspaceDeclaresMember` and `clients/python-environment.ts`'s
|
|
872
|
+
* `isUvWorkspaceMember` are thin callers of it; neither keeps a private segment
|
|
873
|
+
* compiler or minimatch options block any more.
|
|
874
|
+
*
|
|
875
|
+
* `clients/review-graph/workspace-modules.ts`'s `expandWorkspacePattern` is
|
|
876
|
+
* deliberately NOT a caller: npm/pnpm `workspaces` entries are EXPANDED against
|
|
877
|
+
* the filesystem (one `readdir` of the directory preceding the first `*`,
|
|
878
|
+
* yielding the directories that exist and hold a manifest) rather than tested
|
|
879
|
+
* against a candidate path. It answers "which directories does this pattern
|
|
880
|
+
* name", not "does this pattern name this directory"; folding it in would mean
|
|
881
|
+
* giving this pure function a filesystem.
|
|
882
|
+
*
|
|
883
|
+
* The supported syntax is the intersection of the two upstream dialects: `*`,
|
|
884
|
+
* `?`, `**`, `[abc]`/`[!abc]` (dialect-gated), and literals. minimatch-only
|
|
885
|
+
* extensions the pre-fold uv path inherited by accident — brace expansion,
|
|
886
|
+
* extglobs, leading-`!` negation, leading-`#` comments — are NOT honored, and
|
|
887
|
+
* uv's own `glob` crate does not honor them either (same pinned SHA), so
|
|
888
|
+
* dropping them moves uv toward upstream rather than away from it.
|
|
889
|
+
*
|
|
890
|
+
* Matching is NON-BACKTRACKING (#2603): the pattern compiles to a list of
|
|
891
|
+
* bounded steps and {@link matchesWorkspaceMemberSteps} decides it with one
|
|
892
|
+
* memoized (step, position) table, O(steps x characters), no matter how many
|
|
893
|
+
* `**`s the pattern carries. The anchored whole-path regex this replaced was
|
|
894
|
+
* correct but explored 2^N splits of a non-matching path for N `**`
|
|
895
|
+
* components — 124900 ms for `("**\/*" x12)/zzz` against a 40-component path,
|
|
896
|
+
* on a call `detectPythonEnvironment` awaits with no timeout, i.e. a wedged
|
|
897
|
+
* turn rather than a slow answer. The wall-clock half of that fix lives in
|
|
898
|
+
* `tests/clients/workspace-glob-nonbacktracking-budget.test.ts`; the answers
|
|
899
|
+
* are unchanged, pinned by the dialect table and the minimatch differential in
|
|
900
|
+
* `tests/clients/path-utils.test.ts`.
|
|
901
|
+
*
|
|
902
|
+
* A pattern that cannot be compiled at all answers `false` for every path —
|
|
903
|
+
* it declares no member and excludes nothing (#2591 review round 2, F2). The
|
|
904
|
+
* only such patterns today carry an empty character-class range (`[z-a]`:
|
|
905
|
+
* legal glob, illegal JS RegExp). Reachability note, recorded rather than
|
|
906
|
+
* assumed away: no such pattern can reach here through a manifest right now,
|
|
907
|
+
* because `parseTomlStringArray` (`clients/cargo-manifest.ts`) captures an
|
|
908
|
+
* array body non-greedily up to the FIRST `]`, so any entry containing a `]`
|
|
909
|
+
* loses its closing quote and is dropped before it becomes a pattern. That is
|
|
910
|
+
* a property of the TOML reader, not of this matcher, and it is not this
|
|
911
|
+
* function's to rely on — the character-class axis stays because upstream
|
|
912
|
+
* cargo and uv both support classes, and the reader's gap may be closed later.
|
|
913
|
+
*/
|
|
914
|
+
export function matchesWorkspaceMemberPattern(pattern, relativePath, dialect) {
|
|
915
|
+
const normalized = dialect.normalizePattern(pattern);
|
|
916
|
+
if (dialect.globstar === "pattern-never-matches" &&
|
|
917
|
+
normalized.includes("**")) {
|
|
918
|
+
return false;
|
|
919
|
+
}
|
|
920
|
+
const steps = compileWorkspaceMemberPattern(normalized, dialect);
|
|
921
|
+
return (steps !== undefined && matchesWorkspaceMemberSteps(steps, relativePath));
|
|
922
|
+
}
|
|
487
923
|
/**
|
|
488
924
|
* Narrow no-break space, U+202F. macOS writes it before AM/PM in screenshot
|
|
489
925
|
* file names; users type an ordinary space.
|
|
@@ -549,7 +985,7 @@ export function normalizeHostToolPath(input, options = {}) {
|
|
|
549
985
|
(process.platform === "win32" && normalized.startsWith("~\\"))) {
|
|
550
986
|
return path.join(os.homedir(), normalized.slice(2));
|
|
551
987
|
}
|
|
552
|
-
if (
|
|
988
|
+
if (normalized.startsWith("file://")) {
|
|
553
989
|
try {
|
|
554
990
|
return fileURLToPath(normalized);
|
|
555
991
|
}
|
|
@@ -2,8 +2,8 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as readline from "node:readline";
|
|
3
3
|
import { flushLatencyLog, getLatencyLogPath, } from "./latency-logger.js";
|
|
4
4
|
import { getMaxLogSizeMB } from "./log-cleanup.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const DEFAULT_PERF_TOP_N = 5;
|
|
6
|
+
const MAX_PERF_TOP_N = 50;
|
|
7
7
|
export const MAX_PERF_PHASE_SAMPLES = 20_000;
|
|
8
8
|
const PARSE_YIELD_EVERY = 500;
|
|
9
9
|
// The window follows the same threshold that rotates the log out from under it.
|
|
@@ -40,7 +40,14 @@ export function createDebounceScheduler(args) {
|
|
|
40
40
|
write(key, payload);
|
|
41
41
|
}
|
|
42
42
|
function flushAll() {
|
|
43
|
-
|
|
43
|
+
// Iterates `pending.keys()` live (a `Map` iterator reflects mutation
|
|
44
|
+
// during iteration): `flush` deletes the current key before calling
|
|
45
|
+
// `write`, which is safe, but the injected `write` callback must NOT
|
|
46
|
+
// synchronously call `schedule` again for a key not yet visited — that
|
|
47
|
+
// would insert into `pending` mid-iteration and the live iterator would
|
|
48
|
+
// pick it up, flushing a payload the caller expected to survive as
|
|
49
|
+
// "still pending" after this call returns.
|
|
50
|
+
for (const key of pending.keys())
|
|
44
51
|
flush(key);
|
|
45
52
|
}
|
|
46
53
|
function schedule(key, payload) {
|