@next-open-ai/openbot 0.1.8 → 0.1.10

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.
@@ -11,7 +11,7 @@
11
11
  <link
12
12
  href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap"
13
13
  rel="stylesheet">
14
- <script type="module" crossorigin src="/assets/index-DL_hPION.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-J1y_YkPz.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="/assets/index-BBoPEPR6.css">
16
16
  </head>
17
17
 
@@ -1,10 +1,18 @@
1
- import { OnModuleDestroy } from '@nestjs/common';
2
- import Database from 'better-sqlite3';
3
- export declare class DatabaseService implements OnModuleDestroy {
4
- private db;
5
- getDb(): Database.Database;
1
+ import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
+ /** RunResult compatible with better-sqlite3 for callers that use .changes / .lastInsertRowid */
3
+ export interface RunResult {
4
+ changes: number;
5
+ lastInsertRowid: number;
6
+ }
7
+ export declare class DatabaseService implements OnModuleInit, OnModuleDestroy {
8
+ private sqlDb;
9
+ private dbPath;
10
+ private initPromise;
11
+ onModuleInit(): Promise<void>;
12
+ private doInit;
13
+ private getDb;
6
14
  private runMigrations;
7
- run(sql: string, params?: unknown[]): Database.RunResult;
15
+ run(sql: string, params?: unknown[]): RunResult;
8
16
  get<T>(sql: string, params?: unknown[]): T | undefined;
9
17
  all<T>(sql: string, params?: unknown[]): T[];
10
18
  onModuleDestroy(): void;
@@ -5,34 +5,61 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { Injectable } from '@nestjs/common';
8
- import Database from 'better-sqlite3';
9
- import { mkdirSync, existsSync } from 'fs';
8
+ import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'fs';
10
9
  import { join } from 'path';
11
10
  import { homedir } from 'os';
12
11
  let DatabaseService = class DatabaseService {
13
- db = null;
14
- getDb() {
15
- if (!this.db) {
16
- const pathEnv = process.env.OPENBOT_DB_PATH;
17
- const defaultDir = join(homedir(), '.openbot', 'desktop', 'data');
18
- const path = pathEnv === ':memory:' || pathEnv === ''
19
- ? ':memory:'
20
- : pathEnv ?? join(process.env.OPENBOT_DB_DIR ?? defaultDir, 'openbot.db');
21
- if (path !== ':memory:') {
22
- const dir = path.endsWith('.db') ? join(path, '..') : path;
23
- if (!existsSync(dir)) {
24
- mkdirSync(dir, { recursive: true });
25
- }
12
+ sqlDb = null;
13
+ dbPath = null;
14
+ initPromise = null;
15
+ async onModuleInit() {
16
+ if (this.initPromise)
17
+ return this.initPromise;
18
+ this.initPromise = this.doInit();
19
+ return this.initPromise;
20
+ }
21
+ async doInit() {
22
+ const pathEnv = process.env.OPENBOT_DB_PATH;
23
+ const defaultDir = join(homedir(), '.openbot', 'desktop', 'data');
24
+ const path = pathEnv === ':memory:' || pathEnv === ''
25
+ ? ':memory:'
26
+ : pathEnv ?? join(process.env.OPENBOT_DB_DIR ?? defaultDir, 'openbot.db');
27
+ if (path !== ':memory:') {
28
+ const dir = path.endsWith('.db') ? join(path, '..') : path;
29
+ if (!existsSync(dir)) {
30
+ mkdirSync(dir, { recursive: true });
31
+ }
32
+ }
33
+ const initSqlJs = (await import('sql.js')).default;
34
+ const SQL = await initSqlJs();
35
+ let db;
36
+ if (path === ':memory:') {
37
+ db = new SQL.Database();
38
+ this.dbPath = ':memory:';
39
+ }
40
+ else {
41
+ if (existsSync(path)) {
42
+ const buf = readFileSync(path);
43
+ db = new SQL.Database(new Uint8Array(buf));
26
44
  }
27
- this.db = new Database(path);
28
- this.db.pragma('journal_mode = WAL');
29
- this.runMigrations();
45
+ else {
46
+ db = new SQL.Database();
47
+ }
48
+ this.dbPath = path;
30
49
  }
31
- return this.db;
50
+ this.sqlDb = db;
51
+ db.run('PRAGMA foreign_keys = ON;');
52
+ this.runMigrations();
53
+ }
54
+ getDb() {
55
+ if (!this.sqlDb) {
56
+ throw new Error('Database not initialized. Ensure onModuleInit() has completed (Nest awaits it before listening).');
57
+ }
58
+ return this.sqlDb;
32
59
  }
33
60
  runMigrations() {
34
- const db = this.db;
35
- db.exec(`
61
+ const db = this.getDb();
62
+ const ddl = `
36
63
  CREATE TABLE IF NOT EXISTS sessions (
37
64
  id TEXT PRIMARY KEY,
38
65
  created_at INTEGER NOT NULL,
@@ -100,15 +127,18 @@ let DatabaseService = class DatabaseService {
100
127
  );
101
128
  CREATE INDEX IF NOT EXISTS idx_token_usage_session_id ON token_usage(session_id);
102
129
  CREATE INDEX IF NOT EXISTS idx_token_usage_created_at ON token_usage(created_at);
103
- `);
104
- // Add session type column if missing (scheduled vs chat)
130
+ `;
131
+ const statements = ddl.split(';').map((s) => s.trim()).filter(Boolean);
132
+ for (const stmt of statements) {
133
+ db.run(stmt + ';');
134
+ }
105
135
  try {
106
- const info = db.prepare('PRAGMA table_info(sessions)').all();
136
+ const info = this.all('PRAGMA table_info(sessions)', []);
107
137
  if (!info.some((c) => c.name === 'type')) {
108
- db.exec(`ALTER TABLE sessions ADD COLUMN type TEXT DEFAULT 'chat'`);
138
+ db.run("ALTER TABLE sessions ADD COLUMN type TEXT DEFAULT 'chat';");
109
139
  }
110
140
  if (!info.some((c) => c.name === 'agent_id')) {
111
- db.exec(`ALTER TABLE sessions ADD COLUMN agent_id TEXT DEFAULT 'default'`);
141
+ db.run("ALTER TABLE sessions ADD COLUMN agent_id TEXT DEFAULT 'default';");
112
142
  }
113
143
  }
114
144
  catch (_) {
@@ -116,19 +146,56 @@ let DatabaseService = class DatabaseService {
116
146
  }
117
147
  }
118
148
  run(sql, params = []) {
119
- return this.getDb().prepare(sql).run(...params);
149
+ const db = this.getDb();
150
+ db.run(sql, params);
151
+ const rows = db.exec('SELECT changes() AS c, last_insert_rowid() AS id');
152
+ const c = rows[0]?.values?.[0]?.[0] ?? 0;
153
+ const id = rows[0]?.values?.[0]?.[1] ?? 0;
154
+ return { changes: Number(c), lastInsertRowid: Number(id) };
120
155
  }
121
156
  get(sql, params = []) {
122
- return this.getDb().prepare(sql).get(...params);
157
+ const db = this.getDb();
158
+ const stmt = db.prepare(sql);
159
+ try {
160
+ stmt.bind(params);
161
+ const hasRow = stmt.step();
162
+ return (hasRow ? stmt.getAsObject() : undefined);
163
+ }
164
+ finally {
165
+ stmt.free();
166
+ }
123
167
  }
124
168
  all(sql, params = []) {
125
- return this.getDb().prepare(sql).all(...params);
169
+ const db = this.getDb();
170
+ const stmt = db.prepare(sql);
171
+ try {
172
+ stmt.bind(params);
173
+ const rows = [];
174
+ while (stmt.step()) {
175
+ rows.push(stmt.getAsObject());
176
+ }
177
+ return rows;
178
+ }
179
+ finally {
180
+ stmt.free();
181
+ }
126
182
  }
127
183
  onModuleDestroy() {
128
- if (this.db) {
129
- this.db.close();
130
- this.db = null;
184
+ if (!this.sqlDb)
185
+ return;
186
+ if (this.dbPath && this.dbPath !== ':memory:') {
187
+ try {
188
+ const data = this.sqlDb.export();
189
+ writeFileSync(this.dbPath, Buffer.from(data));
190
+ }
191
+ catch (e) {
192
+ console.error('[DatabaseService] Failed to persist database:', e);
193
+ }
131
194
  }
195
+ this.sqlDb.close();
196
+ this.sqlDb = null;
197
+ this.dbPath = null;
198
+ this.initPromise = null;
132
199
  }
133
200
  };
134
201
  DatabaseService = __decorate([
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.8",
6
+ "version": "0.1.10",
7
7
  "description": "CLI and library to run prompts with skill paths (Agent Skills style). Use as npm package or openbot CLI.",
8
8
  "type": "module",
9
9
  "main": "dist/index.js",
@@ -24,10 +24,8 @@
24
24
  "bin": {
25
25
  "openbot": "./dist/cli.js"
26
26
  },
27
- "dependencies": {
28
- "better-sqlite3": "^11.6.0",
29
- "croner": "^9.1.0",
30
- "@mariozechner/pi-ai": "^0.51.2",
27
+ "dependencies": {
28
+ "@mariozechner/pi-ai": "^0.51.2",
31
29
  "@mariozechner/pi-coding-agent": "^0.51.2",
32
30
  "@nestjs/common": "^10.3.0",
33
31
  "@nestjs/core": "^10.3.0",
@@ -37,18 +35,20 @@
37
35
  "@sinclair/typebox": "^0.34.41",
38
36
  "agent-browser": "^0.8.5",
39
37
  "commander": "^14.0.2",
38
+ "croner": "^9.1.0",
40
39
  "reflect-metadata": "^0.2.1",
41
40
  "rxjs": "^7.8.1",
41
+ "sql.js": "^1.13.0",
42
42
  "vectra": "^0.12.3",
43
43
  "ws": "^8.19.0"
44
44
  },
45
- "devDependencies": {
46
- "@types/better-sqlite3": "^7.6.11",
47
- "@types/express": "^4.17.21",
48
- "@types/node": "^22.0.0",
45
+ "devDependencies": {
46
+ "@nestjs/testing": "^10.3.0",
47
+ "@types/express": "^4.17.21",
49
48
  "@types/jest": "^29.5.14",
49
+ "@types/node": "^22.0.0",
50
+ "@types/sql.js": "^1.4.9",
50
51
  "@types/ws": "^8.18.1",
51
- "@nestjs/testing": "^10.3.0",
52
52
  "jest": "^29.7.0",
53
53
  "ts-jest": "^29.2.5",
54
54
  "typescript": "^5.7.0"