From 4d7dd8dbc4de744eade08896031614e4a187d88a Mon Sep 17 00:00:00 2001 From: 12122J <199902626+12122J@users.noreply.github.com> Date: Fri, 22 May 2026 16:00:06 +0000 Subject: [PATCH] feat(cli): extend status json output --- __tests__/sync.test.ts | 8 +++++++ src/bin/codegraph.ts | 49 +++++++++++++++++++++++++++++++++++++++++- src/db/queries.ts | 10 +++++++++ src/index.ts | 7 ++++++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/__tests__/sync.test.ts b/__tests__/sync.test.ts index 708a92a4..b868500d 100644 --- a/__tests__/sync.test.ts +++ b/__tests__/sync.test.ts @@ -49,6 +49,14 @@ describe('Sync Module', () => { }); describe('getChangedFiles()', () => { + it('should report the most recent indexed timestamp', () => { + const lastIndexed = cg.getLastIndexedAt(); + + expect(lastIndexed).toEqual(expect.any(Number)); + expect(lastIndexed).toBeGreaterThan(0); + expect(new Date(lastIndexed!).toISOString()).toMatch(/^\d{4}-\d{2}-\d{2}T/); + }); + it('should detect added files', () => { // Add a new file fs.writeFileSync( diff --git a/src/bin/codegraph.ts b/src/bin/codegraph.ts index 711d39c8..1ab1aa9c 100644 --- a/src/bin/codegraph.ts +++ b/src/bin/codegraph.ts @@ -243,6 +243,39 @@ function createVerboseProgress(): (progress: { phase: string; current: number; t }; } +function toIsoTimestamp(timestamp: number | null | undefined): string | null { + if (timestamp == null) { + return null; + } + return new Date(timestamp).toISOString(); +} + +async function getConfiguredAgentCount(projectPath: string): Promise { + const previousCwd = process.cwd(); + try { + if (fs.existsSync(projectPath) && fs.statSync(projectPath).isDirectory()) { + process.chdir(projectPath); + } + + const { detectAll } = await import('../installer/targets/registry'); + const configuredTargets = new Set(); + + for (const location of ['global', 'local'] as const) { + for (const { target, detection } of detectAll(location)) { + if (detection.alreadyConfigured) { + configuredTargets.add(target.id); + } + } + } + + return configuredTargets.size; + } catch { + return 0; + } finally { + process.chdir(previousCwd); + } +} + /** * Print success message */ @@ -689,11 +722,20 @@ program .option('-j, --json', 'Output as JSON') .action(async (pathArg: string | undefined, options: { json?: boolean }) => { const projectPath = resolveProjectPath(pathArg); + const indexPath = getCodeGraphDir(projectPath); + const agentCount = options.json ? await getConfiguredAgentCount(projectPath) : 0; try { if (!isInitialized(projectPath)) { if (options.json) { - console.log(JSON.stringify({ initialized: false, projectPath })); + console.log(JSON.stringify({ + initialized: false, + projectPath, + indexPath, + lastIndexed: null, + agentCount, + version: packageJson.version, + })); return; } console.log(chalk.bold('\nCodeGraph Status\n')); @@ -709,12 +751,17 @@ program const changes = cg.getChangedFiles(); const backend = cg.getBackend(); const journalMode = cg.getJournalMode(); + const lastIndexed = toIsoTimestamp(cg.getLastIndexedAt()); // JSON output mode if (options.json) { console.log(JSON.stringify({ initialized: true, projectPath, + indexPath, + lastIndexed, + agentCount, + version: packageJson.version, fileCount: stats.fileCount, nodeCount: stats.nodeCount, edgeCount: stats.edgeCount, diff --git a/src/db/queries.ts b/src/db/queries.ts index ebba66e6..54efb0ef 100644 --- a/src/db/queries.ts +++ b/src/db/queries.ts @@ -1137,6 +1137,16 @@ export class QueryBuilder { return rows.map(rowToFileRecord); } + /** + * Get the most recent index timestamp across all tracked files. + */ + getLastIndexedAt(): number | null { + const row = this.db.prepare('SELECT MAX(indexed_at) AS last_indexed_at FROM files').get() as { + last_indexed_at: number | null; + } | undefined; + return row?.last_indexed_at ?? null; + } + /** * Get files that need re-indexing (hash changed) */ diff --git a/src/index.ts b/src/index.ts index b2acf346..5f2d833a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -643,6 +643,13 @@ export class CodeGraph { return this.queries.getAllFiles(); } + /** + * Get the most recent index timestamp across all tracked files. + */ + getLastIndexedAt(): number | null { + return this.queries.getLastIndexedAt(); + } + // =========================================================================== // Graph Query Methods // ===========================================================================