@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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared re-check cadence for a cached "nothing here" verdict — the
|
|
3
|
+
* bound both `file-utils.ts`'s nested `.gitignore`/`.pi-lens.json` matcher
|
|
4
|
+
* (#2159/#2071) and `project-lens-config.ts`'s no-config discovery cache
|
|
5
|
+
* (#2483 round 2) use so a negative result is neither re-statted on every
|
|
6
|
+
* call nor cached for the life of the process.
|
|
7
|
+
*
|
|
8
|
+
* A declared leaf module, the same shape as `ledger-bounds.ts` /
|
|
9
|
+
* `spawn-output-cap.ts`: it imports nothing from `clients/`, because
|
|
10
|
+
* `file-utils.ts` already imports `project-lens-config.ts`, and the
|
|
11
|
+
* `clients/` acyclic-imports rule (`no-client-cycles`,
|
|
12
|
+
* `.dependency-cruiser.cjs`) would reject either of those two files
|
|
13
|
+
* importing a constant that lived inside the other. A shared value neither
|
|
14
|
+
* owns is the only way both stay on the same cadence without one importing
|
|
15
|
+
* the other.
|
|
16
|
+
*/
|
|
17
|
+
export const FRESHNESS_CADENCE_MS = 2_000;
|
|
@@ -167,18 +167,95 @@ function hasGeneratedArtifactContent(content) {
|
|
|
167
167
|
const header = content.slice(0, DEFAULT_HEADER_BYTES);
|
|
168
168
|
return GENERATED_HEADER_PATTERNS.some((pattern) => pattern.test(header));
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Content-shape classifier for machine-emitted text (refs #2346).
|
|
172
|
+
*
|
|
173
|
+
* A saved/scraped page, a minified bundle, or an embedded data blob is one
|
|
174
|
+
* giant line or a handful, so mean non-empty line length on already-loaded
|
|
175
|
+
* content is a language-agnostic generated signature. Extensions covered by
|
|
176
|
+
* name patterns can never cover it (`.html` has no `.min.`-style convention),
|
|
177
|
+
* which is the exact gap #2346 hit: a 269 KB scraped page on 38 lines (mean
|
|
178
|
+
* ~7084/line) drew the full auxiliary scanner stack.
|
|
179
|
+
*
|
|
180
|
+
* The threshold is derived from measurement ON THE SHIPPED STATISTIC (the
|
|
181
|
+
* 4096-byte header/prefix mean, not full-content means — the two differ by
|
|
182
|
+
* 3-7x on long-paragraph prose). Measured 2026-08-28 across all 3,331 text
|
|
183
|
+
* files in this repo: the maximum hand-authored prefix mean is 453.2
|
|
184
|
+
* (`docs/analysisall.md`, unwrapped prose paragraphs); the widest
|
|
185
|
+
* hand-authored one-line shape observed anywhere probed is a ~2048-char
|
|
186
|
+
* barrel re-export. The threshold of 2500 sits ~5.5x above the repo's worst
|
|
187
|
+
* prose file and above every observed hand-authored shape, while the #2346
|
|
188
|
+
* evidence file (269 KB / 38 lines) remains far above it. Direction of
|
|
189
|
+
* error is deliberate per #1107: a borderline machine-emitted file that
|
|
190
|
+
* slips through (false KEEP) costs noise once; a hand-authored file
|
|
191
|
+
* silently classified generated (false DROP) vanishes from scans with no
|
|
192
|
+
* signal. Both constants are exported so the tuning claim is checkable and
|
|
193
|
+
* the regression tests pin the margin probes on both sides.
|
|
194
|
+
*
|
|
195
|
+
* Prefix-path quantization: on the 4096-byte header/prefix paths the
|
|
196
|
+
* achievable means are quantized (~4096 for a one-line prefix, ~2048 for
|
|
197
|
+
* two lines), so any threshold in (2048, 4096] behaves as "is the first
|
|
198
|
+
* line longer than 4096 bytes". A machine-emitted file with 2500-4000-char
|
|
199
|
+
* lines is missed on the prefix path even though its full content would
|
|
200
|
+
* classify — the deliberate false-KEEP direction, not a continuous 5.5x
|
|
201
|
+
* margin there. The full-content path (dispatch) has no such quantization.
|
|
202
|
+
*
|
|
203
|
+
* Degenerate cases are guarded: content below the minimum byte length never
|
|
204
|
+
* classifies generated on line shape alone (a 500-byte single-line config
|
|
205
|
+
* file is not machine-emitted evidence), and an empty or whitespace-only
|
|
206
|
+
* file yields a zero mean and stays source.
|
|
207
|
+
*/
|
|
208
|
+
const MACHINE_EMITTED_LINE_SHAPE_MIN_CONTENT = 2048;
|
|
209
|
+
export const MACHINE_EMITTED_LINE_SHAPE_MEAN_THRESHOLD = 2500;
|
|
210
|
+
export function classifyMachineEmittedLineShape(content) {
|
|
211
|
+
const contentLength = content.length;
|
|
212
|
+
if (contentLength < MACHINE_EMITTED_LINE_SHAPE_MIN_CONTENT) {
|
|
213
|
+
return { generated: false, meanLineLength: 0 };
|
|
214
|
+
}
|
|
215
|
+
// Single O(contentLength) pass. Deliberately no `split(/\r?\n/)`: a
|
|
216
|
+
// minified blob's single line can be megabytes, and splitting allocates a
|
|
217
|
+
// copy of the whole content. `\r` contributes nothing to line length so a
|
|
218
|
+
// CRLF line is measured by its display width.
|
|
219
|
+
let nonEmptyLineTotal = 0;
|
|
220
|
+
let nonEmptyLineCount = 0;
|
|
221
|
+
let currentLineLength = 0;
|
|
222
|
+
for (let i = 0; i < contentLength; i++) {
|
|
223
|
+
const code = content.charCodeAt(i);
|
|
224
|
+
if (code === 10 /* \n */) {
|
|
225
|
+
if (currentLineLength > 0) {
|
|
226
|
+
nonEmptyLineTotal += currentLineLength;
|
|
227
|
+
nonEmptyLineCount += 1;
|
|
228
|
+
}
|
|
229
|
+
currentLineLength = 0;
|
|
230
|
+
}
|
|
231
|
+
else if (code !== 13 /* \r */) {
|
|
232
|
+
currentLineLength += 1;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (currentLineLength > 0) {
|
|
236
|
+
nonEmptyLineTotal += currentLineLength;
|
|
237
|
+
nonEmptyLineCount += 1;
|
|
238
|
+
}
|
|
239
|
+
if (nonEmptyLineCount === 0)
|
|
240
|
+
return { generated: false, meanLineLength: 0 };
|
|
241
|
+
const meanLineLength = nonEmptyLineTotal / nonEmptyLineCount;
|
|
242
|
+
return {
|
|
243
|
+
generated: meanLineLength > MACHINE_EMITTED_LINE_SHAPE_MEAN_THRESHOLD,
|
|
244
|
+
meanLineLength,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// Memoize the header analysis (banner + line shape) per (path, mtimeMs, size,
|
|
248
|
+
// maxBytes). The 4 KB header read (openSync + readSync + closeSync) is ~70% of
|
|
249
|
+
// the per-file cost in `collectSourceFiles`, and the same files are re-scanned
|
|
250
|
+
// by multiple background scanners (todo, project-diagnostics, language-profile)
|
|
174
251
|
// every session/turn. Keying on mtime+size makes the memo self-invalidating:
|
|
175
252
|
// an edited file misses the cache and is re-read. A single stat replaces the
|
|
176
253
|
// open/read/close on a hit. Bounded to avoid unbounded growth on giant repos.
|
|
177
254
|
const HEADER_VERDICT_MEMO_CAP = 50_000;
|
|
178
|
-
const
|
|
179
|
-
/** Test-only: drop the header-
|
|
255
|
+
const headerAnalysisMemo = new BoundedLruCache(HEADER_VERDICT_MEMO_CAP);
|
|
256
|
+
/** Test-only: drop the header-analysis memo so fixtures don't leak across cases. */
|
|
180
257
|
export function _resetGeneratedArtifactCaches() {
|
|
181
|
-
|
|
258
|
+
headerAnalysisMemo.clear();
|
|
182
259
|
}
|
|
183
260
|
function readFileHeader(filePath, maxBytes = DEFAULT_HEADER_BYTES) {
|
|
184
261
|
let fd;
|
|
@@ -202,27 +279,29 @@ function readFileHeader(filePath, maxBytes = DEFAULT_HEADER_BYTES) {
|
|
|
202
279
|
}
|
|
203
280
|
}
|
|
204
281
|
}
|
|
205
|
-
|
|
206
|
-
* Memoized form of "does this file's header contain a generated-code banner?".
|
|
207
|
-
* Returns `false` when the file cannot be stat'd/read (same fallback as the
|
|
208
|
-
* inline read path). Keyed on path + mtime + size so edits invalidate it.
|
|
209
|
-
*/
|
|
210
|
-
function fileHeaderLooksGenerated(filePath, maxBytes) {
|
|
282
|
+
function analyzeFileHeader(filePath, maxBytes) {
|
|
211
283
|
let key;
|
|
212
284
|
try {
|
|
213
285
|
const st = fs.statSync(filePath);
|
|
214
286
|
key = `${st.mtimeMs}:${st.size}:${maxBytes}:${filePath}`;
|
|
215
287
|
}
|
|
216
288
|
catch {
|
|
217
|
-
return
|
|
289
|
+
return undefined;
|
|
218
290
|
}
|
|
219
|
-
const cached =
|
|
291
|
+
const cached = headerAnalysisMemo.get(key);
|
|
220
292
|
if (cached !== undefined)
|
|
221
293
|
return cached;
|
|
222
294
|
const header = readFileHeader(filePath, maxBytes);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
295
|
+
// A header that cannot be read classifies as clean (no banner, no shape
|
|
296
|
+
// signal) and is memoized as such, mirroring the pre-#2346 fallback.
|
|
297
|
+
const analysis = header === undefined
|
|
298
|
+
? { banner: false, shape: { generated: false, meanLineLength: 0 } }
|
|
299
|
+
: {
|
|
300
|
+
banner: hasGeneratedArtifactContent(header),
|
|
301
|
+
shape: classifyMachineEmittedLineShape(header),
|
|
302
|
+
};
|
|
303
|
+
headerAnalysisMemo.set(key, analysis);
|
|
304
|
+
return analysis;
|
|
226
305
|
}
|
|
227
306
|
/**
|
|
228
307
|
* The full verdict (+ evidence tier) behind {@link isGeneratedOrArtifact}'s
|
|
@@ -246,8 +325,7 @@ function fileHeaderLooksGenerated(filePath, maxBytes) {
|
|
|
246
325
|
* function and short-circuit on a hit, so by the time this function runs for
|
|
247
326
|
* those callers evidence (a) has already come back negative. Non-walk
|
|
248
327
|
* callers with no upstream sibling probe (`file-role.ts`'s content-based
|
|
249
|
-
* check,
|
|
250
|
-
* evaluate evidence (b) only — a documented, narrower guarantee than the
|
|
328
|
+
* check) evaluate evidence (b) only — a documented, narrower guarantee than the
|
|
251
329
|
* walk path's.
|
|
252
330
|
*
|
|
253
331
|
* Tradeoff (documented per the issue): when NEITHER piece of evidence
|
|
@@ -272,12 +350,28 @@ export function classifyGeneratedOrArtifactDetailed(filePath, options = {}) {
|
|
|
272
350
|
if (hasGeneratedArtifactContent(options.content)) {
|
|
273
351
|
return { verdict: "generated", evidence: "content" };
|
|
274
352
|
}
|
|
353
|
+
const shape = classifyMachineEmittedLineShape(options.content);
|
|
354
|
+
if (shape.generated) {
|
|
355
|
+
return {
|
|
356
|
+
verdict: "generated",
|
|
357
|
+
evidence: "line-shape",
|
|
358
|
+
lineShapeMean: shape.meanLineLength,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
275
361
|
return { verdict: weakNameMatch ? "override" : "clean" };
|
|
276
362
|
}
|
|
277
363
|
if (options.readContentHeader) {
|
|
278
|
-
|
|
364
|
+
const analysis = analyzeFileHeader(filePath, options.maxHeaderBytes ?? DEFAULT_HEADER_BYTES);
|
|
365
|
+
if (analysis?.banner) {
|
|
279
366
|
return { verdict: "generated", evidence: "content" };
|
|
280
367
|
}
|
|
368
|
+
if (analysis?.shape.generated) {
|
|
369
|
+
return {
|
|
370
|
+
verdict: "generated",
|
|
371
|
+
evidence: "line-shape",
|
|
372
|
+
lineShapeMean: analysis.shape.meanLineLength,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
281
375
|
return { verdict: weakNameMatch ? "override" : "clean" };
|
|
282
376
|
}
|
|
283
377
|
// No content/header probe was supplied or enabled: there is no cheap way
|
|
@@ -292,7 +386,7 @@ export function classifyGeneratedOrArtifactDetailed(filePath, options = {}) {
|
|
|
292
386
|
: { verdict: "clean" };
|
|
293
387
|
}
|
|
294
388
|
/** Verdict-only convenience wrapper over {@link classifyGeneratedOrArtifactDetailed}. */
|
|
295
|
-
|
|
389
|
+
function classifyGeneratedOrArtifact(filePath, options = {}) {
|
|
296
390
|
return classifyGeneratedOrArtifactDetailed(filePath, options).verdict;
|
|
297
391
|
}
|
|
298
392
|
export function isGeneratedOrArtifact(filePath, options = {}) {
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
* `GenerationMapOptions.normalizeKey` for the correctness reason the slow
|
|
51
51
|
* path exists at all.
|
|
52
52
|
*/
|
|
53
|
+
import { BoundedFifoMap } from "./bounded-cache.js";
|
|
53
54
|
import { incrementDegradationCount } from "./degradation-ledger.js";
|
|
54
55
|
/**
|
|
55
56
|
* Names of every generation-carrying store created through this module.
|
|
@@ -136,7 +137,7 @@ export function createGenerationMap(name, options = {}) {
|
|
|
136
137
|
// Insertion-ordered: the oldest key is evicted first. Re-stamping a key
|
|
137
138
|
// refreshes its position so a hot cwd is not evicted by a burst of
|
|
138
139
|
// one-shot ones.
|
|
139
|
-
const stamps = new
|
|
140
|
+
const stamps = new BoundedFifoMap(maxKeys);
|
|
140
141
|
// ONE ticket counter for the whole map. See GenerationMap's doc comment:
|
|
141
142
|
// per-key counters starting at 0 make eviction and forget() fail OPEN.
|
|
142
143
|
// 0 is reserved for "this key holds no stamp" and is never issued.
|
|
@@ -149,14 +150,8 @@ export function createGenerationMap(name, options = {}) {
|
|
|
149
150
|
function issue(key) {
|
|
150
151
|
nextTicket += 1;
|
|
151
152
|
stamps.delete(key);
|
|
152
|
-
stamps.set(key, nextTicket);
|
|
153
|
-
|
|
154
|
-
const oldest = stamps.keys().next().value;
|
|
155
|
-
if (oldest === undefined)
|
|
156
|
-
break;
|
|
157
|
-
stamps.delete(oldest);
|
|
158
|
-
invalidations += 1;
|
|
159
|
-
}
|
|
153
|
+
const evicted = stamps.set(key, nextTicket);
|
|
154
|
+
invalidations += evicted.length;
|
|
160
155
|
return nextTicket;
|
|
161
156
|
}
|
|
162
157
|
return {
|
|
@@ -141,6 +141,11 @@ function canonicalizeGuardCommand(command) {
|
|
|
141
141
|
let pendingSpace = false;
|
|
142
142
|
quote = undefined;
|
|
143
143
|
for (const ch of result) {
|
|
144
|
+
if (!quote && ch === "\n") {
|
|
145
|
+
collapsed += ch;
|
|
146
|
+
pendingSpace = false;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
144
149
|
if (!quote && /\s/.test(ch)) {
|
|
145
150
|
pendingSpace = collapsed.length > 0;
|
|
146
151
|
continue;
|
|
@@ -566,7 +571,7 @@ function markCacheUnknown(runtime, reason) {
|
|
|
566
571
|
/** Persist a complete, bounded, content-bound guard record. */
|
|
567
572
|
export function writeGitGuardRecord(cacheManager, runtime, cwd, record) {
|
|
568
573
|
const capped = capAffectedFiles(Array.isArray(record.affectedFiles) ? record.affectedFiles : [], cwd);
|
|
569
|
-
const fileSeqByPath = { ...
|
|
574
|
+
const fileSeqByPath = { ...record.fileSeqByPath };
|
|
570
575
|
for (const file of capped.files) {
|
|
571
576
|
const key = guardPathKey(file, cwd);
|
|
572
577
|
if (fileSeqByPath[key] === undefined) {
|
|
@@ -62,4 +62,43 @@ export class GoClient {
|
|
|
62
62
|
isGoFile(filePath) {
|
|
63
63
|
return path.extname(filePath).toLowerCase() === ".go";
|
|
64
64
|
}
|
|
65
|
+
/** Forget the memoized go path and latched availability verdict — #2455. */
|
|
66
|
+
resetAvailability() {
|
|
67
|
+
this.availability.reset();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The one `GoClient` this process owns (#2455 fix round 4, F2).
|
|
72
|
+
*
|
|
73
|
+
* `GoClient` is not stateless: it wraps a `createToolchainAvailability` latch
|
|
74
|
+
* whose probe-class "missing" verdict never expires (`isLatchingOutcome`), and
|
|
75
|
+
* `resetGoAvailability` below re-arms exactly ONE such latch. Round 2 shipped
|
|
76
|
+
* with two instances — `dispatch/runners/go-vet.ts` built one for the runner
|
|
77
|
+
* and `bootstrap.ts` built another for `BootstrapClients.goClient`, which is
|
|
78
|
+
* the object `handleSessionStart` reads for its "Active tools" line. The
|
|
79
|
+
* session reset cleared the runner's copy and left the session-start copy
|
|
80
|
+
* latched, so a go toolchain installed between sessions stayed invisible on
|
|
81
|
+
* the surface a user actually sees. One instance, in the module that owns the
|
|
82
|
+
* class, is what makes the reset total; `tests/clients/toolchain-client-singleton.test.ts`
|
|
83
|
+
* holds the line.
|
|
84
|
+
*/
|
|
85
|
+
export const goClient = new GoClient();
|
|
86
|
+
/**
|
|
87
|
+
* Forget `goClient`'s memoized go path and latched availability verdict —
|
|
88
|
+
* #2455. Same #1496/#1535 shape as `resetZizmorTokenAvailability`; wired into
|
|
89
|
+
* `handleSessionStart` beside it (`clients/runtime-session.ts`) so a go
|
|
90
|
+
* toolchain installed mid-process is observed by the next session instead of
|
|
91
|
+
* staying "missing" for the rest of the process's life.
|
|
92
|
+
*
|
|
93
|
+
* This module — not `go-vet.ts` — because the reset must sit beside the single
|
|
94
|
+
* instance it clears (#2455 fix round 4, F2). It was invisible to the
|
|
95
|
+
* session-state sweep before round 2, but not for the reason an earlier draft
|
|
96
|
+
* of this comment gave (#2455 fix round 3, F4): the sweep skips any file
|
|
97
|
+
* exporting no reset at all, so widening the container predicate to "any class
|
|
98
|
+
* declared in `clients/`" could not have surfaced it. Adding this reset is
|
|
99
|
+
* what made the file visible — the fix preceded the detection, and the
|
|
100
|
+
* pair-with-reset blind spot (MISS 3 in `SWEEP_HEURISTIC_LIMITS`) is unchanged.
|
|
101
|
+
*/
|
|
102
|
+
export function resetGoAvailability() {
|
|
103
|
+
goClient.resetAvailability();
|
|
65
104
|
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ktfmt Gradle-plugin style carriage (#2468).
|
|
3
|
+
*
|
|
4
|
+
* The `com.ncorti.ktfmt.gradle` plugin's `ktfmt { }` extension block lets a
|
|
5
|
+
* project select `googleStyle()` or `kotlinLangStyle()` (verified against
|
|
6
|
+
* `KtfmtExtension.kt` in `cortinico/ktfmt-gradle` at
|
|
7
|
+
* `23bdedc8d5d641731a0cf128f1a386d5a127ce4e` — those two are the only style
|
|
8
|
+
* functions it defines today, and both are plain setters over
|
|
9
|
+
* `blockIndent`/`continuationIndent`/`trailingCommaManagementStrategy`, so a
|
|
10
|
+
* body calling both is LAST-CALL-WINS, not first).
|
|
11
|
+
*
|
|
12
|
+
* None of this is read by ktfmt's own CLI from `build.gradle` — verified
|
|
13
|
+
* against `ParsedArgs.kt` in `facebook/ktfmt` (now mirrored at
|
|
14
|
+
* `Kotlin/ktfmt`) at tag v0.63, the exact version `clients/installer/
|
|
15
|
+
* index.ts` pins for pi-lens's managed ktfmt install. That CLI accepts
|
|
16
|
+
* `--google-style` / `--kotlinlang-style` (plus the default `--meta-style`)
|
|
17
|
+
* — so the Gradle-declared choice has to be translated to the matching CLI
|
|
18
|
+
* flag by something on our side; ktfmt itself never bridges `build.gradle`
|
|
19
|
+
* to argv.
|
|
20
|
+
*
|
|
21
|
+
* Reuses the exact lexical pre-pass (`stripGradleCommentsAndStrings` /
|
|
22
|
+
* `namedGradleBlockRanges`) that `clients/tool-policy.ts`'s
|
|
23
|
+
* `getSpotlessKotlinFormatter` already applies to Gradle files, instead of a
|
|
24
|
+
* second hand-rolled Gradle-block parser (#2468 AC) — same
|
|
25
|
+
* single-source-of-truth reuse `clients/cargo-manifest.ts` did for TOML
|
|
26
|
+
* parsing in `clients/formatters.ts`'s rustfmt `--edition` carriage (#2466).
|
|
27
|
+
*
|
|
28
|
+
* ## Project scoping (#2468 review rounds 2 and 3)
|
|
29
|
+
*
|
|
30
|
+
* A Gradle build file configures more than the directory it sits in, and the
|
|
31
|
+
* multi-module layout the plugin is actually used in puts the style in the
|
|
32
|
+
* ROOT build file while each module's own `build.gradle(.kts)` declares only
|
|
33
|
+
* its plugins. Round 1 stopped the ancestor climb at the first directory
|
|
34
|
+
* holding ANY gradle file and matched `ktfmt {` anywhere in it, which was
|
|
35
|
+
* wrong in both directions: a module inherited nothing (the #2468 defect
|
|
36
|
+
* survived for the common layout) while the ROOT's own sources were handed a
|
|
37
|
+
* `subprojects { }`-scoped style that Gradle never applies to them. This
|
|
38
|
+
* module therefore classifies each `ktfmt { }` block by the block ENCLOSING
|
|
39
|
+
* it — the actual brace nesting on the stripped source, not a single
|
|
40
|
+
* hard-coded name test — and climbs past directories that declare no style
|
|
41
|
+
* for the project being formatted:
|
|
42
|
+
*
|
|
43
|
+
* - no enclosing block (a top-level `ktfmt { }`) → the DECLARING directory
|
|
44
|
+
* only. Gradle does not inherit here: the plugin gives each project its own
|
|
45
|
+
* `KtfmtExtension` instance seeded with the plugin conventions (verified at
|
|
46
|
+
* the SHA above), so a module that applies the plugin and calls no style
|
|
47
|
+
* function really does format under ktfmt's default — which is exactly the
|
|
48
|
+
* bare invocation this resolver falls back to. Round 2 spread a top-level
|
|
49
|
+
* block over style-less descendants as a documented heuristic; that
|
|
50
|
+
* manufactured a NEW pi-lens/Gradle disagreement (pi-lens writes
|
|
51
|
+
* `--google-style`, `./gradlew ktfmtCheck` then rejects the file pi-lens
|
|
52
|
+
* just formatted) which the pre-#2468 bare invocation did not have, so it
|
|
53
|
+
* is gone. Aligning with `hasKtfmtConfig`'s wider climb does not justify
|
|
54
|
+
* it: that election answers "is ktfmt the formatter for this file", not
|
|
55
|
+
* "which style"; where Gradle carries no style down, the bare invocation IS
|
|
56
|
+
* the correct carriage of `--meta-style`.
|
|
57
|
+
* - `subprojects { ktfmt { … } }` → DESCENDANT directories only, never the
|
|
58
|
+
* declaring one. `subprojects` configures the children and nothing else.
|
|
59
|
+
* - `allprojects { ktfmt { … } }` → the declaring directory AND descendants.
|
|
60
|
+
* - anything else enclosing it — `configure(subprojects.filter { … }) { }`,
|
|
61
|
+
* `project(":app") { }`, `tasks.register(…) { }`, a convention-plugin
|
|
62
|
+
* wrapper, or more than one nested block — reaches NEITHER scope. pi-lens
|
|
63
|
+
* cannot evaluate a build script, so a scope it cannot compute fails closed
|
|
64
|
+
* to the bare invocation rather than being granted to every project.
|
|
65
|
+
*
|
|
66
|
+
* KNOWN GAP (#2468 review round 3, F3): the first gradle directory found by
|
|
67
|
+
* the climb is treated as the project that OWNS the file. A module directory
|
|
68
|
+
* that is `include(…)`d by `settings.gradle(.kts)` but holds NO build file of
|
|
69
|
+
* its own therefore resolves hop 0 to an ANCESTOR, and asks it for `own`
|
|
70
|
+
* scope when `descendants` is what Gradle would apply. Against a root
|
|
71
|
+
* `subprojects { ktfmt { … } }` this is a fail-safe miss — no flag, the
|
|
72
|
+
* pre-#2468 bare invocation — because `subprojects` only ever fills the
|
|
73
|
+
* `descendants` slot, which hop 0 never reads. But against a root's
|
|
74
|
+
* TOP-LEVEL `ktfmt { }` (`own` scope, by the table above) it is a WRONG
|
|
75
|
+
* flag: hop 0 reads `own` regardless of which project it actually belongs
|
|
76
|
+
* to, so the module is handed the ROOT's own style even though Gradle gives
|
|
77
|
+
* the module its own `KtfmtExtension` and applies no style there. Closing it
|
|
78
|
+
* means reading `settings.gradle`'s `include(…)` list to map a directory to
|
|
79
|
+
* a Gradle project, which this module does not do.
|
|
80
|
+
*/
|
|
81
|
+
import * as os from "node:os";
|
|
82
|
+
import * as path from "node:path";
|
|
83
|
+
import { readTextFileOrUndefined } from "./cargo-manifest.js";
|
|
84
|
+
import { findNearestMarkerRoot } from "./path-utils.js";
|
|
85
|
+
import { gradleBlockRanges, stripGradleCommentsAndStrings, } from "./tool-policy.js";
|
|
86
|
+
/** Nearest-first: a Kotlin script build file wins over its Groovy sibling. */
|
|
87
|
+
const KTFMT_GRADLE_ROOT_FILES = [
|
|
88
|
+
"build.gradle.kts",
|
|
89
|
+
"build.gradle",
|
|
90
|
+
"settings.gradle.kts",
|
|
91
|
+
"settings.gradle",
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* Ancestor gradle directories consulted before giving up. Each hop costs at
|
|
95
|
+
* most four small reads, and Gradle builds nest a handful of levels at most;
|
|
96
|
+
* the cap keeps a pathological tree (or a symlink cycle that survives
|
|
97
|
+
* `path.dirname`) from turning one format into an unbounded walk. The
|
|
98
|
+
* `homeDir` ceiling inside `findNearestMarkerRoot` normally ends the climb
|
|
99
|
+
* long before this.
|
|
100
|
+
*/
|
|
101
|
+
const MAX_GRADLE_ANCESTOR_HOPS = 16;
|
|
102
|
+
/** The CLI flags ktfmt v0.63 actually defines (`ParsedArgs.kt`, verified above). */
|
|
103
|
+
const KTFMT_STYLE_CLI_FLAG = {
|
|
104
|
+
google: "--google-style",
|
|
105
|
+
kotlinlang: "--kotlinlang-style",
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Read the style declared by one `ktfmt { }` block body, LAST call wins.
|
|
109
|
+
*
|
|
110
|
+
* `googleStyle()` and `kotlinLangStyle()` both just `.set(...)` the same
|
|
111
|
+
* three extension properties, so in `ktfmt { googleStyle(); kotlinLangStyle() }`
|
|
112
|
+
* the second call is the one whose values survive into the format (verified
|
|
113
|
+
* against `KtfmtExtension.kt`, SHA above). `undefined` means the block
|
|
114
|
+
* declares no recognized style call — including the `dropboxStyle()` that
|
|
115
|
+
* ktfmt-gradle removed in 0.19.0 and ktfmt's CLI never exposed a flag for,
|
|
116
|
+
* which is simply not a style this resolver can carry.
|
|
117
|
+
*/
|
|
118
|
+
function styleFromKtfmtBlockBody(body) {
|
|
119
|
+
let style;
|
|
120
|
+
let lastIndex = -1;
|
|
121
|
+
for (const [call, candidate] of [
|
|
122
|
+
[/\bgoogleStyle\s*\(\s*\)/g, "google"],
|
|
123
|
+
[/\bkotlinLangStyle\s*\(\s*\)/g, "kotlinlang"],
|
|
124
|
+
]) {
|
|
125
|
+
for (const match of body.matchAll(call)) {
|
|
126
|
+
if (match.index > lastIndex) {
|
|
127
|
+
lastIndex = match.index;
|
|
128
|
+
style = candidate;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return style;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The Gradle blocks whose scope is exactly expressible here. Every other
|
|
136
|
+
* enclosing block — including one we simply have not heard of — is a scope
|
|
137
|
+
* pi-lens cannot evaluate, and is NOT silently promoted to project-wide.
|
|
138
|
+
*/
|
|
139
|
+
const SCOPE_BY_ENCLOSING_BLOCK = {
|
|
140
|
+
subprojects: "descendants",
|
|
141
|
+
allprojects: "both",
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Classify one `ktfmt { }` block by the block that encloses it.
|
|
145
|
+
*
|
|
146
|
+
* `blocks` is every brace pair in the stripped source, so "enclosing" is
|
|
147
|
+
* literal containment, not a guess from a name test: `range` strictly inside
|
|
148
|
+
* `outer` means `outer.start < range.start` (an enclosing body always opens
|
|
149
|
+
* before the body it contains) and `outer.end >= range.end`.
|
|
150
|
+
*
|
|
151
|
+
* More than one enclosing block (`subprojects { afterEvaluate { ktfmt { } } }`)
|
|
152
|
+
* fails closed too. Composing scopes through an arbitrary intermediate is
|
|
153
|
+
* exactly the kind of build-script evaluation this lexical pass cannot do,
|
|
154
|
+
* and the cost of the conservative answer is the pre-#2468 bare invocation.
|
|
155
|
+
*/
|
|
156
|
+
function scopeOfKtfmtBlock(range, blocks) {
|
|
157
|
+
const enclosing = blocks.filter((outer) => outer.start < range.start && outer.end >= range.end);
|
|
158
|
+
if (enclosing.length === 0)
|
|
159
|
+
return "own";
|
|
160
|
+
if (enclosing.length > 1)
|
|
161
|
+
return undefined;
|
|
162
|
+
return SCOPE_BY_ENCLOSING_BLOCK[enclosing[0].name];
|
|
163
|
+
}
|
|
164
|
+
function stylesFromGradleContent(content) {
|
|
165
|
+
const stripped = stripGradleCommentsAndStrings(content);
|
|
166
|
+
const blocks = gradleBlockRanges(stripped);
|
|
167
|
+
const styles = {};
|
|
168
|
+
// Source order, so a later block overwrites an earlier one for the scope
|
|
169
|
+
// it reaches — the same last-call-wins rule that applies inside one body.
|
|
170
|
+
// Each scope is written independently: two blocks that reach DISJOINT sets
|
|
171
|
+
// of projects (a `subprojects { }` one and a top-level one) must not fight
|
|
172
|
+
// over a single slot, or the source order of unrelated scopes decides
|
|
173
|
+
// which project gets the wrong flag.
|
|
174
|
+
for (const range of blocks) {
|
|
175
|
+
if (range.name !== "ktfmt")
|
|
176
|
+
continue;
|
|
177
|
+
const scope = scopeOfKtfmtBlock(range, blocks);
|
|
178
|
+
if (!scope)
|
|
179
|
+
continue;
|
|
180
|
+
const style = styleFromKtfmtBlockBody(stripped.slice(range.start, range.end));
|
|
181
|
+
if (!style)
|
|
182
|
+
continue;
|
|
183
|
+
if (scope !== "descendants")
|
|
184
|
+
styles.own = style;
|
|
185
|
+
if (scope !== "own")
|
|
186
|
+
styles.descendants = style;
|
|
187
|
+
}
|
|
188
|
+
return styles;
|
|
189
|
+
}
|
|
190
|
+
async function stylesForGradleDir(gradleDir) {
|
|
191
|
+
for (const gradleFile of KTFMT_GRADLE_ROOT_FILES) {
|
|
192
|
+
const content = await readTextFileOrUndefined(path.join(gradleDir, gradleFile));
|
|
193
|
+
if (content === undefined)
|
|
194
|
+
continue;
|
|
195
|
+
const styles = stylesFromGradleContent(content);
|
|
196
|
+
if (styles.own || styles.descendants)
|
|
197
|
+
return styles;
|
|
198
|
+
}
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Resolve the ktfmt CLI style flag (`--google-style` / `--kotlinlang-style`)
|
|
203
|
+
* for the Gradle project that owns `filePath`, so a caller that needs it
|
|
204
|
+
* doesn't have ktfmt silently apply its own default style
|
|
205
|
+
* (`--meta-style`-equivalent) where the project's `ktfmt { }` block picked a
|
|
206
|
+
* different one (#2468 — the same manifest-detected-but-not-carried defect
|
|
207
|
+
* shape #2466 fixed for rustfmt `--edition`).
|
|
208
|
+
*
|
|
209
|
+
* - Finds the nearest directory containing a `build.gradle(.kts)`/
|
|
210
|
+
* `settings.gradle(.kts)` file via the shared `findNearestMarkerRoot`
|
|
211
|
+
* walker (home-ceiling guarded, depth-capped — AGENTS.md
|
|
212
|
+
* walk-confinement; never a private walk-up loop). That first directory is
|
|
213
|
+
* TAKEN to be the project that OWNS the file, so its `own`-scope
|
|
214
|
+
* declaration applies; every further hop is an ancestor, so only its
|
|
215
|
+
* `descendants`-scope declaration does. See the module header's KNOWN GAP
|
|
216
|
+
* note for the `include(…)`-only module directory where that
|
|
217
|
+
* identification is wrong — a missed flag against a `subprojects { }` root,
|
|
218
|
+
* but a WRONG flag (the root's own style) against a root TOP-LEVEL one.
|
|
219
|
+
* - A nested module's OWN style declaration still wins over an ancestor's —
|
|
220
|
+
* the climb only continues past a gradle directory that declares NO style
|
|
221
|
+
* applying to this file, so nearest-wins is unchanged where a nearer
|
|
222
|
+
* declaration exists.
|
|
223
|
+
* - Returns `undefined` on any miss (no gradle file found, no `ktfmt { }`
|
|
224
|
+
* block, or no recognized style call in one): callers fall back to their
|
|
225
|
+
* pre-existing default argv rather than guessing. `dropboxStyle()` — the
|
|
226
|
+
* call ktfmt-gradle removed in 0.19.0, never a ktfmt CLI flag — is just
|
|
227
|
+
* such a miss and never becomes a guessed flag.
|
|
228
|
+
*
|
|
229
|
+
* `homeDir` defaults to `os.homedir()` and exists as a parameter so tests can
|
|
230
|
+
* inject a nearer ceiling and prove the guard actually stops a climb (mirrors
|
|
231
|
+
* `resolveCargoPackageEdition`'s `homeDir` parameter, #2466 review round 2,
|
|
232
|
+
* F5) — production callers never pass it.
|
|
233
|
+
*/
|
|
234
|
+
export async function resolveKtfmtGradleStyle(filePath, homeDir = os.homedir()) {
|
|
235
|
+
let searchDir = path.dirname(path.resolve(filePath));
|
|
236
|
+
for (let hop = 0; hop < MAX_GRADLE_ANCESTOR_HOPS; hop += 1) {
|
|
237
|
+
const gradleDir = findNearestMarkerRoot(searchDir, KTFMT_GRADLE_ROOT_FILES, {
|
|
238
|
+
homeDir,
|
|
239
|
+
});
|
|
240
|
+
if (!gradleDir)
|
|
241
|
+
return undefined;
|
|
242
|
+
const styles = await stylesForGradleDir(gradleDir);
|
|
243
|
+
const style = hop === 0 ? styles.own : styles.descendants;
|
|
244
|
+
if (style)
|
|
245
|
+
return KTFMT_STYLE_CLI_FLAG[style];
|
|
246
|
+
const parent = path.dirname(gradleDir);
|
|
247
|
+
if (parent === gradleDir)
|
|
248
|
+
return undefined;
|
|
249
|
+
searchDir = parent;
|
|
250
|
+
}
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
@@ -18,7 +18,7 @@ import { getPackageRoot } from "./package-root.js";
|
|
|
18
18
|
/** tree-sitter-wasms release the grammars are pulled from. */
|
|
19
19
|
export const TREE_SITTER_WASMS_VERSION = "0.1.13";
|
|
20
20
|
/** unpkg mirror of the tree-sitter-wasms artifacts. */
|
|
21
|
-
|
|
21
|
+
const GRAMMAR_CDN_BASE = `https://unpkg.com/tree-sitter-wasms@${TREE_SITTER_WASMS_VERSION}/out`;
|
|
22
22
|
export const GRAMMAR_SOURCE_OVERRIDES = {
|
|
23
23
|
"tree-sitter-lua.wasm": {
|
|
24
24
|
package: "@tree-sitter-grammars/tree-sitter-lua",
|
|
@@ -145,7 +145,7 @@ export const BLOCKED_GRAMMARS = {
|
|
|
145
145
|
},
|
|
146
146
|
};
|
|
147
147
|
/** Runtime signals for the currently-running process. */
|
|
148
|
-
|
|
148
|
+
function currentGrammarRuntime() {
|
|
149
149
|
const m = /^v?(\d+)/.exec(process.versions?.node ?? "");
|
|
150
150
|
return {
|
|
151
151
|
nodeMajor: m ? Number(m[1]) : 0,
|
|
@@ -173,7 +173,7 @@ export function grammarBlockReason(filename, rt = currentGrammarRuntime()) {
|
|
|
173
173
|
* both the download path (validate before writing) and the on-disk path
|
|
174
174
|
* (`fileHasWasmMagic`, for a file poisoned before this shipped) key off it.
|
|
175
175
|
*/
|
|
176
|
-
|
|
176
|
+
const WASM_MAGIC = [0x00, 0x61, 0x73, 0x6d];
|
|
177
177
|
/** Do `bytes` start with the wasm magic number? */
|
|
178
178
|
export function hasWasmMagic(bytes) {
|
|
179
179
|
if (bytes.length < WASM_MAGIC.length)
|