@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.
Files changed (288) hide show
  1. package/README.md +4 -4
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  13. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  14. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  15. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  16. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
  20. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  21. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  22. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  25. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  26. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  27. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  30. package/node_modules/@narumitw/pi-btw/README.md +8 -7
  31. package/node_modules/@narumitw/pi-btw/package.json +2 -2
  32. package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
  33. package/node_modules/pi-lens/CHANGELOG.md +2440 -954
  34. package/node_modules/pi-lens/README.md +13 -0
  35. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  36. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  37. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  38. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  39. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  40. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  41. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  42. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  43. package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
  44. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  45. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  46. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  47. package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
  48. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  49. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  50. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  51. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  52. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  53. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  54. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  55. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  56. package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
  57. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  58. package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
  59. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  60. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  61. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
  63. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
  64. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
  66. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  67. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  68. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  69. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  70. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  71. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
  72. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  73. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  74. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  75. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  85. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  86. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  87. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  99. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  100. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  101. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  102. package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
  103. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  104. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  105. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  106. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  107. package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
  108. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  109. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  110. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  111. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  112. package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
  113. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  114. package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
  116. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  117. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  118. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
  120. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  121. package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
  122. package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
  123. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  124. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  125. package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
  126. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  127. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  128. package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
  129. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  130. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  131. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
  132. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
  134. package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
  135. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  136. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
  137. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  138. package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
  139. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  140. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  141. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  142. package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
  143. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  144. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  145. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  146. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
  147. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  148. package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
  149. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  150. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  151. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  152. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  153. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  154. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  155. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  157. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  158. package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
  159. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  160. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  161. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  162. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  163. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  164. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  165. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  166. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  167. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  168. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  169. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  170. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  171. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  172. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  173. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  174. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  175. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  177. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  178. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  179. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  180. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  181. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  182. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
  183. package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
  184. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
  185. package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
  186. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  187. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
  188. package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
  189. package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
  190. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  191. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
  192. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  193. package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
  194. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  195. package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
  196. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  197. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  198. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  199. package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
  200. package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
  201. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  202. package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
  203. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  204. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  205. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  210. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  211. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  212. package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
  213. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  214. package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
  215. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  216. package/node_modules/pi-lens/dist/index.js +49361 -36888
  217. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  218. package/node_modules/pi-lens/dist/mcp/server.js +211 -44
  219. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  220. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
  221. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
  222. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  223. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  224. package/node_modules/pi-lens/docs/agent-guide.md +2 -2
  225. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  226. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  227. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  228. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
  229. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  230. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  231. package/node_modules/pi-lens/docs/fable.md +27 -0
  232. package/node_modules/pi-lens/docs/features.md +31 -2
  233. package/node_modules/pi-lens/docs/globalconfig.md +45 -1
  234. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  235. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  236. package/node_modules/pi-lens/docs/mcp.md +37 -4
  237. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  238. package/node_modules/pi-lens/docs/settings.md +12 -1
  239. package/node_modules/pi-lens/docs/tools.md +4 -1
  240. package/node_modules/pi-lens/docs/usage.md +18 -0
  241. package/node_modules/pi-lens/package.json +10 -10
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  252. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  253. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  254. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
  255. package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
  256. package/node_modules/pi-mcp-adapter/README.md +34 -3
  257. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  258. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  259. package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
  260. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  261. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  262. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  263. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  264. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  265. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  266. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  267. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  268. package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
  269. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  270. package/node_modules/pi-mcp-adapter/package.json +3 -3
  271. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  272. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  273. package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
  274. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  275. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  276. package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
  277. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  278. package/node_modules/pi-mcp-adapter/types.ts +93 -27
  279. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  280. package/package.json +11 -12
  281. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  282. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  283. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  284. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  285. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  286. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  287. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  288. 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
- return kept.length === report.diagnostics.length
292
- ? report
293
- : { ...report, diagnostics: kept };
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
- const projectDelta = filterDeltaReportDispositions(loadProjectDiagnosticsDeltaReport(cwd), cwd);
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 actionableFiles = (actionable?.files ?? [])
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
- function normalizeRuleForDedup(ruleId) {
558
- return ruleId.replace(/^ast-grep:/, "").replace(/-js$/, "");
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 = normalizeRuleForDedup(diagnostic.rule ?? diagnostic.tool ?? "");
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
- return summary; // never hide a finding on a read error
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 kept) {
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 (kept.length === summary.diagnostics.length)
834
+ if (policyKept.length === summary.diagnostics.length)
735
835
  return summary;
736
- return summarizeDiagnostics(summary.filePath, kept, summary.hasFinalSnapshot);
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 && !result.error);
873
- const unconfirmedLspResults = lspResults.filter((result) => result.timedOut || result.error);
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, nextWriteIndex?.());
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
- return kept.length === (s.diagnostics?.length ?? 0)
1205
- ? s
1206
- : summarizeDiagnostics(s.filePath, kept, s.hasFinalSnapshot);
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