@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
@@ -253,6 +253,118 @@ var init_config = __esm({
253
253
  }
254
254
  });
255
255
 
256
+ // src/lib/runtime-table.ts
257
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
258
+ var init_runtime_table = __esm({
259
+ "src/lib/runtime-table.ts"() {
260
+ "use strict";
261
+ RUNTIME_TABLE = {
262
+ codex: {
263
+ binary: "codex",
264
+ launchMode: "interactive",
265
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
266
+ inlineFlag: "--no-alt-screen",
267
+ apiKeyEnv: "OPENAI_API_KEY",
268
+ defaultModel: "gpt-5.4"
269
+ },
270
+ opencode: {
271
+ binary: "opencode",
272
+ launchMode: "exec",
273
+ autoApproveFlag: "--dangerously-skip-permissions",
274
+ inlineFlag: "",
275
+ apiKeyEnv: "ANTHROPIC_API_KEY",
276
+ defaultModel: "anthropic/claude-sonnet-4-6"
277
+ }
278
+ };
279
+ DEFAULT_RUNTIME = "claude";
280
+ }
281
+ });
282
+
283
+ // src/lib/agent-config.ts
284
+ var agent_config_exports = {};
285
+ __export(agent_config_exports, {
286
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
287
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
288
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
289
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
290
+ clearAgentRuntime: () => clearAgentRuntime,
291
+ getAgentRuntime: () => getAgentRuntime,
292
+ loadAgentConfig: () => loadAgentConfig,
293
+ saveAgentConfig: () => saveAgentConfig,
294
+ setAgentRuntime: () => setAgentRuntime
295
+ });
296
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
297
+ import path2 from "path";
298
+ function loadAgentConfig() {
299
+ if (!existsSync2(AGENT_CONFIG_PATH)) return {};
300
+ try {
301
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
302
+ } catch {
303
+ return {};
304
+ }
305
+ }
306
+ function saveAgentConfig(config) {
307
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
308
+ if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
309
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
310
+ }
311
+ function getAgentRuntime(agentId) {
312
+ const config = loadAgentConfig();
313
+ const entry = config[agentId];
314
+ if (entry) return entry;
315
+ const orgDefault = config["default"];
316
+ if (orgDefault) return orgDefault;
317
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
318
+ }
319
+ function setAgentRuntime(agentId, runtime, model) {
320
+ const knownModels = KNOWN_RUNTIMES[runtime];
321
+ if (!knownModels) {
322
+ return {
323
+ ok: false,
324
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
325
+ };
326
+ }
327
+ if (!knownModels.includes(model)) {
328
+ return {
329
+ ok: false,
330
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
331
+ };
332
+ }
333
+ const config = loadAgentConfig();
334
+ config[agentId] = { runtime, model };
335
+ saveAgentConfig(config);
336
+ return { ok: true };
337
+ }
338
+ function clearAgentRuntime(agentId) {
339
+ const config = loadAgentConfig();
340
+ delete config[agentId];
341
+ saveAgentConfig(config);
342
+ }
343
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
344
+ var init_agent_config = __esm({
345
+ "src/lib/agent-config.ts"() {
346
+ "use strict";
347
+ init_config();
348
+ init_runtime_table();
349
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
350
+ KNOWN_RUNTIMES = {
351
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
352
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
353
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
354
+ };
355
+ RUNTIME_LABELS = {
356
+ claude: "Claude Code (Anthropic)",
357
+ codex: "Codex (OpenAI)",
358
+ opencode: "OpenCode (open source)"
359
+ };
360
+ DEFAULT_MODELS = {
361
+ claude: "claude-opus-4",
362
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
363
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
364
+ };
365
+ }
366
+ });
367
+
256
368
  // src/lib/employees.ts
257
369
  var employees_exports = {};
258
370
  __export(employees_exports, {
@@ -268,6 +380,7 @@ __export(employees_exports, {
268
380
  getEmployeeByRole: () => getEmployeeByRole,
269
381
  getEmployeeNamesByRole: () => getEmployeeNamesByRole,
270
382
  hasRole: () => hasRole,
383
+ hireEmployee: () => hireEmployee,
271
384
  isCoordinatorName: () => isCoordinatorName,
272
385
  isCoordinatorRole: () => isCoordinatorRole,
273
386
  isMultiInstance: () => isMultiInstance,
@@ -280,9 +393,9 @@ __export(employees_exports, {
280
393
  validateEmployeeName: () => validateEmployeeName
281
394
  });
282
395
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
283
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
396
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
284
397
  import { execSync } from "child_process";
285
- import path2 from "path";
398
+ import path3 from "path";
286
399
  import os2 from "os";
287
400
  function normalizeRole(role) {
288
401
  return (role ?? "").trim().toLowerCase();
@@ -319,7 +432,7 @@ function validateEmployeeName(name) {
319
432
  return { valid: true };
320
433
  }
321
434
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
322
- if (!existsSync2(employeesPath)) {
435
+ if (!existsSync3(employeesPath)) {
323
436
  return [];
324
437
  }
325
438
  const raw = await readFile2(employeesPath, "utf-8");
@@ -330,13 +443,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
330
443
  }
331
444
  }
332
445
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
333
- await mkdir2(path2.dirname(employeesPath), { recursive: true });
446
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
334
447
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
335
448
  }
336
449
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
337
- if (!existsSync2(employeesPath)) return [];
450
+ if (!existsSync3(employeesPath)) return [];
338
451
  try {
339
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
452
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
340
453
  } catch {
341
454
  return [];
342
455
  }
@@ -378,6 +491,52 @@ function addEmployee(employees, employee) {
378
491
  }
379
492
  return [...employees, normalized];
380
493
  }
494
+ function appendToCoordinatorTeam(employee) {
495
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
496
+ if (!coordinator) return;
497
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
498
+ if (!existsSync3(idPath)) return;
499
+ const content = readFileSync3(idPath, "utf-8");
500
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
501
+ const teamMatch = content.match(TEAM_SECTION_RE);
502
+ if (!teamMatch || teamMatch.index === void 0) return;
503
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
504
+ const nextHeading = afterTeam.match(/\n## /);
505
+ const entry = `
506
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
507
+ `;
508
+ let updated;
509
+ if (nextHeading && nextHeading.index !== void 0) {
510
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
511
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
512
+ } else {
513
+ updated = content.trimEnd() + "\n" + entry;
514
+ }
515
+ writeFileSync2(idPath, updated, "utf-8");
516
+ }
517
+ function capitalize(s) {
518
+ return s.charAt(0).toUpperCase() + s.slice(1);
519
+ }
520
+ async function hireEmployee(employee) {
521
+ const employees = await loadEmployees();
522
+ const updated = addEmployee(employees, employee);
523
+ await saveEmployees(updated);
524
+ try {
525
+ appendToCoordinatorTeam(employee);
526
+ } catch {
527
+ }
528
+ try {
529
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
530
+ const config = loadAgentConfig2();
531
+ const name = employee.name.toLowerCase();
532
+ if (!config[name] && config["default"]) {
533
+ config[name] = { ...config["default"] };
534
+ saveAgentConfig2(config);
535
+ }
536
+ } catch {
537
+ }
538
+ return updated;
539
+ }
381
540
  async function normalizeRosterCase(rosterPath) {
382
541
  const employees = await loadEmployees(rosterPath);
383
542
  let changed = false;
@@ -387,14 +546,14 @@ async function normalizeRosterCase(rosterPath) {
387
546
  emp.name = emp.name.toLowerCase();
388
547
  changed = true;
389
548
  try {
390
- const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
391
- const oldPath = path2.join(identityDir, `${oldName}.md`);
392
- const newPath = path2.join(identityDir, `${emp.name}.md`);
393
- if (existsSync2(oldPath) && !existsSync2(newPath)) {
549
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
550
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
551
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
552
+ if (existsSync3(oldPath) && !existsSync3(newPath)) {
394
553
  renameSync2(oldPath, newPath);
395
- } else if (existsSync2(oldPath) && oldPath !== newPath) {
396
- const content = readFileSync2(oldPath, "utf-8");
397
- writeFileSync(newPath, content, "utf-8");
554
+ } else if (existsSync3(oldPath) && oldPath !== newPath) {
555
+ const content = readFileSync3(oldPath, "utf-8");
556
+ writeFileSync2(newPath, content, "utf-8");
398
557
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
399
558
  unlinkSync(oldPath);
400
559
  }
@@ -424,7 +583,7 @@ function registerBinSymlinks(name) {
424
583
  errors.push("Could not find 'exe-os' in PATH");
425
584
  return { created, skipped, errors };
426
585
  }
427
- const binDir = path2.dirname(exeBinPath);
586
+ const binDir = path3.dirname(exeBinPath);
428
587
  let target;
429
588
  try {
430
589
  target = readlinkSync(exeBinPath);
@@ -434,8 +593,8 @@ function registerBinSymlinks(name) {
434
593
  }
435
594
  for (const suffix of ["", "-opencode"]) {
436
595
  const linkName = `${name}${suffix}`;
437
- const linkPath = path2.join(binDir, linkName);
438
- if (existsSync2(linkPath)) {
596
+ const linkPath = path3.join(binDir, linkName);
597
+ if (existsSync3(linkPath)) {
439
598
  skipped.push(linkName);
440
599
  continue;
441
600
  }
@@ -448,21 +607,619 @@ function registerBinSymlinks(name) {
448
607
  }
449
608
  return { created, skipped, errors };
450
609
  }
451
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
610
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
452
611
  var init_employees = __esm({
453
612
  "src/lib/employees.ts"() {
454
613
  "use strict";
455
614
  init_config();
456
- EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
615
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
457
616
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
458
617
  COORDINATOR_ROLE = "COO";
459
618
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
619
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
620
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
621
+ }
622
+ });
623
+
624
+ // src/lib/database-adapter.ts
625
+ import os3 from "os";
626
+ import path4 from "path";
627
+ import { createRequire } from "module";
628
+ import { pathToFileURL } from "url";
629
+ function quotedIdentifier(identifier) {
630
+ return `"${identifier.replace(/"/g, '""')}"`;
631
+ }
632
+ function unqualifiedTableName(name) {
633
+ const raw = name.trim().replace(/^"|"$/g, "");
634
+ const parts = raw.split(".");
635
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
636
+ }
637
+ function stripTrailingSemicolon(sql) {
638
+ return sql.trim().replace(/;+\s*$/u, "");
639
+ }
640
+ function appendClause(sql, clause) {
641
+ const trimmed = stripTrailingSemicolon(sql);
642
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
643
+ if (!returningMatch) {
644
+ return `${trimmed}${clause}`;
645
+ }
646
+ const idx = returningMatch.index;
647
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
648
+ }
649
+ function normalizeStatement(stmt) {
650
+ if (typeof stmt === "string") {
651
+ return { kind: "positional", sql: stmt, args: [] };
652
+ }
653
+ const sql = stmt.sql;
654
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
655
+ return { kind: "positional", sql, args: stmt.args ?? [] };
656
+ }
657
+ return { kind: "named", sql, args: stmt.args };
658
+ }
659
+ function rewriteBooleanLiterals(sql) {
660
+ let out = sql;
661
+ for (const column of BOOLEAN_COLUMN_NAMES) {
662
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
663
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
664
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
665
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
666
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
667
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
668
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
669
+ }
670
+ return out;
671
+ }
672
+ function rewriteInsertOrIgnore(sql) {
673
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
674
+ return sql;
675
+ }
676
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
677
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
678
+ }
679
+ function rewriteInsertOrReplace(sql) {
680
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
681
+ if (!match) {
682
+ return sql;
683
+ }
684
+ const rawTable = match[1];
685
+ const rawColumns = match[2];
686
+ const remainder = match[3];
687
+ const tableName = unqualifiedTableName(rawTable);
688
+ const conflictKeys = UPSERT_KEYS[tableName];
689
+ if (!conflictKeys?.length) {
690
+ return sql;
691
+ }
692
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
693
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
694
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
695
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
696
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
697
+ }
698
+ function rewriteSql(sql) {
699
+ let out = sql;
700
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
701
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
702
+ out = rewriteBooleanLiterals(out);
703
+ out = rewriteInsertOrReplace(out);
704
+ out = rewriteInsertOrIgnore(out);
705
+ return stripTrailingSemicolon(out);
706
+ }
707
+ function toBoolean(value) {
708
+ if (value === null || value === void 0) return value;
709
+ if (typeof value === "boolean") return value;
710
+ if (typeof value === "number") return value !== 0;
711
+ if (typeof value === "bigint") return value !== 0n;
712
+ if (typeof value === "string") {
713
+ const normalized = value.trim().toLowerCase();
714
+ if (normalized === "0" || normalized === "false") return false;
715
+ if (normalized === "1" || normalized === "true") return true;
716
+ }
717
+ return Boolean(value);
718
+ }
719
+ function countQuestionMarks(sql, end) {
720
+ let count = 0;
721
+ let inSingle = false;
722
+ let inDouble = false;
723
+ let inLineComment = false;
724
+ let inBlockComment = false;
725
+ for (let i = 0; i < end; i++) {
726
+ const ch = sql[i];
727
+ const next = sql[i + 1];
728
+ if (inLineComment) {
729
+ if (ch === "\n") inLineComment = false;
730
+ continue;
731
+ }
732
+ if (inBlockComment) {
733
+ if (ch === "*" && next === "/") {
734
+ inBlockComment = false;
735
+ i += 1;
736
+ }
737
+ continue;
738
+ }
739
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
740
+ inLineComment = true;
741
+ i += 1;
742
+ continue;
743
+ }
744
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
745
+ inBlockComment = true;
746
+ i += 1;
747
+ continue;
748
+ }
749
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
750
+ inSingle = !inSingle;
751
+ continue;
752
+ }
753
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
754
+ inDouble = !inDouble;
755
+ continue;
756
+ }
757
+ if (!inSingle && !inDouble && ch === "?") {
758
+ count += 1;
759
+ }
760
+ }
761
+ return count;
762
+ }
763
+ function findBooleanPlaceholderIndexes(sql) {
764
+ const indexes = /* @__PURE__ */ new Set();
765
+ for (const column of BOOLEAN_COLUMN_NAMES) {
766
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
767
+ for (const match of sql.matchAll(pattern)) {
768
+ const matchText = match[0];
769
+ const qIndex = match.index + matchText.lastIndexOf("?");
770
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
771
+ }
772
+ }
773
+ return indexes;
774
+ }
775
+ function coerceInsertBooleanArgs(sql, args) {
776
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
777
+ if (!match) return;
778
+ const rawTable = match[1];
779
+ const rawColumns = match[2];
780
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
781
+ if (!boolColumns?.size) return;
782
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
783
+ for (const [index, column] of columns.entries()) {
784
+ if (boolColumns.has(column) && index < args.length) {
785
+ args[index] = toBoolean(args[index]);
786
+ }
787
+ }
788
+ }
789
+ function coerceUpdateBooleanArgs(sql, args) {
790
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
791
+ if (!match) return;
792
+ const rawTable = match[1];
793
+ const setClause = match[2];
794
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
795
+ if (!boolColumns?.size) return;
796
+ const assignments = setClause.split(",");
797
+ let placeholderIndex = 0;
798
+ for (const assignment of assignments) {
799
+ if (!assignment.includes("?")) continue;
800
+ placeholderIndex += 1;
801
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
802
+ if (colMatch && boolColumns.has(colMatch[1])) {
803
+ args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
804
+ }
805
+ }
806
+ }
807
+ function coerceBooleanArgs(sql, args) {
808
+ const nextArgs = [...args];
809
+ coerceInsertBooleanArgs(sql, nextArgs);
810
+ coerceUpdateBooleanArgs(sql, nextArgs);
811
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
812
+ for (const index of placeholderIndexes) {
813
+ if (index > 0 && index <= nextArgs.length) {
814
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
815
+ }
816
+ }
817
+ return nextArgs;
818
+ }
819
+ function convertQuestionMarksToDollarParams(sql) {
820
+ let out = "";
821
+ let placeholder = 0;
822
+ let inSingle = false;
823
+ let inDouble = false;
824
+ let inLineComment = false;
825
+ let inBlockComment = false;
826
+ for (let i = 0; i < sql.length; i++) {
827
+ const ch = sql[i];
828
+ const next = sql[i + 1];
829
+ if (inLineComment) {
830
+ out += ch;
831
+ if (ch === "\n") inLineComment = false;
832
+ continue;
833
+ }
834
+ if (inBlockComment) {
835
+ out += ch;
836
+ if (ch === "*" && next === "/") {
837
+ out += next;
838
+ inBlockComment = false;
839
+ i += 1;
840
+ }
841
+ continue;
842
+ }
843
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
844
+ out += ch + next;
845
+ inLineComment = true;
846
+ i += 1;
847
+ continue;
848
+ }
849
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
850
+ out += ch + next;
851
+ inBlockComment = true;
852
+ i += 1;
853
+ continue;
854
+ }
855
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
856
+ inSingle = !inSingle;
857
+ out += ch;
858
+ continue;
859
+ }
860
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
861
+ inDouble = !inDouble;
862
+ out += ch;
863
+ continue;
864
+ }
865
+ if (!inSingle && !inDouble && ch === "?") {
866
+ placeholder += 1;
867
+ out += `$${placeholder}`;
868
+ continue;
869
+ }
870
+ out += ch;
871
+ }
872
+ return out;
873
+ }
874
+ function translateStatementForPostgres(stmt) {
875
+ const normalized = normalizeStatement(stmt);
876
+ if (normalized.kind === "named") {
877
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
878
+ }
879
+ const rewrittenSql = rewriteSql(normalized.sql);
880
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
881
+ return {
882
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
883
+ args: coercedArgs
884
+ };
885
+ }
886
+ function shouldBypassPostgres(stmt) {
887
+ const normalized = normalizeStatement(stmt);
888
+ if (normalized.kind === "named") {
889
+ return true;
890
+ }
891
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
892
+ }
893
+ function shouldFallbackOnError(error) {
894
+ const message = error instanceof Error ? error.message : String(error);
895
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
896
+ }
897
+ function isReadQuery(sql) {
898
+ const trimmed = sql.trimStart();
899
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
900
+ }
901
+ function buildRow(row, columns) {
902
+ const values = columns.map((column) => row[column]);
903
+ return Object.assign(values, row);
904
+ }
905
+ function buildResultSet(rows, rowsAffected = 0) {
906
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
907
+ const resultRows = rows.map((row) => buildRow(row, columns));
908
+ return {
909
+ columns,
910
+ columnTypes: columns.map(() => ""),
911
+ rows: resultRows,
912
+ rowsAffected,
913
+ lastInsertRowid: void 0,
914
+ toJSON() {
915
+ return {
916
+ columns,
917
+ columnTypes: columns.map(() => ""),
918
+ rows,
919
+ rowsAffected,
920
+ lastInsertRowid: void 0
921
+ };
922
+ }
923
+ };
924
+ }
925
+ async function loadPrismaClient() {
926
+ if (!prismaClientPromise) {
927
+ prismaClientPromise = (async () => {
928
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
929
+ if (explicitPath) {
930
+ const module2 = await import(pathToFileURL(explicitPath).href);
931
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
932
+ if (!PrismaClient2) {
933
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
934
+ }
935
+ return new PrismaClient2();
936
+ }
937
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path4.join(os3.homedir(), "exe-db");
938
+ const requireFromExeDb = createRequire(path4.join(exeDbRoot, "package.json"));
939
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
940
+ const module = await import(pathToFileURL(prismaEntry).href);
941
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
942
+ if (!PrismaClient) {
943
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
944
+ }
945
+ return new PrismaClient();
946
+ })();
947
+ }
948
+ return prismaClientPromise;
949
+ }
950
+ async function ensureCompatibilityViews(prisma) {
951
+ if (!compatibilityBootstrapPromise) {
952
+ compatibilityBootstrapPromise = (async () => {
953
+ for (const mapping of VIEW_MAPPINGS) {
954
+ const relation = mapping.source.replace(/"/g, "");
955
+ const rows = await prisma.$queryRawUnsafe(
956
+ "SELECT to_regclass($1) AS regclass",
957
+ relation
958
+ );
959
+ if (!rows[0]?.regclass) {
960
+ continue;
961
+ }
962
+ await prisma.$executeRawUnsafe(
963
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
964
+ );
965
+ }
966
+ })();
967
+ }
968
+ return compatibilityBootstrapPromise;
969
+ }
970
+ async function executeOnPrisma(executor, stmt) {
971
+ const translated = translateStatementForPostgres(stmt);
972
+ if (isReadQuery(translated.sql)) {
973
+ const rows = await executor.$queryRawUnsafe(
974
+ translated.sql,
975
+ ...translated.args
976
+ );
977
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
978
+ }
979
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
980
+ return buildResultSet([], rowsAffected);
981
+ }
982
+ function splitSqlStatements(sql) {
983
+ const parts = [];
984
+ let current = "";
985
+ let inSingle = false;
986
+ let inDouble = false;
987
+ let inLineComment = false;
988
+ let inBlockComment = false;
989
+ for (let i = 0; i < sql.length; i++) {
990
+ const ch = sql[i];
991
+ const next = sql[i + 1];
992
+ if (inLineComment) {
993
+ current += ch;
994
+ if (ch === "\n") inLineComment = false;
995
+ continue;
996
+ }
997
+ if (inBlockComment) {
998
+ current += ch;
999
+ if (ch === "*" && next === "/") {
1000
+ current += next;
1001
+ inBlockComment = false;
1002
+ i += 1;
1003
+ }
1004
+ continue;
1005
+ }
1006
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
1007
+ current += ch + next;
1008
+ inLineComment = true;
1009
+ i += 1;
1010
+ continue;
1011
+ }
1012
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
1013
+ current += ch + next;
1014
+ inBlockComment = true;
1015
+ i += 1;
1016
+ continue;
1017
+ }
1018
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
1019
+ inSingle = !inSingle;
1020
+ current += ch;
1021
+ continue;
1022
+ }
1023
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
1024
+ inDouble = !inDouble;
1025
+ current += ch;
1026
+ continue;
1027
+ }
1028
+ if (!inSingle && !inDouble && ch === ";") {
1029
+ if (current.trim()) {
1030
+ parts.push(current.trim());
1031
+ }
1032
+ current = "";
1033
+ continue;
1034
+ }
1035
+ current += ch;
1036
+ }
1037
+ if (current.trim()) {
1038
+ parts.push(current.trim());
1039
+ }
1040
+ return parts;
1041
+ }
1042
+ async function createPrismaDbAdapter(fallbackClient) {
1043
+ const prisma = await loadPrismaClient();
1044
+ await ensureCompatibilityViews(prisma);
1045
+ let closed = false;
1046
+ let adapter;
1047
+ const fallbackExecute = async (stmt, error) => {
1048
+ if (!fallbackClient) {
1049
+ if (error) throw error;
1050
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
1051
+ }
1052
+ if (error) {
1053
+ process.stderr.write(
1054
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
1055
+ `
1056
+ );
1057
+ }
1058
+ return fallbackClient.execute(stmt);
1059
+ };
1060
+ adapter = {
1061
+ async execute(stmt) {
1062
+ if (shouldBypassPostgres(stmt)) {
1063
+ return fallbackExecute(stmt);
1064
+ }
1065
+ try {
1066
+ return await executeOnPrisma(prisma, stmt);
1067
+ } catch (error) {
1068
+ if (shouldFallbackOnError(error)) {
1069
+ return fallbackExecute(stmt, error);
1070
+ }
1071
+ throw error;
1072
+ }
1073
+ },
1074
+ async batch(stmts, mode) {
1075
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
1076
+ if (!fallbackClient) {
1077
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
1078
+ }
1079
+ return fallbackClient.batch(stmts, mode);
1080
+ }
1081
+ try {
1082
+ if (prisma.$transaction) {
1083
+ return await prisma.$transaction(async (tx) => {
1084
+ const results2 = [];
1085
+ for (const stmt of stmts) {
1086
+ results2.push(await executeOnPrisma(tx, stmt));
1087
+ }
1088
+ return results2;
1089
+ });
1090
+ }
1091
+ const results = [];
1092
+ for (const stmt of stmts) {
1093
+ results.push(await executeOnPrisma(prisma, stmt));
1094
+ }
1095
+ return results;
1096
+ } catch (error) {
1097
+ if (fallbackClient && shouldFallbackOnError(error)) {
1098
+ process.stderr.write(
1099
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
1100
+ `
1101
+ );
1102
+ return fallbackClient.batch(stmts, mode);
1103
+ }
1104
+ throw error;
1105
+ }
1106
+ },
1107
+ async migrate(stmts) {
1108
+ if (fallbackClient) {
1109
+ return fallbackClient.migrate(stmts);
1110
+ }
1111
+ return adapter.batch(stmts, "deferred");
1112
+ },
1113
+ async transaction(mode) {
1114
+ if (!fallbackClient) {
1115
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
1116
+ }
1117
+ return fallbackClient.transaction(mode);
1118
+ },
1119
+ async executeMultiple(sql) {
1120
+ if (fallbackClient && shouldBypassPostgres(sql)) {
1121
+ return fallbackClient.executeMultiple(sql);
1122
+ }
1123
+ for (const statement of splitSqlStatements(sql)) {
1124
+ await adapter.execute(statement);
1125
+ }
1126
+ },
1127
+ async sync() {
1128
+ if (fallbackClient) {
1129
+ return fallbackClient.sync();
1130
+ }
1131
+ return { frame_no: 0, frames_synced: 0 };
1132
+ },
1133
+ close() {
1134
+ closed = true;
1135
+ prismaClientPromise = null;
1136
+ compatibilityBootstrapPromise = null;
1137
+ void prisma.$disconnect?.();
1138
+ },
1139
+ get closed() {
1140
+ return closed;
1141
+ },
1142
+ get protocol() {
1143
+ return "prisma-postgres";
1144
+ }
1145
+ };
1146
+ return adapter;
1147
+ }
1148
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
1149
+ var init_database_adapter = __esm({
1150
+ "src/lib/database-adapter.ts"() {
1151
+ "use strict";
1152
+ VIEW_MAPPINGS = [
1153
+ { view: "memories", source: "memory.memory_records" },
1154
+ { view: "tasks", source: "memory.tasks" },
1155
+ { view: "behaviors", source: "memory.behaviors" },
1156
+ { view: "entities", source: "memory.entities" },
1157
+ { view: "relationships", source: "memory.relationships" },
1158
+ { view: "entity_memories", source: "memory.entity_memories" },
1159
+ { view: "entity_aliases", source: "memory.entity_aliases" },
1160
+ { view: "notifications", source: "memory.notifications" },
1161
+ { view: "messages", source: "memory.messages" },
1162
+ { view: "users", source: "wiki.users" },
1163
+ { view: "workspaces", source: "wiki.workspaces" },
1164
+ { view: "workspace_users", source: "wiki.workspace_users" },
1165
+ { view: "documents", source: "wiki.workspace_documents" },
1166
+ { view: "chats", source: "wiki.workspace_chats" }
1167
+ ];
1168
+ UPSERT_KEYS = {
1169
+ memories: ["id"],
1170
+ tasks: ["id"],
1171
+ behaviors: ["id"],
1172
+ entities: ["id"],
1173
+ relationships: ["id"],
1174
+ entity_aliases: ["alias"],
1175
+ notifications: ["id"],
1176
+ messages: ["id"],
1177
+ users: ["id"],
1178
+ workspaces: ["id"],
1179
+ workspace_users: ["id"],
1180
+ documents: ["id"],
1181
+ chats: ["id"]
1182
+ };
1183
+ BOOLEAN_COLUMNS_BY_TABLE = {
1184
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
1185
+ behaviors: /* @__PURE__ */ new Set(["active"]),
1186
+ notifications: /* @__PURE__ */ new Set(["read"]),
1187
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
1188
+ };
1189
+ BOOLEAN_COLUMN_NAMES = new Set(
1190
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
1191
+ );
1192
+ IMMEDIATE_FALLBACK_PATTERNS = [
1193
+ /\bPRAGMA\b/i,
1194
+ /\bsqlite_master\b/i,
1195
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
1196
+ /\bMATCH\b/i,
1197
+ /\bvector_distance_cos\s*\(/i,
1198
+ /\bjson_extract\s*\(/i,
1199
+ /\bjulianday\s*\(/i,
1200
+ /\bstrftime\s*\(/i,
1201
+ /\blast_insert_rowid\s*\(/i
1202
+ ];
1203
+ prismaClientPromise = null;
1204
+ compatibilityBootstrapPromise = null;
460
1205
  }
461
1206
  });
462
1207
 
463
1208
  // src/lib/database.ts
464
1209
  import { createClient } from "@libsql/client";
465
1210
  async function initDatabase(config) {
1211
+ if (_walCheckpointTimer) {
1212
+ clearInterval(_walCheckpointTimer);
1213
+ _walCheckpointTimer = null;
1214
+ }
1215
+ if (_daemonClient) {
1216
+ _daemonClient.close();
1217
+ _daemonClient = null;
1218
+ }
1219
+ if (_adapterClient && _adapterClient !== _resilientClient) {
1220
+ _adapterClient.close();
1221
+ }
1222
+ _adapterClient = null;
466
1223
  if (_client) {
467
1224
  _client.close();
468
1225
  _client = null;
@@ -476,6 +1233,7 @@ async function initDatabase(config) {
476
1233
  }
477
1234
  _client = createClient(opts);
478
1235
  _resilientClient = wrapWithRetry(_client);
1236
+ _adapterClient = _resilientClient;
479
1237
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
480
1238
  });
481
1239
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -486,11 +1244,17 @@ async function initDatabase(config) {
486
1244
  });
487
1245
  }, 3e4);
488
1246
  _walCheckpointTimer.unref();
1247
+ if (process.env.DATABASE_URL) {
1248
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
1249
+ }
489
1250
  }
490
1251
  function getClient() {
491
- if (!_resilientClient) {
1252
+ if (!_adapterClient) {
492
1253
  throw new Error("Database client not initialized. Call initDatabase() first.");
493
1254
  }
1255
+ if (process.env.DATABASE_URL) {
1256
+ return _adapterClient;
1257
+ }
494
1258
  if (process.env.EXE_IS_DAEMON === "1") {
495
1259
  return _resilientClient;
496
1260
  }
@@ -1431,26 +2195,36 @@ async function ensureSchema() {
1431
2195
  }
1432
2196
  }
1433
2197
  async function disposeDatabase() {
2198
+ if (_walCheckpointTimer) {
2199
+ clearInterval(_walCheckpointTimer);
2200
+ _walCheckpointTimer = null;
2201
+ }
1434
2202
  if (_daemonClient) {
1435
2203
  _daemonClient.close();
1436
2204
  _daemonClient = null;
1437
2205
  }
2206
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2207
+ _adapterClient.close();
2208
+ }
2209
+ _adapterClient = null;
1438
2210
  if (_client) {
1439
2211
  _client.close();
1440
2212
  _client = null;
1441
2213
  _resilientClient = null;
1442
2214
  }
1443
2215
  }
1444
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
2216
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
1445
2217
  var init_database = __esm({
1446
2218
  "src/lib/database.ts"() {
1447
2219
  "use strict";
1448
2220
  init_db_retry();
1449
2221
  init_employees();
2222
+ init_database_adapter();
1450
2223
  _client = null;
1451
2224
  _resilientClient = null;
1452
2225
  _walCheckpointTimer = null;
1453
2226
  _daemonClient = null;
2227
+ _adapterClient = null;
1454
2228
  initTurso = initDatabase;
1455
2229
  disposeTurso = disposeDatabase;
1456
2230
  }
@@ -1469,13 +2243,13 @@ __export(shard_manager_exports, {
1469
2243
  listShards: () => listShards,
1470
2244
  shardExists: () => shardExists
1471
2245
  });
1472
- import path4 from "path";
1473
- import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
2246
+ import path6 from "path";
2247
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
1474
2248
  import { createClient as createClient2 } from "@libsql/client";
1475
2249
  function initShardManager(encryptionKey) {
1476
2250
  _encryptionKey = encryptionKey;
1477
- if (!existsSync4(SHARDS_DIR)) {
1478
- mkdirSync(SHARDS_DIR, { recursive: true });
2251
+ if (!existsSync5(SHARDS_DIR)) {
2252
+ mkdirSync2(SHARDS_DIR, { recursive: true });
1479
2253
  }
1480
2254
  _shardingEnabled = true;
1481
2255
  }
@@ -1495,7 +2269,7 @@ function getShardClient(projectName) {
1495
2269
  }
1496
2270
  const cached = _shards.get(safeName);
1497
2271
  if (cached) return cached;
1498
- const dbPath = path4.join(SHARDS_DIR, `${safeName}.db`);
2272
+ const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
1499
2273
  const client = createClient2({
1500
2274
  url: `file:${dbPath}`,
1501
2275
  encryptionKey: _encryptionKey
@@ -1505,10 +2279,10 @@ function getShardClient(projectName) {
1505
2279
  }
1506
2280
  function shardExists(projectName) {
1507
2281
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
1508
- return existsSync4(path4.join(SHARDS_DIR, `${safeName}.db`));
2282
+ return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
1509
2283
  }
1510
2284
  function listShards() {
1511
- if (!existsSync4(SHARDS_DIR)) return [];
2285
+ if (!existsSync5(SHARDS_DIR)) return [];
1512
2286
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1513
2287
  }
1514
2288
  async function ensureShardSchema(client) {
@@ -1582,7 +2356,23 @@ async function ensureShardSchema(client) {
1582
2356
  // MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
1583
2357
  "ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
1584
2358
  "ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
1585
- "ALTER TABLE memories ADD COLUMN trajectory TEXT"
2359
+ "ALTER TABLE memories ADD COLUMN trajectory TEXT",
2360
+ // Metadata enrichment columns (must match database.ts)
2361
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
2362
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
2363
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
2364
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
2365
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
2366
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
2367
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
2368
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
2369
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
2370
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
2371
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
2372
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
2373
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
2374
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
2375
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1586
2376
  ]) {
1587
2377
  try {
1588
2378
  await client.execute(col);
@@ -1694,7 +2484,7 @@ var init_shard_manager = __esm({
1694
2484
  "src/lib/shard-manager.ts"() {
1695
2485
  "use strict";
1696
2486
  init_config();
1697
- SHARDS_DIR = path4.join(EXE_AI_DIR, "shards");
2487
+ SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
1698
2488
  _shards = /* @__PURE__ */ new Map();
1699
2489
  _encryptionKey = null;
1700
2490
  _shardingEnabled = false;
@@ -2583,9 +3373,9 @@ __export(active_agent_exports, {
2583
3373
  resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
2584
3374
  writeActiveAgent: () => writeActiveAgent
2585
3375
  });
2586
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
3376
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
2587
3377
  import { execSync as execSync4 } from "child_process";
2588
- import path6 from "path";
3378
+ import path8 from "path";
2589
3379
  function isNameWithOptionalInstance(candidate, baseName) {
2590
3380
  if (candidate === baseName) return true;
2591
3381
  if (!candidate.startsWith(baseName)) return false;
@@ -2629,12 +3419,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
2629
3419
  return null;
2630
3420
  }
2631
3421
  function getMarkerPath() {
2632
- return path6.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
3422
+ return path8.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
2633
3423
  }
2634
3424
  function writeActiveAgent(agentId, agentRole) {
2635
3425
  try {
2636
- mkdirSync3(CACHE_DIR, { recursive: true });
2637
- writeFileSync3(
3426
+ mkdirSync4(CACHE_DIR, { recursive: true });
3427
+ writeFileSync4(
2638
3428
  getMarkerPath(),
2639
3429
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
2640
3430
  );
@@ -2650,7 +3440,7 @@ function clearActiveAgent() {
2650
3440
  function getActiveAgent() {
2651
3441
  try {
2652
3442
  const markerPath = getMarkerPath();
2653
- const raw = readFileSync3(markerPath, "utf8");
3443
+ const raw = readFileSync4(markerPath, "utf8");
2654
3444
  const data = JSON.parse(raw);
2655
3445
  if (data.agentId) {
2656
3446
  if (data.startedAt) {
@@ -2698,14 +3488,14 @@ function getAllActiveAgents() {
2698
3488
  const key = file.slice("active-agent-".length, -".json".length);
2699
3489
  if (key === "undefined") continue;
2700
3490
  try {
2701
- const raw = readFileSync3(path6.join(CACHE_DIR, file), "utf8");
3491
+ const raw = readFileSync4(path8.join(CACHE_DIR, file), "utf8");
2702
3492
  const data = JSON.parse(raw);
2703
3493
  if (!data.agentId) continue;
2704
3494
  if (data.startedAt) {
2705
3495
  const age = Date.now() - new Date(data.startedAt).getTime();
2706
3496
  if (age > STALE_MS) {
2707
3497
  try {
2708
- unlinkSync3(path6.join(CACHE_DIR, file));
3498
+ unlinkSync3(path8.join(CACHE_DIR, file));
2709
3499
  } catch {
2710
3500
  }
2711
3501
  continue;
@@ -2728,11 +3518,11 @@ function getAllActiveAgents() {
2728
3518
  function cleanupSessionMarkers() {
2729
3519
  const key = getSessionKey();
2730
3520
  try {
2731
- unlinkSync3(path6.join(CACHE_DIR, `active-agent-${key}.json`));
3521
+ unlinkSync3(path8.join(CACHE_DIR, `active-agent-${key}.json`));
2732
3522
  } catch {
2733
3523
  }
2734
3524
  try {
2735
- unlinkSync3(path6.join(CACHE_DIR, "active-agent-undefined.json"));
3525
+ unlinkSync3(path8.join(CACHE_DIR, "active-agent-undefined.json"));
2736
3526
  } catch {
2737
3527
  }
2738
3528
  }
@@ -2743,15 +3533,15 @@ var init_active_agent = __esm({
2743
3533
  init_config();
2744
3534
  init_session_key();
2745
3535
  init_employees();
2746
- CACHE_DIR = path6.join(EXE_AI_DIR, "session-cache");
3536
+ CACHE_DIR = path8.join(EXE_AI_DIR, "session-cache");
2747
3537
  STALE_MS = 24 * 60 * 60 * 1e3;
2748
3538
  }
2749
3539
  });
2750
3540
 
2751
3541
  // src/bin/exe-launch-agent.ts
2752
- import os5 from "os";
2753
- import path7 from "path";
2754
- import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync4 } from "fs";
3542
+ import os6 from "os";
3543
+ import path9 from "path";
3544
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync4 } from "fs";
2755
3545
  import { spawnSync } from "child_process";
2756
3546
 
2757
3547
  // src/lib/store.ts
@@ -2760,16 +3550,16 @@ init_database();
2760
3550
 
2761
3551
  // src/lib/keychain.ts
2762
3552
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2763
- import { existsSync as existsSync3 } from "fs";
2764
- import path3 from "path";
2765
- import os3 from "os";
3553
+ import { existsSync as existsSync4 } from "fs";
3554
+ import path5 from "path";
3555
+ import os4 from "os";
2766
3556
  var SERVICE = "exe-mem";
2767
3557
  var ACCOUNT = "master-key";
2768
3558
  function getKeyDir() {
2769
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os3.homedir(), ".exe-os");
3559
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os4.homedir(), ".exe-os");
2770
3560
  }
2771
3561
  function getKeyPath() {
2772
- return path3.join(getKeyDir(), "master.key");
3562
+ return path5.join(getKeyDir(), "master.key");
2773
3563
  }
2774
3564
  async function tryKeytar() {
2775
3565
  try {
@@ -2790,9 +3580,9 @@ async function getMasterKey() {
2790
3580
  }
2791
3581
  }
2792
3582
  const keyPath = getKeyPath();
2793
- if (!existsSync3(keyPath)) {
3583
+ if (!existsSync4(keyPath)) {
2794
3584
  process.stderr.write(
2795
- `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3585
+ `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2796
3586
  `
2797
3587
  );
2798
3588
  return null;
@@ -3103,15 +3893,15 @@ function vectorToBlob(vector) {
3103
3893
  }
3104
3894
 
3105
3895
  // src/lib/behaviors-export.ts
3106
- import os4 from "os";
3107
- import path5 from "path";
3896
+ import os5 from "os";
3897
+ import path7 from "path";
3108
3898
  import {
3109
- existsSync as existsSync5,
3110
- mkdirSync as mkdirSync2,
3899
+ existsSync as existsSync6,
3900
+ mkdirSync as mkdirSync3,
3111
3901
  readdirSync as readdirSync2,
3112
3902
  statSync,
3113
3903
  unlinkSync as unlinkSync2,
3114
- writeFileSync as writeFileSync2
3904
+ writeFileSync as writeFileSync3
3115
3905
  } from "fs";
3116
3906
 
3117
3907
  // src/lib/behaviors.ts
@@ -3146,15 +3936,15 @@ async function listBehaviors(agentId, projectName, limit = 30) {
3146
3936
  }
3147
3937
 
3148
3938
  // src/lib/behaviors-export.ts
3149
- var BEHAVIORS_EXPORT_DIR = path5.join(
3150
- os4.homedir(),
3939
+ var BEHAVIORS_EXPORT_DIR = path7.join(
3940
+ os5.homedir(),
3151
3941
  ".exe-os",
3152
3942
  "behaviors-export"
3153
3943
  );
3154
3944
  var STALE_EXPORT_AGE_MS = 60 * 60 * 1e3;
3155
3945
  var EXPORT_BEHAVIOR_LIMIT = 30;
3156
3946
  function sweepStaleBehaviorExports(now = Date.now()) {
3157
- if (!existsSync5(BEHAVIORS_EXPORT_DIR)) return;
3947
+ if (!existsSync6(BEHAVIORS_EXPORT_DIR)) return;
3158
3948
  let entries;
3159
3949
  try {
3160
3950
  entries = readdirSync2(BEHAVIORS_EXPORT_DIR);
@@ -3162,7 +3952,7 @@ function sweepStaleBehaviorExports(now = Date.now()) {
3162
3952
  return;
3163
3953
  }
3164
3954
  for (const entry of entries) {
3165
- const filePath = path5.join(BEHAVIORS_EXPORT_DIR, entry);
3955
+ const filePath = path7.join(BEHAVIORS_EXPORT_DIR, entry);
3166
3956
  try {
3167
3957
  const stat = statSync(filePath);
3168
3958
  if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
@@ -3195,22 +3985,22 @@ function renderBehaviorExport(behaviors) {
3195
3985
  }
3196
3986
  function exportFilePath(agentId, projectName, sessionKey) {
3197
3987
  if (!sessionKey) {
3198
- return path5.join(BEHAVIORS_EXPORT_DIR, `${agentId}.md`);
3988
+ return path7.join(BEHAVIORS_EXPORT_DIR, `${agentId}.md`);
3199
3989
  }
3200
3990
  const safeProject = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3201
- return path5.join(
3991
+ return path7.join(
3202
3992
  BEHAVIORS_EXPORT_DIR,
3203
3993
  `${agentId}-${safeProject}-${sessionKey}.md`
3204
3994
  );
3205
3995
  }
3206
3996
  async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
3207
- mkdirSync2(BEHAVIORS_EXPORT_DIR, { recursive: true });
3997
+ mkdirSync3(BEHAVIORS_EXPORT_DIR, { recursive: true });
3208
3998
  sweepStaleBehaviorExports();
3209
3999
  const behaviors = await listBehaviors(agentId, projectName, EXPORT_BEHAVIOR_LIMIT);
3210
4000
  if (behaviors.length === 0) return null;
3211
4001
  const body = renderBehaviorExport(behaviors);
3212
4002
  const target = exportFilePath(agentId, projectName, sessionKey);
3213
- writeFileSync2(target, body, "utf-8");
4003
+ writeFileSync3(target, body, "utf-8");
3214
4004
  return target;
3215
4005
  }
3216
4006
 
@@ -3269,7 +4059,7 @@ function parseBasename(basename) {
3269
4059
  return { agent, provider };
3270
4060
  }
3271
4061
  function resolveAgent(argv) {
3272
- const invokedAs = path7.basename(argv[1] ?? "");
4062
+ const invokedAs = path9.basename(argv[1] ?? "");
3273
4063
  if (invokedAs && invokedAs !== "exe-launch-agent" && !invokedAs.endsWith(".js")) {
3274
4064
  const { agent: agent2, provider } = parseBasename(invokedAs.toLowerCase());
3275
4065
  return { agent: agent2, provider, passthrough: argv.slice(2) };
@@ -3298,20 +4088,20 @@ async function isKnownAgent(agent) {
3298
4088
  }
3299
4089
  }
3300
4090
  function identityPathFor(agent) {
3301
- const dir = path7.join(os5.homedir(), ".exe-os", "identity");
3302
- const exactPath = path7.join(dir, `${agent}.md`);
3303
- if (existsSync6(exactPath)) return exactPath;
4091
+ const dir = path9.join(os6.homedir(), ".exe-os", "identity");
4092
+ const exactPath = path9.join(dir, `${agent}.md`);
4093
+ if (existsSync7(exactPath)) return exactPath;
3304
4094
  try {
3305
4095
  const files = readdirSync4(dir);
3306
4096
  const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
3307
- if (match) return path7.join(dir, match);
4097
+ if (match) return path9.join(dir, match);
3308
4098
  } catch {
3309
4099
  }
3310
4100
  return exactPath;
3311
4101
  }
3312
4102
  function leanMcpConfigFor(agent) {
3313
- const p = path7.join(os5.homedir(), ".exe-os", "mcp-configs", `${agent}-lean.json`);
3314
- return existsSync6(p) ? p : null;
4103
+ const p = path9.join(os6.homedir(), ".exe-os", "mcp-configs", `${agent}-lean.json`);
4104
+ return existsSync7(p) ? p : null;
3315
4105
  }
3316
4106
  var _ccHelpOutput = null;
3317
4107
  function getCcHelpOutput() {
@@ -3334,39 +4124,39 @@ function _resetCcHelpCache() {
3334
4124
  function buildLaunchPlan(agent, behaviorsPath, passthrough, _hasAgentFlag, _provider) {
3335
4125
  const args = ["--dangerously-skip-permissions"];
3336
4126
  const idPath = identityPathFor(agent);
3337
- const ccAgentPath = path7.join(os5.homedir(), ".claude", "agents", `${agent}.md`);
4127
+ const ccAgentPath = path9.join(os6.homedir(), ".claude", "agents", `${agent}.md`);
3338
4128
  let effectiveCcPath = null;
3339
- if (existsSync6(ccAgentPath)) {
4129
+ if (existsSync7(ccAgentPath)) {
3340
4130
  effectiveCcPath = ccAgentPath;
3341
4131
  } else {
3342
4132
  try {
3343
- const ccAgentDir = path7.join(os5.homedir(), ".claude", "agents");
4133
+ const ccAgentDir = path9.join(os6.homedir(), ".claude", "agents");
3344
4134
  const ccFiles = readdirSync4(ccAgentDir);
3345
4135
  const ccMatch = ccFiles.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
3346
- if (ccMatch) effectiveCcPath = path7.join(ccAgentDir, ccMatch);
4136
+ if (ccMatch) effectiveCcPath = path9.join(ccAgentDir, ccMatch);
3347
4137
  } catch {
3348
4138
  }
3349
4139
  }
3350
- const effectiveIdPath = existsSync6(idPath) ? idPath : effectiveCcPath;
4140
+ const effectiveIdPath = existsSync7(idPath) ? idPath : effectiveCcPath;
3351
4141
  let identityContent = null;
3352
- if (effectiveIdPath && existsSync6(effectiveIdPath)) {
4142
+ if (effectiveIdPath && existsSync7(effectiveIdPath)) {
3353
4143
  try {
3354
- const content = readFileSync4(effectiveIdPath, "utf-8");
4144
+ const content = readFileSync5(effectiveIdPath, "utf-8");
3355
4145
  if (content.trim().length > 0) identityContent = content;
3356
4146
  } catch {
3357
4147
  }
3358
4148
  }
3359
4149
  if (!identityContent) {
3360
4150
  try {
3361
- const rosterPath = path7.join(os5.homedir(), ".exe-os", "exe-employees.json");
3362
- if (existsSync6(rosterPath)) {
3363
- const roster = JSON.parse(readFileSync4(rosterPath, "utf8"));
4151
+ const rosterPath = path9.join(os6.homedir(), ".exe-os", "exe-employees.json");
4152
+ if (existsSync7(rosterPath)) {
4153
+ const roster = JSON.parse(readFileSync5(rosterPath, "utf8"));
3364
4154
  const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
3365
4155
  if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
3366
4156
  identityContent = emp.systemPrompt;
3367
4157
  try {
3368
- const dir = path7.dirname(idPath);
3369
- if (!existsSync6(dir)) mkdirSync4(dir, { recursive: true });
4158
+ const dir = path9.dirname(idPath);
4159
+ if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
3370
4160
  const hasFrontmatter = identityContent.trimStart().startsWith("---");
3371
4161
  const fileContent = hasFrontmatter ? identityContent : `---
3372
4162
  role: ${(emp.role ?? "employee").toLowerCase()}
@@ -3378,7 +4168,7 @@ updated_at: ${(/* @__PURE__ */ new Date()).toISOString()}
3378
4168
  ---
3379
4169
 
3380
4170
  ${identityContent}`;
3381
- writeFileSync4(idPath, fileContent, "utf-8");
4171
+ writeFileSync5(idPath, fileContent, "utf-8");
3382
4172
  identityContent = fileContent;
3383
4173
  process.stderr.write(`[exe-launch-agent] self-healed missing identity file: ${idPath}
3384
4174
  `);
@@ -3406,15 +4196,15 @@ ${identityContent}`;
3406
4196
  args.push("--system-prompt", getSessionPrompt(identityContent));
3407
4197
  } else {
3408
4198
  try {
3409
- const tmpPath = path7.join(os5.homedir(), ".exe-os", "session-cache", `${agent}-identity.md`);
3410
- mkdirSync4(path7.dirname(tmpPath), { recursive: true });
3411
- writeFileSync4(tmpPath, identityContent, "utf-8");
4199
+ const tmpPath = path9.join(os6.homedir(), ".exe-os", "session-cache", `${agent}-identity.md`);
4200
+ mkdirSync5(path9.dirname(tmpPath), { recursive: true });
4201
+ writeFileSync5(tmpPath, identityContent, "utf-8");
3412
4202
  args.push("--append-system-prompt-file", tmpPath);
3413
4203
  } catch {
3414
4204
  }
3415
4205
  }
3416
4206
  }
3417
- if (behaviorsPath && existsSync6(behaviorsPath)) {
4207
+ if (behaviorsPath && existsSync7(behaviorsPath)) {
3418
4208
  args.push("--append-system-prompt-file", behaviorsPath);
3419
4209
  }
3420
4210
  const leanMcp = leanMcpConfigFor(agent);
@@ -3535,28 +4325,28 @@ async function main() {
3535
4325
  _resetCcAgentSupportCache();
3536
4326
  const hasAgentFlag = claudeSupportsAgentFlag();
3537
4327
  if (hasAgentFlag) {
3538
- const ccAgentDir = path7.join(os5.homedir(), ".claude", "agents");
3539
- const ccAgentFile = path7.join(ccAgentDir, `${agent}.md`);
3540
- if (!existsSync6(ccAgentFile)) {
4328
+ const ccAgentDir = path9.join(os6.homedir(), ".claude", "agents");
4329
+ const ccAgentFile = path9.join(ccAgentDir, `${agent}.md`);
4330
+ if (!existsSync7(ccAgentFile)) {
3541
4331
  const exeIdentity = identityPathFor(agent);
3542
4332
  let sourceFile = null;
3543
- if (existsSync6(exeIdentity)) {
4333
+ if (existsSync7(exeIdentity)) {
3544
4334
  sourceFile = exeIdentity;
3545
4335
  } else {
3546
4336
  try {
3547
- const identityDir = path7.dirname(exeIdentity);
4337
+ const identityDir = path9.dirname(exeIdentity);
3548
4338
  const files = readdirSync4(identityDir);
3549
4339
  const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
3550
- if (match) sourceFile = path7.join(identityDir, match);
4340
+ if (match) sourceFile = path9.join(identityDir, match);
3551
4341
  } catch {
3552
4342
  }
3553
4343
  }
3554
4344
  if (sourceFile) {
3555
4345
  try {
3556
- mkdirSync4(ccAgentDir, { recursive: true });
3557
- let content = readFileSync4(sourceFile, "utf-8");
4346
+ mkdirSync5(ccAgentDir, { recursive: true });
4347
+ let content = readFileSync5(sourceFile, "utf-8");
3558
4348
  content = content.replace(/\$\{agent_id\}/g, baseAgentName(agent));
3559
- writeFileSync4(ccAgentFile, content, "utf-8");
4349
+ writeFileSync5(ccAgentFile, content, "utf-8");
3560
4350
  process.stderr.write(
3561
4351
  `[exe-launch-agent] auto-provisioned ${ccAgentFile} from ${sourceFile}
3562
4352
  `
@@ -3576,7 +4366,7 @@ async function main() {
3576
4366
  const empRole = (() => {
3577
4367
  try {
3578
4368
  const emps = __require("fs").readFileSync(
3579
- path7.join(os5.homedir(), ".exe-os", "exe-employees.json"),
4369
+ path9.join(os6.homedir(), ".exe-os", "exe-employees.json"),
3580
4370
  "utf-8"
3581
4371
  );
3582
4372
  const found = JSON.parse(emps).find(