@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
@@ -631,6 +631,118 @@ var init_config = __esm({
631
631
  }
632
632
  });
633
633
 
634
+ // src/lib/runtime-table.ts
635
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
636
+ var init_runtime_table = __esm({
637
+ "src/lib/runtime-table.ts"() {
638
+ "use strict";
639
+ RUNTIME_TABLE = {
640
+ codex: {
641
+ binary: "codex",
642
+ launchMode: "interactive",
643
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
644
+ inlineFlag: "--no-alt-screen",
645
+ apiKeyEnv: "OPENAI_API_KEY",
646
+ defaultModel: "gpt-5.4"
647
+ },
648
+ opencode: {
649
+ binary: "opencode",
650
+ launchMode: "exec",
651
+ autoApproveFlag: "--dangerously-skip-permissions",
652
+ inlineFlag: "",
653
+ apiKeyEnv: "ANTHROPIC_API_KEY",
654
+ defaultModel: "anthropic/claude-sonnet-4-6"
655
+ }
656
+ };
657
+ DEFAULT_RUNTIME = "claude";
658
+ }
659
+ });
660
+
661
+ // src/lib/agent-config.ts
662
+ var agent_config_exports = {};
663
+ __export(agent_config_exports, {
664
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
665
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
666
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
667
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
668
+ clearAgentRuntime: () => clearAgentRuntime,
669
+ getAgentRuntime: () => getAgentRuntime,
670
+ loadAgentConfig: () => loadAgentConfig,
671
+ saveAgentConfig: () => saveAgentConfig,
672
+ setAgentRuntime: () => setAgentRuntime
673
+ });
674
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
675
+ import path2 from "path";
676
+ function loadAgentConfig() {
677
+ if (!existsSync2(AGENT_CONFIG_PATH)) return {};
678
+ try {
679
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
680
+ } catch {
681
+ return {};
682
+ }
683
+ }
684
+ function saveAgentConfig(config2) {
685
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
686
+ if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
687
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
688
+ }
689
+ function getAgentRuntime(agentId) {
690
+ const config2 = loadAgentConfig();
691
+ const entry = config2[agentId];
692
+ if (entry) return entry;
693
+ const orgDefault = config2["default"];
694
+ if (orgDefault) return orgDefault;
695
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
696
+ }
697
+ function setAgentRuntime(agentId, runtime, model) {
698
+ const knownModels = KNOWN_RUNTIMES[runtime];
699
+ if (!knownModels) {
700
+ return {
701
+ ok: false,
702
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
703
+ };
704
+ }
705
+ if (!knownModels.includes(model)) {
706
+ return {
707
+ ok: false,
708
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
709
+ };
710
+ }
711
+ const config2 = loadAgentConfig();
712
+ config2[agentId] = { runtime, model };
713
+ saveAgentConfig(config2);
714
+ return { ok: true };
715
+ }
716
+ function clearAgentRuntime(agentId) {
717
+ const config2 = loadAgentConfig();
718
+ delete config2[agentId];
719
+ saveAgentConfig(config2);
720
+ }
721
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
722
+ var init_agent_config = __esm({
723
+ "src/lib/agent-config.ts"() {
724
+ "use strict";
725
+ init_config();
726
+ init_runtime_table();
727
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
728
+ KNOWN_RUNTIMES = {
729
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
730
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
731
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
732
+ };
733
+ RUNTIME_LABELS = {
734
+ claude: "Claude Code (Anthropic)",
735
+ codex: "Codex (OpenAI)",
736
+ opencode: "OpenCode (open source)"
737
+ };
738
+ DEFAULT_MODELS = {
739
+ claude: "claude-opus-4",
740
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
741
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
742
+ };
743
+ }
744
+ });
745
+
634
746
  // src/lib/employees.ts
635
747
  var employees_exports = {};
636
748
  __export(employees_exports, {
@@ -646,6 +758,7 @@ __export(employees_exports, {
646
758
  getEmployeeByRole: () => getEmployeeByRole,
647
759
  getEmployeeNamesByRole: () => getEmployeeNamesByRole,
648
760
  hasRole: () => hasRole,
761
+ hireEmployee: () => hireEmployee,
649
762
  isCoordinatorName: () => isCoordinatorName,
650
763
  isCoordinatorRole: () => isCoordinatorRole,
651
764
  isMultiInstance: () => isMultiInstance,
@@ -658,9 +771,9 @@ __export(employees_exports, {
658
771
  validateEmployeeName: () => validateEmployeeName
659
772
  });
660
773
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
661
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
774
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
662
775
  import { execSync } from "child_process";
663
- import path2 from "path";
776
+ import path3 from "path";
664
777
  import os2 from "os";
665
778
  function normalizeRole(role) {
666
779
  return (role ?? "").trim().toLowerCase();
@@ -697,7 +810,7 @@ function validateEmployeeName(name) {
697
810
  return { valid: true };
698
811
  }
699
812
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
700
- if (!existsSync2(employeesPath)) {
813
+ if (!existsSync3(employeesPath)) {
701
814
  return [];
702
815
  }
703
816
  const raw = await readFile2(employeesPath, "utf-8");
@@ -708,13 +821,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
708
821
  }
709
822
  }
710
823
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
711
- await mkdir2(path2.dirname(employeesPath), { recursive: true });
824
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
712
825
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
713
826
  }
714
827
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
715
- if (!existsSync2(employeesPath)) return [];
828
+ if (!existsSync3(employeesPath)) return [];
716
829
  try {
717
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
830
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
718
831
  } catch {
719
832
  return [];
720
833
  }
@@ -756,6 +869,52 @@ function addEmployee(employees, employee) {
756
869
  }
757
870
  return [...employees, normalized];
758
871
  }
872
+ function appendToCoordinatorTeam(employee) {
873
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
874
+ if (!coordinator) return;
875
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
876
+ if (!existsSync3(idPath)) return;
877
+ const content = readFileSync3(idPath, "utf-8");
878
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
879
+ const teamMatch = content.match(TEAM_SECTION_RE);
880
+ if (!teamMatch || teamMatch.index === void 0) return;
881
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
882
+ const nextHeading = afterTeam.match(/\n## /);
883
+ const entry = `
884
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
885
+ `;
886
+ let updated;
887
+ if (nextHeading && nextHeading.index !== void 0) {
888
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
889
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
890
+ } else {
891
+ updated = content.trimEnd() + "\n" + entry;
892
+ }
893
+ writeFileSync2(idPath, updated, "utf-8");
894
+ }
895
+ function capitalize(s) {
896
+ return s.charAt(0).toUpperCase() + s.slice(1);
897
+ }
898
+ async function hireEmployee(employee) {
899
+ const employees = await loadEmployees();
900
+ const updated = addEmployee(employees, employee);
901
+ await saveEmployees(updated);
902
+ try {
903
+ appendToCoordinatorTeam(employee);
904
+ } catch {
905
+ }
906
+ try {
907
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
908
+ const config2 = loadAgentConfig2();
909
+ const name = employee.name.toLowerCase();
910
+ if (!config2[name] && config2["default"]) {
911
+ config2[name] = { ...config2["default"] };
912
+ saveAgentConfig2(config2);
913
+ }
914
+ } catch {
915
+ }
916
+ return updated;
917
+ }
759
918
  async function normalizeRosterCase(rosterPath) {
760
919
  const employees = await loadEmployees(rosterPath);
761
920
  let changed = false;
@@ -765,14 +924,14 @@ async function normalizeRosterCase(rosterPath) {
765
924
  emp.name = emp.name.toLowerCase();
766
925
  changed = true;
767
926
  try {
768
- const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
769
- const oldPath = path2.join(identityDir, `${oldName}.md`);
770
- const newPath = path2.join(identityDir, `${emp.name}.md`);
771
- if (existsSync2(oldPath) && !existsSync2(newPath)) {
927
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
928
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
929
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
930
+ if (existsSync3(oldPath) && !existsSync3(newPath)) {
772
931
  renameSync2(oldPath, newPath);
773
- } else if (existsSync2(oldPath) && oldPath !== newPath) {
774
- const content = readFileSync2(oldPath, "utf-8");
775
- writeFileSync(newPath, content, "utf-8");
932
+ } else if (existsSync3(oldPath) && oldPath !== newPath) {
933
+ const content = readFileSync3(oldPath, "utf-8");
934
+ writeFileSync2(newPath, content, "utf-8");
776
935
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
777
936
  unlinkSync(oldPath);
778
937
  }
@@ -802,7 +961,7 @@ function registerBinSymlinks(name) {
802
961
  errors.push("Could not find 'exe-os' in PATH");
803
962
  return { created, skipped, errors };
804
963
  }
805
- const binDir = path2.dirname(exeBinPath);
964
+ const binDir = path3.dirname(exeBinPath);
806
965
  let target;
807
966
  try {
808
967
  target = readlinkSync(exeBinPath);
@@ -812,8 +971,8 @@ function registerBinSymlinks(name) {
812
971
  }
813
972
  for (const suffix of ["", "-opencode"]) {
814
973
  const linkName = `${name}${suffix}`;
815
- const linkPath = path2.join(binDir, linkName);
816
- if (existsSync2(linkPath)) {
974
+ const linkPath = path3.join(binDir, linkName);
975
+ if (existsSync3(linkPath)) {
817
976
  skipped.push(linkName);
818
977
  continue;
819
978
  }
@@ -826,21 +985,619 @@ function registerBinSymlinks(name) {
826
985
  }
827
986
  return { created, skipped, errors };
828
987
  }
829
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
988
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
830
989
  var init_employees = __esm({
831
990
  "src/lib/employees.ts"() {
832
991
  "use strict";
833
992
  init_config();
834
- EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
993
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
835
994
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
836
995
  COORDINATOR_ROLE = "COO";
837
996
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
997
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
998
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
999
+ }
1000
+ });
1001
+
1002
+ // src/lib/database-adapter.ts
1003
+ import os3 from "os";
1004
+ import path4 from "path";
1005
+ import { createRequire } from "module";
1006
+ import { pathToFileURL } from "url";
1007
+ function quotedIdentifier(identifier) {
1008
+ return `"${identifier.replace(/"/g, '""')}"`;
1009
+ }
1010
+ function unqualifiedTableName(name) {
1011
+ const raw = name.trim().replace(/^"|"$/g, "");
1012
+ const parts = raw.split(".");
1013
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
1014
+ }
1015
+ function stripTrailingSemicolon(sql) {
1016
+ return sql.trim().replace(/;+\s*$/u, "");
1017
+ }
1018
+ function appendClause(sql, clause) {
1019
+ const trimmed = stripTrailingSemicolon(sql);
1020
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
1021
+ if (!returningMatch) {
1022
+ return `${trimmed}${clause}`;
1023
+ }
1024
+ const idx = returningMatch.index;
1025
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
1026
+ }
1027
+ function normalizeStatement(stmt) {
1028
+ if (typeof stmt === "string") {
1029
+ return { kind: "positional", sql: stmt, args: [] };
1030
+ }
1031
+ const sql = stmt.sql;
1032
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
1033
+ return { kind: "positional", sql, args: stmt.args ?? [] };
1034
+ }
1035
+ return { kind: "named", sql, args: stmt.args };
1036
+ }
1037
+ function rewriteBooleanLiterals(sql) {
1038
+ let out = sql;
1039
+ for (const column of BOOLEAN_COLUMN_NAMES) {
1040
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
1041
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
1042
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
1043
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
1044
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
1045
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
1046
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
1047
+ }
1048
+ return out;
1049
+ }
1050
+ function rewriteInsertOrIgnore(sql) {
1051
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
1052
+ return sql;
1053
+ }
1054
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
1055
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
1056
+ }
1057
+ function rewriteInsertOrReplace(sql) {
1058
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
1059
+ if (!match) {
1060
+ return sql;
1061
+ }
1062
+ const rawTable = match[1];
1063
+ const rawColumns = match[2];
1064
+ const remainder = match[3];
1065
+ const tableName = unqualifiedTableName(rawTable);
1066
+ const conflictKeys = UPSERT_KEYS[tableName];
1067
+ if (!conflictKeys?.length) {
1068
+ return sql;
1069
+ }
1070
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
1071
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
1072
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
1073
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
1074
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
1075
+ }
1076
+ function rewriteSql(sql) {
1077
+ let out = sql;
1078
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
1079
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
1080
+ out = rewriteBooleanLiterals(out);
1081
+ out = rewriteInsertOrReplace(out);
1082
+ out = rewriteInsertOrIgnore(out);
1083
+ return stripTrailingSemicolon(out);
1084
+ }
1085
+ function toBoolean(value) {
1086
+ if (value === null || value === void 0) return value;
1087
+ if (typeof value === "boolean") return value;
1088
+ if (typeof value === "number") return value !== 0;
1089
+ if (typeof value === "bigint") return value !== 0n;
1090
+ if (typeof value === "string") {
1091
+ const normalized = value.trim().toLowerCase();
1092
+ if (normalized === "0" || normalized === "false") return false;
1093
+ if (normalized === "1" || normalized === "true") return true;
1094
+ }
1095
+ return Boolean(value);
1096
+ }
1097
+ function countQuestionMarks(sql, end) {
1098
+ let count = 0;
1099
+ let inSingle = false;
1100
+ let inDouble = false;
1101
+ let inLineComment = false;
1102
+ let inBlockComment = false;
1103
+ for (let i = 0; i < end; i++) {
1104
+ const ch = sql[i];
1105
+ const next = sql[i + 1];
1106
+ if (inLineComment) {
1107
+ if (ch === "\n") inLineComment = false;
1108
+ continue;
1109
+ }
1110
+ if (inBlockComment) {
1111
+ if (ch === "*" && next === "/") {
1112
+ inBlockComment = false;
1113
+ i += 1;
1114
+ }
1115
+ continue;
1116
+ }
1117
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1118
+ inLineComment = true;
1119
+ i += 1;
1120
+ continue;
1121
+ }
1122
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1123
+ inBlockComment = true;
1124
+ i += 1;
1125
+ continue;
1126
+ }
1127
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1128
+ inSingle = !inSingle;
1129
+ continue;
1130
+ }
1131
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1132
+ inDouble = !inDouble;
1133
+ continue;
1134
+ }
1135
+ if (!inSingle && !inDouble && ch === "?") {
1136
+ count += 1;
1137
+ }
1138
+ }
1139
+ return count;
1140
+ }
1141
+ function findBooleanPlaceholderIndexes(sql) {
1142
+ const indexes = /* @__PURE__ */ new Set();
1143
+ for (const column of BOOLEAN_COLUMN_NAMES) {
1144
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
1145
+ for (const match of sql.matchAll(pattern)) {
1146
+ const matchText = match[0];
1147
+ const qIndex = match.index + matchText.lastIndexOf("?");
1148
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
1149
+ }
1150
+ }
1151
+ return indexes;
1152
+ }
1153
+ function coerceInsertBooleanArgs(sql, args) {
1154
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
1155
+ if (!match) return;
1156
+ const rawTable = match[1];
1157
+ const rawColumns = match[2];
1158
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
1159
+ if (!boolColumns?.size) return;
1160
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
1161
+ for (const [index, column] of columns.entries()) {
1162
+ if (boolColumns.has(column) && index < args.length) {
1163
+ args[index] = toBoolean(args[index]);
1164
+ }
1165
+ }
1166
+ }
1167
+ function coerceUpdateBooleanArgs(sql, args) {
1168
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
1169
+ if (!match) return;
1170
+ const rawTable = match[1];
1171
+ const setClause = match[2];
1172
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
1173
+ if (!boolColumns?.size) return;
1174
+ const assignments = setClause.split(",");
1175
+ let placeholderIndex = 0;
1176
+ for (const assignment of assignments) {
1177
+ if (!assignment.includes("?")) continue;
1178
+ placeholderIndex += 1;
1179
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
1180
+ if (colMatch && boolColumns.has(colMatch[1])) {
1181
+ args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
1182
+ }
1183
+ }
1184
+ }
1185
+ function coerceBooleanArgs(sql, args) {
1186
+ const nextArgs = [...args];
1187
+ coerceInsertBooleanArgs(sql, nextArgs);
1188
+ coerceUpdateBooleanArgs(sql, nextArgs);
1189
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
1190
+ for (const index of placeholderIndexes) {
1191
+ if (index > 0 && index <= nextArgs.length) {
1192
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
1193
+ }
1194
+ }
1195
+ return nextArgs;
1196
+ }
1197
+ function convertQuestionMarksToDollarParams(sql) {
1198
+ let out = "";
1199
+ let placeholder = 0;
1200
+ let inSingle = false;
1201
+ let inDouble = false;
1202
+ let inLineComment = false;
1203
+ let inBlockComment = false;
1204
+ for (let i = 0; i < sql.length; i++) {
1205
+ const ch = sql[i];
1206
+ const next = sql[i + 1];
1207
+ if (inLineComment) {
1208
+ out += ch;
1209
+ if (ch === "\n") inLineComment = false;
1210
+ continue;
1211
+ }
1212
+ if (inBlockComment) {
1213
+ out += ch;
1214
+ if (ch === "*" && next === "/") {
1215
+ out += next;
1216
+ inBlockComment = false;
1217
+ i += 1;
1218
+ }
1219
+ continue;
1220
+ }
1221
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1222
+ out += ch + next;
1223
+ inLineComment = true;
1224
+ i += 1;
1225
+ continue;
1226
+ }
1227
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1228
+ out += ch + next;
1229
+ inBlockComment = true;
1230
+ i += 1;
1231
+ continue;
1232
+ }
1233
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1234
+ inSingle = !inSingle;
1235
+ out += ch;
1236
+ continue;
1237
+ }
1238
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1239
+ inDouble = !inDouble;
1240
+ out += ch;
1241
+ continue;
1242
+ }
1243
+ if (!inSingle && !inDouble && ch === "?") {
1244
+ placeholder += 1;
1245
+ out += `$${placeholder}`;
1246
+ continue;
1247
+ }
1248
+ out += ch;
1249
+ }
1250
+ return out;
1251
+ }
1252
+ function translateStatementForPostgres(stmt) {
1253
+ const normalized = normalizeStatement(stmt);
1254
+ if (normalized.kind === "named") {
1255
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
1256
+ }
1257
+ const rewrittenSql = rewriteSql(normalized.sql);
1258
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
1259
+ return {
1260
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
1261
+ args: coercedArgs
1262
+ };
1263
+ }
1264
+ function shouldBypassPostgres(stmt) {
1265
+ const normalized = normalizeStatement(stmt);
1266
+ if (normalized.kind === "named") {
1267
+ return true;
1268
+ }
1269
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
1270
+ }
1271
+ function shouldFallbackOnError(error) {
1272
+ const message = error instanceof Error ? error.message : String(error);
1273
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
1274
+ }
1275
+ function isReadQuery(sql) {
1276
+ const trimmed = sql.trimStart();
1277
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
1278
+ }
1279
+ function buildRow(row, columns) {
1280
+ const values = columns.map((column) => row[column]);
1281
+ return Object.assign(values, row);
1282
+ }
1283
+ function buildResultSet(rows, rowsAffected = 0) {
1284
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
1285
+ const resultRows = rows.map((row) => buildRow(row, columns));
1286
+ return {
1287
+ columns,
1288
+ columnTypes: columns.map(() => ""),
1289
+ rows: resultRows,
1290
+ rowsAffected,
1291
+ lastInsertRowid: void 0,
1292
+ toJSON() {
1293
+ return {
1294
+ columns,
1295
+ columnTypes: columns.map(() => ""),
1296
+ rows,
1297
+ rowsAffected,
1298
+ lastInsertRowid: void 0
1299
+ };
1300
+ }
1301
+ };
1302
+ }
1303
+ async function loadPrismaClient() {
1304
+ if (!prismaClientPromise) {
1305
+ prismaClientPromise = (async () => {
1306
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
1307
+ if (explicitPath) {
1308
+ const module2 = await import(pathToFileURL(explicitPath).href);
1309
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
1310
+ if (!PrismaClient2) {
1311
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
1312
+ }
1313
+ return new PrismaClient2();
1314
+ }
1315
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path4.join(os3.homedir(), "exe-db");
1316
+ const requireFromExeDb = createRequire(path4.join(exeDbRoot, "package.json"));
1317
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
1318
+ const module = await import(pathToFileURL(prismaEntry).href);
1319
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
1320
+ if (!PrismaClient) {
1321
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
1322
+ }
1323
+ return new PrismaClient();
1324
+ })();
1325
+ }
1326
+ return prismaClientPromise;
1327
+ }
1328
+ async function ensureCompatibilityViews(prisma) {
1329
+ if (!compatibilityBootstrapPromise) {
1330
+ compatibilityBootstrapPromise = (async () => {
1331
+ for (const mapping of VIEW_MAPPINGS) {
1332
+ const relation = mapping.source.replace(/"/g, "");
1333
+ const rows = await prisma.$queryRawUnsafe(
1334
+ "SELECT to_regclass($1) AS regclass",
1335
+ relation
1336
+ );
1337
+ if (!rows[0]?.regclass) {
1338
+ continue;
1339
+ }
1340
+ await prisma.$executeRawUnsafe(
1341
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
1342
+ );
1343
+ }
1344
+ })();
1345
+ }
1346
+ return compatibilityBootstrapPromise;
1347
+ }
1348
+ async function executeOnPrisma(executor, stmt) {
1349
+ const translated = translateStatementForPostgres(stmt);
1350
+ if (isReadQuery(translated.sql)) {
1351
+ const rows = await executor.$queryRawUnsafe(
1352
+ translated.sql,
1353
+ ...translated.args
1354
+ );
1355
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
1356
+ }
1357
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
1358
+ return buildResultSet([], rowsAffected);
1359
+ }
1360
+ function splitSqlStatements(sql) {
1361
+ const parts = [];
1362
+ let current = "";
1363
+ let inSingle = false;
1364
+ let inDouble = false;
1365
+ let inLineComment = false;
1366
+ let inBlockComment = false;
1367
+ for (let i = 0; i < sql.length; i++) {
1368
+ const ch = sql[i];
1369
+ const next = sql[i + 1];
1370
+ if (inLineComment) {
1371
+ current += ch;
1372
+ if (ch === "\n") inLineComment = false;
1373
+ continue;
1374
+ }
1375
+ if (inBlockComment) {
1376
+ current += ch;
1377
+ if (ch === "*" && next === "/") {
1378
+ current += next;
1379
+ inBlockComment = false;
1380
+ i += 1;
1381
+ }
1382
+ continue;
1383
+ }
1384
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1385
+ current += ch + next;
1386
+ inLineComment = true;
1387
+ i += 1;
1388
+ continue;
1389
+ }
1390
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1391
+ current += ch + next;
1392
+ inBlockComment = true;
1393
+ i += 1;
1394
+ continue;
1395
+ }
1396
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1397
+ inSingle = !inSingle;
1398
+ current += ch;
1399
+ continue;
1400
+ }
1401
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1402
+ inDouble = !inDouble;
1403
+ current += ch;
1404
+ continue;
1405
+ }
1406
+ if (!inSingle && !inDouble && ch === ";") {
1407
+ if (current.trim()) {
1408
+ parts.push(current.trim());
1409
+ }
1410
+ current = "";
1411
+ continue;
1412
+ }
1413
+ current += ch;
1414
+ }
1415
+ if (current.trim()) {
1416
+ parts.push(current.trim());
1417
+ }
1418
+ return parts;
1419
+ }
1420
+ async function createPrismaDbAdapter(fallbackClient) {
1421
+ const prisma = await loadPrismaClient();
1422
+ await ensureCompatibilityViews(prisma);
1423
+ let closed = false;
1424
+ let adapter;
1425
+ const fallbackExecute = async (stmt, error) => {
1426
+ if (!fallbackClient) {
1427
+ if (error) throw error;
1428
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
1429
+ }
1430
+ if (error) {
1431
+ process.stderr.write(
1432
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
1433
+ `
1434
+ );
1435
+ }
1436
+ return fallbackClient.execute(stmt);
1437
+ };
1438
+ adapter = {
1439
+ async execute(stmt) {
1440
+ if (shouldBypassPostgres(stmt)) {
1441
+ return fallbackExecute(stmt);
1442
+ }
1443
+ try {
1444
+ return await executeOnPrisma(prisma, stmt);
1445
+ } catch (error) {
1446
+ if (shouldFallbackOnError(error)) {
1447
+ return fallbackExecute(stmt, error);
1448
+ }
1449
+ throw error;
1450
+ }
1451
+ },
1452
+ async batch(stmts, mode) {
1453
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
1454
+ if (!fallbackClient) {
1455
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
1456
+ }
1457
+ return fallbackClient.batch(stmts, mode);
1458
+ }
1459
+ try {
1460
+ if (prisma.$transaction) {
1461
+ return await prisma.$transaction(async (tx) => {
1462
+ const results2 = [];
1463
+ for (const stmt of stmts) {
1464
+ results2.push(await executeOnPrisma(tx, stmt));
1465
+ }
1466
+ return results2;
1467
+ });
1468
+ }
1469
+ const results = [];
1470
+ for (const stmt of stmts) {
1471
+ results.push(await executeOnPrisma(prisma, stmt));
1472
+ }
1473
+ return results;
1474
+ } catch (error) {
1475
+ if (fallbackClient && shouldFallbackOnError(error)) {
1476
+ process.stderr.write(
1477
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
1478
+ `
1479
+ );
1480
+ return fallbackClient.batch(stmts, mode);
1481
+ }
1482
+ throw error;
1483
+ }
1484
+ },
1485
+ async migrate(stmts) {
1486
+ if (fallbackClient) {
1487
+ return fallbackClient.migrate(stmts);
1488
+ }
1489
+ return adapter.batch(stmts, "deferred");
1490
+ },
1491
+ async transaction(mode) {
1492
+ if (!fallbackClient) {
1493
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
1494
+ }
1495
+ return fallbackClient.transaction(mode);
1496
+ },
1497
+ async executeMultiple(sql) {
1498
+ if (fallbackClient && shouldBypassPostgres(sql)) {
1499
+ return fallbackClient.executeMultiple(sql);
1500
+ }
1501
+ for (const statement of splitSqlStatements(sql)) {
1502
+ await adapter.execute(statement);
1503
+ }
1504
+ },
1505
+ async sync() {
1506
+ if (fallbackClient) {
1507
+ return fallbackClient.sync();
1508
+ }
1509
+ return { frame_no: 0, frames_synced: 0 };
1510
+ },
1511
+ close() {
1512
+ closed = true;
1513
+ prismaClientPromise = null;
1514
+ compatibilityBootstrapPromise = null;
1515
+ void prisma.$disconnect?.();
1516
+ },
1517
+ get closed() {
1518
+ return closed;
1519
+ },
1520
+ get protocol() {
1521
+ return "prisma-postgres";
1522
+ }
1523
+ };
1524
+ return adapter;
1525
+ }
1526
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
1527
+ var init_database_adapter = __esm({
1528
+ "src/lib/database-adapter.ts"() {
1529
+ "use strict";
1530
+ VIEW_MAPPINGS = [
1531
+ { view: "memories", source: "memory.memory_records" },
1532
+ { view: "tasks", source: "memory.tasks" },
1533
+ { view: "behaviors", source: "memory.behaviors" },
1534
+ { view: "entities", source: "memory.entities" },
1535
+ { view: "relationships", source: "memory.relationships" },
1536
+ { view: "entity_memories", source: "memory.entity_memories" },
1537
+ { view: "entity_aliases", source: "memory.entity_aliases" },
1538
+ { view: "notifications", source: "memory.notifications" },
1539
+ { view: "messages", source: "memory.messages" },
1540
+ { view: "users", source: "wiki.users" },
1541
+ { view: "workspaces", source: "wiki.workspaces" },
1542
+ { view: "workspace_users", source: "wiki.workspace_users" },
1543
+ { view: "documents", source: "wiki.workspace_documents" },
1544
+ { view: "chats", source: "wiki.workspace_chats" }
1545
+ ];
1546
+ UPSERT_KEYS = {
1547
+ memories: ["id"],
1548
+ tasks: ["id"],
1549
+ behaviors: ["id"],
1550
+ entities: ["id"],
1551
+ relationships: ["id"],
1552
+ entity_aliases: ["alias"],
1553
+ notifications: ["id"],
1554
+ messages: ["id"],
1555
+ users: ["id"],
1556
+ workspaces: ["id"],
1557
+ workspace_users: ["id"],
1558
+ documents: ["id"],
1559
+ chats: ["id"]
1560
+ };
1561
+ BOOLEAN_COLUMNS_BY_TABLE = {
1562
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
1563
+ behaviors: /* @__PURE__ */ new Set(["active"]),
1564
+ notifications: /* @__PURE__ */ new Set(["read"]),
1565
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
1566
+ };
1567
+ BOOLEAN_COLUMN_NAMES = new Set(
1568
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
1569
+ );
1570
+ IMMEDIATE_FALLBACK_PATTERNS = [
1571
+ /\bPRAGMA\b/i,
1572
+ /\bsqlite_master\b/i,
1573
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
1574
+ /\bMATCH\b/i,
1575
+ /\bvector_distance_cos\s*\(/i,
1576
+ /\bjson_extract\s*\(/i,
1577
+ /\bjulianday\s*\(/i,
1578
+ /\bstrftime\s*\(/i,
1579
+ /\blast_insert_rowid\s*\(/i
1580
+ ];
1581
+ prismaClientPromise = null;
1582
+ compatibilityBootstrapPromise = null;
838
1583
  }
839
1584
  });
840
1585
 
841
1586
  // src/lib/database.ts
842
1587
  import { createClient } from "@libsql/client";
843
1588
  async function initDatabase(config2) {
1589
+ if (_walCheckpointTimer) {
1590
+ clearInterval(_walCheckpointTimer);
1591
+ _walCheckpointTimer = null;
1592
+ }
1593
+ if (_daemonClient) {
1594
+ _daemonClient.close();
1595
+ _daemonClient = null;
1596
+ }
1597
+ if (_adapterClient && _adapterClient !== _resilientClient) {
1598
+ _adapterClient.close();
1599
+ }
1600
+ _adapterClient = null;
844
1601
  if (_client) {
845
1602
  _client.close();
846
1603
  _client = null;
@@ -854,6 +1611,7 @@ async function initDatabase(config2) {
854
1611
  }
855
1612
  _client = createClient(opts);
856
1613
  _resilientClient = wrapWithRetry(_client);
1614
+ _adapterClient = _resilientClient;
857
1615
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
858
1616
  });
859
1617
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -864,11 +1622,17 @@ async function initDatabase(config2) {
864
1622
  });
865
1623
  }, 3e4);
866
1624
  _walCheckpointTimer.unref();
1625
+ if (process.env.DATABASE_URL) {
1626
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
1627
+ }
867
1628
  }
868
1629
  function getClient() {
869
- if (!_resilientClient) {
1630
+ if (!_adapterClient) {
870
1631
  throw new Error("Database client not initialized. Call initDatabase() first.");
871
1632
  }
1633
+ if (process.env.DATABASE_URL) {
1634
+ return _adapterClient;
1635
+ }
872
1636
  if (process.env.EXE_IS_DAEMON === "1") {
873
1637
  return _resilientClient;
874
1638
  }
@@ -1809,26 +2573,36 @@ async function ensureSchema() {
1809
2573
  }
1810
2574
  }
1811
2575
  async function disposeDatabase() {
2576
+ if (_walCheckpointTimer) {
2577
+ clearInterval(_walCheckpointTimer);
2578
+ _walCheckpointTimer = null;
2579
+ }
1812
2580
  if (_daemonClient) {
1813
2581
  _daemonClient.close();
1814
2582
  _daemonClient = null;
1815
2583
  }
2584
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2585
+ _adapterClient.close();
2586
+ }
2587
+ _adapterClient = null;
1816
2588
  if (_client) {
1817
2589
  _client.close();
1818
2590
  _client = null;
1819
2591
  _resilientClient = null;
1820
2592
  }
1821
2593
  }
1822
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
2594
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
1823
2595
  var init_database = __esm({
1824
2596
  "src/lib/database.ts"() {
1825
2597
  "use strict";
1826
2598
  init_db_retry();
1827
2599
  init_employees();
2600
+ init_database_adapter();
1828
2601
  _client = null;
1829
2602
  _resilientClient = null;
1830
2603
  _walCheckpointTimer = null;
1831
2604
  _daemonClient = null;
2605
+ _adapterClient = null;
1832
2606
  initTurso = initDatabase;
1833
2607
  disposeTurso = disposeDatabase;
1834
2608
  }
@@ -1845,11 +2619,11 @@ var init_memory = __esm({
1845
2619
 
1846
2620
  // src/lib/exe-daemon-client.ts
1847
2621
  import net from "net";
1848
- import os3 from "os";
2622
+ import os4 from "os";
1849
2623
  import { spawn } from "child_process";
1850
2624
  import { randomUUID } from "crypto";
1851
- import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
1852
- import path3 from "path";
2625
+ import { existsSync as existsSync4, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
2626
+ import path5 from "path";
1853
2627
  import { fileURLToPath } from "url";
1854
2628
  function handleData(chunk) {
1855
2629
  _buffer += chunk.toString();
@@ -1877,9 +2651,9 @@ function handleData(chunk) {
1877
2651
  }
1878
2652
  }
1879
2653
  function cleanupStaleFiles() {
1880
- if (existsSync3(PID_PATH)) {
2654
+ if (existsSync4(PID_PATH)) {
1881
2655
  try {
1882
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
2656
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
1883
2657
  if (pid > 0) {
1884
2658
  try {
1885
2659
  process.kill(pid, 0);
@@ -1900,17 +2674,17 @@ function cleanupStaleFiles() {
1900
2674
  }
1901
2675
  }
1902
2676
  function findPackageRoot() {
1903
- let dir = path3.dirname(fileURLToPath(import.meta.url));
1904
- const { root } = path3.parse(dir);
2677
+ let dir = path5.dirname(fileURLToPath(import.meta.url));
2678
+ const { root } = path5.parse(dir);
1905
2679
  while (dir !== root) {
1906
- if (existsSync3(path3.join(dir, "package.json"))) return dir;
1907
- dir = path3.dirname(dir);
2680
+ if (existsSync4(path5.join(dir, "package.json"))) return dir;
2681
+ dir = path5.dirname(dir);
1908
2682
  }
1909
2683
  return null;
1910
2684
  }
1911
2685
  function spawnDaemon() {
1912
- const freeGB = os3.freemem() / (1024 * 1024 * 1024);
1913
- const totalGB = os3.totalmem() / (1024 * 1024 * 1024);
2686
+ const freeGB = os4.freemem() / (1024 * 1024 * 1024);
2687
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
1914
2688
  if (totalGB <= 8) {
1915
2689
  process.stderr.write(
1916
2690
  `[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
@@ -1930,8 +2704,8 @@ function spawnDaemon() {
1930
2704
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
1931
2705
  return;
1932
2706
  }
1933
- const daemonPath = path3.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1934
- if (!existsSync3(daemonPath)) {
2707
+ const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
2708
+ if (!existsSync4(daemonPath)) {
1935
2709
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
1936
2710
  `);
1937
2711
  return;
@@ -1939,7 +2713,7 @@ function spawnDaemon() {
1939
2713
  const resolvedPath = daemonPath;
1940
2714
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
1941
2715
  `);
1942
- const logPath = path3.join(path3.dirname(SOCKET_PATH), "exed.log");
2716
+ const logPath = path5.join(path5.dirname(SOCKET_PATH), "exed.log");
1943
2717
  let stderrFd = "ignore";
1944
2718
  try {
1945
2719
  stderrFd = openSync(logPath, "a");
@@ -2090,74 +2864,123 @@ async function pingDaemon() {
2090
2864
  return null;
2091
2865
  }
2092
2866
  function killAndRespawnDaemon() {
2093
- process.stderr.write("[exed-client] Killing daemon for restart...\n");
2094
- if (existsSync3(PID_PATH)) {
2095
- try {
2096
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
2097
- if (pid > 0) {
2098
- try {
2099
- process.kill(pid, "SIGKILL");
2100
- } catch {
2867
+ if (!acquireSpawnLock()) {
2868
+ process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
2869
+ if (_socket) {
2870
+ _socket.destroy();
2871
+ _socket = null;
2872
+ }
2873
+ _connected = false;
2874
+ _buffer = "";
2875
+ return;
2876
+ }
2877
+ try {
2878
+ process.stderr.write("[exed-client] Killing daemon for restart...\n");
2879
+ if (existsSync4(PID_PATH)) {
2880
+ try {
2881
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
2882
+ if (pid > 0) {
2883
+ try {
2884
+ process.kill(pid, "SIGKILL");
2885
+ } catch {
2886
+ }
2101
2887
  }
2888
+ } catch {
2102
2889
  }
2890
+ }
2891
+ if (_socket) {
2892
+ _socket.destroy();
2893
+ _socket = null;
2894
+ }
2895
+ _connected = false;
2896
+ _buffer = "";
2897
+ try {
2898
+ unlinkSync2(PID_PATH);
2103
2899
  } catch {
2104
2900
  }
2901
+ try {
2902
+ unlinkSync2(SOCKET_PATH);
2903
+ } catch {
2904
+ }
2905
+ spawnDaemon();
2906
+ } finally {
2907
+ releaseSpawnLock();
2105
2908
  }
2106
- if (_socket) {
2107
- _socket.destroy();
2108
- _socket = null;
2109
- }
2110
- _connected = false;
2111
- _buffer = "";
2909
+ }
2910
+ function isDaemonTooYoung() {
2112
2911
  try {
2113
- unlinkSync2(PID_PATH);
2912
+ const stat = statSync(PID_PATH);
2913
+ return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
2114
2914
  } catch {
2915
+ return false;
2115
2916
  }
2116
- try {
2117
- unlinkSync2(SOCKET_PATH);
2118
- } catch {
2917
+ }
2918
+ async function retryThenRestart(doRequest, label) {
2919
+ const result = await doRequest();
2920
+ if (!result.error) {
2921
+ _consecutiveFailures = 0;
2922
+ return result;
2923
+ }
2924
+ _consecutiveFailures++;
2925
+ for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
2926
+ const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
2927
+ process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
2928
+ `);
2929
+ await new Promise((r) => setTimeout(r, delayMs));
2930
+ if (!_connected) {
2931
+ if (!await connectToSocket()) continue;
2932
+ }
2933
+ const retry = await doRequest();
2934
+ if (!retry.error) {
2935
+ _consecutiveFailures = 0;
2936
+ return retry;
2937
+ }
2938
+ _consecutiveFailures++;
2939
+ }
2940
+ if (isDaemonTooYoung()) {
2941
+ process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
2942
+ `);
2943
+ return { error: result.error };
2944
+ }
2945
+ process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
2946
+ `);
2947
+ killAndRespawnDaemon();
2948
+ const start = Date.now();
2949
+ let delay2 = 200;
2950
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
2951
+ await new Promise((r) => setTimeout(r, delay2));
2952
+ if (await connectToSocket()) break;
2953
+ delay2 = Math.min(delay2 * 2, 3e3);
2119
2954
  }
2120
- spawnDaemon();
2955
+ if (!_connected) return { error: "Daemon restart failed" };
2956
+ const final = await doRequest();
2957
+ if (!final.error) _consecutiveFailures = 0;
2958
+ return final;
2121
2959
  }
2122
2960
  async function embedViaClient(text, priority = "high") {
2123
2961
  if (!_connected && !await connectEmbedDaemon()) return null;
2124
2962
  _requestCount++;
2125
2963
  if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
2126
2964
  const health = await pingDaemon();
2127
- if (!health) {
2965
+ if (!health && !isDaemonTooYoung()) {
2128
2966
  process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
2129
2967
  `);
2130
2968
  killAndRespawnDaemon();
2131
2969
  const start = Date.now();
2132
- let delay2 = 200;
2970
+ let d = 200;
2133
2971
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
2134
- await new Promise((r) => setTimeout(r, delay2));
2972
+ await new Promise((r) => setTimeout(r, d));
2135
2973
  if (await connectToSocket()) break;
2136
- delay2 = Math.min(delay2 * 2, 3e3);
2974
+ d = Math.min(d * 2, 3e3);
2137
2975
  }
2138
2976
  if (!_connected) return null;
2139
2977
  }
2140
2978
  }
2141
- const result = await sendRequest([text], priority);
2142
- if (!result.error && result.vectors?.[0]) return result.vectors[0];
2143
- if (result.error) {
2144
- process.stderr.write(`[exed-client] Embed failed (${result.error}) \u2014 attempting restart
2145
- `);
2146
- killAndRespawnDaemon();
2147
- const start = Date.now();
2148
- let delay2 = 200;
2149
- while (Date.now() - start < CONNECT_TIMEOUT_MS) {
2150
- await new Promise((r) => setTimeout(r, delay2));
2151
- if (await connectToSocket()) break;
2152
- delay2 = Math.min(delay2 * 2, 3e3);
2153
- }
2154
- if (!_connected) return null;
2155
- const retry = await sendRequest([text], priority);
2156
- if (!retry.error && retry.vectors?.[0]) return retry.vectors[0];
2157
- process.stderr.write(`[exed-client] Embed retry also failed: ${retry.error ?? "no vector"}
2158
- `);
2159
- }
2160
- return null;
2979
+ const result = await retryThenRestart(
2980
+ () => sendRequest([text], priority),
2981
+ "Embed"
2982
+ );
2983
+ return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
2161
2984
  }
2162
2985
  function disconnectClient() {
2163
2986
  if (_socket) {
@@ -2172,14 +2995,14 @@ function disconnectClient() {
2172
2995
  entry.resolve({ error: "Client disconnected" });
2173
2996
  }
2174
2997
  }
2175
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
2998
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
2176
2999
  var init_exe_daemon_client = __esm({
2177
3000
  "src/lib/exe-daemon-client.ts"() {
2178
3001
  "use strict";
2179
3002
  init_config();
2180
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path3.join(EXE_AI_DIR, "exed.sock");
2181
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path3.join(EXE_AI_DIR, "exed.pid");
2182
- SPAWN_LOCK_PATH = path3.join(EXE_AI_DIR, "exed-spawn.lock");
3003
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
3004
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
3005
+ SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
2183
3006
  SPAWN_LOCK_STALE_MS = 3e4;
2184
3007
  CONNECT_TIMEOUT_MS = 15e3;
2185
3008
  REQUEST_TIMEOUT_MS = 3e4;
@@ -2187,7 +3010,11 @@ var init_exe_daemon_client = __esm({
2187
3010
  _connected = false;
2188
3011
  _buffer = "";
2189
3012
  _requestCount = 0;
3013
+ _consecutiveFailures = 0;
2190
3014
  HEALTH_CHECK_INTERVAL = 100;
3015
+ MAX_RETRIES_BEFORE_RESTART = 3;
3016
+ RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
3017
+ MIN_DAEMON_AGE_MS = 3e4;
2191
3018
  _pending = /* @__PURE__ */ new Map();
2192
3019
  MAX_BUFFER = 1e7;
2193
3020
  }
@@ -2231,8 +3058,8 @@ async function embedDirect(text) {
2231
3058
  const llamaCpp = await import("node-llama-cpp");
2232
3059
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
2233
3060
  const { existsSync: existsSync16 } = await import("fs");
2234
- const path20 = await import("path");
2235
- const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
3061
+ const path21 = await import("path");
3062
+ const modelPath = path21.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
2236
3063
  if (!existsSync16(modelPath)) {
2237
3064
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
2238
3065
  }
@@ -2263,14 +3090,14 @@ var init_embedder = __esm({
2263
3090
 
2264
3091
  // src/lib/keychain.ts
2265
3092
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2266
- import { existsSync as existsSync4 } from "fs";
2267
- import path4 from "path";
2268
- import os4 from "os";
3093
+ import { existsSync as existsSync5 } from "fs";
3094
+ import path6 from "path";
3095
+ import os5 from "os";
2269
3096
  function getKeyDir() {
2270
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
3097
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path6.join(os5.homedir(), ".exe-os");
2271
3098
  }
2272
3099
  function getKeyPath() {
2273
- return path4.join(getKeyDir(), "master.key");
3100
+ return path6.join(getKeyDir(), "master.key");
2274
3101
  }
2275
3102
  async function tryKeytar() {
2276
3103
  try {
@@ -2291,9 +3118,9 @@ async function getMasterKey() {
2291
3118
  }
2292
3119
  }
2293
3120
  const keyPath = getKeyPath();
2294
- if (!existsSync4(keyPath)) {
3121
+ if (!existsSync5(keyPath)) {
2295
3122
  process.stderr.write(
2296
- `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3123
+ `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2297
3124
  `
2298
3125
  );
2299
3126
  return null;
@@ -2331,13 +3158,13 @@ __export(shard_manager_exports, {
2331
3158
  listShards: () => listShards,
2332
3159
  shardExists: () => shardExists
2333
3160
  });
2334
- import path5 from "path";
2335
- import { existsSync as existsSync5, mkdirSync, readdirSync } from "fs";
3161
+ import path7 from "path";
3162
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync } from "fs";
2336
3163
  import { createClient as createClient2 } from "@libsql/client";
2337
3164
  function initShardManager(encryptionKey) {
2338
3165
  _encryptionKey = encryptionKey;
2339
- if (!existsSync5(SHARDS_DIR)) {
2340
- mkdirSync(SHARDS_DIR, { recursive: true });
3166
+ if (!existsSync6(SHARDS_DIR)) {
3167
+ mkdirSync2(SHARDS_DIR, { recursive: true });
2341
3168
  }
2342
3169
  _shardingEnabled = true;
2343
3170
  }
@@ -2357,7 +3184,7 @@ function getShardClient(projectName) {
2357
3184
  }
2358
3185
  const cached = _shards.get(safeName);
2359
3186
  if (cached) return cached;
2360
- const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
3187
+ const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
2361
3188
  const client = createClient2({
2362
3189
  url: `file:${dbPath}`,
2363
3190
  encryptionKey: _encryptionKey
@@ -2367,10 +3194,10 @@ function getShardClient(projectName) {
2367
3194
  }
2368
3195
  function shardExists(projectName) {
2369
3196
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2370
- return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
3197
+ return existsSync6(path7.join(SHARDS_DIR, `${safeName}.db`));
2371
3198
  }
2372
3199
  function listShards() {
2373
- if (!existsSync5(SHARDS_DIR)) return [];
3200
+ if (!existsSync6(SHARDS_DIR)) return [];
2374
3201
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
2375
3202
  }
2376
3203
  async function ensureShardSchema(client) {
@@ -2444,7 +3271,23 @@ async function ensureShardSchema(client) {
2444
3271
  // MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
2445
3272
  "ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
2446
3273
  "ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
2447
- "ALTER TABLE memories ADD COLUMN trajectory TEXT"
3274
+ "ALTER TABLE memories ADD COLUMN trajectory TEXT",
3275
+ // Metadata enrichment columns (must match database.ts)
3276
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
3277
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
3278
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
3279
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
3280
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
3281
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
3282
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
3283
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
3284
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
3285
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
3286
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
3287
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
3288
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
3289
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
3290
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
2448
3291
  ]) {
2449
3292
  try {
2450
3293
  await client.execute(col);
@@ -2556,7 +3399,7 @@ var init_shard_manager = __esm({
2556
3399
  "src/lib/shard-manager.ts"() {
2557
3400
  "use strict";
2558
3401
  init_config();
2559
- SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
3402
+ SHARDS_DIR = path7.join(EXE_AI_DIR, "shards");
2560
3403
  _shards = /* @__PURE__ */ new Map();
2561
3404
  _encryptionKey = null;
2562
3405
  _shardingEnabled = false;
@@ -3329,8 +4172,8 @@ __export(wiki_client_exports, {
3329
4172
  listDocuments: () => listDocuments,
3330
4173
  listWorkspaces: () => listWorkspaces
3331
4174
  });
3332
- async function wikiFetch(config2, path20, method = "GET", body) {
3333
- const url = `${config2.baseUrl}/api/v1${path20}`;
4175
+ async function wikiFetch(config2, path21, method = "GET", body) {
4176
+ const url = `${config2.baseUrl}/api/v1${path21}`;
3334
4177
  const headers = {
3335
4178
  Authorization: `Bearer ${config2.apiKey}`,
3336
4179
  "Content-Type": "application/json"
@@ -3363,7 +4206,7 @@ async function wikiFetch(config2, path20, method = "GET", body) {
3363
4206
  }
3364
4207
  }
3365
4208
  if (!response.ok) {
3366
- throw new Error(`Wiki API ${method} ${path20}: ${response.status} ${response.statusText}`);
4209
+ throw new Error(`Wiki API ${method} ${path21}: ${response.status} ${response.statusText}`);
3367
4210
  }
3368
4211
  return response.json();
3369
4212
  } finally {
@@ -4384,13 +5227,13 @@ __export(whatsapp_accounts_exports, {
4384
5227
  getDefaultAccount: () => getDefaultAccount,
4385
5228
  loadAccounts: () => loadAccounts
4386
5229
  });
4387
- import { readFileSync as readFileSync4 } from "fs";
5230
+ import { readFileSync as readFileSync5 } from "fs";
4388
5231
  import { join as join2 } from "path";
4389
5232
  import { homedir as homedir2 } from "os";
4390
5233
  function loadAccounts() {
4391
5234
  if (cachedAccounts !== null) return cachedAccounts;
4392
5235
  try {
4393
- const raw = readFileSync4(CONFIG_PATH2, "utf8");
5236
+ const raw = readFileSync5(CONFIG_PATH2, "utf8");
4394
5237
  const parsed = JSON.parse(raw);
4395
5238
  if (!Array.isArray(parsed)) {
4396
5239
  console.warn("[whatsapp] Config is not an array, ignoring");
@@ -4430,13 +5273,13 @@ var init_whatsapp_accounts = __esm({
4430
5273
  });
4431
5274
 
4432
5275
  // src/lib/session-registry.ts
4433
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync6 } from "fs";
4434
- import path7 from "path";
4435
- import os6 from "os";
5276
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync7 } from "fs";
5277
+ import path9 from "path";
5278
+ import os7 from "os";
4436
5279
  function registerSession(entry) {
4437
- const dir = path7.dirname(REGISTRY_PATH);
4438
- if (!existsSync6(dir)) {
4439
- mkdirSync3(dir, { recursive: true });
5280
+ const dir = path9.dirname(REGISTRY_PATH);
5281
+ if (!existsSync7(dir)) {
5282
+ mkdirSync4(dir, { recursive: true });
4440
5283
  }
4441
5284
  const sessions = listSessions();
4442
5285
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -4445,11 +5288,11 @@ function registerSession(entry) {
4445
5288
  } else {
4446
5289
  sessions.push(entry);
4447
5290
  }
4448
- writeFileSync2(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
5291
+ writeFileSync3(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
4449
5292
  }
4450
5293
  function listSessions() {
4451
5294
  try {
4452
- const raw = readFileSync5(REGISTRY_PATH, "utf8");
5295
+ const raw = readFileSync6(REGISTRY_PATH, "utf8");
4453
5296
  return JSON.parse(raw);
4454
5297
  } catch {
4455
5298
  return [];
@@ -4459,7 +5302,7 @@ var REGISTRY_PATH;
4459
5302
  var init_session_registry = __esm({
4460
5303
  "src/lib/session-registry.ts"() {
4461
5304
  "use strict";
4462
- REGISTRY_PATH = path7.join(os6.homedir(), ".exe-os", "session-registry.json");
5305
+ REGISTRY_PATH = path9.join(os7.homedir(), ".exe-os", "session-registry.json");
4463
5306
  }
4464
5307
  });
4465
5308
 
@@ -4711,67 +5554,6 @@ var init_provider_table = __esm({
4711
5554
  }
4712
5555
  });
4713
5556
 
4714
- // src/lib/runtime-table.ts
4715
- var RUNTIME_TABLE, DEFAULT_RUNTIME;
4716
- var init_runtime_table = __esm({
4717
- "src/lib/runtime-table.ts"() {
4718
- "use strict";
4719
- RUNTIME_TABLE = {
4720
- codex: {
4721
- binary: "codex",
4722
- launchMode: "interactive",
4723
- autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
4724
- inlineFlag: "--no-alt-screen",
4725
- apiKeyEnv: "OPENAI_API_KEY",
4726
- defaultModel: "gpt-5.4"
4727
- },
4728
- opencode: {
4729
- binary: "opencode",
4730
- launchMode: "exec",
4731
- autoApproveFlag: "--dangerously-skip-permissions",
4732
- inlineFlag: "",
4733
- apiKeyEnv: "ANTHROPIC_API_KEY",
4734
- defaultModel: "anthropic/claude-sonnet-4-6"
4735
- }
4736
- };
4737
- DEFAULT_RUNTIME = "claude";
4738
- }
4739
- });
4740
-
4741
- // src/lib/agent-config.ts
4742
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
4743
- import path8 from "path";
4744
- function loadAgentConfig() {
4745
- if (!existsSync7(AGENT_CONFIG_PATH)) return {};
4746
- try {
4747
- return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
4748
- } catch {
4749
- return {};
4750
- }
4751
- }
4752
- function getAgentRuntime(agentId) {
4753
- const config2 = loadAgentConfig();
4754
- const entry = config2[agentId];
4755
- if (entry) return entry;
4756
- const orgDefault = config2["default"];
4757
- if (orgDefault) return orgDefault;
4758
- return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
4759
- }
4760
- var AGENT_CONFIG_PATH, DEFAULT_MODELS;
4761
- var init_agent_config = __esm({
4762
- "src/lib/agent-config.ts"() {
4763
- "use strict";
4764
- init_config();
4765
- init_runtime_table();
4766
- AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
4767
- DEFAULT_MODELS = {
4768
- claude: "claude-opus-4",
4769
- codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
4770
- opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
4771
- };
4772
- }
4773
- });
4774
-
4775
5557
  // src/lib/intercom-queue.ts
4776
5558
  var intercom_queue_exports = {};
4777
5559
  __export(intercom_queue_exports, {
@@ -4782,10 +5564,10 @@ __export(intercom_queue_exports, {
4782
5564
  readQueue: () => readQueue
4783
5565
  });
4784
5566
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
4785
- import path9 from "path";
4786
- import os7 from "os";
5567
+ import path10 from "path";
5568
+ import os8 from "os";
4787
5569
  function ensureDir() {
4788
- const dir = path9.dirname(QUEUE_PATH);
5570
+ const dir = path10.dirname(QUEUE_PATH);
4789
5571
  if (!existsSync8(dir)) mkdirSync5(dir, { recursive: true });
4790
5572
  }
4791
5573
  function readQueue() {
@@ -4891,26 +5673,26 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
4891
5673
  var init_intercom_queue = __esm({
4892
5674
  "src/lib/intercom-queue.ts"() {
4893
5675
  "use strict";
4894
- QUEUE_PATH = path9.join(os7.homedir(), ".exe-os", "intercom-queue.json");
5676
+ QUEUE_PATH = path10.join(os8.homedir(), ".exe-os", "intercom-queue.json");
4895
5677
  MAX_RETRIES2 = 5;
4896
5678
  TTL_MS = 60 * 60 * 1e3;
4897
- INTERCOM_LOG = path9.join(os7.homedir(), ".exe-os", "intercom.log");
5679
+ INTERCOM_LOG = path10.join(os8.homedir(), ".exe-os", "intercom.log");
4898
5680
  }
4899
5681
  });
4900
5682
 
4901
5683
  // src/lib/license.ts
4902
5684
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
4903
5685
  import { randomUUID as randomUUID11 } from "crypto";
4904
- import path10 from "path";
5686
+ import path11 from "path";
4905
5687
  import { jwtVerify, importSPKI } from "jose";
4906
5688
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
4907
5689
  var init_license = __esm({
4908
5690
  "src/lib/license.ts"() {
4909
5691
  "use strict";
4910
5692
  init_config();
4911
- LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
4912
- CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
4913
- DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
5693
+ LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
5694
+ CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
5695
+ DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
4914
5696
  PLAN_LIMITS = {
4915
5697
  free: { devices: 1, employees: 1, memories: 5e3 },
4916
5698
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -4923,7 +5705,7 @@ var init_license = __esm({
4923
5705
 
4924
5706
  // src/lib/plan-limits.ts
4925
5707
  import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
4926
- import path11 from "path";
5708
+ import path12 from "path";
4927
5709
  function getLicenseSync() {
4928
5710
  try {
4929
5711
  if (!existsSync10(CACHE_PATH2)) return freeLicense();
@@ -4995,14 +5777,14 @@ var init_plan_limits = __esm({
4995
5777
  this.name = "PlanLimitError";
4996
5778
  }
4997
5779
  };
4998
- CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
5780
+ CACHE_PATH2 = path12.join(EXE_AI_DIR, "license-cache.json");
4999
5781
  }
5000
5782
  });
5001
5783
 
5002
5784
  // src/lib/notifications.ts
5003
5785
  import crypto3 from "crypto";
5004
- import path12 from "path";
5005
- import os8 from "os";
5786
+ import path13 from "path";
5787
+ import os9 from "os";
5006
5788
  import {
5007
5789
  readFileSync as readFileSync10,
5008
5790
  readdirSync as readdirSync2,
@@ -5111,8 +5893,8 @@ var init_task_scope = __esm({
5111
5893
 
5112
5894
  // src/lib/tasks-crud.ts
5113
5895
  import crypto5 from "crypto";
5114
- import path13 from "path";
5115
- import os9 from "os";
5896
+ import path14 from "path";
5897
+ import os10 from "os";
5116
5898
  import { execSync as execSync4 } from "child_process";
5117
5899
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
5118
5900
  import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
@@ -5290,8 +6072,8 @@ ${laneWarning}` : laneWarning;
5290
6072
  }
5291
6073
  if (input.baseDir) {
5292
6074
  try {
5293
- await mkdir4(path13.join(input.baseDir, "exe", "output"), { recursive: true });
5294
- await mkdir4(path13.join(input.baseDir, "exe", "research"), { recursive: true });
6075
+ await mkdir4(path14.join(input.baseDir, "exe", "output"), { recursive: true });
6076
+ await mkdir4(path14.join(input.baseDir, "exe", "research"), { recursive: true });
5295
6077
  await ensureArchitectureDoc(input.baseDir, input.projectName);
5296
6078
  await ensureGitignoreExe(input.baseDir);
5297
6079
  } catch {
@@ -5327,9 +6109,9 @@ ${laneWarning}` : laneWarning;
5327
6109
  });
5328
6110
  if (input.baseDir) {
5329
6111
  try {
5330
- const EXE_OS_DIR = path13.join(os9.homedir(), ".exe-os");
5331
- const mdPath = path13.join(EXE_OS_DIR, taskFile);
5332
- const mdDir = path13.dirname(mdPath);
6112
+ const EXE_OS_DIR = path14.join(os10.homedir(), ".exe-os");
6113
+ const mdPath = path14.join(EXE_OS_DIR, taskFile);
6114
+ const mdDir = path14.dirname(mdPath);
5333
6115
  if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
5334
6116
  const reviewer = input.reviewer ?? input.assignedBy;
5335
6117
  const mdContent = `# ${input.title}
@@ -5630,7 +6412,7 @@ async function deleteTaskCore(taskId, _baseDir) {
5630
6412
  return { taskFile, assignedTo, assignedBy, taskSlug };
5631
6413
  }
5632
6414
  async function ensureArchitectureDoc(baseDir, projectName) {
5633
- const archPath = path13.join(baseDir, "exe", "ARCHITECTURE.md");
6415
+ const archPath = path14.join(baseDir, "exe", "ARCHITECTURE.md");
5634
6416
  try {
5635
6417
  if (existsSync12(archPath)) return;
5636
6418
  const template = [
@@ -5665,7 +6447,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
5665
6447
  }
5666
6448
  }
5667
6449
  async function ensureGitignoreExe(baseDir) {
5668
- const gitignorePath = path13.join(baseDir, ".gitignore");
6450
+ const gitignorePath = path14.join(baseDir, ".gitignore");
5669
6451
  try {
5670
6452
  if (existsSync12(gitignorePath)) {
5671
6453
  const content = readFileSync11(gitignorePath, "utf-8");
@@ -5699,13 +6481,13 @@ var init_tasks_crud = __esm({
5699
6481
  });
5700
6482
 
5701
6483
  // src/lib/tasks-review.ts
5702
- import path14 from "path";
6484
+ import path15 from "path";
5703
6485
  import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
5704
6486
  async function countPendingReviews(sessionScope) {
5705
6487
  const client = getClient();
5706
6488
  if (sessionScope) {
5707
6489
  const result2 = await client.execute({
5708
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
6490
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
5709
6491
  args: [sessionScope]
5710
6492
  });
5711
6493
  return Number(result2.rows[0]?.cnt) || 0;
@@ -5881,11 +6663,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
5881
6663
  );
5882
6664
  }
5883
6665
  try {
5884
- const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
6666
+ const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
5885
6667
  if (existsSync13(cacheDir)) {
5886
6668
  for (const f of readdirSync3(cacheDir)) {
5887
6669
  if (f.startsWith("review-notified-")) {
5888
- unlinkSync4(path14.join(cacheDir, f));
6670
+ unlinkSync4(path15.join(cacheDir, f));
5889
6671
  }
5890
6672
  }
5891
6673
  }
@@ -5906,7 +6688,7 @@ var init_tasks_review = __esm({
5906
6688
  });
5907
6689
 
5908
6690
  // src/lib/tasks-chain.ts
5909
- import path15 from "path";
6691
+ import path16 from "path";
5910
6692
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
5911
6693
  async function cascadeUnblock(taskId, baseDir, now) {
5912
6694
  const client = getClient();
@@ -5923,7 +6705,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
5923
6705
  });
5924
6706
  for (const ur of unblockedRows.rows) {
5925
6707
  try {
5926
- const ubFile = path15.join(baseDir, String(ur.task_file));
6708
+ const ubFile = path16.join(baseDir, String(ur.task_file));
5927
6709
  let ubContent = await readFile4(ubFile, "utf-8");
5928
6710
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
5929
6711
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -5992,7 +6774,7 @@ var init_tasks_chain = __esm({
5992
6774
 
5993
6775
  // src/lib/project-name.ts
5994
6776
  import { execSync as execSync5 } from "child_process";
5995
- import path16 from "path";
6777
+ import path17 from "path";
5996
6778
  function getProjectName(cwd) {
5997
6779
  const dir = cwd ?? process.cwd();
5998
6780
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -6005,7 +6787,7 @@ function getProjectName(cwd) {
6005
6787
  timeout: 2e3,
6006
6788
  stdio: ["pipe", "pipe", "pipe"]
6007
6789
  }).trim();
6008
- repoRoot = path16.dirname(gitCommonDir);
6790
+ repoRoot = path17.dirname(gitCommonDir);
6009
6791
  } catch {
6010
6792
  repoRoot = execSync5("git rev-parse --show-toplevel", {
6011
6793
  cwd: dir,
@@ -6014,11 +6796,11 @@ function getProjectName(cwd) {
6014
6796
  stdio: ["pipe", "pipe", "pipe"]
6015
6797
  }).trim();
6016
6798
  }
6017
- _cached2 = path16.basename(repoRoot);
6799
+ _cached2 = path17.basename(repoRoot);
6018
6800
  _cachedCwd = dir;
6019
6801
  return _cached2;
6020
6802
  } catch {
6021
- _cached2 = path16.basename(dir);
6803
+ _cached2 = path17.basename(dir);
6022
6804
  _cachedCwd = dir;
6023
6805
  return _cached2;
6024
6806
  }
@@ -6491,7 +7273,7 @@ __export(tasks_exports, {
6491
7273
  updateTaskStatus: () => updateTaskStatus,
6492
7274
  writeCheckpoint: () => writeCheckpoint
6493
7275
  });
6494
- import path17 from "path";
7276
+ import path18 from "path";
6495
7277
  import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
6496
7278
  async function createTask(input) {
6497
7279
  const result = await createTaskCore(input);
@@ -6511,8 +7293,8 @@ async function updateTask(input) {
6511
7293
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
6512
7294
  try {
6513
7295
  const agent = String(row.assigned_to);
6514
- const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
6515
- const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
7296
+ const cacheDir = path18.join(EXE_AI_DIR, "session-cache");
7297
+ const cachePath = path18.join(cacheDir, `current-task-${agent}.json`);
6516
7298
  if (input.status === "in_progress") {
6517
7299
  mkdirSync7(cacheDir, { recursive: true });
6518
7300
  writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -6983,12 +7765,12 @@ __export(tmux_routing_exports, {
6983
7765
  });
6984
7766
  import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
6985
7767
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync4 } from "fs";
6986
- import path18 from "path";
6987
- import os10 from "os";
7768
+ import path19 from "path";
7769
+ import os11 from "os";
6988
7770
  import { fileURLToPath as fileURLToPath2 } from "url";
6989
7771
  import { unlinkSync as unlinkSync6 } from "fs";
6990
7772
  function spawnLockPath(sessionName) {
6991
- return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
7773
+ return path19.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6992
7774
  }
6993
7775
  function isProcessAlive(pid) {
6994
7776
  try {
@@ -7025,8 +7807,8 @@ function releaseSpawnLock2(sessionName) {
7025
7807
  function resolveBehaviorsExporterScript() {
7026
7808
  try {
7027
7809
  const thisFile = fileURLToPath2(import.meta.url);
7028
- const scriptPath = path18.join(
7029
- path18.dirname(thisFile),
7810
+ const scriptPath = path19.join(
7811
+ path19.dirname(thisFile),
7030
7812
  "..",
7031
7813
  "bin",
7032
7814
  "exe-export-behaviors.js"
@@ -7101,7 +7883,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
7101
7883
  mkdirSync8(SESSION_CACHE, { recursive: true });
7102
7884
  }
7103
7885
  const rootExe = extractRootExe(parentExe) ?? parentExe;
7104
- const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
7886
+ const filePath = path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
7105
7887
  writeFileSync7(filePath, JSON.stringify({
7106
7888
  parentExe: rootExe,
7107
7889
  dispatchedBy: dispatchedBy || rootExe,
@@ -7110,7 +7892,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
7110
7892
  }
7111
7893
  function getParentExe(sessionKey) {
7112
7894
  try {
7113
- const data = JSON.parse(readFileSync12(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
7895
+ const data = JSON.parse(readFileSync12(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
7114
7896
  return data.parentExe || null;
7115
7897
  } catch {
7116
7898
  return null;
@@ -7119,7 +7901,7 @@ function getParentExe(sessionKey) {
7119
7901
  function getDispatchedBy(sessionKey) {
7120
7902
  try {
7121
7903
  const data = JSON.parse(readFileSync12(
7122
- path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
7904
+ path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
7123
7905
  "utf8"
7124
7906
  ));
7125
7907
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -7305,7 +8087,7 @@ function sendIntercom(targetSession) {
7305
8087
  try {
7306
8088
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
7307
8089
  const agent = baseAgentName(rawAgent);
7308
- const markerPath = path18.join(SESSION_CACHE, `current-task-${agent}.json`);
8090
+ const markerPath = path19.join(SESSION_CACHE, `current-task-${agent}.json`);
7309
8091
  if (existsSync14(markerPath)) {
7310
8092
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
7311
8093
  return "debounced";
@@ -7315,7 +8097,7 @@ function sendIntercom(targetSession) {
7315
8097
  try {
7316
8098
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
7317
8099
  const agent = baseAgentName(rawAgent);
7318
- const taskDir = path18.join(process.cwd(), "exe", agent);
8100
+ const taskDir = path19.join(process.cwd(), "exe", agent);
7319
8101
  if (existsSync14(taskDir)) {
7320
8102
  const files = readdirSync4(taskDir).filter(
7321
8103
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -7449,8 +8231,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7449
8231
  const transport = getTransport();
7450
8232
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
7451
8233
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
7452
- const logDir = path18.join(os10.homedir(), ".exe-os", "session-logs");
7453
- const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
8234
+ const logDir = path19.join(os11.homedir(), ".exe-os", "session-logs");
8235
+ const logFile = path19.join(logDir, `${instanceLabel}-${Date.now()}.log`);
7454
8236
  if (!existsSync14(logDir)) {
7455
8237
  mkdirSync8(logDir, { recursive: true });
7456
8238
  }
@@ -7458,14 +8240,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7458
8240
  let cleanupSuffix = "";
7459
8241
  try {
7460
8242
  const thisFile = fileURLToPath2(import.meta.url);
7461
- const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
8243
+ const cleanupScript = path19.join(path19.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
7462
8244
  if (existsSync14(cleanupScript)) {
7463
8245
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
7464
8246
  }
7465
8247
  } catch {
7466
8248
  }
7467
8249
  try {
7468
- const claudeJsonPath = path18.join(os10.homedir(), ".claude.json");
8250
+ const claudeJsonPath = path19.join(os11.homedir(), ".claude.json");
7469
8251
  let claudeJson = {};
7470
8252
  try {
7471
8253
  claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
@@ -7480,10 +8262,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7480
8262
  } catch {
7481
8263
  }
7482
8264
  try {
7483
- const settingsDir = path18.join(os10.homedir(), ".claude", "projects");
8265
+ const settingsDir = path19.join(os11.homedir(), ".claude", "projects");
7484
8266
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
7485
- const projSettingsDir = path18.join(settingsDir, normalizedKey);
7486
- const settingsPath = path18.join(projSettingsDir, "settings.json");
8267
+ const projSettingsDir = path19.join(settingsDir, normalizedKey);
8268
+ const settingsPath = path19.join(projSettingsDir, "settings.json");
7487
8269
  let settings = {};
7488
8270
  try {
7489
8271
  settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
@@ -7530,8 +8312,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7530
8312
  let behaviorsFlag = "";
7531
8313
  let legacyFallbackWarned = false;
7532
8314
  if (!useExeAgent && !useBinSymlink) {
7533
- const identityPath = path18.join(
7534
- os10.homedir(),
8315
+ const identityPath = path19.join(
8316
+ os11.homedir(),
7535
8317
  ".exe-os",
7536
8318
  "identity",
7537
8319
  `${employeeName}.md`
@@ -7546,7 +8328,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7546
8328
  }
7547
8329
  const behaviorsFile = exportBehaviorsSync(
7548
8330
  employeeName,
7549
- path18.basename(spawnCwd),
8331
+ path19.basename(spawnCwd),
7550
8332
  sessionName
7551
8333
  );
7552
8334
  if (behaviorsFile) {
@@ -7561,9 +8343,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7561
8343
  }
7562
8344
  let sessionContextFlag = "";
7563
8345
  try {
7564
- const ctxDir = path18.join(os10.homedir(), ".exe-os", "session-cache");
8346
+ const ctxDir = path19.join(os11.homedir(), ".exe-os", "session-cache");
7565
8347
  mkdirSync8(ctxDir, { recursive: true });
7566
- const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
8348
+ const ctxFile = path19.join(ctxDir, `session-context-${sessionName}.md`);
7567
8349
  const ctxContent = [
7568
8350
  `## Session Context`,
7569
8351
  `You are running in tmux session: ${sessionName}.`,
@@ -7647,7 +8429,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7647
8429
  transport.pipeLog(sessionName, logFile);
7648
8430
  try {
7649
8431
  const mySession = getMySession();
7650
- const dispatchInfo = path18.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
8432
+ const dispatchInfo = path19.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
7651
8433
  writeFileSync7(dispatchInfo, JSON.stringify({
7652
8434
  dispatchedBy: mySession,
7653
8435
  rootExe: exeSession,
@@ -7722,15 +8504,15 @@ var init_tmux_routing = __esm({
7722
8504
  init_intercom_queue();
7723
8505
  init_plan_limits();
7724
8506
  init_employees();
7725
- SPAWN_LOCK_DIR = path18.join(os10.homedir(), ".exe-os", "spawn-locks");
7726
- SESSION_CACHE = path18.join(os10.homedir(), ".exe-os", "session-cache");
8507
+ SPAWN_LOCK_DIR = path19.join(os11.homedir(), ".exe-os", "spawn-locks");
8508
+ SESSION_CACHE = path19.join(os11.homedir(), ".exe-os", "session-cache");
7727
8509
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
7728
8510
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
7729
8511
  VERIFY_PANE_LINES = 200;
7730
8512
  INTERCOM_DEBOUNCE_MS = 3e4;
7731
8513
  CODEX_DEBOUNCE_MS = 12e4;
7732
- INTERCOM_LOG2 = path18.join(os10.homedir(), ".exe-os", "intercom.log");
7733
- DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
8514
+ INTERCOM_LOG2 = path19.join(os11.homedir(), ".exe-os", "intercom.log");
8515
+ DEBOUNCE_FILE = path19.join(SESSION_CACHE, "intercom-debounce.json");
7734
8516
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
7735
8517
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
7736
8518
  }
@@ -9586,7 +10368,7 @@ var OllamaProvider = class {
9586
10368
  import { randomUUID as randomUUID5 } from "crypto";
9587
10369
  import { homedir } from "os";
9588
10370
  import { join } from "path";
9589
- import { mkdirSync as mkdirSync2 } from "fs";
10371
+ import { mkdirSync as mkdirSync3 } from "fs";
9590
10372
  var INITIAL_BACKOFF_MS = 1e3;
9591
10373
  var MAX_BACKOFF_MS = 3e5;
9592
10374
  var BACKOFF_MULTIPLIER = 2;
@@ -9612,7 +10394,7 @@ var WhatsAppAdapter = class {
9612
10394
  disconnectedAt = 0;
9613
10395
  async connect(config2) {
9614
10396
  this.authDir = config2.credentials.authDir ?? AUTH_DIR;
9615
- mkdirSync2(this.authDir, { recursive: true });
10397
+ mkdirSync3(this.authDir, { recursive: true });
9616
10398
  const baileys = await import("@whiskeysockets/baileys");
9617
10399
  const { makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion, DisconnectReason, makeCacheableSignalKeyStore } = baileys;
9618
10400
  const { state, saveCreds } = await useMultiFileAuthState(this.authDir);
@@ -10914,12 +11696,12 @@ var SlackAdapter = class {
10914
11696
  // src/gateway/adapters/imessage.ts
10915
11697
  import { execFile } from "child_process";
10916
11698
  import { promisify } from "util";
10917
- import os5 from "os";
10918
- import path6 from "path";
11699
+ import os6 from "os";
11700
+ import path8 from "path";
10919
11701
  var execFileAsync = promisify(execFile);
10920
11702
  var POLL_INTERVAL_MS = 5e3;
10921
- var MESSAGES_DB_PATH = path6.join(
10922
- process.env.HOME ?? os5.homedir(),
11703
+ var MESSAGES_DB_PATH = path8.join(
11704
+ process.env.HOME ?? os6.homedir(),
10923
11705
  "Library/Messages/chat.db"
10924
11706
  );
10925
11707
  var IMessageAdapter = class {
@@ -11764,9 +12546,9 @@ async function ensureCRMContact(info) {
11764
12546
  // src/automation/trigger-engine.ts
11765
12547
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, existsSync as existsSync15, mkdirSync as mkdirSync9 } from "fs";
11766
12548
  import { randomUUID as randomUUID12 } from "crypto";
11767
- import path19 from "path";
11768
- import os11 from "os";
11769
- var TRIGGERS_PATH = path19.join(os11.homedir(), ".exe-os", "triggers.json");
12549
+ import path20 from "path";
12550
+ import os12 from "os";
12551
+ var TRIGGERS_PATH = path20.join(os12.homedir(), ".exe-os", "triggers.json");
11770
12552
  var GRAPH_API_VERSION = "v21.0";
11771
12553
  function substituteTemplate(template, record) {
11772
12554
  return template.replace(