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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (593) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +567 -2
  3. package/dist/ai/crux.d.ts +88 -0
  4. package/dist/ai/crux.d.ts.map +1 -0
  5. package/dist/ai/crux.js +219 -0
  6. package/dist/ai/crux.js.map +1 -0
  7. package/dist/ai/failure.d.ts +60 -0
  8. package/dist/ai/failure.d.ts.map +1 -0
  9. package/dist/ai/failure.js +86 -0
  10. package/dist/ai/failure.js.map +1 -0
  11. package/dist/ai/llm/anthropic.d.ts +37 -0
  12. package/dist/ai/llm/anthropic.d.ts.map +1 -0
  13. package/dist/ai/llm/anthropic.js +144 -0
  14. package/dist/ai/llm/anthropic.js.map +1 -0
  15. package/dist/ai/llm/factory.d.ts +28 -0
  16. package/dist/ai/llm/factory.d.ts.map +1 -0
  17. package/dist/ai/llm/factory.js +36 -0
  18. package/dist/ai/llm/factory.js.map +1 -0
  19. package/dist/ai/llm/litellm.d.ts +34 -0
  20. package/dist/ai/llm/litellm.d.ts.map +1 -0
  21. package/dist/ai/llm/litellm.js +45 -0
  22. package/dist/ai/llm/litellm.js.map +1 -0
  23. package/dist/ai/llm/openai.d.ts +145 -0
  24. package/dist/ai/llm/openai.d.ts.map +1 -0
  25. package/dist/ai/llm/openai.js +629 -0
  26. package/dist/ai/llm/openai.js.map +1 -0
  27. package/dist/ai/llm/orcarouter.d.ts +34 -0
  28. package/dist/ai/llm/orcarouter.d.ts.map +1 -0
  29. package/dist/ai/llm/orcarouter.js +45 -0
  30. package/dist/ai/llm/orcarouter.js.map +1 -0
  31. package/dist/ai/llm/recover-tool.d.ts +21 -0
  32. package/dist/ai/llm/recover-tool.d.ts.map +1 -0
  33. package/dist/ai/llm/recover-tool.js +109 -0
  34. package/dist/ai/llm/recover-tool.js.map +1 -0
  35. package/dist/ai/llm/types.d.ts +122 -0
  36. package/dist/ai/llm/types.d.ts.map +1 -0
  37. package/dist/ai/llm/types.js +33 -0
  38. package/dist/ai/llm/types.js.map +1 -0
  39. package/dist/ai/providers.d.ts +59 -0
  40. package/dist/ai/providers.d.ts.map +1 -0
  41. package/dist/ai/providers.js +54 -0
  42. package/dist/ai/providers.js.map +1 -0
  43. package/dist/ai/summarize.d.ts +25 -0
  44. package/dist/ai/summarize.d.ts.map +1 -0
  45. package/dist/ai/summarize.js +34 -0
  46. package/dist/ai/summarize.js.map +1 -0
  47. package/dist/ai/synthesize.d.ts +40 -0
  48. package/dist/ai/synthesize.d.ts.map +1 -0
  49. package/dist/ai/synthesize.js +230 -0
  50. package/dist/ai/synthesize.js.map +1 -0
  51. package/dist/ask/ask.d.ts +199 -0
  52. package/dist/ask/ask.d.ts.map +1 -0
  53. package/dist/ask/ask.js +1291 -0
  54. package/dist/ask/ask.js.map +1 -0
  55. package/dist/ask/file-rank.d.ts +72 -0
  56. package/dist/ask/file-rank.d.ts.map +1 -0
  57. package/dist/ask/file-rank.js +160 -0
  58. package/dist/ask/file-rank.js.map +1 -0
  59. package/dist/ask/file-selection.d.ts +22 -0
  60. package/dist/ask/file-selection.d.ts.map +1 -0
  61. package/dist/ask/file-selection.js +66 -0
  62. package/dist/ask/file-selection.js.map +1 -0
  63. package/dist/ask/fuse.d.ts +195 -0
  64. package/dist/ask/fuse.d.ts.map +1 -0
  65. package/dist/ask/fuse.js +344 -0
  66. package/dist/ask/fuse.js.map +1 -0
  67. package/dist/ask/graphrank.d.ts +61 -0
  68. package/dist/ask/graphrank.d.ts.map +1 -0
  69. package/dist/ask/graphrank.js +130 -0
  70. package/dist/ask/graphrank.js.map +1 -0
  71. package/dist/ask/index-file.d.ts +44 -0
  72. package/dist/ask/index-file.d.ts.map +1 -0
  73. package/dist/ask/index-file.js +128 -0
  74. package/dist/ask/index-file.js.map +1 -0
  75. package/dist/ask/semantic.d.ts +42 -0
  76. package/dist/ask/semantic.d.ts.map +1 -0
  77. package/dist/ask/semantic.js +293 -0
  78. package/dist/ask/semantic.js.map +1 -0
  79. package/dist/bin/graft.d.ts +3 -0
  80. package/dist/bin/graft.d.ts.map +1 -0
  81. package/dist/bin/graft.js +14 -0
  82. package/dist/bin/graft.js.map +1 -0
  83. package/dist/bin/trail.d.ts +3 -0
  84. package/dist/bin/trail.d.ts.map +1 -0
  85. package/dist/bin/trail.js +13 -0
  86. package/dist/bin/trail.js.map +1 -0
  87. package/dist/blast/blast-cli.d.ts +35 -0
  88. package/dist/blast/blast-cli.d.ts.map +1 -0
  89. package/dist/blast/blast-cli.js +155 -0
  90. package/dist/blast/blast-cli.js.map +1 -0
  91. package/dist/blast/blast.d.ts +128 -0
  92. package/dist/blast/blast.d.ts.map +1 -0
  93. package/dist/blast/blast.js +383 -0
  94. package/dist/blast/blast.js.map +1 -0
  95. package/dist/blast/diff.d.ts +53 -0
  96. package/dist/blast/diff.d.ts.map +1 -0
  97. package/dist/blast/diff.js +193 -0
  98. package/dist/blast/diff.js.map +1 -0
  99. package/dist/blast/evidence.d.ts +51 -0
  100. package/dist/blast/evidence.d.ts.map +1 -0
  101. package/dist/blast/evidence.js +162 -0
  102. package/dist/blast/evidence.js.map +1 -0
  103. package/dist/blast/modules.d.ts +33 -0
  104. package/dist/blast/modules.d.ts.map +1 -0
  105. package/dist/blast/modules.js +83 -0
  106. package/dist/blast/modules.js.map +1 -0
  107. package/dist/blast/name.d.ts +74 -0
  108. package/dist/blast/name.d.ts.map +1 -0
  109. package/dist/blast/name.js +269 -0
  110. package/dist/blast/name.js.map +1 -0
  111. package/dist/blast/owners.d.ts +85 -0
  112. package/dist/blast/owners.d.ts.map +1 -0
  113. package/dist/blast/owners.js +272 -0
  114. package/dist/blast/owners.js.map +1 -0
  115. package/dist/blast/render.d.ts +46 -0
  116. package/dist/blast/render.d.ts.map +1 -0
  117. package/dist/blast/render.js +422 -0
  118. package/dist/blast/render.js.map +1 -0
  119. package/dist/blast/viz.d.ts +37 -0
  120. package/dist/blast/viz.d.ts.map +1 -0
  121. package/dist/blast/viz.js +180 -0
  122. package/dist/blast/viz.js.map +1 -0
  123. package/dist/brand.d.ts +111 -0
  124. package/dist/brand.d.ts.map +1 -0
  125. package/dist/brand.js +282 -0
  126. package/dist/brand.js.map +1 -0
  127. package/dist/claude/build-progress.d.ts +30 -0
  128. package/dist/claude/build-progress.d.ts.map +1 -0
  129. package/dist/claude/build-progress.js +81 -0
  130. package/dist/claude/build-progress.js.map +1 -0
  131. package/dist/claude/hermes-skill-template.d.ts +16 -0
  132. package/dist/claude/hermes-skill-template.d.ts.map +1 -0
  133. package/dist/claude/hermes-skill-template.js +154 -0
  134. package/dist/claude/hermes-skill-template.js.map +1 -0
  135. package/dist/claude/init.d.ts +65 -0
  136. package/dist/claude/init.d.ts.map +1 -0
  137. package/dist/claude/init.js +258 -0
  138. package/dist/claude/init.js.map +1 -0
  139. package/dist/claude/paths.d.ts +9 -0
  140. package/dist/claude/paths.d.ts.map +1 -0
  141. package/dist/claude/paths.js +22 -0
  142. package/dist/claude/paths.js.map +1 -0
  143. package/dist/claude/session-metrics.d.ts +73 -0
  144. package/dist/claude/session-metrics.d.ts.map +1 -0
  145. package/dist/claude/session-metrics.js +209 -0
  146. package/dist/claude/session-metrics.js.map +1 -0
  147. package/dist/claude/settings-merge.d.ts +76 -0
  148. package/dist/claude/settings-merge.d.ts.map +1 -0
  149. package/dist/claude/settings-merge.js +283 -0
  150. package/dist/claude/settings-merge.js.map +1 -0
  151. package/dist/claude/skill-template.d.ts +13 -0
  152. package/dist/claude/skill-template.d.ts.map +1 -0
  153. package/dist/claude/skill-template.js +290 -0
  154. package/dist/claude/skill-template.js.map +1 -0
  155. package/dist/claude/state.d.ts +85 -0
  156. package/dist/claude/state.d.ts.map +1 -0
  157. package/dist/claude/state.js +88 -0
  158. package/dist/claude/state.js.map +1 -0
  159. package/dist/claude/stats.d.ts +5 -0
  160. package/dist/claude/stats.d.ts.map +1 -0
  161. package/dist/claude/stats.js +24 -0
  162. package/dist/claude/stats.js.map +1 -0
  163. package/dist/cli-epilogue.d.ts +12 -0
  164. package/dist/cli-epilogue.d.ts.map +1 -0
  165. package/dist/cli-epilogue.js +72 -0
  166. package/dist/cli-epilogue.js.map +1 -0
  167. package/dist/cli-meta.d.ts +82 -0
  168. package/dist/cli-meta.d.ts.map +1 -0
  169. package/dist/cli-meta.js +238 -0
  170. package/dist/cli-meta.js.map +1 -0
  171. package/dist/cli-picker.d.ts +139 -0
  172. package/dist/cli-picker.d.ts.map +1 -0
  173. package/dist/cli-picker.js +439 -0
  174. package/dist/cli-picker.js.map +1 -0
  175. package/dist/cli.d.ts +3 -0
  176. package/dist/cli.d.ts.map +1 -0
  177. package/dist/cli.js +1638 -0
  178. package/dist/cli.js.map +1 -0
  179. package/dist/context/batches.d.ts +29 -0
  180. package/dist/context/batches.d.ts.map +1 -0
  181. package/dist/context/batches.js +130 -0
  182. package/dist/context/batches.js.map +1 -0
  183. package/dist/context/build.d.ts +57 -0
  184. package/dist/context/build.d.ts.map +1 -0
  185. package/dist/context/build.js +396 -0
  186. package/dist/context/build.js.map +1 -0
  187. package/dist/context/check.d.ts +42 -0
  188. package/dist/context/check.d.ts.map +1 -0
  189. package/dist/context/check.js +162 -0
  190. package/dist/context/check.js.map +1 -0
  191. package/dist/context/map-dir.d.ts +13 -0
  192. package/dist/context/map-dir.d.ts.map +1 -0
  193. package/dist/context/map-dir.js +81 -0
  194. package/dist/context/map-dir.js.map +1 -0
  195. package/dist/context/node-file.d.ts +109 -0
  196. package/dist/context/node-file.d.ts.map +1 -0
  197. package/dist/context/node-file.js +390 -0
  198. package/dist/context/node-file.js.map +1 -0
  199. package/dist/context/price.d.ts +49 -0
  200. package/dist/context/price.d.ts.map +1 -0
  201. package/dist/context/price.js +83 -0
  202. package/dist/context/price.js.map +1 -0
  203. package/dist/context/savings.d.ts +67 -0
  204. package/dist/context/savings.d.ts.map +1 -0
  205. package/dist/context/savings.js +125 -0
  206. package/dist/context/savings.js.map +1 -0
  207. package/dist/engine.d.ts +85 -0
  208. package/dist/engine.d.ts.map +1 -0
  209. package/dist/engine.js +122 -0
  210. package/dist/engine.js.map +1 -0
  211. package/dist/graph/bindings.d.ts +64 -0
  212. package/dist/graph/bindings.d.ts.map +1 -0
  213. package/dist/graph/bindings.js +713 -0
  214. package/dist/graph/bindings.js.map +1 -0
  215. package/dist/graph/build-run.d.ts +25 -0
  216. package/dist/graph/build-run.d.ts.map +1 -0
  217. package/dist/graph/build-run.js +121 -0
  218. package/dist/graph/build-run.js.map +1 -0
  219. package/dist/graph/build.d.ts +88 -0
  220. package/dist/graph/build.d.ts.map +1 -0
  221. package/dist/graph/build.js +386 -0
  222. package/dist/graph/build.js.map +1 -0
  223. package/dist/graph/cards.d.ts +46 -0
  224. package/dist/graph/cards.d.ts.map +1 -0
  225. package/dist/graph/cards.js +280 -0
  226. package/dist/graph/cards.js.map +1 -0
  227. package/dist/graph/check.d.ts +25 -0
  228. package/dist/graph/check.d.ts.map +1 -0
  229. package/dist/graph/check.js +192 -0
  230. package/dist/graph/check.js.map +1 -0
  231. package/dist/graph/container.d.ts +63 -0
  232. package/dist/graph/container.d.ts.map +1 -0
  233. package/dist/graph/container.js +191 -0
  234. package/dist/graph/container.js.map +1 -0
  235. package/dist/graph/depth-parser.d.ts +61 -0
  236. package/dist/graph/depth-parser.d.ts.map +1 -0
  237. package/dist/graph/depth-parser.js +153 -0
  238. package/dist/graph/depth-parser.js.map +1 -0
  239. package/dist/graph/enrich.d.ts +62 -0
  240. package/dist/graph/enrich.d.ts.map +1 -0
  241. package/dist/graph/enrich.js +258 -0
  242. package/dist/graph/enrich.js.map +1 -0
  243. package/dist/graph/extract-cache.d.ts +101 -0
  244. package/dist/graph/extract-cache.d.ts.map +1 -0
  245. package/dist/graph/extract-cache.js +199 -0
  246. package/dist/graph/extract-cache.js.map +1 -0
  247. package/dist/graph/extract.d.ts +85 -0
  248. package/dist/graph/extract.d.ts.map +1 -0
  249. package/dist/graph/extract.js +2377 -0
  250. package/dist/graph/extract.js.map +1 -0
  251. package/dist/graph/fingerprint.d.ts +76 -0
  252. package/dist/graph/fingerprint.d.ts.map +1 -0
  253. package/dist/graph/fingerprint.js +160 -0
  254. package/dist/graph/fingerprint.js.map +1 -0
  255. package/dist/graph/generic.d.ts +74 -0
  256. package/dist/graph/generic.d.ts.map +1 -0
  257. package/dist/graph/generic.js +773 -0
  258. package/dist/graph/generic.js.map +1 -0
  259. package/dist/graph/invariants.d.ts +33 -0
  260. package/dist/graph/invariants.d.ts.map +1 -0
  261. package/dist/graph/invariants.js +52 -0
  262. package/dist/graph/invariants.js.map +1 -0
  263. package/dist/graph/load.d.ts +29 -0
  264. package/dist/graph/load.d.ts.map +1 -0
  265. package/dist/graph/load.js +97 -0
  266. package/dist/graph/load.js.map +1 -0
  267. package/dist/graph/lsp/client.d.ts +61 -0
  268. package/dist/graph/lsp/client.d.ts.map +1 -0
  269. package/dist/graph/lsp/client.js +217 -0
  270. package/dist/graph/lsp/client.js.map +1 -0
  271. package/dist/graph/lsp/enrich.d.ts +11 -0
  272. package/dist/graph/lsp/enrich.d.ts.map +1 -0
  273. package/dist/graph/lsp/enrich.js +163 -0
  274. package/dist/graph/lsp/enrich.js.map +1 -0
  275. package/dist/graph/lsp/registry.d.ts +22 -0
  276. package/dist/graph/lsp/registry.d.ts.map +1 -0
  277. package/dist/graph/lsp/registry.js +71 -0
  278. package/dist/graph/lsp/registry.js.map +1 -0
  279. package/dist/graph/map.d.ts +107 -0
  280. package/dist/graph/map.d.ts.map +1 -0
  281. package/dist/graph/map.js +239 -0
  282. package/dist/graph/map.js.map +1 -0
  283. package/dist/graph/markdown.d.ts +22 -0
  284. package/dist/graph/markdown.d.ts.map +1 -0
  285. package/dist/graph/markdown.js +143 -0
  286. package/dist/graph/markdown.js.map +1 -0
  287. package/dist/graph/native.d.ts +46 -0
  288. package/dist/graph/native.d.ts.map +1 -0
  289. package/dist/graph/native.js +169 -0
  290. package/dist/graph/native.js.map +1 -0
  291. package/dist/graph/queries/c.scm +13 -0
  292. package/dist/graph/queries/c_sharp.scm +19 -0
  293. package/dist/graph/queries/clojure.scm +58 -0
  294. package/dist/graph/queries/cpp.scm +23 -0
  295. package/dist/graph/queries/dart.scm +42 -0
  296. package/dist/graph/queries/elixir.scm +54 -0
  297. package/dist/graph/queries/gleam.scm +51 -0
  298. package/dist/graph/queries/java.scm +20 -0
  299. package/dist/graph/queries/kotlin.scm +43 -0
  300. package/dist/graph/queries/lua.scm +36 -0
  301. package/dist/graph/queries/nix.scm +32 -0
  302. package/dist/graph/queries/php.scm +40 -0
  303. package/dist/graph/queries/ruby.scm +65 -0
  304. package/dist/graph/queries/rust.scm +41 -0
  305. package/dist/graph/queries/scala.scm +66 -0
  306. package/dist/graph/queries/solidity.scm +43 -0
  307. package/dist/graph/queries/swift.scm +51 -0
  308. package/dist/graph/refresh.d.ts +106 -0
  309. package/dist/graph/refresh.d.ts.map +1 -0
  310. package/dist/graph/refresh.js +430 -0
  311. package/dist/graph/refresh.js.map +1 -0
  312. package/dist/graph/relations.d.ts +14 -0
  313. package/dist/graph/relations.d.ts.map +1 -0
  314. package/dist/graph/relations.js +8 -0
  315. package/dist/graph/relations.js.map +1 -0
  316. package/dist/graph/resolve.d.ts +17 -0
  317. package/dist/graph/resolve.d.ts.map +1 -0
  318. package/dist/graph/resolve.js +716 -0
  319. package/dist/graph/resolve.js.map +1 -0
  320. package/dist/graph/root.d.ts +11 -0
  321. package/dist/graph/root.d.ts.map +1 -0
  322. package/dist/graph/root.js +40 -0
  323. package/dist/graph/root.js.map +1 -0
  324. package/dist/graph/scopes.d.ts +40 -0
  325. package/dist/graph/scopes.d.ts.map +1 -0
  326. package/dist/graph/scopes.js +383 -0
  327. package/dist/graph/scopes.js.map +1 -0
  328. package/dist/graph/seed.d.ts +38 -0
  329. package/dist/graph/seed.d.ts.map +1 -0
  330. package/dist/graph/seed.js +229 -0
  331. package/dist/graph/seed.js.map +1 -0
  332. package/dist/graph/source-files.d.ts +46 -0
  333. package/dist/graph/source-files.d.ts.map +1 -0
  334. package/dist/graph/source-files.js +118 -0
  335. package/dist/graph/source-files.js.map +1 -0
  336. package/dist/graph/traverse-cli.d.ts +55 -0
  337. package/dist/graph/traverse-cli.d.ts.map +1 -0
  338. package/dist/graph/traverse-cli.js +189 -0
  339. package/dist/graph/traverse-cli.js.map +1 -0
  340. package/dist/graph/traverse.d.ts +112 -0
  341. package/dist/graph/traverse.d.ts.map +1 -0
  342. package/dist/graph/traverse.js +192 -0
  343. package/dist/graph/traverse.js.map +1 -0
  344. package/dist/graph/types.d.ts +78 -0
  345. package/dist/graph/types.d.ts.map +1 -0
  346. package/dist/graph/types.js +14 -0
  347. package/dist/graph/types.js.map +1 -0
  348. package/dist/graph/wasm-runtime.d.ts +19 -0
  349. package/dist/graph/wasm-runtime.d.ts.map +1 -0
  350. package/dist/graph/wasm-runtime.js +38 -0
  351. package/dist/graph/wasm-runtime.js.map +1 -0
  352. package/dist/graph/workspace-cli.d.ts +56 -0
  353. package/dist/graph/workspace-cli.d.ts.map +1 -0
  354. package/dist/graph/workspace-cli.js +111 -0
  355. package/dist/graph/workspace-cli.js.map +1 -0
  356. package/dist/graph/workspace.d.ts +172 -0
  357. package/dist/graph/workspace.d.ts.map +1 -0
  358. package/dist/graph/workspace.js +714 -0
  359. package/dist/graph/workspace.js.map +1 -0
  360. package/dist/graph/write.d.ts +13 -0
  361. package/dist/graph/write.d.ts.map +1 -0
  362. package/dist/graph/write.js +86 -0
  363. package/dist/graph/write.js.map +1 -0
  364. package/dist/hosts/antigravity.d.ts +14 -0
  365. package/dist/hosts/antigravity.d.ts.map +1 -0
  366. package/dist/hosts/antigravity.js +59 -0
  367. package/dist/hosts/antigravity.js.map +1 -0
  368. package/dist/hosts/auto.d.ts +37 -0
  369. package/dist/hosts/auto.d.ts.map +1 -0
  370. package/dist/hosts/auto.js +141 -0
  371. package/dist/hosts/auto.js.map +1 -0
  372. package/dist/hosts/claude-global.d.ts +72 -0
  373. package/dist/hosts/claude-global.d.ts.map +1 -0
  374. package/dist/hosts/claude-global.js +230 -0
  375. package/dist/hosts/claude-global.js.map +1 -0
  376. package/dist/hosts/config-write.d.ts +36 -0
  377. package/dist/hosts/config-write.d.ts.map +1 -0
  378. package/dist/hosts/config-write.js +64 -0
  379. package/dist/hosts/config-write.js.map +1 -0
  380. package/dist/hosts/init.d.ts +28 -0
  381. package/dist/hosts/init.d.ts.map +1 -0
  382. package/dist/hosts/init.js +89 -0
  383. package/dist/hosts/init.js.map +1 -0
  384. package/dist/hosts/instructions.d.ts +14 -0
  385. package/dist/hosts/instructions.d.ts.map +1 -0
  386. package/dist/hosts/instructions.js +95 -0
  387. package/dist/hosts/instructions.js.map +1 -0
  388. package/dist/hosts/mcp-config.d.ts +78 -0
  389. package/dist/hosts/mcp-config.d.ts.map +1 -0
  390. package/dist/hosts/mcp-config.js +251 -0
  391. package/dist/hosts/mcp-config.js.map +1 -0
  392. package/dist/hosts/plan.d.ts +32 -0
  393. package/dist/hosts/plan.d.ts.map +1 -0
  394. package/dist/hosts/plan.js +73 -0
  395. package/dist/hosts/plan.js.map +1 -0
  396. package/dist/hosts/registry.d.ts +41 -0
  397. package/dist/hosts/registry.d.ts.map +1 -0
  398. package/dist/hosts/registry.js +164 -0
  399. package/dist/hosts/registry.js.map +1 -0
  400. package/dist/hosts/retract.d.ts +47 -0
  401. package/dist/hosts/retract.d.ts.map +1 -0
  402. package/dist/hosts/retract.js +520 -0
  403. package/dist/hosts/retract.js.map +1 -0
  404. package/dist/hosts/sections.d.ts +47 -0
  405. package/dist/hosts/sections.d.ts.map +1 -0
  406. package/dist/hosts/sections.js +127 -0
  407. package/dist/hosts/sections.js.map +1 -0
  408. package/dist/index.d.ts +41 -0
  409. package/dist/index.d.ts.map +1 -0
  410. package/dist/index.js +32 -0
  411. package/dist/index.js.map +1 -0
  412. package/dist/ingest/fs.d.ts +79 -0
  413. package/dist/ingest/fs.d.ts.map +1 -0
  414. package/dist/ingest/fs.js +306 -0
  415. package/dist/ingest/fs.js.map +1 -0
  416. package/dist/init-guard.d.ts +16 -0
  417. package/dist/init-guard.d.ts.map +1 -0
  418. package/dist/init-guard.js +27 -0
  419. package/dist/init-guard.js.map +1 -0
  420. package/dist/mcp/instructions.d.ts +5 -0
  421. package/dist/mcp/instructions.d.ts.map +1 -0
  422. package/dist/mcp/instructions.js +64 -0
  423. package/dist/mcp/instructions.js.map +1 -0
  424. package/dist/mcp/kept-listing.d.ts +27 -0
  425. package/dist/mcp/kept-listing.d.ts.map +1 -0
  426. package/dist/mcp/kept-listing.js +63 -0
  427. package/dist/mcp/kept-listing.js.map +1 -0
  428. package/dist/mcp/server.d.ts +4 -0
  429. package/dist/mcp/server.d.ts.map +1 -0
  430. package/dist/mcp/server.js +147 -0
  431. package/dist/mcp/server.js.map +1 -0
  432. package/dist/mcp/tool-names.d.ts +27 -0
  433. package/dist/mcp/tool-names.d.ts.map +1 -0
  434. package/dist/mcp/tool-names.js +47 -0
  435. package/dist/mcp/tool-names.js.map +1 -0
  436. package/dist/mcp/tools.d.ts +22 -0
  437. package/dist/mcp/tools.d.ts.map +1 -0
  438. package/dist/mcp/tools.js +440 -0
  439. package/dist/mcp/tools.js.map +1 -0
  440. package/dist/node-version.d.ts +15 -0
  441. package/dist/node-version.d.ts.map +1 -0
  442. package/dist/node-version.js +23 -0
  443. package/dist/node-version.js.map +1 -0
  444. package/dist/search/grep-cli.d.ts +35 -0
  445. package/dist/search/grep-cli.d.ts.map +1 -0
  446. package/dist/search/grep-cli.js +115 -0
  447. package/dist/search/grep-cli.js.map +1 -0
  448. package/dist/search/grep.d.ts +60 -0
  449. package/dist/search/grep.d.ts.map +1 -0
  450. package/dist/search/grep.js +143 -0
  451. package/dist/search/grep.js.map +1 -0
  452. package/dist/search/ignored-code.d.ts +9 -0
  453. package/dist/search/ignored-code.d.ts.map +1 -0
  454. package/dist/search/ignored-code.js +73 -0
  455. package/dist/search/ignored-code.js.map +1 -0
  456. package/dist/search/user-regexp.d.ts +26 -0
  457. package/dist/search/user-regexp.d.ts.map +1 -0
  458. package/dist/search/user-regexp.js +150 -0
  459. package/dist/search/user-regexp.js.map +1 -0
  460. package/dist/telemetry/contract.d.ts +117 -0
  461. package/dist/telemetry/contract.d.ts.map +1 -0
  462. package/dist/telemetry/contract.js +341 -0
  463. package/dist/telemetry/contract.js.map +1 -0
  464. package/dist/telemetry/flush.d.ts +21 -0
  465. package/dist/telemetry/flush.d.ts.map +1 -0
  466. package/dist/telemetry/flush.js +85 -0
  467. package/dist/telemetry/flush.js.map +1 -0
  468. package/dist/telemetry/gate.d.ts +30 -0
  469. package/dist/telemetry/gate.d.ts.map +1 -0
  470. package/dist/telemetry/gate.js +81 -0
  471. package/dist/telemetry/gate.js.map +1 -0
  472. package/dist/telemetry/identity.d.ts +40 -0
  473. package/dist/telemetry/identity.d.ts.map +1 -0
  474. package/dist/telemetry/identity.js +80 -0
  475. package/dist/telemetry/identity.js.map +1 -0
  476. package/dist/telemetry/index.d.ts +18 -0
  477. package/dist/telemetry/index.d.ts.map +1 -0
  478. package/dist/telemetry/index.js +16 -0
  479. package/dist/telemetry/index.js.map +1 -0
  480. package/dist/telemetry/key.d.ts +21 -0
  481. package/dist/telemetry/key.d.ts.map +1 -0
  482. package/dist/telemetry/key.js +49 -0
  483. package/dist/telemetry/key.js.map +1 -0
  484. package/dist/telemetry/notice.d.ts +19 -0
  485. package/dist/telemetry/notice.d.ts.map +1 -0
  486. package/dist/telemetry/notice.js +93 -0
  487. package/dist/telemetry/notice.js.map +1 -0
  488. package/dist/telemetry/queue.d.ts +35 -0
  489. package/dist/telemetry/queue.d.ts.map +1 -0
  490. package/dist/telemetry/queue.js +162 -0
  491. package/dist/telemetry/queue.js.map +1 -0
  492. package/dist/telemetry/send.d.ts +19 -0
  493. package/dist/telemetry/send.d.ts.map +1 -0
  494. package/dist/telemetry/send.js +84 -0
  495. package/dist/telemetry/send.js.map +1 -0
  496. package/dist/telemetry/sessions.d.ts +25 -0
  497. package/dist/telemetry/sessions.d.ts.map +1 -0
  498. package/dist/telemetry/sessions.js +104 -0
  499. package/dist/telemetry/sessions.js.map +1 -0
  500. package/dist/telemetry/track.d.ts +62 -0
  501. package/dist/telemetry/track.d.ts.map +1 -0
  502. package/dist/telemetry/track.js +143 -0
  503. package/dist/telemetry/track.js.map +1 -0
  504. package/dist/upkeep-run.d.ts +22 -0
  505. package/dist/upkeep-run.d.ts.map +1 -0
  506. package/dist/upkeep-run.js +85 -0
  507. package/dist/upkeep-run.js.map +1 -0
  508. package/dist/upkeep.d.ts +127 -0
  509. package/dist/upkeep.d.ts.map +1 -0
  510. package/dist/upkeep.js +252 -0
  511. package/dist/upkeep.js.map +1 -0
  512. package/dist/util/actions-folder.d.ts +2 -0
  513. package/dist/util/actions-folder.d.ts.map +1 -0
  514. package/dist/util/actions-folder.js +9 -0
  515. package/dist/util/actions-folder.js.map +1 -0
  516. package/dist/util/browser.d.ts +3 -0
  517. package/dist/util/browser.d.ts.map +1 -0
  518. package/dist/util/browser.js +14 -0
  519. package/dist/util/browser.js.map +1 -0
  520. package/dist/util/child-process.d.ts +15 -0
  521. package/dist/util/child-process.d.ts.map +1 -0
  522. package/dist/util/child-process.js +15 -0
  523. package/dist/util/child-process.js.map +1 -0
  524. package/dist/util/front-matter.d.ts +46 -0
  525. package/dist/util/front-matter.d.ts.map +1 -0
  526. package/dist/util/front-matter.js +113 -0
  527. package/dist/util/front-matter.js.map +1 -0
  528. package/dist/util/id.d.ts +7 -0
  529. package/dist/util/id.d.ts.map +1 -0
  530. package/dist/util/id.js +14 -0
  531. package/dist/util/id.js.map +1 -0
  532. package/dist/util/paths.d.ts +29 -0
  533. package/dist/util/paths.d.ts.map +1 -0
  534. package/dist/util/paths.js +71 -0
  535. package/dist/util/paths.js.map +1 -0
  536. package/dist/util/private-file.d.ts +14 -0
  537. package/dist/util/private-file.d.ts.map +1 -0
  538. package/dist/util/private-file.js +82 -0
  539. package/dist/util/private-file.js.map +1 -0
  540. package/dist/util/source.d.ts +4 -0
  541. package/dist/util/source.d.ts.map +1 -0
  542. package/dist/util/source.js +12 -0
  543. package/dist/util/source.js.map +1 -0
  544. package/dist/util/spinner.d.ts +15 -0
  545. package/dist/util/spinner.d.ts.map +1 -0
  546. package/dist/util/spinner.js +52 -0
  547. package/dist/util/spinner.js.map +1 -0
  548. package/dist/util/state.d.ts +120 -0
  549. package/dist/util/state.d.ts.map +1 -0
  550. package/dist/util/state.js +264 -0
  551. package/dist/util/state.js.map +1 -0
  552. package/dist/vendor/grammars/tree-sitter-go.LICENSE +21 -0
  553. package/dist/vendor/grammars/tree-sitter-go.wasm +0 -0
  554. package/dist/vendor/grammars/tree-sitter-java.LICENSE +21 -0
  555. package/dist/vendor/grammars/tree-sitter-java.wasm +0 -0
  556. package/dist/vendor/grammars/tree-sitter-kotlin.LICENSE +9 -0
  557. package/dist/vendor/grammars/tree-sitter-kotlin.wasm +0 -0
  558. package/dist/vendor/grammars/tree-sitter-php.LICENSE +22 -0
  559. package/dist/vendor/grammars/tree-sitter-php.wasm +0 -0
  560. package/dist/vendor/grammars/tree-sitter-python.LICENSE +21 -0
  561. package/dist/vendor/grammars/tree-sitter-python.wasm +0 -0
  562. package/dist/vendor/grammars/tree-sitter-r.LICENSE +9 -0
  563. package/dist/vendor/grammars/tree-sitter-r.wasm +0 -0
  564. package/dist/vendor/grammars/tree-sitter-swift.LICENSE +21 -0
  565. package/dist/vendor/grammars/tree-sitter-swift.wasm +0 -0
  566. package/dist/vendor/grammars/tree-sitter-tsx.wasm +0 -0
  567. package/dist/vendor/grammars/tree-sitter-typescript.LICENSE +21 -0
  568. package/dist/vendor/grammars/tree-sitter-typescript.wasm +0 -0
  569. package/dist/viewer/app.js +2 -0
  570. package/dist/viewer/index.html +49 -0
  571. package/dist/viewer/style.css +154 -0
  572. package/dist/viz/assemble.d.ts +83 -0
  573. package/dist/viz/assemble.d.ts.map +1 -0
  574. package/dist/viz/assemble.js +101 -0
  575. package/dist/viz/assemble.js.map +1 -0
  576. package/dist/viz/export.d.ts +39 -0
  577. package/dist/viz/export.d.ts.map +1 -0
  578. package/dist/viz/export.js +98 -0
  579. package/dist/viz/export.js.map +1 -0
  580. package/dist/viz/serve.d.ts +13 -0
  581. package/dist/viz/serve.d.ts.map +1 -0
  582. package/dist/viz/serve.js +130 -0
  583. package/dist/viz/serve.js.map +1 -0
  584. package/package.json +115 -4
  585. package/scripts/build-grammar-wasm.mjs +112 -0
  586. package/scripts/build-viewer.mjs +44 -0
  587. package/scripts/graph-quality.mjs +117 -0
  588. package/scripts/pack-trail.mjs +53 -0
  589. package/scripts/postinstall.mjs +65 -0
  590. package/scripts/run-tests.mjs +72 -0
  591. package/scripts/stamp-telemetry-key.mjs +56 -0
  592. package/scripts/tally-audit.mjs +140 -0
  593. package/scripts/vendor-grammars.mjs +53 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Scope-aware ranking for `graft ask`. Pure functions, no fs.
3
+ *
4
+ * The problem: lexical + graph scores are corpus-relative. In a multi-scope
5
+ * repo (a monorepo's `frontend/` + `backend/`, sub-projects under one root),
6
+ * scoring every node against one pooled corpus lets the biggest sub-project set
7
+ * the score scale and drown the small one.
8
+ *
9
+ * This module solves it by keeping the scope PARTITION — each scope is scored
10
+ * and walked separately — while making the resulting scores COMPARABLE, so the
11
+ * combined order can be read straight off the score. Comparability has two
12
+ * requirements, and both must hold or the order is meaningless:
13
+ *
14
+ * 1. shared corpus statistics — the caller scores every scope against the
15
+ * repo-wide IDF and length prior (see `ask.ts`), so the same term is worth
16
+ * the same everywhere;
17
+ * 2. a shared normalization denominator — {@link rankScopesAndFuse} divides
18
+ * every scope by the best raw score in the REPO, not by each scope's own
19
+ * best (see `globalMaxLex` there).
20
+ *
21
+ * Issue #117 was the consequence of neither holding. Each scope divided by its
22
+ * own maximum, so a barely-relevant scope's top hit normalized to ~1.0 exactly
23
+ * like the genuinely relevant scope's top hit; RRF then fused by RANK, which
24
+ * discards magnitude outright, so the weak scope's rank-1 tied the strong
25
+ * scope's rank-1 and displaced its rank-2 — frequently the answer. Measurement
26
+ * across four repositories and four ecosystems put 73% of missed files in that
27
+ * bucket. RRF is retained for `federateAsk` (see `graph/workspace.ts`), where
28
+ * the corpora really are separate repositories and no shared denominator
29
+ * exists — that is the case rank fusion is for.
30
+ *
31
+ * Soft federation: a scope whose top hit is probably an incidental word
32
+ * collision, not a second home for the query, is left out of the combined order
33
+ * and reported in `alsoMatched` instead, so the output can say "also matched:
34
+ * docs/ — narrow with --in docs/" rather than diluting the pack. With
35
+ * comparable scores that gate is simply {@link PARTICIPATION_RATIO} — a scope
36
+ * must reach a real share of the best score anywhere in the repo. Under
37
+ * per-scope normalization that check was vacuous (every scope's top was ~1.0),
38
+ * which is why a separate match-STRENGTH gate ({@link STRONG_FLOOR}/{@link
39
+ * HIGH_FLOOR}) had to stand in for it; that signal is still exported and still
40
+ * used by `federateAsk`, which normalizes per child repo and therefore still
41
+ * needs it.
42
+ */
43
+ /** One scored document, attributed to the ranking scope (path prefix, "" =
44
+ * root) it was scored within. Scores must be per-scope-normalized (each
45
+ * scope's best ≈ its own ceiling) — fusion compares ranks, not raw scores. */
46
+ export interface ScopedDoc {
47
+ id: string;
48
+ scope: string;
49
+ score: number;
50
+ }
51
+ /** Components preserved until immediately before comparable-scope combination.
52
+ * Optional ranking experiments can adjust lexical evidence without having to
53
+ * reconstruct it from the already blended scalar score. */
54
+ export interface ScopeRankCandidate extends ScopedDoc {
55
+ /** Repo-global-normalized lexical component. */
56
+ lexical: number;
57
+ /** Scope-local normalized PPR component. */
58
+ graph: number;
59
+ /** Query-aware final multiplier, such as test-file de-ranking. */
60
+ rankFactor: number;
61
+ }
62
+ export interface FusionResult {
63
+ /** fused order, best first; carries per-doc scope label + fused score.
64
+ * Normalized so the top MULTI-scope fused doc is 1 — but the single-scoring-
65
+ * scope degenerate case passes ORIGINAL (pre-fusion) scores through
66
+ * unchanged, and those are not guaranteed to fall in [0,1]. */
67
+ ranked: {
68
+ id: string;
69
+ scope: string;
70
+ score: number;
71
+ }[];
72
+ /** scopes that participated in fusion */
73
+ federated: string[];
74
+ /** scopes that matched weakly (≥1 scoring doc but below the participation gate) with their best doc */
75
+ alsoMatched: {
76
+ scope: string;
77
+ bestId: string;
78
+ }[];
79
+ }
80
+ /** RRF smoothing constant — the standard value from the original RRF paper;
81
+ * high enough that rank 1 vs 2 differ gently rather than by 2×. */
82
+ export declare const RRF_K = 60;
83
+ /** A scope federates only when its best doc scores at least this share of the
84
+ * global best — below it the match is reported, not fused. Used by
85
+ * `fuseScopes`'s own internal gate (a post-normalization safety net once a
86
+ * caller has already applied the real match-strength gate — see
87
+ * {@link STRONG_FLOOR}/{@link HIGH_FLOOR}). */
88
+ export declare const PARTICIPATION_RATIO = 0.25;
89
+ /** The single source of truth for the cross-scope participation gate shared
90
+ * by `rankScopesAndFuse` (single-graph multi-scope) and `federateAsk`
91
+ * (workspace federation, `src/graph/workspace.ts`) — the two paths that solve
92
+ * the identical "a weak scope must not federate beside a strong one" problem.
93
+ * They MUST use the same floors so they can never drift into inconsistent
94
+ * behavior again.
95
+ *
96
+ * A scope federates iff its top hit matched a query term in a NAME/PATH field
97
+ * at all (any strength ≥ `STRONG_FLOOR`) — the primary gate. Well below every
98
+ * genuine fixture (≥0.45) yet strictly above a body-only collision's 0, so a
99
+ * real partial-relevance hit on a common/low-idf term is never overcorrected
100
+ * out. */
101
+ export declare const STRONG_FLOOR = 0.1;
102
+ /** …OR the overall (name+path+body) coverage is broad enough to be real even
103
+ * body-only. A single incidental body-token collision measures ~0.29 and RISES
104
+ * with corpus size (0.30+ at 200 nodes) but never approaches this, while a
105
+ * genuinely broad match clears it. This is why the gate is on absolute,
106
+ * scale-invariant floors, NOT a raw-lexical-score ratio (which — calibrated for
107
+ * raw-lexical-SCORE space — was far too lenient in coverage/matched-fraction
108
+ * space and leaked junk, worsening as the corpus grew). */
109
+ export declare const HIGH_FLOOR = 0.5;
110
+ /**
111
+ * Partition by scope, rank within scope (input scores are already
112
+ * per-scope-normalized), gate by soft federation, fuse by RRF:
113
+ * `fused(id) = Σ 1/(K + rank_in_scope(id))`, then normalized so the top fused
114
+ * doc is 1. Non-scoring docs (score ≤ 0) are dropped entirely.
115
+ *
116
+ * Degenerate cases degrade to current behavior: zero scoring docs → empty
117
+ * result; exactly one scoring scope → its docs pass through in score order
118
+ * with their ORIGINAL scores (no RRF re-scoring, no gate) — byte-for-byte the
119
+ * single-corpus ranking the caller would have produced anyway.
120
+ */
121
+ export declare function fuseScopes(docs: ScopedDoc[]): FusionResult;
122
+ /**
123
+ * Combine scopes whose scores are ALREADY comparable (shared corpus statistics
124
+ * and a shared normalization denominator — see the module header). Same shape
125
+ * and same gate as {@link fuseScopes}, but the combined order is read straight
126
+ * off the score instead of from reciprocal rank, because with a common scale
127
+ * the magnitude is exactly the signal rank fusion would throw away.
128
+ *
129
+ * Only {@link rankScopesAndFuse} may call this. `federateAsk` fuses separate
130
+ * repositories, which have no common denominator, and must keep using
131
+ * {@link fuseScopes}.
132
+ */
133
+ export declare function combineComparableScopes(docs: ScopedDoc[]): FusionResult;
134
+ /** The per-scope scoring hooks `rankScopesAndFuse` drives — the caller owns
135
+ * the actual lexical math and graph walk (they need its corpus state); this
136
+ * module owns the orchestration so the shape of "rank per scope, then fuse"
137
+ * lives in one place. */
138
+ export interface ScopeRankOps {
139
+ /** Lexical scores for the scope's own docs (positive entries only), computed
140
+ * against the REPO-WIDE corpus statistics. Per-scope statistics would make
141
+ * the returned numbers incomparable between scopes, which is exactly the
142
+ * defect in #117 — see the module header. */
143
+ lex(scope: string): Map<string, number>;
144
+ /** Does ANY scoring doc in this scope match a query term in its NAME or PATH?
145
+ *
146
+ * Serves ONE narrow purpose: suppressing a scope whose entire claim on the
147
+ * query is prose. Score cannot catch that on its own — BM25 rewards a term
148
+ * repeated in comments, so a file mentioning "gateway" thirty times in a
149
+ * banner can outscore the class actually named `GatewayTimeout`.
150
+ *
151
+ * Deliberately evaluated over the whole scope, not just its top hit, and as a
152
+ * presence check rather than a share threshold. Both choices are load-bearing:
153
+ * a share of the whole query is unreachable for long queries (which is how the
154
+ * old gate ended up admitting one scope and hiding the rest), and judging a
155
+ * scope by its single best doc suppressed any scope whose top hit was a file
156
+ * node — measured at 7.6 points of pooled R@10. */
157
+ hasIdentifierMatch?(scope: string): boolean;
158
+ /** Graph walk restricted to the scope's subgraph, seeded by that scope's
159
+ * lexical scores; returns top-normalized centrality (or an empty map). */
160
+ walk(scope: string, seeds: Map<string, number>): Map<string, number>;
161
+ /** Optional query-aware multiplier applied after lexical normalization and
162
+ * graph blending. Use this for priors (such as test-file de-ranking) that
163
+ * normalization must not erase. */
164
+ rankFactor?(scope: string, id: string): number;
165
+ /** Optional candidate collapse after lexical + graph components are known
166
+ * but before comparable scopes are gated and combined. File-aware ranking uses this
167
+ * to supply exactly one real representative per file. The default path omits
168
+ * the hook and remains byte-identical. */
169
+ collapseCandidates?(candidates: readonly ScopeRankCandidate[]): readonly ScopedDoc[];
170
+ }
171
+ /**
172
+ * Multi-scope orchestration for `ask`'s symbol ranking: for each scope, score
173
+ * lexically (against the repo-wide statistics the caller supplies), walk the
174
+ * scope's subgraph, blend exactly like the single-scope path (`lexN +
175
+ * graphWeight·pr`, walk-rescued nodes joining above `rescueFloor`), then
176
+ * combine the scopes with {@link combineComparableScopes}. A scope with zero
177
+ * lexical matches contributes nothing (no seeds → no walk → no docs).
178
+ *
179
+ * The one thing that differs from the single-scope path: `lexN` divides by
180
+ * `globalMaxLex`, the best raw lexical score across ALL scopes, rather than by
181
+ * each scope's own best. That shared denominator is what makes the blended
182
+ * scores comparable, and therefore what lets the combined order be read off the
183
+ * score. Dividing per scope — as this did before #117 — pinned every scope's
184
+ * top hit to ~1.0 regardless of how well it matched, which is the defect.
185
+ *
186
+ * Participation is then the {@link PARTICIPATION_RATIO} share check inside
187
+ * {@link combineComparableScopes}: a scope must reach a real fraction of the
188
+ * best score anywhere in the repo, else it is reported in `alsoMatched` for
189
+ * `--in`. The match-STRENGTH floors ({@link STRONG_FLOOR}/{@link HIGH_FLOOR})
190
+ * are no longer applied here — they existed to stand in for a share check that
191
+ * per-scope normalization had made vacuous. `federateAsk` still normalizes per
192
+ * child repo, so it still gates on strength; see `src/graph/workspace.ts`.
193
+ */
194
+ export declare function rankScopesAndFuse(scopes: string[], ops: ScopeRankOps, graphWeight: number, rescueFloor: number): FusionResult;
195
+ //# sourceMappingURL=fuse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuse.d.ts","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH;;8EAE8E;AAC9E,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;2DAE2D;AAC3D,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B;;;mEAG+D;IAC/D,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,yCAAyC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,uGAAuG;IACvG,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClD;AAED;mEACmE;AACnE,eAAO,MAAM,KAAK,KAAK,CAAC;AAExB;;;;+CAI+C;AAC/C,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC;;;;;;;;;;;UAWU;AACV,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC;;;;;;2DAM2D;AAC3D,eAAO,MAAM,UAAU,MAAM,CAAC;AAQ9B;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,YAAY,CA+D1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,YAAY,CAyDvE;AAED;;;yBAGyB;AACzB,MAAM,WAAW,YAAY;IAC3B;;;iDAG6C;IAC7C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC;;;;;;;;;;;;uDAYmD;IACnD,kBAAkB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5C;8EAC0E;IAC1E,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrE;;uCAEmC;IACnC,UAAU,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/C;;;8CAG0C;IAC1C,kBAAkB,CAAC,CACjB,UAAU,EAAE,SAAS,kBAAkB,EAAE,GACxC,SAAS,SAAS,EAAE,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,YAAY,CAqFd"}
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Scope-aware ranking for `graft ask`. Pure functions, no fs.
3
+ *
4
+ * The problem: lexical + graph scores are corpus-relative. In a multi-scope
5
+ * repo (a monorepo's `frontend/` + `backend/`, sub-projects under one root),
6
+ * scoring every node against one pooled corpus lets the biggest sub-project set
7
+ * the score scale and drown the small one.
8
+ *
9
+ * This module solves it by keeping the scope PARTITION — each scope is scored
10
+ * and walked separately — while making the resulting scores COMPARABLE, so the
11
+ * combined order can be read straight off the score. Comparability has two
12
+ * requirements, and both must hold or the order is meaningless:
13
+ *
14
+ * 1. shared corpus statistics — the caller scores every scope against the
15
+ * repo-wide IDF and length prior (see `ask.ts`), so the same term is worth
16
+ * the same everywhere;
17
+ * 2. a shared normalization denominator — {@link rankScopesAndFuse} divides
18
+ * every scope by the best raw score in the REPO, not by each scope's own
19
+ * best (see `globalMaxLex` there).
20
+ *
21
+ * Issue #117 was the consequence of neither holding. Each scope divided by its
22
+ * own maximum, so a barely-relevant scope's top hit normalized to ~1.0 exactly
23
+ * like the genuinely relevant scope's top hit; RRF then fused by RANK, which
24
+ * discards magnitude outright, so the weak scope's rank-1 tied the strong
25
+ * scope's rank-1 and displaced its rank-2 — frequently the answer. Measurement
26
+ * across four repositories and four ecosystems put 73% of missed files in that
27
+ * bucket. RRF is retained for `federateAsk` (see `graph/workspace.ts`), where
28
+ * the corpora really are separate repositories and no shared denominator
29
+ * exists — that is the case rank fusion is for.
30
+ *
31
+ * Soft federation: a scope whose top hit is probably an incidental word
32
+ * collision, not a second home for the query, is left out of the combined order
33
+ * and reported in `alsoMatched` instead, so the output can say "also matched:
34
+ * docs/ — narrow with --in docs/" rather than diluting the pack. With
35
+ * comparable scores that gate is simply {@link PARTICIPATION_RATIO} — a scope
36
+ * must reach a real share of the best score anywhere in the repo. Under
37
+ * per-scope normalization that check was vacuous (every scope's top was ~1.0),
38
+ * which is why a separate match-STRENGTH gate ({@link STRONG_FLOOR}/{@link
39
+ * HIGH_FLOOR}) had to stand in for it; that signal is still exported and still
40
+ * used by `federateAsk`, which normalizes per child repo and therefore still
41
+ * needs it.
42
+ */
43
+ /** RRF smoothing constant — the standard value from the original RRF paper;
44
+ * high enough that rank 1 vs 2 differ gently rather than by 2×. */
45
+ export const RRF_K = 60;
46
+ /** A scope federates only when its best doc scores at least this share of the
47
+ * global best — below it the match is reported, not fused. Used by
48
+ * `fuseScopes`'s own internal gate (a post-normalization safety net once a
49
+ * caller has already applied the real match-strength gate — see
50
+ * {@link STRONG_FLOOR}/{@link HIGH_FLOOR}). */
51
+ export const PARTICIPATION_RATIO = 0.25;
52
+ /** The single source of truth for the cross-scope participation gate shared
53
+ * by `rankScopesAndFuse` (single-graph multi-scope) and `federateAsk`
54
+ * (workspace federation, `src/graph/workspace.ts`) — the two paths that solve
55
+ * the identical "a weak scope must not federate beside a strong one" problem.
56
+ * They MUST use the same floors so they can never drift into inconsistent
57
+ * behavior again.
58
+ *
59
+ * A scope federates iff its top hit matched a query term in a NAME/PATH field
60
+ * at all (any strength ≥ `STRONG_FLOOR`) — the primary gate. Well below every
61
+ * genuine fixture (≥0.45) yet strictly above a body-only collision's 0, so a
62
+ * real partial-relevance hit on a common/low-idf term is never overcorrected
63
+ * out. */
64
+ export const STRONG_FLOOR = 0.1;
65
+ /** …OR the overall (name+path+body) coverage is broad enough to be real even
66
+ * body-only. A single incidental body-token collision measures ~0.29 and RISES
67
+ * with corpus size (0.30+ at 200 nodes) but never approaches this, while a
68
+ * genuinely broad match clears it. This is why the gate is on absolute,
69
+ * scale-invariant floors, NOT a raw-lexical-score ratio (which — calibrated for
70
+ * raw-lexical-SCORE space — was far too lenient in coverage/matched-fraction
71
+ * space and leaked junk, worsening as the corpus grew). */
72
+ export const HIGH_FLOOR = 0.5;
73
+ /** Score-desc, id-asc ordering — the id tiebreak is what makes fusion
74
+ * deterministic under input shuffle. */
75
+ function byScore(a, b) {
76
+ return b.score - a.score || a.id.localeCompare(b.id);
77
+ }
78
+ /**
79
+ * Partition by scope, rank within scope (input scores are already
80
+ * per-scope-normalized), gate by soft federation, fuse by RRF:
81
+ * `fused(id) = Σ 1/(K + rank_in_scope(id))`, then normalized so the top fused
82
+ * doc is 1. Non-scoring docs (score ≤ 0) are dropped entirely.
83
+ *
84
+ * Degenerate cases degrade to current behavior: zero scoring docs → empty
85
+ * result; exactly one scoring scope → its docs pass through in score order
86
+ * with their ORIGINAL scores (no RRF re-scoring, no gate) — byte-for-byte the
87
+ * single-corpus ranking the caller would have produced anyway.
88
+ */
89
+ export function fuseScopes(docs) {
90
+ const byScope = new Map();
91
+ for (const d of docs) {
92
+ if (d.score <= 0)
93
+ continue;
94
+ const list = byScope.get(d.scope);
95
+ if (list)
96
+ list.push(d);
97
+ else
98
+ byScope.set(d.scope, [d]);
99
+ }
100
+ for (const list of byScope.values())
101
+ list.sort(byScore);
102
+ if (byScope.size === 0)
103
+ return { ranked: [], federated: [], alsoMatched: [] };
104
+ if (byScope.size === 1) {
105
+ const [scope, list] = byScope.entries().next().value;
106
+ return {
107
+ ranked: list.map((d) => ({ id: d.id, scope, score: d.score })),
108
+ federated: [scope],
109
+ alsoMatched: [],
110
+ };
111
+ }
112
+ // Gate: order scopes by their best doc (desc, scope-name tiebreak), split
113
+ // into federated (≥ ratio × global best, inclusive) and alsoMatched.
114
+ const scopesByBest = [...byScope.entries()].sort((a, b) => b[1][0].score - a[1][0].score || a[0].localeCompare(b[0]));
115
+ const gate = PARTICIPATION_RATIO * scopesByBest[0][1][0].score;
116
+ const federated = [];
117
+ const alsoMatched = [];
118
+ for (const [scope, list] of scopesByBest) {
119
+ if (list[0].score >= gate)
120
+ federated.push(scope);
121
+ else
122
+ alsoMatched.push({ scope, bestId: list[0].id });
123
+ }
124
+ // RRF: each federated scope contributes 1/(K + rank) per doc; an id listed
125
+ // in more than one scope sums its contributions and is attributed to the
126
+ // scope where it ranked best.
127
+ const acc = new Map();
128
+ for (const scope of federated) {
129
+ byScope.get(scope).forEach((d, i) => {
130
+ const contribution = 1 / (RRF_K + i + 1);
131
+ const prev = acc.get(d.id);
132
+ if (!prev)
133
+ acc.set(d.id, { scope, score: contribution, bestRank: i });
134
+ else {
135
+ prev.score += contribution;
136
+ if (i < prev.bestRank) {
137
+ prev.scope = scope;
138
+ prev.bestRank = i;
139
+ }
140
+ }
141
+ });
142
+ }
143
+ let max = 0;
144
+ for (const e of acc.values())
145
+ if (e.score > max)
146
+ max = e.score;
147
+ const ranked = [...acc.entries()].map(([id, e]) => ({
148
+ id,
149
+ scope: e.scope,
150
+ score: e.score / max,
151
+ }));
152
+ ranked.sort((a, b) => b.score - a.score || a.scope.localeCompare(b.scope) || a.id.localeCompare(b.id));
153
+ return { ranked, federated, alsoMatched };
154
+ }
155
+ /**
156
+ * Combine scopes whose scores are ALREADY comparable (shared corpus statistics
157
+ * and a shared normalization denominator — see the module header). Same shape
158
+ * and same gate as {@link fuseScopes}, but the combined order is read straight
159
+ * off the score instead of from reciprocal rank, because with a common scale
160
+ * the magnitude is exactly the signal rank fusion would throw away.
161
+ *
162
+ * Only {@link rankScopesAndFuse} may call this. `federateAsk` fuses separate
163
+ * repositories, which have no common denominator, and must keep using
164
+ * {@link fuseScopes}.
165
+ */
166
+ export function combineComparableScopes(docs) {
167
+ const byScope = new Map();
168
+ for (const d of docs) {
169
+ if (d.score <= 0)
170
+ continue;
171
+ const list = byScope.get(d.scope);
172
+ if (list)
173
+ list.push(d);
174
+ else
175
+ byScope.set(d.scope, [d]);
176
+ }
177
+ for (const list of byScope.values())
178
+ list.sort(byScore);
179
+ if (byScope.size === 0)
180
+ return { ranked: [], federated: [], alsoMatched: [] };
181
+ // One scoring scope: pass through untouched. Identical to the single-scope
182
+ // path by construction — the guarantee that a single-scope repo cannot move.
183
+ if (byScope.size === 1) {
184
+ const [scope, list] = byScope.entries().next().value;
185
+ return {
186
+ ranked: list.map((d) => ({ id: d.id, scope, score: d.score })),
187
+ federated: [scope],
188
+ alsoMatched: [],
189
+ };
190
+ }
191
+ // Gate on a real share of the best score in the repo. This is the same
192
+ // ratio check `fuseScopes` runs, but here it MEANS something: the scores
193
+ // being compared share a denominator.
194
+ const scopesByBest = [...byScope.entries()].sort((a, b) => b[1][0].score - a[1][0].score || a[0].localeCompare(b[0]));
195
+ const gate = PARTICIPATION_RATIO * scopesByBest[0][1][0].score;
196
+ const federated = [];
197
+ const alsoMatched = [];
198
+ for (const [scope, list] of scopesByBest) {
199
+ if (list[0].score >= gate)
200
+ federated.push(scope);
201
+ else
202
+ alsoMatched.push({ scope, bestId: list[0].id });
203
+ }
204
+ // An id can only belong to one scope (scope is a path prefix), but keep the
205
+ // defensive max so a duplicate cannot double-count or flip its attribution.
206
+ const acc = new Map();
207
+ for (const scope of federated) {
208
+ for (const d of byScope.get(scope)) {
209
+ const prev = acc.get(d.id);
210
+ if (!prev || d.score > prev.score)
211
+ acc.set(d.id, { scope, score: d.score });
212
+ }
213
+ }
214
+ let max = 0;
215
+ for (const e of acc.values())
216
+ if (e.score > max)
217
+ max = e.score;
218
+ const ranked = [...acc.entries()].map(([id, e]) => ({
219
+ id,
220
+ scope: e.scope,
221
+ score: max > 0 ? e.score / max : 0,
222
+ }));
223
+ ranked.sort((a, b) => b.score - a.score || a.scope.localeCompare(b.scope) || a.id.localeCompare(b.id));
224
+ return { ranked, federated, alsoMatched };
225
+ }
226
+ /**
227
+ * Multi-scope orchestration for `ask`'s symbol ranking: for each scope, score
228
+ * lexically (against the repo-wide statistics the caller supplies), walk the
229
+ * scope's subgraph, blend exactly like the single-scope path (`lexN +
230
+ * graphWeight·pr`, walk-rescued nodes joining above `rescueFloor`), then
231
+ * combine the scopes with {@link combineComparableScopes}. A scope with zero
232
+ * lexical matches contributes nothing (no seeds → no walk → no docs).
233
+ *
234
+ * The one thing that differs from the single-scope path: `lexN` divides by
235
+ * `globalMaxLex`, the best raw lexical score across ALL scopes, rather than by
236
+ * each scope's own best. That shared denominator is what makes the blended
237
+ * scores comparable, and therefore what lets the combined order be read off the
238
+ * score. Dividing per scope — as this did before #117 — pinned every scope's
239
+ * top hit to ~1.0 regardless of how well it matched, which is the defect.
240
+ *
241
+ * Participation is then the {@link PARTICIPATION_RATIO} share check inside
242
+ * {@link combineComparableScopes}: a scope must reach a real fraction of the
243
+ * best score anywhere in the repo, else it is reported in `alsoMatched` for
244
+ * `--in`. The match-STRENGTH floors ({@link STRONG_FLOOR}/{@link HIGH_FLOOR})
245
+ * are no longer applied here — they existed to stand in for a share check that
246
+ * per-scope normalization had made vacuous. `federateAsk` still normalizes per
247
+ * child repo, so it still gates on strength; see `src/graph/workspace.ts`.
248
+ */
249
+ export function rankScopesAndFuse(scopes, ops, graphWeight, rescueFloor) {
250
+ // Pass 1: lexical scoring only, per scope.
251
+ const lexByScope = new Map();
252
+ for (const scope of scopes) {
253
+ const lex = ops.lex(scope);
254
+ if (lex.size === 0)
255
+ continue;
256
+ lexByScope.set(scope, lex);
257
+ }
258
+ const alsoMatched = [];
259
+ const candidatesWithComponents = [];
260
+ // Per-scope raw best, plus the best raw score anywhere in the repo. That
261
+ // repo-wide maximum is the shared denominator every scope normalizes by.
262
+ const meta = new Map();
263
+ let globalMaxLex = 0;
264
+ for (const [scope, lex] of lexByScope) {
265
+ let maxLex = 0, bestId = "";
266
+ for (const [id, v] of lex)
267
+ if (v > maxLex || (v === maxLex && id < bestId)) {
268
+ maxLex = v;
269
+ bestId = id;
270
+ }
271
+ if (maxLex <= 0)
272
+ continue;
273
+ meta.set(scope, { lex, maxLex, bestId });
274
+ if (maxLex > globalMaxLex)
275
+ globalMaxLex = maxLex;
276
+ }
277
+ // Body-only suppression. With a shared denominator a weak scope simply
278
+ // scores low, so participation is decided on score in
279
+ // `combineComparableScopes` — no scope is excluded on a share threshold any
280
+ // more. The single exception is a scope in which NO doc matched a query term
281
+ // in a name or path while some other scope did: that is the comment-banner
282
+ // collision (see `hasIdentifierMatch` above), and score cannot separate it
283
+ // from a real match. Only applied when a genuine identifier match exists
284
+ // somewhere, so a query that legitimately matches only prose still returns
285
+ // something.
286
+ const bodyOnly = new Set();
287
+ if (ops.hasIdentifierMatch) {
288
+ const named = new Map();
289
+ for (const scope of meta.keys())
290
+ named.set(scope, ops.hasIdentifierMatch(scope));
291
+ if ([...named.values()].some(Boolean)) {
292
+ for (const [scope, ok] of named)
293
+ if (!ok)
294
+ bodyOnly.add(scope);
295
+ }
296
+ }
297
+ for (const scope of bodyOnly) {
298
+ alsoMatched.push({ scope, bestId: meta.get(scope).bestId });
299
+ meta.delete(scope);
300
+ }
301
+ // The denominator must come from the scopes that actually rank, or a
302
+ // suppressed scope could still set the scale for everyone else.
303
+ globalMaxLex = 0;
304
+ for (const { maxLex } of meta.values())
305
+ if (maxLex > globalMaxLex)
306
+ globalMaxLex = maxLex;
307
+ for (const [scope, { lex }] of meta) {
308
+ const pr = ops.walk(scope, lex);
309
+ const candidates = new Set(lex.keys());
310
+ for (const [id, p] of pr)
311
+ if (p >= rescueFloor)
312
+ candidates.add(id);
313
+ for (const id of candidates) {
314
+ const lexN = globalMaxLex > 0 ? (lex.get(id) ?? 0) / globalMaxLex : 0;
315
+ const graph = pr.get(id) ?? 0;
316
+ const rankFactor = ops.rankFactor?.(scope, id) ?? 1;
317
+ const blended = (lexN + graphWeight * graph) * rankFactor;
318
+ if (blended > 0) {
319
+ candidatesWithComponents.push({
320
+ id,
321
+ scope,
322
+ score: blended,
323
+ lexical: lexN,
324
+ graph,
325
+ rankFactor,
326
+ });
327
+ }
328
+ }
329
+ }
330
+ const scoped = ops.collapseCandidates
331
+ ? [...ops.collapseCandidates(candidatesWithComponents)]
332
+ : candidatesWithComponents.map((candidate) => ({
333
+ id: candidate.id,
334
+ scope: candidate.scope,
335
+ score: candidate.score,
336
+ }));
337
+ const combined = combineComparableScopes(scoped);
338
+ return {
339
+ ranked: combined.ranked,
340
+ federated: combined.federated,
341
+ alsoMatched: [...alsoMatched, ...combined.alsoMatched],
342
+ };
343
+ }
344
+ //# sourceMappingURL=fuse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Graph-rank re-ranking for `graft ask` — the fix for lexical keyword-collision.
3
+ *
4
+ * Pure term-overlap ranking treats every node independently, so a node that
5
+ * merely shares a word with the query (a window "overlay" widget) can outrank
6
+ * the node the query is actually about (a scroll-"overlay" config) purely on
7
+ * word count. The graph knows better: the right node is the one wired into the
8
+ * cluster of code the query touches.
9
+ *
10
+ * This module runs personalized PageRank (random-walk-with-restart) over the
11
+ * wiring graph, seeded by the lexical scores. Mass concentrates on nodes that
12
+ * are edge-connected to the matched set; a lexically-matched but structurally
13
+ * isolated node keeps only its own restart mass and sinks. "Lexical proposes,
14
+ * graph disposes." Deterministic, $0, no embeddings — a lexical-seed →
15
+ * graph-rank pipeline, the established alternative to vector search for code.
16
+ */
17
+ import type { GraphV1 } from "../graph/types.js";
18
+ export interface PageRankOptions {
19
+ /** Restart probability — the mass that teleports back to the seed set each
20
+ * step. Higher keeps the walk closer to the seeds. 0.25 is the standard value. */
21
+ alpha?: number;
22
+ /** Power-iteration count. 25 is plenty to converge on graphs this size. */
23
+ iters?: number;
24
+ /** Restrict the walk to a subgraph: when present, an edge counts only when
25
+ * BOTH endpoints pass, and only passing ids can hold rank mass or seed
26
+ * weight. Seeds outside the filter are silently ignored (same as a seed
27
+ * naming a non-existent node). Omit for the full-graph walk (unchanged
28
+ * behavior). */
29
+ nodeFilter?: (id: string) => boolean;
30
+ }
31
+ /** Immutable graph topology consumed by the PageRank iteration. Preparing it
32
+ * separately lets a multi-scope query partition one large graph once, instead
33
+ * of rescanning every node and edge for every scope. */
34
+ export interface PageRankTopology {
35
+ ids: ReadonlySet<string>;
36
+ adjacency: ReadonlyMap<string, readonly string[]>;
37
+ }
38
+ export type PageRankRunOptions = Pick<PageRankOptions, "alpha" | "iters">;
39
+ /** Build independent PageRank topologies in one node pass and one edge pass.
40
+ * Edges crossing partitions are excluded, exactly like applying a nodeFilter
41
+ * for each partition independently. Returning `undefined` omits a node. */
42
+ export declare function preparePageRankPartitions(graph: GraphV1, partitionOfId: (id: string) => string | undefined): Map<string, PageRankTopology>;
43
+ /** Prepare one optionally filtered topology. Kept public for callers/tests that
44
+ * reuse the same graph across multiple seed sets. */
45
+ export declare function preparePageRankTopology(graph: GraphV1, nodeFilter?: (id: string) => boolean): PageRankTopology;
46
+ /**
47
+ * Personalized PageRank over the wiring graph.
48
+ *
49
+ * `seeds` maps node id → restart weight (a node's lexical score; only positive
50
+ * weights matter). The graph is treated as UNDIRECTED — for "understand this
51
+ * area" a callee is as relevant as a caller. Returns a score per node
52
+ * normalized so the top node is 1; nodes untouched by the walk are absent.
53
+ *
54
+ * Edges whose endpoints aren't both real nodes (e.g. an unresolved import
55
+ * module string) are ignored, so only genuine symbol-to-symbol wiring counts.
56
+ */
57
+ export declare function personalizedPageRank(graph: GraphV1, seeds: Map<string, number>, opts?: PageRankOptions): Map<string, number>;
58
+ /** Run PageRank on an already prepared topology. This is numerically identical
59
+ * to {@link personalizedPageRank}; it only removes repeated topology scans. */
60
+ export declare function personalizedPageRankPrepared(topology: PageRankTopology, seeds: Map<string, number>, opts?: PageRankRunOptions): Map<string, number>;
61
+ //# sourceMappingURL=graphrank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphrank.d.ts","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD,MAAM,WAAW,eAAe;IAC9B;sFACkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;oBAIgB;IAChB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED;;wDAEwD;AACxD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CACnD;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;AAkB1E;;2EAE2E;AAC3E,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAChD,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAuB/B;AAED;qDACqD;AACrD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GACnC,gBAAgB,CAclB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,IAAI,GAAE,eAAoB,GACzB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAMrB;AAED;+EAC+E;AAC/E,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,IAAI,GAAE,kBAAuB,GAC5B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8CrB"}