@integrity-labs/agt-cli 0.28.886 → 0.28.888

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.
@@ -16,7 +16,7 @@ import {
16
16
  parseEnvIntegrations,
17
17
  shellQuote,
18
18
  summarizeUnanswerablePane
19
- } from "./chunk-FP5M5OVX.js";
19
+ } from "./chunk-OMRYKBFE.js";
20
20
  import {
21
21
  BIND_FAILURE_QUARANTINE_THRESHOLD,
22
22
  INTEGRATIONS_SECTION_END,
@@ -6841,7 +6841,7 @@ function exchangeFailureKind(err) {
6841
6841
  }
6842
6842
 
6843
6843
  // src/lib/api-client.ts
6844
- var agtCliVersion = true ? "0.28.886" : "dev";
6844
+ var agtCliVersion = true ? "0.28.888" : "dev";
6845
6845
  var lastConfigHash = null;
6846
6846
  function setConfigHash(hash) {
6847
6847
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -11451,4 +11451,4 @@ export {
11451
11451
  managerInstallSystemUnitCommand,
11452
11452
  managerUninstallSystemUnitCommand
11453
11453
  };
11454
- //# sourceMappingURL=chunk-2E7GOSID.js.map
11454
+ //# sourceMappingURL=chunk-P2EMIE25.js.map
@@ -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-SG4HA35I.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-RFQKA2H5.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-BQGZXRPV.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-5UINWQ52.js.map
@@ -63,7 +63,7 @@ import {
63
63
  safeWriteJsonAtomic,
64
64
  setConfigHash,
65
65
  tripClass
66
- } from "../chunk-2E7GOSID.js";
66
+ } from "../chunk-P2EMIE25.js";
67
67
  import {
68
68
  getProjectDir as getProjectDir2,
69
69
  getReadyTasks,
@@ -72,9 +72,11 @@ import {
72
72
  syncTasksToScheduler
73
73
  } from "../chunk-3HLECXMI.js";
74
74
  import {
75
+ BLOCKED_ON_PROMPT_DECISION,
75
76
  CHANNEL_SECRET_ENV_KEYS,
76
77
  ChildProcessError,
77
78
  agentRuntimeKey,
79
+ applyBlockedPromptVerdict,
78
80
  buildEgressAllowlist,
79
81
  checkChannelInputs,
80
82
  collectChannelSpawnSecrets,
@@ -94,6 +96,7 @@ import {
94
96
  injectMessage,
95
97
  injectMessageWithStatus,
96
98
  injectOpencodeMessage,
99
+ isConfirmedRespawn,
97
100
  isOpencodeSessionHealthy,
98
101
  isSessionHealthy,
99
102
  isolationMode,
@@ -101,6 +104,7 @@ import {
101
104
  mergeOpencodeConfigArtifact,
102
105
  modelPolicyAuthComponent,
103
106
  modelPolicyEgressDomains,
107
+ noteSessionBlockedOnPrompt,
104
108
  paneLogPath,
105
109
  parseEnvIntegrations,
106
110
  parseModelPolicy,
@@ -117,8 +121,11 @@ import {
117
121
  restartEgressSidecar,
118
122
  rotatePaneLogForDayRollover,
119
123
  rotateSessionForWedge,
124
+ sessionBlockedOnPrompt,
125
+ sessionHealthyAndUnblocked,
120
126
  sha256,
121
127
  sharedBusyBuckets,
128
+ shouldLogBlockedPrompt,
122
129
  startOpencodeSession,
123
130
  startPersistentSession,
124
131
  stopAllSessionsAndWait,
@@ -129,7 +136,7 @@ import {
129
136
  takeZombieDetection,
130
137
  toOpencodeModel,
131
138
  writeEgressAllowlist
132
- } from "../chunk-FP5M5OVX.js";
139
+ } from "../chunk-OMRYKBFE.js";
133
140
  import {
134
141
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
135
142
  AnchorSessionClient,
@@ -12935,7 +12942,7 @@ var firstConnectUnsettledByAgent = /* @__PURE__ */ new Map();
12935
12942
  function verifyPendingRestarts(now) {
12936
12943
  if (pendingRestartVerifications.size === 0) return;
12937
12944
  for (const [codeName, pending2] of pendingRestartVerifications) {
12938
- const healthy = isSessionHealthy(codeName);
12945
+ const healthy = sessionHealthyAndUnblocked(codeName, isSessionHealthy);
12939
12946
  const session = getSessionState(codeName);
12940
12947
  const startedAt = session?.startedAt ?? null;
12941
12948
  const respawnId = session?.currentSessionId ?? null;
@@ -12979,7 +12986,7 @@ function verifyPendingRestarts(now) {
12979
12986
  finishRestartTiming(codeName, "failed", `${outcome.attempt} verify attempts`, log, now);
12980
12987
  if (bindRemediationEnabled() && spawnWasRefusedWithNoSession(codeName)) {
12981
12988
  log(
12982
- `[bind-remediation] '${codeName}' NOT remediating \u2014 the last spawn was refused and no session is running (e.g. the host cannot authenticate to Claude). A re-respawn cannot bind tools when nothing can start, so this would loop without the breaker ever seeing it (ENG-8581). Fix the host, not the session.`
12989
+ `[bind-remediation] '${codeName}' NOT remediating \u2014 the last spawn was refused and no session is running, or the session is blocked on a prompt it cannot answer (e.g. the host cannot authenticate to Claude, ENG-10335). A re-respawn cannot bind tools when nothing can start, so this would loop without the breaker ever seeing it (ENG-8581). Fix the host, not the session.`
12983
12990
  );
12984
12991
  }
12985
12992
  if (shouldRemediateUnverifiedRestart(outcome, {
@@ -13016,7 +13023,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
13016
13023
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
13017
13024
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
13018
13025
  async function channelInboundActivityAgeSecondsFor(codeName) {
13019
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-3OEZ6D3O.js");
13026
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-65AHLKWV.js");
13020
13027
  const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
13021
13028
  if (newest === null) return null;
13022
13029
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -13684,7 +13691,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13684
13691
  var lastVersionCheckAt = 0;
13685
13692
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13686
13693
  var lastResponsivenessProbeAt = 0;
13687
- var agtCliVersion = true ? "0.28.886" : "dev";
13694
+ var agtCliVersion = true ? "0.28.888" : "dev";
13688
13695
  function resolveBrewPath(execFileSync2) {
13689
13696
  try {
13690
13697
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -15274,7 +15281,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
15274
15281
  if (codeNames.length === 0) return;
15275
15282
  void (async () => {
15276
15283
  try {
15277
- const { collectDiagnostics } = await import("../persistent-session-SG4HA35I.js");
15284
+ const { collectDiagnostics } = await import("../persistent-session-RFQKA2H5.js");
15278
15285
  await api.post("/host/heartbeat", {
15279
15286
  host_id: hostId,
15280
15287
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -15416,7 +15423,7 @@ async function pollCycleInner() {
15416
15423
  }
15417
15424
  try {
15418
15425
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
15419
- const { collectDiagnostics } = await import("../persistent-session-SG4HA35I.js");
15426
+ const { collectDiagnostics } = await import("../persistent-session-RFQKA2H5.js");
15420
15427
  const diagCodeNames = [...agentState.persistentSessionAgents];
15421
15428
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
15422
15429
  let tailscaleHostname;
@@ -15585,7 +15592,7 @@ async function pollCycleInner() {
15585
15592
  collectPanelessActivityProbes,
15586
15593
  getResponsivenessIntervalMs,
15587
15594
  occupancyQualificationClassifications
15588
- } = await import("../responsiveness-probe-3OEZ6D3O.js");
15595
+ } = await import("../responsiveness-probe-65AHLKWV.js");
15589
15596
  const probeIntervalMs = getResponsivenessIntervalMs();
15590
15597
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
15591
15598
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -15702,7 +15709,7 @@ async function pollCycleInner() {
15702
15709
  collectResponsivenessProbes,
15703
15710
  livePendingInboundOldestAgeSeconds,
15704
15711
  parkPendingInbound
15705
- } = await import("../responsiveness-probe-3OEZ6D3O.js");
15712
+ } = await import("../responsiveness-probe-65AHLKWV.js");
15706
15713
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
15707
15714
  const wedgeNow = /* @__PURE__ */ new Date();
15708
15715
  const liveAgents = agentState.persistentSessionAgents;
@@ -18687,6 +18694,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
18687
18694
  // reaper is the only component that knows a restart is futile, so it is
18688
18695
  // the only one that can say so.
18689
18696
  onPaneBlocked: (codeName, ctx) => {
18697
+ noteSessionBlockedOnPrompt(codeName, ctx.kind, "mcp-presence-reaper");
18690
18698
  void reportReaperEvent(
18691
18699
  agent.agent_id,
18692
18700
  "mcp-presence-reaper",
@@ -19253,7 +19261,12 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
19253
19261
  detail: `opencode serve on 127.0.0.1:${session.port ?? "?"}`
19254
19262
  };
19255
19263
  }
19256
- async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
19264
+ async function ensurePersistentSession(...args) {
19265
+ const result = await ensurePersistentSessionUnchecked(...args);
19266
+ const blocked = result.sessionHealthyAfter ? sessionBlockedOnPrompt(args[0].code_name) : null;
19267
+ return applyBlockedPromptVerdict(result, blocked);
19268
+ }
19269
+ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refreshData) {
19257
19270
  const codeName = agent.code_name;
19258
19271
  if ((agentFrameworkCache.get(codeName) ?? DEFAULT_FRAMEWORK) === "claude-code" && !isSessionHealthy(codeName)) {
19259
19272
  maybeMigrateAgentToIdKeyedLayout(agent, {
@@ -19841,7 +19854,19 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash20("sha256")
19841
19854
  `[persistent-session] Deferring ${ready.length} ready task(s) for '${codeName}' \u2014 minting a fresh session after an idle day-rollover; schedule NOT advanced, task fires on the fresh session next tick [ENG-8461]`
19842
19855
  );
19843
19856
  }
19844
- for (const task of deferReadyForUsageCap || deferReadyForRollover ? [] : ready) {
19857
+ let deferReadyForBlockedPrompt = false;
19858
+ if (!deferReadyForUsageCap && !deferReadyForRollover && ready.length > 0) {
19859
+ const blockedKind = sessionBlockedOnPrompt(codeName);
19860
+ if (blockedKind) {
19861
+ deferReadyForBlockedPrompt = true;
19862
+ if (shouldLogBlockedPrompt(codeName, "scheduled-firing")) {
19863
+ log(
19864
+ `[persistent-session] Deferring ${ready.length} ready task(s) for '${codeName}' \u2014 session is blocked on an interactive prompt (${blockedKind}) and cannot run a tool call; schedule NOT advanced, will fire once the prompt is answered (further deferrals this episode are not logged) [ENG-10335]`
19865
+ );
19866
+ }
19867
+ }
19868
+ }
19869
+ for (const task of deferReadyForUsageCap || deferReadyForRollover || deferReadyForBlockedPrompt ? [] : ready) {
19845
19870
  if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
19846
19871
  const updated = markTaskFired(codeName, task.taskId, "ok");
19847
19872
  claudeSchedulerStates.set(codeName, updated);
@@ -20103,7 +20128,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
20103
20128
  try {
20104
20129
  const freshId = rotateSessionForWedge(codeName);
20105
20130
  consecutiveWedgeCycles.delete(codeName);
20106
- const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-3OEZ6D3O.js");
20131
+ const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-65AHLKWV.js");
20107
20132
  const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
20108
20133
  const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
20109
20134
  const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
@@ -20134,14 +20159,19 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
20134
20159
  refreshData
20135
20160
  );
20136
20161
  recordSpawnOutcome(codeName, result);
20137
- if (result.decision !== "spawn" || !result.sessionHealthyAfter) {
20162
+ if (!isConfirmedRespawn(result)) {
20138
20163
  log(`[restart-lane] respawn not confirmed for '${codeName}' (decision=${result.decision}) - leaving for slow poll`);
20139
20164
  return;
20140
20165
  }
20166
+ if (result.decision === BLOCKED_ON_PROMPT_DECISION) {
20167
+ log(
20168
+ `[restart-lane] '${codeName}' respawned but is blocked on an interactive prompt - acking, not retrying: a respawn re-presents the same prompt; published unhealthy [ENG-10335]`
20169
+ );
20170
+ }
20141
20171
  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}`));
20142
20172
  void (async () => {
20143
20173
  try {
20144
- const { collectDiagnostics } = await import("../persistent-session-SG4HA35I.js");
20174
+ const { collectDiagnostics } = await import("../persistent-session-RFQKA2H5.js");
20145
20175
  await api.post("/host/heartbeat", {
20146
20176
  host_id: hostId,
20147
20177
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -20179,15 +20209,20 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
20179
20209
  refreshData
20180
20210
  );
20181
20211
  recordSpawnOutcome(codeName, result);
20182
- if (result.decision !== "spawn" || !result.sessionHealthyAfter) {
20212
+ if (!isConfirmedRespawn(result)) {
20183
20213
  log(
20184
20214
  `[fast-mcp-respawn] respawn not confirmed for '${codeName}' (decision=${result.decision}) - leaving for slow poll`
20185
20215
  );
20186
20216
  return;
20187
20217
  }
20218
+ if (result.decision === BLOCKED_ON_PROMPT_DECISION) {
20219
+ log(
20220
+ `[fast-mcp-respawn] '${codeName}' respawned but is blocked on an interactive prompt - not retrying, a respawn re-presents the same prompt; published unhealthy [ENG-10335]`
20221
+ );
20222
+ }
20188
20223
  try {
20189
20224
  const hostId = await getHostId();
20190
- const { collectDiagnostics } = await import("../persistent-session-SG4HA35I.js");
20225
+ const { collectDiagnostics } = await import("../persistent-session-RFQKA2H5.js");
20191
20226
  await api.post("/host/heartbeat", {
20192
20227
  host_id: hostId,
20193
20228
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -20583,7 +20618,13 @@ async function processDirectChatMessage(agent, msg) {
20583
20618
  );
20584
20619
  return;
20585
20620
  }
20586
- if (isSessionHealthy(agent.codeName)) {
20621
+ const blockedOnPrompt = sessionBlockedOnPrompt(agent.codeName);
20622
+ if (blockedOnPrompt && shouldLogBlockedPrompt(agent.codeName, "direct-chat")) {
20623
+ log(
20624
+ `[direct-chat] Not delivering to '${agent.codeName}' (msg=${msg.id}) \u2014 session is blocked on an interactive prompt (${blockedOnPrompt}), so nothing in-session can pull it; leaving pending for durable replay once the prompt is answered (further messages this episode are not logged) [ENG-10335]`
20625
+ );
20626
+ }
20627
+ if (!blockedOnPrompt && isSessionHealthy(agent.codeName)) {
20587
20628
  const useDoorbell = hostFlagStore().getBoolean("direct-chat-doorbell") || isolationMode(agent.codeName) === "docker";
20588
20629
  if (useDoorbell) {
20589
20630
  try {
@@ -20823,7 +20864,7 @@ async function processClaudePairSessions(agents) {
20823
20864
  killPairSession,
20824
20865
  pairTmuxSession,
20825
20866
  finalizeClaudePairOnboarding
20826
- } = await import("../claude-pair-runtime-BQGZXRPV.js");
20867
+ } = await import("../claude-pair-runtime-5UINWQ52.js");
20827
20868
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
20828
20869
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
20829
20870
  const killed = await killPairSession(pairTmuxSession(pairId));