fix(cli): include resolution + synthesizer edges in indexAll report (#413)
The orchestrator's per-file counter only sees extraction-phase edges, so the `X nodes, Y edges` line printed after `codegraph init -i` / `codegraph index` undercounts the graph — often by more than half on repos with heavy cross-file resolution (mall: 20 047 reported vs 45 629 actually in the DB). Snapshot (nodes, edges) before/after the full pipeline in `indexAll` and write the true delta back to the result. New lightweight `QueryBuilder.getNodeAndEdgeCount()` is one round-trip with no per-kind breakdowns. `indexFiles` (no resolution) and `sync` (uses `nodesUpdated`, not `nodesCreated`) are unaffected. Regression test added: `__tests__/integration/full-pipeline.test.ts > reports edgesCreated including resolution + synthesizer phases`.
This commit is contained in:
+9
-1
@@ -9,6 +9,15 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **`codegraph index` / `init -i` summary now reports the true edge count.**
|
||||||
|
The per-file counter in the orchestrator only saw extraction-phase edges,
|
||||||
|
so resolution and synthesizer edges (often >50% of the graph on
|
||||||
|
cross-file-heavy repos like Spring multi-module Java) were missing from
|
||||||
|
the `X nodes, Y edges` line. Snapshotting the DB before/after the full
|
||||||
|
pipeline now reports the actual additions. Example: indexing
|
||||||
|
`macrozheng/mall` previously reported `20 047 edges` while the DB held
|
||||||
|
`45 629`.
|
||||||
|
|
||||||
## [0.9.6] - 2026-05-27
|
## [0.9.6] - 2026-05-27
|
||||||
|
|
||||||
@@ -62,7 +71,6 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
|
|
||||||
Both targets are tested on the same parameterized contract as the existing five agents (idempotent install, sibling preservation, install/uninstall round-trip), with extra coverage for migration-marker detection, legacy → unified entry migration, sibling `disabled` field preservation, and the cross-target case where Gemini CLI and Antigravity IDE coexist in the same `~/.gemini/`. Closes #399.
|
Both targets are tested on the same parameterized contract as the existing five agents (idempotent install, sibling preservation, install/uninstall round-trip), with extra coverage for migration-marker detection, legacy → unified entry migration, sibling `disabled` field preservation, and the cross-target case where Gemini CLI and Antigravity IDE coexist in the same `~/.gemini/`. Closes #399.
|
||||||
- **Installer target for Kiro (CLI + IDE).** `codegraph install` now detects and configures Kiro out of the box on macOS, Linux, and Windows. Writes `mcpServers.codegraph` to `~/.kiro/settings/mcp.json` (global) or `./.kiro/settings/mcp.json` (local), and the codegraph usage block into a dedicated `~/.kiro/steering/codegraph.md` / `./.kiro/steering/codegraph.md` — Kiro's steering system loads every `*.md` file in `steering/` as agent context, so a dedicated file is the natural surface (no marker-based merging required). Sibling MCP servers in `mcp.json` and unrelated steering files (`product.md`, `tech.md`, etc.) are preserved across install / uninstall. Tested on the same parameterized contract as the other agent targets (idempotent install, sibling preservation, install/uninstall round-trip). Closes #385.
|
- **Installer target for Kiro (CLI + IDE).** `codegraph install` now detects and configures Kiro out of the box on macOS, Linux, and Windows. Writes `mcpServers.codegraph` to `~/.kiro/settings/mcp.json` (global) or `./.kiro/settings/mcp.json` (local), and the codegraph usage block into a dedicated `~/.kiro/steering/codegraph.md` / `./.kiro/steering/codegraph.md` — Kiro's steering system loads every `*.md` file in `steering/` as agent context, so a dedicated file is the natural surface (no marker-based merging required). Sibling MCP servers in `mcp.json` and unrelated steering files (`product.md`, `tech.md`, etc.) are preserved across install / uninstall. Tested on the same parameterized contract as the other agent targets (idempotent install, sibling preservation, install/uninstall round-trip). Closes #385.
|
||||||
|
|
||||||
## [0.9.5] - 2026-05-25
|
## [0.9.5] - 2026-05-25
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -241,4 +241,32 @@ describe('Integration: full pipeline', () => {
|
|||||||
cg.destroy();
|
cg.destroy();
|
||||||
}
|
}
|
||||||
}, 30_000);
|
}, 30_000);
|
||||||
|
|
||||||
|
it('reports edgesCreated including resolution + synthesizer phases', async () => {
|
||||||
|
// The synthetic project has cross-file imports, calls, and extends —
|
||||||
|
// all wired up in the resolution phase, AFTER the orchestrator's
|
||||||
|
// per-file extraction counter is done. The CLI summary used to read
|
||||||
|
// only the extraction-phase counter and undercount the graph; this
|
||||||
|
// test pins the counter to the true DB totals across all phases.
|
||||||
|
generateSyntheticProject(tempDir, 30);
|
||||||
|
|
||||||
|
const cg = await CodeGraph.init(tempDir, {
|
||||||
|
config: { include: ['**/*.ts'], exclude: [] },
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await cg.indexAll();
|
||||||
|
const stats = cg.getStats();
|
||||||
|
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
expect(result.nodesCreated).toBe(stats.nodeCount);
|
||||||
|
expect(result.edgesCreated).toBe(stats.edgeCount);
|
||||||
|
// Sanity: cross-file resolution had something to do — calls/extends
|
||||||
|
// edges should exist beyond the bare extraction-time contains edges.
|
||||||
|
const containsOnly = stats.edgesByKind.contains ?? 0;
|
||||||
|
expect(stats.edgeCount).toBeGreaterThan(containsOnly);
|
||||||
|
} finally {
|
||||||
|
cg.destroy();
|
||||||
|
}
|
||||||
|
}, 30_000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1445,6 +1445,19 @@ export class QueryBuilder {
|
|||||||
// Statistics
|
// Statistics
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lightweight (nodes, edges) count snapshot. Used around an index/sync
|
||||||
|
* run to compute true additions across extraction + resolution +
|
||||||
|
* synthesis — the per-phase counter in the orchestrator only sees
|
||||||
|
* extraction's contribution, which is why the CLI summary under-reported
|
||||||
|
* the edge count (resolution + synthesizer edges were invisible).
|
||||||
|
*/
|
||||||
|
getNodeAndEdgeCount(): { nodes: number; edges: number } {
|
||||||
|
return this.db
|
||||||
|
.prepare('SELECT (SELECT COUNT(*) FROM nodes) AS nodes, (SELECT COUNT(*) FROM edges) AS edges')
|
||||||
|
.get() as { nodes: number; edges: number };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get graph statistics
|
* Get graph statistics
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -325,6 +325,7 @@ export class CodeGraph {
|
|||||||
return { success: false, filesIndexed: 0, filesSkipped: 0, filesErrored: 0, nodesCreated: 0, edgesCreated: 0, errors: [{ message: 'Could not acquire file lock - another process may be indexing', severity: 'error' as const }], durationMs: 0 };
|
return { success: false, filesIndexed: 0, filesSkipped: 0, filesErrored: 0, nodesCreated: 0, edgesCreated: 0, errors: [{ message: 'Could not acquire file lock - another process may be indexing', severity: 'error' as const }], durationMs: 0 };
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
const before = this.queries.getNodeAndEdgeCount();
|
||||||
const result = await this.orchestrator.indexAll(options.onProgress, options.signal, options.verbose);
|
const result = await this.orchestrator.indexAll(options.onProgress, options.signal, options.verbose);
|
||||||
|
|
||||||
// Re-detect frameworks now that the index is populated. The resolver
|
// Re-detect frameworks now that the index is populated. The resolver
|
||||||
@@ -367,6 +368,15 @@ export class CodeGraph {
|
|||||||
this.db.runMaintenance();
|
this.db.runMaintenance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The orchestrator only sees extraction-phase counts; resolution and
|
||||||
|
// synthesizer edges (often >50% of the graph on JVM repos) come later.
|
||||||
|
// Recompute against the DB so the CLI summary reports the true totals.
|
||||||
|
if (result.success && result.filesIndexed > 0) {
|
||||||
|
const after = this.queries.getNodeAndEdgeCount();
|
||||||
|
result.nodesCreated = after.nodes - before.nodes;
|
||||||
|
result.edgesCreated = after.edges - before.edges;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} finally {
|
} finally {
|
||||||
this.fileLock.release();
|
this.fileLock.release();
|
||||||
|
|||||||
Reference in New Issue
Block a user