myrlin-workbook 0.3.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.
- package/LICENSE +661 -0
- package/README.md +431 -0
- package/package.json +60 -0
- package/src/core/index.js +35 -0
- package/src/core/notifications.js +143 -0
- package/src/core/process-tracker.js +150 -0
- package/src/core/recovery.js +150 -0
- package/src/core/session-manager.js +183 -0
- package/src/core/workspace-manager.js +147 -0
- package/src/demo.js +12 -0
- package/src/gui.js +197 -0
- package/src/index.js +176 -0
- package/src/mcp/visual-qa.js +496 -0
- package/src/state/docs-manager.js +419 -0
- package/src/state/store.js +852 -0
- package/src/ui/app.js +327 -0
- package/src/ui/dialogs.js +440 -0
- package/src/ui/notification-bar.js +102 -0
- package/src/ui/session-detail.js +110 -0
- package/src/ui/session-list.js +165 -0
- package/src/ui/status-bar.js +84 -0
- package/src/ui/theme.js +180 -0
- package/src/ui/workspace-panel.js +108 -0
- package/src/web/auth.js +268 -0
- package/src/web/backup.js +102 -0
- package/src/web/pty-manager.js +545 -0
- package/src/web/pty-server.js +96 -0
- package/src/web/public/app.js +10477 -0
- package/src/web/public/index.html +1014 -0
- package/src/web/public/logo.png +0 -0
- package/src/web/public/styles-mobile.css +899 -0
- package/src/web/public/styles.css +6296 -0
- package/src/web/public/terminal.js +898 -0
- package/src/web/public/vendor/xterm/xterm.css +209 -0
- package/src/web/public/vendor/xterm/xterm.min.js +2 -0
- package/src/web/public/vendor/xterm-addon-fit/xterm-addon-fit.min.js +2 -0
- package/src/web/public/vendor/xterm-addon-web-links/xterm-addon-web-links.min.js +2 -0
- package/src/web/server.js +4462 -0
package/README.md
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# Myrlin Workbook
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://www.npmjs.com/package/myrlin-workbook)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
[]()
|
|
7
|
+
[]()
|
|
8
|
+
|
|
9
|
+
Open-source workspace manager for Claude Code - cost tracking, conflict detection, 4-pane embedded terminals, per-workspace docs & kanban, session templates, session manager overlay, costs dashboard, 8 themes, [and more](#full-feature-list). Discovers every session you've ever run, organizes them into workspaces. Runs in your browser, everything stays local.
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img src="docs/images/hero-demo.gif" alt="4-pane terminal grid with live sessions" width="800">
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### Try it now
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx myrlin-workbook # Opens browser, discovers your real Claude sessions
|
|
23
|
+
npx myrlin-workbook --demo # Opens browser with sample data (no real sessions needed)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Install from source
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/therealarthur/myrlin-workbook.git
|
|
30
|
+
cd myrlin-workbook
|
|
31
|
+
npm install
|
|
32
|
+
npm run gui # Real sessions
|
|
33
|
+
npm run gui:demo # Sample data
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
On first launch, a random password is generated and printed to the console. Saved to `state/config.json`.
|
|
37
|
+
|
|
38
|
+
**Custom password:**
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Bash/zsh
|
|
42
|
+
CWM_PASSWORD=mypassword npm run gui
|
|
43
|
+
|
|
44
|
+
# PowerShell
|
|
45
|
+
$env:CWM_PASSWORD="mypassword"; npm run gui
|
|
46
|
+
|
|
47
|
+
# cmd.exe
|
|
48
|
+
set CWM_PASSWORD=mypassword && npm run gui
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Prerequisites
|
|
52
|
+
|
|
53
|
+
- **Node.js 18+** ([download](https://nodejs.org))
|
|
54
|
+
- **C++ Build Tools** (required by `node-pty` for real terminal emulation):
|
|
55
|
+
- **Windows**: [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) with "Desktop development with C++" workload
|
|
56
|
+
- **macOS**: `xcode-select --install`
|
|
57
|
+
- **Linux**: `sudo apt install build-essential python3`
|
|
58
|
+
|
|
59
|
+
> **`npm install` fails?** You're missing the C++ build tools above. See [Troubleshooting](#troubleshooting).
|
|
60
|
+
|
|
61
|
+
### Run Modes
|
|
62
|
+
|
|
63
|
+
| Command | Description |
|
|
64
|
+
|---------|-------------|
|
|
65
|
+
| `npx myrlin-workbook` | Web GUI via npx |
|
|
66
|
+
| `npm run gui` | Web GUI (localhost:3456) |
|
|
67
|
+
| `npm run gui:demo` | Web GUI with sample data |
|
|
68
|
+
| `npm start` | TUI mode (terminal-only, blessed) |
|
|
69
|
+
| `npm run demo` | TUI with sample data |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Why
|
|
74
|
+
|
|
75
|
+
I use Claude Code daily and had a growing list of pet peeves. Can't name sessions, so `/resume` is just picking from a list of IDs. No shift+enter for multiline. If you have a few sessions going at once, the terminal window juggling gets old fast. PC restarts and you have to reopen everything from scratch. No idea what you're spending.
|
|
76
|
+
|
|
77
|
+
Got fed up and built something for it. Myrlin scans `~/.claude/projects/`, finds every session you've ever run, and you organize them into workspaces with embedded terminals, docs, and cost tracking. Everything runs locally, no cloud, no telemetry.
|
|
78
|
+
|
|
79
|
+
### Compared to other tools
|
|
80
|
+
|
|
81
|
+
There are good tools in this space. I tried them. Here's where Myrlin fits:
|
|
82
|
+
|
|
83
|
+
| Feature | Myrlin | [ClaudeCodeUI](https://github.com/siteboon/claudecodeui) | [Opcode](https://github.com/winfunc/opcode) | [Claude Squad](https://github.com/smtg-ai/claude-squad) |
|
|
84
|
+
|---------|--------|-------------|--------|-------------|
|
|
85
|
+
| Cost tracking | Yes | No | Yes | No |
|
|
86
|
+
| Costs dashboard | Yes | No | Yes | No |
|
|
87
|
+
| Session discovery | Yes | Yes | No | No |
|
|
88
|
+
| Session manager overlay | Yes | No | No | No |
|
|
89
|
+
| Workspace docs/kanban | Yes | No | No | No |
|
|
90
|
+
| Themes | 8 (Catppuccin + fun flavors) | No | No | No |
|
|
91
|
+
| Session templates | Yes | No | No | No |
|
|
92
|
+
| Conflict detection | Yes | No | No | No |
|
|
93
|
+
| Embedded terminals | 4-pane grid | Single | No | No |
|
|
94
|
+
| Tab grouping | Yes | No | No | No |
|
|
95
|
+
| Windows native | Yes | Buggy | Yes (desktop) | No (tmux) |
|
|
96
|
+
| TUI mode | Yes | No | No | No |
|
|
97
|
+
| Multi-agent | Claude only | Claude+Cursor+Codex | Claude only | 5+ tools |
|
|
98
|
+
| File explorer | No | Yes | No | No |
|
|
99
|
+
| npx install | Yes | Yes | No | No |
|
|
100
|
+
| Build step required | None | Vite | Tauri | None |
|
|
101
|
+
|
|
102
|
+
**What those tools do better:** ClaudeCodeUI has a file explorer and multi-agent support. Opcode is a polished desktop app with 20k stars. Claude Squad supports 5+ AI tools. Myrlin is workspace-first with cost tracking and per-workspace docs. Different approach to the same problem.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Features
|
|
107
|
+
|
|
108
|
+
### Cost Tracking
|
|
109
|
+
|
|
110
|
+
Per-session and per-workspace cost breakdown. Parses Claude's JSONL usage data, applies model-aware pricing (Opus, Sonnet, Haiku), shows input/output/cache tokens. Know exactly what you're spending.
|
|
111
|
+
|
|
112
|
+
### Session Discovery
|
|
113
|
+
|
|
114
|
+
- Scans `~/.claude/projects/` and finds all existing Claude sessions
|
|
115
|
+
- Shows project directory, session count, size, last active
|
|
116
|
+
- Auto-titles sessions from conversation content
|
|
117
|
+
- Import sessions into workspaces with one click
|
|
118
|
+
|
|
119
|
+
### Workspaces & Sessions
|
|
120
|
+
|
|
121
|
+

|
|
122
|
+
|
|
123
|
+
- Named workspaces with color coding
|
|
124
|
+
- Group workspaces under umbrella folders
|
|
125
|
+
- Drag-and-drop sessions between workspaces and into terminal panes
|
|
126
|
+
- State persists to disk. Survives crashes and restarts
|
|
127
|
+
- Auto-recovery on startup (detects orphaned sessions, restores state)
|
|
128
|
+
|
|
129
|
+
### Embedded Terminals
|
|
130
|
+
|
|
131
|
+

|
|
132
|
+
|
|
133
|
+
- 4-pane terminal grid (xterm.js + node-pty + WebSocket). Real PTY, not fake.
|
|
134
|
+
- Tab groups: named sets of terminal panes ("Research", "Debug"), switchable and persistent
|
|
135
|
+
- PTY sessions survive page refresh with scrollback replay on reconnect
|
|
136
|
+
- Model selection (Opus, Sonnet, Haiku) and session resume
|
|
137
|
+
- Right-click context menu with Copy, Stop, Restart, Model picker
|
|
138
|
+
|
|
139
|
+
### Per-Workspace Docs & Feature Board
|
|
140
|
+
|
|
141
|
+

|
|
142
|
+
|
|
143
|
+

|
|
144
|
+
|
|
145
|
+
- Notes, Goals, Tasks, Rules, and Roadmap sections per workspace
|
|
146
|
+
- Kanban-style feature board (Planned -> Active -> Review -> Done)
|
|
147
|
+
- Markdown editor with formatting toolbar
|
|
148
|
+
- AI Insights tab: auto-generated summaries of workspace sessions
|
|
149
|
+
|
|
150
|
+

|
|
151
|
+
|
|
152
|
+
### Session Templates
|
|
153
|
+
|
|
154
|
+
Save your common launch configurations. Pre-set working directory, model, flags, and spawn options. One click to launch a new session from a template.
|
|
155
|
+
|
|
156
|
+
### Conflict Detection
|
|
157
|
+
|
|
158
|
+
Real-time warnings when two or more running sessions are editing the same files. Runs `git status` across active sessions and cross-references modified files. Prevents you from stepping on your own work.
|
|
159
|
+
|
|
160
|
+
### Quick Switcher
|
|
161
|
+
|
|
162
|
+
`Ctrl+K` / `Cmd+K` opens a fuzzy search across all sessions and workspaces. Jump to anything instantly.
|
|
163
|
+
|
|
164
|
+
### Git & Worktree Management
|
|
165
|
+
|
|
166
|
+
- Full git status per workspace: current branch, dirty/clean, ahead/behind remote
|
|
167
|
+
- Branch listing and worktree CRUD
|
|
168
|
+
- **"New Feature Session"**: right-click a workspace -> creates a branch + worktree + Claude session in one click
|
|
169
|
+
- Branch badges on session rows
|
|
170
|
+
|
|
171
|
+
### Themes
|
|
172
|
+
|
|
173
|
+

|
|
174
|
+
|
|
175
|
+

|
|
176
|
+
|
|
177
|
+
8 themes: 4 classic [Catppuccin](https://github.com/catppuccin/catppuccin) (Mocha, Macchiato, Frappe, Latte) plus 4 fun flavors - Cherry (rose), Ocean (navy), Amber (gold), and Mint (jade). Toggle from the header dropdown. Choice persists in localStorage.
|
|
178
|
+
|
|
179
|
+
### Port Detection & Resource Monitoring
|
|
180
|
+
|
|
181
|
+
- Automatic port detection for running sessions (PowerShell on Windows, lsof on Unix)
|
|
182
|
+
- Per-session CPU and memory tracking
|
|
183
|
+
- System overview (CPU, RAM, uptime)
|
|
184
|
+
- Stop, restart, or kill sessions from the Resources tab
|
|
185
|
+
|
|
186
|
+
### Mobile
|
|
187
|
+
|
|
188
|
+
<p align="center">
|
|
189
|
+
<img src="docs/images/mobile-dashboard.png" alt="Mobile workspace view" height="400">
|
|
190
|
+
|
|
191
|
+
<img src="docs/images/mobile-terminal.png" alt="Mobile terminal with toolbar" height="400">
|
|
192
|
+
</p>
|
|
193
|
+
|
|
194
|
+
- Responsive layout with bottom tab bar
|
|
195
|
+
- Touch gestures: swipe between terminal panes, edge swipe for sidebar, long-press for context menus
|
|
196
|
+
- Mobile terminal toolbar: keyboard toggle, Enter, Tab, Ctrl+C, Ctrl+D, Esc, arrows, Copy, Upload
|
|
197
|
+
- Keyboard-aware viewport resizing (terminal stays visible above soft keyboard)
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Full Feature List
|
|
202
|
+
|
|
203
|
+
A comprehensive list of everything Myrlin Workbook offers today.
|
|
204
|
+
|
|
205
|
+
### Core
|
|
206
|
+
|
|
207
|
+
- **Session discovery** - scans `~/.claude/projects/`, finds every session you've ever run
|
|
208
|
+
- **Workspace management** - named workspaces with color coding, drag-and-drop grouping
|
|
209
|
+
- **Auto-recovery** - restores state after crash or restart, detects orphaned sessions
|
|
210
|
+
- **State persistence** - JSON on disk, survives everything
|
|
211
|
+
|
|
212
|
+
### Terminals
|
|
213
|
+
|
|
214
|
+
- **4-pane terminal grid** - xterm.js + node-pty + WebSocket, real PTY (not fake)
|
|
215
|
+
- **Tab groups** - named sets of panes ("Research", "Debug"), switchable and persistent
|
|
216
|
+
- **Tab close buttons** - with live session kill confirmation dialog
|
|
217
|
+
- **Drag-and-hold tab grouping** - hold 1.2s over another tab to create a folder
|
|
218
|
+
- **Cross-tab terminal pane dragging** - drag sessions between panes freely
|
|
219
|
+
- **PTY sessions survive page refresh** - scrollback replay on reconnect
|
|
220
|
+
- **Model selection** - Opus, Sonnet, Haiku per terminal
|
|
221
|
+
- **Right-click context menu** - Copy, Stop, Restart, Model picker
|
|
222
|
+
- **Bracketed paste mode** - proper paste handling in terminal sessions
|
|
223
|
+
|
|
224
|
+
### Cost Tracking
|
|
225
|
+
|
|
226
|
+
- **Per-session and per-workspace cost breakdown** - input/output/cache tokens
|
|
227
|
+
- **Costs dashboard tab** - period selector (Day / Week / Month / All)
|
|
228
|
+
- **SVG timeline chart** - visual spend over time, model breakdown
|
|
229
|
+
- **Sortable session table** - rank sessions by cost, tokens, or duration
|
|
230
|
+
- **Parses JSONL usage data** - model-aware pricing (Opus, Sonnet, Haiku)
|
|
231
|
+
|
|
232
|
+
### Session Management
|
|
233
|
+
|
|
234
|
+
- **Session manager overlay** - click header stats to open, full session control
|
|
235
|
+
- **Mass selection and batch stop** - select multiple sessions, stop them all at once
|
|
236
|
+
- **Filter** - All / Running / Stopped quick filters
|
|
237
|
+
- **One-click terminal open** - from session manager rows
|
|
238
|
+
- **Session templates** - save launch configs (directory, model, flags), one-click launch
|
|
239
|
+
- **Quick switcher** - `Ctrl+K` / `Cmd+K` fuzzy search across sessions and workspaces
|
|
240
|
+
|
|
241
|
+
### Docs & Planning
|
|
242
|
+
|
|
243
|
+
- **Per-workspace docs** - Notes, Goals, Tasks, Rules, Roadmap sections
|
|
244
|
+
- **Kanban-style feature board** - Planned, Active, Review, Done columns
|
|
245
|
+
- **Markdown editor** - with formatting toolbar
|
|
246
|
+
- **AI Insights tab** - auto-generated summaries of workspace sessions
|
|
247
|
+
|
|
248
|
+
### Conflict Detection
|
|
249
|
+
|
|
250
|
+
- **Real-time file conflict warnings** - detects when two+ sessions edit the same files
|
|
251
|
+
- **Conflict center UI** - per-file breakdown with session attribution
|
|
252
|
+
- **Click session chips** - jump directly to the terminal pane for that session
|
|
253
|
+
|
|
254
|
+
### Git & Worktree
|
|
255
|
+
|
|
256
|
+
- **Git status per workspace** - current branch, dirty/clean, ahead/behind remote
|
|
257
|
+
- **Branch listing and worktree CRUD** - create, switch, delete from the UI
|
|
258
|
+
- **"New Feature Session"** - creates branch + worktree + Claude session in one click
|
|
259
|
+
- **Branch badges** - shown on session rows
|
|
260
|
+
|
|
261
|
+
### Themes
|
|
262
|
+
|
|
263
|
+
- **8 themes** - 4 Catppuccin (Mocha, Macchiato, Frappe, Latte) + 4 fun flavors (Cherry, Ocean, Amber, Mint)
|
|
264
|
+
- **Header dropdown toggle** - choice persists in localStorage
|
|
265
|
+
|
|
266
|
+
### Resources & Monitoring
|
|
267
|
+
|
|
268
|
+
- **Port detection** - automatic discovery for running sessions (PowerShell on Windows, lsof on Unix)
|
|
269
|
+
- **Per-session CPU and memory** - live tracking
|
|
270
|
+
- **System overview** - CPU, RAM, uptime
|
|
271
|
+
- **Stop / restart / kill** - from the Resources tab
|
|
272
|
+
|
|
273
|
+
### Mobile
|
|
274
|
+
|
|
275
|
+
- **Responsive layout** - bottom tab bar on small screens
|
|
276
|
+
- **Touch gestures** - swipe between panes, edge swipe for sidebar, long-press for context menus
|
|
277
|
+
- **Mobile terminal toolbar** - keyboard toggle, Enter, Tab, Ctrl+C, Ctrl+D, Esc, arrows, Copy, Upload
|
|
278
|
+
- **Keyboard-aware viewport** - terminal stays visible above soft keyboard
|
|
279
|
+
|
|
280
|
+
... more to come.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Remote Access
|
|
285
|
+
|
|
286
|
+
Expose your local instance with a Cloudflare tunnel:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
npm run gui # Start the server
|
|
290
|
+
cloudflared tunnel --url http://localhost:3456 # In another terminal
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Open the URL from any device. All WebSocket terminal connections, SSE streams, and REST API calls route through the tunnel. For a stable URL, see [Cloudflare tunnel docs](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/).
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Architecture
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
Browser (vanilla JS SPA)
|
|
301
|
+
|
|
|
302
|
+
|-- REST API ---------- Express server
|
|
303
|
+
| |-- State store (JSON + EventEmitter)
|
|
304
|
+
| |-- Session manager (launch/stop/restart)
|
|
305
|
+
| |-- Resource monitoring (CPU, RAM, per-PID)
|
|
306
|
+
| +-- Workspace groups, discovery, docs
|
|
307
|
+
|
|
|
308
|
+
|-- SSE --------------- Real-time updates (store events -> clients)
|
|
309
|
+
|
|
|
310
|
+
+-- WebSocket --------- Terminal I/O (binary frames)
|
|
311
|
+
+-- node-pty -> ConPTY / PTY
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
No React, no build step. Vanilla JS SPA, Express backend. ~24 source files, 26 tests.
|
|
315
|
+
|
|
316
|
+
### Project Structure
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
src/
|
|
320
|
+
|-- state/
|
|
321
|
+
| |-- store.js # Core state (JSON persistence + EventEmitter)
|
|
322
|
+
| +-- docs-manager.js # Per-workspace markdown docs
|
|
323
|
+
|-- core/
|
|
324
|
+
| |-- session-manager.js # Launch/stop/restart processes
|
|
325
|
+
| |-- workspace-manager.js # Workspace CRUD
|
|
326
|
+
| |-- process-tracker.js # PID monitoring
|
|
327
|
+
| |-- recovery.js # Auto-recovery on startup
|
|
328
|
+
| +-- notifications.js # Event-based notifications
|
|
329
|
+
|-- web/
|
|
330
|
+
| |-- server.js # Express API + SSE + resources
|
|
331
|
+
| |-- auth.js # Token auth + rate limiting
|
|
332
|
+
| |-- pty-manager.js # PTY session lifecycle
|
|
333
|
+
| +-- public/
|
|
334
|
+
| |-- index.html # SPA shell
|
|
335
|
+
| |-- app.js # Frontend application
|
|
336
|
+
| |-- styles.css # Catppuccin themes
|
|
337
|
+
| +-- terminal.js # TerminalPane (xterm.js + WebSocket)
|
|
338
|
+
|-- ui/ # TUI mode (blessed)
|
|
339
|
+
|-- index.js # TUI entry point
|
|
340
|
+
+-- gui.js # GUI entry point
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Configuration
|
|
346
|
+
|
|
347
|
+
### Password
|
|
348
|
+
|
|
349
|
+
Loaded in order:
|
|
350
|
+
1. `CWM_PASSWORD` environment variable
|
|
351
|
+
2. `state/config.json` -> `{ "password": "..." }`
|
|
352
|
+
3. Auto-generated (printed to console, saved to config)
|
|
353
|
+
|
|
354
|
+
### Port
|
|
355
|
+
|
|
356
|
+
Default `3456`. Override with `PORT`:
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
PORT=8080 npm run gui
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Keyboard Shortcuts
|
|
365
|
+
|
|
366
|
+
| Key | Action |
|
|
367
|
+
|-----|--------|
|
|
368
|
+
| `Ctrl+K` / `Cmd+K` | Quick switcher |
|
|
369
|
+
| `Escape` | Close modals / menus |
|
|
370
|
+
| `Ctrl+Enter` | Save in notes editor |
|
|
371
|
+
| Double-click session | Inline rename |
|
|
372
|
+
| Right-click session | Context menu (launch, model, rename, hide) |
|
|
373
|
+
| Right-click workspace | Context menu (docs, add session, edit, delete) |
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Troubleshooting
|
|
378
|
+
|
|
379
|
+
### `npm install` fails with node-gyp errors
|
|
380
|
+
`node-pty` needs C++ build tools to compile native bindings. Install the tools listed in [Prerequisites](#prerequisites).
|
|
381
|
+
|
|
382
|
+
**Windows quick fix:**
|
|
383
|
+
```powershell
|
|
384
|
+
npm install -g windows-build-tools
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### `npx myrlin-workbook` hangs on install
|
|
388
|
+
Same issue. node-pty is compiling. If it fails, install the C++ build tools first, then try again.
|
|
389
|
+
|
|
390
|
+
**Still stuck?** Open an [issue](https://github.com/therealarthur/myrlin-workbook/issues) with your full error output and OS version.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Roadmap
|
|
395
|
+
|
|
396
|
+
- Multi-provider support (Codex, Cursor, Aider)
|
|
397
|
+
- ~~Conflict center~~ shipped
|
|
398
|
+
- ~~Session manager overlay~~ shipped
|
|
399
|
+
- ~~Costs dashboard~~ shipped
|
|
400
|
+
- ~~Tab grouping~~ shipped
|
|
401
|
+
- ~~Session templates~~ shipped
|
|
402
|
+
- ~~Session search~~ shipped
|
|
403
|
+
- ~~Light theme~~ shipped (4 Catppuccin themes)
|
|
404
|
+
- ~~Cost tracking~~ shipped (per-session token + cost breakdown)
|
|
405
|
+
- ~~Feature board~~ shipped (Kanban per workspace)
|
|
406
|
+
- ~~Git worktree management~~ shipped (branch CRUD, "New Feature Session" flow)
|
|
407
|
+
- ~~Port detection~~ shipped (auto-discover ports from running sessions)
|
|
408
|
+
- Export/import workspaces
|
|
409
|
+
- Pinned sessions
|
|
410
|
+
- Push notifications for session events
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## License
|
|
415
|
+
|
|
416
|
+
**AGPL-3.0.** Use, modify, self-host freely. If you run a modified version as a public service, you must publish source. See [LICENSE](LICENSE).
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Contributing
|
|
421
|
+
|
|
422
|
+
Issues and PRs welcome. No build step. Clone, `npm install`, hack.
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
npm test # 26 tests
|
|
426
|
+
npm run gui # Start dev server
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
Built by [Arthur](https://github.com/therealarthur).
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "myrlin-workbook",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Browser-based workspace manager for Claude Code sessions - session discovery, multi-terminal, cost tracking, docs, and kanban board",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"myrlin": "./src/gui.js",
|
|
8
|
+
"myrlin-tui": "./src/index.js",
|
|
9
|
+
"cwm": "./src/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "node src/index.js",
|
|
13
|
+
"demo": "node src/demo.js",
|
|
14
|
+
"gui": "node src/gui.js",
|
|
15
|
+
"gui:demo": "node src/gui.js --demo",
|
|
16
|
+
"test": "node test/run.js",
|
|
17
|
+
"mcp:visual-qa": "node src/mcp/visual-qa.js",
|
|
18
|
+
"gui:cdp": "node src/gui.js --cdp"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/therealarthur/myrlin-workbook.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/therealarthur/myrlin-workbook",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"claude",
|
|
30
|
+
"workspace",
|
|
31
|
+
"manager",
|
|
32
|
+
"terminal",
|
|
33
|
+
"tui",
|
|
34
|
+
"ai",
|
|
35
|
+
"coding-assistant",
|
|
36
|
+
"session-manager",
|
|
37
|
+
"developer-tools",
|
|
38
|
+
"xterm",
|
|
39
|
+
"myrlin"
|
|
40
|
+
],
|
|
41
|
+
"author": "Arthur",
|
|
42
|
+
"license": "AGPL-3.0-only",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"blessed": "^0.1.81",
|
|
45
|
+
"blessed-contrib": "^4.11.0",
|
|
46
|
+
"chalk": "^5.6.2",
|
|
47
|
+
"chrome-remote-interface": "^0.34.0",
|
|
48
|
+
"express": "^5.2.1",
|
|
49
|
+
"node-pty": "^1.1.0",
|
|
50
|
+
"ws": "^8.19.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@playwright/test": "^1.58.2",
|
|
54
|
+
"ffmpeg-static": "^5.3.0",
|
|
55
|
+
"sharp": "^0.34.5",
|
|
56
|
+
"xterm": "^5.3.0",
|
|
57
|
+
"xterm-addon-fit": "^0.8.0",
|
|
58
|
+
"xterm-addon-web-links": "^0.9.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core module barrel export
|
|
3
|
+
* Re-exports all core modules for convenient access.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const sessionManager = require('./session-manager');
|
|
7
|
+
const workspaceManager = require('./workspace-manager');
|
|
8
|
+
const processTracker = require('./process-tracker');
|
|
9
|
+
const recovery = require('./recovery');
|
|
10
|
+
const { NotificationManager, getNotificationManager } = require('./notifications');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
// Session lifecycle
|
|
14
|
+
launchSession: sessionManager.launchSession,
|
|
15
|
+
stopSession: sessionManager.stopSession,
|
|
16
|
+
restartSession: sessionManager.restartSession,
|
|
17
|
+
getSessionProcess: sessionManager.getSessionProcess,
|
|
18
|
+
|
|
19
|
+
// Workspace operations
|
|
20
|
+
createWorkspace: workspaceManager.createWorkspace,
|
|
21
|
+
switchWorkspace: workspaceManager.switchWorkspace,
|
|
22
|
+
deleteWorkspace: workspaceManager.deleteWorkspace,
|
|
23
|
+
addSessionToWorkspace: workspaceManager.addSessionToWorkspace,
|
|
24
|
+
getWorkspaceStats: workspaceManager.getWorkspaceStats,
|
|
25
|
+
|
|
26
|
+
// Process tracking
|
|
27
|
+
processTracker,
|
|
28
|
+
|
|
29
|
+
// Recovery
|
|
30
|
+
recovery,
|
|
31
|
+
|
|
32
|
+
// Notifications
|
|
33
|
+
NotificationManager,
|
|
34
|
+
getNotificationManager,
|
|
35
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification Manager - Event-based notification system
|
|
3
|
+
* Maintains a notification queue, emits events, and auto-generates
|
|
4
|
+
* notifications from store events (session/workspace lifecycle).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { EventEmitter } = require('events');
|
|
8
|
+
const { getStore } = require('../state/store');
|
|
9
|
+
|
|
10
|
+
const MAX_QUEUE_SIZE = 50;
|
|
11
|
+
|
|
12
|
+
class NotificationManager extends EventEmitter {
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
/** @type {Array<{ id: number, level: string, title: string, message: string, timestamp: string }>} */
|
|
16
|
+
this._queue = [];
|
|
17
|
+
this._nextId = 1;
|
|
18
|
+
this._storeListenersAttached = false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Push a notification to the queue and emit a 'notification' event.
|
|
23
|
+
* @param {'info'|'success'|'warning'|'error'} level - Notification severity
|
|
24
|
+
* @param {string} title - Short notification title
|
|
25
|
+
* @param {string} message - Notification body
|
|
26
|
+
* @returns {object} The notification object
|
|
27
|
+
*/
|
|
28
|
+
notify(level, title, message) {
|
|
29
|
+
const notification = {
|
|
30
|
+
id: this._nextId++,
|
|
31
|
+
level,
|
|
32
|
+
title,
|
|
33
|
+
message,
|
|
34
|
+
timestamp: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
this._queue.push(notification);
|
|
38
|
+
|
|
39
|
+
// Trim queue to max size
|
|
40
|
+
if (this._queue.length > MAX_QUEUE_SIZE) {
|
|
41
|
+
this._queue = this._queue.slice(-MAX_QUEUE_SIZE);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.emit('notification', notification);
|
|
45
|
+
return notification;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get the most recent N notifications.
|
|
50
|
+
* @param {number} [count=10] - Number of notifications to return
|
|
51
|
+
* @returns {object[]}
|
|
52
|
+
*/
|
|
53
|
+
getRecent(count = 10) {
|
|
54
|
+
return this._queue.slice(-count);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Clear all notifications.
|
|
59
|
+
*/
|
|
60
|
+
clear() {
|
|
61
|
+
this._queue = [];
|
|
62
|
+
this.emit('cleared');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get total notification count.
|
|
67
|
+
* @returns {number}
|
|
68
|
+
*/
|
|
69
|
+
get count() {
|
|
70
|
+
return this._queue.length;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Attach listeners to the store to auto-generate notifications
|
|
75
|
+
* for session and workspace lifecycle events.
|
|
76
|
+
*/
|
|
77
|
+
attachStoreListeners() {
|
|
78
|
+
if (this._storeListenersAttached) return;
|
|
79
|
+
|
|
80
|
+
const store = getStore();
|
|
81
|
+
|
|
82
|
+
store.on('session:created', (session) => {
|
|
83
|
+
this.notify('info', 'Session Created', `"${session.name}" added to workspace`);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
store.on('session:updated', (session) => {
|
|
87
|
+
if (session.status === 'running') {
|
|
88
|
+
this.notify('success', 'Session Started', `"${session.name}" is now running (PID: ${session.pid})`);
|
|
89
|
+
} else if (session.status === 'stopped') {
|
|
90
|
+
this.notify('info', 'Session Stopped', `"${session.name}" has stopped`);
|
|
91
|
+
} else if (session.status === 'error') {
|
|
92
|
+
this.notify('error', 'Session Error', `"${session.name}" encountered an error`);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
store.on('session:deleted', ({ id }) => {
|
|
97
|
+
this.notify('warning', 'Session Deleted', `Session ${id.slice(0, 8)} was removed`);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
store.on('workspace:created', (workspace) => {
|
|
101
|
+
this.notify('success', 'Workspace Created', `"${workspace.name}" workspace is ready`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
store.on('workspace:deleted', ({ id }) => {
|
|
105
|
+
this.notify('warning', 'Workspace Deleted', `Workspace ${id.slice(0, 8)} was removed`);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
store.on('workspace:activated', (workspace) => {
|
|
109
|
+
this.notify('info', 'Workspace Switched', `Active workspace: "${workspace.name}"`);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
store.on('error', ({ type, error }) => {
|
|
113
|
+
this.notify('error', 'Store Error', `${type}: ${error}`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
this._storeListenersAttached = true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Detach from the store and clean up.
|
|
121
|
+
*/
|
|
122
|
+
destroy() {
|
|
123
|
+
this.removeAllListeners();
|
|
124
|
+
this._queue = [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Singleton instance
|
|
129
|
+
let instance = null;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get the singleton NotificationManager instance.
|
|
133
|
+
* @returns {NotificationManager}
|
|
134
|
+
*/
|
|
135
|
+
function getNotificationManager() {
|
|
136
|
+
if (!instance) {
|
|
137
|
+
instance = new NotificationManager();
|
|
138
|
+
instance.attachStoreListeners();
|
|
139
|
+
}
|
|
140
|
+
return instance;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = { NotificationManager, getNotificationManager };
|