@bakapiano/ccsm 0.22.5 → 0.22.7
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/CLAUDE.md +538 -538
- package/README.md +189 -189
- package/bin/ccsm.js +235 -235
- package/lib/cliActivity.js +139 -139
- package/lib/codexSeed.js +183 -183
- package/lib/config.js +279 -274
- package/lib/devices.js +229 -229
- package/lib/folders.js +124 -124
- package/lib/localCliSessions.js +519 -519
- package/lib/persistedSessions.js +129 -129
- package/lib/tunnel.js +621 -621
- package/lib/webTerminal.js +225 -225
- package/lib/workspace.js +233 -233
- package/package.json +57 -57
- package/public/css/base.css +99 -99
- package/public/css/cards.css +183 -183
- package/public/css/feedback.css +504 -504
- package/public/css/forms.css +453 -453
- package/public/css/layout.css +177 -176
- package/public/css/modal.css +190 -190
- package/public/css/responsive.css +176 -176
- package/public/css/sidebar.css +707 -707
- package/public/css/terminals.css +547 -553
- package/public/css/tokens.css +81 -81
- package/public/css/wco.css +196 -196
- package/public/css/widgets.css +2725 -2725
- package/public/index.html +152 -152
- package/public/js/api.js +371 -371
- package/public/js/backend.js +149 -149
- package/public/js/components/App.js +73 -73
- package/public/js/components/DirectoryPicker.js +203 -203
- package/public/js/components/EntityFormModal.js +153 -153
- package/public/js/components/Modal.js +57 -57
- package/public/js/components/OfflineBanner.js +67 -67
- package/public/js/components/PageTitleBar.js +13 -13
- package/public/js/components/PendingApprovalOverlay.js +128 -128
- package/public/js/components/Picker.js +179 -179
- package/public/js/components/Popover.js +55 -55
- package/public/js/components/RestartOverlay.js +36 -36
- package/public/js/components/Sidebar.js +380 -380
- package/public/js/components/TerminalInstance.js +28 -9
- package/public/js/components/XtermTerminal.js +62 -2
- package/public/js/components/useDragSort.js +67 -67
- package/public/js/dialog.js +67 -67
- package/public/js/icons.js +212 -212
- package/public/js/main.js +296 -296
- package/public/js/pages/AboutPage.js +90 -90
- package/public/js/pages/ConfigurePage.js +728 -713
- package/public/js/pages/LaunchPage.js +421 -421
- package/public/js/pages/RemotePage.js +743 -743
- package/public/js/pages/SessionsPage.js +73 -80
- package/public/js/state.js +335 -335
- package/scripts/dev.js +149 -149
- package/scripts/install.js +153 -153
- package/scripts/restart-helper.js +96 -96
- package/scripts/upgrade-helper.js +687 -687
- package/server.js +1820 -1807
- package/public/manifest.webmanifest +0 -25
- package/public/setup/index.html +0 -567
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
// Tiny popover primitive — positions a floating panel relative to an
|
|
2
|
-
// anchor element, closes on outside click + Escape. Used by the unified
|
|
3
|
-
// pickers (CLI / Folder / Repo) so they all share interaction behavior.
|
|
4
|
-
//
|
|
5
|
-
// Usage:
|
|
6
|
-
// const [open, setOpen] = useState(false);
|
|
7
|
-
// const anchor = useRef(null);
|
|
8
|
-
// <button ref=${anchor} onClick=${() => setOpen(true)}>Trigger</button>
|
|
9
|
-
// ${open ? html`<${Popover} anchor=${anchor} onClose=${() => setOpen(false)}>
|
|
10
|
-
// ...panel contents...
|
|
11
|
-
// </${Popover}>` : null}
|
|
12
|
-
|
|
13
|
-
import { html } from '../html.js';
|
|
14
|
-
import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
|
|
15
|
-
import { createPortal } from 'preact/compat';
|
|
16
|
-
|
|
17
|
-
export function Popover({ anchor, onClose, align = 'left', width, children }) {
|
|
18
|
-
const panelRef = useRef(null);
|
|
19
|
-
const [pos, setPos] = useState({ top: 0, left: 0, width: width || 320 });
|
|
20
|
-
|
|
21
|
-
useLayoutEffect(() => {
|
|
22
|
-
const a = anchor && anchor.current;
|
|
23
|
-
if (!a) return;
|
|
24
|
-
const rect = a.getBoundingClientRect();
|
|
25
|
-
const w = width || Math.max(rect.width, 320);
|
|
26
|
-
let left = align === 'right' ? rect.right - w : rect.left;
|
|
27
|
-
// Clamp to viewport with 8px margin.
|
|
28
|
-
left = Math.max(8, Math.min(window.innerWidth - w - 8, left));
|
|
29
|
-
const top = rect.bottom + 6;
|
|
30
|
-
setPos({ top, left, width: w });
|
|
31
|
-
}, [anchor, align, width]);
|
|
32
|
-
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
const onDown = (ev) => {
|
|
35
|
-
if (panelRef.current?.contains(ev.target)) return;
|
|
36
|
-
if (anchor.current?.contains(ev.target)) return;
|
|
37
|
-
onClose?.();
|
|
38
|
-
};
|
|
39
|
-
const onKey = (ev) => { if (ev.key === 'Escape') onClose?.(); };
|
|
40
|
-
document.addEventListener('mousedown', onDown, true);
|
|
41
|
-
document.addEventListener('keydown', onKey, true);
|
|
42
|
-
return () => {
|
|
43
|
-
document.removeEventListener('mousedown', onDown, true);
|
|
44
|
-
document.removeEventListener('keydown', onKey, true);
|
|
45
|
-
};
|
|
46
|
-
}, [anchor, onClose]);
|
|
47
|
-
|
|
48
|
-
return createPortal(
|
|
49
|
-
html`<div ref=${panelRef} class="popover-panel"
|
|
50
|
-
style=${`top:${pos.top}px;left:${pos.left}px;width:${pos.width}px;`}>
|
|
51
|
-
${children}
|
|
52
|
-
</div>`,
|
|
53
|
-
document.body
|
|
54
|
-
);
|
|
55
|
-
}
|
|
1
|
+
// Tiny popover primitive — positions a floating panel relative to an
|
|
2
|
+
// anchor element, closes on outside click + Escape. Used by the unified
|
|
3
|
+
// pickers (CLI / Folder / Repo) so they all share interaction behavior.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// const [open, setOpen] = useState(false);
|
|
7
|
+
// const anchor = useRef(null);
|
|
8
|
+
// <button ref=${anchor} onClick=${() => setOpen(true)}>Trigger</button>
|
|
9
|
+
// ${open ? html`<${Popover} anchor=${anchor} onClose=${() => setOpen(false)}>
|
|
10
|
+
// ...panel contents...
|
|
11
|
+
// </${Popover}>` : null}
|
|
12
|
+
|
|
13
|
+
import { html } from '../html.js';
|
|
14
|
+
import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
|
|
15
|
+
import { createPortal } from 'preact/compat';
|
|
16
|
+
|
|
17
|
+
export function Popover({ anchor, onClose, align = 'left', width, children }) {
|
|
18
|
+
const panelRef = useRef(null);
|
|
19
|
+
const [pos, setPos] = useState({ top: 0, left: 0, width: width || 320 });
|
|
20
|
+
|
|
21
|
+
useLayoutEffect(() => {
|
|
22
|
+
const a = anchor && anchor.current;
|
|
23
|
+
if (!a) return;
|
|
24
|
+
const rect = a.getBoundingClientRect();
|
|
25
|
+
const w = width || Math.max(rect.width, 320);
|
|
26
|
+
let left = align === 'right' ? rect.right - w : rect.left;
|
|
27
|
+
// Clamp to viewport with 8px margin.
|
|
28
|
+
left = Math.max(8, Math.min(window.innerWidth - w - 8, left));
|
|
29
|
+
const top = rect.bottom + 6;
|
|
30
|
+
setPos({ top, left, width: w });
|
|
31
|
+
}, [anchor, align, width]);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const onDown = (ev) => {
|
|
35
|
+
if (panelRef.current?.contains(ev.target)) return;
|
|
36
|
+
if (anchor.current?.contains(ev.target)) return;
|
|
37
|
+
onClose?.();
|
|
38
|
+
};
|
|
39
|
+
const onKey = (ev) => { if (ev.key === 'Escape') onClose?.(); };
|
|
40
|
+
document.addEventListener('mousedown', onDown, true);
|
|
41
|
+
document.addEventListener('keydown', onKey, true);
|
|
42
|
+
return () => {
|
|
43
|
+
document.removeEventListener('mousedown', onDown, true);
|
|
44
|
+
document.removeEventListener('keydown', onKey, true);
|
|
45
|
+
};
|
|
46
|
+
}, [anchor, onClose]);
|
|
47
|
+
|
|
48
|
+
return createPortal(
|
|
49
|
+
html`<div ref=${panelRef} class="popover-panel"
|
|
50
|
+
style=${`top:${pos.top}px;left:${pos.left}px;width:${pos.width}px;`}>
|
|
51
|
+
${children}
|
|
52
|
+
</div>`,
|
|
53
|
+
document.body
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
// Small top-of-viewport banner shown while a user-initiated backend
|
|
2
|
-
// restart is in flight. Used to be a full-screen blocking modal;
|
|
3
|
-
// turned out the user just wanted visible "we're working" feedback,
|
|
4
|
-
// not a giant card-and-button covering the page. Self-dismisses when
|
|
5
|
-
// /api/health reports a fresh PID (different from the one we captured
|
|
6
|
-
// at click time), or after 30s as a safety net.
|
|
7
|
-
|
|
8
|
-
import { html } from '../html.js';
|
|
9
|
-
import { useEffect } from 'preact/hooks';
|
|
10
|
-
import { restartInFlight, serverHealth } from '../state.js';
|
|
11
|
-
import { refreshAll } from '../api.js';
|
|
12
|
-
|
|
13
|
-
export function RestartOverlay() {
|
|
14
|
-
const info = restartInFlight.value;
|
|
15
|
-
const h = serverHealth.value;
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (!info) return;
|
|
19
|
-
if (h.state === 'online' && h.pid && h.pid !== info.prevPid) {
|
|
20
|
-
restartInFlight.value = null;
|
|
21
|
-
refreshAll().catch(() => {});
|
|
22
|
-
}
|
|
23
|
-
const id = setTimeout(() => {
|
|
24
|
-
if (restartInFlight.value === info) restartInFlight.value = null;
|
|
25
|
-
}, 30_000);
|
|
26
|
-
return () => clearTimeout(id);
|
|
27
|
-
}, [info, h.state, h.pid]);
|
|
28
|
-
|
|
29
|
-
if (!info) return null;
|
|
30
|
-
|
|
31
|
-
return html`
|
|
32
|
-
<div class="restart-banner" role="status" aria-live="polite">
|
|
33
|
-
<span class="restart-banner-spinner" aria-hidden="true"></span>
|
|
34
|
-
<span class="restart-banner-text">Restarting backend…</span>
|
|
35
|
-
</div>`;
|
|
36
|
-
}
|
|
1
|
+
// Small top-of-viewport banner shown while a user-initiated backend
|
|
2
|
+
// restart is in flight. Used to be a full-screen blocking modal;
|
|
3
|
+
// turned out the user just wanted visible "we're working" feedback,
|
|
4
|
+
// not a giant card-and-button covering the page. Self-dismisses when
|
|
5
|
+
// /api/health reports a fresh PID (different from the one we captured
|
|
6
|
+
// at click time), or after 30s as a safety net.
|
|
7
|
+
|
|
8
|
+
import { html } from '../html.js';
|
|
9
|
+
import { useEffect } from 'preact/hooks';
|
|
10
|
+
import { restartInFlight, serverHealth } from '../state.js';
|
|
11
|
+
import { refreshAll } from '../api.js';
|
|
12
|
+
|
|
13
|
+
export function RestartOverlay() {
|
|
14
|
+
const info = restartInFlight.value;
|
|
15
|
+
const h = serverHealth.value;
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!info) return;
|
|
19
|
+
if (h.state === 'online' && h.pid && h.pid !== info.prevPid) {
|
|
20
|
+
restartInFlight.value = null;
|
|
21
|
+
refreshAll().catch(() => {});
|
|
22
|
+
}
|
|
23
|
+
const id = setTimeout(() => {
|
|
24
|
+
if (restartInFlight.value === info) restartInFlight.value = null;
|
|
25
|
+
}, 30_000);
|
|
26
|
+
return () => clearTimeout(id);
|
|
27
|
+
}, [info, h.state, h.pid]);
|
|
28
|
+
|
|
29
|
+
if (!info) return null;
|
|
30
|
+
|
|
31
|
+
return html`
|
|
32
|
+
<div class="restart-banner" role="status" aria-live="polite">
|
|
33
|
+
<span class="restart-banner-spinner" aria-hidden="true"></span>
|
|
34
|
+
<span class="restart-banner-text">Restarting backend…</span>
|
|
35
|
+
</div>`;
|
|
36
|
+
}
|