@vibe-forge/tsconfigs 0.8.0 → 0.10.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.
Files changed (71) hide show
  1. package/dist/apps/cli/__tests__/clear.spec.d.ts +1 -0
  2. package/dist/apps/cli/__tests__/clear.spec.js +72 -0
  3. package/dist/apps/cli/src/commands/clear.d.ts +4 -0
  4. package/dist/apps/cli/src/commands/clear.js +62 -39
  5. package/dist/apps/client/src/main.d.ts +1 -0
  6. package/dist/apps/client/src/main.js +1 -0
  7. package/dist/apps/server/__tests__/db/connection.spec.d.ts +1 -0
  8. package/dist/apps/server/__tests__/db/connection.spec.js +58 -0
  9. package/dist/apps/server/__tests__/db/index.spec.js +129 -5
  10. package/dist/apps/server/__tests__/db/schema.spec.js +3 -6
  11. package/dist/apps/server/__tests__/db/sqlite.spec.d.ts +1 -0
  12. package/dist/apps/server/__tests__/db/sqlite.spec.js +51 -0
  13. package/dist/apps/server/__tests__/services/session-start.spec.js +3 -3
  14. package/dist/apps/server/src/db/automation/repo.d.ts +2 -2
  15. package/dist/apps/server/src/db/channelSessions/repo.d.ts +2 -2
  16. package/dist/apps/server/src/db/connection.d.ts +2 -2
  17. package/dist/apps/server/src/db/connection.js +2 -2
  18. package/dist/apps/server/src/db/index.d.ts +2 -2
  19. package/dist/apps/server/src/db/schema.d.ts +3 -3
  20. package/dist/apps/server/src/db/sessions/messages.repo.d.ts +2 -2
  21. package/dist/apps/server/src/db/sessions/repo.d.ts +2 -2
  22. package/dist/apps/server/src/db/sessions/repo.js +1 -1
  23. package/dist/apps/server/src/db/sessions/tags.repo.d.ts +2 -2
  24. package/dist/apps/server/src/db/sqlite.d.ts +44 -0
  25. package/dist/apps/server/src/db/sqlite.js +83 -0
  26. package/dist/apps/server/src/index.js +1 -1
  27. package/dist/apps/server/src/routes/config.js +1 -1
  28. package/dist/apps/server/src/services/config/index.d.ts +2 -8
  29. package/dist/apps/server/src/services/config/index.js +3 -39
  30. package/dist/apps/server/src/services/session/index.js +1 -1
  31. package/dist/apps/server/src/services/session/notification.js +1 -1
  32. package/dist/packages/adapters/claude-code/__tests__/default-config.spec.js +15 -0
  33. package/dist/packages/adapters/claude-code/__tests__/prepare.spec.js +61 -1
  34. package/dist/packages/adapters/claude-code/__tests__/router-daemon.spec.d.ts +1 -0
  35. package/dist/packages/adapters/claude-code/__tests__/router-daemon.spec.js +183 -0
  36. package/dist/packages/adapters/claude-code/src/adapter-config.d.ts +1 -0
  37. package/dist/packages/adapters/claude-code/src/runtime/init.js +0 -45
  38. package/dist/packages/adapters/claude-code/src/runtime/prepare.d.ts +6 -9
  39. package/dist/packages/adapters/claude-code/src/runtime/prepare.js +25 -27
  40. package/dist/packages/adapters/claude-code/src/runtime/router-daemon.d.ts +19 -0
  41. package/dist/packages/adapters/claude-code/src/runtime/router-daemon.js +189 -0
  42. package/dist/packages/channels/lark/src/index.d.ts +4 -4
  43. package/dist/packages/config/__tests__/load.spec.js +219 -2
  44. package/dist/packages/config/__tests__/merge.spec.d.ts +1 -0
  45. package/dist/packages/config/__tests__/merge.spec.js +92 -0
  46. package/dist/packages/config/src/index.d.ts +1 -0
  47. package/dist/packages/config/src/index.js +1 -0
  48. package/dist/packages/config/src/load.d.ts +1 -1
  49. package/dist/packages/config/src/load.js +167 -53
  50. package/dist/packages/config/src/merge.d.ts +7 -0
  51. package/dist/packages/config/src/merge.js +92 -0
  52. package/dist/packages/tsconfigs/tsconfig.bundler.test.tsbuildinfo +1 -1
  53. package/dist/packages/tsconfigs/tsconfig.bundler.tsbuildinfo +1 -1
  54. package/dist/packages/tsconfigs/tsconfig.bundler.web.test.tsbuildinfo +1 -1
  55. package/dist/packages/tsconfigs/tsconfig.bundler.web.tsbuildinfo +1 -1
  56. package/dist/packages/tsconfigs/tsconfig.node.test.tsbuildinfo +1 -1
  57. package/dist/packages/tsconfigs/tsconfig.node.tsbuildinfo +1 -1
  58. package/dist/packages/types/src/config.d.ts +1 -0
  59. package/dist/packages/workspace-assets/__tests__/adapter-asset-plan.spec.d.ts +1 -0
  60. package/dist/packages/workspace-assets/__tests__/adapter-asset-plan.spec.js +121 -0
  61. package/dist/packages/workspace-assets/__tests__/bundle.spec.d.ts +1 -0
  62. package/dist/packages/workspace-assets/__tests__/bundle.spec.js +61 -0
  63. package/dist/packages/workspace-assets/__tests__/prompt-selection.spec.d.ts +1 -0
  64. package/dist/packages/workspace-assets/__tests__/prompt-selection.spec.js +29 -0
  65. package/dist/packages/workspace-assets/__tests__/snapshot.d.ts +15 -0
  66. package/dist/packages/workspace-assets/__tests__/snapshot.js +203 -0
  67. package/dist/packages/workspace-assets/__tests__/test-helpers.d.ts +2 -0
  68. package/dist/packages/workspace-assets/__tests__/test-helpers.js +17 -0
  69. package/dist/packages/workspace-assets/__tests__/workspace-assets.snapshot.spec.d.ts +1 -0
  70. package/dist/packages/workspace-assets/__tests__/workspace-assets.snapshot.spec.js +172 -0
  71. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const promises_1 = require("node:fs/promises");
7
+ const promises_2 = __importDefault(require("node:fs/promises"));
8
+ const node_os_1 = require("node:os");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const vitest_1 = require("vitest");
11
+ const clear_js_1 = require("#~/commands/clear.js");
12
+ const tempDirs = [];
13
+ const createTempDir = async () => {
14
+ const cwd = await promises_2.default.mkdtemp(node_path_1.default.join((0, node_os_1.tmpdir)(), 'vf-clear-'));
15
+ tempDirs.push(cwd);
16
+ return cwd;
17
+ };
18
+ const exists = async (target) => {
19
+ try {
20
+ await (0, promises_1.access)(target);
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ };
27
+ (0, vitest_1.afterEach)(async () => {
28
+ vitest_1.vi.restoreAllMocks();
29
+ await Promise.all(tempDirs.splice(0).map(dir => promises_2.default.rm(dir, { force: true, recursive: true })));
30
+ });
31
+ (0, vitest_1.describe)('clear command', () => {
32
+ (0, vitest_1.it)('clears logs and preserves claude-code-router config assets', async () => {
33
+ const cwd = await createTempDir();
34
+ const logSpy = vitest_1.vi.spyOn(console, 'log').mockImplementation(() => { });
35
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.logs/sub'), { recursive: true });
36
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/logs'), { recursive: true });
37
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/caches'), { recursive: true });
38
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/benchmarks/specs/demo/logs'), { recursive: true });
39
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/.mock/.claude/debug'), { recursive: true });
40
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/logs'), { recursive: true });
41
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/20260330-0000-01-./logs'), {
42
+ recursive: true
43
+ });
44
+ await promises_2.default.mkdir(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/plugins'), { recursive: true });
45
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.logs/sub/task.log'), 'old log');
46
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/logs/session.log'), 'session log');
47
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/caches/cache.json'), '{"ok":true}');
48
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/benchmarks/specs/demo/logs/run.log'), 'benchmark');
49
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude/debug/debug.log'), 'debug');
50
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/logs/ccr-1.log'), 'router log');
51
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/claude-code-router.log'), 'root log');
52
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/.claude-code-router.pid'), '100');
53
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/config.json'), '{"router":true}');
54
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/plugins/plugin.js'), 'export {}');
55
+ await promises_2.default.writeFile(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/20260330-0000-01-./logs/session.log'), 'dated log');
56
+ await (0, clear_js_1.runClearCommand)({ cwd });
57
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.logs'))).toBe(false);
58
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/logs/session.log'))).toBe(false);
59
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/caches/cache.json'))).toBe(false);
60
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/benchmarks/specs/demo/logs'))).toBe(false);
61
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude/debug'))).toBe(false);
62
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/logs'))).toBe(false);
63
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/claude-code-router.log'))).toBe(false);
64
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/20260330-0000-01-.'))).toBe(false);
65
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/logs/.gitkeep'))).toBe(true);
66
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/caches/.gitkeep'))).toBe(true);
67
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/.claude-code-router.pid'))).toBe(true);
68
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/config.json'))).toBe(true);
69
+ (0, vitest_1.expect)(await exists(node_path_1.default.join(cwd, '.ai/.mock/.claude-code-router/plugins/plugin.js'))).toBe(true);
70
+ (0, vitest_1.expect)(logSpy).toHaveBeenCalledWith('Clear logs and cache successfully');
71
+ });
72
+ });
@@ -1,2 +1,6 @@
1
1
  import type { Command } from 'commander';
2
+ export interface RunClearCommandOptions {
3
+ cwd?: string;
4
+ }
5
+ export declare function runClearCommand(options?: RunClearCommandOptions): Promise<void>;
2
6
  export declare function registerClearCommand(program: Command): void;
@@ -3,52 +3,75 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runClearCommand = runClearCommand;
6
7
  exports.registerClearCommand = registerClearCommand;
7
8
  const promises_1 = __importDefault(require("node:fs/promises"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const node_process_1 = __importDefault(require("node:process"));
8
11
  const fast_glob_1 = __importDefault(require("fast-glob"));
12
+ const CLEAR_TARGETS = [
13
+ '.logs',
14
+ '.ai/logs',
15
+ '.ai/caches',
16
+ '.ai/.mock/.claude/debug',
17
+ '.ai/.mock/.claude/todos',
18
+ '.ai/.mock/.claude/session-env',
19
+ '.ai/.mock/.claude/projects',
20
+ '.ai/.mock/.claude-core-router/logs',
21
+ '.ai/.mock/.claude-code-router/logs'
22
+ ];
23
+ const BENCHMARK_LOG_PATTERNS = [
24
+ '.ai/benchmarks/specs/**/logs',
25
+ '.ai/benchmarks/entities/**/logs',
26
+ '.ai/benchmarks/cases/**/logs'
27
+ ];
28
+ const CLAUDE_CODE_ROUTER_LOG_FILE_PATTERNS = [
29
+ '.ai/.mock/.claude-code-router/*.log',
30
+ '.ai/.mock/.claude-code-router/*.log.*'
31
+ ];
32
+ const CLAUDE_CODE_ROUTER_SESSION_LOG_PATTERN = '.ai/.mock/.claude-code-router/*/logs';
33
+ async function collectClearTargets(cwd) {
34
+ const benchmarkLogDirs = await (0, fast_glob_1.default)(BENCHMARK_LOG_PATTERNS, {
35
+ cwd,
36
+ onlyDirectories: true,
37
+ deep: 10
38
+ });
39
+ const claudeCodeRouterSessionLogDirs = await (0, fast_glob_1.default)(CLAUDE_CODE_ROUTER_SESSION_LOG_PATTERN, {
40
+ cwd,
41
+ onlyDirectories: true,
42
+ deep: 2
43
+ });
44
+ const claudeCodeRouterLogFiles = await (0, fast_glob_1.default)(CLAUDE_CODE_ROUTER_LOG_FILE_PATTERNS, {
45
+ cwd,
46
+ onlyFiles: true,
47
+ deep: 1
48
+ });
49
+ return [
50
+ ...CLEAR_TARGETS,
51
+ ...benchmarkLogDirs.filter(dir => dir !== '.ai/logs' && !dir.startsWith('.ai/logs/')),
52
+ ...claudeCodeRouterSessionLogDirs.map(dir => node_path_1.default.dirname(dir)),
53
+ ...claudeCodeRouterLogFiles
54
+ ];
55
+ }
56
+ async function runClearCommand(options = {}) {
57
+ const cwd = options.cwd ?? node_process_1.default.cwd();
58
+ const targets = Array.from(new Set(await collectClearTargets(cwd)));
59
+ await Promise.all(targets.map(target => promises_1.default.rm(node_path_1.default.resolve(cwd, target), { force: true, recursive: true })));
60
+ await Promise.all([
61
+ promises_1.default.mkdir(node_path_1.default.resolve(cwd, '.ai/logs'), { recursive: true }),
62
+ promises_1.default.mkdir(node_path_1.default.resolve(cwd, '.ai/caches'), { recursive: true })
63
+ ]);
64
+ await Promise.all([
65
+ promises_1.default.writeFile(node_path_1.default.resolve(cwd, '.ai/logs/.gitkeep'), ''),
66
+ promises_1.default.writeFile(node_path_1.default.resolve(cwd, '.ai/caches/.gitkeep'), '')
67
+ ]);
68
+ console.log('Clear logs and cache successfully');
69
+ }
9
70
  function registerClearCommand(program) {
10
71
  program
11
72
  .command('clear')
12
73
  .description('Clear logs and cache of sub-agents')
13
74
  .action(async () => {
14
- // Clean main logs and caches
15
- await Promise.all([
16
- promises_1.default.rm('.logs', { force: true, recursive: true }),
17
- promises_1.default.rm('.ai/logs', { force: true, recursive: true }),
18
- promises_1.default.rm('.ai/caches', { force: true, recursive: true }),
19
- promises_1.default.rm('.ai/.mock/.claude/debug', { force: true, recursive: true }),
20
- promises_1.default.rm('.ai/.mock/.claude/todos', { force: true, recursive: true }),
21
- promises_1.default.rm('.ai/.mock/.claude/session-env', { force: true, recursive: true }),
22
- promises_1.default.rm('.ai/.mock/.claude/projects', { force: true, recursive: true }),
23
- promises_1.default.rm('.ai/.mock/.claude-core-router/logs', {
24
- force: true,
25
- recursive: true
26
- })
27
- ]);
28
- // Clean all logs directories using fast-glob patterns
29
- const logsPatterns = [
30
- '.ai/benchmarks/specs/**/logs',
31
- '.ai/benchmarks/entities/**/logs',
32
- '.ai/benchmarks/cases/**/logs'
33
- ];
34
- // Find all logs directories
35
- const logsDirs = await (0, fast_glob_1.default)(logsPatterns, {
36
- onlyDirectories: true,
37
- deep: 10
38
- });
39
- // Remove all found logs directories (exclude main .ai/logs which we handle separately)
40
- const logsDirsToRemove = logsDirs.filter((dir) => dir !== '.ai/logs' && !dir.startsWith('.ai/logs/'));
41
- await Promise.all(logsDirsToRemove.map((logsDir) => promises_1.default.rm(logsDir, { force: true, recursive: true })));
42
- // Recreate main directories
43
- await Promise.all([
44
- promises_1.default.mkdir('.ai/logs', { recursive: true }),
45
- promises_1.default.mkdir('.ai/caches', { recursive: true })
46
- ]);
47
- // create .gitkeep files
48
- await Promise.all([
49
- promises_1.default.writeFile('.ai/logs/.gitkeep', ''),
50
- promises_1.default.writeFile('.ai/caches/.gitkeep', '')
51
- ]);
52
- console.log('Clear logs and cache successfully');
75
+ await runClearCommand();
53
76
  });
54
77
  }
@@ -1,3 +1,4 @@
1
1
  import 'devicon/devicon.min.css';
2
+ import './styles/material-symbols-rounded.scss';
2
3
  import './styles/global.scss';
3
4
  import './i18n';
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import 'devicon/devicon.min.css';
3
+ import './styles/material-symbols-rounded.scss';
3
4
  import './styles/global.scss';
4
5
  import './i18n';
5
6
  import { App as AntdApp, ConfigProvider } from 'antd';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_fs_1 = __importDefault(require("node:fs"));
7
+ const node_os_1 = __importDefault(require("node:os"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const vitest_1 = require("vitest");
10
+ const connection_1 = require("../../src/db/connection");
11
+ (0, vitest_1.describe)('createConnection', () => {
12
+ (0, vitest_1.afterEach)(() => {
13
+ vitest_1.vi.restoreAllMocks();
14
+ delete process.env.DB_PATH;
15
+ });
16
+ (0, vitest_1.it)('uses ~/.vf/db.sqlite when DB_PATH is not configured', () => {
17
+ const tempHome = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'vf-home-'));
18
+ vitest_1.vi.spyOn(node_os_1.default, 'homedir').mockReturnValue(tempHome);
19
+ const connection = (0, connection_1.createConnection)();
20
+ try {
21
+ (0, vitest_1.expect)(connection.dbPath).toBe(node_path_1.default.join(tempHome, '.vf', 'db.sqlite'));
22
+ (0, vitest_1.expect)(node_fs_1.default.existsSync(node_path_1.default.join(tempHome, '.vf'))).toBe(true);
23
+ (0, vitest_1.expect)(node_fs_1.default.existsSync(connection.dbPath)).toBe(true);
24
+ }
25
+ finally {
26
+ connection.db.close();
27
+ node_fs_1.default.rmSync(tempHome, { force: true, recursive: true });
28
+ }
29
+ });
30
+ (0, vitest_1.it)('creates missing parent directories for a custom file path', () => {
31
+ const tempDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'vf-db-path-'));
32
+ const dbPath = node_path_1.default.join(tempDir, 'nested', 'custom.sqlite');
33
+ process.env.DB_PATH = dbPath;
34
+ const connection = (0, connection_1.createConnection)();
35
+ try {
36
+ (0, vitest_1.expect)(connection.dbPath).toBe(dbPath);
37
+ (0, vitest_1.expect)(node_fs_1.default.existsSync(node_path_1.default.dirname(dbPath))).toBe(true);
38
+ (0, vitest_1.expect)(node_fs_1.default.existsSync(dbPath)).toBe(true);
39
+ }
40
+ finally {
41
+ connection.db.close();
42
+ node_fs_1.default.rmSync(tempDir, { force: true, recursive: true });
43
+ }
44
+ });
45
+ (0, vitest_1.it)('appends db.sqlite when DB_PATH points to a directory', () => {
46
+ const tempDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'vf-db-dir-'));
47
+ process.env.DB_PATH = tempDir;
48
+ const connection = (0, connection_1.createConnection)();
49
+ try {
50
+ (0, vitest_1.expect)(connection.dbPath).toBe(node_path_1.default.join(tempDir, 'db.sqlite'));
51
+ (0, vitest_1.expect)(node_fs_1.default.existsSync(connection.dbPath)).toBe(true);
52
+ }
53
+ finally {
54
+ connection.db.close();
55
+ node_fs_1.default.rmSync(tempDir, { force: true, recursive: true });
56
+ }
57
+ });
58
+ });
@@ -1,18 +1,15 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
7
3
  const vitest_1 = require("vitest");
8
4
  const index_js_1 = require("#~/db/index.js");
5
+ const sqlite_js_1 = require("#~/db/sqlite.js");
9
6
  (0, vitest_1.describe)('sqliteDb', () => {
10
7
  let sqlite;
11
8
  let db;
12
9
  (0, vitest_1.beforeEach)(() => {
13
10
  vitest_1.vi.useFakeTimers();
14
11
  vitest_1.vi.setSystemTime(new Date('2026-03-18T00:00:00.000Z'));
15
- sqlite = new better_sqlite3_1.default(':memory:');
12
+ sqlite = (0, sqlite_js_1.createSqliteDatabase)(':memory:');
16
13
  db = new index_js_1.SqliteDb({ db: sqlite });
17
14
  });
18
15
  (0, vitest_1.afterEach)(() => {
@@ -154,4 +151,131 @@ const index_js_1 = require("#~/db/index.js");
154
151
  lastSessionId: 'session-root'
155
152
  });
156
153
  });
154
+ (0, vitest_1.it)('replaces automation triggers and tasks atomically and exposes rule details with runs', () => {
155
+ db.createAutomationRule({
156
+ id: 'rule-1',
157
+ name: 'Nightly run',
158
+ description: null,
159
+ type: 'cron',
160
+ intervalMs: null,
161
+ webhookKey: null,
162
+ cronExpression: '0 0 * * *',
163
+ prompt: 'do work',
164
+ enabled: true,
165
+ createdAt: Date.now(),
166
+ lastRunAt: null,
167
+ lastSessionId: null
168
+ });
169
+ db.replaceAutomationTriggers('rule-1', [
170
+ {
171
+ id: 'trigger-1',
172
+ type: 'cron',
173
+ cronExpression: '0 0 * * *'
174
+ }
175
+ ]);
176
+ db.replaceAutomationTasks('rule-1', [
177
+ {
178
+ id: 'task-1',
179
+ title: 'Task A',
180
+ prompt: 'Summarize activity'
181
+ }
182
+ ]);
183
+ db.createSession('Automation run', 'session-run', 'completed');
184
+ db.updateSessionLastMessages('session-run', 'assistant summary', 'user request');
185
+ db.createAutomationRun('rule-1', 'session-run', 'task-1', 'Task A');
186
+ (0, vitest_1.expect)(db.getAutomationRuleDetail('rule-1')).toEqual({
187
+ id: 'rule-1',
188
+ name: 'Nightly run',
189
+ description: null,
190
+ type: 'cron',
191
+ intervalMs: null,
192
+ webhookKey: null,
193
+ cronExpression: '0 0 * * *',
194
+ prompt: 'do work',
195
+ enabled: true,
196
+ createdAt: Date.now(),
197
+ lastRunAt: null,
198
+ lastSessionId: null,
199
+ triggers: [
200
+ {
201
+ id: 'trigger-1',
202
+ ruleId: 'rule-1',
203
+ type: 'cron',
204
+ intervalMs: null,
205
+ cronExpression: '0 0 * * *',
206
+ webhookKey: null,
207
+ createdAt: Date.now()
208
+ }
209
+ ],
210
+ tasks: [
211
+ {
212
+ id: 'task-1',
213
+ ruleId: 'rule-1',
214
+ title: 'Task A',
215
+ prompt: 'Summarize activity',
216
+ createdAt: Date.now()
217
+ }
218
+ ]
219
+ });
220
+ (0, vitest_1.expect)(db.listAutomationRuns('rule-1')).toEqual([
221
+ {
222
+ id: vitest_1.expect.any(String),
223
+ ruleId: 'rule-1',
224
+ sessionId: 'session-run',
225
+ runAt: Date.now(),
226
+ taskId: 'task-1',
227
+ taskTitle: 'Task A',
228
+ status: 'completed',
229
+ title: 'Automation run',
230
+ lastMessage: 'assistant summary',
231
+ lastUserMessage: 'user request'
232
+ }
233
+ ]);
234
+ });
235
+ (0, vitest_1.it)('rolls back trigger replacement when a later insert fails', () => {
236
+ db.createAutomationRule({
237
+ id: 'rule-1',
238
+ name: 'Nightly run',
239
+ description: null,
240
+ type: 'interval',
241
+ intervalMs: 3000,
242
+ webhookKey: null,
243
+ cronExpression: null,
244
+ prompt: 'do work',
245
+ enabled: true,
246
+ createdAt: Date.now(),
247
+ lastRunAt: null,
248
+ lastSessionId: null
249
+ });
250
+ db.replaceAutomationTriggers('rule-1', [
251
+ {
252
+ id: 'trigger-existing',
253
+ type: 'interval',
254
+ intervalMs: 3000
255
+ }
256
+ ]);
257
+ (0, vitest_1.expect)(() => db.replaceAutomationTriggers('rule-1', [
258
+ {
259
+ id: 'trigger-duplicate',
260
+ type: 'interval',
261
+ intervalMs: 1000
262
+ },
263
+ {
264
+ id: 'trigger-duplicate',
265
+ type: 'cron',
266
+ cronExpression: '* * * * *'
267
+ }
268
+ ])).toThrowError();
269
+ (0, vitest_1.expect)(db.listAutomationTriggers('rule-1')).toEqual([
270
+ {
271
+ id: 'trigger-existing',
272
+ ruleId: 'rule-1',
273
+ type: 'interval',
274
+ intervalMs: 3000,
275
+ cronExpression: null,
276
+ webhookKey: null,
277
+ createdAt: Date.now()
278
+ }
279
+ ]);
280
+ });
157
281
  });
@@ -1,14 +1,11 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
7
3
  const vitest_1 = require("vitest");
8
4
  const schema_1 = require("../../src/db/automation/schema");
9
5
  const schema_2 = require("../../src/db/channelSessions/schema");
10
6
  const schema_3 = require("../../src/db/schema");
11
7
  const schema_4 = require("../../src/db/sessions/schema");
8
+ const sqlite_1 = require("../../src/db/sqlite");
12
9
  (0, vitest_1.describe)('db schema modules', () => {
13
10
  let sqlite;
14
11
  (0, vitest_1.afterEach)(() => {
@@ -16,7 +13,7 @@ const schema_4 = require("../../src/db/sessions/schema");
16
13
  sqlite = undefined;
17
14
  });
18
15
  (0, vitest_1.it)('supports injected schema modules', () => {
19
- sqlite = new better_sqlite3_1.default(':memory:');
16
+ sqlite = (0, sqlite_1.createSqliteDatabase)(':memory:');
20
17
  const customSchemaModule = {
21
18
  name: 'custom',
22
19
  apply({ exec }) {
@@ -28,7 +25,7 @@ const schema_4 = require("../../src/db/sessions/schema");
28
25
  (0, vitest_1.expect)(tables).toHaveLength(1);
29
26
  });
30
27
  (0, vitest_1.it)('migrates missing columns in domain schema modules', () => {
31
- sqlite = new better_sqlite3_1.default(':memory:');
28
+ sqlite = (0, sqlite_1.createSqliteDatabase)(':memory:');
32
29
  sqlite.exec(`
33
30
  CREATE TABLE sessions (
34
31
  id TEXT PRIMARY KEY,
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const sqlite_1 = require("../../src/db/sqlite");
5
+ (0, vitest_1.describe)('node sqlite adapter', () => {
6
+ let db;
7
+ (0, vitest_1.beforeEach)(() => {
8
+ db = (0, sqlite_1.createSqliteDatabase)(':memory:');
9
+ db.exec('CREATE TABLE items (id TEXT PRIMARY KEY, name TEXT NOT NULL);');
10
+ });
11
+ (0, vitest_1.afterEach)(() => {
12
+ db.close();
13
+ });
14
+ (0, vitest_1.it)('commits a successful transaction', () => {
15
+ const insertItem = db.transaction((id, name) => {
16
+ db.prepare('INSERT INTO items (id, name) VALUES (?, ?)').run(id, name);
17
+ });
18
+ insertItem('item-1', 'Item 1');
19
+ (0, vitest_1.expect)(db.prepare('SELECT id, name FROM items ORDER BY id ASC').all()).toEqual([
20
+ {
21
+ id: 'item-1',
22
+ name: 'Item 1'
23
+ }
24
+ ]);
25
+ });
26
+ (0, vitest_1.it)('rolls back a failed transaction', () => {
27
+ const insertThenFail = db.transaction(() => {
28
+ db.prepare('INSERT INTO items (id, name) VALUES (?, ?)').run('item-1', 'Item 1');
29
+ throw new Error('boom');
30
+ });
31
+ (0, vitest_1.expect)(() => insertThenFail()).toThrowError('boom');
32
+ (0, vitest_1.expect)(db.prepare('SELECT id, name FROM items').all()).toEqual([]);
33
+ });
34
+ (0, vitest_1.it)('uses savepoints for nested transactions', () => {
35
+ const outer = db.transaction(() => {
36
+ db.prepare('INSERT INTO items (id, name) VALUES (?, ?)').run('outer', 'Outer');
37
+ const inner = db.transaction(() => {
38
+ db.prepare('INSERT INTO items (id, name) VALUES (?, ?)').run('inner', 'Inner');
39
+ throw new Error('inner failed');
40
+ });
41
+ (0, vitest_1.expect)(() => inner()).toThrowError('inner failed');
42
+ });
43
+ outer();
44
+ (0, vitest_1.expect)(db.prepare('SELECT id, name FROM items ORDER BY id ASC').all()).toEqual([
45
+ {
46
+ id: 'outer',
47
+ name: 'Outer'
48
+ }
49
+ ]);
50
+ });
51
+ });
@@ -7,7 +7,7 @@ const runtime_js_1 = require("#~/services/session/runtime.js");
7
7
  const mocks = vitest_1.vi.hoisted(() => ({
8
8
  run: vitest_1.vi.fn(),
9
9
  generateAdapterQueryOptions: vitest_1.vi.fn(),
10
- loadMergedConfig: vitest_1.vi.fn(),
10
+ loadConfigState: vitest_1.vi.fn(),
11
11
  handleChannelSessionEvent: vitest_1.vi.fn()
12
12
  }));
13
13
  vitest_1.vi.mock('#~/db/index.js', () => ({
@@ -21,7 +21,7 @@ vitest_1.vi.mock('#~/channels/index.js', () => ({
21
21
  handleChannelSessionEvent: mocks.handleChannelSessionEvent
22
22
  }));
23
23
  vitest_1.vi.mock('#~/services/config/index.js', () => ({
24
- loadMergedConfig: mocks.loadMergedConfig
24
+ loadConfigState: mocks.loadConfigState
25
25
  }));
26
26
  vitest_1.vi.mock('#~/services/session/notification.js', () => ({
27
27
  maybeNotifySession: vitest_1.vi.fn().mockResolvedValue(undefined)
@@ -81,7 +81,7 @@ vitest_1.vi.mock('#~/utils/logger.js', () => ({
81
81
  mcpServers: undefined
82
82
  }
83
83
  ]);
84
- mocks.loadMergedConfig.mockResolvedValue({ mergedConfig: {} });
84
+ mocks.loadConfigState.mockResolvedValue({ mergedConfig: {} });
85
85
  mocks.handleChannelSessionEvent.mockResolvedValue(undefined);
86
86
  });
87
87
  (0, vitest_1.it)('reuses the cached runtime when adapter config is unchanged', async () => {
@@ -1,4 +1,4 @@
1
- import type Database from 'better-sqlite3';
1
+ import type { SqliteDatabase } from '../sqlite';
2
2
  export interface AutomationRule {
3
3
  id: string;
4
4
  name: string;
@@ -46,7 +46,7 @@ export interface AutomationRun {
46
46
  lastUserMessage?: string;
47
47
  }
48
48
  type AutomationRuleUpdate = Partial<Omit<AutomationRule, 'id' | 'createdAt'>>;
49
- export declare function createAutomationRepo(db: Database.Database): {
49
+ export declare function createAutomationRepo(db: SqliteDatabase): {
50
50
  createRule: (rule: AutomationRule) => void;
51
51
  createRun: (ruleId: string, sessionId: string, taskId?: string | null, taskTitle?: string | null) => void;
52
52
  getRule: (id: string) => AutomationRule | undefined;
@@ -1,5 +1,5 @@
1
1
  import type { SessionPermissionMode } from '@vibe-forge/core';
2
- import type Database from 'better-sqlite3';
2
+ import type { SqliteDatabase } from '../sqlite';
3
3
  export interface ChannelSessionRow {
4
4
  channelType: string;
5
5
  sessionType: string;
@@ -21,7 +21,7 @@ export interface ChannelPreferenceRow {
21
21
  createdAt: number;
22
22
  updatedAt: number;
23
23
  }
24
- export declare function createChannelSessionsRepo(db: Database.Database): {
24
+ export declare function createChannelSessionsRepo(db: SqliteDatabase): {
25
25
  get: (channelType: string, sessionType: string, channelId: string) => ChannelSessionRow | undefined;
26
26
  getPreference: (channelType: string, sessionType: string, channelId: string) => ChannelPreferenceRow | undefined;
27
27
  getBySessionId: (sessionId: string) => ChannelSessionRow | undefined;
@@ -1,6 +1,6 @@
1
- import Database from 'better-sqlite3';
1
+ import type { SqliteDatabase } from './sqlite';
2
2
  export interface DbConnection {
3
- db: Database.Database;
3
+ db: SqliteDatabase;
4
4
  dbPath: string;
5
5
  }
6
6
  export declare function createConnection(): DbConnection;
@@ -8,7 +8,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_os_1 = __importDefault(require("node:os"));
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const node_process_1 = require("node:process");
11
- const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
11
+ const sqlite_1 = require("./sqlite");
12
12
  function createConnection() {
13
13
  let dbPath = node_process_1.env.DB_PATH;
14
14
  if (dbPath == null || dbPath === '') {
@@ -30,6 +30,6 @@ function createConnection() {
30
30
  }
31
31
  return {
32
32
  dbPath,
33
- db: new better_sqlite3_1.default(dbPath)
33
+ db: (0, sqlite_1.createSqliteDatabase)(dbPath)
34
34
  };
35
35
  }
@@ -1,7 +1,7 @@
1
- import type Database from 'better-sqlite3';
2
1
  import type { AutomationRule, AutomationRuleDetail, AutomationRun, AutomationTask, AutomationTrigger } from './automation/repo';
2
+ import type { SqliteDatabase } from './sqlite';
3
3
  export interface SqliteDbOptions {
4
- db?: Database.Database;
4
+ db?: SqliteDatabase;
5
5
  }
6
6
  export declare class SqliteDb {
7
7
  private db;
@@ -1,6 +1,6 @@
1
- import type Database from 'better-sqlite3';
1
+ import type { SqliteDatabase } from './sqlite';
2
2
  export interface SchemaContext {
3
- db: Database.Database;
3
+ db: SqliteDatabase;
4
4
  exec: (sql: string) => void;
5
5
  getColumns: (tableName: string) => string[];
6
6
  ensureColumn: (tableName: string, columnName: string, definition: string) => void;
@@ -9,4 +9,4 @@ export interface SchemaModule {
9
9
  name: string;
10
10
  apply: (context: SchemaContext) => void;
11
11
  }
12
- export declare function initSchema(db: Database.Database, modules: readonly SchemaModule[]): void;
12
+ export declare function initSchema(db: SqliteDatabase, modules: readonly SchemaModule[]): void;
@@ -1,5 +1,5 @@
1
- import type Database from 'better-sqlite3';
2
- export declare function createMessagesRepo(db: Database.Database): {
1
+ import type { SqliteDatabase } from '../sqlite';
2
+ export declare function createMessagesRepo(db: SqliteDatabase): {
3
3
  copy: (fromSessionId: string, toSessionId: string) => void;
4
4
  list: (sessionId: string) => unknown[];
5
5
  save: (sessionId: string, data: unknown) => void;
@@ -1,7 +1,7 @@
1
- import type Database from 'better-sqlite3';
2
1
  import type { Session } from '@vibe-forge/core';
2
+ import type { SqliteDatabase } from '../sqlite';
3
3
  type SessionUpdate = Partial<Omit<Session, 'id' | 'createdAt' | 'messageCount'>>;
4
- export declare function createSessionsRepo(db: Database.Database): {
4
+ export declare function createSessionsRepo(db: SqliteDatabase): {
5
5
  archiveTree: (id: string, isArchived: boolean) => string[];
6
6
  create: (title?: string, id?: string, status?: string, parentSessionId?: string) => Session;
7
7
  get: (id: string) => Session | undefined;