@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
@@ -731,7 +731,7 @@ function isMultiInstance(agentName, employees) {
731
731
  if (!emp) return false;
732
732
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
733
733
  }
734
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
734
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
735
735
  var init_employees = __esm({
736
736
  "src/lib/employees.ts"() {
737
737
  "use strict";
@@ -740,15 +740,40 @@ var init_employees = __esm({
740
740
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
741
741
  COORDINATOR_ROLE = "COO";
742
742
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
743
+ IDENTITY_DIR = path5.join(EXE_AI_DIR, "identity");
744
+ }
745
+ });
746
+
747
+ // src/lib/database-adapter.ts
748
+ import os5 from "os";
749
+ import path6 from "path";
750
+ import { createRequire } from "module";
751
+ import { pathToFileURL } from "url";
752
+ var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
753
+ var init_database_adapter = __esm({
754
+ "src/lib/database-adapter.ts"() {
755
+ "use strict";
756
+ BOOLEAN_COLUMNS_BY_TABLE = {
757
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
758
+ behaviors: /* @__PURE__ */ new Set(["active"]),
759
+ notifications: /* @__PURE__ */ new Set(["read"]),
760
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
761
+ };
762
+ BOOLEAN_COLUMN_NAMES = new Set(
763
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
764
+ );
743
765
  }
744
766
  });
745
767
 
746
768
  // src/lib/database.ts
747
769
  import { createClient } from "@libsql/client";
748
770
  function getClient() {
749
- if (!_resilientClient) {
771
+ if (!_adapterClient) {
750
772
  throw new Error("Database client not initialized. Call initDatabase() first.");
751
773
  }
774
+ if (process.env.DATABASE_URL) {
775
+ return _adapterClient;
776
+ }
752
777
  if (process.env.EXE_IS_DAEMON === "1") {
753
778
  return _resilientClient;
754
779
  }
@@ -757,30 +782,32 @@ function getClient() {
757
782
  }
758
783
  return _resilientClient;
759
784
  }
760
- var _resilientClient, _daemonClient;
785
+ var _resilientClient, _daemonClient, _adapterClient;
761
786
  var init_database = __esm({
762
787
  "src/lib/database.ts"() {
763
788
  "use strict";
764
789
  init_db_retry();
765
790
  init_employees();
791
+ init_database_adapter();
766
792
  _resilientClient = null;
767
793
  _daemonClient = null;
794
+ _adapterClient = null;
768
795
  }
769
796
  });
770
797
 
771
798
  // src/lib/license.ts
772
799
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
773
800
  import { randomUUID } from "crypto";
774
- import path6 from "path";
801
+ import path7 from "path";
775
802
  import { jwtVerify, importSPKI } from "jose";
776
803
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
777
804
  var init_license = __esm({
778
805
  "src/lib/license.ts"() {
779
806
  "use strict";
780
807
  init_config();
781
- LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
782
- CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
783
- DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
808
+ LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
809
+ CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
810
+ DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
784
811
  PLAN_LIMITS = {
785
812
  free: { devices: 1, employees: 1, memories: 5e3 },
786
813
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -793,7 +820,7 @@ var init_license = __esm({
793
820
 
794
821
  // src/lib/plan-limits.ts
795
822
  import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
796
- import path7 from "path";
823
+ import path8 from "path";
797
824
  function getLicenseSync() {
798
825
  try {
799
826
  if (!existsSync7(CACHE_PATH2)) return freeLicense();
@@ -865,14 +892,14 @@ var init_plan_limits = __esm({
865
892
  this.name = "PlanLimitError";
866
893
  }
867
894
  };
868
- CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
895
+ CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
869
896
  }
870
897
  });
871
898
 
872
899
  // src/lib/notifications.ts
873
900
  import crypto from "crypto";
874
- import path8 from "path";
875
- import os5 from "os";
901
+ import path9 from "path";
902
+ import os6 from "os";
876
903
  import {
877
904
  readFileSync as readFileSync8,
878
905
  readdirSync,
@@ -1036,8 +1063,8 @@ var init_state_bus = __esm({
1036
1063
 
1037
1064
  // src/lib/tasks-crud.ts
1038
1065
  import crypto3 from "crypto";
1039
- import path9 from "path";
1040
- import os6 from "os";
1066
+ import path10 from "path";
1067
+ import os7 from "os";
1041
1068
  import { execSync as execSync4 } from "child_process";
1042
1069
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
1043
1070
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
@@ -1215,8 +1242,8 @@ ${laneWarning}` : laneWarning;
1215
1242
  }
1216
1243
  if (input.baseDir) {
1217
1244
  try {
1218
- await mkdir3(path9.join(input.baseDir, "exe", "output"), { recursive: true });
1219
- await mkdir3(path9.join(input.baseDir, "exe", "research"), { recursive: true });
1245
+ await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
1246
+ await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
1220
1247
  await ensureArchitectureDoc(input.baseDir, input.projectName);
1221
1248
  await ensureGitignoreExe(input.baseDir);
1222
1249
  } catch {
@@ -1252,9 +1279,9 @@ ${laneWarning}` : laneWarning;
1252
1279
  });
1253
1280
  if (input.baseDir) {
1254
1281
  try {
1255
- const EXE_OS_DIR = path9.join(os6.homedir(), ".exe-os");
1256
- const mdPath = path9.join(EXE_OS_DIR, taskFile);
1257
- const mdDir = path9.dirname(mdPath);
1282
+ const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
1283
+ const mdPath = path10.join(EXE_OS_DIR, taskFile);
1284
+ const mdDir = path10.dirname(mdPath);
1258
1285
  if (!existsSync9(mdDir)) await mkdir3(mdDir, { recursive: true });
1259
1286
  const reviewer = input.reviewer ?? input.assignedBy;
1260
1287
  const mdContent = `# ${input.title}
@@ -1555,7 +1582,7 @@ async function deleteTaskCore(taskId, _baseDir) {
1555
1582
  return { taskFile, assignedTo, assignedBy, taskSlug };
1556
1583
  }
1557
1584
  async function ensureArchitectureDoc(baseDir, projectName) {
1558
- const archPath = path9.join(baseDir, "exe", "ARCHITECTURE.md");
1585
+ const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
1559
1586
  try {
1560
1587
  if (existsSync9(archPath)) return;
1561
1588
  const template = [
@@ -1590,7 +1617,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
1590
1617
  }
1591
1618
  }
1592
1619
  async function ensureGitignoreExe(baseDir) {
1593
- const gitignorePath = path9.join(baseDir, ".gitignore");
1620
+ const gitignorePath = path10.join(baseDir, ".gitignore");
1594
1621
  try {
1595
1622
  if (existsSync9(gitignorePath)) {
1596
1623
  const content = readFileSync9(gitignorePath, "utf-8");
@@ -1624,13 +1651,13 @@ var init_tasks_crud = __esm({
1624
1651
  });
1625
1652
 
1626
1653
  // src/lib/tasks-review.ts
1627
- import path10 from "path";
1654
+ import path11 from "path";
1628
1655
  import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
1629
1656
  async function countPendingReviews(sessionScope) {
1630
1657
  const client = getClient();
1631
1658
  if (sessionScope) {
1632
1659
  const result2 = await client.execute({
1633
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
1660
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
1634
1661
  args: [sessionScope]
1635
1662
  });
1636
1663
  return Number(result2.rows[0]?.cnt) || 0;
@@ -1806,11 +1833,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
1806
1833
  );
1807
1834
  }
1808
1835
  try {
1809
- const cacheDir = path10.join(EXE_AI_DIR, "session-cache");
1836
+ const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
1810
1837
  if (existsSync10(cacheDir)) {
1811
1838
  for (const f of readdirSync2(cacheDir)) {
1812
1839
  if (f.startsWith("review-notified-")) {
1813
- unlinkSync3(path10.join(cacheDir, f));
1840
+ unlinkSync3(path11.join(cacheDir, f));
1814
1841
  }
1815
1842
  }
1816
1843
  }
@@ -1831,7 +1858,7 @@ var init_tasks_review = __esm({
1831
1858
  });
1832
1859
 
1833
1860
  // src/lib/tasks-chain.ts
1834
- import path11 from "path";
1861
+ import path12 from "path";
1835
1862
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
1836
1863
  async function cascadeUnblock(taskId, baseDir, now) {
1837
1864
  const client = getClient();
@@ -1848,7 +1875,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
1848
1875
  });
1849
1876
  for (const ur of unblockedRows.rows) {
1850
1877
  try {
1851
- const ubFile = path11.join(baseDir, String(ur.task_file));
1878
+ const ubFile = path12.join(baseDir, String(ur.task_file));
1852
1879
  let ubContent = await readFile3(ubFile, "utf-8");
1853
1880
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
1854
1881
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -1917,7 +1944,7 @@ var init_tasks_chain = __esm({
1917
1944
 
1918
1945
  // src/lib/project-name.ts
1919
1946
  import { execSync as execSync5 } from "child_process";
1920
- import path12 from "path";
1947
+ import path13 from "path";
1921
1948
  function getProjectName(cwd) {
1922
1949
  const dir = cwd ?? process.cwd();
1923
1950
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -1930,7 +1957,7 @@ function getProjectName(cwd) {
1930
1957
  timeout: 2e3,
1931
1958
  stdio: ["pipe", "pipe", "pipe"]
1932
1959
  }).trim();
1933
- repoRoot = path12.dirname(gitCommonDir);
1960
+ repoRoot = path13.dirname(gitCommonDir);
1934
1961
  } catch {
1935
1962
  repoRoot = execSync5("git rev-parse --show-toplevel", {
1936
1963
  cwd: dir,
@@ -1939,11 +1966,11 @@ function getProjectName(cwd) {
1939
1966
  stdio: ["pipe", "pipe", "pipe"]
1940
1967
  }).trim();
1941
1968
  }
1942
- _cached2 = path12.basename(repoRoot);
1969
+ _cached2 = path13.basename(repoRoot);
1943
1970
  _cachedCwd = dir;
1944
1971
  return _cached2;
1945
1972
  } catch {
1946
- _cached2 = path12.basename(dir);
1973
+ _cached2 = path13.basename(dir);
1947
1974
  _cachedCwd = dir;
1948
1975
  return _cached2;
1949
1976
  }
@@ -2416,7 +2443,7 @@ __export(tasks_exports, {
2416
2443
  updateTaskStatus: () => updateTaskStatus,
2417
2444
  writeCheckpoint: () => writeCheckpoint
2418
2445
  });
2419
- import path13 from "path";
2446
+ import path14 from "path";
2420
2447
  import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
2421
2448
  async function createTask(input) {
2422
2449
  const result = await createTaskCore(input);
@@ -2436,8 +2463,8 @@ async function updateTask(input) {
2436
2463
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
2437
2464
  try {
2438
2465
  const agent = String(row.assigned_to);
2439
- const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
2440
- const cachePath = path13.join(cacheDir, `current-task-${agent}.json`);
2466
+ const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
2467
+ const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
2441
2468
  if (input.status === "in_progress") {
2442
2469
  mkdirSync5(cacheDir, { recursive: true });
2443
2470
  writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -2908,12 +2935,12 @@ __export(tmux_routing_exports, {
2908
2935
  });
2909
2936
  import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
2910
2937
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync11, appendFileSync, readdirSync as readdirSync3 } from "fs";
2911
- import path14 from "path";
2912
- import os7 from "os";
2938
+ import path15 from "path";
2939
+ import os8 from "os";
2913
2940
  import { fileURLToPath } from "url";
2914
2941
  import { unlinkSync as unlinkSync5 } from "fs";
2915
2942
  function spawnLockPath(sessionName) {
2916
- return path14.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
2943
+ return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
2917
2944
  }
2918
2945
  function isProcessAlive(pid) {
2919
2946
  try {
@@ -2950,8 +2977,8 @@ function releaseSpawnLock(sessionName) {
2950
2977
  function resolveBehaviorsExporterScript() {
2951
2978
  try {
2952
2979
  const thisFile = fileURLToPath(import.meta.url);
2953
- const scriptPath = path14.join(
2954
- path14.dirname(thisFile),
2980
+ const scriptPath = path15.join(
2981
+ path15.dirname(thisFile),
2955
2982
  "..",
2956
2983
  "bin",
2957
2984
  "exe-export-behaviors.js"
@@ -3026,7 +3053,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
3026
3053
  mkdirSync6(SESSION_CACHE, { recursive: true });
3027
3054
  }
3028
3055
  const rootExe = extractRootExe(parentExe) ?? parentExe;
3029
- const filePath = path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
3056
+ const filePath = path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
3030
3057
  writeFileSync7(filePath, JSON.stringify({
3031
3058
  parentExe: rootExe,
3032
3059
  dispatchedBy: dispatchedBy || rootExe,
@@ -3035,7 +3062,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
3035
3062
  }
3036
3063
  function getParentExe(sessionKey) {
3037
3064
  try {
3038
- const data = JSON.parse(readFileSync10(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3065
+ const data = JSON.parse(readFileSync10(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3039
3066
  return data.parentExe || null;
3040
3067
  } catch {
3041
3068
  return null;
@@ -3044,7 +3071,7 @@ function getParentExe(sessionKey) {
3044
3071
  function getDispatchedBy(sessionKey) {
3045
3072
  try {
3046
3073
  const data = JSON.parse(readFileSync10(
3047
- path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
3074
+ path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
3048
3075
  "utf8"
3049
3076
  ));
3050
3077
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -3230,7 +3257,7 @@ function sendIntercom(targetSession) {
3230
3257
  try {
3231
3258
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
3232
3259
  const agent = baseAgentName(rawAgent);
3233
- const markerPath = path14.join(SESSION_CACHE, `current-task-${agent}.json`);
3260
+ const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
3234
3261
  if (existsSync11(markerPath)) {
3235
3262
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
3236
3263
  return "debounced";
@@ -3240,7 +3267,7 @@ function sendIntercom(targetSession) {
3240
3267
  try {
3241
3268
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
3242
3269
  const agent = baseAgentName(rawAgent);
3243
- const taskDir = path14.join(process.cwd(), "exe", agent);
3270
+ const taskDir = path15.join(process.cwd(), "exe", agent);
3244
3271
  if (existsSync11(taskDir)) {
3245
3272
  const files = readdirSync3(taskDir).filter(
3246
3273
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -3374,8 +3401,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3374
3401
  const transport = getTransport();
3375
3402
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
3376
3403
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
3377
- const logDir = path14.join(os7.homedir(), ".exe-os", "session-logs");
3378
- const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
3404
+ const logDir = path15.join(os8.homedir(), ".exe-os", "session-logs");
3405
+ const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
3379
3406
  if (!existsSync11(logDir)) {
3380
3407
  mkdirSync6(logDir, { recursive: true });
3381
3408
  }
@@ -3383,14 +3410,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3383
3410
  let cleanupSuffix = "";
3384
3411
  try {
3385
3412
  const thisFile = fileURLToPath(import.meta.url);
3386
- const cleanupScript = path14.join(path14.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
3413
+ const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
3387
3414
  if (existsSync11(cleanupScript)) {
3388
3415
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
3389
3416
  }
3390
3417
  } catch {
3391
3418
  }
3392
3419
  try {
3393
- const claudeJsonPath = path14.join(os7.homedir(), ".claude.json");
3420
+ const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
3394
3421
  let claudeJson = {};
3395
3422
  try {
3396
3423
  claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
@@ -3405,10 +3432,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3405
3432
  } catch {
3406
3433
  }
3407
3434
  try {
3408
- const settingsDir = path14.join(os7.homedir(), ".claude", "projects");
3435
+ const settingsDir = path15.join(os8.homedir(), ".claude", "projects");
3409
3436
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
3410
- const projSettingsDir = path14.join(settingsDir, normalizedKey);
3411
- const settingsPath = path14.join(projSettingsDir, "settings.json");
3437
+ const projSettingsDir = path15.join(settingsDir, normalizedKey);
3438
+ const settingsPath = path15.join(projSettingsDir, "settings.json");
3412
3439
  let settings = {};
3413
3440
  try {
3414
3441
  settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
@@ -3455,8 +3482,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3455
3482
  let behaviorsFlag = "";
3456
3483
  let legacyFallbackWarned = false;
3457
3484
  if (!useExeAgent && !useBinSymlink) {
3458
- const identityPath = path14.join(
3459
- os7.homedir(),
3485
+ const identityPath = path15.join(
3486
+ os8.homedir(),
3460
3487
  ".exe-os",
3461
3488
  "identity",
3462
3489
  `${employeeName}.md`
@@ -3471,7 +3498,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3471
3498
  }
3472
3499
  const behaviorsFile = exportBehaviorsSync(
3473
3500
  employeeName,
3474
- path14.basename(spawnCwd),
3501
+ path15.basename(spawnCwd),
3475
3502
  sessionName
3476
3503
  );
3477
3504
  if (behaviorsFile) {
@@ -3486,9 +3513,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3486
3513
  }
3487
3514
  let sessionContextFlag = "";
3488
3515
  try {
3489
- const ctxDir = path14.join(os7.homedir(), ".exe-os", "session-cache");
3516
+ const ctxDir = path15.join(os8.homedir(), ".exe-os", "session-cache");
3490
3517
  mkdirSync6(ctxDir, { recursive: true });
3491
- const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
3518
+ const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
3492
3519
  const ctxContent = [
3493
3520
  `## Session Context`,
3494
3521
  `You are running in tmux session: ${sessionName}.`,
@@ -3572,7 +3599,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3572
3599
  transport.pipeLog(sessionName, logFile);
3573
3600
  try {
3574
3601
  const mySession = getMySession();
3575
- const dispatchInfo = path14.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
3602
+ const dispatchInfo = path15.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
3576
3603
  writeFileSync7(dispatchInfo, JSON.stringify({
3577
3604
  dispatchedBy: mySession,
3578
3605
  rootExe: exeSession,
@@ -3646,15 +3673,15 @@ var init_tmux_routing = __esm({
3646
3673
  init_intercom_queue();
3647
3674
  init_plan_limits();
3648
3675
  init_employees();
3649
- SPAWN_LOCK_DIR = path14.join(os7.homedir(), ".exe-os", "spawn-locks");
3650
- SESSION_CACHE = path14.join(os7.homedir(), ".exe-os", "session-cache");
3676
+ SPAWN_LOCK_DIR = path15.join(os8.homedir(), ".exe-os", "spawn-locks");
3677
+ SESSION_CACHE = path15.join(os8.homedir(), ".exe-os", "session-cache");
3651
3678
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
3652
3679
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
3653
3680
  VERIFY_PANE_LINES = 200;
3654
3681
  INTERCOM_DEBOUNCE_MS = 3e4;
3655
3682
  CODEX_DEBOUNCE_MS = 12e4;
3656
- INTERCOM_LOG2 = path14.join(os7.homedir(), ".exe-os", "intercom.log");
3657
- DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
3683
+ INTERCOM_LOG2 = path15.join(os8.homedir(), ".exe-os", "intercom.log");
3684
+ DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
3658
3685
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
3659
3686
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
3660
3687
  }
@@ -98,8 +98,8 @@ var init_config = __esm({
98
98
  import { readdir } from "fs/promises";
99
99
  import { createReadStream } from "fs";
100
100
  import { createInterface } from "readline";
101
- import path3 from "path";
102
- import os3 from "os";
101
+ import path4 from "path";
102
+ import os4 from "os";
103
103
 
104
104
  // src/lib/database.ts
105
105
  import { createClient } from "@libsql/client";
@@ -112,14 +112,34 @@ import { execSync } from "child_process";
112
112
  import path2 from "path";
113
113
  import os2 from "os";
114
114
  var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
115
+ var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
116
+
117
+ // src/lib/database-adapter.ts
118
+ import os3 from "os";
119
+ import path3 from "path";
120
+ import { createRequire } from "module";
121
+ import { pathToFileURL } from "url";
122
+ var BOOLEAN_COLUMNS_BY_TABLE = {
123
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
124
+ behaviors: /* @__PURE__ */ new Set(["active"]),
125
+ notifications: /* @__PURE__ */ new Set(["read"]),
126
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
127
+ };
128
+ var BOOLEAN_COLUMN_NAMES = new Set(
129
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
130
+ );
115
131
 
116
132
  // src/lib/database.ts
117
133
  var _resilientClient = null;
118
134
  var _daemonClient = null;
135
+ var _adapterClient = null;
119
136
  function getClient() {
120
- if (!_resilientClient) {
137
+ if (!_adapterClient) {
121
138
  throw new Error("Database client not initialized. Call initDatabase() first.");
122
139
  }
140
+ if (process.env.DATABASE_URL) {
141
+ return _adapterClient;
142
+ }
123
143
  if (process.env.EXE_IS_DAEMON === "1") {
124
144
  return _resilientClient;
125
145
  }
@@ -177,18 +197,18 @@ async function getAgentSpend(period = "7d") {
177
197
  for (const row of result.rows) {
178
198
  sessionAgent.set(row.session_uuid, row.agent_id);
179
199
  }
180
- const claudeDir = path3.join(os3.homedir(), ".claude", "projects");
200
+ const claudeDir = path4.join(os4.homedir(), ".claude", "projects");
181
201
  let projectDirs = [];
182
202
  try {
183
203
  const entries = await readdir(claudeDir);
184
- projectDirs = entries.map((e) => path3.join(claudeDir, e));
204
+ projectDirs = entries.map((e) => path4.join(claudeDir, e));
185
205
  } catch {
186
206
  return [];
187
207
  }
188
208
  const agentTotals = /* @__PURE__ */ new Map();
189
209
  for (const [sessionUuid, agentId] of sessionAgent) {
190
210
  for (const dir of projectDirs) {
191
- const jsonlPath = path3.join(dir, `${sessionUuid}.jsonl`);
211
+ const jsonlPath = path4.join(dir, `${sessionUuid}.jsonl`);
192
212
  try {
193
213
  const usage = await extractSessionUsage(jsonlPath);
194
214
  if (usage.input === 0 && usage.output === 0) continue;