@askexenow/exe-os 0.8.85 → 0.8.86

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 (57) hide show
  1. package/dist/bin/cleanup-stale-review-tasks.js +57 -19
  2. package/dist/bin/cli.js +507 -337
  3. package/dist/bin/exe-agent-config.js +242 -0
  4. package/dist/bin/exe-agent.js +3 -3
  5. package/dist/bin/exe-boot.js +344 -346
  6. package/dist/bin/exe-dispatch.js +375 -250
  7. package/dist/bin/exe-forget.js +5 -1
  8. package/dist/bin/exe-gateway.js +260 -135
  9. package/dist/bin/exe-healthcheck.js +133 -1
  10. package/dist/bin/exe-heartbeat.js +72 -31
  11. package/dist/bin/exe-link.js +25 -2
  12. package/dist/bin/exe-new-employee.js +22 -0
  13. package/dist/bin/exe-pending-messages.js +55 -17
  14. package/dist/bin/exe-pending-reviews.js +57 -19
  15. package/dist/bin/exe-search.js +6 -2
  16. package/dist/bin/exe-session-cleanup.js +260 -135
  17. package/dist/bin/exe-start-codex.js +2598 -0
  18. package/dist/bin/exe-start.sh +15 -3
  19. package/dist/bin/exe-status.js +57 -19
  20. package/dist/bin/git-sweep.js +391 -266
  21. package/dist/bin/install.js +22 -0
  22. package/dist/bin/scan-tasks.js +394 -269
  23. package/dist/bin/setup.js +47 -2
  24. package/dist/gateway/index.js +257 -132
  25. package/dist/hooks/bug-report-worker.js +242 -117
  26. package/dist/hooks/commit-complete.js +389 -264
  27. package/dist/hooks/error-recall.js +6 -2
  28. package/dist/hooks/ingest-worker.js +314 -193
  29. package/dist/hooks/post-compact.js +84 -46
  30. package/dist/hooks/pre-compact.js +272 -147
  31. package/dist/hooks/pre-tool-use.js +104 -66
  32. package/dist/hooks/prompt-submit.js +126 -66
  33. package/dist/hooks/session-end.js +277 -152
  34. package/dist/hooks/session-start.js +70 -28
  35. package/dist/hooks/stop.js +90 -52
  36. package/dist/hooks/subagent-stop.js +84 -46
  37. package/dist/hooks/summary-worker.js +175 -114
  38. package/dist/index.js +296 -171
  39. package/dist/lib/agent-config.js +167 -0
  40. package/dist/lib/cloud-sync.js +25 -2
  41. package/dist/lib/exe-daemon.js +338 -213
  42. package/dist/lib/hybrid-search.js +7 -2
  43. package/dist/lib/messaging.js +95 -39
  44. package/dist/lib/runtime-table.js +16 -0
  45. package/dist/lib/session-wrappers.js +22 -0
  46. package/dist/lib/tasks.js +242 -117
  47. package/dist/lib/tmux-routing.js +314 -189
  48. package/dist/mcp/server.js +573 -274
  49. package/dist/mcp/tools/create-task.js +260 -135
  50. package/dist/mcp/tools/list-tasks.js +68 -30
  51. package/dist/mcp/tools/send-message.js +100 -44
  52. package/dist/mcp/tools/update-task.js +123 -67
  53. package/dist/runtime/index.js +276 -151
  54. package/dist/tui/App.js +479 -354
  55. package/package.json +1 -1
  56. package/src/commands/exe/agent-config.md +27 -0
  57. package/src/commands/exe/cc-doctor.md +10 -0
@@ -854,18 +854,69 @@ var init_provider_table = __esm({
854
854
  }
855
855
  });
856
856
 
857
- // src/lib/intercom-queue.ts
858
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
857
+ // src/lib/runtime-table.ts
858
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
859
+ var init_runtime_table = __esm({
860
+ "src/lib/runtime-table.ts"() {
861
+ "use strict";
862
+ RUNTIME_TABLE = {
863
+ codex: {
864
+ binary: "codex",
865
+ launchMode: "exec",
866
+ autoApproveFlag: "--full-auto",
867
+ inlineFlag: "--no-alt-screen",
868
+ apiKeyEnv: "OPENAI_API_KEY",
869
+ defaultModel: "gpt-5.4"
870
+ }
871
+ };
872
+ DEFAULT_RUNTIME = "claude";
873
+ }
874
+ });
875
+
876
+ // src/lib/agent-config.ts
877
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
859
878
  import path5 from "path";
879
+ function loadAgentConfig() {
880
+ if (!existsSync5(AGENT_CONFIG_PATH)) return {};
881
+ try {
882
+ return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
883
+ } catch {
884
+ return {};
885
+ }
886
+ }
887
+ function getAgentRuntime(agentId) {
888
+ const config = loadAgentConfig();
889
+ const entry = config[agentId];
890
+ if (entry) return entry;
891
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
892
+ }
893
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
894
+ var init_agent_config = __esm({
895
+ "src/lib/agent-config.ts"() {
896
+ "use strict";
897
+ init_config();
898
+ init_runtime_table();
899
+ AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
900
+ DEFAULT_MODELS = {
901
+ claude: "claude-opus-4",
902
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
903
+ opencode: "minimax-m2.7"
904
+ };
905
+ }
906
+ });
907
+
908
+ // src/lib/intercom-queue.ts
909
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
910
+ import path6 from "path";
860
911
  import os5 from "os";
861
912
  function ensureDir() {
862
- const dir = path5.dirname(QUEUE_PATH);
863
- if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
913
+ const dir = path6.dirname(QUEUE_PATH);
914
+ if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
864
915
  }
865
916
  function readQueue() {
866
917
  try {
867
- if (!existsSync5(QUEUE_PATH)) return [];
868
- return JSON.parse(readFileSync5(QUEUE_PATH, "utf8"));
918
+ if (!existsSync6(QUEUE_PATH)) return [];
919
+ return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
869
920
  } catch {
870
921
  return [];
871
922
  }
@@ -873,7 +924,7 @@ function readQueue() {
873
924
  function writeQueue(queue) {
874
925
  ensureDir();
875
926
  const tmp = `${QUEUE_PATH}.tmp`;
876
- writeFileSync3(tmp, JSON.stringify(queue, null, 2));
927
+ writeFileSync4(tmp, JSON.stringify(queue, null, 2));
877
928
  renameSync3(tmp, QUEUE_PATH);
878
929
  }
879
930
  function queueIntercom(targetSession, reason) {
@@ -897,25 +948,25 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
897
948
  var init_intercom_queue = __esm({
898
949
  "src/lib/intercom-queue.ts"() {
899
950
  "use strict";
900
- QUEUE_PATH = path5.join(os5.homedir(), ".exe-os", "intercom-queue.json");
951
+ QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
901
952
  TTL_MS = 60 * 60 * 1e3;
902
- INTERCOM_LOG = path5.join(os5.homedir(), ".exe-os", "intercom.log");
953
+ INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
903
954
  }
904
955
  });
905
956
 
906
957
  // src/lib/license.ts
907
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
958
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
908
959
  import { randomUUID } from "crypto";
909
- import path6 from "path";
960
+ import path7 from "path";
910
961
  import { jwtVerify, importSPKI } from "jose";
911
962
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
912
963
  var init_license = __esm({
913
964
  "src/lib/license.ts"() {
914
965
  "use strict";
915
966
  init_config();
916
- LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
917
- CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
918
- DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
967
+ LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
968
+ CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
969
+ DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
919
970
  PLAN_LIMITS = {
920
971
  free: { devices: 1, employees: 1, memories: 5e3 },
921
972
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -927,12 +978,12 @@ var init_license = __esm({
927
978
  });
928
979
 
929
980
  // src/lib/plan-limits.ts
930
- import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
931
- import path7 from "path";
981
+ import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
982
+ import path8 from "path";
932
983
  function getLicenseSync() {
933
984
  try {
934
- if (!existsSync7(CACHE_PATH2)) return freeLicense();
935
- const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
985
+ if (!existsSync8(CACHE_PATH2)) return freeLicense();
986
+ const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
936
987
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
937
988
  const parts = raw.token.split(".");
938
989
  if (parts.length !== 3) return freeLicense();
@@ -970,8 +1021,8 @@ function assertEmployeeLimitSync(rosterPath) {
970
1021
  const filePath = rosterPath ?? EMPLOYEES_PATH;
971
1022
  let count = 0;
972
1023
  try {
973
- if (existsSync7(filePath)) {
974
- const raw = readFileSync7(filePath, "utf8");
1024
+ if (existsSync8(filePath)) {
1025
+ const raw = readFileSync8(filePath, "utf8");
975
1026
  const employees = JSON.parse(raw);
976
1027
  count = Array.isArray(employees) ? employees.length : 0;
977
1028
  }
@@ -1000,7 +1051,7 @@ var init_plan_limits = __esm({
1000
1051
  this.name = "PlanLimitError";
1001
1052
  }
1002
1053
  };
1003
- CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
1054
+ CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
1004
1055
  }
1005
1056
  });
1006
1057
 
@@ -1348,13 +1399,13 @@ __export(tmux_routing_exports, {
1348
1399
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
1349
1400
  });
1350
1401
  import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
1351
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync } from "fs";
1352
- import path8 from "path";
1402
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync9, appendFileSync } from "fs";
1403
+ import path9 from "path";
1353
1404
  import os6 from "os";
1354
1405
  import { fileURLToPath } from "url";
1355
1406
  import { unlinkSync as unlinkSync3 } from "fs";
1356
1407
  function spawnLockPath(sessionName) {
1357
- return path8.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
1408
+ return path9.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
1358
1409
  }
1359
1410
  function isProcessAlive(pid) {
1360
1411
  try {
@@ -1365,13 +1416,13 @@ function isProcessAlive(pid) {
1365
1416
  }
1366
1417
  }
1367
1418
  function acquireSpawnLock(sessionName) {
1368
- if (!existsSync8(SPAWN_LOCK_DIR)) {
1369
- mkdirSync4(SPAWN_LOCK_DIR, { recursive: true });
1419
+ if (!existsSync9(SPAWN_LOCK_DIR)) {
1420
+ mkdirSync5(SPAWN_LOCK_DIR, { recursive: true });
1370
1421
  }
1371
1422
  const lockFile = spawnLockPath(sessionName);
1372
- if (existsSync8(lockFile)) {
1423
+ if (existsSync9(lockFile)) {
1373
1424
  try {
1374
- const lock = JSON.parse(readFileSync8(lockFile, "utf8"));
1425
+ const lock = JSON.parse(readFileSync9(lockFile, "utf8"));
1375
1426
  const age = Date.now() - lock.timestamp;
1376
1427
  if (isProcessAlive(lock.pid) && age < 6e4) {
1377
1428
  return false;
@@ -1379,7 +1430,7 @@ function acquireSpawnLock(sessionName) {
1379
1430
  } catch {
1380
1431
  }
1381
1432
  }
1382
- writeFileSync5(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
1433
+ writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
1383
1434
  return true;
1384
1435
  }
1385
1436
  function releaseSpawnLock(sessionName) {
@@ -1391,13 +1442,13 @@ function releaseSpawnLock(sessionName) {
1391
1442
  function resolveBehaviorsExporterScript() {
1392
1443
  try {
1393
1444
  const thisFile = fileURLToPath(import.meta.url);
1394
- const scriptPath = path8.join(
1395
- path8.dirname(thisFile),
1445
+ const scriptPath = path9.join(
1446
+ path9.dirname(thisFile),
1396
1447
  "..",
1397
1448
  "bin",
1398
1449
  "exe-export-behaviors.js"
1399
1450
  );
1400
- return existsSync8(scriptPath) ? scriptPath : null;
1451
+ return existsSync9(scriptPath) ? scriptPath : null;
1401
1452
  } catch {
1402
1453
  return null;
1403
1454
  }
@@ -1463,12 +1514,12 @@ function extractRootExe(name) {
1463
1514
  return parts.length > 0 ? parts[parts.length - 1] : null;
1464
1515
  }
1465
1516
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
1466
- if (!existsSync8(SESSION_CACHE)) {
1467
- mkdirSync4(SESSION_CACHE, { recursive: true });
1517
+ if (!existsSync9(SESSION_CACHE)) {
1518
+ mkdirSync5(SESSION_CACHE, { recursive: true });
1468
1519
  }
1469
1520
  const rootExe = extractRootExe(parentExe) ?? parentExe;
1470
- const filePath = path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
1471
- writeFileSync5(filePath, JSON.stringify({
1521
+ const filePath = path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
1522
+ writeFileSync6(filePath, JSON.stringify({
1472
1523
  parentExe: rootExe,
1473
1524
  dispatchedBy: dispatchedBy || rootExe,
1474
1525
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -1476,7 +1527,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
1476
1527
  }
1477
1528
  function getParentExe(sessionKey) {
1478
1529
  try {
1479
- const data = JSON.parse(readFileSync8(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1530
+ const data = JSON.parse(readFileSync9(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1480
1531
  return data.parentExe || null;
1481
1532
  } catch {
1482
1533
  return null;
@@ -1484,8 +1535,8 @@ function getParentExe(sessionKey) {
1484
1535
  }
1485
1536
  function getDispatchedBy(sessionKey) {
1486
1537
  try {
1487
- const data = JSON.parse(readFileSync8(
1488
- path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
1538
+ const data = JSON.parse(readFileSync9(
1539
+ path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
1489
1540
  "utf8"
1490
1541
  ));
1491
1542
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -1546,32 +1597,50 @@ async function verifyPaneAtCapacity(sessionName) {
1546
1597
  }
1547
1598
  function readDebounceState() {
1548
1599
  try {
1549
- if (!existsSync8(DEBOUNCE_FILE)) return {};
1550
- return JSON.parse(readFileSync8(DEBOUNCE_FILE, "utf8"));
1600
+ if (!existsSync9(DEBOUNCE_FILE)) return {};
1601
+ const raw = JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
1602
+ const state = {};
1603
+ for (const [key, val] of Object.entries(raw)) {
1604
+ if (typeof val === "number") {
1605
+ state[key] = { lastSent: val, pending: 0 };
1606
+ } else if (val && typeof val === "object" && "lastSent" in val) {
1607
+ state[key] = val;
1608
+ }
1609
+ }
1610
+ return state;
1551
1611
  } catch {
1552
1612
  return {};
1553
1613
  }
1554
1614
  }
1555
1615
  function writeDebounceState(state) {
1556
1616
  try {
1557
- if (!existsSync8(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
1558
- writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
1617
+ if (!existsSync9(SESSION_CACHE)) mkdirSync5(SESSION_CACHE, { recursive: true });
1618
+ writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
1559
1619
  } catch {
1560
1620
  }
1561
1621
  }
1562
1622
  function isDebounced(targetSession) {
1563
1623
  const state = readDebounceState();
1564
- const lastSent = state[targetSession] ?? 0;
1565
- return Date.now() - lastSent < INTERCOM_DEBOUNCE_MS;
1624
+ const entry = state[targetSession];
1625
+ const lastSent = entry?.lastSent ?? 0;
1626
+ if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
1627
+ if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
1628
+ state[targetSession].pending++;
1629
+ writeDebounceState(state);
1630
+ return true;
1631
+ }
1632
+ return false;
1566
1633
  }
1567
1634
  function recordDebounce(targetSession) {
1568
1635
  const state = readDebounceState();
1569
- state[targetSession] = Date.now();
1636
+ const batched = state[targetSession]?.pending ?? 0;
1637
+ state[targetSession] = { lastSent: Date.now(), pending: 0 };
1570
1638
  const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
1571
1639
  for (const key of Object.keys(state)) {
1572
- if ((state[key] ?? 0) < cutoff) delete state[key];
1640
+ if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
1573
1641
  }
1574
1642
  writeDebounceState(state);
1643
+ return batched;
1575
1644
  }
1576
1645
  function logIntercom(msg) {
1577
1646
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
@@ -1616,7 +1685,7 @@ function sendIntercom(targetSession) {
1616
1685
  return "skipped_exe";
1617
1686
  }
1618
1687
  if (isDebounced(targetSession)) {
1619
- logIntercom(`DEBOUNCE \u2192 ${targetSession} (cross-process file debounce)`);
1688
+ logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
1620
1689
  return "debounced";
1621
1690
  }
1622
1691
  try {
@@ -1628,14 +1697,14 @@ function sendIntercom(targetSession) {
1628
1697
  const sessionState = getSessionState(targetSession);
1629
1698
  if (sessionState === "no_claude") {
1630
1699
  queueIntercom(targetSession, "claude not running in session");
1631
- recordDebounce(targetSession);
1632
- logIntercom(`QUEUED \u2192 ${targetSession} (no claude process \u2014 raw shell detected)`);
1700
+ const batched2 = recordDebounce(targetSession);
1701
+ logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
1633
1702
  return "queued";
1634
1703
  }
1635
1704
  if (sessionState === "thinking" || sessionState === "tool") {
1636
1705
  queueIntercom(targetSession, "session busy at send time");
1637
- recordDebounce(targetSession);
1638
- logIntercom(`QUEUED \u2192 ${targetSession} (session busy, will retry from queue)`);
1706
+ const batched2 = recordDebounce(targetSession);
1707
+ logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
1639
1708
  return "queued";
1640
1709
  }
1641
1710
  if (transport.isPaneInCopyMode(targetSession)) {
@@ -1643,8 +1712,8 @@ function sendIntercom(targetSession) {
1643
1712
  transport.sendKeys(targetSession, "q");
1644
1713
  }
1645
1714
  transport.sendKeys(targetSession, "/exe-intercom");
1646
- recordDebounce(targetSession);
1647
- logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
1715
+ const batched = recordDebounce(targetSession);
1716
+ logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
1648
1717
  return "delivered";
1649
1718
  } catch {
1650
1719
  logIntercom(`FAIL \u2192 ${targetSession}`);
@@ -1746,26 +1815,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1746
1815
  const transport = getTransport();
1747
1816
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
1748
1817
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
1749
- const logDir = path8.join(os6.homedir(), ".exe-os", "session-logs");
1750
- const logFile = path8.join(logDir, `${instanceLabel}-${Date.now()}.log`);
1751
- if (!existsSync8(logDir)) {
1752
- mkdirSync4(logDir, { recursive: true });
1818
+ const logDir = path9.join(os6.homedir(), ".exe-os", "session-logs");
1819
+ const logFile = path9.join(logDir, `${instanceLabel}-${Date.now()}.log`);
1820
+ if (!existsSync9(logDir)) {
1821
+ mkdirSync5(logDir, { recursive: true });
1753
1822
  }
1754
1823
  transport.kill(sessionName);
1755
1824
  let cleanupSuffix = "";
1756
1825
  try {
1757
1826
  const thisFile = fileURLToPath(import.meta.url);
1758
- const cleanupScript = path8.join(path8.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
1759
- if (existsSync8(cleanupScript)) {
1827
+ const cleanupScript = path9.join(path9.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
1828
+ if (existsSync9(cleanupScript)) {
1760
1829
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
1761
1830
  }
1762
1831
  } catch {
1763
1832
  }
1764
1833
  try {
1765
- const claudeJsonPath = path8.join(os6.homedir(), ".claude.json");
1834
+ const claudeJsonPath = path9.join(os6.homedir(), ".claude.json");
1766
1835
  let claudeJson = {};
1767
1836
  try {
1768
- claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
1837
+ claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
1769
1838
  } catch {
1770
1839
  }
1771
1840
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -1773,17 +1842,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1773
1842
  const trustDir = opts?.cwd ?? projectDir;
1774
1843
  if (!projects[trustDir]) projects[trustDir] = {};
1775
1844
  projects[trustDir].hasTrustDialogAccepted = true;
1776
- writeFileSync5(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
1845
+ writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
1777
1846
  } catch {
1778
1847
  }
1779
1848
  try {
1780
- const settingsDir = path8.join(os6.homedir(), ".claude", "projects");
1849
+ const settingsDir = path9.join(os6.homedir(), ".claude", "projects");
1781
1850
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
1782
- const projSettingsDir = path8.join(settingsDir, normalizedKey);
1783
- const settingsPath = path8.join(projSettingsDir, "settings.json");
1851
+ const projSettingsDir = path9.join(settingsDir, normalizedKey);
1852
+ const settingsPath = path9.join(projSettingsDir, "settings.json");
1784
1853
  let settings = {};
1785
1854
  try {
1786
- settings = JSON.parse(readFileSync8(settingsPath, "utf8"));
1855
+ settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
1787
1856
  } catch {
1788
1857
  }
1789
1858
  const perms = settings.permissions ?? {};
@@ -1811,20 +1880,23 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1811
1880
  if (changed) {
1812
1881
  perms.allow = allow;
1813
1882
  settings.permissions = perms;
1814
- mkdirSync4(projSettingsDir, { recursive: true });
1815
- writeFileSync5(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1883
+ mkdirSync5(projSettingsDir, { recursive: true });
1884
+ writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1816
1885
  }
1817
1886
  } catch {
1818
1887
  }
1819
1888
  const spawnCwd = opts?.cwd ?? projectDir;
1820
1889
  const useExeAgent = !!(opts?.model && opts?.provider);
1821
- const ccProvider = useExeAgent ? DEFAULT_PROVIDER : detectActiveProvider();
1890
+ const agentRtConfig = getAgentRuntime(employeeName);
1891
+ const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
1892
+ const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
1893
+ const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
1822
1894
  const useBinSymlink = ccProvider !== DEFAULT_PROVIDER;
1823
1895
  let identityFlag = "";
1824
1896
  let behaviorsFlag = "";
1825
1897
  let legacyFallbackWarned = false;
1826
1898
  if (!useExeAgent && !useBinSymlink) {
1827
- const identityPath2 = path8.join(
1899
+ const identityPath2 = path9.join(
1828
1900
  os6.homedir(),
1829
1901
  ".exe-os",
1830
1902
  "identity",
@@ -1834,13 +1906,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1834
1906
  const hasAgentFlag = claudeSupportsAgentFlag();
1835
1907
  if (hasAgentFlag) {
1836
1908
  identityFlag = ` --agent ${employeeName}`;
1837
- } else if (existsSync8(identityPath2)) {
1909
+ } else if (existsSync9(identityPath2)) {
1838
1910
  identityFlag = ` --append-system-prompt-file ${identityPath2}`;
1839
1911
  legacyFallbackWarned = true;
1840
1912
  }
1841
1913
  const behaviorsFile = exportBehaviorsSync(
1842
1914
  employeeName,
1843
- path8.basename(spawnCwd),
1915
+ path9.basename(spawnCwd),
1844
1916
  sessionName
1845
1917
  );
1846
1918
  if (behaviorsFile) {
@@ -1855,16 +1927,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1855
1927
  }
1856
1928
  let sessionContextFlag = "";
1857
1929
  try {
1858
- const ctxDir = path8.join(os6.homedir(), ".exe-os", "session-cache");
1859
- mkdirSync4(ctxDir, { recursive: true });
1860
- const ctxFile = path8.join(ctxDir, `session-context-${sessionName}.md`);
1930
+ const ctxDir = path9.join(os6.homedir(), ".exe-os", "session-cache");
1931
+ mkdirSync5(ctxDir, { recursive: true });
1932
+ const ctxFile = path9.join(ctxDir, `session-context-${sessionName}.md`);
1861
1933
  const ctxContent = [
1862
1934
  `## Session Context`,
1863
1935
  `You are running in tmux session: ${sessionName}.`,
1864
1936
  `Your parent coordinator session is ${exeSession}.`,
1865
1937
  `Your employees (if any) use the -${exeSession} suffix.`
1866
1938
  ].join("\n");
1867
- writeFileSync5(ctxFile, ctxContent);
1939
+ writeFileSync6(ctxFile, ctxContent);
1868
1940
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
1869
1941
  } catch {
1870
1942
  }
@@ -1878,9 +1950,48 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1878
1950
  }
1879
1951
  }
1880
1952
  }
1953
+ if (useCodex) {
1954
+ const codexCfg = RUNTIME_TABLE.codex;
1955
+ if (codexCfg?.apiKeyEnv) {
1956
+ const keyVal = process.env[codexCfg.apiKeyEnv];
1957
+ if (keyVal) {
1958
+ envPrefix = `${envPrefix} ${codexCfg.apiKeyEnv}=${keyVal}`;
1959
+ }
1960
+ }
1961
+ envPrefix = `${envPrefix} EXE_AGENT_MODEL=${agentRtConfig.model}`;
1962
+ }
1963
+ if (useOpencode) {
1964
+ const ocCfg = PROVIDER_TABLE.opencode;
1965
+ if (ocCfg?.apiKeyEnv) {
1966
+ const keyVal = process.env[ocCfg.apiKeyEnv];
1967
+ if (keyVal) {
1968
+ envPrefix = `${envPrefix} ${ocCfg.apiKeyEnv}=${keyVal}`;
1969
+ }
1970
+ }
1971
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
1972
+ }
1973
+ if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
1974
+ const defaultClaudeModel = DEFAULT_MODELS.claude;
1975
+ if (agentRtConfig.runtime === "claude" && agentRtConfig.model !== defaultClaudeModel) {
1976
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
1977
+ }
1978
+ }
1881
1979
  let spawnCommand;
1882
1980
  if (useExeAgent) {
1883
1981
  spawnCommand = `${envPrefix} exe-agent --employee ${employeeName} --model ${opts.model} --provider ${opts.provider}${cleanupSuffix}`;
1982
+ } else if (useCodex) {
1983
+ process.stderr.write(
1984
+ `[tmux-routing] agent-config: ${employeeName} \u2192 codex (${agentRtConfig.model})
1985
+ `
1986
+ );
1987
+ spawnCommand = `${envPrefix} exe-start-codex --agent ${employeeName}${cleanupSuffix}`;
1988
+ } else if (useOpencode) {
1989
+ const binName = `${employeeName}-opencode`;
1990
+ process.stderr.write(
1991
+ `[tmux-routing] agent-config: ${employeeName} \u2192 opencode (${agentRtConfig.model})
1992
+ `
1993
+ );
1994
+ spawnCommand = `${envPrefix} ${binName}${cleanupSuffix}`;
1884
1995
  } else if (useBinSymlink) {
1885
1996
  const binName = `${employeeName}-${ccProvider}`;
1886
1997
  process.stderr.write(
@@ -1902,11 +2013,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1902
2013
  transport.pipeLog(sessionName, logFile);
1903
2014
  try {
1904
2015
  const mySession = getMySession();
1905
- const dispatchInfo = path8.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
1906
- writeFileSync5(dispatchInfo, JSON.stringify({
2016
+ const dispatchInfo = path9.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
2017
+ writeFileSync6(dispatchInfo, JSON.stringify({
1907
2018
  dispatchedBy: mySession,
1908
2019
  rootExe: exeSession,
1909
- provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
2020
+ provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
2021
+ runtime: useCodex ? "codex" : useOpencode ? "opencode" : useExeAgent ? "exe-agent" : "claude",
2022
+ model: useCodex ? agentRtConfig.model : useOpencode ? agentRtConfig.model : void 0,
1910
2023
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
1911
2024
  }));
1912
2025
  } catch {
@@ -1924,6 +2037,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1924
2037
  booted = true;
1925
2038
  break;
1926
2039
  }
2040
+ } else if (useCodex) {
2041
+ if (pane.includes("codex") || pane.includes("Codex") || pane.includes("exe-start-codex")) {
2042
+ booted = true;
2043
+ break;
2044
+ }
1927
2045
  } else {
1928
2046
  if (pane.includes("Claude Code") || pane.includes("\u276F")) {
1929
2047
  booted = true;
@@ -1935,9 +2053,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1935
2053
  }
1936
2054
  if (!booted) {
1937
2055
  releaseSpawnLock(sessionName);
1938
- return { sessionName, error: `${useExeAgent ? "exe-agent" : "claude"} did not boot within 15s` };
2056
+ const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
2057
+ return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
1939
2058
  }
1940
- if (!useExeAgent) {
2059
+ if (!useExeAgent && !useCodex) {
1941
2060
  try {
1942
2061
  transport.sendKeys(sessionName, `/exe-call ${employeeName}`);
1943
2062
  } catch {
@@ -1964,17 +2083,19 @@ var init_tmux_routing = __esm({
1964
2083
  init_cc_agent_support();
1965
2084
  init_mcp_prefix();
1966
2085
  init_provider_table();
2086
+ init_agent_config();
2087
+ init_runtime_table();
1967
2088
  init_intercom_queue();
1968
2089
  init_plan_limits();
1969
2090
  init_employees();
1970
- SPAWN_LOCK_DIR = path8.join(os6.homedir(), ".exe-os", "spawn-locks");
1971
- SESSION_CACHE = path8.join(os6.homedir(), ".exe-os", "session-cache");
2091
+ SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
2092
+ SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
1972
2093
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
1973
2094
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
1974
2095
  VERIFY_PANE_LINES = 200;
1975
2096
  INTERCOM_DEBOUNCE_MS = 3e4;
1976
- INTERCOM_LOG2 = path8.join(os6.homedir(), ".exe-os", "intercom.log");
1977
- DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
2097
+ INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
2098
+ DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
1978
2099
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
1979
2100
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
1980
2101
  }
@@ -2006,11 +2127,11 @@ var init_task_scope = __esm({
2006
2127
 
2007
2128
  // src/lib/tasks-crud.ts
2008
2129
  import crypto3 from "crypto";
2009
- import path9 from "path";
2130
+ import path10 from "path";
2010
2131
  import os7 from "os";
2011
2132
  import { execSync as execSync5 } from "child_process";
2012
2133
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2013
- import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
2134
+ import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
2014
2135
  async function writeCheckpoint(input) {
2015
2136
  const client = getClient();
2016
2137
  const row = await resolveTask(client, input.taskId);
@@ -2185,8 +2306,8 @@ ${laneWarning}` : laneWarning;
2185
2306
  }
2186
2307
  if (input.baseDir) {
2187
2308
  try {
2188
- await mkdir3(path9.join(input.baseDir, "exe", "output"), { recursive: true });
2189
- await mkdir3(path9.join(input.baseDir, "exe", "research"), { recursive: true });
2309
+ await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
2310
+ await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
2190
2311
  await ensureArchitectureDoc(input.baseDir, input.projectName);
2191
2312
  await ensureGitignoreExe(input.baseDir);
2192
2313
  } catch {
@@ -2222,10 +2343,10 @@ ${laneWarning}` : laneWarning;
2222
2343
  });
2223
2344
  if (input.baseDir) {
2224
2345
  try {
2225
- const EXE_OS_DIR = path9.join(os7.homedir(), ".exe-os");
2226
- const mdPath = path9.join(EXE_OS_DIR, taskFile);
2227
- const mdDir = path9.dirname(mdPath);
2228
- if (!existsSync9(mdDir)) await mkdir3(mdDir, { recursive: true });
2346
+ const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
2347
+ const mdPath = path10.join(EXE_OS_DIR, taskFile);
2348
+ const mdDir = path10.dirname(mdPath);
2349
+ if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
2229
2350
  const reviewer = input.reviewer ?? input.assignedBy;
2230
2351
  const mdContent = `# ${input.title}
2231
2352
 
@@ -2250,7 +2371,11 @@ If you skip this, your reviewer will not know you're done and your work won't be
2250
2371
  Do NOT let a failed commit or any error prevent you from calling update_task(done).
2251
2372
  `;
2252
2373
  await writeFile3(mdPath, mdContent, "utf-8");
2253
- } catch {
2374
+ } catch (err) {
2375
+ process.stderr.write(
2376
+ `[create-task] WARNING: .md file write failed for ${taskFile}: ${err instanceof Error ? err.message : String(err)}
2377
+ `
2378
+ );
2254
2379
  }
2255
2380
  }
2256
2381
  return {
@@ -2510,9 +2635,9 @@ async function deleteTaskCore(taskId, _baseDir) {
2510
2635
  return { taskFile, assignedTo, assignedBy, taskSlug };
2511
2636
  }
2512
2637
  async function ensureArchitectureDoc(baseDir, projectName) {
2513
- const archPath = path9.join(baseDir, "exe", "ARCHITECTURE.md");
2638
+ const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
2514
2639
  try {
2515
- if (existsSync9(archPath)) return;
2640
+ if (existsSync10(archPath)) return;
2516
2641
  const template = [
2517
2642
  `# ${projectName} \u2014 System Architecture`,
2518
2643
  "",
@@ -2545,10 +2670,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
2545
2670
  }
2546
2671
  }
2547
2672
  async function ensureGitignoreExe(baseDir) {
2548
- const gitignorePath = path9.join(baseDir, ".gitignore");
2673
+ const gitignorePath = path10.join(baseDir, ".gitignore");
2549
2674
  try {
2550
- if (existsSync9(gitignorePath)) {
2551
- const content = readFileSync9(gitignorePath, "utf-8");
2675
+ if (existsSync10(gitignorePath)) {
2676
+ const content = readFileSync10(gitignorePath, "utf-8");
2552
2677
  if (/^\/?exe\/?$/m.test(content)) return;
2553
2678
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
2554
2679
  } else {
@@ -2579,8 +2704,8 @@ var init_tasks_crud = __esm({
2579
2704
  });
2580
2705
 
2581
2706
  // src/lib/tasks-review.ts
2582
- import path10 from "path";
2583
- import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
2707
+ import path11 from "path";
2708
+ import { existsSync as existsSync11, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
2584
2709
  async function countPendingReviews(sessionScope) {
2585
2710
  const client = getClient();
2586
2711
  if (sessionScope) {
@@ -2761,11 +2886,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
2761
2886
  );
2762
2887
  }
2763
2888
  try {
2764
- const cacheDir = path10.join(EXE_AI_DIR, "session-cache");
2765
- if (existsSync10(cacheDir)) {
2889
+ const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
2890
+ if (existsSync11(cacheDir)) {
2766
2891
  for (const f of readdirSync2(cacheDir)) {
2767
2892
  if (f.startsWith("review-notified-")) {
2768
- unlinkSync4(path10.join(cacheDir, f));
2893
+ unlinkSync4(path11.join(cacheDir, f));
2769
2894
  }
2770
2895
  }
2771
2896
  }
@@ -2786,7 +2911,7 @@ var init_tasks_review = __esm({
2786
2911
  });
2787
2912
 
2788
2913
  // src/lib/tasks-chain.ts
2789
- import path11 from "path";
2914
+ import path12 from "path";
2790
2915
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
2791
2916
  async function cascadeUnblock(taskId, baseDir, now) {
2792
2917
  const client = getClient();
@@ -2803,7 +2928,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
2803
2928
  });
2804
2929
  for (const ur of unblockedRows.rows) {
2805
2930
  try {
2806
- const ubFile = path11.join(baseDir, String(ur.task_file));
2931
+ const ubFile = path12.join(baseDir, String(ur.task_file));
2807
2932
  let ubContent = await readFile3(ubFile, "utf-8");
2808
2933
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
2809
2934
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -2872,7 +2997,7 @@ var init_tasks_chain = __esm({
2872
2997
 
2873
2998
  // src/lib/project-name.ts
2874
2999
  import { execSync as execSync6 } from "child_process";
2875
- import path12 from "path";
3000
+ import path13 from "path";
2876
3001
  function getProjectName(cwd) {
2877
3002
  const dir = cwd ?? process.cwd();
2878
3003
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -2885,7 +3010,7 @@ function getProjectName(cwd) {
2885
3010
  timeout: 2e3,
2886
3011
  stdio: ["pipe", "pipe", "pipe"]
2887
3012
  }).trim();
2888
- repoRoot = path12.dirname(gitCommonDir);
3013
+ repoRoot = path13.dirname(gitCommonDir);
2889
3014
  } catch {
2890
3015
  repoRoot = execSync6("git rev-parse --show-toplevel", {
2891
3016
  cwd: dir,
@@ -2894,11 +3019,11 @@ function getProjectName(cwd) {
2894
3019
  stdio: ["pipe", "pipe", "pipe"]
2895
3020
  }).trim();
2896
3021
  }
2897
- _cached2 = path12.basename(repoRoot);
3022
+ _cached2 = path13.basename(repoRoot);
2898
3023
  _cachedCwd = dir;
2899
3024
  return _cached2;
2900
3025
  } catch {
2901
- _cached2 = path12.basename(dir);
3026
+ _cached2 = path13.basename(dir);
2902
3027
  _cachedCwd = dir;
2903
3028
  return _cached2;
2904
3029
  }
@@ -3371,8 +3496,8 @@ __export(tasks_exports, {
3371
3496
  updateTaskStatus: () => updateTaskStatus,
3372
3497
  writeCheckpoint: () => writeCheckpoint
3373
3498
  });
3374
- import path13 from "path";
3375
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5 } from "fs";
3499
+ import path14 from "path";
3500
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
3376
3501
  async function createTask(input) {
3377
3502
  const result = await createTaskCore(input);
3378
3503
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -3391,11 +3516,11 @@ async function updateTask(input) {
3391
3516
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
3392
3517
  try {
3393
3518
  const agent = String(row.assigned_to);
3394
- const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
3395
- const cachePath = path13.join(cacheDir, `current-task-${agent}.json`);
3519
+ const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
3520
+ const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
3396
3521
  if (input.status === "in_progress") {
3397
- mkdirSync5(cacheDir, { recursive: true });
3398
- writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
3522
+ mkdirSync6(cacheDir, { recursive: true });
3523
+ writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
3399
3524
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
3400
3525
  try {
3401
3526
  unlinkSync5(cachePath);
@@ -3561,17 +3686,17 @@ __export(identity_exports, {
3561
3686
  listIdentities: () => listIdentities,
3562
3687
  updateIdentity: () => updateIdentity
3563
3688
  });
3564
- import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
3689
+ import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
3565
3690
  import { readdirSync as readdirSync4 } from "fs";
3566
- import path15 from "path";
3691
+ import path16 from "path";
3567
3692
  import { createHash } from "crypto";
3568
3693
  function ensureDir2() {
3569
- if (!existsSync11(IDENTITY_DIR)) {
3570
- mkdirSync7(IDENTITY_DIR, { recursive: true });
3694
+ if (!existsSync12(IDENTITY_DIR)) {
3695
+ mkdirSync8(IDENTITY_DIR, { recursive: true });
3571
3696
  }
3572
3697
  }
3573
3698
  function identityPath(agentId) {
3574
- return path15.join(IDENTITY_DIR, `${agentId}.md`);
3699
+ return path16.join(IDENTITY_DIR, `${agentId}.md`);
3575
3700
  }
3576
3701
  function parseFrontmatter(raw) {
3577
3702
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -3612,8 +3737,8 @@ function contentHash(content) {
3612
3737
  }
3613
3738
  function getIdentity(agentId) {
3614
3739
  const filePath = identityPath(agentId);
3615
- if (!existsSync11(filePath)) return null;
3616
- const raw = readFileSync11(filePath, "utf-8");
3740
+ if (!existsSync12(filePath)) return null;
3741
+ const raw = readFileSync12(filePath, "utf-8");
3617
3742
  const { frontmatter, body } = parseFrontmatter(raw);
3618
3743
  return {
3619
3744
  agentId,
@@ -3627,7 +3752,7 @@ async function updateIdentity(agentId, content, updatedBy) {
3627
3752
  ensureDir2();
3628
3753
  const filePath = identityPath(agentId);
3629
3754
  const hash = contentHash(content);
3630
- writeFileSync8(filePath, content, "utf-8");
3755
+ writeFileSync9(filePath, content, "utf-8");
3631
3756
  try {
3632
3757
  const client = getClient();
3633
3758
  await client.execute({
@@ -3683,7 +3808,7 @@ var init_identity = __esm({
3683
3808
  "use strict";
3684
3809
  init_config();
3685
3810
  init_database();
3686
- IDENTITY_DIR = path15.join(EXE_AI_DIR, "identity");
3811
+ IDENTITY_DIR = path16.join(EXE_AI_DIR, "identity");
3687
3812
  }
3688
3813
  });
3689
3814
 
@@ -4223,16 +4348,16 @@ import { z } from "zod";
4223
4348
 
4224
4349
  // src/adapters/claude/active-agent.ts
4225
4350
  init_config();
4226
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync6, readdirSync as readdirSync3 } from "fs";
4351
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, unlinkSync as unlinkSync6, readdirSync as readdirSync3 } from "fs";
4227
4352
  import { execSync as execSync7 } from "child_process";
4228
- import path14 from "path";
4353
+ import path15 from "path";
4229
4354
 
4230
4355
  // src/adapters/claude/session-key.ts
4231
4356
  init_session_key();
4232
4357
 
4233
4358
  // src/adapters/claude/active-agent.ts
4234
4359
  init_employees();
4235
- var CACHE_DIR = path14.join(EXE_AI_DIR, "session-cache");
4360
+ var CACHE_DIR = path15.join(EXE_AI_DIR, "session-cache");
4236
4361
  var STALE_MS = 24 * 60 * 60 * 1e3;
4237
4362
  function isNameWithOptionalInstance(candidate, baseName) {
4238
4363
  if (candidate === baseName) return true;
@@ -4277,12 +4402,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
4277
4402
  return null;
4278
4403
  }
4279
4404
  function getMarkerPath() {
4280
- return path14.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
4405
+ return path15.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
4281
4406
  }
4282
4407
  function getActiveAgent() {
4283
4408
  try {
4284
4409
  const markerPath = getMarkerPath();
4285
- const raw = readFileSync10(markerPath, "utf8");
4410
+ const raw = readFileSync11(markerPath, "utf8");
4286
4411
  const data = JSON.parse(raw);
4287
4412
  if (data.agentId) {
4288
4413
  if (data.startedAt) {
@@ -4367,10 +4492,10 @@ function registerCreateTask(server) {
4367
4492
  skipDispatch: true
4368
4493
  });
4369
4494
  try {
4370
- const { existsSync: existsSync12, mkdirSync: mkdirSync8, writeFileSync: writeFileSync9 } = await import("fs");
4495
+ const { existsSync: existsSync13, mkdirSync: mkdirSync9, writeFileSync: writeFileSync10 } = await import("fs");
4371
4496
  const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
4372
4497
  const idPath = identityPath2(assigned_to);
4373
- if (!existsSync12(idPath)) {
4498
+ if (!existsSync13(idPath)) {
4374
4499
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
4375
4500
  const employees = await loadEmployees2();
4376
4501
  const emp = employees.find((e) => e.name === assigned_to);
@@ -4379,8 +4504,8 @@ function registerCreateTask(server) {
4379
4504
  const template = getTemplateForTitle2(emp.role);
4380
4505
  if (template) {
4381
4506
  const dir = (await import("path")).dirname(idPath);
4382
- if (!existsSync12(dir)) mkdirSync8(dir, { recursive: true });
4383
- writeFileSync9(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
4507
+ if (!existsSync13(dir)) mkdirSync9(dir, { recursive: true });
4508
+ writeFileSync10(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
4384
4509
  }
4385
4510
  }
4386
4511
  }