@bakapiano/ccsm 0.9.0 → 0.10.1

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 (69) hide show
  1. package/CLAUDE.md +222 -195
  2. package/README.md +77 -79
  3. package/lib/cliSessionWatcher.js +249 -0
  4. package/lib/config.js +101 -24
  5. package/lib/folders.js +96 -0
  6. package/lib/localCliSessions.js +177 -0
  7. package/lib/persistedSessions.js +134 -0
  8. package/lib/webTerminal.js +31 -18
  9. package/lib/workspace.js +26 -4
  10. package/package.json +1 -1
  11. package/public/assets/claude-color.svg +1 -0
  12. package/public/assets/codex-color.svg +1 -0
  13. package/public/assets/copilot-color.svg +1 -0
  14. package/public/css/base.css +22 -5
  15. package/public/css/cards.css +37 -3
  16. package/public/css/feedback.css +127 -43
  17. package/public/css/forms.css +97 -25
  18. package/public/css/layout.css +74 -26
  19. package/public/css/modal.css +40 -26
  20. package/public/css/responsive.css +2 -2
  21. package/public/css/sidebar.css +424 -25
  22. package/public/css/terminals.css +138 -0
  23. package/public/css/tokens.css +28 -12
  24. package/public/css/wco.css +38 -39
  25. package/public/css/widgets.css +1177 -6
  26. package/public/index.html +35 -2
  27. package/public/js/api.js +194 -37
  28. package/public/js/components/AdoptModal.js +171 -0
  29. package/public/js/components/App.js +1 -11
  30. package/public/js/components/DirectoryPicker.js +203 -0
  31. package/public/js/components/EntityFormModal.js +105 -0
  32. package/public/js/components/Modal.js +51 -0
  33. package/public/js/components/OfflineBanner.js +29 -23
  34. package/public/js/components/PageTitleBar.js +13 -0
  35. package/public/js/components/Picker.js +179 -0
  36. package/public/js/components/Popover.js +55 -0
  37. package/public/js/components/Sidebar.js +219 -32
  38. package/public/js/components/TerminalView.js +27 -3
  39. package/public/js/components/useDragSort.js +67 -0
  40. package/public/js/dialog.js +10 -2
  41. package/public/js/icons.js +66 -3
  42. package/public/js/main.js +54 -3
  43. package/public/js/pages/AboutPage.js +80 -0
  44. package/public/js/pages/ConfigurePage.js +429 -207
  45. package/public/js/pages/LaunchPage.js +326 -86
  46. package/public/js/pages/SessionsPage.js +91 -41
  47. package/public/js/state.js +102 -73
  48. package/public/manifest.webmanifest +2 -2
  49. package/scripts/install.js +7 -2
  50. package/server.js +755 -441
  51. package/lib/favorites.js +0 -51
  52. package/lib/focus.js +0 -369
  53. package/lib/labels.js +0 -29
  54. package/lib/launcher.js +0 -219
  55. package/lib/sessions.js +0 -272
  56. package/lib/snapshot.js +0 -141
  57. package/public/js/actions.js +0 -107
  58. package/public/js/components/Fab.js +0 -11
  59. package/public/js/components/FavoritesTable.js +0 -81
  60. package/public/js/components/Footer.js +0 -12
  61. package/public/js/components/NewSessionModal.js +0 -153
  62. package/public/js/components/PageHead.js +0 -33
  63. package/public/js/components/Pagination.js +0 -27
  64. package/public/js/components/RecentTable.js +0 -68
  65. package/public/js/components/SessionsTable.js +0 -71
  66. package/public/js/components/SnapshotPanel.js +0 -77
  67. package/public/js/components/TitleCell.js +0 -40
  68. package/public/js/components/WorkspacesGrid.js +0 -41
  69. package/public/js/pages/TerminalsPage.js +0 -74
@@ -154,3 +154,141 @@
154
154
  }
155
155
 
156
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
+ }
@@ -10,6 +10,13 @@
10
10
  --sidebar-hover: #f0ece0;
11
11
  --sidebar-active: #e8e3d5;
12
12
 
13
+ /* Neutral UI chrome — borders, footer strip, etc. These are NEVER
14
+ re-derived from the accent so dividers stay calm regardless of
15
+ theme choice. */
16
+ --ui-border: #d8d4c6;
17
+ --ui-border-soft: #e6e2d4;
18
+ --ui-bg: #f0ece0;
19
+
13
20
  /* Borders & rules */
14
21
  --border: #e8e3d5;
15
22
  --border-soft: #ece8da;
@@ -24,10 +31,10 @@
24
31
  /* Accent — Claude warm copper. Slightly desaturated from raw #c45f3f so
25
32
  solid-fill buttons feel calm against the cream surfaces, while still
26
33
  reading as the same brand hue in star icons, focus rings, etc. */
27
- --accent: #b3614a;
28
- --accent-deep: #8f4a36;
29
- --accent-soft: rgba(179, 97, 74, 0.10);
30
- --accent-softer: rgba(179, 97, 74, 0.04);
34
+ --accent: #2f6fa3;
35
+ --accent-deep: #25577f;
36
+ --accent-soft: rgba(47, 111, 163, 0.10);
37
+ --accent-softer: rgba(47, 111, 163, 0.04);
31
38
 
32
39
  /* Status */
33
40
  --green: #4a8a4a;
@@ -36,19 +43,21 @@
36
43
  --blue: #4a73a5;
37
44
 
38
45
  /* Type */
39
- --body: "Geist", -apple-system, "Segoe UI", system-ui, sans-serif;
40
- --mono: "JetBrains Mono", "Cascadia Mono", "Consolas", monospace;
46
+ --body: "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
47
+ --display: "Geist", ui-sans-serif, system-ui, sans-serif;
48
+ --mono: "JetBrains Mono", "Cascadia Mono", "Consolas", monospace;
41
49
 
42
50
  /* Scale */
43
51
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
44
52
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;
45
53
  --s-12: 48px; --s-16: 64px;
46
54
 
47
- /* Radius */
48
- --r-sm: 6px;
49
- --r: 8px;
50
- --r-md: 10px;
51
- --r-lg: 14px;
55
+ /* Radius — tightened in v1.0 for a more codex-like crisp feel.
56
+ 999px stays in code where pills are intentional (status dots etc). */
57
+ --r-sm: 3px;
58
+ --r: 4px;
59
+ --r-md: 5px;
60
+ --r-lg: 6px;
52
61
 
53
62
  /* Shadow — soft, like print on cream */
54
63
  --shadow-sm: 0 1px 0 rgba(26, 24, 21, 0.04);
@@ -56,8 +65,15 @@
56
65
  0 1px 0 rgba(26, 24, 21, 0.03);
57
66
  --shadow-md: 0 4px 12px -2px rgba(26, 24, 21, 0.08),
58
67
  0 1px 0 rgba(26, 24, 21, 0.04);
68
+ --shadow-lg: 0 18px 40px -16px rgba(26, 24, 21, 0.18),
69
+ 0 4px 12px -4px rgba(26, 24, 21, 0.10);
70
+
71
+ /* Subtle paper grain — applied as a layered background on .app to give
72
+ surfaces the texture of laid paper rather than flat color. SVG noise
73
+ keeps it crisp at any zoom level. */
74
+ --paper-noise: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.10 0 0 0 0 0.09 0 0 0 0 0.07 0 0 0 0.035 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
59
75
 
60
76
  /* Sidebar geometry */
61
77
  --sidebar-w: 232px;
62
- --sidebar-w-collapsed: 60px;
78
+ --sidebar-w-collapsed: 44px;
63
79
  }
@@ -12,6 +12,8 @@
12
12
  */
13
13
 
14
14
  .sidebar-brand,
15
+ .sidebar-top,
16
+ .page-title-bar,
15
17
  .page-head,
16
18
  .page-head-inner,
17
19
  .page-title,
@@ -27,17 +29,16 @@ button, a, input, select, textarea, label,
27
29
  .action, .server-status,
28
30
  .star-btn, .rename-btn, .card-fold, .modal-close,
29
31
  .chip, .radio, .fab,
30
- .ph-stat, .ph-divider {
32
+ .ph-stat, .ph-divider,
33
+ .page-title-bar-actions,
34
+ .session-title-action {
31
35
  -webkit-app-region: no-drag;
32
36
  app-region: no-drag;
33
37
  }
34
38
 
35
- /* `user-select: none` on the drag-target text is needed so clicking the
36
- page title doesn't start a text selection instead of a window drag. But
37
- we only want this in PWA-like contexts — in a regular browser tab the
38
- user should still be able to select the title text. Runtime JS adds
39
- `body.is-app` when not in display-mode:browser; see main.js. */
40
39
  body.is-app .sidebar-brand,
40
+ body.is-app .sidebar-top,
41
+ body.is-app .page-title-bar,
41
42
  body.is-app .page-head,
42
43
  body.is-app .page-head-inner,
43
44
  body.is-app .page-title,
@@ -46,37 +47,23 @@ body.is-app .page-subtitle {
46
47
  -webkit-user-select: none;
47
48
  }
48
49
 
49
- /* In an app window, .main and .sidebar's own top padding is "blank space"
50
- that has no drag region clicking the topmost 32px does nothing. Move
51
- that padding into the draggable child elements (.sidebar-brand and
52
- .page-head) so the windowtop is grabbable all the way to y=0. Visually
53
- nothing shifts; behaviourally the OS-title-bar zone now responds. */
50
+ /* In an app/PWA window, the OS title bar is hidden and only floating
51
+ close/max/min controls remain in the top-right. The 40px top band of
52
+ ccsm (sidebar-top + page-title-bar) IS that title bar — it's already
53
+ tall enough, sits at y=0 with no extra padding, and gets a drag region
54
+ so the user can grab anywhere along it to move the window. */
54
55
  body.is-app .sidebar { padding-top: 0; }
55
56
  body.is-app .main { padding-top: 0; }
56
- body.is-app .sidebar-brand {
57
- padding-top: calc(var(--s-4) + var(--s-4)); /* 32px = old sidebar.pt + old brand.pt */
58
- }
59
- body.is-app .page-head {
60
- padding-top: var(--s-8); /* 32px = old main.pt */
61
- /* Reserve space on the right for the OS window controls (close /
62
- maximize / minimize) that float over the top-right of every
63
- chromeless app window — both --app= (display-mode: standalone)
64
- and PWA. Without this, the server-status pill + Refresh button
65
- slide under those controls and stop being clickable. ~150px covers
66
- three Windows controls + a little breathing room; macOS traffic
67
- lights are on the left so this is harmless there. The WCO override
68
- below uses the precise env() value when the API is available. */
69
- padding-right: 150px;
57
+
58
+ /* Reserve room on the right of page-title-bar so its action buttons don't
59
+ slide under the floating OS controls. 150px covers Windows controls
60
+ (~46px each × 3) with breathing room; macOS traffic lights are on the
61
+ left so this padding is harmless there. WCO override below uses the
62
+ precise env() value when available. */
63
+ body.is-app .page-title-bar {
64
+ padding-right: calc(var(--s-4) + 150px);
70
65
  }
71
66
 
72
- /* In app/PWA mode, hide the in-page title/subtitle entirely. The sidebar
73
- nav already tells the user which section they're on, and the OS title
74
- bar (or the floating WCO controls) is the only chrome we want. This
75
- reclaims a chunky 60+ px of vertical real estate at the top of every
76
- tab — really noticeable in the Terminals tab where xterm benefits
77
- from every pixel. The page-head wrapper survives because it still
78
- hosts the status pill + Refresh button on the right and remains
79
- draggable. */
80
67
  body.is-app .page-title,
81
68
  body.is-app .page-subtitle {
82
69
  display: none;
@@ -88,12 +75,24 @@ body.is-app .page-head {
88
75
  min-height: 28px;
89
76
  }
90
77
 
91
- /* WCO-only · the OS title bar is fully gone, so right-pad the page-head
92
- so the meta cluster doesn't slide under the floating close/max/min
93
- controls. `.main`'s own 32px top padding already clears their height. */
78
+ /* PWA / WCO / --app= mode: shrink the top band to 32px so its mid-line
79
+ matches the OS-floated close/max/min icons (which sit in a fixed ~32px
80
+ bar at y=0 and can't be moved). Outside app mode we keep the roomier
81
+ 40px band — see sidebar.css / layout.css. */
82
+ body.is-app .page-title-bar,
83
+ body.is-app .sidebar-top {
84
+ height: 32px;
85
+ min-height: 32px;
86
+ }
87
+ body.is-app .sidebar-brand,
88
+ body.is-app .sidebar-brand-button,
89
+ body.is-app .collapse-toggle {
90
+ height: 32px;
91
+ min-height: 32px;
92
+ }
93
+
94
94
  @media (display-mode: window-controls-overlay) {
95
- .page-head {
96
- padding-right: calc(var(--s-10) + 100vw - env(titlebar-area-width, 100vw));
97
- min-height: env(titlebar-area-height, 32px);
95
+ body.is-app .page-title-bar {
96
+ padding-right: calc(var(--s-4) + 100vw - env(titlebar-area-width, 100vw));
98
97
  }
99
98
  }