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 +1 -1
- package/skill/SKILL.md +353 -37
- package/src/cli.js +20 -5
- package/src/server.js +3 -3
package/package.json
CHANGED
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
|
-
|
|
17
|
+
**Don't use** for plain text output, simple data, or anything that works fine in the terminal.
|
|
17
18
|
|
|
18
|
-
|
|
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
|
-
|
|
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>
|
|
29
|
-
<p class="subtitle">
|
|
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">
|
|
163
|
+
<div class="mockup-header">iPhone 15 Pro — 393px</div>
|
|
32
164
|
<div class="mockup-body">
|
|
33
|
-
|
|
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
|
-
###
|
|
39
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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 --
|
|
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
|
}
|