@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.
Files changed (59) hide show
  1. package/CLAUDE.md +538 -538
  2. package/README.md +189 -189
  3. package/bin/ccsm.js +235 -235
  4. package/lib/cliActivity.js +139 -139
  5. package/lib/codexSeed.js +183 -183
  6. package/lib/config.js +279 -274
  7. package/lib/devices.js +229 -229
  8. package/lib/folders.js +124 -124
  9. package/lib/localCliSessions.js +519 -519
  10. package/lib/persistedSessions.js +129 -129
  11. package/lib/tunnel.js +621 -621
  12. package/lib/webTerminal.js +225 -225
  13. package/lib/workspace.js +233 -233
  14. package/package.json +57 -57
  15. package/public/css/base.css +99 -99
  16. package/public/css/cards.css +183 -183
  17. package/public/css/feedback.css +504 -504
  18. package/public/css/forms.css +453 -453
  19. package/public/css/layout.css +177 -176
  20. package/public/css/modal.css +190 -190
  21. package/public/css/responsive.css +176 -176
  22. package/public/css/sidebar.css +707 -707
  23. package/public/css/terminals.css +547 -553
  24. package/public/css/tokens.css +81 -81
  25. package/public/css/wco.css +196 -196
  26. package/public/css/widgets.css +2725 -2725
  27. package/public/index.html +152 -152
  28. package/public/js/api.js +371 -371
  29. package/public/js/backend.js +149 -149
  30. package/public/js/components/App.js +73 -73
  31. package/public/js/components/DirectoryPicker.js +203 -203
  32. package/public/js/components/EntityFormModal.js +153 -153
  33. package/public/js/components/Modal.js +57 -57
  34. package/public/js/components/OfflineBanner.js +67 -67
  35. package/public/js/components/PageTitleBar.js +13 -13
  36. package/public/js/components/PendingApprovalOverlay.js +128 -128
  37. package/public/js/components/Picker.js +179 -179
  38. package/public/js/components/Popover.js +55 -55
  39. package/public/js/components/RestartOverlay.js +36 -36
  40. package/public/js/components/Sidebar.js +380 -380
  41. package/public/js/components/TerminalInstance.js +28 -9
  42. package/public/js/components/XtermTerminal.js +62 -2
  43. package/public/js/components/useDragSort.js +67 -67
  44. package/public/js/dialog.js +67 -67
  45. package/public/js/icons.js +212 -212
  46. package/public/js/main.js +296 -296
  47. package/public/js/pages/AboutPage.js +90 -90
  48. package/public/js/pages/ConfigurePage.js +728 -713
  49. package/public/js/pages/LaunchPage.js +421 -421
  50. package/public/js/pages/RemotePage.js +743 -743
  51. package/public/js/pages/SessionsPage.js +73 -80
  52. package/public/js/state.js +335 -335
  53. package/scripts/dev.js +149 -149
  54. package/scripts/install.js +153 -153
  55. package/scripts/restart-helper.js +96 -96
  56. package/scripts/upgrade-helper.js +687 -687
  57. package/server.js +1820 -1807
  58. package/public/manifest.webmanifest +0 -25
  59. 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
+ }