@bakapiano/ccsm 0.22.2 → 0.22.4

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 (60) 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 +233 -231
  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 +592 -592
  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 +187 -15
  42. package/public/js/components/TerminalResizeDebouncer.js +126 -0
  43. package/public/js/components/XtermTerminal.js +148 -14
  44. package/public/js/components/useDragSort.js +67 -67
  45. package/public/js/dialog.js +67 -67
  46. package/public/js/icons.js +212 -212
  47. package/public/js/main.js +296 -296
  48. package/public/js/pages/AboutPage.js +90 -90
  49. package/public/js/pages/ConfigurePage.js +713 -713
  50. package/public/js/pages/LaunchPage.js +421 -421
  51. package/public/js/pages/RemotePage.js +743 -743
  52. package/public/js/pages/SessionsPage.js +100 -100
  53. package/public/js/state.js +335 -335
  54. package/public/manifest.webmanifest +25 -0
  55. package/public/setup/index.html +567 -0
  56. package/scripts/dev.js +149 -149
  57. package/scripts/install.js +153 -153
  58. package/scripts/restart-helper.js +96 -96
  59. package/scripts/upgrade-helper.js +687 -687
  60. package/server.js +1807 -1807
package/public/index.html CHANGED
@@ -1,152 +1,152 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <!-- maximum-scale=1 stops iOS Safari from auto-zooming the page
6
- when the user taps a sub-16px input. xterm's helper textarea
7
- inherits the terminal's own font size (11px on phones); if we
8
- instead bumped it to 16px via CSS, xterm would measure the
9
- cell off the inflated textarea and render every glyph ~50%
10
- oversized. Locking page zoom here lets us leave the textarea
11
- alone. -->
12
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
13
- <!-- Bleeds the cream surface into the Edge/Chrome --app= title bar
14
- so it visually disappears against the body. The browser does
15
- honor this in standalone app windows. -->
16
- <meta name="theme-color" content="#f6f8fa" />
17
- <meta name="color-scheme" content="light" />
18
- <title>CCSM</title>
19
- <!-- All asset paths are RELATIVE so the same index.html works when
20
- served from localhost:7777/ (backend bundle) AND from
21
- https://bakapiano.github.io/ccsm/v1/ (GH Pages hosted). -->
22
- <link rel="icon" type="image/svg+xml" href="./favicon.svg" />
23
- <!-- Point at the ROOT manifest (/ccsm/manifest.webmanifest) so the
24
- installable PWA is scoped to /ccsm/, covering every per-version
25
- subdir. If we shipped a per-version manifest the browser would
26
- scope the PWA to /ccsm/X.Y.Z/ — then the version-guard's
27
- redirect to ../ on backend upgrade would fall out of scope and
28
- the OS would re-show an address bar. -->
29
- <link rel="manifest" href="../manifest.webmanifest" />
30
- <!-- Apply theme (accent + light/dark) BEFORE stylesheets/paint to
31
- avoid a flash of the default light tokens.css bg. Mirrors
32
- applyTheme()/applyAccentCssVars() in state.js — keep the two in
33
- sync. Resolves 'system' against the OS, sets data-theme so the
34
- [data-theme="dark"] CSS overrides apply from the first frame, and
35
- derives the accent-tinted palette for the chosen ground. -->
36
- <script>
37
- (function () {
38
- try {
39
- var hex = localStorage.getItem('ccsm.accent');
40
- if (!/^#[0-9a-fA-F]{6}$/.test(hex || '')) hex = '#2f6fa3';
41
- var mode = localStorage.getItem('ccsm.theme');
42
- if (mode !== 'light' && mode !== 'dark' && mode !== 'system') mode = 'system';
43
- var dark = mode === 'dark' || (mode === 'system'
44
- && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
45
-
46
- var n = parseInt(hex.slice(1), 16);
47
- var A = { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
48
- var toHex = function (v) { v = Math.max(0, Math.min(255, Math.round(v))); var s = v.toString(16); return s.length < 2 ? '0' + s : s; };
49
- var rgb = function (c) { return '#' + toHex(c.r) + toHex(c.g) + toHex(c.b); };
50
- var lerp = function (c1, c2, t) { return { r: c1.r + (c2.r - c1.r) * t, g: c1.g + (c2.g - c1.g) * t, b: c1.b + (c2.b - c1.b) * t }; };
51
- var WHITE = { r: 255, g: 255, b: 255 }, BLACK = { r: 0, g: 0, b: 0 };
52
- var DARK_BASE = { r: 0x18, g: 0x16, b: 0x12 }, LIGHT_INK = { r: 0xec, g: 0xe7, b: 0xda };
53
-
54
- var root = document.documentElement.style;
55
- var set = function (o) { for (var k in o) root.setProperty(k, o[k]); };
56
- var vars;
57
- if (dark) {
58
- var bg = lerp(DARK_BASE, A, 0.06);
59
- var lift = function (t) { return rgb(lerp(bg, LIGHT_INK, t)); };
60
- vars = {
61
- '--accent': hex,
62
- '--accent-deep': rgb(lerp(A, LIGHT_INK, 0.18)),
63
- '--accent-soft': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.18)',
64
- '--accent-softer': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.07)',
65
- '--bg': rgb(bg), '--bg-elev': lift(0.05), '--sidebar-bg': rgb(bg),
66
- '--sidebar-hover': lift(0.09), '--sidebar-active': lift(0.15),
67
- '--border': lift(0.14), '--border-soft': lift(0.09), '--border-strong': lift(0.24),
68
- '--ui-bg': lift(0.05), '--ui-border': lift(0.16), '--ui-border-soft': lift(0.10),
69
- '--ink': rgb(LIGHT_INK),
70
- '--ink-mid': rgb(lerp(LIGHT_INK, DARK_BASE, 0.28)),
71
- '--ink-muted': rgb(lerp(LIGHT_INK, DARK_BASE, 0.45)),
72
- '--ink-faint': rgb(lerp(LIGHT_INK, DARK_BASE, 0.60)),
73
- };
74
- } else {
75
- var mix = function (t) { return rgb(lerp(WHITE, A, t)); };
76
- vars = {
77
- '--accent': hex,
78
- '--accent-deep': rgb(lerp(A, BLACK, 0.2)),
79
- '--accent-soft': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.10)',
80
- '--accent-softer': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.04)',
81
- '--bg': mix(0.04), '--bg-elev': '#ffffff', '--sidebar-bg': mix(0.04),
82
- '--sidebar-hover': mix(0.10), '--sidebar-active': mix(0.15),
83
- '--border': mix(0.15), '--border-soft': mix(0.12), '--border-strong': mix(0.25),
84
- '--ui-bg': mix(0.10), '--ui-border': '#d8d4c6', '--ui-border-soft': '#e6e2d4',
85
- '--ink': '#1a1815', '--ink-mid': '#534e44', '--ink-muted': '#8a8475', '--ink-faint': '#b5af9d',
86
- };
87
- }
88
- document.documentElement.dataset.theme = dark ? 'dark' : 'light';
89
- document.documentElement.style.colorScheme = dark ? 'dark' : 'light';
90
- set(vars);
91
- var meta = document.querySelector('meta[name="theme-color"]');
92
- if (meta) meta.setAttribute('content', vars['--bg']);
93
- } catch (_) {}
94
- })();
95
- </script>
96
- <link rel="preconnect" href="https://fonts.googleapis.com" />
97
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
98
- <link
99
- rel="stylesheet"
100
- href="https://fonts.googleapis.com/css2?family=Geist:wght@300..700&family=Geist+Mono:wght@400..600&family=JetBrains+Mono:wght@400..600&display=swap"
101
- />
102
- <link rel="stylesheet" href="./css/tokens.css" />
103
- <link rel="stylesheet" href="./css/base.css" />
104
- <link rel="stylesheet" href="./css/layout.css" />
105
- <link rel="stylesheet" href="./css/sidebar.css" />
106
- <link rel="stylesheet" href="./css/cards.css" />
107
- <link rel="stylesheet" href="./css/tables.css" />
108
- <link rel="stylesheet" href="./css/forms.css" />
109
- <link rel="stylesheet" href="./css/widgets.css" />
110
- <link rel="stylesheet" href="./css/feedback.css" />
111
- <link rel="stylesheet" href="./css/modal.css" />
112
- <link rel="stylesheet" href="./css/terminals.css" />
113
- <link rel="stylesheet" href="./css/wco.css" />
114
- <link rel="stylesheet" href="./css/responsive.css" />
115
- <!-- Loaded last so its [data-theme="dark"] rules win the cascade. -->
116
- <link rel="stylesheet" href="./css/dark.css" />
117
-
118
- <script type="importmap">
119
- {
120
- "imports": {
121
- "preact": "https://esm.sh/preact@10.27.0",
122
- "preact/hooks": "https://esm.sh/preact@10.27.0/hooks",
123
- "preact/compat": "https://esm.sh/preact@10.27.0/compat",
124
- "@preact/signals": "https://esm.sh/@preact/signals@1.3.2?deps=preact@10.27.0",
125
- "htm": "https://esm.sh/htm@3.1.1",
126
- "@xterm/xterm": "https://esm.sh/@xterm/xterm@5.5.0",
127
- "@xterm/addon-fit": "https://esm.sh/@xterm/addon-fit@0.10.0?deps=@xterm/xterm@5.5.0",
128
- "@xterm/addon-web-links": "https://esm.sh/@xterm/addon-web-links@0.11.0?deps=@xterm/xterm@5.5.0",
129
- "@xterm/addon-clipboard": "https://esm.sh/@xterm/addon-clipboard@0.1.0?deps=@xterm/xterm@5.5.0",
130
- "@xterm/addon-webgl": "https://esm.sh/@xterm/addon-webgl@0.18.0?deps=@xterm/xterm@5.5.0"
131
- }
132
- }
133
- </script>
134
- <link rel="stylesheet" href="https://esm.sh/@xterm/xterm@5.5.0/css/xterm.css" />
135
- </head>
136
- <body>
137
- <div id="app"></div>
138
- <script type="module" src="./js/main.js"></script>
139
- <script>
140
- // Dev hot-reload — only active when the page itself loads from a
141
- // local backend (the /api/dev/ping endpoint exists only on a dev
142
- // checkout). On the GH Pages copy this skips entirely.
143
- if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
144
- fetch('/api/dev/ping', { cache: 'no-store' }).then((r) => {
145
- if (!r.ok) return;
146
- const es = new EventSource('/api/dev/reload');
147
- es.addEventListener('reload', () => location.reload());
148
- }).catch(() => {});
149
- }
150
- </script>
151
- </body>
152
- </html>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <!-- maximum-scale=1 stops iOS Safari from auto-zooming the page
6
+ when the user taps a sub-16px input. xterm's helper textarea
7
+ inherits the terminal's own font size (11px on phones); if we
8
+ instead bumped it to 16px via CSS, xterm would measure the
9
+ cell off the inflated textarea and render every glyph ~50%
10
+ oversized. Locking page zoom here lets us leave the textarea
11
+ alone. -->
12
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
13
+ <!-- Bleeds the cream surface into the Edge/Chrome --app= title bar
14
+ so it visually disappears against the body. The browser does
15
+ honor this in standalone app windows. -->
16
+ <meta name="theme-color" content="#f6f8fa" />
17
+ <meta name="color-scheme" content="light" />
18
+ <title>CCSM</title>
19
+ <!-- All asset paths are RELATIVE so the same index.html works when
20
+ served from localhost:7777/ (backend bundle) AND from
21
+ https://bakapiano.github.io/ccsm/v1/ (GH Pages hosted). -->
22
+ <link rel="icon" type="image/svg+xml" href="./favicon.svg" />
23
+ <!-- Point at the ROOT manifest (/ccsm/manifest.webmanifest) so the
24
+ installable PWA is scoped to /ccsm/, covering every per-version
25
+ subdir. If we shipped a per-version manifest the browser would
26
+ scope the PWA to /ccsm/X.Y.Z/ — then the version-guard's
27
+ redirect to ../ on backend upgrade would fall out of scope and
28
+ the OS would re-show an address bar. -->
29
+ <link rel="manifest" href="../manifest.webmanifest" />
30
+ <!-- Apply theme (accent + light/dark) BEFORE stylesheets/paint to
31
+ avoid a flash of the default light tokens.css bg. Mirrors
32
+ applyTheme()/applyAccentCssVars() in state.js — keep the two in
33
+ sync. Resolves 'system' against the OS, sets data-theme so the
34
+ [data-theme="dark"] CSS overrides apply from the first frame, and
35
+ derives the accent-tinted palette for the chosen ground. -->
36
+ <script>
37
+ (function () {
38
+ try {
39
+ var hex = localStorage.getItem('ccsm.accent');
40
+ if (!/^#[0-9a-fA-F]{6}$/.test(hex || '')) hex = '#2f6fa3';
41
+ var mode = localStorage.getItem('ccsm.theme');
42
+ if (mode !== 'light' && mode !== 'dark' && mode !== 'system') mode = 'system';
43
+ var dark = mode === 'dark' || (mode === 'system'
44
+ && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
45
+
46
+ var n = parseInt(hex.slice(1), 16);
47
+ var A = { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
48
+ var toHex = function (v) { v = Math.max(0, Math.min(255, Math.round(v))); var s = v.toString(16); return s.length < 2 ? '0' + s : s; };
49
+ var rgb = function (c) { return '#' + toHex(c.r) + toHex(c.g) + toHex(c.b); };
50
+ var lerp = function (c1, c2, t) { return { r: c1.r + (c2.r - c1.r) * t, g: c1.g + (c2.g - c1.g) * t, b: c1.b + (c2.b - c1.b) * t }; };
51
+ var WHITE = { r: 255, g: 255, b: 255 }, BLACK = { r: 0, g: 0, b: 0 };
52
+ var DARK_BASE = { r: 0x18, g: 0x16, b: 0x12 }, LIGHT_INK = { r: 0xec, g: 0xe7, b: 0xda };
53
+
54
+ var root = document.documentElement.style;
55
+ var set = function (o) { for (var k in o) root.setProperty(k, o[k]); };
56
+ var vars;
57
+ if (dark) {
58
+ var bg = lerp(DARK_BASE, A, 0.06);
59
+ var lift = function (t) { return rgb(lerp(bg, LIGHT_INK, t)); };
60
+ vars = {
61
+ '--accent': hex,
62
+ '--accent-deep': rgb(lerp(A, LIGHT_INK, 0.18)),
63
+ '--accent-soft': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.18)',
64
+ '--accent-softer': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.07)',
65
+ '--bg': rgb(bg), '--bg-elev': lift(0.05), '--sidebar-bg': rgb(bg),
66
+ '--sidebar-hover': lift(0.09), '--sidebar-active': lift(0.15),
67
+ '--border': lift(0.14), '--border-soft': lift(0.09), '--border-strong': lift(0.24),
68
+ '--ui-bg': lift(0.05), '--ui-border': lift(0.16), '--ui-border-soft': lift(0.10),
69
+ '--ink': rgb(LIGHT_INK),
70
+ '--ink-mid': rgb(lerp(LIGHT_INK, DARK_BASE, 0.28)),
71
+ '--ink-muted': rgb(lerp(LIGHT_INK, DARK_BASE, 0.45)),
72
+ '--ink-faint': rgb(lerp(LIGHT_INK, DARK_BASE, 0.60)),
73
+ };
74
+ } else {
75
+ var mix = function (t) { return rgb(lerp(WHITE, A, t)); };
76
+ vars = {
77
+ '--accent': hex,
78
+ '--accent-deep': rgb(lerp(A, BLACK, 0.2)),
79
+ '--accent-soft': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.10)',
80
+ '--accent-softer': 'rgba(' + A.r + ',' + A.g + ',' + A.b + ',0.04)',
81
+ '--bg': mix(0.04), '--bg-elev': '#ffffff', '--sidebar-bg': mix(0.04),
82
+ '--sidebar-hover': mix(0.10), '--sidebar-active': mix(0.15),
83
+ '--border': mix(0.15), '--border-soft': mix(0.12), '--border-strong': mix(0.25),
84
+ '--ui-bg': mix(0.10), '--ui-border': '#d8d4c6', '--ui-border-soft': '#e6e2d4',
85
+ '--ink': '#1a1815', '--ink-mid': '#534e44', '--ink-muted': '#8a8475', '--ink-faint': '#b5af9d',
86
+ };
87
+ }
88
+ document.documentElement.dataset.theme = dark ? 'dark' : 'light';
89
+ document.documentElement.style.colorScheme = dark ? 'dark' : 'light';
90
+ set(vars);
91
+ var meta = document.querySelector('meta[name="theme-color"]');
92
+ if (meta) meta.setAttribute('content', vars['--bg']);
93
+ } catch (_) {}
94
+ })();
95
+ </script>
96
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
97
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
98
+ <link
99
+ rel="stylesheet"
100
+ href="https://fonts.googleapis.com/css2?family=Geist:wght@300..700&family=Geist+Mono:wght@400..600&family=JetBrains+Mono:wght@400..600&display=swap"
101
+ />
102
+ <link rel="stylesheet" href="./css/tokens.css" />
103
+ <link rel="stylesheet" href="./css/base.css" />
104
+ <link rel="stylesheet" href="./css/layout.css" />
105
+ <link rel="stylesheet" href="./css/sidebar.css" />
106
+ <link rel="stylesheet" href="./css/cards.css" />
107
+ <link rel="stylesheet" href="./css/tables.css" />
108
+ <link rel="stylesheet" href="./css/forms.css" />
109
+ <link rel="stylesheet" href="./css/widgets.css" />
110
+ <link rel="stylesheet" href="./css/feedback.css" />
111
+ <link rel="stylesheet" href="./css/modal.css" />
112
+ <link rel="stylesheet" href="./css/terminals.css" />
113
+ <link rel="stylesheet" href="./css/wco.css" />
114
+ <link rel="stylesheet" href="./css/responsive.css" />
115
+ <!-- Loaded last so its [data-theme="dark"] rules win the cascade. -->
116
+ <link rel="stylesheet" href="./css/dark.css" />
117
+
118
+ <script type="importmap">
119
+ {
120
+ "imports": {
121
+ "preact": "https://esm.sh/preact@10.27.0",
122
+ "preact/hooks": "https://esm.sh/preact@10.27.0/hooks",
123
+ "preact/compat": "https://esm.sh/preact@10.27.0/compat",
124
+ "@preact/signals": "https://esm.sh/@preact/signals@1.3.2?deps=preact@10.27.0",
125
+ "htm": "https://esm.sh/htm@3.1.1",
126
+ "@xterm/xterm": "https://esm.sh/@xterm/xterm@5.5.0",
127
+ "@xterm/addon-fit": "https://esm.sh/@xterm/addon-fit@0.10.0?deps=@xterm/xterm@5.5.0",
128
+ "@xterm/addon-web-links": "https://esm.sh/@xterm/addon-web-links@0.11.0?deps=@xterm/xterm@5.5.0",
129
+ "@xterm/addon-clipboard": "https://esm.sh/@xterm/addon-clipboard@0.1.0?deps=@xterm/xterm@5.5.0",
130
+ "@xterm/addon-webgl": "https://esm.sh/@xterm/addon-webgl@0.18.0?deps=@xterm/xterm@5.5.0"
131
+ }
132
+ }
133
+ </script>
134
+ <link rel="stylesheet" href="https://esm.sh/@xterm/xterm@5.5.0/css/xterm.css" />
135
+ </head>
136
+ <body>
137
+ <div id="app"></div>
138
+ <script type="module" src="./js/main.js"></script>
139
+ <script>
140
+ // Dev hot-reload — only active when the page itself loads from a
141
+ // local backend (the /api/dev/ping endpoint exists only on a dev
142
+ // checkout). On the GH Pages copy this skips entirely.
143
+ if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
144
+ fetch('/api/dev/ping', { cache: 'no-store' }).then((r) => {
145
+ if (!r.ok) return;
146
+ const es = new EventSource('/api/dev/reload');
147
+ es.addEventListener('reload', () => location.reload());
148
+ }).catch(() => {});
149
+ }
150
+ </script>
151
+ </body>
152
+ </html>