@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/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;
@@ -1643,7 +1670,7 @@ function sendIntercom(targetSession) {
1643
1670
  try {
1644
1671
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
1645
1672
  const agent = baseAgentName(rawAgent);
1646
- const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
1673
+ const markerPath = path10.join(SESSION_CACHE, `current-task-${agent}.json`);
1647
1674
  if (existsSync9(markerPath)) {
1648
1675
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
1649
1676
  return "debounced";
@@ -1653,7 +1680,7 @@ function sendIntercom(targetSession) {
1653
1680
  try {
1654
1681
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
1655
1682
  const agent = baseAgentName(rawAgent);
1656
- const taskDir = path9.join(process.cwd(), "exe", agent);
1683
+ const taskDir = path10.join(process.cwd(), "exe", agent);
1657
1684
  if (existsSync9(taskDir)) {
1658
1685
  const files = readdirSync2(taskDir).filter(
1659
1686
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -1787,8 +1814,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1787
1814
  const transport = getTransport();
1788
1815
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
1789
1816
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
1790
- const logDir = path9.join(os6.homedir(), ".exe-os", "session-logs");
1791
- 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`);
1792
1819
  if (!existsSync9(logDir)) {
1793
1820
  mkdirSync5(logDir, { recursive: true });
1794
1821
  }
@@ -1796,14 +1823,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1796
1823
  let cleanupSuffix = "";
1797
1824
  try {
1798
1825
  const thisFile = fileURLToPath(import.meta.url);
1799
- 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");
1800
1827
  if (existsSync9(cleanupScript)) {
1801
1828
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
1802
1829
  }
1803
1830
  } catch {
1804
1831
  }
1805
1832
  try {
1806
- const claudeJsonPath = path9.join(os6.homedir(), ".claude.json");
1833
+ const claudeJsonPath = path10.join(os7.homedir(), ".claude.json");
1807
1834
  let claudeJson = {};
1808
1835
  try {
1809
1836
  claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
@@ -1818,10 +1845,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1818
1845
  } catch {
1819
1846
  }
1820
1847
  try {
1821
- const settingsDir = path9.join(os6.homedir(), ".claude", "projects");
1848
+ const settingsDir = path10.join(os7.homedir(), ".claude", "projects");
1822
1849
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
1823
- const projSettingsDir = path9.join(settingsDir, normalizedKey);
1824
- const settingsPath = path9.join(projSettingsDir, "settings.json");
1850
+ const projSettingsDir = path10.join(settingsDir, normalizedKey);
1851
+ const settingsPath = path10.join(projSettingsDir, "settings.json");
1825
1852
  let settings = {};
1826
1853
  try {
1827
1854
  settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
@@ -1868,8 +1895,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1868
1895
  let behaviorsFlag = "";
1869
1896
  let legacyFallbackWarned = false;
1870
1897
  if (!useExeAgent && !useBinSymlink) {
1871
- const identityPath = path9.join(
1872
- os6.homedir(),
1898
+ const identityPath = path10.join(
1899
+ os7.homedir(),
1873
1900
  ".exe-os",
1874
1901
  "identity",
1875
1902
  `${employeeName}.md`
@@ -1884,7 +1911,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1884
1911
  }
1885
1912
  const behaviorsFile = exportBehaviorsSync(
1886
1913
  employeeName,
1887
- path9.basename(spawnCwd),
1914
+ path10.basename(spawnCwd),
1888
1915
  sessionName
1889
1916
  );
1890
1917
  if (behaviorsFile) {
@@ -1899,9 +1926,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1899
1926
  }
1900
1927
  let sessionContextFlag = "";
1901
1928
  try {
1902
- const ctxDir = path9.join(os6.homedir(), ".exe-os", "session-cache");
1929
+ const ctxDir = path10.join(os7.homedir(), ".exe-os", "session-cache");
1903
1930
  mkdirSync5(ctxDir, { recursive: true });
1904
- const ctxFile = path9.join(ctxDir, `session-context-${sessionName}.md`);
1931
+ const ctxFile = path10.join(ctxDir, `session-context-${sessionName}.md`);
1905
1932
  const ctxContent = [
1906
1933
  `## Session Context`,
1907
1934
  `You are running in tmux session: ${sessionName}.`,
@@ -1985,7 +2012,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1985
2012
  transport.pipeLog(sessionName, logFile);
1986
2013
  try {
1987
2014
  const mySession = getMySession();
1988
- const dispatchInfo = path9.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
2015
+ const dispatchInfo = path10.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
1989
2016
  writeFileSync6(dispatchInfo, JSON.stringify({
1990
2017
  dispatchedBy: mySession,
1991
2018
  rootExe: exeSession,
@@ -2060,15 +2087,15 @@ var init_tmux_routing = __esm({
2060
2087
  init_intercom_queue();
2061
2088
  init_plan_limits();
2062
2089
  init_employees();
2063
- SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
2064
- 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");
2065
2092
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
2066
2093
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
2067
2094
  VERIFY_PANE_LINES = 200;
2068
2095
  INTERCOM_DEBOUNCE_MS = 3e4;
2069
2096
  CODEX_DEBOUNCE_MS = 12e4;
2070
- INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
2071
- 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");
2072
2099
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
2073
2100
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
2074
2101
  }
@@ -2100,8 +2127,8 @@ var init_task_scope = __esm({
2100
2127
 
2101
2128
  // src/lib/tasks-crud.ts
2102
2129
  import crypto3 from "crypto";
2103
- import path10 from "path";
2104
- import os7 from "os";
2130
+ import path11 from "path";
2131
+ import os8 from "os";
2105
2132
  import { execSync as execSync5 } from "child_process";
2106
2133
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2107
2134
  import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
@@ -2279,8 +2306,8 @@ ${laneWarning}` : laneWarning;
2279
2306
  }
2280
2307
  if (input.baseDir) {
2281
2308
  try {
2282
- await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
2283
- 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 });
2284
2311
  await ensureArchitectureDoc(input.baseDir, input.projectName);
2285
2312
  await ensureGitignoreExe(input.baseDir);
2286
2313
  } catch {
@@ -2316,9 +2343,9 @@ ${laneWarning}` : laneWarning;
2316
2343
  });
2317
2344
  if (input.baseDir) {
2318
2345
  try {
2319
- const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
2320
- const mdPath = path10.join(EXE_OS_DIR, taskFile);
2321
- 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);
2322
2349
  if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
2323
2350
  const reviewer = input.reviewer ?? input.assignedBy;
2324
2351
  const mdContent = `# ${input.title}
@@ -2619,7 +2646,7 @@ async function deleteTaskCore(taskId, _baseDir) {
2619
2646
  return { taskFile, assignedTo, assignedBy, taskSlug };
2620
2647
  }
2621
2648
  async function ensureArchitectureDoc(baseDir, projectName) {
2622
- const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
2649
+ const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
2623
2650
  try {
2624
2651
  if (existsSync10(archPath)) return;
2625
2652
  const template = [
@@ -2654,7 +2681,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
2654
2681
  }
2655
2682
  }
2656
2683
  async function ensureGitignoreExe(baseDir) {
2657
- const gitignorePath = path10.join(baseDir, ".gitignore");
2684
+ const gitignorePath = path11.join(baseDir, ".gitignore");
2658
2685
  try {
2659
2686
  if (existsSync10(gitignorePath)) {
2660
2687
  const content = readFileSync10(gitignorePath, "utf-8");
@@ -2688,13 +2715,13 @@ var init_tasks_crud = __esm({
2688
2715
  });
2689
2716
 
2690
2717
  // src/lib/tasks-review.ts
2691
- import path11 from "path";
2718
+ import path12 from "path";
2692
2719
  import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
2693
2720
  async function countPendingReviews(sessionScope) {
2694
2721
  const client = getClient();
2695
2722
  if (sessionScope) {
2696
2723
  const result2 = await client.execute({
2697
- 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 = ?",
2698
2725
  args: [sessionScope]
2699
2726
  });
2700
2727
  return Number(result2.rows[0]?.cnt) || 0;
@@ -2870,11 +2897,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
2870
2897
  );
2871
2898
  }
2872
2899
  try {
2873
- const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
2900
+ const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
2874
2901
  if (existsSync11(cacheDir)) {
2875
2902
  for (const f of readdirSync3(cacheDir)) {
2876
2903
  if (f.startsWith("review-notified-")) {
2877
- unlinkSync4(path11.join(cacheDir, f));
2904
+ unlinkSync4(path12.join(cacheDir, f));
2878
2905
  }
2879
2906
  }
2880
2907
  }
@@ -2895,7 +2922,7 @@ var init_tasks_review = __esm({
2895
2922
  });
2896
2923
 
2897
2924
  // src/lib/tasks-chain.ts
2898
- import path12 from "path";
2925
+ import path13 from "path";
2899
2926
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
2900
2927
  async function cascadeUnblock(taskId, baseDir, now) {
2901
2928
  const client = getClient();
@@ -2912,7 +2939,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
2912
2939
  });
2913
2940
  for (const ur of unblockedRows.rows) {
2914
2941
  try {
2915
- const ubFile = path12.join(baseDir, String(ur.task_file));
2942
+ const ubFile = path13.join(baseDir, String(ur.task_file));
2916
2943
  let ubContent = await readFile3(ubFile, "utf-8");
2917
2944
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
2918
2945
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -2981,7 +3008,7 @@ var init_tasks_chain = __esm({
2981
3008
 
2982
3009
  // src/lib/project-name.ts
2983
3010
  import { execSync as execSync6 } from "child_process";
2984
- import path13 from "path";
3011
+ import path14 from "path";
2985
3012
  function getProjectName(cwd) {
2986
3013
  const dir = cwd ?? process.cwd();
2987
3014
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -2994,7 +3021,7 @@ function getProjectName(cwd) {
2994
3021
  timeout: 2e3,
2995
3022
  stdio: ["pipe", "pipe", "pipe"]
2996
3023
  }).trim();
2997
- repoRoot = path13.dirname(gitCommonDir);
3024
+ repoRoot = path14.dirname(gitCommonDir);
2998
3025
  } catch {
2999
3026
  repoRoot = execSync6("git rev-parse --show-toplevel", {
3000
3027
  cwd: dir,
@@ -3003,11 +3030,11 @@ function getProjectName(cwd) {
3003
3030
  stdio: ["pipe", "pipe", "pipe"]
3004
3031
  }).trim();
3005
3032
  }
3006
- _cached2 = path13.basename(repoRoot);
3033
+ _cached2 = path14.basename(repoRoot);
3007
3034
  _cachedCwd = dir;
3008
3035
  return _cached2;
3009
3036
  } catch {
3010
- _cached2 = path13.basename(dir);
3037
+ _cached2 = path14.basename(dir);
3011
3038
  _cachedCwd = dir;
3012
3039
  return _cached2;
3013
3040
  }
@@ -3480,7 +3507,7 @@ __export(tasks_exports, {
3480
3507
  updateTaskStatus: () => updateTaskStatus,
3481
3508
  writeCheckpoint: () => writeCheckpoint
3482
3509
  });
3483
- import path14 from "path";
3510
+ import path15 from "path";
3484
3511
  import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
3485
3512
  async function createTask(input) {
3486
3513
  const result = await createTaskCore(input);
@@ -3500,8 +3527,8 @@ async function updateTask(input) {
3500
3527
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
3501
3528
  try {
3502
3529
  const agent = String(row.assigned_to);
3503
- const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
3504
- 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`);
3505
3532
  if (input.status === "in_progress") {
3506
3533
  mkdirSync6(cacheDir, { recursive: true });
3507
3534
  writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));