@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
@@ -100,6 +100,118 @@ var init_config = __esm({
100
100
  }
101
101
  });
102
102
 
103
+ // src/lib/runtime-table.ts
104
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
105
+ var init_runtime_table = __esm({
106
+ "src/lib/runtime-table.ts"() {
107
+ "use strict";
108
+ RUNTIME_TABLE = {
109
+ codex: {
110
+ binary: "codex",
111
+ launchMode: "interactive",
112
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
113
+ inlineFlag: "--no-alt-screen",
114
+ apiKeyEnv: "OPENAI_API_KEY",
115
+ defaultModel: "gpt-5.4"
116
+ },
117
+ opencode: {
118
+ binary: "opencode",
119
+ launchMode: "exec",
120
+ autoApproveFlag: "--dangerously-skip-permissions",
121
+ inlineFlag: "",
122
+ apiKeyEnv: "ANTHROPIC_API_KEY",
123
+ defaultModel: "anthropic/claude-sonnet-4-6"
124
+ }
125
+ };
126
+ DEFAULT_RUNTIME = "claude";
127
+ }
128
+ });
129
+
130
+ // src/lib/agent-config.ts
131
+ var agent_config_exports = {};
132
+ __export(agent_config_exports, {
133
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
134
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
135
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
136
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
137
+ clearAgentRuntime: () => clearAgentRuntime,
138
+ getAgentRuntime: () => getAgentRuntime,
139
+ loadAgentConfig: () => loadAgentConfig,
140
+ saveAgentConfig: () => saveAgentConfig,
141
+ setAgentRuntime: () => setAgentRuntime
142
+ });
143
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
144
+ import path2 from "path";
145
+ function loadAgentConfig() {
146
+ if (!existsSync2(AGENT_CONFIG_PATH)) return {};
147
+ try {
148
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
149
+ } catch {
150
+ return {};
151
+ }
152
+ }
153
+ function saveAgentConfig(config) {
154
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
155
+ if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
156
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
157
+ }
158
+ function getAgentRuntime(agentId) {
159
+ const config = loadAgentConfig();
160
+ const entry = config[agentId];
161
+ if (entry) return entry;
162
+ const orgDefault = config["default"];
163
+ if (orgDefault) return orgDefault;
164
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
165
+ }
166
+ function setAgentRuntime(agentId, runtime, model) {
167
+ const knownModels = KNOWN_RUNTIMES[runtime];
168
+ if (!knownModels) {
169
+ return {
170
+ ok: false,
171
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
172
+ };
173
+ }
174
+ if (!knownModels.includes(model)) {
175
+ return {
176
+ ok: false,
177
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
178
+ };
179
+ }
180
+ const config = loadAgentConfig();
181
+ config[agentId] = { runtime, model };
182
+ saveAgentConfig(config);
183
+ return { ok: true };
184
+ }
185
+ function clearAgentRuntime(agentId) {
186
+ const config = loadAgentConfig();
187
+ delete config[agentId];
188
+ saveAgentConfig(config);
189
+ }
190
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
191
+ var init_agent_config = __esm({
192
+ "src/lib/agent-config.ts"() {
193
+ "use strict";
194
+ init_config();
195
+ init_runtime_table();
196
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
197
+ KNOWN_RUNTIMES = {
198
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
199
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
200
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
201
+ };
202
+ RUNTIME_LABELS = {
203
+ claude: "Claude Code (Anthropic)",
204
+ codex: "Codex (OpenAI)",
205
+ opencode: "OpenCode (open source)"
206
+ };
207
+ DEFAULT_MODELS = {
208
+ claude: "claude-opus-4",
209
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
210
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
211
+ };
212
+ }
213
+ });
214
+
103
215
  // src/lib/employees.ts
104
216
  var employees_exports = {};
105
217
  __export(employees_exports, {
@@ -115,6 +227,7 @@ __export(employees_exports, {
115
227
  getEmployeeByRole: () => getEmployeeByRole,
116
228
  getEmployeeNamesByRole: () => getEmployeeNamesByRole,
117
229
  hasRole: () => hasRole,
230
+ hireEmployee: () => hireEmployee,
118
231
  isCoordinatorName: () => isCoordinatorName,
119
232
  isCoordinatorRole: () => isCoordinatorRole,
120
233
  isMultiInstance: () => isMultiInstance,
@@ -127,9 +240,9 @@ __export(employees_exports, {
127
240
  validateEmployeeName: () => validateEmployeeName
128
241
  });
129
242
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
130
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
243
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
131
244
  import { execSync } from "child_process";
132
- import path2 from "path";
245
+ import path3 from "path";
133
246
  import os2 from "os";
134
247
  function normalizeRole(role) {
135
248
  return (role ?? "").trim().toLowerCase();
@@ -166,7 +279,7 @@ function validateEmployeeName(name) {
166
279
  return { valid: true };
167
280
  }
168
281
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
169
- if (!existsSync2(employeesPath)) {
282
+ if (!existsSync3(employeesPath)) {
170
283
  return [];
171
284
  }
172
285
  const raw = await readFile2(employeesPath, "utf-8");
@@ -177,13 +290,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
177
290
  }
178
291
  }
179
292
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
180
- await mkdir2(path2.dirname(employeesPath), { recursive: true });
293
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
181
294
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
182
295
  }
183
296
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
184
- if (!existsSync2(employeesPath)) return [];
297
+ if (!existsSync3(employeesPath)) return [];
185
298
  try {
186
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
299
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
187
300
  } catch {
188
301
  return [];
189
302
  }
@@ -225,6 +338,52 @@ function addEmployee(employees, employee) {
225
338
  }
226
339
  return [...employees, normalized];
227
340
  }
341
+ function appendToCoordinatorTeam(employee) {
342
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
343
+ if (!coordinator) return;
344
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
345
+ if (!existsSync3(idPath)) return;
346
+ const content = readFileSync3(idPath, "utf-8");
347
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
348
+ const teamMatch = content.match(TEAM_SECTION_RE);
349
+ if (!teamMatch || teamMatch.index === void 0) return;
350
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
351
+ const nextHeading = afterTeam.match(/\n## /);
352
+ const entry = `
353
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
354
+ `;
355
+ let updated;
356
+ if (nextHeading && nextHeading.index !== void 0) {
357
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
358
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
359
+ } else {
360
+ updated = content.trimEnd() + "\n" + entry;
361
+ }
362
+ writeFileSync2(idPath, updated, "utf-8");
363
+ }
364
+ function capitalize(s) {
365
+ return s.charAt(0).toUpperCase() + s.slice(1);
366
+ }
367
+ async function hireEmployee(employee) {
368
+ const employees = await loadEmployees();
369
+ const updated = addEmployee(employees, employee);
370
+ await saveEmployees(updated);
371
+ try {
372
+ appendToCoordinatorTeam(employee);
373
+ } catch {
374
+ }
375
+ try {
376
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
377
+ const config = loadAgentConfig2();
378
+ const name = employee.name.toLowerCase();
379
+ if (!config[name] && config["default"]) {
380
+ config[name] = { ...config["default"] };
381
+ saveAgentConfig2(config);
382
+ }
383
+ } catch {
384
+ }
385
+ return updated;
386
+ }
228
387
  async function normalizeRosterCase(rosterPath) {
229
388
  const employees = await loadEmployees(rosterPath);
230
389
  let changed = false;
@@ -234,14 +393,14 @@ async function normalizeRosterCase(rosterPath) {
234
393
  emp.name = emp.name.toLowerCase();
235
394
  changed = true;
236
395
  try {
237
- const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
238
- const oldPath = path2.join(identityDir, `${oldName}.md`);
239
- const newPath = path2.join(identityDir, `${emp.name}.md`);
240
- if (existsSync2(oldPath) && !existsSync2(newPath)) {
396
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
397
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
398
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
399
+ if (existsSync3(oldPath) && !existsSync3(newPath)) {
241
400
  renameSync2(oldPath, newPath);
242
- } else if (existsSync2(oldPath) && oldPath !== newPath) {
243
- const content = readFileSync2(oldPath, "utf-8");
244
- writeFileSync(newPath, content, "utf-8");
401
+ } else if (existsSync3(oldPath) && oldPath !== newPath) {
402
+ const content = readFileSync3(oldPath, "utf-8");
403
+ writeFileSync2(newPath, content, "utf-8");
245
404
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
246
405
  unlinkSync(oldPath);
247
406
  }
@@ -271,7 +430,7 @@ function registerBinSymlinks(name) {
271
430
  errors.push("Could not find 'exe-os' in PATH");
272
431
  return { created, skipped, errors };
273
432
  }
274
- const binDir = path2.dirname(exeBinPath);
433
+ const binDir = path3.dirname(exeBinPath);
275
434
  let target;
276
435
  try {
277
436
  target = readlinkSync(exeBinPath);
@@ -281,8 +440,8 @@ function registerBinSymlinks(name) {
281
440
  }
282
441
  for (const suffix of ["", "-opencode"]) {
283
442
  const linkName = `${name}${suffix}`;
284
- const linkPath = path2.join(binDir, linkName);
285
- if (existsSync2(linkPath)) {
443
+ const linkPath = path3.join(binDir, linkName);
444
+ if (existsSync3(linkPath)) {
286
445
  skipped.push(linkName);
287
446
  continue;
288
447
  }
@@ -295,15 +454,17 @@ function registerBinSymlinks(name) {
295
454
  }
296
455
  return { created, skipped, errors };
297
456
  }
298
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
457
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
299
458
  var init_employees = __esm({
300
459
  "src/lib/employees.ts"() {
301
460
  "use strict";
302
461
  init_config();
303
- EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
462
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
304
463
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
305
464
  COORDINATOR_ROLE = "COO";
306
465
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
466
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
467
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
307
468
  }
308
469
  });
309
470
 
@@ -314,6 +475,27 @@ var init_db_retry = __esm({
314
475
  }
315
476
  });
316
477
 
478
+ // src/lib/database-adapter.ts
479
+ import os3 from "os";
480
+ import path4 from "path";
481
+ import { createRequire } from "module";
482
+ import { pathToFileURL } from "url";
483
+ var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
484
+ var init_database_adapter = __esm({
485
+ "src/lib/database-adapter.ts"() {
486
+ "use strict";
487
+ BOOLEAN_COLUMNS_BY_TABLE = {
488
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
489
+ behaviors: /* @__PURE__ */ new Set(["active"]),
490
+ notifications: /* @__PURE__ */ new Set(["read"]),
491
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
492
+ };
493
+ BOOLEAN_COLUMN_NAMES = new Set(
494
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
495
+ );
496
+ }
497
+ });
498
+
317
499
  // src/lib/database.ts
318
500
  import { createClient } from "@libsql/client";
319
501
  var init_database = __esm({
@@ -321,6 +503,7 @@ var init_database = __esm({
321
503
  "use strict";
322
504
  init_db_retry();
323
505
  init_employees();
506
+ init_database_adapter();
324
507
  }
325
508
  });
326
509
 
@@ -1082,122 +1265,10 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
1082
1265
  }
1083
1266
  });
1084
1267
 
1085
- // src/lib/runtime-table.ts
1086
- var RUNTIME_TABLE, DEFAULT_RUNTIME;
1087
- var init_runtime_table = __esm({
1088
- "src/lib/runtime-table.ts"() {
1089
- "use strict";
1090
- RUNTIME_TABLE = {
1091
- codex: {
1092
- binary: "codex",
1093
- launchMode: "interactive",
1094
- autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
1095
- inlineFlag: "--no-alt-screen",
1096
- apiKeyEnv: "OPENAI_API_KEY",
1097
- defaultModel: "gpt-5.4"
1098
- },
1099
- opencode: {
1100
- binary: "opencode",
1101
- launchMode: "exec",
1102
- autoApproveFlag: "--dangerously-skip-permissions",
1103
- inlineFlag: "",
1104
- apiKeyEnv: "ANTHROPIC_API_KEY",
1105
- defaultModel: "anthropic/claude-sonnet-4-6"
1106
- }
1107
- };
1108
- DEFAULT_RUNTIME = "claude";
1109
- }
1110
- });
1111
-
1112
- // src/lib/agent-config.ts
1113
- var agent_config_exports = {};
1114
- __export(agent_config_exports, {
1115
- AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
1116
- DEFAULT_MODELS: () => DEFAULT_MODELS,
1117
- KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
1118
- RUNTIME_LABELS: () => RUNTIME_LABELS,
1119
- clearAgentRuntime: () => clearAgentRuntime,
1120
- getAgentRuntime: () => getAgentRuntime,
1121
- loadAgentConfig: () => loadAgentConfig,
1122
- saveAgentConfig: () => saveAgentConfig,
1123
- setAgentRuntime: () => setAgentRuntime
1124
- });
1125
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
1126
- import path3 from "path";
1127
- function loadAgentConfig() {
1128
- if (!existsSync3(AGENT_CONFIG_PATH)) return {};
1129
- try {
1130
- return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
1131
- } catch {
1132
- return {};
1133
- }
1134
- }
1135
- function saveAgentConfig(config) {
1136
- const dir = path3.dirname(AGENT_CONFIG_PATH);
1137
- if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
1138
- writeFileSync2(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
1139
- }
1140
- function getAgentRuntime(agentId) {
1141
- const config = loadAgentConfig();
1142
- const entry = config[agentId];
1143
- if (entry) return entry;
1144
- const orgDefault = config["default"];
1145
- if (orgDefault) return orgDefault;
1146
- return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
1147
- }
1148
- function setAgentRuntime(agentId, runtime, model) {
1149
- const knownModels = KNOWN_RUNTIMES[runtime];
1150
- if (!knownModels) {
1151
- return {
1152
- ok: false,
1153
- error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
1154
- };
1155
- }
1156
- if (!knownModels.includes(model)) {
1157
- return {
1158
- ok: false,
1159
- error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
1160
- };
1161
- }
1162
- const config = loadAgentConfig();
1163
- config[agentId] = { runtime, model };
1164
- saveAgentConfig(config);
1165
- return { ok: true };
1166
- }
1167
- function clearAgentRuntime(agentId) {
1168
- const config = loadAgentConfig();
1169
- delete config[agentId];
1170
- saveAgentConfig(config);
1171
- }
1172
- var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
1173
- var init_agent_config = __esm({
1174
- "src/lib/agent-config.ts"() {
1175
- "use strict";
1176
- init_config();
1177
- init_runtime_table();
1178
- AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
1179
- KNOWN_RUNTIMES = {
1180
- claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
1181
- codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
1182
- opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
1183
- };
1184
- RUNTIME_LABELS = {
1185
- claude: "Claude Code (Anthropic)",
1186
- codex: "Codex (OpenAI)",
1187
- opencode: "OpenCode (open source)"
1188
- };
1189
- DEFAULT_MODELS = {
1190
- claude: "claude-opus-4",
1191
- codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
1192
- opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
1193
- };
1194
- }
1195
- });
1196
-
1197
1268
  // src/bin/exe-call.ts
1198
1269
  init_employees();
1199
1270
  init_config();
1200
- import path4 from "path";
1271
+ import path5 from "path";
1201
1272
  import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1202
1273
  import { execSync as execSync2 } from "child_process";
1203
1274
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -1241,10 +1312,10 @@ function buildSessionEnv(employee, sessionDir) {
1241
1312
  env["AGENT_ROLE"] = employee.role;
1242
1313
  return env;
1243
1314
  }
1244
- async function prepareSessionDir(name, systemPrompt, sessionsBase = path4.join(EXE_AI_DIR, "sessions")) {
1245
- const sessionDir = path4.join(sessionsBase, name);
1315
+ async function prepareSessionDir(name, systemPrompt, sessionsBase = path5.join(EXE_AI_DIR, "sessions")) {
1316
+ const sessionDir = path5.join(sessionsBase, name);
1246
1317
  await mkdir3(sessionDir, { recursive: true });
1247
- await writeFile3(path4.join(sessionDir, "CLAUDE.md"), systemPrompt, "utf-8");
1318
+ await writeFile3(path5.join(sessionDir, "CLAUDE.md"), systemPrompt, "utf-8");
1248
1319
  return sessionDir;
1249
1320
  }
1250
1321
  if (isMainModule(import.meta.url)) {
@@ -1252,8 +1323,8 @@ if (isMainModule(import.meta.url)) {
1252
1323
  const employees = await loadEmployees();
1253
1324
  const coordinatorName = getCoordinatorName(employees);
1254
1325
  if (!name || name === coordinatorName) {
1255
- const __dirname = path4.dirname(fileURLToPath2(import.meta.url));
1256
- const bootPath = path4.join(__dirname, "exe-boot.js");
1326
+ const __dirname = path5.dirname(fileURLToPath2(import.meta.url));
1327
+ const bootPath = path5.join(__dirname, "exe-boot.js");
1257
1328
  try {
1258
1329
  execSync2(`node "${bootPath}"`, { stdio: "inherit" });
1259
1330
  } catch (err) {
@@ -1298,13 +1369,13 @@ if (isMainModule(import.meta.url)) {
1298
1369
  console.log(
1299
1370
  `Launching ${employee.name} (${employee.role}) on Codex (${rtConfig.model})...`
1300
1371
  );
1301
- const codexLauncher = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "exe-start-codex.js");
1372
+ const codexLauncher = path5.join(path5.dirname(fileURLToPath2(import.meta.url)), "exe-start-codex.js");
1302
1373
  execSync2(`node "${codexLauncher}" --agent ${employee.name}`, { stdio: "inherit", env });
1303
1374
  } else if (rtConfig.runtime === "opencode") {
1304
1375
  console.log(
1305
1376
  `Launching ${employee.name} (${employee.role}) on OpenCode (${rtConfig.model})...`
1306
1377
  );
1307
- const opencodeLauncher = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "exe-start-opencode.js");
1378
+ const opencodeLauncher = path5.join(path5.dirname(fileURLToPath2(import.meta.url)), "exe-start-opencode.js");
1308
1379
  execSync2(`node "${opencodeLauncher}" --agent ${employee.name}`, { stdio: "inherit", env });
1309
1380
  } else {
1310
1381
  console.log(
@@ -322,12 +322,34 @@ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as r
322
322
  import { execSync } from "child_process";
323
323
  import path3 from "path";
324
324
  import os3 from "os";
325
- var EMPLOYEES_PATH;
325
+ var EMPLOYEES_PATH, IDENTITY_DIR;
326
326
  var init_employees = __esm({
327
327
  "src/lib/employees.ts"() {
328
328
  "use strict";
329
329
  init_config();
330
330
  EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
331
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
332
+ }
333
+ });
334
+
335
+ // src/lib/database-adapter.ts
336
+ import os4 from "os";
337
+ import path4 from "path";
338
+ import { createRequire } from "module";
339
+ import { pathToFileURL } from "url";
340
+ var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
341
+ var init_database_adapter = __esm({
342
+ "src/lib/database-adapter.ts"() {
343
+ "use strict";
344
+ BOOLEAN_COLUMNS_BY_TABLE = {
345
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
346
+ behaviors: /* @__PURE__ */ new Set(["active"]),
347
+ notifications: /* @__PURE__ */ new Set(["read"]),
348
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
349
+ };
350
+ BOOLEAN_COLUMN_NAMES = new Set(
351
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
352
+ );
331
353
  }
332
354
  });
333
355
 
@@ -338,6 +360,7 @@ var init_database = __esm({
338
360
  "use strict";
339
361
  init_db_retry();
340
362
  init_employees();
363
+ init_database_adapter();
341
364
  }
342
365
  });
343
366
 
@@ -360,7 +383,7 @@ __export(license_exports, {
360
383
  });
361
384
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync } from "fs";
362
385
  import { randomUUID } from "crypto";
363
- import path4 from "path";
386
+ import path5 from "path";
364
387
  import { jwtVerify, importSPKI } from "jose";
365
388
  async function fetchRetry(url, init) {
366
389
  try {
@@ -371,7 +394,7 @@ async function fetchRetry(url, init) {
371
394
  }
372
395
  }
373
396
  function loadDeviceId() {
374
- const deviceJsonPath = path4.join(EXE_AI_DIR, "device.json");
397
+ const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
375
398
  try {
376
399
  if (existsSync4(deviceJsonPath)) {
377
400
  const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
@@ -536,7 +559,7 @@ async function checkLicense() {
536
559
  let key = loadLicense();
537
560
  if (!key) {
538
561
  try {
539
- const configPath = path4.join(EXE_AI_DIR, "config.json");
562
+ const configPath = path5.join(EXE_AI_DIR, "config.json");
540
563
  if (existsSync4(configPath)) {
541
564
  const raw = JSON.parse(readFileSync3(configPath, "utf8"));
542
565
  const cloud = raw.cloud;
@@ -697,9 +720,9 @@ var init_license = __esm({
697
720
  "src/lib/license.ts"() {
698
721
  "use strict";
699
722
  init_config();
700
- LICENSE_PATH = path4.join(EXE_AI_DIR, "license.key");
701
- CACHE_PATH = path4.join(EXE_AI_DIR, "license-cache.json");
702
- DEVICE_ID_PATH = path4.join(EXE_AI_DIR, "device-id");
723
+ LICENSE_PATH = path5.join(EXE_AI_DIR, "license.key");
724
+ CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
725
+ DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
703
726
  API_BASE = "https://askexe.com/cloud";
704
727
  RETRY_DELAY_MS = 500;
705
728
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -731,13 +754,13 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
731
754
  // src/lib/crdt-sync.ts
732
755
  import * as Y from "yjs";
733
756
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
734
- import path5 from "path";
757
+ import path6 from "path";
735
758
  import { homedir } from "os";
736
759
  var DEFAULT_STATE_PATH;
737
760
  var init_crdt_sync = __esm({
738
761
  "src/lib/crdt-sync.ts"() {
739
762
  "use strict";
740
- DEFAULT_STATE_PATH = path5.join(homedir(), ".exe-os", "crdt-state.bin");
763
+ DEFAULT_STATE_PATH = path6.join(homedir(), ".exe-os", "crdt-state.bin");
741
764
  }
742
765
  });
743
766
 
@@ -780,7 +803,7 @@ function isMainModule(importMetaUrl) {
780
803
  init_database();
781
804
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3, openSync, closeSync } from "fs";
782
805
  import crypto3 from "crypto";
783
- import path6 from "path";
806
+ import path7 from "path";
784
807
  import { homedir as homedir2 } from "os";
785
808
 
786
809
  // src/lib/crypto.ts
@@ -795,7 +818,7 @@ init_config();
795
818
  init_crdt_sync();
796
819
  init_employees();
797
820
  var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
798
- var ROSTER_LOCK_PATH = path6.join(EXE_AI_DIR, "roster-merge.lock");
821
+ var ROSTER_LOCK_PATH = path7.join(EXE_AI_DIR, "roster-merge.lock");
799
822
  function assertSecureEndpoint(endpoint) {
800
823
  if (endpoint.startsWith("https://")) return;
801
824
  if (endpoint.startsWith("http://")) {
@@ -810,7 +833,7 @@ function assertSecureEndpoint(endpoint) {
810
833
  );
811
834
  }
812
835
  }
813
- var ROSTER_DELETIONS_PATH = path6.join(EXE_AI_DIR, "roster-deletions.json");
836
+ var ROSTER_DELETIONS_PATH = path7.join(EXE_AI_DIR, "roster-deletions.json");
814
837
 
815
838
  // src/bin/exe-cloud.ts
816
839
  var BAR = "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550";