@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
@@ -792,7 +792,7 @@ function isMultiInstance(agentName, employees) {
792
792
  if (!emp) return false;
793
793
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
794
794
  }
795
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
795
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
796
796
  var init_employees = __esm({
797
797
  "src/lib/employees.ts"() {
798
798
  "use strict";
@@ -801,16 +801,601 @@ var init_employees = __esm({
801
801
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
802
802
  COORDINATOR_ROLE = "COO";
803
803
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
804
+ IDENTITY_DIR = path5.join(EXE_AI_DIR, "identity");
805
+ }
806
+ });
807
+
808
+ // src/lib/database-adapter.ts
809
+ import os5 from "os";
810
+ import path6 from "path";
811
+ import { createRequire } from "module";
812
+ import { pathToFileURL } from "url";
813
+ function quotedIdentifier(identifier) {
814
+ return `"${identifier.replace(/"/g, '""')}"`;
815
+ }
816
+ function unqualifiedTableName(name) {
817
+ const raw = name.trim().replace(/^"|"$/g, "");
818
+ const parts = raw.split(".");
819
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
820
+ }
821
+ function stripTrailingSemicolon(sql) {
822
+ return sql.trim().replace(/;+\s*$/u, "");
823
+ }
824
+ function appendClause(sql, clause) {
825
+ const trimmed = stripTrailingSemicolon(sql);
826
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
827
+ if (!returningMatch) {
828
+ return `${trimmed}${clause}`;
829
+ }
830
+ const idx = returningMatch.index;
831
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
832
+ }
833
+ function normalizeStatement(stmt) {
834
+ if (typeof stmt === "string") {
835
+ return { kind: "positional", sql: stmt, args: [] };
836
+ }
837
+ const sql = stmt.sql;
838
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
839
+ return { kind: "positional", sql, args: stmt.args ?? [] };
840
+ }
841
+ return { kind: "named", sql, args: stmt.args };
842
+ }
843
+ function rewriteBooleanLiterals(sql) {
844
+ let out = sql;
845
+ for (const column of BOOLEAN_COLUMN_NAMES) {
846
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
847
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
848
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
849
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
850
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
851
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
852
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
853
+ }
854
+ return out;
855
+ }
856
+ function rewriteInsertOrIgnore(sql) {
857
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
858
+ return sql;
859
+ }
860
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
861
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
862
+ }
863
+ function rewriteInsertOrReplace(sql) {
864
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
865
+ if (!match) {
866
+ return sql;
867
+ }
868
+ const rawTable = match[1];
869
+ const rawColumns = match[2];
870
+ const remainder = match[3];
871
+ const tableName = unqualifiedTableName(rawTable);
872
+ const conflictKeys = UPSERT_KEYS[tableName];
873
+ if (!conflictKeys?.length) {
874
+ return sql;
875
+ }
876
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
877
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
878
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
879
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
880
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
881
+ }
882
+ function rewriteSql(sql) {
883
+ let out = sql;
884
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
885
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
886
+ out = rewriteBooleanLiterals(out);
887
+ out = rewriteInsertOrReplace(out);
888
+ out = rewriteInsertOrIgnore(out);
889
+ return stripTrailingSemicolon(out);
890
+ }
891
+ function toBoolean(value) {
892
+ if (value === null || value === void 0) return value;
893
+ if (typeof value === "boolean") return value;
894
+ if (typeof value === "number") return value !== 0;
895
+ if (typeof value === "bigint") return value !== 0n;
896
+ if (typeof value === "string") {
897
+ const normalized = value.trim().toLowerCase();
898
+ if (normalized === "0" || normalized === "false") return false;
899
+ if (normalized === "1" || normalized === "true") return true;
900
+ }
901
+ return Boolean(value);
902
+ }
903
+ function countQuestionMarks(sql, end) {
904
+ let count = 0;
905
+ let inSingle = false;
906
+ let inDouble = false;
907
+ let inLineComment = false;
908
+ let inBlockComment = false;
909
+ for (let i = 0; i < end; i++) {
910
+ const ch = sql[i];
911
+ const next = sql[i + 1];
912
+ if (inLineComment) {
913
+ if (ch === "\n") inLineComment = false;
914
+ continue;
915
+ }
916
+ if (inBlockComment) {
917
+ if (ch === "*" && next === "/") {
918
+ inBlockComment = false;
919
+ i += 1;
920
+ }
921
+ continue;
922
+ }
923
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
924
+ inLineComment = true;
925
+ i += 1;
926
+ continue;
927
+ }
928
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
929
+ inBlockComment = true;
930
+ i += 1;
931
+ continue;
932
+ }
933
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
934
+ inSingle = !inSingle;
935
+ continue;
936
+ }
937
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
938
+ inDouble = !inDouble;
939
+ continue;
940
+ }
941
+ if (!inSingle && !inDouble && ch === "?") {
942
+ count += 1;
943
+ }
944
+ }
945
+ return count;
946
+ }
947
+ function findBooleanPlaceholderIndexes(sql) {
948
+ const indexes = /* @__PURE__ */ new Set();
949
+ for (const column of BOOLEAN_COLUMN_NAMES) {
950
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
951
+ for (const match of sql.matchAll(pattern)) {
952
+ const matchText = match[0];
953
+ const qIndex = match.index + matchText.lastIndexOf("?");
954
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
955
+ }
956
+ }
957
+ return indexes;
958
+ }
959
+ function coerceInsertBooleanArgs(sql, args) {
960
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
961
+ if (!match) return;
962
+ const rawTable = match[1];
963
+ const rawColumns = match[2];
964
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
965
+ if (!boolColumns?.size) return;
966
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
967
+ for (const [index, column] of columns.entries()) {
968
+ if (boolColumns.has(column) && index < args.length) {
969
+ args[index] = toBoolean(args[index]);
970
+ }
971
+ }
972
+ }
973
+ function coerceUpdateBooleanArgs(sql, args) {
974
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
975
+ if (!match) return;
976
+ const rawTable = match[1];
977
+ const setClause = match[2];
978
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
979
+ if (!boolColumns?.size) return;
980
+ const assignments = setClause.split(",");
981
+ let placeholderIndex = 0;
982
+ for (const assignment of assignments) {
983
+ if (!assignment.includes("?")) continue;
984
+ placeholderIndex += 1;
985
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
986
+ if (colMatch && boolColumns.has(colMatch[1])) {
987
+ args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
988
+ }
989
+ }
990
+ }
991
+ function coerceBooleanArgs(sql, args) {
992
+ const nextArgs = [...args];
993
+ coerceInsertBooleanArgs(sql, nextArgs);
994
+ coerceUpdateBooleanArgs(sql, nextArgs);
995
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
996
+ for (const index of placeholderIndexes) {
997
+ if (index > 0 && index <= nextArgs.length) {
998
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
999
+ }
1000
+ }
1001
+ return nextArgs;
1002
+ }
1003
+ function convertQuestionMarksToDollarParams(sql) {
1004
+ let out = "";
1005
+ let placeholder = 0;
1006
+ let inSingle = false;
1007
+ let inDouble = false;
1008
+ let inLineComment = false;
1009
+ let inBlockComment = false;
1010
+ for (let i = 0; i < sql.length; i++) {
1011
+ const ch = sql[i];
1012
+ const next = sql[i + 1];
1013
+ if (inLineComment) {
1014
+ out += ch;
1015
+ if (ch === "\n") inLineComment = false;
1016
+ continue;
1017
+ }
1018
+ if (inBlockComment) {
1019
+ out += ch;
1020
+ if (ch === "*" && next === "/") {
1021
+ out += next;
1022
+ inBlockComment = false;
1023
+ i += 1;
1024
+ }
1025
+ continue;
1026
+ }
1027
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1028
+ out += ch + next;
1029
+ inLineComment = true;
1030
+ i += 1;
1031
+ continue;
1032
+ }
1033
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1034
+ out += ch + next;
1035
+ inBlockComment = true;
1036
+ i += 1;
1037
+ continue;
1038
+ }
1039
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1040
+ inSingle = !inSingle;
1041
+ out += ch;
1042
+ continue;
1043
+ }
1044
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1045
+ inDouble = !inDouble;
1046
+ out += ch;
1047
+ continue;
1048
+ }
1049
+ if (!inSingle && !inDouble && ch === "?") {
1050
+ placeholder += 1;
1051
+ out += `$${placeholder}`;
1052
+ continue;
1053
+ }
1054
+ out += ch;
1055
+ }
1056
+ return out;
1057
+ }
1058
+ function translateStatementForPostgres(stmt) {
1059
+ const normalized = normalizeStatement(stmt);
1060
+ if (normalized.kind === "named") {
1061
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
1062
+ }
1063
+ const rewrittenSql = rewriteSql(normalized.sql);
1064
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
1065
+ return {
1066
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
1067
+ args: coercedArgs
1068
+ };
1069
+ }
1070
+ function shouldBypassPostgres(stmt) {
1071
+ const normalized = normalizeStatement(stmt);
1072
+ if (normalized.kind === "named") {
1073
+ return true;
1074
+ }
1075
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
1076
+ }
1077
+ function shouldFallbackOnError(error) {
1078
+ const message = error instanceof Error ? error.message : String(error);
1079
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
1080
+ }
1081
+ function isReadQuery(sql) {
1082
+ const trimmed = sql.trimStart();
1083
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
1084
+ }
1085
+ function buildRow(row, columns) {
1086
+ const values = columns.map((column) => row[column]);
1087
+ return Object.assign(values, row);
1088
+ }
1089
+ function buildResultSet(rows, rowsAffected = 0) {
1090
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
1091
+ const resultRows = rows.map((row) => buildRow(row, columns));
1092
+ return {
1093
+ columns,
1094
+ columnTypes: columns.map(() => ""),
1095
+ rows: resultRows,
1096
+ rowsAffected,
1097
+ lastInsertRowid: void 0,
1098
+ toJSON() {
1099
+ return {
1100
+ columns,
1101
+ columnTypes: columns.map(() => ""),
1102
+ rows,
1103
+ rowsAffected,
1104
+ lastInsertRowid: void 0
1105
+ };
1106
+ }
1107
+ };
1108
+ }
1109
+ async function loadPrismaClient() {
1110
+ if (!prismaClientPromise) {
1111
+ prismaClientPromise = (async () => {
1112
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
1113
+ if (explicitPath) {
1114
+ const module2 = await import(pathToFileURL(explicitPath).href);
1115
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
1116
+ if (!PrismaClient2) {
1117
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
1118
+ }
1119
+ return new PrismaClient2();
1120
+ }
1121
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path6.join(os5.homedir(), "exe-db");
1122
+ const requireFromExeDb = createRequire(path6.join(exeDbRoot, "package.json"));
1123
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
1124
+ const module = await import(pathToFileURL(prismaEntry).href);
1125
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
1126
+ if (!PrismaClient) {
1127
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
1128
+ }
1129
+ return new PrismaClient();
1130
+ })();
1131
+ }
1132
+ return prismaClientPromise;
1133
+ }
1134
+ async function ensureCompatibilityViews(prisma) {
1135
+ if (!compatibilityBootstrapPromise) {
1136
+ compatibilityBootstrapPromise = (async () => {
1137
+ for (const mapping of VIEW_MAPPINGS) {
1138
+ const relation = mapping.source.replace(/"/g, "");
1139
+ const rows = await prisma.$queryRawUnsafe(
1140
+ "SELECT to_regclass($1) AS regclass",
1141
+ relation
1142
+ );
1143
+ if (!rows[0]?.regclass) {
1144
+ continue;
1145
+ }
1146
+ await prisma.$executeRawUnsafe(
1147
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
1148
+ );
1149
+ }
1150
+ })();
1151
+ }
1152
+ return compatibilityBootstrapPromise;
1153
+ }
1154
+ async function executeOnPrisma(executor, stmt) {
1155
+ const translated = translateStatementForPostgres(stmt);
1156
+ if (isReadQuery(translated.sql)) {
1157
+ const rows = await executor.$queryRawUnsafe(
1158
+ translated.sql,
1159
+ ...translated.args
1160
+ );
1161
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
1162
+ }
1163
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
1164
+ return buildResultSet([], rowsAffected);
1165
+ }
1166
+ function splitSqlStatements(sql) {
1167
+ const parts = [];
1168
+ let current = "";
1169
+ let inSingle = false;
1170
+ let inDouble = false;
1171
+ let inLineComment = false;
1172
+ let inBlockComment = false;
1173
+ for (let i = 0; i < sql.length; i++) {
1174
+ const ch = sql[i];
1175
+ const next = sql[i + 1];
1176
+ if (inLineComment) {
1177
+ current += ch;
1178
+ if (ch === "\n") inLineComment = false;
1179
+ continue;
1180
+ }
1181
+ if (inBlockComment) {
1182
+ current += ch;
1183
+ if (ch === "*" && next === "/") {
1184
+ current += next;
1185
+ inBlockComment = false;
1186
+ i += 1;
1187
+ }
1188
+ continue;
1189
+ }
1190
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1191
+ current += ch + next;
1192
+ inLineComment = true;
1193
+ i += 1;
1194
+ continue;
1195
+ }
1196
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1197
+ current += ch + next;
1198
+ inBlockComment = true;
1199
+ i += 1;
1200
+ continue;
1201
+ }
1202
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1203
+ inSingle = !inSingle;
1204
+ current += ch;
1205
+ continue;
1206
+ }
1207
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1208
+ inDouble = !inDouble;
1209
+ current += ch;
1210
+ continue;
1211
+ }
1212
+ if (!inSingle && !inDouble && ch === ";") {
1213
+ if (current.trim()) {
1214
+ parts.push(current.trim());
1215
+ }
1216
+ current = "";
1217
+ continue;
1218
+ }
1219
+ current += ch;
1220
+ }
1221
+ if (current.trim()) {
1222
+ parts.push(current.trim());
1223
+ }
1224
+ return parts;
1225
+ }
1226
+ async function createPrismaDbAdapter(fallbackClient) {
1227
+ const prisma = await loadPrismaClient();
1228
+ await ensureCompatibilityViews(prisma);
1229
+ let closed = false;
1230
+ let adapter;
1231
+ const fallbackExecute = async (stmt, error) => {
1232
+ if (!fallbackClient) {
1233
+ if (error) throw error;
1234
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
1235
+ }
1236
+ if (error) {
1237
+ process.stderr.write(
1238
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
1239
+ `
1240
+ );
1241
+ }
1242
+ return fallbackClient.execute(stmt);
1243
+ };
1244
+ adapter = {
1245
+ async execute(stmt) {
1246
+ if (shouldBypassPostgres(stmt)) {
1247
+ return fallbackExecute(stmt);
1248
+ }
1249
+ try {
1250
+ return await executeOnPrisma(prisma, stmt);
1251
+ } catch (error) {
1252
+ if (shouldFallbackOnError(error)) {
1253
+ return fallbackExecute(stmt, error);
1254
+ }
1255
+ throw error;
1256
+ }
1257
+ },
1258
+ async batch(stmts, mode) {
1259
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
1260
+ if (!fallbackClient) {
1261
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
1262
+ }
1263
+ return fallbackClient.batch(stmts, mode);
1264
+ }
1265
+ try {
1266
+ if (prisma.$transaction) {
1267
+ return await prisma.$transaction(async (tx) => {
1268
+ const results2 = [];
1269
+ for (const stmt of stmts) {
1270
+ results2.push(await executeOnPrisma(tx, stmt));
1271
+ }
1272
+ return results2;
1273
+ });
1274
+ }
1275
+ const results = [];
1276
+ for (const stmt of stmts) {
1277
+ results.push(await executeOnPrisma(prisma, stmt));
1278
+ }
1279
+ return results;
1280
+ } catch (error) {
1281
+ if (fallbackClient && shouldFallbackOnError(error)) {
1282
+ process.stderr.write(
1283
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
1284
+ `
1285
+ );
1286
+ return fallbackClient.batch(stmts, mode);
1287
+ }
1288
+ throw error;
1289
+ }
1290
+ },
1291
+ async migrate(stmts) {
1292
+ if (fallbackClient) {
1293
+ return fallbackClient.migrate(stmts);
1294
+ }
1295
+ return adapter.batch(stmts, "deferred");
1296
+ },
1297
+ async transaction(mode) {
1298
+ if (!fallbackClient) {
1299
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
1300
+ }
1301
+ return fallbackClient.transaction(mode);
1302
+ },
1303
+ async executeMultiple(sql) {
1304
+ if (fallbackClient && shouldBypassPostgres(sql)) {
1305
+ return fallbackClient.executeMultiple(sql);
1306
+ }
1307
+ for (const statement of splitSqlStatements(sql)) {
1308
+ await adapter.execute(statement);
1309
+ }
1310
+ },
1311
+ async sync() {
1312
+ if (fallbackClient) {
1313
+ return fallbackClient.sync();
1314
+ }
1315
+ return { frame_no: 0, frames_synced: 0 };
1316
+ },
1317
+ close() {
1318
+ closed = true;
1319
+ prismaClientPromise = null;
1320
+ compatibilityBootstrapPromise = null;
1321
+ void prisma.$disconnect?.();
1322
+ },
1323
+ get closed() {
1324
+ return closed;
1325
+ },
1326
+ get protocol() {
1327
+ return "prisma-postgres";
1328
+ }
1329
+ };
1330
+ return adapter;
1331
+ }
1332
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
1333
+ var init_database_adapter = __esm({
1334
+ "src/lib/database-adapter.ts"() {
1335
+ "use strict";
1336
+ VIEW_MAPPINGS = [
1337
+ { view: "memories", source: "memory.memory_records" },
1338
+ { view: "tasks", source: "memory.tasks" },
1339
+ { view: "behaviors", source: "memory.behaviors" },
1340
+ { view: "entities", source: "memory.entities" },
1341
+ { view: "relationships", source: "memory.relationships" },
1342
+ { view: "entity_memories", source: "memory.entity_memories" },
1343
+ { view: "entity_aliases", source: "memory.entity_aliases" },
1344
+ { view: "notifications", source: "memory.notifications" },
1345
+ { view: "messages", source: "memory.messages" },
1346
+ { view: "users", source: "wiki.users" },
1347
+ { view: "workspaces", source: "wiki.workspaces" },
1348
+ { view: "workspace_users", source: "wiki.workspace_users" },
1349
+ { view: "documents", source: "wiki.workspace_documents" },
1350
+ { view: "chats", source: "wiki.workspace_chats" }
1351
+ ];
1352
+ UPSERT_KEYS = {
1353
+ memories: ["id"],
1354
+ tasks: ["id"],
1355
+ behaviors: ["id"],
1356
+ entities: ["id"],
1357
+ relationships: ["id"],
1358
+ entity_aliases: ["alias"],
1359
+ notifications: ["id"],
1360
+ messages: ["id"],
1361
+ users: ["id"],
1362
+ workspaces: ["id"],
1363
+ workspace_users: ["id"],
1364
+ documents: ["id"],
1365
+ chats: ["id"]
1366
+ };
1367
+ BOOLEAN_COLUMNS_BY_TABLE = {
1368
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
1369
+ behaviors: /* @__PURE__ */ new Set(["active"]),
1370
+ notifications: /* @__PURE__ */ new Set(["read"]),
1371
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
1372
+ };
1373
+ BOOLEAN_COLUMN_NAMES = new Set(
1374
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
1375
+ );
1376
+ IMMEDIATE_FALLBACK_PATTERNS = [
1377
+ /\bPRAGMA\b/i,
1378
+ /\bsqlite_master\b/i,
1379
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
1380
+ /\bMATCH\b/i,
1381
+ /\bvector_distance_cos\s*\(/i,
1382
+ /\bjson_extract\s*\(/i,
1383
+ /\bjulianday\s*\(/i,
1384
+ /\bstrftime\s*\(/i,
1385
+ /\blast_insert_rowid\s*\(/i
1386
+ ];
1387
+ prismaClientPromise = null;
1388
+ compatibilityBootstrapPromise = null;
804
1389
  }
805
1390
  });
806
1391
 
807
1392
  // src/lib/exe-daemon-client.ts
808
1393
  import net from "net";
809
- import os5 from "os";
1394
+ import os6 from "os";
810
1395
  import { spawn } from "child_process";
811
1396
  import { randomUUID } from "crypto";
812
1397
  import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
813
- import path6 from "path";
1398
+ import path7 from "path";
814
1399
  import { fileURLToPath as fileURLToPath2 } from "url";
815
1400
  function handleData(chunk) {
816
1401
  _buffer += chunk.toString();
@@ -861,17 +1446,17 @@ function cleanupStaleFiles() {
861
1446
  }
862
1447
  }
863
1448
  function findPackageRoot() {
864
- let dir = path6.dirname(fileURLToPath2(import.meta.url));
865
- const { root } = path6.parse(dir);
1449
+ let dir = path7.dirname(fileURLToPath2(import.meta.url));
1450
+ const { root } = path7.parse(dir);
866
1451
  while (dir !== root) {
867
- if (existsSync6(path6.join(dir, "package.json"))) return dir;
868
- dir = path6.dirname(dir);
1452
+ if (existsSync6(path7.join(dir, "package.json"))) return dir;
1453
+ dir = path7.dirname(dir);
869
1454
  }
870
1455
  return null;
871
1456
  }
872
1457
  function spawnDaemon() {
873
- const freeGB = os5.freemem() / (1024 * 1024 * 1024);
874
- const totalGB = os5.totalmem() / (1024 * 1024 * 1024);
1458
+ const freeGB = os6.freemem() / (1024 * 1024 * 1024);
1459
+ const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
875
1460
  if (totalGB <= 8) {
876
1461
  process.stderr.write(
877
1462
  `[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
@@ -891,7 +1476,7 @@ function spawnDaemon() {
891
1476
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
892
1477
  return;
893
1478
  }
894
- const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1479
+ const daemonPath = path7.join(pkgRoot, "dist", "lib", "exe-daemon.js");
895
1480
  if (!existsSync6(daemonPath)) {
896
1481
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
897
1482
  `);
@@ -900,7 +1485,7 @@ function spawnDaemon() {
900
1485
  const resolvedPath = daemonPath;
901
1486
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
902
1487
  `);
903
- const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
1488
+ const logPath = path7.join(path7.dirname(SOCKET_PATH), "exed.log");
904
1489
  let stderrFd = "ignore";
905
1490
  try {
906
1491
  stderrFd = openSync(logPath, "a");
@@ -1047,9 +1632,9 @@ var init_exe_daemon_client = __esm({
1047
1632
  "src/lib/exe-daemon-client.ts"() {
1048
1633
  "use strict";
1049
1634
  init_config();
1050
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
1051
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
1052
- SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
1635
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path7.join(EXE_AI_DIR, "exed.sock");
1636
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path7.join(EXE_AI_DIR, "exed.pid");
1637
+ SPAWN_LOCK_PATH = path7.join(EXE_AI_DIR, "exed-spawn.lock");
1053
1638
  SPAWN_LOCK_STALE_MS = 3e4;
1054
1639
  CONNECT_TIMEOUT_MS = 15e3;
1055
1640
  REQUEST_TIMEOUT_MS = 3e4;
@@ -1131,7 +1716,7 @@ __export(db_daemon_client_exports, {
1131
1716
  createDaemonDbClient: () => createDaemonDbClient,
1132
1717
  initDaemonDbClient: () => initDaemonDbClient
1133
1718
  });
1134
- function normalizeStatement(stmt) {
1719
+ function normalizeStatement2(stmt) {
1135
1720
  if (typeof stmt === "string") {
1136
1721
  return { sql: stmt, args: [] };
1137
1722
  }
@@ -1155,7 +1740,7 @@ function createDaemonDbClient(fallbackClient) {
1155
1740
  if (!_useDaemon || !isClientConnected()) {
1156
1741
  return fallbackClient.execute(stmt);
1157
1742
  }
1158
- const { sql, args } = normalizeStatement(stmt);
1743
+ const { sql, args } = normalizeStatement2(stmt);
1159
1744
  const response = await sendDaemonRequest({
1160
1745
  type: "db-execute",
1161
1746
  sql,
@@ -1180,7 +1765,7 @@ function createDaemonDbClient(fallbackClient) {
1180
1765
  if (!_useDaemon || !isClientConnected()) {
1181
1766
  return fallbackClient.batch(stmts, mode);
1182
1767
  }
1183
- const statements = stmts.map(normalizeStatement);
1768
+ const statements = stmts.map(normalizeStatement2);
1184
1769
  const response = await sendDaemonRequest({
1185
1770
  type: "db-batch",
1186
1771
  statements,
@@ -1275,6 +1860,18 @@ __export(database_exports, {
1275
1860
  });
1276
1861
  import { createClient } from "@libsql/client";
1277
1862
  async function initDatabase(config) {
1863
+ if (_walCheckpointTimer) {
1864
+ clearInterval(_walCheckpointTimer);
1865
+ _walCheckpointTimer = null;
1866
+ }
1867
+ if (_daemonClient) {
1868
+ _daemonClient.close();
1869
+ _daemonClient = null;
1870
+ }
1871
+ if (_adapterClient && _adapterClient !== _resilientClient) {
1872
+ _adapterClient.close();
1873
+ }
1874
+ _adapterClient = null;
1278
1875
  if (_client) {
1279
1876
  _client.close();
1280
1877
  _client = null;
@@ -1288,6 +1885,7 @@ async function initDatabase(config) {
1288
1885
  }
1289
1886
  _client = createClient(opts);
1290
1887
  _resilientClient = wrapWithRetry(_client);
1888
+ _adapterClient = _resilientClient;
1291
1889
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1292
1890
  });
1293
1891
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -1298,14 +1896,20 @@ async function initDatabase(config) {
1298
1896
  });
1299
1897
  }, 3e4);
1300
1898
  _walCheckpointTimer.unref();
1899
+ if (process.env.DATABASE_URL) {
1900
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
1901
+ }
1301
1902
  }
1302
1903
  function isInitialized() {
1303
- return _client !== null;
1904
+ return _adapterClient !== null || _client !== null;
1304
1905
  }
1305
1906
  function getClient() {
1306
- if (!_resilientClient) {
1907
+ if (!_adapterClient) {
1307
1908
  throw new Error("Database client not initialized. Call initDatabase() first.");
1308
1909
  }
1910
+ if (process.env.DATABASE_URL) {
1911
+ return _adapterClient;
1912
+ }
1309
1913
  if (process.env.EXE_IS_DAEMON === "1") {
1310
1914
  return _resilientClient;
1311
1915
  }
@@ -1315,6 +1919,7 @@ function getClient() {
1315
1919
  return _resilientClient;
1316
1920
  }
1317
1921
  async function initDaemonClient() {
1922
+ if (process.env.DATABASE_URL) return;
1318
1923
  if (process.env.EXE_IS_DAEMON === "1") return;
1319
1924
  if (!_resilientClient) return;
1320
1925
  try {
@@ -2259,26 +2864,36 @@ async function ensureSchema() {
2259
2864
  }
2260
2865
  }
2261
2866
  async function disposeDatabase() {
2867
+ if (_walCheckpointTimer) {
2868
+ clearInterval(_walCheckpointTimer);
2869
+ _walCheckpointTimer = null;
2870
+ }
2262
2871
  if (_daemonClient) {
2263
2872
  _daemonClient.close();
2264
2873
  _daemonClient = null;
2265
2874
  }
2875
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2876
+ _adapterClient.close();
2877
+ }
2878
+ _adapterClient = null;
2266
2879
  if (_client) {
2267
2880
  _client.close();
2268
2881
  _client = null;
2269
2882
  _resilientClient = null;
2270
2883
  }
2271
2884
  }
2272
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
2885
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
2273
2886
  var init_database = __esm({
2274
2887
  "src/lib/database.ts"() {
2275
2888
  "use strict";
2276
2889
  init_db_retry();
2277
2890
  init_employees();
2891
+ init_database_adapter();
2278
2892
  _client = null;
2279
2893
  _resilientClient = null;
2280
2894
  _walCheckpointTimer = null;
2281
2895
  _daemonClient = null;
2896
+ _adapterClient = null;
2282
2897
  initTurso = initDatabase;
2283
2898
  disposeTurso = disposeDatabase;
2284
2899
  }
@@ -2287,16 +2902,16 @@ var init_database = __esm({
2287
2902
  // src/lib/license.ts
2288
2903
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
2289
2904
  import { randomUUID as randomUUID2 } from "crypto";
2290
- import path7 from "path";
2905
+ import path8 from "path";
2291
2906
  import { jwtVerify, importSPKI } from "jose";
2292
2907
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
2293
2908
  var init_license = __esm({
2294
2909
  "src/lib/license.ts"() {
2295
2910
  "use strict";
2296
2911
  init_config();
2297
- LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
2298
- CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
2299
- DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
2912
+ LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
2913
+ CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
2914
+ DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
2300
2915
  PLAN_LIMITS = {
2301
2916
  free: { devices: 1, employees: 1, memories: 5e3 },
2302
2917
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -2309,7 +2924,7 @@ var init_license = __esm({
2309
2924
 
2310
2925
  // src/lib/plan-limits.ts
2311
2926
  import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
2312
- import path8 from "path";
2927
+ import path9 from "path";
2313
2928
  function getLicenseSync() {
2314
2929
  try {
2315
2930
  if (!existsSync8(CACHE_PATH2)) return freeLicense();
@@ -2381,14 +2996,14 @@ var init_plan_limits = __esm({
2381
2996
  this.name = "PlanLimitError";
2382
2997
  }
2383
2998
  };
2384
- CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
2999
+ CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
2385
3000
  }
2386
3001
  });
2387
3002
 
2388
3003
  // src/lib/notifications.ts
2389
3004
  import crypto from "crypto";
2390
- import path9 from "path";
2391
- import os6 from "os";
3005
+ import path10 from "path";
3006
+ import os7 from "os";
2392
3007
  import {
2393
3008
  readFileSync as readFileSync9,
2394
3009
  readdirSync,
@@ -2528,8 +3143,8 @@ var init_state_bus = __esm({
2528
3143
 
2529
3144
  // src/lib/tasks-crud.ts
2530
3145
  import crypto3 from "crypto";
2531
- import path10 from "path";
2532
- import os7 from "os";
3146
+ import path11 from "path";
3147
+ import os8 from "os";
2533
3148
  import { execSync as execSync4 } from "child_process";
2534
3149
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2535
3150
  import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
@@ -2707,8 +3322,8 @@ ${laneWarning}` : laneWarning;
2707
3322
  }
2708
3323
  if (input.baseDir) {
2709
3324
  try {
2710
- await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
2711
- await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
3325
+ await mkdir3(path11.join(input.baseDir, "exe", "output"), { recursive: true });
3326
+ await mkdir3(path11.join(input.baseDir, "exe", "research"), { recursive: true });
2712
3327
  await ensureArchitectureDoc(input.baseDir, input.projectName);
2713
3328
  await ensureGitignoreExe(input.baseDir);
2714
3329
  } catch {
@@ -2744,9 +3359,9 @@ ${laneWarning}` : laneWarning;
2744
3359
  });
2745
3360
  if (input.baseDir) {
2746
3361
  try {
2747
- const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
2748
- const mdPath = path10.join(EXE_OS_DIR, taskFile);
2749
- const mdDir = path10.dirname(mdPath);
3362
+ const EXE_OS_DIR = path11.join(os8.homedir(), ".exe-os");
3363
+ const mdPath = path11.join(EXE_OS_DIR, taskFile);
3364
+ const mdDir = path11.dirname(mdPath);
2750
3365
  if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
2751
3366
  const reviewer = input.reviewer ?? input.assignedBy;
2752
3367
  const mdContent = `# ${input.title}
@@ -3047,7 +3662,7 @@ async function deleteTaskCore(taskId, _baseDir) {
3047
3662
  return { taskFile, assignedTo, assignedBy, taskSlug };
3048
3663
  }
3049
3664
  async function ensureArchitectureDoc(baseDir, projectName) {
3050
- const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
3665
+ const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
3051
3666
  try {
3052
3667
  if (existsSync10(archPath)) return;
3053
3668
  const template = [
@@ -3082,7 +3697,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
3082
3697
  }
3083
3698
  }
3084
3699
  async function ensureGitignoreExe(baseDir) {
3085
- const gitignorePath = path10.join(baseDir, ".gitignore");
3700
+ const gitignorePath = path11.join(baseDir, ".gitignore");
3086
3701
  try {
3087
3702
  if (existsSync10(gitignorePath)) {
3088
3703
  const content = readFileSync10(gitignorePath, "utf-8");
@@ -3116,13 +3731,13 @@ var init_tasks_crud = __esm({
3116
3731
  });
3117
3732
 
3118
3733
  // src/lib/tasks-review.ts
3119
- import path11 from "path";
3734
+ import path12 from "path";
3120
3735
  import { existsSync as existsSync11, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
3121
3736
  async function countPendingReviews(sessionScope) {
3122
3737
  const client = getClient();
3123
3738
  if (sessionScope) {
3124
3739
  const result2 = await client.execute({
3125
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
3740
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
3126
3741
  args: [sessionScope]
3127
3742
  });
3128
3743
  return Number(result2.rows[0]?.cnt) || 0;
@@ -3298,11 +3913,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
3298
3913
  );
3299
3914
  }
3300
3915
  try {
3301
- const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
3916
+ const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
3302
3917
  if (existsSync11(cacheDir)) {
3303
3918
  for (const f of readdirSync2(cacheDir)) {
3304
3919
  if (f.startsWith("review-notified-")) {
3305
- unlinkSync4(path11.join(cacheDir, f));
3920
+ unlinkSync4(path12.join(cacheDir, f));
3306
3921
  }
3307
3922
  }
3308
3923
  }
@@ -3323,7 +3938,7 @@ var init_tasks_review = __esm({
3323
3938
  });
3324
3939
 
3325
3940
  // src/lib/tasks-chain.ts
3326
- import path12 from "path";
3941
+ import path13 from "path";
3327
3942
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
3328
3943
  async function cascadeUnblock(taskId, baseDir, now) {
3329
3944
  const client = getClient();
@@ -3340,7 +3955,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
3340
3955
  });
3341
3956
  for (const ur of unblockedRows.rows) {
3342
3957
  try {
3343
- const ubFile = path12.join(baseDir, String(ur.task_file));
3958
+ const ubFile = path13.join(baseDir, String(ur.task_file));
3344
3959
  let ubContent = await readFile3(ubFile, "utf-8");
3345
3960
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
3346
3961
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -3414,7 +4029,7 @@ __export(project_name_exports, {
3414
4029
  getProjectName: () => getProjectName
3415
4030
  });
3416
4031
  import { execSync as execSync5 } from "child_process";
3417
- import path13 from "path";
4032
+ import path14 from "path";
3418
4033
  function getProjectName(cwd) {
3419
4034
  const dir = cwd ?? process.cwd();
3420
4035
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -3427,7 +4042,7 @@ function getProjectName(cwd) {
3427
4042
  timeout: 2e3,
3428
4043
  stdio: ["pipe", "pipe", "pipe"]
3429
4044
  }).trim();
3430
- repoRoot = path13.dirname(gitCommonDir);
4045
+ repoRoot = path14.dirname(gitCommonDir);
3431
4046
  } catch {
3432
4047
  repoRoot = execSync5("git rev-parse --show-toplevel", {
3433
4048
  cwd: dir,
@@ -3436,11 +4051,11 @@ function getProjectName(cwd) {
3436
4051
  stdio: ["pipe", "pipe", "pipe"]
3437
4052
  }).trim();
3438
4053
  }
3439
- _cached2 = path13.basename(repoRoot);
4054
+ _cached2 = path14.basename(repoRoot);
3440
4055
  _cachedCwd = dir;
3441
4056
  return _cached2;
3442
4057
  } catch {
3443
- _cached2 = path13.basename(dir);
4058
+ _cached2 = path14.basename(dir);
3444
4059
  _cachedCwd = dir;
3445
4060
  return _cached2;
3446
4061
  }
@@ -3917,7 +4532,7 @@ __export(tasks_exports, {
3917
4532
  updateTaskStatus: () => updateTaskStatus,
3918
4533
  writeCheckpoint: () => writeCheckpoint
3919
4534
  });
3920
- import path14 from "path";
4535
+ import path15 from "path";
3921
4536
  import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5 } from "fs";
3922
4537
  async function createTask(input) {
3923
4538
  const result = await createTaskCore(input);
@@ -3937,8 +4552,8 @@ async function updateTask(input) {
3937
4552
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
3938
4553
  try {
3939
4554
  const agent = String(row.assigned_to);
3940
- const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
3941
- const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
4555
+ const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
4556
+ const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
3942
4557
  if (input.status === "in_progress") {
3943
4558
  mkdirSync5(cacheDir, { recursive: true });
3944
4559
  writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -4409,12 +5024,12 @@ __export(tmux_routing_exports, {
4409
5024
  });
4410
5025
  import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
4411
5026
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync, readdirSync as readdirSync3 } from "fs";
4412
- import path15 from "path";
4413
- import os8 from "os";
5027
+ import path16 from "path";
5028
+ import os9 from "os";
4414
5029
  import { fileURLToPath as fileURLToPath3 } from "url";
4415
5030
  import { unlinkSync as unlinkSync6 } from "fs";
4416
5031
  function spawnLockPath(sessionName) {
4417
- return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
5032
+ return path16.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
4418
5033
  }
4419
5034
  function isProcessAlive(pid) {
4420
5035
  try {
@@ -4451,8 +5066,8 @@ function releaseSpawnLock2(sessionName) {
4451
5066
  function resolveBehaviorsExporterScript() {
4452
5067
  try {
4453
5068
  const thisFile = fileURLToPath3(import.meta.url);
4454
- const scriptPath = path15.join(
4455
- path15.dirname(thisFile),
5069
+ const scriptPath = path16.join(
5070
+ path16.dirname(thisFile),
4456
5071
  "..",
4457
5072
  "bin",
4458
5073
  "exe-export-behaviors.js"
@@ -4527,7 +5142,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
4527
5142
  mkdirSync6(SESSION_CACHE, { recursive: true });
4528
5143
  }
4529
5144
  const rootExe = extractRootExe(parentExe) ?? parentExe;
4530
- const filePath = path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
5145
+ const filePath = path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
4531
5146
  writeFileSync7(filePath, JSON.stringify({
4532
5147
  parentExe: rootExe,
4533
5148
  dispatchedBy: dispatchedBy || rootExe,
@@ -4536,7 +5151,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
4536
5151
  }
4537
5152
  function getParentExe(sessionKey) {
4538
5153
  try {
4539
- const data = JSON.parse(readFileSync11(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
5154
+ const data = JSON.parse(readFileSync11(path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
4540
5155
  return data.parentExe || null;
4541
5156
  } catch {
4542
5157
  return null;
@@ -4545,7 +5160,7 @@ function getParentExe(sessionKey) {
4545
5160
  function getDispatchedBy(sessionKey) {
4546
5161
  try {
4547
5162
  const data = JSON.parse(readFileSync11(
4548
- path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
5163
+ path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
4549
5164
  "utf8"
4550
5165
  ));
4551
5166
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -4731,7 +5346,7 @@ function sendIntercom(targetSession) {
4731
5346
  try {
4732
5347
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
4733
5348
  const agent = baseAgentName(rawAgent);
4734
- const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
5349
+ const markerPath = path16.join(SESSION_CACHE, `current-task-${agent}.json`);
4735
5350
  if (existsSync12(markerPath)) {
4736
5351
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
4737
5352
  return "debounced";
@@ -4741,7 +5356,7 @@ function sendIntercom(targetSession) {
4741
5356
  try {
4742
5357
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
4743
5358
  const agent = baseAgentName(rawAgent);
4744
- const taskDir = path15.join(process.cwd(), "exe", agent);
5359
+ const taskDir = path16.join(process.cwd(), "exe", agent);
4745
5360
  if (existsSync12(taskDir)) {
4746
5361
  const files = readdirSync3(taskDir).filter(
4747
5362
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -4875,8 +5490,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4875
5490
  const transport = getTransport();
4876
5491
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
4877
5492
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
4878
- const logDir = path15.join(os8.homedir(), ".exe-os", "session-logs");
4879
- const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5493
+ const logDir = path16.join(os9.homedir(), ".exe-os", "session-logs");
5494
+ const logFile = path16.join(logDir, `${instanceLabel}-${Date.now()}.log`);
4880
5495
  if (!existsSync12(logDir)) {
4881
5496
  mkdirSync6(logDir, { recursive: true });
4882
5497
  }
@@ -4884,14 +5499,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4884
5499
  let cleanupSuffix = "";
4885
5500
  try {
4886
5501
  const thisFile = fileURLToPath3(import.meta.url);
4887
- const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
5502
+ const cleanupScript = path16.join(path16.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
4888
5503
  if (existsSync12(cleanupScript)) {
4889
5504
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
4890
5505
  }
4891
5506
  } catch {
4892
5507
  }
4893
5508
  try {
4894
- const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
5509
+ const claudeJsonPath = path16.join(os9.homedir(), ".claude.json");
4895
5510
  let claudeJson = {};
4896
5511
  try {
4897
5512
  claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
@@ -4906,10 +5521,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4906
5521
  } catch {
4907
5522
  }
4908
5523
  try {
4909
- const settingsDir = path15.join(os8.homedir(), ".claude", "projects");
5524
+ const settingsDir = path16.join(os9.homedir(), ".claude", "projects");
4910
5525
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
4911
- const projSettingsDir = path15.join(settingsDir, normalizedKey);
4912
- const settingsPath = path15.join(projSettingsDir, "settings.json");
5526
+ const projSettingsDir = path16.join(settingsDir, normalizedKey);
5527
+ const settingsPath = path16.join(projSettingsDir, "settings.json");
4913
5528
  let settings = {};
4914
5529
  try {
4915
5530
  settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
@@ -4956,8 +5571,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4956
5571
  let behaviorsFlag = "";
4957
5572
  let legacyFallbackWarned = false;
4958
5573
  if (!useExeAgent && !useBinSymlink) {
4959
- const identityPath = path15.join(
4960
- os8.homedir(),
5574
+ const identityPath = path16.join(
5575
+ os9.homedir(),
4961
5576
  ".exe-os",
4962
5577
  "identity",
4963
5578
  `${employeeName}.md`
@@ -4972,7 +5587,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4972
5587
  }
4973
5588
  const behaviorsFile = exportBehaviorsSync(
4974
5589
  employeeName,
4975
- path15.basename(spawnCwd),
5590
+ path16.basename(spawnCwd),
4976
5591
  sessionName
4977
5592
  );
4978
5593
  if (behaviorsFile) {
@@ -4987,9 +5602,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4987
5602
  }
4988
5603
  let sessionContextFlag = "";
4989
5604
  try {
4990
- const ctxDir = path15.join(os8.homedir(), ".exe-os", "session-cache");
5605
+ const ctxDir = path16.join(os9.homedir(), ".exe-os", "session-cache");
4991
5606
  mkdirSync6(ctxDir, { recursive: true });
4992
- const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
5607
+ const ctxFile = path16.join(ctxDir, `session-context-${sessionName}.md`);
4993
5608
  const ctxContent = [
4994
5609
  `## Session Context`,
4995
5610
  `You are running in tmux session: ${sessionName}.`,
@@ -5073,7 +5688,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5073
5688
  transport.pipeLog(sessionName, logFile);
5074
5689
  try {
5075
5690
  const mySession = getMySession();
5076
- const dispatchInfo = path15.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
5691
+ const dispatchInfo = path16.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
5077
5692
  writeFileSync7(dispatchInfo, JSON.stringify({
5078
5693
  dispatchedBy: mySession,
5079
5694
  rootExe: exeSession,
@@ -5148,15 +5763,15 @@ var init_tmux_routing = __esm({
5148
5763
  init_intercom_queue();
5149
5764
  init_plan_limits();
5150
5765
  init_employees();
5151
- SPAWN_LOCK_DIR = path15.join(os8.homedir(), ".exe-os", "spawn-locks");
5152
- SESSION_CACHE = path15.join(os8.homedir(), ".exe-os", "session-cache");
5766
+ SPAWN_LOCK_DIR = path16.join(os9.homedir(), ".exe-os", "spawn-locks");
5767
+ SESSION_CACHE = path16.join(os9.homedir(), ".exe-os", "session-cache");
5153
5768
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5154
5769
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
5155
5770
  VERIFY_PANE_LINES = 200;
5156
5771
  INTERCOM_DEBOUNCE_MS = 3e4;
5157
5772
  CODEX_DEBOUNCE_MS = 12e4;
5158
- INTERCOM_LOG2 = path15.join(os8.homedir(), ".exe-os", "intercom.log");
5159
- DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
5773
+ INTERCOM_LOG2 = path16.join(os9.homedir(), ".exe-os", "intercom.log");
5774
+ DEBOUNCE_FILE = path16.join(SESSION_CACHE, "intercom-debounce.json");
5160
5775
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
5161
5776
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
5162
5777
  }
@@ -5198,13 +5813,13 @@ var init_memory = __esm({
5198
5813
  // src/lib/keychain.ts
5199
5814
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
5200
5815
  import { existsSync as existsSync13 } from "fs";
5201
- import path16 from "path";
5202
- import os9 from "os";
5816
+ import path17 from "path";
5817
+ import os10 from "os";
5203
5818
  function getKeyDir() {
5204
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path16.join(os9.homedir(), ".exe-os");
5819
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path17.join(os10.homedir(), ".exe-os");
5205
5820
  }
5206
5821
  function getKeyPath() {
5207
- return path16.join(getKeyDir(), "master.key");
5822
+ return path17.join(getKeyDir(), "master.key");
5208
5823
  }
5209
5824
  async function tryKeytar() {
5210
5825
  try {
@@ -5227,7 +5842,7 @@ async function getMasterKey() {
5227
5842
  const keyPath = getKeyPath();
5228
5843
  if (!existsSync13(keyPath)) {
5229
5844
  process.stderr.write(
5230
- `[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5845
+ `[keychain] Key not found at ${keyPath} (HOME=${os10.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5231
5846
  `
5232
5847
  );
5233
5848
  return null;
@@ -5265,7 +5880,7 @@ __export(shard_manager_exports, {
5265
5880
  listShards: () => listShards,
5266
5881
  shardExists: () => shardExists
5267
5882
  });
5268
- import path17 from "path";
5883
+ import path18 from "path";
5269
5884
  import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync4 } from "fs";
5270
5885
  import { createClient as createClient2 } from "@libsql/client";
5271
5886
  function initShardManager(encryptionKey) {
@@ -5291,7 +5906,7 @@ function getShardClient(projectName) {
5291
5906
  }
5292
5907
  const cached = _shards.get(safeName);
5293
5908
  if (cached) return cached;
5294
- const dbPath = path17.join(SHARDS_DIR, `${safeName}.db`);
5909
+ const dbPath = path18.join(SHARDS_DIR, `${safeName}.db`);
5295
5910
  const client = createClient2({
5296
5911
  url: `file:${dbPath}`,
5297
5912
  encryptionKey: _encryptionKey
@@ -5301,7 +5916,7 @@ function getShardClient(projectName) {
5301
5916
  }
5302
5917
  function shardExists(projectName) {
5303
5918
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
5304
- return existsSync14(path17.join(SHARDS_DIR, `${safeName}.db`));
5919
+ return existsSync14(path18.join(SHARDS_DIR, `${safeName}.db`));
5305
5920
  }
5306
5921
  function listShards() {
5307
5922
  if (!existsSync14(SHARDS_DIR)) return [];
@@ -5378,7 +5993,23 @@ async function ensureShardSchema(client) {
5378
5993
  // MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
5379
5994
  "ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
5380
5995
  "ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
5381
- "ALTER TABLE memories ADD COLUMN trajectory TEXT"
5996
+ "ALTER TABLE memories ADD COLUMN trajectory TEXT",
5997
+ // Metadata enrichment columns (must match database.ts)
5998
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
5999
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
6000
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
6001
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
6002
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
6003
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
6004
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
6005
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
6006
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
6007
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
6008
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
6009
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
6010
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
6011
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
6012
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
5382
6013
  ]) {
5383
6014
  try {
5384
6015
  await client.execute(col);
@@ -5490,7 +6121,7 @@ var init_shard_manager = __esm({
5490
6121
  "src/lib/shard-manager.ts"() {
5491
6122
  "use strict";
5492
6123
  init_config();
5493
- SHARDS_DIR = path17.join(EXE_AI_DIR, "shards");
6124
+ SHARDS_DIR = path18.join(EXE_AI_DIR, "shards");
5494
6125
  _shards = /* @__PURE__ */ new Map();
5495
6126
  _encryptionKey = null;
5496
6127
  _shardingEnabled = false;
@@ -6256,8 +6887,8 @@ var init_store = __esm({
6256
6887
 
6257
6888
  // src/bin/scan-tasks.ts
6258
6889
  import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
6259
- import path18 from "path";
6260
- import os10 from "os";
6890
+ import path19 from "path";
6891
+ import os11 from "os";
6261
6892
 
6262
6893
  // src/lib/is-main.ts
6263
6894
  import { realpathSync } from "fs";
@@ -6277,13 +6908,13 @@ function isMainModule(importMetaUrl) {
6277
6908
  // src/bin/scan-tasks.ts
6278
6909
  init_session_key();
6279
6910
  init_task_scope();
6280
- function getMcpHealthWarning(runtime = getSessionRuntime(), homeDir = os10.homedir()) {
6911
+ function getMcpHealthWarning(runtime = getSessionRuntime(), homeDir = os11.homedir()) {
6281
6912
  if (runtime === "codex") {
6282
6913
  return null;
6283
6914
  }
6284
6915
  try {
6285
6916
  if (runtime === "opencode") {
6286
- const opencodeJson = path18.join(homeDir, ".config", "opencode", "opencode.json");
6917
+ const opencodeJson = path19.join(homeDir, ".config", "opencode", "opencode.json");
6287
6918
  if (!existsSync15(opencodeJson)) {
6288
6919
  return "\u26A0\uFE0F MCP config missing (~/.config/opencode/opencode.json not found) \u2014 exe-os task tools may be unavailable. Run `exe-os opencode`.\n";
6289
6920
  }
@@ -6293,7 +6924,7 @@ function getMcpHealthWarning(runtime = getSessionRuntime(), homeDir = os10.homed
6293
6924
  }
6294
6925
  return null;
6295
6926
  }
6296
- const claudeJson = path18.join(homeDir, ".claude.json");
6927
+ const claudeJson = path19.join(homeDir, ".claude.json");
6297
6928
  if (!existsSync15(claudeJson)) {
6298
6929
  return "\u26A0\uFE0F MCP config missing (~/.claude.json not found) \u2014 close_task won't work. Run /exe-setup\n";
6299
6930
  }
@@ -6462,7 +7093,7 @@ async function main() {
6462
7093
  if (out) tmuxSession = out;
6463
7094
  } catch {
6464
7095
  }
6465
- const result = await scanFromDb(agentId, tmuxSession);
7096
+ const result = await scanFromDb(agentId, tmuxSession, null);
6466
7097
  switch (format) {
6467
7098
  case "json":
6468
7099
  console.log(formatJson(result));