@integrity-labs/agt-cli 0.28.220 → 0.28.222

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.
@@ -18,7 +18,7 @@ import {
18
18
  resolveConnectivityProbe,
19
19
  worseConnectivityOutcome,
20
20
  wrapScheduledTaskPrompt
21
- } from "./chunk-M2PGJQP3.js";
21
+ } from "./chunk-B3E4B7JF.js";
22
22
  import {
23
23
  parsePsRows
24
24
  } from "./chunk-XWVM4KPK.js";
@@ -5529,7 +5529,7 @@ function requireHost() {
5529
5529
  }
5530
5530
 
5531
5531
  // src/lib/api-client.ts
5532
- var agtCliVersion = true ? "0.28.220" : "dev";
5532
+ var agtCliVersion = true ? "0.28.222" : "dev";
5533
5533
  var lastConfigHash = null;
5534
5534
  function setConfigHash(hash) {
5535
5535
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7581,4 +7581,4 @@ export {
7581
7581
  managerInstallSystemUnitCommand,
7582
7582
  managerUninstallSystemUnitCommand
7583
7583
  };
7584
- //# sourceMappingURL=chunk-QLNXRQAV.js.map
7584
+ //# sourceMappingURL=chunk-XNMPRL76.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-S2REZDHF.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-M4ZTLCDP.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-AEPVKQNP.js.map
@@ -36,7 +36,7 @@ import {
36
36
  requireHost,
37
37
  safeWriteJsonAtomic,
38
38
  setConfigHash
39
- } from "../chunk-QLNXRQAV.js";
39
+ } from "../chunk-XNMPRL76.js";
40
40
  import {
41
41
  getProjectDir as getProjectDir2,
42
42
  getReadyTasks,
@@ -121,7 +121,7 @@ import {
121
121
  takeZombieDetection,
122
122
  transcriptActivityAgeSeconds,
123
123
  writeEgressAllowlist
124
- } from "../chunk-M2PGJQP3.js";
124
+ } from "../chunk-B3E4B7JF.js";
125
125
  import {
126
126
  reapOrphanChannelMcps
127
127
  } from "../chunk-XWVM4KPK.js";
@@ -5108,8 +5108,9 @@ function startRealtimeDrift(config2) {
5108
5108
  });
5109
5109
  log2(`[realtime] Subscribing to agent_doc_versions for ${agentIds.length} agent(s)`);
5110
5110
  }
5111
+ var restartRequestFingerprint = /* @__PURE__ */ new Map();
5111
5112
  function startRealtimeAssignments(config2) {
5112
- const { hostId, onAssign, onUnassign, log: log2 } = config2;
5113
+ const { hostId, onAssign, onUnassign, onRestartRequested, log: log2 } = config2;
5113
5114
  const sb = ensureClient(config2);
5114
5115
  assignChannel = sb.channel("assignment-realtime").on("postgres_changes", {
5115
5116
  event: "INSERT",
@@ -5120,6 +5121,22 @@ function startRealtimeAssignments(config2) {
5120
5121
  const row = payload.new;
5121
5122
  log2(`[realtime] Agent assigned: ${row.agent_id} to host ${row.host_id}`);
5122
5123
  onAssign(row);
5124
+ }).on("postgres_changes", {
5125
+ event: "UPDATE",
5126
+ schema: "public",
5127
+ table: "host_agents",
5128
+ filter: `host_id=eq.${hostId}`
5129
+ }, (payload) => {
5130
+ const row = payload.new;
5131
+ const agentId = row.agent_id;
5132
+ if (!agentId) return;
5133
+ const requestedAt = row.restart_requested_at ?? null;
5134
+ const prev = restartRequestFingerprint.get(agentId);
5135
+ restartRequestFingerprint.set(agentId, requestedAt);
5136
+ if (requestedAt && requestedAt !== prev && onRestartRequested) {
5137
+ log2(`[realtime] Restart requested for ${agentId} at ${requestedAt}`);
5138
+ onRestartRequested({ agent_id: agentId, restart_requested_at: requestedAt });
5139
+ }
5123
5140
  }).on("postgres_changes", {
5124
5141
  event: "DELETE",
5125
5142
  schema: "public",
@@ -6224,7 +6241,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6224
6241
  var lastVersionCheckAt = 0;
6225
6242
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6226
6243
  var lastResponsivenessProbeAt = 0;
6227
- var agtCliVersion = true ? "0.28.220" : "dev";
6244
+ var agtCliVersion = true ? "0.28.222" : "dev";
6228
6245
  function resolveBrewPath(execFileSync2) {
6229
6246
  try {
6230
6247
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7133,7 +7150,7 @@ async function pollCycle() {
7133
7150
  }
7134
7151
  try {
7135
7152
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7136
- const { collectDiagnostics } = await import("../persistent-session-S2REZDHF.js");
7153
+ const { collectDiagnostics } = await import("../persistent-session-M4ZTLCDP.js");
7137
7154
  const diagCodeNames = [...agentState.persistentSessionAgents];
7138
7155
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7139
7156
  let tailscaleHostname;
@@ -7281,7 +7298,7 @@ async function pollCycle() {
7281
7298
  const {
7282
7299
  collectResponsivenessProbes,
7283
7300
  getResponsivenessIntervalMs
7284
- } = await import("../responsiveness-probe-BHFLFXY5.js");
7301
+ } = await import("../responsiveness-probe-E25HFGJL.js");
7285
7302
  const probeIntervalMs = getResponsivenessIntervalMs();
7286
7303
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7287
7304
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7313,7 +7330,7 @@ async function pollCycle() {
7313
7330
  collectResponsivenessProbes,
7314
7331
  livePendingInboundOldestAgeSeconds,
7315
7332
  parkPendingInbound
7316
- } = await import("../responsiveness-probe-BHFLFXY5.js");
7333
+ } = await import("../responsiveness-probe-E25HFGJL.js");
7317
7334
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7318
7335
  const wedgeNow = /* @__PURE__ */ new Date();
7319
7336
  const liveAgents = agentState.persistentSessionAgents;
@@ -7486,6 +7503,7 @@ async function pollCycle() {
7486
7503
  for (const agent of agents) {
7487
7504
  const requested = agent.restart_requested_at ?? null;
7488
7505
  if (!requested) continue;
7506
+ if (restartInFlight.has(agent.agent_id)) continue;
7489
7507
  const prev = state6.agents.find((a) => a.agentId === agent.agent_id);
7490
7508
  const lastProcessed = prev?.lastRestartProcessedAt ?? null;
7491
7509
  const alreadyServiced = lastProcessed != null && Date.parse(lastProcessed) >= Date.parse(requested);
@@ -7517,6 +7535,13 @@ async function pollCycle() {
7517
7535
  activeChannels.clear();
7518
7536
  const agentStates = [];
7519
7537
  for (const agent of agents) {
7538
+ if (restartInFlight.has(agent.agent_id)) {
7539
+ const existing = state6.agents.find((a) => a.agentId === agent.agent_id);
7540
+ if (existing) {
7541
+ agentStates.push(existing);
7542
+ continue;
7543
+ }
7544
+ }
7520
7545
  try {
7521
7546
  await processAgent(agent, agentStates);
7522
7547
  } catch (err) {
@@ -7560,7 +7585,7 @@ async function pollCycle() {
7560
7585
  if (restartedCodeNames.length > 0) {
7561
7586
  void (async () => {
7562
7587
  try {
7563
- const { collectDiagnostics } = await import("../persistent-session-S2REZDHF.js");
7588
+ const { collectDiagnostics } = await import("../persistent-session-M4ZTLCDP.js");
7564
7589
  const freshDiagnostics = collectDiagnostics(restartedCodeNames);
7565
7590
  await api.post("/host/heartbeat", {
7566
7591
  host_id: hostId,
@@ -9989,6 +10014,66 @@ function ensureRealtimeDriftStarted(agentStates) {
9989
10014
  log(`[realtime] Drift subscription failed: ${err.message}`);
9990
10015
  });
9991
10016
  }
10017
+ var restartInFlight = /* @__PURE__ */ new Set();
10018
+ async function handleRestartDoorbell(agentId, requestedAt) {
10019
+ if (!hostFlagStore().getBoolean("restart-doorbell")) return;
10020
+ if (restartInFlight.has(agentId)) return;
10021
+ const prev = state6.agents.find((a) => a.agentId === agentId);
10022
+ const codeName = prev?.codeName;
10023
+ if (!codeName) return;
10024
+ const lastProcessed = prev?.lastRestartProcessedAt ?? null;
10025
+ if (lastProcessed != null && Date.parse(lastProcessed) >= Date.parse(requestedAt)) return;
10026
+ restartInFlight.add(agentId);
10027
+ try {
10028
+ log(`[restart-lane] Fast restart for '${codeName}' at ${requestedAt}`);
10029
+ const hostId = await getHostId();
10030
+ let refreshData;
10031
+ try {
10032
+ refreshData = await api.post("/host/refresh", { agent_id: agentId });
10033
+ } catch (err) {
10034
+ log(`[restart-lane] refresh failed for '${codeName}', leaving for slow poll: ${err.message}`);
10035
+ return;
10036
+ }
10037
+ const displayName = refreshData.agent?.display_name ?? codeName;
10038
+ try {
10039
+ const { execSync: es } = await import("child_process");
10040
+ es(`tmux kill-session -t agt-${codeName} 2>/dev/null`, { stdio: "ignore" });
10041
+ } catch {
10042
+ }
10043
+ stopPersistentSessionAndForgetMcpBaseline(codeName);
10044
+ const result = await ensurePersistentSession(
10045
+ { agent_id: agentId, code_name: codeName, display_name: displayName },
10046
+ [],
10047
+ [],
10048
+ refreshData
10049
+ );
10050
+ if (result.decision !== "spawn" || !result.sessionHealthyAfter) {
10051
+ log(`[restart-lane] respawn not confirmed for '${codeName}' (decision=${result.decision}) - leaving for slow poll`);
10052
+ return;
10053
+ }
10054
+ 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}`));
10055
+ void (async () => {
10056
+ try {
10057
+ const { collectDiagnostics } = await import("../persistent-session-M4ZTLCDP.js");
10058
+ await api.post("/host/heartbeat", {
10059
+ host_id: hostId,
10060
+ agent_diagnostics: collectDiagnostics([codeName])
10061
+ });
10062
+ } catch (err) {
10063
+ log(`[restart-lane] post-respawn diagnostics flush failed for '${codeName}': ${err.message}`);
10064
+ }
10065
+ })();
10066
+ prev.lastRestartProcessedAt = requestedAt;
10067
+ try {
10068
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state6, null, 2));
10069
+ } catch (err) {
10070
+ log(`[restart-lane] failed to persist ack for '${codeName}': ${err.message}`);
10071
+ }
10072
+ log(`[restart-lane] '${codeName}' respawned via fast lane`);
10073
+ } finally {
10074
+ restartInFlight.delete(agentId);
10075
+ }
10076
+ }
9992
10077
  function ensureRealtimeAssignStarted(agentStates) {
9993
10078
  if (realtimeAssignStarted) return;
9994
10079
  const apiKey = process.env["AGT_API_KEY"];
@@ -10000,6 +10085,18 @@ function ensureRealtimeAssignStarted(agentStates) {
10000
10085
  supabaseAnonKey: exchange.supabaseAnonKey,
10001
10086
  token: exchange.token,
10002
10087
  hostId: exchange.hostId,
10088
+ // ENG-7335: fast-restart doorbell. Fires the narrow lane; the lane itself is
10089
+ // flag-gated and backstopped by the slow poll, so wiring it unconditionally
10090
+ // is safe (a no-op when the flag is off).
10091
+ onRestartRequested: (payload) => {
10092
+ void handleRestartDoorbell(payload.agent_id, payload.restart_requested_at).catch(
10093
+ (err) => (
10094
+ // Never let a fast-lane failure become an unhandled rejection - the slow
10095
+ // poll backstop re-services the (still-set) restart_requested_at.
10096
+ log(`[restart-lane] doorbell handler failed for ${payload.agent_id}: ${err.message}`)
10097
+ )
10098
+ );
10099
+ },
10003
10100
  onAssign: (payload) => {
10004
10101
  log(`[realtime] Agent ${payload.agent_id} assigned \u2014 will pick up next cycle`);
10005
10102
  markAgentForFreshMemorySync(payload.agent_id);
@@ -10351,7 +10448,7 @@ async function processClaudePairSessions(agents) {
10351
10448
  killPairSession,
10352
10449
  pairTmuxSession,
10353
10450
  finalizeClaudePairOnboarding
10354
- } = await import("../claude-pair-runtime-U3ZFSZA2.js");
10451
+ } = await import("../claude-pair-runtime-AEPVKQNP.js");
10355
10452
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
10356
10453
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
10357
10454
  const killed = await killPairSession(pairTmuxSession(pairId));