@bakapiano/ccsm 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bakapiano/ccsm",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Claude Code Session Manager — Windows web UI to manage many concurrent claude sessions: live list, snapshot/restore, focus existing window, new session in an isolated workspace with repo clones",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "server.js",
|
|
@@ -13,13 +13,48 @@
|
|
|
13
13
|
import { html } from '../html.js';
|
|
14
14
|
import { useEffect, useState } from 'preact/hooks';
|
|
15
15
|
import { serverHealth } from '../state.js';
|
|
16
|
-
import { refreshAll } from '../api.js';
|
|
16
|
+
import { refreshAll, pollHealth } from '../api.js';
|
|
17
17
|
import { BrandMark } from '../icons.js';
|
|
18
18
|
|
|
19
|
+
// Silent ccsm:// launch via hidden iframe. Same trick as the router.
|
|
20
|
+
// If the protocol is registered AND the user has already OK'd the
|
|
21
|
+
// Windows confirmation prompt, ccsm wakes up within ~2s and the
|
|
22
|
+
// banner auto-dismisses on the next health poll. On a cold first
|
|
23
|
+
// visit (protocol not registered, or "Always allow" not yet ticked),
|
|
24
|
+
// the iframe noops silently and the manual "Start ccsm" button is
|
|
25
|
+
// still there as fallback.
|
|
26
|
+
function silentProtocolLaunch() {
|
|
27
|
+
try {
|
|
28
|
+
const f = document.createElement('iframe');
|
|
29
|
+
f.style.display = 'none';
|
|
30
|
+
f.src = 'ccsm://start';
|
|
31
|
+
document.body.appendChild(f);
|
|
32
|
+
setTimeout(() => { try { f.remove(); } catch {} }, 1500);
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
export function OfflineBanner() {
|
|
20
37
|
const h = serverHealth.value;
|
|
21
38
|
const offline = h.state === 'offline';
|
|
22
39
|
const [clicked, setClicked] = useState(false);
|
|
40
|
+
const [autoTried, setAutoTried] = useState(false);
|
|
41
|
+
|
|
42
|
+
// First time we see offline state, try a silent ccsm:// launch and
|
|
43
|
+
// tighten the health-poll cadence for a few seconds so the redirect
|
|
44
|
+
// happens within ~2-3s without any visible UI flash.
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!offline || autoTried) return;
|
|
47
|
+
setAutoTried(true);
|
|
48
|
+
silentProtocolLaunch();
|
|
49
|
+
let n = 0;
|
|
50
|
+
const tick = async () => {
|
|
51
|
+
if (n++ > 12) return; // ~6s of tight polling
|
|
52
|
+
await pollHealth();
|
|
53
|
+
if (serverHealth.value.state === 'online') return;
|
|
54
|
+
setTimeout(tick, 500);
|
|
55
|
+
};
|
|
56
|
+
setTimeout(tick, 500);
|
|
57
|
+
}, [offline]);
|
|
23
58
|
|
|
24
59
|
useEffect(() => {
|
|
25
60
|
if (h.state === 'online' && clicked) {
|