@askexenow/exe-os 0.9.8 → 0.9.9

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 (101) hide show
  1. package/dist/bin/backfill-conversations.js +222 -49
  2. package/dist/bin/backfill-responses.js +221 -48
  3. package/dist/bin/backfill-vectors.js +225 -52
  4. package/dist/bin/cleanup-stale-review-tasks.js +150 -28
  5. package/dist/bin/cli.js +1295 -856
  6. package/dist/bin/exe-agent-config.js +36 -8
  7. package/dist/bin/exe-agent.js +14 -4
  8. package/dist/bin/exe-assign.js +221 -48
  9. package/dist/bin/exe-boot.js +778 -427
  10. package/dist/bin/exe-call.js +41 -13
  11. package/dist/bin/exe-cloud.js +163 -58
  12. package/dist/bin/exe-dispatch.js +276 -139
  13. package/dist/bin/exe-doctor.js +145 -27
  14. package/dist/bin/exe-export-behaviors.js +141 -23
  15. package/dist/bin/exe-forget.js +137 -19
  16. package/dist/bin/exe-gateway.js +677 -388
  17. package/dist/bin/exe-heartbeat.js +227 -108
  18. package/dist/bin/exe-kill.js +138 -20
  19. package/dist/bin/exe-launch-agent.js +172 -39
  20. package/dist/bin/exe-link.js +291 -100
  21. package/dist/bin/exe-new-employee.js +214 -106
  22. package/dist/bin/exe-pending-messages.js +395 -33
  23. package/dist/bin/exe-pending-notifications.js +684 -99
  24. package/dist/bin/exe-pending-reviews.js +420 -74
  25. package/dist/bin/exe-rename.js +147 -49
  26. package/dist/bin/exe-review.js +138 -20
  27. package/dist/bin/exe-search.js +240 -69
  28. package/dist/bin/exe-session-cleanup.js +440 -250
  29. package/dist/bin/exe-settings.js +61 -17
  30. package/dist/bin/exe-start-codex.js +158 -39
  31. package/dist/bin/exe-start-opencode.js +157 -38
  32. package/dist/bin/exe-status.js +151 -29
  33. package/dist/bin/exe-team.js +138 -20
  34. package/dist/bin/git-sweep.js +404 -212
  35. package/dist/bin/graph-backfill.js +137 -19
  36. package/dist/bin/graph-export.js +140 -22
  37. package/dist/bin/install.js +90 -61
  38. package/dist/bin/scan-tasks.js +412 -220
  39. package/dist/bin/setup.js +564 -293
  40. package/dist/bin/shard-migrate.js +139 -21
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +137 -19
  43. package/dist/gateway/index.js +533 -320
  44. package/dist/hooks/bug-report-worker.js +344 -193
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +402 -210
  47. package/dist/hooks/error-recall.js +245 -74
  48. package/dist/hooks/exe-heartbeat-hook.js +16 -6
  49. package/dist/hooks/ingest-worker.js +3423 -3157
  50. package/dist/hooks/ingest.js +832 -97
  51. package/dist/hooks/instructions-loaded.js +227 -54
  52. package/dist/hooks/notification.js +216 -43
  53. package/dist/hooks/post-compact.js +239 -62
  54. package/dist/hooks/pre-compact.js +408 -216
  55. package/dist/hooks/pre-tool-use.js +268 -90
  56. package/dist/hooks/prompt-ingest-worker.js +352 -102
  57. package/dist/hooks/prompt-submit.js +541 -328
  58. package/dist/hooks/response-ingest-worker.js +372 -122
  59. package/dist/hooks/session-end.js +443 -240
  60. package/dist/hooks/session-start.js +313 -127
  61. package/dist/hooks/stop.js +293 -98
  62. package/dist/hooks/subagent-stop.js +239 -62
  63. package/dist/hooks/summary-worker.js +568 -236
  64. package/dist/index.js +538 -324
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +284 -105
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +16 -6
  69. package/dist/lib/database.js +123 -25
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +123 -25
  72. package/dist/lib/device-registry.js +133 -35
  73. package/dist/lib/embedder.js +107 -32
  74. package/dist/lib/employee-templates.js +14 -4
  75. package/dist/lib/employees.js +41 -13
  76. package/dist/lib/exe-daemon-client.js +88 -22
  77. package/dist/lib/exe-daemon.js +935 -587
  78. package/dist/lib/hybrid-search.js +240 -69
  79. package/dist/lib/identity.js +18 -8
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +116 -56
  82. package/dist/lib/reminders.js +14 -4
  83. package/dist/lib/schedules.js +137 -19
  84. package/dist/lib/skill-learning.js +33 -6
  85. package/dist/lib/store.js +137 -19
  86. package/dist/lib/task-router.js +14 -4
  87. package/dist/lib/tasks.js +280 -234
  88. package/dist/lib/tmux-routing.js +172 -125
  89. package/dist/lib/token-spend.js +26 -8
  90. package/dist/mcp/server.js +1326 -609
  91. package/dist/mcp/tools/complete-reminder.js +14 -4
  92. package/dist/mcp/tools/create-reminder.js +14 -4
  93. package/dist/mcp/tools/create-task.js +306 -248
  94. package/dist/mcp/tools/deactivate-behavior.js +16 -6
  95. package/dist/mcp/tools/list-reminders.js +14 -4
  96. package/dist/mcp/tools/list-tasks.js +123 -107
  97. package/dist/mcp/tools/send-message.js +75 -29
  98. package/dist/mcp/tools/update-task.js +1848 -199
  99. package/dist/runtime/index.js +441 -248
  100. package/dist/tui/App.js +761 -424
  101. package/package.json +1 -1
package/dist/bin/setup.js CHANGED
@@ -15,6 +15,44 @@ var __export = (target, all) => {
15
15
  __defProp(target, name, { get: all[name], enumerable: true });
16
16
  };
17
17
 
18
+ // src/lib/secure-files.ts
19
+ import { chmodSync, existsSync, mkdirSync } from "fs";
20
+ import { chmod, mkdir } from "fs/promises";
21
+ async function ensurePrivateDir(dirPath) {
22
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
23
+ try {
24
+ await chmod(dirPath, PRIVATE_DIR_MODE);
25
+ } catch {
26
+ }
27
+ }
28
+ function ensurePrivateDirSync(dirPath) {
29
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
30
+ try {
31
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
32
+ } catch {
33
+ }
34
+ }
35
+ async function enforcePrivateFile(filePath) {
36
+ try {
37
+ await chmod(filePath, PRIVATE_FILE_MODE);
38
+ } catch {
39
+ }
40
+ }
41
+ function enforcePrivateFileSync(filePath) {
42
+ try {
43
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
44
+ } catch {
45
+ }
46
+ }
47
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
48
+ var init_secure_files = __esm({
49
+ "src/lib/secure-files.ts"() {
50
+ "use strict";
51
+ PRIVATE_DIR_MODE = 448;
52
+ PRIVATE_FILE_MODE = 384;
53
+ }
54
+ });
55
+
18
56
  // src/lib/config.ts
19
57
  var config_exports = {};
20
58
  __export(config_exports, {
@@ -31,8 +69,8 @@ __export(config_exports, {
31
69
  migrateConfig: () => migrateConfig,
32
70
  saveConfig: () => saveConfig
33
71
  });
34
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
35
- import { readFileSync, existsSync, renameSync } from "fs";
72
+ import { readFile, writeFile } from "fs/promises";
73
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
36
74
  import path from "path";
37
75
  import os from "os";
38
76
  function resolveDataDir() {
@@ -40,7 +78,7 @@ function resolveDataDir() {
40
78
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
41
79
  const newDir = path.join(os.homedir(), ".exe-os");
42
80
  const legacyDir = path.join(os.homedir(), ".exe-mem");
43
- if (!existsSync(newDir) && existsSync(legacyDir)) {
81
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
44
82
  try {
45
83
  renameSync(legacyDir, newDir);
46
84
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -103,9 +141,9 @@ function normalizeAutoUpdate(raw) {
103
141
  }
104
142
  async function loadConfig() {
105
143
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
106
- await mkdir(dir, { recursive: true });
144
+ await ensurePrivateDir(dir);
107
145
  const configPath = path.join(dir, "config.json");
108
- if (!existsSync(configPath)) {
146
+ if (!existsSync2(configPath)) {
109
147
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
110
148
  }
111
149
  const raw = await readFile(configPath, "utf-8");
@@ -118,6 +156,7 @@ async function loadConfig() {
118
156
  `);
119
157
  try {
120
158
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
159
+ await enforcePrivateFile(configPath);
121
160
  } catch {
122
161
  }
123
162
  }
@@ -136,7 +175,7 @@ async function loadConfig() {
136
175
  function loadConfigSync() {
137
176
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
138
177
  const configPath = path.join(dir, "config.json");
139
- if (!existsSync(configPath)) {
178
+ if (!existsSync2(configPath)) {
140
179
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
141
180
  }
142
181
  try {
@@ -154,12 +193,10 @@ function loadConfigSync() {
154
193
  }
155
194
  async function saveConfig(config) {
156
195
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
157
- await mkdir(dir, { recursive: true });
196
+ await ensurePrivateDir(dir);
158
197
  const configPath = path.join(dir, "config.json");
159
198
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
160
- if (config.cloud?.apiKey) {
161
- await chmod(configPath, 384);
162
- }
199
+ await enforcePrivateFile(configPath);
163
200
  }
164
201
  async function loadConfigFrom(configPath) {
165
202
  const raw = await readFile(configPath, "utf-8");
@@ -179,6 +216,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
179
216
  var init_config = __esm({
180
217
  "src/lib/config.ts"() {
181
218
  "use strict";
219
+ init_secure_files();
182
220
  EXE_AI_DIR = resolveDataDir();
183
221
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
184
222
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -265,7 +303,7 @@ __export(keychain_exports, {
265
303
  setMasterKey: () => setMasterKey
266
304
  });
267
305
  import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
268
- import { existsSync as existsSync2 } from "fs";
306
+ import { existsSync as existsSync3 } from "fs";
269
307
  import path2 from "path";
270
308
  import os2 from "os";
271
309
  function getKeyDir() {
@@ -293,7 +331,7 @@ async function getMasterKey() {
293
331
  }
294
332
  }
295
333
  const keyPath = getKeyPath();
296
- if (!existsSync2(keyPath)) {
334
+ if (!existsSync3(keyPath)) {
297
335
  process.stderr.write(
298
336
  `[keychain] Key not found at ${keyPath} (HOME=${os2.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
299
337
  `
@@ -336,7 +374,7 @@ async function deleteMasterKey() {
336
374
  }
337
375
  }
338
376
  const keyPath = getKeyPath();
339
- if (existsSync2(keyPath)) {
377
+ if (existsSync3(keyPath)) {
340
378
  await unlink(keyPath);
341
379
  }
342
380
  }
@@ -387,13 +425,50 @@ var init_memory = __esm({
387
425
  }
388
426
  });
389
427
 
428
+ // src/lib/daemon-auth.ts
429
+ import crypto from "crypto";
430
+ import path4 from "path";
431
+ import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync } from "fs";
432
+ function normalizeToken(token) {
433
+ if (!token) return null;
434
+ const trimmed = token.trim();
435
+ return trimmed.length > 0 ? trimmed : null;
436
+ }
437
+ function readDaemonToken() {
438
+ try {
439
+ if (!existsSync5(DAEMON_TOKEN_PATH)) return null;
440
+ return normalizeToken(readFileSync2(DAEMON_TOKEN_PATH, "utf8"));
441
+ } catch {
442
+ return null;
443
+ }
444
+ }
445
+ function ensureDaemonToken(seed) {
446
+ const existing = readDaemonToken();
447
+ if (existing) return existing;
448
+ const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
449
+ ensurePrivateDirSync(EXE_AI_DIR);
450
+ writeFileSync(DAEMON_TOKEN_PATH, `${token}
451
+ `, "utf8");
452
+ enforcePrivateFileSync(DAEMON_TOKEN_PATH);
453
+ return token;
454
+ }
455
+ var DAEMON_TOKEN_PATH;
456
+ var init_daemon_auth = __esm({
457
+ "src/lib/daemon-auth.ts"() {
458
+ "use strict";
459
+ init_config();
460
+ init_secure_files();
461
+ DAEMON_TOKEN_PATH = path4.join(EXE_AI_DIR, "exed.token");
462
+ }
463
+ });
464
+
390
465
  // src/lib/exe-daemon-client.ts
391
466
  import net from "net";
392
467
  import os3 from "os";
393
468
  import { spawn } from "child_process";
394
469
  import { randomUUID } from "crypto";
395
- import { existsSync as existsSync4, unlinkSync as unlinkSync2, readFileSync as readFileSync2, openSync, closeSync, statSync } from "fs";
396
- import path4 from "path";
470
+ import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
471
+ import path5 from "path";
397
472
  import { fileURLToPath } from "url";
398
473
  function handleData(chunk) {
399
474
  _buffer += chunk.toString();
@@ -421,9 +496,9 @@ function handleData(chunk) {
421
496
  }
422
497
  }
423
498
  function cleanupStaleFiles() {
424
- if (existsSync4(PID_PATH)) {
499
+ if (existsSync6(PID_PATH)) {
425
500
  try {
426
- const pid = parseInt(readFileSync2(PID_PATH, "utf8").trim(), 10);
501
+ const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
427
502
  if (pid > 0) {
428
503
  try {
429
504
  process.kill(pid, 0);
@@ -444,11 +519,11 @@ function cleanupStaleFiles() {
444
519
  }
445
520
  }
446
521
  function findPackageRoot() {
447
- let dir = path4.dirname(fileURLToPath(import.meta.url));
448
- const { root } = path4.parse(dir);
522
+ let dir = path5.dirname(fileURLToPath(import.meta.url));
523
+ const { root } = path5.parse(dir);
449
524
  while (dir !== root) {
450
- if (existsSync4(path4.join(dir, "package.json"))) return dir;
451
- dir = path4.dirname(dir);
525
+ if (existsSync6(path5.join(dir, "package.json"))) return dir;
526
+ dir = path5.dirname(dir);
452
527
  }
453
528
  return null;
454
529
  }
@@ -474,16 +549,17 @@ function spawnDaemon() {
474
549
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
475
550
  return;
476
551
  }
477
- const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
478
- if (!existsSync4(daemonPath)) {
552
+ const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
553
+ if (!existsSync6(daemonPath)) {
479
554
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
480
555
  `);
481
556
  return;
482
557
  }
483
558
  const resolvedPath = daemonPath;
559
+ const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
484
560
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
485
561
  `);
486
- const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
562
+ const logPath = path5.join(path5.dirname(SOCKET_PATH), "exed.log");
487
563
  let stderrFd = "ignore";
488
564
  try {
489
565
  stderrFd = openSync(logPath, "a");
@@ -501,7 +577,8 @@ function spawnDaemon() {
501
577
  TMUX_PANE: void 0,
502
578
  // Prevents resolveExeSession() from scoping to one session
503
579
  EXE_DAEMON_SOCK: SOCKET_PATH,
504
- EXE_DAEMON_PID: PID_PATH
580
+ EXE_DAEMON_PID: PID_PATH,
581
+ [DAEMON_TOKEN_ENV]: daemonToken
505
582
  }
506
583
  });
507
584
  child.unref();
@@ -611,13 +688,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
611
688
  return;
612
689
  }
613
690
  const id = randomUUID();
691
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
614
692
  const timer = setTimeout(() => {
615
693
  _pending.delete(id);
616
694
  resolve({ error: "Request timeout" });
617
695
  }, timeoutMs);
618
696
  _pending.set(id, { resolve, timer });
619
697
  try {
620
- _socket.write(JSON.stringify({ id, ...payload }) + "\n");
698
+ _socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
621
699
  } catch {
622
700
  clearTimeout(timer);
623
701
  _pending.delete(id);
@@ -646,9 +724,9 @@ function killAndRespawnDaemon() {
646
724
  }
647
725
  try {
648
726
  process.stderr.write("[exed-client] Killing daemon for restart...\n");
649
- if (existsSync4(PID_PATH)) {
727
+ if (existsSync6(PID_PATH)) {
650
728
  try {
651
- const pid = parseInt(readFileSync2(PID_PATH, "utf8").trim(), 10);
729
+ const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
652
730
  if (pid > 0) {
653
731
  try {
654
732
  process.kill(pid, "SIGKILL");
@@ -768,17 +846,19 @@ function disconnectClient() {
768
846
  function isClientConnected() {
769
847
  return _connected;
770
848
  }
771
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
849
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
772
850
  var init_exe_daemon_client = __esm({
773
851
  "src/lib/exe-daemon-client.ts"() {
774
852
  "use strict";
775
853
  init_config();
776
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
777
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
778
- SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
854
+ init_daemon_auth();
855
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
856
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
857
+ SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
779
858
  SPAWN_LOCK_STALE_MS = 3e4;
780
859
  CONNECT_TIMEOUT_MS = 15e3;
781
860
  REQUEST_TIMEOUT_MS = 3e4;
861
+ DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
782
862
  _socket = null;
783
863
  _connected = false;
784
864
  _buffer = "";
@@ -830,10 +910,10 @@ async function disposeEmbedder() {
830
910
  async function embedDirect(text) {
831
911
  const llamaCpp = await import("node-llama-cpp");
832
912
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
833
- const { existsSync: existsSync14 } = await import("fs");
834
- const path15 = await import("path");
835
- const modelPath = path15.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
836
- if (!existsSync14(modelPath)) {
913
+ const { existsSync: existsSync16 } = await import("fs");
914
+ const path16 = await import("path");
915
+ const modelPath = path16.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
916
+ if (!existsSync16(modelPath)) {
837
917
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
838
918
  }
839
919
  const llama = await llamaCpp.getLlama();
@@ -878,9 +958,12 @@ __export(license_exports, {
878
958
  stopLicenseRevalidation: () => stopLicenseRevalidation,
879
959
  validateLicense: () => validateLicense
880
960
  });
881
- import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync5, mkdirSync } from "fs";
961
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
882
962
  import { randomUUID as randomUUID2 } from "crypto";
883
- import path5 from "path";
963
+ import { createRequire } from "module";
964
+ import { pathToFileURL } from "url";
965
+ import os4 from "os";
966
+ import path6 from "path";
884
967
  import { jwtVerify, importSPKI } from "jose";
885
968
  async function fetchRetry(url, init) {
886
969
  try {
@@ -891,37 +974,37 @@ async function fetchRetry(url, init) {
891
974
  }
892
975
  }
893
976
  function loadDeviceId() {
894
- const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
977
+ const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
895
978
  try {
896
- if (existsSync5(deviceJsonPath)) {
897
- const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
979
+ if (existsSync7(deviceJsonPath)) {
980
+ const data = JSON.parse(readFileSync4(deviceJsonPath, "utf8"));
898
981
  if (data.deviceId) return data.deviceId;
899
982
  }
900
983
  } catch {
901
984
  }
902
985
  try {
903
- if (existsSync5(DEVICE_ID_PATH)) {
904
- const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
986
+ if (existsSync7(DEVICE_ID_PATH)) {
987
+ const id2 = readFileSync4(DEVICE_ID_PATH, "utf8").trim();
905
988
  if (id2) return id2;
906
989
  }
907
990
  } catch {
908
991
  }
909
992
  const id = randomUUID2();
910
- mkdirSync(EXE_AI_DIR, { recursive: true });
911
- writeFileSync(DEVICE_ID_PATH, id, "utf8");
993
+ mkdirSync2(EXE_AI_DIR, { recursive: true });
994
+ writeFileSync2(DEVICE_ID_PATH, id, "utf8");
912
995
  return id;
913
996
  }
914
997
  function loadLicense() {
915
998
  try {
916
- if (!existsSync5(LICENSE_PATH)) return null;
917
- return readFileSync3(LICENSE_PATH, "utf8").trim();
999
+ if (!existsSync7(LICENSE_PATH)) return null;
1000
+ return readFileSync4(LICENSE_PATH, "utf8").trim();
918
1001
  } catch {
919
1002
  return null;
920
1003
  }
921
1004
  }
922
1005
  function saveLicense(apiKey) {
923
- mkdirSync(EXE_AI_DIR, { recursive: true });
924
- writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
1006
+ mkdirSync2(EXE_AI_DIR, { recursive: true });
1007
+ writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
925
1008
  }
926
1009
  async function verifyLicenseJwt(token) {
927
1010
  try {
@@ -947,8 +1030,8 @@ async function verifyLicenseJwt(token) {
947
1030
  }
948
1031
  async function getCachedLicense() {
949
1032
  try {
950
- if (!existsSync5(CACHE_PATH)) return null;
951
- const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
1033
+ if (!existsSync7(CACHE_PATH)) return null;
1034
+ const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
952
1035
  if (!raw.token || typeof raw.token !== "string") return null;
953
1036
  return await verifyLicenseJwt(raw.token);
954
1037
  } catch {
@@ -957,8 +1040,8 @@ async function getCachedLicense() {
957
1040
  }
958
1041
  function readCachedToken() {
959
1042
  try {
960
- if (!existsSync5(CACHE_PATH)) return null;
961
- const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
1043
+ if (!existsSync7(CACHE_PATH)) return null;
1044
+ const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
962
1045
  return typeof raw.token === "string" ? raw.token : null;
963
1046
  } catch {
964
1047
  return null;
@@ -992,56 +1075,130 @@ function getRawCachedPlan() {
992
1075
  }
993
1076
  function cacheResponse(token) {
994
1077
  try {
995
- writeFileSync(CACHE_PATH, JSON.stringify({ token }), "utf8");
1078
+ writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
996
1079
  } catch {
997
1080
  }
998
1081
  }
999
- async function validateLicense(apiKey, deviceId) {
1000
- const did = deviceId ?? loadDeviceId();
1082
+ function loadPrismaForLicense() {
1083
+ if (_prismaFailed) return null;
1084
+ const dbUrl = process.env.DATABASE_URL;
1085
+ if (!dbUrl) {
1086
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path6.join(os4.homedir(), "exe-db");
1087
+ if (!existsSync7(path6.join(exeDbRoot, "package.json"))) {
1088
+ _prismaFailed = true;
1089
+ return null;
1090
+ }
1091
+ }
1092
+ if (!_prismaPromise) {
1093
+ _prismaPromise = (async () => {
1094
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
1095
+ if (explicitPath) {
1096
+ const mod2 = await import(pathToFileURL(explicitPath).href);
1097
+ const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
1098
+ if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
1099
+ return new Ctor2();
1100
+ }
1101
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path6.join(os4.homedir(), "exe-db");
1102
+ const req = createRequire(path6.join(exeDbRoot, "package.json"));
1103
+ const entry = req.resolve("@prisma/client");
1104
+ const mod = await import(pathToFileURL(entry).href);
1105
+ const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
1106
+ if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
1107
+ return new Ctor();
1108
+ })().catch((err) => {
1109
+ _prismaFailed = true;
1110
+ _prismaPromise = null;
1111
+ throw err;
1112
+ });
1113
+ }
1114
+ return _prismaPromise;
1115
+ }
1116
+ async function validateViaPostgres(apiKey) {
1117
+ const loader = loadPrismaForLicense();
1118
+ if (!loader) return null;
1119
+ try {
1120
+ const prisma = await loader;
1121
+ const rows = await prisma.$queryRawUnsafe(
1122
+ `SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
1123
+ FROM billing.licenses WHERE key = $1 LIMIT 1`,
1124
+ apiKey
1125
+ );
1126
+ if (!rows || rows.length === 0) return null;
1127
+ const row = rows[0];
1128
+ if (row.status !== "active") return null;
1129
+ if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
1130
+ const plan = row.plan;
1131
+ const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
1132
+ return {
1133
+ valid: true,
1134
+ plan,
1135
+ email: row.email,
1136
+ expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
1137
+ deviceLimit: row.device_limit ?? limits.devices,
1138
+ employeeLimit: row.employee_limit ?? limits.employees,
1139
+ memoryLimit: row.memory_limit ?? limits.memories
1140
+ };
1141
+ } catch {
1142
+ return null;
1143
+ }
1144
+ }
1145
+ async function validateViaCFWorker(apiKey, deviceId) {
1001
1146
  try {
1002
1147
  const res = await fetchRetry(`${API_BASE}/auth/activate`, {
1003
1148
  method: "POST",
1004
1149
  headers: { "Content-Type": "application/json" },
1005
- body: JSON.stringify({ apiKey, deviceId: did }),
1150
+ body: JSON.stringify({ apiKey, deviceId }),
1006
1151
  signal: AbortSignal.timeout(1e4)
1007
1152
  });
1008
- if (res.ok) {
1009
- const data = await res.json();
1010
- if (data.error === "device_limit_exceeded") {
1011
- const cached2 = await getCachedLicense();
1012
- if (cached2) return cached2;
1013
- const raw2 = getRawCachedPlan();
1014
- if (raw2) return { ...raw2, valid: false };
1015
- return { ...FREE_LICENSE, valid: false, plan: "free" };
1016
- }
1017
- if (data.token) {
1018
- cacheResponse(data.token);
1019
- const verified = await verifyLicenseJwt(data.token);
1020
- if (verified) return verified;
1153
+ if (!res.ok) return null;
1154
+ const data = await res.json();
1155
+ if (data.error === "device_limit_exceeded") return null;
1156
+ if (!data.valid) return null;
1157
+ if (data.token) {
1158
+ cacheResponse(data.token);
1159
+ const verified = await verifyLicenseJwt(data.token);
1160
+ if (verified) return verified;
1161
+ }
1162
+ const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
1163
+ return {
1164
+ valid: data.valid,
1165
+ plan: data.plan,
1166
+ email: data.email,
1167
+ expiresAt: data.expiresAt,
1168
+ deviceLimit: limits.devices,
1169
+ employeeLimit: limits.employees,
1170
+ memoryLimit: limits.memories
1171
+ };
1172
+ } catch {
1173
+ return null;
1174
+ }
1175
+ }
1176
+ async function validateLicense(apiKey, deviceId) {
1177
+ const did = deviceId ?? loadDeviceId();
1178
+ const pgResult = await validateViaPostgres(apiKey);
1179
+ if (pgResult) {
1180
+ try {
1181
+ writeFileSync2(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
1182
+ } catch {
1183
+ }
1184
+ return pgResult;
1185
+ }
1186
+ const cfResult = await validateViaCFWorker(apiKey, did);
1187
+ if (cfResult) return cfResult;
1188
+ const cached = await getCachedLicense();
1189
+ if (cached) return cached;
1190
+ try {
1191
+ if (existsSync7(CACHE_PATH)) {
1192
+ const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
1193
+ if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
1194
+ return raw.pgLicense;
1021
1195
  }
1022
- const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
1023
- return {
1024
- valid: data.valid,
1025
- plan: data.plan,
1026
- email: data.email,
1027
- expiresAt: data.expiresAt,
1028
- deviceLimit: limits.devices,
1029
- employeeLimit: limits.employees,
1030
- memoryLimit: limits.memories
1031
- };
1032
1196
  }
1033
- const cached = await getCachedLicense();
1034
- if (cached) return cached;
1035
- const raw = getRawCachedPlan();
1036
- if (raw) return raw;
1037
- return { ...FREE_LICENSE, valid: false, plan: "free" };
1038
1197
  } catch {
1039
- const cached = await getCachedLicense();
1040
- if (cached) return cached;
1041
- const rawFallback = getRawCachedPlan();
1042
- if (rawFallback) return rawFallback;
1043
- return { ...FREE_LICENSE, valid: false, error: "offline" };
1044
1198
  }
1199
+ const rawFallback = getRawCachedPlan();
1200
+ if (rawFallback) return rawFallback;
1201
+ return { ...FREE_LICENSE, valid: false };
1045
1202
  }
1046
1203
  function getCacheAgeMs() {
1047
1204
  try {
@@ -1056,9 +1213,9 @@ async function checkLicense() {
1056
1213
  let key = loadLicense();
1057
1214
  if (!key) {
1058
1215
  try {
1059
- const configPath = path5.join(EXE_AI_DIR, "config.json");
1060
- if (existsSync5(configPath)) {
1061
- const raw = JSON.parse(readFileSync3(configPath, "utf8"));
1216
+ const configPath = path6.join(EXE_AI_DIR, "config.json");
1217
+ if (existsSync7(configPath)) {
1218
+ const raw = JSON.parse(readFileSync4(configPath, "utf8"));
1062
1219
  const cloud = raw.cloud;
1063
1220
  if (cloud?.apiKey) {
1064
1221
  key = cloud.apiKey;
@@ -1212,14 +1369,14 @@ function stopLicenseRevalidation() {
1212
1369
  _revalTimer = null;
1213
1370
  }
1214
1371
  }
1215
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
1372
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, _prismaPromise, _prismaFailed, CACHE_MAX_AGE_MS, _revalTimer;
1216
1373
  var init_license = __esm({
1217
1374
  "src/lib/license.ts"() {
1218
1375
  "use strict";
1219
1376
  init_config();
1220
- LICENSE_PATH = path5.join(EXE_AI_DIR, "license.key");
1221
- CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
1222
- DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
1377
+ LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
1378
+ CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
1379
+ DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
1223
1380
  API_BASE = "https://askexe.com/cloud";
1224
1381
  RETRY_DELAY_MS = 500;
1225
1382
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -1243,6 +1400,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
1243
1400
  employeeLimit: 1,
1244
1401
  memoryLimit: 5e3
1245
1402
  };
1403
+ _prismaPromise = null;
1404
+ _prismaFailed = false;
1246
1405
  CACHE_MAX_AGE_MS = 36e5;
1247
1406
  _revalTimer = null;
1248
1407
  }
@@ -1256,13 +1415,13 @@ __export(crypto_exports, {
1256
1415
  initSyncCrypto: () => initSyncCrypto,
1257
1416
  isSyncCryptoInitialized: () => isSyncCryptoInitialized
1258
1417
  });
1259
- import crypto from "crypto";
1418
+ import crypto2 from "crypto";
1260
1419
  function initSyncCrypto(masterKey) {
1261
1420
  if (masterKey.length !== 32) {
1262
1421
  throw new Error(`Master key must be 32 bytes, got ${masterKey.length}`);
1263
1422
  }
1264
1423
  _syncKey = Buffer.from(
1265
- crypto.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
1424
+ crypto2.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
1266
1425
  );
1267
1426
  }
1268
1427
  function isSyncCryptoInitialized() {
@@ -1276,8 +1435,8 @@ function requireSyncKey() {
1276
1435
  }
1277
1436
  function encryptSyncBlob(data) {
1278
1437
  const key = requireSyncKey();
1279
- const iv = crypto.randomBytes(IV_LENGTH);
1280
- const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
1438
+ const iv = crypto2.randomBytes(IV_LENGTH);
1439
+ const cipher = crypto2.createCipheriv(ALGORITHM, key, iv);
1281
1440
  const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
1282
1441
  const tag = cipher.getAuthTag();
1283
1442
  return Buffer.concat([iv, encrypted, tag]).toString("base64");
@@ -1291,7 +1450,7 @@ function decryptSyncBlob(ciphertext) {
1291
1450
  const iv = combined.subarray(0, IV_LENGTH);
1292
1451
  const tag = combined.subarray(combined.length - TAG_LENGTH);
1293
1452
  const encrypted = combined.subarray(IV_LENGTH, combined.length - TAG_LENGTH);
1294
- const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
1453
+ const decipher = crypto2.createDecipheriv(ALGORITHM, key, iv);
1295
1454
  decipher.setAuthTag(tag);
1296
1455
  return Buffer.concat([decipher.update(encrypted), decipher.final()]);
1297
1456
  }
@@ -1402,20 +1561,21 @@ __export(agent_config_exports, {
1402
1561
  saveAgentConfig: () => saveAgentConfig,
1403
1562
  setAgentRuntime: () => setAgentRuntime
1404
1563
  });
1405
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1406
- import path6 from "path";
1564
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync8 } from "fs";
1565
+ import path7 from "path";
1407
1566
  function loadAgentConfig() {
1408
- if (!existsSync6(AGENT_CONFIG_PATH)) return {};
1567
+ if (!existsSync8(AGENT_CONFIG_PATH)) return {};
1409
1568
  try {
1410
- return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf-8"));
1569
+ return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
1411
1570
  } catch {
1412
1571
  return {};
1413
1572
  }
1414
1573
  }
1415
1574
  function saveAgentConfig(config) {
1416
- const dir = path6.dirname(AGENT_CONFIG_PATH);
1417
- if (!existsSync6(dir)) mkdirSync2(dir, { recursive: true });
1418
- writeFileSync2(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
1575
+ const dir = path7.dirname(AGENT_CONFIG_PATH);
1576
+ ensurePrivateDirSync(dir);
1577
+ writeFileSync3(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
1578
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
1419
1579
  }
1420
1580
  function getAgentRuntime(agentId) {
1421
1581
  const config = loadAgentConfig();
@@ -1455,7 +1615,8 @@ var init_agent_config = __esm({
1455
1615
  "use strict";
1456
1616
  init_config();
1457
1617
  init_runtime_table();
1458
- AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
1618
+ init_secure_files();
1619
+ AGENT_CONFIG_PATH = path7.join(EXE_AI_DIR, "agent-config.json");
1459
1620
  KNOWN_RUNTIMES = {
1460
1621
  claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
1461
1622
  codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
@@ -1502,10 +1663,10 @@ __export(employees_exports, {
1502
1663
  validateEmployeeName: () => validateEmployeeName
1503
1664
  });
1504
1665
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
1505
- import { existsSync as existsSync7, symlinkSync, readlinkSync, readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
1666
+ import { existsSync as existsSync9, symlinkSync, readlinkSync, readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
1506
1667
  import { execSync } from "child_process";
1507
- import path7 from "path";
1508
- import os4 from "os";
1668
+ import path8 from "path";
1669
+ import os5 from "os";
1509
1670
  function normalizeRole(role) {
1510
1671
  return (role ?? "").trim().toLowerCase();
1511
1672
  }
@@ -1541,7 +1702,7 @@ function validateEmployeeName(name) {
1541
1702
  return { valid: true };
1542
1703
  }
1543
1704
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
1544
- if (!existsSync7(employeesPath)) {
1705
+ if (!existsSync9(employeesPath)) {
1545
1706
  return [];
1546
1707
  }
1547
1708
  const raw = await readFile3(employeesPath, "utf-8");
@@ -1552,13 +1713,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
1552
1713
  }
1553
1714
  }
1554
1715
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
1555
- await mkdir4(path7.dirname(employeesPath), { recursive: true });
1716
+ await mkdir4(path8.dirname(employeesPath), { recursive: true });
1556
1717
  await writeFile3(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
1557
1718
  }
1558
1719
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
1559
- if (!existsSync7(employeesPath)) return [];
1720
+ if (!existsSync9(employeesPath)) return [];
1560
1721
  try {
1561
- return JSON.parse(readFileSync5(employeesPath, "utf-8"));
1722
+ return JSON.parse(readFileSync6(employeesPath, "utf-8"));
1562
1723
  } catch {
1563
1724
  return [];
1564
1725
  }
@@ -1603,9 +1764,9 @@ function addEmployee(employees, employee) {
1603
1764
  function appendToCoordinatorTeam(employee) {
1604
1765
  const coordinator = getCoordinatorEmployee(loadEmployeesSync());
1605
1766
  if (!coordinator) return;
1606
- const idPath = path7.join(IDENTITY_DIR, `${coordinator.name}.md`);
1607
- if (!existsSync7(idPath)) return;
1608
- const content = readFileSync5(idPath, "utf-8");
1767
+ const idPath = path8.join(IDENTITY_DIR, `${coordinator.name}.md`);
1768
+ if (!existsSync9(idPath)) return;
1769
+ const content = readFileSync6(idPath, "utf-8");
1609
1770
  if (content.includes(`**${capitalize(employee.name)}`)) return;
1610
1771
  const teamMatch = content.match(TEAM_SECTION_RE);
1611
1772
  if (!teamMatch || teamMatch.index === void 0) return;
@@ -1621,7 +1782,7 @@ function appendToCoordinatorTeam(employee) {
1621
1782
  } else {
1622
1783
  updated = content.trimEnd() + "\n" + entry;
1623
1784
  }
1624
- writeFileSync3(idPath, updated, "utf-8");
1785
+ writeFileSync4(idPath, updated, "utf-8");
1625
1786
  }
1626
1787
  function capitalize(s) {
1627
1788
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -1655,14 +1816,14 @@ async function normalizeRosterCase(rosterPath) {
1655
1816
  emp.name = emp.name.toLowerCase();
1656
1817
  changed = true;
1657
1818
  try {
1658
- const identityDir = path7.join(os4.homedir(), ".exe-os", "identity");
1659
- const oldPath = path7.join(identityDir, `${oldName}.md`);
1660
- const newPath = path7.join(identityDir, `${emp.name}.md`);
1661
- if (existsSync7(oldPath) && !existsSync7(newPath)) {
1819
+ const identityDir = path8.join(os5.homedir(), ".exe-os", "identity");
1820
+ const oldPath = path8.join(identityDir, `${oldName}.md`);
1821
+ const newPath = path8.join(identityDir, `${emp.name}.md`);
1822
+ if (existsSync9(oldPath) && !existsSync9(newPath)) {
1662
1823
  renameSync3(oldPath, newPath);
1663
- } else if (existsSync7(oldPath) && oldPath !== newPath) {
1664
- const content = readFileSync5(oldPath, "utf-8");
1665
- writeFileSync3(newPath, content, "utf-8");
1824
+ } else if (existsSync9(oldPath) && oldPath !== newPath) {
1825
+ const content = readFileSync6(oldPath, "utf-8");
1826
+ writeFileSync4(newPath, content, "utf-8");
1666
1827
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
1667
1828
  unlinkSync3(oldPath);
1668
1829
  }
@@ -1692,7 +1853,7 @@ function registerBinSymlinks(name) {
1692
1853
  errors.push("Could not find 'exe-os' in PATH");
1693
1854
  return { created, skipped, errors };
1694
1855
  }
1695
- const binDir = path7.dirname(exeBinPath);
1856
+ const binDir = path8.dirname(exeBinPath);
1696
1857
  let target;
1697
1858
  try {
1698
1859
  target = readlinkSync(exeBinPath);
@@ -1702,8 +1863,8 @@ function registerBinSymlinks(name) {
1702
1863
  }
1703
1864
  for (const suffix of ["", "-opencode"]) {
1704
1865
  const linkName = `${name}${suffix}`;
1705
- const linkPath = path7.join(binDir, linkName);
1706
- if (existsSync7(linkPath)) {
1866
+ const linkPath = path8.join(binDir, linkName);
1867
+ if (existsSync9(linkPath)) {
1707
1868
  skipped.push(linkName);
1708
1869
  continue;
1709
1870
  }
@@ -1721,20 +1882,20 @@ var init_employees = __esm({
1721
1882
  "src/lib/employees.ts"() {
1722
1883
  "use strict";
1723
1884
  init_config();
1724
- EMPLOYEES_PATH = path7.join(EXE_AI_DIR, "exe-employees.json");
1885
+ EMPLOYEES_PATH = path8.join(EXE_AI_DIR, "exe-employees.json");
1725
1886
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
1726
1887
  COORDINATOR_ROLE = "COO";
1727
1888
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
1728
- IDENTITY_DIR = path7.join(EXE_AI_DIR, "identity");
1889
+ IDENTITY_DIR = path8.join(EXE_AI_DIR, "identity");
1729
1890
  TEAM_SECTION_RE = /^## Team\b.*$/m;
1730
1891
  }
1731
1892
  });
1732
1893
 
1733
1894
  // src/lib/database-adapter.ts
1734
- import os5 from "os";
1735
- import path8 from "path";
1736
- import { createRequire } from "module";
1737
- import { pathToFileURL } from "url";
1895
+ import os6 from "os";
1896
+ import path9 from "path";
1897
+ import { createRequire as createRequire2 } from "module";
1898
+ import { pathToFileURL as pathToFileURL2 } from "url";
1738
1899
  function quotedIdentifier(identifier) {
1739
1900
  return `"${identifier.replace(/"/g, '""')}"`;
1740
1901
  }
@@ -2036,17 +2197,17 @@ async function loadPrismaClient() {
2036
2197
  prismaClientPromise = (async () => {
2037
2198
  const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
2038
2199
  if (explicitPath) {
2039
- const module2 = await import(pathToFileURL(explicitPath).href);
2200
+ const module2 = await import(pathToFileURL2(explicitPath).href);
2040
2201
  const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
2041
2202
  if (!PrismaClient2) {
2042
2203
  throw new Error(`No PrismaClient export found at ${explicitPath}`);
2043
2204
  }
2044
2205
  return new PrismaClient2();
2045
2206
  }
2046
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path8.join(os5.homedir(), "exe-db");
2047
- const requireFromExeDb = createRequire(path8.join(exeDbRoot, "package.json"));
2207
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path9.join(os6.homedir(), "exe-db");
2208
+ const requireFromExeDb = createRequire2(path9.join(exeDbRoot, "package.json"));
2048
2209
  const prismaEntry = requireFromExeDb.resolve("@prisma/client");
2049
- const module = await import(pathToFileURL(prismaEntry).href);
2210
+ const module = await import(pathToFileURL2(prismaEntry).href);
2050
2211
  const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
2051
2212
  if (!PrismaClient) {
2052
2213
  throw new Error(`No PrismaClient export found in ${prismaEntry}`);
@@ -2884,6 +3045,7 @@ async function ensureSchema() {
2884
3045
  project TEXT NOT NULL,
2885
3046
  summary TEXT NOT NULL,
2886
3047
  task_file TEXT,
3048
+ session_scope TEXT,
2887
3049
  read INTEGER NOT NULL DEFAULT 0,
2888
3050
  created_at TEXT NOT NULL
2889
3051
  );
@@ -2892,7 +3054,7 @@ async function ensureSchema() {
2892
3054
  ON notifications(read);
2893
3055
 
2894
3056
  CREATE INDEX IF NOT EXISTS idx_notifications_agent
2895
- ON notifications(agent_id);
3057
+ ON notifications(agent_id, session_scope);
2896
3058
 
2897
3059
  CREATE INDEX IF NOT EXISTS idx_notifications_task_file
2898
3060
  ON notifications(task_file);
@@ -2930,6 +3092,7 @@ async function ensureSchema() {
2930
3092
  target_agent TEXT NOT NULL,
2931
3093
  target_project TEXT,
2932
3094
  target_device TEXT NOT NULL DEFAULT 'local',
3095
+ session_scope TEXT,
2933
3096
  content TEXT NOT NULL,
2934
3097
  priority TEXT DEFAULT 'normal',
2935
3098
  status TEXT DEFAULT 'pending',
@@ -2943,10 +3106,31 @@ async function ensureSchema() {
2943
3106
  );
2944
3107
 
2945
3108
  CREATE INDEX IF NOT EXISTS idx_messages_target
2946
- ON messages(target_agent, status);
3109
+ ON messages(target_agent, session_scope, status);
2947
3110
 
2948
3111
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
2949
- ON messages(target_agent, from_agent, server_seq);
3112
+ ON messages(target_agent, session_scope, from_agent, server_seq);
3113
+ `);
3114
+ try {
3115
+ await client.execute({
3116
+ sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
3117
+ args: []
3118
+ });
3119
+ } catch {
3120
+ }
3121
+ try {
3122
+ await client.execute({
3123
+ sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
3124
+ args: []
3125
+ });
3126
+ } catch {
3127
+ }
3128
+ await client.executeMultiple(`
3129
+ CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
3130
+ ON notifications(agent_id, session_scope, read, created_at);
3131
+
3132
+ CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
3133
+ ON messages(target_agent, session_scope, status, created_at);
2950
3134
  `);
2951
3135
  try {
2952
3136
  await client.execute({
@@ -3530,6 +3714,13 @@ async function ensureSchema() {
3530
3714
  } catch {
3531
3715
  }
3532
3716
  }
3717
+ try {
3718
+ await client.execute({
3719
+ sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3720
+ args: []
3721
+ });
3722
+ } catch {
3723
+ }
3533
3724
  }
3534
3725
  async function disposeDatabase() {
3535
3726
  if (_walCheckpointTimer) {
@@ -3606,8 +3797,8 @@ __export(crdt_sync_exports, {
3606
3797
  rebuildFromDb: () => rebuildFromDb
3607
3798
  });
3608
3799
  import * as Y from "yjs";
3609
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync3, unlinkSync as unlinkSync4 } from "fs";
3610
- import path9 from "path";
3800
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10, mkdirSync as mkdirSync3, unlinkSync as unlinkSync4 } from "fs";
3801
+ import path10 from "path";
3611
3802
  import { homedir } from "os";
3612
3803
  function getStatePath() {
3613
3804
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -3619,9 +3810,9 @@ function initCrdtDoc() {
3619
3810
  if (doc) return doc;
3620
3811
  doc = new Y.Doc();
3621
3812
  const sp = getStatePath();
3622
- if (existsSync8(sp)) {
3813
+ if (existsSync10(sp)) {
3623
3814
  try {
3624
- const state = readFileSync6(sp);
3815
+ const state = readFileSync7(sp);
3625
3816
  Y.applyUpdate(doc, new Uint8Array(state));
3626
3817
  } catch {
3627
3818
  console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
@@ -3763,10 +3954,10 @@ function persistState() {
3763
3954
  if (!doc) return;
3764
3955
  try {
3765
3956
  const sp = getStatePath();
3766
- const dir = path9.dirname(sp);
3767
- if (!existsSync8(dir)) mkdirSync3(dir, { recursive: true });
3957
+ const dir = path10.dirname(sp);
3958
+ if (!existsSync10(dir)) mkdirSync3(dir, { recursive: true });
3768
3959
  const state = Y.encodeStateAsUpdate(doc);
3769
- writeFileSync4(sp, Buffer.from(state));
3960
+ writeFileSync5(sp, Buffer.from(state));
3770
3961
  } catch {
3771
3962
  }
3772
3963
  }
@@ -3807,7 +3998,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
3807
3998
  var init_crdt_sync = __esm({
3808
3999
  "src/lib/crdt-sync.ts"() {
3809
4000
  "use strict";
3810
- DEFAULT_STATE_PATH = path9.join(homedir(), ".exe-os", "crdt-state.bin");
4001
+ DEFAULT_STATE_PATH = path10.join(homedir(), ".exe-os", "crdt-state.bin");
3811
4002
  _statePathOverride = null;
3812
4003
  doc = null;
3813
4004
  }
@@ -3839,39 +4030,107 @@ __export(cloud_sync_exports, {
3839
4030
  cloudSync: () => cloudSync,
3840
4031
  mergeConfig: () => mergeConfig,
3841
4032
  mergeRosterFromRemote: () => mergeRosterFromRemote,
4033
+ pushToPostgres: () => pushToPostgres,
3842
4034
  recordRosterDeletion: () => recordRosterDeletion
3843
4035
  });
3844
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, readdirSync, mkdirSync as mkdirSync4, appendFileSync, unlinkSync as unlinkSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
3845
- import crypto2 from "crypto";
3846
- import path10 from "path";
4036
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync11, readdirSync, mkdirSync as mkdirSync4, appendFileSync, unlinkSync as unlinkSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
4037
+ import crypto3 from "crypto";
4038
+ import path11 from "path";
3847
4039
  import { homedir as homedir2 } from "os";
3848
4040
  function sqlSafe(v) {
3849
4041
  return v === void 0 ? null : v;
3850
4042
  }
3851
4043
  function logError(msg) {
3852
4044
  try {
3853
- const logPath = path10.join(homedir2(), ".exe-os", "workers.log");
4045
+ const logPath = path11.join(homedir2(), ".exe-os", "workers.log");
3854
4046
  appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
3855
4047
  `);
3856
4048
  } catch {
3857
4049
  }
3858
4050
  }
4051
+ function loadPgClient() {
4052
+ if (_pgFailed) return null;
4053
+ const postgresUrl = process.env.DATABASE_URL;
4054
+ const configPath = path11.join(EXE_AI_DIR, "config.json");
4055
+ let cloudPostgresUrl;
4056
+ try {
4057
+ if (existsSync11(configPath)) {
4058
+ const cfg = JSON.parse(readFileSync8(configPath, "utf8"));
4059
+ cloudPostgresUrl = cfg.cloud?.postgresUrl;
4060
+ if (cfg.cloud?.syncToPostgres === false) {
4061
+ _pgFailed = true;
4062
+ return null;
4063
+ }
4064
+ }
4065
+ } catch {
4066
+ }
4067
+ const url = postgresUrl || cloudPostgresUrl;
4068
+ if (!url) {
4069
+ _pgFailed = true;
4070
+ return null;
4071
+ }
4072
+ if (!_pgPromise) {
4073
+ _pgPromise = (async () => {
4074
+ const { createRequire: createRequire3 } = await import("module");
4075
+ const { pathToFileURL: pathToFileURL3 } = await import("url");
4076
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path11.join(homedir2(), "exe-db");
4077
+ const req = createRequire3(path11.join(exeDbRoot, "package.json"));
4078
+ const entry = req.resolve("@prisma/client");
4079
+ const mod = await import(pathToFileURL3(entry).href);
4080
+ const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
4081
+ if (!Ctor) throw new Error("No PrismaClient");
4082
+ return new Ctor();
4083
+ })().catch(() => {
4084
+ _pgFailed = true;
4085
+ _pgPromise = null;
4086
+ throw new Error("pg_unavailable");
4087
+ });
4088
+ }
4089
+ return _pgPromise;
4090
+ }
4091
+ async function pushToPostgres(records) {
4092
+ const loader = loadPgClient();
4093
+ if (!loader) return 0;
4094
+ let prisma;
4095
+ try {
4096
+ prisma = await loader;
4097
+ } catch {
4098
+ return 0;
4099
+ }
4100
+ let inserted = 0;
4101
+ for (const rec of records) {
4102
+ try {
4103
+ await prisma.$executeRawUnsafe(
4104
+ `INSERT INTO raw.raw_events (id, source, source_id, event_type, payload, metadata, timestamp)
4105
+ VALUES (gen_random_uuid(), 'cloud_sync', $1, 'memory', $2::jsonb, $3::jsonb, $4)
4106
+ ON CONFLICT (source, source_id, event_type) DO NOTHING`,
4107
+ String(rec.id ?? ""),
4108
+ JSON.stringify(rec),
4109
+ JSON.stringify({ agent_id: rec.agent_id, project_name: rec.project_name, tool_name: rec.tool_name }),
4110
+ rec.timestamp ? new Date(String(rec.timestamp)) : /* @__PURE__ */ new Date()
4111
+ );
4112
+ inserted++;
4113
+ } catch {
4114
+ }
4115
+ }
4116
+ return inserted;
4117
+ }
3859
4118
  async function withRosterLock(fn) {
3860
4119
  try {
3861
4120
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
3862
4121
  closeSync2(fd);
3863
- writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
4122
+ writeFileSync6(ROSTER_LOCK_PATH, String(Date.now()));
3864
4123
  } catch (err) {
3865
4124
  if (err.code === "EEXIST") {
3866
4125
  try {
3867
- const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
4126
+ const ts = parseInt(readFileSync8(ROSTER_LOCK_PATH, "utf-8"), 10);
3868
4127
  if (Date.now() - ts < LOCK_STALE_MS) {
3869
4128
  throw new Error("Roster merge already in progress \u2014 another sync is running");
3870
4129
  }
3871
4130
  unlinkSync5(ROSTER_LOCK_PATH);
3872
4131
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
3873
4132
  closeSync2(fd);
3874
- writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
4133
+ writeFileSync6(ROSTER_LOCK_PATH, String(Date.now()));
3875
4134
  } catch (retryErr) {
3876
4135
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
3877
4136
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -4141,6 +4400,10 @@ async function cloudSync(config) {
4141
4400
  const maxVersion = Number(records[records.length - 1].version);
4142
4401
  const pushOk = await cloudPush(records, maxVersion, config);
4143
4402
  if (!pushOk) break;
4403
+ try {
4404
+ await pushToPostgres(records);
4405
+ } catch {
4406
+ }
4144
4407
  await client.execute({
4145
4408
  sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
4146
4409
  args: [String(maxVersion)]
@@ -4245,8 +4508,8 @@ async function cloudSync(config) {
4245
4508
  try {
4246
4509
  const employees = await loadEmployees();
4247
4510
  rosterResult.employees = employees.length;
4248
- const idDir = path10.join(EXE_AI_DIR, "identity");
4249
- if (existsSync9(idDir)) {
4511
+ const idDir = path11.join(EXE_AI_DIR, "identity");
4512
+ if (existsSync11(idDir)) {
4250
4513
  rosterResult.identities = readdirSync(idDir).filter((f) => f.endsWith(".md")).length;
4251
4514
  }
4252
4515
  } catch {
@@ -4267,62 +4530,62 @@ async function cloudSync(config) {
4267
4530
  function recordRosterDeletion(name) {
4268
4531
  let deletions = [];
4269
4532
  try {
4270
- if (existsSync9(ROSTER_DELETIONS_PATH)) {
4271
- deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
4533
+ if (existsSync11(ROSTER_DELETIONS_PATH)) {
4534
+ deletions = JSON.parse(readFileSync8(ROSTER_DELETIONS_PATH, "utf-8"));
4272
4535
  }
4273
4536
  } catch {
4274
4537
  }
4275
4538
  if (!deletions.includes(name)) deletions.push(name);
4276
- writeFileSync5(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
4539
+ writeFileSync6(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
4277
4540
  }
4278
4541
  function consumeRosterDeletions() {
4279
4542
  try {
4280
- if (!existsSync9(ROSTER_DELETIONS_PATH)) return [];
4281
- const deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
4282
- writeFileSync5(ROSTER_DELETIONS_PATH, "[]");
4543
+ if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
4544
+ const deletions = JSON.parse(readFileSync8(ROSTER_DELETIONS_PATH, "utf-8"));
4545
+ writeFileSync6(ROSTER_DELETIONS_PATH, "[]");
4283
4546
  return deletions;
4284
4547
  } catch {
4285
4548
  return [];
4286
4549
  }
4287
4550
  }
4288
4551
  function buildRosterBlob(paths) {
4289
- const rosterPath = paths?.rosterPath ?? path10.join(EXE_AI_DIR, "exe-employees.json");
4290
- const identityDir = paths?.identityDir ?? path10.join(EXE_AI_DIR, "identity");
4291
- const configPath = paths?.configPath ?? path10.join(EXE_AI_DIR, "config.json");
4552
+ const rosterPath = paths?.rosterPath ?? path11.join(EXE_AI_DIR, "exe-employees.json");
4553
+ const identityDir = paths?.identityDir ?? path11.join(EXE_AI_DIR, "identity");
4554
+ const configPath = paths?.configPath ?? path11.join(EXE_AI_DIR, "config.json");
4292
4555
  let roster = [];
4293
- if (existsSync9(rosterPath)) {
4556
+ if (existsSync11(rosterPath)) {
4294
4557
  try {
4295
- roster = JSON.parse(readFileSync7(rosterPath, "utf-8"));
4558
+ roster = JSON.parse(readFileSync8(rosterPath, "utf-8"));
4296
4559
  } catch {
4297
4560
  }
4298
4561
  }
4299
4562
  const identities = {};
4300
- if (existsSync9(identityDir)) {
4563
+ if (existsSync11(identityDir)) {
4301
4564
  for (const file of readdirSync(identityDir).filter((f) => f.endsWith(".md"))) {
4302
4565
  try {
4303
- identities[file] = readFileSync7(path10.join(identityDir, file), "utf-8");
4566
+ identities[file] = readFileSync8(path11.join(identityDir, file), "utf-8");
4304
4567
  } catch {
4305
4568
  }
4306
4569
  }
4307
4570
  }
4308
4571
  let config;
4309
- if (existsSync9(configPath)) {
4572
+ if (existsSync11(configPath)) {
4310
4573
  try {
4311
- config = JSON.parse(readFileSync7(configPath, "utf-8"));
4574
+ config = JSON.parse(readFileSync8(configPath, "utf-8"));
4312
4575
  } catch {
4313
4576
  }
4314
4577
  }
4315
4578
  let agentConfig;
4316
- const agentConfigPath = path10.join(EXE_AI_DIR, "agent-config.json");
4317
- if (existsSync9(agentConfigPath)) {
4579
+ const agentConfigPath = path11.join(EXE_AI_DIR, "agent-config.json");
4580
+ if (existsSync11(agentConfigPath)) {
4318
4581
  try {
4319
- agentConfig = JSON.parse(readFileSync7(agentConfigPath, "utf-8"));
4582
+ agentConfig = JSON.parse(readFileSync8(agentConfigPath, "utf-8"));
4320
4583
  } catch {
4321
4584
  }
4322
4585
  }
4323
4586
  const deletedNames = consumeRosterDeletions();
4324
4587
  const content = JSON.stringify({ roster, identities, config, agentConfig, deletedNames });
4325
- const hash = crypto2.createHash("sha256").update(content).digest("hex").slice(0, 16);
4588
+ const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
4326
4589
  return { roster, identities, config, agentConfig, deletedNames, version: hash };
4327
4590
  }
4328
4591
  async function cloudPushRoster(config) {
@@ -4392,23 +4655,24 @@ async function cloudPullRoster(config) {
4392
4655
  }
4393
4656
  }
4394
4657
  function mergeConfig(remoteConfig, configPath) {
4395
- const cfgPath = configPath ?? path10.join(EXE_AI_DIR, "config.json");
4658
+ const cfgPath = configPath ?? path11.join(EXE_AI_DIR, "config.json");
4396
4659
  let local = {};
4397
- if (existsSync9(cfgPath)) {
4660
+ if (existsSync11(cfgPath)) {
4398
4661
  try {
4399
- local = JSON.parse(readFileSync7(cfgPath, "utf-8"));
4662
+ local = JSON.parse(readFileSync8(cfgPath, "utf-8"));
4400
4663
  } catch {
4401
4664
  }
4402
4665
  }
4403
4666
  const merged = { ...remoteConfig, ...local };
4404
- const dir = path10.dirname(cfgPath);
4405
- if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
4406
- writeFileSync5(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
4667
+ const dir = path11.dirname(cfgPath);
4668
+ ensurePrivateDirSync(dir);
4669
+ writeFileSync6(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
4670
+ enforcePrivateFileSync(cfgPath);
4407
4671
  }
4408
4672
  async function mergeRosterFromRemote(remote, paths) {
4409
4673
  return withRosterLock(async () => {
4410
4674
  const rosterPath = paths?.rosterPath ?? void 0;
4411
- const identityDir = paths?.identityDir ?? path10.join(EXE_AI_DIR, "identity");
4675
+ const identityDir = paths?.identityDir ?? path11.join(EXE_AI_DIR, "identity");
4412
4676
  const localEmployees = await loadEmployees(rosterPath);
4413
4677
  const localNames = new Set(localEmployees.map((e) => e.name));
4414
4678
  let added = 0;
@@ -4429,15 +4693,15 @@ async function mergeRosterFromRemote(remote, paths) {
4429
4693
  ) ?? lookupKey;
4430
4694
  const remoteIdentity = remote.identities[matchedKey];
4431
4695
  if (remoteIdentity) {
4432
- if (!existsSync9(identityDir)) mkdirSync4(identityDir, { recursive: true });
4433
- const idPath = path10.join(identityDir, `${remoteEmp.name}.md`);
4696
+ if (!existsSync11(identityDir)) mkdirSync4(identityDir, { recursive: true });
4697
+ const idPath = path11.join(identityDir, `${remoteEmp.name}.md`);
4434
4698
  let localIdentity = null;
4435
4699
  try {
4436
- localIdentity = existsSync9(idPath) ? readFileSync7(idPath, "utf-8") : null;
4700
+ localIdentity = existsSync11(idPath) ? readFileSync8(idPath, "utf-8") : null;
4437
4701
  } catch {
4438
4702
  }
4439
4703
  if (localIdentity !== remoteIdentity) {
4440
- writeFileSync5(idPath, remoteIdentity, "utf-8");
4704
+ writeFileSync6(idPath, remoteIdentity, "utf-8");
4441
4705
  identitiesUpdated++;
4442
4706
  }
4443
4707
  }
@@ -4463,16 +4727,18 @@ async function mergeRosterFromRemote(remote, paths) {
4463
4727
  }
4464
4728
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
4465
4729
  try {
4466
- const agentConfigPath = path10.join(EXE_AI_DIR, "agent-config.json");
4730
+ const agentConfigPath = path11.join(EXE_AI_DIR, "agent-config.json");
4467
4731
  let local = {};
4468
- if (existsSync9(agentConfigPath)) {
4732
+ if (existsSync11(agentConfigPath)) {
4469
4733
  try {
4470
- local = JSON.parse(readFileSync7(agentConfigPath, "utf-8"));
4734
+ local = JSON.parse(readFileSync8(agentConfigPath, "utf-8"));
4471
4735
  } catch {
4472
4736
  }
4473
4737
  }
4474
4738
  const merged = { ...remote.agentConfig, ...local };
4475
- writeFileSync5(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
4739
+ ensurePrivateDirSync(path11.dirname(agentConfigPath));
4740
+ writeFileSync6(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
4741
+ enforcePrivateFileSync(agentConfigPath);
4476
4742
  } catch {
4477
4743
  }
4478
4744
  }
@@ -4896,7 +5162,7 @@ async function cloudPullDocuments(config) {
4896
5162
  }
4897
5163
  return { pulled };
4898
5164
  }
4899
- var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, ROSTER_DELETIONS_PATH;
5165
+ var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, _pgPromise, _pgFailed, ROSTER_DELETIONS_PATH;
4900
5166
  var init_cloud_sync = __esm({
4901
5167
  "src/lib/cloud-sync.ts"() {
4902
5168
  "use strict";
@@ -4907,12 +5173,15 @@ var init_cloud_sync = __esm({
4907
5173
  init_config();
4908
5174
  init_crdt_sync();
4909
5175
  init_employees();
5176
+ init_secure_files();
4910
5177
  LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
4911
5178
  FETCH_TIMEOUT_MS = 3e4;
4912
5179
  PUSH_BATCH_SIZE = 5e3;
4913
- ROSTER_LOCK_PATH = path10.join(EXE_AI_DIR, "roster-merge.lock");
5180
+ ROSTER_LOCK_PATH = path11.join(EXE_AI_DIR, "roster-merge.lock");
4914
5181
  LOCK_STALE_MS = 3e4;
4915
- ROSTER_DELETIONS_PATH = path10.join(EXE_AI_DIR, "roster-deletions.json");
5182
+ _pgPromise = null;
5183
+ _pgFailed = false;
5184
+ ROSTER_DELETIONS_PATH = path11.join(EXE_AI_DIR, "roster-deletions.json");
4916
5185
  }
4917
5186
  });
4918
5187
 
@@ -4922,37 +5191,39 @@ __export(preferences_exports, {
4922
5191
  loadPreferences: () => loadPreferences,
4923
5192
  savePreferences: () => savePreferences
4924
5193
  });
4925
- import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
4926
- import path11 from "path";
4927
- import os6 from "os";
4928
- function loadPreferences(homeDir = os6.homedir()) {
4929
- const configPath = path11.join(homeDir, ".exe-os", "config.json");
4930
- if (!existsSync10(configPath)) return {};
5194
+ import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
5195
+ import path12 from "path";
5196
+ import os7 from "os";
5197
+ function loadPreferences(homeDir = os7.homedir()) {
5198
+ const configPath = path12.join(homeDir, ".exe-os", "config.json");
5199
+ if (!existsSync12(configPath)) return {};
4931
5200
  try {
4932
- const config = JSON.parse(readFileSync8(configPath, "utf-8"));
5201
+ const config = JSON.parse(readFileSync9(configPath, "utf-8"));
4933
5202
  return config.preferences ?? {};
4934
5203
  } catch {
4935
5204
  return {};
4936
5205
  }
4937
5206
  }
4938
- function savePreferences(prefs, homeDir = os6.homedir()) {
4939
- const configDir = path11.join(homeDir, ".exe-os");
4940
- const configPath = path11.join(configDir, "config.json");
4941
- mkdirSync5(configDir, { recursive: true });
5207
+ function savePreferences(prefs, homeDir = os7.homedir()) {
5208
+ const configDir = path12.join(homeDir, ".exe-os");
5209
+ const configPath = path12.join(configDir, "config.json");
5210
+ ensurePrivateDirSync(configDir);
4942
5211
  let config = {};
4943
- if (existsSync10(configPath)) {
5212
+ if (existsSync12(configPath)) {
4944
5213
  try {
4945
- config = JSON.parse(readFileSync8(configPath, "utf-8"));
5214
+ config = JSON.parse(readFileSync9(configPath, "utf-8"));
4946
5215
  } catch {
4947
5216
  config = {};
4948
5217
  }
4949
5218
  }
4950
5219
  config.preferences = prefs;
4951
- writeFileSync6(configPath, JSON.stringify(config, null, 2) + "\n");
5220
+ writeFileSync7(configPath, JSON.stringify(config, null, 2) + "\n");
5221
+ enforcePrivateFileSync(configPath);
4952
5222
  }
4953
5223
  var init_preferences = __esm({
4954
5224
  "src/lib/preferences.ts"() {
4955
5225
  "use strict";
5226
+ init_secure_files();
4956
5227
  }
4957
5228
  });
4958
5229
 
@@ -5723,17 +5994,17 @@ __export(identity_exports, {
5723
5994
  listIdentities: () => listIdentities,
5724
5995
  updateIdentity: () => updateIdentity
5725
5996
  });
5726
- import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
5997
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
5727
5998
  import { readdirSync as readdirSync2 } from "fs";
5728
- import path12 from "path";
5999
+ import path13 from "path";
5729
6000
  import { createHash as createHash2 } from "crypto";
5730
6001
  function ensureDir() {
5731
- if (!existsSync11(IDENTITY_DIR2)) {
5732
- mkdirSync6(IDENTITY_DIR2, { recursive: true });
6002
+ if (!existsSync13(IDENTITY_DIR2)) {
6003
+ mkdirSync5(IDENTITY_DIR2, { recursive: true });
5733
6004
  }
5734
6005
  }
5735
6006
  function identityPath(agentId) {
5736
- return path12.join(IDENTITY_DIR2, `${agentId}.md`);
6007
+ return path13.join(IDENTITY_DIR2, `${agentId}.md`);
5737
6008
  }
5738
6009
  function parseFrontmatter(raw) {
5739
6010
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -5774,8 +6045,8 @@ function contentHash(content) {
5774
6045
  }
5775
6046
  function getIdentity(agentId) {
5776
6047
  const filePath = identityPath(agentId);
5777
- if (!existsSync11(filePath)) return null;
5778
- const raw = readFileSync9(filePath, "utf-8");
6048
+ if (!existsSync13(filePath)) return null;
6049
+ const raw = readFileSync10(filePath, "utf-8");
5779
6050
  const { frontmatter, body } = parseFrontmatter(raw);
5780
6051
  return {
5781
6052
  agentId,
@@ -5789,7 +6060,7 @@ async function updateIdentity(agentId, content, updatedBy) {
5789
6060
  ensureDir();
5790
6061
  const filePath = identityPath(agentId);
5791
6062
  const hash = contentHash(content);
5792
- writeFileSync7(filePath, content, "utf-8");
6063
+ writeFileSync8(filePath, content, "utf-8");
5793
6064
  try {
5794
6065
  const client = getClient();
5795
6066
  await client.execute({
@@ -5845,7 +6116,7 @@ var init_identity = __esm({
5845
6116
  "use strict";
5846
6117
  init_config();
5847
6118
  init_database();
5848
- IDENTITY_DIR2 = path12.join(EXE_AI_DIR, "identity");
6119
+ IDENTITY_DIR2 = path13.join(EXE_AI_DIR, "identity");
5849
6120
  }
5850
6121
  });
5851
6122
 
@@ -6396,36 +6667,36 @@ __export(session_wrappers_exports, {
6396
6667
  generateSessionWrappers: () => generateSessionWrappers
6397
6668
  });
6398
6669
  import {
6399
- existsSync as existsSync12,
6400
- readFileSync as readFileSync10,
6401
- writeFileSync as writeFileSync8,
6402
- mkdirSync as mkdirSync7,
6403
- chmodSync,
6670
+ existsSync as existsSync14,
6671
+ readFileSync as readFileSync11,
6672
+ writeFileSync as writeFileSync9,
6673
+ mkdirSync as mkdirSync6,
6674
+ chmodSync as chmodSync2,
6404
6675
  readdirSync as readdirSync3,
6405
6676
  unlinkSync as unlinkSync6
6406
6677
  } from "fs";
6407
- import path13 from "path";
6678
+ import path14 from "path";
6408
6679
  import { homedir as homedir3 } from "os";
6409
6680
  function generateSessionWrappers(packageRoot, homeDir) {
6410
6681
  const home = homeDir ?? homedir3();
6411
- const binDir = path13.join(home, ".exe-os", "bin");
6412
- const rosterPath = path13.join(home, ".exe-os", "exe-employees.json");
6413
- mkdirSync7(binDir, { recursive: true });
6414
- const exeStartDst = path13.join(binDir, "exe-start");
6682
+ const binDir = path14.join(home, ".exe-os", "bin");
6683
+ const rosterPath = path14.join(home, ".exe-os", "exe-employees.json");
6684
+ mkdirSync6(binDir, { recursive: true });
6685
+ const exeStartDst = path14.join(binDir, "exe-start");
6415
6686
  const candidates = [
6416
- path13.join(packageRoot, "dist", "bin", "exe-start.sh"),
6417
- path13.join(packageRoot, "src", "bin", "exe-start.sh")
6687
+ path14.join(packageRoot, "dist", "bin", "exe-start.sh"),
6688
+ path14.join(packageRoot, "src", "bin", "exe-start.sh")
6418
6689
  ];
6419
6690
  for (const src of candidates) {
6420
- if (existsSync12(src)) {
6421
- writeFileSync8(exeStartDst, readFileSync10(src));
6422
- chmodSync(exeStartDst, 493);
6691
+ if (existsSync14(src)) {
6692
+ writeFileSync9(exeStartDst, readFileSync11(src));
6693
+ chmodSync2(exeStartDst, 493);
6423
6694
  break;
6424
6695
  }
6425
6696
  }
6426
6697
  let employees = [];
6427
6698
  try {
6428
- employees = JSON.parse(readFileSync10(rosterPath, "utf8"));
6699
+ employees = JSON.parse(readFileSync11(rosterPath, "utf8"));
6429
6700
  } catch {
6430
6701
  return { created: 0, pathConfigured: false };
6431
6702
  }
@@ -6435,9 +6706,9 @@ function generateSessionWrappers(packageRoot, homeDir) {
6435
6706
  try {
6436
6707
  for (const f of readdirSync3(binDir)) {
6437
6708
  if (f === "exe-start") continue;
6438
- const fPath = path13.join(binDir, f);
6709
+ const fPath = path14.join(binDir, f);
6439
6710
  try {
6440
- const content = readFileSync10(fPath, "utf8");
6711
+ const content = readFileSync11(fPath, "utf8");
6441
6712
  if (content.includes("exe-start")) {
6442
6713
  unlinkSync6(fPath);
6443
6714
  }
@@ -6452,31 +6723,31 @@ exec "${exeStartDst}" "$0" "$@"
6452
6723
  `;
6453
6724
  for (const emp of employees) {
6454
6725
  for (let n = 1; n <= MAX_N; n++) {
6455
- const wrapperPath = path13.join(binDir, `${emp.name}${n}`);
6456
- writeFileSync8(wrapperPath, wrapperContent);
6457
- chmodSync(wrapperPath, 493);
6726
+ const wrapperPath = path14.join(binDir, `${emp.name}${n}`);
6727
+ writeFileSync9(wrapperPath, wrapperContent);
6728
+ chmodSync2(wrapperPath, 493);
6458
6729
  created++;
6459
6730
  }
6460
6731
  }
6461
6732
  const codexLauncherCandidates = [
6462
- path13.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
6463
- path13.join(packageRoot, "src", "bin", "exe-start-codex.ts")
6733
+ path14.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
6734
+ path14.join(packageRoot, "src", "bin", "exe-start-codex.ts")
6464
6735
  ];
6465
6736
  let codexLauncher = null;
6466
6737
  for (const c of codexLauncherCandidates) {
6467
- if (existsSync12(c)) {
6738
+ if (existsSync14(c)) {
6468
6739
  codexLauncher = c;
6469
6740
  break;
6470
6741
  }
6471
6742
  }
6472
6743
  if (codexLauncher) {
6473
6744
  for (const emp of employees) {
6474
- const wrapperPath = path13.join(binDir, `${emp.name}-codex`);
6745
+ const wrapperPath = path14.join(binDir, `${emp.name}-codex`);
6475
6746
  const content = `#!/bin/bash
6476
6747
  exec node "${codexLauncher}" --agent ${emp.name} "$@"
6477
6748
  `;
6478
- writeFileSync8(wrapperPath, content);
6479
- chmodSync(wrapperPath, 493);
6749
+ writeFileSync9(wrapperPath, content);
6750
+ chmodSync2(wrapperPath, 493);
6480
6751
  created++;
6481
6752
  }
6482
6753
  }
@@ -6494,24 +6765,24 @@ export PATH="${binDir}:$PATH"
6494
6765
  const shell = process.env.SHELL ?? "/bin/bash";
6495
6766
  const profilePaths = [];
6496
6767
  if (shell.includes("zsh")) {
6497
- profilePaths.push(path13.join(home, ".zshrc"));
6768
+ profilePaths.push(path14.join(home, ".zshrc"));
6498
6769
  } else if (shell.includes("bash")) {
6499
- profilePaths.push(path13.join(home, ".bashrc"));
6500
- profilePaths.push(path13.join(home, ".bash_profile"));
6770
+ profilePaths.push(path14.join(home, ".bashrc"));
6771
+ profilePaths.push(path14.join(home, ".bash_profile"));
6501
6772
  } else {
6502
- profilePaths.push(path13.join(home, ".profile"));
6773
+ profilePaths.push(path14.join(home, ".profile"));
6503
6774
  }
6504
6775
  for (const profilePath of profilePaths) {
6505
6776
  try {
6506
6777
  let content = "";
6507
6778
  try {
6508
- content = readFileSync10(profilePath, "utf8");
6779
+ content = readFileSync11(profilePath, "utf8");
6509
6780
  } catch {
6510
6781
  }
6511
6782
  if (content.includes(".exe-os/bin")) {
6512
6783
  return false;
6513
6784
  }
6514
- writeFileSync8(profilePath, content + exportLine);
6785
+ writeFileSync9(profilePath, content + exportLine);
6515
6786
  return true;
6516
6787
  } catch {
6517
6788
  continue;
@@ -6530,14 +6801,14 @@ var init_session_wrappers = __esm({
6530
6801
  // src/lib/setup-wizard.ts
6531
6802
  init_config();
6532
6803
  init_keychain();
6533
- import crypto3 from "crypto";
6534
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync9, unlinkSync as unlinkSync7 } from "fs";
6535
- import os7 from "os";
6536
- import path14 from "path";
6804
+ import crypto4 from "crypto";
6805
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync10, unlinkSync as unlinkSync7 } from "fs";
6806
+ import os8 from "os";
6807
+ import path15 from "path";
6537
6808
  import { createInterface } from "readline";
6538
6809
 
6539
6810
  // src/lib/model-downloader.ts
6540
- import { createWriteStream, createReadStream, existsSync as existsSync3, unlinkSync, renameSync as renameSync2 } from "fs";
6811
+ import { createWriteStream, createReadStream, existsSync as existsSync4, unlinkSync, renameSync as renameSync2 } from "fs";
6541
6812
  import { mkdir as mkdir3 } from "fs/promises";
6542
6813
  import { createHash } from "crypto";
6543
6814
  import path3 from "path";
@@ -6550,7 +6821,7 @@ async function downloadModel(opts) {
6550
6821
  const destPath = path3.join(destDir, LOCAL_FILENAME);
6551
6822
  const tmpPath = destPath + ".tmp";
6552
6823
  await mkdir3(destDir, { recursive: true });
6553
- if (existsSync3(destPath)) {
6824
+ if (existsSync4(destPath)) {
6554
6825
  const hash = await fileHash(destPath);
6555
6826
  if (hash === EXPECTED_SHA256) {
6556
6827
  return destPath;
@@ -6562,7 +6833,7 @@ async function downloadModel(opts) {
6562
6833
  let downloaded = 0;
6563
6834
  for (let attempt = 1; attempt <= MAX_RETRIES2; attempt++) {
6564
6835
  try {
6565
- if (existsSync3(tmpPath)) unlinkSync(tmpPath);
6836
+ if (existsSync4(tmpPath)) unlinkSync(tmpPath);
6566
6837
  const response = await fetchFn(GGUF_URL, {
6567
6838
  redirect: "follow",
6568
6839
  signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
@@ -6607,7 +6878,7 @@ async function downloadModel(opts) {
6607
6878
  process.stderr.write(`
6608
6879
  Download attempt ${attempt} failed, retrying...
6609
6880
  `);
6610
- if (existsSync3(tmpPath)) unlinkSync(tmpPath);
6881
+ if (existsSync4(tmpPath)) unlinkSync(tmpPath);
6611
6882
  }
6612
6883
  }
6613
6884
  }
@@ -6625,32 +6896,32 @@ async function fileHash(filePath) {
6625
6896
 
6626
6897
  // src/lib/setup-wizard.ts
6627
6898
  function findPackageRoot2() {
6628
- let dir = path14.dirname(new URL(import.meta.url).pathname);
6629
- const root = path14.parse(dir).root;
6899
+ let dir = path15.dirname(new URL(import.meta.url).pathname);
6900
+ const root = path15.parse(dir).root;
6630
6901
  while (dir !== root) {
6631
- const pkgPath = path14.join(dir, "package.json");
6632
- if (existsSync13(pkgPath)) {
6902
+ const pkgPath = path15.join(dir, "package.json");
6903
+ if (existsSync15(pkgPath)) {
6633
6904
  try {
6634
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
6905
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
6635
6906
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
6636
6907
  } catch {
6637
6908
  }
6638
6909
  }
6639
- dir = path14.dirname(dir);
6910
+ dir = path15.dirname(dir);
6640
6911
  }
6641
6912
  return null;
6642
6913
  }
6643
- var SETUP_STATE_PATH = path14.join(os7.homedir(), ".exe-os", "setup-state.json");
6914
+ var SETUP_STATE_PATH = path15.join(os8.homedir(), ".exe-os", "setup-state.json");
6644
6915
  function loadSetupState() {
6645
6916
  try {
6646
- return JSON.parse(readFileSync11(SETUP_STATE_PATH, "utf8"));
6917
+ return JSON.parse(readFileSync12(SETUP_STATE_PATH, "utf8"));
6647
6918
  } catch {
6648
6919
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
6649
6920
  }
6650
6921
  }
6651
6922
  function saveSetupState(state) {
6652
- mkdirSync8(path14.dirname(SETUP_STATE_PATH), { recursive: true });
6653
- writeFileSync9(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
6923
+ mkdirSync7(path15.dirname(SETUP_STATE_PATH), { recursive: true });
6924
+ writeFileSync10(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
6654
6925
  }
6655
6926
  function clearSetupState() {
6656
6927
  try {
@@ -6669,10 +6940,10 @@ function ask(rl, prompt) {
6669
6940
  });
6670
6941
  }
6671
6942
  function getAvailableMemoryGB() {
6672
- return os7.freemem() / (1024 * 1024 * 1024);
6943
+ return os8.freemem() / (1024 * 1024 * 1024);
6673
6944
  }
6674
6945
  function getTotalMemoryGB() {
6675
- return os7.totalmem() / (1024 * 1024 * 1024);
6946
+ return os8.totalmem() / (1024 * 1024 * 1024);
6676
6947
  }
6677
6948
  function isLowMemory() {
6678
6949
  return getAvailableMemoryGB() < 2;
@@ -6683,8 +6954,8 @@ async function validateModel(log) {
6683
6954
  if (totalGB <= 8 || isLowMemory()) {
6684
6955
  log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
6685
6956
  log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
6686
- const modelPath = path14.join(MODELS_DIR, LOCAL_FILENAME);
6687
- if (existsSync13(modelPath)) {
6957
+ const modelPath = path15.join(MODELS_DIR, LOCAL_FILENAME);
6958
+ if (existsSync15(modelPath)) {
6688
6959
  const { statSync: statSync2 } = await import("fs");
6689
6960
  const size = statSync2(modelPath).size;
6690
6961
  if (size > 300 * 1e6) {
@@ -6775,7 +7046,7 @@ async function runSetupWizard(opts = {}) {
6775
7046
  if (state.completedSteps.length > 0) {
6776
7047
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
6777
7048
  }
6778
- if (existsSync13(LEGACY_LANCE_PATH)) {
7049
+ if (existsSync15(LEGACY_LANCE_PATH)) {
6779
7050
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
6780
7051
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
6781
7052
  log(" The old directory will not be modified or deleted.");
@@ -6787,7 +7058,7 @@ async function runSetupWizard(opts = {}) {
6787
7058
  log("Encryption key already exists \u2014 skipping generation.");
6788
7059
  } else {
6789
7060
  log("Generating 256-bit encryption key...");
6790
- const key = crypto3.randomBytes(32);
7061
+ const key = crypto4.randomBytes(32);
6791
7062
  await setMasterKey(key);
6792
7063
  log("Encryption key generated and stored securely.");
6793
7064
  }
@@ -6939,19 +7210,19 @@ async function runSetupWizard(opts = {}) {
6939
7210
  await saveConfig(config);
6940
7211
  log("");
6941
7212
  try {
6942
- const claudeJsonPath = path14.join(os7.homedir(), ".claude.json");
7213
+ const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
6943
7214
  let claudeJson = {};
6944
7215
  try {
6945
- claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
7216
+ claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
6946
7217
  } catch {
6947
7218
  }
6948
7219
  if (!claudeJson.projects) claudeJson.projects = {};
6949
7220
  const projects = claudeJson.projects;
6950
- for (const dir of [process.cwd(), os7.homedir()]) {
7221
+ for (const dir of [process.cwd(), os8.homedir()]) {
6951
7222
  if (!projects[dir]) projects[dir] = {};
6952
7223
  projects[dir].hasTrustDialogAccepted = true;
6953
7224
  }
6954
- writeFileSync9(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7225
+ writeFileSync10(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
6955
7226
  } catch {
6956
7227
  }
6957
7228
  state.completedSteps.push(5);
@@ -6965,7 +7236,7 @@ async function runSetupWizard(opts = {}) {
6965
7236
  const prefs = { ...existingPrefs };
6966
7237
  log("=== Config Defaults ===");
6967
7238
  log("");
6968
- const ghosttyDetected = existsSync13(path14.join(os7.homedir(), ".config", "ghostty")) || existsSync13(path14.join(os7.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
7239
+ const ghosttyDetected = existsSync15(path15.join(os8.homedir(), ".config", "ghostty")) || existsSync15(path15.join(os8.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
6969
7240
  if (ghosttyDetected) {
6970
7241
  const ghosttyAnswer = await ask(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
6971
7242
  prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
@@ -7012,7 +7283,7 @@ async function runSetupWizard(opts = {}) {
7012
7283
  let missingIdentities = [];
7013
7284
  for (const emp of roster) {
7014
7285
  const idPath = identityPath2(emp.name);
7015
- if (!existsSync13(idPath)) {
7286
+ if (!existsSync15(idPath)) {
7016
7287
  missingIdentities.push(emp.name);
7017
7288
  }
7018
7289
  }
@@ -7044,7 +7315,7 @@ async function runSetupWizard(opts = {}) {
7044
7315
  }
7045
7316
  missingIdentities = [];
7046
7317
  for (const emp of roster) {
7047
- if (!existsSync13(identityPath2(emp.name))) {
7318
+ if (!existsSync15(identityPath2(emp.name))) {
7048
7319
  missingIdentities.push(emp.name);
7049
7320
  }
7050
7321
  }
@@ -7109,9 +7380,9 @@ async function runSetupWizard(opts = {}) {
7109
7380
  const cooIdentityContent = getIdentityTemplate("coo");
7110
7381
  if (cooIdentityContent) {
7111
7382
  const cooIdPath = identityPath2(cooName);
7112
- mkdirSync8(path14.dirname(cooIdPath), { recursive: true });
7383
+ mkdirSync7(path15.dirname(cooIdPath), { recursive: true });
7113
7384
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
7114
- writeFileSync9(cooIdPath, replaced, "utf-8");
7385
+ writeFileSync10(cooIdPath, replaced, "utf-8");
7115
7386
  }
7116
7387
  registerBinSymlinks2(cooName);
7117
7388
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -7205,9 +7476,9 @@ async function runSetupWizard(opts = {}) {
7205
7476
  const ctoIdentityContent = getIdentityTemplate("cto");
7206
7477
  if (ctoIdentityContent) {
7207
7478
  const ctoIdPath = identityPath2(ctoName);
7208
- mkdirSync8(path14.dirname(ctoIdPath), { recursive: true });
7479
+ mkdirSync7(path15.dirname(ctoIdPath), { recursive: true });
7209
7480
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
7210
- writeFileSync9(ctoIdPath, replaced, "utf-8");
7481
+ writeFileSync10(ctoIdPath, replaced, "utf-8");
7211
7482
  }
7212
7483
  registerBinSymlinks2(ctoName);
7213
7484
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -7228,9 +7499,9 @@ async function runSetupWizard(opts = {}) {
7228
7499
  const cmoIdentityContent = getIdentityTemplate("cmo");
7229
7500
  if (cmoIdentityContent) {
7230
7501
  const cmoIdPath = identityPath2(cmoName);
7231
- mkdirSync8(path14.dirname(cmoIdPath), { recursive: true });
7502
+ mkdirSync7(path15.dirname(cmoIdPath), { recursive: true });
7232
7503
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
7233
- writeFileSync9(cmoIdPath, replaced, "utf-8");
7504
+ writeFileSync10(cmoIdPath, replaced, "utf-8");
7234
7505
  }
7235
7506
  registerBinSymlinks2(cmoName);
7236
7507
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -7252,7 +7523,7 @@ async function runSetupWizard(opts = {}) {
7252
7523
  log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
7253
7524
  }
7254
7525
  if (wrapResult.pathConfigured) {
7255
- const binDir = path14.join(os7.homedir(), ".exe-os", "bin");
7526
+ const binDir = path15.join(os8.homedir(), ".exe-os", "bin");
7256
7527
  process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
7257
7528
  pathJustConfigured = true;
7258
7529
  }
@@ -7295,7 +7566,7 @@ async function runSetupWizard(opts = {}) {
7295
7566
  const pkgRoot2 = findPackageRoot2();
7296
7567
  if (pkgRoot2) {
7297
7568
  try {
7298
- version = JSON.parse(readFileSync11(path14.join(pkgRoot2, "package.json"), "utf-8")).version;
7569
+ version = JSON.parse(readFileSync12(path15.join(pkgRoot2, "package.json"), "utf-8")).version;
7299
7570
  } catch {
7300
7571
  }
7301
7572
  }