@askexenow/exe-os 0.9.7 → 0.9.8

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 (95) hide show
  1. package/dist/bin/backfill-conversations.js +754 -79
  2. package/dist/bin/backfill-responses.js +752 -77
  3. package/dist/bin/backfill-vectors.js +752 -77
  4. package/dist/bin/cleanup-stale-review-tasks.js +657 -35
  5. package/dist/bin/cli.js +1388 -605
  6. package/dist/bin/exe-agent-config.js +123 -95
  7. package/dist/bin/exe-agent.js +41 -25
  8. package/dist/bin/exe-assign.js +732 -57
  9. package/dist/bin/exe-boot.js +784 -153
  10. package/dist/bin/exe-call.js +209 -138
  11. package/dist/bin/exe-cloud.js +35 -12
  12. package/dist/bin/exe-dispatch.js +692 -70
  13. package/dist/bin/exe-doctor.js +648 -26
  14. package/dist/bin/exe-export-behaviors.js +650 -20
  15. package/dist/bin/exe-forget.js +635 -13
  16. package/dist/bin/exe-gateway.js +1053 -271
  17. package/dist/bin/exe-heartbeat.js +665 -43
  18. package/dist/bin/exe-kill.js +646 -16
  19. package/dist/bin/exe-launch-agent.js +887 -97
  20. package/dist/bin/exe-link.js +658 -43
  21. package/dist/bin/exe-new-employee.js +378 -177
  22. package/dist/bin/exe-pending-messages.js +656 -34
  23. package/dist/bin/exe-pending-notifications.js +635 -13
  24. package/dist/bin/exe-pending-reviews.js +659 -37
  25. package/dist/bin/exe-rename.js +645 -30
  26. package/dist/bin/exe-review.js +635 -13
  27. package/dist/bin/exe-search.js +771 -88
  28. package/dist/bin/exe-session-cleanup.js +834 -150
  29. package/dist/bin/exe-settings.js +127 -91
  30. package/dist/bin/exe-start-codex.js +729 -94
  31. package/dist/bin/exe-start-opencode.js +717 -82
  32. package/dist/bin/exe-status.js +657 -35
  33. package/dist/bin/exe-team.js +635 -13
  34. package/dist/bin/git-sweep.js +720 -89
  35. package/dist/bin/graph-backfill.js +643 -13
  36. package/dist/bin/graph-export.js +646 -16
  37. package/dist/bin/install.js +596 -193
  38. package/dist/bin/scan-tasks.js +724 -93
  39. package/dist/bin/setup.js +1038 -210
  40. package/dist/bin/shard-migrate.js +645 -15
  41. package/dist/bin/wiki-sync.js +646 -16
  42. package/dist/gateway/index.js +1027 -245
  43. package/dist/hooks/bug-report-worker.js +891 -170
  44. package/dist/hooks/commit-complete.js +718 -87
  45. package/dist/hooks/error-recall.js +776 -93
  46. package/dist/hooks/exe-heartbeat-hook.js +85 -71
  47. package/dist/hooks/ingest-worker.js +840 -156
  48. package/dist/hooks/ingest.js +90 -73
  49. package/dist/hooks/instructions-loaded.js +669 -38
  50. package/dist/hooks/notification.js +661 -30
  51. package/dist/hooks/post-compact.js +674 -43
  52. package/dist/hooks/pre-compact.js +718 -87
  53. package/dist/hooks/pre-tool-use.js +872 -125
  54. package/dist/hooks/prompt-ingest-worker.js +758 -83
  55. package/dist/hooks/prompt-submit.js +1060 -319
  56. package/dist/hooks/response-ingest-worker.js +758 -83
  57. package/dist/hooks/session-end.js +721 -90
  58. package/dist/hooks/session-start.js +1031 -207
  59. package/dist/hooks/stop.js +680 -49
  60. package/dist/hooks/subagent-stop.js +674 -43
  61. package/dist/hooks/summary-worker.js +816 -132
  62. package/dist/index.js +1015 -232
  63. package/dist/lib/cloud-sync.js +663 -48
  64. package/dist/lib/consolidation.js +26 -3
  65. package/dist/lib/database.js +626 -18
  66. package/dist/lib/db.js +2261 -0
  67. package/dist/lib/device-registry.js +640 -25
  68. package/dist/lib/embedder.js +96 -43
  69. package/dist/lib/employee-templates.js +16 -0
  70. package/dist/lib/employees.js +259 -83
  71. package/dist/lib/exe-daemon-client.js +101 -63
  72. package/dist/lib/exe-daemon.js +894 -162
  73. package/dist/lib/hybrid-search.js +771 -88
  74. package/dist/lib/identity.js +27 -7
  75. package/dist/lib/messaging.js +55 -28
  76. package/dist/lib/reminders.js +21 -1
  77. package/dist/lib/schedules.js +636 -14
  78. package/dist/lib/skill-learning.js +21 -1
  79. package/dist/lib/store.js +643 -13
  80. package/dist/lib/task-router.js +82 -71
  81. package/dist/lib/tasks.js +98 -71
  82. package/dist/lib/tmux-routing.js +87 -60
  83. package/dist/lib/token-spend.js +26 -6
  84. package/dist/mcp/server.js +1784 -458
  85. package/dist/mcp/tools/complete-reminder.js +21 -1
  86. package/dist/mcp/tools/create-reminder.js +21 -1
  87. package/dist/mcp/tools/create-task.js +290 -164
  88. package/dist/mcp/tools/deactivate-behavior.js +24 -4
  89. package/dist/mcp/tools/list-reminders.js +21 -1
  90. package/dist/mcp/tools/list-tasks.js +195 -38
  91. package/dist/mcp/tools/send-message.js +58 -31
  92. package/dist/mcp/tools/update-task.js +75 -48
  93. package/dist/runtime/index.js +720 -89
  94. package/dist/tui/App.js +853 -123
  95. package/package.json +3 -2
package/dist/bin/setup.js CHANGED
@@ -634,74 +634,123 @@ async function pingDaemon() {
634
634
  return null;
635
635
  }
636
636
  function killAndRespawnDaemon() {
637
- process.stderr.write("[exed-client] Killing daemon for restart...\n");
638
- if (existsSync4(PID_PATH)) {
639
- try {
640
- const pid = parseInt(readFileSync2(PID_PATH, "utf8").trim(), 10);
641
- if (pid > 0) {
642
- try {
643
- process.kill(pid, "SIGKILL");
644
- } catch {
637
+ if (!acquireSpawnLock()) {
638
+ process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
639
+ if (_socket) {
640
+ _socket.destroy();
641
+ _socket = null;
642
+ }
643
+ _connected = false;
644
+ _buffer = "";
645
+ return;
646
+ }
647
+ try {
648
+ process.stderr.write("[exed-client] Killing daemon for restart...\n");
649
+ if (existsSync4(PID_PATH)) {
650
+ try {
651
+ const pid = parseInt(readFileSync2(PID_PATH, "utf8").trim(), 10);
652
+ if (pid > 0) {
653
+ try {
654
+ process.kill(pid, "SIGKILL");
655
+ } catch {
656
+ }
645
657
  }
658
+ } catch {
646
659
  }
660
+ }
661
+ if (_socket) {
662
+ _socket.destroy();
663
+ _socket = null;
664
+ }
665
+ _connected = false;
666
+ _buffer = "";
667
+ try {
668
+ unlinkSync2(PID_PATH);
647
669
  } catch {
648
670
  }
671
+ try {
672
+ unlinkSync2(SOCKET_PATH);
673
+ } catch {
674
+ }
675
+ spawnDaemon();
676
+ } finally {
677
+ releaseSpawnLock();
649
678
  }
650
- if (_socket) {
651
- _socket.destroy();
652
- _socket = null;
653
- }
654
- _connected = false;
655
- _buffer = "";
679
+ }
680
+ function isDaemonTooYoung() {
656
681
  try {
657
- unlinkSync2(PID_PATH);
682
+ const stat = statSync(PID_PATH);
683
+ return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
658
684
  } catch {
685
+ return false;
659
686
  }
660
- try {
661
- unlinkSync2(SOCKET_PATH);
662
- } catch {
687
+ }
688
+ async function retryThenRestart(doRequest, label) {
689
+ const result = await doRequest();
690
+ if (!result.error) {
691
+ _consecutiveFailures = 0;
692
+ return result;
693
+ }
694
+ _consecutiveFailures++;
695
+ for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
696
+ const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
697
+ process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
698
+ `);
699
+ await new Promise((r) => setTimeout(r, delayMs));
700
+ if (!_connected) {
701
+ if (!await connectToSocket()) continue;
702
+ }
703
+ const retry = await doRequest();
704
+ if (!retry.error) {
705
+ _consecutiveFailures = 0;
706
+ return retry;
707
+ }
708
+ _consecutiveFailures++;
709
+ }
710
+ if (isDaemonTooYoung()) {
711
+ process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
712
+ `);
713
+ return { error: result.error };
663
714
  }
664
- spawnDaemon();
715
+ process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
716
+ `);
717
+ killAndRespawnDaemon();
718
+ const start = Date.now();
719
+ let delay2 = 200;
720
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
721
+ await new Promise((r) => setTimeout(r, delay2));
722
+ if (await connectToSocket()) break;
723
+ delay2 = Math.min(delay2 * 2, 3e3);
724
+ }
725
+ if (!_connected) return { error: "Daemon restart failed" };
726
+ const final = await doRequest();
727
+ if (!final.error) _consecutiveFailures = 0;
728
+ return final;
665
729
  }
666
730
  async function embedViaClient(text, priority = "high") {
667
731
  if (!_connected && !await connectEmbedDaemon()) return null;
668
732
  _requestCount++;
669
733
  if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
670
734
  const health = await pingDaemon();
671
- if (!health) {
735
+ if (!health && !isDaemonTooYoung()) {
672
736
  process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
673
737
  `);
674
738
  killAndRespawnDaemon();
675
739
  const start = Date.now();
676
- let delay2 = 200;
740
+ let d = 200;
677
741
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
678
- await new Promise((r) => setTimeout(r, delay2));
742
+ await new Promise((r) => setTimeout(r, d));
679
743
  if (await connectToSocket()) break;
680
- delay2 = Math.min(delay2 * 2, 3e3);
744
+ d = Math.min(d * 2, 3e3);
681
745
  }
682
746
  if (!_connected) return null;
683
747
  }
684
748
  }
685
- const result = await sendRequest([text], priority);
686
- if (!result.error && result.vectors?.[0]) return result.vectors[0];
687
- if (result.error) {
688
- process.stderr.write(`[exed-client] Embed failed (${result.error}) \u2014 attempting restart
689
- `);
690
- killAndRespawnDaemon();
691
- const start = Date.now();
692
- let delay2 = 200;
693
- while (Date.now() - start < CONNECT_TIMEOUT_MS) {
694
- await new Promise((r) => setTimeout(r, delay2));
695
- if (await connectToSocket()) break;
696
- delay2 = Math.min(delay2 * 2, 3e3);
697
- }
698
- if (!_connected) return null;
699
- const retry = await sendRequest([text], priority);
700
- if (!retry.error && retry.vectors?.[0]) return retry.vectors[0];
701
- process.stderr.write(`[exed-client] Embed retry also failed: ${retry.error ?? "no vector"}
702
- `);
703
- }
704
- return null;
749
+ const result = await retryThenRestart(
750
+ () => sendRequest([text], priority),
751
+ "Embed"
752
+ );
753
+ return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
705
754
  }
706
755
  function disconnectClient() {
707
756
  if (_socket) {
@@ -719,7 +768,7 @@ function disconnectClient() {
719
768
  function isClientConnected() {
720
769
  return _connected;
721
770
  }
722
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
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;
723
772
  var init_exe_daemon_client = __esm({
724
773
  "src/lib/exe-daemon-client.ts"() {
725
774
  "use strict";
@@ -734,7 +783,11 @@ var init_exe_daemon_client = __esm({
734
783
  _connected = false;
735
784
  _buffer = "";
736
785
  _requestCount = 0;
786
+ _consecutiveFailures = 0;
737
787
  HEALTH_CHECK_INTERVAL = 100;
788
+ MAX_RETRIES_BEFORE_RESTART = 3;
789
+ RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
790
+ MIN_DAEMON_AGE_MS = 3e4;
738
791
  _pending = /* @__PURE__ */ new Map();
739
792
  MAX_BUFFER = 1e7;
740
793
  }
@@ -777,10 +830,10 @@ async function disposeEmbedder() {
777
830
  async function embedDirect(text) {
778
831
  const llamaCpp = await import("node-llama-cpp");
779
832
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
780
- const { existsSync: existsSync13 } = await import("fs");
781
- const path13 = await import("path");
782
- const modelPath = path13.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
783
- if (!existsSync13(modelPath)) {
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)) {
784
837
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
785
838
  }
786
839
  const llama = await llamaCpp.getLlama();
@@ -1309,6 +1362,118 @@ var init_db_retry = __esm({
1309
1362
  }
1310
1363
  });
1311
1364
 
1365
+ // src/lib/runtime-table.ts
1366
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
1367
+ var init_runtime_table = __esm({
1368
+ "src/lib/runtime-table.ts"() {
1369
+ "use strict";
1370
+ RUNTIME_TABLE = {
1371
+ codex: {
1372
+ binary: "codex",
1373
+ launchMode: "interactive",
1374
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
1375
+ inlineFlag: "--no-alt-screen",
1376
+ apiKeyEnv: "OPENAI_API_KEY",
1377
+ defaultModel: "gpt-5.4"
1378
+ },
1379
+ opencode: {
1380
+ binary: "opencode",
1381
+ launchMode: "exec",
1382
+ autoApproveFlag: "--dangerously-skip-permissions",
1383
+ inlineFlag: "",
1384
+ apiKeyEnv: "ANTHROPIC_API_KEY",
1385
+ defaultModel: "anthropic/claude-sonnet-4-6"
1386
+ }
1387
+ };
1388
+ DEFAULT_RUNTIME = "claude";
1389
+ }
1390
+ });
1391
+
1392
+ // src/lib/agent-config.ts
1393
+ var agent_config_exports = {};
1394
+ __export(agent_config_exports, {
1395
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
1396
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
1397
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
1398
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
1399
+ clearAgentRuntime: () => clearAgentRuntime,
1400
+ getAgentRuntime: () => getAgentRuntime,
1401
+ loadAgentConfig: () => loadAgentConfig,
1402
+ saveAgentConfig: () => saveAgentConfig,
1403
+ setAgentRuntime: () => setAgentRuntime
1404
+ });
1405
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1406
+ import path6 from "path";
1407
+ function loadAgentConfig() {
1408
+ if (!existsSync6(AGENT_CONFIG_PATH)) return {};
1409
+ try {
1410
+ return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf-8"));
1411
+ } catch {
1412
+ return {};
1413
+ }
1414
+ }
1415
+ 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");
1419
+ }
1420
+ function getAgentRuntime(agentId) {
1421
+ const config = loadAgentConfig();
1422
+ const entry = config[agentId];
1423
+ if (entry) return entry;
1424
+ const orgDefault = config["default"];
1425
+ if (orgDefault) return orgDefault;
1426
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
1427
+ }
1428
+ function setAgentRuntime(agentId, runtime, model) {
1429
+ const knownModels = KNOWN_RUNTIMES[runtime];
1430
+ if (!knownModels) {
1431
+ return {
1432
+ ok: false,
1433
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
1434
+ };
1435
+ }
1436
+ if (!knownModels.includes(model)) {
1437
+ return {
1438
+ ok: false,
1439
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
1440
+ };
1441
+ }
1442
+ const config = loadAgentConfig();
1443
+ config[agentId] = { runtime, model };
1444
+ saveAgentConfig(config);
1445
+ return { ok: true };
1446
+ }
1447
+ function clearAgentRuntime(agentId) {
1448
+ const config = loadAgentConfig();
1449
+ delete config[agentId];
1450
+ saveAgentConfig(config);
1451
+ }
1452
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
1453
+ var init_agent_config = __esm({
1454
+ "src/lib/agent-config.ts"() {
1455
+ "use strict";
1456
+ init_config();
1457
+ init_runtime_table();
1458
+ AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
1459
+ KNOWN_RUNTIMES = {
1460
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
1461
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
1462
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
1463
+ };
1464
+ RUNTIME_LABELS = {
1465
+ claude: "Claude Code (Anthropic)",
1466
+ codex: "Codex (OpenAI)",
1467
+ opencode: "OpenCode (open source)"
1468
+ };
1469
+ DEFAULT_MODELS = {
1470
+ claude: "claude-opus-4",
1471
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
1472
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
1473
+ };
1474
+ }
1475
+ });
1476
+
1312
1477
  // src/lib/employees.ts
1313
1478
  var employees_exports = {};
1314
1479
  __export(employees_exports, {
@@ -1324,6 +1489,7 @@ __export(employees_exports, {
1324
1489
  getEmployeeByRole: () => getEmployeeByRole,
1325
1490
  getEmployeeNamesByRole: () => getEmployeeNamesByRole,
1326
1491
  hasRole: () => hasRole,
1492
+ hireEmployee: () => hireEmployee,
1327
1493
  isCoordinatorName: () => isCoordinatorName,
1328
1494
  isCoordinatorRole: () => isCoordinatorRole,
1329
1495
  isMultiInstance: () => isMultiInstance,
@@ -1336,9 +1502,9 @@ __export(employees_exports, {
1336
1502
  validateEmployeeName: () => validateEmployeeName
1337
1503
  });
1338
1504
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
1339
- import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync4, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "fs";
1505
+ import { existsSync as existsSync7, symlinkSync, readlinkSync, readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
1340
1506
  import { execSync } from "child_process";
1341
- import path6 from "path";
1507
+ import path7 from "path";
1342
1508
  import os4 from "os";
1343
1509
  function normalizeRole(role) {
1344
1510
  return (role ?? "").trim().toLowerCase();
@@ -1375,7 +1541,7 @@ function validateEmployeeName(name) {
1375
1541
  return { valid: true };
1376
1542
  }
1377
1543
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
1378
- if (!existsSync6(employeesPath)) {
1544
+ if (!existsSync7(employeesPath)) {
1379
1545
  return [];
1380
1546
  }
1381
1547
  const raw = await readFile3(employeesPath, "utf-8");
@@ -1386,13 +1552,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
1386
1552
  }
1387
1553
  }
1388
1554
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
1389
- await mkdir4(path6.dirname(employeesPath), { recursive: true });
1555
+ await mkdir4(path7.dirname(employeesPath), { recursive: true });
1390
1556
  await writeFile3(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
1391
1557
  }
1392
1558
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
1393
- if (!existsSync6(employeesPath)) return [];
1559
+ if (!existsSync7(employeesPath)) return [];
1394
1560
  try {
1395
- return JSON.parse(readFileSync4(employeesPath, "utf-8"));
1561
+ return JSON.parse(readFileSync5(employeesPath, "utf-8"));
1396
1562
  } catch {
1397
1563
  return [];
1398
1564
  }
@@ -1434,6 +1600,52 @@ function addEmployee(employees, employee) {
1434
1600
  }
1435
1601
  return [...employees, normalized];
1436
1602
  }
1603
+ function appendToCoordinatorTeam(employee) {
1604
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
1605
+ 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");
1609
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
1610
+ const teamMatch = content.match(TEAM_SECTION_RE);
1611
+ if (!teamMatch || teamMatch.index === void 0) return;
1612
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
1613
+ const nextHeading = afterTeam.match(/\n## /);
1614
+ const entry = `
1615
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
1616
+ `;
1617
+ let updated;
1618
+ if (nextHeading && nextHeading.index !== void 0) {
1619
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
1620
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
1621
+ } else {
1622
+ updated = content.trimEnd() + "\n" + entry;
1623
+ }
1624
+ writeFileSync3(idPath, updated, "utf-8");
1625
+ }
1626
+ function capitalize(s) {
1627
+ return s.charAt(0).toUpperCase() + s.slice(1);
1628
+ }
1629
+ async function hireEmployee(employee) {
1630
+ const employees = await loadEmployees();
1631
+ const updated = addEmployee(employees, employee);
1632
+ await saveEmployees(updated);
1633
+ try {
1634
+ appendToCoordinatorTeam(employee);
1635
+ } catch {
1636
+ }
1637
+ try {
1638
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
1639
+ const config = loadAgentConfig2();
1640
+ const name = employee.name.toLowerCase();
1641
+ if (!config[name] && config["default"]) {
1642
+ config[name] = { ...config["default"] };
1643
+ saveAgentConfig2(config);
1644
+ }
1645
+ } catch {
1646
+ }
1647
+ return updated;
1648
+ }
1437
1649
  async function normalizeRosterCase(rosterPath) {
1438
1650
  const employees = await loadEmployees(rosterPath);
1439
1651
  let changed = false;
@@ -1443,14 +1655,14 @@ async function normalizeRosterCase(rosterPath) {
1443
1655
  emp.name = emp.name.toLowerCase();
1444
1656
  changed = true;
1445
1657
  try {
1446
- const identityDir = path6.join(os4.homedir(), ".exe-os", "identity");
1447
- const oldPath = path6.join(identityDir, `${oldName}.md`);
1448
- const newPath = path6.join(identityDir, `${emp.name}.md`);
1449
- if (existsSync6(oldPath) && !existsSync6(newPath)) {
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)) {
1450
1662
  renameSync3(oldPath, newPath);
1451
- } else if (existsSync6(oldPath) && oldPath !== newPath) {
1452
- const content = readFileSync4(oldPath, "utf-8");
1453
- writeFileSync2(newPath, content, "utf-8");
1663
+ } else if (existsSync7(oldPath) && oldPath !== newPath) {
1664
+ const content = readFileSync5(oldPath, "utf-8");
1665
+ writeFileSync3(newPath, content, "utf-8");
1454
1666
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
1455
1667
  unlinkSync3(oldPath);
1456
1668
  }
@@ -1480,7 +1692,7 @@ function registerBinSymlinks(name) {
1480
1692
  errors.push("Could not find 'exe-os' in PATH");
1481
1693
  return { created, skipped, errors };
1482
1694
  }
1483
- const binDir = path6.dirname(exeBinPath);
1695
+ const binDir = path7.dirname(exeBinPath);
1484
1696
  let target;
1485
1697
  try {
1486
1698
  target = readlinkSync(exeBinPath);
@@ -1490,8 +1702,8 @@ function registerBinSymlinks(name) {
1490
1702
  }
1491
1703
  for (const suffix of ["", "-opencode"]) {
1492
1704
  const linkName = `${name}${suffix}`;
1493
- const linkPath = path6.join(binDir, linkName);
1494
- if (existsSync6(linkPath)) {
1705
+ const linkPath = path7.join(binDir, linkName);
1706
+ if (existsSync7(linkPath)) {
1495
1707
  skipped.push(linkName);
1496
1708
  continue;
1497
1709
  }
@@ -1504,15 +1716,601 @@ function registerBinSymlinks(name) {
1504
1716
  }
1505
1717
  return { created, skipped, errors };
1506
1718
  }
1507
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
1719
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
1508
1720
  var init_employees = __esm({
1509
1721
  "src/lib/employees.ts"() {
1510
1722
  "use strict";
1511
1723
  init_config();
1512
- EMPLOYEES_PATH = path6.join(EXE_AI_DIR, "exe-employees.json");
1724
+ EMPLOYEES_PATH = path7.join(EXE_AI_DIR, "exe-employees.json");
1513
1725
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
1514
1726
  COORDINATOR_ROLE = "COO";
1515
1727
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
1728
+ IDENTITY_DIR = path7.join(EXE_AI_DIR, "identity");
1729
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
1730
+ }
1731
+ });
1732
+
1733
+ // 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";
1738
+ function quotedIdentifier(identifier) {
1739
+ return `"${identifier.replace(/"/g, '""')}"`;
1740
+ }
1741
+ function unqualifiedTableName(name) {
1742
+ const raw = name.trim().replace(/^"|"$/g, "");
1743
+ const parts = raw.split(".");
1744
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
1745
+ }
1746
+ function stripTrailingSemicolon(sql) {
1747
+ return sql.trim().replace(/;+\s*$/u, "");
1748
+ }
1749
+ function appendClause(sql, clause) {
1750
+ const trimmed = stripTrailingSemicolon(sql);
1751
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
1752
+ if (!returningMatch) {
1753
+ return `${trimmed}${clause}`;
1754
+ }
1755
+ const idx = returningMatch.index;
1756
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
1757
+ }
1758
+ function normalizeStatement(stmt) {
1759
+ if (typeof stmt === "string") {
1760
+ return { kind: "positional", sql: stmt, args: [] };
1761
+ }
1762
+ const sql = stmt.sql;
1763
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
1764
+ return { kind: "positional", sql, args: stmt.args ?? [] };
1765
+ }
1766
+ return { kind: "named", sql, args: stmt.args };
1767
+ }
1768
+ function rewriteBooleanLiterals(sql) {
1769
+ let out = sql;
1770
+ for (const column of BOOLEAN_COLUMN_NAMES) {
1771
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
1772
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
1773
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
1774
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
1775
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
1776
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
1777
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
1778
+ }
1779
+ return out;
1780
+ }
1781
+ function rewriteInsertOrIgnore(sql) {
1782
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
1783
+ return sql;
1784
+ }
1785
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
1786
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
1787
+ }
1788
+ function rewriteInsertOrReplace(sql) {
1789
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
1790
+ if (!match) {
1791
+ return sql;
1792
+ }
1793
+ const rawTable = match[1];
1794
+ const rawColumns = match[2];
1795
+ const remainder = match[3];
1796
+ const tableName = unqualifiedTableName(rawTable);
1797
+ const conflictKeys = UPSERT_KEYS[tableName];
1798
+ if (!conflictKeys?.length) {
1799
+ return sql;
1800
+ }
1801
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
1802
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
1803
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
1804
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
1805
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
1806
+ }
1807
+ function rewriteSql(sql) {
1808
+ let out = sql;
1809
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
1810
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
1811
+ out = rewriteBooleanLiterals(out);
1812
+ out = rewriteInsertOrReplace(out);
1813
+ out = rewriteInsertOrIgnore(out);
1814
+ return stripTrailingSemicolon(out);
1815
+ }
1816
+ function toBoolean(value) {
1817
+ if (value === null || value === void 0) return value;
1818
+ if (typeof value === "boolean") return value;
1819
+ if (typeof value === "number") return value !== 0;
1820
+ if (typeof value === "bigint") return value !== 0n;
1821
+ if (typeof value === "string") {
1822
+ const normalized = value.trim().toLowerCase();
1823
+ if (normalized === "0" || normalized === "false") return false;
1824
+ if (normalized === "1" || normalized === "true") return true;
1825
+ }
1826
+ return Boolean(value);
1827
+ }
1828
+ function countQuestionMarks(sql, end) {
1829
+ let count = 0;
1830
+ let inSingle = false;
1831
+ let inDouble = false;
1832
+ let inLineComment = false;
1833
+ let inBlockComment = false;
1834
+ for (let i = 0; i < end; i++) {
1835
+ const ch = sql[i];
1836
+ const next = sql[i + 1];
1837
+ if (inLineComment) {
1838
+ if (ch === "\n") inLineComment = false;
1839
+ continue;
1840
+ }
1841
+ if (inBlockComment) {
1842
+ if (ch === "*" && next === "/") {
1843
+ inBlockComment = false;
1844
+ i += 1;
1845
+ }
1846
+ continue;
1847
+ }
1848
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1849
+ inLineComment = true;
1850
+ i += 1;
1851
+ continue;
1852
+ }
1853
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1854
+ inBlockComment = true;
1855
+ i += 1;
1856
+ continue;
1857
+ }
1858
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1859
+ inSingle = !inSingle;
1860
+ continue;
1861
+ }
1862
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1863
+ inDouble = !inDouble;
1864
+ continue;
1865
+ }
1866
+ if (!inSingle && !inDouble && ch === "?") {
1867
+ count += 1;
1868
+ }
1869
+ }
1870
+ return count;
1871
+ }
1872
+ function findBooleanPlaceholderIndexes(sql) {
1873
+ const indexes = /* @__PURE__ */ new Set();
1874
+ for (const column of BOOLEAN_COLUMN_NAMES) {
1875
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
1876
+ for (const match of sql.matchAll(pattern)) {
1877
+ const matchText = match[0];
1878
+ const qIndex = match.index + matchText.lastIndexOf("?");
1879
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
1880
+ }
1881
+ }
1882
+ return indexes;
1883
+ }
1884
+ function coerceInsertBooleanArgs(sql, args2) {
1885
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
1886
+ if (!match) return;
1887
+ const rawTable = match[1];
1888
+ const rawColumns = match[2];
1889
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
1890
+ if (!boolColumns?.size) return;
1891
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
1892
+ for (const [index, column] of columns.entries()) {
1893
+ if (boolColumns.has(column) && index < args2.length) {
1894
+ args2[index] = toBoolean(args2[index]);
1895
+ }
1896
+ }
1897
+ }
1898
+ function coerceUpdateBooleanArgs(sql, args2) {
1899
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
1900
+ if (!match) return;
1901
+ const rawTable = match[1];
1902
+ const setClause = match[2];
1903
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
1904
+ if (!boolColumns?.size) return;
1905
+ const assignments = setClause.split(",");
1906
+ let placeholderIndex = 0;
1907
+ for (const assignment of assignments) {
1908
+ if (!assignment.includes("?")) continue;
1909
+ placeholderIndex += 1;
1910
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
1911
+ if (colMatch && boolColumns.has(colMatch[1])) {
1912
+ args2[placeholderIndex - 1] = toBoolean(args2[placeholderIndex - 1]);
1913
+ }
1914
+ }
1915
+ }
1916
+ function coerceBooleanArgs(sql, args2) {
1917
+ const nextArgs = [...args2];
1918
+ coerceInsertBooleanArgs(sql, nextArgs);
1919
+ coerceUpdateBooleanArgs(sql, nextArgs);
1920
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
1921
+ for (const index of placeholderIndexes) {
1922
+ if (index > 0 && index <= nextArgs.length) {
1923
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
1924
+ }
1925
+ }
1926
+ return nextArgs;
1927
+ }
1928
+ function convertQuestionMarksToDollarParams(sql) {
1929
+ let out = "";
1930
+ let placeholder = 0;
1931
+ let inSingle = false;
1932
+ let inDouble = false;
1933
+ let inLineComment = false;
1934
+ let inBlockComment = false;
1935
+ for (let i = 0; i < sql.length; i++) {
1936
+ const ch = sql[i];
1937
+ const next = sql[i + 1];
1938
+ if (inLineComment) {
1939
+ out += ch;
1940
+ if (ch === "\n") inLineComment = false;
1941
+ continue;
1942
+ }
1943
+ if (inBlockComment) {
1944
+ out += ch;
1945
+ if (ch === "*" && next === "/") {
1946
+ out += next;
1947
+ inBlockComment = false;
1948
+ i += 1;
1949
+ }
1950
+ continue;
1951
+ }
1952
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1953
+ out += ch + next;
1954
+ inLineComment = true;
1955
+ i += 1;
1956
+ continue;
1957
+ }
1958
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1959
+ out += ch + next;
1960
+ inBlockComment = true;
1961
+ i += 1;
1962
+ continue;
1963
+ }
1964
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1965
+ inSingle = !inSingle;
1966
+ out += ch;
1967
+ continue;
1968
+ }
1969
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1970
+ inDouble = !inDouble;
1971
+ out += ch;
1972
+ continue;
1973
+ }
1974
+ if (!inSingle && !inDouble && ch === "?") {
1975
+ placeholder += 1;
1976
+ out += `$${placeholder}`;
1977
+ continue;
1978
+ }
1979
+ out += ch;
1980
+ }
1981
+ return out;
1982
+ }
1983
+ function translateStatementForPostgres(stmt) {
1984
+ const normalized = normalizeStatement(stmt);
1985
+ if (normalized.kind === "named") {
1986
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
1987
+ }
1988
+ const rewrittenSql = rewriteSql(normalized.sql);
1989
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
1990
+ return {
1991
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
1992
+ args: coercedArgs
1993
+ };
1994
+ }
1995
+ function shouldBypassPostgres(stmt) {
1996
+ const normalized = normalizeStatement(stmt);
1997
+ if (normalized.kind === "named") {
1998
+ return true;
1999
+ }
2000
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
2001
+ }
2002
+ function shouldFallbackOnError(error) {
2003
+ const message = error instanceof Error ? error.message : String(error);
2004
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
2005
+ }
2006
+ function isReadQuery(sql) {
2007
+ const trimmed = sql.trimStart();
2008
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
2009
+ }
2010
+ function buildRow(row, columns) {
2011
+ const values = columns.map((column) => row[column]);
2012
+ return Object.assign(values, row);
2013
+ }
2014
+ function buildResultSet(rows, rowsAffected = 0) {
2015
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
2016
+ const resultRows = rows.map((row) => buildRow(row, columns));
2017
+ return {
2018
+ columns,
2019
+ columnTypes: columns.map(() => ""),
2020
+ rows: resultRows,
2021
+ rowsAffected,
2022
+ lastInsertRowid: void 0,
2023
+ toJSON() {
2024
+ return {
2025
+ columns,
2026
+ columnTypes: columns.map(() => ""),
2027
+ rows,
2028
+ rowsAffected,
2029
+ lastInsertRowid: void 0
2030
+ };
2031
+ }
2032
+ };
2033
+ }
2034
+ async function loadPrismaClient() {
2035
+ if (!prismaClientPromise) {
2036
+ prismaClientPromise = (async () => {
2037
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
2038
+ if (explicitPath) {
2039
+ const module2 = await import(pathToFileURL(explicitPath).href);
2040
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
2041
+ if (!PrismaClient2) {
2042
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
2043
+ }
2044
+ return new PrismaClient2();
2045
+ }
2046
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path8.join(os5.homedir(), "exe-db");
2047
+ const requireFromExeDb = createRequire(path8.join(exeDbRoot, "package.json"));
2048
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
2049
+ const module = await import(pathToFileURL(prismaEntry).href);
2050
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
2051
+ if (!PrismaClient) {
2052
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
2053
+ }
2054
+ return new PrismaClient();
2055
+ })();
2056
+ }
2057
+ return prismaClientPromise;
2058
+ }
2059
+ async function ensureCompatibilityViews(prisma) {
2060
+ if (!compatibilityBootstrapPromise) {
2061
+ compatibilityBootstrapPromise = (async () => {
2062
+ for (const mapping of VIEW_MAPPINGS) {
2063
+ const relation = mapping.source.replace(/"/g, "");
2064
+ const rows = await prisma.$queryRawUnsafe(
2065
+ "SELECT to_regclass($1) AS regclass",
2066
+ relation
2067
+ );
2068
+ if (!rows[0]?.regclass) {
2069
+ continue;
2070
+ }
2071
+ await prisma.$executeRawUnsafe(
2072
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
2073
+ );
2074
+ }
2075
+ })();
2076
+ }
2077
+ return compatibilityBootstrapPromise;
2078
+ }
2079
+ async function executeOnPrisma(executor, stmt) {
2080
+ const translated = translateStatementForPostgres(stmt);
2081
+ if (isReadQuery(translated.sql)) {
2082
+ const rows = await executor.$queryRawUnsafe(
2083
+ translated.sql,
2084
+ ...translated.args
2085
+ );
2086
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
2087
+ }
2088
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
2089
+ return buildResultSet([], rowsAffected);
2090
+ }
2091
+ function splitSqlStatements(sql) {
2092
+ const parts = [];
2093
+ let current = "";
2094
+ let inSingle = false;
2095
+ let inDouble = false;
2096
+ let inLineComment = false;
2097
+ let inBlockComment = false;
2098
+ for (let i = 0; i < sql.length; i++) {
2099
+ const ch = sql[i];
2100
+ const next = sql[i + 1];
2101
+ if (inLineComment) {
2102
+ current += ch;
2103
+ if (ch === "\n") inLineComment = false;
2104
+ continue;
2105
+ }
2106
+ if (inBlockComment) {
2107
+ current += ch;
2108
+ if (ch === "*" && next === "/") {
2109
+ current += next;
2110
+ inBlockComment = false;
2111
+ i += 1;
2112
+ }
2113
+ continue;
2114
+ }
2115
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
2116
+ current += ch + next;
2117
+ inLineComment = true;
2118
+ i += 1;
2119
+ continue;
2120
+ }
2121
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
2122
+ current += ch + next;
2123
+ inBlockComment = true;
2124
+ i += 1;
2125
+ continue;
2126
+ }
2127
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
2128
+ inSingle = !inSingle;
2129
+ current += ch;
2130
+ continue;
2131
+ }
2132
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
2133
+ inDouble = !inDouble;
2134
+ current += ch;
2135
+ continue;
2136
+ }
2137
+ if (!inSingle && !inDouble && ch === ";") {
2138
+ if (current.trim()) {
2139
+ parts.push(current.trim());
2140
+ }
2141
+ current = "";
2142
+ continue;
2143
+ }
2144
+ current += ch;
2145
+ }
2146
+ if (current.trim()) {
2147
+ parts.push(current.trim());
2148
+ }
2149
+ return parts;
2150
+ }
2151
+ async function createPrismaDbAdapter(fallbackClient) {
2152
+ const prisma = await loadPrismaClient();
2153
+ await ensureCompatibilityViews(prisma);
2154
+ let closed = false;
2155
+ let adapter;
2156
+ const fallbackExecute = async (stmt, error) => {
2157
+ if (!fallbackClient) {
2158
+ if (error) throw error;
2159
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
2160
+ }
2161
+ if (error) {
2162
+ process.stderr.write(
2163
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
2164
+ `
2165
+ );
2166
+ }
2167
+ return fallbackClient.execute(stmt);
2168
+ };
2169
+ adapter = {
2170
+ async execute(stmt) {
2171
+ if (shouldBypassPostgres(stmt)) {
2172
+ return fallbackExecute(stmt);
2173
+ }
2174
+ try {
2175
+ return await executeOnPrisma(prisma, stmt);
2176
+ } catch (error) {
2177
+ if (shouldFallbackOnError(error)) {
2178
+ return fallbackExecute(stmt, error);
2179
+ }
2180
+ throw error;
2181
+ }
2182
+ },
2183
+ async batch(stmts, mode) {
2184
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
2185
+ if (!fallbackClient) {
2186
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
2187
+ }
2188
+ return fallbackClient.batch(stmts, mode);
2189
+ }
2190
+ try {
2191
+ if (prisma.$transaction) {
2192
+ return await prisma.$transaction(async (tx) => {
2193
+ const results2 = [];
2194
+ for (const stmt of stmts) {
2195
+ results2.push(await executeOnPrisma(tx, stmt));
2196
+ }
2197
+ return results2;
2198
+ });
2199
+ }
2200
+ const results = [];
2201
+ for (const stmt of stmts) {
2202
+ results.push(await executeOnPrisma(prisma, stmt));
2203
+ }
2204
+ return results;
2205
+ } catch (error) {
2206
+ if (fallbackClient && shouldFallbackOnError(error)) {
2207
+ process.stderr.write(
2208
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
2209
+ `
2210
+ );
2211
+ return fallbackClient.batch(stmts, mode);
2212
+ }
2213
+ throw error;
2214
+ }
2215
+ },
2216
+ async migrate(stmts) {
2217
+ if (fallbackClient) {
2218
+ return fallbackClient.migrate(stmts);
2219
+ }
2220
+ return adapter.batch(stmts, "deferred");
2221
+ },
2222
+ async transaction(mode) {
2223
+ if (!fallbackClient) {
2224
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
2225
+ }
2226
+ return fallbackClient.transaction(mode);
2227
+ },
2228
+ async executeMultiple(sql) {
2229
+ if (fallbackClient && shouldBypassPostgres(sql)) {
2230
+ return fallbackClient.executeMultiple(sql);
2231
+ }
2232
+ for (const statement of splitSqlStatements(sql)) {
2233
+ await adapter.execute(statement);
2234
+ }
2235
+ },
2236
+ async sync() {
2237
+ if (fallbackClient) {
2238
+ return fallbackClient.sync();
2239
+ }
2240
+ return { frame_no: 0, frames_synced: 0 };
2241
+ },
2242
+ close() {
2243
+ closed = true;
2244
+ prismaClientPromise = null;
2245
+ compatibilityBootstrapPromise = null;
2246
+ void prisma.$disconnect?.();
2247
+ },
2248
+ get closed() {
2249
+ return closed;
2250
+ },
2251
+ get protocol() {
2252
+ return "prisma-postgres";
2253
+ }
2254
+ };
2255
+ return adapter;
2256
+ }
2257
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
2258
+ var init_database_adapter = __esm({
2259
+ "src/lib/database-adapter.ts"() {
2260
+ "use strict";
2261
+ VIEW_MAPPINGS = [
2262
+ { view: "memories", source: "memory.memory_records" },
2263
+ { view: "tasks", source: "memory.tasks" },
2264
+ { view: "behaviors", source: "memory.behaviors" },
2265
+ { view: "entities", source: "memory.entities" },
2266
+ { view: "relationships", source: "memory.relationships" },
2267
+ { view: "entity_memories", source: "memory.entity_memories" },
2268
+ { view: "entity_aliases", source: "memory.entity_aliases" },
2269
+ { view: "notifications", source: "memory.notifications" },
2270
+ { view: "messages", source: "memory.messages" },
2271
+ { view: "users", source: "wiki.users" },
2272
+ { view: "workspaces", source: "wiki.workspaces" },
2273
+ { view: "workspace_users", source: "wiki.workspace_users" },
2274
+ { view: "documents", source: "wiki.workspace_documents" },
2275
+ { view: "chats", source: "wiki.workspace_chats" }
2276
+ ];
2277
+ UPSERT_KEYS = {
2278
+ memories: ["id"],
2279
+ tasks: ["id"],
2280
+ behaviors: ["id"],
2281
+ entities: ["id"],
2282
+ relationships: ["id"],
2283
+ entity_aliases: ["alias"],
2284
+ notifications: ["id"],
2285
+ messages: ["id"],
2286
+ users: ["id"],
2287
+ workspaces: ["id"],
2288
+ workspace_users: ["id"],
2289
+ documents: ["id"],
2290
+ chats: ["id"]
2291
+ };
2292
+ BOOLEAN_COLUMNS_BY_TABLE = {
2293
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
2294
+ behaviors: /* @__PURE__ */ new Set(["active"]),
2295
+ notifications: /* @__PURE__ */ new Set(["read"]),
2296
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
2297
+ };
2298
+ BOOLEAN_COLUMN_NAMES = new Set(
2299
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
2300
+ );
2301
+ IMMEDIATE_FALLBACK_PATTERNS = [
2302
+ /\bPRAGMA\b/i,
2303
+ /\bsqlite_master\b/i,
2304
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
2305
+ /\bMATCH\b/i,
2306
+ /\bvector_distance_cos\s*\(/i,
2307
+ /\bjson_extract\s*\(/i,
2308
+ /\bjulianday\s*\(/i,
2309
+ /\bstrftime\s*\(/i,
2310
+ /\blast_insert_rowid\s*\(/i
2311
+ ];
2312
+ prismaClientPromise = null;
2313
+ compatibilityBootstrapPromise = null;
1516
2314
  }
1517
2315
  });
1518
2316
 
@@ -1586,7 +2384,7 @@ __export(db_daemon_client_exports, {
1586
2384
  createDaemonDbClient: () => createDaemonDbClient,
1587
2385
  initDaemonDbClient: () => initDaemonDbClient
1588
2386
  });
1589
- function normalizeStatement(stmt) {
2387
+ function normalizeStatement2(stmt) {
1590
2388
  if (typeof stmt === "string") {
1591
2389
  return { sql: stmt, args: [] };
1592
2390
  }
@@ -1610,7 +2408,7 @@ function createDaemonDbClient(fallbackClient) {
1610
2408
  if (!_useDaemon || !isClientConnected()) {
1611
2409
  return fallbackClient.execute(stmt);
1612
2410
  }
1613
- const { sql, args: args2 } = normalizeStatement(stmt);
2411
+ const { sql, args: args2 } = normalizeStatement2(stmt);
1614
2412
  const response = await sendDaemonRequest({
1615
2413
  type: "db-execute",
1616
2414
  sql,
@@ -1635,7 +2433,7 @@ function createDaemonDbClient(fallbackClient) {
1635
2433
  if (!_useDaemon || !isClientConnected()) {
1636
2434
  return fallbackClient.batch(stmts, mode);
1637
2435
  }
1638
- const statements = stmts.map(normalizeStatement);
2436
+ const statements = stmts.map(normalizeStatement2);
1639
2437
  const response = await sendDaemonRequest({
1640
2438
  type: "db-batch",
1641
2439
  statements,
@@ -1730,6 +2528,18 @@ __export(database_exports, {
1730
2528
  });
1731
2529
  import { createClient } from "@libsql/client";
1732
2530
  async function initDatabase(config) {
2531
+ if (_walCheckpointTimer) {
2532
+ clearInterval(_walCheckpointTimer);
2533
+ _walCheckpointTimer = null;
2534
+ }
2535
+ if (_daemonClient) {
2536
+ _daemonClient.close();
2537
+ _daemonClient = null;
2538
+ }
2539
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2540
+ _adapterClient.close();
2541
+ }
2542
+ _adapterClient = null;
1733
2543
  if (_client) {
1734
2544
  _client.close();
1735
2545
  _client = null;
@@ -1743,6 +2553,7 @@ async function initDatabase(config) {
1743
2553
  }
1744
2554
  _client = createClient(opts);
1745
2555
  _resilientClient = wrapWithRetry(_client);
2556
+ _adapterClient = _resilientClient;
1746
2557
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1747
2558
  });
1748
2559
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -1753,14 +2564,20 @@ async function initDatabase(config) {
1753
2564
  });
1754
2565
  }, 3e4);
1755
2566
  _walCheckpointTimer.unref();
2567
+ if (process.env.DATABASE_URL) {
2568
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
2569
+ }
1756
2570
  }
1757
2571
  function isInitialized() {
1758
- return _client !== null;
2572
+ return _adapterClient !== null || _client !== null;
1759
2573
  }
1760
2574
  function getClient() {
1761
- if (!_resilientClient) {
2575
+ if (!_adapterClient) {
1762
2576
  throw new Error("Database client not initialized. Call initDatabase() first.");
1763
2577
  }
2578
+ if (process.env.DATABASE_URL) {
2579
+ return _adapterClient;
2580
+ }
1764
2581
  if (process.env.EXE_IS_DAEMON === "1") {
1765
2582
  return _resilientClient;
1766
2583
  }
@@ -1770,6 +2587,7 @@ function getClient() {
1770
2587
  return _resilientClient;
1771
2588
  }
1772
2589
  async function initDaemonClient() {
2590
+ if (process.env.DATABASE_URL) return;
1773
2591
  if (process.env.EXE_IS_DAEMON === "1") return;
1774
2592
  if (!_resilientClient) return;
1775
2593
  try {
@@ -2714,26 +3532,36 @@ async function ensureSchema() {
2714
3532
  }
2715
3533
  }
2716
3534
  async function disposeDatabase() {
3535
+ if (_walCheckpointTimer) {
3536
+ clearInterval(_walCheckpointTimer);
3537
+ _walCheckpointTimer = null;
3538
+ }
2717
3539
  if (_daemonClient) {
2718
3540
  _daemonClient.close();
2719
3541
  _daemonClient = null;
2720
3542
  }
3543
+ if (_adapterClient && _adapterClient !== _resilientClient) {
3544
+ _adapterClient.close();
3545
+ }
3546
+ _adapterClient = null;
2721
3547
  if (_client) {
2722
3548
  _client.close();
2723
3549
  _client = null;
2724
3550
  _resilientClient = null;
2725
3551
  }
2726
3552
  }
2727
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
3553
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
2728
3554
  var init_database = __esm({
2729
3555
  "src/lib/database.ts"() {
2730
3556
  "use strict";
2731
3557
  init_db_retry();
2732
3558
  init_employees();
3559
+ init_database_adapter();
2733
3560
  _client = null;
2734
3561
  _resilientClient = null;
2735
3562
  _walCheckpointTimer = null;
2736
3563
  _daemonClient = null;
3564
+ _adapterClient = null;
2737
3565
  initTurso = initDatabase;
2738
3566
  disposeTurso = disposeDatabase;
2739
3567
  }
@@ -2778,8 +3606,8 @@ __export(crdt_sync_exports, {
2778
3606
  rebuildFromDb: () => rebuildFromDb
2779
3607
  });
2780
3608
  import * as Y from "yjs";
2781
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync2, unlinkSync as unlinkSync4 } from "fs";
2782
- import path7 from "path";
3609
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync3, unlinkSync as unlinkSync4 } from "fs";
3610
+ import path9 from "path";
2783
3611
  import { homedir } from "os";
2784
3612
  function getStatePath() {
2785
3613
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -2791,9 +3619,9 @@ function initCrdtDoc() {
2791
3619
  if (doc) return doc;
2792
3620
  doc = new Y.Doc();
2793
3621
  const sp = getStatePath();
2794
- if (existsSync7(sp)) {
3622
+ if (existsSync8(sp)) {
2795
3623
  try {
2796
- const state = readFileSync5(sp);
3624
+ const state = readFileSync6(sp);
2797
3625
  Y.applyUpdate(doc, new Uint8Array(state));
2798
3626
  } catch {
2799
3627
  console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
@@ -2935,10 +3763,10 @@ function persistState() {
2935
3763
  if (!doc) return;
2936
3764
  try {
2937
3765
  const sp = getStatePath();
2938
- const dir = path7.dirname(sp);
2939
- if (!existsSync7(dir)) mkdirSync2(dir, { recursive: true });
3766
+ const dir = path9.dirname(sp);
3767
+ if (!existsSync8(dir)) mkdirSync3(dir, { recursive: true });
2940
3768
  const state = Y.encodeStateAsUpdate(doc);
2941
- writeFileSync3(sp, Buffer.from(state));
3769
+ writeFileSync4(sp, Buffer.from(state));
2942
3770
  } catch {
2943
3771
  }
2944
3772
  }
@@ -2979,7 +3807,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
2979
3807
  var init_crdt_sync = __esm({
2980
3808
  "src/lib/crdt-sync.ts"() {
2981
3809
  "use strict";
2982
- DEFAULT_STATE_PATH = path7.join(homedir(), ".exe-os", "crdt-state.bin");
3810
+ DEFAULT_STATE_PATH = path9.join(homedir(), ".exe-os", "crdt-state.bin");
2983
3811
  _statePathOverride = null;
2984
3812
  doc = null;
2985
3813
  }
@@ -3013,16 +3841,16 @@ __export(cloud_sync_exports, {
3013
3841
  mergeRosterFromRemote: () => mergeRosterFromRemote,
3014
3842
  recordRosterDeletion: () => recordRosterDeletion
3015
3843
  });
3016
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync8, readdirSync, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
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";
3017
3845
  import crypto2 from "crypto";
3018
- import path8 from "path";
3846
+ import path10 from "path";
3019
3847
  import { homedir as homedir2 } from "os";
3020
3848
  function sqlSafe(v) {
3021
3849
  return v === void 0 ? null : v;
3022
3850
  }
3023
3851
  function logError(msg) {
3024
3852
  try {
3025
- const logPath = path8.join(homedir2(), ".exe-os", "workers.log");
3853
+ const logPath = path10.join(homedir2(), ".exe-os", "workers.log");
3026
3854
  appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
3027
3855
  `);
3028
3856
  } catch {
@@ -3032,18 +3860,18 @@ async function withRosterLock(fn) {
3032
3860
  try {
3033
3861
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
3034
3862
  closeSync2(fd);
3035
- writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
3863
+ writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
3036
3864
  } catch (err) {
3037
3865
  if (err.code === "EEXIST") {
3038
3866
  try {
3039
- const ts = parseInt(readFileSync6(ROSTER_LOCK_PATH, "utf-8"), 10);
3867
+ const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
3040
3868
  if (Date.now() - ts < LOCK_STALE_MS) {
3041
3869
  throw new Error("Roster merge already in progress \u2014 another sync is running");
3042
3870
  }
3043
3871
  unlinkSync5(ROSTER_LOCK_PATH);
3044
3872
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
3045
3873
  closeSync2(fd);
3046
- writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
3874
+ writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
3047
3875
  } catch (retryErr) {
3048
3876
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
3049
3877
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -3417,8 +4245,8 @@ async function cloudSync(config) {
3417
4245
  try {
3418
4246
  const employees = await loadEmployees();
3419
4247
  rosterResult.employees = employees.length;
3420
- const idDir = path8.join(EXE_AI_DIR, "identity");
3421
- if (existsSync8(idDir)) {
4248
+ const idDir = path10.join(EXE_AI_DIR, "identity");
4249
+ if (existsSync9(idDir)) {
3422
4250
  rosterResult.identities = readdirSync(idDir).filter((f) => f.endsWith(".md")).length;
3423
4251
  }
3424
4252
  } catch {
@@ -3439,56 +4267,56 @@ async function cloudSync(config) {
3439
4267
  function recordRosterDeletion(name) {
3440
4268
  let deletions = [];
3441
4269
  try {
3442
- if (existsSync8(ROSTER_DELETIONS_PATH)) {
3443
- deletions = JSON.parse(readFileSync6(ROSTER_DELETIONS_PATH, "utf-8"));
4270
+ if (existsSync9(ROSTER_DELETIONS_PATH)) {
4271
+ deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
3444
4272
  }
3445
4273
  } catch {
3446
4274
  }
3447
4275
  if (!deletions.includes(name)) deletions.push(name);
3448
- writeFileSync4(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
4276
+ writeFileSync5(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
3449
4277
  }
3450
4278
  function consumeRosterDeletions() {
3451
4279
  try {
3452
- if (!existsSync8(ROSTER_DELETIONS_PATH)) return [];
3453
- const deletions = JSON.parse(readFileSync6(ROSTER_DELETIONS_PATH, "utf-8"));
3454
- writeFileSync4(ROSTER_DELETIONS_PATH, "[]");
4280
+ if (!existsSync9(ROSTER_DELETIONS_PATH)) return [];
4281
+ const deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
4282
+ writeFileSync5(ROSTER_DELETIONS_PATH, "[]");
3455
4283
  return deletions;
3456
4284
  } catch {
3457
4285
  return [];
3458
4286
  }
3459
4287
  }
3460
4288
  function buildRosterBlob(paths) {
3461
- const rosterPath = paths?.rosterPath ?? path8.join(EXE_AI_DIR, "exe-employees.json");
3462
- const identityDir = paths?.identityDir ?? path8.join(EXE_AI_DIR, "identity");
3463
- const configPath = paths?.configPath ?? path8.join(EXE_AI_DIR, "config.json");
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");
3464
4292
  let roster = [];
3465
- if (existsSync8(rosterPath)) {
4293
+ if (existsSync9(rosterPath)) {
3466
4294
  try {
3467
- roster = JSON.parse(readFileSync6(rosterPath, "utf-8"));
4295
+ roster = JSON.parse(readFileSync7(rosterPath, "utf-8"));
3468
4296
  } catch {
3469
4297
  }
3470
4298
  }
3471
4299
  const identities = {};
3472
- if (existsSync8(identityDir)) {
4300
+ if (existsSync9(identityDir)) {
3473
4301
  for (const file of readdirSync(identityDir).filter((f) => f.endsWith(".md"))) {
3474
4302
  try {
3475
- identities[file] = readFileSync6(path8.join(identityDir, file), "utf-8");
4303
+ identities[file] = readFileSync7(path10.join(identityDir, file), "utf-8");
3476
4304
  } catch {
3477
4305
  }
3478
4306
  }
3479
4307
  }
3480
4308
  let config;
3481
- if (existsSync8(configPath)) {
4309
+ if (existsSync9(configPath)) {
3482
4310
  try {
3483
- config = JSON.parse(readFileSync6(configPath, "utf-8"));
4311
+ config = JSON.parse(readFileSync7(configPath, "utf-8"));
3484
4312
  } catch {
3485
4313
  }
3486
4314
  }
3487
4315
  let agentConfig;
3488
- const agentConfigPath = path8.join(EXE_AI_DIR, "agent-config.json");
3489
- if (existsSync8(agentConfigPath)) {
4316
+ const agentConfigPath = path10.join(EXE_AI_DIR, "agent-config.json");
4317
+ if (existsSync9(agentConfigPath)) {
3490
4318
  try {
3491
- agentConfig = JSON.parse(readFileSync6(agentConfigPath, "utf-8"));
4319
+ agentConfig = JSON.parse(readFileSync7(agentConfigPath, "utf-8"));
3492
4320
  } catch {
3493
4321
  }
3494
4322
  }
@@ -3564,23 +4392,23 @@ async function cloudPullRoster(config) {
3564
4392
  }
3565
4393
  }
3566
4394
  function mergeConfig(remoteConfig, configPath) {
3567
- const cfgPath = configPath ?? path8.join(EXE_AI_DIR, "config.json");
4395
+ const cfgPath = configPath ?? path10.join(EXE_AI_DIR, "config.json");
3568
4396
  let local = {};
3569
- if (existsSync8(cfgPath)) {
4397
+ if (existsSync9(cfgPath)) {
3570
4398
  try {
3571
- local = JSON.parse(readFileSync6(cfgPath, "utf-8"));
4399
+ local = JSON.parse(readFileSync7(cfgPath, "utf-8"));
3572
4400
  } catch {
3573
4401
  }
3574
4402
  }
3575
4403
  const merged = { ...remoteConfig, ...local };
3576
- const dir = path8.dirname(cfgPath);
3577
- if (!existsSync8(dir)) mkdirSync3(dir, { recursive: true });
3578
- writeFileSync4(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
4404
+ const dir = path10.dirname(cfgPath);
4405
+ if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
4406
+ writeFileSync5(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
3579
4407
  }
3580
4408
  async function mergeRosterFromRemote(remote, paths) {
3581
4409
  return withRosterLock(async () => {
3582
4410
  const rosterPath = paths?.rosterPath ?? void 0;
3583
- const identityDir = paths?.identityDir ?? path8.join(EXE_AI_DIR, "identity");
4411
+ const identityDir = paths?.identityDir ?? path10.join(EXE_AI_DIR, "identity");
3584
4412
  const localEmployees = await loadEmployees(rosterPath);
3585
4413
  const localNames = new Set(localEmployees.map((e) => e.name));
3586
4414
  let added = 0;
@@ -3601,15 +4429,15 @@ async function mergeRosterFromRemote(remote, paths) {
3601
4429
  ) ?? lookupKey;
3602
4430
  const remoteIdentity = remote.identities[matchedKey];
3603
4431
  if (remoteIdentity) {
3604
- if (!existsSync8(identityDir)) mkdirSync3(identityDir, { recursive: true });
3605
- const idPath = path8.join(identityDir, `${remoteEmp.name}.md`);
4432
+ if (!existsSync9(identityDir)) mkdirSync4(identityDir, { recursive: true });
4433
+ const idPath = path10.join(identityDir, `${remoteEmp.name}.md`);
3606
4434
  let localIdentity = null;
3607
4435
  try {
3608
- localIdentity = existsSync8(idPath) ? readFileSync6(idPath, "utf-8") : null;
4436
+ localIdentity = existsSync9(idPath) ? readFileSync7(idPath, "utf-8") : null;
3609
4437
  } catch {
3610
4438
  }
3611
4439
  if (localIdentity !== remoteIdentity) {
3612
- writeFileSync4(idPath, remoteIdentity, "utf-8");
4440
+ writeFileSync5(idPath, remoteIdentity, "utf-8");
3613
4441
  identitiesUpdated++;
3614
4442
  }
3615
4443
  }
@@ -3635,16 +4463,16 @@ async function mergeRosterFromRemote(remote, paths) {
3635
4463
  }
3636
4464
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
3637
4465
  try {
3638
- const agentConfigPath = path8.join(EXE_AI_DIR, "agent-config.json");
4466
+ const agentConfigPath = path10.join(EXE_AI_DIR, "agent-config.json");
3639
4467
  let local = {};
3640
- if (existsSync8(agentConfigPath)) {
4468
+ if (existsSync9(agentConfigPath)) {
3641
4469
  try {
3642
- local = JSON.parse(readFileSync6(agentConfigPath, "utf-8"));
4470
+ local = JSON.parse(readFileSync7(agentConfigPath, "utf-8"));
3643
4471
  } catch {
3644
4472
  }
3645
4473
  }
3646
4474
  const merged = { ...remote.agentConfig, ...local };
3647
- writeFileSync4(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
4475
+ writeFileSync5(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
3648
4476
  } catch {
3649
4477
  }
3650
4478
  }
@@ -4082,9 +4910,9 @@ var init_cloud_sync = __esm({
4082
4910
  LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
4083
4911
  FETCH_TIMEOUT_MS = 3e4;
4084
4912
  PUSH_BATCH_SIZE = 5e3;
4085
- ROSTER_LOCK_PATH = path8.join(EXE_AI_DIR, "roster-merge.lock");
4913
+ ROSTER_LOCK_PATH = path10.join(EXE_AI_DIR, "roster-merge.lock");
4086
4914
  LOCK_STALE_MS = 3e4;
4087
- ROSTER_DELETIONS_PATH = path8.join(EXE_AI_DIR, "roster-deletions.json");
4915
+ ROSTER_DELETIONS_PATH = path10.join(EXE_AI_DIR, "roster-deletions.json");
4088
4916
  }
4089
4917
  });
4090
4918
 
@@ -4094,33 +4922,33 @@ __export(preferences_exports, {
4094
4922
  loadPreferences: () => loadPreferences,
4095
4923
  savePreferences: () => savePreferences
4096
4924
  });
4097
- import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4 } from "fs";
4098
- import path9 from "path";
4099
- import os5 from "os";
4100
- function loadPreferences(homeDir = os5.homedir()) {
4101
- const configPath = path9.join(homeDir, ".exe-os", "config.json");
4102
- if (!existsSync9(configPath)) return {};
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 {};
4103
4931
  try {
4104
- const config = JSON.parse(readFileSync7(configPath, "utf-8"));
4932
+ const config = JSON.parse(readFileSync8(configPath, "utf-8"));
4105
4933
  return config.preferences ?? {};
4106
4934
  } catch {
4107
4935
  return {};
4108
4936
  }
4109
4937
  }
4110
- function savePreferences(prefs, homeDir = os5.homedir()) {
4111
- const configDir = path9.join(homeDir, ".exe-os");
4112
- const configPath = path9.join(configDir, "config.json");
4113
- mkdirSync4(configDir, { recursive: true });
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 });
4114
4942
  let config = {};
4115
- if (existsSync9(configPath)) {
4943
+ if (existsSync10(configPath)) {
4116
4944
  try {
4117
- config = JSON.parse(readFileSync7(configPath, "utf-8"));
4945
+ config = JSON.parse(readFileSync8(configPath, "utf-8"));
4118
4946
  } catch {
4119
4947
  config = {};
4120
4948
  }
4121
4949
  }
4122
4950
  config.preferences = prefs;
4123
- writeFileSync5(configPath, JSON.stringify(config, null, 2) + "\n");
4951
+ writeFileSync6(configPath, JSON.stringify(config, null, 2) + "\n");
4124
4952
  }
4125
4953
  var init_preferences = __esm({
4126
4954
  "src/lib/preferences.ts"() {
@@ -4895,17 +5723,17 @@ __export(identity_exports, {
4895
5723
  listIdentities: () => listIdentities,
4896
5724
  updateIdentity: () => updateIdentity
4897
5725
  });
4898
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
5726
+ import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
4899
5727
  import { readdirSync as readdirSync2 } from "fs";
4900
- import path10 from "path";
5728
+ import path12 from "path";
4901
5729
  import { createHash as createHash2 } from "crypto";
4902
5730
  function ensureDir() {
4903
- if (!existsSync10(IDENTITY_DIR)) {
4904
- mkdirSync5(IDENTITY_DIR, { recursive: true });
5731
+ if (!existsSync11(IDENTITY_DIR2)) {
5732
+ mkdirSync6(IDENTITY_DIR2, { recursive: true });
4905
5733
  }
4906
5734
  }
4907
5735
  function identityPath(agentId) {
4908
- return path10.join(IDENTITY_DIR, `${agentId}.md`);
5736
+ return path12.join(IDENTITY_DIR2, `${agentId}.md`);
4909
5737
  }
4910
5738
  function parseFrontmatter(raw) {
4911
5739
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -4946,8 +5774,8 @@ function contentHash(content) {
4946
5774
  }
4947
5775
  function getIdentity(agentId) {
4948
5776
  const filePath = identityPath(agentId);
4949
- if (!existsSync10(filePath)) return null;
4950
- const raw = readFileSync8(filePath, "utf-8");
5777
+ if (!existsSync11(filePath)) return null;
5778
+ const raw = readFileSync9(filePath, "utf-8");
4951
5779
  const { frontmatter, body } = parseFrontmatter(raw);
4952
5780
  return {
4953
5781
  agentId,
@@ -4961,7 +5789,7 @@ async function updateIdentity(agentId, content, updatedBy) {
4961
5789
  ensureDir();
4962
5790
  const filePath = identityPath(agentId);
4963
5791
  const hash = contentHash(content);
4964
- writeFileSync6(filePath, content, "utf-8");
5792
+ writeFileSync7(filePath, content, "utf-8");
4965
5793
  try {
4966
5794
  const client = getClient();
4967
5795
  await client.execute({
@@ -4978,7 +5806,7 @@ async function updateIdentity(agentId, content, updatedBy) {
4978
5806
  }
4979
5807
  function listIdentities() {
4980
5808
  ensureDir();
4981
- const files = readdirSync2(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
5809
+ const files = readdirSync2(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
4982
5810
  const results = [];
4983
5811
  for (const file of files) {
4984
5812
  const agentId = file.replace(".md", "");
@@ -5011,13 +5839,13 @@ ${teamLines.join("\n")}`);
5011
5839
  }
5012
5840
  return parts.join("\n\n");
5013
5841
  }
5014
- var IDENTITY_DIR;
5842
+ var IDENTITY_DIR2;
5015
5843
  var init_identity = __esm({
5016
5844
  "src/lib/identity.ts"() {
5017
5845
  "use strict";
5018
5846
  init_config();
5019
5847
  init_database();
5020
- IDENTITY_DIR = path10.join(EXE_AI_DIR, "identity");
5848
+ IDENTITY_DIR2 = path12.join(EXE_AI_DIR, "identity");
5021
5849
  }
5022
5850
  });
5023
5851
 
@@ -5568,36 +6396,36 @@ __export(session_wrappers_exports, {
5568
6396
  generateSessionWrappers: () => generateSessionWrappers
5569
6397
  });
5570
6398
  import {
5571
- existsSync as existsSync11,
5572
- readFileSync as readFileSync9,
5573
- writeFileSync as writeFileSync7,
5574
- mkdirSync as mkdirSync6,
6399
+ existsSync as existsSync12,
6400
+ readFileSync as readFileSync10,
6401
+ writeFileSync as writeFileSync8,
6402
+ mkdirSync as mkdirSync7,
5575
6403
  chmodSync,
5576
6404
  readdirSync as readdirSync3,
5577
6405
  unlinkSync as unlinkSync6
5578
6406
  } from "fs";
5579
- import path11 from "path";
6407
+ import path13 from "path";
5580
6408
  import { homedir as homedir3 } from "os";
5581
6409
  function generateSessionWrappers(packageRoot, homeDir) {
5582
6410
  const home = homeDir ?? homedir3();
5583
- const binDir = path11.join(home, ".exe-os", "bin");
5584
- const rosterPath = path11.join(home, ".exe-os", "exe-employees.json");
5585
- mkdirSync6(binDir, { recursive: true });
5586
- const exeStartDst = path11.join(binDir, "exe-start");
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");
5587
6415
  const candidates = [
5588
- path11.join(packageRoot, "dist", "bin", "exe-start.sh"),
5589
- path11.join(packageRoot, "src", "bin", "exe-start.sh")
6416
+ path13.join(packageRoot, "dist", "bin", "exe-start.sh"),
6417
+ path13.join(packageRoot, "src", "bin", "exe-start.sh")
5590
6418
  ];
5591
6419
  for (const src of candidates) {
5592
- if (existsSync11(src)) {
5593
- writeFileSync7(exeStartDst, readFileSync9(src));
6420
+ if (existsSync12(src)) {
6421
+ writeFileSync8(exeStartDst, readFileSync10(src));
5594
6422
  chmodSync(exeStartDst, 493);
5595
6423
  break;
5596
6424
  }
5597
6425
  }
5598
6426
  let employees = [];
5599
6427
  try {
5600
- employees = JSON.parse(readFileSync9(rosterPath, "utf8"));
6428
+ employees = JSON.parse(readFileSync10(rosterPath, "utf8"));
5601
6429
  } catch {
5602
6430
  return { created: 0, pathConfigured: false };
5603
6431
  }
@@ -5607,9 +6435,9 @@ function generateSessionWrappers(packageRoot, homeDir) {
5607
6435
  try {
5608
6436
  for (const f of readdirSync3(binDir)) {
5609
6437
  if (f === "exe-start") continue;
5610
- const fPath = path11.join(binDir, f);
6438
+ const fPath = path13.join(binDir, f);
5611
6439
  try {
5612
- const content = readFileSync9(fPath, "utf8");
6440
+ const content = readFileSync10(fPath, "utf8");
5613
6441
  if (content.includes("exe-start")) {
5614
6442
  unlinkSync6(fPath);
5615
6443
  }
@@ -5624,30 +6452,30 @@ exec "${exeStartDst}" "$0" "$@"
5624
6452
  `;
5625
6453
  for (const emp of employees) {
5626
6454
  for (let n = 1; n <= MAX_N; n++) {
5627
- const wrapperPath = path11.join(binDir, `${emp.name}${n}`);
5628
- writeFileSync7(wrapperPath, wrapperContent);
6455
+ const wrapperPath = path13.join(binDir, `${emp.name}${n}`);
6456
+ writeFileSync8(wrapperPath, wrapperContent);
5629
6457
  chmodSync(wrapperPath, 493);
5630
6458
  created++;
5631
6459
  }
5632
6460
  }
5633
6461
  const codexLauncherCandidates = [
5634
- path11.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
5635
- path11.join(packageRoot, "src", "bin", "exe-start-codex.ts")
6462
+ path13.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
6463
+ path13.join(packageRoot, "src", "bin", "exe-start-codex.ts")
5636
6464
  ];
5637
6465
  let codexLauncher = null;
5638
6466
  for (const c of codexLauncherCandidates) {
5639
- if (existsSync11(c)) {
6467
+ if (existsSync12(c)) {
5640
6468
  codexLauncher = c;
5641
6469
  break;
5642
6470
  }
5643
6471
  }
5644
6472
  if (codexLauncher) {
5645
6473
  for (const emp of employees) {
5646
- const wrapperPath = path11.join(binDir, `${emp.name}-codex`);
6474
+ const wrapperPath = path13.join(binDir, `${emp.name}-codex`);
5647
6475
  const content = `#!/bin/bash
5648
6476
  exec node "${codexLauncher}" --agent ${emp.name} "$@"
5649
6477
  `;
5650
- writeFileSync7(wrapperPath, content);
6478
+ writeFileSync8(wrapperPath, content);
5651
6479
  chmodSync(wrapperPath, 493);
5652
6480
  created++;
5653
6481
  }
@@ -5666,24 +6494,24 @@ export PATH="${binDir}:$PATH"
5666
6494
  const shell = process.env.SHELL ?? "/bin/bash";
5667
6495
  const profilePaths = [];
5668
6496
  if (shell.includes("zsh")) {
5669
- profilePaths.push(path11.join(home, ".zshrc"));
6497
+ profilePaths.push(path13.join(home, ".zshrc"));
5670
6498
  } else if (shell.includes("bash")) {
5671
- profilePaths.push(path11.join(home, ".bashrc"));
5672
- profilePaths.push(path11.join(home, ".bash_profile"));
6499
+ profilePaths.push(path13.join(home, ".bashrc"));
6500
+ profilePaths.push(path13.join(home, ".bash_profile"));
5673
6501
  } else {
5674
- profilePaths.push(path11.join(home, ".profile"));
6502
+ profilePaths.push(path13.join(home, ".profile"));
5675
6503
  }
5676
6504
  for (const profilePath of profilePaths) {
5677
6505
  try {
5678
6506
  let content = "";
5679
6507
  try {
5680
- content = readFileSync9(profilePath, "utf8");
6508
+ content = readFileSync10(profilePath, "utf8");
5681
6509
  } catch {
5682
6510
  }
5683
6511
  if (content.includes(".exe-os/bin")) {
5684
6512
  return false;
5685
6513
  }
5686
- writeFileSync7(profilePath, content + exportLine);
6514
+ writeFileSync8(profilePath, content + exportLine);
5687
6515
  return true;
5688
6516
  } catch {
5689
6517
  continue;
@@ -5703,9 +6531,9 @@ var init_session_wrappers = __esm({
5703
6531
  init_config();
5704
6532
  init_keychain();
5705
6533
  import crypto3 from "crypto";
5706
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync8, unlinkSync as unlinkSync7 } from "fs";
5707
- import os6 from "os";
5708
- import path12 from "path";
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";
5709
6537
  import { createInterface } from "readline";
5710
6538
 
5711
6539
  // src/lib/model-downloader.ts
@@ -5797,32 +6625,32 @@ async function fileHash(filePath) {
5797
6625
 
5798
6626
  // src/lib/setup-wizard.ts
5799
6627
  function findPackageRoot2() {
5800
- let dir = path12.dirname(new URL(import.meta.url).pathname);
5801
- const root = path12.parse(dir).root;
6628
+ let dir = path14.dirname(new URL(import.meta.url).pathname);
6629
+ const root = path14.parse(dir).root;
5802
6630
  while (dir !== root) {
5803
- const pkgPath = path12.join(dir, "package.json");
5804
- if (existsSync12(pkgPath)) {
6631
+ const pkgPath = path14.join(dir, "package.json");
6632
+ if (existsSync13(pkgPath)) {
5805
6633
  try {
5806
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
6634
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
5807
6635
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
5808
6636
  } catch {
5809
6637
  }
5810
6638
  }
5811
- dir = path12.dirname(dir);
6639
+ dir = path14.dirname(dir);
5812
6640
  }
5813
6641
  return null;
5814
6642
  }
5815
- var SETUP_STATE_PATH = path12.join(os6.homedir(), ".exe-os", "setup-state.json");
6643
+ var SETUP_STATE_PATH = path14.join(os7.homedir(), ".exe-os", "setup-state.json");
5816
6644
  function loadSetupState() {
5817
6645
  try {
5818
- return JSON.parse(readFileSync10(SETUP_STATE_PATH, "utf8"));
6646
+ return JSON.parse(readFileSync11(SETUP_STATE_PATH, "utf8"));
5819
6647
  } catch {
5820
6648
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
5821
6649
  }
5822
6650
  }
5823
6651
  function saveSetupState(state) {
5824
- mkdirSync7(path12.dirname(SETUP_STATE_PATH), { recursive: true });
5825
- writeFileSync8(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
6652
+ mkdirSync8(path14.dirname(SETUP_STATE_PATH), { recursive: true });
6653
+ writeFileSync9(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
5826
6654
  }
5827
6655
  function clearSetupState() {
5828
6656
  try {
@@ -5841,10 +6669,10 @@ function ask(rl, prompt) {
5841
6669
  });
5842
6670
  }
5843
6671
  function getAvailableMemoryGB() {
5844
- return os6.freemem() / (1024 * 1024 * 1024);
6672
+ return os7.freemem() / (1024 * 1024 * 1024);
5845
6673
  }
5846
6674
  function getTotalMemoryGB() {
5847
- return os6.totalmem() / (1024 * 1024 * 1024);
6675
+ return os7.totalmem() / (1024 * 1024 * 1024);
5848
6676
  }
5849
6677
  function isLowMemory() {
5850
6678
  return getAvailableMemoryGB() < 2;
@@ -5855,8 +6683,8 @@ async function validateModel(log) {
5855
6683
  if (totalGB <= 8 || isLowMemory()) {
5856
6684
  log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
5857
6685
  log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
5858
- const modelPath = path12.join(MODELS_DIR, LOCAL_FILENAME);
5859
- if (existsSync12(modelPath)) {
6686
+ const modelPath = path14.join(MODELS_DIR, LOCAL_FILENAME);
6687
+ if (existsSync13(modelPath)) {
5860
6688
  const { statSync: statSync2 } = await import("fs");
5861
6689
  const size = statSync2(modelPath).size;
5862
6690
  if (size > 300 * 1e6) {
@@ -5947,7 +6775,7 @@ async function runSetupWizard(opts = {}) {
5947
6775
  if (state.completedSteps.length > 0) {
5948
6776
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
5949
6777
  }
5950
- if (existsSync12(LEGACY_LANCE_PATH)) {
6778
+ if (existsSync13(LEGACY_LANCE_PATH)) {
5951
6779
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
5952
6780
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
5953
6781
  log(" The old directory will not be modified or deleted.");
@@ -6111,19 +6939,19 @@ async function runSetupWizard(opts = {}) {
6111
6939
  await saveConfig(config);
6112
6940
  log("");
6113
6941
  try {
6114
- const claudeJsonPath = path12.join(os6.homedir(), ".claude.json");
6942
+ const claudeJsonPath = path14.join(os7.homedir(), ".claude.json");
6115
6943
  let claudeJson = {};
6116
6944
  try {
6117
- claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
6945
+ claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
6118
6946
  } catch {
6119
6947
  }
6120
6948
  if (!claudeJson.projects) claudeJson.projects = {};
6121
6949
  const projects = claudeJson.projects;
6122
- for (const dir of [process.cwd(), os6.homedir()]) {
6950
+ for (const dir of [process.cwd(), os7.homedir()]) {
6123
6951
  if (!projects[dir]) projects[dir] = {};
6124
6952
  projects[dir].hasTrustDialogAccepted = true;
6125
6953
  }
6126
- writeFileSync8(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
6954
+ writeFileSync9(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
6127
6955
  } catch {
6128
6956
  }
6129
6957
  state.completedSteps.push(5);
@@ -6137,7 +6965,7 @@ async function runSetupWizard(opts = {}) {
6137
6965
  const prefs = { ...existingPrefs };
6138
6966
  log("=== Config Defaults ===");
6139
6967
  log("");
6140
- const ghosttyDetected = existsSync12(path12.join(os6.homedir(), ".config", "ghostty")) || existsSync12(path12.join(os6.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
6968
+ const ghosttyDetected = existsSync13(path14.join(os7.homedir(), ".config", "ghostty")) || existsSync13(path14.join(os7.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
6141
6969
  if (ghosttyDetected) {
6142
6970
  const ghosttyAnswer = await ask(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
6143
6971
  prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
@@ -6184,7 +7012,7 @@ async function runSetupWizard(opts = {}) {
6184
7012
  let missingIdentities = [];
6185
7013
  for (const emp of roster) {
6186
7014
  const idPath = identityPath2(emp.name);
6187
- if (!existsSync12(idPath)) {
7015
+ if (!existsSync13(idPath)) {
6188
7016
  missingIdentities.push(emp.name);
6189
7017
  }
6190
7018
  }
@@ -6216,7 +7044,7 @@ async function runSetupWizard(opts = {}) {
6216
7044
  }
6217
7045
  missingIdentities = [];
6218
7046
  for (const emp of roster) {
6219
- if (!existsSync12(identityPath2(emp.name))) {
7047
+ if (!existsSync13(identityPath2(emp.name))) {
6220
7048
  missingIdentities.push(emp.name);
6221
7049
  }
6222
7050
  }
@@ -6281,9 +7109,9 @@ async function runSetupWizard(opts = {}) {
6281
7109
  const cooIdentityContent = getIdentityTemplate("coo");
6282
7110
  if (cooIdentityContent) {
6283
7111
  const cooIdPath = identityPath2(cooName);
6284
- mkdirSync7(path12.dirname(cooIdPath), { recursive: true });
7112
+ mkdirSync8(path14.dirname(cooIdPath), { recursive: true });
6285
7113
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
6286
- writeFileSync8(cooIdPath, replaced, "utf-8");
7114
+ writeFileSync9(cooIdPath, replaced, "utf-8");
6287
7115
  }
6288
7116
  registerBinSymlinks2(cooName);
6289
7117
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -6377,9 +7205,9 @@ async function runSetupWizard(opts = {}) {
6377
7205
  const ctoIdentityContent = getIdentityTemplate("cto");
6378
7206
  if (ctoIdentityContent) {
6379
7207
  const ctoIdPath = identityPath2(ctoName);
6380
- mkdirSync7(path12.dirname(ctoIdPath), { recursive: true });
7208
+ mkdirSync8(path14.dirname(ctoIdPath), { recursive: true });
6381
7209
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
6382
- writeFileSync8(ctoIdPath, replaced, "utf-8");
7210
+ writeFileSync9(ctoIdPath, replaced, "utf-8");
6383
7211
  }
6384
7212
  registerBinSymlinks2(ctoName);
6385
7213
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -6400,9 +7228,9 @@ async function runSetupWizard(opts = {}) {
6400
7228
  const cmoIdentityContent = getIdentityTemplate("cmo");
6401
7229
  if (cmoIdentityContent) {
6402
7230
  const cmoIdPath = identityPath2(cmoName);
6403
- mkdirSync7(path12.dirname(cmoIdPath), { recursive: true });
7231
+ mkdirSync8(path14.dirname(cmoIdPath), { recursive: true });
6404
7232
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
6405
- writeFileSync8(cmoIdPath, replaced, "utf-8");
7233
+ writeFileSync9(cmoIdPath, replaced, "utf-8");
6406
7234
  }
6407
7235
  registerBinSymlinks2(cmoName);
6408
7236
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -6424,7 +7252,7 @@ async function runSetupWizard(opts = {}) {
6424
7252
  log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
6425
7253
  }
6426
7254
  if (wrapResult.pathConfigured) {
6427
- const binDir = path12.join(os6.homedir(), ".exe-os", "bin");
7255
+ const binDir = path14.join(os7.homedir(), ".exe-os", "bin");
6428
7256
  process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
6429
7257
  pathJustConfigured = true;
6430
7258
  }
@@ -6467,7 +7295,7 @@ async function runSetupWizard(opts = {}) {
6467
7295
  const pkgRoot2 = findPackageRoot2();
6468
7296
  if (pkgRoot2) {
6469
7297
  try {
6470
- version = JSON.parse(readFileSync10(path12.join(pkgRoot2, "package.json"), "utf-8")).version;
7298
+ version = JSON.parse(readFileSync11(path14.join(pkgRoot2, "package.json"), "utf-8")).version;
6471
7299
  } catch {
6472
7300
  }
6473
7301
  }