Files
Claude-Code-Monitor/docs/superpowers/plans/2026-03-16-remove-native-sqlite-dependency.md
T
nntrivi2001 57dc91585d feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
2026-07-30 14:39:03 +07:00

7.2 KiB

Remove Native SQLite Dependency — Implementation Plan

For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Replace better-sqlite3 (native C++ module requiring Python/build tools) with a compatibility layer over Node.js built-in node:sqlite, so npm install succeeds on any machine without native compilation tools.

Architecture: Create server/compat-sqlite.js — a thin wrapper that gives DatabaseSync (from node:sqlite) the same API as better-sqlite3. Move better-sqlite3 to optionalDependencies so it's preferred when prebuilds are available but doesn't block install. The server/db.js loader tries better-sqlite3 first, falls back to the compat wrapper. Update minimum Node version to 22.

Tech Stack: Node.js node:sqlite (DatabaseSync), existing Express/WS server


File Structure

File Action Responsibility
server/compat-sqlite.js Create Wrapper class: DatabaseSync → better-sqlite3 API
server/db.js Modify (line 1) Try better-sqlite3, fallback to compat wrapper
scripts/clear-data.js Modify (line 8) Same fallback import
package.json Modify Move better-sqlite3 to optionalDependencies, bump engines to >=22
server/__tests__/api.test.js Modify (lines 952-959) Fix db.pragma() calls to work with both backends

Chunk 1: Core Implementation

Task 1: Create server/compat-sqlite.js

Files:

  • Create: server/compat-sqlite.js

  • Step 1: Write the compat wrapper

The wrapper must bridge these API differences:

better-sqlite3 node:sqlite (DatabaseSync)
new Database(path) new DatabaseSync(path)
db.pragma("key = value") db.exec("PRAGMA key = value")
db.pragma("key") → value db.prepare("PRAGMA key").get(){key: value}
db.pragma("key", { simple: true }) → value same as above, extract single value
db.transaction(fn) → wrapper fn manual BEGIN/COMMIT/ROLLBACK
db.prepare(sql) → stmt with .run(), .get(), .all() identical API
db.exec(sql) identical
db.close() identical
// server/compat-sqlite.js
const { DatabaseSync } = require("node:sqlite");

class Database {
  constructor(filePath) {
    this._db = new DatabaseSync(filePath);
  }

  exec(sql) {
    this._db.exec(sql);
    return this;
  }

  pragma(str, options) {
    if (str.includes("=")) {
      this._db.exec(`PRAGMA ${str}`);
      return undefined;
    }
    const row = this._db.prepare(`PRAGMA ${str}`).get();
    if (!row) return undefined;
    const keys = Object.keys(row);
    if (options?.simple || keys.length === 1) return row[keys[0]];
    return row;
  }

  prepare(sql) {
    return this._db.prepare(sql);
  }

  transaction(fn) {
    const db = this._db;
    const wrapper = (...args) => {
      db.exec("BEGIN");
      try {
        const result = fn(...args);
        db.exec("COMMIT");
        return result;
      } catch (err) {
        db.exec("ROLLBACK");
        throw err;
      }
    };
    return wrapper;
  }

  close() {
    this._db.close();
  }
}

module.exports = Database;
  • Step 2: Verify the wrapper works standalone

Run: node -e "const DB = require('./server/compat-sqlite'); const db = new DB(':memory:'); db.pragma('journal_mode = WAL'); db.exec('CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)'); const s = db.prepare('INSERT INTO t (v) VALUES (?)'); console.log(s.run('hi')); console.log(db.prepare('SELECT * FROM t').all()); const tx = db.transaction((items) => { for (const i of items) s.run(i); }); tx(['a','b','c']); console.log(db.prepare('SELECT COUNT(*) as c FROM t').get()); db.close(); console.log('OK')"

Expected: OK printed at the end with correct query results.

  • Step 3: Commit
git add server/compat-sqlite.js
git commit -m "feat: add node:sqlite compat wrapper for better-sqlite3 API"

Task 2: Update server/db.js to use fallback import

Files:

  • Modify: server/db.js:1

  • Step 1: Replace the import

Change line 1 from:

const Database = require("better-sqlite3");

To:

let Database;
try {
  Database = require("better-sqlite3");
} catch {
  Database = require("./compat-sqlite");
}
  • Step 2: Verify server starts

Run: node -e "process.env.DASHBOARD_DB_PATH = require('path').join(require('os').tmpdir(), 'test-fallback-' + Date.now() + '.db'); const { db, stmts } = require('./server/db'); console.log('stmts keys:', Object.keys(stmts).length); stmts.insertSession.run('test-1', 'Test', 'active', null, null, null); console.log(stmts.getSession.get('test-1')); db.close(); console.log('OK')"

Expected: Prints statement count (39), session row, and OK.

  • Step 3: Commit
git add server/db.js
git commit -m "feat: fallback to node:sqlite when better-sqlite3 unavailable"

Task 3: Update scripts/clear-data.js to use fallback import

Files:

  • Modify: scripts/clear-data.js:8

  • Step 1: Replace the import

Change line 8 from:

const Database = require("better-sqlite3");

To:

let Database;
try {
  Database = require("better-sqlite3");
} catch {
  Database = require("../server/compat-sqlite");
}
  • Step 2: Commit
git add scripts/clear-data.js
git commit -m "fix: use fallback sqlite import in clear-data script"

Task 4: Update package.json

Files:

  • Modify: package.json

  • Step 1: Move better-sqlite3 to optionalDependencies, bump engines

Move "better-sqlite3": "^11.7.0" from dependencies to optionalDependencies. Change engines from "node": ">=18.0.0" to "node": ">=22.0.0".

  • Step 2: Commit
git add package.json
git commit -m "chore: make better-sqlite3 optional, require Node >= 22"

Task 5: Fix test pragma calls

Files:

  • Modify: server/__tests__/api.test.js:952-959

  • Step 1: Fix pragma calls in Database Integrity tests

The tests call db.pragma("journal_mode", { simple: true }) and db.pragma("foreign_keys", { simple: true }). The compat wrapper supports { simple: true }, so these should work as-is. However, WAL mode isn't available for in-memory databases (returns "memory"). The test creates a file-based DB via TEST_DB, so WAL should work.

No change needed — verify by running tests.

  • Step 2: Run full test suite

Run: node --test server/__tests__/api.test.js

Expected: All tests pass.

  • Step 3: Run setup to verify npm install succeeds without Python

Run: npm run setup

Expected: Install succeeds (better-sqlite3 may warn but won't fail since it's optional).


Task 6: Update documentation

Files:

  • Modify: SETUP.md (if it mentions better-sqlite3 or Python requirements)

  • Step 1: Check and update SETUP.md

Remove any mentions of Python or build tools as requirements. Note that Node >= 22 is required.

  • Step 2: Commit all remaining changes
git add -A
git commit -m "docs: update setup requirements for native-free SQLite"