pi-lens 3.8.73 → 4.0.0

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 (346) hide show
  1. package/CHANGELOG.md +2614 -12
  2. package/README.md +50 -21
  3. package/dist/clients/actionable-warnings.js +73 -18
  4. package/dist/clients/agent-behavior-client.js +21 -4
  5. package/dist/clients/ast-grep-client.js +68 -16
  6. package/dist/clients/ast-grep-types.js +0 -1
  7. package/dist/clients/ast-grep-yaml-synth.js +37 -10
  8. package/dist/clients/atomic-write-staging.js +63 -0
  9. package/dist/clients/atomic-write.js +116 -16
  10. package/dist/clients/bash-file-access.js +193 -23
  11. package/dist/clients/biome-client.js +29 -25
  12. package/dist/clients/bootstrap.js +11 -2
  13. package/dist/clients/bounded-cache.js +34 -0
  14. package/dist/clients/bounded-pid-file-lock.js +192 -0
  15. package/dist/clients/bus-events-logger.js +5 -1
  16. package/dist/clients/bus-publish.js +10 -3
  17. package/dist/clients/cache/rule-cache.js +89 -6
  18. package/dist/clients/cache-manager.js +97 -9
  19. package/dist/clients/cache-observability.js +498 -0
  20. package/dist/clients/call-graph.js +460 -108
  21. package/dist/clients/cascade-logger.js +5 -1
  22. package/dist/clients/child-unref.js +85 -0
  23. package/dist/clients/codebase-model.js +52 -23
  24. package/dist/clients/collateral-test-role.js +40 -0
  25. package/dist/clients/complexity-client.js +6 -8
  26. package/dist/clients/console-guard-install.js +14 -0
  27. package/dist/clients/cooperative-budget.js +42 -0
  28. package/dist/clients/dead-code-client.js +2 -1
  29. package/dist/clients/debug-handles.js +206 -0
  30. package/dist/clients/debug-heap.js +167 -0
  31. package/dist/clients/degradation-ledger.js +153 -0
  32. package/dist/clients/dependency-checker.js +466 -63
  33. package/dist/clients/diagnostic-dispositions.js +83 -13
  34. package/dist/clients/diagnostics-publish.js +10 -3
  35. package/dist/clients/dispatch/auxiliary-lsp.js +34 -0
  36. package/dist/clients/dispatch/dispatcher.js +71 -13
  37. package/dist/clients/dispatch/fact-store.js +11 -0
  38. package/dist/clients/dispatch/facts/function-facts.js +37 -7
  39. package/dist/clients/dispatch/facts/import-facts.js +108 -119
  40. package/dist/clients/dispatch/facts/tree-sitter-facts.js +12 -12
  41. package/dist/clients/dispatch/facts/try-catch-facts.js +13 -0
  42. package/dist/clients/dispatch/indent-detect.js +35 -0
  43. package/dist/clients/dispatch/inline-suppressions.js +17 -8
  44. package/dist/clients/dispatch/integration.js +1094 -611
  45. package/dist/clients/dispatch/lazy.js +14 -0
  46. package/dist/clients/dispatch/plan.js +11 -1
  47. package/dist/clients/dispatch/rule-id-normalize.js +50 -0
  48. package/dist/clients/dispatch/rule-policy.js +135 -0
  49. package/dist/clients/dispatch/rules/async-noise.js +1 -0
  50. package/dist/clients/dispatch/rules/unsafe-boundary.js +7 -0
  51. package/dist/clients/dispatch/runners/ast-grep-napi.js +47 -6
  52. package/dist/clients/dispatch/runners/biome-check.js +5 -9
  53. package/dist/clients/dispatch/runners/detekt.js +3 -2
  54. package/dist/clients/dispatch/runners/hadolint.js +2 -1
  55. package/dist/clients/dispatch/runners/helm-lint.js +154 -0
  56. package/dist/clients/dispatch/runners/htmlhint.js +3 -2
  57. package/dist/clients/dispatch/runners/index.js +5 -1
  58. package/dist/clients/dispatch/runners/lsp.js +14 -6
  59. package/dist/clients/dispatch/runners/markdownlint.js +4 -9
  60. package/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -1
  61. package/dist/clients/dispatch/runners/pyright.js +9 -5
  62. package/dist/clients/dispatch/runners/ruff.js +4 -8
  63. package/dist/clients/dispatch/runners/shellcheck.js +2 -3
  64. package/dist/clients/dispatch/runners/shfmt.js +2 -3
  65. package/dist/clients/dispatch/runners/spotbugs.js +2 -1
  66. package/dist/clients/dispatch/runners/taplo.js +2 -1
  67. package/dist/clients/dispatch/runners/terragrunt.js +163 -0
  68. package/dist/clients/dispatch/runners/tflint.js +37 -5
  69. package/dist/clients/dispatch/runners/tree-sitter.js +155 -166
  70. package/dist/clients/dispatch/runners/trivy-config.js +13 -7
  71. package/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  72. package/dist/clients/dispatch/runners/utils/runner-helpers.js +284 -34
  73. package/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  74. package/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  75. package/dist/clients/disposition-publish.js +10 -3
  76. package/dist/clients/durable-store.js +97 -0
  77. package/dist/clients/event-loop-monitor.js +94 -3
  78. package/dist/clients/extension-log.js +139 -0
  79. package/dist/clients/extension-mode.js +73 -0
  80. package/dist/clients/feature-hints.js +53 -7
  81. package/dist/clients/file-kinds.js +143 -31
  82. package/dist/clients/file-role.js +18 -3
  83. package/dist/clients/file-utils.js +56 -34
  84. package/dist/clients/fix-worklog.js +14 -2
  85. package/dist/clients/format-events-publish.js +16 -3
  86. package/dist/clients/format-service.js +24 -8
  87. package/dist/clients/formatters-lazy.js +8 -0
  88. package/dist/clients/formatters.js +358 -61
  89. package/dist/clients/generated-artifacts.js +169 -15
  90. package/dist/clients/git-guard.js +681 -11
  91. package/dist/clients/git-tracked-ignore.js +4 -0
  92. package/dist/clients/go-client.js +2 -1
  93. package/dist/clients/govulncheck-client.js +8 -0
  94. package/dist/clients/grammar-source.js +12 -4
  95. package/dist/clients/gzip-stage-write.js +102 -0
  96. package/dist/clients/host-ports.js +31 -0
  97. package/dist/clients/installer/index.js +733 -213
  98. package/dist/clients/instance-reaper.js +142 -172
  99. package/dist/clients/jscpd-client.js +31 -54
  100. package/dist/clients/knip-client.js +78 -36
  101. package/dist/clients/language-policy.js +14 -2
  102. package/dist/clients/language-profile.js +72 -77
  103. package/dist/clients/latency-logger.js +28 -16
  104. package/dist/clients/lens-config.js +140 -166
  105. package/dist/clients/lens-engine.js +124 -21
  106. package/dist/clients/lens-events.js +27 -4
  107. package/dist/clients/lens-flag-registry.js +293 -0
  108. package/dist/clients/lens-map.js +96 -26
  109. package/dist/clients/live-bus-emitter.js +30 -0
  110. package/dist/clients/log-cleanup.js +8 -18
  111. package/dist/clients/lsp/cascade-tier.js +23 -3
  112. package/dist/clients/lsp/client.js +566 -57
  113. package/dist/clients/lsp/config.js +74 -10
  114. package/dist/clients/lsp/diagnostic-binding.js +86 -0
  115. package/dist/clients/lsp/edits.js +1012 -121
  116. package/dist/clients/lsp/index.js +1840 -803
  117. package/dist/clients/lsp/language.js +4 -1
  118. package/dist/clients/lsp/launch.js +40 -32
  119. package/dist/clients/lsp/path-utils.js +1 -1
  120. package/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  121. package/dist/clients/lsp/server.js +279 -60
  122. package/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  123. package/dist/clients/lsp-document-symbols.js +112 -0
  124. package/dist/clients/lsp-lazy.js +8 -0
  125. package/dist/clients/lsp-mutation.js +248 -0
  126. package/dist/clients/mcp/analyze.js +128 -36
  127. package/dist/clients/mcp/ipc.js +157 -24
  128. package/dist/clients/mcp/review.js +36 -3
  129. package/dist/clients/mcp/session.js +216 -8
  130. package/dist/clients/memory-sampler.js +115 -0
  131. package/dist/clients/metrics-client.js +2 -1
  132. package/dist/clients/metrics-history.js +2 -1
  133. package/dist/clients/module-report-lsp.js +5 -0
  134. package/dist/clients/module-report.js +267 -82
  135. package/dist/clients/ndjson-logger.js +334 -103
  136. package/dist/clients/opengrep-client.js +1 -1
  137. package/dist/clients/partial-edit-apply.js +120 -5
  138. package/dist/clients/path-keyed-map.js +76 -0
  139. package/dist/clients/path-utils.js +141 -5
  140. package/dist/clients/performance-report.js +327 -0
  141. package/dist/clients/pipeline.js +54 -13
  142. package/dist/clients/print-mode.js +21 -0
  143. package/dist/clients/project-changes.js +117 -4
  144. package/dist/clients/project-diagnostics/cache.js +3 -2
  145. package/dist/clients/project-diagnostics/extractors.js +26 -115
  146. package/dist/clients/project-diagnostics/fresh-fetch.js +149 -19
  147. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +117 -0
  148. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +37 -5
  149. package/dist/clients/project-diagnostics/scanner.js +268 -128
  150. package/dist/clients/project-lens-config.js +138 -34
  151. package/dist/clients/project-report.js +64 -25
  152. package/dist/clients/project-scale.js +8 -10
  153. package/dist/clients/project-snapshot-persist-worker.js +6 -0
  154. package/dist/clients/project-snapshot.js +767 -8
  155. package/dist/clients/project-trust.js +181 -0
  156. package/dist/clients/quiet-window.js +27 -5
  157. package/dist/clients/read-bridge.js +147 -0
  158. package/dist/clients/read-expansion.js +22 -12
  159. package/dist/clients/read-guard-logger.js +159 -1
  160. package/dist/clients/read-guard-tool-lines.js +150 -29
  161. package/dist/clients/read-guard.js +262 -3
  162. package/dist/clients/redact/secrets.js +449 -0
  163. package/dist/clients/resource-sampler.js +144 -39
  164. package/dist/clients/reverse-deps.js +48 -0
  165. package/dist/clients/review-graph/builder.js +2570 -326
  166. package/dist/clients/review-graph/git-identity.js +2 -1
  167. package/dist/clients/review-graph/import-resolvers.js +21 -10
  168. package/dist/clients/review-graph/persist-worker.js +10 -0
  169. package/dist/clients/review-graph/query.js +5 -0
  170. package/dist/clients/review-graph/shared-extraction-ir.js +90 -0
  171. package/dist/clients/review-graph/symbol-id.js +46 -0
  172. package/dist/clients/review-graph/tsconfig-paths.js +57 -6
  173. package/dist/clients/review-graph/workspace-modules.js +51 -3
  174. package/dist/clients/review-graph-logger.js +53 -0
  175. package/dist/clients/ruff-client.js +27 -44
  176. package/dist/clients/runtime-agent-end.js +111 -75
  177. package/dist/clients/runtime-context.js +36 -12
  178. package/dist/clients/runtime-coordinator.js +76 -8
  179. package/dist/clients/runtime-session.js +799 -137
  180. package/dist/clients/runtime-tool-call.js +117 -62
  181. package/dist/clients/runtime-tool-result.js +218 -23
  182. package/dist/clients/runtime-turn.js +284 -40
  183. package/dist/clients/rust-client.js +2 -1
  184. package/dist/clients/safe-spawn.js +873 -71
  185. package/dist/clients/security-scan-client.js +2 -1
  186. package/dist/clients/session-start-observability.js +15 -0
  187. package/dist/clients/session-state-store.js +5 -3
  188. package/dist/clients/sessionstart-logger.js +18 -0
  189. package/dist/clients/sg-runner.js +284 -159
  190. package/dist/clients/slow-fs.js +2 -1
  191. package/dist/clients/smells-rollup.js +224 -0
  192. package/dist/clients/source-filter.js +231 -43
  193. package/dist/clients/source-walker.js +66 -10
  194. package/dist/clients/startup-scan.js +15 -16
  195. package/dist/clients/startup-timing.js +9 -0
  196. package/dist/clients/test-runner-client.js +38 -8
  197. package/dist/clients/todo-scanner.js +30 -3
  198. package/dist/clients/tool-event.js +35 -0
  199. package/dist/clients/tool-policy.js +388 -39
  200. package/dist/clients/tool-render.js +155 -0
  201. package/dist/clients/tree-sitter-cache.js +153 -140
  202. package/dist/clients/tree-sitter-client.js +1722 -80
  203. package/dist/clients/tree-sitter-logger.js +64 -1
  204. package/dist/clients/tree-sitter-query-loader.js +117 -12
  205. package/dist/clients/tree-sitter-shared.js +48 -19
  206. package/dist/clients/tree-sitter-symbol-extractor.js +115 -11
  207. package/dist/clients/user-notify.js +51 -0
  208. package/dist/clients/vanished-instance-marker.js +57 -0
  209. package/dist/clients/warm-attach.js +33 -13
  210. package/dist/clients/widget-state.js +342 -49
  211. package/dist/clients/word-index-logger.js +44 -0
  212. package/dist/clients/word-index.js +612 -68
  213. package/dist/clients/workspace-topology.js +100 -7
  214. package/dist/index.js +65923 -47161
  215. package/dist/mcp/analyze-cli.js +185 -29
  216. package/dist/mcp/cli.js +110 -0
  217. package/dist/mcp/server.js +272 -50
  218. package/dist/tools/ast-grep-search.js +93 -27
  219. package/dist/tools/lens-diagnostics.js +247 -41
  220. package/dist/tools/lsp-diagnostics.js +153 -40
  221. package/dist/tools/lsp-navigation.js +51 -31
  222. package/dist/tools/module-report.js +9 -0
  223. package/dist/tools/symbol-search.js +21 -2
  224. package/docs/agent-guide.md +247 -0
  225. package/docs/agent-tools.md +21 -10
  226. package/docs/analysisall.md +192 -0
  227. package/docs/api-ports-inventory.md +165 -0
  228. package/docs/ast-grep_rules_catalog.md +5 -2
  229. package/docs/astplayground.md +3 -4
  230. package/docs/audit1.md +5 -5
  231. package/docs/durable-store-audit-1202.md +32 -0
  232. package/docs/environment-variables.md +197 -11
  233. package/docs/fable.md +27 -0
  234. package/docs/features.md +35 -5
  235. package/docs/globalconfig.md +101 -5
  236. package/docs/language-coverage.md +6 -5
  237. package/docs/lsp-capability-matrix.md +2 -2
  238. package/docs/mcp.md +54 -20
  239. package/docs/servercapabilities.md +7 -4
  240. package/docs/settings.md +192 -0
  241. package/docs/tools.md +18 -1
  242. package/docs/tree-sitter_rules_catalog.md +11 -31
  243. package/docs/usage.md +31 -0
  244. package/package.json +139 -138
  245. package/rules/ast-grep-rules/rule-tests/hardcoded-url-js-test.yml +1 -0
  246. package/rules/ast-grep-rules/rule-tests/hardcoded-url-test.yml +2 -0
  247. package/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  248. package/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  249. package/rules/ast-grep-rules/rule-tests/no-case-declarations-js-test.yml +10 -0
  250. package/rules/ast-grep-rules/rule-tests/no-case-declarations-test.yml +10 -0
  251. package/rules/ast-grep-rules/rule-tests/no-javascript-url-js-test.yml +10 -0
  252. package/rules/ast-grep-rules/rule-tests/no-javascript-url-test.yml +10 -0
  253. package/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  254. package/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  255. package/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  256. package/rules/ast-grep-rules/rule-tests/strict-equality-js-test.yml +3 -0
  257. package/rules/ast-grep-rules/rule-tests/strict-equality-test.yml +3 -0
  258. package/rules/ast-grep-rules/rule-tests/strict-inequality-js-test.yml +3 -0
  259. package/rules/ast-grep-rules/rule-tests/strict-inequality-test.yml +4 -0
  260. package/rules/ast-grep-rules/rules/hardcoded-url-js.yml +22 -4
  261. package/rules/ast-grep-rules/rules/hardcoded-url.yml +22 -4
  262. package/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  263. package/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  264. package/rules/ast-grep-rules/rules/no-case-declarations-js.yml +4 -3
  265. package/rules/ast-grep-rules/rules/no-case-declarations.yml +4 -3
  266. package/rules/ast-grep-rules/rules/no-console-except-error-js.yml +10 -0
  267. package/rules/ast-grep-rules/rules/no-console-except-error.yml +10 -0
  268. package/rules/ast-grep-rules/rules/no-javascript-url-js.yml +42 -6
  269. package/rules/ast-grep-rules/rules/no-javascript-url.yml +42 -6
  270. package/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  271. package/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  272. package/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  273. package/rules/ast-grep-rules/rules/strict-equality-js.yml +14 -1
  274. package/rules/ast-grep-rules/rules/strict-equality.yml +14 -1
  275. package/rules/ast-grep-rules/rules/strict-inequality-js.yml +14 -1
  276. package/rules/ast-grep-rules/rules/strict-inequality.yml +14 -1
  277. package/rules/tree-sitter-queries/cpp/no-memset-sensitive-data.yml +9 -3
  278. package/rules/tree-sitter-queries/cpp/no-scoped-lock-without-args.yml +6 -6
  279. package/rules/tree-sitter-queries/css/calc-spacing.yml +8 -6
  280. package/rules/tree-sitter-queries/go/go-mutex-copy.yml +21 -18
  281. package/rules/tree-sitter-queries/go/go-shared-map-write-goroutine.yml +3 -3
  282. package/rules/tree-sitter-queries/java/infinite-loop-java.yml +3 -3
  283. package/rules/tree-sitter-queries/java/junit-call-super.yml +6 -4
  284. package/rules/tree-sitter-queries/java/no-double-checked-locking.yml +10 -8
  285. package/rules/tree-sitter-queries/java/no-field-shadowing.yml +1 -1
  286. package/rules/tree-sitter-queries/java/prepared-statement-valid-indices.yml +2 -3
  287. package/rules/tree-sitter-queries/java/resources-closed.yml +2 -2
  288. package/rules/tree-sitter-queries/java/springboot-default-package.yml +6 -3
  289. package/rules/tree-sitter-queries/java/switch-fall-through.yml +6 -4
  290. package/rules/tree-sitter-queries/java/switch-non-case-labels.yml +4 -3
  291. package/rules/tree-sitter-queries/java/tests-include-assertions.yml +6 -5
  292. package/rules/tree-sitter-queries/javascript/switch-case-termination-js.yml +5 -8
  293. package/rules/tree-sitter-queries/javascript/switch-non-case-labels.yml +3 -2
  294. package/rules/tree-sitter-queries/kotlin/prepared-statement-indices.yml +9 -5
  295. package/rules/tree-sitter-queries/php/this-in-static-context.yml +5 -5
  296. package/rules/tree-sitter-queries/python/exit-signature-check.yml +2 -9
  297. package/rules/tree-sitter-queries/python/in-operator-unsupported.yml +3 -4
  298. package/rules/tree-sitter-queries/python/no-super-torchscript.yml +4 -8
  299. package/rules/tree-sitter-queries/python/notimplemented-boolean-context.yml +1 -5
  300. package/rules/tree-sitter-queries/python/python-empty-except.yml +1 -1
  301. package/rules/tree-sitter-queries/python/return-in-init.yml +0 -2
  302. package/rules/tree-sitter-queries/python/yield-return-outside-function.yml +0 -3
  303. package/rules/tree-sitter-queries/ruby/ruby-command-injection.yml +1 -12
  304. package/rules/tree-sitter-queries/ruby/ruby-eval.yml +1 -1
  305. package/rules/tree-sitter-queries/ruby/ruby-insecure-deserialization.yml +4 -4
  306. package/rules/tree-sitter-queries/ruby/ruby-insecure-random.yml +4 -11
  307. package/rules/tree-sitter-queries/ruby/ruby-open-struct.yml +1 -1
  308. package/rules/tree-sitter-queries/ruby/ruby-string-eval.yml +2 -3
  309. package/rules/tree-sitter-queries/ruby/ruby-weak-hash.yml +4 -4
  310. package/rules/tree-sitter-queries/rust/rust-lock-held-across-await.yml +4 -3
  311. package/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  312. package/rules/tree-sitter-queries/typescript/console-statement.yml +11 -0
  313. package/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +4 -9
  314. package/rules/tree-sitter-queries/typescript/empty-switch-case.yml +13 -9
  315. package/rules/tree-sitter-queries/typescript/infinite-loop.yml +2 -2
  316. package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +10 -1
  317. package/rules/tree-sitter-queries/typescript/switch-case-termination.yml +5 -8
  318. package/rules/tree-sitter-queries/typescript/ts-insecure-random.yml +7 -10
  319. package/rules/tree-sitter-queries/typescript/unsafe-regex.yml +4 -2
  320. package/rules/typos/_typos.toml +17 -0
  321. package/scripts/analyze-pi-lens-logs.mjs +55 -2
  322. package/skills/pi-lens-write-tree-sitter-rule/SKILL.md +5 -0
  323. package/dist/clients/ast-grep-parser.js +0 -86
  324. package/dist/clients/config-enabled-shape.js +0 -39
  325. package/dist/clients/lsp/interactive-install.js +0 -367
  326. package/dist/clients/lsp/lsp-index.js +0 -10
  327. package/dist/clients/lsp/server-strategies.js +0 -5
  328. package/dist/clients/project-metadata.js +0 -690
  329. package/dist/clients/source-groups.js +0 -96
  330. package/dist/clients/types.js +0 -11
  331. package/docs/env_variables.md +0 -10
  332. package/rules/tree-sitter-queries/abap-disabled/delete-where.yml +0 -46
  333. package/rules/tree-sitter-queries/cpp/no-confused-move-forward.yml +0 -59
  334. package/rules/tree-sitter-queries/cpp/noexcept-functions.yml +0 -58
  335. package/rules/tree-sitter-queries/java/mockito-initialized.yml +0 -66
  336. package/rules/tree-sitter-queries/java/no-wait-notify-on-thread.yml +0 -58
  337. package/rules/tree-sitter-queries/java/short-circuit-logic.yml +0 -57
  338. package/rules/tree-sitter-queries/java/spring-session-attributes-setcomplete.yml +0 -75
  339. package/rules/tree-sitter-queries/plsql-disabled/delete-update-where.yml +0 -56
  340. package/rules/tree-sitter-queries/plsql-disabled/end-loop-semicolon.yml +0 -51
  341. package/rules/tree-sitter-queries/plsql-disabled/fetch-bulk-collect-limit.yml +0 -47
  342. package/rules/tree-sitter-queries/plsql-disabled/forallsave-exceptions.yml +0 -51
  343. package/rules/tree-sitter-queries/plsql-disabled/nchar-nvarchar2-bytes.yml +0 -54
  344. package/rules/tree-sitter-queries/plsql-disabled/not-null-initialization.yml +0 -59
  345. package/rules/tree-sitter-queries/plsql-disabled/raise-application-error-codes.yml +0 -50
  346. package/rules/tree-sitter-queries/typescript-disabled/ts-path-traversal.yml +0 -71
@@ -9,11 +9,56 @@ import * as fs from "node:fs";
9
9
  import * as path from "node:path";
10
10
  import { getProjectDataDir } from "../file-utils.js";
11
11
  import { readJsonCache } from "../json-cache-read.js";
12
- const CACHE_VERSION = "v3";
12
+ import { resolvePackagePath } from "../package-root.js";
13
+ import { writeFileAtomic } from "../atomic-write.js";
14
+ // v4: cache skip_test_files + fix_action — v3 entries silently dropped them,
15
+ // and ruleHash (rule-file mtimes) never invalidates on a code-only fix.
16
+ // v5 (#675): rule SELECTION changed in code — javascript no longer inherits the
17
+ // typescript rule set and tsx now does. A v4 entry holds the old merge, and
18
+ // queries now compile against the file's parse language, so replaying it would
19
+ // fire typescript rules on javascript trees for real this time.
20
+ // v6 (#878): the ruleHash FINGERPRINT now covers the full effective rule set —
21
+ // inherited rule-source directories (tsx also runs typescript rules), not just
22
+ // the language's own. A v5 tsx entry was hashed over tsx files only, so a
23
+ // typescript-rule edit never invalidated it; v5 entries self-miss anyway (the
24
+ // hash input set changed), the bump just makes the semantics break explicit.
25
+ // v7 (#1118): computeRuleHash now CONTENT-hashes project-local rule files
26
+ // instead of trusting mtime+size alone. mtime+size is the review-graph
27
+ // first-filter, not the full gold standard (size:mtimeMs + confirmContentChanged)
28
+ // — a rule-file edit that preserves both (git checkout timestamp restoration, a
29
+ // same-length tweak, a formatter that preserves mtime) replayed a stale
30
+ // compiled set from disk and re-persisted it under the still-matching
31
+ // fingerprint, poisoning every future process. The bump forces every v6 entry
32
+ // (hashed under the old metadata-only formula) to miss once on upgrade, so a
33
+ // silently-poisoned v6 entry can't be trusted by the new code.
34
+ export const CACHE_VERSION = "v7";
35
+ /**
36
+ * Bundled rule files ship with the extension and are immutable within a
37
+ * process — they can't change mid-session, so the cheap mtime+size
38
+ * fingerprint (v6's whole-set formula) is sufficient for them, and there are
39
+ * ~705 of them across all languages, so unconditionally reading+hashing their
40
+ * bytes on every edit would be the unconditional hot-path hashing the
41
+ * event-loop discipline forbids (RuleCache.get runs on the per-edit
42
+ * tree-sitter runner hot path).
43
+ *
44
+ * Project-local rule files (under `<project>/rules/tree-sitter-queries/`,
45
+ * see `ruleFilesForLanguage`) are the opposite: mutable, and a SMALL set (the
46
+ * handful a developer actually maintains) — cheap to content-hash. Splitting
47
+ * on this prefix mirrors the split `yaml-rule-parser.ts`/`ast-grep-napi.ts`
48
+ * already use for the ast-grep side of the same class (#1105): project-origin
49
+ * trees get a content-hash CONFIRM, bundled trees stay mtime-cheap.
50
+ */
51
+ const BUNDLED_RULES_ROOT = resolvePackagePath(import.meta.url, "rules", "tree-sitter-queries");
52
+ function isBundledRuleFile(resolvedFile) {
53
+ return (resolvedFile === BUNDLED_RULES_ROOT ||
54
+ resolvedFile.startsWith(BUNDLED_RULES_ROOT + path.sep));
55
+ }
13
56
  export class RuleCache {
14
57
  cacheFile;
15
58
  cacheDir;
59
+ language;
16
60
  constructor(language, rootDir = process.cwd()) {
61
+ this.language = language;
17
62
  this.cacheDir = path.join(getProjectDataDir(rootDir), "cache");
18
63
  this.cacheFile = path.join(this.cacheDir, `${language}-rules-${CACHE_VERSION}.json`);
19
64
  }
@@ -25,9 +70,19 @@ export class RuleCache {
25
70
  computeRuleHash(ruleFiles) {
26
71
  const hash = crypto.createHash("sha256");
27
72
  for (const file of ruleFiles.sort((a, b) => a.localeCompare(b))) {
28
- if (fs.existsSync(file)) {
29
- const stat = fs.statSync(file);
30
- hash.update(`${file}:${stat.mtimeMs}:${stat.size}`);
73
+ const resolved = path.resolve(file);
74
+ if (!fs.existsSync(resolved))
75
+ continue;
76
+ const stat = fs.statSync(resolved);
77
+ hash.update(`${file}:${stat.mtimeMs}:${stat.size}`);
78
+ // Content-CONFIRM only the project-local, mutable subset (a handful of
79
+ // files) — mtime+size alone is a first filter, not proof of freshness,
80
+ // and a preserved-mtime+size edit here would otherwise replay (and
81
+ // re-persist) a stale compiled set. Bundled files (~705, immutable
82
+ // within a process) skip this: the metadata fingerprint stays their
83
+ // whole story, keeping the common no-project-rules case as cheap as v6.
84
+ if (!isBundledRuleFile(resolved)) {
85
+ hash.update(fs.readFileSync(resolved));
31
86
  }
32
87
  }
33
88
  return hash.digest("hex").slice(0, 16);
@@ -40,7 +95,8 @@ export class RuleCache {
40
95
  const currentHash = this.computeRuleHash(ruleFiles);
41
96
  const cached = readJsonCache(this.cacheFile, (parsed) => {
42
97
  const entry = parsed;
43
- if (entry.version !== CACHE_VERSION || entry.ruleHash !== currentHash) {
98
+ if (entry.version !== CACHE_VERSION ||
99
+ entry.ruleHash !== currentHash) {
44
100
  return undefined; // Cache invalid
45
101
  }
46
102
  return entry;
@@ -60,12 +116,39 @@ export class RuleCache {
60
116
  ruleHash: this.computeRuleHash(ruleFiles),
61
117
  queries,
62
118
  };
63
- fs.writeFileSync(this.cacheFile, JSON.stringify(entry, null, 2));
119
+ writeFileAtomic(this.cacheFile, JSON.stringify(entry, null, 2));
120
+ this.pruneStaleVersions();
64
121
  }
65
122
  catch {
66
123
  // Cache write failure is non-fatal
67
124
  }
68
125
  }
126
+ // Orphaned `<language>-rules-v<N>.json` files from a prior CACHE_VERSION
127
+ // (e.g. v3 entries left behind by the #448 v3→v4 bump) never got cleaned up
128
+ // on their own — nothing ever read or removed them again once the version
129
+ // bumped. Delete every sibling for this language that isn't the current file.
130
+ pruneStaleVersions() {
131
+ const currentName = path.basename(this.cacheFile);
132
+ const pattern = new RegExp(`^${this.language}-rules-v\\d+\\.json$`);
133
+ let dirents;
134
+ try {
135
+ dirents = fs.readdirSync(this.cacheDir);
136
+ }
137
+ catch {
138
+ return;
139
+ }
140
+ for (const name of dirents) {
141
+ if (name === currentName || !pattern.test(name))
142
+ continue;
143
+ try {
144
+ fs.unlinkSync(path.join(this.cacheDir, name));
145
+ }
146
+ catch {
147
+ // Best-effort; ENOENT (already gone) or any other removal failure
148
+ // shouldn't undo the write that already succeeded above.
149
+ }
150
+ }
151
+ }
69
152
  clear() {
70
153
  try {
71
154
  if (fs.existsSync(this.cacheFile)) {
@@ -8,9 +8,11 @@
8
8
  *
9
9
  * All paths are relative to project root (process.cwd()).
10
10
  */
11
+ import { createSubsystemLogger } from "./extension-log.js";
11
12
  import * as fs from "node:fs";
12
13
  import * as path from "node:path";
13
14
  import { getProjectDataDir } from "./file-utils.js";
15
+ import { writeFileAtomic } from "./atomic-write.js";
14
16
  import { readJsonCache } from "./json-cache-read.js";
15
17
  import { normalizeMapKey } from "./path-utils.js";
16
18
  // --- Defaults ---
@@ -21,6 +23,8 @@ const DEFAULT_TURN_STATE = {
21
23
  maxCycles: 3,
22
24
  lastUpdated: "",
23
25
  };
26
+ export const MCP_TURN_STATE_OWNER_ID = `mcp-${process.pid}`;
27
+ const TURN_OWNER_STALE_MS = 30 * 60 * 1000;
24
28
  // --- Helpers ---
25
29
  function getLensDir(cwd) {
26
30
  return getProjectDataDir(cwd);
@@ -36,7 +40,7 @@ export class CacheManager {
36
40
  log;
37
41
  constructor(verbose = false) {
38
42
  this.log = verbose
39
- ? (msg) => console.error(`[cache] ${msg}`)
43
+ ? createSubsystemLogger("cache")
40
44
  : () => { };
41
45
  }
42
46
  /**
@@ -107,10 +111,45 @@ export class CacheManager {
107
111
  timestamp: new Date().toISOString(),
108
112
  ...extraMeta,
109
113
  };
110
- fs.writeFileSync(cachePath, JSON.stringify(data, null, 2));
111
- fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
114
+ writeFileAtomic(cachePath, JSON.stringify(data, null, 2), {
115
+ bestEffort: false,
116
+ });
117
+ writeFileAtomic(metaPath, JSON.stringify(meta, null, 2), {
118
+ bestEffort: false,
119
+ });
112
120
  this.log(`Cache written: ${scanner}`);
113
121
  }
122
+ /** Inspect a cache without changing the behavior of readCache consumers. */
123
+ inspectCache(scanner, cwd, maxAgeMs = DEFAULT_MAX_AGE_MS) {
124
+ const cachePath = path.join(getCacheDir(cwd), `${scanner}.json`);
125
+ const metaPath = path.join(getCacheDir(cwd), `${scanner}.meta.json`);
126
+ for (const cachePathname of [cachePath, metaPath]) {
127
+ try {
128
+ fs.statSync(cachePathname);
129
+ }
130
+ catch (err) {
131
+ if (err.code === "ENOENT")
132
+ return "missing";
133
+ return "unreadable";
134
+ }
135
+ }
136
+ try {
137
+ const meta = readJsonCache(metaPath, (parsed) => parsed);
138
+ if (!meta || typeof meta.timestamp !== "string")
139
+ return "malformed";
140
+ const timestamp = new Date(meta.timestamp).getTime();
141
+ if (!Number.isFinite(timestamp))
142
+ return "malformed";
143
+ const age = Date.now() - timestamp;
144
+ if (age < 0 || age > maxAgeMs)
145
+ return age < 0 ? "malformed" : "stale";
146
+ const data = readJsonCache(cachePath, (parsed) => parsed);
147
+ return data === undefined ? "malformed" : "fresh";
148
+ }
149
+ catch {
150
+ return "unreadable";
151
+ }
152
+ }
114
153
  /**
115
154
  * Check if a cache entry is fresh (exists and not expired).
116
155
  */
@@ -175,16 +214,57 @@ export class CacheManager {
175
214
  fs.mkdirSync(lensDir, { recursive: true });
176
215
  const statePath = getTurnStatePath(cwd);
177
216
  state.lastUpdated = new Date().toISOString();
178
- fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
217
+ writeFileAtomic(statePath, JSON.stringify(state, null, 2));
218
+ }
219
+ /** Return whether a writer may read/write this workspace worklist. */
220
+ getTurnStateAccess(cwd, owner) {
221
+ const state = this.readTurnState(cwd);
222
+ if (!state.owner) {
223
+ if (!state.sessionId || state.sessionId === owner.id)
224
+ return "owned";
225
+ // Pre-owner files have no liveness information. Preserve the existing
226
+ // stale-session eviction behavior for this legacy shape.
227
+ return "available";
228
+ }
229
+ if (state.owner.kind === owner.kind &&
230
+ state.owner.id === owner.id) {
231
+ return "owned";
232
+ }
233
+ return this.isTurnStateOwnerStale(state.owner) ? "available" : "foreign-live";
234
+ }
235
+ isTurnStateOwnerStale(owner) {
236
+ if (owner.pid > 0 && owner.pid !== process.pid) {
237
+ try {
238
+ process.kill(owner.pid, 0);
239
+ return false;
240
+ }
241
+ catch {
242
+ return true;
243
+ }
244
+ }
245
+ const lastSeen = Date.parse(owner.lastSeen);
246
+ return !Number.isFinite(lastSeen) || Date.now() - lastSeen > TURN_OWNER_STALE_MS;
179
247
  }
180
248
  /**
181
249
  * Add or update a file's modified ranges in turn state.
182
- * Merges overlapping ranges.
250
+ * Merges overlapping ranges. `sessionId:null` deliberately preserves the
251
+ * current owner; callers must provide an explicit owner id to claim a stale
252
+ * worklist.
183
253
  */
184
- addModifiedRange(filePath, range, importsChanged, cwd, sessionId) {
254
+ addModifiedRange(filePath, range, importsChanged, cwd, sessionId, ownerKind = "pi") {
185
255
  const state = this.readTurnState(cwd);
186
- if (sessionId)
256
+ if (sessionId) {
257
+ const owner = {
258
+ kind: ownerKind,
259
+ id: sessionId,
260
+ pid: process.pid,
261
+ lastSeen: new Date().toISOString(),
262
+ };
263
+ if (this.getTurnStateAccess(cwd, owner) === "foreign-live")
264
+ return state;
187
265
  state.sessionId = sessionId;
266
+ state.owner = owner;
267
+ }
188
268
  const normalizedPath = this.toTurnStateKey(filePath, cwd);
189
269
  const existing = state.files[normalizedPath];
190
270
  if (existing) {
@@ -209,19 +289,27 @@ export class CacheManager {
209
289
  /**
210
290
  * Clear turn state (after turn_end processes it).
211
291
  */
212
- clearTurnState(cwd) {
292
+ clearTurnState(cwd, owner) {
293
+ const currentState = this.readTurnState(cwd);
294
+ const isCurrentOwner = this.getTurnStateAccess(cwd, owner) !== "foreign-live";
295
+ if (!isCurrentOwner && process.pid !== currentState.owner?.pid)
296
+ return false;
213
297
  const state = {
214
298
  ...DEFAULT_TURN_STATE,
215
299
  files: {}, // fresh object — DEFAULT_TURN_STATE.files can be polluted by addModifiedRange
216
300
  lastUpdated: new Date().toISOString(),
217
301
  };
218
302
  this.writeTurnState(state, cwd);
303
+ return true;
219
304
  }
220
305
  /**
221
306
  * Increment turn cycle counter.
222
307
  */
223
- incrementTurnCycle(cwd) {
308
+ incrementTurnCycle(cwd, owner) {
224
309
  const state = this.readTurnState(cwd);
310
+ const isCurrentOwner = this.getTurnStateAccess(cwd, owner) !== "foreign-live";
311
+ if (!isCurrentOwner && process.pid !== state.owner?.pid)
312
+ return state;
225
313
  state.turnCycles++;
226
314
  this.writeTurnState(state, cwd);
227
315
  return state;