@askexenow/exe-os 0.8.32 → 0.8.36

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 (87) hide show
  1. package/dist/bin/backfill-conversations.js +332 -348
  2. package/dist/bin/backfill-responses.js +72 -12
  3. package/dist/bin/backfill-vectors.js +72 -12
  4. package/dist/bin/cleanup-stale-review-tasks.js +63 -3
  5. package/dist/bin/cli.js +1518 -1122
  6. package/dist/bin/exe-agent.js +4 -4
  7. package/dist/bin/exe-assign.js +80 -18
  8. package/dist/bin/exe-boot.js +408 -89
  9. package/dist/bin/exe-call.js +83 -24
  10. package/dist/bin/exe-dispatch.js +18 -10
  11. package/dist/bin/exe-doctor.js +63 -3
  12. package/dist/bin/exe-export-behaviors.js +64 -3
  13. package/dist/bin/exe-forget.js +69 -4
  14. package/dist/bin/exe-gateway.js +121 -36
  15. package/dist/bin/exe-heartbeat.js +77 -13
  16. package/dist/bin/exe-kill.js +64 -3
  17. package/dist/bin/exe-launch-agent.js +162 -35
  18. package/dist/bin/exe-link.js +946 -0
  19. package/dist/bin/exe-new-employee.js +121 -36
  20. package/dist/bin/exe-pending-messages.js +72 -7
  21. package/dist/bin/exe-pending-notifications.js +63 -3
  22. package/dist/bin/exe-pending-reviews.js +75 -10
  23. package/dist/bin/exe-rename.js +1287 -0
  24. package/dist/bin/exe-review.js +64 -4
  25. package/dist/bin/exe-search.js +79 -13
  26. package/dist/bin/exe-session-cleanup.js +91 -26
  27. package/dist/bin/exe-status.js +64 -4
  28. package/dist/bin/exe-team.js +64 -4
  29. package/dist/bin/git-sweep.js +71 -4
  30. package/dist/bin/graph-backfill.js +64 -3
  31. package/dist/bin/graph-export.js +64 -3
  32. package/dist/bin/install.js +3 -3
  33. package/dist/bin/scan-tasks.js +71 -4
  34. package/dist/bin/setup.js +156 -38
  35. package/dist/bin/shard-migrate.js +64 -3
  36. package/dist/bin/wiki-sync.js +64 -3
  37. package/dist/gateway/index.js +122 -37
  38. package/dist/hooks/bug-report-worker.js +209 -23
  39. package/dist/hooks/commit-complete.js +71 -4
  40. package/dist/hooks/error-recall.js +79 -13
  41. package/dist/hooks/ingest-worker.js +129 -43
  42. package/dist/hooks/instructions-loaded.js +71 -4
  43. package/dist/hooks/notification.js +71 -4
  44. package/dist/hooks/post-compact.js +71 -4
  45. package/dist/hooks/pre-compact.js +71 -4
  46. package/dist/hooks/pre-tool-use.js +413 -194
  47. package/dist/hooks/prompt-ingest-worker.js +82 -22
  48. package/dist/hooks/prompt-submit.js +103 -37
  49. package/dist/hooks/response-ingest-worker.js +87 -22
  50. package/dist/hooks/session-end.js +71 -4
  51. package/dist/hooks/session-start.js +79 -13
  52. package/dist/hooks/stop.js +71 -4
  53. package/dist/hooks/subagent-stop.js +71 -4
  54. package/dist/hooks/summary-worker.js +303 -50
  55. package/dist/index.js +134 -46
  56. package/dist/lib/cloud-sync.js +209 -15
  57. package/dist/lib/consolidation.js +4 -4
  58. package/dist/lib/database.js +64 -2
  59. package/dist/lib/device-registry.js +70 -3
  60. package/dist/lib/employee-templates.js +48 -22
  61. package/dist/lib/employees.js +34 -1
  62. package/dist/lib/exe-daemon.js +136 -53
  63. package/dist/lib/hybrid-search.js +79 -13
  64. package/dist/lib/identity-templates.js +57 -6
  65. package/dist/lib/identity.js +3 -3
  66. package/dist/lib/messaging.js +22 -14
  67. package/dist/lib/reminders.js +3 -3
  68. package/dist/lib/schedules.js +63 -3
  69. package/dist/lib/skill-learning.js +3 -3
  70. package/dist/lib/status-brief.js +63 -5
  71. package/dist/lib/store.js +64 -3
  72. package/dist/lib/task-router.js +4 -2
  73. package/dist/lib/tasks.js +48 -21
  74. package/dist/lib/tmux-routing.js +47 -20
  75. package/dist/mcp/server.js +727 -58
  76. package/dist/mcp/tools/complete-reminder.js +3 -3
  77. package/dist/mcp/tools/create-reminder.js +3 -3
  78. package/dist/mcp/tools/create-task.js +151 -24
  79. package/dist/mcp/tools/deactivate-behavior.js +3 -3
  80. package/dist/mcp/tools/list-reminders.js +3 -3
  81. package/dist/mcp/tools/list-tasks.js +17 -8
  82. package/dist/mcp/tools/send-message.js +24 -16
  83. package/dist/mcp/tools/update-task.js +25 -16
  84. package/dist/runtime/index.js +112 -24
  85. package/dist/tui/App.js +139 -36
  86. package/package.json +6 -2
  87. package/src/commands/exe/rename.md +12 -0
@@ -6,12 +6,12 @@ import crypto from "crypto";
6
6
 
7
7
  // src/lib/database.ts
8
8
  import { createClient } from "@libsql/client";
9
- var _client = null;
9
+ var _resilientClient = null;
10
10
  function getClient() {
11
- if (!_client) {
11
+ if (!_resilientClient) {
12
12
  throw new Error("Database client not initialized. Call initDatabase() first.");
13
13
  }
14
- return _client;
14
+ return _resilientClient;
15
15
  }
16
16
 
17
17
  // src/lib/reminders.ts
@@ -6,12 +6,12 @@ import crypto from "crypto";
6
6
 
7
7
  // src/lib/database.ts
8
8
  import { createClient } from "@libsql/client";
9
- var _client = null;
9
+ var _resilientClient = null;
10
10
  function getClient() {
11
- if (!_client) {
11
+ if (!_resilientClient) {
12
12
  throw new Error("Database client not initialized. Call initDatabase() first.");
13
13
  }
14
- return _client;
14
+ return _resilientClient;
15
15
  }
16
16
 
17
17
  // src/lib/reminders.ts
@@ -19,19 +19,27 @@ var __copyProps = (to, from, except, desc) => {
19
19
  };
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
 
22
+ // src/lib/db-retry.ts
23
+ var init_db_retry = __esm({
24
+ "src/lib/db-retry.ts"() {
25
+ "use strict";
26
+ }
27
+ });
28
+
22
29
  // src/lib/database.ts
23
30
  import { createClient } from "@libsql/client";
24
31
  function getClient() {
25
- if (!_client) {
32
+ if (!_resilientClient) {
26
33
  throw new Error("Database client not initialized. Call initDatabase() first.");
27
34
  }
28
- return _client;
35
+ return _resilientClient;
29
36
  }
30
- var _client;
37
+ var _resilientClient;
31
38
  var init_database = __esm({
32
39
  "src/lib/database.ts"() {
33
40
  "use strict";
34
- _client = null;
41
+ init_db_retry();
42
+ _resilientClient = null;
35
43
  }
36
44
  });
37
45
 
@@ -508,21 +516,139 @@ var init_tasks_crud = __esm({
508
516
  });
509
517
 
510
518
  // src/lib/employees.ts
519
+ var employees_exports = {};
520
+ __export(employees_exports, {
521
+ EMPLOYEES_PATH: () => EMPLOYEES_PATH,
522
+ addEmployee: () => addEmployee,
523
+ getEmployee: () => getEmployee,
524
+ getEmployeeByRole: () => getEmployeeByRole,
525
+ getEmployeeNamesByRole: () => getEmployeeNamesByRole,
526
+ hasRole: () => hasRole,
527
+ isMultiInstance: () => isMultiInstance,
528
+ loadEmployees: () => loadEmployees,
529
+ loadEmployeesSync: () => loadEmployeesSync,
530
+ registerBinSymlinks: () => registerBinSymlinks,
531
+ saveEmployees: () => saveEmployees,
532
+ validateEmployeeName: () => validateEmployeeName
533
+ });
511
534
  import { readFile as readFile2, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
512
- import { existsSync as existsSync4, symlinkSync, readlinkSync } from "fs";
535
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
513
536
  import { execSync as execSync2 } from "child_process";
514
537
  import path4 from "path";
515
- var EMPLOYEES_PATH;
538
+ function validateEmployeeName(name) {
539
+ if (!name) {
540
+ return { valid: false, error: "Name is required" };
541
+ }
542
+ if (name.length > 32) {
543
+ return { valid: false, error: "Name must be 32 characters or fewer" };
544
+ }
545
+ if (!/^[a-z][a-z0-9]*$/.test(name)) {
546
+ return {
547
+ valid: false,
548
+ error: "Name must start with a letter and contain only lowercase alphanumeric characters"
549
+ };
550
+ }
551
+ return { valid: true };
552
+ }
553
+ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
554
+ if (!existsSync4(employeesPath)) {
555
+ return [];
556
+ }
557
+ const raw = await readFile2(employeesPath, "utf-8");
558
+ try {
559
+ return JSON.parse(raw);
560
+ } catch {
561
+ return [];
562
+ }
563
+ }
564
+ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
565
+ await mkdir3(path4.dirname(employeesPath), { recursive: true });
566
+ await writeFile3(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
567
+ }
568
+ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
569
+ if (!existsSync4(employeesPath)) return [];
570
+ try {
571
+ return JSON.parse(readFileSync4(employeesPath, "utf-8"));
572
+ } catch {
573
+ return [];
574
+ }
575
+ }
576
+ function getEmployee(employees, name) {
577
+ return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
578
+ }
579
+ function getEmployeeByRole(employees, role) {
580
+ const lower = role.toLowerCase();
581
+ return employees.find((e) => e.role.toLowerCase() === lower);
582
+ }
583
+ function getEmployeeNamesByRole(employees, role) {
584
+ const lower = role.toLowerCase();
585
+ return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
586
+ }
587
+ function hasRole(agentName, role) {
588
+ const employees = loadEmployeesSync();
589
+ const emp = getEmployee(employees, agentName);
590
+ return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
591
+ }
592
+ function isMultiInstance(agentName, employees) {
593
+ const roster = employees ?? loadEmployeesSync();
594
+ const emp = getEmployee(roster, agentName);
595
+ if (!emp) return false;
596
+ return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
597
+ }
598
+ function addEmployee(employees, employee) {
599
+ const normalized = { ...employee, name: employee.name.toLowerCase() };
600
+ if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
601
+ throw new Error(`Employee '${normalized.name}' already exists`);
602
+ }
603
+ return [...employees, normalized];
604
+ }
605
+ function registerBinSymlinks(name) {
606
+ const created = [];
607
+ const skipped = [];
608
+ const errors = [];
609
+ let exeBinPath;
610
+ try {
611
+ exeBinPath = execSync2("which exe", { encoding: "utf-8" }).trim();
612
+ } catch {
613
+ errors.push("Could not find 'exe' in PATH");
614
+ return { created, skipped, errors };
615
+ }
616
+ const binDir = path4.dirname(exeBinPath);
617
+ let target;
618
+ try {
619
+ target = readlinkSync(exeBinPath);
620
+ } catch {
621
+ errors.push("Could not read 'exe' symlink");
622
+ return { created, skipped, errors };
623
+ }
624
+ for (const suffix of ["", "-opencode"]) {
625
+ const linkName = `${name}${suffix}`;
626
+ const linkPath = path4.join(binDir, linkName);
627
+ if (existsSync4(linkPath)) {
628
+ skipped.push(linkName);
629
+ continue;
630
+ }
631
+ try {
632
+ symlinkSync(target, linkPath);
633
+ created.push(linkName);
634
+ } catch (err) {
635
+ errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
636
+ }
637
+ }
638
+ return { created, skipped, errors };
639
+ }
640
+ var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
516
641
  var init_employees = __esm({
517
642
  "src/lib/employees.ts"() {
518
643
  "use strict";
519
644
  init_config();
520
645
  EMPLOYEES_PATH = path4.join(EXE_AI_DIR, "exe-employees.json");
646
+ MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
521
647
  }
522
648
  });
523
649
 
524
650
  // src/lib/session-registry.ts
525
- import { readFileSync as readFileSync4, writeFileSync, mkdirSync, existsSync as existsSync5 } from "fs";
651
+ import { readFileSync as readFileSync5, writeFileSync, mkdirSync, existsSync as existsSync5 } from "fs";
526
652
  import path5 from "path";
527
653
  import os3 from "os";
528
654
  function registerSession(entry) {
@@ -541,7 +667,7 @@ function registerSession(entry) {
541
667
  }
542
668
  function listSessions() {
543
669
  try {
544
- const raw = readFileSync4(REGISTRY_PATH, "utf8");
670
+ const raw = readFileSync5(REGISTRY_PATH, "utf8");
545
671
  return JSON.parse(raw);
546
672
  } catch {
547
673
  return [];
@@ -771,7 +897,7 @@ var init_provider_table = __esm({
771
897
  });
772
898
 
773
899
  // src/lib/intercom-queue.ts
774
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
900
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
775
901
  import path6 from "path";
776
902
  import os4 from "os";
777
903
  function ensureDir() {
@@ -781,7 +907,7 @@ function ensureDir() {
781
907
  function readQueue() {
782
908
  try {
783
909
  if (!existsSync6(QUEUE_PATH)) return [];
784
- return JSON.parse(readFileSync5(QUEUE_PATH, "utf8"));
910
+ return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
785
911
  } catch {
786
912
  return [];
787
913
  }
@@ -820,7 +946,7 @@ var init_intercom_queue = __esm({
820
946
  });
821
947
 
822
948
  // src/lib/license.ts
823
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
949
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
824
950
  import { randomUUID } from "crypto";
825
951
  import path7 from "path";
826
952
  import { jwtVerify, importSPKI } from "jose";
@@ -843,12 +969,12 @@ var init_license = __esm({
843
969
  });
844
970
 
845
971
  // src/lib/plan-limits.ts
846
- import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
972
+ import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
847
973
  import path8 from "path";
848
974
  function getLicenseSync() {
849
975
  try {
850
976
  if (!existsSync8(CACHE_PATH2)) return freeLicense();
851
- const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
977
+ const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
852
978
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
853
979
  const parts = raw.token.split(".");
854
980
  if (parts.length !== 3) return freeLicense();
@@ -887,7 +1013,7 @@ function assertEmployeeLimitSync(rosterPath) {
887
1013
  let count = 0;
888
1014
  try {
889
1015
  if (existsSync8(filePath)) {
890
- const raw = readFileSync7(filePath, "utf8");
1016
+ const raw = readFileSync8(filePath, "utf8");
891
1017
  const employees = JSON.parse(raw);
892
1018
  count = Array.isArray(employees) ? employees.length : 0;
893
1019
  }
@@ -922,7 +1048,7 @@ var init_plan_limits = __esm({
922
1048
 
923
1049
  // src/lib/tmux-routing.ts
924
1050
  import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
925
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync9, appendFileSync } from "fs";
1051
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync9, appendFileSync } from "fs";
926
1052
  import path9 from "path";
927
1053
  import os5 from "os";
928
1054
  import { fileURLToPath } from "url";
@@ -971,7 +1097,7 @@ function extractRootExe(name) {
971
1097
  }
972
1098
  function getParentExe(sessionKey) {
973
1099
  try {
974
- const data = JSON.parse(readFileSync8(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1100
+ const data = JSON.parse(readFileSync9(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
975
1101
  return data.parentExe || null;
976
1102
  } catch {
977
1103
  return null;
@@ -1005,7 +1131,7 @@ function findFreeInstance(employeeName, exeSession, maxInstances = 10, isAlive =
1005
1131
  function readDebounceState() {
1006
1132
  try {
1007
1133
  if (!existsSync9(DEBOUNCE_FILE)) return {};
1008
- return JSON.parse(readFileSync8(DEBOUNCE_FILE, "utf8"));
1134
+ return JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
1009
1135
  } catch {
1010
1136
  return {};
1011
1137
  }
@@ -1179,7 +1305,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1179
1305
  const claudeJsonPath = path9.join(os5.homedir(), ".claude.json");
1180
1306
  let claudeJson = {};
1181
1307
  try {
1182
- claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
1308
+ claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
1183
1309
  } catch {
1184
1310
  }
1185
1311
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -1197,7 +1323,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
1197
1323
  const settingsPath = path9.join(projSettingsDir, "settings.json");
1198
1324
  let settings = {};
1199
1325
  try {
1200
- settings = JSON.parse(readFileSync8(settingsPath, "utf8"));
1326
+ settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
1201
1327
  } catch {
1202
1328
  }
1203
1329
  const perms = settings.permissions ?? {};
@@ -1544,7 +1670,7 @@ async function dispatchTaskToEmployee(input) {
1544
1670
  } else {
1545
1671
  const projectDir = input.projectDir ?? process.cwd();
1546
1672
  const result = ensureEmployee(input.assignedTo, exeSession, projectDir, {
1547
- autoInstance: input.assignedTo === "tom" || input.assignedTo === "sasha"
1673
+ autoInstance: isMultiInstance(input.assignedTo)
1548
1674
  });
1549
1675
  if (result.status === "failed") {
1550
1676
  process.stderr.write(
@@ -1566,6 +1692,7 @@ var init_tasks_notify = __esm({
1566
1692
  init_session_key();
1567
1693
  init_notifications();
1568
1694
  init_transport();
1695
+ init_employees();
1569
1696
  }
1570
1697
  });
1571
1698
 
@@ -1607,7 +1734,7 @@ import { z } from "zod";
1607
1734
 
1608
1735
  // src/adapters/claude/active-agent.ts
1609
1736
  init_config();
1610
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
1737
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
1611
1738
  import { execSync as execSync7 } from "child_process";
1612
1739
  import path14 from "path";
1613
1740
 
@@ -1623,7 +1750,7 @@ function getMarkerPath() {
1623
1750
  function getActiveAgent() {
1624
1751
  try {
1625
1752
  const markerPath = getMarkerPath();
1626
- const raw = readFileSync9(markerPath, "utf8");
1753
+ const raw = readFileSync10(markerPath, "utf8");
1627
1754
  const data = JSON.parse(raw);
1628
1755
  if (data.agentId) {
1629
1756
  if (data.startedAt) {
@@ -1717,8 +1844,8 @@ function registerCreateTask(server) {
1717
1844
  try {
1718
1845
  const exeSession = resolveExeSession();
1719
1846
  if (exeSession) {
1720
- const MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["tom", "sasha"]);
1721
- const useAutoInstance = MULTI_INSTANCE_ROLES.has(assigned_to);
1847
+ const { isMultiInstance: isMultiInstance2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
1848
+ const useAutoInstance = isMultiInstance2(assigned_to);
1722
1849
  const { loadConfigSync: loadConfigSync2 } = await Promise.resolve().then(() => (init_config(), config_exports));
1723
1850
  const cfg = loadConfigSync2();
1724
1851
  const result = ensureEmployee(assigned_to, exeSession, process.cwd(), {
@@ -6,12 +6,12 @@ import crypto from "crypto";
6
6
 
7
7
  // src/lib/database.ts
8
8
  import { createClient } from "@libsql/client";
9
- var _client = null;
9
+ var _resilientClient = null;
10
10
  function getClient() {
11
- if (!_client) {
11
+ if (!_resilientClient) {
12
12
  throw new Error("Database client not initialized. Call initDatabase() first.");
13
13
  }
14
- return _client;
14
+ return _resilientClient;
15
15
  }
16
16
 
17
17
  // src/lib/behaviors.ts
@@ -6,12 +6,12 @@ import crypto from "crypto";
6
6
 
7
7
  // src/lib/database.ts
8
8
  import { createClient } from "@libsql/client";
9
- var _client = null;
9
+ var _resilientClient = null;
10
10
  function getClient() {
11
- if (!_client) {
11
+ if (!_resilientClient) {
12
12
  throw new Error("Database client not initialized. Call initDatabase() first.");
13
13
  }
14
- return _client;
14
+ return _resilientClient;
15
15
  }
16
16
 
17
17
  // src/lib/reminders.ts
@@ -3,19 +3,27 @@ var __esm = (fn, res) => function __init() {
3
3
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
4
  };
5
5
 
6
+ // src/lib/db-retry.ts
7
+ var init_db_retry = __esm({
8
+ "src/lib/db-retry.ts"() {
9
+ "use strict";
10
+ }
11
+ });
12
+
6
13
  // src/lib/database.ts
7
14
  import { createClient } from "@libsql/client";
8
15
  function getClient() {
9
- if (!_client) {
16
+ if (!_resilientClient) {
10
17
  throw new Error("Database client not initialized. Call initDatabase() first.");
11
18
  }
12
- return _client;
19
+ return _resilientClient;
13
20
  }
14
- var _client;
21
+ var _resilientClient;
15
22
  var init_database = __esm({
16
23
  "src/lib/database.ts"() {
17
24
  "use strict";
18
- _client = null;
25
+ init_db_retry();
26
+ _resilientClient = null;
19
27
  }
20
28
  });
21
29
 
@@ -194,7 +202,7 @@ var init_tasks_crud = __esm({
194
202
 
195
203
  // src/lib/employees.ts
196
204
  import { readFile as readFile2, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
197
- import { existsSync as existsSync4, symlinkSync, readlinkSync } from "fs";
205
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
198
206
  import { execSync as execSync2 } from "child_process";
199
207
  import path4 from "path";
200
208
  var EMPLOYEES_PATH;
@@ -262,7 +270,7 @@ var init_provider_table = __esm({
262
270
  });
263
271
 
264
272
  // src/lib/intercom-queue.ts
265
- import { readFileSync as readFileSync4, writeFileSync, renameSync as renameSync2, existsSync as existsSync5, mkdirSync } from "fs";
273
+ import { readFileSync as readFileSync5, writeFileSync, renameSync as renameSync2, existsSync as existsSync5, mkdirSync } from "fs";
266
274
  import path6 from "path";
267
275
  import os4 from "os";
268
276
  var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
@@ -276,7 +284,7 @@ var init_intercom_queue = __esm({
276
284
  });
277
285
 
278
286
  // src/lib/license.ts
279
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
287
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
280
288
  import { randomUUID } from "crypto";
281
289
  import path7 from "path";
282
290
  import { jwtVerify, importSPKI } from "jose";
@@ -292,7 +300,7 @@ var init_license = __esm({
292
300
  });
293
301
 
294
302
  // src/lib/plan-limits.ts
295
- import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
303
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
296
304
  import path8 from "path";
297
305
  var CACHE_PATH2;
298
306
  var init_plan_limits = __esm({
@@ -364,6 +372,7 @@ var init_tasks_notify = __esm({
364
372
  init_session_key();
365
373
  init_notifications();
366
374
  init_transport();
375
+ init_employees();
367
376
  }
368
377
  });
369
378
 
@@ -19,19 +19,27 @@ var __copyProps = (to, from, except, desc) => {
19
19
  };
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
 
22
+ // src/lib/db-retry.ts
23
+ var init_db_retry = __esm({
24
+ "src/lib/db-retry.ts"() {
25
+ "use strict";
26
+ }
27
+ });
28
+
22
29
  // src/lib/database.ts
23
30
  import { createClient } from "@libsql/client";
24
31
  function getClient() {
25
- if (!_client) {
32
+ if (!_resilientClient) {
26
33
  throw new Error("Database client not initialized. Call initDatabase() first.");
27
34
  }
28
- return _client;
35
+ return _resilientClient;
29
36
  }
30
- var _client;
37
+ var _resilientClient;
31
38
  var init_database = __esm({
32
39
  "src/lib/database.ts"() {
33
40
  "use strict";
34
- _client = null;
41
+ init_db_retry();
42
+ _resilientClient = null;
35
43
  }
36
44
  });
37
45
 
@@ -432,7 +440,7 @@ var init_config = __esm({
432
440
 
433
441
  // src/lib/employees.ts
434
442
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
435
- import { existsSync as existsSync4, symlinkSync, readlinkSync } from "fs";
443
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
436
444
  import { execSync as execSync3 } from "child_process";
437
445
  import path4 from "path";
438
446
  var EMPLOYEES_PATH;
@@ -445,7 +453,7 @@ var init_employees = __esm({
445
453
  });
446
454
 
447
455
  // src/lib/license.ts
448
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
456
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
449
457
  import { randomUUID } from "crypto";
450
458
  import path5 from "path";
451
459
  import { jwtVerify, importSPKI } from "jose";
@@ -468,12 +476,12 @@ var init_license = __esm({
468
476
  });
469
477
 
470
478
  // src/lib/plan-limits.ts
471
- import { readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
479
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
472
480
  import path6 from "path";
473
481
  function getLicenseSync() {
474
482
  try {
475
483
  if (!existsSync6(CACHE_PATH2)) return freeLicense();
476
- const raw = JSON.parse(readFileSync5(CACHE_PATH2, "utf8"));
484
+ const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
477
485
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
478
486
  const parts = raw.token.split(".");
479
487
  if (parts.length !== 3) return freeLicense();
@@ -512,7 +520,7 @@ function assertEmployeeLimitSync(rosterPath) {
512
520
  let count = 0;
513
521
  try {
514
522
  if (existsSync6(filePath)) {
515
- const raw = readFileSync5(filePath, "utf8");
523
+ const raw = readFileSync6(filePath, "utf8");
516
524
  const employees = JSON.parse(raw);
517
525
  count = Array.isArray(employees) ? employees.length : 0;
518
526
  }
@@ -547,7 +555,7 @@ var init_plan_limits = __esm({
547
555
 
548
556
  // src/lib/tmux-routing.ts
549
557
  import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
550
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
558
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
551
559
  import path7 from "path";
552
560
  import os4 from "os";
553
561
  import { fileURLToPath } from "url";
@@ -596,7 +604,7 @@ function extractRootExe(name) {
596
604
  }
597
605
  function getParentExe(sessionKey) {
598
606
  try {
599
- const data = JSON.parse(readFileSync6(path7.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
607
+ const data = JSON.parse(readFileSync7(path7.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
600
608
  return data.parentExe || null;
601
609
  } catch {
602
610
  return null;
@@ -630,7 +638,7 @@ function findFreeInstance(employeeName, exeSession, maxInstances = 10, isAlive =
630
638
  function readDebounceState() {
631
639
  try {
632
640
  if (!existsSync7(DEBOUNCE_FILE)) return {};
633
- return JSON.parse(readFileSync6(DEBOUNCE_FILE, "utf8"));
641
+ return JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
634
642
  } catch {
635
643
  return {};
636
644
  }
@@ -804,7 +812,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
804
812
  const claudeJsonPath = path7.join(os4.homedir(), ".claude.json");
805
813
  let claudeJson = {};
806
814
  try {
807
- claudeJson = JSON.parse(readFileSync6(claudeJsonPath, "utf8"));
815
+ claudeJson = JSON.parse(readFileSync7(claudeJsonPath, "utf8"));
808
816
  } catch {
809
817
  }
810
818
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -822,7 +830,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
822
830
  const settingsPath = path7.join(projSettingsDir, "settings.json");
823
831
  let settings = {};
824
832
  try {
825
- settings = JSON.parse(readFileSync6(settingsPath, "utf8"));
833
+ settings = JSON.parse(readFileSync7(settingsPath, "utf8"));
826
834
  } catch {
827
835
  }
828
836
  const perms = settings.permissions ?? {};
@@ -1158,7 +1166,7 @@ async function markFailed(messageId, reason) {
1158
1166
 
1159
1167
  // src/adapters/claude/active-agent.ts
1160
1168
  init_config();
1161
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync, readdirSync } from "fs";
1169
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync, readdirSync } from "fs";
1162
1170
  import { execSync as execSync5 } from "child_process";
1163
1171
  import path8 from "path";
1164
1172
 
@@ -1174,7 +1182,7 @@ function getMarkerPath() {
1174
1182
  function getActiveAgent() {
1175
1183
  try {
1176
1184
  const markerPath = getMarkerPath();
1177
- const raw = readFileSync7(markerPath, "utf8");
1185
+ const raw = readFileSync8(markerPath, "utf8");
1178
1186
  const data = JSON.parse(raw);
1179
1187
  if (data.agentId) {
1180
1188
  if (data.startedAt) {