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.
- package/README.md +1 -1
- package/agents/ms-designer.md +8 -8
- package/agents/ms-executor.md +14 -163
- package/agents/ms-plan-checker.md +2 -3
- package/agents/ms-plan-writer.md +6 -21
- package/agents/ms-roadmapper.md +1 -18
- package/agents/ms-verify-fixer.md +1 -1
- package/commands/ms/design-phase.md +9 -14
- package/commands/ms/execute-phase.md +0 -9
- package/commands/ms/help.md +1 -8
- package/commands/ms/new-project.md +3 -40
- package/commands/ms/review-design.md +4 -7
- package/commands/ms/verify-work.md +1 -1
- package/mindsystem/references/design-directions.md +1 -1
- package/mindsystem/references/mock-patterns.md +48 -0
- package/mindsystem/references/plan-format.md +2 -129
- package/mindsystem/references/scope-estimation.md +3 -36
- package/mindsystem/templates/config.json +0 -13
- package/mindsystem/templates/design.md +1 -1
- package/mindsystem/templates/phase-prompt.md +6 -142
- package/mindsystem/templates/roadmap.md +1 -1
- package/mindsystem/templates/summary.md +24 -0
- package/mindsystem/workflows/execute-phase.md +4 -99
- package/mindsystem/workflows/execute-plan.md +12 -523
- package/mindsystem/workflows/generate-mocks.md +74 -0
- package/mindsystem/workflows/mockup-generation.md +11 -5
- package/mindsystem/workflows/plan-phase.md +15 -60
- package/mindsystem/workflows/transition.md +1 -10
- package/mindsystem/workflows/verify-work.md +97 -17
- package/package.json +1 -1
- package/scripts/__pycache__/compare_mockups.cpython-314.pyc +0 -0
- package/scripts/compare_mockups.py +219 -0
- package/mindsystem/references/checkpoint-detection.md +0 -50
- 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
|
|
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,
|
|
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,
|
|
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
|
|
452
|
+
- **Type**: auto
|
|
454
453
|
- **Task name**: Clear, action-oriented
|
|
455
|
-
- **Files**: Which files created/modified
|
|
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
|
-
**
|
|
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.
|
|
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
|
-
**
|
|
497
|
+
**Present a concise numbered task summary for the user:**
|
|
501
498
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
|
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:
|
|
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,
|
|
144
|
+
For each test, determine:
|
|
145
145
|
1. **mock_required**: Does this need special backend state?
|
|
146
|
-
2. **mock_type**:
|
|
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
|
-
**
|
|
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" |
|
|
182
|
+
| "loading", "spinner", "skeleton" | transient_state |
|
|
157
183
|
| "offline", "no connection" | offline_state |
|
|
158
184
|
| Normal happy path | no mock needed |
|
|
159
185
|
|
|
160
|
-
|
|
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: "
|
|
217
|
+
- name: "Recipe list loading skeleton"
|
|
179
218
|
mock_required: true
|
|
180
|
-
mock_type: "
|
|
181
|
-
|
|
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.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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: [
|
|
283
|
+
tests: [6, 7, 8]
|
|
209
284
|
|
|
210
|
-
- batch:
|
|
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: [
|
|
293
|
+
tests: [11, 12]
|
|
214
294
|
```
|
|
215
295
|
</step>
|
|
216
296
|
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -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>
|