brainstorm-companion 2.0.0 → 2.0.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.
- package/README.md +45 -37
- package/package.json +1 -1
- package/skill/SKILL.md +46 -35
- package/skill/visual-companion.md +5 -5
- package/src/cli.js +56 -23
- package/src/mcp.js +45 -52
- package/src/session.js +7 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Visual brainstorming tool for AI coding sessions. Opens a browser window where a
|
|
|
4
4
|
|
|
5
5
|
Zero dependencies. Node.js >= 18 only.
|
|
6
6
|
|
|
7
|
-
**Sessions are persistent** — they
|
|
7
|
+
**Sessions are persistent** — they stay alive until you explicitly stop them with `stop` or `brainstorm_stop_session`. Use `--timeout <minutes>` if you want auto-cleanup.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -39,34 +39,43 @@ Once configured, the agent has access to 5 tools: `brainstorm_start_session`, `b
|
|
|
39
39
|
|
|
40
40
|
## Complete Usage Guide
|
|
41
41
|
|
|
42
|
-
### Quick Start (CLI)
|
|
42
|
+
### Quick Start (CLI) — 3 commands, zero config
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
#
|
|
46
|
-
brainstorm-companion
|
|
45
|
+
brainstorm-companion start # opens browser
|
|
46
|
+
brainstorm-companion push --html '<h2>Hello World</h2>' # shows content
|
|
47
|
+
brainstorm-companion stop # cleans up
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That's it. No arguments required. Now a fuller example:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Start (opens browser, prints URL)
|
|
54
|
+
brainstorm-companion start
|
|
47
55
|
# → Server started: http://127.0.0.1:54321
|
|
48
|
-
# → Session ID: 1234-1700000000000
|
|
49
56
|
|
|
50
|
-
#
|
|
51
|
-
brainstorm-companion push --html '<h2>Dashboard
|
|
57
|
+
# Push content — browser updates instantly
|
|
58
|
+
brainstorm-companion push --html '<h2>Dashboard</h2><p>First draft</p>'
|
|
52
59
|
|
|
53
|
-
#
|
|
54
|
-
brainstorm-companion push --html '<h2>
|
|
60
|
+
# Update — same browser, auto-reloads
|
|
61
|
+
brainstorm-companion push --html '<h2>Dashboard v2</h2><p>Refined</p>'
|
|
55
62
|
|
|
56
|
-
#
|
|
63
|
+
# Read what user clicked
|
|
57
64
|
brainstorm-companion events
|
|
58
|
-
# → [{"type":"click","choice":"grid","text":"A Grid Layout Cards in a responsive grid","timestamp":1700000001234}]
|
|
59
65
|
|
|
60
|
-
#
|
|
66
|
+
# Done
|
|
61
67
|
brainstorm-companion stop
|
|
62
68
|
```
|
|
63
69
|
|
|
64
|
-
**Key
|
|
70
|
+
**Key behaviors:**
|
|
71
|
+
- `start` with no args works immediately — auto-isolates by working directory
|
|
72
|
+
- `start` reuses an existing session — never opens duplicate browsers
|
|
73
|
+
- `push` auto-reloads the browser every time — no restart or refresh needed
|
|
65
74
|
|
|
66
|
-
### Quick Start (MCP / Agent)
|
|
75
|
+
### Quick Start (MCP / Agent) — 3 calls, zero config
|
|
67
76
|
|
|
68
77
|
```
|
|
69
|
-
1. brainstorm_start_session(
|
|
78
|
+
1. brainstorm_start_session()
|
|
70
79
|
→ { url: "http://127.0.0.1:54321", session_dir: "..." }
|
|
71
80
|
|
|
72
81
|
2. brainstorm_push_screen({ html: "<h2>Option A</h2>...", slot: "a", label: "Minimal" })
|
|
@@ -80,7 +89,7 @@ brainstorm-companion stop
|
|
|
80
89
|
5. brainstorm_stop_session({})
|
|
81
90
|
```
|
|
82
91
|
|
|
83
|
-
**
|
|
92
|
+
**No arguments required.** Sessions auto-isolate by working directory — different projects never collide. Sessions persist until `brainstorm_stop_session()` — use `idle_timeout_minutes` for auto-cleanup.
|
|
84
93
|
|
|
85
94
|
---
|
|
86
95
|
|
|
@@ -221,7 +230,7 @@ graph TD
|
|
|
221
230
|
|
|
222
231
|
| Tool | Description |
|
|
223
232
|
|------|-------------|
|
|
224
|
-
| `brainstorm_start_session` | Start server (or reuse existing). Returns URL.
|
|
233
|
+
| `brainstorm_start_session` | Start server (or reuse existing). No args needed. Returns URL. |
|
|
225
234
|
| `brainstorm_push_screen` | Push HTML content. Browser auto-reloads. Use `slot` + `label` for comparison. |
|
|
226
235
|
| `brainstorm_read_events` | Read user interaction events. Option to clear after reading. |
|
|
227
236
|
| `brainstorm_clear_screen` | Clear a specific slot or all content. |
|
|
@@ -234,7 +243,7 @@ graph TD
|
|
|
234
243
|
### Single Decision
|
|
235
244
|
|
|
236
245
|
```
|
|
237
|
-
1. brainstorm_start_session(
|
|
246
|
+
1. brainstorm_start_session()
|
|
238
247
|
2. brainstorm_push_screen({ html: "...options with data-choice..." })
|
|
239
248
|
3. → Tell user to make their selection in the browser
|
|
240
249
|
4. brainstorm_read_events({})
|
|
@@ -245,7 +254,7 @@ graph TD
|
|
|
245
254
|
### A/B/C Comparison
|
|
246
255
|
|
|
247
256
|
```
|
|
248
|
-
1. brainstorm_start_session(
|
|
257
|
+
1. brainstorm_start_session()
|
|
249
258
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
250
259
|
3. brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
251
260
|
4. → Tell user to compare and pick a preference
|
|
@@ -257,7 +266,7 @@ graph TD
|
|
|
257
266
|
### Multi-Round Brainstorming
|
|
258
267
|
|
|
259
268
|
```
|
|
260
|
-
1. brainstorm_start_session(
|
|
269
|
+
1. brainstorm_start_session()
|
|
261
270
|
|
|
262
271
|
// Round 1: Layout
|
|
263
272
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Grid" })
|
|
@@ -280,7 +289,7 @@ graph TD
|
|
|
280
289
|
### Progressive Refinement
|
|
281
290
|
|
|
282
291
|
```
|
|
283
|
-
1. brainstorm_start_session(
|
|
292
|
+
1. brainstorm_start_session()
|
|
284
293
|
|
|
285
294
|
// Show initial mockup
|
|
286
295
|
2. brainstorm_push_screen({ html: "...v1 mockup..." })
|
|
@@ -318,10 +327,10 @@ Global Options:
|
|
|
318
327
|
### `start`
|
|
319
328
|
|
|
320
329
|
```
|
|
321
|
-
brainstorm-companion start [--project-dir <path>] [--port <N>] [--host <H>] [--foreground] [--no-open] [--new]
|
|
330
|
+
brainstorm-companion start [--project-dir <path>] [--port <N>] [--host <H>] [--timeout <min>] [--foreground] [--no-open] [--new]
|
|
322
331
|
```
|
|
323
332
|
|
|
324
|
-
If a session is already running, prints its URL and reuses it. Use `--new` to force a separate parallel session.
|
|
333
|
+
If a session is already running, prints its URL and reuses it. Use `--new` to force a separate parallel session. Use `--timeout 30` for auto-cleanup after 30 minutes idle (default: no timeout).
|
|
325
334
|
|
|
326
335
|
### `push`
|
|
327
336
|
|
|
@@ -373,26 +382,25 @@ Shows Session ID, URL, uptime, event count, and active slots.
|
|
|
373
382
|
|
|
374
383
|
## Best Practices
|
|
375
384
|
|
|
376
|
-
1. **
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
1. **Zero config** — `brainstorm_start_session()` and `brainstorm-companion start` work with no arguments; sessions auto-isolate by working directory
|
|
386
|
+
3. **Never restart to update content** — just call `push_screen` / `push` again; the browser auto-reloads
|
|
387
|
+
4. **One start per workflow** — `start` reuses the existing session automatically
|
|
388
|
+
5. **Push fragments, not full documents** — the frame template handles `<html>`, theming, and scroll
|
|
389
|
+
6. **Start with a heading** — `<h2>` describes what the user is looking at
|
|
390
|
+
7. **Add a `.subtitle`** — describes the decision being made
|
|
391
|
+
8. **One decision per screen** — don't combine unrelated choices
|
|
392
|
+
9. **Use slot labels** — `label` makes comparison tabs readable
|
|
393
|
+
10. **Use `data-choice` for interaction** — the built-in `toggleSelect` emits events automatically
|
|
394
|
+
11. **Tell the user to interact** — after pushing content, let them know the browser is ready
|
|
395
|
+
12. **Read events after user has time** — don't immediately read; wait for user to respond
|
|
396
|
+
13. **Use `--timeout <min>` for auto-cleanup** — or call `stop` / `brainstorm_stop_session` when done
|
|
388
397
|
|
|
389
398
|
## Common Mistakes
|
|
390
399
|
|
|
391
400
|
- **Starting a new session for each update** — DON'T. Call `push_screen` to update the existing browser.
|
|
392
|
-
- **Omitting `project_dir`** — leads to `/tmp` collisions between agents.
|
|
393
401
|
- **Pushing full HTML documents** — push fragments; the frame template adds theming and structure.
|
|
394
402
|
- **Reading events immediately after push** — give the user time to interact first.
|
|
395
|
-
- **Forgetting to stop** — always call `brainstorm_stop_session` when done
|
|
403
|
+
- **Forgetting to stop** — always call `brainstorm_stop_session` / `stop` when done, or use `--timeout`.
|
|
396
404
|
|
|
397
405
|
## Author
|
|
398
406
|
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -5,24 +5,32 @@ description: Visual brainstorming companion — opens a browser window for compa
|
|
|
5
5
|
|
|
6
6
|
# Brainstorm Companion — Complete Agent Reference
|
|
7
7
|
|
|
8
|
+
## Quickstart (3 calls, no setup)
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
brainstorm_start_session()
|
|
12
|
+
brainstorm_push_screen({ html: "<h2>Hello World</h2><p>Your content here</p>" })
|
|
13
|
+
brainstorm_stop_session()
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That's it. No arguments required. A browser opens, your HTML appears, and cleanup happens automatically.
|
|
17
|
+
|
|
8
18
|
## When to Use
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
- Compare multiple design alternatives side-by-side (A/B/C comparison)
|
|
20
|
+
- Show visual mockups, UI designs, or layout options
|
|
21
|
+
- Compare design alternatives side-by-side (A/B/C)
|
|
13
22
|
- Present architecture diagrams (Mermaid), code samples (Prism), or math (KaTeX)
|
|
14
|
-
- Get visual feedback — user clicks and preferences
|
|
15
|
-
- Show interactive prototypes or wireframes
|
|
23
|
+
- Get visual feedback — user clicks and preferences captured as events
|
|
16
24
|
|
|
17
|
-
**Don't use** for plain text
|
|
25
|
+
**Don't use** for plain text, simple data, or anything fine in the terminal.
|
|
18
26
|
|
|
19
27
|
## Session Lifecycle
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- Always
|
|
29
|
+
- **No setup needed** — `brainstorm_start_session()` works with zero arguments
|
|
30
|
+
- **Sessions are persistent** — they stay alive until you call `brainstorm_stop_session`
|
|
31
|
+
- **Safe to call start multiple times** — reuses existing session, never duplicates
|
|
32
|
+
- **Optional timeout** — pass `idle_timeout_minutes` for auto-cleanup
|
|
33
|
+
- **Always stop when done** — `brainstorm_stop_session()` frees port and cleans up
|
|
26
34
|
|
|
27
35
|
---
|
|
28
36
|
|
|
@@ -30,20 +38,24 @@ Sessions are **persistent** — they never time out. A session stays alive until
|
|
|
30
38
|
|
|
31
39
|
### brainstorm_start_session
|
|
32
40
|
|
|
33
|
-
Start the server and open a browser
|
|
41
|
+
Start the server and open a browser. Works with no arguments. Reuses existing session if one is running.
|
|
34
42
|
|
|
35
43
|
```
|
|
44
|
+
// Simplest — no args needed:
|
|
45
|
+
brainstorm_start_session()
|
|
46
|
+
→ { url: "http://127.0.0.1:54321", session_dir: "..." }
|
|
47
|
+
|
|
48
|
+
// With options:
|
|
36
49
|
brainstorm_start_session({
|
|
37
|
-
project_dir: "/path/to/project", //
|
|
50
|
+
project_dir: "/path/to/project", // optional — use cwd for project-local storage
|
|
38
51
|
open_browser: true, // default: true
|
|
39
|
-
|
|
52
|
+
idle_timeout_minutes: 0 // default: 0 = no timeout. Set 30 for auto-cleanup.
|
|
40
53
|
})
|
|
41
|
-
→ { url: "http://127.0.0.1:54321", session_dir: "..." }
|
|
42
54
|
```
|
|
43
55
|
|
|
44
|
-
**
|
|
56
|
+
**No arguments required.** Sessions are auto-isolated by working directory — different projects never collide, even without `project_dir`. Pass `project_dir` only if you want session files stored inside the project folder.
|
|
45
57
|
|
|
46
|
-
**Calling
|
|
58
|
+
**Calling it multiple times is safe** — returns the existing session. Just call `brainstorm_push_screen` to update content.
|
|
47
59
|
|
|
48
60
|
### brainstorm_push_screen
|
|
49
61
|
|
|
@@ -332,7 +344,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
332
344
|
### Single Decision
|
|
333
345
|
|
|
334
346
|
```
|
|
335
|
-
1. brainstorm_start_session(
|
|
347
|
+
1. brainstorm_start_session()
|
|
336
348
|
2. brainstorm_push_screen({ html: "...options with data-choice..." })
|
|
337
349
|
3. → Tell user to make their selection in the browser
|
|
338
350
|
4. brainstorm_read_events({})
|
|
@@ -343,7 +355,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
343
355
|
### A/B/C Comparison
|
|
344
356
|
|
|
345
357
|
```
|
|
346
|
-
1. brainstorm_start_session(
|
|
358
|
+
1. brainstorm_start_session()
|
|
347
359
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
348
360
|
3. brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
349
361
|
4. → Tell user to compare and pick a preference
|
|
@@ -355,7 +367,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
355
367
|
### Multi-Round Brainstorming
|
|
356
368
|
|
|
357
369
|
```
|
|
358
|
-
1. brainstorm_start_session(
|
|
370
|
+
1. brainstorm_start_session()
|
|
359
371
|
|
|
360
372
|
// Round 1: Layout
|
|
361
373
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Grid" })
|
|
@@ -378,7 +390,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
378
390
|
### Progressive Refinement
|
|
379
391
|
|
|
380
392
|
```
|
|
381
|
-
1. brainstorm_start_session(
|
|
393
|
+
1. brainstorm_start_session()
|
|
382
394
|
|
|
383
395
|
// Show initial mockup
|
|
384
396
|
2. brainstorm_push_screen({ html: "...v1 mockup..." })
|
|
@@ -395,23 +407,22 @@ All events include a `timestamp` field (Unix ms).
|
|
|
395
407
|
|
|
396
408
|
## Best Practices
|
|
397
409
|
|
|
398
|
-
1. **
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
+
1. **Zero config** — `brainstorm_start_session()` works with no arguments; isolation is automatic
|
|
411
|
+
3. **Never restart to update content** — just call `brainstorm_push_screen` again; the browser auto-reloads
|
|
412
|
+
4. **One `brainstorm_start_session` per workflow** — it reuses the existing session automatically
|
|
413
|
+
5. **Push fragments, not full documents** — the frame template handles `<html>`, theming, and scroll
|
|
414
|
+
6. **Start with a heading** — `<h2>` describes what the user is looking at
|
|
415
|
+
7. **Add a `.subtitle`** — describes the decision being made
|
|
416
|
+
8. **One decision per screen** — don't combine unrelated choices
|
|
417
|
+
9. **Use slot labels** — `label` makes comparison tabs readable
|
|
418
|
+
10. **Use `data-choice` for interaction** — the built-in `toggleSelect` emits events automatically
|
|
419
|
+
11. **Tell the user to interact** — after pushing content, let them know the browser is ready
|
|
420
|
+
12. **Read events after user has time** — don't immediately read; wait for user to respond
|
|
421
|
+
13. **Clean up with `brainstorm_stop_session`** — or use `idle_timeout_minutes` for auto-cleanup
|
|
410
422
|
|
|
411
423
|
## Common Mistakes
|
|
412
424
|
|
|
413
425
|
- **Starting a new session for each update** — DON'T. Call `push_screen` to update the existing browser.
|
|
414
|
-
- **Omitting `project_dir`** — leads to `/tmp` collisions between agents.
|
|
415
426
|
- **Pushing full HTML documents** — push fragments; the frame template adds theming and structure.
|
|
416
427
|
- **Reading events immediately after push** — give the user time to interact first.
|
|
417
|
-
- **Forgetting to stop** — always call `brainstorm_stop_session` when done
|
|
428
|
+
- **Forgetting to stop** — always call `brainstorm_stop_session` when done, or use `idle_timeout_minutes`.
|
|
@@ -152,9 +152,9 @@ brainstorm_read_events()
|
|
|
152
152
|
When running multi-round comparisons, clear events between rounds to avoid stale data:
|
|
153
153
|
|
|
154
154
|
```
|
|
155
|
-
brainstorm_read_events()
|
|
156
|
-
brainstorm_clear_screen({
|
|
157
|
-
brainstorm_push_screen({ html: "Round 2..." })
|
|
155
|
+
brainstorm_read_events({ clear_after_read: true }) // read and clear in one call
|
|
156
|
+
brainstorm_clear_screen({}) // clear content for next round
|
|
157
|
+
brainstorm_push_screen({ html: "Round 2..." }) // push next round
|
|
158
158
|
```
|
|
159
159
|
|
|
160
160
|
### Interpreting Events
|
|
@@ -250,10 +250,10 @@ stateDiagram-v2
|
|
|
250
250
|
|
|
251
251
|
This example shows a full workflow for choosing a navigation pattern for a new app.
|
|
252
252
|
|
|
253
|
-
### Step 1:
|
|
253
|
+
### Step 1: Start session and present the question
|
|
254
254
|
|
|
255
255
|
```
|
|
256
|
-
brainstorm_start_session()
|
|
256
|
+
brainstorm_start_session() // no args needed — opens browser automatically
|
|
257
257
|
|
|
258
258
|
brainstorm_push_screen({
|
|
259
259
|
html: `
|
package/src/cli.js
CHANGED
|
@@ -14,30 +14,44 @@ const { SessionManager } = require('./session');
|
|
|
14
14
|
const HELP = {
|
|
15
15
|
main: `Usage: brainstorm-companion <command> [options]
|
|
16
16
|
|
|
17
|
-
Opens a browser
|
|
18
|
-
|
|
17
|
+
Visual brainstorming tool. Opens a browser, you push HTML, users interact.
|
|
18
|
+
|
|
19
|
+
Quickstart (3 commands):
|
|
20
|
+
brainstorm-companion start
|
|
21
|
+
brainstorm-companion push --html '<h2>Hello World</h2>'
|
|
22
|
+
brainstorm-companion stop
|
|
23
|
+
|
|
24
|
+
How it works:
|
|
25
|
+
1. "start" opens a browser (reuses existing session if one is running)
|
|
26
|
+
2. "push" sends HTML to the browser — auto-reloads instantly, every time
|
|
27
|
+
3. "events" reads what the user clicked (choices, preferences)
|
|
28
|
+
4. "stop" ends the session
|
|
19
29
|
|
|
20
30
|
Commands:
|
|
21
|
-
start Start
|
|
22
|
-
push Push HTML content
|
|
23
|
-
events Read user interaction events
|
|
31
|
+
start Start server and open browser (or reuse existing session)
|
|
32
|
+
push Push HTML content — browser auto-reloads each time
|
|
33
|
+
events Read user interaction events (clicks, preferences)
|
|
24
34
|
clear Clear content or events
|
|
25
|
-
stop Stop the server
|
|
26
|
-
status Show
|
|
35
|
+
stop Stop the server and clean up
|
|
36
|
+
status Show session info (URL, uptime, slots, events)
|
|
27
37
|
|
|
28
38
|
Global Options:
|
|
29
|
-
--project-dir <path> Session storage
|
|
30
|
-
--session <id> Target a specific session (
|
|
39
|
+
--project-dir <path> Session storage (default: /tmp/brainstorm-companion/)
|
|
40
|
+
--session <id> Target a specific session (for parallel use)
|
|
31
41
|
--mcp Run as MCP server (stdio JSON-RPC)
|
|
32
|
-
--help, -h Show help (use "<command> --help" for
|
|
42
|
+
--help, -h Show help (use "<command> --help" for details)
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
brainstorm-companion
|
|
36
|
-
brainstorm-companion push --html '<h2>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
Comparison mode (side-by-side with tabs):
|
|
45
|
+
brainstorm-companion push --html '<h2>A</h2>' --slot a --label "Grid"
|
|
46
|
+
brainstorm-companion push --html '<h2>B</h2>' --slot b --label "List"
|
|
47
|
+
|
|
48
|
+
Key concepts:
|
|
49
|
+
- No setup needed — "start" works with zero arguments
|
|
50
|
+
- Push HTML fragments (not full documents) — theming is automatic
|
|
51
|
+
- Use --slot a/b/c + --label for side-by-side comparison
|
|
52
|
+
- Add data-choice="val" onclick="toggleSelect(this)" for clickable elements
|
|
53
|
+
- class="mermaid", class="language-*", $$math$$ auto-detected
|
|
54
|
+
- Sessions persist until stopped — use --timeout <min> for auto-cleanup`,
|
|
41
55
|
|
|
42
56
|
start: `Usage: brainstorm-companion start [options]
|
|
43
57
|
|
|
@@ -46,12 +60,13 @@ Start the brainstorm server and open a browser window.
|
|
|
46
60
|
If a session is already running for this project, it reuses it (prints the
|
|
47
61
|
existing URL). Use --new to force a separate session.
|
|
48
62
|
|
|
49
|
-
Sessions
|
|
63
|
+
Sessions persist until explicitly stopped — no timeout by default.
|
|
50
64
|
|
|
51
65
|
Options:
|
|
52
66
|
--project-dir <path> Session storage location (default: /tmp/brainstorm-companion/)
|
|
53
67
|
--port <number> Bind to specific port (default: random ephemeral)
|
|
54
68
|
--host <address> Bind address (default: 127.0.0.1)
|
|
69
|
+
--timeout <minutes> Auto-stop after N minutes of inactivity (default: none)
|
|
55
70
|
--foreground Run server in foreground (don't background)
|
|
56
71
|
--no-open Don't auto-open browser
|
|
57
72
|
--new Force a new session even if one is already running
|
|
@@ -62,8 +77,9 @@ Output:
|
|
|
62
77
|
|
|
63
78
|
Examples:
|
|
64
79
|
brainstorm-companion start
|
|
65
|
-
brainstorm-companion start --project-dir
|
|
66
|
-
brainstorm-companion start --
|
|
80
|
+
brainstorm-companion start --project-dir .
|
|
81
|
+
brainstorm-companion start --timeout 30 # auto-stop after 30min idle
|
|
82
|
+
brainstorm-companion start --new --no-open # parallel session, no browser`,
|
|
67
83
|
|
|
68
84
|
push: `Usage: brainstorm-companion push [<file|->] [options]
|
|
69
85
|
|
|
@@ -169,6 +185,18 @@ function printHelp(command) {
|
|
|
169
185
|
// Helpers
|
|
170
186
|
// ---------------------------------------------------------------------------
|
|
171
187
|
|
|
188
|
+
function printNextSteps() {
|
|
189
|
+
console.log(`
|
|
190
|
+
Next steps:
|
|
191
|
+
brainstorm-companion push --html '<h2>Your content</h2>' Push content to browser
|
|
192
|
+
brainstorm-companion push file.html --slot a --label "A" Comparison mode
|
|
193
|
+
brainstorm-companion events Read user interactions
|
|
194
|
+
brainstorm-companion stop Stop when done
|
|
195
|
+
|
|
196
|
+
Full docs: https://www.npmjs.com/package/brainstorm-companion
|
|
197
|
+
Run: brainstorm-companion push --help for all CSS classes and options`);
|
|
198
|
+
}
|
|
199
|
+
|
|
172
200
|
function sleep(ms) {
|
|
173
201
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
174
202
|
}
|
|
@@ -231,6 +259,7 @@ async function start(argv) {
|
|
|
231
259
|
'project-dir': { type: 'string' },
|
|
232
260
|
'port': { type: 'string', default: '0' },
|
|
233
261
|
'host': { type: 'string', default: '127.0.0.1' },
|
|
262
|
+
'timeout': { type: 'string' },
|
|
234
263
|
'foreground': { type: 'boolean', default: false },
|
|
235
264
|
'no-open': { type: 'boolean', default: false },
|
|
236
265
|
'new': { type: 'boolean', default: false },
|
|
@@ -241,6 +270,8 @@ async function start(argv) {
|
|
|
241
270
|
const projectDir = values['project-dir'] || null;
|
|
242
271
|
const host = values['host'];
|
|
243
272
|
const port = parseInt(values['port'], 10) || 0;
|
|
273
|
+
const timeoutMin = values['timeout'] ? parseInt(values['timeout'], 10) : 0;
|
|
274
|
+
const idleTimeoutMs = timeoutMin > 0 ? timeoutMin * 60 * 1000 : 0;
|
|
244
275
|
const foreground = values['foreground'];
|
|
245
276
|
const noOpen = values['no-open'];
|
|
246
277
|
const forceNew = values['new'];
|
|
@@ -253,6 +284,7 @@ async function start(argv) {
|
|
|
253
284
|
const url = existing.serverInfo.url;
|
|
254
285
|
console.log(`Server already running: ${url}`);
|
|
255
286
|
console.log(`Session ID: ${existing.sessionId}`);
|
|
287
|
+
printNextSteps();
|
|
256
288
|
if (!noOpen) {
|
|
257
289
|
openBrowser(url);
|
|
258
290
|
}
|
|
@@ -269,11 +301,13 @@ async function start(argv) {
|
|
|
269
301
|
host,
|
|
270
302
|
port,
|
|
271
303
|
ownerPid: process.pid,
|
|
304
|
+
idleTimeoutMs,
|
|
272
305
|
});
|
|
273
306
|
|
|
274
307
|
instance.server.once('listening', () => {
|
|
275
308
|
console.log(`Server started: ${instance.url}`);
|
|
276
309
|
console.log(`Session ID: ${path.basename(sessionDir)}`);
|
|
310
|
+
printNextSteps();
|
|
277
311
|
if (!noOpen) {
|
|
278
312
|
openBrowser(instance.url);
|
|
279
313
|
}
|
|
@@ -304,9 +338,7 @@ async function start(argv) {
|
|
|
304
338
|
BRAINSTORM_DIR: sessionDir,
|
|
305
339
|
BRAINSTORM_HOST: host,
|
|
306
340
|
BRAINSTORM_PORT: String(port),
|
|
307
|
-
|
|
308
|
-
// exits immediately, so the server must live independently.
|
|
309
|
-
// No idle timeout — session persists until explicitly stopped.
|
|
341
|
+
BRAINSTORM_IDLE_TIMEOUT: String(idleTimeoutMs),
|
|
310
342
|
},
|
|
311
343
|
});
|
|
312
344
|
child.unref();
|
|
@@ -320,6 +352,7 @@ async function start(argv) {
|
|
|
320
352
|
|
|
321
353
|
console.log(`Server started: ${serverInfo.url}`);
|
|
322
354
|
console.log(`Session ID: ${path.basename(sessionDir)}`);
|
|
355
|
+
printNextSteps();
|
|
323
356
|
|
|
324
357
|
if (!noOpen) {
|
|
325
358
|
openBrowser(serverInfo.url);
|
package/src/mcp.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const crypto = require('node:crypto');
|
|
3
4
|
const fs = require('node:fs');
|
|
4
5
|
const path = require('node:path');
|
|
5
6
|
const { exec } = require('node:child_process');
|
|
6
7
|
const { startServer } = require('./server');
|
|
7
8
|
|
|
9
|
+
function cwdHash() {
|
|
10
|
+
return crypto.createHash('md5').update(process.cwd()).digest('hex').slice(0, 8);
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
class McpServer {
|
|
9
14
|
constructor() {
|
|
10
15
|
this.sessionDir = null; // absolute path once session is started
|
|
@@ -50,7 +55,7 @@ class McpServer {
|
|
|
50
55
|
this.respond(id, {
|
|
51
56
|
protocolVersion: '2024-11-05',
|
|
52
57
|
capabilities: { tools: {} },
|
|
53
|
-
serverInfo: { name: 'brainstorm-companion', version: '2.0.
|
|
58
|
+
serverInfo: { name: 'brainstorm-companion', version: '2.0.1' }
|
|
54
59
|
});
|
|
55
60
|
break;
|
|
56
61
|
|
|
@@ -126,67 +131,54 @@ class McpServer {
|
|
|
126
131
|
return [
|
|
127
132
|
{
|
|
128
133
|
name: 'brainstorm_start_session',
|
|
129
|
-
description: `Start a visual brainstorming session
|
|
134
|
+
description: `Start a visual brainstorming session. Opens a browser window where you push HTML and users interact visually.
|
|
135
|
+
|
|
136
|
+
QUICKSTART — just these 3 calls:
|
|
137
|
+
brainstorm_start_session() → opens browser
|
|
138
|
+
brainstorm_push_screen({ html: "<h2>Hello</h2><p>Content</p>" }) → shows content
|
|
139
|
+
brainstorm_stop_session() → cleans up
|
|
130
140
|
|
|
131
|
-
|
|
132
|
-
1. Call brainstorm_start_session ONCE
|
|
133
|
-
2. Call brainstorm_push_screen
|
|
134
|
-
3. Call brainstorm_read_events to get user clicks/preferences.
|
|
135
|
-
4. Call brainstorm_stop_session when done
|
|
141
|
+
FULL WORKFLOW:
|
|
142
|
+
1. Call brainstorm_start_session ONCE (no args required — works immediately). Returns { url, session_dir }.
|
|
143
|
+
2. Call brainstorm_push_screen with HTML — browser auto-reloads. Call as many times as needed.
|
|
144
|
+
3. Call brainstorm_read_events to get user clicks/preferences.
|
|
145
|
+
4. Call brainstorm_stop_session when done.
|
|
136
146
|
|
|
137
|
-
|
|
147
|
+
If a session is already running, this returns the existing URL (safe to call repeatedly).
|
|
148
|
+
Sessions persist until explicitly stopped — no timeout by default.
|
|
138
149
|
|
|
139
|
-
COMPARISON MODE: Push to slots a/b/c with labels for side-by-side
|
|
150
|
+
COMPARISON MODE: Push to slots a/b/c with labels for side-by-side view:
|
|
151
|
+
brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
152
|
+
brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
140
153
|
|
|
141
|
-
|
|
142
|
-
.options + .option — Selectable
|
|
154
|
+
CSS CLASSES (themed light/dark, push fragments not full docs):
|
|
155
|
+
.options + .option — Selectable cards with .letter (A/B/C) and .content
|
|
143
156
|
.cards + .card — Grid cards with .card-image and .card-body
|
|
144
|
-
.mockup — Browser-window container
|
|
145
|
-
.split — Two-column
|
|
146
|
-
.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
.section — Block with top margin spacing
|
|
151
|
-
.label — Small uppercase badge
|
|
152
|
-
|
|
153
|
-
MAKING ELEMENTS INTERACTIVE:
|
|
154
|
-
Add data-choice="value" and onclick="toggleSelect(this)" to any element to capture clicks as events.
|
|
155
|
-
For multi-select, add data-multiselect to the container.
|
|
157
|
+
.mockup — Browser-window container (.mockup-header + .mockup-body)
|
|
158
|
+
.split — Two-column layout | .pros-cons — Tradeoff grid (.pros/.cons)
|
|
159
|
+
.mock-nav, .mock-sidebar, .mock-content, .mock-button, .mock-input
|
|
160
|
+
|
|
161
|
+
INTERACTIVE ELEMENTS:
|
|
162
|
+
Add data-choice="value" onclick="toggleSelect(this)" to capture clicks.
|
|
156
163
|
Example: <div class="option" data-choice="grid" onclick="toggleSelect(this)"><div class="letter">A</div><div class="content"><h3>Grid</h3></div></div>
|
|
157
164
|
|
|
158
|
-
AUTO-DETECTED
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
tab-switch — User switched tabs. Fields: slot, timestamp
|
|
167
|
-
view-change — User toggled view mode. Fields: mode, timestamp
|
|
168
|
-
|
|
169
|
-
WORKFLOW PATTERNS:
|
|
170
|
-
Single Decision: start → push (options with data-choice) → tell user to select → read_events → use choice → stop
|
|
171
|
-
A/B/C Comparison: start → push slot a → push slot b → tell user to compare → read_events → look for preference → stop
|
|
172
|
-
Multi-Round: start → push round 1 → read_events(clear_after_read:true) → clear_screen → push round 2 → read_events → stop
|
|
173
|
-
Progressive Refinement: start → push v1 → get feedback → push v2 (same browser updates) → iterate → stop
|
|
174
|
-
|
|
175
|
-
BEST PRACTICES:
|
|
176
|
-
- ALWAYS pass project_dir (use cwd) to avoid cross-agent conflicts
|
|
177
|
-
- NEVER restart to update content — just call push_screen again
|
|
178
|
-
- Push HTML fragments, not full documents
|
|
179
|
-
- Start with <h2> heading + .subtitle describing the decision
|
|
180
|
-
- One decision per screen
|
|
181
|
-
- Tell the user the browser is ready after pushing
|
|
165
|
+
AUTO-DETECTED (CDN injected): class="mermaid" (diagrams), class="language-*" (syntax), $$...$$ (math)
|
|
166
|
+
|
|
167
|
+
EVENTS: click (choice,text), preference (choice), tab-switch (slot), view-change (mode)
|
|
168
|
+
|
|
169
|
+
RULES:
|
|
170
|
+
- NEVER restart to update — just push_screen again
|
|
171
|
+
- Push HTML fragments, not full <html> documents
|
|
172
|
+
- Tell user the browser is ready after pushing
|
|
182
173
|
- Give user time before reading events
|
|
183
|
-
- Always
|
|
174
|
+
- Always stop_session when done`,
|
|
184
175
|
inputSchema: {
|
|
185
176
|
type: 'object',
|
|
186
177
|
properties: {
|
|
187
|
-
project_dir: { type: 'string', description: '
|
|
178
|
+
project_dir: { type: 'string', description: 'Optional. Stores session files under <dir>/.superpowers/brainstorm/. If omitted, auto-isolates by working directory.' },
|
|
188
179
|
port: { type: 'number', description: 'Port to bind to (default: random ephemeral)' },
|
|
189
|
-
open_browser: { type: 'boolean', description: '
|
|
180
|
+
open_browser: { type: 'boolean', description: 'Open browser automatically (default: true)' },
|
|
181
|
+
idle_timeout_minutes: { type: 'number', description: 'Auto-stop after N minutes idle (default: 0 = no timeout)' }
|
|
190
182
|
}
|
|
191
183
|
}
|
|
192
184
|
},
|
|
@@ -255,12 +247,12 @@ Give the user time to interact before reading — don't read immediately after p
|
|
|
255
247
|
return { url: this.serverInstance.url, session_dir: this.sessionDir };
|
|
256
248
|
}
|
|
257
249
|
|
|
258
|
-
const { project_dir, port = 0, open_browser = true } = args;
|
|
250
|
+
const { project_dir, port = 0, open_browser = true, idle_timeout_minutes = 0 } = args;
|
|
259
251
|
|
|
260
252
|
// Determine base directory and create session dir
|
|
261
253
|
const baseDir = project_dir
|
|
262
254
|
? path.join(project_dir, '.superpowers', 'brainstorm')
|
|
263
|
-
: '/tmp
|
|
255
|
+
: path.join('/tmp', 'brainstorm-companion', cwdHash());
|
|
264
256
|
const sessionId = `${process.pid}-${Date.now()}`;
|
|
265
257
|
const sessionDir = path.join(baseDir, sessionId);
|
|
266
258
|
fs.mkdirSync(sessionDir, { recursive: true });
|
|
@@ -271,6 +263,7 @@ Give the user time to interact before reading — don't read immediately after p
|
|
|
271
263
|
host: '127.0.0.1',
|
|
272
264
|
port: port || 0,
|
|
273
265
|
ownerPid: process.pid,
|
|
266
|
+
idleTimeoutMs: idle_timeout_minutes > 0 ? idle_timeout_minutes * 60 * 1000 : 0,
|
|
274
267
|
logFn: (...a) => console.error(...a),
|
|
275
268
|
});
|
|
276
269
|
|
package/src/session.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const crypto = require('node:crypto');
|
|
3
4
|
const fs = require('node:fs');
|
|
4
5
|
const path = require('node:path');
|
|
5
6
|
|
|
7
|
+
function cwdHash() {
|
|
8
|
+
return crypto.createHash('md5').update(process.cwd()).digest('hex').slice(0, 8);
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
class SessionManager {
|
|
7
12
|
constructor(projectDir, targetSessionId) {
|
|
8
13
|
this.baseDir = projectDir
|
|
9
|
-
?
|
|
10
|
-
:
|
|
14
|
+
? path.join(projectDir, '.superpowers', 'brainstorm')
|
|
15
|
+
: path.join('/tmp', 'brainstorm-companion', cwdHash());
|
|
11
16
|
this.targetSessionId = targetSessionId || null;
|
|
12
17
|
}
|
|
13
18
|
|