@integrity-labs/agt-cli 0.28.717 → 0.28.719

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 (25) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-KVR5KNED.js → chunk-7LH3SVAD.js} +7 -2
  3. package/dist/chunk-7LH3SVAD.js.map +1 -0
  4. package/dist/{chunk-XSBRGOGL.js → chunk-FG5F657H.js} +4 -4
  5. package/dist/{chunk-JN4D7534.js → chunk-FNALM4HG.js} +120 -19
  6. package/dist/chunk-FNALM4HG.js.map +1 -0
  7. package/dist/{claude-pair-runtime-KWBCSCZO.js → claude-pair-runtime-PDG74SAT.js} +2 -2
  8. package/dist/lib/manager-worker.js +89 -21
  9. package/dist/lib/manager-worker.js.map +1 -1
  10. package/dist/mcp/direct-chat-channel.js +6 -1
  11. package/dist/mcp/index.js +6 -1
  12. package/dist/mcp/origami.js +6 -1
  13. package/dist/mcp/slack-channel.js +6 -1
  14. package/dist/mcp/telegram-channel.js +6 -1
  15. package/dist/{persistent-session-GB3D5OIA.js → persistent-session-2AWYIUCX.js} +7 -3
  16. package/dist/{responsiveness-probe-TDZDQXBU.js → responsiveness-probe-JQS4WA2L.js} +3 -3
  17. package/dist/{session-auth-dead-CPY4UZI7.js → session-auth-dead-VBMZW4GG.js} +2 -2
  18. package/package.json +1 -1
  19. package/dist/chunk-JN4D7534.js.map +0 -1
  20. package/dist/chunk-KVR5KNED.js.map +0 -1
  21. /package/dist/{chunk-XSBRGOGL.js.map → chunk-FG5F657H.js.map} +0 -0
  22. /package/dist/{claude-pair-runtime-KWBCSCZO.js.map → claude-pair-runtime-PDG74SAT.js.map} +0 -0
  23. /package/dist/{persistent-session-GB3D5OIA.js.map → persistent-session-2AWYIUCX.js.map} +0 -0
  24. /package/dist/{responsiveness-probe-TDZDQXBU.js.map → responsiveness-probe-JQS4WA2L.js.map} +0 -0
  25. /package/dist/{session-auth-dead-CPY4UZI7.js.map → session-auth-dead-VBMZW4GG.js.map} +0 -0
@@ -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-GB3D5OIA.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-2AWYIUCX.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-KWBCSCZO.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-PDG74SAT.js.map
@@ -57,7 +57,7 @@ import {
57
57
  safeWriteJsonAtomic,
58
58
  setConfigHash,
59
59
  tripClass
60
- } from "../chunk-XSBRGOGL.js";
60
+ } from "../chunk-FG5F657H.js";
61
61
  import {
62
62
  getProjectDir as getProjectDir2,
63
63
  getReadyTasks,
@@ -115,7 +115,7 @@ import {
115
115
  takeZombieDetection,
116
116
  toOpencodeModel,
117
117
  writeEgressAllowlist
118
- } from "../chunk-JN4D7534.js";
118
+ } from "../chunk-FNALM4HG.js";
119
119
  import {
120
120
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
121
121
  AnchorSessionClient,
@@ -200,7 +200,7 @@ import {
200
200
  subagentActivityAgeSeconds,
201
201
  sumTranscriptUsageInWindow,
202
202
  transcriptActivityAgeSeconds
203
- } from "../chunk-KVR5KNED.js";
203
+ } from "../chunk-7LH3SVAD.js";
204
204
  import {
205
205
  reapOrphanChannelMcps
206
206
  } from "../chunk-XWVM4KPK.js";
@@ -247,8 +247,11 @@ function createSingleFlight(task, opts = {}) {
247
247
  if (running2) {
248
248
  rerunRequested = true;
249
249
  coalesced += 1;
250
- opts.onCoalesce?.(coalesced);
251
- return settled ?? Promise.resolve();
250
+ try {
251
+ opts.onCoalesce?.(coalesced);
252
+ } catch {
253
+ }
254
+ return (settled ?? Promise.resolve()).then(() => ({ coalesced: true }));
252
255
  }
253
256
  running2 = true;
254
257
  let markSettled;
@@ -266,7 +269,7 @@ function createSingleFlight(task, opts = {}) {
266
269
  markSettled();
267
270
  }
268
271
  })();
269
- return primary;
272
+ return primary.then(() => ({ coalesced: false }));
270
273
  }
271
274
  return {
272
275
  run,
@@ -6017,15 +6020,18 @@ function writeManagedSkillManifest(path, ids) {
6017
6020
 
6018
6021
  // src/lib/poll-loop-guard.ts
6019
6022
  async function pollCycleAndReschedule(pollCycle2, opts) {
6023
+ let outcome = void 0;
6020
6024
  try {
6021
- await pollCycle2();
6025
+ outcome = await pollCycle2();
6022
6026
  } catch (err) {
6023
6027
  try {
6024
6028
  await opts.onError(err);
6025
6029
  } catch {
6026
6030
  }
6027
6031
  } finally {
6028
- await opts.reschedule();
6032
+ if (!outcome?.coalesced) {
6033
+ await opts.reschedule();
6034
+ }
6029
6035
  }
6030
6036
  }
6031
6037
 
@@ -10641,13 +10647,58 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
10641
10647
 
10642
10648
  // src/lib/persistent-session-stuck-tracker.ts
10643
10649
  var DEFAULT_STUCK_WARN_THRESHOLD = 3;
10650
+ var DEFAULT_SPAWN_LOOP_WARN_THRESHOLD = 3;
10644
10651
  var PersistentSessionStuckTracker = class {
10645
10652
  counts = /* @__PURE__ */ new Map();
10646
10653
  warned = /* @__PURE__ */ new Set();
10647
10654
  threshold;
10648
- constructor(threshold = DEFAULT_STUCK_WARN_THRESHOLD) {
10655
+ /**
10656
+ * ENG-9614 — the second streak, held separately because it answers a
10657
+ * DIFFERENT question and must not inherit the first one's reset rule.
10658
+ *
10659
+ * `counts` above resets whenever `spawnAttempted` is true, which is correct
10660
+ * for its own question (ENG-5116/Vigil: unhealthy and nobody even TRIED).
10661
+ * But it makes the tracker structurally blind to the inverse: the scratch/tmp
10662
+ * collision attempted a spawn on EVERY tick, so `counts` was deleted on every
10663
+ * tick, `shouldWarn` could never fire, and an agent looped unrecoverably for
10664
+ * 3m48s without this class emitting a single line.
10665
+ *
10666
+ * Folding both into one counter was considered and rejected - a shared
10667
+ * counter would have to pick one reset rule, and either choice makes the
10668
+ * other question unanswerable. Two questions, two counters.
10669
+ */
10670
+ spawnLoopCounts = /* @__PURE__ */ new Map();
10671
+ spawnLoopWarned = /* @__PURE__ */ new Set();
10672
+ spawnLoopThreshold;
10673
+ constructor(threshold = DEFAULT_STUCK_WARN_THRESHOLD, spawnLoopThreshold = DEFAULT_SPAWN_LOOP_WARN_THRESHOLD) {
10649
10674
  if (threshold < 1) throw new Error("stuck-tracker threshold must be >= 1");
10675
+ if (spawnLoopThreshold < 1) throw new Error("stuck-tracker spawn-loop threshold must be >= 1");
10650
10676
  this.threshold = threshold;
10677
+ this.spawnLoopThreshold = spawnLoopThreshold;
10678
+ }
10679
+ /**
10680
+ * Advance the spawn-loop streak for one tick.
10681
+ *
10682
+ * Counts only when a spawn was attempted AND the session is still unhealthy.
10683
+ * Health alone resets it - an agent that came up is not looping, however it
10684
+ * got there. A tick with no spawn attempt neither counts nor resets: that is
10685
+ * the OTHER failure, already owned by `counts`, and letting it clear this
10686
+ * streak would let the two shapes alternate and hide each other.
10687
+ */
10688
+ recordSpawnLoop(codeName, sessionHealthy, spawnAttempted) {
10689
+ if (sessionHealthy) {
10690
+ this.spawnLoopCounts.delete(codeName);
10691
+ this.spawnLoopWarned.delete(codeName);
10692
+ return { ticks: 0, shouldWarn: false };
10693
+ }
10694
+ if (!spawnAttempted) {
10695
+ return { ticks: this.spawnLoopCounts.get(codeName) ?? 0, shouldWarn: false };
10696
+ }
10697
+ const next = (this.spawnLoopCounts.get(codeName) ?? 0) + 1;
10698
+ this.spawnLoopCounts.set(codeName, next);
10699
+ const crossed = next >= this.spawnLoopThreshold && !this.spawnLoopWarned.has(codeName);
10700
+ if (crossed) this.spawnLoopWarned.add(codeName);
10701
+ return { ticks: next, shouldWarn: crossed };
10651
10702
  }
10652
10703
  /**
10653
10704
  * Record one tick for one agent. Returns whether the caller should log
@@ -10658,6 +10709,7 @@ var PersistentSessionStuckTracker = class {
10658
10709
  */
10659
10710
  record(input) {
10660
10711
  const { codeName, sessionHealthy, spawnAttempted } = input;
10712
+ const spawnLoop = this.recordSpawnLoop(codeName, sessionHealthy, spawnAttempted);
10661
10713
  const wasStuck = (this.counts.get(codeName) ?? 0) >= this.threshold;
10662
10714
  if (sessionHealthy || spawnAttempted) {
10663
10715
  this.counts.delete(codeName);
@@ -10665,7 +10717,9 @@ var PersistentSessionStuckTracker = class {
10665
10717
  return {
10666
10718
  consecutiveTicks: 0,
10667
10719
  shouldWarn: false,
10668
- recovered: wasStuck && wasWarned
10720
+ recovered: wasStuck && wasWarned,
10721
+ spawnLoopTicks: spawnLoop.ticks,
10722
+ shouldWarnSpawnLoop: spawnLoop.shouldWarn
10669
10723
  };
10670
10724
  }
10671
10725
  const next = (this.counts.get(codeName) ?? 0) + 1;
@@ -10675,17 +10729,25 @@ var PersistentSessionStuckTracker = class {
10675
10729
  return {
10676
10730
  consecutiveTicks: next,
10677
10731
  shouldWarn: crossed,
10678
- recovered: false
10732
+ recovered: false,
10733
+ spawnLoopTicks: spawnLoop.ticks,
10734
+ shouldWarnSpawnLoop: spawnLoop.shouldWarn
10679
10735
  };
10680
10736
  }
10681
10737
  /** Test/debug helper: peek at an agent's current streak. */
10682
10738
  peek(codeName) {
10683
10739
  return this.counts.get(codeName) ?? 0;
10684
10740
  }
10741
+ /** Test/debug helper: peek at an agent's current spawn-loop streak. */
10742
+ peekSpawnLoop(codeName) {
10743
+ return this.spawnLoopCounts.get(codeName) ?? 0;
10744
+ }
10685
10745
  /** Test helper: clear all state. */
10686
10746
  reset() {
10687
10747
  this.counts.clear();
10688
10748
  this.warned.clear();
10749
+ this.spawnLoopCounts.clear();
10750
+ this.spawnLoopWarned.clear();
10689
10751
  }
10690
10752
  };
10691
10753
 
@@ -12001,7 +12063,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
12001
12063
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
12002
12064
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
12003
12065
  async function channelInboundActivityAgeSecondsFor(codeName) {
12004
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-TDZDQXBU.js");
12066
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-JQS4WA2L.js");
12005
12067
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
12006
12068
  if (newest === null) return null;
12007
12069
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -12649,7 +12711,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12649
12711
  var lastVersionCheckAt = 0;
12650
12712
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12651
12713
  var lastResponsivenessProbeAt = 0;
12652
- var agtCliVersion = true ? "0.28.717" : "dev";
12714
+ var agtCliVersion = true ? "0.28.719" : "dev";
12653
12715
  function resolveBrewPath(execFileSync3) {
12654
12716
  try {
12655
12717
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14176,7 +14238,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
14176
14238
  if (codeNames.length === 0) return;
14177
14239
  void (async () => {
14178
14240
  try {
14179
- const { collectDiagnostics } = await import("../persistent-session-GB3D5OIA.js");
14241
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
14180
14242
  await api.post("/host/heartbeat", {
14181
14243
  host_id: hostId,
14182
14244
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -14294,7 +14356,7 @@ async function pollCycleInner() {
14294
14356
  }
14295
14357
  try {
14296
14358
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
14297
- const { collectDiagnostics } = await import("../persistent-session-GB3D5OIA.js");
14359
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
14298
14360
  const diagCodeNames = [...agentState.persistentSessionAgents];
14299
14361
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
14300
14362
  let tailscaleHostname;
@@ -14463,7 +14525,7 @@ async function pollCycleInner() {
14463
14525
  collectPanelessActivityProbes,
14464
14526
  getResponsivenessIntervalMs,
14465
14527
  occupancyQualificationClassifications
14466
- } = await import("../responsiveness-probe-TDZDQXBU.js");
14528
+ } = await import("../responsiveness-probe-JQS4WA2L.js");
14467
14529
  const probeIntervalMs = getResponsivenessIntervalMs();
14468
14530
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14469
14531
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -14573,7 +14635,7 @@ async function pollCycleInner() {
14573
14635
  collectResponsivenessProbes,
14574
14636
  livePendingInboundOldestAgeSeconds,
14575
14637
  parkPendingInbound
14576
- } = await import("../responsiveness-probe-TDZDQXBU.js");
14638
+ } = await import("../responsiveness-probe-JQS4WA2L.js");
14577
14639
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14578
14640
  const wedgeNow = /* @__PURE__ */ new Date();
14579
14641
  const liveAgents = agentState.persistentSessionAgents;
@@ -14729,7 +14791,7 @@ async function pollCycleInner() {
14729
14791
  }
14730
14792
  try {
14731
14793
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
14732
- const { probeSessionAuth } = await import("../session-auth-dead-CPY4UZI7.js");
14794
+ const { probeSessionAuth } = await import("../session-auth-dead-VBMZW4GG.js");
14733
14795
  const observations = [];
14734
14796
  const pendingCacheCommits = [];
14735
14797
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -17150,6 +17212,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
17150
17212
  } else if (stuck.recovered) {
17151
17213
  log(`[persistent-session-stuck] agent=${agent.code_name} recovered from stuck state`);
17152
17214
  }
17215
+ if (stuck.shouldWarnSpawnLoop) {
17216
+ const failure = getLastFailureContext(agent.code_name);
17217
+ log(
17218
+ `[persistent-session-spawn-loop] WARN: agent=${agent.code_name} respawned ${stuck.spawnLoopTicks} consecutive ticks and is still unhealthy (last_decision=${psResult.decision} signature=${failure.signature} restart_count=${failure.restartCount}) \u2014 the spawn is failing in a way a retry cannot fix; see the pane log tail for the cause (ENG-9614)`
17219
+ );
17220
+ }
17153
17221
  if (agentFw === "claude-code") {
17154
17222
  try {
17155
17223
  checkMcpConfigDriftAndScheduleRestart(agent.code_name, getProjectDir(agent.code_name));
@@ -18554,7 +18622,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18554
18622
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
18555
18623
  void (async () => {
18556
18624
  try {
18557
- const { collectDiagnostics } = await import("../persistent-session-GB3D5OIA.js");
18625
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
18558
18626
  await api.post("/host/heartbeat", {
18559
18627
  host_id: hostId,
18560
18628
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -18605,7 +18673,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
18605
18673
  }
18606
18674
  try {
18607
18675
  const hostId = await getHostId();
18608
- const { collectDiagnostics } = await import("../persistent-session-GB3D5OIA.js");
18676
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
18609
18677
  await api.post("/host/heartbeat", {
18610
18678
  host_id: hostId,
18611
18679
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19237,7 +19305,7 @@ async function processClaudePairSessions(agents) {
19237
19305
  killPairSession,
19238
19306
  pairTmuxSession,
19239
19307
  finalizeClaudePairOnboarding
19240
- } = await import("../claude-pair-runtime-KWBCSCZO.js");
19308
+ } = await import("../claude-pair-runtime-PDG74SAT.js");
19241
19309
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
19242
19310
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
19243
19311
  const killed = await killPairSession(pairTmuxSession(pairId));