@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
|
@@ -11,10 +11,26 @@
|
|
|
11
11
|
* index.ts`'s import surface from `config.js` is mirrored by an explicit
|
|
12
12
|
* `vi.mock` factory in ~58 test files. Importing a new symbol from `config.js`
|
|
13
13
|
* breaks every one of them with "No export is defined on the mock", which is a
|
|
14
|
-
* standing tax on any future export.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* standing tax on any future export.
|
|
15
|
+
*
|
|
16
|
+
* WHY THE CONFIG PAYLOAD LIVES HERE TOO (#2518). Until this fix the payload
|
|
17
|
+
* lived in `config.ts`'s own 32-entry `workspaceConfigs` LRU while this
|
|
18
|
+
* registry held 128, and the two answered halves of ONE question: the registry
|
|
19
|
+
* decides whether a root still needs initializing (`ensureReady`,
|
|
20
|
+
* `mcp/server.ts`), the payload decides whether the operator's
|
|
21
|
+
* `lsp.disabledServers` denial applies (`isServerDisabled`). Thirty-three
|
|
22
|
+
* `ensureReady` calls on other cwds therefore dropped a LIVE root's denial
|
|
23
|
+
* while the registry still reported the root ready, so nothing re-initialized
|
|
24
|
+
* it and a server the operator had turned off came back — #2415 AC 3's exact
|
|
25
|
+
* prohibition, silently.
|
|
26
|
+
*
|
|
27
|
+
* Tying the two CAPS would not have fixed it. `initLSPConfig` registers the
|
|
28
|
+
* root BEFORE its `await` and writes the payload AFTER, so two interleaved
|
|
29
|
+
* initializations enter the two containers in different orders; with separate
|
|
30
|
+
* containers the same cap still evicts different keys from each. One entry per
|
|
31
|
+
* root — the key IS the registration, the value IS the payload — makes a
|
|
32
|
+
* payload miss for a served root impossible by construction instead of by an
|
|
33
|
+
* ordering agreement between two modules.
|
|
18
34
|
*
|
|
19
35
|
* WHY IT IS NOT A LATCH. The first attempt at #2052 used a single
|
|
20
36
|
* last-writer-wins session cwd that fell back to `process.cwd()`. Two bugs
|
|
@@ -31,31 +47,108 @@
|
|
|
31
47
|
*
|
|
32
48
|
* This is also the seam #2053 needs: an explicit `analysisRoot` registers here.
|
|
33
49
|
*/
|
|
50
|
+
import { BoundedFifoMap } from "../bounded-cache.js";
|
|
51
|
+
import { incrementDegradationCount } from "../degradation-ledger.js";
|
|
34
52
|
import { isSameOrWithin } from "./server.js";
|
|
35
53
|
import path from "node:path";
|
|
36
54
|
/**
|
|
37
|
-
* Insertion-ordered, so eviction drops the OLDEST root.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
55
|
+
* Insertion-ordered, so eviction drops the OLDEST root. `BoundedFifoMap`
|
|
56
|
+
* (#2442) owns the eviction; this module no longer hand-rolls it. FIFO and not
|
|
57
|
+
* LRU on purpose: eviction order is REGISTRATION order, so a config write for
|
|
58
|
+
* an already-registered root cannot reorder the registry underneath the
|
|
59
|
+
* `ensureReady` memo that reads it.
|
|
60
|
+
*
|
|
61
|
+
* The value is `undefined` between `registerSessionRoot` and the config write
|
|
62
|
+
* that follows the loader's `await` — the same window in which, before #2518,
|
|
63
|
+
* no payload existed for the root at all. {@link sessionRootConfigEntries}
|
|
64
|
+
* skips those entries, so an in-flight root resolves exactly as it did before:
|
|
65
|
+
* to a shorter ancestor root's config, or to none.
|
|
41
66
|
*/
|
|
42
|
-
const sessionRoots = new Set();
|
|
43
67
|
const SESSION_ROOT_CAP = 128;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
68
|
+
const sessionRoots = new BoundedFifoMap(SESSION_ROOT_CAP);
|
|
69
|
+
/**
|
|
70
|
+
* The cap dropped a root this process was serving. Its files fall back to
|
|
71
|
+
* pre-#2052 clamp behavior and its `lsp.disabledServers` denial stops applying
|
|
72
|
+
* until something initializes the root again — which `shouldInitializeSessionRoot`
|
|
73
|
+
* now guarantees the next SESSION START OR TOOL CALL naming that root does,
|
|
74
|
+
* because the registration went with the payload. Nothing else re-initializes:
|
|
75
|
+
* the readers of the denial (`isServerDisabled`, `getServersForFileWithConfig`,
|
|
76
|
+
* `getServerInitOverride`) ask the store, they never load it.
|
|
77
|
+
*
|
|
78
|
+
* A CONSTANT subject, counted rather than latched (#2518 review F3). The
|
|
79
|
+
* subject cannot be the evicted root: the ledger's `recordDegradationOnce` /
|
|
80
|
+
* `incrementDegradationCount` dedupe keys are unbounded, so a per-root subject
|
|
81
|
+
* would grow one key per root a long-lived process ever cycles through — a
|
|
82
|
+
* container bounded on one axis and unbounded on another, which is the shape
|
|
83
|
+
* this whole fix is about. That argument bounds the SUBJECT; it is not an
|
|
84
|
+
* argument for throwing the tally away, and the number of roots this process
|
|
85
|
+
* has had to drop is exactly what an operator tunes the cap against. The
|
|
86
|
+
* ledger keeps one entry per kind/subject and emits durable rows only on
|
|
87
|
+
* power-of-two counts, so counting is as bounded here as latching.
|
|
88
|
+
*
|
|
89
|
+
* Returns the evicted roots so the caller can drop the per-root session
|
|
90
|
+
* bookkeeping that described them — `initLSPConfig` releases each one's
|
|
91
|
+
* `config_resolved` claim (review F1).
|
|
92
|
+
*/
|
|
93
|
+
function noteEvictedRoots(evicted) {
|
|
94
|
+
const roots = evicted.map(([root]) => root);
|
|
95
|
+
if (roots.length > 0) {
|
|
96
|
+
incrementDegradationCount({
|
|
97
|
+
kind: "lsp-session-root-evicted",
|
|
98
|
+
subject: `cap=${SESSION_ROOT_CAP}`,
|
|
99
|
+
reason: `session root registry at capacity; dropped ${roots[0]} and will load it again on the next session start or tool call naming that root`,
|
|
100
|
+
});
|
|
52
101
|
}
|
|
102
|
+
return roots;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Record a session cwd as served. Idempotent; re-registering refreshes nothing.
|
|
106
|
+
* Returns the roots this insertion dropped at the cap, oldest first.
|
|
107
|
+
*/
|
|
108
|
+
export function registerSessionRoot(cwd) {
|
|
109
|
+
const root = path.resolve(cwd);
|
|
110
|
+
// Present already: leave the entry alone. Writing the `undefined`
|
|
111
|
+
// placeholder over a loaded config would blank a served root's denial for
|
|
112
|
+
// the length of the re-initializing load — the #2518 window in miniature.
|
|
113
|
+
if (sessionRoots.has(root))
|
|
114
|
+
return [];
|
|
115
|
+
return noteEvictedRoots(sessionRoots.set(root, undefined));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Store the config `initLSPConfig` just loaded for a root it registered.
|
|
119
|
+
*
|
|
120
|
+
* Re-inserts the root when the cap dropped it while the load was in flight:
|
|
121
|
+
* the caller is a live session declaring this root right now, so the pair
|
|
122
|
+
* belongs in the registry — and it is a PAIR, which is what keeps the payload
|
|
123
|
+
* from outliving the registration or the registration from outliving the
|
|
124
|
+
* payload.
|
|
125
|
+
*
|
|
126
|
+
* Returns the roots this write dropped at the cap, oldest first.
|
|
127
|
+
*/
|
|
128
|
+
export function setSessionRootConfig(cwd, config) {
|
|
129
|
+
return noteEvictedRoots(sessionRoots.set(path.resolve(cwd), config));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Every served root that has a loaded config, in registration order —
|
|
133
|
+
* `getConfigForFile`'s (`config.ts`) longest-prefix walk. Entries still
|
|
134
|
+
* awaiting their first load are skipped; see the store's doc comment.
|
|
135
|
+
*/
|
|
136
|
+
export function sessionRootConfigEntries() {
|
|
137
|
+
return sessionRoots;
|
|
53
138
|
}
|
|
54
139
|
/** Return whether this exact root is still served after cap eviction. */
|
|
55
140
|
export function isSessionRootRegistered(cwd) {
|
|
56
141
|
return sessionRoots.has(path.resolve(cwd));
|
|
57
142
|
}
|
|
58
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* True when a readiness memo must run initialization for this root.
|
|
145
|
+
*
|
|
146
|
+
* The memo alone is never enough (#2052 R1, #2518): a readiness set caps
|
|
147
|
+
* itself, and `initLSPConfig` has callers (`clients/runtime-session.ts`,
|
|
148
|
+
* `clients/lens-engine.ts`) that no memo sees, so a memo hit can outlive the
|
|
149
|
+
* registration — and with it the config that carries the operator's denial.
|
|
150
|
+
* Every readiness memo asks this function, never its own `has` alone.
|
|
151
|
+
*/
|
|
59
152
|
export function shouldInitializeSessionRoot(cwd, readyRoots) {
|
|
60
153
|
const normalized = path.resolve(cwd);
|
|
61
154
|
return !readyRoots.has(normalized) || !isSessionRootRegistered(normalized);
|
|
@@ -72,7 +165,7 @@ export function isOutsideAllSessionRoots(filePath) {
|
|
|
72
165
|
if (sessionRoots.size === 0)
|
|
73
166
|
return false;
|
|
74
167
|
const resolved = path.resolve(filePath);
|
|
75
|
-
for (const root of sessionRoots) {
|
|
168
|
+
for (const root of sessionRoots.keys()) {
|
|
76
169
|
if (isSameOrWithin(root, resolved))
|
|
77
170
|
return false;
|
|
78
171
|
}
|
|
@@ -85,14 +178,14 @@ export function isOutsideAllSessionRoots(filePath) {
|
|
|
85
178
|
* roots must not emit an unbounded path list.
|
|
86
179
|
*/
|
|
87
180
|
export function getSessionRootsForTelemetry(limit = 4) {
|
|
88
|
-
return [...sessionRoots]
|
|
181
|
+
return [...sessionRoots.keys()]
|
|
89
182
|
.sort((a, b) => Number(a > b) - Number(a < b))
|
|
90
183
|
.slice(0, limit);
|
|
91
184
|
}
|
|
92
185
|
/**
|
|
93
|
-
* Clear the registry
|
|
94
|
-
*
|
|
95
|
-
* exist.
|
|
186
|
+
* Clear the registry — the roots AND the configs they carry, which are one
|
|
187
|
+
* store since #2518, so a reset cannot leave the two disagreeing about which
|
|
188
|
+
* roots exist. Called by `resetLSPConfigStateForTests`.
|
|
96
189
|
*/
|
|
97
190
|
export function resetSessionRootsForTests() {
|
|
98
191
|
sessionRoots.clear();
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
/** Process-lifetime history of successful LSP spawn plus initialize durations. */
|
|
2
|
+
import { BoundedFifoMap } from "../bounded-cache.js";
|
|
2
3
|
const MAX_SERVER_HISTORIES = 64;
|
|
3
|
-
const successfulSpawnDurationMs = new
|
|
4
|
+
const successfulSpawnDurationMs = new BoundedFifoMap(MAX_SERVER_HISTORIES);
|
|
4
5
|
export function recordSuccessfulLspSpawn(serverId, durationMs) {
|
|
5
6
|
if (!Number.isFinite(durationMs) || durationMs < 0)
|
|
6
7
|
return;
|
|
7
8
|
successfulSpawnDurationMs.delete(serverId);
|
|
8
9
|
successfulSpawnDurationMs.set(serverId, durationMs);
|
|
9
|
-
while (successfulSpawnDurationMs.size > MAX_SERVER_HISTORIES) {
|
|
10
|
-
const oldest = successfulSpawnDurationMs.keys().next().value;
|
|
11
|
-
if (oldest === undefined)
|
|
12
|
-
break;
|
|
13
|
-
successfulSpawnDurationMs.delete(oldest);
|
|
14
|
-
}
|
|
15
10
|
}
|
|
16
11
|
export function getSuccessfulLspSpawnDurationMs(serverId) {
|
|
17
12
|
return successfulSpawnDurationMs.get(serverId);
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
* always sent, so an unrecognized/absent value never regresses `Full`/`None`
|
|
17
17
|
* behavior.
|
|
18
18
|
*/
|
|
19
|
-
export const TEXT_DOCUMENT_SYNC_KIND_NONE = 0;
|
|
20
19
|
export const TEXT_DOCUMENT_SYNC_KIND_FULL = 1;
|
|
21
20
|
export const TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL = 2;
|
|
22
21
|
function isSyncKind(value) {
|
|
@@ -37,7 +37,7 @@ import { normalizeMapKey } from "../path-utils.js";
|
|
|
37
37
|
// ---------------------------------------------------------------------------
|
|
38
38
|
// Constants
|
|
39
39
|
// ---------------------------------------------------------------------------
|
|
40
|
-
|
|
40
|
+
const TSSERVER_REQUEST_COMMAND = "typescript.tsserverRequest";
|
|
41
41
|
/**
|
|
42
42
|
* tsserver's synthetic inferred-project name, as its own source builds it:
|
|
43
43
|
* `"/dev/null/inferredProject" + counter + "*"`. `/dev/null` is a deliberate
|
|
@@ -219,13 +219,13 @@ export async function fetchTsserverProjectIdentity(svc, file) {
|
|
|
219
219
|
// ---------------------------------------------------------------------------
|
|
220
220
|
// Helpers
|
|
221
221
|
// ---------------------------------------------------------------------------
|
|
222
|
-
|
|
222
|
+
function isTsserverSyncRawDiagnostic(value) {
|
|
223
223
|
if (!value || typeof value !== "object")
|
|
224
224
|
return false;
|
|
225
225
|
const v = value;
|
|
226
226
|
return typeof v.message === "string" && typeof v.category === "string";
|
|
227
227
|
}
|
|
228
|
-
|
|
228
|
+
function tsserverSeverityFromCategory(category) {
|
|
229
229
|
switch (category) {
|
|
230
230
|
case "error":
|
|
231
231
|
return 1;
|
|
@@ -242,7 +242,7 @@ export function tsserverSeverityFromCategory(category) {
|
|
|
242
242
|
* `LSPDiagnostic`. Both `line`/`offset` are 1-based in tsserver's protocol
|
|
243
243
|
* and 0-based in LSP — this conversion handles that.
|
|
244
244
|
*/
|
|
245
|
-
|
|
245
|
+
function tsserverSyncDiagnosticToLsp(d) {
|
|
246
246
|
const startLine = Math.max(0, (d.startLocation?.line ?? 1) - 1);
|
|
247
247
|
const startChar = Math.max(0, (d.startLocation?.offset ?? 1) - 1);
|
|
248
248
|
const endLine = Math.max(0, (d.endLocation?.line ?? d.startLocation?.line ?? 1) - 1);
|
|
@@ -265,7 +265,7 @@ export function tsserverSyncDiagnosticToLsp(d) {
|
|
|
265
265
|
* executed, the response envelope isn't `{success:true, body:[...]}`, or
|
|
266
266
|
* any error is thrown.
|
|
267
267
|
*/
|
|
268
|
-
|
|
268
|
+
async function runTsserverSyncCommand(svc, file, command) {
|
|
269
269
|
if (typeof svc.executeCommand !== "function")
|
|
270
270
|
return undefined;
|
|
271
271
|
const outcome = await svc.executeCommand(file, TSSERVER_REQUEST_COMMAND, [
|
|
@@ -303,11 +303,18 @@ export async function runTsserverSyncCommand(svc, file, command) {
|
|
|
303
303
|
* server had computed but never published (silentOnClean) — these must be
|
|
304
304
|
* surfaced to the caller, not discarded. `confirmed: false` = sync path
|
|
305
305
|
* unavailable, fall through to existing behavior.
|
|
306
|
+
*
|
|
307
|
+
* #2598: `getAdvertisedCommands` is REQUIRED here rather than probed for. The
|
|
308
|
+
* real `LSPService` defines it unconditionally (clients/lsp/index.ts), and both
|
|
309
|
+
* production callers hand this function that service, so the former
|
|
310
|
+
* `typeof … !== "function"` bail was reachable only from a partial test double
|
|
311
|
+
* (AGENTS.md shape 7). It was also unobservable even there: an absent method
|
|
312
|
+
* throws a `TypeError` that this function's own catch turns into the same
|
|
313
|
+
* `undefined` the bail returned. `executeCommand` stays optional on
|
|
314
|
+
* {@link TsserverSyncCapableService} — see {@link runTsserverSyncCommand}.
|
|
306
315
|
*/
|
|
307
316
|
export async function attemptTsserverSyncDiagnostics(file, svc) {
|
|
308
317
|
try {
|
|
309
|
-
if (typeof svc.getAdvertisedCommands !== "function")
|
|
310
|
-
return undefined;
|
|
311
318
|
const advertised = await svc.getAdvertisedCommands(file);
|
|
312
319
|
if (!advertised.includes(TSSERVER_REQUEST_COMMAND))
|
|
313
320
|
return undefined;
|
|
@@ -24,6 +24,12 @@ export function classifyServerWaitTier(serverId, snapshot) {
|
|
|
24
24
|
const mode = snapshot.workspaceDiagnosticsSupport?.mode;
|
|
25
25
|
if (mode === "pull")
|
|
26
26
|
return "pull-capable";
|
|
27
|
+
if (snapshot.customServer === true &&
|
|
28
|
+
mode === "push-only" &&
|
|
29
|
+
snapshot.diagnosticsUnsupported === true &&
|
|
30
|
+
snapshot.diagnosticsPublished !== true) {
|
|
31
|
+
return "diagnostics-unsupported";
|
|
32
|
+
}
|
|
27
33
|
if (mode !== "push-only")
|
|
28
34
|
return "waits";
|
|
29
35
|
const strategy = getStrategy(serverId, snapshot.launchVariant);
|
|
@@ -73,6 +73,7 @@ export function resolveAstGrepNativeExe(platform = process.platform, arch = proc
|
|
|
73
73
|
return undefined;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
/** @public — loaded by scripts/probe-clean-signal.mjs through a dynamic import wrapper knip cannot see. */
|
|
76
77
|
export const SERVER_DIAGNOSTIC_STRATEGIES = {
|
|
77
78
|
typescript: {
|
|
78
79
|
seedFirstPush: true,
|
|
@@ -287,7 +288,7 @@ const NATIVE_TS7_DIAGNOSTIC_STRATEGY = {
|
|
|
287
288
|
silentOnClean: false,
|
|
288
289
|
};
|
|
289
290
|
/** Fallback for unknown servers. Conservative defaults. */
|
|
290
|
-
|
|
291
|
+
const DEFAULT_STRATEGY = {
|
|
291
292
|
seedFirstPush: false,
|
|
292
293
|
pullRetryBudgetMs: 250,
|
|
293
294
|
debounceMs: 150,
|
|
@@ -398,7 +398,7 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
|
|
|
398
398
|
const epoch = _cacheEpochs.capture(root);
|
|
399
399
|
const existing = loadWorkspaceDiagnosticsCache(root);
|
|
400
400
|
const entries = {
|
|
401
|
-
...
|
|
401
|
+
...existing?.entries,
|
|
402
402
|
};
|
|
403
403
|
const reverseDepsIndex = loadReverseDependencyIndexFromSnapshot({
|
|
404
404
|
cwd: root,
|
|
@@ -2,7 +2,7 @@ import { getLSPService } from "./lsp/index.js";
|
|
|
2
2
|
// Grounded against this repo's workspace-native TypeScript 7.0.2 server
|
|
3
3
|
// (`tsc --lsp --stdio`) on 2026-07-30: 20 already-open documentSymbol calls
|
|
4
4
|
// measured p50 3.70 ms / p95 5.28 ms. Keep generous headroom for slower hosts.
|
|
5
|
-
|
|
5
|
+
const LSP_DOCUMENT_SYMBOL_TIMEOUT_MS = 150;
|
|
6
6
|
export const SYMBOL_KIND_NAMES = {
|
|
7
7
|
1: "file",
|
|
8
8
|
2: "module",
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
import { BoundedSet } from "./bounded-cache.js";
|
|
2
3
|
import { createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
|
|
3
4
|
import { normalizeMapKey } from "./path-utils.js";
|
|
5
|
+
import { getMutationBridge } from "./mutation-bridge.js";
|
|
6
|
+
import { noteMutationHandled } from "./observed-mutation.js";
|
|
7
|
+
import { recordDegradationOnce } from "./degradation-ledger.js";
|
|
8
|
+
// #2450 fix round 3 (minor): gates the "bridge unavailable" dbg line to fire
|
|
9
|
+
// once per session, not once per FILE — a rename that touches many files in
|
|
10
|
+
// a bridge-less process (e.g. the MCP server) would otherwise spam the same
|
|
11
|
+
// line once per touched file. `recordDegradationOnce` itself has no
|
|
12
|
+
// first-occurrence return value (unlike `incrementDegradationCount`), so this
|
|
13
|
+
// tiny local latch is the minimal way to mirror that "once" intent onto the
|
|
14
|
+
// dbg line without changing the ledger's own once-per-(kind,subject) record.
|
|
15
|
+
//
|
|
16
|
+
// Catalog shape 17 (a process-lifetime latch must re-arm at session_start):
|
|
17
|
+
// wired into `handleSessionStart` (`clients/runtime-session.ts`) directly,
|
|
18
|
+
// NOT into `resetDegradationLedger()` — that lives in `degradation-ledger.ts`,
|
|
19
|
+
// which this module already imports, and reaching back from there to here
|
|
20
|
+
// would be a cycle.
|
|
21
|
+
let noBridgeDbgLogged = false;
|
|
22
|
+
export function resetLspMutationNoBridgeDbgLatch() {
|
|
23
|
+
noBridgeDbgLogged = false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Test-only peek at the latch's current value (#2450 fix round 5, F2) — lets
|
|
27
|
+
* the session-state registry probe the actual internal state instead of
|
|
28
|
+
* inferring it from captured dbg messages, the same pattern every other
|
|
29
|
+
* process-private-scalar probe in `tests/support/session-state-registry.ts`
|
|
30
|
+
* uses (e.g. `_observedMutationStateForTests`).
|
|
31
|
+
*/
|
|
32
|
+
export function _lspMutationNoBridgeDbgLoggedForTests() {
|
|
33
|
+
return noBridgeDbgLogged;
|
|
34
|
+
}
|
|
4
35
|
const MAX_SAMPLES = 100;
|
|
5
36
|
const MAX_SUMMARIES_PER_CONTEXT = 100;
|
|
6
37
|
export function newLspMutationCorrelationId(toolCallId) {
|
|
@@ -95,8 +126,35 @@ function uniqueDetails(files, fileDetails) {
|
|
|
95
126
|
}
|
|
96
127
|
function bookkeepLspMutation(context, files, fileDetails) {
|
|
97
128
|
const details = uniqueDetails(files, fileDetails);
|
|
129
|
+
// The direct path below needs `context.runtime` (the receipt) and
|
|
130
|
+
// `context.cacheManager` (the turn-state entry) threaded in by the caller.
|
|
131
|
+
// One caller structurally cannot: `workspace/applyEdit`'s server-initiated-edit
|
|
132
|
+
// handler (clients/lsp/client.ts) builds its own fallback `LspMutationContext`
|
|
133
|
+
// with neither, because there is no live reference to the runtime/cache-manager
|
|
134
|
+
// singletons at that call site. Rather than silently drop bookkeeping for that
|
|
135
|
+
// write, fall back to the mutation bridge (#2423) — mounted once at extension
|
|
136
|
+
// activation with live getters closing over the SAME singletons — which is
|
|
137
|
+
// exactly the seam built for "a producer that cannot reach the bookkeeping
|
|
138
|
+
// surfaces directly". This keeps `recordLspMutation` the ONE call site every
|
|
139
|
+
// LSP-applied edit bookkeeps through; the bridge is this function's OWN
|
|
140
|
+
// fallback, not a second seam other code reaches for on its behalf (#2450).
|
|
141
|
+
// Only the receipt (recordProjectMutation) and the turn-state entry
|
|
142
|
+
// (cacheManager.addModifiedRange) need the bridge fallback: the read-guard
|
|
143
|
+
// stamp is independent of them and already tolerates either being absent.
|
|
144
|
+
const useBridgeFallback = !context.runtime || !context.cacheManager;
|
|
98
145
|
for (const detail of details) {
|
|
99
146
|
const filePath = path.resolve(detail.filePath);
|
|
147
|
+
// #2450 review round 2 (F4): the SAME recordability gate the bridge
|
|
148
|
+
// fallback below already applies internally (`isRecordable`, mounted in
|
|
149
|
+
// index.ts). Applied here too so the direct (deps-threaded) branch
|
|
150
|
+
// cannot record a write the fallback branch would have silently
|
|
151
|
+
// dropped for the exact same reason (`no-read-guard` / ignored /
|
|
152
|
+
// vendor) — the two branches must agree on which files count as
|
|
153
|
+
// project source, not just on how they bookkeep the ones that do.
|
|
154
|
+
if (context.isRecordable && !context.isRecordable(filePath)) {
|
|
155
|
+
context.dbg?.(`lsp mutation not recordable, skipping ${filePath}`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
100
158
|
if (context.readGuard) {
|
|
101
159
|
try {
|
|
102
160
|
context.readGuard.recordWritten(filePath);
|
|
@@ -105,34 +163,118 @@ function bookkeepLspMutation(context, files, fileDetails) {
|
|
|
105
163
|
context.dbg?.(`lsp mutation read-guard stamp failed for ${filePath}: ${err}`);
|
|
106
164
|
}
|
|
107
165
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
166
|
+
if (useBridgeFallback) {
|
|
167
|
+
const bridge = getMutationBridge();
|
|
168
|
+
if (!bridge) {
|
|
169
|
+
// #2450 review round 2 (F4)/round 3 (minor): the MCP server process
|
|
170
|
+
// (`mcp/server.ts`) builds `lsp_navigation` with no
|
|
171
|
+
// `mutationDeps` AND never mounts the bridge (that only happens
|
|
172
|
+
// inside pi's own in-process extension activation, `index.ts`) —
|
|
173
|
+
// every LSP-applied edit in that process is unrecorded. Once per
|
|
174
|
+
// session (not once per file — a rename can touch many files in
|
|
175
|
+
// one call, and a session can issue many renames), not once per
|
|
176
|
+
// process lifetime silently. `subject` is a fixed, one-word
|
|
177
|
+
// degradation-ledger key (round 3: was `context.tool`, which
|
|
178
|
+
// varies per LSP operation — "lsp_navigation:rename" vs
|
|
179
|
+
// "...executeCommand" — so the SAME session could log this
|
|
180
|
+
// degradation once per operation kind instead of truly once).
|
|
181
|
+
recordDegradationOnce({
|
|
182
|
+
kind: "lsp-mutation-bridge-unmounted",
|
|
183
|
+
subject: "lsp-mutation:no-bridge",
|
|
184
|
+
reason: "workspace/applyEdit bookkeeping fell back to the mutation " +
|
|
185
|
+
"bridge, but no bridge is mounted in this process (e.g. the " +
|
|
186
|
+
"MCP server, which never runs pi's extension activation) — " +
|
|
187
|
+
"the write is unrecorded (no read-guard stamp, no turn-state " +
|
|
188
|
+
"entry, no change-log receipt).",
|
|
189
|
+
});
|
|
190
|
+
if (!noBridgeDbgLogged) {
|
|
191
|
+
noBridgeDbgLogged = true;
|
|
192
|
+
context.dbg?.(`lsp mutation bridge unavailable, dropping bookkeeping for ${filePath}`);
|
|
193
|
+
}
|
|
121
194
|
}
|
|
122
|
-
|
|
123
|
-
|
|
195
|
+
else {
|
|
196
|
+
try {
|
|
197
|
+
const recorded = bridge.recordMutation({
|
|
198
|
+
filePath,
|
|
199
|
+
kind: "edit",
|
|
200
|
+
editRanges: detail.range
|
|
201
|
+
? [[detail.range.start, detail.range.end]]
|
|
202
|
+
: undefined,
|
|
203
|
+
consumer: context.tool,
|
|
204
|
+
// Real value threaded through, not the bridge's own
|
|
205
|
+
// historical `false` default (#2450 review round 2, F1) —
|
|
206
|
+
// the tsserver organize-imports/add-import case is exactly
|
|
207
|
+
// the import-changing one.
|
|
208
|
+
importsChanged: detail.importsChanged ?? true,
|
|
209
|
+
// Equivalence with the direct branch below, which never
|
|
210
|
+
// enqueues a deferred autofix/format pass for an LSP-applied
|
|
211
|
+
// edit (#2450 review round 2, F3).
|
|
212
|
+
deferAutofix: false,
|
|
213
|
+
});
|
|
214
|
+
if (!recorded) {
|
|
215
|
+
context.dbg?.(`lsp mutation bridge dropped ${filePath} (recordMutation() ` +
|
|
216
|
+
"returned false — see the mutation_bridge debug output " +
|
|
217
|
+
"for the reason: malformed entry, out-of-scope path, or " +
|
|
218
|
+
"a bookkeeping error)");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
context.dbg?.(`lsp mutation bridge fallback failed for ${filePath}: ${err}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
const runtime = context.runtime;
|
|
228
|
+
// One mutation seam (#2000 phase 1): bump + receipt + change-log live in
|
|
229
|
+
// RuntimeCoordinator.recordProjectMutation.
|
|
230
|
+
runtime?.recordProjectMutation?.({
|
|
231
|
+
filePath,
|
|
232
|
+
source: context.source,
|
|
233
|
+
cwd: context.cwd,
|
|
234
|
+
changedRange: detail.range,
|
|
235
|
+
onAppendError: (err) => context.dbg?.(`lsp mutation project change append failed for ${filePath}: ${err}`),
|
|
236
|
+
});
|
|
237
|
+
if (context.cacheManager) {
|
|
238
|
+
try {
|
|
239
|
+
context.cacheManager.addModifiedRange(filePath, detail.range ?? { start: 1, end: 1 }, detail.importsChanged ?? true, context.cwd, runtime?.telemetrySessionId, undefined,
|
|
240
|
+
// #2504 review round 2 (F1). #2504 added a containment
|
|
241
|
+
// filter to `addModifiedRange` and gave it `cwd` as the
|
|
242
|
+
// project root. On THIS path `cwd` is the calling
|
|
243
|
+
// directory, which `tools/lsp-navigation.ts` scopes to a
|
|
244
|
+
// sub-package while the LSP client's root spans the whole
|
|
245
|
+
// monorepo — so a server-initiated edit on a sibling
|
|
246
|
+
// package (#2450) and every edit whose context carries a
|
|
247
|
+
// separate bookkeeping cwd (#2479) were silently dropped
|
|
248
|
+
// from the worklist. Same root the `isRecordable` gate a
|
|
249
|
+
// few frames up already uses: `runtime.projectRoot`,
|
|
250
|
+
// falling back to `cwd` when no runtime is threaded.
|
|
251
|
+
runtime?.projectRoot ?? context.cwd);
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
context.dbg?.(`lsp mutation modified-range tracking failed for ${filePath}: ${err}`);
|
|
255
|
+
}
|
|
124
256
|
}
|
|
257
|
+
// #2465: the bridge-fallback branch above gets this for free —
|
|
258
|
+
// `recordMutationThroughSeam` calls `noteMutationHandled` for every
|
|
259
|
+
// entry it takes. The DIRECT branch bypasses the bridge entirely, so
|
|
260
|
+
// it has to say so itself, or the #2430 `agent_settled` sweep finds
|
|
261
|
+
// bytes on disk it has no baseline for and reports every
|
|
262
|
+
// `lsp_navigation` rename as drift no tool call explains. Placed
|
|
263
|
+
// after `addModifiedRange` and OUTSIDE its `try`: the mark is about
|
|
264
|
+
// "pi-lens wrote this file", which is true whether or not the
|
|
265
|
+
// turn-state insert threw.
|
|
266
|
+
noteMutationHandled(filePath);
|
|
125
267
|
}
|
|
268
|
+
// #2450 review round 2 (Partial-deps): its own surface, independent of
|
|
269
|
+
// whether the receipt/turn-state used the direct path or the bridge
|
|
270
|
+
// fallback above — a half-threaded caller (one that provides
|
|
271
|
+
// `recordAutofix` but not `runtime`/`cacheManager`) must not lose its
|
|
272
|
+
// turn-summary publisher just because SOME other surface fell back.
|
|
126
273
|
if (context.recordAutofix && context.source === "autofix") {
|
|
127
274
|
const key = normalizeMapKey(filePath);
|
|
128
|
-
const seen = context.autofixRecordedPaths ?? new
|
|
275
|
+
const seen = context.autofixRecordedPaths ?? new BoundedSet(MAX_SAMPLES);
|
|
129
276
|
context.autofixRecordedPaths = seen;
|
|
130
277
|
if (!seen.has(key)) {
|
|
131
|
-
if (seen.size >= MAX_SAMPLES) {
|
|
132
|
-
const oldest = seen.values().next().value;
|
|
133
|
-
if (oldest)
|
|
134
|
-
seen.delete(oldest);
|
|
135
|
-
}
|
|
136
278
|
seen.add(key);
|
|
137
279
|
context.recordAutofix(filePath);
|
|
138
280
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded worker pool — the repo's one shared `mapWithConcurrency`.
|
|
3
|
+
*
|
|
4
|
+
* Lived in `dependency-checker.ts` (its first caller) and was exported from
|
|
5
|
+
* there for `dispatch/runners/biome-check.ts`. #2504 added a third caller,
|
|
6
|
+
* `runtime-turn.ts`'s bounded test-runner batch — and runtime-turn must not
|
|
7
|
+
* drag an ANALYZER client into its eager import graph for a 15-line helper
|
|
8
|
+
* (that is exactly the eager-bootstrap cost #2467 removed). So the value moved
|
|
9
|
+
* to this zero-dependency leaf and `dependency-checker.ts` re-exports it: every
|
|
10
|
+
* existing importer keeps its specifier, and a consumer that only needs the
|
|
11
|
+
* pool no longer loads madge.
|
|
12
|
+
*
|
|
13
|
+
* Same shape as `ledger-bounds.ts` (#2426) for the degradation ledger's bound.
|
|
14
|
+
*
|
|
15
|
+
* NOT consolidated here: `lsp/client.ts` keeps its own file-local copy on
|
|
16
|
+
* purpose (see its comment) — that is a documented decision, not drift.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Run `mapper` over `items` with at most `concurrency` in flight at once.
|
|
20
|
+
*/
|
|
21
|
+
export async function mapWithConcurrency(items, concurrency, mapper) {
|
|
22
|
+
if (items.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
let nextIndex = 0;
|
|
25
|
+
const workerCount = Math.max(1, Math.min(concurrency, items.length));
|
|
26
|
+
const worker = async () => {
|
|
27
|
+
while (true) {
|
|
28
|
+
const index = nextIndex++;
|
|
29
|
+
if (index >= items.length)
|
|
30
|
+
return;
|
|
31
|
+
await mapper(items[index]);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const workers = Array.from({ length: workerCount }, () => worker());
|
|
35
|
+
await Promise.all(workers);
|
|
36
|
+
}
|
|
@@ -23,7 +23,7 @@ import { PathKeyedMap } from "../path-keyed-map.js";
|
|
|
23
23
|
import { normalizeMapKey } from "../path-utils.js";
|
|
24
24
|
import { loadProjectSnapshot } from "../project-snapshot.js";
|
|
25
25
|
import { buildOrUpdateGraph } from "../review-graph/service.js";
|
|
26
|
-
import { recordDiagnostics } from "../widget-state.js";
|
|
26
|
+
import { classifyDiagnosticTier, recordDiagnostics } from "../widget-state.js";
|
|
27
27
|
import { deserializeWordIndex, removeWordIndexDocumentAsync, scheduleWordIndexPersist, updateWordIndexDocumentForEdit, WORD_INDEX_MAX_BYTES, } from "../word-index.js";
|
|
28
28
|
import { logWordIndex } from "../word-index-logger.js";
|
|
29
29
|
import { createMcpHost } from "./host-shim.js";
|
|
@@ -170,6 +170,28 @@ export function _getWarmWordIndexCacheStateForTests() {
|
|
|
170
170
|
// is the persistent warm server's job (see the `lsp` honesty signal + Tier 2).
|
|
171
171
|
const WARMUP_CLIENT_WAIT_MS = 10_000;
|
|
172
172
|
const WARMUP_DIAGNOSTICS_WAIT_MS = 6_000;
|
|
173
|
+
/** One diagnostic, flattened to the fields an MCP consumer needs. */
|
|
174
|
+
/**
|
|
175
|
+
* Split the dispatch `warnings` bucket into real warnings vs advisories using
|
|
176
|
+
* the ONE severity-projection policy ({@link classifyDiagnosticTier}, #2414/
|
|
177
|
+
* #2417) so the model-facing counts never present a `hint`/`info`-tier finding
|
|
178
|
+
* as a warning (#2420, remainder of #2414). The dispatch `semantic` axis (which
|
|
179
|
+
* also drives blocking) is intentionally NOT consulted or mutated here: this is
|
|
180
|
+
* a display-count split, not a blocking-decision change. `blockers`
|
|
181
|
+
* (`semantic:"blocking"`) are computed upstream and never enter this bucket, so
|
|
182
|
+
* nothing that blocks can stop blocking through this seam. A non-advisory entry
|
|
183
|
+
* in the bucket (an `error`/`warning`-tier finding routed here as
|
|
184
|
+
* `semantic:"warning"`/`"none"`) stays counted as a warning exactly as before,
|
|
185
|
+
* so a mixed file's real warning count is unchanged.
|
|
186
|
+
*/
|
|
187
|
+
export function summarizeWarningTiers(warnings) {
|
|
188
|
+
let advisories = 0;
|
|
189
|
+
for (const w of warnings) {
|
|
190
|
+
if (classifyDiagnosticTier(w) === "advisory")
|
|
191
|
+
advisories++;
|
|
192
|
+
}
|
|
193
|
+
return { warnings: warnings.length - advisories, advisories };
|
|
194
|
+
}
|
|
173
195
|
function toMcpDiagnostic(diagnostic) {
|
|
174
196
|
return {
|
|
175
197
|
line: diagnostic.line,
|
|
@@ -235,7 +257,7 @@ export async function analyzeFile(filePath, cwd, options = {}) {
|
|
|
235
257
|
: path.resolve(cwd, filePath);
|
|
236
258
|
// no-delta by default → a full snapshot every call (not delta-filtered);
|
|
237
259
|
// caller flags win over the default.
|
|
238
|
-
const host = createMcpHost({ "no-delta": true, ...
|
|
260
|
+
const host = createMcpHost({ "no-delta": true, ...options.flags }, cwd);
|
|
239
261
|
if (options.warmLsp !== false) {
|
|
240
262
|
await warmLspForFile(absPath, host);
|
|
241
263
|
}
|
|
@@ -345,7 +367,9 @@ export async function analyzeFile(filePath, cwd, options = {}) {
|
|
|
345
367
|
const lspRunner = latencyReport?.runners.find((runner) => runner.runnerId === "lsp");
|
|
346
368
|
const lsp = lspRunner
|
|
347
369
|
? {
|
|
348
|
-
ran: lspRunner.status !== "skipped" &&
|
|
370
|
+
ran: lspRunner.status !== "skipped" &&
|
|
371
|
+
lspRunner.status !== "when_skipped" &&
|
|
372
|
+
lspRunner.status !== "test_file_skipped",
|
|
349
373
|
status: lspRunner.status,
|
|
350
374
|
diagnosticCount: lspRunner.diagnosticCount,
|
|
351
375
|
durationMs: lspRunner.durationMs,
|
|
@@ -360,7 +384,12 @@ export async function analyzeFile(filePath, cwd, options = {}) {
|
|
|
360
384
|
counts: {
|
|
361
385
|
diagnostics: result.diagnostics.length,
|
|
362
386
|
blockers: result.blockers.length,
|
|
363
|
-
|
|
387
|
+
// #2420: `result.warnings` is the dispatch warnings bucket
|
|
388
|
+
// (`semantic:"warning"|"none"`), which still carries `hint`/`info`-tier
|
|
389
|
+
// findings folded in by the runner's severity→semantic map. Project
|
|
390
|
+
// them out through the shared tier policy so the model sees real
|
|
391
|
+
// warnings and advisories separately.
|
|
392
|
+
...summarizeWarningTiers(result.warnings),
|
|
364
393
|
fixed: result.fixed.length,
|
|
365
394
|
},
|
|
366
395
|
lsp,
|