From 2967dbda627a4d849b5bfb5f850b829883ccc22e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 6 Apr 2026 06:34:09 +0000 Subject: [PATCH 01/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index cd06b59..1e3fe88 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "66.4k+", + "message": "68.8k+", "color": "brightgreen", - "npm": "56.1k+", + "npm": "58.4k+", "marketplace": "10.3k+" } From 0ac3318725a22c3a583c508d6620632afe5cc2a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Apr 2026 06:28:15 +0000 Subject: [PATCH 02/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index 1e3fe88..351b89e 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "68.8k+", + "message": "70.5k+", "color": "brightgreen", - "npm": "58.4k+", + "npm": "60.1k+", "marketplace": "10.3k+" } From 28bd0cf2f5f67a0bcdf2712a7b57fb5fdf6e8eae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 8 Apr 2026 12:15:44 +0000 Subject: [PATCH 03/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index 351b89e..09cc864 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "70.5k+", + "message": "71.6k+", "color": "brightgreen", - "npm": "60.1k+", + "npm": "61.2k+", "marketplace": "10.3k+" } From 28707f5b42a35e99a0a98e22016b5b82f8c13fee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 8 Apr 2026 18:23:22 +0000 Subject: [PATCH 04/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index 09cc864..3665430 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "71.6k+", + "message": "71.5k+", "color": "brightgreen", "npm": "61.2k+", - "marketplace": "10.3k+" + "marketplace": "10.2k+" } From fd18f7bae8a614a610537edafb245e443da608a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Apr 2026 06:29:58 +0000 Subject: [PATCH 05/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index 3665430..7fb3727 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "71.5k+", + "message": "71.7k+", "color": "brightgreen", "npm": "61.2k+", - "marketplace": "10.2k+" + "marketplace": "10.5k+" } From 601aaf152e5431cd15f17431daaaf8368eee3ca5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Apr 2026 12:16:58 +0000 Subject: [PATCH 06/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index 7fb3727..e397af0 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "71.7k+", + "message": "72.7k+", "color": "brightgreen", - "npm": "61.2k+", + "npm": "62.2k+", "marketplace": "10.5k+" } From ea82433b59fb7fa28d2a594c0d26718124f1da5f Mon Sep 17 00:00:00 2001 From: James G Date: Thu, 9 Apr 2026 14:53:25 +0100 Subject: [PATCH 07/13] fix: wrap insertEvent with withRetry for concurrent PostToolUse hooks When many tool calls complete in parallel (e.g., batch Linear get_issue), Claude Code spawns multiple PostToolUse hooks simultaneously. These all open the same per-project SessionDB and compete for the SQLite write lock. While better-sqlite3's busy_timeout (30s) handles most contention, edge cases during transaction lock escalation can still surface SQLITE_BUSY. This causes hooks to fail, and Claude Code reports "hook error" to users. Changes: - Wrap SessionDB.insertEvent() transaction with withRetry() for defense-in-depth against SQLITE_BUSY under concurrent hook access - Set busy_timeout pragma in BunSQLiteAdapter to match better-sqlite3's timeout option (previously ignored, causing immediate SQLITE_BUSY failures under Bun runtime) - Add concurrent insert test verifying multiple DB instances can write to the same file without data loss --- src/db-base.ts | 9 +++++++- src/session/db.ts | 7 +++++- tests/session/session-db.test.ts | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/db-base.ts b/src/db-base.ts index 8a5c2ba..e55e71a 100644 --- a/src/db-base.ts +++ b/src/db-base.ts @@ -127,7 +127,14 @@ export function loadDatabase(): typeof DatabaseConstructor { readonly: opts?.readonly, create: true, }); - return new BunSQLiteAdapter(raw); + const adapter = new BunSQLiteAdapter(raw); + // Propagate busy_timeout to match better-sqlite3's timeout option. + // Without this, concurrent writes under Bun fail immediately with + // SQLITE_BUSY instead of retrying (better-sqlite3 sets this automatically). + if (opts?.timeout) { + adapter.pragma(`busy_timeout = ${Number(opts.timeout)}`); + } + return adapter; } as any; } else { // Node.js — use better-sqlite3. diff --git a/src/session/db.ts b/src/session/db.ts index 72b4a35..2b361a6 100644 --- a/src/session/db.ts +++ b/src/session/db.ts @@ -343,7 +343,12 @@ export class SessionDB extends SQLiteBase { this.stmt(S.updateMetaLastEvent).run(sessionId); }); - transaction(); + // Use withRetry to handle SQLITE_BUSY under concurrent PostToolUse hooks. + // When many tool calls complete in parallel (e.g., batch get_issue), multiple + // hook processes compete for the write lock on the same SessionDB file. + // better-sqlite3's busy_timeout handles most cases, but withRetry provides + // defense-in-depth for edge cases like lock escalation during transactions. + this.withRetry(() => transaction()); } /** diff --git a/tests/session/session-db.test.ts b/tests/session/session-db.test.ts index 5f83578..5b12cda 100644 --- a/tests/session/session-db.test.ts +++ b/tests/session/session-db.test.ts @@ -531,3 +531,41 @@ describe("Limit", () => { assert.equal(limited[2].data, "file-2.ts"); }); }); + +// ════════════════════════════════════════════ +// ADDITIONAL: Concurrent insert resilience +// ════════════════════════════════════════════ + +describe("Concurrent Insert Resilience", () => { + test("multiple DB instances can write to the same file without data loss", () => { + // Simulates concurrent PostToolUse hooks writing to the same SessionDB. + // When many tool calls complete in parallel (e.g., batch get_issue), + // multiple hook processes open the same DB and insert events concurrently. + const dbPath = join(tmpdir(), `session-concurrent-${randomUUID()}.db`); + const instances = Array.from({ length: 5 }, () => { + const db = new SessionDB({ dbPath }); + cleanups.push(() => db.cleanup()); + return db; + }); + + const sid = "sess-concurrent"; + instances[0].ensureSession(sid, "/project"); + + // Each instance inserts unique events + for (let i = 0; i < instances.length; i++) { + instances[i].insertEvent(sid, makeEvent({ + type: "mcp", + data: `get_issue: UXF-${i}`, + })); + } + + // All events should be present — no SQLITE_BUSY failures + const events = instances[0].getEvents(sid); + assert.equal(events.length, 5, `Expected 5 events from concurrent inserts, got ${events.length}`); + + // Clean up all instances + for (const db of instances) { + db.close(); + } + }); +}); From 490a71afd62cc6dc4540593530fddaba47d762bf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 10 Apr 2026 06:33:42 +0000 Subject: [PATCH 08/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index e397af0..fecdf27 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "72.7k+", + "message": "73k+", "color": "brightgreen", "npm": "62.2k+", - "marketplace": "10.5k+" + "marketplace": "10.8k+" } From 8cc462d39f495fc93b3c46f53ad17df2ba2d091c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 10 Apr 2026 12:14:03 +0000 Subject: [PATCH 09/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index fecdf27..b2bd359 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "73k+", + "message": "73.8k+", "color": "brightgreen", - "npm": "62.2k+", + "npm": "63k+", "marketplace": "10.8k+" } From 2181310938e3be9571c25641dba7c69d02229e8b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 11 Apr 2026 12:07:24 +0000 Subject: [PATCH 10/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index b2bd359..6b9a0ad 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "73.8k+", + "message": "74.6k+", "color": "brightgreen", - "npm": "63k+", + "npm": "63.8k+", "marketplace": "10.8k+" } From 19519a59297d30720c6e047ee5845230a5696e43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 11 Apr 2026 18:07:55 +0000 Subject: [PATCH 11/13] ci: update install stats --- stats.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stats.json b/stats.json index 6b9a0ad..b5dd7a0 100644 --- a/stats.json +++ b/stats.json @@ -4,5 +4,5 @@ "message": "74.6k+", "color": "brightgreen", "npm": "63.8k+", - "marketplace": "10.8k+" + "marketplace": "10.7k+" } From 0020267626aabf9e50595ce8adc837cf96995bbd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 06:29:46 +0000 Subject: [PATCH 12/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index b5dd7a0..0576eb9 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "74.6k+", + "message": "75.1k+", "color": "brightgreen", - "npm": "63.8k+", + "npm": "64.4k+", "marketplace": "10.7k+" } From d6286730878816b82dfd5c245d34fab0241d41c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 13 Apr 2026 06:40:26 +0000 Subject: [PATCH 13/13] ci: update install stats --- stats.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stats.json b/stats.json index 0576eb9..4d909ff 100644 --- a/stats.json +++ b/stats.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "users", - "message": "75.1k+", + "message": "75.8k+", "color": "brightgreen", - "npm": "64.4k+", + "npm": "65.1k+", "marketplace": "10.7k+" }