homegraph 1.5.0 → 1.5.1

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 (214) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +305 -305
  3. package/dist/bin/command-supervision.d.ts.map +1 -1
  4. package/dist/bin/command-supervision.js +7 -4
  5. package/dist/bin/command-supervision.js.map +1 -1
  6. package/dist/bin/homegraph.js +9 -9
  7. package/dist/db/index.js +36 -36
  8. package/dist/db/migrations.js +37 -37
  9. package/dist/db/queries.js +156 -156
  10. package/dist/db/schema.sql +203 -203
  11. package/dist/directory.js +5 -5
  12. package/dist/extraction/languages/arkts-viewtree.d.ts +2 -4
  13. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
  14. package/dist/extraction/languages/arkts-viewtree.js +6 -21
  15. package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
  16. package/dist/extraction/languages/arkts.d.ts +16 -6
  17. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  18. package/dist/extraction/languages/arkts.js +174 -21
  19. package/dist/extraction/languages/arkts.js.map +1 -1
  20. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  21. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  22. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  23. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  24. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  25. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  26. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  27. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  28. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  29. package/dist/installer/instructions-template.js +9 -9
  30. package/dist/mcp/liveness-watchdog.d.ts +18 -0
  31. package/dist/mcp/liveness-watchdog.d.ts.map +1 -1
  32. package/dist/mcp/liveness-watchdog.js +185 -73
  33. package/dist/mcp/liveness-watchdog.js.map +1 -1
  34. package/dist/mcp/server-instructions.js +47 -47
  35. package/dist/reasoning/reasoner.js +32 -32
  36. package/dist/spec/db/commit-node.js +4 -4
  37. package/dist/spec/db/fragment-node.js +10 -10
  38. package/dist/spec/db/fts.js +8 -8
  39. package/dist/spec/db/relations.js +88 -88
  40. package/dist/spec/db/schema.js +6 -6
  41. package/dist/spec/db/schema.sql +121 -121
  42. package/dist/spec/db/spec-node.js +4 -4
  43. package/dist/spec/llm/prompts.js +53 -53
  44. package/dist/spec/utils.d.ts +16 -4
  45. package/dist/spec/utils.d.ts.map +1 -1
  46. package/dist/spec/utils.js +58 -6
  47. package/dist/spec/utils.js.map +1 -1
  48. package/package.json +62 -62
  49. package/scripts/_tmp-cfwk-resolve.log +0 -0
  50. package/scripts/_tmp-cfwk-sig.log +0 -0
  51. package/scripts/_tmp-cfwk-vt.log +0 -0
  52. package/scripts/add-lang/bench.sh +60 -60
  53. package/scripts/add-lang/check-grammar.mjs +75 -75
  54. package/scripts/add-lang/dump-ast.mjs +103 -103
  55. package/scripts/add-lang/verify-extraction.mjs +70 -70
  56. package/scripts/agent-eval/ab-adoption.sh +91 -91
  57. package/scripts/agent-eval/ab-hook.sh +86 -86
  58. package/scripts/agent-eval/ab-impl.sh +78 -78
  59. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  60. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  61. package/scripts/agent-eval/arms-F.sh +21 -21
  62. package/scripts/agent-eval/arms-matrix.sh +37 -37
  63. package/scripts/agent-eval/audit.sh +68 -68
  64. package/scripts/agent-eval/bench-readme.sh +28 -28
  65. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  66. package/scripts/agent-eval/block-read-hook.sh +19 -19
  67. package/scripts/agent-eval/hook-settings.json +15 -15
  68. package/scripts/agent-eval/itrun.sh +120 -120
  69. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  70. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  71. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  72. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  73. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  74. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  75. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  76. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  77. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  78. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  79. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  80. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  81. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  82. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  83. package/scripts/agent-eval/offload-eval.md +76 -76
  84. package/scripts/agent-eval/parse-arms.mjs +116 -116
  85. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  86. package/scripts/agent-eval/parse-run.mjs +45 -45
  87. package/scripts/agent-eval/parse-session.mjs +93 -93
  88. package/scripts/agent-eval/probe-context.mjs +21 -21
  89. package/scripts/agent-eval/probe-explore.mjs +40 -40
  90. package/scripts/agent-eval/probe-node.mjs +20 -20
  91. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  92. package/scripts/agent-eval/probe-trace.mjs +20 -20
  93. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  94. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -119
  95. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -125
  96. package/scripts/agent-eval/run-agent.sh +34 -34
  97. package/scripts/agent-eval/run-all.sh +75 -75
  98. package/scripts/agent-eval/run-arms.sh +56 -56
  99. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  100. package/scripts/bench-arkts-init-rss.log +0 -0
  101. package/scripts/build-bundle.sh +123 -123
  102. package/scripts/exp_boundary_eval/README.md +247 -247
  103. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  104. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-38.pyc +0 -0
  105. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  106. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-38.pyc +0 -0
  107. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-38.pyc +0 -0
  108. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-310.pyc +0 -0
  109. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-38.pyc +0 -0
  110. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  111. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-38.pyc +0 -0
  112. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  113. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-38.pyc +0 -0
  114. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  115. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-38.pyc +0 -0
  116. package/scripts/exp_boundary_eval/__pycache__/win_mcp_launcher.cpython-38.pyc +0 -0
  117. package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -78
  118. package/scripts/exp_boundary_eval/_test_stdin.py +8 -8
  119. package/scripts/exp_boundary_eval/_utils.py +1116 -1116
  120. package/scripts/exp_boundary_eval/analyze.py +1313 -1313
  121. package/scripts/exp_boundary_eval/deveco_arm.py +519 -519
  122. package/scripts/exp_boundary_eval/run_all.py +378 -378
  123. package/scripts/exp_boundary_eval/run_one.py +165 -165
  124. package/scripts/exp_boundary_eval/run_session.py +158 -158
  125. package/scripts/exp_boundary_eval/setup.py +120 -120
  126. package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -73
  127. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -36
  128. package/scripts/exp_boundary_eval/win_node_launcher.py +24 -24
  129. package/scripts/extract-release-notes.mjs +130 -130
  130. package/scripts/local-install.sh +41 -41
  131. package/scripts/npm-sdk.js +75 -75
  132. package/scripts/npm-shim.js +275 -275
  133. package/scripts/ohos-sdk-publish.mjs +133 -133
  134. package/scripts/pack-npm.sh +119 -119
  135. package/scripts/prepare-release.mjs +270 -270
  136. package/scripts/probe-arkts-mem-why-run.log +0 -0
  137. package/scripts/probe-banner-livecard-ir.log +0 -0
  138. package/scripts/probe-cfwk-ast.stderr.log +0 -0
  139. package/scripts/probe-cfwk-ast.stdout.log +0 -0
  140. package/scripts/probe-cfwk-attr-shape.log +0 -0
  141. package/scripts/probe-cfwk-cfgdump.stderr.log +0 -0
  142. package/scripts/probe-cfwk-cfgdump.stdout.log +0 -0
  143. package/scripts/probe-cfwk-cvc.stderr.log +0 -0
  144. package/scripts/probe-cfwk-cvc.stdout.log +0 -0
  145. package/scripts/probe-cfwk-diag2.log +0 -0
  146. package/scripts/probe-cfwk-diag3.log +0 -0
  147. package/scripts/probe-cfwk-fedbg.stderr.log +0 -0
  148. package/scripts/probe-cfwk-fedbg.stdout.log +0 -0
  149. package/scripts/probe-cfwk-fileresult.log +0 -0
  150. package/scripts/probe-cfwk-fix.stderr.log +0 -0
  151. package/scripts/probe-cfwk-fix.stdout.log +0 -0
  152. package/scripts/probe-cfwk-fix2.stderr.log +0 -0
  153. package/scripts/probe-cfwk-fix2.stdout.log +0 -0
  154. package/scripts/probe-cfwk-fix3.stderr.log +0 -0
  155. package/scripts/probe-cfwk-fix3.stdout.log +0 -0
  156. package/scripts/probe-cfwk-foreach.log +0 -0
  157. package/scripts/probe-cfwk-getmethod-throw.log +0 -0
  158. package/scripts/probe-cfwk-hg-extract.log +0 -0
  159. package/scripts/probe-cfwk-pr1003-noprior.stderr.log +0 -0
  160. package/scripts/probe-cfwk-pr1003-noprior.stdout.log +0 -0
  161. package/scripts/probe-cfwk-pr1003.stderr.log +0 -0
  162. package/scripts/probe-cfwk-pr1003.stdout.log +0 -0
  163. package/scripts/probe-cfwk-preroot-noprior.stderr.log +0 -0
  164. package/scripts/probe-cfwk-preroot-noprior.stdout.log +0 -0
  165. package/scripts/probe-cfwk-preroot-prior.stderr.log +0 -0
  166. package/scripts/probe-cfwk-preroot-prior.stdout.log +0 -0
  167. package/scripts/probe-cfwk-preroot-skipstate.stderr.log +0 -0
  168. package/scripts/probe-cfwk-preroot-skipstate.stdout.log +0 -0
  169. package/scripts/probe-cfwk-resolve-sim.log +0 -0
  170. package/scripts/probe-cfwk-tree-shape.log +0 -0
  171. package/scripts/probe-cfwk-walk-abort.log +0 -0
  172. package/scripts/probe-cfwk.log +0 -0
  173. package/scripts/probe-force-index.log +0 -0
  174. package/scripts/probe-no-force-index.log +0 -0
  175. package/scripts/probe-samefile-ir.stderr.log +0 -0
  176. package/scripts/probe-samefile-ir.stdout.log +224 -0
  177. package/scripts/probe-sdk-vs-project.log +0 -0
  178. package/scripts/probe-viewtree-downgrade.log +0 -0
  179. package/dist/arkts/ohos-api-index.d.ts +0 -15
  180. package/dist/arkts/ohos-api-index.d.ts.map +0 -1
  181. package/dist/arkts/ohos-api-index.js +0 -190
  182. package/dist/arkts/ohos-api-index.js.map +0 -1
  183. package/dist/arkts/ohos-sdk-input.d.ts +0 -36
  184. package/dist/arkts/ohos-sdk-input.d.ts.map +0 -1
  185. package/dist/arkts/ohos-sdk-input.js +0 -214
  186. package/dist/arkts/ohos-sdk-input.js.map +0 -1
  187. package/dist/extraction/languages/arkts-state-decorators.d.ts +0 -13
  188. package/dist/extraction/languages/arkts-state-decorators.d.ts.map +0 -1
  189. package/dist/extraction/languages/arkts-state-decorators.js +0 -26
  190. package/dist/extraction/languages/arkts-state-decorators.js.map +0 -1
  191. package/dist/extraction/languages/ohos-api-consumer.d.ts +0 -34
  192. package/dist/extraction/languages/ohos-api-consumer.d.ts.map +0 -1
  193. package/dist/extraction/languages/ohos-api-consumer.js +0 -283
  194. package/dist/extraction/languages/ohos-api-consumer.js.map +0 -1
  195. package/dist/spec/build/git-scanner.d.ts +0 -93
  196. package/dist/spec/build/git-scanner.d.ts.map +0 -1
  197. package/dist/spec/build/git-scanner.js +0 -254
  198. package/dist/spec/build/git-scanner.js.map +0 -1
  199. package/dist/spec/git-utils.d.ts +0 -8
  200. package/dist/spec/git-utils.d.ts.map +0 -1
  201. package/dist/spec/git-utils.js +0 -14
  202. package/dist/spec/git-utils.js.map +0 -1
  203. package/dist/spec/mine/clusterer.d.ts +0 -63
  204. package/dist/spec/mine/clusterer.d.ts.map +0 -1
  205. package/dist/spec/mine/clusterer.js +0 -904
  206. package/dist/spec/mine/clusterer.js.map +0 -1
  207. package/dist/spec/mine/progress-handler.d.ts +0 -22
  208. package/dist/spec/mine/progress-handler.d.ts.map +0 -1
  209. package/dist/spec/mine/progress-handler.js +0 -108
  210. package/dist/spec/mine/progress-handler.js.map +0 -1
  211. package/dist/spec/mine/progress.d.ts +0 -23
  212. package/dist/spec/mine/progress.d.ts.map +0 -1
  213. package/dist/spec/mine/progress.js +0 -12
  214. package/dist/spec/mine/progress.js.map +0 -1
@@ -119,10 +119,10 @@ function searchSpecsFts(db, query, limit, oversample = 3) {
119
119
  let rows;
120
120
  try {
121
121
  rows = db
122
- .prepare(`SELECT s.id, s.title, s.subtitles
123
- FROM specs_fts f
124
- JOIN spec_nodes s ON s.id = f.id
125
- WHERE specs_fts MATCH ?
122
+ .prepare(`SELECT s.id, s.title, s.subtitles
123
+ FROM specs_fts f
124
+ JOIN spec_nodes s ON s.id = f.id
125
+ WHERE specs_fts MATCH ?
126
126
  ORDER BY rank LIMIT ?`)
127
127
  .all(escaped, rawLimit);
128
128
  }
@@ -159,8 +159,8 @@ function searchSpecsLike(db, query, limit, excludeIds) {
159
159
  // Escape LIKE metacharacters so '%' and '_' are treated as literals
160
160
  const likePat = `%${(0, sql_utils_1.escapeLike)(query)}%`;
161
161
  const rows = db
162
- .prepare(`SELECT id, title, subtitles FROM spec_nodes
163
- WHERE title LIKE ? ESCAPE '\\' OR subtitles LIKE ? ESCAPE '\\'
162
+ .prepare(`SELECT id, title, subtitles FROM spec_nodes
163
+ WHERE title LIKE ? ESCAPE '\\' OR subtitles LIKE ? ESCAPE '\\'
164
164
  ORDER BY id LIMIT ?`)
165
165
  .all(likePat, likePat, limit * 3);
166
166
  const scored = [];
@@ -280,8 +280,8 @@ function searchCodeFragments(db, query, limit = 50) {
280
280
  let rows;
281
281
  try {
282
282
  rows = db
283
- .prepare(`SELECT id FROM code_fragments_fts
284
- WHERE code_fragments_fts MATCH ?
283
+ .prepare(`SELECT id FROM code_fragments_fts
284
+ WHERE code_fragments_fts MATCH ?
285
285
  ORDER BY rank LIMIT ?`)
286
286
  .all(escaped, limit);
287
287
  }
@@ -30,10 +30,10 @@ const sql_utils_1 = require("./sql-utils");
30
30
  * `INSERT OR IGNORE` — duplicates are silently skipped.
31
31
  */
32
32
  function insertSpecCommitRelation(db, specId, commitHash, relationType) {
33
- db.prepare(`
34
- INSERT OR IGNORE INTO spec_commit_relations
35
- (spec_id, commit_hash, relation_type)
36
- VALUES (@specId, @commitHash, @relationType)
33
+ db.prepare(`
34
+ INSERT OR IGNORE INTO spec_commit_relations
35
+ (spec_id, commit_hash, relation_type)
36
+ VALUES (@specId, @commitHash, @relationType)
37
37
  `).run({ specId, commitHash, relationType });
38
38
  }
39
39
  /**
@@ -41,13 +41,13 @@ function insertSpecCommitRelation(db, specId, commitHash, relationType) {
41
41
  * (oldest first — matches Commit4Spec's mining pipeline sort).
42
42
  */
43
43
  function findCommitsBySpec(db, specId) {
44
- const rows = db.prepare(`
45
- SELECT r.commit_hash, r.relation_type,
46
- c.message, c.author, c.timestamp
47
- FROM spec_commit_relations r
48
- JOIN commit_nodes c ON c.hash = r.commit_hash
49
- WHERE r.spec_id = ?
50
- ORDER BY c.timestamp ASC
44
+ const rows = db.prepare(`
45
+ SELECT r.commit_hash, r.relation_type,
46
+ c.message, c.author, c.timestamp
47
+ FROM spec_commit_relations r
48
+ JOIN commit_nodes c ON c.hash = r.commit_hash
49
+ WHERE r.spec_id = ?
50
+ ORDER BY c.timestamp ASC
51
51
  `).all(specId);
52
52
  return rows.map(r => ({
53
53
  specId,
@@ -64,10 +64,10 @@ function findCommitsBySpec(db, specId) {
64
64
  * old active spec's relations move to the deprecated record.
65
65
  */
66
66
  function transferSpecCommitRelations(db, fromSpecId, toSpecId) {
67
- db.prepare(`
68
- UPDATE spec_commit_relations
69
- SET spec_id = @toSpecId
70
- WHERE spec_id = @fromSpecId
67
+ db.prepare(`
68
+ UPDATE spec_commit_relations
69
+ SET spec_id = @toSpecId
70
+ WHERE spec_id = @fromSpecId
71
71
  `).run({ fromSpecId, toSpecId });
72
72
  }
73
73
  // ===========================================================================
@@ -78,10 +78,10 @@ function transferSpecCommitRelations(db, fromSpecId, toSpecId) {
78
78
  * `INSERT OR IGNORE` — duplicates are silently skipped.
79
79
  */
80
80
  function insertCommitFragmentRelation(db, commitHash, fragmentId, relationType) {
81
- db.prepare(`
82
- INSERT OR IGNORE INTO commit_fragment_relations
83
- (commit_hash, fragment_id, relation_type)
84
- VALUES (@commitHash, @fragmentId, @relationType)
81
+ db.prepare(`
82
+ INSERT OR IGNORE INTO commit_fragment_relations
83
+ (commit_hash, fragment_id, relation_type)
84
+ VALUES (@commitHash, @fragmentId, @relationType)
85
85
  `).run({ commitHash, fragmentId, relationType });
86
86
  }
87
87
  // ===========================================================================
@@ -92,10 +92,10 @@ function insertCommitFragmentRelation(db, commitHash, fragmentId, relationType)
92
92
  * `INSERT OR IGNORE` — duplicates are silently skipped.
93
93
  */
94
94
  function insertSpecSpecRelation(db, sourceId, targetId, relationType) {
95
- db.prepare(`
96
- INSERT OR IGNORE INTO spec_spec_relations
97
- (source_id, target_id, relation_type)
98
- VALUES (@sourceId, @targetId, @relationType)
95
+ db.prepare(`
96
+ INSERT OR IGNORE INTO spec_spec_relations
97
+ (source_id, target_id, relation_type)
98
+ VALUES (@sourceId, @targetId, @relationType)
99
99
  `).run({ sourceId, targetId, relationType });
100
100
  }
101
101
  /**
@@ -103,10 +103,10 @@ function insertSpecSpecRelation(db, sourceId, targetId, relationType) {
103
103
  * Called when a spec is deprecated (similarity links become stale).
104
104
  */
105
105
  function deleteSimilarToRelations(db, specId) {
106
- db.prepare(`
107
- DELETE FROM spec_spec_relations
108
- WHERE relation_type = 'SIMILAR_TO'
109
- AND (source_id = ? OR target_id = ?)
106
+ db.prepare(`
107
+ DELETE FROM spec_spec_relations
108
+ WHERE relation_type = 'SIMILAR_TO'
109
+ AND (source_id = ? OR target_id = ?)
110
110
  `).run(specId, specId);
111
111
  }
112
112
  /**
@@ -119,27 +119,27 @@ function transferSpecSpecRelations(db, fromSpecId, toSpecId) {
119
119
  // their own explicit BEGIN/COMMIT boundaries.
120
120
  // Delete rows at `toSpecId` that would collide with the rows being
121
121
  // transferred, so the UPDATE below cannot trigger a PRIMARY KEY conflict.
122
- db.prepare(`
123
- DELETE FROM spec_spec_relations
124
- WHERE source_id = @toSpecId
125
- AND (target_id, relation_type) IN (
126
- SELECT target_id, relation_type FROM spec_spec_relations
127
- WHERE source_id = @fromSpecId
128
- )
122
+ db.prepare(`
123
+ DELETE FROM spec_spec_relations
124
+ WHERE source_id = @toSpecId
125
+ AND (target_id, relation_type) IN (
126
+ SELECT target_id, relation_type FROM spec_spec_relations
127
+ WHERE source_id = @fromSpecId
128
+ )
129
129
  `).run({ fromSpecId, toSpecId });
130
- db.prepare(`
131
- DELETE FROM spec_spec_relations
132
- WHERE target_id = @toSpecId
133
- AND (source_id, relation_type) IN (
134
- SELECT source_id, relation_type FROM spec_spec_relations
135
- WHERE target_id = @fromSpecId
136
- )
130
+ db.prepare(`
131
+ DELETE FROM spec_spec_relations
132
+ WHERE target_id = @toSpecId
133
+ AND (source_id, relation_type) IN (
134
+ SELECT source_id, relation_type FROM spec_spec_relations
135
+ WHERE target_id = @fromSpecId
136
+ )
137
137
  `).run({ fromSpecId, toSpecId });
138
- db.prepare(`
139
- UPDATE spec_spec_relations SET source_id = @toSpecId WHERE source_id = @fromSpecId
138
+ db.prepare(`
139
+ UPDATE spec_spec_relations SET source_id = @toSpecId WHERE source_id = @fromSpecId
140
140
  `).run({ fromSpecId, toSpecId });
141
- db.prepare(`
142
- UPDATE spec_spec_relations SET target_id = @toSpecId WHERE target_id = @fromSpecId
141
+ db.prepare(`
142
+ UPDATE spec_spec_relations SET target_id = @toSpecId WHERE target_id = @fromSpecId
143
143
  `).run({ fromSpecId, toSpecId });
144
144
  }
145
145
  // ===========================================================================
@@ -175,10 +175,10 @@ function countAllRelations(db) {
175
175
  */
176
176
  function findSpecIdsByFragmentPath(db, filePath) {
177
177
  const rows = db
178
- .prepare(`SELECT DISTINCT r.spec_id
179
- FROM spec_commit_relations r
180
- JOIN commit_fragment_relations cfr ON cfr.commit_hash = r.commit_hash
181
- JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
178
+ .prepare(`SELECT DISTINCT r.spec_id
179
+ FROM spec_commit_relations r
180
+ JOIN commit_fragment_relations cfr ON cfr.commit_hash = r.commit_hash
181
+ JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
182
182
  WHERE cf.file_path LIKE ?`)
183
183
  .all(`%${filePath}%`);
184
184
  return rows.map((r) => r.spec_id);
@@ -207,13 +207,13 @@ function findSpecsByFilePath(db, filePath, maxResults = DEFAULT_MAX_SPEC_FIND_RE
207
207
  }
208
208
  const pattern = `%${(0, sql_utils_1.escapeLike)(filePath)}%`;
209
209
  const rows = db
210
- .prepare(`SELECT DISTINCT s.id, s.title, s.status, s.version, s.file_path
211
- FROM spec_nodes s
212
- JOIN spec_commit_relations scr ON scr.spec_id = s.id
213
- JOIN commit_fragment_relations cfr ON cfr.commit_hash = scr.commit_hash
214
- JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
215
- WHERE cf.file_path LIKE ? ESCAPE '\\'
216
- ORDER BY s.id
210
+ .prepare(`SELECT DISTINCT s.id, s.title, s.status, s.version, s.file_path
211
+ FROM spec_nodes s
212
+ JOIN spec_commit_relations scr ON scr.spec_id = s.id
213
+ JOIN commit_fragment_relations cfr ON cfr.commit_hash = scr.commit_hash
214
+ JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
215
+ WHERE cf.file_path LIKE ? ESCAPE '\\'
216
+ ORDER BY s.id
217
217
  LIMIT ?`)
218
218
  .all(pattern, maxResults + 1);
219
219
  const truncated = rows.length > maxResults;
@@ -238,29 +238,29 @@ function findSpecsByFilePath(db, filePath, maxResults = DEFAULT_MAX_SPEC_FIND_RE
238
238
  function findSpecCandidatesByFilePath(db, params) {
239
239
  const pathEscaped = (0, sql_utils_1.escapeLike)(params.filePath);
240
240
  const rows = db
241
- .prepare(`
242
- SELECT
243
- s.id, s.title, s.status, s.version, s.file_path, s.timestamp,
244
- MAX(
245
- MIN(cf.end_line, @entityEnd) - MAX(cf.start_line, @entityStart) + 1,
246
- 0
247
- ) AS overlap_lines,
248
- COUNT(DISTINCT cf.id) AS fragment_count,
249
- COUNT(DISTINCT scr.commit_hash) AS commit_count,
250
- MAX(CASE
251
- WHEN cf.file_path = @exactFilePath THEN 3
252
- WHEN cf.file_path LIKE @suffixLikePattern ESCAPE '\\' THEN 2
253
- ELSE 1
254
- END) AS file_path_match_level
255
- FROM spec_nodes s
256
- JOIN spec_commit_relations scr ON scr.spec_id = s.id
257
- JOIN commit_fragment_relations cfr ON cfr.commit_hash = scr.commit_hash
258
- JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
259
- WHERE s.status = 'active'
260
- AND cf.file_path LIKE @likePattern ESCAPE '\\'
261
- GROUP BY s.id
262
- ORDER BY s.timestamp DESC
263
- LIMIT @maxCandidates
241
+ .prepare(`
242
+ SELECT
243
+ s.id, s.title, s.status, s.version, s.file_path, s.timestamp,
244
+ MAX(
245
+ MIN(cf.end_line, @entityEnd) - MAX(cf.start_line, @entityStart) + 1,
246
+ 0
247
+ ) AS overlap_lines,
248
+ COUNT(DISTINCT cf.id) AS fragment_count,
249
+ COUNT(DISTINCT scr.commit_hash) AS commit_count,
250
+ MAX(CASE
251
+ WHEN cf.file_path = @exactFilePath THEN 3
252
+ WHEN cf.file_path LIKE @suffixLikePattern ESCAPE '\\' THEN 2
253
+ ELSE 1
254
+ END) AS file_path_match_level
255
+ FROM spec_nodes s
256
+ JOIN spec_commit_relations scr ON scr.spec_id = s.id
257
+ JOIN commit_fragment_relations cfr ON cfr.commit_hash = scr.commit_hash
258
+ JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
259
+ WHERE s.status = 'active'
260
+ AND cf.file_path LIKE @likePattern ESCAPE '\\'
261
+ GROUP BY s.id
262
+ ORDER BY s.timestamp DESC
263
+ LIMIT @maxCandidates
264
264
  `)
265
265
  .all({
266
266
  entityEnd: params.endLine,
@@ -291,11 +291,11 @@ function findSpecIdsByFragmentIds(db, fragmentIds) {
291
291
  return [];
292
292
  const placeholders = fragmentIds.map(() => '?').join(',');
293
293
  const rows = db
294
- .prepare(`
295
- SELECT DISTINCT scr.spec_id
296
- FROM commit_fragment_relations cfr
297
- JOIN spec_commit_relations scr ON scr.commit_hash = cfr.commit_hash
298
- WHERE cfr.fragment_id IN (${placeholders})
294
+ .prepare(`
295
+ SELECT DISTINCT scr.spec_id
296
+ FROM commit_fragment_relations cfr
297
+ JOIN spec_commit_relations scr ON scr.commit_hash = cfr.commit_hash
298
+ WHERE cfr.fragment_id IN (${placeholders})
299
299
  `)
300
300
  .all(...fragmentIds);
301
301
  return rows.map((r) => r.spec_id);
@@ -306,10 +306,10 @@ function findSpecIdsByFragmentIds(db, fragmentIds) {
306
306
  */
307
307
  function findFragmentPathsBySpec(db, specId) {
308
308
  const rows = db
309
- .prepare(`SELECT DISTINCT cf.file_path
310
- FROM spec_commit_relations scr
311
- JOIN commit_fragment_relations cfr ON cfr.commit_hash = scr.commit_hash
312
- JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
309
+ .prepare(`SELECT DISTINCT cf.file_path
310
+ FROM spec_commit_relations scr
311
+ JOIN commit_fragment_relations cfr ON cfr.commit_hash = scr.commit_hash
312
+ JOIN code_fragment_nodes cf ON cf.id = cfr.fragment_id
313
313
  WHERE scr.spec_id = ?`)
314
314
  .all(specId);
315
315
  return rows.map((r) => r.file_path);
@@ -93,12 +93,12 @@ function runSpecMigrations(db, fromVersion) {
93
93
  // Create the FTS5 virtual table — the IF NOT EXISTS in schema.sql
94
94
  // handles the case where DDL already ran, but we explicitly run it
95
95
  // here for databases that existed before this migration was added.
96
- db.exec(`
97
- CREATE VIRTUAL TABLE IF NOT EXISTS code_fragments_fts USING fts5(
98
- id,
99
- file_path,
100
- code_diff
101
- );
96
+ db.exec(`
97
+ CREATE VIRTUAL TABLE IF NOT EXISTS code_fragments_fts USING fts5(
98
+ id,
99
+ file_path,
100
+ code_diff
101
+ );
102
102
  `);
103
103
  // Populate FTS from existing code_fragment_nodes data
104
104
  const count = db.prepare('SELECT COUNT(*) as cnt FROM code_fragments_fts').get().cnt;
@@ -1,121 +1,121 @@
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
- relation_type TEXT NOT NULL,
58
- PRIMARY KEY (commit_hash, fragment_id, relation_type),
59
- FOREIGN KEY (commit_hash) REFERENCES commit_nodes(hash) ON DELETE CASCADE,
60
- FOREIGN KEY (fragment_id) REFERENCES code_fragment_nodes(id) ON DELETE CASCADE
61
- );
62
-
63
- CREATE TABLE IF NOT EXISTS spec_spec_relations (
64
- source_id TEXT NOT NULL,
65
- target_id TEXT NOT NULL,
66
- relation_type TEXT NOT NULL, -- 'SIMILAR_TO' | 'EVOLVED_FROM'
67
- PRIMARY KEY (source_id, target_id, relation_type),
68
- FOREIGN KEY (source_id) REFERENCES spec_nodes(id) ON DELETE CASCADE,
69
- FOREIGN KEY (target_id) REFERENCES spec_nodes(id) ON DELETE CASCADE
70
- );
71
-
72
- -- =============================================================================
73
- -- Full-Text Search (standalone — CJK-segmented on insert)
74
- -- =============================================================================
75
-
76
- CREATE VIRTUAL TABLE IF NOT EXISTS specs_fts USING fts5(
77
- id,
78
- title,
79
- subtitles
80
- );
81
-
82
- -- NOTE: `runSpecMigrations` in schema.ts mirrors some of this DDL to patch
83
- -- pre-existing databases. Keep the two in sync when adding migrations.
84
-
85
- CREATE VIRTUAL TABLE IF NOT EXISTS code_fragments_fts USING fts5(
86
- id,
87
- file_path,
88
- code_diff
89
- );
90
-
91
- -- =============================================================================
92
- -- Indexes
93
- -- =============================================================================
94
-
95
- CREATE INDEX IF NOT EXISTS idx_spec_nodes_status ON spec_nodes(status);
96
- CREATE INDEX IF NOT EXISTS idx_spec_nodes_file_path ON spec_nodes(file_path);
97
- CREATE INDEX IF NOT EXISTS idx_commit_nodes_timestamp ON commit_nodes(timestamp);
98
- CREATE INDEX IF NOT EXISTS idx_code_fragment_file_path ON code_fragment_nodes(file_path);
99
- CREATE INDEX IF NOT EXISTS idx_code_fragment_path_lines ON code_fragment_nodes(file_path, start_line, end_line);
100
- CREATE INDEX IF NOT EXISTS idx_scr_spec_id ON spec_commit_relations(spec_id);
101
- CREATE INDEX IF NOT EXISTS idx_scr_commit_hash ON spec_commit_relations(commit_hash);
102
- CREATE INDEX IF NOT EXISTS idx_cfr_commit_hash ON commit_fragment_relations(commit_hash);
103
- CREATE INDEX IF NOT EXISTS idx_cfr_fragment_id ON commit_fragment_relations(fragment_id);
104
- CREATE INDEX IF NOT EXISTS idx_ssr_source ON spec_spec_relations(source_id);
105
- CREATE INDEX IF NOT EXISTS idx_ssr_target ON spec_spec_relations(target_id);
106
-
107
- -- =============================================================================
108
- -- Schema Version
109
- -- =============================================================================
110
-
111
- CREATE TABLE IF NOT EXISTS spec_schema_versions (
112
- version INTEGER PRIMARY KEY,
113
- applied_at INTEGER NOT NULL,
114
- description TEXT
115
- );
116
-
117
- INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description)
118
- VALUES (1, strftime('%s', 'now') * 1000, 'Initial Commit4Spec schema');
119
-
120
- INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description)
121
- VALUES (2, strftime('%s', 'now') * 1000, 'Add code_fragments_fts for content-based fragment search');
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
+ relation_type TEXT NOT NULL,
58
+ PRIMARY KEY (commit_hash, fragment_id, relation_type),
59
+ FOREIGN KEY (commit_hash) REFERENCES commit_nodes(hash) ON DELETE CASCADE,
60
+ FOREIGN KEY (fragment_id) REFERENCES code_fragment_nodes(id) ON DELETE CASCADE
61
+ );
62
+
63
+ CREATE TABLE IF NOT EXISTS spec_spec_relations (
64
+ source_id TEXT NOT NULL,
65
+ target_id TEXT NOT NULL,
66
+ relation_type TEXT NOT NULL, -- 'SIMILAR_TO' | 'EVOLVED_FROM'
67
+ PRIMARY KEY (source_id, target_id, relation_type),
68
+ FOREIGN KEY (source_id) REFERENCES spec_nodes(id) ON DELETE CASCADE,
69
+ FOREIGN KEY (target_id) REFERENCES spec_nodes(id) ON DELETE CASCADE
70
+ );
71
+
72
+ -- =============================================================================
73
+ -- Full-Text Search (standalone — CJK-segmented on insert)
74
+ -- =============================================================================
75
+
76
+ CREATE VIRTUAL TABLE IF NOT EXISTS specs_fts USING fts5(
77
+ id,
78
+ title,
79
+ subtitles
80
+ );
81
+
82
+ -- NOTE: `runSpecMigrations` in schema.ts mirrors some of this DDL to patch
83
+ -- pre-existing databases. Keep the two in sync when adding migrations.
84
+
85
+ CREATE VIRTUAL TABLE IF NOT EXISTS code_fragments_fts USING fts5(
86
+ id,
87
+ file_path,
88
+ code_diff
89
+ );
90
+
91
+ -- =============================================================================
92
+ -- Indexes
93
+ -- =============================================================================
94
+
95
+ CREATE INDEX IF NOT EXISTS idx_spec_nodes_status ON spec_nodes(status);
96
+ CREATE INDEX IF NOT EXISTS idx_spec_nodes_file_path ON spec_nodes(file_path);
97
+ CREATE INDEX IF NOT EXISTS idx_commit_nodes_timestamp ON commit_nodes(timestamp);
98
+ CREATE INDEX IF NOT EXISTS idx_code_fragment_file_path ON code_fragment_nodes(file_path);
99
+ CREATE INDEX IF NOT EXISTS idx_code_fragment_path_lines ON code_fragment_nodes(file_path, start_line, end_line);
100
+ CREATE INDEX IF NOT EXISTS idx_scr_spec_id ON spec_commit_relations(spec_id);
101
+ CREATE INDEX IF NOT EXISTS idx_scr_commit_hash ON spec_commit_relations(commit_hash);
102
+ CREATE INDEX IF NOT EXISTS idx_cfr_commit_hash ON commit_fragment_relations(commit_hash);
103
+ CREATE INDEX IF NOT EXISTS idx_cfr_fragment_id ON commit_fragment_relations(fragment_id);
104
+ CREATE INDEX IF NOT EXISTS idx_ssr_source ON spec_spec_relations(source_id);
105
+ CREATE INDEX IF NOT EXISTS idx_ssr_target ON spec_spec_relations(target_id);
106
+
107
+ -- =============================================================================
108
+ -- Schema Version
109
+ -- =============================================================================
110
+
111
+ CREATE TABLE IF NOT EXISTS spec_schema_versions (
112
+ version INTEGER PRIMARY KEY,
113
+ applied_at INTEGER NOT NULL,
114
+ description TEXT
115
+ );
116
+
117
+ INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description)
118
+ VALUES (1, strftime('%s', 'now') * 1000, 'Initial Commit4Spec schema');
119
+
120
+ INSERT OR IGNORE INTO spec_schema_versions (version, applied_at, description)
121
+ VALUES (2, strftime('%s', 'now') * 1000, 'Add code_fragments_fts for content-based fragment search');
@@ -50,10 +50,10 @@ function rowToSpec(row) {
50
50
  */
51
51
  function insertSpecNode(db, node) {
52
52
  const subtitlesJson = JSON.stringify(node.subtitles);
53
- db.prepare(`
54
- INSERT OR REPLACE INTO spec_nodes
55
- (id, title, subtitles, status, version, file_path, timestamp)
56
- VALUES (@id, @title, @subtitles, @status, @version, @filePath, @timestamp)
53
+ db.prepare(`
54
+ INSERT OR REPLACE INTO spec_nodes
55
+ (id, title, subtitles, status, version, file_path, timestamp)
56
+ VALUES (@id, @title, @subtitles, @status, @version, @filePath, @timestamp)
57
57
  `).run({
58
58
  id: node.id,
59
59
  title: node.title,