trail-code 0.0.0-stage → 0.28.0-semantic.3

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 (593) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +567 -2
  3. package/dist/ai/crux.d.ts +88 -0
  4. package/dist/ai/crux.d.ts.map +1 -0
  5. package/dist/ai/crux.js +219 -0
  6. package/dist/ai/crux.js.map +1 -0
  7. package/dist/ai/failure.d.ts +60 -0
  8. package/dist/ai/failure.d.ts.map +1 -0
  9. package/dist/ai/failure.js +86 -0
  10. package/dist/ai/failure.js.map +1 -0
  11. package/dist/ai/llm/anthropic.d.ts +37 -0
  12. package/dist/ai/llm/anthropic.d.ts.map +1 -0
  13. package/dist/ai/llm/anthropic.js +144 -0
  14. package/dist/ai/llm/anthropic.js.map +1 -0
  15. package/dist/ai/llm/factory.d.ts +28 -0
  16. package/dist/ai/llm/factory.d.ts.map +1 -0
  17. package/dist/ai/llm/factory.js +36 -0
  18. package/dist/ai/llm/factory.js.map +1 -0
  19. package/dist/ai/llm/litellm.d.ts +34 -0
  20. package/dist/ai/llm/litellm.d.ts.map +1 -0
  21. package/dist/ai/llm/litellm.js +45 -0
  22. package/dist/ai/llm/litellm.js.map +1 -0
  23. package/dist/ai/llm/openai.d.ts +145 -0
  24. package/dist/ai/llm/openai.d.ts.map +1 -0
  25. package/dist/ai/llm/openai.js +629 -0
  26. package/dist/ai/llm/openai.js.map +1 -0
  27. package/dist/ai/llm/orcarouter.d.ts +34 -0
  28. package/dist/ai/llm/orcarouter.d.ts.map +1 -0
  29. package/dist/ai/llm/orcarouter.js +45 -0
  30. package/dist/ai/llm/orcarouter.js.map +1 -0
  31. package/dist/ai/llm/recover-tool.d.ts +21 -0
  32. package/dist/ai/llm/recover-tool.d.ts.map +1 -0
  33. package/dist/ai/llm/recover-tool.js +109 -0
  34. package/dist/ai/llm/recover-tool.js.map +1 -0
  35. package/dist/ai/llm/types.d.ts +122 -0
  36. package/dist/ai/llm/types.d.ts.map +1 -0
  37. package/dist/ai/llm/types.js +33 -0
  38. package/dist/ai/llm/types.js.map +1 -0
  39. package/dist/ai/providers.d.ts +59 -0
  40. package/dist/ai/providers.d.ts.map +1 -0
  41. package/dist/ai/providers.js +54 -0
  42. package/dist/ai/providers.js.map +1 -0
  43. package/dist/ai/summarize.d.ts +25 -0
  44. package/dist/ai/summarize.d.ts.map +1 -0
  45. package/dist/ai/summarize.js +34 -0
  46. package/dist/ai/summarize.js.map +1 -0
  47. package/dist/ai/synthesize.d.ts +40 -0
  48. package/dist/ai/synthesize.d.ts.map +1 -0
  49. package/dist/ai/synthesize.js +230 -0
  50. package/dist/ai/synthesize.js.map +1 -0
  51. package/dist/ask/ask.d.ts +199 -0
  52. package/dist/ask/ask.d.ts.map +1 -0
  53. package/dist/ask/ask.js +1291 -0
  54. package/dist/ask/ask.js.map +1 -0
  55. package/dist/ask/file-rank.d.ts +72 -0
  56. package/dist/ask/file-rank.d.ts.map +1 -0
  57. package/dist/ask/file-rank.js +160 -0
  58. package/dist/ask/file-rank.js.map +1 -0
  59. package/dist/ask/file-selection.d.ts +22 -0
  60. package/dist/ask/file-selection.d.ts.map +1 -0
  61. package/dist/ask/file-selection.js +66 -0
  62. package/dist/ask/file-selection.js.map +1 -0
  63. package/dist/ask/fuse.d.ts +195 -0
  64. package/dist/ask/fuse.d.ts.map +1 -0
  65. package/dist/ask/fuse.js +344 -0
  66. package/dist/ask/fuse.js.map +1 -0
  67. package/dist/ask/graphrank.d.ts +61 -0
  68. package/dist/ask/graphrank.d.ts.map +1 -0
  69. package/dist/ask/graphrank.js +130 -0
  70. package/dist/ask/graphrank.js.map +1 -0
  71. package/dist/ask/index-file.d.ts +44 -0
  72. package/dist/ask/index-file.d.ts.map +1 -0
  73. package/dist/ask/index-file.js +128 -0
  74. package/dist/ask/index-file.js.map +1 -0
  75. package/dist/ask/semantic.d.ts +42 -0
  76. package/dist/ask/semantic.d.ts.map +1 -0
  77. package/dist/ask/semantic.js +293 -0
  78. package/dist/ask/semantic.js.map +1 -0
  79. package/dist/bin/graft.d.ts +3 -0
  80. package/dist/bin/graft.d.ts.map +1 -0
  81. package/dist/bin/graft.js +14 -0
  82. package/dist/bin/graft.js.map +1 -0
  83. package/dist/bin/trail.d.ts +3 -0
  84. package/dist/bin/trail.d.ts.map +1 -0
  85. package/dist/bin/trail.js +13 -0
  86. package/dist/bin/trail.js.map +1 -0
  87. package/dist/blast/blast-cli.d.ts +35 -0
  88. package/dist/blast/blast-cli.d.ts.map +1 -0
  89. package/dist/blast/blast-cli.js +155 -0
  90. package/dist/blast/blast-cli.js.map +1 -0
  91. package/dist/blast/blast.d.ts +128 -0
  92. package/dist/blast/blast.d.ts.map +1 -0
  93. package/dist/blast/blast.js +383 -0
  94. package/dist/blast/blast.js.map +1 -0
  95. package/dist/blast/diff.d.ts +53 -0
  96. package/dist/blast/diff.d.ts.map +1 -0
  97. package/dist/blast/diff.js +193 -0
  98. package/dist/blast/diff.js.map +1 -0
  99. package/dist/blast/evidence.d.ts +51 -0
  100. package/dist/blast/evidence.d.ts.map +1 -0
  101. package/dist/blast/evidence.js +162 -0
  102. package/dist/blast/evidence.js.map +1 -0
  103. package/dist/blast/modules.d.ts +33 -0
  104. package/dist/blast/modules.d.ts.map +1 -0
  105. package/dist/blast/modules.js +83 -0
  106. package/dist/blast/modules.js.map +1 -0
  107. package/dist/blast/name.d.ts +74 -0
  108. package/dist/blast/name.d.ts.map +1 -0
  109. package/dist/blast/name.js +269 -0
  110. package/dist/blast/name.js.map +1 -0
  111. package/dist/blast/owners.d.ts +85 -0
  112. package/dist/blast/owners.d.ts.map +1 -0
  113. package/dist/blast/owners.js +272 -0
  114. package/dist/blast/owners.js.map +1 -0
  115. package/dist/blast/render.d.ts +46 -0
  116. package/dist/blast/render.d.ts.map +1 -0
  117. package/dist/blast/render.js +422 -0
  118. package/dist/blast/render.js.map +1 -0
  119. package/dist/blast/viz.d.ts +37 -0
  120. package/dist/blast/viz.d.ts.map +1 -0
  121. package/dist/blast/viz.js +180 -0
  122. package/dist/blast/viz.js.map +1 -0
  123. package/dist/brand.d.ts +111 -0
  124. package/dist/brand.d.ts.map +1 -0
  125. package/dist/brand.js +282 -0
  126. package/dist/brand.js.map +1 -0
  127. package/dist/claude/build-progress.d.ts +30 -0
  128. package/dist/claude/build-progress.d.ts.map +1 -0
  129. package/dist/claude/build-progress.js +81 -0
  130. package/dist/claude/build-progress.js.map +1 -0
  131. package/dist/claude/hermes-skill-template.d.ts +16 -0
  132. package/dist/claude/hermes-skill-template.d.ts.map +1 -0
  133. package/dist/claude/hermes-skill-template.js +154 -0
  134. package/dist/claude/hermes-skill-template.js.map +1 -0
  135. package/dist/claude/init.d.ts +65 -0
  136. package/dist/claude/init.d.ts.map +1 -0
  137. package/dist/claude/init.js +258 -0
  138. package/dist/claude/init.js.map +1 -0
  139. package/dist/claude/paths.d.ts +9 -0
  140. package/dist/claude/paths.d.ts.map +1 -0
  141. package/dist/claude/paths.js +22 -0
  142. package/dist/claude/paths.js.map +1 -0
  143. package/dist/claude/session-metrics.d.ts +73 -0
  144. package/dist/claude/session-metrics.d.ts.map +1 -0
  145. package/dist/claude/session-metrics.js +209 -0
  146. package/dist/claude/session-metrics.js.map +1 -0
  147. package/dist/claude/settings-merge.d.ts +76 -0
  148. package/dist/claude/settings-merge.d.ts.map +1 -0
  149. package/dist/claude/settings-merge.js +283 -0
  150. package/dist/claude/settings-merge.js.map +1 -0
  151. package/dist/claude/skill-template.d.ts +13 -0
  152. package/dist/claude/skill-template.d.ts.map +1 -0
  153. package/dist/claude/skill-template.js +290 -0
  154. package/dist/claude/skill-template.js.map +1 -0
  155. package/dist/claude/state.d.ts +85 -0
  156. package/dist/claude/state.d.ts.map +1 -0
  157. package/dist/claude/state.js +88 -0
  158. package/dist/claude/state.js.map +1 -0
  159. package/dist/claude/stats.d.ts +5 -0
  160. package/dist/claude/stats.d.ts.map +1 -0
  161. package/dist/claude/stats.js +24 -0
  162. package/dist/claude/stats.js.map +1 -0
  163. package/dist/cli-epilogue.d.ts +12 -0
  164. package/dist/cli-epilogue.d.ts.map +1 -0
  165. package/dist/cli-epilogue.js +72 -0
  166. package/dist/cli-epilogue.js.map +1 -0
  167. package/dist/cli-meta.d.ts +82 -0
  168. package/dist/cli-meta.d.ts.map +1 -0
  169. package/dist/cli-meta.js +238 -0
  170. package/dist/cli-meta.js.map +1 -0
  171. package/dist/cli-picker.d.ts +139 -0
  172. package/dist/cli-picker.d.ts.map +1 -0
  173. package/dist/cli-picker.js +439 -0
  174. package/dist/cli-picker.js.map +1 -0
  175. package/dist/cli.d.ts +3 -0
  176. package/dist/cli.d.ts.map +1 -0
  177. package/dist/cli.js +1638 -0
  178. package/dist/cli.js.map +1 -0
  179. package/dist/context/batches.d.ts +29 -0
  180. package/dist/context/batches.d.ts.map +1 -0
  181. package/dist/context/batches.js +130 -0
  182. package/dist/context/batches.js.map +1 -0
  183. package/dist/context/build.d.ts +57 -0
  184. package/dist/context/build.d.ts.map +1 -0
  185. package/dist/context/build.js +396 -0
  186. package/dist/context/build.js.map +1 -0
  187. package/dist/context/check.d.ts +42 -0
  188. package/dist/context/check.d.ts.map +1 -0
  189. package/dist/context/check.js +162 -0
  190. package/dist/context/check.js.map +1 -0
  191. package/dist/context/map-dir.d.ts +13 -0
  192. package/dist/context/map-dir.d.ts.map +1 -0
  193. package/dist/context/map-dir.js +81 -0
  194. package/dist/context/map-dir.js.map +1 -0
  195. package/dist/context/node-file.d.ts +109 -0
  196. package/dist/context/node-file.d.ts.map +1 -0
  197. package/dist/context/node-file.js +390 -0
  198. package/dist/context/node-file.js.map +1 -0
  199. package/dist/context/price.d.ts +49 -0
  200. package/dist/context/price.d.ts.map +1 -0
  201. package/dist/context/price.js +83 -0
  202. package/dist/context/price.js.map +1 -0
  203. package/dist/context/savings.d.ts +67 -0
  204. package/dist/context/savings.d.ts.map +1 -0
  205. package/dist/context/savings.js +125 -0
  206. package/dist/context/savings.js.map +1 -0
  207. package/dist/engine.d.ts +85 -0
  208. package/dist/engine.d.ts.map +1 -0
  209. package/dist/engine.js +122 -0
  210. package/dist/engine.js.map +1 -0
  211. package/dist/graph/bindings.d.ts +64 -0
  212. package/dist/graph/bindings.d.ts.map +1 -0
  213. package/dist/graph/bindings.js +713 -0
  214. package/dist/graph/bindings.js.map +1 -0
  215. package/dist/graph/build-run.d.ts +25 -0
  216. package/dist/graph/build-run.d.ts.map +1 -0
  217. package/dist/graph/build-run.js +121 -0
  218. package/dist/graph/build-run.js.map +1 -0
  219. package/dist/graph/build.d.ts +88 -0
  220. package/dist/graph/build.d.ts.map +1 -0
  221. package/dist/graph/build.js +386 -0
  222. package/dist/graph/build.js.map +1 -0
  223. package/dist/graph/cards.d.ts +46 -0
  224. package/dist/graph/cards.d.ts.map +1 -0
  225. package/dist/graph/cards.js +280 -0
  226. package/dist/graph/cards.js.map +1 -0
  227. package/dist/graph/check.d.ts +25 -0
  228. package/dist/graph/check.d.ts.map +1 -0
  229. package/dist/graph/check.js +192 -0
  230. package/dist/graph/check.js.map +1 -0
  231. package/dist/graph/container.d.ts +63 -0
  232. package/dist/graph/container.d.ts.map +1 -0
  233. package/dist/graph/container.js +191 -0
  234. package/dist/graph/container.js.map +1 -0
  235. package/dist/graph/depth-parser.d.ts +61 -0
  236. package/dist/graph/depth-parser.d.ts.map +1 -0
  237. package/dist/graph/depth-parser.js +153 -0
  238. package/dist/graph/depth-parser.js.map +1 -0
  239. package/dist/graph/enrich.d.ts +62 -0
  240. package/dist/graph/enrich.d.ts.map +1 -0
  241. package/dist/graph/enrich.js +258 -0
  242. package/dist/graph/enrich.js.map +1 -0
  243. package/dist/graph/extract-cache.d.ts +101 -0
  244. package/dist/graph/extract-cache.d.ts.map +1 -0
  245. package/dist/graph/extract-cache.js +199 -0
  246. package/dist/graph/extract-cache.js.map +1 -0
  247. package/dist/graph/extract.d.ts +85 -0
  248. package/dist/graph/extract.d.ts.map +1 -0
  249. package/dist/graph/extract.js +2377 -0
  250. package/dist/graph/extract.js.map +1 -0
  251. package/dist/graph/fingerprint.d.ts +76 -0
  252. package/dist/graph/fingerprint.d.ts.map +1 -0
  253. package/dist/graph/fingerprint.js +160 -0
  254. package/dist/graph/fingerprint.js.map +1 -0
  255. package/dist/graph/generic.d.ts +74 -0
  256. package/dist/graph/generic.d.ts.map +1 -0
  257. package/dist/graph/generic.js +773 -0
  258. package/dist/graph/generic.js.map +1 -0
  259. package/dist/graph/invariants.d.ts +33 -0
  260. package/dist/graph/invariants.d.ts.map +1 -0
  261. package/dist/graph/invariants.js +52 -0
  262. package/dist/graph/invariants.js.map +1 -0
  263. package/dist/graph/load.d.ts +29 -0
  264. package/dist/graph/load.d.ts.map +1 -0
  265. package/dist/graph/load.js +97 -0
  266. package/dist/graph/load.js.map +1 -0
  267. package/dist/graph/lsp/client.d.ts +61 -0
  268. package/dist/graph/lsp/client.d.ts.map +1 -0
  269. package/dist/graph/lsp/client.js +217 -0
  270. package/dist/graph/lsp/client.js.map +1 -0
  271. package/dist/graph/lsp/enrich.d.ts +11 -0
  272. package/dist/graph/lsp/enrich.d.ts.map +1 -0
  273. package/dist/graph/lsp/enrich.js +163 -0
  274. package/dist/graph/lsp/enrich.js.map +1 -0
  275. package/dist/graph/lsp/registry.d.ts +22 -0
  276. package/dist/graph/lsp/registry.d.ts.map +1 -0
  277. package/dist/graph/lsp/registry.js +71 -0
  278. package/dist/graph/lsp/registry.js.map +1 -0
  279. package/dist/graph/map.d.ts +107 -0
  280. package/dist/graph/map.d.ts.map +1 -0
  281. package/dist/graph/map.js +239 -0
  282. package/dist/graph/map.js.map +1 -0
  283. package/dist/graph/markdown.d.ts +22 -0
  284. package/dist/graph/markdown.d.ts.map +1 -0
  285. package/dist/graph/markdown.js +143 -0
  286. package/dist/graph/markdown.js.map +1 -0
  287. package/dist/graph/native.d.ts +46 -0
  288. package/dist/graph/native.d.ts.map +1 -0
  289. package/dist/graph/native.js +169 -0
  290. package/dist/graph/native.js.map +1 -0
  291. package/dist/graph/queries/c.scm +13 -0
  292. package/dist/graph/queries/c_sharp.scm +19 -0
  293. package/dist/graph/queries/clojure.scm +58 -0
  294. package/dist/graph/queries/cpp.scm +23 -0
  295. package/dist/graph/queries/dart.scm +42 -0
  296. package/dist/graph/queries/elixir.scm +54 -0
  297. package/dist/graph/queries/gleam.scm +51 -0
  298. package/dist/graph/queries/java.scm +20 -0
  299. package/dist/graph/queries/kotlin.scm +43 -0
  300. package/dist/graph/queries/lua.scm +36 -0
  301. package/dist/graph/queries/nix.scm +32 -0
  302. package/dist/graph/queries/php.scm +40 -0
  303. package/dist/graph/queries/ruby.scm +65 -0
  304. package/dist/graph/queries/rust.scm +41 -0
  305. package/dist/graph/queries/scala.scm +66 -0
  306. package/dist/graph/queries/solidity.scm +43 -0
  307. package/dist/graph/queries/swift.scm +51 -0
  308. package/dist/graph/refresh.d.ts +106 -0
  309. package/dist/graph/refresh.d.ts.map +1 -0
  310. package/dist/graph/refresh.js +430 -0
  311. package/dist/graph/refresh.js.map +1 -0
  312. package/dist/graph/relations.d.ts +14 -0
  313. package/dist/graph/relations.d.ts.map +1 -0
  314. package/dist/graph/relations.js +8 -0
  315. package/dist/graph/relations.js.map +1 -0
  316. package/dist/graph/resolve.d.ts +17 -0
  317. package/dist/graph/resolve.d.ts.map +1 -0
  318. package/dist/graph/resolve.js +716 -0
  319. package/dist/graph/resolve.js.map +1 -0
  320. package/dist/graph/root.d.ts +11 -0
  321. package/dist/graph/root.d.ts.map +1 -0
  322. package/dist/graph/root.js +40 -0
  323. package/dist/graph/root.js.map +1 -0
  324. package/dist/graph/scopes.d.ts +40 -0
  325. package/dist/graph/scopes.d.ts.map +1 -0
  326. package/dist/graph/scopes.js +383 -0
  327. package/dist/graph/scopes.js.map +1 -0
  328. package/dist/graph/seed.d.ts +38 -0
  329. package/dist/graph/seed.d.ts.map +1 -0
  330. package/dist/graph/seed.js +229 -0
  331. package/dist/graph/seed.js.map +1 -0
  332. package/dist/graph/source-files.d.ts +46 -0
  333. package/dist/graph/source-files.d.ts.map +1 -0
  334. package/dist/graph/source-files.js +118 -0
  335. package/dist/graph/source-files.js.map +1 -0
  336. package/dist/graph/traverse-cli.d.ts +55 -0
  337. package/dist/graph/traverse-cli.d.ts.map +1 -0
  338. package/dist/graph/traverse-cli.js +189 -0
  339. package/dist/graph/traverse-cli.js.map +1 -0
  340. package/dist/graph/traverse.d.ts +112 -0
  341. package/dist/graph/traverse.d.ts.map +1 -0
  342. package/dist/graph/traverse.js +192 -0
  343. package/dist/graph/traverse.js.map +1 -0
  344. package/dist/graph/types.d.ts +78 -0
  345. package/dist/graph/types.d.ts.map +1 -0
  346. package/dist/graph/types.js +14 -0
  347. package/dist/graph/types.js.map +1 -0
  348. package/dist/graph/wasm-runtime.d.ts +19 -0
  349. package/dist/graph/wasm-runtime.d.ts.map +1 -0
  350. package/dist/graph/wasm-runtime.js +38 -0
  351. package/dist/graph/wasm-runtime.js.map +1 -0
  352. package/dist/graph/workspace-cli.d.ts +56 -0
  353. package/dist/graph/workspace-cli.d.ts.map +1 -0
  354. package/dist/graph/workspace-cli.js +111 -0
  355. package/dist/graph/workspace-cli.js.map +1 -0
  356. package/dist/graph/workspace.d.ts +172 -0
  357. package/dist/graph/workspace.d.ts.map +1 -0
  358. package/dist/graph/workspace.js +714 -0
  359. package/dist/graph/workspace.js.map +1 -0
  360. package/dist/graph/write.d.ts +13 -0
  361. package/dist/graph/write.d.ts.map +1 -0
  362. package/dist/graph/write.js +86 -0
  363. package/dist/graph/write.js.map +1 -0
  364. package/dist/hosts/antigravity.d.ts +14 -0
  365. package/dist/hosts/antigravity.d.ts.map +1 -0
  366. package/dist/hosts/antigravity.js +59 -0
  367. package/dist/hosts/antigravity.js.map +1 -0
  368. package/dist/hosts/auto.d.ts +37 -0
  369. package/dist/hosts/auto.d.ts.map +1 -0
  370. package/dist/hosts/auto.js +141 -0
  371. package/dist/hosts/auto.js.map +1 -0
  372. package/dist/hosts/claude-global.d.ts +72 -0
  373. package/dist/hosts/claude-global.d.ts.map +1 -0
  374. package/dist/hosts/claude-global.js +230 -0
  375. package/dist/hosts/claude-global.js.map +1 -0
  376. package/dist/hosts/config-write.d.ts +36 -0
  377. package/dist/hosts/config-write.d.ts.map +1 -0
  378. package/dist/hosts/config-write.js +64 -0
  379. package/dist/hosts/config-write.js.map +1 -0
  380. package/dist/hosts/init.d.ts +28 -0
  381. package/dist/hosts/init.d.ts.map +1 -0
  382. package/dist/hosts/init.js +89 -0
  383. package/dist/hosts/init.js.map +1 -0
  384. package/dist/hosts/instructions.d.ts +14 -0
  385. package/dist/hosts/instructions.d.ts.map +1 -0
  386. package/dist/hosts/instructions.js +95 -0
  387. package/dist/hosts/instructions.js.map +1 -0
  388. package/dist/hosts/mcp-config.d.ts +78 -0
  389. package/dist/hosts/mcp-config.d.ts.map +1 -0
  390. package/dist/hosts/mcp-config.js +251 -0
  391. package/dist/hosts/mcp-config.js.map +1 -0
  392. package/dist/hosts/plan.d.ts +32 -0
  393. package/dist/hosts/plan.d.ts.map +1 -0
  394. package/dist/hosts/plan.js +73 -0
  395. package/dist/hosts/plan.js.map +1 -0
  396. package/dist/hosts/registry.d.ts +41 -0
  397. package/dist/hosts/registry.d.ts.map +1 -0
  398. package/dist/hosts/registry.js +164 -0
  399. package/dist/hosts/registry.js.map +1 -0
  400. package/dist/hosts/retract.d.ts +47 -0
  401. package/dist/hosts/retract.d.ts.map +1 -0
  402. package/dist/hosts/retract.js +520 -0
  403. package/dist/hosts/retract.js.map +1 -0
  404. package/dist/hosts/sections.d.ts +47 -0
  405. package/dist/hosts/sections.d.ts.map +1 -0
  406. package/dist/hosts/sections.js +127 -0
  407. package/dist/hosts/sections.js.map +1 -0
  408. package/dist/index.d.ts +41 -0
  409. package/dist/index.d.ts.map +1 -0
  410. package/dist/index.js +32 -0
  411. package/dist/index.js.map +1 -0
  412. package/dist/ingest/fs.d.ts +79 -0
  413. package/dist/ingest/fs.d.ts.map +1 -0
  414. package/dist/ingest/fs.js +306 -0
  415. package/dist/ingest/fs.js.map +1 -0
  416. package/dist/init-guard.d.ts +16 -0
  417. package/dist/init-guard.d.ts.map +1 -0
  418. package/dist/init-guard.js +27 -0
  419. package/dist/init-guard.js.map +1 -0
  420. package/dist/mcp/instructions.d.ts +5 -0
  421. package/dist/mcp/instructions.d.ts.map +1 -0
  422. package/dist/mcp/instructions.js +64 -0
  423. package/dist/mcp/instructions.js.map +1 -0
  424. package/dist/mcp/kept-listing.d.ts +27 -0
  425. package/dist/mcp/kept-listing.d.ts.map +1 -0
  426. package/dist/mcp/kept-listing.js +63 -0
  427. package/dist/mcp/kept-listing.js.map +1 -0
  428. package/dist/mcp/server.d.ts +4 -0
  429. package/dist/mcp/server.d.ts.map +1 -0
  430. package/dist/mcp/server.js +147 -0
  431. package/dist/mcp/server.js.map +1 -0
  432. package/dist/mcp/tool-names.d.ts +27 -0
  433. package/dist/mcp/tool-names.d.ts.map +1 -0
  434. package/dist/mcp/tool-names.js +47 -0
  435. package/dist/mcp/tool-names.js.map +1 -0
  436. package/dist/mcp/tools.d.ts +22 -0
  437. package/dist/mcp/tools.d.ts.map +1 -0
  438. package/dist/mcp/tools.js +440 -0
  439. package/dist/mcp/tools.js.map +1 -0
  440. package/dist/node-version.d.ts +15 -0
  441. package/dist/node-version.d.ts.map +1 -0
  442. package/dist/node-version.js +23 -0
  443. package/dist/node-version.js.map +1 -0
  444. package/dist/search/grep-cli.d.ts +35 -0
  445. package/dist/search/grep-cli.d.ts.map +1 -0
  446. package/dist/search/grep-cli.js +115 -0
  447. package/dist/search/grep-cli.js.map +1 -0
  448. package/dist/search/grep.d.ts +60 -0
  449. package/dist/search/grep.d.ts.map +1 -0
  450. package/dist/search/grep.js +143 -0
  451. package/dist/search/grep.js.map +1 -0
  452. package/dist/search/ignored-code.d.ts +9 -0
  453. package/dist/search/ignored-code.d.ts.map +1 -0
  454. package/dist/search/ignored-code.js +73 -0
  455. package/dist/search/ignored-code.js.map +1 -0
  456. package/dist/search/user-regexp.d.ts +26 -0
  457. package/dist/search/user-regexp.d.ts.map +1 -0
  458. package/dist/search/user-regexp.js +150 -0
  459. package/dist/search/user-regexp.js.map +1 -0
  460. package/dist/telemetry/contract.d.ts +117 -0
  461. package/dist/telemetry/contract.d.ts.map +1 -0
  462. package/dist/telemetry/contract.js +341 -0
  463. package/dist/telemetry/contract.js.map +1 -0
  464. package/dist/telemetry/flush.d.ts +21 -0
  465. package/dist/telemetry/flush.d.ts.map +1 -0
  466. package/dist/telemetry/flush.js +85 -0
  467. package/dist/telemetry/flush.js.map +1 -0
  468. package/dist/telemetry/gate.d.ts +30 -0
  469. package/dist/telemetry/gate.d.ts.map +1 -0
  470. package/dist/telemetry/gate.js +81 -0
  471. package/dist/telemetry/gate.js.map +1 -0
  472. package/dist/telemetry/identity.d.ts +40 -0
  473. package/dist/telemetry/identity.d.ts.map +1 -0
  474. package/dist/telemetry/identity.js +80 -0
  475. package/dist/telemetry/identity.js.map +1 -0
  476. package/dist/telemetry/index.d.ts +18 -0
  477. package/dist/telemetry/index.d.ts.map +1 -0
  478. package/dist/telemetry/index.js +16 -0
  479. package/dist/telemetry/index.js.map +1 -0
  480. package/dist/telemetry/key.d.ts +21 -0
  481. package/dist/telemetry/key.d.ts.map +1 -0
  482. package/dist/telemetry/key.js +49 -0
  483. package/dist/telemetry/key.js.map +1 -0
  484. package/dist/telemetry/notice.d.ts +19 -0
  485. package/dist/telemetry/notice.d.ts.map +1 -0
  486. package/dist/telemetry/notice.js +93 -0
  487. package/dist/telemetry/notice.js.map +1 -0
  488. package/dist/telemetry/queue.d.ts +35 -0
  489. package/dist/telemetry/queue.d.ts.map +1 -0
  490. package/dist/telemetry/queue.js +162 -0
  491. package/dist/telemetry/queue.js.map +1 -0
  492. package/dist/telemetry/send.d.ts +19 -0
  493. package/dist/telemetry/send.d.ts.map +1 -0
  494. package/dist/telemetry/send.js +84 -0
  495. package/dist/telemetry/send.js.map +1 -0
  496. package/dist/telemetry/sessions.d.ts +25 -0
  497. package/dist/telemetry/sessions.d.ts.map +1 -0
  498. package/dist/telemetry/sessions.js +104 -0
  499. package/dist/telemetry/sessions.js.map +1 -0
  500. package/dist/telemetry/track.d.ts +62 -0
  501. package/dist/telemetry/track.d.ts.map +1 -0
  502. package/dist/telemetry/track.js +143 -0
  503. package/dist/telemetry/track.js.map +1 -0
  504. package/dist/upkeep-run.d.ts +22 -0
  505. package/dist/upkeep-run.d.ts.map +1 -0
  506. package/dist/upkeep-run.js +85 -0
  507. package/dist/upkeep-run.js.map +1 -0
  508. package/dist/upkeep.d.ts +127 -0
  509. package/dist/upkeep.d.ts.map +1 -0
  510. package/dist/upkeep.js +252 -0
  511. package/dist/upkeep.js.map +1 -0
  512. package/dist/util/actions-folder.d.ts +2 -0
  513. package/dist/util/actions-folder.d.ts.map +1 -0
  514. package/dist/util/actions-folder.js +9 -0
  515. package/dist/util/actions-folder.js.map +1 -0
  516. package/dist/util/browser.d.ts +3 -0
  517. package/dist/util/browser.d.ts.map +1 -0
  518. package/dist/util/browser.js +14 -0
  519. package/dist/util/browser.js.map +1 -0
  520. package/dist/util/child-process.d.ts +15 -0
  521. package/dist/util/child-process.d.ts.map +1 -0
  522. package/dist/util/child-process.js +15 -0
  523. package/dist/util/child-process.js.map +1 -0
  524. package/dist/util/front-matter.d.ts +46 -0
  525. package/dist/util/front-matter.d.ts.map +1 -0
  526. package/dist/util/front-matter.js +113 -0
  527. package/dist/util/front-matter.js.map +1 -0
  528. package/dist/util/id.d.ts +7 -0
  529. package/dist/util/id.d.ts.map +1 -0
  530. package/dist/util/id.js +14 -0
  531. package/dist/util/id.js.map +1 -0
  532. package/dist/util/paths.d.ts +29 -0
  533. package/dist/util/paths.d.ts.map +1 -0
  534. package/dist/util/paths.js +71 -0
  535. package/dist/util/paths.js.map +1 -0
  536. package/dist/util/private-file.d.ts +14 -0
  537. package/dist/util/private-file.d.ts.map +1 -0
  538. package/dist/util/private-file.js +82 -0
  539. package/dist/util/private-file.js.map +1 -0
  540. package/dist/util/source.d.ts +4 -0
  541. package/dist/util/source.d.ts.map +1 -0
  542. package/dist/util/source.js +12 -0
  543. package/dist/util/source.js.map +1 -0
  544. package/dist/util/spinner.d.ts +15 -0
  545. package/dist/util/spinner.d.ts.map +1 -0
  546. package/dist/util/spinner.js +52 -0
  547. package/dist/util/spinner.js.map +1 -0
  548. package/dist/util/state.d.ts +120 -0
  549. package/dist/util/state.d.ts.map +1 -0
  550. package/dist/util/state.js +264 -0
  551. package/dist/util/state.js.map +1 -0
  552. package/dist/vendor/grammars/tree-sitter-go.LICENSE +21 -0
  553. package/dist/vendor/grammars/tree-sitter-go.wasm +0 -0
  554. package/dist/vendor/grammars/tree-sitter-java.LICENSE +21 -0
  555. package/dist/vendor/grammars/tree-sitter-java.wasm +0 -0
  556. package/dist/vendor/grammars/tree-sitter-kotlin.LICENSE +9 -0
  557. package/dist/vendor/grammars/tree-sitter-kotlin.wasm +0 -0
  558. package/dist/vendor/grammars/tree-sitter-php.LICENSE +22 -0
  559. package/dist/vendor/grammars/tree-sitter-php.wasm +0 -0
  560. package/dist/vendor/grammars/tree-sitter-python.LICENSE +21 -0
  561. package/dist/vendor/grammars/tree-sitter-python.wasm +0 -0
  562. package/dist/vendor/grammars/tree-sitter-r.LICENSE +9 -0
  563. package/dist/vendor/grammars/tree-sitter-r.wasm +0 -0
  564. package/dist/vendor/grammars/tree-sitter-swift.LICENSE +21 -0
  565. package/dist/vendor/grammars/tree-sitter-swift.wasm +0 -0
  566. package/dist/vendor/grammars/tree-sitter-tsx.wasm +0 -0
  567. package/dist/vendor/grammars/tree-sitter-typescript.LICENSE +21 -0
  568. package/dist/vendor/grammars/tree-sitter-typescript.wasm +0 -0
  569. package/dist/viewer/app.js +2 -0
  570. package/dist/viewer/index.html +49 -0
  571. package/dist/viewer/style.css +154 -0
  572. package/dist/viz/assemble.d.ts +83 -0
  573. package/dist/viz/assemble.d.ts.map +1 -0
  574. package/dist/viz/assemble.js +101 -0
  575. package/dist/viz/assemble.js.map +1 -0
  576. package/dist/viz/export.d.ts +39 -0
  577. package/dist/viz/export.d.ts.map +1 -0
  578. package/dist/viz/export.js +98 -0
  579. package/dist/viz/export.js.map +1 -0
  580. package/dist/viz/serve.d.ts +13 -0
  581. package/dist/viz/serve.d.ts.map +1 -0
  582. package/dist/viz/serve.js +130 -0
  583. package/dist/viz/serve.js.map +1 -0
  584. package/package.json +115 -4
  585. package/scripts/build-grammar-wasm.mjs +112 -0
  586. package/scripts/build-viewer.mjs +44 -0
  587. package/scripts/graph-quality.mjs +117 -0
  588. package/scripts/pack-trail.mjs +53 -0
  589. package/scripts/postinstall.mjs +65 -0
  590. package/scripts/run-tests.mjs +72 -0
  591. package/scripts/stamp-telemetry-key.mjs +56 -0
  592. package/scripts/tally-audit.mjs +140 -0
  593. package/scripts/vendor-grammars.mjs +53 -0
@@ -0,0 +1,773 @@
1
+ /**
2
+ * Generic "breadth" extractor tier — one language-agnostic extractor over any
3
+ * tree-sitter grammar + its `tags.scm` (the standard tree-sitter tags convention). This is how
4
+ * graft covers the long tail of languages for ~one registry row each, instead of
5
+ * a hand-written extractor per language (the depth tier in extract.ts).
6
+ *
7
+ * Grammars are WASM (`tree-sitter-wasm` bundle) loaded via `web-tree-sitter`, so
8
+ * a new language needs no native node-gyp build. Loading is async (WASM init), so
9
+ * callers MUST `await warmGenericGrammars([...])` once before the synchronous
10
+ * `extractGeneric()` is used in a build/check loop. If a grammar isn't warmed,
11
+ * `extractGeneric` degrades to a file node only (never throws).
12
+ *
13
+ * What it emits (signature-only): a file node + one node per `@definition.<kind>`
14
+ * capture, and bare-name `calls` raw edges from `@reference.call` attributed to
15
+ * the innermost enclosing definition. resolve.ts then resolves those calls by
16
+ * name for free (same-file → extracted, unique-global → inferred). Member-call
17
+ * receiver typing (recvType) is NOT produced here — that needs a per-language
18
+ * binding pass; the opt-in LSP tier fills that gap for popular languages.
19
+ */
20
+ import { readFileSync } from "node:fs";
21
+ import { fileURLToPath } from "node:url";
22
+ import { dirname, join } from "node:path";
23
+ import { createRequire } from "node:module";
24
+ import { contentHash } from "../util/id.js";
25
+ import { webTreeSitter } from "./wasm-runtime.js";
26
+ const HERE = dirname(fileURLToPath(import.meta.url));
27
+ const require = createRequire(import.meta.url);
28
+ // queries/ ships beside the compiled JS (copied by the build); fall back to src.
29
+ const QUERY_DIRS = [join(HERE, "queries"), join(HERE, "..", "..", "src", "graph", "queries")];
30
+ /** The breadth registry. Add a row + a queries/<name>.scm to support a language.
31
+ * Extensions here must NOT collide with the depth tier's EXTENSIONS (extract.ts). */
32
+ export const GENERIC_LANGS = [
33
+ { name: "rust", exts: [".rs"], wasm: "rust" },
34
+ { name: "java", exts: [".java"], wasm: "java" },
35
+ { name: "c", exts: [".c", ".h"], wasm: "c" },
36
+ { name: "cpp", exts: [".cpp", ".cc", ".cxx", ".hpp", ".hh"], wasm: "cpp" },
37
+ { name: "ruby", exts: [".rb"], wasm: "ruby" },
38
+ { name: "c_sharp", exts: [".cs"], wasm: "c_sharp" },
39
+ // These ship a tags.scm (calls + symbols); ocaml/zig have none and use the
40
+ // node-kind walker fallback (symbols only) — still one row, zero query.
41
+ { name: "scala", exts: [".scala", ".sc"], wasm: "scala" },
42
+ { name: "elixir", exts: [".ex", ".exs"], wasm: "elixir" },
43
+ { name: "solidity", exts: [".sol"], wasm: "solidity" },
44
+ { name: "ocaml", exts: [".ml", ".mli"], wasm: "ocaml" },
45
+ { name: "zig", exts: [".zig"], wasm: "zig" },
46
+ { name: "dart", exts: [".dart"], wasm: "dart" }, // surfaced by PR #38 (@muneebshere)
47
+ { name: "clojure", exts: [".clj", ".cljs", ".cljc", ".bb"], wasm: "clojure" },
48
+ { name: "nix", exts: [".nix"], wasm: "nix" },
49
+ { name: "lua", exts: [".lua"], wasm: "lua" },
50
+ { name: "gleam", exts: [".gleam"], wasm: "gleam" },
51
+ ];
52
+ /**
53
+ * Stand-ins for the depth tier, used only for a language whose own grammar did not
54
+ * load (depth-parser.ts), as after a broken install. They claim no extension, so
55
+ * `genericLangOf` never returns them; the build picks one by asking
56
+ * {@link fallbackLangOf}. Output is the
57
+ * breadth tier's: symbols and bare-name calls, no receiver types or bindings.
58
+ * Kotlin, Swift and PHP use their vendored queries/<name>.scm; the rest use the
59
+ * bundle's own tags.scm (typescript's builds on javascript's, as upstream does).
60
+ */
61
+ const FALLBACK_LANGS = {
62
+ typescript: { name: "typescript", exts: [], wasm: "typescript", bundledTags: ["javascript", "typescript"] },
63
+ tsx: { name: "tsx", exts: [], wasm: "tsx", bundledTags: ["javascript", "tsx"] },
64
+ python: { name: "python", exts: [], wasm: "python", bundledTags: ["python"] },
65
+ go: { name: "go", exts: [], wasm: "go", bundledTags: ["go"] },
66
+ r: { name: "r", exts: [], wasm: "r", bundledTags: ["r"] },
67
+ kotlin: { name: "kotlin", exts: [], wasm: "kotlin" },
68
+ swift: { name: "swift", exts: [], wasm: "swift" },
69
+ php: { name: "php", exts: [], wasm: "php" },
70
+ };
71
+ /** The breadth-tier grammar that stands in for a depth-tier language whose native
72
+ * grammar can't load. Java already has a breadth row, so it is its own stand-in. */
73
+ export function fallbackLangOf(lang) {
74
+ return lang === "java" ? GENERIC_LANGS.find((l) => l.name === "java") : FALLBACK_LANGS[lang];
75
+ }
76
+ function rowNamed(name) {
77
+ return GENERIC_LANGS.find((l) => l.name === name) ?? Object.values(FALLBACK_LANGS).find((l) => l.name === name);
78
+ }
79
+ const byExt = new Map();
80
+ for (const l of GENERIC_LANGS)
81
+ for (const e of l.exts)
82
+ byExt.set(e, l);
83
+ /** The generic language for a path, or null if no breadth grammar claims it. */
84
+ export function genericLangOf(path) {
85
+ const lower = path.toLowerCase();
86
+ for (const [ext, l] of byExt)
87
+ if (lower.endsWith(ext))
88
+ return l;
89
+ return null;
90
+ }
91
+ /** Every file extension a breadth-tier (generic tree-sitter) grammar claims. */
92
+ export function genericExtensions() {
93
+ return GENERIC_LANGS.flatMap((l) => l.exts);
94
+ }
95
+ // tags.scm @definition.<X> → graft Kind (types.ts). Unmapped → "function".
96
+ const KIND = {
97
+ function: "function", method: "method", class: "class", interface: "interface",
98
+ type: "type", struct: "struct", enum: "enum", module: "module",
99
+ constant: "constant", variable: "variable", field: "variable",
100
+ object: "class", property: "variable", // Scala object; Swift/Scala property
101
+ };
102
+ const loaded = new Map();
103
+ let tsMod = null;
104
+ function requireWasm(wasm) {
105
+ // Resolve the grammar wasm from the tree-sitter-wasm bundle (its package.json
106
+ // `exports` maps the bare "<lang>/…" subpath to the actual "out/<lang>/…" file).
107
+ try {
108
+ const p = require.resolve(`tree-sitter-wasm/${wasm}/tree-sitter-${wasm}.wasm`);
109
+ return readFileSync(p);
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ }
115
+ // Sanitize editor-specific query predicates the tree-sitter Query compiler rejects.
116
+ function sanitizeQuery(raw) {
117
+ return raw.replace(/\(#(?:strip!|set!|set-adjacent!|select-adjacent!|make-range!|offset!|gsub!)[^()]*\)/g, "");
118
+ }
119
+ function loadQuery(row) {
120
+ for (const dir of QUERY_DIRS) {
121
+ try {
122
+ return sanitizeQuery(readFileSync(join(dir, `${row.name}.scm`), "utf8"));
123
+ }
124
+ catch {
125
+ /* try next dir */
126
+ }
127
+ }
128
+ if (!row.bundledTags)
129
+ return null;
130
+ const parts = [];
131
+ for (const dir of row.bundledTags) {
132
+ try {
133
+ parts.push(readFileSync(require.resolve(`tree-sitter-wasm/${dir}/tags.scm`), "utf8"));
134
+ }
135
+ catch {
136
+ /* no tags.scm for this one */
137
+ }
138
+ }
139
+ return parts.length > 0 ? sanitizeQuery(parts.join("\n")) : null;
140
+ }
141
+ /** Warm the WASM grammars for the given graft lang names. Idempotent; must be
142
+ * awaited once before extractGeneric is used in a sync loop. Unknown/unavailable
143
+ * grammars are silently skipped (their files then extract as file-only). */
144
+ export async function warmGenericGrammars(langNames) {
145
+ const want = new Set(langNames);
146
+ const need = [...want].filter((n) => !loaded.has(n) && rowNamed(n) !== undefined);
147
+ if (need.length === 0)
148
+ return;
149
+ tsMod = await webTreeSitter();
150
+ const { Language, Query } = tsMod;
151
+ for (const name of need) {
152
+ const row = rowNamed(name);
153
+ const bytes = requireWasm(row.wasm);
154
+ if (!bytes)
155
+ continue;
156
+ try {
157
+ const language = await Language.load(bytes);
158
+ const scm = loadQuery(row);
159
+ let query = null;
160
+ if (scm) {
161
+ try {
162
+ query = new Query(language, scm);
163
+ }
164
+ catch {
165
+ query = null;
166
+ }
167
+ }
168
+ loaded.set(name, { language, query });
169
+ }
170
+ catch {
171
+ /* grammar failed to instantiate — skip; files extract as file-only */
172
+ }
173
+ }
174
+ }
175
+ /** True if a grammar has been warmed for this lang (else extractGeneric is file-only). */
176
+ export function isWarm(langName) {
177
+ return loaded.has(langName);
178
+ }
179
+ /** Test seam: swap in (or, with null, remove) a grammar entry, returning the
180
+ * previous one so the caller can restore it. The parse-failure path in
181
+ * extractGeneric needs a grammar that throws deterministically; the real crash
182
+ * that motivated it (tree-sitter-wasm PHP on heredocs, #139) is heap-state
183
+ * dependent, so tests inject a fake here instead of depending on it. */
184
+ export function swapGrammarForTest(name, entry) {
185
+ const prev = loaded.get(name) ?? null;
186
+ if (entry)
187
+ loaded.set(name, entry);
188
+ else
189
+ loaded.delete(name);
190
+ return prev;
191
+ }
192
+ /** Load one grammar from the tree-sitter-wasms bundle, initialising
193
+ * web-tree-sitter on first call. Null when the wasm is missing or won't
194
+ * instantiate — never throws, so a caller degrades instead of failing the build.
195
+ *
196
+ * Shared with the container tier (container.ts), which needs a grammar to find
197
+ * where an embedded language starts but none of the tags.scm machinery above.
198
+ * The runtime itself is shared with every WASM tier (wasm-runtime.ts). */
199
+ export async function loadWasmLanguage(wasm) {
200
+ tsMod = await webTreeSitter();
201
+ const bytes = requireWasm(wasm);
202
+ if (!bytes)
203
+ return null;
204
+ try {
205
+ return await tsMod.Language.load(bytes);
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ const PARSE_CHUNK = 16384; // <32KB slices — same tree-sitter limit workaround as extract.ts
212
+ /** Parse with an already-loaded grammar. Returns the root node, or null if the
213
+ * grammar was never warmed or the parse blew up. Companion to
214
+ * `loadWasmLanguage` for callers outside this module. */
215
+ export function parseWasm(language, source) {
216
+ if (!tsMod)
217
+ return null;
218
+ try {
219
+ const parser = new tsMod.Parser();
220
+ parser.setLanguage(language);
221
+ const tree = parser.parse((i) => source.slice(i, i + PARSE_CHUNK));
222
+ return tree?.rootNode ?? null;
223
+ }
224
+ catch {
225
+ return null;
226
+ }
227
+ }
228
+ function fileNode(rel, source) {
229
+ return {
230
+ id: rel, name: rel.split("/").pop() ?? rel, kind: "file", path: rel,
231
+ span: `L1-L${Math.max(1, source.split("\n").length)}`, signature: null,
232
+ exported: true, origin: "generic", body_hash: contentHash(source),
233
+ chars: Buffer.byteLength(source), summary_state: "pending", summary: null, crux: null,
234
+ };
235
+ }
236
+ /** The innermost definition whose span covers the token at byte offset `at` —
237
+ * the caller a reference found there belongs to. Shared by the tags.scm path and
238
+ * the per-language passes below so both attribute edges the same way. */
239
+ function enclosingDef(defs, at) {
240
+ return defs
241
+ .filter((d) => d.startIndex <= at && at < d.endIndex)
242
+ .sort((a, b) => (a.endIndex - a.startIndex) - (b.endIndex - b.startIndex))[0];
243
+ }
244
+ /** Extract a single generic-tier file. Synchronous; needs the grammar pre-warmed.
245
+ * Uses the grammar's compiled tags.scm when present (symbols + call edges);
246
+ * otherwise falls back to a node-kind tree walker (symbols only) so ANY warmed
247
+ * grammar yields a graph even with no vendored query. */
248
+ export function extractGeneric(rel, source, langName) {
249
+ const nodes = [fileNode(rel, source)];
250
+ const rawEdges = [];
251
+ const entry = loaded.get(langName);
252
+ if (!entry || !tsMod)
253
+ return { nodes, rawEdges };
254
+ let tree;
255
+ try {
256
+ const parser = new tsMod.Parser();
257
+ parser.setLanguage(entry.language);
258
+ tree = parser.parse((i) => source.slice(i, i + PARSE_CHUNK));
259
+ }
260
+ catch (err) {
261
+ // A grammar that throws (e.g. a WASM "memory access out of bounds" from an
262
+ // external scanner) is not a per-file syntax problem: swallowing it here left
263
+ // the file with only its file node and the build reporting success. Rethrow so
264
+ // build.ts records it in `errors`, the CLI prints it, and the extract cache
265
+ // remembers the failure instead of caching an empty result as clean.
266
+ throw new Error(`${langName} grammar threw: ${err instanceof Error ? err.message : String(err)}`);
267
+ }
268
+ if (!tree)
269
+ return { nodes, rawEdges };
270
+ const minted = new Set([rel]);
271
+ const lines = source.split("\n");
272
+ const defs = [];
273
+ // One definition per source span: a grammar's tags.scm can capture the same node
274
+ // under two @definition kinds (Swift `func` is method AND function), and the
275
+ // walker can revisit a nested match — both would emit near-duplicate nodes.
276
+ const spanSeen = new Set();
277
+ // Mint one definition node from a whole-definition tree node. Shared by both
278
+ // the tags.scm path and the walker fallback so id/span/signature/body_text are
279
+ // built identically.
280
+ const mkDef = (name, kind, whole) => {
281
+ if (spanSeen.has(whole.startIndex))
282
+ return;
283
+ spanSeen.add(whole.startIndex);
284
+ const idBase = `${rel}#${name}`;
285
+ let id = idBase, n = 2;
286
+ while (minted.has(id))
287
+ id = `${idBase}~${n++}`;
288
+ minted.add(id);
289
+ const startRow = whole.startPosition.row, endRow = whole.endPosition.row;
290
+ const sigLine = (lines[startRow] ?? "").trim().replace(/\s*\{?\s*$/, "");
291
+ nodes.push({
292
+ id, name, kind, path: rel,
293
+ span: `L${startRow + 1}-L${endRow + 1}`,
294
+ signature: sigLine || null, exported: true, origin: "generic",
295
+ body_hash: contentHash(source.slice(whole.startIndex, whole.endIndex)),
296
+ body_text: source.slice(whole.startIndex, whole.endIndex).replace(/\s+/g, " ").slice(0, 5000),
297
+ summary_state: "pending", summary: null, crux: null,
298
+ });
299
+ defs.push({ id, startIndex: whole.startIndex, endIndex: whole.endIndex });
300
+ };
301
+ if (entry.query) {
302
+ tagsExtract(entry.query, tree.rootNode, rel, mkDef, defs, rawEdges, langName);
303
+ }
304
+ else {
305
+ walkExtract(tree.rootNode, mkDef); // no tags.scm → symbols only
306
+ }
307
+ // The preprocessor is invisible to tags.scm, but in C/C++ a local `#include "x.h"`
308
+ // IS the dependency graph — capture it as a file→file import. Likewise a Rust
309
+ // `use crate::…` is an in-crate module dependency.
310
+ if (langName === "c" || langName === "cpp")
311
+ extractIncludes(tree.rootNode, rel, rawEdges);
312
+ else if (langName === "rust")
313
+ extractUses(tree.rootNode, rel, rawEdges);
314
+ else if (langName === "php")
315
+ extractPhpUses(tree.rootNode, rel, rawEdges);
316
+ else if (langName === "gleam")
317
+ extractGleamModules(tree.rootNode, rel, defs, rawEdges);
318
+ return { nodes, rawEdges };
319
+ }
320
+ /** PHP `use App\Models\User;` → a file→class-file `imports` raw edge, one per imported
321
+ * name (a `{ … }` group expands to several). `use function`/`use const` are skipped —
322
+ * those name a symbol, not a PSR-4 class file. resolve.ts settles the fully-qualified
323
+ * name to the in-repo file by namespace suffix, and drops it when it can't. */
324
+ function extractPhpUses(root, rel, rawEdges) {
325
+ const visit = (n) => {
326
+ if (n.type === "namespace_use_declaration") {
327
+ for (const fqn of phpUseNames(n.text))
328
+ rawEdges.push({ source: rel, relation: "imports", specifier: fqn, file: rel });
329
+ }
330
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
331
+ const c = n.namedChild?.(i);
332
+ if (c)
333
+ visit(c);
334
+ }
335
+ };
336
+ visit(root);
337
+ }
338
+ /** The fully-qualified class names a PHP `use` declaration imports. Handles a plain
339
+ * `use A\B\C;`, a comma list `use A\B, C\D;`, a group `use A\B\{C, D};`, and `as` aliases;
340
+ * returns [] for `use function`/`use const` (symbol imports, not class files). */
341
+ function phpUseNames(text) {
342
+ let s = text.replace(/^\s*use\s+/, "").replace(/;\s*$/, "").trim();
343
+ if (/^(function|const)\b/.test(s))
344
+ return [];
345
+ const brace = s.indexOf("{");
346
+ if (brace >= 0) {
347
+ const prefix = s.slice(0, brace).replace(/\\\s*$/, "");
348
+ const inner = s.slice(brace + 1, s.lastIndexOf("}"));
349
+ return inner.split(",").map((m) => m.trim().replace(/\s+as\s+\w+$/i, "").trim()).filter(Boolean)
350
+ .map((m) => `${prefix}\\${m}`);
351
+ }
352
+ return s.split(",").map((c) => c.trim().replace(/\s+as\s+\w+$/i, "").trim()).filter(Boolean);
353
+ }
354
+ /** Rust `use crate::a::b::Item` → a file→module `imports` raw edge whose specifier is the
355
+ * crate-relative module path (`a/b`). Only in-crate imports are captured; `std::`,
356
+ * `super::`, `self::`, external crates, and globs are skipped — resolve.ts settles the
357
+ * path against the file's crate root, and drops it when it can't. */
358
+ function extractUses(root, rel, rawEdges) {
359
+ const visit = (n) => {
360
+ if (n.type === "use_declaration") {
361
+ const spec = rustUseModule(n.text);
362
+ if (spec !== null)
363
+ rawEdges.push({ source: rel, relation: "imports", specifier: spec ? `crate/${spec}` : "crate", file: rel });
364
+ }
365
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
366
+ const c = n.namedChild?.(i);
367
+ if (c)
368
+ visit(c);
369
+ }
370
+ };
371
+ visit(root);
372
+ }
373
+ /** The crate-relative path a Rust `use crate::…` names (`::`→`/`), or null when it is not
374
+ * an in-crate import. The FULL path is returned — including any trailing item segment —
375
+ * because a single `crate::lexical` can be either a module OR a crate-root item; the
376
+ * resolver settles that by finding the longest prefix that is a real module file. A
377
+ * `{ … }` group has no single item, so its prefix (before `{`) is the path. */
378
+ function rustUseModule(text) {
379
+ let s = text.replace(/^\s*use\s+/, "").replace(/;\s*$/, "").trim();
380
+ const brace = s.indexOf("{");
381
+ if (brace >= 0)
382
+ s = s.slice(0, brace).replace(/::\s*$/, "");
383
+ else
384
+ s = s.replace(/\s+as\s+\w+$/, "");
385
+ s = s.trim();
386
+ if (s !== "crate" && !s.startsWith("crate::"))
387
+ return null; // only in-crate absolute imports
388
+ if (s.includes("*"))
389
+ return null; // glob — no single module target
390
+ return s.replace(/^crate::?/, "").replace(/\s+/g, "").replace(/::/g, "/"); // "" = crate root
391
+ }
392
+ /** C/C++ `#include "header.h"` → a file→file `imports` raw edge. Only LOCAL includes
393
+ * (quoted) are captured; system includes (`<stdio.h>`) are skipped — high volume, and
394
+ * there is no in-repo target to navigate to. resolve.ts settles the quoted path to an
395
+ * in-repo header (relative to the including file, else a unique path-suffix match), and
396
+ * keeps it as an external string when it cannot — never a guessed edge. */
397
+ function extractIncludes(root, rel, rawEdges) {
398
+ const visit = (n) => {
399
+ if (n.type === "preproc_include") {
400
+ const raw = n.childForFieldName?.("path")?.text ?? "";
401
+ if (raw.startsWith('"')) {
402
+ const spec = raw.replace(/^"|"$/g, "").trim();
403
+ if (spec)
404
+ rawEdges.push({ source: rel, relation: "imports", specifier: spec, file: rel });
405
+ }
406
+ }
407
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
408
+ const c = n.namedChild?.(i);
409
+ if (c)
410
+ visit(c);
411
+ }
412
+ };
413
+ visit(root);
414
+ }
415
+ /**
416
+ * Gleam's module system IS its dependency graph, and it is unusually exact: an
417
+ * `import app/thing` names one module file, every reference to another module
418
+ * goes through a qualifier that import binds (`thing.helper()`), and there is no
419
+ * ambient global scope for a name to arrive from. This pass reads that table and
420
+ * uses it for two things.
421
+ *
422
+ * First, a file→file `imports` raw edge per import, which resolve.ts settles
423
+ * against the repo's `.gleam` files (`app/thing` → `…/src/app/thing.gleam`).
424
+ *
425
+ * Second, precision on calls. tags.scm sees `list.map(…)` as the bare label
426
+ * `map`, and because EVERY stdlib call in Gleam is spelled that way, resolving
427
+ * those by name alone is a false-edge machine — `map`, `filter`, `try`, `new`
428
+ * and `to_string` all collide with in-repo functions. So qualified calls are
429
+ * emitted here instead, stamped with the module the qualifier names: resolve.ts
430
+ * then looks the label up in that one file, or drops the call when the module is
431
+ * out of repo (the stdlib, a hex dependency). Unqualified imports
432
+ * (`import app/thing.{helper}`, then a bare `helper()`) give the same two halves,
433
+ * so the bare edge tags.scm already emitted is upgraded in place.
434
+ *
435
+ * A function is as often piped into or handed over as it is called outright
436
+ * (`xs |> thing.helper`, `list.map(xs, thing.helper)`), and neither is a
437
+ * `function_call` node, so both are read here too: a pipe's right side is a
438
+ * call, a name passed as a value is a `references` edge.
439
+ */
440
+ function extractGleamModules(root, rel, defs, rawEdges) {
441
+ // `list` in `list.map(…)` → the module path it was bound to. The qualifier is
442
+ // the `as` alias when there is one, else the module path's last segment.
443
+ const byQualifier = new Map();
444
+ // `helper` from `import app/thing.{helper}` (or its `as` alias) → that module.
445
+ const byName = new Map();
446
+ for (let i = 0; i < (root.namedChildCount ?? 0); i++) {
447
+ const imp = root.namedChild?.(i);
448
+ if (imp?.type !== "import")
449
+ continue;
450
+ const mod = imp.childForFieldName?.("module")?.text;
451
+ if (!mod)
452
+ continue;
453
+ rawEdges.push({ source: rel, relation: "imports", specifier: mod, file: rel });
454
+ byQualifier.set(imp.childForFieldName?.("alias")?.text || mod.slice(mod.lastIndexOf("/") + 1), mod);
455
+ const unqualified = imp.childForFieldName?.("imports");
456
+ for (let j = 0; j < (unqualified?.namedChildCount ?? 0); j++) {
457
+ const u = unqualified?.namedChild?.(j);
458
+ if (u?.type !== "unqualified_import")
459
+ continue;
460
+ // `{ other as o }` binds `o`; `{ type Handler }` binds a type, harmless here.
461
+ const local = u.childForFieldName?.("alias")?.text ?? u.childForFieldName?.("name")?.text;
462
+ if (local)
463
+ byName.set(local, mod);
464
+ }
465
+ }
466
+ // This file's own functions, and the module path that names this file, so a
467
+ // name that can only be local resolves in this file alone.
468
+ const ownFns = new Set();
469
+ for (let i = 0; i < (root.namedChildCount ?? 0); i++) {
470
+ const fn = root.namedChild?.(i);
471
+ const name = fn?.type === "function" ? fn.childForFieldName?.("name")?.text : undefined;
472
+ if (name)
473
+ ownFns.add(name);
474
+ }
475
+ const ownModule = rel.replace(/\.gleam$/, "");
476
+ const ownNames = new Set(defs.map((d) => d.id.slice(rel.length + 1).replace(/~\d+$/, "")));
477
+ // A bare name in Gleam is this file's own definition, an unqualified import, or
478
+ // a local — there is nowhere else for it to come from. So every bare edge
479
+ // tags.scm emitted is pinned to the one module it can mean, and one that means
480
+ // neither (a parameter being called, a prelude `Ok` or `Int`) is dropped rather
481
+ // than left to match a same-named definition somewhere else in the repo.
482
+ for (let i = rawEdges.length - 1; i >= 0; i--) {
483
+ const e = rawEdges[i];
484
+ if ((e.relation !== "calls" && e.relation !== "references") || e.specifier || !e.name)
485
+ continue;
486
+ const mod = byName.get(e.name) ?? (ownNames.has(e.name) ? ownModule : undefined);
487
+ if (mod)
488
+ e.specifier = mod;
489
+ else
490
+ rawEdges.splice(i, 1);
491
+ }
492
+ // Every name a function binds — parameters, `let`, `use` and `case` patterns,
493
+ // at any depth. There is no scope analysis here, so a name bound ANYWHERE in
494
+ // the function is treated as a local throughout it. Coarser than real scoping,
495
+ // and only ever in the direction of dropping an edge.
496
+ const boundIn = (fn) => {
497
+ const bound = new Set();
498
+ const names = (n) => {
499
+ // `thing.Busy(x)` and `x: thing.State` spell a module, not a binding.
500
+ if (!n || n.type === "remote_constructor_name" || n.type === "remote_type_identifier")
501
+ return;
502
+ if (n.type === "identifier")
503
+ bound.add(n.text);
504
+ // `Busy(since:)` is shorthand for `Busy(since: since)` — the label binds.
505
+ if (n.type === "record_pattern_argument" && n.namedChildCount === 1 && n.namedChild?.(0)?.type === "label")
506
+ bound.add(n.namedChild(0).text);
507
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++)
508
+ names(n.namedChild?.(i));
509
+ };
510
+ const walk = (n) => {
511
+ if (n.type === "function_parameters" || n.type === "use_assignments" || n.type === "case_clause_patterns")
512
+ names(n);
513
+ else if (n.type === "let" || n.type === "let_assert")
514
+ names(n.childForFieldName?.("pattern"));
515
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
516
+ const c = n.namedChild?.(i);
517
+ if (c)
518
+ walk(c);
519
+ }
520
+ };
521
+ walk(fn);
522
+ return bound;
523
+ };
524
+ const same = (a, b) => !!a && a.startIndex === b.startIndex && a.endIndex === b.endIndex;
525
+ // `xs |> thing.helper` — the right of a pipe is applied, with or without `()`.
526
+ const piped = (n, parent) => parent?.type === "binary_expression" &&
527
+ parent.childForFieldName?.("operator")?.type === "|>" &&
528
+ same(parent.childForFieldName?.("right"), n);
529
+ // Where a bare name is a value being handed on rather than a binding or a call.
530
+ const passed = (n, parent) => parent?.type === "argument" || parent?.type === "list" || parent?.type === "tuple" ||
531
+ ((parent?.type === "let" || parent?.type === "let_assert") && same(parent.childForFieldName?.("value"), n));
532
+ const NONE = new Set();
533
+ // The ways a Gleam file names something in another module. All carry the
534
+ // qualifier, so all get scoped to one file rather than guessed by name.
535
+ const emit = (qualifier, name, relation, locals = NONE) => {
536
+ // Only a bare identifier can be a module qualifier. `field_access` is also how
537
+ // the grammar spells record access, so `cfg.handler.run()` is a field chain,
538
+ // and a qualifier no import bound is a record field holding a function.
539
+ // Neither names a module, and neither gets a guessed edge.
540
+ const mod = qualifier?.type === "identifier" && name && !locals.has(qualifier.text) ? byQualifier.get(qualifier.text) : undefined;
541
+ if (!mod || !name)
542
+ return;
543
+ const enc = enclosingDef(defs, name.startIndex);
544
+ if (relation === "references" && !enc)
545
+ return; // no sound source to hang it on
546
+ rawEdges.push({ source: enc ? enc.id : rel, relation, file: rel, name: name.text, specifier: mod });
547
+ };
548
+ const visit = (n, parent, bound) => {
549
+ if (n.type === "function")
550
+ bound = boundIn(n);
551
+ if (n.type === "function_call") {
552
+ // `list.map(…)` — a remote function call.
553
+ const fn = n.childForFieldName?.("function");
554
+ if (fn?.type === "field_access")
555
+ emit(fn.childForFieldName?.("record") ?? null, fn.childForFieldName?.("field") ?? null, "calls");
556
+ }
557
+ else if (n.type === "field_access") {
558
+ // `thing.helper` with no call around it: applied when it sits on the right
559
+ // of a pipe, otherwise named as a value — a callback (`list.map(xs,
560
+ // thing.helper)`) or a constant (`thing.limit`). Either way the module's
561
+ // symbol is in use, and without the edge it reads as dead code.
562
+ //
563
+ // A local may share the module's name (`fn show(user: User)` under `import
564
+ // app/user`), and Gleam then reads `user.x` as the record's field first and
565
+ // the module's `x` only if there is no such field. Applied, that is nearly
566
+ // always the module (`user.to_string(user)`), so calls keep their edge; read
567
+ // as a value it is nearly always the field (`user.name`), so that is dropped.
568
+ if (!(parent?.type === "function_call" && same(parent.childForFieldName?.("function"), n))) {
569
+ const record = n.childForFieldName?.("record") ?? null;
570
+ const field = n.childForFieldName?.("field") ?? null;
571
+ if (piped(n, parent))
572
+ emit(record, field, "calls");
573
+ else
574
+ emit(record, field, "references", bound);
575
+ }
576
+ }
577
+ else if (n.type === "identifier" && !bound.has(n.text)) {
578
+ // The same two shapes for a bare name, which is only ever this file's own
579
+ // function or an unqualified import — anything a local could be is dropped.
580
+ const enc = enclosingDef(defs, n.startIndex);
581
+ const mod = byName.get(n.text) ?? (ownFns.has(n.text) ? ownModule : undefined);
582
+ if (!mod || !enc || enc.id === `${rel}#${n.text}`) {
583
+ // not a function this file can name, or the function naming itself
584
+ }
585
+ else if (piped(n, parent)) {
586
+ rawEdges.push({ source: enc.id, relation: "calls", file: rel, name: n.text, specifier: mod });
587
+ }
588
+ else if (passed(n, parent)) {
589
+ rawEdges.push({ source: enc.id, relation: "references", file: rel, name: n.text, specifier: mod });
590
+ }
591
+ }
592
+ else if (n.type === "remote_constructor_name") {
593
+ // `thing.Busy(since: 1)`, a record update, or a `case` pattern — all apply
594
+ // or take apart the same callable, the way the local forms do in tags.scm.
595
+ emit(n.childForFieldName?.("module") ?? null, n.childForFieldName?.("name") ?? null, "calls");
596
+ }
597
+ else if (n.type === "remote_type_identifier") {
598
+ // `thing.State` in an annotation — names the type without calling it.
599
+ emit(n.childForFieldName?.("module") ?? null, n.childForFieldName?.("name") ?? null, "references");
600
+ }
601
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
602
+ const c = n.namedChild?.(i);
603
+ if (c)
604
+ visit(c, n, bound);
605
+ }
606
+ };
607
+ visit(root, null, NONE);
608
+ }
609
+ /** tags.scm path: @definition.<kind> → nodes, @reference.call/@reference.send →
610
+ * bare-name call edges attributed to the innermost enclosing definition. */
611
+ function tagsExtract(query, root, rel, mkDef, defs, rawEdges, langName) {
612
+ const q = query;
613
+ const matches = q.matches(root);
614
+ // Some grammars' tags.scm capture a definition's own NAME token as a
615
+ // @reference.call too (Ruby tags `def foo`'s `foo` as both @name and a call),
616
+ // producing bogus self-loops (foo→foo). Skip any call at a definition's name token.
617
+ const defNameAt = new Set();
618
+ const calls = [];
619
+ const refs = [];
620
+ for (const m of matches) {
621
+ const cap = {};
622
+ for (const c of m.captures)
623
+ cap[c.name] = c.node;
624
+ const defKey = Object.keys(cap).find((k) => k.startsWith("definition."));
625
+ if (defKey && cap.name) {
626
+ defNameAt.add(cap.name.startIndex);
627
+ mkDef(cap.name.text, KIND[defKey.slice("definition.".length)] ?? "function", defScope(cap[defKey], langName));
628
+ }
629
+ if (("reference.call" in cap || "reference.send" in cap) && cap.name)
630
+ calls.push({ name: cap.name.text, at: cap.name.startIndex });
631
+ // Structural references the grammar already marks: a supertype (extends), an
632
+ // implemented interface, an object creation (`new Foo`), a module alias. Grammars
633
+ // label these @reference.class/.interface/.implementation/.module — heterogeneous
634
+ // syntactically but all "names this symbol without calling it". They become
635
+ // `references` edges the same precision-first resolver settles to a type-like def
636
+ // (same-file certain, unique cross-file inferred, ambiguous dropped), so a data
637
+ // class that's only ever extended or instantiated stops being an orphan.
638
+ if (("reference.class" in cap || "reference.interface" in cap ||
639
+ "reference.implementation" in cap || "reference.module" in cap) && cap.name)
640
+ refs.push({ name: cap.name.text, at: cap.name.startIndex });
641
+ }
642
+ for (const c of calls) {
643
+ if (defNameAt.has(c.at))
644
+ continue;
645
+ const enc = enclosingDef(defs, c.at);
646
+ rawEdges.push({ source: enc ? enc.id : rel, relation: "calls", file: rel, name: c.name });
647
+ }
648
+ for (const r of refs) {
649
+ if (defNameAt.has(r.at))
650
+ continue;
651
+ const enc = enclosingDef(defs, r.at);
652
+ if (!enc)
653
+ continue; // a reference with no enclosing definition has no sound source
654
+ rawEdges.push({ source: enc.id, relation: "references", file: rel, name: r.name });
655
+ }
656
+ }
657
+ // Node-type → Kind for the walker fallback. A node is a definition when its type
658
+ // ends with a declaration-ish suffix AND names a construct — matched most-specific
659
+ // first (method before function). Covers the common tree-sitter grammar vocab
660
+ // without any per-language query.
661
+ const DEF_SUFFIX = /(declaration|definition|_item|_specifier|_decl|_def|_binding)$/;
662
+ function classifyKind(type) {
663
+ const t = type.toLowerCase();
664
+ if (!DEF_SUFFIX.test(t) && !/^(class|struct|enum|interface|trait|module|namespace)/.test(t))
665
+ return null;
666
+ if (/method|constructor/.test(t))
667
+ return "method";
668
+ if (/func|function|def\b|subroutine|procedure/.test(t))
669
+ return "function";
670
+ if (/class/.test(t))
671
+ return "class";
672
+ if (/struct|record/.test(t))
673
+ return "struct";
674
+ if (/interface|trait|protocol/.test(t))
675
+ return "interface";
676
+ if (/enum/.test(t))
677
+ return "enum";
678
+ if (/module|namespace|package|mod_/.test(t))
679
+ return "module";
680
+ if (/const/.test(t))
681
+ return "constant";
682
+ if (/typedef|type_alias|type_def|alias/.test(t))
683
+ return "type";
684
+ if (/type/.test(t))
685
+ return "type";
686
+ if (/(^|_)(val|var|let|field|property)/.test(t))
687
+ return "variable";
688
+ return null;
689
+ }
690
+ /** The declared name of a node: its `name` field, else the first identifier-ish
691
+ * descendant within a couple of levels. */
692
+ function nodeName(node) {
693
+ const byField = node.childForFieldName?.("name");
694
+ if (byField?.text)
695
+ return byField.text;
696
+ const stack = [{ n: node, d: 0 }];
697
+ while (stack.length) {
698
+ const { n, d } = stack.shift();
699
+ if (d > 0 && /identifier|name/.test(n.type) && n.text && !n.text.includes("\n"))
700
+ return n.text;
701
+ if (d < 3)
702
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
703
+ const c = n.namedChild?.(i);
704
+ if (c)
705
+ stack.push({ n: c, d: d + 1 });
706
+ }
707
+ }
708
+ return null;
709
+ }
710
+ /** Walker fallback: DFS every named node, emit a def for each classified one
711
+ * (symbols only — no call resolution without a query). */
712
+ function walkExtract(root, mkDef) {
713
+ const visit = (n) => {
714
+ const kind = classifyKind(n.type);
715
+ if (kind) {
716
+ const name = nodeName(n);
717
+ if (name)
718
+ mkDef(name, kind, n);
719
+ }
720
+ for (let i = 0; i < (n.namedChildCount ?? 0); i++) {
721
+ const c = n.namedChild?.(i);
722
+ if (c)
723
+ visit(c);
724
+ }
725
+ };
726
+ visit(root);
727
+ }
728
+ // Some grammars' tags.scm put @definition.<X> on a narrow node (C tags the
729
+ // `function_declarator`, not the whole `function_definition` with its body), so
730
+ // the capture's span stops before the body and calls inside it can't be
731
+ // attributed to the function. Expand up to the outermost enclosing
732
+ // declaration/definition node so a def's span covers its body.
733
+ const DEF_CONTAINER = /(definition|declaration|specifier|_item)$/;
734
+ function nextNamedSibling(n) {
735
+ const tagged = n;
736
+ if ("nextNamedSibling" in tagged)
737
+ return tagged.nextNamedSibling ?? null;
738
+ const p = n.parent;
739
+ if (!p?.namedChild)
740
+ return null;
741
+ const count = p.namedChildCount ?? 0;
742
+ for (let i = 0; i < count - 1; i++) {
743
+ const c = p.namedChild(i);
744
+ if (c && c.startIndex === n.startIndex && c.endIndex === n.endIndex)
745
+ return p.namedChild(i + 1);
746
+ }
747
+ return null;
748
+ }
749
+ function defScope(node, langName) {
750
+ let n = node;
751
+ while (n.parent && DEF_CONTAINER.test(n.parent.type))
752
+ n = n.parent;
753
+ // Dart's grammar leaves `function_signature` / `method_signature` as a sibling
754
+ // of `function_body` (no wrapping function_definition). Expand so a def's span
755
+ // covers its body and calls inside it attribute to the function, not the file
756
+ // or enclosing class. Gated on Dart so other breadth-tier languages are untouched.
757
+ if (langName === "dart") {
758
+ const body = nextNamedSibling(n);
759
+ if (body?.type === "function_body") {
760
+ return {
761
+ type: n.type,
762
+ text: n.text,
763
+ startIndex: n.startIndex,
764
+ endIndex: body.endIndex,
765
+ startPosition: n.startPosition,
766
+ endPosition: body.endPosition,
767
+ parent: n.parent,
768
+ };
769
+ }
770
+ }
771
+ return n;
772
+ }
773
+ //# sourceMappingURL=generic.js.map