switchroom 0.14.93 → 0.15.0
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.
|
@@ -13560,6 +13560,7 @@ class AuthBroker {
|
|
|
13560
13560
|
listeners = new Map;
|
|
13561
13561
|
refreshTimer = null;
|
|
13562
13562
|
consumerProbeTimer = null;
|
|
13563
|
+
fleetProbeTimer = null;
|
|
13563
13564
|
fetchQuotaImpl;
|
|
13564
13565
|
stateDir;
|
|
13565
13566
|
socketRoot;
|
|
@@ -13641,6 +13642,17 @@ class AuthBroker {
|
|
|
13641
13642
|
}, probeMs);
|
|
13642
13643
|
this.consumerProbeTimer.unref();
|
|
13643
13644
|
}
|
|
13645
|
+
if (probeMs > 0 && process.env.SWITCHROOM_DISABLE_FLEET_QUOTA_PROBE !== "1") {
|
|
13646
|
+
this.fleetQuotaProbeTick().catch((err) => {
|
|
13647
|
+
this.logErr(`fleet-quota-probe (boot) threw: ${err.message}`);
|
|
13648
|
+
});
|
|
13649
|
+
this.fleetProbeTimer = setInterval(() => {
|
|
13650
|
+
this.fleetQuotaProbeTick().catch((err) => {
|
|
13651
|
+
this.logErr(`fleet-quota-probe threw: ${err.message}`);
|
|
13652
|
+
});
|
|
13653
|
+
}, probeMs);
|
|
13654
|
+
this.fleetProbeTimer.unref();
|
|
13655
|
+
}
|
|
13644
13656
|
}
|
|
13645
13657
|
const fanned = this.fanoutAll();
|
|
13646
13658
|
if (fanned.length > 0) {
|
|
@@ -13671,6 +13683,10 @@ class AuthBroker {
|
|
|
13671
13683
|
clearInterval(this.consumerProbeTimer);
|
|
13672
13684
|
this.consumerProbeTimer = null;
|
|
13673
13685
|
}
|
|
13686
|
+
if (this.fleetProbeTimer) {
|
|
13687
|
+
clearInterval(this.fleetProbeTimer);
|
|
13688
|
+
this.fleetProbeTimer = null;
|
|
13689
|
+
}
|
|
13674
13690
|
for (const [sock, lis] of this.listeners) {
|
|
13675
13691
|
try {
|
|
13676
13692
|
lis.server.close();
|
|
@@ -14096,22 +14112,42 @@ class AuthBroker {
|
|
|
14096
14112
|
ok: result.ok,
|
|
14097
14113
|
error: result.ok ? undefined : result.reason
|
|
14098
14114
|
});
|
|
14099
|
-
if (result.ok)
|
|
14100
|
-
this.
|
|
14101
|
-
fiveHourUtilizationPct: result.data.fiveHourUtilizationPct,
|
|
14102
|
-
sevenDayUtilizationPct: result.data.sevenDayUtilizationPct,
|
|
14103
|
-
fiveHourResetAt: result.data.fiveHourResetAt?.toISOString() ?? null,
|
|
14104
|
-
sevenDayResetAt: result.data.sevenDayResetAt?.toISOString() ?? null,
|
|
14105
|
-
representativeClaim: result.data.representativeClaim,
|
|
14106
|
-
overageStatus: result.data.overageStatus,
|
|
14107
|
-
overageDisabledReason: result.data.overageDisabledReason,
|
|
14108
|
-
capturedAt: this.now()
|
|
14109
|
-
};
|
|
14110
|
-
}
|
|
14115
|
+
if (result.ok)
|
|
14116
|
+
this.cacheQuotaSnapshot(label, result);
|
|
14111
14117
|
return { label, result };
|
|
14112
14118
|
}));
|
|
14113
14119
|
socket.write(encodeSuccess(id, { results }));
|
|
14114
14120
|
}
|
|
14121
|
+
cacheQuotaSnapshot(label, result) {
|
|
14122
|
+
if (!result.ok)
|
|
14123
|
+
return;
|
|
14124
|
+
this.lastQuotaCache[label] = {
|
|
14125
|
+
fiveHourUtilizationPct: result.data.fiveHourUtilizationPct,
|
|
14126
|
+
sevenDayUtilizationPct: result.data.sevenDayUtilizationPct,
|
|
14127
|
+
fiveHourResetAt: result.data.fiveHourResetAt?.toISOString() ?? null,
|
|
14128
|
+
sevenDayResetAt: result.data.sevenDayResetAt?.toISOString() ?? null,
|
|
14129
|
+
representativeClaim: result.data.representativeClaim,
|
|
14130
|
+
overageStatus: result.data.overageStatus,
|
|
14131
|
+
overageDisabledReason: result.data.overageDisabledReason,
|
|
14132
|
+
capturedAt: this.now()
|
|
14133
|
+
};
|
|
14134
|
+
}
|
|
14135
|
+
async fleetQuotaProbeTick() {
|
|
14136
|
+
for (const label of listAccounts(this.home)) {
|
|
14137
|
+
const creds = readAccountCredentials(label, this.home);
|
|
14138
|
+
const token = creds?.claudeAiOauth?.accessToken;
|
|
14139
|
+
if (!token)
|
|
14140
|
+
continue;
|
|
14141
|
+
let result;
|
|
14142
|
+
try {
|
|
14143
|
+
result = await this.fetchQuotaImpl({ accessToken: token });
|
|
14144
|
+
} catch (err) {
|
|
14145
|
+
this.logErr(`fleet-quota-probe ${label}: ${err.message}`);
|
|
14146
|
+
continue;
|
|
14147
|
+
}
|
|
14148
|
+
this.cacheQuotaSnapshot(label, result);
|
|
14149
|
+
}
|
|
14150
|
+
}
|
|
14115
14151
|
async consumerQuotaProbeTick() {
|
|
14116
14152
|
const accounts = Array.from(new Set((this.config.auth?.consumers ?? []).map((c) => c.account)));
|
|
14117
14153
|
for (const label of accounts) {
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -49937,8 +49937,8 @@ var {
|
|
|
49937
49937
|
} = import__.default;
|
|
49938
49938
|
|
|
49939
49939
|
// src/build-info.ts
|
|
49940
|
-
var VERSION = "0.
|
|
49941
|
-
var COMMIT_SHA = "
|
|
49940
|
+
var VERSION = "0.15.0";
|
|
49941
|
+
var COMMIT_SHA = "5841c1d5";
|
|
49942
49942
|
|
|
49943
49943
|
// src/cli/agent.ts
|
|
49944
49944
|
init_source();
|
package/dist/cli/ui/index.html
CHANGED
|
@@ -440,15 +440,20 @@
|
|
|
440
440
|
return h;
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
+
// Tolerate a single transient failure on the 10s auto-refresh: one blip
|
|
444
|
+
// (e.g. the web container restarting) shouldn't flash a scary error over a
|
|
445
|
+
// healthy dashboard. Only surface the error after two in a row.
|
|
446
|
+
let agentFetchFails = 0;
|
|
443
447
|
async function fetchAgents() {
|
|
444
448
|
try {
|
|
445
449
|
const res = await fetch(`${API}/api/agents`, { headers: authHeaders() });
|
|
446
450
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
447
451
|
agents = await res.json();
|
|
448
452
|
render();
|
|
453
|
+
agentFetchFails = 0;
|
|
449
454
|
clearError();
|
|
450
455
|
} catch (err) {
|
|
451
|
-
showError(`Failed to fetch agents: ${err.message}`);
|
|
456
|
+
if (++agentFetchFails >= 2) showError(`Failed to fetch agents: ${err.message}`);
|
|
452
457
|
}
|
|
453
458
|
}
|
|
454
459
|
|
|
@@ -494,12 +499,18 @@
|
|
|
494
499
|
}
|
|
495
500
|
|
|
496
501
|
async function fetchConnections() {
|
|
502
|
+
// Each fetch falls back independently (.catch → default). A single
|
|
503
|
+
// network blip — e.g. one endpoint momentarily unreachable — must NOT
|
|
504
|
+
// reject the whole batch and blank the connected accounts; the others
|
|
505
|
+
// still render. (Previously a bare Promise.all meant any one failure
|
|
506
|
+
// wiped the tab, so a connected Google/Microsoft account "vanished".)
|
|
507
|
+
const safe = (p, fallback) => p.then(r => r.ok ? r.json() : fallback).catch(() => fallback);
|
|
497
508
|
try {
|
|
498
509
|
const [google, microsoft, notion, agents] = await Promise.all([
|
|
499
|
-
fetch(`${API}/api/google-accounts`, { headers: authHeaders() })
|
|
500
|
-
fetch(`${API}/api/microsoft-accounts`, { headers: authHeaders() })
|
|
501
|
-
fetch(`${API}/api/notion-workspace`, { headers: authHeaders() })
|
|
502
|
-
fetch(`${API}/api/agents`, { headers: authHeaders() })
|
|
510
|
+
safe(fetch(`${API}/api/google-accounts`, { headers: authHeaders() }), []),
|
|
511
|
+
safe(fetch(`${API}/api/microsoft-accounts`, { headers: authHeaders() }), []),
|
|
512
|
+
safe(fetch(`${API}/api/notion-workspace`, { headers: authHeaders() }), { configured: false, databases: [] }),
|
|
513
|
+
safe(fetch(`${API}/api/agents`, { headers: authHeaders() }), []),
|
|
503
514
|
]);
|
|
504
515
|
const agentNames = (agents || []).map(a => a.name).sort();
|
|
505
516
|
renderConnections({ google, microsoft, notion, agentNames });
|
package/package.json
CHANGED
|
@@ -52971,11 +52971,11 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
|
52971
52971
|
}
|
|
52972
52972
|
|
|
52973
52973
|
// ../src/build-info.ts
|
|
52974
|
-
var VERSION = "0.
|
|
52975
|
-
var COMMIT_SHA = "
|
|
52976
|
-
var COMMIT_DATE = "2026-06-
|
|
52977
|
-
var LATEST_PR =
|
|
52978
|
-
var COMMITS_AHEAD_OF_TAG =
|
|
52974
|
+
var VERSION = "0.15.0";
|
|
52975
|
+
var COMMIT_SHA = "5841c1d5";
|
|
52976
|
+
var COMMIT_DATE = "2026-06-09T23:17:14Z";
|
|
52977
|
+
var LATEST_PR = 2253;
|
|
52978
|
+
var COMMITS_AHEAD_OF_TAG = 0;
|
|
52979
52979
|
|
|
52980
52980
|
// gateway/boot-version.ts
|
|
52981
52981
|
function formatRelativeAgo(iso) {
|