@askexenow/exe-os 0.9.38 → 0.9.39

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 (69) hide show
  1. package/dist/bin/backfill-conversations.js +34 -7
  2. package/dist/bin/backfill-responses.js +34 -7
  3. package/dist/bin/backfill-vectors.js +34 -7
  4. package/dist/bin/cleanup-stale-review-tasks.js +35 -8
  5. package/dist/bin/cli.js +72 -42
  6. package/dist/bin/exe-agent.js +11 -3
  7. package/dist/bin/exe-assign.js +34 -7
  8. package/dist/bin/exe-boot.js +48 -18
  9. package/dist/bin/exe-call.js +132 -340
  10. package/dist/bin/exe-dispatch.js +34 -7
  11. package/dist/bin/exe-doctor.js +37 -10
  12. package/dist/bin/exe-export-behaviors.js +36 -9
  13. package/dist/bin/exe-forget.js +34 -7
  14. package/dist/bin/exe-gateway.js +40 -12
  15. package/dist/bin/exe-heartbeat.js +35 -8
  16. package/dist/bin/exe-kill.js +34 -7
  17. package/dist/bin/exe-launch-agent.js +285 -1079
  18. package/dist/bin/exe-new-employee.js +29 -10
  19. package/dist/bin/exe-pending-messages.js +34 -7
  20. package/dist/bin/exe-pending-notifications.js +34 -7
  21. package/dist/bin/exe-pending-reviews.js +34 -7
  22. package/dist/bin/exe-rename.js +41 -13
  23. package/dist/bin/exe-review.js +34 -7
  24. package/dist/bin/exe-search.js +36 -9
  25. package/dist/bin/exe-session-cleanup.js +36 -9
  26. package/dist/bin/exe-start-codex.js +36 -9
  27. package/dist/bin/exe-start-opencode.js +36 -9
  28. package/dist/bin/exe-status.js +35 -8
  29. package/dist/bin/exe-team.js +34 -7
  30. package/dist/bin/git-sweep.js +34 -7
  31. package/dist/bin/graph-backfill.js +34 -7
  32. package/dist/bin/graph-export.js +34 -7
  33. package/dist/bin/install.js +2 -1
  34. package/dist/bin/intercom-check.js +36 -9
  35. package/dist/bin/scan-tasks.js +34 -7
  36. package/dist/bin/setup.js +18 -17
  37. package/dist/bin/shard-migrate.js +34 -7
  38. package/dist/gateway/index.js +38 -10
  39. package/dist/hooks/bug-report-worker.js +38 -10
  40. package/dist/hooks/codex-stop-task-finalizer.js +36 -9
  41. package/dist/hooks/commit-complete.js +34 -7
  42. package/dist/hooks/error-recall.js +36 -9
  43. package/dist/hooks/ingest.js +36 -8
  44. package/dist/hooks/instructions-loaded.js +42 -10
  45. package/dist/hooks/notification.js +34 -7
  46. package/dist/hooks/post-compact.js +34 -7
  47. package/dist/hooks/post-tool-combined.js +37 -10
  48. package/dist/hooks/pre-compact.js +35 -8
  49. package/dist/hooks/pre-tool-use.js +36 -8
  50. package/dist/hooks/prompt-submit.js +41 -13
  51. package/dist/hooks/session-end.js +35 -8
  52. package/dist/hooks/session-start.js +47 -14
  53. package/dist/hooks/stop.js +35 -8
  54. package/dist/hooks/subagent-stop.js +34 -7
  55. package/dist/hooks/summary-worker.js +43 -16
  56. package/dist/index.js +36 -8
  57. package/dist/lib/consolidation.js +2 -1
  58. package/dist/lib/employee-templates.js +2 -1
  59. package/dist/lib/employees.js +2 -1
  60. package/dist/lib/exe-daemon.js +136 -36
  61. package/dist/lib/hybrid-search.js +36 -9
  62. package/dist/lib/identity.js +8 -3
  63. package/dist/lib/schedules.js +34 -7
  64. package/dist/lib/store.js +34 -7
  65. package/dist/mcp/server.js +133 -33
  66. package/dist/mcp/tools/create-task.js +10 -4
  67. package/dist/runtime/index.js +34 -7
  68. package/dist/tui/App.js +40 -11
  69. package/package.json +1 -1
@@ -126,153 +126,11 @@ var init_config = __esm({
126
126
  }
127
127
  });
128
128
 
129
- // src/lib/runtime-table.ts
130
- var RUNTIME_TABLE, DEFAULT_RUNTIME;
131
- var init_runtime_table = __esm({
132
- "src/lib/runtime-table.ts"() {
133
- "use strict";
134
- RUNTIME_TABLE = {
135
- codex: {
136
- binary: "codex",
137
- launchMode: "interactive",
138
- autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
139
- inlineFlag: "--no-alt-screen",
140
- apiKeyEnv: "OPENAI_API_KEY",
141
- defaultModel: "gpt-5.5"
142
- },
143
- opencode: {
144
- binary: "opencode",
145
- launchMode: "exec",
146
- autoApproveFlag: "--dangerously-skip-permissions",
147
- inlineFlag: "",
148
- apiKeyEnv: "ANTHROPIC_API_KEY",
149
- defaultModel: "anthropic/claude-sonnet-4-6"
150
- }
151
- };
152
- DEFAULT_RUNTIME = "claude";
153
- }
154
- });
155
-
156
- // src/lib/agent-config.ts
157
- var agent_config_exports = {};
158
- __export(agent_config_exports, {
159
- AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
160
- DEFAULT_MODELS: () => DEFAULT_MODELS,
161
- KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
162
- RUNTIME_LABELS: () => RUNTIME_LABELS,
163
- clearAgentRuntime: () => clearAgentRuntime,
164
- getAgentRuntime: () => getAgentRuntime,
165
- loadAgentConfig: () => loadAgentConfig,
166
- saveAgentConfig: () => saveAgentConfig,
167
- setAgentRuntime: () => setAgentRuntime
168
- });
169
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
170
- import path2 from "path";
171
- function loadAgentConfig() {
172
- if (!existsSync3(AGENT_CONFIG_PATH)) return {};
173
- try {
174
- return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
175
- } catch {
176
- return {};
177
- }
178
- }
179
- function saveAgentConfig(config) {
180
- const dir = path2.dirname(AGENT_CONFIG_PATH);
181
- ensurePrivateDirSync(dir);
182
- writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
183
- enforcePrivateFileSync(AGENT_CONFIG_PATH);
184
- }
185
- function getAgentRuntime(agentId) {
186
- const config = loadAgentConfig();
187
- const entry = config[agentId];
188
- if (entry) return entry;
189
- const orgDefault = config["default"];
190
- if (orgDefault) return orgDefault;
191
- return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
192
- }
193
- function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
194
- const knownModels = KNOWN_RUNTIMES[runtime];
195
- if (!knownModels) {
196
- return {
197
- ok: false,
198
- error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
199
- };
200
- }
201
- if (!knownModels.includes(model)) {
202
- return {
203
- ok: false,
204
- error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
205
- };
206
- }
207
- const config = loadAgentConfig();
208
- const entry = { runtime, model };
209
- if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
210
- config[agentId] = entry;
211
- saveAgentConfig(config);
212
- return { ok: true };
213
- }
214
- function clearAgentRuntime(agentId) {
215
- const config = loadAgentConfig();
216
- delete config[agentId];
217
- saveAgentConfig(config);
218
- }
219
- var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
220
- var init_agent_config = __esm({
221
- "src/lib/agent-config.ts"() {
222
- "use strict";
223
- init_config();
224
- init_runtime_table();
225
- init_secure_files();
226
- AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
227
- KNOWN_RUNTIMES = {
228
- claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
229
- codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
230
- opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
231
- };
232
- RUNTIME_LABELS = {
233
- claude: "Claude Code (Anthropic)",
234
- codex: "Codex (OpenAI)",
235
- opencode: "OpenCode (open source)"
236
- };
237
- DEFAULT_MODELS = {
238
- claude: "claude-opus-4.6",
239
- codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
240
- opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
241
- };
242
- }
243
- });
244
-
245
129
  // src/lib/employees.ts
246
- var employees_exports = {};
247
- __export(employees_exports, {
248
- COORDINATOR_ROLE: () => COORDINATOR_ROLE,
249
- DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
250
- EMPLOYEES_PATH: () => EMPLOYEES_PATH,
251
- addEmployee: () => addEmployee,
252
- baseAgentName: () => baseAgentName,
253
- canCoordinate: () => canCoordinate,
254
- getCoordinatorEmployee: () => getCoordinatorEmployee,
255
- getCoordinatorName: () => getCoordinatorName,
256
- getEmployee: () => getEmployee,
257
- getEmployeeByRole: () => getEmployeeByRole,
258
- getEmployeeNamesByRole: () => getEmployeeNamesByRole,
259
- hasRole: () => hasRole,
260
- hireEmployee: () => hireEmployee,
261
- isCoordinatorName: () => isCoordinatorName,
262
- isCoordinatorRole: () => isCoordinatorRole,
263
- isMultiInstance: () => isMultiInstance,
264
- loadEmployees: () => loadEmployees,
265
- loadEmployeesSync: () => loadEmployeesSync,
266
- normalizeRole: () => normalizeRole,
267
- normalizeRosterCase: () => normalizeRosterCase,
268
- registerBinSymlinks: () => registerBinSymlinks,
269
- saveEmployees: () => saveEmployees,
270
- validateEmployeeName: () => validateEmployeeName
271
- });
272
130
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
273
- import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
131
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
274
132
  import { execSync } from "child_process";
275
- import path3 from "path";
133
+ import path2 from "path";
276
134
  import os2 from "os";
277
135
  function normalizeRole(role) {
278
136
  return (role ?? "").trim().toLowerCase();
@@ -286,30 +144,8 @@ function getCoordinatorEmployee(employees) {
286
144
  function getCoordinatorName(employees = loadEmployeesSync()) {
287
145
  return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
288
146
  }
289
- function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
290
- if (!agentName) return false;
291
- return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
292
- }
293
- function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
294
- return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
295
- }
296
- function validateEmployeeName(name) {
297
- if (!name) {
298
- return { valid: false, error: "Name is required" };
299
- }
300
- if (name.length > 32) {
301
- return { valid: false, error: "Name must be 32 characters or fewer" };
302
- }
303
- if (!/^[a-z][a-z0-9]*$/.test(name)) {
304
- return {
305
- valid: false,
306
- error: "Name must start with a letter and contain only lowercase alphanumeric characters"
307
- };
308
- }
309
- return { valid: true };
310
- }
311
147
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
312
- if (!existsSync4(employeesPath)) {
148
+ if (!existsSync3(employeesPath)) {
313
149
  return [];
314
150
  }
315
151
  const raw = await readFile2(employeesPath, "utf-8");
@@ -319,14 +155,10 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
319
155
  return [];
320
156
  }
321
157
  }
322
- async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
323
- await mkdir2(path3.dirname(employeesPath), { recursive: true });
324
- await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
325
- }
326
158
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
327
- if (!existsSync4(employeesPath)) return [];
159
+ if (!existsSync3(employeesPath)) return [];
328
160
  try {
329
- return JSON.parse(readFileSync3(employeesPath, "utf-8"));
161
+ return JSON.parse(readFileSync2(employeesPath, "utf-8"));
330
162
  } catch {
331
163
  return [];
332
164
  }
@@ -334,167 +166,15 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
334
166
  function getEmployee(employees, name) {
335
167
  return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
336
168
  }
337
- function getEmployeeByRole(employees, role) {
338
- const lower = role.toLowerCase();
339
- return employees.find((e) => e.role.toLowerCase() === lower);
340
- }
341
- function getEmployeeNamesByRole(employees, role) {
342
- const lower = role.toLowerCase();
343
- return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
344
- }
345
- function hasRole(agentName, role) {
346
- const employees = loadEmployeesSync();
347
- const emp = getEmployee(employees, agentName);
348
- return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
349
- }
350
- function baseAgentName(name, employees) {
351
- const match = name.match(/^([a-zA-Z]+)\d+$/);
352
- if (!match) return name;
353
- const base = match[1];
354
- const roster = employees ?? loadEmployeesSync();
355
- if (getEmployee(roster, base)) return base;
356
- return name;
357
- }
358
- function isMultiInstance(agentName, employees) {
359
- const roster = employees ?? loadEmployeesSync();
360
- const emp = getEmployee(roster, agentName);
361
- if (!emp) return false;
362
- return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
363
- }
364
- function addEmployee(employees, employee) {
365
- const normalized = { ...employee, name: employee.name.toLowerCase() };
366
- if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
367
- throw new Error(`Employee '${normalized.name}' already exists`);
368
- }
369
- return [...employees, normalized];
370
- }
371
- function appendToCoordinatorTeam(employee) {
372
- const coordinator = getCoordinatorEmployee(loadEmployeesSync());
373
- if (!coordinator) return;
374
- const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
375
- if (!existsSync4(idPath)) return;
376
- const content = readFileSync3(idPath, "utf-8");
377
- if (content.includes(`**${capitalize(employee.name)}`)) return;
378
- const teamMatch = content.match(TEAM_SECTION_RE);
379
- if (!teamMatch || teamMatch.index === void 0) return;
380
- const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
381
- const nextHeading = afterTeam.match(/\n## /);
382
- const entry = `
383
- **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
384
- `;
385
- let updated;
386
- if (nextHeading && nextHeading.index !== void 0) {
387
- const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
388
- updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
389
- } else {
390
- updated = content.trimEnd() + "\n" + entry;
391
- }
392
- writeFileSync2(idPath, updated, "utf-8");
393
- }
394
- function capitalize(s) {
395
- return s.charAt(0).toUpperCase() + s.slice(1);
396
- }
397
- async function hireEmployee(employee) {
398
- const employees = await loadEmployees();
399
- const updated = addEmployee(employees, employee);
400
- await saveEmployees(updated);
401
- try {
402
- appendToCoordinatorTeam(employee);
403
- } catch {
404
- }
405
- try {
406
- const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
407
- const config = loadAgentConfig2();
408
- const name = employee.name.toLowerCase();
409
- if (!config[name] && config["default"]) {
410
- config[name] = { ...config["default"] };
411
- saveAgentConfig2(config);
412
- }
413
- } catch {
414
- }
415
- return updated;
416
- }
417
- async function normalizeRosterCase(rosterPath) {
418
- const employees = await loadEmployees(rosterPath);
419
- let changed = false;
420
- for (const emp of employees) {
421
- if (emp.name !== emp.name.toLowerCase()) {
422
- const oldName = emp.name;
423
- emp.name = emp.name.toLowerCase();
424
- changed = true;
425
- try {
426
- const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
427
- const oldPath = path3.join(identityDir, `${oldName}.md`);
428
- const newPath = path3.join(identityDir, `${emp.name}.md`);
429
- if (existsSync4(oldPath) && !existsSync4(newPath)) {
430
- renameSync2(oldPath, newPath);
431
- } else if (existsSync4(oldPath) && oldPath !== newPath) {
432
- const content = readFileSync3(oldPath, "utf-8");
433
- writeFileSync2(newPath, content, "utf-8");
434
- if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
435
- unlinkSync(oldPath);
436
- }
437
- }
438
- } catch {
439
- }
440
- }
441
- }
442
- if (changed) {
443
- await saveEmployees(employees, rosterPath);
444
- }
445
- return changed;
446
- }
447
- function findExeBin() {
448
- try {
449
- return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
450
- } catch {
451
- return null;
452
- }
453
- }
454
- function registerBinSymlinks(name) {
455
- const created = [];
456
- const skipped = [];
457
- const errors = [];
458
- const exeBinPath = findExeBin();
459
- if (!exeBinPath) {
460
- errors.push("Could not find 'exe-os' in PATH");
461
- return { created, skipped, errors };
462
- }
463
- const binDir = path3.dirname(exeBinPath);
464
- let target;
465
- try {
466
- target = readlinkSync(exeBinPath);
467
- } catch {
468
- errors.push("Could not read 'exe' symlink");
469
- return { created, skipped, errors };
470
- }
471
- for (const suffix of ["", "-opencode"]) {
472
- const linkName = `${name}${suffix}`;
473
- const linkPath = path3.join(binDir, linkName);
474
- if (existsSync4(linkPath)) {
475
- skipped.push(linkName);
476
- continue;
477
- }
478
- try {
479
- symlinkSync(target, linkPath);
480
- created.push(linkName);
481
- } catch (err) {
482
- errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
483
- }
484
- }
485
- return { created, skipped, errors };
486
- }
487
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
169
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
488
170
  var init_employees = __esm({
489
171
  "src/lib/employees.ts"() {
490
172
  "use strict";
491
173
  init_config();
492
- EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
174
+ EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
493
175
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
494
176
  COORDINATOR_ROLE = "COO";
495
- MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
496
- IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
497
- TEAM_SECTION_RE = /^## Team\b.*$/m;
177
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
498
178
  }
499
179
  });
500
180
 
@@ -507,7 +187,7 @@ var init_db_retry = __esm({
507
187
 
508
188
  // src/lib/database-adapter.ts
509
189
  import os3 from "os";
510
- import path4 from "path";
190
+ import path3 from "path";
511
191
  import { createRequire } from "module";
512
192
  import { pathToFileURL } from "url";
513
193
  var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
@@ -765,7 +445,8 @@ __export(employee_templates_exports, {
765
445
  });
766
446
  function getSessionPrompt(storedPrompt) {
767
447
  const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
768
- const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
448
+ const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
449
+ const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
769
450
  const globalBlock = getGlobalProceduresBlock();
770
451
  return `${globalBlock}${rolePrompt}
771
452
  ${BASE_OPERATING_PROCEDURES}`;
@@ -1367,10 +1048,127 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
1367
1048
  }
1368
1049
  });
1369
1050
 
1051
+ // src/lib/runtime-table.ts
1052
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
1053
+ var init_runtime_table = __esm({
1054
+ "src/lib/runtime-table.ts"() {
1055
+ "use strict";
1056
+ RUNTIME_TABLE = {
1057
+ codex: {
1058
+ binary: "codex",
1059
+ launchMode: "interactive",
1060
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
1061
+ inlineFlag: "--no-alt-screen",
1062
+ apiKeyEnv: "OPENAI_API_KEY",
1063
+ defaultModel: "gpt-5.5"
1064
+ },
1065
+ opencode: {
1066
+ binary: "opencode",
1067
+ launchMode: "exec",
1068
+ autoApproveFlag: "--dangerously-skip-permissions",
1069
+ inlineFlag: "",
1070
+ apiKeyEnv: "ANTHROPIC_API_KEY",
1071
+ defaultModel: "anthropic/claude-sonnet-4-6"
1072
+ }
1073
+ };
1074
+ DEFAULT_RUNTIME = "claude";
1075
+ }
1076
+ });
1077
+
1078
+ // src/lib/agent-config.ts
1079
+ var agent_config_exports = {};
1080
+ __export(agent_config_exports, {
1081
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
1082
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
1083
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
1084
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
1085
+ clearAgentRuntime: () => clearAgentRuntime,
1086
+ getAgentRuntime: () => getAgentRuntime,
1087
+ loadAgentConfig: () => loadAgentConfig,
1088
+ saveAgentConfig: () => saveAgentConfig,
1089
+ setAgentRuntime: () => setAgentRuntime
1090
+ });
1091
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
1092
+ import path4 from "path";
1093
+ function loadAgentConfig() {
1094
+ if (!existsSync4(AGENT_CONFIG_PATH)) return {};
1095
+ try {
1096
+ return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
1097
+ } catch {
1098
+ return {};
1099
+ }
1100
+ }
1101
+ function saveAgentConfig(config) {
1102
+ const dir = path4.dirname(AGENT_CONFIG_PATH);
1103
+ ensurePrivateDirSync(dir);
1104
+ writeFileSync2(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
1105
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
1106
+ }
1107
+ function getAgentRuntime(agentId) {
1108
+ const config = loadAgentConfig();
1109
+ const entry = config[agentId];
1110
+ if (entry) return entry;
1111
+ const orgDefault = config["default"];
1112
+ if (orgDefault) return orgDefault;
1113
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
1114
+ }
1115
+ function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
1116
+ const knownModels = KNOWN_RUNTIMES[runtime];
1117
+ if (!knownModels) {
1118
+ return {
1119
+ ok: false,
1120
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
1121
+ };
1122
+ }
1123
+ if (!knownModels.includes(model)) {
1124
+ return {
1125
+ ok: false,
1126
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
1127
+ };
1128
+ }
1129
+ const config = loadAgentConfig();
1130
+ const entry = { runtime, model };
1131
+ if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
1132
+ config[agentId] = entry;
1133
+ saveAgentConfig(config);
1134
+ return { ok: true };
1135
+ }
1136
+ function clearAgentRuntime(agentId) {
1137
+ const config = loadAgentConfig();
1138
+ delete config[agentId];
1139
+ saveAgentConfig(config);
1140
+ }
1141
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
1142
+ var init_agent_config = __esm({
1143
+ "src/lib/agent-config.ts"() {
1144
+ "use strict";
1145
+ init_config();
1146
+ init_runtime_table();
1147
+ init_secure_files();
1148
+ AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
1149
+ KNOWN_RUNTIMES = {
1150
+ claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
1151
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
1152
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
1153
+ };
1154
+ RUNTIME_LABELS = {
1155
+ claude: "Claude Code (Anthropic)",
1156
+ codex: "Codex (OpenAI)",
1157
+ opencode: "OpenCode (open source)"
1158
+ };
1159
+ DEFAULT_MODELS = {
1160
+ claude: "claude-opus-4.6",
1161
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
1162
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
1163
+ };
1164
+ }
1165
+ });
1166
+
1370
1167
  // src/bin/exe-call.ts
1371
1168
  init_employees();
1372
1169
  init_config();
1373
1170
  import path5 from "path";
1171
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1374
1172
  import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1375
1173
  import { execSync as execSync2 } from "child_process";
1376
1174
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -1441,7 +1239,8 @@ if (isMainModule(import.meta.url)) {
1441
1239
  process.exit(1);
1442
1240
  }
1443
1241
  const employee = resolveEmployee(name, employees);
1444
- let prompt = employee.systemPrompt;
1242
+ const identityPath = path5.join(EXE_AI_DIR, "identity", `${employee.name}.md`);
1243
+ let prompt = existsSync5(identityPath) ? readFileSync4(identityPath, "utf-8") : employee.systemPrompt;
1445
1244
  if (!prompt || prompt.trim().length < 20) {
1446
1245
  const { DEFAULT_EXE: DEFAULT_EXE2, TEMPLATES: TEMPLATES2, personalizePrompt: personalizePrompt2 } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
1447
1246
  if (employee.role === "COO") {
@@ -1453,17 +1252,10 @@ if (isMainModule(import.meta.url)) {
1453
1252
  } else {
1454
1253
  const templateKey = employee.templateName ?? employee.name;
1455
1254
  const template = TEMPLATES2[templateKey];
1456
- if (template) {
1457
- prompt = personalizePrompt2(template.systemPrompt, templateKey, employee.name);
1458
- }
1459
- }
1460
- if (prompt && prompt.length > 20) {
1461
- const { saveEmployees: saveEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
1462
- employee.systemPrompt = prompt;
1463
- await saveEmployees2(employees);
1255
+ if (template) prompt = personalizePrompt2(template.systemPrompt, templateKey, employee.name);
1464
1256
  }
1465
1257
  }
1466
- const sessionDir = await prepareSessionDir(name, getSessionPrompt(prompt));
1258
+ const sessionDir = await prepareSessionDir(name, getSessionPrompt(prompt ?? ""));
1467
1259
  const env = buildSessionEnv(employee, sessionDir);
1468
1260
  const { getAgentRuntime: getAgentRuntime2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
1469
1261
  const rtConfig = getAgentRuntime2(employee.name);
@@ -6934,7 +6934,7 @@ __export(shard_manager_exports, {
6934
6934
  shardExists: () => shardExists
6935
6935
  });
6936
6936
  import path19 from "path";
6937
- import { existsSync as existsSync16, mkdirSync as mkdirSync7, readdirSync as readdirSync4 } from "fs";
6937
+ import { existsSync as existsSync16, mkdirSync as mkdirSync7, readdirSync as readdirSync4, renameSync as renameSync4, statSync as statSync2 } from "fs";
6938
6938
  import { createClient as createClient2 } from "@libsql/client";
6939
6939
  function initShardManager(encryptionKey) {
6940
6940
  _encryptionKey = encryptionKey;
@@ -6956,7 +6956,7 @@ function getShardClient(projectName) {
6956
6956
  if (!_encryptionKey) {
6957
6957
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
6958
6958
  }
6959
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
6959
+ const safeName = safeShardName(projectName);
6960
6960
  if (!safeName || safeName === "unknown") {
6961
6961
  throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
6962
6962
  }
@@ -6978,9 +6978,12 @@ function getShardClient(projectName) {
6978
6978
  return client;
6979
6979
  }
6980
6980
  function shardExists(projectName) {
6981
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
6981
+ const safeName = safeShardName(projectName);
6982
6982
  return existsSync16(path19.join(SHARDS_DIR, `${safeName}.db`));
6983
6983
  }
6984
+ function safeShardName(projectName) {
6985
+ return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
6986
+ }
6984
6987
  function listShards() {
6985
6988
  if (!existsSync16(SHARDS_DIR)) return [];
6986
6989
  return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
@@ -7074,7 +7077,8 @@ async function ensureShardSchema(client) {
7074
7077
  "ALTER TABLE memories ADD COLUMN token_cost REAL",
7075
7078
  "ALTER TABLE memories ADD COLUMN audience TEXT",
7076
7079
  "ALTER TABLE memories ADD COLUMN language_type TEXT",
7077
- "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
7080
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
7081
+ "ALTER TABLE memories ADD COLUMN deleted_at TEXT"
7078
7082
  ]) {
7079
7083
  try {
7080
7084
  await client.execute(col);
@@ -7170,9 +7174,32 @@ async function ensureShardSchema(client) {
7170
7174
  }
7171
7175
  }
7172
7176
  async function getReadyShardClient(projectName) {
7173
- const client = getShardClient(projectName);
7174
- await ensureShardSchema(client);
7175
- return client;
7177
+ const safeName = safeShardName(projectName);
7178
+ let client = getShardClient(projectName);
7179
+ try {
7180
+ await ensureShardSchema(client);
7181
+ return client;
7182
+ } catch (err) {
7183
+ const message = err instanceof Error ? err.message : String(err);
7184
+ if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
7185
+ client.close();
7186
+ _shards.delete(safeName);
7187
+ _shardLastAccess.delete(safeName);
7188
+ const dbPath = path19.join(SHARDS_DIR, `${safeName}.db`);
7189
+ if (existsSync16(dbPath)) {
7190
+ const stat = statSync2(dbPath);
7191
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7192
+ const archivedPath = path19.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
7193
+ renameSync4(dbPath, archivedPath);
7194
+ process.stderr.write(
7195
+ `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
7196
+ `
7197
+ );
7198
+ }
7199
+ client = getShardClient(projectName);
7200
+ await ensureShardSchema(client);
7201
+ return client;
7202
+ }
7176
7203
  }
7177
7204
  function evictLRU() {
7178
7205
  let oldest = null;