homegraph 1.1.2 → 1.2.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 (361) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +268 -243
  3. package/dist/arkts/ohos-api-index.d.ts +15 -0
  4. package/dist/arkts/ohos-api-index.d.ts.map +1 -0
  5. package/dist/arkts/ohos-api-index.js +190 -0
  6. package/dist/arkts/ohos-api-index.js.map +1 -0
  7. package/dist/arkts/ohos-sdk-input.d.ts +36 -0
  8. package/dist/arkts/ohos-sdk-input.d.ts.map +1 -0
  9. package/dist/arkts/ohos-sdk-input.js +214 -0
  10. package/dist/arkts/ohos-sdk-input.js.map +1 -0
  11. package/dist/bin/command-supervision.d.ts +12 -0
  12. package/dist/bin/command-supervision.d.ts.map +1 -0
  13. package/dist/bin/command-supervision.js +86 -0
  14. package/dist/bin/command-supervision.js.map +1 -0
  15. package/dist/bin/homegraph.d.ts +1 -1
  16. package/dist/bin/homegraph.js +971 -71
  17. package/dist/bin/homegraph.js.map +1 -1
  18. package/dist/db/index.d.ts +20 -0
  19. package/dist/db/index.d.ts.map +1 -1
  20. package/dist/db/index.js +39 -0
  21. package/dist/db/index.js.map +1 -1
  22. package/dist/db/migrations.d.ts +1 -1
  23. package/dist/db/migrations.d.ts.map +1 -1
  24. package/dist/db/migrations.js +58 -19
  25. package/dist/db/migrations.js.map +1 -1
  26. package/dist/db/queries.d.ts +14 -0
  27. package/dist/db/queries.d.ts.map +1 -1
  28. package/dist/db/queries.js +314 -143
  29. package/dist/db/queries.js.map +1 -1
  30. package/dist/db/schema.sql +172 -152
  31. package/dist/directory.d.ts +32 -0
  32. package/dist/directory.d.ts.map +1 -1
  33. package/dist/directory.js +88 -5
  34. package/dist/directory.js.map +1 -1
  35. package/dist/extraction/arkts-batch-worker.d.ts +2 -0
  36. package/dist/extraction/arkts-batch-worker.d.ts.map +1 -0
  37. package/dist/extraction/arkts-batch-worker.js +28 -0
  38. package/dist/extraction/arkts-batch-worker.js.map +1 -0
  39. package/dist/extraction/context.d.ts +11 -0
  40. package/dist/extraction/context.d.ts.map +1 -1
  41. package/dist/extraction/context.js +20 -0
  42. package/dist/extraction/context.js.map +1 -1
  43. package/dist/extraction/index.d.ts +16 -2
  44. package/dist/extraction/index.d.ts.map +1 -1
  45. package/dist/extraction/index.js +619 -380
  46. package/dist/extraction/index.js.map +1 -1
  47. package/dist/extraction/languages/arkts-state-decorators.d.ts +13 -0
  48. package/dist/extraction/languages/arkts-state-decorators.d.ts.map +1 -0
  49. package/dist/extraction/languages/arkts-state-decorators.js +26 -0
  50. package/dist/extraction/languages/arkts-state-decorators.js.map +1 -0
  51. package/dist/extraction/languages/arkts-viewtree.d.ts +4 -2
  52. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
  53. package/dist/extraction/languages/arkts-viewtree.js +21 -6
  54. package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
  55. package/dist/extraction/languages/arkts.d.ts +98 -2
  56. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  57. package/dist/extraction/languages/arkts.js +1290 -61
  58. package/dist/extraction/languages/arkts.js.map +1 -1
  59. package/dist/extraction/languages/c-cpp.d.ts +56 -0
  60. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  61. package/dist/extraction/languages/c-cpp.js +198 -1
  62. package/dist/extraction/languages/c-cpp.js.map +1 -1
  63. package/dist/extraction/languages/ohos-api-consumer.d.ts +34 -0
  64. package/dist/extraction/languages/ohos-api-consumer.d.ts.map +1 -0
  65. package/dist/extraction/languages/ohos-api-consumer.js +283 -0
  66. package/dist/extraction/languages/ohos-api-consumer.js.map +1 -0
  67. package/dist/extraction/parse-pool.d.ts +126 -0
  68. package/dist/extraction/parse-pool.d.ts.map +1 -0
  69. package/dist/extraction/parse-pool.js +319 -0
  70. package/dist/extraction/parse-pool.js.map +1 -0
  71. package/dist/extraction/tree-sitter-types.d.ts +17 -0
  72. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  73. package/dist/extraction/tree-sitter.d.ts +21 -0
  74. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  75. package/dist/extraction/tree-sitter.js +198 -27
  76. package/dist/extraction/tree-sitter.js.map +1 -1
  77. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  78. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  79. package/dist/graph/traversal.d.ts.map +1 -1
  80. package/dist/graph/traversal.js +76 -17
  81. package/dist/graph/traversal.js.map +1 -1
  82. package/dist/index.d.ts +25 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +78 -4
  85. package/dist/index.js.map +1 -1
  86. package/dist/installer/instructions-template.js +9 -9
  87. package/dist/installer/targets/shared.d.ts +5 -6
  88. package/dist/installer/targets/shared.d.ts.map +1 -1
  89. package/dist/installer/targets/shared.js +5 -6
  90. package/dist/installer/targets/shared.js.map +1 -1
  91. package/dist/mcp/daemon-paths.d.ts +30 -3
  92. package/dist/mcp/daemon-paths.d.ts.map +1 -1
  93. package/dist/mcp/daemon-paths.js +50 -10
  94. package/dist/mcp/daemon-paths.js.map +1 -1
  95. package/dist/mcp/daemon-registry.d.ts.map +1 -1
  96. package/dist/mcp/daemon-registry.js +7 -3
  97. package/dist/mcp/daemon-registry.js.map +1 -1
  98. package/dist/mcp/daemon.d.ts +48 -0
  99. package/dist/mcp/daemon.d.ts.map +1 -1
  100. package/dist/mcp/daemon.js +196 -32
  101. package/dist/mcp/daemon.js.map +1 -1
  102. package/dist/mcp/engine.d.ts +17 -0
  103. package/dist/mcp/engine.d.ts.map +1 -1
  104. package/dist/mcp/engine.js +73 -1
  105. package/dist/mcp/engine.js.map +1 -1
  106. package/dist/mcp/index.d.ts.map +1 -1
  107. package/dist/mcp/index.js +25 -43
  108. package/dist/mcp/index.js.map +1 -1
  109. package/dist/mcp/liveness-watchdog.js +16 -16
  110. package/dist/mcp/ppid-watchdog.d.ts +18 -0
  111. package/dist/mcp/ppid-watchdog.d.ts.map +1 -1
  112. package/dist/mcp/ppid-watchdog.js +37 -0
  113. package/dist/mcp/ppid-watchdog.js.map +1 -1
  114. package/dist/mcp/query-cache.d.ts +25 -0
  115. package/dist/mcp/query-cache.d.ts.map +1 -0
  116. package/dist/mcp/query-cache.js +191 -0
  117. package/dist/mcp/query-cache.js.map +1 -0
  118. package/dist/mcp/query-pool.d.ts +94 -0
  119. package/dist/mcp/query-pool.d.ts.map +1 -0
  120. package/dist/mcp/query-pool.js +297 -0
  121. package/dist/mcp/query-pool.js.map +1 -0
  122. package/dist/mcp/query-worker.d.ts +24 -0
  123. package/dist/mcp/query-worker.d.ts.map +1 -0
  124. package/dist/mcp/query-worker.js +87 -0
  125. package/dist/mcp/query-worker.js.map +1 -0
  126. package/dist/mcp/server-instructions.d.ts +5 -7
  127. package/dist/mcp/server-instructions.d.ts.map +1 -1
  128. package/dist/mcp/server-instructions.js +72 -74
  129. package/dist/mcp/server-instructions.js.map +1 -1
  130. package/dist/mcp/tools.d.ts +94 -4
  131. package/dist/mcp/tools.d.ts.map +1 -1
  132. package/dist/mcp/tools.js +877 -71
  133. package/dist/mcp/tools.js.map +1 -1
  134. package/dist/project-config.d.ts +20 -0
  135. package/dist/project-config.d.ts.map +1 -1
  136. package/dist/project-config.js +42 -2
  137. package/dist/project-config.js.map +1 -1
  138. package/dist/reasoning/login.js +1 -1
  139. package/dist/reasoning/login.js.map +1 -1
  140. package/dist/reasoning/reasoner.js +32 -32
  141. package/dist/resolution/c-fnptr-synthesizer.d.ts +0 -28
  142. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  143. package/dist/resolution/c-fnptr-synthesizer.js +765 -79
  144. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  145. package/dist/resolution/callback-synthesizer.d.ts +1 -1
  146. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  147. package/dist/resolution/callback-synthesizer.js +72 -11
  148. package/dist/resolution/callback-synthesizer.js.map +1 -1
  149. package/dist/resolution/cooperative-yield.d.ts +32 -0
  150. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  151. package/dist/resolution/cooperative-yield.js +42 -0
  152. package/dist/resolution/cooperative-yield.js.map +1 -0
  153. package/dist/resolution/index.d.ts +11 -2
  154. package/dist/resolution/index.d.ts.map +1 -1
  155. package/dist/resolution/index.js +72 -4
  156. package/dist/resolution/index.js.map +1 -1
  157. package/dist/resolution/name-matcher.d.ts +22 -0
  158. package/dist/resolution/name-matcher.d.ts.map +1 -1
  159. package/dist/resolution/name-matcher.js +317 -20
  160. package/dist/resolution/name-matcher.js.map +1 -1
  161. package/dist/spec/config.d.ts +39 -0
  162. package/dist/spec/config.d.ts.map +1 -0
  163. package/dist/spec/config.js +304 -0
  164. package/dist/spec/config.js.map +1 -0
  165. package/dist/spec/db/commit-node.d.ts +23 -0
  166. package/dist/spec/db/commit-node.d.ts.map +1 -0
  167. package/dist/spec/db/commit-node.js +62 -0
  168. package/dist/spec/db/commit-node.js.map +1 -0
  169. package/dist/spec/db/fragment-node.d.ts +24 -0
  170. package/dist/spec/db/fragment-node.d.ts.map +1 -0
  171. package/dist/spec/db/fragment-node.js +128 -0
  172. package/dist/spec/db/fragment-node.js.map +1 -0
  173. package/dist/spec/db/fts.d.ts +74 -0
  174. package/dist/spec/db/fts.d.ts.map +1 -0
  175. package/dist/spec/db/fts.js +324 -0
  176. package/dist/spec/db/fts.js.map +1 -0
  177. package/dist/spec/db/index.d.ts +13 -0
  178. package/dist/spec/db/index.d.ts.map +1 -0
  179. package/dist/spec/db/index.js +50 -0
  180. package/dist/spec/db/index.js.map +1 -0
  181. package/dist/spec/db/relations.d.ts +55 -0
  182. package/dist/spec/db/relations.d.ts.map +1 -0
  183. package/dist/spec/db/relations.js +158 -0
  184. package/dist/spec/db/relations.js.map +1 -0
  185. package/dist/spec/db/schema.d.ts +33 -0
  186. package/dist/spec/db/schema.d.ts.map +1 -0
  187. package/dist/spec/db/schema.js +119 -0
  188. package/dist/spec/db/schema.js.map +1 -0
  189. package/dist/spec/db/schema.sql +117 -0
  190. package/dist/spec/db/spec-node.d.ts +41 -0
  191. package/dist/spec/db/spec-node.d.ts.map +1 -0
  192. package/dist/spec/db/spec-node.js +114 -0
  193. package/dist/spec/db/spec-node.js.map +1 -0
  194. package/dist/spec/evolve/impact-locator.d.ts +13 -0
  195. package/dist/spec/evolve/impact-locator.d.ts.map +1 -0
  196. package/dist/spec/evolve/impact-locator.js +25 -0
  197. package/dist/spec/evolve/impact-locator.js.map +1 -0
  198. package/dist/spec/evolve/llm-client.d.ts +50 -0
  199. package/dist/spec/evolve/llm-client.d.ts.map +1 -0
  200. package/dist/spec/evolve/llm-client.js +176 -0
  201. package/dist/spec/evolve/llm-client.js.map +1 -0
  202. package/dist/spec/evolve/logic-checker.d.ts +12 -0
  203. package/dist/spec/evolve/logic-checker.d.ts.map +1 -0
  204. package/dist/spec/evolve/logic-checker.js +24 -0
  205. package/dist/spec/evolve/logic-checker.js.map +1 -0
  206. package/dist/spec/evolve/pipeline.d.ts +42 -0
  207. package/dist/spec/evolve/pipeline.d.ts.map +1 -0
  208. package/dist/spec/evolve/pipeline.js +567 -0
  209. package/dist/spec/evolve/pipeline.js.map +1 -0
  210. package/dist/spec/evolve/spec-rewriter.d.ts +42 -0
  211. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -0
  212. package/dist/spec/evolve/spec-rewriter.js +230 -0
  213. package/dist/spec/evolve/spec-rewriter.js.map +1 -0
  214. package/dist/spec/graph/queries.d.ts +155 -0
  215. package/dist/spec/graph/queries.d.ts.map +1 -0
  216. package/dist/spec/graph/queries.js +440 -0
  217. package/dist/spec/graph/queries.js.map +1 -0
  218. package/dist/spec/llm/client.d.ts +29 -0
  219. package/dist/spec/llm/client.d.ts.map +1 -0
  220. package/dist/spec/llm/client.js +123 -0
  221. package/dist/spec/llm/client.js.map +1 -0
  222. package/dist/spec/llm/index.d.ts +3 -0
  223. package/dist/spec/llm/index.d.ts.map +1 -0
  224. package/dist/spec/llm/index.js +11 -0
  225. package/dist/spec/llm/index.js.map +1 -0
  226. package/dist/spec/llm/prompts.d.ts +13 -0
  227. package/dist/spec/llm/prompts.d.ts.map +1 -0
  228. package/dist/spec/llm/prompts.js +75 -0
  229. package/dist/spec/llm/prompts.js.map +1 -0
  230. package/dist/spec/mining/diff-parser.d.ts +33 -0
  231. package/dist/spec/mining/diff-parser.d.ts.map +1 -0
  232. package/dist/spec/mining/diff-parser.js +166 -0
  233. package/dist/spec/mining/diff-parser.js.map +1 -0
  234. package/dist/spec/mining/git-scanner.d.ts +103 -0
  235. package/dist/spec/mining/git-scanner.d.ts.map +1 -0
  236. package/dist/spec/mining/git-scanner.js +307 -0
  237. package/dist/spec/mining/git-scanner.js.map +1 -0
  238. package/dist/spec/mining/pipeline.d.ts +53 -0
  239. package/dist/spec/mining/pipeline.d.ts.map +1 -0
  240. package/dist/spec/mining/pipeline.js +178 -0
  241. package/dist/spec/mining/pipeline.js.map +1 -0
  242. package/dist/spec/mining/scope-resolver.d.ts +45 -0
  243. package/dist/spec/mining/scope-resolver.d.ts.map +1 -0
  244. package/dist/spec/mining/scope-resolver.js +103 -0
  245. package/dist/spec/mining/scope-resolver.js.map +1 -0
  246. package/dist/spec/mining/spec-extractor.d.ts +69 -0
  247. package/dist/spec/mining/spec-extractor.d.ts.map +1 -0
  248. package/dist/spec/mining/spec-extractor.js +369 -0
  249. package/dist/spec/mining/spec-extractor.js.map +1 -0
  250. package/dist/spec/types.d.ts +149 -0
  251. package/dist/spec/types.d.ts.map +1 -0
  252. package/dist/spec/types.js +15 -0
  253. package/dist/spec/types.js.map +1 -0
  254. package/dist/spec/utils.d.ts +167 -0
  255. package/dist/spec/utils.d.ts.map +1 -0
  256. package/dist/spec/utils.js +463 -0
  257. package/dist/spec/utils.js.map +1 -0
  258. package/dist/sync/worktree.d.ts +9 -0
  259. package/dist/sync/worktree.d.ts.map +1 -1
  260. package/dist/sync/worktree.js +40 -0
  261. package/dist/sync/worktree.js.map +1 -1
  262. package/dist/types.d.ts +6 -1
  263. package/dist/types.d.ts.map +1 -1
  264. package/dist/ui/shimmer-progress.d.ts +2 -0
  265. package/dist/ui/shimmer-progress.d.ts.map +1 -1
  266. package/dist/ui/shimmer-progress.js +19 -2
  267. package/dist/ui/shimmer-progress.js.map +1 -1
  268. package/dist/upgrade/index.js +1 -1
  269. package/dist/upgrade/index.js.map +1 -1
  270. package/package.json +58 -57
  271. package/scripts/add-lang/bench.sh +60 -60
  272. package/scripts/add-lang/check-grammar.mjs +75 -75
  273. package/scripts/add-lang/dump-ast.mjs +103 -103
  274. package/scripts/add-lang/verify-extraction.mjs +70 -70
  275. package/scripts/agent-eval/ab-adoption.sh +91 -91
  276. package/scripts/agent-eval/ab-hook.sh +86 -86
  277. package/scripts/agent-eval/ab-impl.sh +78 -78
  278. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  279. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  280. package/scripts/agent-eval/arms-F.sh +21 -21
  281. package/scripts/agent-eval/arms-matrix.sh +37 -37
  282. package/scripts/agent-eval/audit.sh +68 -68
  283. package/scripts/agent-eval/bench-readme.sh +28 -28
  284. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  285. package/scripts/agent-eval/block-read-hook.sh +19 -19
  286. package/scripts/agent-eval/hook-settings.json +15 -15
  287. package/scripts/agent-eval/itrun.sh +120 -120
  288. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  289. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  290. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  291. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  292. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  293. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  294. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  295. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  296. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  297. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  298. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  299. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  300. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  301. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  302. package/scripts/agent-eval/offload-eval.md +76 -76
  303. package/scripts/agent-eval/parse-arms.mjs +116 -116
  304. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  305. package/scripts/agent-eval/parse-run.mjs +45 -45
  306. package/scripts/agent-eval/parse-session.mjs +93 -93
  307. package/scripts/agent-eval/probe-context.mjs +21 -21
  308. package/scripts/agent-eval/probe-explore.mjs +40 -40
  309. package/scripts/agent-eval/probe-node.mjs +20 -20
  310. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  311. package/scripts/agent-eval/probe-trace.mjs +20 -20
  312. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  313. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  314. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  315. package/scripts/agent-eval/run-agent.sh +34 -34
  316. package/scripts/agent-eval/run-all.sh +69 -69
  317. package/scripts/agent-eval/run-arms.sh +56 -56
  318. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  319. package/scripts/build-bundle.sh +118 -118
  320. package/scripts/exp_boundary_eval/README.md +247 -0
  321. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  322. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  323. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
  324. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  325. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  326. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  327. package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -0
  328. package/scripts/exp_boundary_eval/_test_stdin.py +8 -0
  329. package/scripts/exp_boundary_eval/_utils.py +1116 -0
  330. package/scripts/exp_boundary_eval/analyze.py +1313 -0
  331. package/scripts/exp_boundary_eval/data/agents.json +109 -0
  332. package/scripts/exp_boundary_eval/data/experiments.json +140 -0
  333. package/scripts/exp_boundary_eval/deveco_arm.py +519 -0
  334. package/scripts/exp_boundary_eval/run_all.py +378 -0
  335. package/scripts/exp_boundary_eval/run_one.py +165 -0
  336. package/scripts/exp_boundary_eval/run_session.py +158 -0
  337. package/scripts/exp_boundary_eval/setup.py +120 -0
  338. package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -0
  339. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -0
  340. package/scripts/exp_boundary_eval/win_node_launcher.py +24 -0
  341. package/scripts/extract-release-notes.mjs +130 -130
  342. package/scripts/local-install.sh +41 -41
  343. package/scripts/npm-sdk.js +75 -75
  344. package/scripts/npm-shim.js +268 -246
  345. package/scripts/ohos-sdk-publish.mjs +133 -0
  346. package/scripts/pack-npm.sh +119 -119
  347. package/scripts/prepare-release.mjs +270 -270
  348. package/scripts/qa_eval/README.md +407 -404
  349. package/scripts/qa_eval/_test_deveco_probe.py +41 -41
  350. package/scripts/qa_eval/agent_runner.py +526 -526
  351. package/scripts/qa_eval/data/.gitignore +4 -4
  352. package/scripts/qa_eval/data/test-set.jsonl +2 -22
  353. package/scripts/qa_eval/eval_metrics.py +274 -233
  354. package/scripts/qa_eval/external_agent.py +976 -671
  355. package/scripts/qa_eval/llm_config.py +92 -92
  356. package/scripts/qa_eval/memory_monitor.py +132 -132
  357. package/scripts/qa_eval/my_answer_accuracy.py +187 -187
  358. package/scripts/qa_eval/requirements.txt +2 -2
  359. package/scripts/qa_eval/run_pipeline.py +804 -711
  360. package/scripts/qa_eval/stats_efficiency.py +279 -279
  361. package/scripts/qa_eval/stats_scores.py +207 -207
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * Relation CRUD — persistence operations for the three relation tables:
4
+ *
5
+ * - ``spec_commit_relations`` (Spec ↔ Commit)
6
+ * - ``commit_fragment_relations`` (Commit ↔ CodeFragment)
7
+ * - ``spec_spec_relations`` (Spec ↔ Spec)
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.insertSpecCommitRelation = insertSpecCommitRelation;
11
+ exports.findCommitsBySpec = findCommitsBySpec;
12
+ exports.transferSpecCommitRelations = transferSpecCommitRelations;
13
+ exports.insertCommitFragmentRelation = insertCommitFragmentRelation;
14
+ exports.insertSpecSpecRelation = insertSpecSpecRelation;
15
+ exports.deleteSimilarToRelations = deleteSimilarToRelations;
16
+ exports.transferSpecSpecRelations = transferSpecSpecRelations;
17
+ exports.countAllRelations = countAllRelations;
18
+ // ===========================================================================
19
+ // Spec ↔ Commit Relations
20
+ // ===========================================================================
21
+ /**
22
+ * Insert a relation between a Spec and a Commit.
23
+ * `INSERT OR IGNORE` — duplicates are silently skipped.
24
+ */
25
+ function insertSpecCommitRelation(db, specId, commitHash, relationType) {
26
+ db.prepare(`
27
+ INSERT OR IGNORE INTO spec_commit_relations
28
+ (spec_id, commit_hash, relation_type)
29
+ VALUES (@specId, @commitHash, @relationType)
30
+ `).run({ specId, commitHash, relationType });
31
+ }
32
+ /**
33
+ * Find all commits linked to a spec, ordered by commit timestamp
34
+ * (oldest first — matches Commit4Spec's mining pipeline sort).
35
+ */
36
+ function findCommitsBySpec(db, specId) {
37
+ const rows = db.prepare(`
38
+ SELECT r.commit_hash, r.relation_type,
39
+ c.message, c.author, c.timestamp
40
+ FROM spec_commit_relations r
41
+ JOIN commit_nodes c ON c.hash = r.commit_hash
42
+ WHERE r.spec_id = ?
43
+ ORDER BY c.timestamp ASC
44
+ `).all(specId);
45
+ return rows.map(r => ({
46
+ specId,
47
+ commitHash: r.commit_hash,
48
+ relationType: r.relation_type,
49
+ message: r.message,
50
+ author: r.author,
51
+ timestamp: r.timestamp,
52
+ }));
53
+ }
54
+ /**
55
+ * Transfer all spec–commit relations from one spec to another.
56
+ * Used during self-evolve when a spec is versioned:
57
+ * old active spec's relations move to the deprecated record.
58
+ */
59
+ function transferSpecCommitRelations(db, fromSpecId, toSpecId) {
60
+ db.prepare(`
61
+ UPDATE spec_commit_relations
62
+ SET spec_id = @toSpecId
63
+ WHERE spec_id = @fromSpecId
64
+ `).run({ fromSpecId, toSpecId });
65
+ }
66
+ // ===========================================================================
67
+ // Commit ↔ CodeFragment Relations
68
+ // ===========================================================================
69
+ /**
70
+ * Link a commit to a code fragment.
71
+ * `INSERT OR IGNORE` — duplicates are silently skipped.
72
+ */
73
+ function insertCommitFragmentRelation(db, commitHash, fragmentId) {
74
+ db.prepare(`
75
+ INSERT OR IGNORE INTO commit_fragment_relations
76
+ (commit_hash, fragment_id)
77
+ VALUES (@commitHash, @fragmentId)
78
+ `).run({ commitHash, fragmentId });
79
+ }
80
+ // ===========================================================================
81
+ // Spec ↔ Spec Relations
82
+ // ===========================================================================
83
+ /**
84
+ * Insert a relation between two specs (SIMILAR_TO or EVOLVED_FROM).
85
+ * `INSERT OR IGNORE` — duplicates are silently skipped.
86
+ */
87
+ function insertSpecSpecRelation(db, sourceId, targetId, relationType) {
88
+ db.prepare(`
89
+ INSERT OR IGNORE INTO spec_spec_relations
90
+ (source_id, target_id, relation_type)
91
+ VALUES (@sourceId, @targetId, @relationType)
92
+ `).run({ sourceId, targetId, relationType });
93
+ }
94
+ /**
95
+ * Remove all SIMILAR_TO relations involving a spec.
96
+ * Called when a spec is deprecated (similarity links become stale).
97
+ */
98
+ function deleteSimilarToRelations(db, specId) {
99
+ db.prepare(`
100
+ DELETE FROM spec_spec_relations
101
+ WHERE relation_type = 'SIMILAR_TO'
102
+ AND (source_id = ? OR target_id = ?)
103
+ `).run(specId, specId);
104
+ }
105
+ /**
106
+ * Transfer all spec–spec relations from one spec to another.
107
+ * Used during self-evolve versioning (old spec's relations move to
108
+ * the deprecated record).
109
+ */
110
+ function transferSpecSpecRelations(db, fromSpecId, toSpecId) {
111
+ // No transaction wrapper — callers (e.g. applyUpdate) manage
112
+ // their own explicit BEGIN/COMMIT boundaries.
113
+ // Delete rows at `toSpecId` that would collide with the rows being
114
+ // transferred, so the UPDATE below cannot trigger a PRIMARY KEY conflict.
115
+ db.prepare(`
116
+ DELETE FROM spec_spec_relations
117
+ WHERE source_id = @toSpecId
118
+ AND (target_id, relation_type) IN (
119
+ SELECT target_id, relation_type FROM spec_spec_relations
120
+ WHERE source_id = @fromSpecId
121
+ )
122
+ `).run({ fromSpecId, toSpecId });
123
+ db.prepare(`
124
+ DELETE FROM spec_spec_relations
125
+ WHERE target_id = @toSpecId
126
+ AND (source_id, relation_type) IN (
127
+ SELECT source_id, relation_type FROM spec_spec_relations
128
+ WHERE target_id = @fromSpecId
129
+ )
130
+ `).run({ fromSpecId, toSpecId });
131
+ db.prepare(`
132
+ UPDATE spec_spec_relations SET source_id = @toSpecId WHERE source_id = @fromSpecId
133
+ `).run({ fromSpecId, toSpecId });
134
+ db.prepare(`
135
+ UPDATE spec_spec_relations SET target_id = @toSpecId WHERE target_id = @fromSpecId
136
+ `).run({ fromSpecId, toSpecId });
137
+ }
138
+ // ===========================================================================
139
+ // Stats
140
+ // ===========================================================================
141
+ /**
142
+ * Count total rows across all three relation tables.
143
+ */
144
+ function countAllRelations(db) {
145
+ let total = 0;
146
+ for (const table of [
147
+ 'spec_commit_relations',
148
+ 'commit_fragment_relations',
149
+ 'spec_spec_relations',
150
+ ]) {
151
+ const row = db
152
+ .prepare(`SELECT COUNT(*) as cnt FROM ${table}`)
153
+ .get();
154
+ total += row?.cnt ?? 0;
155
+ }
156
+ return total;
157
+ }
158
+ //# sourceMappingURL=relations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relations.js","sourceRoot":"","sources":["../../../src/spec/db/relations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Spec Schema — DDL Initialisation
3
+ *
4
+ * Reads `schema.sql` and executes all statements idempotently
5
+ * (`CREATE IF NOT EXISTS`). Follows the same pattern as HomeGraph's
6
+ * `DatabaseConnection.initialize()` in `src/db/index.ts`.
7
+ */
8
+ import { SqliteDatabase } from '../../db/sqlite-adapter';
9
+ /**
10
+ * The latest schema version this module knows about.
11
+ * Bump this when adding migrations.
12
+ */
13
+ export declare const CURRENT_SPEC_SCHEMA_VERSION = 2;
14
+ /**
15
+ * Execute all DDL statements from `schema.sql`.
16
+ *
17
+ * Idempotent — can be called multiple times safely (every statement
18
+ * uses `CREATE IF NOT EXISTS`).
19
+ */
20
+ export declare function initSpecSchema(db: SqliteDatabase): void;
21
+ /**
22
+ * Get the current spec schema version from the database.
23
+ * Returns 0 if the table doesn't exist yet.
24
+ */
25
+ export declare function getCurrentSpecVersion(db: SqliteDatabase): number;
26
+ /**
27
+ * Run pending migrations.
28
+ *
29
+ * v1 → v2: Create code_fragments_fts virtual table and populate it
30
+ * from existing code_fragment_nodes data.
31
+ */
32
+ export declare function runSpecMigrations(db: SqliteDatabase, fromVersion: number): void;
33
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/spec/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAIzD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,GAAG,IAAI,CAMvD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CAShE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAwC/E"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /**
3
+ * Spec Schema — DDL Initialisation
4
+ *
5
+ * Reads `schema.sql` and executes all statements idempotently
6
+ * (`CREATE IF NOT EXISTS`). Follows the same pattern as HomeGraph's
7
+ * `DatabaseConnection.initialize()` in `src/db/index.ts`.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.CURRENT_SPEC_SCHEMA_VERSION = void 0;
44
+ exports.initSpecSchema = initSpecSchema;
45
+ exports.getCurrentSpecVersion = getCurrentSpecVersion;
46
+ exports.runSpecMigrations = runSpecMigrations;
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ /**
50
+ * The latest schema version this module knows about.
51
+ * Bump this when adding migrations.
52
+ */
53
+ exports.CURRENT_SPEC_SCHEMA_VERSION = 2;
54
+ /**
55
+ * Execute all DDL statements from `schema.sql`.
56
+ *
57
+ * Idempotent — can be called multiple times safely (every statement
58
+ * uses `CREATE IF NOT EXISTS`).
59
+ */
60
+ function initSpecSchema(db) {
61
+ db.pragma('foreign_keys = ON');
62
+ const schemaPath = path.join(__dirname, 'schema.sql');
63
+ const schema = fs.readFileSync(schemaPath, 'utf-8');
64
+ db.exec(schema);
65
+ }
66
+ /**
67
+ * Get the current spec schema version from the database.
68
+ * Returns 0 if the table doesn't exist yet.
69
+ */
70
+ function getCurrentSpecVersion(db) {
71
+ try {
72
+ const row = db
73
+ .prepare('SELECT MAX(version) as version FROM spec_schema_versions')
74
+ .get();
75
+ return row?.version ?? 0;
76
+ }
77
+ catch {
78
+ return 0;
79
+ }
80
+ }
81
+ /**
82
+ * Run pending migrations.
83
+ *
84
+ * v1 → v2: Create code_fragments_fts virtual table and populate it
85
+ * from existing code_fragment_nodes data.
86
+ */
87
+ function runSpecMigrations(db, fromVersion) {
88
+ if (fromVersion < 2) {
89
+ // Create the FTS5 virtual table — the IF NOT EXISTS in schema.sql
90
+ // handles the case where DDL already ran, but we explicitly run it
91
+ // here for databases that existed before this migration was added.
92
+ db.exec(`
93
+ CREATE VIRTUAL TABLE IF NOT EXISTS code_fragments_fts USING fts5(
94
+ id,
95
+ file_path,
96
+ code_diff
97
+ );
98
+ `);
99
+ // Populate FTS from existing code_fragment_nodes data
100
+ const count = db.prepare('SELECT COUNT(*) as cnt FROM code_fragments_fts').get().cnt;
101
+ if (count === 0) {
102
+ const rows = db
103
+ .prepare('SELECT id, file_path, code_diff FROM code_fragment_nodes')
104
+ .all();
105
+ if (rows.length > 0) {
106
+ const insert = db.prepare('INSERT INTO code_fragments_fts (id, file_path, code_diff) VALUES (?, ?, ?)');
107
+ const insertMany = db.transaction((fragments) => {
108
+ for (const f of fragments) {
109
+ insert.run(f.id, f.file_path, f.code_diff);
110
+ }
111
+ });
112
+ insertMany(rows);
113
+ }
114
+ }
115
+ // Record migration
116
+ db.prepare("INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description) VALUES (2, strftime('%s', 'now') * 1000, 'Add code_fragments_fts for content-based fragment search')").run();
117
+ }
118
+ }
119
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/spec/db/schema.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBH,wCAMC;AAMD,sDASC;AAQD,8CAwCC;AApFD,uCAAyB;AACzB,2CAA6B;AAE7B;;;GAGG;AACU,QAAA,2BAA2B,GAAG,CAAC,CAAC;AAE7C;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,EAAkB;IAC/C,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAE/B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACpD,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,EAAkB;IACtD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE;aACX,OAAO,CAAC,0DAA0D,CAAC;aACnE,GAAG,EAA4C,CAAC;QACnD,OAAO,GAAG,EAAE,OAAO,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,EAAkB,EAAE,WAAmB;IACvE,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACpB,kEAAkE;QAClE,mEAAmE;QACnE,mEAAmE;QACnE,EAAE,CAAC,IAAI,CAAC;;;;;;KAMP,CAAC,CAAC;QAEH,sDAAsD;QACtD,MAAM,KAAK,GACT,EAAE,CAAC,OAAO,CAAC,gDAAgD,CAAC,CAAC,GAAG,EACjE,CAAC,GAAG,CAAC;QACN,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,EAAE;iBACZ,OAAO,CAAC,0DAA0D,CAAC;iBACnE,GAAG,EAAiE,CAAC;YAExE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CACvB,4EAA4E,CAC7E,CAAC;gBACF,MAAM,UAAU,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,SAAsE,EAAE,EAAE;oBAC3G,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;wBAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;oBAC7C,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,EAAE,CAAC,OAAO,CACR,oLAAoL,CACrL,CAAC,GAAG,EAAE,CAAC;IACV,CAAC;AACH,CAAC"}
@@ -0,0 +1,117 @@
1
+ -- Commit4Spec Schema for HomeGraph
2
+ -- Version 2
3
+ --
4
+ -- Independent tables that coexist alongside HomeGraph's `nodes`/`edges`
5
+ -- core graph. These tables form a three-layer Spec→Commit→CodeFragment
6
+ -- relationship model — a higher-level semantic overlay on the code graph.
7
+ --
8
+ -- FTS5 uses a standalone virtual table (not external content) because
9
+ -- Spec text needs CJK character-level segmentation before indexing.
10
+
11
+ -- =============================================================================
12
+ -- Entity Tables
13
+ -- =============================================================================
14
+
15
+ CREATE TABLE IF NOT EXISTS spec_nodes (
16
+ id TEXT PRIMARY KEY,
17
+ title TEXT NOT NULL,
18
+ subtitles TEXT NOT NULL, -- JSON array of markdown heading + preview
19
+ status TEXT NOT NULL DEFAULT 'active', -- 'active' | 'deprecated'
20
+ version INTEGER NOT NULL DEFAULT 1,
21
+ file_path TEXT NOT NULL,
22
+ timestamp INTEGER NOT NULL -- Unix epoch milliseconds
23
+ );
24
+
25
+ CREATE TABLE IF NOT EXISTS commit_nodes (
26
+ hash TEXT PRIMARY KEY, -- Full 40-char commit hash
27
+ message TEXT NOT NULL, -- First line of commit message
28
+ author TEXT NOT NULL,
29
+ timestamp INTEGER NOT NULL -- Unix epoch milliseconds
30
+ );
31
+
32
+ CREATE TABLE IF NOT EXISTS code_fragment_nodes (
33
+ id TEXT PRIMARY KEY, -- 12-char hex UUID prefix
34
+ change_type TEXT NOT NULL, -- 'ADD' | 'MODIFY' | 'DELETE'
35
+ file_path TEXT NOT NULL,
36
+ start_line INTEGER NOT NULL,
37
+ end_line INTEGER NOT NULL,
38
+ code_diff TEXT NOT NULL -- Unified diff text
39
+ );
40
+
41
+ -- =============================================================================
42
+ -- Relation Tables
43
+ -- =============================================================================
44
+
45
+ CREATE TABLE IF NOT EXISTS spec_commit_relations (
46
+ spec_id TEXT NOT NULL,
47
+ commit_hash TEXT NOT NULL,
48
+ relation_type TEXT NOT NULL, -- 'GENERATE' | 'SUMMARIZED_FROM'
49
+ PRIMARY KEY (spec_id, commit_hash, relation_type),
50
+ FOREIGN KEY (spec_id) REFERENCES spec_nodes(id) ON DELETE CASCADE,
51
+ FOREIGN KEY (commit_hash) REFERENCES commit_nodes(hash) ON DELETE CASCADE
52
+ );
53
+
54
+ CREATE TABLE IF NOT EXISTS commit_fragment_relations (
55
+ commit_hash TEXT NOT NULL,
56
+ fragment_id TEXT NOT NULL,
57
+ PRIMARY KEY (commit_hash, fragment_id),
58
+ FOREIGN KEY (commit_hash) REFERENCES commit_nodes(hash) ON DELETE CASCADE,
59
+ FOREIGN KEY (fragment_id) REFERENCES code_fragment_nodes(id) ON DELETE CASCADE
60
+ );
61
+
62
+ CREATE TABLE IF NOT EXISTS spec_spec_relations (
63
+ source_id TEXT NOT NULL,
64
+ target_id TEXT NOT NULL,
65
+ relation_type TEXT NOT NULL, -- 'SIMILAR_TO' | 'EVOLVED_FROM'
66
+ PRIMARY KEY (source_id, target_id, relation_type),
67
+ FOREIGN KEY (source_id) REFERENCES spec_nodes(id) ON DELETE CASCADE,
68
+ FOREIGN KEY (target_id) REFERENCES spec_nodes(id) ON DELETE CASCADE
69
+ );
70
+
71
+ -- =============================================================================
72
+ -- Full-Text Search (standalone — CJK-segmented on insert)
73
+ -- =============================================================================
74
+
75
+ CREATE VIRTUAL TABLE IF NOT EXISTS specs_fts USING fts5(
76
+ id,
77
+ title,
78
+ subtitles
79
+ );
80
+
81
+ CREATE VIRTUAL TABLE IF NOT EXISTS code_fragments_fts USING fts5(
82
+ id,
83
+ file_path,
84
+ code_diff
85
+ );
86
+
87
+ -- =============================================================================
88
+ -- Indexes
89
+ -- =============================================================================
90
+
91
+ CREATE INDEX IF NOT EXISTS idx_spec_nodes_status ON spec_nodes(status);
92
+ CREATE INDEX IF NOT EXISTS idx_spec_nodes_file_path ON spec_nodes(file_path);
93
+ CREATE INDEX IF NOT EXISTS idx_commit_nodes_timestamp ON commit_nodes(timestamp);
94
+ CREATE INDEX IF NOT EXISTS idx_code_fragment_file_path ON code_fragment_nodes(file_path);
95
+ CREATE INDEX IF NOT EXISTS idx_code_fragment_path_lines ON code_fragment_nodes(file_path, start_line, end_line);
96
+ CREATE INDEX IF NOT EXISTS idx_scr_spec_id ON spec_commit_relations(spec_id);
97
+ CREATE INDEX IF NOT EXISTS idx_scr_commit_hash ON spec_commit_relations(commit_hash);
98
+ CREATE INDEX IF NOT EXISTS idx_cfr_commit_hash ON commit_fragment_relations(commit_hash);
99
+ CREATE INDEX IF NOT EXISTS idx_cfr_fragment_id ON commit_fragment_relations(fragment_id);
100
+ CREATE INDEX IF NOT EXISTS idx_ssr_source ON spec_spec_relations(source_id);
101
+ CREATE INDEX IF NOT EXISTS idx_ssr_target ON spec_spec_relations(target_id);
102
+
103
+ -- =============================================================================
104
+ -- Schema Version
105
+ -- =============================================================================
106
+
107
+ CREATE TABLE IF NOT EXISTS spec_schema_versions (
108
+ version INTEGER PRIMARY KEY,
109
+ applied_at INTEGER NOT NULL,
110
+ description TEXT
111
+ );
112
+
113
+ INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description)
114
+ VALUES (1, strftime('%s', 'now') * 1000, 'Initial Commit4Spec schema');
115
+
116
+ INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description)
117
+ VALUES (2, strftime('%s', 'now') * 1000, 'Add code_fragments_fts for content-based fragment search');
@@ -0,0 +1,41 @@
1
+ /**
2
+ * SpecNode CRUD — persistence operations for ``spec_nodes``.
3
+ *
4
+ * Every insert also updates the standalone FTS5 index with CJK-segmented
5
+ * text (see `fts.ts` for the segmentation logic).
6
+ */
7
+ import { SqliteDatabase } from '../../db/sqlite-adapter';
8
+ import { SpecNode } from '../types';
9
+ /**
10
+ * Insert or replace a SpecNode. Also updates the standalone FTS5 index
11
+ * with CJK-segmented text.
12
+ */
13
+ export declare function insertSpecNode(db: SqliteDatabase, node: SpecNode): SpecNode;
14
+ /**
15
+ * Look up a SpecNode by primary key. Returns null when not found.
16
+ */
17
+ export declare function findSpecById(db: SqliteDatabase, specId: string): SpecNode | null;
18
+ /**
19
+ * Update the status of a Spec (e.g. mark as deprecated).
20
+ */
21
+ export declare function updateSpecStatus(db: SqliteDatabase, specId: string, status: SpecNode['status']): void;
22
+ /**
23
+ * Update the version field of a Spec.
24
+ */
25
+ export declare function updateSpecVersion(db: SqliteDatabase, specId: string, version: number): void;
26
+ /**
27
+ * Delete a Spec and its FTS5 entry.
28
+ */
29
+ export declare function deleteSpec(db: SqliteDatabase, specId: string): void;
30
+ /**
31
+ * List every spec, ordered by id.
32
+ */
33
+ export declare function listAllSpecs(db: SqliteDatabase): SpecNode[];
34
+ /**
35
+ * Count specs by status.
36
+ */
37
+ export declare function countSpecsByStatus(db: SqliteDatabase): {
38
+ active: number;
39
+ deprecated: number;
40
+ };
41
+ //# sourceMappingURL=spec-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-node.d.ts","sourceRoot":"","sources":["../../../src/spec/db/spec-node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AA2CpC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CA2B3E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAMhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,CAErG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3F;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,QAAQ,EAAE,CAK3D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAW7F"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ /**
3
+ * SpecNode CRUD — persistence operations for ``spec_nodes``.
4
+ *
5
+ * Every insert also updates the standalone FTS5 index with CJK-segmented
6
+ * text (see `fts.ts` for the segmentation logic).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.insertSpecNode = insertSpecNode;
10
+ exports.findSpecById = findSpecById;
11
+ exports.updateSpecStatus = updateSpecStatus;
12
+ exports.updateSpecVersion = updateSpecVersion;
13
+ exports.deleteSpec = deleteSpec;
14
+ exports.listAllSpecs = listAllSpecs;
15
+ exports.countSpecsByStatus = countSpecsByStatus;
16
+ const fts_1 = require("./fts");
17
+ // ---------------------------------------------------------------------------
18
+ // Helpers
19
+ // ---------------------------------------------------------------------------
20
+ function rowToSpec(row) {
21
+ let subtitles;
22
+ try {
23
+ subtitles = JSON.parse(row.subtitles || '[]');
24
+ }
25
+ catch {
26
+ subtitles = [];
27
+ }
28
+ return {
29
+ id: row.id,
30
+ title: row.title,
31
+ subtitles,
32
+ status: row.status,
33
+ version: row.version,
34
+ filePath: row.file_path,
35
+ timestamp: row.timestamp,
36
+ };
37
+ }
38
+ // ---------------------------------------------------------------------------
39
+ // Persistence
40
+ // ---------------------------------------------------------------------------
41
+ /**
42
+ * Insert or replace a SpecNode. Also updates the standalone FTS5 index
43
+ * with CJK-segmented text.
44
+ */
45
+ function insertSpecNode(db, node) {
46
+ const subtitlesJson = JSON.stringify(node.subtitles);
47
+ db.prepare(`
48
+ INSERT OR REPLACE INTO spec_nodes
49
+ (id, title, subtitles, status, version, file_path, timestamp)
50
+ VALUES (@id, @title, @subtitles, @status, @version, @filePath, @timestamp)
51
+ `).run({
52
+ id: node.id,
53
+ title: node.title,
54
+ subtitles: subtitlesJson,
55
+ status: node.status,
56
+ version: node.version,
57
+ filePath: node.filePath,
58
+ timestamp: node.timestamp,
59
+ });
60
+ // Update FTS5 index with CJK-segmented text
61
+ const segmentedTitle = (0, fts_1.segmentCjk)(node.title);
62
+ const segmentedSubtitles = (0, fts_1.segmentCjk)(subtitlesJson);
63
+ db.prepare('DELETE FROM specs_fts WHERE id = ?').run(node.id);
64
+ db.prepare('INSERT INTO specs_fts(id, title, subtitles) VALUES (?, ?, ?)').run(node.id, segmentedTitle, segmentedSubtitles);
65
+ return node;
66
+ }
67
+ /**
68
+ * Look up a SpecNode by primary key. Returns null when not found.
69
+ */
70
+ function findSpecById(db, specId) {
71
+ const row = db.prepare('SELECT id, title, subtitles, status, version, file_path, timestamp FROM spec_nodes WHERE id = ?').get(specId);
72
+ return row ? rowToSpec(row) : null;
73
+ }
74
+ /**
75
+ * Update the status of a Spec (e.g. mark as deprecated).
76
+ */
77
+ function updateSpecStatus(db, specId, status) {
78
+ db.prepare('UPDATE spec_nodes SET status = ? WHERE id = ?').run(status, specId);
79
+ }
80
+ /**
81
+ * Update the version field of a Spec.
82
+ */
83
+ function updateSpecVersion(db, specId, version) {
84
+ db.prepare('UPDATE spec_nodes SET version = ? WHERE id = ?').run(version, specId);
85
+ }
86
+ /**
87
+ * Delete a Spec and its FTS5 entry.
88
+ */
89
+ function deleteSpec(db, specId) {
90
+ db.prepare('DELETE FROM spec_nodes WHERE id = ?').run(specId);
91
+ db.prepare('DELETE FROM specs_fts WHERE id = ?').run(specId);
92
+ }
93
+ /**
94
+ * List every spec, ordered by id.
95
+ */
96
+ function listAllSpecs(db) {
97
+ const rows = db.prepare('SELECT id, title, subtitles, status, version, file_path, timestamp FROM spec_nodes ORDER BY id').all();
98
+ return rows.map(rowToSpec);
99
+ }
100
+ /**
101
+ * Count specs by status.
102
+ */
103
+ function countSpecsByStatus(db) {
104
+ const rows = db.prepare('SELECT status, COUNT(*) as cnt FROM spec_nodes GROUP BY status').all();
105
+ const counts = { active: 0, deprecated: 0 };
106
+ for (const row of rows) {
107
+ if (row.status === 'active')
108
+ counts.active = row.cnt;
109
+ else if (row.status === 'deprecated')
110
+ counts.deprecated = row.cnt;
111
+ }
112
+ return counts;
113
+ }
114
+ //# sourceMappingURL=spec-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-node.js","sourceRoot":"","sources":["../../../src/spec/db/spec-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { SqliteDatabase } from '../../db/sqlite-adapter';
2
+ /**
3
+ * Find specs affected by the given list of file paths.
4
+ *
5
+ * Each file path should already be clean (no `a/` or `b/` prefix) — paths
6
+ * sourced from `DiffFragment.filePath` via diff-parser already have prefixes
7
+ * stripped.
8
+ *
9
+ * Queries the spec knowledge graph for specs whose code fragments match the
10
+ * path, returns deduplicated, alphabetically sorted spec IDs.
11
+ */
12
+ export declare function locateAffectedSpecs(db: SqliteDatabase, filePaths: string[]): string[];
13
+ //# sourceMappingURL=impact-locator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact-locator.d.ts","sourceRoot":"","sources":["../../../src/spec/evolve/impact-locator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGzD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EAAE,GAClB,MAAM,EAAE,CAWV"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.locateAffectedSpecs = locateAffectedSpecs;
4
+ const queries_1 = require("../graph/queries");
5
+ /**
6
+ * Find specs affected by the given list of file paths.
7
+ *
8
+ * Each file path should already be clean (no `a/` or `b/` prefix) — paths
9
+ * sourced from `DiffFragment.filePath` via diff-parser already have prefixes
10
+ * stripped.
11
+ *
12
+ * Queries the spec knowledge graph for specs whose code fragments match the
13
+ * path, returns deduplicated, alphabetically sorted spec IDs.
14
+ */
15
+ function locateAffectedSpecs(db, filePaths) {
16
+ const specIds = new Set();
17
+ for (const fp of filePaths) {
18
+ const matches = (0, queries_1.findSpecsByFragmentPath)(db, fp);
19
+ for (const specId of matches) {
20
+ specIds.add(specId);
21
+ }
22
+ }
23
+ return Array.from(specIds).sort();
24
+ }
25
+ //# sourceMappingURL=impact-locator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact-locator.js","sourceRoot":"","sources":["../../../src/spec/evolve/impact-locator.ts"],"names":[],"mappings":";;AAaA,kDAcC;AA1BD,8CAA2D;AAE3D;;;;;;;;;GASG;AACH,SAAgB,mBAAmB,CACjC,EAAkB,EAClB,SAAmB;IAEnB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAA,iCAAuB,EAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AACpC,CAAC"}