From cae87e67b80f11c41442e0a1bda11bfd1c22dbd0 Mon Sep 17 00:00:00 2001 From: Murali Varadarajan Date: Tue, 27 Jan 2026 11:03:47 -0800 Subject: [PATCH] Async hook support for claude --- package.json | 2 +- packages/cli/package.json | 2 +- packages/cli/src/lib/database.ts | 69 ++++++++++++++++++-------------- packages/cli/src/lib/hooks.ts | 4 +- 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 265a060..c3f8af1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "agentblame", "displayName": "Agent Blame", "description": "Track AI-generated vs human-written code. Provides git notes storage, CLI, and GitHub PR attribution.", - "version": "0.2.6", + "version": "0.2.10", "private": true, "license": "Apache-2.0", "repository": { diff --git a/packages/cli/package.json b/packages/cli/package.json index 5a5c25c..bec3adc 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@mesadev/agentblame", - "version": "0.2.9", + "version": "0.2.10", "description": "CLI to track AI-generated vs human-written code", "license": "Apache-2.0", "repository": { diff --git a/packages/cli/src/lib/database.ts b/packages/cli/src/lib/database.ts index eaa639f..7fcfb05 100644 --- a/packages/cli/src/lib/database.ts +++ b/packages/cli/src/lib/database.ts @@ -204,7 +204,10 @@ export interface InsertEditParams { } /** - * Insert a new AI edit into the database + * Insert a new AI edit into the database. + * Uses an explicit transaction to ensure atomicity - either all data + * is written (edit + lines) or none. This is especially important + * when running async hooks where the process could be interrupted. */ export function insertEdit(params: InsertEditParams): number { const db = getDatabase(); @@ -217,41 +220,49 @@ export function insertEdit(params: InsertEditParams): number { ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); - const result = editStmt.run( - params.timestamp, - params.provider, - params.filePath, - params.model, - params.content, - params.contentHash, - params.contentHashNormalized, - params.editType, - params.oldContent || null, - params.sessionId || null, - params.toolUseId || null - ); - - const editId = Number(result.lastInsertRowid); - - // Insert lines with line numbers and context const lineStmt = db.prepare(` INSERT INTO lines (edit_id, content, hash, hash_normalized, line_number, context_before, context_after) VALUES (?, ?, ?, ?, ?, ?, ?) `); - for (const line of params.lines) { - lineStmt.run( - editId, - line.content, - line.hash, - line.hashNormalized, - line.lineNumber || null, - line.contextBefore || null, - line.contextAfter || null + // Wrap in transaction for atomicity + db.exec("BEGIN TRANSACTION"); + try { + const result = editStmt.run( + params.timestamp, + params.provider, + params.filePath, + params.model, + params.content, + params.contentHash, + params.contentHashNormalized, + params.editType, + params.oldContent || null, + params.sessionId || null, + params.toolUseId || null ); - } - return editId; + const editId = Number(result.lastInsertRowid); + + // Insert lines with line numbers and context + for (const line of params.lines) { + lineStmt.run( + editId, + line.content, + line.hash, + line.hashNormalized, + line.lineNumber || null, + line.contextBefore || null, + line.contextAfter || null + ); + } + + db.exec("COMMIT"); + return editId; + } catch (err) { + db.exec("ROLLBACK"); + throw err; + } } // ============================================================================= diff --git a/packages/cli/src/lib/hooks.ts b/packages/cli/src/lib/hooks.ts index ea1390a..e51ee2a 100644 --- a/packages/cli/src/lib/hooks.ts +++ b/packages/cli/src/lib/hooks.ts @@ -232,10 +232,10 @@ export async function installClaudeHooks(repoRoot: string): Promise { ) ); - // Add the new hook + // Add the new hook with async: true for non-blocking execution config.hooks.PostToolUse.push({ matcher: "Edit|Write|MultiEdit", - hooks: [{ type: "command", command: hookCommand }], + hooks: [{ type: "command", command: hookCommand, async: true }], }); await fs.promises.writeFile(