detached process

This commit is contained in:
Colby McHenry
2026-02-11 02:58:59 -06:00
parent 09a8d24bd8
commit eee081e2a7
+22 -8
View File
@@ -25,6 +25,7 @@
import { Command } from 'commander'; import { Command } from 'commander';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import { spawn } from 'child_process';
import CodeGraph, { getCodeGraphDir, findNearestCodeGraphRoot } from '../index'; import CodeGraph, { getCodeGraphDir, findNearestCodeGraphRoot } from '../index';
import type { IndexProgress } from '../index'; import type { IndexProgress } from '../index';
import { runInstaller } from '../installer'; import { runInstaller } from '../installer';
@@ -957,8 +958,11 @@ program
/** /**
* codegraph sync-if-dirty [path] * codegraph sync-if-dirty [path]
* *
* Syncs the index only if .codegraph/.dirty exists. * Checks if .codegraph/.dirty exists and, if so, spawns a detached
* Removes the marker BEFORE syncing so edits during sync * background process to run `codegraph sync`. The hook process exits
* immediately so Claude Code's Stop hook never blocks.
*
* Removes the marker BEFORE spawning so edits during sync
* create a new marker for the next Stop event. * create a new marker for the next Stop event.
* Runs silently and always exits 0. * Runs silently and always exits 0.
*/ */
@@ -972,7 +976,7 @@ program
if (!projectRoot) { if (!projectRoot) {
process.exit(0); process.exit(0);
} }
const dirtyPath = path.join(getCodeGraphDir(projectRoot), '.dirty'); const dirtyPath = path.join(getCodeGraphDir(projectRoot!), '.dirty');
// No marker → nothing to do (sub-ms exit) // No marker → nothing to do (sub-ms exit)
if (!fs.existsSync(dirtyPath)) { if (!fs.existsSync(dirtyPath)) {
@@ -983,14 +987,24 @@ program
try { fs.unlinkSync(dirtyPath); } catch { /* ignore */ } try { fs.unlinkSync(dirtyPath); } catch { /* ignore */ }
// If not fully initialized (no DB), exit // If not fully initialized (no DB), exit
if (!CodeGraph.isInitialized(projectRoot)) { if (!CodeGraph.isInitialized(projectRoot!)) {
process.exit(0); process.exit(0);
} }
// Run sync // Spawn `codegraph sync` as a detached background process
const cg = await CodeGraph.open(projectRoot); // so this hook exits immediately and doesn't block Claude Code
await cg.sync(); const isWindows = process.platform === 'win32';
cg.destroy(); const child = spawn(
isWindows ? 'codegraph' : process.argv[0]!,
isWindows ? ['sync', '--quiet', projectRoot!] : [process.argv[1]!, 'sync', '--quiet', projectRoot!],
{
detached: true,
stdio: 'ignore',
windowsHide: true,
shell: isWindows,
}
);
child.unref();
} catch { } catch {
// Never fail — this runs at the end of Claude responses // Never fail — this runs at the end of Claude responses
} }