shadok-ai 0.16.6 → 0.16.9
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/README.md +13 -10
- package/package.json +1 -1
- package/public/index.html +39 -31
package/README.md
CHANGED
|
@@ -531,16 +531,19 @@ every 25s (tunable with `SHADOK_WS_PING_MS`) to keep the connection warm, so no
|
|
|
531
531
|
proxy change is normally needed; if your proxy still cuts it, raise
|
|
532
532
|
`proxy_read_timeout` above the ping interval.
|
|
533
533
|
|
|
534
|
-
**Sleep / wake
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
534
|
+
**Sleep / wake / network blips.** When the machine comes back (an `online`
|
|
535
|
+
event, the tab becoming visible, a back/forward-cache restore), the cockpit
|
|
536
|
+
revives the links that actually **dropped** — resetting their backoff so a
|
|
537
|
+
genuinely-closed socket reconnects promptly instead of waiting out a delay that
|
|
538
|
+
climbed while you were away. A socket that still reports "open" is left alone:
|
|
539
|
+
`online` fires on every network blip (wifi roam, VPN, interface change), and
|
|
540
|
+
force-reconnecting healthy links on each one reconnected all your agents at
|
|
541
|
+
once — tripping the upstream single-use-token OAuth refresh race so a batch
|
|
542
|
+
stuck on "connecting…". A slept socket that looks "open" but is dead is
|
|
543
|
+
terminated by the server heartbeat (~50s) and reconnects on the resulting
|
|
544
|
+
`close` without that churn. Only a back/forward-cache restore force-replaces an
|
|
545
|
+
"open" socket, because there the restored page's old sockets are dead yet fire
|
|
546
|
+
no `close`.
|
|
544
547
|
|
|
545
548
|
### Cross-instance peers
|
|
546
549
|
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -2272,6 +2272,20 @@
|
|
|
2272
2272
|
.tab .lastat, .tab .ctxnum { font-size: 11px; color: var(--text-dim); }
|
|
2273
2273
|
.tab.active { border-left: 0; border-radius: 6px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); background: var(--bg-raised); font-weight: 600; }
|
|
2274
2274
|
:root:not([data-mode="light"]) .tab.active { background: var(--bg-inset); box-shadow: inset 0 0 0 1px var(--line); }
|
|
2275
|
+
/* A working agent must stay visible in light mode. Two things hid it: 12% of
|
|
2276
|
+
the accent over a near-white panel is barely a tint, and the white
|
|
2277
|
+
`.tab.active` above comes later at the same weight, so the agent you are
|
|
2278
|
+
watching — the one most likely to be working — went plain white. The tint
|
|
2279
|
+
is mixed INTO the surface (opaque) and the selectors outweigh both
|
|
2280
|
+
`.tab.active` rules, so the active tab keeps its state colour in either mode.
|
|
2281
|
+
`background-COLOR`, never the shorthand: `background` expands to
|
|
2282
|
+
`background-image: none`, and these selectors outweigh `.tab.has-bg`, so the
|
|
2283
|
+
shorthand silently erased the green hatch of an agent with background work
|
|
2284
|
+
still running (measured: light mode, a working non-active row lost it). */
|
|
2285
|
+
:root[data-mode="light"] .tab.working,
|
|
2286
|
+
:root[data-mode="light"] .rail-item.working { background-color: color-mix(in srgb, var(--amber) 22%, var(--bg-raised)); }
|
|
2287
|
+
:root[data-mode="light"] .tab.working.active { background-color: color-mix(in srgb, var(--amber) 18%, var(--bg-raised)); }
|
|
2288
|
+
:root:not([data-mode="light"]) .tab.working.active { background-color: color-mix(in srgb, var(--amber) 16%, var(--bg-inset)); }
|
|
2275
2289
|
.tab.active .tav .led { border-color: var(--bg-raised); }
|
|
2276
2290
|
.tab.unread { border-left: 0; border-radius: 6px; font-weight: 700; }
|
|
2277
2291
|
.group-head { gap: 10px; padding: 8px; font-size: 14px; color: var(--text); border-radius: 6px; }
|
|
@@ -7081,51 +7095,45 @@
|
|
|
7081
7095
|
// off. Bounded so an update that never lands doesn't leave us hammering.
|
|
7082
7096
|
let reloadExpectedUntil = 0;
|
|
7083
7097
|
|
|
7084
|
-
/**
|
|
7085
|
-
*
|
|
7086
|
-
*
|
|
7087
|
-
*
|
|
7088
|
-
*
|
|
7089
|
-
*
|
|
7090
|
-
*
|
|
7091
|
-
*
|
|
7092
|
-
*
|
|
7098
|
+
/** Revive the tabs whose link actually DROPPED — fired when the machine/tab
|
|
7099
|
+
* comes back (online / visible). It resets the backoff and reconnects at
|
|
7100
|
+
* once, so a genuinely-closed socket comes back promptly instead of waiting
|
|
7101
|
+
* out an exponential delay that climbed while we were away.
|
|
7102
|
+
*
|
|
7103
|
+
* It deliberately does NOT touch a socket that still reports OPEN. An earlier
|
|
7104
|
+
* version force-replaced OPEN sockets too (to catch a laptop-sleep "zombie" —
|
|
7105
|
+
* OPEN on the client, dead on the wire). But `online` fires on EVERY network
|
|
7106
|
+
* blip (wifi roam, VPN, interface change), and force-closing every healthy
|
|
7107
|
+
* link on each blip reconnected all N agents at once — tripping the upstream
|
|
7108
|
+
* OAuth refresh-token race (single-use tokens, concurrent `claude --resume`,
|
|
7109
|
+
* biting at ~10–30 agents) so a whole batch stuck on "connecting…". That mass
|
|
7110
|
+
* churn was worse than the zombie it chased: a slept socket is terminated by
|
|
7111
|
+
* the server heartbeat (~50s) and the resulting `close` reconnects it anyway,
|
|
7112
|
+
* no force needed. `force` is kept ONLY for a bfcache `pageshow`, where the
|
|
7113
|
+
* restored page's old sockets are genuinely dead and fire no `close`. */
|
|
7093
7114
|
function reconnectAllNow(force) {
|
|
7094
7115
|
for (const t of tabs) {
|
|
7095
7116
|
if (t.closing || !t.sessionId) continue;
|
|
7096
7117
|
const st = t.ws && t.ws.readyState;
|
|
7097
7118
|
if (st === WebSocket.CONNECTING) continue; // a link is already on its way
|
|
7098
|
-
if (st === WebSocket.OPEN && !force) continue; // healthy
|
|
7119
|
+
if (st === WebSocket.OPEN && !force) continue; // healthy — leave it, a blip is not a death
|
|
7099
7120
|
if (t.reconnectTimer) clearTimeout(t.reconnectTimer);
|
|
7100
|
-
t.reconnectAttempts = 0;
|
|
7121
|
+
t.reconnectAttempts = 0; // reset the backoff: reconnect promptly, not after a climbed delay
|
|
7101
7122
|
const old = t.ws;
|
|
7102
7123
|
openLink(t); // replaces t.ws with the fresh socket
|
|
7103
|
-
// Close
|
|
7124
|
+
// Close a forced (bfcache) zombie only after openLink swapped t.ws, so its
|
|
7104
7125
|
// `close` handler sees `t.ws !== ws` and does not schedule a competing
|
|
7105
7126
|
// reconnect. A no-op when `old` was already closed.
|
|
7106
7127
|
if (old && old !== t.ws) { try { old.close(); } catch {} }
|
|
7107
7128
|
}
|
|
7108
7129
|
}
|
|
7109
7130
|
|
|
7110
|
-
//
|
|
7111
|
-
//
|
|
7112
|
-
//
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
const STALE_WAKE_MS = 10_000;
|
|
7117
|
-
let hiddenAt = 0;
|
|
7118
|
-
function wokeAfterLongAway() {
|
|
7119
|
-
const away = hiddenAt ? Date.now() - hiddenAt : 0;
|
|
7120
|
-
hiddenAt = 0;
|
|
7121
|
-
return away > STALE_WAKE_MS;
|
|
7122
|
-
}
|
|
7123
|
-
window.addEventListener("online", () => reconnectAllNow(true));
|
|
7124
|
-
window.addEventListener("pageshow", (e) => reconnectAllNow(!!e.persisted || wokeAfterLongAway()));
|
|
7125
|
-
document.addEventListener("visibilitychange", () => {
|
|
7126
|
-
if (document.hidden) { hiddenAt = Date.now(); return; }
|
|
7127
|
-
reconnectAllNow(wokeAfterLongAway());
|
|
7128
|
-
});
|
|
7131
|
+
// Reconnect the links that dropped while we were away — but never disturb a
|
|
7132
|
+
// healthy one (see reconnectAllNow). Only a bfcache restore forces, because
|
|
7133
|
+
// there the old sockets are dead yet fire no `close`.
|
|
7134
|
+
window.addEventListener("online", () => reconnectAllNow(false));
|
|
7135
|
+
window.addEventListener("pageshow", (e) => reconnectAllNow(!!e.persisted));
|
|
7136
|
+
document.addEventListener("visibilitychange", () => { if (!document.hidden) reconnectAllNow(false); });
|
|
7129
7137
|
|
|
7130
7138
|
/**
|
|
7131
7139
|
* Lists the agents alive in the server right now — including ones spawned
|