@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.
Files changed (145) hide show
  1. package/AGENTS.md +37 -27
  2. package/CHANGELOG.md +47 -0
  3. package/CLAUDE.md +37 -27
  4. package/README.md +15 -2
  5. package/assets/spec/rg13-1780435029246/test-questions.json +1 -0
  6. package/assets/spec/rg13-1780468345132/test-questions.json +1 -0
  7. package/package.json +3 -3
  8. package/packages/cli/dist/tool-registration.js +1 -0
  9. package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
  10. package/packages/cli/tool-registration.ts +1 -0
  11. package/packages/tools/architecture/dist/index.js +549 -2
  12. package/packages/tools/architecture/dist/index.test.d.ts +1 -0
  13. package/packages/tools/architecture/dist/index.test.js +229 -0
  14. package/packages/tools/architecture/dist/tsconfig.tsbuildinfo +1 -1
  15. package/packages/tools/architecture/index.test.ts +329 -0
  16. package/packages/tools/architecture/index.ts +613 -5
  17. package/packages/tools/codegraph/dist/index.d.ts +3 -0
  18. package/packages/tools/codegraph/dist/index.js +343 -0
  19. package/packages/tools/codegraph/dist/lib/cg-instance.d.ts +29 -0
  20. package/packages/tools/codegraph/dist/lib/cg-instance.js +59 -0
  21. package/packages/tools/codegraph/dist/lib/cg-instance.test.d.ts +1 -0
  22. package/packages/tools/codegraph/dist/lib/cg-instance.test.js +27 -0
  23. package/packages/tools/codegraph/dist/lib/cmd-explore.d.ts +5 -0
  24. package/packages/tools/codegraph/dist/lib/cmd-explore.js +95 -0
  25. package/packages/tools/codegraph/dist/lib/cmd-explore.test.d.ts +1 -0
  26. package/packages/tools/codegraph/dist/lib/cmd-explore.test.js +133 -0
  27. package/packages/tools/codegraph/dist/lib/cmd-flag-splice.test.d.ts +1 -0
  28. package/packages/tools/codegraph/dist/lib/cmd-flag-splice.test.js +83 -0
  29. package/packages/tools/codegraph/dist/lib/cmd-init.d.ts +5 -0
  30. package/packages/tools/codegraph/dist/lib/cmd-init.js +50 -0
  31. package/packages/tools/codegraph/dist/lib/cmd-init.test.d.ts +1 -0
  32. package/packages/tools/codegraph/dist/lib/cmd-init.test.js +51 -0
  33. package/packages/tools/codegraph/dist/lib/cmd-list-apis.d.ts +5 -0
  34. package/packages/tools/codegraph/dist/lib/cmd-list-apis.js +64 -0
  35. package/packages/tools/codegraph/dist/lib/cmd-list-apis.test.d.ts +1 -0
  36. package/packages/tools/codegraph/dist/lib/cmd-list-apis.test.js +69 -0
  37. package/packages/tools/codegraph/dist/lib/cmd-search.d.ts +5 -0
  38. package/packages/tools/codegraph/dist/lib/cmd-search.js +21 -0
  39. package/packages/tools/codegraph/dist/lib/cmd-search.test.d.ts +1 -0
  40. package/packages/tools/codegraph/dist/lib/cmd-search.test.js +30 -0
  41. package/packages/tools/codegraph/dist/lib/cmd-status.d.ts +4 -0
  42. package/packages/tools/codegraph/dist/lib/cmd-status.js +44 -0
  43. package/packages/tools/codegraph/dist/lib/cmd-status.test.d.ts +1 -0
  44. package/packages/tools/codegraph/dist/lib/cmd-status.test.js +72 -0
  45. package/packages/tools/codegraph/dist/lib/cmd-survey.d.ts +36 -0
  46. package/packages/tools/codegraph/dist/lib/cmd-survey.js +142 -0
  47. package/packages/tools/codegraph/dist/lib/cmd-survey.test.d.ts +1 -0
  48. package/packages/tools/codegraph/dist/lib/cmd-survey.test.js +136 -0
  49. package/packages/tools/codegraph/dist/lib/cmd-sync.d.ts +4 -0
  50. package/packages/tools/codegraph/dist/lib/cmd-sync.js +51 -0
  51. package/packages/tools/codegraph/dist/lib/cmd-sync.test.d.ts +1 -0
  52. package/packages/tools/codegraph/dist/lib/cmd-sync.test.js +30 -0
  53. package/packages/tools/codegraph/dist/lib/cmd-verify.d.ts +4 -0
  54. package/packages/tools/codegraph/dist/lib/cmd-verify.js +134 -0
  55. package/packages/tools/codegraph/dist/lib/cmd-verify.test.d.ts +1 -0
  56. package/packages/tools/codegraph/dist/lib/cmd-verify.test.js +139 -0
  57. package/packages/tools/codegraph/dist/lib/formatter.d.ts +67 -0
  58. package/packages/tools/codegraph/dist/lib/formatter.js +107 -0
  59. package/packages/tools/codegraph/dist/lib/formatter.test.d.ts +1 -0
  60. package/packages/tools/codegraph/dist/lib/formatter.test.js +41 -0
  61. package/packages/tools/codegraph/dist/lib/survey/grouper.d.ts +19 -0
  62. package/packages/tools/codegraph/dist/lib/survey/grouper.js +194 -0
  63. package/packages/tools/codegraph/dist/lib/survey/grouper.test.d.ts +1 -0
  64. package/packages/tools/codegraph/dist/lib/survey/grouper.test.js +62 -0
  65. package/packages/tools/codegraph/dist/lib/survey/scanner.d.ts +31 -0
  66. package/packages/tools/codegraph/dist/lib/survey/scanner.js +50 -0
  67. package/packages/tools/codegraph/dist/lib/verify/checker.d.ts +32 -0
  68. package/packages/tools/codegraph/dist/lib/verify/checker.js +146 -0
  69. package/packages/tools/codegraph/dist/lib/verify/checker.test.d.ts +1 -0
  70. package/packages/tools/codegraph/dist/lib/verify/checker.test.js +128 -0
  71. package/packages/tools/codegraph/dist/tsconfig.tsbuildinfo +1 -0
  72. package/packages/tools/codegraph/env.d.ts +56 -0
  73. package/packages/tools/codegraph/index.ts +362 -0
  74. package/packages/tools/codegraph/lib/cg-instance.test.ts +36 -0
  75. package/packages/tools/codegraph/lib/cg-instance.ts +66 -0
  76. package/packages/tools/codegraph/lib/cmd-explore.test.ts +195 -0
  77. package/packages/tools/codegraph/lib/cmd-explore.ts +129 -0
  78. package/packages/tools/codegraph/lib/cmd-flag-splice.test.ts +94 -0
  79. package/packages/tools/codegraph/lib/cmd-init.test.ts +68 -0
  80. package/packages/tools/codegraph/lib/cmd-init.ts +60 -0
  81. package/packages/tools/codegraph/lib/cmd-list-apis.test.ts +80 -0
  82. package/packages/tools/codegraph/lib/cmd-list-apis.ts +90 -0
  83. package/packages/tools/codegraph/lib/cmd-search.test.ts +37 -0
  84. package/packages/tools/codegraph/lib/cmd-search.ts +32 -0
  85. package/packages/tools/codegraph/lib/cmd-status.test.ts +86 -0
  86. package/packages/tools/codegraph/lib/cmd-status.ts +53 -0
  87. package/packages/tools/codegraph/lib/cmd-survey.test.ts +161 -0
  88. package/packages/tools/codegraph/lib/cmd-survey.ts +199 -0
  89. package/packages/tools/codegraph/lib/cmd-sync.test.ts +41 -0
  90. package/packages/tools/codegraph/lib/cmd-sync.ts +62 -0
  91. package/packages/tools/codegraph/lib/cmd-verify.test.ts +162 -0
  92. package/packages/tools/codegraph/lib/cmd-verify.ts +145 -0
  93. package/packages/tools/codegraph/lib/formatter.test.ts +47 -0
  94. package/packages/tools/codegraph/lib/formatter.ts +130 -0
  95. package/packages/tools/codegraph/lib/survey/grouper.test.ts +72 -0
  96. package/packages/tools/codegraph/lib/survey/grouper.ts +226 -0
  97. package/packages/tools/codegraph/lib/survey/scanner.ts +89 -0
  98. package/packages/tools/codegraph/lib/verify/checker.test.ts +140 -0
  99. package/packages/tools/codegraph/lib/verify/checker.ts +172 -0
  100. package/packages/tools/codegraph/package.json +23 -0
  101. package/packages/tools/codegraph/tsconfig.json +22 -0
  102. package/resources/project-architecture/atlas/atlas.history.log +32 -0
  103. package/resources/project-architecture/atlas/atlas.history.undo.json +356 -28
  104. package/resources/project-architecture/atlas/atlas.history.undo.stack.json +14350 -0
  105. package/resources/project-architecture/atlas/atlas.index.yaml +76 -12
  106. package/resources/project-architecture/atlas/features/codegraph.yaml +95 -0
  107. package/resources/project-architecture/atlas/features/eval-ci-gate.yaml +6 -1
  108. package/resources/project-architecture/atlas/features/eval-cli.yaml +16 -1
  109. package/resources/project-architecture/atlas/features/eval-executor.yaml +12 -2
  110. package/resources/project-architecture/atlas/features/eval-isolation.yaml +6 -1
  111. package/resources/project-architecture/atlas/features/eval-optimizer.yaml +17 -2
  112. package/resources/project-architecture/atlas/features/eval-question.yaml +12 -2
  113. package/resources/project-architecture/atlas/features/eval-reporter.yaml +6 -1
  114. package/resources/project-architecture/atlas/features/eval-scorer.yaml +12 -2
  115. package/resources/project-architecture/features/codegraph/cg-discovery.html +47 -0
  116. package/resources/project-architecture/features/codegraph/cg-lifecycle.html +48 -0
  117. package/resources/project-architecture/features/codegraph/cg-validation.html +47 -0
  118. package/resources/project-architecture/features/codegraph/index.html +58 -0
  119. package/resources/project-architecture/features/eval-ci-gate/workflow-trigger.html +6 -1
  120. package/resources/project-architecture/features/eval-cli/cli-handler.html +8 -1
  121. package/resources/project-architecture/features/eval-executor/exec-api-client.html +6 -1
  122. package/resources/project-architecture/features/eval-executor/trace-recorder.html +6 -1
  123. package/resources/project-architecture/features/eval-isolation/tool-dispatcher.html +6 -1
  124. package/resources/project-architecture/features/eval-optimizer/dedup-engine.html +6 -1
  125. package/resources/project-architecture/features/eval-optimizer/issue-extractor.html +7 -1
  126. package/resources/project-architecture/features/eval-question/question-loader.html +6 -1
  127. package/resources/project-architecture/features/eval-question/variant-generator.html +6 -1
  128. package/resources/project-architecture/features/eval-reporter/report-composer.html +6 -1
  129. package/resources/project-architecture/features/eval-scorer/judge-api-client.html +6 -1
  130. package/resources/project-architecture/features/eval-scorer/judge-prompt-builder.html +6 -1
  131. package/resources/project-architecture/index.html +200 -94
  132. package/scripts/test.sh +39 -0
  133. package/skills/design/SKILL.md +33 -0
  134. package/skills/init-project-html/SKILL.md +66 -56
  135. package/skills/init-project-html/lib/atlas/assets/architecture.css +2 -1
  136. package/skills/init-project-html/lib/atlas/render.js +11 -1
  137. package/skills/init-project-html/lib/atlas/schema.js +44 -7
  138. package/skills/init-project-html/references/TEMPLATE_SPEC.md +20 -0
  139. package/skills/init-project-html/references/architecture.md +35 -35
  140. package/skills/init-project-html/references/definition.md +12 -17
  141. package/skills/update-project-html/README.md +16 -27
  142. package/skills/update-project-html/SKILL.md +54 -41
  143. package/skills/update-project-html/references/architecture.md +35 -35
  144. package/skills/update-project-html/references/definition.md +12 -17
  145. 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"}