pan-wizard 3.34.0 → 3.36.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 +16 -10
- package/agents/pan-conductor.md +2 -2
- package/agents/pan-debugger.md +3 -1
- package/agents/pan-design-checker.md +1 -0
- package/agents/pan-designer.md +1 -1
- package/agents/pan-executor.md +43 -1
- package/agents/pan-experiment-runner.md +1 -1
- package/agents/pan-hardener.md +3 -1
- package/agents/pan-meta-reviewer.md +1 -1
- package/agents/pan-phase-researcher.md +16 -2
- package/agents/pan-plan-checker.md +37 -9
- package/agents/pan-planner.md +14 -2
- package/agents/pan-previewer.md +2 -0
- package/agents/pan-project-researcher.md +9 -1
- package/agents/pan-research-synthesizer.md +1 -1
- package/agents/pan-reviewer.md +8 -2
- package/agents/pan-verifier.md +3 -3
- package/bin/install-lib.cjs +119 -16
- package/bin/install.js +34 -62
- package/commands/pan/cost.md +21 -5
- package/commands/pan/dashboard.md +0 -3
- package/commands/pan/design-phase.md +2 -2
- package/commands/pan/hud.md +1 -5
- package/commands/pan/knowledge.md +0 -1
- package/commands/pan/mcp-bridge.md +1 -3
- package/commands/pan/optimize.md +2 -0
- package/commands/pan/phase-tests.md +1 -1
- package/commands/pan/preview.md +2 -3
- package/commands/pan/report.md +1 -5
- package/commands/pan/research-phase.md +4 -4
- package/commands/pan/review-deep.md +0 -2
- package/commands/pan/what-if.md +1 -2
- package/hooks/dist/pan-context-monitor.js +12 -3
- package/hooks/dist/pan-guard.js +244 -0
- package/hooks/dist/pan-statusline.js +5 -2
- package/package.json +1 -1
- package/pan-wizard-core/bin/lib/commands.cjs +24 -2
- package/pan-wizard-core/bin/lib/config.cjs +13 -1
- package/pan-wizard-core/bin/lib/core.cjs +9 -4
- package/pan-wizard-core/bin/lib/cost.cjs +146 -0
- package/pan-wizard-core/bin/lib/doc-lint.cjs +5 -3
- package/pan-wizard-core/bin/lib/findings.cjs +239 -23
- package/pan-wizard-core/bin/lib/git.cjs +1 -1
- package/pan-wizard-core/bin/lib/hygiene.cjs +11 -5
- package/pan-wizard-core/bin/lib/init.cjs +6 -0
- package/pan-wizard-core/bin/lib/mutate.cjs +257 -0
- package/pan-wizard-core/bin/lib/optimize.cjs +13 -1
- package/pan-wizard-core/bin/lib/phase-gate.cjs +180 -0
- package/pan-wizard-core/bin/lib/phase-remove.cjs +91 -11
- package/pan-wizard-core/bin/lib/phase.cjs +61 -9
- package/pan-wizard-core/bin/lib/plan-lint.cjs +161 -0
- package/pan-wizard-core/bin/lib/preview.cjs +35 -31
- package/pan-wizard-core/bin/lib/research-lint.cjs +121 -0
- package/pan-wizard-core/bin/lib/roadmap.cjs +1 -0
- package/pan-wizard-core/bin/lib/test-gate.cjs +433 -0
- package/pan-wizard-core/bin/lib/usage.cjs +104 -0
- package/pan-wizard-core/bin/lib/verdict.cjs +140 -10
- package/pan-wizard-core/bin/lib/verify-integrity.cjs +181 -0
- package/pan-wizard-core/bin/lib/verify-plan-set.cjs +230 -0
- package/pan-wizard-core/bin/lib/verify-red.cjs +138 -0
- package/pan-wizard-core/bin/lib/verify-scope.cjs +148 -6
- package/pan-wizard-core/bin/lib/verify.cjs +27 -27
- package/pan-wizard-core/bin/lib/whatif.cjs +48 -6
- package/pan-wizard-core/bin/pan-tools.cjs +106 -9
- package/pan-wizard-core/mcp/merge-gate.cjs +14 -3
- package/pan-wizard-core/mcp/native-tools.cjs +3 -3
- package/pan-wizard-core/mcp/orchestrator.cjs +4 -1
- package/pan-wizard-core/opencode/pan-wizard.js +36 -8
- package/pan-wizard-core/references/design-methodology.md +1 -1
- package/pan-wizard-core/references/handoff-decisions.md +1 -1
- package/pan-wizard-core/references/model-profiles.md +1 -1
- package/pan-wizard-core/references/planning-config.md +3 -3
- package/pan-wizard-core/references/verdict-contract.md +6 -1
- package/pan-wizard-core/templates/config.json +6 -6
- package/pan-wizard-core/templates/debug-subagent-prompt.md +2 -1
- package/pan-wizard-core/templates/design.md +5 -4
- package/pan-wizard-core/templates/phase-prompt.md +9 -0
- package/pan-wizard-core/templates/planner-subagent-prompt.md +2 -0
- package/pan-wizard-core/templates/preview-report.md +1 -1
- package/pan-wizard-core/templates/research-project/architecture.md +6 -0
- package/pan-wizard-core/templates/research-project/features.md +6 -0
- package/pan-wizard-core/templates/research-project/pitfalls.md +6 -0
- package/pan-wizard-core/templates/research-project/stack.md +6 -0
- package/pan-wizard-core/templates/research.md +10 -0
- package/pan-wizard-core/templates/state.md +4 -4
- package/pan-wizard-core/templates/summary-complex.md +5 -1
- package/pan-wizard-core/templates/summary-minimal.md +4 -0
- package/pan-wizard-core/templates/summary-standard.md +5 -1
- package/pan-wizard-core/templates/summary.md +8 -1
- package/pan-wizard-core/workflows/diagnose-issues.md +4 -4
- package/pan-wizard-core/workflows/discuss-phase.md +2 -1
- package/pan-wizard-core/workflows/exec-phase.md +92 -45
- package/pan-wizard-core/workflows/execute-plan.md +3 -1
- package/pan-wizard-core/workflows/help.md +103 -44
- package/pan-wizard-core/workflows/milestone-gaps.md +2 -2
- package/pan-wizard-core/workflows/new-project.md +8 -16
- package/pan-wizard-core/workflows/plan-phase.md +40 -8
- package/pan-wizard-core/workflows/progress.md +1 -1
- package/pan-wizard-core/workflows/quick.md +2 -2
- package/pan-wizard-core/workflows/remove-phase.md +11 -1
- package/pan-wizard-core/workflows/settings.md +17 -0
- package/pan-wizard-core/workflows/todo-check.md +3 -2
- package/pan-wizard-core/workflows/transition.md +4 -0
- package/pan-wizard-core/workflows/verify-phase.md +40 -47
- package/scripts/build-help.cjs +106 -0
- package/scripts/build-hooks.js +1 -0
- package/scripts/generate-skills-docs.py +2 -2
- package/scripts/mutation-probe.cjs +7 -80
- package/scripts/prompt-lint.cjs +167 -0
- package/scripts/test-surface.cjs +169 -6
|
@@ -525,9 +525,7 @@ Display spawning indicator:
|
|
|
525
525
|
Spawn 4 parallel pan-project-researcher agents with path references:
|
|
526
526
|
|
|
527
527
|
```
|
|
528
|
-
Task(prompt="
|
|
529
|
-
|
|
530
|
-
<research_type>
|
|
528
|
+
Task(prompt="<research_type>
|
|
531
529
|
Project Research — Stack dimension for [domain].
|
|
532
530
|
</research_type>
|
|
533
531
|
|
|
@@ -563,11 +561,9 @@ Your stack.md feeds into roadmap creation. Be prescriptive:
|
|
|
563
561
|
Write to: .planning/research/stack.md
|
|
564
562
|
Use template: ~/.claude/pan-wizard-core/templates/research-project/stack.md
|
|
565
563
|
</output>
|
|
566
|
-
", subagent_type="
|
|
567
|
-
|
|
568
|
-
Task(prompt="First, read ~/.claude/agents/pan-project-researcher.md for your role and instructions.
|
|
564
|
+
", subagent_type="pan-project-researcher", model="{researcher_model}", description="Stack research")
|
|
569
565
|
|
|
570
|
-
<research_type>
|
|
566
|
+
Task(prompt="<research_type>
|
|
571
567
|
Project Research — Features dimension for [domain].
|
|
572
568
|
</research_type>
|
|
573
569
|
|
|
@@ -603,11 +599,9 @@ Your features.md feeds into requirements definition. Categorize clearly:
|
|
|
603
599
|
Write to: .planning/research/features.md
|
|
604
600
|
Use template: ~/.claude/pan-wizard-core/templates/research-project/features.md
|
|
605
601
|
</output>
|
|
606
|
-
", subagent_type="
|
|
602
|
+
", subagent_type="pan-project-researcher", model="{researcher_model}", description="Features research")
|
|
607
603
|
|
|
608
|
-
Task(prompt="
|
|
609
|
-
|
|
610
|
-
<research_type>
|
|
604
|
+
Task(prompt="<research_type>
|
|
611
605
|
Project Research — Architecture dimension for [domain].
|
|
612
606
|
</research_type>
|
|
613
607
|
|
|
@@ -643,11 +637,9 @@ Your architecture.md informs phase structure in roadmap. Include:
|
|
|
643
637
|
Write to: .planning/research/architecture.md
|
|
644
638
|
Use template: ~/.claude/pan-wizard-core/templates/research-project/architecture.md
|
|
645
639
|
</output>
|
|
646
|
-
", subagent_type="
|
|
647
|
-
|
|
648
|
-
Task(prompt="First, read ~/.claude/agents/pan-project-researcher.md for your role and instructions.
|
|
640
|
+
", subagent_type="pan-project-researcher", model="{researcher_model}", description="Architecture research")
|
|
649
641
|
|
|
650
|
-
<research_type>
|
|
642
|
+
Task(prompt="<research_type>
|
|
651
643
|
Project Research — Pitfalls dimension for [domain].
|
|
652
644
|
</research_type>
|
|
653
645
|
|
|
@@ -683,7 +675,7 @@ Your pitfalls.md prevents mistakes in roadmap/planning. For each pitfall:
|
|
|
683
675
|
Write to: .planning/research/pitfalls.md
|
|
684
676
|
Use template: ~/.claude/pan-wizard-core/templates/research-project/pitfalls.md
|
|
685
677
|
</output>
|
|
686
|
-
", subagent_type="
|
|
678
|
+
", subagent_type="pan-project-researcher", model="{researcher_model}", description="Pitfalls research")
|
|
687
679
|
```
|
|
688
680
|
|
|
689
681
|
After all 4 agents complete, spawn synthesizer to create summary.md:
|
|
@@ -280,8 +280,8 @@ Write to: {phase_dir}/{padded_phase}-research.md
|
|
|
280
280
|
|
|
281
281
|
```
|
|
282
282
|
Task(
|
|
283
|
-
prompt=
|
|
284
|
-
subagent_type="
|
|
283
|
+
prompt=research_prompt,
|
|
284
|
+
subagent_type="pan-phase-researcher",
|
|
285
285
|
model="{researcher_model}",
|
|
286
286
|
description="Research Phase {phase}"
|
|
287
287
|
)
|
|
@@ -383,8 +383,8 @@ Output consumed by /pan:exec-phase. Plans need:
|
|
|
383
383
|
|
|
384
384
|
```
|
|
385
385
|
Task(
|
|
386
|
-
prompt=
|
|
387
|
-
subagent_type="
|
|
386
|
+
prompt=filled_prompt,
|
|
387
|
+
subagent_type="pan-planner",
|
|
388
388
|
model="{planner_model}",
|
|
389
389
|
description="Plan Phase {phase}"
|
|
390
390
|
)
|
|
@@ -392,12 +392,26 @@ Task(
|
|
|
392
392
|
|
|
393
393
|
## 9. Handle Planner Return
|
|
394
394
|
|
|
395
|
-
- **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): skip to step 13. Otherwise: step 10.
|
|
395
|
+
- **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): still run the code checks at the start of step 10 (`verify plan-set`, `verify review-focus`, `verify decisions`; they cost no model call), send any errors back to the planner (step 12), then skip to step 13. Otherwise: step 10.
|
|
396
396
|
- **`## GAP CLOSURE PLANS CREATED`:** (`--gaps` mode) Handle as `## PLANNING COMPLETE`.
|
|
397
397
|
- **`## CHECKPOINT REACHED`:** Present to user, get response, spawn a fresh planner (step 8's Task) with the response added to its prompt
|
|
398
398
|
|
|
399
399
|
## 10. Spawn pan-plan-checker Agent
|
|
400
400
|
|
|
401
|
+
**First, the checks code can make.** Run them before spending a checker:
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
PLAN_SET=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify plan-set "${PHASE_NUMBER}")
|
|
405
|
+
PLAN_SET_EXIT=$?
|
|
406
|
+
REVIEW_FOCUS=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify review-focus "${PHASE_NUMBER}")
|
|
407
|
+
REVIEW_FOCUS_EXIT=$?
|
|
408
|
+
DECISIONS=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify decisions "${PHASE_NUMBER}")
|
|
409
|
+
DECISIONS_EXIT=$?
|
|
410
|
+
RESEARCH_LINT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs research lint "${PHASE_NUMBER}" 2>/dev/null)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Exit 1 from `verify plan-set` means the plan set is broken in a way no review can wave through: a roadmap requirement no plan lists, two plans in one wave modifying the same file, a `depends_on` that names no plan or a plan in the same or a later wave, or a cycle. Exit 1 from `verify review-focus` means a plan has no `## Review Focus` section, more than five items, or an item that names no owning task or no test. Exit 1 from `verify decisions` means a plan cites a `DD-N` decision the design does not record, or a recorded decision no plan cites (it exits 0 when there is no design, or a design without ids). On any exit 1, send the `errors` of each failing check to the planner as the revision context (step 12; it counts as an iteration) and do not spawn the checker for this set. All exit 0: continue, and pass any `warnings` to the checker. `RESEARCH_LINT` never blocks planning: it goes to the checker as `<research_claims>` (claims with no source or date, and `stale` ones older than their type's window), and is `{"error":"no_research"}` when the phase was not researched.
|
|
414
|
+
|
|
401
415
|
Display banner:
|
|
402
416
|
```
|
|
403
417
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -427,6 +441,14 @@ Checker prompt:
|
|
|
427
441
|
**Project skills:** Check .agents/skills/ directory (if exists) — verify plans account for project skill rules
|
|
428
442
|
</verification_context>
|
|
429
443
|
|
|
444
|
+
<research_claims>
|
|
445
|
+
{RESEARCH_LINT}
|
|
446
|
+
</research_claims>
|
|
447
|
+
|
|
448
|
+
<open_findings>
|
|
449
|
+
{output of `pan-tools findings list --phase {phase_number} --agent pan-plan-checker --status open`: empty on the first check; on a re-check, answer each in `resolutions`}
|
|
450
|
+
</open_findings>
|
|
451
|
+
|
|
430
452
|
<expected_output>
|
|
431
453
|
- ## VERIFICATION PASSED — all checks pass
|
|
432
454
|
- ## ISSUES FOUND — structured issue list
|
|
@@ -457,7 +479,7 @@ The fallback reads the heading when the report carries no valid `pan-verdict` bl
|
|
|
457
479
|
- **`passed`:** Display confirmation, proceed to step 13.
|
|
458
480
|
- **`issues_found`:** Display issues, check iteration count, proceed to step 12.
|
|
459
481
|
|
|
460
|
-
Each re-check in the revision loop overwrites the same file and is recorded again as the next attempt. The
|
|
482
|
+
Each re-check in the revision loop overwrites the same file and is recorded again as the next attempt. The checker answers each earlier issue in `resolutions`; the record closes the ones it answers `resolved` with evidence, and one it neither reports nor answers stays open.
|
|
461
483
|
|
|
462
484
|
## 12. Revision Loop (At Most 2 Revisions, 3 Checks)
|
|
463
485
|
|
|
@@ -491,8 +513,8 @@ Return what changed.
|
|
|
491
513
|
|
|
492
514
|
```
|
|
493
515
|
Task(
|
|
494
|
-
prompt=
|
|
495
|
-
subagent_type="
|
|
516
|
+
prompt=revision_prompt,
|
|
517
|
+
subagent_type="pan-planner",
|
|
496
518
|
model="{planner_model}",
|
|
497
519
|
description="Revise Phase {phase} plans"
|
|
498
520
|
)
|
|
@@ -524,6 +546,15 @@ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Last Activity" "$
|
|
|
524
546
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Last Activity Description" "Phase ${PHASE_NUMBER} planned — ${PLAN_COUNT} plans created"
|
|
525
547
|
```
|
|
526
548
|
|
|
549
|
+
**Spend so far and what execution may cost** (`cost.phase_budget_usd`, default $20; it only warns):
|
|
550
|
+
|
|
551
|
+
```bash
|
|
552
|
+
BUDGET=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs cost budget --phase "${PHASE_NUMBER}" 2>/dev/null)
|
|
553
|
+
FORECAST=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs preview phase "${PHASE_NUMBER}" 2>/dev/null)
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
In the final status, when the budget's `status` is not `off`, add: "Budget: ${spent_usd} of ${budget_usd} spent so far". When `FORECAST`'s `cost_forecast.phase.status` is `ok`, add its p50 and p10–p90, and say so when the p50 alone is above what is left of the budget. When the forecast is `insufficient`, say nothing about it. Never stop or ask on either.
|
|
557
|
+
|
|
527
558
|
Route to `<offer_next>` OR `auto_advance` depending on flags/config.
|
|
528
559
|
|
|
529
560
|
**Circular optimization — log plan creation:**
|
|
@@ -590,6 +621,7 @@ Task(
|
|
|
590
621
|
</instructions>
|
|
591
622
|
",
|
|
592
623
|
subagent_type="general-purpose",
|
|
624
|
+
model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
|
|
593
625
|
description="Execute Phase ${PHASE}"
|
|
594
626
|
)
|
|
595
627
|
```
|
|
@@ -54,7 +54,7 @@ ROADMAP=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs roadmap analyze)
|
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
This returns structured JSON with:
|
|
57
|
-
- All phases with disk status (complete/partial/planned/empty/no_directory)
|
|
57
|
+
- All phases with disk status (complete/partial/planned/researched/discussed/empty/no_directory)
|
|
58
58
|
- Goal and dependencies per phase
|
|
59
59
|
- Plan and summary counts per phase
|
|
60
60
|
- Aggregated stats: total plans, summaries, progress percent
|
|
@@ -229,8 +229,8 @@ Return what changed.
|
|
|
229
229
|
|
|
230
230
|
```
|
|
231
231
|
Task(
|
|
232
|
-
prompt=
|
|
233
|
-
subagent_type="
|
|
232
|
+
prompt=revision_prompt,
|
|
233
|
+
subagent_type="pan-planner",
|
|
234
234
|
model="{planner_model}",
|
|
235
235
|
description="Revise quick plan: ${DESCRIPTION}"
|
|
236
236
|
)
|
|
@@ -72,6 +72,8 @@ This will:
|
|
|
72
72
|
Proceed? (y/n)
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
If an integer target has decimal phases inserted after it (`### Phase {target}.1:` and so on in roadmap.md, or `{target}.N-*` directories), name them in the summary and ask whether to remove them too. pan-tools refuses to remove the integer phase while they exist, because they would be left behind under a different phase's number.
|
|
76
|
+
|
|
75
77
|
Wait for confirmation.
|
|
76
78
|
</step>
|
|
77
79
|
|
|
@@ -88,6 +90,14 @@ If the phase has executed plans (summary.md files), pan-tools will error. Use `-
|
|
|
88
90
|
RESULT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phase remove "${target}" --force)
|
|
89
91
|
```
|
|
90
92
|
|
|
93
|
+
If the phase has decimal phases, pan-tools errors and names them. Add `--with-decimals` only if the user confirmed removing them as well (each is checked for executed plans the same way, so `--force` still applies to them):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
RESULT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phase remove "${target}" --with-decimals)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Otherwise stop and report the decimals; the user can remove them one by one first.
|
|
100
|
+
|
|
91
101
|
The CLI handles:
|
|
92
102
|
- Deleting the phase directory
|
|
93
103
|
- Renumbering all subsequent directories (in reverse order to avoid conflicts)
|
|
@@ -95,7 +105,7 @@ The CLI handles:
|
|
|
95
105
|
- Updating roadmap.md (removing section, renumbering all phase references, updating dependencies)
|
|
96
106
|
- Updating state.md (decrementing phase count)
|
|
97
107
|
|
|
98
|
-
Extract from result: `removed`, `directory_deleted`, `renamed_directories`, `renamed_files`, `roadmap_updated`, `state_updated
|
|
108
|
+
Extract from result: `removed`, `directory_deleted`, `renamed_directories`, `renamed_files`, `roadmap_updated`, `state_updated`, and `removed_decimals` when `--with-decimals` removed any.
|
|
99
109
|
</step>
|
|
100
110
|
|
|
101
111
|
<step name="commit">
|
|
@@ -31,6 +31,7 @@ Parse current values (when a key is absent, use PAN's default: `true` for resear
|
|
|
31
31
|
- `workflow.nyquist_validation` — validation architecture research during plan-phase
|
|
32
32
|
- `model_profile` — which model each agent uses (default: `balanced`)
|
|
33
33
|
- `routing.strategy` — how model tiers are adjusted at runtime (default: `static`)
|
|
34
|
+
- `cost.phase_budget_usd` — spend per phase PAN warns about, in API-equivalent dollars (default: `20`; `0` = off). It never stops a run
|
|
34
35
|
- `branching_strategy` — branching approach (default: `"none"`; a top-level key — a nested `git.branching_strategy` is ignored when the top-level key exists, as it does in every config `config-ensure-section` creates — write the top-level key)
|
|
35
36
|
</step>
|
|
36
37
|
|
|
@@ -112,9 +113,23 @@ AskUserQuestion([
|
|
|
112
113
|
{ label: "Static (Recommended)", description: "Profile assigns fixed tiers to each agent. Predictable and simple." },
|
|
113
114
|
{ label: "Complexity", description: "Adjust tiers by task complexity, only where a model is resolved with the task passed (resolve-model --metadata); the *_model values workflows pass are not, so it changes nothing there" }
|
|
114
115
|
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
question: "Warn when a phase's spend passes how much? (API-equivalent dollars; warns only, never stops)",
|
|
119
|
+
header: "Phase budget",
|
|
120
|
+
multiSelect: false,
|
|
121
|
+
options: [
|
|
122
|
+
{ label: "$20 per phase (Recommended)", description: "Warn at $16 (80%) and again once a phase passes $20" },
|
|
123
|
+
{ label: "$50 per phase", description: "For larger phases or the quality profile" },
|
|
124
|
+
{ label: "$10 per phase", description: "For small phases or the budget profile" },
|
|
125
|
+
{ label: "Off", description: "No spend warnings; /pan:cost still reports spend" }
|
|
126
|
+
]
|
|
115
127
|
}
|
|
116
128
|
])
|
|
117
129
|
```
|
|
130
|
+
|
|
131
|
+
A dollar amount typed under Other is used as given.
|
|
132
|
+
```
|
|
118
133
|
</step>
|
|
119
134
|
|
|
120
135
|
<step name="update_config">
|
|
@@ -129,6 +144,7 @@ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs config-set workflow.auto_advanc
|
|
|
129
144
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs config-set workflow.nyquist_validation <true|false>
|
|
130
145
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs config-set branching_strategy <none|phase|milestone>
|
|
131
146
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs config-set routing.strategy <static|complexity>
|
|
147
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs config-set cost.phase_budget_usd <20|50|10|0|amount>
|
|
132
148
|
```
|
|
133
149
|
</step>
|
|
134
150
|
|
|
@@ -194,6 +210,7 @@ Display:
|
|
|
194
210
|
| Nyquist Validation | {On/Off} |
|
|
195
211
|
| Git Branching | {None/Per Phase/Per Milestone} |
|
|
196
212
|
| Routing Strategy | {Static/Complexity} |
|
|
213
|
+
| Phase Budget | {$N per phase (warn only)/Off} |
|
|
197
214
|
| Saved as Defaults | {Yes/No} |
|
|
198
215
|
|
|
199
216
|
These settings apply to future /pan:plan-phase and /pan:exec-phase runs.
|
|
@@ -12,7 +12,8 @@ Read all files referenced by the invoking prompt's execution_context before star
|
|
|
12
12
|
Load todo context:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
|
|
15
|
+
AREA="" # the area argument when one was given: /pan:todo-check api → AREA="api"; empty lists every todo
|
|
16
|
+
INIT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs init todos "$AREA")
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
Extract from init JSON: `todo_count`, `todos`, `pending_dir`.
|
|
@@ -35,7 +36,7 @@ Exit.
|
|
|
35
36
|
</step>
|
|
36
37
|
|
|
37
38
|
<step name="parse_filter">
|
|
38
|
-
|
|
39
|
+
The area filter was applied in init_context (AREA):
|
|
39
40
|
- `/pan:todo-check` → show all
|
|
40
41
|
- `/pan:todo-check api` → filter to area:api only
|
|
41
42
|
</step>
|
|
@@ -155,6 +155,8 @@ If found, delete them — phase is complete, handoffs are stale.
|
|
|
155
155
|
TRANSITION=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phase complete "${current_phase}") # skip when exec-phase invoked this workflow: its `phase complete` already ran — reuse that result
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
+
`phase complete` runs the phase gate first. Exit 1 with `error: phase_gate_refused` (`workflow.phase_gate: enforce`) means the phase was not marked complete: show `gate.reasons` and stop the transition. With `gate.ok` false under `warn`, the phase was marked complete: show the reasons as warnings before continuing.
|
|
159
|
+
|
|
158
160
|
The CLI handles:
|
|
159
161
|
- Marking the phase checkbox as `[x]` complete with today's date
|
|
160
162
|
- Updating plan count to final (e.g., "3/3 plans complete")
|
|
@@ -453,6 +455,7 @@ Task(
|
|
|
453
455
|
</instructions>
|
|
454
456
|
",
|
|
455
457
|
subagent_type="general-purpose",
|
|
458
|
+
model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
|
|
456
459
|
description="Plan Phase ${NEXT_PHASE}"
|
|
457
460
|
)
|
|
458
461
|
```
|
|
@@ -495,6 +498,7 @@ Task(
|
|
|
495
498
|
</instructions>
|
|
496
499
|
",
|
|
497
500
|
subagent_type="general-purpose",
|
|
501
|
+
model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
|
|
498
502
|
description="Discuss Phase ${NEXT_PHASE}"
|
|
499
503
|
)
|
|
500
504
|
```
|
|
@@ -85,65 +85,58 @@ This step provides awareness; the hard gate is enforced by exec-phase.
|
|
|
85
85
|
</step>
|
|
86
86
|
|
|
87
87
|
<step name="run_test_suite">
|
|
88
|
-
**Run the project's test suite as a verification gate.**
|
|
88
|
+
**Run the project's test suite as a verification gate, through the engine.**
|
|
89
89
|
|
|
90
|
-
This step catches test regressions that goal-backward analysis cannot detect.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
This step catches test regressions that goal-backward analysis cannot detect. The engine
|
|
91
|
+
runs the suite, not you: it finds the project's test command in any language
|
|
92
|
+
(`workflow.test_command` in config.json, else package.json's test script, pytest, `go test
|
|
93
|
+
./...`, cargo, Maven, Gradle or `make test`), reads the runner's own output, compares it with
|
|
94
|
+
the baseline exec-phase recorded before the first wave, and writes the result to the phase
|
|
95
|
+
directory as `{NN}-test-run.json`.
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
|
|
98
|
+
TEST_RUN=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs test run --phase "${phase_number}")
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
Read from the JSON: `status`, `reason`, `command`, `total`, `passed`, `failed`,
|
|
102
|
+
`regressions`, `preexisting_failures` and `record`.
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
TEST_COUNT=$(echo "$TEST_OUTPUT" | grep -E "^ℹ tests" | awk '{print $NF}')
|
|
109
|
-
TEST_PASS=$(echo "$TEST_OUTPUT" | grep -E "^ℹ pass" | awk '{print $NF}')
|
|
110
|
-
TEST_FAIL=$(echo "$TEST_OUTPUT" | grep -E "^ℹ fail" | awk '{print $NF}')
|
|
111
|
-
```
|
|
104
|
+
**Copy the status; do not judge it.** Write `test_gate: <status>` into the verification.md
|
|
105
|
+
frontmatter exactly as the record says. Reconcile compares the two, so a verification whose
|
|
106
|
+
`test_gate` disagrees with the record is refused at the phase gate, and a failed record
|
|
107
|
+
lowers a `passed` verification to `gaps_found` whatever the frontmatter says.
|
|
112
108
|
|
|
113
|
-
|
|
109
|
+
| `status` | What it means | What you do |
|
|
110
|
+
|----------|---------------|-------------|
|
|
111
|
+
| `passed` | The suite ran and nothing that passed at the baseline fails now | Record the counts. If `preexisting_failures` is not empty, list them as known failures the phase inherited, not as gaps |
|
|
112
|
+
| `failed` | A test that passed at the baseline fails now (`regressions`), or the suite did not run at all (a crash, a build error, a timeout: `reason` says `suite did not run`) | Set the overall status to `gaps_found` and list each regression, or the reason, as a gap |
|
|
113
|
+
| `skipped` | There was nothing to run: no test command, or one that ran no tests | Add a `not_checked` entry: `check: "tests"`, `reason:` the record's `reason` |
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
A suite that exists and did not run is `failed`, never `skipped`: the engine decides that
|
|
116
|
+
from the exit code and the runner's output, and you copy it.
|
|
117
|
+
|
|
118
|
+
**If test gate FAILED:** Continue verification (gather full picture) but set overall status to `gaps_found` regardless of goal-backward results. Include test failures as gaps in the report.
|
|
119
|
+
</step>
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
| `TEST_EXIT` = 0 **and** `TEST_FAIL` = 0 (a real number) | Record counts, continue to must-haves |
|
|
124
|
-
| `TEST_EXIT` = 0 **and** no `ℹ` count lines (a runner other than Node's built-in one) | Set `test_gate_status: passed`; record the runner's own summary line as the counts |
|
|
125
|
-
| `TEST_EXIT` ≠ 0 **and** failures were reported | Set `test_gate_status: failed`, include failure details |
|
|
126
|
-
| `TEST_EXIT` ≠ 0 **and** `TEST_FAIL` is empty/absent — the suite CRASHED or could not run (syntax error, missing module, bad import, no runner) | Set `test_gate_status: failed`, and record the reason as `suite did not run`. **Never `skipped`, never `passed`.** A suite that cannot execute is stronger evidence of a broken phase than one that runs and fails |
|
|
127
|
-
| `HAS_TEST` = `no` (handled in step 1) | Record as `test_gate_status: skipped`, continue. This is the ONLY legitimate route to `skipped` |
|
|
121
|
+
<step name="mutation_report">
|
|
122
|
+
**Measure whether the tests pin the code the phase wrote** (a report, never a gate).
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
project. They must never share a verdict; the first is `skipped`, the second is
|
|
132
|
-
`failed`.
|
|
124
|
+
Only when the test gate passed: a mutant cannot be read against a suite that already fails.
|
|
125
|
+
With `workflow.mutation_gate: off` the command runs nothing and says so.
|
|
133
126
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
TEST_GATE_STATUS: passed | failed | skipped
|
|
137
|
-
TEST_TOTAL: ${TEST_COUNT}
|
|
138
|
-
TEST_PASSED: ${TEST_PASS}
|
|
139
|
-
TEST_FAILED: ${TEST_FAIL}
|
|
127
|
+
```bash
|
|
128
|
+
MUTATION=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify mutate --phase "${phase_number}" --max 5)
|
|
140
129
|
```
|
|
141
|
-
Write `test_gate: ${TEST_GATE_STATUS}` into the verification.md frontmatter. When it is
|
|
142
|
-
`skipped`, also add a `not_checked` entry (`check: "tests"`, `reason: "no test script in
|
|
143
|
-
package.json"`). The recorder reads both: a pass whose tests never ran is recorded as a
|
|
144
|
-
pass with tests not checked, never as a plain pass.
|
|
145
130
|
|
|
146
|
-
|
|
131
|
+
The engine flips one comparison, boolean or `+ 1` at a time on the lines the phase's plan
|
|
132
|
+
commits changed, in a throwaway worktree at HEAD, and runs the suite against each mutant. Read
|
|
133
|
+
`checked`, `sampled`, `killed`, `survivors` (file, line, the swap) and `aborted`.
|
|
134
|
+
|
|
135
|
+
Write a **Test strength** section in verification.md: `killed/sampled`, and each survivor as
|
|
136
|
+
`file:line — before → after`, framed as a test the phase could add. A survivor is a lead, not a
|
|
137
|
+
gap: it never changes the status. `aborted: flaky` (the unmutated suite passed once and failed
|
|
138
|
+
once) is worth reporting as a finding of its own; `checked: false` with its `reason` goes in
|
|
139
|
+
`not_checked` as `check: "mutation"`.
|
|
147
140
|
</step>
|
|
148
141
|
|
|
149
142
|
<step name="establish_must_haves">
|
|
@@ -328,7 +321,7 @@ If human_needed: list items requiring human testing.
|
|
|
328
321
|
|
|
329
322
|
Orchestrator routes: `passed` → update_roadmap | `gaps_found` → create/execute fixes, re-verify | `human_needed` → present to user.
|
|
330
323
|
|
|
331
|
-
**Record the verification.** The record adds its findings to the ledger and logs the outcome to the trace (`verdict_passed`, `verdict_failed` or `verdict_needs_human`). A re-verification is the next attempt
|
|
324
|
+
**Record the verification.** The record adds its findings to the ledger and logs the outcome to the trace (`verdict_passed`, `verdict_failed` or `verdict_needs_human`). A re-verification is the next attempt. It closes the gaps it lists under `re_verification.gaps_closed`; a gap it neither reports nor answers stays open:
|
|
332
325
|
```bash
|
|
333
326
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${phase_number}" --file "$REPORT_PATH" 2>/dev/null || true
|
|
334
327
|
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* Generate /pan:help's command index from command frontmatter (program L5).
|
|
5
|
+
*
|
|
6
|
+
* node scripts/build-help.cjs # print the block
|
|
7
|
+
* node scripts/build-help.cjs --write # rewrite the block in pan-wizard-core/workflows/help.md
|
|
8
|
+
* node scripts/build-help.cjs --check # exit 1 when the committed block is stale
|
|
9
|
+
*
|
|
10
|
+
* The block between GENERATED_START and GENERATED_END in help.md lists every
|
|
11
|
+
* commands/pan/*.md by its frontmatter `group` and `description`, so help cannot leave
|
|
12
|
+
* a command out. tests/help-generated.test.cjs fails when it is stale.
|
|
13
|
+
*/
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const { extractFrontmatter } = require('../pan-wizard-core/bin/lib/frontmatter.cjs');
|
|
17
|
+
|
|
18
|
+
const ROOT = path.join(__dirname, '..');
|
|
19
|
+
const HELP_REL = path.join('pan-wizard-core', 'workflows', 'help.md');
|
|
20
|
+
const GENERATED_START = '<!-- generated:command-index:start (scripts/build-help.cjs --write) -->';
|
|
21
|
+
const GENERATED_END = '<!-- generated:command-index:end -->';
|
|
22
|
+
|
|
23
|
+
// The order a new user reads the groups in; groups not listed follow, alphabetically.
|
|
24
|
+
const GROUP_ORDER = [
|
|
25
|
+
'Getting Started', 'Phase Lifecycle', 'Phase Management', 'Session & Progress',
|
|
26
|
+
'Milestone', 'Milestone Lifecycle', 'Focus', 'Foresight', 'Review', 'Validation',
|
|
27
|
+
'Observability', 'Knowledge', 'Self-Improvement', 'Git Workflow', 'Army',
|
|
28
|
+
'External tools', 'System', 'Community',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
/** Every shipped command as {name, group, description}, sorted by name. */
|
|
32
|
+
function readCommands(root = ROOT) {
|
|
33
|
+
const dir = path.join(root, 'commands', 'pan');
|
|
34
|
+
return fs.readdirSync(dir).filter((f) => f.endsWith('.md')).sort().map((f) => {
|
|
35
|
+
const fm = extractFrontmatter(fs.readFileSync(path.join(dir, f), 'utf-8')) || {};
|
|
36
|
+
return {
|
|
37
|
+
// The file name is the command (`/pan:<file>`); some frontmatter names omit the prefix.
|
|
38
|
+
name: `pan:${f.replace(/\.md$/, '')}`,
|
|
39
|
+
group: String(fm.group || '').trim(),
|
|
40
|
+
description: String(fm.description || '').replace(/\s+/g, ' ').trim(),
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Backslashes first, so one in a description cannot turn the escaped pipe after it back into a cell break.
|
|
46
|
+
const cell = (s) => s.replace(/\\/g, '\\\\').replace(/\|/g, '\\|');
|
|
47
|
+
|
|
48
|
+
/** The markdown command index, grouped. Throws on a command with no group or description. */
|
|
49
|
+
function renderCommandIndex(commands) {
|
|
50
|
+
const groups = new Map();
|
|
51
|
+
for (const c of commands) {
|
|
52
|
+
if (!c.group) throw new Error(`${c.name} has no group in its frontmatter`);
|
|
53
|
+
if (!c.description) throw new Error(`${c.name} has no description in its frontmatter`);
|
|
54
|
+
if (!groups.has(c.group)) groups.set(c.group, []);
|
|
55
|
+
groups.get(c.group).push(c);
|
|
56
|
+
}
|
|
57
|
+
const rank = (g) => { const i = GROUP_ORDER.indexOf(g); return i === -1 ? GROUP_ORDER.length : i; };
|
|
58
|
+
const order = [...groups.keys()].sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
|
|
59
|
+
const out = [];
|
|
60
|
+
for (const g of order) {
|
|
61
|
+
out.push(`### ${g}`, '| Command | Description |', '|---------|-------------|');
|
|
62
|
+
for (const c of groups.get(g).sort((a, b) => a.name.localeCompare(b.name))) out.push(`| \`/${c.name}\` | ${cell(c.description)} |`);
|
|
63
|
+
out.push('');
|
|
64
|
+
}
|
|
65
|
+
return out.join('\n').trimEnd();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The generated block's content in a help.md text, or null when the markers are missing. */
|
|
69
|
+
function extractBlock(text) {
|
|
70
|
+
const t = String(text).replace(/\r\n/g, '\n');
|
|
71
|
+
const a = t.indexOf(GENERATED_START);
|
|
72
|
+
const b = t.indexOf(GENERATED_END);
|
|
73
|
+
if (a === -1 || b === -1 || b < a) return null;
|
|
74
|
+
return t.slice(a + GENERATED_START.length, b).trim();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** help.md with its block replaced by `block`. Throws when the markers are missing. */
|
|
78
|
+
function replaceBlock(text, block) {
|
|
79
|
+
const t = String(text).replace(/\r\n/g, '\n');
|
|
80
|
+
const a = t.indexOf(GENERATED_START);
|
|
81
|
+
const b = t.indexOf(GENERATED_END);
|
|
82
|
+
if (a === -1 || b === -1 || b < a) throw new Error(`${HELP_REL} has no generated command-index markers`);
|
|
83
|
+
return t.slice(0, a + GENERATED_START.length) + '\n' + block + '\n' + t.slice(b);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function main(argv) {
|
|
87
|
+
const file = path.join(ROOT, HELP_REL);
|
|
88
|
+
const block = renderCommandIndex(readCommands(ROOT));
|
|
89
|
+
if (argv.includes('--write')) {
|
|
90
|
+
fs.writeFileSync(file, replaceBlock(fs.readFileSync(file, 'utf-8'), block));
|
|
91
|
+
process.stdout.write(`wrote the command index into ${HELP_REL}\n`);
|
|
92
|
+
} else if (argv.includes('--check')) {
|
|
93
|
+
if (extractBlock(fs.readFileSync(file, 'utf-8')) !== block) {
|
|
94
|
+
process.stderr.write(`${HELP_REL}'s command index is stale: run node scripts/build-help.cjs --write\n`);
|
|
95
|
+
process.exitCode = 1;
|
|
96
|
+
} else {
|
|
97
|
+
process.stdout.write(`${HELP_REL}'s command index is up to date\n`);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
process.stdout.write(block + '\n');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (require.main === module) main(process.argv.slice(2));
|
|
105
|
+
|
|
106
|
+
module.exports = { GROUP_ORDER, GENERATED_START, GENERATED_END, readCommands, renderCommandIndex, extractBlock, replaceBlock };
|
package/scripts/build-hooks.js
CHANGED
|
@@ -391,11 +391,11 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
391
391
|
w(s.description)
|
|
392
392
|
w("")
|
|
393
393
|
if s.argument_hint:
|
|
394
|
-
w(
|
|
394
|
+
w("```text")
|
|
395
395
|
w(f"{s.command} {s.argument_hint}")
|
|
396
396
|
w(f"```")
|
|
397
397
|
else:
|
|
398
|
-
w(
|
|
398
|
+
w("```text")
|
|
399
399
|
w(f"{s.command}")
|
|
400
400
|
w(f"```")
|
|
401
401
|
w("")
|