@bakapiano/ccsm 0.5.0 → 0.8.3

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 (70) hide show
  1. package/README.md +172 -38
  2. package/bin/ccsm.js +194 -0
  3. package/lib/config.js +1 -0
  4. package/lib/favorites.js +23 -45
  5. package/lib/focus.js +90 -14
  6. package/lib/jsonStore.js +60 -0
  7. package/lib/labels.js +29 -0
  8. package/lib/webTerminal.js +173 -0
  9. package/lib/workspace.js +8 -4
  10. package/package.json +11 -3
  11. package/public/css/base.css +82 -0
  12. package/public/css/cards.css +149 -0
  13. package/public/css/feedback.css +219 -0
  14. package/public/css/forms.css +282 -0
  15. package/public/css/layout.css +107 -0
  16. package/public/css/modal.css +169 -0
  17. package/public/css/responsive.css +10 -0
  18. package/public/css/sidebar.css +165 -0
  19. package/public/css/tables.css +266 -0
  20. package/public/css/terminals.css +112 -0
  21. package/public/css/tokens.css +63 -0
  22. package/public/css/wco.css +70 -0
  23. package/public/css/widgets.css +204 -0
  24. package/public/favicon.svg +18 -0
  25. package/public/index.html +53 -379
  26. package/public/js/actions.js +87 -0
  27. package/public/js/api.js +103 -0
  28. package/public/js/backend.js +28 -0
  29. package/public/js/components/App.js +45 -0
  30. package/public/js/components/Card.js +24 -0
  31. package/public/js/components/DialogHost.js +45 -0
  32. package/public/js/components/Fab.js +11 -0
  33. package/public/js/components/FavoritesTable.js +81 -0
  34. package/public/js/components/Footer.js +12 -0
  35. package/public/js/components/NewSessionModal.js +142 -0
  36. package/public/js/components/OfflineBanner.js +52 -0
  37. package/public/js/components/PageHead.js +33 -0
  38. package/public/js/components/Pagination.js +27 -0
  39. package/public/js/components/ProgressList.js +32 -0
  40. package/public/js/components/RecentTable.js +68 -0
  41. package/public/js/components/RepoPicker.js +40 -0
  42. package/public/js/components/ReposEditor.js +74 -0
  43. package/public/js/components/ServerStatus.js +18 -0
  44. package/public/js/components/SessionsTable.js +71 -0
  45. package/public/js/components/Sidebar.js +52 -0
  46. package/public/js/components/SnapshotPanel.js +77 -0
  47. package/public/js/components/TerminalView.js +108 -0
  48. package/public/js/components/TitleCell.js +40 -0
  49. package/public/js/components/Toast.js +8 -0
  50. package/public/js/components/WorkspacePicker.js +19 -0
  51. package/public/js/components/WorkspacesGrid.js +41 -0
  52. package/public/js/dialog.js +59 -0
  53. package/public/js/html.js +6 -0
  54. package/public/js/icons.js +114 -0
  55. package/public/js/main.js +81 -0
  56. package/public/js/pages/AboutPage.js +85 -0
  57. package/public/js/pages/ConfigurePage.js +194 -0
  58. package/public/js/pages/LaunchPage.js +117 -0
  59. package/public/js/pages/SessionsPage.js +47 -0
  60. package/public/js/pages/TerminalsPage.js +74 -0
  61. package/public/js/state.js +87 -0
  62. package/public/js/streaming.js +96 -0
  63. package/public/js/toast.js +14 -0
  64. package/public/js/util.js +24 -0
  65. package/public/manifest.webmanifest +14 -0
  66. package/scripts/install.js +111 -0
  67. package/scripts/uninstall.js +56 -0
  68. package/server.js +314 -31
  69. package/public/app.js +0 -894
  70. package/public/styles.css +0 -1204
@@ -0,0 +1,112 @@
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
+ }
95
+ /* Don't override xterm's background — its renderer (canvas/WebGL) assumes
96
+ an opaque surface and ghosts on scroll if we force transparent. The
97
+ theme object in TerminalView.js already paints #faf9f5 to match the
98
+ surrounding card. */
99
+ .terminal-host .xterm-viewport {
100
+ scrollbar-width: thin;
101
+ }
102
+
103
+ .terminal-empty {
104
+ height: 100%;
105
+ display: flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ font-size: 13px;
109
+ color: var(--ink-muted);
110
+ }
111
+
112
+ .terminal-empty-page { width: 100%; }
@@ -0,0 +1,63 @@
1
+ /* ccsm · design tokens · v0.6 */
2
+
3
+ :root {
4
+ /* Surfaces — cream with neutral whites. Sidebar shares the page bg
5
+ so they read as one continuous surface; separation is just the
6
+ hairline border on .sidebar. */
7
+ --bg: #faf9f5;
8
+ --bg-elev: #ffffff;
9
+ --sidebar-bg: #faf9f5;
10
+ --sidebar-hover: #f0ece0;
11
+ --sidebar-active: #e8e3d5;
12
+
13
+ /* Borders & rules */
14
+ --border: #e8e3d5;
15
+ --border-soft: #ece8da;
16
+ --border-strong: #d4cdb8;
17
+
18
+ /* Ink */
19
+ --ink: #1a1815;
20
+ --ink-mid: #534e44;
21
+ --ink-muted: #8a8475;
22
+ --ink-faint: #b5af9d;
23
+
24
+ /* Accent — Claude warm copper. Slightly desaturated from raw #c45f3f so
25
+ solid-fill buttons feel calm against the cream surfaces, while still
26
+ 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);
31
+
32
+ /* Status */
33
+ --green: #4a8a4a;
34
+ --yellow: #c4892b;
35
+ --red: #b73f3f;
36
+ --blue: #4a73a5;
37
+
38
+ /* Type */
39
+ --body: "Geist", -apple-system, "Segoe UI", system-ui, sans-serif;
40
+ --mono: "JetBrains Mono", "Cascadia Mono", "Consolas", monospace;
41
+
42
+ /* Scale */
43
+ --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
44
+ --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;
45
+ --s-12: 48px; --s-16: 64px;
46
+
47
+ /* Radius */
48
+ --r-sm: 6px;
49
+ --r: 8px;
50
+ --r-md: 10px;
51
+ --r-lg: 14px;
52
+
53
+ /* Shadow — soft, like print on cream */
54
+ --shadow-sm: 0 1px 0 rgba(26, 24, 21, 0.04);
55
+ --shadow: 0 1px 2px rgba(26, 24, 21, 0.04),
56
+ 0 1px 0 rgba(26, 24, 21, 0.03);
57
+ --shadow-md: 0 4px 12px -2px rgba(26, 24, 21, 0.08),
58
+ 0 1px 0 rgba(26, 24, 21, 0.04);
59
+
60
+ /* Sidebar geometry */
61
+ --sidebar-w: 232px;
62
+ --sidebar-w-collapsed: 60px;
63
+ }
@@ -0,0 +1,70 @@
1
+ /* PWA / --app= window drag regions.
2
+ *
3
+ * `-webkit-app-region: drag` is a Chromium-only property; it has effect in
4
+ * Electron, installed PWA windows, AND in `--app=` chromeless mode where
5
+ * the manifest's display_override unlocks WCO-ish behaviour. In a plain
6
+ * browser tab it's silently ignored. We therefore apply it *unconditionally*
7
+ * (no `@media (display-mode: …)` gate) so any surface that does honour it
8
+ * gets the drag handles — particularly the case where Edge `--app=` reads
9
+ * our manifest, hides its own OS title bar, but still reports
10
+ * display-mode: browser. Without unconditional rules, that window has
11
+ * neither a native title bar to grab NOR app-region drag → undraggable.
12
+ */
13
+
14
+ .sidebar-brand,
15
+ .page-head,
16
+ .page-head-inner,
17
+ .page-title,
18
+ .page-subtitle {
19
+ -webkit-app-region: drag;
20
+ app-region: drag;
21
+ }
22
+
23
+ /* Any interactive element opts out of drag so click / focus / scroll
24
+ still reach the page. */
25
+ button, a, input, select, textarea, label,
26
+ .nav-item, .util-item, .collapse-toggle,
27
+ .action, .server-status,
28
+ .star-btn, .rename-btn, .card-fold, .modal-close,
29
+ .chip, .radio, .fab,
30
+ .ph-stat, .ph-divider {
31
+ -webkit-app-region: no-drag;
32
+ app-region: no-drag;
33
+ }
34
+
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
+ body.is-app .sidebar-brand,
41
+ body.is-app .page-head,
42
+ body.is-app .page-head-inner,
43
+ body.is-app .page-title,
44
+ body.is-app .page-subtitle {
45
+ user-select: none;
46
+ -webkit-user-select: none;
47
+ }
48
+
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. */
54
+ body.is-app .sidebar { padding-top: 0; }
55
+ 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
+ }
62
+
63
+ /* WCO-only · the OS title bar is fully gone, so right-pad the page-head
64
+ so the meta cluster doesn't slide under the floating close/max/min
65
+ controls. `.main`'s own 32px top padding already clears their height. */
66
+ @media (display-mode: window-controls-overlay) {
67
+ .page-head {
68
+ padding-right: calc(var(--s-10) + 100vw - env(titlebar-area-width, 100vw));
69
+ }
70
+ }
@@ -0,0 +1,204 @@
1
+ /* Workspace cards · clone-progress list · pagination · snapshot preview */
2
+
3
+ .workspace-grid {
4
+ display: grid;
5
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
6
+ gap: var(--s-3);
7
+ }
8
+ .workspace-card {
9
+ padding: var(--s-4);
10
+ border: 1px solid var(--border);
11
+ background: var(--bg-elev);
12
+ border-radius: var(--r-md);
13
+ transition: border-color .12s, box-shadow .12s;
14
+ }
15
+ .workspace-card:hover {
16
+ border-color: var(--border-strong);
17
+ box-shadow: var(--shadow);
18
+ }
19
+ .workspace-card.in-use {
20
+ background: var(--bg);
21
+ border-color: var(--ink-faint);
22
+ }
23
+ .workspace-card .ws-head {
24
+ display: flex;
25
+ align-items: baseline;
26
+ justify-content: space-between;
27
+ gap: var(--s-2);
28
+ margin-bottom: 4px;
29
+ }
30
+ .workspace-card .ws-name {
31
+ font-size: 14.5px;
32
+ font-weight: 600;
33
+ letter-spacing: -0.01em;
34
+ color: var(--ink);
35
+ }
36
+ .workspace-card .ws-tag {
37
+ font-family: var(--mono);
38
+ font-size: 10px;
39
+ text-transform: uppercase;
40
+ letter-spacing: 0.08em;
41
+ padding: 2px 7px;
42
+ border-radius: 4px;
43
+ background: var(--bg);
44
+ color: var(--ink-muted);
45
+ border: 1px solid var(--border-soft);
46
+ }
47
+ .workspace-card.in-use .ws-tag {
48
+ background: var(--bg-elev);
49
+ color: var(--ink-mid);
50
+ border-color: var(--ink-faint);
51
+ }
52
+ .workspace-card .ws-path {
53
+ font-family: var(--mono);
54
+ font-size: 11px;
55
+ color: var(--ink-muted);
56
+ word-break: break-all;
57
+ margin-bottom: var(--s-3);
58
+ }
59
+ .workspace-card .ws-repos {
60
+ display: flex;
61
+ flex-wrap: wrap;
62
+ gap: 4px;
63
+ }
64
+ .workspace-card .ws-repo {
65
+ font-family: var(--mono);
66
+ font-size: 10.5px;
67
+ padding: 2px 7px;
68
+ border-radius: 4px;
69
+ background: var(--bg);
70
+ color: var(--ink-muted);
71
+ border: 1px solid var(--border-soft);
72
+ }
73
+ .workspace-card .ws-repo.cloned {
74
+ color: var(--green);
75
+ background: rgba(74, 138, 74, 0.06);
76
+ border-color: rgba(74, 138, 74, 0.25);
77
+ }
78
+
79
+ /* Clone progress — one row per repo, NDJSON-driven by /api/sessions/new */
80
+ .progress-list {
81
+ display: flex;
82
+ flex-direction: column;
83
+ gap: var(--s-2);
84
+ margin-top: var(--s-3);
85
+ }
86
+ .progress-list:empty { display: none; }
87
+
88
+ .progress-item {
89
+ border: 1px solid var(--border);
90
+ background: var(--bg);
91
+ border-radius: var(--r-sm);
92
+ padding: var(--s-3) var(--s-4);
93
+ }
94
+ .progress-item .head {
95
+ display: grid;
96
+ grid-template-columns: 1fr auto auto;
97
+ align-items: baseline;
98
+ gap: var(--s-3);
99
+ margin-bottom: var(--s-2);
100
+ }
101
+ .progress-item .name {
102
+ font-family: var(--body);
103
+ font-size: 12.5px;
104
+ font-weight: 600;
105
+ color: var(--ink);
106
+ }
107
+ .progress-item .phase {
108
+ font-family: var(--mono);
109
+ font-size: 10.5px;
110
+ color: var(--ink-muted);
111
+ letter-spacing: 0.04em;
112
+ }
113
+ .progress-item .pct {
114
+ font-family: var(--mono);
115
+ font-size: 11.5px;
116
+ color: var(--ink-mid);
117
+ font-variant-numeric: tabular-nums;
118
+ }
119
+ .progress-bar {
120
+ height: 3px;
121
+ background: var(--border);
122
+ position: relative;
123
+ overflow: hidden;
124
+ border-radius: 2px;
125
+ }
126
+ .progress-bar .fill {
127
+ height: 100%;
128
+ width: 0;
129
+ background: var(--ink);
130
+ transition: width .2s ease;
131
+ border-radius: 2px;
132
+ }
133
+ .progress-bar .fill.indeterminate {
134
+ width: 35% !important;
135
+ animation: indeterm 1.4s ease-in-out infinite;
136
+ }
137
+ @keyframes indeterm {
138
+ from { transform: translateX(-110%); }
139
+ to { transform: translateX(330%); }
140
+ }
141
+ .progress-item.ok .fill { background: var(--green); }
142
+ .progress-item.error .fill { background: var(--red); }
143
+ .progress-item .detail {
144
+ margin-top: 4px;
145
+ font-family: var(--mono);
146
+ font-size: 10.5px;
147
+ color: var(--ink-muted);
148
+ min-height: 12px;
149
+ }
150
+
151
+ /* Pagination row — sits below table inside .card-body-flush card */
152
+ .pagination {
153
+ display: flex;
154
+ align-items: center;
155
+ gap: var(--s-3);
156
+ padding: var(--s-3) var(--s-6);
157
+ border-top: 1px solid var(--border-soft);
158
+ background: var(--bg);
159
+ font-size: 12.5px;
160
+ color: var(--ink-mid);
161
+ flex-wrap: wrap;
162
+ }
163
+ .pagination-info {
164
+ flex: 1;
165
+ text-align: center;
166
+ font-family: var(--mono);
167
+ font-size: 11.5px;
168
+ color: var(--ink-muted);
169
+ }
170
+ .pagination-info strong {
171
+ color: var(--ink);
172
+ font-weight: 600;
173
+ }
174
+ .pagination select {
175
+ font-size: 11.5px;
176
+ padding: 4px 24px 4px 8px;
177
+ }
178
+
179
+ /* Snapshot raw-text preview (collapsible <details>) */
180
+ .snapshot-detail { margin-top: var(--s-4); }
181
+ .snapshot-detail summary {
182
+ cursor: pointer;
183
+ font-size: 12.5px;
184
+ color: var(--ink-mid);
185
+ padding: var(--s-2) 0;
186
+ user-select: none;
187
+ font-weight: 500;
188
+ }
189
+ .snapshot-detail summary::marker { color: var(--ink-mid); }
190
+ .snapshot-detail summary:hover { color: var(--ink); }
191
+ .preview {
192
+ font-family: var(--mono);
193
+ font-size: 11.5px;
194
+ color: var(--ink-mid);
195
+ background: var(--bg);
196
+ border: 1px solid var(--border);
197
+ border-radius: var(--r-sm);
198
+ padding: var(--s-3);
199
+ margin-top: var(--s-2);
200
+ max-height: 280px;
201
+ overflow: auto;
202
+ white-space: pre;
203
+ line-height: 1.55;
204
+ }
@@ -0,0 +1,18 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <!-- terminal window body -->
3
+ <rect x="2" y="4" width="28" height="24" rx="3" fill="#1a1815"/>
4
+ <!-- title bar divider -->
5
+ <line x1="2" y1="10" x2="30" y2="10" stroke="#faf9f5" stroke-width="0.6" opacity="0.45"/>
6
+ <!-- traffic-light dots -->
7
+ <circle cx="6" cy="7" r="1" fill="#faf9f5"/>
8
+ <circle cx="9.5" cy="7" r="1" fill="#faf9f5" opacity="0.65"/>
9
+ <circle cx="13" cy="7" r="1" fill="#faf9f5" opacity="0.4"/>
10
+ <!-- ccsm prompt text -->
11
+ <text x="16" y="19.5"
12
+ text-anchor="middle"
13
+ dominant-baseline="central"
14
+ font-family="'Cascadia Mono', 'Consolas', 'Courier New', monospace"
15
+ font-weight="700"
16
+ font-size="10"
17
+ fill="#faf9f5">ccsm</text>
18
+ </svg>