@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
package/dist/index.js CHANGED
@@ -359,6 +359,61 @@ var init_intercom_queue = __esm({
359
359
  }
360
360
  });
361
361
 
362
+ // src/lib/db-retry.ts
363
+ function isBusyError(err) {
364
+ if (err instanceof Error) {
365
+ const msg = err.message.toLowerCase();
366
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
367
+ }
368
+ return false;
369
+ }
370
+ function delay(ms) {
371
+ return new Promise((resolve) => setTimeout(resolve, ms));
372
+ }
373
+ async function retryOnBusy(fn, label) {
374
+ let lastError;
375
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
376
+ try {
377
+ return await fn();
378
+ } catch (err) {
379
+ lastError = err;
380
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
381
+ throw err;
382
+ }
383
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
384
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
385
+ process.stderr.write(
386
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
387
+ `
388
+ );
389
+ await delay(backoff + jitter);
390
+ }
391
+ }
392
+ throw lastError;
393
+ }
394
+ function wrapWithRetry(client) {
395
+ return new Proxy(client, {
396
+ get(target, prop, receiver) {
397
+ if (prop === "execute") {
398
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
399
+ }
400
+ if (prop === "batch") {
401
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
402
+ }
403
+ return Reflect.get(target, prop, receiver);
404
+ }
405
+ });
406
+ }
407
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
408
+ var init_db_retry = __esm({
409
+ "src/lib/db-retry.ts"() {
410
+ "use strict";
411
+ MAX_RETRIES = 3;
412
+ BASE_DELAY_MS = 200;
413
+ MAX_JITTER_MS = 300;
414
+ }
415
+ });
416
+
362
417
  // src/lib/database.ts
363
418
  var database_exports = {};
364
419
  __export(database_exports, {
@@ -366,6 +421,7 @@ __export(database_exports, {
366
421
  disposeTurso: () => disposeTurso,
367
422
  ensureSchema: () => ensureSchema,
368
423
  getClient: () => getClient,
424
+ getRawClient: () => getRawClient,
369
425
  initDatabase: () => initDatabase,
370
426
  initTurso: () => initTurso,
371
427
  isInitialized: () => isInitialized
@@ -375,6 +431,7 @@ async function initDatabase(config2) {
375
431
  if (_client) {
376
432
  _client.close();
377
433
  _client = null;
434
+ _resilientClient = null;
378
435
  }
379
436
  const opts = {
380
437
  url: `file:${config2.dbPath}`
@@ -383,20 +440,27 @@ async function initDatabase(config2) {
383
440
  opts.encryptionKey = config2.encryptionKey;
384
441
  }
385
442
  _client = createClient(opts);
443
+ _resilientClient = wrapWithRetry(_client);
386
444
  }
387
445
  function isInitialized() {
388
446
  return _client !== null;
389
447
  }
390
448
  function getClient() {
449
+ if (!_resilientClient) {
450
+ throw new Error("Database client not initialized. Call initDatabase() first.");
451
+ }
452
+ return _resilientClient;
453
+ }
454
+ function getRawClient() {
391
455
  if (!_client) {
392
456
  throw new Error("Database client not initialized. Call initDatabase() first.");
393
457
  }
394
458
  return _client;
395
459
  }
396
460
  async function ensureSchema() {
397
- const client = getClient();
461
+ const client = getRawClient();
398
462
  await client.execute("PRAGMA journal_mode = WAL");
399
- await client.execute("PRAGMA busy_timeout = 5000");
463
+ await client.execute("PRAGMA busy_timeout = 30000");
400
464
  try {
401
465
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
402
466
  } catch {
@@ -1189,13 +1253,16 @@ async function disposeDatabase() {
1189
1253
  if (_client) {
1190
1254
  _client.close();
1191
1255
  _client = null;
1256
+ _resilientClient = null;
1192
1257
  }
1193
1258
  }
1194
- var _client, initTurso, disposeTurso;
1259
+ var _client, _resilientClient, initTurso, disposeTurso;
1195
1260
  var init_database = __esm({
1196
1261
  "src/lib/database.ts"() {
1197
1262
  "use strict";
1263
+ init_db_retry();
1198
1264
  _client = null;
1265
+ _resilientClient = null;
1199
1266
  initTurso = initDatabase;
1200
1267
  disposeTurso = disposeDatabase;
1201
1268
  }
@@ -1446,20 +1513,38 @@ var init_config = __esm({
1446
1513
 
1447
1514
  // src/lib/employees.ts
1448
1515
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1449
- import { existsSync as existsSync4, symlinkSync, readlinkSync } from "fs";
1516
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
1450
1517
  import { execSync as execSync4 } from "child_process";
1451
1518
  import path5 from "path";
1452
- var EMPLOYEES_PATH;
1519
+ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
1520
+ if (!existsSync4(employeesPath)) return [];
1521
+ try {
1522
+ return JSON.parse(readFileSync4(employeesPath, "utf-8"));
1523
+ } catch {
1524
+ return [];
1525
+ }
1526
+ }
1527
+ function getEmployee(employees, name) {
1528
+ return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
1529
+ }
1530
+ function isMultiInstance(agentName, employees) {
1531
+ const roster = employees ?? loadEmployeesSync();
1532
+ const emp = getEmployee(roster, agentName);
1533
+ if (!emp) return false;
1534
+ return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
1535
+ }
1536
+ var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
1453
1537
  var init_employees = __esm({
1454
1538
  "src/lib/employees.ts"() {
1455
1539
  "use strict";
1456
1540
  init_config();
1457
1541
  EMPLOYEES_PATH = path5.join(EXE_AI_DIR, "exe-employees.json");
1542
+ MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
1458
1543
  }
1459
1544
  });
1460
1545
 
1461
1546
  // src/lib/license.ts
1462
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
1547
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
1463
1548
  import { randomUUID as randomUUID2 } from "crypto";
1464
1549
  import path6 from "path";
1465
1550
  import { jwtVerify, importSPKI } from "jose";
@@ -1482,12 +1567,12 @@ var init_license = __esm({
1482
1567
  });
1483
1568
 
1484
1569
  // src/lib/plan-limits.ts
1485
- import { readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
1570
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
1486
1571
  import path7 from "path";
1487
1572
  function getLicenseSync() {
1488
1573
  try {
1489
1574
  if (!existsSync6(CACHE_PATH2)) return freeLicense();
1490
- const raw = JSON.parse(readFileSync5(CACHE_PATH2, "utf8"));
1575
+ const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
1491
1576
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
1492
1577
  const parts = raw.token.split(".");
1493
1578
  if (parts.length !== 3) return freeLicense();
@@ -1526,7 +1611,7 @@ function assertEmployeeLimitSync(rosterPath) {
1526
1611
  let count = 0;
1527
1612
  try {
1528
1613
  if (existsSync6(filePath)) {
1529
- const raw = readFileSync5(filePath, "utf8");
1614
+ const raw = readFileSync6(filePath, "utf8");
1530
1615
  const employees = JSON.parse(raw);
1531
1616
  count = Array.isArray(employees) ? employees.length : 0;
1532
1617
  }
@@ -1564,7 +1649,7 @@ import crypto from "crypto";
1564
1649
  import path8 from "path";
1565
1650
  import os5 from "os";
1566
1651
  import {
1567
- readFileSync as readFileSync6,
1652
+ readFileSync as readFileSync7,
1568
1653
  readdirSync,
1569
1654
  unlinkSync,
1570
1655
  existsSync as existsSync7,
@@ -1650,7 +1735,7 @@ import crypto3 from "crypto";
1650
1735
  import path9 from "path";
1651
1736
  import { execSync as execSync5 } from "child_process";
1652
1737
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
1653
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
1738
+ import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
1654
1739
  async function writeCheckpoint(input) {
1655
1740
  const client = getClient();
1656
1741
  const row = await resolveTask(client, input.taskId);
@@ -2027,7 +2112,7 @@ async function ensureGitignoreExe(baseDir) {
2027
2112
  const gitignorePath = path9.join(baseDir, ".gitignore");
2028
2113
  try {
2029
2114
  if (existsSync8(gitignorePath)) {
2030
- const content = readFileSync7(gitignorePath, "utf-8");
2115
+ const content = readFileSync8(gitignorePath, "utf-8");
2031
2116
  if (/^\/?exe\/?$/m.test(content)) return;
2032
2117
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
2033
2118
  } else {
@@ -2403,7 +2488,7 @@ async function dispatchTaskToEmployee(input) {
2403
2488
  } else {
2404
2489
  const projectDir = input.projectDir ?? process.cwd();
2405
2490
  const result = ensureEmployee(input.assignedTo, exeSession, projectDir, {
2406
- autoInstance: input.assignedTo === "tom" || input.assignedTo === "sasha"
2491
+ autoInstance: isMultiInstance(input.assignedTo)
2407
2492
  });
2408
2493
  if (result.status === "failed") {
2409
2494
  process.stderr.write(
@@ -2438,6 +2523,7 @@ var init_tasks_notify = __esm({
2438
2523
  init_session_key();
2439
2524
  init_notifications();
2440
2525
  init_transport();
2526
+ init_employees();
2441
2527
  }
2442
2528
  });
2443
2529
 
@@ -3273,7 +3359,7 @@ __export(tmux_routing_exports, {
3273
3359
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
3274
3360
  });
3275
3361
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
3276
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync } from "fs";
3362
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync } from "fs";
3277
3363
  import path14 from "path";
3278
3364
  import os6 from "os";
3279
3365
  import { fileURLToPath } from "url";
@@ -3340,7 +3426,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
3340
3426
  }
3341
3427
  function getParentExe(sessionKey) {
3342
3428
  try {
3343
- const data = JSON.parse(readFileSync8(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3429
+ const data = JSON.parse(readFileSync9(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3344
3430
  return data.parentExe || null;
3345
3431
  } catch {
3346
3432
  return null;
@@ -3348,7 +3434,7 @@ function getParentExe(sessionKey) {
3348
3434
  }
3349
3435
  function getDispatchedBy(sessionKey) {
3350
3436
  try {
3351
- const data = JSON.parse(readFileSync8(
3437
+ const data = JSON.parse(readFileSync9(
3352
3438
  path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
3353
3439
  "utf8"
3354
3440
  ));
@@ -3411,7 +3497,7 @@ async function verifyPaneAtCapacity(sessionName) {
3411
3497
  function readDebounceState() {
3412
3498
  try {
3413
3499
  if (!existsSync10(DEBOUNCE_FILE)) return {};
3414
- return JSON.parse(readFileSync8(DEBOUNCE_FILE, "utf8"));
3500
+ return JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
3415
3501
  } catch {
3416
3502
  return {};
3417
3503
  }
@@ -3611,7 +3697,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3611
3697
  const claudeJsonPath = path14.join(os6.homedir(), ".claude.json");
3612
3698
  let claudeJson = {};
3613
3699
  try {
3614
- claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
3700
+ claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
3615
3701
  } catch {
3616
3702
  }
3617
3703
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -3629,7 +3715,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3629
3715
  const settingsPath = path14.join(projSettingsDir, "settings.json");
3630
3716
  let settings = {};
3631
3717
  try {
3632
- settings = JSON.parse(readFileSync8(settingsPath, "utf8"));
3718
+ settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
3633
3719
  } catch {
3634
3720
  }
3635
3721
  const perms = settings.permissions ?? {};
@@ -3936,7 +4022,7 @@ function listShards() {
3936
4022
  }
3937
4023
  async function ensureShardSchema(client) {
3938
4024
  await client.execute("PRAGMA journal_mode = WAL");
3939
- await client.execute("PRAGMA busy_timeout = 5000");
4025
+ await client.execute("PRAGMA busy_timeout = 30000");
3940
4026
  try {
3941
4027
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
3942
4028
  } catch {
@@ -4588,8 +4674,8 @@ function findContainingChunk(filePath, snippet) {
4588
4674
  try {
4589
4675
  const ext = filePath.split(".").pop()?.toLowerCase();
4590
4676
  if (ext !== "ts" && ext !== "tsx" && ext !== "js" && ext !== "jsx") return "";
4591
- const { readFileSync: readFileSync12 } = __require("fs");
4592
- const source = readFileSync12(filePath, "utf8");
4677
+ const { readFileSync: readFileSync13 } = __require("fs");
4678
+ const source = readFileSync13(filePath, "utf8");
4593
4679
  const lines = source.split("\n");
4594
4680
  const lowerSnippet = snippet.toLowerCase().slice(0, 80);
4595
4681
  let matchLine = -1;
@@ -5161,7 +5247,7 @@ var init_crm_bridge = __esm({
5161
5247
  import net from "net";
5162
5248
  import { spawn } from "child_process";
5163
5249
  import { randomUUID as randomUUID5 } from "crypto";
5164
- import { existsSync as existsSync13, unlinkSync as unlinkSync4, readFileSync as readFileSync9, openSync, closeSync, statSync } from "fs";
5250
+ import { existsSync as existsSync13, unlinkSync as unlinkSync4, readFileSync as readFileSync10, openSync, closeSync, statSync } from "fs";
5165
5251
  import path17 from "path";
5166
5252
  import { fileURLToPath as fileURLToPath2 } from "url";
5167
5253
  function handleData(chunk) {
@@ -5186,7 +5272,7 @@ function handleData(chunk) {
5186
5272
  function cleanupStaleFiles() {
5187
5273
  if (existsSync13(PID_PATH)) {
5188
5274
  try {
5189
- const pid = parseInt(readFileSync9(PID_PATH, "utf8").trim(), 10);
5275
+ const pid = parseInt(readFileSync10(PID_PATH, "utf8").trim(), 10);
5190
5276
  if (pid > 0) {
5191
5277
  try {
5192
5278
  process.kill(pid, 0);
@@ -5334,11 +5420,11 @@ async function connectEmbedDaemon() {
5334
5420
  }
5335
5421
  }
5336
5422
  const start = Date.now();
5337
- let delay = 100;
5423
+ let delay2 = 100;
5338
5424
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
5339
- await new Promise((r) => setTimeout(r, delay));
5425
+ await new Promise((r) => setTimeout(r, delay2));
5340
5426
  if (await connectToSocket()) return true;
5341
- delay = Math.min(delay * 2, 3e3);
5427
+ delay2 = Math.min(delay2 * 2, 3e3);
5342
5428
  }
5343
5429
  return false;
5344
5430
  }
@@ -5394,7 +5480,7 @@ function killAndRespawnDaemon() {
5394
5480
  process.stderr.write("[exed-client] Killing daemon for restart...\n");
5395
5481
  if (existsSync13(PID_PATH)) {
5396
5482
  try {
5397
- const pid = parseInt(readFileSync9(PID_PATH, "utf8").trim(), 10);
5483
+ const pid = parseInt(readFileSync10(PID_PATH, "utf8").trim(), 10);
5398
5484
  if (pid > 0) {
5399
5485
  try {
5400
5486
  process.kill(pid, "SIGKILL");
@@ -5430,11 +5516,11 @@ async function embedViaClient(text, priority = "high") {
5430
5516
  `);
5431
5517
  killAndRespawnDaemon();
5432
5518
  const start = Date.now();
5433
- let delay = 200;
5519
+ let delay2 = 200;
5434
5520
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
5435
- await new Promise((r) => setTimeout(r, delay));
5521
+ await new Promise((r) => setTimeout(r, delay2));
5436
5522
  if (await connectToSocket()) break;
5437
- delay = Math.min(delay * 2, 3e3);
5523
+ delay2 = Math.min(delay2 * 2, 3e3);
5438
5524
  }
5439
5525
  if (!_connected) return null;
5440
5526
  }
@@ -5446,11 +5532,11 @@ async function embedViaClient(text, priority = "high") {
5446
5532
  `);
5447
5533
  killAndRespawnDaemon();
5448
5534
  const start = Date.now();
5449
- let delay = 200;
5535
+ let delay2 = 200;
5450
5536
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
5451
- await new Promise((r) => setTimeout(r, delay));
5537
+ await new Promise((r) => setTimeout(r, delay2));
5452
5538
  if (await connectToSocket()) break;
5453
- delay = Math.min(delay * 2, 3e3);
5539
+ delay2 = Math.min(delay2 * 2, 3e3);
5454
5540
  }
5455
5541
  if (!_connected) return null;
5456
5542
  const retry = await sendRequest([text], priority);
@@ -5694,13 +5780,13 @@ __export(whatsapp_accounts_exports, {
5694
5780
  getDefaultAccount: () => getDefaultAccount,
5695
5781
  loadAccounts: () => loadAccounts
5696
5782
  });
5697
- import { readFileSync as readFileSync10 } from "fs";
5783
+ import { readFileSync as readFileSync11 } from "fs";
5698
5784
  import { join as join2 } from "path";
5699
5785
  import { homedir as homedir2 } from "os";
5700
5786
  function loadAccounts() {
5701
5787
  if (cachedAccounts !== null) return cachedAccounts;
5702
5788
  try {
5703
- const raw = readFileSync10(CONFIG_PATH2, "utf8");
5789
+ const raw = readFileSync11(CONFIG_PATH2, "utf8");
5704
5790
  const parsed = JSON.parse(raw);
5705
5791
  if (!Array.isArray(parsed)) {
5706
5792
  console.warn("[whatsapp] Config is not an array, ignoring");
@@ -5876,7 +5962,7 @@ async function deliverLocalMessage(messageId) {
5876
5962
  return true;
5877
5963
  } catch {
5878
5964
  const newRetryCount = msg.retryCount + 1;
5879
- if (newRetryCount >= MAX_RETRIES) {
5965
+ if (newRetryCount >= MAX_RETRIES2) {
5880
5966
  await markFailed(messageId, "session unavailable after 10 retries");
5881
5967
  } else {
5882
5968
  await client.execute({
@@ -5965,7 +6051,7 @@ async function retryPendingMessages() {
5965
6051
  sql: `SELECT * FROM messages
5966
6052
  WHERE status = 'pending' AND retry_count < ?
5967
6053
  ORDER BY id`,
5968
- args: [MAX_RETRIES]
6054
+ args: [MAX_RETRIES2]
5969
6055
  });
5970
6056
  let delivered = 0;
5971
6057
  for (const row of result.rows) {
@@ -5978,13 +6064,13 @@ async function retryPendingMessages() {
5978
6064
  }
5979
6065
  return delivered;
5980
6066
  }
5981
- var MAX_RETRIES, _wsClientSend;
6067
+ var MAX_RETRIES2, _wsClientSend;
5982
6068
  var init_messaging = __esm({
5983
6069
  "src/lib/messaging.ts"() {
5984
6070
  "use strict";
5985
6071
  init_database();
5986
6072
  init_tmux_routing();
5987
- MAX_RETRIES = 10;
6073
+ MAX_RETRIES2 = 10;
5988
6074
  _wsClientSend = null;
5989
6075
  }
5990
6076
  });
@@ -7226,12 +7312,14 @@ var DEFAULT_BLOOM_CONFIG = {
7226
7312
  },
7227
7313
  tierRules: {
7228
7314
  junior: {
7229
- eligible: ["tom"],
7315
+ eligible: [],
7316
+ // resolved dynamically from roster (Principal Engineer role)
7230
7317
  reviewRequired: false,
7231
7318
  manualOnly: false
7232
7319
  },
7233
7320
  standard: {
7234
- eligible: ["tom"],
7321
+ eligible: [],
7322
+ // resolved dynamically from roster (Principal Engineer role)
7235
7323
  reviewRequired: false,
7236
7324
  manualOnly: false
7237
7325
  },
@@ -8352,8 +8440,8 @@ async function retryWithBackoff(fn, config2 = {}) {
8352
8440
  } catch (err) {
8353
8441
  lastError = err instanceof Error ? err : new Error(String(err));
8354
8442
  if (attempt < maxRetries) {
8355
- const delay = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
8356
- await new Promise((r) => setTimeout(r, delay));
8443
+ const delay2 = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
8444
+ await new Promise((r) => setTimeout(r, delay2));
8357
8445
  }
8358
8446
  }
8359
8447
  }
@@ -11850,7 +11938,7 @@ async function ensureCRMContact(info) {
11850
11938
  }
11851
11939
 
11852
11940
  // src/automation/trigger-engine.ts
11853
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
11941
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
11854
11942
  import { randomUUID as randomUUID14 } from "crypto";
11855
11943
  import path19 from "path";
11856
11944
  import os7 from "os";
@@ -11909,7 +11997,7 @@ function evaluateConditions(conditions, record) {
11909
11997
  function loadTriggers(project) {
11910
11998
  if (!existsSync14(TRIGGERS_PATH)) return [];
11911
11999
  try {
11912
- const raw = readFileSync11(TRIGGERS_PATH, "utf-8");
12000
+ const raw = readFileSync12(TRIGGERS_PATH, "utf-8");
11913
12001
  const all = JSON.parse(raw);
11914
12002
  if (!Array.isArray(all)) return [];
11915
12003
  if (project) {