@integrity-labs/agt-cli 0.27.52 → 0.27.54

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.
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-JRF3JXTC.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-6TWTADQN.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-PZBLMYVH.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-OOVDC4YK.js.map
@@ -15,7 +15,7 @@ import {
15
15
  provisionOrientHook,
16
16
  provisionStopHook,
17
17
  requireHost
18
- } from "../chunk-IMKH4X56.js";
18
+ } from "../chunk-54EOGPOF.js";
19
19
  import {
20
20
  getProjectDir as getProjectDir2,
21
21
  getReadyTasks,
@@ -46,7 +46,7 @@ import {
46
46
  stopAllSessionsAndWait,
47
47
  stopPersistentSession,
48
48
  takeZombieDetection
49
- } from "../chunk-5S322IC7.js";
49
+ } from "../chunk-4ZKBMJ3Y.js";
50
50
  import {
51
51
  KANBAN_CHECK_COMMAND,
52
52
  appendDmFooter,
@@ -69,7 +69,7 @@ import {
69
69
  resolveConnectivityProbe,
70
70
  resolveDmTarget,
71
71
  wrapScheduledTaskPrompt
72
- } from "../chunk-UOHGOS3O.js";
72
+ } from "../chunk-2NOH5XB5.js";
73
73
  import {
74
74
  parsePsRows,
75
75
  reapOrphanChannelMcps
@@ -1234,6 +1234,92 @@ function formatReaperBootLine(opts) {
1234
1234
  return `[drain] step=boot-reaper total=${opts.totalRecorded} killed=${opts.killed} already_dead=${opts.alreadyDead} pid_reused_skipped=${opts.pidReusedSkipped} kanban_reset=${opts.kanbanReset}`;
1235
1235
  }
1236
1236
 
1237
+ // src/lib/direct-chat-spawn-gate.ts
1238
+ var DEFAULT_DIRECT_CHAT_HOST_CONCURRENCY = 2;
1239
+ var DEFAULT_DIRECT_CHAT_PER_AGENT_CONCURRENCY = 1;
1240
+ var DEFAULT_DIRECT_CHAT_MAX_AGE_MS = 30 * 6e4;
1241
+ function directChatHostConcurrency() {
1242
+ const raw = parseInt(process.env["AGT_DIRECT_CHAT_MAX_CONCURRENCY"] ?? "", 10);
1243
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_DIRECT_CHAT_HOST_CONCURRENCY;
1244
+ }
1245
+ function directChatMaxAgeMs() {
1246
+ const raw = parseInt(process.env["AGT_DIRECT_CHAT_MAX_AGE_MS"] ?? "", 10);
1247
+ return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_DIRECT_CHAT_MAX_AGE_MS;
1248
+ }
1249
+ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
1250
+ if (!maxAgeMs || maxAgeMs <= 0) return false;
1251
+ if (!createdAt) return false;
1252
+ const created = Date.parse(createdAt);
1253
+ if (!Number.isFinite(created)) return false;
1254
+ return nowMs - created > maxAgeMs;
1255
+ }
1256
+ var DirectChatSpawnGate = class {
1257
+ hostMax;
1258
+ perAgentMax;
1259
+ host = 0;
1260
+ perAgent = /* @__PURE__ */ new Map();
1261
+ queue = [];
1262
+ constructor(config2) {
1263
+ this.hostMax = Math.max(1, config2?.hostMaxConcurrency ?? DEFAULT_DIRECT_CHAT_HOST_CONCURRENCY);
1264
+ this.perAgentMax = Math.max(
1265
+ 1,
1266
+ config2?.perAgentMaxConcurrency ?? DEFAULT_DIRECT_CHAT_PER_AGENT_CONCURRENCY
1267
+ );
1268
+ }
1269
+ /** Live host-wide spawn count. */
1270
+ get hostInFlight() {
1271
+ return this.host;
1272
+ }
1273
+ /** Live spawn count for a single agent. */
1274
+ agentInFlight(codeName) {
1275
+ return this.perAgent.get(codeName) ?? 0;
1276
+ }
1277
+ /** Number of acquirers currently waiting for a slot. */
1278
+ get queuedCount() {
1279
+ return this.queue.length;
1280
+ }
1281
+ canGrant(codeName) {
1282
+ return this.host < this.hostMax && this.agentInFlight(codeName) < this.perAgentMax;
1283
+ }
1284
+ grant(codeName) {
1285
+ this.host += 1;
1286
+ this.perAgent.set(codeName, this.agentInFlight(codeName) + 1);
1287
+ let released = false;
1288
+ return () => {
1289
+ if (released) return;
1290
+ released = true;
1291
+ this.host -= 1;
1292
+ const remaining = this.agentInFlight(codeName) - 1;
1293
+ if (remaining <= 0) this.perAgent.delete(codeName);
1294
+ else this.perAgent.set(codeName, remaining);
1295
+ this.drain();
1296
+ };
1297
+ }
1298
+ /** Acquire a spawn slot for `codeName`. Resolves with a single-use release. */
1299
+ acquire(codeName) {
1300
+ if (this.canGrant(codeName)) {
1301
+ return Promise.resolve(this.grant(codeName));
1302
+ }
1303
+ return new Promise((resolve) => {
1304
+ this.queue.push({ codeName, resolve });
1305
+ });
1306
+ }
1307
+ /** Grant as many queued waiters as free slots allow, in FIFO order. */
1308
+ drain() {
1309
+ let i = 0;
1310
+ while (i < this.queue.length && this.host < this.hostMax) {
1311
+ const waiter = this.queue[i];
1312
+ if (!waiter) break;
1313
+ if (this.canGrant(waiter.codeName)) {
1314
+ this.queue.splice(i, 1);
1315
+ waiter.resolve(this.grant(waiter.codeName));
1316
+ } else {
1317
+ i += 1;
1318
+ }
1319
+ }
1320
+ }
1321
+ };
1322
+
1237
1323
  // src/lib/usage-banner-monitor.ts
1238
1324
  var MIN_CHECK_INTERVAL_MS = 6e4;
1239
1325
  var PANE_TAIL_LINES_FOR_BANNER = 200;
@@ -3512,7 +3598,7 @@ var cachedFrameworkVersion = null;
3512
3598
  var lastVersionCheckAt = 0;
3513
3599
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
3514
3600
  var lastResponsivenessProbeAt = 0;
3515
- var agtCliVersion = true ? "0.27.52" : "dev";
3601
+ var agtCliVersion = true ? "0.27.54" : "dev";
3516
3602
  function resolveBrewPath(execFileSync4) {
3517
3603
  try {
3518
3604
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -4587,7 +4673,7 @@ async function pollCycle() {
4587
4673
  }
4588
4674
  try {
4589
4675
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
4590
- const { collectDiagnostics } = await import("../persistent-session-JRF3JXTC.js");
4676
+ const { collectDiagnostics } = await import("../persistent-session-6TWTADQN.js");
4591
4677
  const diagCodeNames = [...agentState.persistentSessionAgents];
4592
4678
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
4593
4679
  let tailscaleHostname;
@@ -4655,7 +4741,7 @@ async function pollCycle() {
4655
4741
  const {
4656
4742
  collectResponsivenessProbes,
4657
4743
  getResponsivenessIntervalMs
4658
- } = await import("../responsiveness-probe-JZLGWZFN.js");
4744
+ } = await import("../responsiveness-probe-KBUKS7PN.js");
4659
4745
  const probeIntervalMs = getResponsivenessIntervalMs();
4660
4746
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
4661
4747
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7670,6 +7756,9 @@ function triggerEarlyPoll(reason) {
7670
7756
  }, 0);
7671
7757
  }
7672
7758
  var directChatInFlight = /* @__PURE__ */ new Set();
7759
+ var directChatSpawnGate = new DirectChatSpawnGate({
7760
+ hostMaxConcurrency: directChatHostConcurrency()
7761
+ });
7673
7762
  async function pollDirectChatMessages(agentStates) {
7674
7763
  for (const agent of agentStates) {
7675
7764
  if (agent.status !== "active") continue;
@@ -7692,6 +7781,18 @@ async function pollDirectChatMessages(agentStates) {
7692
7781
  async function processDirectChatMessage(agent, msg) {
7693
7782
  const fw = agentFrameworkCache.get(agent.codeName) ?? "openclaw";
7694
7783
  log(`[direct-chat] Processing message for '${agent.codeName}' (fw=${fw}): id=${msg.id} len=${msg.content.length}`);
7784
+ if (isDirectChatMessageExpired(msg.created_at, Date.now(), directChatMaxAgeMs())) {
7785
+ log(`[direct-chat] Expired backlog message for '${agent.codeName}' (msg=${msg.id}, created_at=${msg.created_at}) \u2014 draining without delivery`);
7786
+ try {
7787
+ await api.post("/host/direct-chat/reply", {
7788
+ agent_id: agent.agentId,
7789
+ session_id: msg.session_id,
7790
+ content: "[Expired] This message timed out before it could be processed. Please resend it."
7791
+ });
7792
+ } catch {
7793
+ }
7794
+ return;
7795
+ }
7695
7796
  if (isSessionHealthy(agent.codeName)) {
7696
7797
  const escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
7697
7798
  const channelEnvelope = `<channel source="direct-chat" session_id="${escapeXml(msg.session_id)}" user="webapp">
@@ -7710,9 +7811,24 @@ ${escapeXml(msg.content)}
7710
7811
  }
7711
7812
  log(`[direct-chat] Inject reported unverified for '${agent.codeName}' (msg=${msg.id}) \u2014 falling back to one-shot direct-chat handling`);
7712
7813
  }
7814
+ let releaseSpawnSlot;
7713
7815
  try {
7714
7816
  let reply;
7715
7817
  if (fw === "claude-code") {
7818
+ releaseSpawnSlot = await directChatSpawnGate.acquire(agent.codeName);
7819
+ if (isDirectChatMessageExpired(msg.created_at, Date.now(), directChatMaxAgeMs())) {
7820
+ log(`[direct-chat] Message for '${agent.codeName}' expired while queued behind the spawn gate (msg=${msg.id}) \u2014 draining without a spawn`);
7821
+ try {
7822
+ await api.post("/host/direct-chat/reply", {
7823
+ agent_id: agent.agentId,
7824
+ session_id: msg.session_id,
7825
+ content: "[Expired] This message timed out before it could be processed. Please resend it."
7826
+ });
7827
+ } catch {
7828
+ }
7829
+ return;
7830
+ }
7831
+ log(`[direct-chat] One-shot spawn for '${agent.codeName}' (msg=${msg.id}; host in-flight=${directChatSpawnGate.hostInFlight}, queued=${directChatSpawnGate.queuedCount})`);
7716
7832
  const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-EM24LTGV.js");
7717
7833
  const projDir = ccProjectDir(agent.codeName);
7718
7834
  const mcpConfigPath = join7(projDir, ".mcp.json");
@@ -7813,6 +7929,8 @@ ${escapeXml(msg.content)}
7813
7929
  });
7814
7930
  } catch {
7815
7931
  }
7932
+ } finally {
7933
+ releaseSpawnSlot?.();
7816
7934
  }
7817
7935
  }
7818
7936
  var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
@@ -8767,7 +8885,7 @@ async function processClaudePairSessions(agents) {
8767
8885
  killPairSession,
8768
8886
  pairTmuxSession,
8769
8887
  finalizeClaudePairOnboarding
8770
- } = await import("../claude-pair-runtime-PZBLMYVH.js");
8888
+ } = await import("../claude-pair-runtime-OOVDC4YK.js");
8771
8889
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
8772
8890
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
8773
8891
  const killed = await killPairSession(pairTmuxSession(pairId));