@integrity-labs/agt-cli 0.28.1015 → 0.28.1017
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 +5 -5
- package/dist/{chunk-MHDNKKEO.js → chunk-CVQDMHOP.js} +10 -2
- package/dist/{chunk-MHDNKKEO.js.map → chunk-CVQDMHOP.js.map} +1 -1
- package/dist/{chunk-GHHDFHKE.js → chunk-HIDB6U3D.js} +1558 -1372
- package/dist/chunk-HIDB6U3D.js.map +1 -0
- package/dist/{chunk-RJ3SI5JG.js → chunk-X7SX25N6.js} +20 -2
- package/dist/chunk-X7SX25N6.js.map +1 -0
- package/dist/{claude-pair-runtime-GSPFYCG4.js → claude-pair-runtime-JQRJXNSL.js} +2 -2
- package/dist/lib/manager-worker.js +178 -21
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/telegram-channel.js +194 -3
- package/dist/{persistent-session-YP2UTQGA.js → persistent-session-UZBB7EOS.js} +3 -3
- package/dist/{responsiveness-probe-YTFWHUTQ.js → responsiveness-probe-KLOUFBM5.js} +3 -3
- package/dist/{session-auth-dead-TX4YQUTJ.js → session-auth-dead-JJUKS75B.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-GHHDFHKE.js.map +0 -1
- package/dist/chunk-RJ3SI5JG.js.map +0 -1
- /package/dist/{claude-pair-runtime-GSPFYCG4.js.map → claude-pair-runtime-JQRJXNSL.js.map} +0 -0
- /package/dist/{persistent-session-YP2UTQGA.js.map → persistent-session-UZBB7EOS.js.map} +0 -0
- /package/dist/{responsiveness-probe-YTFWHUTQ.js.map → responsiveness-probe-KLOUFBM5.js.map} +0 -0
- /package/dist/{session-auth-dead-TX4YQUTJ.js.map → session-auth-dead-JJUKS75B.js.map} +0 -0
|
@@ -266,7 +266,7 @@ async function spawnPairSession(session) {
|
|
|
266
266
|
return { ok: true };
|
|
267
267
|
} catch {
|
|
268
268
|
}
|
|
269
|
-
const { resolveClaudeBinary } = await import("./persistent-session-
|
|
269
|
+
const { resolveClaudeBinary } = await import("./persistent-session-UZBB7EOS.js");
|
|
270
270
|
const claudeBin = resolveClaudeBinary();
|
|
271
271
|
const pairEnv = {
|
|
272
272
|
...process.env,
|
|
@@ -734,4 +734,4 @@ export {
|
|
|
734
734
|
startClaudePair,
|
|
735
735
|
submitClaudePairCode
|
|
736
736
|
};
|
|
737
|
-
//# sourceMappingURL=claude-pair-runtime-
|
|
737
|
+
//# sourceMappingURL=claude-pair-runtime-JQRJXNSL.js.map
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
decidePin,
|
|
19
19
|
defaultFlagsCachePath,
|
|
20
20
|
deriveMcpServerKey,
|
|
21
|
+
describeBlockedPromptHold,
|
|
21
22
|
describeChannelWriteFailure,
|
|
22
23
|
describeStartupCompletion,
|
|
23
24
|
diffEnvIntegrations,
|
|
@@ -65,7 +66,7 @@ import {
|
|
|
65
66
|
safeWriteJsonAtomic,
|
|
66
67
|
setConfigHash,
|
|
67
68
|
tripClass
|
|
68
|
-
} from "../chunk-
|
|
69
|
+
} from "../chunk-HIDB6U3D.js";
|
|
69
70
|
import {
|
|
70
71
|
getProjectDir as getProjectDir2,
|
|
71
72
|
getReadyTasks,
|
|
@@ -146,7 +147,7 @@ import {
|
|
|
146
147
|
takeZombieDetection,
|
|
147
148
|
toOpencodeModel,
|
|
148
149
|
writeEgressAllowlist
|
|
149
|
-
} from "../chunk-
|
|
150
|
+
} from "../chunk-CVQDMHOP.js";
|
|
150
151
|
import {
|
|
151
152
|
ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
|
|
152
153
|
AnchorSessionClient,
|
|
@@ -187,6 +188,7 @@ import {
|
|
|
187
188
|
classifyCursorAdvance,
|
|
188
189
|
classifyOutput,
|
|
189
190
|
classifySlackPolicyBlock,
|
|
191
|
+
classifyTelegramPolicyBlock,
|
|
190
192
|
classifyTranscriptRateLimit,
|
|
191
193
|
coerceOnboardingState,
|
|
192
194
|
cursorAdvanceCounterKey,
|
|
@@ -250,7 +252,7 @@ import {
|
|
|
250
252
|
subagentActivityAgeSeconds,
|
|
251
253
|
sumTranscriptUsageInWindow,
|
|
252
254
|
transcriptActivityAgeSeconds
|
|
253
|
-
} from "../chunk-
|
|
255
|
+
} from "../chunk-X7SX25N6.js";
|
|
254
256
|
import "../chunk-DHWNVVX4.js";
|
|
255
257
|
import {
|
|
256
258
|
reapOrphanChannelMcps
|
|
@@ -305,7 +307,44 @@ var TELEGRAM_RESTART_ON_CHANGE_ENV_KEYS = [
|
|
|
305
307
|
/** Peer kill switch. A switch whose purpose is stopping something promptly. */
|
|
306
308
|
"PEER_DISABLED",
|
|
307
309
|
/** Derived boolean mirror of the same switch, kept for the rollout. */
|
|
308
|
-
"TELEGRAM_PEER_DISABLED"
|
|
310
|
+
"TELEGRAM_PEER_DISABLED",
|
|
311
|
+
// ENG-9665. These are the purest case this list exists for: they ARE the
|
|
312
|
+
// sender policy, so a change to them is an operator changing who may talk to
|
|
313
|
+
// the agent, made in the console and visible there immediately. Waiting for
|
|
314
|
+
// an unrelated respawn would mean the console shows a restriction the running
|
|
315
|
+
// session is not applying - which is the exact ENG-9802 defect, and the same
|
|
316
|
+
// gap this file's header notes for SLACK_SENDER_POLICY.
|
|
317
|
+
//
|
|
318
|
+
// WHICH MECHANISM ACTUALLY RESPAWNS FOR THESE - Obi Wan `1c6a60a29aa5`, and
|
|
319
|
+
// it is `decideSenderPolicyRestart`, NOT this list's hash.
|
|
320
|
+
//
|
|
321
|
+
// Being classified here is a statement that a change is restart-worthy. It is
|
|
322
|
+
// NOT, for these three, the thing that delivers the restart:
|
|
323
|
+
// `telegramPolicyEnvFromInputs` builds the restart basis from the CHANNEL
|
|
324
|
+
// CONFIG, and a sender policy is not in the channel config - it is a column on
|
|
325
|
+
// `agents`. So these keys can never enter that hash, and the earlier comment
|
|
326
|
+
// here (and commit 97868b5a's message) credited a mechanism that does not
|
|
327
|
+
// reach them.
|
|
328
|
+
//
|
|
329
|
+
// The restart does happen, via `decideSenderPolicyRestart`, which reads the
|
|
330
|
+
// policy from where it actually lives and now covers telegram because
|
|
331
|
+
// `senderPolicyIsEnforcedOn('telegram')` is true. Deliberately NOT plumbed
|
|
332
|
+
// into the basis as well: that would mean two mechanisms racing to respawn on
|
|
333
|
+
// one edit, and the config-shaped one would be reading a value that is not in
|
|
334
|
+
// the config.
|
|
335
|
+
//
|
|
336
|
+
// KNOWN CONSEQUENCE, stated rather than left to be found:
|
|
337
|
+
// `isTelegramPolicyRestrictive` reads the basis, so it returns false for an
|
|
338
|
+
// agent whose ONLY Telegram restriction is a sender policy. That feeds the
|
|
339
|
+
// ENG-7771 unknown-baseline branch. Correct today only because
|
|
340
|
+
// `decideSenderPolicyRestart` covers the same agent by a different route; if
|
|
341
|
+
// that ever stops being true, this is where the gap reappears.
|
|
342
|
+
/** The mode itself. Nothing else decides more about who is admitted. */
|
|
343
|
+
"TELEGRAM_SENDER_POLICY",
|
|
344
|
+
/** manager_only's single admitted counterparty. */
|
|
345
|
+
"TELEGRAM_SENDER_POLICY_PRINCIPAL_ID",
|
|
346
|
+
/** team_only's admitted set. An edit here adds or removes people. */
|
|
347
|
+
"TELEGRAM_SENDER_POLICY_TEAM_PRINCIPAL_IDS"
|
|
309
348
|
];
|
|
310
349
|
function telegramPolicyEnvBasis(env) {
|
|
311
350
|
const parts = [];
|
|
@@ -11241,6 +11280,37 @@ function parsePeerAgentModeEnv2(raw) {
|
|
|
11241
11280
|
return "off";
|
|
11242
11281
|
}
|
|
11243
11282
|
|
|
11283
|
+
// ../../packages/core/dist/channels/governance/telegram-inbound-filter.js
|
|
11284
|
+
function isBotSender(evt) {
|
|
11285
|
+
return evt.from?.is_bot === true;
|
|
11286
|
+
}
|
|
11287
|
+
function isSameTeamPeer(evt) {
|
|
11288
|
+
const gate = evt.peerGatePath;
|
|
11289
|
+
return gate === "same_team" || gate === void 0;
|
|
11290
|
+
}
|
|
11291
|
+
function decideSenderPolicyForwardTelegram(evt, policy) {
|
|
11292
|
+
if (policy.mode === "all")
|
|
11293
|
+
return { forward: true };
|
|
11294
|
+
const fromId = evt.from?.id;
|
|
11295
|
+
if (fromId === void 0)
|
|
11296
|
+
return { forward: false, reason: "sender_policy" };
|
|
11297
|
+
const fromIdStr = String(fromId);
|
|
11298
|
+
if (policy.mode === "manager_only") {
|
|
11299
|
+
return policy.principalTelegramUserId && fromIdStr === policy.principalTelegramUserId ? { forward: true } : { forward: false, reason: "sender_policy" };
|
|
11300
|
+
}
|
|
11301
|
+
if (policy.mode === "team_only") {
|
|
11302
|
+
const list = policy.teamPrincipalTelegramUserIds;
|
|
11303
|
+
if (list && list.length > 0 && list.includes(fromIdStr)) {
|
|
11304
|
+
return { forward: true };
|
|
11305
|
+
}
|
|
11306
|
+
return isBotSender(evt) && isSameTeamPeer(evt) ? { forward: true } : { forward: false, reason: "sender_policy" };
|
|
11307
|
+
}
|
|
11308
|
+
if (policy.mode === "team_agents_only") {
|
|
11309
|
+
return isBotSender(evt) && isSameTeamPeer(evt) ? { forward: true } : { forward: false, reason: "sender_policy" };
|
|
11310
|
+
}
|
|
11311
|
+
return isBotSender(evt) ? { forward: true } : { forward: false, reason: "sender_policy" };
|
|
11312
|
+
}
|
|
11313
|
+
|
|
11244
11314
|
// ../../packages/core/dist/channels/governance/telegram-chat-type.js
|
|
11245
11315
|
function isTelegramPrivateChat(chatType) {
|
|
11246
11316
|
return chatType === "private";
|
|
@@ -11254,6 +11324,7 @@ function evaluateTelegramInboundGate(evt, deps) {
|
|
|
11254
11324
|
const content = text.length > 0 ? { forward: true } : { forward: false, reason: "empty" };
|
|
11255
11325
|
let peerLeaf;
|
|
11256
11326
|
let isSelf = false;
|
|
11327
|
+
let peerGatePath;
|
|
11257
11328
|
if (isBot) {
|
|
11258
11329
|
const classifierMsg = {
|
|
11259
11330
|
message_id: evt.message_id,
|
|
@@ -11271,6 +11342,13 @@ function evaluateTelegramInboundGate(evt, deps) {
|
|
|
11271
11342
|
const c = classifyPeerMessage2(classifierMsg, deps.peerConfig, deps.self);
|
|
11272
11343
|
isSelf = c.kind === "self";
|
|
11273
11344
|
peerLeaf = { kind: c.kind, reason: c.kind === "drop" ? c.reason : void 0 };
|
|
11345
|
+
peerGatePath = evt.from ? deps.peerConfig.peers.find((pr) => pr.bot_id === evt.from.id)?.gate_path : void 0;
|
|
11346
|
+
}
|
|
11347
|
+
const policy = deps.senderPolicy;
|
|
11348
|
+
let senderPolicyLeaf;
|
|
11349
|
+
if (policy) {
|
|
11350
|
+
const verdict = decideSenderPolicyForwardTelegram({ ...evt, peerGatePath }, policy);
|
|
11351
|
+
senderPolicyLeaf = verdict.forward ? { forward: true } : { forward: false, reason: classifyTelegramPolicyBlock(policy) };
|
|
11274
11352
|
}
|
|
11275
11353
|
const decision = decideInboundAccess({
|
|
11276
11354
|
content,
|
|
@@ -11286,7 +11364,27 @@ function evaluateTelegramInboundGate(evt, deps) {
|
|
|
11286
11364
|
// this is `{ forward: true }`, which the composer treats identically to the
|
|
11287
11365
|
// field being absent.
|
|
11288
11366
|
chatType: deps.privateChatsOnly && !isTelegramPrivateChat(evt.chat.type) ? { forward: false } : { forward: true },
|
|
11289
|
-
//
|
|
11367
|
+
// ENG-9665: the sender-policy axis, applied to ALL senders (a peer agent is
|
|
11368
|
+
// gated here too, before peer governance) exactly as on Slack and Teams.
|
|
11369
|
+
// Absent policy means `all`, which is a no-op.
|
|
11370
|
+
senderPolicy: senderPolicyLeaf,
|
|
11371
|
+
// Injection gate: no command dispatch, and NO DECLINE IS EVER SENT on this
|
|
11372
|
+
// path - so `sameOrg` has nothing to decide here.
|
|
11373
|
+
//
|
|
11374
|
+
// Obi Wan `2d99e22b7e8d`: this used to compute
|
|
11375
|
+
// `allowedChats.size > 0 && allowedChats.has(chatId)` under a comment
|
|
11376
|
+
// reasoning about decline-vs-silence as if it were live. It is not. This
|
|
11377
|
+
// function returns `{ admit, reason }` and DISCARDS `decision.decline`, and
|
|
11378
|
+
// `dispatchTelegramInbound` only logs and returns 'dropped_gate'. So the
|
|
11379
|
+
// computed value had no observable effect for any allowlist, while the
|
|
11380
|
+
// comment implied an agent WITH one would decline. A reader auditing the
|
|
11381
|
+
// insider-decline posture would have concluded opencode Telegram delivers
|
|
11382
|
+
// declines when it delivers silence in every case.
|
|
11383
|
+
//
|
|
11384
|
+
// `slack-sender-gate.ts` states this honestly with a flat `sameOrg: false`,
|
|
11385
|
+
// so this now matches its sibling. IF a decline is ever wired on this
|
|
11386
|
+
// runtime, this is the line to revisit - and the argument for what to put
|
|
11387
|
+
// here lives in telegram-channel.ts, where declines are actually sent.
|
|
11290
11388
|
sameOrg: false
|
|
11291
11389
|
});
|
|
11292
11390
|
if (decision.kind === "drop")
|
|
@@ -11317,6 +11415,32 @@ function buildTelegramPeerClassifierConfigFromEnv(env, opts) {
|
|
|
11317
11415
|
peer_disabled_mode: parseTelegramPeerDisabledModeEnv(env, opts?.onWarn)
|
|
11318
11416
|
};
|
|
11319
11417
|
}
|
|
11418
|
+
function buildTelegramSenderPolicyFromEnv(env, ctx) {
|
|
11419
|
+
const raw = (env["TELEGRAM_SENDER_POLICY"] ?? "all").trim().toLowerCase();
|
|
11420
|
+
const teamId = ctx.agentTeamId;
|
|
11421
|
+
if (raw === "all")
|
|
11422
|
+
return { mode: "all" };
|
|
11423
|
+
if (raw === "agents_only")
|
|
11424
|
+
return { mode: "agents_only" };
|
|
11425
|
+
if (raw === "team_agents_only") {
|
|
11426
|
+
if (!teamId)
|
|
11427
|
+
throw new Error("TELEGRAM_SENDER_POLICY=team_agents_only requires AGT_TEAM_ID");
|
|
11428
|
+
return { mode: "team_agents_only", teamId };
|
|
11429
|
+
}
|
|
11430
|
+
if (raw === "team_only") {
|
|
11431
|
+
if (!teamId)
|
|
11432
|
+
throw new Error("TELEGRAM_SENDER_POLICY=team_only requires AGT_TEAM_ID");
|
|
11433
|
+
const teamPrincipalTelegramUserIds = (env["TELEGRAM_SENDER_POLICY_TEAM_PRINCIPAL_IDS"] ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
11434
|
+
return { mode: "team_only", teamId, teamPrincipalTelegramUserIds };
|
|
11435
|
+
}
|
|
11436
|
+
if (raw === "manager_only") {
|
|
11437
|
+
if (!teamId)
|
|
11438
|
+
throw new Error("TELEGRAM_SENDER_POLICY=manager_only requires AGT_TEAM_ID");
|
|
11439
|
+
const principalTelegramUserId = env["TELEGRAM_SENDER_POLICY_PRINCIPAL_ID"];
|
|
11440
|
+
return principalTelegramUserId ? { mode: "manager_only", teamId, principalTelegramUserId } : { mode: "manager_only", teamId };
|
|
11441
|
+
}
|
|
11442
|
+
throw new Error(`Invalid TELEGRAM_SENDER_POLICY=${JSON.stringify(env["TELEGRAM_SENDER_POLICY"])}`);
|
|
11443
|
+
}
|
|
11320
11444
|
|
|
11321
11445
|
// src/lib/telegram-ingest.ts
|
|
11322
11446
|
var nodeHttpsTelegramFetch = (url, init) => new Promise((resolve2, reject) => {
|
|
@@ -11375,7 +11499,7 @@ function memoryOffsetStore(initial = 0) {
|
|
|
11375
11499
|
value = o;
|
|
11376
11500
|
} };
|
|
11377
11501
|
}
|
|
11378
|
-
function resolveTelegramIngestParamsFromEnv(env) {
|
|
11502
|
+
function resolveTelegramIngestParamsFromEnv(env, ctx) {
|
|
11379
11503
|
const botToken = env["TELEGRAM_BOT_TOKEN"];
|
|
11380
11504
|
if (!botToken) return null;
|
|
11381
11505
|
const ackReaction = (env["TELEGRAM_ACK_REACTION"] ?? "").trim() || "\u{1F440}";
|
|
@@ -11384,6 +11508,7 @@ function resolveTelegramIngestParamsFromEnv(env) {
|
|
|
11384
11508
|
botToken,
|
|
11385
11509
|
allowedChats: parseTelegramAllowedChatsEnv(env),
|
|
11386
11510
|
peerConfig: buildTelegramPeerClassifierConfigFromEnv(env),
|
|
11511
|
+
senderPolicy: buildTelegramSenderPolicyFromEnv(env, ctx),
|
|
11387
11512
|
ackReaction,
|
|
11388
11513
|
...skipReaction ? { skipReaction } : {}
|
|
11389
11514
|
};
|
|
@@ -11441,7 +11566,12 @@ async function dispatchTelegramInbound(update, ctx) {
|
|
|
11441
11566
|
const decision = evaluateTelegramInboundGate(msg, {
|
|
11442
11567
|
allowedChats: ctx.allowedChats,
|
|
11443
11568
|
peerConfig: ctx.peerConfig,
|
|
11444
|
-
self: ctx.self
|
|
11569
|
+
self: ctx.self,
|
|
11570
|
+
// ENG-9665 / Obi Wan `526be87f0cbd`: THE LINE THAT WAS MISSING. Without it
|
|
11571
|
+
// `deps.senderPolicy` is undefined, which the gate treats as `all`, so the
|
|
11572
|
+
// registry's claim that both runtimes supply this leaf was false on this
|
|
11573
|
+
// path. eng-9665-opencode-sender-policy.test.ts fails if it is removed.
|
|
11574
|
+
senderPolicy: ctx.senderPolicy
|
|
11445
11575
|
});
|
|
11446
11576
|
if (!decision.admit) {
|
|
11447
11577
|
ctx.log(`[telegram-ingest:${ctx.codeName}] dropped chat=${redactId(chatId)} reason=${decision.reason}`);
|
|
@@ -11548,6 +11678,7 @@ function startTelegramIngest(config2) {
|
|
|
11548
11678
|
codeName: config2.codeName,
|
|
11549
11679
|
allowedChats: config2.allowedChats,
|
|
11550
11680
|
peerConfig: config2.peerConfig,
|
|
11681
|
+
senderPolicy: config2.senderPolicy,
|
|
11551
11682
|
self: config2.self,
|
|
11552
11683
|
inject: config2.inject,
|
|
11553
11684
|
sendReply,
|
|
@@ -11635,6 +11766,10 @@ function fingerprint2(params) {
|
|
|
11635
11766
|
botToken: params.botToken,
|
|
11636
11767
|
allowedChats: [...params.allowedChats].sort(),
|
|
11637
11768
|
peerConfig: params.peerConfig,
|
|
11769
|
+
// The whole policy: the mode AND the principal identities. A revocation
|
|
11770
|
+
// changes only the ids, so hashing the mode alone would miss exactly the
|
|
11771
|
+
// case `3ff390e32af6` describes.
|
|
11772
|
+
senderPolicy: params.senderPolicy,
|
|
11638
11773
|
ackReaction: params.ackReaction ?? null,
|
|
11639
11774
|
skipReaction: params.skipReaction ?? null
|
|
11640
11775
|
})
|
|
@@ -11704,7 +11839,7 @@ async function ensureOpencodeTelegramIngest(opts) {
|
|
|
11704
11839
|
stopOpencodeTelegramIngest(codeName, log2);
|
|
11705
11840
|
return;
|
|
11706
11841
|
}
|
|
11707
|
-
params = resolveTelegramIngestParamsFromEnv(env);
|
|
11842
|
+
params = resolveTelegramIngestParamsFromEnv(env, { agentTeamId: env["AGT_TEAM_ID"] ?? null });
|
|
11708
11843
|
} catch (err) {
|
|
11709
11844
|
stopOpencodeTelegramIngest(codeName, log2);
|
|
11710
11845
|
log2(`[telegram-ingest:${codeName}] not started: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -11740,6 +11875,7 @@ async function ensureOpencodeTelegramIngest(opts) {
|
|
|
11740
11875
|
botToken: params.botToken,
|
|
11741
11876
|
allowedChats: params.allowedChats,
|
|
11742
11877
|
peerConfig: params.peerConfig,
|
|
11878
|
+
senderPolicy: params.senderPolicy,
|
|
11743
11879
|
self,
|
|
11744
11880
|
inject: (msg) => injectOpencodeMessage(codeName, msg, { awaitReply: true }),
|
|
11745
11881
|
log: log2,
|
|
@@ -13654,7 +13790,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
|
|
|
13654
13790
|
var dayRolloverInboundHold = /* @__PURE__ */ new Map();
|
|
13655
13791
|
var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
|
|
13656
13792
|
async function channelInboundActivityAgeSecondsFor(codeName) {
|
|
13657
|
-
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-
|
|
13793
|
+
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-KLOUFBM5.js");
|
|
13658
13794
|
const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
|
|
13659
13795
|
if (newest === null) return null;
|
|
13660
13796
|
return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
|
|
@@ -14173,7 +14309,7 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gate
|
|
|
14173
14309
|
const gate = restartGateFor(codeName, gateReason);
|
|
14174
14310
|
if (gate !== "bypass" && gate !== "proceed") {
|
|
14175
14311
|
log(`[maintenance-window] Deferring '${gateReason}' restart for '${codeName}' (${gate})`);
|
|
14176
|
-
return;
|
|
14312
|
+
return false;
|
|
14177
14313
|
}
|
|
14178
14314
|
cancelPendingSessionRestart(codeName);
|
|
14179
14315
|
stopPersistentSession(codeName, log);
|
|
@@ -14191,6 +14327,7 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gate
|
|
|
14191
14327
|
recordRestartForBreaker(codeName, breakerReason);
|
|
14192
14328
|
}
|
|
14193
14329
|
reportRestartEvent(codeName, breakerReason, auditDetail);
|
|
14330
|
+
return true;
|
|
14194
14331
|
}
|
|
14195
14332
|
var agentRuntimeTeardownDeps = {
|
|
14196
14333
|
stopOpencodeServe: (codeName, teardownLog) => stopOpencodeSession(codeName, teardownLog),
|
|
@@ -14397,7 +14534,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
14397
14534
|
var lastVersionCheckAt = 0;
|
|
14398
14535
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
14399
14536
|
var lastResponsivenessProbeAt = 0;
|
|
14400
|
-
var agtCliVersion = true ? "0.28.
|
|
14537
|
+
var agtCliVersion = true ? "0.28.1017" : "dev";
|
|
14401
14538
|
function resolveBrewPath(execFileSync3) {
|
|
14402
14539
|
try {
|
|
14403
14540
|
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -16032,7 +16169,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
16032
16169
|
if (codeNames.length === 0) return;
|
|
16033
16170
|
void (async () => {
|
|
16034
16171
|
try {
|
|
16035
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
16172
|
+
const { collectDiagnostics } = await import("../persistent-session-UZBB7EOS.js");
|
|
16036
16173
|
await api.post("/host/heartbeat", {
|
|
16037
16174
|
host_id: hostId,
|
|
16038
16175
|
agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
|
|
@@ -16174,7 +16311,7 @@ async function pollCycleInner() {
|
|
|
16174
16311
|
}
|
|
16175
16312
|
try {
|
|
16176
16313
|
const { detectHostSecurity } = await import("../host-security-KQYYZZVW.js");
|
|
16177
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
16314
|
+
const { collectDiagnostics } = await import("../persistent-session-UZBB7EOS.js");
|
|
16178
16315
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
16179
16316
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor) : void 0;
|
|
16180
16317
|
let tailscaleHostname;
|
|
@@ -16350,7 +16487,7 @@ async function pollCycleInner() {
|
|
|
16350
16487
|
collectPanelessActivityProbes,
|
|
16351
16488
|
getResponsivenessIntervalMs,
|
|
16352
16489
|
occupancyQualificationClassifications
|
|
16353
|
-
} = await import("../responsiveness-probe-
|
|
16490
|
+
} = await import("../responsiveness-probe-KLOUFBM5.js");
|
|
16354
16491
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
16355
16492
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
16356
16493
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -16467,7 +16604,7 @@ async function pollCycleInner() {
|
|
|
16467
16604
|
collectResponsivenessProbes,
|
|
16468
16605
|
livePendingInboundOldestAgeSeconds,
|
|
16469
16606
|
parkPendingInbound
|
|
16470
|
-
} = await import("../responsiveness-probe-
|
|
16607
|
+
} = await import("../responsiveness-probe-KLOUFBM5.js");
|
|
16471
16608
|
const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-M6AFZWNU.js");
|
|
16472
16609
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
16473
16610
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -16623,7 +16760,7 @@ async function pollCycleInner() {
|
|
|
16623
16760
|
}
|
|
16624
16761
|
try {
|
|
16625
16762
|
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-VR5QGP3J.js");
|
|
16626
|
-
const { probeSessionAuth } = await import("../session-auth-dead-
|
|
16763
|
+
const { probeSessionAuth } = await import("../session-auth-dead-JJUKS75B.js");
|
|
16627
16764
|
const observations = [];
|
|
16628
16765
|
const pendingCacheCommits = [];
|
|
16629
16766
|
const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
|
|
@@ -19480,6 +19617,26 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
19480
19617
|
);
|
|
19481
19618
|
reapMissingMcpSessions({
|
|
19482
19619
|
log,
|
|
19620
|
+
/**
|
|
19621
|
+
* ENG-10878: let the reaper see the budget it would be spending.
|
|
19622
|
+
*
|
|
19623
|
+
* `mcp-presence-reaper` is on the TIGHT crash bar with
|
|
19624
|
+
* `auth-tuple-change` and `model-change` - 2 in 600s, the 3rd trips.
|
|
19625
|
+
* NOT with `day-rollover` or `channel-set-change`, which this comment
|
|
19626
|
+
* used to name (obi-wan `486aa45fa3bd`): those are `'scheduled'` and
|
|
19627
|
+
* `'provisioning'` class and are not counted by `remainingCrashBudget`
|
|
19628
|
+
* at all. The single restart ENG-10878 spends on a blocked
|
|
19629
|
+
* pane cannot trip the breaker alone, but it can be the event that lets
|
|
19630
|
+
* a later one do it, and the agent is then paused on another reason's
|
|
19631
|
+
* account. With this wired, the reaper declines the restart when there
|
|
19632
|
+
* is nothing left and says so, rather than spending the last unit.
|
|
19633
|
+
*
|
|
19634
|
+
* The arithmetic lives in the breaker (`remainingCrashBudget`) rather
|
|
19635
|
+
* than here: `max` and the window are its business and are env-tunable,
|
|
19636
|
+
* so computing it at the call site would quietly stop being correct the
|
|
19637
|
+
* moment either moves.
|
|
19638
|
+
*/
|
|
19639
|
+
restartBudgetRemaining: (codeName) => restartBreaker.remainingCrashBudget(codeName),
|
|
19483
19640
|
codeName: agent.code_name,
|
|
19484
19641
|
mcpJson: computerUseReaperView(mcpJsonParsed, computerUseVerdict),
|
|
19485
19642
|
sessionStartedAt: sess?.startedAt ?? null,
|
|
@@ -19565,7 +19722,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
19565
19722
|
agent.agent_id,
|
|
19566
19723
|
"mcp-presence-reaper",
|
|
19567
19724
|
"blocked",
|
|
19568
|
-
|
|
19725
|
+
`${describeBlockedPromptHold(ctx)}: tmux attach -t agt-${codeName}` + // Fingerprint, never pane text. This string is persisted on the
|
|
19569
19726
|
// alert row, so it leaves the host; the pane can hold the
|
|
19570
19727
|
// customer message the agent was mid-turn on. Same policy the
|
|
19571
19728
|
// channel-input-watchdog follows for this very block.
|
|
@@ -21007,7 +21164,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
21007
21164
|
try {
|
|
21008
21165
|
const freshId = rotateSessionForWedge(codeName);
|
|
21009
21166
|
consecutiveWedgeCycles.delete(codeName);
|
|
21010
|
-
const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-
|
|
21167
|
+
const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-KLOUFBM5.js");
|
|
21011
21168
|
const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
|
|
21012
21169
|
const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
|
|
21013
21170
|
const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
|
|
@@ -21050,7 +21207,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
21050
21207
|
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}`));
|
|
21051
21208
|
void (async () => {
|
|
21052
21209
|
try {
|
|
21053
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
21210
|
+
const { collectDiagnostics } = await import("../persistent-session-UZBB7EOS.js");
|
|
21054
21211
|
await api.post("/host/heartbeat", {
|
|
21055
21212
|
host_id: hostId,
|
|
21056
21213
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
|
|
@@ -21101,7 +21258,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
21101
21258
|
}
|
|
21102
21259
|
try {
|
|
21103
21260
|
const hostId = await getHostId();
|
|
21104
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
21261
|
+
const { collectDiagnostics } = await import("../persistent-session-UZBB7EOS.js");
|
|
21105
21262
|
await api.post("/host/heartbeat", {
|
|
21106
21263
|
host_id: hostId,
|
|
21107
21264
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
|
|
@@ -21772,7 +21929,7 @@ async function processClaudePairSessions(agents) {
|
|
|
21772
21929
|
// cannot take it for itself — by the time it runs, the write it is looking
|
|
21773
21930
|
// for may already have happened.
|
|
21774
21931
|
snapshotPairConfig
|
|
21775
|
-
} = await import("../claude-pair-runtime-
|
|
21932
|
+
} = await import("../claude-pair-runtime-JQRJXNSL.js");
|
|
21776
21933
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
21777
21934
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
21778
21935
|
const killed = await killPairSession(pairTmuxSession(pairId));
|