@herbertgao/pi-extensions 2026.8.13 → 2026.8.15

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 (263) hide show
  1. package/README.md +19 -14
  2. package/THIRD_PARTY_NOTICES.md +0 -1
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +19 -0
  4. package/node_modules/@czottmann/pi-automode/README.md +5 -1
  5. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +126 -13
  6. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +7 -3
  7. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +2 -0
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +134 -23
  9. package/node_modules/@czottmann/pi-automode/package.json +1 -1
  10. package/node_modules/@herbertgao/{pi-stash → pi-bark}/LICENSE +4 -5
  11. package/node_modules/@herbertgao/pi-bark/README.md +44 -0
  12. package/node_modules/@herbertgao/pi-bark/assets/pi-icon.png +0 -0
  13. package/node_modules/@herbertgao/pi-bark/package.json +53 -0
  14. package/node_modules/@herbertgao/pi-bark/src/index.ts +178 -0
  15. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
  16. package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
  17. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  18. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  19. package/node_modules/@herbertgao/pi-subagents/package.json +2 -1
  20. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +8 -1
  21. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  22. package/node_modules/@narumitw/pi-btw/README.md +125 -88
  23. package/node_modules/@narumitw/pi-btw/dist/index.ts +140 -45
  24. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
  25. package/node_modules/@narumitw/pi-btw/package.json +5 -8
  26. package/node_modules/@narumitw/pi-btw/src/btw.ts +31 -26
  27. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +106 -17
  28. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -2
  29. package/node_modules/@narumitw/pi-btw/src/settings.ts +16 -0
  30. package/node_modules/@tifan/pi-handoff/README.md +36 -13
  31. package/node_modules/@tifan/pi-handoff/package.json +2 -2
  32. package/node_modules/@tifan/pi-handoff/src/index.ts +160 -4
  33. package/node_modules/@tifan/pi-preferred-thinking/README.md +1 -1
  34. package/node_modules/@tifan/pi-preferred-thinking/package.json +1 -1
  35. package/node_modules/@tifan/pi-preferred-thinking/src/index.ts +15 -2
  36. package/node_modules/@tifan/pi-recap/README.md +1 -1
  37. package/node_modules/@tifan/pi-recap/package.json +2 -2
  38. package/node_modules/@tifan/pi-recap/src/index.ts +15 -0
  39. package/node_modules/@tifan/pi-rename/README.md +42 -21
  40. package/node_modules/@tifan/pi-rename/package.json +1 -1
  41. package/node_modules/@tifan/pi-rename/src/index.ts +62 -11
  42. package/node_modules/@tifan/pi-rename/src/language.ts +18 -0
  43. package/node_modules/@tifan/pi-rename/src/models.ts +69 -13
  44. package/node_modules/@tifan/pi-rename/src/naming.ts +36 -7
  45. package/node_modules/@tifan/pi-rename/src/sanitize.ts +22 -14
  46. package/node_modules/pi-lens/CHANGELOG.md +320 -0
  47. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +79 -0
  48. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +16 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +13 -6
  50. package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +12 -0
  51. package/node_modules/pi-lens/dist/clients/biome-client.js +7 -0
  52. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +20 -0
  53. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +56 -19
  54. package/node_modules/pi-lens/dist/clients/build-identity.js +95 -0
  55. package/node_modules/pi-lens/dist/clients/bus-publish.js +3 -0
  56. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +2 -1
  57. package/node_modules/pi-lens/dist/clients/cache-observability.js +2 -1
  58. package/node_modules/pi-lens/dist/clients/cascade-logger.js +15 -1
  59. package/node_modules/pi-lens/dist/clients/dead-code-client.js +14 -11
  60. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +56 -4
  61. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +14 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +20 -3
  63. package/node_modules/pi-lens/dist/clients/deps/minimatch.js +1 -1
  64. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +39 -0
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +150 -9
  66. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +231 -9
  67. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +205 -100
  68. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +87 -0
  69. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +21 -5
  70. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +174 -55
  71. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +5 -1
  72. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +16 -3
  73. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +54 -9
  74. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +1 -3
  75. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +37 -1
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -1
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +11 -4
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +4 -0
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +8 -3
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +76 -25
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +4 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +19 -7
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +7 -13
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +51 -17
  85. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +66 -1
  86. package/node_modules/pi-lens/dist/clients/file-utils.js +157 -7
  87. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +5 -0
  88. package/node_modules/pi-lens/dist/clients/formatters.js +28 -3
  89. package/node_modules/pi-lens/dist/clients/git-guard.js +197 -47
  90. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +32 -1
  91. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +5 -1
  92. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +7 -0
  93. package/node_modules/pi-lens/dist/clients/installer/index.js +131 -34
  94. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +3 -1
  95. package/node_modules/pi-lens/dist/clients/instance-reaper.js +4 -13
  96. package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +145 -0
  97. package/node_modules/pi-lens/dist/clients/instance-registry.js +432 -122
  98. package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
  99. package/node_modules/pi-lens/dist/clients/language-profile.js +4 -2
  100. package/node_modules/pi-lens/dist/clients/latency-logger.js +19 -1
  101. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  102. package/node_modules/pi-lens/dist/clients/lens-map.js +3 -1
  103. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +4 -0
  104. package/node_modules/pi-lens/dist/clients/lsp/client.js +516 -31
  105. package/node_modules/pi-lens/dist/clients/lsp/config.js +25 -2
  106. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +9 -4
  107. package/node_modules/pi-lens/dist/clients/lsp/index.js +509 -182
  108. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +5 -0
  109. package/node_modules/pi-lens/dist/clients/lsp/launch.js +36 -8
  110. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +116 -4
  111. package/node_modules/pi-lens/dist/clients/lsp/server.js +142 -13
  112. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +99 -0
  113. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +16 -6
  114. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +32 -23
  115. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +16 -2
  116. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +12 -6
  117. package/node_modules/pi-lens/dist/clients/mcp/session.js +14 -1
  118. package/node_modules/pi-lens/dist/clients/memory-sampler.js +23 -1
  119. package/node_modules/pi-lens/dist/clients/message-end-attribution.js +30 -0
  120. package/node_modules/pi-lens/dist/clients/metrics-history.js +21 -4
  121. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +232 -18
  122. package/node_modules/pi-lens/dist/clients/package-manager.js +6 -18
  123. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +14 -1
  124. package/node_modules/pi-lens/dist/clients/path-utils.js +32 -0
  125. package/node_modules/pi-lens/dist/clients/pipeline.js +0 -8
  126. package/node_modules/pi-lens/dist/clients/process-singletons.js +210 -0
  127. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +2 -1
  128. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +10 -4
  129. package/node_modules/pi-lens/dist/clients/project-snapshot.js +33 -11
  130. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +24 -2
  131. package/node_modules/pi-lens/dist/clients/read-guard.js +74 -7
  132. package/node_modules/pi-lens/dist/clients/recent-touches.js +17 -5
  133. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +639 -62
  134. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +5 -1
  135. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +21 -1
  136. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +68 -0
  137. package/node_modules/pi-lens/dist/clients/runtime-session.js +30 -12
  138. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +15 -0
  139. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +106 -7
  140. package/node_modules/pi-lens/dist/clients/runtime-turn.js +242 -27
  141. package/node_modules/pi-lens/dist/clients/safe-spawn.js +158 -18
  142. package/node_modules/pi-lens/dist/clients/security-scan-client.js +48 -17
  143. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +238 -42
  144. package/node_modules/pi-lens/dist/clients/sg-runner.js +27 -15
  145. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +338 -0
  146. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +37 -0
  147. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +15 -1
  148. package/node_modules/pi-lens/dist/clients/startup-scan.js +6 -7
  149. package/node_modules/pi-lens/dist/clients/startup-timing.js +69 -4
  150. package/node_modules/pi-lens/dist/clients/string-utils.js +20 -0
  151. package/node_modules/pi-lens/dist/clients/test-runner-client.js +419 -88
  152. package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
  153. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +11 -5
  154. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +17 -1
  155. package/node_modules/pi-lens/dist/clients/warm-attach.js +8 -10
  156. package/node_modules/pi-lens/dist/clients/word-index-logger.js +13 -1
  157. package/node_modules/pi-lens/dist/clients/word-index-store.js +448 -0
  158. package/node_modules/pi-lens/dist/clients/word-index.js +582 -104
  159. package/node_modules/pi-lens/dist/clients/workspace-topology.js +17 -0
  160. package/node_modules/pi-lens/dist/clients/zizmor-config.js +26 -6
  161. package/node_modules/pi-lens/dist/index.js +11243 -6651
  162. package/node_modules/pi-lens/dist/mcp/build-staleness.js +8 -7
  163. package/node_modules/pi-lens/dist/mcp/cli.js +3 -1
  164. package/node_modules/pi-lens/dist/mcp/server.js +6 -1
  165. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +4 -0
  166. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +14 -5
  167. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
  168. package/node_modules/pi-lens/docs/agent-guide.md +4 -2
  169. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +41 -10
  170. package/node_modules/pi-lens/docs/astplayground.md +26 -17
  171. package/node_modules/pi-lens/package.json +5 -1
  172. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/c-no-malloc-free-test.yml +20 -0
  173. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-malloc-free-test.yml +25 -0
  174. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-printf-test.yml +19 -0
  175. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-fmt-println-test.yml +19 -0
  176. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-panic-in-lib-test.yml +17 -0
  177. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-underscore-func-name-test.yml +18 -0
  178. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-errors-is-test.yml +15 -0
  179. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-string-builder-test.yml +21 -0
  180. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/hyphenated-svg-attribute-test.yml +11 -0
  181. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-lateinit-test.yml +17 -0
  182. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-nullable-boolean-test.yml +15 -0
  183. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-println-test.yml +19 -0
  184. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unnecessary-let-test.yml +7 -0
  185. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unsafe-cast-test.yml +7 -0
  186. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-var-test.yml +7 -0
  187. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-data-class-test.yml +25 -0
  188. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-is-empty-test.yml +11 -0
  189. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-important-test.yml +21 -0
  190. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-types-test.yml +30 -0
  191. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-string-concat-in-loop-test.yml +100 -0
  192. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-system-out-println-test.yml +7 -0
  193. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/prefer-string-is-empty-test.yml +7 -0
  194. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/python-optional-type-test.yml +9 -0
  195. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/reducible-list-comprehension-test.yml +11 -0
  196. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ruby-symbol-to-proc-candidate-test.yml +10 -0
  197. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/rust-no-chars-enumerate-test.yml +7 -0
  198. package/node_modules/pi-lens/rules/ast-grep-rules/rules/c-no-malloc-free.yml +39 -0
  199. package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-malloc-free.yml +45 -0
  200. package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-printf.yml +41 -0
  201. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-fmt-println.yml +43 -0
  202. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-panic-in-lib.yml +41 -0
  203. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-underscore-func-name.yml +35 -0
  204. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-errors-is.yml +40 -0
  205. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-string-builder.yml +43 -0
  206. package/node_modules/pi-lens/rules/ast-grep-rules/rules/hyphenated-svg-attribute.yml +32 -0
  207. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-lateinit.yml +37 -0
  208. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-nullable-boolean.yml +33 -0
  209. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-println.yml +42 -0
  210. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unnecessary-let.yml +28 -0
  211. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unsafe-cast.yml +28 -0
  212. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-var.yml +35 -0
  213. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-data-class.yml +66 -0
  214. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-is-empty.yml +35 -0
  215. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-important.yml +21 -0
  216. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-types.yml +33 -0
  217. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-string-concat-in-loop.yml +90 -0
  218. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-system-out-println.yml +16 -0
  219. package/node_modules/pi-lens/rules/ast-grep-rules/rules/prefer-string-is-empty.yml +11 -0
  220. package/node_modules/pi-lens/rules/ast-grep-rules/rules/python-optional-type.yml +22 -0
  221. package/node_modules/pi-lens/rules/ast-grep-rules/rules/reducible-list-comprehension.yml +29 -0
  222. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ruby-symbol-to-proc-candidate.yml +25 -0
  223. package/node_modules/pi-lens/rules/ast-grep-rules/rules/rust-no-chars-enumerate.yml +19 -0
  224. package/node_modules/pi-mcp-adapter/CHANGELOG.md +35 -0
  225. package/node_modules/pi-mcp-adapter/README.md +5 -2
  226. package/node_modules/pi-mcp-adapter/cli.js +4 -4
  227. package/node_modules/pi-mcp-adapter/commands.ts +1 -1
  228. package/node_modules/pi-mcp-adapter/config.ts +1 -0
  229. package/node_modules/pi-mcp-adapter/dist/config.js +1 -0
  230. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
  231. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.d.ts +24 -0
  232. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js +336 -0
  233. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js.map +1 -0
  234. package/node_modules/pi-mcp-adapter/dist/types.d.ts +3 -1
  235. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
  236. package/node_modules/pi-mcp-adapter/index.ts +90 -6
  237. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +124 -32
  238. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +0 -2
  239. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +89 -0
  240. package/node_modules/pi-mcp-adapter/mcp-references.ts +9 -1
  241. package/node_modules/pi-mcp-adapter/package.json +1 -1
  242. package/node_modules/pi-mcp-adapter/proxy-modes.ts +62 -22
  243. package/node_modules/pi-mcp-adapter/request-headers-command.ts +1 -1
  244. package/node_modules/pi-mcp-adapter/server-manager.ts +6 -0
  245. package/node_modules/pi-mcp-adapter/types.ts +3 -1
  246. package/node_modules/pi-web-access/CHANGELOG.md +42 -0
  247. package/node_modules/pi-web-access/README.md +26 -10
  248. package/node_modules/pi-web-access/curator-page.ts +12 -3
  249. package/node_modules/pi-web-access/curator-server.ts +3 -1
  250. package/node_modules/pi-web-access/extract.ts +88 -13
  251. package/node_modules/pi-web-access/gemini-search.ts +10 -5
  252. package/node_modules/pi-web-access/github-extract.ts +47 -3
  253. package/node_modules/pi-web-access/index.ts +40 -40
  254. package/node_modules/pi-web-access/package.json +1 -1
  255. package/node_modules/pi-web-access/page-query.ts +61 -8
  256. package/node_modules/pi-web-access/xcrawl.ts +264 -0
  257. package/package.json +19 -22
  258. package/node_modules/@herbertgao/pi-stash/README.md +0 -34
  259. package/node_modules/@herbertgao/pi-stash/package.json +0 -51
  260. package/node_modules/@herbertgao/pi-stash/src/index.ts +0 -118
  261. package/node_modules/@tifan/pi-titlebar-spinner/README.md +0 -24
  262. package/node_modules/@tifan/pi-titlebar-spinner/package.json +0 -39
  263. package/node_modules/@tifan/pi-titlebar-spinner/src/index.ts +0 -49
@@ -10,7 +10,8 @@ import { detectFileKind } from "../file-kinds.js";
10
10
  import { getLspCapableKinds, getPrimaryDispatchGroup, } from "../language-policy.js";
11
11
  import { formatSlopScoreSummary, } from "../session-summary.js";
12
12
  import { clearCoverageNoticeState, clearLatencyReports, createDispatchContext, dispatchForFile, formatLatencyReport, getLatencyReports, RunnerRegistry, } from "./dispatcher.js";
13
- import { FactStore } from "./fact-store.js";
13
+ import { recordDegradationOnce } from "../degradation-ledger.js";
14
+ import { FactStore, setFactStoreEvictionReporter } from "./fact-store.js";
14
15
  import { TOOL_PLANS } from "./plan.js";
15
16
  // Re-export latency tracking types and functions
16
17
  export { clearLatencyReports, formatLatencyReport, getLatencyReports };
@@ -37,7 +38,7 @@ import { clearModuleGraphCache } from "../review-graph/workspace-modules.js";
37
38
  import { releaseWorkspaceTopologyIdleTimers } from "../workspace-topology.js";
38
39
  import { RUNTIME_CONFIG } from "../runtime-config.js";
39
40
  import { findCompiledClassesDir, hasJavaBuildDescriptor, } from "../tool-policy.js";
40
- import { removeWordIndexDocument, updateWordIndexDocument, WORD_INDEX_MAX_BYTES, } from "../word-index.js";
41
+ import { removeWordIndexDocumentAsync, updateWordIndexDocumentForEdit, WORD_INDEX_MAX_BYTES, } from "../word-index.js";
41
42
  import { reconcileCascadeNeighborLspErrors } from "../widget-state.js";
42
43
  import { findAuxiliaryProfileForSource } from "./auxiliary-lsp.js";
43
44
  // Register fact providers. All register eagerly here (the dispatch entry) — the
@@ -98,7 +99,46 @@ registerRule(commentedCredentialsRule);
98
99
  export function applyProjectLensConfig(cwd) {
99
100
  return loadPiLensProjectConfig(cwd);
100
101
  }
101
- const sessionFacts = new FactStore();
102
+ // "dispatch" labels this store's eviction telemetry (#2243 review round 3,
103
+ // F1) — five other production FactStore instances exist (mcp/analyze.ts,
104
+ // lens-map.ts, project-diagnostics/scanner.ts, runtime-session.ts's
105
+ // session-start call-graph task, mcp/cli.ts); a shared constant subject let
106
+ // runtime-session's session-start review-graph walk consume the once-per-
107
+ // session ledger slot before any dispatch ran, misattributing the record.
108
+ const sessionFacts = new FactStore("dispatch");
109
+ // #2243 item 4: wire the fact-store's capacity-eviction telemetry to the
110
+ // ledger from HERE, not from fact-store.ts. fact-store stays an import leaf so
111
+ // it cannot re-enter the safe-spawn ↔ degradation-ledger cycle (see
112
+ // `setFactStoreEvictionReporter`). The reporter forwards each store's own
113
+ // subject, so the ledger's per-kind+subject dedupe emits exactly ONE record
114
+ // per session PER STORE, re-arming when the ledger resets at session_start.
115
+ //
116
+ // #2247 review F1: the axis was previously dropped here, so
117
+ // `recordDegradationOnce`'s `${kind}\0${subject}` dedupe collapsed a store's
118
+ // count-axis and byte-axis evictions onto the SAME key — whichever axis
119
+ // tripped first (always count, since 1024 typical files land far under 64
120
+ // MiB) silently consumed the once-per-session slot and a later byte-axis
121
+ // eviction on that same store recorded nothing. Fold the axis into the
122
+ // subject (`<store>:<axis>`), matching this ledger's own `<store>:<file>`
123
+ // convention (see `demoted-finding-retired`'s doc comment) rather than
124
+ // growing the `kind` union per axis. `pinned-over-budget` (#2247 review F2)
125
+ // is a distinct condition, not an eviction, so it gets its own kind instead
126
+ // of sharing the eviction kind's subject convention.
127
+ setFactStoreEvictionReporter((subject, axis, reason) => {
128
+ if (axis === "pinned-over-budget") {
129
+ recordDegradationOnce({
130
+ kind: "fact-store-pinned-over-budget",
131
+ subject,
132
+ reason,
133
+ });
134
+ return;
135
+ }
136
+ recordDegradationOnce({
137
+ kind: "fact-store-capacity-eviction",
138
+ subject: `${subject}:${axis}`,
139
+ reason,
140
+ });
141
+ });
102
142
  const cascadeDiagnosticBaselines = new Map();
103
143
  const sessionRunnerRegistry = new RunnerRegistry();
104
144
  registerDefaultRunners(sessionRunnerRegistry);
@@ -137,32 +177,62 @@ function scheduleAstGrepWarningScan(filePath, cwd, pi, logContext) {
137
177
  const existing = astGrepWarnDebounceTimers.get(filePath);
138
178
  if (existing)
139
179
  clearTimeout(existing);
140
- const timer = setTimeout(async () => {
180
+ const timer = setTimeout(() => {
141
181
  astGrepWarnDebounceTimers.delete(filePath);
142
- try {
143
- const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, false);
144
- if (ctx.kind !== "jsts")
145
- return;
146
- // Single-runner group: ast-grep only, warning mode (blockingOnly=false)
147
- const group = {
148
- mode: "all",
149
- runnerIds: ["ast-grep"],
150
- filterKinds: ["jsts"],
151
- };
152
- const result = await dispatchForFile(ctx, [group], sessionRunnerRegistry);
153
- if (result.diagnostics.length === 0)
154
- return;
155
- const logger = getDiagnosticLogger();
156
- for (const d of result.diagnostics) {
157
- logger.logCaught(d, logContext, false);
158
- }
159
- }
160
- catch {
182
+ void runAstGrepWarningScan(filePath, cwd, pi, logContext).catch(() => {
161
183
  // Non-critical background scan — swallow errors silently
162
- }
184
+ });
163
185
  }, AST_GREP_WARN_DEBOUNCE_MS);
164
186
  astGrepWarnDebounceTimers.set(filePath, timer);
165
187
  }
188
+ /**
189
+ * Run the debounced ast-grep warning scan for one jsts file.
190
+ *
191
+ * #2243 item 1: this is a dispatch entry point like dispatchLint*, so it must
192
+ * follow the same discipline. It fires ~2 s after the last write, and in that
193
+ * window the review-graph project walk (`buildOrUpdateGraph`) seeds facts for
194
+ * every file into the SAME `sessionFacts`, which can evict this file's
195
+ * `file.content`. `dispatcher.ts` reads that fact back with `?? ""` for inline
196
+ * suppressions, so a stale or evicted read silently stops applying
197
+ * `pi-lens-ignore`. Two guards, matching the other dispatch callers:
198
+ * 1. `beginDispatchFor` pins the file for the dispatch (released in the
199
+ * finally), so a concurrent walk cannot evict it mid-dispatch. This
200
+ * does NOT clear the file's existing facts the way `clearFileFactsFor`
201
+ * does for the other dispatch callers (#2243 review round 3, F5): this
202
+ * scan fires ~2s after the SAME edit's inline dispatch already
203
+ * re-derived every fact for this file, so a second clear+re-derive
204
+ * here bought nothing but ~51ms of redundant re-parsing across all
205
+ * five providers (measured; a warm-cache read is ~1ms).
206
+ * 2. `runProviders` still re-derives `file.content` when it's actually
207
+ * missing (a genuine miss — evicted, or never computed), so the read
208
+ * never depends on staleness.
209
+ * `facts` is injected only for tests; production always uses `sessionFacts`.
210
+ */
211
+ export async function runAstGrepWarningScan(filePath, cwd, pi, logContext, facts = sessionFacts) {
212
+ const ctx = createDispatchContext(filePath, cwd, pi, facts, false);
213
+ if (ctx.kind !== "jsts")
214
+ return;
215
+ facts.beginDispatchFor(ctx.filePath);
216
+ try {
217
+ // Single-runner group: ast-grep only, warning mode (blockingOnly=false)
218
+ const group = {
219
+ mode: "all",
220
+ runnerIds: ["ast-grep"],
221
+ filterKinds: ["jsts"],
222
+ };
223
+ await runProviders(ctx);
224
+ const result = await dispatchForFile(ctx, [group], sessionRunnerRegistry);
225
+ if (result.diagnostics.length === 0)
226
+ return;
227
+ const logger = getDiagnosticLogger();
228
+ for (const d of result.diagnostics) {
229
+ logger.logCaught(d, logContext, false);
230
+ }
231
+ }
232
+ finally {
233
+ facts.endDispatchFor(ctx.filePath);
234
+ }
235
+ }
166
236
  function resetSessionSlopScore() {
167
237
  sessionSlopRuleCounts.clear();
168
238
  sessionSlopDiagnosticCount = 0;
@@ -496,6 +566,11 @@ function touchReverseDepsEntry(key, entry, armIdleTimer = true) {
496
566
  entry.idleTimer.unref?.();
497
567
  }
498
568
  function setReverseDepsEntry(key, entry, armIdleTimer = true) {
569
+ const previous = reverseDepsIndexCache.get(key);
570
+ if (previous?.idleTimer !== undefined) {
571
+ clearTimeout(previous.idleTimer);
572
+ previous.idleTimer = undefined;
573
+ }
499
574
  const resident = { ...entry, lastUsedAt: Date.now() };
500
575
  reverseDepsIndexCache.set(key, resident);
501
576
  touchReverseDepsEntry(key, resident, armIdleTimer);
@@ -604,20 +679,28 @@ function isIgnoredCascadeNeighbor(filePath, cwd) {
604
679
  * debounced persist (never a synchronous write per edit — same #260
605
680
  * discipline as the graph).
606
681
  *
607
- * Race safety against a build-in-progress: this function body is entirely
608
- * synchronous (no `await` anywhere in it) and is called synchronously at
609
- * `computeCascadeForFile`'s entry, before its own `await buildOrUpdateGraph`.
610
- * Node is single-threaded, so two overlapping cascades (#450's unawaited
611
- * concurrency) can never interleave mid-mutation here — each call runs to
612
- * completion in one turn. The only cross-build hazard is a full session-start
613
- * rebuild REPLACING `runtime.wordIndex` with a new object between the caller
614
- * reading `runtime.wordIndex` (in runtime-tool-result.ts, also synchronous)
615
- * and this function receiving it — in that case this call simply mutates
616
- * whichever index object it was handed (old or new), and the other one is
617
- * abandoned/superseded, never corrupted. No queue, no lock: the simplest rule
618
- * that is still provably correct.
682
+ * Race safety against a build-in-progress: the update runs cooperatively, on
683
+ * an 8 ms budget, through the word index's own per-index operation queue
684
+ * (#2067 AC4). It used to run synchronously here, on the reasoning that two
685
+ * overlapping cascades (#450's unawaited concurrency) could not interleave
686
+ * mid-mutation if nothing ever yielded — the reviewer's 300-document probe had
687
+ * lost 1,719 postings during an 8 ms yield. That hazard is what the queue
688
+ * closed: every async operation on one index is chained behind the previous
689
+ * one in call order, so overlapping cascades are ordered rather than
690
+ * interleaved, and the cooperative arena compactor is separately proof against
691
+ * a synchronous edit landing mid-copy (#2117 review F2). What the synchronous
692
+ * variant could not fix is its own cost: one replacement on a 2,600-document
693
+ * corpus held the event loop for the whole replacement, which is the block
694
+ * #2067 measured at 1.1 s before interning and still tens of ms after it.
695
+ *
696
+ * The only cross-build hazard is a full session-start rebuild REPLACING
697
+ * `runtime.wordIndex` with a new object between the caller reading
698
+ * `runtime.wordIndex` (in runtime-tool-result.ts, synchronous) and this
699
+ * function receiving it — in that case this call simply mutates whichever
700
+ * index object it was handed (old or new), and the other one is
701
+ * abandoned/superseded, never corrupted.
619
702
  */
620
- function updateWordIndexForCascade(args) {
703
+ async function updateWordIndexForCascade(args) {
621
704
  const { wordIndex, filePath, content, onUpdated, dbg } = args;
622
705
  if (!wordIndex || !wordIndex.forward)
623
706
  return;
@@ -625,11 +708,14 @@ function updateWordIndexForCascade(args) {
625
708
  return;
626
709
  const byteLength = Buffer.byteLength(content, "utf-8");
627
710
  if (byteLength > WORD_INDEX_MAX_BYTES) {
628
- removeWordIndexDocument(wordIndex, filePath);
711
+ await removeWordIndexDocumentAsync(wordIndex, filePath);
629
712
  dbg?.(`word-index per-edit: dropped ${filePath} (over size cap)`);
630
713
  }
631
714
  else {
632
- updateWordIndexDocument(wordIndex, { path: filePath, content });
715
+ await updateWordIndexDocumentForEdit(wordIndex, {
716
+ path: filePath,
717
+ content,
718
+ });
633
719
  dbg?.(`word-index per-edit: updated ${filePath}`);
634
720
  }
635
721
  onUpdated?.(wordIndex);
@@ -689,7 +775,7 @@ export async function computeCascadeForFile(filePath, cwd, options = {}) {
689
775
  // The old hazard — this update silently orphaning a SECOND entry next to the
690
776
  // walker's original-cased one — is now structurally impossible at the map
691
777
  // layer, so this seam no longer has to hand-match the build path's key shape.
692
- updateWordIndexForCascade({
778
+ await updateWordIndexForCascade({
693
779
  wordIndex,
694
780
  filePath: nodePath.resolve(filePath),
695
781
  content: fileContent,
@@ -1982,16 +2068,23 @@ export async function dispatchLint(filePath, cwd, pi, modifiedRanges, projectRoo
1982
2068
  // pre-existing issues after the first write.
1983
2069
  const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, true, modifiedRanges, projectRoot);
1984
2070
  sessionFacts.clearFileFactsFor(ctx.filePath);
1985
- const kind = ctx.kind;
1986
- if (!kind)
1987
- return "";
1988
- const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
1989
- if (groups.length === 0)
1990
- return "";
1991
- await runProviders(ctx);
1992
- const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry);
1993
- trackSessionSlopStats(ctx, result.diagnostics);
1994
- return result.output;
2071
+ // #2243 item 2: release the pin when the dispatch settles, so the pin set
2072
+ // tracks in-flight dispatches rather than the last N files touched.
2073
+ try {
2074
+ const kind = ctx.kind;
2075
+ if (!kind)
2076
+ return "";
2077
+ const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
2078
+ if (groups.length === 0)
2079
+ return "";
2080
+ await runProviders(ctx);
2081
+ const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry);
2082
+ trackSessionSlopStats(ctx, result.diagnostics);
2083
+ return result.output;
2084
+ }
2085
+ finally {
2086
+ sessionFacts.endDispatchFor(ctx.filePath);
2087
+ }
1995
2088
  }
1996
2089
  /**
1997
2090
  * Run linting and return full result (including diagnostics)
@@ -2002,44 +2095,50 @@ export async function dispatchLintWithResult(filePath, cwd, pi, modifiedRanges,
2002
2095
  // facade, pass blockingOnly=false to run every runner.
2003
2096
  const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, options?.blockingOnly ?? true, modifiedRanges, options?.projectRoot, options?.writeIndex, options?.telemetryModel, options?.telemetryProvider);
2004
2097
  sessionFacts.clearFileFactsFor(ctx.filePath);
2005
- const kind = ctx.kind;
2006
- if (!kind) {
2007
- return {
2008
- diagnostics: [],
2009
- blockers: [],
2010
- warnings: [],
2011
- baselineWarningCount: 0,
2012
- fixed: [],
2013
- resolvedCount: 0,
2014
- output: "",
2015
- blockerOutput: "",
2016
- hasBlockers: false,
2017
- };
2018
- }
2019
- const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
2020
- if (groups.length === 0) {
2021
- return {
2022
- diagnostics: [],
2023
- blockers: [],
2024
- warnings: [],
2025
- baselineWarningCount: 0,
2026
- fixed: [],
2027
- resolvedCount: 0,
2028
- output: "",
2029
- blockerOutput: "",
2030
- hasBlockers: false,
2031
- };
2098
+ // #2243 item 2: release the pin when the dispatch settles.
2099
+ try {
2100
+ const kind = ctx.kind;
2101
+ if (!kind) {
2102
+ return {
2103
+ diagnostics: [],
2104
+ blockers: [],
2105
+ warnings: [],
2106
+ baselineWarningCount: 0,
2107
+ fixed: [],
2108
+ resolvedCount: 0,
2109
+ output: "",
2110
+ blockerOutput: "",
2111
+ hasBlockers: false,
2112
+ };
2113
+ }
2114
+ const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
2115
+ if (groups.length === 0) {
2116
+ return {
2117
+ diagnostics: [],
2118
+ blockers: [],
2119
+ warnings: [],
2120
+ baselineWarningCount: 0,
2121
+ fixed: [],
2122
+ resolvedCount: 0,
2123
+ output: "",
2124
+ blockerOutput: "",
2125
+ hasBlockers: false,
2126
+ };
2127
+ }
2128
+ await runProviders(ctx);
2129
+ const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry);
2130
+ trackSessionSlopStats(ctx, result.diagnostics);
2131
+ // Schedule debounced ast-grep warning scan for jsts files.
2132
+ // Runs 2s after the last write — collapses rapid sequential edits into one scan.
2133
+ // Results are logged only, never surfaced to the agent.
2134
+ if (kind === "jsts" && logContext) {
2135
+ scheduleAstGrepWarningScan(filePath, cwd, pi, logContext);
2136
+ }
2137
+ return result;
2032
2138
  }
2033
- await runProviders(ctx);
2034
- const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry);
2035
- trackSessionSlopStats(ctx, result.diagnostics);
2036
- // Schedule debounced ast-grep warning scan for jsts files.
2037
- // Runs 2s after the last write — collapses rapid sequential edits into one scan.
2038
- // Results are logged only, never surfaced to the agent.
2039
- if (kind === "jsts" && logContext) {
2040
- scheduleAstGrepWarningScan(filePath, cwd, pi, logContext);
2139
+ finally {
2140
+ sessionFacts.endDispatchFor(ctx.filePath);
2041
2141
  }
2042
- return result;
2043
2142
  }
2044
2143
  /**
2045
2144
  * Same real dispatch path as {@link dispatchLintWithResult} (real context, real
@@ -2064,20 +2163,26 @@ export async function dispatchLintDetailed(filePath, cwd, pi, options) {
2064
2163
  };
2065
2164
  const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, options?.blockingOnly ?? false, options?.modifiedRanges, options?.projectRoot);
2066
2165
  sessionFacts.clearFileFactsFor(ctx.filePath);
2067
- const kind = ctx.kind;
2068
- if (!kind)
2069
- return { result: empty, runners: [] };
2070
- const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
2071
- if (groups.length === 0)
2072
- return { result: empty, runners: [] };
2073
- const runners = [];
2074
- const sink = (runnerId, result) => {
2075
- runners.push({ runnerId, result });
2076
- };
2077
- await runProviders(ctx);
2078
- const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry, sink);
2079
- trackSessionSlopStats(ctx, result.diagnostics);
2080
- return { result, runners };
2166
+ // #2243 item 2: release the pin when the dispatch settles.
2167
+ try {
2168
+ const kind = ctx.kind;
2169
+ if (!kind)
2170
+ return { result: empty, runners: [] };
2171
+ const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
2172
+ if (groups.length === 0)
2173
+ return { result: empty, runners: [] };
2174
+ const runners = [];
2175
+ const sink = (runnerId, result) => {
2176
+ runners.push({ runnerId, result });
2177
+ };
2178
+ await runProviders(ctx);
2179
+ const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry, sink);
2180
+ trackSessionSlopStats(ctx, result.diagnostics);
2181
+ return { result, runners };
2182
+ }
2183
+ finally {
2184
+ sessionFacts.endDispatchFor(ctx.filePath);
2185
+ }
2081
2186
  }
2082
2187
  /**
2083
2188
  * Check if a file should be processed by the dispatcher
@@ -0,0 +1,87 @@
1
+ /** Turn-end handoff for runners moved off the post-write critical path. */
2
+ import { incrementDegradationCount } from "../degradation-ledger.js";
3
+ const pending = [];
4
+ export const MAX_PENDING_RUNNER_FINDINGS = 50;
5
+ export function deferRunnerFindings(entry) {
6
+ const tracked = { ...entry, settled: false };
7
+ // Attach exactly once at ownership time. Re-attaching at every turn end
8
+ // accumulates handlers on a promise that may never settle (#2122 F8).
9
+ void tracked.promise.then((result) => {
10
+ tracked.result = result;
11
+ tracked.settled = true;
12
+ }, (error) => {
13
+ tracked.result = {
14
+ status: "failed",
15
+ diagnostics: [],
16
+ semantic: "warning",
17
+ failureKind: "exception",
18
+ failureMessage: String(error).slice(0, 200),
19
+ };
20
+ tracked.settled = true;
21
+ });
22
+ pending.push(tracked);
23
+ if (pending.length > MAX_PENDING_RUNNER_FINDINGS) {
24
+ const evicted = pending.shift();
25
+ if (evicted) {
26
+ incrementDegradationCount({
27
+ kind: "runner-findings-evicted",
28
+ subject: `${evicted.runnerId}:${evicted.filePath}`,
29
+ reason: `pending runner cap ${MAX_PENDING_RUNNER_FINDINGS}`,
30
+ });
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Resolve already-finished runner work for this turn. Unfinished work remains
36
+ * owned by the store and is retried at the next turn boundary.
37
+ */
38
+ export async function drainPendingRunnerFindings(maxWaitMs = 2_000) {
39
+ if (pending.length === 0)
40
+ return [];
41
+ const current = pending.splice(0, pending.length);
42
+ const results = [];
43
+ // Give already-resolved promises one microtask turn without introducing a
44
+ // wall-clock wait. This observes completed work while preserving the F5
45
+ // zero-budget contract for in-flight runners.
46
+ if (maxWaitMs === 0)
47
+ await Promise.resolve();
48
+ if (maxWaitMs > 0 && current.some((entry) => !entry.settled)) {
49
+ await new Promise((resolve) => {
50
+ const timer = setTimeout(resolve, maxWaitMs);
51
+ timer.unref?.();
52
+ });
53
+ }
54
+ for (const entry of current) {
55
+ if (entry.settled && entry.result) {
56
+ results.push({
57
+ filePath: entry.filePath,
58
+ cwd: entry.cwd,
59
+ projectRoot: entry.projectRoot,
60
+ runnerId: entry.runnerId,
61
+ markedAtMs: entry.markedAtMs,
62
+ writeIndex: entry.writeIndex,
63
+ result: entry.result,
64
+ });
65
+ }
66
+ else {
67
+ pending.push(entry);
68
+ }
69
+ }
70
+ return results;
71
+ }
72
+ /** Drop a stale answer and record the lost re-run coverage. */
73
+ export function dropStaleRunnerFindings(entry) {
74
+ if (!entry.result)
75
+ return;
76
+ incrementDegradationCount({
77
+ kind: "runner-findings-stale",
78
+ subject: `${entry.runnerId}:${entry.filePath}`,
79
+ reason: "completed result was older than the latest file edit",
80
+ });
81
+ }
82
+ export function resetPendingRunnerFindings() {
83
+ pending.length = 0;
84
+ }
85
+ export function pendingRunnerFindingsSize() {
86
+ return pending.length;
87
+ }
@@ -95,7 +95,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
95
95
  json: {
96
96
  name: "JSON Processing",
97
97
  capabilities: ["format", "lint"],
98
- writeGroups: [primary("json")],
98
+ writeGroups: [
99
+ primary("json"),
100
+ { mode: "all", runnerIds: ["trivy-config"], filterKinds: ["json"] },
101
+ ],
99
102
  },
100
103
  markdown: {
101
104
  name: "Markdown Processing",
@@ -108,7 +111,11 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
108
111
  css: {
109
112
  name: "CSS Processing",
110
113
  capabilities: ["format", "lint"],
111
- writeGroups: [primary("css")],
114
+ writeGroups: [
115
+ primary("css"),
116
+ { mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["css"] },
117
+ { mode: "all", runnerIds: ["ast-grep-napi"], filterKinds: ["css"] },
118
+ ],
112
119
  },
113
120
  yaml: {
114
121
  name: "YAML Processing",
@@ -131,7 +138,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
131
138
  html: {
132
139
  name: "HTML Linting",
133
140
  capabilities: ["lint"],
134
- writeGroups: [primary("html")],
141
+ writeGroups: [
142
+ primary("html"),
143
+ { mode: "all", runnerIds: ["ast-grep-napi"], filterKinds: ["html"] },
144
+ ],
135
145
  },
136
146
  docker: {
137
147
  name: "Dockerfile Linting",
@@ -141,7 +151,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
141
151
  php: {
142
152
  name: "PHP Linting",
143
153
  capabilities: ["types", "lint"],
144
- writeGroups: [primary("php")],
154
+ writeGroups: [
155
+ primary("php"),
156
+ { mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["php"] },
157
+ ],
145
158
  },
146
159
  powershell: {
147
160
  name: "PowerShell Linting",
@@ -156,7 +169,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
156
169
  csharp: {
157
170
  name: "C# Linting",
158
171
  capabilities: ["types", "lint"],
159
- writeGroups: [primary("csharp")],
172
+ writeGroups: [
173
+ primary("csharp"),
174
+ { mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["csharp"] },
175
+ ],
160
176
  },
161
177
  fsharp: {
162
178
  name: "F# Linting",