@proletariat/cli 0.3.88 → 0.3.89

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 (68) hide show
  1. package/dist/commands/db/repair.d.ts +14 -0
  2. package/dist/commands/db/repair.js +186 -0
  3. package/dist/commands/db/repair.js.map +1 -0
  4. package/dist/commands/session/list.js +42 -0
  5. package/dist/commands/session/list.js.map +1 -1
  6. package/dist/commands/session/poke.d.ts +6 -0
  7. package/dist/commands/session/poke.js +40 -0
  8. package/dist/commands/session/poke.js.map +1 -1
  9. package/dist/commands/work/start.d.ts +1 -0
  10. package/dist/commands/work/start.js +20 -1
  11. package/dist/commands/work/start.js.map +1 -1
  12. package/dist/lib/dashboard/data.js +2 -2
  13. package/dist/lib/dashboard/data.js.map +1 -1
  14. package/dist/lib/database/db-safety.d.ts +59 -0
  15. package/dist/lib/database/db-safety.js +295 -0
  16. package/dist/lib/database/db-safety.js.map +1 -0
  17. package/dist/lib/database/driver.d.ts +1 -1
  18. package/dist/lib/database/driver.js +2 -1
  19. package/dist/lib/database/driver.js.map +1 -1
  20. package/dist/lib/database/index.d.ts +1 -0
  21. package/dist/lib/database/index.js +2 -0
  22. package/dist/lib/database/index.js.map +1 -1
  23. package/dist/lib/database/migrations/0012_add_action_network_allowlist.d.ts +9 -0
  24. package/dist/lib/database/migrations/0012_add_action_network_allowlist.js +22 -0
  25. package/dist/lib/database/migrations/0012_add_action_network_allowlist.js.map +1 -0
  26. package/dist/lib/database/migrations/index.js +2 -0
  27. package/dist/lib/database/migrations/index.js.map +1 -1
  28. package/dist/lib/database/workspace.d.ts +6 -1
  29. package/dist/lib/database/workspace.js +37 -1
  30. package/dist/lib/database/workspace.js.map +1 -1
  31. package/dist/lib/execution/config.d.ts +13 -0
  32. package/dist/lib/execution/config.js +60 -0
  33. package/dist/lib/execution/config.js.map +1 -1
  34. package/dist/lib/execution/devcontainer.d.ts +2 -0
  35. package/dist/lib/execution/devcontainer.js +6 -1
  36. package/dist/lib/execution/devcontainer.js.map +1 -1
  37. package/dist/lib/execution/runners/docker-management.d.ts +6 -0
  38. package/dist/lib/execution/runners/docker-management.js +28 -12
  39. package/dist/lib/execution/runners/docker-management.js.map +1 -1
  40. package/dist/lib/execution/runners/sandbox.js +2 -1
  41. package/dist/lib/execution/runners/sandbox.js.map +1 -1
  42. package/dist/lib/execution/spawner.d.ts +2 -0
  43. package/dist/lib/execution/spawner.js +1 -0
  44. package/dist/lib/execution/spawner.js.map +1 -1
  45. package/dist/lib/execution/storage.d.ts +43 -9
  46. package/dist/lib/execution/storage.js +58 -43
  47. package/dist/lib/execution/storage.js.map +1 -1
  48. package/dist/lib/execution/types.d.ts +1 -0
  49. package/dist/lib/execution/types.js.map +1 -1
  50. package/dist/lib/pmo/find-pmo.js +10 -10
  51. package/dist/lib/pmo/find-pmo.js.map +1 -1
  52. package/dist/lib/pmo/schema.d.ts +1 -1
  53. package/dist/lib/pmo/schema.js +1 -0
  54. package/dist/lib/pmo/schema.js.map +1 -1
  55. package/dist/lib/pmo/storage/actions.js +9 -3
  56. package/dist/lib/pmo/storage/actions.js.map +1 -1
  57. package/dist/lib/pmo/storage/types.d.ts +1 -0
  58. package/dist/lib/pmo/types.d.ts +1 -0
  59. package/dist/lib/pmo/types.js.map +1 -1
  60. package/dist/lib/registry/index.d.ts +2 -2
  61. package/dist/lib/registry/index.js +5 -6
  62. package/dist/lib/registry/index.js.map +1 -1
  63. package/dist/lib/session-store.js +2 -2
  64. package/dist/lib/session-store.js.map +1 -1
  65. package/dist/lib/work-lifecycle/action-chaining.js +4 -0
  66. package/dist/lib/work-lifecycle/action-chaining.js.map +1 -1
  67. package/oclif.manifest.json +950 -889
  68. package/package.json +1 -1
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Database Safety — WAL mode, auto-backup, corruption recovery.
3
+ *
4
+ * Provides:
5
+ * - WAL journal mode configuration
6
+ * - Rotating backup (keeps last 5 copies)
7
+ * - Integrity check on open with auto-recovery
8
+ * - Manual repair via dump/reimport
9
+ *
10
+ * See: PRLT-1081
11
+ */
12
+ import Database from 'better-sqlite3';
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ const MAX_BACKUPS = 5;
16
+ /**
17
+ * Enable WAL journal mode on a database connection.
18
+ * WAL allows concurrent readers with one writer and is significantly
19
+ * more resistant to corruption than the default journal_mode=delete.
20
+ */
21
+ export function enableWALMode(db) {
22
+ db.pragma('journal_mode = WAL');
23
+ }
24
+ /**
25
+ * Get the backup path for a given database path and backup number.
26
+ */
27
+ export function getBackupPath(dbPath, n) {
28
+ return `${dbPath}.backup.${n}`;
29
+ }
30
+ /**
31
+ * Create a rotating backup of the database file.
32
+ * Keeps the last MAX_BACKUPS copies, numbered 1 (newest) through MAX_BACKUPS (oldest).
33
+ * Rotates existing backups before copying the current database.
34
+ *
35
+ * Returns true if backup was created, false if source didn't exist.
36
+ */
37
+ export function createRotatingBackup(dbPath) {
38
+ if (!fs.existsSync(dbPath)) {
39
+ return false;
40
+ }
41
+ // Rotate existing backups: delete oldest, shift others up
42
+ const oldest = getBackupPath(dbPath, MAX_BACKUPS);
43
+ if (fs.existsSync(oldest)) {
44
+ fs.unlinkSync(oldest);
45
+ }
46
+ for (let i = MAX_BACKUPS - 1; i >= 1; i--) {
47
+ const src = getBackupPath(dbPath, i);
48
+ const dst = getBackupPath(dbPath, i + 1);
49
+ if (fs.existsSync(src)) {
50
+ fs.renameSync(src, dst);
51
+ }
52
+ }
53
+ // Copy current database as backup.1 (newest)
54
+ try {
55
+ fs.copyFileSync(dbPath, getBackupPath(dbPath, 1));
56
+ // Also copy WAL and SHM files if they exist (for WAL-mode databases)
57
+ const walPath = `${dbPath}-wal`;
58
+ const shmPath = `${dbPath}-shm`;
59
+ if (fs.existsSync(walPath)) {
60
+ fs.copyFileSync(walPath, `${getBackupPath(dbPath, 1)}-wal`);
61
+ }
62
+ if (fs.existsSync(shmPath)) {
63
+ fs.copyFileSync(shmPath, `${getBackupPath(dbPath, 1)}-shm`);
64
+ }
65
+ return true;
66
+ }
67
+ catch {
68
+ // Backup failure is not fatal — log and continue
69
+ return false;
70
+ }
71
+ }
72
+ /**
73
+ * Run PRAGMA integrity_check on a database.
74
+ * Returns { ok: true } if the database is healthy, or { ok: false, errors } with details.
75
+ */
76
+ export function checkIntegrity(db) {
77
+ try {
78
+ const rows = db.pragma('integrity_check');
79
+ const errors = rows
80
+ .map(r => r.integrity_check)
81
+ .filter(msg => msg !== 'ok');
82
+ return { ok: errors.length === 0, errors };
83
+ }
84
+ catch (error) {
85
+ return {
86
+ ok: false,
87
+ errors: [error instanceof Error ? error.message : String(error)],
88
+ };
89
+ }
90
+ }
91
+ /**
92
+ * Quick integrity check using PRAGMA quick_check (faster than full integrity_check).
93
+ * Skips checking that the contents of table rows match the indexes.
94
+ */
95
+ export function quickCheckIntegrity(db) {
96
+ try {
97
+ const rows = db.pragma('quick_check');
98
+ const errors = rows
99
+ .map(r => r.quick_check)
100
+ .filter(msg => msg !== 'ok');
101
+ return { ok: errors.length === 0, errors };
102
+ }
103
+ catch (error) {
104
+ return {
105
+ ok: false,
106
+ errors: [error instanceof Error ? error.message : String(error)],
107
+ };
108
+ }
109
+ }
110
+ /**
111
+ * Attempt to repair a corrupted database.
112
+ *
113
+ * Strategy:
114
+ * 1. Try dump/reimport — opens the corrupt DB, dumps all SQL, creates a new DB
115
+ * 2. If dump fails, fall back to the most recent backup
116
+ *
117
+ * The original corrupt file is preserved as dbPath.corrupt for forensics.
118
+ */
119
+ export function repairDatabase(dbPath) {
120
+ // Try dump/reimport first
121
+ const dumpResult = attemptDumpReimport(dbPath);
122
+ if (dumpResult.success) {
123
+ return dumpResult;
124
+ }
125
+ // Fall back to backup restore
126
+ const backupResult = attemptBackupRestore(dbPath);
127
+ if (backupResult.success) {
128
+ return backupResult;
129
+ }
130
+ return {
131
+ success: false,
132
+ method: 'none',
133
+ message: `Could not repair database. Dump failed: ${dumpResult.message}. No usable backups found.`,
134
+ };
135
+ }
136
+ /**
137
+ * Attempt recovery via .dump and reimport.
138
+ * Opens the corrupt database, extracts as much SQL as possible,
139
+ * then creates a fresh database from that SQL.
140
+ */
141
+ function attemptDumpReimport(dbPath) {
142
+ let corruptDb = null;
143
+ let newDb = null;
144
+ const tempPath = `${dbPath}.repair-temp`;
145
+ try {
146
+ // Open corrupt database — may partially work
147
+ corruptDb = new Database(dbPath, { readonly: true });
148
+ // Dump all recoverable SQL
149
+ const tables = corruptDb.prepare("SELECT sql FROM sqlite_master WHERE sql IS NOT NULL ORDER BY CASE type WHEN 'table' THEN 1 WHEN 'index' THEN 2 ELSE 3 END").all();
150
+ if (tables.length === 0) {
151
+ return { success: false, method: 'dump-reimport', message: 'No tables found in corrupt database' };
152
+ }
153
+ // Create new database with recovered schema
154
+ newDb = new Database(tempPath);
155
+ newDb.pragma('journal_mode = WAL');
156
+ for (const { sql } of tables) {
157
+ try {
158
+ newDb.exec(sql);
159
+ }
160
+ catch {
161
+ // Skip objects that fail to recreate (e.g., references to missing tables)
162
+ }
163
+ }
164
+ // Copy data table by table
165
+ const tableNames = corruptDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
166
+ let rowsRecovered = 0;
167
+ for (const { name } of tableNames) {
168
+ try {
169
+ const rows = corruptDb.prepare(`SELECT * FROM "${name}"`).all();
170
+ if (rows.length === 0)
171
+ continue;
172
+ const columns = Object.keys(rows[0]);
173
+ const placeholders = columns.map(() => '?').join(', ');
174
+ const insertSql = `INSERT OR IGNORE INTO "${name}" (${columns.map(c => `"${c}"`).join(', ')}) VALUES (${placeholders})`;
175
+ const insertStmt = newDb.prepare(insertSql);
176
+ const insertAll = newDb.transaction((data) => {
177
+ for (const row of data) {
178
+ insertStmt.run(...columns.map(c => row[c]));
179
+ }
180
+ });
181
+ insertAll(rows);
182
+ rowsRecovered += rows.length;
183
+ }
184
+ catch {
185
+ // Skip tables that can't be read
186
+ }
187
+ }
188
+ corruptDb.close();
189
+ corruptDb = null;
190
+ newDb.close();
191
+ newDb = null;
192
+ // Swap files: corrupt → .corrupt, repaired → original
193
+ const corruptBackupPath = `${dbPath}.corrupt`;
194
+ if (fs.existsSync(corruptBackupPath)) {
195
+ fs.unlinkSync(corruptBackupPath);
196
+ }
197
+ fs.renameSync(dbPath, corruptBackupPath);
198
+ fs.renameSync(tempPath, dbPath);
199
+ // Clean up old WAL/SHM files from the corrupt database
200
+ for (const suffix of ['-wal', '-shm']) {
201
+ const f = `${dbPath}${suffix}`;
202
+ if (fs.existsSync(f)) {
203
+ fs.unlinkSync(f);
204
+ }
205
+ }
206
+ return {
207
+ success: true,
208
+ method: 'dump-reimport',
209
+ message: `Recovered ${rowsRecovered} rows from ${tableNames.length} tables. Corrupt file saved as ${path.basename(corruptBackupPath)}.`,
210
+ };
211
+ }
212
+ catch (error) {
213
+ // Clean up on failure
214
+ if (corruptDb) {
215
+ try {
216
+ corruptDb.close();
217
+ }
218
+ catch { /* ignore */ }
219
+ }
220
+ if (newDb) {
221
+ try {
222
+ newDb.close();
223
+ }
224
+ catch { /* ignore */ }
225
+ }
226
+ if (fs.existsSync(tempPath)) {
227
+ try {
228
+ fs.unlinkSync(tempPath);
229
+ }
230
+ catch { /* ignore */ }
231
+ }
232
+ return {
233
+ success: false,
234
+ method: 'dump-reimport',
235
+ message: error instanceof Error ? error.message : String(error),
236
+ };
237
+ }
238
+ }
239
+ /**
240
+ * Attempt recovery by restoring from the most recent valid backup.
241
+ * Tries backups 1 through MAX_BACKUPS, validates each with integrity_check.
242
+ */
243
+ function attemptBackupRestore(dbPath) {
244
+ for (let i = 1; i <= MAX_BACKUPS; i++) {
245
+ const backupPath = getBackupPath(dbPath, i);
246
+ if (!fs.existsSync(backupPath)) {
247
+ continue;
248
+ }
249
+ // Validate the backup
250
+ let backupDb = null;
251
+ try {
252
+ backupDb = new Database(backupPath, { readonly: true });
253
+ const check = checkIntegrity(backupDb);
254
+ backupDb.close();
255
+ backupDb = null;
256
+ if (!check.ok) {
257
+ continue;
258
+ }
259
+ // Backup is valid — swap it in
260
+ const corruptBackupPath = `${dbPath}.corrupt`;
261
+ if (fs.existsSync(corruptBackupPath)) {
262
+ fs.unlinkSync(corruptBackupPath);
263
+ }
264
+ fs.renameSync(dbPath, corruptBackupPath);
265
+ fs.copyFileSync(backupPath, dbPath);
266
+ // Clean up old WAL/SHM files
267
+ for (const suffix of ['-wal', '-shm']) {
268
+ const f = `${dbPath}${suffix}`;
269
+ if (fs.existsSync(f)) {
270
+ fs.unlinkSync(f);
271
+ }
272
+ }
273
+ return {
274
+ success: true,
275
+ method: 'backup-restore',
276
+ message: `Restored from backup.${i}. Corrupt file saved as ${path.basename(corruptBackupPath)}.`,
277
+ };
278
+ }
279
+ catch {
280
+ if (backupDb) {
281
+ try {
282
+ backupDb.close();
283
+ }
284
+ catch { /* ignore */ }
285
+ }
286
+ continue;
287
+ }
288
+ }
289
+ return {
290
+ success: false,
291
+ method: 'backup-restore',
292
+ message: 'No valid backups found',
293
+ };
294
+ }
295
+ //# sourceMappingURL=db-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-safety.js","sourceRoot":"","sources":["../../../src/lib/database/db-safety.ts"],"names":[],"mappings":"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"}
@@ -99,7 +99,7 @@ export declare class BetterSqlite3Driver implements DatabaseDriver {
99
99
  export declare function wrapDatabase(db: Database.Database): DatabaseDriver;
100
100
  /**
101
101
  * Create a DatabaseDriver by opening a new better-sqlite3 connection.
102
- * Configures standard pragmas (foreign keys, busy timeout).
102
+ * Configures standard pragmas (WAL mode, foreign keys, busy timeout).
103
103
  */
104
104
  export declare function openDriver(dbPath: string, options?: {
105
105
  foreignKeys?: boolean;
@@ -73,10 +73,11 @@ export function wrapDatabase(db) {
73
73
  }
74
74
  /**
75
75
  * Create a DatabaseDriver by opening a new better-sqlite3 connection.
76
- * Configures standard pragmas (foreign keys, busy timeout).
76
+ * Configures standard pragmas (WAL mode, foreign keys, busy timeout).
77
77
  */
78
78
  export function openDriver(dbPath, options) {
79
79
  const db = new Database(dbPath);
80
+ db.pragma('journal_mode = WAL');
80
81
  if (options?.foreignKeys !== false) {
81
82
  db.pragma('foreign_keys = ON');
82
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/lib/database/driver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/lib/database/driver.ts"],"names":[],"mappings":"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"}
@@ -25,3 +25,4 @@ export { type MediaItem, addMediaItemToDatabase, updateMediaItemStatus, getWorks
25
25
  export { checkPMOExists, getPMOSetting, dropPMOTables, upsertWorkspaceSetting, } from './pmo-bootstrap.js';
26
26
  export { type DatabaseDriver, type PreparedStatement, type RunResult, BetterSqlite3Driver, wrapDatabase, openDriver, getRawDatabase, } from './driver.js';
27
27
  export { SettingsStore, createSettingsStore, } from './settings-store.js';
28
+ export { enableWALMode, createRotatingBackup, checkIntegrity, quickCheckIntegrity, repairDatabase, getBackupPath, type IntegrityCheckResult, type RepairResult, } from './db-safety.js';
@@ -35,4 +35,6 @@ export { checkPMOExists, getPMOSetting, dropPMOTables, upsertWorkspaceSetting, }
35
35
  export { BetterSqlite3Driver, wrapDatabase, openDriver, getRawDatabase, } from './driver.js';
36
36
  // Settings store
37
37
  export { SettingsStore, createSettingsStore, } from './settings-store.js';
38
+ // Database safety (WAL, backup, integrity, repair)
39
+ export { enableWALMode, createRotatingBackup, checkIntegrity, quickCheckIntegrity, repairDatabase, getBackupPath, } from './db-safety.js';
38
40
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/database/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,0DAA0D;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD,sBAAsB;AACtB,OAAO,EAEL,WAAW,EACX,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AAEvB,mBAAmB;AACnB,OAAO,EAML,mBAAmB,EACnB,2BAA2B,EAC3B,8BAA8B,EAC9B,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,wBAAwB;AACxB,OAAO,EAEL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,mBAAmB,CAAA;AAE1B,mBAAmB;AACnB,OAAO,EAGL,cAAc,EACd,cAAc,EACd,SAAS,EACT,QAAQ,EACR,WAAW,EACX,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,aAAa,GACd,MAAM,aAAa,CAAA;AAEpB,sBAAsB;AACtB,OAAO,EAEL,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,wBAAwB;AACxB,OAAO,EAEL,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,2BAA2B,GAC5B,MAAM,YAAY,CAAA;AAEnB,2BAA2B;AAC3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAE3B,8BAA8B;AAC9B,OAAO,EAIL,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,iBAAiB;AACjB,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/database/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,0DAA0D;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD,sBAAsB;AACtB,OAAO,EAEL,WAAW,EACX,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AAEvB,mBAAmB;AACnB,OAAO,EAML,mBAAmB,EACnB,2BAA2B,EAC3B,8BAA8B,EAC9B,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,wBAAwB;AACxB,OAAO,EAEL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,mBAAmB,CAAA;AAE1B,mBAAmB;AACnB,OAAO,EAGL,cAAc,EACd,cAAc,EACd,SAAS,EACT,QAAQ,EACR,WAAW,EACX,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,aAAa,GACd,MAAM,aAAa,CAAA;AAEpB,sBAAsB;AACtB,OAAO,EAEL,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,wBAAwB;AACxB,OAAO,EAEL,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,2BAA2B,GAC5B,MAAM,YAAY,CAAA;AAEnB,2BAA2B;AAC3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAE3B,8BAA8B;AAC9B,OAAO,EAIL,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,iBAAiB;AACjB,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAA;AAE5B,mDAAmD;AACnD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,aAAa,GAGd,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Migration 0012 — Add network_allowlist column to pmo_actions
3
+ *
4
+ * Enables per-action network allowlist configuration.
5
+ * Stores a JSON array of domain strings (e.g., '["api.linear.app"]').
6
+ * NULL means use workspace/global defaults only.
7
+ */
8
+ import type { Migration } from '../migrator.js';
9
+ export declare const addActionNetworkAllowlist: Migration;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Migration 0012 — Add network_allowlist column to pmo_actions
3
+ *
4
+ * Enables per-action network allowlist configuration.
5
+ * Stores a JSON array of domain strings (e.g., '["api.linear.app"]').
6
+ * NULL means use workspace/global defaults only.
7
+ */
8
+ export const addActionNetworkAllowlist = {
9
+ id: '0012',
10
+ name: 'add_action_network_allowlist',
11
+ up: (db) => {
12
+ const tableExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='pmo_actions'").get();
13
+ if (!tableExists)
14
+ return;
15
+ const tableInfo = db.prepare("PRAGMA table_info(pmo_actions)").all();
16
+ if (tableInfo.some(col => col.name === 'network_allowlist')) {
17
+ return; // Column already exists
18
+ }
19
+ db.exec("ALTER TABLE pmo_actions ADD COLUMN network_allowlist TEXT");
20
+ },
21
+ };
22
+ //# sourceMappingURL=0012_add_action_network_allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"0012_add_action_network_allowlist.js","sourceRoot":"","sources":["../../../../src/lib/database/migrations/0012_add_action_network_allowlist.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,CAAC,MAAM,yBAAyB,GAAc;IAClD,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,8BAA8B;IACpC,EAAE,EAAE,CAAC,EAAqB,EAAE,EAAE;QAC5B,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAC5B,0EAA0E,CAC3E,CAAC,GAAG,EAAE,CAAA;QACP,IAAI,CAAC,WAAW;YAAE,OAAM;QAExB,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC,GAAG,EAAwB,CAAA;QAC1F,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,mBAAmB,CAAC,EAAE,CAAC;YAC5D,OAAM,CAAC,wBAAwB;QACjC,CAAC;QAED,EAAE,CAAC,IAAI,CACL,2DAA2D,CAC5D,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -15,6 +15,7 @@ import { addAgentMountMode } from './0008_add_agent_mount_mode.js';
15
15
  import { createMediaItems } from './0009_create_media_items.js';
16
16
  import { addTicketPosition } from './0010_add_ticket_position.js';
17
17
  import { addReviewGate } from './0011_add_review_gate.js';
18
+ import { addActionNetworkAllowlist } from './0012_add_action_network_allowlist.js';
18
19
  /**
19
20
  * Ordered list of all migrations.
20
21
  * New migrations should be appended to the end of this array.
@@ -31,5 +32,6 @@ export const ALL_MIGRATIONS = [
31
32
  createMediaItems,
32
33
  addTicketPosition,
33
34
  addReviewGate,
35
+ addActionNetworkAllowlist,
34
36
  ];
35
37
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/database/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,QAAQ;IACR,SAAS;IACT,eAAe;IACf,aAAa;IACb,qBAAqB;IACrB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,aAAa;CACd,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/database/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAA;AAElF;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,QAAQ;IACR,SAAS;IACT,eAAe;IACf,aAAa;IACb,qBAAqB;IACrB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,aAAa;IACb,yBAAyB;CAC1B,CAAA"}
@@ -28,7 +28,12 @@ export declare function getDatabasePath(workspacePath: string): string;
28
28
  */
29
29
  export declare function getConfigPath(workspacePath: string): string;
30
30
  /**
31
- * Open workspace database connection
31
+ * Open workspace database connection.
32
+ *
33
+ * Safety features (PRLT-1081):
34
+ * - Creates a rotating backup before opening (keeps last 5)
35
+ * - Enables WAL journal mode for corruption resistance
36
+ * - Runs a quick integrity check; auto-repairs if corruption detected
32
37
  */
33
38
  export declare function openWorkspaceDatabase(workspacePath: string): Database.Database;
34
39
  /**
@@ -13,6 +13,7 @@ import { ALL_MIGRATIONS } from './migrations/index.js';
13
13
  import { createDrizzleConnection } from './drizzle.js';
14
14
  import { workspace as workspaceTable, } from './drizzle-schema.js';
15
15
  import { BetterSqlite3Driver } from './driver.js';
16
+ import { enableWALMode, createRotatingBackup, quickCheckIntegrity, repairDatabase, } from './db-safety.js';
16
17
  /**
17
18
  * Open the workspace database, wrap it with Drizzle, run a function,
18
19
  * and close the connection. Handles the open/close lifecycle.
@@ -68,13 +69,20 @@ export function getConfigPath(workspacePath) {
68
69
  return path.join(workspacePath, '.proletariat', 'config.json');
69
70
  }
70
71
  /**
71
- * Open workspace database connection
72
+ * Open workspace database connection.
73
+ *
74
+ * Safety features (PRLT-1081):
75
+ * - Creates a rotating backup before opening (keeps last 5)
76
+ * - Enables WAL journal mode for corruption resistance
77
+ * - Runs a quick integrity check; auto-repairs if corruption detected
72
78
  */
73
79
  export function openWorkspaceDatabase(workspacePath) {
74
80
  const dbPath = getDatabasePath(workspacePath);
75
81
  if (!fs.existsSync(dbPath)) {
76
82
  throw new Error(`Database not found: ${dbPath}. Run 'prlt new' first.`);
77
83
  }
84
+ // Auto-backup before opening (cheap insurance against corruption)
85
+ createRotatingBackup(dbPath);
78
86
  let db;
79
87
  try {
80
88
  db = new Database(dbPath);
@@ -83,8 +91,35 @@ export function openWorkspaceDatabase(workspacePath) {
83
91
  throwIfNativeBindingError(error, 'openWorkspaceDatabase');
84
92
  throw error;
85
93
  }
94
+ // Enable WAL mode — allows concurrent readers with one writer,
95
+ // significantly more resistant to corruption than journal_mode=delete
96
+ enableWALMode(db);
86
97
  db.pragma('foreign_keys = ON');
87
98
  db.pragma('busy_timeout = 5000');
99
+ // Quick integrity check on startup
100
+ const integrity = quickCheckIntegrity(db);
101
+ if (!integrity.ok) {
102
+ db.close();
103
+ // Attempt auto-repair
104
+ const repair = repairDatabase(dbPath);
105
+ if (!repair.success) {
106
+ throw new Error(`Database corruption detected in ${dbPath}.\n` +
107
+ `Integrity errors: ${integrity.errors.join('; ')}\n` +
108
+ `Auto-repair failed: ${repair.message}\n` +
109
+ `Run 'prlt db repair' for manual recovery options.`);
110
+ }
111
+ // Re-open the repaired database
112
+ try {
113
+ db = new Database(dbPath);
114
+ }
115
+ catch (error) {
116
+ throwIfNativeBindingError(error, 'openWorkspaceDatabase (post-repair)');
117
+ throw error;
118
+ }
119
+ enableWALMode(db);
120
+ db.pragma('foreign_keys = ON');
121
+ db.pragma('busy_timeout = 5000');
122
+ }
88
123
  runDrizzleMigrations(db, ALL_MIGRATIONS);
89
124
  ensureEphemeralAgentTypes(db);
90
125
  return db;
@@ -120,6 +155,7 @@ export function createWorkspaceDatabase(workspacePath, type, workspaceName, hasP
120
155
  throwIfNativeBindingError(error, 'createWorkspaceDatabase');
121
156
  throw error;
122
157
  }
158
+ enableWALMode(db);
123
159
  db.pragma('foreign_keys = ON');
124
160
  runDrizzleMigrations(db, ALL_MIGRATIONS);
125
161
  const ddb = createDrizzleConnection(db);
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/lib/database/workspace.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/lib/database/workspace.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AACrC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,uBAAuB,EAAkB,MAAM,cAAc,CAAA;AACtE,OAAO,EACL,SAAS,IAAI,cAAc,GAC5B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,GACf,MAAM,gBAAgB,CAAA;AAWvB;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAI,aAAqB,EAAE,EAAsD;IAC1G,MAAM,QAAQ,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAA;IACrD,MAAM,GAAG,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAA;IAC7C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;IAC1B,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,KAAK,EAAE,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,yBAAyB,CAAC,EAAqB;IACtD,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,qEAAqE,CAAC,CAAC,GAAG,EAAE,CAAA;IAC3G,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAM;IACR,CAAC;IAED,EAAE,CAAC,IAAI,CAAC,uGAAuG,CAAC,CAAA;IAEhH,EAAE,CAAC,IAAI,CAAC;;;;GAIP,CAAC,CAAA;IAEF,MAAM,kBAAkB,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;GAKrC,CAAC,CAAC,GAAG,EAAwB,CAAA;IAE9B,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAA;IACpF,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;QACvC,IAAI,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,aAAqB;IACnD,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,EAAE,cAAc,CAAC,CAAA;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,aAAqB;IACjD,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,aAAqB;IACzD,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAAA;IAE7C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,yBAAyB,CAAC,CAAA;IACzE,CAAC;IAED,kEAAkE;IAClE,oBAAoB,CAAC,MAAM,CAAC,CAAA;IAE5B,IAAI,EAAqB,CAAA;IACzB,IAAI,CAAC;QACH,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yBAAyB,CAAC,KAAK,EAAE,uBAAuB,CAAC,CAAA;QACzD,MAAM,KAAK,CAAA;IACb,CAAC;IAED,+DAA+D;IAC/D,sEAAsE;IACtE,aAAa,CAAC,EAAE,CAAC,CAAA;IACjB,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC9B,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAEhC,mCAAmC;IACnC,MAAM,SAAS,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAA;IACzC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;QAClB,EAAE,CAAC,KAAK,EAAE,CAAA;QAEV,sBAAsB;QACtB,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;QACrC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,mCAAmC,MAAM,KAAK;gBAC9C,qBAAqB,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBACpD,uBAAuB,MAAM,CAAC,OAAO,IAAI;gBACzC,mDAAmD,CACpD,CAAA;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC;YACH,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,yBAAyB,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAA;YACvE,MAAM,KAAK,CAAA;QACb,CAAC;QACD,aAAa,CAAC,EAAE,CAAC,CAAA;QACjB,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;QAC9B,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAClC,CAAC;IAED,oBAAoB,CAAC,EAAE,EAAE,cAAc,CAAC,CAAA;IACxC,yBAAyB,CAAC,EAAE,CAAC,CAAA;IAE7B,OAAO,EAAE,CAAA;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,aAAqB;IACvD,MAAM,EAAE,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC/C,OAAO,IAAI,mBAAmB,CAAC,EAAE,CAAC,CAAA;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,aAAqB,EACrB,IAAwB,EACxB,aAAqB,EACrB,SAAkB,KAAK;IAEvB,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAAA;IAC7C,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,CAAC,CAAA;IAE/C,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACnC,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,CAAC;IAED,MAAM,eAAe,GAAG;QACtB,OAAO,EAAE,OAAO;QAChB,aAAa,EAAE,CAAC;KACjB,CAAA;IACD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAEtE,IAAI,EAAqB,CAAA;IACzB,IAAI,CAAC;QACH,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yBAAyB,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAA;QAC3D,MAAM,KAAK,CAAA;IACb,CAAC;IAED,aAAa,CAAC,EAAE,CAAC,CAAA;IACjB,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC9B,oBAAoB,CAAC,EAAE,EAAE,cAAc,CAAC,CAAA;IAExC,MAAM,GAAG,GAAG,uBAAuB,CAAC,EAAE,CAAC,CAAA;IACvC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;QAChC,EAAE,EAAE,CAAC;QACL,IAAI;QACJ,aAAa;QACb,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC,GAAG,EAAE,CAAA;IAER,OAAO,EAAE,CAAA;AACX,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAqB;IACtD,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE;YACxC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;YAC5D,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAA;YACrB,OAAO;gBACL,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC;gBACf,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,cAAc,EAAE,GAAG,CAAC,aAAa;gBACjC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC5B,eAAe,EAAE,GAAG,CAAC,aAAa;gBAClC,UAAU,EAAE,GAAG,CAAC,SAAS;aAC1B,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -65,6 +65,19 @@ export declare function setDefaultCleanupPolicy(db: Database.Database, policy: C
65
65
  * Set the cleanup policy for a specific action.
66
66
  */
67
67
  export declare function setActionCleanupPolicy(db: Database.Database, actionId: string, policy: CleanupPolicy): void;
68
+ /**
69
+ * Resolve the network allowlist for a spawn, merging layers:
70
+ * 1. Action-level: action.networkAllowlist (from pmo_actions table)
71
+ * 2. Per-action override: network.actions.{actionId} (from workspace_settings)
72
+ * 3. Workspace global: firewall.allowlistDomains (from ExecutionConfig)
73
+ *
74
+ * All layers are merged (union). Duplicates are removed.
75
+ */
76
+ export declare function getNetworkAllowlist(config: ExecutionConfig, actionId?: string, actionNetworkAllowlist?: string[], db?: Database.Database): string[];
77
+ /**
78
+ * Set the network allowlist for a specific action in workspace_settings.
79
+ */
80
+ export declare function setActionNetworkAllowlist(db: Database.Database, actionId: string, domains: string[]): void;
68
81
  /**
69
82
  * Save terminal app preference
70
83
  */
@@ -302,6 +302,66 @@ export function setDefaultCleanupPolicy(db, policy) {
302
302
  export function setActionCleanupPolicy(db, actionId, policy) {
303
303
  setSetting(db, `cleanup.actions.${actionId}`, policy);
304
304
  }
305
+ // =============================================================================
306
+ // Network Allowlist Configuration
307
+ // =============================================================================
308
+ /**
309
+ * Resolve the network allowlist for a spawn, merging layers:
310
+ * 1. Action-level: action.networkAllowlist (from pmo_actions table)
311
+ * 2. Per-action override: network.actions.{actionId} (from workspace_settings)
312
+ * 3. Workspace global: firewall.allowlistDomains (from ExecutionConfig)
313
+ *
314
+ * All layers are merged (union). Duplicates are removed.
315
+ */
316
+ export function getNetworkAllowlist(config, actionId, actionNetworkAllowlist, db) {
317
+ const domains = new Set();
318
+ // Layer 1: workspace-level firewall.allowlistDomains (always applied)
319
+ for (const domain of config.firewall.allowlistDomains) {
320
+ domains.add(domain.trim().toLowerCase());
321
+ }
322
+ // Layer 2: per-action override from workspace_settings
323
+ if (db && actionId) {
324
+ const settingValue = getSetting(db, `network.actions.${actionId}`);
325
+ if (settingValue) {
326
+ try {
327
+ const parsed = JSON.parse(settingValue);
328
+ if (Array.isArray(parsed)) {
329
+ for (const d of parsed) {
330
+ if (typeof d === 'string' && d.trim()) {
331
+ domains.add(d.trim().toLowerCase());
332
+ }
333
+ }
334
+ }
335
+ }
336
+ catch {
337
+ // Backward-compatible fallback: comma-separated
338
+ for (const d of settingValue.split(',')) {
339
+ if (d.trim())
340
+ domains.add(d.trim().toLowerCase());
341
+ }
342
+ }
343
+ }
344
+ }
345
+ // Layer 3: action-level networkAllowlist (from pmo_actions table)
346
+ if (actionNetworkAllowlist) {
347
+ for (const domain of actionNetworkAllowlist) {
348
+ domains.add(domain.trim().toLowerCase());
349
+ }
350
+ }
351
+ return [...domains].filter(Boolean);
352
+ }
353
+ /**
354
+ * Set the network allowlist for a specific action in workspace_settings.
355
+ */
356
+ export function setActionNetworkAllowlist(db, actionId, domains) {
357
+ const cleaned = [...new Set(domains.map(d => d.trim().toLowerCase()).filter(Boolean))];
358
+ if (cleaned.length === 0) {
359
+ settingsFor(db).delete(`network.actions.${actionId}`);
360
+ }
361
+ else {
362
+ setSetting(db, `network.actions.${actionId}`, JSON.stringify(cleaned));
363
+ }
364
+ }
305
365
  /**
306
366
  * Save terminal app preference
307
367
  */