refactor: migrate from better-sqlite3 to bun:sqlite

- Updated build-hooks.js to remove better-sqlite3 dependency and use bun:sqlite.
- Modified smart-install.js to eliminate checks and installations related to better-sqlite3.
- Refactored Database.ts, SessionSearch.ts, SessionStore.ts, and migrations.ts to import and utilize bun:sqlite.
- Replaced exec and pragma calls with appropriate run methods for bun:sqlite compatibility.
- Removed unnecessary native module verification and installation logic for better-sqlite3.
This commit is contained in:
Alex Newman
2025-12-10 22:11:55 -05:00
parent b39cf84730
commit e4bd0ae461
12 changed files with 145 additions and 218 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ module.exports = {
apps: [
{
name: 'claude-mem-worker',
script: './plugin/scripts/worker-service.cjs',
script: 'bun ./plugin/scripts/worker-service.cjs',
// Windows: prevent visible console windows
windowsHide: true,
// INTENTIONAL: Watch mode enables auto-restart on plugin updates
-2
View File
@@ -50,7 +50,6 @@
"@anthropic-ai/claude-agent-sdk": "^0.1.62",
"@modelcontextprotocol/sdk": "^1.20.1",
"ansi-to-html": "^0.7.2",
"better-sqlite3": "^12.5.0",
"express": "^4.18.2",
"glob": "^11.0.3",
"handlebars": "^4.7.8",
@@ -60,7 +59,6 @@
"zod-to-json-schema": "^3.24.6"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.8",
"@types/cors": "^2.8.19",
"@types/express": "^4.17.21",
"@types/node": "^20.0.0",
+4 -5
View File
@@ -1,13 +1,12 @@
{
"name": "claude-mem-plugin",
"version": "7.0.9",
"version": "7.0.10",
"private": true,
"description": "Runtime dependencies for claude-mem bundled hooks",
"type": "module",
"dependencies": {
"better-sqlite3": "^12.5.0"
},
"dependencies": {},
"engines": {
"node": ">=18.0.0"
"node": ">=18.0.0",
"bun": ">=1.0.0"
}
}
File diff suppressed because one or more lines are too long
-11
View File
@@ -287,17 +287,6 @@ async function runNpmInstall() {
encoding: 'utf-8',
});
// Verify better-sqlite3 was installed
if (!existsSync(BETTER_SQLITE3_PATH)) {
throw new Error('better-sqlite3 installation verification failed');
}
// Verify native modules actually work
const nativeModulesWork = await verifyNativeModules();
if (!nativeModulesWork) {
throw new Error('Native modules failed to load after install');
}
const packageVersion = getPackageVersion();
const nodeVersion = getNodeVersion();
setInstalledVersion(packageVersion, nodeVersion);
File diff suppressed because one or more lines are too long
+8 -10
View File
@@ -59,8 +59,7 @@ async function buildHooks() {
console.log('✓ Output directories ready');
// Generate plugin/package.json for cache directory dependency installation
// The bundled hooks use `external: ['better-sqlite3']` so dependencies must be
// installed at runtime. This package.json enables npm install in the cache directory.
// Note: bun:sqlite is a Bun built-in, no external dependencies needed for SQLite
console.log('\n📦 Generating plugin package.json...');
const pluginPackageJson = {
name: 'claude-mem-plugin',
@@ -68,11 +67,10 @@ async function buildHooks() {
private: true,
description: 'Runtime dependencies for claude-mem bundled hooks',
type: 'module',
dependencies: {
'better-sqlite3': packageJson.dependencies['better-sqlite3']
},
dependencies: {},
engines: {
node: '>=18.0.0'
node: '>=18.0.0',
bun: '>=1.0.0'
}
};
fs.writeFileSync('plugin/package.json', JSON.stringify(pluginPackageJson, null, 2) + '\n');
@@ -103,7 +101,7 @@ async function buildHooks() {
outfile: `${hooksDir}/${WORKER_SERVICE.name}.cjs`,
minify: true,
logLevel: 'error', // Suppress warnings (import.meta warning is benign)
external: ['better-sqlite3'],
external: ['bun:sqlite'],
define: {
'__DEFAULT_PACKAGE_VERSION__': `"${version}"`
},
@@ -128,7 +126,7 @@ async function buildHooks() {
outfile: `${hooksDir}/${MCP_SERVER.name}.cjs`,
minify: true,
logLevel: 'error',
external: ['better-sqlite3'],
external: ['bun:sqlite'],
define: {
'__DEFAULT_PACKAGE_VERSION__': `"${version}"`
},
@@ -153,7 +151,7 @@ async function buildHooks() {
outfile: `${hooksDir}/${CONTEXT_GENERATOR.name}.cjs`,
minify: true,
logLevel: 'error',
external: ['better-sqlite3'],
external: ['bun:sqlite'],
define: {
'__DEFAULT_PACKAGE_VERSION__': `"${version}"`
}
@@ -176,7 +174,7 @@ async function buildHooks() {
format: 'esm',
outfile,
minify: true,
external: ['better-sqlite3'],
external: ['bun:sqlite'],
define: {
'__DEFAULT_PACKAGE_VERSION__': `"${version}"`
},
+2 -59
View File
@@ -25,7 +25,6 @@ const MARKETPLACE_ROOT = join(homedir(), '.claude', 'plugins', 'marketplaces', '
const PACKAGE_JSON_PATH = join(MARKETPLACE_ROOT, 'package.json');
const VERSION_MARKER_PATH = join(MARKETPLACE_ROOT, '.install-version');
const NODE_MODULES_PATH = join(MARKETPLACE_ROOT, 'node_modules');
const BETTER_SQLITE3_PATH = join(NODE_MODULES_PATH, 'better-sqlite3');
// Colors for output
const colors = {
@@ -104,11 +103,6 @@ function needsInstall() {
return true;
}
// Check if better-sqlite3 is installed
if (!existsSync(BETTER_SQLITE3_PATH)) {
log('📦 better-sqlite3 missing - reinstalling', colors.cyan);
return true;
}
// Check version marker
const currentPackageVersion = getPackageVersion();
@@ -143,46 +137,6 @@ function needsInstall() {
return false;
}
/**
* Verify that better-sqlite3 native module loads correctly
* This catches ABI mismatches and corrupted builds
*/
async function verifyNativeModules() {
try {
log('🔍 Verifying native modules...', colors.dim);
// CRITICAL: Use createRequire() to resolve from MARKETPLACE_ROOT
// This script may run from cache but must load modules from marketplace's node_modules
const require = createRequire(join(MARKETPLACE_ROOT, 'package.json'));
const Database = require('better-sqlite3');
// Try to create a test in-memory database
const db = new Database(':memory:');
// Run a simple query to ensure it works
const result = db.prepare('SELECT 1 + 1 as result').get();
// Clean up
db.close();
if (result.result !== 2) {
throw new Error('SQLite math check failed');
}
log('✓ Native modules verified', colors.dim);
return true;
} catch (error) {
if (error.code === 'ERR_DLOPEN_FAILED') {
log('⚠️ Native module ABI mismatch detected', colors.yellow);
return false;
}
// Other errors are unexpected - log and fail
log(`❌ Native module verification failed: ${error.message}`, colors.red);
return false;
}
}
function getWindowsErrorHelp(errorOutput) {
// Detect Python version at runtime
@@ -203,7 +157,7 @@ function getWindowsErrorHelp(errorOutput) {
'║ Windows Installation Help ║',
'╚══════════════════════════════════════════════════════════════════════╝',
'',
'📋 better-sqlite3 requires build tools to compile native modules.',
'',
'',
'🔧 Option 1: Install Visual Studio Build Tools (Recommended)',
' 1. Download: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022',
@@ -232,9 +186,6 @@ function getWindowsErrorHelp(errorOutput) {
help.push('❌ Permission denied - try running as Administrator');
}
help.push('');
help.push('📖 Full documentation: https://github.com/WiseLibs/better-sqlite3/blob/master/docs/troubleshooting.md');
help.push('');
return help.join('\n');
}
@@ -266,10 +217,7 @@ async function runNpmInstall() {
windowsHide: true,
});
// Verify better-sqlite3 was installed
if (!existsSync(BETTER_SQLITE3_PATH)) {
throw new Error('better-sqlite3 installation verification failed');
}
// NEW: Verify native modules actually work
const nativeModulesWork = await verifyNativeModules();
@@ -300,11 +248,6 @@ async function runNpmInstall() {
log('❌ Installation failed after retrying!', colors.bright);
log('', colors.reset);
// Provide Windows-specific help
if (isWindows && lastError && lastError.message && lastError.message.includes('better-sqlite3')) {
log(getWindowsErrorHelp(lastError.message), colors.yellow);
}
// Show generic error info with troubleshooting steps
if (lastError) {
if (lastError.stderr) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { Database } from 'better-sqlite3';
import { Database } from 'bun:sqlite';
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
export interface Migration {
+9 -9
View File
@@ -1,4 +1,4 @@
import Database from 'better-sqlite3';
import { Database } from 'bun:sqlite';
import { TableNameRow } from '../../types/database.js';
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
import {
@@ -18,7 +18,7 @@ import {
* Vector search is handled by ChromaDB - this class only supports filtering without query text
*/
export class SessionSearch {
private db: Database.Database;
private db: Database;
constructor(dbPath?: string) {
if (!dbPath) {
@@ -26,7 +26,7 @@ export class SessionSearch {
dbPath = DB_PATH;
}
this.db = new Database(dbPath);
this.db.pragma('journal_mode = WAL');
this.db.run('PRAGMA journal_mode = WAL');
// Ensure FTS tables exist
this.ensureFTSTables();
@@ -60,7 +60,7 @@ export class SessionSearch {
console.error('[SessionSearch] Creating FTS5 tables...');
// Create observations_fts virtual table
this.db.exec(`
this.db.run(`
CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5(
title,
subtitle,
@@ -74,14 +74,14 @@ export class SessionSearch {
`);
// Populate with existing data
this.db.exec(`
this.db.run(`
INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
SELECT id, title, subtitle, narrative, text, facts, concepts
FROM observations;
`);
// Create triggers for observations
this.db.exec(`
this.db.run(`
CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN
INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
@@ -101,7 +101,7 @@ export class SessionSearch {
`);
// Create session_summaries_fts virtual table
this.db.exec(`
this.db.run(`
CREATE VIRTUAL TABLE IF NOT EXISTS session_summaries_fts USING fts5(
request,
investigated,
@@ -115,14 +115,14 @@ export class SessionSearch {
`);
// Populate with existing data
this.db.exec(`
this.db.run(`
INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes)
SELECT id, request, investigated, learned, completed, next_steps, notes
FROM session_summaries;
`);
// Create triggers for session_summaries
this.db.exec(`
this.db.run(`
CREATE TRIGGER IF NOT EXISTS session_summaries_ai AFTER INSERT ON session_summaries BEGIN
INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes)
VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes);
+46 -46
View File
@@ -1,4 +1,4 @@
import Database from 'better-sqlite3';
import { Database } from 'bun:sqlite';
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
import { logger } from '../../utils/logger.js';
import {
@@ -18,16 +18,16 @@ import {
* Provides simple, synchronous CRUD operations for session-based memory
*/
export class SessionStore {
public db: Database.Database;
public db: Database;
constructor() {
ensureDir(DATA_DIR);
this.db = new Database(DB_PATH);
// Ensure optimized settings
this.db.pragma('journal_mode = WAL');
this.db.pragma('synchronous = NORMAL');
this.db.pragma('foreign_keys = ON');
this.db.run('PRAGMA journal_mode = WAL');
this.db.run('PRAGMA synchronous = NORMAL');
this.db.run('PRAGMA foreign_keys = ON');
// Initialize schema if needed (fresh database)
this.initializeSchema();
@@ -49,7 +49,7 @@ export class SessionStore {
private initializeSchema(): void {
try {
// Create schema_versions table if it doesn't exist
this.db.exec(`
this.db.run(`
CREATE TABLE IF NOT EXISTS schema_versions (
id INTEGER PRIMARY KEY,
version INTEGER UNIQUE NOT NULL,
@@ -67,7 +67,7 @@ export class SessionStore {
console.error('[SessionStore] Initializing fresh database with migration004...');
// Migration004: SDK agent architecture tables
this.db.exec(`
this.db.run(`
CREATE TABLE IF NOT EXISTS sdk_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
claude_session_id TEXT UNIQUE NOT NULL,
@@ -146,11 +146,11 @@ export class SessionStore {
if (applied) return;
// Check if column exists
const tableInfo = this.db.pragma('table_info(sdk_sessions)') as TableColumnInfo[];
const tableInfo = this.db.query('PRAGMA table_info(sdk_sessions)').all() as TableColumnInfo[];
const hasWorkerPort = tableInfo.some(col => col.name === 'worker_port');
if (!hasWorkerPort) {
this.db.exec('ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER');
this.db.run('ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER');
console.error('[SessionStore] Added worker_port column to sdk_sessions table');
}
@@ -171,29 +171,29 @@ export class SessionStore {
if (applied) return;
// Check sdk_sessions for prompt_counter
const sessionsInfo = this.db.pragma('table_info(sdk_sessions)') as TableColumnInfo[];
const sessionsInfo = this.db.query('PRAGMA table_info(sdk_sessions)').all() as TableColumnInfo[];
const hasPromptCounter = sessionsInfo.some(col => col.name === 'prompt_counter');
if (!hasPromptCounter) {
this.db.exec('ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0');
this.db.run('ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0');
console.error('[SessionStore] Added prompt_counter column to sdk_sessions table');
}
// Check observations for prompt_number
const observationsInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
const observationsInfo = this.db.query('PRAGMA table_info(observations)').all() as TableColumnInfo[];
const obsHasPromptNumber = observationsInfo.some(col => col.name === 'prompt_number');
if (!obsHasPromptNumber) {
this.db.exec('ALTER TABLE observations ADD COLUMN prompt_number INTEGER');
this.db.run('ALTER TABLE observations ADD COLUMN prompt_number INTEGER');
console.error('[SessionStore] Added prompt_number column to observations table');
}
// Check session_summaries for prompt_number
const summariesInfo = this.db.pragma('table_info(session_summaries)') as TableColumnInfo[];
const summariesInfo = this.db.query('PRAGMA table_info(session_summaries)').all() as TableColumnInfo[];
const sumHasPromptNumber = summariesInfo.some(col => col.name === 'prompt_number');
if (!sumHasPromptNumber) {
this.db.exec('ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER');
this.db.run('ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER');
console.error('[SessionStore] Added prompt_number column to session_summaries table');
}
@@ -214,7 +214,7 @@ export class SessionStore {
if (applied) return;
// Check if UNIQUE constraint exists
const summariesIndexes = this.db.pragma('index_list(session_summaries)') as IndexInfo[];
const summariesIndexes = this.db.query('PRAGMA index_list(session_summaries)').all() as IndexInfo[];
const hasUniqueConstraint = summariesIndexes.some(idx => idx.unique === 1);
if (!hasUniqueConstraint) {
@@ -226,11 +226,11 @@ export class SessionStore {
console.error('[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id...');
// Begin transaction
this.db.exec('BEGIN TRANSACTION');
this.db.run('BEGIN TRANSACTION');
try {
// Create new table without UNIQUE constraint
this.db.exec(`
this.db.run(`
CREATE TABLE session_summaries_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sdk_session_id TEXT NOT NULL,
@@ -251,7 +251,7 @@ export class SessionStore {
`);
// Copy data from old table
this.db.exec(`
this.db.run(`
INSERT INTO session_summaries_new
SELECT id, sdk_session_id, project, request, investigated, learned,
completed, next_steps, files_read, files_edited, notes,
@@ -260,20 +260,20 @@ export class SessionStore {
`);
// Drop old table
this.db.exec('DROP TABLE session_summaries');
this.db.run('DROP TABLE session_summaries');
// Rename new table
this.db.exec('ALTER TABLE session_summaries_new RENAME TO session_summaries');
this.db.run('ALTER TABLE session_summaries_new RENAME TO session_summaries');
// Recreate indexes
this.db.exec(`
this.db.run(`
CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id);
CREATE INDEX idx_session_summaries_project ON session_summaries(project);
CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC);
`);
// Commit transaction
this.db.exec('COMMIT');
this.db.run('COMMIT');
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(7, new Date().toISOString());
@@ -281,7 +281,7 @@ export class SessionStore {
console.error('[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id');
} catch (error: any) {
// Rollback on error
this.db.exec('ROLLBACK');
this.db.run('ROLLBACK');
throw error;
}
} catch (error: any) {
@@ -299,7 +299,7 @@ export class SessionStore {
if (applied) return;
// Check if new fields already exist
const tableInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
const tableInfo = this.db.query('PRAGMA table_info(observations)').all() as TableColumnInfo[];
const hasTitle = tableInfo.some(col => col.name === 'title');
if (hasTitle) {
@@ -311,7 +311,7 @@ export class SessionStore {
console.error('[SessionStore] Adding hierarchical fields to observations table...');
// Add new columns
this.db.exec(`
this.db.run(`
ALTER TABLE observations ADD COLUMN title TEXT;
ALTER TABLE observations ADD COLUMN subtitle TEXT;
ALTER TABLE observations ADD COLUMN facts TEXT;
@@ -341,7 +341,7 @@ export class SessionStore {
if (applied) return;
// Check if text column is already nullable
const tableInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
const tableInfo = this.db.query('PRAGMA table_info(observations)').all() as TableColumnInfo[];
const textColumn = tableInfo.find(col => col.name === 'text');
if (!textColumn || textColumn.notnull === 0) {
@@ -353,11 +353,11 @@ export class SessionStore {
console.error('[SessionStore] Making observations.text nullable...');
// Begin transaction
this.db.exec('BEGIN TRANSACTION');
this.db.run('BEGIN TRANSACTION');
try {
// Create new table with text as nullable
this.db.exec(`
this.db.run(`
CREATE TABLE observations_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sdk_session_id TEXT NOT NULL,
@@ -379,7 +379,7 @@ export class SessionStore {
`);
// Copy data from old table (all existing columns)
this.db.exec(`
this.db.run(`
INSERT INTO observations_new
SELECT id, sdk_session_id, project, text, type, title, subtitle, facts,
narrative, concepts, files_read, files_modified, prompt_number,
@@ -388,13 +388,13 @@ export class SessionStore {
`);
// Drop old table
this.db.exec('DROP TABLE observations');
this.db.run('DROP TABLE observations');
// Rename new table
this.db.exec('ALTER TABLE observations_new RENAME TO observations');
this.db.run('ALTER TABLE observations_new RENAME TO observations');
// Recreate indexes
this.db.exec(`
this.db.run(`
CREATE INDEX idx_observations_sdk_session ON observations(sdk_session_id);
CREATE INDEX idx_observations_project ON observations(project);
CREATE INDEX idx_observations_type ON observations(type);
@@ -402,7 +402,7 @@ export class SessionStore {
`);
// Commit transaction
this.db.exec('COMMIT');
this.db.run('COMMIT');
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(9, new Date().toISOString());
@@ -410,7 +410,7 @@ export class SessionStore {
console.error('[SessionStore] Successfully made observations.text nullable');
} catch (error: any) {
// Rollback on error
this.db.exec('ROLLBACK');
this.db.run('ROLLBACK');
throw error;
}
} catch (error: any) {
@@ -428,7 +428,7 @@ export class SessionStore {
if (applied) return;
// Check if table already exists
const tableInfo = this.db.pragma('table_info(user_prompts)') as TableColumnInfo[];
const tableInfo = this.db.query('PRAGMA table_info(user_prompts)').all() as TableColumnInfo[];
if (tableInfo.length > 0) {
// Already migrated
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());
@@ -438,11 +438,11 @@ export class SessionStore {
console.error('[SessionStore] Creating user_prompts table with FTS5 support...');
// Begin transaction
this.db.exec('BEGIN TRANSACTION');
this.db.run('BEGIN TRANSACTION');
try {
// Create main table (using claude_session_id since sdk_session_id is set asynchronously by worker)
this.db.exec(`
this.db.run(`
CREATE TABLE user_prompts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
claude_session_id TEXT NOT NULL,
@@ -460,7 +460,7 @@ export class SessionStore {
`);
// Create FTS5 virtual table
this.db.exec(`
this.db.run(`
CREATE VIRTUAL TABLE user_prompts_fts USING fts5(
prompt_text,
content='user_prompts',
@@ -469,7 +469,7 @@ export class SessionStore {
`);
// Create triggers to sync FTS5
this.db.exec(`
this.db.run(`
CREATE TRIGGER user_prompts_ai AFTER INSERT ON user_prompts BEGIN
INSERT INTO user_prompts_fts(rowid, prompt_text)
VALUES (new.id, new.prompt_text);
@@ -489,7 +489,7 @@ export class SessionStore {
`);
// Commit transaction
this.db.exec('COMMIT');
this.db.run('COMMIT');
// Record migration
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());
@@ -497,7 +497,7 @@ export class SessionStore {
console.error('[SessionStore] Successfully created user_prompts table with FTS5 support');
} catch (error: any) {
// Rollback on error
this.db.exec('ROLLBACK');
this.db.run('ROLLBACK');
throw error;
}
} catch (error: any) {
@@ -517,20 +517,20 @@ export class SessionStore {
if (applied) return;
// Check if discovery_tokens column exists in observations table
const observationsInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
const observationsInfo = this.db.query('PRAGMA table_info(observations)').all() as TableColumnInfo[];
const obsHasDiscoveryTokens = observationsInfo.some(col => col.name === 'discovery_tokens');
if (!obsHasDiscoveryTokens) {
this.db.exec('ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
this.db.run('ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
console.error('[SessionStore] Added discovery_tokens column to observations table');
}
// Check if discovery_tokens column exists in session_summaries table
const summariesInfo = this.db.pragma('table_info(session_summaries)') as TableColumnInfo[];
const summariesInfo = this.db.query('PRAGMA table_info(session_summaries)').all() as TableColumnInfo[];
const sumHasDiscoveryTokens = summariesInfo.some(col => col.name === 'discovery_tokens');
if (!sumHasDiscoveryTokens) {
this.db.exec('ALTER TABLE session_summaries ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
this.db.run('ALTER TABLE session_summaries ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
console.error('[SessionStore] Added discovery_tokens column to session_summaries table');
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { Database } from 'better-sqlite3';
import { Database } from 'bun:sqlite';
import { Migration } from './Database.js';
/**