@duckmind/dm-linux-x64 0.65.8 → 0.66.2

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 (549) hide show
  1. package/dm +2 -2
  2. package/extensions/.dm-extensions.json +14 -548
  3. package/extensions/dm-lens/clients/dispatch/runners/utils/runner-helpers.js +1 -1
  4. package/extensions/dm-mcp-adapter/mcp-keyring-helper.cjs +1 -1
  5. package/extensions/dm-ponytail/hooks/ponytail-activate.js +1 -1
  6. package/extensions/dm-ponytail/hooks/ponytail-instructions.js +1 -1
  7. package/extensions/dm-subagents/src/extension/tool-activation.js +7 -2
  8. package/extensions/dm-subagents/src/runs/background/runner-aliases.js +2 -2
  9. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +4 -1
  10. package/extensions/dm-subagents/src/runs/shared/child-session.js +8 -6
  11. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +5 -1
  12. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +9 -1
  13. package/extensions/dm-subagents/src/watchdog/review.js +4 -1
  14. package/extensions/dm-web-access/tool-activation.js +0 -1
  15. package/package.json +1 -1
  16. package/extensions/dm-lens/dist/clients/actionable-warnings-logger.js +0 -24
  17. package/extensions/dm-lens/dist/clients/actionable-warnings.js +0 -1014
  18. package/extensions/dm-lens/dist/clients/advisory-provenance.js +0 -385
  19. package/extensions/dm-lens/dist/clients/agent-behavior-client.js +0 -94
  20. package/extensions/dm-lens/dist/clients/agent-nudge.js +0 -151
  21. package/extensions/dm-lens/dist/clients/analysed-root.js +0 -1
  22. package/extensions/dm-lens/dist/clients/ast-grep-client.js +0 -576
  23. package/extensions/dm-lens/dist/clients/ast-grep-rule-manager.js +0 -114
  24. package/extensions/dm-lens/dist/clients/ast-grep-tool-logger.js +0 -85
  25. package/extensions/dm-lens/dist/clients/ast-grep-types.js +0 -1
  26. package/extensions/dm-lens/dist/clients/ast-grep-yaml-synth.js +0 -109
  27. package/extensions/dm-lens/dist/clients/atomic-write-staging.js +0 -66
  28. package/extensions/dm-lens/dist/clients/atomic-write.js +0 -37
  29. package/extensions/dm-lens/dist/clients/availability-probe-flight.js +0 -11
  30. package/extensions/dm-lens/dist/clients/bash-file-access.js +0 -830
  31. package/extensions/dm-lens/dist/clients/biome-client.js +0 -221
  32. package/extensions/dm-lens/dist/clients/blocker-freshness.js +0 -385
  33. package/extensions/dm-lens/dist/clients/blocker-past-eof.js +0 -49
  34. package/extensions/dm-lens/dist/clients/bootstrap.js +0 -246
  35. package/extensions/dm-lens/dist/clients/bounded-cache.js +0 -105
  36. package/extensions/dm-lens/dist/clients/bounded-pid-file-lock.js +0 -173
  37. package/extensions/dm-lens/dist/clients/bounded-telemetry.js +0 -104
  38. package/extensions/dm-lens/dist/clients/build-identity.js +0 -45
  39. package/extensions/dm-lens/dist/clients/bundled-resource-health.js +0 -41
  40. package/extensions/dm-lens/dist/clients/bus-events-logger.js +0 -48
  41. package/extensions/dm-lens/dist/clients/bus-publish.js +0 -117
  42. package/extensions/dm-lens/dist/clients/cache/rule-cache.js +0 -103
  43. package/extensions/dm-lens/dist/clients/cache-manager.js +0 -340
  44. package/extensions/dm-lens/dist/clients/cache-observability.js +0 -847
  45. package/extensions/dm-lens/dist/clients/call-graph.js +0 -628
  46. package/extensions/dm-lens/dist/clients/cargo-manifest.js +0 -151
  47. package/extensions/dm-lens/dist/clients/cascade-budget.js +0 -52
  48. package/extensions/dm-lens/dist/clients/cascade-format.js +0 -160
  49. package/extensions/dm-lens/dist/clients/cascade-logger.js +0 -22
  50. package/extensions/dm-lens/dist/clients/cascade-types.js +0 -1
  51. package/extensions/dm-lens/dist/clients/child-unref.js +0 -59
  52. package/extensions/dm-lens/dist/clients/code-quality-warnings.js +0 -192
  53. package/extensions/dm-lens/dist/clients/codebase-model.js +0 -110
  54. package/extensions/dm-lens/dist/clients/collateral-test-role.js +0 -8
  55. package/extensions/dm-lens/dist/clients/complexity-client.js +0 -398
  56. package/extensions/dm-lens/dist/clients/config-core/deny.js +0 -117
  57. package/extensions/dm-lens/dist/clients/config-core/index.js +0 -2
  58. package/extensions/dm-lens/dist/clients/config-core/merge.js +0 -228
  59. package/extensions/dm-lens/dist/clients/config-core/normalize.js +0 -217
  60. package/extensions/dm-lens/dist/clients/config-core/process-spec.js +0 -147
  61. package/extensions/dm-lens/dist/clients/config-core/provenance.js +0 -54
  62. package/extensions/dm-lens/dist/clients/config-core/records.js +0 -79
  63. package/extensions/dm-lens/dist/clients/config-core/resolve.js +0 -48
  64. package/extensions/dm-lens/dist/clients/config-core/safe-object.js +0 -22
  65. package/extensions/dm-lens/dist/clients/config-core/schema.js +0 -90
  66. package/extensions/dm-lens/dist/clients/config-diagnostic-codes.js +0 -90
  67. package/extensions/dm-lens/dist/clients/config-locations.js +0 -175
  68. package/extensions/dm-lens/dist/clients/config-resolve.js +0 -359
  69. package/extensions/dm-lens/dist/clients/config-schema.js +0 -128
  70. package/extensions/dm-lens/dist/clients/config-warn.js +0 -146
  71. package/extensions/dm-lens/dist/clients/console-guard-install.js +0 -4
  72. package/extensions/dm-lens/dist/clients/cooperative-budget.js +0 -36
  73. package/extensions/dm-lens/dist/clients/dead-code-client.js +0 -342
  74. package/extensions/dm-lens/dist/clients/dead-code-logger.js +0 -18
  75. package/extensions/dm-lens/dist/clients/deadline-utils.js +0 -117
  76. package/extensions/dm-lens/dist/clients/debug-handles.js +0 -121
  77. package/extensions/dm-lens/dist/clients/debug-heap.js +0 -80
  78. package/extensions/dm-lens/dist/clients/deferred-lsp-work.js +0 -33
  79. package/extensions/dm-lens/dist/clients/degradation-ledger.js +0 -272
  80. package/extensions/dm-lens/dist/clients/demoted-finding-render.js +0 -61
  81. package/extensions/dm-lens/dist/clients/dependency-checker.js +0 -525
  82. package/extensions/dm-lens/dist/clients/deps/ast-grep-napi.js +0 -17
  83. package/extensions/dm-lens/dist/clients/deps/dm-host-deps.js +0 -10
  84. package/extensions/dm-lens/dist/clients/deps/dm-tui-compat.js +0 -58
  85. package/extensions/dm-lens/dist/clients/deps/js-yaml.js +0 -7
  86. package/extensions/dm-lens/dist/clients/deps/minimatch.js +0 -6
  87. package/extensions/dm-lens/dist/clients/deps/pidusage.js +0 -5
  88. package/extensions/dm-lens/dist/clients/deps/typebox.js +0 -5
  89. package/extensions/dm-lens/dist/clients/deps/vscode-jsonrpc.js +0 -8
  90. package/extensions/dm-lens/dist/clients/deps/web-tree-sitter.js +0 -11
  91. package/extensions/dm-lens/dist/clients/diagnostic-dispositions.js +0 -318
  92. package/extensions/dm-lens/dist/clients/diagnostic-line-freshness.js +0 -144
  93. package/extensions/dm-lens/dist/clients/diagnostic-logger.js +0 -60
  94. package/extensions/dm-lens/dist/clients/diagnostic-tracker.js +0 -89
  95. package/extensions/dm-lens/dist/clients/diagnostics-publish.js +0 -134
  96. package/extensions/dm-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -16
  97. package/extensions/dm-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -158
  98. package/extensions/dm-lens/dist/clients/dispatch/collect-later-tier.js +0 -25
  99. package/extensions/dm-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -58
  100. package/extensions/dm-lens/dist/clients/dispatch/dispatcher.js +0 -953
  101. package/extensions/dm-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
  102. package/extensions/dm-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
  103. package/extensions/dm-lens/dist/clients/dispatch/fact-runner.js +0 -18
  104. package/extensions/dm-lens/dist/clients/dispatch/fact-scheduler.js +0 -52
  105. package/extensions/dm-lens/dist/clients/dispatch/fact-store.js +0 -199
  106. package/extensions/dm-lens/dist/clients/dispatch/facts/comment-facts.js +0 -20
  107. package/extensions/dm-lens/dist/clients/dispatch/facts/file-content.js +0 -18
  108. package/extensions/dm-lens/dist/clients/dispatch/facts/function-facts.js +0 -281
  109. package/extensions/dm-lens/dist/clients/dispatch/facts/import-facts.js +0 -169
  110. package/extensions/dm-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -19
  111. package/extensions/dm-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -95
  112. package/extensions/dm-lens/dist/clients/dispatch/finding-policy.js +0 -159
  113. package/extensions/dm-lens/dist/clients/dispatch/indent-detect.js +0 -227
  114. package/extensions/dm-lens/dist/clients/dispatch/inline-suppressions.js +0 -52
  115. package/extensions/dm-lens/dist/clients/dispatch/integration.js +0 -1463
  116. package/extensions/dm-lens/dist/clients/dispatch/lazy.js +0 -8
  117. package/extensions/dm-lens/dist/clients/dispatch/pending-runner-findings.js +0 -75
  118. package/extensions/dm-lens/dist/clients/dispatch/plan.js +0 -278
  119. package/extensions/dm-lens/dist/clients/dispatch/priorities.js +0 -14
  120. package/extensions/dm-lens/dist/clients/dispatch/rule-id-normalize.js +0 -42
  121. package/extensions/dm-lens/dist/clients/dispatch/rule-ignores.js +0 -21
  122. package/extensions/dm-lens/dist/clients/dispatch/rule-policy.js +0 -73
  123. package/extensions/dm-lens/dist/clients/dispatch/rules/async-noise.js +0 -31
  124. package/extensions/dm-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  125. package/extensions/dm-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -35
  126. package/extensions/dm-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -29
  127. package/extensions/dm-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -29
  128. package/extensions/dm-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -31
  129. package/extensions/dm-lens/dist/clients/dispatch/rules/high-complexity.js +0 -56
  130. package/extensions/dm-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -45
  131. package/extensions/dm-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -31
  132. package/extensions/dm-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -45
  133. package/extensions/dm-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -46
  134. package/extensions/dm-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -38
  135. package/extensions/dm-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  136. package/extensions/dm-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -101
  137. package/extensions/dm-lens/dist/clients/dispatch/runner-context.js +0 -46
  138. package/extensions/dm-lens/dist/clients/dispatch/runners/actionlint.js +0 -98
  139. package/extensions/dm-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -690
  140. package/extensions/dm-lens/dist/clients/dispatch/runners/biome-check.js +0 -202
  141. package/extensions/dm-lens/dist/clients/dispatch/runners/cpp-check.js +0 -190
  142. package/extensions/dm-lens/dist/clients/dispatch/runners/credo.js +0 -66
  143. package/extensions/dm-lens/dist/clients/dispatch/runners/cue-vet.js +0 -167
  144. package/extensions/dm-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -151
  145. package/extensions/dm-lens/dist/clients/dispatch/runners/detekt.js +0 -157
  146. package/extensions/dm-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -157
  147. package/extensions/dm-lens/dist/clients/dispatch/runners/elixir-check.js +0 -153
  148. package/extensions/dm-lens/dist/clients/dispatch/runners/eslint.js +0 -99
  149. package/extensions/dm-lens/dist/clients/dispatch/runners/fact-rules.js +0 -20
  150. package/extensions/dm-lens/dist/clients/dispatch/runners/fish-indent.js +0 -65
  151. package/extensions/dm-lens/dist/clients/dispatch/runners/gleam-check.js +0 -107
  152. package/extensions/dm-lens/dist/clients/dispatch/runners/go-vet.js +0 -51
  153. package/extensions/dm-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -89
  154. package/extensions/dm-lens/dist/clients/dispatch/runners/hadolint.js +0 -83
  155. package/extensions/dm-lens/dist/clients/dispatch/runners/helm-lint.js +0 -144
  156. package/extensions/dm-lens/dist/clients/dispatch/runners/helm-render.js +0 -593
  157. package/extensions/dm-lens/dist/clients/dispatch/runners/htmlhint.js +0 -103
  158. package/extensions/dm-lens/dist/clients/dispatch/runners/index.js +0 -100
  159. package/extensions/dm-lens/dist/clients/dispatch/runners/javac.js +0 -82
  160. package/extensions/dm-lens/dist/clients/dispatch/runners/ktlint.js +0 -93
  161. package/extensions/dm-lens/dist/clients/dispatch/runners/lsp.js +0 -206
  162. package/extensions/dm-lens/dist/clients/dispatch/runners/markdownlint.js +0 -129
  163. package/extensions/dm-lens/dist/clients/dispatch/runners/mypy.js +0 -70
  164. package/extensions/dm-lens/dist/clients/dispatch/runners/oxlint.js +0 -305
  165. package/extensions/dm-lens/dist/clients/dispatch/runners/php-lint.js +0 -70
  166. package/extensions/dm-lens/dist/clients/dispatch/runners/phpstan.js +0 -90
  167. package/extensions/dm-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -56
  168. package/extensions/dm-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -307
  169. package/extensions/dm-lens/dist/clients/dispatch/runners/pyright.js +0 -118
  170. package/extensions/dm-lens/dist/clients/dispatch/runners/rubocop.js +0 -79
  171. package/extensions/dm-lens/dist/clients/dispatch/runners/ruff.js +0 -69
  172. package/extensions/dm-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -147
  173. package/extensions/dm-lens/dist/clients/dispatch/runners/shellcheck.js +0 -111
  174. package/extensions/dm-lens/dist/clients/dispatch/runners/shfmt.js +0 -81
  175. package/extensions/dm-lens/dist/clients/dispatch/runners/spellcheck.js +0 -74
  176. package/extensions/dm-lens/dist/clients/dispatch/runners/spotbugs.js +0 -208
  177. package/extensions/dm-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -136
  178. package/extensions/dm-lens/dist/clients/dispatch/runners/stylelint.js +0 -118
  179. package/extensions/dm-lens/dist/clients/dispatch/runners/swiftlint.js +0 -143
  180. package/extensions/dm-lens/dist/clients/dispatch/runners/taplo.js +0 -97
  181. package/extensions/dm-lens/dist/clients/dispatch/runners/terragrunt.js +0 -110
  182. package/extensions/dm-lens/dist/clients/dispatch/runners/tflint.js +0 -104
  183. package/extensions/dm-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -516
  184. package/extensions/dm-lens/dist/clients/dispatch/runners/trivy-config.js +0 -155
  185. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -285
  186. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -61
  187. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -61
  188. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -130
  189. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1067
  190. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -40
  191. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -117
  192. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -88
  193. package/extensions/dm-lens/dist/clients/dispatch/runners/utils.js +0 -8
  194. package/extensions/dm-lens/dist/clients/dispatch/runners/vale.js +0 -106
  195. package/extensions/dm-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -163
  196. package/extensions/dm-lens/dist/clients/dispatch/runners/yamllint.js +0 -83
  197. package/extensions/dm-lens/dist/clients/dispatch/runners/zig-check.js +0 -72
  198. package/extensions/dm-lens/dist/clients/dispatch/suppress-writer.js +0 -57
  199. package/extensions/dm-lens/dist/clients/dispatch/tool-profile.js +0 -30
  200. package/extensions/dm-lens/dist/clients/dispatch/types.js +0 -7
  201. package/extensions/dm-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
  202. package/extensions/dm-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -31
  203. package/extensions/dm-lens/dist/clients/disposition-logger.js +0 -19
  204. package/extensions/dm-lens/dist/clients/disposition-publish.js +0 -88
  205. package/extensions/dm-lens/dist/clients/durable-store.js +0 -77
  206. package/extensions/dm-lens/dist/clients/effective-config.js +0 -160
  207. package/extensions/dm-lens/dist/clients/env-utils.js +0 -26
  208. package/extensions/dm-lens/dist/clients/error-class.js +0 -3
  209. package/extensions/dm-lens/dist/clients/eval-timestamp.js +0 -2
  210. package/extensions/dm-lens/dist/clients/event-loop-hold.js +0 -119
  211. package/extensions/dm-lens/dist/clients/event-loop-monitor.js +0 -84
  212. package/extensions/dm-lens/dist/clients/extension-log.js +0 -230
  213. package/extensions/dm-lens/dist/clients/extension-mode.js +0 -20
  214. package/extensions/dm-lens/dist/clients/feature-hints.js +0 -88
  215. package/extensions/dm-lens/dist/clients/file-kinds.js +0 -304
  216. package/extensions/dm-lens/dist/clients/file-role.js +0 -50
  217. package/extensions/dm-lens/dist/clients/file-time.js +0 -112
  218. package/extensions/dm-lens/dist/clients/file-utils.js +0 -630
  219. package/extensions/dm-lens/dist/clients/finding-delivery-gate.js +0 -129
  220. package/extensions/dm-lens/dist/clients/finding-identity.js +0 -23
  221. package/extensions/dm-lens/dist/clients/fix-worklog.js +0 -75
  222. package/extensions/dm-lens/dist/clients/format-events-publish.js +0 -230
  223. package/extensions/dm-lens/dist/clients/format-service.js +0 -154
  224. package/extensions/dm-lens/dist/clients/formatters-lazy.js +0 -8
  225. package/extensions/dm-lens/dist/clients/formatters.js +0 -1351
  226. package/extensions/dm-lens/dist/clients/freshness-cadence.js +0 -1
  227. package/extensions/dm-lens/dist/clients/freshness.js +0 -8
  228. package/extensions/dm-lens/dist/clients/generated-artifacts.js +0 -209
  229. package/extensions/dm-lens/dist/clients/generation-guard.js +0 -105
  230. package/extensions/dm-lens/dist/clients/git-guard.js +0 -770
  231. package/extensions/dm-lens/dist/clients/git-tracked-ignore.js +0 -120
  232. package/extensions/dm-lens/dist/clients/gitleaks-client.js +0 -282
  233. package/extensions/dm-lens/dist/clients/go-client.js +0 -47
  234. package/extensions/dm-lens/dist/clients/govulncheck-client.js +0 -411
  235. package/extensions/dm-lens/dist/clients/gradle-ktfmt-style.js +0 -177
  236. package/extensions/dm-lens/dist/clients/grammar-source.js +0 -224
  237. package/extensions/dm-lens/dist/clients/gzip-stage-write.js +0 -85
  238. package/extensions/dm-lens/dist/clients/hashline-anchor.js +0 -222
  239. package/extensions/dm-lens/dist/clients/hook-budgets.js +0 -16
  240. package/extensions/dm-lens/dist/clients/host-edit-normalize.js +0 -87
  241. package/extensions/dm-lens/dist/clients/host-ports.js +0 -35
  242. package/extensions/dm-lens/dist/clients/indent-retarget.js +0 -102
  243. package/extensions/dm-lens/dist/clients/inline-blocker-dispositions.js +0 -103
  244. package/extensions/dm-lens/dist/clients/install-diagnostics.js +0 -123
  245. package/extensions/dm-lens/dist/clients/installer/index.js +0 -3770
  246. package/extensions/dm-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -17
  247. package/extensions/dm-lens/dist/clients/installer/managed-tool-refresh.js +0 -522
  248. package/extensions/dm-lens/dist/clients/instance-reaper-state.js +0 -3
  249. package/extensions/dm-lens/dist/clients/instance-reaper.js +0 -577
  250. package/extensions/dm-lens/dist/clients/instance-registry-lock.js +0 -131
  251. package/extensions/dm-lens/dist/clients/instance-registry.js +0 -452
  252. package/extensions/dm-lens/dist/clients/jscpd-client.js +0 -252
  253. package/extensions/dm-lens/dist/clients/json-cache-read.js +0 -25
  254. package/extensions/dm-lens/dist/clients/knip-client.js +0 -472
  255. package/extensions/dm-lens/dist/clients/language-policy.js +0 -242
  256. package/extensions/dm-lens/dist/clients/language-profile.js +0 -261
  257. package/extensions/dm-lens/dist/clients/language-registry.js +0 -424
  258. package/extensions/dm-lens/dist/clients/latency-logger.js +0 -192
  259. package/extensions/dm-lens/dist/clients/lazy-import.js +0 -14
  260. package/extensions/dm-lens/dist/clients/ledger-bounds.js +0 -21
  261. package/extensions/dm-lens/dist/clients/lens-config.js +0 -237
  262. package/extensions/dm-lens/dist/clients/lens-engine.js +0 -181
  263. package/extensions/dm-lens/dist/clients/lens-events.js +0 -105
  264. package/extensions/dm-lens/dist/clients/lens-flag-registry.js +0 -302
  265. package/extensions/dm-lens/dist/clients/lens-map.js +0 -980
  266. package/extensions/dm-lens/dist/clients/live-bus-emitter.js +0 -53
  267. package/extensions/dm-lens/dist/clients/log-cleanup.js +0 -138
  268. package/extensions/dm-lens/dist/clients/lsp/aggregation.js +0 -88
  269. package/extensions/dm-lens/dist/clients/lsp/cascade-tier.js +0 -203
  270. package/extensions/dm-lens/dist/clients/lsp/client.js +0 -2709
  271. package/extensions/dm-lens/dist/clients/lsp/config.js +0 -252
  272. package/extensions/dm-lens/dist/clients/lsp/content-limits.js +0 -21
  273. package/extensions/dm-lens/dist/clients/lsp/diagnostic-binding.js +0 -79
  274. package/extensions/dm-lens/dist/clients/lsp/document-drift.js +0 -312
  275. package/extensions/dm-lens/dist/clients/lsp/edits.js +0 -930
  276. package/extensions/dm-lens/dist/clients/lsp/index.js +0 -4448
  277. package/extensions/dm-lens/dist/clients/lsp/inferred-project.js +0 -121
  278. package/extensions/dm-lens/dist/clients/lsp/jvm-runtime.js +0 -194
  279. package/extensions/dm-lens/dist/clients/lsp/language.js +0 -23
  280. package/extensions/dm-lens/dist/clients/lsp/launch.js +0 -468
  281. package/extensions/dm-lens/dist/clients/lsp/lombok.js +0 -146
  282. package/extensions/dm-lens/dist/clients/lsp/path-utils.js +0 -1
  283. package/extensions/dm-lens/dist/clients/lsp/pending-aux-coverage.js +0 -90
  284. package/extensions/dm-lens/dist/clients/lsp/position-encoding.js +0 -28
  285. package/extensions/dm-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -42
  286. package/extensions/dm-lens/dist/clients/lsp/server.js +0 -2422
  287. package/extensions/dm-lens/dist/clients/lsp/session-roots.js +0 -52
  288. package/extensions/dm-lens/dist/clients/lsp/spawn-history.js +0 -15
  289. package/extensions/dm-lens/dist/clients/lsp/sync-kind.js +0 -30
  290. package/extensions/dm-lens/dist/clients/lsp/tsserver-sync.js +0 -156
  291. package/extensions/dm-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  292. package/extensions/dm-lens/dist/clients/lsp/wait-policy/classification.js +0 -36
  293. package/extensions/dm-lens/dist/clients/lsp/wait-policy/index.js +0 -3
  294. package/extensions/dm-lens/dist/clients/lsp/wait-policy/strategies.js +0 -175
  295. package/extensions/dm-lens/dist/clients/lsp/watch-queue.js +0 -40
  296. package/extensions/dm-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -267
  297. package/extensions/dm-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -7
  298. package/extensions/dm-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -93
  299. package/extensions/dm-lens/dist/clients/lsp-budget.js +0 -83
  300. package/extensions/dm-lens/dist/clients/lsp-document-symbols.js +0 -93
  301. package/extensions/dm-lens/dist/clients/lsp-lazy.js +0 -8
  302. package/extensions/dm-lens/dist/clients/lsp-mutation.js +0 -273
  303. package/extensions/dm-lens/dist/clients/lsp-status.js +0 -37
  304. package/extensions/dm-lens/dist/clients/map-with-concurrency.js +0 -20
  305. package/extensions/dm-lens/dist/clients/mcp/analyze.js +0 -251
  306. package/extensions/dm-lens/dist/clients/mcp/host-shim.js +0 -14
  307. package/extensions/dm-lens/dist/clients/mcp/ipc.js +0 -302
  308. package/extensions/dm-lens/dist/clients/mcp/review.js +0 -137
  309. package/extensions/dm-lens/dist/clients/mcp/session.js +0 -305
  310. package/extensions/dm-lens/dist/clients/memory-sampler.js +0 -107
  311. package/extensions/dm-lens/dist/clients/message-end-attribution.js +0 -18
  312. package/extensions/dm-lens/dist/clients/metrics-client.js +0 -80
  313. package/extensions/dm-lens/dist/clients/metrics-history.js +0 -255
  314. package/extensions/dm-lens/dist/clients/middle-man-analysis.js +0 -161
  315. package/extensions/dm-lens/dist/clients/model-provider.js +0 -31
  316. package/extensions/dm-lens/dist/clients/module-report-lsp.js +0 -140
  317. package/extensions/dm-lens/dist/clients/module-report.js +0 -1642
  318. package/extensions/dm-lens/dist/clients/mutating-tool.js +0 -377
  319. package/extensions/dm-lens/dist/clients/mutation-attribution.js +0 -168
  320. package/extensions/dm-lens/dist/clients/mutation-bridge.js +0 -102
  321. package/extensions/dm-lens/dist/clients/ndjson-logger.js +0 -471
  322. package/extensions/dm-lens/dist/clients/observed-mutation-sources.js +0 -43
  323. package/extensions/dm-lens/dist/clients/observed-mutation.js +0 -709
  324. package/extensions/dm-lens/dist/clients/oldtext-autopatch.js +0 -100
  325. package/extensions/dm-lens/dist/clients/opaque-mutation-scan.js +0 -313
  326. package/extensions/dm-lens/dist/clients/opengrep-client.js +0 -216
  327. package/extensions/dm-lens/dist/clients/opengrep-config.js +0 -52
  328. package/extensions/dm-lens/dist/clients/package-manager.js +0 -303
  329. package/extensions/dm-lens/dist/clients/package-root.js +0 -25
  330. package/extensions/dm-lens/dist/clients/partial-edit-apply.js +0 -337
  331. package/extensions/dm-lens/dist/clients/path-attribution-telemetry.js +0 -31
  332. package/extensions/dm-lens/dist/clients/path-keyed-map.js +0 -57
  333. package/extensions/dm-lens/dist/clients/path-utils.js +0 -476
  334. package/extensions/dm-lens/dist/clients/performance-report.js +0 -291
  335. package/extensions/dm-lens/dist/clients/persist-debounce.js +0 -37
  336. package/extensions/dm-lens/dist/clients/persistent-reverify.js +0 -165
  337. package/extensions/dm-lens/dist/clients/php-cs-fixer-config.js +0 -15
  338. package/extensions/dm-lens/dist/clients/pipeline.js +0 -1091
  339. package/extensions/dm-lens/dist/clients/post-autofix-notice.js +0 -19
  340. package/extensions/dm-lens/dist/clients/print-mode.js +0 -3
  341. package/extensions/dm-lens/dist/clients/probe-home-state.js +0 -62
  342. package/extensions/dm-lens/dist/clients/process-bridge.js +0 -20
  343. package/extensions/dm-lens/dist/clients/process-singletons.js +0 -69
  344. package/extensions/dm-lens/dist/clients/process-snapshot.js +0 -22
  345. package/extensions/dm-lens/dist/clients/project-changes.js +0 -112
  346. package/extensions/dm-lens/dist/clients/project-conventions.js +0 -152
  347. package/extensions/dm-lens/dist/clients/project-diagnostics/cache.js +0 -91
  348. package/extensions/dm-lens/dist/clients/project-diagnostics/extractors.js +0 -53
  349. package/extensions/dm-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -408
  350. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -64
  351. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -38
  352. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -21
  353. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -23
  354. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -28
  355. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -45
  356. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -34
  357. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -32
  358. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -79
  359. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -41
  360. package/extensions/dm-lens/dist/clients/project-diagnostics/scanner.js +0 -349
  361. package/extensions/dm-lens/dist/clients/project-diagnostics/types.js +0 -1
  362. package/extensions/dm-lens/dist/clients/project-lens-config.js +0 -437
  363. package/extensions/dm-lens/dist/clients/project-report.js +0 -527
  364. package/extensions/dm-lens/dist/clients/project-scale.js +0 -60
  365. package/extensions/dm-lens/dist/clients/project-scan-policy.js +0 -4
  366. package/extensions/dm-lens/dist/clients/project-snapshot-fingerprint.js +0 -39
  367. package/extensions/dm-lens/dist/clients/project-snapshot-persist-worker.js +0 -14
  368. package/extensions/dm-lens/dist/clients/project-snapshot.js +0 -1178
  369. package/extensions/dm-lens/dist/clients/project-trust.js +0 -104
  370. package/extensions/dm-lens/dist/clients/python-environment.js +0 -120
  371. package/extensions/dm-lens/dist/clients/python-provenance.js +0 -551
  372. package/extensions/dm-lens/dist/clients/quiet-window-config.js +0 -16
  373. package/extensions/dm-lens/dist/clients/quiet-window.js +0 -126
  374. package/extensions/dm-lens/dist/clients/read-bridge.js +0 -46
  375. package/extensions/dm-lens/dist/clients/read-expansion.js +0 -218
  376. package/extensions/dm-lens/dist/clients/read-guard-logger.js +0 -178
  377. package/extensions/dm-lens/dist/clients/read-guard-tool-lines.js +0 -1042
  378. package/extensions/dm-lens/dist/clients/read-guard.js +0 -1096
  379. package/extensions/dm-lens/dist/clients/recent-touches.js +0 -126
  380. package/extensions/dm-lens/dist/clients/redact/secrets.js +0 -386
  381. package/extensions/dm-lens/dist/clients/resource-sampler.js +0 -344
  382. package/extensions/dm-lens/dist/clients/reverse-deps.js +0 -227
  383. package/extensions/dm-lens/dist/clients/review-graph/builder.js +0 -3635
  384. package/extensions/dm-lens/dist/clients/review-graph/format.js +0 -30
  385. package/extensions/dm-lens/dist/clients/review-graph/git-identity.js +0 -115
  386. package/extensions/dm-lens/dist/clients/review-graph/import-resolvers.js +0 -325
  387. package/extensions/dm-lens/dist/clients/review-graph/persist-worker.js +0 -8
  388. package/extensions/dm-lens/dist/clients/review-graph/query.js +0 -195
  389. package/extensions/dm-lens/dist/clients/review-graph/revision-drift.js +0 -3
  390. package/extensions/dm-lens/dist/clients/review-graph/service.js +0 -60
  391. package/extensions/dm-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -54
  392. package/extensions/dm-lens/dist/clients/review-graph/symbol-id.js +0 -29
  393. package/extensions/dm-lens/dist/clients/review-graph/tsconfig-paths.js +0 -253
  394. package/extensions/dm-lens/dist/clients/review-graph/types.js +0 -1
  395. package/extensions/dm-lens/dist/clients/review-graph/workspace-modules.js +0 -374
  396. package/extensions/dm-lens/dist/clients/review-graph-logger.js +0 -51
  397. package/extensions/dm-lens/dist/clients/ruff-client.js +0 -109
  398. package/extensions/dm-lens/dist/clients/rules-scanner.js +0 -113
  399. package/extensions/dm-lens/dist/clients/run-duration.js +0 -9
  400. package/extensions/dm-lens/dist/clients/runtime-agent-end.js +0 -608
  401. package/extensions/dm-lens/dist/clients/runtime-config.js +0 -39
  402. package/extensions/dm-lens/dist/clients/runtime-context.js +0 -155
  403. package/extensions/dm-lens/dist/clients/runtime-coordinator.js +0 -817
  404. package/extensions/dm-lens/dist/clients/runtime-session.js +0 -1625
  405. package/extensions/dm-lens/dist/clients/runtime-tool-call.js +0 -868
  406. package/extensions/dm-lens/dist/clients/runtime-tool-result.js +0 -1317
  407. package/extensions/dm-lens/dist/clients/runtime-turn.js +0 -2333
  408. package/extensions/dm-lens/dist/clients/rust-client.js +0 -48
  409. package/extensions/dm-lens/dist/clients/safe-spawn.js +0 -1267
  410. package/extensions/dm-lens/dist/clients/sanitize.js +0 -174
  411. package/extensions/dm-lens/dist/clients/scan-utils.js +0 -7
  412. package/extensions/dm-lens/dist/clients/scratch-tree-policy.js +0 -57
  413. package/extensions/dm-lens/dist/clients/search-read-registration.js +0 -59
  414. package/extensions/dm-lens/dist/clients/secret-findings.js +0 -69
  415. package/extensions/dm-lens/dist/clients/security-scan-client.js +0 -208
  416. package/extensions/dm-lens/dist/clients/session-event-guard.js +0 -111
  417. package/extensions/dm-lens/dist/clients/session-lifecycle.js +0 -173
  418. package/extensions/dm-lens/dist/clients/session-start-observability.js +0 -47
  419. package/extensions/dm-lens/dist/clients/session-state-store.js +0 -63
  420. package/extensions/dm-lens/dist/clients/session-summary.js +0 -8
  421. package/extensions/dm-lens/dist/clients/sessionstart-logger.js +0 -22
  422. package/extensions/dm-lens/dist/clients/sg-runner.js +0 -627
  423. package/extensions/dm-lens/dist/clients/sgconfig.js +0 -280
  424. package/extensions/dm-lens/dist/clients/shared-checkout-guard.js +0 -177
  425. package/extensions/dm-lens/dist/clients/single-flight.js +0 -52
  426. package/extensions/dm-lens/dist/clients/situational-tool-telemetry.js +0 -85
  427. package/extensions/dm-lens/dist/clients/skills-resolver.js +0 -38
  428. package/extensions/dm-lens/dist/clients/slow-fs.js +0 -77
  429. package/extensions/dm-lens/dist/clients/smells-rollup.js +0 -118
  430. package/extensions/dm-lens/dist/clients/source-filter.js +0 -320
  431. package/extensions/dm-lens/dist/clients/source-walker.js +0 -96
  432. package/extensions/dm-lens/dist/clients/spawn-output-cap.js +0 -35
  433. package/extensions/dm-lens/dist/clients/spawn-timeout-cooldown.js +0 -51
  434. package/extensions/dm-lens/dist/clients/stale-marker.js +0 -1
  435. package/extensions/dm-lens/dist/clients/startup-scan.js +0 -222
  436. package/extensions/dm-lens/dist/clients/startup-timing.js +0 -67
  437. package/extensions/dm-lens/dist/clients/string-utils.js +0 -6
  438. package/extensions/dm-lens/dist/clients/subagent-mode.js +0 -40
  439. package/extensions/dm-lens/dist/clients/symbol-containment.js +0 -16
  440. package/extensions/dm-lens/dist/clients/symbol-types.js +0 -1
  441. package/extensions/dm-lens/dist/clients/test-runner-client.js +0 -1504
  442. package/extensions/dm-lens/dist/clients/test-runner-delivery.js +0 -260
  443. package/extensions/dm-lens/dist/clients/todo-scanner.js +0 -164
  444. package/extensions/dm-lens/dist/clients/tool-agreement.js +0 -377
  445. package/extensions/dm-lens/dist/clients/tool-config.js +0 -218
  446. package/extensions/dm-lens/dist/clients/tool-cwd.js +0 -235
  447. package/extensions/dm-lens/dist/clients/tool-definition.js +0 -22
  448. package/extensions/dm-lens/dist/clients/tool-event.js +0 -18
  449. package/extensions/dm-lens/dist/clients/tool-policy.js +0 -2393
  450. package/extensions/dm-lens/dist/clients/tool-probe.js +0 -5
  451. package/extensions/dm-lens/dist/clients/tool-render.js +0 -79
  452. package/extensions/dm-lens/dist/clients/tool-set-policy.js +0 -70
  453. package/extensions/dm-lens/dist/clients/tree-sitter-cache.js +0 -206
  454. package/extensions/dm-lens/dist/clients/tree-sitter-client.js +0 -2787
  455. package/extensions/dm-lens/dist/clients/tree-sitter-logger.js +0 -77
  456. package/extensions/dm-lens/dist/clients/tree-sitter-navigator.js +0 -198
  457. package/extensions/dm-lens/dist/clients/tree-sitter-query-loader.js +0 -318
  458. package/extensions/dm-lens/dist/clients/tree-sitter-shared.js +0 -87
  459. package/extensions/dm-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -957
  460. package/extensions/dm-lens/dist/clients/trivy-client.js +0 -305
  461. package/extensions/dm-lens/dist/clients/tui-fit.js +0 -26
  462. package/extensions/dm-lens/dist/clients/turn-context.js +0 -48
  463. package/extensions/dm-lens/dist/clients/turn-end/lane.js +0 -1
  464. package/extensions/dm-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -54
  465. package/extensions/dm-lens/dist/clients/turn-end/lanes/secrets.js +0 -131
  466. package/extensions/dm-lens/dist/clients/turn-summary-render.js +0 -56
  467. package/extensions/dm-lens/dist/clients/turn-summary.js +0 -84
  468. package/extensions/dm-lens/dist/clients/typos-config.js +0 -9
  469. package/extensions/dm-lens/dist/clients/user-notify.js +0 -15
  470. package/extensions/dm-lens/dist/clients/vanished-instance-marker.js +0 -18
  471. package/extensions/dm-lens/dist/clients/warm-attach.js +0 -210
  472. package/extensions/dm-lens/dist/clients/widget-state.js +0 -963
  473. package/extensions/dm-lens/dist/clients/word-index-logger.js +0 -21
  474. package/extensions/dm-lens/dist/clients/word-index-store.js +0 -222
  475. package/extensions/dm-lens/dist/clients/word-index.js +0 -1426
  476. package/extensions/dm-lens/dist/clients/workspace-topology.js +0 -261
  477. package/extensions/dm-lens/dist/clients/write-ordering-guard.js +0 -24
  478. package/extensions/dm-lens/dist/clients/zizmor-config.js +0 -160
  479. package/extensions/dm-lens/dist/i18n.js +0 -67
  480. package/extensions/dm-lens/dist/index.js +0 -1782
  481. package/extensions/dm-lens/dist/mcp/analyze-cli.js +0 -178
  482. package/extensions/dm-lens/dist/mcp/build-staleness.js +0 -55
  483. package/extensions/dm-lens/dist/mcp/cli.js +0 -78
  484. package/extensions/dm-lens/dist/mcp/server.js +0 -1208
  485. package/extensions/dm-lens/dist/mcp/worker.js +0 -33
  486. package/extensions/dm-lens/dist/scripts/lib/process-scan.mjs +0 -256
  487. package/extensions/dm-lens/dist/scripts/lib/skills-predicate.mjs +0 -53
  488. package/extensions/dm-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -45
  489. package/extensions/dm-lens/dist/tools/activate-tools.js +0 -61
  490. package/extensions/dm-lens/dist/tools/ast-grep-outline.js +0 -127
  491. package/extensions/dm-lens/dist/tools/ast-grep-replace.js +0 -226
  492. package/extensions/dm-lens/dist/tools/ast-grep-search.js +0 -687
  493. package/extensions/dm-lens/dist/tools/effective-config.js +0 -59
  494. package/extensions/dm-lens/dist/tools/lens-diagnostic-mark.js +0 -240
  495. package/extensions/dm-lens/dist/tools/lens-diagnostics.js +0 -1484
  496. package/extensions/dm-lens/dist/tools/lsp-diagnostics.js +0 -1088
  497. package/extensions/dm-lens/dist/tools/lsp-navigation.js +0 -1194
  498. package/extensions/dm-lens/dist/tools/lsp-structured-output.js +0 -277
  499. package/extensions/dm-lens/dist/tools/module-report.js +0 -332
  500. package/extensions/dm-lens/dist/tools/project-report.js +0 -72
  501. package/extensions/dm-lens/dist/tools/render-compact.js +0 -272
  502. package/extensions/dm-lens/dist/tools/scan-progress.js +0 -31
  503. package/extensions/dm-lens/dist/tools/shared.js +0 -26
  504. package/extensions/dm-lens/dist/tools/symbol-search.js +0 -133
  505. package/extensions/dm-mcp-adapter/dist/abort.js +0 -35
  506. package/extensions/dm-mcp-adapter/dist/agent-dir.js +0 -45
  507. package/extensions/dm-mcp-adapter/dist/agent-plugin-loader.js +0 -392
  508. package/extensions/dm-mcp-adapter/dist/agent-plugin-provenance.js +0 -26
  509. package/extensions/dm-mcp-adapter/dist/bearer-command-resolver.js +0 -182
  510. package/extensions/dm-mcp-adapter/dist/claude-plugin-loader.js +0 -350
  511. package/extensions/dm-mcp-adapter/dist/config.js +0 -1310
  512. package/extensions/dm-mcp-adapter/dist/consent-manager.js +0 -84
  513. package/extensions/dm-mcp-adapter/dist/elicitation-handler.js +0 -308
  514. package/extensions/dm-mcp-adapter/dist/errors.js +0 -225
  515. package/extensions/dm-mcp-adapter/dist/http-ca.js +0 -71
  516. package/extensions/dm-mcp-adapter/dist/jev-client.js +0 -359
  517. package/extensions/dm-mcp-adapter/dist/jev-contracts.js +0 -1
  518. package/extensions/dm-mcp-adapter/dist/jev-key-store.js +0 -176
  519. package/extensions/dm-mcp-adapter/dist/json-schema-validator.js +0 -70
  520. package/extensions/dm-mcp-adapter/dist/lifecycle.js +0 -387
  521. package/extensions/dm-mcp-adapter/dist/logger.js +0 -115
  522. package/extensions/dm-mcp-adapter/dist/mcp-auth-fetch.js +0 -86
  523. package/extensions/dm-mcp-adapter/dist/mcp-auth-flow.js +0 -949
  524. package/extensions/dm-mcp-adapter/dist/mcp-auth.js +0 -997
  525. package/extensions/dm-mcp-adapter/dist/mcp-bearer-store.js +0 -182
  526. package/extensions/dm-mcp-adapter/dist/mcp-callback-server.js +0 -381
  527. package/extensions/dm-mcp-adapter/dist/mcp-oauth-provider.js +0 -524
  528. package/extensions/dm-mcp-adapter/dist/mcp-probe.js +0 -151
  529. package/extensions/dm-mcp-adapter/dist/mcp-tasks.js +0 -300
  530. package/extensions/dm-mcp-adapter/dist/mcp-trace.js +0 -215
  531. package/extensions/dm-mcp-adapter/dist/metadata-cache.js +0 -267
  532. package/extensions/dm-mcp-adapter/dist/npx-resolver.js +0 -465
  533. package/extensions/dm-mcp-adapter/dist/package-mcp-loader.js +0 -135
  534. package/extensions/dm-mcp-adapter/dist/request-headers-command.js +0 -294
  535. package/extensions/dm-mcp-adapter/dist/resource-tools.js +0 -7
  536. package/extensions/dm-mcp-adapter/dist/runtime-owner.js +0 -94
  537. package/extensions/dm-mcp-adapter/dist/sampling-handler.js +0 -213
  538. package/extensions/dm-mcp-adapter/dist/secure-keyring.js +0 -191
  539. package/extensions/dm-mcp-adapter/dist/server-manager.js +0 -1514
  540. package/extensions/dm-mcp-adapter/dist/session-approvals.js +0 -127
  541. package/extensions/dm-mcp-adapter/dist/session-recovery.js +0 -82
  542. package/extensions/dm-mcp-adapter/dist/state.js +0 -1
  543. package/extensions/dm-mcp-adapter/dist/types.js +0 -286
  544. package/extensions/dm-mcp-adapter/dist/ui-app-bridge-helpers.js +0 -36
  545. package/extensions/dm-mcp-adapter/dist/ui-resource-handler.js +0 -204
  546. package/extensions/dm-mcp-adapter/dist/ui-stream-types.js +0 -58
  547. package/extensions/dm-mcp-adapter/dist/ui-tool-visibility.js +0 -26
  548. package/extensions/dm-mcp-adapter/dist/unix-socket-transport.js +0 -83
  549. package/extensions/dm-mcp-adapter/dist/utils.js +0 -382
@@ -1,2787 +0,0 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
- import * as crypto from "node:crypto";
3
- import * as fs from "node:fs";
4
- import { createRequire } from "node:module";
5
- import * as path from "node:path";
6
- import { getDegradationLedgerGeneration, incrementDegradationCount, recordDegradation, recordDegradationOnce } from "./degradation-ledger.js";
7
- import { BoundedFifoMap } from "./bounded-cache.js";
8
- import { loadWebTreeSitter } from "./deps/web-tree-sitter.js";
9
- import { transientRetryDelayMs } from "./dispatch/runners/utils/availability-policy.js";
10
- import { getProjectIgnoreMatcher, isExcludedDirName } from "./file-utils.js";
11
- import { downloadGrammarDetailed, fileHasWasmMagic, grammarBlockReason, grammarFileSha256, isVendoredGrammar, LANGUAGE_TO_GRAMMAR, pinnedGrammarHash, vendoredGrammarRefusal, vendoredGrammarsDir } from "./grammar-source.js";
12
- import { getPackageRoot, resolvePackagePath } from "./package-root.js";
13
- import { resolveWebTreeSitterPackageDir } from "../scripts/lib/web-tree-sitter-dir.mjs";
14
- import { assertInstallAllowed, getProjectTrustGeneration } from "./project-trust.js";
15
- import { escapeRegExp } from "./string-utils.js";
16
- import { logTreeSitterDiagnostic } from "./tree-sitter-logger.js";
17
- import { notifyUserDegradation } from "./user-notify.js";
18
- const _require = createRequire(import.meta.url);
19
- import { createTreeCacheCounters, deriveScanTreeCacheCapacity, TreeCache } from "./tree-sitter-cache.js";
20
- import { TreeSitterNavigator } from "./tree-sitter-navigator.js";
21
- import { isProvenSqlAlchemySessionReceiver, isSafePsycopgIdentifierComposition, isSqlAlchemyEntityQueryArgument, isSqlAlchemyStatementArgument, PYTHON_SQLALCHEMY_RECEIVER_NAMES, PYTHON_SQLALCHEMY_STATEMENT_BUILDERS } from "./python-provenance.js";
22
- import { TreeSitterQueryLoader } from "./tree-sitter-query-loader.js";
23
- const TREE_SITTER_MAX_SCAN_FILES = 20000;
24
- const QUERY_BATCH_MAX_LOAD_FAILURES = 3;
25
- const NO_NESTED_ANCHOR_VISIT_CAP = 1e4;
26
- const PYTHON_SQL_SINK_METHODS = new Set([
27
- "execute",
28
- "executemany",
29
- "query",
30
- "raw"
31
- ]);
32
- const TYPESCRIPT_SQL_KNOWN_PACKAGES = new Set([
33
- "pg",
34
- "mysql2",
35
- "better-sqlite3",
36
- "knex",
37
- "@prisma/client"
38
- ]);
39
- const TYPESCRIPT_SQL_IMPORTS = new WeakMap;
40
- const NOT_PARSED = { parsed: false };
41
- function createParserCounters() {
42
- return {
43
- parserInvocations: 0,
44
- parserDurationMs: 0,
45
- parserFailures: 0
46
- };
47
- }
48
- function grammarWriteBlockedReason(dir) {
49
- let probe = dir;
50
- while (!fs.existsSync(probe)) {
51
- const parent = path.dirname(probe);
52
- if (parent === probe)
53
- return "ENOENT";
54
- probe = parent;
55
- }
56
- try {
57
- fs.accessSync(probe, fs.constants.W_OK);
58
- return;
59
- } catch (err) {
60
- return err?.code ?? "EACCES";
61
- }
62
- }
63
- function grammarFileStamp(filePath) {
64
- try {
65
- const stat = fs.statSync(filePath);
66
- return stat.isFile() ? `${stat.size}:${stat.mtimeMs}` : undefined;
67
- } catch {
68
- return;
69
- }
70
- }
71
- function isTreeSitterWasmAbortError(error) {
72
- const message = error instanceof Error ? error.message : String(error);
73
- return message.includes("Aborted") || message.includes("abort()");
74
- }
75
- const RESOLUTION_ERROR_CODES = new Set([
76
- "ERR_MODULE_NOT_FOUND",
77
- "MODULE_NOT_FOUND",
78
- "ERR_INVALID_MODULE_SPECIFIER",
79
- "ERR_UNSUPPORTED_DIR_IMPORT",
80
- "ENOENT",
81
- "EMFILE",
82
- "EBUSY",
83
- "EAGAIN",
84
- "EPERM",
85
- "ETXTBSY"
86
- ]);
87
- function collectErrorCodes(err) {
88
- const codes = [];
89
- let current = err;
90
- const seen = new Set;
91
- while (current instanceof Error && !seen.has(current)) {
92
- seen.add(current);
93
- const code = current.code;
94
- if (typeof code === "string")
95
- codes.push(code);
96
- current = current.cause;
97
- }
98
- return codes;
99
- }
100
- function classifyWebTreeSitterLoadFailure(err) {
101
- const codes = collectErrorCodes(err);
102
- return codes.some((code) => RESOLUTION_ERROR_CODES.has(code)) ? "resolution" : "evaluation";
103
- }
104
-
105
- export class TreeSitterClient {
106
- initialized = false;
107
- initPromise = null;
108
- webTreeSitterLoadFailed = false;
109
- languages = new Map;
110
- parsers = new Map;
111
- treeCache;
112
- navigator = new TreeSitterNavigator;
113
- grammarsDir;
114
- grammarEnsurePromises = new Map;
115
- grammarRetryAtMs = new Map;
116
- verifiedGrammarPaths = new Map;
117
- decodeFailedGrammarPaths = new Map;
118
- verifiedGrammarVersionAt = new Map;
119
- staleGrammarVersionAt = new Map;
120
- staleReportedGrammarPaths = new Set;
121
- poisonedGrammarPaths = new Set;
122
- grammarFailureAttempts = new Map;
123
- grammarLastNotifiedDelayMs = new Map;
124
- grammarNotificationsLedgerGen = getDegradationLedgerGeneration();
125
- trustBlockedGrammarNotifications = new Set;
126
- trustNotificationsGeneration = getProjectTrustGeneration();
127
- ParserClass = null;
128
- LanguageLoader = null;
129
- static QUERY_CACHE_MAX_ENTRIES = 256;
130
- static QUERY_BATCH_CACHE_MAX_ENTRIES = 256;
131
- queryCache = new BoundedFifoMap(TreeSitterClient.QUERY_CACHE_MAX_ENTRIES);
132
- queryBatchCache = new BoundedFifoMap(TreeSitterClient.QUERY_BATCH_CACHE_MAX_ENTRIES);
133
- queryCacheCap() {
134
- const value = Number.parseInt(process.env.DM_LENS_TREE_SITTER_QUERY_CACHE_CAP ?? "", 10);
135
- return Number.isSafeInteger(value) && value > 0 ? value : TreeSitterClient.QUERY_CACHE_MAX_ENTRIES;
136
- }
137
- queryBatchCacheCap() {
138
- const value = Number.parseInt(process.env.DM_LENS_TREE_SITTER_QUERY_BATCH_CACHE_CAP ?? "", 10);
139
- return Number.isSafeInteger(value) && value > 0 ? value : TreeSitterClient.QUERY_BATCH_CACHE_MAX_ENTRIES;
140
- }
141
- cacheQuery(key, value) {
142
- this.queryCache.delete(key);
143
- const evicted = this.queryCache.setMaxEntries(this.queryCacheCap());
144
- evicted.push(...this.queryCache.set(key, value));
145
- for (const [, dropped] of evicted)
146
- dropped?.query?.delete?.();
147
- }
148
- cacheQueryBatch(key, value) {
149
- this.queryBatchCache.delete(key);
150
- const evicted = this.queryBatchCache.setMaxEntries(this.queryBatchCacheCap());
151
- evicted.push(...this.queryBatchCache.set(key, value));
152
- for (const [, dropped] of evicted)
153
- dropped?.query?.delete?.();
154
- }
155
- queryBatchLoadFailures = new Map;
156
- queryLoader = new TreeSitterQueryLoader;
157
- verbose;
158
- parserCounters = createParserCounters();
159
- parseCacheMeasurement = new AsyncLocalStorage;
160
- activeMeasurements = 0;
161
- onWasmAbort;
162
- wasmAborted = false;
163
- grammarDirResolutionDeps;
164
- constructor(verbose = false, onWasmAbort, grammarDirResolutionDeps) {
165
- this.grammarDirResolutionDeps = grammarDirResolutionDeps ?? {
166
- resolveAsset: (asset) => this.resolveWebTreeSitterAsset(asset),
167
- resolvePackage: (specifier) => _require.resolve(specifier),
168
- packageRoot: () => getPackageRoot(import.meta.url),
169
- cwd: () => process.cwd()
170
- };
171
- this.grammarsDir = this.findGrammarsDir();
172
- this.verbose = verbose;
173
- this.onWasmAbort = onWasmAbort;
174
- this.treeCache = new TreeCache(50, verbose, 4096, (key, amount) => {
175
- const measurement = this.parseCacheMeasurement.getStore();
176
- if (measurement)
177
- measurement[key] += amount;
178
- }, (error) => this.reportWasmAbort(error));
179
- }
180
- recordParserCounter(key, amount = 1) {
181
- this.parserCounters[key] += amount;
182
- const measurement = this.parseCacheMeasurement.getStore();
183
- if (measurement)
184
- measurement[key] += amount;
185
- }
186
- reportWasmAbort(error) {
187
- if (!isTreeSitterWasmAbortError(error))
188
- return false;
189
- if (!this.wasmAborted) {
190
- this.wasmAborted = true;
191
- recordDegradation({
192
- kind: "wasm-abort",
193
- subject: "web-tree-sitter",
194
- reason: error instanceof Error ? error.message : String(error)
195
- });
196
- this.onWasmAbort?.();
197
- }
198
- return true;
199
- }
200
- getRuntimeStats() {
201
- return {
202
- languagesLoaded: this.languages.size,
203
- parsersLoaded: this.parsers.size,
204
- queryCacheSize: this.queryCache.size,
205
- queryBatchCacheSize: this.queryBatchCache.size
206
- };
207
- }
208
- getParseCacheStats() {
209
- return {
210
- ...this.treeCache.getStats(),
211
- ...this.parserCounters
212
- };
213
- }
214
- ensureTreeCacheCapacity(fileCount) {
215
- this.treeCache.setMaxSize(deriveScanTreeCacheCapacity(fileCount, this.treeCache.getMaxSize()));
216
- }
217
- async withParseCacheMeasurement(work, onComplete) {
218
- const measurement = {
219
- ...createTreeCacheCounters(),
220
- ...createParserCounters()
221
- };
222
- this.activeMeasurements++;
223
- try {
224
- return await this.parseCacheMeasurement.run(measurement, async () => {
225
- try {
226
- return await work();
227
- } finally {
228
- const cacheStats = this.treeCache.getStats();
229
- try {
230
- onComplete({
231
- ...cacheStats,
232
- ...measurement,
233
- misses: measurement.lookups - measurement.hits
234
- });
235
- } catch {}
236
- }
237
- });
238
- } finally {
239
- if (--this.activeMeasurements === 0)
240
- this.parseCacheMeasurement.disable();
241
- }
242
- }
243
- dbg(msg) {
244
- if (this.verbose) {
245
- logTreeSitterDiagnostic({
246
- subsystem: "tree-sitter-client",
247
- level: "debug",
248
- message: msg
249
- });
250
- }
251
- }
252
- webTreeSitterPackageDir() {
253
- return resolveWebTreeSitterPackageDir({
254
- resolve: (specifier) => this.grammarDirResolutionDeps.resolvePackage(specifier),
255
- packageRoot: () => this.grammarDirResolutionDeps.packageRoot(),
256
- cwd: () => this.grammarDirResolutionDeps.cwd()
257
- });
258
- }
259
- resolveWebTreeSitterAsset(asset) {
260
- try {
261
- const resolved = this.grammarDirResolutionDeps.resolvePackage(`web-tree-sitter/${asset}`);
262
- if (fs.existsSync(resolved))
263
- return resolved;
264
- } catch {}
265
- const pkgDir = this.webTreeSitterPackageDir();
266
- if (pkgDir) {
267
- const candidate = path.join(pkgDir, asset);
268
- if (fs.existsSync(candidate))
269
- return candidate;
270
- }
271
- return;
272
- }
273
- _bundledGrammarsDir;
274
- bundledGrammarsDir() {
275
- if (this._bundledGrammarsDir)
276
- return this._bundledGrammarsDir;
277
- try {
278
- const dir = resolvePackagePath(import.meta.url, "grammars");
279
- if (fs.existsSync(dir))
280
- this._bundledGrammarsDir = dir;
281
- return this._bundledGrammarsDir;
282
- } catch {
283
- return;
284
- }
285
- }
286
- _vendoredGrammarsDir;
287
- vendoredGrammarsDir() {
288
- if (this._vendoredGrammarsDir)
289
- return this._vendoredGrammarsDir;
290
- try {
291
- const dir = vendoredGrammarsDir();
292
- if (fs.existsSync(dir))
293
- this._vendoredGrammarsDir = dir;
294
- return this._vendoredGrammarsDir;
295
- } catch {
296
- return;
297
- }
298
- }
299
- grammarSourceDirs() {
300
- const dirs = [];
301
- const push = (d) => {
302
- if (d && !dirs.includes(d))
303
- dirs.push(d);
304
- };
305
- push(this.vendoredGrammarsDir());
306
- push(this.bundledGrammarsDir());
307
- push(this.grammarsDir || undefined);
308
- push(this.resolveWebTreeSitterAsset("grammars"));
309
- return dirs;
310
- }
311
- resolveGrammarFile(grammarFile) {
312
- for (const dir of this.grammarSourceDirs()) {
313
- const candidate = path.join(dir, grammarFile);
314
- const stamp = grammarFileStamp(candidate);
315
- if (!stamp)
316
- continue;
317
- if (this.decodeFailedGrammarPaths.get(candidate) === stamp)
318
- continue;
319
- if (this.verifiedGrammarPaths.get(candidate) === stamp) {
320
- if (this.isGrammarVersionCurrent(candidate, grammarFile, stamp)) {
321
- return candidate;
322
- }
323
- continue;
324
- }
325
- if (fileHasWasmMagic(candidate)) {
326
- this.verifiedGrammarPaths.set(candidate, stamp);
327
- if (this.isGrammarVersionCurrent(candidate, grammarFile, stamp)) {
328
- return candidate;
329
- }
330
- continue;
331
- }
332
- this.verifiedGrammarPaths.delete(candidate);
333
- this.reportPoisonedGrammarFile(candidate, grammarFile);
334
- }
335
- return;
336
- }
337
- refreshGrammarSessionLatches() {
338
- const ledgerGen = getDegradationLedgerGeneration();
339
- if (ledgerGen === this.grammarNotificationsLedgerGen)
340
- return;
341
- this.grammarNotificationsLedgerGen = ledgerGen;
342
- this.grammarLastNotifiedDelayMs.clear();
343
- this.poisonedGrammarPaths.clear();
344
- this.staleReportedGrammarPaths.clear();
345
- }
346
- reportPoisonedGrammarFile(candidate, grammarFile) {
347
- this.refreshGrammarSessionLatches();
348
- if (this.poisonedGrammarPaths.has(candidate))
349
- return;
350
- this.poisonedGrammarPaths.add(candidate);
351
- logTreeSitterDiagnostic({
352
- subsystem: "tree-sitter-client",
353
- level: "warn",
354
- message: `ignoring ${candidate}: the file is not a wasm module (missing the \\0asm preamble) — ` + `most likely a captive-portal or proxy page written by an earlier download (#1548). ` + `dm-lens will treat the grammar as missing and try to fetch it again.`,
355
- metadata: { grammarFile, path: candidate, outcome: "not-wasm" }
356
- });
357
- incrementDegradationCount({
358
- kind: "grammar-blocked",
359
- subject: grammarFile,
360
- reason: "on-disk grammar file is not a wasm module — ignored, re-fetching"
361
- });
362
- }
363
- isGrammarVersionCurrent(candidate, grammarFile, stamp) {
364
- if (isVendoredGrammar(grammarFile))
365
- return true;
366
- if (this.staleGrammarVersionAt.get(candidate) === stamp) {
367
- this.reportStaleGrammarVersion(candidate, grammarFile);
368
- return false;
369
- }
370
- if (this.verifiedGrammarVersionAt.get(candidate) === stamp)
371
- return true;
372
- const pinnedHash = pinnedGrammarHash(grammarFile);
373
- if (!pinnedHash) {
374
- this.verifiedGrammarVersionAt.set(candidate, stamp);
375
- return true;
376
- }
377
- const actualHash = grammarFileSha256(candidate);
378
- if (actualHash === pinnedHash) {
379
- this.verifiedGrammarVersionAt.set(candidate, stamp);
380
- return true;
381
- }
382
- this.verifiedGrammarVersionAt.delete(candidate);
383
- this.staleGrammarVersionAt.set(candidate, stamp);
384
- this.reportStaleGrammarVersion(candidate, grammarFile);
385
- return false;
386
- }
387
- reportStaleGrammarVersion(candidate, grammarFile) {
388
- this.refreshGrammarSessionLatches();
389
- if (this.staleReportedGrammarPaths.has(candidate))
390
- return;
391
- this.staleReportedGrammarPaths.add(candidate);
392
- logTreeSitterDiagnostic({
393
- subsystem: "tree-sitter-client",
394
- level: "warn",
395
- message: `ignoring ${candidate}: its sha256 no longer matches the pinned grammar ` + `manifest — the pinned tree-sitter-wasms version (or a SOURCE_OVERRIDES entry) ` + `moved since this file was downloaded. dm-lens will treat the grammar as ` + `missing and re-fetch the current build (#1760).`,
396
- metadata: { grammarFile, path: candidate, outcome: "stale-version" }
397
- });
398
- incrementDegradationCount({
399
- kind: "grammar-blocked",
400
- subject: grammarFile,
401
- reason: "cached grammar no longer matches the pinned manifest hash — ignored, re-fetching"
402
- });
403
- }
404
- findGrammarsDir(deps = this.grammarDirResolutionDeps) {
405
- const grammarsDir = deps.resolveAsset("grammars");
406
- if (grammarsDir && fs.existsSync(path.join(grammarsDir, "tree-sitter-typescript.wasm"))) {
407
- return grammarsDir;
408
- }
409
- try {
410
- const wasmsOut = path.join(path.dirname(deps.resolvePackage("tree-sitter-wasms/package.json")), "out");
411
- if (fs.existsSync(wasmsOut))
412
- return wasmsOut;
413
- } catch {}
414
- const cwdWasms = path.join(deps.cwd(), "node_modules", "tree-sitter-wasms", "out");
415
- if (fs.existsSync(cwdWasms))
416
- return cwdWasms;
417
- return "";
418
- }
419
- grammarsWriteDir() {
420
- const pkgDir = this.webTreeSitterPackageDir();
421
- return pkgDir ? path.join(pkgDir, "grammars") : undefined;
422
- }
423
- async ensureGrammar(grammarFile) {
424
- if (this.resolveGrammarFile(grammarFile)) {
425
- return true;
426
- }
427
- if (!assertInstallAllowed(`tree-sitter grammar fetch: ${grammarFile}`)) {
428
- const unavailable = `tree-sitter grammar '${grammarFile}' is unavailable because the project is not trusted; ` + `runtime grammar downloads are disabled until trust is granted.`;
429
- logTreeSitterDiagnostic({
430
- subsystem: "tree-sitter-client",
431
- message: unavailable,
432
- metadata: { grammarFile, outcome: "trust-gated" }
433
- });
434
- recordDegradation({
435
- kind: "grammar-blocked",
436
- subject: grammarFile,
437
- reason: "runtime grammar download blocked because project is untrusted"
438
- });
439
- const generation = getProjectTrustGeneration();
440
- if (generation !== this.trustNotificationsGeneration) {
441
- this.trustNotificationsGeneration = generation;
442
- this.trustBlockedGrammarNotifications.clear();
443
- }
444
- if (!this.trustBlockedGrammarNotifications.has(grammarFile)) {
445
- this.trustBlockedGrammarNotifications.add(grammarFile);
446
- notifyUserDegradation(`dm-lens: ${unavailable}`);
447
- }
448
- return false;
449
- }
450
- const inflight = this.grammarEnsurePromises.get(grammarFile);
451
- if (inflight)
452
- return inflight;
453
- const retryAt = this.grammarRetryAtMs.get(grammarFile);
454
- if (retryAt !== undefined && Date.now() < retryAt) {
455
- return false;
456
- }
457
- const task = (async () => {
458
- try {
459
- return await this.fetchGrammar(grammarFile);
460
- } catch (err) {
461
- const message = err instanceof Error ? err.message : String(err);
462
- this.recordGrammarFailure(grammarFile, `The runtime grammar fetch threw an unexpected error (${message}).`, true, "download-failed");
463
- return false;
464
- }
465
- })();
466
- this.grammarEnsurePromises.set(grammarFile, task);
467
- task.finally(() => {
468
- if (this.grammarEnsurePromises.get(grammarFile) === task) {
469
- this.grammarEnsurePromises.delete(grammarFile);
470
- }
471
- }).catch(() => {});
472
- return task;
473
- }
474
- async fetchGrammar(grammarFile) {
475
- if (isVendoredGrammar(grammarFile)) {
476
- const { reason } = vendoredGrammarRefusal(grammarFile);
477
- this.recordGrammarFailure(grammarFile, reason ?? `${grammarFile} is missing from vendor/grammars/.`, false);
478
- return false;
479
- }
480
- const dir = this.grammarsDir && fs.existsSync(this.grammarsDir) ? this.grammarsDir : this.grammarsWriteDir();
481
- if (!dir) {
482
- this.recordGrammarFailure(grammarFile, "No grammars directory could be resolved for the runtime fetch: the web-tree-sitter package is not locatable from this runtime, from dm-lens's own package root, or from the working directory.", true, "write-dir-unresolvable");
483
- return false;
484
- }
485
- const writeBlock = grammarWriteBlockedReason(dir);
486
- if (writeBlock) {
487
- this.recordGrammarFailure(grammarFile, `The grammars directory ${dir} cannot be written to (${writeBlock}), so the runtime fetch has nowhere to land.`, true, "write-dir-unwritable");
488
- return false;
489
- }
490
- const { ok, retryable, reason } = await downloadGrammarDetailed(dir, grammarFile);
491
- if (ok) {
492
- if (!this.grammarsDir)
493
- this.grammarsDir = dir;
494
- this.grammarRetryAtMs.delete(grammarFile);
495
- this.grammarFailureAttempts.delete(grammarFile);
496
- this.grammarLastNotifiedDelayMs.delete(grammarFile);
497
- logTreeSitterDiagnostic({
498
- subsystem: "tree-sitter-client",
499
- level: "warn",
500
- message: `fetched missing tree-sitter grammar ${grammarFile} at runtime (install scripts were skipped by the package manager)`,
501
- metadata: { grammarFile, outcome: "fetched" }
502
- });
503
- } else {
504
- this.recordGrammarFailure(grammarFile, reason ?? "The package manager skipped install scripts and the runtime download failed.", retryable, "download-failed");
505
- }
506
- return ok;
507
- }
508
- recordGrammarFailure(grammarFile, detail, retryable, cause) {
509
- const attempts = (this.grammarFailureAttempts.get(grammarFile) ?? 0) + 1;
510
- this.grammarFailureAttempts.set(grammarFile, attempts);
511
- const retryDelayMs = retryable ? transientRetryDelayMs(attempts, "probe-timeout") : undefined;
512
- this.grammarRetryAtMs.set(grammarFile, retryDelayMs === undefined ? Number.POSITIVE_INFINITY : Date.now() + retryDelayMs);
513
- const remedy = cause === "write-dir-unresolvable" ? `This is a packaging/module-resolution fault, not a download problem: reinstall dm-lens so its ` + `web-tree-sitter dependency is present, or drop the wasm into dm-lens's own grammars/ directory.` : cause === "write-dir-unwritable" ? `This is a filesystem-permission fault, not a download problem: make that directory writable ` + `for the user dm-lens runs as, or reinstall dm-lens as that user.` : retryable ? `if the problem persists, allow the package manager's build scripts ` + `(pnpm approve-builds / bun trustedDependencies) or restore network access.` : `Fix: reinstall with a manager that runs postinstall, allow its build scripts ` + `(pnpm approve-builds / bun trustedDependencies), or restore network access.`;
514
- const unavailable = `tree-sitter grammar '${grammarFile}' is unavailable — symbol search, ` + `module reports and structural rules for this language will be degraded. ` + `${detail} ` + (retryable ? `dm-lens will retry automatically in ${Math.round(retryDelayMs / 1000)}s; ` : `The grammar source reports it does not exist (not a network problem), so this will not ` + `resolve on retry. `) + remedy;
515
- logTreeSitterDiagnostic({
516
- subsystem: "tree-sitter-client",
517
- message: unavailable,
518
- metadata: {
519
- grammarFile,
520
- outcome: "unavailable",
521
- retryable,
522
- retryDelayMs,
523
- attempts,
524
- ...cause ? { cause } : {}
525
- }
526
- });
527
- incrementDegradationCount({
528
- kind: "grammar-blocked",
529
- subject: grammarFile,
530
- reason: retryable ? `runtime grammar download failed — retryable (${detail.trim()})` : `runtime grammar download failed — durable (${detail.trim()})`
531
- });
532
- this.refreshGrammarSessionLatches();
533
- const notifyKey = retryDelayMs ?? -1;
534
- if (this.grammarLastNotifiedDelayMs.get(grammarFile) !== notifyKey) {
535
- this.grammarLastNotifiedDelayMs.set(grammarFile, notifyKey);
536
- notifyUserDegradation(`dm-lens: ${unavailable}`);
537
- }
538
- }
539
- recordGrammarLoadFailure(grammarPath, grammarFile, err) {
540
- const stamp = grammarFileStamp(grammarPath);
541
- this.verifiedGrammarPaths.delete(grammarPath);
542
- if (stamp)
543
- this.decodeFailedGrammarPaths.set(grammarPath, stamp);
544
- const message = err instanceof Error ? err.message : String(err);
545
- logTreeSitterDiagnostic({
546
- subsystem: "tree-sitter-client",
547
- level: "warn",
548
- message: `Language.load failed for ${grammarPath} even though the wasm preamble check ` + `passed (${message}) — most likely a truncated download (#1564). Treating the ` + `grammar as missing so the next demand re-fetches it.`,
549
- metadata: { grammarFile, path: grammarPath, outcome: "load-failed" }
550
- });
551
- this.recordGrammarFailure(grammarFile, `Language.load failed on a resolved grammar file (${message}).`, true);
552
- }
553
- async init() {
554
- if (this.wasmAborted)
555
- return false;
556
- if (this.initialized)
557
- return true;
558
- if (this.webTreeSitterLoadFailed)
559
- return false;
560
- if (this.initPromise)
561
- return this.initPromise;
562
- this.initPromise = (async () => {
563
- try {
564
- let mod;
565
- try {
566
- mod = await loadWebTreeSitter();
567
- } catch (err) {
568
- const classification = classifyWebTreeSitterLoadFailure(err);
569
- if (classification === "evaluation") {
570
- this.webTreeSitterLoadFailed = true;
571
- }
572
- recordDegradationOnce({
573
- kind: "web-tree-sitter-load-failed",
574
- subject: "web-tree-sitter",
575
- reason: (err instanceof Error ? err.message : String(err)) + (classification === "resolution" ? " (resolution failure — retryable)" : " (evaluation failure — latched for the session)")
576
- });
577
- throw err;
578
- }
579
- const anyMod = mod;
580
- const ParserClass = anyMod.Parser || anyMod.default || anyMod;
581
- if (!ParserClass || typeof ParserClass.init !== "function") {
582
- this.dbg("Parser class not found or missing init method");
583
- return false;
584
- }
585
- this.ParserClass = ParserClass;
586
- this.LanguageLoader = mod.Language;
587
- const wasmPath = this.resolveWebTreeSitterAsset("tree-sitter.wasm");
588
- if (!wasmPath) {
589
- this.dbg("Could not resolve tree-sitter.wasm");
590
- return false;
591
- }
592
- const wasmDir = path.dirname(wasmPath);
593
- this.dbg(`Looking for WASM at: ${wasmPath}, exists: ${fs.existsSync(wasmPath)}`);
594
- await ParserClass.init({
595
- locateFile: (scriptName) => {
596
- const fullPath = path.join(wasmDir, scriptName);
597
- this.dbg(`locateFile: ${scriptName} -> ${fullPath}`);
598
- return fullPath;
599
- }
600
- });
601
- this.initialized = true;
602
- return true;
603
- } catch (err) {
604
- this.reportWasmAbort(err);
605
- this.dbg(`Init error: ${err}`);
606
- return false;
607
- } finally {
608
- this.initPromise = null;
609
- }
610
- })();
611
- return this.initPromise;
612
- }
613
- resetLoadStateForSession() {
614
- this.webTreeSitterLoadFailed = false;
615
- }
616
- async loadLanguage(languageId) {
617
- if (this.wasmAborted)
618
- return null;
619
- this.dbg(`Loading language: ${languageId}`);
620
- if (this.languages.has(languageId)) {
621
- this.dbg(`Language ${languageId} already loaded`);
622
- return this.languages.get(languageId);
623
- }
624
- if (!this.ParserClass) {
625
- this.dbg(`ParserClass not initialized`);
626
- return null;
627
- }
628
- const grammarFile = LANGUAGE_TO_GRAMMAR[languageId];
629
- if (!grammarFile) {
630
- this.dbg(`No grammar file for ${languageId}`);
631
- return null;
632
- }
633
- const blockReason = grammarBlockReason(grammarFile);
634
- if (blockReason) {
635
- this.dbg(`Grammar ${grammarFile} blocked on this runtime — ${blockReason}`);
636
- recordDegradation({
637
- kind: "grammar-blocked",
638
- subject: grammarFile,
639
- reason: blockReason
640
- });
641
- return null;
642
- }
643
- let grammarPath = this.resolveGrammarFile(grammarFile);
644
- if (!grammarPath) {
645
- if (await this.ensureGrammar(grammarFile)) {
646
- grammarPath = this.resolveGrammarFile(grammarFile);
647
- }
648
- }
649
- this.dbg(`Grammar path: ${grammarPath}, exists: ${grammarPath && fs.existsSync(grammarPath)}`);
650
- if (!grammarPath || !fs.existsSync(grammarPath)) {
651
- this.dbg(`Grammar file not found: ${grammarPath}`);
652
- return null;
653
- }
654
- try {
655
- if (!this.LanguageLoader?.load) {
656
- this.dbg(`LanguageLoader.load not available`);
657
- return null;
658
- }
659
- this.dbg(`Calling Language.load...`);
660
- const language = await this.LanguageLoader.load(grammarPath);
661
- this.dbg(`Language loaded: ${language?.name || "unknown"}`);
662
- if (language) {
663
- this.languages.set(languageId, language);
664
- }
665
- return language;
666
- } catch (err) {
667
- if (!this.reportWasmAbort(err)) {
668
- this.recordGrammarLoadFailure(grammarPath, grammarFile, err);
669
- }
670
- this.dbg(`Language load error: ${err}`);
671
- return null;
672
- }
673
- }
674
- async getParser(languageId) {
675
- if (this.wasmAborted)
676
- return null;
677
- if (this.parsers.has(languageId)) {
678
- return this.parsers.get(languageId);
679
- }
680
- const language = await this.loadLanguage(languageId);
681
- if (!language || !this.ParserClass)
682
- return null;
683
- const parser = new this.ParserClass;
684
- parser.setLanguage(language);
685
- this.parsers.set(languageId, parser);
686
- return parser;
687
- }
688
- async parseFile(filePath, languageId, contentOverride) {
689
- const outcome = await this.parseFileAndUse(filePath, languageId, contentOverride, (tree) => tree);
690
- return outcome.parsed ? outcome.value : null;
691
- }
692
- async withParsedTree(filePath, languageId, contentOverride, consume) {
693
- return this.parseFileAndUse(filePath, languageId, contentOverride, consume);
694
- }
695
- async parseFileAndUse(filePath, languageId, contentOverride, consume) {
696
- this.dbg(`Parsing ${filePath} with language ${languageId}`);
697
- const parser = await this.getParser(languageId);
698
- if (!parser) {
699
- this.dbg(`Failed to get parser for ${languageId}`);
700
- return NOT_PARSED;
701
- }
702
- let tree;
703
- try {
704
- const content = contentOverride ?? fs.readFileSync(filePath, "utf-8");
705
- this.dbg(`File content length: ${content.length}`);
706
- const cachedTree = this.treeCache.get(filePath, content, languageId);
707
- if (cachedTree) {
708
- this.dbg(`Using cached tree for ${filePath}`);
709
- tree = cachedTree;
710
- } else {
711
- const parseStartedAt = performance.now();
712
- this.recordParserCounter("parserInvocations");
713
- try {
714
- tree = parser.parse(content);
715
- } catch (err) {
716
- this.recordParserCounter("parserFailures");
717
- throw err;
718
- } finally {
719
- this.recordParserCounter("parserDurationMs", performance.now() - parseStartedAt);
720
- }
721
- this.dbg(`Parsed, root node type: ${tree.rootNode.type}`);
722
- this.treeCache.set(filePath, content, languageId, tree);
723
- }
724
- } catch (err) {
725
- this.reportWasmAbort(err);
726
- this.dbg(`Parse error: ${err}`);
727
- return NOT_PARSED;
728
- }
729
- try {
730
- return { parsed: true, value: consume(tree) };
731
- } catch (error) {
732
- this.reportWasmAbort(error);
733
- throw error;
734
- }
735
- }
736
- extractInjections(filePath, content) {
737
- const injections = [];
738
- const sqlPattern = /\b(sql|query|execute)\s*`([^`]+)`/gi;
739
- let match;
740
- while ((match = sqlPattern.exec(content)) !== null) {
741
- const lines = content.slice(0, match.index).split(`
742
- `);
743
- injections.push({
744
- type: "sql",
745
- content: match[2],
746
- line: lines.length,
747
- column: lines[lines.length - 1].length
748
- });
749
- }
750
- const cssPattern = /\b(styled(?:\.\w+)?|css)\s*`([^`]+)`/gi;
751
- while ((match = cssPattern.exec(content)) !== null) {
752
- const lines = content.slice(0, match.index).split(`
753
- `);
754
- injections.push({
755
- type: "css",
756
- content: match[2],
757
- line: lines.length,
758
- column: lines[lines.length - 1].length
759
- });
760
- }
761
- const regexPattern = /new\s+RegExp\s*\(\s*`([^`]+)`/gi;
762
- while ((match = regexPattern.exec(content)) !== null) {
763
- const lines = content.slice(0, match.index).split(`
764
- `);
765
- injections.push({
766
- type: "regex",
767
- content: match[1],
768
- line: lines.length,
769
- column: lines[lines.length - 1].length
770
- });
771
- }
772
- this.dbg(`Found ${injections.length} injections in ${filePath}`);
773
- return injections;
774
- }
775
- isAvailable() {
776
- if (this.wasmAborted)
777
- return false;
778
- if (this.resolveGrammarFile("tree-sitter-typescript.wasm"))
779
- return true;
780
- const dir = this.findGrammarsDir();
781
- this.grammarsDir = dir;
782
- return !!dir && fs.existsSync(dir);
783
- }
784
- async isLanguageSupported(languageId) {
785
- if (this.wasmAborted)
786
- return false;
787
- if (!this.initialized)
788
- await this.init();
789
- const language = await this.loadLanguage(languageId);
790
- return language !== null;
791
- }
792
- getLanguage(languageId) {
793
- if (this.wasmAborted)
794
- return null;
795
- return this.languages.get(languageId) || null;
796
- }
797
- async structuralSearch(pattern, languageId, rootDir, options = {}) {
798
- if (!this.initialized) {
799
- const ok = await this.init();
800
- if (!ok)
801
- return [];
802
- }
803
- try {
804
- await this.queryLoader.loadQueries(rootDir);
805
- } catch (err) {
806
- this.dbg(`Failed to load queries for ${rootDir}: ${err}`);
807
- }
808
- this.dbg(`Compiling pattern: ${pattern.slice(0, 50)}...`);
809
- const compiled = await this.compileQuery(pattern, languageId);
810
- if (!compiled) {
811
- this.dbg(`Pattern compilation failed`);
812
- return [];
813
- }
814
- this.dbg(`Pattern compiled, metavars: ${compiled.metavars.join(", ")}`);
815
- const files = this.collectFiles(rootDir, languageId, options.fileFilter);
816
- this.dbg(`Scanning ${files.length} files...`);
817
- const matches = [];
818
- const maxResults = options.maxResults ?? 50;
819
- for (const file of files) {
820
- if (matches.length >= maxResults)
821
- break;
822
- const fileMatches = await this.searchFileWithQuery(file, compiled.query, compiled.metavars, languageId, pattern, compiled.postFilter, compiled.postFilterParams);
823
- matches.push(...fileMatches);
824
- }
825
- return matches.slice(0, maxResults);
826
- }
827
- async runQueryOnFile(queryDef, filePath, languageId, options = {}, contentOverride) {
828
- if (!this.initialized) {
829
- const ok = await this.init();
830
- if (!ok)
831
- return [];
832
- }
833
- const compiled = await this.compileRawQuery(queryDef.id, queryDef.query, queryDef.metavars, languageId, queryDef.post_filter, queryDef.post_filter_params);
834
- if (!compiled)
835
- return [];
836
- const matches = await this.searchFileWithQuery(filePath, compiled.query, compiled.metavars, languageId, queryDef.id, compiled.postFilter, compiled.postFilterParams, contentOverride);
837
- const maxResults = options.maxResults ?? 50;
838
- return matches.slice(0, maxResults);
839
- }
840
- async runQueriesOnFile(queryDefs, filePath, languageId, options = {}, contentOverride) {
841
- if (queryDefs.length === 0)
842
- return [];
843
- if (!this.initialized) {
844
- const ok = await this.init();
845
- if (!ok)
846
- return [];
847
- }
848
- const maxResults = options.maxResults ?? 50;
849
- const batch = await this.compileQueryBatch(queryDefs, languageId);
850
- if (!batch) {
851
- const results = [];
852
- for (const queryDef of queryDefs) {
853
- const matches = await this.runQueryOnFile(queryDef, filePath, languageId, options, contentOverride);
854
- for (const match of matches)
855
- results.push({ queryDef, match });
856
- }
857
- return results;
858
- }
859
- const perQuery = new Map;
860
- await this.parseFileAndUse(filePath, languageId, contentOverride, (tree) => {
861
- try {
862
- const rootNode = tree.rootNode;
863
- for (const match of batch.query.matches(rootNode)) {
864
- const owner = batch.ownerOfPattern[match.patternIndex];
865
- if (owner === undefined)
866
- continue;
867
- const bucket = perQuery.get(owner) ?? [];
868
- if (bucket.length >= maxResults)
869
- continue;
870
- const entry = batch.entries[owner];
871
- const captures = {};
872
- for (const capture of match.captures) {
873
- if (entry.metavars.includes(capture.name)) {
874
- captures[capture.name] = capture.node;
875
- }
876
- }
877
- if (!this.evaluatePredicates(batch.query, match))
878
- continue;
879
- if (entry.postFilter && !this.applyPostFilter(entry.postFilter, entry.postFilterParams, captures, rootNode)) {
880
- continue;
881
- }
882
- if (match.captures.length === 0)
883
- continue;
884
- const firstNode = match.captures[0].node;
885
- const textCaptures = {};
886
- for (const [name, node] of Object.entries(captures)) {
887
- textCaptures[name] = node.text;
888
- }
889
- bucket.push({
890
- file: filePath,
891
- line: firstNode.startPosition.row + 1,
892
- column: firstNode.startPosition.column + 1,
893
- matchedText: firstNode.text,
894
- nodeType: firstNode.type,
895
- captures: textCaptures
896
- });
897
- perQuery.set(owner, bucket);
898
- }
899
- } catch (err) {
900
- this.reportWasmAbort(err);
901
- this.dbg(`Batched query matching error: ${err}`);
902
- }
903
- });
904
- const results = [];
905
- for (let i = 0;i < batch.entries.length; i++) {
906
- for (const match of perQuery.get(i) ?? []) {
907
- results.push({ queryDef: batch.entries[i].queryDef, match });
908
- }
909
- }
910
- return results;
911
- }
912
- async compileQueryBatch(queryDefs, languageId) {
913
- const identity = crypto.createHash("sha256").update(JSON.stringify(queryDefs)).digest("hex");
914
- const cacheKey = this.getQueryCacheKey(`batch:${identity}`, languageId);
915
- const cached = this.queryBatchCache.get(cacheKey);
916
- if (cached !== undefined) {
917
- this.queryBatchCache.delete(cacheKey);
918
- this.queryBatchCache.set(cacheKey, cached);
919
- return cached;
920
- }
921
- const language = await this.loadLanguage(languageId);
922
- if (!language) {
923
- const failures = (this.queryBatchLoadFailures.get(cacheKey) ?? 0) + 1;
924
- if (failures >= QUERY_BATCH_MAX_LOAD_FAILURES) {
925
- this.dbg(`Batch: grammar for ${languageId} failed to load ${failures} times — caching miss`);
926
- this.queryBatchLoadFailures.delete(cacheKey);
927
- this.cacheQueryBatch(cacheKey, null);
928
- } else {
929
- this.queryBatchLoadFailures.set(cacheKey, failures);
930
- }
931
- return null;
932
- }
933
- this.queryBatchLoadFailures.delete(cacheKey);
934
- const build = async () => {
935
- const Query = (await loadWebTreeSitter()).Query;
936
- const entries = [];
937
- const sources = [];
938
- const ownerOfPattern = [];
939
- for (const queryDef of queryDefs) {
940
- let patternCount;
941
- try {
942
- const probe = new Query(language, queryDef.query);
943
- patternCount = probe.patternCount();
944
- probe.delete?.();
945
- } catch (err) {
946
- if (this.reportWasmAbort(err))
947
- return null;
948
- this.dbg(`Batch: skipping ${queryDef.id} for ${languageId}: ${err}`);
949
- this.reportQueryCompileFailure(queryDef.id, languageId, err);
950
- continue;
951
- }
952
- const owner = entries.length;
953
- entries.push({
954
- queryDef,
955
- metavars: queryDef.metavars ?? [],
956
- postFilter: queryDef.post_filter,
957
- postFilterParams: queryDef.post_filter_params
958
- });
959
- sources.push(queryDef.query);
960
- for (let i = 0;i < patternCount; i++)
961
- ownerOfPattern.push(owner);
962
- }
963
- if (entries.length === 0)
964
- return null;
965
- try {
966
- const query = new Query(language, sources.join(`
967
- `));
968
- if (query.patternCount() !== ownerOfPattern.length) {
969
- this.dbg(`Batch pattern count mismatch for ${languageId} (${query.patternCount()} vs ${ownerOfPattern.length}) — falling back`);
970
- return null;
971
- }
972
- return { query, entries, ownerOfPattern };
973
- } catch (err) {
974
- if (this.reportWasmAbort(err))
975
- return null;
976
- this.dbg(`Batch compile failed for ${languageId}: ${err}`);
977
- return null;
978
- }
979
- };
980
- const batch = await build();
981
- this.cacheQueryBatch(cacheKey, batch);
982
- return batch;
983
- }
984
- patternToQuery(pattern, languageId) {
985
- const loadedQuery = this.queryLoader.findMatchingQuery(pattern, languageId);
986
- if (loadedQuery) {
987
- this.dbg(`Using loaded query: ${loadedQuery.id}`);
988
- return {
989
- query: loadedQuery.query,
990
- metavars: loadedQuery.metavars,
991
- postFilter: loadedQuery.post_filter,
992
- postFilterParams: loadedQuery.post_filter_params,
993
- queryDef: loadedQuery
994
- };
995
- }
996
- return this.getInlinePattern(pattern);
997
- }
998
- getInlinePattern(pattern) {
999
- if (pattern.includes("async function") && pattern.includes("$NAME")) {
1000
- return {
1001
- query: `(function_declaration
1002
- "async"
1003
- name: (identifier) @NAME
1004
- parameters: (formal_parameters) @PARAMS
1005
- body: (statement_block) @BODY)`,
1006
- metavars: ["NAME", "PARAMS", "BODY"]
1007
- };
1008
- }
1009
- if (pattern.includes("console")) {
1010
- return {
1011
- query: `(call_expression
1012
- function: (member_expression
1013
- object: (identifier) @OBJ (#eq? @OBJ "console")
1014
- property: (property_identifier) @METHOD)
1015
- arguments: (arguments) @ARGS)`,
1016
- metavars: ["OBJ", "METHOD", "ARGS"]
1017
- };
1018
- }
1019
- if (pattern.includes("function $NAME") && pattern.includes("PARAMS")) {
1020
- return {
1021
- query: `(function_declaration
1022
- name: (identifier) @NAME
1023
- parameters: (formal_parameters) @PARAMS
1024
- body: (statement_block) @BODY)`,
1025
- metavars: ["NAME", "PARAMS", "BODY"],
1026
- postFilter: "count_params",
1027
- postFilterParams: { min_params: 6 }
1028
- };
1029
- }
1030
- if (pattern.includes(".then") && pattern.includes(".catch")) {
1031
- return {
1032
- query: `(call_expression
1033
- function: (member_expression
1034
- object: (call_expression
1035
- function: (member_expression
1036
- object: (call_expression
1037
- function: (member_expression
1038
- property: (property_identifier) @M1)
1039
- arguments: (arguments))
1040
- property: (property_identifier) @M2)
1041
- arguments: (arguments))
1042
- property: (property_identifier) @M3)
1043
- arguments: (arguments))
1044
- (#match? @M1 "^(then|catch)$")
1045
- (#match? @M2 "^(then|catch)$")
1046
- (#match? @M3 "^(then|catch)$")`,
1047
- metavars: ["M1", "M2", "M3"]
1048
- };
1049
- }
1050
- const simpleMatch = pattern.match(/\$([A-Z_][A-Z0-9_]*)/);
1051
- if (simpleMatch) {
1052
- const name = simpleMatch[1];
1053
- return {
1054
- query: `(identifier) @${name}`,
1055
- metavars: [name]
1056
- };
1057
- }
1058
- return { query: "", metavars: [] };
1059
- }
1060
- getQueryCacheKey(pattern, languageId) {
1061
- return `${languageId}:${pattern}`;
1062
- }
1063
- async compileQuery(pattern, languageId) {
1064
- const cacheKey = this.getQueryCacheKey(pattern, languageId);
1065
- if (this.queryCache.has(cacheKey)) {
1066
- this.dbg(`Query cache hit: ${cacheKey}`);
1067
- const cached = this.queryCache.get(cacheKey);
1068
- this.queryCache.delete(cacheKey);
1069
- this.queryCache.set(cacheKey, cached);
1070
- return cached;
1071
- }
1072
- const language = await this.loadLanguage(languageId);
1073
- if (!language) {
1074
- this.dbg(`Could not load language ${languageId}`);
1075
- return null;
1076
- }
1077
- const { query: queryStr, metavars, postFilter, postFilterParams } = this.patternToQuery(pattern, languageId);
1078
- this.dbg(`Query string: ${queryStr.slice(0, 100)}...`);
1079
- try {
1080
- const Query = (await loadWebTreeSitter()).Query;
1081
- const query = new Query(language, queryStr);
1082
- this.dbg(`Query compiled with ${query.patternCount()} patterns`);
1083
- const result = { query, metavars, postFilter, postFilterParams };
1084
- this.cacheQuery(cacheKey, result);
1085
- return result;
1086
- } catch (err) {
1087
- this.reportWasmAbort(err);
1088
- this.dbg(`Query compilation failed: ${err}`);
1089
- return null;
1090
- }
1091
- }
1092
- async compileRawQuery(queryId, queryStr, metavars, languageId, postFilter, postFilterParams) {
1093
- const cacheKey = this.getQueryCacheKey(`raw:${queryId}:${queryStr}`, languageId);
1094
- if (this.queryCache.has(cacheKey)) {
1095
- const cached = this.queryCache.get(cacheKey);
1096
- this.queryCache.delete(cacheKey);
1097
- this.queryCache.set(cacheKey, cached);
1098
- return cached;
1099
- }
1100
- const language = await this.loadLanguage(languageId);
1101
- if (!language)
1102
- return null;
1103
- try {
1104
- const Query = (await loadWebTreeSitter()).Query;
1105
- const query = new Query(language, queryStr);
1106
- const result = { query, metavars, postFilter, postFilterParams };
1107
- this.cacheQuery(cacheKey, result);
1108
- return result;
1109
- } catch (err) {
1110
- this.reportWasmAbort(err);
1111
- this.dbg(`Raw query compilation failed (${queryId}): ${err}`);
1112
- this.reportQueryCompileFailure(queryId, languageId, err);
1113
- return null;
1114
- }
1115
- }
1116
- reportedCompileFailures = new Set;
1117
- reportQueryCompileFailure(ruleId, languageId, err) {
1118
- const key = `${ruleId}:${languageId}`;
1119
- if (this.reportedCompileFailures.has(key))
1120
- return;
1121
- this.reportedCompileFailures.add(key);
1122
- logTreeSitterDiagnostic({
1123
- subsystem: "tree-sitter-client",
1124
- languageId,
1125
- message: `tree-sitter rule '${ruleId}' failed to compile against '${languageId}' — ` + `matches for this rule are silently dropped rather than reported. ` + `Fix the query in the rule definition to re-enable it. (${err})`,
1126
- metadata: { ruleId }
1127
- });
1128
- }
1129
- hasChildToken(node, token) {
1130
- return node.children?.some((child) => child.type === token || child.text === token);
1131
- }
1132
- bindingNames(node) {
1133
- const names = new Set;
1134
- if (!node)
1135
- return names;
1136
- const stack = [node];
1137
- while (stack.length > 0) {
1138
- const current = stack.pop();
1139
- if (current.type === "identifier")
1140
- names.add(current.text);
1141
- else if (current.type === "shorthand_property_identifier_pattern") {
1142
- names.add(current.text);
1143
- }
1144
- if (current.type === "property_identifier" || current.type === "type_identifier" || current.type === "computed_property_name")
1145
- continue;
1146
- if (current.type === "assignment_pattern" || current.type === "object_assignment_pattern") {
1147
- const left = current.childForFieldName?.("left");
1148
- if (left)
1149
- stack.push(left);
1150
- continue;
1151
- }
1152
- stack.push(...current.children ?? []);
1153
- }
1154
- return names;
1155
- }
1156
- containsYieldInFunctionBody(node, root = node) {
1157
- for (const child of node.children ?? []) {
1158
- if (child.type === "yield")
1159
- return true;
1160
- if (child !== root && ["function_definition", "class_definition", "lambda"].includes(child.type)) {
1161
- continue;
1162
- }
1163
- if (this.containsYieldInFunctionBody(child, root))
1164
- return true;
1165
- }
1166
- return false;
1167
- }
1168
- isLikelySqlAlchemyReceiver(text) {
1169
- const tail = text.split(".").pop() ?? text;
1170
- return PYTHON_SQLALCHEMY_RECEIVER_NAMES.has(tail.toLowerCase());
1171
- }
1172
- switchCaseBodyStatements(caseNode) {
1173
- const named = (caseNode.children ?? []).filter((c) => c.isNamed && !c.type.includes("comment"));
1174
- return named.slice(1);
1175
- }
1176
- hasFallthroughMarker(caseNode) {
1177
- const comments = [];
1178
- const body = this.switchCaseBodyStatements(caseNode);
1179
- const last = body[body.length - 1];
1180
- const lastEnd = last?.endIndex ?? caseNode.startIndex;
1181
- for (const c of caseNode.children ?? []) {
1182
- if (c.type.includes("comment") && c.startIndex >= lastEnd) {
1183
- comments.push(c);
1184
- }
1185
- }
1186
- const siblings = (caseNode.parent?.children ?? []).filter((c) => c.isNamed);
1187
- const index = siblings.findIndex((c) => c.startIndex === caseNode.startIndex);
1188
- const next = index >= 0 ? siblings[index + 1] : undefined;
1189
- if (next?.type.includes("comment"))
1190
- comments.push(next);
1191
- if (last) {
1192
- const NESTED_FN = new Set([
1193
- "function_declaration",
1194
- "function_expression",
1195
- "arrow_function",
1196
- "method_definition",
1197
- "generator_function",
1198
- "generator_function_declaration",
1199
- "class_declaration"
1200
- ]);
1201
- const stack = [last];
1202
- for (let visited = 0;stack.length > 0 && visited < 500; visited++) {
1203
- const node = stack.pop();
1204
- if (!node)
1205
- break;
1206
- if (node.type.includes("comment"))
1207
- comments.push(node);
1208
- if (!NESTED_FN.has(node.type)) {
1209
- stack.push(...node.children ?? []);
1210
- }
1211
- }
1212
- }
1213
- return comments.some((c) => /falls?\s?through/i.test(c.text));
1214
- }
1215
- statementTerminates(node, depth = 0) {
1216
- if (depth > 20)
1217
- return false;
1218
- const t = node.type;
1219
- const TERMINATORS = new Set([
1220
- "break_statement",
1221
- "return_statement",
1222
- "throw_statement",
1223
- "continue_statement"
1224
- ]);
1225
- if (TERMINATORS.has(t))
1226
- return true;
1227
- if (t === "statement_block" || t === "else_clause" || t === "catch_clause" || t === "finally_clause") {
1228
- const inner = (node.children ?? []).filter((c) => c.isNamed && !c.type.includes("comment"));
1229
- const last = inner[inner.length - 1];
1230
- if (!last)
1231
- return false;
1232
- return this.statementTerminates(last, depth + 1);
1233
- }
1234
- if (t === "try_statement") {
1235
- const tryBody = (node.children ?? []).find((c) => c.type === "statement_block");
1236
- const tryTerminates = tryBody ? this.statementTerminates(tryBody, depth + 1) : false;
1237
- const catches = (node.children ?? []).filter((c) => c.type === "catch_clause");
1238
- const fin = (node.children ?? []).find((c) => c.type === "finally_clause");
1239
- if (tryTerminates) {
1240
- return catches.every((c) => this.statementTerminates(c, depth + 1));
1241
- }
1242
- return !!fin && this.statementTerminates(fin, depth + 1);
1243
- }
1244
- if (t === "if_statement") {
1245
- const named = (node.children ?? []).filter((c) => c.isNamed && !c.type.includes("comment"));
1246
- const consequence = named[1];
1247
- const alternative = named[2];
1248
- if (!consequence || !alternative)
1249
- return false;
1250
- return this.statementTerminates(consequence, depth + 1) && this.statementTerminates(alternative, depth + 1);
1251
- }
1252
- return false;
1253
- }
1254
- nextSiblingIsSwitchLabel(caseNode) {
1255
- const siblings = (caseNode.parent?.children ?? []).filter((c) => c.isNamed && !c.type.includes("comment"));
1256
- const index = siblings.findIndex((c) => c.startIndex === caseNode.startIndex);
1257
- const next = index >= 0 ? siblings[index + 1] : undefined;
1258
- return next?.type === "switch_case" || next?.type === "switch_default";
1259
- }
1260
- bodyHasLoopExit(node, insideNestedLoop) {
1261
- const NESTS_BREAK = new Set([
1262
- "for_statement",
1263
- "for_in_statement",
1264
- "while_statement",
1265
- "do_statement",
1266
- "switch_statement"
1267
- ]);
1268
- const NESTED_FN = new Set([
1269
- "function_declaration",
1270
- "function_expression",
1271
- "arrow_function",
1272
- "method_definition",
1273
- "generator_function",
1274
- "generator_function_declaration",
1275
- "class_declaration"
1276
- ]);
1277
- for (const child of node.children ?? []) {
1278
- const t = child.type;
1279
- if (NESTED_FN.has(t))
1280
- continue;
1281
- if (t === "return_statement" || t === "throw_statement")
1282
- return true;
1283
- if (t === "break_statement") {
1284
- const labeled = (child.children ?? []).some((c) => c.isNamed);
1285
- if (!insideNestedLoop || labeled)
1286
- return true;
1287
- }
1288
- if (this.bodyHasLoopExit(child, insideNestedLoop || NESTS_BREAK.has(t))) {
1289
- return true;
1290
- }
1291
- }
1292
- return false;
1293
- }
1294
- enclosingBindingName(node) {
1295
- let cur = node?.parent;
1296
- for (let depth = 0;cur && depth < 12; depth++) {
1297
- const t = cur.type;
1298
- if (t === "variable_declarator") {
1299
- const name = cur.children?.find((c) => c.isNamed);
1300
- return name?.text ?? "";
1301
- }
1302
- if (t === "assignment_expression") {
1303
- return cur.children?.[0]?.text ?? "";
1304
- }
1305
- if (t === "statement_block" || t === "program" || t === "function_declaration" || t === "function_expression" || t === "arrow_function" || t === "method_definition") {
1306
- return "";
1307
- }
1308
- cur = cur.parent;
1309
- }
1310
- return "";
1311
- }
1312
- resolvesToFileLiteralConst(name, rootNode) {
1313
- const valueNode = this.resolveFileConstValueNode(name, rootNode);
1314
- if (!valueNode)
1315
- return false;
1316
- return this.isFixedUrlLiteralExpr(valueNode);
1317
- }
1318
- resolveFileConstValueNode(name, rootNode) {
1319
- const constDeclarators = [];
1320
- let hasNonConstBinding = false;
1321
- let hasReassignment = false;
1322
- const stack = [rootNode];
1323
- while (stack.length > 0) {
1324
- const node = stack.pop();
1325
- if (!node)
1326
- continue;
1327
- if (node.type === "variable_declarator") {
1328
- const nameNode = node.childForFieldName?.("name");
1329
- if (nameNode?.type === "identifier" && nameNode.text === name) {
1330
- const decl = node.parent;
1331
- const isConst = decl?.type === "lexical_declaration" && (decl.children ?? []).some((c) => c.type === "const");
1332
- if (isConst) {
1333
- constDeclarators.push(node);
1334
- } else {
1335
- hasNonConstBinding = true;
1336
- }
1337
- }
1338
- } else if (node.type === "assignment_expression" || node.type === "augmented_assignment_expression") {
1339
- const left = node.childForFieldName?.("left");
1340
- if (left?.type === "identifier" && left.text === name) {
1341
- hasReassignment = true;
1342
- } else if ((left?.type === "member_expression" || left?.type === "subscript_expression") && left.childForFieldName?.("object")?.type === "identifier" && left.childForFieldName?.("object")?.text === name) {
1343
- const searchOnly = left.type === "member_expression" && left.childForFieldName?.("property")?.text === "search";
1344
- if (!searchOnly) {
1345
- hasReassignment = true;
1346
- }
1347
- }
1348
- }
1349
- for (const child of node.children ?? [])
1350
- stack.push(child);
1351
- }
1352
- if (hasNonConstBinding || hasReassignment || constDeclarators.length !== 1) {
1353
- return null;
1354
- }
1355
- return constDeclarators[0].childForFieldName?.("value") ?? null;
1356
- }
1357
- isFixedUrlLiteralExpr(node) {
1358
- if (node.type === "string")
1359
- return true;
1360
- if (node.type === "template_string") {
1361
- return !(node.children ?? []).some((c) => c.type === "template_substitution");
1362
- }
1363
- return false;
1364
- }
1365
- isImportedBinding(name, rootNode) {
1366
- return this.importedAs(name, rootNode) !== null;
1367
- }
1368
- importedAs(name, rootNode) {
1369
- const stack = [rootNode];
1370
- while (stack.length > 0) {
1371
- const node = stack.pop();
1372
- if (!node)
1373
- continue;
1374
- if (node.type === "import_specifier") {
1375
- const nameNode = node.childForFieldName?.("name");
1376
- const aliasNode = node.childForFieldName?.("alias");
1377
- const local = (aliasNode ?? nameNode)?.text;
1378
- if (local === name)
1379
- return nameNode?.text ?? null;
1380
- } else if (node.type === "namespace_import" || node.type === "import_clause") {
1381
- for (const c of node.children ?? []) {
1382
- if (c.type === "identifier" && c.text === name)
1383
- return name;
1384
- }
1385
- }
1386
- for (const child of node.children ?? [])
1387
- stack.push(child);
1388
- }
1389
- return null;
1390
- }
1391
- isFixedUrlBaseExpr(base, rootNode) {
1392
- if (base.type === "string")
1393
- return true;
1394
- if (base.type === "identifier") {
1395
- return this.isFixedBaseIdentifier(base, rootNode);
1396
- }
1397
- if (base.type === "template_string") {
1398
- for (const child of base.children ?? []) {
1399
- if (child.type !== "template_substitution")
1400
- continue;
1401
- const inner = (child.children ?? []).find((c) => c.isNamed);
1402
- if (!inner || inner.type !== "identifier" || !this.isFixedBaseIdentifier(inner, rootNode)) {
1403
- return false;
1404
- }
1405
- }
1406
- return true;
1407
- }
1408
- return false;
1409
- }
1410
- isFixedBaseIdentifier(ident, rootNode) {
1411
- const name = ident.text;
1412
- if (!this.isShadowedByEnclosingParam(ident, name) && this.resolvesToFileLiteralConst(name, rootNode)) {
1413
- return true;
1414
- }
1415
- return this.isImportedBinding(name, rootNode);
1416
- }
1417
- isShadowedByEnclosingParam(node, name) {
1418
- const FUNCTION_TYPES = new Set([
1419
- "function_declaration",
1420
- "function_expression",
1421
- "generator_function",
1422
- "generator_function_declaration",
1423
- "arrow_function",
1424
- "method_definition"
1425
- ]);
1426
- let current = node.parent;
1427
- while (current) {
1428
- if (FUNCTION_TYPES.has(current.type)) {
1429
- const bare = current.childForFieldName?.("parameter");
1430
- if (bare?.type === "identifier" && bare.text === name)
1431
- return true;
1432
- const params = current.childForFieldName?.("parameters");
1433
- if (params && this.paramsBindName(params, name))
1434
- return true;
1435
- }
1436
- current = current.parent;
1437
- }
1438
- return false;
1439
- }
1440
- paramsBindName(params, name) {
1441
- for (const param of params.children ?? []) {
1442
- if (!param.isNamed)
1443
- continue;
1444
- const pattern = param.type === "required_parameter" || param.type === "optional_parameter" ? param.childForFieldName?.("pattern") : param;
1445
- if (pattern && this.patternBindsName(pattern, name))
1446
- return true;
1447
- }
1448
- return false;
1449
- }
1450
- patternBindsName(pattern, name) {
1451
- if (pattern.type === "identifier")
1452
- return pattern.text === name;
1453
- const stack = [pattern];
1454
- while (stack.length > 0) {
1455
- const n = stack.pop();
1456
- if (!n)
1457
- continue;
1458
- if ((n.type === "identifier" || n.type === "shorthand_property_identifier_pattern") && n.text === name) {
1459
- return true;
1460
- }
1461
- if (n.type === "assignment_pattern") {
1462
- const left = n.childForFieldName?.("left") ?? n.children?.[0];
1463
- if (left)
1464
- stack.push(left);
1465
- continue;
1466
- }
1467
- for (const c of n.children ?? [])
1468
- stack.push(c);
1469
- }
1470
- return false;
1471
- }
1472
- resolvesToFixedNewUrlConst(name, rootNode) {
1473
- const value = this.resolveFileConstValueNode(name, rootNode);
1474
- if (!value || value.type !== "new_expression")
1475
- return false;
1476
- const ctor = value.childForFieldName?.("constructor");
1477
- const ctorName = ctor?.text ?? "";
1478
- const isUrlCtor = ctorName === "URL" || ctor?.type === "identifier" && this.importedAs(ctorName, rootNode) === "URL";
1479
- if (!isUrlCtor)
1480
- return false;
1481
- const args = (value.childForFieldName?.("arguments")?.children ?? []).filter((c) => c.isNamed && c.type !== "comment");
1482
- if (args.length === 0)
1483
- return false;
1484
- if (!this.isFixedUrlLiteralExpr(args[0]))
1485
- return false;
1486
- if (args.length === 1)
1487
- return true;
1488
- return this.isFixedUrlBaseExpr(args[1], rootNode);
1489
- }
1490
- newUrlBaseVarName(urlNode) {
1491
- let member;
1492
- if (urlNode.type === "call_expression") {
1493
- member = urlNode.childForFieldName?.("function");
1494
- } else if (urlNode.type === "member_expression") {
1495
- member = urlNode;
1496
- }
1497
- if (!member || member.type !== "member_expression")
1498
- return null;
1499
- const prop = member.childForFieldName?.("property")?.text;
1500
- if (prop !== "toString" && prop !== "href")
1501
- return null;
1502
- const object = member.childForFieldName?.("object");
1503
- if (object?.type !== "identifier")
1504
- return null;
1505
- return object.text;
1506
- }
1507
- isSafeSqlAlchemyExpressionCall(node) {
1508
- if (node.type !== "call")
1509
- return false;
1510
- const callee = node.children?.[0]?.text ?? "";
1511
- const expression = node.text;
1512
- for (const name of PYTHON_SQLALCHEMY_STATEMENT_BUILDERS) {
1513
- if (callee === name || expression.startsWith(`${name}(`))
1514
- return true;
1515
- }
1516
- return false;
1517
- }
1518
- applyPostFilter(postFilter, postFilterParams, captures, rootNode) {
1519
- function extractSlots(classNode) {
1520
- const classText = classNode.text ?? "";
1521
- if (!classText.includes("__slots__"))
1522
- return null;
1523
- const body = classNode.children?.find((c) => c.type === "block");
1524
- if (!body)
1525
- return null;
1526
- const slots = [];
1527
- for (const stmt of body.children ?? []) {
1528
- if (stmt.type !== "expression_statement")
1529
- continue;
1530
- const assignment = stmt.children?.find((c) => c.type === "assignment");
1531
- if (!assignment)
1532
- continue;
1533
- const lhsText = (assignment.children?.[0]?.text ?? "").trim();
1534
- if (lhsText !== "__slots__")
1535
- continue;
1536
- const rhs = assignment.children?.[2];
1537
- if (!rhs)
1538
- continue;
1539
- if (rhs.type === "string") {
1540
- const s = (rhs.text ?? "").replace(/^["']|["']$/g, "");
1541
- if (s)
1542
- slots.push(s);
1543
- } else if (rhs.type === "tuple" || rhs.type === "list") {
1544
- for (const el of rhs.children ?? []) {
1545
- if (!el.isNamed)
1546
- continue;
1547
- if (el.type === "string") {
1548
- slots.push((el.text ?? "").replace(/^["']|["']$/g, ""));
1549
- }
1550
- }
1551
- }
1552
- break;
1553
- }
1554
- return slots;
1555
- }
1556
- switch (postFilter) {
1557
- case "no_nested_anchor_chain": {
1558
- try {
1559
- const outer = captures.OUTER_ELEMENT;
1560
- if (!outer) {
1561
- this.reportPostFilterFailure(postFilter, "missing OUTER_ELEMENT capture");
1562
- return true;
1563
- }
1564
- const isAnchorElement = (node) => {
1565
- if (node.type !== "jsx_element")
1566
- return false;
1567
- const opening = node.childForFieldName?.("open_tag") ?? node.children?.find((child) => child.type === "jsx_opening_element");
1568
- const name = opening?.childForFieldName?.("name") ?? opening?.children?.find((child) => child.type === "identifier");
1569
- return name?.text === "a";
1570
- };
1571
- let visited = 0;
1572
- let ancestor = outer.parent;
1573
- while (ancestor) {
1574
- if (++visited > NO_NESTED_ANCHOR_VISIT_CAP) {
1575
- this.reportPostFilterFailure(postFilter, `ancestor walk exceeded ${NO_NESTED_ANCHOR_VISIT_CAP} nodes`);
1576
- return true;
1577
- }
1578
- if (isAnchorElement(ancestor))
1579
- return false;
1580
- ancestor = ancestor.parent;
1581
- }
1582
- const pending = [...outer.children ?? []];
1583
- while (pending.length > 0) {
1584
- const node = pending.pop();
1585
- if (!node)
1586
- continue;
1587
- if (++visited > NO_NESTED_ANCHOR_VISIT_CAP) {
1588
- this.reportPostFilterFailure(postFilter, `descendant walk exceeded ${NO_NESTED_ANCHOR_VISIT_CAP} nodes`);
1589
- return true;
1590
- }
1591
- if (isAnchorElement(node))
1592
- return true;
1593
- pending.push(...node.children ?? []);
1594
- }
1595
- return false;
1596
- } catch (error) {
1597
- const reason = error instanceof Error ? error.message : String(error);
1598
- this.reportPostFilterFailure(postFilter, `tree walk failed${reason ? `: ${reason}` : ""}`);
1599
- return true;
1600
- }
1601
- }
1602
- case "differs_only_by_case": {
1603
- try {
1604
- const field = captures.FIELD?.text ?? "";
1605
- const method = captures.METHOD?.text ?? "";
1606
- return field !== method && field.toLocaleLowerCase() === method.toLocaleLowerCase();
1607
- } catch {
1608
- return true;
1609
- }
1610
- }
1611
- case "in_default_package": {
1612
- try {
1613
- if (!rootNode)
1614
- return true;
1615
- return !(rootNode.children ?? []).some((node) => node.type === "package_declaration");
1616
- } catch {
1617
- return true;
1618
- }
1619
- }
1620
- case "missing_mimetype_and_download_name": {
1621
- try {
1622
- const firstArg = captures.FIRST_ARG;
1623
- if (!firstArg)
1624
- return true;
1625
- if (firstArg.type === "string")
1626
- return false;
1627
- const args = firstArg.parent;
1628
- if (!args)
1629
- return true;
1630
- return !(args.children ?? []).some((node) => {
1631
- if (node.type !== "keyword_argument")
1632
- return false;
1633
- const name = node.childForFieldName?.("name")?.text;
1634
- return name === "mimetype" || name === "download_name";
1635
- });
1636
- } catch {
1637
- return true;
1638
- }
1639
- }
1640
- case "missing_super_call": {
1641
- try {
1642
- const body = captures.BODY;
1643
- const method = captures.METHOD?.text ?? "";
1644
- if (!body || !method)
1645
- return true;
1646
- const stack = [body];
1647
- for (let visited = 0;stack.length > 0 && visited < 1e4; visited++) {
1648
- const node = stack.pop();
1649
- if (!node)
1650
- break;
1651
- if (node.type === "method_invocation" && node.childForFieldName?.("object")?.text === "super" && node.childForFieldName?.("name")?.text === method) {
1652
- return false;
1653
- }
1654
- stack.push(...node.children ?? []);
1655
- }
1656
- return true;
1657
- } catch {
1658
- return true;
1659
- }
1660
- }
1661
- case "no_assertion_call": {
1662
- try {
1663
- const body = captures.BODY;
1664
- if (!body)
1665
- return true;
1666
- const assertionNames = /^(?:assert\w*|fail|verify|expect|check|assume\w*)$/i;
1667
- const stack = [body];
1668
- for (let visited = 0;stack.length > 0 && visited < 1e4; visited++) {
1669
- const node = stack.pop();
1670
- if (!node)
1671
- break;
1672
- if (node.type === "method_invocation") {
1673
- const name = node.childForFieldName?.("name")?.text ?? "";
1674
- if (assertionNames.test(name))
1675
- return false;
1676
- }
1677
- stack.push(...node.children ?? []);
1678
- }
1679
- return true;
1680
- } catch {
1681
- return true;
1682
- }
1683
- }
1684
- case "not_closed_or_try_with_resources": {
1685
- try {
1686
- const declaration = captures.DECL;
1687
- const resource = captures.RESOURCE?.text ?? "";
1688
- if (!declaration || !resource)
1689
- return true;
1690
- const scope = this.navigator.findParent(declaration, [
1691
- "method_declaration",
1692
- "constructor_declaration",
1693
- "block"
1694
- ]) ?? rootNode;
1695
- if (!scope)
1696
- return true;
1697
- const resourceWord = new RegExp(`\\b${escapeRegExp(resource)}\\b`);
1698
- const stack = [scope];
1699
- for (let visited = 0;stack.length > 0 && visited < 1e4; visited++) {
1700
- const node = stack.pop();
1701
- if (!node)
1702
- break;
1703
- if (node.type === "method_invocation" && node.childForFieldName?.("object")?.text === resource && node.childForFieldName?.("name")?.text === "close") {
1704
- return false;
1705
- }
1706
- if (node.type === "resource" && resourceWord.test(node.text ?? "")) {
1707
- return false;
1708
- }
1709
- stack.push(...node.children ?? []);
1710
- }
1711
- return true;
1712
- } catch {
1713
- return true;
1714
- }
1715
- }
1716
- case "same_method_no_base_case": {
1717
- try {
1718
- const method = captures.NAME?.text ?? "";
1719
- if (!method || captures.RECURSE?.text !== method)
1720
- return false;
1721
- const call = captures.CALL;
1722
- const declaration = call ? this.navigator.findParent(call, ["method_declaration"]) : undefined;
1723
- if (!declaration)
1724
- return true;
1725
- const stack = [declaration];
1726
- for (let visited = 0;stack.length > 0 && visited < 1e4; visited++) {
1727
- const node = stack.pop();
1728
- if (!node)
1729
- break;
1730
- if (node.type === "if_statement" || node.type === "switch_expression" || node.type === "switch_statement" || node.type === "while_statement" || node.type === "do_statement" || node.type === "for_statement" || node.type === "enhanced_for_statement" || node.type === "ternary_expression") {
1731
- return false;
1732
- }
1733
- stack.push(...node.children ?? []);
1734
- }
1735
- return stack.length > 0 ? false : true;
1736
- } catch {
1737
- return true;
1738
- }
1739
- }
1740
- case "memset_for_sensitive_data": {
1741
- try {
1742
- const destination = captures.DEST?.text ?? "";
1743
- const value = captures.VALUE?.text?.trim() ?? "";
1744
- if (!/^(?:0|0x0+|NULL|nullptr)$/.test(value))
1745
- return false;
1746
- return /(?:pass(?:word)?|passwd|secret|token|api_?key|private_?key|credential|auth|pin)/i.test(destination);
1747
- } catch {
1748
- return true;
1749
- }
1750
- }
1751
- case "unsafe_regex_dynamic_identifier": {
1752
- try {
1753
- const interpolationNode = captures.INTERPOLATION;
1754
- const interpolation = interpolationNode?.text ?? "";
1755
- const identifier = interpolation.match(/^\$\{\s*([A-Za-z_$][\w$]*)\s*\}$/)?.[1];
1756
- if (!identifier || !rootNode || !interpolationNode)
1757
- return true;
1758
- const useRow = interpolationNode.startPosition.row;
1759
- const hasEscapeSignal = (text) => /\b(?:escape|Escape)\w*\s*\(/.test(text) || /\.\s*replace\s*\(\s*\//.test(text);
1760
- let lastWriteRow = -1;
1761
- let lastWriteSafe = false;
1762
- const consider = (row, valueText) => {
1763
- if (row >= useRow || row < lastWriteRow)
1764
- return;
1765
- lastWriteRow = row;
1766
- lastWriteSafe = valueText !== undefined && hasEscapeSignal(valueText);
1767
- };
1768
- const stack = [rootNode];
1769
- while (stack.length > 0) {
1770
- const node = stack.pop();
1771
- if (!node)
1772
- continue;
1773
- if (node.type === "variable_declarator") {
1774
- const name = node.childForFieldName?.("name");
1775
- if (name?.text === identifier) {
1776
- const initializer = node.childForFieldName?.("value");
1777
- consider(node.startPosition.row, initializer?.text);
1778
- }
1779
- } else if (node.type === "assignment_expression") {
1780
- const left = node.childForFieldName?.("left");
1781
- if (left?.type === "identifier" && left.text === identifier) {
1782
- const right = node.childForFieldName?.("right");
1783
- consider(node.startPosition.row, right?.text);
1784
- }
1785
- }
1786
- stack.push(...node.children);
1787
- }
1788
- return lastWriteRow >= 0 && lastWriteSafe ? false : true;
1789
- } catch {
1790
- return true;
1791
- }
1792
- }
1793
- case "is_generator_with_valued_return": {
1794
- const returnNode = captures.RETURN;
1795
- const functionNode = captures.FUNCTION ?? (returnNode ? this.navigator.findParent(returnNode, ["function_definition"]) : undefined);
1796
- if (!functionNode)
1797
- return false;
1798
- if (this.hasChildToken(functionNode, "async"))
1799
- return false;
1800
- return this.containsYieldInFunctionBody(functionNode);
1801
- }
1802
- case "count_params": {
1803
- const paramsNode = captures.PARAMS;
1804
- if (!paramsNode)
1805
- return true;
1806
- const paramCount = paramsNode.children.filter((c) => {
1807
- if (c.type !== "required_parameter")
1808
- return false;
1809
- if (c.text.includes("="))
1810
- return false;
1811
- if (c.children?.some((ch) => ch.text === "?"))
1812
- return false;
1813
- return true;
1814
- }).length;
1815
- return paramCount >= (postFilterParams?.min_params ?? 6);
1816
- }
1817
- case "empty_body": {
1818
- const bodyNode = captures.BODY;
1819
- if (!bodyNode)
1820
- return true;
1821
- const meaningful = bodyNode.children.filter((c) => c.isNamed && c.type !== "comment" && c.type !== "line_comment" && c.type !== "block_comment");
1822
- return meaningful.length === 0;
1823
- }
1824
- case "is_empty_block": {
1825
- const caseNode = captures.CASE;
1826
- if (!caseNode)
1827
- return false;
1828
- if (this.switchCaseBodyStatements(caseNode).length > 0)
1829
- return false;
1830
- return !this.nextSiblingIsSwitchLabel(caseNode);
1831
- }
1832
- case "no_break_or_return_in_body": {
1833
- const bodyNode = captures.BODY;
1834
- if (!bodyNode)
1835
- return false;
1836
- return !this.bodyHasLoopExit(bodyNode, false);
1837
- }
1838
- case "same_param_name": {
1839
- const first = this.bindingNames(captures.PARAM1);
1840
- const second = this.bindingNames(captures.NAME);
1841
- return [...first].some((name) => second.has(name));
1842
- }
1843
- case "no_terminating_statement": {
1844
- const caseNode = captures.CASE;
1845
- if (!caseNode)
1846
- return false;
1847
- if (this.hasFallthroughMarker(caseNode))
1848
- return false;
1849
- const body = this.switchCaseBodyStatements(caseNode);
1850
- if (body.length === 0)
1851
- return false;
1852
- return !this.statementTerminates(body[body.length - 1]);
1853
- }
1854
- case "no_break_or_return": {
1855
- const bodyNode = captures.BODY;
1856
- if (!bodyNode)
1857
- return false;
1858
- return !this.bodyHasLoopExit(bodyNode, false);
1859
- }
1860
- case "is_double_checked_locking": {
1861
- const outer = captures.FIELD?.text;
1862
- const inner = captures.FIELD2?.text;
1863
- return !!outer && outer === inner;
1864
- }
1865
- case "shadows_parent_field": {
1866
- const parentName = captures.PARENT?.text;
1867
- const fieldName = captures.NAME?.text;
1868
- if (!parentName || !fieldName)
1869
- return false;
1870
- let root = captures.NAME;
1871
- while (root.parent)
1872
- root = root.parent;
1873
- const stack = [root];
1874
- while (stack.length) {
1875
- const node = stack.pop();
1876
- if (node.type === "class_declaration" && node.childForFieldName?.("name")?.text === parentName) {
1877
- const body = node.childForFieldName?.("body");
1878
- for (const member of body?.children ?? []) {
1879
- if (member.type !== "field_declaration")
1880
- continue;
1881
- for (const declarator of member.children ?? []) {
1882
- if (declarator.type === "variable_declarator" && declarator.childForFieldName?.("name")?.text === fieldName) {
1883
- return true;
1884
- }
1885
- }
1886
- }
1887
- }
1888
- for (const child of node.children ?? [])
1889
- stack.push(child);
1890
- }
1891
- return false;
1892
- }
1893
- case "missing_break_between_cases": {
1894
- const label = captures.LABEL;
1895
- const group = label?.parent;
1896
- if (!group)
1897
- return false;
1898
- const TERMINATORS = new Set([
1899
- "break_statement",
1900
- "return_statement",
1901
- "throw_statement",
1902
- "continue_statement",
1903
- "yield_statement"
1904
- ]);
1905
- for (const child of group.children ?? []) {
1906
- if (TERMINATORS.has(child.type))
1907
- return false;
1908
- }
1909
- return true;
1910
- }
1911
- case "scoped_lock_empty_args": {
1912
- const decl = captures.DECL;
1913
- if (!decl)
1914
- return false;
1915
- for (const sibling of decl.parent?.children ?? []) {
1916
- if (sibling.type === "argument_list")
1917
- return false;
1918
- }
1919
- return true;
1920
- }
1921
- case "calc_missing_spaces": {
1922
- const text = captures.EXPR?.text ?? "";
1923
- return /[\w%)][+-][\w.(]/.test(text);
1924
- }
1925
- case "bare_except_only": {
1926
- const clauseNode = captures.CLAUSE;
1927
- if (!clauseNode)
1928
- return true;
1929
- const hasExceptionSpec = clauseNode.children.some((c) => {
1930
- if (!c.isNamed)
1931
- return false;
1932
- return c.type !== "block";
1933
- });
1934
- return !hasExceptionSpec;
1935
- }
1936
- case "eq_mod_fn": {
1937
- const mod = captures.MOD?.text ?? "";
1938
- const fn = captures.FN?.text ?? "";
1939
- return mod === "threading" && fn === "Thread";
1940
- }
1941
- case "regex_first_arg_identifier": {
1942
- const mod = captures.MOD?.text ?? "";
1943
- if (mod !== "re")
1944
- return false;
1945
- const func = captures.FUNC?.text ?? "";
1946
- if (!/^(compile|match|search|fullmatch|findall|finditer|sub|subn|split)$/.test(func)) {
1947
- return false;
1948
- }
1949
- const argsNode = captures.ARGS;
1950
- if (!argsNode)
1951
- return false;
1952
- const firstNamed = (argsNode.children ?? []).find((c) => c.isNamed);
1953
- if (!firstNamed)
1954
- return false;
1955
- return firstNamed.type === "identifier";
1956
- }
1957
- case "open_mode_invalid": {
1958
- const modeNode = captures.MODE;
1959
- if (!modeNode)
1960
- return false;
1961
- const text = modeNode.text ?? "";
1962
- const stripped = text.replace(/^["']|["']$/g, "");
1963
- if (stripped.length === 0)
1964
- return false;
1965
- if (stripped.length === 1)
1966
- return false;
1967
- if (!/^[rwxabt+]+$/.test(stripped))
1968
- return true;
1969
- const validShape = /^[rwax][bt]?\+?$/;
1970
- if (!validShape.test(stripped))
1971
- return true;
1972
- return false;
1973
- }
1974
- case "status_204_with_value_return": {
1975
- const funcNode = captures.FUNC;
1976
- const valNode = captures.VAL;
1977
- if (!funcNode || !valNode)
1978
- return false;
1979
- if (Number(valNode.text ?? 0) !== 204)
1980
- return false;
1981
- const queue = [funcNode];
1982
- while (queue.length > 0) {
1983
- const node = queue.shift();
1984
- if (node.type === "return_statement") {
1985
- const hasValue = node.children.some((c) => c.isNamed && c.type !== "comment");
1986
- if (hasValue)
1987
- return true;
1988
- }
1989
- if (node.children)
1990
- queue.push(...node.children);
1991
- }
1992
- return false;
1993
- }
1994
- case "has_mixed_async": {
1995
- const bodyNode = captures.BODY;
1996
- if (!bodyNode)
1997
- return true;
1998
- const bodyText = bodyNode.text;
1999
- return bodyText.includes("await") && /\.\s*(then|catch)\s*\(/.test(bodyText);
2000
- }
2001
- case "format_arity_mismatch": {
2002
- const formatNode = captures.FORMAT;
2003
- const argsNode = captures.ARGS;
2004
- if (!formatNode || !argsNode)
2005
- return false;
2006
- const fmtText = (formatNode.text ?? "").replace(/^["']|["']$/g, "");
2007
- const fmt = fmtText;
2008
- let placeholderCount = 0;
2009
- const namedKeys = [];
2010
- const positionalRegex = /%(?:\([^)]+\))?[#0\- +]*\d*(?:\.\d+)?[hlL]?[diouxXeEfFgGcrs%]/g;
2011
- const positionalMatches = fmt.match(positionalRegex) ?? [];
2012
- for (const m of positionalMatches) {
2013
- if (m === "%%")
2014
- continue;
2015
- placeholderCount++;
2016
- const namedMatch = m.match(/^%\(([^)]+)\)/);
2017
- if (namedMatch)
2018
- namedKeys.push(namedMatch[1]);
2019
- }
2020
- if (namedKeys.length > 0) {
2021
- if (argsNode.type === "dictionary") {
2022
- const dictKeys = [];
2023
- for (const child of argsNode.children ?? []) {
2024
- if (child.type === "pair" && child.children?.[0]) {
2025
- dictKeys.push((child.children[0].text ?? "").replace(/^["']|["']$/g, ""));
2026
- }
2027
- }
2028
- const missing = namedKeys.filter((k) => !dictKeys.includes(k));
2029
- return missing.length > 0;
2030
- }
2031
- return true;
2032
- }
2033
- if (argsNode.type === "tuple") {
2034
- const argCount = (argsNode.children ?? []).filter((c) => c.isNamed).length;
2035
- if (argCount !== placeholderCount)
2036
- return true;
2037
- }
2038
- return false;
2039
- }
2040
- case "aws_policy_public": {
2041
- const policyNode = captures.POLICY;
2042
- if (!policyNode)
2043
- return false;
2044
- const text = policyNode.text ?? "";
2045
- const patterns = [
2046
- /"Principal"\s*:\s*"\*"/,
2047
- /"Principal"\s*:\s*\{\s*"AWS"\s*:\s*"\*"\s*\}/,
2048
- /"Effect"\s*:\s*"Allow"[\s\S]*?"Action"\s*:\s*"\*"[\s\S]*?"Resource"\s*:\s*"\*"/,
2049
- /"Principal"\s*:\s*"\*"/
2050
- ];
2051
- return patterns.some((p) => p.test(text));
2052
- }
2053
- case "slots_attribute_mismatch": {
2054
- const selfNode = captures.SELF;
2055
- const attrNode = captures.ATTR;
2056
- const methodNode = captures.METHOD;
2057
- if (!selfNode || !attrNode || !methodNode)
2058
- return false;
2059
- if (selfNode.text !== "self")
2060
- return false;
2061
- const attrName = attrNode.text ?? "";
2062
- let parent = methodNode.parent;
2063
- while (parent && parent.type !== "class_definition") {
2064
- parent = parent.parent;
2065
- }
2066
- if (!parent)
2067
- return false;
2068
- const slots = extractSlots(parent);
2069
- if (slots === null || slots.length === 0)
2070
- return false;
2071
- return !slots.includes(attrName);
2072
- }
2073
- case "special_method_arity": {
2074
- const nameNode = captures.NAME;
2075
- const paramsNode = captures.PARAMS;
2076
- if (!nameNode || !paramsNode)
2077
- return false;
2078
- const name = nameNode.text ?? "";
2079
- const expected = {
2080
- __del__: 0,
2081
- __repr__: 0,
2082
- __str__: 0,
2083
- __hash__: 0,
2084
- __bool__: 0,
2085
- __len__: 0,
2086
- __eq__: 1,
2087
- __lt__: 1,
2088
- __le__: 1,
2089
- __gt__: 1,
2090
- __ge__: 1,
2091
- __ne__: 1
2092
- };
2093
- const expectedCount = expected[name];
2094
- if (expectedCount === undefined)
2095
- return false;
2096
- const paramCount = (paramsNode.children ?? []).filter((c) => {
2097
- if (c.type !== "identifier" && c.type !== "typed_parameter")
2098
- return false;
2099
- if (c.text.includes("="))
2100
- return false;
2101
- return true;
2102
- }).length;
2103
- return paramCount !== expectedCount + 1;
2104
- }
2105
- case "no_super_call": {
2106
- const bodyNode = captures.BODY;
2107
- if (!bodyNode)
2108
- return true;
2109
- return !/(?<!\/\/.*)super\s*\(/.test(bodyNode.text);
2110
- }
2111
- case "in_test_block": {
2112
- const first = Object.values(captures)[0];
2113
- return !!first && this.navigator.isInTestBlock(first);
2114
- }
2115
- case "not_in_test_block": {
2116
- const first = Object.values(captures)[0];
2117
- return !first || !this.navigator.isInTestBlock(first);
2118
- }
2119
- case "not_in_try_catch": {
2120
- const first = Object.values(captures)[0];
2121
- return !first || !this.navigator.isInTryCatch(first);
2122
- }
2123
- case "in_try_catch": {
2124
- const first = Object.values(captures)[0];
2125
- return !!first && this.navigator.isInTryCatch(first);
2126
- }
2127
- case "name_matches_param": {
2128
- const nameNode = captures.NAME;
2129
- const paramNode = captures.PARAM;
2130
- return !!nameNode && !!paramNode && nameNode.text === paramNode.text;
2131
- }
2132
- case "not_in_function": {
2133
- const first = Object.values(captures)[0];
2134
- return !first || !this.navigator.isInside(first, [
2135
- "function_definition",
2136
- "function_declaration",
2137
- "method_definition",
2138
- "arrow_function"
2139
- ]);
2140
- }
2141
- case "check_secret_pattern": {
2142
- const varName = captures.VARNAME?.text ?? "";
2143
- const varNameLower = varName.toLowerCase();
2144
- if (varName === varName.toUpperCase() && /[A-Z]/.test(varName)) {
2145
- return false;
2146
- }
2147
- return [
2148
- /api[_-]?key/,
2149
- /api[_-]?secret/,
2150
- /password/,
2151
- /passwd/,
2152
- /secret/,
2153
- /token/,
2154
- /auth/,
2155
- /private[_-]?key/,
2156
- /access[_-]?token/,
2157
- /credentials/,
2158
- /aws[_-]?secret/,
2159
- /github[_-]?token/,
2160
- /client[_-]?secret/
2161
- ].some((p) => p.test(varNameLower));
2162
- }
2163
- case "returns_error": {
2164
- const first = Object.values(captures)[0];
2165
- if (!first)
2166
- return false;
2167
- const funcNode = this.navigator.findParent(first, [
2168
- "function_declaration",
2169
- "method_declaration"
2170
- ]);
2171
- if (!funcNode)
2172
- return false;
2173
- const signature = String(funcNode.text ?? "").split("{", 1)[0]?.trim() ?? "";
2174
- const returnPart = signature.match(/func\s*(?:\([^)]*\)\s*)?[A-Za-z_]\w*\s*\([^)]*\)\s*(.*)$/s)?.[1]?.trim() ?? "";
2175
- return returnPart.length > 0 && /\berror\b/.test(returnPart);
2176
- }
2177
- case "python_empty_except": {
2178
- const bodyNode = captures.BODY;
2179
- if (!bodyNode)
2180
- return true;
2181
- return !bodyNode.children.some((c) => c.isNamed && c.type !== "pass_statement" && c.type !== "comment");
2182
- }
2183
- case "check_in_operator_types": {
2184
- const target = captures.TARGET;
2185
- if (!target)
2186
- return false;
2187
- return ["none", "true", "false", "integer", "float"].includes(target.type);
2188
- }
2189
- case "torchscript_super_call": {
2190
- const call = captures.CALL;
2191
- if (!call)
2192
- return false;
2193
- const isTorchScriptDecorated = (node) => {
2194
- const decorated = node?.parent;
2195
- if (!decorated || decorated.type !== "decorated_definition")
2196
- return false;
2197
- return (decorated.children ?? []).some((c) => c.type === "decorator" && /^@(torch\.jit\.script|jit\.script)$/.test(c.text ?? ""));
2198
- };
2199
- const methodNode = this.navigator.findParent(call, [
2200
- "function_definition"
2201
- ]);
2202
- if (!methodNode)
2203
- return false;
2204
- const classNode = this.navigator.findParent(methodNode, [
2205
- "class_definition"
2206
- ]);
2207
- return isTorchScriptDecorated(methodNode) || isTorchScriptDecorated(classNode);
2208
- }
2209
- case "exit_params_insufficient": {
2210
- const params = captures.PARAMS;
2211
- if (!params)
2212
- return true;
2213
- const named = (params.children ?? []).filter((c) => c.isNamed);
2214
- if (named.some((c) => c.type === "list_splat_pattern" || c.type === "dictionary_splat_pattern")) {
2215
- return false;
2216
- }
2217
- return named.length < 4;
2218
- }
2219
- case "ruby_empty_rescue": {
2220
- const bodyNode = captures.BODY;
2221
- if (!bodyNode)
2222
- return true;
2223
- return !bodyNode.children.some((c) => c.isNamed && !["comment", "nil", "nil_literal"].includes(c.type));
2224
- }
2225
- case "ts_command_injection_sink":
2226
- return captures.MOD?.text === "child_process" && /^(exec|execSync)$/.test(captures.FN?.text ?? "");
2227
- case "ts_sql_injection_sink": {
2228
- const template = captures.TEMPLATE?.text ?? "";
2229
- const rawPrefix = template.replace(/^`/, "").replace(/`$/, "").replace(/^(?:\s|\/\*[\s\S]*?\*\/|--[^\n]*(?:\n|$))*/, "");
2230
- if (/^(?:SELECT[\s\S]*(?:\bFROM\b|\$\{)|INSERT\s+INTO\b|UPDATE\s+[\s\S]*\bSET\b|DELETE\s+FROM\b|CREATE\s+(?:OR\s+REPLACE\s+|TEMP(?:ORARY)?\s+|UNIQUE\s+|MATERIALIZED\s+)*(?:TABLE|INDEX|VIEW|SCHEMA|DATABASE|TRIGGER|FUNCTION|PROCEDURE|SEQUENCE|TYPE|EXTENSION)\b|DROP\s+(?:OR\s+REPLACE\s+|TEMP(?:ORARY)?\s+|UNIQUE\s+|MATERIALIZED\s+)*(?:TABLE|INDEX|VIEW|SCHEMA|DATABASE|TRIGGER|FUNCTION|PROCEDURE|SEQUENCE|TYPE|EXTENSION)\b|ALTER\s+(?:OR\s+REPLACE\s+|TEMP(?:ORARY)?\s+|UNIQUE\s+|MATERIALIZED\s+)*(?:TABLE|INDEX|VIEW|SCHEMA|DATABASE|TRIGGER|FUNCTION|PROCEDURE|SEQUENCE|TYPE|EXTENSION)\b|GRANT\b|REVOKE\b|WITH[\s\S]*\bSELECT\b|MERGE\s+INTO\b|TRUNCATE\s+TABLE\b|REPLACE\s+INTO\b)/i.test(rawPrefix))
2231
- return true;
2232
- if (!rootNode || !captures.OBJ)
2233
- return false;
2234
- let imported = TYPESCRIPT_SQL_IMPORTS.get(rootNode);
2235
- if (!imported) {
2236
- const names = new Set;
2237
- const stack = [rootNode];
2238
- while (stack.length > 0) {
2239
- const node = stack.pop();
2240
- if (!node)
2241
- continue;
2242
- if (node.type === "import_statement") {
2243
- const source = node.childForFieldName?.("source")?.text ?? "";
2244
- const packageName = source.replace(/^['"]|['"]$/g, "");
2245
- const isKnown = [...TYPESCRIPT_SQL_KNOWN_PACKAGES].some((pkg) => packageName === pkg || packageName.startsWith(`${pkg}/`));
2246
- if (isKnown) {
2247
- const importStack = [node];
2248
- while (importStack.length > 0) {
2249
- const importNode = importStack.pop();
2250
- if (!importNode)
2251
- continue;
2252
- if (importNode.type === "identifier" || importNode.type === "import_specifier") {
2253
- names.add(importNode.text);
2254
- }
2255
- importStack.push(...importNode.children);
2256
- }
2257
- }
2258
- }
2259
- stack.push(...node.children);
2260
- }
2261
- const declarations = new Map;
2262
- const declarationStack = [rootNode];
2263
- while (declarationStack.length > 0) {
2264
- const node = declarationStack.pop();
2265
- if (!node)
2266
- continue;
2267
- if (node.type === "variable_declarator") {
2268
- const name = node.childForFieldName?.("name")?.text;
2269
- const value = node.childForFieldName?.("value");
2270
- if (name && value)
2271
- declarations.set(name, value);
2272
- }
2273
- declarationStack.push(...node.children);
2274
- }
2275
- const resolvesKnownValue = (node, seen = new Set) => {
2276
- if (node.type === "identifier") {
2277
- if (names.has(node.text))
2278
- return true;
2279
- if (seen.has(node.text))
2280
- return false;
2281
- const value = declarations.get(node.text);
2282
- if (!value)
2283
- return false;
2284
- seen.add(node.text);
2285
- return resolvesKnownValue(value, seen);
2286
- }
2287
- if (node.type === "await_expression") {
2288
- const value = node.children.find((child) => child.isNamed);
2289
- return value ? resolvesKnownValue(value, seen) : false;
2290
- }
2291
- if (node.type === "new_expression") {
2292
- const ctor = node.childForFieldName?.("constructor");
2293
- return ctor ? resolvesKnownValue(ctor, seen) : false;
2294
- }
2295
- if (node.type === "call_expression") {
2296
- const fn = node.childForFieldName?.("function");
2297
- return fn ? resolvesKnownValue(fn, seen) : false;
2298
- }
2299
- return false;
2300
- };
2301
- let changed = true;
2302
- while (changed) {
2303
- changed = false;
2304
- for (const [name, value] of declarations) {
2305
- if (!names.has(name) && resolvesKnownValue(value)) {
2306
- names.add(name);
2307
- changed = true;
2308
- }
2309
- }
2310
- }
2311
- imported = names;
2312
- TYPESCRIPT_SQL_IMPORTS.set(rootNode, imported);
2313
- }
2314
- const resolvesToKnownClient = (node) => {
2315
- if (node.type === "identifier")
2316
- return imported.has(node.text);
2317
- if (node.type === "await_expression") {
2318
- const value = node.children.find((child) => child.isNamed);
2319
- return value ? resolvesToKnownClient(value) : false;
2320
- }
2321
- if (node.type === "new_expression") {
2322
- const ctor = node.childForFieldName?.("constructor");
2323
- return ctor ? resolvesToKnownClient(ctor) : false;
2324
- }
2325
- if (node.type === "call_expression") {
2326
- const fn = node.childForFieldName?.("function");
2327
- return fn ? resolvesToKnownClient(fn) : false;
2328
- }
2329
- return false;
2330
- };
2331
- return resolvesToKnownClient(captures.OBJ);
2332
- }
2333
- case "ts_ssrf_sink": {
2334
- const fn = captures.FN?.text ?? "";
2335
- const obj = captures.OBJ?.text ?? "";
2336
- const urlText = captures.URL?.text ?? "";
2337
- const allowedFns = new Set([
2338
- "fetch",
2339
- "request",
2340
- "get",
2341
- "post",
2342
- "put",
2343
- "patch",
2344
- "delete"
2345
- ]);
2346
- if (!allowedFns.has(fn))
2347
- return false;
2348
- if (rootNode && captures.URL?.type === "identifier" && this.resolvesToFileLiteralConst(urlText, rootNode)) {
2349
- return false;
2350
- }
2351
- if (rootNode && captures.URL) {
2352
- const urlVar = this.newUrlBaseVarName(captures.URL);
2353
- if (urlVar && this.resolvesToFixedNewUrlConst(urlVar, rootNode)) {
2354
- return false;
2355
- }
2356
- }
2357
- const looksLikeExternalInput = urlText.includes(".") || /user|external|remote|input|target|webhook|callback|redirect|untrusted|arbitrary/i.test(urlText);
2358
- if (!looksLikeExternalInput)
2359
- return false;
2360
- if (!obj)
2361
- return fn === "fetch";
2362
- return new Set([
2363
- "axios",
2364
- "http",
2365
- "https",
2366
- "got",
2367
- "request",
2368
- "superagent",
2369
- "undici"
2370
- ]).has(obj);
2371
- }
2372
- case "ts_weak_hash_algorithm":
2373
- return captures.FN?.text === "createHash" && /^(md5|sha1)$/i.test(captures.ALG?.text ?? "");
2374
- case "ts_insecure_random_source": {
2375
- if (captures.OBJ?.text !== "Math" || captures.FN?.text !== "random")
2376
- return false;
2377
- const varName = this.enclosingBindingName(captures.CALL ?? captures.VAR);
2378
- return /token|secret|password|key|nonce|salt|csrf|auth|session|credential|hash|otp|pin/i.test(varName);
2379
- }
2380
- case "ts_detached_async_call":
2381
- return /(Async$|fetch$|request$)/.test(captures.FN?.text ?? "");
2382
- case "incomplete_assertion": {
2383
- const expectNode = captures.EXPECT;
2384
- if (!expectNode)
2385
- return false;
2386
- const CHAI_PROPERTY_ASSERTIONS = new Set([
2387
- "true",
2388
- "false",
2389
- "null",
2390
- "undefined",
2391
- "empty",
2392
- "NaN",
2393
- "finite",
2394
- "exist",
2395
- "arguments",
2396
- "extensible",
2397
- "sealed",
2398
- "frozen",
2399
- "locked"
2400
- ]);
2401
- let current = expectNode.parent;
2402
- if (!current)
2403
- return false;
2404
- current = current.parent;
2405
- if (!current)
2406
- return false;
2407
- if (current.type === "expression_statement" || current.type === "return_statement")
2408
- return true;
2409
- let lastPropertyName = null;
2410
- while (current && current.type === "member_expression") {
2411
- const propNode = current.children?.find((c) => c.type === "property_identifier");
2412
- if (propNode)
2413
- lastPropertyName = propNode.text;
2414
- const parent = current.parent;
2415
- if (!parent)
2416
- return false;
2417
- if (parent.type === "expression_statement" || parent.type === "return_statement") {
2418
- if (lastPropertyName && CHAI_PROPERTY_ASSERTIONS.has(lastPropertyName))
2419
- return false;
2420
- return true;
2421
- }
2422
- if (parent.type === "call_expression")
2423
- return false;
2424
- current = parent;
2425
- }
2426
- return false;
2427
- }
2428
- case "py_command_injection_sink": {
2429
- const mod = captures.MOD?.text ?? "";
2430
- const fn = captures.FN?.text ?? "";
2431
- const kw = captures.KW?.text ?? "";
2432
- return mod === "os" && /^(system|popen)$/.test(fn) || mod === "subprocess" && /^(run|Popen|call|check_output|check_call)$/.test(fn) && kw === "shell";
2433
- }
2434
- case "go_command_injection_sink":
2435
- return captures.PKG?.text === "exec" && /^(Command|CommandContext)$/.test(captures.FN?.text ?? "") && /^"(sh|bash|zsh|cmd|powershell|pwsh)"$/.test(captures.SHELL?.text ?? "") && /^"(-c|\/c)"$/.test(captures.FLAG?.text ?? "");
2436
- case "ruby_command_injection_sink":
2437
- return /^(system|exec|spawn|popen|capture3|capture2|capture2e)$/.test(captures.FN?.text ?? "");
2438
- case "py_ssrf_sink":
2439
- return captures.MOD?.text === "requests" && /^(get|post|put|patch|delete|request|head|options)$/.test(captures.FN?.text ?? "");
2440
- case "py_path_traversal_sink":
2441
- return /^(open|read_text|read_bytes|write_text|write_bytes|remove|unlink|rmdir)$/.test(captures.FN?.text ?? "");
2442
- case "go_path_traversal_sink":
2443
- return /^(os|ioutil)$/.test(captures.PKG?.text ?? "") && /^(Open|OpenFile|ReadFile|WriteFile|Create|Remove|RemoveAll)$/.test(captures.FN?.text ?? "");
2444
- case "py_sql_injection_sink": {
2445
- const fn = captures.FN?.text ?? "";
2446
- if (!PYTHON_SQL_SINK_METHODS.has(fn))
2447
- return false;
2448
- const sqlNode = captures.SQL;
2449
- const receiver = captures.OBJ;
2450
- if (fn === "execute" && this.isLikelySqlAlchemyReceiver(receiver?.text ?? "")) {
2451
- return false;
2452
- }
2453
- if (sqlNode && this.isSafeSqlAlchemyExpressionCall(sqlNode)) {
2454
- return false;
2455
- }
2456
- if (isProvenSqlAlchemySessionReceiver(receiver, rootNode)) {
2457
- if (fn === "query" && isSqlAlchemyEntityQueryArgument(sqlNode, rootNode)) {
2458
- return false;
2459
- }
2460
- if (fn === "execute" && isSqlAlchemyStatementArgument(sqlNode, rootNode)) {
2461
- return false;
2462
- }
2463
- }
2464
- if (isSafePsycopgIdentifierComposition(sqlNode, rootNode)) {
2465
- return false;
2466
- }
2467
- return true;
2468
- }
2469
- case "go_sql_injection_sink":
2470
- return /^(Query|QueryContext|QueryRow|QueryRowContext|Exec|ExecContext)$/.test(captures.DBFN?.text ?? "") && captures.FMTPKG?.text === "fmt" && captures.FMTFN?.text === "Sprintf";
2471
- case "py_insecure_deserialization_sink":
2472
- return /^(pickle|yaml)$/.test(captures.MOD?.text ?? "") && /^(load|loads|unsafe_load)$/.test(captures.FN?.text ?? "");
2473
- case "ruby_insecure_deserialization_sink":
2474
- return /^(Marshal|YAML|Psych)$/.test(captures.MOD?.text ?? "") && /^(load|unsafe_load)$/.test(captures.FN?.text ?? "");
2475
- case "match_captures": {
2476
- for (const [captureName, pattern] of Object.entries(postFilterParams ?? {})) {
2477
- const node = captures[captureName];
2478
- if (!node)
2479
- return false;
2480
- if (!new RegExp(pattern).test(node.text))
2481
- return false;
2482
- }
2483
- return true;
2484
- }
2485
- case "case_range_single_value": {
2486
- const start = captures.START?.text ?? "";
2487
- const end = captures.END?.text ?? "";
2488
- return start === end;
2489
- }
2490
- case "goto_jumps_backward": {
2491
- const label = captures.LABEL;
2492
- const gotoNode = captures.GOTO;
2493
- if (!label || !gotoNode)
2494
- return false;
2495
- return label.startIndex < gotoNode.startIndex;
2496
- }
2497
- case "goto_targets_inner_block": {
2498
- const target = captures.TARGET;
2499
- if (!target)
2500
- return false;
2501
- let depth = 0;
2502
- let node = target.parent;
2503
- while (node) {
2504
- if (node.type === "compound_statement")
2505
- depth++;
2506
- node = node.parent;
2507
- }
2508
- return depth >= 2;
2509
- }
2510
- case "c_memset_sensitive_arg": {
2511
- const callNode = captures.CALL;
2512
- if (!callNode || callNode.type !== "call_expression")
2513
- return false;
2514
- const argList = callNode.children?.find((c) => c.type === "argument_list");
2515
- if (!argList)
2516
- return false;
2517
- const firstArg = argList.children?.find((c) => c.isNamed);
2518
- if (!firstArg)
2519
- return false;
2520
- const argName = firstArg.text ?? "";
2521
- return /password|secret|key|token|credential|auth|private|passwd|pin|salt|nonce|iv|seed/i.test(argName);
2522
- }
2523
- case "c_stdlib_name": {
2524
- const name = captures.NAME?.text ?? "";
2525
- const STDLIB_NAMES = new Set([
2526
- "malloc",
2527
- "calloc",
2528
- "realloc",
2529
- "free",
2530
- "alloca",
2531
- "printf",
2532
- "fprintf",
2533
- "sprintf",
2534
- "snprintf",
2535
- "vprintf",
2536
- "vfprintf",
2537
- "vsprintf",
2538
- "vsnprintf",
2539
- "scanf",
2540
- "fscanf",
2541
- "sscanf",
2542
- "vscanf",
2543
- "vfscanf",
2544
- "vsscanf",
2545
- "strcpy",
2546
- "strncpy",
2547
- "strcat",
2548
- "strncat",
2549
- "strcmp",
2550
- "strncmp",
2551
- "strlen",
2552
- "strchr",
2553
- "strrchr",
2554
- "strstr",
2555
- "strerror",
2556
- "memcpy",
2557
- "memmove",
2558
- "memset",
2559
- "memcmp",
2560
- "memchr",
2561
- "fopen",
2562
- "fclose",
2563
- "fread",
2564
- "fwrite",
2565
- "fgets",
2566
- "fputs",
2567
- "getc",
2568
- "putc",
2569
- "getchar",
2570
- "putchar",
2571
- "exit",
2572
- "abort",
2573
- "assert",
2574
- "errno",
2575
- "abs",
2576
- "labs",
2577
- "llabs",
2578
- "div",
2579
- "ldiv",
2580
- "lldiv",
2581
- "atoi",
2582
- "atol",
2583
- "atoll",
2584
- "strtol",
2585
- "strtoll",
2586
- "strtoul",
2587
- "strtoull",
2588
- "strtod",
2589
- "strtof",
2590
- "strtold",
2591
- "qsort",
2592
- "bsearch",
2593
- "time",
2594
- "clock",
2595
- "difftime",
2596
- "mktime",
2597
- "strftime",
2598
- "getenv",
2599
- "setenv",
2600
- "putenv",
2601
- "system",
2602
- "isalpha",
2603
- "isdigit",
2604
- "isalnum",
2605
- "isspace",
2606
- "isupper",
2607
- "islower",
2608
- "toupper",
2609
- "tolower",
2610
- "sizeof",
2611
- "offsetof",
2612
- "NULL",
2613
- "EXIT_SUCCESS",
2614
- "EXIT_FAILURE"
2615
- ]);
2616
- return STDLIB_NAMES.has(name);
2617
- }
2618
- case "c_octal_literal": {
2619
- const num = captures.NUM?.text ?? "";
2620
- return /^0[0-7]+$/.test(num);
2621
- }
2622
- case "c_noreturn_attr": {
2623
- const attr = captures.ATTR?.text ?? "";
2624
- return attr === "noreturn";
2625
- }
2626
- case "c_label_in_switch": {
2627
- const stmt = captures.STMT;
2628
- if (!stmt)
2629
- return false;
2630
- let node = stmt.parent;
2631
- while (node) {
2632
- if (node.type === "switch_statement")
2633
- return true;
2634
- node = node.parent;
2635
- }
2636
- return false;
2637
- }
2638
- default:
2639
- this.reportMissingPostFilter(postFilter);
2640
- return false;
2641
- }
2642
- }
2643
- reportedMissingPostFilters = new Set;
2644
- reportedPostFilterFailures = new Set;
2645
- reportPostFilterFailure(postFilter, reason) {
2646
- if (this.reportedPostFilterFailures.has(postFilter))
2647
- return;
2648
- this.reportedPostFilterFailures.add(postFilter);
2649
- logTreeSitterDiagnostic({
2650
- subsystem: "tree-sitter-client",
2651
- message: `tree-sitter rule post_filter '${postFilter}' failed — ` + `keeping the diagnostic (fail-open): ${reason}.`,
2652
- metadata: { postFilter }
2653
- });
2654
- }
2655
- reportMissingPostFilter(postFilter) {
2656
- if (this.reportedMissingPostFilters.has(postFilter))
2657
- return;
2658
- this.reportedMissingPostFilters.add(postFilter);
2659
- logTreeSitterDiagnostic({
2660
- subsystem: "tree-sitter-client",
2661
- message: `tree-sitter rule post_filter '${postFilter}' is not implemented — ` + `matches for the rules using it are suppressed rather than reported unfiltered. ` + `Implement it in applyPostFilter (clients/tree-sitter-client.ts) to re-enable them.`,
2662
- metadata: { postFilter }
2663
- });
2664
- }
2665
- textPredicatesInvalidLogged = false;
2666
- hasValidTextPredicates(query) {
2667
- const valid = Array.isArray(query?.textPredicates);
2668
- if (!valid) {
2669
- if (!this.textPredicatesInvalidLogged) {
2670
- this.textPredicatesInvalidLogged = true;
2671
- logTreeSitterDiagnostic({
2672
- subsystem: "tree-sitter-client",
2673
- message: "web-tree-sitter Query.textPredicates is missing or not an array — " + "#match?/#eq? predicates cannot be evaluated. Failing CLOSED: matches " + "for this query are dropped rather than reported unfiltered.",
2674
- metadata: { textPredicatesType: typeof query?.textPredicates }
2675
- });
2676
- }
2677
- recordDegradationOnce({
2678
- kind: "query-predicates-invalid",
2679
- subject: "web-tree-sitter",
2680
- reason: "Query.textPredicates is missing or not an array — #match?/#eq? " + "predicates cannot be evaluated; structural matches relying on them " + "are dropped fail-closed"
2681
- });
2682
- }
2683
- return valid;
2684
- }
2685
- evaluatePredicates(query, match) {
2686
- if (!this.hasValidTextPredicates(query))
2687
- return false;
2688
- const predicates = query.textPredicates?.[match.patternIndex] ?? [];
2689
- return predicates.every((fn) => fn(match.captures));
2690
- }
2691
- async searchFileWithQuery(filePath, query, metavars, languageId, _originalPattern, postFilter, postFilterParams, contentOverride) {
2692
- const matches = [];
2693
- await this.parseFileAndUse(filePath, languageId, contentOverride, (tree) => {
2694
- try {
2695
- const rootNode = tree.rootNode;
2696
- const queryMatches = query.matches(rootNode);
2697
- for (const match of queryMatches) {
2698
- const captures = {};
2699
- for (const capture of match.captures) {
2700
- if (metavars.includes(capture.name)) {
2701
- captures[capture.name] = capture.node;
2702
- }
2703
- }
2704
- if (!this.evaluatePredicates(query, match)) {
2705
- continue;
2706
- }
2707
- if (postFilter && !this.applyPostFilter(postFilter, postFilterParams, captures, rootNode)) {
2708
- continue;
2709
- }
2710
- if (match.captures.length > 0) {
2711
- const firstNode = match.captures[0].node;
2712
- const textCaptures = {};
2713
- for (const [name, node] of Object.entries(captures)) {
2714
- textCaptures[name] = node.text;
2715
- }
2716
- matches.push({
2717
- file: filePath,
2718
- line: firstNode.startPosition.row + 1,
2719
- column: firstNode.startPosition.column + 1,
2720
- matchedText: firstNode.text,
2721
- nodeType: firstNode.type,
2722
- captures: textCaptures
2723
- });
2724
- }
2725
- }
2726
- if (matches.length > 0) {
2727
- this.dbg(`Found ${matches.length} matches in ${path.basename(filePath)}`);
2728
- }
2729
- } catch (err) {
2730
- this.reportWasmAbort(err);
2731
- this.dbg(`Query matching error: ${err}`);
2732
- }
2733
- });
2734
- return matches;
2735
- }
2736
- collectFiles(dir, languageId, fileFilter) {
2737
- const files = [];
2738
- const extensions = this.getExtensionsForLanguage(languageId);
2739
- const rootDir = path.resolve(dir);
2740
- const ignoreMatcher = getProjectIgnoreMatcher(rootDir);
2741
- const scan = (d) => {
2742
- if (files.length >= TREE_SITTER_MAX_SCAN_FILES)
2743
- return;
2744
- try {
2745
- const entries = fs.readdirSync(d, { withFileTypes: true });
2746
- for (const entry of entries) {
2747
- if (files.length >= TREE_SITTER_MAX_SCAN_FILES)
2748
- return;
2749
- const full = path.join(d, entry.name);
2750
- if (entry.isDirectory()) {
2751
- if (isExcludedDirName(entry.name))
2752
- continue;
2753
- if (ignoreMatcher.isIgnored(full, true))
2754
- continue;
2755
- scan(full);
2756
- } else if (extensions.some((ext) => entry.name.endsWith(ext))) {
2757
- if (ignoreMatcher.isIgnored(full, false))
2758
- continue;
2759
- if (!fileFilter || fileFilter(full)) {
2760
- files.push(full);
2761
- }
2762
- }
2763
- }
2764
- } catch {}
2765
- };
2766
- scan(rootDir);
2767
- return files;
2768
- }
2769
- getExtensionsForLanguage(languageId) {
2770
- const mapping = {
2771
- typescript: [".ts", ".mts", ".cts"],
2772
- tsx: [".tsx"],
2773
- javascript: [".js", ".mjs", ".cjs"],
2774
- python: [".py"],
2775
- rust: [".rs"],
2776
- go: [".go"],
2777
- java: [".java"],
2778
- kotlin: [".kt", ".kts"],
2779
- dart: [".dart"],
2780
- c: [".c", ".h"],
2781
- cpp: [".cpp", ".hpp", ".cc", ".hh"],
2782
- elixir: [".ex", ".exs"],
2783
- ruby: [".rb"]
2784
- };
2785
- return mapping[languageId] || [];
2786
- }
2787
- }