@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.
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
5
11
  var __esm = (fn, res) => function __init() {
6
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
13
  };
@@ -608,6 +614,14 @@ var init_agent_config = __esm({
608
614
  });
609
615
 
610
616
  // src/lib/intercom-queue.ts
617
+ var intercom_queue_exports = {};
618
+ __export(intercom_queue_exports, {
619
+ clearQueueForAgent: () => clearQueueForAgent,
620
+ drainForSession: () => drainForSession,
621
+ drainQueue: () => drainQueue,
622
+ queueIntercom: () => queueIntercom,
623
+ readQueue: () => readQueue
624
+ });
611
625
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
612
626
  import path6 from "path";
613
627
  import os4 from "os";
@@ -646,11 +660,80 @@ function queueIntercom(targetSession, reason) {
646
660
  }
647
661
  writeQueue(queue);
648
662
  }
649
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
663
+ function drainQueue(isSessionBusy2, sendKeys) {
664
+ const queue = readQueue();
665
+ if (queue.length === 0) return { drained: 0, failed: 0 };
666
+ const remaining = [];
667
+ let drained = 0;
668
+ let failed = 0;
669
+ for (const item of queue) {
670
+ const age = Date.now() - new Date(item.queuedAt).getTime();
671
+ if (age > TTL_MS) {
672
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
673
+ failed++;
674
+ continue;
675
+ }
676
+ try {
677
+ if (!isSessionBusy2(item.targetSession)) {
678
+ const success = sendKeys(item.targetSession);
679
+ if (success) {
680
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
681
+ drained++;
682
+ continue;
683
+ }
684
+ }
685
+ } catch {
686
+ }
687
+ item.attempts++;
688
+ if (item.attempts >= MAX_RETRIES) {
689
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES} retries exhausted, reason: ${item.reason})`);
690
+ failed++;
691
+ continue;
692
+ }
693
+ remaining.push(item);
694
+ }
695
+ writeQueue(remaining);
696
+ return { drained, failed };
697
+ }
698
+ function drainForSession(targetSession, sendKeys) {
699
+ const queue = readQueue();
700
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
701
+ if (match < 0) return false;
702
+ const success = sendKeys(targetSession);
703
+ if (success) {
704
+ queue.splice(match, 1);
705
+ writeQueue(queue);
706
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
707
+ return true;
708
+ }
709
+ return false;
710
+ }
711
+ function clearQueueForAgent(agentName) {
712
+ const queue = readQueue();
713
+ const before = queue.length;
714
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
715
+ if (filtered.length < before) {
716
+ writeQueue(filtered);
717
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
718
+ }
719
+ }
720
+ function logQueue(msg) {
721
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
722
+ `;
723
+ process.stderr.write(`[intercom-queue] ${msg}
724
+ `);
725
+ try {
726
+ const { appendFileSync: appendFileSync2 } = __require("fs");
727
+ appendFileSync2(INTERCOM_LOG, line);
728
+ } catch {
729
+ }
730
+ }
731
+ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
650
732
  var init_intercom_queue = __esm({
651
733
  "src/lib/intercom-queue.ts"() {
652
734
  "use strict";
653
735
  QUEUE_PATH = path6.join(os4.homedir(), ".exe-os", "intercom-queue.json");
736
+ MAX_RETRIES = 5;
654
737
  TTL_MS = 60 * 60 * 1e3;
655
738
  INTERCOM_LOG = path6.join(os4.homedir(), ".exe-os", "intercom.log");
656
739
  }
@@ -669,18 +752,18 @@ function delay(ms) {
669
752
  }
670
753
  async function retryOnBusy(fn, label) {
671
754
  let lastError;
672
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
755
+ for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
673
756
  try {
674
757
  return await fn();
675
758
  } catch (err) {
676
759
  lastError = err;
677
- if (!isBusyError(err) || attempt === MAX_RETRIES) {
760
+ if (!isBusyError(err) || attempt === MAX_RETRIES2) {
678
761
  throw err;
679
762
  }
680
763
  const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
681
764
  const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
682
765
  process.stderr.write(
683
- `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
766
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES2} \u2014 waiting ${backoff + jitter}ms
684
767
  `
685
768
  );
686
769
  await delay(backoff + jitter);
@@ -701,11 +784,11 @@ function wrapWithRetry(client) {
701
784
  }
702
785
  });
703
786
  }
704
- var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
787
+ var MAX_RETRIES2, BASE_DELAY_MS, MAX_JITTER_MS;
705
788
  var init_db_retry = __esm({
706
789
  "src/lib/db-retry.ts"() {
707
790
  "use strict";
708
- MAX_RETRIES = 3;
791
+ MAX_RETRIES2 = 3;
709
792
  BASE_DELAY_MS = 200;
710
793
  MAX_JITTER_MS = 300;
711
794
  }
@@ -3124,6 +3207,13 @@ ${input2.result}` : `\u26A0\uFE0F ${warning}`;
3124
3207
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3125
3208
  } catch {
3126
3209
  }
3210
+ if (input2.status === "done" || input2.status === "cancelled") {
3211
+ try {
3212
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
3213
+ clearQueueForAgent2(String(row.assigned_to));
3214
+ } catch {
3215
+ }
3216
+ }
3127
3217
  try {
3128
3218
  await writeCheckpoint({
3129
3219
  taskId,
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
5
11
  var __esm = (fn, res) => function __init() {
6
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
13
  };
@@ -3448,6 +3454,18 @@ process.stdin.on("data", (chunk) => {
3448
3454
  });
3449
3455
  process.stdin.on("end", () => {
3450
3456
  try {
3457
+ if (process.env.EXE_DEBUG_HOOKS || process.env.EXE_RUNTIME === "codex") {
3458
+ try {
3459
+ const debugPath = path13.join(EXE_AI_DIR, "logs", "hook-stdin-stop.log");
3460
+ const { mkdirSync: mkdirSync7, writeFileSync: writeFileSync7 } = __require("fs");
3461
+ mkdirSync7(path13.dirname(debugPath), { recursive: true });
3462
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
3463
+ const snippet = input.length > 500 ? input.slice(0, 500) + "...[truncated]" : input;
3464
+ writeFileSync7(debugPath, `[${ts}] len=${input.length} ${snippet}
3465
+ `, { flag: "a" });
3466
+ } catch {
3467
+ }
3468
+ }
3451
3469
  const data = JSON.parse(input);
3452
3470
  const message = data.last_assistant_message;
3453
3471
  if (!message || message.length < MIN_LENGTH) {
package/dist/index.js CHANGED
@@ -852,6 +852,14 @@ var init_agent_config = __esm({
852
852
  });
853
853
 
854
854
  // src/lib/intercom-queue.ts
855
+ var intercom_queue_exports = {};
856
+ __export(intercom_queue_exports, {
857
+ clearQueueForAgent: () => clearQueueForAgent,
858
+ drainForSession: () => drainForSession,
859
+ drainQueue: () => drainQueue,
860
+ queueIntercom: () => queueIntercom,
861
+ readQueue: () => readQueue
862
+ });
855
863
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
856
864
  import path6 from "path";
857
865
  import os5 from "os";
@@ -890,11 +898,80 @@ function queueIntercom(targetSession, reason) {
890
898
  }
891
899
  writeQueue(queue);
892
900
  }
893
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
901
+ function drainQueue(isSessionBusy2, sendKeys) {
902
+ const queue = readQueue();
903
+ if (queue.length === 0) return { drained: 0, failed: 0 };
904
+ const remaining = [];
905
+ let drained = 0;
906
+ let failed = 0;
907
+ for (const item of queue) {
908
+ const age = Date.now() - new Date(item.queuedAt).getTime();
909
+ if (age > TTL_MS) {
910
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
911
+ failed++;
912
+ continue;
913
+ }
914
+ try {
915
+ if (!isSessionBusy2(item.targetSession)) {
916
+ const success = sendKeys(item.targetSession);
917
+ if (success) {
918
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
919
+ drained++;
920
+ continue;
921
+ }
922
+ }
923
+ } catch {
924
+ }
925
+ item.attempts++;
926
+ if (item.attempts >= MAX_RETRIES) {
927
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES} retries exhausted, reason: ${item.reason})`);
928
+ failed++;
929
+ continue;
930
+ }
931
+ remaining.push(item);
932
+ }
933
+ writeQueue(remaining);
934
+ return { drained, failed };
935
+ }
936
+ function drainForSession(targetSession, sendKeys) {
937
+ const queue = readQueue();
938
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
939
+ if (match < 0) return false;
940
+ const success = sendKeys(targetSession);
941
+ if (success) {
942
+ queue.splice(match, 1);
943
+ writeQueue(queue);
944
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
945
+ return true;
946
+ }
947
+ return false;
948
+ }
949
+ function clearQueueForAgent(agentName) {
950
+ const queue = readQueue();
951
+ const before = queue.length;
952
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
953
+ if (filtered.length < before) {
954
+ writeQueue(filtered);
955
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
956
+ }
957
+ }
958
+ function logQueue(msg) {
959
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
960
+ `;
961
+ process.stderr.write(`[intercom-queue] ${msg}
962
+ `);
963
+ try {
964
+ const { appendFileSync: appendFileSync2 } = __require("fs");
965
+ appendFileSync2(INTERCOM_LOG, line);
966
+ } catch {
967
+ }
968
+ }
969
+ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
894
970
  var init_intercom_queue = __esm({
895
971
  "src/lib/intercom-queue.ts"() {
896
972
  "use strict";
897
973
  QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
974
+ MAX_RETRIES = 5;
898
975
  TTL_MS = 60 * 60 * 1e3;
899
976
  INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
900
977
  }
@@ -913,18 +990,18 @@ function delay(ms) {
913
990
  }
914
991
  async function retryOnBusy(fn, label) {
915
992
  let lastError;
916
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
993
+ for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
917
994
  try {
918
995
  return await fn();
919
996
  } catch (err) {
920
997
  lastError = err;
921
- if (!isBusyError(err) || attempt === MAX_RETRIES) {
998
+ if (!isBusyError(err) || attempt === MAX_RETRIES2) {
922
999
  throw err;
923
1000
  }
924
1001
  const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
925
1002
  const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
926
1003
  process.stderr.write(
927
- `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
1004
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES2} \u2014 waiting ${backoff + jitter}ms
928
1005
  `
929
1006
  );
930
1007
  await delay(backoff + jitter);
@@ -945,11 +1022,11 @@ function wrapWithRetry(client) {
945
1022
  }
946
1023
  });
947
1024
  }
948
- var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
1025
+ var MAX_RETRIES2, BASE_DELAY_MS, MAX_JITTER_MS;
949
1026
  var init_db_retry = __esm({
950
1027
  "src/lib/db-retry.ts"() {
951
1028
  "use strict";
952
- MAX_RETRIES = 3;
1029
+ MAX_RETRIES2 = 3;
953
1030
  BASE_DELAY_MS = 200;
954
1031
  MAX_JITTER_MS = 300;
955
1032
  }
@@ -3294,6 +3371,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
3294
3371
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3295
3372
  } catch {
3296
3373
  }
3374
+ if (input.status === "done" || input.status === "cancelled") {
3375
+ try {
3376
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
3377
+ clearQueueForAgent2(String(row.assigned_to));
3378
+ } catch {
3379
+ }
3380
+ }
3297
3381
  try {
3298
3382
  await writeCheckpoint({
3299
3383
  taskId,
@@ -8443,7 +8527,7 @@ async function deliverLocalMessage(messageId) {
8443
8527
  return true;
8444
8528
  } catch {
8445
8529
  const newRetryCount = msg.retryCount + 1;
8446
- if (newRetryCount >= MAX_RETRIES2) {
8530
+ if (newRetryCount >= MAX_RETRIES3) {
8447
8531
  await markFailed(messageId, "session unavailable after 10 retries");
8448
8532
  } else {
8449
8533
  await client.execute({
@@ -8532,7 +8616,7 @@ async function retryPendingMessages() {
8532
8616
  sql: `SELECT * FROM messages
8533
8617
  WHERE status = 'pending' AND retry_count < ?
8534
8618
  ORDER BY id`,
8535
- args: [MAX_RETRIES2]
8619
+ args: [MAX_RETRIES3]
8536
8620
  });
8537
8621
  let delivered = 0;
8538
8622
  for (const row of result.rows) {
@@ -8545,13 +8629,13 @@ async function retryPendingMessages() {
8545
8629
  }
8546
8630
  return delivered;
8547
8631
  }
8548
- var MAX_RETRIES2, _wsClientSend;
8632
+ var MAX_RETRIES3, _wsClientSend;
8549
8633
  var init_messaging = __esm({
8550
8634
  "src/lib/messaging.ts"() {
8551
8635
  "use strict";
8552
8636
  init_database();
8553
8637
  init_tmux_routing();
8554
- MAX_RETRIES2 = 10;
8638
+ MAX_RETRIES3 = 10;
8555
8639
  _wsClientSend = null;
8556
8640
  }
8557
8641
  });
@@ -112,7 +112,7 @@ var DEFAULT_RUNTIME = "claude";
112
112
  var AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
113
113
  var KNOWN_RUNTIMES = {
114
114
  claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
115
- codex: ["gpt-5.4", "gpt-5.5", "o3", "o4-mini"],
115
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
116
116
  opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
117
117
  };
118
118
  var RUNTIME_LABELS = {
@@ -773,7 +773,7 @@ var init_agent_config = __esm({
773
773
  AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
774
774
  KNOWN_RUNTIMES = {
775
775
  claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
776
- codex: ["gpt-5.4", "gpt-5.5", "o3", "o4-mini"],
776
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
777
777
  opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
778
778
  };
779
779
  RUNTIME_LABELS = {
@@ -792,6 +792,7 @@ var init_agent_config = __esm({
792
792
  // src/lib/intercom-queue.ts
793
793
  var intercom_queue_exports = {};
794
794
  __export(intercom_queue_exports, {
795
+ clearQueueForAgent: () => clearQueueForAgent,
795
796
  drainForSession: () => drainForSession,
796
797
  drainQueue: () => drainQueue,
797
798
  queueIntercom: () => queueIntercom,
@@ -883,6 +884,15 @@ function drainForSession(targetSession, sendKeys) {
883
884
  }
884
885
  return false;
885
886
  }
887
+ function clearQueueForAgent(agentName) {
888
+ const queue = readQueue();
889
+ const before = queue.length;
890
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
891
+ if (filtered.length < before) {
892
+ writeQueue(filtered);
893
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
894
+ }
895
+ }
886
896
  function logQueue(msg) {
887
897
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
888
898
  `;
@@ -3507,6 +3517,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
3507
3517
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3508
3518
  } catch {
3509
3519
  }
3520
+ if (input.status === "done" || input.status === "cancelled") {
3521
+ try {
3522
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
3523
+ clearQueueForAgent2(String(row.assigned_to));
3524
+ } catch {
3525
+ }
3526
+ }
3510
3527
  try {
3511
3528
  await writeCheckpoint({
3512
3529
  taskId,
package/dist/lib/tasks.js CHANGED
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
5
11
  var __esm = (fn, res) => function __init() {
6
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
13
  };
@@ -744,6 +750,14 @@ var init_agent_config = __esm({
744
750
  });
745
751
 
746
752
  // src/lib/intercom-queue.ts
753
+ var intercom_queue_exports = {};
754
+ __export(intercom_queue_exports, {
755
+ clearQueueForAgent: () => clearQueueForAgent,
756
+ drainForSession: () => drainForSession,
757
+ drainQueue: () => drainQueue,
758
+ queueIntercom: () => queueIntercom,
759
+ readQueue: () => readQueue
760
+ });
747
761
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
748
762
  import path6 from "path";
749
763
  import os5 from "os";
@@ -782,11 +796,80 @@ function queueIntercom(targetSession, reason) {
782
796
  }
783
797
  writeQueue(queue);
784
798
  }
785
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
799
+ function drainQueue(isSessionBusy2, sendKeys) {
800
+ const queue = readQueue();
801
+ if (queue.length === 0) return { drained: 0, failed: 0 };
802
+ const remaining = [];
803
+ let drained = 0;
804
+ let failed = 0;
805
+ for (const item of queue) {
806
+ const age = Date.now() - new Date(item.queuedAt).getTime();
807
+ if (age > TTL_MS) {
808
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
809
+ failed++;
810
+ continue;
811
+ }
812
+ try {
813
+ if (!isSessionBusy2(item.targetSession)) {
814
+ const success = sendKeys(item.targetSession);
815
+ if (success) {
816
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
817
+ drained++;
818
+ continue;
819
+ }
820
+ }
821
+ } catch {
822
+ }
823
+ item.attempts++;
824
+ if (item.attempts >= MAX_RETRIES) {
825
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES} retries exhausted, reason: ${item.reason})`);
826
+ failed++;
827
+ continue;
828
+ }
829
+ remaining.push(item);
830
+ }
831
+ writeQueue(remaining);
832
+ return { drained, failed };
833
+ }
834
+ function drainForSession(targetSession, sendKeys) {
835
+ const queue = readQueue();
836
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
837
+ if (match < 0) return false;
838
+ const success = sendKeys(targetSession);
839
+ if (success) {
840
+ queue.splice(match, 1);
841
+ writeQueue(queue);
842
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
843
+ return true;
844
+ }
845
+ return false;
846
+ }
847
+ function clearQueueForAgent(agentName) {
848
+ const queue = readQueue();
849
+ const before = queue.length;
850
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
851
+ if (filtered.length < before) {
852
+ writeQueue(filtered);
853
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
854
+ }
855
+ }
856
+ function logQueue(msg) {
857
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
858
+ `;
859
+ process.stderr.write(`[intercom-queue] ${msg}
860
+ `);
861
+ try {
862
+ const { appendFileSync: appendFileSync2 } = __require("fs");
863
+ appendFileSync2(INTERCOM_LOG, line);
864
+ } catch {
865
+ }
866
+ }
867
+ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
786
868
  var init_intercom_queue = __esm({
787
869
  "src/lib/intercom-queue.ts"() {
788
870
  "use strict";
789
871
  QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
872
+ MAX_RETRIES = 5;
790
873
  TTL_MS = 60 * 60 * 1e3;
791
874
  INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
792
875
  }
@@ -2480,6 +2563,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
2480
2563
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
2481
2564
  } catch {
2482
2565
  }
2566
+ if (input.status === "done" || input.status === "cancelled") {
2567
+ try {
2568
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
2569
+ clearQueueForAgent2(String(row.assigned_to));
2570
+ } catch {
2571
+ }
2572
+ }
2483
2573
  try {
2484
2574
  await writeCheckpoint({
2485
2575
  taskId,
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
5
11
  var __esm = (fn, res) => function __init() {
6
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
13
  };
@@ -546,6 +552,14 @@ var init_agent_config = __esm({
546
552
  });
547
553
 
548
554
  // src/lib/intercom-queue.ts
555
+ var intercom_queue_exports = {};
556
+ __export(intercom_queue_exports, {
557
+ clearQueueForAgent: () => clearQueueForAgent,
558
+ drainForSession: () => drainForSession,
559
+ drainQueue: () => drainQueue,
560
+ queueIntercom: () => queueIntercom,
561
+ readQueue: () => readQueue
562
+ });
549
563
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
550
564
  import path4 from "path";
551
565
  import os3 from "os";
@@ -584,11 +598,80 @@ function queueIntercom(targetSession, reason) {
584
598
  }
585
599
  writeQueue(queue);
586
600
  }
587
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
601
+ function drainQueue(isSessionBusy2, sendKeys) {
602
+ const queue = readQueue();
603
+ if (queue.length === 0) return { drained: 0, failed: 0 };
604
+ const remaining = [];
605
+ let drained = 0;
606
+ let failed = 0;
607
+ for (const item of queue) {
608
+ const age = Date.now() - new Date(item.queuedAt).getTime();
609
+ if (age > TTL_MS) {
610
+ logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
611
+ failed++;
612
+ continue;
613
+ }
614
+ try {
615
+ if (!isSessionBusy2(item.targetSession)) {
616
+ const success = sendKeys(item.targetSession);
617
+ if (success) {
618
+ logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
619
+ drained++;
620
+ continue;
621
+ }
622
+ }
623
+ } catch {
624
+ }
625
+ item.attempts++;
626
+ if (item.attempts >= MAX_RETRIES) {
627
+ logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES} retries exhausted, reason: ${item.reason})`);
628
+ failed++;
629
+ continue;
630
+ }
631
+ remaining.push(item);
632
+ }
633
+ writeQueue(remaining);
634
+ return { drained, failed };
635
+ }
636
+ function drainForSession(targetSession, sendKeys) {
637
+ const queue = readQueue();
638
+ const match = queue.findIndex((q) => q.targetSession === targetSession);
639
+ if (match < 0) return false;
640
+ const success = sendKeys(targetSession);
641
+ if (success) {
642
+ queue.splice(match, 1);
643
+ writeQueue(queue);
644
+ logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
645
+ return true;
646
+ }
647
+ return false;
648
+ }
649
+ function clearQueueForAgent(agentName) {
650
+ const queue = readQueue();
651
+ const before = queue.length;
652
+ const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
653
+ if (filtered.length < before) {
654
+ writeQueue(filtered);
655
+ logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
656
+ }
657
+ }
658
+ function logQueue(msg) {
659
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
660
+ `;
661
+ process.stderr.write(`[intercom-queue] ${msg}
662
+ `);
663
+ try {
664
+ const { appendFileSync: appendFileSync2 } = __require("fs");
665
+ appendFileSync2(INTERCOM_LOG, line);
666
+ } catch {
667
+ }
668
+ }
669
+ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
588
670
  var init_intercom_queue = __esm({
589
671
  "src/lib/intercom-queue.ts"() {
590
672
  "use strict";
591
673
  QUEUE_PATH = path4.join(os3.homedir(), ".exe-os", "intercom-queue.json");
674
+ MAX_RETRIES = 5;
592
675
  TTL_MS = 60 * 60 * 1e3;
593
676
  INTERCOM_LOG = path4.join(os3.homedir(), ".exe-os", "intercom.log");
594
677
  }
@@ -1443,6 +1526,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
1443
1526
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
1444
1527
  } catch {
1445
1528
  }
1529
+ if (input.status === "done" || input.status === "cancelled") {
1530
+ try {
1531
+ const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
1532
+ clearQueueForAgent2(String(row.assigned_to));
1533
+ } catch {
1534
+ }
1535
+ }
1446
1536
  try {
1447
1537
  await writeCheckpoint({
1448
1538
  taskId,