sdl-mcp 0.6.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 (496) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/config/benchmark.ci.config.json +86 -0
  4. package/config/benchmark.ci.windows.config.json +86 -0
  5. package/config/benchmark.config.example.json +86 -0
  6. package/config/benchmark.config.json +86 -0
  7. package/config/sdlmcp.config.example.json +139 -0
  8. package/config/sdlmcp.config.json +48 -0
  9. package/config/sdlmcp.config.schema.json +381 -0
  10. package/dist/agent/evidence.d.ts +18 -0
  11. package/dist/agent/evidence.d.ts.map +1 -0
  12. package/dist/agent/evidence.js +107 -0
  13. package/dist/agent/evidence.js.map +1 -0
  14. package/dist/agent/executor.d.ts +28 -0
  15. package/dist/agent/executor.d.ts.map +1 -0
  16. package/dist/agent/executor.js +261 -0
  17. package/dist/agent/executor.js.map +1 -0
  18. package/dist/agent/index.d.ts +6 -0
  19. package/dist/agent/index.d.ts.map +1 -0
  20. package/dist/agent/index.js +6 -0
  21. package/dist/agent/index.js.map +1 -0
  22. package/dist/agent/orchestrator.d.ts +14 -0
  23. package/dist/agent/orchestrator.d.ts.map +1 -0
  24. package/dist/agent/orchestrator.js +108 -0
  25. package/dist/agent/orchestrator.js.map +1 -0
  26. package/dist/agent/planner.d.ts +21 -0
  27. package/dist/agent/planner.d.ts.map +1 -0
  28. package/dist/agent/planner.js +153 -0
  29. package/dist/agent/planner.js.map +1 -0
  30. package/dist/agent/types.d.ts +86 -0
  31. package/dist/agent/types.d.ts.map +1 -0
  32. package/dist/agent/types.js +2 -0
  33. package/dist/agent/types.js.map +1 -0
  34. package/dist/benchmark/index.d.ts +4 -0
  35. package/dist/benchmark/index.d.ts.map +1 -0
  36. package/dist/benchmark/index.js +4 -0
  37. package/dist/benchmark/index.js.map +1 -0
  38. package/dist/benchmark/regression.d.ts +40 -0
  39. package/dist/benchmark/regression.d.ts.map +1 -0
  40. package/dist/benchmark/regression.js +199 -0
  41. package/dist/benchmark/regression.js.map +1 -0
  42. package/dist/benchmark/smoothing.d.ts +40 -0
  43. package/dist/benchmark/smoothing.d.ts.map +1 -0
  44. package/dist/benchmark/smoothing.js +121 -0
  45. package/dist/benchmark/smoothing.js.map +1 -0
  46. package/dist/benchmark/threshold.d.ts +64 -0
  47. package/dist/benchmark/threshold.d.ts.map +1 -0
  48. package/dist/benchmark/threshold.js +173 -0
  49. package/dist/benchmark/threshold.js.map +1 -0
  50. package/dist/cli/argParsing.d.ts +34 -0
  51. package/dist/cli/argParsing.d.ts.map +1 -0
  52. package/dist/cli/argParsing.js +329 -0
  53. package/dist/cli/argParsing.js.map +1 -0
  54. package/dist/cli/commands/benchmark.d.ts +16 -0
  55. package/dist/cli/commands/benchmark.d.ts.map +1 -0
  56. package/dist/cli/commands/benchmark.js +412 -0
  57. package/dist/cli/commands/benchmark.js.map +1 -0
  58. package/dist/cli/commands/doctor.d.ts +3 -0
  59. package/dist/cli/commands/doctor.d.ts.map +1 -0
  60. package/dist/cli/commands/doctor.js +218 -0
  61. package/dist/cli/commands/doctor.js.map +1 -0
  62. package/dist/cli/commands/export.d.ts +12 -0
  63. package/dist/cli/commands/export.d.ts.map +1 -0
  64. package/dist/cli/commands/export.js +70 -0
  65. package/dist/cli/commands/export.js.map +1 -0
  66. package/dist/cli/commands/import.d.ts +10 -0
  67. package/dist/cli/commands/import.d.ts.map +1 -0
  68. package/dist/cli/commands/import.js +40 -0
  69. package/dist/cli/commands/import.js.map +1 -0
  70. package/dist/cli/commands/index.d.ts +3 -0
  71. package/dist/cli/commands/index.d.ts.map +1 -0
  72. package/dist/cli/commands/index.js +89 -0
  73. package/dist/cli/commands/index.js.map +1 -0
  74. package/dist/cli/commands/init.d.ts +3 -0
  75. package/dist/cli/commands/init.d.ts.map +1 -0
  76. package/dist/cli/commands/init.js +221 -0
  77. package/dist/cli/commands/init.js.map +1 -0
  78. package/dist/cli/commands/pull.d.ts +11 -0
  79. package/dist/cli/commands/pull.d.ts.map +1 -0
  80. package/dist/cli/commands/pull.js +47 -0
  81. package/dist/cli/commands/pull.js.map +1 -0
  82. package/dist/cli/commands/serve.d.ts +3 -0
  83. package/dist/cli/commands/serve.d.ts.map +1 -0
  84. package/dist/cli/commands/serve.js +72 -0
  85. package/dist/cli/commands/serve.js.map +1 -0
  86. package/dist/cli/commands/version.d.ts +3 -0
  87. package/dist/cli/commands/version.d.ts.map +1 -0
  88. package/dist/cli/commands/version.js +24 -0
  89. package/dist/cli/commands/version.js.map +1 -0
  90. package/dist/cli/index.d.ts +3 -0
  91. package/dist/cli/index.d.ts.map +1 -0
  92. package/dist/cli/index.js +213 -0
  93. package/dist/cli/index.js.map +1 -0
  94. package/dist/cli/logging.d.ts +10 -0
  95. package/dist/cli/logging.d.ts.map +1 -0
  96. package/dist/cli/logging.js +48 -0
  97. package/dist/cli/logging.js.map +1 -0
  98. package/dist/cli/transport/http.d.ts +3 -0
  99. package/dist/cli/transport/http.d.ts.map +1 -0
  100. package/dist/cli/transport/http.js +106 -0
  101. package/dist/cli/transport/http.js.map +1 -0
  102. package/dist/cli/transport/stdio.d.ts +3 -0
  103. package/dist/cli/transport/stdio.d.ts.map +1 -0
  104. package/dist/cli/transport/stdio.js +6 -0
  105. package/dist/cli/transport/stdio.js.map +1 -0
  106. package/dist/cli/types.d.ts +41 -0
  107. package/dist/cli/types.d.ts.map +1 -0
  108. package/dist/cli/types.js +2 -0
  109. package/dist/cli/types.js.map +1 -0
  110. package/dist/code/gate.d.ts +11 -0
  111. package/dist/code/gate.d.ts.map +1 -0
  112. package/dist/code/gate.js +134 -0
  113. package/dist/code/gate.js.map +1 -0
  114. package/dist/code/hotpath.d.ts +17 -0
  115. package/dist/code/hotpath.d.ts.map +1 -0
  116. package/dist/code/hotpath.js +200 -0
  117. package/dist/code/hotpath.js.map +1 -0
  118. package/dist/code/redact.d.ts +19 -0
  119. package/dist/code/redact.d.ts.map +1 -0
  120. package/dist/code/redact.js +92 -0
  121. package/dist/code/redact.js.map +1 -0
  122. package/dist/code/skeleton.d.ts +32 -0
  123. package/dist/code/skeleton.d.ts.map +1 -0
  124. package/dist/code/skeleton.js +610 -0
  125. package/dist/code/skeleton.js.map +1 -0
  126. package/dist/code/windows.d.ts +18 -0
  127. package/dist/code/windows.d.ts.map +1 -0
  128. package/dist/code/windows.js +236 -0
  129. package/dist/code/windows.js.map +1 -0
  130. package/dist/config/constants.d.ts +340 -0
  131. package/dist/config/constants.d.ts.map +1 -0
  132. package/dist/config/constants.js +379 -0
  133. package/dist/config/constants.js.map +1 -0
  134. package/dist/config/loadConfig.d.ts +3 -0
  135. package/dist/config/loadConfig.d.ts.map +1 -0
  136. package/dist/config/loadConfig.js +71 -0
  137. package/dist/config/loadConfig.js.map +1 -0
  138. package/dist/config/types.d.ts +509 -0
  139. package/dist/config/types.d.ts.map +1 -0
  140. package/dist/config/types.js +139 -0
  141. package/dist/config/types.js.map +1 -0
  142. package/dist/db/db.d.ts +4 -0
  143. package/dist/db/db.d.ts.map +1 -0
  144. package/dist/db/db.js +47 -0
  145. package/dist/db/db.js.map +1 -0
  146. package/dist/db/migrations.d.ts +15 -0
  147. package/dist/db/migrations.d.ts.map +1 -0
  148. package/dist/db/migrations.js +81 -0
  149. package/dist/db/migrations.js.map +1 -0
  150. package/dist/db/queries.d.ts +440 -0
  151. package/dist/db/queries.d.ts.map +1 -0
  152. package/dist/db/queries.js +1054 -0
  153. package/dist/db/queries.js.map +1 -0
  154. package/dist/db/schema.d.ts +132 -0
  155. package/dist/db/schema.d.ts.map +1 -0
  156. package/dist/db/schema.js +2 -0
  157. package/dist/db/schema.js.map +1 -0
  158. package/dist/delta/blastRadius.d.ts +24 -0
  159. package/dist/delta/blastRadius.d.ts.map +1 -0
  160. package/dist/delta/blastRadius.js +239 -0
  161. package/dist/delta/blastRadius.js.map +1 -0
  162. package/dist/delta/diff.d.ts +16 -0
  163. package/dist/delta/diff.d.ts.map +1 -0
  164. package/dist/delta/diff.js +236 -0
  165. package/dist/delta/diff.js.map +1 -0
  166. package/dist/delta/versioning.d.ts +11 -0
  167. package/dist/delta/versioning.d.ts.map +1 -0
  168. package/dist/delta/versioning.js +68 -0
  169. package/dist/delta/versioning.js.map +1 -0
  170. package/dist/graph/buildGraph.d.ts +12 -0
  171. package/dist/graph/buildGraph.d.ts.map +1 -0
  172. package/dist/graph/buildGraph.js +81 -0
  173. package/dist/graph/buildGraph.js.map +1 -0
  174. package/dist/graph/cache.d.ts +111 -0
  175. package/dist/graph/cache.d.ts.map +1 -0
  176. package/dist/graph/cache.js +237 -0
  177. package/dist/graph/cache.js.map +1 -0
  178. package/dist/graph/metrics.d.ts +12 -0
  179. package/dist/graph/metrics.d.ts.map +1 -0
  180. package/dist/graph/metrics.js +253 -0
  181. package/dist/graph/metrics.js.map +1 -0
  182. package/dist/graph/minHeap.d.ts +91 -0
  183. package/dist/graph/minHeap.d.ts.map +1 -0
  184. package/dist/graph/minHeap.js +159 -0
  185. package/dist/graph/minHeap.js.map +1 -0
  186. package/dist/graph/overview.d.ts +22 -0
  187. package/dist/graph/overview.d.ts.map +1 -0
  188. package/dist/graph/overview.js +379 -0
  189. package/dist/graph/overview.js.map +1 -0
  190. package/dist/graph/score.d.ts +27 -0
  191. package/dist/graph/score.d.ts.map +1 -0
  192. package/dist/graph/score.js +214 -0
  193. package/dist/graph/score.js.map +1 -0
  194. package/dist/graph/slice.d.ts +51 -0
  195. package/dist/graph/slice.d.ts.map +1 -0
  196. package/dist/graph/slice.js +1047 -0
  197. package/dist/graph/slice.js.map +1 -0
  198. package/dist/graph/sliceCache.d.ts +33 -0
  199. package/dist/graph/sliceCache.d.ts.map +1 -0
  200. package/dist/graph/sliceCache.js +140 -0
  201. package/dist/graph/sliceCache.js.map +1 -0
  202. package/dist/indexer/adapter/BaseAdapter.d.ts +29 -0
  203. package/dist/indexer/adapter/BaseAdapter.d.ts.map +1 -0
  204. package/dist/indexer/adapter/BaseAdapter.js +97 -0
  205. package/dist/indexer/adapter/BaseAdapter.js.map +1 -0
  206. package/dist/indexer/adapter/LanguageAdapter.d.ts +20 -0
  207. package/dist/indexer/adapter/LanguageAdapter.d.ts.map +1 -0
  208. package/dist/indexer/adapter/LanguageAdapter.js +2 -0
  209. package/dist/indexer/adapter/LanguageAdapter.js.map +1 -0
  210. package/dist/indexer/adapter/adapters.d.ts +57 -0
  211. package/dist/indexer/adapter/adapters.d.ts.map +1 -0
  212. package/dist/indexer/adapter/adapters.js +129 -0
  213. package/dist/indexer/adapter/adapters.js.map +1 -0
  214. package/dist/indexer/adapter/c.d.ts +18 -0
  215. package/dist/indexer/adapter/c.d.ts.map +1 -0
  216. package/dist/indexer/adapter/c.js +443 -0
  217. package/dist/indexer/adapter/c.js.map +1 -0
  218. package/dist/indexer/adapter/cpp.d.ts +18 -0
  219. package/dist/indexer/adapter/cpp.d.ts.map +1 -0
  220. package/dist/indexer/adapter/cpp.js +493 -0
  221. package/dist/indexer/adapter/cpp.js.map +1 -0
  222. package/dist/indexer/adapter/csharp.d.ts +48 -0
  223. package/dist/indexer/adapter/csharp.d.ts.map +1 -0
  224. package/dist/indexer/adapter/csharp.js +638 -0
  225. package/dist/indexer/adapter/csharp.js.map +1 -0
  226. package/dist/indexer/adapter/go.d.ts +14 -0
  227. package/dist/indexer/adapter/go.d.ts.map +1 -0
  228. package/dist/indexer/adapter/go.js +400 -0
  229. package/dist/indexer/adapter/go.js.map +1 -0
  230. package/dist/indexer/adapter/index.d.ts +14 -0
  231. package/dist/indexer/adapter/index.d.ts.map +1 -0
  232. package/dist/indexer/adapter/index.js +13 -0
  233. package/dist/indexer/adapter/index.js.map +1 -0
  234. package/dist/indexer/adapter/java.d.ts +14 -0
  235. package/dist/indexer/adapter/java.d.ts.map +1 -0
  236. package/dist/indexer/adapter/java.js +391 -0
  237. package/dist/indexer/adapter/java.js.map +1 -0
  238. package/dist/indexer/adapter/kotlin.d.ts +18 -0
  239. package/dist/indexer/adapter/kotlin.d.ts.map +1 -0
  240. package/dist/indexer/adapter/kotlin.js +599 -0
  241. package/dist/indexer/adapter/kotlin.js.map +1 -0
  242. package/dist/indexer/adapter/php.d.ts +18 -0
  243. package/dist/indexer/adapter/php.d.ts.map +1 -0
  244. package/dist/indexer/adapter/php.js +574 -0
  245. package/dist/indexer/adapter/php.js.map +1 -0
  246. package/dist/indexer/adapter/plugin/index.d.ts +3 -0
  247. package/dist/indexer/adapter/plugin/index.d.ts.map +1 -0
  248. package/dist/indexer/adapter/plugin/index.js +3 -0
  249. package/dist/indexer/adapter/plugin/index.js.map +1 -0
  250. package/dist/indexer/adapter/plugin/loader.d.ts +13 -0
  251. package/dist/indexer/adapter/plugin/loader.d.ts.map +1 -0
  252. package/dist/indexer/adapter/plugin/loader.js +154 -0
  253. package/dist/indexer/adapter/plugin/loader.js.map +1 -0
  254. package/dist/indexer/adapter/plugin/types.d.ts +76 -0
  255. package/dist/indexer/adapter/plugin/types.d.ts.map +1 -0
  256. package/dist/indexer/adapter/plugin/types.js +47 -0
  257. package/dist/indexer/adapter/plugin/types.js.map +1 -0
  258. package/dist/indexer/adapter/python.d.ts +14 -0
  259. package/dist/indexer/adapter/python.d.ts.map +1 -0
  260. package/dist/indexer/adapter/python.js +511 -0
  261. package/dist/indexer/adapter/python.js.map +1 -0
  262. package/dist/indexer/adapter/registry.d.ts +17 -0
  263. package/dist/indexer/adapter/registry.d.ts.map +1 -0
  264. package/dist/indexer/adapter/registry.js +134 -0
  265. package/dist/indexer/adapter/registry.js.map +1 -0
  266. package/dist/indexer/adapter/rust.d.ts +18 -0
  267. package/dist/indexer/adapter/rust.d.ts.map +1 -0
  268. package/dist/indexer/adapter/rust.js +709 -0
  269. package/dist/indexer/adapter/rust.js.map +1 -0
  270. package/dist/indexer/adapter/shell.d.ts +18 -0
  271. package/dist/indexer/adapter/shell.d.ts.map +1 -0
  272. package/dist/indexer/adapter/shell.js +345 -0
  273. package/dist/indexer/adapter/shell.js.map +1 -0
  274. package/dist/indexer/adapter/typescript.d.ts +14 -0
  275. package/dist/indexer/adapter/typescript.d.ts.map +1 -0
  276. package/dist/indexer/adapter/typescript.js +31 -0
  277. package/dist/indexer/adapter/typescript.js.map +1 -0
  278. package/dist/indexer/configEdges.d.ts +30 -0
  279. package/dist/indexer/configEdges.d.ts.map +1 -0
  280. package/dist/indexer/configEdges.js +260 -0
  281. package/dist/indexer/configEdges.js.map +1 -0
  282. package/dist/indexer/fileScanner.d.ts +16 -0
  283. package/dist/indexer/fileScanner.d.ts.map +1 -0
  284. package/dist/indexer/fileScanner.js +90 -0
  285. package/dist/indexer/fileScanner.js.map +1 -0
  286. package/dist/indexer/fingerprints.d.ts +23 -0
  287. package/dist/indexer/fingerprints.d.ts.map +1 -0
  288. package/dist/indexer/fingerprints.js +97 -0
  289. package/dist/indexer/fingerprints.js.map +1 -0
  290. package/dist/indexer/indexer.d.ts +58 -0
  291. package/dist/indexer/indexer.d.ts.map +1 -0
  292. package/dist/indexer/indexer.js +1229 -0
  293. package/dist/indexer/indexer.js.map +1 -0
  294. package/dist/indexer/summaries.d.ts +5 -0
  295. package/dist/indexer/summaries.d.ts.map +1 -0
  296. package/dist/indexer/summaries.js +331 -0
  297. package/dist/indexer/summaries.js.map +1 -0
  298. package/dist/indexer/treesitter/extractCalls.d.ts +40 -0
  299. package/dist/indexer/treesitter/extractCalls.d.ts.map +1 -0
  300. package/dist/indexer/treesitter/extractCalls.js +561 -0
  301. package/dist/indexer/treesitter/extractCalls.js.map +1 -0
  302. package/dist/indexer/treesitter/extractImports.d.ts +12 -0
  303. package/dist/indexer/treesitter/extractImports.d.ts.map +1 -0
  304. package/dist/indexer/treesitter/extractImports.js +184 -0
  305. package/dist/indexer/treesitter/extractImports.js.map +1 -0
  306. package/dist/indexer/treesitter/extractSymbols.d.ts +24 -0
  307. package/dist/indexer/treesitter/extractSymbols.d.ts.map +1 -0
  308. package/dist/indexer/treesitter/extractSymbols.js +389 -0
  309. package/dist/indexer/treesitter/extractSymbols.js.map +1 -0
  310. package/dist/indexer/treesitter/grammarLoader.d.ts +6 -0
  311. package/dist/indexer/treesitter/grammarLoader.d.ts.map +1 -0
  312. package/dist/indexer/treesitter/grammarLoader.js +125 -0
  313. package/dist/indexer/treesitter/grammarLoader.js.map +1 -0
  314. package/dist/indexer/treesitter/symbolUtils.d.ts +4 -0
  315. package/dist/indexer/treesitter/symbolUtils.d.ts.map +1 -0
  316. package/dist/indexer/treesitter/symbolUtils.js +26 -0
  317. package/dist/indexer/treesitter/symbolUtils.js.map +1 -0
  318. package/dist/indexer/treesitter/tsTreesitter.d.ts +9 -0
  319. package/dist/indexer/treesitter/tsTreesitter.d.ts.map +1 -0
  320. package/dist/indexer/treesitter/tsTreesitter.js +54 -0
  321. package/dist/indexer/treesitter/tsTreesitter.js.map +1 -0
  322. package/dist/indexer/treesitter/types.d.ts +19 -0
  323. package/dist/indexer/treesitter/types.d.ts.map +1 -0
  324. package/dist/indexer/treesitter/types.js +7 -0
  325. package/dist/indexer/treesitter/types.js.map +1 -0
  326. package/dist/indexer/ts/tsParser.d.ts +20 -0
  327. package/dist/indexer/ts/tsParser.d.ts.map +1 -0
  328. package/dist/indexer/ts/tsParser.js +114 -0
  329. package/dist/indexer/ts/tsParser.js.map +1 -0
  330. package/dist/indexer/worker.d.ts +2 -0
  331. package/dist/indexer/worker.d.ts.map +1 -0
  332. package/dist/indexer/worker.js +59 -0
  333. package/dist/indexer/worker.js.map +1 -0
  334. package/dist/indexer/workerPool.d.ts +20 -0
  335. package/dist/indexer/workerPool.d.ts.map +1 -0
  336. package/dist/indexer/workerPool.js +93 -0
  337. package/dist/indexer/workerPool.js.map +1 -0
  338. package/dist/main.d.ts +2 -0
  339. package/dist/main.d.ts.map +1 -0
  340. package/dist/main.js +111 -0
  341. package/dist/main.js.map +1 -0
  342. package/dist/mcp/errors.d.ts +40 -0
  343. package/dist/mcp/errors.d.ts.map +1 -0
  344. package/dist/mcp/errors.js +66 -0
  345. package/dist/mcp/errors.js.map +1 -0
  346. package/dist/mcp/resources.d.ts +24 -0
  347. package/dist/mcp/resources.d.ts.map +1 -0
  348. package/dist/mcp/resources.js +140 -0
  349. package/dist/mcp/resources.js.map +1 -0
  350. package/dist/mcp/telemetry.d.ts +67 -0
  351. package/dist/mcp/telemetry.d.ts.map +1 -0
  352. package/dist/mcp/telemetry.js +128 -0
  353. package/dist/mcp/telemetry.js.map +1 -0
  354. package/dist/mcp/tools/agent.d.ts +241 -0
  355. package/dist/mcp/tools/agent.d.ts.map +1 -0
  356. package/dist/mcp/tools/agent.js +113 -0
  357. package/dist/mcp/tools/agent.js.map +1 -0
  358. package/dist/mcp/tools/code.d.ts +32 -0
  359. package/dist/mcp/tools/code.d.ts.map +1 -0
  360. package/dist/mcp/tools/code.js +388 -0
  361. package/dist/mcp/tools/code.js.map +1 -0
  362. package/dist/mcp/tools/delta.d.ts +12 -0
  363. package/dist/mcp/tools/delta.d.ts.map +1 -0
  364. package/dist/mcp/tools/delta.js +82 -0
  365. package/dist/mcp/tools/delta.js.map +1 -0
  366. package/dist/mcp/tools/index.d.ts +3 -0
  367. package/dist/mcp/tools/index.d.ts.map +1 -0
  368. package/dist/mcp/tools/index.js +35 -0
  369. package/dist/mcp/tools/index.js.map +1 -0
  370. package/dist/mcp/tools/policy.d.ts +20 -0
  371. package/dist/mcp/tools/policy.d.ts.map +1 -0
  372. package/dist/mcp/tools/policy.js +67 -0
  373. package/dist/mcp/tools/policy.js.map +1 -0
  374. package/dist/mcp/tools/prRisk.d.ts +34 -0
  375. package/dist/mcp/tools/prRisk.d.ts.map +1 -0
  376. package/dist/mcp/tools/prRisk.js +304 -0
  377. package/dist/mcp/tools/prRisk.js.map +1 -0
  378. package/dist/mcp/tools/repo.d.ts +46 -0
  379. package/dist/mcp/tools/repo.d.ts.map +1 -0
  380. package/dist/mcp/tools/repo.js +224 -0
  381. package/dist/mcp/tools/repo.js.map +1 -0
  382. package/dist/mcp/tools/slice.d.ts +44 -0
  383. package/dist/mcp/tools/slice.d.ts.map +1 -0
  384. package/dist/mcp/tools/slice.js +688 -0
  385. package/dist/mcp/tools/slice.js.map +1 -0
  386. package/dist/mcp/tools/symbol.d.ts +21 -0
  387. package/dist/mcp/tools/symbol.d.ts.map +1 -0
  388. package/dist/mcp/tools/symbol.js +416 -0
  389. package/dist/mcp/tools/symbol.js.map +1 -0
  390. package/dist/mcp/tools.d.ts +6003 -0
  391. package/dist/mcp/tools.d.ts.map +1 -0
  392. package/dist/mcp/tools.js +932 -0
  393. package/dist/mcp/tools.js.map +1 -0
  394. package/dist/mcp/types.d.ts +500 -0
  395. package/dist/mcp/types.d.ts.map +1 -0
  396. package/dist/mcp/types.js +2 -0
  397. package/dist/mcp/types.js.map +1 -0
  398. package/dist/policy/engine.d.ts +21 -0
  399. package/dist/policy/engine.d.ts.map +1 -0
  400. package/dist/policy/engine.js +477 -0
  401. package/dist/policy/engine.js.map +1 -0
  402. package/dist/policy/types.d.ts +73 -0
  403. package/dist/policy/types.d.ts.map +1 -0
  404. package/dist/policy/types.js +12 -0
  405. package/dist/policy/types.js.map +1 -0
  406. package/dist/server.d.ts +17 -0
  407. package/dist/server.d.ts.map +1 -0
  408. package/dist/server.js +136 -0
  409. package/dist/server.js.map +1 -0
  410. package/dist/sync/pull.d.ts +4 -0
  411. package/dist/sync/pull.d.ts.map +1 -0
  412. package/dist/sync/pull.js +113 -0
  413. package/dist/sync/pull.js.map +1 -0
  414. package/dist/sync/sync.d.ts +6 -0
  415. package/dist/sync/sync.d.ts.map +1 -0
  416. package/dist/sync/sync.js +244 -0
  417. package/dist/sync/sync.js.map +1 -0
  418. package/dist/sync/types.d.ts +136 -0
  419. package/dist/sync/types.d.ts.map +1 -0
  420. package/dist/sync/types.js +2 -0
  421. package/dist/sync/types.js.map +1 -0
  422. package/dist/ts/diagnostics.d.ts +61 -0
  423. package/dist/ts/diagnostics.d.ts.map +1 -0
  424. package/dist/ts/diagnostics.js +259 -0
  425. package/dist/ts/diagnostics.js.map +1 -0
  426. package/dist/ts/mapping.d.ts +27 -0
  427. package/dist/ts/mapping.d.ts.map +1 -0
  428. package/dist/ts/mapping.js +68 -0
  429. package/dist/ts/mapping.js.map +1 -0
  430. package/dist/util/asyncFs.d.ts +103 -0
  431. package/dist/util/asyncFs.d.ts.map +1 -0
  432. package/dist/util/asyncFs.js +133 -0
  433. package/dist/util/asyncFs.js.map +1 -0
  434. package/dist/util/concurrency.d.ts +77 -0
  435. package/dist/util/concurrency.d.ts.map +1 -0
  436. package/dist/util/concurrency.js +146 -0
  437. package/dist/util/concurrency.js.map +1 -0
  438. package/dist/util/depLabels.d.ts +3 -0
  439. package/dist/util/depLabels.d.ts.map +1 -0
  440. package/dist/util/depLabels.js +19 -0
  441. package/dist/util/depLabels.js.map +1 -0
  442. package/dist/util/findPackageRoot.d.ts +7 -0
  443. package/dist/util/findPackageRoot.d.ts.map +1 -0
  444. package/dist/util/findPackageRoot.js +21 -0
  445. package/dist/util/findPackageRoot.js.map +1 -0
  446. package/dist/util/hashing.d.ts +9 -0
  447. package/dist/util/hashing.d.ts.map +1 -0
  448. package/dist/util/hashing.js +37 -0
  449. package/dist/util/hashing.js.map +1 -0
  450. package/dist/util/logger.d.ts +14 -0
  451. package/dist/util/logger.d.ts.map +1 -0
  452. package/dist/util/logger.js +51 -0
  453. package/dist/util/logger.js.map +1 -0
  454. package/dist/util/paths.d.ts +6 -0
  455. package/dist/util/paths.d.ts.map +1 -0
  456. package/dist/util/paths.js +79 -0
  457. package/dist/util/paths.js.map +1 -0
  458. package/dist/util/time.d.ts +4 -0
  459. package/dist/util/time.d.ts.map +1 -0
  460. package/dist/util/time.js +20 -0
  461. package/dist/util/time.js.map +1 -0
  462. package/dist/util/tokenize.d.ts +5 -0
  463. package/dist/util/tokenize.d.ts.map +1 -0
  464. package/dist/util/tokenize.js +30 -0
  465. package/dist/util/tokenize.js.map +1 -0
  466. package/dist/util/truncation.d.ts +38 -0
  467. package/dist/util/truncation.d.ts.map +1 -0
  468. package/dist/util/truncation.js +259 -0
  469. package/dist/util/truncation.js.map +1 -0
  470. package/migrations/.gitkeep +1 -0
  471. package/migrations/0001_init.sql +61 -0
  472. package/migrations/0002_edges_indexes.sql +2 -0
  473. package/migrations/0003_versions.sql +22 -0
  474. package/migrations/0004_metrics_audit.sql +23 -0
  475. package/migrations/0005_slice_handles.sql +15 -0
  476. package/migrations/0006_content_addressed.sql +29 -0
  477. package/migrations/0007_add_language_to_symbols.sql +28 -0
  478. package/migrations/0008_performance_indexes.sql +21 -0
  479. package/migrations/0009_fix_edge_fks.sql +37 -0
  480. package/migrations/0010_standardize_fks.sql +35 -0
  481. package/migrations/0011_add_directory_column.sql +20 -0
  482. package/migrations/0012_symbol_references.sql +16 -0
  483. package/migrations/0013_sync_artifacts.sql +17 -0
  484. package/package.json +107 -0
  485. package/templates/CLAUDE.md.template +179 -0
  486. package/templates/README.md +228 -0
  487. package/templates/claude-code.json +54 -0
  488. package/templates/codex.json +55 -0
  489. package/templates/gemini.json +66 -0
  490. package/templates/opencode.json +90 -0
  491. package/templates/plugin-template/LICENSE +21 -0
  492. package/templates/plugin-template/README.md +309 -0
  493. package/templates/plugin-template/index.ts +160 -0
  494. package/templates/plugin-template/package.json +31 -0
  495. package/templates/plugin-template/test/plugin.test.ts +186 -0
  496. package/templates/plugin-template/tsconfig.json +21 -0
@@ -0,0 +1,1047 @@
1
+ import { loadGraphForRepo } from "./buildGraph.js";
2
+ import { scoreSymbolWithMetrics } from "./score.js";
3
+ import { loadConfig } from "../config/loadConfig.js";
4
+ import { tokenize, estimateTokens as estimateTextTokens, } from "../util/tokenize.js";
5
+ import { hashCard } from "../util/hashing.js";
6
+ import { pickDepLabel } from "../util/depLabels.js";
7
+ import * as db from "../db/queries.js";
8
+ import { DEFAULT_MAX_CARDS, DEFAULT_MAX_TOKENS_SLICE, SLICE_SCORE_THRESHOLD, MAX_FRONTIER, TASK_TEXT_START_NODE_MAX, TASK_TEXT_TOKEN_MAX, TASK_TEXT_TOKEN_QUERY_LIMIT, TASK_TEXT_MIN_TOKEN_LENGTH, ENTRY_FIRST_HOP_MAX_PER_SYMBOL, ENTRY_SIBLING_MAX_PER_SYMBOL, ENTRY_SIBLING_MIN_SHARED_PREFIX, SYMBOL_TOKEN_BASE, SYMBOL_TOKEN_ADDITIONAL_MAX, SYMBOL_TOKEN_MAX, SYMBOL_CARD_MAX_DEPS_PER_KIND, SYMBOL_CARD_MAX_DEPS_PER_KIND_LIGHT, SYMBOL_CARD_MAX_INVARIANTS, SYMBOL_CARD_MAX_INVARIANTS_LIGHT, SYMBOL_CARD_MAX_SIDE_EFFECTS, SYMBOL_CARD_MAX_SIDE_EFFECTS_LIGHT, AST_FINGERPRINT_WIRE_LENGTH, SYMBOL_CARD_MAX_TEST_REFS, SYMBOL_CARD_SUMMARY_MAX_CHARS, SYMBOL_CARD_SUMMARY_MAX_CHARS_LIGHT, TOKENS_PER_CHAR_ESTIMATE, DB_QUERY_LIMIT_DEFAULT, } from "../config/constants.js";
9
+ import { MinHeap } from "./minHeap.js";
10
+ import { symbolCardCache } from "./cache.js";
11
+ import { getSliceCacheKey, getCachedSlice, setCachedSlice, } from "./sliceCache.js";
12
+ const START_NODE_SOURCE_PRIORITY = {
13
+ entrySymbol: 0,
14
+ entrySibling: 1,
15
+ entryFirstHop: 2,
16
+ stackTrace: 3,
17
+ failingTestPath: 4,
18
+ editedFile: 5,
19
+ taskText: 6,
20
+ };
21
+ const START_NODE_SOURCE_SCORE = {
22
+ entrySymbol: -1.4,
23
+ entrySibling: -1.22,
24
+ entryFirstHop: -1.18,
25
+ stackTrace: -1.2,
26
+ failingTestPath: -1.1,
27
+ editedFile: -1.0,
28
+ taskText: -0.6,
29
+ };
30
+ const TASK_TEXT_STOP_WORDS = new Set([
31
+ "a",
32
+ "an",
33
+ "and",
34
+ "are",
35
+ "as",
36
+ "at",
37
+ "be",
38
+ "by",
39
+ "do",
40
+ "does",
41
+ "for",
42
+ "from",
43
+ "id",
44
+ "in",
45
+ "is",
46
+ "it",
47
+ "of",
48
+ "on",
49
+ "or",
50
+ "please",
51
+ "task",
52
+ "that",
53
+ "the",
54
+ "this",
55
+ "to",
56
+ "with",
57
+ ]);
58
+ const DYNAMIC_CAP_MIN_CARDS = 6;
59
+ const DYNAMIC_CAP_HIGH_CONFIDENCE_MARGIN = 0.2;
60
+ const DYNAMIC_CAP_RECENT_SCORE_WINDOW = 6;
61
+ const DYNAMIC_CAP_MIN_ENTRY_COVERAGE = 0.9;
62
+ const DYNAMIC_CAP_FRONTIER_SCORE_MARGIN = 0.08;
63
+ const DYNAMIC_CAP_FRONTIER_DROP_FACTOR = 0.67;
64
+ /**
65
+ * Builds a graph slice for code context delivery.
66
+ * Uses beam search to select relevant symbols based on entry points and scoring.
67
+ * Supports truncation and spillover for large slices.
68
+ *
69
+ * @param request - Slice build parameters including repoId, versionId, task context, and budget
70
+ * @returns Graph slice with cards, edges, and truncation metadata
71
+ */
72
+ export async function buildSlice(request) {
73
+ const config = loadConfig();
74
+ const cacheConfig = config.cache;
75
+ const cacheEnabled = cacheConfig?.enabled ?? true;
76
+ const cacheKey = getSliceCacheKey(request);
77
+ const cached = cacheEnabled ? getCachedSlice(cacheKey) : null;
78
+ if (cached) {
79
+ return cached;
80
+ }
81
+ const sliceConfig = config.slice;
82
+ const edgeWeights = sliceConfig?.edgeWeights ?? {
83
+ call: 1.0,
84
+ import: 0.6,
85
+ config: 0.8,
86
+ };
87
+ const graph = loadGraphForRepo(request.repoId);
88
+ const budget = {
89
+ maxCards: request.budget?.maxCards ??
90
+ sliceConfig?.defaultMaxCards ??
91
+ DEFAULT_MAX_CARDS,
92
+ maxEstimatedTokens: request.budget?.maxEstimatedTokens ??
93
+ sliceConfig?.defaultMaxTokens ??
94
+ DEFAULT_MAX_TOKENS_SLICE,
95
+ };
96
+ const startNodes = resolveStartNodes(graph, request);
97
+ const startSymbols = startNodes.map((node) => node.symbolId);
98
+ const { sliceCards, frontier, wasTruncated, droppedCandidates } = beamSearch(graph, startNodes, budget, request, edgeWeights);
99
+ const detailedSymbolIds = resolveDetailedSymbolIds(Array.from(sliceCards), request);
100
+ const cards = await loadSymbolCards(Array.from(sliceCards), request.versionId, request.repoId, detailedSymbolIds);
101
+ const { cardsForPayload, cardRefs, } = buildPayloadCardsAndRefs(cards, request.knownCardEtags);
102
+ const { symbolIndex, edges } = loadEdgesBetweenSymbols(Array.from(sliceCards), request.repoId);
103
+ const estimatedTokens = estimateTokens(cardsForPayload);
104
+ const slice = {
105
+ repoId: request.repoId,
106
+ versionId: request.versionId,
107
+ budget,
108
+ startSymbols,
109
+ symbolIndex,
110
+ cards: cardsForPayload,
111
+ cardRefs,
112
+ edges,
113
+ };
114
+ if (wasTruncated || cards.length >= budget.maxCards) {
115
+ slice.frontier = frontier.slice(0, 10).map((item) => ({
116
+ symbolId: item.symbolId,
117
+ score: item.score,
118
+ why: item.why,
119
+ }));
120
+ const totalEdges = edges.length;
121
+ const maxEdges = Math.max(0, totalEdges);
122
+ slice.truncation = {
123
+ truncated: true,
124
+ droppedCards: droppedCandidates,
125
+ droppedEdges: maxEdges,
126
+ howToResume: {
127
+ type: "token",
128
+ value: estimatedTokens,
129
+ },
130
+ };
131
+ }
132
+ if (cacheEnabled) {
133
+ setCachedSlice(cacheKey, slice);
134
+ }
135
+ return slice;
136
+ }
137
+ function resolveStartNodes(graph, request) {
138
+ const startNodes = new Map();
139
+ const explicitEntrySymbols = [];
140
+ const addStartNode = (symbolId, source) => {
141
+ if (!graph.symbols.has(symbolId))
142
+ return;
143
+ const existingSource = startNodes.get(symbolId);
144
+ if (existingSource &&
145
+ START_NODE_SOURCE_PRIORITY[existingSource] <=
146
+ START_NODE_SOURCE_PRIORITY[source]) {
147
+ return;
148
+ }
149
+ startNodes.set(symbolId, source);
150
+ };
151
+ if (request.entrySymbols) {
152
+ for (const symbolId of request.entrySymbols) {
153
+ if (!graph.symbols.has(symbolId))
154
+ continue;
155
+ explicitEntrySymbols.push(symbolId);
156
+ addStartNode(symbolId, "entrySymbol");
157
+ }
158
+ }
159
+ const limits = computeStartNodeLimits(request, explicitEntrySymbols.length);
160
+ for (const symbolId of explicitEntrySymbols) {
161
+ if (startNodes.size >= limits.maxTotalStartNodes)
162
+ break;
163
+ const firstHopSymbols = collectEntryFirstHopSymbols(graph, symbolId, limits.maxFirstHopPerEntry);
164
+ for (const firstHopSymbolId of firstHopSymbols) {
165
+ if (startNodes.size >= limits.maxTotalStartNodes)
166
+ break;
167
+ addStartNode(firstHopSymbolId, "entryFirstHop");
168
+ }
169
+ }
170
+ if (explicitEntrySymbols.length > 0) {
171
+ const symbolsByFile = buildSymbolsByFile(graph);
172
+ for (const symbolId of explicitEntrySymbols) {
173
+ if (startNodes.size >= limits.maxTotalStartNodes)
174
+ break;
175
+ const siblingSymbols = collectEntrySiblingSymbols(graph, symbolId, symbolsByFile, limits.maxSiblingPerEntry);
176
+ for (const siblingSymbolId of siblingSymbols) {
177
+ if (startNodes.size >= limits.maxTotalStartNodes)
178
+ break;
179
+ addStartNode(siblingSymbolId, "entrySibling");
180
+ }
181
+ }
182
+ }
183
+ if (request.stackTrace) {
184
+ const stackSymbols = extractSymbolsFromStackTrace(request.stackTrace, request.repoId);
185
+ for (const symbolId of stackSymbols) {
186
+ if (startNodes.size >= limits.maxTotalStartNodes)
187
+ break;
188
+ addStartNode(symbolId, "stackTrace");
189
+ }
190
+ }
191
+ if (request.failingTestPath) {
192
+ const fileSymbols = getSymbolsByPath(request.repoId, request.failingTestPath);
193
+ for (const symbolId of fileSymbols) {
194
+ if (startNodes.size >= limits.maxTotalStartNodes)
195
+ break;
196
+ addStartNode(symbolId, "failingTestPath");
197
+ }
198
+ }
199
+ if (request.editedFiles) {
200
+ for (const filePath of request.editedFiles) {
201
+ if (startNodes.size >= limits.maxTotalStartNodes)
202
+ break;
203
+ const fileSymbols = getSymbolsByPath(request.repoId, filePath);
204
+ for (const symbolId of fileSymbols) {
205
+ if (startNodes.size >= limits.maxTotalStartNodes)
206
+ break;
207
+ addStartNode(symbolId, "editedFile");
208
+ }
209
+ }
210
+ }
211
+ if (request.taskText) {
212
+ const taskTokens = collectTaskTextSeedTokens(request.taskText);
213
+ let taskTextSeedCount = 0;
214
+ for (const token of taskTokens) {
215
+ if (taskTextSeedCount >= limits.maxTaskTextStartNodes ||
216
+ startNodes.size >= limits.maxTotalStartNodes) {
217
+ break;
218
+ }
219
+ const remaining = limits.maxTaskTextStartNodes - taskTextSeedCount;
220
+ const perTokenLimit = Math.max(1, Math.min(DB_QUERY_LIMIT_DEFAULT, TASK_TEXT_TOKEN_QUERY_LIMIT, remaining));
221
+ const results = db.searchSymbolsLite(request.repoId, token, perTokenLimit);
222
+ for (const result of results) {
223
+ if (taskTextSeedCount >= limits.maxTaskTextStartNodes ||
224
+ startNodes.size >= limits.maxTotalStartNodes) {
225
+ break;
226
+ }
227
+ const symbolId = result.symbol_id;
228
+ if (startNodes.has(symbolId))
229
+ continue;
230
+ addStartNode(symbolId, "taskText");
231
+ if (startNodes.has(symbolId)) {
232
+ taskTextSeedCount++;
233
+ }
234
+ }
235
+ }
236
+ }
237
+ return Array.from(startNodes.entries())
238
+ .sort(([, sourceA], [, sourceB]) => START_NODE_SOURCE_PRIORITY[sourceA] -
239
+ START_NODE_SOURCE_PRIORITY[sourceB])
240
+ .map(([symbolId, source]) => ({ symbolId, source }));
241
+ }
242
+ function collectTaskTextSeedTokens(taskText) {
243
+ const seen = new Set();
244
+ const filtered = [];
245
+ for (const token of tokenize(taskText)) {
246
+ if (token.length < TASK_TEXT_MIN_TOKEN_LENGTH)
247
+ continue;
248
+ if (TASK_TEXT_STOP_WORDS.has(token))
249
+ continue;
250
+ if (/^\d+$/.test(token))
251
+ continue;
252
+ if (!/[a-z]/.test(token))
253
+ continue;
254
+ if (seen.has(token))
255
+ continue;
256
+ seen.add(token);
257
+ filtered.push(token);
258
+ }
259
+ filtered.sort((a, b) => {
260
+ const rankDiff = getTaskTextTokenRank(b) - getTaskTextTokenRank(a);
261
+ if (rankDiff !== 0)
262
+ return rankDiff;
263
+ return b.length - a.length;
264
+ });
265
+ return filtered.slice(0, TASK_TEXT_TOKEN_MAX);
266
+ }
267
+ function resolveDetailedSymbolIds(symbolIds, request) {
268
+ if (request.cardDetail === "full") {
269
+ return new Set(symbolIds);
270
+ }
271
+ return new Set(request.entrySymbols ?? []);
272
+ }
273
+ export function buildPayloadCardsAndRefs(cards, knownCardEtags) {
274
+ const hasKnownCardEtags = Boolean(knownCardEtags && Object.keys(knownCardEtags).length > 0);
275
+ if (!hasKnownCardEtags) {
276
+ return {
277
+ cardsForPayload: cards.map((card) => {
278
+ const detailLevel = card.detailLevel ?? "compact";
279
+ const normalized = {
280
+ ...card,
281
+ detailLevel,
282
+ };
283
+ delete normalized.etag;
284
+ return toSliceSymbolCard(normalized);
285
+ }),
286
+ };
287
+ }
288
+ const cardsForPayload = [];
289
+ const cardRefs = [];
290
+ const knownEtags = knownCardEtags ?? {};
291
+ for (const card of cards) {
292
+ const detailLevel = card.detailLevel ?? "compact";
293
+ const cardWithoutEtag = { ...card };
294
+ cardWithoutEtag.detailLevel = detailLevel;
295
+ delete cardWithoutEtag.etag;
296
+ const etag = hashCard(cardWithoutEtag);
297
+ if (knownEtags[card.symbolId] === etag) {
298
+ continue;
299
+ }
300
+ cardRefs.push({
301
+ symbolId: card.symbolId,
302
+ etag,
303
+ detailLevel,
304
+ });
305
+ cardsForPayload.push(toSliceSymbolCard(cardWithoutEtag));
306
+ }
307
+ return {
308
+ cardsForPayload,
309
+ cardRefs,
310
+ };
311
+ }
312
+ function getTaskTextTokenRank(token) {
313
+ let rank = 0;
314
+ if (token.includes("/") || token.includes("\\"))
315
+ rank += 4;
316
+ if (token.includes(".") || token.includes("_") || token.includes("-"))
317
+ rank += 3;
318
+ if (/[0-9]/.test(token))
319
+ rank += 2;
320
+ if (token.length >= 8)
321
+ rank += 1;
322
+ return rank;
323
+ }
324
+ function buildSymbolsByFile(graph) {
325
+ const symbolsByFile = new Map();
326
+ for (const [symbolId, symbol] of graph.symbols) {
327
+ const current = symbolsByFile.get(symbol.file_id);
328
+ if (current) {
329
+ current.push(symbolId);
330
+ continue;
331
+ }
332
+ symbolsByFile.set(symbol.file_id, [symbolId]);
333
+ }
334
+ return symbolsByFile;
335
+ }
336
+ function collectEntryFirstHopSymbols(graph, entrySymbolId, maxPerSymbol) {
337
+ const outgoing = graph.adjacencyOut.get(entrySymbolId) ?? [];
338
+ if (outgoing.length === 0)
339
+ return [];
340
+ const ranked = new Map();
341
+ for (const edge of outgoing) {
342
+ if (edge.type !== "call" && edge.type !== "import")
343
+ continue;
344
+ const target = graph.symbols.get(edge.to_symbol_id);
345
+ if (!target)
346
+ continue;
347
+ let rank = edge.type === "call" ? 4 : 2;
348
+ if (target.exported === 1)
349
+ rank += 1;
350
+ if (target.kind === "function" || target.kind === "method")
351
+ rank += 1;
352
+ const previous = ranked.get(edge.to_symbol_id);
353
+ if (previous === undefined || rank > previous) {
354
+ ranked.set(edge.to_symbol_id, rank);
355
+ }
356
+ }
357
+ return Array.from(ranked.entries())
358
+ .sort((a, b) => {
359
+ if (b[1] !== a[1])
360
+ return b[1] - a[1];
361
+ const nameA = graph.symbols.get(a[0])?.name ?? "";
362
+ const nameB = graph.symbols.get(b[0])?.name ?? "";
363
+ return nameA.localeCompare(nameB);
364
+ })
365
+ .slice(0, maxPerSymbol)
366
+ .map(([symbolId]) => symbolId);
367
+ }
368
+ function collectEntrySiblingSymbols(graph, entrySymbolId, symbolsByFile, maxPerSymbol) {
369
+ const entrySymbol = graph.symbols.get(entrySymbolId);
370
+ if (!entrySymbol)
371
+ return [];
372
+ const symbolIdsInFile = symbolsByFile.get(entrySymbol.file_id) ?? [];
373
+ if (symbolIdsInFile.length <= 1)
374
+ return [];
375
+ const entryName = entrySymbol.name.toLowerCase();
376
+ const ranked = [];
377
+ for (const candidateId of symbolIdsInFile) {
378
+ if (candidateId === entrySymbolId)
379
+ continue;
380
+ const candidate = graph.symbols.get(candidateId);
381
+ if (!candidate)
382
+ continue;
383
+ if (candidate.kind !== entrySymbol.kind)
384
+ continue;
385
+ const sharedPrefix = commonPrefixLength(entryName, candidate.name.toLowerCase());
386
+ if (sharedPrefix < ENTRY_SIBLING_MIN_SHARED_PREFIX)
387
+ continue;
388
+ let rank = sharedPrefix;
389
+ if (candidate.exported === 1)
390
+ rank += 2;
391
+ ranked.push({ symbolId: candidateId, rank, name: candidate.name });
392
+ }
393
+ return ranked
394
+ .sort((a, b) => {
395
+ if (b.rank !== a.rank)
396
+ return b.rank - a.rank;
397
+ return a.name.localeCompare(b.name);
398
+ })
399
+ .slice(0, maxPerSymbol)
400
+ .map((item) => item.symbolId);
401
+ }
402
+ function computeStartNodeLimits(request, explicitEntryCount) {
403
+ const budgetMaxCards = Math.max(1, request.budget?.maxCards ?? DEFAULT_MAX_CARDS);
404
+ const maxTotalStartNodes = Math.max(12, Math.min(96, budgetMaxCards * 2));
405
+ if (explicitEntryCount === 0) {
406
+ return {
407
+ maxTotalStartNodes,
408
+ maxTaskTextStartNodes: TASK_TEXT_START_NODE_MAX,
409
+ maxFirstHopPerEntry: ENTRY_FIRST_HOP_MAX_PER_SYMBOL,
410
+ maxSiblingPerEntry: ENTRY_SIBLING_MAX_PER_SYMBOL,
411
+ };
412
+ }
413
+ const hasStrongSignals = Boolean(request.stackTrace ||
414
+ request.failingTestPath ||
415
+ (request.editedFiles && request.editedFiles.length > 0));
416
+ const adaptiveTaskBudget = Math.max(2, Math.floor(budgetMaxCards / 5));
417
+ const maxTaskTextStartNodes = hasStrongSignals
418
+ ? Math.min(TASK_TEXT_START_NODE_MAX, Math.min(4, adaptiveTaskBudget))
419
+ : Math.min(TASK_TEXT_START_NODE_MAX, Math.min(8, adaptiveTaskBudget));
420
+ return {
421
+ maxTotalStartNodes,
422
+ maxTaskTextStartNodes,
423
+ maxFirstHopPerEntry: Math.min(ENTRY_FIRST_HOP_MAX_PER_SYMBOL, 2),
424
+ maxSiblingPerEntry: Math.min(ENTRY_SIBLING_MAX_PER_SYMBOL, 1),
425
+ };
426
+ }
427
+ function commonPrefixLength(a, b) {
428
+ const max = Math.min(a.length, b.length);
429
+ let i = 0;
430
+ while (i < max && a[i] === b[i]) {
431
+ i++;
432
+ }
433
+ return i;
434
+ }
435
+ function extractSymbolsFromStackTrace(stackTrace, repoId) {
436
+ const symbols = new Set();
437
+ const lines = stackTrace.split("\n");
438
+ const filesByRepo = db.getFilesByRepoLite(repoId);
439
+ const filePaths = new Map();
440
+ for (const file of filesByRepo) {
441
+ filePaths.set(file.rel_path, file.file_id);
442
+ }
443
+ for (const [path, fileId] of filePaths.entries()) {
444
+ for (const line of lines) {
445
+ if (line.includes(path)) {
446
+ const symbolIds = db.getSymbolIdsByFile(fileId);
447
+ for (const symbolId of symbolIds) {
448
+ symbols.add(symbolId);
449
+ }
450
+ break;
451
+ }
452
+ }
453
+ }
454
+ return Array.from(symbols);
455
+ }
456
+ function getSymbolsByPath(repoId, filePath) {
457
+ const filesByRepo = db.getFilesByRepoLite(repoId);
458
+ const file = filesByRepo.find((f) => f.rel_path === filePath);
459
+ if (!file)
460
+ return [];
461
+ const symbolIds = db.getSymbolIdsByFile(file.file_id);
462
+ return symbolIds;
463
+ }
464
+ function beamSearch(graph, startNodes, budget, request, edgeWeights) {
465
+ const sliceCards = new Set();
466
+ const visited = new Set();
467
+ const frontier = new MinHeap();
468
+ let droppedCandidates = 0;
469
+ let sequence = 0;
470
+ let effectiveCardCap = budget.maxCards;
471
+ const entrySymbols = new Set(request.entrySymbols ?? []);
472
+ const requiredEntryCoverage = entrySymbols.size;
473
+ const minCardsForDynamicCap = computeMinCardsForDynamicCap(budget.maxCards, requiredEntryCoverage);
474
+ let coveredEntrySymbols = 0;
475
+ let highConfidenceCards = 0;
476
+ const recentAcceptedScores = [];
477
+ for (const { symbolId, source } of startNodes) {
478
+ if (!visited.has(symbolId) && graph.symbols.has(symbolId)) {
479
+ frontier.insert({
480
+ symbolId,
481
+ score: START_NODE_SOURCE_SCORE[source],
482
+ why: getStartNodeWhy(source),
483
+ priority: START_NODE_SOURCE_PRIORITY[source],
484
+ sequence: sequence++,
485
+ });
486
+ visited.add(symbolId);
487
+ }
488
+ }
489
+ const context = {
490
+ query: request.taskText ?? "",
491
+ queryTokens: request.taskText ? tokenize(request.taskText) : undefined,
492
+ stackTrace: request.stackTrace,
493
+ failingTestPath: request.failingTestPath,
494
+ editedFiles: request.editedFiles,
495
+ entrySymbols: request.entrySymbols,
496
+ };
497
+ let belowThresholdCount = 0;
498
+ let wasTruncated = false;
499
+ let totalTokens = 0;
500
+ while (!frontier.isEmpty() && sliceCards.size < effectiveCardCap) {
501
+ const current = frontier.extractMin();
502
+ const actualScore = -current.score;
503
+ if (sliceCards.size >= effectiveCardCap) {
504
+ wasTruncated = true;
505
+ break;
506
+ }
507
+ if (actualScore < SLICE_SCORE_THRESHOLD) {
508
+ belowThresholdCount++;
509
+ if (belowThresholdCount >= 5)
510
+ break;
511
+ continue;
512
+ }
513
+ belowThresholdCount = 0;
514
+ sliceCards.add(current.symbolId);
515
+ if (entrySymbols.has(current.symbolId)) {
516
+ coveredEntrySymbols++;
517
+ }
518
+ if (actualScore >= SLICE_SCORE_THRESHOLD + DYNAMIC_CAP_HIGH_CONFIDENCE_MARGIN) {
519
+ highConfidenceCards++;
520
+ }
521
+ recentAcceptedScores.push(actualScore);
522
+ if (recentAcceptedScores.length > DYNAMIC_CAP_RECENT_SCORE_WINDOW) {
523
+ recentAcceptedScores.shift();
524
+ }
525
+ const cardTokens = estimateCardTokens(current.symbolId, graph);
526
+ totalTokens += cardTokens;
527
+ if (totalTokens > budget.maxEstimatedTokens) {
528
+ sliceCards.delete(current.symbolId);
529
+ totalTokens -= cardTokens;
530
+ wasTruncated = true;
531
+ droppedCandidates++;
532
+ break;
533
+ }
534
+ const outgoing = graph.adjacencyOut.get(current.symbolId) ?? [];
535
+ const neighborIds = outgoing
536
+ .map((e) => e.to_symbol_id)
537
+ .filter((id) => !visited.has(id) && !sliceCards.has(id));
538
+ if (neighborIds.length === 0)
539
+ continue;
540
+ const neighborsMap = new Map();
541
+ for (const id of neighborIds) {
542
+ const symbol = graph.symbols.get(id);
543
+ if (symbol) {
544
+ neighborsMap.set(id, symbol);
545
+ }
546
+ }
547
+ if (neighborsMap.size === 0)
548
+ continue;
549
+ const metricsMap = db.getMetricsBySymbolIds([...neighborsMap.keys()]);
550
+ const fileIds = new Set([...neighborsMap.values()].map((s) => s.file_id));
551
+ const filesMap = db.getFilesByIds([...fileIds]);
552
+ for (const [neighborId, neighborSymbol] of neighborsMap) {
553
+ if (visited.has(neighborId))
554
+ continue;
555
+ visited.add(neighborId);
556
+ const edge = outgoing.find((e) => e.to_symbol_id === neighborId);
557
+ if (!edge)
558
+ continue;
559
+ const edgeWeight = edgeWeights[edge.type] ?? 0.5;
560
+ const neighborScore = -(scoreSymbolWithMetrics(neighborSymbol, context, metricsMap.get(neighborId) ?? null, filesMap.get(neighborSymbol.file_id)) * edgeWeight);
561
+ if (-neighborScore < SLICE_SCORE_THRESHOLD) {
562
+ droppedCandidates++;
563
+ continue;
564
+ }
565
+ if (frontier.size() < MAX_FRONTIER) {
566
+ frontier.insert({
567
+ symbolId: neighborId,
568
+ score: neighborScore,
569
+ why: getEdgeWhy(edge.type),
570
+ priority: 10,
571
+ sequence: sequence++,
572
+ });
573
+ }
574
+ else {
575
+ const min = frontier.peek();
576
+ const candidate = {
577
+ symbolId: neighborId,
578
+ score: neighborScore,
579
+ why: getEdgeWhy(edge.type),
580
+ priority: 10,
581
+ sequence: sequence++,
582
+ };
583
+ if (min && compareFrontierItems(min, candidate) > 0) {
584
+ frontier.extractMin();
585
+ frontier.insert(candidate);
586
+ }
587
+ else {
588
+ droppedCandidates++;
589
+ }
590
+ }
591
+ }
592
+ if (shouldTightenDynamicCardCap({
593
+ sliceSize: sliceCards.size,
594
+ minCardsForDynamicCap,
595
+ highConfidenceCards,
596
+ requiredEntryCoverage,
597
+ coveredEntrySymbols,
598
+ recentAcceptedScores,
599
+ nextFrontierScore: frontier.peek() ? -frontier.peek().score : null,
600
+ })) {
601
+ effectiveCardCap = Math.min(effectiveCardCap, sliceCards.size);
602
+ }
603
+ }
604
+ const frontierArray = frontier.toHeapArray().map((item) => ({
605
+ symbolId: item.symbolId,
606
+ score: -item.score,
607
+ why: item.why,
608
+ priority: item.priority,
609
+ sequence: item.sequence,
610
+ }));
611
+ if (sliceCards.size >= budget.maxCards || frontierArray.length > 0) {
612
+ wasTruncated = true;
613
+ droppedCandidates += frontierArray.length;
614
+ }
615
+ return {
616
+ sliceCards,
617
+ frontier: frontierArray,
618
+ wasTruncated,
619
+ droppedCandidates,
620
+ };
621
+ }
622
+ function computeMinCardsForDynamicCap(budgetMaxCards, entrySymbolCount) {
623
+ const entryFloor = entrySymbolCount > 0 ? entrySymbolCount + 2 : DYNAMIC_CAP_MIN_CARDS;
624
+ return Math.max(Math.min(budgetMaxCards, DYNAMIC_CAP_MIN_CARDS), Math.min(budgetMaxCards, entryFloor));
625
+ }
626
+ function shouldTightenDynamicCardCap(state) {
627
+ if (state.sliceSize < state.minCardsForDynamicCap)
628
+ return false;
629
+ if (state.nextFrontierScore === null)
630
+ return false;
631
+ if (state.recentAcceptedScores.length === 0)
632
+ return false;
633
+ const highConfidenceRatio = state.highConfidenceCards / Math.max(1, state.sliceSize);
634
+ if (highConfidenceRatio < 0.6)
635
+ return false;
636
+ if (state.requiredEntryCoverage > 0) {
637
+ const entryCoverageRatio = state.coveredEntrySymbols / Math.max(1, state.requiredEntryCoverage);
638
+ if (entryCoverageRatio < DYNAMIC_CAP_MIN_ENTRY_COVERAGE)
639
+ return false;
640
+ }
641
+ const recentAvg = state.recentAcceptedScores.reduce((sum, score) => sum + score, 0) /
642
+ state.recentAcceptedScores.length;
643
+ const dropThreshold = Math.max(SLICE_SCORE_THRESHOLD + DYNAMIC_CAP_FRONTIER_SCORE_MARGIN, recentAvg * DYNAMIC_CAP_FRONTIER_DROP_FACTOR);
644
+ return state.nextFrontierScore < dropThreshold;
645
+ }
646
+ function compareFrontierItems(a, b) {
647
+ if (a.score !== b.score)
648
+ return a.score - b.score;
649
+ if (a.priority !== b.priority)
650
+ return a.priority - b.priority;
651
+ return a.sequence - b.sequence;
652
+ }
653
+ function getStartNodeWhy(source) {
654
+ switch (source) {
655
+ case "entrySymbol":
656
+ return "entry symbol";
657
+ case "entrySibling":
658
+ return "entry sibling";
659
+ case "entryFirstHop":
660
+ return "entry dependency";
661
+ case "stackTrace":
662
+ return "stack trace";
663
+ case "failingTestPath":
664
+ return "failing test";
665
+ case "editedFile":
666
+ return "edited file";
667
+ case "taskText":
668
+ return "task text";
669
+ }
670
+ }
671
+ function getEdgeWhy(edgeType) {
672
+ switch (edgeType) {
673
+ case "call":
674
+ return "calls";
675
+ case "import":
676
+ return "imports";
677
+ case "config":
678
+ return "configures";
679
+ }
680
+ }
681
+ function estimateCardTokens(symbolId, graph) {
682
+ const symbol = graph.symbols.get(symbolId);
683
+ if (!symbol)
684
+ return SYMBOL_TOKEN_BASE;
685
+ let tokens = SYMBOL_TOKEN_BASE;
686
+ tokens += symbol.name.length / TOKENS_PER_CHAR_ESTIMATE;
687
+ if (symbol.signature_json) {
688
+ tokens += symbol.signature_json.length / TOKENS_PER_CHAR_ESTIMATE;
689
+ }
690
+ if (symbol.summary) {
691
+ tokens += Math.min(symbol.summary.length / TOKENS_PER_CHAR_ESTIMATE, SYMBOL_TOKEN_ADDITIONAL_MAX);
692
+ }
693
+ const outgoing = graph.adjacencyOut.get(symbolId) ?? [];
694
+ tokens += outgoing.length * 5;
695
+ return Math.ceil(tokens);
696
+ }
697
+ function uniqueLimit(values, max) {
698
+ const seen = new Set();
699
+ const result = [];
700
+ for (const value of values) {
701
+ if (!value || seen.has(value))
702
+ continue;
703
+ seen.add(value);
704
+ result.push(value);
705
+ if (result.length >= max)
706
+ break;
707
+ }
708
+ return result;
709
+ }
710
+ function toFullCard(card) {
711
+ const normalized = {
712
+ ...card,
713
+ detailLevel: "full",
714
+ };
715
+ delete normalized.etag;
716
+ return normalized;
717
+ }
718
+ function toCompactCard(card) {
719
+ const compact = {
720
+ symbolId: card.symbolId,
721
+ repoId: card.repoId,
722
+ file: card.file,
723
+ range: card.range,
724
+ kind: card.kind,
725
+ name: card.name,
726
+ exported: card.exported,
727
+ deps: {
728
+ imports: uniqueLimit(card.deps?.imports ?? [], SYMBOL_CARD_MAX_DEPS_PER_KIND_LIGHT),
729
+ calls: uniqueLimit(card.deps?.calls ?? [], SYMBOL_CARD_MAX_DEPS_PER_KIND_LIGHT),
730
+ },
731
+ detailLevel: "compact",
732
+ version: card.version,
733
+ };
734
+ if (card.visibility) {
735
+ compact.visibility = card.visibility;
736
+ }
737
+ if (card.summary) {
738
+ compact.summary = card.summary.slice(0, SYMBOL_CARD_SUMMARY_MAX_CHARS_LIGHT);
739
+ }
740
+ return compact;
741
+ }
742
+ export function toSliceSymbolCard(card) {
743
+ const detailLevel = card.detailLevel ?? "compact";
744
+ const astFingerprint = card.version.astFingerprint.slice(0, AST_FINGERPRINT_WIRE_LENGTH);
745
+ const sliceCard = {
746
+ symbolId: card.symbolId,
747
+ file: card.file,
748
+ range: card.range,
749
+ kind: card.kind,
750
+ name: card.name,
751
+ exported: card.exported,
752
+ deps: card.deps,
753
+ detailLevel,
754
+ version: {
755
+ astFingerprint,
756
+ },
757
+ };
758
+ if (card.visibility) {
759
+ sliceCard.visibility = card.visibility;
760
+ }
761
+ if (card.signature) {
762
+ sliceCard.signature = card.signature;
763
+ }
764
+ if (card.summary) {
765
+ sliceCard.summary = card.summary;
766
+ }
767
+ if (card.invariants && card.invariants.length > 0) {
768
+ sliceCard.invariants = card.invariants;
769
+ }
770
+ if (card.sideEffects && card.sideEffects.length > 0) {
771
+ sliceCard.sideEffects = card.sideEffects;
772
+ }
773
+ if (card.metrics) {
774
+ sliceCard.metrics = card.metrics;
775
+ }
776
+ return sliceCard;
777
+ }
778
+ async function loadSymbolCards(symbolIds, versionId, repoId, detailedSymbolIds) {
779
+ if (symbolIds.length === 0)
780
+ return [];
781
+ const config = loadConfig();
782
+ const cacheConfig = config.cache;
783
+ const cacheEnabled = cacheConfig?.enabled ?? true;
784
+ const cards = [];
785
+ const uncachedSymbolIds = [];
786
+ const detailBySymbolId = new Map();
787
+ for (const symbolId of symbolIds) {
788
+ const isDetailed = detailedSymbolIds?.has(symbolId) ?? false;
789
+ detailBySymbolId.set(symbolId, isDetailed);
790
+ }
791
+ if (cacheEnabled) {
792
+ for (const symbolId of symbolIds) {
793
+ const isDetailed = detailBySymbolId.get(symbolId) ?? false;
794
+ const cachedCard = symbolCardCache.get(repoId, symbolId, versionId);
795
+ if (!cachedCard) {
796
+ uncachedSymbolIds.push(symbolId);
797
+ continue;
798
+ }
799
+ if (isDetailed) {
800
+ if (cachedCard.detailLevel === "compact") {
801
+ uncachedSymbolIds.push(symbolId);
802
+ continue;
803
+ }
804
+ cards.push(toFullCard(cachedCard));
805
+ continue;
806
+ }
807
+ cards.push(toCompactCard(cachedCard));
808
+ }
809
+ }
810
+ else {
811
+ uncachedSymbolIds.push(...symbolIds);
812
+ }
813
+ if (uncachedSymbolIds.length === 0) {
814
+ return cards;
815
+ }
816
+ uncachedSymbolIds.sort();
817
+ // Batch fetch all symbols (1 query instead of N)
818
+ const symbolsMap = db.getSymbolsByIds(uncachedSymbolIds);
819
+ // Collect unique file IDs and batch fetch files (1 query instead of N)
820
+ const fileIds = new Set();
821
+ for (const symbol of symbolsMap.values()) {
822
+ fileIds.add(symbol.file_id);
823
+ }
824
+ const filesMap = db.getFilesByIds([...fileIds]);
825
+ // Batch fetch all metrics (1 query instead of N)
826
+ const metricsMap = db.getMetricsBySymbolIds(uncachedSymbolIds);
827
+ // Batch fetch all outgoing edges (1 query instead of N)
828
+ const edgesMap = db.getEdgesFromSymbols(uncachedSymbolIds);
829
+ // Collect all imported symbol IDs to batch fetch their names
830
+ const importedSymbolIds = new Set();
831
+ const calledSymbolIds = new Set();
832
+ for (const edges of edgesMap.values()) {
833
+ for (const edge of edges) {
834
+ if (edge.type === "import") {
835
+ importedSymbolIds.add(edge.to_symbol_id);
836
+ }
837
+ else if (edge.type === "call") {
838
+ calledSymbolIds.add(edge.to_symbol_id);
839
+ }
840
+ }
841
+ }
842
+ // Batch fetch imported symbols for name lookup (lite version - only name needed)
843
+ const importedSymbolsMap = db.getSymbolsByIdsLite([...importedSymbolIds]);
844
+ const calledSymbolsMap = db.getSymbolsByIdsLite([...calledSymbolIds]);
845
+ // Build cards using pre-fetched data
846
+ for (const symbolId of uncachedSymbolIds) {
847
+ const symbolRow = symbolsMap.get(symbolId);
848
+ if (!symbolRow)
849
+ continue;
850
+ const isDetailed = detailBySymbolId.get(symbolId) ?? false;
851
+ const file = filesMap.get(symbolRow.file_id);
852
+ const metrics = metricsMap.get(symbolId);
853
+ const outgoingEdges = edgesMap.get(symbolId) ?? [];
854
+ const importDeps = [];
855
+ const callDeps = [];
856
+ for (const edge of outgoingEdges) {
857
+ if (edge.type === "import") {
858
+ const importedSymbol = importedSymbolsMap.get(edge.to_symbol_id);
859
+ const depLabel = pickDepLabel(edge.to_symbol_id, importedSymbol?.name);
860
+ if (depLabel) {
861
+ importDeps.push(depLabel);
862
+ }
863
+ }
864
+ else if (edge.type === "call") {
865
+ const calledSymbol = calledSymbolsMap.get(edge.to_symbol_id);
866
+ const depLabel = pickDepLabel(edge.to_symbol_id, calledSymbol?.name);
867
+ if (depLabel) {
868
+ callDeps.push(depLabel);
869
+ }
870
+ }
871
+ }
872
+ const depLimit = isDetailed
873
+ ? SYMBOL_CARD_MAX_DEPS_PER_KIND
874
+ : SYMBOL_CARD_MAX_DEPS_PER_KIND_LIGHT;
875
+ const deps = {
876
+ imports: uniqueLimit(importDeps, depLimit),
877
+ calls: uniqueLimit(callDeps, depLimit),
878
+ };
879
+ let signature;
880
+ if (isDetailed && symbolRow.signature_json) {
881
+ try {
882
+ signature = JSON.parse(symbolRow.signature_json);
883
+ }
884
+ catch (error) {
885
+ // Log parse failure but continue with fallback
886
+ process.stderr.write(`[sdl-mcp] Failed to parse signature_json for symbol ${symbolId}: ${error instanceof Error ? error.message : String(error)}\n`);
887
+ signature = { name: symbolRow.name };
888
+ }
889
+ }
890
+ else if (isDetailed) {
891
+ signature = { name: symbolRow.name };
892
+ }
893
+ let invariants;
894
+ if (symbolRow.invariants_json) {
895
+ try {
896
+ const parsed = JSON.parse(symbolRow.invariants_json);
897
+ invariants = parsed.slice(0, isDetailed
898
+ ? SYMBOL_CARD_MAX_INVARIANTS
899
+ : SYMBOL_CARD_MAX_INVARIANTS_LIGHT);
900
+ }
901
+ catch (error) {
902
+ process.stderr.write(`[sdl-mcp] Failed to parse invariants_json for symbol ${symbolId}: ${error instanceof Error ? error.message : String(error)}\n`);
903
+ }
904
+ }
905
+ let sideEffects;
906
+ if (symbolRow.side_effects_json) {
907
+ try {
908
+ const parsed = JSON.parse(symbolRow.side_effects_json);
909
+ sideEffects = parsed.slice(0, isDetailed
910
+ ? SYMBOL_CARD_MAX_SIDE_EFFECTS
911
+ : SYMBOL_CARD_MAX_SIDE_EFFECTS_LIGHT);
912
+ }
913
+ catch (error) {
914
+ process.stderr.write(`[sdl-mcp] Failed to parse side_effects_json for symbol ${symbolId}: ${error instanceof Error ? error.message : String(error)}\n`);
915
+ }
916
+ }
917
+ let metricsData;
918
+ if (isDetailed && metrics) {
919
+ let testRefs;
920
+ if (metrics.test_refs_json) {
921
+ try {
922
+ testRefs = JSON.parse(metrics.test_refs_json);
923
+ }
924
+ catch (error) {
925
+ process.stderr.write(`[sdl-mcp] Failed to parse test_refs_json for symbol ${symbolId}: ${error instanceof Error ? error.message : String(error)}\n`);
926
+ }
927
+ }
928
+ if (testRefs) {
929
+ testRefs = uniqueLimit(testRefs, SYMBOL_CARD_MAX_TEST_REFS);
930
+ }
931
+ metricsData = {
932
+ fanIn: metrics.fan_in,
933
+ fanOut: metrics.fan_out,
934
+ churn30d: metrics.churn_30d,
935
+ testRefs,
936
+ };
937
+ }
938
+ const baseCard = {
939
+ symbolId: symbolRow.symbol_id,
940
+ repoId: symbolRow.repo_id,
941
+ file: file?.rel_path ?? "",
942
+ range: {
943
+ startLine: symbolRow.range_start_line,
944
+ startCol: symbolRow.range_start_col,
945
+ endLine: symbolRow.range_end_line,
946
+ endCol: symbolRow.range_end_col,
947
+ },
948
+ kind: symbolRow.kind,
949
+ name: symbolRow.name,
950
+ exported: symbolRow.exported === 1,
951
+ visibility: symbolRow.visibility ?? undefined,
952
+ signature: isDetailed ? signature : undefined,
953
+ summary: symbolRow.summary
954
+ ? symbolRow.summary.slice(0, isDetailed
955
+ ? SYMBOL_CARD_SUMMARY_MAX_CHARS
956
+ : SYMBOL_CARD_SUMMARY_MAX_CHARS_LIGHT)
957
+ : undefined,
958
+ invariants: invariants && invariants.length > 0 ? invariants : undefined,
959
+ sideEffects: sideEffects && sideEffects.length > 0 ? sideEffects : undefined,
960
+ deps,
961
+ metrics: isDetailed ? metricsData : undefined,
962
+ detailLevel: isDetailed ? "full" : "compact",
963
+ version: {
964
+ ledgerVersion: versionId,
965
+ astFingerprint: symbolRow.ast_fingerprint,
966
+ },
967
+ };
968
+ const card = isDetailed ? toFullCard(baseCard) : toCompactCard(baseCard);
969
+ cards.push(card);
970
+ // Only full cards go into the shared symbol cache; compact cards can
971
+ // otherwise leak into symbol.getCard responses.
972
+ if (cacheEnabled && isDetailed) {
973
+ await symbolCardCache.set(repoId, symbolRow.symbol_id, versionId, toFullCard(card));
974
+ }
975
+ }
976
+ return cards;
977
+ }
978
+ function loadEdgesBetweenSymbols(symbolIds, _repoId) {
979
+ if (symbolIds.length === 0) {
980
+ return {
981
+ symbolIndex: [],
982
+ edges: [],
983
+ };
984
+ }
985
+ const symbolSet = new Set(symbolIds);
986
+ const dbEdges = [];
987
+ // Batch fetch all outgoing edges (1 query instead of N)
988
+ const edgesMap = db.getEdgesFromSymbols(symbolIds);
989
+ for (const [_fromId, outgoing] of edgesMap) {
990
+ for (const edge of outgoing) {
991
+ if (symbolSet.has(edge.to_symbol_id)) {
992
+ dbEdges.push(edge);
993
+ }
994
+ }
995
+ }
996
+ return encodeEdgesWithSymbolIndex(symbolIds, dbEdges);
997
+ }
998
+ export function encodeEdgesWithSymbolIndex(symbolIds, dbEdges) {
999
+ const symbolIndex = Array.from(new Set(symbolIds)).sort();
1000
+ const symbolPosition = new Map();
1001
+ for (const [index, symbolId] of symbolIndex.entries()) {
1002
+ symbolPosition.set(symbolId, index);
1003
+ }
1004
+ const edges = [];
1005
+ for (const edge of dbEdges) {
1006
+ const fromIndex = symbolPosition.get(edge.from_symbol_id);
1007
+ const toIndex = symbolPosition.get(edge.to_symbol_id);
1008
+ if (fromIndex === undefined || toIndex === undefined)
1009
+ continue;
1010
+ edges.push([fromIndex, toIndex, edge.type, edge.weight]);
1011
+ }
1012
+ return {
1013
+ symbolIndex,
1014
+ edges,
1015
+ };
1016
+ }
1017
+ export function estimateTokens(cards) {
1018
+ let total = 0;
1019
+ for (const card of cards) {
1020
+ let cardTokens = SYMBOL_TOKEN_BASE;
1021
+ cardTokens += estimateTextTokens(card.name);
1022
+ cardTokens += estimateTextTokens(card.file);
1023
+ if (card.signature) {
1024
+ const sigText = JSON.stringify(card.signature);
1025
+ cardTokens += estimateTextTokens(sigText);
1026
+ }
1027
+ if (card.summary) {
1028
+ cardTokens += Math.min(estimateTextTokens(card.summary), SYMBOL_TOKEN_ADDITIONAL_MAX);
1029
+ }
1030
+ cardTokens += card.deps.imports.length * 5;
1031
+ cardTokens += card.deps.calls.length * 5;
1032
+ if (card.invariants) {
1033
+ for (const invariant of card.invariants) {
1034
+ cardTokens += estimateTextTokens(invariant);
1035
+ }
1036
+ }
1037
+ if (card.sideEffects) {
1038
+ for (const effect of card.sideEffects) {
1039
+ cardTokens += estimateTextTokens(effect);
1040
+ }
1041
+ }
1042
+ cardTokens = Math.min(cardTokens, SYMBOL_TOKEN_MAX);
1043
+ total += cardTokens;
1044
+ }
1045
+ return total;
1046
+ }
1047
+ //# sourceMappingURL=slice.js.map