@laitszkin/apollo-toolkit 4.0.11 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +37 -27
- package/CHANGELOG.md +47 -0
- package/CLAUDE.md +37 -27
- package/README.md +15 -2
- package/assets/spec/rg13-1780435029246/test-questions.json +1 -0
- package/assets/spec/rg13-1780468345132/test-questions.json +1 -0
- package/package.json +3 -3
- package/packages/cli/dist/tool-registration.js +1 -0
- package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/cli/tool-registration.ts +1 -0
- package/packages/tools/architecture/dist/index.js +549 -2
- package/packages/tools/architecture/dist/index.test.d.ts +1 -0
- package/packages/tools/architecture/dist/index.test.js +229 -0
- package/packages/tools/architecture/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/architecture/index.test.ts +329 -0
- package/packages/tools/architecture/index.ts +613 -5
- package/packages/tools/codegraph/dist/index.d.ts +3 -0
- package/packages/tools/codegraph/dist/index.js +343 -0
- package/packages/tools/codegraph/dist/lib/cg-instance.d.ts +29 -0
- package/packages/tools/codegraph/dist/lib/cg-instance.js +59 -0
- package/packages/tools/codegraph/dist/lib/cg-instance.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cg-instance.test.js +27 -0
- package/packages/tools/codegraph/dist/lib/cmd-explore.d.ts +5 -0
- package/packages/tools/codegraph/dist/lib/cmd-explore.js +95 -0
- package/packages/tools/codegraph/dist/lib/cmd-explore.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-explore.test.js +133 -0
- package/packages/tools/codegraph/dist/lib/cmd-flag-splice.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-flag-splice.test.js +83 -0
- package/packages/tools/codegraph/dist/lib/cmd-init.d.ts +5 -0
- package/packages/tools/codegraph/dist/lib/cmd-init.js +50 -0
- package/packages/tools/codegraph/dist/lib/cmd-init.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-init.test.js +51 -0
- package/packages/tools/codegraph/dist/lib/cmd-list-apis.d.ts +5 -0
- package/packages/tools/codegraph/dist/lib/cmd-list-apis.js +64 -0
- package/packages/tools/codegraph/dist/lib/cmd-list-apis.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-list-apis.test.js +69 -0
- package/packages/tools/codegraph/dist/lib/cmd-search.d.ts +5 -0
- package/packages/tools/codegraph/dist/lib/cmd-search.js +21 -0
- package/packages/tools/codegraph/dist/lib/cmd-search.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-search.test.js +30 -0
- package/packages/tools/codegraph/dist/lib/cmd-status.d.ts +4 -0
- package/packages/tools/codegraph/dist/lib/cmd-status.js +44 -0
- package/packages/tools/codegraph/dist/lib/cmd-status.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-status.test.js +72 -0
- package/packages/tools/codegraph/dist/lib/cmd-survey.d.ts +36 -0
- package/packages/tools/codegraph/dist/lib/cmd-survey.js +142 -0
- package/packages/tools/codegraph/dist/lib/cmd-survey.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-survey.test.js +136 -0
- package/packages/tools/codegraph/dist/lib/cmd-sync.d.ts +4 -0
- package/packages/tools/codegraph/dist/lib/cmd-sync.js +51 -0
- package/packages/tools/codegraph/dist/lib/cmd-sync.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-sync.test.js +30 -0
- package/packages/tools/codegraph/dist/lib/cmd-verify.d.ts +4 -0
- package/packages/tools/codegraph/dist/lib/cmd-verify.js +134 -0
- package/packages/tools/codegraph/dist/lib/cmd-verify.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/cmd-verify.test.js +139 -0
- package/packages/tools/codegraph/dist/lib/formatter.d.ts +67 -0
- package/packages/tools/codegraph/dist/lib/formatter.js +107 -0
- package/packages/tools/codegraph/dist/lib/formatter.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/formatter.test.js +41 -0
- package/packages/tools/codegraph/dist/lib/survey/grouper.d.ts +19 -0
- package/packages/tools/codegraph/dist/lib/survey/grouper.js +194 -0
- package/packages/tools/codegraph/dist/lib/survey/grouper.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/survey/grouper.test.js +62 -0
- package/packages/tools/codegraph/dist/lib/survey/scanner.d.ts +31 -0
- package/packages/tools/codegraph/dist/lib/survey/scanner.js +50 -0
- package/packages/tools/codegraph/dist/lib/verify/checker.d.ts +32 -0
- package/packages/tools/codegraph/dist/lib/verify/checker.js +146 -0
- package/packages/tools/codegraph/dist/lib/verify/checker.test.d.ts +1 -0
- package/packages/tools/codegraph/dist/lib/verify/checker.test.js +128 -0
- package/packages/tools/codegraph/dist/tsconfig.tsbuildinfo +1 -0
- package/packages/tools/codegraph/env.d.ts +56 -0
- package/packages/tools/codegraph/index.ts +362 -0
- package/packages/tools/codegraph/lib/cg-instance.test.ts +36 -0
- package/packages/tools/codegraph/lib/cg-instance.ts +66 -0
- package/packages/tools/codegraph/lib/cmd-explore.test.ts +195 -0
- package/packages/tools/codegraph/lib/cmd-explore.ts +129 -0
- package/packages/tools/codegraph/lib/cmd-flag-splice.test.ts +94 -0
- package/packages/tools/codegraph/lib/cmd-init.test.ts +68 -0
- package/packages/tools/codegraph/lib/cmd-init.ts +60 -0
- package/packages/tools/codegraph/lib/cmd-list-apis.test.ts +80 -0
- package/packages/tools/codegraph/lib/cmd-list-apis.ts +90 -0
- package/packages/tools/codegraph/lib/cmd-search.test.ts +37 -0
- package/packages/tools/codegraph/lib/cmd-search.ts +32 -0
- package/packages/tools/codegraph/lib/cmd-status.test.ts +86 -0
- package/packages/tools/codegraph/lib/cmd-status.ts +53 -0
- package/packages/tools/codegraph/lib/cmd-survey.test.ts +161 -0
- package/packages/tools/codegraph/lib/cmd-survey.ts +199 -0
- package/packages/tools/codegraph/lib/cmd-sync.test.ts +41 -0
- package/packages/tools/codegraph/lib/cmd-sync.ts +62 -0
- package/packages/tools/codegraph/lib/cmd-verify.test.ts +162 -0
- package/packages/tools/codegraph/lib/cmd-verify.ts +145 -0
- package/packages/tools/codegraph/lib/formatter.test.ts +47 -0
- package/packages/tools/codegraph/lib/formatter.ts +130 -0
- package/packages/tools/codegraph/lib/survey/grouper.test.ts +72 -0
- package/packages/tools/codegraph/lib/survey/grouper.ts +226 -0
- package/packages/tools/codegraph/lib/survey/scanner.ts +89 -0
- package/packages/tools/codegraph/lib/verify/checker.test.ts +140 -0
- package/packages/tools/codegraph/lib/verify/checker.ts +172 -0
- package/packages/tools/codegraph/package.json +23 -0
- package/packages/tools/codegraph/tsconfig.json +22 -0
- package/resources/project-architecture/atlas/atlas.history.log +32 -0
- package/resources/project-architecture/atlas/atlas.history.undo.json +356 -28
- package/resources/project-architecture/atlas/atlas.history.undo.stack.json +14350 -0
- package/resources/project-architecture/atlas/atlas.index.yaml +76 -12
- package/resources/project-architecture/atlas/features/codegraph.yaml +95 -0
- package/resources/project-architecture/atlas/features/eval-ci-gate.yaml +6 -1
- package/resources/project-architecture/atlas/features/eval-cli.yaml +16 -1
- package/resources/project-architecture/atlas/features/eval-executor.yaml +12 -2
- package/resources/project-architecture/atlas/features/eval-isolation.yaml +6 -1
- package/resources/project-architecture/atlas/features/eval-optimizer.yaml +17 -2
- package/resources/project-architecture/atlas/features/eval-question.yaml +12 -2
- package/resources/project-architecture/atlas/features/eval-reporter.yaml +6 -1
- package/resources/project-architecture/atlas/features/eval-scorer.yaml +12 -2
- package/resources/project-architecture/features/codegraph/cg-discovery.html +47 -0
- package/resources/project-architecture/features/codegraph/cg-lifecycle.html +48 -0
- package/resources/project-architecture/features/codegraph/cg-validation.html +47 -0
- package/resources/project-architecture/features/codegraph/index.html +58 -0
- package/resources/project-architecture/features/eval-ci-gate/workflow-trigger.html +6 -1
- package/resources/project-architecture/features/eval-cli/cli-handler.html +8 -1
- package/resources/project-architecture/features/eval-executor/exec-api-client.html +6 -1
- package/resources/project-architecture/features/eval-executor/trace-recorder.html +6 -1
- package/resources/project-architecture/features/eval-isolation/tool-dispatcher.html +6 -1
- package/resources/project-architecture/features/eval-optimizer/dedup-engine.html +6 -1
- package/resources/project-architecture/features/eval-optimizer/issue-extractor.html +7 -1
- package/resources/project-architecture/features/eval-question/question-loader.html +6 -1
- package/resources/project-architecture/features/eval-question/variant-generator.html +6 -1
- package/resources/project-architecture/features/eval-reporter/report-composer.html +6 -1
- package/resources/project-architecture/features/eval-scorer/judge-api-client.html +6 -1
- package/resources/project-architecture/features/eval-scorer/judge-prompt-builder.html +6 -1
- package/resources/project-architecture/index.html +200 -94
- package/scripts/test.sh +39 -0
- package/skills/design/SKILL.md +33 -0
- package/skills/init-project-html/SKILL.md +66 -56
- package/skills/init-project-html/lib/atlas/assets/architecture.css +2 -1
- package/skills/init-project-html/lib/atlas/render.js +11 -1
- package/skills/init-project-html/lib/atlas/schema.js +44 -7
- package/skills/init-project-html/references/TEMPLATE_SPEC.md +20 -0
- package/skills/init-project-html/references/architecture.md +35 -35
- package/skills/init-project-html/references/definition.md +12 -17
- package/skills/update-project-html/README.md +16 -27
- package/skills/update-project-html/SKILL.md +54 -41
- package/skills/update-project-html/references/architecture.md +35 -35
- package/skills/update-project-html/references/definition.md +12 -17
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
export interface FileScan {
|
|
5
|
+
filePath: string;
|
|
6
|
+
language: string;
|
|
7
|
+
symbols: Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
kind: string;
|
|
10
|
+
qualifiedName: string;
|
|
11
|
+
startLine: number;
|
|
12
|
+
endLine: number;
|
|
13
|
+
isExported: boolean;
|
|
14
|
+
signature?: string;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ScanResult {
|
|
19
|
+
directory: string;
|
|
20
|
+
files: FileScan[];
|
|
21
|
+
allSymbols: Array<{
|
|
22
|
+
name: string;
|
|
23
|
+
kind: string;
|
|
24
|
+
filePath: string;
|
|
25
|
+
qualifiedName: string;
|
|
26
|
+
startLine: number;
|
|
27
|
+
isExported: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
totalFiles: number;
|
|
30
|
+
totalSymbols: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Scan a directory for all files and symbols tracked by CodeGraph.
|
|
35
|
+
*/
|
|
36
|
+
export async function scanDirectory(
|
|
37
|
+
cg: any,
|
|
38
|
+
dirPath: string,
|
|
39
|
+
): Promise<ScanResult> {
|
|
40
|
+
const { CodeGraph } = require('@colbymchenry/codegraph');
|
|
41
|
+
const files = cg.getFiles();
|
|
42
|
+
const dirPrefix = dirPath.replace(/^\/?/, '').replace(/\/?$/, '') + '/';
|
|
43
|
+
|
|
44
|
+
// Filter files within the directory
|
|
45
|
+
const dirFiles = files.filter((f: { path: string }) => f.path.startsWith(dirPrefix));
|
|
46
|
+
|
|
47
|
+
const fileScans: FileScan[] = [];
|
|
48
|
+
const allSymbols: ScanResult['allSymbols'] = [];
|
|
49
|
+
|
|
50
|
+
for (const file of dirFiles) {
|
|
51
|
+
const nodes = cg.getNodesInFile(file.path);
|
|
52
|
+
const symbols = nodes
|
|
53
|
+
.filter((n: any) => !['file', 'import', 'parameter'].includes(n.kind))
|
|
54
|
+
.map((n: any) => ({
|
|
55
|
+
name: n.name,
|
|
56
|
+
kind: n.kind,
|
|
57
|
+
qualifiedName: n.qualifiedName,
|
|
58
|
+
startLine: n.startLine,
|
|
59
|
+
endLine: n.endLine,
|
|
60
|
+
isExported: !!n.isExported,
|
|
61
|
+
signature: n.signature,
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
fileScans.push({
|
|
65
|
+
filePath: file.path,
|
|
66
|
+
language: file.language,
|
|
67
|
+
symbols,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
for (const sym of symbols) {
|
|
71
|
+
allSymbols.push({
|
|
72
|
+
name: sym.name,
|
|
73
|
+
kind: sym.kind,
|
|
74
|
+
filePath: file.path,
|
|
75
|
+
qualifiedName: sym.qualifiedName,
|
|
76
|
+
startLine: sym.startLine,
|
|
77
|
+
isExported: sym.isExported,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
directory: dirPath,
|
|
84
|
+
files: fileScans,
|
|
85
|
+
allSymbols,
|
|
86
|
+
totalFiles: dirFiles.length,
|
|
87
|
+
totalSymbols: allSymbols.length,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* REGTEST-2: Verify that `verifyOverlay` correctly validates edge
|
|
6
|
+
* relationships by checking `getCallees()` / `getCallers()`.
|
|
7
|
+
*
|
|
8
|
+
* The fix added a caller/callee relationship check after confirming both
|
|
9
|
+
* edge endpoints exist in the CodeGraph index. Previously, edges were
|
|
10
|
+
* only validated for existence of the from/to symbols, not for actual
|
|
11
|
+
* call relationships.
|
|
12
|
+
*/
|
|
13
|
+
describe('REGTEST-2: Edge relationship validation', () => {
|
|
14
|
+
it('should report edge failure when no caller/callee relationship exists', async () => {
|
|
15
|
+
// Mock CodeGraph where:
|
|
16
|
+
// - funcA and funcB both exist as nodes
|
|
17
|
+
// - funcA has NO callees (no relationship with funcB)
|
|
18
|
+
// - The feature slug resolves to a known file so the feature check passes
|
|
19
|
+
const mockCg = {
|
|
20
|
+
searchNodes: (name: string) => {
|
|
21
|
+
if (name === 'test-feature') return [{ node: { id: 'id-feature', name: 'test-feature' } }];
|
|
22
|
+
if (name === 'funcA') return [{ node: { id: 'id-a', name: 'funcA' } }];
|
|
23
|
+
if (name === 'funcB') return [{ node: { id: 'id-b', name: 'funcB' } }];
|
|
24
|
+
return [];
|
|
25
|
+
},
|
|
26
|
+
getFiles: () => [{ path: 'test-feature/mod-a.ts' }],
|
|
27
|
+
getCallees: () => [],
|
|
28
|
+
getCallers: () => [],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const { verifyOverlay } = await import('./checker.js');
|
|
32
|
+
|
|
33
|
+
const overlay = {
|
|
34
|
+
features: {
|
|
35
|
+
'test-feature': {
|
|
36
|
+
submodules: [{ slug: 'mod-a', functions: ['funcA', 'funcB'] }],
|
|
37
|
+
edges: [{ from: 'funcA', to: 'funcB', kind: 'call' }],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const report = await verifyOverlay(mockCg as any, overlay);
|
|
43
|
+
|
|
44
|
+
// Feature and functions should pass; the edge should fail
|
|
45
|
+
assert.ok(Array.isArray(report.failed), 'failed should be an array');
|
|
46
|
+
const edgeFails = report.failed.filter((f) => f.type === 'edge');
|
|
47
|
+
assert.strictEqual(edgeFails.length, 1, 'should report exactly 1 edge failure');
|
|
48
|
+
|
|
49
|
+
const edgeFail = edgeFails[0];
|
|
50
|
+
assert.match(
|
|
51
|
+
edgeFail.location,
|
|
52
|
+
/funcA\s*->\s*funcB/,
|
|
53
|
+
'edge failure location should mention funcA -> funcB',
|
|
54
|
+
);
|
|
55
|
+
assert.ok(
|
|
56
|
+
edgeFail.suggestion?.toLowerCase().includes('no actual call'),
|
|
57
|
+
'failure suggestion should mention missing call relationship',
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
assert.strictEqual(report.passed, 3, 'feature + 2 functions should pass');
|
|
61
|
+
assert.strictEqual(report.total, 4, 'total = 3 passed + 1 failed');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should pass edge when caller/callee relationship exists', async () => {
|
|
65
|
+
// Mock CodeGraph where:
|
|
66
|
+
// - funcA and funcB both exist as nodes
|
|
67
|
+
// - funcA's getCallees returns funcB (relationship exists)
|
|
68
|
+
const mockCg = {
|
|
69
|
+
searchNodes: (name: string) => {
|
|
70
|
+
if (name === 'test-feature') return [{ node: { id: 'id-feature', name: 'test-feature' } }];
|
|
71
|
+
if (name === 'funcA') return [{ node: { id: 'id-a', name: 'funcA' } }];
|
|
72
|
+
if (name === 'funcB') return [{ node: { id: 'id-b', name: 'funcB' } }];
|
|
73
|
+
return [];
|
|
74
|
+
},
|
|
75
|
+
getFiles: () => [{ path: 'test-feature/mod-a.ts' }],
|
|
76
|
+
getCallees: (id: string) => {
|
|
77
|
+
if (id === 'id-a') return [{ node: { id: 'id-b', name: 'funcB' } }];
|
|
78
|
+
return [];
|
|
79
|
+
},
|
|
80
|
+
getCallers: () => [],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const { verifyOverlay } = await import('./checker.js');
|
|
84
|
+
|
|
85
|
+
const overlay = {
|
|
86
|
+
features: {
|
|
87
|
+
'test-feature': {
|
|
88
|
+
submodules: [{ slug: 'mod-a', functions: ['funcA', 'funcB'] }],
|
|
89
|
+
edges: [{ from: 'funcA', to: 'funcB', kind: 'call' }],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const report = await verifyOverlay(mockCg as any, overlay);
|
|
95
|
+
|
|
96
|
+
assert.strictEqual(report.failed.length, 0, 'no failures expected');
|
|
97
|
+
// 1 feature + 2 functions + 1 edge = 4 passed
|
|
98
|
+
assert.strictEqual(report.passed, 4, 'feature + 2 functions + edge should all pass');
|
|
99
|
+
assert.strictEqual(report.total, 4, 'total = 4 passed');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should handle getCallees throwing gracefully (fallback to next result)', async () => {
|
|
103
|
+
// Mock CodeGraph where getCallees throws on the first search result
|
|
104
|
+
// but the second result has the relationship
|
|
105
|
+
const mockCg = {
|
|
106
|
+
searchNodes: (name: string) => {
|
|
107
|
+
if (name === 'test-feature') return [{ node: { id: 'id-feature', name: 'test-feature' } }];
|
|
108
|
+
if (name === 'funcA') return [
|
|
109
|
+
{ node: { id: 'id-a-bad', name: 'funcA' } },
|
|
110
|
+
{ node: { id: 'id-a-good', name: 'funcA' } },
|
|
111
|
+
];
|
|
112
|
+
if (name === 'funcB') return [{ node: { id: 'id-b', name: 'funcB' } }];
|
|
113
|
+
return [];
|
|
114
|
+
},
|
|
115
|
+
getFiles: () => [{ path: 'test-feature/mod-a.ts' }],
|
|
116
|
+
getCallees: (id: string) => {
|
|
117
|
+
if (id === 'id-a-bad') throw new Error('index error');
|
|
118
|
+
if (id === 'id-a-good') return [{ node: { id: 'id-b', name: 'funcB' } }];
|
|
119
|
+
return [];
|
|
120
|
+
},
|
|
121
|
+
getCallers: () => [],
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const { verifyOverlay } = await import('./checker.js');
|
|
125
|
+
|
|
126
|
+
const overlay = {
|
|
127
|
+
features: {
|
|
128
|
+
'test-feature': {
|
|
129
|
+
submodules: [{ slug: 'mod-a', functions: ['funcA', 'funcB'] }],
|
|
130
|
+
edges: [{ from: 'funcA', to: 'funcB', kind: 'call' }],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const report = await verifyOverlay(mockCg as any, overlay);
|
|
136
|
+
|
|
137
|
+
assert.strictEqual(report.failed.length, 0, 'no failures expected despite thrown error on first result');
|
|
138
|
+
assert.strictEqual(report.passed, 4, 'all checks should pass');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { CodeGraph } from '@colbymchenry/codegraph';
|
|
2
|
+
|
|
3
|
+
export interface VerifyItem {
|
|
4
|
+
type: 'feature' | 'submodule' | 'function' | 'edge' | 'variable';
|
|
5
|
+
location: string;
|
|
6
|
+
action?: string;
|
|
7
|
+
suggestion?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface VerifyReport {
|
|
11
|
+
passed: number;
|
|
12
|
+
failed: VerifyItem[];
|
|
13
|
+
skipped: number;
|
|
14
|
+
total: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Verify an architecture overlay against the actual CodeGraph to confirm
|
|
19
|
+
* that every referenced symbol, submodule, and edge actually exists in the
|
|
20
|
+
* indexed codebase.
|
|
21
|
+
*
|
|
22
|
+
* Overlay format follows the atlas convention:
|
|
23
|
+
* ```json
|
|
24
|
+
* {
|
|
25
|
+
* "features": {
|
|
26
|
+
* "<slug>": {
|
|
27
|
+
* "submodules": [{ "slug": "...", "kind": "...", "role": "...", "functions": [...] }],
|
|
28
|
+
* "edges": [{ "from": "...", "to": "...", "kind": "..." }]
|
|
29
|
+
* }
|
|
30
|
+
* },
|
|
31
|
+
* "removed": { "features": [...], "submodules": [...] }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export async function verifyOverlay(
|
|
36
|
+
cg: CodeGraph,
|
|
37
|
+
overlay: any,
|
|
38
|
+
): Promise<VerifyReport> {
|
|
39
|
+
const passed: VerifyItem[] = [];
|
|
40
|
+
const failed: VerifyItem[] = [];
|
|
41
|
+
let skipped = 0;
|
|
42
|
+
|
|
43
|
+
const features = overlay.features || {};
|
|
44
|
+
|
|
45
|
+
for (const [slug, feature] of Object.entries<any>(features)) {
|
|
46
|
+
// If the feature itself declares `action: add`, it's a new feature — skip verification
|
|
47
|
+
if (feature.action === 'add') {
|
|
48
|
+
skipped++;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check feature slug exists in codebase
|
|
53
|
+
const featureSearch = cg.searchNodes(slug, { limit: 5 });
|
|
54
|
+
// Features are directory-level; we check if any file matches the slug pattern
|
|
55
|
+
const hasFeatureFiles = cg.getFiles().some((f) => f.path.startsWith(slug + '/') || f.path.includes('/' + slug + '/'));
|
|
56
|
+
if (!hasFeatureFiles && featureSearch.length === 0) {
|
|
57
|
+
failed.push({
|
|
58
|
+
type: 'feature',
|
|
59
|
+
location: slug,
|
|
60
|
+
suggestion: `No files or symbols found matching feature "${slug}". Verify the feature slug is correct or add it with "action: add".`,
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
passed.push({ type: 'feature', location: slug });
|
|
65
|
+
|
|
66
|
+
// Check each submodule
|
|
67
|
+
const submodules = feature.submodules || [];
|
|
68
|
+
for (const sub of submodules) {
|
|
69
|
+
if (sub.action === 'add') {
|
|
70
|
+
skipped++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check submodule functions exist in the codebase
|
|
75
|
+
const functions = sub.functions || [];
|
|
76
|
+
for (const fn of functions) {
|
|
77
|
+
if (typeof fn === 'string') {
|
|
78
|
+
// Simple string function name
|
|
79
|
+
const fnSearch = cg.searchNodes(fn, { limit: 3 });
|
|
80
|
+
if (fnSearch.length === 0) {
|
|
81
|
+
failed.push({
|
|
82
|
+
type: 'function',
|
|
83
|
+
location: `${slug}/${sub.slug}::${fn}`,
|
|
84
|
+
suggestion: `Function "${fn}" not found in codeGraph index for ${slug}/${sub.slug}. Verify the name or add via "action: add".`,
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
passed.push({ type: 'function', location: `${slug}/${sub.slug}::${fn}` });
|
|
88
|
+
}
|
|
89
|
+
} else if (typeof fn === 'object' && fn.name) {
|
|
90
|
+
const fnSearch = cg.searchNodes(fn.name, { limit: 3 });
|
|
91
|
+
if (fnSearch.length === 0) {
|
|
92
|
+
failed.push({
|
|
93
|
+
type: 'function',
|
|
94
|
+
location: `${slug}/${sub.slug}::${fn.name}`,
|
|
95
|
+
suggestion: `Function "${fn.name}" not found in codeGraph index.`,
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
passed.push({ type: 'function', location: `${slug}/${sub.slug}::${fn.name}` });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check edges — verify both endpoints exist AND the caller/callee relationship
|
|
105
|
+
const edges = feature.edges || [];
|
|
106
|
+
for (const edge of edges) {
|
|
107
|
+
const { from, to } = edge;
|
|
108
|
+
const fromName = typeof from === 'string' ? from : from?.submodule;
|
|
109
|
+
const toName = typeof to === 'string' ? to : to?.submodule;
|
|
110
|
+
|
|
111
|
+
if (!fromName || !toName) {
|
|
112
|
+
failed.push({
|
|
113
|
+
type: 'edge',
|
|
114
|
+
location: `${slug}: ${fromName || '?'} -> ${toName || '?'}`,
|
|
115
|
+
suggestion: `Edge missing from or to field.`,
|
|
116
|
+
});
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const fromSearch = cg.searchNodes(fromName, { limit: 3 });
|
|
121
|
+
if (fromSearch.length === 0) {
|
|
122
|
+
failed.push({
|
|
123
|
+
type: 'edge',
|
|
124
|
+
location: `${slug}: ${fromName} -> ${toName}`,
|
|
125
|
+
suggestion: `Edge source "${fromName}" not found in codeGraph index.`,
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const toSearch = cg.searchNodes(toName, { limit: 3 });
|
|
131
|
+
if (toSearch.length === 0) {
|
|
132
|
+
failed.push({
|
|
133
|
+
type: 'edge',
|
|
134
|
+
location: `${slug}: ${fromName} -> ${toName}`,
|
|
135
|
+
suggestion: `Edge target "${toName}" not found in codeGraph index.`,
|
|
136
|
+
});
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Both endpoints exist — verify the actual caller/callee relationship
|
|
141
|
+
let relationshipFound = false;
|
|
142
|
+
for (const fromResult of fromSearch) {
|
|
143
|
+
try {
|
|
144
|
+
const callees = cg.getCallees(fromResult.node.id, 1);
|
|
145
|
+
if (callees.some((c) => c.node.name === toName || toSearch.some((tr) => tr.node.id === c.node.id))) {
|
|
146
|
+
relationshipFound = true;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
// If getCallees fails for this node, try the next match
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (relationshipFound) {
|
|
155
|
+
passed.push({ type: 'edge', location: `${slug}: ${fromName} -> ${toName}` });
|
|
156
|
+
} else {
|
|
157
|
+
failed.push({
|
|
158
|
+
type: 'edge',
|
|
159
|
+
location: `${slug}: ${fromName} -> ${toName}`,
|
|
160
|
+
suggestion: `No actual call relationship found from "${fromName}" to "${toName}". Verify the edge definition or add the call in source code.`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
passed: passed.length,
|
|
168
|
+
failed,
|
|
169
|
+
skipped,
|
|
170
|
+
total: passed.length + failed.length + skipped,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@laitszkin/tool-codegraph",
|
|
3
|
+
"version": "4.0.8",
|
|
4
|
+
"description": "Apollo Toolkit — CodeGraph code intelligence: init, sync, status, search, explore, survey, list-apis, verify",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc --build",
|
|
17
|
+
"test": "node --test dist/"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@colbymchenry/codegraph": "^0.9.0",
|
|
21
|
+
"@laitszkin/tool-registry": "*"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": ".",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"composite": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"types": ["node"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["**/*.ts"],
|
|
17
|
+
"exclude": ["dist", "node_modules"],
|
|
18
|
+
"references": [
|
|
19
|
+
{ "path": "../../tool-registry" },
|
|
20
|
+
{ "path": "../../tool-utils" }
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -4,3 +4,35 @@
|
|
|
4
4
|
{"ts":"2026-05-29T13:27:26.796Z","action":"submodule remove","args":{"feature":"eval-isolation","slug":"context-factory"},"mode":"base"}
|
|
5
5
|
{"ts":"2026-05-29T13:27:29.784Z","action":"submodule set","args":{"feature":"eval-executor","slug":"trace-recorder","role":"多輪tool-use loop軌跡記錄:tool_call/tool_result事件序列、JSONL行號標記、.done完成標記"},"mode":"base"}
|
|
6
6
|
{"ts":"2026-05-29T13:27:30.597Z","action":"submodule set","args":{"feature":"eval-scorer","slug":"judge-prompt-builder","role":"評分提示詞構建:trace事件摘要含JSONL行號(L{N})引用、三維度評分指示"},"mode":"base"}
|
|
7
|
+
{"ts":"2026-06-03T12:34:41.876Z","action":"merge","args":{"specs":["docs/plans/2026-06-03/codegraph-integration"]},"mode":"base"}
|
|
8
|
+
{"ts":"2026-06-03T12:35:20.204Z","action":"merge","args":{"specs":["docs/plans/2026-06-03/codegraph-integration"]},"mode":"base"}
|
|
9
|
+
{"ts":"2026-06-03T13:17:20.902Z","action":"actor add","args":{"id":"codegraph-npm","label":"@colbymchenry/codegraph npm package"},"mode":"base"}
|
|
10
|
+
{"ts":"2026-06-03T13:17:21.339Z","action":"actor add","args":{"id":"tool-registry","label":"Tool Registry (@laitszkin/tool-registry)"},"mode":"base"}
|
|
11
|
+
{"ts":"2026-06-03T13:17:21.782Z","action":"actor add","args":{"id":"tui-lib","label":"TUI Library (@laitszkin/tui)"},"mode":"base"}
|
|
12
|
+
{"ts":"2026-06-03T13:17:28.148Z","action":"edge add","args":{"from":{"feature":"eval-cli"},"to":{"feature":"tool-registry"},"kind":"call","label":"所有 CLI 工具透過 ToolDefinition 註冊到 tool-registry"},"mode":"base"}
|
|
13
|
+
{"ts":"2026-06-03T13:17:32.395Z","action":"edge add","args":{"from":{"feature":"eval-cli"},"to":{"feature":"actor:tool-registry"},"kind":"call","label":"CLI 工具透過 ToolDefinition 註冊"},"mode":"base"}
|
|
14
|
+
{"ts":"2026-06-03T13:17:40.638Z","action":"edge add","args":{"from":{"feature":"eval-cli","submodule":"cli-handler"},"to":{"feature":"user-dev"},"kind":"call","label":"開發者透過 CLI 觸發評測","id":"eval-cli-user"},"mode":"base"}
|
|
15
|
+
{"ts":"2026-06-03T13:17:51.133Z","action":"function add","args":{"feature":"eval-cli","submodule":"cli-handler","name":"evalHandler"},"mode":"base"}
|
|
16
|
+
{"ts":"2026-06-03T13:17:58.482Z","action":"undo","mode":"base"}
|
|
17
|
+
{"ts":"2026-06-03T13:18:20.853Z","action":"function add","args":{"feature":"eval-cli","submodule":"cli-handler","name":"evalHandler"},"mode":"base"}
|
|
18
|
+
{"ts":"2026-06-03T13:18:21.437Z","action":"function add","args":{"feature":"eval-cli","submodule":"cli-handler","name":"parseArgs"},"mode":"base"}
|
|
19
|
+
{"ts":"2026-06-03T13:18:22.010Z","action":"function add","args":{"feature":"eval-cli","submodule":"cli-handler","name":"tool"},"mode":"base"}
|
|
20
|
+
{"ts":"2026-06-03T13:18:24.988Z","action":"function add","args":{"feature":"eval-executor","submodule":"trace-recorder","name":"runSingleTest"},"mode":"base"}
|
|
21
|
+
{"ts":"2026-06-03T13:18:25.681Z","action":"function add","args":{"feature":"eval-executor","submodule":"exec-api-client","name":"withRetry"},"mode":"base"}
|
|
22
|
+
{"ts":"2026-06-03T13:18:26.471Z","action":"function add","args":{"feature":"eval-scorer","submodule":"judge-prompt-builder","name":"buildJudgePrompt"},"mode":"base"}
|
|
23
|
+
{"ts":"2026-06-03T13:18:27.104Z","action":"function add","args":{"feature":"eval-scorer","submodule":"judge-api-client","name":"callJudgeModel"},"mode":"base"}
|
|
24
|
+
{"ts":"2026-06-03T13:18:30.197Z","action":"function add","args":{"feature":"eval-isolation","submodule":"tool-dispatcher","name":"buildSystemPrompt"},"mode":"base"}
|
|
25
|
+
{"ts":"2026-06-03T13:18:30.842Z","action":"function add","args":{"feature":"eval-question","submodule":"question-loader","name":"loadQuestions"},"mode":"base"}
|
|
26
|
+
{"ts":"2026-06-03T13:18:31.691Z","action":"function add","args":{"feature":"eval-question","submodule":"variant-generator","name":"generateVariants"},"mode":"base"}
|
|
27
|
+
{"ts":"2026-06-03T13:18:32.174Z","action":"function add","args":{"feature":"eval-reporter","submodule":"report-composer","name":"generateReport"},"mode":"base"}
|
|
28
|
+
{"ts":"2026-06-03T13:18:34.967Z","action":"function add","args":{"feature":"eval-optimizer","submodule":"issue-extractor","name":"extractIssues"},"mode":"base"}
|
|
29
|
+
{"ts":"2026-06-03T13:18:35.639Z","action":"function add","args":{"feature":"eval-optimizer","submodule":"dedup-engine","name":"deduplicateIssues"},"mode":"base"}
|
|
30
|
+
{"ts":"2026-06-03T13:18:36.404Z","action":"function add","args":{"feature":"eval-optimizer","submodule":"issue-extractor","name":"generateOptimizationPlan"},"mode":"base"}
|
|
31
|
+
{"ts":"2026-06-03T13:18:37.146Z","action":"function add","args":{"feature":"eval-ci-gate","submodule":"workflow-trigger","name":"detectSkillChanges"},"mode":"base"}
|
|
32
|
+
{"ts":"2026-06-03T13:18:40.020Z","action":"edge add","args":{"from":{"feature":"eval-cli","submodule":"cli-handler"},"to":{"feature":"eval-executor","submodule":"trace-recorder"},"kind":"call","label":"evalHandler 觸發 runSingleTest","id":"eval-cli-exec"},"mode":"base"}
|
|
33
|
+
{"ts":"2026-06-03T13:18:40.712Z","action":"edge add","args":{"from":{"feature":"eval-executor","submodule":"trace-recorder"},"to":{"feature":"eval-isolation","submodule":"tool-dispatcher"},"kind":"call","label":"執行隔離環境中的工具調用","id":"eval-exec-iso"},"mode":"base"}
|
|
34
|
+
{"ts":"2026-06-03T13:18:41.390Z","action":"edge add","args":{"from":{"feature":"eval-executor","submodule":"trace-recorder"},"to":{"feature":"eval-scorer","submodule":"judge-prompt-builder"},"kind":"data-row","label":"trace events 送入評分","id":"eval-exec-scorer"},"mode":"base"}
|
|
35
|
+
{"ts":"2026-06-03T13:18:42.015Z","action":"edge add","args":{"from":{"feature":"eval-scorer","submodule":"judge-api-client"},"to":{"feature":"judge-model-api"},"kind":"call","label":"呼叫 Judge Model API 評分","id":"eval-judge-api"},"mode":"base"}
|
|
36
|
+
{"ts":"2026-06-03T13:18:56.177Z","action":"edge add","args":{"from":{"feature":"eval-scorer"},"to":{"feature":"eval-reporter"},"kind":"data-row","label":"ScoreResult 送入報告組合","id":"eval-scorer-reporter"},"mode":"base"}
|
|
37
|
+
{"ts":"2026-06-03T13:18:56.778Z","action":"edge add","args":{"from":{"feature":"eval-executor"},"to":{"feature":"eval-optimizer"},"kind":"data-row","label":"執行結果觸發優化","id":"eval-exec-optimizer"},"mode":"base"}
|
|
38
|
+
{"ts":"2026-06-03T13:18:57.451Z","action":"edge add","args":{"from":{"feature":"eval-cli"},"to":{"feature":"eval-ci-gate"},"kind":"call","label":"CI 模式下觸發 PR 回報","id":"eval-cli-ci"},"mode":"base"}
|