@integrity-labs/agt-cli 0.28.131 → 0.28.133

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.
@@ -28,7 +28,7 @@ import {
28
28
  requireHost,
29
29
  safeWriteJsonAtomic,
30
30
  setConfigHash
31
- } from "../chunk-N5N3CA6W.js";
31
+ } from "../chunk-L3WP7Y5L.js";
32
32
  import {
33
33
  getProjectDir as getProjectDir2,
34
34
  getReadyTasks,
@@ -1676,6 +1676,18 @@ function decideMaintenanceWindowGate(opts) {
1676
1676
  if (!opts.window) return "proceed";
1677
1677
  return isWithinMaintenanceWindow(opts.window, opts.now) ? "proceed" : "defer";
1678
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
+ }
1679
1691
  function isUrgentUpgrade(opts) {
1680
1692
  if (!opts.urgentTarget) return false;
1681
1693
  if (opts.installed === "dev") return false;
@@ -6780,6 +6792,21 @@ function restartGateFor(codeName, reason) {
6780
6792
  now: /* @__PURE__ */ new Date()
6781
6793
  });
6782
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
+ }
6783
6810
  var runningMcpHashes = /* @__PURE__ */ new Map();
6784
6811
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
6785
6812
  var runningChannelSecretHashes = /* @__PURE__ */ new Map();
@@ -7040,7 +7067,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
7040
7067
  var lastVersionCheckAt = 0;
7041
7068
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
7042
7069
  var lastResponsivenessProbeAt = 0;
7043
- var agtCliVersion = true ? "0.28.131" : "dev";
7070
+ var agtCliVersion = true ? "0.28.133" : "dev";
7044
7071
  function resolveBrewPath(execFileSync4) {
7045
7072
  try {
7046
7073
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7341,7 +7368,8 @@ var selfUpdateUpToDateLogged = false;
7341
7368
  var restartAfterUpgrade = false;
7342
7369
  var pendingUpgradeVersion = null;
7343
7370
  var selfUpdateInFlight = false;
7344
- async function checkAndUpdateCli() {
7371
+ async function checkAndUpdateCli(opts) {
7372
+ const force = opts?.force ?? false;
7345
7373
  if (selfUpdateInFlight) return;
7346
7374
  selfUpdateInFlight = true;
7347
7375
  try {
@@ -7359,19 +7387,21 @@ async function checkAndUpdateCli() {
7359
7387
  if (!isBrewFormula && !isNpmGlobal) return;
7360
7388
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
7361
7389
  const markerPath = join16(homedir9(), ".augmented", ".last-update-check");
7362
- try {
7363
- const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
7364
- if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
7365
- } 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
+ }
7366
7396
  }
7367
7397
  try {
7368
7398
  writeF(markerPath, String(Date.now()));
7369
7399
  } catch {
7370
7400
  }
7371
7401
  if (isBrewFormula) {
7372
- await checkAndUpdateCliViaBrew();
7402
+ await checkAndUpdateCliViaBrew(force);
7373
7403
  } else {
7374
- await checkAndUpdateCliViaNpm();
7404
+ await checkAndUpdateCliViaNpm(force);
7375
7405
  }
7376
7406
  try {
7377
7407
  writeF(markerPath, String(Date.now()));
@@ -7381,7 +7411,7 @@ async function checkAndUpdateCli() {
7381
7411
  selfUpdateInFlight = false;
7382
7412
  }
7383
7413
  }
7384
- async function checkAndUpdateCliViaBrew() {
7414
+ async function checkAndUpdateCliViaBrew(force = false) {
7385
7415
  const { execFileSync: execFileSync4 } = await import("child_process");
7386
7416
  const brewPath = resolveBrewPath(execFileSync4);
7387
7417
  if (!brewPath) return;
@@ -7400,7 +7430,7 @@ async function checkAndUpdateCliViaBrew() {
7400
7430
  if (agtOutdated) {
7401
7431
  const installed = agtOutdated.installed_versions?.[0] ?? "unknown";
7402
7432
  const latest = agtOutdated.current_version ?? "unknown";
7403
- if (decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7433
+ if (!force && decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7404
7434
  log(
7405
7435
  `[self-update] agt CLI ${installed} \u2192 ${latest} (brew) deferred \u2014 ` + formatWindowDeferLogLine(cachedMaintenanceWindow ?? {}, /* @__PURE__ */ new Date())
7406
7436
  );
@@ -7412,7 +7442,7 @@ async function checkAndUpdateCliViaBrew() {
7412
7442
  lastAppliedMs: readLastSelfUpdateAppliedMs(selfUpdateAppliedMarkerPath()),
7413
7443
  now: Date.now()
7414
7444
  });
7415
- if (!coalesce.proceed) {
7445
+ if (!force && !coalesce.proceed) {
7416
7446
  log(formatCoalesceDeferLogLine({
7417
7447
  installed,
7418
7448
  latest,
@@ -7422,7 +7452,7 @@ async function checkAndUpdateCliViaBrew() {
7422
7452
  }));
7423
7453
  return;
7424
7454
  }
7425
- 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)" : ""}...`);
7426
7456
  try {
7427
7457
  execFileSync4(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
7428
7458
  timeout: 12e4,
@@ -7443,7 +7473,7 @@ async function checkAndUpdateCliViaBrew() {
7443
7473
  log(`[self-update] brew outdated failed: ${err.message}`);
7444
7474
  }
7445
7475
  }
7446
- async function checkAndUpdateCliViaNpm() {
7476
+ async function checkAndUpdateCliViaNpm(force = false) {
7447
7477
  if (agtCliVersion === "dev") return;
7448
7478
  const channel = process.env.AGT_CLI_RELEASE_CHANNEL || "latest";
7449
7479
  let latest;
@@ -7501,7 +7531,7 @@ async function checkAndUpdateCliViaNpm() {
7501
7531
  }
7502
7532
  return;
7503
7533
  }
7504
- if (decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7534
+ if (!force && decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() }) === "defer") {
7505
7535
  log(
7506
7536
  `[self-update] agt CLI ${agtCliVersion} \u2192 ${latest} (channel=${channel}) deferred \u2014 ` + formatWindowDeferLogLine(cachedMaintenanceWindow ?? {}, /* @__PURE__ */ new Date())
7507
7537
  );
@@ -7513,7 +7543,7 @@ async function checkAndUpdateCliViaNpm() {
7513
7543
  lastAppliedMs: readLastSelfUpdateAppliedMs(selfUpdateAppliedMarkerPath()),
7514
7544
  now: Date.now()
7515
7545
  });
7516
- if (!coalesce.proceed) {
7546
+ if (!force && !coalesce.proceed) {
7517
7547
  log(formatCoalesceDeferLogLine({
7518
7548
  installed: agtCliVersion,
7519
7549
  latest,
@@ -8239,11 +8269,53 @@ async function pollCycle() {
8239
8269
  // combines these with the org's server-resolved flags + versions into a
8240
8270
  // host_config_snapshots row (on change) so bugs correlate with config.
8241
8271
  // Allowlist-only by construction — no raw env / secrets ever sent.
8242
- 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
8243
8277
  });
8244
8278
  if (hbResp?.maintenance_window) {
8245
8279
  cachedMaintenanceWindow = hbResp.maintenance_window;
8246
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
+ }
8247
8319
  if (hbResp?.feature_flags) {
8248
8320
  hostFlagStore().applyHeartbeat(hbResp.feature_flags, hbResp.flags_schema_version);
8249
8321
  }
@@ -12475,6 +12547,12 @@ function startManager(opts) {
12475
12547
  const n = autoResumeMarkers.size;
12476
12548
  if (n > 0) log(`[startup] rehydrated ${n} auto-resume marker(s) (ENG-6088)`);
12477
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
+ }
12478
12556
  }
12479
12557
  } catch (err) {
12480
12558
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);