switchroom 0.15.33 → 0.15.34

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.
@@ -50574,8 +50574,8 @@ var {
50574
50574
  } = import__.default;
50575
50575
 
50576
50576
  // src/build-info.ts
50577
- var VERSION = "0.15.33";
50578
- var COMMIT_SHA = "9681f212";
50577
+ var VERSION = "0.15.34";
50578
+ var COMMIT_SHA = "508eb512";
50579
50579
 
50580
50580
  // src/cli/agent.ts
50581
50581
  init_source();
@@ -1015,23 +1015,41 @@
1015
1015
  return provLine + body;
1016
1016
  }
1017
1017
 
1018
- async function fetchConnections() {
1019
- // Each fetch falls back independently (.catch → default). A single
1020
- // network blip — e.g. one endpoint momentarily unreachable — must NOT
1021
- // reject the whole batch and blank the connected accounts; the others
1022
- // still render. (Previously a bare Promise.all meant any one failure
1023
- // wiped the tab, so a connected Google/Microsoft account "vanished".)
1024
- const safe = (p, fallback) => p.then(r => r.ok ? r.json() : fallback).catch(() => fallback);
1018
+ async function fetchConnections(opts) {
1019
+ opts = opts || {};
1020
+ const attempt = opts.attempt || 0;
1021
+ // Distinguish a FAILED fetch from a genuinely-empty result. The old
1022
+ // `safe` collapsed both to []/{}, so a transient broker/web blip
1023
+ // rendered identically to "nothing configured" and because this tab
1024
+ // fetches only on open (NOT the 10s fleet poll), a one-time failure
1025
+ // stuck until a manual re-click. Track ok per fetch so renderConnections
1026
+ // can show an honest "couldn't load" state, and self-heal with bounded
1027
+ // retries. (A single endpoint failing still renders the others.)
1028
+ const safe = (p, fallback) => p
1029
+ .then(r => r.ok ? r.json().then(d => ({ ok: true, data: d })) : { ok: false, data: fallback })
1030
+ .catch(() => ({ ok: false, data: fallback }));
1025
1031
  try {
1026
- const [google, microsoft, notion, agents] = await Promise.all([
1032
+ const [g, ms, n, ag] = await Promise.all([
1027
1033
  safe(fetch(`${API}/api/google-accounts`, { headers: authHeaders() }), []),
1028
1034
  safe(fetch(`${API}/api/microsoft-accounts`, { headers: authHeaders() }), []),
1029
1035
  safe(fetch(`${API}/api/notion-workspace`, { headers: authHeaders() }), { configured: false, databases: [] }),
1030
1036
  safe(fetch(`${API}/api/agents`, { headers: authHeaders() }), []),
1031
1037
  ]);
1032
- const agentNames = (agents || []).map(a => a.name).sort();
1033
- renderConnections({ google, microsoft, notion, agentNames });
1038
+ // Notion legitimately reports unconfigured not a failure. The OAuth
1039
+ // providers + the agent list are the ones whose failure must not read
1040
+ // as "empty".
1041
+ const fetchFailed = !g.ok || !ms.ok || !ag.ok;
1042
+ renderConnections({
1043
+ google: g.data, microsoft: ms.data, notion: n.data,
1044
+ agentNames: (ag.data || []).map(a => a.name).sort(),
1045
+ googleFailed: !g.ok, microsoftFailed: !ms.ok, fetchFailed,
1046
+ });
1034
1047
  clearError();
1048
+ // Self-heal a transient blip without a manual re-click. Bounded
1049
+ // backoff (3s, 6s, 9s); stops the instant a fetch succeeds.
1050
+ if (fetchFailed && attempt < 3) {
1051
+ setTimeout(() => fetchConnections({ attempt: attempt + 1 }), 3000 * (attempt + 1));
1052
+ }
1035
1053
  } catch (err) {
1036
1054
  showError(`Failed to fetch connections: ${err.message}`);
1037
1055
  }
@@ -1566,6 +1584,14 @@
1566
1584
  detail: 'These accounts are from the config; the broker did not return live slot state, so connection status may be stale.',
1567
1585
  remediation: { kind: 'none', label: 'Refresh the tab once the broker is reachable to see live status.' },
1568
1586
  };
1587
+ case 'connections-unreachable':
1588
+ return {
1589
+ title: "Couldn't load live connection data — retrying",
1590
+ detail: 'The dashboard could not reach the account data source (the broker or web container may be restarting). ' +
1591
+ 'This is NOT "no accounts configured" — your connected accounts are unchanged. ' +
1592
+ 'Auto-retrying; the tab fills in once it recovers.',
1593
+ remediation: { kind: 'none', label: 'Or refresh the page if it persists.' },
1594
+ };
1569
1595
  default:
1570
1596
  return { title: String(kind || 'Problem'), remediation: { kind: 'none' } };
1571
1597
  }
@@ -2093,13 +2119,21 @@
2093
2119
  const notion = data.notion || { configured: false, databases: [] };
2094
2120
  const agentNames = data.agentNames || [];
2095
2121
 
2122
+ // When a provider's fetch FAILED (not genuinely empty), its empty-state
2123
+ // must say "couldn't load", never "none configured" — otherwise a
2124
+ // transient blip reads as "you have no accounts".
2096
2125
  const googleSection = _connectionSection(
2097
2126
  'Google',
2098
- 'No Google accounts. Add one under <code>google_accounts:</code> and run <code>switchroom auth google account add</code>.',
2127
+ data.googleFailed
2128
+ ? "Couldn't load Google accounts — the data source was unreachable (retrying)."
2129
+ : 'No Google accounts. Add one under <code>google_accounts:</code> and run <code>switchroom auth google account add</code>.',
2099
2130
  google.map(a => renderOAuthAccountCard(a, { showType: false, provider: 'google', agentNames })).join(''),
2100
2131
  );
2101
2132
 
2102
2133
  const msCards = microsoft.map(a => renderOAuthAccountCard(a, { showType: true, provider: 'microsoft', agentNames })).join('');
2134
+ const msEmpty = data.microsoftFailed
2135
+ ? "Couldn't load Microsoft accounts — the data source was unreachable (retrying)."
2136
+ : 'No Microsoft accounts yet — click <b>Connect a Microsoft account</b> above (or <code>/connect microsoft</code> from Telegram).';
2103
2137
  const microsoftSection = `
2104
2138
  <div style="margin-bottom:1.5rem">
2105
2139
  <h3 style="margin:0 0 .6rem;font-size:.95rem;color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em">
@@ -2109,7 +2143,7 @@
2109
2143
  <div id="ms-connect-card"></div>
2110
2144
  ${msCards
2111
2145
  ? `<div class="accounts-grid">${msCards}</div>`
2112
- : `<div class="loading" style="padding:.8rem">No Microsoft accounts yet — click <b>Connect a Microsoft account</b> above (or <code>/connect microsoft</code> from Telegram).</div>`}
2146
+ : `<div class="loading" style="padding:.8rem">${msEmpty}</div>`}
2113
2147
  </div>`;
2114
2148
 
2115
2149
  let notionCards = '';
@@ -2156,7 +2190,14 @@
2156
2190
  ? renderProblem(problemFor('connections-degraded', {}))
2157
2191
  : '';
2158
2192
 
2159
- container.innerHTML = degradedBanner + googleSection + microsoftSection + notionSection;
2193
+ // A failed fetch must NOT masquerade as "nothing configured" — lead
2194
+ // with an honest banner so the operator knows the empty look is a
2195
+ // load failure (auto-retrying), not an absence of accounts.
2196
+ const unreachableBanner = data.fetchFailed
2197
+ ? renderProblem(problemFor('connections-unreachable', {}))
2198
+ : '';
2199
+
2200
+ container.innerHTML = unreachableBanner + degradedBanner + googleSection + microsoftSection + notionSection;
2160
2201
  }
2161
2202
 
2162
2203
  function renderSchedule(data) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.15.33",
3
+ "version": "0.15.34",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54460,10 +54460,10 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
54460
54460
  }
54461
54461
 
54462
54462
  // ../src/build-info.ts
54463
- var VERSION = "0.15.33";
54464
- var COMMIT_SHA = "9681f212";
54465
- var COMMIT_DATE = "2026-06-15T12:48:47Z";
54466
- var LATEST_PR = 2386;
54463
+ var VERSION = "0.15.34";
54464
+ var COMMIT_SHA = "508eb512";
54465
+ var COMMIT_DATE = "2026-06-16T02:47:01Z";
54466
+ var LATEST_PR = 2389;
54467
54467
  var COMMITS_AHEAD_OF_TAG = 0;
54468
54468
 
54469
54469
  // gateway/boot-version.ts