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,307 @@
1
+ "use strict";
2
+ /**
3
+ * Git commit history scanning and spec↔commit pairing.
4
+ *
5
+ * Replaces `commit4spec/reverse_engineer/git_scanner.py` and
6
+ * `commit4spec/reverse_engineer/git_utils.py`. Discovers spec↔commit pairs via
7
+ * two strategies:
8
+ *
9
+ * - **Strategy A — commit message scope:** extract conventional-commit scopes
10
+ * from commit messages and resolve them to spec IDs on disk.
11
+ * - **Strategy B — commit-info.md:** discover specs on disk, read their
12
+ * `commit-info.md` for linked commit hashes, and verify those commits exist.
13
+ *
14
+ * All Git operations use `execFileSync` with an args array (never template
15
+ * strings) to avoid shell injection risks — matching the HomeGraph convention
16
+ * in `src/sync/git-hooks.ts` and `src/sync/worktree.ts`.
17
+ *
18
+ * @module spec/mining/git-scanner
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.isGitRepo = isGitRepo;
22
+ exports.getAllCommits = getAllCommits;
23
+ exports.getCommitInfo = getCommitInfo;
24
+ exports.getCommitDiff = getCommitDiff;
25
+ exports.getCommitRange = getCommitRange;
26
+ exports.scan = scan;
27
+ const child_process_1 = require("child_process");
28
+ const utils_1 = require("../utils");
29
+ const scope_resolver_1 = require("./scope-resolver");
30
+ const spec_extractor_1 = require("./spec-extractor");
31
+ const errors_1 = require("../../errors");
32
+ // ---------------------------------------------------------------------------
33
+ // Helpers
34
+ // ---------------------------------------------------------------------------
35
+ /** Shared options for all `execFileSync` Git calls. */
36
+ function gitExecOptions(repoPath) {
37
+ const stdio = ['ignore', 'pipe', 'ignore'];
38
+ return {
39
+ cwd: repoPath,
40
+ encoding: 'utf8',
41
+ stdio,
42
+ windowsHide: true,
43
+ };
44
+ }
45
+ /**
46
+ * Convert an ISO-8601 string to Unix epoch milliseconds.
47
+ * Returns 0 for invalid or unparseable strings.
48
+ */
49
+ function parseISOTimestamp(isoString) {
50
+ const ts = new Date(isoString).getTime();
51
+ return isNaN(ts) ? 0 : ts;
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // isGitRepo
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Check whether `repoPath` is a git repository.
58
+ *
59
+ * Runs `git rev-parse --git-dir` and returns `true` on success, `false`
60
+ * when the command fails (not a repo, git not installed, etc.).
61
+ */
62
+ function isGitRepo(repoPath) {
63
+ try {
64
+ (0, child_process_1.execFileSync)('git', ['rev-parse', '--git-dir'], gitExecOptions(repoPath));
65
+ return true;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ // ---------------------------------------------------------------------------
72
+ // getAllCommits
73
+ // ---------------------------------------------------------------------------
74
+ /**
75
+ * Return every commit in `repoPath` as `CommitInfo` objects.
76
+ *
77
+ * Runs `git log --format='%H%n%aI%n%an%n%s%n---END---'` and parses the
78
+ * output one five-line block per commit. Commits are returned in reverse
79
+ * chronological order (most recent first), matching Git's default.
80
+ *
81
+ * An empty repo yields an empty array.
82
+ */
83
+ function getAllCommits(repoPath) {
84
+ let stdout;
85
+ try {
86
+ stdout = (0, child_process_1.execFileSync)('git', ['log', "--format=%H%n%aI%n%an%n%s%n---END---"], gitExecOptions(repoPath));
87
+ }
88
+ catch {
89
+ return [];
90
+ }
91
+ const lines = stdout.trim().split('\n');
92
+ const commits = [];
93
+ // Each commit occupies 5 lines: hash, ISO timestamp, author, subject, separator.
94
+ for (let i = 0; i + 4 < lines.length; i += 5) {
95
+ const hash = lines[i].trim();
96
+ const isoString = lines[i + 1].trim();
97
+ const author = lines[i + 2].trim();
98
+ const message = lines[i + 3].trim();
99
+ // lines[i+4] is the ---END--- separator — skip it.
100
+ if (!hash)
101
+ continue;
102
+ commits.push({
103
+ hash,
104
+ message,
105
+ author,
106
+ timestamp: parseISOTimestamp(isoString),
107
+ });
108
+ }
109
+ return commits;
110
+ }
111
+ // ---------------------------------------------------------------------------
112
+ // getCommitInfo
113
+ // ---------------------------------------------------------------------------
114
+ /**
115
+ * Retrieve metadata for a single commit.
116
+ *
117
+ * Runs `git show -s --format='%H%n%aI%n%an%n%s' <commitHash>`. Returns
118
+ * `null` when the command fails (hash not found, invalid repo, etc.).
119
+ */
120
+ function getCommitInfo(repoPath, commitHash) {
121
+ let stdout;
122
+ try {
123
+ stdout = (0, child_process_1.execFileSync)('git', ['show', '-s', "--format=%H%n%aI%n%an%n%s", commitHash], gitExecOptions(repoPath));
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ const lines = stdout.trim().split('\n');
129
+ if (lines.length < 4)
130
+ return null;
131
+ const hash = lines[0].trim();
132
+ const isoString = lines[1].trim();
133
+ const author = lines[2].trim();
134
+ const message = lines[3].trim();
135
+ if (!hash)
136
+ return null;
137
+ return {
138
+ hash,
139
+ message,
140
+ author,
141
+ timestamp: parseISOTimestamp(isoString),
142
+ };
143
+ }
144
+ // ---------------------------------------------------------------------------
145
+ // getCommitDiff
146
+ // ---------------------------------------------------------------------------
147
+ /**
148
+ * Return the full unified diff introduced by `commitHash`.
149
+ *
150
+ * Strategy:
151
+ * 1. Query the parent hash(es) via `git log --pretty=%P -n 1 <commitHash>`.
152
+ * 2. If a parent exists, diff it against the commit: `git diff <parent> <commitHash>`.
153
+ * 3. For an initial (root) commit with no parent, use `git diff <commitHash>`
154
+ * which shows all files added in that commit.
155
+ *
156
+ * Returns an empty string when any Git command fails.
157
+ */
158
+ function getCommitDiff(repoPath, commitHash) {
159
+ // Step 1 — get parent hashes.
160
+ let parentStdout;
161
+ try {
162
+ parentStdout = (0, child_process_1.execFileSync)('git', ['log', '--pretty=%P', '-n', '1', commitHash], gitExecOptions(repoPath));
163
+ }
164
+ catch {
165
+ return '';
166
+ }
167
+ const parents = parentStdout.trim().split(/\s+/).filter(Boolean);
168
+ // Step 2 & 3 — run the appropriate diff.
169
+ try {
170
+ if (parents.length > 0) {
171
+ const parent = parents[0];
172
+ return (0, child_process_1.execFileSync)('git', ['diff', parent, commitHash], gitExecOptions(repoPath));
173
+ }
174
+ // Initial commit — no parent.
175
+ return (0, child_process_1.execFileSync)('git', ['diff', commitHash], gitExecOptions(repoPath));
176
+ }
177
+ catch {
178
+ return '';
179
+ }
180
+ }
181
+ // ---------------------------------------------------------------------------
182
+ // getCommitRange
183
+ // ---------------------------------------------------------------------------
184
+ /**
185
+ * Return every commit between `fromHash` (exclusive) and `toHash`
186
+ * (inclusive) in chronological order (oldest first).
187
+ *
188
+ * Runs `git log --reverse --format="..." fromHash..toHash`. Returns an empty
189
+ * array when either hash is not found or the range is empty.
190
+ *
191
+ * Callers should validate that `fromHash` is an ancestor of `toHash` before
192
+ * calling this function (use `git merge-base --is-ancestor`). Results are
193
+ * undefined when the two hashes are on unrelated branches.
194
+ */
195
+ function getCommitRange(repoPath, fromHash, toHash) {
196
+ let stdout;
197
+ try {
198
+ stdout = (0, child_process_1.execFileSync)('git', ['log', '--reverse', `--format=%H%n%aI%n%an%n%s%n---END---`, `${fromHash}..${toHash}`], gitExecOptions(repoPath));
199
+ }
200
+ catch {
201
+ return [];
202
+ }
203
+ const lines = stdout.trim().split('\n');
204
+ const commits = [];
205
+ for (let i = 0; i + 4 < lines.length; i += 5) {
206
+ const hash = lines[i].trim();
207
+ const isoString = lines[i + 1].trim();
208
+ const author = lines[i + 2].trim();
209
+ const message = lines[i + 3].trim();
210
+ if (!hash)
211
+ continue;
212
+ commits.push({
213
+ hash,
214
+ message,
215
+ author,
216
+ timestamp: parseISOTimestamp(isoString),
217
+ });
218
+ }
219
+ return commits;
220
+ }
221
+ // ---------------------------------------------------------------------------
222
+ // scan
223
+ // ---------------------------------------------------------------------------
224
+ /**
225
+ * Main scanning function — discovers spec↔commit pairs using two strategies.
226
+ *
227
+ * **Strategy A — commit message scope:**
228
+ * Iterates every commit in the repo, extracts a conventional-commit scope from
229
+ * its message, normalizes it, and checks whether the resulting spec ID exists
230
+ * on disk. When a match is found the pair is recorded with full spec and
231
+ * commit metadata.
232
+ *
233
+ * **Strategy B — commit-info.md:**
234
+ * Discovers all specs on disk that were **not** already paired by Strategy A,
235
+ * reads their metadata (which may include a commit hash from `commit-info.md`),
236
+ * and verifies the commit exists in the repo. Verified pairs are added.
237
+ *
238
+ * Duplicates (identical specId + commitHash) are de-duplicated via a
239
+ * `Map` keyed on `"${specId}|${commitHash}"`.
240
+ */
241
+ function scan(repoPath, specStoragePath, config) {
242
+ const pairs = new Map();
243
+ // ---- Strategy A: commit message scope ----
244
+ const commits = getAllCommits(repoPath);
245
+ for (const commit of commits) {
246
+ const specId = (0, scope_resolver_1.resolveScopeToSpec)(commit.message, specStoragePath, config);
247
+ if (!specId) {
248
+ (0, errors_1.logDebug)('Strategy A: no scope match', {
249
+ commitHash: commit.hash.slice(0, 7),
250
+ message: commit.message,
251
+ });
252
+ continue;
253
+ }
254
+ const specMetadata = (0, spec_extractor_1.extractSpecMetadata)(specStoragePath, specId, config);
255
+ const key = `${specId}|${commit.hash}`;
256
+ if (!pairs.has(key)) {
257
+ pairs.set(key, {
258
+ specId,
259
+ commitHash: commit.hash,
260
+ specMetadata,
261
+ commitMetadata: commit,
262
+ });
263
+ }
264
+ }
265
+ // ---- Strategy B: commit-info.md ----
266
+ // Collect specIds already paired by Strategy A.
267
+ const pairedSpecIds = new Set();
268
+ for (const pair of pairs.values()) {
269
+ pairedSpecIds.add(pair.specId);
270
+ }
271
+ const specs = (0, utils_1.discoverSpecs)(specStoragePath);
272
+ for (const spec of specs) {
273
+ if (pairedSpecIds.has(spec.specId)) {
274
+ continue;
275
+ }
276
+ const metadata = (0, spec_extractor_1.extractSpecMetadata)(specStoragePath, spec.specId, config);
277
+ if (!metadata) {
278
+ // extractSpecMetadata already logs the reason.
279
+ continue;
280
+ }
281
+ if (!metadata.commitHash) {
282
+ (0, errors_1.logDebug)('Strategy B: no commit hash in spec metadata', {
283
+ specId: spec.specId,
284
+ });
285
+ continue;
286
+ }
287
+ const commitInfo = getCommitInfo(repoPath, metadata.commitHash);
288
+ if (!commitInfo) {
289
+ (0, errors_1.logWarn)('Strategy B: commit-info.md hash does not match any known commit', {
290
+ specId: spec.specId,
291
+ commitHash: metadata.commitHash,
292
+ });
293
+ continue;
294
+ }
295
+ const key = `${spec.specId}|${metadata.commitHash}`;
296
+ if (!pairs.has(key)) {
297
+ pairs.set(key, {
298
+ specId: spec.specId,
299
+ commitHash: metadata.commitHash,
300
+ specMetadata: metadata,
301
+ commitMetadata: commitInfo,
302
+ });
303
+ }
304
+ }
305
+ return Array.from(pairs.values());
306
+ }
307
+ //# sourceMappingURL=git-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-scanner.js","sourceRoot":"","sources":["../../../src/spec/mining/git-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Mining pipeline orchestrator — main entry point for reverse-mining spec
3
+ * knowledge from Git history.
4
+ *
5
+ * Replaces `commit4spec/reverse_engineer/pipeline.py`. Discovers spec↔commit
6
+ * pairs via `scan()`, persists them into the SQLite knowledge graph, and
7
+ * writes a `.homegraph/commit4spec/meta.json` anchor so the self-evolve pipeline can
8
+ * pick up where mining left off.
9
+ *
10
+ * @module spec/mining/pipeline
11
+ */
12
+ import { SqliteDatabase } from '../../db/sqlite-adapter';
13
+ import { SpecConfig } from '../config';
14
+ export interface MiningResult {
15
+ specsFound: number;
16
+ commitsFound: number;
17
+ fragmentsFound: number;
18
+ relationsCreated: number;
19
+ totalEntries: number;
20
+ skippedEntries: Array<{
21
+ specId: string;
22
+ reason: string;
23
+ }>;
24
+ }
25
+ /**
26
+ * Run the full reverse-mining pipeline.
27
+ *
28
+ * Steps (ported from `pipeline.py:49-151`):
29
+ *
30
+ * 1. Initialise the spec knowledge-graph schema in the database.
31
+ * 2. Discover all specs on disk (for the `totalEntries` count).
32
+ * 3. Scan the repository for spec↔commit pairs.
33
+ * 4. Sort pairs by commit timestamp ascending so that `INSERT OR REPLACE`
34
+ * gives the most-recent commit the final word for each spec node.
35
+ * 5. Process each pair:
36
+ * - Insert a SpecNode (once per specId; deduplicated by commit timestamp).
37
+ * - Insert a CommitNode (once per commit hash).
38
+ * - Insert a SUMMARIZED_FROM relation.
39
+ * - Parse the commit diff into code fragments and persist them.
40
+ * 6. Build a list of specs discovered on disk but never matched to a commit.
41
+ * 7. Write `.homegraph/commit4spec/meta.json`.
42
+ * 8. Return the `MiningResult` with all counts.
43
+ *
44
+ * Edge cases:
45
+ * - Empty pairs → zero counts, write meta anyway, return result.
46
+ * - Pair with commit metadata but no spec metadata → commit and fragments
47
+ * are still persisted; SpecNode and spec_commit_relation are skipped.
48
+ * - Pair with spec metadata but no commit metadata → entire pair is skipped.
49
+ * - Same spec in multiple pairs → only counted once in `specsFound`, but
50
+ * every commit relation is created.
51
+ */
52
+ export declare function runMiningPipeline(repoPath: string, specStoragePath: string, db: SqliteDatabase, config?: SpecConfig): MiningResult;
53
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../src/spec/mining/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAkB,MAAM,WAAW,CAAC;AAmBvD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,EAAE,EAAE,cAAc,EAClB,MAAM,CAAC,EAAE,UAAU,GAClB,YAAY,CAwId"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ /**
3
+ * Mining pipeline orchestrator — main entry point for reverse-mining spec
4
+ * knowledge from Git history.
5
+ *
6
+ * Replaces `commit4spec/reverse_engineer/pipeline.py`. Discovers spec↔commit
7
+ * pairs via `scan()`, persists them into the SQLite knowledge graph, and
8
+ * writes a `.homegraph/commit4spec/meta.json` anchor so the self-evolve pipeline can
9
+ * pick up where mining left off.
10
+ *
11
+ * @module spec/mining/pipeline
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.runMiningPipeline = runMiningPipeline;
15
+ const config_1 = require("../config");
16
+ const utils_1 = require("../utils");
17
+ const schema_1 = require("../db/schema");
18
+ const spec_node_1 = require("../db/spec-node");
19
+ const commit_node_1 = require("../db/commit-node");
20
+ const fragment_node_1 = require("../db/fragment-node");
21
+ const relations_1 = require("../db/relations");
22
+ const child_process_1 = require("child_process");
23
+ const git_scanner_1 = require("./git-scanner");
24
+ const diff_parser_1 = require("./diff-parser");
25
+ const errors_1 = require("../../errors");
26
+ // ---------------------------------------------------------------------------
27
+ // runMiningPipeline
28
+ // ---------------------------------------------------------------------------
29
+ /**
30
+ * Run the full reverse-mining pipeline.
31
+ *
32
+ * Steps (ported from `pipeline.py:49-151`):
33
+ *
34
+ * 1. Initialise the spec knowledge-graph schema in the database.
35
+ * 2. Discover all specs on disk (for the `totalEntries` count).
36
+ * 3. Scan the repository for spec↔commit pairs.
37
+ * 4. Sort pairs by commit timestamp ascending so that `INSERT OR REPLACE`
38
+ * gives the most-recent commit the final word for each spec node.
39
+ * 5. Process each pair:
40
+ * - Insert a SpecNode (once per specId; deduplicated by commit timestamp).
41
+ * - Insert a CommitNode (once per commit hash).
42
+ * - Insert a SUMMARIZED_FROM relation.
43
+ * - Parse the commit diff into code fragments and persist them.
44
+ * 6. Build a list of specs discovered on disk but never matched to a commit.
45
+ * 7. Write `.homegraph/commit4spec/meta.json`.
46
+ * 8. Return the `MiningResult` with all counts.
47
+ *
48
+ * Edge cases:
49
+ * - Empty pairs → zero counts, write meta anyway, return result.
50
+ * - Pair with commit metadata but no spec metadata → commit and fragments
51
+ * are still persisted; SpecNode and spec_commit_relation are skipped.
52
+ * - Pair with spec metadata but no commit metadata → entire pair is skipped.
53
+ * - Same spec in multiple pairs → only counted once in `specsFound`, but
54
+ * every commit relation is created.
55
+ */
56
+ function runMiningPipeline(repoPath, specStoragePath, db, config) {
57
+ // Resolve config once — guarantee a valid SpecConfig for downstream consumers.
58
+ const resolvedConfig = config ?? (0, config_1.loadSpecConfig)(repoPath);
59
+ // ---- Step 1: init schema ----
60
+ (0, schema_1.initSpecSchema)(db);
61
+ // ---- Step 2: discover specs (for totalEntries) ----
62
+ const allEntries = (0, utils_1.discoverSpecs)(specStoragePath);
63
+ const totalEntries = allEntries.length;
64
+ // ---- Step 3: scan for pairs ----
65
+ const pairs = (0, git_scanner_1.scan)(repoPath, specStoragePath, resolvedConfig);
66
+ // ---- Step 4: sort by commit timestamp ascending (oldest first) ----
67
+ // INSERT OR REPLACE is used for SpecNode — when the same spec appears
68
+ // in multiple pairs, the LAST write (most-recent commit) naturally wins.
69
+ pairs.sort((a, b) => {
70
+ const aTs = a.commitMetadata?.timestamp ?? 0;
71
+ const bTs = b.commitMetadata?.timestamp ?? 0;
72
+ return aTs - bTs;
73
+ });
74
+ // ---- Step 5: process pairs ----
75
+ const writtenSpecIds = new Set();
76
+ const seenCommitHashes = new Set();
77
+ let specsFound = 0;
78
+ let commitsFound = 0;
79
+ let fragmentsFound = 0;
80
+ let relationsCreated = 0;
81
+ for (const pair of pairs) {
82
+ // Skip if no commit metadata (no data to insert).
83
+ const cm = pair.commitMetadata;
84
+ if (!cm) {
85
+ continue;
86
+ }
87
+ const sm = pair.specMetadata;
88
+ // Insert SpecNode if spec metadata is present.
89
+ // INSERT OR REPLACE lets the most-recent commit (last in ascending
90
+ // order) overwrite the timestamp. We still track writtenSpecIds to
91
+ // correctly count distinct specs (not overwrites).
92
+ if (sm) {
93
+ (0, errors_1.logDebug)('Processing pair: inserting SpecNode', {
94
+ specId: sm.specId,
95
+ title: sm.title,
96
+ });
97
+ (0, spec_node_1.insertSpecNode)(db, {
98
+ id: sm.specId,
99
+ title: sm.title,
100
+ subtitles: sm.subtitles,
101
+ status: 'active',
102
+ version: 1,
103
+ filePath: sm.filePath,
104
+ timestamp: cm.timestamp,
105
+ });
106
+ if (!writtenSpecIds.has(pair.specId)) {
107
+ writtenSpecIds.add(pair.specId);
108
+ specsFound++;
109
+ }
110
+ }
111
+ // Insert CommitNode if not yet seen.
112
+ if (!seenCommitHashes.has(cm.hash)) {
113
+ (0, commit_node_1.insertCommitNode)(db, {
114
+ hash: cm.hash,
115
+ message: cm.message,
116
+ author: cm.author,
117
+ timestamp: cm.timestamp,
118
+ });
119
+ seenCommitHashes.add(cm.hash);
120
+ commitsFound++;
121
+ }
122
+ // Insert spec_commit_relation (only when spec metadata exists).
123
+ if (sm) {
124
+ (0, relations_1.insertSpecCommitRelation)(db, pair.specId, cm.hash, 'SUMMARIZED_FROM');
125
+ relationsCreated++;
126
+ }
127
+ // ---- Analyze diff and insert fragments ----
128
+ const preFetchedDiff = (0, git_scanner_1.getCommitDiff)(repoPath, cm.hash);
129
+ const fragments = (0, diff_parser_1.analyzeCommitDiff)(repoPath, cm.hash, preFetchedDiff);
130
+ for (const frag of fragments) {
131
+ // insertCodeFragment auto-generates an id when the `id` field is empty.
132
+ const inserted = (0, fragment_node_1.insertCodeFragment)(db, {
133
+ id: '',
134
+ changeType: frag.changeType,
135
+ filePath: frag.filePath,
136
+ startLine: frag.startLine,
137
+ endLine: frag.endLine,
138
+ codeDiff: frag.codeDiff,
139
+ });
140
+ fragmentsFound++;
141
+ (0, relations_1.insertCommitFragmentRelation)(db, cm.hash, inserted.id);
142
+ relationsCreated++;
143
+ }
144
+ }
145
+ // ---- Step 6: build skipped entries ----
146
+ const skippedEntries = allEntries
147
+ .filter((e) => !writtenSpecIds.has(e.specId))
148
+ .map((e) => ({ specId: e.specId, reason: 'No matching commits found' }));
149
+ for (const skipped of skippedEntries) {
150
+ (0, errors_1.logWarn)('Spec discovered on disk but no matching commits found', {
151
+ specId: skipped.specId,
152
+ });
153
+ }
154
+ // ---- Step 7: write meta ----
155
+ let headHash;
156
+ try {
157
+ headHash = (0, child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], {
158
+ cwd: repoPath,
159
+ encoding: 'utf8',
160
+ stdio: ['ignore', 'pipe', 'ignore'],
161
+ windowsHide: true,
162
+ }).trim();
163
+ }
164
+ catch {
165
+ headHash = undefined;
166
+ }
167
+ (0, utils_1.writeMeta)(repoPath, specStoragePath, headHash);
168
+ // ---- Step 8: return result ----
169
+ return {
170
+ specsFound,
171
+ commitsFound,
172
+ fragmentsFound,
173
+ relationsCreated,
174
+ totalEntries,
175
+ skippedEntries,
176
+ };
177
+ }
178
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../../src/spec/mining/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Commit message scope parsing and resolution.
3
+ *
4
+ * Replaces `commit4spec/reverse_engineer/scope_resolver.py`.
5
+ * Extracts conventional-commit scopes, normalizes them, and resolves them to
6
+ * spec IDs found on disk.
7
+ *
8
+ * @module spec/mining/scope-resolver
9
+ */
10
+ import { SpecConfig } from '../config';
11
+ /**
12
+ * Extract a scope from a commit message using the configured regex.
13
+ *
14
+ * Only searches the **first line** of the commit message. Returns the
15
+ * contents of the first capture group (the scope), or `null` when there is
16
+ * no match or the regex has no capture group.
17
+ */
18
+ export declare function extractScope(message: string, scopeRegex: string): string | null;
19
+ /**
20
+ * Normalize a scope string.
21
+ *
22
+ * Steps applied in order:
23
+ *
24
+ * 1. **Strip prefixes** — for each prefix in `stripPrefixes`, if `scope`
25
+ * starts with it, remove it and stop (only the first matching prefix is
26
+ * stripped).
27
+ * 2. **Lowercase** — if `lowercase` is `true`, convert to lower case.
28
+ * 3. **Pad spec number** — if `padSpecNumber` is `true`, match the pattern
29
+ * `/^spec(\d+)$/i` and zero-pad the numeric portion to 2 digits
30
+ * (e.g. `spec3` → `spec03`).
31
+ */
32
+ export declare function normalizeScope(scope: string, config: {
33
+ stripPrefixes: string[];
34
+ lowercase: boolean;
35
+ padSpecNumber: boolean;
36
+ }): string;
37
+ /**
38
+ * Extract a scope from a commit message, normalize it, then check whether the
39
+ * resulting spec ID exists on disk in `specStoragePath`.
40
+ *
41
+ * Returns the normalized spec ID when the scope resolves to an existing spec,
42
+ * otherwise `null`.
43
+ */
44
+ export declare function resolveScopeToSpec(message: string, specStoragePath: string, config: SpecConfig): string | null;
45
+ //# sourceMappingURL=scope-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-resolver.d.ts","sourceRoot":"","sources":["../../../src/spec/mining/scope-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAQvC;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB/E;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;IAAE,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,GAC9E,MAAM,CAyBR;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,UAAU,GACjB,MAAM,GAAG,IAAI,CAYf"}