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,1054 @@
1
+ import { getDb } from "./db.js";
2
+ import { hashContent } from "../util/hashing.js";
3
+ import { MAX_STATEMENT_CACHE_SIZE, DB_CHUNK_SIZE, DB_QUERY_LIMIT_DEFAULT, DB_QUERY_LIMIT_MAX, } from "../config/constants.js";
4
+ import { z } from "zod";
5
+ const stmtCache = new Map();
6
+ const stmtCacheOrder = [];
7
+ /**
8
+ * Escapes SQL LIKE wildcard characters (%, _, \) in user input.
9
+ * Prevents unintended pattern matching when user input contains these chars.
10
+ */
11
+ function escapeSearchPattern(query) {
12
+ return query.replace(/[%_\\]/g, "\\$&");
13
+ }
14
+ function stmt(sql) {
15
+ let s = stmtCache.get(sql);
16
+ if (s) {
17
+ const idx = stmtCacheOrder.indexOf(sql);
18
+ if (idx !== -1) {
19
+ stmtCacheOrder.splice(idx, 1);
20
+ stmtCacheOrder.push(sql);
21
+ }
22
+ }
23
+ else {
24
+ s = getDb().prepare(sql);
25
+ stmtCache.set(sql, s);
26
+ stmtCacheOrder.push(sql);
27
+ if (stmtCache.size > MAX_STATEMENT_CACHE_SIZE) {
28
+ const oldest = stmtCacheOrder.shift();
29
+ if (oldest) {
30
+ stmtCache.delete(oldest);
31
+ }
32
+ }
33
+ }
34
+ return s;
35
+ }
36
+ export function resetQueryCache() {
37
+ stmtCache.clear();
38
+ stmtCacheOrder.length = 0;
39
+ }
40
+ // Repo operations
41
+ /**
42
+ * Creates a new repository record in the database.
43
+ *
44
+ * @param repo - Repository record with repo_id, root_path, config_json, and created_at
45
+ */
46
+ export function createRepo(repo) {
47
+ stmt("INSERT INTO repos (repo_id, root_path, config_json, created_at) VALUES (?, ?, ?, ?)").run(repo.repo_id, repo.root_path, repo.config_json, repo.created_at);
48
+ }
49
+ /**
50
+ * Retrieves a repository by ID.
51
+ *
52
+ * @param repoId - Repository identifier
53
+ * @returns Repository record or null if not found
54
+ */
55
+ export function getRepo(repoId) {
56
+ return stmt("SELECT * FROM repos WHERE repo_id = ?").get(repoId);
57
+ }
58
+ /**
59
+ * Lists all repositories in the database.
60
+ *
61
+ * @returns Array of all repository records
62
+ */
63
+ export function listRepos() {
64
+ return stmt("SELECT * FROM repos").all();
65
+ }
66
+ /**
67
+ * Updates repository root_path and config_json by ID.
68
+ *
69
+ * @param repoId - Repository identifier
70
+ * @param updates - Partial repository record with fields to update (only root_path and config_json are supported)
71
+ */
72
+ export function updateRepo(repoId, updates) {
73
+ stmt("UPDATE repos SET root_path = coalesce(?, root_path), config_json = coalesce(?, config_json) WHERE repo_id = ?").run(updates.root_path ?? null, updates.config_json ?? null, repoId);
74
+ }
75
+ // File operations
76
+ /**
77
+ * Inserts or updates a file record.
78
+ * Uses upsert semantics to handle both new and existing files.
79
+ *
80
+ * @param file - File record without file_id (auto-generated) and directory (computed)
81
+ */
82
+ export function upsertFile(file) {
83
+ const directory = file.rel_path.includes("/")
84
+ ? file.rel_path.substring(0, file.rel_path.lastIndexOf("/"))
85
+ : "";
86
+ stmt(`INSERT INTO files (repo_id, rel_path, content_hash, language, byte_size, last_indexed_at, directory)
87
+ VALUES (?, ?, ?, ?, ?, ?, ?)
88
+ ON CONFLICT(repo_id, rel_path) DO UPDATE SET
89
+ content_hash = excluded.content_hash,
90
+ language = excluded.language,
91
+ byte_size = excluded.byte_size,
92
+ last_indexed_at = excluded.last_indexed_at,
93
+ directory = excluded.directory`).run(file.repo_id, file.rel_path, file.content_hash, file.language, file.byte_size, file.last_indexed_at, directory);
94
+ }
95
+ /**
96
+ * Retrieves a file by ID.
97
+ *
98
+ * @param fileId - File identifier
99
+ * @returns File record or null if not found
100
+ */
101
+ export function getFile(fileId) {
102
+ return stmt("SELECT * FROM files WHERE file_id = ?").get(fileId);
103
+ }
104
+ /**
105
+ * Lists all files for a repository.
106
+ *
107
+ * @param repoId - Repository identifier
108
+ * @returns Array of file records for the repository
109
+ */
110
+ export function getFilesByRepo(repoId) {
111
+ return stmt("SELECT * FROM files WHERE repo_id = ?").all(repoId);
112
+ }
113
+ /**
114
+ * Lists all files for a repository with minimal projection.
115
+ * Returns only file_id and rel_path for lightweight lookups.
116
+ *
117
+ * @param repoId - Repository identifier
118
+ * @returns Array of file records with minimal fields
119
+ */
120
+ export function getFilesByRepoLite(repoId) {
121
+ return stmt("SELECT file_id, rel_path FROM files WHERE repo_id = ?").all(repoId);
122
+ }
123
+ /**
124
+ * Retrieves a file by repository ID and relative path.
125
+ *
126
+ * @param repoId - Repository identifier
127
+ * @param relPath - Relative path within repository
128
+ * @returns File record or null if not found
129
+ */
130
+ export function getFileByRepoPath(repoId, relPath) {
131
+ return stmt("SELECT * FROM files WHERE repo_id = ? AND rel_path = ?").get(repoId, relPath);
132
+ }
133
+ /**
134
+ * Deletes a file record by ID.
135
+ *
136
+ * @param fileId - File identifier
137
+ */
138
+ export function deleteFile(fileId) {
139
+ stmt("DELETE FROM files WHERE file_id = ?").run(fileId);
140
+ }
141
+ /**
142
+ * Batch fetch files by IDs. Uses chunked queries to avoid SQLite parameter limits.
143
+ * Returns a Map for O(1) lookup by file_id.
144
+ */
145
+ export function getFilesByIds(fileIds) {
146
+ if (fileIds.length === 0)
147
+ return new Map();
148
+ const result = new Map();
149
+ const uniqueIds = [...new Set(fileIds)]; // Deduplicate
150
+ for (let i = 0; i < uniqueIds.length; i += DB_CHUNK_SIZE) {
151
+ const chunk = uniqueIds.slice(i, i + DB_CHUNK_SIZE);
152
+ const placeholders = chunk.map(() => "?").join(",");
153
+ const rows = getDb()
154
+ .prepare(`SELECT * FROM files WHERE file_id IN (${placeholders})`)
155
+ .all(...chunk);
156
+ for (const row of rows) {
157
+ result.set(row.file_id, row);
158
+ }
159
+ }
160
+ return result;
161
+ }
162
+ /**
163
+ * Batch fetch files by IDs with minimal projection.
164
+ * Returns only file_id and rel_path for lightweight lookups.
165
+ * Uses chunked queries to avoid SQLite parameter limits.
166
+ *
167
+ * @param fileIds - Array of file identifiers
168
+ * @returns Map of file_id to minimal file record
169
+ */
170
+ export function getFilesByIdsLite(fileIds) {
171
+ if (fileIds.length === 0)
172
+ return new Map();
173
+ const result = new Map();
174
+ const uniqueIds = [...new Set(fileIds)]; // Deduplicate
175
+ for (let i = 0; i < uniqueIds.length; i += DB_CHUNK_SIZE) {
176
+ const chunk = uniqueIds.slice(i, i + DB_CHUNK_SIZE);
177
+ const placeholders = chunk.map(() => "?").join(",");
178
+ const rows = getDb()
179
+ .prepare(`SELECT file_id, rel_path FROM files WHERE file_id IN (${placeholders})`)
180
+ .all(...chunk);
181
+ for (const row of rows) {
182
+ result.set(row.file_id, row);
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ // Symbol operations
188
+ /**
189
+ * Inserts or updates a symbol record.
190
+ * Uses upsert semantics to handle both new and existing symbols.
191
+ *
192
+ * @param symbol - Complete symbol record with all fields
193
+ */
194
+ export function upsertSymbol(symbol) {
195
+ stmt(`INSERT INTO symbols (
196
+ symbol_id, repo_id, file_id, kind, name, exported, visibility, language,
197
+ range_start_line, range_start_col, range_end_line, range_end_col,
198
+ ast_fingerprint, signature_json, summary, invariants_json, side_effects_json, updated_at
199
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
200
+ ON CONFLICT(symbol_id) DO UPDATE SET
201
+ repo_id = excluded.repo_id,
202
+ file_id = excluded.file_id,
203
+ kind = excluded.kind,
204
+ name = excluded.name,
205
+ exported = excluded.exported,
206
+ visibility = excluded.visibility,
207
+ language = excluded.language,
208
+ range_start_line = excluded.range_start_line,
209
+ range_start_col = excluded.range_start_col,
210
+ range_end_line = excluded.range_end_line,
211
+ range_end_col = excluded.range_end_col,
212
+ ast_fingerprint = excluded.ast_fingerprint,
213
+ signature_json = excluded.signature_json,
214
+ summary = excluded.summary,
215
+ invariants_json = excluded.invariants_json,
216
+ side_effects_json = excluded.side_effects_json,
217
+ updated_at = excluded.updated_at`).run(symbol.symbol_id, symbol.repo_id, symbol.file_id, symbol.kind, symbol.name, symbol.exported, symbol.visibility, symbol.language, symbol.range_start_line, symbol.range_start_col, symbol.range_end_line, symbol.range_end_col, symbol.ast_fingerprint, symbol.signature_json, symbol.summary, symbol.invariants_json, symbol.side_effects_json, symbol.updated_at);
218
+ }
219
+ /**
220
+ * Retrieves a symbol by ID.
221
+ *
222
+ * @param symbolId - Symbol identifier
223
+ * @returns Symbol record or null if not found
224
+ */
225
+ export function getSymbol(symbolId) {
226
+ return stmt("SELECT * FROM symbols WHERE symbol_id = ?").get(symbolId);
227
+ }
228
+ /**
229
+ * Lists all symbols for a file.
230
+ *
231
+ * @param fileId - File identifier
232
+ * @returns Array of symbol records for the file
233
+ */
234
+ export function getSymbolsByFile(fileId) {
235
+ return stmt("SELECT * FROM symbols WHERE file_id = ?").all(fileId);
236
+ }
237
+ /**
238
+ * Lists all symbol IDs for a file (minimal projection).
239
+ * Use when only symbol IDs are needed, not full records.
240
+ *
241
+ * @param fileId - File identifier
242
+ * @returns Array of symbol identifiers
243
+ */
244
+ export function getSymbolIdsByFile(fileId) {
245
+ return stmt("SELECT symbol_id FROM symbols WHERE file_id = ?")
246
+ .all(fileId)
247
+ .map((row) => row.symbol_id);
248
+ }
249
+ /**
250
+ * Lists all symbols for a file with minimal projection.
251
+ * Returns symbol_id, name, exported for import resolution.
252
+ *
253
+ * @param fileId - File identifier
254
+ * @returns Array of symbol records with minimal fields
255
+ */
256
+ export function getSymbolsByFileLite(fileId) {
257
+ return stmt("SELECT symbol_id, name, exported FROM symbols WHERE file_id = ?").all(fileId);
258
+ }
259
+ /**
260
+ * Lists all symbols for a repository.
261
+ *
262
+ * @param repoId - Repository identifier
263
+ * @returns Array of all symbol records for repository
264
+ */
265
+ export function getSymbolsByRepo(repoId) {
266
+ return stmt("SELECT * FROM symbols WHERE repo_id = ?").all(repoId);
267
+ }
268
+ /**
269
+ * Lists all symbols for a repository with version snapshot projection.
270
+ * Returns only fields needed for versioning: symbol_id, ast_fingerprint, signature_json,
271
+ * summary, invariants_json, side_effects_json.
272
+ *
273
+ * @param repoId - Repository identifier
274
+ * @returns Array of symbol records for snapshot
275
+ */
276
+ export function getSymbolsByRepoForSnapshot(repoId) {
277
+ return stmt(`SELECT symbol_id, ast_fingerprint, signature_json, summary, invariants_json, side_effects_json
278
+ FROM symbols WHERE repo_id = ?`).all(repoId);
279
+ }
280
+ export function countSymbolsByRepo(repoId) {
281
+ const result = stmt("SELECT COUNT(*) as count FROM symbols WHERE repo_id = ?").get(repoId);
282
+ return result.count;
283
+ }
284
+ /**
285
+ * Batch fetch symbols by IDs. Uses chunked queries to avoid SQLite parameter limits.
286
+ * Returns a Map for O(1) lookup by symbol_id.
287
+ *
288
+ * @param symbolIds - Array of symbol identifiers
289
+ * @returns Map of symbol_id to SymbolRow
290
+ */
291
+ export function getSymbolsByIds(symbolIds) {
292
+ if (symbolIds.length === 0)
293
+ return new Map();
294
+ const result = new Map();
295
+ for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
296
+ const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
297
+ const placeholders = chunk.map(() => "?").join(",");
298
+ const rows = getDb()
299
+ .prepare(`SELECT * FROM symbols WHERE symbol_id IN (${placeholders})`)
300
+ .all(...chunk);
301
+ for (const row of rows) {
302
+ result.set(row.symbol_id, row);
303
+ }
304
+ }
305
+ return result;
306
+ }
307
+ /**
308
+ * Batch fetch symbols by IDs with minimal projection.
309
+ * Returns only symbol_id, name, file_id for lightweight lookups.
310
+ * Uses chunked queries to avoid SQLite parameter limits.
311
+ *
312
+ * @param symbolIds - Array of symbol identifiers
313
+ * @returns Map of symbol_id to minimal symbol record
314
+ */
315
+ export function getSymbolsByIdsLite(symbolIds) {
316
+ if (symbolIds.length === 0)
317
+ return new Map();
318
+ const result = new Map();
319
+ for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
320
+ const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
321
+ const placeholders = chunk.map(() => "?").join(",");
322
+ const rows = getDb()
323
+ .prepare(`SELECT symbol_id, name, file_id FROM symbols WHERE symbol_id IN (${placeholders})`)
324
+ .all(...chunk);
325
+ for (const row of rows) {
326
+ result.set(row.symbol_id, row);
327
+ }
328
+ }
329
+ return result;
330
+ }
331
+ /**
332
+ * Searches symbols by name or summary with LIKE pattern matching.
333
+ * Returns full symbol records with all fields.
334
+ *
335
+ * @param repoId - Repository identifier
336
+ * @param query - Search query string
337
+ * @param limit - Maximum number of results to return
338
+ * @returns Array of matching symbol records
339
+ */
340
+ export function searchSymbols(repoId, query, limit) {
341
+ const searchPattern = `%${escapeSearchPattern(query)}%`;
342
+ // Order results by relevance:
343
+ // 1. Exact name match (case-sensitive) first
344
+ // 2. Exact name match (case-insensitive) second
345
+ // 3. Prefer core files over adapter/test files (deprioritize adapter/, tests/, scripts/)
346
+ // 4. Important symbol kinds (class, function, interface, type, method) before variables
347
+ // 5. Name matches before summary-only matches
348
+ return stmt(`SELECT s.* FROM symbols s
349
+ JOIN files f ON s.file_id = f.file_id
350
+ WHERE s.repo_id = ? AND (s.name LIKE ? ESCAPE '\\' OR s.summary LIKE ? ESCAPE '\\')
351
+ ORDER BY
352
+ CASE WHEN s.name = ? THEN 0 ELSE 1 END,
353
+ CASE WHEN LOWER(s.name) = LOWER(?) THEN 0 ELSE 1 END,
354
+ CASE
355
+ WHEN f.rel_path LIKE '%/adapter/%' THEN 2
356
+ WHEN f.rel_path LIKE '%/tests/%' OR f.rel_path LIKE 'tests/%' THEN 2
357
+ WHEN f.rel_path LIKE 'scripts/%' THEN 2
358
+ WHEN f.rel_path LIKE '%.test.%' OR f.rel_path LIKE '%.spec.%' THEN 2
359
+ ELSE 0
360
+ END,
361
+ CASE s.kind
362
+ WHEN 'class' THEN 0
363
+ WHEN 'function' THEN 1
364
+ WHEN 'interface' THEN 2
365
+ WHEN 'type' THEN 3
366
+ WHEN 'method' THEN 4
367
+ WHEN 'constructor' THEN 5
368
+ WHEN 'module' THEN 6
369
+ ELSE 7
370
+ END,
371
+ CASE WHEN s.name LIKE ? ESCAPE '\\' THEN 0 ELSE 1 END
372
+ LIMIT ?`).all(repoId, searchPattern, searchPattern, query, query, searchPattern, limit);
373
+ }
374
+ /**
375
+ * Searches symbols by name or summary with LIKE pattern matching.
376
+ * Returns minimal projection: only symbol_id, name, file_id, kind.
377
+ * Use for search result listings where full symbol data is not needed.
378
+ *
379
+ * @param repoId - Repository identifier
380
+ * @param query - Search query string
381
+ * @param limit - Maximum number of results to return
382
+ * @returns Array of symbol records with minimal fields
383
+ */
384
+ export function searchSymbolsLite(repoId, query, limit) {
385
+ const searchPattern = `%${escapeSearchPattern(query)}%`;
386
+ // Order results by relevance (same logic as searchSymbols)
387
+ return stmt(`SELECT s.symbol_id, s.name, s.file_id, s.kind FROM symbols s
388
+ JOIN files f ON s.file_id = f.file_id
389
+ WHERE s.repo_id = ? AND (s.name LIKE ? ESCAPE '\\' OR s.summary LIKE ? ESCAPE '\\')
390
+ ORDER BY
391
+ CASE WHEN s.name = ? THEN 0 ELSE 1 END,
392
+ CASE WHEN LOWER(s.name) = LOWER(?) THEN 0 ELSE 1 END,
393
+ CASE
394
+ WHEN f.rel_path LIKE '%/adapter/%' THEN 2
395
+ WHEN f.rel_path LIKE '%/tests/%' OR f.rel_path LIKE 'tests/%' THEN 2
396
+ WHEN f.rel_path LIKE 'scripts/%' THEN 2
397
+ WHEN f.rel_path LIKE '%.test.%' OR f.rel_path LIKE '%.spec.%' THEN 2
398
+ ELSE 0
399
+ END,
400
+ CASE s.kind
401
+ WHEN 'class' THEN 0
402
+ WHEN 'function' THEN 1
403
+ WHEN 'interface' THEN 2
404
+ WHEN 'type' THEN 3
405
+ WHEN 'method' THEN 4
406
+ WHEN 'constructor' THEN 5
407
+ WHEN 'module' THEN 6
408
+ ELSE 7
409
+ END,
410
+ CASE WHEN s.name LIKE ? ESCAPE '\\' THEN 0 ELSE 1 END
411
+ LIMIT ?`).all(repoId, searchPattern, searchPattern, query, query, searchPattern, limit);
412
+ }
413
+ /**
414
+ * Finds symbols within a line range, sorted by containment.
415
+ * Returns fully contained symbols first, then overlapping.
416
+ *
417
+ * @param repoId - Repository identifier
418
+ * @param fileId - File identifier
419
+ * @param startLine - Start line of range (1-indexed)
420
+ * @param endLine - End line of range (1-indexed)
421
+ * @returns Array of symbol records sorted by containment
422
+ */
423
+ export function findSymbolsInRange(repoId, fileId, startLine, endLine) {
424
+ return stmt(`SELECT * FROM symbols
425
+ WHERE repo_id = ? AND file_id = ?
426
+ AND range_start_line <= ? AND range_end_line >= ?
427
+ ORDER BY
428
+ CASE
429
+ WHEN range_start_line >= ? AND range_end_line <= ? THEN 0
430
+ WHEN range_start_line <= ? AND range_end_line >= ? THEN 1
431
+ WHEN range_start_line >= ? AND range_start_line <= ? THEN 2
432
+ WHEN range_end_line >= ? AND range_end_line <= ? THEN 3
433
+ ELSE 4
434
+ END,
435
+ ABS(range_start_line - ?)`).all(repoId, fileId, endLine, startLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, startLine);
436
+ }
437
+ /**
438
+ * Finds symbols within a line range with minimal projection.
439
+ * Returns only symbol_id for diagnostic mapping.
440
+ *
441
+ * @param repoId - Repository identifier
442
+ * @param fileId - File identifier
443
+ * @param startLine - Start line of range (1-indexed)
444
+ * @param endLine - End line of range (1-indexed)
445
+ * @returns Array of symbol IDs sorted by containment
446
+ */
447
+ export function findSymbolsInRangeLite(repoId, fileId, startLine, endLine) {
448
+ return stmt(`SELECT symbol_id FROM symbols
449
+ WHERE repo_id = ? AND file_id = ?
450
+ AND range_start_line <= ? AND range_end_line >= ?
451
+ ORDER BY
452
+ CASE
453
+ WHEN range_start_line >= ? AND range_end_line <= ? THEN 0
454
+ WHEN range_start_line <= ? AND range_end_line >= ? THEN 1
455
+ WHEN range_start_line >= ? AND range_start_line <= ? THEN 2
456
+ WHEN range_end_line >= ? AND range_end_line <= ? THEN 3
457
+ ELSE 4
458
+ END,
459
+ ABS(range_start_line - ?)`).all(repoId, fileId, endLine, startLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, endLine, startLine, startLine);
460
+ }
461
+ /**
462
+ * Deletes all symbols for a file.
463
+ *
464
+ * @param fileId - File identifier
465
+ */
466
+ export function deleteSymbolsByFile(fileId) {
467
+ stmt("DELETE FROM symbols WHERE file_id = ?").run(fileId);
468
+ }
469
+ /**
470
+ * Deletes all symbols for a file along with their edges, metrics, and versions.
471
+ * Runs within a transaction for atomicity.
472
+ *
473
+ * @param fileId - File identifier
474
+ */
475
+ export function deleteSymbolsByFileWithEdges(fileId) {
476
+ // Cascading foreign keys on symbols remove dependent edges/metrics/versions.
477
+ deleteSymbolsByFile(fileId);
478
+ }
479
+ // Edge operations
480
+ /**
481
+ * Creates a new edge record.
482
+ *
483
+ * @param edge - Edge record with all required fields
484
+ */
485
+ export function createEdge(edge) {
486
+ stmt("INSERT INTO edges (repo_id, from_symbol_id, to_symbol_id, type, weight, provenance, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run(edge.repo_id, edge.from_symbol_id, edge.to_symbol_id, edge.type, edge.weight, edge.provenance, edge.created_at);
487
+ }
488
+ /**
489
+ * Retrieves outgoing edges for a symbol.
490
+ *
491
+ * @param symbolId - Symbol identifier
492
+ * @returns Array of outgoing edge records
493
+ */
494
+ export function getEdgesFrom(symbolId) {
495
+ return stmt("SELECT * FROM edges WHERE from_symbol_id = ?").all(symbolId);
496
+ }
497
+ /**
498
+ * Retrieves incoming edges for a symbol.
499
+ * Used by scripts/dump-symbol.ts for symbol analysis.
500
+ *
501
+ * @param symbolId - Symbol identifier
502
+ * @returns Array of incoming edge records
503
+ */
504
+ export function getEdgesTo(symbolId) {
505
+ return stmt("SELECT * FROM edges WHERE to_symbol_id = ?").all(symbolId);
506
+ }
507
+ /**
508
+ * Lists all edges for a repository.
509
+ *
510
+ * @param repoId - Repository identifier
511
+ * @returns Array of all edge records for repository
512
+ */
513
+ export function getEdgesByRepo(repoId) {
514
+ return stmt("SELECT * FROM edges WHERE repo_id = ?").all(repoId);
515
+ }
516
+ /**
517
+ * Batch fetch outgoing edges for multiple symbols. Uses chunked queries.
518
+ * Returns a Map where key is from_symbol_id and value is array of edges.
519
+ *
520
+ * @param symbolIds - Array of symbol identifiers
521
+ * @returns Map of symbol_id to array of outgoing edges
522
+ */
523
+ export function getEdgesFromSymbols(symbolIds) {
524
+ if (symbolIds.length === 0)
525
+ return new Map();
526
+ const result = new Map();
527
+ // Initialize empty arrays for all requested symbols
528
+ for (const id of symbolIds) {
529
+ result.set(id, []);
530
+ }
531
+ for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
532
+ const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
533
+ const placeholders = chunk.map(() => "?").join(",");
534
+ const rows = getDb()
535
+ .prepare(`SELECT * FROM edges WHERE from_symbol_id IN (${placeholders})`)
536
+ .all(...chunk);
537
+ for (const row of rows) {
538
+ const edges = result.get(row.from_symbol_id);
539
+ if (edges) {
540
+ edges.push(row);
541
+ }
542
+ }
543
+ }
544
+ return result;
545
+ }
546
+ /**
547
+ * Batch fetch outgoing edges for multiple symbols with minimal projection.
548
+ * Returns only from_symbol_id, to_symbol_id, type for dependency tracking.
549
+ * Uses chunked queries to avoid SQLite parameter limits.
550
+ *
551
+ * @param symbolIds - Array of symbol identifiers
552
+ * @returns Map of symbol_id to array of minimal edge records
553
+ */
554
+ export function getEdgesFromSymbolsLite(symbolIds) {
555
+ if (symbolIds.length === 0)
556
+ return new Map();
557
+ const result = new Map();
558
+ // Initialize empty arrays for all requested symbols
559
+ for (const id of symbolIds) {
560
+ result.set(id, []);
561
+ }
562
+ for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
563
+ const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
564
+ const placeholders = chunk.map(() => "?").join(",");
565
+ const rows = getDb()
566
+ .prepare(`SELECT from_symbol_id, to_symbol_id, type FROM edges WHERE from_symbol_id IN (${placeholders})`)
567
+ .all(...chunk);
568
+ for (const row of rows) {
569
+ const edges = result.get(row.from_symbol_id);
570
+ if (edges) {
571
+ edges.push(row);
572
+ }
573
+ }
574
+ }
575
+ return result;
576
+ }
577
+ /**
578
+ * Deletes all edges (both incoming and outgoing) for a symbol.
579
+ *
580
+ * @param symbolId - Symbol identifier
581
+ */
582
+ export function deleteEdgesBySymbol(symbolId) {
583
+ stmt("DELETE FROM edges WHERE from_symbol_id = ? OR to_symbol_id = ?").run(symbolId, symbolId);
584
+ }
585
+ // Version operations
586
+ export function createVersion(version) {
587
+ stmt("INSERT INTO versions (version_id, repo_id, created_at, reason) VALUES (?, ?, ?, ?)").run(version.version_id, version.repo_id, version.created_at, version.reason);
588
+ }
589
+ export function getVersion(versionId) {
590
+ return stmt("SELECT * FROM versions WHERE version_id = ?").get(versionId);
591
+ }
592
+ export function getLatestVersion(repoId) {
593
+ return stmt("SELECT * FROM versions WHERE repo_id = ? ORDER BY created_at DESC LIMIT 1").get(repoId);
594
+ }
595
+ export function listVersions(repoId, limit = DB_QUERY_LIMIT_DEFAULT) {
596
+ return stmt("SELECT * FROM versions WHERE repo_id = ? ORDER BY created_at DESC LIMIT ?").all(repoId, limit);
597
+ }
598
+ // Symbol version operations
599
+ export function snapshotSymbolVersion(versionId, symbolId, snapshot) {
600
+ stmt(`INSERT INTO symbol_versions (version_id, symbol_id, ast_fingerprint, signature_json, summary, invariants_json, side_effects_json)
601
+ VALUES (?, ?, ?, ?, ?, ?, ?)
602
+ ON CONFLICT(version_id, symbol_id) DO UPDATE SET
603
+ ast_fingerprint = excluded.ast_fingerprint,
604
+ signature_json = excluded.signature_json,
605
+ summary = excluded.summary,
606
+ invariants_json = excluded.invariants_json,
607
+ side_effects_json = excluded.side_effects_json`).run(versionId, symbolId, snapshot.ast_fingerprint, snapshot.signature_json, snapshot.summary, snapshot.invariants_json, snapshot.side_effects_json);
608
+ }
609
+ export function getSymbolVersion(versionId, symbolId) {
610
+ return stmt("SELECT * FROM symbol_versions WHERE version_id = ? AND symbol_id = ?").get(versionId, symbolId);
611
+ }
612
+ // Metrics operations
613
+ export function upsertMetrics(metrics) {
614
+ stmt(`INSERT INTO metrics (symbol_id, fan_in, fan_out, churn_30d, test_refs_json, updated_at)
615
+ VALUES (?, ?, ?, ?, ?, ?)
616
+ ON CONFLICT(symbol_id) DO UPDATE SET
617
+ fan_in = excluded.fan_in,
618
+ fan_out = excluded.fan_out,
619
+ churn_30d = excluded.churn_30d,
620
+ test_refs_json = excluded.test_refs_json,
621
+ updated_at = excluded.updated_at`).run(metrics.symbolId, metrics.fanIn, metrics.fanOut, metrics.churn30d, metrics.testRefsJson, metrics.updatedAt);
622
+ }
623
+ export function getMetrics(symbolId) {
624
+ return stmt("SELECT * FROM metrics WHERE symbol_id = ?").get(symbolId);
625
+ }
626
+ /**
627
+ * Batch fetch metrics by symbol IDs. Uses chunked queries to avoid SQLite parameter limits.
628
+ * Returns a Map for O(1) lookup by symbol_id.
629
+ */
630
+ export function getMetricsBySymbolIds(symbolIds) {
631
+ if (symbolIds.length === 0)
632
+ return new Map();
633
+ const result = new Map();
634
+ for (let i = 0; i < symbolIds.length; i += DB_CHUNK_SIZE) {
635
+ const chunk = symbolIds.slice(i, i + DB_CHUNK_SIZE);
636
+ const placeholders = chunk.map(() => "?").join(",");
637
+ const rows = getDb()
638
+ .prepare(`SELECT * FROM metrics WHERE symbol_id IN (${placeholders})`)
639
+ .all(...chunk);
640
+ for (const row of rows) {
641
+ result.set(row.symbol_id, row);
642
+ }
643
+ }
644
+ return result;
645
+ }
646
+ const AuditEventSchema = z.object({
647
+ timestamp: z.string(),
648
+ tool: z.string(),
649
+ decision: z.string(),
650
+ repoId: z.string().optional(),
651
+ symbolId: z.string().optional(),
652
+ detailsJson: z.string(),
653
+ });
654
+ export function logAuditEvent(event) {
655
+ const validated = AuditEventSchema.parse(event);
656
+ stmt("INSERT INTO audit (timestamp, tool, decision, repo_id, symbol_id, details_json) VALUES (?, ?, ?, ?, ?, ?)").run(validated.timestamp, validated.tool, validated.decision, validated.repoId ?? null, validated.symbolId ?? null, validated.detailsJson);
657
+ }
658
+ export function getAuditEvents(repoId, limit) {
659
+ return stmt(`SELECT * FROM audit
660
+ WHERE (? IS NULL OR repo_id = ?)
661
+ ORDER BY timestamp DESC
662
+ LIMIT ?`).all(repoId ?? null, repoId ?? null, limit ?? DB_QUERY_LIMIT_MAX);
663
+ }
664
+ // Transaction helpers
665
+ export function createRepoTransaction(repo) {
666
+ const db = getDb();
667
+ const createTx = db.transaction(() => {
668
+ createRepo(repo);
669
+ });
670
+ createTx();
671
+ }
672
+ export function upsertFileTransaction(file) {
673
+ const db = getDb();
674
+ const upsertTx = db.transaction(() => {
675
+ upsertFile(file);
676
+ });
677
+ upsertTx();
678
+ }
679
+ export function upsertSymbolTransaction(symbol) {
680
+ const db = getDb();
681
+ const upsertTx = db.transaction(() => {
682
+ upsertSymbol(symbol);
683
+ });
684
+ upsertTx();
685
+ }
686
+ export function createEdgeTransaction(edge) {
687
+ const db = getDb();
688
+ const createTx = db.transaction(() => {
689
+ createEdge(edge);
690
+ });
691
+ createTx();
692
+ }
693
+ export function createVersionTransaction(version) {
694
+ const db = getDb();
695
+ const createTx = db.transaction(() => {
696
+ createVersion(version);
697
+ });
698
+ createTx();
699
+ }
700
+ export function deleteFileTransaction(fileId) {
701
+ const db = getDb();
702
+ const deleteTx = db.transaction(() => {
703
+ deleteSymbolsByFileWithEdges(fileId);
704
+ deleteSymbolReferencesByFileId(fileId);
705
+ deleteFile(fileId);
706
+ });
707
+ deleteTx();
708
+ }
709
+ export function deleteSymbolTransaction(symbolId) {
710
+ const db = getDb();
711
+ const deleteTx = db.transaction(() => {
712
+ deleteEdgesBySymbol(symbolId);
713
+ stmt("DELETE FROM metrics WHERE symbol_id = ?").run(symbolId);
714
+ stmt("DELETE FROM symbol_versions WHERE symbol_id = ?").run(symbolId);
715
+ stmt("DELETE FROM symbols WHERE symbol_id = ?").run(symbolId);
716
+ });
717
+ deleteTx();
718
+ }
719
+ export function createSnapshotTransaction(version, snapshots) {
720
+ const db = getDb();
721
+ const snapshotTx = db.transaction(() => {
722
+ createVersion(version);
723
+ for (const snapshot of snapshots) {
724
+ snapshotSymbolVersion(version.version_id, snapshot.symbol_id, snapshot);
725
+ }
726
+ const sortedVersions = [...snapshots].sort((a, b) => a.symbol_id.localeCompare(b.symbol_id));
727
+ const fingerprints = sortedVersions
728
+ .map((sv) => sv.ast_fingerprint)
729
+ .join("|");
730
+ const combined = `${version.prev_version_hash || "none"}:${fingerprints}`;
731
+ const versionHash = hashContent(combined);
732
+ updateVersionHashes(version.version_id, version.prev_version_hash, versionHash);
733
+ });
734
+ snapshotTx();
735
+ }
736
+ // Slice handle operations
737
+ export function createSliceHandle(handle) {
738
+ stmt(`INSERT INTO slice_handles (handle, repo_id, created_at, expires_at, min_version, max_version, slice_hash, spillover_ref)
739
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(handle.handle, handle.repo_id, handle.created_at, handle.expires_at, handle.min_version ?? null, handle.max_version ?? null, handle.slice_hash, handle.spillover_ref ?? null);
740
+ }
741
+ export function getSliceHandle(handle) {
742
+ return stmt("SELECT * FROM slice_handles WHERE handle = ?").get(handle);
743
+ }
744
+ export function deleteSliceHandle(handle) {
745
+ stmt("DELETE FROM slice_handles WHERE handle = ?").run(handle);
746
+ }
747
+ export function deleteExpiredSliceHandles(beforeTimestamp) {
748
+ const result = stmt("DELETE FROM slice_handles WHERE expires_at < ?").run(beforeTimestamp);
749
+ return result.changes;
750
+ }
751
+ export function updateSliceHandleSpillover(handle, spilloverRef) {
752
+ stmt("UPDATE slice_handles SET spillover_ref = ? WHERE handle = ?").run(spilloverRef, handle);
753
+ }
754
+ // Content-addressed storage operations
755
+ export function upsertCardHash(cardHash, cardBlob, createdAt) {
756
+ stmt(`INSERT INTO card_hashes (card_hash, card_blob, created_at)
757
+ VALUES (?, ?, ?)
758
+ ON CONFLICT(card_hash) DO NOTHING`).run(cardHash, cardBlob, createdAt);
759
+ }
760
+ export function getCardHash(cardHash) {
761
+ return stmt("SELECT * FROM card_hashes WHERE card_hash = ?").get(cardHash);
762
+ }
763
+ export function upsertToolPolicyHash(policyHash, policyBlob, createdAt) {
764
+ stmt(`INSERT INTO tool_policy_hashes (policy_hash, policy_blob, created_at)
765
+ VALUES (?, ?, ?)
766
+ ON CONFLICT(policy_hash) DO NOTHING`).run(policyHash, policyBlob, createdAt);
767
+ }
768
+ export function getToolPolicyHash(policyHash) {
769
+ return stmt("SELECT * FROM tool_policy_hashes WHERE policy_hash = ?").get(policyHash);
770
+ }
771
+ export function upsertTsconfigHash(tsconfigHash, tsconfigBlob, createdAt) {
772
+ stmt(`INSERT INTO tsconfig_hashes (tsconfig_hash, tsconfig_blob, created_at)
773
+ VALUES (?, ?, ?)
774
+ ON CONFLICT(tsconfig_hash) DO NOTHING`).run(tsconfigHash, tsconfigBlob, createdAt);
775
+ }
776
+ export function getTsconfigHash(tsconfigHash) {
777
+ return stmt("SELECT * FROM tsconfig_hashes WHERE tsconfig_hash = ?").get(tsconfigHash);
778
+ }
779
+ // Version hash operations
780
+ export function updateVersionHashes(versionId, prevVersionHash, versionHash) {
781
+ stmt("UPDATE versions SET prev_version_hash = ?, version_hash = ? WHERE version_id = ?").run(prevVersionHash, versionHash, versionId);
782
+ }
783
+ export function getVersionByHash(versionHash) {
784
+ return stmt("SELECT * FROM versions WHERE version_hash = ?").get(versionHash);
785
+ }
786
+ export function listVersionsByPrevHash(prevVersionHash) {
787
+ return stmt("SELECT * FROM versions WHERE prev_version_hash = ? ORDER BY created_at DESC").all(prevVersionHash);
788
+ }
789
+ // Symbol reference operations (inverted index for test references)
790
+ export function insertSymbolReference(ref) {
791
+ stmt(`INSERT INTO symbol_references (repo_id, symbol_name, file_id, line_number, created_at)
792
+ VALUES (?, ?, ?, ?, ?)`).run(ref.repo_id, ref.symbol_name, ref.file_id, ref.line_number, ref.created_at);
793
+ }
794
+ export function getTestRefsForSymbol(repoId, symbolName) {
795
+ return stmt(`SELECT f.rel_path FROM symbol_references sr
796
+ JOIN files f ON sr.file_id = f.file_id
797
+ WHERE sr.repo_id = ? AND sr.symbol_name = ?`)
798
+ .all(repoId, symbolName)
799
+ .map((r) => r.rel_path);
800
+ }
801
+ export function deleteSymbolReferencesByFileId(fileId) {
802
+ stmt("DELETE FROM symbol_references WHERE file_id = ?").run(fileId);
803
+ }
804
+ /**
805
+ * Aggregates symbol counts by directory for a repository.
806
+ * Groups files by their parent directory and counts symbols by kind.
807
+ *
808
+ * @param repoId - Repository identifier
809
+ * @returns Array of directory aggregations
810
+ */
811
+ export function getDirectoryAggregates(repoId) {
812
+ // Use pre-computed directory column for better performance
813
+ return stmt(`
814
+ SELECT
815
+ f.directory,
816
+ COUNT(DISTINCT s.file_id) as file_count,
817
+ COUNT(*) as symbol_count,
818
+ SUM(CASE WHEN s.exported = 1 THEN 1 ELSE 0 END) as exported_count,
819
+ SUM(CASE WHEN s.kind = 'function' THEN 1 ELSE 0 END) as function_count,
820
+ SUM(CASE WHEN s.kind = 'class' THEN 1 ELSE 0 END) as class_count,
821
+ SUM(CASE WHEN s.kind = 'interface' THEN 1 ELSE 0 END) as interface_count,
822
+ SUM(CASE WHEN s.kind = 'type' THEN 1 ELSE 0 END) as type_count,
823
+ SUM(CASE WHEN s.kind = 'method' THEN 1 ELSE 0 END) as method_count,
824
+ SUM(CASE WHEN s.kind = 'variable' THEN 1 ELSE 0 END) as variable_count,
825
+ SUM(CASE WHEN s.kind = 'module' THEN 1 ELSE 0 END) as module_count,
826
+ SUM(CASE WHEN s.kind = 'constructor' THEN 1 ELSE 0 END) as constructor_count
827
+ FROM symbols s
828
+ JOIN files f ON s.file_id = f.file_id
829
+ WHERE s.repo_id = ?
830
+ GROUP BY f.directory
831
+ ORDER BY symbol_count DESC
832
+ `).all(repoId);
833
+ }
834
+ /**
835
+ * Gets exported symbols grouped by directory.
836
+ *
837
+ * @param repoId - Repository identifier
838
+ * @param limit - Maximum symbols per directory
839
+ * @returns Array of exported symbol records with directory
840
+ */
841
+ export function getExportedSymbolsByDirectory(repoId, limit = 20) {
842
+ return stmt(`
843
+ WITH file_dirs AS (
844
+ SELECT
845
+ file_id,
846
+ CASE
847
+ WHEN instr(rel_path, '/') > 0
848
+ THEN substr(rel_path, 1, length(rel_path) - length(replace(rel_path, rtrim(rel_path, replace(rel_path, '/', '')), '')))
849
+ ELSE ''
850
+ END as directory
851
+ FROM files
852
+ WHERE repo_id = ?
853
+ ),
854
+ ranked_exports AS (
855
+ SELECT
856
+ s.symbol_id,
857
+ s.name,
858
+ s.kind,
859
+ s.exported,
860
+ s.signature_json,
861
+ fd.directory,
862
+ ROW_NUMBER() OVER (PARTITION BY fd.directory ORDER BY s.name) as rn
863
+ FROM symbols s
864
+ JOIN file_dirs fd ON s.file_id = fd.file_id
865
+ WHERE s.repo_id = ? AND s.exported = 1
866
+ )
867
+ SELECT symbol_id, name, kind, exported, directory, signature_json
868
+ FROM ranked_exports
869
+ WHERE rn <= ?
870
+ ORDER BY directory, name
871
+ `).all(repoId, repoId, limit);
872
+ }
873
+ /**
874
+ * Gets top symbols by fan-in (most depended upon).
875
+ *
876
+ * @param repoId - Repository identifier
877
+ * @param limit - Maximum number of symbols to return
878
+ * @returns Array of symbols ordered by fan-in descending
879
+ */
880
+ export function getTopSymbolsByFanIn(repoId, limit = 10) {
881
+ return stmt(`
882
+ WITH file_dirs AS (
883
+ SELECT
884
+ file_id,
885
+ CASE
886
+ WHEN instr(rel_path, '/') > 0
887
+ THEN substr(rel_path, 1, length(rel_path) - length(replace(rel_path, rtrim(rel_path, replace(rel_path, '/', '')), '')))
888
+ ELSE ''
889
+ END as directory
890
+ FROM files
891
+ WHERE repo_id = ?
892
+ )
893
+ SELECT
894
+ s.symbol_id,
895
+ s.name,
896
+ s.kind,
897
+ s.exported,
898
+ s.signature_json,
899
+ COALESCE(m.fan_in, 0) as fan_in,
900
+ COALESCE(m.fan_out, 0) as fan_out,
901
+ COALESCE(m.churn_30d, 0) as churn_30d,
902
+ COALESCE(fd.directory, '') as directory
903
+ FROM symbols s
904
+ LEFT JOIN metrics m ON s.symbol_id = m.symbol_id
905
+ LEFT JOIN file_dirs fd ON s.file_id = fd.file_id
906
+ WHERE s.repo_id = ?
907
+ ORDER BY COALESCE(m.fan_in, 0) DESC
908
+ LIMIT ?
909
+ `).all(repoId, repoId, limit);
910
+ }
911
+ /**
912
+ * Gets top symbols by churn (most frequently changed).
913
+ *
914
+ * @param repoId - Repository identifier
915
+ * @param limit - Maximum number of symbols to return
916
+ * @returns Array of symbols ordered by churn descending
917
+ */
918
+ export function getTopSymbolsByChurn(repoId, limit = 10) {
919
+ return stmt(`
920
+ WITH file_dirs AS (
921
+ SELECT
922
+ file_id,
923
+ CASE
924
+ WHEN instr(rel_path, '/') > 0
925
+ THEN substr(rel_path, 1, length(rel_path) - length(replace(rel_path, rtrim(rel_path, replace(rel_path, '/', '')), '')))
926
+ ELSE ''
927
+ END as directory
928
+ FROM files
929
+ WHERE repo_id = ?
930
+ )
931
+ SELECT
932
+ s.symbol_id,
933
+ s.name,
934
+ s.kind,
935
+ s.exported,
936
+ s.signature_json,
937
+ COALESCE(m.fan_in, 0) as fan_in,
938
+ COALESCE(m.fan_out, 0) as fan_out,
939
+ COALESCE(m.churn_30d, 0) as churn_30d,
940
+ COALESCE(fd.directory, '') as directory
941
+ FROM symbols s
942
+ LEFT JOIN metrics m ON s.symbol_id = m.symbol_id
943
+ LEFT JOIN file_dirs fd ON s.file_id = fd.file_id
944
+ WHERE s.repo_id = ? AND COALESCE(m.churn_30d, 0) > 0
945
+ ORDER BY COALESCE(m.churn_30d, 0) DESC
946
+ LIMIT ?
947
+ `).all(repoId, repoId, limit);
948
+ }
949
+ /**
950
+ * Gets files with most symbols.
951
+ *
952
+ * @param repoId - Repository identifier
953
+ * @param limit - Maximum number of files to return
954
+ * @returns Array of files ordered by symbol count descending
955
+ */
956
+ export function getFilesBySymbolCount(repoId, limit = 10) {
957
+ return stmt(`
958
+ SELECT
959
+ f.rel_path,
960
+ CASE
961
+ WHEN instr(f.rel_path, '/') > 0
962
+ THEN substr(f.rel_path, 1, length(f.rel_path) - length(replace(f.rel_path, rtrim(f.rel_path, replace(f.rel_path, '/', '')), '')))
963
+ ELSE ''
964
+ END as directory,
965
+ COUNT(s.symbol_id) as symbol_count,
966
+ 0 as edge_count
967
+ FROM files f
968
+ LEFT JOIN symbols s ON f.file_id = s.file_id
969
+ WHERE f.repo_id = ?
970
+ GROUP BY f.file_id
971
+ ORDER BY symbol_count DESC
972
+ LIMIT ?
973
+ `).all(repoId, limit);
974
+ }
975
+ /**
976
+ * Gets files with most edges (highest connectivity).
977
+ *
978
+ * @param repoId - Repository identifier
979
+ * @param limit - Maximum number of files to return
980
+ * @returns Array of files ordered by edge count descending
981
+ */
982
+ export function getFilesByEdgeCount(repoId, limit = 10) {
983
+ return stmt(`
984
+ WITH file_edges AS (
985
+ SELECT
986
+ s.file_id,
987
+ COUNT(e.edge_id) as edge_count
988
+ FROM symbols s
989
+ LEFT JOIN edges e ON s.symbol_id = e.from_symbol_id OR s.symbol_id = e.to_symbol_id
990
+ WHERE s.repo_id = ?
991
+ GROUP BY s.file_id
992
+ )
993
+ SELECT
994
+ f.rel_path,
995
+ CASE
996
+ WHEN instr(f.rel_path, '/') > 0
997
+ THEN substr(f.rel_path, 1, length(f.rel_path) - length(replace(f.rel_path, rtrim(f.rel_path, replace(f.rel_path, '/', '')), '')))
998
+ ELSE ''
999
+ END as directory,
1000
+ 0 as symbol_count,
1001
+ COALESCE(fe.edge_count, 0) as edge_count
1002
+ FROM files f
1003
+ LEFT JOIN file_edges fe ON f.file_id = fe.file_id
1004
+ WHERE f.repo_id = ?
1005
+ ORDER BY edge_count DESC
1006
+ LIMIT ?
1007
+ `).all(repoId, repoId, limit);
1008
+ }
1009
+ /**
1010
+ * Gets aggregate edge counts by type for a repository.
1011
+ *
1012
+ * @param repoId - Repository identifier
1013
+ * @returns Object with counts per edge type
1014
+ */
1015
+ export function getEdgeCountsByType(repoId) {
1016
+ const rows = stmt(`
1017
+ SELECT type, COUNT(*) as count
1018
+ FROM edges
1019
+ WHERE repo_id = ?
1020
+ GROUP BY type
1021
+ `).all(repoId);
1022
+ const result = { call: 0, import: 0, config: 0 };
1023
+ for (const row of rows) {
1024
+ if (row.type === "call")
1025
+ result.call = row.count;
1026
+ else if (row.type === "import")
1027
+ result.import = row.count;
1028
+ else if (row.type === "config")
1029
+ result.config = row.count;
1030
+ }
1031
+ return result;
1032
+ }
1033
+ /**
1034
+ * Gets total counts for files, symbols, and edges in a repository.
1035
+ *
1036
+ * @param repoId - Repository identifier
1037
+ * @returns Object with total counts
1038
+ */
1039
+ export function getRepoTotals(repoId) {
1040
+ const row = stmt(`
1041
+ SELECT
1042
+ (SELECT COUNT(*) FROM files WHERE repo_id = ?) as file_count,
1043
+ (SELECT COUNT(*) FROM symbols WHERE repo_id = ?) as symbol_count,
1044
+ (SELECT COUNT(*) FROM edges WHERE repo_id = ?) as edge_count,
1045
+ (SELECT COUNT(*) FROM symbols WHERE repo_id = ? AND exported = 1) as exported_count
1046
+ `).get(repoId, repoId, repoId, repoId);
1047
+ return {
1048
+ fileCount: row.file_count,
1049
+ symbolCount: row.symbol_count,
1050
+ edgeCount: row.edge_count,
1051
+ exportedCount: row.exported_count,
1052
+ };
1053
+ }
1054
+ //# sourceMappingURL=queries.js.map