@bakapiano/ccsm 0.22.3 → 0.22.5

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 (61) 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 +274 -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 +176 -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 +645 -543
  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 +159 -22
  42. package/public/js/components/TerminalResizeDebouncer.js +126 -0
  43. package/public/js/components/TerminalView.js +15 -2
  44. package/public/js/components/XtermTerminal.js +74 -15
  45. package/public/js/components/useDragSort.js +67 -67
  46. package/public/js/dialog.js +67 -67
  47. package/public/js/icons.js +212 -212
  48. package/public/js/main.js +296 -296
  49. package/public/js/pages/AboutPage.js +90 -90
  50. package/public/js/pages/ConfigurePage.js +713 -713
  51. package/public/js/pages/LaunchPage.js +421 -421
  52. package/public/js/pages/RemotePage.js +743 -743
  53. package/public/js/pages/SessionsPage.js +199 -80
  54. package/public/js/state.js +335 -335
  55. package/public/manifest.webmanifest +25 -0
  56. package/public/setup/index.html +567 -0
  57. package/scripts/dev.js +149 -149
  58. package/scripts/install.js +153 -153
  59. package/scripts/restart-helper.js +96 -96
  60. package/scripts/upgrade-helper.js +687 -687
  61. package/server.js +1807 -1807
@@ -1,67 +1,67 @@
1
- // Lightweight HTML5 drag-reorder helper.
2
- //
3
- // Usage:
4
- // const dnd = useDragSort(items.map((i) => i.id), async (nextIds) => {
5
- // await reorderFolders(nextIds);
6
- // });
7
- // items.map((it) => html`
8
- // <div ...${dnd.rowProps(it.id)}>
9
- // <span ...${dnd.handleProps(it.id)}>⋮⋮</span>
10
- // ...
11
- // </div>`);
12
- //
13
- // rowProps spreads onDragOver / onDrop / data-* on the row container.
14
- // handleProps spreads draggable + onDragStart on the drag handle. We
15
- // gate "draggable" on the handle so clicks inside the row don't start a
16
- // drag and the user can still click rows normally.
17
-
18
- import { useRef, useState } from 'preact/hooks';
19
-
20
- export function useDragSort(ids, onCommit) {
21
- const dragging = useRef(null);
22
- const [overId, setOverId] = useState(null);
23
-
24
- const handleProps = (id) => ({
25
- draggable: true,
26
- onDragStart: (ev) => {
27
- dragging.current = id;
28
- ev.dataTransfer.effectAllowed = 'move';
29
- // Setting some data is required for Firefox to actually start a drag.
30
- try { ev.dataTransfer.setData('text/plain', id); } catch {}
31
- },
32
- onDragEnd: () => { dragging.current = null; setOverId(null); },
33
- });
34
-
35
- const rowProps = (id) => ({
36
- 'data-dnd-id': id,
37
- 'data-dnd-over': overId === id ? 'true' : undefined,
38
- onDragOver: (ev) => {
39
- if (dragging.current == null || dragging.current === id) return;
40
- ev.preventDefault();
41
- ev.dataTransfer.dropEffect = 'move';
42
- if (overId !== id) setOverId(id);
43
- },
44
- onDragLeave: (ev) => {
45
- // Only clear if the pointer leaves the row entirely (not when entering a child).
46
- const rt = ev.relatedTarget;
47
- if (rt && ev.currentTarget.contains(rt)) return;
48
- if (overId === id) setOverId(null);
49
- },
50
- onDrop: (ev) => {
51
- ev.preventDefault();
52
- const src = dragging.current;
53
- dragging.current = null;
54
- setOverId(null);
55
- if (src == null || src === id) return;
56
- const cur = [...ids];
57
- const from = cur.indexOf(src);
58
- const to = cur.indexOf(id);
59
- if (from < 0 || to < 0) return;
60
- cur.splice(from, 1);
61
- cur.splice(to, 0, src);
62
- onCommit?.(cur);
63
- },
64
- });
65
-
66
- return { handleProps, rowProps, draggingId: dragging.current, overId };
67
- }
1
+ // Lightweight HTML5 drag-reorder helper.
2
+ //
3
+ // Usage:
4
+ // const dnd = useDragSort(items.map((i) => i.id), async (nextIds) => {
5
+ // await reorderFolders(nextIds);
6
+ // });
7
+ // items.map((it) => html`
8
+ // <div ...${dnd.rowProps(it.id)}>
9
+ // <span ...${dnd.handleProps(it.id)}>⋮⋮</span>
10
+ // ...
11
+ // </div>`);
12
+ //
13
+ // rowProps spreads onDragOver / onDrop / data-* on the row container.
14
+ // handleProps spreads draggable + onDragStart on the drag handle. We
15
+ // gate "draggable" on the handle so clicks inside the row don't start a
16
+ // drag and the user can still click rows normally.
17
+
18
+ import { useRef, useState } from 'preact/hooks';
19
+
20
+ export function useDragSort(ids, onCommit) {
21
+ const dragging = useRef(null);
22
+ const [overId, setOverId] = useState(null);
23
+
24
+ const handleProps = (id) => ({
25
+ draggable: true,
26
+ onDragStart: (ev) => {
27
+ dragging.current = id;
28
+ ev.dataTransfer.effectAllowed = 'move';
29
+ // Setting some data is required for Firefox to actually start a drag.
30
+ try { ev.dataTransfer.setData('text/plain', id); } catch {}
31
+ },
32
+ onDragEnd: () => { dragging.current = null; setOverId(null); },
33
+ });
34
+
35
+ const rowProps = (id) => ({
36
+ 'data-dnd-id': id,
37
+ 'data-dnd-over': overId === id ? 'true' : undefined,
38
+ onDragOver: (ev) => {
39
+ if (dragging.current == null || dragging.current === id) return;
40
+ ev.preventDefault();
41
+ ev.dataTransfer.dropEffect = 'move';
42
+ if (overId !== id) setOverId(id);
43
+ },
44
+ onDragLeave: (ev) => {
45
+ // Only clear if the pointer leaves the row entirely (not when entering a child).
46
+ const rt = ev.relatedTarget;
47
+ if (rt && ev.currentTarget.contains(rt)) return;
48
+ if (overId === id) setOverId(null);
49
+ },
50
+ onDrop: (ev) => {
51
+ ev.preventDefault();
52
+ const src = dragging.current;
53
+ dragging.current = null;
54
+ setOverId(null);
55
+ if (src == null || src === id) return;
56
+ const cur = [...ids];
57
+ const from = cur.indexOf(src);
58
+ const to = cur.indexOf(id);
59
+ if (from < 0 || to < 0) return;
60
+ cur.splice(from, 1);
61
+ cur.splice(to, 0, src);
62
+ onCommit?.(cur);
63
+ },
64
+ });
65
+
66
+ return { handleProps, rowProps, draggingId: dragging.current, overId };
67
+ }
@@ -1,67 +1,67 @@
1
- // Promise-based confirm/prompt rendered through DialogHost. The stack
2
- // signal lets us nest dialogs if ever needed; .close() pops by id.
3
-
4
- import { signal } from '@preact/signals';
5
- import { html } from './html.js';
6
-
7
- export const dialogs = signal([]);
8
- let nextId = 1;
9
-
10
- function push(entry) {
11
- return new Promise((resolve) => {
12
- const id = nextId++;
13
- const close = (action, host) => {
14
- dialogs.value = dialogs.value.filter((d) => d.id !== id);
15
- resolve(entry.onResolve(action, host));
16
- };
17
- dialogs.value = [...dialogs.value, { id, ...entry, close }];
18
- });
19
- }
20
-
21
- const CLOSE_X = html`
22
- <button class="modal-close" type="button" aria-label="Close" data-action="cancel">
23
- <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
24
- <line x1="3" y1="3" x2="13" y2="13"/>
25
- <line x1="13" y1="3" x2="3" y2="13"/>
26
- </svg>
27
- </button>`;
28
-
29
- export function ccsmConfirm(message, opts = {}) {
30
- const { title = 'Confirm', okLabel = 'Confirm', cancelLabel = 'Cancel', danger = false } = opts;
31
- return push({
32
- render: () => html`<div class="modal modal-dialog">
33
- <header class="modal-head"><h2>${title}</h2>${CLOSE_X}</header>
34
- <div class="modal-body"><p class="dialog-msg">${message}</p></div>
35
- <footer class="modal-foot">
36
- <button class="action" data-action="cancel">${cancelLabel}</button>
37
- <button class=${`action ${danger ? 'danger' : 'primary'}`} data-action="ok">${okLabel}</button>
38
- </footer>
39
- </div>`,
40
- onResolve: (action) => action === 'ok' || action === 'enter',
41
- });
42
- }
43
-
44
- export function ccsmPrompt(message, defaultValue = '', opts = {}) {
45
- const { title, okLabel = 'Save', cancelLabel = 'Cancel', placeholder = '' } = opts;
46
- return push({
47
- render: () => html`<div class="modal modal-dialog">
48
- <header class="modal-head"><h2>${title || message}</h2>${CLOSE_X}</header>
49
- <div class="modal-body">
50
- ${title ? html`<p class="dialog-msg">${message}</p>` : null}
51
- <input type="text" class="input" placeholder=${placeholder} value=${defaultValue} />
52
- </div>
53
- <footer class="modal-foot">
54
- <button class="action" data-action="cancel">${cancelLabel}</button>
55
- <button class="action primary" data-action="ok">${okLabel}</button>
56
- </footer>
57
- </div>`,
58
- initialFocus: (host) => {
59
- const inp = host.querySelector('input');
60
- if (inp) { inp.focus(); inp.select(); }
61
- },
62
- onResolve: (action, host) => {
63
- const inp = host?.querySelector('input');
64
- return (action === 'ok' || action === 'enter') ? (inp?.value ?? '') : null;
65
- },
66
- });
67
- }
1
+ // Promise-based confirm/prompt rendered through DialogHost. The stack
2
+ // signal lets us nest dialogs if ever needed; .close() pops by id.
3
+
4
+ import { signal } from '@preact/signals';
5
+ import { html } from './html.js';
6
+
7
+ export const dialogs = signal([]);
8
+ let nextId = 1;
9
+
10
+ function push(entry) {
11
+ return new Promise((resolve) => {
12
+ const id = nextId++;
13
+ const close = (action, host) => {
14
+ dialogs.value = dialogs.value.filter((d) => d.id !== id);
15
+ resolve(entry.onResolve(action, host));
16
+ };
17
+ dialogs.value = [...dialogs.value, { id, ...entry, close }];
18
+ });
19
+ }
20
+
21
+ const CLOSE_X = html`
22
+ <button class="modal-close" type="button" aria-label="Close" data-action="cancel">
23
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
24
+ <line x1="3" y1="3" x2="13" y2="13"/>
25
+ <line x1="13" y1="3" x2="3" y2="13"/>
26
+ </svg>
27
+ </button>`;
28
+
29
+ export function ccsmConfirm(message, opts = {}) {
30
+ const { title = 'Confirm', okLabel = 'Confirm', cancelLabel = 'Cancel', danger = false } = opts;
31
+ return push({
32
+ render: () => html`<div class="modal modal-dialog">
33
+ <header class="modal-head"><h2>${title}</h2>${CLOSE_X}</header>
34
+ <div class="modal-body"><p class="dialog-msg">${message}</p></div>
35
+ <footer class="modal-foot">
36
+ <button class="action" data-action="cancel">${cancelLabel}</button>
37
+ <button class=${`action ${danger ? 'danger' : 'primary'}`} data-action="ok">${okLabel}</button>
38
+ </footer>
39
+ </div>`,
40
+ onResolve: (action) => action === 'ok' || action === 'enter',
41
+ });
42
+ }
43
+
44
+ export function ccsmPrompt(message, defaultValue = '', opts = {}) {
45
+ const { title, okLabel = 'Save', cancelLabel = 'Cancel', placeholder = '' } = opts;
46
+ return push({
47
+ render: () => html`<div class="modal modal-dialog">
48
+ <header class="modal-head"><h2>${title || message}</h2>${CLOSE_X}</header>
49
+ <div class="modal-body">
50
+ ${title ? html`<p class="dialog-msg">${message}</p>` : null}
51
+ <input type="text" class="input" placeholder=${placeholder} value=${defaultValue} />
52
+ </div>
53
+ <footer class="modal-foot">
54
+ <button class="action" data-action="cancel">${cancelLabel}</button>
55
+ <button class="action primary" data-action="ok">${okLabel}</button>
56
+ </footer>
57
+ </div>`,
58
+ initialFocus: (host) => {
59
+ const inp = host.querySelector('input');
60
+ if (inp) { inp.focus(); inp.select(); }
61
+ },
62
+ onResolve: (action, host) => {
63
+ const inp = host?.querySelector('input');
64
+ return (action === 'ok' || action === 'enter') ? (inp?.value ?? '') : null;
65
+ },
66
+ });
67
+ }