@integrity-labs/agt-cli 0.27.114 → 0.27.115

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.
@@ -17,7 +17,7 @@ import {
17
17
  provisionStopHook,
18
18
  requireHost,
19
19
  safeWriteJsonAtomic
20
- } from "../chunk-7KIMZAMG.js";
20
+ } from "../chunk-EOMWSV4B.js";
21
21
  import {
22
22
  getProjectDir as getProjectDir2,
23
23
  getReadyTasks,
@@ -47,6 +47,7 @@ import {
47
47
  readPaneLogTail,
48
48
  resetRestartCount,
49
49
  resolveClaudeBinary,
50
+ rotateSessionForWedge,
50
51
  sanitizeMcpJson,
51
52
  sendToAgent,
52
53
  sessionTranscriptDir,
@@ -55,7 +56,7 @@ import {
55
56
  stopPersistentSession,
56
57
  takeWatchdogGiveUpCount,
57
58
  takeZombieDetection
58
- } from "../chunk-RN3OMHW7.js";
59
+ } from "../chunk-IUN5LBTQ.js";
59
60
  import {
60
61
  KANBAN_CHECK_COMMAND,
61
62
  SUPPRESS_SENTINEL,
@@ -3076,6 +3077,53 @@ function clearAgentState(agentId, codeName) {
3076
3077
  return channelCacheMutated;
3077
3078
  }
3078
3079
 
3080
+ // src/lib/wedge-detection.ts
3081
+ var DEFAULTS = {
3082
+ inboundWaitSeconds: 120,
3083
+ inboundHardWaitSeconds: 300,
3084
+ paneStaleSeconds: 120,
3085
+ minCycles: 3
3086
+ };
3087
+ function parseMode(raw) {
3088
+ const v = (raw ?? "").trim().toLowerCase();
3089
+ return v === "shadow" || v === "enforce" ? v : "off";
3090
+ }
3091
+ function parsePositiveInt(raw, fallback, floor) {
3092
+ const n = raw ? Number.parseInt(raw, 10) : NaN;
3093
+ return Number.isInteger(n) && n >= floor ? n : fallback;
3094
+ }
3095
+ function resolveWedgeConfig(env = process.env) {
3096
+ const inboundWaitSeconds = parsePositiveInt(
3097
+ env.AGT_WEDGE_INBOUND_WAIT_SECONDS,
3098
+ DEFAULTS.inboundWaitSeconds,
3099
+ 30
3100
+ );
3101
+ const inboundHardWaitSeconds = Math.max(
3102
+ inboundWaitSeconds,
3103
+ parsePositiveInt(env.AGT_WEDGE_INBOUND_HARD_WAIT_SECONDS, DEFAULTS.inboundHardWaitSeconds, 30)
3104
+ );
3105
+ return {
3106
+ mode: parseMode(env.AGT_WEDGE_RESTART_MODE),
3107
+ inboundWaitSeconds,
3108
+ inboundHardWaitSeconds,
3109
+ paneStaleSeconds: parsePositiveInt(env.AGT_WEDGE_PANE_STALE_SECONDS, DEFAULTS.paneStaleSeconds, 30),
3110
+ minCycles: parsePositiveInt(env.AGT_WEDGE_MIN_CYCLES, DEFAULTS.minCycles, 2)
3111
+ };
3112
+ }
3113
+ function isWedgeCandidateCycle(signals, config2) {
3114
+ const inboundAge = signals.pendingInboundOldestAgeSeconds;
3115
+ if (inboundAge === null) return false;
3116
+ if (inboundAge < config2.inboundWaitSeconds) return false;
3117
+ if (inboundAge >= config2.inboundHardWaitSeconds) return true;
3118
+ const paneAge = signals.paneActivityAgeSeconds;
3119
+ const paneAdvancing = paneAge !== null && paneAge < config2.paneStaleSeconds;
3120
+ return !paneAdvancing;
3121
+ }
3122
+ function decideWedgeRestart(input, config2) {
3123
+ if (!isWedgeCandidateCycle(input, config2)) return "none";
3124
+ return input.consecutiveWedgeCycles >= config2.minCycles ? "wedged" : "none";
3125
+ }
3126
+
3079
3127
  // src/lib/restart-flags.ts
3080
3128
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync8, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync3 } from "fs";
3081
3129
  import { homedir as homedir3 } from "os";
@@ -3876,6 +3924,7 @@ function cancelPendingSessionRestart(codeName) {
3876
3924
  }
3877
3925
  var RESTART_DEFER_RECHECK_MS = 6e4;
3878
3926
  var lastInboundMs = /* @__PURE__ */ new Map();
3927
+ var consecutiveWedgeCycles = /* @__PURE__ */ new Map();
3879
3928
  function noteInbound(codeName) {
3880
3929
  lastInboundMs.set(codeName, Date.now());
3881
3930
  }
@@ -4174,7 +4223,7 @@ var cachedMaintenanceWindow = null;
4174
4223
  var lastVersionCheckAt = 0;
4175
4224
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
4176
4225
  var lastResponsivenessProbeAt = 0;
4177
- var agtCliVersion = true ? "0.27.114" : "dev";
4226
+ var agtCliVersion = true ? "0.27.115" : "dev";
4178
4227
  function resolveBrewPath(execFileSync4) {
4179
4228
  try {
4180
4229
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -5367,7 +5416,7 @@ async function pollCycle() {
5367
5416
  }
5368
5417
  try {
5369
5418
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
5370
- const { collectDiagnostics } = await import("../persistent-session-E6YLH6TX.js");
5419
+ const { collectDiagnostics } = await import("../persistent-session-PIR45QFL.js");
5371
5420
  const diagCodeNames = [...agentState.persistentSessionAgents];
5372
5421
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
5373
5422
  let tailscaleHostname;
@@ -5454,12 +5503,12 @@ async function pollCycle() {
5454
5503
  const {
5455
5504
  collectResponsivenessProbes,
5456
5505
  getResponsivenessIntervalMs
5457
- } = await import("../responsiveness-probe-TDHX6JKG.js");
5506
+ } = await import("../responsiveness-probe-FLQZ7E5H.js");
5458
5507
  const probeIntervalMs = getResponsivenessIntervalMs();
5459
5508
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
5460
5509
  const probeCodeNames = [...agentState.persistentSessionAgents];
5461
5510
  if (probeCodeNames.length > 0) {
5462
- const { takeAcpxExecFailureCount, creditAcpxExecFailureCount } = await import("../persistent-session-E6YLH6TX.js");
5511
+ const { takeAcpxExecFailureCount, creditAcpxExecFailureCount } = await import("../persistent-session-PIR45QFL.js");
5463
5512
  const drainedGiveUps = /* @__PURE__ */ new Map();
5464
5513
  const drainedAcpxFailures = /* @__PURE__ */ new Map();
5465
5514
  const probes = collectResponsivenessProbes(probeCodeNames).map((p) => {
@@ -5486,6 +5535,58 @@ async function pollCycle() {
5486
5535
  } catch (err) {
5487
5536
  log(`[responsiveness-probe] collection failed: ${err.message}`);
5488
5537
  }
5538
+ try {
5539
+ const wedgeConfig = resolveWedgeConfig();
5540
+ if (wedgeConfig.mode !== "off") {
5541
+ const { collectResponsivenessProbes } = await import("../responsiveness-probe-FLQZ7E5H.js");
5542
+ const liveAgents = agentState.persistentSessionAgents;
5543
+ for (const tracked of consecutiveWedgeCycles.keys()) {
5544
+ if (!liveAgents.has(tracked)) consecutiveWedgeCycles.delete(tracked);
5545
+ }
5546
+ for (const probe of collectResponsivenessProbes([...liveAgents])) {
5547
+ const codeName = probe.code_name;
5548
+ if (!isSessionHealthy(codeName)) {
5549
+ consecutiveWedgeCycles.delete(codeName);
5550
+ continue;
5551
+ }
5552
+ const signals = {
5553
+ paneActivityAgeSeconds: probe.pane_activity_age_seconds,
5554
+ pendingInboundOldestAgeSeconds: probe.pending_inbound_oldest_age_seconds ?? null
5555
+ };
5556
+ if (!isWedgeCandidateCycle(signals, wedgeConfig)) {
5557
+ consecutiveWedgeCycles.delete(codeName);
5558
+ continue;
5559
+ }
5560
+ const streak = (consecutiveWedgeCycles.get(codeName) ?? 0) + 1;
5561
+ consecutiveWedgeCycles.set(codeName, streak);
5562
+ if (decideWedgeRestart({ ...signals, consecutiveWedgeCycles: streak }, wedgeConfig) !== "wedged") {
5563
+ continue;
5564
+ }
5565
+ const detail = `agent=${codeName} paneAge=${signals.paneActivityAgeSeconds}s inboundAge=${signals.pendingInboundOldestAgeSeconds}s cycles=${streak}`;
5566
+ if (wedgeConfig.mode === "shadow") {
5567
+ if (streak === wedgeConfig.minCycles) {
5568
+ log(`[wedge] SHADOW would force-fresh respawn ${detail}`);
5569
+ }
5570
+ continue;
5571
+ }
5572
+ try {
5573
+ const newId = rotateSessionForWedge(codeName);
5574
+ try {
5575
+ const { execSync: es } = await import("child_process");
5576
+ es(`tmux kill-session -t agt-${codeName} 2>/dev/null`, { stdio: "ignore" });
5577
+ } catch {
5578
+ }
5579
+ stopPersistentSessionAndForgetMcpBaseline(codeName);
5580
+ consecutiveWedgeCycles.delete(codeName);
5581
+ log(`[wedge] forced fresh respawn ${detail} \u2192 new session ${newId} (transcript preserved)`);
5582
+ } catch (err) {
5583
+ log(`[wedge] force-fresh respawn failed for ${codeName}: ${err.message}`);
5584
+ }
5585
+ }
5586
+ }
5587
+ } catch (err) {
5588
+ log(`[wedge] detection failed: ${err.message}`);
5589
+ }
5489
5590
  try {
5490
5591
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
5491
5592
  const observations = [];
@@ -9855,7 +9956,7 @@ async function processClaudePairSessions(agents) {
9855
9956
  killPairSession,
9856
9957
  pairTmuxSession,
9857
9958
  finalizeClaudePairOnboarding
9858
- } = await import("../claude-pair-runtime-KVJ4U436.js");
9959
+ } = await import("../claude-pair-runtime-UX7GWW3O.js");
9859
9960
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
9860
9961
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
9861
9962
  const killed = await killPairSession(pairTmuxSession(pairId));