@askexenow/exe-os 0.9.0 → 0.9.2

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.
@@ -3,6 +3,12 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
6
12
  var __esm = (fn, res) => function __init() {
7
13
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
14
  };
@@ -547,6 +553,14 @@ var init_agent_config = __esm({
547
553
  });
548
554
 
549
555
  // src/lib/intercom-queue.ts
556
+ var intercom_queue_exports = {};
557
+ __export(intercom_queue_exports, {
558
+ clearQueueForAgent: () => clearQueueForAgent,
559
+ drainForSession: () => drainForSession,
560
+ drainQueue: () => drainQueue,
561
+ queueIntercom: () => queueIntercom,
562
+ readQueue: () => readQueue
563
+ });
550
564
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
551
565
  import path4 from "path";
552
566
  import os3 from "os";
@@ -585,11 +599,80 @@ function queueIntercom(targetSession, reason) {
585
599
  }
586
600
  writeQueue(queue);
587
601
  }
588
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
602
+ function drainQueue(isSessionBusy2, sendKeys) {
603
+ const queue = readQueue();
604
+ if (queue.length === 0) return { drained: 0, failed: 0 };
605
+ const remaining = [];
606
+ let drained = 0;
607
+ let failed = 0;
608
+ for (const item of queue) {
609
+ const age = Date.now() - new Date(item.queuedAt).getTime();
610
+ if (age > TTL_MS) {
611
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
612
+ failed++;
613
+ continue;
614
+ }
615
+ try {
616
+ if (!isSessionBusy2(item.targetSession)) {
617
+ const success = sendKeys(item.targetSession);
618
+ if (success) {
619
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
620
+ drained++;
621
+ continue;
622
+ }
623
+ }
624
+ } catch {
625
+ }
626
+ item.attempts++;
627
+ if (item.attempts >= MAX_RETRIES) {
628
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES} retries exhausted, reason: ${item.reason})`);
629
+ failed++;
630
+ continue;
631
+ }
632
+ remaining.push(item);
633
+ }
634
+ writeQueue(remaining);
635
+ return { drained, failed };
636
+ }
637
+ function drainForSession(targetSession, sendKeys) {
638
+ const queue = readQueue();
639
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
640
+ if (match < 0) return false;
641
+ const success = sendKeys(targetSession);
642
+ if (success) {
643
+ queue.splice(match, 1);
644
+ writeQueue(queue);
645
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
646
+ return true;
647
+ }
648
+ return false;
649
+ }
650
+ function clearQueueForAgent(agentName) {
651
+ const queue = readQueue();
652
+ const before = queue.length;
653
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
654
+ if (filtered.length < before) {
655
+ writeQueue(filtered);
656
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
657
+ }
658
+ }
659
+ function logQueue(msg) {
660
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
661
+ `;
662
+ process.stderr.write(`[intercom-queue] ${msg}
663
+ `);
664
+ try {
665
+ const { appendFileSync: appendFileSync2 } = __require("fs");
666
+ appendFileSync2(INTERCOM_LOG, line);
667
+ } catch {
668
+ }
669
+ }
670
+ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
589
671
  var init_intercom_queue = __esm({
590
672
  "src/lib/intercom-queue.ts"() {
591
673
  "use strict";
592
674
  QUEUE_PATH = path4.join(os3.homedir(), ".exe-os", "intercom-queue.json");
675
+ MAX_RETRIES = 5;
593
676
  TTL_MS = 60 * 60 * 1e3;
594
677
  INTERCOM_LOG = path4.join(os3.homedir(), ".exe-os", "intercom.log");
595
678
  }
@@ -608,18 +691,18 @@ function delay(ms) {
608
691
  }
609
692
  async function retryOnBusy(fn, label) {
610
693
  let lastError;
611
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
694
+ for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
612
695
  try {
613
696
  return await fn();
614
697
  } catch (err) {
615
698
  lastError = err;
616
- if (!isBusyError(err) || attempt === MAX_RETRIES) {
699
+ if (!isBusyError(err) || attempt === MAX_RETRIES2) {
617
700
  throw err;
618
701
  }
619
702
  const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
620
703
  const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
621
704
  process.stderr.write(
622
- `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
705
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES2} \u2014 waiting ${backoff + jitter}ms
623
706
  `
624
707
  );
625
708
  await delay(backoff + jitter);
@@ -640,11 +723,11 @@ function wrapWithRetry(client) {
640
723
  }
641
724
  });
642
725
  }
643
- var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
726
+ var MAX_RETRIES2, BASE_DELAY_MS, MAX_JITTER_MS;
644
727
  var init_db_retry = __esm({
645
728
  "src/lib/db-retry.ts"() {
646
729
  "use strict";
647
- MAX_RETRIES = 3;
730
+ MAX_RETRIES2 = 3;
648
731
  BASE_DELAY_MS = 200;
649
732
  MAX_JITTER_MS = 300;
650
733
  }
@@ -2451,6 +2534,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
2451
2534
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
2452
2535
  } catch {
2453
2536
  }
2537
+ if (input.status === "done" || input.status === "cancelled") {
2538
+ try {
2539
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
2540
+ clearQueueForAgent2(String(row.assigned_to));
2541
+ } catch {
2542
+ }
2543
+ }
2454
2544
  try {
2455
2545
  await writeCheckpoint({
2456
2546
  taskId,
@@ -2025,7 +2025,7 @@ function isMainModule(importMetaUrl) {
2025
2025
  }
2026
2026
 
2027
2027
  // src/bin/exe-doctor.ts
2028
- import { existsSync as existsSync6 } from "fs";
2028
+ import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
2029
2029
  import { spawn } from "child_process";
2030
2030
  import path6 from "path";
2031
2031
  import { randomUUID as randomUUID2 } from "crypto";
@@ -2437,6 +2437,46 @@ async function auditOrphanedProjects(client) {
2437
2437
  }
2438
2438
  return orphans;
2439
2439
  }
2440
+ function auditHookHealth() {
2441
+ const logPath = path6.join(
2442
+ process.env.HOME ?? process.env.USERPROFILE ?? "",
2443
+ ".exe-os",
2444
+ "logs",
2445
+ "hooks.log"
2446
+ );
2447
+ if (!existsSync6(logPath)) {
2448
+ return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
2449
+ }
2450
+ let content;
2451
+ try {
2452
+ content = readFileSync3(logPath, "utf-8");
2453
+ } catch {
2454
+ return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
2455
+ }
2456
+ const lines = content.split("\n").filter(Boolean);
2457
+ const totalLines = lines.length;
2458
+ const recent = lines.slice(-200);
2459
+ const oneHourAgo = new Date(Date.now() - 36e5).toISOString();
2460
+ let errorsLastHour = 0;
2461
+ const patternCounts = /* @__PURE__ */ new Map();
2462
+ for (const line of recent) {
2463
+ const isError = /error|Error|ERR|FAIL|throw|exception|TypeError|ReferenceError|SyntaxError/i.test(line);
2464
+ if (!isError) continue;
2465
+ const tsMatch = line.match(/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/);
2466
+ if (tsMatch && tsMatch[1] >= oneHourAgo) {
2467
+ errorsLastHour++;
2468
+ } else if (!tsMatch) {
2469
+ errorsLastHour++;
2470
+ }
2471
+ const patternMatch = line.match(/((?:TypeError|ReferenceError|SyntaxError|Error):[^\n]{0,80})/);
2472
+ if (patternMatch) {
2473
+ const p = patternMatch[1];
2474
+ patternCounts.set(p, (patternCounts.get(p) ?? 0) + 1);
2475
+ }
2476
+ }
2477
+ const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
2478
+ return { logExists: true, totalLines, errorsLastHour, topPatterns };
2479
+ }
2440
2480
  async function runAudit(client, flags) {
2441
2481
  const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, conflicts] = await Promise.all([
2442
2482
  auditStats(client, flags),
@@ -2448,7 +2488,8 @@ async function runAudit(client, flags) {
2448
2488
  detectConflicts(client, flags.project, flags.agent)
2449
2489
  ]);
2450
2490
  const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
2451
- return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts };
2491
+ const hookHealth = auditHookHealth();
2492
+ return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth };
2452
2493
  }
2453
2494
  function indicator(value, warn) {
2454
2495
  if (value === 0) return "\u{1F7E2}";
@@ -2516,6 +2557,17 @@ function formatReport(report, flags) {
2516
2557
  } else {
2517
2558
  lines.push("\u{1F7E2} Conflicts: none detected");
2518
2559
  }
2560
+ const hh = report.hookHealth;
2561
+ if (!hh.logExists) {
2562
+ lines.push("\u{1F7E0} Hook logs: no log file (run installer to enable stderr capture)");
2563
+ } else if (hh.errorsLastHour === 0) {
2564
+ lines.push(`\u{1F7E2} Hook logs: ${fmtNum(hh.totalLines)} lines, 0 errors in last hour`);
2565
+ } else {
2566
+ lines.push(`\u{1F534} Hook logs: ${fmtNum(hh.errorsLastHour)} errors in last hour (${fmtNum(hh.totalLines)} total lines)`);
2567
+ for (const p of hh.topPatterns) {
2568
+ lines.push(` ${p.count}x: ${p.pattern}`);
2569
+ }
2570
+ }
2519
2571
  lines.push("");
2520
2572
  if (flags.verbose) {
2521
2573
  if (report.duplicates.length > 0) {
@@ -2749,6 +2801,7 @@ export {
2749
2801
  auditBloated,
2750
2802
  auditDuplicates,
2751
2803
  auditFts,
2804
+ auditHookHealth,
2752
2805
  auditNullVectors,
2753
2806
  auditOrphanedProjects,
2754
2807
  auditStats,
@@ -6448,6 +6448,14 @@ var init_agent_config = __esm({
6448
6448
  });
6449
6449
 
6450
6450
  // src/lib/intercom-queue.ts
6451
+ var intercom_queue_exports = {};
6452
+ __export(intercom_queue_exports, {
6453
+ clearQueueForAgent: () => clearQueueForAgent,
6454
+ drainForSession: () => drainForSession,
6455
+ drainQueue: () => drainQueue,
6456
+ queueIntercom: () => queueIntercom,
6457
+ readQueue: () => readQueue
6458
+ });
6451
6459
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, renameSync as renameSync3, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
6452
6460
  import path10 from "path";
6453
6461
  import os7 from "os";
@@ -6486,11 +6494,80 @@ function queueIntercom(targetSession, reason) {
6486
6494
  }
6487
6495
  writeQueue(queue);
6488
6496
  }
6489
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
6497
+ function drainQueue(isSessionBusy2, sendKeys) {
6498
+ const queue = readQueue();
6499
+ if (queue.length === 0) return { drained: 0, failed: 0 };
6500
+ const remaining = [];
6501
+ let drained = 0;
6502
+ let failed = 0;
6503
+ for (const item of queue) {
6504
+ const age = Date.now() - new Date(item.queuedAt).getTime();
6505
+ if (age > TTL_MS) {
6506
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
6507
+ failed++;
6508
+ continue;
6509
+ }
6510
+ try {
6511
+ if (!isSessionBusy2(item.targetSession)) {
6512
+ const success = sendKeys(item.targetSession);
6513
+ if (success) {
6514
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
6515
+ drained++;
6516
+ continue;
6517
+ }
6518
+ }
6519
+ } catch {
6520
+ }
6521
+ item.attempts++;
6522
+ if (item.attempts >= MAX_RETRIES2) {
6523
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
6524
+ failed++;
6525
+ continue;
6526
+ }
6527
+ remaining.push(item);
6528
+ }
6529
+ writeQueue(remaining);
6530
+ return { drained, failed };
6531
+ }
6532
+ function drainForSession(targetSession, sendKeys) {
6533
+ const queue = readQueue();
6534
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
6535
+ if (match < 0) return false;
6536
+ const success = sendKeys(targetSession);
6537
+ if (success) {
6538
+ queue.splice(match, 1);
6539
+ writeQueue(queue);
6540
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
6541
+ return true;
6542
+ }
6543
+ return false;
6544
+ }
6545
+ function clearQueueForAgent(agentName) {
6546
+ const queue = readQueue();
6547
+ const before = queue.length;
6548
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
6549
+ if (filtered.length < before) {
6550
+ writeQueue(filtered);
6551
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
6552
+ }
6553
+ }
6554
+ function logQueue(msg) {
6555
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
6556
+ `;
6557
+ process.stderr.write(`[intercom-queue] ${msg}
6558
+ `);
6559
+ try {
6560
+ const { appendFileSync: appendFileSync2 } = __require("fs");
6561
+ appendFileSync2(INTERCOM_LOG, line);
6562
+ } catch {
6563
+ }
6564
+ }
6565
+ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
6490
6566
  var init_intercom_queue = __esm({
6491
6567
  "src/lib/intercom-queue.ts"() {
6492
6568
  "use strict";
6493
6569
  QUEUE_PATH = path10.join(os7.homedir(), ".exe-os", "intercom-queue.json");
6570
+ MAX_RETRIES2 = 5;
6494
6571
  TTL_MS = 60 * 60 * 1e3;
6495
6572
  INTERCOM_LOG = path10.join(os7.homedir(), ".exe-os", "intercom.log");
6496
6573
  }
@@ -7176,6 +7253,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
7176
7253
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
7177
7254
  } catch {
7178
7255
  }
7256
+ if (input.status === "done" || input.status === "cancelled") {
7257
+ try {
7258
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
7259
+ clearQueueForAgent2(String(row.assigned_to));
7260
+ } catch {
7261
+ }
7262
+ }
7179
7263
  try {
7180
7264
  await writeCheckpoint({
7181
7265
  taskId,
@@ -9415,7 +9499,7 @@ async function deliverLocalMessage(messageId) {
9415
9499
  return true;
9416
9500
  } catch {
9417
9501
  const newRetryCount = msg.retryCount + 1;
9418
- if (newRetryCount >= MAX_RETRIES2) {
9502
+ if (newRetryCount >= MAX_RETRIES3) {
9419
9503
  await markFailed(messageId, "session unavailable after 10 retries");
9420
9504
  } else {
9421
9505
  await client.execute({
@@ -9504,7 +9588,7 @@ async function retryPendingMessages() {
9504
9588
  sql: `SELECT * FROM messages
9505
9589
  WHERE status = 'pending' AND retry_count < ?
9506
9590
  ORDER BY id`,
9507
- args: [MAX_RETRIES2]
9591
+ args: [MAX_RETRIES3]
9508
9592
  });
9509
9593
  let delivered = 0;
9510
9594
  for (const row of result.rows) {
@@ -9517,13 +9601,13 @@ async function retryPendingMessages() {
9517
9601
  }
9518
9602
  return delivered;
9519
9603
  }
9520
- var MAX_RETRIES2, _wsClientSend;
9604
+ var MAX_RETRIES3, _wsClientSend;
9521
9605
  var init_messaging = __esm({
9522
9606
  "src/lib/messaging.ts"() {
9523
9607
  "use strict";
9524
9608
  init_database();
9525
9609
  init_tmux_routing();
9526
- MAX_RETRIES2 = 10;
9610
+ MAX_RETRIES3 = 10;
9527
9611
  _wsClientSend = null;
9528
9612
  }
9529
9613
  });
@@ -1162,6 +1162,10 @@ async function cleanSettingsJsonMcp(settingsPath) {
1162
1162
  }
1163
1163
  async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1164
1164
  const settingsPath = path9.join(homeDir, ".claude", "settings.json");
1165
+ const logsDir = path9.join(homeDir, ".exe-os", "logs");
1166
+ const hookLogPath = path9.join(logsDir, "hooks.log");
1167
+ const logSuffix = ` 2>> "${hookLogPath}"`;
1168
+ await mkdir3(logsDir, { recursive: true });
1165
1169
  let settings = {};
1166
1170
  if (existsSync9(settingsPath)) {
1167
1171
  try {
@@ -1185,11 +1189,11 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1185
1189
  hooks: [
1186
1190
  {
1187
1191
  type: "command",
1188
- command: `node "${path9.join(packageRoot, "dist", "hooks", "ingest.js")}"`
1192
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
1189
1193
  },
1190
1194
  {
1191
1195
  type: "command",
1192
- command: `node "${path9.join(packageRoot, "dist", "hooks", "error-recall.js")}"`
1196
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
1193
1197
  }
1194
1198
  ]
1195
1199
  },
@@ -1201,7 +1205,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1201
1205
  hooks: [
1202
1206
  {
1203
1207
  type: "command",
1204
- command: `node "${path9.join(packageRoot, "dist", "hooks", "session-start.js")}"`,
1208
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
1205
1209
  timeout: 1e4
1206
1210
  }
1207
1211
  ]
@@ -1214,7 +1218,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1214
1218
  hooks: [
1215
1219
  {
1216
1220
  type: "command",
1217
- command: `node "${path9.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"`
1221
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
1218
1222
  }
1219
1223
  ]
1220
1224
  },
@@ -1226,7 +1230,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1226
1230
  hooks: [
1227
1231
  {
1228
1232
  type: "command",
1229
- command: `node "${path9.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"`,
1233
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
1230
1234
  timeout: 5e3
1231
1235
  }
1232
1236
  ]
@@ -1239,7 +1243,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1239
1243
  hooks: [
1240
1244
  {
1241
1245
  type: "command",
1242
- command: `node "${path9.join(packageRoot, "dist", "hooks", "stop.js")}"`
1246
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
1243
1247
  }
1244
1248
  ]
1245
1249
  },
@@ -1252,7 +1256,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1252
1256
  hooks: [
1253
1257
  {
1254
1258
  type: "command",
1255
- command: `node "${path9.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"`
1259
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
1256
1260
  }
1257
1261
  ]
1258
1262
  },
@@ -1264,7 +1268,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1264
1268
  hooks: [
1265
1269
  {
1266
1270
  type: "command",
1267
- command: `node "${path9.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"`
1271
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"${logSuffix}`
1268
1272
  }
1269
1273
  ]
1270
1274
  },
@@ -1276,7 +1280,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1276
1280
  hooks: [
1277
1281
  {
1278
1282
  type: "command",
1279
- command: `node "${path9.join(packageRoot, "dist", "hooks", "pre-compact.js")}"`,
1283
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "pre-compact.js")}"${logSuffix}`,
1280
1284
  timeout: 1e4
1281
1285
  }
1282
1286
  ]
@@ -1289,7 +1293,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1289
1293
  hooks: [
1290
1294
  {
1291
1295
  type: "command",
1292
- command: `node "${path9.join(packageRoot, "dist", "hooks", "session-end.js")}"`
1296
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "session-end.js")}"${logSuffix}`
1293
1297
  }
1294
1298
  ]
1295
1299
  },
@@ -1301,7 +1305,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1301
1305
  hooks: [
1302
1306
  {
1303
1307
  type: "command",
1304
- command: `node "${path9.join(packageRoot, "dist", "hooks", "notification.js")}"`
1308
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "notification.js")}"${logSuffix}`
1305
1309
  }
1306
1310
  ]
1307
1311
  },
@@ -1313,7 +1317,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1313
1317
  hooks: [
1314
1318
  {
1315
1319
  type: "command",
1316
- command: `node "${path9.join(packageRoot, "dist", "hooks", "post-compact.js")}"`,
1320
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "post-compact.js")}"${logSuffix}`,
1317
1321
  timeout: 1e4
1318
1322
  }
1319
1323
  ]
@@ -1326,7 +1330,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1326
1330
  hooks: [
1327
1331
  {
1328
1332
  type: "command",
1329
- command: `node "${path9.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"`
1333
+ command: `node "${path9.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"${logSuffix}`
1330
1334
  }
1331
1335
  ]
1332
1336
  },
@@ -3,6 +3,12 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
6
12
  var __esm = (fn, res) => function __init() {
7
13
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
14
  };
@@ -3428,6 +3434,14 @@ var init_agent_config = __esm({
3428
3434
  });
3429
3435
 
3430
3436
  // src/lib/intercom-queue.ts
3437
+ var intercom_queue_exports = {};
3438
+ __export(intercom_queue_exports, {
3439
+ clearQueueForAgent: () => clearQueueForAgent,
3440
+ drainForSession: () => drainForSession,
3441
+ drainQueue: () => drainQueue,
3442
+ queueIntercom: () => queueIntercom,
3443
+ readQueue: () => readQueue
3444
+ });
3431
3445
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
3432
3446
  import path8 from "path";
3433
3447
  import os6 from "os";
@@ -3466,11 +3480,80 @@ function queueIntercom(targetSession, reason) {
3466
3480
  }
3467
3481
  writeQueue(queue);
3468
3482
  }
3469
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
3483
+ function drainQueue(isSessionBusy2, sendKeys) {
3484
+ const queue = readQueue();
3485
+ if (queue.length === 0) return { drained: 0, failed: 0 };
3486
+ const remaining = [];
3487
+ let drained = 0;
3488
+ let failed = 0;
3489
+ for (const item of queue) {
3490
+ const age = Date.now() - new Date(item.queuedAt).getTime();
3491
+ if (age > TTL_MS) {
3492
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
3493
+ failed++;
3494
+ continue;
3495
+ }
3496
+ try {
3497
+ if (!isSessionBusy2(item.targetSession)) {
3498
+ const success = sendKeys(item.targetSession);
3499
+ if (success) {
3500
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
3501
+ drained++;
3502
+ continue;
3503
+ }
3504
+ }
3505
+ } catch {
3506
+ }
3507
+ item.attempts++;
3508
+ if (item.attempts >= MAX_RETRIES2) {
3509
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
3510
+ failed++;
3511
+ continue;
3512
+ }
3513
+ remaining.push(item);
3514
+ }
3515
+ writeQueue(remaining);
3516
+ return { drained, failed };
3517
+ }
3518
+ function drainForSession(targetSession, sendKeys) {
3519
+ const queue = readQueue();
3520
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
3521
+ if (match < 0) return false;
3522
+ const success = sendKeys(targetSession);
3523
+ if (success) {
3524
+ queue.splice(match, 1);
3525
+ writeQueue(queue);
3526
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
3527
+ return true;
3528
+ }
3529
+ return false;
3530
+ }
3531
+ function clearQueueForAgent(agentName2) {
3532
+ const queue = readQueue();
3533
+ const before = queue.length;
3534
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName2}-`));
3535
+ if (filtered.length < before) {
3536
+ writeQueue(filtered);
3537
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName2}`);
3538
+ }
3539
+ }
3540
+ function logQueue(msg) {
3541
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
3542
+ `;
3543
+ process.stderr.write(`[intercom-queue] ${msg}
3544
+ `);
3545
+ try {
3546
+ const { appendFileSync: appendFileSync3 } = __require("fs");
3547
+ appendFileSync3(INTERCOM_LOG, line);
3548
+ } catch {
3549
+ }
3550
+ }
3551
+ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
3470
3552
  var init_intercom_queue = __esm({
3471
3553
  "src/lib/intercom-queue.ts"() {
3472
3554
  "use strict";
3473
3555
  QUEUE_PATH = path8.join(os6.homedir(), ".exe-os", "intercom-queue.json");
3556
+ MAX_RETRIES2 = 5;
3474
3557
  TTL_MS = 60 * 60 * 1e3;
3475
3558
  INTERCOM_LOG = path8.join(os6.homedir(), ".exe-os", "intercom.log");
3476
3559
  }
@@ -4171,6 +4254,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
4171
4254
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
4172
4255
  } catch {
4173
4256
  }
4257
+ if (input.status === "done" || input.status === "cancelled") {
4258
+ try {
4259
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
4260
+ clearQueueForAgent2(String(row.assigned_to));
4261
+ } catch {
4262
+ }
4263
+ }
4174
4264
  try {
4175
4265
  await writeCheckpoint({
4176
4266
  taskId,
@@ -342,7 +342,7 @@ var DEFAULT_RUNTIME = "claude";
342
342
  var AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
343
343
  var KNOWN_RUNTIMES = {
344
344
  claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
345
- codex: ["gpt-5.4", "gpt-5.5", "o3", "o4-mini"],
345
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
346
346
  opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
347
347
  };
348
348
  var RUNTIME_LABELS = {