brainstorm-companion 1.1.2 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainstorm-companion",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "AI-assisted visual brainstorming companion",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
package/skill/SKILL.md CHANGED
@@ -12,60 +12,376 @@ Use this tool when you need to:
12
12
  - Compare multiple design alternatives side-by-side (A/B/C comparison)
13
13
  - Present architecture diagrams (Mermaid), code samples (Prism), or math (KaTeX)
14
14
  - Get visual feedback — user clicks and preferences are captured as events
15
+ - Show interactive prototypes or wireframes
15
16
 
16
- ## Quick Start
17
+ **Don't use** for plain text output, simple data, or anything that works fine in the terminal.
17
18
 
18
- 1. Call `brainstorm_start_session` to start the server and open the browser
19
- 2. Call `brainstorm_push_screen` with HTML content to display
20
- 3. For comparisons, use the `slot` parameter (a, b, c) with labels
21
- 4. Call `brainstorm_read_events` to get user interactions
22
- 5. Call `brainstorm_stop_session` when done
19
+ ## MCP Tools Reference
23
20
 
24
- ## HTML Content Patterns
21
+ ### brainstorm_start_session
22
+
23
+ Start the server and open a browser window.
24
+
25
+ ```
26
+ brainstorm_start_session({
27
+ project_dir: "/path/to/project", // ALWAYS pass this — use the current working directory
28
+ open_browser: true, // default: true
29
+ port: 0 // default: random
30
+ })
31
+ → { url: "http://127.0.0.1:54321", session_dir: "..." }
32
+ ```
33
+
34
+ **Always pass `project_dir`** — this keeps session files with the project and avoids conflicts between agents. Without it, all sessions go to `/tmp/brainstorm-companion/` and may collide.
35
+
36
+ The server runs independently in the background with a 30-minute idle timeout. It survives the calling process exiting.
37
+
38
+ ### brainstorm_push_screen
39
+
40
+ Push HTML content to the browser. The browser auto-reloads — no manual refresh needed.
41
+
42
+ **Single screen mode:**
43
+ ```
44
+ brainstorm_push_screen({
45
+ html: "<h2>Dashboard Layout</h2><p>Content here...</p>"
46
+ })
47
+ → { path: "...", slot: null, label: null }
48
+ ```
49
+
50
+ **Comparison mode (slots a, b, c):**
51
+ ```
52
+ brainstorm_push_screen({ html: "<h2>Option A</h2>...", slot: "a", label: "Minimal" })
53
+ brainstorm_push_screen({ html: "<h2>Option B</h2>...", slot: "b", label: "Sidebar" })
54
+ brainstorm_push_screen({ html: "<h2>Option C</h2>...", slot: "c", label: "Hybrid" })
55
+ → Browser shows all three side-by-side with tabs and preference buttons
56
+ ```
57
+
58
+ When slots are used, the browser switches to comparison mode with:
59
+ - Tab bar for switching between options
60
+ - Side-by-side view (toggle to single view with Tab key)
61
+ - Preference buttons for picking a favorite
62
+ - Keyboard shortcuts: 1/2/3 or a/b/c to switch, Tab to toggle view
63
+
64
+ ### brainstorm_read_events
65
+
66
+ Read user interaction events (clicks, preferences).
67
+
68
+ ```
69
+ brainstorm_read_events({ clear_after_read: false })
70
+ → { events: [...], count: N }
71
+ ```
72
+
73
+ Set `clear_after_read: true` between brainstorming rounds to avoid stale events.
74
+
75
+ ### brainstorm_clear_screen
76
+
77
+ Clear content from the browser.
78
+
79
+ ```
80
+ brainstorm_clear_screen({}) // Clear all content
81
+ brainstorm_clear_screen({ slot: "a" }) // Clear just slot A
82
+ ```
83
+
84
+ ### brainstorm_stop_session
85
+
86
+ Stop the server and clean up session files.
87
+
88
+ ```
89
+ brainstorm_stop_session({})
90
+ → { stopped: true }
91
+ ```
92
+
93
+ Always call this when done brainstorming to free the port and clean up files.
94
+
95
+ ## HTML Content — What to Push
96
+
97
+ 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.
98
+
99
+ ### Selectable Options (A/B/C choices)
25
100
 
26
- ### Single Option Display
27
101
  ```html
28
- <h2>Dashboard Layout</h2>
29
- <p class="subtitle">Proposed navigation structure</p>
102
+ <h2>Choose a Layout</h2>
103
+ <p class="subtitle">Select the dashboard structure</p>
104
+ <div class="options">
105
+ <div class="option" data-choice="grid" onclick="toggleSelect(this)">
106
+ <div class="letter">A</div>
107
+ <div class="content">
108
+ <h3>Grid Layout</h3>
109
+ <p>Cards in a responsive grid, best for dashboards</p>
110
+ </div>
111
+ </div>
112
+ <div class="option" data-choice="list" onclick="toggleSelect(this)">
113
+ <div class="letter">B</div>
114
+ <div class="content">
115
+ <h3>List Layout</h3>
116
+ <p>Vertical scrolling list, best for feeds</p>
117
+ </div>
118
+ </div>
119
+ <div class="option" data-choice="table" onclick="toggleSelect(this)">
120
+ <div class="letter">C</div>
121
+ <div class="content">
122
+ <h3>Table Layout</h3>
123
+ <p>Dense data table, best for admin panels</p>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ ```
128
+
129
+ **Key:** `data-choice="value"` + `onclick="toggleSelect(this)"` makes any element clickable and captures the selection as an event. The `.letter` div shows A/B/C badges.
130
+
131
+ For multi-select, add `data-multiselect` to the container:
132
+ ```html
133
+ <div class="options" data-multiselect>...</div>
134
+ ```
135
+
136
+ ### Card Grid
137
+
138
+ ```html
139
+ <h2>Feature Mockups</h2>
140
+ <div class="cards">
141
+ <div class="card" data-choice="dashboard" onclick="toggleSelect(this)">
142
+ <div class="card-image"><div class="placeholder">Dashboard Preview</div></div>
143
+ <div class="card-body">
144
+ <h3>Dashboard</h3>
145
+ <p>Analytics overview with charts</p>
146
+ </div>
147
+ </div>
148
+ <div class="card" data-choice="settings" onclick="toggleSelect(this)">
149
+ <div class="card-image"><div class="placeholder">Settings Preview</div></div>
150
+ <div class="card-body">
151
+ <h3>Settings</h3>
152
+ <p>User preferences panel</p>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ ```
157
+
158
+ ### Mockup Container
159
+
160
+ ```html
161
+ <h2>Mobile App — Home Screen</h2>
30
162
  <div class="mockup">
31
- <div class="mockup-header">Desktop View</div>
163
+ <div class="mockup-header">iPhone 15 Pro — 393px</div>
32
164
  <div class="mockup-body">
33
- <!-- Your mockup content -->
165
+ <div class="mock-nav">Home | Search | Profile</div>
166
+ <div class="mock-content">
167
+ <h3>Welcome back</h3>
168
+ <p>Your feed content here</p>
169
+ <div class="mock-button">Create Post</div>
170
+ </div>
34
171
  </div>
35
172
  </div>
36
173
  ```
37
174
 
38
- ### A/B/C Choice Options
39
- Push to separate slots for comparison mode:
175
+ ### Side-by-Side Comparison
176
+
177
+ ```html
178
+ <h2>Before / After</h2>
179
+ <div class="split">
180
+ <div>
181
+ <h3>Current</h3>
182
+ <div class="mockup">
183
+ <div class="mockup-body">Old design...</div>
184
+ </div>
185
+ </div>
186
+ <div>
187
+ <h3>Proposed</h3>
188
+ <div class="mockup">
189
+ <div class="mockup-body">New design...</div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ ```
194
+
195
+ ### Pros and Cons
196
+
197
+ ```html
198
+ <h2>Trade-off Analysis</h2>
199
+ <div class="pros-cons">
200
+ <div class="pros">
201
+ <h4>Pros</h4>
202
+ <ul>
203
+ <li>Faster development</li>
204
+ <li>Better mobile support</li>
205
+ </ul>
206
+ </div>
207
+ <div class="cons">
208
+ <h4>Cons</h4>
209
+ <ul>
210
+ <li>Larger bundle size</li>
211
+ <li>Learning curve</li>
212
+ </ul>
213
+ </div>
214
+ </div>
215
+ ```
216
+
217
+ ### Mermaid Diagrams
218
+
219
+ Wrap diagram syntax in `<div class="mermaid">`. CDN is injected automatically.
220
+
221
+ ```html
222
+ <h2>System Architecture</h2>
223
+ <div class="mermaid">
224
+ graph LR
225
+ Client[Browser] --> API[API Server]
226
+ API --> DB[(Database)]
227
+ API --> Cache[(Redis)]
228
+ API --> Queue[Job Queue]
229
+ Queue --> Workers[Background Workers]
230
+ </div>
231
+ ```
232
+
233
+ Supported: flowchart, sequence, class, state, ER, Gantt, pie.
234
+
235
+ ```html
236
+ <h2>Auth Flow</h2>
237
+ <div class="mermaid">
238
+ sequenceDiagram
239
+ User->>Client: Submit login
240
+ Client->>API: POST /auth/login
241
+ API->>DB: Verify credentials
242
+ DB-->>API: User record
243
+ API-->>Client: JWT token
244
+ Client-->>User: Redirect to dashboard
245
+ </div>
246
+ ```
247
+
248
+ ### Syntax-Highlighted Code
249
+
250
+ Use `class="language-*"` on `<code>` elements. Prism.js CDN is injected automatically.
251
+
252
+ ```html
253
+ <h2>API Response Format</h2>
254
+ <pre><code class="language-typescript">
255
+ interface ApiResponse<T> {
256
+ data: T;
257
+ status: "success" | "error";
258
+ timestamp: number;
259
+ }
260
+ </code></pre>
40
261
  ```
41
- brainstorm_push_screen({ html: "<h2>Minimal Nav</h2>...", slot: "a", label: "Minimal" })
42
- brainstorm_push_screen({ html: "<h2>Full Sidebar</h2>...", slot: "b", label: "Sidebar" })
262
+
263
+ ### Math (KaTeX)
264
+
265
+ Use `$$...$$` for display math. KaTeX CDN is injected automatically.
266
+
267
+ ```html
268
+ <h2>Loss Function</h2>
269
+ <p>$$L = -\sum_{i} y_i \log(\hat{y}_i)$$</p>
43
270
  ```
44
271
 
45
- ### Available CSS Classes
272
+ ## CSS Classes Quick Reference
273
+
274
+ | Class | Purpose |
275
+ |-------|---------|
276
+ | `.options` | Vertical list container for `.option` elements |
277
+ | `.option` | Selectable option card (pair with `data-choice` + `onclick="toggleSelect(this)"`) |
278
+ | `.option .letter` | A/B/C badge inside an option |
279
+ | `.option .content` | Text content inside an option |
280
+ | `.cards` | Responsive grid container for `.card` elements |
281
+ | `.card` | Grid card with hover effect (pair with `data-choice` + `onclick`) |
282
+ | `.card-image` | Image/preview area at top of card |
283
+ | `.card-body` | Text area at bottom of card |
284
+ | `.mockup` | Browser-window-style container |
285
+ | `.mockup-header` | Title bar for mockup (shows viewport label) |
286
+ | `.mockup-body` | Content area inside mockup |
287
+ | `.split` | Two-column 50/50 side-by-side layout |
288
+ | `.pros-cons` | Two-column pros/cons grid |
289
+ | `.pros` | Green-tinted column (use with `<h4>Pros</h4>` + `<ul>`) |
290
+ | `.cons` | Red-tinted column (use with `<h4>Cons</h4>` + `<ul>`) |
291
+ | `.placeholder` | Dashed gray placeholder area |
292
+ | `.subtitle` | Muted text below headings |
293
+ | `.section` | Block with top margin spacing |
294
+ | `.label` | Small uppercase badge |
295
+ | `.mock-nav` | Horizontal nav bar mockup |
296
+ | `.mock-sidebar` | Sidebar column mockup |
297
+ | `.mock-content` | Main content area mockup |
298
+ | `.mock-button` | Styled button element |
299
+ | `.mock-input` | Styled input field |
300
+
301
+ ## Event Types
302
+
303
+ | Event | When | Key Fields |
304
+ |-------|------|-----------|
305
+ | `click` | User clicks a `[data-choice]` element | `choice`, `text`, `id` |
306
+ | `preference` | User picks a preferred slot in comparison mode | `choice` (slot id) |
307
+ | `tab-switch` | User switches tabs in comparison mode | `slot` |
308
+ | `view-change` | User toggles side-by-side vs single view | `mode` |
46
309
 
47
- **Layout:** `.options`, `.option`, `.cards`, `.card`, `.split`, `.mockup`, `.mockup-header`, `.mockup-body`
48
- **Interactive:** Add `data-choice="value"` and `onclick="toggleSelect(this)"` to make elements clickable
49
- **Styling:** `.pros-cons`, `.pros`, `.cons`, `.placeholder`, `.subtitle`, `.section`, `.label`
50
- **Mock UI:** `.mock-nav`, `.mock-sidebar`, `.mock-content`, `.mock-button`, `.mock-input`
310
+ All events include a `timestamp` field (Unix ms).
51
311
 
52
- ### Auto-detected Libraries
53
- Content is automatically enhanced when these patterns are found:
54
- - **Mermaid diagrams:** `<div class="mermaid">graph TD; A-->B</div>`
55
- - **Syntax highlighting:** `<pre><code class="language-typescript">...</code></pre>`
56
- - **Math (KaTeX):** `$$E = mc^2$$`
312
+ ## Workflow Patterns
57
313
 
58
- ## Event Format
314
+ ### Single Decision
59
315
 
60
- Events are JSON objects:
61
- ```json
62
- {"type": "click", "choice": "a", "text": "Option A", "timestamp": 1234567890}
63
- {"type": "preference", "choice": "b", "timestamp": 1234567890}
64
316
  ```
317
+ 1. brainstorm_start_session({ project_dir: "..." })
318
+ 2. brainstorm_push_screen({ html: "...options with data-choice..." })
319
+ 3. → Tell user to make their selection in the browser
320
+ 4. brainstorm_read_events({})
321
+ 5. → Use the choice to proceed
322
+ 6. brainstorm_stop_session({})
323
+ ```
324
+
325
+ ### A/B/C Comparison
326
+
327
+ ```
328
+ 1. brainstorm_start_session({ project_dir: "..." })
329
+ 2. brainstorm_push_screen({ html: "...", slot: "a", label: "Option A" })
330
+ 3. brainstorm_push_screen({ html: "...", slot: "b", label: "Option B" })
331
+ 4. → Tell user to compare and pick a preference
332
+ 5. brainstorm_read_events({})
333
+ 6. → Look for { type: "preference", choice: "a"|"b" }
334
+ 7. brainstorm_stop_session({})
335
+ ```
336
+
337
+ ### Multi-Round Brainstorming
338
+
339
+ ```
340
+ 1. brainstorm_start_session({ project_dir: "..." })
341
+
342
+ // Round 1: Layout
343
+ 2. brainstorm_push_screen({ html: "...", slot: "a", label: "Grid" })
344
+ 3. brainstorm_push_screen({ html: "...", slot: "b", label: "List" })
345
+ 4. brainstorm_read_events({ clear_after_read: true })
346
+ 5. → User chose "Grid"
347
+
348
+ // Round 2: Color scheme (clear old slots first)
349
+ 6. brainstorm_clear_screen({})
350
+ 7. brainstorm_push_screen({ html: "...", slot: "a", label: "Light" })
351
+ 8. brainstorm_push_screen({ html: "...", slot: "b", label: "Dark" })
352
+ 9. brainstorm_read_events({ clear_after_read: true })
353
+ 10. → User chose "Dark"
354
+
355
+ // Show final summary
356
+ 11. brainstorm_push_screen({ html: "<h2>Decisions: Grid + Dark</h2>..." })
357
+ 12. brainstorm_stop_session({})
358
+ ```
359
+
360
+ ### Progressive Refinement
361
+
362
+ ```
363
+ 1. brainstorm_start_session({ project_dir: "..." })
364
+
365
+ // Show initial mockup
366
+ 2. brainstorm_push_screen({ html: "...v1 mockup..." })
367
+ 3. → Get feedback from user (text in chat, not events)
368
+
369
+ // Push refined version — browser auto-reloads
370
+ 4. brainstorm_push_screen({ html: "...v2 mockup with changes..." })
371
+ 5. → Iterate until user is satisfied
372
+
373
+ 6. brainstorm_stop_session({})
374
+ ```
375
+
376
+ ## Best Practices
65
377
 
66
- ## Tips
67
- - Use the frame template's built-in dark/light theme it auto-detects OS preference
68
- - For mockups, use the `.mockup` container with `.mockup-header` for context
69
- - For comparisons, always use slots they enable side-by-side iframe comparison
70
- - Check events after giving the user time to interact
71
- - The browser auto-reloads when content changes
378
+ 1. **Always pass `project_dir`** to `brainstorm_start_session` — avoids cross-agent conflicts
379
+ 2. **Push fragments, not full documents** — the frame template handles `<html>`, theming, and scroll
380
+ 3. **Start with a heading** `<h2>` describes what the user is looking at
381
+ 4. **Add a `.subtitle`**describes the decision being made
382
+ 5. **One decision per screen** don't combine unrelated choices
383
+ 6. **Use slot labels** `label` makes comparison tabs readable
384
+ 7. **Use `data-choice` for interaction** — the built-in `toggleSelect` emits events automatically
385
+ 8. **Tell the user to interact** — after pushing content, let them know the browser is ready
386
+ 9. **Read events after user has time** — don't immediately read; wait for user to respond
387
+ 10. **Clean up with `brainstorm_stop_session`** — frees the port and removes temp files
package/src/cli.js CHANGED
@@ -42,7 +42,9 @@ Examples:
42
42
  start: `Usage: brainstorm-companion start [options]
43
43
 
44
44
  Start the brainstorm server and open a browser window.
45
- Each start creates a new isolated session with its own port and data directory.
45
+
46
+ If a session is already running for this project, it reuses it (prints the
47
+ existing URL). Use --new to force a separate session.
46
48
 
47
49
  Options:
48
50
  --project-dir <path> Session storage location (default: /tmp/brainstorm-companion/)
@@ -50,18 +52,16 @@ Options:
50
52
  --host <address> Bind address (default: 127.0.0.1)
51
53
  --foreground Run server in foreground (don't background)
52
54
  --no-open Don't auto-open browser
55
+ --new Force a new session even if one is already running
53
56
 
54
57
  Output:
55
58
  Server started: http://127.0.0.1:<port>
56
59
  Session ID: <id>
57
60
 
58
- Save the Session ID to target this instance with other commands when
59
- running multiple sessions in parallel.
60
-
61
61
  Examples:
62
62
  brainstorm-companion start
63
63
  brainstorm-companion start --project-dir ./my-project --no-open
64
- brainstorm-companion start --port 8080 --foreground`,
64
+ brainstorm-companion start --new # force separate parallel session`,
65
65
 
66
66
  push: `Usage: brainstorm-companion push [<file|->] [options]
67
67
 
@@ -231,6 +231,7 @@ async function start(argv) {
231
231
  'host': { type: 'string', default: '127.0.0.1' },
232
232
  'foreground': { type: 'boolean', default: false },
233
233
  'no-open': { type: 'boolean', default: false },
234
+ 'new': { type: 'boolean', default: false },
234
235
  },
235
236
  strict: false,
236
237
  });
@@ -240,8 +241,22 @@ async function start(argv) {
240
241
  const port = parseInt(values['port'], 10) || 0;
241
242
  const foreground = values['foreground'];
242
243
  const noOpen = values['no-open'];
244
+ const forceNew = values['new'];
243
245
 
244
246
  const session = new SessionManager(projectDir);
247
+
248
+ // Reuse existing active session unless --new is passed
249
+ const existing = !forceNew ? session.getActive() : null;
250
+ if (existing) {
251
+ const url = existing.serverInfo.url;
252
+ console.log(`Server already running: ${url}`);
253
+ console.log(`Session ID: ${existing.sessionId}`);
254
+ if (!noOpen) {
255
+ openBrowser(url);
256
+ }
257
+ return;
258
+ }
259
+
245
260
  const { sessionDir } = session.create();
246
261
 
247
262
  if (foreground) {
package/src/server.js CHANGED
@@ -208,7 +208,7 @@ function startServer(config = {}) {
208
208
  } else {
209
209
  html = html + comparisonHelperInjection;
210
210
  }
211
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
211
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' });
212
212
  res.end(html);
213
213
  } else {
214
214
  // Single screen mode
@@ -226,7 +226,7 @@ function startServer(config = {}) {
226
226
  html = html.replace('</head>', cdnTags + '\n</head>');
227
227
  }
228
228
  html = injectHelper(html);
229
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
229
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' });
230
230
  res.end(html);
231
231
  }
232
232
  return;
@@ -248,7 +248,7 @@ function startServer(config = {}) {
248
248
  html = html.replace('</head>', slotCdnTags + '\n</head>');
249
249
  }
250
250
  html = injectHelper(html);
251
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
251
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' });
252
252
  res.end(html);
253
253
  return;
254
254
  }