@herbertgao/pi-extensions 2026.9.0 → 2026.9.1
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/@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 +988 -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 -2
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
- 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 -2
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +1 -3
- package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -0
- 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-telemetry.js +59 -4
- package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +2 -2
- 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 +44 -18
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -2
- 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 +47 -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 +171 -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 +167 -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 +197 -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 -2
- 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-line-freshness.js +12 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -18
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -7
- 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 +380 -26
- 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 +0 -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 +0 -1
- 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 +13 -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 +0 -1
- 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 +0 -1
- 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 +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -1
- 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 -4
- 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/vale.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -3
- 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/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-time.js +6 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +112 -9
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
- package/node_modules/pi-lens/dist/clients/format-service.js +6 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +276 -102
- package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +114 -19
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
- package/node_modules/pi-lens/dist/clients/git-guard.js +1 -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/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 +71 -52
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +104 -230
- package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
- package/node_modules/pi-lens/dist/clients/language-registry.js +595 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +160 -2
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +13 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +141 -30
- package/node_modules/pi-lens/dist/clients/lens-engine.js +30 -37
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +59 -6
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -2
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +168 -30
- package/node_modules/pi-lens/dist/clients/lsp/config.js +483 -158
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +15 -2
- package/node_modules/pi-lens/dist/clients/lsp/index.js +676 -71
- package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -169
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -16
- 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/tsserver-sync.js +9 -2
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.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/middle-man-analysis.js +2 -4
- package/node_modules/pi-lens/dist/clients/module-report.js +20 -45
- 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 -20
- 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 +68 -22
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +4 -0
- 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 +428 -13
- 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 +77 -16
- 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-diagnostics/fresh-fetch.js +4 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +393 -122
- 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 +15 -4
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
- package/node_modules/pi-lens/dist/clients/read-guard.js +21 -0
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +152 -109
- 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 +18 -2
- 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 +139 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +168 -35
- 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 -1
- 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/sessionstart-logger.js +12 -3
- package/node_modules/pi-lens/dist/clients/sgconfig.js +6 -1
- package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- 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 +239 -0
- package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
- package/node_modules/pi-lens/dist/clients/tool-policy.js +91 -21
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +86 -48
- 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/typos-config.js +5 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +6 -2
- package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/word-index-store.js +20 -5
- package/node_modules/pi-lens/dist/clients/word-index.js +243 -31
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +3 -0
- package/node_modules/pi-lens/dist/index.js +64335 -54300
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -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 +95 -24
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +67 -80
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
- package/node_modules/pi-lens/dist/tools/shared.js +0 -1
- 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/language-coverage.md +2 -2
- 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 +27 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +38 -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 +182 -0
- 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/package.json +15 -23
- 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/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/rpc-load-check.mjs +3 -1
- 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 +5 -5
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// The ONE structural replica of pi's own skill-loading walk (#2626 review
|
|
2
|
+
// round 2, F1/F2).
|
|
3
|
+
//
|
|
4
|
+
// Two independent detectors used to answer "does this directory tree hold a
|
|
5
|
+
// skill pi would load" with two DIFFERENT, hand-rolled heuristics that both
|
|
6
|
+
// diverged from pi's real resolver:
|
|
7
|
+
// - `clients/skills-resolver.ts` (a `SKILL.md` one level down only, no
|
|
8
|
+
// recursion, no root `.md` acceptance, no symlink-follow, no dot/
|
|
9
|
+
// node_modules skip)
|
|
10
|
+
// - `scripts/install-selftest.mjs`'s `countSkillFiles` (recursed
|
|
11
|
+
// UNBOUNDED — would double-count a `SKILL.md` sitting inside another
|
|
12
|
+
// skill's own resource subdirectory — with no dot/node_modules skip, no
|
|
13
|
+
// root `.md` acceptance, no symlink handling)
|
|
14
|
+
// Neither matched `loadSkillsFromDirInternal` in
|
|
15
|
+
// `@earendil-works/pi-coding-agent` `dist/core/skills.js` (mirrored by
|
|
16
|
+
// `collectSkillEntries` in `dist/core/package-manager.js`, byte-identical
|
|
17
|
+
// walk, confirmed against the 0.85.1 tarball). This module is the fold: BOTH
|
|
18
|
+
// consumers now derive from `collectSkillEntryPaths` below.
|
|
19
|
+
//
|
|
20
|
+
// Discovery rules, replicated from `loadSkillsFromDirInternal` (verified
|
|
21
|
+
// against the extracted 0.85.1 `skills.js`):
|
|
22
|
+
// 1. If `dir` directly contains a (non-symlink-broken) `SKILL.md`, `dir` IS
|
|
23
|
+
// one skill root — return immediately, do NOT look at `dir`'s other
|
|
24
|
+
// entries or recurse into its subdirectories (a `SKILL.md` inside a
|
|
25
|
+
// skill's own reference/ subfolder is the skill's OWN resource, not a
|
|
26
|
+
// second skill).
|
|
27
|
+
// 2. Otherwise, skip dot-prefixed entries and `node_modules`; recurse into
|
|
28
|
+
// every remaining subdirectory (same two rules, one level down); at the
|
|
29
|
+
// OUTERMOST call only (`isRoot`), a loose `*.md` file directly in `dir`
|
|
30
|
+
// also counts (pi's `includeRootFiles`, true only for the top call).
|
|
31
|
+
// 3. A symlink is followed via `statSync` (broken symlink = skip) for BOTH
|
|
32
|
+
// the `SKILL.md` check and the directory/file classification in step 2.
|
|
33
|
+
//
|
|
34
|
+
// Deliberately NOT replicated (out of #2626's scope — packaging/path
|
|
35
|
+
// resolution, not skill-content validation):
|
|
36
|
+
// - `.gitignore`/`.ignore`/`.fdignore` matching inside the skills tree.
|
|
37
|
+
// - frontmatter parsing: pi additionally requires a non-empty `description`
|
|
38
|
+
// field before a discovered file becomes a loaded skill. A `SKILL.md`
|
|
39
|
+
// file that exists but fails THAT validation is a content-authoring
|
|
40
|
+
// defect a maintainer would see in normal use, not a silent zero.
|
|
41
|
+
// Both gaps mean this predicate can be a bit more OPTIMISTIC than pi's true
|
|
42
|
+
// count in a pathological case (an ignored or description-less file still
|
|
43
|
+
// counts as "found" here); it is never more PESSIMISTIC — every real skill
|
|
44
|
+
// pi loads is found by this walk too — which is the direction #2626 cares
|
|
45
|
+
// about (never claim "no skills" when pi would load one).
|
|
46
|
+
import * as fs from "node:fs";
|
|
47
|
+
import * as path from "node:path";
|
|
48
|
+
/**
|
|
49
|
+
* Symlink-aware entry classification, mirroring `loadSkillsFromDirInternal`'s
|
|
50
|
+
* own `entry.isSymbolicLink() ? statSync(fullPath) : entry`.
|
|
51
|
+
* @param {string} fullPath
|
|
52
|
+
* @param {import("node:fs").Dirent} entry
|
|
53
|
+
* @returns {"file" | "dir" | "other"}
|
|
54
|
+
*/
|
|
55
|
+
export function resolvedEntryKind(fullPath, entry) {
|
|
56
|
+
if (entry.isSymbolicLink()) {
|
|
57
|
+
try {
|
|
58
|
+
const stats = fs.statSync(fullPath);
|
|
59
|
+
if (stats.isDirectory())
|
|
60
|
+
return "dir";
|
|
61
|
+
if (stats.isFile())
|
|
62
|
+
return "file";
|
|
63
|
+
return "other";
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return "other"; // broken symlink
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (entry.isDirectory())
|
|
70
|
+
return "dir";
|
|
71
|
+
if (entry.isFile())
|
|
72
|
+
return "file";
|
|
73
|
+
return "other";
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The structural walk over an ALREADY-READ directory listing — split out
|
|
77
|
+
* from `collectSkillEntryPaths` so a caller that already has `entries` (a
|
|
78
|
+
* top-level ENOENT/EACCES distinction, say) is not forced into a second
|
|
79
|
+
* `readdirSync`.
|
|
80
|
+
* @param {string} dir
|
|
81
|
+
* @param {import("node:fs").Dirent[]} entries
|
|
82
|
+
* @param {boolean} isRoot
|
|
83
|
+
* @returns {string[]} absolute paths of every `SKILL.md` (or, at the root,
|
|
84
|
+
* loose `.md`) file pi's own resolver would treat as a skill entry point.
|
|
85
|
+
*/
|
|
86
|
+
export function scanEntriesForSkills(dir, entries, isRoot) {
|
|
87
|
+
for (const entry of entries) {
|
|
88
|
+
if (entry.name === "SKILL.md" &&
|
|
89
|
+
resolvedEntryKind(path.join(dir, entry.name), entry) === "file") {
|
|
90
|
+
return [path.join(dir, entry.name)];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const found = [];
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const fullPath = path.join(dir, entry.name);
|
|
99
|
+
const kind = resolvedEntryKind(fullPath, entry);
|
|
100
|
+
if (kind === "dir") {
|
|
101
|
+
found.push(...collectSkillEntryPaths(fullPath, false));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (isRoot && kind === "file" && entry.name.endsWith(".md")) {
|
|
105
|
+
found.push(fullPath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return found;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Every skill entry point under `dir`, recursively, per pi's discovery
|
|
112
|
+
* rules. Fail-closed: a `readdirSync` error at `dir` (absent, unreadable) or
|
|
113
|
+
* any recursed-into subdirectory returns `[]` for that branch rather than
|
|
114
|
+
* throwing — matching `loadSkillsFromDirInternal`'s own bare `try { … }
|
|
115
|
+
* catch {}` per directory.
|
|
116
|
+
* @param {string} dir
|
|
117
|
+
* @param {boolean} [isRoot]
|
|
118
|
+
* @returns {string[]}
|
|
119
|
+
*/
|
|
120
|
+
export function collectSkillEntryPaths(dir, isRoot = true) {
|
|
121
|
+
let entries;
|
|
122
|
+
try {
|
|
123
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
return scanEntriesForSkills(dir, entries, isRoot);
|
|
129
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* effective_config pi tool (#2427) — the in-process half of
|
|
3
|
+
* `pilens_effective_config`.
|
|
4
|
+
*
|
|
5
|
+
* A thin wrapper over the `effectiveConfig()` engine seam
|
|
6
|
+
* (`clients/lens-engine.ts`), like `tools/symbol-search.ts` over
|
|
7
|
+
* `symbolSearch()`: the payload is byte-identical to the MCP mirror's because
|
|
8
|
+
* both render the SAME view object, and neither adapter shapes it. The whole
|
|
9
|
+
* reason the capability is an engine method rather than an MCP handler is that
|
|
10
|
+
* a second projection would be a second chance to disagree about which server
|
|
11
|
+
* is running.
|
|
12
|
+
*/
|
|
13
|
+
import { Type } from "../clients/deps/typebox.js";
|
|
14
|
+
import { effectiveConfig, isEffectiveFileViewError, } from "../clients/lens-engine.js";
|
|
15
|
+
import { compactRenderResult } from "./render-compact.js";
|
|
16
|
+
/** One line per decision, for the compact renderer. */
|
|
17
|
+
function summarize(view) {
|
|
18
|
+
const documents = `${view.documents.length} config file(s)`;
|
|
19
|
+
if (!view.file)
|
|
20
|
+
return `effective_config — ${documents}`;
|
|
21
|
+
if (isEffectiveFileViewError(view.file)) {
|
|
22
|
+
return `effective_config — ${documents} · ${view.file.error}`;
|
|
23
|
+
}
|
|
24
|
+
const selected = view.file.servers.filter((entry) => entry.selected).length;
|
|
25
|
+
const denied = view.file.servers.filter((entry) => entry.reason === "disabled-by-config").length;
|
|
26
|
+
const tools = view.file.tools.filter((entry) => entry.selected).length;
|
|
27
|
+
// The denial clause is built first rather than nested inside the summary
|
|
28
|
+
// template: a conditional expression inside a template inside a template is
|
|
29
|
+
// the S3358/nested-template shape SonarCloud flags, and it hid the one
|
|
30
|
+
// number a reader is looking for (#2427 review round 2, F3).
|
|
31
|
+
const deniedClause = denied > 0 ? `, ${denied} denied by config` : "";
|
|
32
|
+
return (`effective_config ${view.file.path} — ${documents} · ` +
|
|
33
|
+
`${selected} server(s) selected${deniedClause} · ` +
|
|
34
|
+
`${tools} tool(s)`);
|
|
35
|
+
}
|
|
36
|
+
export function createEffectiveConfigTool(getProjectRoot) {
|
|
37
|
+
return {
|
|
38
|
+
name: "effective_config",
|
|
39
|
+
label: "Effective Config",
|
|
40
|
+
description: "The resolved pi-lens configuration with the provenance of every decision — which file and tier each setting came from, and the trust decision that applied. Pass `file` to also get, for that path, its language, every LSP server with the reason it was selected or denied (including which tier's config denied it, which a nearer file cannot lift), and the lint/format runners that would dispatch. Answers 'why is X running/selected' without reading logs. Redacted by construction: it reports sources, never values — no env values, no command arguments beyond the binary, and config paths are home-relative.",
|
|
41
|
+
promptSnippet: "Resolved config + provenance — why a server or tool is selected",
|
|
42
|
+
renderResult: compactRenderResult(({ details, isError }) => isError
|
|
43
|
+
? "effective_config — failed"
|
|
44
|
+
: (details?.summary ?? "effective_config")),
|
|
45
|
+
parameters: Type.Object({
|
|
46
|
+
file: Type.Optional(Type.String({
|
|
47
|
+
description: "Path to explain: adds the resolved language plus the per-server and " +
|
|
48
|
+
"per-runner selection decisions for it. Must resolve inside `cwd` " +
|
|
49
|
+
"(a sibling package in the same monorepo does not count) — a file " +
|
|
50
|
+
"outside it is rejected with the `cwd` it was measured against; " +
|
|
51
|
+
"re-query with `cwd` set to that file's own workspace instead.",
|
|
52
|
+
})),
|
|
53
|
+
}),
|
|
54
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
55
|
+
const cwd = getProjectRoot() || ctx.cwd || ".";
|
|
56
|
+
const view = await effectiveConfig({
|
|
57
|
+
cwd,
|
|
58
|
+
...(params.file === undefined ? {} : { file: params.file }),
|
|
59
|
+
redact: true,
|
|
60
|
+
});
|
|
61
|
+
const summary = summarize(view);
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: "text",
|
|
66
|
+
text: `${summary}\n\n${JSON.stringify(view)}`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
// Summary-shaped, like `symbol_search`'s: the full view is already
|
|
70
|
+
// in `content[0].text`, and `details` exists for the renderer.
|
|
71
|
+
// Duplicating a whole provenance dump into it would double the
|
|
72
|
+
// payload of every call for one line of output.
|
|
73
|
+
details: {
|
|
74
|
+
summary,
|
|
75
|
+
documents: view.documents.length,
|
|
76
|
+
provenance: view.provenance.length,
|
|
77
|
+
...(view.file === undefined
|
|
78
|
+
? {}
|
|
79
|
+
: isEffectiveFileViewError(view.file)
|
|
80
|
+
? { fileError: view.file.error }
|
|
81
|
+
: {
|
|
82
|
+
file: view.file.path,
|
|
83
|
+
selectedServers: view.file.servers.filter((entry) => entry.selected).length,
|
|
84
|
+
}),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
import { promises as fs } from "node:fs";
|
|
12
12
|
import * as fsSync from "node:fs";
|
|
13
13
|
import * as path from "node:path";
|
|
14
|
+
import { BoundedLruCache } from "../clients/bounded-cache.js";
|
|
14
15
|
import { Type } from "../clients/deps/typebox.js";
|
|
15
16
|
import { anchorsForDiagnostic, applyDispositions, applyWeakDispositions, hasAnyDispositionMarks, hasStrictDispositionMarks, getDisposition, } from "../clients/diagnostic-dispositions.js";
|
|
17
|
+
import { DEPENDENCY_DRIFT_MAX_DELIVERIES } from "../clients/blocker-freshness.js";
|
|
16
18
|
import { freshnessFromMtime } from "../clients/freshness.js";
|
|
17
19
|
import { applyInlineSuppressions } from "../clients/dispatch/inline-suppressions.js";
|
|
18
20
|
import { gateFindingsByPathFreshness } from "../clients/advisory-provenance.js";
|
|
@@ -34,7 +36,7 @@ import { ANALYZER_IDS, fetchFreshProjectDiagnostics, } from "../clients/project-
|
|
|
34
36
|
import { loadBootstrapClients } from "../clients/bootstrap.js";
|
|
35
37
|
import { generatedSkipNotice, scanTruncationNotice, } from "../clients/lens-engine.js";
|
|
36
38
|
import { scanProjectDiagnostics } from "../clients/project-diagnostics/scanner.js";
|
|
37
|
-
import { getFileDiagnosticSummaries, reconcileCorrelatedScanDiagnostics, reconcileScanDiagnostics, reconcileStaleWidgetDependencyBlockers, reconcileStaleWidgetFiles, widgetDiagnosticUri, } from "../clients/widget-state.js";
|
|
39
|
+
import { classifyDiagnosticTier, getFileDiagnosticSummaries, reconcileCorrelatedScanDiagnostics, reconcileScanDiagnostics, reconcileStaleWidgetDependencyBlockers, reconcileStaleWidgetFiles, widgetDiagnosticUri, } from "../clients/widget-state.js";
|
|
38
40
|
import { logLatency } from "../clients/latency-logger.js";
|
|
39
41
|
import { convertLspDiagnostics } from "../clients/dispatch/utils/lsp-diagnostics.js";
|
|
40
42
|
import { retagAuxiliaryDiagnostics } from "../clients/dispatch/auxiliary-lsp.js";
|
|
@@ -203,9 +205,15 @@ captureLspStatusRepaint, getRuntime) {
|
|
|
203
205
|
const b = details?.totalBlocking ?? 0;
|
|
204
206
|
const e = details?.totalErrors ?? 0;
|
|
205
207
|
const w = details?.totalWarnings ?? 0;
|
|
208
|
+
// #2414: hint/info tier never contributes to `b + e + w` — a session
|
|
209
|
+
// with only style opinions is genuinely "clean" of code defects, but
|
|
210
|
+
// the one-line summary still names the advisory count so it isn't
|
|
211
|
+
// indistinguishable from a session with zero findings at all.
|
|
212
|
+
const adv = details?.totalAdvisories ?? 0;
|
|
206
213
|
const files = details?.filesWithIssues ?? details?.filesChecked ?? 0;
|
|
207
214
|
if (b + e + w === 0) {
|
|
208
|
-
|
|
215
|
+
const advisorySuffix = adv > 0 ? `, ${adv} hint${adv === 1 ? "" : "s"}` : "";
|
|
216
|
+
return `lens_diagnostics ${mode} — clean${advisorySuffix} (${files} files)${coldSuffix}${failedSuffix}`;
|
|
209
217
|
}
|
|
210
218
|
const parts = [`${b} blocking`];
|
|
211
219
|
if (b === 0 && e > 0)
|
|
@@ -417,15 +425,12 @@ function appendProjectDiagnosticsDeltaLines(lines, cwd, report, severity, includ
|
|
|
417
425
|
* TTL. Insertion-ordered LRU cap bounds resident source bytes; repeated
|
|
418
426
|
* queries and multi-file reports that cite the same file reuse one read.
|
|
419
427
|
*/
|
|
420
|
-
const CACHED_CONTENT_MEMO_CAP = 64;
|
|
421
|
-
const cachedContentMemo = new
|
|
428
|
+
export const CACHED_CONTENT_MEMO_CAP = 64;
|
|
429
|
+
const cachedContentMemo = new BoundedLruCache(CACHED_CONTENT_MEMO_CAP);
|
|
422
430
|
function readContentForAnchors(filePath, stat) {
|
|
423
431
|
const key = normalizeEphemeralMapKey(filePath);
|
|
424
432
|
const hit = cachedContentMemo.get(key);
|
|
425
433
|
if (hit && hit.mtimeMs === stat.mtimeMs && hit.size === stat.size) {
|
|
426
|
-
// Refresh LRU position.
|
|
427
|
-
cachedContentMemo.delete(key);
|
|
428
|
-
cachedContentMemo.set(key, hit);
|
|
429
434
|
return hit.content;
|
|
430
435
|
}
|
|
431
436
|
let content;
|
|
@@ -435,11 +440,6 @@ function readContentForAnchors(filePath, stat) {
|
|
|
435
440
|
catch {
|
|
436
441
|
return undefined;
|
|
437
442
|
}
|
|
438
|
-
if (cachedContentMemo.size >= CACHED_CONTENT_MEMO_CAP) {
|
|
439
|
-
const oldest = cachedContentMemo.keys().next().value;
|
|
440
|
-
if (oldest !== undefined)
|
|
441
|
-
cachedContentMemo.delete(oldest);
|
|
442
|
-
}
|
|
443
443
|
cachedContentMemo.set(key, {
|
|
444
444
|
mtimeMs: stat.mtimeMs,
|
|
445
445
|
size: stat.size,
|
|
@@ -447,6 +447,11 @@ function readContentForAnchors(filePath, stat) {
|
|
|
447
447
|
});
|
|
448
448
|
return content;
|
|
449
449
|
}
|
|
450
|
+
/** #2442 test-only: exercise the bounded content memo (LRU) directly,
|
|
451
|
+
* without a full lens_diagnostics dispatch. */
|
|
452
|
+
export function _readContentForAnchorsForTests(filePath, stat) {
|
|
453
|
+
return readContentForAnchors(filePath, stat);
|
|
454
|
+
}
|
|
450
455
|
/**
|
|
451
456
|
* ONE disposition seam for every cache-only lens_diagnostics surface —
|
|
452
457
|
* mode=all summaries, mode=delta's actionable/quality warnings, the delta
|
|
@@ -548,7 +553,35 @@ function loadProjectRulePolicyMap(cwd) {
|
|
|
548
553
|
* `clients/finding-delivery-gate.ts` surface `lens-diagnostics:mode-delta`.
|
|
549
554
|
*/
|
|
550
555
|
function applyDeltaFreshnessGate(files, cwd, generatedAt) {
|
|
551
|
-
|
|
556
|
+
// #2504 review round 4 (F1): an actionable-warnings report is no longer the
|
|
557
|
+
// product of exactly ONE pass. A deferred off-hook LSP pull upserts its
|
|
558
|
+
// per-file entries into whatever report is persisted when it lands, so one
|
|
559
|
+
// report can carry entries observed minutes apart. Judging the older half
|
|
560
|
+
// against the newer report-level stamp would pass an out-of-band edit made
|
|
561
|
+
// in between off as live -- exactly the leak this gate exists to stop. Each
|
|
562
|
+
// distinct stamp is gated on its own; the ordinary single-stamp report
|
|
563
|
+
// takes one pass, as before, and the original file order is preserved.
|
|
564
|
+
const stamps = new Set(files.map((file) => file.generatedAt ?? generatedAt ?? ""));
|
|
565
|
+
if (stamps.size > 1) {
|
|
566
|
+
const gatedByPath = new Map();
|
|
567
|
+
for (const stamp of stamps) {
|
|
568
|
+
const group = files.filter((file) => (file.generatedAt ?? generatedAt ?? "") === stamp);
|
|
569
|
+
for (const gated of applyDeltaFreshnessGate(group.map((file) => ({
|
|
570
|
+
filePath: file.filePath,
|
|
571
|
+
warnings: file.warnings,
|
|
572
|
+
})), cwd, stamp === "" ? undefined : stamp)) {
|
|
573
|
+
gatedByPath.set(gated.filePath, gated);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return files
|
|
577
|
+
.map((file) => gatedByPath.get(file.filePath))
|
|
578
|
+
.filter((entry) => entry !== undefined);
|
|
579
|
+
}
|
|
580
|
+
// Every entry shares one stamp here; prefer the per-entry one when it has
|
|
581
|
+
// it, so a merged report's single surviving half is still aged by its own.
|
|
582
|
+
const stampedAt = [...stamps][0];
|
|
583
|
+
const effectiveAt = stampedAt !== undefined && stampedAt !== "" ? stampedAt : generatedAt;
|
|
584
|
+
if (!effectiveAt)
|
|
552
585
|
return files;
|
|
553
586
|
const flat = [];
|
|
554
587
|
for (const file of files) {
|
|
@@ -561,7 +594,7 @@ function applyDeltaFreshnessGate(files, cwd, generatedAt) {
|
|
|
561
594
|
store: "lens-diagnostics-delta",
|
|
562
595
|
findings: flat,
|
|
563
596
|
cwd,
|
|
564
|
-
scannedAt:
|
|
597
|
+
scannedAt: effectiveAt,
|
|
565
598
|
citedPath: (f) => f.filePath,
|
|
566
599
|
onMissing: "drop",
|
|
567
600
|
});
|
|
@@ -611,6 +644,9 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
|
611
644
|
.filter((file) => includeFile(file.filePath))
|
|
612
645
|
.map((file) => ({
|
|
613
646
|
filePath: file.filePath,
|
|
647
|
+
// #2504 r4 (F1): carried through, so a merged report's older
|
|
648
|
+
// entries keep their own age all the way to the freshness gate.
|
|
649
|
+
generatedAt: file.generatedAt,
|
|
614
650
|
warnings: applyRulePolicy(applyCachedDispositions(file.warnings ?? [], cwd, file.filePath), policyMap),
|
|
615
651
|
}))
|
|
616
652
|
.filter((file) => file.warnings.length > 0);
|
|
@@ -886,6 +922,7 @@ function summarizeDiagnostics(filePath, diagnostics, hasFinalSnapshot) {
|
|
|
886
922
|
let blocking = 0;
|
|
887
923
|
let errors = 0;
|
|
888
924
|
let warnings = 0;
|
|
925
|
+
let advisories = 0;
|
|
889
926
|
for (const diagnostic of diagnostics) {
|
|
890
927
|
// #1641: a demoted past-EOF entry keeps its severity for display but
|
|
891
928
|
// drops out of the tallies — same reasoning as widget-state's `isBlocking`.
|
|
@@ -893,24 +930,28 @@ function summarizeDiagnostics(filePath, diagnostics, hasFinalSnapshot) {
|
|
|
893
930
|
continue;
|
|
894
931
|
if (diagnostic.semantic === "blocking")
|
|
895
932
|
blocking++;
|
|
896
|
-
|
|
933
|
+
// #2414: severity → tier classification is shared with
|
|
934
|
+
// `countDiagnostics`/`countAdvisories` in `clients/widget-state.ts` via
|
|
935
|
+
// `classifyDiagnosticTier` — mode=all reads that store's tally and
|
|
936
|
+
// mode=full reads this one, so the two must agree. `hint`/`info` no
|
|
937
|
+
// longer inflate `warnings` (they used to, matching a pre-#2414
|
|
938
|
+
// `countDiagnostics`, so a hint-only file scored 0/0/0 there too and the
|
|
939
|
+
// `withIssues` filter below dropped it — that gap is now closed via
|
|
940
|
+
// `advisories`, not by re-folding hints into `warnings`).
|
|
941
|
+
const tier = classifyDiagnosticTier(diagnostic);
|
|
942
|
+
if (tier === "error")
|
|
897
943
|
errors++;
|
|
898
|
-
|
|
899
|
-
// `countDiagnostics` in `clients/widget-state.ts` — mode=all reads that
|
|
900
|
-
// tally and mode=full reads this one, so the two must agree. An exact
|
|
901
|
-
// `=== "warning"` test scored a hint-only file 0/0/0, the `withIssues`
|
|
902
|
-
// filter below then dropped it, and mode=full rendered "No issues" for a
|
|
903
|
-
// file whose own `details` still carried the diagnostic.
|
|
904
|
-
else if (diagnostic.severity === "warning" ||
|
|
905
|
-
diagnostic.severity === "hint" ||
|
|
906
|
-
diagnostic.severity === "info")
|
|
944
|
+
else if (tier === "warning")
|
|
907
945
|
warnings++;
|
|
946
|
+
else if (tier === "advisory")
|
|
947
|
+
advisories++;
|
|
908
948
|
}
|
|
909
949
|
return {
|
|
910
950
|
filePath,
|
|
911
951
|
blocking,
|
|
912
952
|
errors,
|
|
913
953
|
warnings,
|
|
954
|
+
advisories,
|
|
914
955
|
hasFinalSnapshot,
|
|
915
956
|
diagnostics,
|
|
916
957
|
};
|
|
@@ -1839,6 +1880,13 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1839
1880
|
}
|
|
1840
1881
|
// @delivery-surface: lens-diagnostics:mode-all
|
|
1841
1882
|
function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(), detailOverrides = { mode: "all" }, staleDropped = 0, pathsScope, dependencyDemoted = 0) {
|
|
1883
|
+
// #2275 review F2: the widget footer stops DRAWING a dependency-drift
|
|
1884
|
+
// demotion once it hits `DEPENDENCY_DRIFT_MAX_DELIVERIES` unconfirmed
|
|
1885
|
+
// deliveries, but the record stays here (dropping it would make an
|
|
1886
|
+
// unconfirmed LSP error read as clean). Say so, through the same note
|
|
1887
|
+
// channel as the demotion itself, so the agent knows why the footer went
|
|
1888
|
+
// quiet and that a re-run can still confirm the finding.
|
|
1889
|
+
const footerCapped = summaries.reduce((n, s) => n + (s.diagnostics ?? []).filter((d) => d.footerRetired === true).length, 0);
|
|
1842
1890
|
// Files changed/deleted since their diagnostics were recorded have already
|
|
1843
1891
|
// been dropped by reconcileStaleWidgetFiles; note them so the agent knows
|
|
1844
1892
|
// those aren't "clean", just un-rescanned (use mode=full to refresh).
|
|
@@ -1847,6 +1895,9 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1847
1895
|
: "") +
|
|
1848
1896
|
(dependencyDemoted > 0
|
|
1849
1897
|
? ` (${dependencyDemoted} blocking finding${dependencyDemoted === 1 ? "" : "s"} demoted to [stale] — an imported file changed since; re-run to confirm)`
|
|
1898
|
+
: "") +
|
|
1899
|
+
(footerCapped > 0
|
|
1900
|
+
? ` (${footerCapped} demoted finding${footerCapped === 1 ? "" : "s"} capped after ${DEPENDENCY_DRIFT_MAX_DELIVERIES} unconfirmed deliveries — no longer shown in the pi-lens footer, still listed here; re-run to confirm)`
|
|
1850
1901
|
: "");
|
|
1851
1902
|
// mode=full already actively scanned exactly the requested paths, so a zero
|
|
1852
1903
|
// result there IS a legitimate clean read — the cache-only note only applies
|
|
@@ -1901,11 +1952,18 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1901
1952
|
const withIssues = visibleSummaries.filter((s) => {
|
|
1902
1953
|
if (severity === "error")
|
|
1903
1954
|
return s.blocking > 0 || s.errors > 0;
|
|
1955
|
+
// #2414: a "warning" filter must not admit hint/info — that is exactly
|
|
1956
|
+
// the "present hints as warnings" defect this issue exists to close.
|
|
1904
1957
|
if (severity === "warning")
|
|
1905
1958
|
return s.warnings > 0;
|
|
1959
|
+
// severity: "all" — a hint/info-only file (`advisories > 0`,
|
|
1960
|
+
// warnings === 0) must still surface here, or the #2414 fix that stops
|
|
1961
|
+
// hints inflating `warnings` would silently drop that file from the
|
|
1962
|
+
// detailed listing instead of just from the compact warning tally.
|
|
1906
1963
|
return (s.blocking > 0 ||
|
|
1907
1964
|
s.errors > 0 ||
|
|
1908
1965
|
s.warnings > 0 ||
|
|
1966
|
+
s.advisories > 0 ||
|
|
1909
1967
|
(s.diagnostics ?? []).some((d) => d.stale));
|
|
1910
1968
|
});
|
|
1911
1969
|
const pathsNote = isFullMode ? "" : pathsScopeCacheOnlyNote(pathsScope);
|
|
@@ -1930,6 +1988,7 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1930
1988
|
let totalBlocking = 0;
|
|
1931
1989
|
let totalErrors = 0;
|
|
1932
1990
|
let totalWarnings = 0;
|
|
1991
|
+
let totalAdvisories = 0;
|
|
1933
1992
|
for (const s of sorted) {
|
|
1934
1993
|
const rel = path.relative(cwd, s.filePath);
|
|
1935
1994
|
const parts = [];
|
|
@@ -1939,6 +1998,11 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1939
1998
|
parts.push(`${s.errors}E`);
|
|
1940
1999
|
if (s.warnings > 0)
|
|
1941
2000
|
parts.push(`${s.warnings}W`);
|
|
2001
|
+
// #2414: hint/info never inflate `warnings`, but a hint-only row still
|
|
2002
|
+
// needs a reason to be listed — otherwise it shows a bare filename with
|
|
2003
|
+
// no count at all.
|
|
2004
|
+
if (s.advisories > 0)
|
|
2005
|
+
parts.push(`${s.advisories} hint${s.advisories === 1 ? "" : "s"}`);
|
|
1942
2006
|
if (!s.hasFinalSnapshot)
|
|
1943
2007
|
parts.push(`(pending)`);
|
|
1944
2008
|
const staleCount = (s.diagnostics ?? []).filter((d) => d.stale).length;
|
|
@@ -1984,6 +2048,7 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1984
2048
|
totalBlocking += s.blocking;
|
|
1985
2049
|
totalErrors += s.errors;
|
|
1986
2050
|
totalWarnings += s.warnings;
|
|
2051
|
+
totalAdvisories += s.advisories;
|
|
1987
2052
|
}
|
|
1988
2053
|
// #1799: `totalBlocking` and `totalErrors` count the same findings UNLESS a
|
|
1989
2054
|
// dependency-drift demotion (#1631) has revoked blocking authority from an
|
|
@@ -2004,6 +2069,11 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
2004
2069
|
totalWarnings > 0
|
|
2005
2070
|
? ` ${totalWarnings} warning${totalWarnings === 1 ? "" : "s"}`
|
|
2006
2071
|
: null,
|
|
2072
|
+
// #2414: reported separately from `warnings` — hint/info are style
|
|
2073
|
+
// opinions, not defects, and must not read as unresolved code issues.
|
|
2074
|
+
totalAdvisories > 0
|
|
2075
|
+
? ` ${totalAdvisories} hint/info (style — not counted as warnings)`
|
|
2076
|
+
: null,
|
|
2007
2077
|
]
|
|
2008
2078
|
.filter(Boolean)
|
|
2009
2079
|
.join("\n");
|
|
@@ -2017,6 +2087,7 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
2017
2087
|
totalBlocking,
|
|
2018
2088
|
totalErrors,
|
|
2019
2089
|
totalWarnings,
|
|
2090
|
+
totalAdvisories,
|
|
2020
2091
|
staleDropped,
|
|
2021
2092
|
},
|
|
2022
2093
|
};
|