@integrity-labs/agt-cli 0.28.130 → 0.28.132

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-YU3FIAUK.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-6MR7EVEN.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-F5KZNGVO.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-NJDB2EPV.js.map
@@ -28,7 +28,7 @@ import {
28
28
  requireHost,
29
29
  safeWriteJsonAtomic,
30
30
  setConfigHash
31
- } from "../chunk-RTSX4A54.js";
31
+ } from "../chunk-GF2KBUVY.js";
32
32
  import {
33
33
  getProjectDir as getProjectDir2,
34
34
  getReadyTasks,
@@ -72,7 +72,7 @@ import {
72
72
  takeZombieDetection,
73
73
  transcriptActivityAgeSeconds,
74
74
  writeEgressAllowlist
75
- } from "../chunk-XBF7ACI5.js";
75
+ } from "../chunk-U3CDNNEK.js";
76
76
  import {
77
77
  FLAGS_SCHEMA_VERSION,
78
78
  FLAG_REGISTRY,
@@ -374,16 +374,38 @@ function findMcpChildrenForAgent(args) {
374
374
  return matched;
375
375
  }
376
376
  function reapStaleMcpChildren(args) {
377
- const { log: log2, codeName, serverKeys, mcpJson, graceMs = 5e3 } = args;
377
+ const { log: log2, codeName, serverKeys, mcpJson, graceMs = 5e3, isolated = false } = args;
378
378
  if (serverKeys.length === 0) return [];
379
- const runPs = args.runPs ?? (() => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
380
- const killProcess = args.killProcess ?? ((pid, signal) => {
379
+ const runPs = args.runPs ?? (isolated ? () => execFileSync("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
380
+ encoding: "utf-8",
381
+ timeout: 8e3
382
+ }) : () => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
383
+ const killProcess = args.killProcess ?? (isolated ? (pid, signal) => {
384
+ try {
385
+ execFileSync(
386
+ "docker",
387
+ ["exec", `agt-${codeName}`, "kill", signal === "SIGKILL" ? "-KILL" : "-TERM", String(pid)],
388
+ { timeout: 8e3, stdio: "ignore" }
389
+ );
390
+ } catch {
391
+ }
392
+ } : (pid, signal) => {
381
393
  try {
382
394
  process.kill(pid, signal);
383
395
  } catch {
384
396
  }
385
397
  });
386
- const isAlive = args.isAlive ?? ((pid) => {
398
+ const isAlive = args.isAlive ?? (isolated ? (pid) => {
399
+ try {
400
+ execFileSync("docker", ["exec", `agt-${codeName}`, "kill", "-0", String(pid)], {
401
+ timeout: 8e3,
402
+ stdio: "ignore"
403
+ });
404
+ return true;
405
+ } catch {
406
+ return false;
407
+ }
408
+ } : (pid) => {
387
409
  try {
388
410
  process.kill(pid, 0);
389
411
  return true;
@@ -399,7 +421,7 @@ function reapStaleMcpChildren(args) {
399
421
  return [];
400
422
  }
401
423
  const rows = parsePsRows(psOutput);
402
- const targets = findMcpChildrenForAgent({ rows, codeName, serverKeys, mcpJson });
424
+ const targets = findMcpChildrenForAgent({ rows, codeName, serverKeys, mcpJson, inContainer: isolated });
403
425
  if (targets.length === 0) return [];
404
426
  const byPid = new Map(rows.map((r) => [r.pid, r]));
405
427
  const describe = (pid) => {
@@ -437,7 +459,8 @@ function reapStaleMcpChildren(args) {
437
459
  rows: parsePsRows(freshPsOutput),
438
460
  codeName,
439
461
  serverKeys,
440
- mcpJson
462
+ mcpJson,
463
+ inContainer: isolated
441
464
  })
442
465
  );
443
466
  const stragglers = targets.filter((pid) => isAlive(pid) && stillOwned.has(pid));
@@ -1653,6 +1676,18 @@ function decideMaintenanceWindowGate(opts) {
1653
1676
  if (!opts.window) return "proceed";
1654
1677
  return isWithinMaintenanceWindow(opts.window, opts.now) ? "proceed" : "defer";
1655
1678
  }
1679
+ function decideForcedUpdate(opts) {
1680
+ const { requestedAt, lastProcessedAt, hostBusy } = opts;
1681
+ if (!requestedAt) return "none";
1682
+ const requestedMs = Date.parse(requestedAt);
1683
+ if (Number.isNaN(requestedMs)) return "none";
1684
+ if (lastProcessedAt) {
1685
+ const processedMs = Date.parse(lastProcessedAt);
1686
+ if (!Number.isNaN(processedMs) && processedMs >= requestedMs) return "already-handled";
1687
+ }
1688
+ if (hostBusy) return "defer-idle";
1689
+ return "consume";
1690
+ }
1656
1691
  function isUrgentUpgrade(opts) {
1657
1692
  if (!opts.urgentTarget) return false;
1658
1693
  if (opts.installed === "dev") return false;
@@ -6757,6 +6792,21 @@ function restartGateFor(codeName, reason) {
6757
6792
  now: /* @__PURE__ */ new Date()
6758
6793
  });
6759
6794
  }
6795
+ function isHostBusyForForcedUpdate() {
6796
+ const now = /* @__PURE__ */ new Date();
6797
+ for (const agent of state6.agents) {
6798
+ const decision = decideRestartGate({
6799
+ window: null,
6800
+ paneLogAgeSeconds: paneLogAgeSecondsFor(agent.codeName),
6801
+ transcriptAgeSeconds: transcriptAgeSecondsFor(agent.codeName),
6802
+ inboundAgeSeconds: inboundAgeSecondsFor(agent.codeName),
6803
+ now,
6804
+ env: {}
6805
+ });
6806
+ if (decision === "defer-idle") return true;
6807
+ }
6808
+ return false;
6809
+ }
6760
6810
  var runningMcpHashes = /* @__PURE__ */ new Map();
6761
6811
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
6762
6812
  var runningChannelSecretHashes = /* @__PURE__ */ new Map();
@@ -7017,7 +7067,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
7017
7067
  var lastVersionCheckAt = 0;
7018
7068
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
7019
7069
  var lastResponsivenessProbeAt = 0;
7020
- var agtCliVersion = true ? "0.28.130" : "dev";
7070
+ var agtCliVersion = true ? "0.28.132" : "dev";
7021
7071
  function resolveBrewPath(execFileSync4) {
7022
7072
  try {
7023
7073
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7318,7 +7368,8 @@ var selfUpdateUpToDateLogged = false;
7318
7368
  var restartAfterUpgrade = false;
7319
7369
  var pendingUpgradeVersion = null;
7320
7370
  var selfUpdateInFlight = false;
7321
- async function checkAndUpdateCli() {
7371
+ async function checkAndUpdateCli(opts) {
7372
+ const force = opts?.force ?? false;
7322
7373
  if (selfUpdateInFlight) return;
7323
7374
  selfUpdateInFlight = true;
7324
7375
  try {
@@ -7336,19 +7387,21 @@ async function checkAndUpdateCli() {
7336
7387
  if (!isBrewFormula && !isNpmGlobal) return;
7337
7388
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
7338
7389
  const markerPath = join16(homedir9(), ".augmented", ".last-update-check");
7339
- try {
7340
- const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
7341
- if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
7342
- } catch {
7390
+ if (!force) {
7391
+ try {
7392
+ const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
7393
+ if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
7394
+ } catch {
7395
+ }
7343
7396
  }
7344
7397
  try {
7345
7398
  writeF(markerPath, String(Date.now()));
7346
7399
  } catch {
7347
7400
  }
7348
7401
  if (isBrewFormula) {
7349
- await checkAndUpdateCliViaBrew();
7402
+ await checkAndUpdateCliViaBrew(force);
7350
7403
  } else {
7351
- await checkAndUpdateCliViaNpm();
7404
+ await checkAndUpdateCliViaNpm(force);
7352
7405
  }
7353
7406
  try {
7354
7407
  writeF(markerPath, String(Date.now()));
@@ -7358,7 +7411,7 @@ async function checkAndUpdateCli() {
7358
7411
  selfUpdateInFlight = false;
7359
7412
  }
7360
7413
  }
7361
- async function checkAndUpdateCliViaBrew() {
7414
+ async function checkAndUpdateCliViaBrew(force = false) {
7362
7415
  const { execFileSync: execFileSync4 } = await import("child_process");
7363
7416
  const brewPath = resolveBrewPath(execFileSync4);
7364
7417
  if (!brewPath) return;
@@ -7377,7 +7430,7 @@ async function checkAndUpdateCliViaBrew() {
7377
7430
  if (agtOutdated) {
7378
7431
  const installed = agtOutdated.installed_versions?.[0] ?? "unknown";
7379
7432
  const latest = agtOutdated.current_version ?? "unknown";
7380
- if (decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7433
+ if (!force && decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7381
7434
  log(
7382
7435
  `[self-update] agt CLI ${installed} \u2192 ${latest} (brew) deferred \u2014 ` + formatWindowDeferLogLine(cachedMaintenanceWindow ?? {}, /* @__PURE__ */ new Date())
7383
7436
  );
@@ -7389,7 +7442,7 @@ async function checkAndUpdateCliViaBrew() {
7389
7442
  lastAppliedMs: readLastSelfUpdateAppliedMs(selfUpdateAppliedMarkerPath()),
7390
7443
  now: Date.now()
7391
7444
  });
7392
- if (!coalesce.proceed) {
7445
+ if (!force && !coalesce.proceed) {
7393
7446
  log(formatCoalesceDeferLogLine({
7394
7447
  installed,
7395
7448
  latest,
@@ -7399,7 +7452,7 @@ async function checkAndUpdateCliViaBrew() {
7399
7452
  }));
7400
7453
  return;
7401
7454
  }
7402
- log(`[self-update] agt CLI update available: ${installed} \u2192 ${latest}. Upgrading via brew...`);
7455
+ log(`[self-update] agt CLI update available: ${installed} \u2192 ${latest}. Upgrading via brew${force ? " (forced \u2014 Update CLI now)" : ""}...`);
7403
7456
  try {
7404
7457
  execFileSync4(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
7405
7458
  timeout: 12e4,
@@ -7420,7 +7473,7 @@ async function checkAndUpdateCliViaBrew() {
7420
7473
  log(`[self-update] brew outdated failed: ${err.message}`);
7421
7474
  }
7422
7475
  }
7423
- async function checkAndUpdateCliViaNpm() {
7476
+ async function checkAndUpdateCliViaNpm(force = false) {
7424
7477
  if (agtCliVersion === "dev") return;
7425
7478
  const channel = process.env.AGT_CLI_RELEASE_CHANNEL || "latest";
7426
7479
  let latest;
@@ -7478,7 +7531,7 @@ async function checkAndUpdateCliViaNpm() {
7478
7531
  }
7479
7532
  return;
7480
7533
  }
7481
- if (decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7534
+ if (!force && decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7482
7535
  log(
7483
7536
  `[self-update] agt CLI ${agtCliVersion} \u2192 ${latest} (channel=${channel}) deferred \u2014 ` + formatWindowDeferLogLine(cachedMaintenanceWindow ?? {}, /* @__PURE__ */ new Date())
7484
7537
  );
@@ -7490,7 +7543,7 @@ async function checkAndUpdateCliViaNpm() {
7490
7543
  lastAppliedMs: readLastSelfUpdateAppliedMs(selfUpdateAppliedMarkerPath()),
7491
7544
  now: Date.now()
7492
7545
  });
7493
- if (!coalesce.proceed) {
7546
+ if (!force && !coalesce.proceed) {
7494
7547
  log(formatCoalesceDeferLogLine({
7495
7548
  installed: agtCliVersion,
7496
7549
  latest,
@@ -8144,7 +8197,7 @@ async function pollCycle() {
8144
8197
  }
8145
8198
  try {
8146
8199
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
8147
- const { collectDiagnostics } = await import("../persistent-session-YU3FIAUK.js");
8200
+ const { collectDiagnostics } = await import("../persistent-session-6MR7EVEN.js");
8148
8201
  const diagCodeNames = [...agentState.persistentSessionAgents];
8149
8202
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
8150
8203
  let tailscaleHostname;
@@ -8216,11 +8269,53 @@ async function pollCycle() {
8216
8269
  // combines these with the org's server-resolved flags + versions into a
8217
8270
  // host_config_snapshots row (on change) so bugs correlate with config.
8218
8271
  // Allowlist-only by construction — no raw env / secrets ever sent.
8219
- env_gates: collectEnvGates(process.env)
8272
+ env_gates: collectEnvGates(process.env),
8273
+ // ENG-6692: ack the last consumed "Update CLI now" timestamp so the API
8274
+ // clears hosts.update_requested_at. Echoes our persisted dedup marker;
8275
+ // null until we've ever consumed one.
8276
+ update_request_processed_at: state6.lastUpdateRequestProcessedAt ?? null
8220
8277
  });
8221
8278
  if (hbResp?.maintenance_window) {
8222
8279
  cachedMaintenanceWindow = hbResp.maintenance_window;
8223
8280
  }
8281
+ const requestedUpdateAt = hbResp?.update_requested_at ?? null;
8282
+ const forcedUpdate = decideForcedUpdate({
8283
+ requestedAt: requestedUpdateAt,
8284
+ lastProcessedAt: state6.lastUpdateRequestProcessedAt ?? null,
8285
+ hostBusy: isHostBusyForForcedUpdate()
8286
+ });
8287
+ if (forcedUpdate === "defer-idle") {
8288
+ log(
8289
+ `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: an agent is mid-turn / recently active. Retrying next poll.`
8290
+ );
8291
+ } else if (forcedUpdate === "consume") {
8292
+ if (selfUpdateInFlight) {
8293
+ log(
8294
+ `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: a self-update is already in flight. Retrying next poll.`
8295
+ );
8296
+ } else {
8297
+ const prevProcessedAt = state6.lastUpdateRequestProcessedAt ?? null;
8298
+ state6.lastUpdateRequestProcessedAt = requestedUpdateAt;
8299
+ let persisted = true;
8300
+ try {
8301
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state6, null, 2));
8302
+ } catch (err) {
8303
+ persisted = false;
8304
+ state6.lastUpdateRequestProcessedAt = prevProcessedAt;
8305
+ log(
8306
+ `[self-update] failed to persist update-request ack; retrying next heartbeat: ${err.message}`
8307
+ );
8308
+ }
8309
+ if (persisted) {
8310
+ log(
8311
+ `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 running window-bypassing self-update now (host idle).`
8312
+ );
8313
+ void checkAndUpdateCli({ force: true }).catch(
8314
+ (err) => log(`[self-update] forced check failed: ${err.message}`)
8315
+ );
8316
+ }
8317
+ }
8318
+ }
8224
8319
  if (hbResp?.feature_flags) {
8225
8320
  hostFlagStore().applyHeartbeat(hbResp.feature_flags, hbResp.flags_schema_version);
8226
8321
  }
@@ -8245,7 +8340,7 @@ async function pollCycle() {
8245
8340
  const {
8246
8341
  collectResponsivenessProbes,
8247
8342
  getResponsivenessIntervalMs
8248
- } = await import("../responsiveness-probe-TN5JW2NM.js");
8343
+ } = await import("../responsiveness-probe-GWJ6TKO2.js");
8249
8344
  const probeIntervalMs = getResponsivenessIntervalMs();
8250
8345
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
8251
8346
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -8277,7 +8372,7 @@ async function pollCycle() {
8277
8372
  collectResponsivenessProbes,
8278
8373
  livePendingInboundOldestAgeSeconds,
8279
8374
  parkPendingInbound
8280
- } = await import("../responsiveness-probe-TN5JW2NM.js");
8375
+ } = await import("../responsiveness-probe-GWJ6TKO2.js");
8281
8376
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
8282
8377
  const wedgeNow = /* @__PURE__ */ new Date();
8283
8378
  const liveAgents = agentState.persistentSessionAgents;
@@ -8550,7 +8645,9 @@ async function pollCycle() {
8550
8645
  await healthCheckGateways(agentStates);
8551
8646
  if (Date.now() - lastChannelSweepAt >= CHANNEL_SWEEP_INTERVAL_MS) {
8552
8647
  lastChannelSweepAt = Date.now();
8553
- const agentCodeNames = new Set(agentStates.map((a) => a.codeName));
8648
+ const agentCodeNames = new Set(
8649
+ agentStates.map((a) => a.codeName).filter((c) => isolationMode(c) !== "docker")
8650
+ );
8554
8651
  sweepChannelProcesses({
8555
8652
  agentCodeNames,
8556
8653
  dryRun: CHANNEL_SWEEP_DRY_RUN,
@@ -9695,7 +9792,11 @@ async function processAgent(agent, agentStates) {
9695
9792
  log,
9696
9793
  codeName: agent.code_name,
9697
9794
  serverKeys: affectedServerKeys,
9698
- mcpJson: mcpJsonForReap
9795
+ mcpJson: mcpJsonForReap,
9796
+ // ENG-6670: enumerate + signal in the container PID namespace
9797
+ // for Docker-isolated agents (host ps can't see in-container
9798
+ // children; a host kill on a container pid would be wrong).
9799
+ isolated: isolationMode(agent.code_name) === "docker"
9699
9800
  });
9700
9801
  }
9701
9802
  const names = integrations.map((i) => i.display_name || i.definition_id).join(", ");
@@ -11820,7 +11921,7 @@ async function processClaudePairSessions(agents) {
11820
11921
  killPairSession,
11821
11922
  pairTmuxSession,
11822
11923
  finalizeClaudePairOnboarding
11823
- } = await import("../claude-pair-runtime-F5KZNGVO.js");
11924
+ } = await import("../claude-pair-runtime-NJDB2EPV.js");
11824
11925
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11825
11926
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11826
11927
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -12446,6 +12547,12 @@ function startManager(opts) {
12446
12547
  const n = autoResumeMarkers.size;
12447
12548
  if (n > 0) log(`[startup] rehydrated ${n} auto-resume marker(s) (ENG-6088)`);
12448
12549
  }
12550
+ if (typeof parsed.lastUpdateRequestProcessedAt === "string" || parsed.lastUpdateRequestProcessedAt === null) {
12551
+ state6.lastUpdateRequestProcessedAt = parsed.lastUpdateRequestProcessedAt;
12552
+ if (state6.lastUpdateRequestProcessedAt) {
12553
+ log(`[startup] rehydrated update-request ack at ${state6.lastUpdateRequestProcessedAt} (ENG-6692)`);
12554
+ }
12555
+ }
12449
12556
  }
12450
12557
  } catch (err) {
12451
12558
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);