homegraph 1.5.1 → 1.5.2

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 (258) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +305 -305
  3. package/dist/bin/homegraph.js +9 -9
  4. package/dist/db/index.js +36 -36
  5. package/dist/db/migrations.js +37 -37
  6. package/dist/db/queries.js +156 -156
  7. package/dist/db/schema.sql +203 -203
  8. package/dist/directory.js +5 -5
  9. package/dist/extraction/index.d.ts +1 -1
  10. package/dist/extraction/index.d.ts.map +1 -1
  11. package/dist/extraction/index.js +54 -43
  12. package/dist/extraction/index.js.map +1 -1
  13. package/dist/extraction/languages/arkts.d.ts +53 -6
  14. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  15. package/dist/extraction/languages/arkts.js +565 -65
  16. package/dist/extraction/languages/arkts.js.map +1 -1
  17. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  18. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  19. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  20. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  21. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  22. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  23. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  24. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  25. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +3 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/installer/instructions-template.js +9 -9
  30. package/dist/mcp/diff-impact.d.ts +131 -0
  31. package/dist/mcp/diff-impact.d.ts.map +1 -0
  32. package/dist/mcp/diff-impact.js +385 -0
  33. package/dist/mcp/diff-impact.js.map +1 -0
  34. package/dist/mcp/liveness-watchdog.js +51 -51
  35. package/dist/mcp/server-instructions.d.ts +1 -1
  36. package/dist/mcp/server-instructions.d.ts.map +1 -1
  37. package/dist/mcp/server-instructions.js +49 -47
  38. package/dist/mcp/server-instructions.js.map +1 -1
  39. package/dist/mcp/tools.d.ts +21 -5
  40. package/dist/mcp/tools.d.ts.map +1 -1
  41. package/dist/mcp/tools.js +305 -55
  42. package/dist/mcp/tools.js.map +1 -1
  43. package/dist/resolution/callback-synthesizer.d.ts +2 -1
  44. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  45. package/dist/resolution/callback-synthesizer.js +153 -53
  46. package/dist/resolution/callback-synthesizer.js.map +1 -1
  47. package/dist/resolution/frameworks/arkts-entry.d.ts.map +1 -1
  48. package/dist/resolution/frameworks/arkts-entry.js +20 -9
  49. package/dist/resolution/frameworks/arkts-entry.js.map +1 -1
  50. package/dist/resolution/index.d.ts.map +1 -1
  51. package/dist/resolution/index.js +1 -1
  52. package/dist/resolution/index.js.map +1 -1
  53. package/dist/resolution/memory-budget.d.ts +33 -0
  54. package/dist/resolution/memory-budget.d.ts.map +1 -1
  55. package/dist/resolution/memory-budget.js +58 -0
  56. package/dist/resolution/memory-budget.js.map +1 -1
  57. package/dist/resolution/resolver-pool.d.ts +2 -0
  58. package/dist/resolution/resolver-pool.d.ts.map +1 -1
  59. package/dist/resolution/resolver-pool.js +4 -0
  60. package/dist/resolution/resolver-pool.js.map +1 -1
  61. package/dist/spec/db/commit-node.js +4 -4
  62. package/dist/spec/db/fragment-node.js +10 -10
  63. package/dist/spec/db/fts.js +8 -8
  64. package/dist/spec/db/relations.js +88 -88
  65. package/dist/spec/db/schema.js +6 -6
  66. package/dist/spec/db/schema.sql +121 -121
  67. package/dist/spec/db/spec-node.js +4 -4
  68. package/dist/spec/llm/prompts.js +53 -53
  69. package/dist/ui/shimmer-progress.d.ts.map +1 -1
  70. package/dist/ui/shimmer-progress.js +4 -1
  71. package/dist/ui/shimmer-progress.js.map +1 -1
  72. package/package.json +61 -62
  73. package/dist/extraction/languages/arkts-viewtree.d.ts +0 -22
  74. package/dist/extraction/languages/arkts-viewtree.d.ts.map +0 -1
  75. package/dist/extraction/languages/arkts-viewtree.js +0 -133
  76. package/dist/extraction/languages/arkts-viewtree.js.map +0 -1
  77. package/dist/reasoning/config.d.ts +0 -45
  78. package/dist/reasoning/config.d.ts.map +0 -1
  79. package/dist/reasoning/config.js +0 -171
  80. package/dist/reasoning/config.js.map +0 -1
  81. package/dist/reasoning/credentials.d.ts +0 -5
  82. package/dist/reasoning/credentials.d.ts.map +0 -1
  83. package/dist/reasoning/credentials.js +0 -83
  84. package/dist/reasoning/credentials.js.map +0 -1
  85. package/dist/reasoning/login.d.ts +0 -21
  86. package/dist/reasoning/login.d.ts.map +0 -1
  87. package/dist/reasoning/login.js +0 -85
  88. package/dist/reasoning/login.js.map +0 -1
  89. package/dist/reasoning/reasoner.d.ts +0 -43
  90. package/dist/reasoning/reasoner.d.ts.map +0 -1
  91. package/dist/reasoning/reasoner.js +0 -308
  92. package/dist/reasoning/reasoner.js.map +0 -1
  93. package/dist/spec/evolve/llm-client.d.ts +0 -50
  94. package/dist/spec/evolve/llm-client.d.ts.map +0 -1
  95. package/dist/spec/evolve/llm-client.js +0 -176
  96. package/dist/spec/evolve/llm-client.js.map +0 -1
  97. package/dist/spec/evolve/logic-checker.d.ts +0 -12
  98. package/dist/spec/evolve/logic-checker.d.ts.map +0 -1
  99. package/dist/spec/evolve/logic-checker.js +0 -24
  100. package/dist/spec/evolve/logic-checker.js.map +0 -1
  101. package/dist/spec/llm/index.d.ts +0 -3
  102. package/dist/spec/llm/index.d.ts.map +0 -1
  103. package/dist/spec/llm/index.js +0 -11
  104. package/dist/spec/llm/index.js.map +0 -1
  105. package/dist/spec/mining/diff-parser.d.ts +0 -33
  106. package/dist/spec/mining/diff-parser.d.ts.map +0 -1
  107. package/dist/spec/mining/diff-parser.js +0 -166
  108. package/dist/spec/mining/diff-parser.js.map +0 -1
  109. package/dist/spec/mining/git-scanner.d.ts +0 -103
  110. package/dist/spec/mining/git-scanner.d.ts.map +0 -1
  111. package/dist/spec/mining/git-scanner.js +0 -307
  112. package/dist/spec/mining/git-scanner.js.map +0 -1
  113. package/dist/spec/mining/pipeline.d.ts +0 -53
  114. package/dist/spec/mining/pipeline.d.ts.map +0 -1
  115. package/dist/spec/mining/pipeline.js +0 -178
  116. package/dist/spec/mining/pipeline.js.map +0 -1
  117. package/dist/spec/mining/scope-resolver.d.ts +0 -45
  118. package/dist/spec/mining/scope-resolver.d.ts.map +0 -1
  119. package/dist/spec/mining/scope-resolver.js +0 -103
  120. package/dist/spec/mining/scope-resolver.js.map +0 -1
  121. package/dist/spec/mining/spec-extractor.d.ts +0 -69
  122. package/dist/spec/mining/spec-extractor.d.ts.map +0 -1
  123. package/dist/spec/mining/spec-extractor.js +0 -369
  124. package/dist/spec/mining/spec-extractor.js.map +0 -1
  125. package/dist/spec/utils.d.ts +0 -167
  126. package/dist/spec/utils.d.ts.map +0 -1
  127. package/dist/spec/utils.js +0 -463
  128. package/dist/spec/utils.js.map +0 -1
  129. package/scripts/_tmp-cfwk-resolve.log +0 -0
  130. package/scripts/_tmp-cfwk-sig.log +0 -0
  131. package/scripts/_tmp-cfwk-vt.log +0 -0
  132. package/scripts/add-lang/bench.sh +0 -60
  133. package/scripts/add-lang/check-grammar.mjs +0 -75
  134. package/scripts/add-lang/dump-ast.mjs +0 -103
  135. package/scripts/add-lang/verify-extraction.mjs +0 -70
  136. package/scripts/agent-eval/ab-adoption.sh +0 -91
  137. package/scripts/agent-eval/ab-hook.sh +0 -86
  138. package/scripts/agent-eval/ab-impl.sh +0 -78
  139. package/scripts/agent-eval/ab-new-vs-baseline.sh +0 -102
  140. package/scripts/agent-eval/ab-sufficiency.sh +0 -78
  141. package/scripts/agent-eval/arms-F.sh +0 -21
  142. package/scripts/agent-eval/arms-matrix.sh +0 -37
  143. package/scripts/agent-eval/audit.sh +0 -68
  144. package/scripts/agent-eval/bench-readme.sh +0 -28
  145. package/scripts/agent-eval/bench-why-repo.sh +0 -22
  146. package/scripts/agent-eval/block-read-hook.sh +0 -19
  147. package/scripts/agent-eval/hook-settings.json +0 -15
  148. package/scripts/agent-eval/itrun.sh +0 -120
  149. package/scripts/agent-eval/offload-eval-3arm.sh +0 -72
  150. package/scripts/agent-eval/offload-eval-cost.mjs +0 -133
  151. package/scripts/agent-eval/offload-eval-effort.mjs +0 -108
  152. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +0 -25
  153. package/scripts/agent-eval/offload-eval-frontload.sh +0 -47
  154. package/scripts/agent-eval/offload-eval-ground-truth.json +0 -18
  155. package/scripts/agent-eval/offload-eval-hook.mjs +0 -84
  156. package/scripts/agent-eval/offload-eval-judge.mjs +0 -103
  157. package/scripts/agent-eval/offload-eval-matrix.sh +0 -20
  158. package/scripts/agent-eval/offload-eval-metrics.mjs +0 -94
  159. package/scripts/agent-eval/offload-eval-refs1.sh +0 -50
  160. package/scripts/agent-eval/offload-eval-setup.sh +0 -24
  161. package/scripts/agent-eval/offload-eval-styles.sh +0 -72
  162. package/scripts/agent-eval/offload-eval-summarize.mjs +0 -68
  163. package/scripts/agent-eval/offload-eval.md +0 -76
  164. package/scripts/agent-eval/parse-arms.mjs +0 -116
  165. package/scripts/agent-eval/parse-bench-readme.mjs +0 -84
  166. package/scripts/agent-eval/parse-run.mjs +0 -45
  167. package/scripts/agent-eval/parse-session.mjs +0 -93
  168. package/scripts/agent-eval/probe-context.mjs +0 -21
  169. package/scripts/agent-eval/probe-explore.mjs +0 -40
  170. package/scripts/agent-eval/probe-node.mjs +0 -20
  171. package/scripts/agent-eval/probe-sweep.mjs +0 -119
  172. package/scripts/agent-eval/probe-trace.mjs +0 -20
  173. package/scripts/agent-eval/redirect-read-hook.sh +0 -38
  174. package/scripts/agent-eval/repro-concurrent-explore.mjs +0 -119
  175. package/scripts/agent-eval/repro-daemon-clients.mjs +0 -125
  176. package/scripts/agent-eval/run-agent.sh +0 -34
  177. package/scripts/agent-eval/run-all.sh +0 -75
  178. package/scripts/agent-eval/run-arms.sh +0 -56
  179. package/scripts/agent-eval/seq-matrix.mjs +0 -137
  180. package/scripts/bench-arkts-init-rss.log +0 -0
  181. package/scripts/build-bundle.sh +0 -123
  182. package/scripts/exp_boundary_eval/README.md +0 -247
  183. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  184. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-38.pyc +0 -0
  185. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  186. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-38.pyc +0 -0
  187. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-38.pyc +0 -0
  188. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-310.pyc +0 -0
  189. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-38.pyc +0 -0
  190. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  191. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-38.pyc +0 -0
  192. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  193. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-38.pyc +0 -0
  194. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  195. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-38.pyc +0 -0
  196. package/scripts/exp_boundary_eval/__pycache__/win_mcp_launcher.cpython-38.pyc +0 -0
  197. package/scripts/exp_boundary_eval/_test_mcp_chain.py +0 -78
  198. package/scripts/exp_boundary_eval/_test_stdin.py +0 -8
  199. package/scripts/exp_boundary_eval/_utils.py +0 -1116
  200. package/scripts/exp_boundary_eval/analyze.py +0 -1313
  201. package/scripts/exp_boundary_eval/deveco_arm.py +0 -519
  202. package/scripts/exp_boundary_eval/run_all.py +0 -378
  203. package/scripts/exp_boundary_eval/run_one.py +0 -165
  204. package/scripts/exp_boundary_eval/run_session.py +0 -158
  205. package/scripts/exp_boundary_eval/setup.py +0 -120
  206. package/scripts/exp_boundary_eval/win_mcp_launcher.py +0 -73
  207. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +0 -36
  208. package/scripts/exp_boundary_eval/win_node_launcher.py +0 -24
  209. package/scripts/extract-release-notes.mjs +0 -130
  210. package/scripts/local-install.sh +0 -41
  211. package/scripts/npm-sdk.js +0 -75
  212. package/scripts/npm-shim.js +0 -275
  213. package/scripts/ohos-sdk-publish.mjs +0 -133
  214. package/scripts/pack-npm.sh +0 -119
  215. package/scripts/prepare-release.mjs +0 -270
  216. package/scripts/probe-arkts-mem-why-run.log +0 -0
  217. package/scripts/probe-banner-livecard-ir.log +0 -0
  218. package/scripts/probe-cfwk-ast.stderr.log +0 -0
  219. package/scripts/probe-cfwk-ast.stdout.log +0 -0
  220. package/scripts/probe-cfwk-attr-shape.log +0 -0
  221. package/scripts/probe-cfwk-cfgdump.stderr.log +0 -0
  222. package/scripts/probe-cfwk-cfgdump.stdout.log +0 -0
  223. package/scripts/probe-cfwk-cvc.stderr.log +0 -0
  224. package/scripts/probe-cfwk-cvc.stdout.log +0 -0
  225. package/scripts/probe-cfwk-diag2.log +0 -0
  226. package/scripts/probe-cfwk-diag3.log +0 -0
  227. package/scripts/probe-cfwk-fedbg.stderr.log +0 -0
  228. package/scripts/probe-cfwk-fedbg.stdout.log +0 -0
  229. package/scripts/probe-cfwk-fileresult.log +0 -0
  230. package/scripts/probe-cfwk-fix.stderr.log +0 -0
  231. package/scripts/probe-cfwk-fix.stdout.log +0 -0
  232. package/scripts/probe-cfwk-fix2.stderr.log +0 -0
  233. package/scripts/probe-cfwk-fix2.stdout.log +0 -0
  234. package/scripts/probe-cfwk-fix3.stderr.log +0 -0
  235. package/scripts/probe-cfwk-fix3.stdout.log +0 -0
  236. package/scripts/probe-cfwk-foreach.log +0 -0
  237. package/scripts/probe-cfwk-getmethod-throw.log +0 -0
  238. package/scripts/probe-cfwk-hg-extract.log +0 -0
  239. package/scripts/probe-cfwk-pr1003-noprior.stderr.log +0 -0
  240. package/scripts/probe-cfwk-pr1003-noprior.stdout.log +0 -0
  241. package/scripts/probe-cfwk-pr1003.stderr.log +0 -0
  242. package/scripts/probe-cfwk-pr1003.stdout.log +0 -0
  243. package/scripts/probe-cfwk-preroot-noprior.stderr.log +0 -0
  244. package/scripts/probe-cfwk-preroot-noprior.stdout.log +0 -0
  245. package/scripts/probe-cfwk-preroot-prior.stderr.log +0 -0
  246. package/scripts/probe-cfwk-preroot-prior.stdout.log +0 -0
  247. package/scripts/probe-cfwk-preroot-skipstate.stderr.log +0 -0
  248. package/scripts/probe-cfwk-preroot-skipstate.stdout.log +0 -0
  249. package/scripts/probe-cfwk-resolve-sim.log +0 -0
  250. package/scripts/probe-cfwk-tree-shape.log +0 -0
  251. package/scripts/probe-cfwk-walk-abort.log +0 -0
  252. package/scripts/probe-cfwk.log +0 -0
  253. package/scripts/probe-force-index.log +0 -0
  254. package/scripts/probe-no-force-index.log +0 -0
  255. package/scripts/probe-samefile-ir.stderr.log +0 -0
  256. package/scripts/probe-samefile-ir.stdout.log +0 -224
  257. package/scripts/probe-sdk-vs-project.log +0 -0
  258. package/scripts/probe-viewtree-downgrade.log +0 -0
@@ -1,369 +0,0 @@
1
- "use strict";
2
- /**
3
- * Spec file discovery and metadata extraction.
4
- *
5
- * Replaces `commit4spec/reverse_engineer/spec_extractor.py`.
6
- * Discovers spec files in a storage directory and extracts structured
7
- * metadata (title, subtitles, commit hash from commit-info.md).
8
- *
9
- * @module spec/mining/spec-extractor
10
- */
11
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- var desc = Object.getOwnPropertyDescriptor(m, k);
14
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
- desc = { enumerable: true, get: function() { return m[k]; } };
16
- }
17
- Object.defineProperty(o, k2, desc);
18
- }) : (function(o, m, k, k2) {
19
- if (k2 === undefined) k2 = k;
20
- o[k2] = m[k];
21
- }));
22
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
- Object.defineProperty(o, "default", { enumerable: true, value: v });
24
- }) : function(o, v) {
25
- o["default"] = v;
26
- });
27
- var __importStar = (this && this.__importStar) || (function () {
28
- var ownKeys = function(o) {
29
- ownKeys = Object.getOwnPropertyNames || function (o) {
30
- var ar = [];
31
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
- return ar;
33
- };
34
- return ownKeys(o);
35
- };
36
- return function (mod) {
37
- if (mod && mod.__esModule) return mod;
38
- var result = {};
39
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
- __setModuleDefault(result, mod);
41
- return result;
42
- };
43
- })();
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.extractMarkdownHeadings = extractMarkdownHeadings;
46
- exports.extractSpecMetadata = extractSpecMetadata;
47
- const fs = __importStar(require("fs"));
48
- const path = __importStar(require("path"));
49
- const config_1 = require("../config");
50
- const utils_1 = require("../utils");
51
- const errors_1 = require("../../errors");
52
- // ---------------------------------------------------------------------------
53
- // Constants
54
- // ---------------------------------------------------------------------------
55
- const HEADING_RE = /^(#{1,6})\s+(.*)/;
56
- // ---------------------------------------------------------------------------
57
- // extractMarkdownHeadings
58
- // ---------------------------------------------------------------------------
59
- /**
60
- * Parse ATX headings from markdown content and build breadcrumb-path strings
61
- * with content previews.
62
- *
63
- * Algorithm (ported from `spec_extractor.py:50-88`):
64
- *
65
- * 1. Find all `#` … `######` headings (ATX-style) and their line positions.
66
- * 2. Walk through headings, maintaining a breadcrumb stack — pop until the
67
- * stack is shorter than the current heading's level, then push the new
68
- * heading text.
69
- * 3. For each heading, collect the "direct content" lines — non-heading,
70
- * non-empty lines between this heading and the next heading of equal or
71
- * higher level (or EOF).
72
- * 4. Skip headings that have sub-headings but no direct content.
73
- * 5. Build a display string: `breadcrumb_path - first_direct_content_line`.
74
- * 6. Strip `SPEC` suffix from level-1 (root) breadcrumb parts.
75
- * 7. Truncate the preview to `maxContentLen` characters, appending `…`
76
- * when truncated.
77
- *
78
- * @param content - Raw markdown string.
79
- * @param maxContentLen - Max characters for the content preview (default 200).
80
- * @returns Array of formatted heading strings.
81
- */
82
- function extractMarkdownHeadings(content, maxContentLen = 200) {
83
- const lines = content.split('\n');
84
- const headings = [];
85
- for (let i = 0; i < lines.length; i++) {
86
- const match = HEADING_RE.exec(lines[i]);
87
- if (!match)
88
- continue;
89
- const text = match[2].trim();
90
- if (!text)
91
- continue;
92
- headings.push({
93
- lineIndex: i,
94
- level: match[1].length,
95
- text,
96
- });
97
- }
98
- // Second pass: build breadcrumb and collect direct content.
99
- const breadcrumb = [];
100
- const result = [];
101
- for (let hi = 0; hi < headings.length; hi++) {
102
- const h = headings[hi];
103
- // Adjust breadcrumb: pop until we're at the right depth.
104
- while (breadcrumb.length >= h.level) {
105
- breadcrumb.pop();
106
- }
107
- breadcrumb.push(h.text);
108
- // Determine the end line of this heading's content section.
109
- // The section ends at the next heading of equal or higher level (or EOF).
110
- let endLine = lines.length;
111
- for (let hj = hi + 1; hj < headings.length; hj++) {
112
- const nextH = headings[hj];
113
- if (nextH.level <= h.level) {
114
- endLine = nextH.lineIndex;
115
- break;
116
- }
117
- }
118
- // Collect direct content: non-heading, non-empty lines within this section.
119
- const directLines = [];
120
- let hasSubHeadings = false;
121
- for (let li = h.lineIndex + 1; li < endLine; li++) {
122
- const line = lines[li].trim();
123
- if (!line)
124
- continue;
125
- if (HEADING_RE.test(line)) {
126
- hasSubHeadings = true;
127
- continue;
128
- }
129
- directLines.push(line);
130
- }
131
- // Skip headings that only contain sub-headings (no direct text).
132
- if (hasSubHeadings && directLines.length === 0) {
133
- continue;
134
- }
135
- // Build the display path.
136
- let display = breadcrumb.join(' → ');
137
- // Strip trailing SPEC from level-1 (root) headings.
138
- if (breadcrumb.length === 1) {
139
- display = display.replace(/\s*SPEC\s*$/i, '');
140
- }
141
- // Append content preview (first direct line, truncated).
142
- if (directLines.length > 0) {
143
- let preview = directLines[0];
144
- if (preview.length > maxContentLen) {
145
- preview = preview.slice(0, maxContentLen) + '…';
146
- }
147
- display += ' - ' + preview;
148
- }
149
- result.push(display);
150
- }
151
- return result;
152
- }
153
- // ---------------------------------------------------------------------------
154
- // _findPrimaryDoc
155
- // ---------------------------------------------------------------------------
156
- /**
157
- * Find the primary spec document by trying each candidate name.
158
- *
159
- * Replaces the `{spec_dir}` placeholder in each candidate with `specDirName`,
160
- * then checks whether the resolved file exists in `specDirPath`. Returns the
161
- * first match as `[resolvedName, absolutePath]`, or `null` when no candidate
162
- * matches.
163
- *
164
- * Ported from `spec_extractor.py:94-114`.
165
- */
166
- function _findPrimaryDoc(specDirPath, specDirName, candidates) {
167
- for (const candidate of candidates) {
168
- const resolved = candidate.replace(/\{spec_dir\}/g, specDirName);
169
- const absPath = path.join(specDirPath, resolved);
170
- if (fs.existsSync(absPath)) {
171
- return [resolved, absPath];
172
- }
173
- }
174
- return null;
175
- }
176
- // ---------------------------------------------------------------------------
177
- // Glob helper
178
- // ---------------------------------------------------------------------------
179
- /**
180
- * Simple glob-to-regex conversion for supplementary document matching.
181
- *
182
- * Only handles `*` (any non-separator characters) and literal text.
183
- * Does not support `**`, `?`, or character classes — sufficient for
184
- * patterns like `"*.md"` or `"changelog-*.md"`.
185
- */
186
- function globToRegex(glob) {
187
- // Escape regex-special characters except *
188
- let pattern = '';
189
- for (const ch of glob) {
190
- if (ch === '*') {
191
- pattern += '[^/]*';
192
- }
193
- else if ('.+^${}()|[]\\'.includes(ch)) {
194
- pattern += '\\' + ch;
195
- }
196
- else {
197
- pattern += ch;
198
- }
199
- }
200
- return new RegExp('^' + pattern + '$');
201
- }
202
- // ---------------------------------------------------------------------------
203
- // _buildMetadata
204
- // ---------------------------------------------------------------------------
205
- /**
206
- * Build `SpecMetadata` from raw spec content and supplementary documents.
207
- *
208
- * Ported from `spec_extractor.py:120-171`.
209
- *
210
- * 1. Extract a title from the first `# ` heading (stripping a trailing
211
- * `SPEC` suffix); fallback to `specId`.
212
- * 2. Collect subtitles via `extractMarkdownHeadings`.
213
- * 3. Discover supplementary `.md` files in `specDirPath` that match
214
- * `config.supplementaryGlobs` (excluding the primary doc) and merge
215
- * their headings into the subtitle list.
216
- * 4. Resolve a commit hash from `commit-info.md` content in `specDirPath`
217
- * (using `config.commitInfoCandidates`).
218
- */
219
- function _buildMetadata(specId, content, filePath, specDirPath, config) {
220
- // ---- title ----
221
- let title = specId;
222
- const firstH1Match = content.match(/^#\s+(.*)/m);
223
- if (firstH1Match && firstH1Match[1]) {
224
- title = firstH1Match[1].trim().replace(/\s*SPEC\s*$/i, '');
225
- if (!title) {
226
- title = specId;
227
- }
228
- }
229
- // ---- subtitles from primary doc ----
230
- const subtitles = extractMarkdownHeadings(content);
231
- // ---- supplementary docs ----
232
- // Find the primary doc's filename so we can skip it.
233
- const primaryDocName = path.basename(filePath);
234
- let dirEntries;
235
- try {
236
- dirEntries = fs.readdirSync(specDirPath, { withFileTypes: true });
237
- }
238
- catch {
239
- dirEntries = [];
240
- }
241
- const globRegexes = config.supplementaryGlobs.map((g) => globToRegex(g));
242
- for (const entry of dirEntries) {
243
- if (!entry.isFile())
244
- continue;
245
- if (!entry.name.endsWith('.md'))
246
- continue;
247
- if (entry.name === primaryDocName)
248
- continue;
249
- // Check if the file name matches any supplementary glob.
250
- const matchesGlob = globRegexes.some((re) => re.test(entry.name));
251
- if (!matchesGlob)
252
- continue;
253
- const suppPath = path.join(specDirPath, entry.name);
254
- const suppContent = (0, utils_1.readFileContent)(suppPath);
255
- if (suppContent === null)
256
- continue;
257
- const suppHeadings = extractMarkdownHeadings(suppContent);
258
- for (const heading of suppHeadings) {
259
- subtitles.push(heading);
260
- }
261
- }
262
- // ---- commit hash ----
263
- let commitHash = null;
264
- for (const candidate of config.commitInfoCandidates) {
265
- const ciPath = path.join(specDirPath, candidate);
266
- const ciContent = (0, utils_1.readFileContent)(ciPath);
267
- if (ciContent !== null) {
268
- commitHash = (0, utils_1.parseCommitInfoMd)(ciContent);
269
- break;
270
- }
271
- }
272
- (0, errors_1.logDebug)('Built spec metadata', { specId, title, subtitleCount: subtitles.length, commitHash });
273
- return {
274
- specId,
275
- title,
276
- subtitles,
277
- commitHash,
278
- filePath,
279
- type: 'directory',
280
- };
281
- }
282
- // ---------------------------------------------------------------------------
283
- // extractSpecMetadata (public)
284
- // ---------------------------------------------------------------------------
285
- /**
286
- * Discover and extract metadata for a single spec, given its storage location
287
- * and directory name.
288
- *
289
- * Ported from `spec_extractor.py:177-237`.
290
- *
291
- * Two discovery branches are attempted in order:
292
- *
293
- * - **Flat-file**: checks `{specStoragePath}/{specDirName}.md`. If it exists,
294
- * reads it and produces metadata with `type: 'flat-file'`.
295
- * - **Directory**: checks `{specStoragePath}/{specDirName}/`. If it exists,
296
- * searches for a primary document using `config.discovery.primaryDocCandidates`,
297
- * reads it, and produces metadata with `type: 'directory'`.
298
- *
299
- * Returns `null` when neither branch yields a readable spec.
300
- *
301
- * @param specStoragePath - Root directory where specs are stored.
302
- * @param specDirName - Name of the spec (e.g. "spec03", "auth-module").
303
- * @param config - Optional full `SpecConfig`; falls back to defaults
304
- * when omitted (discovery config resolved at call site).
305
- */
306
- function extractSpecMetadata(specStoragePath, specDirName, config) {
307
- // Resolve discovery config — use provided config or the built-in defaults.
308
- const discoveryConfig = config?.discovery ?? config_1.DEFAULT_CONFIG.discovery;
309
- // Branch A: flat-file
310
- const flatFilePath = path.join(specStoragePath, `${specDirName}.md`);
311
- if (fs.existsSync(flatFilePath) && fs.statSync(flatFilePath).isFile()) {
312
- const content = (0, utils_1.readFileContent)(flatFilePath);
313
- if (content !== null) {
314
- (0, errors_1.logDebug)('Discovered flat-file spec', { specDirName, path: flatFilePath });
315
- // Build metadata manually for flat-file (no supplementary docs or
316
- // commit-info in the same directory — those live alongside the flat
317
- // file's parent, which is specStoragePath itself).
318
- let title = specDirName;
319
- const firstH1Match = content.match(/^#\s+(.*)/m);
320
- if (firstH1Match && firstH1Match[1]) {
321
- title = firstH1Match[1].trim().replace(/\s*SPEC\s*$/i, '');
322
- if (!title)
323
- title = specDirName;
324
- }
325
- const subtitles = extractMarkdownHeadings(content);
326
- // Attempt to read commit-info from specStoragePath for supplementary
327
- // context (though flat-file specs rarely have one).
328
- let commitHash = null;
329
- for (const candidate of discoveryConfig.commitInfoCandidates) {
330
- const ciPath = path.join(specStoragePath, candidate);
331
- const ciContent = (0, utils_1.readFileContent)(ciPath);
332
- if (ciContent !== null) {
333
- commitHash = (0, utils_1.parseCommitInfoMd)(ciContent);
334
- break;
335
- }
336
- }
337
- return {
338
- specId: specDirName,
339
- title,
340
- subtitles,
341
- commitHash,
342
- filePath: flatFilePath,
343
- type: 'flat-file',
344
- };
345
- }
346
- }
347
- // Branch B: directory
348
- const specDirPath = path.join(specStoragePath, specDirName);
349
- if (fs.existsSync(specDirPath) && fs.statSync(specDirPath).isDirectory()) {
350
- const primary = _findPrimaryDoc(specDirPath, specDirName, discoveryConfig.primaryDocCandidates);
351
- if (primary) {
352
- const [, primaryAbsPath] = primary;
353
- const content = (0, utils_1.readFileContent)(primaryAbsPath);
354
- if (content !== null) {
355
- (0, errors_1.logDebug)('Discovered directory spec', { specDirName, primaryDoc: primaryAbsPath });
356
- const meta = _buildMetadata(specDirName, content, primaryAbsPath, specDirPath, discoveryConfig);
357
- return { ...meta, type: 'directory' };
358
- }
359
- }
360
- // Directory exists but no primary doc was found or it was unreadable.
361
- (0, errors_1.logWarn)('Spec directory exists but no primary doc found', {
362
- specDirName,
363
- specDirPath,
364
- candidates: discoveryConfig.primaryDocCandidates,
365
- });
366
- }
367
- return null;
368
- }
369
- //# sourceMappingURL=spec-extractor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spec-extractor.js","sourceRoot":"","sources":["../../../src/spec/mining/spec-extractor.ts"],"names":[],"mappings":"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"}
@@ -1,167 +0,0 @@
1
- /**
2
- * Spec utility functions — replaces `file_utils.py`, `meta.py`, and
3
- * `truncate.py` from Python Commit4Spec.
4
- *
5
- * Covers file I/O, meta.json read/write, text/diff truncation, and budget
6
- * computation. All functions are synchronous and use Node.js built-ins.
7
- *
8
- * @module spec/utils
9
- */
10
- export interface SpecEntry {
11
- specId: string;
12
- entryType: 'directory' | 'file';
13
- path: string;
14
- }
15
- export interface SpecMeta {
16
- repoPath: string;
17
- specStoragePath: string;
18
- currentCommitID?: string;
19
- createdAt?: string;
20
- updatedAt: string;
21
- }
22
- export interface BudgetProfile {
23
- tier: 'tiny' | 'small' | 'medium' | 'large' | 'vlarge';
24
- maxFragments: number;
25
- maxContents: number;
26
- contentBudget: number;
27
- }
28
- /** Root directory for spec data, relative to the repository root. */
29
- export declare const SPEC_DATA_DIR = ".homegraph/commit4spec";
30
- /**
31
- * Read a UTF-8 file synchronously.
32
- *
33
- * Returns `null` for ENOENT (not found), EISDIR (is a directory), or EACCES
34
- * (permission denied). Other errors propagate.
35
- */
36
- export declare function readFileContent(filePath: string): string | null;
37
- /**
38
- * Write a UTF-8 file synchronously, creating parent directories as needed.
39
- *
40
- * Parent directories are created with `fs.mkdirSync({ recursive: true })`.
41
- * If the parent exists but is not a directory the underlying error propagates.
42
- */
43
- export declare function writeFileContent(filePath: string, content: string): void;
44
- /**
45
- * Parse commit-info.md content for a commit hash.
46
- *
47
- * Searches line by line for one of:
48
- * - `commit: HASH`
49
- * - `commit-id: HASH`
50
- * - `commit_id: HASH`
51
- * - a bare 40-char hex hash on its own line
52
- *
53
- * Returns the first matched hash (7–40 hex chars), or `null` if no hash is
54
- * found. Empty or whitespace-only input returns `null`.
55
- */
56
- export declare function parseCommitInfoMd(content: string): string | null;
57
- /**
58
- * Discover specs in a storage directory.
59
- *
60
- * A "spec" is any `.md` file OR any subdirectory. For `.md` files the
61
- * `specId` is the basename without the extension. For subdirectories the
62
- * `specId` is the directory name.
63
- *
64
- * Returns an empty array when `specStoragePath` does not exist or is not a
65
- * directory.
66
- */
67
- export declare function discoverSpecs(specStoragePath: string): SpecEntry[];
68
- /**
69
- * Resolve the database path.
70
- *
71
- * Priority:
72
- * 1. If `explicitDbPath` is given, return it as-is (no side effects).
73
- * 2. If `repoPath` is given, default to `{repoPath}/${SPEC_DATA_DIR}/commit4spec.db`
74
- * and ensure `${SPEC_DATA_DIR}/.gitignore` exists containing `"*"`.
75
- * 3. If neither is given, return `"./commit4spec.db"`.
76
- */
77
- export declare function resolveDbPath(repoPath?: string, explicitDbPath?: string): string;
78
- /**
79
- * Read `${SPEC_DATA_DIR}/meta.json` from `repoPath`.
80
- *
81
- * Returns `null` when the file is missing, unreadable, or contains invalid
82
- * JSON or a JSON value that is not a plain object.
83
- */
84
- export declare function readMeta(repoPath: string): SpecMeta | null;
85
- /**
86
- * Write `${SPEC_DATA_DIR}/meta.json` to `repoPath`.
87
- *
88
- * If existing meta has a `createdAt` field it is preserved; otherwise a new
89
- * ISO-8601 timestamp is generated. `updatedAt` is always set to the current
90
- * time. The `${SPEC_DATA_DIR}` directory is created if it does not exist.
91
- *
92
- * Returns the full `SpecMeta` that was written.
93
- */
94
- export declare function writeMeta(repoPath: string, specStoragePath: string, currentCommitID?: string): SpecMeta;
95
- /**
96
- * Truncate a unified diff at a sensible boundary.
97
- *
98
- * The algorithm prefers semantic boundaries to keep diffs readable:
99
- *
100
- * 1. If the diff is shorter than `maxChars` (default 3800), return it unchanged.
101
- * 2. Try: find the **last** `@@` hunk header in the trailing 50% portion of
102
- * the diff and cut right before it.
103
- * 3. Fallback: find the **last** newline in the trailing 80% portion and cut
104
- * after it.
105
- * 4. Hard fallback: cut exactly at `maxChars`.
106
- *
107
- * Always appends `" …(truncated)"` when truncation occurs.
108
- *
109
- * @param diff - The unified diff text to truncate.
110
- * @param maxChars - Maximum allowed characters (including suffix). Default 3800.
111
- * @returns The (possibly truncated) diff text.
112
- */
113
- export declare function truncateCodeDiff(diff: string, maxChars?: number): string;
114
- /**
115
- * Truncate plain text with newline-awareness.
116
- *
117
- * When the text is longer than `maxChars`, it is cut at the last newline
118
- * found before `maxChars` (minus the suffix length). If no suitable newline
119
- * exists, a hard cut is made.
120
- *
121
- * The suffix `" …(truncated)"` is appended only when truncation occurs.
122
- *
123
- * @param text - The text to truncate.
124
- * @param maxChars - Maximum allowed characters (including suffix).
125
- * @returns The (possibly truncated) text.
126
- */
127
- export declare function truncateText(text: string, maxChars: number): string;
128
- /**
129
- * Truncate a subtitles array.
130
- *
131
- * 1. If the array has more than `maxEntries`, it is sliced to `maxEntries`.
132
- * 2. Each remaining entry that exceeds `maxChars` is individually truncated
133
- * via `truncateText`.
134
- *
135
- * Entries that already fit within both limits are left unchanged.
136
- *
137
- * @param subtitles - Array of subtitle strings.
138
- * @param maxChars - Maximum characters per entry (including suffix).
139
- * @param maxEntries - Maximum number of entries to keep.
140
- * @returns The truncated subtitles array (always a new array).
141
- */
142
- export declare function truncateSubtitles(subtitles: string[], maxChars: number, maxEntries: number): string[];
143
- /**
144
- * Compute a budget profile based on spec and optional fragment counts.
145
- *
146
- * The profile determines how many fragments, contents, and characters the
147
- * pipeline should budget when building LLM prompts. Higher counts produce
148
- * tighter budgets to keep prompts manageable.
149
- *
150
- * Thresholds (matching `truncate.py:38-57`):
151
- *
152
- * | specCount | tier | maxFragments | maxContents | contentBudget |
153
- * |-----------|---------|--------------|-------------|---------------|
154
- * | ≤ 3 | tiny | 12 | 16 | 48000 |
155
- * | ≤ 8 | small | 10 | 14 | 40000 |
156
- * | ≤ 15 | medium | 8 | 12 | 32000 |
157
- * | ≤ 30 | large | 6 | 10 | 24000 |
158
- * | > 30 | vlarge | 0 | 0 | 16000 |
159
- *
160
- * The `vlarge` tier disables fragment/contents inclusion entirely (0 values).
161
- *
162
- * @param specCount - Number of specs in the knowledge graph.
163
- * @param fragmentCount - (Unused) reserved for future per-fragment weighting.
164
- * @returns The budget profile for the given scale.
165
- */
166
- export declare function computeBudgetProfile(specCount: number, _fragmentCount?: number): BudgetProfile;
167
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/spec/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,WAAW,GAAG,MAAM,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAMD,qEAAqE;AACrE,eAAO,MAAM,aAAa,2BAA2B,CAAC;AAStD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS/D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAMxE;AAmBD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBhE;AAMD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,EAAE,CA6BlE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAiChF;AAMD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA8C1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,MAAM,GACvB,QAAQ,CAyBV;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAa,GAAG,MAAM,CA6C9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBnE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAMV;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,GACtB,aAAa,CAcf"}