@integrity-labs/agt-cli 0.28.409 → 0.28.410

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.
package/dist/bin/agt.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-QEWIZCQC.js";
43
+ } from "../chunk-QZEA7FWB.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -4829,7 +4829,7 @@ import { execFileSync, execSync } from "child_process";
4829
4829
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4830
4830
  import chalk18 from "chalk";
4831
4831
  import ora16 from "ora";
4832
- var cliVersion = true ? "0.28.409" : "dev";
4832
+ var cliVersion = true ? "0.28.410" : "dev";
4833
4833
  async function fetchLatestVersion() {
4834
4834
  const host2 = getHost();
4835
4835
  if (!host2) return null;
@@ -6001,7 +6001,7 @@ function handleError(err) {
6001
6001
  }
6002
6002
 
6003
6003
  // src/bin/agt.ts
6004
- var cliVersion2 = true ? "0.28.409" : "dev";
6004
+ var cliVersion2 = true ? "0.28.410" : "dev";
6005
6005
  var program = new Command();
6006
6006
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6007
6007
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -6247,7 +6247,7 @@ function requireHost() {
6247
6247
  }
6248
6248
 
6249
6249
  // src/lib/api-client.ts
6250
- var agtCliVersion = true ? "0.28.409" : "dev";
6250
+ var agtCliVersion = true ? "0.28.410" : "dev";
6251
6251
  var lastConfigHash = null;
6252
6252
  function setConfigHash(hash) {
6253
6253
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8751,4 +8751,4 @@ export {
8751
8751
  managerInstallSystemUnitCommand,
8752
8752
  managerUninstallSystemUnitCommand
8753
8753
  };
8754
- //# sourceMappingURL=chunk-QEWIZCQC.js.map
8754
+ //# sourceMappingURL=chunk-QZEA7FWB.js.map
@@ -45,7 +45,7 @@ import {
45
45
  resolveEffectivePinRaw,
46
46
  safeWriteJsonAtomic,
47
47
  setConfigHash
48
- } from "../chunk-QEWIZCQC.js";
48
+ } from "../chunk-QZEA7FWB.js";
49
49
  import {
50
50
  getProjectDir as getProjectDir2,
51
51
  getReadyTasks,
@@ -1588,6 +1588,10 @@ function decideMaintenanceWindowGate(opts) {
1588
1588
  function shouldConsumeForcedUpdate(outcome) {
1589
1589
  return outcome !== "failed";
1590
1590
  }
1591
+ var FORCED_UPDATE_DEFER_ESCALATE_AFTER = 20;
1592
+ function shouldRelaxForcedUpdateIdleGate(deferStreak) {
1593
+ return deferStreak >= FORCED_UPDATE_DEFER_ESCALATE_AFTER;
1594
+ }
1591
1595
  function decideForcedUpdate(opts) {
1592
1596
  const { requestedAt, lastProcessedAt, hostBusy } = opts;
1593
1597
  if (!requestedAt) return "none";
@@ -8931,14 +8935,20 @@ function restartGateFor(codeName, reason) {
8931
8935
  now: /* @__PURE__ */ new Date()
8932
8936
  });
8933
8937
  }
8934
- function isHostBusyForForcedUpdate() {
8938
+ function isHostBusyForForcedUpdate(opts) {
8935
8939
  const now = /* @__PURE__ */ new Date();
8936
8940
  for (const agent of state6.agents) {
8937
8941
  const decision = decideRestartGate({
8938
8942
  window: null,
8939
8943
  paneLogAgeSeconds: paneLogAgeSecondsFor(agent.codeName),
8940
8944
  transcriptAgeSeconds: transcriptAgeSecondsFor(agent.codeName),
8941
- inboundAgeSeconds: inboundAgeSecondsFor(agent.codeName),
8945
+ // ENG-8079: past the defer-streak threshold, drop the inbound-quiet axis
8946
+ // and gate on progress alone. Passing null means "no signal" for that axis
8947
+ // (see decideRestartGate), so only transcript/pane progress governs — an
8948
+ // agent mid-turn still defers, an agent that merely received a message in
8949
+ // the last 5 minutes no longer does. On a 14-agent host the inbound axis
8950
+ // is what made the gate un-satisfiable in practice.
8951
+ inboundAgeSeconds: opts?.relaxed ? null : inboundAgeSecondsFor(agent.codeName),
8942
8952
  now,
8943
8953
  env: {}
8944
8954
  });
@@ -8946,6 +8956,66 @@ function isHostBusyForForcedUpdate() {
8946
8956
  }
8947
8957
  return false;
8948
8958
  }
8959
+ function runPendingForcedUpdate() {
8960
+ const requestedUpdateAt = cachedUpdateRequestedAt;
8961
+ const relaxed = shouldRelaxForcedUpdateIdleGate(forcedUpdateDeferStreak);
8962
+ const forcedUpdate = decideForcedUpdate({
8963
+ requestedAt: requestedUpdateAt,
8964
+ lastProcessedAt: state6.lastUpdateRequestProcessedAt ?? null,
8965
+ hostBusy: isHostBusyForForcedUpdate({ relaxed })
8966
+ });
8967
+ if (forcedUpdate !== "defer-idle") forcedUpdateDeferStreak = 0;
8968
+ if (forcedUpdate === "none" || forcedUpdate === "already-handled") return false;
8969
+ if (forcedUpdate === "defer-idle") {
8970
+ forcedUpdateDeferStreak += 1;
8971
+ if (forcedUpdateDeferStreak === 1 || forcedUpdateDeferStreak % 10 === 0) {
8972
+ log(
8973
+ `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: an agent is mid-turn / recently active (consecutive defers: ${forcedUpdateDeferStreak}). Retrying next poll.`
8974
+ );
8975
+ }
8976
+ if (forcedUpdateDeferStreak === FORCED_UPDATE_DEFER_ESCALATE_AFTER) {
8977
+ log(
8978
+ `[self-update] WARN "Update CLI now" has deferred ${forcedUpdateDeferStreak} consecutive polls waiting for an idle host. Relaxing the idle gate to the progress axis only (an agent actively producing tokens still defers; "received a message in the last 5 minutes" no longer does).`
8979
+ );
8980
+ }
8981
+ return false;
8982
+ }
8983
+ if (selfUpdateInFlight) {
8984
+ log(
8985
+ `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: a self-update is already in flight. Retrying next poll.`
8986
+ );
8987
+ return false;
8988
+ }
8989
+ log(
8990
+ `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 running window-bypassing self-update now (host idle${relaxed ? ", relaxed gate" : ""}).`
8991
+ );
8992
+ const prevProcessedAt = state6.lastUpdateRequestProcessedAt ?? null;
8993
+ void checkAndUpdateCli({ force: true }).then((outcome) => {
8994
+ if (!shouldConsumeForcedUpdate(outcome)) {
8995
+ log(
8996
+ `[self-update] "Update CLI now" did not complete (no install ran) \u2014 leaving the request pending; the next idle poll retries.`
8997
+ );
8998
+ return;
8999
+ }
9000
+ log(
9001
+ outcome === "updated" ? `[self-update] "Update CLI now" completed \u2014 upgrade installed; manager restart scheduled.` : `[self-update] "Update CLI now" completed \u2014 host was already on the latest in-channel build; nothing to install.`
9002
+ );
9003
+ state6.lastUpdateRequestProcessedAt = requestedUpdateAt;
9004
+ try {
9005
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state6, null, 2));
9006
+ } catch (err) {
9007
+ state6.lastUpdateRequestProcessedAt = prevProcessedAt;
9008
+ log(
9009
+ `[self-update] failed to persist update-request ack; retrying next poll: ${err.message}`
9010
+ );
9011
+ }
9012
+ }).catch((err) => {
9013
+ log(
9014
+ `[self-update] forced check failed: ${err.message} \u2014 leaving the request pending for retry.`
9015
+ );
9016
+ });
9017
+ return true;
9018
+ }
8949
9019
  var runningMcpHashes = /* @__PURE__ */ new Map();
8950
9020
  var anchorSessionLifecycle = new AnchorSessionLifecycle();
8951
9021
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
@@ -9307,7 +9377,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9307
9377
  var lastVersionCheckAt = 0;
9308
9378
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9309
9379
  var lastResponsivenessProbeAt = 0;
9310
- var agtCliVersion = true ? "0.28.409" : "dev";
9380
+ var agtCliVersion = true ? "0.28.410" : "dev";
9311
9381
  function resolveBrewPath(execFileSync2) {
9312
9382
  try {
9313
9383
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -9776,6 +9846,8 @@ var selfUpdatePinInvalidLogged = false;
9776
9846
  var restartAfterUpgrade = false;
9777
9847
  var pendingUpgradeVersion = null;
9778
9848
  var selfUpdateInFlight = false;
9849
+ var cachedUpdateRequestedAt = null;
9850
+ var forcedUpdateDeferStreak = 0;
9779
9851
  async function checkAndUpdateCli(opts) {
9780
9852
  const force = opts?.force ?? false;
9781
9853
  if (selfUpdateInFlight) return "failed";
@@ -9954,27 +10026,41 @@ async function checkAndUpdateCliViaNpm(force = false) {
9954
10026
  );
9955
10027
  return await installAgtCliViaNpm(pinDecision.version, `pin=${pinDecision.version}`);
9956
10028
  }
9957
- let latest;
9958
- try {
9959
- const res = await fetch(
9960
- `https://registry.npmjs.org/@integrity-labs/agt-cli/${encodeURIComponent(channel)}`,
9961
- {
9962
- signal: AbortSignal.timeout(1e4),
9963
- headers: { Accept: "application/json" }
10029
+ const REGISTRY_TIMEOUT_MS = 1e4;
10030
+ const registryAttempts = force ? 2 : 1;
10031
+ let latest = null;
10032
+ let lastFetchErr = "";
10033
+ for (let attempt = 1; attempt <= registryAttempts; attempt++) {
10034
+ try {
10035
+ const res = await fetch(
10036
+ `https://registry.npmjs.org/@integrity-labs/agt-cli/${encodeURIComponent(channel)}`,
10037
+ {
10038
+ signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
10039
+ headers: { Accept: "application/json" }
10040
+ }
10041
+ );
10042
+ if (!res.ok) {
10043
+ log(`[self-update] npm registry returned ${res.status} (channel=${channel})`);
10044
+ return "failed";
10045
+ }
10046
+ const body = await res.json();
10047
+ if (!body.version) {
10048
+ log(`[self-update] npm registry response missing version field`);
10049
+ return "failed";
10050
+ }
10051
+ latest = body.version;
10052
+ break;
10053
+ } catch (err) {
10054
+ lastFetchErr = err.message;
10055
+ if (attempt < registryAttempts) {
10056
+ log(
10057
+ `[self-update] npm registry fetch failed (attempt ${attempt}/${registryAttempts}): ${lastFetchErr} \u2014 retrying.`
10058
+ );
9964
10059
  }
9965
- );
9966
- if (!res.ok) {
9967
- log(`[self-update] npm registry returned ${res.status} (channel=${channel})`);
9968
- return "failed";
9969
- }
9970
- const body = await res.json();
9971
- if (!body.version) {
9972
- log(`[self-update] npm registry response missing version field`);
9973
- return "failed";
9974
10060
  }
9975
- latest = body.version;
9976
- } catch (err) {
9977
- log(`[self-update] npm registry fetch failed: ${err.message}`);
10061
+ }
10062
+ if (latest === null) {
10063
+ log(`[self-update] npm registry fetch failed: ${lastFetchErr}`);
9978
10064
  return "failed";
9979
10065
  }
9980
10066
  const urgentTarget = await fetchUrgentDistTagVersion();
@@ -10515,7 +10601,15 @@ async function pollCycle() {
10515
10601
  } catch (err) {
10516
10602
  log(`[restart-handler] processRestartFlags threw: ${err.message}`);
10517
10603
  }
10518
- checkAndUpdateCli().catch((err) => log(`[self-update] Check failed: ${err.message}`));
10604
+ let forcedUpdateKicked = false;
10605
+ try {
10606
+ forcedUpdateKicked = runPendingForcedUpdate();
10607
+ } catch (err) {
10608
+ log(`[self-update] runPendingForcedUpdate threw: ${err.message}`);
10609
+ }
10610
+ if (!forcedUpdateKicked) {
10611
+ checkAndUpdateCli().catch((err) => log(`[self-update] Check failed: ${err.message}`));
10612
+ }
10519
10613
  maybeUpgradeClaudeCode().catch((err) => log(`[claude-code-upgrade] Check failed: ${err.message}`));
10520
10614
  try {
10521
10615
  registeredAgentsCache.clear();
@@ -10625,49 +10719,7 @@ async function pollCycle() {
10625
10719
  cachedDesiredAgtCliVersion = hbResp.desired_agt_cli_version ?? null;
10626
10720
  }
10627
10721
  }
10628
- const requestedUpdateAt = hbResp?.update_requested_at ?? null;
10629
- const forcedUpdate = decideForcedUpdate({
10630
- requestedAt: requestedUpdateAt,
10631
- lastProcessedAt: state6.lastUpdateRequestProcessedAt ?? null,
10632
- hostBusy: isHostBusyForForcedUpdate()
10633
- });
10634
- if (forcedUpdate === "defer-idle") {
10635
- log(
10636
- `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: an agent is mid-turn / recently active. Retrying next poll.`
10637
- );
10638
- } else if (forcedUpdate === "consume") {
10639
- if (selfUpdateInFlight) {
10640
- log(
10641
- `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: a self-update is already in flight. Retrying next poll.`
10642
- );
10643
- } else {
10644
- log(
10645
- `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 running window-bypassing self-update now (host idle).`
10646
- );
10647
- const prevProcessedAt = state6.lastUpdateRequestProcessedAt ?? null;
10648
- void checkAndUpdateCli({ force: true }).then((outcome) => {
10649
- if (!shouldConsumeForcedUpdate(outcome)) {
10650
- log(
10651
- `[self-update] "Update CLI now" did not complete (no install ran) \u2014 leaving the request pending; the next idle heartbeat retries.`
10652
- );
10653
- return;
10654
- }
10655
- state6.lastUpdateRequestProcessedAt = requestedUpdateAt;
10656
- try {
10657
- atomicWriteFileSync(getStateFile(), JSON.stringify(state6, null, 2));
10658
- } catch (err) {
10659
- state6.lastUpdateRequestProcessedAt = prevProcessedAt;
10660
- log(
10661
- `[self-update] failed to persist update-request ack; retrying next heartbeat: ${err.message}`
10662
- );
10663
- }
10664
- }).catch((err) => {
10665
- log(
10666
- `[self-update] forced check failed: ${err.message} \u2014 leaving the request pending for retry.`
10667
- );
10668
- });
10669
- }
10670
- }
10722
+ cachedUpdateRequestedAt = hbResp?.update_requested_at ?? null;
10671
10723
  if (hbResp?.feature_flags) {
10672
10724
  hostFlagStore().applyHeartbeat(hbResp.feature_flags, hbResp.flags_schema_version);
10673
10725
  }