homegraph 1.1.2 → 1.1.3
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.
- package/LICENSE +21 -21
- package/README.md +243 -243
- package/dist/bin/homegraph.js +371 -9
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/db/migrations.js +18 -18
- package/dist/db/queries.js +140 -140
- package/dist/db/schema.sql +152 -152
- package/dist/directory.js +5 -5
- package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/dist/installer/instructions-template.js +9 -9
- package/dist/installer/targets/shared.d.ts +5 -6
- package/dist/installer/targets/shared.d.ts.map +1 -1
- package/dist/installer/targets/shared.js +5 -6
- package/dist/installer/targets/shared.js.map +1 -1
- package/dist/mcp/liveness-watchdog.js +16 -16
- package/dist/mcp/server-instructions.js +69 -69
- package/dist/mcp/tools.d.ts +17 -4
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +192 -22
- package/dist/mcp/tools.js.map +1 -1
- package/dist/reasoning/reasoner.js +32 -32
- package/dist/spec/config.d.ts +43 -0
- package/dist/spec/config.d.ts.map +1 -0
- package/dist/spec/config.js +275 -0
- package/dist/spec/config.js.map +1 -0
- package/dist/spec/db/commit-node.d.ts +23 -0
- package/dist/spec/db/commit-node.d.ts.map +1 -0
- package/dist/spec/db/commit-node.js +62 -0
- package/dist/spec/db/commit-node.js.map +1 -0
- package/dist/spec/db/fragment-node.d.ts +23 -0
- package/dist/spec/db/fragment-node.d.ts.map +1 -0
- package/dist/spec/db/fragment-node.js +120 -0
- package/dist/spec/db/fragment-node.js.map +1 -0
- package/dist/spec/db/fts.d.ts +60 -0
- package/dist/spec/db/fts.d.ts.map +1 -0
- package/dist/spec/db/fts.js +285 -0
- package/dist/spec/db/fts.js.map +1 -0
- package/dist/spec/db/index.d.ts +13 -0
- package/dist/spec/db/index.d.ts.map +1 -0
- package/dist/spec/db/index.js +50 -0
- package/dist/spec/db/index.js.map +1 -0
- package/dist/spec/db/relations.d.ts +55 -0
- package/dist/spec/db/relations.d.ts.map +1 -0
- package/dist/spec/db/relations.js +158 -0
- package/dist/spec/db/relations.js.map +1 -0
- package/dist/spec/db/schema.d.ts +30 -0
- package/dist/spec/db/schema.d.ts.map +1 -0
- package/dist/spec/db/schema.js +87 -0
- package/dist/spec/db/schema.js.map +1 -0
- package/dist/spec/db/schema.sql +107 -0
- package/dist/spec/db/spec-node.d.ts +41 -0
- package/dist/spec/db/spec-node.d.ts.map +1 -0
- package/dist/spec/db/spec-node.js +114 -0
- package/dist/spec/db/spec-node.js.map +1 -0
- package/dist/spec/evolve/impact-locator.d.ts +13 -0
- package/dist/spec/evolve/impact-locator.d.ts.map +1 -0
- package/dist/spec/evolve/impact-locator.js +25 -0
- package/dist/spec/evolve/impact-locator.js.map +1 -0
- package/dist/spec/evolve/llm-client.d.ts +50 -0
- package/dist/spec/evolve/llm-client.d.ts.map +1 -0
- package/dist/spec/evolve/llm-client.js +176 -0
- package/dist/spec/evolve/llm-client.js.map +1 -0
- package/dist/spec/evolve/logic-checker.d.ts +12 -0
- package/dist/spec/evolve/logic-checker.d.ts.map +1 -0
- package/dist/spec/evolve/logic-checker.js +48 -0
- package/dist/spec/evolve/logic-checker.js.map +1 -0
- package/dist/spec/evolve/pipeline.d.ts +40 -0
- package/dist/spec/evolve/pipeline.d.ts.map +1 -0
- package/dist/spec/evolve/pipeline.js +314 -0
- package/dist/spec/evolve/pipeline.js.map +1 -0
- package/dist/spec/evolve/spec-rewriter.d.ts +42 -0
- package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -0
- package/dist/spec/evolve/spec-rewriter.js +254 -0
- package/dist/spec/evolve/spec-rewriter.js.map +1 -0
- package/dist/spec/graph/queries.d.ts +58 -0
- package/dist/spec/graph/queries.d.ts.map +1 -0
- package/dist/spec/graph/queries.js +215 -0
- package/dist/spec/graph/queries.js.map +1 -0
- package/dist/spec/mining/diff-parser.d.ts +33 -0
- package/dist/spec/mining/diff-parser.d.ts.map +1 -0
- package/dist/spec/mining/diff-parser.js +166 -0
- package/dist/spec/mining/diff-parser.js.map +1 -0
- package/dist/spec/mining/git-scanner.d.ts +91 -0
- package/dist/spec/mining/git-scanner.d.ts.map +1 -0
- package/dist/spec/mining/git-scanner.js +266 -0
- package/dist/spec/mining/git-scanner.js.map +1 -0
- package/dist/spec/mining/pipeline.d.ts +53 -0
- package/dist/spec/mining/pipeline.d.ts.map +1 -0
- package/dist/spec/mining/pipeline.js +165 -0
- package/dist/spec/mining/pipeline.js.map +1 -0
- package/dist/spec/mining/scope-resolver.d.ts +45 -0
- package/dist/spec/mining/scope-resolver.d.ts.map +1 -0
- package/dist/spec/mining/scope-resolver.js +103 -0
- package/dist/spec/mining/scope-resolver.js.map +1 -0
- package/dist/spec/mining/spec-extractor.d.ts +69 -0
- package/dist/spec/mining/spec-extractor.d.ts.map +1 -0
- package/dist/spec/mining/spec-extractor.js +369 -0
- package/dist/spec/mining/spec-extractor.js.map +1 -0
- package/dist/spec/types.d.ts +149 -0
- package/dist/spec/types.d.ts.map +1 -0
- package/dist/spec/types.js +15 -0
- package/dist/spec/types.js.map +1 -0
- package/dist/spec/utils.d.ts +166 -0
- package/dist/spec/utils.d.ts.map +1 -0
- package/dist/spec/utils.js +461 -0
- package/dist/spec/utils.js.map +1 -0
- package/package.json +58 -57
- package/scripts/add-lang/bench.sh +60 -60
- package/scripts/add-lang/check-grammar.mjs +75 -75
- package/scripts/add-lang/dump-ast.mjs +103 -103
- package/scripts/add-lang/verify-extraction.mjs +70 -70
- package/scripts/agent-eval/ab-adoption.sh +91 -91
- package/scripts/agent-eval/ab-hook.sh +86 -86
- package/scripts/agent-eval/ab-impl.sh +78 -78
- package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
- package/scripts/agent-eval/ab-sufficiency.sh +78 -78
- package/scripts/agent-eval/arms-F.sh +21 -21
- package/scripts/agent-eval/arms-matrix.sh +37 -37
- package/scripts/agent-eval/audit.sh +68 -68
- package/scripts/agent-eval/bench-readme.sh +28 -28
- package/scripts/agent-eval/bench-why-repo.sh +22 -22
- package/scripts/agent-eval/block-read-hook.sh +19 -19
- package/scripts/agent-eval/hook-settings.json +15 -15
- package/scripts/agent-eval/itrun.sh +120 -120
- package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
- package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
- package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
- package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
- package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
- package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
- package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
- package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
- package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
- package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
- package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
- package/scripts/agent-eval/offload-eval-setup.sh +24 -24
- package/scripts/agent-eval/offload-eval-styles.sh +71 -71
- package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
- package/scripts/agent-eval/offload-eval.md +76 -76
- package/scripts/agent-eval/parse-arms.mjs +116 -116
- package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
- package/scripts/agent-eval/parse-run.mjs +45 -45
- package/scripts/agent-eval/parse-session.mjs +93 -93
- package/scripts/agent-eval/probe-context.mjs +21 -21
- package/scripts/agent-eval/probe-explore.mjs +40 -40
- package/scripts/agent-eval/probe-node.mjs +20 -20
- package/scripts/agent-eval/probe-sweep.mjs +119 -119
- package/scripts/agent-eval/probe-trace.mjs +20 -20
- package/scripts/agent-eval/redirect-read-hook.sh +38 -38
- package/scripts/agent-eval/run-agent.sh +34 -34
- package/scripts/agent-eval/run-all.sh +69 -69
- package/scripts/agent-eval/run-arms.sh +56 -56
- package/scripts/agent-eval/seq-matrix.mjs +137 -137
- package/scripts/build-bundle.sh +118 -118
- package/scripts/extract-release-notes.mjs +130 -130
- package/scripts/local-install.sh +41 -41
- package/scripts/npm-sdk.js +75 -75
- package/scripts/npm-shim.js +246 -246
- package/scripts/pack-npm.sh +119 -119
- package/scripts/prepare-release.mjs +270 -270
- package/scripts/qa_eval/README.md +407 -404
- package/scripts/qa_eval/_test_deveco_probe.py +41 -41
- package/scripts/qa_eval/agent_runner.py +526 -526
- package/scripts/qa_eval/data/.gitignore +4 -4
- package/scripts/qa_eval/data/test-set.jsonl +2 -22
- package/scripts/qa_eval/eval_metrics.py +274 -233
- package/scripts/qa_eval/external_agent.py +976 -671
- package/scripts/qa_eval/llm_config.py +92 -92
- package/scripts/qa_eval/memory_monitor.py +132 -132
- package/scripts/qa_eval/my_answer_accuracy.py +187 -187
- package/scripts/qa_eval/requirements.txt +2 -2
- package/scripts/qa_eval/run_pipeline.py +804 -711
- package/scripts/qa_eval/stats_efficiency.py +279 -279
- package/scripts/qa_eval/stats_scores.py +207 -207
|
@@ -0,0 +1,369 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-extractor.js","sourceRoot":"","sources":["../../../src/spec/mining/spec-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commit4Spec Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Core types for the Spec knowledge graph — a higher-level semantic overlay
|
|
5
|
+
* on top of HomeGraph's code-symbol graph. Tracks design documents (Specs),
|
|
6
|
+
* Git commits, and code-change fragments, linked through a three-layer
|
|
7
|
+
* relationship model.
|
|
8
|
+
*
|
|
9
|
+
* These types mirror the Python dataclasses in Commit4Spec's
|
|
10
|
+
* `db/models/*.py` and are stored in separate SQLite tables from
|
|
11
|
+
* HomeGraph's `nodes` / `edges` core graph.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A design Spec — a higher-level document describing system behavior,
|
|
15
|
+
* discovered from either commit-message scopes or spec files on disk.
|
|
16
|
+
*/
|
|
17
|
+
export interface SpecNode {
|
|
18
|
+
/** Unique spec identifier (e.g. "spec28", "auth-module") */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Title extracted from the spec document's first heading */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Subtitle entries — markdown headings with content previews */
|
|
23
|
+
subtitles: string[];
|
|
24
|
+
/** Lifecycle status */
|
|
25
|
+
status: 'active' | 'deprecated';
|
|
26
|
+
/** Version number (incremented on each self-evolution rewrite) */
|
|
27
|
+
version: number;
|
|
28
|
+
/** Filesystem path to the spec document */
|
|
29
|
+
filePath: string;
|
|
30
|
+
/** Unix epoch millisecond timestamp of last update */
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A Git commit — metadata extracted from the repository history.
|
|
35
|
+
*/
|
|
36
|
+
export interface CommitNode {
|
|
37
|
+
/** Full commit hash (40-char hex) */
|
|
38
|
+
hash: string;
|
|
39
|
+
/** Commit message (first line) */
|
|
40
|
+
message: string;
|
|
41
|
+
/** Commit author name */
|
|
42
|
+
author: string;
|
|
43
|
+
/** Unix epoch millisecond timestamp */
|
|
44
|
+
timestamp: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A code-change fragment — a single file's diff from a commit,
|
|
48
|
+
* tracked as a coarse-grained range (not AST-level).
|
|
49
|
+
*/
|
|
50
|
+
export interface CodeFragmentNode {
|
|
51
|
+
/** 12-character hex identifier (auto-generated UUID prefix) */
|
|
52
|
+
id: string;
|
|
53
|
+
/** Kind of change */
|
|
54
|
+
changeType: 'ADD' | 'MODIFY' | 'DELETE';
|
|
55
|
+
/** Changed file path relative to repo root */
|
|
56
|
+
filePath: string;
|
|
57
|
+
/** First changed line (1-indexed) */
|
|
58
|
+
startLine: number;
|
|
59
|
+
/** Last changed line (1-indexed) */
|
|
60
|
+
endLine: number;
|
|
61
|
+
/** Unified diff text for this fragment */
|
|
62
|
+
codeDiff: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Relationship types between Spec entities.
|
|
66
|
+
*
|
|
67
|
+
* - GENERATE: commit → spec (parsed from commit message scope)
|
|
68
|
+
* - SUMMARIZED_FROM: spec → commit (discovered during mining)
|
|
69
|
+
* - SIMILAR_TO: spec ↔ spec (semantic similarity match)
|
|
70
|
+
* - EVOLVED_FROM: new spec → old/deprecated spec (self-evolve)
|
|
71
|
+
* - CONTAINS: commit → code fragment
|
|
72
|
+
*/
|
|
73
|
+
export type RelationType = 'GENERATE' | 'SUMMARIZED_FROM' | 'SIMILAR_TO' | 'EVOLVED_FROM' | 'CONTAINS';
|
|
74
|
+
/**
|
|
75
|
+
* A link between a Spec and a Commit.
|
|
76
|
+
*/
|
|
77
|
+
export interface SpecCommitRelation {
|
|
78
|
+
specId: string;
|
|
79
|
+
commitHash: string;
|
|
80
|
+
relationType: RelationType;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A link between a Commit and a CodeFragment.
|
|
84
|
+
*/
|
|
85
|
+
export interface CommitFragmentRelation {
|
|
86
|
+
commitHash: string;
|
|
87
|
+
fragmentId: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A link between two Specs.
|
|
91
|
+
*/
|
|
92
|
+
export interface SpecSpecRelation {
|
|
93
|
+
sourceId: string;
|
|
94
|
+
targetId: string;
|
|
95
|
+
relationType: RelationType;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Full context for a Spec — the spec itself, all linked commits,
|
|
99
|
+
* and the code fragments each commit touched.
|
|
100
|
+
*/
|
|
101
|
+
export interface SpecContext {
|
|
102
|
+
spec: SpecNode;
|
|
103
|
+
commits: SpecCommitContext[];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A commit with its relation type and code fragments, all bound
|
|
107
|
+
* to a specific spec.
|
|
108
|
+
*/
|
|
109
|
+
export interface SpecCommitContext {
|
|
110
|
+
commit: CommitNode;
|
|
111
|
+
relationType: RelationType;
|
|
112
|
+
fragments: CodeFragmentNode[];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A compact commit reference (hash + message only) for lightweight
|
|
116
|
+
* context serialisation.
|
|
117
|
+
*/
|
|
118
|
+
export interface CommitReference {
|
|
119
|
+
hash: string;
|
|
120
|
+
message: string;
|
|
121
|
+
timestamp: number;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A search result for a spec with scoring metadata.
|
|
125
|
+
*/
|
|
126
|
+
export interface SpecSearchResult {
|
|
127
|
+
/** Matching spec */
|
|
128
|
+
id: string;
|
|
129
|
+
title: string;
|
|
130
|
+
subtitles: string[];
|
|
131
|
+
/** Relevance score — 3.0 (exact title) → 1.0 (subtitles-only match) */
|
|
132
|
+
_score: number;
|
|
133
|
+
/** Which search stage produced this result */
|
|
134
|
+
_method?: 'fts5' | 'like' | 'all' | 'discovery';
|
|
135
|
+
/** LIKE tier label (only for LIKE results) */
|
|
136
|
+
_tier?: 'exact_title' | 'starts_with_title' | 'contains_title' | 'contains_subtitle';
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Statistics about the Spec knowledge graph.
|
|
140
|
+
*/
|
|
141
|
+
export interface SpecStats {
|
|
142
|
+
specCount: number;
|
|
143
|
+
commitCount: number;
|
|
144
|
+
fragmentCount: number;
|
|
145
|
+
relationCount: number;
|
|
146
|
+
activeSpecCount: number;
|
|
147
|
+
deprecatedSpecCount: number;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/spec/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Commit4Spec Type Definitions
|
|
4
|
+
*
|
|
5
|
+
* Core types for the Spec knowledge graph — a higher-level semantic overlay
|
|
6
|
+
* on top of HomeGraph's code-symbol graph. Tracks design documents (Specs),
|
|
7
|
+
* Git commits, and code-change fragments, linked through a three-layer
|
|
8
|
+
* relationship model.
|
|
9
|
+
*
|
|
10
|
+
* These types mirror the Python dataclasses in Commit4Spec's
|
|
11
|
+
* `db/models/*.py` and are stored in separate SQLite tables from
|
|
12
|
+
* HomeGraph's `nodes` / `edges` core graph.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/spec/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG"}
|