@cardor/agent-harness-kit 1.2.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +352 -51
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/{mysql-IMDWH2CU.js → mysql-NXLYFD2H.js} +11 -2
- package/dist/mysql-NXLYFD2H.js.map +1 -0
- package/dist/{postgres-TYINLEAT.js → postgres-6BXN7ZH4.js} +11 -2
- package/dist/postgres-6BXN7ZH4.js.map +1 -0
- package/dist/{sqlite-5R6LB3RX.js → sqlite-M65L55DA.js} +15 -2
- package/dist/sqlite-M65L55DA.js.map +1 -0
- package/package.json +1 -1
- package/dist/mysql-IMDWH2CU.js.map +0 -1
- package/dist/postgres-TYINLEAT.js.map +0 -1
- package/dist/sqlite-5R6LB3RX.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,7 @@ interface TaskRow {
|
|
|
88
88
|
created_at: string;
|
|
89
89
|
started_at: string | null;
|
|
90
90
|
completed_at: string | null;
|
|
91
|
+
archived_at: string | null;
|
|
91
92
|
}
|
|
92
93
|
type AgentName = 'lead' | 'explorer' | 'builder' | 'reviewer' | `custom:${string}`;
|
|
93
94
|
type ActionStatus = 'in_progress' | 'completed' | 'blocked';
|
|
@@ -11,7 +11,8 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|
|
11
11
|
assigned_to VARCHAR(255),
|
|
12
12
|
created_at VARCHAR(30) NOT NULL,
|
|
13
13
|
started_at VARCHAR(30),
|
|
14
|
-
completed_at VARCHAR(30)
|
|
14
|
+
completed_at VARCHAR(30),
|
|
15
|
+
archived_at VARCHAR(30)
|
|
15
16
|
);
|
|
16
17
|
|
|
17
18
|
CREATE TABLE IF NOT EXISTS task_acceptance (
|
|
@@ -82,6 +83,10 @@ var MySQLDriver = class {
|
|
|
82
83
|
for (const stmt of statements) {
|
|
83
84
|
await conn.execute(stmt);
|
|
84
85
|
}
|
|
86
|
+
try {
|
|
87
|
+
await conn.execute("ALTER TABLE tasks ADD COLUMN archived_at VARCHAR(30)");
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
85
90
|
} finally {
|
|
86
91
|
conn.release();
|
|
87
92
|
}
|
|
@@ -120,6 +125,8 @@ var MySQLDriver = class {
|
|
|
120
125
|
conn.release();
|
|
121
126
|
}
|
|
122
127
|
}
|
|
128
|
+
async reconnect() {
|
|
129
|
+
}
|
|
123
130
|
async close() {
|
|
124
131
|
await this.pool.end();
|
|
125
132
|
}
|
|
@@ -152,10 +159,12 @@ var MySQLTxDriver = class {
|
|
|
152
159
|
}
|
|
153
160
|
async ensureSchema() {
|
|
154
161
|
}
|
|
162
|
+
async reconnect() {
|
|
163
|
+
}
|
|
155
164
|
async close() {
|
|
156
165
|
}
|
|
157
166
|
};
|
|
158
167
|
export {
|
|
159
168
|
MySQLDriver
|
|
160
169
|
};
|
|
161
|
-
//# sourceMappingURL=mysql-
|
|
170
|
+
//# sourceMappingURL=mysql-NXLYFD2H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/drivers/mysql.ts"],"sourcesContent":["import mysql, { type ExecuteValues } from 'mysql2/promise'\n\nimport type { DBDriver } from './types'\nimport type { RemoteDBConfig } from '@/types'\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS tasks (\n id INT AUTO_INCREMENT PRIMARY KEY,\n slug VARCHAR(255) NOT NULL UNIQUE,\n title VARCHAR(500) NOT NULL,\n description TEXT,\n status VARCHAR(20) NOT NULL DEFAULT 'pending'\n CHECK(status IN ('pending','in_progress','done','blocked')),\n assigned_to VARCHAR(255),\n created_at VARCHAR(30) NOT NULL,\n started_at VARCHAR(30),\n completed_at VARCHAR(30),\n archived_at VARCHAR(30)\n);\n\nCREATE TABLE IF NOT EXISTS task_acceptance (\n id INT AUTO_INCREMENT PRIMARY KEY,\n task_id INT NOT NULL,\n criterion TEXT NOT NULL,\n met INT NOT NULL DEFAULT 0,\n FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id VARCHAR(36) PRIMARY KEY,\n task_id INT NOT NULL,\n agent VARCHAR(100) NOT NULL,\n status VARCHAR(20) NOT NULL DEFAULT 'in_progress'\n CHECK(status IN ('in_progress','completed','blocked')),\n created_at VARCHAR(30) NOT NULL,\n completed_at VARCHAR(30),\n summary TEXT,\n FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS action_sections (\n id INT AUTO_INCREMENT PRIMARY KEY,\n action_id VARCHAR(36) NOT NULL,\n section_type VARCHAR(100) NOT NULL,\n content TEXT NOT NULL,\n created_at VARCHAR(30) NOT NULL,\n FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS action_files (\n id INT AUTO_INCREMENT PRIMARY KEY,\n action_id VARCHAR(36) NOT NULL,\n file_path VARCHAR(1000) NOT NULL,\n operation VARCHAR(20) NOT NULL\n CHECK(operation IN ('read','created','modified','deleted')),\n notes TEXT,\n FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS action_tools (\n id INT AUTO_INCREMENT PRIMARY KEY,\n action_id VARCHAR(36) NOT NULL,\n tool_name VARCHAR(255) NOT NULL,\n args_json TEXT,\n result_summary TEXT,\n called_at VARCHAR(30) NOT NULL,\n FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_actions_task_id ON actions(task_id);\nCREATE INDEX IF NOT EXISTS idx_actions_agent ON actions(agent);\nCREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\nCREATE INDEX IF NOT EXISTS idx_action_files_path ON action_files(file_path(255));\nCREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);\n`\n\ntype MySQLPool = mysql.Pool\n\nexport class MySQLDriver implements DBDriver {\n private pool: MySQLPool\n\n constructor(config: RemoteDBConfig) {\n this.pool = mysql.createPool(config.connectionString)\n }\n\n async ensureSchema(): Promise<void> {\n // Run each statement individually since mysql2 doesn't support multi-statement by default\n const statements = SCHEMA.split(';')\n .map((s) => s.trim())\n .filter(Boolean)\n\n const conn = await this.pool.getConnection()\n try {\n for (const stmt of statements) {\n await conn.execute(stmt)\n }\n // Migration: add archived_at column (safe to run multiple times)\n try {\n await conn.execute('ALTER TABLE tasks ADD COLUMN archived_at VARCHAR(30)')\n } catch {\n // Column already exists — ignore\n }\n } finally {\n conn.release()\n }\n }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const [rows] = await this.pool.execute(sql, params as ExecuteValues)\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n const rows = await this.query<T>(sql, params)\n return (rows as T[])[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.pool.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).insertId\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.pool.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).affectedRows\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.pool.query(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n const conn = await this.pool.getConnection()\n await conn.beginTransaction()\n try {\n const txDriver = new MySQLTxDriver(conn)\n const result = await fn(txDriver)\n await conn.commit()\n return result\n } catch (err) {\n await conn.rollback()\n throw err\n } finally {\n conn.release()\n }\n }\n\n async reconnect(): Promise<void> {\n /* no-op — connection pool handles freshness */\n }\n\n async close(): Promise<void> {\n await this.pool.end()\n }\n}\n\nclass MySQLTxDriver implements DBDriver {\n constructor(private conn: mysql.PoolConnection) { }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const [rows] = await this.conn.execute(sql, params as ExecuteValues)\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n return (await this.query<T>(sql, params))[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.conn.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).insertId\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.conn.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).affectedRows\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.conn.query(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n return fn(this)\n }\n\n async ensureSchema(): Promise<void> { }\n async reconnect(): Promise<void> {\n /* no-op — connection pool handles freshness */\n }\n async close(): Promise<void> { }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -11,7 +11,8 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|
|
11
11
|
assigned_to TEXT,
|
|
12
12
|
created_at TEXT NOT NULL,
|
|
13
13
|
started_at TEXT,
|
|
14
|
-
completed_at TEXT
|
|
14
|
+
completed_at TEXT,
|
|
15
|
+
archived_at TEXT
|
|
15
16
|
);
|
|
16
17
|
|
|
17
18
|
CREATE TABLE IF NOT EXISTS task_acceptance (
|
|
@@ -77,6 +78,10 @@ var PostgresDriver = class {
|
|
|
77
78
|
}
|
|
78
79
|
async ensureSchema() {
|
|
79
80
|
await this.sql.unsafe(SCHEMA);
|
|
81
|
+
try {
|
|
82
|
+
await this.sql.unsafe(`ALTER TABLE tasks ADD COLUMN archived_at TEXT`);
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
80
85
|
}
|
|
81
86
|
async query(sql, params = []) {
|
|
82
87
|
const rows = await this.sql.unsafe(toPositional(sql), params);
|
|
@@ -106,6 +111,8 @@ var PostgresDriver = class {
|
|
|
106
111
|
});
|
|
107
112
|
return result;
|
|
108
113
|
}
|
|
114
|
+
async reconnect() {
|
|
115
|
+
}
|
|
109
116
|
async close() {
|
|
110
117
|
await this.sql.end();
|
|
111
118
|
}
|
|
@@ -139,10 +146,12 @@ var PostgresTxDriver = class {
|
|
|
139
146
|
}
|
|
140
147
|
async ensureSchema() {
|
|
141
148
|
}
|
|
149
|
+
async reconnect() {
|
|
150
|
+
}
|
|
142
151
|
async close() {
|
|
143
152
|
}
|
|
144
153
|
};
|
|
145
154
|
export {
|
|
146
155
|
PostgresDriver
|
|
147
156
|
};
|
|
148
|
-
//# sourceMappingURL=postgres-
|
|
157
|
+
//# sourceMappingURL=postgres-6BXN7ZH4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/drivers/postgres.ts"],"sourcesContent":["import postgres from 'postgres'\n\nimport type { DBDriver } from './types'\nimport type { RemoteDBConfig } from '@/types'\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS tasks (\n id SERIAL PRIMARY KEY,\n slug TEXT NOT NULL UNIQUE,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT NOT NULL DEFAULT 'pending'\n CHECK(status IN ('pending','in_progress','done','blocked')),\n assigned_to TEXT,\n created_at TEXT NOT NULL,\n started_at TEXT,\n completed_at TEXT,\n archived_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS task_acceptance (\n id SERIAL PRIMARY KEY,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n criterion TEXT NOT NULL,\n met INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id TEXT PRIMARY KEY,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n agent TEXT NOT NULL\n CHECK(agent IN ('lead','explorer','builder','reviewer') OR agent LIKE 'custom:%'),\n status TEXT NOT NULL DEFAULT 'in_progress'\n CHECK(status IN ('in_progress','completed','blocked')),\n created_at TEXT NOT NULL,\n completed_at TEXT,\n summary TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_sections (\n id SERIAL PRIMARY KEY,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n section_type TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS action_files (\n id SERIAL PRIMARY KEY,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n file_path TEXT NOT NULL,\n operation TEXT NOT NULL\n CHECK(operation IN ('read','created','modified','deleted')),\n notes TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_tools (\n id SERIAL PRIMARY KEY,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n args_json TEXT,\n result_summary TEXT,\n called_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_actions_task_id ON actions(task_id);\nCREATE INDEX IF NOT EXISTS idx_actions_agent ON actions(agent);\nCREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\nCREATE INDEX IF NOT EXISTS idx_action_files_path ON action_files(file_path);\nCREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);\n`\n\n// Convert SQLite-style ? placeholders to Postgres $1, $2, ...\nfunction toPositional(sql: string): string {\n let i = 0\n return sql.replace(/\\?/g, () => `$${++i}`)\n}\n\nexport class PostgresDriver implements DBDriver {\n private sql: postgres.Sql\n\n constructor(config: RemoteDBConfig) {\n this.sql = postgres(config.connectionString)\n }\n\n async ensureSchema(): Promise<void> {\n await this.sql.unsafe(SCHEMA)\n // Migration: add archived_at column (safe to run multiple times)\n try {\n await this.sql.unsafe(`ALTER TABLE tasks ADD COLUMN archived_at TEXT`)\n } catch {\n // Column already exists — ignore\n }\n }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const rows = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n const rows = await this.query<T>(sql, params)\n return rows[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const withReturning = toPositional(sql.trimEnd()) + ' RETURNING id'\n const rows = await this.sql.unsafe(withReturning, params as postgres.ParameterOrJSON<never>[])\n return (rows[0] as unknown as { id: number }).id\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const result = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return result.count\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.sql.unsafe(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n let result!: T\n await this.sql.begin(async (txSql) => {\n const txDriver = new PostgresTxDriver(txSql)\n result = await fn(txDriver)\n })\n return result\n }\n\n async reconnect(): Promise<void> {\n /* no-op — connection pool handles freshness */\n }\n\n async close(): Promise<void> {\n await this.sql.end()\n }\n}\n\nclass PostgresTxDriver implements DBDriver {\n constructor(private sql: postgres.TransactionSql) { }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const rows = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n return (await this.query<T>(sql, params))[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const withReturning = toPositional(sql.trimEnd()) + ' RETURNING id'\n const rows = await this.sql.unsafe(withReturning, params as postgres.ParameterOrJSON<never>[])\n return (rows[0] as unknown as { id: number }).id\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const result = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return result.count\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.sql.unsafe(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n return fn(this)\n }\n\n async ensureSchema(): Promise<void> { }\n async reconnect(): Promise<void> {\n /* no-op — connection pool handles freshness */\n }\n async close(): Promise<void> { }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -31,7 +31,8 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|
|
31
31
|
assigned_to TEXT,
|
|
32
32
|
created_at TEXT NOT NULL,
|
|
33
33
|
started_at TEXT,
|
|
34
|
-
completed_at TEXT
|
|
34
|
+
completed_at TEXT,
|
|
35
|
+
archived_at TEXT
|
|
35
36
|
);
|
|
36
37
|
|
|
37
38
|
CREATE TABLE IF NOT EXISTS task_acceptance (
|
|
@@ -88,7 +89,9 @@ CREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);
|
|
|
88
89
|
`;
|
|
89
90
|
var SQLiteDriver = class {
|
|
90
91
|
db;
|
|
92
|
+
dbPath;
|
|
91
93
|
constructor(dbPath) {
|
|
94
|
+
this.dbPath = dbPath;
|
|
92
95
|
mkdirSync(dirname(dbPath), { recursive: true });
|
|
93
96
|
if (existsSync(dbPath)) {
|
|
94
97
|
const shm = `${dbPath}-shm`;
|
|
@@ -104,6 +107,10 @@ var SQLiteDriver = class {
|
|
|
104
107
|
}
|
|
105
108
|
async ensureSchema() {
|
|
106
109
|
this.db.exec(SCHEMA);
|
|
110
|
+
try {
|
|
111
|
+
this.db.exec("ALTER TABLE tasks ADD COLUMN archived_at TEXT");
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
107
114
|
}
|
|
108
115
|
async query(sql, params = []) {
|
|
109
116
|
return this.db.prepare(sql).all(...params);
|
|
@@ -122,6 +129,12 @@ var SQLiteDriver = class {
|
|
|
122
129
|
async execRaw(sql) {
|
|
123
130
|
this.db.exec(sql);
|
|
124
131
|
}
|
|
132
|
+
async reconnect() {
|
|
133
|
+
this.db.close();
|
|
134
|
+
this.db = openSQLite(this.dbPath);
|
|
135
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
136
|
+
this.db.exec("PRAGMA foreign_keys = ON");
|
|
137
|
+
}
|
|
125
138
|
async transaction(fn) {
|
|
126
139
|
this.db.exec("BEGIN IMMEDIATE");
|
|
127
140
|
try {
|
|
@@ -140,4 +153,4 @@ var SQLiteDriver = class {
|
|
|
140
153
|
export {
|
|
141
154
|
SQLiteDriver
|
|
142
155
|
};
|
|
143
|
-
//# sourceMappingURL=sqlite-
|
|
156
|
+
//# sourceMappingURL=sqlite-M65L55DA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/drivers/sqlite.ts","../src/core/sqlite-adapter.ts"],"sourcesContent":["import { existsSync, mkdirSync, rmSync, statSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\nimport { lastInsertId, openSQLite, type SQLiteDB } from '../sqlite-adapter'\n\nimport type { DBDriver } from './types'\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS tasks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n slug TEXT NOT NULL UNIQUE,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT NOT NULL DEFAULT 'pending'\n CHECK(status IN ('pending','in_progress','done','blocked')),\n assigned_to TEXT,\n created_at TEXT NOT NULL,\n started_at TEXT,\n completed_at TEXT,\n archived_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS task_acceptance (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n criterion TEXT NOT NULL,\n met INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id TEXT PRIMARY KEY,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n agent TEXT NOT NULL\n CHECK(agent IN ('lead','explorer','builder','reviewer') OR agent LIKE 'custom:%'),\n status TEXT NOT NULL DEFAULT 'in_progress'\n CHECK(status IN ('in_progress','completed','blocked')),\n created_at TEXT NOT NULL,\n completed_at TEXT,\n summary TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_sections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n section_type TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS action_files (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n file_path TEXT NOT NULL,\n operation TEXT NOT NULL\n CHECK(operation IN ('read','created','modified','deleted')),\n notes TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_tools (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n args_json TEXT,\n result_summary TEXT,\n called_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_actions_task_id ON actions(task_id);\nCREATE INDEX IF NOT EXISTS idx_actions_agent ON actions(agent);\nCREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\nCREATE INDEX IF NOT EXISTS idx_action_files_path ON action_files(file_path);\nCREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);\n`\n\nexport class SQLiteDriver implements DBDriver {\n private db: SQLiteDB\n private dbPath: string\n\n constructor(dbPath: string) {\n this.dbPath = dbPath\n mkdirSync(dirname(dbPath), { recursive: true })\n // Remove stale WAL/SHM files left by a crashed session — they cause SQLITE_IOERR.\n // A 0-byte WAL alongside a non-empty SHM means the last checkpoint never completed.\n if (existsSync(dbPath)) {\n const shm = `${dbPath}-shm`\n const wal = `${dbPath}-wal`\n if (existsSync(shm) && existsSync(wal) && statSync(wal).size === 0) {\n rmSync(shm, { force: true })\n rmSync(wal, { force: true })\n }\n }\n this.db = openSQLite(dbPath)\n this.db.exec('PRAGMA journal_mode = WAL')\n this.db.exec('PRAGMA foreign_keys = ON')\n }\n\n async ensureSchema(): Promise<void> {\n this.db.exec(SCHEMA)\n // Migration: add archived_at column (safe to run multiple times)\n try {\n this.db.exec('ALTER TABLE tasks ADD COLUMN archived_at TEXT')\n } catch {\n // Column already exists — ignore\n }\n }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n return this.db.prepare(sql).all(...params) as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n return (this.db.prepare(sql).get(...params) as unknown as T) ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n this.db.prepare(sql).run(...params)\n return lastInsertId(this.db)\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const result = this.db.prepare(sql).run(...params)\n return (result as { changes?: number }).changes ?? 0\n }\n\n async execRaw(sql: string): Promise<void> {\n this.db.exec(sql)\n }\n\n async reconnect(): Promise<void> {\n this.db.close()\n this.db = openSQLite(this.dbPath)\n this.db.exec('PRAGMA journal_mode = WAL')\n this.db.exec('PRAGMA foreign_keys = ON')\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n this.db.exec('BEGIN IMMEDIATE')\n try {\n const result = await fn(this)\n this.db.exec('COMMIT')\n return result\n } catch (err) {\n this.db.exec('ROLLBACK')\n throw err\n }\n }\n\n async close(): Promise<void> {\n this.db.close()\n }\n}\n","import { createRequire } from 'node:module'\n\nconst _require = createRequire(import.meta.url)\nconst isBun = 'bun' in process.versions\n\n// ─── Shared interface ─────────────────────────────────────────────────────────\n// Both node:sqlite (DatabaseSync) and bun:sqlite (Database) expose this surface.\n\nexport type SQLRow = Record<string, unknown>\n\nexport interface SQLStatement {\n run(...args: unknown[]): unknown\n get(...args: unknown[]): SQLRow | undefined\n all(...args: unknown[]): SQLRow[]\n}\n\nexport interface SQLiteDB {\n exec(sql: string): void\n prepare(sql: string): SQLStatement\n close(): void\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\nexport function openSQLite(path: string): SQLiteDB {\n if (isBun) {\n const { Database } = _require('bun:sqlite') as {\n Database: new (path: string) => unknown\n }\n return new Database(path) as unknown as SQLiteDB\n }\n\n const { DatabaseSync } = _require('node:sqlite') as {\n DatabaseSync: new (path: string) => unknown\n }\n return new DatabaseSync(path) as unknown as SQLiteDB\n}\n\n// ─── last_insert_rowid() helper ───────────────────────────────────────────────\n// Both bun:sqlite and node:sqlite have different return types for stmt.run().\n// Reading last_insert_rowid() directly avoids the inconsistency.\n\nexport function lastInsertId(db: SQLiteDB): number {\n const row = db.prepare('SELECT last_insert_rowid() AS id').get() as { id: number }\n return row.id\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/drivers/mysql.ts"],"sourcesContent":["import mysql, { type ExecuteValues } from 'mysql2/promise'\n\nimport type { DBDriver } from './types'\nimport type { RemoteDBConfig } from '@/types'\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS tasks (\n id INT AUTO_INCREMENT PRIMARY KEY,\n slug VARCHAR(255) NOT NULL UNIQUE,\n title VARCHAR(500) NOT NULL,\n description TEXT,\n status VARCHAR(20) NOT NULL DEFAULT 'pending'\n CHECK(status IN ('pending','in_progress','done','blocked')),\n assigned_to VARCHAR(255),\n created_at VARCHAR(30) NOT NULL,\n started_at VARCHAR(30),\n completed_at VARCHAR(30)\n);\n\nCREATE TABLE IF NOT EXISTS task_acceptance (\n id INT AUTO_INCREMENT PRIMARY KEY,\n task_id INT NOT NULL,\n criterion TEXT NOT NULL,\n met INT NOT NULL DEFAULT 0,\n FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id VARCHAR(36) PRIMARY KEY,\n task_id INT NOT NULL,\n agent VARCHAR(100) NOT NULL,\n status VARCHAR(20) NOT NULL DEFAULT 'in_progress'\n CHECK(status IN ('in_progress','completed','blocked')),\n created_at VARCHAR(30) NOT NULL,\n completed_at VARCHAR(30),\n summary TEXT,\n FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS action_sections (\n id INT AUTO_INCREMENT PRIMARY KEY,\n action_id VARCHAR(36) NOT NULL,\n section_type VARCHAR(100) NOT NULL,\n content TEXT NOT NULL,\n created_at VARCHAR(30) NOT NULL,\n FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS action_files (\n id INT AUTO_INCREMENT PRIMARY KEY,\n action_id VARCHAR(36) NOT NULL,\n file_path VARCHAR(1000) NOT NULL,\n operation VARCHAR(20) NOT NULL\n CHECK(operation IN ('read','created','modified','deleted')),\n notes TEXT,\n FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS action_tools (\n id INT AUTO_INCREMENT PRIMARY KEY,\n action_id VARCHAR(36) NOT NULL,\n tool_name VARCHAR(255) NOT NULL,\n args_json TEXT,\n result_summary TEXT,\n called_at VARCHAR(30) NOT NULL,\n FOREIGN KEY (action_id) REFERENCES actions(id) ON DELETE CASCADE\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_actions_task_id ON actions(task_id);\nCREATE INDEX IF NOT EXISTS idx_actions_agent ON actions(agent);\nCREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\nCREATE INDEX IF NOT EXISTS idx_action_files_path ON action_files(file_path(255));\nCREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);\n`\n\ntype MySQLPool = mysql.Pool\n\nexport class MySQLDriver implements DBDriver {\n private pool: MySQLPool\n\n constructor(config: RemoteDBConfig) {\n this.pool = mysql.createPool(config.connectionString)\n }\n\n async ensureSchema(): Promise<void> {\n // Run each statement individually since mysql2 doesn't support multi-statement by default\n const statements = SCHEMA.split(';')\n .map((s) => s.trim())\n .filter(Boolean)\n\n const conn = await this.pool.getConnection()\n try {\n for (const stmt of statements) {\n await conn.execute(stmt)\n }\n } finally {\n conn.release()\n }\n }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const [rows] = await this.pool.execute(sql, params as ExecuteValues)\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n const rows = await this.query<T>(sql, params)\n return (rows as T[])[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.pool.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).insertId\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.pool.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).affectedRows\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.pool.query(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n const conn = await this.pool.getConnection()\n await conn.beginTransaction()\n try {\n const txDriver = new MySQLTxDriver(conn)\n const result = await fn(txDriver)\n await conn.commit()\n return result\n } catch (err) {\n await conn.rollback()\n throw err\n } finally {\n conn.release()\n }\n }\n\n async close(): Promise<void> {\n await this.pool.end()\n }\n}\n\nclass MySQLTxDriver implements DBDriver {\n constructor(private conn: mysql.PoolConnection) { }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const [rows] = await this.conn.execute(sql, params as ExecuteValues)\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n return (await this.query<T>(sql, params))[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.conn.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).insertId\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const [result] = await this.conn.execute(sql, params as ExecuteValues)\n return (result as mysql.ResultSetHeader).affectedRows\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.conn.query(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n return fn(this)\n }\n\n async ensureSchema(): Promise<void> { }\n async close(): Promise<void> { }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/drivers/postgres.ts"],"sourcesContent":["import postgres from 'postgres'\n\nimport type { DBDriver } from './types'\nimport type { RemoteDBConfig } from '@/types'\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS tasks (\n id SERIAL PRIMARY KEY,\n slug TEXT NOT NULL UNIQUE,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT NOT NULL DEFAULT 'pending'\n CHECK(status IN ('pending','in_progress','done','blocked')),\n assigned_to TEXT,\n created_at TEXT NOT NULL,\n started_at TEXT,\n completed_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS task_acceptance (\n id SERIAL PRIMARY KEY,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n criterion TEXT NOT NULL,\n met INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id TEXT PRIMARY KEY,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n agent TEXT NOT NULL\n CHECK(agent IN ('lead','explorer','builder','reviewer') OR agent LIKE 'custom:%'),\n status TEXT NOT NULL DEFAULT 'in_progress'\n CHECK(status IN ('in_progress','completed','blocked')),\n created_at TEXT NOT NULL,\n completed_at TEXT,\n summary TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_sections (\n id SERIAL PRIMARY KEY,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n section_type TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS action_files (\n id SERIAL PRIMARY KEY,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n file_path TEXT NOT NULL,\n operation TEXT NOT NULL\n CHECK(operation IN ('read','created','modified','deleted')),\n notes TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_tools (\n id SERIAL PRIMARY KEY,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n args_json TEXT,\n result_summary TEXT,\n called_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_actions_task_id ON actions(task_id);\nCREATE INDEX IF NOT EXISTS idx_actions_agent ON actions(agent);\nCREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\nCREATE INDEX IF NOT EXISTS idx_action_files_path ON action_files(file_path);\nCREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);\n`\n\n// Convert SQLite-style ? placeholders to Postgres $1, $2, ...\nfunction toPositional(sql: string): string {\n let i = 0\n return sql.replace(/\\?/g, () => `$${++i}`)\n}\n\nexport class PostgresDriver implements DBDriver {\n private sql: postgres.Sql\n\n constructor(config: RemoteDBConfig) {\n this.sql = postgres(config.connectionString)\n }\n\n async ensureSchema(): Promise<void> {\n await this.sql.unsafe(SCHEMA)\n }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const rows = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n const rows = await this.query<T>(sql, params)\n return rows[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const withReturning = toPositional(sql.trimEnd()) + ' RETURNING id'\n const rows = await this.sql.unsafe(withReturning, params as postgres.ParameterOrJSON<never>[])\n return (rows[0] as unknown as { id: number }).id\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const result = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return result.count\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.sql.unsafe(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n let result!: T\n await this.sql.begin(async (txSql) => {\n const txDriver = new PostgresTxDriver(txSql)\n result = await fn(txDriver)\n })\n return result\n }\n\n async close(): Promise<void> {\n await this.sql.end()\n }\n}\n\nclass PostgresTxDriver implements DBDriver {\n constructor(private sql: postgres.TransactionSql) { }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n const rows = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return rows as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n return (await this.query<T>(sql, params))[0] ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n const withReturning = toPositional(sql.trimEnd()) + ' RETURNING id'\n const rows = await this.sql.unsafe(withReturning, params as postgres.ParameterOrJSON<never>[])\n return (rows[0] as unknown as { id: number }).id\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const result = await this.sql.unsafe(toPositional(sql), params as postgres.ParameterOrJSON<never>[])\n return result.count\n }\n\n async execRaw(sql: string): Promise<void> {\n await this.sql.unsafe(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n return fn(this)\n }\n\n async ensureSchema(): Promise<void> { }\n async close(): Promise<void> { }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/drivers/sqlite.ts","../src/core/sqlite-adapter.ts"],"sourcesContent":["import { existsSync, mkdirSync, rmSync, statSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\nimport { lastInsertId, openSQLite, type SQLiteDB } from '../sqlite-adapter'\n\nimport type { DBDriver } from './types'\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS tasks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n slug TEXT NOT NULL UNIQUE,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT NOT NULL DEFAULT 'pending'\n CHECK(status IN ('pending','in_progress','done','blocked')),\n assigned_to TEXT,\n created_at TEXT NOT NULL,\n started_at TEXT,\n completed_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS task_acceptance (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n criterion TEXT NOT NULL,\n met INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id TEXT PRIMARY KEY,\n task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,\n agent TEXT NOT NULL\n CHECK(agent IN ('lead','explorer','builder','reviewer') OR agent LIKE 'custom:%'),\n status TEXT NOT NULL DEFAULT 'in_progress'\n CHECK(status IN ('in_progress','completed','blocked')),\n created_at TEXT NOT NULL,\n completed_at TEXT,\n summary TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_sections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n section_type TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS action_files (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n file_path TEXT NOT NULL,\n operation TEXT NOT NULL\n CHECK(operation IN ('read','created','modified','deleted')),\n notes TEXT\n);\n\nCREATE TABLE IF NOT EXISTS action_tools (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action_id TEXT NOT NULL REFERENCES actions(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n args_json TEXT,\n result_summary TEXT,\n called_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_actions_task_id ON actions(task_id);\nCREATE INDEX IF NOT EXISTS idx_actions_agent ON actions(agent);\nCREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\nCREATE INDEX IF NOT EXISTS idx_action_files_path ON action_files(file_path);\nCREATE INDEX IF NOT EXISTS idx_action_tools_name ON action_tools(tool_name);\n`\n\nexport class SQLiteDriver implements DBDriver {\n private db: SQLiteDB\n\n constructor(dbPath: string) {\n mkdirSync(dirname(dbPath), { recursive: true })\n // Remove stale WAL/SHM files left by a crashed session — they cause SQLITE_IOERR.\n // A 0-byte WAL alongside a non-empty SHM means the last checkpoint never completed.\n if (existsSync(dbPath)) {\n const shm = `${dbPath}-shm`\n const wal = `${dbPath}-wal`\n if (existsSync(shm) && existsSync(wal) && statSync(wal).size === 0) {\n rmSync(shm, { force: true })\n rmSync(wal, { force: true })\n }\n }\n this.db = openSQLite(dbPath)\n this.db.exec('PRAGMA journal_mode = WAL')\n this.db.exec('PRAGMA foreign_keys = ON')\n }\n\n async ensureSchema(): Promise<void> {\n this.db.exec(SCHEMA)\n }\n\n async query<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n return this.db.prepare(sql).all(...params) as unknown as T[]\n }\n\n async queryOne<T>(sql: string, params: unknown[] = []): Promise<T | null> {\n return (this.db.prepare(sql).get(...params) as unknown as T) ?? null\n }\n\n async insert(sql: string, params: unknown[] = []): Promise<number> {\n this.db.prepare(sql).run(...params)\n return lastInsertId(this.db)\n }\n\n async exec(sql: string, params: unknown[] = []): Promise<number> {\n const result = this.db.prepare(sql).run(...params)\n return (result as { changes?: number }).changes ?? 0\n }\n\n async execRaw(sql: string): Promise<void> {\n this.db.exec(sql)\n }\n\n async transaction<T>(fn: (tx: DBDriver) => Promise<T>): Promise<T> {\n this.db.exec('BEGIN IMMEDIATE')\n try {\n const result = await fn(this)\n this.db.exec('COMMIT')\n return result\n } catch (err) {\n this.db.exec('ROLLBACK')\n throw err\n }\n }\n\n async close(): Promise<void> {\n this.db.close()\n }\n}\n","import { createRequire } from 'node:module'\n\nconst _require = createRequire(import.meta.url)\nconst isBun = 'bun' in process.versions\n\n// ─── Shared interface ─────────────────────────────────────────────────────────\n// Both node:sqlite (DatabaseSync) and bun:sqlite (Database) expose this surface.\n\nexport type SQLRow = Record<string, unknown>\n\nexport interface SQLStatement {\n run(...args: unknown[]): unknown\n get(...args: unknown[]): SQLRow | undefined\n all(...args: unknown[]): SQLRow[]\n}\n\nexport interface SQLiteDB {\n exec(sql: string): void\n prepare(sql: string): SQLStatement\n close(): void\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\nexport function openSQLite(path: string): SQLiteDB {\n if (isBun) {\n const { Database } = _require('bun:sqlite') as {\n Database: new (path: string) => unknown\n }\n return new Database(path) as unknown as SQLiteDB\n }\n\n const { DatabaseSync } = _require('node:sqlite') as {\n DatabaseSync: new (path: string) => unknown\n }\n return new DatabaseSync(path) as unknown as SQLiteDB\n}\n\n// ─── last_insert_rowid() helper ───────────────────────────────────────────────\n// Both bun:sqlite and node:sqlite have different return types for stmt.run().\n// Reading last_insert_rowid() directly avoids the inconsistency.\n\nexport function lastInsertId(db: SQLiteDB): number {\n const row = db.prepare('SELECT last_insert_rowid() AS id').get() as { id: number }\n return row.id\n}\n"],"mappings":"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","names":[]}
|