@bakapiano/ccsm 0.22.3 → 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 +225 -225
  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 +148 -22
  42. package/public/js/components/TerminalResizeDebouncer.js +126 -0
  43. package/public/js/components/XtermTerminal.js +62 -15
  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/README.md CHANGED
@@ -1,189 +1,189 @@
1
- # ccsm — Claude Code Session Manager
2
-
3
- A single pane over every Claude / Codex / Copilot CLI session on your
4
- machine. Each session runs inside the page (xterm.js + a PTY pool in
5
- the local backend), gets recorded, and re-attaches to the exact
6
- upstream conversation when you click it again.
7
-
8
- [![open](https://img.shields.io/badge/open-bakapiano.github.io%2Fccsm-1a1815?style=flat-square)](https://bakapiano.github.io/ccsm/)
9
-
10
- ```
11
- ┌── browser ─────────────────────────┐
12
- │ https://bakapiano.github.io/ccsm/ ← version router
13
- │ ↓
14
- │ /ccsm/X.Y.Z/ ← per-version frontend (pinned to your backend)
15
- └────────────┬───────────────────────┘
16
- │ fetch /api/* (CORS)
17
- │ ws://localhost:7777/ws/*
18
-
19
- ┌── local backend ───────────────────┐
20
- │ ccsm (npm bin) │
21
- │ ├── /api/sessions /api/sessions/new │
22
- │ ├── /api/sessions/:id/resume │
23
- │ ├── /api/sessions/adopt │
24
- │ ├── /api/version /api/upgrade │
25
- │ ├── /ws/terminal/:id (PTY) │
26
- │ └── /api/health /api/heartbeat │
27
- └────────────────────────────────────┘
28
- ```
29
-
30
- ## What it does
31
-
32
- - **Runs every CLI session in the page.** `claude`, `codex`, `copilot`
33
- or any custom command, in an xterm.js panel. Switch sessions in the
34
- sidebar; the PTY keeps running in the backend.
35
- - **`--resume <uuid>` precision.** ccsm watches the upstream CLI's
36
- transcript dir after spawn and captures its session UUID. Click a
37
- stopped session later → re-spawns with `--resume <uuid>` (or
38
- whatever `resumeIdArgs` template you set per-CLI) so the exact
39
- conversation comes back.
40
- - **Import existing sessions.** Scans `~/.claude` / `~/.codex` /
41
- `~/.copilot` and lets you adopt any session ccsm didn't start.
42
- - **Workspaces + clones.** "New session" picks an unused workspace
43
- under your work-dir, clones selected repos with live `git clone
44
- --progress` streamed to per-repo progress bars, opens a fresh CLI
45
- there. Or pick any existing folder via the file browser.
46
- - **Folders.** Drag sessions into named folders for organisation.
47
- - **In-app upgrade.** About page checks npm for newer versions of
48
- ccsm and offers a one-click upgrade button. Backend self-restarts.
49
-
50
- ## Install
51
-
52
- ```bash
53
- npm i -g @bakapiano/ccsm
54
- ```
55
-
56
- This:
57
- - puts `ccsm` on your PATH
58
- - registers a `ccsm://` URL protocol so the hosted frontend can wake
59
- the backend with one click
60
-
61
- `npx @bakapiano/ccsm` works too for a one-shot trial — the protocol
62
- still gets registered.
63
-
64
- ## Use
65
-
66
- ```bash
67
- ccsm # starts the backend, opens the frontend
68
- ```
69
-
70
- Or just visit **https://bakapiano.github.io/ccsm/** in any browser.
71
- If the backend isn't running, the router shows a "Backend not running"
72
- banner with a **Start ccsm** button — click it, Windows asks once
73
- whether to open the `ccsm://` handler (check "Always allow"), and the
74
- backend spawns silently behind the page. The router auto-reconnects in
75
- 1-2s and redirects to the frontend matching your installed backend
76
- version.
77
-
78
- ### Install as PWA
79
-
80
- In Chrome / Edge, click the install icon in the address bar (or use the
81
- "Install ccsm" button on the **About** tab inside the app). The PWA gets
82
- its own window, its own icon, and Window Controls Overlay so the title
83
- bar blends into the page.
84
-
85
- After installing, clicking the PWA icon is the new entry point — no
86
- terminal needed.
87
-
88
- ## Defaults
89
-
90
- | | |
91
- |---|---|
92
- | Port | `7777` (auto-bumps if taken) |
93
- | Work dir | `~/ccsm-workspaces` (each subdirectory holds one or more repo clones) |
94
- | Built-in CLIs | `claude`, `codex`, `copilot` — add your own via the **Configure** tab |
95
- | Data dir | `~/.ccsm/` (override with `CCSM_HOME=<path>`) — survives upgrades and npx cache wipes |
96
-
97
- All of the above are editable through the **Configure** tab.
98
-
99
- ## Layout
100
-
101
- ```
102
- ccsm/
103
- ├── server.js # Express + WebSocket; API only in prod
104
- ├── bin/ccsm.js # launcher · detaches server, opens browser
105
- ├── scripts/
106
- │ ├── install.js # postinstall · registers ccsm:// (Windows)
107
- │ └── uninstall.js # preuninstall · cleanup
108
- ├── lib/
109
- │ ├── persistedSessions.js # ~/.ccsm/sessions.json — the source of truth
110
- │ ├── folders.js # sidebar tree
111
- │ ├── localCliSessions.js # scan ~/.claude · ~/.codex · ~/.copilot
112
- │ ├── workspace.js # ws-N allocation + repo clones
113
- │ ├── webTerminal.js # node-pty pool · WebSocket bridge
114
- │ ├── jsonStore.js · config.js
115
- ├── pages-root/ # → GH Pages / (version router)
116
- └── public/ # → GH Pages /<pkg.version>/ (per-version frontend)
117
-
118
- ~/.ccsm/ # or $CCSM_HOME
119
- ├── config.json
120
- ├── sessions.json # persisted sessions
121
- ├── folders.json
122
- ├── server.log
123
- └── browser-profile/ # Edge/Chrome --user-data-dir
124
- ```
125
-
126
- ## How "wake on click" works
127
-
128
- The hosted frontend lives entirely in the browser sandbox — it cannot
129
- spawn processes. So when the backend is down, the OfflineBanner's
130
- **Start ccsm** is a plain `<a href="ccsm://start">`. The OS hands that
131
- off to a per-user URL protocol handler registered at install time:
132
-
133
- ```
134
- HKCU\Software\Classes\ccsm\shell\open\command
135
- → wscript.exe "<LOCALAPPDATA>\ccsm\launcher.vbs" "%1"
136
- ```
137
-
138
- The `.vbs` calls `ccsm.cmd "ccsm://start"` with `WindowStyle = 0`. That
139
- gets to `bin/ccsm.js`, which parses the protocol URL, spawns
140
- `server.js` detached, and exits. Zero windows ever flash.
141
-
142
- First click triggers a one-time Windows dialog ("Open ccsm.cmd?"). Tick
143
- **Always allow** and future clicks are silent.
144
-
145
- ## Lifecycle (when does the backend die)
146
-
147
- | trigger | reaction |
148
- |---|---|
149
- | The auto-opened browser window closes | wait 12s · if any other client heartbeats during that window, stay alive; otherwise gracefulShutdown |
150
- | No heartbeat for 90s | gracefulShutdown |
151
- | `POST /api/shutdown` | gracefulShutdown |
152
- | `POST /api/upgrade` after install | self-respawn + gracefulShutdown |
153
- | SIGINT / SIGTERM | gracefulShutdown |
154
-
155
- ## Dev
156
-
157
- ```bash
158
- git clone https://github.com/bakapiano/ccsm
159
- cd ccsm
160
- npm install
161
- CCSM_NO_BROWSER=1 CCSM_KEEP_ALIVE=1 node server.js
162
- # opens http://localhost:7777 with hot-reload (public/ is served locally
163
- # and SSE pushes a reload event on every file save)
164
- ```
165
-
166
- Dev mode is detected via `__dirname.includes('node_modules')` — when
167
- running from a checkout, the backend also serves `public/`. In an
168
- npm-installed copy it's API-only, and you use the hosted frontend.
169
-
170
- ## Versioning (frontend ↔ backend)
171
-
172
- The hosted root (`/ccsm/`) is a tiny static **version router**: it
173
- probes `localhost:7777/api/health`, then redirects you to
174
- `/ccsm/<backend.version>/`. Each release publishes a fresh
175
- per-version subdir; old ones stay forever. No semver-compat logic — a
176
- frontend is always 1:1 with the backend it was built against.
177
-
178
- If your backend gets upgraded under a still-loaded page, the
179
- per-version frontend detects the mismatch on its next probe and
180
- bounces you back through the router automatically.
181
-
182
- ## Status
183
-
184
- - Backend: Windows-first. macOS / Linux backend ports planned (URL
185
- protocol registration is the only platform-specific install piece).
186
- - Frontend: cross-platform (pure web).
187
-
188
- See [CLAUDE.md](CLAUDE.md) for design decisions and the non-obvious
189
- gotchas baked into the launcher / session-watcher / lifecycle code.
1
+ # ccsm — Claude Code Session Manager
2
+
3
+ A single pane over every Claude / Codex / Copilot CLI session on your
4
+ machine. Each session runs inside the page (xterm.js + a PTY pool in
5
+ the local backend), gets recorded, and re-attaches to the exact
6
+ upstream conversation when you click it again.
7
+
8
+ [![open](https://img.shields.io/badge/open-bakapiano.github.io%2Fccsm-1a1815?style=flat-square)](https://bakapiano.github.io/ccsm/)
9
+
10
+ ```
11
+ ┌── browser ─────────────────────────┐
12
+ │ https://bakapiano.github.io/ccsm/ ← version router
13
+ │ ↓
14
+ │ /ccsm/X.Y.Z/ ← per-version frontend (pinned to your backend)
15
+ └────────────┬───────────────────────┘
16
+ │ fetch /api/* (CORS)
17
+ │ ws://localhost:7777/ws/*
18
+
19
+ ┌── local backend ───────────────────┐
20
+ │ ccsm (npm bin) │
21
+ │ ├── /api/sessions /api/sessions/new │
22
+ │ ├── /api/sessions/:id/resume │
23
+ │ ├── /api/sessions/adopt │
24
+ │ ├── /api/version /api/upgrade │
25
+ │ ├── /ws/terminal/:id (PTY) │
26
+ │ └── /api/health /api/heartbeat │
27
+ └────────────────────────────────────┘
28
+ ```
29
+
30
+ ## What it does
31
+
32
+ - **Runs every CLI session in the page.** `claude`, `codex`, `copilot`
33
+ or any custom command, in an xterm.js panel. Switch sessions in the
34
+ sidebar; the PTY keeps running in the backend.
35
+ - **`--resume <uuid>` precision.** ccsm watches the upstream CLI's
36
+ transcript dir after spawn and captures its session UUID. Click a
37
+ stopped session later → re-spawns with `--resume <uuid>` (or
38
+ whatever `resumeIdArgs` template you set per-CLI) so the exact
39
+ conversation comes back.
40
+ - **Import existing sessions.** Scans `~/.claude` / `~/.codex` /
41
+ `~/.copilot` and lets you adopt any session ccsm didn't start.
42
+ - **Workspaces + clones.** "New session" picks an unused workspace
43
+ under your work-dir, clones selected repos with live `git clone
44
+ --progress` streamed to per-repo progress bars, opens a fresh CLI
45
+ there. Or pick any existing folder via the file browser.
46
+ - **Folders.** Drag sessions into named folders for organisation.
47
+ - **In-app upgrade.** About page checks npm for newer versions of
48
+ ccsm and offers a one-click upgrade button. Backend self-restarts.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ npm i -g @bakapiano/ccsm
54
+ ```
55
+
56
+ This:
57
+ - puts `ccsm` on your PATH
58
+ - registers a `ccsm://` URL protocol so the hosted frontend can wake
59
+ the backend with one click
60
+
61
+ `npx @bakapiano/ccsm` works too for a one-shot trial — the protocol
62
+ still gets registered.
63
+
64
+ ## Use
65
+
66
+ ```bash
67
+ ccsm # starts the backend, opens the frontend
68
+ ```
69
+
70
+ Or just visit **https://bakapiano.github.io/ccsm/** in any browser.
71
+ If the backend isn't running, the router shows a "Backend not running"
72
+ banner with a **Start ccsm** button — click it, Windows asks once
73
+ whether to open the `ccsm://` handler (check "Always allow"), and the
74
+ backend spawns silently behind the page. The router auto-reconnects in
75
+ 1-2s and redirects to the frontend matching your installed backend
76
+ version.
77
+
78
+ ### Install as PWA
79
+
80
+ In Chrome / Edge, click the install icon in the address bar (or use the
81
+ "Install ccsm" button on the **About** tab inside the app). The PWA gets
82
+ its own window, its own icon, and Window Controls Overlay so the title
83
+ bar blends into the page.
84
+
85
+ After installing, clicking the PWA icon is the new entry point — no
86
+ terminal needed.
87
+
88
+ ## Defaults
89
+
90
+ | | |
91
+ |---|---|
92
+ | Port | `7777` (auto-bumps if taken) |
93
+ | Work dir | `~/ccsm-workspaces` (each subdirectory holds one or more repo clones) |
94
+ | Built-in CLIs | `claude`, `codex`, `copilot` — add your own via the **Configure** tab |
95
+ | Data dir | `~/.ccsm/` (override with `CCSM_HOME=<path>`) — survives upgrades and npx cache wipes |
96
+
97
+ All of the above are editable through the **Configure** tab.
98
+
99
+ ## Layout
100
+
101
+ ```
102
+ ccsm/
103
+ ├── server.js # Express + WebSocket; API only in prod
104
+ ├── bin/ccsm.js # launcher · detaches server, opens browser
105
+ ├── scripts/
106
+ │ ├── install.js # postinstall · registers ccsm:// (Windows)
107
+ │ └── uninstall.js # preuninstall · cleanup
108
+ ├── lib/
109
+ │ ├── persistedSessions.js # ~/.ccsm/sessions.json — the source of truth
110
+ │ ├── folders.js # sidebar tree
111
+ │ ├── localCliSessions.js # scan ~/.claude · ~/.codex · ~/.copilot
112
+ │ ├── workspace.js # ws-N allocation + repo clones
113
+ │ ├── webTerminal.js # node-pty pool · WebSocket bridge
114
+ │ ├── jsonStore.js · config.js
115
+ ├── pages-root/ # → GH Pages / (version router)
116
+ └── public/ # → GH Pages /<pkg.version>/ (per-version frontend)
117
+
118
+ ~/.ccsm/ # or $CCSM_HOME
119
+ ├── config.json
120
+ ├── sessions.json # persisted sessions
121
+ ├── folders.json
122
+ ├── server.log
123
+ └── browser-profile/ # Edge/Chrome --user-data-dir
124
+ ```
125
+
126
+ ## How "wake on click" works
127
+
128
+ The hosted frontend lives entirely in the browser sandbox — it cannot
129
+ spawn processes. So when the backend is down, the OfflineBanner's
130
+ **Start ccsm** is a plain `<a href="ccsm://start">`. The OS hands that
131
+ off to a per-user URL protocol handler registered at install time:
132
+
133
+ ```
134
+ HKCU\Software\Classes\ccsm\shell\open\command
135
+ → wscript.exe "<LOCALAPPDATA>\ccsm\launcher.vbs" "%1"
136
+ ```
137
+
138
+ The `.vbs` calls `ccsm.cmd "ccsm://start"` with `WindowStyle = 0`. That
139
+ gets to `bin/ccsm.js`, which parses the protocol URL, spawns
140
+ `server.js` detached, and exits. Zero windows ever flash.
141
+
142
+ First click triggers a one-time Windows dialog ("Open ccsm.cmd?"). Tick
143
+ **Always allow** and future clicks are silent.
144
+
145
+ ## Lifecycle (when does the backend die)
146
+
147
+ | trigger | reaction |
148
+ |---|---|
149
+ | The auto-opened browser window closes | wait 12s · if any other client heartbeats during that window, stay alive; otherwise gracefulShutdown |
150
+ | No heartbeat for 90s | gracefulShutdown |
151
+ | `POST /api/shutdown` | gracefulShutdown |
152
+ | `POST /api/upgrade` after install | self-respawn + gracefulShutdown |
153
+ | SIGINT / SIGTERM | gracefulShutdown |
154
+
155
+ ## Dev
156
+
157
+ ```bash
158
+ git clone https://github.com/bakapiano/ccsm
159
+ cd ccsm
160
+ npm install
161
+ CCSM_NO_BROWSER=1 CCSM_KEEP_ALIVE=1 node server.js
162
+ # opens http://localhost:7777 with hot-reload (public/ is served locally
163
+ # and SSE pushes a reload event on every file save)
164
+ ```
165
+
166
+ Dev mode is detected via `__dirname.includes('node_modules')` — when
167
+ running from a checkout, the backend also serves `public/`. In an
168
+ npm-installed copy it's API-only, and you use the hosted frontend.
169
+
170
+ ## Versioning (frontend ↔ backend)
171
+
172
+ The hosted root (`/ccsm/`) is a tiny static **version router**: it
173
+ probes `localhost:7777/api/health`, then redirects you to
174
+ `/ccsm/<backend.version>/`. Each release publishes a fresh
175
+ per-version subdir; old ones stay forever. No semver-compat logic — a
176
+ frontend is always 1:1 with the backend it was built against.
177
+
178
+ If your backend gets upgraded under a still-loaded page, the
179
+ per-version frontend detects the mismatch on its next probe and
180
+ bounces you back through the router automatically.
181
+
182
+ ## Status
183
+
184
+ - Backend: Windows-first. macOS / Linux backend ports planned (URL
185
+ protocol registration is the only platform-specific install piece).
186
+ - Frontend: cross-platform (pure web).
187
+
188
+ See [CLAUDE.md](CLAUDE.md) for design decisions and the non-obvious
189
+ gotchas baked into the launcher / session-watcher / lifecycle code.