brainstorm-companion 2.0.1 → 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 +20 -22
- package/package.json +1 -1
- package/skill/SKILL.md +18 -19
- package/skill/visual-companion.md +5 -5
- package/src/cli.js +15 -0
- package/src/mcp.js +7 -2
- package/src/session.js +7 -2
package/README.md
CHANGED
|
@@ -68,10 +68,9 @@ brainstorm-companion stop
|
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
**Key behaviors:**
|
|
71
|
-
- `start` with no args works immediately
|
|
71
|
+
- `start` with no args works immediately — auto-isolates by working directory
|
|
72
72
|
- `start` reuses an existing session — never opens duplicate browsers
|
|
73
73
|
- `push` auto-reloads the browser every time — no restart or refresh needed
|
|
74
|
-
- Add `--project-dir .` for project-local storage
|
|
75
74
|
|
|
76
75
|
### Quick Start (MCP / Agent) — 3 calls, zero config
|
|
77
76
|
|
|
@@ -90,7 +89,7 @@ brainstorm-companion stop
|
|
|
90
89
|
5. brainstorm_stop_session({})
|
|
91
90
|
```
|
|
92
91
|
|
|
93
|
-
**No arguments required.**
|
|
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.
|
|
94
93
|
|
|
95
94
|
---
|
|
96
95
|
|
|
@@ -231,7 +230,7 @@ graph TD
|
|
|
231
230
|
|
|
232
231
|
| Tool | Description |
|
|
233
232
|
|------|-------------|
|
|
234
|
-
| `brainstorm_start_session` | Start server (or reuse existing). Returns URL.
|
|
233
|
+
| `brainstorm_start_session` | Start server (or reuse existing). No args needed. Returns URL. |
|
|
235
234
|
| `brainstorm_push_screen` | Push HTML content. Browser auto-reloads. Use `slot` + `label` for comparison. |
|
|
236
235
|
| `brainstorm_read_events` | Read user interaction events. Option to clear after reading. |
|
|
237
236
|
| `brainstorm_clear_screen` | Clear a specific slot or all content. |
|
|
@@ -244,7 +243,7 @@ graph TD
|
|
|
244
243
|
### Single Decision
|
|
245
244
|
|
|
246
245
|
```
|
|
247
|
-
1. brainstorm_start_session(
|
|
246
|
+
1. brainstorm_start_session()
|
|
248
247
|
2. brainstorm_push_screen({ html: "...options with data-choice..." })
|
|
249
248
|
3. → Tell user to make their selection in the browser
|
|
250
249
|
4. brainstorm_read_events({})
|
|
@@ -255,7 +254,7 @@ graph TD
|
|
|
255
254
|
### A/B/C Comparison
|
|
256
255
|
|
|
257
256
|
```
|
|
258
|
-
1. brainstorm_start_session(
|
|
257
|
+
1. brainstorm_start_session()
|
|
259
258
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
260
259
|
3. brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
261
260
|
4. → Tell user to compare and pick a preference
|
|
@@ -267,7 +266,7 @@ graph TD
|
|
|
267
266
|
### Multi-Round Brainstorming
|
|
268
267
|
|
|
269
268
|
```
|
|
270
|
-
1. brainstorm_start_session(
|
|
269
|
+
1. brainstorm_start_session()
|
|
271
270
|
|
|
272
271
|
// Round 1: Layout
|
|
273
272
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Grid" })
|
|
@@ -290,7 +289,7 @@ graph TD
|
|
|
290
289
|
### Progressive Refinement
|
|
291
290
|
|
|
292
291
|
```
|
|
293
|
-
1. brainstorm_start_session(
|
|
292
|
+
1. brainstorm_start_session()
|
|
294
293
|
|
|
295
294
|
// Show initial mockup
|
|
296
295
|
2. brainstorm_push_screen({ html: "...v1 mockup..." })
|
|
@@ -383,26 +382,25 @@ Shows Session ID, URL, uptime, event count, and active slots.
|
|
|
383
382
|
|
|
384
383
|
## Best Practices
|
|
385
384
|
|
|
386
|
-
1. **
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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
|
|
398
397
|
|
|
399
398
|
## Common Mistakes
|
|
400
399
|
|
|
401
400
|
- **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
401
|
- **Pushing full HTML documents** — push fragments; the frame template adds theming and structure.
|
|
404
402
|
- **Reading events immediately after push** — give the user time to interact first.
|
|
405
|
-
- **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`.
|
|
406
404
|
|
|
407
405
|
## Author
|
|
408
406
|
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -53,7 +53,7 @@ brainstorm_start_session({
|
|
|
53
53
|
})
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
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.
|
|
57
57
|
|
|
58
58
|
**Calling it multiple times is safe** — returns the existing session. Just call `brainstorm_push_screen` to update content.
|
|
59
59
|
|
|
@@ -344,7 +344,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
344
344
|
### Single Decision
|
|
345
345
|
|
|
346
346
|
```
|
|
347
|
-
1. brainstorm_start_session(
|
|
347
|
+
1. brainstorm_start_session()
|
|
348
348
|
2. brainstorm_push_screen({ html: "...options with data-choice..." })
|
|
349
349
|
3. → Tell user to make their selection in the browser
|
|
350
350
|
4. brainstorm_read_events({})
|
|
@@ -355,7 +355,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
355
355
|
### A/B/C Comparison
|
|
356
356
|
|
|
357
357
|
```
|
|
358
|
-
1. brainstorm_start_session(
|
|
358
|
+
1. brainstorm_start_session()
|
|
359
359
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
|
|
360
360
|
3. brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
|
|
361
361
|
4. → Tell user to compare and pick a preference
|
|
@@ -367,7 +367,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
367
367
|
### Multi-Round Brainstorming
|
|
368
368
|
|
|
369
369
|
```
|
|
370
|
-
1. brainstorm_start_session(
|
|
370
|
+
1. brainstorm_start_session()
|
|
371
371
|
|
|
372
372
|
// Round 1: Layout
|
|
373
373
|
2. brainstorm_push_screen({ html: "...", slot: "a", label: "Grid" })
|
|
@@ -390,7 +390,7 @@ All events include a `timestamp` field (Unix ms).
|
|
|
390
390
|
### Progressive Refinement
|
|
391
391
|
|
|
392
392
|
```
|
|
393
|
-
1. brainstorm_start_session(
|
|
393
|
+
1. brainstorm_start_session()
|
|
394
394
|
|
|
395
395
|
// Show initial mockup
|
|
396
396
|
2. brainstorm_push_screen({ html: "...v1 mockup..." })
|
|
@@ -407,23 +407,22 @@ All events include a `timestamp` field (Unix ms).
|
|
|
407
407
|
|
|
408
408
|
## Best Practices
|
|
409
409
|
|
|
410
|
-
1. **
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
|
422
422
|
|
|
423
423
|
## Common Mistakes
|
|
424
424
|
|
|
425
425
|
- **Starting a new session for each update** — DON'T. Call `push_screen` to update the existing browser.
|
|
426
|
-
- **Omitting `project_dir`** — leads to `/tmp` collisions between agents.
|
|
427
426
|
- **Pushing full HTML documents** — push fragments; the frame template adds theming and structure.
|
|
428
427
|
- **Reading events immediately after push** — give the user time to interact first.
|
|
429
|
-
- **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
|
@@ -185,6 +185,18 @@ function printHelp(command) {
|
|
|
185
185
|
// Helpers
|
|
186
186
|
// ---------------------------------------------------------------------------
|
|
187
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
|
+
|
|
188
200
|
function sleep(ms) {
|
|
189
201
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
190
202
|
}
|
|
@@ -272,6 +284,7 @@ async function start(argv) {
|
|
|
272
284
|
const url = existing.serverInfo.url;
|
|
273
285
|
console.log(`Server already running: ${url}`);
|
|
274
286
|
console.log(`Session ID: ${existing.sessionId}`);
|
|
287
|
+
printNextSteps();
|
|
275
288
|
if (!noOpen) {
|
|
276
289
|
openBrowser(url);
|
|
277
290
|
}
|
|
@@ -294,6 +307,7 @@ async function start(argv) {
|
|
|
294
307
|
instance.server.once('listening', () => {
|
|
295
308
|
console.log(`Server started: ${instance.url}`);
|
|
296
309
|
console.log(`Session ID: ${path.basename(sessionDir)}`);
|
|
310
|
+
printNextSteps();
|
|
297
311
|
if (!noOpen) {
|
|
298
312
|
openBrowser(instance.url);
|
|
299
313
|
}
|
|
@@ -338,6 +352,7 @@ async function start(argv) {
|
|
|
338
352
|
|
|
339
353
|
console.log(`Server started: ${serverInfo.url}`);
|
|
340
354
|
console.log(`Session ID: ${path.basename(sessionDir)}`);
|
|
355
|
+
printNextSteps();
|
|
341
356
|
|
|
342
357
|
if (!noOpen) {
|
|
343
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
|
|
@@ -170,7 +175,7 @@ RULES:
|
|
|
170
175
|
inputSchema: {
|
|
171
176
|
type: 'object',
|
|
172
177
|
properties: {
|
|
173
|
-
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.' },
|
|
174
179
|
port: { type: 'number', description: 'Port to bind to (default: random ephemeral)' },
|
|
175
180
|
open_browser: { type: 'boolean', description: 'Open browser automatically (default: true)' },
|
|
176
181
|
idle_timeout_minutes: { type: 'number', description: 'Auto-stop after N minutes idle (default: 0 = no timeout)' }
|
|
@@ -247,7 +252,7 @@ Give the user time to interact before reading — don't read immediately after p
|
|
|
247
252
|
// Determine base directory and create session dir
|
|
248
253
|
const baseDir = project_dir
|
|
249
254
|
? path.join(project_dir, '.superpowers', 'brainstorm')
|
|
250
|
-
: '/tmp
|
|
255
|
+
: path.join('/tmp', 'brainstorm-companion', cwdHash());
|
|
251
256
|
const sessionId = `${process.pid}-${Date.now()}`;
|
|
252
257
|
const sessionDir = path.join(baseDir, sessionId);
|
|
253
258
|
fs.mkdirSync(sessionDir, { recursive: true });
|
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
|
|