@next-open-ai/openbot 0.1.8 → 0.2.1

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.
Files changed (81) hide show
  1. package/README.md +6 -6
  2. package/{desktop → apps/desktop}/README.md +3 -3
  3. package/{desktop/renderer/dist/assets/index-DL_hPION.js → apps/desktop/renderer/dist/assets/index-BOS-F8a4.js} +37 -37
  4. package/{desktop/renderer/dist/assets/index-BBoPEPR6.css → apps/desktop/renderer/dist/assets/index-DxqxayUL.css} +2 -2
  5. package/{desktop → apps/desktop}/renderer/dist/index.html +2 -2
  6. package/dist/cli/cli.d.ts +2 -0
  7. package/dist/cli/cli.js +172 -0
  8. package/dist/cli.d.ts +4 -1
  9. package/dist/cli.js +4 -172
  10. package/dist/gateway/auth-hooks.d.ts +17 -0
  11. package/dist/gateway/auth-hooks.js +19 -0
  12. package/dist/gateway/channel-handler.d.ts +6 -0
  13. package/dist/gateway/channel-handler.js +3 -0
  14. package/dist/gateway/index.d.ts +1 -1
  15. package/dist/gateway/index.js +1 -1
  16. package/dist/gateway/methods/agent-cancel.js +1 -1
  17. package/dist/gateway/methods/agent-chat.js +3 -3
  18. package/dist/gateway/methods/install-skill-from-path.js +1 -1
  19. package/dist/gateway/methods/run-scheduled-task.js +3 -3
  20. package/dist/gateway/paths.d.ts +20 -0
  21. package/dist/gateway/paths.js +19 -0
  22. package/dist/gateway/server.d.ts +2 -4
  23. package/dist/gateway/server.js +98 -208
  24. package/dist/gateway/sse-handler.d.ts +6 -0
  25. package/dist/gateway/sse-handler.js +3 -0
  26. package/dist/gateway/voice-handler.d.ts +12 -0
  27. package/dist/gateway/voice-handler.js +18 -0
  28. package/dist/index.d.ts +5 -5
  29. package/dist/index.js +5 -5
  30. package/dist/server/agents/agents.service.js +1 -1
  31. package/dist/server/bootstrap.d.ts +15 -0
  32. package/dist/server/bootstrap.js +38 -0
  33. package/dist/server/config/config.service.d.ts +1 -1
  34. package/dist/server/config/config.service.js +1 -1
  35. package/dist/server/database/database.service.d.ts +14 -6
  36. package/dist/server/database/database.service.js +99 -32
  37. package/dist/server/main.js +6 -19
  38. package/dist/server/skills/skills.service.js +1 -1
  39. package/dist/server/workspace/workspace.service.js +1 -1
  40. package/package.json +23 -20
  41. package/desktop/renderer/dist/assets/logo-RfPiqt5-.png +0 -0
  42. /package/dist/{agent → core/agent}/agent-dir.d.ts +0 -0
  43. /package/dist/{agent → core/agent}/agent-dir.js +0 -0
  44. /package/dist/{agent → core/agent}/agent-manager.d.ts +0 -0
  45. /package/dist/{agent → core/agent}/agent-manager.js +0 -0
  46. /package/dist/{agent → core/agent}/config-manager.d.ts +0 -0
  47. /package/dist/{agent → core/agent}/config-manager.js +0 -0
  48. /package/dist/{agent → core/agent}/run.d.ts +0 -0
  49. /package/dist/{agent → core/agent}/run.js +0 -0
  50. /package/dist/{agent → core/agent}/skills.d.ts +0 -0
  51. /package/dist/{agent → core/agent}/skills.js +0 -0
  52. /package/dist/{config → core/config}/desktop-config.d.ts +0 -0
  53. /package/dist/{config → core/config}/desktop-config.js +0 -0
  54. /package/dist/{config → core/config}/provider-support-default.d.ts +0 -0
  55. /package/dist/{config → core/config}/provider-support-default.js +0 -0
  56. /package/dist/{installer → core/installer}/index.d.ts +0 -0
  57. /package/dist/{installer → core/installer}/index.js +0 -0
  58. /package/dist/{installer → core/installer}/skill-installer.d.ts +0 -0
  59. /package/dist/{installer → core/installer}/skill-installer.js +0 -0
  60. /package/dist/{memory → core/memory}/build-summary.d.ts +0 -0
  61. /package/dist/{memory → core/memory}/build-summary.js +0 -0
  62. /package/dist/{memory → core/memory}/compaction-extension.d.ts +0 -0
  63. /package/dist/{memory → core/memory}/compaction-extension.js +0 -0
  64. /package/dist/{memory → core/memory}/embedding.d.ts +0 -0
  65. /package/dist/{memory → core/memory}/embedding.js +0 -0
  66. /package/dist/{memory → core/memory}/index.d.ts +0 -0
  67. /package/dist/{memory → core/memory}/index.js +0 -0
  68. /package/dist/{memory → core/memory}/remote-embedding.d.ts +0 -0
  69. /package/dist/{memory → core/memory}/remote-embedding.js +0 -0
  70. /package/dist/{memory → core/memory}/types.d.ts +0 -0
  71. /package/dist/{memory → core/memory}/types.js +0 -0
  72. /package/dist/{memory → core/memory}/vector-store.d.ts +0 -0
  73. /package/dist/{memory → core/memory}/vector-store.js +0 -0
  74. /package/dist/{tools → core/tools}/browser-tool.d.ts +0 -0
  75. /package/dist/{tools → core/tools}/browser-tool.js +0 -0
  76. /package/dist/{tools → core/tools}/index.d.ts +0 -0
  77. /package/dist/{tools → core/tools}/index.js +0 -0
  78. /package/dist/{tools → core/tools}/install-skill-tool.d.ts +0 -0
  79. /package/dist/{tools → core/tools}/install-skill-tool.js +0 -0
  80. /package/dist/{tools → core/tools}/save-experience-tool.d.ts +0 -0
  81. /package/dist/{tools → core/tools}/save-experience-tool.js +0 -0
@@ -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([
@@ -1,22 +1,9 @@
1
1
  /**
2
- * OpenBot Desktop 后端入口(NestJS HTTP API,前缀 server-api)。
3
- * WebSocket Gateway(src/gateway/)是不同进程;Gateway 可拉本进程并代理 /server-api。
2
+ * OpenBot Desktop 后端入口(独立模式)。
3
+ * 内嵌到 Gateway 时由 gateway/server 调用 createNestAppEmbedded,不经过本文件。
4
4
  */
5
- import { NestFactory } from '@nestjs/core';
6
- import { AppModule } from './app.module.js';
7
- async function bootstrap() {
8
- const app = await NestFactory.create(AppModule, {
9
- cors: true,
10
- });
11
- // Set global prefix
12
- app.setGlobalPrefix('server-api');
13
- // Enable CORS for frontend
14
- app.enableCors({
15
- origin: ['http://localhost:5173', 'http://localhost:38081'],
16
- credentials: true,
17
- });
18
- const port = process.env.PORT || 38081;
19
- await app.listen(port);
5
+ import { createNestAppStandalone } from './bootstrap.js';
6
+ const port = Number(process.env.PORT) || 38081;
7
+ createNestAppStandalone(port).then(() => {
20
8
  console.log(`🚀 OpenBot Desktop Server running on http://localhost:${port}`);
21
- }
22
- bootstrap();
9
+ });
@@ -16,7 +16,7 @@ import { tmpdir } from 'os';
16
16
  import { randomUUID } from 'crypto';
17
17
  import { exec } from 'child_process';
18
18
  import { promisify } from 'util';
19
- import { getOpenbotAgentDir, getOpenbotWorkspaceDir } from '../../agent/agent-dir.js';
19
+ import { getOpenbotAgentDir, getOpenbotWorkspaceDir } from '../../core/agent/agent-dir.js';
20
20
  const execAsync = promisify(exec);
21
21
  /** 工作区技能名仅允许英文、数字、下划线、连字符 */
22
22
  const SKILL_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
@@ -8,7 +8,7 @@ import { Injectable } from '@nestjs/common';
8
8
  import { readdir, stat, rm } from 'fs/promises';
9
9
  import { join, resolve, relative } from 'path';
10
10
  import { existsSync } from 'fs';
11
- import { getOpenbotWorkspaceDir } from '../../agent/agent-dir.js';
11
+ import { getOpenbotWorkspaceDir } from '../../core/agent/agent-dir.js';
12
12
  let WorkspaceService = class WorkspaceService {
13
13
  getWorkspaceRoot(name) {
14
14
  return join(getOpenbotWorkspaceDir(), name);
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.2.1",
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",
@@ -19,15 +19,13 @@
19
19
  "dist",
20
20
  "skills",
21
21
  "README.md",
22
- "desktop/renderer/dist"
22
+ "apps/desktop/renderer/dist"
23
23
  ],
24
24
  "bin": {
25
- "openbot": "./dist/cli.js"
25
+ "openbot": "./dist/cli/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"
@@ -56,16 +56,19 @@
56
56
  "scripts": {
57
57
  "clean": "rm -rf dist",
58
58
  "build": "npm run clean && tsc",
59
- "prepublishOnly": "npm run build && cd desktop && npm run build:renderer",
60
- "start": "node dist/cli.js",
61
- "run": "node dist/cli.js",
62
- "dev": "npm run build && node dist/cli.js",
63
- "desktop:dev": "cd desktop && npm run dev",
64
- "desktop:build": "cd desktop && npm run build",
65
- "desktop:install": "cd desktop && npm install",
59
+ "build:web": "cd apps/desktop && npm run build:renderer",
60
+ "build:all": "npm run build && npm run build:web",
61
+ "prepublishOnly": "npm run build && cd apps/desktop && npm run build:renderer",
62
+ "start": "node dist/cli/cli.js",
63
+ "run": "node dist/cli/cli.js",
64
+ "dev": "npm run build && node dist/cli/cli.js",
65
+ "desktop:dev": "cd apps/desktop && npm run dev",
66
+ "desktop:build": "cd apps/desktop && npm run build",
67
+ "desktop:install": "cd apps/desktop && npm install",
66
68
  "test": "jest --config test/jest.config.cjs",
67
69
  "test:memory": "node test/run-memory.mjs",
68
- "test:e2e": "OPENBOT_DB_PATH=:memory: jest --config test/jest.config.cjs --testPathPattern=e2e"
70
+ "test:e2e": "OPENBOT_DB_PATH=:memory: jest --config test/jest.config.cjs --testPathPattern=e2e",
71
+ "test:gateway-e2e": "npm run build && node test/gateway/server.e2e.mjs"
69
72
  },
70
73
  "engines": {
71
74
  "node": ">=20.0.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes