mindsystem-cc 3.10.1 → 3.12.0

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.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/agents/ms-designer.md +8 -8
  3. package/agents/ms-executor.md +14 -163
  4. package/agents/ms-plan-checker.md +2 -3
  5. package/agents/ms-plan-writer.md +6 -21
  6. package/agents/ms-roadmapper.md +1 -18
  7. package/agents/ms-verify-fixer.md +1 -1
  8. package/commands/ms/design-phase.md +9 -14
  9. package/commands/ms/execute-phase.md +0 -9
  10. package/commands/ms/help.md +1 -8
  11. package/commands/ms/new-project.md +3 -40
  12. package/commands/ms/review-design.md +4 -7
  13. package/commands/ms/verify-work.md +1 -1
  14. package/mindsystem/references/design-directions.md +1 -1
  15. package/mindsystem/references/mock-patterns.md +48 -0
  16. package/mindsystem/references/plan-format.md +2 -129
  17. package/mindsystem/references/scope-estimation.md +3 -36
  18. package/mindsystem/templates/config.json +0 -13
  19. package/mindsystem/templates/design.md +1 -1
  20. package/mindsystem/templates/phase-prompt.md +6 -142
  21. package/mindsystem/templates/roadmap.md +1 -1
  22. package/mindsystem/templates/summary.md +24 -0
  23. package/mindsystem/workflows/execute-phase.md +4 -99
  24. package/mindsystem/workflows/execute-plan.md +12 -523
  25. package/mindsystem/workflows/generate-mocks.md +74 -0
  26. package/mindsystem/workflows/mockup-generation.md +11 -5
  27. package/mindsystem/workflows/plan-phase.md +15 -60
  28. package/mindsystem/workflows/transition.md +1 -10
  29. package/mindsystem/workflows/verify-work.md +97 -17
  30. package/package.json +1 -1
  31. package/scripts/__pycache__/compare_mockups.cpython-314.pyc +0 -0
  32. package/scripts/compare_mockups.py +219 -0
  33. package/mindsystem/references/checkpoint-detection.md +0 -50
  34. package/mindsystem/references/checkpoints.md +0 -788
@@ -75,7 +75,7 @@ Spawn 3 ms-mockup-designer agents IN PARALLEL, each receiving:
75
75
  - `<design_direction>` — One of the 3 derived directions (name, philosophy, concrete choices)
76
76
  - `<platform>` — `mobile` or `web`
77
77
  - `<feature_grounding>` — The screen/feature being mocked
78
- - `<existing_aesthetic>` — Colors/fonts from implement-ui or codebase (if exists)
78
+ - `<existing_aesthetic>` — Colors/fonts from project UI skill or codebase (if exists)
79
79
  - `<mockup_template>` — The HTML scaffold from the template file
80
80
  - Output path: `.planning/phases/{phase}-{slug}/mockups/variant-a.html` (b, c for others)
81
81
 
@@ -87,16 +87,22 @@ Task(prompt=assembled_context, subagent_type="ms-mockup-designer", description="
87
87
  </step>
88
88
 
89
89
  <step name="present_mockups">
90
- After all 3 agents return, display file paths:
90
+ After all 3 agents return, generate comparison page and open it:
91
+
92
+ ```bash
93
+ uv run ~/.claude/mindsystem/scripts/compare_mockups.py "${PHASE_DIR}/mockups"
94
+ open "${PHASE_DIR}/mockups/comparison.html"
95
+ ```
96
+
97
+ Display summary:
91
98
 
92
99
  ```markdown
93
- 3 mockup variants generated:
100
+ 3 mockup variants generated — comparison page opened in browser.
94
101
 
102
+ Individual variants for reference:
95
103
  - **A: {Direction A name}** — `.planning/phases/{phase}-{slug}/mockups/variant-a.html`
96
104
  - **B: {Direction B name}** — `.planning/phases/{phase}-{slug}/mockups/variant-b.html`
97
105
  - **C: {Direction C name}** — `.planning/phases/{phase}-{slug}/mockups/variant-c.html`
98
-
99
- Open these in your browser to compare.
100
106
  ```
101
107
 
102
108
  Use AskUserQuestion:
@@ -18,7 +18,7 @@ Decimal phases enable urgent work insertion without renumbering:
18
18
  1. .planning/ROADMAP.md
19
19
  2. .planning/PROJECT.md
20
20
 
21
- **Note:** Heavy references (phase-prompt.md, plan-format.md, scope-estimation.md, checkpoints.md, goal-backward.md, plan-risk-assessment.md) are loaded by the ms-plan-writer subagent, not main context. Lighter references (checkpoint-detection.md, tdd.md) are loaded on demand during task breakdown.
21
+ **Note:** Heavy references (phase-prompt.md, plan-format.md, scope-estimation.md, goal-backward.md, plan-risk-assessment.md) are loaded by the ms-plan-writer subagent, not main context. Lighter references (tdd.md) are loaded on demand during task breakdown.
22
22
  </required_reading>
23
23
 
24
24
  <purpose>
@@ -184,7 +184,6 @@ type: execute
184
184
  wave: 1 # Gap closures typically single wave
185
185
  depends_on: [] # Usually independent of each other
186
186
  files_modified: [...]
187
- autonomous: true
188
187
  gap_closure: true # Flag for tracking
189
188
  ---
190
189
  ```
@@ -450,9 +449,9 @@ For each potential task, ask:
450
449
  3. **Can this run independently?** (no dependencies = Wave 1 candidate)
451
450
 
452
451
  **Standard tasks need:**
453
- - **Type**: auto, checkpoint:human-verify, checkpoint:decision (human-action rarely needed)
452
+ - **Type**: auto
454
453
  - **Task name**: Clear, action-oriented
455
- - **Files**: Which files created/modified (for auto tasks)
454
+ - **Files**: Which files created/modified
456
455
  - **Action hint**: Brief implementation guidance
457
456
  - **Verify hint**: How to prove it worked
458
457
  - **Done hint**: Acceptance criteria
@@ -480,11 +479,9 @@ Standard tasks (remain in standard plans):
480
479
 
481
480
  Read `~/.claude/mindsystem/references/tdd.md` now for TDD criteria and plan structure.
482
481
 
483
- **Checkpoints:** Visual/functional verification checkpoint:human-verify. Implementation choices checkpoint:decision. Manual action (email, 2FA) checkpoint:human-action (rare).
482
+ **Decisions:** If you identify a task that requires choosing between approaches (which auth provider, which database, etc.), use AskUserQuestion to resolve it now. Don't defer decisions to execution. For purely technical choices where the user hasn't expressed preference, make the decision and document it in the plan's objective.
484
483
 
485
- **Critical:** If external resource has CLI/API (Vercel, Stripe, etc.), use type="auto" to automate. Only checkpoint for verification AFTER automation.
486
-
487
- Read `~/.claude/mindsystem/references/checkpoint-detection.md` now for detection rules.
484
+ **Critical:** If external resource has CLI/API (Vercel, Stripe, etc.), use type="auto" to automate.
488
485
 
489
486
  **User setup detection:** For tasks involving external services, identify human-required configuration:
490
487
 
@@ -497,57 +494,16 @@ External service indicators:
497
494
  Note external services for risk scoring.
498
495
 
499
496
  <output_format>
500
- **After task identification, produce structured task list for handoff:**
497
+ **Present a concise numbered task summary for the user:**
501
498
 
502
- ```xml
503
- <task_list>
504
- <task id="1">
505
- <name>Create User model</name>
506
- <type>auto</type>
507
- <needs>nothing</needs>
508
- <creates>src/models/user.ts</creates>
509
- <checkpoint>false</checkpoint>
510
- <tdd_candidate>false</tdd_candidate>
511
- <action_hint>Define User type with id, email, createdAt</action_hint>
512
- <verify_hint>tsc --noEmit passes</verify_hint>
513
- <done_hint>User type exportable</done_hint>
514
- </task>
515
- <task id="2">
516
- <name>Create login endpoint</name>
517
- <type>auto</type>
518
- <needs>src/models/user.ts</needs>
519
- <creates>src/app/api/auth/login/route.ts</creates>
520
- <checkpoint>false</checkpoint>
521
- <tdd_candidate>true</tdd_candidate>
522
- <action_hint>POST endpoint with bcrypt validation</action_hint>
523
- <verify_hint>curl returns 200 with valid credentials</verify_hint>
524
- <done_hint>Login works with valid credentials</done_hint>
525
- </task>
526
- <task id="3">
527
- <name>Verify login flow</name>
528
- <type>checkpoint:human-verify</type>
529
- <needs>src/app/api/auth/login/route.ts</needs>
530
- <creates>nothing</creates>
531
- <checkpoint>true</checkpoint>
532
- <tdd_candidate>false</tdd_candidate>
533
- <action_hint>N/A</action_hint>
534
- <verify_hint>User tests login manually</verify_hint>
535
- <done_hint>User approves login flow</done_hint>
536
- </task>
537
- </task_list>
538
- ```
499
+ ### Tasks Identified
500
+
501
+ 1. **Create User model** → `src/models/user.ts` (no dependencies)
502
+ 2. **Create login endpoint** → `src/app/api/auth/login/route.ts` (needs: Task 1) [TDD]
503
+
504
+ Format: numbered list with task name, key files, dependency hint, and `[TDD]` flag if applicable. No XML.
539
505
 
540
- Each task captures:
541
- - `id`: Sequential identifier
542
- - `name`: Action-oriented task name
543
- - `type`: auto, checkpoint:human-verify, checkpoint:decision, checkpoint:human-action
544
- - `needs`: Files/types this task requires (or "nothing")
545
- - `creates`: Files/types this task produces (or "nothing")
546
- - `checkpoint`: true if requires user interaction
547
- - `tdd_candidate`: true if should be TDD plan
548
- - `action_hint`: Brief implementation guidance (subagent expands)
549
- - `verify_hint`: How to verify completion
550
- - `done_hint`: Acceptance criteria
506
+ **Retain full task details internally.** For each task, maintain in your analysis: id, name, type, needs, creates, tdd_candidate, action_hint, verify_hint, done_hint. These are needed for the handoff step — they just don't need to be displayed.
551
507
  </output_format>
552
508
  </step>
553
509
 
@@ -562,7 +518,7 @@ Assemble handoff payload:
562
518
 
563
519
  ```xml
564
520
  <task_list>
565
- {tasks from break_into_tasks}
521
+ {Construct full task XML from your analysis. Each task needs: id, name, type, needs, creates, tdd_candidate, action_hint, verify_hint, done_hint. Use the same XML schema the plan-writer expects.}
566
522
  </task_list>
567
523
 
568
524
  <phase_context>
@@ -571,7 +527,6 @@ Assemble handoff payload:
571
527
  <phase_dir>.planning/phases/{PHASE}-{PHASE_NAME}</phase_dir>
572
528
  <phase_goal>{goal from ROADMAP}</phase_goal>
573
529
  <requirements>{REQ-IDs from ROADMAP}</requirements>
574
- <depth>{from config.json or "standard"}</depth>
575
530
  <subsystem_hint>{best-match subsystem from config.json}</subsystem_hint>
576
531
  </phase_context>
577
532
 
@@ -790,7 +745,7 @@ Tasks are instructions for Claude, not Jira tickets.
790
745
  - [ ] Tasks identified with needs/creates dependencies
791
746
  - [ ] Task list handed off to ms-plan-writer
792
747
  - [ ] PLAN file(s) created by subagent with XML structure
793
- - [ ] Each plan: depends_on, files_modified, autonomous in frontmatter
748
+ - [ ] Each plan: depends_on, files_modified in frontmatter
794
749
  - [ ] Each plan: must_haves derived (truths, artifacts, key_links)
795
750
  - [ ] Each plan: 2-3 tasks (~50% context)
796
751
  - [ ] Wave structure maximizes parallelism
@@ -50,14 +50,6 @@ ls .planning/phases/XX-current/*-SUMMARY.md 2>/dev/null | sort
50
50
  - If counts match: all plans complete
51
51
  - If counts don't match: incomplete
52
52
 
53
- <config-check>
54
-
55
- ```bash
56
- cat .planning/config.json 2>/dev/null
57
- ```
58
-
59
- </config-check>
60
-
61
53
  **If all plans complete:**
62
54
 
63
55
  ```
@@ -71,8 +63,7 @@ Proceed directly to cleanup_handoff step.
71
63
 
72
64
  **If plans incomplete:**
73
65
 
74
- **SAFETY RAIL: always_confirm_destructive applies here.**
75
- Skipping incomplete plans is destructive — ALWAYS prompt regardless of mode.
66
+ **SAFETY RAIL: Skipping incomplete plans is destructive — always confirm.**
76
67
 
77
68
  Present:
78
69
 
@@ -139,25 +139,63 @@ Skip internal/non-observable items (refactors, type changes, etc.).
139
139
  </step>
140
140
 
141
141
  <step name="classify_tests">
142
- **Classify all tests by mock requirements:**
142
+ **Classify all tests by mock requirements using two-tier analysis:**
143
143
 
144
- For each test, analyze the expected behavior to determine:
144
+ For each test, determine:
145
145
  1. **mock_required**: Does this need special backend state?
146
- 2. **mock_type**: Freeform string describing needed state (e.g., "error_state", "premium_user", "empty_response")
146
+ 2. **mock_type**: Classification (e.g., "transient_state", "external_data", "error_state", "premium_user", "empty_response")
147
147
  3. **dependencies**: Other tests this depends on (infer from descriptions)
148
148
 
149
- **Classification heuristics:**
149
+ **Tier 1: SUMMARY.md mock_hints (primary)**
150
+
151
+ Check if SUMMARY.md files contain mock_hints frontmatter:
152
+ ```bash
153
+ grep -l "mock_hints:" "$PHASE_DIR"/*-SUMMARY.md 2>/dev/null
154
+ ```
155
+
156
+ If found, check the value:
157
+
158
+ - **`mock_hints: none`** → Short-circuit: all tests start as `mock_required: false`. Apply keyword heuristics only as safety net (scan test descriptions for obvious mock signals like "error", "loading", "empty").
159
+
160
+ - **`mock_hints` with content** → Parse and match tests against hints:
161
+ - Test relates to a `transient_states` entry → `mock_type: "transient_state"`, `mock_reason: "[from hint]"`
162
+ - Test relates to an `external_data` entry → `mock_type: "external_data"`, `needs_user_confirmation: true`
163
+ - Test doesn't match any hint → apply keyword heuristics below
164
+
165
+ **Tier 2: Inline classification (fallback for legacy summaries)**
166
+
167
+ When no `mock_hints` key found in any SUMMARY.md (legacy summaries written before executor populated this field):
168
+
169
+ Classify in main context using the two-question framework:
170
+
171
+ 1. **Is the observable state transient?** — Does it appear briefly during async operations? (loading skeleton, spinner, transition animation). If YES → `mock_type: "transient_state"`
172
+
173
+ 2. **Does the test depend on external data?** — Does the feature fetch from an API, database, or external service? Would the test fail without specific data existing? If YES → `mock_type: "external_data"`, `needs_user_confirmation: true`
174
+
175
+ Reason over SUMMARY.md content (accomplishments, files created/modified, decisions) to answer these questions. Supplement with keyword heuristics:
150
176
 
151
177
  | Expected behavior contains | Likely mock_type |
152
178
  |---------------------------|------------------|
153
- | "error", "fails", "invalid" | error_state |
179
+ | "error", "fails", "invalid", "retry" | error_state |
154
180
  | "premium", "pro", "paid", "subscription" | premium_user |
155
181
  | "empty", "no results", "placeholder" | empty_response |
156
- | "loading", "spinner", "skeleton" | loading_state |
182
+ | "loading", "spinner", "skeleton" | transient_state |
157
183
  | "offline", "no connection" | offline_state |
158
184
  | Normal happy path | no mock needed |
159
185
 
160
- **Dependency inference:**
186
+ For tests that remain genuinely uncertain after both the two-question framework and keyword heuristics, present them via AskUserQuestion grouped by uncertainty:
187
+ ```
188
+ questions:
189
+ - question: "Does [test name] require mock data or a special app state to test?"
190
+ header: "Mock needed?"
191
+ options:
192
+ - label: "No mock needed"
193
+ description: "Can test with real/local data"
194
+ - label: "Needs mock"
195
+ description: "Requires simulated state or data"
196
+ ```
197
+
198
+ **Dependency inference (both tiers):**
161
199
  - "Reply to comment" depends on "View comments"
162
200
  - "Delete account" depends on "Login"
163
201
  - Tests mentioning prior state depend on tests that create that state
@@ -173,12 +211,21 @@ tests:
173
211
  - name: "Login error message"
174
212
  mock_required: true
175
213
  mock_type: "error_state"
214
+ mock_reason: "error response from auth endpoint"
176
215
  dependencies: ["login_flow"]
177
216
 
178
- - name: "Premium badge display"
217
+ - name: "Recipe list loading skeleton"
179
218
  mock_required: true
180
- mock_type: "premium_user"
181
- dependencies: ["login_flow"]
219
+ mock_type: "transient_state"
220
+ mock_reason: "loading skeleton during recipe fetch — async, resolves in <1s"
221
+ dependencies: []
222
+
223
+ - name: "View recipe list"
224
+ mock_required: true
225
+ mock_type: "external_data"
226
+ mock_reason: "recipe items from /api/recipes"
227
+ needs_user_confirmation: true
228
+ dependencies: []
182
229
  ```
183
230
  </step>
184
231
 
@@ -189,10 +236,33 @@ tests:
189
236
 
190
237
  **Rules:**
191
238
  1. Group by mock_type (tests needing same mock state go together)
192
- 2. Respect dependencies (if B depends on A, A must be in same or earlier batch)
193
- 3. Max 4 tests per batch (AskUserQuestion limit)
194
- 4. No-mock tests first (run before any mock setup)
195
- 5. Order mock states logically: success → error → empty → loading
239
+ 2. **User confirmation for external_data tests:** Before batching, collect all tests with `needs_user_confirmation: true`, grouped by data source. Present via AskUserQuestion:
240
+
241
+ ```
242
+ questions:
243
+ - question: "Do you have [data_type] data from [source] locally?"
244
+ header: "[data_type]"
245
+ options:
246
+ - label: "Yes, data exists"
247
+ description: "I have [data_type] in my local environment"
248
+ - label: "No, needs mock"
249
+ description: "I need this data mocked for testing"
250
+ - label: "Skip these tests"
251
+ description: "Log as assumptions and move on"
252
+ multiSelect: false
253
+ ```
254
+
255
+ Handle responses:
256
+ - "Yes, data exists" → reclassify affected tests as `mock_required: false`
257
+ - "No, needs mock" → keep as `mock_required: true`, `mock_type: "external_data"`
258
+ - "Skip these tests" → mark all affected tests as `skipped`
259
+
260
+ Group by data source (not per-test) to stay within AskUserQuestion's 4-question limit.
261
+
262
+ 3. **Separate transient_state batch:** Transient states use a different mock strategy (delay/force) than data mocks. Give them their own batch.
263
+ 4. Respect dependencies (if B depends on A, A must be in same or earlier batch)
264
+ 5. Max 4 tests per batch (AskUserQuestion limit)
265
+ 6. Batch ordering: no-mock → external_data → error_state → empty_response → transient_state → premium_user → offline_state
196
266
 
197
267
  **Batch structure:**
198
268
  ```yaml
@@ -203,14 +273,24 @@ batches:
203
273
  tests: [1, 2, 3]
204
274
 
205
275
  - batch: 2
276
+ name: "External Data"
277
+ mock_type: "external_data"
278
+ tests: [4, 5]
279
+
280
+ - batch: 3
206
281
  name: "Error States"
207
282
  mock_type: "error_state"
208
- tests: [4, 5, 6, 7]
283
+ tests: [6, 7, 8]
209
284
 
210
- - batch: 3
285
+ - batch: 4
286
+ name: "Transient States"
287
+ mock_type: "transient_state"
288
+ tests: [9, 10]
289
+
290
+ - batch: 5
211
291
  name: "Premium Features"
212
292
  mock_type: "premium_user"
213
- tests: [8, 9, 10]
293
+ tests: [11, 12]
214
294
  ```
215
295
  </step>
216
296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindsystem-cc",
3
- "version": "3.10.1",
3
+ "version": "3.12.0",
4
4
  "description": "A meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.",
5
5
  "bin": {
6
6
  "mindsystem-cc": "bin/install.js"
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.10"
4
+ # ///
5
+ """Combine variant-*.html mockup files into a single side-by-side comparison page."""
6
+
7
+ import re
8
+ import sys
9
+ from pathlib import Path
10
+
11
+
12
+ def extract_title(html: str) -> str:
13
+ """Extract the content of the <title> tag from an HTML string."""
14
+ match = re.search(r"<title>(.*?)</title>", html, re.IGNORECASE)
15
+ return match.group(1) if match else "Untitled"
16
+
17
+
18
+ def is_device_mockup(html: str) -> bool:
19
+ """Detect if the HTML is a phone-frame mockup (has a fixed-size .device element)."""
20
+ return bool(re.search(r"\.device\s*\{", html))
21
+
22
+
23
+ def build_device_html(panels: list[tuple[str, str]]) -> str:
24
+ """Side-by-side layout for phone-frame mockups."""
25
+ panels_html = ""
26
+ for label, filename in panels:
27
+ panels_html += f"""
28
+ <div class="panel">
29
+ <h2>{label}</h2>
30
+ <iframe src="{filename}"></iframe>
31
+ </div>"""
32
+
33
+ return f"""\
34
+ <!DOCTYPE html>
35
+ <html lang="en">
36
+ <head>
37
+ <meta charset="UTF-8">
38
+ <title>Mockup Comparison</title>
39
+ <style>
40
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
41
+ body {{
42
+ background: #1a1a1a;
43
+ color: #fff;
44
+ font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
45
+ padding: 24px;
46
+ }}
47
+ h1 {{
48
+ text-align: center;
49
+ margin-bottom: 24px;
50
+ font-size: 24px;
51
+ font-weight: 600;
52
+ }}
53
+ .container {{
54
+ display: flex;
55
+ justify-content: center;
56
+ gap: 32px;
57
+ flex-wrap: wrap;
58
+ }}
59
+ .panel {{
60
+ display: flex;
61
+ flex-direction: column;
62
+ align-items: center;
63
+ gap: 12px;
64
+ }}
65
+ .panel h2 {{
66
+ font-size: 16px;
67
+ font-weight: 500;
68
+ color: #ccc;
69
+ }}
70
+ iframe {{
71
+ border: none;
72
+ border-radius: 8px;
73
+ background: #e5e5e5;
74
+ width: 450px;
75
+ height: 920px;
76
+ }}
77
+ </style>
78
+ </head>
79
+ <body>
80
+ <h1>Mockup Comparison</h1>
81
+ <div class="container">{panels_html}
82
+ </div>
83
+ </body>
84
+ </html>
85
+ """
86
+
87
+
88
+ def build_fluid_html(panels: list[tuple[str, str]]) -> str:
89
+ """Tabbed layout for full web page mockups."""
90
+ tabs_html = ""
91
+ panes_html = ""
92
+ for i, (label, filename) in enumerate(panels):
93
+ active = " active" if i == 0 else ""
94
+ tabs_html += f"""
95
+ <button class="tab{active}" data-index="{i}">{label}</button>"""
96
+ panes_html += f"""
97
+ <iframe class="pane{active}" data-index="{i}" src="{filename}"></iframe>"""
98
+
99
+ return f"""\
100
+ <!DOCTYPE html>
101
+ <html lang="en">
102
+ <head>
103
+ <meta charset="UTF-8">
104
+ <title>Mockup Comparison</title>
105
+ <style>
106
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
107
+ html, body {{ height: 100%; }}
108
+ body {{
109
+ background: #1a1a1a;
110
+ color: #fff;
111
+ font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
112
+ display: flex;
113
+ flex-direction: column;
114
+ }}
115
+ .tab-bar {{
116
+ display: flex;
117
+ gap: 4px;
118
+ padding: 16px 24px 0;
119
+ flex-shrink: 0;
120
+ }}
121
+ .tab {{
122
+ padding: 10px 24px;
123
+ border: none;
124
+ border-radius: 8px 8px 0 0;
125
+ background: #2a2a2a;
126
+ color: #888;
127
+ font-size: 14px;
128
+ font-weight: 500;
129
+ font-family: inherit;
130
+ cursor: pointer;
131
+ transition: background 0.15s, color 0.15s;
132
+ }}
133
+ .tab:hover {{
134
+ background: #333;
135
+ color: #bbb;
136
+ }}
137
+ .tab.active {{
138
+ background: #e5e5e5;
139
+ color: #111;
140
+ }}
141
+ .pane-container {{
142
+ flex: 1;
143
+ padding: 0 24px 24px;
144
+ min-height: 0;
145
+ }}
146
+ .pane {{
147
+ display: none;
148
+ width: 100%;
149
+ height: 100%;
150
+ border: none;
151
+ border-radius: 0 8px 8px 8px;
152
+ background: #e5e5e5;
153
+ }}
154
+ .pane.active {{
155
+ display: block;
156
+ }}
157
+ </style>
158
+ </head>
159
+ <body>
160
+ <div class="tab-bar">{tabs_html}
161
+ </div>
162
+ <div class="pane-container">{panes_html}
163
+ </div>
164
+ <script>
165
+ document.querySelectorAll('.tab').forEach(tab => {{
166
+ tab.addEventListener('click', () => {{
167
+ const idx = tab.dataset.index;
168
+ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
169
+ document.querySelectorAll('.pane').forEach(p => p.classList.remove('active'));
170
+ tab.classList.add('active');
171
+ document.querySelector('.pane[data-index="' + idx + '"]').classList.add('active');
172
+ }});
173
+ }});
174
+ </script>
175
+ </body>
176
+ </html>
177
+ """
178
+
179
+
180
+ def main() -> None:
181
+ if len(sys.argv) > 1:
182
+ mockups_dir = Path(sys.argv[1])
183
+ else:
184
+ mockups_dir = Path.cwd()
185
+
186
+ variants = sorted(mockups_dir.glob("variant-*.html"))
187
+ if not variants:
188
+ print(f"No variant-*.html files found in {mockups_dir}", file=sys.stderr)
189
+ sys.exit(1)
190
+
191
+ print(f"Found {len(variants)} variants: {', '.join(v.name for v in variants)}")
192
+
193
+ # Read variants and detect layout mode
194
+ panels: list[tuple[str, str]] = []
195
+ all_device = True
196
+ for path in variants:
197
+ html = path.read_text()
198
+ letter = path.stem.split("-")[-1].upper()
199
+ title = extract_title(html)
200
+ label = f"Variant {letter}: {title}"
201
+ if not is_device_mockup(html):
202
+ all_device = False
203
+ panels.append((label, path.name))
204
+
205
+ mode = "device" if all_device else "fluid"
206
+ print(f"Layout mode: {mode}")
207
+
208
+ if mode == "device":
209
+ comparison = build_device_html(panels)
210
+ else:
211
+ comparison = build_fluid_html(panels)
212
+
213
+ output = mockups_dir / "comparison.html"
214
+ output.write_text(comparison)
215
+ print(f"Generated: {output}")
216
+
217
+
218
+ if __name__ == "__main__":
219
+ main()
@@ -1,50 +0,0 @@
1
- <checkpoint_detection>
2
- Lite reference for identifying checkpoint types during task breakdown. Full checkpoint templates and examples are in the ms-plan-writer subagent.
3
-
4
- <checkpoint_types>
5
-
6
- | Type | Use When | Frequency |
7
- |------|----------|-----------|
8
- | `checkpoint:human-verify` | Claude automated work, human confirms visual/functional correctness | 90% |
9
- | `checkpoint:decision` | Human must choose between options affecting implementation | 9% |
10
- | `checkpoint:human-action` | Truly unavoidable manual step with no CLI/API (rare) | 1% |
11
-
12
- </checkpoint_types>
13
-
14
- <detection_rules>
15
-
16
- **Mark as `checkpoint:human-verify` when:**
17
- - Visual UI checks needed (layout, styling, responsiveness)
18
- - Interactive flows require human testing (click through wizard, test user flows)
19
- - Functional verification beyond automated tests (feature works as expected)
20
- - Audio/video playback, animation smoothness, accessibility
21
-
22
- **Mark as `checkpoint:decision` when:**
23
- - Technology selection (auth provider, database, library)
24
- - Architecture choices (monorepo vs separate, API patterns)
25
- - Design decisions (color scheme, layout approach)
26
- - Feature prioritization between variants
27
-
28
- **Mark as `checkpoint:human-action` when (rare):**
29
- - Email verification links (account creation)
30
- - SMS 2FA codes (phone verification)
31
- - Manual account approvals
32
- - Credit card 3D Secure flows
33
- - OAuth app approvals requiring browser
34
-
35
- </detection_rules>
36
-
37
- <automation_first_principle>
38
- **If it has CLI/API, Claude automates it. No exceptions.**
39
-
40
- Never create `checkpoint:human-action` for:
41
- - Deployments (use `vercel`, `railway`, `fly` CLI)
42
- - Database operations (use provider CLI)
43
- - Webhook setup (use APIs)
44
- - Environment files (use Write tool)
45
- - Running builds/tests (use Bash tool)
46
-
47
- The rule: Claude does everything automatable. Checkpoints verify AFTER automation, not replace it.
48
- </automation_first_principle>
49
-
50
- </checkpoint_detection>