@askexenow/exe-os 0.9.6 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/bin/backfill-conversations.js +754 -79
  2. package/dist/bin/backfill-responses.js +752 -77
  3. package/dist/bin/backfill-vectors.js +752 -77
  4. package/dist/bin/cleanup-stale-review-tasks.js +668 -37
  5. package/dist/bin/cli.js +1399 -607
  6. package/dist/bin/exe-agent-config.js +123 -95
  7. package/dist/bin/exe-agent.js +41 -25
  8. package/dist/bin/exe-assign.js +732 -57
  9. package/dist/bin/exe-boot.js +795 -155
  10. package/dist/bin/exe-call.js +209 -138
  11. package/dist/bin/exe-cloud.js +35 -12
  12. package/dist/bin/exe-dispatch.js +703 -72
  13. package/dist/bin/exe-doctor.js +648 -26
  14. package/dist/bin/exe-export-behaviors.js +650 -20
  15. package/dist/bin/exe-forget.js +635 -13
  16. package/dist/bin/exe-gateway.js +1064 -273
  17. package/dist/bin/exe-heartbeat.js +676 -45
  18. package/dist/bin/exe-kill.js +646 -16
  19. package/dist/bin/exe-launch-agent.js +887 -97
  20. package/dist/bin/exe-link.js +658 -43
  21. package/dist/bin/exe-new-employee.js +378 -177
  22. package/dist/bin/exe-pending-messages.js +656 -34
  23. package/dist/bin/exe-pending-notifications.js +635 -13
  24. package/dist/bin/exe-pending-reviews.js +659 -37
  25. package/dist/bin/exe-rename.js +645 -30
  26. package/dist/bin/exe-review.js +635 -13
  27. package/dist/bin/exe-search.js +771 -88
  28. package/dist/bin/exe-session-cleanup.js +845 -152
  29. package/dist/bin/exe-settings.js +127 -91
  30. package/dist/bin/exe-start-codex.js +729 -94
  31. package/dist/bin/exe-start-opencode.js +717 -82
  32. package/dist/bin/exe-status.js +668 -37
  33. package/dist/bin/exe-team.js +635 -13
  34. package/dist/bin/git-sweep.js +731 -91
  35. package/dist/bin/graph-backfill.js +643 -13
  36. package/dist/bin/graph-export.js +646 -16
  37. package/dist/bin/install.js +596 -193
  38. package/dist/bin/scan-tasks.js +735 -95
  39. package/dist/bin/setup.js +1038 -210
  40. package/dist/bin/shard-migrate.js +645 -15
  41. package/dist/bin/wiki-sync.js +646 -16
  42. package/dist/gateway/index.js +1038 -247
  43. package/dist/hooks/bug-report-worker.js +902 -172
  44. package/dist/hooks/commit-complete.js +729 -89
  45. package/dist/hooks/error-recall.js +776 -93
  46. package/dist/hooks/exe-heartbeat-hook.js +85 -71
  47. package/dist/hooks/ingest-worker.js +851 -158
  48. package/dist/hooks/ingest.js +90 -73
  49. package/dist/hooks/instructions-loaded.js +669 -38
  50. package/dist/hooks/notification.js +661 -30
  51. package/dist/hooks/post-compact.js +685 -45
  52. package/dist/hooks/pre-compact.js +729 -89
  53. package/dist/hooks/pre-tool-use.js +883 -127
  54. package/dist/hooks/prompt-ingest-worker.js +758 -83
  55. package/dist/hooks/prompt-submit.js +1071 -321
  56. package/dist/hooks/response-ingest-worker.js +758 -83
  57. package/dist/hooks/session-end.js +732 -92
  58. package/dist/hooks/session-start.js +1042 -209
  59. package/dist/hooks/stop.js +691 -51
  60. package/dist/hooks/subagent-stop.js +685 -45
  61. package/dist/hooks/summary-worker.js +827 -134
  62. package/dist/index.js +1026 -234
  63. package/dist/lib/cloud-sync.js +663 -48
  64. package/dist/lib/consolidation.js +26 -3
  65. package/dist/lib/database.js +626 -18
  66. package/dist/lib/db.js +2261 -0
  67. package/dist/lib/device-registry.js +640 -25
  68. package/dist/lib/embedder.js +96 -43
  69. package/dist/lib/employee-templates.js +16 -0
  70. package/dist/lib/employees.js +259 -83
  71. package/dist/lib/exe-daemon-client.js +101 -63
  72. package/dist/lib/exe-daemon.js +905 -164
  73. package/dist/lib/hybrid-search.js +771 -88
  74. package/dist/lib/identity.js +27 -7
  75. package/dist/lib/messaging.js +66 -30
  76. package/dist/lib/reminders.js +21 -1
  77. package/dist/lib/schedules.js +636 -14
  78. package/dist/lib/skill-learning.js +21 -1
  79. package/dist/lib/store.js +643 -13
  80. package/dist/lib/task-router.js +82 -71
  81. package/dist/lib/tasks.js +109 -73
  82. package/dist/lib/tmux-routing.js +98 -62
  83. package/dist/lib/token-spend.js +26 -6
  84. package/dist/mcp/server.js +1807 -472
  85. package/dist/mcp/tools/complete-reminder.js +21 -1
  86. package/dist/mcp/tools/create-reminder.js +21 -1
  87. package/dist/mcp/tools/create-task.js +301 -166
  88. package/dist/mcp/tools/deactivate-behavior.js +24 -4
  89. package/dist/mcp/tools/list-reminders.js +21 -1
  90. package/dist/mcp/tools/list-tasks.js +206 -40
  91. package/dist/mcp/tools/send-message.js +69 -33
  92. package/dist/mcp/tools/update-task.js +86 -50
  93. package/dist/runtime/index.js +731 -91
  94. package/dist/tui/App.js +864 -125
  95. package/package.json +3 -2
@@ -368,7 +368,7 @@ function registerBinSymlinks(name) {
368
368
  }
369
369
  return { created, skipped, errors };
370
370
  }
371
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
371
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
372
372
  var init_employees = __esm({
373
373
  "src/lib/employees.ts"() {
374
374
  "use strict";
@@ -377,6 +377,7 @@ var init_employees = __esm({
377
377
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
378
378
  COORDINATOR_ROLE = "COO";
379
379
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
380
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
380
381
  }
381
382
  });
382
383
 
@@ -435,13 +436,597 @@ var init_db_retry = __esm({
435
436
  }
436
437
  });
437
438
 
439
+ // src/lib/database-adapter.ts
440
+ import os3 from "os";
441
+ import path3 from "path";
442
+ import { createRequire } from "module";
443
+ import { pathToFileURL } from "url";
444
+ function quotedIdentifier(identifier) {
445
+ return `"${identifier.replace(/"/g, '""')}"`;
446
+ }
447
+ function unqualifiedTableName(name) {
448
+ const raw = name.trim().replace(/^"|"$/g, "");
449
+ const parts = raw.split(".");
450
+ return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
451
+ }
452
+ function stripTrailingSemicolon(sql) {
453
+ return sql.trim().replace(/;+\s*$/u, "");
454
+ }
455
+ function appendClause(sql, clause) {
456
+ const trimmed = stripTrailingSemicolon(sql);
457
+ const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
458
+ if (!returningMatch) {
459
+ return `${trimmed}${clause}`;
460
+ }
461
+ const idx = returningMatch.index;
462
+ return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
463
+ }
464
+ function normalizeStatement(stmt) {
465
+ if (typeof stmt === "string") {
466
+ return { kind: "positional", sql: stmt, args: [] };
467
+ }
468
+ const sql = stmt.sql;
469
+ if (Array.isArray(stmt.args) || stmt.args === void 0) {
470
+ return { kind: "positional", sql, args: stmt.args ?? [] };
471
+ }
472
+ return { kind: "named", sql, args: stmt.args };
473
+ }
474
+ function rewriteBooleanLiterals(sql) {
475
+ let out = sql;
476
+ for (const column of BOOLEAN_COLUMN_NAMES) {
477
+ const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
478
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
479
+ out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
480
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
481
+ out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
482
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
483
+ out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
484
+ }
485
+ return out;
486
+ }
487
+ function rewriteInsertOrIgnore(sql) {
488
+ if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
489
+ return sql;
490
+ }
491
+ const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
492
+ return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
493
+ }
494
+ function rewriteInsertOrReplace(sql) {
495
+ const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
496
+ if (!match) {
497
+ return sql;
498
+ }
499
+ const rawTable = match[1];
500
+ const rawColumns = match[2];
501
+ const remainder = match[3];
502
+ const tableName = unqualifiedTableName(rawTable);
503
+ const conflictKeys = UPSERT_KEYS[tableName];
504
+ if (!conflictKeys?.length) {
505
+ return sql;
506
+ }
507
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
508
+ const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
509
+ const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
510
+ const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
511
+ return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
512
+ }
513
+ function rewriteSql(sql) {
514
+ let out = sql;
515
+ out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
516
+ out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
517
+ out = rewriteBooleanLiterals(out);
518
+ out = rewriteInsertOrReplace(out);
519
+ out = rewriteInsertOrIgnore(out);
520
+ return stripTrailingSemicolon(out);
521
+ }
522
+ function toBoolean(value) {
523
+ if (value === null || value === void 0) return value;
524
+ if (typeof value === "boolean") return value;
525
+ if (typeof value === "number") return value !== 0;
526
+ if (typeof value === "bigint") return value !== 0n;
527
+ if (typeof value === "string") {
528
+ const normalized = value.trim().toLowerCase();
529
+ if (normalized === "0" || normalized === "false") return false;
530
+ if (normalized === "1" || normalized === "true") return true;
531
+ }
532
+ return Boolean(value);
533
+ }
534
+ function countQuestionMarks(sql, end) {
535
+ let count = 0;
536
+ let inSingle = false;
537
+ let inDouble = false;
538
+ let inLineComment = false;
539
+ let inBlockComment = false;
540
+ for (let i = 0; i < end; i++) {
541
+ const ch = sql[i];
542
+ const next = sql[i + 1];
543
+ if (inLineComment) {
544
+ if (ch === "\n") inLineComment = false;
545
+ continue;
546
+ }
547
+ if (inBlockComment) {
548
+ if (ch === "*" && next === "/") {
549
+ inBlockComment = false;
550
+ i += 1;
551
+ }
552
+ continue;
553
+ }
554
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
555
+ inLineComment = true;
556
+ i += 1;
557
+ continue;
558
+ }
559
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
560
+ inBlockComment = true;
561
+ i += 1;
562
+ continue;
563
+ }
564
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
565
+ inSingle = !inSingle;
566
+ continue;
567
+ }
568
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
569
+ inDouble = !inDouble;
570
+ continue;
571
+ }
572
+ if (!inSingle && !inDouble && ch === "?") {
573
+ count += 1;
574
+ }
575
+ }
576
+ return count;
577
+ }
578
+ function findBooleanPlaceholderIndexes(sql) {
579
+ const indexes = /* @__PURE__ */ new Set();
580
+ for (const column of BOOLEAN_COLUMN_NAMES) {
581
+ const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
582
+ for (const match of sql.matchAll(pattern)) {
583
+ const matchText = match[0];
584
+ const qIndex = match.index + matchText.lastIndexOf("?");
585
+ indexes.add(countQuestionMarks(sql, qIndex + 1));
586
+ }
587
+ }
588
+ return indexes;
589
+ }
590
+ function coerceInsertBooleanArgs(sql, args) {
591
+ const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
592
+ if (!match) return;
593
+ const rawTable = match[1];
594
+ const rawColumns = match[2];
595
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
596
+ if (!boolColumns?.size) return;
597
+ const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
598
+ for (const [index, column] of columns.entries()) {
599
+ if (boolColumns.has(column) && index < args.length) {
600
+ args[index] = toBoolean(args[index]);
601
+ }
602
+ }
603
+ }
604
+ function coerceUpdateBooleanArgs(sql, args) {
605
+ const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
606
+ if (!match) return;
607
+ const rawTable = match[1];
608
+ const setClause = match[2];
609
+ const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
610
+ if (!boolColumns?.size) return;
611
+ const assignments = setClause.split(",");
612
+ let placeholderIndex = 0;
613
+ for (const assignment of assignments) {
614
+ if (!assignment.includes("?")) continue;
615
+ placeholderIndex += 1;
616
+ const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
617
+ if (colMatch && boolColumns.has(colMatch[1])) {
618
+ args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
619
+ }
620
+ }
621
+ }
622
+ function coerceBooleanArgs(sql, args) {
623
+ const nextArgs = [...args];
624
+ coerceInsertBooleanArgs(sql, nextArgs);
625
+ coerceUpdateBooleanArgs(sql, nextArgs);
626
+ const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
627
+ for (const index of placeholderIndexes) {
628
+ if (index > 0 && index <= nextArgs.length) {
629
+ nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
630
+ }
631
+ }
632
+ return nextArgs;
633
+ }
634
+ function convertQuestionMarksToDollarParams(sql) {
635
+ let out = "";
636
+ let placeholder = 0;
637
+ let inSingle = false;
638
+ let inDouble = false;
639
+ let inLineComment = false;
640
+ let inBlockComment = false;
641
+ for (let i = 0; i < sql.length; i++) {
642
+ const ch = sql[i];
643
+ const next = sql[i + 1];
644
+ if (inLineComment) {
645
+ out += ch;
646
+ if (ch === "\n") inLineComment = false;
647
+ continue;
648
+ }
649
+ if (inBlockComment) {
650
+ out += ch;
651
+ if (ch === "*" && next === "/") {
652
+ out += next;
653
+ inBlockComment = false;
654
+ i += 1;
655
+ }
656
+ continue;
657
+ }
658
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
659
+ out += ch + next;
660
+ inLineComment = true;
661
+ i += 1;
662
+ continue;
663
+ }
664
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
665
+ out += ch + next;
666
+ inBlockComment = true;
667
+ i += 1;
668
+ continue;
669
+ }
670
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
671
+ inSingle = !inSingle;
672
+ out += ch;
673
+ continue;
674
+ }
675
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
676
+ inDouble = !inDouble;
677
+ out += ch;
678
+ continue;
679
+ }
680
+ if (!inSingle && !inDouble && ch === "?") {
681
+ placeholder += 1;
682
+ out += `$${placeholder}`;
683
+ continue;
684
+ }
685
+ out += ch;
686
+ }
687
+ return out;
688
+ }
689
+ function translateStatementForPostgres(stmt) {
690
+ const normalized = normalizeStatement(stmt);
691
+ if (normalized.kind === "named") {
692
+ throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
693
+ }
694
+ const rewrittenSql = rewriteSql(normalized.sql);
695
+ const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
696
+ return {
697
+ sql: convertQuestionMarksToDollarParams(rewrittenSql),
698
+ args: coercedArgs
699
+ };
700
+ }
701
+ function shouldBypassPostgres(stmt) {
702
+ const normalized = normalizeStatement(stmt);
703
+ if (normalized.kind === "named") {
704
+ return true;
705
+ }
706
+ return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
707
+ }
708
+ function shouldFallbackOnError(error) {
709
+ const message = error instanceof Error ? error.message : String(error);
710
+ return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
711
+ }
712
+ function isReadQuery(sql) {
713
+ const trimmed = sql.trimStart();
714
+ return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
715
+ }
716
+ function buildRow(row, columns) {
717
+ const values = columns.map((column) => row[column]);
718
+ return Object.assign(values, row);
719
+ }
720
+ function buildResultSet(rows, rowsAffected = 0) {
721
+ const columns = rows[0] ? Object.keys(rows[0]) : [];
722
+ const resultRows = rows.map((row) => buildRow(row, columns));
723
+ return {
724
+ columns,
725
+ columnTypes: columns.map(() => ""),
726
+ rows: resultRows,
727
+ rowsAffected,
728
+ lastInsertRowid: void 0,
729
+ toJSON() {
730
+ return {
731
+ columns,
732
+ columnTypes: columns.map(() => ""),
733
+ rows,
734
+ rowsAffected,
735
+ lastInsertRowid: void 0
736
+ };
737
+ }
738
+ };
739
+ }
740
+ async function loadPrismaClient() {
741
+ if (!prismaClientPromise) {
742
+ prismaClientPromise = (async () => {
743
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
744
+ if (explicitPath) {
745
+ const module2 = await import(pathToFileURL(explicitPath).href);
746
+ const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
747
+ if (!PrismaClient2) {
748
+ throw new Error(`No PrismaClient export found at ${explicitPath}`);
749
+ }
750
+ return new PrismaClient2();
751
+ }
752
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os3.homedir(), "exe-db");
753
+ const requireFromExeDb = createRequire(path3.join(exeDbRoot, "package.json"));
754
+ const prismaEntry = requireFromExeDb.resolve("@prisma/client");
755
+ const module = await import(pathToFileURL(prismaEntry).href);
756
+ const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
757
+ if (!PrismaClient) {
758
+ throw new Error(`No PrismaClient export found in ${prismaEntry}`);
759
+ }
760
+ return new PrismaClient();
761
+ })();
762
+ }
763
+ return prismaClientPromise;
764
+ }
765
+ async function ensureCompatibilityViews(prisma) {
766
+ if (!compatibilityBootstrapPromise) {
767
+ compatibilityBootstrapPromise = (async () => {
768
+ for (const mapping of VIEW_MAPPINGS) {
769
+ const relation = mapping.source.replace(/"/g, "");
770
+ const rows = await prisma.$queryRawUnsafe(
771
+ "SELECT to_regclass($1) AS regclass",
772
+ relation
773
+ );
774
+ if (!rows[0]?.regclass) {
775
+ continue;
776
+ }
777
+ await prisma.$executeRawUnsafe(
778
+ `CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
779
+ );
780
+ }
781
+ })();
782
+ }
783
+ return compatibilityBootstrapPromise;
784
+ }
785
+ async function executeOnPrisma(executor, stmt) {
786
+ const translated = translateStatementForPostgres(stmt);
787
+ if (isReadQuery(translated.sql)) {
788
+ const rows = await executor.$queryRawUnsafe(
789
+ translated.sql,
790
+ ...translated.args
791
+ );
792
+ return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
793
+ }
794
+ const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
795
+ return buildResultSet([], rowsAffected);
796
+ }
797
+ function splitSqlStatements(sql) {
798
+ const parts = [];
799
+ let current = "";
800
+ let inSingle = false;
801
+ let inDouble = false;
802
+ let inLineComment = false;
803
+ let inBlockComment = false;
804
+ for (let i = 0; i < sql.length; i++) {
805
+ const ch = sql[i];
806
+ const next = sql[i + 1];
807
+ if (inLineComment) {
808
+ current += ch;
809
+ if (ch === "\n") inLineComment = false;
810
+ continue;
811
+ }
812
+ if (inBlockComment) {
813
+ current += ch;
814
+ if (ch === "*" && next === "/") {
815
+ current += next;
816
+ inBlockComment = false;
817
+ i += 1;
818
+ }
819
+ continue;
820
+ }
821
+ if (!inSingle && !inDouble && ch === "-" && next === "-") {
822
+ current += ch + next;
823
+ inLineComment = true;
824
+ i += 1;
825
+ continue;
826
+ }
827
+ if (!inSingle && !inDouble && ch === "/" && next === "*") {
828
+ current += ch + next;
829
+ inBlockComment = true;
830
+ i += 1;
831
+ continue;
832
+ }
833
+ if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
834
+ inSingle = !inSingle;
835
+ current += ch;
836
+ continue;
837
+ }
838
+ if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
839
+ inDouble = !inDouble;
840
+ current += ch;
841
+ continue;
842
+ }
843
+ if (!inSingle && !inDouble && ch === ";") {
844
+ if (current.trim()) {
845
+ parts.push(current.trim());
846
+ }
847
+ current = "";
848
+ continue;
849
+ }
850
+ current += ch;
851
+ }
852
+ if (current.trim()) {
853
+ parts.push(current.trim());
854
+ }
855
+ return parts;
856
+ }
857
+ async function createPrismaDbAdapter(fallbackClient) {
858
+ const prisma = await loadPrismaClient();
859
+ await ensureCompatibilityViews(prisma);
860
+ let closed = false;
861
+ let adapter;
862
+ const fallbackExecute = async (stmt, error) => {
863
+ if (!fallbackClient) {
864
+ if (error) throw error;
865
+ throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
866
+ }
867
+ if (error) {
868
+ process.stderr.write(
869
+ `[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
870
+ `
871
+ );
872
+ }
873
+ return fallbackClient.execute(stmt);
874
+ };
875
+ adapter = {
876
+ async execute(stmt) {
877
+ if (shouldBypassPostgres(stmt)) {
878
+ return fallbackExecute(stmt);
879
+ }
880
+ try {
881
+ return await executeOnPrisma(prisma, stmt);
882
+ } catch (error) {
883
+ if (shouldFallbackOnError(error)) {
884
+ return fallbackExecute(stmt, error);
885
+ }
886
+ throw error;
887
+ }
888
+ },
889
+ async batch(stmts, mode) {
890
+ if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
891
+ if (!fallbackClient) {
892
+ throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
893
+ }
894
+ return fallbackClient.batch(stmts, mode);
895
+ }
896
+ try {
897
+ if (prisma.$transaction) {
898
+ return await prisma.$transaction(async (tx) => {
899
+ const results2 = [];
900
+ for (const stmt of stmts) {
901
+ results2.push(await executeOnPrisma(tx, stmt));
902
+ }
903
+ return results2;
904
+ });
905
+ }
906
+ const results = [];
907
+ for (const stmt of stmts) {
908
+ results.push(await executeOnPrisma(prisma, stmt));
909
+ }
910
+ return results;
911
+ } catch (error) {
912
+ if (fallbackClient && shouldFallbackOnError(error)) {
913
+ process.stderr.write(
914
+ `[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
915
+ `
916
+ );
917
+ return fallbackClient.batch(stmts, mode);
918
+ }
919
+ throw error;
920
+ }
921
+ },
922
+ async migrate(stmts) {
923
+ if (fallbackClient) {
924
+ return fallbackClient.migrate(stmts);
925
+ }
926
+ return adapter.batch(stmts, "deferred");
927
+ },
928
+ async transaction(mode) {
929
+ if (!fallbackClient) {
930
+ throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
931
+ }
932
+ return fallbackClient.transaction(mode);
933
+ },
934
+ async executeMultiple(sql) {
935
+ if (fallbackClient && shouldBypassPostgres(sql)) {
936
+ return fallbackClient.executeMultiple(sql);
937
+ }
938
+ for (const statement of splitSqlStatements(sql)) {
939
+ await adapter.execute(statement);
940
+ }
941
+ },
942
+ async sync() {
943
+ if (fallbackClient) {
944
+ return fallbackClient.sync();
945
+ }
946
+ return { frame_no: 0, frames_synced: 0 };
947
+ },
948
+ close() {
949
+ closed = true;
950
+ prismaClientPromise = null;
951
+ compatibilityBootstrapPromise = null;
952
+ void prisma.$disconnect?.();
953
+ },
954
+ get closed() {
955
+ return closed;
956
+ },
957
+ get protocol() {
958
+ return "prisma-postgres";
959
+ }
960
+ };
961
+ return adapter;
962
+ }
963
+ var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
964
+ var init_database_adapter = __esm({
965
+ "src/lib/database-adapter.ts"() {
966
+ "use strict";
967
+ VIEW_MAPPINGS = [
968
+ { view: "memories", source: "memory.memory_records" },
969
+ { view: "tasks", source: "memory.tasks" },
970
+ { view: "behaviors", source: "memory.behaviors" },
971
+ { view: "entities", source: "memory.entities" },
972
+ { view: "relationships", source: "memory.relationships" },
973
+ { view: "entity_memories", source: "memory.entity_memories" },
974
+ { view: "entity_aliases", source: "memory.entity_aliases" },
975
+ { view: "notifications", source: "memory.notifications" },
976
+ { view: "messages", source: "memory.messages" },
977
+ { view: "users", source: "wiki.users" },
978
+ { view: "workspaces", source: "wiki.workspaces" },
979
+ { view: "workspace_users", source: "wiki.workspace_users" },
980
+ { view: "documents", source: "wiki.workspace_documents" },
981
+ { view: "chats", source: "wiki.workspace_chats" }
982
+ ];
983
+ UPSERT_KEYS = {
984
+ memories: ["id"],
985
+ tasks: ["id"],
986
+ behaviors: ["id"],
987
+ entities: ["id"],
988
+ relationships: ["id"],
989
+ entity_aliases: ["alias"],
990
+ notifications: ["id"],
991
+ messages: ["id"],
992
+ users: ["id"],
993
+ workspaces: ["id"],
994
+ workspace_users: ["id"],
995
+ documents: ["id"],
996
+ chats: ["id"]
997
+ };
998
+ BOOLEAN_COLUMNS_BY_TABLE = {
999
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
1000
+ behaviors: /* @__PURE__ */ new Set(["active"]),
1001
+ notifications: /* @__PURE__ */ new Set(["read"]),
1002
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
1003
+ };
1004
+ BOOLEAN_COLUMN_NAMES = new Set(
1005
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
1006
+ );
1007
+ IMMEDIATE_FALLBACK_PATTERNS = [
1008
+ /\bPRAGMA\b/i,
1009
+ /\bsqlite_master\b/i,
1010
+ /(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
1011
+ /\bMATCH\b/i,
1012
+ /\bvector_distance_cos\s*\(/i,
1013
+ /\bjson_extract\s*\(/i,
1014
+ /\bjulianday\s*\(/i,
1015
+ /\bstrftime\s*\(/i,
1016
+ /\blast_insert_rowid\s*\(/i
1017
+ ];
1018
+ prismaClientPromise = null;
1019
+ compatibilityBootstrapPromise = null;
1020
+ }
1021
+ });
1022
+
438
1023
  // src/lib/exe-daemon-client.ts
439
1024
  import net from "net";
440
- import os3 from "os";
1025
+ import os4 from "os";
441
1026
  import { spawn } from "child_process";
442
1027
  import { randomUUID } from "crypto";
443
1028
  import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
444
- import path3 from "path";
1029
+ import path4 from "path";
445
1030
  import { fileURLToPath } from "url";
446
1031
  function handleData(chunk) {
447
1032
  _buffer += chunk.toString();
@@ -492,17 +1077,17 @@ function cleanupStaleFiles() {
492
1077
  }
493
1078
  }
494
1079
  function findPackageRoot() {
495
- let dir = path3.dirname(fileURLToPath(import.meta.url));
496
- const { root } = path3.parse(dir);
1080
+ let dir = path4.dirname(fileURLToPath(import.meta.url));
1081
+ const { root } = path4.parse(dir);
497
1082
  while (dir !== root) {
498
- if (existsSync3(path3.join(dir, "package.json"))) return dir;
499
- dir = path3.dirname(dir);
1083
+ if (existsSync3(path4.join(dir, "package.json"))) return dir;
1084
+ dir = path4.dirname(dir);
500
1085
  }
501
1086
  return null;
502
1087
  }
503
1088
  function spawnDaemon() {
504
- const freeGB = os3.freemem() / (1024 * 1024 * 1024);
505
- const totalGB = os3.totalmem() / (1024 * 1024 * 1024);
1089
+ const freeGB = os4.freemem() / (1024 * 1024 * 1024);
1090
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
506
1091
  if (totalGB <= 8) {
507
1092
  process.stderr.write(
508
1093
  `[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
@@ -522,7 +1107,7 @@ function spawnDaemon() {
522
1107
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
523
1108
  return;
524
1109
  }
525
- const daemonPath = path3.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1110
+ const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
526
1111
  if (!existsSync3(daemonPath)) {
527
1112
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
528
1113
  `);
@@ -531,7 +1116,7 @@ function spawnDaemon() {
531
1116
  const resolvedPath = daemonPath;
532
1117
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
533
1118
  `);
534
- const logPath = path3.join(path3.dirname(SOCKET_PATH), "exed.log");
1119
+ const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
535
1120
  let stderrFd = "ignore";
536
1121
  try {
537
1122
  stderrFd = openSync(logPath, "a");
@@ -678,9 +1263,9 @@ var init_exe_daemon_client = __esm({
678
1263
  "src/lib/exe-daemon-client.ts"() {
679
1264
  "use strict";
680
1265
  init_config();
681
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path3.join(EXE_AI_DIR, "exed.sock");
682
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path3.join(EXE_AI_DIR, "exed.pid");
683
- SPAWN_LOCK_PATH = path3.join(EXE_AI_DIR, "exed-spawn.lock");
1266
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
1267
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
1268
+ SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
684
1269
  SPAWN_LOCK_STALE_MS = 3e4;
685
1270
  CONNECT_TIMEOUT_MS = 15e3;
686
1271
  REQUEST_TIMEOUT_MS = 3e4;
@@ -762,7 +1347,7 @@ __export(db_daemon_client_exports, {
762
1347
  createDaemonDbClient: () => createDaemonDbClient,
763
1348
  initDaemonDbClient: () => initDaemonDbClient
764
1349
  });
765
- function normalizeStatement(stmt) {
1350
+ function normalizeStatement2(stmt) {
766
1351
  if (typeof stmt === "string") {
767
1352
  return { sql: stmt, args: [] };
768
1353
  }
@@ -786,7 +1371,7 @@ function createDaemonDbClient(fallbackClient) {
786
1371
  if (!_useDaemon || !isClientConnected()) {
787
1372
  return fallbackClient.execute(stmt);
788
1373
  }
789
- const { sql, args } = normalizeStatement(stmt);
1374
+ const { sql, args } = normalizeStatement2(stmt);
790
1375
  const response = await sendDaemonRequest({
791
1376
  type: "db-execute",
792
1377
  sql,
@@ -811,7 +1396,7 @@ function createDaemonDbClient(fallbackClient) {
811
1396
  if (!_useDaemon || !isClientConnected()) {
812
1397
  return fallbackClient.batch(stmts, mode);
813
1398
  }
814
- const statements = stmts.map(normalizeStatement);
1399
+ const statements = stmts.map(normalizeStatement2);
815
1400
  const response = await sendDaemonRequest({
816
1401
  type: "db-batch",
817
1402
  statements,
@@ -906,6 +1491,18 @@ __export(database_exports, {
906
1491
  });
907
1492
  import { createClient } from "@libsql/client";
908
1493
  async function initDatabase(config) {
1494
+ if (_walCheckpointTimer) {
1495
+ clearInterval(_walCheckpointTimer);
1496
+ _walCheckpointTimer = null;
1497
+ }
1498
+ if (_daemonClient) {
1499
+ _daemonClient.close();
1500
+ _daemonClient = null;
1501
+ }
1502
+ if (_adapterClient && _adapterClient !== _resilientClient) {
1503
+ _adapterClient.close();
1504
+ }
1505
+ _adapterClient = null;
909
1506
  if (_client) {
910
1507
  _client.close();
911
1508
  _client = null;
@@ -919,6 +1516,7 @@ async function initDatabase(config) {
919
1516
  }
920
1517
  _client = createClient(opts);
921
1518
  _resilientClient = wrapWithRetry(_client);
1519
+ _adapterClient = _resilientClient;
922
1520
  _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
923
1521
  });
924
1522
  _client.execute("PRAGMA journal_mode = WAL").catch(() => {
@@ -929,14 +1527,20 @@ async function initDatabase(config) {
929
1527
  });
930
1528
  }, 3e4);
931
1529
  _walCheckpointTimer.unref();
1530
+ if (process.env.DATABASE_URL) {
1531
+ _adapterClient = await createPrismaDbAdapter(_resilientClient);
1532
+ }
932
1533
  }
933
1534
  function isInitialized() {
934
- return _client !== null;
1535
+ return _adapterClient !== null || _client !== null;
935
1536
  }
936
1537
  function getClient() {
937
- if (!_resilientClient) {
1538
+ if (!_adapterClient) {
938
1539
  throw new Error("Database client not initialized. Call initDatabase() first.");
939
1540
  }
1541
+ if (process.env.DATABASE_URL) {
1542
+ return _adapterClient;
1543
+ }
940
1544
  if (process.env.EXE_IS_DAEMON === "1") {
941
1545
  return _resilientClient;
942
1546
  }
@@ -946,6 +1550,7 @@ function getClient() {
946
1550
  return _resilientClient;
947
1551
  }
948
1552
  async function initDaemonClient() {
1553
+ if (process.env.DATABASE_URL) return;
949
1554
  if (process.env.EXE_IS_DAEMON === "1") return;
950
1555
  if (!_resilientClient) return;
951
1556
  try {
@@ -1890,26 +2495,36 @@ async function ensureSchema() {
1890
2495
  }
1891
2496
  }
1892
2497
  async function disposeDatabase() {
2498
+ if (_walCheckpointTimer) {
2499
+ clearInterval(_walCheckpointTimer);
2500
+ _walCheckpointTimer = null;
2501
+ }
1893
2502
  if (_daemonClient) {
1894
2503
  _daemonClient.close();
1895
2504
  _daemonClient = null;
1896
2505
  }
2506
+ if (_adapterClient && _adapterClient !== _resilientClient) {
2507
+ _adapterClient.close();
2508
+ }
2509
+ _adapterClient = null;
1897
2510
  if (_client) {
1898
2511
  _client.close();
1899
2512
  _client = null;
1900
2513
  _resilientClient = null;
1901
2514
  }
1902
2515
  }
1903
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
2516
+ var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
1904
2517
  var init_database = __esm({
1905
2518
  "src/lib/database.ts"() {
1906
2519
  "use strict";
1907
2520
  init_db_retry();
1908
2521
  init_employees();
2522
+ init_database_adapter();
1909
2523
  _client = null;
1910
2524
  _resilientClient = null;
1911
2525
  _walCheckpointTimer = null;
1912
2526
  _daemonClient = null;
2527
+ _adapterClient = null;
1913
2528
  initTurso = initDatabase;
1914
2529
  disposeTurso = disposeDatabase;
1915
2530
  }
@@ -2120,13 +2735,13 @@ __export(keychain_exports, {
2120
2735
  });
2121
2736
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2122
2737
  import { existsSync as existsSync4 } from "fs";
2123
- import path4 from "path";
2124
- import os4 from "os";
2738
+ import path5 from "path";
2739
+ import os5 from "os";
2125
2740
  function getKeyDir() {
2126
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
2741
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os5.homedir(), ".exe-os");
2127
2742
  }
2128
2743
  function getKeyPath() {
2129
- return path4.join(getKeyDir(), "master.key");
2744
+ return path5.join(getKeyDir(), "master.key");
2130
2745
  }
2131
2746
  async function tryKeytar() {
2132
2747
  try {
@@ -2149,7 +2764,7 @@ async function getMasterKey() {
2149
2764
  const keyPath = getKeyPath();
2150
2765
  if (!existsSync4(keyPath)) {
2151
2766
  process.stderr.write(
2152
- `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2767
+ `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2153
2768
  `
2154
2769
  );
2155
2770
  return null;
@@ -2300,7 +2915,7 @@ __export(shard_manager_exports, {
2300
2915
  listShards: () => listShards,
2301
2916
  shardExists: () => shardExists
2302
2917
  });
2303
- import path5 from "path";
2918
+ import path6 from "path";
2304
2919
  import { existsSync as existsSync5, mkdirSync, readdirSync } from "fs";
2305
2920
  import { createClient as createClient2 } from "@libsql/client";
2306
2921
  function initShardManager(encryptionKey) {
@@ -2326,7 +2941,7 @@ function getShardClient(projectName) {
2326
2941
  }
2327
2942
  const cached = _shards.get(safeName);
2328
2943
  if (cached) return cached;
2329
- const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
2944
+ const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
2330
2945
  const client = createClient2({
2331
2946
  url: `file:${dbPath}`,
2332
2947
  encryptionKey: _encryptionKey
@@ -2336,7 +2951,7 @@ function getShardClient(projectName) {
2336
2951
  }
2337
2952
  function shardExists(projectName) {
2338
2953
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2339
- return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
2954
+ return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
2340
2955
  }
2341
2956
  function listShards() {
2342
2957
  if (!existsSync5(SHARDS_DIR)) return [];
@@ -2413,7 +3028,23 @@ async function ensureShardSchema(client) {
2413
3028
  // MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
2414
3029
  "ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
2415
3030
  "ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
2416
- "ALTER TABLE memories ADD COLUMN trajectory TEXT"
3031
+ "ALTER TABLE memories ADD COLUMN trajectory TEXT",
3032
+ // Metadata enrichment columns (must match database.ts)
3033
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
3034
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
3035
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
3036
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
3037
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
3038
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
3039
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
3040
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
3041
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
3042
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
3043
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
3044
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
3045
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
3046
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
3047
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
2417
3048
  ]) {
2418
3049
  try {
2419
3050
  await client.execute(col);
@@ -2525,7 +3156,7 @@ var init_shard_manager = __esm({
2525
3156
  "src/lib/shard-manager.ts"() {
2526
3157
  "use strict";
2527
3158
  init_config();
2528
- SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
3159
+ SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
2529
3160
  _shards = /* @__PURE__ */ new Map();
2530
3161
  _encryptionKey = null;
2531
3162
  _shardingEnabled = false;
@@ -2633,10 +3264,10 @@ __export(session_registry_exports, {
2633
3264
  });
2634
3265
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync6 } from "fs";
2635
3266
  import { execSync as execSync2 } from "child_process";
2636
- import path6 from "path";
2637
- import os5 from "os";
3267
+ import path7 from "path";
3268
+ import os6 from "os";
2638
3269
  function registerSession(entry) {
2639
- const dir = path6.dirname(REGISTRY_PATH);
3270
+ const dir = path7.dirname(REGISTRY_PATH);
2640
3271
  if (!existsSync6(dir)) {
2641
3272
  mkdirSync2(dir, { recursive: true });
2642
3273
  }
@@ -2680,7 +3311,7 @@ var REGISTRY_PATH;
2680
3311
  var init_session_registry = __esm({
2681
3312
  "src/lib/session-registry.ts"() {
2682
3313
  "use strict";
2683
- REGISTRY_PATH = path6.join(os5.homedir(), ".exe-os", "session-registry.json");
3314
+ REGISTRY_PATH = path7.join(os6.homedir(), ".exe-os", "session-registry.json");
2684
3315
  }
2685
3316
  });
2686
3317
 
@@ -2961,7 +3592,7 @@ var init_runtime_table = __esm({
2961
3592
 
2962
3593
  // src/lib/agent-config.ts
2963
3594
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
2964
- import path7 from "path";
3595
+ import path8 from "path";
2965
3596
  function loadAgentConfig() {
2966
3597
  if (!existsSync7(AGENT_CONFIG_PATH)) return {};
2967
3598
  try {
@@ -2984,7 +3615,7 @@ var init_agent_config = __esm({
2984
3615
  "use strict";
2985
3616
  init_config();
2986
3617
  init_runtime_table();
2987
- AGENT_CONFIG_PATH = path7.join(EXE_AI_DIR, "agent-config.json");
3618
+ AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
2988
3619
  DEFAULT_MODELS = {
2989
3620
  claude: "claude-opus-4",
2990
3621
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
@@ -3003,10 +3634,10 @@ __export(intercom_queue_exports, {
3003
3634
  readQueue: () => readQueue
3004
3635
  });
3005
3636
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
3006
- import path8 from "path";
3007
- import os6 from "os";
3637
+ import path9 from "path";
3638
+ import os7 from "os";
3008
3639
  function ensureDir() {
3009
- const dir = path8.dirname(QUEUE_PATH);
3640
+ const dir = path9.dirname(QUEUE_PATH);
3010
3641
  if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
3011
3642
  }
3012
3643
  function readQueue() {
@@ -3112,10 +3743,10 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
3112
3743
  var init_intercom_queue = __esm({
3113
3744
  "src/lib/intercom-queue.ts"() {
3114
3745
  "use strict";
3115
- QUEUE_PATH = path8.join(os6.homedir(), ".exe-os", "intercom-queue.json");
3746
+ QUEUE_PATH = path9.join(os7.homedir(), ".exe-os", "intercom-queue.json");
3116
3747
  MAX_RETRIES2 = 5;
3117
3748
  TTL_MS = 60 * 60 * 1e3;
3118
- INTERCOM_LOG = path8.join(os6.homedir(), ".exe-os", "intercom.log");
3749
+ INTERCOM_LOG = path9.join(os7.homedir(), ".exe-os", "intercom.log");
3119
3750
  }
3120
3751
  });
3121
3752
 
@@ -3138,7 +3769,7 @@ __export(license_exports, {
3138
3769
  });
3139
3770
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
3140
3771
  import { randomUUID as randomUUID3 } from "crypto";
3141
- import path9 from "path";
3772
+ import path10 from "path";
3142
3773
  import { jwtVerify, importSPKI } from "jose";
3143
3774
  async function fetchRetry(url, init) {
3144
3775
  try {
@@ -3149,7 +3780,7 @@ async function fetchRetry(url, init) {
3149
3780
  }
3150
3781
  }
3151
3782
  function loadDeviceId() {
3152
- const deviceJsonPath = path9.join(EXE_AI_DIR, "device.json");
3783
+ const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
3153
3784
  try {
3154
3785
  if (existsSync9(deviceJsonPath)) {
3155
3786
  const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
@@ -3314,7 +3945,7 @@ async function checkLicense() {
3314
3945
  let key = loadLicense();
3315
3946
  if (!key) {
3316
3947
  try {
3317
- const configPath = path9.join(EXE_AI_DIR, "config.json");
3948
+ const configPath = path10.join(EXE_AI_DIR, "config.json");
3318
3949
  if (existsSync9(configPath)) {
3319
3950
  const raw = JSON.parse(readFileSync7(configPath, "utf8"));
3320
3951
  const cloud = raw.cloud;
@@ -3475,9 +4106,9 @@ var init_license = __esm({
3475
4106
  "src/lib/license.ts"() {
3476
4107
  "use strict";
3477
4108
  init_config();
3478
- LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
3479
- CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
3480
- DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
4109
+ LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
4110
+ CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
4111
+ DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
3481
4112
  API_BASE = "https://askexe.com/cloud";
3482
4113
  RETRY_DELAY_MS = 500;
3483
4114
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -3508,7 +4139,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
3508
4139
 
3509
4140
  // src/lib/plan-limits.ts
3510
4141
  import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
3511
- import path10 from "path";
4142
+ import path11 from "path";
3512
4143
  function getLicenseSync() {
3513
4144
  try {
3514
4145
  if (!existsSync10(CACHE_PATH2)) return freeLicense();
@@ -3580,14 +4211,14 @@ var init_plan_limits = __esm({
3580
4211
  this.name = "PlanLimitError";
3581
4212
  }
3582
4213
  };
3583
- CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
4214
+ CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
3584
4215
  }
3585
4216
  });
3586
4217
 
3587
4218
  // src/lib/notifications.ts
3588
4219
  import crypto from "crypto";
3589
- import path11 from "path";
3590
- import os7 from "os";
4220
+ import path12 from "path";
4221
+ import os8 from "os";
3591
4222
  import {
3592
4223
  readFileSync as readFileSync9,
3593
4224
  readdirSync as readdirSync2,
@@ -3705,8 +4336,8 @@ async function markDoneTaskNotificationsAsRead() {
3705
4336
  }
3706
4337
  }
3707
4338
  async function migrateJsonNotifications() {
3708
- const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path11.join(os7.homedir(), ".exe-os");
3709
- const notifDir = path11.join(base, "notifications");
4339
+ const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path12.join(os8.homedir(), ".exe-os");
4340
+ const notifDir = path12.join(base, "notifications");
3710
4341
  if (!existsSync11(notifDir)) return 0;
3711
4342
  let migrated = 0;
3712
4343
  try {
@@ -3715,7 +4346,7 @@ async function migrateJsonNotifications() {
3715
4346
  const client = getClient();
3716
4347
  for (const file of files) {
3717
4348
  try {
3718
- const filePath = path11.join(notifDir, file);
4349
+ const filePath = path12.join(notifDir, file);
3719
4350
  const data = JSON.parse(readFileSync9(filePath, "utf8"));
3720
4351
  await client.execute({
3721
4352
  sql: `INSERT OR IGNORE INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
@@ -3863,8 +4494,8 @@ var init_session_kill_telemetry = __esm({
3863
4494
 
3864
4495
  // src/lib/tasks-crud.ts
3865
4496
  import crypto3 from "crypto";
3866
- import path12 from "path";
3867
- import os8 from "os";
4497
+ import path13 from "path";
4498
+ import os9 from "os";
3868
4499
  import { execSync as execSync5 } from "child_process";
3869
4500
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
3870
4501
  import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
@@ -4042,8 +4673,8 @@ ${laneWarning}` : laneWarning;
4042
4673
  }
4043
4674
  if (input.baseDir) {
4044
4675
  try {
4045
- await mkdir4(path12.join(input.baseDir, "exe", "output"), { recursive: true });
4046
- await mkdir4(path12.join(input.baseDir, "exe", "research"), { recursive: true });
4676
+ await mkdir4(path13.join(input.baseDir, "exe", "output"), { recursive: true });
4677
+ await mkdir4(path13.join(input.baseDir, "exe", "research"), { recursive: true });
4047
4678
  await ensureArchitectureDoc(input.baseDir, input.projectName);
4048
4679
  await ensureGitignoreExe(input.baseDir);
4049
4680
  } catch {
@@ -4079,9 +4710,9 @@ ${laneWarning}` : laneWarning;
4079
4710
  });
4080
4711
  if (input.baseDir) {
4081
4712
  try {
4082
- const EXE_OS_DIR = path12.join(os8.homedir(), ".exe-os");
4083
- const mdPath = path12.join(EXE_OS_DIR, taskFile);
4084
- const mdDir = path12.dirname(mdPath);
4713
+ const EXE_OS_DIR = path13.join(os9.homedir(), ".exe-os");
4714
+ const mdPath = path13.join(EXE_OS_DIR, taskFile);
4715
+ const mdDir = path13.dirname(mdPath);
4085
4716
  if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
4086
4717
  const reviewer = input.reviewer ?? input.assignedBy;
4087
4718
  const mdContent = `# ${input.title}
@@ -4382,7 +5013,7 @@ async function deleteTaskCore(taskId, _baseDir) {
4382
5013
  return { taskFile, assignedTo, assignedBy, taskSlug };
4383
5014
  }
4384
5015
  async function ensureArchitectureDoc(baseDir, projectName) {
4385
- const archPath = path12.join(baseDir, "exe", "ARCHITECTURE.md");
5016
+ const archPath = path13.join(baseDir, "exe", "ARCHITECTURE.md");
4386
5017
  try {
4387
5018
  if (existsSync12(archPath)) return;
4388
5019
  const template = [
@@ -4417,7 +5048,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
4417
5048
  }
4418
5049
  }
4419
5050
  async function ensureGitignoreExe(baseDir) {
4420
- const gitignorePath = path12.join(baseDir, ".gitignore");
5051
+ const gitignorePath = path13.join(baseDir, ".gitignore");
4421
5052
  try {
4422
5053
  if (existsSync12(gitignorePath)) {
4423
5054
  const content = readFileSync10(gitignorePath, "utf-8");
@@ -4451,13 +5082,13 @@ var init_tasks_crud = __esm({
4451
5082
  });
4452
5083
 
4453
5084
  // src/lib/tasks-review.ts
4454
- import path13 from "path";
5085
+ import path14 from "path";
4455
5086
  import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
4456
5087
  async function countPendingReviews(sessionScope) {
4457
5088
  const client = getClient();
4458
5089
  if (sessionScope) {
4459
5090
  const result2 = await client.execute({
4460
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
5091
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
4461
5092
  args: [sessionScope]
4462
5093
  });
4463
5094
  return Number(result2.rows[0]?.cnt) || 0;
@@ -4633,11 +5264,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
4633
5264
  );
4634
5265
  }
4635
5266
  try {
4636
- const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
5267
+ const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
4637
5268
  if (existsSync13(cacheDir)) {
4638
5269
  for (const f of readdirSync3(cacheDir)) {
4639
5270
  if (f.startsWith("review-notified-")) {
4640
- unlinkSync4(path13.join(cacheDir, f));
5271
+ unlinkSync4(path14.join(cacheDir, f));
4641
5272
  }
4642
5273
  }
4643
5274
  }
@@ -4658,7 +5289,7 @@ var init_tasks_review = __esm({
4658
5289
  });
4659
5290
 
4660
5291
  // src/lib/tasks-chain.ts
4661
- import path14 from "path";
5292
+ import path15 from "path";
4662
5293
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
4663
5294
  async function cascadeUnblock(taskId, baseDir, now) {
4664
5295
  const client = getClient();
@@ -4675,7 +5306,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
4675
5306
  });
4676
5307
  for (const ur of unblockedRows.rows) {
4677
5308
  try {
4678
- const ubFile = path14.join(baseDir, String(ur.task_file));
5309
+ const ubFile = path15.join(baseDir, String(ur.task_file));
4679
5310
  let ubContent = await readFile4(ubFile, "utf-8");
4680
5311
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
4681
5312
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -4749,7 +5380,7 @@ __export(project_name_exports, {
4749
5380
  getProjectName: () => getProjectName
4750
5381
  });
4751
5382
  import { execSync as execSync6 } from "child_process";
4752
- import path15 from "path";
5383
+ import path16 from "path";
4753
5384
  function getProjectName(cwd) {
4754
5385
  const dir = cwd ?? process.cwd();
4755
5386
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -4762,7 +5393,7 @@ function getProjectName(cwd) {
4762
5393
  timeout: 2e3,
4763
5394
  stdio: ["pipe", "pipe", "pipe"]
4764
5395
  }).trim();
4765
- repoRoot = path15.dirname(gitCommonDir);
5396
+ repoRoot = path16.dirname(gitCommonDir);
4766
5397
  } catch {
4767
5398
  repoRoot = execSync6("git rev-parse --show-toplevel", {
4768
5399
  cwd: dir,
@@ -4771,11 +5402,11 @@ function getProjectName(cwd) {
4771
5402
  stdio: ["pipe", "pipe", "pipe"]
4772
5403
  }).trim();
4773
5404
  }
4774
- _cached2 = path15.basename(repoRoot);
5405
+ _cached2 = path16.basename(repoRoot);
4775
5406
  _cachedCwd = dir;
4776
5407
  return _cached2;
4777
5408
  } catch {
4778
- _cached2 = path15.basename(dir);
5409
+ _cached2 = path16.basename(dir);
4779
5410
  _cachedCwd = dir;
4780
5411
  return _cached2;
4781
5412
  }
@@ -5252,7 +5883,7 @@ __export(tasks_exports, {
5252
5883
  updateTaskStatus: () => updateTaskStatus,
5253
5884
  writeCheckpoint: () => writeCheckpoint
5254
5885
  });
5255
- import path16 from "path";
5886
+ import path17 from "path";
5256
5887
  import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
5257
5888
  async function createTask(input) {
5258
5889
  const result = await createTaskCore(input);
@@ -5272,8 +5903,8 @@ async function updateTask(input) {
5272
5903
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
5273
5904
  try {
5274
5905
  const agent = String(row.assigned_to);
5275
- const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
5276
- const cachePath = path16.join(cacheDir, `current-task-${agent}.json`);
5906
+ const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
5907
+ const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
5277
5908
  if (input.status === "in_progress") {
5278
5909
  mkdirSync6(cacheDir, { recursive: true });
5279
5910
  writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -5744,12 +6375,12 @@ __export(tmux_routing_exports, {
5744
6375
  });
5745
6376
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
5746
6377
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync4 } from "fs";
5747
- import path17 from "path";
5748
- import os9 from "os";
6378
+ import path18 from "path";
6379
+ import os10 from "os";
5749
6380
  import { fileURLToPath as fileURLToPath2 } from "url";
5750
6381
  import { unlinkSync as unlinkSync6 } from "fs";
5751
6382
  function spawnLockPath(sessionName) {
5752
- return path17.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6383
+ return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
5753
6384
  }
5754
6385
  function isProcessAlive(pid) {
5755
6386
  try {
@@ -5786,8 +6417,8 @@ function releaseSpawnLock2(sessionName) {
5786
6417
  function resolveBehaviorsExporterScript() {
5787
6418
  try {
5788
6419
  const thisFile = fileURLToPath2(import.meta.url);
5789
- const scriptPath = path17.join(
5790
- path17.dirname(thisFile),
6420
+ const scriptPath = path18.join(
6421
+ path18.dirname(thisFile),
5791
6422
  "..",
5792
6423
  "bin",
5793
6424
  "exe-export-behaviors.js"
@@ -5862,7 +6493,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
5862
6493
  mkdirSync7(SESSION_CACHE, { recursive: true });
5863
6494
  }
5864
6495
  const rootExe = extractRootExe(parentExe) ?? parentExe;
5865
- const filePath = path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
6496
+ const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
5866
6497
  writeFileSync7(filePath, JSON.stringify({
5867
6498
  parentExe: rootExe,
5868
6499
  dispatchedBy: dispatchedBy || rootExe,
@@ -5871,7 +6502,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
5871
6502
  }
5872
6503
  function getParentExe(sessionKey) {
5873
6504
  try {
5874
- const data = JSON.parse(readFileSync11(path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6505
+ const data = JSON.parse(readFileSync11(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
5875
6506
  return data.parentExe || null;
5876
6507
  } catch {
5877
6508
  return null;
@@ -5880,7 +6511,7 @@ function getParentExe(sessionKey) {
5880
6511
  function getDispatchedBy(sessionKey) {
5881
6512
  try {
5882
6513
  const data = JSON.parse(readFileSync11(
5883
- path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
6514
+ path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
5884
6515
  "utf8"
5885
6516
  ));
5886
6517
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -5891,15 +6522,24 @@ function getDispatchedBy(sessionKey) {
5891
6522
  function resolveExeSession() {
5892
6523
  const mySession = getMySession();
5893
6524
  if (!mySession) return null;
6525
+ const fromSessionName = extractRootExe(mySession);
5894
6526
  try {
5895
6527
  const key = getSessionKey();
5896
6528
  const parentExe = getParentExe(key);
5897
6529
  if (parentExe) {
5898
- return extractRootExe(parentExe) ?? parentExe;
6530
+ const fromCache = extractRootExe(parentExe) ?? parentExe;
6531
+ if (fromSessionName && fromCache !== fromSessionName) {
6532
+ process.stderr.write(
6533
+ `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
6534
+ `
6535
+ );
6536
+ return fromSessionName;
6537
+ }
6538
+ return fromCache;
5899
6539
  }
5900
6540
  } catch {
5901
6541
  }
5902
- return extractRootExe(mySession) ?? mySession;
6542
+ return fromSessionName ?? mySession;
5903
6543
  }
5904
6544
  function isEmployeeAlive(sessionName) {
5905
6545
  return getTransport().isAlive(sessionName);
@@ -6057,7 +6697,7 @@ function sendIntercom(targetSession) {
6057
6697
  try {
6058
6698
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
6059
6699
  const agent = baseAgentName(rawAgent);
6060
- const markerPath = path17.join(SESSION_CACHE, `current-task-${agent}.json`);
6700
+ const markerPath = path18.join(SESSION_CACHE, `current-task-${agent}.json`);
6061
6701
  if (existsSync14(markerPath)) {
6062
6702
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
6063
6703
  return "debounced";
@@ -6067,7 +6707,7 @@ function sendIntercom(targetSession) {
6067
6707
  try {
6068
6708
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
6069
6709
  const agent = baseAgentName(rawAgent);
6070
- const taskDir = path17.join(process.cwd(), "exe", agent);
6710
+ const taskDir = path18.join(process.cwd(), "exe", agent);
6071
6711
  if (existsSync14(taskDir)) {
6072
6712
  const files = readdirSync4(taskDir).filter(
6073
6713
  (f) => f.endsWith(".md") && f !== "DONE.txt"
@@ -6201,8 +6841,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6201
6841
  const transport = getTransport();
6202
6842
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
6203
6843
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
6204
- const logDir = path17.join(os9.homedir(), ".exe-os", "session-logs");
6205
- const logFile = path17.join(logDir, `${instanceLabel}-${Date.now()}.log`);
6844
+ const logDir = path18.join(os10.homedir(), ".exe-os", "session-logs");
6845
+ const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
6206
6846
  if (!existsSync14(logDir)) {
6207
6847
  mkdirSync7(logDir, { recursive: true });
6208
6848
  }
@@ -6210,14 +6850,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6210
6850
  let cleanupSuffix = "";
6211
6851
  try {
6212
6852
  const thisFile = fileURLToPath2(import.meta.url);
6213
- const cleanupScript = path17.join(path17.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
6853
+ const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
6214
6854
  if (existsSync14(cleanupScript)) {
6215
6855
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
6216
6856
  }
6217
6857
  } catch {
6218
6858
  }
6219
6859
  try {
6220
- const claudeJsonPath = path17.join(os9.homedir(), ".claude.json");
6860
+ const claudeJsonPath = path18.join(os10.homedir(), ".claude.json");
6221
6861
  let claudeJson = {};
6222
6862
  try {
6223
6863
  claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
@@ -6232,10 +6872,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6232
6872
  } catch {
6233
6873
  }
6234
6874
  try {
6235
- const settingsDir = path17.join(os9.homedir(), ".claude", "projects");
6875
+ const settingsDir = path18.join(os10.homedir(), ".claude", "projects");
6236
6876
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
6237
- const projSettingsDir = path17.join(settingsDir, normalizedKey);
6238
- const settingsPath = path17.join(projSettingsDir, "settings.json");
6877
+ const projSettingsDir = path18.join(settingsDir, normalizedKey);
6878
+ const settingsPath = path18.join(projSettingsDir, "settings.json");
6239
6879
  let settings = {};
6240
6880
  try {
6241
6881
  settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
@@ -6282,8 +6922,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6282
6922
  let behaviorsFlag = "";
6283
6923
  let legacyFallbackWarned = false;
6284
6924
  if (!useExeAgent && !useBinSymlink) {
6285
- const identityPath = path17.join(
6286
- os9.homedir(),
6925
+ const identityPath = path18.join(
6926
+ os10.homedir(),
6287
6927
  ".exe-os",
6288
6928
  "identity",
6289
6929
  `${employeeName}.md`
@@ -6298,7 +6938,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6298
6938
  }
6299
6939
  const behaviorsFile = exportBehaviorsSync(
6300
6940
  employeeName,
6301
- path17.basename(spawnCwd),
6941
+ path18.basename(spawnCwd),
6302
6942
  sessionName
6303
6943
  );
6304
6944
  if (behaviorsFile) {
@@ -6313,9 +6953,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6313
6953
  }
6314
6954
  let sessionContextFlag = "";
6315
6955
  try {
6316
- const ctxDir = path17.join(os9.homedir(), ".exe-os", "session-cache");
6956
+ const ctxDir = path18.join(os10.homedir(), ".exe-os", "session-cache");
6317
6957
  mkdirSync7(ctxDir, { recursive: true });
6318
- const ctxFile = path17.join(ctxDir, `session-context-${sessionName}.md`);
6958
+ const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
6319
6959
  const ctxContent = [
6320
6960
  `## Session Context`,
6321
6961
  `You are running in tmux session: ${sessionName}.`,
@@ -6399,7 +7039,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6399
7039
  transport.pipeLog(sessionName, logFile);
6400
7040
  try {
6401
7041
  const mySession = getMySession();
6402
- const dispatchInfo = path17.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
7042
+ const dispatchInfo = path18.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
6403
7043
  writeFileSync7(dispatchInfo, JSON.stringify({
6404
7044
  dispatchedBy: mySession,
6405
7045
  rootExe: exeSession,
@@ -6474,15 +7114,15 @@ var init_tmux_routing = __esm({
6474
7114
  init_intercom_queue();
6475
7115
  init_plan_limits();
6476
7116
  init_employees();
6477
- SPAWN_LOCK_DIR = path17.join(os9.homedir(), ".exe-os", "spawn-locks");
6478
- SESSION_CACHE = path17.join(os9.homedir(), ".exe-os", "session-cache");
7117
+ SPAWN_LOCK_DIR = path18.join(os10.homedir(), ".exe-os", "spawn-locks");
7118
+ SESSION_CACHE = path18.join(os10.homedir(), ".exe-os", "session-cache");
6479
7119
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
6480
7120
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
6481
7121
  VERIFY_PANE_LINES = 200;
6482
7122
  INTERCOM_DEBOUNCE_MS = 3e4;
6483
7123
  CODEX_DEBOUNCE_MS = 12e4;
6484
- INTERCOM_LOG2 = path17.join(os9.homedir(), ".exe-os", "intercom.log");
6485
- DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
7124
+ INTERCOM_LOG2 = path18.join(os10.homedir(), ".exe-os", "intercom.log");
7125
+ DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
6486
7126
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
6487
7127
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
6488
7128
  }
@@ -6540,12 +7180,12 @@ __export(worker_gate_exports, {
6540
7180
  tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
6541
7181
  });
6542
7182
  import { readdirSync as readdirSync6, writeFileSync as writeFileSync9, unlinkSync as unlinkSync8, mkdirSync as mkdirSync9, existsSync as existsSync15 } from "fs";
6543
- import path19 from "path";
7183
+ import path20 from "path";
6544
7184
  function tryAcquireWorkerSlot() {
6545
7185
  try {
6546
7186
  mkdirSync9(WORKER_PID_DIR, { recursive: true });
6547
7187
  const reservationId = `res-${process.pid}-${Date.now()}`;
6548
- const reservationPath = path19.join(WORKER_PID_DIR, `${reservationId}.pid`);
7188
+ const reservationPath = path20.join(WORKER_PID_DIR, `${reservationId}.pid`);
6549
7189
  writeFileSync9(reservationPath, String(process.pid));
6550
7190
  const files = readdirSync6(WORKER_PID_DIR);
6551
7191
  let alive = 0;
@@ -6563,7 +7203,7 @@ function tryAcquireWorkerSlot() {
6563
7203
  alive++;
6564
7204
  } catch {
6565
7205
  try {
6566
- unlinkSync8(path19.join(WORKER_PID_DIR, f));
7206
+ unlinkSync8(path20.join(WORKER_PID_DIR, f));
6567
7207
  } catch {
6568
7208
  }
6569
7209
  }
@@ -6587,13 +7227,13 @@ function tryAcquireWorkerSlot() {
6587
7227
  function registerWorkerPid(pid) {
6588
7228
  try {
6589
7229
  mkdirSync9(WORKER_PID_DIR, { recursive: true });
6590
- writeFileSync9(path19.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
7230
+ writeFileSync9(path20.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
6591
7231
  } catch {
6592
7232
  }
6593
7233
  }
6594
7234
  function cleanupWorkerPid() {
6595
7235
  try {
6596
- unlinkSync8(path19.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
7236
+ unlinkSync8(path20.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
6597
7237
  } catch {
6598
7238
  }
6599
7239
  }
@@ -6633,9 +7273,9 @@ var init_worker_gate = __esm({
6633
7273
  "src/lib/worker-gate.ts"() {
6634
7274
  "use strict";
6635
7275
  init_config();
6636
- WORKER_PID_DIR = path19.join(EXE_AI_DIR, "worker-pids");
7276
+ WORKER_PID_DIR = path20.join(EXE_AI_DIR, "worker-pids");
6637
7277
  MAX_CONCURRENT_WORKERS = 3;
6638
- BACKFILL_LOCK = path19.join(WORKER_PID_DIR, "backfill.lock");
7278
+ BACKFILL_LOCK = path20.join(WORKER_PID_DIR, "backfill.lock");
6639
7279
  }
6640
7280
  });
6641
7281
 
@@ -6738,7 +7378,7 @@ __export(crdt_sync_exports, {
6738
7378
  });
6739
7379
  import * as Y from "yjs";
6740
7380
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync16, mkdirSync as mkdirSync10, unlinkSync as unlinkSync9 } from "fs";
6741
- import path20 from "path";
7381
+ import path21 from "path";
6742
7382
  import { homedir } from "os";
6743
7383
  function getStatePath() {
6744
7384
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -6894,7 +7534,7 @@ function persistState() {
6894
7534
  if (!doc) return;
6895
7535
  try {
6896
7536
  const sp = getStatePath();
6897
- const dir = path20.dirname(sp);
7537
+ const dir = path21.dirname(sp);
6898
7538
  if (!existsSync16(dir)) mkdirSync10(dir, { recursive: true });
6899
7539
  const state = Y.encodeStateAsUpdate(doc);
6900
7540
  writeFileSync10(sp, Buffer.from(state));
@@ -6938,7 +7578,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
6938
7578
  var init_crdt_sync = __esm({
6939
7579
  "src/lib/crdt-sync.ts"() {
6940
7580
  "use strict";
6941
- DEFAULT_STATE_PATH = path20.join(homedir(), ".exe-os", "crdt-state.bin");
7581
+ DEFAULT_STATE_PATH = path21.join(homedir(), ".exe-os", "crdt-state.bin");
6942
7582
  _statePathOverride = null;
6943
7583
  doc = null;
6944
7584
  }
@@ -6974,14 +7614,14 @@ __export(cloud_sync_exports, {
6974
7614
  });
6975
7615
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync11, existsSync as existsSync17, readdirSync as readdirSync7, mkdirSync as mkdirSync11, appendFileSync as appendFileSync2, unlinkSync as unlinkSync10, openSync as openSync2, closeSync as closeSync2 } from "fs";
6976
7616
  import crypto7 from "crypto";
6977
- import path21 from "path";
7617
+ import path22 from "path";
6978
7618
  import { homedir as homedir2 } from "os";
6979
7619
  function sqlSafe(v) {
6980
7620
  return v === void 0 ? null : v;
6981
7621
  }
6982
7622
  function logError(msg) {
6983
7623
  try {
6984
- const logPath = path21.join(homedir2(), ".exe-os", "workers.log");
7624
+ const logPath = path22.join(homedir2(), ".exe-os", "workers.log");
6985
7625
  appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
6986
7626
  `);
6987
7627
  } catch {
@@ -7376,7 +8016,7 @@ async function cloudSync(config) {
7376
8016
  try {
7377
8017
  const employees = await loadEmployees();
7378
8018
  rosterResult.employees = employees.length;
7379
- const idDir = path21.join(EXE_AI_DIR, "identity");
8019
+ const idDir = path22.join(EXE_AI_DIR, "identity");
7380
8020
  if (existsSync17(idDir)) {
7381
8021
  rosterResult.identities = readdirSync7(idDir).filter((f) => f.endsWith(".md")).length;
7382
8022
  }
@@ -7417,9 +8057,9 @@ function consumeRosterDeletions() {
7417
8057
  }
7418
8058
  }
7419
8059
  function buildRosterBlob(paths) {
7420
- const rosterPath = paths?.rosterPath ?? path21.join(EXE_AI_DIR, "exe-employees.json");
7421
- const identityDir = paths?.identityDir ?? path21.join(EXE_AI_DIR, "identity");
7422
- const configPath = paths?.configPath ?? path21.join(EXE_AI_DIR, "config.json");
8060
+ const rosterPath = paths?.rosterPath ?? path22.join(EXE_AI_DIR, "exe-employees.json");
8061
+ const identityDir = paths?.identityDir ?? path22.join(EXE_AI_DIR, "identity");
8062
+ const configPath = paths?.configPath ?? path22.join(EXE_AI_DIR, "config.json");
7423
8063
  let roster = [];
7424
8064
  if (existsSync17(rosterPath)) {
7425
8065
  try {
@@ -7431,7 +8071,7 @@ function buildRosterBlob(paths) {
7431
8071
  if (existsSync17(identityDir)) {
7432
8072
  for (const file of readdirSync7(identityDir).filter((f) => f.endsWith(".md"))) {
7433
8073
  try {
7434
- identities[file] = readFileSync14(path21.join(identityDir, file), "utf-8");
8074
+ identities[file] = readFileSync14(path22.join(identityDir, file), "utf-8");
7435
8075
  } catch {
7436
8076
  }
7437
8077
  }
@@ -7444,7 +8084,7 @@ function buildRosterBlob(paths) {
7444
8084
  }
7445
8085
  }
7446
8086
  let agentConfig;
7447
- const agentConfigPath = path21.join(EXE_AI_DIR, "agent-config.json");
8087
+ const agentConfigPath = path22.join(EXE_AI_DIR, "agent-config.json");
7448
8088
  if (existsSync17(agentConfigPath)) {
7449
8089
  try {
7450
8090
  agentConfig = JSON.parse(readFileSync14(agentConfigPath, "utf-8"));
@@ -7523,7 +8163,7 @@ async function cloudPullRoster(config) {
7523
8163
  }
7524
8164
  }
7525
8165
  function mergeConfig(remoteConfig, configPath) {
7526
- const cfgPath = configPath ?? path21.join(EXE_AI_DIR, "config.json");
8166
+ const cfgPath = configPath ?? path22.join(EXE_AI_DIR, "config.json");
7527
8167
  let local = {};
7528
8168
  if (existsSync17(cfgPath)) {
7529
8169
  try {
@@ -7532,14 +8172,14 @@ function mergeConfig(remoteConfig, configPath) {
7532
8172
  }
7533
8173
  }
7534
8174
  const merged = { ...remoteConfig, ...local };
7535
- const dir = path21.dirname(cfgPath);
8175
+ const dir = path22.dirname(cfgPath);
7536
8176
  if (!existsSync17(dir)) mkdirSync11(dir, { recursive: true });
7537
8177
  writeFileSync11(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
7538
8178
  }
7539
8179
  async function mergeRosterFromRemote(remote, paths) {
7540
8180
  return withRosterLock(async () => {
7541
8181
  const rosterPath = paths?.rosterPath ?? void 0;
7542
- const identityDir = paths?.identityDir ?? path21.join(EXE_AI_DIR, "identity");
8182
+ const identityDir = paths?.identityDir ?? path22.join(EXE_AI_DIR, "identity");
7543
8183
  const localEmployees = await loadEmployees(rosterPath);
7544
8184
  const localNames = new Set(localEmployees.map((e) => e.name));
7545
8185
  let added = 0;
@@ -7561,7 +8201,7 @@ async function mergeRosterFromRemote(remote, paths) {
7561
8201
  const remoteIdentity = remote.identities[matchedKey];
7562
8202
  if (remoteIdentity) {
7563
8203
  if (!existsSync17(identityDir)) mkdirSync11(identityDir, { recursive: true });
7564
- const idPath = path21.join(identityDir, `${remoteEmp.name}.md`);
8204
+ const idPath = path22.join(identityDir, `${remoteEmp.name}.md`);
7565
8205
  let localIdentity = null;
7566
8206
  try {
7567
8207
  localIdentity = existsSync17(idPath) ? readFileSync14(idPath, "utf-8") : null;
@@ -7594,7 +8234,7 @@ async function mergeRosterFromRemote(remote, paths) {
7594
8234
  }
7595
8235
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
7596
8236
  try {
7597
- const agentConfigPath = path21.join(EXE_AI_DIR, "agent-config.json");
8237
+ const agentConfigPath = path22.join(EXE_AI_DIR, "agent-config.json");
7598
8238
  let local = {};
7599
8239
  if (existsSync17(agentConfigPath)) {
7600
8240
  try {
@@ -8041,9 +8681,9 @@ var init_cloud_sync = __esm({
8041
8681
  LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
8042
8682
  FETCH_TIMEOUT_MS = 3e4;
8043
8683
  PUSH_BATCH_SIZE = 5e3;
8044
- ROSTER_LOCK_PATH = path21.join(EXE_AI_DIR, "roster-merge.lock");
8684
+ ROSTER_LOCK_PATH = path22.join(EXE_AI_DIR, "roster-merge.lock");
8045
8685
  LOCK_STALE_MS = 3e4;
8046
- ROSTER_DELETIONS_PATH = path21.join(EXE_AI_DIR, "roster-deletions.json");
8686
+ ROSTER_DELETIONS_PATH = path22.join(EXE_AI_DIR, "roster-deletions.json");
8047
8687
  }
8048
8688
  });
8049
8689
 
@@ -8225,10 +8865,10 @@ var init_schedules = __esm({
8225
8865
 
8226
8866
  // src/bin/exe-boot.ts
8227
8867
  init_employees();
8228
- import path22 from "path";
8868
+ import path23 from "path";
8229
8869
  import { mkdir as mkdir5, writeFile as writeFile6 } from "fs/promises";
8230
8870
  import { existsSync as existsSync18, readFileSync as readFileSync15, readdirSync as readdirSync8, unlinkSync as unlinkSync11 } from "fs";
8231
- import os10 from "os";
8871
+ import os11 from "os";
8232
8872
 
8233
8873
  // src/lib/employee-templates.ts
8234
8874
  init_global_procedures();
@@ -8732,11 +9372,11 @@ init_session_key();
8732
9372
  init_employees();
8733
9373
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, unlinkSync as unlinkSync7, readdirSync as readdirSync5 } from "fs";
8734
9374
  import { execSync as execSync8 } from "child_process";
8735
- import path18 from "path";
8736
- var CACHE_DIR = path18.join(EXE_AI_DIR, "session-cache");
9375
+ import path19 from "path";
9376
+ var CACHE_DIR = path19.join(EXE_AI_DIR, "session-cache");
8737
9377
  var STALE_MS = 24 * 60 * 60 * 1e3;
8738
9378
  function getMarkerPath() {
8739
- return path18.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
9379
+ return path19.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
8740
9380
  }
8741
9381
  function writeActiveAgent(agentId, agentRole) {
8742
9382
  try {
@@ -8751,11 +9391,11 @@ function writeActiveAgent(agentId, agentRole) {
8751
9391
  function cleanupSessionMarkers() {
8752
9392
  const key = getSessionKey();
8753
9393
  try {
8754
- unlinkSync7(path18.join(CACHE_DIR, `active-agent-${key}.json`));
9394
+ unlinkSync7(path19.join(CACHE_DIR, `active-agent-${key}.json`));
8755
9395
  } catch {
8756
9396
  }
8757
9397
  try {
8758
- unlinkSync7(path18.join(CACHE_DIR, "active-agent-undefined.json"));
9398
+ unlinkSync7(path19.join(CACHE_DIR, "active-agent-undefined.json"));
8759
9399
  } catch {
8760
9400
  }
8761
9401
  }
@@ -8845,7 +9485,7 @@ async function boot(options) {
8845
9485
  const employeeDirs = entries.filter((e) => e.isDirectory() && !["output", "research"].includes(e.name));
8846
9486
  for (const dir of employeeDirs) {
8847
9487
  const employee = dir.name;
8848
- const taskDir = path22.join(exeDir, employee);
9488
+ const taskDir = path23.join(exeDir, employee);
8849
9489
  let files;
8850
9490
  try {
8851
9491
  files = readdirSync9(taskDir).filter((f) => f.endsWith(".md"));
@@ -8856,7 +9496,7 @@ async function boot(options) {
8856
9496
  const taskFilePath = `exe/${employee}/${file}`;
8857
9497
  let content;
8858
9498
  try {
8859
- content = readFs(path22.join(taskDir, file), "utf8");
9499
+ content = readFs(path23.join(taskDir, file), "utf8");
8860
9500
  } catch {
8861
9501
  continue;
8862
9502
  }
@@ -8942,12 +9582,12 @@ async function boot(options) {
8942
9582
  }
8943
9583
  try {
8944
9584
  for (const reviewDirName of /* @__PURE__ */ new Set(["exe", coordinatorName])) {
8945
- const reviewDir = path22.join(process.cwd(), "exe", reviewDirName);
9585
+ const reviewDir = path23.join(process.cwd(), "exe", reviewDirName);
8946
9586
  if (existsSync18(reviewDir)) {
8947
9587
  for (const f of readdirSync8(reviewDir)) {
8948
9588
  if (f.startsWith("review-") && f.endsWith(".md")) {
8949
9589
  try {
8950
- unlinkSync11(path22.join(reviewDir, f));
9590
+ unlinkSync11(path23.join(reviewDir, f));
8951
9591
  } catch {
8952
9592
  }
8953
9593
  }
@@ -8993,7 +9633,7 @@ async function boot(options) {
8993
9633
  });
8994
9634
  const taskFile = String(r.task_file);
8995
9635
  try {
8996
- const filePath = path22.join(process.cwd(), taskFile);
9636
+ const filePath = path23.join(process.cwd(), taskFile);
8997
9637
  if (existsSync18(filePath)) {
8998
9638
  let content = readFileSync15(filePath, "utf8");
8999
9639
  content = content.replace(/\*\*Status:\*\* needs_review/, "**Status:** done");
@@ -9492,8 +10132,8 @@ async function boot(options) {
9492
10132
  })()
9493
10133
  ]);
9494
10134
  try {
9495
- const configPath = path22.join(
9496
- process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os10.homedir(), ".exe-os"),
10135
+ const configPath = path23.join(
10136
+ process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path23.join(os11.homedir(), ".exe-os"),
9497
10137
  "config.json"
9498
10138
  );
9499
10139
  if (existsSync18(configPath)) {
@@ -9503,7 +10143,7 @@ async function boot(options) {
9503
10143
  } catch {
9504
10144
  }
9505
10145
  try {
9506
- const backfillFlagPath = path22.join(EXE_AI_DIR, "session-cache", "needs-backfill");
10146
+ const backfillFlagPath = path23.join(EXE_AI_DIR, "session-cache", "needs-backfill");
9507
10147
  const isBackfillNeeded = () => existsSync18(backfillFlagPath);
9508
10148
  const coverageResult = await client.execute({
9509
10149
  sql: `SELECT COUNT(*) as total,
@@ -9526,7 +10166,7 @@ async function boot(options) {
9526
10166
  let daemonRunning = false;
9527
10167
  let daemonUptime;
9528
10168
  let daemonRequestsServed;
9529
- const socketPath = path22.join(EXE_AI_DIR, "exed.sock");
10169
+ const socketPath = path23.join(EXE_AI_DIR, "exed.sock");
9530
10170
  if (existsSync18(socketPath)) {
9531
10171
  try {
9532
10172
  const net2 = await import("net");
@@ -9569,7 +10209,7 @@ async function boot(options) {
9569
10209
  }
9570
10210
  }
9571
10211
  if (!daemonRunning) {
9572
- const pidPath = path22.join(EXE_AI_DIR, "exed.pid");
10212
+ const pidPath = path23.join(EXE_AI_DIR, "exed.pid");
9573
10213
  if (existsSync18(pidPath)) {
9574
10214
  try {
9575
10215
  const pid = parseInt(readFileSync15(pidPath, "utf8").trim(), 10);
@@ -9583,7 +10223,7 @@ async function boot(options) {
9583
10223
  }
9584
10224
  if (nullCount === 0) {
9585
10225
  try {
9586
- const flagPath = path22.join(EXE_AI_DIR, "session-cache", "needs-backfill");
10226
+ const flagPath = path23.join(EXE_AI_DIR, "session-cache", "needs-backfill");
9587
10227
  if (existsSync18(flagPath)) {
9588
10228
  const { unlinkSync: unlinkSync12 } = await import("fs");
9589
10229
  unlinkSync12(flagPath);
@@ -9610,10 +10250,10 @@ async function boot(options) {
9610
10250
  const { spawn: spawn2 } = await import("child_process");
9611
10251
  const { fileURLToPath: fileURLToPath4 } = await import("url");
9612
10252
  const thisFile = fileURLToPath4(import.meta.url);
9613
- const backfillPath = path22.resolve(path22.dirname(thisFile), "backfill-vectors.js");
10253
+ const backfillPath = path23.resolve(path23.dirname(thisFile), "backfill-vectors.js");
9614
10254
  if (existsSync18(backfillPath)) {
9615
10255
  const { openSync: openSync3, closeSync: closeSync3 } = await import("fs");
9616
- const workerLogPath = path22.join(EXE_AI_DIR, "workers.log");
10256
+ const workerLogPath = path23.join(EXE_AI_DIR, "workers.log");
9617
10257
  let stderrFd = "ignore";
9618
10258
  try {
9619
10259
  stderrFd = openSync3(workerLogPath, "a");
@@ -9643,7 +10283,7 @@ async function boot(options) {
9643
10283
  const criticalBinaries = ["backfill-vectors.js", "scan-tasks.js"];
9644
10284
  const missing = [];
9645
10285
  for (const bin of criticalBinaries) {
9646
- const binPath = path22.resolve(path22.dirname(thisFile), bin);
10286
+ const binPath = path23.resolve(path23.dirname(thisFile), bin);
9647
10287
  if (!existsSync18(binPath)) {
9648
10288
  missing.push(`dist/bin/${bin}`);
9649
10289
  }
@@ -9673,7 +10313,7 @@ async function boot(options) {
9673
10313
  console.log(brief);
9674
10314
  return;
9675
10315
  }
9676
- const sessionDir = path22.join(EXE_AI_DIR, "sessions", coordinatorName);
10316
+ const sessionDir = path23.join(EXE_AI_DIR, "sessions", coordinatorName);
9677
10317
  await mkdir5(sessionDir, { recursive: true });
9678
10318
  const claudeMdContent = `${getSessionPrompt(coordinatorEmployee.systemPrompt)}
9679
10319
 
@@ -9682,7 +10322,7 @@ async function boot(options) {
9682
10322
  # Status Brief
9683
10323
 
9684
10324
  ${brief}`;
9685
- await writeFile6(path22.join(sessionDir, "CLAUDE.md"), claudeMdContent, "utf-8");
10325
+ await writeFile6(path23.join(sessionDir, "CLAUDE.md"), claudeMdContent, "utf-8");
9686
10326
  const unread = await readUnreadNotifications();
9687
10327
  if (unread.length > 0) {
9688
10328
  console.log(`\u{1F4EC} ${unread.length} unread notification${unread.length === 1 ? "" : "s"}`);
@@ -9691,8 +10331,8 @@ ${brief}`;
9691
10331
  await cleanupOldNotifications();
9692
10332
  console.log(brief);
9693
10333
  try {
9694
- const configPath2 = path22.join(
9695
- process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os10.homedir(), ".exe-os"),
10334
+ const configPath2 = path23.join(
10335
+ process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path23.join(os11.homedir(), ".exe-os"),
9696
10336
  "config.json"
9697
10337
  );
9698
10338
  if (existsSync18(configPath2)) {