@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
|
@@ -1,5 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyzer bootstrap: the 17 shell-out analysis clients, loaded ON DEMAND.
|
|
3
|
+
*
|
|
4
|
+
* #2467: nothing about extension activation needs these clients. They are
|
|
5
|
+
* consumed by session startup's background scans, by the bootstrap-dependent
|
|
6
|
+
* `tool_call` branches, and by the project-diagnostics tools — every one of
|
|
7
|
+
* which can prove it needs them before the graph is paid for. So activation
|
|
8
|
+
* never touches this seam, and the load itself sits behind ONE shared
|
|
9
|
+
* retryable promise every consumer joins: `clients/single-flight.ts`'s
|
|
10
|
+
* primitive owns the identity-guarded release, so a rejected load frees the
|
|
11
|
+
* key for the next demand instead of latching (#1690/#1674) and concurrent
|
|
12
|
+
* demands never start a second load.
|
|
13
|
+
*
|
|
14
|
+
* The measured cost this moves off the interactive path is ~16ms of module
|
|
15
|
+
* evaluation plus ~3ms of construction, on top of whatever the 17 client
|
|
16
|
+
* modules are not already resident for — see the PR body for the numbers.
|
|
17
|
+
* The first session of a process runs in QUICK mode, which uses none of these
|
|
18
|
+
* clients, so that whole cost used to be paid for nothing on exactly the
|
|
19
|
+
* start the user is waiting on.
|
|
20
|
+
*
|
|
21
|
+
* Two accessors, deliberately different contracts:
|
|
22
|
+
*
|
|
23
|
+
* - {@link loadBootstrapClients} is the STRICT form the callers that cannot
|
|
24
|
+
* proceed without the clients keep using. It rejects rather than inventing
|
|
25
|
+
* an answer.
|
|
26
|
+
* - {@link requestBootstrapClients} is the BOUNDED, FAIL-OPEN form (#2467):
|
|
27
|
+
* it bounds the caller's wait on both axes AGENTS.md requires — a
|
|
28
|
+
* wall-clock ceiling and the caller's abort signal — and returns `null`
|
|
29
|
+
* rather than throwing, so the caller proceeds without the clients and the
|
|
30
|
+
* degradation is counted once in the ledger instead of surfacing as a
|
|
31
|
+
* failed tool call.
|
|
32
|
+
*
|
|
33
|
+
* Neither bound cancels the LOAD; promises are not cancellable and a dynamic
|
|
34
|
+
* import has no abort seam. They bound the WAIT. The shared flight keeps
|
|
35
|
+
* running, so a later demand reuses whatever it produced — the same
|
|
36
|
+
* abandon-the-wait, keep-the-work shape as `lsp-pull-late-answer`.
|
|
37
|
+
*/
|
|
1
38
|
import { logExtension } from "./extension-log.js";
|
|
2
|
-
|
|
39
|
+
import { bounded } from "./deadline-utils.js";
|
|
40
|
+
import { logLatency } from "./latency-logger.js";
|
|
41
|
+
import { emitBounded } from "./bounded-telemetry.js";
|
|
42
|
+
import { recordDegradationOnce } from "./degradation-ledger.js";
|
|
43
|
+
import { createSingleFlight } from "./single-flight.js";
|
|
44
|
+
/**
|
|
45
|
+
* The clients of a COMPLETED load, or `null` while none has completed.
|
|
46
|
+
*
|
|
47
|
+
* Process-lifetime on purpose: the 17 clients are stateless constructions and
|
|
48
|
+
* every session-scoped latch that lives ON them is re-armed at `session_start`
|
|
49
|
+
* by its own registered reset (`resetInstallRetryLatches`, #1497, is the
|
|
50
|
+
* canonical one). Dropping the clients at a session boundary would re-pay the
|
|
51
|
+
* whole load for nothing and would silently orphan those resets.
|
|
52
|
+
*
|
|
53
|
+
* Only a SUCCESSFUL load writes it, which is what makes retry-after-failure
|
|
54
|
+
* work at all: a rejected load leaves this `null`, so the next demand starts a
|
|
55
|
+
* fresh flight instead of replaying the rejection (#1570's eviction, now owned
|
|
56
|
+
* by the single-flight primitive's identity-guarded release).
|
|
57
|
+
*/
|
|
58
|
+
let residentClients = null;
|
|
59
|
+
/**
|
|
60
|
+
* Set by {@link markAnalyzerBootstrapShutdown} when the PRIMARY session tears
|
|
61
|
+
* down. It refuses NEW loads only — a demand that already joined the in-flight
|
|
62
|
+
* load keeps its promise and still settles (#2467 AC4). Session-scoped, not
|
|
63
|
+
* process-scoped: a replacement session in the same process must be able to
|
|
64
|
+
* load again, which is what {@link resetAnalyzerBootstrapSessionState} restores.
|
|
65
|
+
*/
|
|
66
|
+
let bootstrapShutdown = false;
|
|
67
|
+
/**
|
|
68
|
+
* The abort signal every BOUNDED demand races, aborted by
|
|
69
|
+
* {@link markAnalyzerBootstrapShutdown} and replaced at `session_start`.
|
|
70
|
+
*
|
|
71
|
+
* #2467 review: the two session-start schedulers must NOT bind the ambient
|
|
72
|
+
* TURN signal — a `session_start` that lands mid-turn (sequential
|
|
73
|
+
* replacement, `/new`) would otherwise cancel every startup scan with no
|
|
74
|
+
* retry, which is #1394's exact lesson. They are not turn-scoped work. But
|
|
75
|
+
* "no abort at all" is not the answer either: AGENTS.md's both-bounds rule
|
|
76
|
+
* wants a wall-clock ceiling AND an abort race, and the bound that is
|
|
77
|
+
* genuinely theirs is the SESSION's own teardown. So the seam supplies it,
|
|
78
|
+
* for every caller, rather than each caller inventing one.
|
|
79
|
+
*/
|
|
80
|
+
let bootstrapShutdownController = new AbortController();
|
|
81
|
+
/**
|
|
82
|
+
* Consecutive BUILD failures, reset by a successful build and by
|
|
83
|
+
* `session_start`. See {@link BOOTSTRAP_FAILURE_STRIKE_LIMIT}.
|
|
84
|
+
*/
|
|
85
|
+
let bootstrapFailureStrikes = 0;
|
|
86
|
+
/**
|
|
87
|
+
* How many BUILDS have been started this process (not how many demands were
|
|
88
|
+
* made — concurrent demands share one build). Stamped into the
|
|
89
|
+
* `bootstrap_clients_load` record as `attempt`, which is the discrimination
|
|
90
|
+
* #2467's observability section asks for: it tells a field reader whether a
|
|
91
|
+
* record is the initial attempt or a retry after a transient failure, without
|
|
92
|
+
* adding a per-demand record.
|
|
93
|
+
*/
|
|
94
|
+
let bootstrapLoadAttempts = 0;
|
|
95
|
+
/**
|
|
96
|
+
* The one key in the flight registry. `createSingleFlight` is keyed because
|
|
97
|
+
* most of its sites dedupe per file or per server; this one has a single
|
|
98
|
+
* subject, so it pays one map entry for the four guards the primitive owns.
|
|
99
|
+
*/
|
|
100
|
+
const BOOTSTRAP_FLIGHT_KEY = "analyzer-bootstrap";
|
|
101
|
+
/**
|
|
102
|
+
* No `generation` hook. The primitive's own doc states the rule: a generation
|
|
103
|
+
* is for an answer a session boundary INVALIDATES. These clients are stateless
|
|
104
|
+
* and outlive every session in the process, so a pre-reset flight's result is
|
|
105
|
+
* exactly as correct for a post-reset caller — a generation check here could
|
|
106
|
+
* never kill a test, which is the vacuous guard this repo keeps deleting.
|
|
107
|
+
*/
|
|
108
|
+
const bootstrapFlight = createSingleFlight();
|
|
109
|
+
/**
|
|
110
|
+
* Wall-clock ceiling on ONE caller's wait, not on the load.
|
|
111
|
+
*
|
|
112
|
+
* Measured cold cost of the load is ~100ms from an empty module graph and
|
|
113
|
+
* ~19ms once `index.ts`'s own graph is resident, so 10s is not a performance
|
|
114
|
+
* budget — it is the liveness bound AGENTS.md's both-bounds rule requires, so
|
|
115
|
+
* a wedged module evaluation cannot park a `tool_call` handler forever.
|
|
116
|
+
*/
|
|
117
|
+
const BOOTSTRAP_LOAD_TIMEOUT_MS = 10_000;
|
|
118
|
+
/**
|
|
119
|
+
* How many consecutive failed builds before the seam stops rebuilding.
|
|
120
|
+
*
|
|
121
|
+
* Retry-after-failure is right for a TRANSIENT fault, which is the case the
|
|
122
|
+
* flight's identity-guarded release was written for. It is wrong for a
|
|
123
|
+
* PERMANENT one: an analyzer module that cannot resolve under the host's
|
|
124
|
+
* package layout (#285/#335) fails identically every time, and without a
|
|
125
|
+
* latch every later demand re-ran seventeen dynamic imports plus
|
|
126
|
+
* `collectInstallDiagnostics` — on the tool-call hot path — for an answer
|
|
127
|
+
* that could not change. Three strikes distinguishes "the filesystem
|
|
128
|
+
* hiccuped" from "this environment cannot load these analyzers"; after that
|
|
129
|
+
* the demand fails OPEN immediately, and `session_start` re-arms the latch so
|
|
130
|
+
* a repaired environment is never locked out for the life of the process.
|
|
131
|
+
*/
|
|
132
|
+
const BOOTSTRAP_FAILURE_STRIKE_LIMIT = 3;
|
|
3
133
|
/**
|
|
4
134
|
* A stand-in for an analysis client whose module failed to load (an unresolved
|
|
5
135
|
* runtime dependency under a package-manager layout the resolver can't traverse
|
|
@@ -48,81 +178,387 @@ async function logBootstrapFailures(failures) {
|
|
|
48
178
|
}
|
|
49
179
|
}
|
|
50
180
|
/**
|
|
51
|
-
* Every per-client load below is individually
|
|
52
|
-
* degrade to a stub instead of throwing), so this
|
|
53
|
-
* reject in practice
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
181
|
+
* Build the 17 clients once. Every per-client load below is individually
|
|
182
|
+
* fail-soft (`load`/`loadList` degrade to a stub instead of throwing), so this
|
|
183
|
+
* is not expected to reject in practice — a genuinely unexpected throw (e.g.
|
|
184
|
+
* `logBootstrapFailures`) is what the retryable flight above exists for.
|
|
185
|
+
*
|
|
186
|
+
* Not exported: callers go through {@link loadBootstrapClients} or
|
|
187
|
+
* {@link requestBootstrapClients} so the sharing, the retry, and the shutdown
|
|
188
|
+
* gate cannot be bypassed by a new call site.
|
|
189
|
+
*/
|
|
190
|
+
async function buildBootstrapClients() {
|
|
191
|
+
const failures = [];
|
|
192
|
+
// Load + construct one client in isolation; on failure record it and
|
|
193
|
+
// substitute a degraded no-op stub so the others still load — single-seam
|
|
194
|
+
// fail-soft, consumers never special-case it.
|
|
195
|
+
async function load(name, make) {
|
|
196
|
+
try {
|
|
197
|
+
return await make();
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
failures.push({ name, err });
|
|
201
|
+
return degradedClient();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Lists degrade to empty (a stub Proxy isn't iterable), e.g. dead-code.
|
|
205
|
+
async function loadList(name, make) {
|
|
206
|
+
try {
|
|
207
|
+
return await make();
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
failures.push({ name, err });
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const [ruffClient, biomeClient, knipClient, todoScanner, jscpdClient, depChecker, testRunnerClient, metricsClient, complexityClient, goClient, govulncheckClient, gitleaksClient, trivyClient, opengrepClient, rustClient, agentBehaviorClient, deadCodeClients,] = await Promise.all([
|
|
215
|
+
load("ruff", async () => new (await import("./ruff-client.js")).RuffClient()),
|
|
216
|
+
load("biome", async () => new (await import("./biome-client.js")).BiomeClient()),
|
|
217
|
+
load("knip", async () => new (await import("./knip-client.js")).KnipClient()),
|
|
218
|
+
load("todo", async () => new (await import("./todo-scanner.js")).TodoScanner()),
|
|
219
|
+
load("jscpd", async () => new (await import("./jscpd-client.js")).JscpdClient()),
|
|
220
|
+
load("dependency-checker", async () => new (await import("./dependency-checker.js")).DependencyChecker()),
|
|
221
|
+
load("test-runner", async () => new (await import("./test-runner-client.js")).TestRunnerClient()),
|
|
222
|
+
load("metrics", async () => new (await import("./metrics-client.js")).MetricsClient()),
|
|
223
|
+
load("complexity", async () => new (await import("./complexity-client.js")).ComplexityClient()),
|
|
224
|
+
// The process-wide singleton, NOT a fresh instance (#2455 fix round 4,
|
|
225
|
+
// F2). `handleSessionStart` reads this object for its "Active tools"
|
|
226
|
+
// line while `resetGoAvailability` re-arms the singleton's latch; a
|
|
227
|
+
// second instance here meant the reset never reached the surface a
|
|
228
|
+
// user actually sees.
|
|
229
|
+
load("go", async () => (await import("./go-client.js")).goClient),
|
|
230
|
+
load("govulncheck", async () => new (await import("./govulncheck-client.js")).GovulncheckClient()),
|
|
231
|
+
load("gitleaks", async () => new (await import("./gitleaks-client.js")).GitleaksClient()),
|
|
232
|
+
load("trivy", async () => new (await import("./trivy-client.js")).TrivyClient()),
|
|
233
|
+
load("opengrep", async () => new (await import("./opengrep-client.js")).OpengrepClient()),
|
|
234
|
+
// The process-wide singleton, for the same reason as "go" above.
|
|
235
|
+
load("rust", async () => (await import("./rust-client.js")).rustClient),
|
|
236
|
+
load("agent-behavior", async () => new (await import("./agent-behavior-client.js")).AgentBehaviorClient()),
|
|
237
|
+
loadList("dead-code", async () => (await import("./dead-code-client.js")).getDeadCodeClients()),
|
|
238
|
+
]);
|
|
239
|
+
if (failures.length > 0)
|
|
240
|
+
await logBootstrapFailures(failures);
|
|
241
|
+
return {
|
|
242
|
+
ruffClient,
|
|
243
|
+
biomeClient,
|
|
244
|
+
knipClient,
|
|
245
|
+
todoScanner,
|
|
246
|
+
jscpdClient,
|
|
247
|
+
depChecker,
|
|
248
|
+
testRunnerClient,
|
|
249
|
+
metricsClient,
|
|
250
|
+
complexityClient,
|
|
251
|
+
goClient,
|
|
252
|
+
govulncheckClient,
|
|
253
|
+
gitleaksClient,
|
|
254
|
+
trivyClient,
|
|
255
|
+
opengrepClient,
|
|
256
|
+
rustClient,
|
|
257
|
+
agentBehaviorClient,
|
|
258
|
+
deadCodeClients,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Why a demand could not be served: `shutdown` (the primary session already
|
|
263
|
+
* tore down, so no new load may start), `timeout` (the caller's wall-clock
|
|
264
|
+
* ceiling elapsed), `aborted` (the caller's own signal fired — Escape, turn
|
|
265
|
+
* abort), `failed` (the load itself rejected), or `latched`
|
|
266
|
+
* ({@link BOOTSTRAP_FAILURE_STRIKE_LIMIT} consecutive builds failed, so the
|
|
267
|
+
* seam stopped rebuilding). A `null` from
|
|
268
|
+
* {@link requestBootstrapClients} never says which on its own, so the reason
|
|
269
|
+
* travels in the bounded record and the ledger entry instead.
|
|
270
|
+
*/
|
|
271
|
+
const BOOTSTRAP_UNAVAILABLE_REASONS = [
|
|
272
|
+
"shutdown",
|
|
273
|
+
"timeout",
|
|
274
|
+
"aborted",
|
|
275
|
+
"failed",
|
|
276
|
+
"latched",
|
|
277
|
+
];
|
|
278
|
+
/** A demand that could not be served. Carries the discriminating reason. */
|
|
279
|
+
class BootstrapUnavailableError extends Error {
|
|
280
|
+
unavailableReason;
|
|
281
|
+
constructor(unavailableReason, message) {
|
|
282
|
+
super(message);
|
|
283
|
+
this.name = "BootstrapUnavailableError";
|
|
284
|
+
this.unavailableReason = unavailableReason;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The clients a completed load produced, or `null`.
|
|
289
|
+
*
|
|
290
|
+
* NEVER starts a load. This is the accessor for work that must touch the
|
|
291
|
+
* clients only if they already exist — session start's `metricsClient.reset()`
|
|
292
|
+
* and `knipClient.resetSessionState()` are exactly that: re-arming state on a
|
|
293
|
+
* client that was never constructed is vacuous, and loading 17 modules in
|
|
294
|
+
* order to reset nothing is the cost #2467 removes.
|
|
295
|
+
*/
|
|
296
|
+
export function peekBootstrapClients() {
|
|
297
|
+
return residentClients;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* A {@link SessionBootstrapAccess} over clients that are ALREADY loaded.
|
|
301
|
+
*
|
|
302
|
+
* `clients/mcp/session.ts` builds its whole session context up front — an MCP
|
|
303
|
+
* call has nothing to defer to — so it holds the seventeen clients before it
|
|
304
|
+
* ever calls `handleSessionStart`. This is the two-line adapter that lets the
|
|
305
|
+
* handler take ONE shape instead of admitting a second, untyped one in which
|
|
306
|
+
* fifteen individually-optional client fields stood in for the seam ("exactly
|
|
307
|
+
* one of the two is supplied" was prose, not a type; a dropped
|
|
308
|
+
* `metricsClient` compiled and silently skipped every startup scan).
|
|
309
|
+
*/
|
|
310
|
+
export function residentBootstrapAccess(clients) {
|
|
311
|
+
return {
|
|
312
|
+
peek: () => clients,
|
|
313
|
+
request: async () => clients,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* The STRICT accessor: resolve the shared clients or reject.
|
|
318
|
+
*
|
|
319
|
+
* Concurrent callers join one flight (identity-guarded by
|
|
320
|
+
* `clients/single-flight.ts`, so a late settle can never evict a successor's
|
|
321
|
+
* entry). A rejected load releases the key, so the NEXT demand retries rather
|
|
322
|
+
* than replaying the rejection — with the caveat `clients/lazy-import.ts`
|
|
323
|
+
* documents: a module that threw during EVALUATION is memoized as rejected by
|
|
324
|
+
* Node's ESM loader, so a retry re-runs `buildBootstrapClients` but that one
|
|
325
|
+
* module's `import()` replays its cached rejection. Every per-client load is
|
|
326
|
+
* individually fail-soft, so that case degrades one analyzer, not the set.
|
|
57
327
|
*/
|
|
58
328
|
export function loadBootstrapClients() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
329
|
+
// The memo short-circuit sits ABOVE the flight check deliberately, and is
|
|
330
|
+
// written only on success — so it can never hide the in-flight path from a
|
|
331
|
+
// concurrent caller the way #1690's did. Before the first success there is
|
|
332
|
+
// no memo, which is exactly the window sharing has to cover.
|
|
333
|
+
if (residentClients)
|
|
334
|
+
return Promise.resolve(residentClients);
|
|
335
|
+
// #2467: refuse to START a load after primary shutdown, but never
|
|
336
|
+
// invalidate a waiter. `has()` is the whole guard: when a flight is already
|
|
337
|
+
// running the call below joins it, so the demand that was mid-air when
|
|
338
|
+
// shutdown landed still settles with real clients.
|
|
339
|
+
if (bootstrapShutdown && !bootstrapFlight.has(BOOTSTRAP_FLIGHT_KEY)) {
|
|
340
|
+
return Promise.reject(new BootstrapUnavailableError("shutdown", "analyzer bootstrap declined: primary session is shutting down"));
|
|
341
|
+
}
|
|
342
|
+
// Unlike the shutdown gate above, this one has no `!has()` half: strikes
|
|
343
|
+
// only ever reach the limit inside `noteBootstrapBuildFailure`, which runs
|
|
344
|
+
// synchronously INSIDE this flight's own callback, immediately before it
|
|
345
|
+
// rethrows and the flight's `release` runs — there is no synchronous window
|
|
346
|
+
// in which a fresh call can observe strikes at the limit while that same
|
|
347
|
+
// flight is still registered. A `!has()` half here would only ever be
|
|
348
|
+
// false, so it stayed an untested branch (#2467 review, F2) rather than a
|
|
349
|
+
// second guard.
|
|
350
|
+
if (bootstrapFailureStrikes >= BOOTSTRAP_FAILURE_STRIKE_LIMIT) {
|
|
351
|
+
return Promise.reject(new BootstrapUnavailableError("latched", `analyzer bootstrap declined: ${bootstrapFailureStrikes} consecutive load failures`));
|
|
352
|
+
}
|
|
353
|
+
return bootstrapFlight.run(BOOTSTRAP_FLIGHT_KEY, async () => {
|
|
354
|
+
const attempt = (bootstrapLoadAttempts += 1);
|
|
355
|
+
const startedAt = Date.now();
|
|
356
|
+
let clients;
|
|
357
|
+
try {
|
|
358
|
+
clients = await buildBootstrapClients();
|
|
72
359
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return await make();
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
failures.push({ name, err });
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
noteBootstrapBuildFailure(err);
|
|
362
|
+
throw err;
|
|
82
363
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (failures.length > 0)
|
|
103
|
-
await logBootstrapFailures(failures);
|
|
104
|
-
return {
|
|
105
|
-
ruffClient,
|
|
106
|
-
biomeClient,
|
|
107
|
-
knipClient,
|
|
108
|
-
todoScanner,
|
|
109
|
-
jscpdClient,
|
|
110
|
-
depChecker,
|
|
111
|
-
testRunnerClient,
|
|
112
|
-
metricsClient,
|
|
113
|
-
complexityClient,
|
|
114
|
-
goClient,
|
|
115
|
-
govulncheckClient,
|
|
116
|
-
gitleaksClient,
|
|
117
|
-
trivyClient,
|
|
118
|
-
opengrepClient,
|
|
119
|
-
rustClient,
|
|
120
|
-
agentBehaviorClient,
|
|
121
|
-
deadCodeClients,
|
|
122
|
-
};
|
|
123
|
-
})().catch((err) => {
|
|
124
|
-
bootstrapPromise = null;
|
|
125
|
-
throw err;
|
|
364
|
+
// A SUCCESS is what makes the strikes consecutive rather than a running
|
|
365
|
+
// total, so one bad build in a healthy process never edges the latch shut.
|
|
366
|
+
bootstrapFailureStrikes = 0;
|
|
367
|
+
residentClients = clients;
|
|
368
|
+
// The one timing record #2467's observability section keeps. It used to
|
|
369
|
+
// be emitted by `handleSessionStart` from timestamps `index.ts` took
|
|
370
|
+
// around its eager pre-handler load; now it is emitted where the load
|
|
371
|
+
// actually happens, so it stays truthful once the load is on demand.
|
|
372
|
+
// `attempt` distinguishes a retry from the initial attempt without
|
|
373
|
+
// adding a per-demand record.
|
|
374
|
+
logLatency({
|
|
375
|
+
type: "phase",
|
|
376
|
+
phase: "bootstrap_clients_load",
|
|
377
|
+
filePath: process.cwd(),
|
|
378
|
+
startedAt: new Date(startedAt).toISOString(),
|
|
379
|
+
durationMs: Date.now() - startedAt,
|
|
380
|
+
metadata: { attempt },
|
|
381
|
+
});
|
|
382
|
+
return clients;
|
|
126
383
|
});
|
|
127
|
-
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Count a failed build and, on the transition that closes the latch, write the
|
|
387
|
+
* ONE durable row saying this environment has stopped being retried.
|
|
388
|
+
*
|
|
389
|
+
* `recordDegradationOnce` is the repo's own once-per-kind/subject recorder, so
|
|
390
|
+
* the latch needs no parallel "have I logged this yet" boolean beside the one
|
|
391
|
+
* the ledger already keeps.
|
|
392
|
+
*/
|
|
393
|
+
function noteBootstrapBuildFailure(err) {
|
|
394
|
+
bootstrapFailureStrikes += 1;
|
|
395
|
+
if (bootstrapFailureStrikes !== BOOTSTRAP_FAILURE_STRIKE_LIMIT)
|
|
396
|
+
return;
|
|
397
|
+
recordDegradationOnce({
|
|
398
|
+
kind: "analyzer-bootstrap-latched",
|
|
399
|
+
subject: BOOTSTRAP_FLIGHT_KEY,
|
|
400
|
+
reason: `${BOOTSTRAP_FAILURE_STRIKE_LIMIT} consecutive load failures; no further builds this session: ${err?.message ?? String(err)}`,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* The BOUNDED, FAIL-OPEN accessor (#2467).
|
|
405
|
+
*
|
|
406
|
+
* Bounds the caller's WAIT on both axes AGENTS.md's both-bounds rule names —
|
|
407
|
+
* a wall-clock ceiling AND the caller's abort signal — and answers `null`
|
|
408
|
+
* instead of throwing, so the caller proceeds without the clients. Every
|
|
409
|
+
* `null` caused by the SEAM (shutdown, timeout, a rejected load, or the
|
|
410
|
+
* strike latch) is counted in the degradation ledger under
|
|
411
|
+
* `analyzer-bootstrap-unavailable`, rising-edge per subject, so a repeated
|
|
412
|
+
* failure stays one record with an exact count rather than per-demand spam.
|
|
413
|
+
* A `null` caused by the CALLER'S OWN signal firing is not: that is the
|
|
414
|
+
* caller choosing to stop waiting (Escape, a turn ending), not the analyzer
|
|
415
|
+
* graph degrading, and counting it inverted the two in `pilens_health`.
|
|
416
|
+
*/
|
|
417
|
+
export async function requestBootstrapClients(options) {
|
|
418
|
+
if (residentClients)
|
|
419
|
+
return residentClients;
|
|
420
|
+
// The seam's own session-teardown bound travels with EVERY demand, so a
|
|
421
|
+
// caller whose work is not turn-scoped (the two session-start schedulers)
|
|
422
|
+
// still satisfies AGENTS.md's both-bounds rule without binding a turn
|
|
423
|
+
// signal that would cancel it for the wrong reason.
|
|
424
|
+
const shutdownSignal = bootstrapShutdownController.signal;
|
|
425
|
+
const timeoutMs = options.timeoutMs ?? BOOTSTRAP_LOAD_TIMEOUT_MS;
|
|
426
|
+
try {
|
|
427
|
+
// #2523 slice 2: this used to be `awaitWithinBounds`, a private copy of
|
|
428
|
+
// exactly what `bounded()` does — same three-way precedence, same
|
|
429
|
+
// remove-the-listener-in-`finally`, same abandon-the-wait-keep-the-work
|
|
430
|
+
// contract. `bounded()` is a true superset of it (it also records the
|
|
431
|
+
// abandonment), so the copy is gone rather than kept in sync by hand.
|
|
432
|
+
//
|
|
433
|
+
// `undefined` here can only mean a bound fired: `loadBootstrapClients`
|
|
434
|
+
// resolves `BootstrapClients` or rejects, never `undefined`.
|
|
435
|
+
const clients = await bounded(loadBootstrapClients(), {
|
|
436
|
+
ms: timeoutMs,
|
|
437
|
+
// Genuinely absent for the three session-start schedulers — see
|
|
438
|
+
// `SessionBootstrapAccess.request` for why binding a turn signal
|
|
439
|
+
// there is the wrong bound. `shutdownSignal` is the second live
|
|
440
|
+
// bound in that case, so both still hold.
|
|
441
|
+
signal: options.signal,
|
|
442
|
+
shutdownSignal,
|
|
443
|
+
// The hook on the hook axis, the demand on the label (#2557 F7).
|
|
444
|
+
// `<hook>:loadBootstrapClients:<reason>` joins against
|
|
445
|
+
// `HOOK_WALL_BUDGET_MS` and still says WHICH demand blew the budget.
|
|
446
|
+
hook: options.hook,
|
|
447
|
+
label: `loadBootstrapClients:${options.reason}`,
|
|
448
|
+
});
|
|
449
|
+
if (clients)
|
|
450
|
+
return clients;
|
|
451
|
+
throw abandonedError(options.signal, shutdownSignal, timeoutMs);
|
|
452
|
+
}
|
|
453
|
+
catch (err) {
|
|
454
|
+
const unavailableReason = err instanceof BootstrapUnavailableError
|
|
455
|
+
? err.unavailableReason
|
|
456
|
+
: "failed";
|
|
457
|
+
// "aborted" means the CALLER'S OWN signal fired — a user pressing Escape
|
|
458
|
+
// mid-tool-call, a turn ending. That is the caller choosing to stop
|
|
459
|
+
// waiting, not the analyzer graph degrading, and writing it to the ledger
|
|
460
|
+
// inverted the two: a deliberate cancel surfaced identically to an
|
|
461
|
+
// unhealthy environment in `pilens_health`. `shutdown`/`timeout`/`failed`/
|
|
462
|
+
// `latched` all describe the SEAM failing to serve the demand, so those
|
|
463
|
+
// still count.
|
|
464
|
+
if (unavailableReason !== "aborted") {
|
|
465
|
+
emitBounded("bootstrap_clients_unavailable", options.reason, {
|
|
466
|
+
durationMs: 0,
|
|
467
|
+
metadata: {
|
|
468
|
+
unavailableReason,
|
|
469
|
+
attempt: bootstrapLoadAttempts,
|
|
470
|
+
detail: err?.message ?? String(err),
|
|
471
|
+
},
|
|
472
|
+
}, {
|
|
473
|
+
ledgerKind: "analyzer-bootstrap-unavailable",
|
|
474
|
+
risingEdgePer: "identity",
|
|
475
|
+
reason: unavailableReason,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Which bound won, read off the caller's own signal rather than guessed.
|
|
483
|
+
*
|
|
484
|
+
* Read AFTER `bounded()` has settled, exactly as the deleted `awaitWithinBounds`
|
|
485
|
+
* read it after its own race — and in the same precedence `bounded()` applies
|
|
486
|
+
* internally (caller, then teardown, then the clock), so the reason this
|
|
487
|
+
* reconstructs is the reason that fired.
|
|
488
|
+
*/
|
|
489
|
+
function abandonedError(signal, shutdownSignal, timeoutMs) {
|
|
490
|
+
if (signal?.aborted) {
|
|
491
|
+
return new BootstrapUnavailableError("aborted", "analyzer bootstrap wait abandoned: caller aborted");
|
|
492
|
+
}
|
|
493
|
+
if (shutdownSignal.aborted) {
|
|
494
|
+
return new BootstrapUnavailableError("shutdown", "analyzer bootstrap wait abandoned: primary session is shutting down");
|
|
495
|
+
}
|
|
496
|
+
return new BootstrapUnavailableError("timeout", `analyzer bootstrap wait abandoned after ${timeoutMs}ms`);
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Refuse NEW loads from here on — the primary session is tearing down.
|
|
500
|
+
*
|
|
501
|
+
* Deliberately does NOT clear `residentClients` or the in-flight entry: a
|
|
502
|
+
* demand already waiting must still settle (#2467), and the clients a
|
|
503
|
+
* completed load produced stay usable for whatever teardown work is still
|
|
504
|
+
* draining. Nothing here spawns, which is what AGENTS.md's #234 teardown rule
|
|
505
|
+
* requires of a `session_shutdown`-time call.
|
|
506
|
+
*/
|
|
507
|
+
export function markAnalyzerBootstrapShutdown() {
|
|
508
|
+
bootstrapShutdown = true;
|
|
509
|
+
// Unparks any bounded demand still waiting on a load rather than leaving it
|
|
510
|
+
// to burn the full wall-clock ceiling for clients its session will never use.
|
|
511
|
+
bootstrapShutdownController.abort();
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Re-arm the shutdown gate at `session_start`.
|
|
515
|
+
*
|
|
516
|
+
* The gate is a per-SESSION claim ("this session is over") held in
|
|
517
|
+
* process-lived storage — AGENTS.md defect shape 17 exactly. Without this a
|
|
518
|
+
* replacement session in the same process would find the analyzers refused
|
|
519
|
+
* for the rest of the process. The resident clients are NOT dropped: see
|
|
520
|
+
* `residentClients`' own comment for why re-paying the load at every session
|
|
521
|
+
* boundary would be wrong.
|
|
522
|
+
*/
|
|
523
|
+
export function resetAnalyzerBootstrapSessionState() {
|
|
524
|
+
bootstrapShutdown = false;
|
|
525
|
+
bootstrapShutdownController = new AbortController();
|
|
526
|
+
// The strike latch is a per-SESSION claim too: an environment repaired
|
|
527
|
+
// between sessions (a dependency installed, a package layout fixed) must be
|
|
528
|
+
// retried, not written off for the life of the process.
|
|
529
|
+
bootstrapFailureStrikes = 0;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Is the shutdown gate closed — i.e. would a fresh demand be refused?
|
|
533
|
+
*
|
|
534
|
+
* A synchronous read of the same flag {@link loadBootstrapClients} checks,
|
|
535
|
+
* so the session-state registry's probe can prove the session_start reset
|
|
536
|
+
* re-arms it without awaiting a load.
|
|
537
|
+
*/
|
|
538
|
+
export function isAnalyzerBootstrapShutdown() {
|
|
539
|
+
return bootstrapShutdown;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* How many consecutive builds have failed — the session-state registry's probe
|
|
543
|
+
* for the strike latch, which cannot be read off {@link isAnalyzerBootstrapShutdown}.
|
|
544
|
+
*/
|
|
545
|
+
export function _analyzerBootstrapFailureStrikes() {
|
|
546
|
+
return bootstrapFailureStrikes;
|
|
547
|
+
}
|
|
548
|
+
/** Test-only: close the strike latch without paying three real failed builds. */
|
|
549
|
+
export function _armAnalyzerBootstrapLatchForTests() {
|
|
550
|
+
bootstrapFailureStrikes = BOOTSTRAP_FAILURE_STRIKE_LIMIT;
|
|
551
|
+
}
|
|
552
|
+
/** Test-only: drop the resident clients, the flight, and the gate. */
|
|
553
|
+
export function _resetAnalyzerBootstrapForTests() {
|
|
554
|
+
residentClients = null;
|
|
555
|
+
bootstrapShutdown = false;
|
|
556
|
+
bootstrapShutdownController = new AbortController();
|
|
557
|
+
bootstrapFailureStrikes = 0;
|
|
558
|
+
bootstrapLoadAttempts = 0;
|
|
559
|
+
bootstrapFlight.clear();
|
|
560
|
+
}
|
|
561
|
+
/** Test/diagnostic: how many builds have been STARTED this process. */
|
|
562
|
+
export function _analyzerBootstrapLoadAttempts() {
|
|
563
|
+
return bootstrapLoadAttempts;
|
|
128
564
|
}
|