@integrity-labs/agt-cli 0.28.1177 → 0.28.1178

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.
Files changed (38) hide show
  1. package/dist/bin/agt.js +104 -417
  2. package/dist/bin/agt.js.map +1 -1
  3. package/dist/{chunk-H37WRW2E.js → chunk-3XURNDW5.js} +6 -5
  4. package/dist/chunk-3XURNDW5.js.map +1 -0
  5. package/dist/{chunk-45UH24I2.js → chunk-DAIXT5DR.js} +435 -56
  6. package/dist/chunk-DAIXT5DR.js.map +1 -0
  7. package/dist/{manager-supervisor-KIFBGETA.js → chunk-H3JMPEH7.js} +176 -8
  8. package/dist/chunk-H3JMPEH7.js.map +1 -0
  9. package/dist/{chunk-47P33SZF.js → chunk-MHSZBN6M.js} +12 -2
  10. package/dist/chunk-MHSZBN6M.js.map +1 -0
  11. package/dist/{chunk-DJNCIWVG.js → chunk-MO5JQVBG.js} +2 -2
  12. package/dist/{chunk-NHUXO5H2.js → chunk-R2NQG77N.js} +2 -2
  13. package/dist/{claude-code-updater-H7RNX6M7.js → claude-code-updater-F2O3LAWX.js} +3 -3
  14. package/dist/{claude-pair-runtime-53JY6TQX.js → claude-pair-runtime-I6KVCUBG.js} +3 -3
  15. package/dist/lib/manager-worker.js +258 -20
  16. package/dist/lib/manager-worker.js.map +1 -1
  17. package/dist/manager-supervisor-TD7E6FPC.js +26 -0
  18. package/dist/mcp/direct-chat-channel.js +4 -0
  19. package/dist/mcp/index.js +4 -0
  20. package/dist/mcp/origami.js +4 -0
  21. package/dist/mcp/slack-channel.js +4 -0
  22. package/dist/mcp/telegram-channel.js +4 -0
  23. package/dist/{persistent-session-HVYGIS5C.js → persistent-session-7HP4KOED.js} +4 -4
  24. package/dist/persistent-session-7HP4KOED.js.map +1 -0
  25. package/dist/{responsiveness-probe-OGZ6ADVR.js → responsiveness-probe-EPG7NOKI.js} +4 -4
  26. package/dist/{session-auth-dead-2JJLKURE.js → session-auth-dead-IG3MKV2W.js} +3 -3
  27. package/package.json +1 -1
  28. package/dist/chunk-45UH24I2.js.map +0 -1
  29. package/dist/chunk-47P33SZF.js.map +0 -1
  30. package/dist/chunk-H37WRW2E.js.map +0 -1
  31. package/dist/manager-supervisor-KIFBGETA.js.map +0 -1
  32. /package/dist/{chunk-DJNCIWVG.js.map → chunk-MO5JQVBG.js.map} +0 -0
  33. /package/dist/{chunk-NHUXO5H2.js.map → chunk-R2NQG77N.js.map} +0 -0
  34. /package/dist/{claude-code-updater-H7RNX6M7.js.map → claude-code-updater-F2O3LAWX.js.map} +0 -0
  35. /package/dist/{claude-pair-runtime-53JY6TQX.js.map → claude-pair-runtime-I6KVCUBG.js.map} +0 -0
  36. /package/dist/{persistent-session-HVYGIS5C.js.map → manager-supervisor-TD7E6FPC.js.map} +0 -0
  37. /package/dist/{responsiveness-probe-OGZ6ADVR.js.map → responsiveness-probe-EPG7NOKI.js.map} +0 -0
  38. /package/dist/{session-auth-dead-2JJLKURE.js.map → session-auth-dead-IG3MKV2W.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  encodeClaudeProjectPath
3
- } from "./chunk-47P33SZF.js";
3
+ } from "./chunk-MHSZBN6M.js";
4
4
 
5
5
  // src/lib/daily-session.ts
6
6
  import { randomUUID } from "crypto";
@@ -235,4 +235,4 @@ export {
235
235
  peekCurrentSession,
236
236
  readDailySessionPin
237
237
  };
238
- //# sourceMappingURL=chunk-DJNCIWVG.js.map
238
+ //# sourceMappingURL=chunk-MO5JQVBG.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-XWVM4KPK.js";
5
5
  import {
6
6
  FORCED_UPDATE_HARD_DEADLINE_MS
7
- } from "./chunk-47P33SZF.js";
7
+ } from "./chunk-MHSZBN6M.js";
8
8
  import {
9
9
  effectiveClaudeJsonPath
10
10
  } from "./chunk-AIUIMEUS.js";
@@ -722,4 +722,4 @@ export {
722
722
  probeClaudeInstalls,
723
723
  maybeUpdateClaudeCode
724
724
  };
725
- //# sourceMappingURL=chunk-NHUXO5H2.js.map
725
+ //# sourceMappingURL=chunk-R2NQG77N.js.map
@@ -13,9 +13,9 @@ import {
13
13
  probeClaudeInstalls,
14
14
  readsAsNativeInstall,
15
15
  shouldRunClaudeCodeUpdater
16
- } from "./chunk-NHUXO5H2.js";
16
+ } from "./chunk-R2NQG77N.js";
17
17
  import "./chunk-XWVM4KPK.js";
18
- import "./chunk-47P33SZF.js";
18
+ import "./chunk-MHSZBN6M.js";
19
19
  import "./chunk-AIUIMEUS.js";
20
20
  import "./chunk-DGUM43GV.js";
21
21
  export {
@@ -34,4 +34,4 @@ export {
34
34
  readsAsNativeInstall,
35
35
  shouldRunClaudeCodeUpdater
36
36
  };
37
- //# sourceMappingURL=claude-code-updater-H7RNX6M7.js.map
37
+ //# sourceMappingURL=claude-code-updater-F2O3LAWX.js.map
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  redactPaneFrame,
10
10
  sanitizeTerminalFrame
11
- } from "./chunk-47P33SZF.js";
11
+ } from "./chunk-MHSZBN6M.js";
12
12
  import {
13
13
  CLAUDE_CONFIG_DIR_ENV,
14
14
  claudeConfigDirFor,
@@ -321,7 +321,7 @@ async function spawnPairSession(session) {
321
321
  return { ok: true };
322
322
  } catch {
323
323
  }
324
- const { resolveClaudeBinary } = await import("./persistent-session-HVYGIS5C.js");
324
+ const { resolveClaudeBinary } = await import("./persistent-session-7HP4KOED.js");
325
325
  const claudeBin = resolveClaudeBinary();
326
326
  const pairEnv = {
327
327
  ...process.env,
@@ -836,4 +836,4 @@ export {
836
836
  startClaudePair,
837
837
  submitClaudePairCode
838
838
  };
839
- //# sourceMappingURL=claude-pair-runtime-53JY6TQX.js.map
839
+ //# sourceMappingURL=claude-pair-runtime-I6KVCUBG.js.map
@@ -11,6 +11,7 @@ import {
11
11
  RestartBreaker,
12
12
  SUPERVISOR_RESTART_EXIT_CODE,
13
13
  TunnelWatcher,
14
+ adoptHostKeyInProcess,
14
15
  api,
15
16
  atomicWriteFileSync,
16
17
  buildClaudeAgentMatcher,
@@ -52,6 +53,7 @@ import {
52
53
  markQuarantinedForProbe,
53
54
  migrateAgentDirToIdKeyed,
54
55
  mintAgentKey,
56
+ mintRotatedHostKey,
55
57
  parseRmPolicy,
56
58
  pinAllowsUrgent,
57
59
  provision,
@@ -65,6 +67,7 @@ import {
65
67
  provisionSessionStateHook,
66
68
  provisionStopHook,
67
69
  readEnvNumber,
70
+ readEtcEnvironmentValue,
68
71
  readHostArchiveAddress,
69
72
  reapLegacyTokenFile,
70
73
  reapMissingMcpSessions,
@@ -76,8 +79,10 @@ import {
76
79
  safeWriteJsonAtomic,
77
80
  setConfigHash,
78
81
  shellGuard,
79
- tripClass
80
- } from "../chunk-45UH24I2.js";
82
+ tripClass,
83
+ writeEtcEnvironment,
84
+ writeProfileDScript
85
+ } from "../chunk-DAIXT5DR.js";
81
86
  import {
82
87
  CLAUDE_CODE_SECURITY_FLOOR,
83
88
  SELF_UPDATE_TIMEOUTS,
@@ -91,7 +96,11 @@ import {
91
96
  runSafeCleanup,
92
97
  tightestDiskStat,
93
98
  withPackageCacheLock
94
- } from "../chunk-NHUXO5H2.js";
99
+ } from "../chunk-R2NQG77N.js";
100
+ import {
101
+ rewriteSupervisorApiKey,
102
+ supervisorChannelsRefusing
103
+ } from "../chunk-H3JMPEH7.js";
95
104
  import {
96
105
  getProjectDir as getProjectDir2,
97
106
  getReadyTasks,
@@ -178,7 +187,7 @@ import {
178
187
  webFetchBaselineValue,
179
188
  webFetchRestartNeeded,
180
189
  writeEgressAllowlist
181
- } from "../chunk-H37WRW2E.js";
190
+ } from "../chunk-3XURNDW5.js";
182
191
  import {
183
192
  isAgentIdle,
184
193
  isStaleForToday,
@@ -187,7 +196,7 @@ import {
187
196
  sessionTranscriptDir,
188
197
  subagentActivityAgeSeconds,
189
198
  transcriptActivityAgeSeconds
190
- } from "../chunk-DJNCIWVG.js";
199
+ } from "../chunk-MO5JQVBG.js";
191
200
  import {
192
201
  classifyUnanswerablePane,
193
202
  focusedConfirmDialogBlock,
@@ -303,9 +312,10 @@ import {
303
312
  scrubPreservingIdentifiers,
304
313
  senderPolicyIsEnforcedOn,
305
314
  serializeAccountEnforcementMarker,
315
+ shouldMintReplacementKey,
306
316
  stabiliseResetInstant,
307
317
  sumTranscriptUsageInWindow
308
- } from "../chunk-47P33SZF.js";
318
+ } from "../chunk-MHSZBN6M.js";
309
319
  import {
310
320
  CLAUDE_CONFIG_DIR_ENV,
311
321
  claudeConfigDirFor,
@@ -3641,6 +3651,100 @@ function maybeMigrateAgentToIdKeyedLayout(agent, deps) {
3641
3651
  }
3642
3652
  }
3643
3653
 
3654
+ // src/lib/host-key-rotation.ts
3655
+ async function adoptRotatedHostKey(deps) {
3656
+ const refusals = deps.preflightPersist?.() ?? [];
3657
+ if (refusals.length > 0) {
3658
+ deps.log(
3659
+ `[key-rotation] not minting: ${refusals.length} persist channel(s) would refuse the new key, so a mint would leak an active credential for nothing. ${refusals.join(" | ")}`
3660
+ );
3661
+ return deps.held ? { status: "persist-refused", reasons: refusals, held: deps.held } : { status: "persist-refused", reasons: refusals };
3662
+ }
3663
+ let minted;
3664
+ if (deps.held) {
3665
+ minted = deps.held;
3666
+ deps.log(`[key-rotation] retrying the persist of ${minted.prefix}, minted earlier for this request`);
3667
+ } else {
3668
+ let result;
3669
+ try {
3670
+ result = await deps.mint();
3671
+ } catch (err) {
3672
+ const detail = err instanceof Error ? err.message : String(err);
3673
+ deps.log(`[key-rotation] mint failed: ${detail}`);
3674
+ return { status: "error", detail };
3675
+ }
3676
+ if (result && "refused" in result) {
3677
+ deps.log(
3678
+ `[key-rotation] the control plane refused the mint for good: ${result.refused}. Not retrying this request. If it never completes, a compromised rotation clears it (docs/runbooks/host-api-key-rotation.md).`
3679
+ );
3680
+ return { status: "mint-refused", reason: result.refused };
3681
+ }
3682
+ if (!result || !result.rawKey || !result.prefix) {
3683
+ deps.log("[key-rotation] mint returned nothing usable - leaving the current key in force");
3684
+ return { status: "mint-failed" };
3685
+ }
3686
+ minted = result;
3687
+ }
3688
+ let persisted;
3689
+ try {
3690
+ persisted = deps.persist(minted.rawKey);
3691
+ } catch (err) {
3692
+ const detail = err instanceof Error ? err.message : String(err);
3693
+ deps.log(
3694
+ `[key-rotation] could not persist the new key (${minted.prefix}): ${detail} - NOT adopting, NOT acking; the current key stays in force`
3695
+ );
3696
+ return { status: "error", detail, held: minted };
3697
+ }
3698
+ if (!persisted) {
3699
+ deps.log(
3700
+ `[key-rotation] could not persist the new key (${minted.prefix}) - NOT adopting, NOT acking; the current key stays in force`
3701
+ );
3702
+ return { status: "persist-failed", prefix: minted.prefix, held: minted };
3703
+ }
3704
+ if (deps.onPersisted && !deps.onPersisted(minted.prefix)) {
3705
+ deps.log(
3706
+ `[key-rotation] persisted ${minted.prefix} but could not save the pending ack - NOT adopting; the current key stays in force and the retry reuses this key`
3707
+ );
3708
+ return { status: "error", detail: "pending ack could not be saved", held: minted };
3709
+ }
3710
+ try {
3711
+ deps.adoptInProcess(minted.rawKey);
3712
+ } catch (err) {
3713
+ const detail = err instanceof Error ? err.message : String(err);
3714
+ deps.log(
3715
+ `[key-rotation] persisted ${minted.prefix} but could not adopt it in-process: ${detail} - it will take effect on the next manager restart`
3716
+ );
3717
+ return { status: "error", detail, held: minted };
3718
+ }
3719
+ deps.log(
3720
+ `[key-rotation] adopted new host key ${minted.prefix}. The previous key stays valid until the control plane expires it on this host's ack.`
3721
+ );
3722
+ return { status: "adopted", prefix: minted.prefix };
3723
+ }
3724
+ function nextPendingAck(pending2, resp) {
3725
+ if (!pending2) return { pending: null, log: null };
3726
+ if (!resp || !("key_rotation_requested_at" in resp)) {
3727
+ return {
3728
+ pending: pending2,
3729
+ log: `[key-rotation] the heartbeat did not report key_rotation_requested_at, so nothing confirms ${pending2} was finalized. Re-acking next poll; the current key stays in force.`
3730
+ };
3731
+ }
3732
+ if (resp.key_rotation_requested_at) {
3733
+ return {
3734
+ pending: pending2,
3735
+ log: `[key-rotation] acked ${pending2} but the request is still armed server-side, so the outgoing key was NOT expired. Re-acking next poll; the current key stays in force either way.`
3736
+ };
3737
+ }
3738
+ return {
3739
+ pending: null,
3740
+ log: `[key-rotation] acked adoption of ${pending2}; the previous key is now expiring`
3741
+ };
3742
+ }
3743
+ function alreadyHandledRotationRequest(requestedAt, lastHandled) {
3744
+ if (!requestedAt) return true;
3745
+ return requestedAt === lastHandled;
3746
+ }
3747
+
3644
3748
  // src/lib/heartbeat-account-email.ts
3645
3749
  function mayReportAccountEmail(rawMode) {
3646
3750
  return rawMode === "subscription";
@@ -15131,7 +15235,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
15131
15235
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
15132
15236
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
15133
15237
  async function channelInboundActivityAgeSecondsFor(codeName) {
15134
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-OGZ6ADVR.js");
15238
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-EPG7NOKI.js");
15135
15239
  const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
15136
15240
  if (newest === null) return null;
15137
15241
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -15928,7 +16032,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
15928
16032
  var lastVersionCheckAt = 0;
15929
16033
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
15930
16034
  var lastResponsivenessProbeAt = 0;
15931
- var agtCliVersion = true ? "0.28.1177" : "dev";
16035
+ var agtCliVersion = true ? "0.28.1178" : "dev";
15932
16036
  function resolveBrewPath(execFileSync3) {
15933
16037
  try {
15934
16038
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -16171,6 +16275,82 @@ async function diskNodeVersion() {
16171
16275
  }
16172
16276
  var hostNodeObservation = null;
16173
16277
  var hostNodeObservedAt = 0;
16278
+ var lastKeyRotationHandled = null;
16279
+ var pendingKeyRotationAck = null;
16280
+ function setPendingKeyRotationAck(next) {
16281
+ const prevMemory = pendingKeyRotationAck;
16282
+ const prevState = state9.pendingKeyRotationAck ?? null;
16283
+ pendingKeyRotationAck = next?.prefix ?? null;
16284
+ state9.pendingKeyRotationAck = next;
16285
+ try {
16286
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state9, null, 2));
16287
+ return true;
16288
+ } catch (err) {
16289
+ log(`[key-rotation] could not persist the pending ack: ${err.message}`);
16290
+ if (next !== null) {
16291
+ pendingKeyRotationAck = prevMemory;
16292
+ state9.pendingKeyRotationAck = prevState;
16293
+ return false;
16294
+ }
16295
+ return true;
16296
+ }
16297
+ }
16298
+ var keyRotationRetryAfter = 0;
16299
+ var KEY_ROTATION_RETRY_MS = 5 * 6e4;
16300
+ var heldRotatedKey = null;
16301
+ function persistRotatedHostKey(rawKey) {
16302
+ const apiUrl = process.env["AGT_HOST"]?.trim();
16303
+ if (!apiUrl) {
16304
+ log("[key-rotation] AGT_HOST is not set, so the env channels cannot be rewritten");
16305
+ return false;
16306
+ }
16307
+ const consoleUrl = process.env["AGT_CONSOLE_URL"] ?? readEtcEnvironmentValue("AGT_CONSOLE_URL");
16308
+ let supervisor;
16309
+ try {
16310
+ supervisor = rewriteSupervisorApiKey(rawKey, void 0, getApiKey() ?? void 0);
16311
+ } catch (err) {
16312
+ log(`[key-rotation] supervisor env rewrite threw: ${err?.message ?? String(err)}`);
16313
+ return false;
16314
+ }
16315
+ for (const path of supervisor.rewritten) {
16316
+ log(`[key-rotation] rewrote AGT_API_KEY in ${path}`);
16317
+ }
16318
+ for (const f of supervisor.failed) {
16319
+ log(`[key-rotation] ${f.path} holds AGT_API_KEY and could NOT be rewritten: ${f.error}`);
16320
+ }
16321
+ for (const path of supervisor.rolledBack ?? []) {
16322
+ log(`[key-rotation] put ${path} back to the running key, because another channel failed`);
16323
+ }
16324
+ if (supervisor.failed.length > 0) {
16325
+ log(
16326
+ `[key-rotation] ${supervisor.failed.length} supervisor channel(s) would still hand out the OUTGOING key - the rotation is abandoned, not acked, so that key keeps working. Retrying after the backoff.`
16327
+ );
16328
+ return false;
16329
+ }
16330
+ if (supervisor.rewritten.length > 0) {
16331
+ let wroteEtcEnvironment = false;
16332
+ try {
16333
+ wroteEtcEnvironment = writeEtcEnvironment(apiUrl, rawKey, consoleUrl);
16334
+ } catch (err) {
16335
+ log(`[key-rotation] /etc/environment write threw: ${err?.message ?? String(err)}`);
16336
+ }
16337
+ try {
16338
+ if (!writeProfileDScript(apiUrl, rawKey, consoleUrl)) {
16339
+ log("[key-rotation] /etc/profile.d/agt.sh was not written; it is read by login shells, not by the manager");
16340
+ }
16341
+ } catch (err) {
16342
+ log(`[key-rotation] /etc/profile.d write threw (non-fatal): ${err?.message ?? String(err)}`);
16343
+ }
16344
+ if (!wroteEtcEnvironment) {
16345
+ log("[key-rotation] /etc/environment was not rewritten; the supervisor channel has the new key, so a restart is safe, but an SSM session and a re-bootstrap will read the old one");
16346
+ }
16347
+ return true;
16348
+ }
16349
+ log(
16350
+ `[key-rotation] no supervisor env channel holds AGT_API_KEY (${supervisor.keyless.length > 0 ? `present but keyless: ${supervisor.keyless.join(", ")}` : "none installed"}) - nothing would hand the new key to the next manager start, so the rotation is abandoned, not acked`
16351
+ );
16352
+ return false;
16353
+ }
16174
16354
  function invalidateHostNodeObservation(pathVersion) {
16175
16355
  hostNodeObservedAt = 0;
16176
16356
  if (pathVersion !== void 0 && hostNodeObservation) {
@@ -17740,7 +17920,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
17740
17920
  if (codeNames.length === 0) return;
17741
17921
  void (async () => {
17742
17922
  try {
17743
- const { collectDiagnostics } = await import("../persistent-session-HVYGIS5C.js");
17923
+ const { collectDiagnostics } = await import("../persistent-session-7HP4KOED.js");
17744
17924
  await api.post("/host/heartbeat", {
17745
17925
  host_id: hostId,
17746
17926
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
@@ -17883,7 +18063,7 @@ async function pollCycleInner() {
17883
18063
  }
17884
18064
  try {
17885
18065
  const { detectHostSecurity } = await import("../host-security-KQYYZZVW.js");
17886
- const { collectDiagnostics } = await import("../persistent-session-HVYGIS5C.js");
18066
+ const { collectDiagnostics } = await import("../persistent-session-7HP4KOED.js");
17887
18067
  const diagCodeNames = [...agentState.persistentSessionAgents];
17888
18068
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor) : void 0;
17889
18069
  let tailscaleHostname;
@@ -17963,6 +18143,14 @@ async function pollCycleInner() {
17963
18143
  hostNodePin,
17964
18144
  hostNodePin ? hostNodeConvergence.stateOf(hostNodePin) : null
17965
18145
  ),
18146
+ // ENG-11642: ack a rotated key. Carries the PREFIX, never the key.
18147
+ //
18148
+ // Sent on this authenticated heartbeat on purpose: by the time it goes
18149
+ // out the request is already signed with the NEW key, so the ack and
18150
+ // "the new key works" are the same fact rather than two claims. The API
18151
+ // treats this as permission to expire the outgoing key, so it must not
18152
+ // be possible to ack with a key that cannot authenticate.
18153
+ ...pendingKeyRotationAck ? { key_rotation_adopted_prefix: pendingKeyRotationAck } : {},
17966
18154
  agent_diagnostics: agentDiagnostics,
17967
18155
  hostname: tailscaleHostname,
17968
18156
  os_username: osUsername,
@@ -18085,9 +18273,52 @@ async function pollCycleInner() {
18085
18273
  hostFlagStore().applyNotifyDispatchByAgent(hbResp?.notify_dispatch_by_agent);
18086
18274
  hostFlagStore().applyBooleanFlagsByAgent(hbResp?.feature_flags_by_agent);
18087
18275
  setConfigHash(hbResp?.config_hash ?? null);
18276
+ const ackDecision = nextPendingAck(pendingKeyRotationAck, hbResp);
18277
+ if (ackDecision.log) log(ackDecision.log);
18278
+ if (pendingKeyRotationAck !== null && ackDecision.pending === null) {
18279
+ setPendingKeyRotationAck(null);
18280
+ }
18281
+ const rotationRequestedAt = hbResp?.key_rotation_requested_at ?? null;
18282
+ if (shouldMintReplacementKey(rotationRequestedAt) && !alreadyHandledRotationRequest(rotationRequestedAt, lastKeyRotationHandled) && Date.now() >= keyRotationRetryAfter) {
18283
+ const outcome = await adoptRotatedHostKey({
18284
+ mint: async () => {
18285
+ const current = getApiKey();
18286
+ if (!current) return null;
18287
+ return mintRotatedHostKey(current);
18288
+ },
18289
+ preflightPersist: () => supervisorChannelsRefusing(void 0, {
18290
+ runningKeys: [
18291
+ getApiKey() ?? "",
18292
+ ...heldRotatedKey && heldRotatedKey.requestedAt === rotationRequestedAt ? [heldRotatedKey.minted.rawKey] : []
18293
+ ]
18294
+ }),
18295
+ held: heldRotatedKey && heldRotatedKey.requestedAt === rotationRequestedAt ? heldRotatedKey.minted : void 0,
18296
+ persist: (rawKey) => persistRotatedHostKey(rawKey),
18297
+ onPersisted: (prefix) => rotationRequestedAt ? setPendingKeyRotationAck({ prefix, requestedAt: rotationRequestedAt }) : true,
18298
+ adoptInProcess: (rawKey) => adoptHostKeyInProcess(rawKey),
18299
+ log
18300
+ });
18301
+ if (outcome.status === "error" && outcome.held && pendingKeyRotationAck === outcome.held.prefix) {
18302
+ setPendingKeyRotationAck(null);
18303
+ }
18304
+ heldRotatedKey = (outcome.status === "persist-failed" || outcome.status === "error" || outcome.status === "persist-refused") && outcome.held && rotationRequestedAt ? { requestedAt: rotationRequestedAt, minted: outcome.held } : null;
18305
+ if (outcome.status === "mint-refused") {
18306
+ lastKeyRotationHandled = rotationRequestedAt;
18307
+ } else if (outcome.status === "adopted") {
18308
+ lastKeyRotationHandled = rotationRequestedAt;
18309
+ setPendingKeyRotationAck(
18310
+ rotationRequestedAt ? { prefix: outcome.prefix, requestedAt: rotationRequestedAt } : null
18311
+ );
18312
+ } else {
18313
+ keyRotationRetryAfter = Date.now() + KEY_ROTATION_RETRY_MS;
18314
+ log(
18315
+ `[key-rotation] attempt did not complete (${outcome.status}); retrying after ${Math.round(KEY_ROTATION_RETRY_MS / 6e4)}m. The current key stays in force.`
18316
+ );
18317
+ }
18318
+ }
18088
18319
  try {
18089
18320
  const desiredClaudeCodeVersion = hbResp?.desired_claude_code_version?.trim();
18090
- const { maybeUpdateClaudeCode, shouldRunClaudeCodeUpdater } = await import("../claude-code-updater-H7RNX6M7.js");
18321
+ const { maybeUpdateClaudeCode, shouldRunClaudeCodeUpdater } = await import("../claude-code-updater-F2O3LAWX.js");
18091
18322
  const securityFloor = currentSecurityFloor();
18092
18323
  claudeUpdaterInFlight = true;
18093
18324
  if (desiredClaudeCodeVersion && (claudePairLoop.busy || claudePairingInProgress())) {
@@ -18122,7 +18353,7 @@ async function pollCycleInner() {
18122
18353
  collectPanelessActivityProbes,
18123
18354
  getResponsivenessIntervalMs,
18124
18355
  occupancyQualificationClassifications
18125
- } = await import("../responsiveness-probe-OGZ6ADVR.js");
18356
+ } = await import("../responsiveness-probe-EPG7NOKI.js");
18126
18357
  const probeIntervalMs = getResponsivenessIntervalMs();
18127
18358
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
18128
18359
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -18239,7 +18470,7 @@ async function pollCycleInner() {
18239
18470
  collectResponsivenessProbes,
18240
18471
  livePendingInboundOldestAgeSeconds,
18241
18472
  parkPendingInbound
18242
- } = await import("../responsiveness-probe-OGZ6ADVR.js");
18473
+ } = await import("../responsiveness-probe-EPG7NOKI.js");
18243
18474
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-M6AFZWNU.js");
18244
18475
  const wedgeNow = /* @__PURE__ */ new Date();
18245
18476
  const liveAgents = agentState.persistentSessionAgents;
@@ -18525,7 +18756,7 @@ async function pollCycleInner() {
18525
18756
  }
18526
18757
  }
18527
18758
  );
18528
- const { parkPendingInbound } = await import("../responsiveness-probe-OGZ6ADVR.js");
18759
+ const { parkPendingInbound } = await import("../responsiveness-probe-EPG7NOKI.js");
18529
18760
  const { parked, deadLettered } = parkPendingInbound(codeName, new Date(fatalNowMs));
18530
18761
  paneFatalStreak.delete(codeName);
18531
18762
  paneFatalRestarts.set(codeName, [...history, fatalNowMs]);
@@ -18556,7 +18787,7 @@ async function pollCycleInner() {
18556
18787
  TRANSCRIPT_MOUNT_ESCALATION_REFRESH_MS,
18557
18788
  bindSourceEscalations
18558
18789
  } = await import("../transcript-mount-health-OHE6IVJV.js");
18559
- const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-HVYGIS5C.js");
18790
+ const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-7HP4KOED.js");
18560
18791
  const mountConfig = resolveTranscriptMountConfig();
18561
18792
  const liveAgents = agentState.persistentSessionAgents;
18562
18793
  for (const tracked of [
@@ -18721,7 +18952,7 @@ async function pollCycleInner() {
18721
18952
  }
18722
18953
  try {
18723
18954
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-VR5QGP3J.js");
18724
- const { probeSessionAuth } = await import("../session-auth-dead-2JJLKURE.js");
18955
+ const { probeSessionAuth } = await import("../session-auth-dead-IG3MKV2W.js");
18725
18956
  const observations = [];
18726
18957
  const pendingCacheCommits = [];
18727
18958
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -23410,7 +23641,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
23410
23641
  try {
23411
23642
  const freshId = rotateSessionForWedge(codeName);
23412
23643
  consecutiveWedgeCycles.delete(codeName);
23413
- const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-OGZ6ADVR.js");
23644
+ const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-EPG7NOKI.js");
23414
23645
  const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
23415
23646
  const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
23416
23647
  const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
@@ -23453,7 +23684,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
23453
23684
  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}`));
23454
23685
  void (async () => {
23455
23686
  try {
23456
- const { collectDiagnostics } = await import("../persistent-session-HVYGIS5C.js");
23687
+ const { collectDiagnostics } = await import("../persistent-session-7HP4KOED.js");
23457
23688
  await api.post("/host/heartbeat", {
23458
23689
  host_id: hostId,
23459
23690
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
@@ -23504,7 +23735,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
23504
23735
  }
23505
23736
  try {
23506
23737
  const hostId = await getHostId();
23507
- const { collectDiagnostics } = await import("../persistent-session-HVYGIS5C.js");
23738
+ const { collectDiagnostics } = await import("../persistent-session-7HP4KOED.js");
23508
23739
  await api.post("/host/heartbeat", {
23509
23740
  host_id: hostId,
23510
23741
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
@@ -24206,7 +24437,7 @@ async function processClaudePairSessions(agents) {
24206
24437
  snapshotPairConfig,
24207
24438
  // ENG-11659: result -> report body + the manager.log line that records it.
24208
24439
  planPairStartReport
24209
- } = await import("../claude-pair-runtime-53JY6TQX.js");
24440
+ } = await import("../claude-pair-runtime-I6KVCUBG.js");
24210
24441
  const { resetClaudeSignin, describeSigninResetForLog, describeSigninResetFailure } = await import("../claude-signin-reset-6IJMMVYG.js");
24211
24442
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
24212
24443
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
@@ -25304,6 +25535,13 @@ function startManager(opts) {
25304
25535
  log(`[startup] rehydrated update-request ack at ${state9.lastUpdateRequestProcessedAt} (ENG-6692)`);
25305
25536
  }
25306
25537
  }
25538
+ const pendingAck = parsed.pendingKeyRotationAck;
25539
+ if (pendingAck && typeof pendingAck.prefix === "string" && typeof pendingAck.requestedAt === "string") {
25540
+ state9.pendingKeyRotationAck = pendingAck;
25541
+ pendingKeyRotationAck = pendingAck.prefix;
25542
+ lastKeyRotationHandled = pendingAck.requestedAt;
25543
+ log(`[startup] rehydrated pending key-rotation ack for ${pendingAck.prefix} (ENG-11642)`);
25544
+ }
25307
25545
  }
25308
25546
  } catch (err) {
25309
25547
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);