@askexenow/exe-os 0.9.6 → 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 +668 -37
  5. package/dist/bin/cli.js +1399 -607
  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 +795 -155
  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 +703 -72
  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 +1064 -273
  17. package/dist/bin/exe-heartbeat.js +676 -45
  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 +845 -152
  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 +668 -37
  33. package/dist/bin/exe-team.js +635 -13
  34. package/dist/bin/git-sweep.js +731 -91
  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 +735 -95
  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 +1038 -247
  43. package/dist/hooks/bug-report-worker.js +902 -172
  44. package/dist/hooks/commit-complete.js +729 -89
  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 +851 -158
  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 +685 -45
  52. package/dist/hooks/pre-compact.js +729 -89
  53. package/dist/hooks/pre-tool-use.js +883 -127
  54. package/dist/hooks/prompt-ingest-worker.js +758 -83
  55. package/dist/hooks/prompt-submit.js +1071 -321
  56. package/dist/hooks/response-ingest-worker.js +758 -83
  57. package/dist/hooks/session-end.js +732 -92
  58. package/dist/hooks/session-start.js +1042 -209
  59. package/dist/hooks/stop.js +691 -51
  60. package/dist/hooks/subagent-stop.js +685 -45
  61. package/dist/hooks/summary-worker.js +827 -134
  62. package/dist/index.js +1026 -234
  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 +905 -164
  73. package/dist/lib/hybrid-search.js +771 -88
  74. package/dist/lib/identity.js +27 -7
  75. package/dist/lib/messaging.js +66 -30
  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 +109 -73
  82. package/dist/lib/tmux-routing.js +98 -62
  83. package/dist/lib/token-spend.js +26 -6
  84. package/dist/mcp/server.js +1807 -472
  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 +301 -166
  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 +206 -40
  91. package/dist/mcp/tools/send-message.js +69 -33
  92. package/dist/mcp/tools/update-task.js +86 -50
  93. package/dist/runtime/index.js +731 -91
  94. package/dist/tui/App.js +864 -125
  95. package/package.json +3 -2
package/dist/lib/tasks.js CHANGED
@@ -262,7 +262,7 @@ function isMultiInstance(agentName, employees) {
262
262
  if (!emp) return false;
263
263
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
264
264
  }
265
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
265
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
266
266
  var init_employees = __esm({
267
267
  "src/lib/employees.ts"() {
268
268
  "use strict";
@@ -271,15 +271,40 @@ var init_employees = __esm({
271
271
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
272
272
  COORDINATOR_ROLE = "COO";
273
273
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
274
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
275
+ }
276
+ });
277
+
278
+ // src/lib/database-adapter.ts
279
+ import os3 from "os";
280
+ import path3 from "path";
281
+ import { createRequire } from "module";
282
+ import { pathToFileURL } from "url";
283
+ var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
284
+ var init_database_adapter = __esm({
285
+ "src/lib/database-adapter.ts"() {
286
+ "use strict";
287
+ BOOLEAN_COLUMNS_BY_TABLE = {
288
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
289
+ behaviors: /* @__PURE__ */ new Set(["active"]),
290
+ notifications: /* @__PURE__ */ new Set(["read"]),
291
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
292
+ };
293
+ BOOLEAN_COLUMN_NAMES = new Set(
294
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
295
+ );
274
296
  }
275
297
  });
276
298
 
277
299
  // src/lib/database.ts
278
300
  import { createClient } from "@libsql/client";
279
301
  function getClient() {
280
- if (!_resilientClient) {
302
+ if (!_adapterClient) {
281
303
  throw new Error("Database client not initialized. Call initDatabase() first.");
282
304
  }
305
+ if (process.env.DATABASE_URL) {
306
+ return _adapterClient;
307
+ }
283
308
  if (process.env.EXE_IS_DAEMON === "1") {
284
309
  return _resilientClient;
285
310
  }
@@ -288,21 +313,23 @@ function getClient() {
288
313
  }
289
314
  return _resilientClient;
290
315
  }
291
- var _resilientClient, _daemonClient;
316
+ var _resilientClient, _daemonClient, _adapterClient;
292
317
  var init_database = __esm({
293
318
  "src/lib/database.ts"() {
294
319
  "use strict";
295
320
  init_db_retry();
296
321
  init_employees();
322
+ init_database_adapter();
297
323
  _resilientClient = null;
298
324
  _daemonClient = null;
325
+ _adapterClient = null;
299
326
  }
300
327
  });
301
328
 
302
329
  // src/lib/notifications.ts
303
330
  import crypto from "crypto";
304
- import path3 from "path";
305
- import os3 from "os";
331
+ import path4 from "path";
332
+ import os4 from "os";
306
333
  import {
307
334
  readFileSync as readFileSync3,
308
335
  readdirSync,
@@ -408,10 +435,10 @@ var init_state_bus = __esm({
408
435
 
409
436
  // src/lib/session-registry.ts
410
437
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync4 } from "fs";
411
- import path4 from "path";
412
- import os4 from "os";
438
+ import path5 from "path";
439
+ import os5 from "os";
413
440
  function registerSession(entry) {
414
- const dir = path4.dirname(REGISTRY_PATH);
441
+ const dir = path5.dirname(REGISTRY_PATH);
415
442
  if (!existsSync4(dir)) {
416
443
  mkdirSync(dir, { recursive: true });
417
444
  }
@@ -436,7 +463,7 @@ var REGISTRY_PATH;
436
463
  var init_session_registry = __esm({
437
464
  "src/lib/session-registry.ts"() {
438
465
  "use strict";
439
- REGISTRY_PATH = path4.join(os4.homedir(), ".exe-os", "session-registry.json");
466
+ REGISTRY_PATH = path5.join(os5.homedir(), ".exe-os", "session-registry.json");
440
467
  }
441
468
  });
442
469
 
@@ -717,7 +744,7 @@ var init_runtime_table = __esm({
717
744
 
718
745
  // src/lib/agent-config.ts
719
746
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
720
- import path5 from "path";
747
+ import path6 from "path";
721
748
  function loadAgentConfig() {
722
749
  if (!existsSync5(AGENT_CONFIG_PATH)) return {};
723
750
  try {
@@ -740,7 +767,7 @@ var init_agent_config = __esm({
740
767
  "use strict";
741
768
  init_config();
742
769
  init_runtime_table();
743
- AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
770
+ AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
744
771
  DEFAULT_MODELS = {
745
772
  claude: "claude-opus-4",
746
773
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
@@ -759,10 +786,10 @@ __export(intercom_queue_exports, {
759
786
  readQueue: () => readQueue
760
787
  });
761
788
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
762
- import path6 from "path";
763
- import os5 from "os";
789
+ import path7 from "path";
790
+ import os6 from "os";
764
791
  function ensureDir() {
765
- const dir = path6.dirname(QUEUE_PATH);
792
+ const dir = path7.dirname(QUEUE_PATH);
766
793
  if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
767
794
  }
768
795
  function readQueue() {
@@ -868,26 +895,26 @@ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
868
895
  var init_intercom_queue = __esm({
869
896
  "src/lib/intercom-queue.ts"() {
870
897
  "use strict";
871
- QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
898
+ QUEUE_PATH = path7.join(os6.homedir(), ".exe-os", "intercom-queue.json");
872
899
  MAX_RETRIES = 5;
873
900
  TTL_MS = 60 * 60 * 1e3;
874
- INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
901
+ INTERCOM_LOG = path7.join(os6.homedir(), ".exe-os", "intercom.log");
875
902
  }
876
903
  });
877
904
 
878
905
  // src/lib/license.ts
879
906
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
880
907
  import { randomUUID } from "crypto";
881
- import path7 from "path";
908
+ import path8 from "path";
882
909
  import { jwtVerify, importSPKI } from "jose";
883
910
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
884
911
  var init_license = __esm({
885
912
  "src/lib/license.ts"() {
886
913
  "use strict";
887
914
  init_config();
888
- LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
889
- CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
890
- DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
915
+ LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
916
+ CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
917
+ DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
891
918
  PLAN_LIMITS = {
892
919
  free: { devices: 1, employees: 1, memories: 5e3 },
893
920
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -900,7 +927,7 @@ var init_license = __esm({
900
927
 
901
928
  // src/lib/plan-limits.ts
902
929
  import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
903
- import path8 from "path";
930
+ import path9 from "path";
904
931
  function getLicenseSync() {
905
932
  try {
906
933
  if (!existsSync8(CACHE_PATH2)) return freeLicense();
@@ -972,7 +999,7 @@ var init_plan_limits = __esm({
972
999
  this.name = "PlanLimitError";
973
1000
  }
974
1001
  };
975
- CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
1002
+ CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
976
1003
  }
977
1004
  });
978
1005
 
@@ -1321,12 +1348,12 @@ __export(tmux_routing_exports, {
1321
1348
  });
1322
1349
  import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
1323
1350
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync9, appendFileSync, readdirSync as readdirSync2 } from "fs";
1324
- import path9 from "path";
1325
- import os6 from "os";
1351
+ import path10 from "path";
1352
+ import os7 from "os";
1326
1353
  import { fileURLToPath } from "url";
1327
1354
  import { unlinkSync as unlinkSync3 } from "fs";
1328
1355
  function spawnLockPath(sessionName) {
1329
- return path9.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
1356
+ return path10.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
1330
1357
  }
1331
1358
  function isProcessAlive(pid) {
1332
1359
  try {
@@ -1363,8 +1390,8 @@ function releaseSpawnLock(sessionName) {
1363
1390
  function resolveBehaviorsExporterScript() {
1364
1391
  try {
1365
1392
  const thisFile = fileURLToPath(import.meta.url);
1366
- const scriptPath = path9.join(
1367
- path9.dirname(thisFile),
1393
+ const scriptPath = path10.join(
1394
+ path10.dirname(thisFile),
1368
1395
  "..",
1369
1396
  "bin",
1370
1397
  "exe-export-behaviors.js"
@@ -1439,7 +1466,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
1439
1466
  mkdirSync5(SESSION_CACHE, { recursive: true });
1440
1467
  }
1441
1468
  const rootExe = extractRootExe(parentExe) ?? parentExe;
1442
- const filePath = path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
1469
+ const filePath = path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
1443
1470
  writeFileSync6(filePath, JSON.stringify({
1444
1471
  parentExe: rootExe,
1445
1472
  dispatchedBy: dispatchedBy || rootExe,
@@ -1448,7 +1475,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
1448
1475
  }
1449
1476
  function getParentExe(sessionKey) {
1450
1477
  try {
1451
- const data = JSON.parse(readFileSync9(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1478
+ const data = JSON.parse(readFileSync9(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1452
1479
  return data.parentExe || null;
1453
1480
  } catch {
1454
1481
  return null;
@@ -1457,7 +1484,7 @@ function getParentExe(sessionKey) {
1457
1484
  function getDispatchedBy(sessionKey) {
1458
1485
  try {
1459
1486
  const data = JSON.parse(readFileSync9(
1460
- path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
1487
+ path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
1461
1488
  "utf8"
1462
1489
  ));
1463
1490
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -1468,15 +1495,24 @@ function getDispatchedBy(sessionKey) {
1468
1495
  function resolveExeSession() {
1469
1496
  const mySession = getMySession();
1470
1497
  if (!mySession) return null;
1498
+ const fromSessionName = extractRootExe(mySession);
1471
1499
  try {
1472
1500
  const key = getSessionKey();
1473
1501
  const parentExe = getParentExe(key);
1474
1502
  if (parentExe) {
1475
- return extractRootExe(parentExe) ?? parentExe;
1503
+ const fromCache = extractRootExe(parentExe) ?? parentExe;
1504
+ if (fromSessionName && fromCache !== fromSessionName) {
1505
+ process.stderr.write(
1506
+ `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
1507
+ `
1508
+ );
1509
+ return fromSessionName;
1510
+ }
1511
+ return fromCache;
1476
1512
  }
1477
1513
  } catch {
1478
1514
  }
1479
- return extractRootExe(mySession) ?? mySession;
1515
+ return fromSessionName ?? mySession;
1480
1516
  }
1481
1517
  function isEmployeeAlive(sessionName) {
1482
1518
  return getTransport().isAlive(sessionName);
@@ -1634,7 +1670,7 @@ function sendIntercom(targetSession) {
1634
1670
  try {
1635
1671
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
1636
1672
  const agent = baseAgentName(rawAgent);
1637
- const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
1673
+ const markerPath = path10.join(SESSION_CACHE, `current-task-${agent}.json`);
1638
1674
  if (existsSync9(markerPath)) {
1639
1675
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
1640
1676
  return "debounced";
@@ -1644,7 +1680,7 @@ function sendIntercom(targetSession) {
1644
1680
  try {
1645
1681
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
1646
1682
  const agent = baseAgentName(rawAgent);
1647
- const taskDir = path9.join(process.cwd(), "exe", agent);
1683
+ const taskDir = path10.join(process.cwd(), "exe", agent);
1648
1684
  if (existsSync9(taskDir)) {
1649
1685
  const files = readdirSync2(taskDir).filter(
1650
1686
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -1778,8 +1814,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1778
1814
  const transport = getTransport();
1779
1815
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
1780
1816
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
1781
- const logDir = path9.join(os6.homedir(), ".exe-os", "session-logs");
1782
- const logFile = path9.join(logDir, `${instanceLabel}-${Date.now()}.log`);
1817
+ const logDir = path10.join(os7.homedir(), ".exe-os", "session-logs");
1818
+ const logFile = path10.join(logDir, `${instanceLabel}-${Date.now()}.log`);
1783
1819
  if (!existsSync9(logDir)) {
1784
1820
  mkdirSync5(logDir, { recursive: true });
1785
1821
  }
@@ -1787,14 +1823,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1787
1823
  let cleanupSuffix = "";
1788
1824
  try {
1789
1825
  const thisFile = fileURLToPath(import.meta.url);
1790
- const cleanupScript = path9.join(path9.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
1826
+ const cleanupScript = path10.join(path10.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
1791
1827
  if (existsSync9(cleanupScript)) {
1792
1828
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
1793
1829
  }
1794
1830
  } catch {
1795
1831
  }
1796
1832
  try {
1797
- const claudeJsonPath = path9.join(os6.homedir(), ".claude.json");
1833
+ const claudeJsonPath = path10.join(os7.homedir(), ".claude.json");
1798
1834
  let claudeJson = {};
1799
1835
  try {
1800
1836
  claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
@@ -1809,10 +1845,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1809
1845
  } catch {
1810
1846
  }
1811
1847
  try {
1812
- const settingsDir = path9.join(os6.homedir(), ".claude", "projects");
1848
+ const settingsDir = path10.join(os7.homedir(), ".claude", "projects");
1813
1849
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
1814
- const projSettingsDir = path9.join(settingsDir, normalizedKey);
1815
- const settingsPath = path9.join(projSettingsDir, "settings.json");
1850
+ const projSettingsDir = path10.join(settingsDir, normalizedKey);
1851
+ const settingsPath = path10.join(projSettingsDir, "settings.json");
1816
1852
  let settings = {};
1817
1853
  try {
1818
1854
  settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
@@ -1859,8 +1895,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1859
1895
  let behaviorsFlag = "";
1860
1896
  let legacyFallbackWarned = false;
1861
1897
  if (!useExeAgent && !useBinSymlink) {
1862
- const identityPath = path9.join(
1863
- os6.homedir(),
1898
+ const identityPath = path10.join(
1899
+ os7.homedir(),
1864
1900
  ".exe-os",
1865
1901
  "identity",
1866
1902
  `${employeeName}.md`
@@ -1875,7 +1911,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1875
1911
  }
1876
1912
  const behaviorsFile = exportBehaviorsSync(
1877
1913
  employeeName,
1878
- path9.basename(spawnCwd),
1914
+ path10.basename(spawnCwd),
1879
1915
  sessionName
1880
1916
  );
1881
1917
  if (behaviorsFile) {
@@ -1890,9 +1926,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1890
1926
  }
1891
1927
  let sessionContextFlag = "";
1892
1928
  try {
1893
- const ctxDir = path9.join(os6.homedir(), ".exe-os", "session-cache");
1929
+ const ctxDir = path10.join(os7.homedir(), ".exe-os", "session-cache");
1894
1930
  mkdirSync5(ctxDir, { recursive: true });
1895
- const ctxFile = path9.join(ctxDir, `session-context-${sessionName}.md`);
1931
+ const ctxFile = path10.join(ctxDir, `session-context-${sessionName}.md`);
1896
1932
  const ctxContent = [
1897
1933
  `## Session Context`,
1898
1934
  `You are running in tmux session: ${sessionName}.`,
@@ -1976,7 +2012,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1976
2012
  transport.pipeLog(sessionName, logFile);
1977
2013
  try {
1978
2014
  const mySession = getMySession();
1979
- const dispatchInfo = path9.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
2015
+ const dispatchInfo = path10.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
1980
2016
  writeFileSync6(dispatchInfo, JSON.stringify({
1981
2017
  dispatchedBy: mySession,
1982
2018
  rootExe: exeSession,
@@ -2051,15 +2087,15 @@ var init_tmux_routing = __esm({
2051
2087
  init_intercom_queue();
2052
2088
  init_plan_limits();
2053
2089
  init_employees();
2054
- SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
2055
- SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
2090
+ SPAWN_LOCK_DIR = path10.join(os7.homedir(), ".exe-os", "spawn-locks");
2091
+ SESSION_CACHE = path10.join(os7.homedir(), ".exe-os", "session-cache");
2056
2092
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
2057
2093
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
2058
2094
  VERIFY_PANE_LINES = 200;
2059
2095
  INTERCOM_DEBOUNCE_MS = 3e4;
2060
2096
  CODEX_DEBOUNCE_MS = 12e4;
2061
- INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
2062
- DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
2097
+ INTERCOM_LOG2 = path10.join(os7.homedir(), ".exe-os", "intercom.log");
2098
+ DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
2063
2099
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
2064
2100
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
2065
2101
  }
@@ -2091,8 +2127,8 @@ var init_task_scope = __esm({
2091
2127
 
2092
2128
  // src/lib/tasks-crud.ts
2093
2129
  import crypto3 from "crypto";
2094
- import path10 from "path";
2095
- import os7 from "os";
2130
+ import path11 from "path";
2131
+ import os8 from "os";
2096
2132
  import { execSync as execSync5 } from "child_process";
2097
2133
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2098
2134
  import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
@@ -2270,8 +2306,8 @@ ${laneWarning}` : laneWarning;
2270
2306
  }
2271
2307
  if (input.baseDir) {
2272
2308
  try {
2273
- await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
2274
- await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
2309
+ await mkdir3(path11.join(input.baseDir, "exe", "output"), { recursive: true });
2310
+ await mkdir3(path11.join(input.baseDir, "exe", "research"), { recursive: true });
2275
2311
  await ensureArchitectureDoc(input.baseDir, input.projectName);
2276
2312
  await ensureGitignoreExe(input.baseDir);
2277
2313
  } catch {
@@ -2307,9 +2343,9 @@ ${laneWarning}` : laneWarning;
2307
2343
  });
2308
2344
  if (input.baseDir) {
2309
2345
  try {
2310
- const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
2311
- const mdPath = path10.join(EXE_OS_DIR, taskFile);
2312
- const mdDir = path10.dirname(mdPath);
2346
+ const EXE_OS_DIR = path11.join(os8.homedir(), ".exe-os");
2347
+ const mdPath = path11.join(EXE_OS_DIR, taskFile);
2348
+ const mdDir = path11.dirname(mdPath);
2313
2349
  if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
2314
2350
  const reviewer = input.reviewer ?? input.assignedBy;
2315
2351
  const mdContent = `# ${input.title}
@@ -2610,7 +2646,7 @@ async function deleteTaskCore(taskId, _baseDir) {
2610
2646
  return { taskFile, assignedTo, assignedBy, taskSlug };
2611
2647
  }
2612
2648
  async function ensureArchitectureDoc(baseDir, projectName) {
2613
- const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
2649
+ const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
2614
2650
  try {
2615
2651
  if (existsSync10(archPath)) return;
2616
2652
  const template = [
@@ -2645,7 +2681,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
2645
2681
  }
2646
2682
  }
2647
2683
  async function ensureGitignoreExe(baseDir) {
2648
- const gitignorePath = path10.join(baseDir, ".gitignore");
2684
+ const gitignorePath = path11.join(baseDir, ".gitignore");
2649
2685
  try {
2650
2686
  if (existsSync10(gitignorePath)) {
2651
2687
  const content = readFileSync10(gitignorePath, "utf-8");
@@ -2679,13 +2715,13 @@ var init_tasks_crud = __esm({
2679
2715
  });
2680
2716
 
2681
2717
  // src/lib/tasks-review.ts
2682
- import path11 from "path";
2718
+ import path12 from "path";
2683
2719
  import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
2684
2720
  async function countPendingReviews(sessionScope) {
2685
2721
  const client = getClient();
2686
2722
  if (sessionScope) {
2687
2723
  const result2 = await client.execute({
2688
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
2724
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
2689
2725
  args: [sessionScope]
2690
2726
  });
2691
2727
  return Number(result2.rows[0]?.cnt) || 0;
@@ -2861,11 +2897,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
2861
2897
  );
2862
2898
  }
2863
2899
  try {
2864
- const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
2900
+ const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
2865
2901
  if (existsSync11(cacheDir)) {
2866
2902
  for (const f of readdirSync3(cacheDir)) {
2867
2903
  if (f.startsWith("review-notified-")) {
2868
- unlinkSync4(path11.join(cacheDir, f));
2904
+ unlinkSync4(path12.join(cacheDir, f));
2869
2905
  }
2870
2906
  }
2871
2907
  }
@@ -2886,7 +2922,7 @@ var init_tasks_review = __esm({
2886
2922
  });
2887
2923
 
2888
2924
  // src/lib/tasks-chain.ts
2889
- import path12 from "path";
2925
+ import path13 from "path";
2890
2926
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
2891
2927
  async function cascadeUnblock(taskId, baseDir, now) {
2892
2928
  const client = getClient();
@@ -2903,7 +2939,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
2903
2939
  });
2904
2940
  for (const ur of unblockedRows.rows) {
2905
2941
  try {
2906
- const ubFile = path12.join(baseDir, String(ur.task_file));
2942
+ const ubFile = path13.join(baseDir, String(ur.task_file));
2907
2943
  let ubContent = await readFile3(ubFile, "utf-8");
2908
2944
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
2909
2945
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -2972,7 +3008,7 @@ var init_tasks_chain = __esm({
2972
3008
 
2973
3009
  // src/lib/project-name.ts
2974
3010
  import { execSync as execSync6 } from "child_process";
2975
- import path13 from "path";
3011
+ import path14 from "path";
2976
3012
  function getProjectName(cwd) {
2977
3013
  const dir = cwd ?? process.cwd();
2978
3014
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -2985,7 +3021,7 @@ function getProjectName(cwd) {
2985
3021
  timeout: 2e3,
2986
3022
  stdio: ["pipe", "pipe", "pipe"]
2987
3023
  }).trim();
2988
- repoRoot = path13.dirname(gitCommonDir);
3024
+ repoRoot = path14.dirname(gitCommonDir);
2989
3025
  } catch {
2990
3026
  repoRoot = execSync6("git rev-parse --show-toplevel", {
2991
3027
  cwd: dir,
@@ -2994,11 +3030,11 @@ function getProjectName(cwd) {
2994
3030
  stdio: ["pipe", "pipe", "pipe"]
2995
3031
  }).trim();
2996
3032
  }
2997
- _cached2 = path13.basename(repoRoot);
3033
+ _cached2 = path14.basename(repoRoot);
2998
3034
  _cachedCwd = dir;
2999
3035
  return _cached2;
3000
3036
  } catch {
3001
- _cached2 = path13.basename(dir);
3037
+ _cached2 = path14.basename(dir);
3002
3038
  _cachedCwd = dir;
3003
3039
  return _cached2;
3004
3040
  }
@@ -3471,7 +3507,7 @@ __export(tasks_exports, {
3471
3507
  updateTaskStatus: () => updateTaskStatus,
3472
3508
  writeCheckpoint: () => writeCheckpoint
3473
3509
  });
3474
- import path14 from "path";
3510
+ import path15 from "path";
3475
3511
  import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
3476
3512
  async function createTask(input) {
3477
3513
  const result = await createTaskCore(input);
@@ -3491,8 +3527,8 @@ async function updateTask(input) {
3491
3527
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
3492
3528
  try {
3493
3529
  const agent = String(row.assigned_to);
3494
- const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
3495
- const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
3530
+ const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
3531
+ const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
3496
3532
  if (input.status === "in_progress") {
3497
3533
  mkdirSync6(cacheDir, { recursive: true });
3498
3534
  writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));