@herbertgao/pi-extensions 2026.8.4 → 2026.8.5
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/README.md +4 -4
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +8 -7
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
- package/node_modules/pi-lens/CHANGELOG.md +2440 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
- package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
- package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
- package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +49361 -36888
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +211 -44
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/docs/agent-guide.md +2 -2
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +31 -2
- package/node_modules/pi-lens/docs/globalconfig.md +45 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +12 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +18 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
- package/node_modules/pi-mcp-adapter/README.md +34 -3
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +3 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +93 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/package.json +11 -12
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -14,17 +14,21 @@ import * as path from "node:path";
|
|
|
14
14
|
import { Type } from "../clients/deps/typebox.js";
|
|
15
15
|
import { anchorsForDiagnostic, applyDispositions, applyWeakDispositions, getDisposition, } from "../clients/diagnostic-dispositions.js";
|
|
16
16
|
import { applyInlineSuppressions } from "../clients/dispatch/inline-suppressions.js";
|
|
17
|
+
import { normalizeRuleId } from "../clients/dispatch/rule-id-normalize.js";
|
|
18
|
+
import { applyRulePolicy, rulePolicyMapFromConfig } from "../clients/dispatch/rule-policy.js";
|
|
19
|
+
import { loadPiLensProjectConfig } from "../clients/project-lens-config.js";
|
|
17
20
|
import { compactRenderResult } from "./render-compact.js";
|
|
18
21
|
import { combineAbortSignals } from "../clients/deadline-utils.js";
|
|
19
22
|
import { getProjectIgnoreMatcher } from "../clients/file-utils.js";
|
|
20
23
|
import { isAtOrAboveHomeDir, normalizeFilePath, } from "../clients/path-utils.js";
|
|
21
24
|
import { getLSPService } from "../clients/lsp/index.js";
|
|
22
25
|
import { primaryServerId } from "../clients/lsp/config.js";
|
|
26
|
+
import { hashDiagnosticContent, } from "../clients/lsp/diagnostic-binding.js";
|
|
23
27
|
import { loadProjectDiagnosticsDeltaReport, loadProjectDiagnosticsSnapshot, PROJECT_DIAGNOSTICS_CACHE_VERSION, reconcileProjectDiagnosticsSnapshot, } from "../clients/project-diagnostics/cache.js";
|
|
24
28
|
import { warmTriggerFor } from "../clients/project-diagnostics/extractors.js";
|
|
25
29
|
import { fetchFreshProjectDiagnostics } from "../clients/project-diagnostics/fresh-fetch.js";
|
|
26
30
|
import { loadBootstrapClients } from "../clients/bootstrap.js";
|
|
27
|
-
import { scanTruncationNotice } from "../clients/lens-engine.js";
|
|
31
|
+
import { generatedSkipNotice, scanTruncationNotice, } from "../clients/lens-engine.js";
|
|
28
32
|
import { scanProjectDiagnostics } from "../clients/project-diagnostics/scanner.js";
|
|
29
33
|
import { getFileDiagnosticSummaries, reconcileScanDiagnostics, reconcileStaleWidgetFiles, } from "../clients/widget-state.js";
|
|
30
34
|
import { convertLspDiagnostics } from "../clients/dispatch/utils/lsp-diagnostics.js";
|
|
@@ -50,6 +54,48 @@ const FULL_SCAN_WALL_CLOCK_MS = (() => {
|
|
|
50
54
|
const raw = Number(process.env.PI_LENS_LENS_DIAGNOSTICS_FULL_TIMEOUT_MS);
|
|
51
55
|
return Number.isFinite(raw) && raw > 0 ? raw : 300_000; // 5 min default
|
|
52
56
|
})();
|
|
57
|
+
// Binding verification is a fallback for result producers that supplied a
|
|
58
|
+
// content hash without an already-computed disk verdict. Keep it one-file-at-a-
|
|
59
|
+
// time and yield periodically: a full scan can contain thousands of results,
|
|
60
|
+
// and a synchronous read loop here would freeze the host even though the LSP
|
|
61
|
+
// work itself was asynchronous (#1198 follow-up).
|
|
62
|
+
const FULL_SCAN_BINDING_YIELD_EVERY = 16;
|
|
63
|
+
async function findFullScanBindingMismatches(results) {
|
|
64
|
+
const mismatched = new WeakSet();
|
|
65
|
+
let sinceYield = 0;
|
|
66
|
+
for (const result of results) {
|
|
67
|
+
if (result.boundToCurrentDisk === false) {
|
|
68
|
+
mismatched.add(result);
|
|
69
|
+
}
|
|
70
|
+
else if (
|
|
71
|
+
// A `true` verdict came from the LSP/cache binding seam and has already
|
|
72
|
+
// compared its fingerprint with disk. Only legacy/partial producers need
|
|
73
|
+
// this fallback read; `unknown` remains unknown when no hash exists.
|
|
74
|
+
result.boundToCurrentDisk !== true &&
|
|
75
|
+
result.contentHash !== undefined) {
|
|
76
|
+
try {
|
|
77
|
+
// Promise-based, sequential reads bound both event-loop occupancy and
|
|
78
|
+
// outstanding file handles. A read failure deliberately leaves the
|
|
79
|
+
// verdict unknown (the historical fail-open behavior).
|
|
80
|
+
const content = await fs.readFile(result.filePath, "utf-8");
|
|
81
|
+
if (hashDiagnosticContent(content) !== result.contentHash) {
|
|
82
|
+
mismatched.add(result);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Unreadable/deleted files cannot disprove the binding. Leave them
|
|
87
|
+
// unknown for the existing caller policy, rather than manufacturing a
|
|
88
|
+
// mismatch or a clean verdict here.
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
sinceYield += 1;
|
|
92
|
+
if (sinceYield >= FULL_SCAN_BINDING_YIELD_EVERY) {
|
|
93
|
+
sinceYield = 0;
|
|
94
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return mismatched;
|
|
98
|
+
}
|
|
53
99
|
export function createLensDiagnosticsTool(cacheManager, getCwd, getLspService = getLSPService,
|
|
54
100
|
// Flush any debounced per-edit dispatches before reading, so files the agent
|
|
55
101
|
// fixed earlier in the turn are re-dispatched and the widget reflects the
|
|
@@ -156,6 +202,9 @@ captureLspStatusRepaint) {
|
|
|
156
202
|
maxLspFiles: Type.Optional(Type.Number({
|
|
157
203
|
description: "mode=full only: cap the number of files routed through the language server for the project-wide LSP sweep. On large projects (e.g. a Next.js app with thousands of source files) the uncapped sweep can take many minutes; set this to bound it. Default is generous (env PI_LENS_LSP_WORKSPACE_MAX_FILES, else 5000).",
|
|
158
204
|
})),
|
|
205
|
+
includeGenerated: Type.Optional(Type.Boolean({
|
|
206
|
+
description: "mode=full refreshRunners=cheap/all only (no effect with refreshRunners=cached/none, since no project scan runs to apply it to): scan WITHOUT the generated/artifact NAME-heuristic filter (lockfiles, gen.ts-style names, generated/ dirs, …). Default false. Use when a scan's 'excluded by generated-name heuristics' notice suggests a real file was skipped.",
|
|
207
|
+
})),
|
|
159
208
|
severity: Type.Optional(Type.String({
|
|
160
209
|
enum: ["error", "warning", "all"],
|
|
161
210
|
description: "Filter by severity (default: all).",
|
|
@@ -192,6 +241,7 @@ captureLspStatusRepaint) {
|
|
|
192
241
|
: undefined;
|
|
193
242
|
const maxProjectFiles = parsePositiveInt(params.maxProjectFiles);
|
|
194
243
|
const maxLspFiles = parsePositiveInt(params.maxLspFiles);
|
|
244
|
+
const includeGenerated = params.includeGenerated === true;
|
|
195
245
|
const cwd = ctx.cwd ?? getCwd();
|
|
196
246
|
let pathsScope;
|
|
197
247
|
try {
|
|
@@ -236,6 +286,7 @@ captureLspStatusRepaint) {
|
|
|
236
286
|
refreshRunners,
|
|
237
287
|
maxProjectFiles,
|
|
238
288
|
maxLspFiles,
|
|
289
|
+
includeGenerated,
|
|
239
290
|
signal: fullSignal,
|
|
240
291
|
wallClockMs: FULL_SCAN_WALL_CLOCK_MS,
|
|
241
292
|
onProgress,
|
|
@@ -281,23 +332,46 @@ function appendProjectDiagnosticsDeltaLines(lines, cwd, report, severity, includ
|
|
|
281
332
|
* delta mode re-serves them. Anchored via `projectDiagnosticToWidget` so the
|
|
282
333
|
* (tool, rule) an agent's mark binds to matches mode=full's own project-runner
|
|
283
334
|
* filter (`applyInlineSuppressionsToSummaries`), keeping the two paths in
|
|
284
|
-
* agreement. Weak-anchored → no file read.
|
|
335
|
+
* agreement. Weak-anchored → no file read. Also applies the project's
|
|
336
|
+
* `.pi-lens.json` `rules.<id>.disable`/`select` policy so a project's policy
|
|
337
|
+
* overlays the same delta report cache; the cache is otherwise insensitive to
|
|
338
|
+
* a project-config edit (the per-edit path picks it up immediately, but a
|
|
339
|
+
* non-dispatch tool query would replay the pre-edit state).
|
|
285
340
|
*/
|
|
286
|
-
function filterDeltaReportDispositions(report, cwd) {
|
|
341
|
+
function filterDeltaReportDispositions(report, cwd, policyMap) {
|
|
287
342
|
if (!report?.diagnostics.length)
|
|
288
343
|
return report;
|
|
289
344
|
const kept = report.diagnostics.filter((d) => applyWeakDispositions([projectDiagnosticToWidget(d)], cwd, d.filePath)
|
|
290
345
|
.length === 1);
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
346
|
+
const policyKept = applyRulePolicy(kept, policyMap);
|
|
347
|
+
if (policyKept.length === report.diagnostics.length)
|
|
348
|
+
return report;
|
|
349
|
+
return { ...report, diagnostics: policyKept };
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Load the rule-policy map from a project's `.pi-lens.json` — same source the
|
|
353
|
+
* per-edit dispatch path uses, so a project's policy applies consistently
|
|
354
|
+
* across every output surface. `loadPiLensProjectConfig` is mtime-cached, and
|
|
355
|
+
* the map is filtered to entries that actually have a `disable`/`select` list
|
|
356
|
+
* (thresholds are handled elsewhere), so the common case returns undefined and
|
|
357
|
+
* the filter step is skipped outright.
|
|
358
|
+
*/
|
|
359
|
+
function loadProjectRulePolicyMap(cwd) {
|
|
360
|
+
return rulePolicyMapFromConfig(loadPiLensProjectConfig(cwd).rules);
|
|
294
361
|
}
|
|
295
362
|
function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
296
363
|
const actionableEntry = cacheManager.readCache("actionable-warnings", cwd);
|
|
297
364
|
const qualityEntry = cacheManager.readCache("code-quality-warnings", cwd);
|
|
298
365
|
const actionable = actionableEntry?.data;
|
|
299
366
|
const quality = qualityEntry?.data;
|
|
300
|
-
|
|
367
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable` /
|
|
368
|
+
// `rules.<id>.select`) — output-only filtering applied consistently across
|
|
369
|
+
// every mode. The cache-only delta/all paths would otherwise leak project-
|
|
370
|
+
// policy oversight (the per-edit dispatch already filters, but the cache
|
|
371
|
+
// snapshots predate the user's project config edit and would replay
|
|
372
|
+
// filtered findings). Weak-anchored like weak disposition — zero I/O.
|
|
373
|
+
const policyMap = loadProjectRulePolicyMap(cwd);
|
|
374
|
+
const projectDelta = filterDeltaReportDispositions(loadProjectDiagnosticsDeltaReport(cwd), cwd, policyMap);
|
|
301
375
|
const ignoreFile = createCurrentIgnoreFilter(cwd);
|
|
302
376
|
const includeFile = (filePath) => ignoreFile(filePath) && (!pathsScope || pathsScope.includeFile(filePath));
|
|
303
377
|
// #755: delta re-serves the actionable/quality caches verbatim, but those
|
|
@@ -305,20 +379,15 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
|
305
379
|
// the weak disposition filter (suppress/defer) here so a mark converges
|
|
306
380
|
// immediately, not only on the next edit. Weak-anchored → zero file I/O, so
|
|
307
381
|
// this stays "instant" (see applyWeakDispositions).
|
|
308
|
-
const
|
|
382
|
+
const visibleWarningFiles = (files) => (files ?? [])
|
|
309
383
|
.filter((file) => includeFile(file.filePath))
|
|
310
384
|
.map((file) => ({
|
|
311
385
|
filePath: file.filePath,
|
|
312
|
-
warnings: applyWeakDispositions(file.warnings ?? [], cwd, file.filePath),
|
|
313
|
-
}))
|
|
314
|
-
.filter((file) => file.warnings.length > 0);
|
|
315
|
-
const qualityFiles = (quality?.files ?? [])
|
|
316
|
-
.filter((file) => includeFile(file.filePath))
|
|
317
|
-
.map((file) => ({
|
|
318
|
-
filePath: file.filePath,
|
|
319
|
-
warnings: applyWeakDispositions(file.warnings ?? [], cwd, file.filePath),
|
|
386
|
+
warnings: applyRulePolicy(applyWeakDispositions(file.warnings ?? [], cwd, file.filePath), policyMap),
|
|
320
387
|
}))
|
|
321
388
|
.filter((file) => file.warnings.length > 0);
|
|
389
|
+
const actionableFiles = visibleWarningFiles(actionable?.files);
|
|
390
|
+
const qualityFiles = visibleWarningFiles(quality?.files);
|
|
322
391
|
const lines = [];
|
|
323
392
|
// Fixable warnings from actionable-warnings
|
|
324
393
|
if (severity !== "error") {
|
|
@@ -353,7 +422,7 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
|
353
422
|
.filter((f) => includeFile(f.filePath))
|
|
354
423
|
.map((f) => ({
|
|
355
424
|
...f,
|
|
356
|
-
diagnostics: applyWeakDispositions(f.diagnostics, cwd, f.filePath),
|
|
425
|
+
diagnostics: applyRulePolicy(applyWeakDispositions(f.diagnostics, cwd, f.filePath), policyMap),
|
|
357
426
|
}))
|
|
358
427
|
.filter((f) => f.diagnostics.length > 0);
|
|
359
428
|
const carriedIssues = carried.reduce((n, f) => n + f.diagnostics.length, 0);
|
|
@@ -484,6 +553,20 @@ function filterProjectDiagnosticsDeltaReport(report, includeFile) {
|
|
|
484
553
|
diagnostics: report.diagnostics.filter((d) => includeFile(d.filePath)),
|
|
485
554
|
};
|
|
486
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* Apply the project rule policy to a project-diagnostics snapshot/delta
|
|
558
|
+
* report's `diagnostics` list, in place of the collection's shape. Used by
|
|
559
|
+
* `formatFullMode` so `projectSnapshot.diagnostics.length` /
|
|
560
|
+
* `projectDelta.diagnostics.length` — which feed both the merged summaries
|
|
561
|
+
* and the `details.projectDiagnostics`/`details.projectDiagnosticsDelta`
|
|
562
|
+
* counts — already reflect the policy instead of reporting a pre-policy
|
|
563
|
+
* count that disagrees with the rendered text.
|
|
564
|
+
*/
|
|
565
|
+
function applyProjectRulePolicy(value, policyMap) {
|
|
566
|
+
if (!value)
|
|
567
|
+
return undefined;
|
|
568
|
+
return { ...value, diagnostics: applyRulePolicy(value.diagnostics, policyMap) };
|
|
569
|
+
}
|
|
487
570
|
/** A diagnostic counts as error-like when it blocks or has error severity. */
|
|
488
571
|
function isErrorLike(d) {
|
|
489
572
|
return d.semantic === "blocking" || d.severity === "error";
|
|
@@ -553,12 +636,12 @@ function projectDiagnosticToWidget(diagnostic) {
|
|
|
553
636
|
// violation must collapse to one finding in mode=full's merge regardless of which
|
|
554
637
|
// engine produced it. Strip the `ast-grep:` source prefix and the `-js` language
|
|
555
638
|
// suffix (the napi runner already treats `<id>` / `<id>-js` as one rule) so the
|
|
556
|
-
// LSP sweep and the napi scan don't double-report the same line.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
639
|
+
// LSP sweep and the napi scan don't double-report the same line. The
|
|
640
|
+
// normalization itself now lives in `clients/dispatch/rule-id-normalize.ts` so the
|
|
641
|
+
// inline suppression parser, the project rule-policy matcher, and dedup all apply
|
|
642
|
+
// the same canonical form.
|
|
560
643
|
function diagnosticDedupKey(filePath, diagnostic) {
|
|
561
|
-
const ruleId =
|
|
644
|
+
const ruleId = normalizeRuleId(diagnostic.rule ?? diagnostic.tool ?? "");
|
|
562
645
|
return [path.resolve(filePath), diagnostic.line ?? "?", ruleId].join(":");
|
|
563
646
|
}
|
|
564
647
|
function summarizeDiagnostics(filePath, diagnostics, hasFinalSnapshot) {
|
|
@@ -701,8 +784,14 @@ function mergeDiagnosticsWithWidgetSummaries(widgetSummaries, lspResults, projec
|
|
|
701
784
|
* a read failure is fail-safe (keep the diagnostics rather than hide a finding on
|
|
702
785
|
* an I/O error). Re-summarizes so the blocking/error/warning counts reflect the
|
|
703
786
|
* suppression.
|
|
787
|
+
*
|
|
788
|
+
* Also applies the project's `.pi-lens.json` `rules.<id>.disable`/`select`
|
|
789
|
+
* policy AFTER inline suppression / disposition so the same set of findings
|
|
790
|
+
* the per-edit `dispatcher.ts` filters is what's rendered here. The policy
|
|
791
|
+
* map is passed in (computed once per `formatFullMode` call) rather than
|
|
792
|
+
* re-deriving per file — see `loadProjectRulePolicyMap(cwd)`.
|
|
704
793
|
*/
|
|
705
|
-
async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
794
|
+
async function applyInlineSuppressionsToSummaries(summaries, cwd, policyMap) {
|
|
706
795
|
return Promise.all(summaries.map(async (summary) => {
|
|
707
796
|
if (!summary.diagnostics.length)
|
|
708
797
|
return summary;
|
|
@@ -711,7 +800,13 @@ async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
|
711
800
|
content = await fs.readFile(summary.filePath, "utf8");
|
|
712
801
|
}
|
|
713
802
|
catch {
|
|
714
|
-
|
|
803
|
+
// Inline suppression/disposition remains fail-open when the file cannot
|
|
804
|
+
// be read, but project policy does not depend on content and must still
|
|
805
|
+
// be applied so a fresh full-mode result cannot bypass `disable`/`select`.
|
|
806
|
+
const policyKept = applyRulePolicy(summary.diagnostics, policyMap);
|
|
807
|
+
return policyKept.length === summary.diagnostics.length
|
|
808
|
+
? summary
|
|
809
|
+
: summarizeDiagnostics(summary.filePath, policyKept, summary.hasFinalSnapshot);
|
|
715
810
|
}
|
|
716
811
|
const inlineKept = applyInlineSuppressions(summary.diagnostics, content);
|
|
717
812
|
// #690: same false-positive/suppress/defer disposition filter the
|
|
@@ -719,11 +814,16 @@ async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
|
719
814
|
// diagnostics from a fresh LSP sweep/project scan that never went
|
|
720
815
|
// through that path, so without this a disposed finding reappears here.
|
|
721
816
|
const kept = applyDispositions(inlineKept, cwd, summary.filePath, content);
|
|
817
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`).
|
|
818
|
+
// Applied after inline suppression / disposition so the policy's
|
|
819
|
+
// output-only filtering affects the same surface the per-edit path
|
|
820
|
+
// produces (no double-counting, no leftover policy-rejected findings).
|
|
821
|
+
const policyKept = applyRulePolicy(kept, policyMap);
|
|
722
822
|
// Tag `flagged` diagnostics for the render loop (formatAllMode). Content
|
|
723
823
|
// is already in hand here (unlike mode=all/delta's cache-only path), so
|
|
724
824
|
// this is the one place the tag can be computed without adding I/O to
|
|
725
825
|
// the "instant" modes.
|
|
726
|
-
for (const d of
|
|
826
|
+
for (const d of policyKept) {
|
|
727
827
|
// flagged is weak-anchored (module doc, diagnostic-dispositions.ts) so
|
|
728
828
|
// the tag survives incidental edits to the flagged line itself.
|
|
729
829
|
const { weak } = anchorsForDiagnostic(cwd, summary.filePath, d, content);
|
|
@@ -731,9 +831,9 @@ async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
|
731
831
|
d.flagged = true;
|
|
732
832
|
}
|
|
733
833
|
}
|
|
734
|
-
if (
|
|
834
|
+
if (policyKept.length === summary.diagnostics.length)
|
|
735
835
|
return summary;
|
|
736
|
-
return summarizeDiagnostics(summary.filePath,
|
|
836
|
+
return summarizeDiagnostics(summary.filePath, policyKept, summary.hasFinalSnapshot);
|
|
737
837
|
}));
|
|
738
838
|
}
|
|
739
839
|
function shouldUseCachedProjectDiagnostics(value) {
|
|
@@ -781,6 +881,7 @@ async function getProjectDiagnosticsSnapshotForFullMode(cwd, options) {
|
|
|
781
881
|
maxFiles: options.maxProjectFiles,
|
|
782
882
|
signal: options.signal,
|
|
783
883
|
files: options.files,
|
|
884
|
+
includeGenerated: options.includeGenerated,
|
|
784
885
|
});
|
|
785
886
|
}
|
|
786
887
|
if (shouldUseCachedProjectDiagnostics(options.refreshRunners)) {
|
|
@@ -848,6 +949,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
848
949
|
signal,
|
|
849
950
|
onProgress: options.onProgress,
|
|
850
951
|
onServerReady: options.onServerReady,
|
|
952
|
+
nextWriteIndex: options.nextWriteIndex,
|
|
851
953
|
files: explicitFiles,
|
|
852
954
|
}),
|
|
853
955
|
getProjectDiagnosticsSnapshotForFullMode(cwd, {
|
|
@@ -858,6 +960,12 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
858
960
|
]);
|
|
859
961
|
const aborted = signal?.aborted ?? false;
|
|
860
962
|
const lspResults = rawLspResults.filter((result) => includeFile(result.filePath));
|
|
963
|
+
// A result bound to a different document must not replace the current
|
|
964
|
+
// widget state, even when it contains real diagnostics. Pull results may carry
|
|
965
|
+
// a content hash without the push binding verdict, so verify that hash against
|
|
966
|
+
// disk through the bounded async fallback above; unreadable files remain
|
|
967
|
+
// unknown and retain the existing fail-open policy.
|
|
968
|
+
const mismatchedLspResults = await findFullScanBindingMismatches(lspResults);
|
|
861
969
|
// #630: `timedOut`/`error` means the per-file check never actually
|
|
862
970
|
// completed or was inconclusive (#570's `touchFile().inconclusive`, or
|
|
863
971
|
// this sweep's own outer per-file deadline/throw — see
|
|
@@ -869,8 +977,12 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
869
977
|
// the unfiltered `lspResults` in, so a timed-out file's placeholder `[]`
|
|
870
978
|
// read as "0 diagnostics" — false-clean — in the rendered/`details`
|
|
871
979
|
// output (#630).
|
|
872
|
-
const confirmedLspResults = lspResults.filter((result) => !result.timedOut &&
|
|
873
|
-
|
|
980
|
+
const confirmedLspResults = lspResults.filter((result) => !result.timedOut &&
|
|
981
|
+
!result.error &&
|
|
982
|
+
!mismatchedLspResults.has(result));
|
|
983
|
+
const unconfirmedLspResults = lspResults.filter((result) => result.timedOut ||
|
|
984
|
+
result.error ||
|
|
985
|
+
mismatchedLspResults.has(result));
|
|
874
986
|
// #571: reconcile this scan's fresh, CONFIRMED per-file results into the
|
|
875
987
|
// footer cache. A footer write is never allowed to fail the tool call, so
|
|
876
988
|
// any unexpected throw is swallowed.
|
|
@@ -891,12 +1003,33 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
891
1003
|
// (`applyAuxiliarySuppressions`), so an empty content string here is a
|
|
892
1004
|
// safe no-op re-check rather than a behavior gap.
|
|
893
1005
|
const retagged = retagAuxiliaryDiagnostics(diagnostics, result.diagnostics, "", { cwd, fileRole: detectFileRole(result.filePath) });
|
|
894
|
-
reconcileScanDiagnostics(result.filePath, retagged, true,
|
|
1006
|
+
reconcileScanDiagnostics(result.filePath, retagged, true,
|
|
1007
|
+
// The service reserves this token when the file enters the scan. The
|
|
1008
|
+
// fallback preserves compatibility with older test doubles/services.
|
|
1009
|
+
result.writeIndex ?? nextWriteIndex?.(),
|
|
1010
|
+
// #1093: `observedAt` is set only when this result was served from
|
|
1011
|
+
// the workspace-diagnostics cache (a replay of an older scan) —
|
|
1012
|
+
// stamp `touchedAt` with when it was scanned, not now(), so a
|
|
1013
|
+
// mode=full that only re-serves the cache can't keep a resolved
|
|
1014
|
+
// finding on screen by re-arming the mtime gate. Undefined for
|
|
1015
|
+
// freshly-touched results (observed now).
|
|
1016
|
+
result.observedAt);
|
|
895
1017
|
}
|
|
896
1018
|
catch {
|
|
897
1019
|
// Never let a footer-reconciliation hiccup fail the scan itself.
|
|
898
1020
|
}
|
|
899
1021
|
}
|
|
1022
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`) —
|
|
1023
|
+
// loaded once per mode=full call, BEFORE `projectSnapshot`/`projectDelta`
|
|
1024
|
+
// are built below, so `.diagnostics.length` on both (which feeds
|
|
1025
|
+
// `details.projectDiagnostics`/`details.projectDiagnosticsDelta` as well
|
|
1026
|
+
// as the merge into `summaries`) is the POST-policy count. Threaded into
|
|
1027
|
+
// `applyInlineSuppressionsToSummaries` too (idempotent re-apply there) so
|
|
1028
|
+
// the merged summaries honor the same policy the per-edit dispatch path
|
|
1029
|
+
// applies. A project config read failure is treated as "no policy"
|
|
1030
|
+
// (defensive, matches the `applyInlineSuppressionsToSummaries` read-error
|
|
1031
|
+
// discipline).
|
|
1032
|
+
const policyMap = loadProjectRulePolicyMap(cwd);
|
|
900
1033
|
const scannedSnapshot = filterProjectDiagnosticsSnapshot(rawProjectSnapshot, includeFile);
|
|
901
1034
|
// Heavyweight-analyzer findings (jscpd, madge, gitleaks, knip, govulncheck,
|
|
902
1035
|
// trivy, dead-code) — a FRESH run of each (#585), not a cache-only read:
|
|
@@ -911,14 +1044,14 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
911
1044
|
// computed above, in the SAME `Promise.all` as the LSP sweep (#613) — only
|
|
912
1045
|
// when the caller opted into project-runner state (otherwise it's the
|
|
913
1046
|
// `Promise.resolve({...})` stub from `analyzersPromise` above).
|
|
914
|
-
const projectSnapshot = foldExtraDiagnosticsIntoSnapshot(scannedSnapshot, extracted.diagnostics.filter((d) => includeFile(d.filePath)), extracted.runners, cwd);
|
|
915
|
-
const projectDelta = filterProjectDiagnosticsDeltaReport(loadProjectDiagnosticsDeltaReport(cwd), includeFile);
|
|
1047
|
+
const projectSnapshot = applyProjectRulePolicy(foldExtraDiagnosticsIntoSnapshot(scannedSnapshot, extracted.diagnostics.filter((d) => includeFile(d.filePath)), extracted.runners, cwd), policyMap);
|
|
1048
|
+
const projectDelta = applyProjectRulePolicy(filterProjectDiagnosticsDeltaReport(loadProjectDiagnosticsDeltaReport(cwd), includeFile), policyMap);
|
|
916
1049
|
// #630: only the CONFIRMED LSP results contribute diagnostics to the merge
|
|
917
1050
|
// — an unconfirmed (timed-out/errored) file's placeholder `[]` must not be
|
|
918
1051
|
// read as "0 issues, clean" via its LSP contribution. It can still
|
|
919
1052
|
// legitimately show diagnostics from widgetSummaries/project-runner state
|
|
920
1053
|
// below if those independently have entries for it.
|
|
921
|
-
const summaries = await applyInlineSuppressionsToSummaries(mergeDiagnosticsWithWidgetSummaries(getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath)), confirmedLspResults, projectSnapshot, projectDelta), cwd);
|
|
1054
|
+
const summaries = await applyInlineSuppressionsToSummaries(mergeDiagnosticsWithWidgetSummaries(getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath)), confirmedLspResults, projectSnapshot, projectDelta), cwd, policyMap);
|
|
922
1055
|
const result = formatAllMode(cwd, severity, summaries, {
|
|
923
1056
|
mode: "full",
|
|
924
1057
|
lspFilesChecked: rawLspResults.length,
|
|
@@ -1057,6 +1190,14 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1057
1190
|
const scanTruncatedNote = scanTruncatedNoticeText
|
|
1058
1191
|
? `\n\n${scanTruncatedNoticeText}`
|
|
1059
1192
|
: "";
|
|
1193
|
+
// #1107 phase 2: same "reached the seam, nothing rendered it" gap as #784
|
|
1194
|
+
// above, for the generated-name/dir skip counters.
|
|
1195
|
+
const generatedSkipNoticeText = projectSnapshot
|
|
1196
|
+
? generatedSkipNotice(projectSnapshot)
|
|
1197
|
+
: undefined;
|
|
1198
|
+
const generatedSkipNote = generatedSkipNoticeText
|
|
1199
|
+
? `\n\n${generatedSkipNoticeText}`
|
|
1200
|
+
: "";
|
|
1060
1201
|
const abortedNote = abortedIds.size > 0
|
|
1061
1202
|
? `\n\nstopped mid-scan (still running in the background, not reflected in this result): ${[
|
|
1062
1203
|
...abortedIds,
|
|
@@ -1110,6 +1251,19 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1110
1251
|
// #784: lets a caller check "was the cheap project scan truncated"
|
|
1111
1252
|
// without parsing the text note.
|
|
1112
1253
|
projectScanTruncated: projectSnapshot?.scanTruncated ?? false,
|
|
1254
|
+
// #1107 phase 2: same machine-readable convention, for the
|
|
1255
|
+
// generated-name/dir skip counters.
|
|
1256
|
+
...(projectSnapshot?.generatedFileSkips
|
|
1257
|
+
? { projectGeneratedFileSkips: projectSnapshot.generatedFileSkips }
|
|
1258
|
+
: {}),
|
|
1259
|
+
...(projectSnapshot?.generatedNameOnlySkips
|
|
1260
|
+
? {
|
|
1261
|
+
projectGeneratedNameOnlySkips: projectSnapshot.generatedNameOnlySkips,
|
|
1262
|
+
}
|
|
1263
|
+
: {}),
|
|
1264
|
+
...(projectSnapshot?.generatedDirSkips
|
|
1265
|
+
? { projectGeneratedDirSkips: projectSnapshot.generatedDirSkips }
|
|
1266
|
+
: {}),
|
|
1113
1267
|
},
|
|
1114
1268
|
};
|
|
1115
1269
|
// Stopped mid-scan: the results above are whatever completed before the abort.
|
|
@@ -1138,6 +1292,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1138
1292
|
failedNote +
|
|
1139
1293
|
walkUnsafeRootNote +
|
|
1140
1294
|
scanTruncatedNote +
|
|
1295
|
+
generatedSkipNote +
|
|
1141
1296
|
abortedNote +
|
|
1142
1297
|
freshNote +
|
|
1143
1298
|
missingNote,
|
|
@@ -1152,6 +1307,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1152
1307
|
failedNote ||
|
|
1153
1308
|
walkUnsafeRootNote ||
|
|
1154
1309
|
scanTruncatedNote ||
|
|
1310
|
+
generatedSkipNote ||
|
|
1155
1311
|
abortedNote ||
|
|
1156
1312
|
freshNote ||
|
|
1157
1313
|
unconfirmedLspNote ||
|
|
@@ -1168,6 +1324,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1168
1324
|
failedNote +
|
|
1169
1325
|
walkUnsafeRootNote +
|
|
1170
1326
|
scanTruncatedNote +
|
|
1327
|
+
generatedSkipNote +
|
|
1171
1328
|
abortedNote +
|
|
1172
1329
|
freshNote +
|
|
1173
1330
|
missingNote,
|
|
@@ -1197,13 +1354,20 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1197
1354
|
// post-dispatch lens_diagnostic_mark (suppress/defer) would otherwise still
|
|
1198
1355
|
// show here. Re-apply the weak filter (zero I/O) for the cache-only path and
|
|
1199
1356
|
// re-summarize so blocking/error/warning counts reflect the drop.
|
|
1357
|
+
// Same project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`)
|
|
1358
|
+
// overlays both modes: mode=full re-applies it after inline suppression /
|
|
1359
|
+
// disposition (zero I/O), mode=all applies it here on the cache-only path.
|
|
1360
|
+
// The full path's policyMover is loaded below in `applyInlineSuppressionsToSummaries`.
|
|
1361
|
+
const policyMap = loadProjectRulePolicyMap(cwd);
|
|
1200
1362
|
const dispositioned = isFullMode
|
|
1201
1363
|
? summaries
|
|
1202
1364
|
: summaries.map((s) => {
|
|
1203
1365
|
const kept = applyWeakDispositions(s.diagnostics ?? [], cwd, s.filePath);
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1366
|
+
const policyKept = applyRulePolicy(kept, policyMap);
|
|
1367
|
+
if (policyKept.length === kept.length &&
|
|
1368
|
+
kept.length === (s.diagnostics?.length ?? 0))
|
|
1369
|
+
return s;
|
|
1370
|
+
return summarizeDiagnostics(s.filePath, policyKept, s.hasFinalSnapshot);
|
|
1207
1371
|
});
|
|
1208
1372
|
const visibleSummaries = dispositioned.filter((s) => includeFile(s.filePath));
|
|
1209
1373
|
// Filter to files with actual issues
|