@askexenow/exe-os 0.9.6 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/bin/backfill-conversations.js +754 -79
  2. package/dist/bin/backfill-responses.js +752 -77
  3. package/dist/bin/backfill-vectors.js +752 -77
  4. package/dist/bin/cleanup-stale-review-tasks.js +668 -37
  5. package/dist/bin/cli.js +1399 -607
  6. package/dist/bin/exe-agent-config.js +123 -95
  7. package/dist/bin/exe-agent.js +41 -25
  8. package/dist/bin/exe-assign.js +732 -57
  9. package/dist/bin/exe-boot.js +795 -155
  10. package/dist/bin/exe-call.js +209 -138
  11. package/dist/bin/exe-cloud.js +35 -12
  12. package/dist/bin/exe-dispatch.js +703 -72
  13. package/dist/bin/exe-doctor.js +648 -26
  14. package/dist/bin/exe-export-behaviors.js +650 -20
  15. package/dist/bin/exe-forget.js +635 -13
  16. package/dist/bin/exe-gateway.js +1064 -273
  17. package/dist/bin/exe-heartbeat.js +676 -45
  18. package/dist/bin/exe-kill.js +646 -16
  19. package/dist/bin/exe-launch-agent.js +887 -97
  20. package/dist/bin/exe-link.js +658 -43
  21. package/dist/bin/exe-new-employee.js +378 -177
  22. package/dist/bin/exe-pending-messages.js +656 -34
  23. package/dist/bin/exe-pending-notifications.js +635 -13
  24. package/dist/bin/exe-pending-reviews.js +659 -37
  25. package/dist/bin/exe-rename.js +645 -30
  26. package/dist/bin/exe-review.js +635 -13
  27. package/dist/bin/exe-search.js +771 -88
  28. package/dist/bin/exe-session-cleanup.js +845 -152
  29. package/dist/bin/exe-settings.js +127 -91
  30. package/dist/bin/exe-start-codex.js +729 -94
  31. package/dist/bin/exe-start-opencode.js +717 -82
  32. package/dist/bin/exe-status.js +668 -37
  33. package/dist/bin/exe-team.js +635 -13
  34. package/dist/bin/git-sweep.js +731 -91
  35. package/dist/bin/graph-backfill.js +643 -13
  36. package/dist/bin/graph-export.js +646 -16
  37. package/dist/bin/install.js +596 -193
  38. package/dist/bin/scan-tasks.js +735 -95
  39. package/dist/bin/setup.js +1038 -210
  40. package/dist/bin/shard-migrate.js +645 -15
  41. package/dist/bin/wiki-sync.js +646 -16
  42. package/dist/gateway/index.js +1038 -247
  43. package/dist/hooks/bug-report-worker.js +902 -172
  44. package/dist/hooks/commit-complete.js +729 -89
  45. package/dist/hooks/error-recall.js +776 -93
  46. package/dist/hooks/exe-heartbeat-hook.js +85 -71
  47. package/dist/hooks/ingest-worker.js +851 -158
  48. package/dist/hooks/ingest.js +90 -73
  49. package/dist/hooks/instructions-loaded.js +669 -38
  50. package/dist/hooks/notification.js +661 -30
  51. package/dist/hooks/post-compact.js +685 -45
  52. package/dist/hooks/pre-compact.js +729 -89
  53. package/dist/hooks/pre-tool-use.js +883 -127
  54. package/dist/hooks/prompt-ingest-worker.js +758 -83
  55. package/dist/hooks/prompt-submit.js +1071 -321
  56. package/dist/hooks/response-ingest-worker.js +758 -83
  57. package/dist/hooks/session-end.js +732 -92
  58. package/dist/hooks/session-start.js +1042 -209
  59. package/dist/hooks/stop.js +691 -51
  60. package/dist/hooks/subagent-stop.js +685 -45
  61. package/dist/hooks/summary-worker.js +827 -134
  62. package/dist/index.js +1026 -234
  63. package/dist/lib/cloud-sync.js +663 -48
  64. package/dist/lib/consolidation.js +26 -3
  65. package/dist/lib/database.js +626 -18
  66. package/dist/lib/db.js +2261 -0
  67. package/dist/lib/device-registry.js +640 -25
  68. package/dist/lib/embedder.js +96 -43
  69. package/dist/lib/employee-templates.js +16 -0
  70. package/dist/lib/employees.js +259 -83
  71. package/dist/lib/exe-daemon-client.js +101 -63
  72. package/dist/lib/exe-daemon.js +905 -164
  73. package/dist/lib/hybrid-search.js +771 -88
  74. package/dist/lib/identity.js +27 -7
  75. package/dist/lib/messaging.js +66 -30
  76. package/dist/lib/reminders.js +21 -1
  77. package/dist/lib/schedules.js +636 -14
  78. package/dist/lib/skill-learning.js +21 -1
  79. package/dist/lib/store.js +643 -13
  80. package/dist/lib/task-router.js +82 -71
  81. package/dist/lib/tasks.js +109 -73
  82. package/dist/lib/tmux-routing.js +98 -62
  83. package/dist/lib/token-spend.js +26 -6
  84. package/dist/mcp/server.js +1807 -472
  85. package/dist/mcp/tools/complete-reminder.js +21 -1
  86. package/dist/mcp/tools/create-reminder.js +21 -1
  87. package/dist/mcp/tools/create-task.js +301 -166
  88. package/dist/mcp/tools/deactivate-behavior.js +24 -4
  89. package/dist/mcp/tools/list-reminders.js +21 -1
  90. package/dist/mcp/tools/list-tasks.js +206 -40
  91. package/dist/mcp/tools/send-message.js +69 -33
  92. package/dist/mcp/tools/update-task.js +86 -50
  93. package/dist/runtime/index.js +731 -91
  94. package/dist/tui/App.js +864 -125
  95. package/package.json +3 -2
@@ -323,7 +323,7 @@ function isMultiInstance(agentName, employees) {
323
323
  if (!emp) return false;
324
324
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
325
325
  }
326
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
326
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
327
327
  var init_employees = __esm({
328
328
  "src/lib/employees.ts"() {
329
329
  "use strict";
@@ -332,6 +332,7 @@ var init_employees = __esm({
332
332
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
333
333
  COORDINATOR_ROLE = "COO";
334
334
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
335
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
335
336
  }
336
337
  });
337
338
 
@@ -791,13 +792,597 @@ var init_db_retry = __esm({
791
792
  }
792
793
  });
793
794
 
795
+ // src/lib/database-adapter.ts
796
+ import os5 from "os";
797
+ import path7 from "path";
798
+ import { createRequire } from "module";
799
+ import { pathToFileURL } from "url";
800
+ function quotedIdentifier(identifier) {
801
+ return `"${identifier.replace(/"/g, '""')}"`;
802
+ }
803
+ function unqualifiedTableName(name) {
804
+ const raw = name.trim().replace(/^"|"$/g, "");
805
+ const parts = raw.split(".");
806
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
807
+ }
808
+ function stripTrailingSemicolon(sql) {
809
+ return sql.trim().replace(/;+\s*$/u, "");
810
+ }
811
+ function appendClause(sql, clause) {
812
+ const trimmed = stripTrailingSemicolon(sql);
813
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
814
+ if (!returningMatch) {
815
+ return `${trimmed}${clause}`;
816
+ }
817
+ const idx = returningMatch.index;
818
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
819
+ }
820
+ function normalizeStatement(stmt) {
821
+ if (typeof stmt === "string") {
822
+ return { kind: "positional", sql: stmt, args: [] };
823
+ }
824
+ const sql = stmt.sql;
825
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
826
+ return { kind: "positional", sql, args: stmt.args ?? [] };
827
+ }
828
+ return { kind: "named", sql, args: stmt.args };
829
+ }
830
+ function rewriteBooleanLiterals(sql) {
831
+ let out = sql;
832
+ for (const column of BOOLEAN_COLUMN_NAMES) {
833
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
834
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
835
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
836
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
837
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
838
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
839
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
840
+ }
841
+ return out;
842
+ }
843
+ function rewriteInsertOrIgnore(sql) {
844
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
845
+ return sql;
846
+ }
847
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
848
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
849
+ }
850
+ function rewriteInsertOrReplace(sql) {
851
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
852
+ if (!match) {
853
+ return sql;
854
+ }
855
+ const rawTable = match[1];
856
+ const rawColumns = match[2];
857
+ const remainder = match[3];
858
+ const tableName = unqualifiedTableName(rawTable);
859
+ const conflictKeys = UPSERT_KEYS[tableName];
860
+ if (!conflictKeys?.length) {
861
+ return sql;
862
+ }
863
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
864
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
865
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
866
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
867
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
868
+ }
869
+ function rewriteSql(sql) {
870
+ let out = sql;
871
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
872
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
873
+ out = rewriteBooleanLiterals(out);
874
+ out = rewriteInsertOrReplace(out);
875
+ out = rewriteInsertOrIgnore(out);
876
+ return stripTrailingSemicolon(out);
877
+ }
878
+ function toBoolean(value) {
879
+ if (value === null || value === void 0) return value;
880
+ if (typeof value === "boolean") return value;
881
+ if (typeof value === "number") return value !== 0;
882
+ if (typeof value === "bigint") return value !== 0n;
883
+ if (typeof value === "string") {
884
+ const normalized = value.trim().toLowerCase();
885
+ if (normalized === "0" || normalized === "false") return false;
886
+ if (normalized === "1" || normalized === "true") return true;
887
+ }
888
+ return Boolean(value);
889
+ }
890
+ function countQuestionMarks(sql, end) {
891
+ let count = 0;
892
+ let inSingle = false;
893
+ let inDouble = false;
894
+ let inLineComment = false;
895
+ let inBlockComment = false;
896
+ for (let i = 0; i < end; i++) {
897
+ const ch = sql[i];
898
+ const next = sql[i + 1];
899
+ if (inLineComment) {
900
+ if (ch === "\n") inLineComment = false;
901
+ continue;
902
+ }
903
+ if (inBlockComment) {
904
+ if (ch === "*" && next === "/") {
905
+ inBlockComment = false;
906
+ i += 1;
907
+ }
908
+ continue;
909
+ }
910
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
911
+ inLineComment = true;
912
+ i += 1;
913
+ continue;
914
+ }
915
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
916
+ inBlockComment = true;
917
+ i += 1;
918
+ continue;
919
+ }
920
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
921
+ inSingle = !inSingle;
922
+ continue;
923
+ }
924
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
925
+ inDouble = !inDouble;
926
+ continue;
927
+ }
928
+ if (!inSingle && !inDouble && ch === "?") {
929
+ count += 1;
930
+ }
931
+ }
932
+ return count;
933
+ }
934
+ function findBooleanPlaceholderIndexes(sql) {
935
+ const indexes = /* @__PURE__ */ new Set();
936
+ for (const column of BOOLEAN_COLUMN_NAMES) {
937
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
938
+ for (const match of sql.matchAll(pattern)) {
939
+ const matchText = match[0];
940
+ const qIndex = match.index + matchText.lastIndexOf("?");
941
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
942
+ }
943
+ }
944
+ return indexes;
945
+ }
946
+ function coerceInsertBooleanArgs(sql, args) {
947
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
948
+ if (!match) return;
949
+ const rawTable = match[1];
950
+ const rawColumns = match[2];
951
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
952
+ if (!boolColumns?.size) return;
953
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
954
+ for (const [index, column] of columns.entries()) {
955
+ if (boolColumns.has(column) && index < args.length) {
956
+ args[index] = toBoolean(args[index]);
957
+ }
958
+ }
959
+ }
960
+ function coerceUpdateBooleanArgs(sql, args) {
961
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
962
+ if (!match) return;
963
+ const rawTable = match[1];
964
+ const setClause = match[2];
965
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
966
+ if (!boolColumns?.size) return;
967
+ const assignments = setClause.split(",");
968
+ let placeholderIndex = 0;
969
+ for (const assignment of assignments) {
970
+ if (!assignment.includes("?")) continue;
971
+ placeholderIndex += 1;
972
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
973
+ if (colMatch && boolColumns.has(colMatch[1])) {
974
+ args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
975
+ }
976
+ }
977
+ }
978
+ function coerceBooleanArgs(sql, args) {
979
+ const nextArgs = [...args];
980
+ coerceInsertBooleanArgs(sql, nextArgs);
981
+ coerceUpdateBooleanArgs(sql, nextArgs);
982
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
983
+ for (const index of placeholderIndexes) {
984
+ if (index > 0 && index <= nextArgs.length) {
985
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
986
+ }
987
+ }
988
+ return nextArgs;
989
+ }
990
+ function convertQuestionMarksToDollarParams(sql) {
991
+ let out = "";
992
+ let placeholder = 0;
993
+ let inSingle = false;
994
+ let inDouble = false;
995
+ let inLineComment = false;
996
+ let inBlockComment = false;
997
+ for (let i = 0; i < sql.length; i++) {
998
+ const ch = sql[i];
999
+ const next = sql[i + 1];
1000
+ if (inLineComment) {
1001
+ out += ch;
1002
+ if (ch === "\n") inLineComment = false;
1003
+ continue;
1004
+ }
1005
+ if (inBlockComment) {
1006
+ out += ch;
1007
+ if (ch === "*" && next === "/") {
1008
+ out += next;
1009
+ inBlockComment = false;
1010
+ i += 1;
1011
+ }
1012
+ continue;
1013
+ }
1014
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1015
+ out += ch + next;
1016
+ inLineComment = true;
1017
+ i += 1;
1018
+ continue;
1019
+ }
1020
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1021
+ out += ch + next;
1022
+ inBlockComment = true;
1023
+ i += 1;
1024
+ continue;
1025
+ }
1026
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1027
+ inSingle = !inSingle;
1028
+ out += ch;
1029
+ continue;
1030
+ }
1031
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1032
+ inDouble = !inDouble;
1033
+ out += ch;
1034
+ continue;
1035
+ }
1036
+ if (!inSingle && !inDouble && ch === "?") {
1037
+ placeholder += 1;
1038
+ out += `$${placeholder}`;
1039
+ continue;
1040
+ }
1041
+ out += ch;
1042
+ }
1043
+ return out;
1044
+ }
1045
+ function translateStatementForPostgres(stmt) {
1046
+ const normalized = normalizeStatement(stmt);
1047
+ if (normalized.kind === "named") {
1048
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
1049
+ }
1050
+ const rewrittenSql = rewriteSql(normalized.sql);
1051
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
1052
+ return {
1053
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
1054
+ args: coercedArgs
1055
+ };
1056
+ }
1057
+ function shouldBypassPostgres(stmt) {
1058
+ const normalized = normalizeStatement(stmt);
1059
+ if (normalized.kind === "named") {
1060
+ return true;
1061
+ }
1062
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
1063
+ }
1064
+ function shouldFallbackOnError(error) {
1065
+ const message = error instanceof Error ? error.message : String(error);
1066
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
1067
+ }
1068
+ function isReadQuery(sql) {
1069
+ const trimmed = sql.trimStart();
1070
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
1071
+ }
1072
+ function buildRow(row, columns) {
1073
+ const values = columns.map((column) => row[column]);
1074
+ return Object.assign(values, row);
1075
+ }
1076
+ function buildResultSet(rows, rowsAffected = 0) {
1077
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
1078
+ const resultRows = rows.map((row) => buildRow(row, columns));
1079
+ return {
1080
+ columns,
1081
+ columnTypes: columns.map(() => ""),
1082
+ rows: resultRows,
1083
+ rowsAffected,
1084
+ lastInsertRowid: void 0,
1085
+ toJSON() {
1086
+ return {
1087
+ columns,
1088
+ columnTypes: columns.map(() => ""),
1089
+ rows,
1090
+ rowsAffected,
1091
+ lastInsertRowid: void 0
1092
+ };
1093
+ }
1094
+ };
1095
+ }
1096
+ async function loadPrismaClient() {
1097
+ if (!prismaClientPromise) {
1098
+ prismaClientPromise = (async () => {
1099
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
1100
+ if (explicitPath) {
1101
+ const module2 = await import(pathToFileURL(explicitPath).href);
1102
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
1103
+ if (!PrismaClient2) {
1104
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
1105
+ }
1106
+ return new PrismaClient2();
1107
+ }
1108
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path7.join(os5.homedir(), "exe-db");
1109
+ const requireFromExeDb = createRequire(path7.join(exeDbRoot, "package.json"));
1110
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
1111
+ const module = await import(pathToFileURL(prismaEntry).href);
1112
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
1113
+ if (!PrismaClient) {
1114
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
1115
+ }
1116
+ return new PrismaClient();
1117
+ })();
1118
+ }
1119
+ return prismaClientPromise;
1120
+ }
1121
+ async function ensureCompatibilityViews(prisma) {
1122
+ if (!compatibilityBootstrapPromise) {
1123
+ compatibilityBootstrapPromise = (async () => {
1124
+ for (const mapping of VIEW_MAPPINGS) {
1125
+ const relation = mapping.source.replace(/"/g, "");
1126
+ const rows = await prisma.$queryRawUnsafe(
1127
+ "SELECT to_regclass($1) AS regclass",
1128
+ relation
1129
+ );
1130
+ if (!rows[0]?.regclass) {
1131
+ continue;
1132
+ }
1133
+ await prisma.$executeRawUnsafe(
1134
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
1135
+ );
1136
+ }
1137
+ })();
1138
+ }
1139
+ return compatibilityBootstrapPromise;
1140
+ }
1141
+ async function executeOnPrisma(executor, stmt) {
1142
+ const translated = translateStatementForPostgres(stmt);
1143
+ if (isReadQuery(translated.sql)) {
1144
+ const rows = await executor.$queryRawUnsafe(
1145
+ translated.sql,
1146
+ ...translated.args
1147
+ );
1148
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
1149
+ }
1150
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
1151
+ return buildResultSet([], rowsAffected);
1152
+ }
1153
+ function splitSqlStatements(sql) {
1154
+ const parts = [];
1155
+ let current = "";
1156
+ let inSingle = false;
1157
+ let inDouble = false;
1158
+ let inLineComment = false;
1159
+ let inBlockComment = false;
1160
+ for (let i = 0; i < sql.length; i++) {
1161
+ const ch = sql[i];
1162
+ const next = sql[i + 1];
1163
+ if (inLineComment) {
1164
+ current += ch;
1165
+ if (ch === "\n") inLineComment = false;
1166
+ continue;
1167
+ }
1168
+ if (inBlockComment) {
1169
+ current += ch;
1170
+ if (ch === "*" && next === "/") {
1171
+ current += next;
1172
+ inBlockComment = false;
1173
+ i += 1;
1174
+ }
1175
+ continue;
1176
+ }
1177
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1178
+ current += ch + next;
1179
+ inLineComment = true;
1180
+ i += 1;
1181
+ continue;
1182
+ }
1183
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1184
+ current += ch + next;
1185
+ inBlockComment = true;
1186
+ i += 1;
1187
+ continue;
1188
+ }
1189
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1190
+ inSingle = !inSingle;
1191
+ current += ch;
1192
+ continue;
1193
+ }
1194
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1195
+ inDouble = !inDouble;
1196
+ current += ch;
1197
+ continue;
1198
+ }
1199
+ if (!inSingle && !inDouble && ch === ";") {
1200
+ if (current.trim()) {
1201
+ parts.push(current.trim());
1202
+ }
1203
+ current = "";
1204
+ continue;
1205
+ }
1206
+ current += ch;
1207
+ }
1208
+ if (current.trim()) {
1209
+ parts.push(current.trim());
1210
+ }
1211
+ return parts;
1212
+ }
1213
+ async function createPrismaDbAdapter(fallbackClient) {
1214
+ const prisma = await loadPrismaClient();
1215
+ await ensureCompatibilityViews(prisma);
1216
+ let closed = false;
1217
+ let adapter;
1218
+ const fallbackExecute = async (stmt, error) => {
1219
+ if (!fallbackClient) {
1220
+ if (error) throw error;
1221
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
1222
+ }
1223
+ if (error) {
1224
+ process.stderr.write(
1225
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
1226
+ `
1227
+ );
1228
+ }
1229
+ return fallbackClient.execute(stmt);
1230
+ };
1231
+ adapter = {
1232
+ async execute(stmt) {
1233
+ if (shouldBypassPostgres(stmt)) {
1234
+ return fallbackExecute(stmt);
1235
+ }
1236
+ try {
1237
+ return await executeOnPrisma(prisma, stmt);
1238
+ } catch (error) {
1239
+ if (shouldFallbackOnError(error)) {
1240
+ return fallbackExecute(stmt, error);
1241
+ }
1242
+ throw error;
1243
+ }
1244
+ },
1245
+ async batch(stmts, mode) {
1246
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
1247
+ if (!fallbackClient) {
1248
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
1249
+ }
1250
+ return fallbackClient.batch(stmts, mode);
1251
+ }
1252
+ try {
1253
+ if (prisma.$transaction) {
1254
+ return await prisma.$transaction(async (tx) => {
1255
+ const results2 = [];
1256
+ for (const stmt of stmts) {
1257
+ results2.push(await executeOnPrisma(tx, stmt));
1258
+ }
1259
+ return results2;
1260
+ });
1261
+ }
1262
+ const results = [];
1263
+ for (const stmt of stmts) {
1264
+ results.push(await executeOnPrisma(prisma, stmt));
1265
+ }
1266
+ return results;
1267
+ } catch (error) {
1268
+ if (fallbackClient && shouldFallbackOnError(error)) {
1269
+ process.stderr.write(
1270
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
1271
+ `
1272
+ );
1273
+ return fallbackClient.batch(stmts, mode);
1274
+ }
1275
+ throw error;
1276
+ }
1277
+ },
1278
+ async migrate(stmts) {
1279
+ if (fallbackClient) {
1280
+ return fallbackClient.migrate(stmts);
1281
+ }
1282
+ return adapter.batch(stmts, "deferred");
1283
+ },
1284
+ async transaction(mode) {
1285
+ if (!fallbackClient) {
1286
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
1287
+ }
1288
+ return fallbackClient.transaction(mode);
1289
+ },
1290
+ async executeMultiple(sql) {
1291
+ if (fallbackClient && shouldBypassPostgres(sql)) {
1292
+ return fallbackClient.executeMultiple(sql);
1293
+ }
1294
+ for (const statement of splitSqlStatements(sql)) {
1295
+ await adapter.execute(statement);
1296
+ }
1297
+ },
1298
+ async sync() {
1299
+ if (fallbackClient) {
1300
+ return fallbackClient.sync();
1301
+ }
1302
+ return { frame_no: 0, frames_synced: 0 };
1303
+ },
1304
+ close() {
1305
+ closed = true;
1306
+ prismaClientPromise = null;
1307
+ compatibilityBootstrapPromise = null;
1308
+ void prisma.$disconnect?.();
1309
+ },
1310
+ get closed() {
1311
+ return closed;
1312
+ },
1313
+ get protocol() {
1314
+ return "prisma-postgres";
1315
+ }
1316
+ };
1317
+ return adapter;
1318
+ }
1319
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
1320
+ var init_database_adapter = __esm({
1321
+ "src/lib/database-adapter.ts"() {
1322
+ "use strict";
1323
+ VIEW_MAPPINGS = [
1324
+ { view: "memories", source: "memory.memory_records" },
1325
+ { view: "tasks", source: "memory.tasks" },
1326
+ { view: "behaviors", source: "memory.behaviors" },
1327
+ { view: "entities", source: "memory.entities" },
1328
+ { view: "relationships", source: "memory.relationships" },
1329
+ { view: "entity_memories", source: "memory.entity_memories" },
1330
+ { view: "entity_aliases", source: "memory.entity_aliases" },
1331
+ { view: "notifications", source: "memory.notifications" },
1332
+ { view: "messages", source: "memory.messages" },
1333
+ { view: "users", source: "wiki.users" },
1334
+ { view: "workspaces", source: "wiki.workspaces" },
1335
+ { view: "workspace_users", source: "wiki.workspace_users" },
1336
+ { view: "documents", source: "wiki.workspace_documents" },
1337
+ { view: "chats", source: "wiki.workspace_chats" }
1338
+ ];
1339
+ UPSERT_KEYS = {
1340
+ memories: ["id"],
1341
+ tasks: ["id"],
1342
+ behaviors: ["id"],
1343
+ entities: ["id"],
1344
+ relationships: ["id"],
1345
+ entity_aliases: ["alias"],
1346
+ notifications: ["id"],
1347
+ messages: ["id"],
1348
+ users: ["id"],
1349
+ workspaces: ["id"],
1350
+ workspace_users: ["id"],
1351
+ documents: ["id"],
1352
+ chats: ["id"]
1353
+ };
1354
+ BOOLEAN_COLUMNS_BY_TABLE = {
1355
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
1356
+ behaviors: /* @__PURE__ */ new Set(["active"]),
1357
+ notifications: /* @__PURE__ */ new Set(["read"]),
1358
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
1359
+ };
1360
+ BOOLEAN_COLUMN_NAMES = new Set(
1361
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
1362
+ );
1363
+ IMMEDIATE_FALLBACK_PATTERNS = [
1364
+ /\bPRAGMA\b/i,
1365
+ /\bsqlite_master\b/i,
1366
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
1367
+ /\bMATCH\b/i,
1368
+ /\bvector_distance_cos\s*\(/i,
1369
+ /\bjson_extract\s*\(/i,
1370
+ /\bjulianday\s*\(/i,
1371
+ /\bstrftime\s*\(/i,
1372
+ /\blast_insert_rowid\s*\(/i
1373
+ ];
1374
+ prismaClientPromise = null;
1375
+ compatibilityBootstrapPromise = null;
1376
+ }
1377
+ });
1378
+
794
1379
  // src/lib/exe-daemon-client.ts
795
1380
  import net from "net";
796
- import os5 from "os";
1381
+ import os6 from "os";
797
1382
  import { spawn } from "child_process";
798
1383
  import { randomUUID } from "crypto";
799
1384
  import { existsSync as existsSync6, unlinkSync as unlinkSync3, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
800
- import path7 from "path";
1385
+ import path8 from "path";
801
1386
  import { fileURLToPath } from "url";
802
1387
  function handleData(chunk) {
803
1388
  _buffer += chunk.toString();
@@ -848,17 +1433,17 @@ function cleanupStaleFiles() {
848
1433
  }
849
1434
  }
850
1435
  function findPackageRoot() {
851
- let dir = path7.dirname(fileURLToPath(import.meta.url));
852
- const { root } = path7.parse(dir);
1436
+ let dir = path8.dirname(fileURLToPath(import.meta.url));
1437
+ const { root } = path8.parse(dir);
853
1438
  while (dir !== root) {
854
- if (existsSync6(path7.join(dir, "package.json"))) return dir;
855
- dir = path7.dirname(dir);
1439
+ if (existsSync6(path8.join(dir, "package.json"))) return dir;
1440
+ dir = path8.dirname(dir);
856
1441
  }
857
1442
  return null;
858
1443
  }
859
1444
  function spawnDaemon() {
860
- const freeGB = os5.freemem() / (1024 * 1024 * 1024);
861
- const totalGB = os5.totalmem() / (1024 * 1024 * 1024);
1445
+ const freeGB = os6.freemem() / (1024 * 1024 * 1024);
1446
+ const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
862
1447
  if (totalGB <= 8) {
863
1448
  process.stderr.write(
864
1449
  `[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
@@ -878,7 +1463,7 @@ function spawnDaemon() {
878
1463
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
879
1464
  return;
880
1465
  }
881
- const daemonPath = path7.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1466
+ const daemonPath = path8.join(pkgRoot, "dist", "lib", "exe-daemon.js");
882
1467
  if (!existsSync6(daemonPath)) {
883
1468
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
884
1469
  `);
@@ -887,7 +1472,7 @@ function spawnDaemon() {
887
1472
  const resolvedPath = daemonPath;
888
1473
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
889
1474
  `);
890
- const logPath = path7.join(path7.dirname(SOCKET_PATH), "exed.log");
1475
+ const logPath = path8.join(path8.dirname(SOCKET_PATH), "exed.log");
891
1476
  let stderrFd = "ignore";
892
1477
  try {
893
1478
  stderrFd = openSync(logPath, "a");
@@ -1034,9 +1619,9 @@ var init_exe_daemon_client = __esm({
1034
1619
  "src/lib/exe-daemon-client.ts"() {
1035
1620
  "use strict";
1036
1621
  init_config();
1037
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path7.join(EXE_AI_DIR, "exed.sock");
1038
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path7.join(EXE_AI_DIR, "exed.pid");
1039
- SPAWN_LOCK_PATH = path7.join(EXE_AI_DIR, "exed-spawn.lock");
1622
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path8.join(EXE_AI_DIR, "exed.sock");
1623
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path8.join(EXE_AI_DIR, "exed.pid");
1624
+ SPAWN_LOCK_PATH = path8.join(EXE_AI_DIR, "exed-spawn.lock");
1040
1625
  SPAWN_LOCK_STALE_MS = 3e4;
1041
1626
  CONNECT_TIMEOUT_MS = 15e3;
1042
1627
  REQUEST_TIMEOUT_MS = 3e4;
@@ -1118,7 +1703,7 @@ __export(db_daemon_client_exports, {
1118
1703
  createDaemonDbClient: () => createDaemonDbClient,
1119
1704
  initDaemonDbClient: () => initDaemonDbClient
1120
1705
  });
1121
- function normalizeStatement(stmt) {
1706
+ function normalizeStatement2(stmt) {
1122
1707
  if (typeof stmt === "string") {
1123
1708
  return { sql: stmt, args: [] };
1124
1709
  }
@@ -1142,7 +1727,7 @@ function createDaemonDbClient(fallbackClient) {
1142
1727
  if (!_useDaemon || !isClientConnected()) {
1143
1728
  return fallbackClient.execute(stmt);
1144
1729
  }
1145
- const { sql, args } = normalizeStatement(stmt);
1730
+ const { sql, args } = normalizeStatement2(stmt);
1146
1731
  const response = await sendDaemonRequest({
1147
1732
  type: "db-execute",
1148
1733
  sql,
@@ -1167,7 +1752,7 @@ function createDaemonDbClient(fallbackClient) {
1167
1752
  if (!_useDaemon || !isClientConnected()) {
1168
1753
  return fallbackClient.batch(stmts, mode);
1169
1754
  }
1170
- const statements = stmts.map(normalizeStatement);
1755
+ const statements = stmts.map(normalizeStatement2);
1171
1756
  const response = await sendDaemonRequest({
1172
1757
  type: "db-batch",
1173
1758
  statements,
@@ -1262,6 +1847,18 @@ __export(database_exports, {
1262
1847
  });
1263
1848
  import { createClient } from "@libsql/client";
1264
1849
  async function initDatabase(config) {
1850
+ if (_walCheckpointTimer) {
1851
+ clearInterval(_walCheckpointTimer);
1852
+ _walCheckpointTimer = null;
1853
+ }
1854
+ if (_daemonClient) {
1855
+ _daemonClient.close();
1856
+ _daemonClient = null;
1857
+ }
1858
+ if (_adapterClient && _adapterClient !== _resilientClient) {
1859
+ _adapterClient.close();
1860
+ }
1861
+ _adapterClient = null;
1265
1862
  if (_client) {
1266
1863
  _client.close();
1267
1864
  _client = null;
@@ -1275,6 +1872,7 @@ async function initDatabase(config) {
1275
1872
  }
1276
1873
  _client = createClient(opts);
1277
1874
  _resilientClient = wrapWithRetry(_client);
1875
+ _adapterClient = _resilientClient;
1278
1876
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1279
1877
  });
1280
1878
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -1285,14 +1883,20 @@ async function initDatabase(config) {
1285
1883
  });
1286
1884
  }, 3e4);
1287
1885
  _walCheckpointTimer.unref();
1886
+ if (process.env.DATABASE_URL) {
1887
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
1888
+ }
1288
1889
  }
1289
1890
  function isInitialized() {
1290
- return _client !== null;
1891
+ return _adapterClient !== null || _client !== null;
1291
1892
  }
1292
1893
  function getClient() {
1293
- if (!_resilientClient) {
1894
+ if (!_adapterClient) {
1294
1895
  throw new Error("Database client not initialized. Call initDatabase() first.");
1295
1896
  }
1897
+ if (process.env.DATABASE_URL) {
1898
+ return _adapterClient;
1899
+ }
1296
1900
  if (process.env.EXE_IS_DAEMON === "1") {
1297
1901
  return _resilientClient;
1298
1902
  }
@@ -1302,6 +1906,7 @@ function getClient() {
1302
1906
  return _resilientClient;
1303
1907
  }
1304
1908
  async function initDaemonClient() {
1909
+ if (process.env.DATABASE_URL) return;
1305
1910
  if (process.env.EXE_IS_DAEMON === "1") return;
1306
1911
  if (!_resilientClient) return;
1307
1912
  try {
@@ -2246,26 +2851,36 @@ async function ensureSchema() {
2246
2851
  }
2247
2852
  }
2248
2853
  async function disposeDatabase() {
2854
+ if (_walCheckpointTimer) {
2855
+ clearInterval(_walCheckpointTimer);
2856
+ _walCheckpointTimer = null;
2857
+ }
2249
2858
  if (_daemonClient) {
2250
2859
  _daemonClient.close();
2251
2860
  _daemonClient = null;
2252
2861
  }
2862
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2863
+ _adapterClient.close();
2864
+ }
2865
+ _adapterClient = null;
2253
2866
  if (_client) {
2254
2867
  _client.close();
2255
2868
  _client = null;
2256
2869
  _resilientClient = null;
2257
2870
  }
2258
2871
  }
2259
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
2872
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
2260
2873
  var init_database = __esm({
2261
2874
  "src/lib/database.ts"() {
2262
2875
  "use strict";
2263
2876
  init_db_retry();
2264
2877
  init_employees();
2878
+ init_database_adapter();
2265
2879
  _client = null;
2266
2880
  _resilientClient = null;
2267
2881
  _walCheckpointTimer = null;
2268
2882
  _daemonClient = null;
2883
+ _adapterClient = null;
2269
2884
  initTurso = initDatabase;
2270
2885
  disposeTurso = disposeDatabase;
2271
2886
  }
@@ -2274,16 +2889,16 @@ var init_database = __esm({
2274
2889
  // src/lib/license.ts
2275
2890
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
2276
2891
  import { randomUUID as randomUUID2 } from "crypto";
2277
- import path8 from "path";
2892
+ import path9 from "path";
2278
2893
  import { jwtVerify, importSPKI } from "jose";
2279
2894
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
2280
2895
  var init_license = __esm({
2281
2896
  "src/lib/license.ts"() {
2282
2897
  "use strict";
2283
2898
  init_config();
2284
- LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
2285
- CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
2286
- DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
2899
+ LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
2900
+ CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
2901
+ DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
2287
2902
  PLAN_LIMITS = {
2288
2903
  free: { devices: 1, employees: 1, memories: 5e3 },
2289
2904
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -2296,7 +2911,7 @@ var init_license = __esm({
2296
2911
 
2297
2912
  // src/lib/plan-limits.ts
2298
2913
  import { readFileSync as readFileSync9, existsSync as existsSync8 } from "fs";
2299
- import path9 from "path";
2914
+ import path10 from "path";
2300
2915
  function getLicenseSync() {
2301
2916
  try {
2302
2917
  if (!existsSync8(CACHE_PATH2)) return freeLicense();
@@ -2368,14 +2983,14 @@ var init_plan_limits = __esm({
2368
2983
  this.name = "PlanLimitError";
2369
2984
  }
2370
2985
  };
2371
- CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
2986
+ CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
2372
2987
  }
2373
2988
  });
2374
2989
 
2375
2990
  // src/lib/notifications.ts
2376
2991
  import crypto from "crypto";
2377
- import path10 from "path";
2378
- import os6 from "os";
2992
+ import path11 from "path";
2993
+ import os7 from "os";
2379
2994
  import {
2380
2995
  readFileSync as readFileSync10,
2381
2996
  readdirSync as readdirSync2,
@@ -2515,8 +3130,8 @@ var init_state_bus = __esm({
2515
3130
 
2516
3131
  // src/lib/tasks-crud.ts
2517
3132
  import crypto3 from "crypto";
2518
- import path11 from "path";
2519
- import os7 from "os";
3133
+ import path12 from "path";
3134
+ import os8 from "os";
2520
3135
  import { execSync as execSync5 } from "child_process";
2521
3136
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2522
3137
  import { existsSync as existsSync10, readFileSync as readFileSync11 } from "fs";
@@ -2694,8 +3309,8 @@ ${laneWarning}` : laneWarning;
2694
3309
  }
2695
3310
  if (input2.baseDir) {
2696
3311
  try {
2697
- await mkdir3(path11.join(input2.baseDir, "exe", "output"), { recursive: true });
2698
- await mkdir3(path11.join(input2.baseDir, "exe", "research"), { recursive: true });
3312
+ await mkdir3(path12.join(input2.baseDir, "exe", "output"), { recursive: true });
3313
+ await mkdir3(path12.join(input2.baseDir, "exe", "research"), { recursive: true });
2699
3314
  await ensureArchitectureDoc(input2.baseDir, input2.projectName);
2700
3315
  await ensureGitignoreExe(input2.baseDir);
2701
3316
  } catch {
@@ -2731,9 +3346,9 @@ ${laneWarning}` : laneWarning;
2731
3346
  });
2732
3347
  if (input2.baseDir) {
2733
3348
  try {
2734
- const EXE_OS_DIR = path11.join(os7.homedir(), ".exe-os");
2735
- const mdPath = path11.join(EXE_OS_DIR, taskFile);
2736
- const mdDir = path11.dirname(mdPath);
3349
+ const EXE_OS_DIR = path12.join(os8.homedir(), ".exe-os");
3350
+ const mdPath = path12.join(EXE_OS_DIR, taskFile);
3351
+ const mdDir = path12.dirname(mdPath);
2737
3352
  if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
2738
3353
  const reviewer = input2.reviewer ?? input2.assignedBy;
2739
3354
  const mdContent = `# ${input2.title}
@@ -3034,7 +3649,7 @@ async function deleteTaskCore(taskId, _baseDir) {
3034
3649
  return { taskFile, assignedTo, assignedBy, taskSlug };
3035
3650
  }
3036
3651
  async function ensureArchitectureDoc(baseDir, projectName) {
3037
- const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
3652
+ const archPath = path12.join(baseDir, "exe", "ARCHITECTURE.md");
3038
3653
  try {
3039
3654
  if (existsSync10(archPath)) return;
3040
3655
  const template = [
@@ -3069,7 +3684,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
3069
3684
  }
3070
3685
  }
3071
3686
  async function ensureGitignoreExe(baseDir) {
3072
- const gitignorePath = path11.join(baseDir, ".gitignore");
3687
+ const gitignorePath = path12.join(baseDir, ".gitignore");
3073
3688
  try {
3074
3689
  if (existsSync10(gitignorePath)) {
3075
3690
  const content = readFileSync11(gitignorePath, "utf-8");
@@ -3103,13 +3718,13 @@ var init_tasks_crud = __esm({
3103
3718
  });
3104
3719
 
3105
3720
  // src/lib/tasks-review.ts
3106
- import path12 from "path";
3721
+ import path13 from "path";
3107
3722
  import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync5 } from "fs";
3108
3723
  async function countPendingReviews(sessionScope) {
3109
3724
  const client = getClient();
3110
3725
  if (sessionScope) {
3111
3726
  const result2 = await client.execute({
3112
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
3727
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
3113
3728
  args: [sessionScope]
3114
3729
  });
3115
3730
  return Number(result2.rows[0]?.cnt) || 0;
@@ -3285,11 +3900,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
3285
3900
  );
3286
3901
  }
3287
3902
  try {
3288
- const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
3903
+ const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
3289
3904
  if (existsSync11(cacheDir)) {
3290
3905
  for (const f of readdirSync3(cacheDir)) {
3291
3906
  if (f.startsWith("review-notified-")) {
3292
- unlinkSync5(path12.join(cacheDir, f));
3907
+ unlinkSync5(path13.join(cacheDir, f));
3293
3908
  }
3294
3909
  }
3295
3910
  }
@@ -3310,7 +3925,7 @@ var init_tasks_review = __esm({
3310
3925
  });
3311
3926
 
3312
3927
  // src/lib/tasks-chain.ts
3313
- import path13 from "path";
3928
+ import path14 from "path";
3314
3929
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
3315
3930
  async function cascadeUnblock(taskId, baseDir, now) {
3316
3931
  const client = getClient();
@@ -3327,7 +3942,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
3327
3942
  });
3328
3943
  for (const ur of unblockedRows.rows) {
3329
3944
  try {
3330
- const ubFile = path13.join(baseDir, String(ur.task_file));
3945
+ const ubFile = path14.join(baseDir, String(ur.task_file));
3331
3946
  let ubContent = await readFile3(ubFile, "utf-8");
3332
3947
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
3333
3948
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -3396,7 +4011,7 @@ var init_tasks_chain = __esm({
3396
4011
 
3397
4012
  // src/lib/project-name.ts
3398
4013
  import { execSync as execSync6 } from "child_process";
3399
- import path14 from "path";
4014
+ import path15 from "path";
3400
4015
  function getProjectName(cwd) {
3401
4016
  const dir = cwd ?? process.cwd();
3402
4017
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -3409,7 +4024,7 @@ function getProjectName(cwd) {
3409
4024
  timeout: 2e3,
3410
4025
  stdio: ["pipe", "pipe", "pipe"]
3411
4026
  }).trim();
3412
- repoRoot = path14.dirname(gitCommonDir);
4027
+ repoRoot = path15.dirname(gitCommonDir);
3413
4028
  } catch {
3414
4029
  repoRoot = execSync6("git rev-parse --show-toplevel", {
3415
4030
  cwd: dir,
@@ -3418,11 +4033,11 @@ function getProjectName(cwd) {
3418
4033
  stdio: ["pipe", "pipe", "pipe"]
3419
4034
  }).trim();
3420
4035
  }
3421
- _cached2 = path14.basename(repoRoot);
4036
+ _cached2 = path15.basename(repoRoot);
3422
4037
  _cachedCwd = dir;
3423
4038
  return _cached2;
3424
4039
  } catch {
3425
- _cached2 = path14.basename(dir);
4040
+ _cached2 = path15.basename(dir);
3426
4041
  _cachedCwd = dir;
3427
4042
  return _cached2;
3428
4043
  }
@@ -3895,7 +4510,7 @@ __export(tasks_exports, {
3895
4510
  updateTaskStatus: () => updateTaskStatus,
3896
4511
  writeCheckpoint: () => writeCheckpoint
3897
4512
  });
3898
- import path15 from "path";
4513
+ import path16 from "path";
3899
4514
  import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync6 } from "fs";
3900
4515
  async function createTask(input2) {
3901
4516
  const result = await createTaskCore(input2);
@@ -3915,8 +4530,8 @@ async function updateTask(input2) {
3915
4530
  const { row, taskFile, now, taskId } = await updateTaskStatus(input2);
3916
4531
  try {
3917
4532
  const agent = String(row.assigned_to);
3918
- const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
3919
- const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
4533
+ const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
4534
+ const cachePath = path16.join(cacheDir, `current-task-${agent}.json`);
3920
4535
  if (input2.status === "in_progress") {
3921
4536
  mkdirSync6(cacheDir, { recursive: true });
3922
4537
  writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -4387,12 +5002,12 @@ __export(tmux_routing_exports, {
4387
5002
  });
4388
5003
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
4389
5004
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync12, appendFileSync, readdirSync as readdirSync4 } from "fs";
4390
- import path16 from "path";
4391
- import os8 from "os";
5005
+ import path17 from "path";
5006
+ import os9 from "os";
4392
5007
  import { fileURLToPath as fileURLToPath2 } from "url";
4393
5008
  import { unlinkSync as unlinkSync7 } from "fs";
4394
5009
  function spawnLockPath(sessionName) {
4395
- return path16.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
5010
+ return path17.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
4396
5011
  }
4397
5012
  function isProcessAlive(pid) {
4398
5013
  try {
@@ -4429,8 +5044,8 @@ function releaseSpawnLock2(sessionName) {
4429
5044
  function resolveBehaviorsExporterScript() {
4430
5045
  try {
4431
5046
  const thisFile = fileURLToPath2(import.meta.url);
4432
- const scriptPath = path16.join(
4433
- path16.dirname(thisFile),
5047
+ const scriptPath = path17.join(
5048
+ path17.dirname(thisFile),
4434
5049
  "..",
4435
5050
  "bin",
4436
5051
  "exe-export-behaviors.js"
@@ -4505,7 +5120,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
4505
5120
  mkdirSync7(SESSION_CACHE, { recursive: true });
4506
5121
  }
4507
5122
  const rootExe = extractRootExe(parentExe) ?? parentExe;
4508
- const filePath = path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
5123
+ const filePath = path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
4509
5124
  writeFileSync8(filePath, JSON.stringify({
4510
5125
  parentExe: rootExe,
4511
5126
  dispatchedBy: dispatchedBy || rootExe,
@@ -4514,7 +5129,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
4514
5129
  }
4515
5130
  function getParentExe(sessionKey) {
4516
5131
  try {
4517
- const data = JSON.parse(readFileSync12(path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
5132
+ const data = JSON.parse(readFileSync12(path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
4518
5133
  return data.parentExe || null;
4519
5134
  } catch {
4520
5135
  return null;
@@ -4523,7 +5138,7 @@ function getParentExe(sessionKey) {
4523
5138
  function getDispatchedBy(sessionKey) {
4524
5139
  try {
4525
5140
  const data = JSON.parse(readFileSync12(
4526
- path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
5141
+ path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
4527
5142
  "utf8"
4528
5143
  ));
4529
5144
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -4534,15 +5149,24 @@ function getDispatchedBy(sessionKey) {
4534
5149
  function resolveExeSession() {
4535
5150
  const mySession = getMySession();
4536
5151
  if (!mySession) return null;
5152
+ const fromSessionName = extractRootExe(mySession);
4537
5153
  try {
4538
5154
  const key = getSessionKey();
4539
5155
  const parentExe = getParentExe(key);
4540
5156
  if (parentExe) {
4541
- return extractRootExe(parentExe) ?? parentExe;
5157
+ const fromCache = extractRootExe(parentExe) ?? parentExe;
5158
+ if (fromSessionName && fromCache !== fromSessionName) {
5159
+ process.stderr.write(
5160
+ `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
5161
+ `
5162
+ );
5163
+ return fromSessionName;
5164
+ }
5165
+ return fromCache;
4542
5166
  }
4543
5167
  } catch {
4544
5168
  }
4545
- return extractRootExe(mySession) ?? mySession;
5169
+ return fromSessionName ?? mySession;
4546
5170
  }
4547
5171
  function isEmployeeAlive(sessionName) {
4548
5172
  return getTransport().isAlive(sessionName);
@@ -4700,7 +5324,7 @@ function sendIntercom(targetSession) {
4700
5324
  try {
4701
5325
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
4702
5326
  const agent = baseAgentName(rawAgent);
4703
- const markerPath = path16.join(SESSION_CACHE, `current-task-${agent}.json`);
5327
+ const markerPath = path17.join(SESSION_CACHE, `current-task-${agent}.json`);
4704
5328
  if (existsSync12(markerPath)) {
4705
5329
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
4706
5330
  return "debounced";
@@ -4710,7 +5334,7 @@ function sendIntercom(targetSession) {
4710
5334
  try {
4711
5335
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
4712
5336
  const agent = baseAgentName(rawAgent);
4713
- const taskDir = path16.join(process.cwd(), "exe", agent);
5337
+ const taskDir = path17.join(process.cwd(), "exe", agent);
4714
5338
  if (existsSync12(taskDir)) {
4715
5339
  const files = readdirSync4(taskDir).filter(
4716
5340
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -4844,8 +5468,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4844
5468
  const transport = getTransport();
4845
5469
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
4846
5470
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
4847
- const logDir = path16.join(os8.homedir(), ".exe-os", "session-logs");
4848
- const logFile = path16.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5471
+ const logDir = path17.join(os9.homedir(), ".exe-os", "session-logs");
5472
+ const logFile = path17.join(logDir, `${instanceLabel}-${Date.now()}.log`);
4849
5473
  if (!existsSync12(logDir)) {
4850
5474
  mkdirSync7(logDir, { recursive: true });
4851
5475
  }
@@ -4853,14 +5477,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4853
5477
  let cleanupSuffix = "";
4854
5478
  try {
4855
5479
  const thisFile = fileURLToPath2(import.meta.url);
4856
- const cleanupScript = path16.join(path16.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
5480
+ const cleanupScript = path17.join(path17.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
4857
5481
  if (existsSync12(cleanupScript)) {
4858
5482
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
4859
5483
  }
4860
5484
  } catch {
4861
5485
  }
4862
5486
  try {
4863
- const claudeJsonPath = path16.join(os8.homedir(), ".claude.json");
5487
+ const claudeJsonPath = path17.join(os9.homedir(), ".claude.json");
4864
5488
  let claudeJson = {};
4865
5489
  try {
4866
5490
  claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
@@ -4875,10 +5499,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4875
5499
  } catch {
4876
5500
  }
4877
5501
  try {
4878
- const settingsDir = path16.join(os8.homedir(), ".claude", "projects");
5502
+ const settingsDir = path17.join(os9.homedir(), ".claude", "projects");
4879
5503
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
4880
- const projSettingsDir = path16.join(settingsDir, normalizedKey);
4881
- const settingsPath = path16.join(projSettingsDir, "settings.json");
5504
+ const projSettingsDir = path17.join(settingsDir, normalizedKey);
5505
+ const settingsPath = path17.join(projSettingsDir, "settings.json");
4882
5506
  let settings = {};
4883
5507
  try {
4884
5508
  settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
@@ -4925,8 +5549,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4925
5549
  let behaviorsFlag = "";
4926
5550
  let legacyFallbackWarned = false;
4927
5551
  if (!useExeAgent && !useBinSymlink) {
4928
- const identityPath = path16.join(
4929
- os8.homedir(),
5552
+ const identityPath = path17.join(
5553
+ os9.homedir(),
4930
5554
  ".exe-os",
4931
5555
  "identity",
4932
5556
  `${employeeName}.md`
@@ -4941,7 +5565,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4941
5565
  }
4942
5566
  const behaviorsFile = exportBehaviorsSync(
4943
5567
  employeeName,
4944
- path16.basename(spawnCwd),
5568
+ path17.basename(spawnCwd),
4945
5569
  sessionName
4946
5570
  );
4947
5571
  if (behaviorsFile) {
@@ -4956,9 +5580,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4956
5580
  }
4957
5581
  let sessionContextFlag = "";
4958
5582
  try {
4959
- const ctxDir = path16.join(os8.homedir(), ".exe-os", "session-cache");
5583
+ const ctxDir = path17.join(os9.homedir(), ".exe-os", "session-cache");
4960
5584
  mkdirSync7(ctxDir, { recursive: true });
4961
- const ctxFile = path16.join(ctxDir, `session-context-${sessionName}.md`);
5585
+ const ctxFile = path17.join(ctxDir, `session-context-${sessionName}.md`);
4962
5586
  const ctxContent = [
4963
5587
  `## Session Context`,
4964
5588
  `You are running in tmux session: ${sessionName}.`,
@@ -5042,7 +5666,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5042
5666
  transport.pipeLog(sessionName, logFile);
5043
5667
  try {
5044
5668
  const mySession = getMySession();
5045
- const dispatchInfo = path16.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
5669
+ const dispatchInfo = path17.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
5046
5670
  writeFileSync8(dispatchInfo, JSON.stringify({
5047
5671
  dispatchedBy: mySession,
5048
5672
  rootExe: exeSession,
@@ -5117,15 +5741,15 @@ var init_tmux_routing = __esm({
5117
5741
  init_intercom_queue();
5118
5742
  init_plan_limits();
5119
5743
  init_employees();
5120
- SPAWN_LOCK_DIR = path16.join(os8.homedir(), ".exe-os", "spawn-locks");
5121
- SESSION_CACHE = path16.join(os8.homedir(), ".exe-os", "session-cache");
5744
+ SPAWN_LOCK_DIR = path17.join(os9.homedir(), ".exe-os", "spawn-locks");
5745
+ SESSION_CACHE = path17.join(os9.homedir(), ".exe-os", "session-cache");
5122
5746
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5123
5747
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
5124
5748
  VERIFY_PANE_LINES = 200;
5125
5749
  INTERCOM_DEBOUNCE_MS = 3e4;
5126
5750
  CODEX_DEBOUNCE_MS = 12e4;
5127
- INTERCOM_LOG2 = path16.join(os8.homedir(), ".exe-os", "intercom.log");
5128
- DEBOUNCE_FILE = path16.join(SESSION_CACHE, "intercom-debounce.json");
5751
+ INTERCOM_LOG2 = path17.join(os9.homedir(), ".exe-os", "intercom.log");
5752
+ DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
5129
5753
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
5130
5754
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
5131
5755
  }
@@ -5167,13 +5791,13 @@ var init_memory = __esm({
5167
5791
  // src/lib/keychain.ts
5168
5792
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
5169
5793
  import { existsSync as existsSync13 } from "fs";
5170
- import path17 from "path";
5171
- import os9 from "os";
5794
+ import path18 from "path";
5795
+ import os10 from "os";
5172
5796
  function getKeyDir() {
5173
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path17.join(os9.homedir(), ".exe-os");
5797
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path18.join(os10.homedir(), ".exe-os");
5174
5798
  }
5175
5799
  function getKeyPath() {
5176
- return path17.join(getKeyDir(), "master.key");
5800
+ return path18.join(getKeyDir(), "master.key");
5177
5801
  }
5178
5802
  async function tryKeytar() {
5179
5803
  try {
@@ -5196,7 +5820,7 @@ async function getMasterKey() {
5196
5820
  const keyPath = getKeyPath();
5197
5821
  if (!existsSync13(keyPath)) {
5198
5822
  process.stderr.write(
5199
- `[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5823
+ `[keychain] Key not found at ${keyPath} (HOME=${os10.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5200
5824
  `
5201
5825
  );
5202
5826
  return null;
@@ -5234,7 +5858,7 @@ __export(shard_manager_exports, {
5234
5858
  listShards: () => listShards,
5235
5859
  shardExists: () => shardExists
5236
5860
  });
5237
- import path18 from "path";
5861
+ import path19 from "path";
5238
5862
  import { existsSync as existsSync14, mkdirSync as mkdirSync8, readdirSync as readdirSync5 } from "fs";
5239
5863
  import { createClient as createClient2 } from "@libsql/client";
5240
5864
  function initShardManager(encryptionKey) {
@@ -5260,7 +5884,7 @@ function getShardClient(projectName) {
5260
5884
  }
5261
5885
  const cached = _shards.get(safeName);
5262
5886
  if (cached) return cached;
5263
- const dbPath = path18.join(SHARDS_DIR, `${safeName}.db`);
5887
+ const dbPath = path19.join(SHARDS_DIR, `${safeName}.db`);
5264
5888
  const client = createClient2({
5265
5889
  url: `file:${dbPath}`,
5266
5890
  encryptionKey: _encryptionKey
@@ -5270,7 +5894,7 @@ function getShardClient(projectName) {
5270
5894
  }
5271
5895
  function shardExists(projectName) {
5272
5896
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
5273
- return existsSync14(path18.join(SHARDS_DIR, `${safeName}.db`));
5897
+ return existsSync14(path19.join(SHARDS_DIR, `${safeName}.db`));
5274
5898
  }
5275
5899
  function listShards() {
5276
5900
  if (!existsSync14(SHARDS_DIR)) return [];
@@ -5347,7 +5971,23 @@ async function ensureShardSchema(client) {
5347
5971
  // MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
5348
5972
  "ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
5349
5973
  "ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
5350
- "ALTER TABLE memories ADD COLUMN trajectory TEXT"
5974
+ "ALTER TABLE memories ADD COLUMN trajectory TEXT",
5975
+ // Metadata enrichment columns (must match database.ts)
5976
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
5977
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
5978
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
5979
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
5980
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
5981
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
5982
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
5983
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
5984
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
5985
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
5986
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
5987
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
5988
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
5989
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
5990
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
5351
5991
  ]) {
5352
5992
  try {
5353
5993
  await client.execute(col);
@@ -5459,7 +6099,7 @@ var init_shard_manager = __esm({
5459
6099
  "src/lib/shard-manager.ts"() {
5460
6100
  "use strict";
5461
6101
  init_config();
5462
- SHARDS_DIR = path18.join(EXE_AI_DIR, "shards");
6102
+ SHARDS_DIR = path19.join(EXE_AI_DIR, "shards");
5463
6103
  _shards = /* @__PURE__ */ new Map();
5464
6104
  _encryptionKey = null;
5465
6105
  _shardingEnabled = false;