@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
@@ -1,176 +1,176 @@
1
- /* Narrow viewports: force-collapse sidebar, single-col config grid */
2
-
3
- /* Narrow desktop / tablet viewports: stack the page-head, single-column
4
- config grids. Sidebar stays at full width — user can still toggle it
5
- manually via the collapse button. Phone-sized (≤ 640px) gets the FAB
6
- drawer treatment below. */
7
- @media (max-width: 900px) {
8
- .main { padding: 0 var(--s-4); }
9
- .page-head { flex-direction: column; gap: var(--s-3); }
10
- .config-grid { grid-template-columns: 1fr; }
11
- }
12
-
13
- /* Phone viewports (≤ 640px): sidebar disappears entirely from the grid
14
- layout; a circular floating button bottom-left toggles a full-screen
15
- drawer that re-mounts the sidebar over everything else. */
16
- @media (max-width: 640px) {
17
- /* Shrink the whole app to the visible area ABOVE the soft keyboard.
18
- --app-vh is the visualViewport height (main.js); the layout-viewport
19
- 100vh never shrinks for the keyboard, which left the terminal's bottom
20
- rows hidden behind it. 100dvh is the fallback before the JS runs. */
21
- .app.is-mobile { grid-template-columns: 1fr !important; height: var(--app-vh, 100dvh); }
22
- /* Keyboard up: keep the terminal's content above the floating key bar
23
- (TerminalKeyBar, ~50px). Only the terminal pane needs this — other
24
- pages have their own scroll padding. */
25
- body.kb-open .app.is-mobile .session-pane-body { padding-bottom: 50px; }
26
- .app.is-mobile .sidebar {
27
- /* Collapsed (drawer closed): out of the flow + invisible. */
28
- position: fixed;
29
- inset: 0;
30
- z-index: 200;
31
- width: 100%;
32
- height: 100%;
33
- transform: translateX(-100%);
34
- transition: transform .22s cubic-bezier(.4, 0, .2, 1);
35
- padding: var(--s-3);
36
- background: var(--bg);
37
- border-right: 0;
38
- overflow-y: auto;
39
- }
40
- .app.is-mobile.drawer-open .sidebar { transform: translateX(0); }
41
- /* Brand + nav labels come BACK on mobile — they were hidden by the
42
- 900px collapse rule above. */
43
- .app.is-mobile .brand-name,
44
- .app.is-mobile .nav-label,
45
- .app.is-mobile .nav-badge { opacity: 1; pointer-events: auto; }
46
- /* Sidebar drag handle isn't useful at full-screen; close button isn't
47
- either since the FAB doubles as a toggle. */
48
- .app.is-mobile .sidebar [aria-label="resize sidebar"] { display: none; }
49
- .app.is-mobile .collapse-toggle { display: none; }
50
-
51
- /* Main pane occupies full width — no sidebar gutter. */
52
- .app.is-mobile .main { padding: 0 var(--s-3); }
53
- /* Session pane edge-to-edge margin needs to match the new padding. */
54
- .app.is-mobile .session-pane { margin: 0 calc(-1 * var(--s-3)); }
55
-
56
- /* The bottom-left FAB (52px circle + 16px margin) overlaps content
57
- near the bottom-left corner. Reserve room inside scroll containers
58
- so the last button / row isn't trapped under it. */
59
- .app.is-mobile .settings-scroll { padding-bottom: 80px; }
60
- .app.is-mobile .remote-page { padding-bottom: 80px; }
61
- /* Launch page is its own block (no scroll wrapper) — push it up too
62
- so the Launch button doesn't end up under the FAB. */
63
- .app.is-mobile [data-panel="launch"] { padding-bottom: 80px; }
64
- .app.is-mobile [data-panel="about"] { padding-bottom: 80px; }
65
- /* Sessions terminal: the .session-actions footer / tabs at top means
66
- the FAB sits over the terminal corner — leave it; the user can
67
- scroll the terminal independently. */
68
-
69
- /* Touch scrolling: drive xterm's OWN scrollable .xterm-viewport natively
70
- so finger drags get real momentum and never "drop" mid-flick. A
71
- JS-intercepted scroll can't: the moment Chrome's compositor decides the
72
- drag is a vertical pan it cancels the touch sequence, so the handler
73
- only ever sees the opening frames — the "滑一点就断触" symptom. The
74
- catch is that the .xterm-screen layer (DOM rows on mobile) sits ON TOP
75
- of the viewport and swallows every touch; only the thin scrollbar strip
76
- at the right edge reached the viewport, which is exactly the
77
- "中间滑不动、侧边能滑" report. Make the screen transparent to pointers so
78
- the drag lands on the viewport underneath; pan-y marks it a vertical
79
- scroller so the compositor scrolls it directly. (Tap-to-focus is then
80
- re-added in JS — see TerminalView — since taps no longer reach xterm's
81
- own focus path.) */
82
- .app.is-mobile .terminal-host .xterm-screen { pointer-events: none; }
83
- .app.is-mobile .terminal-host .xterm-viewport { touch-action: pan-y; }
84
-
85
- /* Long inline code (URLs, paths) in the About / Remote bodies break
86
- out of card edges on a narrow viewport. Let them wrap on any
87
- character instead of stretching the line. */
88
- .settings-section code,
89
- .card code,
90
- .remote-fact code {
91
- word-break: break-all;
92
- white-space: normal;
93
- }
94
-
95
- /* iOS Safari + Edge auto-zoom the viewport when the user taps an
96
- <input>/<textarea> whose font-size is < 16px. Defensive bump on
97
- real form inputs. NOTE: we deliberately do NOT touch
98
- .xterm-helper-textarea here — xterm.js measures cell dimensions
99
- off that element's computed font, so forcing it to 16px makes the
100
- terminal render every glyph at ~16px regardless of the fontSize
101
- option we passed in. (TerminalView intentionally picks 11px on
102
- phones for ~50 cols.) On real iPhone the helper textarea anti-
103
- zoom is handled by the viewport meta tag instead — see
104
- public/index.html's `maximum-scale=1.0`. */
105
- .input,
106
- input[type="text"],
107
- input[type="search"],
108
- input[type="email"],
109
- input[type="number"],
110
- input[type="password"],
111
- input[type="url"],
112
- textarea,
113
- select { font-size: 16px !important; }
114
- }
115
-
116
- /* FAB + backdrop · sit above page content but BELOW dialogs. The
117
- `left` and `bottom` inline styles come from MobileNavFab.js (drag-
118
- persisted), so we don't set defaults here — the component seeds
119
- them on mount. `touch-action: none` stops the browser from also
120
- scrolling the page while the user is dragging the FAB. */
121
- .mobile-nav-fab {
122
- position: fixed;
123
- z-index: 220; /* above the terminal key bar (215) */
124
- width: 52px;
125
- height: 52px;
126
- border-radius: 50%;
127
- border: 1px solid var(--border-strong);
128
- background: var(--bg-elev);
129
- color: var(--ink);
130
- display: inline-flex;
131
- align-items: center;
132
- justify-content: center;
133
- box-shadow:
134
- 0 10px 24px -6px rgba(0,0,0,.28),
135
- 0 2px 4px rgba(0,0,0,.10);
136
- cursor: grab;
137
- touch-action: none;
138
- user-select: none;
139
- transition: box-shadow .15s, background .15s, transform .18s ease;
140
- }
141
- /* When the soft keyboard (and the terminal key bar that floats above it)
142
- is up, lift the FAB clear of the key bar so they don't overlap. The
143
- key bar is ~50px tall; nudge up a bit more for breathing room. */
144
- body.kb-open .mobile-nav-fab { transform: translateY(-60px); }
145
- /* No translateY on hover — would fight the inline left/bottom we set
146
- on every pointermove during drag, making the FAB jitter under the
147
- finger as :hover toggles on/off. Background-only hover for desktop
148
- pointers; touch never matches :hover. */
149
- .mobile-nav-fab:hover { background: var(--bg); }
150
- .mobile-nav-fab:active { cursor: grabbing; }
151
- /* Suppress the browser's default focus ring + tap highlight — on touch
152
- the ring lingers after every tap and reads as a stuck "selected"
153
- state on the FAB. We're not removing all affordance: the icon swap
154
- (hamburger ↔ X) + the is-open border change still communicate state.
155
- :focus-visible is also dropped here since the FAB is touch-first. */
156
- .mobile-nav-fab:focus,
157
- .mobile-nav-fab:focus-visible { outline: none; }
158
- .mobile-nav-fab { -webkit-tap-highlight-color: transparent; }
159
- .mobile-nav-fab svg { width: 22px; height: 22px; stroke-width: 2; pointer-events: none; }
160
- /* Open state stays the same paper white — only the icon swaps to X.
161
- Keeping the colour consistent reads as "same button, different
162
- mode" instead of two different controls. */
163
- .mobile-nav-fab.is-open {
164
- background: var(--bg-elev);
165
- color: var(--ink);
166
- border-color: var(--border-strong);
167
- }
168
-
169
- .mobile-nav-backdrop {
170
- position: fixed;
171
- inset: 0;
172
- z-index: 199; /* below sidebar (200) + fab (220), above content */
173
- background: rgba(26, 24, 21, 0.45);
174
- backdrop-filter: blur(2px);
175
- animation: panel-in .15s ease-out;
176
- }
1
+ /* Narrow viewports: force-collapse sidebar, single-col config grid */
2
+
3
+ /* Narrow desktop / tablet viewports: stack the page-head, single-column
4
+ config grids. Sidebar stays at full width — user can still toggle it
5
+ manually via the collapse button. Phone-sized (≤ 640px) gets the FAB
6
+ drawer treatment below. */
7
+ @media (max-width: 900px) {
8
+ .main { padding: 0 var(--s-4); }
9
+ .page-head { flex-direction: column; gap: var(--s-3); }
10
+ .config-grid { grid-template-columns: 1fr; }
11
+ }
12
+
13
+ /* Phone viewports (≤ 640px): sidebar disappears entirely from the grid
14
+ layout; a circular floating button bottom-left toggles a full-screen
15
+ drawer that re-mounts the sidebar over everything else. */
16
+ @media (max-width: 640px) {
17
+ /* Shrink the whole app to the visible area ABOVE the soft keyboard.
18
+ --app-vh is the visualViewport height (main.js); the layout-viewport
19
+ 100vh never shrinks for the keyboard, which left the terminal's bottom
20
+ rows hidden behind it. 100dvh is the fallback before the JS runs. */
21
+ .app.is-mobile { grid-template-columns: 1fr !important; height: var(--app-vh, 100dvh); }
22
+ /* Keyboard up: keep the terminal's content above the floating key bar
23
+ (TerminalKeyBar, ~50px). Only the terminal pane needs this — other
24
+ pages have their own scroll padding. */
25
+ body.kb-open .app.is-mobile .session-pane-body { padding-bottom: 50px; }
26
+ .app.is-mobile .sidebar {
27
+ /* Collapsed (drawer closed): out of the flow + invisible. */
28
+ position: fixed;
29
+ inset: 0;
30
+ z-index: 200;
31
+ width: 100%;
32
+ height: 100%;
33
+ transform: translateX(-100%);
34
+ transition: transform .22s cubic-bezier(.4, 0, .2, 1);
35
+ padding: var(--s-3);
36
+ background: var(--bg);
37
+ border-right: 0;
38
+ overflow-y: auto;
39
+ }
40
+ .app.is-mobile.drawer-open .sidebar { transform: translateX(0); }
41
+ /* Brand + nav labels come BACK on mobile — they were hidden by the
42
+ 900px collapse rule above. */
43
+ .app.is-mobile .brand-name,
44
+ .app.is-mobile .nav-label,
45
+ .app.is-mobile .nav-badge { opacity: 1; pointer-events: auto; }
46
+ /* Sidebar drag handle isn't useful at full-screen; close button isn't
47
+ either since the FAB doubles as a toggle. */
48
+ .app.is-mobile .sidebar [aria-label="resize sidebar"] { display: none; }
49
+ .app.is-mobile .collapse-toggle { display: none; }
50
+
51
+ /* Main pane occupies full width — no sidebar gutter. */
52
+ .app.is-mobile .main { padding: 0 var(--s-3); }
53
+ /* Session pane edge-to-edge margin needs to match the new padding. */
54
+ .app.is-mobile .session-pane { margin: 0 calc(-1 * var(--s-3)); }
55
+
56
+ /* The bottom-left FAB (52px circle + 16px margin) overlaps content
57
+ near the bottom-left corner. Reserve room inside scroll containers
58
+ so the last button / row isn't trapped under it. */
59
+ .app.is-mobile .settings-scroll { padding-bottom: 80px; }
60
+ .app.is-mobile .remote-page { padding-bottom: 80px; }
61
+ /* Launch page is its own block (no scroll wrapper) — push it up too
62
+ so the Launch button doesn't end up under the FAB. */
63
+ .app.is-mobile [data-panel="launch"] { padding-bottom: 80px; }
64
+ .app.is-mobile [data-panel="about"] { padding-bottom: 80px; }
65
+ /* Sessions terminal: the .session-actions footer / tabs at top means
66
+ the FAB sits over the terminal corner — leave it; the user can
67
+ scroll the terminal independently. */
68
+
69
+ /* Touch scrolling: drive xterm's OWN scrollable .xterm-viewport natively
70
+ so finger drags get real momentum and never "drop" mid-flick. A
71
+ JS-intercepted scroll can't: the moment Chrome's compositor decides the
72
+ drag is a vertical pan it cancels the touch sequence, so the handler
73
+ only ever sees the opening frames — the "滑一点就断触" symptom. The
74
+ catch is that the .xterm-screen layer (DOM rows on mobile) sits ON TOP
75
+ of the viewport and swallows every touch; only the thin scrollbar strip
76
+ at the right edge reached the viewport, which is exactly the
77
+ "中间滑不动、侧边能滑" report. Make the screen transparent to pointers so
78
+ the drag lands on the viewport underneath; pan-y marks it a vertical
79
+ scroller so the compositor scrolls it directly. (Tap-to-focus is then
80
+ re-added in JS — see TerminalView — since taps no longer reach xterm's
81
+ own focus path.) */
82
+ .app.is-mobile .terminal-host .xterm-screen { pointer-events: none; }
83
+ .app.is-mobile .terminal-host .xterm-viewport { touch-action: pan-y; }
84
+
85
+ /* Long inline code (URLs, paths) in the About / Remote bodies break
86
+ out of card edges on a narrow viewport. Let them wrap on any
87
+ character instead of stretching the line. */
88
+ .settings-section code,
89
+ .card code,
90
+ .remote-fact code {
91
+ word-break: break-all;
92
+ white-space: normal;
93
+ }
94
+
95
+ /* iOS Safari + Edge auto-zoom the viewport when the user taps an
96
+ <input>/<textarea> whose font-size is < 16px. Defensive bump on
97
+ real form inputs. NOTE: we deliberately do NOT touch
98
+ .xterm-helper-textarea here — xterm.js measures cell dimensions
99
+ off that element's computed font, so forcing it to 16px makes the
100
+ terminal render every glyph at ~16px regardless of the fontSize
101
+ option we passed in. (TerminalView intentionally picks 11px on
102
+ phones for ~50 cols.) On real iPhone the helper textarea anti-
103
+ zoom is handled by the viewport meta tag instead — see
104
+ public/index.html's `maximum-scale=1.0`. */
105
+ .input,
106
+ input[type="text"],
107
+ input[type="search"],
108
+ input[type="email"],
109
+ input[type="number"],
110
+ input[type="password"],
111
+ input[type="url"],
112
+ textarea,
113
+ select { font-size: 16px !important; }
114
+ }
115
+
116
+ /* FAB + backdrop · sit above page content but BELOW dialogs. The
117
+ `left` and `bottom` inline styles come from MobileNavFab.js (drag-
118
+ persisted), so we don't set defaults here — the component seeds
119
+ them on mount. `touch-action: none` stops the browser from also
120
+ scrolling the page while the user is dragging the FAB. */
121
+ .mobile-nav-fab {
122
+ position: fixed;
123
+ z-index: 220; /* above the terminal key bar (215) */
124
+ width: 52px;
125
+ height: 52px;
126
+ border-radius: 50%;
127
+ border: 1px solid var(--border-strong);
128
+ background: var(--bg-elev);
129
+ color: var(--ink);
130
+ display: inline-flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ box-shadow:
134
+ 0 10px 24px -6px rgba(0,0,0,.28),
135
+ 0 2px 4px rgba(0,0,0,.10);
136
+ cursor: grab;
137
+ touch-action: none;
138
+ user-select: none;
139
+ transition: box-shadow .15s, background .15s, transform .18s ease;
140
+ }
141
+ /* When the soft keyboard (and the terminal key bar that floats above it)
142
+ is up, lift the FAB clear of the key bar so they don't overlap. The
143
+ key bar is ~50px tall; nudge up a bit more for breathing room. */
144
+ body.kb-open .mobile-nav-fab { transform: translateY(-60px); }
145
+ /* No translateY on hover — would fight the inline left/bottom we set
146
+ on every pointermove during drag, making the FAB jitter under the
147
+ finger as :hover toggles on/off. Background-only hover for desktop
148
+ pointers; touch never matches :hover. */
149
+ .mobile-nav-fab:hover { background: var(--bg); }
150
+ .mobile-nav-fab:active { cursor: grabbing; }
151
+ /* Suppress the browser's default focus ring + tap highlight — on touch
152
+ the ring lingers after every tap and reads as a stuck "selected"
153
+ state on the FAB. We're not removing all affordance: the icon swap
154
+ (hamburger ↔ X) + the is-open border change still communicate state.
155
+ :focus-visible is also dropped here since the FAB is touch-first. */
156
+ .mobile-nav-fab:focus,
157
+ .mobile-nav-fab:focus-visible { outline: none; }
158
+ .mobile-nav-fab { -webkit-tap-highlight-color: transparent; }
159
+ .mobile-nav-fab svg { width: 22px; height: 22px; stroke-width: 2; pointer-events: none; }
160
+ /* Open state stays the same paper white — only the icon swaps to X.
161
+ Keeping the colour consistent reads as "same button, different
162
+ mode" instead of two different controls. */
163
+ .mobile-nav-fab.is-open {
164
+ background: var(--bg-elev);
165
+ color: var(--ink);
166
+ border-color: var(--border-strong);
167
+ }
168
+
169
+ .mobile-nav-backdrop {
170
+ position: fixed;
171
+ inset: 0;
172
+ z-index: 199; /* below sidebar (200) + fab (220), above content */
173
+ background: rgba(26, 24, 21, 0.45);
174
+ backdrop-filter: blur(2px);
175
+ animation: panel-in .15s ease-out;
176
+ }