diff --git a/package-lock.json b/package-lock.json index d2b48ae..dab3a8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "youagent", - "version": "0.1.0", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "youagent", - "version": "0.1.0", + "version": "0.0.1", "license": "MIT", "dependencies": { - "better-sqlite3": "^11.0.0", + "better-sqlite3": "^12.4.1", "chalk": "^5.3.0", "commander": "^12.1.0", "node-cron": "^3.0.3", @@ -1480,14 +1480,17 @@ "license": "MIT" }, "node_modules/better-sqlite3": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz", - "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", + "version": "12.11.1", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.11.1.tgz", + "integrity": "sha512-dq9AtApgg5PGFtBzPFSBl3HZQjHok5gaQCM6zh2Yk0aSmDCs1CbnVI8/HgASQkNKsWFpseIO9beg5xxpYhbIfA==", "hasInstallScript": true, "license": "MIT", "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x" } }, "node_modules/bindings": { diff --git a/package.json b/package.json index a94e698..f98221b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "prepublishOnly": "npm run build && npm test" }, "dependencies": { - "better-sqlite3": "^11.0.0", + "better-sqlite3": "^12.4.1", "chalk": "^5.3.0", "commander": "^12.1.0", "node-cron": "^3.0.3", diff --git a/src/storage/database.ts b/src/storage/database.ts index 014ed07..6d957df 100644 --- a/src/storage/database.ts +++ b/src/storage/database.ts @@ -9,13 +9,39 @@ import { homedir } from 'node:os'; const DEFAULT_DB_PATH = join(homedir(), '.youagent', 'youagent.db'); +/** + * Detect failures caused by a missing or incompatible better-sqlite3 + * native binding, as opposed to ordinary database errors. + */ +function isNativeModuleError(err: unknown): boolean { + if (!(err instanceof Error)) return false; + const code = (err as NodeJS.ErrnoException).code; + if (code === 'ERR_DLOPEN_FAILED' || code === 'MODULE_NOT_FOUND') return true; + return /better_sqlite3\.node|Could not locate the bindings file|NODE_MODULE_VERSION/i.test( + err.message + ); +} + export class AgentDatabase { private db: Database.Database; constructor(dbPath?: string) { const resolvedPath = dbPath ?? DEFAULT_DB_PATH; mkdirSync(dirname(resolvedPath), { recursive: true }); - this.db = new Database(resolvedPath); + try { + this.db = new Database(resolvedPath); + } catch (err) { + if (isNativeModuleError(err)) { + throw new Error( + 'youagent could not load its SQLite engine (better-sqlite3). ' + + 'The native module is missing or was built for a different Node.js version.\n' + + 'To fix, run: npm rebuild better-sqlite3\n' + + 'Or reinstall youagent on Node.js 20 or newer so a prebuilt binary can be used.\n' + + `Original error: ${err instanceof Error ? err.message : String(err)}` + ); + } + throw err; + } // Enable WAL mode for better concurrent read performance. this.db.pragma('journal_mode = WAL');