pan-wizard 3.35.0 → 3.37.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 (339) hide show
  1. package/CHANGELOG.md +3645 -0
  2. package/README.md +46 -52
  3. package/agents/pan-conductor.md +2 -3
  4. package/agents/pan-counterfactual.md +1 -2
  5. package/agents/pan-debugger.md +14 -3
  6. package/agents/pan-design-checker.md +1 -2
  7. package/agents/pan-designer.md +2 -3
  8. package/agents/pan-document_code.md +1 -2
  9. package/agents/pan-executor.md +25 -0
  10. package/agents/pan-hardener.md +4 -3
  11. package/agents/pan-integration-checker.md +1 -2
  12. package/agents/pan-knowledge.md +1 -2
  13. package/agents/pan-meta-reviewer.md +3 -3
  14. package/agents/pan-optimizer.md +4 -4
  15. package/agents/pan-phase-researcher.md +80 -475
  16. package/agents/pan-plan-checker.md +40 -3
  17. package/agents/pan-planner.md +21 -7
  18. package/agents/pan-previewer.md +3 -2
  19. package/agents/pan-project-researcher.md +72 -493
  20. package/agents/pan-release.md +1 -1
  21. package/agents/pan-reviewer.md +14 -3
  22. package/agents/pan-roadmapper.md +12 -7
  23. package/agents/pan-verifier.md +9 -4
  24. package/bin/install-lib.cjs +134 -14
  25. package/bin/install.js +59 -12
  26. package/commands/pan/army.md +1 -1
  27. package/commands/pan/autodev.md +76 -0
  28. package/commands/pan/cost.md +21 -1
  29. package/commands/pan/exec-phase.md +3 -4
  30. package/commands/pan/focus-auto.md +14 -7
  31. package/commands/pan/focus-design.md +4 -5
  32. package/commands/pan/focus-docs.md +24 -0
  33. package/commands/pan/learn.md +13 -6
  34. package/commands/pan/milestone-audit.md +8 -1
  35. package/commands/pan/milestone-done.md +10 -5
  36. package/commands/pan/milestone-new.md +2 -2
  37. package/commands/pan/new-project.md +15 -12
  38. package/commands/pan/plan-phase.md +15 -9
  39. package/commands/pan/preview.md +1 -1
  40. package/commands/pan/quick.md +1 -1
  41. package/commands/pan/review-deep.md +11 -5
  42. package/commands/pan/settings.md +6 -0
  43. package/commands/pan/verify-phase.md +6 -2
  44. package/docs/AGENTS.md +917 -0
  45. package/docs/ARCHITECTURE.md +1054 -0
  46. package/docs/CLI-REFERENCE.md +4582 -0
  47. package/docs/COMPARISON.md +116 -0
  48. package/docs/DEVELOPMENT.md +490 -0
  49. package/docs/ECOSYSTEM-REVIEW-2026-06.md +107 -0
  50. package/docs/ECOSYSTEM-REVIEW-2026-08.md +349 -0
  51. package/docs/EXAMPLES.md +584 -0
  52. package/docs/FAQ.md +254 -0
  53. package/docs/FIELD-HARVEST-2026-07.md +88 -0
  54. package/docs/FIELD-REPORT-army-2026-06.md +121 -0
  55. package/docs/HOOKS.md +638 -0
  56. package/docs/IMPROVEMENT-TODO.md +246 -0
  57. package/docs/INTERNALS.md +485 -0
  58. package/docs/MIGRATION-v2-to-v3.md +258 -0
  59. package/docs/SECURITY-HARDENING.md +230 -0
  60. package/docs/SKILLS-ENHANCEMENT-PLAN-V2.md +122 -0
  61. package/docs/SKILLS-FULL-TEXT.md +9685 -0
  62. package/docs/SKILLS-REFERENCE.md +1037 -0
  63. package/docs/TROUBLESHOOTING.md +1084 -0
  64. package/docs/USER-GUIDE.md +1437 -0
  65. package/docs/archive/SKILLS-ENHANCEMENT-PLAN.md +230 -0
  66. package/docs/audits/AUDIT-2026-08-e2e-ROADMAP.md +117 -0
  67. package/docs/audits/AUDIT-2026-08-e2e-VERIFICATION.md +693 -0
  68. package/docs/audits/AUDIT-2026-08-e2e.md +1546 -0
  69. package/docs/audits/OUTSTANDING-2026-08.md +275 -0
  70. package/docs/audits/STABILITY-TEST-2026-08.md +640 -0
  71. package/docs/branding/README-brand-draft.md +119 -0
  72. package/docs/branding/handoff/IMPLEMENTATION.md +205 -0
  73. package/docs/branding/handoff/README-brand-draft.md +119 -0
  74. package/docs/branding/handoff/image-prompts.md +46 -0
  75. package/docs/branding/image-prompts.md +46 -0
  76. package/docs/branding/nano-banana-prompts.txt +60 -0
  77. package/docs/context-monitor.md +13 -0
  78. package/docs/decisions/ADR-0001-strategic-feature-prioritization.md +83 -0
  79. package/docs/decisions/ADR-0002-copilot-cli-runtime.md +71 -0
  80. package/docs/decisions/ADR-0003-smart-execution.md +84 -0
  81. package/docs/decisions/ADR-0004-copilot-cli-interaction.md +89 -0
  82. package/docs/decisions/ADR-0005-command-naming.md +80 -0
  83. package/docs/decisions/ADR-0006-focus-commands.md +101 -0
  84. package/docs/decisions/ADR-0007-ship-v1.md +73 -0
  85. package/docs/decisions/ADR-0008-map-codebase-mermaid-togaf.md +80 -0
  86. package/docs/decisions/ADR-0009-production-deployment-checklist.md +68 -0
  87. package/docs/decisions/ADR-0010-standards-integration.md +79 -0
  88. package/docs/decisions/ADR-0011-help-commands-rewrite.md +64 -0
  89. package/docs/decisions/ADR-0012-contributors-attribution-index.md +42 -0
  90. package/docs/decisions/ADR-0013-strategic-feature-additions.md +53 -0
  91. package/docs/decisions/ADR-0014-internal-cleanup-code-quality.md +53 -0
  92. package/docs/decisions/ADR-0015-focus-auto-runner.md +296 -0
  93. package/docs/decisions/ADR-0016-enhanced-doc-sync.md +54 -0
  94. package/docs/decisions/ADR-0017-enhanced-focus-design.md +69 -0
  95. package/docs/decisions/ADR-0018-user-reality-testing.md +84 -0
  96. package/docs/decisions/ADR-0019-end-to-end-user-acceptance-testing.md +113 -0
  97. package/docs/decisions/ADR-0020-ai-drift-prevention.md +55 -0
  98. package/docs/decisions/ADR-0021-codebase-mapper-v2.md +76 -0
  99. package/docs/decisions/ADR-0022-lifecycle-completeness.md +63 -0
  100. package/docs/decisions/ADR-0023-opus-4-7-adoption.md +89 -0
  101. package/docs/decisions/ADR-0024-spec-b-v2-completion.md +137 -0
  102. package/docs/decisions/ADR-0025-behavioral-guardrails-layer.md +129 -0
  103. package/docs/decisions/ADR-0026-self-improvement-loop.md +171 -0
  104. package/docs/decisions/ADR-0027-doc-code-link-graph.md +164 -0
  105. package/docs/decisions/ADR-0028-unified-agents-skills-target.md +46 -0
  106. package/docs/decisions/ADR-0029-experiment-evaluator.md +76 -0
  107. package/docs/decisions/ADR-0030-planning-concurrency.md +37 -0
  108. package/docs/decisions/ADR-0031-focus-auto-backlog-source.md +47 -0
  109. package/docs/decisions/ADR-0032-squad-model.md +64 -0
  110. package/docs/decisions/ADR-0033-army-campaign.md +40 -0
  111. package/docs/decisions/ADR-0034-scheduled-campaigns.md +57 -0
  112. package/docs/decisions/ADR-0035-army-hud-dashboard.md +40 -0
  113. package/docs/decisions/ADR-0036-agentic-memory-architecture.md +106 -0
  114. package/docs/decisions/ADR-0037-pin-security-agents-to-opus.md +51 -0
  115. package/docs/decisions/ADR-0038-skill-aligned-decomposition.md +41 -0
  116. package/docs/decisions/ADR-0039-worktree-as-project-variant.md +37 -0
  117. package/docs/decisions/ADR-0040-memory-injection-defense.md +55 -0
  118. package/docs/decisions/ADR-0041-mcp-dual-era-bridge.md +47 -0
  119. package/docs/decisions/ADR-0042-design-parity-both-flows.md +45 -0
  120. package/docs/decisions/ADR-0043-addressable-planning-roots.md +56 -0
  121. package/docs/decisions/ADR-0044-bound-the-cached-context.md +104 -0
  122. package/docs/decisions/ADR-0045-agent-plugins-bundle.md +76 -0
  123. package/docs/decisions/ADR-0046-subagent-frontmatter-decisions.md +39 -0
  124. package/docs/decisions/ADR-0047-pan-harness.md +76 -0
  125. package/docs/decisions/ADR-0048-one-core-per-project.md +43 -0
  126. package/docs/decisions/ADR-0049-machine-verdicts-and-findings-ledger.md +116 -0
  127. package/docs/specs/ai_drift_prevention_featureai.md +286 -0
  128. package/docs/specs/codebase_mapper_v2_featureai.md +930 -0
  129. package/docs/specs/command_naming_optimization_featureai.md +930 -0
  130. package/docs/specs/comp_analysis_markdown_v1.md +149 -0
  131. package/docs/specs/continuous_autonomous_execution_featureai.md +304 -0
  132. package/docs/specs/contributors_attribution_index_featureai.md +476 -0
  133. package/docs/specs/copilot_cli_interaction_featureai.md +868 -0
  134. package/docs/specs/copilot_cli_runtime_featureai.md +647 -0
  135. package/docs/specs/custom-skills-assessment.md +461 -0
  136. package/docs/specs/deployment_audit_findings_featureai.md +243 -0
  137. package/docs/specs/doc_code_link_graph_featureai.md +253 -0
  138. package/docs/specs/documentation_alignment_cleanup_featureai.md +69 -0
  139. package/docs/specs/e2e_visual_testing_featureai.md +615 -0
  140. package/docs/specs/end_to_end_user_acceptance_testing_featureai.md +810 -0
  141. package/docs/specs/evidence-loop-plan.md +76 -0
  142. package/docs/specs/evidence_loop_featureai.md +497 -0
  143. package/docs/specs/focus-auto-optimize-category.md +449 -0
  144. package/docs/specs/focus-auto-optimize-superplan.md +188 -0
  145. package/docs/specs/focus_auto_runner_featureai.md +1102 -0
  146. package/docs/specs/focus_design_v2_featureai.md +197 -0
  147. package/docs/specs/focus_sync_v2_featureai.md +202 -0
  148. package/docs/specs/git_integration_overhaul_featureai.md +326 -0
  149. package/docs/specs/glm_zai_provider_featureai.md +200 -0
  150. package/docs/specs/googlecli_adoption_featureai.md +661 -0
  151. package/docs/specs/help_commands_rewrite_featureai.md +860 -0
  152. package/docs/specs/industry_analysis_strategic_additions_featureai.md +231 -0
  153. package/docs/specs/industry_comparison_and_feature_gaps_featureai.md +674 -0
  154. package/docs/specs/internal_cleanup_code_quality_featureai.md +486 -0
  155. package/docs/specs/investigations/README.md +31 -0
  156. package/docs/specs/investigations/digests/2026-09-28.md +47 -0
  157. package/docs/specs/investigations/digests/2026-10-08.md +62 -0
  158. package/docs/specs/investigations/digests/2026-10-10.md +61 -0
  159. package/docs/specs/investigations/features/debugger-red-loop-first.md +55 -0
  160. package/docs/specs/investigations/features/harness-cross-host-behaviour.md +93 -0
  161. package/docs/specs/investigations/features/optimize-apply-regression-gate.md +66 -0
  162. package/docs/specs/investigations/features/reviewer-smell-baseline.md +57 -0
  163. package/docs/specs/investigations/features/trace-failure-capture.md +69 -0
  164. package/docs/specs/lifecycle_completeness_featureai.md +754 -0
  165. package/docs/specs/local-first-ci.md +42 -0
  166. package/docs/specs/map_codebase_mermaid_togaf_featureai.md +805 -0
  167. package/docs/specs/market-delta-2026-09-superplan.md +310 -0
  168. package/docs/specs/market-ideas-2026-09.md +131 -0
  169. package/docs/specs/market-ideas-2026-10.md +428 -0
  170. package/docs/specs/market-ideas-ledger.md +177 -0
  171. package/docs/specs/memory-optimization-2026-10.md +285 -0
  172. package/docs/specs/multi-track-planning-roots.md +143 -0
  173. package/docs/specs/multi_model_routing_featureai.md +687 -0
  174. package/docs/specs/multi_model_routing_superplan.md +197 -0
  175. package/docs/specs/opus_47_existing_enhancements_featureai.md +247 -0
  176. package/docs/specs/opus_47_extended_features_featureai.md +363 -0
  177. package/docs/specs/opus_47_extended_features_v2_featureai.md +397 -0
  178. package/docs/specs/pan_focus_commands_featureai.md +2336 -0
  179. package/docs/specs/pan_zcode_mcp_bridge_featureai.md +120 -0
  180. package/docs/specs/product-excellence-superplan.md +315 -0
  181. package/docs/specs/product_excellence_program_2026_q4_featureai.md +365 -0
  182. package/docs/specs/production_deployment_readiness_featureai.md +433 -0
  183. package/docs/specs/production_readiness_ship_v1_featureai.md +698 -0
  184. package/docs/specs/real_test_enforcement_featureai.md +213 -0
  185. package/docs/specs/reality-check-2026-09-superplan.md +362 -0
  186. package/docs/specs/right-sized-ceremony.md +74 -0
  187. package/docs/specs/roadmap_and_competition_2026_q4_featureai.md +390 -0
  188. package/docs/specs/self_improvement_loop_featureai.md +875 -0
  189. package/docs/specs/skill-aligned-decomposition.md +155 -0
  190. package/docs/specs/standards_integration_featureai.md +833 -0
  191. package/docs/specs/testing-system-redesign-2026-09.md +267 -0
  192. package/docs/specs/user_reality_testing_system_featureai.md +788 -0
  193. package/docs/specs/watch-triggers.json +22 -0
  194. package/docs/specs/workflow-integration-redesign.md +742 -0
  195. package/docs/specs/workflow_state_consistency_featureai.md +183 -0
  196. package/hooks/dist/pan-context-monitor.js +9 -2
  197. package/hooks/dist/pan-cost-logger.js +5 -0
  198. package/hooks/dist/pan-guard.js +28 -5
  199. package/hooks/dist/pan-stop-guard.js +9 -9
  200. package/hooks/dist/pan-trace-logger.js +5 -0
  201. package/package.json +10 -2
  202. package/pan-wizard-core/bin/lib/agents-md.cjs +57 -8
  203. package/pan-wizard-core/bin/lib/autodev-report.cjs +180 -0
  204. package/pan-wizard-core/bin/lib/autodev.cjs +642 -0
  205. package/pan-wizard-core/bin/lib/ci.cjs +143 -0
  206. package/pan-wizard-core/bin/lib/commands.cjs +1 -1
  207. package/pan-wizard-core/bin/lib/config.cjs +41 -5
  208. package/pan-wizard-core/bin/lib/constants.cjs +27 -1
  209. package/pan-wizard-core/bin/lib/core.cjs +31 -14
  210. package/pan-wizard-core/bin/lib/cost.cjs +160 -4
  211. package/pan-wizard-core/bin/lib/cross-family.cjs +164 -0
  212. package/pan-wizard-core/bin/lib/debug-cases.cjs +104 -0
  213. package/pan-wizard-core/bin/lib/doc-lint.cjs +5 -3
  214. package/pan-wizard-core/bin/lib/failure-class.cjs +81 -0
  215. package/pan-wizard-core/bin/lib/findings.cjs +148 -9
  216. package/pan-wizard-core/bin/lib/focus.cjs +1 -1
  217. package/pan-wizard-core/bin/lib/git.cjs +1 -1
  218. package/pan-wizard-core/bin/lib/hosts.cjs +88 -0
  219. package/pan-wizard-core/bin/lib/init.cjs +7 -2
  220. package/pan-wizard-core/bin/lib/knowledge.cjs +2 -0
  221. package/pan-wizard-core/bin/lib/merge.cjs +50 -0
  222. package/pan-wizard-core/bin/lib/mutate.cjs +268 -0
  223. package/pan-wizard-core/bin/lib/next-action.cjs +112 -0
  224. package/pan-wizard-core/bin/lib/optimize.cjs +2 -2
  225. package/pan-wizard-core/bin/lib/phase-gate.cjs +15 -9
  226. package/pan-wizard-core/bin/lib/phase-remove.cjs +91 -11
  227. package/pan-wizard-core/bin/lib/phase.cjs +85 -13
  228. package/pan-wizard-core/bin/lib/plan-lint.cjs +310 -0
  229. package/pan-wizard-core/bin/lib/preview.cjs +26 -4
  230. package/pan-wizard-core/bin/lib/requirements-lint.cjs +130 -0
  231. package/pan-wizard-core/bin/lib/research-lint.cjs +268 -0
  232. package/pan-wizard-core/bin/lib/review-deep.cjs +14 -22
  233. package/pan-wizard-core/bin/lib/review-vote.cjs +105 -0
  234. package/pan-wizard-core/bin/lib/roadmap.cjs +1 -0
  235. package/pan-wizard-core/bin/lib/runner.cjs +2 -16
  236. package/pan-wizard-core/bin/lib/sizing.cjs +356 -0
  237. package/pan-wizard-core/bin/lib/squads.cjs +1 -1
  238. package/pan-wizard-core/bin/lib/state-write.cjs +247 -0
  239. package/pan-wizard-core/bin/lib/test-gate.cjs +433 -0
  240. package/pan-wizard-core/bin/lib/uat.cjs +149 -0
  241. package/pan-wizard-core/bin/lib/usage.cjs +104 -0
  242. package/pan-wizard-core/bin/lib/verdict.cjs +26 -3
  243. package/pan-wizard-core/bin/lib/verify-plan-set.cjs +30 -1
  244. package/pan-wizard-core/bin/lib/verify-preflight.cjs +2 -2
  245. package/pan-wizard-core/bin/lib/verify-red.cjs +174 -0
  246. package/pan-wizard-core/bin/lib/verify-retro.cjs +3 -2
  247. package/pan-wizard-core/bin/lib/verify-scope.cjs +143 -2
  248. package/pan-wizard-core/bin/lib/verify.cjs +86 -31
  249. package/pan-wizard-core/bin/lib/worktree.cjs +70 -0
  250. package/pan-wizard-core/bin/pan-tools.cjs +257 -28
  251. package/pan-wizard-core/learnings/universal/autonomous-loop.md +2 -2
  252. package/pan-wizard-core/mcp/orchestrator.cjs +4 -1
  253. package/pan-wizard-core/references/continuation-format.md +3 -3
  254. package/pan-wizard-core/references/design-methodology.md +1 -1
  255. package/pan-wizard-core/references/guardrails.md +1 -1
  256. package/pan-wizard-core/references/handoff-decisions.md +1 -1
  257. package/pan-wizard-core/references/model-profiles.md +2 -3
  258. package/pan-wizard-core/references/questioning.md +24 -0
  259. package/pan-wizard-core/references/ui-brand.md +4 -6
  260. package/pan-wizard-core/references/verdict-contract.md +2 -1
  261. package/pan-wizard-core/templates/config.json +10 -2
  262. package/pan-wizard-core/templates/debug.md +1 -0
  263. package/pan-wizard-core/templates/design.md +5 -4
  264. package/pan-wizard-core/templates/discovery.md +2 -2
  265. package/pan-wizard-core/templates/phase-prompt.md +7 -0
  266. package/pan-wizard-core/templates/requirements.md +9 -0
  267. package/pan-wizard-core/templates/research.md +10 -0
  268. package/pan-wizard-core/templates/summary-complex.md +5 -1
  269. package/pan-wizard-core/templates/summary-minimal.md +4 -0
  270. package/pan-wizard-core/templates/summary-standard.md +5 -1
  271. package/pan-wizard-core/templates/summary.md +8 -1
  272. package/pan-wizard-core/workflows/add-phase.md +4 -6
  273. package/pan-wizard-core/workflows/assumptions.md +19 -1
  274. package/pan-wizard-core/workflows/diagnose-issues.md +2 -0
  275. package/pan-wizard-core/workflows/discuss-phase.md +4 -2
  276. package/pan-wizard-core/workflows/exec-lean.md +69 -0
  277. package/pan-wizard-core/workflows/exec-phase.md +79 -15
  278. package/pan-wizard-core/workflows/execute-plan.md +3 -1
  279. package/{commands/pan → pan-wizard-core/workflows}/focus-doc-audit.md +13 -29
  280. package/{commands/pan → pan-wizard-core/workflows}/focus-drift-walking.md +3 -18
  281. package/{commands/pan → pan-wizard-core/workflows}/focus-exec.md +8 -23
  282. package/{commands/pan → pan-wizard-core/workflows}/focus-plan.md +6 -20
  283. package/{commands/pan → pan-wizard-core/workflows}/focus-scan.md +3 -16
  284. package/{commands/pan → pan-wizard-core/workflows}/focus-sync.md +7 -21
  285. package/pan-wizard-core/workflows/health.md +6 -0
  286. package/pan-wizard-core/workflows/help.md +114 -77
  287. package/pan-wizard-core/workflows/insert-phase.md +4 -6
  288. package/pan-wizard-core/workflows/learn.md +3 -3
  289. package/pan-wizard-core/workflows/milestone-audit.md +2 -2
  290. package/pan-wizard-core/workflows/milestone-new.md +38 -95
  291. package/pan-wizard-core/workflows/new-project.md +96 -258
  292. package/pan-wizard-core/workflows/optimize.md +107 -5
  293. package/pan-wizard-core/workflows/phase-tests.md +10 -0
  294. package/pan-wizard-core/workflows/plan-phase.md +106 -45
  295. package/pan-wizard-core/workflows/profile.md +50 -0
  296. package/pan-wizard-core/workflows/progress.md +10 -0
  297. package/pan-wizard-core/workflows/quick.md +34 -43
  298. package/pan-wizard-core/workflows/remove-phase.md +11 -1
  299. package/pan-wizard-core/workflows/research-phase.md +118 -40
  300. package/pan-wizard-core/workflows/resume-project.md +18 -2
  301. package/pan-wizard-core/workflows/settings.md +33 -19
  302. package/pan-wizard-core/workflows/todo-check.md +6 -2
  303. package/pan-wizard-core/workflows/transition.md +22 -4
  304. package/pan-wizard-core/workflows/uat-walkthrough.md +90 -0
  305. package/pan-wizard-core/workflows/update.md +1 -1
  306. package/pan-wizard-core/workflows/verify-phase.md +39 -46
  307. package/scripts/build-agent-plugin.js +35 -15
  308. package/scripts/build-help.cjs +106 -0
  309. package/scripts/build-plugin.js +10 -1
  310. package/scripts/deprecate-old-versions.js +70 -3
  311. package/scripts/generate-skills-docs.py +1 -1
  312. package/scripts/git-hooks/pre-push +27 -0
  313. package/scripts/install-git-hooks.js +7 -5
  314. package/scripts/install-pre-push.cjs +38 -0
  315. package/scripts/land.cjs +151 -0
  316. package/scripts/local-ci.cjs +501 -0
  317. package/scripts/local-schedule.cjs +277 -0
  318. package/scripts/mutation-probe.cjs +7 -80
  319. package/scripts/prompt-lint.cjs +32 -0
  320. package/scripts/prompt-rules.cjs +156 -0
  321. package/scripts/run-tests.cjs +7 -1
  322. package/scripts/test-quality-lint.cjs +3 -3
  323. package/scripts/test-surface.cjs +175 -6
  324. package/agents/pan-research-synthesizer.md +0 -246
  325. package/commands/pan/audit-deployment.md +0 -386
  326. package/commands/pan/dashboard.md +0 -22
  327. package/commands/pan/discord.md +0 -19
  328. package/commands/pan/mcp-bridge.md +0 -143
  329. package/commands/pan/milestone-cleanup.md +0 -19
  330. package/commands/pan/milestone-gaps.md +0 -35
  331. package/commands/pan/optimize.md +0 -115
  332. package/commands/pan/profile.md +0 -76
  333. package/commands/pan/research-phase.md +0 -189
  334. package/pan-wizard-core/bin/lib/bridge.cjs +0 -269
  335. package/pan-wizard-core/templates/research-project/architecture.md +0 -204
  336. package/pan-wizard-core/templates/research-project/features.md +0 -147
  337. package/pan-wizard-core/templates/research-project/pitfalls.md +0 -200
  338. package/pan-wizard-core/templates/research-project/stack.md +0 -120
  339. package/pan-wizard-core/templates/research-project/summary.md +0 -170
@@ -0,0 +1,90 @@
1
+ <purpose>
2
+ Walk the user through user acceptance testing for one phase, one test at a time, on any runtime. Record each answer through the engine, so every runtime leaves the same `{phase_num}-uat.md`. When the walkthrough finds issues, diagnose them, then hand the gaps to `/pan:plan-phase {phase_num} --gaps`.
3
+ </purpose>
4
+
5
+ <core_principle>
6
+ The user is the oracle here. You present what they should be able to observe, they say whether they observed it, and the engine writes it down. Never mark a test passed on their behalf, and never rephrase their report: an issue is recorded in their words.
7
+ </core_principle>
8
+
9
+ <process>
10
+
11
+ <step name="initialize">
12
+ ```bash
13
+ INIT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs init phase-op "${PHASE_ARG}")
14
+ ```
15
+ Take `phase_dir`, `phase_number` and `phase_name` from the JSON. Look for an existing session:
16
+
17
+ ```bash
18
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs uat status "${PHASE_NUMBER}"
19
+ ```
20
+
21
+ - **A session exists with tests pending:** resume at the first pending test.
22
+ - **A session exists and is complete:** show its summary. If it has gaps, go to `diagnose`; otherwise go to `done`.
23
+ - **No session (`uat_not_found`):** go to `build_tests`.
24
+ </step>
25
+
26
+ <step name="build_tests">
27
+ Create the file, then fill in its tests:
28
+
29
+ ```bash
30
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs scaffold uat --phase "${PHASE_NUMBER}"
31
+ ```
32
+
33
+ Read the phase's summaries (`{phase_dir}/*-summary.md`) and its plans' `must_haves`. Write one test per user-observable truth into the file's `## Tests` section, each as:
34
+
35
+ ```markdown
36
+ ### N. <short name>
37
+ expected: <what the user should be able to see or do, concretely: the command, the screen, the output>
38
+ result: [pending]
39
+ ```
40
+
41
+ Keep to what a person can observe without reading the code. Write the test list once, in full, then leave every result to the engine.
42
+ </step>
43
+
44
+ <step name="walk">
45
+ For each pending test, in order:
46
+
47
+ 1. Show the test: its name and its `expected` behaviour, with the exact steps to observe it.
48
+ 2. Ask for the result:
49
+ ```
50
+ AskUserQuestion([
51
+ { question: "Test N: <name>. Did you observe the expected behaviour?", header: "UAT", multiSelect: false, options: [
52
+ { label: "Pass", description: "It behaves as expected" },
53
+ { label: "Issue", description: "Something differs; describe what you saw" },
54
+ { label: "Skip", description: "Cannot test this now" }
55
+ ] }
56
+ ])
57
+ ```
58
+ Runtimes without AskUserQuestion ask the same question in plain text and take the answer from the reply.
59
+ 3. Record it, in the user's own words for an issue:
60
+ ```bash
61
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs uat record "${PHASE_NUMBER}" --test N --result pass
62
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs uat record "${PHASE_NUMBER}" --test N --result issue --reported "<their words>" --severity major
63
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs uat record "${PHASE_NUMBER}" --test N --result skipped --reason "<why>"
64
+ ```
65
+ Severity: `blocker` (cannot use the feature), `major` (wrong behaviour), `minor` (works, but rough), `cosmetic`.
66
+
67
+ When no test is pending, the engine marks the session `complete`.
68
+ </step>
69
+
70
+ <step name="diagnose">
71
+ ```bash
72
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs uat status "${PHASE_NUMBER}"
73
+ ```
74
+
75
+ If `gaps` is empty, go to `done`. Otherwise follow the diagnose-issues workflow (@~/.claude/pan-wizard-core/workflows/diagnose-issues.md). On Claude Code the native `/pan-diagnose-issues {phase_num}` script does the same in parallel. Diagnosis fills each gap's `root_cause`, `artifacts`, `missing` and `debug_session`, and the engine keeps those fields across any later re-record.
76
+ </step>
77
+
78
+ <step name="done">
79
+ Report the summary (`passed`, `issues`, `skipped`). With gaps:
80
+
81
+ ```
82
+ UAT found {issues} issue(s), diagnosed in {phase_num}-uat.md.
83
+
84
+ Next: /pan:plan-phase {phase_num} --gaps
85
+ ```
86
+
87
+ Without gaps: "UAT passed. Continue with `/pan:exec-phase {phase_num}` (transition) or the next phase."
88
+ </step>
89
+
90
+ </process>
@@ -197,7 +197,7 @@ Format completion message (changelog was already shown in confirmation step):
197
197
 
198
198
  ⚠️ Restart your AI coding tool to pick up the new commands.
199
199
 
200
- [View full changelog](https://github.com/oharms/PanWizard/blob/main/CHANGELOG.md)
200
+ Full changelog: ~/.claude/pan-wizard-core/CHANGELOG.md
201
201
  ```
202
202
  </step>
203
203
 
@@ -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
- 1. Detect whether a test script exists. **This decides `skipped` vs `failed` later**, so
93
- it must be answered BEFORE running anything — `npm test` on a project with no `test`
94
- script exits non-zero with "Missing script", which is indistinguishable from a crash
95
- once you are only looking at the exit code.
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
- HAS_TEST=$(node -e "try{const p=require('./package.json');process.stdout.write(p.scripts&&p.scripts.test?'yes':'no')}catch(e){process.stdout.write('no')}")
98
+ TEST_RUN=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs test run --phase "${phase_number}")
99
99
  ```
100
100
 
101
- **If `HAS_TEST` is `no`:** record `test_gate_status: skipped` and go to step 4. Do not
102
- run the suite, and do not report a crash — there is nothing to run.
101
+ Read from the JSON: `status`, `reason`, `command`, `total`, `passed`, `failed`,
102
+ `regressions`, `preexisting_failures` and `record`.
103
103
 
104
- 2. Run test suite and capture results:
105
- ```bash
106
- TEST_OUTPUT=$(npm test 2>&1)
107
- TEST_EXIT=$?
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
- 3. Evaluate results.
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
- **Check `TEST_EXIT` FIRST, before any count.** A suite that did not run emits no
116
- `ℹ fail` / `# fail` line at all, so `TEST_FAIL` comes back EMPTY — not `0`. Reading an empty
117
- value as "no failures" scores a crashed suite as a pass, which is the worst
118
- direction this gate can fail in: a phase ships green on a project whose tests never
119
- executed. Empty is not zero. Judge the exit code, then the counts.
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
- | Condition | Action |
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, unless the project chose gate mode).
128
123
 
129
- **The distinction that matters:** *no test command exists* is a project that never had
130
- tests — a known, acceptable gap. *A test command exists and did not run* is a broken
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
- 4. Store test gate results for inclusion in verification.md:
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
- **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.
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: in `report` mode it never changes the status. In `gate` mode (`workflow.mutation_gate: gate`) the result carries `gate`: when `gate.failed` is true (the score is below `workflow.mutation_floor`), set the status to `gaps_found` and list each survivor as a gap; `verify reconcile` refuses a passed verification over a failed gate. `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">
@@ -15,9 +15,17 @@
15
15
  * canonical agent reference copies under agents/
16
16
  *
17
17
  * hooks/pan-*.js PAN's hook scripts (pure Node), shared by every vendor
18
- * hooks/hooks.json Codex: default plugin hooks location; matcher-group
18
+ * hooks/hooks.json Codex's default plugin hooks location; matcher-group
19
19
  * shape with `${PLUGIN_ROOT}` paths and `async` observers
20
- * (developers.openai.com/plugins/build/plugins, 2026-09-10)
20
+ * (developers.openai.com/plugins/build/plugins, 2026-09-10).
21
+ * NOT LOADED BY CODEX for this bundle: a root plugin.json
22
+ * with the agent-plugins.org schema makes Codex treat the
23
+ * plugin as an Agent Plugin, and its loader then skips
24
+ * hooks entirely (codex-rs/core-plugins/src/loader.rs,
25
+ * "Enforce Agent Plugin runtime boundaries" #37027,
26
+ * 2026-08-05; same at rust-v0.163.0; read 2026-10-19, R55).
27
+ * Codex users get PAN's hooks from a `--codex` install
28
+ * (.codex/hooks.json). Kept for the other consumers.
21
29
  * com.github.copilot/ Copilot's reverse-domain namespace (ADR-0045 D5):
22
30
  * agents/pan-*.agent.md agents in Copilot's format
23
31
  * hooks/hooks.json flat PascalCase format, `${CLAUDE_PLUGIN_ROOT}` paths
@@ -90,25 +98,35 @@ function emitSkills(srcDir, skillsDir, prefix) {
90
98
  if (entry.isDirectory()) { recurse(srcPath, `${currentPrefix}-${entry.name}`); continue; }
91
99
  if (!entry.name.endsWith('.md')) continue;
92
100
  const skillName = `${currentPrefix}-${entry.name.replace(/\.md$/, '')}`;
93
- const skillDir = path.join(skillsDir, skillName);
94
- fs.mkdirSync(skillDir, { recursive: true });
95
- let content = fs.readFileSync(srcPath, 'utf8');
96
- content = lib.rewriteUnifiedSkillCommandContent(content, REWRITE);
97
- content = lib.convertClaudeCommandToUnifiedSkill(content, skillName, { adapterNote: lib.agentPluginSkillAdapterNote() });
98
- const { skill, reference } = lib.splitOversizedSkill(content, skillName);
99
- fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skill);
100
- if (reference) {
101
- const refPath = path.join(skillDir, ...lib.AGENT_PLUGIN_SKILL_REFERENCE.split('/'));
102
- fs.mkdirSync(path.dirname(refPath), { recursive: true });
103
- fs.writeFileSync(refPath, reference);
104
- split++;
105
- }
101
+ if (emitSkill(fs.readFileSync(srcPath, 'utf8'), skillsDir, skillName)) split++;
106
102
  count++;
107
103
  }
108
104
  })(srcDir, prefix);
105
+ // Renamed commands keep their old names as aliases, as the installer writes them (L7).
106
+ const { COMMAND_ALIASES } = require(path.join(ROOT, 'pan-wizard-core', 'bin', 'lib', 'constants.cjs'));
107
+ for (const [oldName, alias] of Object.entries(COMMAND_ALIASES)) {
108
+ const target = fs.readFileSync(path.join(srcDir, `${alias.to}.md`), 'utf8');
109
+ if (emitSkill(lib.renderCommandAlias(target, oldName, alias), skillsDir, `${prefix}-${oldName}`)) split++;
110
+ count++;
111
+ }
109
112
  return { count, split };
110
113
  }
111
114
 
115
+ /** One command → skills/<name>/SKILL.md (plus a reference file when split). Returns true when split. */
116
+ function emitSkill(content, skillsDir, skillName) {
117
+ const skillDir = path.join(skillsDir, skillName);
118
+ fs.mkdirSync(skillDir, { recursive: true });
119
+ content = lib.rewriteUnifiedSkillCommandContent(content, REWRITE);
120
+ content = lib.convertClaudeCommandToUnifiedSkill(content, skillName, { adapterNote: lib.agentPluginSkillAdapterNote() });
121
+ const { skill, reference } = lib.splitOversizedSkill(content, skillName);
122
+ fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skill);
123
+ if (!reference) return false;
124
+ const refPath = path.join(skillDir, ...lib.AGENT_PLUGIN_SKILL_REFERENCE.split('/'));
125
+ fs.mkdirSync(path.dirname(refPath), { recursive: true });
126
+ fs.writeFileSync(refPath, reference);
127
+ return true;
128
+ }
129
+
112
130
  /** pan-wizard-core → bundle, markdown rewritten, everything else verbatim. */
113
131
  function emitCore(srcDir, destDir) {
114
132
  (function recurse(currentSrc, currentDest) {
@@ -133,6 +151,8 @@ function emitCore(srcDir, destDir) {
133
151
  if (err.code !== 'ENOENT') throw err;
134
152
  }
135
153
  fs.writeFileSync(path.join(destDir, 'VERSION'), pkg.version);
154
+ // `/pan:update` points at the installed changelog, as a loose-file install carries it.
155
+ fs.copyFileSync(path.join(ROOT, 'CHANGELOG.md'), path.join(destDir, 'CHANGELOG.md'));
136
156
  }
137
157
 
138
158
  /** Canonical agent reference copies under <core>/agents/ (ADR-0028). */
@@ -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 };
@@ -111,7 +111,14 @@ function main() {
111
111
  );
112
112
 
113
113
  // 2. Commands (Claude flavor, plugin-root-relative paths)
114
- copyTree(path.join(ROOT, 'commands', 'pan'), path.join(OUT, 'commands', 'pan'), rewriteContent);
114
+ // Commands are user-invoked only on Claude Code (M49): out of the model's listing.
115
+ copyTree(path.join(ROOT, 'commands', 'pan'), path.join(OUT, 'commands', 'pan'), (c) => lib.withClaudeUserInvokedOnly(rewriteContent(c)));
116
+ // Renamed commands keep their old names as aliases, as the installer writes them (L7).
117
+ const { COMMAND_ALIASES } = require(path.join(ROOT, 'pan-wizard-core', 'bin', 'lib', 'constants.cjs'));
118
+ for (const [oldName, alias] of Object.entries(COMMAND_ALIASES)) {
119
+ const target = fs.readFileSync(path.join(ROOT, 'commands', 'pan', `${alias.to}.md`), 'utf8');
120
+ fs.writeFileSync(path.join(OUT, 'commands', 'pan', `${oldName}.md`), lib.withClaudeUserInvokedOnly(rewriteContent(lib.renderCommandAlias(target, oldName, alias))));
121
+ }
115
122
 
116
123
  // 3. Agents
117
124
  copyTree(path.join(ROOT, 'agents'), path.join(OUT, 'agents'), rewriteContent);
@@ -152,6 +159,8 @@ function main() {
152
159
  copyTree(path.join(ROOT, 'pan-wizard-core'), path.join(OUT, 'pan-wizard-core'), rewriteContent);
153
160
  fs.rmSync(path.join(OUT, 'pan-wizard-core', 'learnings', 'internal'), { recursive: true, force: true });
154
161
  fs.writeFileSync(path.join(OUT, 'pan-wizard-core', 'VERSION'), pkg.version);
162
+ // `/pan:update` points at the installed changelog, as a loose-file install carries it.
163
+ fs.copyFileSync(path.join(ROOT, 'CHANGELOG.md'), path.join(OUT, 'pan-wizard-core', 'CHANGELOG.md'));
155
164
 
156
165
  // 6. Native workflows. A plugin loads `workflows/` at its root and exposes each
157
166
  // script as `/<plugin>:<meta.name>`. Until 2026-09 the builder never wrote this
@@ -156,6 +156,58 @@ function npmJson(args, fallback = null) {
156
156
  return JSON.parse(out);
157
157
  }
158
158
 
159
+ /**
160
+ * Turn npm's stderr into the error that matters.
161
+ *
162
+ * WHY. npm writes warnings before the error, and on a GitHub runner the first
163
+ * line is setup-node's `npm warn Unknown user config "always-auth"` — present on
164
+ * every call, unrelated to any failure. Reporting only the first line made all 69
165
+ * failures across the 3.35.0 and 3.36.0 releases say that, hiding the cause. The
166
+ * real error is the `npm error code X` line plus the first other `npm error` line,
167
+ * skipping npm's closing "A complete log of this run..." pointer.
168
+ */
169
+ function summarizeNpmError(stderr) {
170
+ const lines = String(stderr || '').split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
171
+ let code = null;
172
+ let detail = null;
173
+ for (const l of lines) {
174
+ const m = /^npm (?:error|ERR!)\s*(.*)$/.exec(l);
175
+ if (!m) continue;
176
+ const rest = m[1].trim();
177
+ const c = /^code\s+(\S+)$/.exec(rest);
178
+ if (c) { code = code || c[1]; continue; }
179
+ if (!detail && rest && !/^A complete log of this run/i.test(rest)) detail = rest;
180
+ }
181
+ if (!detail) detail = lines.find((l) => !/^npm (warn|notice)\b/i.test(l)) || null;
182
+ return { code, detail };
183
+ }
184
+
185
+ /** Auth refusals: every further call with the same credential fails the same way. */
186
+ const AUTH_CODES = new Set(['E401', 'E403', 'EOTP', 'ENEEDAUTH']);
187
+ function isAuthFailure(code) {
188
+ return AUTH_CODES.has(code);
189
+ }
190
+
191
+ /**
192
+ * What the owner has to change, per auth failure. `npm deprecate` cannot use the
193
+ * OIDC trusted-publishing credential (npm grants that for `npm publish` only), so
194
+ * it runs on the NPM_TOKEN secret, and each hint points at that secret.
195
+ */
196
+ const AUTH_HINTS = {
197
+ E401: 'NPM_TOKEN is missing, expired or revoked — write-enabled granular tokens expire (90 days at most); create a new one and update the secret',
198
+ ENEEDAUTH: 'NPM_TOKEN is missing or empty — add it as a repository secret',
199
+ EOTP: 'NPM_TOKEN cannot get past 2FA — create the granular token with "Bypass 2FA" enabled',
200
+ E403: 'NPM_TOKEN has no write access to pan-wizard — give the granular token Read and write on the pan-wizard package',
201
+ };
202
+
203
+ /** One line for the log: `CODE: detail (hint)`, falling back to what npm or node said. */
204
+ function formatNpmError(stderr, fallback = '') {
205
+ const { code, detail } = summarizeNpmError(stderr);
206
+ const text = detail || String(fallback || '').split('\n')[0] || 'unknown error';
207
+ const head = code ? `${code}: ${text}` : text;
208
+ return AUTH_HINTS[code] ? `${head} (${AUTH_HINTS[code]})` : head;
209
+ }
210
+
159
211
  function main() {
160
212
  const args = process.argv.slice(2);
161
213
  const apply = args.includes('--apply');
@@ -185,7 +237,7 @@ function main() {
185
237
  // npm returns a bare string for a single version, or {version: message}.
186
238
  deprecatedAlready = (map && typeof map === 'object') ? Object.keys(map) : [];
187
239
  } catch (e) {
188
- console.error(`deprecate: could not read the registry (${String(e.message).split('\n')[0]}). Nothing changed.`);
240
+ console.error(`deprecate: could not read the registry (${formatNpmError(e.stderr, e.message)}). Nothing changed.`);
189
241
  return; // never fail the build over housekeeping
190
242
  }
191
243
 
@@ -210,16 +262,31 @@ function main() {
210
262
  console.log(` ✓ ${v}`);
211
263
  } catch (e) {
212
264
  failed++;
213
- console.error(` ✗ ${v}: ${String(e.stderr || e.message).split('\n')[0]}`);
265
+ console.error(` ✗ ${v}: ${formatNpmError(e.stderr, e.message)}`);
266
+ // An auth refusal repeats identically for every remaining version — say it
267
+ // once and stop rather than printing the same line 35 times.
268
+ if (isAuthFailure(summarizeNpmError(e.stderr).code)) {
269
+ const skipped = deprecate.length - deprecate.indexOf(v) - 1;
270
+ if (skipped > 0) console.error(` stopping: authentication refused — ${skipped} remaining version(s) not attempted.`);
271
+ break;
272
+ }
214
273
  }
215
274
  }
216
275
  if (failed) {
217
276
  // Reported, not fatal. The publish already succeeded; a red build here would
218
277
  // imply the release failed, which is false and worse than the omission.
219
278
  console.error(`deprecate: ${failed} of ${deprecate.length} failed — release is unaffected.`);
279
+ // continue-on-error hides a failed step inside the log; an annotation puts it
280
+ // on the run's summary page where the owner actually looks.
281
+ if (process.env.GITHUB_ACTIONS === 'true') {
282
+ console.log(`::warning title=Deprecation sweep failed::${failed} of ${deprecate.length} old versions were not deprecated — see the "Deprecate superseded versions" step log`);
283
+ }
220
284
  }
221
285
  }
222
286
 
223
287
  if (require.main === module) main();
224
288
 
225
- module.exports = { selectVersionsToDeprecate, buildMessage, parse, compare, assertQuotable };
289
+ module.exports = {
290
+ selectVersionsToDeprecate, buildMessage, parse, compare, assertQuotable,
291
+ summarizeNpmError, formatNpmError, isAuthFailure,
292
+ };
@@ -517,7 +517,7 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
517
517
  w("| Continuous improvement | `focus-auto --category <cat>` |")
518
518
  w("| Execute micro-prompts | `focus-auto --category prompts` |")
519
519
  w("| Feature investigation | `focus-design \"description\"` |")
520
- w("| Doc hygiene | `focus-drift-walking` or `focus-doc-audit` |")
520
+ w("| Doc hygiene | `focus-auto --step drift` or `focus-docs` |")
521
521
  w("")
522
522
 
523
523
  return "\n".join(lines)
@@ -0,0 +1,27 @@
1
+ #!/bin/sh
2
+ # PAN Wizard pre-push hook — the fast subset of the local CI (scripts/local-ci.cjs --fast):
3
+ # the suite on the current Node, the harness at tier 0, and gitleaks.
4
+ #
5
+ # Opt-in. core.hooksPath points every clone at this directory, so the hook is always
6
+ # present; it does nothing until you turn it on for this clone:
7
+ # npm run hooks:pre-push (git config pan.prePush true)
8
+ # npm run hooks:pre-push -- --off (turn it off again)
9
+ #
10
+ # Bypass once: SKIP_PREPUSH=1 git push or git push --no-verify
11
+ #
12
+ # Exit codes:
13
+ # 0 off, bypassed, or every gate passed (a skipped gate is listed, not passed)
14
+ # 1 a gate failed — read the summary and .ci-local/logs/ before pushing
15
+
16
+ if [ "$(git config --bool pan.prePush 2>/dev/null)" != "true" ]; then
17
+ exit 0
18
+ fi
19
+
20
+ if [ "${SKIP_PREPUSH:-}" = "1" ]; then
21
+ echo "[pre-push] SKIP_PREPUSH=1 — local CI bypassed." >&2
22
+ exit 0
23
+ fi
24
+
25
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
26
+ echo "[pre-push] local CI, fast subset (SKIP_PREPUSH=1 to bypass)…" >&2
27
+ exec node "$REPO_ROOT/scripts/local-ci.cjs" --fast
@@ -57,12 +57,14 @@ try {
57
57
  // through `prepare`, every Linux and macOS checkout was left with a one-bit dirty
58
58
  // tree that nothing looked at until CI began asserting the tree is unchanged
59
59
  // (2026-09-17).
60
- const hookFile = path.join(REPO_ROOT, HOOKS_DIR, 'pre-commit');
60
+ // pre-push is tracked here too but stays inert until `npm run hooks:pre-push` opts in.
61
61
  if (process.platform !== 'win32') {
62
- try {
63
- fs.chmodSync(hookFile, 0o755);
64
- } catch {
65
- // Best effort.
62
+ for (const name of ['pre-commit', 'pre-push']) {
63
+ try {
64
+ fs.chmodSync(path.join(REPO_ROOT, HOOKS_DIR, name), 0o755);
65
+ } catch {
66
+ // Best effort.
67
+ }
66
68
  }
67
69
  }
68
70
 
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * install-pre-push.cjs — turn the local-CI pre-push hook on or off for this clone
4
+ * (`npm run hooks:pre-push`, `npm run hooks:pre-push -- --off`).
5
+ *
6
+ * The hook itself is tracked at scripts/git-hooks/pre-push, where core.hooksPath already
7
+ * points (scripts/install-git-hooks.js). It is inert until `pan.prePush` is true in this
8
+ * clone's git config, so a fresh clone never runs the local CI on push unless its owner
9
+ * asked for it. This script sets or clears that key, and makes sure core.hooksPath is set.
10
+ *
11
+ * Exit 0 on success, 1 when git refuses.
12
+ */
13
+
14
+ 'use strict';
15
+
16
+ const { spawnSync } = require('child_process');
17
+ const path = require('path');
18
+
19
+ const REPO_ROOT = path.resolve(__dirname, '..');
20
+ const off = process.argv.includes('--off');
21
+
22
+ function git(args) {
23
+ const r = spawnSync('git', args, { cwd: REPO_ROOT, encoding: 'utf8' });
24
+ if (r.status !== 0 && !(off && args.includes('--unset'))) {
25
+ console.error(`[pre-push] git ${args.join(' ')} failed: ${(r.stderr || r.error && r.error.message || '').trim()}`);
26
+ process.exit(1);
27
+ }
28
+ return r;
29
+ }
30
+
31
+ if (off) {
32
+ git(['config', '--local', '--unset', 'pan.prePush']);
33
+ console.error('[pre-push] off — git push no longer runs the local CI.');
34
+ } else {
35
+ git(['config', '--local', 'core.hooksPath', 'scripts/git-hooks']);
36
+ git(['config', '--local', 'pan.prePush', 'true']);
37
+ console.error('[pre-push] on — git push runs `node scripts/local-ci.cjs --fast` first (SKIP_PREPUSH=1 to bypass once; --off to remove).');
38
+ }