pan-wizard 3.5.1 → 3.7.10
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 +10 -10
- package/agents/pan-executor.md +18 -0
- package/agents/pan-experiment-runner.md +126 -0
- package/agents/pan-phase-researcher.md +16 -0
- package/agents/pan-plan-checker.md +80 -0
- package/agents/pan-planner.md +19 -0
- package/agents/pan-reviewer.md +2 -0
- package/agents/pan-verifier.md +41 -0
- package/bin/install-lib.cjs +55 -0
- package/bin/install.js +71 -22
- package/commands/pan/debug.md +1 -1
- package/commands/pan/experiment.md +219 -0
- package/commands/pan/health.md +1 -1
- package/commands/pan/learn.md +15 -1
- package/commands/pan/optimize.md +13 -0
- package/commands/pan/patches.md +10 -1
- package/commands/pan/phase-tests.md +1 -4
- package/commands/pan/todo-add.md +1 -1
- package/commands/pan/todo-check.md +1 -1
- package/hooks/dist/pan-cost-logger.js +54 -4
- package/hooks/dist/pan-trace-logger.js +72 -3
- package/package.json +67 -66
- package/pan-wizard-core/bin/lib/commands.cjs +8 -0
- package/pan-wizard-core/bin/lib/config.cjs +13 -2
- package/pan-wizard-core/bin/lib/context-budget.cjs +73 -0
- package/pan-wizard-core/bin/lib/core.cjs +13 -0
- package/pan-wizard-core/bin/lib/doc-lint/frontmatter.js +270 -0
- package/pan-wizard-core/bin/lib/doc-lint/reporter.js +45 -0
- package/pan-wizard-core/bin/lib/doc-lint/schema.js +202 -0
- package/pan-wizard-core/bin/lib/doc-lint/validate.js +190 -0
- package/pan-wizard-core/bin/lib/doc-lint/walk.js +135 -0
- package/pan-wizard-core/bin/lib/doc-lint.cjs +287 -0
- package/pan-wizard-core/bin/lib/experiment.cjs +501 -0
- package/pan-wizard-core/bin/lib/learn-index.cjs +235 -0
- package/pan-wizard-core/bin/lib/learn-lint.cjs +292 -0
- package/pan-wizard-core/bin/lib/optimize.cjs +474 -1
- package/pan-wizard-core/bin/lib/runner.cjs +472 -0
- package/pan-wizard-core/bin/pan-tools.cjs +222 -2
- package/pan-wizard-core/learnings/README.md +70 -0
- package/pan-wizard-core/learnings/index.json +540 -0
- package/pan-wizard-core/learnings/internal/.gitkeep +2 -0
- package/pan-wizard-core/learnings/internal/experiment-runner.md +81 -0
- package/pan-wizard-core/learnings/internal/external-research.md +93 -0
- package/pan-wizard-core/learnings/internal/loop-design.md +33 -0
- package/pan-wizard-core/learnings/internal/pan-dev-bugs.md +181 -0
- package/pan-wizard-core/learnings/universal/.gitkeep +2 -0
- package/pan-wizard-core/learnings/universal/atomic-state.md +21 -0
- package/pan-wizard-core/learnings/universal/binary-io.md +21 -0
- package/pan-wizard-core/learnings/universal/comment-syntax.md +21 -0
- package/pan-wizard-core/learnings/universal/composition.md +33 -0
- package/pan-wizard-core/learnings/universal/concurrency.md +33 -0
- package/pan-wizard-core/learnings/universal/dag-scheduler.md +33 -0
- package/pan-wizard-core/learnings/universal/data-driven-design.md +21 -0
- package/pan-wizard-core/learnings/universal/design-process.md +21 -0
- package/pan-wizard-core/learnings/universal/empirical-spike.md +21 -0
- package/pan-wizard-core/learnings/universal/error-handling.md +23 -0
- package/pan-wizard-core/learnings/universal/error-paths.md +21 -0
- package/pan-wizard-core/learnings/universal/glob-semantics.md +21 -0
- package/pan-wizard-core/learnings/universal/idempotency.md +21 -0
- package/pan-wizard-core/learnings/universal/invariants.md +21 -0
- package/pan-wizard-core/learnings/universal/io-patterns.md +21 -0
- package/pan-wizard-core/learnings/universal/numeric-edge-cases.md +21 -0
- package/pan-wizard-core/learnings/universal/output-conventions.md +21 -0
- package/pan-wizard-core/learnings/universal/parser-design.md +21 -0
- package/pan-wizard-core/learnings/universal/phase-locking.md +21 -0
- package/pan-wizard-core/learnings/universal/pipe-friendly-cli.md +21 -0
- package/pan-wizard-core/learnings/universal/schema-design.md +21 -0
- package/pan-wizard-core/learnings/universal/secret-handling.md +21 -0
- package/pan-wizard-core/learnings/universal/streaming-io.md +21 -0
- package/pan-wizard-core/learnings/universal/test-patterns.md +57 -0
- package/pan-wizard-core/learnings/universal/test-strategy.md +33 -0
- package/pan-wizard-core/learnings/universal/unicode.md +21 -0
- package/pan-wizard-core/learnings/universal/vendor-pattern.md +21 -0
- package/pan-wizard-core/references/guardrails.md +58 -0
- package/pan-wizard-core/references/handoff-decisions.md +156 -0
- package/pan-wizard-core/references/schemas/pan-command.schema.yml +39 -0
- package/pan-wizard-core/references/verification-patterns.md +31 -0
- package/pan-wizard-core/templates/config.json +2 -1
- package/pan-wizard-core/templates/idea.md +52 -0
- package/pan-wizard-core/templates/summary-complex.md +14 -5
- package/pan-wizard-core/templates/summary-minimal.md +6 -0
- package/pan-wizard-core/templates/summary-standard.md +14 -3
- package/pan-wizard-core/workflows/discuss-phase.md +108 -1
- package/pan-wizard-core/workflows/exec-phase.md +37 -1
- package/pan-wizard-core/workflows/execute-plan.md +14 -0
- package/pan-wizard-core/workflows/health.md +23 -0
- package/pan-wizard-core/workflows/new-project.md +65 -81
- package/pan-wizard-core/workflows/plan-phase.md +58 -0
- package/pan-wizard-core/workflows/transition.md +102 -7
- package/pan-wizard-core/workflows/verify-phase.md +14 -0
- package/scripts/build-hooks.js +7 -1
- package/scripts/generate-skills-docs.py +10 -8
- package/scripts/release-check.js +184 -0
|
@@ -6,8 +6,32 @@ Create executable phase prompts (plan.md files) for a roadmap phase with integra
|
|
|
6
6
|
Read all files referenced by the invoking prompt's execution_context before starting.
|
|
7
7
|
|
|
8
8
|
@~/.claude/pan-wizard-core/references/ui-brand.md
|
|
9
|
+
@~/.claude/pan-wizard-core/references/guardrails.md
|
|
10
|
+
|
|
11
|
+
> **Also see:** `~/.claude/pan-wizard-core/learnings/universal/` — AI-derived patterns from prior experiments. **Don't skim the whole folder.** Run `pan-tools learn topics-for --agent planner --token-budget 5000 --raw` to load only the topics tagged relevant for planning at the configured budget. Per P-RES-002 (distractor-density research), reading every topic degrades reasoning even at modest token counts.
|
|
9
12
|
</required_reading>
|
|
10
13
|
|
|
14
|
+
## Phase 0 — Clarify Phase Scope (recommended)
|
|
15
|
+
|
|
16
|
+
Before drafting the phase plan, confirm:
|
|
17
|
+
|
|
18
|
+
1. **What does "complete" look like for this phase?**
|
|
19
|
+
2. **What's deliberately out of scope?**
|
|
20
|
+
3. **Any constraints or dependencies on other phases?**
|
|
21
|
+
|
|
22
|
+
If the answers aren't already in `.planning/requirements.md` or the phase context file, ask the user. A 2-minute clarification prevents 30-minute rework downstream.
|
|
23
|
+
|
|
24
|
+
## Re-Read Checkpoints
|
|
25
|
+
|
|
26
|
+
Context compaction may have dropped earlier sections. Re-read the relevant section *before* you begin each step — not after you hit a problem.
|
|
27
|
+
|
|
28
|
+
| Before this step | Re-read | Why |
|
|
29
|
+
|------------------|---------|-----|
|
|
30
|
+
| Writing the plan | This workflow's "Plan structure" section | Plan format drifts across long sessions |
|
|
31
|
+
| Spawning the planner agent | `references/guardrails.md` | Code Preservation Principle applies to all generated code |
|
|
32
|
+
| Reviewing planner output | `references/checkpoints.md` | Checkpoint conventions are easy to misremember |
|
|
33
|
+
| Marking plan ready | `workflows/exec-phase.md` | The downstream consumer's expectations matter |
|
|
34
|
+
|
|
11
35
|
<process>
|
|
12
36
|
|
|
13
37
|
## 1. Initialize
|
|
@@ -152,6 +176,28 @@ If `context_path` is not null, display: `Using phase context from: ${context_pat
|
|
|
152
176
|
|
|
153
177
|
**If `context_path` is null (no context.md exists):**
|
|
154
178
|
|
|
179
|
+
**P-1802 fix (v3.7.7):** in `--auto` mode (or when `workflow.auto_advance` is true) **do not call `AskUserQuestion`** and **do not attempt to spawn `discuss-phase` either** (discuss-phase has its own unguarded AskUserQuestion calls deeper in the workflow — they exit headless `claude -p` immediately). Instead, **proceed without a context.md**: the planner derives implementation decisions from project-level research, requirements, and the original idea.md frontmatter.
|
|
180
|
+
|
|
181
|
+
This trades user-design-input quality for autonomous reliability — in auto mode the user has already encoded their preferences in idea.md / project.md / requirements.md, so a missing per-phase context.md is acceptable. Surfaced when wookie's Phase 3 was launched directly with `/pan:plan-phase 3 --auto` (no Phase 3 context.md yet) and `/pan:discuss-phase 3 --auto` (which itself exited): both exited in 40-75 seconds with zero commits before this fix. Same root pattern as P-1301 which removed AskUserQuestion from `new-project.md`'s auto block.
|
|
182
|
+
|
|
183
|
+
**Auto-mode decision (no user prompt):**
|
|
184
|
+
|
|
185
|
+
If `--auto` flag is present in `$ARGUMENTS` OR `workflow.auto_advance` is `true` in config:
|
|
186
|
+
|
|
187
|
+
1. Log a `decision` trace event:
|
|
188
|
+
```bash
|
|
189
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
|
|
190
|
+
--type decision --category skip-context-auto \
|
|
191
|
+
--description "Phase ${PHASE} P-1802 bypass: no context.md, proceeding with research+requirements+idea only" \
|
|
192
|
+
--agent orchestrator --impact minor 2>/dev/null || true
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
2. Display: `Auto-mode: no Phase ${PHASE} context.md — planning from project-level research + requirements + idea.md`
|
|
196
|
+
|
|
197
|
+
3. Proceed to step 5 (Handle Research). The `pan-planner` agent reads project-level `.planning/research/architecture.md`, `features.md`, `stack.md` and the original `.planning/idea.md` to derive phase-scoped decisions itself.
|
|
198
|
+
|
|
199
|
+
**Interactive-mode decision tree (the original behavior; runs when neither `--auto` nor `workflow.auto_advance` is set):**
|
|
200
|
+
|
|
155
201
|
Use AskUserQuestion:
|
|
156
202
|
- header: "No context"
|
|
157
203
|
- question: "No context.md found for Phase {X}. Plans will use research and requirements only — your design preferences won't be included. Continue or capture context first?"
|
|
@@ -166,6 +212,18 @@ If "Run discuss-phase first": Display `/pan:discuss-phase {X}` and exit workflow
|
|
|
166
212
|
|
|
167
213
|
**Skip if:** `--gaps` flag, `--skip-research` flag, or `research_enabled` is false (from init) without `--research` override.
|
|
168
214
|
|
|
215
|
+
**P-1401 lightweight-phase bypass (v3.7.3+):** Also skip per-phase research when ALL three are true:
|
|
216
|
+
|
|
217
|
+
1. The phase has only **1 plan** (read `plan_count` from init JSON)
|
|
218
|
+
2. The plan's `change_class` is in `[chore, docs, feat-trivial]` (i.e., scaffolding, config, single-file feat with ≤3 tasks)
|
|
219
|
+
3. Project-level `research/architecture.md`, `features.md`, `stack.md` already exist (so the planner has broad context to draw from)
|
|
220
|
+
|
|
221
|
+
In that case, log a `decision` trace event (`type: "decision", category: "skip-research-trivial"`) and proceed directly to step 6 (planning). Saves ~3 commits and ~5 minutes per trivial phase. Surfaced by panloop run: Phase 1 (project setup, scaffolding only) over-ceremonialized.
|
|
222
|
+
|
|
223
|
+
This is a workflow-level optimization — the planner still produces a plan, just without per-phase research.md. Phase 2+ phases with substantive build work still go through full research.
|
|
224
|
+
|
|
225
|
+
**P-1602 phase_record_compact (v3.7.5+):** When `workflow.phase_record_compact: true` AND the lightweight-phase bypass above triggers, also skip per-phase context.md creation (step 4) and emit a single combined `${PHASE_NUM}-record.md` after planning containing: goal, locked decisions (from project-level context), plan summary, must_haves. Reduces 4-file phase output (context, research, plan, summary) to a 2-file output (record, plan) for trivial phases. Off by default — opt-in via `pan-tools config-set workflow.phase_record_compact true`. Substantive phases (>1 plan or non-trivial change_class) still produce full per-phase artifacts regardless of this flag.
|
|
226
|
+
|
|
169
227
|
**If `has_research` is true (from init) AND no `--research` flag:** Use existing, skip to step 6.
|
|
170
228
|
|
|
171
229
|
**If research.md missing OR `--research` flag:**
|
|
@@ -18,6 +18,24 @@ Mark current phase complete and advance to next. This is the natural point where
|
|
|
18
18
|
|
|
19
19
|
</purpose>
|
|
20
20
|
|
|
21
|
+
<state_write_policy>
|
|
22
|
+
|
|
23
|
+
**P-1604 (v3.7.5) — batch state.md writes.** This workflow contains 5 logically separate state.md updates: position, progress bar, Project Reference, Accumulated Context, Session Continuity. Earlier versions wrote each as its own edit + commit, which produced 5 commits per transition (visible as state-file thrash in trace logs).
|
|
24
|
+
|
|
25
|
+
**Required pattern from v3.7.5 onward:**
|
|
26
|
+
|
|
27
|
+
1. Run the steps below to *plan* each state.md update, but **do not write or commit** between them. Hold the changes in memory.
|
|
28
|
+
2. After `update_session_continuity_after_transition` (the last state.md-touching step before `offer_next_phase`), perform a **single Edit** that applies all four section updates (Project Reference, Accumulated Context, Session Continuity, plus the progress bar from `update_current_position_after_transition`).
|
|
29
|
+
3. Then issue **one** commit:
|
|
30
|
+
```bash
|
|
31
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs commit "docs(transition): phase ${current_phase} → ${next_phase} (state, progress, context)"
|
|
32
|
+
```
|
|
33
|
+
The `phase complete` call inside `update_roadmap_and_state` makes its own commit (roadmap + state position) — that one stays separate, since it must run first to compute `next_phase`.
|
|
34
|
+
|
|
35
|
+
Net result per transition: 2 commits instead of 5. Reduces git noise and keeps `/pan:learn` overhead metrics (commits_per_minute) honest. Substantive content of each step below is unchanged — only the **timing of the write** changes.
|
|
36
|
+
|
|
37
|
+
</state_write_policy>
|
|
38
|
+
|
|
21
39
|
<process>
|
|
22
40
|
|
|
23
41
|
<step name="load_project_state" priority="first">
|
|
@@ -317,6 +335,14 @@ After (if database indexing was addressed in Phase 2):
|
|
|
317
335
|
|
|
318
336
|
Update Session Continuity section in state.md to reflect transition completion.
|
|
319
337
|
|
|
338
|
+
**P-1804 fix (v3.7.8):** the "Stopped at" line is mirrored into the frontmatter `stopped_at:` field by `syncStateFrontmatter()`. Direct `Edit` on the body alone leaves frontmatter and body out of sync — that's why the wookie run's frontmatter still showed `"Phase 1 plan 01-01 executed, awaiting verification"` after Phase 5 completed. **Use `pan-tools state update` for "Stopped at"** so the frontmatter resyncs automatically; the other two lines (Last session, Resume file) have no frontmatter mirror and can be edited directly.
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Stopped at" "Phase ${current_phase} complete, ready to plan Phase ${next_phase}"
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Then Edit state.md (still under the P-1604 batched-write policy — fold this Edit into the final batched Edit at the end of the workflow):
|
|
345
|
+
|
|
320
346
|
**Format:**
|
|
321
347
|
|
|
322
348
|
```markdown
|
|
@@ -328,7 +354,7 @@ Resume file: None
|
|
|
328
354
|
**Step complete when:**
|
|
329
355
|
|
|
330
356
|
- [ ] Last session timestamp updated to current date and time
|
|
331
|
-
- [ ] Stopped at
|
|
357
|
+
- [ ] Stopped at field updated **via `pan-tools state update`** (not raw Edit) so the frontmatter `stopped_at` field stays in sync
|
|
332
358
|
- [ ] Resume file confirmed as None (transitions don't use resume files)
|
|
333
359
|
|
|
334
360
|
</step>
|
|
@@ -368,29 +394,98 @@ ls .planning/phases/*[X+1]*/*-context.md 2>/dev/null
|
|
|
368
394
|
|
|
369
395
|
<if mode="yolo">
|
|
370
396
|
|
|
371
|
-
**
|
|
397
|
+
**P-1801 fix (v3.7.6):** In auto mode, **spawn the next phase as a Task subagent** — same pattern as `plan-phase.md`'s auto-advance to exec-phase. Prose-based "DO NOT exit. Read X" instructions (the v3.7.4 P-1701 attempt) were not behaviorally binding: the orchestrator returned from sub-agent calls and exited cleanly at the phase boundary. A `Task(...)` invocation is a tool call the orchestrator cannot ignore — control flow is forced into the next phase's workflow.
|
|
398
|
+
|
|
399
|
+
Cost trade-off: each Task spawn restarts context (loses the cumulative cache reads from the previous phase). Acceptable because: (1) cross-phase cache value is low — phase N's plan/research is mostly irrelevant to phase N+1's executor — and (2) reliability beats marginal cost optimization for autonomous runs.
|
|
400
|
+
|
|
401
|
+
**If context.md exists for the next phase:**
|
|
372
402
|
|
|
403
|
+
Display:
|
|
373
404
|
```
|
|
374
405
|
Phase [X] marked complete.
|
|
375
406
|
|
|
376
407
|
Next: Phase [X+1] — [Name]
|
|
377
408
|
|
|
378
|
-
⚡ Auto-
|
|
409
|
+
⚡ Auto-spawning Phase [X+1] planning...
|
|
379
410
|
```
|
|
380
411
|
|
|
381
|
-
|
|
412
|
+
Then spawn the next phase as a Task subagent — do NOT call SlashCommand or attempt in-context continuation:
|
|
382
413
|
|
|
383
|
-
|
|
414
|
+
```
|
|
415
|
+
Task(
|
|
416
|
+
prompt="
|
|
417
|
+
<objective>
|
|
418
|
+
You are the plan-phase orchestrator. Plan all work for Phase ${NEXT_PHASE}: ${NEXT_PHASE_NAME}.
|
|
419
|
+
</objective>
|
|
420
|
+
|
|
421
|
+
<execution_context>
|
|
422
|
+
@~/.claude/pan-wizard-core/workflows/plan-phase.md
|
|
423
|
+
@~/.claude/pan-wizard-core/references/guardrails.md
|
|
424
|
+
@~/.claude/pan-wizard-core/references/model-profile-resolution.md
|
|
425
|
+
</execution_context>
|
|
426
|
+
|
|
427
|
+
<arguments>
|
|
428
|
+
PHASE=${NEXT_PHASE}
|
|
429
|
+
ARGUMENTS='${NEXT_PHASE} --auto'
|
|
430
|
+
</arguments>
|
|
431
|
+
|
|
432
|
+
<instructions>
|
|
433
|
+
1. Read plan-phase.md from execution_context for your complete workflow.
|
|
434
|
+
2. Follow ALL steps: initialize, validate_phase, load context.md, handle research (P-1401 bypass if applicable), spawn pan-planner, optionally spawn pan-plan-checker, then auto-advance to exec-phase via Task (per plan-phase.md step 14).
|
|
435
|
+
3. After exec-phase completes and verification passes, exec-phase will return to its own auto-advance handler which spawns transition.md — that transition will spawn Phase ${NEXT_PHASE}+1 via this same pattern, recursing until milestone-done.
|
|
436
|
+
4. Do NOT use the Skill tool or /pan: commands. Do NOT exit early — let the recursion run.
|
|
437
|
+
</instructions>
|
|
438
|
+
",
|
|
439
|
+
subagent_type="general-purpose",
|
|
440
|
+
description="Plan Phase ${NEXT_PHASE}"
|
|
441
|
+
)
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**If context.md does NOT exist for the next phase:**
|
|
384
445
|
|
|
446
|
+
Display:
|
|
385
447
|
```
|
|
386
448
|
Phase [X] marked complete.
|
|
387
449
|
|
|
388
450
|
Next: Phase [X+1] — [Name]
|
|
389
451
|
|
|
390
|
-
⚡ Auto-
|
|
452
|
+
⚡ Auto-spawning Phase [X+1] discussion (no context.md)...
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Then spawn discuss-phase as a Task subagent:
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
Task(
|
|
459
|
+
prompt="
|
|
460
|
+
<objective>
|
|
461
|
+
You are the discuss-phase orchestrator. Capture decisions for Phase ${NEXT_PHASE}: ${NEXT_PHASE_NAME}, then auto-advance to plan-phase.
|
|
462
|
+
</objective>
|
|
463
|
+
|
|
464
|
+
<execution_context>
|
|
465
|
+
@~/.claude/pan-wizard-core/workflows/discuss-phase.md
|
|
466
|
+
@~/.claude/pan-wizard-core/references/questioning.md
|
|
467
|
+
</execution_context>
|
|
468
|
+
|
|
469
|
+
<arguments>
|
|
470
|
+
PHASE=${NEXT_PHASE}
|
|
471
|
+
ARGUMENTS='${NEXT_PHASE} --auto'
|
|
472
|
+
</arguments>
|
|
473
|
+
|
|
474
|
+
<instructions>
|
|
475
|
+
1. Read discuss-phase.md from execution_context for your complete workflow.
|
|
476
|
+
2. In --auto mode, use sensible defaults rather than blocking on AskUserQuestion (P-1301 pattern).
|
|
477
|
+
3. After context.md is captured, auto-advance to plan-phase via Task spawn (the discuss-phase auto-advance step handles this).
|
|
478
|
+
4. Do NOT use the Skill tool or /pan: commands. Do NOT exit early.
|
|
479
|
+
</instructions>
|
|
480
|
+
",
|
|
481
|
+
subagent_type="general-purpose",
|
|
482
|
+
description="Discuss Phase ${NEXT_PHASE}"
|
|
483
|
+
)
|
|
391
484
|
```
|
|
392
485
|
|
|
393
|
-
|
|
486
|
+
**Handle next-phase Task return:**
|
|
487
|
+
- **PHASE COMPLETE** (the spawned chain reached verification + roadmap update for ${NEXT_PHASE} and beyond, and either hit milestone-done or recursed further) → Done. Workflow chain finished.
|
|
488
|
+
- **GAPS FOUND / FAILED / TIMEOUT** → Display the failure, stop the recursion, return status to user. Do NOT attempt to skip ahead.
|
|
394
489
|
|
|
395
490
|
</if>
|
|
396
491
|
|
|
@@ -19,9 +19,23 @@ Then verify each level against the actual codebase.
|
|
|
19
19
|
|
|
20
20
|
<required_reading>
|
|
21
21
|
@~/.claude/pan-wizard-core/references/verification-patterns.md
|
|
22
|
+
@~/.claude/pan-wizard-core/references/guardrails.md
|
|
22
23
|
@~/.claude/pan-wizard-core/templates/verification-report.md
|
|
24
|
+
|
|
25
|
+
> **Also see:** `~/.claude/pan-wizard-core/learnings/universal/` — AI-derived patterns from prior experiments. **Don't skim the whole folder.** Run `pan-tools learn topics-for --agent verifier --token-budget 5000 --raw` to load only the topics tagged relevant for verification at the configured budget. Per P-RES-002 (distractor-density research), reading every topic degrades reasoning even at modest token counts.
|
|
23
26
|
</required_reading>
|
|
24
27
|
|
|
28
|
+
## Re-Read Checkpoints
|
|
29
|
+
|
|
30
|
+
Context compaction may have dropped earlier sections. Re-read the relevant section *before* you begin each step — not after you hit a problem.
|
|
31
|
+
|
|
32
|
+
| Before this step | Re-read | Why |
|
|
33
|
+
|------------------|---------|-----|
|
|
34
|
+
| Running test suite | `references/guardrails.md` Stop-the-Line rule | Test regressions block phase completion — do not paper over |
|
|
35
|
+
| Verifying truths/artifacts | This workflow's `<core_principle>` | Goal-backward analysis is easy to skip under time pressure |
|
|
36
|
+
| Determining final status | This workflow's `<step name="determine_status">` | Status criteria (passed / gaps_found / human_needed) are precise |
|
|
37
|
+
| Writing verification report | `templates/verification-report.md` | Report shape is checked downstream |
|
|
38
|
+
|
|
25
39
|
<process>
|
|
26
40
|
|
|
27
41
|
<step name="load_context" priority="first">
|
package/scripts/build-hooks.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Copy PAN hooks to dist for installation.
|
|
3
|
+
* Copy PAN hooks from hooks/ to hooks/dist/ for installation.
|
|
4
|
+
*
|
|
5
|
+
* This is COPY-ONLY. PAN's hooks are pure Node.js with zero runtime
|
|
6
|
+
* dependencies, so no bundling step is needed. The script is named
|
|
7
|
+
* "build-hooks" for npm-script convention, but the work is `cp`.
|
|
8
|
+
*
|
|
9
|
+
* (See docs/IMPROVEMENT-TODO.md P2 for the rationale.)
|
|
4
10
|
*/
|
|
5
11
|
|
|
6
12
|
const fs = require('fs');
|
|
@@ -232,13 +232,14 @@ def generate_full_text(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
232
232
|
w("Every skill (slash command) available in PAN Wizard, reproduced in full.")
|
|
233
233
|
w("This is the actual prompt text that Claude receives when a skill is invoked.")
|
|
234
234
|
w("")
|
|
235
|
-
w(f"**Version:** {version}
|
|
235
|
+
w(f"**Version:** {version}")
|
|
236
236
|
w("")
|
|
237
237
|
w("> Auto-generated by `scripts/generate-skills-docs.py` — do not edit manually.")
|
|
238
|
+
w("> For canonical counts (commands / agents / modules / etc.), see `CLAUDE.md`.")
|
|
238
239
|
w("")
|
|
239
240
|
w("---")
|
|
240
241
|
w("")
|
|
241
|
-
w(
|
|
242
|
+
w("## Part 1: Shipped Skills")
|
|
242
243
|
w("")
|
|
243
244
|
w("These are installed into host projects via the PAN installer.")
|
|
244
245
|
|
|
@@ -256,7 +257,7 @@ def generate_full_text(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
256
257
|
w("")
|
|
257
258
|
w("---")
|
|
258
259
|
w("")
|
|
259
|
-
w(
|
|
260
|
+
w("## Part 2: Dev Skills")
|
|
260
261
|
w("")
|
|
261
262
|
w("These exist only in the PAN source repository and are NOT shipped to end users.")
|
|
262
263
|
|
|
@@ -329,9 +330,10 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
329
330
|
w("Complete catalog of every skill (slash command) available in PAN Wizard, organized by purpose.")
|
|
330
331
|
w("Each entry shows the command, what it does, what tools it uses, and when to reach for it.")
|
|
331
332
|
w("")
|
|
332
|
-
w(f"**Version:** {version}
|
|
333
|
+
w(f"**Version:** {version}")
|
|
333
334
|
w("")
|
|
334
335
|
w("> Auto-generated by `scripts/generate-skills-docs.py` — do not edit manually.")
|
|
336
|
+
w("> For canonical counts (commands / agents / modules / etc.), see `CLAUDE.md`.")
|
|
335
337
|
w("")
|
|
336
338
|
w("---")
|
|
337
339
|
w("")
|
|
@@ -346,11 +348,11 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
346
348
|
|
|
347
349
|
w("## Table of Contents")
|
|
348
350
|
w("")
|
|
349
|
-
w(
|
|
351
|
+
w("- [Shipped Skills](#shipped-skills) — installed into host projects")
|
|
350
352
|
for g in ordered_groups:
|
|
351
353
|
anchor = g.lower().replace(" & ", "--").replace(" ", "-")
|
|
352
354
|
w(f" - [{g}](#{anchor})")
|
|
353
|
-
w(
|
|
355
|
+
w("- [Dev Skills](#dev-skills) — PAN source repo only")
|
|
354
356
|
for cat in DEV_CATEGORIES:
|
|
355
357
|
anchor = cat.lower().replace(" & ", "--").replace(" ", "-")
|
|
356
358
|
w(f" - [{cat}](#{anchor})")
|
|
@@ -359,7 +361,7 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
359
361
|
w("")
|
|
360
362
|
|
|
361
363
|
# ── Shipped Skills ──
|
|
362
|
-
w(
|
|
364
|
+
w("## Shipped Skills")
|
|
363
365
|
w("")
|
|
364
366
|
w("These are installed into host projects via the PAN installer and available to end users.")
|
|
365
367
|
w("")
|
|
@@ -401,7 +403,7 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
|
|
|
401
403
|
w("")
|
|
402
404
|
|
|
403
405
|
# ── Dev Skills ──
|
|
404
|
-
w(
|
|
406
|
+
w("## Dev Skills")
|
|
405
407
|
w("")
|
|
406
408
|
w("These exist only in the PAN source repository (`.claude/commands/`) and are NOT shipped to end users.")
|
|
407
409
|
w("")
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* release-check.js — Pre-publish validation gate.
|
|
4
|
+
*
|
|
5
|
+
* Wired into `prepublishOnly` so `npm publish` fails BEFORE upload if any
|
|
6
|
+
* gate is red. Runs five checks in order; first failure aborts.
|
|
7
|
+
*
|
|
8
|
+
* 1. build:hooks — hook scripts copy/build cleanly
|
|
9
|
+
* 2. test:all — full test suite (unit + scenario) passes
|
|
10
|
+
* 3. npm audit — no known vulnerabilities in production deps
|
|
11
|
+
* (we have zero runtime deps, but esbuild dev-dep is checked)
|
|
12
|
+
* 4. doc-lint counts — no drift-prone count violations in user-facing docs
|
|
13
|
+
* 5. npm pack dry-run — package builds; size is sane
|
|
14
|
+
* 6. smoke install — npm pack + install into temp dir + run pan-tools list
|
|
15
|
+
* catches "ships but doesn't actually work" failures
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* node scripts/release-check.js # all gates
|
|
19
|
+
* node scripts/release-check.js --skip-audit # skip audit (use carefully)
|
|
20
|
+
* node scripts/release-check.js --skip-smoke # skip pack+install (faster)
|
|
21
|
+
*
|
|
22
|
+
* Exit code 0 = all clear; non-zero = a gate failed (see stderr).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const { execFileSync, spawnSync } = require('child_process');
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const path = require('path');
|
|
30
|
+
const os = require('os');
|
|
31
|
+
|
|
32
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
33
|
+
const ARGS = process.argv.slice(2);
|
|
34
|
+
const SKIP_AUDIT = ARGS.includes('--skip-audit');
|
|
35
|
+
const SKIP_SMOKE = ARGS.includes('--skip-smoke');
|
|
36
|
+
|
|
37
|
+
const checks = [];
|
|
38
|
+
let failed = false;
|
|
39
|
+
|
|
40
|
+
function logGate(name, ok, detail = '') {
|
|
41
|
+
const mark = ok ? 'OK' : 'FAIL';
|
|
42
|
+
const line = `[release-check] ${mark} ${name}${detail ? ' — ' + detail : ''}`;
|
|
43
|
+
process.stderr.write(line + '\n');
|
|
44
|
+
checks.push({ name, ok, detail });
|
|
45
|
+
if (!ok) failed = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function run(cmd, args, opts = {}) {
|
|
49
|
+
return spawnSync(cmd, args, {
|
|
50
|
+
cwd: REPO_ROOT,
|
|
51
|
+
stdio: opts.capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
|
|
52
|
+
encoding: 'utf-8',
|
|
53
|
+
shell: process.platform === 'win32',
|
|
54
|
+
...opts,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Gate 1: build:hooks
|
|
59
|
+
process.stderr.write('\n[release-check] Gate 1/6: build:hooks\n');
|
|
60
|
+
{
|
|
61
|
+
const r = run('npm', ['run', 'build:hooks']);
|
|
62
|
+
logGate('build:hooks', r.status === 0, r.status !== 0 ? `exit ${r.status}` : '');
|
|
63
|
+
if (failed) process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Gate 2: test:all
|
|
67
|
+
process.stderr.write('\n[release-check] Gate 2/6: test:all\n');
|
|
68
|
+
{
|
|
69
|
+
const r = run('npm', ['run', 'test:all']);
|
|
70
|
+
logGate('test:all', r.status === 0, r.status !== 0 ? `exit ${r.status}` : '');
|
|
71
|
+
if (failed) process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Gate 3: npm audit (production deps only)
|
|
75
|
+
if (SKIP_AUDIT) {
|
|
76
|
+
process.stderr.write('\n[release-check] Gate 3/6: npm audit (SKIPPED)\n');
|
|
77
|
+
} else {
|
|
78
|
+
process.stderr.write('\n[release-check] Gate 3/6: npm audit --omit=dev\n');
|
|
79
|
+
const r = run('npm', ['audit', '--omit=dev', '--audit-level=high'], { capture: true });
|
|
80
|
+
// npm audit exits non-zero on findings. We tolerate moderate; fail on high+.
|
|
81
|
+
const ok = r.status === 0;
|
|
82
|
+
logGate('npm audit', ok, ok ? 'no high-severity findings' : `exit ${r.status} — high or critical CVEs in production deps`);
|
|
83
|
+
if (!ok) {
|
|
84
|
+
process.stderr.write((r.stdout || '') + '\n' + (r.stderr || '') + '\n');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Gate 4: doc-lint counts on user-facing docs (count-SSoT enforcement)
|
|
90
|
+
process.stderr.write('\n[release-check] Gate 4/6: doc-lint counts docs/\n');
|
|
91
|
+
{
|
|
92
|
+
const tools = path.join(REPO_ROOT, 'pan-wizard-core', 'bin', 'pan-tools.cjs');
|
|
93
|
+
const docsDir = path.join(REPO_ROOT, 'docs');
|
|
94
|
+
const r = run('node', [tools, 'doc-lint', 'counts', docsDir, '--raw'], { capture: true });
|
|
95
|
+
const ok = r.status === 0;
|
|
96
|
+
logGate('doc-lint counts', ok, ok ? 'no count violations in docs/' : 'drift-prone counts found outside CLAUDE.md');
|
|
97
|
+
if (!ok) {
|
|
98
|
+
process.stderr.write((r.stdout || '') + '\n');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Gate 5: npm pack dry-run
|
|
104
|
+
process.stderr.write('\n[release-check] Gate 5/6: npm pack --dry-run\n');
|
|
105
|
+
{
|
|
106
|
+
const r = run('npm', ['pack', '--dry-run', '--json'], { capture: true });
|
|
107
|
+
if (r.status !== 0) {
|
|
108
|
+
logGate('npm pack dry-run', false, `exit ${r.status}`);
|
|
109
|
+
process.stderr.write((r.stderr || '') + '\n');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
// Parse the JSON output to check size
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(r.stdout);
|
|
115
|
+
const entry = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
116
|
+
const size = entry.size || 0;
|
|
117
|
+
const fileCount = entry.files ? entry.files.length : 0;
|
|
118
|
+
const sizeMB = (size / 1024 / 1024).toFixed(2);
|
|
119
|
+
// Flag if pack size exceeds 50MB — large for a zero-runtime-dep tool
|
|
120
|
+
const ok = size < 50 * 1024 * 1024;
|
|
121
|
+
logGate('npm pack dry-run', ok, `${sizeMB}MB, ${fileCount} files`);
|
|
122
|
+
if (!ok) process.exit(1);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
logGate('npm pack dry-run', false, 'JSON parse failed: ' + err.message);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Gate 6: smoke install — pack and install into temp dir, run pan-tools
|
|
130
|
+
if (SKIP_SMOKE) {
|
|
131
|
+
process.stderr.write('\n[release-check] Gate 6/6: smoke install (SKIPPED)\n');
|
|
132
|
+
} else {
|
|
133
|
+
process.stderr.write('\n[release-check] Gate 6/6: smoke install (npm pack + install + sanity)\n');
|
|
134
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pan-release-smoke-'));
|
|
135
|
+
try {
|
|
136
|
+
// Pack
|
|
137
|
+
const pack = run('npm', ['pack', '--pack-destination', tmpDir, '--json'], { capture: true });
|
|
138
|
+
if (pack.status !== 0) {
|
|
139
|
+
logGate('smoke install (pack)', false, `exit ${pack.status}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
const packJson = JSON.parse(pack.stdout);
|
|
143
|
+
const tarball = path.join(tmpDir, packJson[0].filename);
|
|
144
|
+
if (!fs.existsSync(tarball)) {
|
|
145
|
+
logGate('smoke install (pack)', false, `tarball not found at ${tarball}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
// Install into a separate fake project dir
|
|
149
|
+
const installDir = path.join(tmpDir, 'install-target');
|
|
150
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
151
|
+
fs.writeFileSync(path.join(installDir, 'package.json'), JSON.stringify({ name: 'smoke-test', version: '0.0.0' }));
|
|
152
|
+
const inst = run('npm', ['install', tarball, '--no-save', '--prefix', installDir], { capture: true });
|
|
153
|
+
if (inst.status !== 0) {
|
|
154
|
+
logGate('smoke install (install)', false, `exit ${inst.status}`);
|
|
155
|
+
process.stderr.write((inst.stderr || '') + '\n');
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
// Sanity: invoke pan-tools experiment list against an empty root
|
|
159
|
+
const panToolsPath = path.join(installDir, 'node_modules', 'pan-wizard', 'pan-wizard-core', 'bin', 'pan-tools.cjs');
|
|
160
|
+
if (!fs.existsSync(panToolsPath)) {
|
|
161
|
+
logGate('smoke install (sanity)', false, `pan-tools.cjs missing in installed package at ${panToolsPath}`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
// Pick a non-existent root so we exercise the read path without scaffolding anything
|
|
165
|
+
const fakeRoot = path.join(tmpDir, 'no-experiments-here');
|
|
166
|
+
const sanity = run('node', [panToolsPath, 'experiment', 'list', '--root', fakeRoot], { capture: true });
|
|
167
|
+
const ok = sanity.status === 0;
|
|
168
|
+
logGate('smoke install', ok, ok ? 'pan-tools experiment list works in installed package' : `exit ${sanity.status}`);
|
|
169
|
+
if (!ok) {
|
|
170
|
+
process.stderr.write((sanity.stderr || '') + '\n');
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
} finally {
|
|
174
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch { /* best-effort */ }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Summary
|
|
179
|
+
process.stderr.write('\n[release-check] Summary:\n');
|
|
180
|
+
for (const c of checks) {
|
|
181
|
+
process.stderr.write(` [${c.ok ? 'OK' : 'FAIL'}] ${c.name}${c.detail ? ' — ' + c.detail : ''}\n`);
|
|
182
|
+
}
|
|
183
|
+
process.stderr.write(`\n[release-check] ${failed ? 'FAILED' : 'PASSED'}\n`);
|
|
184
|
+
process.exit(failed ? 1 : 0);
|