pi-lens 4.1.2 → 4.1.4

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 (359) hide show
  1. package/CHANGELOG.md +1308 -0
  2. package/README.md +3 -0
  3. package/config/biome/core.jsonc +11 -2
  4. package/config/dependency-cruiser-eager-allowlist.json +91 -0
  5. package/dist/clients/actionable-warnings-logger.js +18 -3
  6. package/dist/clients/actionable-warnings.js +927 -80
  7. package/dist/clients/agent-behavior-client.js +13 -4
  8. package/dist/clients/ast-grep-client.js +136 -9
  9. package/dist/clients/ast-grep-rule-manager.js +60 -5
  10. package/dist/clients/ast-grep-tool-logger.js +2 -2
  11. package/dist/clients/availability-probe-flight.js +12 -0
  12. package/dist/clients/bash-file-access.js +1 -3
  13. package/dist/clients/biome-client.js +16 -2
  14. package/dist/clients/blocker-freshness.js +34 -0
  15. package/dist/clients/bootstrap.js +509 -73
  16. package/dist/clients/bounded-cache.js +152 -12
  17. package/dist/clients/bounded-telemetry.js +115 -23
  18. package/dist/clients/build-identity.js +95 -0
  19. package/dist/clients/bundled-resource-health.js +113 -0
  20. package/dist/clients/bus-events-logger.js +2 -2
  21. package/dist/clients/bus-publish.js +3 -0
  22. package/dist/clients/cache/rule-cache.js +33 -5
  23. package/dist/clients/cache-manager.js +105 -6
  24. package/dist/clients/cache-observability.js +46 -19
  25. package/dist/clients/cargo-manifest.js +422 -0
  26. package/dist/clients/cascade-logger.js +17 -3
  27. package/dist/clients/code-quality-warnings.js +13 -3
  28. package/dist/clients/complexity-client.js +16 -5
  29. package/dist/clients/config-core/deny.js +221 -0
  30. package/dist/clients/config-core/index.js +47 -0
  31. package/dist/clients/config-core/merge.js +357 -0
  32. package/dist/clients/config-core/normalize.js +340 -0
  33. package/dist/clients/config-core/process-spec.js +248 -0
  34. package/dist/clients/config-core/provenance.js +171 -0
  35. package/dist/clients/config-core/records.js +218 -0
  36. package/dist/clients/config-core/resolve.js +125 -0
  37. package/dist/clients/config-core/safe-object.js +78 -0
  38. package/dist/clients/config-core/schema.js +167 -0
  39. package/dist/clients/config-diagnostic-codes.js +281 -0
  40. package/dist/clients/config-locations.js +160 -0
  41. package/dist/clients/config-resolve.js +789 -0
  42. package/dist/clients/config-schema.js +197 -0
  43. package/dist/clients/config-warn.js +407 -0
  44. package/dist/clients/dead-code-client.js +33 -25
  45. package/dist/clients/dead-code-logger.js +2 -2
  46. package/dist/clients/deadline-utils.js +178 -0
  47. package/dist/clients/debug-handles.js +2 -2
  48. package/dist/clients/debug-heap.js +3 -3
  49. package/dist/clients/deferred-lsp-work.js +106 -0
  50. package/dist/clients/degradation-ledger.js +166 -8
  51. package/dist/clients/demoted-finding-render.js +14 -0
  52. package/dist/clients/dependency-checker.js +28 -22
  53. package/dist/clients/deps/minimatch.js +1 -1
  54. package/dist/clients/diagnostic-line-freshness.js +12 -9
  55. package/dist/clients/diagnostic-logger.js +14 -4
  56. package/dist/clients/dispatch/collect-later-tier.js +39 -0
  57. package/dist/clients/dispatch/dispatcher.js +304 -19
  58. package/dist/clients/dispatch/fact-store.js +328 -9
  59. package/dist/clients/dispatch/integration.js +214 -107
  60. package/dist/clients/dispatch/pending-runner-findings.js +87 -0
  61. package/dist/clients/dispatch/plan.js +21 -5
  62. package/dist/clients/dispatch/runners/actionlint.js +0 -1
  63. package/dist/clients/dispatch/runners/ast-grep-napi.js +550 -77
  64. package/dist/clients/dispatch/runners/biome-check.js +0 -1
  65. package/dist/clients/dispatch/runners/cpp-check.js +0 -1
  66. package/dist/clients/dispatch/runners/credo.js +0 -1
  67. package/dist/clients/dispatch/runners/cue-vet.js +0 -1
  68. package/dist/clients/dispatch/runners/dart-analyze.js +0 -1
  69. package/dist/clients/dispatch/runners/detekt.js +0 -1
  70. package/dist/clients/dispatch/runners/dotnet-build.js +0 -1
  71. package/dist/clients/dispatch/runners/elixir-check.js +0 -1
  72. package/dist/clients/dispatch/runners/eslint.js +5 -2
  73. package/dist/clients/dispatch/runners/fact-rules.js +0 -1
  74. package/dist/clients/dispatch/runners/fish-indent.js +0 -1
  75. package/dist/clients/dispatch/runners/gleam-check.js +0 -1
  76. package/dist/clients/dispatch/runners/go-vet.js +1 -3
  77. package/dist/clients/dispatch/runners/golangci-lint.js +0 -1
  78. package/dist/clients/dispatch/runners/hadolint.js +0 -1
  79. package/dist/clients/dispatch/runners/helm-lint.js +16 -4
  80. package/dist/clients/dispatch/runners/helm-render.js +54 -10
  81. package/dist/clients/dispatch/runners/htmlhint.js +0 -1
  82. package/dist/clients/dispatch/runners/index.js +1 -3
  83. package/dist/clients/dispatch/runners/javac.js +0 -1
  84. package/dist/clients/dispatch/runners/ktlint.js +0 -1
  85. package/dist/clients/dispatch/runners/lsp.js +37 -2
  86. package/dist/clients/dispatch/runners/markdownlint.js +4 -2
  87. package/dist/clients/dispatch/runners/mypy.js +0 -1
  88. package/dist/clients/dispatch/runners/oxlint.js +24 -22
  89. package/dist/clients/dispatch/runners/php-lint.js +0 -1
  90. package/dist/clients/dispatch/runners/phpstan.js +0 -1
  91. package/dist/clients/dispatch/runners/prisma-validate.js +0 -1
  92. package/dist/clients/dispatch/runners/psscriptanalyzer.js +4 -1
  93. package/dist/clients/dispatch/runners/pyright.js +7 -4
  94. package/dist/clients/dispatch/runners/rubocop.js +0 -1
  95. package/dist/clients/dispatch/runners/ruff.js +0 -1
  96. package/dist/clients/dispatch/runners/rust-clippy.js +9 -6
  97. package/dist/clients/dispatch/runners/shellcheck.js +0 -1
  98. package/dist/clients/dispatch/runners/shfmt.js +0 -1
  99. package/dist/clients/dispatch/runners/spellcheck.js +0 -1
  100. package/dist/clients/dispatch/runners/spotbugs.js +0 -1
  101. package/dist/clients/dispatch/runners/sqlfluff.js +0 -1
  102. package/dist/clients/dispatch/runners/stylelint.js +0 -1
  103. package/dist/clients/dispatch/runners/swiftlint.js +0 -1
  104. package/dist/clients/dispatch/runners/taplo.js +0 -1
  105. package/dist/clients/dispatch/runners/terragrunt.js +0 -1
  106. package/dist/clients/dispatch/runners/tflint.js +0 -1
  107. package/dist/clients/dispatch/runners/tree-sitter.js +0 -1
  108. package/dist/clients/dispatch/runners/trivy-config.js +0 -1
  109. package/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
  110. package/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -4
  111. package/dist/clients/dispatch/runners/utils/runner-helpers.js +270 -105
  112. package/dist/clients/dispatch/runners/utils/spawn-outcome.js +4 -0
  113. package/dist/clients/dispatch/runners/utils/tool-failure.js +19 -7
  114. package/dist/clients/dispatch/runners/utils/toolchain-availability.js +89 -26
  115. package/dist/clients/dispatch/runners/vale.js +0 -1
  116. package/dist/clients/dispatch/runners/yaml-rule-parser.js +51 -17
  117. package/dist/clients/dispatch/runners/yamllint.js +0 -1
  118. package/dist/clients/dispatch/runners/zig-check.js +0 -1
  119. package/dist/clients/disposition-logger.js +3 -3
  120. package/dist/clients/effective-config.js +403 -0
  121. package/dist/clients/error-class.js +23 -0
  122. package/dist/clients/event-loop-hold.js +274 -0
  123. package/dist/clients/event-loop-monitor.js +66 -1
  124. package/dist/clients/extension-log.js +2 -2
  125. package/dist/clients/feature-hints.js +2 -1
  126. package/dist/clients/file-time.js +6 -1
  127. package/dist/clients/file-utils.js +266 -13
  128. package/dist/clients/finding-delivery-gate.js +55 -13
  129. package/dist/clients/format-service.js +6 -1
  130. package/dist/clients/formatters.js +303 -104
  131. package/dist/clients/freshness-cadence.js +17 -0
  132. package/dist/clients/generated-artifacts.js +114 -19
  133. package/dist/clients/generation-guard.js +4 -9
  134. package/dist/clients/git-guard.js +198 -48
  135. package/dist/clients/git-tracked-ignore.js +32 -1
  136. package/dist/clients/go-client.js +39 -0
  137. package/dist/clients/govulncheck-client.js +5 -1
  138. package/dist/clients/gradle-ktfmt-style.js +252 -0
  139. package/dist/clients/gzip-stage-write.js +7 -0
  140. package/dist/clients/hashline-anchor.js +424 -0
  141. package/dist/clients/hook-budgets.js +76 -0
  142. package/dist/clients/host-edit-normalize.js +5 -2
  143. package/dist/clients/host-ports.js +1 -1
  144. package/dist/clients/installer/index.js +200 -84
  145. package/dist/clients/installer/managed-tool-refresh.js +3 -1
  146. package/dist/clients/instance-reaper.js +108 -243
  147. package/dist/clients/instance-registry-lock.js +145 -0
  148. package/dist/clients/instance-registry.js +435 -122
  149. package/dist/clients/jscpd-client.js +6 -1
  150. package/dist/clients/language-profile.js +4 -2
  151. package/dist/clients/language-registry.js +595 -0
  152. package/dist/clients/latency-logger.js +179 -3
  153. package/dist/clients/ledger-bounds.js +13 -0
  154. package/dist/clients/lens-config.js +141 -30
  155. package/dist/clients/lens-engine.js +30 -37
  156. package/dist/clients/lens-flag-registry.js +67 -6
  157. package/dist/clients/lens-map.js +3 -1
  158. package/dist/clients/log-cleanup.js +2 -2
  159. package/dist/clients/lsp/aggregation.js +3 -1
  160. package/dist/clients/lsp/cascade-tier.js +4 -0
  161. package/dist/clients/lsp/client.js +672 -49
  162. package/dist/clients/lsp/config.js +504 -156
  163. package/dist/clients/lsp/diagnostic-binding.js +10 -5
  164. package/dist/clients/lsp/edits.js +15 -2
  165. package/dist/clients/lsp/index.js +1179 -247
  166. package/dist/clients/lsp/jvm-runtime.js +5 -0
  167. package/dist/clients/lsp/language.js +18 -169
  168. package/dist/clients/lsp/launch.js +38 -9
  169. package/dist/clients/lsp/pending-aux-coverage.js +113 -12
  170. package/dist/clients/lsp/server.js +426 -160
  171. package/dist/clients/lsp/session-roots.js +192 -0
  172. package/dist/clients/lsp/spawn-history.js +2 -7
  173. package/dist/clients/lsp/tsserver-sync.js +9 -2
  174. package/dist/clients/lsp/workspace-diagnostics-cache.js +17 -7
  175. package/dist/clients/lsp/workspace-sweep-hold.js +32 -23
  176. package/dist/clients/lsp-mutation.js +179 -23
  177. package/dist/clients/map-with-concurrency.js +36 -0
  178. package/dist/clients/mcp/analyze.js +45 -10
  179. package/dist/clients/mcp/session.js +19 -17
  180. package/dist/clients/memory-sampler.js +28 -1
  181. package/dist/clients/message-end-attribution.js +30 -0
  182. package/dist/clients/metrics-history.js +21 -4
  183. package/dist/clients/middle-man-analysis.js +2 -4
  184. package/dist/clients/module-report.js +20 -45
  185. package/dist/clients/mutating-tool.js +651 -0
  186. package/dist/clients/mutation-attribution.js +368 -0
  187. package/dist/clients/mutation-bridge.js +240 -0
  188. package/dist/clients/ndjson-logger.js +247 -20
  189. package/dist/clients/observed-mutation-sources.js +101 -0
  190. package/dist/clients/observed-mutation.js +1215 -0
  191. package/dist/clients/opaque-mutation-scan.js +300 -40
  192. package/dist/clients/opengrep-config.js +4 -0
  193. package/dist/clients/package-manager.js +201 -44
  194. package/dist/clients/partial-edit-apply.js +359 -80
  195. package/dist/clients/path-attribution-telemetry.js +23 -7
  196. package/dist/clients/path-keyed-map.js +35 -3
  197. package/dist/clients/path-utils.js +460 -13
  198. package/dist/clients/persist-debounce.js +8 -1
  199. package/dist/clients/php-cs-fixer-config.js +114 -0
  200. package/dist/clients/pipeline.js +77 -24
  201. package/dist/clients/probe-home-state.js +228 -0
  202. package/dist/clients/process-bridge.js +66 -0
  203. package/dist/clients/process-singletons.js +210 -0
  204. package/dist/clients/process-snapshot.js +68 -0
  205. package/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
  206. package/dist/clients/project-diagnostics/runner-adapters/madge.js +2 -1
  207. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
  208. package/dist/clients/project-diagnostics/scanner.js +61 -24
  209. package/dist/clients/project-lens-config.js +393 -122
  210. package/dist/clients/project-snapshot.js +85 -35
  211. package/dist/clients/python-environment.js +217 -0
  212. package/dist/clients/python-provenance.js +639 -0
  213. package/dist/clients/quiet-window.js +6 -1
  214. package/dist/clients/read-bridge.js +13 -21
  215. package/dist/clients/read-expansion.js +9 -46
  216. package/dist/clients/read-guard-logger.js +39 -6
  217. package/dist/clients/read-guard-tool-lines.js +364 -212
  218. package/dist/clients/read-guard.js +95 -7
  219. package/dist/clients/recent-touches.js +17 -5
  220. package/dist/clients/resource-sampler.js +195 -96
  221. package/dist/clients/review-graph/builder.js +752 -132
  222. package/dist/clients/review-graph/service.js +55 -3
  223. package/dist/clients/review-graph/shared-extraction-ir.js +7 -15
  224. package/dist/clients/review-graph/tsconfig-paths.js +5 -1
  225. package/dist/clients/review-graph/workspace-modules.js +10 -74
  226. package/dist/clients/review-graph-logger.js +30 -4
  227. package/dist/clients/runtime-agent-end.js +18 -2
  228. package/dist/clients/runtime-context.js +49 -16
  229. package/dist/clients/runtime-coordinator.js +93 -6
  230. package/dist/clients/runtime-session.js +169 -34
  231. package/dist/clients/runtime-tool-call.js +183 -35
  232. package/dist/clients/runtime-tool-result.js +894 -241
  233. package/dist/clients/runtime-turn.js +1264 -74
  234. package/dist/clients/rust-client.js +31 -0
  235. package/dist/clients/safe-spawn.js +191 -28
  236. package/dist/clients/sanitize.js +7 -1
  237. package/dist/clients/scratch-tree-policy.js +1 -3
  238. package/dist/clients/security-scan-client.js +51 -17
  239. package/dist/clients/session-lifecycle.js +238 -42
  240. package/dist/clients/session-start-observability.js +79 -0
  241. package/dist/clients/sessionstart-logger.js +12 -3
  242. package/dist/clients/sg-runner.js +27 -15
  243. package/dist/clients/sgconfig.js +6 -1
  244. package/dist/clients/shared-checkout-guard.js +338 -0
  245. package/dist/clients/skills-resolver.js +105 -0
  246. package/dist/clients/smells-rollup.js +2 -2
  247. package/dist/clients/spawn-output-cap.js +37 -0
  248. package/dist/clients/spawn-timeout-cooldown.js +15 -1
  249. package/dist/clients/startup-scan.js +6 -7
  250. package/dist/clients/startup-timing.js +69 -4
  251. package/dist/clients/string-utils.js +33 -0
  252. package/dist/clients/subagent-mode.js +17 -4
  253. package/dist/clients/test-runner-client.js +586 -118
  254. package/dist/clients/test-runner-delivery.js +239 -0
  255. package/dist/clients/tool-definition.js +41 -1
  256. package/dist/clients/tool-policy.js +92 -22
  257. package/dist/clients/tree-sitter-cache.js +40 -40
  258. package/dist/clients/tree-sitter-client.js +97 -53
  259. package/dist/clients/tree-sitter-logger.js +19 -3
  260. package/dist/clients/tree-sitter-query-loader.js +81 -1
  261. package/dist/clients/tree-sitter-shared.js +51 -46
  262. package/dist/clients/tree-sitter-symbol-extractor.js +28 -0
  263. package/dist/clients/typos-config.js +5 -0
  264. package/dist/clients/user-notify.js +6 -2
  265. package/dist/clients/warm-attach.js +8 -10
  266. package/dist/clients/widget-state.js +191 -26
  267. package/dist/clients/word-index-logger.js +15 -3
  268. package/dist/clients/word-index-store.js +463 -0
  269. package/dist/clients/word-index.js +815 -125
  270. package/dist/clients/workspace-topology.js +25 -1
  271. package/dist/clients/zizmor-config.js +29 -6
  272. package/dist/index.js +68577 -53950
  273. package/dist/mcp/analyze-cli.js +3 -1
  274. package/dist/mcp/build-staleness.js +8 -7
  275. package/dist/mcp/cli.js +3 -1
  276. package/dist/mcp/server.js +133 -6
  277. package/dist/scripts/lib/process-scan.mjs +583 -0
  278. package/dist/scripts/lib/skills-predicate.mjs +129 -0
  279. package/dist/tools/effective-config.js +89 -0
  280. package/dist/tools/lens-diagnostics.js +99 -24
  281. package/dist/tools/lsp-diagnostics.js +81 -85
  282. package/dist/tools/lsp-navigation.js +40 -17
  283. package/dist/tools/shared.js +0 -1
  284. package/docs/agent-guide.md +68 -3
  285. package/docs/ast-grep_rules_catalog.md +41 -10
  286. package/docs/astplayground.md +26 -17
  287. package/docs/configuration.md +222 -0
  288. package/docs/dependencies.md +3 -3
  289. package/docs/features.md +44 -5
  290. package/docs/language-coverage.md +2 -2
  291. package/docs/pi-lens-fixer.md +25 -0
  292. package/docs/pi-lens-investigator.md +25 -0
  293. package/docs/pi-lens-reviewer.md +27 -0
  294. package/docs/pi-lens-subagent.md +38 -0
  295. package/docs/pi-lens-warden.md +55 -0
  296. package/docs/public-api-stability.md +359 -0
  297. package/docs/release-qa-baseline.md +182 -0
  298. package/docs/subagent-compat.md +110 -30
  299. package/docs/tree-sitter_rules_catalog.md +2 -2
  300. package/package.json +17 -21
  301. package/rules/ast-grep-rules/rule-tests/c-no-malloc-free-test.yml +20 -0
  302. package/rules/ast-grep-rules/rule-tests/cpp-no-malloc-free-test.yml +25 -0
  303. package/rules/ast-grep-rules/rule-tests/cpp-no-printf-test.yml +19 -0
  304. package/rules/ast-grep-rules/rule-tests/go-no-fmt-println-test.yml +19 -0
  305. package/rules/ast-grep-rules/rule-tests/go-no-panic-in-lib-test.yml +17 -0
  306. package/rules/ast-grep-rules/rule-tests/go-no-underscore-func-name-test.yml +18 -0
  307. package/rules/ast-grep-rules/rule-tests/go-prefer-errors-is-test.yml +15 -0
  308. package/rules/ast-grep-rules/rule-tests/go-prefer-string-builder-test.yml +21 -0
  309. package/rules/ast-grep-rules/rule-tests/hyphenated-svg-attribute-test.yml +11 -0
  310. package/rules/ast-grep-rules/rule-tests/kotlin-no-lateinit-test.yml +17 -0
  311. package/rules/ast-grep-rules/rule-tests/kotlin-no-nullable-boolean-test.yml +15 -0
  312. package/rules/ast-grep-rules/rule-tests/kotlin-no-println-test.yml +19 -0
  313. package/rules/ast-grep-rules/rule-tests/kotlin-no-unnecessary-let-test.yml +7 -0
  314. package/rules/ast-grep-rules/rule-tests/kotlin-no-unsafe-cast-test.yml +7 -0
  315. package/rules/ast-grep-rules/rule-tests/kotlin-no-var-test.yml +7 -0
  316. package/rules/ast-grep-rules/rule-tests/kotlin-prefer-data-class-test.yml +25 -0
  317. package/rules/ast-grep-rules/rule-tests/kotlin-prefer-is-empty-test.yml +11 -0
  318. package/rules/ast-grep-rules/rule-tests/no-important-test.yml +21 -0
  319. package/rules/ast-grep-rules/rule-tests/no-raw-types-test.yml +30 -0
  320. package/rules/ast-grep-rules/rule-tests/no-string-concat-in-loop-test.yml +100 -0
  321. package/rules/ast-grep-rules/rule-tests/no-system-out-println-test.yml +7 -0
  322. package/rules/ast-grep-rules/rule-tests/prefer-string-is-empty-test.yml +7 -0
  323. package/rules/ast-grep-rules/rule-tests/python-optional-type-test.yml +9 -0
  324. package/rules/ast-grep-rules/rule-tests/reducible-list-comprehension-test.yml +11 -0
  325. package/rules/ast-grep-rules/rule-tests/ruby-symbol-to-proc-candidate-test.yml +10 -0
  326. package/rules/ast-grep-rules/rule-tests/rust-no-chars-enumerate-test.yml +7 -0
  327. package/rules/ast-grep-rules/rules/c-no-malloc-free.yml +39 -0
  328. package/rules/ast-grep-rules/rules/cpp-no-malloc-free.yml +45 -0
  329. package/rules/ast-grep-rules/rules/cpp-no-printf.yml +41 -0
  330. package/rules/ast-grep-rules/rules/go-no-fmt-println.yml +43 -0
  331. package/rules/ast-grep-rules/rules/go-no-panic-in-lib.yml +41 -0
  332. package/rules/ast-grep-rules/rules/go-no-underscore-func-name.yml +35 -0
  333. package/rules/ast-grep-rules/rules/go-prefer-errors-is.yml +40 -0
  334. package/rules/ast-grep-rules/rules/go-prefer-string-builder.yml +43 -0
  335. package/rules/ast-grep-rules/rules/hyphenated-svg-attribute.yml +32 -0
  336. package/rules/ast-grep-rules/rules/kotlin-no-lateinit.yml +37 -0
  337. package/rules/ast-grep-rules/rules/kotlin-no-nullable-boolean.yml +33 -0
  338. package/rules/ast-grep-rules/rules/kotlin-no-println.yml +42 -0
  339. package/rules/ast-grep-rules/rules/kotlin-no-unnecessary-let.yml +28 -0
  340. package/rules/ast-grep-rules/rules/kotlin-no-unsafe-cast.yml +28 -0
  341. package/rules/ast-grep-rules/rules/kotlin-no-var.yml +35 -0
  342. package/rules/ast-grep-rules/rules/kotlin-prefer-data-class.yml +66 -0
  343. package/rules/ast-grep-rules/rules/kotlin-prefer-is-empty.yml +35 -0
  344. package/rules/ast-grep-rules/rules/no-important.yml +21 -0
  345. package/rules/ast-grep-rules/rules/no-raw-types.yml +33 -0
  346. package/rules/ast-grep-rules/rules/no-string-concat-in-loop.yml +90 -0
  347. package/rules/ast-grep-rules/rules/no-system-out-println.yml +16 -0
  348. package/rules/ast-grep-rules/rules/prefer-string-is-empty.yml +11 -0
  349. package/rules/ast-grep-rules/rules/python-optional-type.yml +22 -0
  350. package/rules/ast-grep-rules/rules/reducible-list-comprehension.yml +29 -0
  351. package/rules/ast-grep-rules/rules/ruby-symbol-to-proc-candidate.yml +25 -0
  352. package/rules/ast-grep-rules/rules/rust-no-chars-enumerate.yml +19 -0
  353. package/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
  354. package/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
  355. package/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
  356. package/scripts/analyze-pi-lens-logs.mjs +192 -1
  357. package/scripts/install-selftest.mjs +58 -2
  358. package/scripts/lib/skills-predicate.mjs +129 -0
  359. package/scripts/rpc-load-check.mjs +3 -1
@@ -0,0 +1,252 @@
1
+ /**
2
+ * ktfmt Gradle-plugin style carriage (#2468).
3
+ *
4
+ * The `com.ncorti.ktfmt.gradle` plugin's `ktfmt { }` extension block lets a
5
+ * project select `googleStyle()` or `kotlinLangStyle()` (verified against
6
+ * `KtfmtExtension.kt` in `cortinico/ktfmt-gradle` at
7
+ * `23bdedc8d5d641731a0cf128f1a386d5a127ce4e` — those two are the only style
8
+ * functions it defines today, and both are plain setters over
9
+ * `blockIndent`/`continuationIndent`/`trailingCommaManagementStrategy`, so a
10
+ * body calling both is LAST-CALL-WINS, not first).
11
+ *
12
+ * None of this is read by ktfmt's own CLI from `build.gradle` — verified
13
+ * against `ParsedArgs.kt` in `facebook/ktfmt` (now mirrored at
14
+ * `Kotlin/ktfmt`) at tag v0.63, the exact version `clients/installer/
15
+ * index.ts` pins for pi-lens's managed ktfmt install. That CLI accepts
16
+ * `--google-style` / `--kotlinlang-style` (plus the default `--meta-style`)
17
+ * — so the Gradle-declared choice has to be translated to the matching CLI
18
+ * flag by something on our side; ktfmt itself never bridges `build.gradle`
19
+ * to argv.
20
+ *
21
+ * Reuses the exact lexical pre-pass (`stripGradleCommentsAndStrings` /
22
+ * `namedGradleBlockRanges`) that `clients/tool-policy.ts`'s
23
+ * `getSpotlessKotlinFormatter` already applies to Gradle files, instead of a
24
+ * second hand-rolled Gradle-block parser (#2468 AC) — same
25
+ * single-source-of-truth reuse `clients/cargo-manifest.ts` did for TOML
26
+ * parsing in `clients/formatters.ts`'s rustfmt `--edition` carriage (#2466).
27
+ *
28
+ * ## Project scoping (#2468 review rounds 2 and 3)
29
+ *
30
+ * A Gradle build file configures more than the directory it sits in, and the
31
+ * multi-module layout the plugin is actually used in puts the style in the
32
+ * ROOT build file while each module's own `build.gradle(.kts)` declares only
33
+ * its plugins. Round 1 stopped the ancestor climb at the first directory
34
+ * holding ANY gradle file and matched `ktfmt {` anywhere in it, which was
35
+ * wrong in both directions: a module inherited nothing (the #2468 defect
36
+ * survived for the common layout) while the ROOT's own sources were handed a
37
+ * `subprojects { }`-scoped style that Gradle never applies to them. This
38
+ * module therefore classifies each `ktfmt { }` block by the block ENCLOSING
39
+ * it — the actual brace nesting on the stripped source, not a single
40
+ * hard-coded name test — and climbs past directories that declare no style
41
+ * for the project being formatted:
42
+ *
43
+ * - no enclosing block (a top-level `ktfmt { }`) → the DECLARING directory
44
+ * only. Gradle does not inherit here: the plugin gives each project its own
45
+ * `KtfmtExtension` instance seeded with the plugin conventions (verified at
46
+ * the SHA above), so a module that applies the plugin and calls no style
47
+ * function really does format under ktfmt's default — which is exactly the
48
+ * bare invocation this resolver falls back to. Round 2 spread a top-level
49
+ * block over style-less descendants as a documented heuristic; that
50
+ * manufactured a NEW pi-lens/Gradle disagreement (pi-lens writes
51
+ * `--google-style`, `./gradlew ktfmtCheck` then rejects the file pi-lens
52
+ * just formatted) which the pre-#2468 bare invocation did not have, so it
53
+ * is gone. Aligning with `hasKtfmtConfig`'s wider climb does not justify
54
+ * it: that election answers "is ktfmt the formatter for this file", not
55
+ * "which style"; where Gradle carries no style down, the bare invocation IS
56
+ * the correct carriage of `--meta-style`.
57
+ * - `subprojects { ktfmt { … } }` → DESCENDANT directories only, never the
58
+ * declaring one. `subprojects` configures the children and nothing else.
59
+ * - `allprojects { ktfmt { … } }` → the declaring directory AND descendants.
60
+ * - anything else enclosing it — `configure(subprojects.filter { … }) { }`,
61
+ * `project(":app") { }`, `tasks.register(…) { }`, a convention-plugin
62
+ * wrapper, or more than one nested block — reaches NEITHER scope. pi-lens
63
+ * cannot evaluate a build script, so a scope it cannot compute fails closed
64
+ * to the bare invocation rather than being granted to every project.
65
+ *
66
+ * KNOWN GAP (#2468 review round 3, F3): the first gradle directory found by
67
+ * the climb is treated as the project that OWNS the file. A module directory
68
+ * that is `include(…)`d by `settings.gradle(.kts)` but holds NO build file of
69
+ * its own therefore resolves hop 0 to an ANCESTOR, and asks it for `own`
70
+ * scope when `descendants` is what Gradle would apply. Against a root
71
+ * `subprojects { ktfmt { … } }` this is a fail-safe miss — no flag, the
72
+ * pre-#2468 bare invocation — because `subprojects` only ever fills the
73
+ * `descendants` slot, which hop 0 never reads. But against a root's
74
+ * TOP-LEVEL `ktfmt { }` (`own` scope, by the table above) it is a WRONG
75
+ * flag: hop 0 reads `own` regardless of which project it actually belongs
76
+ * to, so the module is handed the ROOT's own style even though Gradle gives
77
+ * the module its own `KtfmtExtension` and applies no style there. Closing it
78
+ * means reading `settings.gradle`'s `include(…)` list to map a directory to
79
+ * a Gradle project, which this module does not do.
80
+ */
81
+ import * as os from "node:os";
82
+ import * as path from "node:path";
83
+ import { readTextFileOrUndefined } from "./cargo-manifest.js";
84
+ import { findNearestMarkerRoot } from "./path-utils.js";
85
+ import { gradleBlockRanges, stripGradleCommentsAndStrings, } from "./tool-policy.js";
86
+ /** Nearest-first: a Kotlin script build file wins over its Groovy sibling. */
87
+ const KTFMT_GRADLE_ROOT_FILES = [
88
+ "build.gradle.kts",
89
+ "build.gradle",
90
+ "settings.gradle.kts",
91
+ "settings.gradle",
92
+ ];
93
+ /**
94
+ * Ancestor gradle directories consulted before giving up. Each hop costs at
95
+ * most four small reads, and Gradle builds nest a handful of levels at most;
96
+ * the cap keeps a pathological tree (or a symlink cycle that survives
97
+ * `path.dirname`) from turning one format into an unbounded walk. The
98
+ * `homeDir` ceiling inside `findNearestMarkerRoot` normally ends the climb
99
+ * long before this.
100
+ */
101
+ const MAX_GRADLE_ANCESTOR_HOPS = 16;
102
+ /** The CLI flags ktfmt v0.63 actually defines (`ParsedArgs.kt`, verified above). */
103
+ const KTFMT_STYLE_CLI_FLAG = {
104
+ google: "--google-style",
105
+ kotlinlang: "--kotlinlang-style",
106
+ };
107
+ /**
108
+ * Read the style declared by one `ktfmt { }` block body, LAST call wins.
109
+ *
110
+ * `googleStyle()` and `kotlinLangStyle()` both just `.set(...)` the same
111
+ * three extension properties, so in `ktfmt { googleStyle(); kotlinLangStyle() }`
112
+ * the second call is the one whose values survive into the format (verified
113
+ * against `KtfmtExtension.kt`, SHA above). `undefined` means the block
114
+ * declares no recognized style call — including the `dropboxStyle()` that
115
+ * ktfmt-gradle removed in 0.19.0 and ktfmt's CLI never exposed a flag for,
116
+ * which is simply not a style this resolver can carry.
117
+ */
118
+ function styleFromKtfmtBlockBody(body) {
119
+ let style;
120
+ let lastIndex = -1;
121
+ for (const [call, candidate] of [
122
+ [/\bgoogleStyle\s*\(\s*\)/g, "google"],
123
+ [/\bkotlinLangStyle\s*\(\s*\)/g, "kotlinlang"],
124
+ ]) {
125
+ for (const match of body.matchAll(call)) {
126
+ if (match.index > lastIndex) {
127
+ lastIndex = match.index;
128
+ style = candidate;
129
+ }
130
+ }
131
+ }
132
+ return style;
133
+ }
134
+ /**
135
+ * The Gradle blocks whose scope is exactly expressible here. Every other
136
+ * enclosing block — including one we simply have not heard of — is a scope
137
+ * pi-lens cannot evaluate, and is NOT silently promoted to project-wide.
138
+ */
139
+ const SCOPE_BY_ENCLOSING_BLOCK = {
140
+ subprojects: "descendants",
141
+ allprojects: "both",
142
+ };
143
+ /**
144
+ * Classify one `ktfmt { }` block by the block that encloses it.
145
+ *
146
+ * `blocks` is every brace pair in the stripped source, so "enclosing" is
147
+ * literal containment, not a guess from a name test: `range` strictly inside
148
+ * `outer` means `outer.start < range.start` (an enclosing body always opens
149
+ * before the body it contains) and `outer.end >= range.end`.
150
+ *
151
+ * More than one enclosing block (`subprojects { afterEvaluate { ktfmt { } } }`)
152
+ * fails closed too. Composing scopes through an arbitrary intermediate is
153
+ * exactly the kind of build-script evaluation this lexical pass cannot do,
154
+ * and the cost of the conservative answer is the pre-#2468 bare invocation.
155
+ */
156
+ function scopeOfKtfmtBlock(range, blocks) {
157
+ const enclosing = blocks.filter((outer) => outer.start < range.start && outer.end >= range.end);
158
+ if (enclosing.length === 0)
159
+ return "own";
160
+ if (enclosing.length > 1)
161
+ return undefined;
162
+ return SCOPE_BY_ENCLOSING_BLOCK[enclosing[0].name];
163
+ }
164
+ function stylesFromGradleContent(content) {
165
+ const stripped = stripGradleCommentsAndStrings(content);
166
+ const blocks = gradleBlockRanges(stripped);
167
+ const styles = {};
168
+ // Source order, so a later block overwrites an earlier one for the scope
169
+ // it reaches — the same last-call-wins rule that applies inside one body.
170
+ // Each scope is written independently: two blocks that reach DISJOINT sets
171
+ // of projects (a `subprojects { }` one and a top-level one) must not fight
172
+ // over a single slot, or the source order of unrelated scopes decides
173
+ // which project gets the wrong flag.
174
+ for (const range of blocks) {
175
+ if (range.name !== "ktfmt")
176
+ continue;
177
+ const scope = scopeOfKtfmtBlock(range, blocks);
178
+ if (!scope)
179
+ continue;
180
+ const style = styleFromKtfmtBlockBody(stripped.slice(range.start, range.end));
181
+ if (!style)
182
+ continue;
183
+ if (scope !== "descendants")
184
+ styles.own = style;
185
+ if (scope !== "own")
186
+ styles.descendants = style;
187
+ }
188
+ return styles;
189
+ }
190
+ async function stylesForGradleDir(gradleDir) {
191
+ for (const gradleFile of KTFMT_GRADLE_ROOT_FILES) {
192
+ const content = await readTextFileOrUndefined(path.join(gradleDir, gradleFile));
193
+ if (content === undefined)
194
+ continue;
195
+ const styles = stylesFromGradleContent(content);
196
+ if (styles.own || styles.descendants)
197
+ return styles;
198
+ }
199
+ return {};
200
+ }
201
+ /**
202
+ * Resolve the ktfmt CLI style flag (`--google-style` / `--kotlinlang-style`)
203
+ * for the Gradle project that owns `filePath`, so a caller that needs it
204
+ * doesn't have ktfmt silently apply its own default style
205
+ * (`--meta-style`-equivalent) where the project's `ktfmt { }` block picked a
206
+ * different one (#2468 — the same manifest-detected-but-not-carried defect
207
+ * shape #2466 fixed for rustfmt `--edition`).
208
+ *
209
+ * - Finds the nearest directory containing a `build.gradle(.kts)`/
210
+ * `settings.gradle(.kts)` file via the shared `findNearestMarkerRoot`
211
+ * walker (home-ceiling guarded, depth-capped — AGENTS.md
212
+ * walk-confinement; never a private walk-up loop). That first directory is
213
+ * TAKEN to be the project that OWNS the file, so its `own`-scope
214
+ * declaration applies; every further hop is an ancestor, so only its
215
+ * `descendants`-scope declaration does. See the module header's KNOWN GAP
216
+ * note for the `include(…)`-only module directory where that
217
+ * identification is wrong — a missed flag against a `subprojects { }` root,
218
+ * but a WRONG flag (the root's own style) against a root TOP-LEVEL one.
219
+ * - A nested module's OWN style declaration still wins over an ancestor's —
220
+ * the climb only continues past a gradle directory that declares NO style
221
+ * applying to this file, so nearest-wins is unchanged where a nearer
222
+ * declaration exists.
223
+ * - Returns `undefined` on any miss (no gradle file found, no `ktfmt { }`
224
+ * block, or no recognized style call in one): callers fall back to their
225
+ * pre-existing default argv rather than guessing. `dropboxStyle()` — the
226
+ * call ktfmt-gradle removed in 0.19.0, never a ktfmt CLI flag — is just
227
+ * such a miss and never becomes a guessed flag.
228
+ *
229
+ * `homeDir` defaults to `os.homedir()` and exists as a parameter so tests can
230
+ * inject a nearer ceiling and prove the guard actually stops a climb (mirrors
231
+ * `resolveCargoPackageEdition`'s `homeDir` parameter, #2466 review round 2,
232
+ * F5) — production callers never pass it.
233
+ */
234
+ export async function resolveKtfmtGradleStyle(filePath, homeDir = os.homedir()) {
235
+ let searchDir = path.dirname(path.resolve(filePath));
236
+ for (let hop = 0; hop < MAX_GRADLE_ANCESTOR_HOPS; hop += 1) {
237
+ const gradleDir = findNearestMarkerRoot(searchDir, KTFMT_GRADLE_ROOT_FILES, {
238
+ homeDir,
239
+ });
240
+ if (!gradleDir)
241
+ return undefined;
242
+ const styles = await stylesForGradleDir(gradleDir);
243
+ const style = hop === 0 ? styles.own : styles.descendants;
244
+ if (style)
245
+ return KTFMT_STYLE_CLI_FLAG[style];
246
+ const parent = path.dirname(gradleDir);
247
+ if (parent === gradleDir)
248
+ return undefined;
249
+ searchDir = parent;
250
+ }
251
+ return undefined;
252
+ }
@@ -39,6 +39,10 @@ import { stagePathFor } from "./atomic-write-staging.js";
39
39
  * to a main-thread rewrite on an error result).
40
40
  */
41
41
  export async function writeGzipStageFile(data, stagePath, testDelayMs, options) {
42
+ // Worker-path duration starts inside this stage, so it includes the worker's
43
+ // test delay, serialization, gzip, and rename, but excludes postMessage queue
44
+ // latency. Main-thread callers measure from their inclusive persist entry.
45
+ const startedAt = performance.now();
42
46
  const tmpPath = stagePathFor(stagePath);
43
47
  try {
44
48
  if (testDelayMs) {
@@ -56,6 +60,7 @@ export async function writeGzipStageFile(data, stagePath, testDelayMs, options)
56
60
  gzBytes: 0,
57
61
  serializeMs,
58
62
  writeMs: 0,
63
+ durationMs: performance.now() - startedAt,
59
64
  semanticFingerprint,
60
65
  skippedUnchanged: true,
61
66
  };
@@ -77,6 +82,7 @@ export async function writeGzipStageFile(data, stagePath, testDelayMs, options)
77
82
  gzBytes,
78
83
  serializeMs,
79
84
  writeMs,
85
+ durationMs: performance.now() - startedAt,
80
86
  semanticFingerprint,
81
87
  };
82
88
  }
@@ -116,6 +122,7 @@ export function serveGzipStageWorker(buildBaseResult, options) {
116
122
  result.gzBytes = metrics.gzBytes;
117
123
  result.serializeMs = metrics.serializeMs;
118
124
  result.writeMs = metrics.writeMs;
125
+ result.durationMs = metrics.durationMs;
119
126
  result.semanticFingerprint = metrics.semanticFingerprint;
120
127
  result.skippedUnchanged = metrics.skippedUnchanged;
121
128
  }