@bakapiano/ccsm 0.14.0 → 0.15.0

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 (52) hide show
  1. package/CLAUDE.md +474 -475
  2. package/README.md +189 -190
  3. package/bin/ccsm.js +194 -194
  4. package/lib/cliActivity.js +118 -0
  5. package/lib/codexSeed.js +147 -0
  6. package/lib/config.js +211 -188
  7. package/lib/folders.js +105 -105
  8. package/lib/localCliSessions.js +489 -489
  9. package/lib/persistedSessions.js +144 -142
  10. package/lib/webTerminal.js +224 -224
  11. package/lib/workspace.js +230 -230
  12. package/package.json +57 -57
  13. package/public/css/base.css +99 -99
  14. package/public/css/cards.css +183 -183
  15. package/public/css/feedback.css +303 -303
  16. package/public/css/forms.css +405 -405
  17. package/public/css/layout.css +160 -160
  18. package/public/css/modal.css +190 -190
  19. package/public/css/responsive.css +10 -10
  20. package/public/css/sidebar.css +613 -608
  21. package/public/css/terminals.css +294 -294
  22. package/public/css/tokens.css +81 -81
  23. package/public/css/wco.css +98 -98
  24. package/public/css/widgets.css +1628 -1628
  25. package/public/index.html +111 -105
  26. package/public/js/api.js +296 -280
  27. package/public/js/components/AdoptModal.js +343 -343
  28. package/public/js/components/App.js +35 -35
  29. package/public/js/components/DirectoryPicker.js +203 -203
  30. package/public/js/components/EntityFormModal.js +141 -141
  31. package/public/js/components/Modal.js +51 -51
  32. package/public/js/components/OfflineBanner.js +93 -93
  33. package/public/js/components/PageTitleBar.js +13 -13
  34. package/public/js/components/Picker.js +179 -179
  35. package/public/js/components/Popover.js +55 -55
  36. package/public/js/components/Sidebar.js +299 -299
  37. package/public/js/components/TerminalView.js +314 -314
  38. package/public/js/components/useDragSort.js +67 -67
  39. package/public/js/dialog.js +67 -67
  40. package/public/js/icons.js +177 -177
  41. package/public/js/main.js +132 -132
  42. package/public/js/pages/AboutPage.js +165 -165
  43. package/public/js/pages/ConfigurePage.js +505 -475
  44. package/public/js/pages/LaunchPage.js +369 -369
  45. package/public/js/pages/SessionsPage.js +101 -97
  46. package/public/js/state.js +231 -231
  47. package/scripts/dev.js +44 -11
  48. package/scripts/install.js +158 -158
  49. package/scripts/restart-helper.js +91 -0
  50. package/server.js +1278 -1254
  51. package/lib/cliSessionWatcher.js +0 -275
  52. package/public/manifest.webmanifest +0 -15
@@ -1,294 +1,294 @@
1
- /* Terminals tab · left rail (active sessions) + right pane (xterm host) */
2
-
3
- .terminals-layout {
4
- display: grid;
5
- grid-template-columns: 240px 1fr;
6
- gap: var(--s-4);
7
- /* viewport minus page header + footer + padding; lets xterm fill height */
8
- height: calc(100vh - 220px);
9
- min-height: 480px;
10
- }
11
-
12
- .terminals-rail {
13
- background: var(--bg-elev);
14
- border: 1px solid var(--border);
15
- border-radius: var(--r-md);
16
- padding: var(--s-2);
17
- display: flex;
18
- flex-direction: column;
19
- gap: 2px;
20
- overflow-y: auto;
21
- }
22
- .terminals-rail-head {
23
- display: flex;
24
- justify-content: space-between;
25
- align-items: center;
26
- padding: var(--s-2) var(--s-3);
27
- font-size: 11px;
28
- text-transform: uppercase;
29
- letter-spacing: 0.06em;
30
- color: var(--ink-muted);
31
- border-bottom: 1px solid var(--border-soft);
32
- margin-bottom: var(--s-2);
33
- }
34
-
35
- /* button row showing one terminal in the rail */
36
- .terminal-row {
37
- appearance: none;
38
- background: transparent;
39
- border: 0;
40
- width: 100%;
41
- text-align: left;
42
- padding: 8px 10px;
43
- border-radius: var(--r-sm);
44
- cursor: pointer;
45
- display: grid;
46
- grid-template-columns: 10px 1fr auto auto;
47
- align-items: center;
48
- gap: 8px;
49
- color: var(--ink-mid);
50
- font-family: var(--body);
51
- font-size: 13px;
52
- transition: background .12s ease, color .12s ease;
53
- }
54
- .terminal-row:hover { background: var(--bg); color: var(--ink); }
55
- .terminal-row.is-active {
56
- background: var(--sidebar-active);
57
- color: var(--ink);
58
- }
59
- .terminal-row-title {
60
- white-space: nowrap;
61
- overflow: hidden;
62
- text-overflow: ellipsis;
63
- min-width: 0;
64
- font-weight: 500;
65
- }
66
- .terminal-row-meta {
67
- font-family: var(--mono);
68
- font-size: 10.5px;
69
- color: var(--ink-muted);
70
- font-variant-numeric: tabular-nums;
71
- }
72
- .terminal-row-actions { display: inline-flex; }
73
- .terminal-row .action.tiny.danger {
74
- padding: 1px 7px;
75
- font-size: 11px;
76
- min-width: 0;
77
- }
78
-
79
- /* right pane — full-height xterm host */
80
- .terminals-main {
81
- background: var(--bg);
82
- border: 1px solid var(--border);
83
- border-radius: var(--r-md);
84
- padding: var(--s-3);
85
- overflow: hidden;
86
- min-width: 0;
87
- display: flex;
88
- flex-direction: column;
89
- }
90
- .terminal-host {
91
- flex: 1;
92
- min-height: 0;
93
- width: 100%;
94
- /* IME composition (Chinese/Japanese pinyin) lives in absolutely-positioned
95
- .xterm-helper-textarea + .composition-view that grow with the composed
96
- string. Near the right edge they overflow the viewport and trigger a
97
- horizontal scrollbar that visually "pushes" the layout. Clip here so
98
- the overflow is silently absorbed instead of expanding the page.
99
- Do NOT touch the textarea/composition-view's own text properties —
100
- xterm relies on their single-line behaviour to keep IME events firing
101
- correctly (forcing pre-wrap / break-all eats compositionupdate events
102
- in Chromium and Chinese input stops working entirely). */
103
- overflow: hidden;
104
- contain: layout;
105
- }
106
- /* While the user is composing (IME), pin the helper textarea to the right
107
- edge of the terminal so it grows leftward instead of pushing the layout
108
- rightward. Only touches positioning — NOT width / wrap / max-width, which
109
- would break Chromium's compositionupdate event flow and stop Chinese
110
- input from working. The class is toggled by TerminalView.js. */
111
- .terminal-host.is-composing .xterm-helper-textarea {
112
- left: auto !important;
113
- right: 0 !important;
114
- text-align: right;
115
- /* xterm un-hides the textarea during composition so the user can see the
116
- composed string inline. We've moved it to the right edge to stop it
117
- pushing layout — but that means the composed pinyin would now visibly
118
- appear on the right. Hide its glyphs (caret + text) so the user only
119
- sees the OS-native IME candidate popup, which floats independently
120
- and is unaffected. */
121
- color: transparent !important;
122
- caret-color: transparent !important;
123
- background: transparent !important;
124
- text-shadow: none !important;
125
- }
126
- /* xterm also overlays a .composition-view (a small box at the cursor with
127
- the in-progress string + a gold caret using THEME.cursor). We can't
128
- display:none it — Chromium needs it in the layout tree to keep the IME
129
- compositionupdate events flowing — but we can make it visually invisible
130
- while leaving it laid out. */
131
- .terminal-host .composition-view {
132
- opacity: 0 !important;
133
- color: transparent !important;
134
- background: transparent !important;
135
- border-color: transparent !important;
136
- box-shadow: none !important;
137
- pointer-events: none;
138
- }
139
- /* Don't override xterm's background — its renderer (canvas/WebGL) assumes
140
- an opaque surface and ghosts on scroll if we force transparent. The
141
- theme object in TerminalView.js already paints #faf9f5 to match the
142
- surrounding card. */
143
- .terminal-host .xterm-viewport {
144
- scrollbar-width: thin;
145
- }
146
-
147
- .terminal-empty {
148
- height: 100%;
149
- display: flex;
150
- align-items: center;
151
- justify-content: center;
152
- font-size: 13px;
153
- color: var(--ink-muted);
154
- }
155
-
156
- .terminal-empty-page { width: 100%; }
157
-
158
- /* === v1.0 session pane === */
159
-
160
- .sessions-empty {
161
- display: flex;
162
- align-items: center;
163
- justify-content: center;
164
- min-height: 60vh;
165
- /* Decorative faint hairline grid, only in this empty state — adds
166
- editorial atmosphere without affecting any real content view. */
167
- background-image:
168
- linear-gradient(to right, rgba(216, 212, 198, 0.5) 1px, transparent 1px),
169
- linear-gradient(to bottom, rgba(216, 212, 198, 0.5) 1px, transparent 1px);
170
- background-size: 56px 56px;
171
- background-position: center;
172
- position: relative;
173
- }
174
- .sessions-empty::before,
175
- .sessions-empty::after {
176
- content: "";
177
- position: absolute;
178
- inset: 0;
179
- pointer-events: none;
180
- }
181
- .sessions-empty::before {
182
- background: radial-gradient(ellipse at center, transparent 0%, var(--bg) 75%);
183
- }
184
- .sessions-empty-card {
185
- text-align: center;
186
- padding: var(--s-12) var(--s-10);
187
- background: var(--bg-elev);
188
- border: 1px solid var(--border-soft);
189
- border-radius: 6px;
190
- max-width: 440px;
191
- position: relative;
192
- z-index: 1;
193
- box-shadow: var(--shadow-lg);
194
- }
195
- .sessions-empty-card::before {
196
- content: "· EMPTY ·";
197
- display: block;
198
- font-family: var(--mono);
199
- font-size: 10px;
200
- letter-spacing: 0.28em;
201
- color: var(--ink-faint);
202
- margin-bottom: var(--s-4);
203
- }
204
- .sessions-empty-card h2 {
205
- margin: 0 0 var(--s-3);
206
- font-size: 20px;
207
- font-weight: 600;
208
- letter-spacing: -0.015em;
209
- line-height: 1.2;
210
- color: var(--ink);
211
- }
212
- .sessions-empty-card p {
213
- margin: 0 0 var(--s-5);
214
- color: var(--ink-mid);
215
- font-size: 13.5px;
216
- line-height: 1.55;
217
- }
218
-
219
- .session-pane {
220
- display: flex;
221
- flex-direction: column;
222
- /* Fill the entire content area edge-to-edge — negative horizontal margin
223
- cancels .main's horizontal padding so the terminal touches the window
224
- edges (and the sidebar border) with no surrounding chrome. */
225
- flex: 1;
226
- min-height: 0;
227
- height: 100%;
228
- margin: 0 calc(-1 * var(--s-4));
229
- /* Cancel the tab-panel gap above so the terminal sits flush under the
230
- title bar with no white band. */
231
- margin-top: calc(-1 * var(--s-4));
232
- background: var(--bg-elev);
233
- overflow: hidden;
234
- }
235
- .session-pane-head {
236
- display: flex;
237
- align-items: center;
238
- gap: var(--s-3);
239
- padding: var(--s-3) var(--s-4);
240
- border-bottom: 1px solid var(--border);
241
- background: var(--bg);
242
- flex-wrap: wrap;
243
- }
244
- .session-pane-title {
245
- display: flex;
246
- align-items: center;
247
- gap: var(--s-2);
248
- }
249
- .session-pane-title h2 {
250
- margin: 0;
251
- font-size: 14.5px;
252
- font-weight: 600;
253
- }
254
- .session-pane-meta {
255
- display: flex;
256
- gap: var(--s-3);
257
- align-items: center;
258
- font-size: 11.5px;
259
- flex: 1;
260
- overflow: hidden;
261
- }
262
- .session-pane-meta .mono {
263
- font-family: var(--mono);
264
- color: var(--ink-mid);
265
- white-space: nowrap;
266
- overflow: hidden;
267
- text-overflow: ellipsis;
268
- max-width: 50%;
269
- }
270
- .session-pane-meta .muted {
271
- color: var(--ink-muted);
272
- }
273
- .session-pane-actions {
274
- display: flex;
275
- gap: var(--s-2);
276
- flex-shrink: 0;
277
- }
278
- .session-pane-body {
279
- flex: 1;
280
- min-height: 0;
281
- background: #1a1815;
282
- }
283
- .session-pane-body .terminal-host {
284
- height: 100%;
285
- }
286
- .session-pane-body .terminal-empty {
287
- background: var(--bg);
288
- display: flex;
289
- flex-direction: column;
290
- align-items: center;
291
- justify-content: center;
292
- gap: var(--s-3);
293
- height: 100%;
294
- }
1
+ /* Terminals tab · left rail (active sessions) + right pane (xterm host) */
2
+
3
+ .terminals-layout {
4
+ display: grid;
5
+ grid-template-columns: 240px 1fr;
6
+ gap: var(--s-4);
7
+ /* viewport minus page header + footer + padding; lets xterm fill height */
8
+ height: calc(100vh - 220px);
9
+ min-height: 480px;
10
+ }
11
+
12
+ .terminals-rail {
13
+ background: var(--bg-elev);
14
+ border: 1px solid var(--border);
15
+ border-radius: var(--r-md);
16
+ padding: var(--s-2);
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: 2px;
20
+ overflow-y: auto;
21
+ }
22
+ .terminals-rail-head {
23
+ display: flex;
24
+ justify-content: space-between;
25
+ align-items: center;
26
+ padding: var(--s-2) var(--s-3);
27
+ font-size: 11px;
28
+ text-transform: uppercase;
29
+ letter-spacing: 0.06em;
30
+ color: var(--ink-muted);
31
+ border-bottom: 1px solid var(--border-soft);
32
+ margin-bottom: var(--s-2);
33
+ }
34
+
35
+ /* button row showing one terminal in the rail */
36
+ .terminal-row {
37
+ appearance: none;
38
+ background: transparent;
39
+ border: 0;
40
+ width: 100%;
41
+ text-align: left;
42
+ padding: 8px 10px;
43
+ border-radius: var(--r-sm);
44
+ cursor: pointer;
45
+ display: grid;
46
+ grid-template-columns: 10px 1fr auto auto;
47
+ align-items: center;
48
+ gap: 8px;
49
+ color: var(--ink-mid);
50
+ font-family: var(--body);
51
+ font-size: 13px;
52
+ transition: background .12s ease, color .12s ease;
53
+ }
54
+ .terminal-row:hover { background: var(--bg); color: var(--ink); }
55
+ .terminal-row.is-active {
56
+ background: var(--sidebar-active);
57
+ color: var(--ink);
58
+ }
59
+ .terminal-row-title {
60
+ white-space: nowrap;
61
+ overflow: hidden;
62
+ text-overflow: ellipsis;
63
+ min-width: 0;
64
+ font-weight: 500;
65
+ }
66
+ .terminal-row-meta {
67
+ font-family: var(--mono);
68
+ font-size: 10.5px;
69
+ color: var(--ink-muted);
70
+ font-variant-numeric: tabular-nums;
71
+ }
72
+ .terminal-row-actions { display: inline-flex; }
73
+ .terminal-row .action.tiny.danger {
74
+ padding: 1px 7px;
75
+ font-size: 11px;
76
+ min-width: 0;
77
+ }
78
+
79
+ /* right pane — full-height xterm host */
80
+ .terminals-main {
81
+ background: var(--bg);
82
+ border: 1px solid var(--border);
83
+ border-radius: var(--r-md);
84
+ padding: var(--s-3);
85
+ overflow: hidden;
86
+ min-width: 0;
87
+ display: flex;
88
+ flex-direction: column;
89
+ }
90
+ .terminal-host {
91
+ flex: 1;
92
+ min-height: 0;
93
+ width: 100%;
94
+ /* IME composition (Chinese/Japanese pinyin) lives in absolutely-positioned
95
+ .xterm-helper-textarea + .composition-view that grow with the composed
96
+ string. Near the right edge they overflow the viewport and trigger a
97
+ horizontal scrollbar that visually "pushes" the layout. Clip here so
98
+ the overflow is silently absorbed instead of expanding the page.
99
+ Do NOT touch the textarea/composition-view's own text properties —
100
+ xterm relies on their single-line behaviour to keep IME events firing
101
+ correctly (forcing pre-wrap / break-all eats compositionupdate events
102
+ in Chromium and Chinese input stops working entirely). */
103
+ overflow: hidden;
104
+ contain: layout;
105
+ }
106
+ /* While the user is composing (IME), pin the helper textarea to the right
107
+ edge of the terminal so it grows leftward instead of pushing the layout
108
+ rightward. Only touches positioning — NOT width / wrap / max-width, which
109
+ would break Chromium's compositionupdate event flow and stop Chinese
110
+ input from working. The class is toggled by TerminalView.js. */
111
+ .terminal-host.is-composing .xterm-helper-textarea {
112
+ left: auto !important;
113
+ right: 0 !important;
114
+ text-align: right;
115
+ /* xterm un-hides the textarea during composition so the user can see the
116
+ composed string inline. We've moved it to the right edge to stop it
117
+ pushing layout — but that means the composed pinyin would now visibly
118
+ appear on the right. Hide its glyphs (caret + text) so the user only
119
+ sees the OS-native IME candidate popup, which floats independently
120
+ and is unaffected. */
121
+ color: transparent !important;
122
+ caret-color: transparent !important;
123
+ background: transparent !important;
124
+ text-shadow: none !important;
125
+ }
126
+ /* xterm also overlays a .composition-view (a small box at the cursor with
127
+ the in-progress string + a gold caret using THEME.cursor). We can't
128
+ display:none it — Chromium needs it in the layout tree to keep the IME
129
+ compositionupdate events flowing — but we can make it visually invisible
130
+ while leaving it laid out. */
131
+ .terminal-host .composition-view {
132
+ opacity: 0 !important;
133
+ color: transparent !important;
134
+ background: transparent !important;
135
+ border-color: transparent !important;
136
+ box-shadow: none !important;
137
+ pointer-events: none;
138
+ }
139
+ /* Don't override xterm's background — its renderer (canvas/WebGL) assumes
140
+ an opaque surface and ghosts on scroll if we force transparent. The
141
+ theme object in TerminalView.js already paints #faf9f5 to match the
142
+ surrounding card. */
143
+ .terminal-host .xterm-viewport {
144
+ scrollbar-width: thin;
145
+ }
146
+
147
+ .terminal-empty {
148
+ height: 100%;
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ font-size: 13px;
153
+ color: var(--ink-muted);
154
+ }
155
+
156
+ .terminal-empty-page { width: 100%; }
157
+
158
+ /* === v1.0 session pane === */
159
+
160
+ .sessions-empty {
161
+ display: flex;
162
+ align-items: center;
163
+ justify-content: center;
164
+ min-height: 60vh;
165
+ /* Decorative faint hairline grid, only in this empty state — adds
166
+ editorial atmosphere without affecting any real content view. */
167
+ background-image:
168
+ linear-gradient(to right, rgba(216, 212, 198, 0.5) 1px, transparent 1px),
169
+ linear-gradient(to bottom, rgba(216, 212, 198, 0.5) 1px, transparent 1px);
170
+ background-size: 56px 56px;
171
+ background-position: center;
172
+ position: relative;
173
+ }
174
+ .sessions-empty::before,
175
+ .sessions-empty::after {
176
+ content: "";
177
+ position: absolute;
178
+ inset: 0;
179
+ pointer-events: none;
180
+ }
181
+ .sessions-empty::before {
182
+ background: radial-gradient(ellipse at center, transparent 0%, var(--bg) 75%);
183
+ }
184
+ .sessions-empty-card {
185
+ text-align: center;
186
+ padding: var(--s-12) var(--s-10);
187
+ background: var(--bg-elev);
188
+ border: 1px solid var(--border-soft);
189
+ border-radius: 6px;
190
+ max-width: 440px;
191
+ position: relative;
192
+ z-index: 1;
193
+ box-shadow: var(--shadow-lg);
194
+ }
195
+ .sessions-empty-card::before {
196
+ content: "· EMPTY ·";
197
+ display: block;
198
+ font-family: var(--mono);
199
+ font-size: 10px;
200
+ letter-spacing: 0.28em;
201
+ color: var(--ink-faint);
202
+ margin-bottom: var(--s-4);
203
+ }
204
+ .sessions-empty-card h2 {
205
+ margin: 0 0 var(--s-3);
206
+ font-size: 20px;
207
+ font-weight: 600;
208
+ letter-spacing: -0.015em;
209
+ line-height: 1.2;
210
+ color: var(--ink);
211
+ }
212
+ .sessions-empty-card p {
213
+ margin: 0 0 var(--s-5);
214
+ color: var(--ink-mid);
215
+ font-size: 13.5px;
216
+ line-height: 1.55;
217
+ }
218
+
219
+ .session-pane {
220
+ display: flex;
221
+ flex-direction: column;
222
+ /* Fill the entire content area edge-to-edge — negative horizontal margin
223
+ cancels .main's horizontal padding so the terminal touches the window
224
+ edges (and the sidebar border) with no surrounding chrome. */
225
+ flex: 1;
226
+ min-height: 0;
227
+ height: 100%;
228
+ margin: 0 calc(-1 * var(--s-4));
229
+ /* Cancel the tab-panel gap above so the terminal sits flush under the
230
+ title bar with no white band. */
231
+ margin-top: calc(-1 * var(--s-4));
232
+ background: var(--bg-elev);
233
+ overflow: hidden;
234
+ }
235
+ .session-pane-head {
236
+ display: flex;
237
+ align-items: center;
238
+ gap: var(--s-3);
239
+ padding: var(--s-3) var(--s-4);
240
+ border-bottom: 1px solid var(--border);
241
+ background: var(--bg);
242
+ flex-wrap: wrap;
243
+ }
244
+ .session-pane-title {
245
+ display: flex;
246
+ align-items: center;
247
+ gap: var(--s-2);
248
+ }
249
+ .session-pane-title h2 {
250
+ margin: 0;
251
+ font-size: 14.5px;
252
+ font-weight: 600;
253
+ }
254
+ .session-pane-meta {
255
+ display: flex;
256
+ gap: var(--s-3);
257
+ align-items: center;
258
+ font-size: 11.5px;
259
+ flex: 1;
260
+ overflow: hidden;
261
+ }
262
+ .session-pane-meta .mono {
263
+ font-family: var(--mono);
264
+ color: var(--ink-mid);
265
+ white-space: nowrap;
266
+ overflow: hidden;
267
+ text-overflow: ellipsis;
268
+ max-width: 50%;
269
+ }
270
+ .session-pane-meta .muted {
271
+ color: var(--ink-muted);
272
+ }
273
+ .session-pane-actions {
274
+ display: flex;
275
+ gap: var(--s-2);
276
+ flex-shrink: 0;
277
+ }
278
+ .session-pane-body {
279
+ flex: 1;
280
+ min-height: 0;
281
+ background: #1a1815;
282
+ }
283
+ .session-pane-body .terminal-host {
284
+ height: 100%;
285
+ }
286
+ .session-pane-body .terminal-empty {
287
+ background: var(--bg);
288
+ display: flex;
289
+ flex-direction: column;
290
+ align-items: center;
291
+ justify-content: center;
292
+ gap: var(--s-3);
293
+ height: 100%;
294
+ }