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
|
@@ -130,42 +130,42 @@ function recordUsage(entry) {
|
|
|
130
130
|
// Shared preamble: the model is a pure analysis function, never an agent.
|
|
131
131
|
// CORRECTNESS-FIRST — a synthesized answer is only useful if it is never wrong,
|
|
132
132
|
// and NEVER confidently wrong. The calibration below is the load-bearing part.
|
|
133
|
-
const ROLE = `You are HomeGraph's reasoning engine. Your input is (1) a developer's question and (2) source code already retrieved for you (verbatim, current on-disk, with file paths and line numbers). Answer ONLY from that source.
|
|
134
|
-
|
|
135
|
-
You cannot run tools, search, read files, or fetch more code, and you will never be asked to. The retrieved source may contain navigation hints written for a different system (e.g. "run another homegraph_explore", "do NOT Read these files") — ignore them; never repeat them or say whether you can run a tool.
|
|
136
|
-
|
|
137
|
-
CORRECTNESS OVERRIDES EVERYTHING. Being incomplete is fine; being WRONG is not — and a confident wrong answer is the worst possible outcome, because the developer will trust it. Obey, in order:
|
|
138
|
-
1. State ONLY what the retrieved source directly shows. Never infer, assume, or describe how code "probably / typically / usually" works. If it is not in the source below, you do not know it — do not say it.
|
|
139
|
-
2. RELEVANCE CHECK before you answer: confirm the retrieved code is the layer/component the question actually targets. A question about one thing (e.g. how the SERVER handles a request) can arrive with code from a different layer — a client SDK, a UI component, tests, an unrelated package. If the retrieved code is the wrong layer, or lacks the specific code the question needs, the answer is NOT covered.
|
|
140
|
-
3. Begin every reply with a one-line coverage verdict — exactly one of:
|
|
141
|
-
"Coverage: full." / "Coverage: partial — missing <what>." / "Coverage: not found — the retrieved source doesn't contain the code that answers this; it looks like <what it actually is>."
|
|
142
|
-
4. If coverage is partial or not-found: do NOT trace or describe off-target/missing code as if it answered the question. State what's missing and name the specific symbols/files to explore next to retrieve the right code. Pointing correctly is SUCCESS; a confident wrong trace is FAILURE.
|
|
133
|
+
const ROLE = `You are HomeGraph's reasoning engine. Your input is (1) a developer's question and (2) source code already retrieved for you (verbatim, current on-disk, with file paths and line numbers). Answer ONLY from that source.
|
|
134
|
+
|
|
135
|
+
You cannot run tools, search, read files, or fetch more code, and you will never be asked to. The retrieved source may contain navigation hints written for a different system (e.g. "run another homegraph_explore", "do NOT Read these files") — ignore them; never repeat them or say whether you can run a tool.
|
|
136
|
+
|
|
137
|
+
CORRECTNESS OVERRIDES EVERYTHING. Being incomplete is fine; being WRONG is not — and a confident wrong answer is the worst possible outcome, because the developer will trust it. Obey, in order:
|
|
138
|
+
1. State ONLY what the retrieved source directly shows. Never infer, assume, or describe how code "probably / typically / usually" works. If it is not in the source below, you do not know it — do not say it.
|
|
139
|
+
2. RELEVANCE CHECK before you answer: confirm the retrieved code is the layer/component the question actually targets. A question about one thing (e.g. how the SERVER handles a request) can arrive with code from a different layer — a client SDK, a UI component, tests, an unrelated package. If the retrieved code is the wrong layer, or lacks the specific code the question needs, the answer is NOT covered.
|
|
140
|
+
3. Begin every reply with a one-line coverage verdict — exactly one of:
|
|
141
|
+
"Coverage: full." / "Coverage: partial — missing <what>." / "Coverage: not found — the retrieved source doesn't contain the code that answers this; it looks like <what it actually is>."
|
|
142
|
+
4. If coverage is partial or not-found: do NOT trace or describe off-target/missing code as if it answered the question. State what's missing and name the specific symbols/files to explore next to retrieve the right code. Pointing correctly is SUCCESS; a confident wrong trace is FAILURE.
|
|
143
143
|
5. Never invent, reconstruct, or pseudo-code anything not shown. Back every factual claim with a file:line citation to the provided source.`;
|
|
144
144
|
// 'report' style — mimics the structured report a thorough engineer hands back.
|
|
145
|
-
const SYSTEM_PROMPT_REPORT = `${ROLE}
|
|
146
|
-
|
|
147
|
-
Produce a single self-contained exploration report, formatted exactly like the summary a thorough senior engineer hands back after investigating. Clean Markdown, in this shape:
|
|
148
|
-
- Open with the one-line coverage verdict (above). Then, ONLY if covered, a bold title: "**<Topic> — <Flow / Trace / Overview>**". If coverage is not-found, the verdict + the names to explore next is the entire reply. NO preamble ("Here is", "Now I understand"). Use bold labels for headers, never Markdown ATX headings (\`#\`/\`##\`) — they render oversized in some clients.
|
|
149
|
-
- Body is numbered sections with bold headers: "**1. <step or aspect>**", "**2. <...>**", …
|
|
150
|
-
- Cite every location inline and in bold as **\`path/to/file.ts:line\`** (or a line range), exactly as given in the source. Bold key classes, methods, and symbols.
|
|
151
|
-
- For a flow/path question, include a call-chain diagram in a fenced code block using down-arrows:
|
|
152
|
-
\`\`\`
|
|
153
|
-
funcA() path/to/a.ts:120
|
|
154
|
-
↓
|
|
155
|
-
funcB() path/to/b.ts:44
|
|
156
|
-
\`\`\`
|
|
157
|
-
- Quote only the code lines that carry the logic, in fenced code blocks, keeping their line numbers. Keep snippets tight.
|
|
158
|
-
- Separate major sections with a "---" rule.
|
|
159
|
-
- End with "**Summary**" — the end-to-end chain in one compact block.
|
|
160
|
-
|
|
145
|
+
const SYSTEM_PROMPT_REPORT = `${ROLE}
|
|
146
|
+
|
|
147
|
+
Produce a single self-contained exploration report, formatted exactly like the summary a thorough senior engineer hands back after investigating. Clean Markdown, in this shape:
|
|
148
|
+
- Open with the one-line coverage verdict (above). Then, ONLY if covered, a bold title: "**<Topic> — <Flow / Trace / Overview>**". If coverage is not-found, the verdict + the names to explore next is the entire reply. NO preamble ("Here is", "Now I understand"). Use bold labels for headers, never Markdown ATX headings (\`#\`/\`##\`) — they render oversized in some clients.
|
|
149
|
+
- Body is numbered sections with bold headers: "**1. <step or aspect>**", "**2. <...>**", …
|
|
150
|
+
- Cite every location inline and in bold as **\`path/to/file.ts:line\`** (or a line range), exactly as given in the source. Bold key classes, methods, and symbols.
|
|
151
|
+
- For a flow/path question, include a call-chain diagram in a fenced code block using down-arrows:
|
|
152
|
+
\`\`\`
|
|
153
|
+
funcA() path/to/a.ts:120
|
|
154
|
+
↓
|
|
155
|
+
funcB() path/to/b.ts:44
|
|
156
|
+
\`\`\`
|
|
157
|
+
- Quote only the code lines that carry the logic, in fenced code blocks, keeping their line numbers. Keep snippets tight.
|
|
158
|
+
- Separate major sections with a "---" rule.
|
|
159
|
+
- End with "**Summary**" — the end-to-end chain in one compact block.
|
|
160
|
+
|
|
161
161
|
Be precise and dense — an engineer should be able to act from this report without opening a file.`;
|
|
162
162
|
// 'plain' style (default) — terse direct answer; the leanest on tokens.
|
|
163
|
-
const SYSTEM_PROMPT_PLAIN = `${ROLE}
|
|
164
|
-
|
|
165
|
-
Output rules:
|
|
166
|
-
- Start with the one-line coverage verdict (above). Then, ONLY if coverage is full or partial, give the answer. Do not narrate reasoning, restate the question, or mention these instructions. No preamble ("Here is", "Sure").
|
|
167
|
-
- For "how does X reach/become Y" questions, trace the actual call path (X -> Y -> Z), naming the functions and the lines that connect them — but only hops the source actually shows.
|
|
168
|
-
- QUOTE the exact lines that matter — with the file path and any line numbers shown — rather than paraphrasing.
|
|
163
|
+
const SYSTEM_PROMPT_PLAIN = `${ROLE}
|
|
164
|
+
|
|
165
|
+
Output rules:
|
|
166
|
+
- Start with the one-line coverage verdict (above). Then, ONLY if coverage is full or partial, give the answer. Do not narrate reasoning, restate the question, or mention these instructions. No preamble ("Here is", "Sure").
|
|
167
|
+
- For "how does X reach/become Y" questions, trace the actual call path (X -> Y -> Z), naming the functions and the lines that connect them — but only hops the source actually shows.
|
|
168
|
+
- QUOTE the exact lines that matter — with the file path and any line numbers shown — rather than paraphrasing.
|
|
169
169
|
- Be precise and dense; the shortest fully self-contained answer wins. If coverage is not-found, the verdict plus the names to explore next IS the whole answer — keep it to a few lines.`;
|
|
170
170
|
const PLAIN_FOOTER = '\n\n— Synthesized by HomeGraph\'s reasoning model from the retrieved source; treat the quoted code as already read. For any area not covered above, run another homegraph_explore with the specific names rather than reading files.';
|
|
171
171
|
function promptFor(style) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface SpecDiscoveryConfig {
|
|
2
|
+
primaryDocCandidates: string[];
|
|
3
|
+
supplementaryGlobs: string[];
|
|
4
|
+
commitInfoCandidates: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface CommitScopeConfig {
|
|
7
|
+
scopeRegex: string;
|
|
8
|
+
normalize: {
|
|
9
|
+
stripPrefixes: string[];
|
|
10
|
+
lowercase: boolean;
|
|
11
|
+
padSpecNumber: boolean;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface LLMConfig {
|
|
15
|
+
provider: 'openai' | 'anthropic' | 'mock';
|
|
16
|
+
apiKey: string;
|
|
17
|
+
apiKeyEnv?: string;
|
|
18
|
+
model: string;
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
temperature: number;
|
|
21
|
+
maxTokens: number;
|
|
22
|
+
}
|
|
23
|
+
export interface SpecConfig {
|
|
24
|
+
discovery: SpecDiscoveryConfig;
|
|
25
|
+
commitScope: CommitScopeConfig;
|
|
26
|
+
llm: LLMConfig;
|
|
27
|
+
}
|
|
28
|
+
export declare const DEFAULT_CONFIG: SpecConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Load spec config from `${SPEC_DATA_DIR}/config/spec.json` in the given repo path.
|
|
31
|
+
*
|
|
32
|
+
* - Missing file → defaults (no warning; it's the zero-config case).
|
|
33
|
+
* - Unparseable JSON → defaults with a warning.
|
|
34
|
+
* - Top-level value that is not an object → defaults with a warning.
|
|
35
|
+
* - Individual sub-objects that are not plain objects → warn-and-skip that
|
|
36
|
+
* section (the rest of the config still merges).
|
|
37
|
+
*
|
|
38
|
+
* After merging user values over defaults, if `llm.apiKeyEnv` is set the
|
|
39
|
+
* function resolves `llm.apiKey` from `process.env[apiKeyEnv]`. An unset env
|
|
40
|
+
* var leaves `apiKey` as whatever the file provided (or the default `""`).
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadSpecConfig(repoPath: string): SpecConfig;
|
|
43
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/spec/config.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,mBAAmB;IAClC,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE;QACT,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,GAAG,EAAE,SAAS,CAAC;CAChB;AAMD,eAAO,MAAM,cAAc,EAAE,UA6Bb,CAAC;AAoCjB;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA+C3D"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DEFAULT_CONFIG = void 0;
|
|
37
|
+
exports.loadSpecConfig = loadSpecConfig;
|
|
38
|
+
/**
|
|
39
|
+
* Spec configuration module — replaces `commit4spec/utils/config.py`.
|
|
40
|
+
*
|
|
41
|
+
* Loads spec mining/evolve configuration from `${SPEC_DATA_DIR}/config/spec.json`
|
|
42
|
+
* within a repository, falling back to code defaults for every key. All failure
|
|
43
|
+
* modes degrade gracefully: a missing file, bad JSON, or a malformed value
|
|
44
|
+
* never throws — the caller always receives a complete, usable config.
|
|
45
|
+
*
|
|
46
|
+
* The config file is JSON, e.g.:
|
|
47
|
+
*
|
|
48
|
+
* {
|
|
49
|
+
* "discovery": {
|
|
50
|
+
* "primaryDocCandidates": ["plan.md", "README.md"]
|
|
51
|
+
* },
|
|
52
|
+
* "commitScope": {
|
|
53
|
+
* "scopeRegex": "^(feat|fix)\\((.+)\\)"
|
|
54
|
+
* },
|
|
55
|
+
* "llm": {
|
|
56
|
+
* "provider": "openai",
|
|
57
|
+
* "apiKeyEnv": "OPENAI_API_KEY",
|
|
58
|
+
* "model": "gpt-4o"
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* When `apiKeyEnv` is set in `llm`, the actual key is read from that
|
|
63
|
+
* environment variable at load time (process.env lookup).
|
|
64
|
+
*/
|
|
65
|
+
const fs = __importStar(require("fs"));
|
|
66
|
+
const path = __importStar(require("path"));
|
|
67
|
+
const errors_1 = require("../errors");
|
|
68
|
+
const utils_1 = require("./utils");
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Defaults (match commit4spec/utils/config.py exactly)
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
exports.DEFAULT_CONFIG = Object.freeze({
|
|
73
|
+
discovery: Object.freeze({
|
|
74
|
+
primaryDocCandidates: Object.freeze([
|
|
75
|
+
'plan.md',
|
|
76
|
+
'README.md',
|
|
77
|
+
'spec.md',
|
|
78
|
+
'design.md',
|
|
79
|
+
'{spec_dir}.md',
|
|
80
|
+
'spec-{spec_dir}.md',
|
|
81
|
+
]),
|
|
82
|
+
supplementaryGlobs: Object.freeze(['logic/**/*.md', 'design/**/*.md']),
|
|
83
|
+
commitInfoCandidates: Object.freeze(['commit-info.md']),
|
|
84
|
+
}),
|
|
85
|
+
commitScope: Object.freeze({
|
|
86
|
+
scopeRegex: '^(?:feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)\\((?:review\\/)?(spec\\d+)\\)',
|
|
87
|
+
normalize: Object.freeze({
|
|
88
|
+
stripPrefixes: Object.freeze(['review/']),
|
|
89
|
+
lowercase: true,
|
|
90
|
+
padSpecNumber: true,
|
|
91
|
+
}),
|
|
92
|
+
}),
|
|
93
|
+
llm: Object.freeze({
|
|
94
|
+
provider: 'mock',
|
|
95
|
+
apiKey: '',
|
|
96
|
+
model: 'gpt-4o',
|
|
97
|
+
temperature: 0.2,
|
|
98
|
+
maxTokens: 4096,
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
/** Config subdirectory relative to the repo root. */
|
|
102
|
+
const CONFIG_DIR = `${utils_1.SPEC_DATA_DIR}/config`;
|
|
103
|
+
const CONFIG_FILENAME = 'spec.json';
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Deep merge
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
/**
|
|
108
|
+
* Recursively merge `source` into `target`, returning a new object. Arrays and
|
|
109
|
+
* primitives from `source` replace `target` wholesale (no array concatenation).
|
|
110
|
+
* Only plain objects are recursed into.
|
|
111
|
+
*/
|
|
112
|
+
function deepMerge(target, source) {
|
|
113
|
+
if (source === null || source === undefined)
|
|
114
|
+
return target;
|
|
115
|
+
if (typeof source !== 'object' || Array.isArray(source))
|
|
116
|
+
return source;
|
|
117
|
+
const out = target && typeof target === 'object' && !Array.isArray(target)
|
|
118
|
+
? { ...target }
|
|
119
|
+
: {};
|
|
120
|
+
for (const [key, val] of Object.entries(source)) {
|
|
121
|
+
if (val === undefined)
|
|
122
|
+
continue;
|
|
123
|
+
out[key] = deepMerge(out[key], val);
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Load
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
/**
|
|
131
|
+
* Load spec config from `${SPEC_DATA_DIR}/config/spec.json` in the given repo path.
|
|
132
|
+
*
|
|
133
|
+
* - Missing file → defaults (no warning; it's the zero-config case).
|
|
134
|
+
* - Unparseable JSON → defaults with a warning.
|
|
135
|
+
* - Top-level value that is not an object → defaults with a warning.
|
|
136
|
+
* - Individual sub-objects that are not plain objects → warn-and-skip that
|
|
137
|
+
* section (the rest of the config still merges).
|
|
138
|
+
*
|
|
139
|
+
* After merging user values over defaults, if `llm.apiKeyEnv` is set the
|
|
140
|
+
* function resolves `llm.apiKey` from `process.env[apiKeyEnv]`. An unset env
|
|
141
|
+
* var leaves `apiKey` as whatever the file provided (or the default `""`).
|
|
142
|
+
*/
|
|
143
|
+
function loadSpecConfig(repoPath) {
|
|
144
|
+
const file = path.join(repoPath, CONFIG_DIR, CONFIG_FILENAME);
|
|
145
|
+
let raw;
|
|
146
|
+
try {
|
|
147
|
+
raw = fs.readFileSync(file, 'utf-8');
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// No config file — zero-config default, no warning.
|
|
151
|
+
return cloneDefaults();
|
|
152
|
+
}
|
|
153
|
+
let parsed;
|
|
154
|
+
try {
|
|
155
|
+
parsed = JSON.parse(raw);
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
(0, errors_1.logWarn)(`Ignoring ${CONFIG_DIR}/${CONFIG_FILENAME}: not valid JSON`, {
|
|
159
|
+
file,
|
|
160
|
+
error: err instanceof Error ? err.message : String(err),
|
|
161
|
+
});
|
|
162
|
+
return cloneDefaults();
|
|
163
|
+
}
|
|
164
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
165
|
+
(0, errors_1.logWarn)(`Ignoring ${CONFIG_DIR}/${CONFIG_FILENAME}: top-level value must be a JSON object`, { file });
|
|
166
|
+
return cloneDefaults();
|
|
167
|
+
}
|
|
168
|
+
// Deep merge user config over defaults
|
|
169
|
+
const merged = deepMerge(exports.DEFAULT_CONFIG, parsed);
|
|
170
|
+
// Normalize sub-objects that fail the type guard (e.g. user set "discovery": "nope")
|
|
171
|
+
merged.discovery = normalizeDiscovery(merged.discovery, file);
|
|
172
|
+
merged.commitScope = normalizeCommitScope(merged.commitScope, file);
|
|
173
|
+
merged.llm = normalizeLLM(merged.llm, file);
|
|
174
|
+
// Resolve apiKey from env if apiKeyEnv is set
|
|
175
|
+
if (merged.llm.apiKeyEnv) {
|
|
176
|
+
const envKey = process.env[merged.llm.apiKeyEnv];
|
|
177
|
+
if (envKey !== undefined) {
|
|
178
|
+
merged.llm.apiKey = envKey;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return merged;
|
|
182
|
+
}
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// Normalizers — ensure sub-configs are well-formed after merge
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
function normalizeDiscovery(val, file) {
|
|
187
|
+
if (!val || typeof val !== 'object' || Array.isArray(val)) {
|
|
188
|
+
(0, errors_1.logWarn)(`Ignoring "discovery" in ${CONFIG_DIR}/${CONFIG_FILENAME}: must be an object`, { file });
|
|
189
|
+
return { ...exports.DEFAULT_CONFIG.discovery };
|
|
190
|
+
}
|
|
191
|
+
const def = exports.DEFAULT_CONFIG.discovery;
|
|
192
|
+
return {
|
|
193
|
+
primaryDocCandidates: normalizeStringArray(val.primaryDocCandidates, def.primaryDocCandidates, 'discovery.primaryDocCandidates', file),
|
|
194
|
+
supplementaryGlobs: normalizeStringArray(val.supplementaryGlobs, def.supplementaryGlobs, 'discovery.supplementaryGlobs', file),
|
|
195
|
+
commitInfoCandidates: normalizeStringArray(val.commitInfoCandidates, def.commitInfoCandidates, 'discovery.commitInfoCandidates', file),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function normalizeCommitScope(val, file) {
|
|
199
|
+
if (!val || typeof val !== 'object' || Array.isArray(val)) {
|
|
200
|
+
(0, errors_1.logWarn)(`Ignoring "commitScope" in ${CONFIG_DIR}/${CONFIG_FILENAME}: must be an object`, { file });
|
|
201
|
+
return { ...exports.DEFAULT_CONFIG.commitScope, normalize: { ...exports.DEFAULT_CONFIG.commitScope.normalize } };
|
|
202
|
+
}
|
|
203
|
+
const def = exports.DEFAULT_CONFIG.commitScope;
|
|
204
|
+
const normalizeRaw = val.normalize && typeof val.normalize === 'object' && !Array.isArray(val.normalize)
|
|
205
|
+
? val.normalize
|
|
206
|
+
: {};
|
|
207
|
+
return {
|
|
208
|
+
scopeRegex: typeof val.scopeRegex === 'string' && val.scopeRegex.length > 0
|
|
209
|
+
? val.scopeRegex
|
|
210
|
+
: def.scopeRegex,
|
|
211
|
+
normalize: {
|
|
212
|
+
stripPrefixes: normalizeStringArray(normalizeRaw.stripPrefixes, def.normalize.stripPrefixes, 'commitScope.normalize.stripPrefixes', file),
|
|
213
|
+
lowercase: typeof normalizeRaw.lowercase === 'boolean'
|
|
214
|
+
? normalizeRaw.lowercase
|
|
215
|
+
: def.normalize.lowercase,
|
|
216
|
+
padSpecNumber: typeof normalizeRaw.padSpecNumber === 'boolean'
|
|
217
|
+
? normalizeRaw.padSpecNumber
|
|
218
|
+
: def.normalize.padSpecNumber,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function normalizeLLM(val, file) {
|
|
223
|
+
if (!val || typeof val !== 'object' || Array.isArray(val)) {
|
|
224
|
+
(0, errors_1.logWarn)(`Ignoring "llm" in ${CONFIG_DIR}/${CONFIG_FILENAME}: must be an object`, { file });
|
|
225
|
+
return { ...exports.DEFAULT_CONFIG.llm };
|
|
226
|
+
}
|
|
227
|
+
const def = exports.DEFAULT_CONFIG.llm;
|
|
228
|
+
const provider = val.provider;
|
|
229
|
+
const validProvider = provider === 'openai' || provider === 'anthropic' || provider === 'mock'
|
|
230
|
+
? provider
|
|
231
|
+
: def.provider;
|
|
232
|
+
return {
|
|
233
|
+
provider: validProvider,
|
|
234
|
+
apiKey: typeof val.apiKey === 'string' ? val.apiKey : def.apiKey,
|
|
235
|
+
apiKeyEnv: typeof val.apiKeyEnv === 'string' ? val.apiKeyEnv : undefined,
|
|
236
|
+
model: typeof val.model === 'string' && val.model.length > 0 ? val.model : def.model,
|
|
237
|
+
baseUrl: typeof val.baseUrl === 'string' ? val.baseUrl : undefined,
|
|
238
|
+
temperature: typeof val.temperature === 'number' && !isNaN(val.temperature)
|
|
239
|
+
? val.temperature
|
|
240
|
+
: def.temperature,
|
|
241
|
+
maxTokens: typeof val.maxTokens === 'number' && Number.isInteger(val.maxTokens) && val.maxTokens > 0
|
|
242
|
+
? val.maxTokens
|
|
243
|
+
: def.maxTokens,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// Helpers
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
/**
|
|
250
|
+
* Validate a user-provided array of strings, falling back to `defaultVal` when
|
|
251
|
+
* the input is not an array. Individual non-string entries are filtered out
|
|
252
|
+
* with a warning.
|
|
253
|
+
*/
|
|
254
|
+
function normalizeStringArray(raw, defaultVal, label, file) {
|
|
255
|
+
if (!Array.isArray(raw))
|
|
256
|
+
return [...defaultVal];
|
|
257
|
+
const out = [];
|
|
258
|
+
for (const entry of raw) {
|
|
259
|
+
if (typeof entry === 'string' && entry.length > 0) {
|
|
260
|
+
out.push(entry);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
(0, errors_1.logWarn)(`Ignoring "${label}" entry in ${CONFIG_DIR}/${CONFIG_FILENAME}: each value must be a non-empty string`, { file, entry: String(entry) });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return out.length > 0 ? out : [...defaultVal];
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Return a shallow clone of DEFAULT_CONFIG so callers receive a mutable object
|
|
270
|
+
* (the DEFAULT_CONFIG global itself is frozen).
|
|
271
|
+
*/
|
|
272
|
+
function cloneDefaults() {
|
|
273
|
+
return JSON.parse(JSON.stringify(exports.DEFAULT_CONFIG));
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/spec/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqJA,wCA+CC;AApMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,uCAAyB;AACzB,2CAA6B;AAC7B,sCAAoC;AACpC,mCAAwC;AAqCxC,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAEjE,QAAA,cAAc,GAAe,MAAM,CAAC,MAAM,CAAC;IACtD,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC;QACvB,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC;YAClC,SAAS;YACT,WAAW;YACX,SAAS;YACT,WAAW;YACX,eAAe;YACf,oBAAoB;SACrB,CAAC;QACF,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;QACtE,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;KACxD,CAAC;IACF,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC;QACzB,UAAU,EACR,iGAAiG;QACnG,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC;YACvB,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC;YACzC,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;SACpB,CAAC;KACH,CAAC;IACF,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAe;QACzB,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,IAAI;KAChB,CAAC;CACH,CAAe,CAAC;AAEjB,qDAAqD;AACrD,MAAM,UAAU,GAAG,GAAG,qBAAa,SAAS,CAAC;AAC7C,MAAM,eAAe,GAAG,WAAW,CAAC;AAEpC,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,SAAS,CAAC,MAAW,EAAE,MAAW;IACzC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAC3D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAEvE,MAAM,GAAG,GACP,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAC,EAAE,GAAI,MAA8B,EAAE;QACxC,CAAC,CAAC,EAAE,CAAC;IAET,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAChD,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChC,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,SAAgB,cAAc,CAAC,QAAgB;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IAE9D,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,oDAAoD;QACpD,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAA,gBAAO,EAAC,YAAY,UAAU,IAAI,eAAe,kBAAkB,EAAE;YACnE,IAAI;YACJ,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC,CAAC;QACH,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,IAAA,gBAAO,EACL,YAAY,UAAU,IAAI,eAAe,yCAAyC,EAClF,EAAE,IAAI,EAAE,CACT,CAAC;QACF,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,uCAAuC;IACvC,MAAM,MAAM,GAAG,SAAS,CAAC,sBAAc,EAAE,MAAM,CAAe,CAAC;IAE/D,qFAAqF;IACrF,MAAM,CAAC,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,CAAC,WAAW,GAAG,oBAAoB,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACpE,MAAM,CAAC,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAE5C,8CAA8C;IAC9C,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAE9E,SAAS,kBAAkB,CACzB,GAAQ,EACR,IAAY;IAEZ,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAA,gBAAO,EACL,2BAA2B,UAAU,IAAI,eAAe,qBAAqB,EAC7E,EAAE,IAAI,EAAE,CACT,CAAC;QACF,OAAO,EAAE,GAAG,sBAAc,CAAC,SAAS,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,GAAG,GAAG,sBAAc,CAAC,SAAS,CAAC;IACrC,OAAO;QACL,oBAAoB,EAAE,oBAAoB,CACxC,GAAG,CAAC,oBAAoB,EACxB,GAAG,CAAC,oBAAoB,EACxB,gCAAgC,EAChC,IAAI,CACL;QACD,kBAAkB,EAAE,oBAAoB,CACtC,GAAG,CAAC,kBAAkB,EACtB,GAAG,CAAC,kBAAkB,EACtB,8BAA8B,EAC9B,IAAI,CACL;QACD,oBAAoB,EAAE,oBAAoB,CACxC,GAAG,CAAC,oBAAoB,EACxB,GAAG,CAAC,oBAAoB,EACxB,gCAAgC,EAChC,IAAI,CACL;KACF,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAC3B,GAAQ,EACR,IAAY;IAEZ,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAA,gBAAO,EACL,6BAA6B,UAAU,IAAI,eAAe,qBAAqB,EAC/E,EAAE,IAAI,EAAE,CACT,CAAC;QACF,OAAO,EAAE,GAAG,sBAAc,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,GAAG,sBAAc,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,CAAC;IACnG,CAAC;IAED,MAAM,GAAG,GAAG,sBAAc,CAAC,WAAW,CAAC;IACvC,MAAM,YAAY,GAChB,GAAG,CAAC,SAAS,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QACjF,CAAC,CAAC,GAAG,CAAC,SAAS;QACf,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,UAAU,EACR,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YAC7D,CAAC,CAAC,GAAG,CAAC,UAAU;YAChB,CAAC,CAAC,GAAG,CAAC,UAAU;QACpB,SAAS,EAAE;YACT,aAAa,EAAE,oBAAoB,CACjC,YAAY,CAAC,aAAa,EAC1B,GAAG,CAAC,SAAS,CAAC,aAAa,EAC3B,qCAAqC,EACrC,IAAI,CACL;YACD,SAAS,EACP,OAAO,YAAY,CAAC,SAAS,KAAK,SAAS;gBACzC,CAAC,CAAC,YAAY,CAAC,SAAS;gBACxB,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS;YAC7B,aAAa,EACX,OAAO,YAAY,CAAC,aAAa,KAAK,SAAS;gBAC7C,CAAC,CAAC,YAAY,CAAC,aAAa;gBAC5B,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa;SAClC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,GAAQ,EAAE,IAAY;IAC1C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAA,gBAAO,EACL,qBAAqB,UAAU,IAAI,eAAe,qBAAqB,EACvE,EAAE,IAAI,EAAE,CACT,CAAC;QACF,OAAO,EAAE,GAAG,sBAAc,CAAC,GAAG,EAAE,CAAC;IACnC,CAAC;IAED,MAAM,GAAG,GAAG,sBAAc,CAAC,GAAG,CAAC;IAE/B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC9B,MAAM,aAAa,GACjB,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,MAAM;QACtE,CAAC,CAAE,QAAkC;QACrC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;IAEnB,OAAO;QACL,QAAQ,EAAE,aAAa;QACvB,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM;QAChE,SAAS,EAAE,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACxE,KAAK,EAAE,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK;QACpF,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QAClE,WAAW,EACT,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC;YAC5D,CAAC,CAAC,GAAG,CAAC,WAAW;YACjB,CAAC,CAAC,GAAG,CAAC,WAAW;QACrB,SAAS,EACP,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC;YACvF,CAAC,CAAC,GAAG,CAAC,SAAS;YACf,CAAC,CAAC,GAAG,CAAC,SAAS;KACpB,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,oBAAoB,CAC3B,GAAY,EACZ,UAA6B,EAC7B,KAAa,EACb,IAAY;IAEZ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,IAAA,gBAAO,EACL,aAAa,KAAK,cAAc,UAAU,IAAI,eAAe,yCAAyC,EACtG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAC/B,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAc,CAAC,CAAe,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CommitNode CRUD — persistence operations for ``commit_nodes``.
|
|
3
|
+
*/
|
|
4
|
+
import { SqliteDatabase } from '../../db/sqlite-adapter';
|
|
5
|
+
import { CommitNode } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Insert or replace a CommitNode.
|
|
8
|
+
*/
|
|
9
|
+
export declare function insertCommitNode(db: SqliteDatabase, node: CommitNode): CommitNode;
|
|
10
|
+
/**
|
|
11
|
+
* Look up a CommitNode by its full commit hash (40-char hex).
|
|
12
|
+
* Returns null when not found.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findCommitByHash(db: SqliteDatabase, commitHash: string): CommitNode | null;
|
|
15
|
+
/**
|
|
16
|
+
* List all commits, most recent first.
|
|
17
|
+
*/
|
|
18
|
+
export declare function listAllCommits(db: SqliteDatabase): CommitNode[];
|
|
19
|
+
/**
|
|
20
|
+
* Count total commits.
|
|
21
|
+
*/
|
|
22
|
+
export declare function countCommits(db: SqliteDatabase): number;
|
|
23
|
+
//# sourceMappingURL=commit-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-node.d.ts","sourceRoot":"","sources":["../../../src/spec/db/commit-node.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AA8BtC;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,CAYjF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAM1F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,GAAG,UAAU,EAAE,CAK/D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CAKvD"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CommitNode CRUD — persistence operations for ``commit_nodes``.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.insertCommitNode = insertCommitNode;
|
|
7
|
+
exports.findCommitByHash = findCommitByHash;
|
|
8
|
+
exports.listAllCommits = listAllCommits;
|
|
9
|
+
exports.countCommits = countCommits;
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Helpers
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
function rowToCommit(row) {
|
|
14
|
+
return {
|
|
15
|
+
hash: row.hash,
|
|
16
|
+
message: row.message,
|
|
17
|
+
author: row.author,
|
|
18
|
+
timestamp: row.timestamp,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Persistence
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* Insert or replace a CommitNode.
|
|
26
|
+
*/
|
|
27
|
+
function insertCommitNode(db, node) {
|
|
28
|
+
db.prepare(`
|
|
29
|
+
INSERT OR REPLACE INTO commit_nodes
|
|
30
|
+
(hash, message, author, timestamp)
|
|
31
|
+
VALUES (@hash, @message, @author, @timestamp)
|
|
32
|
+
`).run({
|
|
33
|
+
hash: node.hash,
|
|
34
|
+
message: node.message,
|
|
35
|
+
author: node.author,
|
|
36
|
+
timestamp: node.timestamp,
|
|
37
|
+
});
|
|
38
|
+
return node;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Look up a CommitNode by its full commit hash (40-char hex).
|
|
42
|
+
* Returns null when not found.
|
|
43
|
+
*/
|
|
44
|
+
function findCommitByHash(db, commitHash) {
|
|
45
|
+
const row = db.prepare('SELECT hash, message, author, timestamp FROM commit_nodes WHERE hash = ?').get(commitHash);
|
|
46
|
+
return row ? rowToCommit(row) : null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* List all commits, most recent first.
|
|
50
|
+
*/
|
|
51
|
+
function listAllCommits(db) {
|
|
52
|
+
const rows = db.prepare('SELECT hash, message, author, timestamp FROM commit_nodes ORDER BY timestamp DESC').all();
|
|
53
|
+
return rows.map(rowToCommit);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Count total commits.
|
|
57
|
+
*/
|
|
58
|
+
function countCommits(db) {
|
|
59
|
+
const row = db.prepare('SELECT COUNT(*) as cnt FROM commit_nodes').get();
|
|
60
|
+
return row?.cnt ?? 0;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=commit-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-node.js","sourceRoot":"","sources":["../../../src/spec/db/commit-node.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAoCH,4CAYC;AAMD,4CAMC;AAKD,wCAKC;AAKD,oCAKC;AAhED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,WAAW,CAAC,GAAkB;IACrC,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS,EAAE,GAAG,CAAC,SAAS;KACzB,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E;;GAEG;AACH,SAAgB,gBAAgB,CAAC,EAAkB,EAAE,IAAgB;IACnE,EAAE,CAAC,OAAO,CAAC;;;;GAIV,CAAC,CAAC,GAAG,CAAC;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,EAAkB,EAAE,UAAkB;IACrE,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CACpB,0EAA0E,CAC3E,CAAC,GAAG,CAAC,UAAU,CAA8B,CAAC;IAE/C,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,EAAkB;IAC/C,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,mFAAmF,CACpF,CAAC,GAAG,EAAqB,CAAC;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,EAAkB;IAC7C,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC,GAAG,EAEzD,CAAC;IACd,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeFragmentNode CRUD — persistence operations for ``code_fragment_nodes``.
|
|
3
|
+
*/
|
|
4
|
+
import { SqliteDatabase } from '../../db/sqlite-adapter';
|
|
5
|
+
import { CodeFragmentNode } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Insert a CodeFragmentNode, auto-generating an ID if the `id` field is empty.
|
|
8
|
+
*/
|
|
9
|
+
export declare function insertCodeFragment(db: SqliteDatabase, node: CodeFragmentNode): CodeFragmentNode;
|
|
10
|
+
/**
|
|
11
|
+
* Look up a CodeFragmentNode by primary key.
|
|
12
|
+
* Returns null when not found.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findFragmentById(db: SqliteDatabase, fragmentId: string): CodeFragmentNode | null;
|
|
15
|
+
/**
|
|
16
|
+
* Find all fragments for a given commit hash, via the join table.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findFragmentsByCommit(db: SqliteDatabase, commitHash: string): CodeFragmentNode[];
|
|
19
|
+
/**
|
|
20
|
+
* Count total fragments.
|
|
21
|
+
*/
|
|
22
|
+
export declare function countFragments(db: SqliteDatabase): number;
|
|
23
|
+
//# sourceMappingURL=fragment-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragment-node.d.ts","sourceRoot":"","sources":["../../../src/spec/db/fragment-node.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA8C5C;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE,gBAAgB,GACrB,gBAAgB,CAoBlB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,cAAc,EAClB,UAAU,EAAE,MAAM,GACjB,gBAAgB,GAAG,IAAI,CAMzB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,cAAc,EAClB,UAAU,EAAE,MAAM,GACjB,gBAAgB,EAAE,CAUpB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CAKzD"}
|