@integrity-labs/agt-cli 0.28.978 → 0.28.979

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-7DI7HSGB.js";
43
+ } from "../chunk-4K6ZLKIZ.js";
44
44
  import {
45
45
  getProjectDir,
46
46
  isSessionResumeDisabled,
@@ -5471,7 +5471,7 @@ import { execFileSync, execSync } from "child_process";
5471
5471
  import { existsSync as existsSync11, realpathSync as realpathSync2 } from "fs";
5472
5472
  import chalk18 from "chalk";
5473
5473
  import ora16 from "ora";
5474
- var cliVersion = true ? "0.28.978" : "dev";
5474
+ var cliVersion = true ? "0.28.979" : "dev";
5475
5475
  async function fetchLatestVersion() {
5476
5476
  const host2 = getHost();
5477
5477
  if (!host2) return null;
@@ -6731,7 +6731,7 @@ function handleError(err) {
6731
6731
  }
6732
6732
 
6733
6733
  // src/bin/agt.ts
6734
- var cliVersion2 = true ? "0.28.978" : "dev";
6734
+ var cliVersion2 = true ? "0.28.979" : "dev";
6735
6735
  var program = new Command();
6736
6736
  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");
6737
6737
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -6967,7 +6967,7 @@ function exchangeFailureKind(err) {
6967
6967
  }
6968
6968
 
6969
6969
  // src/lib/api-client.ts
6970
- var agtCliVersion = true ? "0.28.978" : "dev";
6970
+ var agtCliVersion = true ? "0.28.979" : "dev";
6971
6971
  var lastConfigHash = null;
6972
6972
  function setConfigHash(hash) {
6973
6973
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -11709,4 +11709,4 @@ export {
11709
11709
  managerInstallSystemUnitCommand,
11710
11710
  managerUninstallSystemUnitCommand
11711
11711
  };
11712
- //# sourceMappingURL=chunk-7DI7HSGB.js.map
11712
+ //# sourceMappingURL=chunk-4K6ZLKIZ.js.map
@@ -63,7 +63,7 @@ import {
63
63
  safeWriteJsonAtomic,
64
64
  setConfigHash,
65
65
  tripClass
66
- } from "../chunk-7DI7HSGB.js";
66
+ } from "../chunk-4K6ZLKIZ.js";
67
67
  import {
68
68
  getProjectDir as getProjectDir2,
69
69
  getReadyTasks,
@@ -246,7 +246,7 @@ import {
246
246
 
247
247
  // src/lib/manager-worker.ts
248
248
  import { createHash as createHash20 } from "crypto";
249
- import { readFileSync as readFileSync33, writeFileSync as writeFileSync18, mkdirSync as mkdirSync15, existsSync as existsSync19, rmSync as rmSync8, readdirSync as readdirSync12, statSync as statSync12, unlinkSync as unlinkSync6, renameSync as renameSync11, utimesSync as utimesSync4 } from "fs";
249
+ import { readFileSync as readFileSync33, writeFileSync as writeFileSync18, mkdirSync as mkdirSync15, existsSync as existsSync19, rmSync as rmSync8, readdirSync as readdirSync12, statSync as statSync13, unlinkSync as unlinkSync6, renameSync as renameSync11, utimesSync as utimesSync4 } from "fs";
250
250
 
251
251
  // src/lib/atomic-file-replace.ts
252
252
  import { copyFileSync, renameSync, unlinkSync } from "fs";
@@ -5605,6 +5605,36 @@ function bundleFingerprint(files) {
5605
5605
  return sorted.map((f) => `${f.relativePath}\0${f.content}`).join("");
5606
5606
  }
5607
5607
 
5608
+ // src/lib/self-update-device-state-hold.ts
5609
+ import { statSync as statSync5 } from "fs";
5610
+ import { platform as osPlatform } from "os";
5611
+ function realStat(path) {
5612
+ try {
5613
+ return { isFile: statSync5(path).isFile() };
5614
+ } catch (err) {
5615
+ return { errno: err?.code ?? "UNKNOWN" };
5616
+ }
5617
+ }
5618
+ function deviceStateHoldApplies(inputs) {
5619
+ const { authMode, credentialPaths } = inputs;
5620
+ const platform4 = inputs.platform ?? osPlatform;
5621
+ const statPath = inputs.statPath ?? realStat;
5622
+ if (authMode === null) return { applies: true, because: "mode-unknown" };
5623
+ if (authMode !== "subscription") return { applies: true, because: "non-subscription-mode" };
5624
+ if (platform4() === "darwin") return { applies: true, because: "platform-opaque" };
5625
+ let sawUnknownError = false;
5626
+ for (const path of credentialPaths) {
5627
+ const result = statPath(path);
5628
+ if ("isFile" in result) {
5629
+ if (result.isFile) return { applies: true, because: "paired" };
5630
+ continue;
5631
+ }
5632
+ if (result.errno !== "ENOENT") sawUnknownError = true;
5633
+ }
5634
+ if (sawUnknownError) return { applies: true, because: "credentials-unreadable" };
5635
+ return { applies: false, because: "never-paired" };
5636
+ }
5637
+
5608
5638
  // src/lib/channel-config-hash.ts
5609
5639
  import { createHash as createHash8 } from "crypto";
5610
5640
  var DERIVED_PRINCIPAL_ID_LIST_KEYS = [
@@ -5659,7 +5689,7 @@ import {
5659
5689
  readdirSync as readdirSync5,
5660
5690
  renameSync as renameSync5,
5661
5691
  rmSync as rmSync3,
5662
- statSync as statSync5,
5692
+ statSync as statSync6,
5663
5693
  utimesSync,
5664
5694
  writeFileSync as writeFileSync8
5665
5695
  } from "fs";
@@ -5708,7 +5738,7 @@ function sweepKnowledgeCache(cacheDir, now = Date.now()) {
5708
5738
  for (const name of readdirSync5(cacheDir)) {
5709
5739
  const path = join24(cacheDir, name);
5710
5740
  try {
5711
- if (now - statSync5(path).mtimeMs > CACHE_TTL_MS) rmSync3(path, { force: true });
5741
+ if (now - statSync6(path).mtimeMs > CACHE_TTL_MS) rmSync3(path, { force: true });
5712
5742
  } catch {
5713
5743
  }
5714
5744
  }
@@ -5762,7 +5792,7 @@ import {
5762
5792
  readdirSync as readdirSync6,
5763
5793
  renameSync as renameSync6,
5764
5794
  rmSync as rmSync4,
5765
- statSync as statSync6,
5795
+ statSync as statSync7,
5766
5796
  utimesSync as utimesSync2,
5767
5797
  writeFileSync as writeFileSync9
5768
5798
  } from "fs";
@@ -5811,7 +5841,7 @@ function sweepMemoryCache(cacheDir, now = Date.now()) {
5811
5841
  for (const name of readdirSync6(cacheDir)) {
5812
5842
  const path = join25(cacheDir, name);
5813
5843
  try {
5814
- if (now - statSync6(path).mtimeMs > CACHE_TTL_MS2) rmSync4(path, { force: true });
5844
+ if (now - statSync7(path).mtimeMs > CACHE_TTL_MS2) rmSync4(path, { force: true });
5815
5845
  } catch {
5816
5846
  }
5817
5847
  }
@@ -5871,7 +5901,7 @@ import {
5871
5901
  readdirSync as readdirSync7,
5872
5902
  renameSync as renameSync7,
5873
5903
  rmSync as rmSync5,
5874
- statSync as statSync7,
5904
+ statSync as statSync8,
5875
5905
  utimesSync as utimesSync3,
5876
5906
  writeFileSync as writeFileSync10
5877
5907
  } from "fs";
@@ -5920,7 +5950,7 @@ function sweepSkillCache(cacheDir, now = Date.now()) {
5920
5950
  for (const name of readdirSync7(cacheDir)) {
5921
5951
  const path = join26(cacheDir, name);
5922
5952
  try {
5923
- if (now - statSync7(path).mtimeMs > CACHE_TTL_MS3) rmSync5(path, { force: true });
5953
+ if (now - statSync8(path).mtimeMs > CACHE_TTL_MS3) rmSync5(path, { force: true });
5924
5954
  } catch {
5925
5955
  }
5926
5956
  }
@@ -6425,7 +6455,7 @@ function pruneStuckStreaksToAgents(maps, activeAgentIds) {
6425
6455
  }
6426
6456
 
6427
6457
  // src/lib/claude-device-state.ts
6428
- import { readFileSync as readFileSync24, statSync as statSync8 } from "fs";
6458
+ import { readFileSync as readFileSync24, statSync as statSync9 } from "fs";
6429
6459
  import { homedir as homedir13 } from "os";
6430
6460
  import { join as join30 } from "path";
6431
6461
  function claudeDeviceStatePath(env = process.env) {
@@ -6433,7 +6463,7 @@ function claudeDeviceStatePath(env = process.env) {
6433
6463
  }
6434
6464
  function checkClaudeDeviceState(path = claudeDeviceStatePath()) {
6435
6465
  try {
6436
- if (!statSync8(path).isFile()) return { usable: false, reason: "not-a-file" };
6466
+ if (!statSync9(path).isFile()) return { usable: false, reason: "not-a-file" };
6437
6467
  } catch (err) {
6438
6468
  return {
6439
6469
  usable: false,
@@ -7210,7 +7240,7 @@ function clearRestartTiming(codeName) {
7210
7240
  function resolveModelChain(refreshData) {
7211
7241
  const agent = refreshData.agent;
7212
7242
  const modelDefaults = refreshData.model_defaults;
7213
- const platform3 = modelDefaults?.platform ?? {};
7243
+ const platform4 = modelDefaults?.platform ?? {};
7214
7244
  const org = modelDefaults?.org ?? {};
7215
7245
  function resolve2(tier) {
7216
7246
  const agentField = `${tier}_model`;
@@ -7219,7 +7249,7 @@ function resolveModelChain(refreshData) {
7219
7249
  if (agentVal) return agentVal;
7220
7250
  const orgVal = org?.[platformField];
7221
7251
  if (orgVal) return orgVal;
7222
- const platformVal = platform3?.[platformField];
7252
+ const platformVal = platform4?.[platformField];
7223
7253
  if (platformVal) return platformVal;
7224
7254
  return void 0;
7225
7255
  }
@@ -8825,7 +8855,7 @@ import { homedir as homedir16 } from "os";
8825
8855
  import { join as join37 } from "path";
8826
8856
 
8827
8857
  // src/lib/agent-serving-probe.ts
8828
- import { readFileSync as readFileSync28, readdirSync as readdirSync8, statSync as statSync9 } from "fs";
8858
+ import { readFileSync as readFileSync28, readdirSync as readdirSync8, statSync as statSync10 } from "fs";
8829
8859
  import { join as join36 } from "path";
8830
8860
  var RATE_LIMIT_WINDOW_MS = 6 * 60 * 60 * 1e3;
8831
8861
  function probeRateLimit(args) {
@@ -8844,7 +8874,7 @@ function probeRateLimit(args) {
8844
8874
  if (!name.endsWith(".jsonl")) continue;
8845
8875
  const path = join36(dir, name);
8846
8876
  try {
8847
- const st = statSync9(path);
8877
+ const st = statSync10(path);
8848
8878
  if (!st.isFile() || st.mtimeMs < startMs) continue;
8849
8879
  } catch {
8850
8880
  continue;
@@ -8983,7 +9013,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
8983
9013
  }
8984
9014
 
8985
9015
  // src/lib/occupancy-gate.ts
8986
- import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync9, readSync as readSync2, statSync as statSync10 } from "fs";
9016
+ import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync9, readSync as readSync2, statSync as statSync11 } from "fs";
8987
9017
  import { join as join38 } from "path";
8988
9018
  function rostersMeasuredZero(mode, attested, runtimeRunning) {
8989
9019
  return mode === "enforce" && attested && runtimeRunning;
@@ -8998,7 +9028,7 @@ var brackets = /* @__PURE__ */ new Map();
8998
9028
  function readAlignedTail(path, tailBytes, maxAlignBytes) {
8999
9029
  let fd = null;
9000
9030
  try {
9001
- const size = statSync10(path).size;
9031
+ const size = statSync11(path).size;
9002
9032
  if (size <= 0) return { content: "", complete: true, truncated: false };
9003
9033
  fd = openSync2(path, "r");
9004
9034
  let readStart = Math.max(0, size - tailBytes);
@@ -9142,7 +9172,7 @@ function collectQualifyingTurns(codeName, nowMs, opts = {}) {
9142
9172
  for (const path of paths) {
9143
9173
  let st;
9144
9174
  try {
9145
- st = statSync10(path);
9175
+ st = statSync11(path);
9146
9176
  } catch (err) {
9147
9177
  if (!isAbsentDirError(err)) complete = false;
9148
9178
  continue;
@@ -9248,7 +9278,7 @@ function qualifyBuckets(buckets, qualifying, mode, nowMs, neighbourhoodMs = DEFA
9248
9278
  }
9249
9279
 
9250
9280
  // src/lib/pane-occupancy-sampler.ts
9251
- import { statSync as statSync11 } from "fs";
9281
+ import { statSync as statSync12 } from "fs";
9252
9282
  var SAMPLE_INTERVAL_MS = 1e4;
9253
9283
  var IDLE_GAP_MS = 12e4;
9254
9284
  var POST_IDLE_CREDIT_MS = 6e4;
@@ -9262,7 +9292,7 @@ function hasFreshPaneObservation(codeName, nowMs, maxAgeMs = OBSERVATION_FRESH_M
9262
9292
  }
9263
9293
  function paneMtimeMs(codeName) {
9264
9294
  try {
9265
- return statSync11(paneLogPath(codeName)).mtimeMs;
9295
+ return statSync12(paneLogPath(codeName)).mtimeMs;
9266
9296
  } catch {
9267
9297
  return null;
9268
9298
  }
@@ -13235,6 +13265,44 @@ function classifyLazyDayRolloverReset(i) {
13235
13265
  return i.deviceStateReady === false ? "defer-device-state" : "reset";
13236
13266
  }
13237
13267
  var deviceStateRotationGate = new DeviceStateRotationGate();
13268
+ var SELF_UPDATE_DEVICE_STATE_HOLD_KEY = "(self-update)";
13269
+ var selfUpdateForcedHoldAnnounced = false;
13270
+ var forcedUpdateRequestLatch = null;
13271
+ function lastForcedOutcomeFor(requestedAt) {
13272
+ return requestedAt !== null && forcedUpdateRequestLatch?.requestedAt === requestedAt ? forcedUpdateRequestLatch.lastOutcome : null;
13273
+ }
13274
+ var credentialsUnreadableAnnounced = false;
13275
+ async function hostShouldHaveClaudeDeviceState() {
13276
+ const verdict = deviceStateHoldApplies({
13277
+ authMode: getCachedClaudeAuthMode(),
13278
+ credentialPaths: await findClaudeCredentialsPaths()
13279
+ });
13280
+ const unreadable = verdict.applies && verdict.because === "credentials-unreadable";
13281
+ if (!unreadable) credentialsUnreadableAnnounced = false;
13282
+ if (unreadable && !credentialsUnreadableAnnounced) {
13283
+ credentialsUnreadableAnnounced = true;
13284
+ log(
13285
+ "[self-update] could not determine whether this host is paired: a Claude credentials path exists but could not be stat'd. Holding the CLI upgrade rather than guessing. Check the permissions on ~/.claude. [ENG-10724]"
13286
+ );
13287
+ }
13288
+ return verdict.applies;
13289
+ }
13290
+ async function selfUpdateDeviceStateHold(force) {
13291
+ if (!await hostShouldHaveClaudeDeviceState()) return null;
13292
+ const deviceState = deviceStateRotationGate.mayRotate(SELF_UPDATE_DEVICE_STATE_HOLD_KEY, Date.now());
13293
+ if (deviceState.ready) {
13294
+ selfUpdateForcedHoldAnnounced = false;
13295
+ return null;
13296
+ }
13297
+ const announceForced = force && !selfUpdateForcedHoldAnnounced;
13298
+ if (deviceState.firstHold || announceForced) {
13299
+ if (announceForced) selfUpdateForcedHoldAnnounced = true;
13300
+ log(
13301
+ `[self-update] HELD${force ? ' (forced "Update CLI now")' : ""} - the host's ~/.claude.json is not usable (${deviceState.reason}) and this host is paired for Claude Code. A CLI upgrade ends in a manager restart, which would rebuild every isolation container on this host against the missing file and park every agent on the login picker. Keeping the current binary; the upgrade applies on the first check after the file is usable again. Pair the host from the Hosts page. (further holds this episode are not logged) [ENG-10724]`
13302
+ );
13303
+ }
13304
+ return "failed";
13305
+ }
13238
13306
  function deviceStateAllowsRollover(codeName, path) {
13239
13307
  const gate = deviceStateRotationGate.mayRotate(codeName, Date.now());
13240
13308
  if (gate.ready) return true;
@@ -13299,7 +13367,7 @@ function performLazyDayRolloverReset(codeName, agentTimezone) {
13299
13367
  }
13300
13368
  function paneLogAgeSecondsFor(codeName) {
13301
13369
  try {
13302
- const mtimeMs = statSync12(paneLogPath(codeName)).mtimeMs;
13370
+ const mtimeMs = statSync13(paneLogPath(codeName)).mtimeMs;
13303
13371
  return Math.max(0, Math.floor((Date.now() - mtimeMs) / 1e3));
13304
13372
  } catch (err) {
13305
13373
  if (err?.code === "ENOENT") return null;
@@ -13391,6 +13459,13 @@ function runPendingForcedUpdate() {
13391
13459
  forcedUpdateRelaxAnnounced = false;
13392
13460
  }
13393
13461
  if (forcedUpdate === "none" || forcedUpdate === "already-handled") return false;
13462
+ if (forcedUpdateRequestLatch && forcedUpdateRequestLatch.requestedAt !== requestedUpdateAt) {
13463
+ forcedUpdateRequestLatch = null;
13464
+ selfUpdateForcedHoldAnnounced = false;
13465
+ }
13466
+ if (forcedUpdate !== "defer-idle" && forcedUpdateRequestLatch?.requestedAt === requestedUpdateAt && forcedUpdateRequestLatch.lastOutcome !== null && Date.now() - forcedUpdateRequestLatch.lastAttemptMs < UPDATE_CHECK_INTERVAL_MS) {
13467
+ return false;
13468
+ }
13394
13469
  if (forcedUpdate === "defer-idle") {
13395
13470
  forcedUpdateDeferStreak += 1;
13396
13471
  if (forcedUpdateDeferStreak === 1 || forcedUpdateDeferStreak % 10 === 0) {
@@ -13412,17 +13487,30 @@ function runPendingForcedUpdate() {
13412
13487
  );
13413
13488
  return false;
13414
13489
  }
13415
- log(
13416
- forcedUpdate === "consume-deadline" ? `[self-update] WARN "Update CLI now" requested at ${requestedUpdateAt} has been pending ${describePendingFor(pendingForMs)} and the host still reads busy \u2014 running the window-bypassing self-update anyway (ENG-8449 hard deadline). A live turn may be interrupted; the operator asked for this update explicitly.` : `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 running window-bypassing self-update now (host idle${relaxed ? ", relaxed gate" : ""}).`
13417
- );
13490
+ if (lastForcedOutcomeFor(requestedUpdateAt) === null) {
13491
+ log(
13492
+ forcedUpdate === "consume-deadline" ? `[self-update] WARN "Update CLI now" requested at ${requestedUpdateAt} has been pending ${describePendingFor(pendingForMs)} and the host still reads busy \u2014 running the window-bypassing self-update anyway (ENG-8449 hard deadline). A live turn may be interrupted; the operator asked for this update explicitly.` : `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 running window-bypassing self-update now (host idle${relaxed ? ", relaxed gate" : ""}).`
13493
+ );
13494
+ }
13418
13495
  const prevProcessedAt = state8.lastUpdateRequestProcessedAt ?? null;
13496
+ const attemptStartedMs = Date.now();
13419
13497
  void checkAndUpdateCli({ force: true }).then((outcome) => {
13420
13498
  if (!shouldConsumeForcedUpdate(outcome)) {
13421
- log(
13422
- `[self-update] "Update CLI now" did not complete (no install ran) \u2014 leaving the request pending; the next idle poll retries.`
13423
- );
13499
+ const previous = lastForcedOutcomeFor(requestedUpdateAt);
13500
+ forcedUpdateRequestLatch = requestedUpdateAt === null ? null : {
13501
+ requestedAt: requestedUpdateAt,
13502
+ lastOutcome: outcome,
13503
+ lastAttemptMs: attemptStartedMs
13504
+ };
13505
+ if (previous !== outcome) {
13506
+ log(
13507
+ `[self-update] "Update CLI now" did not complete (outcome: ${outcome}, no install ran) \u2014 leaving the request pending; the next idle poll retries. (repeats of this outcome are not logged)`
13508
+ );
13509
+ }
13424
13510
  return;
13425
13511
  }
13512
+ forcedUpdateRequestLatch = null;
13513
+ selfUpdateForcedHoldAnnounced = false;
13426
13514
  log(
13427
13515
  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.`
13428
13516
  );
@@ -13867,7 +13955,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13867
13955
  var lastVersionCheckAt = 0;
13868
13956
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13869
13957
  var lastResponsivenessProbeAt = 0;
13870
- var agtCliVersion = true ? "0.28.978" : "dev";
13958
+ var agtCliVersion = true ? "0.28.979" : "dev";
13871
13959
  function resolveBrewPath(execFileSync2) {
13872
13960
  try {
13873
13961
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14550,6 +14638,8 @@ async function checkAndUpdateCliViaBrew(force = false) {
14550
14638
  return "noop";
14551
14639
  }
14552
14640
  log(`[self-update] agt CLI update available: ${installed} \u2192 ${latest}. Upgrading via brew${force ? " (forced \u2014 Update CLI now)" : ""}...`);
14641
+ const brewInstallHold = await selfUpdateDeviceStateHold(force);
14642
+ if (brewInstallHold) return brewInstallHold;
14553
14643
  try {
14554
14644
  execFileSync2(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
14555
14645
  timeout: 12e4,
@@ -14606,7 +14696,7 @@ async function checkAndUpdateCliViaNpm(force = false) {
14606
14696
  log(
14607
14697
  `[self-update] URGENT agt CLI hotfix ${agtCliVersion} \u2192 ${urgentTarget2} overrides pin=${pinDecision.version} (AGT_CLI_PIN_ALLOW_URGENT). Upgrading via npm...`
14608
14698
  );
14609
- return await installAgtCliViaNpm(urgentTarget2, "urgent(pin-allow-urgent)");
14699
+ return await installAgtCliViaNpm(urgentTarget2, "urgent(pin-allow-urgent)", force);
14610
14700
  }
14611
14701
  }
14612
14702
  if (pinDecision.kind === "satisfied") {
@@ -14619,7 +14709,7 @@ async function checkAndUpdateCliViaNpm(force = false) {
14619
14709
  log(
14620
14710
  `[self-update] agt CLI pinned to ${pinDecision.version} (AGT_CLI_PIN_VERSION); installing exact version (${agtCliVersion} \u2192 ${pinDecision.version})...`
14621
14711
  );
14622
- return await installAgtCliViaNpm(pinDecision.version, `pin=${pinDecision.version}`);
14712
+ return await installAgtCliViaNpm(pinDecision.version, `pin=${pinDecision.version}`, force);
14623
14713
  }
14624
14714
  const REGISTRY_TIMEOUT_MS = 1e4;
14625
14715
  const registryAttempts = force ? 2 : 1;
@@ -14667,7 +14757,7 @@ async function checkAndUpdateCliViaNpm(force = false) {
14667
14757
  log(
14668
14758
  `[self-update] URGENT agt CLI hotfix ${agtCliVersion} \u2192 ${urgentTarget} (overrides channel=${channel} + maintenance window). Upgrading via npm...`
14669
14759
  );
14670
- return await installAgtCliViaNpm(urgentTarget, "urgent");
14760
+ return await installAgtCliViaNpm(urgentTarget, "urgent", force);
14671
14761
  }
14672
14762
  let shouldUpdate;
14673
14763
  if (channel === "latest") {
@@ -14712,7 +14802,7 @@ async function checkAndUpdateCliViaNpm(force = false) {
14712
14802
  return "noop";
14713
14803
  }
14714
14804
  log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest} (channel=${channel}). Upgrading via npm...`);
14715
- return await installAgtCliViaNpm(latest, `channel=${channel}`);
14805
+ return await installAgtCliViaNpm(latest, `channel=${channel}`, force);
14716
14806
  }
14717
14807
  async function fetchUrgentDistTagVersion() {
14718
14808
  try {
@@ -14727,7 +14817,7 @@ async function fetchUrgentDistTagVersion() {
14727
14817
  return null;
14728
14818
  }
14729
14819
  }
14730
- async function installAgtCliViaNpm(version, reasonLabel) {
14820
+ async function installAgtCliViaNpm(version, reasonLabel, force = false) {
14731
14821
  const { execFileSync: execFileSync2 } = await import("child_process");
14732
14822
  const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
14733
14823
  const cmd = isRoot ? "npm" : "sudo";
@@ -14738,6 +14828,8 @@ async function installAgtCliViaNpm(version, reasonLabel) {
14738
14828
  "--registry=https://registry.npmjs.org"
14739
14829
  ];
14740
14830
  const args = isRoot ? installArgs : ["-n", "npm", ...installArgs];
14831
+ const npmInstallHold = await selfUpdateDeviceStateHold(force);
14832
+ if (npmInstallHold) return npmInstallHold;
14741
14833
  try {
14742
14834
  execFileSync2(cmd, args, { timeout: 18e4, stdio: "pipe" });
14743
14835
  } catch (err) {
@@ -21484,7 +21576,7 @@ function reapRetiredMemories(configDir, codeName, log2) {
21484
21576
  if (!file.endsWith(".retired")) continue;
21485
21577
  const path = join42(dir, file);
21486
21578
  try {
21487
- if (statSync12(path).mtimeMs < cutoff) {
21579
+ if (statSync13(path).mtimeMs < cutoff) {
21488
21580
  unlinkSync6(path);
21489
21581
  reaped++;
21490
21582
  }