pan-wizard 3.30.0 → 3.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +30 -26
  2. package/agents/pan-design-checker.md +18 -0
  3. package/agents/pan-optimizer.md +5 -1
  4. package/agents/pan-plan-checker.md +23 -0
  5. package/agents/pan-reviewer.md +19 -0
  6. package/agents/pan-verifier.md +23 -0
  7. package/bin/install-lib.cjs +129 -33
  8. package/bin/install.js +16 -9
  9. package/commands/pan/army.md +4 -4
  10. package/commands/pan/design-phase.md +8 -0
  11. package/commands/pan/exec-phase.md +1 -1
  12. package/commands/pan/git.md +2 -2
  13. package/commands/pan/learn.md +2 -0
  14. package/commands/pan/optimize.md +14 -2
  15. package/commands/pan/review-deep.md +5 -5
  16. package/commands/pan/verify-phase.md +8 -9
  17. package/hooks/dist/pan-check-update.js +53 -2
  18. package/hooks/dist/pan-context-monitor.js +42 -1
  19. package/hooks/dist/pan-cost-logger.js +132 -11
  20. package/hooks/dist/pan-state-reinject.js +158 -0
  21. package/hooks/dist/pan-stop-guard.js +50 -4
  22. package/hooks/dist/pan-trace-logger.js +324 -18
  23. package/package.json +1 -1
  24. package/pan-wizard-core/bin/lib/commands.cjs +22 -5
  25. package/pan-wizard-core/bin/lib/config.cjs +2 -0
  26. package/pan-wizard-core/bin/lib/constants.cjs +31 -1
  27. package/pan-wizard-core/bin/lib/context-budget.cjs +27 -2
  28. package/pan-wizard-core/bin/lib/core.cjs +232 -23
  29. package/pan-wizard-core/bin/lib/cost-rebuild.cjs +11 -0
  30. package/pan-wizard-core/bin/lib/cost.cjs +135 -46
  31. package/pan-wizard-core/bin/lib/findings.cjs +381 -0
  32. package/pan-wizard-core/bin/lib/focus.cjs +72 -19
  33. package/pan-wizard-core/bin/lib/foreign-planning.cjs +24 -6
  34. package/pan-wizard-core/bin/lib/frontmatter.cjs +5 -2
  35. package/pan-wizard-core/bin/lib/hygiene.cjs +12 -2
  36. package/pan-wizard-core/bin/lib/init.cjs +4 -1
  37. package/pan-wizard-core/bin/lib/memory-optimize.cjs +12 -6
  38. package/pan-wizard-core/bin/lib/memory-rebuild.cjs +9 -2
  39. package/pan-wizard-core/bin/lib/optimize.cjs +349 -21
  40. package/pan-wizard-core/bin/lib/phase-report.cjs +4 -1
  41. package/pan-wizard-core/bin/lib/review-deep.cjs +36 -0
  42. package/pan-wizard-core/bin/lib/roadmap.cjs +87 -18
  43. package/pan-wizard-core/bin/lib/state.cjs +93 -24
  44. package/pan-wizard-core/bin/lib/suggest.cjs +21 -9
  45. package/pan-wizard-core/bin/lib/template.cjs +6 -3
  46. package/pan-wizard-core/bin/lib/verdict.cjs +431 -0
  47. package/pan-wizard-core/bin/lib/verify-deploy.cjs +19 -2
  48. package/pan-wizard-core/bin/lib/verify-preflight.cjs +4 -2
  49. package/pan-wizard-core/bin/lib/verify-scope.cjs +156 -0
  50. package/pan-wizard-core/bin/lib/verify.cjs +25 -2
  51. package/pan-wizard-core/bin/pan-tools.cjs +69 -6
  52. package/pan-wizard-core/learnings/README.md +10 -7
  53. package/pan-wizard-core/mcp/tool-registry.cjs +16 -4
  54. package/pan-wizard-core/references/verdict-contract.md +101 -0
  55. package/pan-wizard-core/templates/verification-report.md +16 -0
  56. package/pan-wizard-core/workflows/exec-phase.md +73 -47
  57. package/pan-wizard-core/workflows/health.md +2 -0
  58. package/pan-wizard-core/workflows/help.md +2 -2
  59. package/pan-wizard-core/workflows/learn.md +4 -2
  60. package/pan-wizard-core/workflows/milestone-audit.md +15 -3
  61. package/pan-wizard-core/workflows/optimize.md +14 -1
  62. package/pan-wizard-core/workflows/phase-tests.md +1 -1
  63. package/pan-wizard-core/workflows/plan-phase.md +20 -15
  64. package/pan-wizard-core/workflows/progress.md +1 -1
  65. package/pan-wizard-core/workflows/todo-add.md +1 -1
  66. package/pan-wizard-core/workflows/todo-check.md +7 -6
  67. package/pan-wizard-core/workflows/verify-phase.md +3 -13
  68. package/pan-zcode/README.md +3 -3
  69. package/scripts/build-agent-plugin.js +4 -0
  70. package/scripts/build-hooks.js +2 -1
  71. package/scripts/build-plugin.js +10 -0
  72. package/scripts/git-hooks/pre-commit +2 -1
  73. package/scripts/npm-dist-tag.js +47 -0
  74. package/scripts/plugin-path.js +6 -1
  75. package/scripts/test-surface.cjs +1 -0
@@ -31,10 +31,10 @@ If `--session <id>` was specified, use that session ID.
31
31
 
32
32
  Run:
33
33
  ```
34
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize learn [--session <id>]
34
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize learn [--session <id> | --sessions <n>]
35
35
  ```
36
36
 
37
- This produces `.planning/optimization/reports/{session}-analysis.json`.
37
+ This produces `.planning/optimization/reports/{session}-analysis.json`. With `--sessions <n>` it pools the last n sessions into `pooled-<n>-{session}-analysis.json`: a recommendation should explain failures that recur across runs, not one run's accident.
38
38
 
39
39
  Read the output and note:
40
40
  - `summary.errors` — how many error events
@@ -42,6 +42,8 @@ Read the output and note:
42
42
  - `summary.memory_misses` — how many memory miss events
43
43
  - `summary.wasted_tokens` — tokens wasted on redundancies
44
44
  - `top_error_patterns` — most frequent error categories
45
+ - `top_tool_error_patterns` — failed tool calls captured from the subagents' own transcripts, ranked by how many spawns hit them
46
+ - `verdict_stats` — each judge's pass/fail counts, retries, and the retries that resolved a failure
45
47
  - `top_memory_misses` — most frequent memory miss topics
46
48
 
47
49
  ## Step 3 — Invoke pan-optimizer agent
@@ -82,6 +82,18 @@ From each verification.md, extract:
82
82
 
83
83
  If a phase is missing verification.md, flag it as "unverified phase" — this is a blocker.
84
84
 
85
+ ### 2b. Read the Recorded Findings
86
+
87
+ What the judges found in this milestone, and what was decided about each finding, is on record. Read it rather than reconstructing it from prose:
88
+
89
+ ```bash
90
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings debt --milestone "{version}"
91
+ ```
92
+
93
+ - **`deferred`** findings were continued past on purpose, and each carries the reason recorded at the time. They are the milestone's tech debt: put every one in `tech_debt`, with its id and reason.
94
+ - **`open`** findings were never disposed (no fix, deferral, dismissal or decision). List them under "Undisposed findings" in the report. They are not blockers by themselves: the verification gate handles blockers. They do mean the milestone cannot be `passed`, so the status is at least `tech_debt`.
95
+ - A dismissal or decision is settled and not debt. `findings list --milestone "{version}" --status dismissed` shows the dismissals and their reasons when the report needs them.
96
+
85
97
  ## 3. Spawn Integration Checker
86
98
 
87
99
  With phase context collected:
@@ -181,11 +193,11 @@ gaps: # Critical blockers
181
193
  evidence: "{specific evidence or lack thereof}"
182
194
  integration: [...]
183
195
  flows: [...]
184
- tech_debt: # Non-critical, deferred
196
+ tech_debt: # Non-critical, deferred — from `findings debt` (step 2b) plus anything the verifications list
185
197
  - phase: 01-auth
186
198
  items:
199
+ - "[f_81ab3c9d20] no password strength validation — deferred: accepted at review: PASS_WITH_WARNINGS"
187
200
  - "TODO: add rate limiting"
188
- - "Warning: no password strength validation"
189
201
  - phase: 03-dashboard
190
202
  items:
191
203
  - "Deferred: mobile responsive layout"
@@ -197,7 +209,7 @@ Plus full markdown report with tables for requirements, phases, integration, tec
197
209
  **Status values:**
198
210
  - `passed` — all requirements met, no critical gaps, minimal tech debt
199
211
  - `gaps_found` — critical blockers exist
200
- - `tech_debt` — no blockers but accumulated deferred items need review
212
+ - `tech_debt` — no blockers but accumulated deferred items need review, or recorded findings were never disposed
201
213
 
202
214
  ## 7. Present Results
203
215
 
@@ -8,6 +8,7 @@ Manage the circular optimization loop — apply reports, check stats, control tr
8
8
  |------------|--------|
9
9
  | `apply` | Apply safe recommendations from most recent report |
10
10
  | `apply --report <file>` | Apply from a specific report |
11
+ | `revert <apply_id>` / `revert --last` | Undo one apply exactly |
11
12
  | `list` | List all reports |
12
13
  | `stats` | Show cumulative stats |
13
14
  | `trace init` | Start a new trace session |
@@ -40,8 +41,9 @@ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize apply [--report <path>
40
41
 
41
42
  Show the user:
42
43
  - **Applied** — each item that was written (memory entries, notes)
43
- - **Skipped** — items that already exist or had unknown types
44
+ - **Skipped** — items that already exist, that an earlier apply already wrote, or that had unknown types
44
45
  - **Still needs review** — prompt/workflow suggestions in `suggestions.md`
46
+ - **The `apply_id`**, and how to undo the apply: `/pan:optimize revert <apply_id>`
45
47
 
46
48
  If memory entries were written, tell the user:
47
49
  > Memory entries have been added to `.planning/memory/`. They will be loaded on the next agent run, reducing future memory misses for these topics.
@@ -54,6 +56,17 @@ If `.planning/optimization/suggestions.md` exists, tell the user to review it fo
54
56
 
55
57
  ---
56
58
 
59
+ ## revert
60
+
61
+ ```
62
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize revert <apply_id>
63
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize revert --last
64
+ ```
65
+
66
+ Show the user each reverted action and each refused one, with its reason. A refusal means someone edited the file after the apply, or a later apply also wrote it. Revert that later apply first; never force it. The status is `reverted`, `partial`, `refused` or `nothing_to_revert`.
67
+
68
+ ---
69
+
57
70
  ## trace init
58
71
 
59
72
  ### Step 1 — Extract description
@@ -364,7 +364,7 @@ Present next steps:
364
364
 
365
365
  **Also available:**
366
366
  - `/pan:phase-tests {next_phase}` — test another phase
367
- - `/pan:verify-phase {phase_number}` — run UAT verification
367
+ - `/pan:verify-phase {phase_number}` — re-run goal-backward verification
368
368
 
369
369
  ---
370
370
  ```
@@ -222,7 +222,7 @@ In that case, log a `decision` trace event (`type: "decision", category: "skip-r
222
222
 
223
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
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.
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 the planning output (context, research, plan) to a record and a plan for trivial phases; execution still writes the plan's summary. 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
226
 
227
227
  **If `has_research` is true (from init) AND no `--research` flag:** Use existing, skip to step 6.
228
228
 
@@ -448,20 +448,20 @@ Task(
448
448
 
449
449
  ## 11. Handle Checker Return
450
450
 
451
- - **`## VERIFICATION PASSED`:** Display confirmation, proceed to step 13.
452
- ```bash
453
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
454
- --type decision --category plan_verified \
455
- --description "Plan-checker passed for phase ${PHASE_NUMBER}" \
456
- --agent pan-plan-checker --impact trivial 2>/dev/null || true
457
- ```
458
- - **`## ISSUES FOUND`:** Display issues, check iteration count, proceed to step 12.
459
- ```bash
460
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
461
- --type error --category plan_checker_issues \
462
- --description "Plan-checker found issues in phase ${PHASE_NUMBER} plans" \
463
- --agent pan-plan-checker --impact minor 2>/dev/null || true
464
- ```
451
+ Save the checker's returned text, verbatim and in full (including its closing `pan-verdict` block), to `{phase_dir}/{padded_phase}-plan-check.md` with the Write tool. Then record it, and branch on the record. The record also adds the issues to the findings ledger and logs the check to the trace; there is no separate trace call:
452
+
453
+ ```bash
454
+ CHECK_FILE="{phase_dir}/{padded_phase}-plan-check.md"
455
+ CHECK_VERDICT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${PHASE_NUMBER}" --agent pan-plan-checker --file "$CHECK_FILE" --raw 2>/dev/null) \
456
+ || CHECK_VERDICT=$(grep -q '^## VERIFICATION PASSED' "$CHECK_FILE" && echo passed || echo issues_found)
457
+ ```
458
+
459
+ The fallback reads the heading when the report carries no valid `pan-verdict` block.
460
+
461
+ - **`passed`:** Display confirmation, proceed to step 13.
462
+ - **`issues_found`:** Display issues, check iteration count, proceed to step 12.
463
+
464
+ Each re-check in the revision loop overwrites the same file and is recorded again as the next attempt. The issues a revision resolved are closed by that record.
465
465
 
466
466
  ## 12. Revision Loop (Max 3 Iterations)
467
467
 
@@ -510,6 +510,11 @@ Display: `Max iterations reached. {N} issues remain:` + issue list
510
510
 
511
511
  Offer: 1) Force proceed, 2) Provide guidance and retry, 3) Abandon
512
512
 
513
+ **On "Force proceed":** record that planning continues past the remaining issues. Execution and the milestone audit will see them as deferred, with this reason:
514
+ ```bash
515
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings dispose --phase "${PHASE_NUMBER}" --agent pan-plan-checker --open --as deferred --reason "force proceed after 3 plan revision iterations"
516
+ ```
517
+
513
518
  ## 13. Present Final Status
514
519
 
515
520
  **Sync state.md first** — without this, state.md says "Ready to plan" until the
@@ -252,7 +252,7 @@ uat.md exists with gaps (diagnosed issues). User needs to plan fixes.
252
252
 
253
253
  **Also available:**
254
254
  - `/pan:exec-phase {phase}` — execute phase plans
255
- - `/pan:verify-phase {phase}` — run more UAT testing
255
+ - `/pan:verify-phase {phase}` — re-run goal-backward verification
256
256
 
257
257
  ---
258
258
  ```
@@ -19,7 +19,7 @@ Extract from init JSON: `commit_docs`, `date`, `timestamp`, `todo_count`, `todos
19
19
 
20
20
  Ensure directories exist:
21
21
  ```bash
22
- mkdir -p .planning/todos/pending .planning/todos/done
22
+ mkdir -p .planning/todos/pending .planning/todos/completed
23
23
  ```
24
24
 
25
25
  Note existing areas from the todos array for consistency in infer_area step.
@@ -105,7 +105,7 @@ Use AskUserQuestion:
105
105
  - header: "Action"
106
106
  - question: "This todo relates to Phase [N]: [name]. What would you like to do?"
107
107
  - options:
108
- - "Work on it now" — move to done, start working
108
+ - "Work on it now" — mark it completed, start working
109
109
  - "Add to phase plan" — include when planning Phase [N]
110
110
  - "Brainstorm approach" — think through before deciding
111
111
  - "Put it back" — return to list
@@ -116,7 +116,7 @@ Use AskUserQuestion:
116
116
  - header: "Action"
117
117
  - question: "What would you like to do with this todo?"
118
118
  - options:
119
- - "Work on it now" — move to done, start working
119
+ - "Work on it now" — mark it completed, start working
120
120
  - "Create a phase" — /pan:add-phase with this scope
121
121
  - "Brainstorm approach" — think through before deciding
122
122
  - "Put it back" — return to list
@@ -125,8 +125,9 @@ Use AskUserQuestion:
125
125
  <step name="execute_action">
126
126
  **Work on it now:**
127
127
  ```bash
128
- mv ".planning/todos/pending/[filename]" ".planning/todos/done/"
128
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs todo complete "[filename]"
129
129
  ```
130
+ This moves it to `.planning/todos/completed/` with a `completed:` date — the directory `init todos` and `/pan:progress` count.
130
131
  Update state.md todo count. Present problem/solution context. Begin work or ask how to proceed.
131
132
 
132
133
  **Add to phase plan:**
@@ -150,11 +151,11 @@ Re-run `init todos` to get updated count, then update state.md "### Pending Todo
150
151
  </step>
151
152
 
152
153
  <step name="git_commit">
153
- If todo was moved to done/, commit the change:
154
+ If the todo was completed, commit the change:
154
155
 
155
156
  ```bash
156
157
  git rm --cached .planning/todos/pending/[filename] 2>/dev/null || true
157
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs commit "docs: start work on todo - [title]" --files .planning/todos/done/[filename] .planning/state.md
158
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs commit "docs: start work on todo - [title]" --files .planning/todos/completed/[filename] .planning/state.md
158
159
  ```
159
160
 
160
161
  Tool respects `commit_docs` config and gitignore automatically.
@@ -172,5 +173,5 @@ Confirm: "Committed: docs: start work on todo - [title]"
172
173
  - [ ] Appropriate actions offered
173
174
  - [ ] Selected action executed
174
175
  - [ ] state.md updated if todo count changed
175
- - [ ] Changes committed to git (if todo moved to done/)
176
+ - [ ] Changes committed to git (if the todo was completed)
176
177
  </success_criteria>
@@ -321,21 +321,11 @@ If human_needed: list items requiring human testing.
321
321
 
322
322
  Orchestrator routes: `passed` → update_roadmap | `gaps_found` → create/execute fixes, re-verify | `human_needed` → present to user.
323
323
 
324
- **Circular optimization — log verification outcome:**
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, and it closes the gaps it no longer reports:
325
325
  ```bash
326
- # Map status to impact and event type
327
- if [ "${STATUS}" = "passed" ]; then
328
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
329
- --type decision --category verification_passed \
330
- --description "Phase ${PHASE_NUMBER} verification passed (score: ${SCORE})" \
331
- --agent pan-verifier --impact minor 2>/dev/null || true
332
- elif [ "${STATUS}" = "gaps_found" ]; then
333
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
334
- --type error --category verification_gaps \
335
- --description "Phase ${PHASE_NUMBER} verification found gaps (score: ${SCORE})" \
336
- --agent pan-verifier --impact major 2>/dev/null || true
337
- fi
326
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${PHASE_NUMBER}" --file "$REPORT_PATH" 2>/dev/null || true
338
327
  ```
328
+ Recording the same report twice is a no-op, so exec-phase recording it again after this workflow returns is safe.
339
329
  </step>
340
330
 
341
331
  </process>
@@ -50,7 +50,7 @@ before ADR-0028.
50
50
  preserves the body; plus a command → skill wrapper.
51
51
  - **M4 — bundle + install.** `bin/install-zcode.js` — assembles `agents/` + `pan-mcp.json` +
52
52
  manifest + `INSTALL-ZCODE.md` into a `--target` dir; refuses to write inside the source repo;
53
- drives ZCode's own Import to finish.
53
+ leaves the finish to the human in ZCode's own Settings and Import, following `INSTALL-ZCODE.md`.
54
54
  - **M5 — hardening + docs.** Full test matrix + [`KNOWN-BETA-RISKS.md`](KNOWN-BETA-RISKS.md)
55
55
  (the beta-churn ledger + the M0 go/no-go questions).
56
56
 
@@ -59,11 +59,11 @@ Tests: `tests/pan-zcode-mcp.test.cjs`, `tests/pan-zcode-orchestration.test.cjs`,
59
59
 
60
60
  ## Still pending — M0 (needs a real ZCode install)
61
61
 
62
- Two go/no-go facts can only be settled empirically: **can a subagent call MCP tools?** and **are
62
+ Among the go/no-go facts only a real install can settle (the M0 table in `KNOWN-BETA-RISKS.md`) are **can a subagent call MCP tools?** and **are
63
63
  local stdio MCP calls metered?** Both have folded-in fallbacks (see `KNOWN-BETA-RISKS.md`), so the
64
64
  design holds either way — but confirm them before relying on the richer paths.
65
65
 
66
- A third M0 checkpoint (added 2026-08): **which protocol era does the real ZCode client speak?**
66
+ Another M0 checkpoint (added 2026-08, not yet in `KNOWN-BETA-RISKS.md`): **which protocol era does the real ZCode client speak?**
67
67
  The bridge is now dual-era (ADR-0041), so it answers both a legacy `initialize` handshake and a
68
68
  modern `server/discover` probe. Confirm on a real install which path ZCode takes and that the
69
69
  version it declares is in our supported list; if ZCode ever declares a revision newer than
@@ -150,6 +150,8 @@ function hookCommands(rootVar) {
150
150
  contextMonitorCommand: cmd('pan-context-monitor.js'),
151
151
  costLoggerCommand: cmd('pan-cost-logger.js'),
152
152
  traceLoggerCommand: cmd('pan-trace-logger.js'),
153
+ stopGuardCommand: cmd('pan-stop-guard.js'),
154
+ stateReinjectCommand: cmd('pan-state-reinject.js'),
153
155
  };
154
156
  }
155
157
 
@@ -166,6 +168,8 @@ function emitCopilotNamespace(agentsSrc, nsDir) {
166
168
  content = lib.rewriteAgentReferenceCopy(content, TOKEN_PREFIX);
167
169
  content = lib.stripThinkingFrontmatter(content, 'copilot');
168
170
  content = lib.convertClaudeToCopilotAgent(content);
171
+ // The agent carries the root token, so it carries what the token means.
172
+ if (content.includes(TOKEN_PREFIX)) content = content.replace(/\s*$/, '\n\n' + lib.agentPluginSkillAdapterNote('agent') + '\n');
169
173
  fs.writeFileSync(path.join(agentsDest, f.replace(/\.md$/, '.agent.md')), content);
170
174
  agents++;
171
175
  }
@@ -22,7 +22,8 @@ const HOOKS_TO_COPY = [
22
22
  'pan-statusline.js',
23
23
  'pan-cost-logger.js',
24
24
  'pan-trace-logger.js',
25
- 'pan-stop-guard.js'
25
+ 'pan-stop-guard.js',
26
+ 'pan-state-reinject.js'
26
27
  ];
27
28
 
28
29
  function build() {
@@ -169,6 +169,15 @@ function main() {
169
169
  );
170
170
  }
171
171
 
172
+ // 7. Eval suite (market-ideas M4). `claude plugin eval` reads `evals/` at the
173
+ // plugin root; the cases live in harness/plugin-evals/ beside the harness
174
+ // scenarios they come from. harness/ is not in the npm package, so a build from
175
+ // an installed copy has no suite to copy and the plugin ships without one.
176
+ const evalsSrc = path.join(ROOT, 'harness', 'plugin-evals');
177
+ if (fs.existsSync(evalsSrc)) {
178
+ fs.cpSync(evalsSrc, path.join(OUT, 'evals'), { recursive: true });
179
+ }
180
+
172
181
  // Sanity report
173
182
  const count = (p) => { try { return fs.readdirSync(p).length; } catch { return 0; } };
174
183
  console.log('PAN plugin built at', path.relative(ROOT, OUT));
@@ -176,6 +185,7 @@ function main() {
176
185
  console.log(' agents:', count(path.join(OUT, 'agents')));
177
186
  console.log(' hooks:', count(path.join(OUT, 'hooks')));
178
187
  console.log(' workflows:', workflowScripts.length);
188
+ console.log(' eval cases:', count(path.join(OUT, 'evals')) ? fs.readdirSync(path.join(OUT, 'evals'), { withFileTypes: true }).filter(e => e.isDirectory()).length : 0);
179
189
  console.log(' version:', pkg.version);
180
190
  }
181
191
 
@@ -10,7 +10,8 @@
10
10
  # Or with a symlink (Unix / Git Bash):
11
11
  # ln -sf ../../scripts/git-hooks/pre-commit .git/hooks/pre-commit
12
12
  #
13
- # Bypass for an emergency (creates a paper trail in the commit log):
13
+ # Bypass for an emergency (the hook only prints that the scan was skipped;
14
+ # nothing is recorded in the commit):
14
15
  # SKIP_GITLEAKS=1 git commit -m "..."
15
16
  #
16
17
  # Exit codes:
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Print the npm dist-tag a version publishes under: `next` for a prerelease
4
+ * (`3.31.0-rc.1`), `latest` otherwise.
5
+ *
6
+ * WHY. The release workflow ran `npm publish` with no `--tag`, and npm's default
7
+ * tag is `latest` — so a release candidate would have become what
8
+ * `npm install pan-wizard` resolves to for every user (market-ideas queue M1,
9
+ * 2026-09-21). Publishing a candidate under `next` keeps it installable by name
10
+ * (`pan-wizard@next`, `pan-wizard@3.31.0-rc.1`) without moving anyone onto it.
11
+ *
12
+ * A version that is not `major.minor.patch[-prerelease]` exits 1 rather than
13
+ * guessing a tag: publishing junk under `latest` is the failure this prevents.
14
+ *
15
+ * Usage:
16
+ * node scripts/npm-dist-tag.js # the tag for package.json's version
17
+ * node scripts/npm-dist-tag.js 3.31.0-rc.1
18
+ */
19
+
20
+ 'use strict';
21
+
22
+ const path = require('path');
23
+ const { parse } = require('./deprecate-old-versions.js');
24
+
25
+ /**
26
+ * @param {string} version
27
+ * @returns {'latest'|'next'|null} null when the version does not parse
28
+ */
29
+ function distTagFor(version) {
30
+ const v = parse(version);
31
+ if (!v) return null;
32
+ return v.pre === null ? 'latest' : 'next';
33
+ }
34
+
35
+ function main() {
36
+ const version = process.argv[2] || require(path.join(__dirname, '..', 'package.json')).version;
37
+ const tag = distTagFor(version);
38
+ if (!tag) {
39
+ process.stderr.write(`npm-dist-tag: '${version}' is not a semver version — refusing to pick a tag\n`);
40
+ process.exit(1);
41
+ }
42
+ process.stdout.write(tag + '\n');
43
+ }
44
+
45
+ module.exports = { distTagFor };
46
+
47
+ if (require.main === module) main();
@@ -49,8 +49,13 @@ function fail(message) {
49
49
  function build() {
50
50
  try {
51
51
  // Relay the builder's stdout to stderr so stdout stays single-line.
52
+ // PAN_PLUGIN_OUT redirects the builder; this script prints PLUGIN_DIR, so a value
53
+ // inherited from the caller's environment would build one place and point the
54
+ // marketplace at another (3.28.0 review, LOW). Build where the path says.
55
+ const env = { ...process.env };
56
+ delete env.PAN_PLUGIN_OUT;
52
57
  const out = execFileSync(process.execPath, [path.join(ROOT, 'scripts', 'build-plugin.js')], {
53
- cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
58
+ cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], env,
54
59
  });
55
60
  if (out) process.stderr.write(out);
56
61
  } catch (err) {
@@ -68,6 +68,7 @@ const EVENT_HOOKS = Object.freeze({
68
68
  postToolUse: ['pan-context-monitor.js'],
69
69
  subagentStop: ['pan-cost-logger.js', 'pan-trace-logger.js'],
70
70
  stop: ['pan-stop-guard.js'],
71
+ compact: ['pan-state-reinject.js'],
71
72
  });
72
73
 
73
74
  // ─── Parsers (pure) ─────────────────────────────────────────────────────────