switchroom 0.18.3 → 0.18.6
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 +2 -1
- package/dist/auth-broker/index.js +2 -1
- package/dist/cli/notion-write-pretool.mjs +2 -1
- package/dist/cli/switchroom.js +119 -74
- package/dist/host-control/main.js +3 -2
- package/dist/vault/approvals/kernel-server.js +2 -1
- package/dist/vault/broker/server.js +37 -8
- package/package.json +1 -1
- package/skills/switchroom-release/SKILL.md +78 -0
- package/telegram-plugin/auth-snapshot-format.ts +15 -1
- package/telegram-plugin/dist/gateway/gateway.js +922 -459
- package/telegram-plugin/gateway/gateway.ts +260 -21
- package/telegram-plugin/gateway/resolve-person.ts +304 -0
- package/telegram-plugin/gateway/unhandled-rejection-policy.ts +21 -1
- package/telegram-plugin/hooks/silent-end-scan.mjs +164 -40
- package/telegram-plugin/operator-events.ts +21 -0
- package/telegram-plugin/pending-work-progress.ts +42 -7
- package/telegram-plugin/quota-bar-format.ts +360 -0
- package/telegram-plugin/subagent-watcher.ts +27 -9
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +21 -0
- package/telegram-plugin/tests/gateway-boot-marker-clear.test.ts +3 -3
- package/telegram-plugin/tests/operator-events.test.ts +16 -0
- package/telegram-plugin/tests/pending-work-progress.test.ts +116 -3
- package/telegram-plugin/tests/quota-bar-format.test.ts +444 -0
- package/telegram-plugin/tests/resolve-person.test.ts +290 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-integration.test.ts +53 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-scan.test.ts +138 -0
- package/telegram-plugin/tests/subagent-watcher.test.ts +61 -0
- package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +19 -0
- package/telegram-plugin/tests/worker-activity-feed.test.ts +97 -0
- package/telegram-plugin/worker-activity-feed.ts +220 -15
- package/profiles/default/CLAUDE.md +0 -116
- package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/vendor/hindsight-memory/scripts/__pycache__/directive_verify.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/drain_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/recall.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/retain.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/session_end.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/bank.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/client.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/config.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/content.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/daemon.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/directives.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/gateway_ipc.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/llm.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/switchroom_envelope.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/__init__.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_config_client_casts.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_config_client_casts.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_capture_nudge.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_capture_nudge.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_verify.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_verify.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directives.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directives.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_gateway_ipc.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_gateway_ipc.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_context_slice.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_context_slice.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_integration.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_integration.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_tag_filters.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_tag_filters.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_topic_filter.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_topic_filter.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_trivial_skip.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_trivial_skip.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_retain_window.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_retain_window.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_sender_routing.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_sender_routing.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_switchroom_envelope.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/conftest.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_bank.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_bank.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_client.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_client.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_config.cpython-313-pytest-9.0.3.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_config.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_config.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_content.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_content.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_drain_pending.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_drain_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_hooks.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_hooks.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_manifest.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_manifest.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_pending.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_recall_exit_codes.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_recall_exit_codes.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_session_end_pending.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_session_end_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_state.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_state.cpython-313.pyc +0 -0
|
@@ -12658,6 +12658,445 @@ var init_demo_mask = __esm(() => {
|
|
|
12658
12658
|
vaultKeyCache = new Map;
|
|
12659
12659
|
});
|
|
12660
12660
|
|
|
12661
|
+
// auth-snapshot-format.ts
|
|
12662
|
+
function classifyHealth(snap, now = new Date) {
|
|
12663
|
+
if (!snap.quota)
|
|
12664
|
+
return "unknown";
|
|
12665
|
+
const q = snap.quota;
|
|
12666
|
+
if (isProbeThin(q))
|
|
12667
|
+
return "unknown";
|
|
12668
|
+
const norm = refillNormalizedUtils(q, now);
|
|
12669
|
+
const max = Math.max(norm.fiveHourUtilizationPct, norm.sevenDayUtilizationPct);
|
|
12670
|
+
if (max >= 99.5)
|
|
12671
|
+
return "blocked";
|
|
12672
|
+
if (max >= THROTTLING_THRESHOLD_PCT)
|
|
12673
|
+
return "throttling";
|
|
12674
|
+
return "healthy";
|
|
12675
|
+
}
|
|
12676
|
+
function blockedReason(snap, now = new Date) {
|
|
12677
|
+
if (classifyHealth(snap, now) !== "blocked")
|
|
12678
|
+
return null;
|
|
12679
|
+
return "quota-exhausted";
|
|
12680
|
+
}
|
|
12681
|
+
function bindingWindow(q) {
|
|
12682
|
+
if (q.representativeClaim === "seven_day")
|
|
12683
|
+
return "7d";
|
|
12684
|
+
if (q.representativeClaim === "five_hour")
|
|
12685
|
+
return "5h";
|
|
12686
|
+
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7d" : "5h";
|
|
12687
|
+
}
|
|
12688
|
+
function formatRelative(target, now = new Date) {
|
|
12689
|
+
if (!target)
|
|
12690
|
+
return "\u2014";
|
|
12691
|
+
const deltaMs = target.getTime() - now.getTime();
|
|
12692
|
+
if (deltaMs <= 0)
|
|
12693
|
+
return "now";
|
|
12694
|
+
const totalMin = Math.round(deltaMs / 60000);
|
|
12695
|
+
if (totalMin < 60)
|
|
12696
|
+
return `${totalMin}m`;
|
|
12697
|
+
const h = Math.floor(totalMin / 60);
|
|
12698
|
+
const m = totalMin % 60;
|
|
12699
|
+
if (h < 24)
|
|
12700
|
+
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
12701
|
+
const d = Math.floor(h / 24);
|
|
12702
|
+
const rh = h % 24;
|
|
12703
|
+
return rh > 0 ? `${d}d ${rh}h` : `${d}d`;
|
|
12704
|
+
}
|
|
12705
|
+
function formatAbsolute(target, tz = "UTC") {
|
|
12706
|
+
if (!target)
|
|
12707
|
+
return "\u2014";
|
|
12708
|
+
return target.toLocaleString("en-US", {
|
|
12709
|
+
timeZone: tz,
|
|
12710
|
+
weekday: "short",
|
|
12711
|
+
hour: "numeric",
|
|
12712
|
+
minute: "2-digit",
|
|
12713
|
+
hour12: true
|
|
12714
|
+
});
|
|
12715
|
+
}
|
|
12716
|
+
function formatStatusTime(target, now = new Date, tz = "UTC") {
|
|
12717
|
+
if (!target)
|
|
12718
|
+
return "\u2014";
|
|
12719
|
+
const dayFmt = new Intl.DateTimeFormat("en-CA", {
|
|
12720
|
+
timeZone: tz,
|
|
12721
|
+
year: "numeric",
|
|
12722
|
+
month: "2-digit",
|
|
12723
|
+
day: "2-digit"
|
|
12724
|
+
});
|
|
12725
|
+
const timeFmt = new Intl.DateTimeFormat("en-US", {
|
|
12726
|
+
timeZone: tz,
|
|
12727
|
+
hour: "numeric",
|
|
12728
|
+
minute: "2-digit",
|
|
12729
|
+
hour12: true
|
|
12730
|
+
});
|
|
12731
|
+
const timeStr = timeFmt.format(target);
|
|
12732
|
+
if (dayFmt.format(target) === dayFmt.format(now)) {
|
|
12733
|
+
return timeStr;
|
|
12734
|
+
}
|
|
12735
|
+
const withinWeek = target.getTime() - now.getTime() < 7 * 24 * 60 * 60 * 1000;
|
|
12736
|
+
const dateFmt = new Intl.DateTimeFormat("en-US", {
|
|
12737
|
+
timeZone: tz,
|
|
12738
|
+
weekday: "short",
|
|
12739
|
+
...withinWeek ? {} : { day: "numeric", month: "short" }
|
|
12740
|
+
});
|
|
12741
|
+
return `${dateFmt.format(target)} ${timeStr}`;
|
|
12742
|
+
}
|
|
12743
|
+
function fmtPct(pct) {
|
|
12744
|
+
return `${Math.min(100, Math.round(pct))}%`;
|
|
12745
|
+
}
|
|
12746
|
+
function displayLabel(label, opts) {
|
|
12747
|
+
return opts.demo ? maskEmail(label) : label;
|
|
12748
|
+
}
|
|
12749
|
+
function renderAccountRow(snap, opts) {
|
|
12750
|
+
const now = opts.now ?? new Date;
|
|
12751
|
+
const tz = opts.tz ?? "UTC";
|
|
12752
|
+
const lines = [];
|
|
12753
|
+
const marker = snap.isActive ? "\u25cf " : "";
|
|
12754
|
+
const label = displayLabel(snap.label, opts);
|
|
12755
|
+
if (!snap.quota) {
|
|
12756
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota probe failed_`);
|
|
12757
|
+
if (snap.quotaError) {
|
|
12758
|
+
lines.push(` _${escapeMarkdown(snap.quotaError)}_`);
|
|
12759
|
+
}
|
|
12760
|
+
return lines;
|
|
12761
|
+
}
|
|
12762
|
+
const q = snap.quota;
|
|
12763
|
+
if (isProbeThin(q)) {
|
|
12764
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota unknown (thin probe)_`);
|
|
12765
|
+
return lines;
|
|
12766
|
+
}
|
|
12767
|
+
const norm = refillNormalizedUtils(q, now);
|
|
12768
|
+
const fiveStr = fmtPct(norm.fiveHourUtilizationPct);
|
|
12769
|
+
const sevenStr = fmtPct(norm.sevenDayUtilizationPct);
|
|
12770
|
+
lines.push(`${marker}\`${codeSpanSafe(label)}\` ${fiveStr} / ${sevenStr}`);
|
|
12771
|
+
const health = classifyHealth(snap, now);
|
|
12772
|
+
if (health === "blocked") {
|
|
12773
|
+
const win = bindingWindow(q);
|
|
12774
|
+
const reset2 = win === "5h" ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
12775
|
+
const winLabel = win === "5h" ? "5-hour" : "7-day";
|
|
12776
|
+
lines.push(reset2 ? ` _quota exhausted \u2014 back ${formatAbsolute(reset2, tz)} (\`in ${formatRelative(reset2, now)}\`, ${winLabel} cap)_` : ` _quota exhausted \u2014 ${winLabel} cap, reset time unknown_`);
|
|
12777
|
+
return lines;
|
|
12778
|
+
}
|
|
12779
|
+
const fiveResetIn = q.fiveHourResetAt ? q.fiveHourResetAt.getTime() - now.getTime() : Infinity;
|
|
12780
|
+
const sevenResetIn = q.sevenDayResetAt ? q.sevenDayResetAt.getTime() - now.getTime() : Infinity;
|
|
12781
|
+
const fiveFirst = fiveResetIn <= sevenResetIn;
|
|
12782
|
+
const fiveSeg = q.fiveHourResetAt ? `5h refills ${formatAbsolute(q.fiveHourResetAt, tz)} (\`in ${formatRelative(q.fiveHourResetAt, now)}\`)` : "5h refills \u2014";
|
|
12783
|
+
const sevenSeg = q.sevenDayResetAt ? `7d resets ${formatAbsolute(q.sevenDayResetAt, tz)} (\`in ${formatRelative(q.sevenDayResetAt, now)}\`)` : "7d resets \u2014";
|
|
12784
|
+
lines.push(` _${fiveFirst ? fiveSeg : sevenSeg}_`);
|
|
12785
|
+
lines.push(` _${fiveFirst ? sevenSeg : fiveSeg}_`);
|
|
12786
|
+
if (q.overageDisabledReason != null && OVERAGE_EXHAUSTED_REASONS.has(q.overageDisabledReason)) {
|
|
12787
|
+
lines.push(` _overage off (${escapeMarkdown(q.overageDisabledReason)}) \u2014 serving from quota_`);
|
|
12788
|
+
}
|
|
12789
|
+
return lines;
|
|
12790
|
+
}
|
|
12791
|
+
function formatAgeStamp(atMs, now = new Date) {
|
|
12792
|
+
const ageSec = Math.max(0, Math.round((now.getTime() - atMs) / 1000));
|
|
12793
|
+
return ageSec < 60 ? `${ageSec}s ago` : `${Math.round(ageSec / 60)}m ago`;
|
|
12794
|
+
}
|
|
12795
|
+
function tableCell(s) {
|
|
12796
|
+
return s.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
12797
|
+
}
|
|
12798
|
+
function pctCells(snap, now) {
|
|
12799
|
+
if (!snap.quota)
|
|
12800
|
+
return { five: "\u2014", seven: "\u2014" };
|
|
12801
|
+
if (isProbeThin(snap.quota))
|
|
12802
|
+
return { five: "?", seven: "?" };
|
|
12803
|
+
const norm = refillNormalizedUtils(snap.quota, now);
|
|
12804
|
+
return { five: fmtPct(norm.fiveHourUtilizationPct), seven: fmtPct(norm.sevenDayUtilizationPct) };
|
|
12805
|
+
}
|
|
12806
|
+
function windowResetCell(snap, now, tz, win) {
|
|
12807
|
+
if (!snap.quota) {
|
|
12808
|
+
return snap.quotaError ? `probe failed (${snap.quotaError})` : "\u2014";
|
|
12809
|
+
}
|
|
12810
|
+
if (isProbeThin(snap.quota))
|
|
12811
|
+
return "quota unknown";
|
|
12812
|
+
const reset2 = win === "5h" ? snap.quota.fiveHourResetAt : snap.quota.sevenDayResetAt;
|
|
12813
|
+
if (!reset2)
|
|
12814
|
+
return "\u2014";
|
|
12815
|
+
return `${formatStatusTime(reset2, now, tz)} (in ${formatRelative(reset2, now)})`;
|
|
12816
|
+
}
|
|
12817
|
+
function renderAuthSnapshotFormat2(snapshots, opts = {}) {
|
|
12818
|
+
const now = opts.now ?? new Date;
|
|
12819
|
+
const tz = opts.tz ?? "UTC";
|
|
12820
|
+
const lines = [];
|
|
12821
|
+
lines.push("\uD83D\uDD0B **Auth \u2014 fleet status**");
|
|
12822
|
+
const ordered = [...snapshots].sort((a, b) => {
|
|
12823
|
+
if (a.isActive !== b.isActive)
|
|
12824
|
+
return a.isActive ? -1 : 1;
|
|
12825
|
+
const r = TABLE_HEALTH_RANK[classifyHealth(a, now)] - TABLE_HEALTH_RANK[classifyHealth(b, now)];
|
|
12826
|
+
if (r !== 0)
|
|
12827
|
+
return r;
|
|
12828
|
+
return a.label.localeCompare(b.label);
|
|
12829
|
+
});
|
|
12830
|
+
if (ordered.length > 0) {
|
|
12831
|
+
lines.push("");
|
|
12832
|
+
lines.push("| State | Account | 5h | 5h resets | 7d | 7d resets |");
|
|
12833
|
+
lines.push("| --- | --- | --- | --- | --- | --- |");
|
|
12834
|
+
for (const s of ordered) {
|
|
12835
|
+
const emoji = HEALTH_EMOJI[classifyHealth(s, now)];
|
|
12836
|
+
const label = displayLabel(s.label, opts);
|
|
12837
|
+
const accountCell = `\`${codeSpanSafe(s.isActive ? `${label} (active)` : label)}\``;
|
|
12838
|
+
const { five, seven } = pctCells(s, now);
|
|
12839
|
+
const fiveReset = windowResetCell(s, now, tz, "5h");
|
|
12840
|
+
const sevenReset = windowResetCell(s, now, tz, "7d");
|
|
12841
|
+
lines.push(`| ${emoji} | ${tableCell(accountCell)} | ${five} | ${tableCell(fiveReset)} | ${seven} | ${tableCell(sevenReset)} |`);
|
|
12842
|
+
}
|
|
12843
|
+
}
|
|
12844
|
+
lines.push("");
|
|
12845
|
+
lines.push(`_${recommendation(snapshots, now, opts.demo ?? false)}_`);
|
|
12846
|
+
if (opts.staleCachedAtMs != null) {
|
|
12847
|
+
lines.push(`_\u26a0 cached ${formatAgeStamp(opts.staleCachedAtMs, now)}_`);
|
|
12848
|
+
} else if (opts.liveProbedAtMs != null) {
|
|
12849
|
+
lines.push(`_Live \u00b7 refreshed ${formatAgeStamp(opts.liveProbedAtMs, now)}_`);
|
|
12850
|
+
} else if (opts.probeFailed) {
|
|
12851
|
+
lines.push("_\u26a0 probe failed \u2014 no live data_");
|
|
12852
|
+
} else {
|
|
12853
|
+
lines.push("_Live_");
|
|
12854
|
+
}
|
|
12855
|
+
return lines.join(`
|
|
12856
|
+
`);
|
|
12857
|
+
}
|
|
12858
|
+
function recommendation(snapshots, now = new Date, demo = false) {
|
|
12859
|
+
const active = snapshots.find((s) => s.isActive);
|
|
12860
|
+
if (!active)
|
|
12861
|
+
return "No active account set.";
|
|
12862
|
+
const activeHealth = classifyHealth(active, now);
|
|
12863
|
+
const others = snapshots.filter((s) => !s.isActive);
|
|
12864
|
+
const healthyAlt = others.find((s) => classifyHealth(s, now) === "healthy");
|
|
12865
|
+
const lbl = (s) => demo ? maskEmail(s.label) : s.label;
|
|
12866
|
+
const activeLabel = lbl(active);
|
|
12867
|
+
if (activeHealth === "healthy") {
|
|
12868
|
+
return `Recommendation: stay on ${activeLabel}.`;
|
|
12869
|
+
}
|
|
12870
|
+
if (activeHealth === "throttling") {
|
|
12871
|
+
if (healthyAlt) {
|
|
12872
|
+
return `Recommendation: active ${activeLabel} is throttling. Switch to ${lbl(healthyAlt)} for headroom.`;
|
|
12873
|
+
}
|
|
12874
|
+
return `Recommendation: active ${activeLabel} is throttling; no healthy alternative \u2014 wait for refill.`;
|
|
12875
|
+
}
|
|
12876
|
+
if (activeHealth === "blocked") {
|
|
12877
|
+
if (healthyAlt) {
|
|
12878
|
+
return `Recommendation: active ${activeLabel} is BLOCKED \u2014 switch to ${lbl(healthyAlt)} now.`;
|
|
12879
|
+
}
|
|
12880
|
+
return summarizeNoHealthyAlt(snapshots, now, demo);
|
|
12881
|
+
}
|
|
12882
|
+
return `Active ${activeLabel}: quota probe failed; broker last_seen unknown.`;
|
|
12883
|
+
}
|
|
12884
|
+
function summarizeNoHealthyAlt(snapshots, now, demo = false) {
|
|
12885
|
+
const mask = (label) => demo ? maskEmail(label) : label;
|
|
12886
|
+
let throttlingLabel = null;
|
|
12887
|
+
let allTrulyBlocked = true;
|
|
12888
|
+
for (const s of snapshots) {
|
|
12889
|
+
const h = classifyHealth(s, now);
|
|
12890
|
+
if (h === "throttling") {
|
|
12891
|
+
if (!throttlingLabel)
|
|
12892
|
+
throttlingLabel = s.label;
|
|
12893
|
+
allTrulyBlocked = false;
|
|
12894
|
+
} else if (h === "healthy" || h === "unknown") {
|
|
12895
|
+
allTrulyBlocked = false;
|
|
12896
|
+
} else if (h === "blocked" && blockedReason(s, now) === "quota-exhausted") {
|
|
12897
|
+
if (s.quota) {
|
|
12898
|
+
const win = bindingWindow(s.quota);
|
|
12899
|
+
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
12900
|
+
if (at && at.getTime() > now.getTime())
|
|
12901
|
+
allTrulyBlocked = false;
|
|
12902
|
+
}
|
|
12903
|
+
}
|
|
12904
|
+
}
|
|
12905
|
+
const earliestRecovery = pickEarliestRecovery(snapshots, now);
|
|
12906
|
+
if (throttlingLabel) {
|
|
12907
|
+
const eta = earliestRecovery ? ` Soonest full refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.` : "";
|
|
12908
|
+
return `No fully-healthy account; ${mask(throttlingLabel)} is throttling but still usable.${eta}`;
|
|
12909
|
+
}
|
|
12910
|
+
if (!allTrulyBlocked) {
|
|
12911
|
+
if (earliestRecovery) {
|
|
12912
|
+
return `All accounts at capacity; soonest refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
12913
|
+
}
|
|
12914
|
+
return `All accounts at capacity \u2014 waiting on a window refill.`;
|
|
12915
|
+
}
|
|
12916
|
+
if (earliestRecovery) {
|
|
12917
|
+
return `All accounts blocked. Earliest recovery: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
12918
|
+
}
|
|
12919
|
+
return `All accounts blocked. Run /auth add to attach another subscription.`;
|
|
12920
|
+
}
|
|
12921
|
+
function pickEarliestRecovery(snapshots, now) {
|
|
12922
|
+
let best = null;
|
|
12923
|
+
for (const s of snapshots) {
|
|
12924
|
+
if (!s.quota)
|
|
12925
|
+
continue;
|
|
12926
|
+
if (isProbeThin(s.quota))
|
|
12927
|
+
continue;
|
|
12928
|
+
const win = bindingWindow(s.quota);
|
|
12929
|
+
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
12930
|
+
if (!at || at.getTime() <= now.getTime())
|
|
12931
|
+
continue;
|
|
12932
|
+
if (!best || at.getTime() < best.at.getTime()) {
|
|
12933
|
+
best = { label: s.label, at };
|
|
12934
|
+
}
|
|
12935
|
+
}
|
|
12936
|
+
return best;
|
|
12937
|
+
}
|
|
12938
|
+
function renderFallbackAnnouncement(input) {
|
|
12939
|
+
const now = input.now ?? new Date;
|
|
12940
|
+
const tz = input.tz ?? "UTC";
|
|
12941
|
+
const lines = [];
|
|
12942
|
+
const limitWord = input.oldQuota ? limitWordFor(input.oldQuota) : "quota";
|
|
12943
|
+
const headerLimit = limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
|
|
12944
|
+
if (!input.newLabel) {
|
|
12945
|
+
lines.push(`\uD83D\uDD34 **All accounts blocked \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
12946
|
+
lines.push("");
|
|
12947
|
+
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
12948
|
+
const fleet = input.fleetSnapshots ?? [];
|
|
12949
|
+
if (fleet.length > 0) {
|
|
12950
|
+
lines.push("");
|
|
12951
|
+
const rowOpts = { now, tz };
|
|
12952
|
+
const healthOrder = ["blocked", "throttling", "healthy", "unknown"];
|
|
12953
|
+
const rank = (s) => healthOrder.indexOf(classifyHealth(s, now));
|
|
12954
|
+
const ordered = [...fleet].sort((a, b) => rank(a) - rank(b) || Number(b.isActive) - Number(a.isActive));
|
|
12955
|
+
for (const snap of ordered) {
|
|
12956
|
+
for (const ln of renderAccountRow(snap, rowOpts))
|
|
12957
|
+
lines.push(ln);
|
|
12958
|
+
}
|
|
12959
|
+
const earliest = pickEarliestRecovery(fleet, now);
|
|
12960
|
+
if (earliest) {
|
|
12961
|
+
lines.push("");
|
|
12962
|
+
lines.push(`Earliest recovery: \`${codeSpanSafe(earliest.label)}\` ` + `${formatAbsolute(earliest.at, tz)} (in ${formatRelative(earliest.at, now)})`);
|
|
12963
|
+
}
|
|
12964
|
+
} else if (input.oldQuota) {
|
|
12965
|
+
const recovery = recoveryAtFor(input.oldQuota);
|
|
12966
|
+
if (recovery) {
|
|
12967
|
+
lines.push(`${escapeMarkdown(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
|
|
12968
|
+
}
|
|
12969
|
+
}
|
|
12970
|
+
lines.push("");
|
|
12971
|
+
lines.push(`Run \`/auth add <label>\` to attach another subscription, ` + `or \`/auth refresh\` to re-probe.`);
|
|
12972
|
+
return lines.join(`
|
|
12973
|
+
`);
|
|
12974
|
+
}
|
|
12975
|
+
lines.push(`\u2713 **Switched fleet \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
12976
|
+
lines.push("");
|
|
12977
|
+
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` \u2192 \`${codeSpanSafe(input.newLabel)}\``);
|
|
12978
|
+
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
12979
|
+
lines.push("");
|
|
12980
|
+
if (input.oldQuota) {
|
|
12981
|
+
const recovery = recoveryAtFor(input.oldQuota);
|
|
12982
|
+
if (recovery) {
|
|
12983
|
+
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
|
|
12984
|
+
}
|
|
12985
|
+
}
|
|
12986
|
+
if (input.newQuota) {
|
|
12987
|
+
const fiveStr = fmtPct(input.newQuota.fiveHourUtilizationPct);
|
|
12988
|
+
const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
|
|
12989
|
+
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
|
|
12990
|
+
const headroomStr = hasHeadroom ? "_(plenty of headroom)_" : "_(near limit \u2014 watch this)_";
|
|
12991
|
+
lines.push(`\`${codeSpanSafe(input.newLabel)}\` now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
12992
|
+
} else {
|
|
12993
|
+
lines.push(`_(quota probe for new account is pending \u2014 will reflect on next /auth)_`);
|
|
12994
|
+
}
|
|
12995
|
+
return lines.join(`
|
|
12996
|
+
`);
|
|
12997
|
+
}
|
|
12998
|
+
function limitWordFor(q) {
|
|
12999
|
+
if (q.representativeClaim === "seven_day" && q.sevenDayUtilizationPct >= 99)
|
|
13000
|
+
return "7-day";
|
|
13001
|
+
if (q.representativeClaim === "five_hour" && q.fiveHourUtilizationPct >= 99)
|
|
13002
|
+
return "5-hour";
|
|
13003
|
+
if (q.sevenDayUtilizationPct >= 99)
|
|
13004
|
+
return "7-day";
|
|
13005
|
+
if (q.fiveHourUtilizationPct >= 99)
|
|
13006
|
+
return "5-hour";
|
|
13007
|
+
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7-day" : "5-hour";
|
|
13008
|
+
}
|
|
13009
|
+
function recoveryAtFor(q) {
|
|
13010
|
+
const word = limitWordFor(q);
|
|
13011
|
+
if (word === "7-day")
|
|
13012
|
+
return q.sevenDayResetAt;
|
|
13013
|
+
if (word === "5-hour")
|
|
13014
|
+
return q.fiveHourResetAt;
|
|
13015
|
+
if (!q.fiveHourResetAt)
|
|
13016
|
+
return q.sevenDayResetAt;
|
|
13017
|
+
if (!q.sevenDayResetAt)
|
|
13018
|
+
return q.fiveHourResetAt;
|
|
13019
|
+
return q.fiveHourResetAt.getTime() < q.sevenDayResetAt.getTime() ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
13020
|
+
}
|
|
13021
|
+
function buildSnapshotKeyboard(snapshots, opts = {}) {
|
|
13022
|
+
const max = opts.maxSwitchButtons ?? 3;
|
|
13023
|
+
const now = opts.now ?? new Date;
|
|
13024
|
+
const rows = [];
|
|
13025
|
+
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);
|
|
13026
|
+
for (const t of switchTargets) {
|
|
13027
|
+
rows.push([
|
|
13028
|
+
{
|
|
13029
|
+
text: `Switch fleet \u2192 ${opts.demo ? maskEmail(t.label) : t.label}`,
|
|
13030
|
+
callbackData: `auth:use:${t.label}`
|
|
13031
|
+
}
|
|
13032
|
+
]);
|
|
13033
|
+
}
|
|
13034
|
+
rows.push([
|
|
13035
|
+
{ text: "\u21bb Refresh", callbackData: opts.demo ? "auth:refresh:demo" : "auth:refresh" },
|
|
13036
|
+
{ text: "/usage", insertText: "/usage" },
|
|
13037
|
+
{ text: "+ Add", insertText: "/auth add " }
|
|
13038
|
+
]);
|
|
13039
|
+
return rows;
|
|
13040
|
+
}
|
|
13041
|
+
function switchPriority(s, now = new Date) {
|
|
13042
|
+
const h = classifyHealth(s, now);
|
|
13043
|
+
if (h === "healthy")
|
|
13044
|
+
return 0;
|
|
13045
|
+
if (h === "throttling")
|
|
13046
|
+
return 1;
|
|
13047
|
+
if (h === "unknown")
|
|
13048
|
+
return 2;
|
|
13049
|
+
return 3;
|
|
13050
|
+
}
|
|
13051
|
+
function buildSnapshotsFromState(state3, quotas) {
|
|
13052
|
+
const out = [];
|
|
13053
|
+
for (let i = 0;i < state3.accounts.length; i++) {
|
|
13054
|
+
const acc = state3.accounts[i];
|
|
13055
|
+
const q = quotas[i];
|
|
13056
|
+
out.push({
|
|
13057
|
+
label: acc.label,
|
|
13058
|
+
isActive: acc.label === state3.active,
|
|
13059
|
+
quota: q && q.ok ? q.data : null,
|
|
13060
|
+
quotaError: q && !q.ok ? q.reason : undefined,
|
|
13061
|
+
expiresAtMs: acc.expiresAt
|
|
13062
|
+
});
|
|
13063
|
+
}
|
|
13064
|
+
return out;
|
|
13065
|
+
}
|
|
13066
|
+
function reviveLastQuota(snap) {
|
|
13067
|
+
if (!snap)
|
|
13068
|
+
return null;
|
|
13069
|
+
return {
|
|
13070
|
+
fiveHourUtilizationPct: snap.fiveHourUtilizationPct,
|
|
13071
|
+
sevenDayUtilizationPct: snap.sevenDayUtilizationPct,
|
|
13072
|
+
fiveHourResetAt: snap.fiveHourResetAt ? new Date(snap.fiveHourResetAt) : null,
|
|
13073
|
+
sevenDayResetAt: snap.sevenDayResetAt ? new Date(snap.sevenDayResetAt) : null,
|
|
13074
|
+
representativeClaim: snap.representativeClaim,
|
|
13075
|
+
overageStatus: snap.overageStatus,
|
|
13076
|
+
overageDisabledReason: snap.overageDisabledReason,
|
|
13077
|
+
fiveHourUtilPresent: snap.fiveHourUtilPresent,
|
|
13078
|
+
sevenDayUtilPresent: snap.sevenDayUtilPresent
|
|
13079
|
+
};
|
|
13080
|
+
}
|
|
13081
|
+
var THROTTLING_THRESHOLD_PCT = 80, OVERAGE_EXHAUSTED_REASONS, HEALTH_EMOJI, TABLE_HEALTH_RANK;
|
|
13082
|
+
var init_auth_snapshot_format = __esm(() => {
|
|
13083
|
+
init_demo_mask();
|
|
13084
|
+
init_card_format();
|
|
13085
|
+
OVERAGE_EXHAUSTED_REASONS = new Set(["out_of_credits"]);
|
|
13086
|
+
HEALTH_EMOJI = {
|
|
13087
|
+
healthy: "\uD83D\uDFE2",
|
|
13088
|
+
throttling: "\uD83D\uDFE1",
|
|
13089
|
+
blocked: "\uD83D\uDD34",
|
|
13090
|
+
unknown: "\u26aa"
|
|
13091
|
+
};
|
|
13092
|
+
TABLE_HEALTH_RANK = {
|
|
13093
|
+
blocked: 0,
|
|
13094
|
+
throttling: 1,
|
|
13095
|
+
unknown: 2,
|
|
13096
|
+
healthy: 3
|
|
13097
|
+
};
|
|
13098
|
+
});
|
|
13099
|
+
|
|
12661
13100
|
// ../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
12662
13101
|
var util, objectUtil, ZodParsedType, getParsedType = (data) => {
|
|
12663
13102
|
const t = typeof data;
|
|
@@ -24950,7 +25389,8 @@ var init_schema = __esm(() => {
|
|
|
24950
25389
|
UserSchema = exports_external.object({
|
|
24951
25390
|
name: exports_external.string().optional().describe("Display name for the user."),
|
|
24952
25391
|
telegram_ids: exports_external.array(exports_external.string()).min(1).describe("Telegram username(s) and/or numeric user id(s) identifying this user " + "(a leading @ is optional). Matched against the message sender for " + "per-speaker memory routing."),
|
|
24953
|
-
profile_bank: exports_external.string().describe("Hindsight bank holding this user's memory profile (author via " + "`switchroom memory profile add <bank> ...`).")
|
|
25392
|
+
profile_bank: exports_external.string().describe("Hindsight bank holding this user's memory profile (author via " + "`switchroom memory profile add <bank> ...`)."),
|
|
25393
|
+
person_id: exports_external.string().optional().describe("Free-text display name projected into the inbound `<channel>` " + 'tag\'s `user` attribute (e.g. "Lisa") so an agent can greet by ' + "name instead of only seeing the raw Telegram id/username. NOT a " + "stable identity system \u2014 just a label. Resolution is boot-time-only " + "(no hot-reload; a config change needs an agent restart) and " + "chat-scoped (a resolved name is only shown in a chat/group the " + "person is actually a member of, per that chat's access.json " + "membership \u2014 never broadcast into every chat the agent operates " + "in). Keep this broadly safe to show, the same discipline as " + "picking a `profile_bank` name: there is no automated enforcement " + "that a `person_id` stays safe if a group's membership changes " + "later \u2014 see docs/configuration.md.")
|
|
24954
25394
|
});
|
|
24955
25395
|
SwitchroomConfigSchema = exports_external.object({
|
|
24956
25396
|
switchroom: exports_external.object({
|
|
@@ -36687,7 +37127,7 @@ var init_boot_card = __esm(() => {
|
|
|
36687
37127
|
var exports_auth_snapshot_format = {};
|
|
36688
37128
|
__export(exports_auth_snapshot_format, {
|
|
36689
37129
|
zipProbeResults: () => zipProbeResults,
|
|
36690
|
-
reviveLastQuota: () =>
|
|
37130
|
+
reviveLastQuota: () => reviveLastQuota2,
|
|
36691
37131
|
renderFallbackAnnouncement: () => renderFallbackAnnouncement2,
|
|
36692
37132
|
renderAuthSnapshotFormat2: () => renderAuthSnapshotFormat22,
|
|
36693
37133
|
recommendation: () => recommendation2,
|
|
@@ -36891,6 +37331,8 @@ function renderAuthSnapshotFormat22(snapshots, opts = {}) {
|
|
|
36891
37331
|
lines.push(`_\u26a0 cached ${formatAgeStamp2(opts.staleCachedAtMs, now)}_`);
|
|
36892
37332
|
} else if (opts.liveProbedAtMs != null) {
|
|
36893
37333
|
lines.push(`_Live \u00b7 refreshed ${formatAgeStamp2(opts.liveProbedAtMs, now)}_`);
|
|
37334
|
+
} else if (opts.probeFailed) {
|
|
37335
|
+
lines.push("_\u26a0 probe failed \u2014 no live data_");
|
|
36894
37336
|
} else {
|
|
36895
37337
|
lines.push("_Live_");
|
|
36896
37338
|
}
|
|
@@ -37118,7 +37560,7 @@ function buildSnapshotsFromState2(state4, quotas) {
|
|
|
37118
37560
|
}
|
|
37119
37561
|
return out;
|
|
37120
37562
|
}
|
|
37121
|
-
function
|
|
37563
|
+
function reviveLastQuota2(snap) {
|
|
37122
37564
|
if (!snap)
|
|
37123
37565
|
return null;
|
|
37124
37566
|
return {
|
|
@@ -37139,7 +37581,7 @@ function buildSnapshotsFromCachedState(state4) {
|
|
|
37139
37581
|
return {
|
|
37140
37582
|
label: acc.label,
|
|
37141
37583
|
isActive: acc.label === state4.active,
|
|
37142
|
-
quota:
|
|
37584
|
+
quota: reviveLastQuota2(lq),
|
|
37143
37585
|
quotaError: lq ? undefined : "no cached quota (no probe since broker start)",
|
|
37144
37586
|
expiresAtMs: acc.expiresAt,
|
|
37145
37587
|
capturedAtMs: lq?.capturedAt
|
|
@@ -37147,7 +37589,7 @@ function buildSnapshotsFromCachedState(state4) {
|
|
|
37147
37589
|
});
|
|
37148
37590
|
}
|
|
37149
37591
|
var THROTTLING_THRESHOLD_PCT2 = 80, OVERAGE_EXHAUSTED_REASONS2, HEALTH_EMOJI2, TABLE_HEALTH_RANK2;
|
|
37150
|
-
var
|
|
37592
|
+
var init_auth_snapshot_format2 = __esm(() => {
|
|
37151
37593
|
init_demo_mask();
|
|
37152
37594
|
init_card_format();
|
|
37153
37595
|
OVERAGE_EXHAUSTED_REASONS2 = new Set(["out_of_credits"]);
|
|
@@ -37799,6 +38241,148 @@ var init_approvals_commands = __esm(() => {
|
|
|
37799
38241
|
init_client3();
|
|
37800
38242
|
});
|
|
37801
38243
|
|
|
38244
|
+
// quota-bar-format.ts
|
|
38245
|
+
var exports_quota_bar_format = {};
|
|
38246
|
+
__export(exports_quota_bar_format, {
|
|
38247
|
+
renderUsageCard: () => renderUsageCard,
|
|
38248
|
+
renderQuotaBarBlockFromListState: () => renderQuotaBarBlockFromListState,
|
|
38249
|
+
renderQuotaBarBlock: () => renderQuotaBarBlock,
|
|
38250
|
+
renderQuotaBarAccount: () => renderQuotaBarAccount,
|
|
38251
|
+
pickDot: () => pickDot,
|
|
38252
|
+
formatWindowRow: () => formatWindowRow,
|
|
38253
|
+
formatTimeLeft: () => formatTimeLeft,
|
|
38254
|
+
elapsedFraction: () => elapsedFraction,
|
|
38255
|
+
buildBar: () => buildBar,
|
|
38256
|
+
accountStatus: () => accountStatus
|
|
38257
|
+
});
|
|
38258
|
+
function pickDot(pct) {
|
|
38259
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
38260
|
+
if (clamped >= 90)
|
|
38261
|
+
return "\uD83D\uDD34";
|
|
38262
|
+
if (clamped >= 50)
|
|
38263
|
+
return "\uD83D\uDFE1";
|
|
38264
|
+
return "\uD83D\uDFE2";
|
|
38265
|
+
}
|
|
38266
|
+
function formatTimeLeft(target, now = new Date) {
|
|
38267
|
+
if (!target)
|
|
38268
|
+
return "resets now";
|
|
38269
|
+
const deltaMs = target.getTime() - now.getTime();
|
|
38270
|
+
if (!Number.isFinite(deltaMs) || deltaMs <= 0)
|
|
38271
|
+
return "resets now";
|
|
38272
|
+
const totalMin = Math.round(deltaMs / 60000);
|
|
38273
|
+
if (totalMin < 60)
|
|
38274
|
+
return `${totalMin}m left`;
|
|
38275
|
+
const totalHours = Math.floor(totalMin / 60);
|
|
38276
|
+
const m = totalMin % 60;
|
|
38277
|
+
if (totalHours < 24)
|
|
38278
|
+
return `${totalHours}h${m}m left`;
|
|
38279
|
+
const d = Math.floor(totalHours / 24);
|
|
38280
|
+
const h = totalHours % 24;
|
|
38281
|
+
return h > 0 ? `${d}d${h}h left` : `${d}d left`;
|
|
38282
|
+
}
|
|
38283
|
+
function elapsedFraction(target, windowDurationMs, now = new Date) {
|
|
38284
|
+
if (!target)
|
|
38285
|
+
return 0;
|
|
38286
|
+
const timeLeftMs = target.getTime() - now.getTime();
|
|
38287
|
+
if (!Number.isFinite(timeLeftMs) || timeLeftMs <= 0)
|
|
38288
|
+
return 0;
|
|
38289
|
+
return Math.max(0, Math.min(1, 1 - timeLeftMs / windowDurationMs));
|
|
38290
|
+
}
|
|
38291
|
+
function buildBar(pct, elapsedFrac) {
|
|
38292
|
+
const clampedPct = Math.max(0, Math.min(100, pct));
|
|
38293
|
+
const fillCount = Math.round(clampedPct / 100 * BAR_WIDTH);
|
|
38294
|
+
const cells = new Array(BAR_WIDTH).fill("\u2591");
|
|
38295
|
+
for (let i = 0;i < fillCount; i++)
|
|
38296
|
+
cells[i] = "\u2588";
|
|
38297
|
+
const tickIndex = Math.max(0, Math.min(BAR_WIDTH - 1, Math.round(elapsedFrac * (BAR_WIDTH - 1))));
|
|
38298
|
+
cells[tickIndex] = "\u2503";
|
|
38299
|
+
return cells.join("");
|
|
38300
|
+
}
|
|
38301
|
+
function accountStatus(isActive, exhausted) {
|
|
38302
|
+
if (isActive)
|
|
38303
|
+
return "active";
|
|
38304
|
+
if (exhausted)
|
|
38305
|
+
return "exhausted";
|
|
38306
|
+
return "idle";
|
|
38307
|
+
}
|
|
38308
|
+
function formatWindowRow(window2, pct, resetAt, now = new Date) {
|
|
38309
|
+
const windowMs = window2 === "5h" ? FIVE_HOUR_MS : SEVEN_DAY_MS;
|
|
38310
|
+
const dot = pickDot(pct);
|
|
38311
|
+
const bar = buildBar(pct, elapsedFraction(resetAt, windowMs, now));
|
|
38312
|
+
const pctStr = `${Math.round(Math.max(0, Math.min(100, pct)))}%`;
|
|
38313
|
+
const timeLeft = formatTimeLeft(resetAt, now);
|
|
38314
|
+
return `- ${dot} ${window2} \`[${bar}] ${pctStr} / ${timeLeft}\``;
|
|
38315
|
+
}
|
|
38316
|
+
function renderQuotaBarAccount(label, isActive, exhausted, quota, now = new Date, demo = false) {
|
|
38317
|
+
const status = accountStatus(isActive, exhausted);
|
|
38318
|
+
const displayLabel3 = demo ? maskEmail(label) : label;
|
|
38319
|
+
const lines = [`- **${escapeMarkdown(displayLabel3)}** (${status})`];
|
|
38320
|
+
if (!quota || isProbeThin(quota)) {
|
|
38321
|
+
const reason = !quota ? "no data \u2014 probe failed" : "no data \u2014 thin probe";
|
|
38322
|
+
lines.push(`- \u26a0\ufe0f 5h \`${reason}\``);
|
|
38323
|
+
lines.push(`- \u26a0\ufe0f 7d \`${reason}\``);
|
|
38324
|
+
return lines;
|
|
38325
|
+
}
|
|
38326
|
+
const norm = refillNormalizedUtils(quota, now);
|
|
38327
|
+
lines.push(formatWindowRow("5h", norm.fiveHourUtilizationPct, quota.fiveHourResetAt, now));
|
|
38328
|
+
lines.push(formatWindowRow("7d", norm.sevenDayUtilizationPct, quota.sevenDayResetAt, now));
|
|
38329
|
+
return lines;
|
|
38330
|
+
}
|
|
38331
|
+
function formatAgeStamp3(atMs, now = new Date) {
|
|
38332
|
+
const ageSec = Math.max(0, Math.round((now.getTime() - atMs) / 1000));
|
|
38333
|
+
return ageSec < 60 ? `${ageSec}s ago` : `${Math.round(ageSec / 60)}m ago`;
|
|
38334
|
+
}
|
|
38335
|
+
function renderQuotaBarBlock(snapshots, exhaustedByLabel, opts = {}) {
|
|
38336
|
+
const now = opts.now ?? new Date;
|
|
38337
|
+
const demo = opts.demo ?? false;
|
|
38338
|
+
const lines = [];
|
|
38339
|
+
for (const snap of snapshots) {
|
|
38340
|
+
const exhausted = exhaustedByLabel.get(snap.label) ?? false;
|
|
38341
|
+
lines.push(...renderQuotaBarAccount(snap.label, snap.isActive, exhausted, snap.quota, now, demo));
|
|
38342
|
+
}
|
|
38343
|
+
return lines.join(`
|
|
38344
|
+
`);
|
|
38345
|
+
}
|
|
38346
|
+
function renderQuotaBarBlockFromListState(state4, opts = {}) {
|
|
38347
|
+
const now = opts.now ?? new Date;
|
|
38348
|
+
const exhaustedByLabel = new Map(state4.accounts.map((a) => [a.label, a.exhausted]));
|
|
38349
|
+
const snapshots = state4.accounts.map((acc) => ({
|
|
38350
|
+
label: acc.label,
|
|
38351
|
+
isActive: acc.label === state4.active,
|
|
38352
|
+
quota: reviveLastQuota(acc.last_quota ?? null),
|
|
38353
|
+
quotaError: acc.last_quota ? undefined : "no cached quota (no probe since broker start)",
|
|
38354
|
+
expiresAtMs: acc.expiresAt,
|
|
38355
|
+
capturedAtMs: acc.last_quota?.capturedAt
|
|
38356
|
+
}));
|
|
38357
|
+
return renderQuotaBarBlock(snapshots, exhaustedByLabel, { now });
|
|
38358
|
+
}
|
|
38359
|
+
function renderUsageCard(snapshots, exhaustedByLabel, opts = {}) {
|
|
38360
|
+
const now = opts.now ?? new Date;
|
|
38361
|
+
const demo = opts.demo ?? false;
|
|
38362
|
+
const bar = renderQuotaBarBlock(snapshots, exhaustedByLabel, { now, demo });
|
|
38363
|
+
const lines = [bar];
|
|
38364
|
+
lines.push(`_${recommendation(snapshots, now, demo)}_`);
|
|
38365
|
+
if (opts.staleCachedAtMs != null) {
|
|
38366
|
+
lines.push(`_\u26a0 cached ${formatAgeStamp3(opts.staleCachedAtMs, now)}_`);
|
|
38367
|
+
} else if (opts.liveProbedAtMs != null) {
|
|
38368
|
+
lines.push(`_Live \u00b7 refreshed ${formatAgeStamp3(opts.liveProbedAtMs, now)}_`);
|
|
38369
|
+
} else if (opts.probeFailed) {
|
|
38370
|
+
lines.push("_\u26a0 probe failed \u2014 no live data_");
|
|
38371
|
+
} else {
|
|
38372
|
+
lines.push("_Live_");
|
|
38373
|
+
}
|
|
38374
|
+
return lines.join(`
|
|
38375
|
+
`);
|
|
38376
|
+
}
|
|
38377
|
+
var FIVE_HOUR_MS, SEVEN_DAY_MS, BAR_WIDTH = 10;
|
|
38378
|
+
var init_quota_bar_format = __esm(() => {
|
|
38379
|
+
init_auth_snapshot_format();
|
|
38380
|
+
init_card_format();
|
|
38381
|
+
init_demo_mask();
|
|
38382
|
+
FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
|
|
38383
|
+
SEVEN_DAY_MS = 7 * 24 * 60 * 60 * 1000;
|
|
38384
|
+
});
|
|
38385
|
+
|
|
37802
38386
|
// gateway/approval-callback.ts
|
|
37803
38387
|
var exports_approval_callback = {};
|
|
37804
38388
|
__export(exports_approval_callback, {
|
|
@@ -40681,6 +41265,19 @@ function extractRetryAfterSecs(err) {
|
|
|
40681
41265
|
return ra;
|
|
40682
41266
|
return null;
|
|
40683
41267
|
}
|
|
41268
|
+
function classifyEditError(err) {
|
|
41269
|
+
const retryAfter = extractRetryAfterSecs(err);
|
|
41270
|
+
if (retryAfter != null)
|
|
41271
|
+
return "rate_limited";
|
|
41272
|
+
const desc = err instanceof Error ? err.message : err != null && typeof err === "object" && ("description" in err) ? String(err.description) : String(err);
|
|
41273
|
+
const low = desc.toLowerCase();
|
|
41274
|
+
if (low.includes("not modified"))
|
|
41275
|
+
return "not_modified";
|
|
41276
|
+
if (low.includes("not found") || low.includes("can't be edited") || low.includes("cannot be edited") || low.includes("not enough rights")) {
|
|
41277
|
+
return "gone";
|
|
41278
|
+
}
|
|
41279
|
+
return "transient";
|
|
41280
|
+
}
|
|
40684
41281
|
function createWorkerActivityFeed(opts) {
|
|
40685
41282
|
const log = opts.log ?? (() => {});
|
|
40686
41283
|
const nowFn = opts.now ?? Date.now;
|
|
@@ -40694,6 +41291,18 @@ function createWorkerActivityFeed(opts) {
|
|
|
40694
41291
|
});
|
|
40695
41292
|
const clearIntervalFn = opts.clearInterval ?? ((handle) => clearInterval(handle));
|
|
40696
41293
|
const handles = new Map;
|
|
41294
|
+
const finalized = new Set;
|
|
41295
|
+
const FINALIZED_CAP = 256;
|
|
41296
|
+
function markFinalized(agentId) {
|
|
41297
|
+
if (finalized.has(agentId))
|
|
41298
|
+
return;
|
|
41299
|
+
finalized.add(agentId);
|
|
41300
|
+
if (finalized.size > FINALIZED_CAP) {
|
|
41301
|
+
const oldest = finalized.values().next().value;
|
|
41302
|
+
if (oldest != null)
|
|
41303
|
+
finalized.delete(oldest);
|
|
41304
|
+
}
|
|
41305
|
+
}
|
|
40697
41306
|
let heartbeatTimer = null;
|
|
40698
41307
|
function sendOptsFor(h) {
|
|
40699
41308
|
return {
|
|
@@ -40755,29 +41364,65 @@ function createWorkerActivityFeed(opts) {
|
|
|
40755
41364
|
h.lastEditAt = nowFn();
|
|
40756
41365
|
log(`worker-feed: edit agent=${h.agentId} chat=${h.chatId} ` + `thread=${h.threadId ?? "-"} msgId=${h.messageId} bytes=${body.length}`);
|
|
40757
41366
|
} catch (err) {
|
|
40758
|
-
|
|
40759
|
-
|
|
40760
|
-
|
|
40761
|
-
|
|
41367
|
+
const outcome = classifyEditError(err);
|
|
41368
|
+
if (outcome === "rate_limited") {
|
|
41369
|
+
noteRateLimited(h, err, "edit");
|
|
41370
|
+
return;
|
|
41371
|
+
}
|
|
41372
|
+
if (outcome === "not_modified") {
|
|
41373
|
+
h.lastBody = body;
|
|
41374
|
+
h.lastEditAt = nowFn();
|
|
41375
|
+
return;
|
|
41376
|
+
}
|
|
41377
|
+
if (outcome === "gone") {
|
|
41378
|
+
h.messageId = null;
|
|
41379
|
+
h.lastBody = null;
|
|
41380
|
+
return;
|
|
41381
|
+
}
|
|
41382
|
+
log(`worker-feed: edit transient error agent=${h.agentId}: ${err.message}`);
|
|
40762
41383
|
}
|
|
40763
41384
|
}
|
|
40764
41385
|
async function doFinish(h, view) {
|
|
40765
|
-
|
|
41386
|
+
h.finished = true;
|
|
41387
|
+
markFinalized(h.agentId);
|
|
41388
|
+
if (h.messageId == null) {
|
|
41389
|
+
h.pendingFinish = null;
|
|
40766
41390
|
return;
|
|
41391
|
+
}
|
|
40767
41392
|
if (nowFn() < h.cooldownUntil) {
|
|
41393
|
+
h.pendingFinish = view;
|
|
40768
41394
|
return;
|
|
40769
41395
|
}
|
|
40770
41396
|
const body = renderWorkerActivity({ ...view, narrativeLines: h.narrative });
|
|
40771
|
-
if (body === h.lastBody)
|
|
41397
|
+
if (body === h.lastBody) {
|
|
41398
|
+
h.pendingFinish = null;
|
|
40772
41399
|
return;
|
|
41400
|
+
}
|
|
40773
41401
|
try {
|
|
40774
41402
|
await opts.bot.editMessageText(h.chatId, h.messageId, body, sendOptsFor(h));
|
|
40775
41403
|
h.lastBody = body;
|
|
40776
41404
|
h.lastEditAt = nowFn();
|
|
41405
|
+
h.pendingFinish = null;
|
|
40777
41406
|
log(`worker-feed: finish agent=${h.agentId} chat=${h.chatId} ` + `thread=${h.threadId ?? "-"} msgId=${h.messageId} state=${view.state} bytes=${body.length}`);
|
|
40778
41407
|
} catch (err) {
|
|
40779
|
-
|
|
40780
|
-
|
|
41408
|
+
const outcome = classifyEditError(err);
|
|
41409
|
+
if (outcome === "rate_limited") {
|
|
41410
|
+
noteRateLimited(h, err, "finish");
|
|
41411
|
+
h.pendingFinish = view;
|
|
41412
|
+
return;
|
|
41413
|
+
}
|
|
41414
|
+
if (outcome === "not_modified") {
|
|
41415
|
+
h.lastBody = body;
|
|
41416
|
+
h.lastEditAt = nowFn();
|
|
41417
|
+
h.pendingFinish = null;
|
|
41418
|
+
return;
|
|
41419
|
+
}
|
|
41420
|
+
if (outcome === "gone") {
|
|
41421
|
+
h.pendingFinish = null;
|
|
41422
|
+
return;
|
|
41423
|
+
}
|
|
41424
|
+
h.pendingFinish = view;
|
|
41425
|
+
log(`worker-feed: finish transient error agent=${h.agentId}: ${err.message}`);
|
|
40781
41426
|
}
|
|
40782
41427
|
}
|
|
40783
41428
|
function heartbeatTick() {
|
|
@@ -40785,6 +41430,17 @@ function createWorkerActivityFeed(opts) {
|
|
|
40785
41430
|
for (const h of handles.values()) {
|
|
40786
41431
|
if (!handles.has(h.agentId))
|
|
40787
41432
|
continue;
|
|
41433
|
+
if (h.pendingFinish != null && now >= h.cooldownUntil) {
|
|
41434
|
+
const view2 = h.pendingFinish;
|
|
41435
|
+
h.chain = h.chain.then(() => doFinish(h, view2)).catch((err) => {
|
|
41436
|
+
log(`worker-feed: heartbeat finalize re-drive error ${h.agentId}: ${err.message}`);
|
|
41437
|
+
}).finally(() => {
|
|
41438
|
+
if (handles.get(h.agentId)?.pendingFinish == null) {
|
|
41439
|
+
handles.delete(h.agentId);
|
|
41440
|
+
}
|
|
41441
|
+
});
|
|
41442
|
+
continue;
|
|
41443
|
+
}
|
|
40788
41444
|
if (h.lastView == null)
|
|
40789
41445
|
continue;
|
|
40790
41446
|
if (h.lastView.state !== "running")
|
|
@@ -40828,7 +41484,12 @@ function createWorkerActivityFeed(opts) {
|
|
|
40828
41484
|
update(agentId, chatId, view, threadId) {
|
|
40829
41485
|
if (chatId.length === 0)
|
|
40830
41486
|
return Promise.resolve();
|
|
40831
|
-
|
|
41487
|
+
if (finalized.has(agentId))
|
|
41488
|
+
return Promise.resolve();
|
|
41489
|
+
const existing = handles.get(agentId);
|
|
41490
|
+
if (existing?.finished === true)
|
|
41491
|
+
return Promise.resolve();
|
|
41492
|
+
let h = existing;
|
|
40832
41493
|
if (h == null) {
|
|
40833
41494
|
h = {
|
|
40834
41495
|
agentId,
|
|
@@ -40842,7 +41503,9 @@ function createWorkerActivityFeed(opts) {
|
|
|
40842
41503
|
chain: Promise.resolve(),
|
|
40843
41504
|
lastView: null,
|
|
40844
41505
|
dispatchAtMs: null,
|
|
40845
|
-
stepStartedAtMs: null
|
|
41506
|
+
stepStartedAtMs: null,
|
|
41507
|
+
finished: false,
|
|
41508
|
+
pendingFinish: null
|
|
40846
41509
|
};
|
|
40847
41510
|
handles.set(agentId, h);
|
|
40848
41511
|
}
|
|
@@ -40859,11 +41522,14 @@ function createWorkerActivityFeed(opts) {
|
|
|
40859
41522
|
h.chain = h.chain.then(() => doFinish(h, view)).catch((err) => {
|
|
40860
41523
|
log(`worker-feed: finish chain error ${agentId}: ${err.message}`);
|
|
40861
41524
|
}).finally(() => {
|
|
40862
|
-
handles.
|
|
41525
|
+
if (handles.get(agentId)?.pendingFinish == null) {
|
|
41526
|
+
handles.delete(agentId);
|
|
41527
|
+
}
|
|
40863
41528
|
});
|
|
40864
41529
|
return h.chain;
|
|
40865
41530
|
},
|
|
40866
41531
|
drop(agentId) {
|
|
41532
|
+
markFinalized(agentId);
|
|
40867
41533
|
handles.delete(agentId);
|
|
40868
41534
|
},
|
|
40869
41535
|
heartbeatTick,
|
|
@@ -57237,8 +57903,20 @@ _still working (${minutes}m) \u00b7 message me anytime, I'll keep you posted_`;
|
|
|
57237
57903
|
elapsedMs: elapsed
|
|
57238
57904
|
});
|
|
57239
57905
|
}).catch((err) => {
|
|
57240
|
-
|
|
57241
|
-
|
|
57906
|
+
const desc = err instanceof Error ? err.message : err != null && typeof err === "object" && ("description" in err) ? String(err.description) : String(err);
|
|
57907
|
+
const low = desc.toLowerCase();
|
|
57908
|
+
if (low.includes("not modified")) {
|
|
57909
|
+
activeDeps2.emitMetric?.({
|
|
57910
|
+
kind: "pending_progress_edited",
|
|
57911
|
+
chatKey: key,
|
|
57912
|
+
elapsedMs: elapsed
|
|
57913
|
+
});
|
|
57914
|
+
return;
|
|
57915
|
+
}
|
|
57916
|
+
if (low.includes("not found") || low.includes("can't be edited") || low.includes("cannot be edited") || low.includes("not enough rights")) {
|
|
57917
|
+
clearPending(key, "stale_turn");
|
|
57918
|
+
return;
|
|
57919
|
+
}
|
|
57242
57920
|
});
|
|
57243
57921
|
}
|
|
57244
57922
|
}
|
|
@@ -57790,427 +58468,121 @@ function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.no
|
|
|
57790
58468
|
writeFileSync8(join11(telegramStateDir, QUARANTINE_FILENAME), JSON.stringify(marker) + `
|
|
57791
58469
|
`, "utf-8");
|
|
57792
58470
|
}
|
|
57793
|
-
|
|
57794
|
-
|
|
57795
|
-
|
|
57796
|
-
|
|
57797
|
-
|
|
57798
|
-
function
|
|
57799
|
-
|
|
57800
|
-
|
|
57801
|
-
const
|
|
57802
|
-
|
|
57803
|
-
|
|
57804
|
-
|
|
57805
|
-
|
|
57806
|
-
|
|
57807
|
-
|
|
57808
|
-
|
|
57809
|
-
return "throttling";
|
|
57810
|
-
return "healthy";
|
|
57811
|
-
}
|
|
57812
|
-
function blockedReason(snap, now = new Date) {
|
|
57813
|
-
if (classifyHealth(snap, now) !== "blocked")
|
|
57814
|
-
return null;
|
|
57815
|
-
return "quota-exhausted";
|
|
57816
|
-
}
|
|
57817
|
-
function bindingWindow(q) {
|
|
57818
|
-
if (q.representativeClaim === "seven_day")
|
|
57819
|
-
return "7d";
|
|
57820
|
-
if (q.representativeClaim === "five_hour")
|
|
57821
|
-
return "5h";
|
|
57822
|
-
return q.sevenDayUtilizationPct >= q.fiveHourUtilizationPct ? "7d" : "5h";
|
|
57823
|
-
}
|
|
57824
|
-
function formatRelative(target, now = new Date) {
|
|
57825
|
-
if (!target)
|
|
57826
|
-
return "\u2014";
|
|
57827
|
-
const deltaMs = target.getTime() - now.getTime();
|
|
57828
|
-
if (deltaMs <= 0)
|
|
57829
|
-
return "now";
|
|
57830
|
-
const totalMin = Math.round(deltaMs / 60000);
|
|
57831
|
-
if (totalMin < 60)
|
|
57832
|
-
return `${totalMin}m`;
|
|
57833
|
-
const h = Math.floor(totalMin / 60);
|
|
57834
|
-
const m = totalMin % 60;
|
|
57835
|
-
if (h < 24)
|
|
57836
|
-
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
57837
|
-
const d = Math.floor(h / 24);
|
|
57838
|
-
const rh = h % 24;
|
|
57839
|
-
return rh > 0 ? `${d}d ${rh}h` : `${d}d`;
|
|
57840
|
-
}
|
|
57841
|
-
function formatAbsolute(target, tz = "UTC") {
|
|
57842
|
-
if (!target)
|
|
57843
|
-
return "\u2014";
|
|
57844
|
-
return target.toLocaleString("en-US", {
|
|
57845
|
-
timeZone: tz,
|
|
57846
|
-
weekday: "short",
|
|
57847
|
-
hour: "numeric",
|
|
57848
|
-
minute: "2-digit",
|
|
57849
|
-
hour12: true
|
|
57850
|
-
});
|
|
57851
|
-
}
|
|
57852
|
-
function formatStatusTime(target, now = new Date, tz = "UTC") {
|
|
57853
|
-
if (!target)
|
|
57854
|
-
return "\u2014";
|
|
57855
|
-
const dayFmt = new Intl.DateTimeFormat("en-CA", {
|
|
57856
|
-
timeZone: tz,
|
|
57857
|
-
year: "numeric",
|
|
57858
|
-
month: "2-digit",
|
|
57859
|
-
day: "2-digit"
|
|
57860
|
-
});
|
|
57861
|
-
const timeFmt = new Intl.DateTimeFormat("en-US", {
|
|
57862
|
-
timeZone: tz,
|
|
57863
|
-
hour: "numeric",
|
|
57864
|
-
minute: "2-digit",
|
|
57865
|
-
hour12: true
|
|
57866
|
-
});
|
|
57867
|
-
const timeStr = timeFmt.format(target);
|
|
57868
|
-
if (dayFmt.format(target) === dayFmt.format(now)) {
|
|
57869
|
-
return timeStr;
|
|
57870
|
-
}
|
|
57871
|
-
const withinWeek = target.getTime() - now.getTime() < 7 * 24 * 60 * 60 * 1000;
|
|
57872
|
-
const dateFmt = new Intl.DateTimeFormat("en-US", {
|
|
57873
|
-
timeZone: tz,
|
|
57874
|
-
weekday: "short",
|
|
57875
|
-
...withinWeek ? {} : { day: "numeric", month: "short" }
|
|
57876
|
-
});
|
|
57877
|
-
return `${dateFmt.format(target)} ${timeStr}`;
|
|
57878
|
-
}
|
|
57879
|
-
function fmtPct(pct) {
|
|
57880
|
-
return `${Math.min(100, Math.round(pct))}%`;
|
|
57881
|
-
}
|
|
57882
|
-
function displayLabel(label, opts) {
|
|
57883
|
-
return opts.demo ? maskEmail(label) : label;
|
|
57884
|
-
}
|
|
57885
|
-
var HEALTH_EMOJI = {
|
|
57886
|
-
healthy: "\uD83D\uDFE2",
|
|
57887
|
-
throttling: "\uD83D\uDFE1",
|
|
57888
|
-
blocked: "\uD83D\uDD34",
|
|
57889
|
-
unknown: "\u26aa"
|
|
57890
|
-
};
|
|
57891
|
-
function renderAccountRow(snap, opts) {
|
|
57892
|
-
const now = opts.now ?? new Date;
|
|
57893
|
-
const tz = opts.tz ?? "UTC";
|
|
57894
|
-
const lines = [];
|
|
57895
|
-
const marker = snap.isActive ? "\u25cf " : "";
|
|
57896
|
-
const label = displayLabel(snap.label, opts);
|
|
57897
|
-
if (!snap.quota) {
|
|
57898
|
-
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota probe failed_`);
|
|
57899
|
-
if (snap.quotaError) {
|
|
57900
|
-
lines.push(` _${escapeMarkdown(snap.quotaError)}_`);
|
|
57901
|
-
}
|
|
57902
|
-
return lines;
|
|
57903
|
-
}
|
|
57904
|
-
const q = snap.quota;
|
|
57905
|
-
if (isProbeThin(q)) {
|
|
57906
|
-
lines.push(`${marker}\`${codeSpanSafe(label)}\` _quota unknown (thin probe)_`);
|
|
57907
|
-
return lines;
|
|
57908
|
-
}
|
|
57909
|
-
const norm = refillNormalizedUtils(q, now);
|
|
57910
|
-
const fiveStr = fmtPct(norm.fiveHourUtilizationPct);
|
|
57911
|
-
const sevenStr = fmtPct(norm.sevenDayUtilizationPct);
|
|
57912
|
-
lines.push(`${marker}\`${codeSpanSafe(label)}\` ${fiveStr} / ${sevenStr}`);
|
|
57913
|
-
const health = classifyHealth(snap, now);
|
|
57914
|
-
if (health === "blocked") {
|
|
57915
|
-
const win = bindingWindow(q);
|
|
57916
|
-
const reset2 = win === "5h" ? q.fiveHourResetAt : q.sevenDayResetAt;
|
|
57917
|
-
const winLabel = win === "5h" ? "5-hour" : "7-day";
|
|
57918
|
-
lines.push(reset2 ? ` _quota exhausted \u2014 back ${formatAbsolute(reset2, tz)} (\`in ${formatRelative(reset2, now)}\`, ${winLabel} cap)_` : ` _quota exhausted \u2014 ${winLabel} cap, reset time unknown_`);
|
|
57919
|
-
return lines;
|
|
57920
|
-
}
|
|
57921
|
-
const fiveResetIn = q.fiveHourResetAt ? q.fiveHourResetAt.getTime() - now.getTime() : Infinity;
|
|
57922
|
-
const sevenResetIn = q.sevenDayResetAt ? q.sevenDayResetAt.getTime() - now.getTime() : Infinity;
|
|
57923
|
-
const fiveFirst = fiveResetIn <= sevenResetIn;
|
|
57924
|
-
const fiveSeg = q.fiveHourResetAt ? `5h refills ${formatAbsolute(q.fiveHourResetAt, tz)} (\`in ${formatRelative(q.fiveHourResetAt, now)}\`)` : "5h refills \u2014";
|
|
57925
|
-
const sevenSeg = q.sevenDayResetAt ? `7d resets ${formatAbsolute(q.sevenDayResetAt, tz)} (\`in ${formatRelative(q.sevenDayResetAt, now)}\`)` : "7d resets \u2014";
|
|
57926
|
-
lines.push(` _${fiveFirst ? fiveSeg : sevenSeg}_`);
|
|
57927
|
-
lines.push(` _${fiveFirst ? sevenSeg : fiveSeg}_`);
|
|
57928
|
-
if (q.overageDisabledReason != null && OVERAGE_EXHAUSTED_REASONS.has(q.overageDisabledReason)) {
|
|
57929
|
-
lines.push(` _overage off (${escapeMarkdown(q.overageDisabledReason)}) \u2014 serving from quota_`);
|
|
57930
|
-
}
|
|
57931
|
-
return lines;
|
|
57932
|
-
}
|
|
57933
|
-
function formatAgeStamp(atMs, now = new Date) {
|
|
57934
|
-
const ageSec = Math.max(0, Math.round((now.getTime() - atMs) / 1000));
|
|
57935
|
-
return ageSec < 60 ? `${ageSec}s ago` : `${Math.round(ageSec / 60)}m ago`;
|
|
57936
|
-
}
|
|
57937
|
-
var TABLE_HEALTH_RANK = {
|
|
57938
|
-
blocked: 0,
|
|
57939
|
-
throttling: 1,
|
|
57940
|
-
unknown: 2,
|
|
57941
|
-
healthy: 3
|
|
57942
|
-
};
|
|
57943
|
-
function tableCell(s) {
|
|
57944
|
-
return s.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
57945
|
-
}
|
|
57946
|
-
function pctCells(snap, now) {
|
|
57947
|
-
if (!snap.quota)
|
|
57948
|
-
return { five: "\u2014", seven: "\u2014" };
|
|
57949
|
-
if (isProbeThin(snap.quota))
|
|
57950
|
-
return { five: "?", seven: "?" };
|
|
57951
|
-
const norm = refillNormalizedUtils(snap.quota, now);
|
|
57952
|
-
return { five: fmtPct(norm.fiveHourUtilizationPct), seven: fmtPct(norm.sevenDayUtilizationPct) };
|
|
57953
|
-
}
|
|
57954
|
-
function windowResetCell(snap, now, tz, win) {
|
|
57955
|
-
if (!snap.quota) {
|
|
57956
|
-
return snap.quotaError ? `probe failed (${snap.quotaError})` : "\u2014";
|
|
57957
|
-
}
|
|
57958
|
-
if (isProbeThin(snap.quota))
|
|
57959
|
-
return "quota unknown";
|
|
57960
|
-
const reset2 = win === "5h" ? snap.quota.fiveHourResetAt : snap.quota.sevenDayResetAt;
|
|
57961
|
-
if (!reset2)
|
|
57962
|
-
return "\u2014";
|
|
57963
|
-
return `${formatStatusTime(reset2, now, tz)} (in ${formatRelative(reset2, now)})`;
|
|
57964
|
-
}
|
|
57965
|
-
function renderAuthSnapshotFormat2(snapshots, opts = {}) {
|
|
57966
|
-
const now = opts.now ?? new Date;
|
|
57967
|
-
const tz = opts.tz ?? "UTC";
|
|
57968
|
-
const lines = [];
|
|
57969
|
-
lines.push("\uD83D\uDD0B **Auth \u2014 fleet status**");
|
|
57970
|
-
const ordered = [...snapshots].sort((a, b) => {
|
|
57971
|
-
if (a.isActive !== b.isActive)
|
|
57972
|
-
return a.isActive ? -1 : 1;
|
|
57973
|
-
const r = TABLE_HEALTH_RANK[classifyHealth(a, now)] - TABLE_HEALTH_RANK[classifyHealth(b, now)];
|
|
57974
|
-
if (r !== 0)
|
|
57975
|
-
return r;
|
|
57976
|
-
return a.label.localeCompare(b.label);
|
|
57977
|
-
});
|
|
57978
|
-
if (ordered.length > 0) {
|
|
57979
|
-
lines.push("");
|
|
57980
|
-
lines.push("| State | Account | 5h | 5h resets | 7d | 7d resets |");
|
|
57981
|
-
lines.push("| --- | --- | --- | --- | --- | --- |");
|
|
57982
|
-
for (const s of ordered) {
|
|
57983
|
-
const emoji = HEALTH_EMOJI[classifyHealth(s, now)];
|
|
57984
|
-
const label = displayLabel(s.label, opts);
|
|
57985
|
-
const accountCell = `\`${codeSpanSafe(s.isActive ? `${label} (active)` : label)}\``;
|
|
57986
|
-
const { five, seven } = pctCells(s, now);
|
|
57987
|
-
const fiveReset = windowResetCell(s, now, tz, "5h");
|
|
57988
|
-
const sevenReset = windowResetCell(s, now, tz, "7d");
|
|
57989
|
-
lines.push(`| ${emoji} | ${tableCell(accountCell)} | ${five} | ${tableCell(fiveReset)} | ${seven} | ${tableCell(sevenReset)} |`);
|
|
57990
|
-
}
|
|
57991
|
-
}
|
|
57992
|
-
lines.push("");
|
|
57993
|
-
lines.push(`_${recommendation(snapshots, now, opts.demo ?? false)}_`);
|
|
57994
|
-
if (opts.staleCachedAtMs != null) {
|
|
57995
|
-
lines.push(`_\u26a0 cached ${formatAgeStamp(opts.staleCachedAtMs, now)}_`);
|
|
57996
|
-
} else if (opts.liveProbedAtMs != null) {
|
|
57997
|
-
lines.push(`_Live \u00b7 refreshed ${formatAgeStamp(opts.liveProbedAtMs, now)}_`);
|
|
57998
|
-
} else {
|
|
57999
|
-
lines.push("_Live_");
|
|
58000
|
-
}
|
|
58001
|
-
return lines.join(`
|
|
58002
|
-
`);
|
|
58003
|
-
}
|
|
58004
|
-
function recommendation(snapshots, now = new Date, demo = false) {
|
|
58005
|
-
const active = snapshots.find((s) => s.isActive);
|
|
58006
|
-
if (!active)
|
|
58007
|
-
return "No active account set.";
|
|
58008
|
-
const activeHealth = classifyHealth(active, now);
|
|
58009
|
-
const others = snapshots.filter((s) => !s.isActive);
|
|
58010
|
-
const healthyAlt = others.find((s) => classifyHealth(s, now) === "healthy");
|
|
58011
|
-
const lbl = (s) => demo ? maskEmail(s.label) : s.label;
|
|
58012
|
-
const activeLabel = lbl(active);
|
|
58013
|
-
if (activeHealth === "healthy") {
|
|
58014
|
-
return `Recommendation: stay on ${activeLabel}.`;
|
|
58015
|
-
}
|
|
58016
|
-
if (activeHealth === "throttling") {
|
|
58017
|
-
if (healthyAlt) {
|
|
58018
|
-
return `Recommendation: active ${activeLabel} is throttling. Switch to ${lbl(healthyAlt)} for headroom.`;
|
|
58019
|
-
}
|
|
58020
|
-
return `Recommendation: active ${activeLabel} is throttling; no healthy alternative \u2014 wait for refill.`;
|
|
58021
|
-
}
|
|
58022
|
-
if (activeHealth === "blocked") {
|
|
58023
|
-
if (healthyAlt) {
|
|
58024
|
-
return `Recommendation: active ${activeLabel} is BLOCKED \u2014 switch to ${lbl(healthyAlt)} now.`;
|
|
58025
|
-
}
|
|
58026
|
-
return summarizeNoHealthyAlt(snapshots, now, demo);
|
|
58027
|
-
}
|
|
58028
|
-
return `Active ${activeLabel}: quota probe failed; broker last_seen unknown.`;
|
|
58029
|
-
}
|
|
58030
|
-
function summarizeNoHealthyAlt(snapshots, now, demo = false) {
|
|
58031
|
-
const mask = (label) => demo ? maskEmail(label) : label;
|
|
58032
|
-
let throttlingLabel = null;
|
|
58033
|
-
let allTrulyBlocked = true;
|
|
58034
|
-
for (const s of snapshots) {
|
|
58035
|
-
const h = classifyHealth(s, now);
|
|
58036
|
-
if (h === "throttling") {
|
|
58037
|
-
if (!throttlingLabel)
|
|
58038
|
-
throttlingLabel = s.label;
|
|
58039
|
-
allTrulyBlocked = false;
|
|
58040
|
-
} else if (h === "healthy" || h === "unknown") {
|
|
58041
|
-
allTrulyBlocked = false;
|
|
58042
|
-
} else if (h === "blocked" && blockedReason(s, now) === "quota-exhausted") {
|
|
58043
|
-
if (s.quota) {
|
|
58044
|
-
const win = bindingWindow(s.quota);
|
|
58045
|
-
const at = win === "5h" ? s.quota.fiveHourResetAt : s.quota.sevenDayResetAt;
|
|
58046
|
-
if (at && at.getTime() > now.getTime())
|
|
58047
|
-
allTrulyBlocked = false;
|
|
58048
|
-
}
|
|
58471
|
+
|
|
58472
|
+
// gateway/resolve-person.ts
|
|
58473
|
+
function normalizeTelegramKey(raw) {
|
|
58474
|
+
return raw.trim().replace(/^@/, "").toLowerCase();
|
|
58475
|
+
}
|
|
58476
|
+
function buildPersonDirectory(entries) {
|
|
58477
|
+
const byTelegramKey = {};
|
|
58478
|
+
const dropped = [];
|
|
58479
|
+
const personIdOwner = new Map;
|
|
58480
|
+
const telegramKeyOwner = new Map;
|
|
58481
|
+
for (const raw of entries) {
|
|
58482
|
+
const key = typeof raw.key === "string" ? raw.key.trim() : "";
|
|
58483
|
+
const personId = typeof raw.person_id === "string" ? raw.person_id.trim() : "";
|
|
58484
|
+
if (key.length === 0) {
|
|
58485
|
+
dropped.push({ key: raw.key || "(unknown)", reason: "missing users: map key", reasonClass: "missing users: map key" });
|
|
58486
|
+
continue;
|
|
58049
58487
|
}
|
|
58050
|
-
|
|
58051
|
-
|
|
58052
|
-
|
|
58053
|
-
const eta = earliestRecovery ? ` Soonest full refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.` : "";
|
|
58054
|
-
return `No fully-healthy account; ${mask(throttlingLabel)} is throttling but still usable.${eta}`;
|
|
58055
|
-
}
|
|
58056
|
-
if (!allTrulyBlocked) {
|
|
58057
|
-
if (earliestRecovery) {
|
|
58058
|
-
return `All accounts at capacity; soonest refill: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
58488
|
+
if (personId.length === 0) {
|
|
58489
|
+
dropped.push({ key, reason: "empty or missing person_id", reasonClass: "empty or missing person_id" });
|
|
58490
|
+
continue;
|
|
58059
58491
|
}
|
|
58060
|
-
|
|
58061
|
-
|
|
58062
|
-
if (earliestRecovery) {
|
|
58063
|
-
return `All accounts blocked. Earliest recovery: ${mask(earliestRecovery.label)} in ${formatRelative(earliestRecovery.at, now)}.`;
|
|
58064
|
-
}
|
|
58065
|
-
return `All accounts blocked. Run /auth add to attach another subscription.`;
|
|
58066
|
-
}
|
|
58067
|
-
function pickEarliestRecovery(snapshots, now) {
|
|
58068
|
-
let best = null;
|
|
58069
|
-
for (const s of snapshots) {
|
|
58070
|
-
if (!s.quota)
|
|
58492
|
+
if (!Array.isArray(raw.telegram_ids) || raw.telegram_ids.length === 0) {
|
|
58493
|
+
dropped.push({ key, reason: "no telegram_ids to resolve against", reasonClass: "no telegram_ids to resolve against" });
|
|
58071
58494
|
continue;
|
|
58072
|
-
|
|
58495
|
+
}
|
|
58496
|
+
const personIdLower = personId.toLowerCase();
|
|
58497
|
+
const existingOwner = personIdOwner.get(personIdLower);
|
|
58498
|
+
if (existingOwner != null && existingOwner !== key) {
|
|
58499
|
+
dropped.push({
|
|
58500
|
+
key,
|
|
58501
|
+
reason: `duplicate person_id "${personId}" already claimed by users.${existingOwner}`,
|
|
58502
|
+
reasonClass: `duplicate person_id already claimed by users.${existingOwner}`
|
|
58503
|
+
});
|
|
58073
58504
|
continue;
|
|
58074
|
-
|
|
58075
|
-
|
|
58076
|
-
|
|
58505
|
+
}
|
|
58506
|
+
personIdOwner.set(personIdLower, key);
|
|
58507
|
+
const telegramKeys = [...new Set(raw.telegram_ids.map(normalizeTelegramKey).filter((k) => k.length > 0))];
|
|
58508
|
+
if (telegramKeys.length === 0) {
|
|
58509
|
+
dropped.push({ key, reason: "telegram_ids contained no usable id/username", reasonClass: "telegram_ids contained no usable id/username" });
|
|
58510
|
+
personIdOwner.delete(personIdLower);
|
|
58077
58511
|
continue;
|
|
58078
|
-
if (!best || at.getTime() < best.at.getTime()) {
|
|
58079
|
-
best = { label: s.label, at };
|
|
58080
58512
|
}
|
|
58081
|
-
|
|
58082
|
-
|
|
58083
|
-
|
|
58084
|
-
|
|
58085
|
-
|
|
58086
|
-
|
|
58087
|
-
|
|
58088
|
-
|
|
58089
|
-
|
|
58090
|
-
|
|
58091
|
-
|
|
58092
|
-
|
|
58093
|
-
|
|
58094
|
-
const fleet = input.fleetSnapshots ?? [];
|
|
58095
|
-
if (fleet.length > 0) {
|
|
58096
|
-
lines.push("");
|
|
58097
|
-
const rowOpts = { now, tz };
|
|
58098
|
-
const healthOrder = ["blocked", "throttling", "healthy", "unknown"];
|
|
58099
|
-
const rank = (s) => healthOrder.indexOf(classifyHealth(s, now));
|
|
58100
|
-
const ordered = [...fleet].sort((a, b) => rank(a) - rank(b) || Number(b.isActive) - Number(a.isActive));
|
|
58101
|
-
for (const snap of ordered) {
|
|
58102
|
-
for (const ln of renderAccountRow(snap, rowOpts))
|
|
58103
|
-
lines.push(ln);
|
|
58104
|
-
}
|
|
58105
|
-
const earliest = pickEarliestRecovery(fleet, now);
|
|
58106
|
-
if (earliest) {
|
|
58107
|
-
lines.push("");
|
|
58108
|
-
lines.push(`Earliest recovery: \`${codeSpanSafe(earliest.label)}\` ` + `${formatAbsolute(earliest.at, tz)} (in ${formatRelative(earliest.at, now)})`);
|
|
58109
|
-
}
|
|
58110
|
-
} else if (input.oldQuota) {
|
|
58111
|
-
const recovery = recoveryAtFor(input.oldQuota);
|
|
58112
|
-
if (recovery) {
|
|
58113
|
-
lines.push(`${escapeMarkdown(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
|
|
58114
|
-
}
|
|
58513
|
+
const collidingTelegramKey = telegramKeys.find((tk) => {
|
|
58514
|
+
const existingTkOwner = telegramKeyOwner.get(tk);
|
|
58515
|
+
return existingTkOwner != null && existingTkOwner !== key;
|
|
58516
|
+
});
|
|
58517
|
+
if (collidingTelegramKey != null) {
|
|
58518
|
+
const existingTkOwner = telegramKeyOwner.get(collidingTelegramKey);
|
|
58519
|
+
dropped.push({
|
|
58520
|
+
key,
|
|
58521
|
+
reason: `duplicate telegram_id "${collidingTelegramKey}" already claimed by users.${existingTkOwner}`,
|
|
58522
|
+
reasonClass: `duplicate telegram_id already claimed by users.${existingTkOwner}`
|
|
58523
|
+
});
|
|
58524
|
+
personIdOwner.delete(personIdLower);
|
|
58525
|
+
continue;
|
|
58115
58526
|
}
|
|
58116
|
-
|
|
58117
|
-
|
|
58118
|
-
|
|
58119
|
-
|
|
58120
|
-
}
|
|
58121
|
-
lines.push(`\u2713 **Switched fleet \u00b7 ${headerLimit} on ${escapeMarkdown(input.oldLabel)}**`);
|
|
58122
|
-
lines.push("");
|
|
58123
|
-
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` \u2192 \`${codeSpanSafe(input.newLabel)}\``);
|
|
58124
|
-
lines.push(`Triggered by: agent **${escapeMarkdown(input.triggerAgent)}**`);
|
|
58125
|
-
lines.push("");
|
|
58126
|
-
if (input.oldQuota) {
|
|
58127
|
-
const recovery = recoveryAtFor(input.oldQuota);
|
|
58128
|
-
if (recovery) {
|
|
58129
|
-
lines.push(`\`${codeSpanSafe(input.oldLabel)}\` recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
|
|
58527
|
+
const entry = { key, personId, telegramKeys };
|
|
58528
|
+
for (const tk of telegramKeys) {
|
|
58529
|
+
telegramKeyOwner.set(tk, key);
|
|
58530
|
+
byTelegramKey[tk] = entry;
|
|
58130
58531
|
}
|
|
58131
58532
|
}
|
|
58132
|
-
|
|
58133
|
-
const fiveStr = fmtPct(input.newQuota.fiveHourUtilizationPct);
|
|
58134
|
-
const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
|
|
58135
|
-
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
|
|
58136
|
-
const headroomStr = hasHeadroom ? "_(plenty of headroom)_" : "_(near limit \u2014 watch this)_";
|
|
58137
|
-
lines.push(`\`${codeSpanSafe(input.newLabel)}\` now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
58138
|
-
} else {
|
|
58139
|
-
lines.push(`_(quota probe for new account is pending \u2014 will reflect on next /auth)_`);
|
|
58140
|
-
}
|
|
58141
|
-
return lines.join(`
|
|
58142
|
-
`);
|
|
58533
|
+
return { directory: { byTelegramKey }, dropped };
|
|
58143
58534
|
}
|
|
58144
|
-
function
|
|
58145
|
-
|
|
58146
|
-
|
|
58147
|
-
|
|
58148
|
-
|
|
58149
|
-
|
|
58150
|
-
|
|
58151
|
-
|
|
58152
|
-
|
|
58153
|
-
|
|
58154
|
-
}
|
|
58155
|
-
|
|
58156
|
-
|
|
58157
|
-
|
|
58158
|
-
return
|
|
58159
|
-
|
|
58160
|
-
|
|
58161
|
-
|
|
58162
|
-
|
|
58163
|
-
|
|
58164
|
-
|
|
58165
|
-
|
|
58166
|
-
}
|
|
58167
|
-
|
|
58168
|
-
|
|
58169
|
-
|
|
58170
|
-
const rows = [];
|
|
58171
|
-
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);
|
|
58172
|
-
for (const t of switchTargets) {
|
|
58173
|
-
rows.push([
|
|
58174
|
-
{
|
|
58175
|
-
text: `Switch fleet \u2192 ${opts.demo ? maskEmail(t.label) : t.label}`,
|
|
58176
|
-
callbackData: `auth:use:${t.label}`
|
|
58177
|
-
}
|
|
58178
|
-
]);
|
|
58535
|
+
function runPersonDirectoryBootCheck(readEntries) {
|
|
58536
|
+
try {
|
|
58537
|
+
const rawEntries = readEntries();
|
|
58538
|
+
const { directory, dropped } = buildPersonDirectory(rawEntries);
|
|
58539
|
+
if (dropped.length > 0) {
|
|
58540
|
+
const alertSummary = dropped.map((d) => `${d.key} (${d.reasonClass})`).join("; ");
|
|
58541
|
+
const logSummary = dropped.map((d) => `${d.key} (${d.reason})`).join("; ");
|
|
58542
|
+
const plural = dropped.length === 1 ? "y" : "ies";
|
|
58543
|
+
return {
|
|
58544
|
+
directory,
|
|
58545
|
+
alertDetail: `person_id: dropped ${dropped.length} malformed users: entr${plural} at boot \u2014 ${alertSummary}`,
|
|
58546
|
+
logLine: `telegram gateway: person_id boot validation dropped ${dropped.length} entr${plural}: ${logSummary}`
|
|
58547
|
+
};
|
|
58548
|
+
}
|
|
58549
|
+
return {
|
|
58550
|
+
directory,
|
|
58551
|
+
alertDetail: null,
|
|
58552
|
+
logLine: rawEntries.length > 0 ? `telegram gateway: person_id boot validation ok \u2014 ${Object.keys(directory.byTelegramKey).length} telegram id/username(s) resolved` : `telegram gateway: person_id boot validation ok \u2014 no person_id entries configured`
|
|
58553
|
+
};
|
|
58554
|
+
} catch (err) {
|
|
58555
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58556
|
+
return {
|
|
58557
|
+
directory: { byTelegramKey: {} },
|
|
58558
|
+
alertDetail: `person_id boot validation crashed \u2014 name resolution disabled this boot (fail-open, raw ids/usernames will show); see gateway stderr for detail`,
|
|
58559
|
+
logLine: `telegram gateway: person_id boot validation CRASHED (name resolution disabled this boot, raw ids will show \u2014 fail-open): ${msg}`
|
|
58560
|
+
};
|
|
58179
58561
|
}
|
|
58180
|
-
rows.push([
|
|
58181
|
-
{ text: "\u21bb Refresh", callbackData: opts.demo ? "auth:refresh:demo" : "auth:refresh" },
|
|
58182
|
-
{ text: "/usage", insertText: "/usage" },
|
|
58183
|
-
{ text: "+ Add", insertText: "/auth add " }
|
|
58184
|
-
]);
|
|
58185
|
-
return rows;
|
|
58186
|
-
}
|
|
58187
|
-
function switchPriority(s, now = new Date) {
|
|
58188
|
-
const h = classifyHealth(s, now);
|
|
58189
|
-
if (h === "healthy")
|
|
58190
|
-
return 0;
|
|
58191
|
-
if (h === "throttling")
|
|
58192
|
-
return 1;
|
|
58193
|
-
if (h === "unknown")
|
|
58194
|
-
return 2;
|
|
58195
|
-
return 3;
|
|
58196
58562
|
}
|
|
58197
|
-
function
|
|
58198
|
-
const
|
|
58199
|
-
|
|
58200
|
-
|
|
58201
|
-
|
|
58202
|
-
|
|
58203
|
-
|
|
58204
|
-
|
|
58205
|
-
|
|
58206
|
-
|
|
58207
|
-
|
|
58208
|
-
|
|
58563
|
+
function resolvePersonName(directory, opts) {
|
|
58564
|
+
const idKey = normalizeTelegramKey(opts.telegramId);
|
|
58565
|
+
const usernameKey = opts.username ? normalizeTelegramKey(opts.username) : undefined;
|
|
58566
|
+
const entry = directory.byTelegramKey[idKey] ?? (usernameKey ? directory.byTelegramKey[usernameKey] : undefined);
|
|
58567
|
+
if (!entry)
|
|
58568
|
+
return;
|
|
58569
|
+
if (opts.isDm)
|
|
58570
|
+
return entry.personId;
|
|
58571
|
+
const allowFrom = opts.groupAllowFrom ?? [];
|
|
58572
|
+
const allowFromNormalized = allowFrom.map(normalizeTelegramKey);
|
|
58573
|
+
const memberConfirmed = allowFromNormalized.includes(idKey) || usernameKey != null && allowFromNormalized.includes(usernameKey);
|
|
58574
|
+
return memberConfirmed ? entry.personId : undefined;
|
|
58575
|
+
}
|
|
58576
|
+
function safeResolvePersonName(directory, opts, rawFallback) {
|
|
58577
|
+
try {
|
|
58578
|
+
return resolvePersonName(directory, opts) ?? rawFallback;
|
|
58579
|
+
} catch {
|
|
58580
|
+
return rawFallback;
|
|
58209
58581
|
}
|
|
58210
|
-
return out;
|
|
58211
58582
|
}
|
|
58212
58583
|
|
|
58213
58584
|
// gateway/auth-command.ts
|
|
58585
|
+
init_auth_snapshot_format();
|
|
58214
58586
|
init_demo_mask();
|
|
58215
58587
|
var AUTH_RM_CONFIRM_TTL_MS = 60000;
|
|
58216
58588
|
var pendingAuthRmFlows = new Map;
|
|
@@ -60148,6 +60520,20 @@ function renderOperatorEvent(ev) {
|
|
|
60148
60520
|
]
|
|
60149
60521
|
}
|
|
60150
60522
|
};
|
|
60523
|
+
case "config-warning":
|
|
60524
|
+
return {
|
|
60525
|
+
text: [
|
|
60526
|
+
`\u2139\ufe0f **Config warning** for **${agent}**.`,
|
|
60527
|
+
detail ? `_${detail}_` : "",
|
|
60528
|
+
`Non-urgent \u2014 config will keep working with today's fallback behavior.`
|
|
60529
|
+
].filter(Boolean).join(`
|
|
60530
|
+
`),
|
|
60531
|
+
keyboard: {
|
|
60532
|
+
inline_keyboard: [
|
|
60533
|
+
[{ text: "\u274c Dismiss", callback_data: `op:dismiss:${encodeURIComponent(ev.agent)}` }]
|
|
60534
|
+
]
|
|
60535
|
+
}
|
|
60536
|
+
};
|
|
60151
60537
|
}
|
|
60152
60538
|
}
|
|
60153
60539
|
var DEFAULT_OPERATOR_EVENT_COOLDOWN_MS = 5 * 60000;
|
|
@@ -60402,6 +60788,7 @@ function resolveModelUnavailableFromOperatorEvent(ev) {
|
|
|
60402
60788
|
|
|
60403
60789
|
// auto-fallback-fleet.ts
|
|
60404
60790
|
init_card_format();
|
|
60791
|
+
init_auth_snapshot_format();
|
|
60405
60792
|
function renderFallbackFailureNotice(triggerAgent, reason) {
|
|
60406
60793
|
return `\u26a0\ufe0f **Auto-failover could not run** (trigger: **${escapeMarkdown(triggerAgent)}**)
|
|
60407
60794
|
` + `${escapeMarkdown(reason)}
|
|
@@ -72126,7 +72513,7 @@ function readSubTail(entry, tail, now, onDescriptionUpdate, fs2, log, db2, paren
|
|
|
72126
72513
|
const events = projectSubagentLine(line, entry.agentId, startState);
|
|
72127
72514
|
const fireNarrativeProgress = () => {
|
|
72128
72515
|
if (onProgress == null || entry.state !== "running" || entry.historical)
|
|
72129
|
-
return;
|
|
72516
|
+
return false;
|
|
72130
72517
|
try {
|
|
72131
72518
|
onProgress({
|
|
72132
72519
|
agentId: entry.agentId,
|
|
@@ -72140,24 +72527,26 @@ function readSubTail(entry, tail, now, onDescriptionUpdate, fs2, log, db2, paren
|
|
|
72140
72527
|
lastTool: entry.lastTool,
|
|
72141
72528
|
toolCount: entry.toolCount
|
|
72142
72529
|
});
|
|
72530
|
+
return true;
|
|
72143
72531
|
} catch (cbErr) {
|
|
72144
72532
|
log?.(`subagent-watcher: onProgress callback error ${entry.agentId}: ${cbErr.message}`);
|
|
72533
|
+
return false;
|
|
72145
72534
|
}
|
|
72146
72535
|
};
|
|
72147
72536
|
const resolvePendingSubNarrative = (toolName, toolInput) => {
|
|
72148
72537
|
if (entry.pendingNarrative == null)
|
|
72149
|
-
return;
|
|
72538
|
+
return false;
|
|
72150
72539
|
const pending = entry.pendingNarrative;
|
|
72151
72540
|
entry.pendingNarrative = null;
|
|
72152
72541
|
if (toolName != null && REPLY_TOOLS2.has(toolName)) {
|
|
72153
72542
|
const replyText = typeof toolInput?.text === "string" ? toolInput.text : "";
|
|
72154
72543
|
if (isDraftOfReply2(pending.text, replyText))
|
|
72155
|
-
return;
|
|
72544
|
+
return false;
|
|
72156
72545
|
} else if (toolName == null && entry.lastReplyText != null && entry.lastReplyText.length > 0) {
|
|
72157
72546
|
if (isDraftOfReply2(pending.text, entry.lastReplyText))
|
|
72158
|
-
return;
|
|
72547
|
+
return false;
|
|
72159
72548
|
}
|
|
72160
|
-
fireNarrativeProgress();
|
|
72549
|
+
return fireNarrativeProgress();
|
|
72161
72550
|
};
|
|
72162
72551
|
for (const ev of events) {
|
|
72163
72552
|
const idleSecBeforeBump = Math.round((now - entry.lastActivityAt) / 1000);
|
|
@@ -72185,7 +72574,7 @@ function readSubTail(entry, tail, now, onDescriptionUpdate, fs2, log, db2, paren
|
|
|
72185
72574
|
log?.(`subagent-watcher: stall cleared for ${entry.agentId} (activity resumed after ${idleSecBeforeBump}s \u2014 re-arming detection)`);
|
|
72186
72575
|
}
|
|
72187
72576
|
if (ev.kind === "sub_agent_tool_use") {
|
|
72188
|
-
resolvePendingSubNarrative(ev.toolName, ev.input);
|
|
72577
|
+
const narrativeJustFired = resolvePendingSubNarrative(ev.toolName, ev.input);
|
|
72189
72578
|
if (REPLY_TOOLS2.has(ev.toolName) && typeof ev.input?.text === "string") {
|
|
72190
72579
|
entry.lastReplyText = ev.input.text;
|
|
72191
72580
|
}
|
|
@@ -72194,7 +72583,7 @@ function readSubTail(entry, tail, now, onDescriptionUpdate, fs2, log, db2, paren
|
|
|
72194
72583
|
name: ev.toolName,
|
|
72195
72584
|
sanitisedArg: sanitiseToolArg(ev.toolName, ev.input ?? {})
|
|
72196
72585
|
};
|
|
72197
|
-
if (onProgress != null && entry.state === "running" && !entry.historical) {
|
|
72586
|
+
if (onProgress != null && entry.state === "running" && !entry.historical && !narrativeJustFired) {
|
|
72198
72587
|
const toolLine = describeToolUse(ev.toolName, ev.input ?? {});
|
|
72199
72588
|
if (toolLine != null && toolLine.length > 0) {
|
|
72200
72589
|
try {
|
|
@@ -74769,9 +75158,10 @@ function saveCreditState(stateDir, state4) {
|
|
|
74769
75158
|
}
|
|
74770
75159
|
|
|
74771
75160
|
// quota-watch.ts
|
|
75161
|
+
init_auth_snapshot_format();
|
|
75162
|
+
init_card_format();
|
|
74772
75163
|
import { readFileSync as readFileSync42, writeFileSync as writeFileSync32, existsSync as existsSync41, mkdirSync as mkdirSync31 } from "fs";
|
|
74773
75164
|
import { join as join43 } from "path";
|
|
74774
|
-
init_card_format();
|
|
74775
75165
|
var STATE_FILE2 = "quota-watch.json";
|
|
74776
75166
|
function emptyQuotaWatchState() {
|
|
74777
75167
|
return {};
|
|
@@ -74995,7 +75385,7 @@ function patchQuotaWatchState(current, accountLabel, accountState) {
|
|
|
74995
75385
|
}
|
|
74996
75386
|
|
|
74997
75387
|
// gateway/gateway.ts
|
|
74998
|
-
|
|
75388
|
+
init_auth_snapshot_format2();
|
|
74999
75389
|
|
|
75000
75390
|
// demo-mask.ts
|
|
75001
75391
|
function stableAssign2(input, cache, pool, overflow) {
|
|
@@ -75096,10 +75486,10 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
|
75096
75486
|
}
|
|
75097
75487
|
|
|
75098
75488
|
// ../src/build-info.ts
|
|
75099
|
-
var VERSION = "0.18.
|
|
75100
|
-
var COMMIT_SHA = "
|
|
75101
|
-
var COMMIT_DATE = "2026-07-
|
|
75102
|
-
var LATEST_PR =
|
|
75489
|
+
var VERSION = "0.18.6";
|
|
75490
|
+
var COMMIT_SHA = "b62d558a";
|
|
75491
|
+
var COMMIT_DATE = "2026-07-10T10:22:09+10:00";
|
|
75492
|
+
var LATEST_PR = 2970;
|
|
75103
75493
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
75104
75494
|
|
|
75105
75495
|
// gateway/boot-version.ts
|
|
@@ -75161,7 +75551,7 @@ function classifyRejection(err, opts = {}) {
|
|
|
75161
75551
|
if (e.error_code !== 400)
|
|
75162
75552
|
return "shutdown";
|
|
75163
75553
|
const desc = (e.description ?? "").toLowerCase();
|
|
75164
|
-
if (desc.includes("message is not modified") || desc.includes("message to edit not found") || desc.includes("message to delete not found") || desc.includes("can't parse entities") || desc.includes("unsupported start tag") || desc.includes("chat not found") || desc.includes("not enough rights")) {
|
|
75554
|
+
if (desc.includes("message is not modified") || desc.includes("message to edit not found") || desc.includes("message to delete not found") || desc.includes("can't parse entities") || desc.includes("unsupported start tag") || desc.includes("chat not found") || desc.includes("not enough rights") || desc.includes("group chat was upgraded to a supergroup chat") || desc.includes("chat_id is empty") || desc.includes("group chat was deactivated")) {
|
|
75165
75555
|
return "log_only";
|
|
75166
75556
|
}
|
|
75167
75557
|
return "shutdown";
|
|
@@ -76550,6 +76940,7 @@ var ACCESS_FILE = join47(STATE_DIR, "access.json");
|
|
|
76550
76940
|
var APPROVED_DIR = join47(STATE_DIR, "approved");
|
|
76551
76941
|
var ENV_FILE = join47(STATE_DIR, ".env");
|
|
76552
76942
|
var INBOX_DIR = join47(STATE_DIR, "inbox");
|
|
76943
|
+
var PEOPLE_FILE = join47(STATE_DIR, "people.json");
|
|
76553
76944
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
76554
76945
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
76555
76946
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -76823,6 +77214,18 @@ var BOOT_ACCESS = STATIC ? (() => {
|
|
|
76823
77214
|
function loadAccess() {
|
|
76824
77215
|
return BOOT_ACCESS ?? readAccessFile();
|
|
76825
77216
|
}
|
|
77217
|
+
function readPeopleFile() {
|
|
77218
|
+
try {
|
|
77219
|
+
const raw = readFileSync45(PEOPLE_FILE, "utf8");
|
|
77220
|
+
const parsed = JSON.parse(raw);
|
|
77221
|
+
if (!Array.isArray(parsed.entries))
|
|
77222
|
+
return [];
|
|
77223
|
+
return parsed.entries;
|
|
77224
|
+
} catch {
|
|
77225
|
+
return [];
|
|
77226
|
+
}
|
|
77227
|
+
}
|
|
77228
|
+
var PERSON_DIRECTORY = { byTelegramKey: {} };
|
|
76826
77229
|
function assertAllowedChat(chat_id) {
|
|
76827
77230
|
const id = String(chat_id);
|
|
76828
77231
|
const access = loadAccess();
|
|
@@ -76999,6 +77402,29 @@ function resolveSubagentOriginChat(agentId) {
|
|
|
76999
77402
|
return null;
|
|
77000
77403
|
}
|
|
77001
77404
|
}
|
|
77405
|
+
var WORKER_FEED_FALLBACK_LOG_CAP = 256;
|
|
77406
|
+
var workerFeedOwnerDmFallbackLogged = new Set;
|
|
77407
|
+
function resolveWorkerFeedChat(agentId, fleetChatId) {
|
|
77408
|
+
const origin = resolveSubagentOriginChat(agentId);
|
|
77409
|
+
if (origin != null && origin.chatId.length > 0)
|
|
77410
|
+
return origin;
|
|
77411
|
+
if (fleetChatId.length > 0)
|
|
77412
|
+
return { chatId: fleetChatId };
|
|
77413
|
+
const ownerDm = loadAccess().allowFrom[0] ?? "";
|
|
77414
|
+
if (origin == null && fleetChatId.length === 0 && ownerDm.length > 0) {
|
|
77415
|
+
if (!workerFeedOwnerDmFallbackLogged.has(agentId)) {
|
|
77416
|
+
workerFeedOwnerDmFallbackLogged.add(agentId);
|
|
77417
|
+
if (workerFeedOwnerDmFallbackLogged.size > WORKER_FEED_FALLBACK_LOG_CAP) {
|
|
77418
|
+
const oldest = workerFeedOwnerDmFallbackLogged.values().next().value;
|
|
77419
|
+
if (oldest != null)
|
|
77420
|
+
workerFeedOwnerDmFallbackLogged.delete(oldest);
|
|
77421
|
+
}
|
|
77422
|
+
process.stderr.write(`telegram gateway: worker-feed origin unresolved agent=${agentId} \u2014 routing card to owner DM
|
|
77423
|
+
`);
|
|
77424
|
+
}
|
|
77425
|
+
}
|
|
77426
|
+
return { chatId: ownerDm, threadId: origin?.threadId };
|
|
77427
|
+
}
|
|
77002
77428
|
var REGISTRY_REAPER_INTERVAL_MS = 21600000;
|
|
77003
77429
|
function runHistoryReaperNow(reason) {
|
|
77004
77430
|
const retentionDays = resolveRetentionDays(HISTORY_ACCESS.historyRetentionDays);
|
|
@@ -77861,7 +78287,12 @@ async function resolveCompactCard(kind, occNow) {
|
|
|
77861
78287
|
try {
|
|
77862
78288
|
await swallowingApiCall(() => bot.api.editMessageText(card.chatId, card.messageId, richMessage2(text5), {}), { chat_id: card.chatId, verb: `proactiveCompact.${kind}` });
|
|
77863
78289
|
} catch (err) {
|
|
77864
|
-
|
|
78290
|
+
const desc = err instanceof Error ? err.message : String(err);
|
|
78291
|
+
const low = desc.toLowerCase();
|
|
78292
|
+
if (low.includes("not modified") || low.includes("not found") || low.includes("can't be edited") || low.includes("cannot be edited") || low.includes("not enough rights") || low.includes("429") || low.includes("retry after")) {
|
|
78293
|
+
return;
|
|
78294
|
+
}
|
|
78295
|
+
process.stderr.write(`telegram gateway: proactive-compact ${kind} card edit failed: ${desc}
|
|
77865
78296
|
`);
|
|
77866
78297
|
}
|
|
77867
78298
|
}
|
|
@@ -82387,7 +82818,9 @@ async function drainActivitySummary(turn, producer = "tool", openFlags) {
|
|
|
82387
82818
|
turn.activityLastSentRender = target;
|
|
82388
82819
|
} catch (err) {
|
|
82389
82820
|
const msg = err instanceof Error ? err.message : String(err);
|
|
82390
|
-
|
|
82821
|
+
const low = msg.toLowerCase();
|
|
82822
|
+
const isTransport = low.includes("not modified") || low.includes("not found") || low.includes("can't be edited") || low.includes("cannot be edited") || low.includes("not enough rights") || low.includes("429") || low.includes("retry after");
|
|
82823
|
+
if (!isTransport) {
|
|
82391
82824
|
turn.activityDrainFailures += 1;
|
|
82392
82825
|
process.stderr.write(`telegram gateway: activity-summary drain failed: ${msg} (chat=${chat} thread=${thread ?? "-"} replyAnchor=${turn.sourceMessageId ?? "none"} everOpened=${turn.activityEverOpened} failures=${turn.activityDrainFailures})
|
|
82393
82826
|
`);
|
|
@@ -82558,7 +82991,12 @@ function clearActivitySummary(turn, finalHtmlOverride) {
|
|
|
82558
82991
|
try {
|
|
82559
82992
|
await robustApiCall(() => bot.api.deleteMessage(chat, id), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.delete" });
|
|
82560
82993
|
} catch (err) {
|
|
82561
|
-
|
|
82994
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
82995
|
+
const low = msg.toLowerCase();
|
|
82996
|
+
if (low.includes("not modified") || low.includes("not found") || low.includes("not enough rights") || low.includes("429") || low.includes("retry after")) {
|
|
82997
|
+
return;
|
|
82998
|
+
}
|
|
82999
|
+
process.stderr.write(`telegram gateway: activity-summary delete failed: ${msg}
|
|
82562
83000
|
`);
|
|
82563
83001
|
}
|
|
82564
83002
|
return;
|
|
@@ -82580,10 +83018,12 @@ function clearActivitySummary(turn, finalHtmlOverride) {
|
|
|
82580
83018
|
await robustApiCall(() => bot.api.editMessageText(chat, id, richMessage2(finalHtml), {}), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.finalize" });
|
|
82581
83019
|
} catch (err) {
|
|
82582
83020
|
const msg = err instanceof Error ? err.message : String(err);
|
|
82583
|
-
|
|
82584
|
-
|
|
82585
|
-
|
|
83021
|
+
const low = msg.toLowerCase();
|
|
83022
|
+
if (low.includes("not modified") || low.includes("not found") || low.includes("can't be edited") || low.includes("cannot be edited") || low.includes("not enough rights") || low.includes("429") || low.includes("retry after")) {
|
|
83023
|
+
return;
|
|
82586
83024
|
}
|
|
83025
|
+
process.stderr.write(`telegram gateway: activity-summary finalize failed: ${msg}
|
|
83026
|
+
`);
|
|
82587
83027
|
}
|
|
82588
83028
|
});
|
|
82589
83029
|
}
|
|
@@ -84192,12 +84632,19 @@ ${preBlock(write.output)}`;
|
|
|
84192
84632
|
}
|
|
84193
84633
|
const originTurnId = deriveTurnId(chat_id, messageThreadId ?? null, msgId);
|
|
84194
84634
|
const topicScope = TOPIC_FRAMING_ENABLED && messageThreadId != null ? "This message belongs to the current topic only \u2014 answer ONLY this question, in this topic. Do not also answer a pending message from another topic." : undefined;
|
|
84635
|
+
const rawUser = from.username ?? String(from.id);
|
|
84636
|
+
const displayUser = safeResolvePersonName(PERSON_DIRECTORY, {
|
|
84637
|
+
telegramId: String(from.id),
|
|
84638
|
+
username: from.username,
|
|
84639
|
+
isDm: isDmChatId(chat_id),
|
|
84640
|
+
groupAllowFrom: access.groups[chat_id]?.allowFrom
|
|
84641
|
+
}, rawUser);
|
|
84195
84642
|
const inboundMsg = {
|
|
84196
84643
|
type: "inbound",
|
|
84197
84644
|
chatId: chat_id,
|
|
84198
84645
|
...messageThreadId != null ? { threadId: messageThreadId } : {},
|
|
84199
84646
|
messageId: msgId ?? 0,
|
|
84200
|
-
user:
|
|
84647
|
+
user: displayUser,
|
|
84201
84648
|
userId: from.id,
|
|
84202
84649
|
ts: ctx.message?.date ?? Math.floor(Date.now() / 1000),
|
|
84203
84650
|
text: effectiveText,
|
|
@@ -84212,7 +84659,7 @@ ${preBlock(write.output)}`;
|
|
|
84212
84659
|
meta: {
|
|
84213
84660
|
chat_id,
|
|
84214
84661
|
...msgId != null ? { message_id: String(msgId) } : {},
|
|
84215
|
-
user:
|
|
84662
|
+
user: displayUser,
|
|
84216
84663
|
user_id: String(from.id),
|
|
84217
84664
|
ts: new Date((ctx.message?.date ?? 0) * 1000).toISOString(),
|
|
84218
84665
|
...messageThreadId != null ? { message_thread_id: String(messageThreadId) } : {},
|
|
@@ -87729,14 +88176,14 @@ _Tap /auth to see updated quota for the new active account._`), {}), { chat_id:
|
|
|
87729
88176
|
const probeResp = state4.accounts.length > 0 ? await client3.probeQuota(state4.accounts.map((a) => a.label), undefined, true).catch(() => ({ results: [] })) : { results: [] };
|
|
87730
88177
|
const { quotas, staleCachedAtMs } = zipProbeResults(state4.accounts.map((a) => a.label), probeResp.results);
|
|
87731
88178
|
const tz = process.env.SWITCHROOM_TIMEZONE ?? process.env.TZ ?? "UTC";
|
|
87732
|
-
const { renderAuthSnapshotFormat2: renderAuthSnapshotFormat23, buildSnapshotsFromState: buildSnapshotsFromState4, buildSnapshotKeyboard: buildSnapshotKeyboard3 } = await Promise.resolve().then(() => (
|
|
88179
|
+
const { renderAuthSnapshotFormat2: renderAuthSnapshotFormat23, buildSnapshotsFromState: buildSnapshotsFromState4, buildSnapshotKeyboard: buildSnapshotKeyboard3 } = await Promise.resolve().then(() => (init_auth_snapshot_format2(), exports_auth_snapshot_format));
|
|
87733
88180
|
const snapshots = buildSnapshotsFromState4(state4, quotas);
|
|
87734
88181
|
const renderNow = new Date;
|
|
87735
88182
|
const text5 = renderAuthSnapshotFormat23(snapshots, {
|
|
87736
88183
|
tz,
|
|
87737
88184
|
now: renderNow,
|
|
87738
88185
|
demo: refreshDemo,
|
|
87739
|
-
...staleCachedAtMs != null ? { staleCachedAtMs } : { liveProbedAtMs: renderNow.getTime() }
|
|
88186
|
+
...staleCachedAtMs != null ? { staleCachedAtMs } : probeResp.results.length > 0 ? { liveProbedAtMs: renderNow.getTime() } : { probeFailed: true }
|
|
87740
88187
|
});
|
|
87741
88188
|
const kbRows = buildSnapshotKeyboard3(snapshots, { now: renderNow, demo: refreshDemo });
|
|
87742
88189
|
const inline_keyboard = kbRows.map((row) => row.map((b) => {
|
|
@@ -88118,16 +88565,17 @@ bot.command("usage", async (ctx) => {
|
|
|
88118
88565
|
if (client3) {
|
|
88119
88566
|
const state4 = await client3.listState();
|
|
88120
88567
|
if (state4.accounts.length > 0) {
|
|
88568
|
+
const renderNow = new Date;
|
|
88121
88569
|
const probeResp = await client3.probeQuota(state4.accounts.map((a) => a.label)).catch(() => ({ results: [] }));
|
|
88122
88570
|
const { quotas, staleCachedAtMs } = zipProbeResults(state4.accounts.map((a) => a.label), probeResp.results);
|
|
88123
|
-
const {
|
|
88124
|
-
const
|
|
88571
|
+
const { buildSnapshotsFromState: buildSnapshotsFromState4, buildSnapshotKeyboard: buildSnapshotKeyboard3 } = await Promise.resolve().then(() => (init_auth_snapshot_format2(), exports_auth_snapshot_format));
|
|
88572
|
+
const { renderUsageCard: renderUsageCard2 } = await Promise.resolve().then(() => (init_quota_bar_format(), exports_quota_bar_format));
|
|
88125
88573
|
const snapshots = buildSnapshotsFromState4(state4, quotas);
|
|
88126
|
-
const
|
|
88127
|
-
|
|
88128
|
-
now:
|
|
88574
|
+
const exhaustedByLabel = new Map(state4.accounts.map((a) => [a.label, a.exhausted]));
|
|
88575
|
+
const text5 = renderUsageCard2(snapshots, exhaustedByLabel, {
|
|
88576
|
+
now: renderNow,
|
|
88129
88577
|
demo,
|
|
88130
|
-
...staleCachedAtMs != null ? { staleCachedAtMs } : { liveProbedAtMs:
|
|
88578
|
+
...staleCachedAtMs != null ? { staleCachedAtMs } : probeResp.results.length > 0 ? { liveProbedAtMs: renderNow.getTime() } : { probeFailed: true }
|
|
88131
88579
|
});
|
|
88132
88580
|
const kbRows = buildSnapshotKeyboard3(snapshots, { now: new Date, demo });
|
|
88133
88581
|
const keyboard = new import_grammy12.InlineKeyboard;
|
|
@@ -89970,6 +90418,21 @@ var didOneTimeSetup = false;
|
|
|
89970
90418
|
`);
|
|
89971
90419
|
if (!didOneTimeSetup) {
|
|
89972
90420
|
didOneTimeSetup = true;
|
|
90421
|
+
{
|
|
90422
|
+
const bootCheck = runPersonDirectoryBootCheck(readPeopleFile);
|
|
90423
|
+
PERSON_DIRECTORY = bootCheck.directory;
|
|
90424
|
+
process.stderr.write(bootCheck.logLine + `
|
|
90425
|
+
`);
|
|
90426
|
+
if (bootCheck.alertDetail != null) {
|
|
90427
|
+
emitGatewayOperatorEvent({
|
|
90428
|
+
kind: "config-warning",
|
|
90429
|
+
agent: process.env.SWITCHROOM_AGENT_NAME ?? "-",
|
|
90430
|
+
detail: bootCheck.alertDetail,
|
|
90431
|
+
suggestedActions: [],
|
|
90432
|
+
firstSeenAt: new Date
|
|
90433
|
+
});
|
|
90434
|
+
}
|
|
90435
|
+
}
|
|
89973
90436
|
registerSwitchroomBotCommands().catch(() => {});
|
|
89974
90437
|
try {
|
|
89975
90438
|
const accessAtBoot = loadAccess();
|
|
@@ -90459,8 +90922,8 @@ var didOneTimeSetup = false;
|
|
|
90459
90922
|
orphanStatusEnabled
|
|
90460
90923
|
});
|
|
90461
90924
|
if (surface === "worker-feed") {
|
|
90462
|
-
const
|
|
90463
|
-
const wkChat =
|
|
90925
|
+
const wk = resolveWorkerFeedChat(agentId, fleetChatId);
|
|
90926
|
+
const wkChat = wk.chatId;
|
|
90464
90927
|
workerActivityFeed?.update(agentId, wkChat, {
|
|
90465
90928
|
description: dispatch.feedDescription,
|
|
90466
90929
|
lastTool,
|
|
@@ -90468,7 +90931,7 @@ var didOneTimeSetup = false;
|
|
|
90468
90931
|
latestSummary: stepLine,
|
|
90469
90932
|
elapsedMs,
|
|
90470
90933
|
state: "running"
|
|
90471
|
-
},
|
|
90934
|
+
}, wk.threadId)?.then(() => reconcileWorkerPin(agentId, wkChat, true));
|
|
90472
90935
|
return;
|
|
90473
90936
|
}
|
|
90474
90937
|
if (surface !== "nest")
|
|
@@ -90517,8 +90980,8 @@ var didOneTimeSetup = false;
|
|
|
90517
90980
|
stampTurn.subagentActivityAt = Date.now();
|
|
90518
90981
|
}
|
|
90519
90982
|
if (workerFeedEnabled) {
|
|
90520
|
-
const
|
|
90521
|
-
const wkChat =
|
|
90983
|
+
const wk = resolveWorkerFeedChat(agentId, fleetChatId);
|
|
90984
|
+
const wkChat = wk.chatId;
|
|
90522
90985
|
workerActivityFeed?.update(agentId, wkChat, {
|
|
90523
90986
|
description: dispatch.feedDescription,
|
|
90524
90987
|
lastTool,
|
|
@@ -90526,7 +90989,7 @@ var didOneTimeSetup = false;
|
|
|
90526
90989
|
latestSummary: stepLine,
|
|
90527
90990
|
elapsedMs,
|
|
90528
90991
|
state: "running"
|
|
90529
|
-
},
|
|
90992
|
+
}, wk.threadId)?.then(() => reconcileWorkerPin(agentId, wkChat, true));
|
|
90530
90993
|
return;
|
|
90531
90994
|
}
|
|
90532
90995
|
const progressOrigin = resolveSubagentOriginChat(agentId);
|