@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.
- package/dist/bin/agt.js +104 -417
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-H37WRW2E.js → chunk-3XURNDW5.js} +6 -5
- package/dist/chunk-3XURNDW5.js.map +1 -0
- package/dist/{chunk-45UH24I2.js → chunk-DAIXT5DR.js} +435 -56
- package/dist/chunk-DAIXT5DR.js.map +1 -0
- package/dist/{manager-supervisor-KIFBGETA.js → chunk-H3JMPEH7.js} +176 -8
- package/dist/chunk-H3JMPEH7.js.map +1 -0
- package/dist/{chunk-47P33SZF.js → chunk-MHSZBN6M.js} +12 -2
- package/dist/chunk-MHSZBN6M.js.map +1 -0
- package/dist/{chunk-DJNCIWVG.js → chunk-MO5JQVBG.js} +2 -2
- package/dist/{chunk-NHUXO5H2.js → chunk-R2NQG77N.js} +2 -2
- package/dist/{claude-code-updater-H7RNX6M7.js → claude-code-updater-F2O3LAWX.js} +3 -3
- package/dist/{claude-pair-runtime-53JY6TQX.js → claude-pair-runtime-I6KVCUBG.js} +3 -3
- package/dist/lib/manager-worker.js +258 -20
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/manager-supervisor-TD7E6FPC.js +26 -0
- package/dist/mcp/direct-chat-channel.js +4 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/origami.js +4 -0
- package/dist/mcp/slack-channel.js +4 -0
- package/dist/mcp/telegram-channel.js +4 -0
- package/dist/{persistent-session-HVYGIS5C.js → persistent-session-7HP4KOED.js} +4 -4
- package/dist/persistent-session-7HP4KOED.js.map +1 -0
- package/dist/{responsiveness-probe-OGZ6ADVR.js → responsiveness-probe-EPG7NOKI.js} +4 -4
- package/dist/{session-auth-dead-2JJLKURE.js → session-auth-dead-IG3MKV2W.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-45UH24I2.js.map +0 -1
- package/dist/chunk-47P33SZF.js.map +0 -1
- package/dist/chunk-H37WRW2E.js.map +0 -1
- package/dist/manager-supervisor-KIFBGETA.js.map +0 -1
- /package/dist/{chunk-DJNCIWVG.js.map → chunk-MO5JQVBG.js.map} +0 -0
- /package/dist/{chunk-NHUXO5H2.js.map → chunk-R2NQG77N.js.map} +0 -0
- /package/dist/{claude-code-updater-H7RNX6M7.js.map → claude-code-updater-F2O3LAWX.js.map} +0 -0
- /package/dist/{claude-pair-runtime-53JY6TQX.js.map → claude-pair-runtime-I6KVCUBG.js.map} +0 -0
- /package/dist/{persistent-session-HVYGIS5C.js.map → manager-supervisor-TD7E6FPC.js.map} +0 -0
- /package/dist/{responsiveness-probe-OGZ6ADVR.js.map → responsiveness-probe-EPG7NOKI.js.map} +0 -0
- /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-
|
|
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-
|
|
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-
|
|
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-
|
|
725
|
+
//# sourceMappingURL=chunk-R2NQG77N.js.map
|
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
probeClaudeInstalls,
|
|
14
14
|
readsAsNativeInstall,
|
|
15
15
|
shouldRunClaudeCodeUpdater
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-R2NQG77N.js";
|
|
17
17
|
import "./chunk-XWVM4KPK.js";
|
|
18
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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}`);
|