@vizalice/codegraph 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (821) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +872 -0
  3. package/dist/bin/codegraph.d.ts +26 -0
  4. package/dist/bin/codegraph.d.ts.map +1 -0
  5. package/dist/bin/codegraph.js +2324 -0
  6. package/dist/bin/codegraph.js.map +1 -0
  7. package/dist/bin/command-supervision.d.ts +49 -0
  8. package/dist/bin/command-supervision.d.ts.map +1 -0
  9. package/dist/bin/command-supervision.js +95 -0
  10. package/dist/bin/command-supervision.js.map +1 -0
  11. package/dist/bin/fatal-handler.d.ts +20 -0
  12. package/dist/bin/fatal-handler.d.ts.map +1 -0
  13. package/dist/bin/fatal-handler.js +118 -0
  14. package/dist/bin/fatal-handler.js.map +1 -0
  15. package/dist/bin/node-version-check.d.ts +37 -0
  16. package/dist/bin/node-version-check.d.ts.map +1 -0
  17. package/dist/bin/node-version-check.js +79 -0
  18. package/dist/bin/node-version-check.js.map +1 -0
  19. package/dist/bin/uninstall.d.ts +14 -0
  20. package/dist/bin/uninstall.d.ts.map +1 -0
  21. package/dist/bin/uninstall.js +36 -0
  22. package/dist/bin/uninstall.js.map +1 -0
  23. package/dist/context/formatter.d.ts +36 -0
  24. package/dist/context/formatter.d.ts.map +1 -0
  25. package/dist/context/formatter.js +269 -0
  26. package/dist/context/formatter.js.map +1 -0
  27. package/dist/context/index.d.ts +119 -0
  28. package/dist/context/index.d.ts.map +1 -0
  29. package/dist/context/index.js +1333 -0
  30. package/dist/context/index.js.map +1 -0
  31. package/dist/context/markers.d.ts +19 -0
  32. package/dist/context/markers.d.ts.map +1 -0
  33. package/dist/context/markers.js +22 -0
  34. package/dist/context/markers.js.map +1 -0
  35. package/dist/db/index.d.ts +378 -0
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +831 -0
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/db/migrations.d.ts +44 -0
  40. package/dist/db/migrations.d.ts.map +1 -0
  41. package/dist/db/migrations.js +236 -0
  42. package/dist/db/migrations.js.map +1 -0
  43. package/dist/db/queries.d.ts +705 -0
  44. package/dist/db/queries.d.ts.map +1 -0
  45. package/dist/db/queries.js +2435 -0
  46. package/dist/db/queries.js.map +1 -0
  47. package/dist/db/schema.sql +207 -0
  48. package/dist/db/sqlite-adapter.d.ts +55 -0
  49. package/dist/db/sqlite-adapter.d.ts.map +1 -0
  50. package/dist/db/sqlite-adapter.js +135 -0
  51. package/dist/db/sqlite-adapter.js.map +1 -0
  52. package/dist/db/wal-valve.d.ts +119 -0
  53. package/dist/db/wal-valve.d.ts.map +1 -0
  54. package/dist/db/wal-valve.js +290 -0
  55. package/dist/db/wal-valve.js.map +1 -0
  56. package/dist/directory.d.ts +183 -0
  57. package/dist/directory.d.ts.map +1 -0
  58. package/dist/directory.js +797 -0
  59. package/dist/directory.js.map +1 -0
  60. package/dist/errors.d.ts +136 -0
  61. package/dist/errors.d.ts.map +1 -0
  62. package/dist/errors.js +219 -0
  63. package/dist/errors.js.map +1 -0
  64. package/dist/extraction/astro-extractor.d.ts +79 -0
  65. package/dist/extraction/astro-extractor.d.ts.map +1 -0
  66. package/dist/extraction/astro-extractor.js +320 -0
  67. package/dist/extraction/astro-extractor.js.map +1 -0
  68. package/dist/extraction/cfml-extractor.d.ts +107 -0
  69. package/dist/extraction/cfml-extractor.d.ts.map +1 -0
  70. package/dist/extraction/cfml-extractor.js +494 -0
  71. package/dist/extraction/cfml-extractor.js.map +1 -0
  72. package/dist/extraction/dfm-extractor.d.ts +31 -0
  73. package/dist/extraction/dfm-extractor.d.ts.map +1 -0
  74. package/dist/extraction/dfm-extractor.js +151 -0
  75. package/dist/extraction/dfm-extractor.js.map +1 -0
  76. package/dist/extraction/extraction-version.d.ts +25 -0
  77. package/dist/extraction/extraction-version.d.ts.map +1 -0
  78. package/dist/extraction/extraction-version.js +28 -0
  79. package/dist/extraction/extraction-version.js.map +1 -0
  80. package/dist/extraction/function-ref.d.ts +118 -0
  81. package/dist/extraction/function-ref.d.ts.map +1 -0
  82. package/dist/extraction/function-ref.js +733 -0
  83. package/dist/extraction/function-ref.js.map +1 -0
  84. package/dist/extraction/generated-detection.d.ts +66 -0
  85. package/dist/extraction/generated-detection.d.ts.map +1 -0
  86. package/dist/extraction/generated-detection.js +248 -0
  87. package/dist/extraction/generated-detection.js.map +1 -0
  88. package/dist/extraction/grammars.d.ts +138 -0
  89. package/dist/extraction/grammars.d.ts.map +1 -0
  90. package/dist/extraction/grammars.js +694 -0
  91. package/dist/extraction/grammars.js.map +1 -0
  92. package/dist/extraction/index.d.ts +308 -0
  93. package/dist/extraction/index.d.ts.map +1 -0
  94. package/dist/extraction/index.js +2711 -0
  95. package/dist/extraction/index.js.map +1 -0
  96. package/dist/extraction/kernel/decode.d.ts +9 -0
  97. package/dist/extraction/kernel/decode.d.ts.map +1 -0
  98. package/dist/extraction/kernel/decode.js +162 -0
  99. package/dist/extraction/kernel/decode.js.map +1 -0
  100. package/dist/extraction/kernel/index.d.ts +64 -0
  101. package/dist/extraction/kernel/index.d.ts.map +1 -0
  102. package/dist/extraction/kernel/index.js +279 -0
  103. package/dist/extraction/kernel/index.js.map +1 -0
  104. package/dist/extraction/kernel/layout.d.ts +101 -0
  105. package/dist/extraction/kernel/layout.d.ts.map +1 -0
  106. package/dist/extraction/kernel/layout.js +104 -0
  107. package/dist/extraction/kernel/layout.js.map +1 -0
  108. package/dist/extraction/kernel/loader.d.ts +103 -0
  109. package/dist/extraction/kernel/loader.d.ts.map +1 -0
  110. package/dist/extraction/kernel/loader.js +146 -0
  111. package/dist/extraction/kernel/loader.js.map +1 -0
  112. package/dist/extraction/languages/arkts.d.ts +3 -0
  113. package/dist/extraction/languages/arkts.d.ts.map +1 -0
  114. package/dist/extraction/languages/arkts.js +127 -0
  115. package/dist/extraction/languages/arkts.js.map +1 -0
  116. package/dist/extraction/languages/c-cpp.d.ts +124 -0
  117. package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
  118. package/dist/extraction/languages/c-cpp.js +1689 -0
  119. package/dist/extraction/languages/c-cpp.js.map +1 -0
  120. package/dist/extraction/languages/cfquery.d.ts +12 -0
  121. package/dist/extraction/languages/cfquery.d.ts.map +1 -0
  122. package/dist/extraction/languages/cfquery.js +28 -0
  123. package/dist/extraction/languages/cfquery.js.map +1 -0
  124. package/dist/extraction/languages/cfscript.d.ts +3 -0
  125. package/dist/extraction/languages/cfscript.d.ts.map +1 -0
  126. package/dist/extraction/languages/cfscript.js +73 -0
  127. package/dist/extraction/languages/cfscript.js.map +1 -0
  128. package/dist/extraction/languages/cobol.d.ts +33 -0
  129. package/dist/extraction/languages/cobol.d.ts.map +1 -0
  130. package/dist/extraction/languages/cobol.js +499 -0
  131. package/dist/extraction/languages/cobol.js.map +1 -0
  132. package/dist/extraction/languages/csharp.d.ts +25 -0
  133. package/dist/extraction/languages/csharp.d.ts.map +1 -0
  134. package/dist/extraction/languages/csharp.js +175 -0
  135. package/dist/extraction/languages/csharp.js.map +1 -0
  136. package/dist/extraction/languages/dart.d.ts +3 -0
  137. package/dist/extraction/languages/dart.d.ts.map +1 -0
  138. package/dist/extraction/languages/dart.js +374 -0
  139. package/dist/extraction/languages/dart.js.map +1 -0
  140. package/dist/extraction/languages/erlang.d.ts +3 -0
  141. package/dist/extraction/languages/erlang.d.ts.map +1 -0
  142. package/dist/extraction/languages/erlang.js +350 -0
  143. package/dist/extraction/languages/erlang.js.map +1 -0
  144. package/dist/extraction/languages/go.d.ts +3 -0
  145. package/dist/extraction/languages/go.d.ts.map +1 -0
  146. package/dist/extraction/languages/go.js +111 -0
  147. package/dist/extraction/languages/go.js.map +1 -0
  148. package/dist/extraction/languages/index.d.ts +10 -0
  149. package/dist/extraction/languages/index.d.ts.map +1 -0
  150. package/dist/extraction/languages/index.js +71 -0
  151. package/dist/extraction/languages/index.js.map +1 -0
  152. package/dist/extraction/languages/java.d.ts +3 -0
  153. package/dist/extraction/languages/java.d.ts.map +1 -0
  154. package/dist/extraction/languages/java.js +315 -0
  155. package/dist/extraction/languages/java.js.map +1 -0
  156. package/dist/extraction/languages/javascript.d.ts +3 -0
  157. package/dist/extraction/languages/javascript.d.ts.map +1 -0
  158. package/dist/extraction/languages/javascript.js +106 -0
  159. package/dist/extraction/languages/javascript.js.map +1 -0
  160. package/dist/extraction/languages/kotlin.d.ts +3 -0
  161. package/dist/extraction/languages/kotlin.d.ts.map +1 -0
  162. package/dist/extraction/languages/kotlin.js +379 -0
  163. package/dist/extraction/languages/kotlin.js.map +1 -0
  164. package/dist/extraction/languages/lua.d.ts +3 -0
  165. package/dist/extraction/languages/lua.d.ts.map +1 -0
  166. package/dist/extraction/languages/lua.js +150 -0
  167. package/dist/extraction/languages/lua.js.map +1 -0
  168. package/dist/extraction/languages/luau.d.ts +3 -0
  169. package/dist/extraction/languages/luau.d.ts.map +1 -0
  170. package/dist/extraction/languages/luau.js +37 -0
  171. package/dist/extraction/languages/luau.js.map +1 -0
  172. package/dist/extraction/languages/nix.d.ts +3 -0
  173. package/dist/extraction/languages/nix.d.ts.map +1 -0
  174. package/dist/extraction/languages/nix.js +294 -0
  175. package/dist/extraction/languages/nix.js.map +1 -0
  176. package/dist/extraction/languages/objc.d.ts +3 -0
  177. package/dist/extraction/languages/objc.d.ts.map +1 -0
  178. package/dist/extraction/languages/objc.js +179 -0
  179. package/dist/extraction/languages/objc.js.map +1 -0
  180. package/dist/extraction/languages/pascal.d.ts +3 -0
  181. package/dist/extraction/languages/pascal.d.ts.map +1 -0
  182. package/dist/extraction/languages/pascal.js +77 -0
  183. package/dist/extraction/languages/pascal.js.map +1 -0
  184. package/dist/extraction/languages/php.d.ts +3 -0
  185. package/dist/extraction/languages/php.d.ts.map +1 -0
  186. package/dist/extraction/languages/php.js +196 -0
  187. package/dist/extraction/languages/php.js.map +1 -0
  188. package/dist/extraction/languages/python.d.ts +3 -0
  189. package/dist/extraction/languages/python.d.ts.map +1 -0
  190. package/dist/extraction/languages/python.js +56 -0
  191. package/dist/extraction/languages/python.js.map +1 -0
  192. package/dist/extraction/languages/r.d.ts +3 -0
  193. package/dist/extraction/languages/r.d.ts.map +1 -0
  194. package/dist/extraction/languages/r.js +314 -0
  195. package/dist/extraction/languages/r.js.map +1 -0
  196. package/dist/extraction/languages/ruby.d.ts +3 -0
  197. package/dist/extraction/languages/ruby.d.ts.map +1 -0
  198. package/dist/extraction/languages/ruby.js +149 -0
  199. package/dist/extraction/languages/ruby.js.map +1 -0
  200. package/dist/extraction/languages/rust.d.ts +3 -0
  201. package/dist/extraction/languages/rust.d.ts.map +1 -0
  202. package/dist/extraction/languages/rust.js +145 -0
  203. package/dist/extraction/languages/rust.js.map +1 -0
  204. package/dist/extraction/languages/scala.d.ts +3 -0
  205. package/dist/extraction/languages/scala.d.ts.map +1 -0
  206. package/dist/extraction/languages/scala.js +209 -0
  207. package/dist/extraction/languages/scala.js.map +1 -0
  208. package/dist/extraction/languages/solidity.d.ts +3 -0
  209. package/dist/extraction/languages/solidity.d.ts.map +1 -0
  210. package/dist/extraction/languages/solidity.js +293 -0
  211. package/dist/extraction/languages/solidity.js.map +1 -0
  212. package/dist/extraction/languages/swift.d.ts +3 -0
  213. package/dist/extraction/languages/swift.d.ts.map +1 -0
  214. package/dist/extraction/languages/swift.js +152 -0
  215. package/dist/extraction/languages/swift.js.map +1 -0
  216. package/dist/extraction/languages/terraform.d.ts +3 -0
  217. package/dist/extraction/languages/terraform.d.ts.map +1 -0
  218. package/dist/extraction/languages/terraform.js +641 -0
  219. package/dist/extraction/languages/terraform.js.map +1 -0
  220. package/dist/extraction/languages/typescript.d.ts +16 -0
  221. package/dist/extraction/languages/typescript.d.ts.map +1 -0
  222. package/dist/extraction/languages/typescript.js +167 -0
  223. package/dist/extraction/languages/typescript.js.map +1 -0
  224. package/dist/extraction/languages/vbnet.d.ts +11 -0
  225. package/dist/extraction/languages/vbnet.d.ts.map +1 -0
  226. package/dist/extraction/languages/vbnet.js +141 -0
  227. package/dist/extraction/languages/vbnet.js.map +1 -0
  228. package/dist/extraction/liquid-extractor.d.ts +59 -0
  229. package/dist/extraction/liquid-extractor.d.ts.map +1 -0
  230. package/dist/extraction/liquid-extractor.js +357 -0
  231. package/dist/extraction/liquid-extractor.js.map +1 -0
  232. package/dist/extraction/mybatis-extractor.d.ts +68 -0
  233. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  234. package/dist/extraction/mybatis-extractor.js +300 -0
  235. package/dist/extraction/mybatis-extractor.js.map +1 -0
  236. package/dist/extraction/parse-pool.d.ts +160 -0
  237. package/dist/extraction/parse-pool.d.ts.map +1 -0
  238. package/dist/extraction/parse-pool.js +402 -0
  239. package/dist/extraction/parse-pool.js.map +1 -0
  240. package/dist/extraction/parse-worker.d.ts +8 -0
  241. package/dist/extraction/parse-worker.d.ts.map +1 -0
  242. package/dist/extraction/parse-worker.js +138 -0
  243. package/dist/extraction/parse-worker.js.map +1 -0
  244. package/dist/extraction/razor-extractor.d.ts +42 -0
  245. package/dist/extraction/razor-extractor.d.ts.map +1 -0
  246. package/dist/extraction/razor-extractor.js +285 -0
  247. package/dist/extraction/razor-extractor.js.map +1 -0
  248. package/dist/extraction/store-worker.d.ts +24 -0
  249. package/dist/extraction/store-worker.d.ts.map +1 -0
  250. package/dist/extraction/store-worker.js +139 -0
  251. package/dist/extraction/store-worker.js.map +1 -0
  252. package/dist/extraction/store-writer.d.ts +63 -0
  253. package/dist/extraction/store-writer.d.ts.map +1 -0
  254. package/dist/extraction/store-writer.js +174 -0
  255. package/dist/extraction/store-writer.js.map +1 -0
  256. package/dist/extraction/svelte-extractor.d.ts +56 -0
  257. package/dist/extraction/svelte-extractor.d.ts.map +1 -0
  258. package/dist/extraction/svelte-extractor.js +275 -0
  259. package/dist/extraction/svelte-extractor.js.map +1 -0
  260. package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
  261. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
  262. package/dist/extraction/tree-sitter-helpers.js +153 -0
  263. package/dist/extraction/tree-sitter-helpers.js.map +1 -0
  264. package/dist/extraction/tree-sitter-types.d.ts +260 -0
  265. package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
  266. package/dist/extraction/tree-sitter-types.js +10 -0
  267. package/dist/extraction/tree-sitter-types.js.map +1 -0
  268. package/dist/extraction/tree-sitter.d.ts +728 -0
  269. package/dist/extraction/tree-sitter.d.ts.map +1 -0
  270. package/dist/extraction/tree-sitter.js +6676 -0
  271. package/dist/extraction/tree-sitter.js.map +1 -0
  272. package/dist/extraction/vue-extractor.d.ts +51 -0
  273. package/dist/extraction/vue-extractor.d.ts.map +1 -0
  274. package/dist/extraction/vue-extractor.js +254 -0
  275. package/dist/extraction/vue-extractor.js.map +1 -0
  276. package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
  277. package/dist/extraction/wasm/tree-sitter-c.wasm +0 -0
  278. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  279. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  280. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  281. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  282. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  283. package/dist/extraction/wasm/tree-sitter-cpp.wasm +0 -0
  284. package/dist/extraction/wasm/tree-sitter-dart.wasm +0 -0
  285. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  286. package/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
  287. package/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
  288. package/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
  289. package/dist/extraction/wasm/tree-sitter-kotlin.wasm +0 -0
  290. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  291. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  292. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  293. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  294. package/dist/extraction/wasm/tree-sitter-php.wasm +0 -0
  295. package/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
  296. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  297. package/dist/extraction/wasm/tree-sitter-ruby.wasm +0 -0
  298. package/dist/extraction/wasm/tree-sitter-rust.wasm +0 -0
  299. package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  300. package/dist/extraction/wasm/tree-sitter-swift.wasm +0 -0
  301. package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
  302. package/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
  303. package/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
  304. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  305. package/dist/extraction/wasm-runtime-flags.d.ts +53 -0
  306. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  307. package/dist/extraction/wasm-runtime-flags.js +130 -0
  308. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  309. package/dist/graph/index.d.ts +8 -0
  310. package/dist/graph/index.d.ts.map +1 -0
  311. package/dist/graph/index.js +13 -0
  312. package/dist/graph/index.js.map +1 -0
  313. package/dist/graph/queries.d.ts +106 -0
  314. package/dist/graph/queries.d.ts.map +1 -0
  315. package/dist/graph/queries.js +341 -0
  316. package/dist/graph/queries.js.map +1 -0
  317. package/dist/graph/traversal.d.ts +127 -0
  318. package/dist/graph/traversal.d.ts.map +1 -0
  319. package/dist/graph/traversal.js +599 -0
  320. package/dist/graph/traversal.js.map +1 -0
  321. package/dist/index.d.ts +677 -0
  322. package/dist/index.d.ts.map +1 -0
  323. package/dist/index.js +1718 -0
  324. package/dist/index.js.map +1 -0
  325. package/dist/installer/beta-signup.d.ts +54 -0
  326. package/dist/installer/beta-signup.d.ts.map +1 -0
  327. package/dist/installer/beta-signup.js +178 -0
  328. package/dist/installer/beta-signup.js.map +1 -0
  329. package/dist/installer/config-writer.d.ts +28 -0
  330. package/dist/installer/config-writer.d.ts.map +1 -0
  331. package/dist/installer/config-writer.js +91 -0
  332. package/dist/installer/config-writer.js.map +1 -0
  333. package/dist/installer/index.d.ts +144 -0
  334. package/dist/installer/index.d.ts.map +1 -0
  335. package/dist/installer/index.js +634 -0
  336. package/dist/installer/index.js.map +1 -0
  337. package/dist/installer/instructions-template.d.ts +41 -0
  338. package/dist/installer/instructions-template.d.ts.map +1 -0
  339. package/dist/installer/instructions-template.js +53 -0
  340. package/dist/installer/instructions-template.js.map +1 -0
  341. package/dist/installer/targets/antigravity.d.ts +57 -0
  342. package/dist/installer/targets/antigravity.d.ts.map +1 -0
  343. package/dist/installer/targets/antigravity.js +308 -0
  344. package/dist/installer/targets/antigravity.js.map +1 -0
  345. package/dist/installer/targets/claude.d.ts +62 -0
  346. package/dist/installer/targets/claude.d.ts.map +1 -0
  347. package/dist/installer/targets/claude.js +486 -0
  348. package/dist/installer/targets/claude.js.map +1 -0
  349. package/dist/installer/targets/codex.d.ts +18 -0
  350. package/dist/installer/targets/codex.d.ts.map +1 -0
  351. package/dist/installer/targets/codex.js +185 -0
  352. package/dist/installer/targets/codex.js.map +1 -0
  353. package/dist/installer/targets/copilot-cli.d.ts +32 -0
  354. package/dist/installer/targets/copilot-cli.d.ts.map +1 -0
  355. package/dist/installer/targets/copilot-cli.js +209 -0
  356. package/dist/installer/targets/copilot-cli.js.map +1 -0
  357. package/dist/installer/targets/copilot-jetbrains.d.ts +42 -0
  358. package/dist/installer/targets/copilot-jetbrains.d.ts.map +1 -0
  359. package/dist/installer/targets/copilot-jetbrains.js +238 -0
  360. package/dist/installer/targets/copilot-jetbrains.js.map +1 -0
  361. package/dist/installer/targets/copilot-vscode.d.ts +47 -0
  362. package/dist/installer/targets/copilot-vscode.d.ts.map +1 -0
  363. package/dist/installer/targets/copilot-vscode.js +219 -0
  364. package/dist/installer/targets/copilot-vscode.js.map +1 -0
  365. package/dist/installer/targets/cursor.d.ts +35 -0
  366. package/dist/installer/targets/cursor.d.ts.map +1 -0
  367. package/dist/installer/targets/cursor.js +254 -0
  368. package/dist/installer/targets/cursor.js.map +1 -0
  369. package/dist/installer/targets/dsh.d.ts +97 -0
  370. package/dist/installer/targets/dsh.d.ts.map +1 -0
  371. package/dist/installer/targets/dsh.js +358 -0
  372. package/dist/installer/targets/dsh.js.map +1 -0
  373. package/dist/installer/targets/gemini.d.ts +26 -0
  374. package/dist/installer/targets/gemini.d.ts.map +1 -0
  375. package/dist/installer/targets/gemini.js +165 -0
  376. package/dist/installer/targets/gemini.js.map +1 -0
  377. package/dist/installer/targets/hermes.d.ts +18 -0
  378. package/dist/installer/targets/hermes.d.ts.map +1 -0
  379. package/dist/installer/targets/hermes.js +359 -0
  380. package/dist/installer/targets/hermes.js.map +1 -0
  381. package/dist/installer/targets/kiro.d.ts +27 -0
  382. package/dist/installer/targets/kiro.d.ts.map +1 -0
  383. package/dist/installer/targets/kiro.js +178 -0
  384. package/dist/installer/targets/kiro.js.map +1 -0
  385. package/dist/installer/targets/opencode.d.ts +38 -0
  386. package/dist/installer/targets/opencode.d.ts.map +1 -0
  387. package/dist/installer/targets/opencode.js +288 -0
  388. package/dist/installer/targets/opencode.js.map +1 -0
  389. package/dist/installer/targets/registry.d.ts +35 -0
  390. package/dist/installer/targets/registry.d.ts.map +1 -0
  391. package/dist/installer/targets/registry.js +101 -0
  392. package/dist/installer/targets/registry.js.map +1 -0
  393. package/dist/installer/targets/shared.d.ts +132 -0
  394. package/dist/installer/targets/shared.d.ts.map +1 -0
  395. package/dist/installer/targets/shared.js +314 -0
  396. package/dist/installer/targets/shared.js.map +1 -0
  397. package/dist/installer/targets/toml.d.ts +53 -0
  398. package/dist/installer/targets/toml.d.ts.map +1 -0
  399. package/dist/installer/targets/toml.js +226 -0
  400. package/dist/installer/targets/toml.js.map +1 -0
  401. package/dist/installer/targets/types.d.ts +109 -0
  402. package/dist/installer/targets/types.d.ts.map +1 -0
  403. package/dist/installer/targets/types.js +16 -0
  404. package/dist/installer/targets/types.js.map +1 -0
  405. package/dist/installer/targets/zcode.d.ts +106 -0
  406. package/dist/installer/targets/zcode.d.ts.map +1 -0
  407. package/dist/installer/targets/zcode.js +451 -0
  408. package/dist/installer/targets/zcode.js.map +1 -0
  409. package/dist/mcp/daemon-manager.d.ts +42 -0
  410. package/dist/mcp/daemon-manager.d.ts.map +1 -0
  411. package/dist/mcp/daemon-manager.js +129 -0
  412. package/dist/mcp/daemon-manager.js.map +1 -0
  413. package/dist/mcp/daemon-paths.d.ts +73 -0
  414. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  415. package/dist/mcp/daemon-paths.js +165 -0
  416. package/dist/mcp/daemon-paths.js.map +1 -0
  417. package/dist/mcp/daemon-registry.d.ts +47 -0
  418. package/dist/mcp/daemon-registry.d.ts.map +1 -0
  419. package/dist/mcp/daemon-registry.js +233 -0
  420. package/dist/mcp/daemon-registry.js.map +1 -0
  421. package/dist/mcp/daemon.d.ts +290 -0
  422. package/dist/mcp/daemon.d.ts.map +1 -0
  423. package/dist/mcp/daemon.js +862 -0
  424. package/dist/mcp/daemon.js.map +1 -0
  425. package/dist/mcp/dynamic-boundaries.d.ts +41 -0
  426. package/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
  427. package/dist/mcp/dynamic-boundaries.js +360 -0
  428. package/dist/mcp/dynamic-boundaries.js.map +1 -0
  429. package/dist/mcp/early-ppid.d.ts +26 -0
  430. package/dist/mcp/early-ppid.d.ts.map +1 -0
  431. package/dist/mcp/early-ppid.js +29 -0
  432. package/dist/mcp/early-ppid.js.map +1 -0
  433. package/dist/mcp/engine.d.ts +122 -0
  434. package/dist/mcp/engine.d.ts.map +1 -0
  435. package/dist/mcp/engine.js +350 -0
  436. package/dist/mcp/engine.js.map +1 -0
  437. package/dist/mcp/explore-dedup.d.ts +137 -0
  438. package/dist/mcp/explore-dedup.d.ts.map +1 -0
  439. package/dist/mcp/explore-dedup.js +236 -0
  440. package/dist/mcp/explore-dedup.js.map +1 -0
  441. package/dist/mcp/explore-diagnostics.d.ts +287 -0
  442. package/dist/mcp/explore-diagnostics.d.ts.map +1 -0
  443. package/dist/mcp/explore-diagnostics.js +555 -0
  444. package/dist/mcp/explore-diagnostics.js.map +1 -0
  445. package/dist/mcp/explore-session-state.d.ts +217 -0
  446. package/dist/mcp/explore-session-state.d.ts.map +1 -0
  447. package/dist/mcp/explore-session-state.js +322 -0
  448. package/dist/mcp/explore-session-state.js.map +1 -0
  449. package/dist/mcp/index.d.ts +137 -0
  450. package/dist/mcp/index.d.ts.map +1 -0
  451. package/dist/mcp/index.js +554 -0
  452. package/dist/mcp/index.js.map +1 -0
  453. package/dist/mcp/liveness-watchdog.d.ts +35 -0
  454. package/dist/mcp/liveness-watchdog.d.ts.map +1 -0
  455. package/dist/mcp/liveness-watchdog.js +269 -0
  456. package/dist/mcp/liveness-watchdog.js.map +1 -0
  457. package/dist/mcp/ppid-watchdog.d.ts +62 -0
  458. package/dist/mcp/ppid-watchdog.d.ts.map +1 -0
  459. package/dist/mcp/ppid-watchdog.js +64 -0
  460. package/dist/mcp/ppid-watchdog.js.map +1 -0
  461. package/dist/mcp/proxy.d.ts +87 -0
  462. package/dist/mcp/proxy.d.ts.map +1 -0
  463. package/dist/mcp/proxy.js +672 -0
  464. package/dist/mcp/proxy.js.map +1 -0
  465. package/dist/mcp/query-pool.d.ts +108 -0
  466. package/dist/mcp/query-pool.d.ts.map +1 -0
  467. package/dist/mcp/query-pool.js +315 -0
  468. package/dist/mcp/query-pool.js.map +1 -0
  469. package/dist/mcp/query-worker.d.ts +24 -0
  470. package/dist/mcp/query-worker.d.ts.map +1 -0
  471. package/dist/mcp/query-worker.js +87 -0
  472. package/dist/mcp/query-worker.js.map +1 -0
  473. package/dist/mcp/server-instructions.d.ts +34 -0
  474. package/dist/mcp/server-instructions.d.ts.map +1 -0
  475. package/dist/mcp/server-instructions.js +111 -0
  476. package/dist/mcp/server-instructions.js.map +1 -0
  477. package/dist/mcp/session.d.ts +109 -0
  478. package/dist/mcp/session.d.ts.map +1 -0
  479. package/dist/mcp/session.js +375 -0
  480. package/dist/mcp/session.js.map +1 -0
  481. package/dist/mcp/startup-handshake.d.ts +44 -0
  482. package/dist/mcp/startup-handshake.d.ts.map +1 -0
  483. package/dist/mcp/startup-handshake.js +73 -0
  484. package/dist/mcp/startup-handshake.js.map +1 -0
  485. package/dist/mcp/stdin-teardown.d.ts +27 -0
  486. package/dist/mcp/stdin-teardown.d.ts.map +1 -0
  487. package/dist/mcp/stdin-teardown.js +49 -0
  488. package/dist/mcp/stdin-teardown.js.map +1 -0
  489. package/dist/mcp/tools.d.ts +862 -0
  490. package/dist/mcp/tools.d.ts.map +1 -0
  491. package/dist/mcp/tools.js +6526 -0
  492. package/dist/mcp/tools.js.map +1 -0
  493. package/dist/mcp/transport.d.ts +188 -0
  494. package/dist/mcp/transport.d.ts.map +1 -0
  495. package/dist/mcp/transport.js +377 -0
  496. package/dist/mcp/transport.js.map +1 -0
  497. package/dist/mcp/version.d.ts +19 -0
  498. package/dist/mcp/version.d.ts.map +1 -0
  499. package/dist/mcp/version.js +71 -0
  500. package/dist/mcp/version.js.map +1 -0
  501. package/dist/project-config.d.ts +94 -0
  502. package/dist/project-config.d.ts.map +1 -0
  503. package/dist/project-config.js +374 -0
  504. package/dist/project-config.js.map +1 -0
  505. package/dist/prompt-hook-output.d.ts +23 -0
  506. package/dist/prompt-hook-output.d.ts.map +1 -0
  507. package/dist/prompt-hook-output.js +35 -0
  508. package/dist/prompt-hook-output.js.map +1 -0
  509. package/dist/resolution/c-fnptr-synthesizer.d.ts +6 -0
  510. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -0
  511. package/dist/resolution/c-fnptr-synthesizer.js +1506 -0
  512. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -0
  513. package/dist/resolution/callback-synthesizer.d.ts +59 -0
  514. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  515. package/dist/resolution/callback-synthesizer.js +4030 -0
  516. package/dist/resolution/callback-synthesizer.js.map +1 -0
  517. package/dist/resolution/cooperative-yield.d.ts +40 -0
  518. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  519. package/dist/resolution/cooperative-yield.js +44 -0
  520. package/dist/resolution/cooperative-yield.js.map +1 -0
  521. package/dist/resolution/frameworks/astro.d.ts +9 -0
  522. package/dist/resolution/frameworks/astro.d.ts.map +1 -0
  523. package/dist/resolution/frameworks/astro.js +169 -0
  524. package/dist/resolution/frameworks/astro.js.map +1 -0
  525. package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
  526. package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
  527. package/dist/resolution/frameworks/cargo-workspace.js +225 -0
  528. package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
  529. package/dist/resolution/frameworks/cics.d.ts +20 -0
  530. package/dist/resolution/frameworks/cics.d.ts.map +1 -0
  531. package/dist/resolution/frameworks/cics.js +90 -0
  532. package/dist/resolution/frameworks/cics.js.map +1 -0
  533. package/dist/resolution/frameworks/csharp.d.ts +8 -0
  534. package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
  535. package/dist/resolution/frameworks/csharp.js +241 -0
  536. package/dist/resolution/frameworks/csharp.js.map +1 -0
  537. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  538. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  539. package/dist/resolution/frameworks/drupal.js +367 -0
  540. package/dist/resolution/frameworks/drupal.js.map +1 -0
  541. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  542. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  543. package/dist/resolution/frameworks/expo-modules.js +148 -0
  544. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  545. package/dist/resolution/frameworks/express.d.ts +8 -0
  546. package/dist/resolution/frameworks/express.d.ts.map +1 -0
  547. package/dist/resolution/frameworks/express.js +308 -0
  548. package/dist/resolution/frameworks/express.js.map +1 -0
  549. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  550. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  551. package/dist/resolution/frameworks/fabric.js +354 -0
  552. package/dist/resolution/frameworks/fabric.js.map +1 -0
  553. package/dist/resolution/frameworks/go.d.ts +8 -0
  554. package/dist/resolution/frameworks/go.d.ts.map +1 -0
  555. package/dist/resolution/frameworks/go.js +184 -0
  556. package/dist/resolution/frameworks/go.js.map +1 -0
  557. package/dist/resolution/frameworks/goframe.d.ts +41 -0
  558. package/dist/resolution/frameworks/goframe.d.ts.map +1 -0
  559. package/dist/resolution/frameworks/goframe.js +112 -0
  560. package/dist/resolution/frameworks/goframe.js.map +1 -0
  561. package/dist/resolution/frameworks/index.d.ts +50 -0
  562. package/dist/resolution/frameworks/index.d.ts.map +1 -0
  563. package/dist/resolution/frameworks/index.js +175 -0
  564. package/dist/resolution/frameworks/index.js.map +1 -0
  565. package/dist/resolution/frameworks/java.d.ts +8 -0
  566. package/dist/resolution/frameworks/java.d.ts.map +1 -0
  567. package/dist/resolution/frameworks/java.js +517 -0
  568. package/dist/resolution/frameworks/java.js.map +1 -0
  569. package/dist/resolution/frameworks/laravel.d.ts +13 -0
  570. package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
  571. package/dist/resolution/frameworks/laravel.js +257 -0
  572. package/dist/resolution/frameworks/laravel.js.map +1 -0
  573. package/dist/resolution/frameworks/nestjs.d.ts +26 -0
  574. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
  575. package/dist/resolution/frameworks/nestjs.js +698 -0
  576. package/dist/resolution/frameworks/nestjs.js.map +1 -0
  577. package/dist/resolution/frameworks/play.d.ts +19 -0
  578. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  579. package/dist/resolution/frameworks/play.js +111 -0
  580. package/dist/resolution/frameworks/play.js.map +1 -0
  581. package/dist/resolution/frameworks/python.d.ts +10 -0
  582. package/dist/resolution/frameworks/python.d.ts.map +1 -0
  583. package/dist/resolution/frameworks/python.js +400 -0
  584. package/dist/resolution/frameworks/python.js.map +1 -0
  585. package/dist/resolution/frameworks/react-native.d.ts +3 -0
  586. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  587. package/dist/resolution/frameworks/react-native.js +410 -0
  588. package/dist/resolution/frameworks/react-native.js.map +1 -0
  589. package/dist/resolution/frameworks/react.d.ts +8 -0
  590. package/dist/resolution/frameworks/react.d.ts.map +1 -0
  591. package/dist/resolution/frameworks/react.js +334 -0
  592. package/dist/resolution/frameworks/react.js.map +1 -0
  593. package/dist/resolution/frameworks/ruby.d.ts +8 -0
  594. package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
  595. package/dist/resolution/frameworks/ruby.js +302 -0
  596. package/dist/resolution/frameworks/ruby.js.map +1 -0
  597. package/dist/resolution/frameworks/rust.d.ts +8 -0
  598. package/dist/resolution/frameworks/rust.d.ts.map +1 -0
  599. package/dist/resolution/frameworks/rust.js +304 -0
  600. package/dist/resolution/frameworks/rust.js.map +1 -0
  601. package/dist/resolution/frameworks/svelte.d.ts +9 -0
  602. package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
  603. package/dist/resolution/frameworks/svelte.js +253 -0
  604. package/dist/resolution/frameworks/svelte.js.map +1 -0
  605. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  606. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  607. package/dist/resolution/frameworks/swift-objc.js +252 -0
  608. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  609. package/dist/resolution/frameworks/swift.d.ts +10 -0
  610. package/dist/resolution/frameworks/swift.d.ts.map +1 -0
  611. package/dist/resolution/frameworks/swift.js +400 -0
  612. package/dist/resolution/frameworks/swift.js.map +1 -0
  613. package/dist/resolution/frameworks/terraform.d.ts +38 -0
  614. package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
  615. package/dist/resolution/frameworks/terraform.js +277 -0
  616. package/dist/resolution/frameworks/terraform.js.map +1 -0
  617. package/dist/resolution/frameworks/vue.d.ts +9 -0
  618. package/dist/resolution/frameworks/vue.d.ts.map +1 -0
  619. package/dist/resolution/frameworks/vue.js +303 -0
  620. package/dist/resolution/frameworks/vue.js.map +1 -0
  621. package/dist/resolution/go-module.d.ts +26 -0
  622. package/dist/resolution/go-module.d.ts.map +1 -0
  623. package/dist/resolution/go-module.js +78 -0
  624. package/dist/resolution/go-module.js.map +1 -0
  625. package/dist/resolution/goframe-synthesizer.d.ts +29 -0
  626. package/dist/resolution/goframe-synthesizer.d.ts.map +1 -0
  627. package/dist/resolution/goframe-synthesizer.js +163 -0
  628. package/dist/resolution/goframe-synthesizer.js.map +1 -0
  629. package/dist/resolution/import-resolver.d.ts +84 -0
  630. package/dist/resolution/import-resolver.d.ts.map +1 -0
  631. package/dist/resolution/import-resolver.js +2134 -0
  632. package/dist/resolution/import-resolver.js.map +1 -0
  633. package/dist/resolution/index.d.ts +343 -0
  634. package/dist/resolution/index.d.ts.map +1 -0
  635. package/dist/resolution/index.js +2339 -0
  636. package/dist/resolution/index.js.map +1 -0
  637. package/dist/resolution/lru-cache.d.ts +24 -0
  638. package/dist/resolution/lru-cache.d.ts.map +1 -0
  639. package/dist/resolution/lru-cache.js +62 -0
  640. package/dist/resolution/lru-cache.js.map +1 -0
  641. package/dist/resolution/memory-budget.d.ts +48 -0
  642. package/dist/resolution/memory-budget.d.ts.map +1 -0
  643. package/dist/resolution/memory-budget.js +162 -0
  644. package/dist/resolution/memory-budget.js.map +1 -0
  645. package/dist/resolution/name-matcher.d.ts +123 -0
  646. package/dist/resolution/name-matcher.d.ts.map +1 -0
  647. package/dist/resolution/name-matcher.js +2134 -0
  648. package/dist/resolution/name-matcher.js.map +1 -0
  649. package/dist/resolution/path-aliases.d.ts +68 -0
  650. package/dist/resolution/path-aliases.d.ts.map +1 -0
  651. package/dist/resolution/path-aliases.js +238 -0
  652. package/dist/resolution/path-aliases.js.map +1 -0
  653. package/dist/resolution/resolver-pool.d.ts +106 -0
  654. package/dist/resolution/resolver-pool.d.ts.map +1 -0
  655. package/dist/resolution/resolver-pool.js +344 -0
  656. package/dist/resolution/resolver-pool.js.map +1 -0
  657. package/dist/resolution/resolver-worker.d.ts +17 -0
  658. package/dist/resolution/resolver-worker.d.ts.map +1 -0
  659. package/dist/resolution/resolver-worker.js +141 -0
  660. package/dist/resolution/resolver-worker.js.map +1 -0
  661. package/dist/resolution/strip-comments.d.ts +27 -0
  662. package/dist/resolution/strip-comments.d.ts.map +1 -0
  663. package/dist/resolution/strip-comments.js +492 -0
  664. package/dist/resolution/strip-comments.js.map +1 -0
  665. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  666. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  667. package/dist/resolution/swift-objc-bridge.js +256 -0
  668. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  669. package/dist/resolution/types.d.ts +265 -0
  670. package/dist/resolution/types.d.ts.map +1 -0
  671. package/dist/resolution/types.js +8 -0
  672. package/dist/resolution/types.js.map +1 -0
  673. package/dist/resolution/workspace-packages.d.ts +58 -0
  674. package/dist/resolution/workspace-packages.d.ts.map +1 -0
  675. package/dist/resolution/workspace-packages.js +346 -0
  676. package/dist/resolution/workspace-packages.js.map +1 -0
  677. package/dist/search/identifier-segments.d.ts +60 -0
  678. package/dist/search/identifier-segments.d.ts.map +1 -0
  679. package/dist/search/identifier-segments.js +176 -0
  680. package/dist/search/identifier-segments.js.map +1 -0
  681. package/dist/search/query-parser.d.ts +57 -0
  682. package/dist/search/query-parser.d.ts.map +1 -0
  683. package/dist/search/query-parser.js +177 -0
  684. package/dist/search/query-parser.js.map +1 -0
  685. package/dist/search/query-utils.d.ts +87 -0
  686. package/dist/search/query-utils.d.ts.map +1 -0
  687. package/dist/search/query-utils.js +450 -0
  688. package/dist/search/query-utils.js.map +1 -0
  689. package/dist/sync/git-hooks.d.ts +45 -0
  690. package/dist/sync/git-hooks.d.ts.map +1 -0
  691. package/dist/sync/git-hooks.js +227 -0
  692. package/dist/sync/git-hooks.js.map +1 -0
  693. package/dist/sync/index.d.ts +19 -0
  694. package/dist/sync/index.d.ts.map +1 -0
  695. package/dist/sync/index.js +35 -0
  696. package/dist/sync/index.js.map +1 -0
  697. package/dist/sync/watch-policy.d.ts +48 -0
  698. package/dist/sync/watch-policy.d.ts.map +1 -0
  699. package/dist/sync/watch-policy.js +124 -0
  700. package/dist/sync/watch-policy.js.map +1 -0
  701. package/dist/sync/watcher.d.ts +379 -0
  702. package/dist/sync/watcher.d.ts.map +1 -0
  703. package/dist/sync/watcher.js +921 -0
  704. package/dist/sync/watcher.js.map +1 -0
  705. package/dist/sync/worktree.d.ts +63 -0
  706. package/dist/sync/worktree.d.ts.map +1 -0
  707. package/dist/sync/worktree.js +182 -0
  708. package/dist/sync/worktree.js.map +1 -0
  709. package/dist/telemetry/index.d.ts +143 -0
  710. package/dist/telemetry/index.d.ts.map +1 -0
  711. package/dist/telemetry/index.js +541 -0
  712. package/dist/telemetry/index.js.map +1 -0
  713. package/dist/types.d.ts +465 -0
  714. package/dist/types.d.ts.map +1 -0
  715. package/dist/types.js +117 -0
  716. package/dist/types.js.map +1 -0
  717. package/dist/ui/color.d.ts +21 -0
  718. package/dist/ui/color.d.ts.map +1 -0
  719. package/dist/ui/color.js +42 -0
  720. package/dist/ui/color.js.map +1 -0
  721. package/dist/ui/glyphs.d.ts +67 -0
  722. package/dist/ui/glyphs.d.ts.map +1 -0
  723. package/dist/ui/glyphs.js +125 -0
  724. package/dist/ui/glyphs.js.map +1 -0
  725. package/dist/ui/shimmer-progress.d.ts +11 -0
  726. package/dist/ui/shimmer-progress.d.ts.map +1 -0
  727. package/dist/ui/shimmer-progress.js +164 -0
  728. package/dist/ui/shimmer-progress.js.map +1 -0
  729. package/dist/ui/shimmer-worker.d.ts +2 -0
  730. package/dist/ui/shimmer-worker.d.ts.map +1 -0
  731. package/dist/ui/shimmer-worker.js +126 -0
  732. package/dist/ui/shimmer-worker.js.map +1 -0
  733. package/dist/ui/types.d.ts +15 -0
  734. package/dist/ui/types.d.ts.map +1 -0
  735. package/dist/ui/types.js +3 -0
  736. package/dist/ui/types.js.map +1 -0
  737. package/dist/upgrade/index.d.ts +171 -0
  738. package/dist/upgrade/index.d.ts.map +1 -0
  739. package/dist/upgrade/index.js +659 -0
  740. package/dist/upgrade/index.js.map +1 -0
  741. package/dist/upgrade/remove-binary.d.ts +87 -0
  742. package/dist/upgrade/remove-binary.d.ts.map +1 -0
  743. package/dist/upgrade/remove-binary.js +289 -0
  744. package/dist/upgrade/remove-binary.js.map +1 -0
  745. package/dist/upgrade/update-check.d.ts +92 -0
  746. package/dist/upgrade/update-check.d.ts.map +1 -0
  747. package/dist/upgrade/update-check.js +258 -0
  748. package/dist/upgrade/update-check.js.map +1 -0
  749. package/dist/utils.d.ts +224 -0
  750. package/dist/utils.d.ts.map +1 -0
  751. package/dist/utils.js +583 -0
  752. package/dist/utils.js.map +1 -0
  753. package/package.json +61 -0
  754. package/scripts/add-lang/bench.sh +60 -0
  755. package/scripts/add-lang/check-grammar.mjs +75 -0
  756. package/scripts/add-lang/dump-ast.mjs +103 -0
  757. package/scripts/add-lang/verify-extraction.mjs +70 -0
  758. package/scripts/agent-eval/ab-adoption.sh +91 -0
  759. package/scripts/agent-eval/ab-hook.sh +86 -0
  760. package/scripts/agent-eval/ab-impl.sh +78 -0
  761. package/scripts/agent-eval/ab-new-vs-baseline.sh +161 -0
  762. package/scripts/agent-eval/ab-sufficiency.sh +78 -0
  763. package/scripts/agent-eval/allocation-fixtures.json +344 -0
  764. package/scripts/agent-eval/arms-F.sh +21 -0
  765. package/scripts/agent-eval/arms-matrix.sh +37 -0
  766. package/scripts/agent-eval/audit.sh +68 -0
  767. package/scripts/agent-eval/bench-readme.sh +48 -0
  768. package/scripts/agent-eval/bench-why-repo.sh +22 -0
  769. package/scripts/agent-eval/block-read-hook.sh +19 -0
  770. package/scripts/agent-eval/compare-arms.mjs +209 -0
  771. package/scripts/agent-eval/diff-index-drift.mjs +102 -0
  772. package/scripts/agent-eval/hook-settings.json +15 -0
  773. package/scripts/agent-eval/itrun.sh +120 -0
  774. package/scripts/agent-eval/no-cli-shim.sh +96 -0
  775. package/scripts/agent-eval/offload-eval-3arm.sh +72 -0
  776. package/scripts/agent-eval/offload-eval-cost.mjs +133 -0
  777. package/scripts/agent-eval/offload-eval-effort.mjs +108 -0
  778. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -0
  779. package/scripts/agent-eval/offload-eval-frontload.sh +47 -0
  780. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -0
  781. package/scripts/agent-eval/offload-eval-hook.mjs +84 -0
  782. package/scripts/agent-eval/offload-eval-judge.mjs +103 -0
  783. package/scripts/agent-eval/offload-eval-matrix.sh +20 -0
  784. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -0
  785. package/scripts/agent-eval/offload-eval-refs1.sh +50 -0
  786. package/scripts/agent-eval/offload-eval-setup.sh +24 -0
  787. package/scripts/agent-eval/offload-eval-styles.sh +72 -0
  788. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -0
  789. package/scripts/agent-eval/offload-eval.md +76 -0
  790. package/scripts/agent-eval/parse-arms.mjs +116 -0
  791. package/scripts/agent-eval/parse-bench-readme.mjs +238 -0
  792. package/scripts/agent-eval/parse-run.mjs +1401 -0
  793. package/scripts/agent-eval/parse-session.mjs +130 -0
  794. package/scripts/agent-eval/probe-allocation.mjs +335 -0
  795. package/scripts/agent-eval/probe-context.mjs +21 -0
  796. package/scripts/agent-eval/probe-decl-only.mjs +198 -0
  797. package/scripts/agent-eval/probe-explore.mjs +40 -0
  798. package/scripts/agent-eval/probe-factory-closure.mjs +147 -0
  799. package/scripts/agent-eval/probe-file-spend.mjs +195 -0
  800. package/scripts/agent-eval/probe-named-symbol.mjs +163 -0
  801. package/scripts/agent-eval/probe-node.mjs +20 -0
  802. package/scripts/agent-eval/probe-suite-envelope.mjs +124 -0
  803. package/scripts/agent-eval/probe-sweep.mjs +119 -0
  804. package/scripts/agent-eval/probe-trace.mjs +20 -0
  805. package/scripts/agent-eval/redirect-read-hook.sh +38 -0
  806. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  807. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  808. package/scripts/agent-eval/run-agent.sh +34 -0
  809. package/scripts/agent-eval/run-all.sh +149 -0
  810. package/scripts/agent-eval/run-arms.sh +56 -0
  811. package/scripts/agent-eval/seq-matrix.mjs +137 -0
  812. package/scripts/build-bundle.sh +145 -0
  813. package/scripts/build-kernel.sh +87 -0
  814. package/scripts/dump-graph.mjs +57 -0
  815. package/scripts/extract-release-notes.mjs +130 -0
  816. package/scripts/kernel-parity.mjs +283 -0
  817. package/scripts/local-install.sh +41 -0
  818. package/scripts/npm-sdk.js +75 -0
  819. package/scripts/npm-shim.js +279 -0
  820. package/scripts/pack-npm.sh +123 -0
  821. package/scripts/prepare-release.mjs +270 -0
@@ -0,0 +1,1506 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.cFnPointerDispatchEdges = cFnPointerDispatchEdges;
37
+ /**
38
+ * C/C++ function-pointer dispatch synthesis (#932).
39
+ *
40
+ * C/C++ polymorphism is the function pointer: a struct carries a fn-pointer
41
+ * field (`int (*fn)(int)`, or a fn-pointer-typedef field `hook_func func`),
42
+ * concrete functions are *registered* into it through a table
43
+ * (`static struct cmd cmds[] = {{"add", cmd_add}, …}`, a designated
44
+ * `.fn = cmd_add`, or `x->fn = cmd_add`), and the dispatcher calls through it
45
+ * indirectly (`p->fn(argv)`). Static extraction captures neither the
46
+ * registration→field binding nor the indirect call, so the dispatcher→handler
47
+ * edge is missing and `git`'s `run_builtin` looks like it calls nothing, the
48
+ * hooks in `hook_demo.c` are unreachable, etc.
49
+ *
50
+ * This bridges it, keyed by **(struct type, fn-pointer field)**:
51
+ * • registrations — a function bound to `S.field` via a positional
52
+ * initializer (matched by field index), a designated `.field = fn`, or a
53
+ * direct `x.field = fn` / `x->field = fn` assignment;
54
+ * • dispatch — `recv->field(…)` / `recv.field(…)` where `recv` resolves to a
55
+ * value of struct type `S` (from the enclosing function's params / locals,
56
+ * or by walking a chained/array receiver `c->cmd->proc` across field types),
57
+ * falling back to the field name when it is unique to one struct;
58
+ * • field←field propagation — `a->f = b->g` merges `B.g`'s handlers into
59
+ * `A.f`, so a generic single-slot hook that is reassigned from a registry
60
+ * (the `hook_demo.c` shape: `h->func = found->fn`) still resolves.
61
+ *
62
+ * Also handles **macro-built tables** (#991) — the dominant real-world shape,
63
+ * e.g. redis' command table, sqlite's builtin functions, and vim's `:ex` /
64
+ * normal-mode commands. The fn-pointer arg lives inside a macro call
65
+ * (`MAKE_CMD(…,proc,…)` / `FUNCTION(…,xFunc)` / `EXCMD(…,fn,…)`) in a generated
66
+ * or `#include`-d file; the table's struct type may itself be an object-macro
67
+ * alias; the field may use a function-TYPE typedef; the struct may be defined
68
+ * INLINE with the array; and the whole thing may sit behind `#ifdef` switched on
69
+ * by the includer. The registration pass reads each `#include`-d file as a unit
70
+ * with the includer's effective macro env (own + headers) in scope, evaluates
71
+ * its `#ifdef`s against the includer's defined set, expands object/function
72
+ * macros, peels a brace-wrapped element, and parses an inline struct in place —
73
+ * then reads the positional/designated bindings. Dispatch additionally resolves
74
+ * an array subscript through a file-scope table (`(cmdnames[i].cmd_func)(…)`).
75
+ *
76
+ * Also bridges **bare arrays of function pointers** (no struct, no field) —
77
+ * `opcode_t *opcodes[256] = {nop,…}` dispatched `opcodes[op](…)` (SameBoy's CPU),
78
+ * `zend_rc_dtor_func_t t[] = {[IS_STRING]=(cast)fn,…}` dispatched `t[GC_TYPE(p)](…)`
79
+ * (php's Zend) — keyed by the array VARIABLE name. The element type must be a
80
+ * function typedef (the precision gate), entries are literal function names, and
81
+ * the same-file table wins on a name collision (two file-local `opcodes[256]`).
82
+ *
83
+ * Whole-graph pass after base resolution; all edges are `provenance:'heuristic'`
84
+ * (`synthesizedBy:'fn-pointer-dispatch'`). High precision via the (type, field)
85
+ * key + a real-function gate; a project with no fn-pointer dispatch is a no-op.
86
+ *
87
+ * ## Fuse-then-link architecture (§7a.8, task #5 step 1)
88
+ *
89
+ * The pass used to sweep every file's text FOUR times (typedefs, registrations,
90
+ * propagation, dispatch), and on the Linux kernel the all-or-nothing source
91
+ * cache declines, so each sweep re-read + re-stripped the whole corpus — 4.4
92
+ * strips/file, ~78s of the ~230s kernel-scale wall (§7a.8 calibration). It now
93
+ * runs as ONE extraction sweep plus filtered linking stages:
94
+ *
95
+ * 1. **Extraction sweep** — reads + strips each file ONCE and collects, per
96
+ * file: typedef names, each struct node's field declarations (parsed
97
+ * structurally, fn-pointer classification deferred — the typedef sets
98
+ * aren't complete mid-sweep), the resolved local includes, and cheap
99
+ * SURVIVAL FILTERS for the later stages (distinct initializer type
100
+ * tokens, array element types, inline-struct summaries, field-assignment
101
+ * field pairs, dispatch field / array names — all interned, a few MB even
102
+ * on the kernel).
103
+ * 2. **Struct-layout linking** — classifies the deferred fields against the
104
+ * now-complete typedef sets and registers layouts by replaying the struct
105
+ * kind-scan, so registration order (which decides same-name layout
106
+ * precedence) is byte-identical to the old dedicated pass.
107
+ * 3. **Registration / propagation / dispatch** — the original pass bodies,
108
+ * UNCHANGED, but each file is first checked against its survival filter
109
+ * and only surviving files are re-stripped (LRU-served). The filters only
110
+ * ever over-approximate: a filtered-out file is one where every match
111
+ * would have failed the pass's own gates before any side effect, so
112
+ * skipping it cannot change the edge set. On the kernel only ~16% of
113
+ * files have any dispatch-shaped match at all, so the lazy re-strips are
114
+ * a fraction of a sweep and total strip work drops ~4.4× → ~1.5×.
115
+ *
116
+ * The extraction sweep is also the step-2 boundary: a native per-file extractor
117
+ * can replace the sweep's scans without touching the linking stages.
118
+ */
119
+ const path = __importStar(require("node:path"));
120
+ const memory_budget_1 = require("./memory-budget");
121
+ const lru_cache_1 = require("./lru-cache");
122
+ const strip_comments_1 = require("./strip-comments");
123
+ const loader_1 = require("../extraction/kernel/loader");
124
+ const C_CPP_EXT = /\.(c|h|cc|cpp|cxx|hpp|hh|hxx|cppm|ipp|inl|tcc)$/i;
125
+ const FN_KINDS = new Set(['function', 'method']);
126
+ const FANOUT_CAP = 300; // a real command table (git ~150) is legitimate fan-out; this only stops pathological cases.
127
+ /** Slice a node's body from a pre-split line array — the per-file sweeps
128
+ * call this once per NODE, and splitting the whole file per node was an
129
+ * O(nodes × file-size) term (~1.6M full-file splits on the Linux tree,
130
+ * §7a.3 cFnPtr round). Split once per file, slice many times. */
131
+ function sliceLinesPre(lines, startLine, endLine) {
132
+ if (!startLine)
133
+ return '';
134
+ return lines.slice(startLine - 1, endLine ?? startLine).join('\n');
135
+ }
136
+ /** Index of the `}` matching the `{` at `open` (which must point at a `{`). -1 if unbalanced. */
137
+ function matchBrace(src, open) {
138
+ let depth = 0;
139
+ for (let i = open; i < src.length; i++) {
140
+ const c = src[i];
141
+ if (c === '{')
142
+ depth++;
143
+ else if (c === '}') {
144
+ depth--;
145
+ if (depth === 0)
146
+ return i;
147
+ }
148
+ }
149
+ return -1;
150
+ }
151
+ /** Split `body` on `sep` at brace/paren/bracket depth 0 (commas inside `{…}` / `(…)` stay together). */
152
+ function splitTopLevel(body, sep) {
153
+ const out = [];
154
+ let depth = 0;
155
+ let start = 0;
156
+ for (let i = 0; i < body.length; i++) {
157
+ const c = body[i];
158
+ if (c === '{' || c === '(' || c === '[')
159
+ depth++;
160
+ else if (c === '}' || c === ')' || c === ']')
161
+ depth--;
162
+ else if (c === sep && depth === 0) {
163
+ out.push(body.slice(start, i));
164
+ start = i + 1;
165
+ }
166
+ }
167
+ out.push(body.slice(start));
168
+ return out;
169
+ }
170
+ /** Index of the `)` matching the `(` at `open` (which must point at a `(`). -1 if unbalanced. */
171
+ function matchParen(src, open) {
172
+ let depth = 0;
173
+ for (let i = open; i < src.length; i++) {
174
+ const c = src[i];
175
+ if (c === '(')
176
+ depth++;
177
+ else if (c === ')') {
178
+ depth--;
179
+ if (depth === 0)
180
+ return i;
181
+ }
182
+ }
183
+ return -1;
184
+ }
185
+ /**
186
+ * Collect function-like macros from (comment-stripped) source, joining
187
+ * `\`-continuations first. Only object/positional table macros matter here, so
188
+ * variadic macros are skipped. Used to expand registration tables built through
189
+ * a macro (redis' `MAKE_CMD(…)`) before reading the struct-field bindings.
190
+ */
191
+ function parseFunctionMacros(stripped) {
192
+ const out = new Map();
193
+ if (!stripped.includes('#define') && !stripped.includes('# define'))
194
+ return out;
195
+ const joined = stripped.replace(/\\\r?\n/g, ' ');
196
+ const RE = /^[ \t]*#[ \t]*define[ \t]+(\w+)\(([^)]*)\)\s+(.+)$/gm;
197
+ let m;
198
+ while ((m = RE.exec(joined))) {
199
+ const params = m[2].split(',').map((p) => p.trim()).filter(Boolean);
200
+ if (params.some((p) => p === '...' || p.endsWith('...')))
201
+ continue; // variadic — skip
202
+ out.set(m[1], { params, expansion: m[3].trim() });
203
+ }
204
+ return out;
205
+ }
206
+ /**
207
+ * Collect object-like macros `#define NAME value` (NAME not immediately followed
208
+ * by `(`). redis aliases the table's struct type this way:
209
+ * `#define COMMAND_STRUCT redisCommand`, used as `struct COMMAND_STRUCT table[]`.
210
+ */
211
+ function parseObjectMacros(stripped) {
212
+ const out = new Map();
213
+ if (!stripped.includes('#define') && !stripped.includes('# define'))
214
+ return out;
215
+ const joined = stripped.replace(/\\\r?\n/g, ' ');
216
+ const RE = /^[ \t]*#[ \t]*define[ \t]+(\w+)[ \t]+(\S[^\n]*)$/gm;
217
+ let m;
218
+ while ((m = RE.exec(joined)))
219
+ out.set(m[1], m[2].trim());
220
+ return out;
221
+ }
222
+ /** All macro names a file `#define`s (value-ful or not) — the "defined" set for #ifdef. */
223
+ function parseDefinedNames(stripped) {
224
+ const out = new Set();
225
+ if (!stripped.includes('#define') && !stripped.includes('# define'))
226
+ return out;
227
+ const RE = /^[ \t]*#[ \t]*define[ \t]+(\w+)/gm;
228
+ let m;
229
+ while ((m = RE.exec(stripped)))
230
+ out.add(m[1]);
231
+ return out;
232
+ }
233
+ /**
234
+ * Drop the inactive arms of `#ifdef`/`#ifndef`/`#if defined(X)`/`#else`/`#elif`/
235
+ * `#endif` given a set of defined macro names, keeping line offsets (inactive
236
+ * lines are blanked, not removed). A conditional whose expression we can't
237
+ * evaluate (`#if SOME_EXPR`) keeps its body — better to over-keep than to drop
238
+ * live code. This is what makes a header included with a switch macro defined
239
+ * (vim's `ex_cmds.h` under `DO_DECLARE_EXCMD`) expose only its active table.
240
+ */
241
+ function evalConditionals(text, defined) {
242
+ if (!/#\s*if/.test(text))
243
+ return text;
244
+ const lines = text.split('\n');
245
+ // stack frame: parentActive = enclosing kept?; active = this arm kept?; taken = any arm taken yet
246
+ const stack = [];
247
+ const activeNow = () => (stack.length === 0 ? true : stack[stack.length - 1].active);
248
+ const condDefined = (expr) => {
249
+ let mm = expr.match(/^defined\s*\(?\s*(\w+)\s*\)?$/);
250
+ if (mm)
251
+ return defined.has(mm[1]);
252
+ mm = expr.match(/^!\s*defined\s*\(?\s*(\w+)\s*\)?$/);
253
+ if (mm)
254
+ return !defined.has(mm[1]);
255
+ return null; // unevaluable
256
+ };
257
+ for (let i = 0; i < lines.length; i++) {
258
+ const t = lines[i].trim();
259
+ let mm;
260
+ if ((mm = t.match(/^#\s*ifdef\s+(\w+)/))) {
261
+ const pa = activeNow();
262
+ const cond = defined.has(mm[1]);
263
+ stack.push({ parentActive: pa, active: pa && cond, taken: cond });
264
+ lines[i] = '';
265
+ continue;
266
+ }
267
+ if ((mm = t.match(/^#\s*ifndef\s+(\w+)/))) {
268
+ const pa = activeNow();
269
+ const cond = !defined.has(mm[1]);
270
+ stack.push({ parentActive: pa, active: pa && cond, taken: cond });
271
+ lines[i] = '';
272
+ continue;
273
+ }
274
+ if ((mm = t.match(/^#\s*if\s+(.+)$/))) {
275
+ const pa = activeNow();
276
+ const c = condDefined(mm[1].trim());
277
+ const cond = c === null ? true : c; // unevaluable → keep
278
+ stack.push({ parentActive: pa, active: pa && cond, taken: cond });
279
+ lines[i] = '';
280
+ continue;
281
+ }
282
+ if (/^#\s*elif\b/.test(t)) {
283
+ const top = stack[stack.length - 1];
284
+ if (top) {
285
+ top.active = top.parentActive && !top.taken;
286
+ top.taken = true;
287
+ }
288
+ lines[i] = '';
289
+ continue;
290
+ }
291
+ if (/^#\s*else\b/.test(t)) {
292
+ const top = stack[stack.length - 1];
293
+ if (top) {
294
+ top.active = top.parentActive && !top.taken;
295
+ top.taken = true;
296
+ }
297
+ lines[i] = '';
298
+ continue;
299
+ }
300
+ if (/^#\s*endif\b/.test(t)) {
301
+ stack.pop();
302
+ lines[i] = '';
303
+ continue;
304
+ }
305
+ if (!activeNow())
306
+ lines[i] = ''; // blank an inactive line (keep the newline)
307
+ }
308
+ return lines.join('\n');
309
+ }
310
+ /** Resolve a type token through object-like macro aliases (transitive, capped). */
311
+ function resolveTypeName(name, objEnv) {
312
+ let n = name;
313
+ for (let i = 0; objEnv && i < 5; i++) {
314
+ const v = objEnv.get(n);
315
+ const t = v?.trim().match(/^(?:(?:struct|union)\s+)?(\w+)$/);
316
+ if (!t)
317
+ break;
318
+ n = t[1];
319
+ }
320
+ return n;
321
+ }
322
+ /** Substitute call args for the macro's params (whole-token) in its expansion. */
323
+ function substituteMacro(def, args) {
324
+ const map = new Map();
325
+ def.params.forEach((p, i) => map.set(p, args[i] ?? ''));
326
+ return def.expansion.replace(/\b\w+\b/g, (tok) => (map.has(tok) ? map.get(tok) : tok));
327
+ }
328
+ /**
329
+ * Expand known function-like macro calls in `text` to a fixpoint (depth-capped).
330
+ * `MAKE_CMD("get",…,getCommand,…)` → the positional value list whose slots line
331
+ * up with the struct's fields, so the existing positional registration can read
332
+ * `getCommand` straight out of the `proc` slot.
333
+ */
334
+ function expandMacroCalls(text, env) {
335
+ if (env.size === 0)
336
+ return text;
337
+ let out = text;
338
+ for (let pass = 0; pass < 6; pass++) {
339
+ let changed = false;
340
+ const RE = /\b(\w+)\s*\(/g;
341
+ let m;
342
+ while ((m = RE.exec(out))) {
343
+ const def = env.get(m[1]);
344
+ if (!def)
345
+ continue;
346
+ const open = m.index + m[0].length - 1; // index of the `(`
347
+ const close = matchParen(out, open);
348
+ if (close < 0)
349
+ continue;
350
+ const args = splitTopLevel(out.slice(open + 1, close), ',').map((a) => a.trim());
351
+ out = out.slice(0, m.index) + substituteMacro(def, args) + out.slice(close + 1);
352
+ changed = true;
353
+ break; // restart scan — offsets shifted
354
+ }
355
+ if (!changed)
356
+ break;
357
+ }
358
+ return out;
359
+ }
360
+ /** A fn-pointer field looks like `… (*name)(…)` — capture `name`. A
361
+ * calling-convention / attribute macro may precede the `*`
362
+ * (`(ZEND_FASTCALL *name)`), so allow leading word tokens. */
363
+ const FNPTR_DECL_RE = /\(\s*(?:\w+\s+)*\*\s*(\w+)\s*\)\s*\(/;
364
+ /** `typedef RET (*NAME)(…)` — a function-pointer typedef (CC/attr macro before
365
+ * the `*` allowed, as in php's `typedef void (ZEND_FASTCALL *fn_t)(…)`). */
366
+ const FNPTR_TYPEDEF_RE = /\btypedef\b[^;{}]*?\(\s*(?:\w+\s+)*\*\s*(\w+)\s*\)\s*\(/g;
367
+ /** A whole brace-free `typedef … ;` statement — capture the guts to spot the
368
+ * function-TYPE form `typedef RET NAME(params)` (no `(*name)` pointer form). */
369
+ const FNTYPE_TYPEDEF_STMT_RE = /\btypedef\b([^;{}]*);/g;
370
+ /** Return-type keywords that must never be mistaken for the typedef's name. */
371
+ const C_TYPE_KEYWORDS = new Set([
372
+ 'void', 'int', 'char', 'short', 'long', 'unsigned', 'signed', 'float', 'double',
373
+ 'const', 'struct', 'union', 'enum', 'static', 'volatile', 'register', 'inline',
374
+ ]);
375
+ /** `#include "local/header"` — captured from RAW source (string contents survive). */
376
+ const INCLUDE_RE = /#[ \t]*include[ \t]+"([^"\n]+)"/g;
377
+ /** Included files worth scanning for registration tables (e.g. a generated `.def`). */
378
+ const INCLUDABLE_EXT = /\.(def|inc|h|hh|hpp|hxx|c|cc|cpp|cxx|ipp|tcc|tbl)$/i;
379
+ /** `#define NAME single_identifier` (possibly `struct`-prefixed) — an
380
+ * object-macro that COULD alias a struct type name (`resolveTypeName`'s exact
381
+ * value shape). The extraction sweep collects every such NAME into a global
382
+ * set: an initializer type token that direct-misses the struct layouts still
383
+ * survives the registration filter when it is alias-SHAPED anywhere, so the
384
+ * per-file macro-env alias resolution (redis' `COMMAND_STRUCT`) keeps working
385
+ * without retaining per-file object-macro tables (6.1M `#define`s on the
386
+ * Linux tree — the amdgpu register headers — rule that out). Numeric values
387
+ * are excluded: `resolveTypeName` would rewrite to a dead-end token that can
388
+ * never name a struct, so skipping them is exact, and it drops the register
389
+ * flood. */
390
+ const OBJ_ALIAS_RE = /^[ \t]*#[ \t]*define[ \t]+(\w+)[ \t]+(?:(?:struct|union)[ \t]+)*[A-Za-z_]\w*[ \t\r]*$/gm;
391
+ /** `(?:struct )?TYPE name[opt] = {` initializers, where TYPE is a struct that
392
+ * has ≥1 fn-pointer field. Handles both single (`= {…}`) and array
393
+ * (`[] = { {…}, {…} }`) forms. Macro calls inside an element are expanded first. */
394
+ const INIT_RE = /(?:^|[;{}])\s*(?:(?:static|const|extern|register|volatile)\s+)*(?:(?:struct|union)\s+)?(\w+)\s+(\w+)\s*(\[[^\]]*\])?\s*=\s*\{/g;
395
+ /** `struct TAG { … } var[opt] [= {…}]` — the struct is defined INLINE with the
396
+ * table (vim's `cmdname`/`nv_cmd`); its layout never became a node, so parse it
397
+ * here and register it before reading the entries. No leading anchor: a
398
+ * `struct TAG {` with a brace body is always a definition (it may be preceded
399
+ * by a `#define …` line ending in a digit, as in vim), and the trailing
400
+ * `var … = {` check below is what distinguishes a TABLE from a plain type. */
401
+ const INLINE_STRUCT_RE = /\b(?:struct|union)\s+(\w+)\s*\{/g;
402
+ /** `(?:static …)* ELEMTYPE [*] name[…] = { … }` — a bare array of function
403
+ * pointers (no struct wrapper). The optional `*` covers a function-TYPE
404
+ * typedef element (`opcode_t *opcodes[]`); a function-pointer typedef element
405
+ * (`zend_rc_dtor_func_t t[]`) needs none. The typedef-set membership gate
406
+ * is what separates this from a plain data/struct array. */
407
+ const ARRAY_TABLE_RE = /(?:^|[;{}])\s*(?:(?:static|const|extern|register|volatile)\s+)*(\w+)\s+(\*\s*)?(\w+)\s*\[[^\]]*\]\s*=\s*\{/g;
408
+ /** Dispatch sites: `base->…->field(` or `base.…field(` where `field` is a known
409
+ * fn-pointer field. The base may be a chain (`c->cmd->proc`) or carry array
410
+ * subscripts (`cmdnames[i].cmd_func`). An optional `)` before the call covers
411
+ * the parenthesized form `(cmdnames[i].cmd_func)(&ea)` vim uses. */
412
+ const DISPATCH_RE = /((?:\w+(?:\s*\[[^\][]*\])?\s*(?:->|\.)\s*)+)(\w+)\s*\)?\s*\(/g;
413
+ /** Bare-array dispatch: `tbl[i](…)` or the explicit-deref `(*tbl[i])(…)`. The
414
+ * subscript may itself contain a call (`tbl[GC_TYPE(p)](…)`), so the index
415
+ * class excludes only brackets. Precision comes from the `arrayReg` gate —
416
+ * this fires only when `tbl` is a known fn-pointer array. */
417
+ const ARRAY_DISPATCH_RE = /(?:\(\s*\*\s*)?\b(\w+)\s*\[[^\][]*\]\s*\)?\s*\(/g;
418
+ /** Field←field propagation sites: `a->f = b->g`. */
419
+ const FIELD_ASSIGN_RE = /(\w+)\s*(?:->|\.)\s*(\w+)\s*=\s*(\w+)\s*(?:->|\.)\s*(\w+)/g;
420
+ const NO_INCLUDES = [];
421
+ async function cFnPointerDispatchEdges(_queries, ctx, onYield, onFraction) {
422
+ let scannedFiles = 0;
423
+ const files = ctx.getAllFiles().filter((f) => C_CPP_EXT.test(f));
424
+ if (files.length === 0)
425
+ return [];
426
+ // CODEGRAPH_SYNTH_TIMINGS sub-attribution: this pass is 86% of kernel-scale
427
+ // synthesis (306s, §7a.2/§7a.3) — per-stage walls + read/strip accounting
428
+ // name which stage and which cost class owns it. Post-refactor mapping:
429
+ // A = extraction sweep, B = struct-layout linking, C = registration,
430
+ // D = propagation, E = dispatch.
431
+ const prof = process.env.CODEGRAPH_SYNTH_TIMINGS
432
+ ? { A: 0, B: 0, C: 0, D: 0, E: 0, readMs: 0, readN: 0, stripMs: 0, stripN: 0, nodesMs: 0, nodesN: 0 }
433
+ : null;
434
+ // Within-pass progress: this is the pass that parks the "Linking dynamic
435
+ // dispatch" bar on C-heavy repos, so it reports a real fraction of its
436
+ // dominant work. `files` is swept once per stage loop below (extraction,
437
+ // registration, propagation, dispatch), reported at the same per-16-files
438
+ // cadence as the cooperative yield.
439
+ const FILE_SWEEPS = 4;
440
+ const tick = async () => {
441
+ if ((++scannedFiles & 15) === 0) {
442
+ onFraction?.(scannedFiles / (files.length * FILE_SWEEPS));
443
+ await onYield();
444
+ }
445
+ };
446
+ // Cache raw + stripped source per file, LRU-BOUNDED. The old unbounded Maps
447
+ // retained every C/C++ file's raw AND stripped text for the whole pass —
448
+ // multiple GB on the Linux kernel, one of the two OOM culprits in #1212.
449
+ // The extraction sweep reads sequentially; the linking stages re-request
450
+ // only surviving files (plus include units), so access is near-sequential
451
+ // and a small LRU hits; a miss just re-reads + re-strips.
452
+ // Cache sizing is memory-budget-aware AND all-or-nothing (§7a.3 cFnPtr
453
+ // round): a partial LRU is WORSE than useless for cyclic sweeps (a first
454
+ // attempt sized ~61k against 63.8k files thrashed to a ~0% cross-sweep hit
455
+ // rate). Hold every stripped file (~24KB each measured on the Linux tree)
456
+ // only when 40% of the live memory budget covers it; otherwise keep the
457
+ // within-stage-locality 128. When the big cache declines (the kernel), the
458
+ // survival filters keep the linking stages' re-strips to a fraction of a
459
+ // sweep. Slack over files.length: non-indexed includes (.def/.inc, generated
460
+ // headers) join the working set mid-pass. Pass-scoped transient, freed on
461
+ // return.
462
+ const fullCacheCap = Math.ceil(files.length * 1.05) + 512;
463
+ const cacheCap = (0, memory_budget_1.memoryBudgetBytes)() * 0.5 >= fullCacheCap * 24_576 ? fullCacheCap : 128;
464
+ const rawCache = new lru_cache_1.LRUCache(Math.min(cacheCap, 4096));
465
+ const raw = (file) => {
466
+ if (rawCache.has(file))
467
+ return rawCache.get(file);
468
+ const t0 = prof ? Date.now() : 0;
469
+ const r = ctx.readFile(file);
470
+ if (prof) {
471
+ prof.readMs += Date.now() - t0;
472
+ prof.readN++;
473
+ }
474
+ rawCache.set(file, r);
475
+ return r;
476
+ };
477
+ const srcCache = new lru_cache_1.LRUCache(cacheCap);
478
+ const src = (file) => {
479
+ // A cached '' (empty or unreadable file) returns '' where the miss path
480
+ // returns null for unreadable — every caller falsy-checks, so the two are
481
+ // interchangeable.
482
+ const hit = srcCache.get(file);
483
+ if (hit !== undefined)
484
+ return hit;
485
+ const r = raw(file);
486
+ const t0 = prof ? Date.now() : 0;
487
+ const s = r == null ? '' : (0, strip_comments_1.stripCommentsForRegex)(r, 'c');
488
+ if (prof) {
489
+ prof.stripMs += Date.now() - t0;
490
+ prof.stripN++;
491
+ }
492
+ srcCache.set(file, s);
493
+ return r == null ? null : s;
494
+ };
495
+ // Resolve a quoted include relative to the includer's directory, then the
496
+ // project root. Returns a project-root-relative path that exists on disk
497
+ // (even if it was never indexed — e.g. redis' generated `commands.def`).
498
+ const resolveInclude = (includer, inc) => {
499
+ const dir = path.posix.dirname(includer.replace(/\\/g, '/'));
500
+ const cand = path.posix.normalize(path.posix.join(dir, inc));
501
+ if (ctx.fileExists(cand))
502
+ return cand;
503
+ if (ctx.fileExists(inc))
504
+ return inc;
505
+ return null;
506
+ };
507
+ // Retained strings are interned through here. Regex captures off a big file
508
+ // string are V8 sliced strings — retaining one pins the whole parent file
509
+ // text, and the facts tables retain captures from EVERY file for the whole
510
+ // pass. The Buffer round-trip forces a flat copy on first sight; repeats
511
+ // (field names recur heavily) then share the one flat instance.
512
+ const interned = new Map();
513
+ const intern = (x) => {
514
+ let f = interned.get(x);
515
+ if (f === undefined) {
516
+ f = Buffer.from(x, 'utf8').toString('utf8');
517
+ interned.set(f, f);
518
+ }
519
+ return f;
520
+ };
521
+ // ---- Global tables the extraction sweep fills ----
522
+ // fn-pointer: typedef RET (*NAME)(…) → a field `NAME f` is a fn ptr
523
+ // fn-type: typedef RET NAME(params) → a field `NAME *f` is a fn ptr
524
+ // The fn-type form is redis' command idiom: `typedef void redisCommandProc(client*)`
525
+ // declared as `redisCommandProc *proc;`. Without this, `proc` reads as data.
526
+ const fnPtrTypedefs = new Set();
527
+ const fnTypeTypedefs = new Set();
528
+ /** Struct node id → its structurally-parsed fields (classified + registered
529
+ * in the linking stage, in kind-scan order). */
530
+ const rawFieldsByNode = new Map();
531
+ const factsByFile = new Map();
532
+ /** Every inline-struct candidate tag anywhere — an over-approximation of the
533
+ * tags the registration stage can add to `structLayout` mid-stage, folded
534
+ * into the registration filter's layout check. */
535
+ const inlineTags = new Set();
536
+ /** Object-macro names with an alias-shaped value anywhere (see OBJ_ALIAS_RE). */
537
+ const aliasNames = new Set();
538
+ // Parse a struct body (the text between its `{` and `}`) into ordered fields,
539
+ // structure only — see RawFieldDecl for why classification is deferred.
540
+ const parseStructFieldsRaw = (inner) => {
541
+ const fields = [];
542
+ let idx = 0;
543
+ for (const rawDecl of splitTopLevel(inner, ';')) {
544
+ const decl = rawDecl.trim();
545
+ if (!decl)
546
+ continue;
547
+ // A field decl can declare several names sharing a leading type:
548
+ // `struct redisCommand *cmd, *lastcmd;`. Each declarator is its own
549
+ // positional slot and carries that type (so `client.cmd → redisCommand`).
550
+ const parts = splitTopLevel(decl, ',');
551
+ const firstTyped = parts[0].match(/(\w+)\s+\**\s*(\w+)\s*$/);
552
+ const sharedType = firstTyped ? firstTyped[1] : '';
553
+ for (let pi = 0; pi < parts.length; pi++) {
554
+ const p = parts[pi].trim();
555
+ let name = null;
556
+ let type = '';
557
+ let ptr = false;
558
+ const pm = p.match(FNPTR_DECL_RE);
559
+ if (pm) {
560
+ name = pm[1]; // `… (*name)(…)` — a function pointer
561
+ ptr = true;
562
+ }
563
+ else if (pi === 0) {
564
+ if (firstTyped) {
565
+ name = firstTyped[2];
566
+ type = sharedType;
567
+ }
568
+ }
569
+ else {
570
+ // a subsequent declarator: `*name` / `**name` / `name`
571
+ const dm = p.match(/^\**\s*(\w+)/);
572
+ if (dm) {
573
+ name = dm[1];
574
+ type = sharedType;
575
+ }
576
+ }
577
+ // Always advance the positional index. An unparsed field (anonymous
578
+ // union, exotic declarator) still occupies one slot, and macro-expanded
579
+ // positional tables (redis' MAKE_CMD) only align if every field counts.
580
+ fields.push({ name, index: idx, ptr, type });
581
+ idx++;
582
+ }
583
+ }
584
+ return fields;
585
+ };
586
+ // Classify deferred fields against the (now-complete) typedef sets.
587
+ const classifyFields = (rawFields) => rawFields.map((f) => ({
588
+ name: f.name ?? '',
589
+ index: f.index,
590
+ isFnPtr: !!f.name &&
591
+ (f.ptr || (!!f.type && (fnPtrTypedefs.has(f.type) || fnTypeTypedefs.has(f.type)))),
592
+ type: f.type,
593
+ }));
594
+ const parseStructFields = (inner) => classifyFields(parseStructFieldsRaw(inner));
595
+ // Exact per-file include resolution (from RAW source — string contents survive).
596
+ const scanIncludes = (file) => {
597
+ const rawText = raw(file);
598
+ if (!rawText || !rawText.includes('include'))
599
+ return NO_INCLUDES;
600
+ const out = [];
601
+ INCLUDE_RE.lastIndex = 0;
602
+ let im;
603
+ while ((im = INCLUDE_RE.exec(rawText))) {
604
+ if (!INCLUDABLE_EXT.test(im[1]))
605
+ continue;
606
+ const t = resolveInclude(file, im[1]);
607
+ if (t)
608
+ out.push(intern(t));
609
+ }
610
+ return out.length ? out : NO_INCLUDES;
611
+ };
612
+ // Indexed files answer from their facts; non-indexed includes (reached by
613
+ // buildEnv's depth-2 recursion) fall back to a bounded lazy scan.
614
+ const includeCache = new lru_cache_1.LRUCache(1024);
615
+ const localIncludesOf = (file) => {
616
+ const f = factsByFile.get(file);
617
+ if (f)
618
+ return f.includes;
619
+ let out = includeCache.get(file);
620
+ if (out)
621
+ return out;
622
+ out = scanIncludes(file);
623
+ includeCache.set(file, out);
624
+ return out;
625
+ };
626
+ // ---- Stage A: the extraction sweep — ONE read + strip per file ----
627
+ //
628
+ // Two implementations, record-identical by the differential suite:
629
+ // • native (task #5 step 2): the kernel's `cfnptrScanFiles` strips and
630
+ // scans a BATCH of files per NAPI call (codegraph-kernel/src/cfnptr.rs —
631
+ // hand-rolled byte machines replicating the JS regex semantics), and the
632
+ // TS side only reads files, ships batches, and interns the returned
633
+ // facts. Include-path resolution stays here (it needs the filesystem).
634
+ // • JS: the original sweep, kept verbatim — the fallback for platforms
635
+ // without a kernel binary, older binaries (feature detection), the
636
+ // CODEGRAPH_KERNEL=0 kill switch, and CODEGRAPH_KERNEL_CFNPTR=0 (this
637
+ // scanner's own switch).
638
+ const kernel = process.env.CODEGRAPH_KERNEL === '0' || process.env.CODEGRAPH_KERNEL_CFNPTR === '0'
639
+ ? null
640
+ : (0, loader_1.getKernel)();
641
+ const nativeSweep = kernel && typeof kernel.cfnptrScanFiles === 'function' ? kernel.cfnptrScanFiles.bind(kernel) : null;
642
+ const mergeNativeFacts = (file, out) => {
643
+ for (const t of out.fnPtrTypedefs)
644
+ fnPtrTypedefs.add(intern(t));
645
+ for (const t of out.fnTypeTypedefs)
646
+ fnTypeTypedefs.add(intern(t));
647
+ for (const so of out.structs) {
648
+ if (!so.parsed)
649
+ continue; // body never parsed — the JS sweep records nothing either
650
+ rawFieldsByNode.set(so.id, so.fields.map((f) => ({ name: f.name || null, index: f.index, ptr: f.ptr, type: f.type })));
651
+ }
652
+ for (const t of out.inlineTags)
653
+ inlineTags.add(intern(t));
654
+ for (const t of out.aliasNames)
655
+ aliasNames.add(intern(t));
656
+ const includes = [];
657
+ for (const cap of out.includes) {
658
+ if (!INCLUDABLE_EXT.test(cap))
659
+ continue;
660
+ const t = resolveInclude(file, cap);
661
+ if (t)
662
+ includes.push(intern(t));
663
+ }
664
+ if (out.initTokens.length || out.arrayElems.length || out.inlinePtr || out.inlineTypes.length ||
665
+ out.dPairs.length || out.dispatchFields.length || out.arrayDispatchNames.length || includes.length) {
666
+ factsByFile.set(file, {
667
+ initTokens: out.initTokens.length ? out.initTokens.map(intern) : null,
668
+ arrayElems: out.arrayElems.length ? out.arrayElems.map(intern) : null,
669
+ inlinePtr: out.inlinePtr,
670
+ inlineTypes: out.inlineTypes.length ? out.inlineTypes.map(intern) : null,
671
+ dPairs: out.dPairs.length ? out.dPairs.map(intern) : null,
672
+ dispatchFields: out.dispatchFields.length ? out.dispatchFields.map(intern) : null,
673
+ arrayDispatchNames: out.arrayDispatchNames.length ? out.arrayDispatchNames.map(intern) : null,
674
+ includes: includes.length ? includes : NO_INCLUDES,
675
+ });
676
+ }
677
+ };
678
+ let tPass = Date.now();
679
+ if (nativeSweep) {
680
+ // Batch of 16 = the tick/onFraction cadence, so yielding and progress
681
+ // reporting keep their shape while the boundary crossing amortizes.
682
+ const BATCH = 16;
683
+ let batch = [];
684
+ const flush = () => {
685
+ if (batch.length === 0)
686
+ return;
687
+ const outs = nativeSweep(batch.map((b) => b.input));
688
+ for (let bi = 0; bi < batch.length; bi++)
689
+ mergeNativeFacts(batch[bi].file, outs[bi]);
690
+ batch = [];
691
+ };
692
+ for (const file of files) {
693
+ await tick();
694
+ const rawText = raw(file);
695
+ if (!rawText)
696
+ continue; // unreadable or empty — the JS sweep skips these too
697
+ const tN = prof ? Date.now() : 0;
698
+ const fileNodes = ctx.getNodesInFile(file);
699
+ if (prof) {
700
+ prof.nodesMs += Date.now() - tN;
701
+ prof.nodesN++;
702
+ }
703
+ const structs = [];
704
+ for (const st of fileNodes) {
705
+ if (st.kind !== 'struct' && st.kind !== 'union')
706
+ continue;
707
+ // sliceLinesPre semantics ride along: falsy startLine never parses,
708
+ // and `endLine ?? startLine` is applied here so the kernel sees the
709
+ // exact slice bounds the JS sweep would use.
710
+ structs.push({ id: st.id, startLine: st.startLine ?? 0, endLine: st.endLine ?? st.startLine ?? 0 });
711
+ }
712
+ batch.push({ file, input: { text: rawText, structs } });
713
+ if (batch.length >= BATCH)
714
+ flush();
715
+ }
716
+ flush();
717
+ }
718
+ // JS sweep (fallback path — see the stage comment above).
719
+ if (!nativeSweep)
720
+ for (const file of files) {
721
+ await tick();
722
+ const s = src(file);
723
+ if (!s)
724
+ continue;
725
+ // Typedefs (cross-file).
726
+ if (s.includes('typedef')) {
727
+ FNPTR_TYPEDEF_RE.lastIndex = 0;
728
+ let m;
729
+ while ((m = FNPTR_TYPEDEF_RE.exec(s)))
730
+ fnPtrTypedefs.add(intern(m[1]));
731
+ FNTYPE_TYPEDEF_STMT_RE.lastIndex = 0;
732
+ while ((m = FNTYPE_TYPEDEF_STMT_RE.exec(s))) {
733
+ const guts = m[1];
734
+ if (guts.includes('(*') || guts.includes('( *'))
735
+ continue; // pointer form — handled above
736
+ const fm = guts.match(/\b(\w+)\s*\(/); // last identifier before the param list
737
+ if (fm && !C_TYPE_KEYWORDS.has(fm[1]))
738
+ fnTypeTypedefs.add(intern(fm[1]));
739
+ }
740
+ }
741
+ // Struct-node field declarations (registered later in kind-scan order).
742
+ const tN = prof ? Date.now() : 0;
743
+ const fileNodes = ctx.getNodesInFile(file);
744
+ if (prof) {
745
+ prof.nodesMs += Date.now() - tN;
746
+ prof.nodesN++;
747
+ }
748
+ let lines = null;
749
+ for (const st of fileNodes) {
750
+ if (st.kind !== 'struct' && st.kind !== 'union')
751
+ continue;
752
+ lines ??= s.split('\n');
753
+ const body = sliceLinesPre(lines, st.startLine, st.endLine);
754
+ const open = body.indexOf('{');
755
+ const close = open >= 0 ? matchBrace(body, open) : -1;
756
+ if (open < 0 || close < 0)
757
+ continue;
758
+ rawFieldsByNode.set(st.id, parseStructFieldsRaw(body.slice(open + 1, close)));
759
+ }
760
+ // Registration filters. These are full-file, NO-SKIP scans: the original
761
+ // registration pass jumps its scan cursor past a processed initializer
762
+ // body, so a no-skip scan finds a SUPERSET of its matches — exactly the
763
+ // over-approximation the filter needs.
764
+ const initTokens = new Set();
765
+ const arrayElems = new Set();
766
+ const inlineTypes = new Set();
767
+ let inlinePtr = false;
768
+ if (s.includes('{')) {
769
+ INLINE_STRUCT_RE.lastIndex = 0;
770
+ let im;
771
+ while ((im = INLINE_STRUCT_RE.exec(s))) {
772
+ const sOpen = im.index + im[0].length - 1;
773
+ const sClose = matchBrace(s, sOpen);
774
+ if (sClose < 0)
775
+ continue;
776
+ // After `}`, expect `var [opt] [= {…}]` to be a table candidate.
777
+ const vm = s.slice(sClose + 1).match(/^\s*(\w+)\s*(\[[^\]]*\])?\s*(=\s*\{)?/);
778
+ if (!vm || !vm[1])
779
+ continue;
780
+ inlineTags.add(intern(im[1]));
781
+ for (const f of parseStructFieldsRaw(s.slice(sOpen + 1, sClose))) {
782
+ if (!f.name)
783
+ continue;
784
+ if (f.ptr)
785
+ inlinePtr = true;
786
+ else if (f.type)
787
+ inlineTypes.add(intern(f.type));
788
+ }
789
+ }
790
+ if (s.includes('=')) {
791
+ INIT_RE.lastIndex = 0;
792
+ let m;
793
+ while ((m = INIT_RE.exec(s)))
794
+ initTokens.add(intern(m[1]));
795
+ ARRAY_TABLE_RE.lastIndex = 0;
796
+ while ((m = ARRAY_TABLE_RE.exec(s)))
797
+ arrayElems.add(intern((m[2] ? '*' : '') + m[1]));
798
+ }
799
+ }
800
+ // Alias-shaped object macros (registration filter support).
801
+ if (s.includes('#define') || s.includes('# define')) {
802
+ const joined = s.replace(/\\\r?\n/g, ' ');
803
+ OBJ_ALIAS_RE.lastIndex = 0;
804
+ let m;
805
+ while ((m = OBJ_ALIAS_RE.exec(joined)))
806
+ aliasNames.add(intern(m[1]));
807
+ }
808
+ // Propagation + dispatch filters (full-file scans ⊇ the per-function-body
809
+ // scans the pass bodies run — a body slice is a substring of the file).
810
+ const dPairs = new Set();
811
+ if (s.includes('=')) {
812
+ FIELD_ASSIGN_RE.lastIndex = 0;
813
+ let m;
814
+ while ((m = FIELD_ASSIGN_RE.exec(s)))
815
+ dPairs.add(intern(m[2] + '\0' + m[4]));
816
+ }
817
+ const dispatchFields = new Set();
818
+ const arrayNames = new Set();
819
+ DISPATCH_RE.lastIndex = 0;
820
+ let dm;
821
+ while ((dm = DISPATCH_RE.exec(s)))
822
+ dispatchFields.add(intern(dm[2]));
823
+ ARRAY_DISPATCH_RE.lastIndex = 0;
824
+ while ((dm = ARRAY_DISPATCH_RE.exec(s)))
825
+ arrayNames.add(intern(dm[1]));
826
+ const includes = scanIncludes(file);
827
+ if (initTokens.size || arrayElems.size || inlinePtr || inlineTypes.size ||
828
+ dPairs.size || dispatchFields.size || arrayNames.size || includes.length) {
829
+ factsByFile.set(file, {
830
+ initTokens: initTokens.size ? [...initTokens] : null,
831
+ arrayElems: arrayElems.size ? [...arrayElems] : null,
832
+ inlinePtr,
833
+ inlineTypes: inlineTypes.size ? [...inlineTypes] : null,
834
+ dPairs: dPairs.size ? [...dPairs] : null,
835
+ dispatchFields: dispatchFields.size ? [...dispatchFields] : null,
836
+ arrayDispatchNames: arrayNames.size ? [...arrayNames] : null,
837
+ includes,
838
+ });
839
+ }
840
+ }
841
+ if (prof) {
842
+ prof.A = Date.now() - tPass;
843
+ tPass = Date.now();
844
+ }
845
+ // ---- Stage B: struct field layouts (linking — text-free) ----
846
+ // structLayout: struct name → ordered fields, for structs with ≥1 fn-pointer
847
+ // field (drives positional registration + dispatch).
848
+ // allStructFields: EVERY struct name → ALL its field layouts (a name can be
849
+ // reused across files — e.g. redis has two unrelated `client` structs), used
850
+ // to walk a chained receiver's field types (`c->cmd->proc`: client.cmd →
851
+ // redisCommand). The walk searches every same-named layout for the field.
852
+ // fieldToStructs: fn-pointer field name → set of struct names that declare it.
853
+ // Registration REPLAYS the struct kind-scan (rowid order, ≠ the extraction
854
+ // sweep's path order): same-name layout precedence — `structLayout.set`
855
+ // last-wins, `allStructFields` first-match in the chain walk — depends on it.
856
+ const structLayout = new Map();
857
+ const allStructFields = new Map();
858
+ const fieldToStructs = new Map();
859
+ // Register a parsed struct under `name` into the three indexes.
860
+ const registerStructLayout = (name, fields) => {
861
+ if (!allStructFields.has(name))
862
+ allStructFields.set(name, []);
863
+ allStructFields.get(name).push(fields);
864
+ for (const f of fields) {
865
+ if (f.name && f.isFnPtr) {
866
+ if (!fieldToStructs.has(f.name))
867
+ fieldToStructs.set(f.name, new Set());
868
+ fieldToStructs.get(f.name).add(name);
869
+ }
870
+ }
871
+ if (fields.some((f) => f.isFnPtr))
872
+ structLayout.set(name, fields);
873
+ };
874
+ for (const kind of ['struct', 'union']) {
875
+ for (const st of (ctx.iterateNodesByKind?.(kind) ?? ctx.getNodesByKind(kind))) {
876
+ if ((++scannedFiles & 255) === 0)
877
+ await onYield();
878
+ if (!C_CPP_EXT.test(st.filePath))
879
+ continue;
880
+ const rawFields = rawFieldsByNode.get(st.id);
881
+ if (!rawFields)
882
+ continue; // file unreadable or body unparsable at sweep time — the old pass skipped it too
883
+ registerStructLayout(st.name, classifyFields(rawFields));
884
+ }
885
+ }
886
+ rawFieldsByNode.clear();
887
+ if (prof) {
888
+ prof.B = Date.now() - tPass;
889
+ tPass = Date.now();
890
+ }
891
+ // NB: no early return on an empty structLayout here — an inline `struct TAG
892
+ // { … } var[]` table whose struct never became a node (vim's `cmdname`, broken
893
+ // up by `#ifdef`) is discovered later during the unit scan. The `reg.size === 0`
894
+ // guard after registration still short-circuits when nothing bridges.
895
+ const fnPtrFieldOf = (struct, field) => !!structLayout.get(struct)?.some((f) => f.name === field && f.isFnPtr);
896
+ // C/C++ function + method nodes are STREAMED per stage (see D/E) —
897
+ // the old materialized `cFns` array held every function node on the repo
898
+ // (O(nodes) memory, part of the #1212 kernel OOM).
899
+ // ---- function-name → node resolution (prefer a function in the same file) ----
900
+ const resolveFn = (name, preferFile) => {
901
+ const cands = ctx.getNodesByName(name).filter((n) => FN_KINDS.has(n.kind));
902
+ if (cands.length === 0)
903
+ return null;
904
+ if (cands.length === 1)
905
+ return cands[0];
906
+ if (preferFile) {
907
+ const same = cands.find((n) => n.filePath === preferFile);
908
+ if (same)
909
+ return same;
910
+ }
911
+ return cands[0];
912
+ };
913
+ // ---- Stage C: registrations — Map<"struct.field", Set<funcNodeId>> ----
914
+ // Ids only — retaining the full Node per registration (the old `idToNode`)
915
+ // was write-only dead weight at O(registrations) memory.
916
+ const reg = new Map();
917
+ const addReg = (struct, field, fn) => {
918
+ const key = `${struct}.${field}`;
919
+ if (!reg.has(key))
920
+ reg.set(key, new Set());
921
+ reg.get(key).add(fn.id);
922
+ };
923
+ // Bare arrays-of-fn-pointers (no struct): array VARIABLE name → per-file sets
924
+ // of registered function ids. Multi-entry because a file-scope `static` table
925
+ // name can recur across files (SameBoy declares `static opcode_t *opcodes[256]`
926
+ // in BOTH sm83_cpu.c and sm83_disassembler.c), so dispatch resolves same-file.
927
+ const arrayReg = new Map();
928
+ const addArrayReg = (name, file, fn) => {
929
+ let entries = arrayReg.get(name);
930
+ if (!entries) {
931
+ entries = [];
932
+ arrayReg.set(name, entries);
933
+ }
934
+ let e = entries.find((x) => x.file === file);
935
+ if (!e) {
936
+ e = { file, ids: new Set() };
937
+ entries.push(e);
938
+ }
939
+ e.ids.add(fn.id);
940
+ };
941
+ // A struct value `{ … }` (one element) — register its function entries to the
942
+ // struct's fields, by `.field = fn` designators or by positional slot.
943
+ const registerStructValue = (struct, valueBody, file, env) => {
944
+ const layout = structLayout.get(struct);
945
+ if (!layout)
946
+ return;
947
+ if (env && env.size)
948
+ valueBody = expandMacroCalls(valueBody, env);
949
+ // A macro can expand to a whole brace-wrapped element (sqlite's
950
+ // `FUNCTION(…)` → `{nArg, …, xFunc, …}`); peel one outer layer so the
951
+ // positional slots are visible.
952
+ valueBody = valueBody.trim();
953
+ if (valueBody.startsWith('{')) {
954
+ const e = matchBrace(valueBody, 0);
955
+ if (e > 0 && valueBody.slice(e + 1).trim() === '')
956
+ valueBody = valueBody.slice(1, e);
957
+ }
958
+ const items = splitTopLevel(valueBody, ',');
959
+ let pos = 0;
960
+ for (const rawItem of items) {
961
+ const item = rawItem.trim();
962
+ if (!item)
963
+ continue;
964
+ const des = item.match(/^\.\s*(\w+)\s*=\s*(?:&\s*)?(\w+)\s*$/);
965
+ if (des) {
966
+ const field = des[1];
967
+ if (fnPtrFieldOf(struct, field)) {
968
+ const fn = resolveFn(des[2], file);
969
+ if (fn)
970
+ addReg(struct, field, fn);
971
+ }
972
+ // a designated item does not advance positional counting
973
+ continue;
974
+ }
975
+ const field = layout.find((f) => f.index === pos);
976
+ if (field?.isFnPtr) {
977
+ const id = item.match(/^&?\s*(\w+)\s*$/);
978
+ if (id) {
979
+ const fn = resolveFn(id[1], file);
980
+ if (fn)
981
+ addReg(struct, field.name, fn);
982
+ }
983
+ }
984
+ pos++;
985
+ }
986
+ };
987
+ // Collect the literal function entries of an array-of-fn-pointers initializer
988
+ // and register them under the array's variable name. Entries may be positional
989
+ // (`fn`, `&fn`), designated by index (`[OP] = fn`), or cast-wrapped
990
+ // (`(handler_t)fn`, as in php's Zend dtor table). Non-identifier entries
991
+ // (`NULL`, `0`, a nested expression) are skipped — a miss, never a wrong edge.
992
+ // No index tracking: a runtime subscript fans the dispatch out to the whole
993
+ // set, exactly like a command table reaches every command.
994
+ const registerArrayValue = (name, body, file, env) => {
995
+ if (env && env.size)
996
+ body = expandMacroCalls(body, env);
997
+ for (const rawItem of splitTopLevel(body, ',')) {
998
+ let item = rawItem.trim();
999
+ if (!item)
1000
+ continue;
1001
+ const des = item.match(/^\[[^\]]*\]\s*=\s*([\s\S]*)$/); // `[IDX] = …` designator
1002
+ if (des)
1003
+ item = des[1].trim();
1004
+ item = item.replace(/^\((?:[\w\s*]+)\)\s*/, '').replace(/^&\s*/, '').trim(); // (cast) / &
1005
+ const id = item.match(/^(\w+)$/);
1006
+ if (!id)
1007
+ continue;
1008
+ const fn = resolveFn(id[1], file);
1009
+ if (fn)
1010
+ addArrayReg(name, file, fn);
1011
+ }
1012
+ };
1013
+ // Per-file macro + include parsing (any file, indexed or not), cached.
1014
+ // Derived per-file caches, LRU-bounded like the content caches (#1212).
1015
+ // These stay LAZY (recompute-on-miss through `src`): retaining every file's
1016
+ // parsed tables is ruled out by the kernel's 6.1M `#define`s, and the
1017
+ // registration stage below only builds an env for files that survive its
1018
+ // filter or carry local includes, so most files never need one.
1019
+ const fnMacroCache = new lru_cache_1.LRUCache(256);
1020
+ const fileFnMacros = (file) => {
1021
+ let m = fnMacroCache.get(file);
1022
+ if (!m) {
1023
+ m = parseFunctionMacros(src(file) ?? '');
1024
+ fnMacroCache.set(file, m);
1025
+ }
1026
+ return m;
1027
+ };
1028
+ const objMacroCache = new lru_cache_1.LRUCache(256);
1029
+ const fileObjMacros = (file) => {
1030
+ let m = objMacroCache.get(file);
1031
+ if (!m) {
1032
+ m = parseObjectMacros(src(file) ?? '');
1033
+ objMacroCache.set(file, m);
1034
+ }
1035
+ return m;
1036
+ };
1037
+ const definedCache = new lru_cache_1.LRUCache(256);
1038
+ const fileDefinedNames = (file) => {
1039
+ let d = definedCache.get(file);
1040
+ if (!d) {
1041
+ d = parseDefinedNames(src(file) ?? '');
1042
+ definedCache.set(file, d);
1043
+ }
1044
+ return d;
1045
+ };
1046
+ // A file's effective macro environment = its own #defines PLUS those of the
1047
+ // headers it #includes (redis' `MAKE_CMD` sits beside the table; sqlite's
1048
+ // `FUNCTION` lives in `sqliteInt.h`, included by the file with the table).
1049
+ // First writer wins, so the file's own defs override included ones; depth-2
1050
+ // covers a macro defined in a header-of-a-header.
1051
+ const buildEnv = (file, depth, seen, fn, obj, def) => {
1052
+ if (depth < 0 || seen.has(file))
1053
+ return;
1054
+ seen.add(file);
1055
+ for (const [k, v] of fileFnMacros(file))
1056
+ if (!fn.has(k))
1057
+ fn.set(k, v);
1058
+ for (const [k, v] of fileObjMacros(file))
1059
+ if (!obj.has(k))
1060
+ obj.set(k, v);
1061
+ for (const n of fileDefinedNames(file))
1062
+ def.add(n);
1063
+ for (const inc of localIncludesOf(file))
1064
+ buildEnv(inc, depth - 1, seen, fn, obj, def);
1065
+ };
1066
+ const indexedSet = new Set(files);
1067
+ const seenInclude = new Set();
1068
+ // Global variable → struct type, for resolving a dispatch through a file-scope
1069
+ // table by subscript (`cmdnames[i].cmd_func(…)`).
1070
+ const globalVarType = new Map();
1071
+ // Process a `{ … }` initializer body (array of elements or a single struct).
1072
+ const processInit = (struct, body, isArray, file, env) => {
1073
+ if (isArray) {
1074
+ for (const el of splitTopLevel(body, ',')) {
1075
+ const t = el.trim();
1076
+ if (t.startsWith('{')) {
1077
+ const e = matchBrace(t, 0);
1078
+ if (e > 0)
1079
+ registerStructValue(struct, t.slice(1, e), file, env);
1080
+ }
1081
+ else if (t) {
1082
+ // an element built by a macro (`MAKE_CMD(…)`/`FUNCTION(…)`) or a bare value
1083
+ registerStructValue(struct, t, file, env);
1084
+ }
1085
+ }
1086
+ }
1087
+ else {
1088
+ registerStructValue(struct, body, file, env);
1089
+ }
1090
+ };
1091
+ // Process ONE unit's text and discard it. The old shape built every unit up
1092
+ // front (`const units: Unit[]`) — the full text of every C file plus its
1093
+ // expanded includes held simultaneously, gigabytes on the kernel (#1212).
1094
+ const processUnit = (unit) => {
1095
+ const s = unit.text;
1096
+ if (!s || !s.includes('{'))
1097
+ return;
1098
+ INLINE_STRUCT_RE.lastIndex = 0;
1099
+ let im;
1100
+ while ((im = INLINE_STRUCT_RE.exec(s))) {
1101
+ const tag = im[1];
1102
+ const sOpen = im.index + im[0].length - 1; // the struct body's `{`
1103
+ const sClose = matchBrace(s, sOpen);
1104
+ if (sClose < 0)
1105
+ continue;
1106
+ // After `}`, expect `var [opt] [= {…}]` to be a table; else it's a plain type.
1107
+ const after = s.slice(sClose + 1);
1108
+ const vm = after.match(/^\s*(\w+)\s*(\[[^\]]*\])?\s*(=\s*\{)?/);
1109
+ if (!vm || !vm[1])
1110
+ continue;
1111
+ const fields = parseStructFields(s.slice(sOpen + 1, sClose));
1112
+ if (!fields.some((f) => f.isFnPtr))
1113
+ continue; // only tables of fn pointers matter
1114
+ if (!structLayout.has(tag))
1115
+ registerStructLayout(tag, fields);
1116
+ globalVarType.set(vm[1], tag);
1117
+ if (vm[3]) {
1118
+ const aOpen = sClose + 1 + after.indexOf('{', vm[0].length - 1);
1119
+ const aClose = matchBrace(s, aOpen);
1120
+ if (aClose > 0) {
1121
+ processInit(tag, s.slice(aOpen + 1, aClose), !!vm[2], unit.file, unit.env);
1122
+ INLINE_STRUCT_RE.lastIndex = aClose;
1123
+ }
1124
+ }
1125
+ }
1126
+ if (!s.includes('='))
1127
+ return;
1128
+ INIT_RE.lastIndex = 0;
1129
+ let m;
1130
+ while ((m = INIT_RE.exec(s))) {
1131
+ let struct = m[1];
1132
+ if (!structLayout.has(struct))
1133
+ struct = resolveTypeName(struct, unit.objEnv);
1134
+ if (!structLayout.has(struct))
1135
+ continue;
1136
+ const isArray = !!m[3];
1137
+ const open = m.index + m[0].length - 1; // points at the `{`
1138
+ const close = matchBrace(s, open);
1139
+ if (close < 0)
1140
+ continue;
1141
+ globalVarType.set(m[2], struct);
1142
+ processInit(struct, s.slice(open + 1, close), isArray, unit.file, unit.env);
1143
+ INIT_RE.lastIndex = close;
1144
+ }
1145
+ // Bare arrays-of-function-pointers (no struct, no field). Gated on the
1146
+ // element type being a function typedef — a fn-TYPE typedef needs the `*`
1147
+ // (array of pointers to it), a fn-pointer typedef does not. A data or
1148
+ // struct array's element type is never in these sets, so it never fires.
1149
+ ARRAY_TABLE_RE.lastIndex = 0;
1150
+ let am;
1151
+ while ((am = ARRAY_TABLE_RE.exec(s))) {
1152
+ const elemType = am[1];
1153
+ const hasStar = !!am[2];
1154
+ if (!((fnTypeTypedefs.has(elemType) && hasStar) || fnPtrTypedefs.has(elemType)))
1155
+ continue;
1156
+ const open = am.index + am[0].length - 1; // the `{`
1157
+ const close = matchBrace(s, open);
1158
+ if (close < 0)
1159
+ continue;
1160
+ registerArrayValue(am[3], s.slice(open + 1, close), unit.file, unit.env);
1161
+ ARRAY_TABLE_RE.lastIndex = close;
1162
+ }
1163
+ };
1164
+ // Can this file's OWN unit have any side effect? Every check mirrors a gate
1165
+ // in processUnit, over-approximated to the filter's coarser knowledge:
1166
+ // • inline structs — the fn-ptr-field gate, with per-candidate field types
1167
+ // unioned per file;
1168
+ // • initializers — `structLayout.has` against the layouts' SUPERSET
1169
+ // (kind-scan layouts ∪ every inline tag — structLayout only grows during
1170
+ // this stage), with alias-shaped tokens surviving in place of the
1171
+ // per-file `resolveTypeName` walk;
1172
+ // • bare arrays — the exact typedef-set gate.
1173
+ // A filtered-out file is one where every match fails its gate before any
1174
+ // side effect, so skipping the unit cannot change the outcome.
1175
+ const typedefHit = (t) => fnPtrTypedefs.has(t) || fnTypeTypedefs.has(t);
1176
+ const regSurvives = (f) => f.inlinePtr ||
1177
+ (f.inlineTypes?.some(typedefHit) ?? false) ||
1178
+ (f.initTokens?.some((t) => structLayout.has(t) || inlineTags.has(t) || aliasNames.has(t)) ?? false) ||
1179
+ (f.arrayElems?.some((e) => e.charCodeAt(0) === 42 /* '*' */ ? typedefHit(e.slice(1)) : fnPtrTypedefs.has(e)) ?? false);
1180
+ // ---- Stage C: registrations — stream each surviving file (and every file's
1181
+ // qualifying local includes) through processUnit, one at a time.
1182
+ for (const file of files) {
1183
+ await tick();
1184
+ const facts = factsByFile.get(file);
1185
+ if (!facts)
1186
+ continue; // no facts ⇒ nothing matched at sweep time ⇒ the old pass would no-op here
1187
+ const survives = regSurvives(facts);
1188
+ if (!survives && facts.includes.length === 0)
1189
+ continue;
1190
+ const env = new Map();
1191
+ const objEnv = new Map();
1192
+ const defined = new Set();
1193
+ buildEnv(file, 2, new Set(), env, objEnv, defined);
1194
+ if (survives) {
1195
+ const s = src(file);
1196
+ if (s)
1197
+ processUnit({ text: s, file, env, objEnv });
1198
+ }
1199
+ for (const target of facts.includes) {
1200
+ if (seenInclude.has(`${file}>${target}`))
1201
+ continue;
1202
+ const incSrc = src(target);
1203
+ if (!incSrc)
1204
+ continue;
1205
+ if (indexedSet.has(target)) {
1206
+ // Re-scan an indexed header only when this includer unlocks guarded code.
1207
+ const ownDef = fileDefinedNames(target);
1208
+ const adds = [...defined].some((n) => !ownDef.has(n));
1209
+ if (!adds || !/#\s*if/.test(incSrc))
1210
+ continue;
1211
+ }
1212
+ seenInclude.add(`${file}>${target}`);
1213
+ // The include is pasted into the includer — evaluate its conditionals in
1214
+ // the includer's defined set (a no-op when it has none). Re-parse the
1215
+ // included file's OWN macros from that resolved text so a macro it defines
1216
+ // conditionally (vim's `EXCMD`, whose plain last-wins parse picks the enum
1217
+ // arm) overrides with the ARM THAT IS ACTUALLY ACTIVE here.
1218
+ const text = evalConditionals(incSrc, defined);
1219
+ const incEnv = new Map(env);
1220
+ for (const [k, v] of parseFunctionMacros(text))
1221
+ incEnv.set(k, v);
1222
+ const incObjEnv = new Map(objEnv);
1223
+ for (const [k, v] of parseObjectMacros(text))
1224
+ incObjEnv.set(k, v);
1225
+ processUnit({ text, file: target, env: incEnv, objEnv: incObjEnv });
1226
+ }
1227
+ }
1228
+ if (prof) {
1229
+ prof.C = Date.now() - tPass;
1230
+ tPass = Date.now();
1231
+ }
1232
+ // ---- receiver-type resolution within a function's source ----
1233
+ // `(?:struct )?TYPE [*]recv` declared in the params or body → TYPE (if a known
1234
+ // fn-pointer-bearing struct).
1235
+ const recvReCache = new Map();
1236
+ const recvTypeIn = (fnSrc, recv) => {
1237
+ let re = recvReCache.get(recv);
1238
+ if (!re) {
1239
+ re = new RegExp(`(?:(?:struct|union)\\s+)?(\\w+)\\s*\\*?\\s*\\b${recv}\\b\\s*(?:[,)=;]|\\[)`, 'g');
1240
+ recvReCache.set(recv, re);
1241
+ }
1242
+ re.lastIndex = 0;
1243
+ let m;
1244
+ while ((m = re.exec(fnSrc))) {
1245
+ if (structLayout.has(m[1]))
1246
+ return m[1];
1247
+ }
1248
+ return null;
1249
+ };
1250
+ // Declared type of a local/param `v` — ANY type token, not just fn-pointer
1251
+ // structs (the base of a chained receiver needn't carry a fn pointer itself).
1252
+ // Falls back to a file-scope table variable (`cmdnames` in `cmdnames[i].fn()`).
1253
+ const escapeRe = (x) => x.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1254
+ const varReCache = new Map();
1255
+ const varTypeIn = (fnSrc, v) => {
1256
+ let re = varReCache.get(v);
1257
+ if (!re) {
1258
+ re = new RegExp(`(?:(?:struct|union)\\s+)?(\\w+)\\s*\\*?\\s*\\b${escapeRe(v)}\\b\\s*(?:[,)=;]|\\[)`, 'g');
1259
+ varReCache.set(v, re);
1260
+ }
1261
+ re.lastIndex = 0;
1262
+ let m;
1263
+ while ((m = re.exec(fnSrc))) {
1264
+ if (!C_TYPE_KEYWORDS.has(m[1]))
1265
+ return m[1];
1266
+ }
1267
+ return globalVarType.get(v) ?? null;
1268
+ };
1269
+ // Resolve a member-access chain (`c->cmd`, or just `p`) to a struct type,
1270
+ // walking each segment's declared field type. `c->cmd->proc` dispatch:
1271
+ // base chain `c->cmd` → client.cmd's type `redisCommand`, the proc owner.
1272
+ // Array subscripts (`cmdnames[i]`) are stripped — an index yields one element.
1273
+ const resolveChainType = (fnSrc, chain) => {
1274
+ const segs = chain.replace(/\s*\[[^\]]*\]/g, '').split(/\s*(?:->|\.)\s*/).filter(Boolean);
1275
+ if (segs.length === 0)
1276
+ return null;
1277
+ let t = varTypeIn(fnSrc, segs[0]);
1278
+ for (let i = 1; t && i < segs.length; i++) {
1279
+ let next = null;
1280
+ for (const fields of allStructFields.get(t) ?? []) {
1281
+ const f = fields.find((fl) => fl.name === segs[i] && fl.type);
1282
+ if (f) {
1283
+ next = f.type;
1284
+ break;
1285
+ }
1286
+ }
1287
+ t = next;
1288
+ }
1289
+ return t;
1290
+ };
1291
+ // ---- Stage D: field←field propagation (`a->f = b->g`) ----
1292
+ // Collected as (targetStruct.field ← sourceStruct.field) pairs, then merged to
1293
+ // a fixpoint so a hook slot inherits a registry field's handlers.
1294
+ // Filter: a file matters only if SOME collected pair has BOTH fields known as
1295
+ // fn-pointer fields — the loop body's own pre-gate. A skipped file's matches
1296
+ // would all `continue` there, so skipping is side-effect-free.
1297
+ const propagations = [];
1298
+ for (const file of files) {
1299
+ await tick();
1300
+ const facts = factsByFile.get(file);
1301
+ if (!facts?.dPairs?.some((p) => {
1302
+ const i = p.indexOf('\0');
1303
+ return fieldToStructs.has(p.slice(0, i)) && fieldToStructs.has(p.slice(i + 1));
1304
+ }))
1305
+ continue;
1306
+ const s = src(file);
1307
+ if (!s || !s.includes('='))
1308
+ continue;
1309
+ const tN = prof ? Date.now() : 0;
1310
+ const fnsD = ctx.getNodesInFile(file);
1311
+ if (prof) {
1312
+ prof.nodesMs += Date.now() - tN;
1313
+ prof.nodesN++;
1314
+ }
1315
+ const dLines = s.split('\n');
1316
+ for (const fn of fnsD) {
1317
+ if (!FN_KINDS.has(fn.kind))
1318
+ continue;
1319
+ const body = sliceLinesPre(dLines, fn.startLine, fn.endLine);
1320
+ if (!body.includes('='))
1321
+ continue;
1322
+ FIELD_ASSIGN_RE.lastIndex = 0;
1323
+ let m;
1324
+ while ((m = FIELD_ASSIGN_RE.exec(body))) {
1325
+ const [, lrecv, lfield, rrecv, rfield] = m;
1326
+ // Pre-gate on field NAMES: `a->f = b->g` matches every struct-field
1327
+ // assignment in the tree (millions on the kernel), but only fields
1328
+ // that are fn-pointer fields of SOME struct can pass fnPtrFieldOf —
1329
+ // skip the two regex type resolutions for the ~99% that can't.
1330
+ if (!fieldToStructs.has(lfield) || !fieldToStructs.has(rfield))
1331
+ continue;
1332
+ const lt = recvTypeIn(body, lrecv);
1333
+ const rt = recvTypeIn(body, rrecv);
1334
+ if (lt && rt && fnPtrFieldOf(lt, lfield) && fnPtrFieldOf(rt, rfield)) {
1335
+ propagations.push({ to: `${lt}.${lfield}`, from: `${rt}.${rfield}` });
1336
+ }
1337
+ }
1338
+ }
1339
+ }
1340
+ for (let pass = 0; pass < 3 && propagations.length; pass++) {
1341
+ let changed = false;
1342
+ for (const { to, from } of propagations) {
1343
+ const fromSet = reg.get(from);
1344
+ if (!fromSet)
1345
+ continue;
1346
+ if (!reg.has(to))
1347
+ reg.set(to, new Set());
1348
+ const toSet = reg.get(to);
1349
+ for (const id of fromSet) {
1350
+ if (!toSet.has(id)) {
1351
+ toSet.add(id);
1352
+ changed = true;
1353
+ }
1354
+ }
1355
+ }
1356
+ if (!changed)
1357
+ break;
1358
+ }
1359
+ if (prof) {
1360
+ prof.D = Date.now() - tPass;
1361
+ tPass = Date.now();
1362
+ }
1363
+ if (reg.size === 0 && arrayReg.size === 0)
1364
+ return [];
1365
+ // ---- Stage E: dispatch sites → edges ----
1366
+ // Filter: a file matters only if some dispatch field is a known fn-pointer
1367
+ // field, or some subscripted name is a registered fn-pointer array — the loop
1368
+ // body's own first gates (`owners` / `entries`), which a skipped file's
1369
+ // matches would all fail before touching `seen`/`added`/`edges`.
1370
+ const edges = [];
1371
+ const seen = new Set();
1372
+ for (const file of files) {
1373
+ await tick();
1374
+ const facts = factsByFile.get(file);
1375
+ if (!facts)
1376
+ continue;
1377
+ const eSurvives = (facts.dispatchFields?.some((f) => fieldToStructs.has(f)) ?? false) ||
1378
+ (arrayReg.size > 0 && (facts.arrayDispatchNames?.some((n) => arrayReg.has(n)) ?? false));
1379
+ if (!eSurvives)
1380
+ continue;
1381
+ const s = src(file);
1382
+ if (!s)
1383
+ continue;
1384
+ const tN = prof ? Date.now() : 0;
1385
+ const fnsE = ctx.getNodesInFile(file);
1386
+ if (prof) {
1387
+ prof.nodesMs += Date.now() - tN;
1388
+ prof.nodesN++;
1389
+ }
1390
+ const eLines = s.split('\n');
1391
+ for (const fn of fnsE) {
1392
+ if (!FN_KINDS.has(fn.kind))
1393
+ continue;
1394
+ const body = sliceLinesPre(eLines, fn.startLine, fn.endLine);
1395
+ DISPATCH_RE.lastIndex = 0;
1396
+ let m;
1397
+ let added = 0;
1398
+ // Incremental line counting: matches arrive in ascending index order, so
1399
+ // count newlines since the previous match instead of re-splitting the
1400
+ // whole body prefix per match (O(body) each — real time on god-files).
1401
+ let lcIdx = 0;
1402
+ let lcLine = fn.startLine;
1403
+ const lineAt = (idx) => {
1404
+ for (let i = lcIdx; i < idx; i++)
1405
+ if (body.charCodeAt(i) === 10)
1406
+ lcLine++;
1407
+ lcIdx = idx;
1408
+ return lcLine;
1409
+ };
1410
+ while ((m = DISPATCH_RE.exec(body)) && added < FANOUT_CAP) {
1411
+ const baseChain = m[1].replace(/\s*(?:->|\.)\s*$/, '').trim(); // receiver, minus the trailing arrow
1412
+ const field = m[2];
1413
+ const owners = fieldToStructs.get(field);
1414
+ if (!owners || owners.size === 0)
1415
+ continue;
1416
+ // 1) resolve the receiver chain's struct type precisely (handles c->cmd->proc);
1417
+ // 2) else the last segment as a simple local/param of a fn-pointer-bearing struct;
1418
+ // 3) else fall back to a field name that belongs to exactly one struct.
1419
+ let struct = resolveChainType(body, baseChain);
1420
+ if (!struct || !owners.has(struct)) {
1421
+ const lastSeg = baseChain.replace(/\s*\[[^\]]*\]/g, '').split(/\s*(?:->|\.)\s*/).pop();
1422
+ const t = recvTypeIn(body, lastSeg);
1423
+ struct = t && owners.has(t) ? t : null;
1424
+ }
1425
+ if (!struct || !owners.has(struct))
1426
+ struct = owners.size === 1 ? [...owners][0] : null;
1427
+ if (!struct)
1428
+ continue;
1429
+ const targets = reg.get(`${struct}.${field}`);
1430
+ if (!targets)
1431
+ continue;
1432
+ const line = lineAt(m.index);
1433
+ for (const tid of targets) {
1434
+ if (tid === fn.id)
1435
+ continue;
1436
+ const key = `${fn.id}>${tid}`;
1437
+ if (seen.has(key))
1438
+ continue;
1439
+ seen.add(key);
1440
+ edges.push({
1441
+ source: fn.id,
1442
+ target: tid,
1443
+ kind: 'calls',
1444
+ line,
1445
+ provenance: 'heuristic',
1446
+ metadata: {
1447
+ synthesizedBy: 'fn-pointer-dispatch',
1448
+ via: `${struct}.${field}`,
1449
+ registeredAt: `${fn.filePath}:${line}`,
1450
+ },
1451
+ });
1452
+ if (++added >= FANOUT_CAP)
1453
+ break;
1454
+ }
1455
+ }
1456
+ // ---- bare array-of-fn-pointers dispatch (`tbl[i](…)`) ----
1457
+ if (arrayReg.size && added < FANOUT_CAP) {
1458
+ // Fresh scan from the body's start — rewind the line-count cursor too.
1459
+ lcIdx = 0;
1460
+ lcLine = fn.startLine;
1461
+ ARRAY_DISPATCH_RE.lastIndex = 0;
1462
+ while ((m = ARRAY_DISPATCH_RE.exec(body)) && added < FANOUT_CAP) {
1463
+ const entries = arrayReg.get(m[1]);
1464
+ if (!entries)
1465
+ continue;
1466
+ // Same-file table wins on a name collision (two file-local `opcodes`);
1467
+ // a unique name resolves cross-file; otherwise ambiguous — bail.
1468
+ const ids = entries.length === 1
1469
+ ? entries[0].ids
1470
+ : (entries.find((e) => e.file === fn.filePath)?.ids ?? null);
1471
+ if (!ids)
1472
+ continue;
1473
+ const line = lineAt(m.index);
1474
+ for (const tid of ids) {
1475
+ if (tid === fn.id)
1476
+ continue;
1477
+ const key = `${fn.id}>${tid}`;
1478
+ if (seen.has(key))
1479
+ continue;
1480
+ seen.add(key);
1481
+ edges.push({
1482
+ source: fn.id,
1483
+ target: tid,
1484
+ kind: 'calls',
1485
+ line,
1486
+ provenance: 'heuristic',
1487
+ metadata: {
1488
+ synthesizedBy: 'fn-pointer-dispatch',
1489
+ via: `${m[1]}[]`,
1490
+ registeredAt: `${fn.filePath}:${line}`,
1491
+ },
1492
+ });
1493
+ if (++added >= FANOUT_CAP)
1494
+ break;
1495
+ }
1496
+ }
1497
+ }
1498
+ }
1499
+ }
1500
+ if (prof) {
1501
+ prof.E = Date.now() - tPass;
1502
+ console.error(`[synth-timing] cFnPtr sub: A=${prof.A}ms B=${prof.B}ms C=${prof.C}ms D=${prof.D}ms E=${prof.E}ms | read n=${prof.readN} ${prof.readMs}ms strip n=${prof.stripN} ${prof.stripMs}ms nodesInFile n=${prof.nodesN} ${prof.nodesMs}ms`);
1503
+ }
1504
+ return edges;
1505
+ }
1506
+ //# sourceMappingURL=c-fnptr-synthesizer.js.map