brainstorm-companion 1.2.1 → 2.0.1
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 +223 -97
- package/package.json +1 -1
- package/skill/SKILL.md +46 -16
- package/src/cli.js +42 -22
- package/src/mcp.js +71 -15
- package/src/server.js +9 -2
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ 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 stay alive until you explicitly stop them with `stop` or `brainstorm_stop_session`. Use `--timeout <minutes>` if you want auto-cleanup.
|
|
8
|
+
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
@@ -16,33 +18,83 @@ Or run directly:
|
|
|
16
18
|
npx brainstorm-companion start
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
### Claude Code MCP Setup
|
|
22
|
+
|
|
23
|
+
Add to `~/.claude/settings.json`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"brainstorm": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["brainstorm-companion", "--mcp"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Once configured, the agent has access to 5 tools: `brainstorm_start_session`, `brainstorm_push_screen`, `brainstorm_read_events`, `brainstorm_clear_screen`, and `brainstorm_stop_session`. Full documentation is embedded in the tool descriptions — the agent becomes an expert immediately upon connecting.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Complete Usage Guide
|
|
41
|
+
|
|
42
|
+
### Quick Start (CLI) — 3 commands, zero config
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
brainstorm-companion start # opens browser
|
|
46
|
+
brainstorm-companion push --html '<h2>Hello World</h2>' # shows content
|
|
47
|
+
brainstorm-companion stop # cleans up
|
|
48
|
+
```
|
|
20
49
|
|
|
21
|
-
|
|
50
|
+
That's it. No arguments required. Now a fuller example:
|
|
22
51
|
|
|
23
52
|
```bash
|
|
24
|
-
#
|
|
25
|
-
brainstorm-companion start
|
|
53
|
+
# Start (opens browser, prints URL)
|
|
54
|
+
brainstorm-companion start
|
|
26
55
|
# → Server started: http://127.0.0.1:54321
|
|
27
|
-
# → Session ID: 1234-1700000000000
|
|
28
56
|
|
|
29
|
-
#
|
|
30
|
-
brainstorm-companion push --html '<h2>Dashboard
|
|
57
|
+
# Push content — browser updates instantly
|
|
58
|
+
brainstorm-companion push --html '<h2>Dashboard</h2><p>First draft</p>'
|
|
31
59
|
|
|
32
|
-
#
|
|
33
|
-
brainstorm-companion push --html '<h2>
|
|
60
|
+
# Update — same browser, auto-reloads
|
|
61
|
+
brainstorm-companion push --html '<h2>Dashboard v2</h2><p>Refined</p>'
|
|
34
62
|
|
|
35
|
-
#
|
|
63
|
+
# Read what user clicked
|
|
36
64
|
brainstorm-companion events
|
|
37
|
-
# → [{"type":"click","choice":"grid","text":"A Grid Layout Cards in a responsive grid","timestamp":1700000001234}]
|
|
38
65
|
|
|
39
|
-
#
|
|
66
|
+
# Done
|
|
40
67
|
brainstorm-companion stop
|
|
41
68
|
```
|
|
42
69
|
|
|
43
|
-
**Key
|
|
70
|
+
**Key behaviors:**
|
|
71
|
+
- `start` with no args works immediately (stores in `/tmp/brainstorm-companion/`)
|
|
72
|
+
- `start` reuses an existing session — never opens duplicate browsers
|
|
73
|
+
- `push` auto-reloads the browser every time — no restart or refresh needed
|
|
74
|
+
- Add `--project-dir .` for project-local storage
|
|
44
75
|
|
|
45
|
-
###
|
|
76
|
+
### Quick Start (MCP / Agent) — 3 calls, zero config
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
1. brainstorm_start_session()
|
|
80
|
+
→ { url: "http://127.0.0.1:54321", session_dir: "..." }
|
|
81
|
+
|
|
82
|
+
2. brainstorm_push_screen({ html: "<h2>Option A</h2>...", slot: "a", label: "Minimal" })
|
|
83
|
+
brainstorm_push_screen({ html: "<h2>Option B</h2>...", slot: "b", label: "Sidebar" })
|
|
84
|
+
|
|
85
|
+
3. brainstorm_read_events({})
|
|
86
|
+
→ { events: [{ type: "preference", choice: "a" }], count: 1 }
|
|
87
|
+
|
|
88
|
+
4. brainstorm_push_screen({ html: "<h2>Revised A</h2>...", slot: "a", label: "Minimal v2" })
|
|
89
|
+
|
|
90
|
+
5. brainstorm_stop_session({})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**No arguments required.** `brainstorm_start_session()` works with zero config. Pass `project_dir` for project-local storage or when multiple agents run simultaneously. Sessions persist until `brainstorm_stop_session()` — use `idle_timeout_minutes` for auto-cleanup.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Side-by-Side Comparison
|
|
46
98
|
|
|
47
99
|
Push to named slots for comparison mode with tabs and preference selection:
|
|
48
100
|
|
|
@@ -54,7 +106,7 @@ brainstorm-companion push --html '<h2>Hybrid</h2><p>Collapsible sidebar + top ba
|
|
|
54
106
|
|
|
55
107
|
Browser shows all three side-by-side with tabs, keyboard shortcuts (1/2/3), and a preference bar.
|
|
56
108
|
|
|
57
|
-
|
|
109
|
+
## Updating Content In-Place
|
|
58
110
|
|
|
59
111
|
The browser auto-reloads whenever content is pushed. No need to restart the session or manually refresh:
|
|
60
112
|
|
|
@@ -72,7 +124,7 @@ brainstorm-companion push --html '<h2>Updated Option A</h2>' --slot a --label "R
|
|
|
72
124
|
# → Only slot A updates, others stay
|
|
73
125
|
```
|
|
74
126
|
|
|
75
|
-
|
|
127
|
+
## From Files or Stdin
|
|
76
128
|
|
|
77
129
|
```bash
|
|
78
130
|
brainstorm-companion push mockup.html
|
|
@@ -80,7 +132,7 @@ brainstorm-companion push mockup.html --slot a --label "v1"
|
|
|
80
132
|
cat design.html | brainstorm-companion push -
|
|
81
133
|
```
|
|
82
134
|
|
|
83
|
-
|
|
135
|
+
## Parallel Instances
|
|
84
136
|
|
|
85
137
|
Multiple agents can run simultaneously on the same project. Use `--new` to force a separate session:
|
|
86
138
|
|
|
@@ -102,26 +154,80 @@ brainstorm-companion stop --session 1111-000
|
|
|
102
154
|
|
|
103
155
|
Without `--new`, `start` reuses the existing session (the default for single-agent use).
|
|
104
156
|
|
|
105
|
-
|
|
157
|
+
---
|
|
106
158
|
|
|
107
|
-
|
|
159
|
+
## HTML Content Guide
|
|
108
160
|
|
|
109
|
-
###
|
|
161
|
+
### Built-in CSS Classes
|
|
110
162
|
|
|
111
|
-
|
|
163
|
+
The frame template provides themed styles (auto light/dark mode). Push HTML **fragments**, not full documents — the frame wraps your content with theming, a header, and a selection indicator bar.
|
|
112
164
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
165
|
+
| Class | Purpose |
|
|
166
|
+
|-------|---------|
|
|
167
|
+
| `.options` + `.option` | Selectable vertical option cards with letter badges |
|
|
168
|
+
| `.option .letter` | A/B/C badge inside an option |
|
|
169
|
+
| `.option .content` | Text content inside an option |
|
|
170
|
+
| `.cards` + `.card` | Grid cards with `.card-image` and `.card-body` |
|
|
171
|
+
| `.mockup` | Browser-window container with `.mockup-header` and `.mockup-body` |
|
|
172
|
+
| `.split` | Side-by-side two-column layout |
|
|
173
|
+
| `.pros-cons` | Pros/cons comparison with `.pros` (green) and `.cons` (red) |
|
|
174
|
+
| `.placeholder` | Dashed placeholder area |
|
|
175
|
+
| `.subtitle` | Muted text below headings |
|
|
176
|
+
| `.section` | Block with top margin spacing |
|
|
177
|
+
| `.label` | Small uppercase badge |
|
|
178
|
+
| `.mock-nav`, `.mock-sidebar`, `.mock-content` | UI mockup building blocks |
|
|
179
|
+
| `.mock-button`, `.mock-input` | Styled form elements |
|
|
180
|
+
|
|
181
|
+
### Making Elements Interactive
|
|
182
|
+
|
|
183
|
+
Add `data-choice` and `onclick="toggleSelect(this)"` to capture user selections:
|
|
184
|
+
|
|
185
|
+
```html
|
|
186
|
+
<div class="option" data-choice="grid" onclick="toggleSelect(this)">
|
|
187
|
+
<div class="letter">A</div>
|
|
188
|
+
<div class="content"><h3>Grid Layout</h3></div>
|
|
189
|
+
</div>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
For multi-select, add `data-multiselect` to the container:
|
|
193
|
+
|
|
194
|
+
```html
|
|
195
|
+
<div class="options" data-multiselect>...</div>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Auto-detected Libraries
|
|
199
|
+
|
|
200
|
+
Content is automatically enhanced when these patterns are detected (CDN injected automatically):
|
|
201
|
+
|
|
202
|
+
| Pattern | Library | What it does |
|
|
203
|
+
|---------|---------|-------------|
|
|
204
|
+
| `class="mermaid"` | Mermaid | Renders diagrams (flowchart, sequence, class, state, ER, Gantt, pie) |
|
|
205
|
+
| `class="language-*"` | Prism.js | Syntax highlighting |
|
|
206
|
+
| `$$...$$` or `class="math"` | KaTeX | Math rendering |
|
|
207
|
+
|
|
208
|
+
```html
|
|
209
|
+
<div class="mermaid">
|
|
210
|
+
graph TD
|
|
211
|
+
A[Start] --> B{Decision}
|
|
212
|
+
B -->|Yes| C[Action]
|
|
213
|
+
B -->|No| D[Other]
|
|
214
|
+
</div>
|
|
122
215
|
```
|
|
123
216
|
|
|
124
|
-
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Event Types
|
|
220
|
+
|
|
221
|
+
| Event | When | Key Fields |
|
|
222
|
+
|-------|------|-----------|
|
|
223
|
+
| `click` | User clicks a `[data-choice]` element | `choice`, `text`, `id`, `timestamp` |
|
|
224
|
+
| `preference` | User picks a preferred slot in comparison mode | `choice` (slot id), `timestamp` |
|
|
225
|
+
| `tab-switch` | User switches tabs in comparison mode | `slot`, `timestamp` |
|
|
226
|
+
| `view-change` | User toggles side-by-side vs single view | `mode`, `timestamp` |
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## MCP Tools Reference
|
|
125
231
|
|
|
126
232
|
| Tool | Description |
|
|
127
233
|
|------|-------------|
|
|
@@ -131,25 +237,73 @@ Add to `~/.claude/settings.json`:
|
|
|
131
237
|
| `brainstorm_clear_screen` | Clear a specific slot or all content. |
|
|
132
238
|
| `brainstorm_stop_session` | Stop server and clean up session files. |
|
|
133
239
|
|
|
134
|
-
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Workflow Patterns
|
|
243
|
+
|
|
244
|
+
### Single Decision
|
|
135
245
|
|
|
136
246
|
```
|
|
137
|
-
1. brainstorm_start_session({ project_dir: "
|
|
138
|
-
|
|
247
|
+
1. brainstorm_start_session({ project_dir: "..." })
|
|
248
|
+
2. brainstorm_push_screen({ html: "...options with data-choice..." })
|
|
249
|
+
3. → Tell user to make their selection in the browser
|
|
250
|
+
4. brainstorm_read_events({})
|
|
251
|
+
5. → Use the choice to proceed
|
|
252
|
+
6. brainstorm_stop_session({})
|
|
253
|
+
```
|
|
139
254
|
|
|
140
|
-
|
|
141
|
-
brainstorm_push_screen({ html: "<h2>Option B</h2>...", slot: "b", label: "Sidebar" })
|
|
255
|
+
### A/B/C Comparison
|
|
142
256
|
|
|
143
|
-
|
|
144
|
-
|
|
257
|
+
```
|
|
258
|
+
1. brainstorm_start_session({ project_dir: "..." })
|
|
259
|
+
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
260
|
+
3. brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
261
|
+
4. → Tell user to compare and pick a preference
|
|
262
|
+
5. brainstorm_read_events({})
|
|
263
|
+
6. → Look for { type: "preference", choice: "a"|"b" }
|
|
264
|
+
7. brainstorm_stop_session({})
|
|
265
|
+
```
|
|
145
266
|
|
|
146
|
-
|
|
147
|
-
4. brainstorm_push_screen({ html: "<h2>Revised A</h2>...", slot: "a", label: "Minimal v2" })
|
|
267
|
+
### Multi-Round Brainstorming
|
|
148
268
|
|
|
149
|
-
|
|
269
|
+
```
|
|
270
|
+
1. brainstorm_start_session({ project_dir: "..." })
|
|
271
|
+
|
|
272
|
+
// Round 1: Layout
|
|
273
|
+
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Grid" })
|
|
274
|
+
3. brainstorm_push_screen({ html: "...", slot: "b", label: "List" })
|
|
275
|
+
4. brainstorm_read_events({ clear_after_read: true })
|
|
276
|
+
5. → User chose "Grid"
|
|
277
|
+
|
|
278
|
+
// Round 2: Color scheme (clear old slots first)
|
|
279
|
+
6. brainstorm_clear_screen({})
|
|
280
|
+
7. brainstorm_push_screen({ html: "...", slot: "a", label: "Light" })
|
|
281
|
+
8. brainstorm_push_screen({ html: "...", slot: "b", label: "Dark" })
|
|
282
|
+
9. brainstorm_read_events({ clear_after_read: true })
|
|
283
|
+
10. → User chose "Dark"
|
|
284
|
+
|
|
285
|
+
// Show final summary
|
|
286
|
+
11. brainstorm_push_screen({ html: "<h2>Decisions: Grid + Dark</h2>..." })
|
|
287
|
+
12. brainstorm_stop_session({})
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Progressive Refinement
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
1. brainstorm_start_session({ project_dir: "..." })
|
|
294
|
+
|
|
295
|
+
// Show initial mockup
|
|
296
|
+
2. brainstorm_push_screen({ html: "...v1 mockup..." })
|
|
297
|
+
3. → Get feedback from user (text in chat, not events)
|
|
298
|
+
|
|
299
|
+
// Push refined version — browser auto-reloads
|
|
300
|
+
4. brainstorm_push_screen({ html: "...v2 mockup with changes..." })
|
|
301
|
+
5. → Iterate until user is satisfied
|
|
302
|
+
|
|
303
|
+
6. brainstorm_stop_session({})
|
|
150
304
|
```
|
|
151
305
|
|
|
152
|
-
|
|
306
|
+
---
|
|
153
307
|
|
|
154
308
|
## CLI Reference
|
|
155
309
|
|
|
@@ -174,10 +328,10 @@ Global Options:
|
|
|
174
328
|
### `start`
|
|
175
329
|
|
|
176
330
|
```
|
|
177
|
-
brainstorm-companion start [--project-dir <path>] [--port <N>] [--host <H>] [--foreground] [--no-open] [--new]
|
|
331
|
+
brainstorm-companion start [--project-dir <path>] [--port <N>] [--host <H>] [--timeout <min>] [--foreground] [--no-open] [--new]
|
|
178
332
|
```
|
|
179
333
|
|
|
180
|
-
If a session is already running, prints its URL and reuses it. Use `--new` to force a separate parallel session.
|
|
334
|
+
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).
|
|
181
335
|
|
|
182
336
|
### `push`
|
|
183
337
|
|
|
@@ -215,58 +369,7 @@ brainstorm-companion status
|
|
|
215
369
|
|
|
216
370
|
Shows Session ID, URL, uptime, event count, and active slots.
|
|
217
371
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
### Built-in CSS Classes
|
|
221
|
-
|
|
222
|
-
The frame template provides themed styles (auto light/dark mode):
|
|
223
|
-
|
|
224
|
-
| Class | Purpose |
|
|
225
|
-
|-------|---------|
|
|
226
|
-
| `.options` + `.option` | Selectable vertical option cards with letter badges |
|
|
227
|
-
| `.cards` + `.card` | Grid cards with `.card-image` and `.card-body` |
|
|
228
|
-
| `.mockup` | Container with `.mockup-header` and `.mockup-body` |
|
|
229
|
-
| `.split` | Side-by-side two-column layout |
|
|
230
|
-
| `.pros-cons` | Pros/cons comparison with `.pros` and `.cons` |
|
|
231
|
-
| `.placeholder` | Dashed placeholder area |
|
|
232
|
-
| `.mock-nav`, `.mock-sidebar`, `.mock-content` | UI mockup building blocks |
|
|
233
|
-
| `.mock-button`, `.mock-input` | Styled form elements |
|
|
234
|
-
|
|
235
|
-
### Making Elements Interactive
|
|
236
|
-
|
|
237
|
-
Add `data-choice` and `onclick="toggleSelect(this)"` to capture user selections:
|
|
238
|
-
|
|
239
|
-
```html
|
|
240
|
-
<div class="option" data-choice="grid" onclick="toggleSelect(this)">
|
|
241
|
-
<div class="letter">A</div>
|
|
242
|
-
<div class="content"><h3>Grid Layout</h3></div>
|
|
243
|
-
</div>
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
For multi-select, add `data-multiselect` to the container:
|
|
247
|
-
|
|
248
|
-
```html
|
|
249
|
-
<div class="options" data-multiselect>...</div>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Auto-detected Libraries
|
|
253
|
-
|
|
254
|
-
Content is automatically enhanced when these patterns are detected:
|
|
255
|
-
|
|
256
|
-
| Pattern | Library | What it does |
|
|
257
|
-
|---------|---------|-------------|
|
|
258
|
-
| `class="mermaid"` | Mermaid | Renders diagrams from text |
|
|
259
|
-
| `class="language-*"` | Prism.js | Syntax highlighting |
|
|
260
|
-
| `$$...$$` or `class="math"` | KaTeX | Math rendering |
|
|
261
|
-
|
|
262
|
-
```html
|
|
263
|
-
<div class="mermaid">
|
|
264
|
-
graph TD
|
|
265
|
-
A[Start] --> B{Decision}
|
|
266
|
-
B -->|Yes| C[Action]
|
|
267
|
-
B -->|No| D[Other]
|
|
268
|
-
</div>
|
|
269
|
-
```
|
|
372
|
+
---
|
|
270
373
|
|
|
271
374
|
## How It Works
|
|
272
375
|
|
|
@@ -276,7 +379,30 @@ graph TD
|
|
|
276
379
|
4. Click events are sent over WebSocket to the server and appended to a `.events` JSONL file
|
|
277
380
|
5. `events` reads the JSONL file and returns structured JSON
|
|
278
381
|
6. Each session is fully isolated: own port, own directory, own event log
|
|
279
|
-
7.
|
|
382
|
+
7. Sessions are persistent — they stay alive until explicitly stopped with `stop` or `brainstorm_stop_session`
|
|
383
|
+
|
|
384
|
+
## Best Practices
|
|
385
|
+
|
|
386
|
+
1. **Always pass `project_dir`** to `brainstorm_start_session` — avoids cross-agent conflicts
|
|
387
|
+
2. **Never restart to update content** — just call `brainstorm_push_screen` again; the browser auto-reloads
|
|
388
|
+
3. **One `brainstorm_start_session` per workflow** — it reuses the existing session automatically
|
|
389
|
+
4. **Push fragments, not full documents** — the frame template handles `<html>`, theming, and scroll
|
|
390
|
+
5. **Start with a heading** — `<h2>` describes what the user is looking at
|
|
391
|
+
6. **Add a `.subtitle`** — describes the decision being made
|
|
392
|
+
7. **One decision per screen** — don't combine unrelated choices
|
|
393
|
+
8. **Use slot labels** — `label` makes comparison tabs readable
|
|
394
|
+
9. **Use `data-choice` for interaction** — the built-in `toggleSelect` emits events automatically
|
|
395
|
+
10. **Tell the user to interact** — after pushing content, let them know the browser is ready
|
|
396
|
+
11. **Read events after user has time** — don't immediately read; wait for user to respond
|
|
397
|
+
12. **Clean up with `brainstorm_stop_session`** — frees the port and removes temp files
|
|
398
|
+
|
|
399
|
+
## Common Mistakes
|
|
400
|
+
|
|
401
|
+
- **Starting a new session for each update** — DON'T. Call `push_screen` to update the existing browser.
|
|
402
|
+
- **Omitting `project_dir`** — leads to `/tmp` collisions between agents.
|
|
403
|
+
- **Pushing full HTML documents** — push fragments; the frame template adds theming and structure.
|
|
404
|
+
- **Reading events immediately after push** — give the user time to interact first.
|
|
405
|
+
- **Forgetting to stop** — always call `brainstorm_stop_session` when done.
|
|
280
406
|
|
|
281
407
|
## Author
|
|
282
408
|
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -1,41 +1,61 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: brainstorm-companion
|
|
3
|
-
description: Visual brainstorming companion — opens a browser window for comparing design mockups, architecture options, and UI prototypes. Agents push HTML content and users interact visually.
|
|
3
|
+
description: Visual brainstorming companion — opens a browser window for comparing design mockups, architecture options, and UI prototypes. Agents push HTML content and users interact visually. Sessions are persistent and never time out.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Brainstorm Companion
|
|
6
|
+
# Brainstorm Companion — Complete Agent Reference
|
|
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.
|
|
7
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
|
-
|
|
23
|
+
- Get visual feedback — user clicks and preferences captured as events
|
|
24
|
+
|
|
25
|
+
**Don't use** for plain text, simple data, or anything fine in the terminal.
|
|
16
26
|
|
|
17
|
-
|
|
27
|
+
## Session Lifecycle
|
|
28
|
+
|
|
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
|
|
34
|
+
|
|
35
|
+
---
|
|
18
36
|
|
|
19
37
|
## MCP Tools Reference
|
|
20
38
|
|
|
21
39
|
### brainstorm_start_session
|
|
22
40
|
|
|
23
|
-
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.
|
|
24
42
|
|
|
25
43
|
```
|
|
44
|
+
// Simplest — no args needed:
|
|
45
|
+
brainstorm_start_session()
|
|
46
|
+
→ { url: "http://127.0.0.1:54321", session_dir: "..." }
|
|
47
|
+
|
|
48
|
+
// With options:
|
|
26
49
|
brainstorm_start_session({
|
|
27
|
-
project_dir: "/path/to/project", //
|
|
50
|
+
project_dir: "/path/to/project", // optional — use cwd for project-local storage
|
|
28
51
|
open_browser: true, // default: true
|
|
29
|
-
|
|
52
|
+
idle_timeout_minutes: 0 // default: 0 = no timeout. Set 30 for auto-cleanup.
|
|
30
53
|
})
|
|
31
|
-
→ { url: "http://127.0.0.1:54321", session_dir: "..." }
|
|
32
54
|
```
|
|
33
55
|
|
|
34
|
-
|
|
56
|
+
**`project_dir` is optional.** Without it, sessions go to `/tmp/brainstorm-companion/`. Pass the current working directory for project-local storage or when multiple agents may run simultaneously.
|
|
35
57
|
|
|
36
|
-
**Calling
|
|
37
|
-
|
|
38
|
-
The server runs independently in the background with a 30-minute idle timeout.
|
|
58
|
+
**Calling it multiple times is safe** — returns the existing session. Just call `brainstorm_push_screen` to update content.
|
|
39
59
|
|
|
40
60
|
### brainstorm_push_screen
|
|
41
61
|
|
|
@@ -94,6 +114,8 @@ brainstorm_stop_session({})
|
|
|
94
114
|
|
|
95
115
|
Always call this when done brainstorming to free the port and clean up files.
|
|
96
116
|
|
|
117
|
+
---
|
|
118
|
+
|
|
97
119
|
## HTML Content — What to Push
|
|
98
120
|
|
|
99
121
|
You push HTML **fragments**, not full documents. The frame template wraps your content with theming (auto light/dark mode), a header, and a selection indicator bar.
|
|
@@ -271,6 +293,8 @@ Use `$$...$$` for display math. KaTeX CDN is injected automatically.
|
|
|
271
293
|
<p>$$L = -\sum_{i} y_i \log(\hat{y}_i)$$</p>
|
|
272
294
|
```
|
|
273
295
|
|
|
296
|
+
---
|
|
297
|
+
|
|
274
298
|
## CSS Classes Quick Reference
|
|
275
299
|
|
|
276
300
|
| Class | Purpose |
|
|
@@ -300,6 +324,8 @@ Use `$$...$$` for display math. KaTeX CDN is injected automatically.
|
|
|
300
324
|
| `.mock-button` | Styled button element |
|
|
301
325
|
| `.mock-input` | Styled input field |
|
|
302
326
|
|
|
327
|
+
---
|
|
328
|
+
|
|
303
329
|
## Event Types
|
|
304
330
|
|
|
305
331
|
| Event | When | Key Fields |
|
|
@@ -311,6 +337,8 @@ Use `$$...$$` for display math. KaTeX CDN is injected automatically.
|
|
|
311
337
|
|
|
312
338
|
All events include a `timestamp` field (Unix ms).
|
|
313
339
|
|
|
340
|
+
---
|
|
341
|
+
|
|
314
342
|
## Workflow Patterns
|
|
315
343
|
|
|
316
344
|
### Single Decision
|
|
@@ -375,6 +403,8 @@ All events include a `timestamp` field (Unix ms).
|
|
|
375
403
|
6. brainstorm_stop_session({})
|
|
376
404
|
```
|
|
377
405
|
|
|
406
|
+
---
|
|
407
|
+
|
|
378
408
|
## Best Practices
|
|
379
409
|
|
|
380
410
|
1. **Always pass `project_dir`** to `brainstorm_start_session` — avoids cross-agent conflicts
|
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,10 +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
|
|
|
63
|
+
Sessions persist until explicitly stopped — no timeout by default.
|
|
64
|
+
|
|
49
65
|
Options:
|
|
50
66
|
--project-dir <path> Session storage location (default: /tmp/brainstorm-companion/)
|
|
51
67
|
--port <number> Bind to specific port (default: random ephemeral)
|
|
52
68
|
--host <address> Bind address (default: 127.0.0.1)
|
|
69
|
+
--timeout <minutes> Auto-stop after N minutes of inactivity (default: none)
|
|
53
70
|
--foreground Run server in foreground (don't background)
|
|
54
71
|
--no-open Don't auto-open browser
|
|
55
72
|
--new Force a new session even if one is already running
|
|
@@ -60,8 +77,9 @@ Output:
|
|
|
60
77
|
|
|
61
78
|
Examples:
|
|
62
79
|
brainstorm-companion start
|
|
63
|
-
brainstorm-companion start --project-dir
|
|
64
|
-
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`,
|
|
65
83
|
|
|
66
84
|
push: `Usage: brainstorm-companion push [<file|->] [options]
|
|
67
85
|
|
|
@@ -229,6 +247,7 @@ async function start(argv) {
|
|
|
229
247
|
'project-dir': { type: 'string' },
|
|
230
248
|
'port': { type: 'string', default: '0' },
|
|
231
249
|
'host': { type: 'string', default: '127.0.0.1' },
|
|
250
|
+
'timeout': { type: 'string' },
|
|
232
251
|
'foreground': { type: 'boolean', default: false },
|
|
233
252
|
'no-open': { type: 'boolean', default: false },
|
|
234
253
|
'new': { type: 'boolean', default: false },
|
|
@@ -239,6 +258,8 @@ async function start(argv) {
|
|
|
239
258
|
const projectDir = values['project-dir'] || null;
|
|
240
259
|
const host = values['host'];
|
|
241
260
|
const port = parseInt(values['port'], 10) || 0;
|
|
261
|
+
const timeoutMin = values['timeout'] ? parseInt(values['timeout'], 10) : 0;
|
|
262
|
+
const idleTimeoutMs = timeoutMin > 0 ? timeoutMin * 60 * 1000 : 0;
|
|
242
263
|
const foreground = values['foreground'];
|
|
243
264
|
const noOpen = values['no-open'];
|
|
244
265
|
const forceNew = values['new'];
|
|
@@ -267,6 +288,7 @@ async function start(argv) {
|
|
|
267
288
|
host,
|
|
268
289
|
port,
|
|
269
290
|
ownerPid: process.pid,
|
|
291
|
+
idleTimeoutMs,
|
|
270
292
|
});
|
|
271
293
|
|
|
272
294
|
instance.server.once('listening', () => {
|
|
@@ -302,9 +324,7 @@ async function start(argv) {
|
|
|
302
324
|
BRAINSTORM_DIR: sessionDir,
|
|
303
325
|
BRAINSTORM_HOST: host,
|
|
304
326
|
BRAINSTORM_PORT: String(port),
|
|
305
|
-
|
|
306
|
-
// exits immediately, so the server must live independently.
|
|
307
|
-
// Server still has 30-minute idle timeout for cleanup.
|
|
327
|
+
BRAINSTORM_IDLE_TIMEOUT: String(idleTimeoutMs),
|
|
308
328
|
},
|
|
309
329
|
});
|
|
310
330
|
child.unref();
|
package/src/mcp.js
CHANGED
|
@@ -50,7 +50,7 @@ class McpServer {
|
|
|
50
50
|
this.respond(id, {
|
|
51
51
|
protocolVersion: '2024-11-05',
|
|
52
52
|
capabilities: { tools: {} },
|
|
53
|
-
serverInfo: { name: 'brainstorm-companion', version: '
|
|
53
|
+
serverInfo: { name: 'brainstorm-companion', version: '2.0.1' }
|
|
54
54
|
});
|
|
55
55
|
break;
|
|
56
56
|
|
|
@@ -126,52 +126,107 @@ class McpServer {
|
|
|
126
126
|
return [
|
|
127
127
|
{
|
|
128
128
|
name: 'brainstorm_start_session',
|
|
129
|
-
description:
|
|
129
|
+
description: `Start a visual brainstorming session. Opens a browser window where you push HTML and users interact visually.
|
|
130
|
+
|
|
131
|
+
QUICKSTART — just these 3 calls:
|
|
132
|
+
brainstorm_start_session() → opens browser
|
|
133
|
+
brainstorm_push_screen({ html: "<h2>Hello</h2><p>Content</p>" }) → shows content
|
|
134
|
+
brainstorm_stop_session() → cleans up
|
|
135
|
+
|
|
136
|
+
FULL WORKFLOW:
|
|
137
|
+
1. Call brainstorm_start_session ONCE (no args required — works immediately). Returns { url, session_dir }.
|
|
138
|
+
2. Call brainstorm_push_screen with HTML — browser auto-reloads. Call as many times as needed.
|
|
139
|
+
3. Call brainstorm_read_events to get user clicks/preferences.
|
|
140
|
+
4. Call brainstorm_stop_session when done.
|
|
141
|
+
|
|
142
|
+
If a session is already running, this returns the existing URL (safe to call repeatedly).
|
|
143
|
+
Sessions persist until explicitly stopped — no timeout by default.
|
|
144
|
+
|
|
145
|
+
COMPARISON MODE: Push to slots a/b/c with labels for side-by-side view:
|
|
146
|
+
brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
147
|
+
brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
148
|
+
|
|
149
|
+
CSS CLASSES (themed light/dark, push fragments not full docs):
|
|
150
|
+
.options + .option — Selectable cards with .letter (A/B/C) and .content
|
|
151
|
+
.cards + .card — Grid cards with .card-image and .card-body
|
|
152
|
+
.mockup — Browser-window container (.mockup-header + .mockup-body)
|
|
153
|
+
.split — Two-column layout | .pros-cons — Tradeoff grid (.pros/.cons)
|
|
154
|
+
.mock-nav, .mock-sidebar, .mock-content, .mock-button, .mock-input
|
|
155
|
+
|
|
156
|
+
INTERACTIVE ELEMENTS:
|
|
157
|
+
Add data-choice="value" onclick="toggleSelect(this)" to capture clicks.
|
|
158
|
+
Example: <div class="option" data-choice="grid" onclick="toggleSelect(this)"><div class="letter">A</div><div class="content"><h3>Grid</h3></div></div>
|
|
159
|
+
|
|
160
|
+
AUTO-DETECTED (CDN injected): class="mermaid" (diagrams), class="language-*" (syntax), $$...$$ (math)
|
|
161
|
+
|
|
162
|
+
EVENTS: click (choice,text), preference (choice), tab-switch (slot), view-change (mode)
|
|
163
|
+
|
|
164
|
+
RULES:
|
|
165
|
+
- NEVER restart to update — just push_screen again
|
|
166
|
+
- Push HTML fragments, not full <html> documents
|
|
167
|
+
- Tell user the browser is ready after pushing
|
|
168
|
+
- Give user time before reading events
|
|
169
|
+
- Always stop_session when done`,
|
|
130
170
|
inputSchema: {
|
|
131
171
|
type: 'object',
|
|
132
172
|
properties: {
|
|
133
|
-
project_dir: { type: 'string', description: 'Project directory for session storage' },
|
|
134
|
-
port: { type: 'number', description: 'Port to bind to (default: random)' },
|
|
135
|
-
open_browser: { type: 'boolean', description: '
|
|
173
|
+
project_dir: { type: 'string', description: 'Project directory for session storage. Optional — defaults to /tmp/brainstorm-companion/. Pass cwd for project-local storage.' },
|
|
174
|
+
port: { type: 'number', description: 'Port to bind to (default: random ephemeral)' },
|
|
175
|
+
open_browser: { type: 'boolean', description: 'Open browser automatically (default: true)' },
|
|
176
|
+
idle_timeout_minutes: { type: 'number', description: 'Auto-stop after N minutes idle (default: 0 = no timeout)' }
|
|
136
177
|
}
|
|
137
178
|
}
|
|
138
179
|
},
|
|
139
180
|
{
|
|
140
181
|
name: 'brainstorm_push_screen',
|
|
141
|
-
description:
|
|
182
|
+
description: `Push HTML content to the brainstorm browser window. The browser auto-reloads instantly — call repeatedly to update content without restarting the session.
|
|
183
|
+
|
|
184
|
+
SINGLE SCREEN: Pass html only. Previous content is replaced.
|
|
185
|
+
COMPARISON MODE: Pass html + slot (a/b/c) + label. Browser shows tabs, side-by-side view, and preference buttons.
|
|
186
|
+
|
|
187
|
+
Push HTML fragments (not full <html> documents). The frame template adds theming, fonts, and scroll handling.
|
|
188
|
+
|
|
189
|
+
Built-in CSS classes: .options/.option (selectable cards), .cards/.card (grid), .mockup (browser frame), .split (two-column), .pros-cons (tradeoffs).
|
|
190
|
+
Interactive: Add data-choice="value" onclick="toggleSelect(this)" to capture clicks as events.
|
|
191
|
+
Auto-detected: class="mermaid" (diagrams), class="language-*" (syntax highlighting), $$...$$ (math).`,
|
|
142
192
|
inputSchema: {
|
|
143
193
|
type: 'object',
|
|
144
194
|
properties: {
|
|
145
|
-
html: { type: 'string', description: 'HTML
|
|
146
|
-
slot: { type: 'string', description: 'Slot for comparison mode: a, b, or c' },
|
|
147
|
-
label: { type: 'string', description: '
|
|
195
|
+
html: { type: 'string', description: 'HTML fragment to display (not a full document — the frame template wraps it)' },
|
|
196
|
+
slot: { type: 'string', description: 'Slot for comparison mode: a, b, or c. When used, browser shows tabbed comparison view.' },
|
|
197
|
+
label: { type: 'string', description: 'Display label for the slot tab (e.g., "Option A", "Minimal", "Dark Theme")' }
|
|
148
198
|
},
|
|
149
199
|
required: ['html']
|
|
150
200
|
}
|
|
151
201
|
},
|
|
152
202
|
{
|
|
153
203
|
name: 'brainstorm_read_events',
|
|
154
|
-
description:
|
|
204
|
+
description: `Read user interaction events from the brainstorm browser. Returns { events: [...], count: N }.
|
|
205
|
+
|
|
206
|
+
Event types: click (data-choice element clicked — fields: choice, text, id), preference (slot comparison pick — fields: choice), tab-switch (tab changed — fields: slot), view-change (view toggled — fields: mode). All events include timestamp.
|
|
207
|
+
|
|
208
|
+
Use clear_after_read: true between brainstorming rounds to avoid reading stale events from the previous round.
|
|
209
|
+
Give the user time to interact before reading — don't read immediately after pushing content.`,
|
|
155
210
|
inputSchema: {
|
|
156
211
|
type: 'object',
|
|
157
212
|
properties: {
|
|
158
|
-
clear_after_read: { type: 'boolean', description: 'Clear events after reading (default: false)' }
|
|
213
|
+
clear_after_read: { type: 'boolean', description: 'Clear events after reading to avoid stale data in next round (default: false)' }
|
|
159
214
|
}
|
|
160
215
|
}
|
|
161
216
|
},
|
|
162
217
|
{
|
|
163
218
|
name: 'brainstorm_clear_screen',
|
|
164
|
-
description: 'Clear content from the brainstorm browser
|
|
219
|
+
description: 'Clear content from the brainstorm browser. Pass slot to clear a specific comparison slot, or omit to clear all content (all slots and screens). Useful between multi-round brainstorming to reset the view before pushing new content.',
|
|
165
220
|
inputSchema: {
|
|
166
221
|
type: 'object',
|
|
167
222
|
properties: {
|
|
168
|
-
slot: { type: 'string', description: 'Clear specific slot (a, b, or c). Omit to clear all.' }
|
|
223
|
+
slot: { type: 'string', description: 'Clear specific slot (a, b, or c). Omit to clear all content.' }
|
|
169
224
|
}
|
|
170
225
|
}
|
|
171
226
|
},
|
|
172
227
|
{
|
|
173
228
|
name: 'brainstorm_stop_session',
|
|
174
|
-
description: 'Stop the brainstorm companion server and clean up.',
|
|
229
|
+
description: 'Stop the brainstorm companion server and clean up all session files. Always call this when done brainstorming to free the port and remove temp files. Safe to call multiple times.',
|
|
175
230
|
inputSchema: { type: 'object', properties: {} }
|
|
176
231
|
}
|
|
177
232
|
];
|
|
@@ -187,7 +242,7 @@ class McpServer {
|
|
|
187
242
|
return { url: this.serverInstance.url, session_dir: this.sessionDir };
|
|
188
243
|
}
|
|
189
244
|
|
|
190
|
-
const { project_dir, port = 0, open_browser = true } = args;
|
|
245
|
+
const { project_dir, port = 0, open_browser = true, idle_timeout_minutes = 0 } = args;
|
|
191
246
|
|
|
192
247
|
// Determine base directory and create session dir
|
|
193
248
|
const baseDir = project_dir
|
|
@@ -203,6 +258,7 @@ class McpServer {
|
|
|
203
258
|
host: '127.0.0.1',
|
|
204
259
|
port: port || 0,
|
|
205
260
|
ownerPid: process.pid,
|
|
261
|
+
idleTimeoutMs: idle_timeout_minutes > 0 ? idle_timeout_minutes * 60 * 1000 : 0,
|
|
206
262
|
logFn: (...a) => console.error(...a),
|
|
207
263
|
});
|
|
208
264
|
|
package/src/server.js
CHANGED
|
@@ -11,7 +11,10 @@ const { detectLibraries, buildInjections } = require('./content-detect');
|
|
|
11
11
|
// Constants
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Idle timeout is DISABLED by default (0 = no timeout). Sessions stay alive
|
|
15
|
+
// until explicitly stopped via `stop` / `brainstorm_stop_session`, or the
|
|
16
|
+
// owner process exits. Pass a positive `idleTimeoutMs` to override.
|
|
17
|
+
const DEFAULT_IDLE_TIMEOUT_MS = 0;
|
|
15
18
|
const OWNER_CHECK_INTERVAL_MS = 60 * 1000; // 60 seconds
|
|
16
19
|
|
|
17
20
|
const MIME_TYPES = {
|
|
@@ -110,6 +113,7 @@ function startServer(config = {}) {
|
|
|
110
113
|
host = '127.0.0.1',
|
|
111
114
|
port: requestedPort = 0,
|
|
112
115
|
ownerPid = null,
|
|
116
|
+
idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS,
|
|
113
117
|
logFn = console.log,
|
|
114
118
|
} = config;
|
|
115
119
|
|
|
@@ -141,9 +145,11 @@ function startServer(config = {}) {
|
|
|
141
145
|
|
|
142
146
|
function resetIdleTimer() {
|
|
143
147
|
if (idleTimer) clearTimeout(idleTimer);
|
|
148
|
+
// 0 or falsy = no idle timeout — session stays alive until explicitly stopped
|
|
149
|
+
if (!idleTimeoutMs) return;
|
|
144
150
|
idleTimer = setTimeout(() => {
|
|
145
151
|
shutdown('idle-timeout');
|
|
146
|
-
},
|
|
152
|
+
}, idleTimeoutMs);
|
|
147
153
|
// Don't block the event loop
|
|
148
154
|
if (idleTimer.unref) idleTimer.unref();
|
|
149
155
|
}
|
|
@@ -614,6 +620,7 @@ if (require.main === module) {
|
|
|
614
620
|
screenDir,
|
|
615
621
|
host: process.env.BRAINSTORM_HOST || '127.0.0.1',
|
|
616
622
|
port: process.env.BRAINSTORM_PORT ? parseInt(process.env.BRAINSTORM_PORT, 10) : 0,
|
|
623
|
+
idleTimeoutMs: process.env.BRAINSTORM_IDLE_TIMEOUT ? parseInt(process.env.BRAINSTORM_IDLE_TIMEOUT, 10) : 0,
|
|
617
624
|
});
|
|
618
625
|
instance.server.on('listening', () => {
|
|
619
626
|
console.log(JSON.stringify({ type: 'server-ready', url: instance.url }));
|