switchroom 0.19.1 → 0.19.3
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/agent-scheduler/index.js +31 -1
- package/dist/auth-broker/index.js +565 -48
- package/dist/cli/autoaccept-poll.js +31 -1
- package/dist/cli/drive-write-pretool.mjs +32 -2
- package/dist/cli/ms-365-write-pretool.mjs +32 -2
- package/dist/cli/switchroom.js +1148 -274
- package/dist/host-control/main.js +3 -3
- package/dist/vault/approvals/kernel-server.js +2 -2
- package/dist/vault/broker/server.js +2 -2
- package/package.json +3 -2
- package/profiles/_base/start.sh.hbs +1 -0
- package/profiles/default/CLAUDE.md.hbs +8 -0
- package/skills/mental-model-curator/SKILL.md +68 -2
- package/skills/switchroom-cli/SKILL.md +25 -0
- package/telegram-plugin/auth-snapshot-format.ts +143 -12
- package/telegram-plugin/dist/bridge/bridge.js +8 -2
- package/telegram-plugin/dist/gateway/gateway.js +1427 -689
- package/telegram-plugin/dist/server.js +8 -2
- package/telegram-plugin/external-spend.ts +135 -0
- package/telegram-plugin/flushed-turn-supersede.ts +117 -13
- package/telegram-plugin/gateway/auth-add-flow.ts +215 -6
- package/telegram-plugin/gateway/auth-command.ts +138 -5
- package/telegram-plugin/gateway/gateway.ts +141 -158
- package/telegram-plugin/gateway/inbound-interceptors.ts +13 -3
- package/telegram-plugin/gateway/model-command.ts +309 -1
- package/telegram-plugin/gateway/narrative-lane.ts +23 -9
- package/telegram-plugin/gateway/outbound-send-path.ts +68 -15
- package/telegram-plugin/gateway/session-model-source.ts +90 -10
- package/telegram-plugin/gateway/status-pin-store.ts +64 -4
- package/telegram-plugin/gateway/stream-render.ts +22 -5
- package/telegram-plugin/gateway/usage-mask.ts +29 -0
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +19 -2
- package/telegram-plugin/quota-bar-format.ts +78 -12
- package/telegram-plugin/quota-check.ts +17 -2
- package/telegram-plugin/reply-owner-resolve.ts +76 -11
- package/telegram-plugin/session-tail.ts +27 -3
- package/telegram-plugin/tests/activity-card-wiring.test.ts +47 -0
- package/telegram-plugin/tests/auth-add-flow.test.ts +367 -5
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +41 -0
- package/telegram-plugin/tests/external-spend.test.ts +168 -0
- package/telegram-plugin/tests/flushed-turn-supersede.test.ts +117 -0
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +219 -29
- package/telegram-plugin/tests/model-command.test.ts +220 -0
- package/telegram-plugin/tests/quota-bar-format.test.ts +43 -0
- package/telegram-plugin/tests/quota-check.test.ts +57 -0
- package/telegram-plugin/tests/reply-owner-resolve.test.ts +257 -13
- package/telegram-plugin/tests/send-reply-golden.test.ts +154 -0
- package/telegram-plugin/tests/session-model-source.test.ts +142 -0
- package/telegram-plugin/tests/session-tail-first-attach.test.ts +115 -2
- package/telegram-plugin/tests/status-pin-store.test.ts +198 -0
- package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +50 -0
- package/telegram-plugin/tests/usage-footer-freshness.test.ts +141 -0
- package/telegram-plugin/tests/usage-mask.test.ts +35 -0
- package/telegram-plugin/tests/worker-feed-dispatch.test.ts +27 -0
- package/telegram-plugin/tests/worker-feed-pin-persistence.test.ts +131 -1
- package/vendor/hindsight-memory/CHANGELOG.md +102 -0
- package/vendor/hindsight-memory/README.md +2 -1
- package/vendor/hindsight-memory/hooks/hooks.json +12 -0
- package/vendor/hindsight-memory/scripts/directive_verify.py +100 -3
- package/vendor/hindsight-memory/scripts/lib/config.py +150 -1
- package/vendor/hindsight-memory/scripts/lib/content.py +55 -5
- package/vendor/hindsight-memory/scripts/lib/directives.py +152 -15
- package/vendor/hindsight-memory/scripts/lib/parallel_recall.py +142 -0
- package/vendor/hindsight-memory/scripts/lib/state.py +31 -0
- package/vendor/hindsight-memory/scripts/recall.py +789 -143
- package/vendor/hindsight-memory/scripts/reconcile_tail.py +22 -1
- package/vendor/hindsight-memory/scripts/retain.py +71 -2
- package/vendor/hindsight-memory/scripts/subagent_retain.py +501 -0
- package/vendor/hindsight-memory/scripts/tests/test_directive_verify.py +169 -0
- package/vendor/hindsight-memory/scripts/tests/test_directives.py +177 -0
- package/vendor/hindsight-memory/scripts/tests/test_lesson_tagging.py +200 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_context_turns_default.py +200 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_envelope_strip_telemetry.py +477 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_integration.py +51 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_parallel_deadline.py +409 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_tag_weights.py +96 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_transcript_fallback.py +413 -0
- package/vendor/hindsight-memory/scripts/tests/test_reconcile_durability.py +49 -0
- package/vendor/hindsight-memory/scripts/tests/test_subagent_retain.py +439 -0
- package/vendor/hindsight-memory/settings.json +3 -1
|
@@ -7196,6 +7196,67 @@ var init_format = __esm(() => {
|
|
|
7196
7196
|
];
|
|
7197
7197
|
});
|
|
7198
7198
|
|
|
7199
|
+
// ../src/auth/quota.ts
|
|
7200
|
+
function isProbeThin(q) {
|
|
7201
|
+
return q.fiveHourUtilPresent === false && q.sevenDayUtilPresent === false;
|
|
7202
|
+
}
|
|
7203
|
+
function refillNormalizedUtils(q, now) {
|
|
7204
|
+
const nowMs = now.getTime();
|
|
7205
|
+
const fiveHourRefilled = q.fiveHourResetAt != null && q.fiveHourResetAt.getTime() <= nowMs;
|
|
7206
|
+
const sevenDayRefilled = q.sevenDayResetAt != null && q.sevenDayResetAt.getTime() <= nowMs;
|
|
7207
|
+
return {
|
|
7208
|
+
fiveHourUtilizationPct: fiveHourRefilled ? 0 : q.fiveHourUtilizationPct,
|
|
7209
|
+
sevenDayUtilizationPct: sevenDayRefilled ? 0 : q.sevenDayUtilizationPct,
|
|
7210
|
+
fiveHourRefilled,
|
|
7211
|
+
sevenDayRefilled
|
|
7212
|
+
};
|
|
7213
|
+
}
|
|
7214
|
+
|
|
7215
|
+
// demo-mask.ts
|
|
7216
|
+
function stableAssign(input, cache, pool, overflow) {
|
|
7217
|
+
const existing = cache.get(input);
|
|
7218
|
+
if (existing !== undefined)
|
|
7219
|
+
return existing;
|
|
7220
|
+
const index = cache.size;
|
|
7221
|
+
const value = index < pool.length ? pool[index] : overflow(index);
|
|
7222
|
+
cache.set(input, value);
|
|
7223
|
+
return value;
|
|
7224
|
+
}
|
|
7225
|
+
function maskEmail(label) {
|
|
7226
|
+
return stableAssign(label, emailCache, EMAIL_POOL, (i) => `demo${i + 1}@example.com`);
|
|
7227
|
+
}
|
|
7228
|
+
function maskUsername(tag) {
|
|
7229
|
+
return stableAssign(tag, usernameCache, USERNAME_POOL, (i) => `@demo_user${i + 1}`);
|
|
7230
|
+
}
|
|
7231
|
+
function maskVaultKey(name) {
|
|
7232
|
+
return stableAssign(name, vaultKeyCache, [], (i) => `demo/secret-${i + 1}`);
|
|
7233
|
+
}
|
|
7234
|
+
var EMAIL_POOL, emailCache, USERNAME_POOL, usernameCache, vaultKeyCache;
|
|
7235
|
+
var init_demo_mask = __esm(() => {
|
|
7236
|
+
EMAIL_POOL = [
|
|
7237
|
+
"ada@example.com",
|
|
7238
|
+
"grace@example.com",
|
|
7239
|
+
"linus@example.com",
|
|
7240
|
+
"hopper@example.com",
|
|
7241
|
+
"turing@example.com",
|
|
7242
|
+
"lovelace@example.com",
|
|
7243
|
+
"dijkstra@example.com",
|
|
7244
|
+
"knuth@example.com",
|
|
7245
|
+
"ritchie@example.com",
|
|
7246
|
+
"torvalds@example.com"
|
|
7247
|
+
];
|
|
7248
|
+
emailCache = new Map;
|
|
7249
|
+
USERNAME_POOL = [
|
|
7250
|
+
"@demo_user",
|
|
7251
|
+
"@demo_user2",
|
|
7252
|
+
"@demo_user3",
|
|
7253
|
+
"@demo_user4",
|
|
7254
|
+
"@demo_user5"
|
|
7255
|
+
];
|
|
7256
|
+
usernameCache = new Map;
|
|
7257
|
+
vaultKeyCache = new Map;
|
|
7258
|
+
});
|
|
7259
|
+
|
|
7199
7260
|
// text-voice-scrub.ts
|
|
7200
7261
|
function enabled() {
|
|
7201
7262
|
const v = process.env.SWITCHROOM_DISABLE_VOICE_SCRUB;
|
|
@@ -7383,6 +7444,533 @@ var init_card_format = __esm(() => {
|
|
|
7383
7444
|
init_text_voice_scrub();
|
|
7384
7445
|
});
|
|
7385
7446
|
|
|
7447
|
+
// auth-snapshot-format.ts
|
|
7448
|
+
var exports_auth_snapshot_format = {};
|
|
7449
|
+
__export(exports_auth_snapshot_format, {
|
|
7450
|
+
zipProbeResults: () => zipProbeResults,
|
|
7451
|
+
reviveLastQuota: () => reviveLastQuota,
|
|
7452
|
+
renderFallbackAnnouncement: () => renderFallbackAnnouncement,
|
|
7453
|
+
renderAuthSnapshotFormat2: () => renderAuthSnapshotFormat2,
|
|
7454
|
+
recommendation: () => recommendation,
|
|
7455
|
+
formatStatusTime: () => formatStatusTime,
|
|
7456
|
+
formatRelative: () => formatRelative,
|
|
7457
|
+
formatAbsolute: () => formatAbsolute,
|
|
7458
|
+
fmtPct: () => fmtPct,
|
|
7459
|
+
deriveUsageFooterFreshness: () => deriveUsageFooterFreshness,
|
|
7460
|
+
classifyHealth: () => classifyHealth,
|
|
7461
|
+
buildSnapshotsFromState: () => buildSnapshotsFromState,
|
|
7462
|
+
buildSnapshotsFromCachedState: () => buildSnapshotsFromCachedState,
|
|
7463
|
+
buildSnapshotKeyboard: () => buildSnapshotKeyboard,
|
|
7464
|
+
blockedReason: () => blockedReason,
|
|
7465
|
+
bindingWindow: () => bindingWindow,
|
|
7466
|
+
THROTTLING_THRESHOLD_PCT: () => THROTTLING_THRESHOLD_PCT
|
|
7467
|
+
});
|
|
7468
|
+
function classifyHealth(snap, now = new Date) {
|
|
7469
|
+
if (!snap.isActive) {
|
|
7470
|
+
if (snap.entitlementBlocked === true)
|
|
7471
|
+
return "org-blocked";
|
|
7472
|
+
if (snap.inService === false)
|
|
7473
|
+
return "retired";
|
|
7474
|
+
}
|
|
7475
|
+
if (!snap.quota)
|
|
7476
|
+
return "unknown";
|
|
7477
|
+
const q = snap.quota;
|
|
7478
|
+
if (isProbeThin(q))
|
|
7479
|
+
return "unknown";
|
|
7480
|
+
const norm = refillNormalizedUtils(q, now);
|
|
7481
|
+
const max = Math.max(norm.fiveHourUtilizationPct, norm.sevenDayUtilizationPct);
|
|
7482
|
+
if (max >= 99.5)
|
|
7483
|
+
return "blocked";
|
|
7484
|
+
if (max >= THROTTLING_THRESHOLD_PCT)
|
|
7485
|
+
return "throttling";
|
|
7486
|
+
return "healthy";
|
|
7487
|
+
}
|
|
7488
|
+
function blockedReason(snap, now = new Date) {
|
|
7489
|
+
if (classifyHealth(snap, now) !== "blocked")
|
|
7490
|
+
return null;
|
|
7491
|
+
return "quota-exhausted";
|
|
7492
|
+
}
|
|
7493
|
+
function bindingWindow(q) {
|
|
7494
|
+
if (q.representativeClaim === "seven_day")
|
|
7495
|
+
return "7d";
|
|
7496
|
+
if (q.representativeClaim === "five_hour")
|
|
7497
|
+
return "5h";
|
|
7498
|
+
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7d" : "5h";
|
|
7499
|
+
}
|
|
7500
|
+
function formatRelative(target, now = new Date) {
|
|
7501
|
+
if (!target)
|
|
7502
|
+
return "\u2014";
|
|
7503
|
+
const deltaMs = target.getTime() - now.getTime();
|
|
7504
|
+
if (deltaMs <= 0)
|
|
7505
|
+
return "now";
|
|
7506
|
+
const totalMin = Math.round(deltaMs / 60000);
|
|
7507
|
+
if (totalMin < 60)
|
|
7508
|
+
return `${totalMin}m`;
|
|
7509
|
+
const h = Math.floor(totalMin / 60);
|
|
7510
|
+
const m = totalMin % 60;
|
|
7511
|
+
if (h < 24)
|
|
7512
|
+
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
7513
|
+
const d = Math.floor(h / 24);
|
|
7514
|
+
const rh = h % 24;
|
|
7515
|
+
return rh > 0 ? `${d}d ${rh}h` : `${d}d`;
|
|
7516
|
+
}
|
|
7517
|
+
function formatAbsolute(target, tz = "UTC") {
|
|
7518
|
+
if (!target)
|
|
7519
|
+
return "\u2014";
|
|
7520
|
+
return target.toLocaleString("en-US", {
|
|
7521
|
+
timeZone: tz,
|
|
7522
|
+
weekday: "short",
|
|
7523
|
+
hour: "numeric",
|
|
7524
|
+
minute: "2-digit",
|
|
7525
|
+
hour12: true
|
|
7526
|
+
});
|
|
7527
|
+
}
|
|
7528
|
+
function formatStatusTime(target, now = new Date, tz = "UTC") {
|
|
7529
|
+
if (!target)
|
|
7530
|
+
return "\u2014";
|
|
7531
|
+
const dayFmt = new Intl.DateTimeFormat("en-CA", {
|
|
7532
|
+
timeZone: tz,
|
|
7533
|
+
year: "numeric",
|
|
7534
|
+
month: "2-digit",
|
|
7535
|
+
day: "2-digit"
|
|
7536
|
+
});
|
|
7537
|
+
const timeFmt = new Intl.DateTimeFormat("en-US", {
|
|
7538
|
+
timeZone: tz,
|
|
7539
|
+
hour: "numeric",
|
|
7540
|
+
minute: "2-digit",
|
|
7541
|
+
hour12: true
|
|
7542
|
+
});
|
|
7543
|
+
const timeStr = timeFmt.format(target);
|
|
7544
|
+
if (dayFmt.format(target) === dayFmt.format(now)) {
|
|
7545
|
+
return timeStr;
|
|
7546
|
+
}
|
|
7547
|
+
const withinWeek = target.getTime() - now.getTime() < 7 * 24 * 60 * 60 * 1000;
|
|
7548
|
+
const dateFmt = new Intl.DateTimeFormat("en-US", {
|
|
7549
|
+
timeZone: tz,
|
|
7550
|
+
weekday: "short",
|
|
7551
|
+
...withinWeek ? {} : { day: "numeric", month: "short" }
|
|
7552
|
+
});
|
|
7553
|
+
return `${dateFmt.format(target)} ${timeStr}`;
|
|
7554
|
+
}
|
|
7555
|
+
function fmtPct(pct) {
|
|
7556
|
+
return `${Math.min(100, Math.round(pct))}%`;
|
|
7557
|
+
}
|
|
7558
|
+
function displayLabel(label, opts) {
|
|
7559
|
+
return opts.demo ? maskEmail(label) : label;
|
|
7560
|
+
}
|
|
7561
|
+
function renderAccountRow(snap, opts) {
|
|
7562
|
+
const now = opts.now ?? new Date;
|
|
7563
|
+
const tz = opts.tz ?? "UTC";
|
|
7564
|
+
const lines = [];
|
|
7565
|
+
const marker = snap.isActive ? "\u25cf " : "";
|
|
7566
|
+
const label = displayLabel(snap.label, opts);
|
|
7567
|
+
const health = classifyHealth(snap, now);
|
|
7568
|
+
if (health === "org-blocked" || health === "retired") {
|
|
7569
|
+
const note = health === "org-blocked" ? "DISABLED (org) \u2014 no fleet routing" : "retired \u2014 removed from fleet rotation";
|
|
7570
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` _${note}_`);
|
|
7571
|
+
return lines;
|
|
7572
|
+
}
|
|
7573
|
+
if (!snap.quota) {
|
|
7574
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota probe failed_`);
|
|
7575
|
+
if (snap.quotaError) {
|
|
7576
|
+
lines.push(` _${escapeMarkdown(snap.quotaError)}_`);
|
|
7577
|
+
}
|
|
7578
|
+
return lines;
|
|
7579
|
+
}
|
|
7580
|
+
const q = snap.quota;
|
|
7581
|
+
if (isProbeThin(q)) {
|
|
7582
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota unknown (thin probe)_`);
|
|
7583
|
+
return lines;
|
|
7584
|
+
}
|
|
7585
|
+
const norm = refillNormalizedUtils(q, now);
|
|
7586
|
+
const fiveStr = fmtPct(norm.fiveHourUtilizationPct);
|
|
7587
|
+
const sevenStr = fmtPct(norm.sevenDayUtilizationPct);
|
|
7588
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` ${fiveStr} / ${sevenStr}`);
|
|
7589
|
+
if (health === "blocked") {
|
|
7590
|
+
const win = bindingWindow(q);
|
|
7591
|
+
const reset = win === "5h" ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
7592
|
+
const winLabel = win === "5h" ? "5-hour" : "7-day";
|
|
7593
|
+
lines.push(reset ? ` _quota exhausted \u2014 back ${formatAbsolute(reset, tz)} (\`in ${formatRelative(reset, now)}\`, ${winLabel} cap)_` : ` _quota exhausted \u2014 ${winLabel} cap, reset time unknown_`);
|
|
7594
|
+
return lines;
|
|
7595
|
+
}
|
|
7596
|
+
const fiveResetIn = q.fiveHourResetAt ? q.fiveHourResetAt.getTime() - now.getTime() : Infinity;
|
|
7597
|
+
const sevenResetIn = q.sevenDayResetAt ? q.sevenDayResetAt.getTime() - now.getTime() : Infinity;
|
|
7598
|
+
const fiveFirst = fiveResetIn <= sevenResetIn;
|
|
7599
|
+
const fiveSeg = q.fiveHourResetAt ? `5h refills ${formatAbsolute(q.fiveHourResetAt, tz)} (\`in ${formatRelative(q.fiveHourResetAt, now)}\`)` : "5h refills \u2014";
|
|
7600
|
+
const sevenSeg = q.sevenDayResetAt ? `7d resets ${formatAbsolute(q.sevenDayResetAt, tz)} (\`in ${formatRelative(q.sevenDayResetAt, now)}\`)` : "7d resets \u2014";
|
|
7601
|
+
lines.push(` _${fiveFirst ? fiveSeg : sevenSeg}_`);
|
|
7602
|
+
lines.push(` _${fiveFirst ? sevenSeg : fiveSeg}_`);
|
|
7603
|
+
if (q.overageDisabledReason != null && OVERAGE_EXHAUSTED_REASONS.has(q.overageDisabledReason)) {
|
|
7604
|
+
lines.push(` _overage off (${escapeMarkdown(q.overageDisabledReason)}) \u2014 serving from quota_`);
|
|
7605
|
+
}
|
|
7606
|
+
return lines;
|
|
7607
|
+
}
|
|
7608
|
+
function formatAgeStamp(atMs, now = new Date) {
|
|
7609
|
+
const ageSec = Math.max(0, Math.round((now.getTime() - atMs) / 1000));
|
|
7610
|
+
return ageSec < 60 ? `${ageSec}s ago` : `${Math.round(ageSec / 60)}m ago`;
|
|
7611
|
+
}
|
|
7612
|
+
function tableCell(s) {
|
|
7613
|
+
return s.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
7614
|
+
}
|
|
7615
|
+
function pctCells(snap, now) {
|
|
7616
|
+
if (!snap.quota)
|
|
7617
|
+
return { five: "\u2014", seven: "\u2014" };
|
|
7618
|
+
if (isProbeThin(snap.quota))
|
|
7619
|
+
return { five: "?", seven: "?" };
|
|
7620
|
+
const norm = refillNormalizedUtils(snap.quota, now);
|
|
7621
|
+
return { five: fmtPct(norm.fiveHourUtilizationPct), seven: fmtPct(norm.sevenDayUtilizationPct) };
|
|
7622
|
+
}
|
|
7623
|
+
function windowResetCell(snap, now, tz, win) {
|
|
7624
|
+
if (!snap.quota) {
|
|
7625
|
+
return snap.quotaError ? `probe failed (${snap.quotaError})` : "\u2014";
|
|
7626
|
+
}
|
|
7627
|
+
if (isProbeThin(snap.quota))
|
|
7628
|
+
return "quota unknown";
|
|
7629
|
+
const reset = win === "5h" ? snap.quota.fiveHourResetAt : snap.quota.sevenDayResetAt;
|
|
7630
|
+
if (!reset)
|
|
7631
|
+
return "\u2014";
|
|
7632
|
+
return `${formatStatusTime(reset, now, tz)} (in ${formatRelative(reset, now)})`;
|
|
7633
|
+
}
|
|
7634
|
+
function renderAuthSnapshotFormat2(snapshots, opts = {}) {
|
|
7635
|
+
const now = opts.now ?? new Date;
|
|
7636
|
+
const tz = opts.tz ?? "UTC";
|
|
7637
|
+
const lines = [];
|
|
7638
|
+
lines.push("\uD83D\uDD0B **Auth \u2014 fleet status**");
|
|
7639
|
+
const ordered = [...snapshots].sort((a, b) => {
|
|
7640
|
+
if (a.isActive !== b.isActive)
|
|
7641
|
+
return a.isActive ? -1 : 1;
|
|
7642
|
+
const r = TABLE_HEALTH_RANK[classifyHealth(a, now)] - TABLE_HEALTH_RANK[classifyHealth(b, now)];
|
|
7643
|
+
if (r !== 0)
|
|
7644
|
+
return r;
|
|
7645
|
+
return a.label.localeCompare(b.label);
|
|
7646
|
+
});
|
|
7647
|
+
if (ordered.length > 0) {
|
|
7648
|
+
lines.push("");
|
|
7649
|
+
lines.push("| State | Account | 5h | 5h resets | 7d | 7d resets |");
|
|
7650
|
+
lines.push("| --- | --- | --- | --- | --- | --- |");
|
|
7651
|
+
for (const s of ordered) {
|
|
7652
|
+
const emoji = HEALTH_EMOJI[classifyHealth(s, now)];
|
|
7653
|
+
const label = displayLabel(s.label, opts);
|
|
7654
|
+
const accountCell = `\`${codeSpanSafe(s.isActive ? `${label} (active)` : label)}\``;
|
|
7655
|
+
const { five, seven } = pctCells(s, now);
|
|
7656
|
+
const fiveReset = windowResetCell(s, now, tz, "5h");
|
|
7657
|
+
const sevenReset = windowResetCell(s, now, tz, "7d");
|
|
7658
|
+
lines.push(`| ${emoji} | ${tableCell(accountCell)} | ${five} | ${tableCell(fiveReset)} | ${seven} | ${tableCell(sevenReset)} |`);
|
|
7659
|
+
}
|
|
7660
|
+
}
|
|
7661
|
+
lines.push("");
|
|
7662
|
+
lines.push(`_${recommendation(snapshots, now, opts.demo ?? false)}_`);
|
|
7663
|
+
if (opts.staleCachedAtMs != null) {
|
|
7664
|
+
lines.push(`_\u26a0 cached ${formatAgeStamp(opts.staleCachedAtMs, now)}_`);
|
|
7665
|
+
} else if (opts.liveProbedAtMs != null) {
|
|
7666
|
+
lines.push(`_Live \u00b7 refreshed ${formatAgeStamp(opts.liveProbedAtMs, now)}_`);
|
|
7667
|
+
} else if (opts.probeFailed) {
|
|
7668
|
+
lines.push("_\u26a0 probe failed \u2014 no live data_");
|
|
7669
|
+
} else {
|
|
7670
|
+
lines.push("_Live_");
|
|
7671
|
+
}
|
|
7672
|
+
return lines.join(`
|
|
7673
|
+
`);
|
|
7674
|
+
}
|
|
7675
|
+
function recommendation(snapshots, now = new Date, demo = false) {
|
|
7676
|
+
const active = snapshots.find((s) => s.isActive);
|
|
7677
|
+
if (!active)
|
|
7678
|
+
return "No active account set.";
|
|
7679
|
+
const activeHealth = classifyHealth(active, now);
|
|
7680
|
+
const inServiceFleet = snapshots.filter((s) => {
|
|
7681
|
+
const h = classifyHealth(s, now);
|
|
7682
|
+
return h !== "retired" && h !== "org-blocked";
|
|
7683
|
+
});
|
|
7684
|
+
const others = inServiceFleet.filter((s) => !s.isActive);
|
|
7685
|
+
const healthyAlt = others.find((s) => classifyHealth(s, now) === "healthy");
|
|
7686
|
+
const lbl = (s) => demo ? maskEmail(s.label) : s.label;
|
|
7687
|
+
const activeLabel = lbl(active);
|
|
7688
|
+
if (activeHealth === "healthy") {
|
|
7689
|
+
return `Recommendation: stay on ${activeLabel}.`;
|
|
7690
|
+
}
|
|
7691
|
+
if (activeHealth === "throttling") {
|
|
7692
|
+
if (healthyAlt) {
|
|
7693
|
+
return `Recommendation: active ${activeLabel} is throttling. Switch to ${lbl(healthyAlt)} for headroom.`;
|
|
7694
|
+
}
|
|
7695
|
+
return `Recommendation: active ${activeLabel} is throttling; no healthy alternative \u2014 wait for refill.`;
|
|
7696
|
+
}
|
|
7697
|
+
if (activeHealth === "blocked") {
|
|
7698
|
+
if (healthyAlt) {
|
|
7699
|
+
return `Recommendation: active ${activeLabel} is BLOCKED \u2014 switch to ${lbl(healthyAlt)} now.`;
|
|
7700
|
+
}
|
|
7701
|
+
return summarizeNoHealthyAlt(inServiceFleet, now, demo);
|
|
7702
|
+
}
|
|
7703
|
+
return `Active ${activeLabel}: quota probe failed; broker last_seen unknown.`;
|
|
7704
|
+
}
|
|
7705
|
+
function summarizeNoHealthyAlt(snapshots, now, demo = false) {
|
|
7706
|
+
const mask = (label) => demo ? maskEmail(label) : label;
|
|
7707
|
+
let throttlingLabel = null;
|
|
7708
|
+
let allTrulyBlocked = true;
|
|
7709
|
+
for (const s of snapshots) {
|
|
7710
|
+
const h = classifyHealth(s, now);
|
|
7711
|
+
if (h === "throttling") {
|
|
7712
|
+
if (!throttlingLabel)
|
|
7713
|
+
throttlingLabel = s.label;
|
|
7714
|
+
allTrulyBlocked = false;
|
|
7715
|
+
} else if (h === "healthy" || h === "unknown") {
|
|
7716
|
+
allTrulyBlocked = false;
|
|
7717
|
+
} else if (h === "blocked" && blockedReason(s, now) === "quota-exhausted") {
|
|
7718
|
+
if (s.quota) {
|
|
7719
|
+
const win = bindingWindow(s.quota);
|
|
7720
|
+
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
7721
|
+
if (at && at.getTime() > now.getTime())
|
|
7722
|
+
allTrulyBlocked = false;
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
}
|
|
7726
|
+
const earliestRecovery = pickEarliestRecovery(snapshots, now);
|
|
7727
|
+
if (throttlingLabel) {
|
|
7728
|
+
const eta = earliestRecovery ? ` Soonest full refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.` : "";
|
|
7729
|
+
return `No fully-healthy account; ${mask(throttlingLabel)} is throttling but still usable.${eta}`;
|
|
7730
|
+
}
|
|
7731
|
+
if (!allTrulyBlocked) {
|
|
7732
|
+
if (earliestRecovery) {
|
|
7733
|
+
return `All accounts at capacity; soonest refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
7734
|
+
}
|
|
7735
|
+
return `All accounts at capacity \u2014 waiting on a window refill.`;
|
|
7736
|
+
}
|
|
7737
|
+
if (earliestRecovery) {
|
|
7738
|
+
return `All accounts blocked. Earliest recovery: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
7739
|
+
}
|
|
7740
|
+
return `All accounts blocked. Run /auth add to attach another subscription.`;
|
|
7741
|
+
}
|
|
7742
|
+
function pickEarliestRecovery(snapshots, now) {
|
|
7743
|
+
let best = null;
|
|
7744
|
+
for (const s of snapshots) {
|
|
7745
|
+
if (!s.quota)
|
|
7746
|
+
continue;
|
|
7747
|
+
if (isProbeThin(s.quota))
|
|
7748
|
+
continue;
|
|
7749
|
+
const win = bindingWindow(s.quota);
|
|
7750
|
+
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
7751
|
+
if (!at || at.getTime() <= now.getTime())
|
|
7752
|
+
continue;
|
|
7753
|
+
if (!best || at.getTime() < best.at.getTime()) {
|
|
7754
|
+
best = { label: s.label, at };
|
|
7755
|
+
}
|
|
7756
|
+
}
|
|
7757
|
+
return best;
|
|
7758
|
+
}
|
|
7759
|
+
function renderFallbackAnnouncement(input) {
|
|
7760
|
+
const now = input.now ?? new Date;
|
|
7761
|
+
const tz = input.tz ?? "UTC";
|
|
7762
|
+
const lines = [];
|
|
7763
|
+
const limitWord = input.oldQuota ? limitWordFor(input.oldQuota) : "quota";
|
|
7764
|
+
const headerLimit = input.cause === "rate-limit" ? "rate limit" : limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
|
|
7765
|
+
if (!input.newLabel) {
|
|
7766
|
+
lines.push(`\uD83D\uDD34 **All accounts blocked \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
7767
|
+
lines.push("");
|
|
7768
|
+
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
7769
|
+
const fleet = input.fleetSnapshots ?? [];
|
|
7770
|
+
if (fleet.length > 0) {
|
|
7771
|
+
lines.push("");
|
|
7772
|
+
const rowOpts = { now, tz };
|
|
7773
|
+
const healthOrder = [
|
|
7774
|
+
"org-blocked",
|
|
7775
|
+
"blocked",
|
|
7776
|
+
"throttling",
|
|
7777
|
+
"healthy",
|
|
7778
|
+
"unknown",
|
|
7779
|
+
"retired"
|
|
7780
|
+
];
|
|
7781
|
+
const rank = (s) => healthOrder.indexOf(classifyHealth(s, now));
|
|
7782
|
+
const ordered = [...fleet].sort((a, b) => rank(a) - rank(b) || Number(b.isActive) - Number(a.isActive));
|
|
7783
|
+
for (const snap of ordered) {
|
|
7784
|
+
for (const ln of renderAccountRow(snap, rowOpts))
|
|
7785
|
+
lines.push(ln);
|
|
7786
|
+
}
|
|
7787
|
+
const earliest = pickEarliestRecovery(fleet, now);
|
|
7788
|
+
if (earliest) {
|
|
7789
|
+
lines.push("");
|
|
7790
|
+
lines.push(`Earliest recovery: \`${codeSpanSafe(earliest.label)}\` ` + `${formatAbsolute(earliest.at, tz)} (in ${formatRelative(earliest.at, now)})`);
|
|
7791
|
+
}
|
|
7792
|
+
} else {
|
|
7793
|
+
const recovery = (input.oldQuota ? recoveryAtFor(input.oldQuota) : null) ?? input.parsedResetAt ?? null;
|
|
7794
|
+
if (recovery) {
|
|
7795
|
+
lines.push(`${escapeMarkdown(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
|
|
7796
|
+
}
|
|
7797
|
+
}
|
|
7798
|
+
lines.push("");
|
|
7799
|
+
lines.push(`Run \`/auth add <label>\` to attach another subscription, ` + `or \`/auth refresh\` to re-probe.`);
|
|
7800
|
+
return lines.join(`
|
|
7801
|
+
`);
|
|
7802
|
+
}
|
|
7803
|
+
lines.push(`\u2713 **Switched fleet \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
7804
|
+
lines.push("");
|
|
7805
|
+
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` \u2192 \`${codeSpanSafe(input.newLabel)}\``);
|
|
7806
|
+
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
7807
|
+
lines.push("");
|
|
7808
|
+
{
|
|
7809
|
+
const recovery = (input.oldQuota ? recoveryAtFor(input.oldQuota) : null) ?? input.parsedResetAt ?? null;
|
|
7810
|
+
if (recovery) {
|
|
7811
|
+
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
|
|
7812
|
+
}
|
|
7813
|
+
}
|
|
7814
|
+
if (input.newQuota) {
|
|
7815
|
+
const fiveStr = fmtPct(input.newQuota.fiveHourUtilizationPct);
|
|
7816
|
+
const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
|
|
7817
|
+
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
|
|
7818
|
+
const headroomStr = hasHeadroom ? "_(plenty of headroom)_" : "_(near limit \u2014 watch this)_";
|
|
7819
|
+
lines.push(`\`${codeSpanSafe(input.newLabel)}\` now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
7820
|
+
} else {
|
|
7821
|
+
lines.push(`_(quota probe for new account is pending \u2014 will reflect on next /auth)_`);
|
|
7822
|
+
}
|
|
7823
|
+
return lines.join(`
|
|
7824
|
+
`);
|
|
7825
|
+
}
|
|
7826
|
+
function limitWordFor(q) {
|
|
7827
|
+
if (q.representativeClaim === "seven_day" && q.sevenDayUtilizationPct >= 99)
|
|
7828
|
+
return "7-day";
|
|
7829
|
+
if (q.representativeClaim === "five_hour" && q.fiveHourUtilizationPct >= 99)
|
|
7830
|
+
return "5-hour";
|
|
7831
|
+
if (q.sevenDayUtilizationPct >= 99)
|
|
7832
|
+
return "7-day";
|
|
7833
|
+
if (q.fiveHourUtilizationPct >= 99)
|
|
7834
|
+
return "5-hour";
|
|
7835
|
+
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7-day" : "5-hour";
|
|
7836
|
+
}
|
|
7837
|
+
function recoveryAtFor(q) {
|
|
7838
|
+
const word = limitWordFor(q);
|
|
7839
|
+
if (word === "7-day")
|
|
7840
|
+
return q.sevenDayResetAt;
|
|
7841
|
+
if (word === "5-hour")
|
|
7842
|
+
return q.fiveHourResetAt;
|
|
7843
|
+
if (!q.fiveHourResetAt)
|
|
7844
|
+
return q.sevenDayResetAt;
|
|
7845
|
+
if (!q.sevenDayResetAt)
|
|
7846
|
+
return q.fiveHourResetAt;
|
|
7847
|
+
return q.fiveHourResetAt.getTime() < q.sevenDayResetAt.getTime() ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
7848
|
+
}
|
|
7849
|
+
function buildSnapshotKeyboard(snapshots, opts = {}) {
|
|
7850
|
+
const max = opts.maxSwitchButtons ?? 3;
|
|
7851
|
+
const now = opts.now ?? new Date;
|
|
7852
|
+
const rows = [];
|
|
7853
|
+
const switchTargets = snapshots.filter((s) => !s.isActive).sort((a, b) => switchPriority(a, now) - switchPriority(b, now)).filter((s) => {
|
|
7854
|
+
const h = classifyHealth(s, now);
|
|
7855
|
+
return h !== "blocked" && h !== "unknown" && h !== "retired" && h !== "org-blocked";
|
|
7856
|
+
}).slice(0, max);
|
|
7857
|
+
for (const t of switchTargets) {
|
|
7858
|
+
rows.push([
|
|
7859
|
+
{
|
|
7860
|
+
text: `Switch fleet \u2192 ${opts.demo ? maskEmail(t.label) : t.label}`,
|
|
7861
|
+
callbackData: `auth:use:${t.label}`
|
|
7862
|
+
}
|
|
7863
|
+
]);
|
|
7864
|
+
}
|
|
7865
|
+
rows.push([
|
|
7866
|
+
{ text: "\u21bb Refresh", callbackData: opts.demo ? "auth:refresh:demo" : "auth:refresh" },
|
|
7867
|
+
{ text: "/usage", insertText: "/usage" },
|
|
7868
|
+
{ text: "+ Add", insertText: "/auth add " }
|
|
7869
|
+
]);
|
|
7870
|
+
return rows;
|
|
7871
|
+
}
|
|
7872
|
+
function switchPriority(s, now = new Date) {
|
|
7873
|
+
const h = classifyHealth(s, now);
|
|
7874
|
+
if (h === "healthy")
|
|
7875
|
+
return 0;
|
|
7876
|
+
if (h === "throttling")
|
|
7877
|
+
return 1;
|
|
7878
|
+
if (h === "unknown")
|
|
7879
|
+
return 2;
|
|
7880
|
+
if (h === "blocked")
|
|
7881
|
+
return 3;
|
|
7882
|
+
return 4;
|
|
7883
|
+
}
|
|
7884
|
+
function zipProbeResults(labels, results) {
|
|
7885
|
+
let staleCachedAtMs;
|
|
7886
|
+
const quotas = labels.map((label) => {
|
|
7887
|
+
const hit = results.find((r) => r.label === label);
|
|
7888
|
+
if (!hit)
|
|
7889
|
+
return { ok: false, reason: "broker returned no result for account" };
|
|
7890
|
+
if (hit.served === "cache" && hit.capturedAt != null) {
|
|
7891
|
+
staleCachedAtMs = staleCachedAtMs == null ? hit.capturedAt : Math.min(staleCachedAtMs, hit.capturedAt);
|
|
7892
|
+
}
|
|
7893
|
+
return hit.result;
|
|
7894
|
+
});
|
|
7895
|
+
return staleCachedAtMs != null ? { quotas, staleCachedAtMs } : { quotas };
|
|
7896
|
+
}
|
|
7897
|
+
function deriveUsageFooterFreshness(results, staleCachedAtMs, liveProbedAtMs) {
|
|
7898
|
+
if (staleCachedAtMs != null)
|
|
7899
|
+
return { staleCachedAtMs };
|
|
7900
|
+
if (results.some((r) => r.result.ok))
|
|
7901
|
+
return { liveProbedAtMs };
|
|
7902
|
+
return { probeFailed: true };
|
|
7903
|
+
}
|
|
7904
|
+
function buildSnapshotsFromState(state, quotas) {
|
|
7905
|
+
const out = [];
|
|
7906
|
+
for (let i = 0;i < state.accounts.length; i++) {
|
|
7907
|
+
const acc = state.accounts[i];
|
|
7908
|
+
const q = quotas[i];
|
|
7909
|
+
out.push({
|
|
7910
|
+
label: acc.label,
|
|
7911
|
+
isActive: acc.label === state.active,
|
|
7912
|
+
quota: q && q.ok ? q.data : null,
|
|
7913
|
+
quotaError: q && !q.ok ? q.reason : undefined,
|
|
7914
|
+
expiresAtMs: acc.expiresAt,
|
|
7915
|
+
inService: acc.in_service,
|
|
7916
|
+
entitlementBlocked: acc.entitlement_blocked
|
|
7917
|
+
});
|
|
7918
|
+
}
|
|
7919
|
+
return out;
|
|
7920
|
+
}
|
|
7921
|
+
function reviveLastQuota(snap) {
|
|
7922
|
+
if (!snap)
|
|
7923
|
+
return null;
|
|
7924
|
+
return {
|
|
7925
|
+
fiveHourUtilizationPct: snap.fiveHourUtilizationPct,
|
|
7926
|
+
sevenDayUtilizationPct: snap.sevenDayUtilizationPct,
|
|
7927
|
+
fiveHourResetAt: snap.fiveHourResetAt ? new Date(snap.fiveHourResetAt) : null,
|
|
7928
|
+
sevenDayResetAt: snap.sevenDayResetAt ? new Date(snap.sevenDayResetAt) : null,
|
|
7929
|
+
representativeClaim: snap.representativeClaim,
|
|
7930
|
+
overageStatus: snap.overageStatus,
|
|
7931
|
+
overageDisabledReason: snap.overageDisabledReason,
|
|
7932
|
+
fiveHourUtilPresent: snap.fiveHourUtilPresent,
|
|
7933
|
+
sevenDayUtilPresent: snap.sevenDayUtilPresent
|
|
7934
|
+
};
|
|
7935
|
+
}
|
|
7936
|
+
function buildSnapshotsFromCachedState(state) {
|
|
7937
|
+
return state.accounts.map((acc) => {
|
|
7938
|
+
const lq = acc.last_quota ?? null;
|
|
7939
|
+
return {
|
|
7940
|
+
label: acc.label,
|
|
7941
|
+
isActive: acc.label === state.active,
|
|
7942
|
+
quota: reviveLastQuota(lq),
|
|
7943
|
+
quotaError: lq ? undefined : "no cached quota (no probe since broker start)",
|
|
7944
|
+
expiresAtMs: acc.expiresAt,
|
|
7945
|
+
capturedAtMs: lq?.capturedAt,
|
|
7946
|
+
inService: acc.in_service,
|
|
7947
|
+
entitlementBlocked: acc.entitlement_blocked
|
|
7948
|
+
};
|
|
7949
|
+
});
|
|
7950
|
+
}
|
|
7951
|
+
var THROTTLING_THRESHOLD_PCT = 80, OVERAGE_EXHAUSTED_REASONS, HEALTH_EMOJI, TABLE_HEALTH_RANK;
|
|
7952
|
+
var init_auth_snapshot_format = __esm(() => {
|
|
7953
|
+
init_demo_mask();
|
|
7954
|
+
init_card_format();
|
|
7955
|
+
OVERAGE_EXHAUSTED_REASONS = new Set(["out_of_credits"]);
|
|
7956
|
+
HEALTH_EMOJI = {
|
|
7957
|
+
healthy: "\uD83D\uDFE2",
|
|
7958
|
+
throttling: "\uD83D\uDFE1",
|
|
7959
|
+
blocked: "\uD83D\uDD34",
|
|
7960
|
+
unknown: "\u26aa",
|
|
7961
|
+
"org-blocked": "\u26d4",
|
|
7962
|
+
retired: "\u26ab"
|
|
7963
|
+
};
|
|
7964
|
+
TABLE_HEALTH_RANK = {
|
|
7965
|
+
"org-blocked": 0,
|
|
7966
|
+
blocked: 1,
|
|
7967
|
+
throttling: 2,
|
|
7968
|
+
unknown: 3,
|
|
7969
|
+
healthy: 4,
|
|
7970
|
+
retired: 5
|
|
7971
|
+
};
|
|
7972
|
+
});
|
|
7973
|
+
|
|
7386
7974
|
// secret-detect/patterns.ts
|
|
7387
7975
|
var ANCHORED_PATTERNS, STRUCTURED_PATTERNS, PROVIDER_PATTERNS, ALL_PATTERNS;
|
|
7388
7976
|
var init_patterns = __esm(() => {
|
|
@@ -13034,51 +13622,6 @@ var init_tmux = __esm(() => {
|
|
|
13034
13622
|
MAX_BYTES = 10 * 1024 * 1024;
|
|
13035
13623
|
});
|
|
13036
13624
|
|
|
13037
|
-
// demo-mask.ts
|
|
13038
|
-
function stableAssign(input, cache, pool, overflow) {
|
|
13039
|
-
const existing = cache.get(input);
|
|
13040
|
-
if (existing !== undefined)
|
|
13041
|
-
return existing;
|
|
13042
|
-
const index = cache.size;
|
|
13043
|
-
const value = index < pool.length ? pool[index] : overflow(index);
|
|
13044
|
-
cache.set(input, value);
|
|
13045
|
-
return value;
|
|
13046
|
-
}
|
|
13047
|
-
function maskEmail(label) {
|
|
13048
|
-
return stableAssign(label, emailCache, EMAIL_POOL, (i) => `demo${i + 1}@example.com`);
|
|
13049
|
-
}
|
|
13050
|
-
function maskUsername(tag) {
|
|
13051
|
-
return stableAssign(tag, usernameCache, USERNAME_POOL, (i) => `@demo_user${i + 1}`);
|
|
13052
|
-
}
|
|
13053
|
-
function maskVaultKey(name) {
|
|
13054
|
-
return stableAssign(name, vaultKeyCache, [], (i) => `demo/secret-${i + 1}`);
|
|
13055
|
-
}
|
|
13056
|
-
var EMAIL_POOL, emailCache, USERNAME_POOL, usernameCache, vaultKeyCache;
|
|
13057
|
-
var init_demo_mask = __esm(() => {
|
|
13058
|
-
EMAIL_POOL = [
|
|
13059
|
-
"ada@example.com",
|
|
13060
|
-
"grace@example.com",
|
|
13061
|
-
"linus@example.com",
|
|
13062
|
-
"hopper@example.com",
|
|
13063
|
-
"turing@example.com",
|
|
13064
|
-
"lovelace@example.com",
|
|
13065
|
-
"dijkstra@example.com",
|
|
13066
|
-
"knuth@example.com",
|
|
13067
|
-
"ritchie@example.com",
|
|
13068
|
-
"torvalds@example.com"
|
|
13069
|
-
];
|
|
13070
|
-
emailCache = new Map;
|
|
13071
|
-
USERNAME_POOL = [
|
|
13072
|
-
"@demo_user",
|
|
13073
|
-
"@demo_user2",
|
|
13074
|
-
"@demo_user3",
|
|
13075
|
-
"@demo_user4",
|
|
13076
|
-
"@demo_user5"
|
|
13077
|
-
];
|
|
13078
|
-
usernameCache = new Map;
|
|
13079
|
-
vaultKeyCache = new Map;
|
|
13080
|
-
});
|
|
13081
|
-
|
|
13082
13625
|
// ../node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/identity.js
|
|
13083
13626
|
var require_identity = __commonJS((exports) => {
|
|
13084
13627
|
var ALIAS = Symbol.for("yaml.alias");
|
|
@@ -22029,506 +22572,6 @@ var init_resolver = __esm(() => {
|
|
|
22029
22572
|
materializedDirs = new Set;
|
|
22030
22573
|
});
|
|
22031
22574
|
|
|
22032
|
-
// ../src/auth/quota.ts
|
|
22033
|
-
function isProbeThin(q) {
|
|
22034
|
-
return q.fiveHourUtilPresent === false && q.sevenDayUtilPresent === false;
|
|
22035
|
-
}
|
|
22036
|
-
function refillNormalizedUtils(q, now) {
|
|
22037
|
-
const nowMs = now.getTime();
|
|
22038
|
-
const fiveHourRefilled = q.fiveHourResetAt != null && q.fiveHourResetAt.getTime() <= nowMs;
|
|
22039
|
-
const sevenDayRefilled = q.sevenDayResetAt != null && q.sevenDayResetAt.getTime() <= nowMs;
|
|
22040
|
-
return {
|
|
22041
|
-
fiveHourUtilizationPct: fiveHourRefilled ? 0 : q.fiveHourUtilizationPct,
|
|
22042
|
-
sevenDayUtilizationPct: sevenDayRefilled ? 0 : q.sevenDayUtilizationPct,
|
|
22043
|
-
fiveHourRefilled,
|
|
22044
|
-
sevenDayRefilled
|
|
22045
|
-
};
|
|
22046
|
-
}
|
|
22047
|
-
|
|
22048
|
-
// auth-snapshot-format.ts
|
|
22049
|
-
var exports_auth_snapshot_format = {};
|
|
22050
|
-
__export(exports_auth_snapshot_format, {
|
|
22051
|
-
zipProbeResults: () => zipProbeResults,
|
|
22052
|
-
reviveLastQuota: () => reviveLastQuota,
|
|
22053
|
-
renderFallbackAnnouncement: () => renderFallbackAnnouncement,
|
|
22054
|
-
renderAuthSnapshotFormat2: () => renderAuthSnapshotFormat2,
|
|
22055
|
-
recommendation: () => recommendation,
|
|
22056
|
-
formatStatusTime: () => formatStatusTime,
|
|
22057
|
-
formatRelative: () => formatRelative,
|
|
22058
|
-
formatAbsolute: () => formatAbsolute,
|
|
22059
|
-
fmtPct: () => fmtPct,
|
|
22060
|
-
classifyHealth: () => classifyHealth,
|
|
22061
|
-
buildSnapshotsFromState: () => buildSnapshotsFromState,
|
|
22062
|
-
buildSnapshotsFromCachedState: () => buildSnapshotsFromCachedState,
|
|
22063
|
-
buildSnapshotKeyboard: () => buildSnapshotKeyboard,
|
|
22064
|
-
blockedReason: () => blockedReason,
|
|
22065
|
-
bindingWindow: () => bindingWindow,
|
|
22066
|
-
THROTTLING_THRESHOLD_PCT: () => THROTTLING_THRESHOLD_PCT
|
|
22067
|
-
});
|
|
22068
|
-
function classifyHealth(snap, now = new Date) {
|
|
22069
|
-
if (!snap.quota)
|
|
22070
|
-
return "unknown";
|
|
22071
|
-
const q = snap.quota;
|
|
22072
|
-
if (isProbeThin(q))
|
|
22073
|
-
return "unknown";
|
|
22074
|
-
const norm = refillNormalizedUtils(q, now);
|
|
22075
|
-
const max = Math.max(norm.fiveHourUtilizationPct, norm.sevenDayUtilizationPct);
|
|
22076
|
-
if (max >= 99.5)
|
|
22077
|
-
return "blocked";
|
|
22078
|
-
if (max >= THROTTLING_THRESHOLD_PCT)
|
|
22079
|
-
return "throttling";
|
|
22080
|
-
return "healthy";
|
|
22081
|
-
}
|
|
22082
|
-
function blockedReason(snap, now = new Date) {
|
|
22083
|
-
if (classifyHealth(snap, now) !== "blocked")
|
|
22084
|
-
return null;
|
|
22085
|
-
return "quota-exhausted";
|
|
22086
|
-
}
|
|
22087
|
-
function bindingWindow(q) {
|
|
22088
|
-
if (q.representativeClaim === "seven_day")
|
|
22089
|
-
return "7d";
|
|
22090
|
-
if (q.representativeClaim === "five_hour")
|
|
22091
|
-
return "5h";
|
|
22092
|
-
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7d" : "5h";
|
|
22093
|
-
}
|
|
22094
|
-
function formatRelative(target, now = new Date) {
|
|
22095
|
-
if (!target)
|
|
22096
|
-
return "\u2014";
|
|
22097
|
-
const deltaMs = target.getTime() - now.getTime();
|
|
22098
|
-
if (deltaMs <= 0)
|
|
22099
|
-
return "now";
|
|
22100
|
-
const totalMin = Math.round(deltaMs / 60000);
|
|
22101
|
-
if (totalMin < 60)
|
|
22102
|
-
return `${totalMin}m`;
|
|
22103
|
-
const h = Math.floor(totalMin / 60);
|
|
22104
|
-
const m = totalMin % 60;
|
|
22105
|
-
if (h < 24)
|
|
22106
|
-
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
22107
|
-
const d = Math.floor(h / 24);
|
|
22108
|
-
const rh = h % 24;
|
|
22109
|
-
return rh > 0 ? `${d}d ${rh}h` : `${d}d`;
|
|
22110
|
-
}
|
|
22111
|
-
function formatAbsolute(target, tz = "UTC") {
|
|
22112
|
-
if (!target)
|
|
22113
|
-
return "\u2014";
|
|
22114
|
-
return target.toLocaleString("en-US", {
|
|
22115
|
-
timeZone: tz,
|
|
22116
|
-
weekday: "short",
|
|
22117
|
-
hour: "numeric",
|
|
22118
|
-
minute: "2-digit",
|
|
22119
|
-
hour12: true
|
|
22120
|
-
});
|
|
22121
|
-
}
|
|
22122
|
-
function formatStatusTime(target, now = new Date, tz = "UTC") {
|
|
22123
|
-
if (!target)
|
|
22124
|
-
return "\u2014";
|
|
22125
|
-
const dayFmt = new Intl.DateTimeFormat("en-CA", {
|
|
22126
|
-
timeZone: tz,
|
|
22127
|
-
year: "numeric",
|
|
22128
|
-
month: "2-digit",
|
|
22129
|
-
day: "2-digit"
|
|
22130
|
-
});
|
|
22131
|
-
const timeFmt = new Intl.DateTimeFormat("en-US", {
|
|
22132
|
-
timeZone: tz,
|
|
22133
|
-
hour: "numeric",
|
|
22134
|
-
minute: "2-digit",
|
|
22135
|
-
hour12: true
|
|
22136
|
-
});
|
|
22137
|
-
const timeStr = timeFmt.format(target);
|
|
22138
|
-
if (dayFmt.format(target) === dayFmt.format(now)) {
|
|
22139
|
-
return timeStr;
|
|
22140
|
-
}
|
|
22141
|
-
const withinWeek = target.getTime() - now.getTime() < 7 * 24 * 60 * 60 * 1000;
|
|
22142
|
-
const dateFmt = new Intl.DateTimeFormat("en-US", {
|
|
22143
|
-
timeZone: tz,
|
|
22144
|
-
weekday: "short",
|
|
22145
|
-
...withinWeek ? {} : { day: "numeric", month: "short" }
|
|
22146
|
-
});
|
|
22147
|
-
return `${dateFmt.format(target)} ${timeStr}`;
|
|
22148
|
-
}
|
|
22149
|
-
function fmtPct(pct) {
|
|
22150
|
-
return `${Math.min(100, Math.round(pct))}%`;
|
|
22151
|
-
}
|
|
22152
|
-
function displayLabel(label, opts) {
|
|
22153
|
-
return opts.demo ? maskEmail(label) : label;
|
|
22154
|
-
}
|
|
22155
|
-
function renderAccountRow(snap, opts) {
|
|
22156
|
-
const now = opts.now ?? new Date;
|
|
22157
|
-
const tz = opts.tz ?? "UTC";
|
|
22158
|
-
const lines = [];
|
|
22159
|
-
const marker = snap.isActive ? "\u25cf " : "";
|
|
22160
|
-
const label = displayLabel(snap.label, opts);
|
|
22161
|
-
if (!snap.quota) {
|
|
22162
|
-
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota probe failed_`);
|
|
22163
|
-
if (snap.quotaError) {
|
|
22164
|
-
lines.push(` _${escapeMarkdown(snap.quotaError)}_`);
|
|
22165
|
-
}
|
|
22166
|
-
return lines;
|
|
22167
|
-
}
|
|
22168
|
-
const q = snap.quota;
|
|
22169
|
-
if (isProbeThin(q)) {
|
|
22170
|
-
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota unknown (thin probe)_`);
|
|
22171
|
-
return lines;
|
|
22172
|
-
}
|
|
22173
|
-
const norm = refillNormalizedUtils(q, now);
|
|
22174
|
-
const fiveStr = fmtPct(norm.fiveHourUtilizationPct);
|
|
22175
|
-
const sevenStr = fmtPct(norm.sevenDayUtilizationPct);
|
|
22176
|
-
lines.push(`${marker}\`${codeSpanSafe(label)}\` ${fiveStr} / ${sevenStr}`);
|
|
22177
|
-
const health = classifyHealth(snap, now);
|
|
22178
|
-
if (health === "blocked") {
|
|
22179
|
-
const win = bindingWindow(q);
|
|
22180
|
-
const reset = win === "5h" ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
22181
|
-
const winLabel = win === "5h" ? "5-hour" : "7-day";
|
|
22182
|
-
lines.push(reset ? ` _quota exhausted \u2014 back ${formatAbsolute(reset, tz)} (\`in ${formatRelative(reset, now)}\`, ${winLabel} cap)_` : ` _quota exhausted \u2014 ${winLabel} cap, reset time unknown_`);
|
|
22183
|
-
return lines;
|
|
22184
|
-
}
|
|
22185
|
-
const fiveResetIn = q.fiveHourResetAt ? q.fiveHourResetAt.getTime() - now.getTime() : Infinity;
|
|
22186
|
-
const sevenResetIn = q.sevenDayResetAt ? q.sevenDayResetAt.getTime() - now.getTime() : Infinity;
|
|
22187
|
-
const fiveFirst = fiveResetIn <= sevenResetIn;
|
|
22188
|
-
const fiveSeg = q.fiveHourResetAt ? `5h refills ${formatAbsolute(q.fiveHourResetAt, tz)} (\`in ${formatRelative(q.fiveHourResetAt, now)}\`)` : "5h refills \u2014";
|
|
22189
|
-
const sevenSeg = q.sevenDayResetAt ? `7d resets ${formatAbsolute(q.sevenDayResetAt, tz)} (\`in ${formatRelative(q.sevenDayResetAt, now)}\`)` : "7d resets \u2014";
|
|
22190
|
-
lines.push(` _${fiveFirst ? fiveSeg : sevenSeg}_`);
|
|
22191
|
-
lines.push(` _${fiveFirst ? sevenSeg : fiveSeg}_`);
|
|
22192
|
-
if (q.overageDisabledReason != null && OVERAGE_EXHAUSTED_REASONS.has(q.overageDisabledReason)) {
|
|
22193
|
-
lines.push(` _overage off (${escapeMarkdown(q.overageDisabledReason)}) \u2014 serving from quota_`);
|
|
22194
|
-
}
|
|
22195
|
-
return lines;
|
|
22196
|
-
}
|
|
22197
|
-
function formatAgeStamp(atMs, now = new Date) {
|
|
22198
|
-
const ageSec = Math.max(0, Math.round((now.getTime() - atMs) / 1000));
|
|
22199
|
-
return ageSec < 60 ? `${ageSec}s ago` : `${Math.round(ageSec / 60)}m ago`;
|
|
22200
|
-
}
|
|
22201
|
-
function tableCell(s) {
|
|
22202
|
-
return s.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
22203
|
-
}
|
|
22204
|
-
function pctCells(snap, now) {
|
|
22205
|
-
if (!snap.quota)
|
|
22206
|
-
return { five: "\u2014", seven: "\u2014" };
|
|
22207
|
-
if (isProbeThin(snap.quota))
|
|
22208
|
-
return { five: "?", seven: "?" };
|
|
22209
|
-
const norm = refillNormalizedUtils(snap.quota, now);
|
|
22210
|
-
return { five: fmtPct(norm.fiveHourUtilizationPct), seven: fmtPct(norm.sevenDayUtilizationPct) };
|
|
22211
|
-
}
|
|
22212
|
-
function windowResetCell(snap, now, tz, win) {
|
|
22213
|
-
if (!snap.quota) {
|
|
22214
|
-
return snap.quotaError ? `probe failed (${snap.quotaError})` : "\u2014";
|
|
22215
|
-
}
|
|
22216
|
-
if (isProbeThin(snap.quota))
|
|
22217
|
-
return "quota unknown";
|
|
22218
|
-
const reset = win === "5h" ? snap.quota.fiveHourResetAt : snap.quota.sevenDayResetAt;
|
|
22219
|
-
if (!reset)
|
|
22220
|
-
return "\u2014";
|
|
22221
|
-
return `${formatStatusTime(reset, now, tz)} (in ${formatRelative(reset, now)})`;
|
|
22222
|
-
}
|
|
22223
|
-
function renderAuthSnapshotFormat2(snapshots, opts = {}) {
|
|
22224
|
-
const now = opts.now ?? new Date;
|
|
22225
|
-
const tz = opts.tz ?? "UTC";
|
|
22226
|
-
const lines = [];
|
|
22227
|
-
lines.push("\uD83D\uDD0B **Auth \u2014 fleet status**");
|
|
22228
|
-
const ordered = [...snapshots].sort((a, b) => {
|
|
22229
|
-
if (a.isActive !== b.isActive)
|
|
22230
|
-
return a.isActive ? -1 : 1;
|
|
22231
|
-
const r = TABLE_HEALTH_RANK[classifyHealth(a, now)] - TABLE_HEALTH_RANK[classifyHealth(b, now)];
|
|
22232
|
-
if (r !== 0)
|
|
22233
|
-
return r;
|
|
22234
|
-
return a.label.localeCompare(b.label);
|
|
22235
|
-
});
|
|
22236
|
-
if (ordered.length > 0) {
|
|
22237
|
-
lines.push("");
|
|
22238
|
-
lines.push("| State | Account | 5h | 5h resets | 7d | 7d resets |");
|
|
22239
|
-
lines.push("| --- | --- | --- | --- | --- | --- |");
|
|
22240
|
-
for (const s of ordered) {
|
|
22241
|
-
const emoji = HEALTH_EMOJI[classifyHealth(s, now)];
|
|
22242
|
-
const label = displayLabel(s.label, opts);
|
|
22243
|
-
const accountCell = `\`${codeSpanSafe(s.isActive ? `${label} (active)` : label)}\``;
|
|
22244
|
-
const { five, seven } = pctCells(s, now);
|
|
22245
|
-
const fiveReset = windowResetCell(s, now, tz, "5h");
|
|
22246
|
-
const sevenReset = windowResetCell(s, now, tz, "7d");
|
|
22247
|
-
lines.push(`| ${emoji} | ${tableCell(accountCell)} | ${five} | ${tableCell(fiveReset)} | ${seven} | ${tableCell(sevenReset)} |`);
|
|
22248
|
-
}
|
|
22249
|
-
}
|
|
22250
|
-
lines.push("");
|
|
22251
|
-
lines.push(`_${recommendation(snapshots, now, opts.demo ?? false)}_`);
|
|
22252
|
-
if (opts.staleCachedAtMs != null) {
|
|
22253
|
-
lines.push(`_\u26a0 cached ${formatAgeStamp(opts.staleCachedAtMs, now)}_`);
|
|
22254
|
-
} else if (opts.liveProbedAtMs != null) {
|
|
22255
|
-
lines.push(`_Live \u00b7 refreshed ${formatAgeStamp(opts.liveProbedAtMs, now)}_`);
|
|
22256
|
-
} else if (opts.probeFailed) {
|
|
22257
|
-
lines.push("_\u26a0 probe failed \u2014 no live data_");
|
|
22258
|
-
} else {
|
|
22259
|
-
lines.push("_Live_");
|
|
22260
|
-
}
|
|
22261
|
-
return lines.join(`
|
|
22262
|
-
`);
|
|
22263
|
-
}
|
|
22264
|
-
function recommendation(snapshots, now = new Date, demo = false) {
|
|
22265
|
-
const active = snapshots.find((s) => s.isActive);
|
|
22266
|
-
if (!active)
|
|
22267
|
-
return "No active account set.";
|
|
22268
|
-
const activeHealth = classifyHealth(active, now);
|
|
22269
|
-
const others = snapshots.filter((s) => !s.isActive);
|
|
22270
|
-
const healthyAlt = others.find((s) => classifyHealth(s, now) === "healthy");
|
|
22271
|
-
const lbl = (s) => demo ? maskEmail(s.label) : s.label;
|
|
22272
|
-
const activeLabel = lbl(active);
|
|
22273
|
-
if (activeHealth === "healthy") {
|
|
22274
|
-
return `Recommendation: stay on ${activeLabel}.`;
|
|
22275
|
-
}
|
|
22276
|
-
if (activeHealth === "throttling") {
|
|
22277
|
-
if (healthyAlt) {
|
|
22278
|
-
return `Recommendation: active ${activeLabel} is throttling. Switch to ${lbl(healthyAlt)} for headroom.`;
|
|
22279
|
-
}
|
|
22280
|
-
return `Recommendation: active ${activeLabel} is throttling; no healthy alternative \u2014 wait for refill.`;
|
|
22281
|
-
}
|
|
22282
|
-
if (activeHealth === "blocked") {
|
|
22283
|
-
if (healthyAlt) {
|
|
22284
|
-
return `Recommendation: active ${activeLabel} is BLOCKED \u2014 switch to ${lbl(healthyAlt)} now.`;
|
|
22285
|
-
}
|
|
22286
|
-
return summarizeNoHealthyAlt(snapshots, now, demo);
|
|
22287
|
-
}
|
|
22288
|
-
return `Active ${activeLabel}: quota probe failed; broker last_seen unknown.`;
|
|
22289
|
-
}
|
|
22290
|
-
function summarizeNoHealthyAlt(snapshots, now, demo = false) {
|
|
22291
|
-
const mask = (label) => demo ? maskEmail(label) : label;
|
|
22292
|
-
let throttlingLabel = null;
|
|
22293
|
-
let allTrulyBlocked = true;
|
|
22294
|
-
for (const s of snapshots) {
|
|
22295
|
-
const h = classifyHealth(s, now);
|
|
22296
|
-
if (h === "throttling") {
|
|
22297
|
-
if (!throttlingLabel)
|
|
22298
|
-
throttlingLabel = s.label;
|
|
22299
|
-
allTrulyBlocked = false;
|
|
22300
|
-
} else if (h === "healthy" || h === "unknown") {
|
|
22301
|
-
allTrulyBlocked = false;
|
|
22302
|
-
} else if (h === "blocked" && blockedReason(s, now) === "quota-exhausted") {
|
|
22303
|
-
if (s.quota) {
|
|
22304
|
-
const win = bindingWindow(s.quota);
|
|
22305
|
-
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
22306
|
-
if (at && at.getTime() > now.getTime())
|
|
22307
|
-
allTrulyBlocked = false;
|
|
22308
|
-
}
|
|
22309
|
-
}
|
|
22310
|
-
}
|
|
22311
|
-
const earliestRecovery = pickEarliestRecovery(snapshots, now);
|
|
22312
|
-
if (throttlingLabel) {
|
|
22313
|
-
const eta = earliestRecovery ? ` Soonest full refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.` : "";
|
|
22314
|
-
return `No fully-healthy account; ${mask(throttlingLabel)} is throttling but still usable.${eta}`;
|
|
22315
|
-
}
|
|
22316
|
-
if (!allTrulyBlocked) {
|
|
22317
|
-
if (earliestRecovery) {
|
|
22318
|
-
return `All accounts at capacity; soonest refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
22319
|
-
}
|
|
22320
|
-
return `All accounts at capacity \u2014 waiting on a window refill.`;
|
|
22321
|
-
}
|
|
22322
|
-
if (earliestRecovery) {
|
|
22323
|
-
return `All accounts blocked. Earliest recovery: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
22324
|
-
}
|
|
22325
|
-
return `All accounts blocked. Run /auth add to attach another subscription.`;
|
|
22326
|
-
}
|
|
22327
|
-
function pickEarliestRecovery(snapshots, now) {
|
|
22328
|
-
let best = null;
|
|
22329
|
-
for (const s of snapshots) {
|
|
22330
|
-
if (!s.quota)
|
|
22331
|
-
continue;
|
|
22332
|
-
if (isProbeThin(s.quota))
|
|
22333
|
-
continue;
|
|
22334
|
-
const win = bindingWindow(s.quota);
|
|
22335
|
-
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
22336
|
-
if (!at || at.getTime() <= now.getTime())
|
|
22337
|
-
continue;
|
|
22338
|
-
if (!best || at.getTime() < best.at.getTime()) {
|
|
22339
|
-
best = { label: s.label, at };
|
|
22340
|
-
}
|
|
22341
|
-
}
|
|
22342
|
-
return best;
|
|
22343
|
-
}
|
|
22344
|
-
function renderFallbackAnnouncement(input) {
|
|
22345
|
-
const now = input.now ?? new Date;
|
|
22346
|
-
const tz = input.tz ?? "UTC";
|
|
22347
|
-
const lines = [];
|
|
22348
|
-
const limitWord = input.oldQuota ? limitWordFor(input.oldQuota) : "quota";
|
|
22349
|
-
const headerLimit = input.cause === "rate-limit" ? "rate limit" : limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
|
|
22350
|
-
if (!input.newLabel) {
|
|
22351
|
-
lines.push(`\uD83D\uDD34 **All accounts blocked \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
22352
|
-
lines.push("");
|
|
22353
|
-
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
22354
|
-
const fleet = input.fleetSnapshots ?? [];
|
|
22355
|
-
if (fleet.length > 0) {
|
|
22356
|
-
lines.push("");
|
|
22357
|
-
const rowOpts = { now, tz };
|
|
22358
|
-
const healthOrder = ["blocked", "throttling", "healthy", "unknown"];
|
|
22359
|
-
const rank = (s) => healthOrder.indexOf(classifyHealth(s, now));
|
|
22360
|
-
const ordered = [...fleet].sort((a, b) => rank(a) - rank(b) || Number(b.isActive) - Number(a.isActive));
|
|
22361
|
-
for (const snap of ordered) {
|
|
22362
|
-
for (const ln of renderAccountRow(snap, rowOpts))
|
|
22363
|
-
lines.push(ln);
|
|
22364
|
-
}
|
|
22365
|
-
const earliest = pickEarliestRecovery(fleet, now);
|
|
22366
|
-
if (earliest) {
|
|
22367
|
-
lines.push("");
|
|
22368
|
-
lines.push(`Earliest recovery: \`${codeSpanSafe(earliest.label)}\` ` + `${formatAbsolute(earliest.at, tz)} (in ${formatRelative(earliest.at, now)})`);
|
|
22369
|
-
}
|
|
22370
|
-
} else {
|
|
22371
|
-
const recovery = (input.oldQuota ? recoveryAtFor(input.oldQuota) : null) ?? input.parsedResetAt ?? null;
|
|
22372
|
-
if (recovery) {
|
|
22373
|
-
lines.push(`${escapeMarkdown(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
|
|
22374
|
-
}
|
|
22375
|
-
}
|
|
22376
|
-
lines.push("");
|
|
22377
|
-
lines.push(`Run \`/auth add <label>\` to attach another subscription, ` + `or \`/auth refresh\` to re-probe.`);
|
|
22378
|
-
return lines.join(`
|
|
22379
|
-
`);
|
|
22380
|
-
}
|
|
22381
|
-
lines.push(`\u2713 **Switched fleet \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
22382
|
-
lines.push("");
|
|
22383
|
-
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` \u2192 \`${codeSpanSafe(input.newLabel)}\``);
|
|
22384
|
-
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
22385
|
-
lines.push("");
|
|
22386
|
-
{
|
|
22387
|
-
const recovery = (input.oldQuota ? recoveryAtFor(input.oldQuota) : null) ?? input.parsedResetAt ?? null;
|
|
22388
|
-
if (recovery) {
|
|
22389
|
-
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
|
|
22390
|
-
}
|
|
22391
|
-
}
|
|
22392
|
-
if (input.newQuota) {
|
|
22393
|
-
const fiveStr = fmtPct(input.newQuota.fiveHourUtilizationPct);
|
|
22394
|
-
const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
|
|
22395
|
-
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
|
|
22396
|
-
const headroomStr = hasHeadroom ? "_(plenty of headroom)_" : "_(near limit \u2014 watch this)_";
|
|
22397
|
-
lines.push(`\`${codeSpanSafe(input.newLabel)}\` now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
22398
|
-
} else {
|
|
22399
|
-
lines.push(`_(quota probe for new account is pending \u2014 will reflect on next /auth)_`);
|
|
22400
|
-
}
|
|
22401
|
-
return lines.join(`
|
|
22402
|
-
`);
|
|
22403
|
-
}
|
|
22404
|
-
function limitWordFor(q) {
|
|
22405
|
-
if (q.representativeClaim === "seven_day" && q.sevenDayUtilizationPct >= 99)
|
|
22406
|
-
return "7-day";
|
|
22407
|
-
if (q.representativeClaim === "five_hour" && q.fiveHourUtilizationPct >= 99)
|
|
22408
|
-
return "5-hour";
|
|
22409
|
-
if (q.sevenDayUtilizationPct >= 99)
|
|
22410
|
-
return "7-day";
|
|
22411
|
-
if (q.fiveHourUtilizationPct >= 99)
|
|
22412
|
-
return "5-hour";
|
|
22413
|
-
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7-day" : "5-hour";
|
|
22414
|
-
}
|
|
22415
|
-
function recoveryAtFor(q) {
|
|
22416
|
-
const word = limitWordFor(q);
|
|
22417
|
-
if (word === "7-day")
|
|
22418
|
-
return q.sevenDayResetAt;
|
|
22419
|
-
if (word === "5-hour")
|
|
22420
|
-
return q.fiveHourResetAt;
|
|
22421
|
-
if (!q.fiveHourResetAt)
|
|
22422
|
-
return q.sevenDayResetAt;
|
|
22423
|
-
if (!q.sevenDayResetAt)
|
|
22424
|
-
return q.fiveHourResetAt;
|
|
22425
|
-
return q.fiveHourResetAt.getTime() < q.sevenDayResetAt.getTime() ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
22426
|
-
}
|
|
22427
|
-
function buildSnapshotKeyboard(snapshots, opts = {}) {
|
|
22428
|
-
const max = opts.maxSwitchButtons ?? 3;
|
|
22429
|
-
const now = opts.now ?? new Date;
|
|
22430
|
-
const rows = [];
|
|
22431
|
-
const switchTargets = snapshots.filter((s) => !s.isActive).sort((a, b) => switchPriority(a, now) - switchPriority(b, now)).filter((s) => classifyHealth(s, now) !== "blocked" && classifyHealth(s, now) !== "unknown").slice(0, max);
|
|
22432
|
-
for (const t of switchTargets) {
|
|
22433
|
-
rows.push([
|
|
22434
|
-
{
|
|
22435
|
-
text: `Switch fleet \u2192 ${opts.demo ? maskEmail(t.label) : t.label}`,
|
|
22436
|
-
callbackData: `auth:use:${t.label}`
|
|
22437
|
-
}
|
|
22438
|
-
]);
|
|
22439
|
-
}
|
|
22440
|
-
rows.push([
|
|
22441
|
-
{ text: "\u21bb Refresh", callbackData: opts.demo ? "auth:refresh:demo" : "auth:refresh" },
|
|
22442
|
-
{ text: "/usage", insertText: "/usage" },
|
|
22443
|
-
{ text: "+ Add", insertText: "/auth add " }
|
|
22444
|
-
]);
|
|
22445
|
-
return rows;
|
|
22446
|
-
}
|
|
22447
|
-
function switchPriority(s, now = new Date) {
|
|
22448
|
-
const h = classifyHealth(s, now);
|
|
22449
|
-
if (h === "healthy")
|
|
22450
|
-
return 0;
|
|
22451
|
-
if (h === "throttling")
|
|
22452
|
-
return 1;
|
|
22453
|
-
if (h === "unknown")
|
|
22454
|
-
return 2;
|
|
22455
|
-
return 3;
|
|
22456
|
-
}
|
|
22457
|
-
function zipProbeResults(labels, results) {
|
|
22458
|
-
let staleCachedAtMs;
|
|
22459
|
-
const quotas = labels.map((label) => {
|
|
22460
|
-
const hit = results.find((r) => r.label === label);
|
|
22461
|
-
if (!hit)
|
|
22462
|
-
return { ok: false, reason: "broker returned no result for account" };
|
|
22463
|
-
if (hit.served === "cache" && hit.capturedAt != null) {
|
|
22464
|
-
staleCachedAtMs = staleCachedAtMs == null ? hit.capturedAt : Math.min(staleCachedAtMs, hit.capturedAt);
|
|
22465
|
-
}
|
|
22466
|
-
return hit.result;
|
|
22467
|
-
});
|
|
22468
|
-
return staleCachedAtMs != null ? { quotas, staleCachedAtMs } : { quotas };
|
|
22469
|
-
}
|
|
22470
|
-
function buildSnapshotsFromState(state, quotas) {
|
|
22471
|
-
const out = [];
|
|
22472
|
-
for (let i = 0;i < state.accounts.length; i++) {
|
|
22473
|
-
const acc = state.accounts[i];
|
|
22474
|
-
const q = quotas[i];
|
|
22475
|
-
out.push({
|
|
22476
|
-
label: acc.label,
|
|
22477
|
-
isActive: acc.label === state.active,
|
|
22478
|
-
quota: q && q.ok ? q.data : null,
|
|
22479
|
-
quotaError: q && !q.ok ? q.reason : undefined,
|
|
22480
|
-
expiresAtMs: acc.expiresAt
|
|
22481
|
-
});
|
|
22482
|
-
}
|
|
22483
|
-
return out;
|
|
22484
|
-
}
|
|
22485
|
-
function reviveLastQuota(snap) {
|
|
22486
|
-
if (!snap)
|
|
22487
|
-
return null;
|
|
22488
|
-
return {
|
|
22489
|
-
fiveHourUtilizationPct: snap.fiveHourUtilizationPct,
|
|
22490
|
-
sevenDayUtilizationPct: snap.sevenDayUtilizationPct,
|
|
22491
|
-
fiveHourResetAt: snap.fiveHourResetAt ? new Date(snap.fiveHourResetAt) : null,
|
|
22492
|
-
sevenDayResetAt: snap.sevenDayResetAt ? new Date(snap.sevenDayResetAt) : null,
|
|
22493
|
-
representativeClaim: snap.representativeClaim,
|
|
22494
|
-
overageStatus: snap.overageStatus,
|
|
22495
|
-
overageDisabledReason: snap.overageDisabledReason,
|
|
22496
|
-
fiveHourUtilPresent: snap.fiveHourUtilPresent,
|
|
22497
|
-
sevenDayUtilPresent: snap.sevenDayUtilPresent
|
|
22498
|
-
};
|
|
22499
|
-
}
|
|
22500
|
-
function buildSnapshotsFromCachedState(state) {
|
|
22501
|
-
return state.accounts.map((acc) => {
|
|
22502
|
-
const lq = acc.last_quota ?? null;
|
|
22503
|
-
return {
|
|
22504
|
-
label: acc.label,
|
|
22505
|
-
isActive: acc.label === state.active,
|
|
22506
|
-
quota: reviveLastQuota(lq),
|
|
22507
|
-
quotaError: lq ? undefined : "no cached quota (no probe since broker start)",
|
|
22508
|
-
expiresAtMs: acc.expiresAt,
|
|
22509
|
-
capturedAtMs: lq?.capturedAt
|
|
22510
|
-
};
|
|
22511
|
-
});
|
|
22512
|
-
}
|
|
22513
|
-
var THROTTLING_THRESHOLD_PCT = 80, OVERAGE_EXHAUSTED_REASONS, HEALTH_EMOJI, TABLE_HEALTH_RANK;
|
|
22514
|
-
var init_auth_snapshot_format = __esm(() => {
|
|
22515
|
-
init_demo_mask();
|
|
22516
|
-
init_card_format();
|
|
22517
|
-
OVERAGE_EXHAUSTED_REASONS = new Set(["out_of_credits"]);
|
|
22518
|
-
HEALTH_EMOJI = {
|
|
22519
|
-
healthy: "\uD83D\uDFE2",
|
|
22520
|
-
throttling: "\uD83D\uDFE1",
|
|
22521
|
-
blocked: "\uD83D\uDD34",
|
|
22522
|
-
unknown: "\u26aa"
|
|
22523
|
-
};
|
|
22524
|
-
TABLE_HEALTH_RANK = {
|
|
22525
|
-
blocked: 0,
|
|
22526
|
-
throttling: 1,
|
|
22527
|
-
unknown: 2,
|
|
22528
|
-
healthy: 3
|
|
22529
|
-
};
|
|
22530
|
-
});
|
|
22531
|
-
|
|
22532
22575
|
// ../src/auth/broker/protocol.ts
|
|
22533
22576
|
function encodeRequest2(req) {
|
|
22534
22577
|
const line = JSON.stringify(RequestSchema2.parse(req)) + `
|
|
@@ -22549,7 +22592,7 @@ function decodeResponse2(line) {
|
|
|
22549
22592
|
}
|
|
22550
22593
|
return ResponseSchema2.parse(parsed);
|
|
22551
22594
|
}
|
|
22552
|
-
var MAX_FRAME_BYTES2, PROTOCOL_VERSION = 1, ProviderNameSchema, GetCredentialsRequestSchema, ListStateRequestSchema, SetActiveRequestSchema, MarkExhaustedRequestSchema, MarkThrottledRequestSchema, RefreshAccountRequestSchema, AnthropicCredentialsSchema, GoogleCredentialsSchema, MicrosoftCredentialsSchema, ProviderCredentialsSchema, AddAccountRequestSchema, RmAccountRequestSchema, SetOverrideRequestSchema, ListGoogleAccountsRequestSchema, ListMicrosoftAccountsRequestSchema, ProbeQuotaRequestSchema, ClaimNotificationRequestSchema, RequestSchema2, GetCredentialsDataSchema, AccountStateSchema, AgentStateSchema, ConsumerStateSchema, ListStateDataSchema, SetActiveDataSchema, MarkExhaustedDataSchema, MarkThrottledDataSchema, RefreshAccountDataSchema, AddAccountDataSchema, RmAccountDataSchema, SetOverrideDataSchema, ClaimNotificationDataSchema, GoogleAccountStateSchema, ListGoogleAccountsDataSchema, MicrosoftAccountStateSchema, ListMicrosoftAccountsDataSchema, ErrorBodySchema, SuccessResponseSchema, ErrorResponseSchema2, ResponseSchema2;
|
|
22595
|
+
var MAX_FRAME_BYTES2, PROTOCOL_VERSION = 1, ProviderNameSchema, GetCredentialsRequestSchema, ListStateRequestSchema, SetActiveRequestSchema, MarkExhaustedRequestSchema, MarkThrottledRequestSchema, RefreshAccountRequestSchema, AnthropicCredentialsSchema, GoogleCredentialsSchema, MicrosoftCredentialsSchema, ProviderCredentialsSchema, AddAccountRequestSchema, RmAccountRequestSchema, SetOverrideRequestSchema, ListGoogleAccountsRequestSchema, ListMicrosoftAccountsRequestSchema, ProbeQuotaRequestSchema, ClaimNotificationRequestSchema, GetExternalSpendRequestSchema, RequestSchema2, GetCredentialsDataSchema, AccountStateSchema, AgentStateSchema, ConsumerStateSchema, ListStateDataSchema, SetActiveDataSchema, MarkExhaustedDataSchema, MarkThrottledDataSchema, RefreshAccountDataSchema, AddAccountDataSchema, RmAccountDataSchema, SetOverrideDataSchema, ClaimNotificationDataSchema, GetExternalSpendDataSchema, GoogleAccountStateSchema, ListGoogleAccountsDataSchema, MicrosoftAccountStateSchema, ListMicrosoftAccountsDataSchema, ErrorBodySchema, SuccessResponseSchema, ErrorResponseSchema2, ResponseSchema2;
|
|
22553
22596
|
var init_protocol2 = __esm(() => {
|
|
22554
22597
|
init_zod();
|
|
22555
22598
|
MAX_FRAME_BYTES2 = 64 * 1024;
|
|
@@ -22680,6 +22723,12 @@ var init_protocol2 = __esm(() => {
|
|
|
22680
22723
|
key: exports_external.string().min(1).max(512),
|
|
22681
22724
|
windowMs: exports_external.number().int().positive().max(86400000)
|
|
22682
22725
|
});
|
|
22726
|
+
GetExternalSpendRequestSchema = exports_external.object({
|
|
22727
|
+
v: exports_external.literal(PROTOCOL_VERSION),
|
|
22728
|
+
op: exports_external.literal("get-external-spend"),
|
|
22729
|
+
id: exports_external.string().min(1),
|
|
22730
|
+
forceLive: exports_external.boolean().optional()
|
|
22731
|
+
});
|
|
22683
22732
|
RequestSchema2 = exports_external.discriminatedUnion("op", [
|
|
22684
22733
|
GetCredentialsRequestSchema,
|
|
22685
22734
|
ListStateRequestSchema,
|
|
@@ -22693,7 +22742,8 @@ var init_protocol2 = __esm(() => {
|
|
|
22693
22742
|
ListGoogleAccountsRequestSchema,
|
|
22694
22743
|
ListMicrosoftAccountsRequestSchema,
|
|
22695
22744
|
ProbeQuotaRequestSchema,
|
|
22696
|
-
ClaimNotificationRequestSchema
|
|
22745
|
+
ClaimNotificationRequestSchema,
|
|
22746
|
+
GetExternalSpendRequestSchema
|
|
22697
22747
|
]);
|
|
22698
22748
|
GetCredentialsDataSchema = exports_external.object({
|
|
22699
22749
|
account: exports_external.string(),
|
|
@@ -22704,6 +22754,8 @@ var init_protocol2 = __esm(() => {
|
|
|
22704
22754
|
label: exports_external.string(),
|
|
22705
22755
|
expiresAt: exports_external.number().optional(),
|
|
22706
22756
|
exhausted: exports_external.boolean(),
|
|
22757
|
+
in_service: exports_external.boolean().optional(),
|
|
22758
|
+
entitlement_blocked: exports_external.boolean().optional(),
|
|
22707
22759
|
exhausted_until: exports_external.number().optional(),
|
|
22708
22760
|
throttled_until: exports_external.number().optional(),
|
|
22709
22761
|
threshold_violations: exports_external.number().int().nonnegative().optional(),
|
|
@@ -22760,6 +22812,18 @@ var init_protocol2 = __esm(() => {
|
|
|
22760
22812
|
ClaimNotificationDataSchema = exports_external.object({
|
|
22761
22813
|
granted: exports_external.boolean()
|
|
22762
22814
|
});
|
|
22815
|
+
GetExternalSpendDataSchema = exports_external.object({
|
|
22816
|
+
available: exports_external.boolean(),
|
|
22817
|
+
day24hUsd: exports_external.number().optional(),
|
|
22818
|
+
day7dUsd: exports_external.number().optional(),
|
|
22819
|
+
top: exports_external.array(exports_external.object({
|
|
22820
|
+
label: exports_external.string(),
|
|
22821
|
+
usd: exports_external.number()
|
|
22822
|
+
})).optional(),
|
|
22823
|
+
capturedAtMs: exports_external.number().int().nonnegative().optional(),
|
|
22824
|
+
served: exports_external.enum(["live", "cache"]).optional(),
|
|
22825
|
+
reason: exports_external.string().optional()
|
|
22826
|
+
});
|
|
22763
22827
|
GoogleAccountStateSchema = exports_external.object({
|
|
22764
22828
|
account: exports_external.string(),
|
|
22765
22829
|
expiresAt: exports_external.number(),
|
|
@@ -22930,6 +22994,15 @@ class AuthBrokerClient {
|
|
|
22930
22994
|
}
|
|
22931
22995
|
return parsed;
|
|
22932
22996
|
}
|
|
22997
|
+
async getExternalSpend(forceLive) {
|
|
22998
|
+
const data = await this.send({
|
|
22999
|
+
v: PROTOCOL_VERSION,
|
|
23000
|
+
id: randomUUID(),
|
|
23001
|
+
op: "get-external-spend",
|
|
23002
|
+
...forceLive ? { forceLive: true } : {}
|
|
23003
|
+
});
|
|
23004
|
+
return data;
|
|
23005
|
+
}
|
|
22933
23006
|
async setActive(account) {
|
|
22934
23007
|
const data = await this.send({
|
|
22935
23008
|
v: PROTOCOL_VERSION,
|
|
@@ -29337,7 +29410,7 @@ var FLUSH_SUPPRESSION_WINDOW_MS = 2000;
|
|
|
29337
29410
|
var init_turn_flush_suppression = () => {};
|
|
29338
29411
|
|
|
29339
29412
|
// ../src/util/atomic.ts
|
|
29340
|
-
import { closeSync as closeSync6, constants as constants2, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync11, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
|
|
29413
|
+
import { closeSync as closeSync6, constants as constants2, fchmodSync, fchownSync, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync11, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
|
|
29341
29414
|
var TMP_OPEN_FLAGS;
|
|
29342
29415
|
var init_atomic = __esm(() => {
|
|
29343
29416
|
TMP_OPEN_FLAGS = constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | (constants2.O_NOFOLLOW ?? 0);
|
|
@@ -36742,6 +36815,7 @@ __export(exports_auth_snapshot_format2, {
|
|
|
36742
36815
|
formatRelative: () => formatRelative2,
|
|
36743
36816
|
formatAbsolute: () => formatAbsolute2,
|
|
36744
36817
|
fmtPct: () => fmtPct2,
|
|
36818
|
+
deriveUsageFooterFreshness: () => deriveUsageFooterFreshness2,
|
|
36745
36819
|
classifyHealth: () => classifyHealth2,
|
|
36746
36820
|
buildSnapshotsFromState: () => buildSnapshotsFromState2,
|
|
36747
36821
|
buildSnapshotsFromCachedState: () => buildSnapshotsFromCachedState2,
|
|
@@ -36751,6 +36825,12 @@ __export(exports_auth_snapshot_format2, {
|
|
|
36751
36825
|
THROTTLING_THRESHOLD_PCT: () => THROTTLING_THRESHOLD_PCT2
|
|
36752
36826
|
});
|
|
36753
36827
|
function classifyHealth2(snap, now = new Date) {
|
|
36828
|
+
if (!snap.isActive) {
|
|
36829
|
+
if (snap.entitlementBlocked === true)
|
|
36830
|
+
return "org-blocked";
|
|
36831
|
+
if (snap.inService === false)
|
|
36832
|
+
return "retired";
|
|
36833
|
+
}
|
|
36754
36834
|
if (!snap.quota)
|
|
36755
36835
|
return "unknown";
|
|
36756
36836
|
const q = snap.quota;
|
|
@@ -36843,6 +36923,12 @@ function renderAccountRow2(snap, opts) {
|
|
|
36843
36923
|
const lines = [];
|
|
36844
36924
|
const marker = snap.isActive ? "\u25cf " : "";
|
|
36845
36925
|
const label = displayLabel2(snap.label, opts);
|
|
36926
|
+
const health = classifyHealth2(snap, now);
|
|
36927
|
+
if (health === "org-blocked" || health === "retired") {
|
|
36928
|
+
const note = health === "org-blocked" ? "DISABLED (org) \u2014 no fleet routing" : "retired \u2014 removed from fleet rotation";
|
|
36929
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` _${note}_`);
|
|
36930
|
+
return lines;
|
|
36931
|
+
}
|
|
36846
36932
|
if (!snap.quota) {
|
|
36847
36933
|
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota probe failed_`);
|
|
36848
36934
|
if (snap.quotaError) {
|
|
@@ -36859,7 +36945,6 @@ function renderAccountRow2(snap, opts) {
|
|
|
36859
36945
|
const fiveStr = fmtPct2(norm.fiveHourUtilizationPct);
|
|
36860
36946
|
const sevenStr = fmtPct2(norm.sevenDayUtilizationPct);
|
|
36861
36947
|
lines.push(`${marker}\`${codeSpanSafe(label)}\` ${fiveStr} / ${sevenStr}`);
|
|
36862
|
-
const health = classifyHealth2(snap, now);
|
|
36863
36948
|
if (health === "blocked") {
|
|
36864
36949
|
const win = bindingWindow3(q);
|
|
36865
36950
|
const reset2 = win === "5h" ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
@@ -36951,7 +37036,11 @@ function recommendation2(snapshots, now = new Date, demo = false) {
|
|
|
36951
37036
|
if (!active)
|
|
36952
37037
|
return "No active account set.";
|
|
36953
37038
|
const activeHealth = classifyHealth2(active, now);
|
|
36954
|
-
const
|
|
37039
|
+
const inServiceFleet = snapshots.filter((s) => {
|
|
37040
|
+
const h = classifyHealth2(s, now);
|
|
37041
|
+
return h !== "retired" && h !== "org-blocked";
|
|
37042
|
+
});
|
|
37043
|
+
const others = inServiceFleet.filter((s) => !s.isActive);
|
|
36955
37044
|
const healthyAlt = others.find((s) => classifyHealth2(s, now) === "healthy");
|
|
36956
37045
|
const lbl = (s) => demo ? maskEmail(s.label) : s.label;
|
|
36957
37046
|
const activeLabel = lbl(active);
|
|
@@ -36968,7 +37057,7 @@ function recommendation2(snapshots, now = new Date, demo = false) {
|
|
|
36968
37057
|
if (healthyAlt) {
|
|
36969
37058
|
return `Recommendation: active ${activeLabel} is BLOCKED \u2014 switch to ${lbl(healthyAlt)} now.`;
|
|
36970
37059
|
}
|
|
36971
|
-
return summarizeNoHealthyAlt2(
|
|
37060
|
+
return summarizeNoHealthyAlt2(inServiceFleet, now, demo);
|
|
36972
37061
|
}
|
|
36973
37062
|
return `Active ${activeLabel}: quota probe failed; broker last_seen unknown.`;
|
|
36974
37063
|
}
|
|
@@ -37040,7 +37129,14 @@ function renderFallbackAnnouncement2(input) {
|
|
|
37040
37129
|
if (fleet.length > 0) {
|
|
37041
37130
|
lines.push("");
|
|
37042
37131
|
const rowOpts = { now, tz };
|
|
37043
|
-
const healthOrder = [
|
|
37132
|
+
const healthOrder = [
|
|
37133
|
+
"org-blocked",
|
|
37134
|
+
"blocked",
|
|
37135
|
+
"throttling",
|
|
37136
|
+
"healthy",
|
|
37137
|
+
"unknown",
|
|
37138
|
+
"retired"
|
|
37139
|
+
];
|
|
37044
37140
|
const rank = (s) => healthOrder.indexOf(classifyHealth2(s, now));
|
|
37045
37141
|
const ordered = [...fleet].sort((a, b) => rank(a) - rank(b) || Number(b.isActive) - Number(a.isActive));
|
|
37046
37142
|
for (const snap of ordered) {
|
|
@@ -37113,7 +37209,10 @@ function buildSnapshotKeyboard2(snapshots, opts = {}) {
|
|
|
37113
37209
|
const max = opts.maxSwitchButtons ?? 3;
|
|
37114
37210
|
const now = opts.now ?? new Date;
|
|
37115
37211
|
const rows = [];
|
|
37116
|
-
const switchTargets = snapshots.filter((s) => !s.isActive).sort((a, b) => switchPriority2(a, now) - switchPriority2(b, now)).filter((s) =>
|
|
37212
|
+
const switchTargets = snapshots.filter((s) => !s.isActive).sort((a, b) => switchPriority2(a, now) - switchPriority2(b, now)).filter((s) => {
|
|
37213
|
+
const h = classifyHealth2(s, now);
|
|
37214
|
+
return h !== "blocked" && h !== "unknown" && h !== "retired" && h !== "org-blocked";
|
|
37215
|
+
}).slice(0, max);
|
|
37117
37216
|
for (const t of switchTargets) {
|
|
37118
37217
|
rows.push([
|
|
37119
37218
|
{
|
|
@@ -37137,7 +37236,9 @@ function switchPriority2(s, now = new Date) {
|
|
|
37137
37236
|
return 1;
|
|
37138
37237
|
if (h === "unknown")
|
|
37139
37238
|
return 2;
|
|
37140
|
-
|
|
37239
|
+
if (h === "blocked")
|
|
37240
|
+
return 3;
|
|
37241
|
+
return 4;
|
|
37141
37242
|
}
|
|
37142
37243
|
function zipProbeResults2(labels, results) {
|
|
37143
37244
|
let staleCachedAtMs;
|
|
@@ -37152,6 +37253,13 @@ function zipProbeResults2(labels, results) {
|
|
|
37152
37253
|
});
|
|
37153
37254
|
return staleCachedAtMs != null ? { quotas, staleCachedAtMs } : { quotas };
|
|
37154
37255
|
}
|
|
37256
|
+
function deriveUsageFooterFreshness2(results, staleCachedAtMs, liveProbedAtMs) {
|
|
37257
|
+
if (staleCachedAtMs != null)
|
|
37258
|
+
return { staleCachedAtMs };
|
|
37259
|
+
if (results.some((r) => r.result.ok))
|
|
37260
|
+
return { liveProbedAtMs };
|
|
37261
|
+
return { probeFailed: true };
|
|
37262
|
+
}
|
|
37155
37263
|
function buildSnapshotsFromState2(state7, quotas) {
|
|
37156
37264
|
const out = [];
|
|
37157
37265
|
for (let i = 0;i < state7.accounts.length; i++) {
|
|
@@ -37162,7 +37270,9 @@ function buildSnapshotsFromState2(state7, quotas) {
|
|
|
37162
37270
|
isActive: acc.label === state7.active,
|
|
37163
37271
|
quota: q && q.ok ? q.data : null,
|
|
37164
37272
|
quotaError: q && !q.ok ? q.reason : undefined,
|
|
37165
|
-
expiresAtMs: acc.expiresAt
|
|
37273
|
+
expiresAtMs: acc.expiresAt,
|
|
37274
|
+
inService: acc.in_service,
|
|
37275
|
+
entitlementBlocked: acc.entitlement_blocked
|
|
37166
37276
|
});
|
|
37167
37277
|
}
|
|
37168
37278
|
return out;
|
|
@@ -37191,7 +37301,9 @@ function buildSnapshotsFromCachedState2(state7) {
|
|
|
37191
37301
|
quota: reviveLastQuota2(lq),
|
|
37192
37302
|
quotaError: lq ? undefined : "no cached quota (no probe since broker start)",
|
|
37193
37303
|
expiresAtMs: acc.expiresAt,
|
|
37194
|
-
capturedAtMs: lq?.capturedAt
|
|
37304
|
+
capturedAtMs: lq?.capturedAt,
|
|
37305
|
+
inService: acc.in_service,
|
|
37306
|
+
entitlementBlocked: acc.entitlement_blocked
|
|
37195
37307
|
};
|
|
37196
37308
|
});
|
|
37197
37309
|
}
|
|
@@ -37204,13 +37316,17 @@ var init_auth_snapshot_format2 = __esm(() => {
|
|
|
37204
37316
|
healthy: "\uD83D\uDFE2",
|
|
37205
37317
|
throttling: "\uD83D\uDFE1",
|
|
37206
37318
|
blocked: "\uD83D\uDD34",
|
|
37207
|
-
unknown: "\u26aa"
|
|
37319
|
+
unknown: "\u26aa",
|
|
37320
|
+
"org-blocked": "\u26d4",
|
|
37321
|
+
retired: "\u26ab"
|
|
37208
37322
|
};
|
|
37209
37323
|
TABLE_HEALTH_RANK2 = {
|
|
37210
|
-
blocked: 0,
|
|
37211
|
-
|
|
37212
|
-
|
|
37213
|
-
|
|
37324
|
+
"org-blocked": 0,
|
|
37325
|
+
blocked: 1,
|
|
37326
|
+
throttling: 2,
|
|
37327
|
+
unknown: 3,
|
|
37328
|
+
healthy: 4,
|
|
37329
|
+
retired: 5
|
|
37214
37330
|
};
|
|
37215
37331
|
});
|
|
37216
37332
|
|
|
@@ -37626,6 +37742,140 @@ var init_config_approval_handler = __esm(() => {
|
|
|
37626
37742
|
pending = new Map;
|
|
37627
37743
|
});
|
|
37628
37744
|
|
|
37745
|
+
// ../src/litellm/external-spend.ts
|
|
37746
|
+
function isExternalModel(model) {
|
|
37747
|
+
const m = model.trim().toLowerCase();
|
|
37748
|
+
if (!m)
|
|
37749
|
+
return false;
|
|
37750
|
+
if (m.startsWith("claude"))
|
|
37751
|
+
return false;
|
|
37752
|
+
if (m.includes("anthropic/claude"))
|
|
37753
|
+
return false;
|
|
37754
|
+
if (m.startsWith("openrouter/"))
|
|
37755
|
+
return true;
|
|
37756
|
+
if (m.startsWith("sr-"))
|
|
37757
|
+
return true;
|
|
37758
|
+
for (const needle of BARE_EXTERNAL_NEEDLES) {
|
|
37759
|
+
if (m.includes(needle))
|
|
37760
|
+
return true;
|
|
37761
|
+
}
|
|
37762
|
+
return false;
|
|
37763
|
+
}
|
|
37764
|
+
function shortModelLabel(model) {
|
|
37765
|
+
let m = model.trim();
|
|
37766
|
+
if (m.toLowerCase().startsWith("openrouter/")) {
|
|
37767
|
+
m = m.slice("openrouter/".length);
|
|
37768
|
+
}
|
|
37769
|
+
const parts = m.split("/").filter(Boolean);
|
|
37770
|
+
if (parts.length >= 2) {
|
|
37771
|
+
m = parts[parts.length - 1];
|
|
37772
|
+
}
|
|
37773
|
+
if (m.toLowerCase().startsWith("sr-")) {
|
|
37774
|
+
m = m.slice(3);
|
|
37775
|
+
}
|
|
37776
|
+
return m || model.trim();
|
|
37777
|
+
}
|
|
37778
|
+
function formatUsd(n) {
|
|
37779
|
+
if (!Number.isFinite(n) || n < 0)
|
|
37780
|
+
return "$0.00";
|
|
37781
|
+
return `$${n.toFixed(2)}`;
|
|
37782
|
+
}
|
|
37783
|
+
function utcDateString(d) {
|
|
37784
|
+
return d.toISOString().slice(0, 10);
|
|
37785
|
+
}
|
|
37786
|
+
function addUtcDays(dateStr, days) {
|
|
37787
|
+
const [y, m, d] = dateStr.split("-").map(Number);
|
|
37788
|
+
const dt = new Date(Date.UTC(y, m - 1, d));
|
|
37789
|
+
dt.setUTCDate(dt.getUTCDate() + days);
|
|
37790
|
+
return utcDateString(dt);
|
|
37791
|
+
}
|
|
37792
|
+
function rowDay(row) {
|
|
37793
|
+
const st = row.startTime;
|
|
37794
|
+
if (!st || typeof st !== "string")
|
|
37795
|
+
return null;
|
|
37796
|
+
return st.length >= 10 ? st.slice(0, 10) : null;
|
|
37797
|
+
}
|
|
37798
|
+
function externalModelsFromRow(row) {
|
|
37799
|
+
const out = {};
|
|
37800
|
+
const models = row.models ?? {};
|
|
37801
|
+
for (const [name, raw] of Object.entries(models)) {
|
|
37802
|
+
if (!isExternalModel(name))
|
|
37803
|
+
continue;
|
|
37804
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
37805
|
+
if (!Number.isFinite(n) || n === 0)
|
|
37806
|
+
continue;
|
|
37807
|
+
out[name] = (out[name] ?? 0) + n;
|
|
37808
|
+
}
|
|
37809
|
+
return out;
|
|
37810
|
+
}
|
|
37811
|
+
function summarizeExternalSpend(days, now = new Date) {
|
|
37812
|
+
const today = utcDateString(now);
|
|
37813
|
+
const start7 = addUtcDays(today, -6);
|
|
37814
|
+
let day24hUsd = 0;
|
|
37815
|
+
let day7dUsd = 0;
|
|
37816
|
+
const byModel = {};
|
|
37817
|
+
for (const row of days) {
|
|
37818
|
+
const day = rowDay(row);
|
|
37819
|
+
if (!day)
|
|
37820
|
+
continue;
|
|
37821
|
+
if (day < start7 || day > today)
|
|
37822
|
+
continue;
|
|
37823
|
+
const ext = externalModelsFromRow(row);
|
|
37824
|
+
let rowSum = 0;
|
|
37825
|
+
for (const [name, usd] of Object.entries(ext)) {
|
|
37826
|
+
rowSum += usd;
|
|
37827
|
+
byModel[name] = (byModel[name] ?? 0) + usd;
|
|
37828
|
+
}
|
|
37829
|
+
day7dUsd += rowSum;
|
|
37830
|
+
if (day === today)
|
|
37831
|
+
day24hUsd += rowSum;
|
|
37832
|
+
}
|
|
37833
|
+
const top = Object.entries(byModel).filter(([, usd]) => usd > 0).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, EXTERNAL_SPEND_TOP_N).map(([name, usd]) => ({ label: shortModelLabel(name), usd }));
|
|
37834
|
+
return { day24hUsd, day7dUsd, top };
|
|
37835
|
+
}
|
|
37836
|
+
function normalizeSpendLogRows(body) {
|
|
37837
|
+
if (Array.isArray(body))
|
|
37838
|
+
return body;
|
|
37839
|
+
if (body && typeof body === "object") {
|
|
37840
|
+
const data = body.data;
|
|
37841
|
+
if (Array.isArray(data))
|
|
37842
|
+
return data;
|
|
37843
|
+
}
|
|
37844
|
+
return [];
|
|
37845
|
+
}
|
|
37846
|
+
var EXTERNAL_SPEND_TOP_N = 3, EXTERNAL_SPEND_CACHE_TTL_MS = 90000, BARE_EXTERNAL_NEEDLES;
|
|
37847
|
+
var init_external_spend = __esm(() => {
|
|
37848
|
+
BARE_EXTERNAL_NEEDLES = [
|
|
37849
|
+
"gpt-oss",
|
|
37850
|
+
"grok",
|
|
37851
|
+
"gemini",
|
|
37852
|
+
"deepseek",
|
|
37853
|
+
"kimi",
|
|
37854
|
+
"glm-",
|
|
37855
|
+
"qwen",
|
|
37856
|
+
"llama"
|
|
37857
|
+
];
|
|
37858
|
+
});
|
|
37859
|
+
|
|
37860
|
+
// external-spend.ts
|
|
37861
|
+
function formatExternalSpendBlock(summary) {
|
|
37862
|
+
if (summary == null)
|
|
37863
|
+
return [];
|
|
37864
|
+
const lines = [
|
|
37865
|
+
"- \uD83D\uDCB8 External",
|
|
37866
|
+
`- 24h \`${formatUsd(summary.day24hUsd)}\` \u00b7 7d \`${formatUsd(summary.day7dUsd)}\``
|
|
37867
|
+
];
|
|
37868
|
+
if (summary.top.length > 0) {
|
|
37869
|
+
const topParts = summary.top.map((t) => `\`${t.label} ${formatUsd(t.usd)}\``);
|
|
37870
|
+
lines.push(`- top ${topParts.join(" \u00b7 ")}`);
|
|
37871
|
+
}
|
|
37872
|
+
return lines;
|
|
37873
|
+
}
|
|
37874
|
+
var init_external_spend2 = __esm(() => {
|
|
37875
|
+
init_external_spend();
|
|
37876
|
+
init_external_spend();
|
|
37877
|
+
});
|
|
37878
|
+
|
|
37629
37879
|
// quota-bar-format.ts
|
|
37630
37880
|
var exports_quota_bar_format = {};
|
|
37631
37881
|
__export(exports_quota_bar_format, {
|
|
@@ -37683,9 +37933,13 @@ function buildBar(pct, elapsedFrac) {
|
|
|
37683
37933
|
cells[tickIndex] = "\u2503";
|
|
37684
37934
|
return cells.join("");
|
|
37685
37935
|
}
|
|
37686
|
-
function accountStatus(isActive, exhausted) {
|
|
37936
|
+
function accountStatus(isActive, exhausted, opts = {}) {
|
|
37687
37937
|
if (isActive)
|
|
37688
37938
|
return "active";
|
|
37939
|
+
if (opts.entitlementBlocked === true)
|
|
37940
|
+
return "org-disabled";
|
|
37941
|
+
if (opts.inService === false)
|
|
37942
|
+
return "retired";
|
|
37689
37943
|
if (exhausted)
|
|
37690
37944
|
return "exhausted";
|
|
37691
37945
|
return "idle";
|
|
@@ -37698,10 +37952,15 @@ function formatWindowRow(window2, pct, resetAt, now = new Date) {
|
|
|
37698
37952
|
const timeLeft = formatTimeLeft(resetAt, now);
|
|
37699
37953
|
return `- ${dot} ${window2} \`[${bar}] ${pctStr} / ${timeLeft}\``;
|
|
37700
37954
|
}
|
|
37701
|
-
function renderQuotaBarAccount(label, isActive, exhausted, quota, now = new Date, demo = false) {
|
|
37702
|
-
const status = accountStatus(isActive, exhausted);
|
|
37955
|
+
function renderQuotaBarAccount(label, isActive, exhausted, quota, now = new Date, demo = false, service = {}) {
|
|
37956
|
+
const status = accountStatus(isActive, exhausted, service);
|
|
37703
37957
|
const displayLabel3 = demo ? maskEmail(label) : label;
|
|
37704
|
-
const lines = [`- **${escapeMarkdown(displayLabel3)}** (${status})`];
|
|
37958
|
+
const lines = [`- **${escapeMarkdown(displayLabel3)}** (${STATUS_LABEL[status]})`];
|
|
37959
|
+
if (status === "retired" || status === "org-disabled") {
|
|
37960
|
+
const note = status === "org-disabled" ? "disabled by org \u2014 no fleet routing" : "retired \u2014 removed from fleet rotation";
|
|
37961
|
+
lines.push(`- \u26ab \`${note}\``);
|
|
37962
|
+
return lines;
|
|
37963
|
+
}
|
|
37705
37964
|
if (!quota || isProbeThin(quota)) {
|
|
37706
37965
|
const reason = !quota ? "no data \u2014 probe failed" : "no data \u2014 thin probe";
|
|
37707
37966
|
lines.push(`- \u26a0\ufe0f 5h \`${reason}\``);
|
|
@@ -37721,9 +37980,17 @@ function renderQuotaBarBlock(snapshots, exhaustedByLabel, opts = {}) {
|
|
|
37721
37980
|
const now = opts.now ?? new Date;
|
|
37722
37981
|
const demo = opts.demo ?? false;
|
|
37723
37982
|
const lines = [];
|
|
37724
|
-
|
|
37983
|
+
const outOfService = (s) => !s.isActive && (s.entitlementBlocked === true || s.inService === false);
|
|
37984
|
+
const ordered = [
|
|
37985
|
+
...snapshots.filter((s) => !outOfService(s)),
|
|
37986
|
+
...snapshots.filter(outOfService)
|
|
37987
|
+
];
|
|
37988
|
+
for (const snap of ordered) {
|
|
37725
37989
|
const exhausted = exhaustedByLabel.get(snap.label) ?? false;
|
|
37726
|
-
lines.push(...renderQuotaBarAccount(snap.label, snap.isActive, exhausted, snap.quota, now, demo
|
|
37990
|
+
lines.push(...renderQuotaBarAccount(snap.label, snap.isActive, exhausted, snap.quota, now, demo, {
|
|
37991
|
+
inService: snap.inService,
|
|
37992
|
+
entitlementBlocked: snap.entitlementBlocked
|
|
37993
|
+
}));
|
|
37727
37994
|
}
|
|
37728
37995
|
return lines.join(`
|
|
37729
37996
|
`);
|
|
@@ -37737,7 +38004,9 @@ function renderQuotaBarBlockFromListState(state7, opts = {}) {
|
|
|
37737
38004
|
quota: reviveLastQuota(acc.last_quota ?? null),
|
|
37738
38005
|
quotaError: acc.last_quota ? undefined : "no cached quota (no probe since broker start)",
|
|
37739
38006
|
expiresAtMs: acc.expiresAt,
|
|
37740
|
-
capturedAtMs: acc.last_quota?.capturedAt
|
|
38007
|
+
capturedAtMs: acc.last_quota?.capturedAt,
|
|
38008
|
+
inService: acc.in_service,
|
|
38009
|
+
entitlementBlocked: acc.entitlement_blocked
|
|
37741
38010
|
}));
|
|
37742
38011
|
return renderQuotaBarBlock(snapshots, exhaustedByLabel, { now });
|
|
37743
38012
|
}
|
|
@@ -37747,6 +38016,9 @@ function renderUsageCard(snapshots, exhaustedByLabel, opts = {}) {
|
|
|
37747
38016
|
const bar = renderQuotaBarBlock(snapshots, exhaustedByLabel, { now, demo });
|
|
37748
38017
|
const lines = [bar];
|
|
37749
38018
|
lines.push(`_${recommendation(snapshots, now, demo)}_`);
|
|
38019
|
+
if (opts.externalSpend != null) {
|
|
38020
|
+
lines.push(...formatExternalSpendBlock(opts.externalSpend));
|
|
38021
|
+
}
|
|
37750
38022
|
if (opts.staleCachedAtMs != null) {
|
|
37751
38023
|
lines.push(`_\u26a0 cached ${formatAgeStamp3(opts.staleCachedAtMs, now)}_`);
|
|
37752
38024
|
} else if (opts.liveProbedAtMs != null) {
|
|
@@ -37759,13 +38031,95 @@ function renderUsageCard(snapshots, exhaustedByLabel, opts = {}) {
|
|
|
37759
38031
|
return lines.join(`
|
|
37760
38032
|
`);
|
|
37761
38033
|
}
|
|
37762
|
-
var FIVE_HOUR_MS, SEVEN_DAY_MS, BAR_WIDTH = 10;
|
|
38034
|
+
var FIVE_HOUR_MS, SEVEN_DAY_MS, BAR_WIDTH = 10, STATUS_LABEL;
|
|
37763
38035
|
var init_quota_bar_format = __esm(() => {
|
|
37764
38036
|
init_auth_snapshot_format();
|
|
37765
38037
|
init_card_format();
|
|
37766
38038
|
init_demo_mask();
|
|
38039
|
+
init_external_spend2();
|
|
37767
38040
|
FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
|
|
37768
38041
|
SEVEN_DAY_MS = 7 * 24 * 60 * 60 * 1000;
|
|
38042
|
+
STATUS_LABEL = {
|
|
38043
|
+
active: "active",
|
|
38044
|
+
"org-disabled": "DISABLED (org)",
|
|
38045
|
+
retired: "retired",
|
|
38046
|
+
exhausted: "exhausted",
|
|
38047
|
+
idle: "idle"
|
|
38048
|
+
};
|
|
38049
|
+
});
|
|
38050
|
+
|
|
38051
|
+
// external-spend.ts
|
|
38052
|
+
var exports_external_spend = {};
|
|
38053
|
+
__export(exports_external_spend, {
|
|
38054
|
+
utcDateString: () => utcDateString,
|
|
38055
|
+
summarizeExternalSpend: () => summarizeExternalSpend,
|
|
38056
|
+
shortModelLabel: () => shortModelLabel,
|
|
38057
|
+
normalizeSpendLogRows: () => normalizeSpendLogRows,
|
|
38058
|
+
isExternalModel: () => isExternalModel,
|
|
38059
|
+
formatUsd: () => formatUsd,
|
|
38060
|
+
formatExternalSpendBlock: () => formatExternalSpendBlock2,
|
|
38061
|
+
fetchExternalSpendSummary: () => fetchExternalSpendSummary,
|
|
38062
|
+
clearExternalSpendCache: () => clearExternalSpendCache,
|
|
38063
|
+
addUtcDays: () => addUtcDays,
|
|
38064
|
+
EXTERNAL_SPEND_CACHE_TTL_MS: () => EXTERNAL_SPEND_CACHE_TTL_MS
|
|
38065
|
+
});
|
|
38066
|
+
function clearExternalSpendCache() {
|
|
38067
|
+
clientCache = null;
|
|
38068
|
+
}
|
|
38069
|
+
function formatExternalSpendBlock2(summary) {
|
|
38070
|
+
if (summary == null)
|
|
38071
|
+
return [];
|
|
38072
|
+
const lines = [
|
|
38073
|
+
"- \uD83D\uDCB8 External",
|
|
38074
|
+
`- 24h \`${formatUsd(summary.day24hUsd)}\` \u00b7 7d \`${formatUsd(summary.day7dUsd)}\``
|
|
38075
|
+
];
|
|
38076
|
+
if (summary.top.length > 0) {
|
|
38077
|
+
const topParts = summary.top.map((t) => `\`${t.label} ${formatUsd(t.usd)}\``);
|
|
38078
|
+
lines.push(`- top ${topParts.join(" \u00b7 ")}`);
|
|
38079
|
+
}
|
|
38080
|
+
return lines;
|
|
38081
|
+
}
|
|
38082
|
+
async function fetchExternalSpendSummary(nowOrDeps = {}) {
|
|
38083
|
+
const deps = nowOrDeps instanceof Date ? { now: nowOrDeps } : nowOrDeps;
|
|
38084
|
+
const ttl = deps.cacheTtlMs ?? CLIENT_CACHE_TTL_MS;
|
|
38085
|
+
if (!deps.bypassCache && clientCache && Date.now() - clientCache.atMs < ttl) {
|
|
38086
|
+
return clientCache.summary;
|
|
38087
|
+
}
|
|
38088
|
+
try {
|
|
38089
|
+
let data;
|
|
38090
|
+
if (deps.getExternalSpend) {
|
|
38091
|
+
data = await deps.getExternalSpend(deps.forceLive);
|
|
38092
|
+
} else {
|
|
38093
|
+
const { AuthBrokerClient: AuthBrokerClient3 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
38094
|
+
const client3 = new AuthBrokerClient3;
|
|
38095
|
+
try {
|
|
38096
|
+
data = await client3.getExternalSpend(deps.forceLive);
|
|
38097
|
+
} finally {
|
|
38098
|
+
try {
|
|
38099
|
+
await client3.close();
|
|
38100
|
+
} catch {}
|
|
38101
|
+
}
|
|
38102
|
+
}
|
|
38103
|
+
if (!data?.available)
|
|
38104
|
+
return null;
|
|
38105
|
+
if (typeof data.day24hUsd !== "number" || typeof data.day7dUsd !== "number" || !Array.isArray(data.top)) {
|
|
38106
|
+
return null;
|
|
38107
|
+
}
|
|
38108
|
+
const summary = {
|
|
38109
|
+
day24hUsd: data.day24hUsd,
|
|
38110
|
+
day7dUsd: data.day7dUsd,
|
|
38111
|
+
top: data.top.map((t) => ({ label: String(t.label), usd: Number(t.usd) }))
|
|
38112
|
+
};
|
|
38113
|
+
clientCache = { atMs: Date.now(), summary };
|
|
38114
|
+
return summary;
|
|
38115
|
+
} catch {
|
|
38116
|
+
return null;
|
|
38117
|
+
}
|
|
38118
|
+
}
|
|
38119
|
+
var CLIENT_CACHE_TTL_MS = 30000, clientCache = null;
|
|
38120
|
+
var init_external_spend3 = __esm(() => {
|
|
38121
|
+
init_external_spend();
|
|
38122
|
+
init_external_spend();
|
|
37769
38123
|
});
|
|
37770
38124
|
|
|
37771
38125
|
// ../src/vault/approvals/client.ts
|
|
@@ -38411,6 +38765,16 @@ function buildStopReply(turnInFlight, queuedSessionCmds) {
|
|
|
38411
38765
|
`) };
|
|
38412
38766
|
}
|
|
38413
38767
|
|
|
38768
|
+
// gateway/usage-mask.ts
|
|
38769
|
+
function shouldMaskUsageLabels(chatType, groupAllowFrom) {
|
|
38770
|
+
if (chatType === "private")
|
|
38771
|
+
return false;
|
|
38772
|
+
if (chatType === "group" || chatType === "supergroup") {
|
|
38773
|
+
return (groupAllowFrom ?? []).length === 0;
|
|
38774
|
+
}
|
|
38775
|
+
return true;
|
|
38776
|
+
}
|
|
38777
|
+
|
|
38414
38778
|
// gateway/busy-ack.ts
|
|
38415
38779
|
var BUSY_ACK_STEP_AGE_THRESHOLD_MS = 12000;
|
|
38416
38780
|
function shouldPostBusyAck(input) {
|
|
@@ -40001,6 +40365,23 @@ function normalizeForDedup(text) {
|
|
|
40001
40365
|
|
|
40002
40366
|
// flushed-turn-supersede.ts
|
|
40003
40367
|
var DEFAULT_SUPERSEDE_TTL_MS = 60000;
|
|
40368
|
+
var SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS = 32;
|
|
40369
|
+
function normalizeForMatch(text) {
|
|
40370
|
+
return text.replace(/\s+/g, " ").trim();
|
|
40371
|
+
}
|
|
40372
|
+
function flushedAnswerMatchesReply(flushedText, replyText) {
|
|
40373
|
+
const flushed = normalizeForMatch(flushedText);
|
|
40374
|
+
const reply = normalizeForMatch(replyText);
|
|
40375
|
+
if (flushed.length === 0 || reply.length === 0)
|
|
40376
|
+
return false;
|
|
40377
|
+
if (flushed === reply)
|
|
40378
|
+
return true;
|
|
40379
|
+
if (reply.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS && flushed.includes(reply))
|
|
40380
|
+
return true;
|
|
40381
|
+
if (flushed.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS && reply.includes(flushed))
|
|
40382
|
+
return true;
|
|
40383
|
+
return false;
|
|
40384
|
+
}
|
|
40004
40385
|
function decideSupersede(record, args) {
|
|
40005
40386
|
const ttlMs = args.ttlMs ?? DEFAULT_SUPERSEDE_TTL_MS;
|
|
40006
40387
|
if (record == null)
|
|
@@ -40012,7 +40393,15 @@ function decideSupersede(record, args) {
|
|
|
40012
40393
|
if (!sameTurn) {
|
|
40013
40394
|
return { supersede: false, deleteMessageIds: [], reason: "different-turn" };
|
|
40014
40395
|
}
|
|
40015
|
-
|
|
40396
|
+
if (args.replyText != null && !flushedAnswerMatchesReply(record.text, args.replyText)) {
|
|
40397
|
+
return { supersede: false, deleteMessageIds: [], reason: "new-content", recordText: record.text };
|
|
40398
|
+
}
|
|
40399
|
+
return {
|
|
40400
|
+
supersede: true,
|
|
40401
|
+
deleteMessageIds: [...record.messageIds],
|
|
40402
|
+
reason: "supersede",
|
|
40403
|
+
recordText: record.text
|
|
40404
|
+
};
|
|
40016
40405
|
}
|
|
40017
40406
|
var NULL_TURN_KEY = "<<null-turn>>";
|
|
40018
40407
|
function turnKey(turnId) {
|
|
@@ -40044,7 +40433,12 @@ class FlushedTurnSupersedeRegistry {
|
|
|
40044
40433
|
}
|
|
40045
40434
|
peek(chatId, threadId, args) {
|
|
40046
40435
|
const rec = this.entries.get(makeKey2(chatId, threadId))?.get(turnKey(args.liveTurnId));
|
|
40047
|
-
return decideSupersede(rec, {
|
|
40436
|
+
return decideSupersede(rec, {
|
|
40437
|
+
liveTurnId: args.liveTurnId,
|
|
40438
|
+
replyText: args.replyText,
|
|
40439
|
+
now: args.now,
|
|
40440
|
+
ttlMs: this.ttlMs
|
|
40441
|
+
});
|
|
40048
40442
|
}
|
|
40049
40443
|
take(chatId, threadId, args) {
|
|
40050
40444
|
const lane = makeKey2(chatId, threadId);
|
|
@@ -40633,6 +41027,63 @@ function buildStopReply2(turnInFlight, queuedSessionCmds) {
|
|
|
40633
41027
|
`) };
|
|
40634
41028
|
}
|
|
40635
41029
|
|
|
41030
|
+
// gateway/auth-command.ts
|
|
41031
|
+
init_format();
|
|
41032
|
+
init_auth_snapshot_format();
|
|
41033
|
+
init_demo_mask();
|
|
41034
|
+
var pendingAuthRmFlows = new Map;
|
|
41035
|
+
function isAuthAdmin(args) {
|
|
41036
|
+
return args.isAdmin === true;
|
|
41037
|
+
}
|
|
41038
|
+
var REQUIRED_USAGE_SCOPE = "user:profile";
|
|
41039
|
+
function readdPrecheckError(label, replace, labelExists) {
|
|
41040
|
+
if (replace && !labelExists) {
|
|
41041
|
+
return `**/auth readd:** no account named \`${codeSpanSafe(label)}\` to re-auth. ` + `Run \`/auth show\` for the current list, or \`/auth add ${codeSpanSafe(label)}\` to add it fresh.`;
|
|
41042
|
+
}
|
|
41043
|
+
if (!replace && labelExists) {
|
|
41044
|
+
return `**/auth add:** \`${codeSpanSafe(label)}\` already exists. ` + `Use \`/auth readd ${codeSpanSafe(label)}\` to re-authenticate it in place (e.g. to widen scope).`;
|
|
41045
|
+
}
|
|
41046
|
+
return null;
|
|
41047
|
+
}
|
|
41048
|
+
async function runReaddPrecheck(getClient, label, replace) {
|
|
41049
|
+
try {
|
|
41050
|
+
const client = await getClient();
|
|
41051
|
+
if (!client)
|
|
41052
|
+
return null;
|
|
41053
|
+
const state = await client.listState();
|
|
41054
|
+
const exists = state.accounts.some((a) => a.label === label);
|
|
41055
|
+
return readdPrecheckError(label, replace, exists);
|
|
41056
|
+
} catch {
|
|
41057
|
+
return null;
|
|
41058
|
+
}
|
|
41059
|
+
}
|
|
41060
|
+
function formatGrantedScopesReply(scopes) {
|
|
41061
|
+
const list = Array.isArray(scopes) ? scopes.filter((s) => typeof s === "string") : [];
|
|
41062
|
+
const hasUsageScope = list.includes(REQUIRED_USAGE_SCOPE);
|
|
41063
|
+
if (list.length === 0) {
|
|
41064
|
+
return {
|
|
41065
|
+
text: `
|
|
41066
|
+
\u26a0\ufe0f **No scopes reported** on the new token \u2014 could not confirm \`${REQUIRED_USAGE_SCOPE}\`. ` + `7-day usage reporting may not work. Re-run \`/auth readd\` if usage is missing.`,
|
|
41067
|
+
hasUsageScope: false
|
|
41068
|
+
};
|
|
41069
|
+
}
|
|
41070
|
+
const rendered = list.map((s) => `\`${codeSpanSafe(s)}\``).join(", ");
|
|
41071
|
+
if (hasUsageScope) {
|
|
41072
|
+
return {
|
|
41073
|
+
text: `
|
|
41074
|
+
Granted scopes: ${rendered}
|
|
41075
|
+
\u2713 \`${REQUIRED_USAGE_SCOPE}\` present \u2014 7-day usage reporting is unlocked.`,
|
|
41076
|
+
hasUsageScope: true
|
|
41077
|
+
};
|
|
41078
|
+
}
|
|
41079
|
+
return {
|
|
41080
|
+
text: `
|
|
41081
|
+
Granted scopes: ${rendered}
|
|
41082
|
+
` + `\u26a0\ufe0f **\`${REQUIRED_USAGE_SCOPE}\` is MISSING** \u2014 7-day usage reporting will not work for this account. ` + `This usually means the narrow \`setup-token\` minter was used. Re-run \`/auth readd <label>\` with the broad login to fix.`,
|
|
41083
|
+
hasUsageScope: false
|
|
41084
|
+
};
|
|
41085
|
+
}
|
|
41086
|
+
|
|
40636
41087
|
// gateway/interrupt-defer.ts
|
|
40637
41088
|
class ToolFlightTracker2 {
|
|
40638
41089
|
inFlight = new Set;
|
|
@@ -41678,11 +42129,14 @@ async function interceptAuthAdd(p, deps) {
|
|
|
41678
42129
|
deps.pendingAuthAddFlows.delete(p.interceptKey);
|
|
41679
42130
|
try {
|
|
41680
42131
|
const credentials = await deps.submitAccountAuthCode(pendingAdd, p.text.trim());
|
|
42132
|
+
const replace = pendingAdd.replace === true;
|
|
41681
42133
|
try {
|
|
41682
|
-
await deps.addAccountViaBroker(pendingAdd.label, credentials, { replace
|
|
42134
|
+
await deps.addAccountViaBroker(pendingAdd.label, credentials, { replace });
|
|
41683
42135
|
deps.cleanAuthAddScratchDir(pendingAdd.scratchDir);
|
|
41684
|
-
|
|
41685
|
-
|
|
42136
|
+
const scopeReply = formatGrantedScopesReply(credentials.claudeAiOauth?.scopes);
|
|
42137
|
+
const verb = replace ? "re-authenticated" : "added";
|
|
42138
|
+
await deps.switchroomReply(p.ctx, `\u2713 Account \`${pendingAdd.label}\` ${verb}.
|
|
42139
|
+
The fleet's active account hasn't changed. Send \`/auth use ${deps.escapeHtmlForTg(pendingAdd.label)}\` to switch to it.` + scopeReply.text, { html: true });
|
|
41686
42140
|
} catch (brokerErr) {
|
|
41687
42141
|
deps.cleanAuthAddScratchDir(pendingAdd.scratchDir);
|
|
41688
42142
|
await deps.switchroomReply(p.ctx, `**/auth add failed at broker:** ${deps.escapeHtmlForTg(brokerErr?.message ?? String(brokerErr))}`, { html: true });
|
|
@@ -42308,11 +42762,14 @@ async function interceptAuthAdd2(p, deps) {
|
|
|
42308
42762
|
deps.pendingAuthAddFlows.delete(p.interceptKey);
|
|
42309
42763
|
try {
|
|
42310
42764
|
const credentials = await deps.submitAccountAuthCode(pendingAdd, p.text.trim());
|
|
42765
|
+
const replace = pendingAdd.replace === true;
|
|
42311
42766
|
try {
|
|
42312
|
-
await deps.addAccountViaBroker(pendingAdd.label, credentials, { replace
|
|
42767
|
+
await deps.addAccountViaBroker(pendingAdd.label, credentials, { replace });
|
|
42313
42768
|
deps.cleanAuthAddScratchDir(pendingAdd.scratchDir);
|
|
42314
|
-
|
|
42315
|
-
|
|
42769
|
+
const scopeReply = formatGrantedScopesReply(credentials.claudeAiOauth?.scopes);
|
|
42770
|
+
const verb = replace ? "re-authenticated" : "added";
|
|
42771
|
+
await deps.switchroomReply(p.ctx, `\u2713 Account \`${pendingAdd.label}\` ${verb}.
|
|
42772
|
+
The fleet's active account hasn't changed. Send \`/auth use ${deps.escapeHtmlForTg(pendingAdd.label)}\` to switch to it.` + scopeReply.text, { html: true });
|
|
42316
42773
|
} catch (brokerErr) {
|
|
42317
42774
|
deps.cleanAuthAddScratchDir(pendingAdd.scratchDir);
|
|
42318
42775
|
await deps.switchroomReply(p.ctx, `**/auth add failed at broker:** ${deps.escapeHtmlForTg(brokerErr?.message ?? String(brokerErr))}`, { html: true });
|
|
@@ -42809,6 +43266,7 @@ function pinnedMessageIsOurs(tracked, chatId, pinnedMessageId) {
|
|
|
42809
43266
|
return false;
|
|
42810
43267
|
}
|
|
42811
43268
|
var storeLockTails = new Map;
|
|
43269
|
+
var pinReconcileTails = new Map;
|
|
42812
43270
|
|
|
42813
43271
|
// gateway/pinned-message-handler.ts
|
|
42814
43272
|
async function handlePinnedMessage(ctx, deps) {
|
|
@@ -43272,14 +43730,23 @@ function relaunchErrorReply(deps, model, err) {
|
|
|
43272
43730
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43273
43731
|
return { text: `\u274c Could not schedule model switch: ${deps.escapeHtml(msg)}`, html: true };
|
|
43274
43732
|
}
|
|
43733
|
+
function unvalidatedIdCaveat(deps, model) {
|
|
43734
|
+
if (!model.trim().toLowerCase().startsWith("claude-"))
|
|
43735
|
+
return null;
|
|
43736
|
+
return `_\`${deps.escapeHtml(model)}\` can't be validated before launch \u2014 if it isn't a real Claude model id, claude will silently serve the configured fallback model instead. I check the first reply and will warn if that happens._`;
|
|
43737
|
+
}
|
|
43275
43738
|
async function scheduleRelaunchReply(deps, model, reason) {
|
|
43276
43739
|
try {
|
|
43277
43740
|
await deps.scheduleModelRelaunch(model, reason);
|
|
43278
43741
|
} catch (err) {
|
|
43279
43742
|
return relaunchErrorReply(deps, model, err);
|
|
43280
43743
|
}
|
|
43281
|
-
|
|
43282
|
-
|
|
43744
|
+
const caveat = unvalidatedIdCaveat(deps, model);
|
|
43745
|
+
return {
|
|
43746
|
+
text: [switchingLine(deps, model), ...caveat ? [caveat] : [], PERSIST_NOTE].join(`
|
|
43747
|
+
`),
|
|
43748
|
+
html: true
|
|
43749
|
+
};
|
|
43283
43750
|
}
|
|
43284
43751
|
async function scheduleDefaultRelaunchReply(deps, reason) {
|
|
43285
43752
|
try {
|
|
@@ -50565,16 +51032,28 @@ function formatModelLabel2(model) {
|
|
|
50565
51032
|
}
|
|
50566
51033
|
|
|
50567
51034
|
// gateway/session-model-source.ts
|
|
50568
|
-
function createSessionModelSource() {
|
|
51035
|
+
function createSessionModelSource(options = {}) {
|
|
50569
51036
|
let seq = 0;
|
|
50570
51037
|
let transcript = null;
|
|
50571
51038
|
let override = null;
|
|
51039
|
+
let overrideUnverified = false;
|
|
51040
|
+
let onDivergence = null;
|
|
50572
51041
|
return {
|
|
50573
|
-
noteTranscriptModel(model) {
|
|
51042
|
+
noteTranscriptModel(model, opts) {
|
|
50574
51043
|
transcript = { model, seq: ++seq };
|
|
51044
|
+
if (opts?.replayed === true)
|
|
51045
|
+
return;
|
|
51046
|
+
if (override != null && overrideUnverified) {
|
|
51047
|
+
overrideUnverified = false;
|
|
51048
|
+
const matches = options.servedMatchesRequested;
|
|
51049
|
+
if (matches != null && !matches(override.model, model)) {
|
|
51050
|
+
onDivergence?.({ requested: override.model, served: model });
|
|
51051
|
+
}
|
|
51052
|
+
}
|
|
50575
51053
|
},
|
|
50576
|
-
setOverride(model) {
|
|
51054
|
+
setOverride(model, opts) {
|
|
50577
51055
|
override = model == null ? null : { model, seq: ++seq };
|
|
51056
|
+
overrideUnverified = model != null && opts?.verify === true;
|
|
50578
51057
|
},
|
|
50579
51058
|
getOverride() {
|
|
50580
51059
|
return override?.model ?? null;
|
|
@@ -50588,6 +51067,9 @@ function createSessionModelSource() {
|
|
|
50588
51067
|
return { model: override.model, source: "override" };
|
|
50589
51068
|
}
|
|
50590
51069
|
return { model: transcript.model, source: "transcript" };
|
|
51070
|
+
},
|
|
51071
|
+
setDivergenceHandler(handler) {
|
|
51072
|
+
onDivergence = handler;
|
|
50591
51073
|
}
|
|
50592
51074
|
};
|
|
50593
51075
|
}
|
|
@@ -68599,7 +69081,7 @@ init_format();
|
|
|
68599
69081
|
init_auth_snapshot_format();
|
|
68600
69082
|
init_demo_mask();
|
|
68601
69083
|
var AUTH_RM_CONFIRM_TTL_MS = 60000;
|
|
68602
|
-
var
|
|
69084
|
+
var pendingAuthRmFlows2 = new Map;
|
|
68603
69085
|
var LABEL_RE = /^[A-Za-z0-9._@+-]+$/;
|
|
68604
69086
|
var LABEL_MAX = 64;
|
|
68605
69087
|
function validateAuthAddLabel(label) {
|
|
@@ -68647,14 +69129,24 @@ function parseAuthCommand(text4) {
|
|
|
68647
69129
|
return { kind: "help", reason: "Usage: /auth use <label>" };
|
|
68648
69130
|
return { kind: "use", label };
|
|
68649
69131
|
}
|
|
68650
|
-
case "add":
|
|
68651
|
-
|
|
69132
|
+
case "add":
|
|
69133
|
+
case "readd": {
|
|
69134
|
+
const positional = parts.slice(1).filter((t) => !t.startsWith("--"));
|
|
69135
|
+
const flags = new Set(parts.slice(1).filter((t) => t.startsWith("--")).map((t) => t.toLowerCase()));
|
|
69136
|
+
const label = positional[0];
|
|
69137
|
+
const usage = verb === "readd" ? "Usage: /auth readd <label>" : "Usage: /auth add <label>";
|
|
68652
69138
|
if (!label)
|
|
68653
|
-
return { kind: "help", reason:
|
|
69139
|
+
return { kind: "help", reason: usage };
|
|
68654
69140
|
const err = validateAuthAddLabel(label);
|
|
68655
69141
|
if (err)
|
|
68656
69142
|
return { kind: "help", reason: err };
|
|
68657
|
-
|
|
69143
|
+
for (const f of flags) {
|
|
69144
|
+
if (f !== "--replace") {
|
|
69145
|
+
return { kind: "help", reason: `Unknown flag \`${codeSpanSafe(f)}\` for \`/auth ${verb}\`.` };
|
|
69146
|
+
}
|
|
69147
|
+
}
|
|
69148
|
+
const replace2 = verb === "readd" || flags.has("--replace");
|
|
69149
|
+
return { kind: "add", label, replace: replace2 };
|
|
68658
69150
|
}
|
|
68659
69151
|
case "cancel":
|
|
68660
69152
|
return { kind: "cancel" };
|
|
@@ -68774,6 +69266,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
68774
69266
|
` + ` \`/auth use <label>\` \u2014 admin: swap the fleet to <label>
|
|
68775
69267
|
` + ` \`/auth rotate\` \u2014 admin: cycle to next non-exhausted fallback
|
|
68776
69268
|
` + ` \`/auth add <label>\` \u2014 admin: OAuth-add a new Anthropic account from chat
|
|
69269
|
+
` + ` \`/auth readd <label>\` \u2014 admin: re-auth an EXISTING account in place (widen scope)
|
|
68777
69270
|
` + ` \`/auth google add <email>\` \u2014 admin: Telegram-native Google account add/re-auth
|
|
68778
69271
|
` + ` \`/auth microsoft add <email>\` \u2014 admin: Telegram-native Microsoft account add/re-auth
|
|
68779
69272
|
` + ` \`/auth cancel\` \u2014 abort an \`/auth add\` or provider add in progress
|
|
@@ -68928,7 +69421,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
68928
69421
|
};
|
|
68929
69422
|
}
|
|
68930
69423
|
if (ctx.chatId) {
|
|
68931
|
-
|
|
69424
|
+
pendingAuthRmFlows2.set(ctx.chatId, {
|
|
68932
69425
|
label: parsed.label,
|
|
68933
69426
|
expiresAt: Date.now() + AUTH_RM_CONFIRM_TTL_MS
|
|
68934
69427
|
});
|
|
@@ -68942,11 +69435,11 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
68942
69435
|
};
|
|
68943
69436
|
}
|
|
68944
69437
|
if (parsed.kind === "rm-confirmed") {
|
|
68945
|
-
const pending = ctx.chatId ?
|
|
69438
|
+
const pending = ctx.chatId ? pendingAuthRmFlows2.get(ctx.chatId) : undefined;
|
|
68946
69439
|
const now = Date.now();
|
|
68947
69440
|
if (!pending || pending.label !== parsed.label || pending.expiresAt <= now) {
|
|
68948
69441
|
if (ctx.chatId && pending && pending.expiresAt <= now) {
|
|
68949
|
-
|
|
69442
|
+
pendingAuthRmFlows2.delete(ctx.chatId);
|
|
68950
69443
|
}
|
|
68951
69444
|
return {
|
|
68952
69445
|
text: `**/auth rm:** no pending confirm for \`${codeSpanSafe(parsed.label)}\` (expired or not started). ` + `Send \`/auth rm ${codeSpanSafe(parsed.label)}\` first.`,
|
|
@@ -68954,7 +69447,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
68954
69447
|
};
|
|
68955
69448
|
}
|
|
68956
69449
|
if (ctx.chatId)
|
|
68957
|
-
|
|
69450
|
+
pendingAuthRmFlows2.delete(ctx.chatId);
|
|
68958
69451
|
try {
|
|
68959
69452
|
const data = await ctx.client.rmAccount(parsed.label);
|
|
68960
69453
|
return {
|
|
@@ -69044,7 +69537,7 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
69044
69537
|
html: true
|
|
69045
69538
|
};
|
|
69046
69539
|
}
|
|
69047
|
-
function
|
|
69540
|
+
function isAuthAdmin2(args) {
|
|
69048
69541
|
return args.isAdmin === true;
|
|
69049
69542
|
}
|
|
69050
69543
|
function isAdmin(ctx) {
|
|
@@ -69626,6 +70119,15 @@ class AuthBrokerClient2 {
|
|
|
69626
70119
|
}
|
|
69627
70120
|
return parsed;
|
|
69628
70121
|
}
|
|
70122
|
+
async getExternalSpend(forceLive) {
|
|
70123
|
+
const data = await this.send({
|
|
70124
|
+
v: PROTOCOL_VERSION,
|
|
70125
|
+
id: randomUUID4(),
|
|
70126
|
+
op: "get-external-spend",
|
|
70127
|
+
...forceLive ? { forceLive: true } : {}
|
|
70128
|
+
});
|
|
70129
|
+
return data;
|
|
70130
|
+
}
|
|
69629
70131
|
async setActive(account) {
|
|
69630
70132
|
const data = await this.send({
|
|
69631
70133
|
v: PROTOCOL_VERSION,
|
|
@@ -70119,6 +70621,12 @@ function readTokenFromCredentialsFile(credentialsFilePath) {
|
|
|
70119
70621
|
}
|
|
70120
70622
|
}
|
|
70121
70623
|
|
|
70624
|
+
// ../src/auth/via-claude.ts
|
|
70625
|
+
var PRE_PASTE_RULES = [
|
|
70626
|
+
{ name: "theme", match: /Choose.{1,30}text.{1,30}style/, keys: ["Enter"] },
|
|
70627
|
+
{ name: "login-method", match: /Select login method/, keys: ["Enter"] }
|
|
70628
|
+
];
|
|
70629
|
+
|
|
70122
70630
|
// gateway/auth-add-flow.ts
|
|
70123
70631
|
function makeAuthAddTmuxOps(tmuxBin = "tmux") {
|
|
70124
70632
|
return {
|
|
@@ -70144,6 +70652,11 @@ function makeAuthAddTmuxOps(tmuxBin = "tmux") {
|
|
|
70144
70652
|
stdio: ["pipe", "pipe", "pipe"]
|
|
70145
70653
|
});
|
|
70146
70654
|
},
|
|
70655
|
+
sendKey(socket, session, key) {
|
|
70656
|
+
execFileSync4(tmuxBin, ["-L", socket, "send-keys", "-t", session, key], {
|
|
70657
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
70658
|
+
});
|
|
70659
|
+
},
|
|
70147
70660
|
hasSession(socket, session) {
|
|
70148
70661
|
try {
|
|
70149
70662
|
execFileSync4(tmuxBin, ["-L", socket, "has-session", "-t", session], {
|
|
@@ -70216,10 +70729,11 @@ async function startAccountAuthSession(label, opts = {}) {
|
|
|
70216
70729
|
throw new Error('tmux supervisor required for /auth add: SWITCHROOM_TMUX_SUPERVISOR is not set to "1". ' + "Legacy pipe-based setup-token is unsupported (setup-token writes to /dev/tty, not stdout/stderr).");
|
|
70217
70730
|
}
|
|
70218
70731
|
const home2 = opts.home ?? homedir9();
|
|
70219
|
-
const urlTimeoutMs = opts.urlTimeoutMs ??
|
|
70732
|
+
const urlTimeoutMs = opts.urlTimeoutMs ?? 30000;
|
|
70220
70733
|
const agentName3 = opts.agentName ?? process.env.SWITCHROOM_AGENT_NAME ?? "gateway";
|
|
70221
70734
|
const tmux = opts.tmuxOps ?? makeAuthAddTmuxOps(opts.tmuxBin);
|
|
70222
70735
|
const binary = opts.claudeBinary ?? "claude";
|
|
70736
|
+
const mode = opts.mode ?? "via-claude";
|
|
70223
70737
|
const scratchDir = pickScratchDir(label, home2);
|
|
70224
70738
|
mkdirSync23(scratchDir, { recursive: true, mode: 448 });
|
|
70225
70739
|
sweepOrphanSessions(home2, tmux);
|
|
@@ -70240,18 +70754,21 @@ ${tmuxSession}`, "utf8");
|
|
|
70240
70754
|
sessionEnv["CLAUDE_CONFIG_DIR"] = scratchDir;
|
|
70241
70755
|
if (process.env.XDG_CONFIG_HOME)
|
|
70242
70756
|
sessionEnv["XDG_CONFIG_HOME"] = process.env.XDG_CONFIG_HOME;
|
|
70757
|
+
const sessionCmd = mode === "via-claude" ? binary : binary + " setup-token";
|
|
70758
|
+
const minterLabel = mode === "via-claude" ? "claude login" : "claude setup-token";
|
|
70243
70759
|
try {
|
|
70244
|
-
tmux.newSession(tmuxSocket, tmuxSession, sessionEnv,
|
|
70760
|
+
tmux.newSession(tmuxSocket, tmuxSession, sessionEnv, sessionCmd);
|
|
70245
70761
|
} catch (err) {
|
|
70246
70762
|
cleanScratchDir(scratchDir);
|
|
70247
|
-
throw new Error(`Failed to start tmux session for
|
|
70763
|
+
throw new Error(`Failed to start tmux session for ${minterLabel}: ${err.message}`);
|
|
70248
70764
|
}
|
|
70765
|
+
const preFired = new Set;
|
|
70249
70766
|
const loginUrl = await new Promise((resolve7, reject) => {
|
|
70250
70767
|
const deadline = setTimeout(() => {
|
|
70251
70768
|
clearInterval(ticker);
|
|
70252
70769
|
tmux.killSession(tmuxSocket, tmuxSession);
|
|
70253
70770
|
cleanScratchDir(scratchDir);
|
|
70254
|
-
reject(new Error(
|
|
70771
|
+
reject(new Error(`${minterLabel} did not print an OAuth URL within ${urlTimeoutMs}ms`));
|
|
70255
70772
|
}, urlTimeoutMs);
|
|
70256
70773
|
const ticker = setInterval(() => {
|
|
70257
70774
|
const pane = tmux.capture(tmuxSocket, tmuxSession);
|
|
@@ -70259,9 +70776,20 @@ ${tmuxSession}`, "utf8");
|
|
|
70259
70776
|
clearTimeout(deadline);
|
|
70260
70777
|
clearInterval(ticker);
|
|
70261
70778
|
cleanScratchDir(scratchDir);
|
|
70262
|
-
reject(new Error(
|
|
70779
|
+
reject(new Error(`${minterLabel} exited before printing OAuth URL`));
|
|
70263
70780
|
return;
|
|
70264
70781
|
}
|
|
70782
|
+
if (mode === "via-claude") {
|
|
70783
|
+
for (const rule of PRE_PASTE_RULES) {
|
|
70784
|
+
if (preFired.has(rule.name))
|
|
70785
|
+
continue;
|
|
70786
|
+
if (rule.match.test(pane)) {
|
|
70787
|
+
preFired.add(rule.name);
|
|
70788
|
+
for (const key of rule.keys)
|
|
70789
|
+
tmux.sendKey(tmuxSocket, tmuxSession, key);
|
|
70790
|
+
}
|
|
70791
|
+
}
|
|
70792
|
+
}
|
|
70265
70793
|
const url = parseSetupTokenUrl(pane);
|
|
70266
70794
|
if (url) {
|
|
70267
70795
|
clearTimeout(deadline);
|
|
@@ -70270,12 +70798,14 @@ ${tmuxSession}`, "utf8");
|
|
|
70270
70798
|
}
|
|
70271
70799
|
}, 500);
|
|
70272
70800
|
});
|
|
70273
|
-
return { loginUrl, scratchDir, tmuxSocket, tmuxSession };
|
|
70801
|
+
return { loginUrl, scratchDir, tmuxSocket, tmuxSession, mode };
|
|
70274
70802
|
}
|
|
70275
70803
|
async function submitAccountAuthCode(flow3, code2, opts = {}) {
|
|
70276
70804
|
const pollIntervalMs = opts.pollIntervalMs ?? 250;
|
|
70277
70805
|
const pollTimeoutMs = opts.pollTimeoutMs ?? 300000;
|
|
70278
70806
|
const tmux = opts.tmuxOps ?? makeAuthAddTmuxOps();
|
|
70807
|
+
const mode = flow3.mode ?? "via-claude";
|
|
70808
|
+
const blindEnterDelaysMs = opts.blindEnterDelaysMs ?? (mode === "via-claude" ? [1500, 3000, 5000] : []);
|
|
70279
70809
|
const credentialsPath = join26(flow3.scratchDir, ".credentials.json");
|
|
70280
70810
|
try {
|
|
70281
70811
|
tmux.send(flow3.tmuxSocket, flow3.tmuxSession, code2);
|
|
@@ -70283,9 +70813,19 @@ async function submitAccountAuthCode(flow3, code2, opts = {}) {
|
|
|
70283
70813
|
cleanScratchDir(flow3.scratchDir);
|
|
70284
70814
|
throw new Error(`Failed to submit auth code to tmux session: ${err.message}`);
|
|
70285
70815
|
}
|
|
70816
|
+
const pasteAt = Date.now();
|
|
70817
|
+
const blindEnters = blindEnterDelaysMs.map((d) => ({ at: pasteAt + d, fired: false }));
|
|
70286
70818
|
const deadline = Date.now() + pollTimeoutMs;
|
|
70287
70819
|
while (Date.now() < deadline) {
|
|
70288
70820
|
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
70821
|
+
for (const be of blindEnters) {
|
|
70822
|
+
if (!be.fired && Date.now() >= be.at) {
|
|
70823
|
+
be.fired = true;
|
|
70824
|
+
try {
|
|
70825
|
+
tmux.sendKey(flow3.tmuxSocket, flow3.tmuxSession, "Enter");
|
|
70826
|
+
} catch {}
|
|
70827
|
+
}
|
|
70828
|
+
}
|
|
70289
70829
|
if (existsSync22(credentialsPath)) {
|
|
70290
70830
|
const token = readTokenFromCredentialsFile(credentialsPath);
|
|
70291
70831
|
if (token) {
|
|
@@ -70315,6 +70855,59 @@ function cancelAccountAuthSession(flow3, tmuxOps) {
|
|
|
70315
70855
|
tmux.killSession(flow3.tmuxSocket, flow3.tmuxSession);
|
|
70316
70856
|
cleanScratchDir(flow3.scratchDir);
|
|
70317
70857
|
}
|
|
70858
|
+
async function handleAuthAddOrCancel(opts) {
|
|
70859
|
+
const { parsed, isAdmin: isAdmin2, currentAgent, chatId, threadId, reply, escapeHtml: escapeHtml5 } = opts;
|
|
70860
|
+
if (!isAuthAdmin({ isAdmin: isAdmin2 })) {
|
|
70861
|
+
await reply(`**Not authorized.** \`/auth ${parsed.kind}\` is admin-only.
|
|
70862
|
+
` + `Set \`admin: true\` on this agent in switchroom.yaml to unlock ` + `(the same flag that gates \`/agents\`, \`/restart\`, ` + `\`/update\` etc.).`);
|
|
70863
|
+
return;
|
|
70864
|
+
}
|
|
70865
|
+
const authAddKey = chatKey(chatId, threadId);
|
|
70866
|
+
if (parsed.kind === "cancel") {
|
|
70867
|
+
const existing = pendingAuthAddFlows.get(authAddKey);
|
|
70868
|
+
if (!existing) {
|
|
70869
|
+
await reply("_No pending `/auth add` flow in this chat._");
|
|
70870
|
+
return;
|
|
70871
|
+
}
|
|
70872
|
+
cancelAccountAuthSession(existing);
|
|
70873
|
+
pendingAuthAddFlows.delete(authAddKey);
|
|
70874
|
+
await reply("Cancelled.");
|
|
70875
|
+
return;
|
|
70876
|
+
}
|
|
70877
|
+
if (pendingAuthAddFlows.has(authAddKey)) {
|
|
70878
|
+
await reply("_An `/auth add` flow is already in progress for this chat. " + "Finish the paste, or send `/auth cancel` to abort._");
|
|
70879
|
+
return;
|
|
70880
|
+
}
|
|
70881
|
+
const precheckErr = await runReaddPrecheck(() => getAuthBrokerClient(currentAgent), parsed.label, parsed.replace);
|
|
70882
|
+
if (precheckErr) {
|
|
70883
|
+
await reply(precheckErr);
|
|
70884
|
+
return;
|
|
70885
|
+
}
|
|
70886
|
+
try {
|
|
70887
|
+
const { loginUrl, scratchDir, tmuxSocket, tmuxSession, mode } = await startAccountAuthSession(parsed.label);
|
|
70888
|
+
pendingAuthAddFlows.set(authAddKey, {
|
|
70889
|
+
label: parsed.label,
|
|
70890
|
+
scratchDir,
|
|
70891
|
+
tmuxSocket,
|
|
70892
|
+
tmuxSession,
|
|
70893
|
+
startedAt: Date.now(),
|
|
70894
|
+
replace: parsed.replace,
|
|
70895
|
+
mode
|
|
70896
|
+
});
|
|
70897
|
+
const verbNoun = parsed.replace ? "Re-authenticating account" : "Adding account";
|
|
70898
|
+
await reply(`**${verbNoun}** \`${parsed.label}\`
|
|
70899
|
+
|
|
70900
|
+
` + `1. Open this URL on your phone:
|
|
70901
|
+
${loginUrl}
|
|
70902
|
+
|
|
70903
|
+
` + `2. Log into Anthropic, copy the code Claude shows.
|
|
70904
|
+
` + `3. Paste it back here.
|
|
70905
|
+
|
|
70906
|
+
` + `Send \`/auth cancel\` to abort.`);
|
|
70907
|
+
} catch (err) {
|
|
70908
|
+
await reply(`**/auth ${parsed.replace ? "readd" : "add"} failed:** ${escapeHtml5(err?.message ?? String(err))}`);
|
|
70909
|
+
}
|
|
70910
|
+
}
|
|
70318
70911
|
|
|
70319
70912
|
// gateway/auth-loopback-relay.ts
|
|
70320
70913
|
import { spawn } from "node:child_process";
|
|
@@ -73154,6 +73747,23 @@ ${input.newReplyText}`;
|
|
|
73154
73747
|
|
|
73155
73748
|
// flushed-turn-supersede.ts
|
|
73156
73749
|
var DEFAULT_SUPERSEDE_TTL_MS2 = 60000;
|
|
73750
|
+
var SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 = 32;
|
|
73751
|
+
function normalizeForMatch2(text4) {
|
|
73752
|
+
return text4.replace(/\s+/g, " ").trim();
|
|
73753
|
+
}
|
|
73754
|
+
function flushedAnswerMatchesReply2(flushedText, replyText) {
|
|
73755
|
+
const flushed = normalizeForMatch2(flushedText);
|
|
73756
|
+
const reply = normalizeForMatch2(replyText);
|
|
73757
|
+
if (flushed.length === 0 || reply.length === 0)
|
|
73758
|
+
return false;
|
|
73759
|
+
if (flushed === reply)
|
|
73760
|
+
return true;
|
|
73761
|
+
if (reply.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && flushed.includes(reply))
|
|
73762
|
+
return true;
|
|
73763
|
+
if (flushed.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && reply.includes(flushed))
|
|
73764
|
+
return true;
|
|
73765
|
+
return false;
|
|
73766
|
+
}
|
|
73157
73767
|
function decideSupersede2(record, args) {
|
|
73158
73768
|
const ttlMs = args.ttlMs ?? DEFAULT_SUPERSEDE_TTL_MS2;
|
|
73159
73769
|
if (record == null)
|
|
@@ -73165,7 +73775,15 @@ function decideSupersede2(record, args) {
|
|
|
73165
73775
|
if (!sameTurn) {
|
|
73166
73776
|
return { supersede: false, deleteMessageIds: [], reason: "different-turn" };
|
|
73167
73777
|
}
|
|
73168
|
-
|
|
73778
|
+
if (args.replyText != null && !flushedAnswerMatchesReply2(record.text, args.replyText)) {
|
|
73779
|
+
return { supersede: false, deleteMessageIds: [], reason: "new-content", recordText: record.text };
|
|
73780
|
+
}
|
|
73781
|
+
return {
|
|
73782
|
+
supersede: true,
|
|
73783
|
+
deleteMessageIds: [...record.messageIds],
|
|
73784
|
+
reason: "supersede",
|
|
73785
|
+
recordText: record.text
|
|
73786
|
+
};
|
|
73169
73787
|
}
|
|
73170
73788
|
function decideSupersedeCorrection(input) {
|
|
73171
73789
|
const eligible = input.flushMessageIds.length === 1 && input.chunkCount === 1 && !input.hasFiles && !input.suppressText && !input.hasOpenPreview;
|
|
@@ -73204,7 +73822,12 @@ class FlushedTurnSupersedeRegistry2 {
|
|
|
73204
73822
|
}
|
|
73205
73823
|
peek(chatId, threadId, args) {
|
|
73206
73824
|
const rec = this.entries.get(makeKey3(chatId, threadId))?.get(turnKey2(args.liveTurnId));
|
|
73207
|
-
return decideSupersede2(rec, {
|
|
73825
|
+
return decideSupersede2(rec, {
|
|
73826
|
+
liveTurnId: args.liveTurnId,
|
|
73827
|
+
replyText: args.replyText,
|
|
73828
|
+
now: args.now,
|
|
73829
|
+
ttlMs: this.ttlMs
|
|
73830
|
+
});
|
|
73208
73831
|
}
|
|
73209
73832
|
take(chatId, threadId, args) {
|
|
73210
73833
|
const lane = makeKey3(chatId, threadId);
|
|
@@ -73253,7 +73876,9 @@ function decideAnswerLatchSuppression(input) {
|
|
|
73253
73876
|
return false;
|
|
73254
73877
|
if (!input.isLateReply)
|
|
73255
73878
|
return false;
|
|
73256
|
-
|
|
73879
|
+
if (input.replyMatchesFlushedAnswer === false)
|
|
73880
|
+
return false;
|
|
73881
|
+
return input.ownerAnswerDelivered === "flush";
|
|
73257
73882
|
}
|
|
73258
73883
|
|
|
73259
73884
|
// telegraph.ts
|
|
@@ -73854,31 +74479,40 @@ async function sendReply(deps, req) {
|
|
|
73854
74479
|
const replyThreadId = args.message_thread_id != null ? Number(args.message_thread_id) : undefined;
|
|
73855
74480
|
const ownerTurn = resolveReplyOwnerTurn(turn, chat_id, args);
|
|
73856
74481
|
const resolvedTurnId = ownerTurn?.turnId ?? null;
|
|
73857
|
-
const decision = flushedTurnSupersede.take(chat_id, replyThreadId, { liveTurnId: resolvedTurnId, now: Date.now() });
|
|
74482
|
+
const decision = flushedTurnSupersede.take(chat_id, replyThreadId, { liveTurnId: resolvedTurnId, replyText: text4, now: Date.now() });
|
|
73858
74483
|
if (decision.supersede) {
|
|
73859
74484
|
process.stderr.write(`telegram gateway: reply: superseding flushed turn message(s) ` + `chatId=${chat_id} ids=${JSON.stringify(decision.deleteMessageIds)}
|
|
73860
74485
|
`);
|
|
73861
74486
|
supersedeFlushIds = decision.deleteMessageIds;
|
|
73862
|
-
if (ownerTurn != null)
|
|
73863
|
-
ownerTurn.answerDelivered =
|
|
74487
|
+
if (ownerTurn != null) {
|
|
74488
|
+
ownerTurn.answerDelivered = "flush";
|
|
74489
|
+
if (decision.recordText != null)
|
|
74490
|
+
ownerTurn.flushedAnswerText = decision.recordText;
|
|
74491
|
+
}
|
|
73864
74492
|
} else {
|
|
73865
74493
|
const replySubstantive = isSubstantiveFinalReply({
|
|
73866
74494
|
text: rawText,
|
|
73867
74495
|
disableNotification: args.disable_notification === true
|
|
73868
74496
|
});
|
|
74497
|
+
const replyMatchesFlushedAnswer = decision.reason === "new-content" ? false : ownerTurn?.flushedAnswerText != null ? flushedAnswerMatchesReply2(ownerTurn.flushedAnswerText, text4) : null;
|
|
73869
74498
|
const suppressByLatch = decideAnswerLatchSuppression({
|
|
73870
74499
|
superseded: false,
|
|
73871
74500
|
replySubstantive,
|
|
73872
74501
|
isLateReply: turn == null,
|
|
73873
|
-
ownerAnswerDelivered: ownerTurn?.answerDelivered ?? false
|
|
74502
|
+
ownerAnswerDelivered: ownerTurn?.answerDelivered ?? false,
|
|
74503
|
+
replyMatchesFlushedAnswer
|
|
73874
74504
|
});
|
|
74505
|
+
if (decision.reason === "new-content") {
|
|
74506
|
+
process.stderr.write(`telegram gateway: reply: flush supersede declined \u2014 new content (#3429) ` + `chatId=${chat_id} ownerTurnId=${JSON.stringify(resolvedTurnId)}; sending fresh
|
|
74507
|
+
`);
|
|
74508
|
+
}
|
|
73875
74509
|
if (suppressByLatch) {
|
|
73876
74510
|
process.stderr.write(`telegram gateway: reply: suppressed by answer-delivered latch ` + `(flush already delivered this turn's answer) chatId=${chat_id} ` + `ownerTurnId=${JSON.stringify(resolvedTurnId)}
|
|
73877
74511
|
`);
|
|
73878
74512
|
return { content: [{ type: "text", text: "sent (deduped \u2014 answer already delivered via turn-flush)" }] };
|
|
73879
74513
|
}
|
|
73880
74514
|
if (replySubstantive && ownerTurn != null) {
|
|
73881
|
-
ownerTurn.answerDelivered =
|
|
74515
|
+
ownerTurn.answerDelivered = "reply";
|
|
73882
74516
|
}
|
|
73883
74517
|
}
|
|
73884
74518
|
}
|
|
@@ -75853,6 +76487,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
75853
76487
|
finalAnswerSubstantive: false,
|
|
75854
76488
|
finalAnswerEverDelivered: false,
|
|
75855
76489
|
answerDelivered: false,
|
|
76490
|
+
flushedAnswerText: null,
|
|
75856
76491
|
endedAt: null,
|
|
75857
76492
|
firstPingAt: null,
|
|
75858
76493
|
firstPingWasSubstantive: false,
|
|
@@ -75952,7 +76587,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
75952
76587
|
if (turn != null) {
|
|
75953
76588
|
turn.currentModel = ev.model;
|
|
75954
76589
|
}
|
|
75955
|
-
sessionModelSource.noteTranscriptModel(ev.model);
|
|
76590
|
+
sessionModelSource.noteTranscriptModel(ev.model, { replayed: ev.replayed === true });
|
|
75956
76591
|
return;
|
|
75957
76592
|
}
|
|
75958
76593
|
case "usage": {
|
|
@@ -76358,7 +76993,8 @@ function handleSessionEvent(deps, ev) {
|
|
|
76358
76993
|
}
|
|
76359
76994
|
turn.finalAnswerDelivered = true;
|
|
76360
76995
|
turn.finalAnswerSubstantive = true;
|
|
76361
|
-
turn.answerDelivered =
|
|
76996
|
+
turn.answerDelivered = "flush";
|
|
76997
|
+
turn.flushedAnswerText = capturedText;
|
|
76362
76998
|
const backstopLatchClaimed = backstopDeliveryLedger.claim(turn.turnId);
|
|
76363
76999
|
const cardTakeover = progressDriver?.takeOverCard({
|
|
76364
77000
|
chatId: backstopChatId,
|
|
@@ -76430,6 +77066,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
76430
77066
|
backstopCtrl.finalize("error");
|
|
76431
77067
|
backstopDeliveryLedger.release(turn.turnId);
|
|
76432
77068
|
turn.answerDelivered = false;
|
|
77069
|
+
turn.flushedAnswerText = null;
|
|
76433
77070
|
} else if (backstopCtrl) {
|
|
76434
77071
|
backstopCtrl.finalize("done");
|
|
76435
77072
|
}
|
|
@@ -76447,6 +77084,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
76447
77084
|
`);
|
|
76448
77085
|
if (!delivered) {
|
|
76449
77086
|
turn.answerDelivered = false;
|
|
77087
|
+
turn.flushedAnswerText = null;
|
|
76450
77088
|
backstopDeliveryLedger.release(turn.turnId);
|
|
76451
77089
|
if (backstopCtrl)
|
|
76452
77090
|
backstopCtrl.finalize("error");
|
|
@@ -78479,8 +79117,10 @@ function formatQuotaBlock(q, now = new Date) {
|
|
|
78479
79117
|
const lines = [];
|
|
78480
79118
|
lines.push("**Claude plan quota**");
|
|
78481
79119
|
lines.push("");
|
|
78482
|
-
|
|
78483
|
-
|
|
79120
|
+
const fiveHour = q.fiveHourUtilPresent === false ? "no data" : `\`${Math.round(q.fiveHourUtilizationPct)}%\``;
|
|
79121
|
+
const sevenDay = q.sevenDayUtilPresent === false ? "no data" : `\`${Math.round(q.sevenDayUtilizationPct)}%\``;
|
|
79122
|
+
lines.push(`**5h window** ${fiveHour} \u00b7 \`${formatResetRelative2(q.fiveHourResetAt, now)}\``);
|
|
79123
|
+
lines.push(`**7d window** ${sevenDay} \u00b7 \`${formatResetRelative2(q.sevenDayResetAt, now)}\``);
|
|
78484
79124
|
if (q.representativeClaim) {
|
|
78485
79125
|
lines.push("");
|
|
78486
79126
|
lines.push(`_Binding window: ${q.representativeClaim.replace(/_/g, " ")}_`);
|
|
@@ -79172,6 +79812,100 @@ function classifyModelSwitchConfirmation(input) {
|
|
|
79172
79812
|
}
|
|
79173
79813
|
return { kind: "default", launched: revertedTo };
|
|
79174
79814
|
}
|
|
79815
|
+
function formatModelRelaunchDiagLog(input) {
|
|
79816
|
+
const { agent, launched, configured, confirmation, isApplyBoot } = input;
|
|
79817
|
+
const L = launched || "(none)";
|
|
79818
|
+
if (confirmation == null) {
|
|
79819
|
+
return "telegram gateway: gw /model relaunch applied agent=" + agent + " launched=" + L + " configured=" + configured + " override=" + (isApplyBoot ? "set" : "cleared") + `
|
|
79820
|
+
`;
|
|
79821
|
+
}
|
|
79822
|
+
if (confirmation.kind === "not-applied") {
|
|
79823
|
+
return "telegram gateway: gw /model relaunch NOT-APPLIED agent=" + agent + " target=" + confirmation.target + " launched=" + L + " configured=" + configured + " revertedTo=" + confirmation.revertedTo + `
|
|
79824
|
+
`;
|
|
79825
|
+
}
|
|
79826
|
+
if (confirmation.kind === "applied") {
|
|
79827
|
+
return "telegram gateway: gw /model relaunch applied agent=" + agent + " launched=" + L + " configured=" + configured + ` override=set outcome=applied
|
|
79828
|
+
`;
|
|
79829
|
+
}
|
|
79830
|
+
return "telegram gateway: gw /model relaunch applied agent=" + agent + " launched=" + L + " configured=" + configured + ` override=cleared outcome=default
|
|
79831
|
+
`;
|
|
79832
|
+
}
|
|
79833
|
+
function formatModelSwitchConfirmationBody(confirmation) {
|
|
79834
|
+
if (confirmation.kind === "applied") {
|
|
79835
|
+
return "\u2705 Now running `" + confirmation.launched + "` \u2014 session-only, reverts to the configured model on the next restart. Fresh session; memory and the handoff briefing carry the context.";
|
|
79836
|
+
}
|
|
79837
|
+
if (confirmation.kind === "not-applied") {
|
|
79838
|
+
return "\u26a0\ufe0f Your switch to `" + confirmation.target + "` didn't apply \u2014 the agent reverted to `" + confirmation.revertedTo + "` (the apply-boot didn't complete). Re-issue `/model " + confirmation.target + "` to try again.";
|
|
79839
|
+
}
|
|
79840
|
+
return "\u2705 Now running `" + confirmation.launched + "` (the configured default) \u2014 fresh session; memory and the handoff briefing carry the context.";
|
|
79841
|
+
}
|
|
79842
|
+
function formatModelRelaunchSuppressNotAppliedLog(input) {
|
|
79843
|
+
return "telegram gateway: gw /model relaunch NOT-APPLIED \u2014 suppressing not-applied confirmation (a .session-model-alert is present and will be relayed) agent=" + input.agent + " target=" + input.target + `
|
|
79844
|
+
`;
|
|
79845
|
+
}
|
|
79846
|
+
function resolveModelSwitchBootNotice(input) {
|
|
79847
|
+
const { agent, confirmation, hasSessionModelAlert } = input;
|
|
79848
|
+
if (confirmation.kind === "not-applied" && hasSessionModelAlert) {
|
|
79849
|
+
return {
|
|
79850
|
+
kind: "suppress",
|
|
79851
|
+
log: formatModelRelaunchSuppressNotAppliedLog({ agent, target: confirmation.target })
|
|
79852
|
+
};
|
|
79853
|
+
}
|
|
79854
|
+
return { kind: "card", body: formatModelSwitchConfirmationBody(confirmation) };
|
|
79855
|
+
}
|
|
79856
|
+
function servedModelMatchesRequested(requested, served) {
|
|
79857
|
+
const req = requested.trim().toLowerCase();
|
|
79858
|
+
const srv = served.trim().toLowerCase();
|
|
79859
|
+
if (!srv.startsWith("claude-"))
|
|
79860
|
+
return true;
|
|
79861
|
+
if (MODEL_ALIASES2.includes(req)) {
|
|
79862
|
+
if (req === "default")
|
|
79863
|
+
return true;
|
|
79864
|
+
if (modelFamilyToken(srv) === req)
|
|
79865
|
+
return true;
|
|
79866
|
+
return srv.slice("claude-".length).split("-").includes(req);
|
|
79867
|
+
}
|
|
79868
|
+
if (req.startsWith("claude-")) {
|
|
79869
|
+
return srv === req || srv.startsWith(req + "-");
|
|
79870
|
+
}
|
|
79871
|
+
return true;
|
|
79872
|
+
}
|
|
79873
|
+
function formatServedModelDivergenceLog(input) {
|
|
79874
|
+
return "telegram gateway: gw /model served-model DIVERGENCE agent=" + input.agent + " requested=" + input.requested + " served=" + input.served + ` (--fallback-model substituted: requested id invalid/unknown OR model transiently unavailable)
|
|
79875
|
+
`;
|
|
79876
|
+
}
|
|
79877
|
+
function formatServedModelDivergenceCard(input) {
|
|
79878
|
+
return "\u26a0\ufe0f The first reply was served by `" + input.served + "`, not the requested `" + input.requested + "` \u2014 claude substituted the fallback model. Either the requested id is invalid/unknown, or the model was temporarily unavailable for that call (a transient substitution self-corrects on later replies). If it persists, re-issue `/model <valid id>` or `/model default`. `/status` always shows the model actually serving calls.";
|
|
79879
|
+
}
|
|
79880
|
+
function sendModelBootCard(deps, chat, body, failLabel) {
|
|
79881
|
+
deps.sendCard(chat.chatId, body, {
|
|
79882
|
+
parse_mode: "Markdown",
|
|
79883
|
+
...chat.threadId != null ? { message_thread_id: chat.threadId } : {}
|
|
79884
|
+
}).catch((err) => deps.log(`telegram gateway: ${failLabel} send failed: ${err?.message ?? String(err)}
|
|
79885
|
+
`));
|
|
79886
|
+
}
|
|
79887
|
+
function buildServedModelDivergenceHandler(deps) {
|
|
79888
|
+
return (d) => {
|
|
79889
|
+
deps.log(formatServedModelDivergenceLog({ agent: deps.agent, requested: d.requested, served: d.served }));
|
|
79890
|
+
if (deps.chat == null)
|
|
79891
|
+
return;
|
|
79892
|
+
sendModelBootCard(deps, deps.chat, formatServedModelDivergenceCard(d), "served-model divergence");
|
|
79893
|
+
};
|
|
79894
|
+
}
|
|
79895
|
+
function deliverModelSwitchBootNotice(deps) {
|
|
79896
|
+
if (deps.chat == null)
|
|
79897
|
+
return;
|
|
79898
|
+
const notice = resolveModelSwitchBootNotice({
|
|
79899
|
+
agent: deps.agent,
|
|
79900
|
+
confirmation: deps.confirmation,
|
|
79901
|
+
hasSessionModelAlert: deps.hasSessionModelAlert
|
|
79902
|
+
});
|
|
79903
|
+
if (notice.kind === "suppress") {
|
|
79904
|
+
deps.log(notice.log);
|
|
79905
|
+
return;
|
|
79906
|
+
}
|
|
79907
|
+
sendModelBootCard(deps, deps.chat, notice.body, "model-switch confirmation");
|
|
79908
|
+
}
|
|
79175
79909
|
function resolveStaleAwareBusy(input) {
|
|
79176
79910
|
const turnStale = input.currentTurnActive && input.turnAgeMs !== null && input.turnAgeMs > input.hardTtlMs;
|
|
79177
79911
|
const approvalLive = input.oldestPendingApprovalAgeMs !== null && input.oldestPendingApprovalAgeMs <= input.hardTtlMs;
|
|
@@ -79240,14 +79974,23 @@ function relaunchErrorReply2(deps, model, err) {
|
|
|
79240
79974
|
const msg = err instanceof Error ? err.message : String(err);
|
|
79241
79975
|
return { text: `\u274c Could not schedule model switch: ${deps.escapeHtml(msg)}`, html: true };
|
|
79242
79976
|
}
|
|
79977
|
+
function unvalidatedIdCaveat2(deps, model) {
|
|
79978
|
+
if (!model.trim().toLowerCase().startsWith("claude-"))
|
|
79979
|
+
return null;
|
|
79980
|
+
return `_\`${deps.escapeHtml(model)}\` can't be validated before launch \u2014 if it isn't a real Claude model id, claude will silently serve the configured fallback model instead. I check the first reply and will warn if that happens._`;
|
|
79981
|
+
}
|
|
79243
79982
|
async function scheduleRelaunchReply2(deps, model, reason) {
|
|
79244
79983
|
try {
|
|
79245
79984
|
await deps.scheduleModelRelaunch(model, reason);
|
|
79246
79985
|
} catch (err) {
|
|
79247
79986
|
return relaunchErrorReply2(deps, model, err);
|
|
79248
79987
|
}
|
|
79249
|
-
|
|
79250
|
-
|
|
79988
|
+
const caveat = unvalidatedIdCaveat2(deps, model);
|
|
79989
|
+
return {
|
|
79990
|
+
text: [switchingLine2(deps, model), ...caveat ? [caveat] : [], PERSIST_NOTE3].join(`
|
|
79991
|
+
`),
|
|
79992
|
+
html: true
|
|
79993
|
+
};
|
|
79251
79994
|
}
|
|
79252
79995
|
async function scheduleDefaultRelaunchReply2(deps, reason) {
|
|
79253
79996
|
try {
|
|
@@ -80073,7 +80816,7 @@ var HINDSIGHT_HEALTHCHECK_PY = 'import urllib.request,sys; sys.exit(0 if urllib.
|
|
|
80073
80816
|
var HINDSIGHT_HEALTHCHECK_CMD = `python3 -c '${HINDSIGHT_HEALTHCHECK_PY}'`;
|
|
80074
80817
|
|
|
80075
80818
|
// ../src/memory/hindsight.ts
|
|
80076
|
-
var DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise.";
|
|
80819
|
+
var DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise, " + "including in-flight workflow/process narration (a sub-task started, " + "paused, or is still running) \u2014 only retain the outcome once a task " + "actually completes or a decision is made.";
|
|
80077
80820
|
var PROFILE_MEMORY_DEFAULTS = {
|
|
80078
80821
|
"health-coach": {
|
|
80079
80822
|
disposition: { skepticism: 2, literalism: 2, empathy: 5 },
|
|
@@ -84201,6 +84944,17 @@ function withStoreLock(path2, fn) {
|
|
|
84201
84944
|
}));
|
|
84202
84945
|
return run3;
|
|
84203
84946
|
}
|
|
84947
|
+
var pinReconcileTails2 = new Map;
|
|
84948
|
+
function withPinReconcileLock(pinKey, fn) {
|
|
84949
|
+
const prev = pinReconcileTails2.get(pinKey) ?? Promise.resolve();
|
|
84950
|
+
const run3 = prev.then(fn, fn);
|
|
84951
|
+
pinReconcileTails2.set(pinKey, run3.then(() => {
|
|
84952
|
+
return;
|
|
84953
|
+
}, () => {
|
|
84954
|
+
return;
|
|
84955
|
+
}));
|
|
84956
|
+
return run3;
|
|
84957
|
+
}
|
|
84204
84958
|
function applyStatusPinRow(path2, fs2, pinKey, row, log) {
|
|
84205
84959
|
const current = loadStatusPins(path2, fs2);
|
|
84206
84960
|
const others = current.filter((p) => p.pinKey !== pinKey);
|
|
@@ -84227,7 +84981,11 @@ function reconcileAndPersistStatusPin(args) {
|
|
|
84227
84981
|
return next2;
|
|
84228
84982
|
}
|
|
84229
84983
|
const next = await args.applyPin();
|
|
84230
|
-
|
|
84984
|
+
if (next == null) {
|
|
84985
|
+
applyStatusPinRow(path2, fs2, pinKey, null, log);
|
|
84986
|
+
} else {
|
|
84987
|
+
applyStatusPinRow(path2, fs2, pinKey, { pinKey, chatId, messageId: next.messageId }, log);
|
|
84988
|
+
}
|
|
84231
84989
|
return next;
|
|
84232
84990
|
});
|
|
84233
84991
|
}
|
|
@@ -92377,10 +93135,10 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
92377
93135
|
}
|
|
92378
93136
|
|
|
92379
93137
|
// ../src/build-info.ts
|
|
92380
|
-
var VERSION = "0.19.
|
|
92381
|
-
var COMMIT_SHA = "
|
|
92382
|
-
var COMMIT_DATE = "2026-07-
|
|
92383
|
-
var LATEST_PR =
|
|
93138
|
+
var VERSION = "0.19.3";
|
|
93139
|
+
var COMMIT_SHA = "41896be4";
|
|
93140
|
+
var COMMIT_DATE = "2026-07-20T10:37:39+10:00";
|
|
93141
|
+
var LATEST_PR = 3456;
|
|
92384
93142
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
92385
93143
|
|
|
92386
93144
|
// gateway/boot-version.ts
|
|
@@ -95198,7 +95956,7 @@ var progressUpdateLastSent = new Map;
|
|
|
95198
95956
|
var progressUpdateTurnCount = new Map;
|
|
95199
95957
|
var currentTurn = null;
|
|
95200
95958
|
var currentTurnMap = new CurrentTurnMap;
|
|
95201
|
-
var sessionModelSource = createSessionModelSource();
|
|
95959
|
+
var sessionModelSource = createSessionModelSource({ servedMatchesRequested: servedModelMatchesRequested });
|
|
95202
95960
|
var lastActiveTurnChatId;
|
|
95203
95961
|
function setCurrentTurn(turn, key) {
|
|
95204
95962
|
currentTurnMap.set(turn, key);
|
|
@@ -96990,9 +97748,9 @@ var pendingStateReaper = isGatewayMain ? setInterval(() => {
|
|
|
96990
97748
|
if (now - v > 60000)
|
|
96991
97749
|
lastAuthRefreshAtMs.delete(k);
|
|
96992
97750
|
}
|
|
96993
|
-
for (const [k, v] of
|
|
97751
|
+
for (const [k, v] of pendingAuthRmFlows2) {
|
|
96994
97752
|
if (now >= v.expiresAt)
|
|
96995
|
-
|
|
97753
|
+
pendingAuthRmFlows2.delete(k);
|
|
96996
97754
|
}
|
|
96997
97755
|
pendingVaultOps.sweep(now);
|
|
96998
97756
|
sweepPermissionTtl({
|
|
@@ -97645,7 +98403,7 @@ var midSessionCardReaper = isGatewayMain ? setInterval(() => {
|
|
|
97645
98403
|
midSessionCardReaper?.unref();
|
|
97646
98404
|
async function reconcileStatusPin(pinKey, chatId, desired) {
|
|
97647
98405
|
try {
|
|
97648
|
-
await reconcileStatusPinInner(pinKey, chatId, desired);
|
|
98406
|
+
await withPinReconcileLock(pinKey, () => reconcileStatusPinInner(pinKey, chatId, desired));
|
|
97649
98407
|
} catch (err) {
|
|
97650
98408
|
const msg = err instanceof Error ? err.message : String(err);
|
|
97651
98409
|
process.stderr.write(`telegram gateway: status-pin reconcile absorbed error (key=${pinKey} chat=${chatId}): ${msg}
|
|
@@ -100546,6 +101304,10 @@ function isAuthorizedSender(ctx) {
|
|
|
100546
101304
|
}
|
|
100547
101305
|
return false;
|
|
100548
101306
|
}
|
|
101307
|
+
function shouldMaskAccountLabels(ctx) {
|
|
101308
|
+
const groupAllowFrom = ctx.chat?.type === "group" || ctx.chat?.type === "supergroup" ? loadAccess().groups[String(ctx.chat.id)]?.allowFrom : undefined;
|
|
101309
|
+
return shouldMaskUsageLabels(ctx.chat?.type, groupAllowFrom);
|
|
101310
|
+
}
|
|
100549
101311
|
var __inboundRouterTestSeam = {
|
|
100550
101312
|
activeStatusReactions,
|
|
100551
101313
|
activeTurnStartedAt,
|
|
@@ -103832,7 +104594,7 @@ The gateway will restart as part of the recreate step; watch for the post-restar
|
|
|
103832
104594
|
const me = cfg?.agents?.[getMyAgentName()];
|
|
103833
104595
|
isAdmin2 = me?.admin === true || me?.root === true;
|
|
103834
104596
|
} catch {}
|
|
103835
|
-
if (!
|
|
104597
|
+
if (!isAuthAdmin2({ isAdmin: isAdmin2 })) {
|
|
103836
104598
|
await switchroomReply(ctx, `**Not authorized.** \`/connect\` requires this agent to have \`admin: true\` in switchroom.yaml.`, { html: true });
|
|
103837
104599
|
return;
|
|
103838
104600
|
}
|
|
@@ -103923,52 +104685,19 @@ ${appNote}`), {
|
|
|
103923
104685
|
} catch {}
|
|
103924
104686
|
const chatId = String(ctx.chat?.id ?? "");
|
|
103925
104687
|
if (parsed.kind === "add" || parsed.kind === "cancel") {
|
|
103926
|
-
|
|
103927
|
-
|
|
103928
|
-
|
|
103929
|
-
|
|
103930
|
-
|
|
103931
|
-
|
|
103932
|
-
|
|
103933
|
-
|
|
103934
|
-
|
|
103935
|
-
await switchroomReply(ctx, "_No pending `/auth add` flow in this chat._", { html: true });
|
|
103936
|
-
return;
|
|
103937
|
-
}
|
|
103938
|
-
cancelAccountAuthSession(existing);
|
|
103939
|
-
pendingAuthAddFlows.delete(authAddKey);
|
|
103940
|
-
await switchroomReply(ctx, "Cancelled.", { html: true });
|
|
103941
|
-
return;
|
|
103942
|
-
}
|
|
103943
|
-
if (pendingAuthAddFlows.has(authAddKey)) {
|
|
103944
|
-
await switchroomReply(ctx, "_An `/auth add` flow is already in progress for this chat. Finish the paste, or send `/auth cancel` to abort._", { html: true });
|
|
103945
|
-
return;
|
|
103946
|
-
}
|
|
103947
|
-
try {
|
|
103948
|
-
const { loginUrl, scratchDir, tmuxSocket, tmuxSession } = await startAccountAuthSession(parsed.label);
|
|
103949
|
-
pendingAuthAddFlows.set(authAddKey, {
|
|
103950
|
-
label: parsed.label,
|
|
103951
|
-
scratchDir,
|
|
103952
|
-
tmuxSocket,
|
|
103953
|
-
tmuxSession,
|
|
103954
|
-
startedAt: Date.now()
|
|
103955
|
-
});
|
|
103956
|
-
await switchroomReply(ctx, `**Adding account** \`${parsed.label}\`
|
|
103957
|
-
|
|
103958
|
-
1. Open this URL on your phone:
|
|
103959
|
-
${loginUrl}
|
|
103960
|
-
|
|
103961
|
-
2. Log into Anthropic, copy the code Claude shows.
|
|
103962
|
-
3. Paste it back here.
|
|
103963
|
-
|
|
103964
|
-
Send \`/auth cancel\` to abort.`, { html: true });
|
|
103965
|
-
} catch (err) {
|
|
103966
|
-
await switchroomReply(ctx, `**/auth add failed:** ${escapeHtmlForTg2(err?.message ?? String(err))}`, { html: true });
|
|
103967
|
-
}
|
|
104688
|
+
await handleAuthAddOrCancel({
|
|
104689
|
+
parsed,
|
|
104690
|
+
isAdmin: isAdmin2,
|
|
104691
|
+
currentAgent,
|
|
104692
|
+
chatId,
|
|
104693
|
+
threadId: ctx.message?.message_thread_id ?? null,
|
|
104694
|
+
reply: (text6) => switchroomReply(ctx, text6, { html: true }),
|
|
104695
|
+
escapeHtml: escapeHtmlForTg2
|
|
104696
|
+
});
|
|
103968
104697
|
return;
|
|
103969
104698
|
}
|
|
103970
104699
|
if (parsed.kind === "provider-add" || parsed.kind === "provider-cancel") {
|
|
103971
|
-
if (!
|
|
104700
|
+
if (!isAuthAdmin2({ isAdmin: isAdmin2 })) {
|
|
103972
104701
|
await switchroomReply(ctx, `**Not authorized.** \`/auth ${parsed.provider}\` is admin-only.
|
|
103973
104702
|
Set \`admin: true\` on this agent in switchroom.yaml to unlock.`, { html: true });
|
|
103974
104703
|
return;
|
|
@@ -104403,7 +105132,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
104403
105132
|
bot2.command("usage", async (ctx) => {
|
|
104404
105133
|
if (!isAuthorizedSender(ctx))
|
|
104405
105134
|
return;
|
|
104406
|
-
const demo = hasDemoFlag(getCommandArgs(ctx));
|
|
105135
|
+
const demo = hasDemoFlag(getCommandArgs(ctx)) || shouldMaskAccountLabels(ctx);
|
|
104407
105136
|
const currentAgent = getMyAgentName();
|
|
104408
105137
|
try {
|
|
104409
105138
|
const client3 = await getAuthBrokerClient2(currentAgent);
|
|
@@ -104416,11 +105145,14 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
104416
105145
|
const { buildSnapshotsFromState: buildSnapshotsFromState4, buildSnapshotKeyboard: buildSnapshotKeyboard3 } = await Promise.resolve().then(() => (init_auth_snapshot_format2(), exports_auth_snapshot_format2));
|
|
104417
105146
|
const { renderUsageCard: renderUsageCard2 } = await Promise.resolve().then(() => (init_quota_bar_format(), exports_quota_bar_format));
|
|
104418
105147
|
const snapshots = buildSnapshotsFromState4(state7, quotas);
|
|
105148
|
+
const { fetchExternalSpendSummary: fetchExternalSpendSummary2 } = await Promise.resolve().then(() => (init_external_spend3(), exports_external_spend));
|
|
105149
|
+
const externalSpend = await fetchExternalSpendSummary2(renderNow).catch(() => null);
|
|
104419
105150
|
const exhaustedByLabel = new Map(state7.accounts.map((a) => [a.label, a.exhausted]));
|
|
104420
105151
|
const text5 = renderUsageCard2(snapshots, exhaustedByLabel, {
|
|
104421
105152
|
now: renderNow,
|
|
104422
105153
|
demo,
|
|
104423
|
-
|
|
105154
|
+
externalSpend,
|
|
105155
|
+
...deriveUsageFooterFreshness2(probeResp.results, staleCachedAtMs, renderNow.getTime())
|
|
104424
105156
|
});
|
|
104425
105157
|
let kbRows = buildSnapshotKeyboard3(snapshots, { now: new Date, demo });
|
|
104426
105158
|
if (ctx.chat?.type !== "private") {
|
|
@@ -105749,28 +106481,34 @@ async function startGateway() {
|
|
|
105749
106481
|
return resolveMainModel(raw ?? undefined);
|
|
105750
106482
|
})();
|
|
105751
106483
|
const isApplyBoot = launched.length > 0 && launched !== configured;
|
|
105752
|
-
sessionModelSource.setOverride(isApplyBoot ? launched : null);
|
|
105753
|
-
|
|
105754
|
-
|
|
105755
|
-
|
|
105756
|
-
|
|
105757
|
-
|
|
105758
|
-
|
|
105759
|
-
|
|
105760
|
-
|
|
106484
|
+
sessionModelSource.setOverride(isApplyBoot ? launched : null, { verify: true });
|
|
106485
|
+
const modelBootCardDeps = {
|
|
106486
|
+
agent: getMyAgentName(),
|
|
106487
|
+
chat: modelSwitchMarkerChat,
|
|
106488
|
+
log: (line) => process.stderr.write(line),
|
|
106489
|
+
sendCard: (chatId, body, opts) => lockedBot.api.sendMessage(chatId, body, opts)
|
|
106490
|
+
};
|
|
106491
|
+
if (isApplyBoot) {
|
|
106492
|
+
sessionModelSource.setDivergenceHandler(buildServedModelDivergenceHandler(modelBootCardDeps));
|
|
106493
|
+
}
|
|
106494
|
+
const confirmation = modelSwitchReason != null ? classifyModelSwitchConfirmation({
|
|
106495
|
+
reason: modelSwitchReason,
|
|
106496
|
+
launched,
|
|
106497
|
+
configured
|
|
106498
|
+
}) : null;
|
|
106499
|
+
process.stderr.write(formatModelRelaunchDiagLog({
|
|
106500
|
+
agent: getMyAgentName(),
|
|
106501
|
+
launched,
|
|
106502
|
+
configured,
|
|
106503
|
+
confirmation,
|
|
106504
|
+
isApplyBoot
|
|
106505
|
+
}));
|
|
106506
|
+
if (confirmation != null) {
|
|
106507
|
+
deliverModelSwitchBootNotice({
|
|
106508
|
+
...modelBootCardDeps,
|
|
106509
|
+
confirmation,
|
|
106510
|
+
hasSessionModelAlert: existsSync54(join59(smAgentDir, ".session-model-alert"))
|
|
105761
106511
|
});
|
|
105762
|
-
const hasSessionModelAlert = existsSync54(join59(smAgentDir, ".session-model-alert"));
|
|
105763
|
-
if (confirmation.kind === "not-applied" && hasSessionModelAlert) {
|
|
105764
|
-
process.stderr.write(`telegram gateway: gw /model relaunch applied \u2014 suppressing not-applied confirmation (a .session-model-alert is present and will be relayed) agent=${getMyAgentName()} target=${confirmation.target}
|
|
105765
|
-
`);
|
|
105766
|
-
} else {
|
|
105767
|
-
const body = confirmation.kind === "applied" ? `\u2705 Now running \`${confirmation.launched}\` \u2014 session-only, reverts to the configured model on the next restart. Fresh session; memory and the handoff briefing carry the context.` : confirmation.kind === "not-applied" ? `\u26A0\uFE0F Your switch to \`${confirmation.target}\` didn't apply \u2014 the agent reverted to \`${confirmation.revertedTo}\` (the apply-boot didn't complete). Re-issue \`/model ${confirmation.target}\` to try again.` : `\u2705 Now running \`${confirmation.launched}\` (the configured default) \u2014 fresh session; memory and the handoff briefing carry the context.`;
|
|
105768
|
-
lockedBot.api.sendMessage(chat.chatId, body, {
|
|
105769
|
-
parse_mode: "Markdown",
|
|
105770
|
-
...chat.threadId != null ? { message_thread_id: chat.threadId } : {}
|
|
105771
|
-
}).catch((err) => process.stderr.write(`telegram gateway: model-switch confirmation send failed: ${err?.message ?? String(err)}
|
|
105772
|
-
`));
|
|
105773
|
-
}
|
|
105774
106512
|
}
|
|
105775
106513
|
} catch {}
|
|
105776
106514
|
}
|