@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
@@ -417,7 +417,7 @@ function registerBinSymlinks(name) {
417
417
  }
418
418
  return { created, skipped, errors };
419
419
  }
420
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
420
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
421
421
  var init_employees = __esm({
422
422
  "src/lib/employees.ts"() {
423
423
  "use strict";
@@ -425,16 +425,601 @@ var init_employees = __esm({
425
425
  EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
426
426
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
427
427
  COORDINATOR_ROLE = "COO";
428
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
429
+ }
430
+ });
431
+
432
+ // src/lib/database-adapter.ts
433
+ import os3 from "os";
434
+ import path3 from "path";
435
+ import { createRequire } from "module";
436
+ import { pathToFileURL } from "url";
437
+ function quotedIdentifier(identifier) {
438
+ return `"${identifier.replace(/"/g, '""')}"`;
439
+ }
440
+ function unqualifiedTableName(name) {
441
+ const raw = name.trim().replace(/^"|"$/g, "");
442
+ const parts = raw.split(".");
443
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
444
+ }
445
+ function stripTrailingSemicolon(sql) {
446
+ return sql.trim().replace(/;+\s*$/u, "");
447
+ }
448
+ function appendClause(sql, clause) {
449
+ const trimmed = stripTrailingSemicolon(sql);
450
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
451
+ if (!returningMatch) {
452
+ return `${trimmed}${clause}`;
453
+ }
454
+ const idx = returningMatch.index;
455
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
456
+ }
457
+ function normalizeStatement(stmt) {
458
+ if (typeof stmt === "string") {
459
+ return { kind: "positional", sql: stmt, args: [] };
460
+ }
461
+ const sql = stmt.sql;
462
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
463
+ return { kind: "positional", sql, args: stmt.args ?? [] };
464
+ }
465
+ return { kind: "named", sql, args: stmt.args };
466
+ }
467
+ function rewriteBooleanLiterals(sql) {
468
+ let out = sql;
469
+ for (const column of BOOLEAN_COLUMN_NAMES) {
470
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
471
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
472
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
473
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
474
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
475
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
476
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
477
+ }
478
+ return out;
479
+ }
480
+ function rewriteInsertOrIgnore(sql) {
481
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
482
+ return sql;
483
+ }
484
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
485
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
486
+ }
487
+ function rewriteInsertOrReplace(sql) {
488
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
489
+ if (!match) {
490
+ return sql;
491
+ }
492
+ const rawTable = match[1];
493
+ const rawColumns = match[2];
494
+ const remainder = match[3];
495
+ const tableName = unqualifiedTableName(rawTable);
496
+ const conflictKeys = UPSERT_KEYS[tableName];
497
+ if (!conflictKeys?.length) {
498
+ return sql;
499
+ }
500
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
501
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
502
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
503
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
504
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
505
+ }
506
+ function rewriteSql(sql) {
507
+ let out = sql;
508
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
509
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
510
+ out = rewriteBooleanLiterals(out);
511
+ out = rewriteInsertOrReplace(out);
512
+ out = rewriteInsertOrIgnore(out);
513
+ return stripTrailingSemicolon(out);
514
+ }
515
+ function toBoolean(value) {
516
+ if (value === null || value === void 0) return value;
517
+ if (typeof value === "boolean") return value;
518
+ if (typeof value === "number") return value !== 0;
519
+ if (typeof value === "bigint") return value !== 0n;
520
+ if (typeof value === "string") {
521
+ const normalized = value.trim().toLowerCase();
522
+ if (normalized === "0" || normalized === "false") return false;
523
+ if (normalized === "1" || normalized === "true") return true;
524
+ }
525
+ return Boolean(value);
526
+ }
527
+ function countQuestionMarks(sql, end) {
528
+ let count = 0;
529
+ let inSingle = false;
530
+ let inDouble = false;
531
+ let inLineComment = false;
532
+ let inBlockComment = false;
533
+ for (let i = 0; i < end; i++) {
534
+ const ch = sql[i];
535
+ const next = sql[i + 1];
536
+ if (inLineComment) {
537
+ if (ch === "\n") inLineComment = false;
538
+ continue;
539
+ }
540
+ if (inBlockComment) {
541
+ if (ch === "*" && next === "/") {
542
+ inBlockComment = false;
543
+ i += 1;
544
+ }
545
+ continue;
546
+ }
547
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
548
+ inLineComment = true;
549
+ i += 1;
550
+ continue;
551
+ }
552
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
553
+ inBlockComment = true;
554
+ i += 1;
555
+ continue;
556
+ }
557
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
558
+ inSingle = !inSingle;
559
+ continue;
560
+ }
561
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
562
+ inDouble = !inDouble;
563
+ continue;
564
+ }
565
+ if (!inSingle && !inDouble && ch === "?") {
566
+ count += 1;
567
+ }
568
+ }
569
+ return count;
570
+ }
571
+ function findBooleanPlaceholderIndexes(sql) {
572
+ const indexes = /* @__PURE__ */ new Set();
573
+ for (const column of BOOLEAN_COLUMN_NAMES) {
574
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
575
+ for (const match of sql.matchAll(pattern)) {
576
+ const matchText = match[0];
577
+ const qIndex = match.index + matchText.lastIndexOf("?");
578
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
579
+ }
580
+ }
581
+ return indexes;
582
+ }
583
+ function coerceInsertBooleanArgs(sql, args) {
584
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
585
+ if (!match) return;
586
+ const rawTable = match[1];
587
+ const rawColumns = match[2];
588
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
589
+ if (!boolColumns?.size) return;
590
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
591
+ for (const [index, column] of columns.entries()) {
592
+ if (boolColumns.has(column) && index < args.length) {
593
+ args[index] = toBoolean(args[index]);
594
+ }
595
+ }
596
+ }
597
+ function coerceUpdateBooleanArgs(sql, args) {
598
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
599
+ if (!match) return;
600
+ const rawTable = match[1];
601
+ const setClause = match[2];
602
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
603
+ if (!boolColumns?.size) return;
604
+ const assignments = setClause.split(",");
605
+ let placeholderIndex = 0;
606
+ for (const assignment of assignments) {
607
+ if (!assignment.includes("?")) continue;
608
+ placeholderIndex += 1;
609
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
610
+ if (colMatch && boolColumns.has(colMatch[1])) {
611
+ args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
612
+ }
613
+ }
614
+ }
615
+ function coerceBooleanArgs(sql, args) {
616
+ const nextArgs = [...args];
617
+ coerceInsertBooleanArgs(sql, nextArgs);
618
+ coerceUpdateBooleanArgs(sql, nextArgs);
619
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
620
+ for (const index of placeholderIndexes) {
621
+ if (index > 0 && index <= nextArgs.length) {
622
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
623
+ }
624
+ }
625
+ return nextArgs;
626
+ }
627
+ function convertQuestionMarksToDollarParams(sql) {
628
+ let out = "";
629
+ let placeholder = 0;
630
+ let inSingle = false;
631
+ let inDouble = false;
632
+ let inLineComment = false;
633
+ let inBlockComment = false;
634
+ for (let i = 0; i < sql.length; i++) {
635
+ const ch = sql[i];
636
+ const next = sql[i + 1];
637
+ if (inLineComment) {
638
+ out += ch;
639
+ if (ch === "\n") inLineComment = false;
640
+ continue;
641
+ }
642
+ if (inBlockComment) {
643
+ out += ch;
644
+ if (ch === "*" && next === "/") {
645
+ out += next;
646
+ inBlockComment = false;
647
+ i += 1;
648
+ }
649
+ continue;
650
+ }
651
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
652
+ out += ch + next;
653
+ inLineComment = true;
654
+ i += 1;
655
+ continue;
656
+ }
657
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
658
+ out += ch + next;
659
+ inBlockComment = true;
660
+ i += 1;
661
+ continue;
662
+ }
663
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
664
+ inSingle = !inSingle;
665
+ out += ch;
666
+ continue;
667
+ }
668
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
669
+ inDouble = !inDouble;
670
+ out += ch;
671
+ continue;
672
+ }
673
+ if (!inSingle && !inDouble && ch === "?") {
674
+ placeholder += 1;
675
+ out += `$${placeholder}`;
676
+ continue;
677
+ }
678
+ out += ch;
679
+ }
680
+ return out;
681
+ }
682
+ function translateStatementForPostgres(stmt) {
683
+ const normalized = normalizeStatement(stmt);
684
+ if (normalized.kind === "named") {
685
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
686
+ }
687
+ const rewrittenSql = rewriteSql(normalized.sql);
688
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
689
+ return {
690
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
691
+ args: coercedArgs
692
+ };
693
+ }
694
+ function shouldBypassPostgres(stmt) {
695
+ const normalized = normalizeStatement(stmt);
696
+ if (normalized.kind === "named") {
697
+ return true;
698
+ }
699
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
700
+ }
701
+ function shouldFallbackOnError(error) {
702
+ const message = error instanceof Error ? error.message : String(error);
703
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
704
+ }
705
+ function isReadQuery(sql) {
706
+ const trimmed = sql.trimStart();
707
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
708
+ }
709
+ function buildRow(row, columns) {
710
+ const values = columns.map((column) => row[column]);
711
+ return Object.assign(values, row);
712
+ }
713
+ function buildResultSet(rows, rowsAffected = 0) {
714
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
715
+ const resultRows = rows.map((row) => buildRow(row, columns));
716
+ return {
717
+ columns,
718
+ columnTypes: columns.map(() => ""),
719
+ rows: resultRows,
720
+ rowsAffected,
721
+ lastInsertRowid: void 0,
722
+ toJSON() {
723
+ return {
724
+ columns,
725
+ columnTypes: columns.map(() => ""),
726
+ rows,
727
+ rowsAffected,
728
+ lastInsertRowid: void 0
729
+ };
730
+ }
731
+ };
732
+ }
733
+ async function loadPrismaClient() {
734
+ if (!prismaClientPromise) {
735
+ prismaClientPromise = (async () => {
736
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
737
+ if (explicitPath) {
738
+ const module2 = await import(pathToFileURL(explicitPath).href);
739
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
740
+ if (!PrismaClient2) {
741
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
742
+ }
743
+ return new PrismaClient2();
744
+ }
745
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os3.homedir(), "exe-db");
746
+ const requireFromExeDb = createRequire(path3.join(exeDbRoot, "package.json"));
747
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
748
+ const module = await import(pathToFileURL(prismaEntry).href);
749
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
750
+ if (!PrismaClient) {
751
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
752
+ }
753
+ return new PrismaClient();
754
+ })();
755
+ }
756
+ return prismaClientPromise;
757
+ }
758
+ async function ensureCompatibilityViews(prisma) {
759
+ if (!compatibilityBootstrapPromise) {
760
+ compatibilityBootstrapPromise = (async () => {
761
+ for (const mapping of VIEW_MAPPINGS) {
762
+ const relation = mapping.source.replace(/"/g, "");
763
+ const rows = await prisma.$queryRawUnsafe(
764
+ "SELECT to_regclass($1) AS regclass",
765
+ relation
766
+ );
767
+ if (!rows[0]?.regclass) {
768
+ continue;
769
+ }
770
+ await prisma.$executeRawUnsafe(
771
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
772
+ );
773
+ }
774
+ })();
775
+ }
776
+ return compatibilityBootstrapPromise;
777
+ }
778
+ async function executeOnPrisma(executor, stmt) {
779
+ const translated = translateStatementForPostgres(stmt);
780
+ if (isReadQuery(translated.sql)) {
781
+ const rows = await executor.$queryRawUnsafe(
782
+ translated.sql,
783
+ ...translated.args
784
+ );
785
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
786
+ }
787
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
788
+ return buildResultSet([], rowsAffected);
789
+ }
790
+ function splitSqlStatements(sql) {
791
+ const parts = [];
792
+ let current = "";
793
+ let inSingle = false;
794
+ let inDouble = false;
795
+ let inLineComment = false;
796
+ let inBlockComment = false;
797
+ for (let i = 0; i < sql.length; i++) {
798
+ const ch = sql[i];
799
+ const next = sql[i + 1];
800
+ if (inLineComment) {
801
+ current += ch;
802
+ if (ch === "\n") inLineComment = false;
803
+ continue;
804
+ }
805
+ if (inBlockComment) {
806
+ current += ch;
807
+ if (ch === "*" && next === "/") {
808
+ current += next;
809
+ inBlockComment = false;
810
+ i += 1;
811
+ }
812
+ continue;
813
+ }
814
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
815
+ current += ch + next;
816
+ inLineComment = true;
817
+ i += 1;
818
+ continue;
819
+ }
820
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
821
+ current += ch + next;
822
+ inBlockComment = true;
823
+ i += 1;
824
+ continue;
825
+ }
826
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
827
+ inSingle = !inSingle;
828
+ current += ch;
829
+ continue;
830
+ }
831
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
832
+ inDouble = !inDouble;
833
+ current += ch;
834
+ continue;
835
+ }
836
+ if (!inSingle && !inDouble && ch === ";") {
837
+ if (current.trim()) {
838
+ parts.push(current.trim());
839
+ }
840
+ current = "";
841
+ continue;
842
+ }
843
+ current += ch;
844
+ }
845
+ if (current.trim()) {
846
+ parts.push(current.trim());
847
+ }
848
+ return parts;
849
+ }
850
+ async function createPrismaDbAdapter(fallbackClient) {
851
+ const prisma = await loadPrismaClient();
852
+ await ensureCompatibilityViews(prisma);
853
+ let closed = false;
854
+ let adapter;
855
+ const fallbackExecute = async (stmt, error) => {
856
+ if (!fallbackClient) {
857
+ if (error) throw error;
858
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
859
+ }
860
+ if (error) {
861
+ process.stderr.write(
862
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
863
+ `
864
+ );
865
+ }
866
+ return fallbackClient.execute(stmt);
867
+ };
868
+ adapter = {
869
+ async execute(stmt) {
870
+ if (shouldBypassPostgres(stmt)) {
871
+ return fallbackExecute(stmt);
872
+ }
873
+ try {
874
+ return await executeOnPrisma(prisma, stmt);
875
+ } catch (error) {
876
+ if (shouldFallbackOnError(error)) {
877
+ return fallbackExecute(stmt, error);
878
+ }
879
+ throw error;
880
+ }
881
+ },
882
+ async batch(stmts, mode) {
883
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
884
+ if (!fallbackClient) {
885
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
886
+ }
887
+ return fallbackClient.batch(stmts, mode);
888
+ }
889
+ try {
890
+ if (prisma.$transaction) {
891
+ return await prisma.$transaction(async (tx) => {
892
+ const results2 = [];
893
+ for (const stmt of stmts) {
894
+ results2.push(await executeOnPrisma(tx, stmt));
895
+ }
896
+ return results2;
897
+ });
898
+ }
899
+ const results = [];
900
+ for (const stmt of stmts) {
901
+ results.push(await executeOnPrisma(prisma, stmt));
902
+ }
903
+ return results;
904
+ } catch (error) {
905
+ if (fallbackClient && shouldFallbackOnError(error)) {
906
+ process.stderr.write(
907
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
908
+ `
909
+ );
910
+ return fallbackClient.batch(stmts, mode);
911
+ }
912
+ throw error;
913
+ }
914
+ },
915
+ async migrate(stmts) {
916
+ if (fallbackClient) {
917
+ return fallbackClient.migrate(stmts);
918
+ }
919
+ return adapter.batch(stmts, "deferred");
920
+ },
921
+ async transaction(mode) {
922
+ if (!fallbackClient) {
923
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
924
+ }
925
+ return fallbackClient.transaction(mode);
926
+ },
927
+ async executeMultiple(sql) {
928
+ if (fallbackClient && shouldBypassPostgres(sql)) {
929
+ return fallbackClient.executeMultiple(sql);
930
+ }
931
+ for (const statement of splitSqlStatements(sql)) {
932
+ await adapter.execute(statement);
933
+ }
934
+ },
935
+ async sync() {
936
+ if (fallbackClient) {
937
+ return fallbackClient.sync();
938
+ }
939
+ return { frame_no: 0, frames_synced: 0 };
940
+ },
941
+ close() {
942
+ closed = true;
943
+ prismaClientPromise = null;
944
+ compatibilityBootstrapPromise = null;
945
+ void prisma.$disconnect?.();
946
+ },
947
+ get closed() {
948
+ return closed;
949
+ },
950
+ get protocol() {
951
+ return "prisma-postgres";
952
+ }
953
+ };
954
+ return adapter;
955
+ }
956
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
957
+ var init_database_adapter = __esm({
958
+ "src/lib/database-adapter.ts"() {
959
+ "use strict";
960
+ VIEW_MAPPINGS = [
961
+ { view: "memories", source: "memory.memory_records" },
962
+ { view: "tasks", source: "memory.tasks" },
963
+ { view: "behaviors", source: "memory.behaviors" },
964
+ { view: "entities", source: "memory.entities" },
965
+ { view: "relationships", source: "memory.relationships" },
966
+ { view: "entity_memories", source: "memory.entity_memories" },
967
+ { view: "entity_aliases", source: "memory.entity_aliases" },
968
+ { view: "notifications", source: "memory.notifications" },
969
+ { view: "messages", source: "memory.messages" },
970
+ { view: "users", source: "wiki.users" },
971
+ { view: "workspaces", source: "wiki.workspaces" },
972
+ { view: "workspace_users", source: "wiki.workspace_users" },
973
+ { view: "documents", source: "wiki.workspace_documents" },
974
+ { view: "chats", source: "wiki.workspace_chats" }
975
+ ];
976
+ UPSERT_KEYS = {
977
+ memories: ["id"],
978
+ tasks: ["id"],
979
+ behaviors: ["id"],
980
+ entities: ["id"],
981
+ relationships: ["id"],
982
+ entity_aliases: ["alias"],
983
+ notifications: ["id"],
984
+ messages: ["id"],
985
+ users: ["id"],
986
+ workspaces: ["id"],
987
+ workspace_users: ["id"],
988
+ documents: ["id"],
989
+ chats: ["id"]
990
+ };
991
+ BOOLEAN_COLUMNS_BY_TABLE = {
992
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
993
+ behaviors: /* @__PURE__ */ new Set(["active"]),
994
+ notifications: /* @__PURE__ */ new Set(["read"]),
995
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
996
+ };
997
+ BOOLEAN_COLUMN_NAMES = new Set(
998
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
999
+ );
1000
+ IMMEDIATE_FALLBACK_PATTERNS = [
1001
+ /\bPRAGMA\b/i,
1002
+ /\bsqlite_master\b/i,
1003
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
1004
+ /\bMATCH\b/i,
1005
+ /\bvector_distance_cos\s*\(/i,
1006
+ /\bjson_extract\s*\(/i,
1007
+ /\bjulianday\s*\(/i,
1008
+ /\bstrftime\s*\(/i,
1009
+ /\blast_insert_rowid\s*\(/i
1010
+ ];
1011
+ prismaClientPromise = null;
1012
+ compatibilityBootstrapPromise = null;
428
1013
  }
429
1014
  });
430
1015
 
431
1016
  // src/lib/exe-daemon-client.ts
432
1017
  import net from "net";
433
- import os3 from "os";
1018
+ import os4 from "os";
434
1019
  import { spawn } from "child_process";
435
1020
  import { randomUUID } from "crypto";
436
1021
  import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
437
- import path3 from "path";
1022
+ import path4 from "path";
438
1023
  import { fileURLToPath } from "url";
439
1024
  function handleData(chunk) {
440
1025
  _buffer += chunk.toString();
@@ -485,17 +1070,17 @@ function cleanupStaleFiles() {
485
1070
  }
486
1071
  }
487
1072
  function findPackageRoot() {
488
- let dir = path3.dirname(fileURLToPath(import.meta.url));
489
- const { root } = path3.parse(dir);
1073
+ let dir = path4.dirname(fileURLToPath(import.meta.url));
1074
+ const { root } = path4.parse(dir);
490
1075
  while (dir !== root) {
491
- if (existsSync3(path3.join(dir, "package.json"))) return dir;
492
- dir = path3.dirname(dir);
1076
+ if (existsSync3(path4.join(dir, "package.json"))) return dir;
1077
+ dir = path4.dirname(dir);
493
1078
  }
494
1079
  return null;
495
1080
  }
496
1081
  function spawnDaemon() {
497
- const freeGB = os3.freemem() / (1024 * 1024 * 1024);
498
- const totalGB = os3.totalmem() / (1024 * 1024 * 1024);
1082
+ const freeGB = os4.freemem() / (1024 * 1024 * 1024);
1083
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
499
1084
  if (totalGB <= 8) {
500
1085
  process.stderr.write(
501
1086
  `[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
@@ -515,7 +1100,7 @@ function spawnDaemon() {
515
1100
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
516
1101
  return;
517
1102
  }
518
- const daemonPath = path3.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1103
+ const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
519
1104
  if (!existsSync3(daemonPath)) {
520
1105
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
521
1106
  `);
@@ -524,7 +1109,7 @@ function spawnDaemon() {
524
1109
  const resolvedPath = daemonPath;
525
1110
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
526
1111
  `);
527
- const logPath = path3.join(path3.dirname(SOCKET_PATH), "exed.log");
1112
+ const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
528
1113
  let stderrFd = "ignore";
529
1114
  try {
530
1115
  stderrFd = openSync(logPath, "a");
@@ -675,74 +1260,123 @@ async function pingDaemon() {
675
1260
  return null;
676
1261
  }
677
1262
  function killAndRespawnDaemon() {
678
- process.stderr.write("[exed-client] Killing daemon for restart...\n");
679
- if (existsSync3(PID_PATH)) {
680
- try {
681
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
682
- if (pid > 0) {
683
- try {
684
- process.kill(pid, "SIGKILL");
685
- } catch {
1263
+ if (!acquireSpawnLock()) {
1264
+ process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
1265
+ if (_socket) {
1266
+ _socket.destroy();
1267
+ _socket = null;
1268
+ }
1269
+ _connected = false;
1270
+ _buffer = "";
1271
+ return;
1272
+ }
1273
+ try {
1274
+ process.stderr.write("[exed-client] Killing daemon for restart...\n");
1275
+ if (existsSync3(PID_PATH)) {
1276
+ try {
1277
+ const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
1278
+ if (pid > 0) {
1279
+ try {
1280
+ process.kill(pid, "SIGKILL");
1281
+ } catch {
1282
+ }
686
1283
  }
1284
+ } catch {
687
1285
  }
1286
+ }
1287
+ if (_socket) {
1288
+ _socket.destroy();
1289
+ _socket = null;
1290
+ }
1291
+ _connected = false;
1292
+ _buffer = "";
1293
+ try {
1294
+ unlinkSync2(PID_PATH);
688
1295
  } catch {
689
1296
  }
1297
+ try {
1298
+ unlinkSync2(SOCKET_PATH);
1299
+ } catch {
1300
+ }
1301
+ spawnDaemon();
1302
+ } finally {
1303
+ releaseSpawnLock();
690
1304
  }
691
- if (_socket) {
692
- _socket.destroy();
693
- _socket = null;
694
- }
695
- _connected = false;
696
- _buffer = "";
1305
+ }
1306
+ function isDaemonTooYoung() {
697
1307
  try {
698
- unlinkSync2(PID_PATH);
1308
+ const stat = statSync(PID_PATH);
1309
+ return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
699
1310
  } catch {
1311
+ return false;
700
1312
  }
701
- try {
702
- unlinkSync2(SOCKET_PATH);
703
- } catch {
1313
+ }
1314
+ async function retryThenRestart(doRequest, label) {
1315
+ const result = await doRequest();
1316
+ if (!result.error) {
1317
+ _consecutiveFailures = 0;
1318
+ return result;
704
1319
  }
705
- spawnDaemon();
1320
+ _consecutiveFailures++;
1321
+ for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
1322
+ const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
1323
+ process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
1324
+ `);
1325
+ await new Promise((r) => setTimeout(r, delayMs));
1326
+ if (!_connected) {
1327
+ if (!await connectToSocket()) continue;
1328
+ }
1329
+ const retry = await doRequest();
1330
+ if (!retry.error) {
1331
+ _consecutiveFailures = 0;
1332
+ return retry;
1333
+ }
1334
+ _consecutiveFailures++;
1335
+ }
1336
+ if (isDaemonTooYoung()) {
1337
+ process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
1338
+ `);
1339
+ return { error: result.error };
1340
+ }
1341
+ process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
1342
+ `);
1343
+ killAndRespawnDaemon();
1344
+ const start = Date.now();
1345
+ let delay2 = 200;
1346
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1347
+ await new Promise((r) => setTimeout(r, delay2));
1348
+ if (await connectToSocket()) break;
1349
+ delay2 = Math.min(delay2 * 2, 3e3);
1350
+ }
1351
+ if (!_connected) return { error: "Daemon restart failed" };
1352
+ const final = await doRequest();
1353
+ if (!final.error) _consecutiveFailures = 0;
1354
+ return final;
706
1355
  }
707
1356
  async function embedViaClient(text, priority = "high") {
708
1357
  if (!_connected && !await connectEmbedDaemon()) return null;
709
1358
  _requestCount++;
710
1359
  if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
711
1360
  const health = await pingDaemon();
712
- if (!health) {
1361
+ if (!health && !isDaemonTooYoung()) {
713
1362
  process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
714
1363
  `);
715
1364
  killAndRespawnDaemon();
716
1365
  const start = Date.now();
717
- let delay2 = 200;
1366
+ let d = 200;
718
1367
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
719
- await new Promise((r) => setTimeout(r, delay2));
1368
+ await new Promise((r) => setTimeout(r, d));
720
1369
  if (await connectToSocket()) break;
721
- delay2 = Math.min(delay2 * 2, 3e3);
1370
+ d = Math.min(d * 2, 3e3);
722
1371
  }
723
1372
  if (!_connected) return null;
724
1373
  }
725
1374
  }
726
- const result = await sendRequest([text], priority);
727
- if (!result.error && result.vectors?.[0]) return result.vectors[0];
728
- if (result.error) {
729
- process.stderr.write(`[exed-client] Embed failed (${result.error}) \u2014 attempting restart
730
- `);
731
- killAndRespawnDaemon();
732
- const start = Date.now();
733
- let delay2 = 200;
734
- while (Date.now() - start < CONNECT_TIMEOUT_MS) {
735
- await new Promise((r) => setTimeout(r, delay2));
736
- if (await connectToSocket()) break;
737
- delay2 = Math.min(delay2 * 2, 3e3);
738
- }
739
- if (!_connected) return null;
740
- const retry = await sendRequest([text], priority);
741
- if (!retry.error && retry.vectors?.[0]) return retry.vectors[0];
742
- process.stderr.write(`[exed-client] Embed retry also failed: ${retry.error ?? "no vector"}
743
- `);
744
- }
745
- return null;
1375
+ const result = await retryThenRestart(
1376
+ () => sendRequest([text], priority),
1377
+ "Embed"
1378
+ );
1379
+ return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
746
1380
  }
747
1381
  function disconnectClient() {
748
1382
  if (_socket) {
@@ -760,14 +1394,14 @@ function disconnectClient() {
760
1394
  function isClientConnected() {
761
1395
  return _connected;
762
1396
  }
763
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
1397
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
764
1398
  var init_exe_daemon_client = __esm({
765
1399
  "src/lib/exe-daemon-client.ts"() {
766
1400
  "use strict";
767
1401
  init_config();
768
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path3.join(EXE_AI_DIR, "exed.sock");
769
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path3.join(EXE_AI_DIR, "exed.pid");
770
- SPAWN_LOCK_PATH = path3.join(EXE_AI_DIR, "exed-spawn.lock");
1402
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
1403
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
1404
+ SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
771
1405
  SPAWN_LOCK_STALE_MS = 3e4;
772
1406
  CONNECT_TIMEOUT_MS = 15e3;
773
1407
  REQUEST_TIMEOUT_MS = 3e4;
@@ -775,7 +1409,11 @@ var init_exe_daemon_client = __esm({
775
1409
  _connected = false;
776
1410
  _buffer = "";
777
1411
  _requestCount = 0;
1412
+ _consecutiveFailures = 0;
778
1413
  HEALTH_CHECK_INTERVAL = 100;
1414
+ MAX_RETRIES_BEFORE_RESTART = 3;
1415
+ RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
1416
+ MIN_DAEMON_AGE_MS = 3e4;
779
1417
  _pending = /* @__PURE__ */ new Map();
780
1418
  MAX_BUFFER = 1e7;
781
1419
  }
@@ -851,7 +1489,7 @@ __export(db_daemon_client_exports, {
851
1489
  createDaemonDbClient: () => createDaemonDbClient,
852
1490
  initDaemonDbClient: () => initDaemonDbClient
853
1491
  });
854
- function normalizeStatement(stmt) {
1492
+ function normalizeStatement2(stmt) {
855
1493
  if (typeof stmt === "string") {
856
1494
  return { sql: stmt, args: [] };
857
1495
  }
@@ -875,7 +1513,7 @@ function createDaemonDbClient(fallbackClient) {
875
1513
  if (!_useDaemon || !isClientConnected()) {
876
1514
  return fallbackClient.execute(stmt);
877
1515
  }
878
- const { sql, args } = normalizeStatement(stmt);
1516
+ const { sql, args } = normalizeStatement2(stmt);
879
1517
  const response = await sendDaemonRequest({
880
1518
  type: "db-execute",
881
1519
  sql,
@@ -900,7 +1538,7 @@ function createDaemonDbClient(fallbackClient) {
900
1538
  if (!_useDaemon || !isClientConnected()) {
901
1539
  return fallbackClient.batch(stmts, mode);
902
1540
  }
903
- const statements = stmts.map(normalizeStatement);
1541
+ const statements = stmts.map(normalizeStatement2);
904
1542
  const response = await sendDaemonRequest({
905
1543
  type: "db-batch",
906
1544
  statements,
@@ -995,6 +1633,18 @@ __export(database_exports, {
995
1633
  });
996
1634
  import { createClient } from "@libsql/client";
997
1635
  async function initDatabase(config) {
1636
+ if (_walCheckpointTimer) {
1637
+ clearInterval(_walCheckpointTimer);
1638
+ _walCheckpointTimer = null;
1639
+ }
1640
+ if (_daemonClient) {
1641
+ _daemonClient.close();
1642
+ _daemonClient = null;
1643
+ }
1644
+ if (_adapterClient && _adapterClient !== _resilientClient) {
1645
+ _adapterClient.close();
1646
+ }
1647
+ _adapterClient = null;
998
1648
  if (_client) {
999
1649
  _client.close();
1000
1650
  _client = null;
@@ -1008,6 +1658,7 @@ async function initDatabase(config) {
1008
1658
  }
1009
1659
  _client = createClient(opts);
1010
1660
  _resilientClient = wrapWithRetry(_client);
1661
+ _adapterClient = _resilientClient;
1011
1662
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1012
1663
  });
1013
1664
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -1018,14 +1669,20 @@ async function initDatabase(config) {
1018
1669
  });
1019
1670
  }, 3e4);
1020
1671
  _walCheckpointTimer.unref();
1672
+ if (process.env.DATABASE_URL) {
1673
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
1674
+ }
1021
1675
  }
1022
1676
  function isInitialized() {
1023
- return _client !== null;
1677
+ return _adapterClient !== null || _client !== null;
1024
1678
  }
1025
1679
  function getClient() {
1026
- if (!_resilientClient) {
1680
+ if (!_adapterClient) {
1027
1681
  throw new Error("Database client not initialized. Call initDatabase() first.");
1028
1682
  }
1683
+ if (process.env.DATABASE_URL) {
1684
+ return _adapterClient;
1685
+ }
1029
1686
  if (process.env.EXE_IS_DAEMON === "1") {
1030
1687
  return _resilientClient;
1031
1688
  }
@@ -1035,6 +1692,7 @@ function getClient() {
1035
1692
  return _resilientClient;
1036
1693
  }
1037
1694
  async function initDaemonClient() {
1695
+ if (process.env.DATABASE_URL) return;
1038
1696
  if (process.env.EXE_IS_DAEMON === "1") return;
1039
1697
  if (!_resilientClient) return;
1040
1698
  try {
@@ -1979,26 +2637,36 @@ async function ensureSchema() {
1979
2637
  }
1980
2638
  }
1981
2639
  async function disposeDatabase() {
2640
+ if (_walCheckpointTimer) {
2641
+ clearInterval(_walCheckpointTimer);
2642
+ _walCheckpointTimer = null;
2643
+ }
1982
2644
  if (_daemonClient) {
1983
2645
  _daemonClient.close();
1984
2646
  _daemonClient = null;
1985
2647
  }
2648
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2649
+ _adapterClient.close();
2650
+ }
2651
+ _adapterClient = null;
1986
2652
  if (_client) {
1987
2653
  _client.close();
1988
2654
  _client = null;
1989
2655
  _resilientClient = null;
1990
2656
  }
1991
2657
  }
1992
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
2658
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
1993
2659
  var init_database = __esm({
1994
2660
  "src/lib/database.ts"() {
1995
2661
  "use strict";
1996
2662
  init_db_retry();
1997
2663
  init_employees();
2664
+ init_database_adapter();
1998
2665
  _client = null;
1999
2666
  _resilientClient = null;
2000
2667
  _walCheckpointTimer = null;
2001
2668
  _daemonClient = null;
2669
+ _adapterClient = null;
2002
2670
  initTurso = initDatabase;
2003
2671
  disposeTurso = disposeDatabase;
2004
2672
  }
@@ -2015,13 +2683,13 @@ __export(keychain_exports, {
2015
2683
  });
2016
2684
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2017
2685
  import { existsSync as existsSync4 } from "fs";
2018
- import path4 from "path";
2019
- import os4 from "os";
2686
+ import path5 from "path";
2687
+ import os5 from "os";
2020
2688
  function getKeyDir() {
2021
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
2689
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os5.homedir(), ".exe-os");
2022
2690
  }
2023
2691
  function getKeyPath() {
2024
- return path4.join(getKeyDir(), "master.key");
2692
+ return path5.join(getKeyDir(), "master.key");
2025
2693
  }
2026
2694
  async function tryKeytar() {
2027
2695
  try {
@@ -2044,7 +2712,7 @@ async function getMasterKey() {
2044
2712
  const keyPath = getKeyPath();
2045
2713
  if (!existsSync4(keyPath)) {
2046
2714
  process.stderr.write(
2047
- `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2715
+ `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2048
2716
  `
2049
2717
  );
2050
2718
  return null;
@@ -2195,7 +2863,7 @@ __export(shard_manager_exports, {
2195
2863
  listShards: () => listShards,
2196
2864
  shardExists: () => shardExists
2197
2865
  });
2198
- import path5 from "path";
2866
+ import path6 from "path";
2199
2867
  import { existsSync as existsSync5, mkdirSync, readdirSync } from "fs";
2200
2868
  import { createClient as createClient2 } from "@libsql/client";
2201
2869
  function initShardManager(encryptionKey) {
@@ -2221,7 +2889,7 @@ function getShardClient(projectName) {
2221
2889
  }
2222
2890
  const cached = _shards.get(safeName);
2223
2891
  if (cached) return cached;
2224
- const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
2892
+ const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
2225
2893
  const client = createClient2({
2226
2894
  url: `file:${dbPath}`,
2227
2895
  encryptionKey: _encryptionKey
@@ -2231,7 +2899,7 @@ function getShardClient(projectName) {
2231
2899
  }
2232
2900
  function shardExists(projectName) {
2233
2901
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2234
- return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
2902
+ return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
2235
2903
  }
2236
2904
  function listShards() {
2237
2905
  if (!existsSync5(SHARDS_DIR)) return [];
@@ -2308,7 +2976,23 @@ async function ensureShardSchema(client) {
2308
2976
  // MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
2309
2977
  "ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
2310
2978
  "ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
2311
- "ALTER TABLE memories ADD COLUMN trajectory TEXT"
2979
+ "ALTER TABLE memories ADD COLUMN trajectory TEXT",
2980
+ // Metadata enrichment columns (must match database.ts)
2981
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
2982
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
2983
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
2984
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
2985
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
2986
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
2987
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
2988
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
2989
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
2990
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
2991
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
2992
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
2993
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
2994
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
2995
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
2312
2996
  ]) {
2313
2997
  try {
2314
2998
  await client.execute(col);
@@ -2420,7 +3104,7 @@ var init_shard_manager = __esm({
2420
3104
  "src/lib/shard-manager.ts"() {
2421
3105
  "use strict";
2422
3106
  init_config();
2423
- SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
3107
+ SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
2424
3108
  _shards = /* @__PURE__ */ new Map();
2425
3109
  _encryptionKey = null;
2426
3110
  _shardingEnabled = false;
@@ -2616,8 +3300,8 @@ ${p.content}`).join("\n\n");
2616
3300
 
2617
3301
  // src/lib/notifications.ts
2618
3302
  import crypto from "crypto";
2619
- import path6 from "path";
2620
- import os5 from "os";
3303
+ import path7 from "path";
3304
+ import os6 from "os";
2621
3305
  import {
2622
3306
  readFileSync as readFileSync4,
2623
3307
  readdirSync as readdirSync2,
@@ -2657,13 +3341,13 @@ var init_notifications = __esm({
2657
3341
  });
2658
3342
 
2659
3343
  // src/lib/session-registry.ts
2660
- import path7 from "path";
2661
- import os6 from "os";
3344
+ import path8 from "path";
3345
+ import os7 from "os";
2662
3346
  var REGISTRY_PATH;
2663
3347
  var init_session_registry = __esm({
2664
3348
  "src/lib/session-registry.ts"() {
2665
3349
  "use strict";
2666
- REGISTRY_PATH = path7.join(os6.homedir(), ".exe-os", "session-registry.json");
3350
+ REGISTRY_PATH = path8.join(os7.homedir(), ".exe-os", "session-registry.json");
2667
3351
  }
2668
3352
  });
2669
3353
 
@@ -2899,14 +3583,14 @@ var init_runtime_table = __esm({
2899
3583
 
2900
3584
  // src/lib/agent-config.ts
2901
3585
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
2902
- import path8 from "path";
3586
+ import path9 from "path";
2903
3587
  var AGENT_CONFIG_PATH, DEFAULT_MODELS;
2904
3588
  var init_agent_config = __esm({
2905
3589
  "src/lib/agent-config.ts"() {
2906
3590
  "use strict";
2907
3591
  init_config();
2908
3592
  init_runtime_table();
2909
- AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
3593
+ AGENT_CONFIG_PATH = path9.join(EXE_AI_DIR, "agent-config.json");
2910
3594
  DEFAULT_MODELS = {
2911
3595
  claude: "claude-opus-4",
2912
3596
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
@@ -2917,15 +3601,15 @@ var init_agent_config = __esm({
2917
3601
 
2918
3602
  // src/lib/intercom-queue.ts
2919
3603
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
2920
- import path9 from "path";
2921
- import os7 from "os";
3604
+ import path10 from "path";
3605
+ import os8 from "os";
2922
3606
  var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
2923
3607
  var init_intercom_queue = __esm({
2924
3608
  "src/lib/intercom-queue.ts"() {
2925
3609
  "use strict";
2926
- QUEUE_PATH = path9.join(os7.homedir(), ".exe-os", "intercom-queue.json");
3610
+ QUEUE_PATH = path10.join(os8.homedir(), ".exe-os", "intercom-queue.json");
2927
3611
  TTL_MS = 60 * 60 * 1e3;
2928
- INTERCOM_LOG = path9.join(os7.homedir(), ".exe-os", "intercom.log");
3612
+ INTERCOM_LOG = path10.join(os8.homedir(), ".exe-os", "intercom.log");
2929
3613
  }
2930
3614
  });
2931
3615
 
@@ -2948,7 +3632,7 @@ __export(license_exports, {
2948
3632
  });
2949
3633
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
2950
3634
  import { randomUUID as randomUUID3 } from "crypto";
2951
- import path10 from "path";
3635
+ import path11 from "path";
2952
3636
  import { jwtVerify, importSPKI } from "jose";
2953
3637
  async function fetchRetry(url, init) {
2954
3638
  try {
@@ -2959,7 +3643,7 @@ async function fetchRetry(url, init) {
2959
3643
  }
2960
3644
  }
2961
3645
  function loadDeviceId() {
2962
- const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
3646
+ const deviceJsonPath = path11.join(EXE_AI_DIR, "device.json");
2963
3647
  try {
2964
3648
  if (existsSync9(deviceJsonPath)) {
2965
3649
  const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
@@ -3124,7 +3808,7 @@ async function checkLicense() {
3124
3808
  let key = loadLicense();
3125
3809
  if (!key) {
3126
3810
  try {
3127
- const configPath = path10.join(EXE_AI_DIR, "config.json");
3811
+ const configPath = path11.join(EXE_AI_DIR, "config.json");
3128
3812
  if (existsSync9(configPath)) {
3129
3813
  const raw = JSON.parse(readFileSync7(configPath, "utf8"));
3130
3814
  const cloud = raw.cloud;
@@ -3285,9 +3969,9 @@ var init_license = __esm({
3285
3969
  "src/lib/license.ts"() {
3286
3970
  "use strict";
3287
3971
  init_config();
3288
- LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
3289
- CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
3290
- DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
3972
+ LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
3973
+ CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
3974
+ DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
3291
3975
  API_BASE = "https://askexe.com/cloud";
3292
3976
  RETRY_DELAY_MS = 500;
3293
3977
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -3328,7 +4012,7 @@ __export(plan_limits_exports, {
3328
4012
  getLicenseSync: () => getLicenseSync
3329
4013
  });
3330
4014
  import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
3331
- import path11 from "path";
4015
+ import path12 from "path";
3332
4016
  function getLicenseSync() {
3333
4017
  try {
3334
4018
  if (!existsSync10(CACHE_PATH2)) return freeLicense();
@@ -3437,14 +4121,14 @@ var init_plan_limits = __esm({
3437
4121
  this.name = "PlanLimitError";
3438
4122
  }
3439
4123
  };
3440
- CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
4124
+ CACHE_PATH2 = path12.join(EXE_AI_DIR, "license-cache.json");
3441
4125
  }
3442
4126
  });
3443
4127
 
3444
4128
  // src/lib/tmux-routing.ts
3445
4129
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync, readdirSync as readdirSync3 } from "fs";
3446
- import path12 from "path";
3447
- import os8 from "os";
4130
+ import path13 from "path";
4131
+ import os9 from "os";
3448
4132
  import { fileURLToPath as fileURLToPath2 } from "url";
3449
4133
  function getMySession() {
3450
4134
  return getTransport().getMySession();
@@ -3457,7 +4141,7 @@ function extractRootExe(name) {
3457
4141
  }
3458
4142
  function getParentExe(sessionKey) {
3459
4143
  try {
3460
- const data = JSON.parse(readFileSync9(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
4144
+ const data = JSON.parse(readFileSync9(path13.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3461
4145
  return data.parentExe || null;
3462
4146
  } catch {
3463
4147
  return null;
@@ -3500,10 +4184,10 @@ var init_tmux_routing = __esm({
3500
4184
  init_intercom_queue();
3501
4185
  init_plan_limits();
3502
4186
  init_employees();
3503
- SPAWN_LOCK_DIR = path12.join(os8.homedir(), ".exe-os", "spawn-locks");
3504
- SESSION_CACHE = path12.join(os8.homedir(), ".exe-os", "session-cache");
3505
- INTERCOM_LOG2 = path12.join(os8.homedir(), ".exe-os", "intercom.log");
3506
- DEBOUNCE_FILE = path12.join(SESSION_CACHE, "intercom-debounce.json");
4187
+ SPAWN_LOCK_DIR = path13.join(os9.homedir(), ".exe-os", "spawn-locks");
4188
+ SESSION_CACHE = path13.join(os9.homedir(), ".exe-os", "session-cache");
4189
+ INTERCOM_LOG2 = path13.join(os9.homedir(), ".exe-os", "intercom.log");
4190
+ DEBOUNCE_FILE = path13.join(SESSION_CACHE, "intercom-debounce.json");
3507
4191
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
3508
4192
  }
3509
4193
  });
@@ -3570,8 +4254,8 @@ async function embedDirect(text) {
3570
4254
  const llamaCpp = await import("node-llama-cpp");
3571
4255
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
3572
4256
  const { existsSync: existsSync16 } = await import("fs");
3573
- const path17 = await import("path");
3574
- const modelPath = path17.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
4257
+ const path18 = await import("path");
4258
+ const modelPath = path18.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
3575
4259
  if (!existsSync16(modelPath)) {
3576
4260
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
3577
4261
  }
@@ -3611,12 +4295,12 @@ __export(worker_gate_exports, {
3611
4295
  tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
3612
4296
  });
3613
4297
  import { readdirSync as readdirSync4, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6, existsSync as existsSync12 } from "fs";
3614
- import path13 from "path";
4298
+ import path14 from "path";
3615
4299
  function tryAcquireWorkerSlot() {
3616
4300
  try {
3617
4301
  mkdirSync6(WORKER_PID_DIR, { recursive: true });
3618
4302
  const reservationId = `res-${process.pid}-${Date.now()}`;
3619
- const reservationPath = path13.join(WORKER_PID_DIR, `${reservationId}.pid`);
4303
+ const reservationPath = path14.join(WORKER_PID_DIR, `${reservationId}.pid`);
3620
4304
  writeFileSync6(reservationPath, String(process.pid));
3621
4305
  const files = readdirSync4(WORKER_PID_DIR);
3622
4306
  let alive = 0;
@@ -3634,7 +4318,7 @@ function tryAcquireWorkerSlot() {
3634
4318
  alive++;
3635
4319
  } catch {
3636
4320
  try {
3637
- unlinkSync4(path13.join(WORKER_PID_DIR, f));
4321
+ unlinkSync4(path14.join(WORKER_PID_DIR, f));
3638
4322
  } catch {
3639
4323
  }
3640
4324
  }
@@ -3658,13 +4342,13 @@ function tryAcquireWorkerSlot() {
3658
4342
  function registerWorkerPid(pid) {
3659
4343
  try {
3660
4344
  mkdirSync6(WORKER_PID_DIR, { recursive: true });
3661
- writeFileSync6(path13.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
4345
+ writeFileSync6(path14.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
3662
4346
  } catch {
3663
4347
  }
3664
4348
  }
3665
4349
  function cleanupWorkerPid() {
3666
4350
  try {
3667
- unlinkSync4(path13.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
4351
+ unlinkSync4(path14.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
3668
4352
  } catch {
3669
4353
  }
3670
4354
  }
@@ -3704,9 +4388,9 @@ var init_worker_gate = __esm({
3704
4388
  "src/lib/worker-gate.ts"() {
3705
4389
  "use strict";
3706
4390
  init_config();
3707
- WORKER_PID_DIR = path13.join(EXE_AI_DIR, "worker-pids");
4391
+ WORKER_PID_DIR = path14.join(EXE_AI_DIR, "worker-pids");
3708
4392
  MAX_CONCURRENT_WORKERS = 3;
3709
- BACKFILL_LOCK = path13.join(WORKER_PID_DIR, "backfill.lock");
4393
+ BACKFILL_LOCK = path14.join(WORKER_PID_DIR, "backfill.lock");
3710
4394
  }
3711
4395
  });
3712
4396
 
@@ -3809,7 +4493,7 @@ __export(crdt_sync_exports, {
3809
4493
  });
3810
4494
  import * as Y from "yjs";
3811
4495
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync13, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
3812
- import path14 from "path";
4496
+ import path15 from "path";
3813
4497
  import { homedir } from "os";
3814
4498
  function getStatePath() {
3815
4499
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -3965,7 +4649,7 @@ function persistState() {
3965
4649
  if (!doc) return;
3966
4650
  try {
3967
4651
  const sp = getStatePath();
3968
- const dir = path14.dirname(sp);
4652
+ const dir = path15.dirname(sp);
3969
4653
  if (!existsSync13(dir)) mkdirSync7(dir, { recursive: true });
3970
4654
  const state = Y.encodeStateAsUpdate(doc);
3971
4655
  writeFileSync7(sp, Buffer.from(state));
@@ -4009,7 +4693,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
4009
4693
  var init_crdt_sync = __esm({
4010
4694
  "src/lib/crdt-sync.ts"() {
4011
4695
  "use strict";
4012
- DEFAULT_STATE_PATH = path14.join(homedir(), ".exe-os", "crdt-state.bin");
4696
+ DEFAULT_STATE_PATH = path15.join(homedir(), ".exe-os", "crdt-state.bin");
4013
4697
  _statePathOverride = null;
4014
4698
  doc = null;
4015
4699
  }
@@ -4045,14 +4729,14 @@ __export(cloud_sync_exports, {
4045
4729
  });
4046
4730
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync14, readdirSync as readdirSync5, mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, unlinkSync as unlinkSync6, openSync as openSync2, closeSync as closeSync2 } from "fs";
4047
4731
  import crypto3 from "crypto";
4048
- import path15 from "path";
4732
+ import path16 from "path";
4049
4733
  import { homedir as homedir2 } from "os";
4050
4734
  function sqlSafe(v) {
4051
4735
  return v === void 0 ? null : v;
4052
4736
  }
4053
4737
  function logError(msg) {
4054
4738
  try {
4055
- const logPath = path15.join(homedir2(), ".exe-os", "workers.log");
4739
+ const logPath = path16.join(homedir2(), ".exe-os", "workers.log");
4056
4740
  appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
4057
4741
  `);
4058
4742
  } catch {
@@ -4447,7 +5131,7 @@ async function cloudSync(config) {
4447
5131
  try {
4448
5132
  const employees = await loadEmployees();
4449
5133
  rosterResult.employees = employees.length;
4450
- const idDir = path15.join(EXE_AI_DIR, "identity");
5134
+ const idDir = path16.join(EXE_AI_DIR, "identity");
4451
5135
  if (existsSync14(idDir)) {
4452
5136
  rosterResult.identities = readdirSync5(idDir).filter((f) => f.endsWith(".md")).length;
4453
5137
  }
@@ -4488,9 +5172,9 @@ function consumeRosterDeletions() {
4488
5172
  }
4489
5173
  }
4490
5174
  function buildRosterBlob(paths) {
4491
- const rosterPath = paths?.rosterPath ?? path15.join(EXE_AI_DIR, "exe-employees.json");
4492
- const identityDir = paths?.identityDir ?? path15.join(EXE_AI_DIR, "identity");
4493
- const configPath = paths?.configPath ?? path15.join(EXE_AI_DIR, "config.json");
5175
+ const rosterPath = paths?.rosterPath ?? path16.join(EXE_AI_DIR, "exe-employees.json");
5176
+ const identityDir = paths?.identityDir ?? path16.join(EXE_AI_DIR, "identity");
5177
+ const configPath = paths?.configPath ?? path16.join(EXE_AI_DIR, "config.json");
4494
5178
  let roster = [];
4495
5179
  if (existsSync14(rosterPath)) {
4496
5180
  try {
@@ -4502,7 +5186,7 @@ function buildRosterBlob(paths) {
4502
5186
  if (existsSync14(identityDir)) {
4503
5187
  for (const file of readdirSync5(identityDir).filter((f) => f.endsWith(".md"))) {
4504
5188
  try {
4505
- identities[file] = readFileSync11(path15.join(identityDir, file), "utf-8");
5189
+ identities[file] = readFileSync11(path16.join(identityDir, file), "utf-8");
4506
5190
  } catch {
4507
5191
  }
4508
5192
  }
@@ -4515,7 +5199,7 @@ function buildRosterBlob(paths) {
4515
5199
  }
4516
5200
  }
4517
5201
  let agentConfig;
4518
- const agentConfigPath = path15.join(EXE_AI_DIR, "agent-config.json");
5202
+ const agentConfigPath = path16.join(EXE_AI_DIR, "agent-config.json");
4519
5203
  if (existsSync14(agentConfigPath)) {
4520
5204
  try {
4521
5205
  agentConfig = JSON.parse(readFileSync11(agentConfigPath, "utf-8"));
@@ -4594,7 +5278,7 @@ async function cloudPullRoster(config) {
4594
5278
  }
4595
5279
  }
4596
5280
  function mergeConfig(remoteConfig, configPath) {
4597
- const cfgPath = configPath ?? path15.join(EXE_AI_DIR, "config.json");
5281
+ const cfgPath = configPath ?? path16.join(EXE_AI_DIR, "config.json");
4598
5282
  let local = {};
4599
5283
  if (existsSync14(cfgPath)) {
4600
5284
  try {
@@ -4603,14 +5287,14 @@ function mergeConfig(remoteConfig, configPath) {
4603
5287
  }
4604
5288
  }
4605
5289
  const merged = { ...remoteConfig, ...local };
4606
- const dir = path15.dirname(cfgPath);
5290
+ const dir = path16.dirname(cfgPath);
4607
5291
  if (!existsSync14(dir)) mkdirSync8(dir, { recursive: true });
4608
5292
  writeFileSync8(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
4609
5293
  }
4610
5294
  async function mergeRosterFromRemote(remote, paths) {
4611
5295
  return withRosterLock(async () => {
4612
5296
  const rosterPath = paths?.rosterPath ?? void 0;
4613
- const identityDir = paths?.identityDir ?? path15.join(EXE_AI_DIR, "identity");
5297
+ const identityDir = paths?.identityDir ?? path16.join(EXE_AI_DIR, "identity");
4614
5298
  const localEmployees = await loadEmployees(rosterPath);
4615
5299
  const localNames = new Set(localEmployees.map((e) => e.name));
4616
5300
  let added = 0;
@@ -4632,7 +5316,7 @@ async function mergeRosterFromRemote(remote, paths) {
4632
5316
  const remoteIdentity = remote.identities[matchedKey];
4633
5317
  if (remoteIdentity) {
4634
5318
  if (!existsSync14(identityDir)) mkdirSync8(identityDir, { recursive: true });
4635
- const idPath = path15.join(identityDir, `${remoteEmp.name}.md`);
5319
+ const idPath = path16.join(identityDir, `${remoteEmp.name}.md`);
4636
5320
  let localIdentity = null;
4637
5321
  try {
4638
5322
  localIdentity = existsSync14(idPath) ? readFileSync11(idPath, "utf-8") : null;
@@ -4665,7 +5349,7 @@ async function mergeRosterFromRemote(remote, paths) {
4665
5349
  }
4666
5350
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
4667
5351
  try {
4668
- const agentConfigPath = path15.join(EXE_AI_DIR, "agent-config.json");
5352
+ const agentConfigPath = path16.join(EXE_AI_DIR, "agent-config.json");
4669
5353
  let local = {};
4670
5354
  if (existsSync14(agentConfigPath)) {
4671
5355
  try {
@@ -5112,9 +5796,9 @@ var init_cloud_sync = __esm({
5112
5796
  LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
5113
5797
  FETCH_TIMEOUT_MS = 3e4;
5114
5798
  PUSH_BATCH_SIZE = 5e3;
5115
- ROSTER_LOCK_PATH = path15.join(EXE_AI_DIR, "roster-merge.lock");
5799
+ ROSTER_LOCK_PATH = path16.join(EXE_AI_DIR, "roster-merge.lock");
5116
5800
  LOCK_STALE_MS = 3e4;
5117
- ROSTER_DELETIONS_PATH = path15.join(EXE_AI_DIR, "roster-deletions.json");
5801
+ ROSTER_DELETIONS_PATH = path16.join(EXE_AI_DIR, "roster-deletions.json");
5118
5802
  }
5119
5803
  });
5120
5804
 
@@ -5484,7 +6168,7 @@ init_employees();
5484
6168
  import crypto4 from "crypto";
5485
6169
  import { execSync as execSync4 } from "child_process";
5486
6170
  import { existsSync as existsSync15, mkdirSync as mkdirSync9, openSync as openSync3, closeSync as closeSync3 } from "fs";
5487
- import path16 from "path";
6171
+ import path17 from "path";
5488
6172
  async function main() {
5489
6173
  const agentId = process.env.AGENT_ID ?? "default";
5490
6174
  const agentRole = process.env.AGENT_ROLE ?? "employee";
@@ -5619,7 +6303,7 @@ async function main() {
5619
6303
  }
5620
6304
  try {
5621
6305
  const { EXE_AI_DIR: EXE_AI_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5622
- const flagPath = path16.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
6306
+ const flagPath = path17.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
5623
6307
  if (existsSync15(flagPath)) {
5624
6308
  const { tryAcquireWorkerSlot: tryAcquireWorkerSlot2, registerWorkerPid: registerWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
5625
6309
  if (!tryAcquireWorkerSlot2()) {
@@ -5628,11 +6312,11 @@ async function main() {
5628
6312
  const { spawn: spawn2 } = await import("child_process");
5629
6313
  const { fileURLToPath: fileURLToPath3 } = await import("url");
5630
6314
  const thisFile = fileURLToPath3(import.meta.url);
5631
- const backfillPath = path16.resolve(path16.dirname(thisFile), "backfill-vectors.js");
6315
+ const backfillPath = path17.resolve(path17.dirname(thisFile), "backfill-vectors.js");
5632
6316
  if (existsSync15(backfillPath)) {
5633
6317
  const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5634
- const bLogPath = path16.join(exeDir2, "workers.log");
5635
- mkdirSync9(path16.dirname(bLogPath), { recursive: true });
6318
+ const bLogPath = path17.join(exeDir2, "workers.log");
6319
+ mkdirSync9(path17.dirname(bLogPath), { recursive: true });
5636
6320
  const bLogFd = openSync3(bLogPath, "a");
5637
6321
  const child = spawn2(process.execPath, [backfillPath], {
5638
6322
  detached: true,