@integrity-labs/agt-cli 0.28.221 → 0.28.223

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-S2REZDHF.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-JGBNCAKI.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-U3ZFSZA2.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-VBCNGNZW.js.map
@@ -29,6 +29,7 @@ import {
29
29
  provisionChannelProgressHook,
30
30
  provisionIsolationHook,
31
31
  provisionOrientHook,
32
+ provisionPreCompactHook,
32
33
  provisionSessionStateHook,
33
34
  provisionStopHook,
34
35
  reapMissingMcpSessions,
@@ -36,7 +37,7 @@ import {
36
37
  requireHost,
37
38
  safeWriteJsonAtomic,
38
39
  setConfigHash
39
- } from "../chunk-SMV5PL54.js";
40
+ } from "../chunk-7GJGGLKZ.js";
40
41
  import {
41
42
  getProjectDir as getProjectDir2,
42
43
  getReadyTasks,
@@ -121,7 +122,7 @@ import {
121
122
  takeZombieDetection,
122
123
  transcriptActivityAgeSeconds,
123
124
  writeEgressAllowlist
124
- } from "../chunk-M2PGJQP3.js";
125
+ } from "../chunk-MJ2TQQOO.js";
125
126
  import {
126
127
  reapOrphanChannelMcps
127
128
  } from "../chunk-XWVM4KPK.js";
@@ -5108,8 +5109,9 @@ function startRealtimeDrift(config2) {
5108
5109
  });
5109
5110
  log2(`[realtime] Subscribing to agent_doc_versions for ${agentIds.length} agent(s)`);
5110
5111
  }
5112
+ var restartRequestFingerprint = /* @__PURE__ */ new Map();
5111
5113
  function startRealtimeAssignments(config2) {
5112
- const { hostId, onAssign, onUnassign, log: log2 } = config2;
5114
+ const { hostId, onAssign, onUnassign, onRestartRequested, log: log2 } = config2;
5113
5115
  const sb = ensureClient(config2);
5114
5116
  assignChannel = sb.channel("assignment-realtime").on("postgres_changes", {
5115
5117
  event: "INSERT",
@@ -5120,6 +5122,22 @@ function startRealtimeAssignments(config2) {
5120
5122
  const row = payload.new;
5121
5123
  log2(`[realtime] Agent assigned: ${row.agent_id} to host ${row.host_id}`);
5122
5124
  onAssign(row);
5125
+ }).on("postgres_changes", {
5126
+ event: "UPDATE",
5127
+ schema: "public",
5128
+ table: "host_agents",
5129
+ filter: `host_id=eq.${hostId}`
5130
+ }, (payload) => {
5131
+ const row = payload.new;
5132
+ const agentId = row.agent_id;
5133
+ if (!agentId) return;
5134
+ const requestedAt = row.restart_requested_at ?? null;
5135
+ const prev = restartRequestFingerprint.get(agentId);
5136
+ restartRequestFingerprint.set(agentId, requestedAt);
5137
+ if (requestedAt && requestedAt !== prev && onRestartRequested) {
5138
+ log2(`[realtime] Restart requested for ${agentId} at ${requestedAt}`);
5139
+ onRestartRequested({ agent_id: agentId, restart_requested_at: requestedAt });
5140
+ }
5123
5141
  }).on("postgres_changes", {
5124
5142
  event: "DELETE",
5125
5143
  schema: "public",
@@ -6224,7 +6242,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6224
6242
  var lastVersionCheckAt = 0;
6225
6243
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6226
6244
  var lastResponsivenessProbeAt = 0;
6227
- var agtCliVersion = true ? "0.28.221" : "dev";
6245
+ var agtCliVersion = true ? "0.28.223" : "dev";
6228
6246
  function resolveBrewPath(execFileSync2) {
6229
6247
  try {
6230
6248
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7133,7 +7151,7 @@ async function pollCycle() {
7133
7151
  }
7134
7152
  try {
7135
7153
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7136
- const { collectDiagnostics } = await import("../persistent-session-S2REZDHF.js");
7154
+ const { collectDiagnostics } = await import("../persistent-session-JGBNCAKI.js");
7137
7155
  const diagCodeNames = [...agentState.persistentSessionAgents];
7138
7156
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7139
7157
  let tailscaleHostname;
@@ -7281,7 +7299,7 @@ async function pollCycle() {
7281
7299
  const {
7282
7300
  collectResponsivenessProbes,
7283
7301
  getResponsivenessIntervalMs
7284
- } = await import("../responsiveness-probe-BHFLFXY5.js");
7302
+ } = await import("../responsiveness-probe-3AYQX6CL.js");
7285
7303
  const probeIntervalMs = getResponsivenessIntervalMs();
7286
7304
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7287
7305
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7313,7 +7331,7 @@ async function pollCycle() {
7313
7331
  collectResponsivenessProbes,
7314
7332
  livePendingInboundOldestAgeSeconds,
7315
7333
  parkPendingInbound
7316
- } = await import("../responsiveness-probe-BHFLFXY5.js");
7334
+ } = await import("../responsiveness-probe-3AYQX6CL.js");
7317
7335
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7318
7336
  const wedgeNow = /* @__PURE__ */ new Date();
7319
7337
  const liveAgents = agentState.persistentSessionAgents;
@@ -7486,6 +7504,7 @@ async function pollCycle() {
7486
7504
  for (const agent of agents) {
7487
7505
  const requested = agent.restart_requested_at ?? null;
7488
7506
  if (!requested) continue;
7507
+ if (restartInFlight.has(agent.agent_id)) continue;
7489
7508
  const prev = state6.agents.find((a) => a.agentId === agent.agent_id);
7490
7509
  const lastProcessed = prev?.lastRestartProcessedAt ?? null;
7491
7510
  const alreadyServiced = lastProcessed != null && Date.parse(lastProcessed) >= Date.parse(requested);
@@ -7517,6 +7536,13 @@ async function pollCycle() {
7517
7536
  activeChannels.clear();
7518
7537
  const agentStates = [];
7519
7538
  for (const agent of agents) {
7539
+ if (restartInFlight.has(agent.agent_id)) {
7540
+ const existing = state6.agents.find((a) => a.agentId === agent.agent_id);
7541
+ if (existing) {
7542
+ agentStates.push(existing);
7543
+ continue;
7544
+ }
7545
+ }
7520
7546
  try {
7521
7547
  await processAgent(agent, agentStates);
7522
7548
  } catch (err) {
@@ -7560,7 +7586,7 @@ async function pollCycle() {
7560
7586
  if (restartedCodeNames.length > 0) {
7561
7587
  void (async () => {
7562
7588
  try {
7563
- const { collectDiagnostics } = await import("../persistent-session-S2REZDHF.js");
7589
+ const { collectDiagnostics } = await import("../persistent-session-JGBNCAKI.js");
7564
7590
  const freshDiagnostics = collectDiagnostics(restartedCodeNames);
7565
7591
  await api.post("/host/heartbeat", {
7566
7592
  host_id: hostId,
@@ -9751,6 +9777,11 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash10("sha256")
9751
9777
  } catch (err) {
9752
9778
  log(`[persistent-session] Failed to provision session-state hook for '${codeName}': ${err.message}`);
9753
9779
  }
9780
+ try {
9781
+ provisionPreCompactHook(codeName);
9782
+ } catch (err) {
9783
+ log(`[persistent-session] Failed to provision PreCompact hook for '${codeName}': ${err.message}`);
9784
+ }
9754
9785
  const sessionRunResult = await startRun({
9755
9786
  agent_id: agent.agent_id,
9756
9787
  source_type: "system",
@@ -9989,6 +10020,66 @@ function ensureRealtimeDriftStarted(agentStates) {
9989
10020
  log(`[realtime] Drift subscription failed: ${err.message}`);
9990
10021
  });
9991
10022
  }
10023
+ var restartInFlight = /* @__PURE__ */ new Set();
10024
+ async function handleRestartDoorbell(agentId, requestedAt) {
10025
+ if (!hostFlagStore().getBoolean("restart-doorbell")) return;
10026
+ if (restartInFlight.has(agentId)) return;
10027
+ const prev = state6.agents.find((a) => a.agentId === agentId);
10028
+ const codeName = prev?.codeName;
10029
+ if (!codeName) return;
10030
+ const lastProcessed = prev?.lastRestartProcessedAt ?? null;
10031
+ if (lastProcessed != null && Date.parse(lastProcessed) >= Date.parse(requestedAt)) return;
10032
+ restartInFlight.add(agentId);
10033
+ try {
10034
+ log(`[restart-lane] Fast restart for '${codeName}' at ${requestedAt}`);
10035
+ const hostId = await getHostId();
10036
+ let refreshData;
10037
+ try {
10038
+ refreshData = await api.post("/host/refresh", { agent_id: agentId });
10039
+ } catch (err) {
10040
+ log(`[restart-lane] refresh failed for '${codeName}', leaving for slow poll: ${err.message}`);
10041
+ return;
10042
+ }
10043
+ const displayName = refreshData.agent?.display_name ?? codeName;
10044
+ try {
10045
+ const { execSync: es } = await import("child_process");
10046
+ es(`tmux kill-session -t agt-${codeName} 2>/dev/null`, { stdio: "ignore" });
10047
+ } catch {
10048
+ }
10049
+ stopPersistentSessionAndForgetMcpBaseline(codeName);
10050
+ const result = await ensurePersistentSession(
10051
+ { agent_id: agentId, code_name: codeName, display_name: displayName },
10052
+ [],
10053
+ [],
10054
+ refreshData
10055
+ );
10056
+ if (result.decision !== "spawn" || !result.sessionHealthyAfter) {
10057
+ log(`[restart-lane] respawn not confirmed for '${codeName}' (decision=${result.decision}) - leaving for slow poll`);
10058
+ return;
10059
+ }
10060
+ 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}`));
10061
+ void (async () => {
10062
+ try {
10063
+ const { collectDiagnostics } = await import("../persistent-session-JGBNCAKI.js");
10064
+ await api.post("/host/heartbeat", {
10065
+ host_id: hostId,
10066
+ agent_diagnostics: collectDiagnostics([codeName])
10067
+ });
10068
+ } catch (err) {
10069
+ log(`[restart-lane] post-respawn diagnostics flush failed for '${codeName}': ${err.message}`);
10070
+ }
10071
+ })();
10072
+ prev.lastRestartProcessedAt = requestedAt;
10073
+ try {
10074
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state6, null, 2));
10075
+ } catch (err) {
10076
+ log(`[restart-lane] failed to persist ack for '${codeName}': ${err.message}`);
10077
+ }
10078
+ log(`[restart-lane] '${codeName}' respawned via fast lane`);
10079
+ } finally {
10080
+ restartInFlight.delete(agentId);
10081
+ }
10082
+ }
9992
10083
  function ensureRealtimeAssignStarted(agentStates) {
9993
10084
  if (realtimeAssignStarted) return;
9994
10085
  const apiKey = process.env["AGT_API_KEY"];
@@ -10000,6 +10091,18 @@ function ensureRealtimeAssignStarted(agentStates) {
10000
10091
  supabaseAnonKey: exchange.supabaseAnonKey,
10001
10092
  token: exchange.token,
10002
10093
  hostId: exchange.hostId,
10094
+ // ENG-7335: fast-restart doorbell. Fires the narrow lane; the lane itself is
10095
+ // flag-gated and backstopped by the slow poll, so wiring it unconditionally
10096
+ // is safe (a no-op when the flag is off).
10097
+ onRestartRequested: (payload) => {
10098
+ void handleRestartDoorbell(payload.agent_id, payload.restart_requested_at).catch(
10099
+ (err) => (
10100
+ // Never let a fast-lane failure become an unhandled rejection - the slow
10101
+ // poll backstop re-services the (still-set) restart_requested_at.
10102
+ log(`[restart-lane] doorbell handler failed for ${payload.agent_id}: ${err.message}`)
10103
+ )
10104
+ );
10105
+ },
10003
10106
  onAssign: (payload) => {
10004
10107
  log(`[realtime] Agent ${payload.agent_id} assigned \u2014 will pick up next cycle`);
10005
10108
  markAgentForFreshMemorySync(payload.agent_id);
@@ -10351,7 +10454,7 @@ async function processClaudePairSessions(agents) {
10351
10454
  killPairSession,
10352
10455
  pairTmuxSession,
10353
10456
  finalizeClaudePairOnboarding
10354
- } = await import("../claude-pair-runtime-U3ZFSZA2.js");
10457
+ } = await import("../claude-pair-runtime-VBCNGNZW.js");
10355
10458
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
10356
10459
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
10357
10460
  const killed = await killPairSession(pairTmuxSession(pairId));