@herbertgao/pi-extensions 2026.8.4 → 2026.8.6
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 +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
- 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/feature/context.ts +74 -5
- 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 +53 -14
- 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 +18 -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 +20 -4
- 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/fleet-list.ts +15 -6
- 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/@herbertgao/pi-subagents/src/worktree.ts +9 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -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 +32 -24
- package/node_modules/@narumitw/pi-btw/package.json +6 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/pi-lens/CHANGELOG.md +2535 -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/advisory-provenance.js +314 -0
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
- 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 +136 -24
- 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-events-logger.js +62 -6
- package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
- 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/cascade-format.js +57 -2
- 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 +26 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
- 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 +361 -77
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
- 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 +1172 -683
- 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 +47 -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/availability-policy.js +226 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
- 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 +473 -42
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -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 +18 -4
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +432 -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/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
- 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 +678 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
- 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 +395 -100
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
- package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
- 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 +72 -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 +63 -9
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
- package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
- 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 +437 -86
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
- 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 +127 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
- 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/model-provider.js +53 -0
- 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 +76 -15
- 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/fresh-fetch.js +1 -1
- 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/runner-adapters/runner-findings.js +23 -2
- 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/query.js +24 -0
- 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/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
- package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
- package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -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 +342 -33
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
- package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -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 +7 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -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 +50 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +51785 -36118
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +219 -46
- package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
- 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/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +40 -15
- 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 +14 -3
- 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 +45 -3
- package/node_modules/pi-lens/docs/globalconfig.md +56 -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 +18 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +41 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -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-chained-type-assertions-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -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-reflect-apply-js-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -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-chained-type-assertions.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -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-reflect-apply-js.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -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 +134 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
- package/node_modules/pi-mcp-adapter/README.md +38 -4
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/cli.js +25 -4
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/config.ts +4 -4
- package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
- 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/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +4 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +41 -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 +62 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +176 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/node_modules/pi-web-access/CHANGELOG.md +14 -0
- package/node_modules/pi-web-access/README.md +18 -12
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +5 -3
- package/node_modules/pi-web-access/curator-server.ts +2 -1
- package/node_modules/pi-web-access/extract.ts +106 -34
- package/node_modules/pi-web-access/fetch-params.ts +17 -3
- package/node_modules/pi-web-access/firecrawl.ts +172 -12
- package/node_modules/pi-web-access/gemini-search.ts +18 -4
- package/node_modules/pi-web-access/index.ts +120 -48
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/summary-review.ts +11 -5
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +12 -13
- 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
|
|
@@ -72,7 +118,7 @@ nextWriteIndex,
|
|
|
72
118
|
// #798/#338: capture host UI methods synchronously from the active tool event.
|
|
73
119
|
// The returned closure is safe for the later async sweep to invoke because it
|
|
74
120
|
// never dereferences the session-guarded ctx.ui getter.
|
|
75
|
-
captureLspStatusRepaint) {
|
|
121
|
+
captureLspStatusRepaint, getRuntime) {
|
|
76
122
|
return {
|
|
77
123
|
name: "lens_diagnostics",
|
|
78
124
|
label: "Project Diagnostics",
|
|
@@ -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,12 +286,14 @@ 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,
|
|
242
293
|
onServerReady: repaintLspStatus,
|
|
243
294
|
pathsScope,
|
|
244
295
|
nextWriteIndex,
|
|
296
|
+
runtime: getRuntime?.(),
|
|
245
297
|
});
|
|
246
298
|
}
|
|
247
299
|
return formatDeltaMode(cacheManager, cwd, severity, pathsScope);
|
|
@@ -281,23 +333,46 @@ function appendProjectDiagnosticsDeltaLines(lines, cwd, report, severity, includ
|
|
|
281
333
|
* delta mode re-serves them. Anchored via `projectDiagnosticToWidget` so the
|
|
282
334
|
* (tool, rule) an agent's mark binds to matches mode=full's own project-runner
|
|
283
335
|
* filter (`applyInlineSuppressionsToSummaries`), keeping the two paths in
|
|
284
|
-
* agreement. Weak-anchored → no file read.
|
|
336
|
+
* agreement. Weak-anchored → no file read. Also applies the project's
|
|
337
|
+
* `.pi-lens.json` `rules.<id>.disable`/`select` policy so a project's policy
|
|
338
|
+
* overlays the same delta report cache; the cache is otherwise insensitive to
|
|
339
|
+
* a project-config edit (the per-edit path picks it up immediately, but a
|
|
340
|
+
* non-dispatch tool query would replay the pre-edit state).
|
|
285
341
|
*/
|
|
286
|
-
function filterDeltaReportDispositions(report, cwd) {
|
|
342
|
+
function filterDeltaReportDispositions(report, cwd, policyMap) {
|
|
287
343
|
if (!report?.diagnostics.length)
|
|
288
344
|
return report;
|
|
289
345
|
const kept = report.diagnostics.filter((d) => applyWeakDispositions([projectDiagnosticToWidget(d)], cwd, d.filePath)
|
|
290
346
|
.length === 1);
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
347
|
+
const policyKept = applyRulePolicy(kept, policyMap);
|
|
348
|
+
if (policyKept.length === report.diagnostics.length)
|
|
349
|
+
return report;
|
|
350
|
+
return { ...report, diagnostics: policyKept };
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Load the rule-policy map from a project's `.pi-lens.json` — same source the
|
|
354
|
+
* per-edit dispatch path uses, so a project's policy applies consistently
|
|
355
|
+
* across every output surface. `loadPiLensProjectConfig` is mtime-cached, and
|
|
356
|
+
* the map is filtered to entries that actually have a `disable`/`select` list
|
|
357
|
+
* (thresholds are handled elsewhere), so the common case returns undefined and
|
|
358
|
+
* the filter step is skipped outright.
|
|
359
|
+
*/
|
|
360
|
+
function loadProjectRulePolicyMap(cwd) {
|
|
361
|
+
return rulePolicyMapFromConfig(loadPiLensProjectConfig(cwd).rules);
|
|
294
362
|
}
|
|
295
363
|
function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
296
364
|
const actionableEntry = cacheManager.readCache("actionable-warnings", cwd);
|
|
297
365
|
const qualityEntry = cacheManager.readCache("code-quality-warnings", cwd);
|
|
298
366
|
const actionable = actionableEntry?.data;
|
|
299
367
|
const quality = qualityEntry?.data;
|
|
300
|
-
|
|
368
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable` /
|
|
369
|
+
// `rules.<id>.select`) — output-only filtering applied consistently across
|
|
370
|
+
// every mode. The cache-only delta/all paths would otherwise leak project-
|
|
371
|
+
// policy oversight (the per-edit dispatch already filters, but the cache
|
|
372
|
+
// snapshots predate the user's project config edit and would replay
|
|
373
|
+
// filtered findings). Weak-anchored like weak disposition — zero I/O.
|
|
374
|
+
const policyMap = loadProjectRulePolicyMap(cwd);
|
|
375
|
+
const projectDelta = filterDeltaReportDispositions(loadProjectDiagnosticsDeltaReport(cwd), cwd, policyMap);
|
|
301
376
|
const ignoreFile = createCurrentIgnoreFilter(cwd);
|
|
302
377
|
const includeFile = (filePath) => ignoreFile(filePath) && (!pathsScope || pathsScope.includeFile(filePath));
|
|
303
378
|
// #755: delta re-serves the actionable/quality caches verbatim, but those
|
|
@@ -305,20 +380,15 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
|
305
380
|
// the weak disposition filter (suppress/defer) here so a mark converges
|
|
306
381
|
// immediately, not only on the next edit. Weak-anchored → zero file I/O, so
|
|
307
382
|
// this stays "instant" (see applyWeakDispositions).
|
|
308
|
-
const
|
|
383
|
+
const visibleWarningFiles = (files) => (files ?? [])
|
|
309
384
|
.filter((file) => includeFile(file.filePath))
|
|
310
385
|
.map((file) => ({
|
|
311
386
|
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),
|
|
387
|
+
warnings: applyRulePolicy(applyWeakDispositions(file.warnings ?? [], cwd, file.filePath), policyMap),
|
|
320
388
|
}))
|
|
321
389
|
.filter((file) => file.warnings.length > 0);
|
|
390
|
+
const actionableFiles = visibleWarningFiles(actionable?.files);
|
|
391
|
+
const qualityFiles = visibleWarningFiles(quality?.files);
|
|
322
392
|
const lines = [];
|
|
323
393
|
// Fixable warnings from actionable-warnings
|
|
324
394
|
if (severity !== "error") {
|
|
@@ -353,7 +423,7 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
|
|
|
353
423
|
.filter((f) => includeFile(f.filePath))
|
|
354
424
|
.map((f) => ({
|
|
355
425
|
...f,
|
|
356
|
-
diagnostics: applyWeakDispositions(f.diagnostics, cwd, f.filePath),
|
|
426
|
+
diagnostics: applyRulePolicy(applyWeakDispositions(f.diagnostics, cwd, f.filePath), policyMap),
|
|
357
427
|
}))
|
|
358
428
|
.filter((f) => f.diagnostics.length > 0);
|
|
359
429
|
const carriedIssues = carried.reduce((n, f) => n + f.diagnostics.length, 0);
|
|
@@ -484,6 +554,20 @@ function filterProjectDiagnosticsDeltaReport(report, includeFile) {
|
|
|
484
554
|
diagnostics: report.diagnostics.filter((d) => includeFile(d.filePath)),
|
|
485
555
|
};
|
|
486
556
|
}
|
|
557
|
+
/**
|
|
558
|
+
* Apply the project rule policy to a project-diagnostics snapshot/delta
|
|
559
|
+
* report's `diagnostics` list, in place of the collection's shape. Used by
|
|
560
|
+
* `formatFullMode` so `projectSnapshot.diagnostics.length` /
|
|
561
|
+
* `projectDelta.diagnostics.length` — which feed both the merged summaries
|
|
562
|
+
* and the `details.projectDiagnostics`/`details.projectDiagnosticsDelta`
|
|
563
|
+
* counts — already reflect the policy instead of reporting a pre-policy
|
|
564
|
+
* count that disagrees with the rendered text.
|
|
565
|
+
*/
|
|
566
|
+
function applyProjectRulePolicy(value, policyMap) {
|
|
567
|
+
if (!value)
|
|
568
|
+
return undefined;
|
|
569
|
+
return { ...value, diagnostics: applyRulePolicy(value.diagnostics, policyMap) };
|
|
570
|
+
}
|
|
487
571
|
/** A diagnostic counts as error-like when it blocks or has error severity. */
|
|
488
572
|
function isErrorLike(d) {
|
|
489
573
|
return d.semantic === "blocking" || d.severity === "error";
|
|
@@ -553,12 +637,12 @@ function projectDiagnosticToWidget(diagnostic) {
|
|
|
553
637
|
// violation must collapse to one finding in mode=full's merge regardless of which
|
|
554
638
|
// engine produced it. Strip the `ast-grep:` source prefix and the `-js` language
|
|
555
639
|
// 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
|
-
|
|
640
|
+
// LSP sweep and the napi scan don't double-report the same line. The
|
|
641
|
+
// normalization itself now lives in `clients/dispatch/rule-id-normalize.ts` so the
|
|
642
|
+
// inline suppression parser, the project rule-policy matcher, and dedup all apply
|
|
643
|
+
// the same canonical form.
|
|
560
644
|
function diagnosticDedupKey(filePath, diagnostic) {
|
|
561
|
-
const ruleId =
|
|
645
|
+
const ruleId = normalizeRuleId(diagnostic.rule ?? diagnostic.tool ?? "");
|
|
562
646
|
return [path.resolve(filePath), diagnostic.line ?? "?", ruleId].join(":");
|
|
563
647
|
}
|
|
564
648
|
function summarizeDiagnostics(filePath, diagnostics, hasFinalSnapshot) {
|
|
@@ -701,8 +785,14 @@ function mergeDiagnosticsWithWidgetSummaries(widgetSummaries, lspResults, projec
|
|
|
701
785
|
* a read failure is fail-safe (keep the diagnostics rather than hide a finding on
|
|
702
786
|
* an I/O error). Re-summarizes so the blocking/error/warning counts reflect the
|
|
703
787
|
* suppression.
|
|
788
|
+
*
|
|
789
|
+
* Also applies the project's `.pi-lens.json` `rules.<id>.disable`/`select`
|
|
790
|
+
* policy AFTER inline suppression / disposition so the same set of findings
|
|
791
|
+
* the per-edit `dispatcher.ts` filters is what's rendered here. The policy
|
|
792
|
+
* map is passed in (computed once per `formatFullMode` call) rather than
|
|
793
|
+
* re-deriving per file — see `loadProjectRulePolicyMap(cwd)`.
|
|
704
794
|
*/
|
|
705
|
-
async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
795
|
+
async function applyInlineSuppressionsToSummaries(summaries, cwd, policyMap) {
|
|
706
796
|
return Promise.all(summaries.map(async (summary) => {
|
|
707
797
|
if (!summary.diagnostics.length)
|
|
708
798
|
return summary;
|
|
@@ -711,7 +801,13 @@ async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
|
711
801
|
content = await fs.readFile(summary.filePath, "utf8");
|
|
712
802
|
}
|
|
713
803
|
catch {
|
|
714
|
-
|
|
804
|
+
// Inline suppression/disposition remains fail-open when the file cannot
|
|
805
|
+
// be read, but project policy does not depend on content and must still
|
|
806
|
+
// be applied so a fresh full-mode result cannot bypass `disable`/`select`.
|
|
807
|
+
const policyKept = applyRulePolicy(summary.diagnostics, policyMap);
|
|
808
|
+
return policyKept.length === summary.diagnostics.length
|
|
809
|
+
? summary
|
|
810
|
+
: summarizeDiagnostics(summary.filePath, policyKept, summary.hasFinalSnapshot);
|
|
715
811
|
}
|
|
716
812
|
const inlineKept = applyInlineSuppressions(summary.diagnostics, content);
|
|
717
813
|
// #690: same false-positive/suppress/defer disposition filter the
|
|
@@ -719,11 +815,16 @@ async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
|
719
815
|
// diagnostics from a fresh LSP sweep/project scan that never went
|
|
720
816
|
// through that path, so without this a disposed finding reappears here.
|
|
721
817
|
const kept = applyDispositions(inlineKept, cwd, summary.filePath, content);
|
|
818
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`).
|
|
819
|
+
// Applied after inline suppression / disposition so the policy's
|
|
820
|
+
// output-only filtering affects the same surface the per-edit path
|
|
821
|
+
// produces (no double-counting, no leftover policy-rejected findings).
|
|
822
|
+
const policyKept = applyRulePolicy(kept, policyMap);
|
|
722
823
|
// Tag `flagged` diagnostics for the render loop (formatAllMode). Content
|
|
723
824
|
// is already in hand here (unlike mode=all/delta's cache-only path), so
|
|
724
825
|
// this is the one place the tag can be computed without adding I/O to
|
|
725
826
|
// the "instant" modes.
|
|
726
|
-
for (const d of
|
|
827
|
+
for (const d of policyKept) {
|
|
727
828
|
// flagged is weak-anchored (module doc, diagnostic-dispositions.ts) so
|
|
728
829
|
// the tag survives incidental edits to the flagged line itself.
|
|
729
830
|
const { weak } = anchorsForDiagnostic(cwd, summary.filePath, d, content);
|
|
@@ -731,9 +832,9 @@ async function applyInlineSuppressionsToSummaries(summaries, cwd) {
|
|
|
731
832
|
d.flagged = true;
|
|
732
833
|
}
|
|
733
834
|
}
|
|
734
|
-
if (
|
|
835
|
+
if (policyKept.length === summary.diagnostics.length)
|
|
735
836
|
return summary;
|
|
736
|
-
return summarizeDiagnostics(summary.filePath,
|
|
837
|
+
return summarizeDiagnostics(summary.filePath, policyKept, summary.hasFinalSnapshot);
|
|
737
838
|
}));
|
|
738
839
|
}
|
|
739
840
|
function shouldUseCachedProjectDiagnostics(value) {
|
|
@@ -781,6 +882,7 @@ async function getProjectDiagnosticsSnapshotForFullMode(cwd, options) {
|
|
|
781
882
|
maxFiles: options.maxProjectFiles,
|
|
782
883
|
signal: options.signal,
|
|
783
884
|
files: options.files,
|
|
885
|
+
includeGenerated: options.includeGenerated,
|
|
784
886
|
});
|
|
785
887
|
}
|
|
786
888
|
if (shouldUseCachedProjectDiagnostics(options.refreshRunners)) {
|
|
@@ -834,7 +936,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
834
936
|
// scan, makes it genuinely concurrent — all three phases now race the SAME
|
|
835
937
|
// signal from the same starting point instead of stacking.
|
|
836
938
|
const analyzersPromise = shouldIncludeProjectRunners(options.refreshRunners)
|
|
837
|
-
? loadBootstrapClients().then((clients) => fetchFreshProjectDiagnostics(cacheManager, cwd, clients, signal))
|
|
939
|
+
? loadBootstrapClients().then((clients) => fetchFreshProjectDiagnostics(cacheManager, cwd, clients, signal, { runtime: options.runtime }))
|
|
838
940
|
: Promise.resolve({
|
|
839
941
|
diagnostics: [],
|
|
840
942
|
runners: [],
|
|
@@ -848,6 +950,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
848
950
|
signal,
|
|
849
951
|
onProgress: options.onProgress,
|
|
850
952
|
onServerReady: options.onServerReady,
|
|
953
|
+
nextWriteIndex: options.nextWriteIndex,
|
|
851
954
|
files: explicitFiles,
|
|
852
955
|
}),
|
|
853
956
|
getProjectDiagnosticsSnapshotForFullMode(cwd, {
|
|
@@ -858,6 +961,12 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
858
961
|
]);
|
|
859
962
|
const aborted = signal?.aborted ?? false;
|
|
860
963
|
const lspResults = rawLspResults.filter((result) => includeFile(result.filePath));
|
|
964
|
+
// A result bound to a different document must not replace the current
|
|
965
|
+
// widget state, even when it contains real diagnostics. Pull results may carry
|
|
966
|
+
// a content hash without the push binding verdict, so verify that hash against
|
|
967
|
+
// disk through the bounded async fallback above; unreadable files remain
|
|
968
|
+
// unknown and retain the existing fail-open policy.
|
|
969
|
+
const mismatchedLspResults = await findFullScanBindingMismatches(lspResults);
|
|
861
970
|
// #630: `timedOut`/`error` means the per-file check never actually
|
|
862
971
|
// completed or was inconclusive (#570's `touchFile().inconclusive`, or
|
|
863
972
|
// this sweep's own outer per-file deadline/throw — see
|
|
@@ -869,8 +978,12 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
869
978
|
// the unfiltered `lspResults` in, so a timed-out file's placeholder `[]`
|
|
870
979
|
// read as "0 diagnostics" — false-clean — in the rendered/`details`
|
|
871
980
|
// output (#630).
|
|
872
|
-
const confirmedLspResults = lspResults.filter((result) => !result.timedOut &&
|
|
873
|
-
|
|
981
|
+
const confirmedLspResults = lspResults.filter((result) => !result.timedOut &&
|
|
982
|
+
!result.error &&
|
|
983
|
+
!mismatchedLspResults.has(result));
|
|
984
|
+
const unconfirmedLspResults = lspResults.filter((result) => result.timedOut ||
|
|
985
|
+
result.error ||
|
|
986
|
+
mismatchedLspResults.has(result));
|
|
874
987
|
// #571: reconcile this scan's fresh, CONFIRMED per-file results into the
|
|
875
988
|
// footer cache. A footer write is never allowed to fail the tool call, so
|
|
876
989
|
// any unexpected throw is swallowed.
|
|
@@ -891,12 +1004,33 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
891
1004
|
// (`applyAuxiliarySuppressions`), so an empty content string here is a
|
|
892
1005
|
// safe no-op re-check rather than a behavior gap.
|
|
893
1006
|
const retagged = retagAuxiliaryDiagnostics(diagnostics, result.diagnostics, "", { cwd, fileRole: detectFileRole(result.filePath) });
|
|
894
|
-
reconcileScanDiagnostics(result.filePath, retagged, true,
|
|
1007
|
+
reconcileScanDiagnostics(result.filePath, retagged, true,
|
|
1008
|
+
// The service reserves this token when the file enters the scan. The
|
|
1009
|
+
// fallback preserves compatibility with older test doubles/services.
|
|
1010
|
+
result.writeIndex ?? nextWriteIndex?.(),
|
|
1011
|
+
// #1093: `observedAt` is set only when this result was served from
|
|
1012
|
+
// the workspace-diagnostics cache (a replay of an older scan) —
|
|
1013
|
+
// stamp `touchedAt` with when it was scanned, not now(), so a
|
|
1014
|
+
// mode=full that only re-serves the cache can't keep a resolved
|
|
1015
|
+
// finding on screen by re-arming the mtime gate. Undefined for
|
|
1016
|
+
// freshly-touched results (observed now).
|
|
1017
|
+
result.observedAt);
|
|
895
1018
|
}
|
|
896
1019
|
catch {
|
|
897
1020
|
// Never let a footer-reconciliation hiccup fail the scan itself.
|
|
898
1021
|
}
|
|
899
1022
|
}
|
|
1023
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`) —
|
|
1024
|
+
// loaded once per mode=full call, BEFORE `projectSnapshot`/`projectDelta`
|
|
1025
|
+
// are built below, so `.diagnostics.length` on both (which feeds
|
|
1026
|
+
// `details.projectDiagnostics`/`details.projectDiagnosticsDelta` as well
|
|
1027
|
+
// as the merge into `summaries`) is the POST-policy count. Threaded into
|
|
1028
|
+
// `applyInlineSuppressionsToSummaries` too (idempotent re-apply there) so
|
|
1029
|
+
// the merged summaries honor the same policy the per-edit dispatch path
|
|
1030
|
+
// applies. A project config read failure is treated as "no policy"
|
|
1031
|
+
// (defensive, matches the `applyInlineSuppressionsToSummaries` read-error
|
|
1032
|
+
// discipline).
|
|
1033
|
+
const policyMap = loadProjectRulePolicyMap(cwd);
|
|
900
1034
|
const scannedSnapshot = filterProjectDiagnosticsSnapshot(rawProjectSnapshot, includeFile);
|
|
901
1035
|
// Heavyweight-analyzer findings (jscpd, madge, gitleaks, knip, govulncheck,
|
|
902
1036
|
// trivy, dead-code) — a FRESH run of each (#585), not a cache-only read:
|
|
@@ -911,14 +1045,14 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
911
1045
|
// computed above, in the SAME `Promise.all` as the LSP sweep (#613) — only
|
|
912
1046
|
// when the caller opted into project-runner state (otherwise it's the
|
|
913
1047
|
// `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);
|
|
1048
|
+
const projectSnapshot = applyProjectRulePolicy(foldExtraDiagnosticsIntoSnapshot(scannedSnapshot, extracted.diagnostics.filter((d) => includeFile(d.filePath)), extracted.runners, cwd), policyMap);
|
|
1049
|
+
const projectDelta = applyProjectRulePolicy(filterProjectDiagnosticsDeltaReport(loadProjectDiagnosticsDeltaReport(cwd), includeFile), policyMap);
|
|
916
1050
|
// #630: only the CONFIRMED LSP results contribute diagnostics to the merge
|
|
917
1051
|
// — an unconfirmed (timed-out/errored) file's placeholder `[]` must not be
|
|
918
1052
|
// read as "0 issues, clean" via its LSP contribution. It can still
|
|
919
1053
|
// legitimately show diagnostics from widgetSummaries/project-runner state
|
|
920
1054
|
// below if those independently have entries for it.
|
|
921
|
-
const summaries = await applyInlineSuppressionsToSummaries(mergeDiagnosticsWithWidgetSummaries(getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath)), confirmedLspResults, projectSnapshot, projectDelta), cwd);
|
|
1055
|
+
const summaries = await applyInlineSuppressionsToSummaries(mergeDiagnosticsWithWidgetSummaries(getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath)), confirmedLspResults, projectSnapshot, projectDelta), cwd, policyMap);
|
|
922
1056
|
const result = formatAllMode(cwd, severity, summaries, {
|
|
923
1057
|
mode: "full",
|
|
924
1058
|
lspFilesChecked: rawLspResults.length,
|
|
@@ -1057,6 +1191,14 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1057
1191
|
const scanTruncatedNote = scanTruncatedNoticeText
|
|
1058
1192
|
? `\n\n${scanTruncatedNoticeText}`
|
|
1059
1193
|
: "";
|
|
1194
|
+
// #1107 phase 2: same "reached the seam, nothing rendered it" gap as #784
|
|
1195
|
+
// above, for the generated-name/dir skip counters.
|
|
1196
|
+
const generatedSkipNoticeText = projectSnapshot
|
|
1197
|
+
? generatedSkipNotice(projectSnapshot)
|
|
1198
|
+
: undefined;
|
|
1199
|
+
const generatedSkipNote = generatedSkipNoticeText
|
|
1200
|
+
? `\n\n${generatedSkipNoticeText}`
|
|
1201
|
+
: "";
|
|
1060
1202
|
const abortedNote = abortedIds.size > 0
|
|
1061
1203
|
? `\n\nstopped mid-scan (still running in the background, not reflected in this result): ${[
|
|
1062
1204
|
...abortedIds,
|
|
@@ -1110,6 +1252,19 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1110
1252
|
// #784: lets a caller check "was the cheap project scan truncated"
|
|
1111
1253
|
// without parsing the text note.
|
|
1112
1254
|
projectScanTruncated: projectSnapshot?.scanTruncated ?? false,
|
|
1255
|
+
// #1107 phase 2: same machine-readable convention, for the
|
|
1256
|
+
// generated-name/dir skip counters.
|
|
1257
|
+
...(projectSnapshot?.generatedFileSkips
|
|
1258
|
+
? { projectGeneratedFileSkips: projectSnapshot.generatedFileSkips }
|
|
1259
|
+
: {}),
|
|
1260
|
+
...(projectSnapshot?.generatedNameOnlySkips
|
|
1261
|
+
? {
|
|
1262
|
+
projectGeneratedNameOnlySkips: projectSnapshot.generatedNameOnlySkips,
|
|
1263
|
+
}
|
|
1264
|
+
: {}),
|
|
1265
|
+
...(projectSnapshot?.generatedDirSkips
|
|
1266
|
+
? { projectGeneratedDirSkips: projectSnapshot.generatedDirSkips }
|
|
1267
|
+
: {}),
|
|
1113
1268
|
},
|
|
1114
1269
|
};
|
|
1115
1270
|
// Stopped mid-scan: the results above are whatever completed before the abort.
|
|
@@ -1138,6 +1293,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1138
1293
|
failedNote +
|
|
1139
1294
|
walkUnsafeRootNote +
|
|
1140
1295
|
scanTruncatedNote +
|
|
1296
|
+
generatedSkipNote +
|
|
1141
1297
|
abortedNote +
|
|
1142
1298
|
freshNote +
|
|
1143
1299
|
missingNote,
|
|
@@ -1152,6 +1308,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1152
1308
|
failedNote ||
|
|
1153
1309
|
walkUnsafeRootNote ||
|
|
1154
1310
|
scanTruncatedNote ||
|
|
1311
|
+
generatedSkipNote ||
|
|
1155
1312
|
abortedNote ||
|
|
1156
1313
|
freshNote ||
|
|
1157
1314
|
unconfirmedLspNote ||
|
|
@@ -1168,6 +1325,7 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
|
|
|
1168
1325
|
failedNote +
|
|
1169
1326
|
walkUnsafeRootNote +
|
|
1170
1327
|
scanTruncatedNote +
|
|
1328
|
+
generatedSkipNote +
|
|
1171
1329
|
abortedNote +
|
|
1172
1330
|
freshNote +
|
|
1173
1331
|
missingNote,
|
|
@@ -1197,13 +1355,20 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
|
|
|
1197
1355
|
// post-dispatch lens_diagnostic_mark (suppress/defer) would otherwise still
|
|
1198
1356
|
// show here. Re-apply the weak filter (zero I/O) for the cache-only path and
|
|
1199
1357
|
// re-summarize so blocking/error/warning counts reflect the drop.
|
|
1358
|
+
// Same project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`)
|
|
1359
|
+
// overlays both modes: mode=full re-applies it after inline suppression /
|
|
1360
|
+
// disposition (zero I/O), mode=all applies it here on the cache-only path.
|
|
1361
|
+
// The full path's policyMover is loaded below in `applyInlineSuppressionsToSummaries`.
|
|
1362
|
+
const policyMap = loadProjectRulePolicyMap(cwd);
|
|
1200
1363
|
const dispositioned = isFullMode
|
|
1201
1364
|
? summaries
|
|
1202
1365
|
: summaries.map((s) => {
|
|
1203
1366
|
const kept = applyWeakDispositions(s.diagnostics ?? [], cwd, s.filePath);
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1367
|
+
const policyKept = applyRulePolicy(kept, policyMap);
|
|
1368
|
+
if (policyKept.length === kept.length &&
|
|
1369
|
+
kept.length === (s.diagnostics?.length ?? 0))
|
|
1370
|
+
return s;
|
|
1371
|
+
return summarizeDiagnostics(s.filePath, policyKept, s.hasFinalSnapshot);
|
|
1207
1372
|
});
|
|
1208
1373
|
const visibleSummaries = dispositioned.filter((s) => includeFile(s.filePath));
|
|
1209
1374
|
// Filter to files with actual issues
|