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.
Files changed (38) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +431 -0
  3. package/package.json +60 -0
  4. package/src/core/index.js +35 -0
  5. package/src/core/notifications.js +143 -0
  6. package/src/core/process-tracker.js +150 -0
  7. package/src/core/recovery.js +150 -0
  8. package/src/core/session-manager.js +183 -0
  9. package/src/core/workspace-manager.js +147 -0
  10. package/src/demo.js +12 -0
  11. package/src/gui.js +197 -0
  12. package/src/index.js +176 -0
  13. package/src/mcp/visual-qa.js +496 -0
  14. package/src/state/docs-manager.js +419 -0
  15. package/src/state/store.js +852 -0
  16. package/src/ui/app.js +327 -0
  17. package/src/ui/dialogs.js +440 -0
  18. package/src/ui/notification-bar.js +102 -0
  19. package/src/ui/session-detail.js +110 -0
  20. package/src/ui/session-list.js +165 -0
  21. package/src/ui/status-bar.js +84 -0
  22. package/src/ui/theme.js +180 -0
  23. package/src/ui/workspace-panel.js +108 -0
  24. package/src/web/auth.js +268 -0
  25. package/src/web/backup.js +102 -0
  26. package/src/web/pty-manager.js +545 -0
  27. package/src/web/pty-server.js +96 -0
  28. package/src/web/public/app.js +10477 -0
  29. package/src/web/public/index.html +1014 -0
  30. package/src/web/public/logo.png +0 -0
  31. package/src/web/public/styles-mobile.css +899 -0
  32. package/src/web/public/styles.css +6296 -0
  33. package/src/web/public/terminal.js +898 -0
  34. package/src/web/public/vendor/xterm/xterm.css +209 -0
  35. package/src/web/public/vendor/xterm/xterm.min.js +2 -0
  36. package/src/web/public/vendor/xterm-addon-fit/xterm-addon-fit.min.js +2 -0
  37. package/src/web/public/vendor/xterm-addon-web-links/xterm-addon-web-links.min.js +2 -0
  38. package/src/web/server.js +4462 -0
package/README.md ADDED
@@ -0,0 +1,431 @@
1
+ # Myrlin Workbook
2
+
3
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE)
4
+ [![npm](https://img.shields.io/npm/v/myrlin-workbook.svg)](https://www.npmjs.com/package/myrlin-workbook)
5
+ [![Node](https://img.shields.io/badge/Node.js-18%2B-green.svg)](https://nodejs.org)
6
+ [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)]()
7
+ [![Tests](https://img.shields.io/badge/Tests-26%20passing-brightgreen.svg)]()
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
+ ![Workspace dashboard with sessions grouped by project](docs/images/hero-dashboard.png)
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
+ ![4-pane terminal grid with concurrent sessions](docs/images/terminal-grid.png)
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
+ ![Docs panel with Notes, Goals, Tasks, Roadmap, and Rules](docs/images/docs-panel.png)
142
+
143
+ ![Switching between workspace docs](docs/images/workspace-docs.gif)
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
+ ![Feature tracking Kanban board](docs/images/kanban-board.png)
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
+ ![All 4 Catppuccin themes: Mocha, Macchiato, Frappe, and Latte](docs/images/theme-showcase.png)
174
+
175
+ ![Theme switching in action](docs/images/theme-switching.gif)
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
+ &nbsp;&nbsp;&nbsp;
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 };