@integrity-labs/agt-cli 0.28.661 → 0.28.662
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-
|
|
43
|
+
} from "../chunk-77YTVCXK.js";
|
|
44
44
|
import {
|
|
45
45
|
readDirectChatSessionState
|
|
46
46
|
} from "../chunk-5JAUM7J2.js";
|
|
@@ -4909,7 +4909,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4909
4909
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4910
4910
|
import chalk18 from "chalk";
|
|
4911
4911
|
import ora16 from "ora";
|
|
4912
|
-
var cliVersion = true ? "0.28.
|
|
4912
|
+
var cliVersion = true ? "0.28.662" : "dev";
|
|
4913
4913
|
async function fetchLatestVersion() {
|
|
4914
4914
|
const host2 = getHost();
|
|
4915
4915
|
if (!host2) return null;
|
|
@@ -6089,7 +6089,7 @@ function handleError(err) {
|
|
|
6089
6089
|
}
|
|
6090
6090
|
|
|
6091
6091
|
// src/bin/agt.ts
|
|
6092
|
-
var cliVersion2 = true ? "0.28.
|
|
6092
|
+
var cliVersion2 = true ? "0.28.662" : "dev";
|
|
6093
6093
|
var program = new Command();
|
|
6094
6094
|
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");
|
|
6095
6095
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -6342,7 +6342,7 @@ function exchangeFailureKind(err) {
|
|
|
6342
6342
|
}
|
|
6343
6343
|
|
|
6344
6344
|
// src/lib/api-client.ts
|
|
6345
|
-
var agtCliVersion = true ? "0.28.
|
|
6345
|
+
var agtCliVersion = true ? "0.28.662" : "dev";
|
|
6346
6346
|
var lastConfigHash = null;
|
|
6347
6347
|
function setConfigHash(hash) {
|
|
6348
6348
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -10084,4 +10084,4 @@ export {
|
|
|
10084
10084
|
managerInstallSystemUnitCommand,
|
|
10085
10085
|
managerUninstallSystemUnitCommand
|
|
10086
10086
|
};
|
|
10087
|
-
//# sourceMappingURL=chunk-
|
|
10087
|
+
//# sourceMappingURL=chunk-77YTVCXK.js.map
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
safeWriteJsonAtomic,
|
|
56
56
|
setConfigHash,
|
|
57
57
|
tripClass
|
|
58
|
-
} from "../chunk-
|
|
58
|
+
} from "../chunk-77YTVCXK.js";
|
|
59
59
|
import {
|
|
60
60
|
getProjectDir as getProjectDir2,
|
|
61
61
|
getReadyTasks,
|
|
@@ -12219,6 +12219,7 @@ function resolveAgentFramework(codeName) {
|
|
|
12219
12219
|
function clearAgentCaches(agentId, codeName) {
|
|
12220
12220
|
const channelCacheMutated = clearAgentState(agentId, codeName);
|
|
12221
12221
|
agentChannelTokens.delete(codeName);
|
|
12222
|
+
forgetChannelSyncState(agentId);
|
|
12222
12223
|
sharedBusyBuckets.reset(codeName);
|
|
12223
12224
|
stopOpencodeSlackIngest(codeName, log);
|
|
12224
12225
|
stopOpencodeTelegramIngest(codeName, log);
|
|
@@ -12252,7 +12253,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
12252
12253
|
var lastVersionCheckAt = 0;
|
|
12253
12254
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
12254
12255
|
var lastResponsivenessProbeAt = 0;
|
|
12255
|
-
var agtCliVersion = true ? "0.28.
|
|
12256
|
+
var agtCliVersion = true ? "0.28.662" : "dev";
|
|
12256
12257
|
function resolveBrewPath(execFileSync3) {
|
|
12257
12258
|
try {
|
|
12258
12259
|
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -13355,6 +13356,60 @@ function saveChannelHashCache2() {
|
|
|
13355
13356
|
}
|
|
13356
13357
|
var channelWriteFailureCounts = /* @__PURE__ */ new Map();
|
|
13357
13358
|
var CHANNEL_WRITE_FAILURE_ESCALATE_EVERY = 90;
|
|
13359
|
+
var channelSyncFailures = /* @__PURE__ */ new Map();
|
|
13360
|
+
var channelSyncAttemptedSets = /* @__PURE__ */ new Map();
|
|
13361
|
+
function sameChannelSet(a, b) {
|
|
13362
|
+
if (a === void 0) return false;
|
|
13363
|
+
if (a.size !== b.size) return false;
|
|
13364
|
+
for (const v of b) if (!a.has(v)) return false;
|
|
13365
|
+
return true;
|
|
13366
|
+
}
|
|
13367
|
+
function forgetChannelSyncState(agentId) {
|
|
13368
|
+
channelSyncFailures.delete(agentId);
|
|
13369
|
+
channelSyncAttemptedSets.delete(agentId);
|
|
13370
|
+
}
|
|
13371
|
+
var CHANNEL_SYNC_FREE_ATTEMPTS = 3;
|
|
13372
|
+
var CHANNEL_SYNC_MAX_BACKOFF_MS = 5 * 6e4;
|
|
13373
|
+
var CHANNEL_SYNC_STUCK_AFTER_MS = 10 * 6e4;
|
|
13374
|
+
function channelSyncBackoffMs(attempts) {
|
|
13375
|
+
if (attempts <= CHANNEL_SYNC_FREE_ATTEMPTS) return 0;
|
|
13376
|
+
const step = attempts - CHANNEL_SYNC_FREE_ATTEMPTS;
|
|
13377
|
+
const delay = 1e4 * 2 ** (step - 1);
|
|
13378
|
+
return Math.min(delay, CHANNEL_SYNC_MAX_BACKOFF_MS);
|
|
13379
|
+
}
|
|
13380
|
+
function recordChannelSyncFailure(failures, agentId, reason, now) {
|
|
13381
|
+
const prior = failures.get(agentId);
|
|
13382
|
+
const attempts = (prior?.attempts ?? 0) + 1;
|
|
13383
|
+
const next = {
|
|
13384
|
+
attempts,
|
|
13385
|
+
since: prior?.since ?? now,
|
|
13386
|
+
lastReason: reason,
|
|
13387
|
+
loggedAtAttempt: prior?.loggedAtAttempt ?? 0,
|
|
13388
|
+
nextAttemptAt: now + channelSyncBackoffMs(attempts)
|
|
13389
|
+
};
|
|
13390
|
+
failures.set(agentId, next);
|
|
13391
|
+
return next;
|
|
13392
|
+
}
|
|
13393
|
+
function shouldLogChannelSyncFailure(state8) {
|
|
13394
|
+
if (state8.attempts === 1) return true;
|
|
13395
|
+
if (state8.attempts <= CHANNEL_SYNC_FREE_ATTEMPTS) return false;
|
|
13396
|
+
return state8.attempts > state8.loggedAtAttempt;
|
|
13397
|
+
}
|
|
13398
|
+
function stuckChannelSyncs(failures, now, thresholdMs = CHANNEL_SYNC_STUCK_AFTER_MS) {
|
|
13399
|
+
const out = [];
|
|
13400
|
+
for (const [agentId, state8] of failures) {
|
|
13401
|
+
const stuckForMs = now - state8.since;
|
|
13402
|
+
if (stuckForMs < thresholdMs) continue;
|
|
13403
|
+
out.push({
|
|
13404
|
+
agent_id: agentId,
|
|
13405
|
+
attempts: state8.attempts,
|
|
13406
|
+
stuck_for_seconds: Math.floor(stuckForMs / 1e3),
|
|
13407
|
+
reason: state8.lastReason
|
|
13408
|
+
});
|
|
13409
|
+
}
|
|
13410
|
+
out.sort((a, b) => b.stuck_for_seconds - a.stuck_for_seconds);
|
|
13411
|
+
return out;
|
|
13412
|
+
}
|
|
13358
13413
|
var persistedDeliveryBaseline = createDeliveryBaselineMaps();
|
|
13359
13414
|
function loadSenderPolicyBaseline2() {
|
|
13360
13415
|
loadSenderPolicyBaseline(persistedDeliveryBaseline, channelHashCacheDir(), log);
|
|
@@ -13749,6 +13804,22 @@ async function pollCycleInner() {
|
|
|
13749
13804
|
// Omitted (undefined) on hosts that haven't run the assertion
|
|
13750
13805
|
// (non-claude-code frameworks).
|
|
13751
13806
|
channels_setting_status: lastManagedSettingsStatus ?? void 0,
|
|
13807
|
+
// ENG-9252: agents whose channel credential sync has failed to converge
|
|
13808
|
+
// for longer than CHANNEL_SYNC_STUCK_AFTER_MS. The API opens/closes a
|
|
13809
|
+
// per-agent alert on the edge, exactly as it does for
|
|
13810
|
+
// `channels_setting_status` above.
|
|
13811
|
+
//
|
|
13812
|
+
// This field is the whole point of the ticket. The retry loop it
|
|
13813
|
+
// reports on ran for over three hours on a customer host and raised
|
|
13814
|
+
// NOTHING: non-convergence moves no heartbeat, no session-health signal
|
|
13815
|
+
// and no restart counter, so every projection an operator would consult
|
|
13816
|
+
// read healthy while the manager span. A bounded retry that is still
|
|
13817
|
+
// silent would have fixed the CPU and left the invisibility.
|
|
13818
|
+
//
|
|
13819
|
+
// ALWAYS SENT, including as an empty array — that is what lets the API
|
|
13820
|
+
// close a resolved alert on the edge. Omitting it when empty would make
|
|
13821
|
+
// "recovered" and "this CLI is too old to report" the same wire value.
|
|
13822
|
+
channel_sync_stuck: stuckChannelSyncs(channelSyncFailures, Date.now()),
|
|
13752
13823
|
// ENG-6251: capability advertisement — the flags schema version this
|
|
13753
13824
|
// CLI compiled with, so the admin UI can show flip reach across a
|
|
13754
13825
|
// mixed-CLI fleet (an older CLI sends an older fingerprint).
|
|
@@ -14678,6 +14749,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
14678
14749
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
14679
14750
|
let agentDir = join36(adapter.getAgentDir(agent.code_name), "provision");
|
|
14680
14751
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
14752
|
+
forgetChannelSyncState(agent.agent_id);
|
|
14681
14753
|
if (previousKnownStatus !== agent.status) {
|
|
14682
14754
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
14683
14755
|
}
|
|
@@ -14881,6 +14953,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
14881
14953
|
const previousChannelIds = agentState.knownChannels.get(agent.agent_id);
|
|
14882
14954
|
const channelsChanged = !previousChannelIds || currentChannelIds.size !== previousChannelIds.size || [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) || [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));
|
|
14883
14955
|
let channelConfigConverged = true;
|
|
14956
|
+
let channelConfigFailureReason = "";
|
|
14957
|
+
const attemptedChannelIds = channelSyncAttemptedSets.get(agent.agent_id);
|
|
14958
|
+
const channelSetChangedSinceAttempt = !sameChannelSet(attemptedChannelIds, currentChannelIds);
|
|
14959
|
+
if (attemptedChannelIds !== void 0 && channelSetChangedSinceAttempt && channelSyncFailures.delete(agent.agent_id)) {
|
|
14960
|
+
log(
|
|
14961
|
+
`[channels] channel set changed for '${agent.code_name}' since the last attempt \u2014 clearing the credential-sync backoff and retrying immediately (ENG-9252)`
|
|
14962
|
+
);
|
|
14963
|
+
}
|
|
14884
14964
|
if (previousChannelIds && channelsChanged && frameworkAdapter.removeChannelCredentials) {
|
|
14885
14965
|
for (const ch of previousChannelIds) {
|
|
14886
14966
|
if (!currentChannelIds.has(ch)) {
|
|
@@ -14889,6 +14969,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
14889
14969
|
log(`Removed ${ch} credentials for '${agent.code_name}'`);
|
|
14890
14970
|
} catch (err) {
|
|
14891
14971
|
channelConfigConverged = false;
|
|
14972
|
+
channelConfigFailureReason = `removing ${ch} credentials threw: ${err.message}`;
|
|
14892
14973
|
log(`Failed to remove ${ch} credentials for '${agent.code_name}': ${err.message}`);
|
|
14893
14974
|
}
|
|
14894
14975
|
}
|
|
@@ -15152,7 +15233,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15152
15233
|
agentChannelTokens.delete(agent.code_name);
|
|
15153
15234
|
}
|
|
15154
15235
|
}
|
|
15155
|
-
|
|
15236
|
+
const channelSyncBackoff = channelSyncFailures.get(agent.agent_id);
|
|
15237
|
+
const channelSyncDeferred = channelSyncBackoff !== void 0 && Date.now() < channelSyncBackoff.nextAttemptAt;
|
|
15238
|
+
if (!channelSyncDeferred) {
|
|
15239
|
+
channelSyncAttemptedSets.set(agent.agent_id, new Set(currentChannelIds));
|
|
15240
|
+
}
|
|
15241
|
+
if (refreshData.channel_configs && frameworkAdapter.writeChannelCredentials && !channelSyncDeferred) {
|
|
15156
15242
|
if (agent.status === "active") {
|
|
15157
15243
|
for (const [channelId, entry] of Object.entries(refreshData.channel_configs)) {
|
|
15158
15244
|
if (quarantinedChannels.has(channelId)) {
|
|
@@ -15257,6 +15343,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15257
15343
|
const landed = frameworkAdapter.hasChannelCredentials?.(agent.code_name, channelId) ?? true;
|
|
15258
15344
|
if (!landed) {
|
|
15259
15345
|
channelConfigConverged = false;
|
|
15346
|
+
channelConfigFailureReason = `credentials for ${channelId} reported a clean write but did not land on disk (reason=${reason}) \u2014 likely a missing credential field, or the guarded .mcp.json write was rejected by the secret lint / config validator`;
|
|
15260
15347
|
const attempts = (channelWriteFailureCounts.get(cacheKey) ?? 0) + 1;
|
|
15261
15348
|
channelWriteFailureCounts.set(cacheKey, attempts);
|
|
15262
15349
|
if (attempts === 1 || attempts % CHANNEL_WRITE_FAILURE_ESCALATE_EVERY === 0) {
|
|
@@ -15274,6 +15361,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15274
15361
|
}
|
|
15275
15362
|
} catch (err) {
|
|
15276
15363
|
channelConfigConverged = false;
|
|
15364
|
+
channelConfigFailureReason = `writing ${channelId} credentials threw: ${err.message}`;
|
|
15277
15365
|
log(`Failed to write channel credentials for '${agent.code_name}/${channelId}': ${err.message}`);
|
|
15278
15366
|
}
|
|
15279
15367
|
}
|
|
@@ -15287,11 +15375,35 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15287
15375
|
}
|
|
15288
15376
|
}
|
|
15289
15377
|
if (channelConfigConverged) {
|
|
15290
|
-
|
|
15378
|
+
const ended = channelSyncFailures.get(agent.agent_id);
|
|
15379
|
+
if (ended && !channelSyncDeferred) {
|
|
15380
|
+
channelSyncFailures.delete(agent.agent_id);
|
|
15381
|
+
const stuckForSeconds = Math.floor((Date.now() - ended.since) / 1e3);
|
|
15382
|
+
log(
|
|
15383
|
+
`[channels] Credential sync for '${agent.code_name}' converged after ${ended.attempts} failed attempt(s) over ${stuckForSeconds}s \u2014 recovered (ENG-9252)`
|
|
15384
|
+
);
|
|
15385
|
+
}
|
|
15386
|
+
if (!channelSyncDeferred) {
|
|
15387
|
+
agentState.knownChannels.set(agent.agent_id, currentChannelIds);
|
|
15388
|
+
}
|
|
15291
15389
|
} else {
|
|
15292
|
-
|
|
15390
|
+
const state8 = recordChannelSyncFailure(
|
|
15391
|
+
channelSyncFailures,
|
|
15392
|
+
agent.agent_id,
|
|
15393
|
+
channelConfigFailureReason || "reason not recorded",
|
|
15394
|
+
Date.now()
|
|
15395
|
+
);
|
|
15396
|
+
if (shouldLogChannelSyncFailure(state8)) {
|
|
15397
|
+
state8.loggedAtAttempt = state8.attempts;
|
|
15398
|
+
const stuckForSeconds = Math.floor((Date.now() - state8.since) / 1e3);
|
|
15399
|
+
const waitMs = channelSyncBackoffMs(state8.attempts);
|
|
15400
|
+
log(
|
|
15401
|
+
`[channels] Credential sync did not converge for '${agent.code_name}' \u2014 attempt ${state8.attempts}, stuck ${stuckForSeconds}s, next retry in ${Math.round(waitMs / 1e3)}s. Cause: ${state8.lastReason}. Diff left live (ENG-9252).`
|
|
15402
|
+
);
|
|
15403
|
+
}
|
|
15293
15404
|
}
|
|
15294
|
-
const
|
|
15405
|
+
const channelConfigConvergedThisTick = channelConfigConverged && !channelSyncDeferred;
|
|
15406
|
+
const restartDecision = channelConfigConvergedThisTick ? decideChannelRestart({
|
|
15295
15407
|
previousChannelIds,
|
|
15296
15408
|
currentChannelIds,
|
|
15297
15409
|
sessionMode: refreshData.agent.session_mode,
|
|
@@ -15343,7 +15455,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15343
15455
|
writeDmNoticeMarkers
|
|
15344
15456
|
);
|
|
15345
15457
|
}
|
|
15346
|
-
if (
|
|
15458
|
+
if (channelConfigConvergedThisTick) {
|
|
15347
15459
|
const hasSenderPolicyChannel = currentChannelIds.has("slack") || currentChannelIds.has("msteams");
|
|
15348
15460
|
const senderPolicyForRestartHash = refreshData.sender_policy ?? null;
|
|
15349
15461
|
const senderPolicyHash = computeSenderPolicyRestartHash(senderPolicyForRestartHash);
|
|
@@ -16376,7 +16488,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16376
16488
|
} catch (err) {
|
|
16377
16489
|
log(`[hot-reload] .mcp.json drift check failed for '${agent.code_name}': ${err.message}`);
|
|
16378
16490
|
}
|
|
16379
|
-
if (
|
|
16491
|
+
if (channelConfigConvergedThisTick) {
|
|
16380
16492
|
try {
|
|
16381
16493
|
checkChannelSecretDriftAndScheduleRestart(agent.code_name, getProjectDir(agent.code_name));
|
|
16382
16494
|
} catch (err) {
|
|
@@ -19314,12 +19426,16 @@ process.on("disconnect", () => {
|
|
|
19314
19426
|
});
|
|
19315
19427
|
export {
|
|
19316
19428
|
BACK_ONLINE_GREETING_GUIDANCE,
|
|
19429
|
+
CHANNEL_SYNC_FREE_ATTEMPTS,
|
|
19430
|
+
CHANNEL_SYNC_MAX_BACKOFF_MS,
|
|
19431
|
+
CHANNEL_SYNC_STUCK_AFTER_MS,
|
|
19317
19432
|
DAY_ROLLOVER_FORCE_GRACE_MIN,
|
|
19318
19433
|
DAY_ROLLOVER_INBOUND_DEFER_MAX_MIN,
|
|
19319
19434
|
DAY_ROLLOVER_INBOUND_GRACE_SEC,
|
|
19320
19435
|
UntrustworthyToolkitResponseError,
|
|
19321
19436
|
applyRestartAcks,
|
|
19322
19437
|
cancelKanbanNoticeOnDrain,
|
|
19438
|
+
channelSyncBackoffMs,
|
|
19323
19439
|
classifyLazyDayRolloverReset,
|
|
19324
19440
|
claudeCodeUpgradeMarkerPath,
|
|
19325
19441
|
claudeCodeUpgradeThrottled,
|
|
@@ -19334,6 +19450,7 @@ export {
|
|
|
19334
19450
|
extractCharterSlackPeers,
|
|
19335
19451
|
extractCharterTelegramPeers,
|
|
19336
19452
|
fetchManagedToolkits,
|
|
19453
|
+
forgetChannelSyncState,
|
|
19337
19454
|
hasRevokedResiduals,
|
|
19338
19455
|
inboundHoldMinutes,
|
|
19339
19456
|
isOlderSemverTuple,
|
|
@@ -19342,10 +19459,13 @@ export {
|
|
|
19342
19459
|
maybeInjectKanbanCheck,
|
|
19343
19460
|
maybeProbeClaudeRuntimeAuth,
|
|
19344
19461
|
maybeUpgradeClaudeCode,
|
|
19462
|
+
recordChannelSyncFailure,
|
|
19345
19463
|
refreshSkillsIndexInClaudeMd,
|
|
19346
19464
|
reorderRestartedFirst,
|
|
19347
19465
|
resolveManagedMcpServerId,
|
|
19348
19466
|
restartReasonBindsNewMcp,
|
|
19467
|
+
sameChannelSet,
|
|
19468
|
+
shouldLogChannelSyncFailure,
|
|
19349
19469
|
shouldReapOnRetag,
|
|
19350
19470
|
shouldReportRestartToAudit,
|
|
19351
19471
|
shouldSkipRevokedCleanup,
|
|
@@ -19353,6 +19473,7 @@ export {
|
|
|
19353
19473
|
stampClaudeCodeUpgradeMarker,
|
|
19354
19474
|
startManager,
|
|
19355
19475
|
stopManager,
|
|
19476
|
+
stuckChannelSyncs,
|
|
19356
19477
|
supersededRuntimeImageIds
|
|
19357
19478
|
};
|
|
19358
19479
|
//# sourceMappingURL=manager-worker.js.map
|