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.
- package/CHANGELOG.md +3645 -0
- package/README.md +46 -52
- package/agents/pan-conductor.md +2 -3
- package/agents/pan-counterfactual.md +1 -2
- package/agents/pan-debugger.md +14 -3
- package/agents/pan-design-checker.md +1 -2
- package/agents/pan-designer.md +2 -3
- package/agents/pan-document_code.md +1 -2
- package/agents/pan-executor.md +25 -0
- package/agents/pan-hardener.md +4 -3
- package/agents/pan-integration-checker.md +1 -2
- package/agents/pan-knowledge.md +1 -2
- package/agents/pan-meta-reviewer.md +3 -3
- package/agents/pan-optimizer.md +4 -4
- package/agents/pan-phase-researcher.md +80 -475
- package/agents/pan-plan-checker.md +40 -3
- package/agents/pan-planner.md +21 -7
- package/agents/pan-previewer.md +3 -2
- package/agents/pan-project-researcher.md +72 -493
- package/agents/pan-release.md +1 -1
- package/agents/pan-reviewer.md +14 -3
- package/agents/pan-roadmapper.md +12 -7
- package/agents/pan-verifier.md +9 -4
- package/bin/install-lib.cjs +134 -14
- package/bin/install.js +59 -12
- package/commands/pan/army.md +1 -1
- package/commands/pan/autodev.md +76 -0
- package/commands/pan/cost.md +21 -1
- package/commands/pan/exec-phase.md +3 -4
- package/commands/pan/focus-auto.md +14 -7
- package/commands/pan/focus-design.md +4 -5
- package/commands/pan/focus-docs.md +24 -0
- package/commands/pan/learn.md +13 -6
- package/commands/pan/milestone-audit.md +8 -1
- package/commands/pan/milestone-done.md +10 -5
- package/commands/pan/milestone-new.md +2 -2
- package/commands/pan/new-project.md +15 -12
- package/commands/pan/plan-phase.md +15 -9
- package/commands/pan/preview.md +1 -1
- package/commands/pan/quick.md +1 -1
- package/commands/pan/review-deep.md +11 -5
- package/commands/pan/settings.md +6 -0
- package/commands/pan/verify-phase.md +6 -2
- package/docs/AGENTS.md +917 -0
- package/docs/ARCHITECTURE.md +1054 -0
- package/docs/CLI-REFERENCE.md +4582 -0
- package/docs/COMPARISON.md +116 -0
- package/docs/DEVELOPMENT.md +490 -0
- package/docs/ECOSYSTEM-REVIEW-2026-06.md +107 -0
- package/docs/ECOSYSTEM-REVIEW-2026-08.md +349 -0
- package/docs/EXAMPLES.md +584 -0
- package/docs/FAQ.md +254 -0
- package/docs/FIELD-HARVEST-2026-07.md +88 -0
- package/docs/FIELD-REPORT-army-2026-06.md +121 -0
- package/docs/HOOKS.md +638 -0
- package/docs/IMPROVEMENT-TODO.md +246 -0
- package/docs/INTERNALS.md +485 -0
- package/docs/MIGRATION-v2-to-v3.md +258 -0
- package/docs/SECURITY-HARDENING.md +230 -0
- package/docs/SKILLS-ENHANCEMENT-PLAN-V2.md +122 -0
- package/docs/SKILLS-FULL-TEXT.md +9685 -0
- package/docs/SKILLS-REFERENCE.md +1037 -0
- package/docs/TROUBLESHOOTING.md +1084 -0
- package/docs/USER-GUIDE.md +1437 -0
- package/docs/archive/SKILLS-ENHANCEMENT-PLAN.md +230 -0
- package/docs/audits/AUDIT-2026-08-e2e-ROADMAP.md +117 -0
- package/docs/audits/AUDIT-2026-08-e2e-VERIFICATION.md +693 -0
- package/docs/audits/AUDIT-2026-08-e2e.md +1546 -0
- package/docs/audits/OUTSTANDING-2026-08.md +275 -0
- package/docs/audits/STABILITY-TEST-2026-08.md +640 -0
- package/docs/branding/README-brand-draft.md +119 -0
- package/docs/branding/handoff/IMPLEMENTATION.md +205 -0
- package/docs/branding/handoff/README-brand-draft.md +119 -0
- package/docs/branding/handoff/image-prompts.md +46 -0
- package/docs/branding/image-prompts.md +46 -0
- package/docs/branding/nano-banana-prompts.txt +60 -0
- package/docs/context-monitor.md +13 -0
- package/docs/decisions/ADR-0001-strategic-feature-prioritization.md +83 -0
- package/docs/decisions/ADR-0002-copilot-cli-runtime.md +71 -0
- package/docs/decisions/ADR-0003-smart-execution.md +84 -0
- package/docs/decisions/ADR-0004-copilot-cli-interaction.md +89 -0
- package/docs/decisions/ADR-0005-command-naming.md +80 -0
- package/docs/decisions/ADR-0006-focus-commands.md +101 -0
- package/docs/decisions/ADR-0007-ship-v1.md +73 -0
- package/docs/decisions/ADR-0008-map-codebase-mermaid-togaf.md +80 -0
- package/docs/decisions/ADR-0009-production-deployment-checklist.md +68 -0
- package/docs/decisions/ADR-0010-standards-integration.md +79 -0
- package/docs/decisions/ADR-0011-help-commands-rewrite.md +64 -0
- package/docs/decisions/ADR-0012-contributors-attribution-index.md +42 -0
- package/docs/decisions/ADR-0013-strategic-feature-additions.md +53 -0
- package/docs/decisions/ADR-0014-internal-cleanup-code-quality.md +53 -0
- package/docs/decisions/ADR-0015-focus-auto-runner.md +296 -0
- package/docs/decisions/ADR-0016-enhanced-doc-sync.md +54 -0
- package/docs/decisions/ADR-0017-enhanced-focus-design.md +69 -0
- package/docs/decisions/ADR-0018-user-reality-testing.md +84 -0
- package/docs/decisions/ADR-0019-end-to-end-user-acceptance-testing.md +113 -0
- package/docs/decisions/ADR-0020-ai-drift-prevention.md +55 -0
- package/docs/decisions/ADR-0021-codebase-mapper-v2.md +76 -0
- package/docs/decisions/ADR-0022-lifecycle-completeness.md +63 -0
- package/docs/decisions/ADR-0023-opus-4-7-adoption.md +89 -0
- package/docs/decisions/ADR-0024-spec-b-v2-completion.md +137 -0
- package/docs/decisions/ADR-0025-behavioral-guardrails-layer.md +129 -0
- package/docs/decisions/ADR-0026-self-improvement-loop.md +171 -0
- package/docs/decisions/ADR-0027-doc-code-link-graph.md +164 -0
- package/docs/decisions/ADR-0028-unified-agents-skills-target.md +46 -0
- package/docs/decisions/ADR-0029-experiment-evaluator.md +76 -0
- package/docs/decisions/ADR-0030-planning-concurrency.md +37 -0
- package/docs/decisions/ADR-0031-focus-auto-backlog-source.md +47 -0
- package/docs/decisions/ADR-0032-squad-model.md +64 -0
- package/docs/decisions/ADR-0033-army-campaign.md +40 -0
- package/docs/decisions/ADR-0034-scheduled-campaigns.md +57 -0
- package/docs/decisions/ADR-0035-army-hud-dashboard.md +40 -0
- package/docs/decisions/ADR-0036-agentic-memory-architecture.md +106 -0
- package/docs/decisions/ADR-0037-pin-security-agents-to-opus.md +51 -0
- package/docs/decisions/ADR-0038-skill-aligned-decomposition.md +41 -0
- package/docs/decisions/ADR-0039-worktree-as-project-variant.md +37 -0
- package/docs/decisions/ADR-0040-memory-injection-defense.md +55 -0
- package/docs/decisions/ADR-0041-mcp-dual-era-bridge.md +47 -0
- package/docs/decisions/ADR-0042-design-parity-both-flows.md +45 -0
- package/docs/decisions/ADR-0043-addressable-planning-roots.md +56 -0
- package/docs/decisions/ADR-0044-bound-the-cached-context.md +104 -0
- package/docs/decisions/ADR-0045-agent-plugins-bundle.md +76 -0
- package/docs/decisions/ADR-0046-subagent-frontmatter-decisions.md +39 -0
- package/docs/decisions/ADR-0047-pan-harness.md +76 -0
- package/docs/decisions/ADR-0048-one-core-per-project.md +43 -0
- package/docs/decisions/ADR-0049-machine-verdicts-and-findings-ledger.md +116 -0
- package/docs/specs/ai_drift_prevention_featureai.md +286 -0
- package/docs/specs/codebase_mapper_v2_featureai.md +930 -0
- package/docs/specs/command_naming_optimization_featureai.md +930 -0
- package/docs/specs/comp_analysis_markdown_v1.md +149 -0
- package/docs/specs/continuous_autonomous_execution_featureai.md +304 -0
- package/docs/specs/contributors_attribution_index_featureai.md +476 -0
- package/docs/specs/copilot_cli_interaction_featureai.md +868 -0
- package/docs/specs/copilot_cli_runtime_featureai.md +647 -0
- package/docs/specs/custom-skills-assessment.md +461 -0
- package/docs/specs/deployment_audit_findings_featureai.md +243 -0
- package/docs/specs/doc_code_link_graph_featureai.md +253 -0
- package/docs/specs/documentation_alignment_cleanup_featureai.md +69 -0
- package/docs/specs/e2e_visual_testing_featureai.md +615 -0
- package/docs/specs/end_to_end_user_acceptance_testing_featureai.md +810 -0
- package/docs/specs/evidence-loop-plan.md +76 -0
- package/docs/specs/evidence_loop_featureai.md +497 -0
- package/docs/specs/focus-auto-optimize-category.md +449 -0
- package/docs/specs/focus-auto-optimize-superplan.md +188 -0
- package/docs/specs/focus_auto_runner_featureai.md +1102 -0
- package/docs/specs/focus_design_v2_featureai.md +197 -0
- package/docs/specs/focus_sync_v2_featureai.md +202 -0
- package/docs/specs/git_integration_overhaul_featureai.md +326 -0
- package/docs/specs/glm_zai_provider_featureai.md +200 -0
- package/docs/specs/googlecli_adoption_featureai.md +661 -0
- package/docs/specs/help_commands_rewrite_featureai.md +860 -0
- package/docs/specs/industry_analysis_strategic_additions_featureai.md +231 -0
- package/docs/specs/industry_comparison_and_feature_gaps_featureai.md +674 -0
- package/docs/specs/internal_cleanup_code_quality_featureai.md +486 -0
- package/docs/specs/investigations/README.md +31 -0
- package/docs/specs/investigations/digests/2026-09-28.md +47 -0
- package/docs/specs/investigations/digests/2026-10-08.md +62 -0
- package/docs/specs/investigations/digests/2026-10-10.md +61 -0
- package/docs/specs/investigations/features/debugger-red-loop-first.md +55 -0
- package/docs/specs/investigations/features/harness-cross-host-behaviour.md +93 -0
- package/docs/specs/investigations/features/optimize-apply-regression-gate.md +66 -0
- package/docs/specs/investigations/features/reviewer-smell-baseline.md +57 -0
- package/docs/specs/investigations/features/trace-failure-capture.md +69 -0
- package/docs/specs/lifecycle_completeness_featureai.md +754 -0
- package/docs/specs/local-first-ci.md +42 -0
- package/docs/specs/map_codebase_mermaid_togaf_featureai.md +805 -0
- package/docs/specs/market-delta-2026-09-superplan.md +310 -0
- package/docs/specs/market-ideas-2026-09.md +131 -0
- package/docs/specs/market-ideas-2026-10.md +428 -0
- package/docs/specs/market-ideas-ledger.md +177 -0
- package/docs/specs/memory-optimization-2026-10.md +285 -0
- package/docs/specs/multi-track-planning-roots.md +143 -0
- package/docs/specs/multi_model_routing_featureai.md +687 -0
- package/docs/specs/multi_model_routing_superplan.md +197 -0
- package/docs/specs/opus_47_existing_enhancements_featureai.md +247 -0
- package/docs/specs/opus_47_extended_features_featureai.md +363 -0
- package/docs/specs/opus_47_extended_features_v2_featureai.md +397 -0
- package/docs/specs/pan_focus_commands_featureai.md +2336 -0
- package/docs/specs/pan_zcode_mcp_bridge_featureai.md +120 -0
- package/docs/specs/product-excellence-superplan.md +315 -0
- package/docs/specs/product_excellence_program_2026_q4_featureai.md +365 -0
- package/docs/specs/production_deployment_readiness_featureai.md +433 -0
- package/docs/specs/production_readiness_ship_v1_featureai.md +698 -0
- package/docs/specs/real_test_enforcement_featureai.md +213 -0
- package/docs/specs/reality-check-2026-09-superplan.md +362 -0
- package/docs/specs/right-sized-ceremony.md +74 -0
- package/docs/specs/roadmap_and_competition_2026_q4_featureai.md +390 -0
- package/docs/specs/self_improvement_loop_featureai.md +875 -0
- package/docs/specs/skill-aligned-decomposition.md +155 -0
- package/docs/specs/standards_integration_featureai.md +833 -0
- package/docs/specs/testing-system-redesign-2026-09.md +267 -0
- package/docs/specs/user_reality_testing_system_featureai.md +788 -0
- package/docs/specs/watch-triggers.json +22 -0
- package/docs/specs/workflow-integration-redesign.md +742 -0
- package/docs/specs/workflow_state_consistency_featureai.md +183 -0
- package/hooks/dist/pan-context-monitor.js +9 -2
- package/hooks/dist/pan-cost-logger.js +5 -0
- package/hooks/dist/pan-guard.js +28 -5
- package/hooks/dist/pan-stop-guard.js +9 -9
- package/hooks/dist/pan-trace-logger.js +5 -0
- package/package.json +10 -2
- package/pan-wizard-core/bin/lib/agents-md.cjs +57 -8
- package/pan-wizard-core/bin/lib/autodev-report.cjs +180 -0
- package/pan-wizard-core/bin/lib/autodev.cjs +642 -0
- package/pan-wizard-core/bin/lib/ci.cjs +143 -0
- package/pan-wizard-core/bin/lib/commands.cjs +1 -1
- package/pan-wizard-core/bin/lib/config.cjs +41 -5
- package/pan-wizard-core/bin/lib/constants.cjs +27 -1
- package/pan-wizard-core/bin/lib/core.cjs +31 -14
- package/pan-wizard-core/bin/lib/cost.cjs +160 -4
- package/pan-wizard-core/bin/lib/cross-family.cjs +164 -0
- package/pan-wizard-core/bin/lib/debug-cases.cjs +104 -0
- package/pan-wizard-core/bin/lib/doc-lint.cjs +5 -3
- package/pan-wizard-core/bin/lib/failure-class.cjs +81 -0
- package/pan-wizard-core/bin/lib/findings.cjs +148 -9
- package/pan-wizard-core/bin/lib/focus.cjs +1 -1
- package/pan-wizard-core/bin/lib/git.cjs +1 -1
- package/pan-wizard-core/bin/lib/hosts.cjs +88 -0
- package/pan-wizard-core/bin/lib/init.cjs +7 -2
- package/pan-wizard-core/bin/lib/knowledge.cjs +2 -0
- package/pan-wizard-core/bin/lib/merge.cjs +50 -0
- package/pan-wizard-core/bin/lib/mutate.cjs +268 -0
- package/pan-wizard-core/bin/lib/next-action.cjs +112 -0
- package/pan-wizard-core/bin/lib/optimize.cjs +2 -2
- package/pan-wizard-core/bin/lib/phase-gate.cjs +15 -9
- package/pan-wizard-core/bin/lib/phase-remove.cjs +91 -11
- package/pan-wizard-core/bin/lib/phase.cjs +85 -13
- package/pan-wizard-core/bin/lib/plan-lint.cjs +310 -0
- package/pan-wizard-core/bin/lib/preview.cjs +26 -4
- package/pan-wizard-core/bin/lib/requirements-lint.cjs +130 -0
- package/pan-wizard-core/bin/lib/research-lint.cjs +268 -0
- package/pan-wizard-core/bin/lib/review-deep.cjs +14 -22
- package/pan-wizard-core/bin/lib/review-vote.cjs +105 -0
- package/pan-wizard-core/bin/lib/roadmap.cjs +1 -0
- package/pan-wizard-core/bin/lib/runner.cjs +2 -16
- package/pan-wizard-core/bin/lib/sizing.cjs +356 -0
- package/pan-wizard-core/bin/lib/squads.cjs +1 -1
- package/pan-wizard-core/bin/lib/state-write.cjs +247 -0
- package/pan-wizard-core/bin/lib/test-gate.cjs +433 -0
- package/pan-wizard-core/bin/lib/uat.cjs +149 -0
- package/pan-wizard-core/bin/lib/usage.cjs +104 -0
- package/pan-wizard-core/bin/lib/verdict.cjs +26 -3
- package/pan-wizard-core/bin/lib/verify-plan-set.cjs +30 -1
- package/pan-wizard-core/bin/lib/verify-preflight.cjs +2 -2
- package/pan-wizard-core/bin/lib/verify-red.cjs +174 -0
- package/pan-wizard-core/bin/lib/verify-retro.cjs +3 -2
- package/pan-wizard-core/bin/lib/verify-scope.cjs +143 -2
- package/pan-wizard-core/bin/lib/verify.cjs +86 -31
- package/pan-wizard-core/bin/lib/worktree.cjs +70 -0
- package/pan-wizard-core/bin/pan-tools.cjs +257 -28
- package/pan-wizard-core/learnings/universal/autonomous-loop.md +2 -2
- package/pan-wizard-core/mcp/orchestrator.cjs +4 -1
- package/pan-wizard-core/references/continuation-format.md +3 -3
- package/pan-wizard-core/references/design-methodology.md +1 -1
- package/pan-wizard-core/references/guardrails.md +1 -1
- package/pan-wizard-core/references/handoff-decisions.md +1 -1
- package/pan-wizard-core/references/model-profiles.md +2 -3
- package/pan-wizard-core/references/questioning.md +24 -0
- package/pan-wizard-core/references/ui-brand.md +4 -6
- package/pan-wizard-core/references/verdict-contract.md +2 -1
- package/pan-wizard-core/templates/config.json +10 -2
- package/pan-wizard-core/templates/debug.md +1 -0
- package/pan-wizard-core/templates/design.md +5 -4
- package/pan-wizard-core/templates/discovery.md +2 -2
- package/pan-wizard-core/templates/phase-prompt.md +7 -0
- package/pan-wizard-core/templates/requirements.md +9 -0
- package/pan-wizard-core/templates/research.md +10 -0
- package/pan-wizard-core/templates/summary-complex.md +5 -1
- package/pan-wizard-core/templates/summary-minimal.md +4 -0
- package/pan-wizard-core/templates/summary-standard.md +5 -1
- package/pan-wizard-core/templates/summary.md +8 -1
- package/pan-wizard-core/workflows/add-phase.md +4 -6
- package/pan-wizard-core/workflows/assumptions.md +19 -1
- package/pan-wizard-core/workflows/diagnose-issues.md +2 -0
- package/pan-wizard-core/workflows/discuss-phase.md +4 -2
- package/pan-wizard-core/workflows/exec-lean.md +69 -0
- package/pan-wizard-core/workflows/exec-phase.md +79 -15
- package/pan-wizard-core/workflows/execute-plan.md +3 -1
- package/{commands/pan → pan-wizard-core/workflows}/focus-doc-audit.md +13 -29
- package/{commands/pan → pan-wizard-core/workflows}/focus-drift-walking.md +3 -18
- package/{commands/pan → pan-wizard-core/workflows}/focus-exec.md +8 -23
- package/{commands/pan → pan-wizard-core/workflows}/focus-plan.md +6 -20
- package/{commands/pan → pan-wizard-core/workflows}/focus-scan.md +3 -16
- package/{commands/pan → pan-wizard-core/workflows}/focus-sync.md +7 -21
- package/pan-wizard-core/workflows/health.md +6 -0
- package/pan-wizard-core/workflows/help.md +114 -77
- package/pan-wizard-core/workflows/insert-phase.md +4 -6
- package/pan-wizard-core/workflows/learn.md +3 -3
- package/pan-wizard-core/workflows/milestone-audit.md +2 -2
- package/pan-wizard-core/workflows/milestone-new.md +38 -95
- package/pan-wizard-core/workflows/new-project.md +96 -258
- package/pan-wizard-core/workflows/optimize.md +107 -5
- package/pan-wizard-core/workflows/phase-tests.md +10 -0
- package/pan-wizard-core/workflows/plan-phase.md +106 -45
- package/pan-wizard-core/workflows/profile.md +50 -0
- package/pan-wizard-core/workflows/progress.md +10 -0
- package/pan-wizard-core/workflows/quick.md +34 -43
- package/pan-wizard-core/workflows/remove-phase.md +11 -1
- package/pan-wizard-core/workflows/research-phase.md +118 -40
- package/pan-wizard-core/workflows/resume-project.md +18 -2
- package/pan-wizard-core/workflows/settings.md +33 -19
- package/pan-wizard-core/workflows/todo-check.md +6 -2
- package/pan-wizard-core/workflows/transition.md +22 -4
- package/pan-wizard-core/workflows/uat-walkthrough.md +90 -0
- package/pan-wizard-core/workflows/update.md +1 -1
- package/pan-wizard-core/workflows/verify-phase.md +39 -46
- package/scripts/build-agent-plugin.js +35 -15
- package/scripts/build-help.cjs +106 -0
- package/scripts/build-plugin.js +10 -1
- package/scripts/deprecate-old-versions.js +70 -3
- package/scripts/generate-skills-docs.py +1 -1
- package/scripts/git-hooks/pre-push +27 -0
- package/scripts/install-git-hooks.js +7 -5
- package/scripts/install-pre-push.cjs +38 -0
- package/scripts/land.cjs +151 -0
- package/scripts/local-ci.cjs +501 -0
- package/scripts/local-schedule.cjs +277 -0
- package/scripts/mutation-probe.cjs +7 -80
- package/scripts/prompt-lint.cjs +32 -0
- package/scripts/prompt-rules.cjs +156 -0
- package/scripts/run-tests.cjs +7 -1
- package/scripts/test-quality-lint.cjs +3 -3
- package/scripts/test-surface.cjs +175 -6
- package/agents/pan-research-synthesizer.md +0 -246
- package/commands/pan/audit-deployment.md +0 -386
- package/commands/pan/dashboard.md +0 -22
- package/commands/pan/discord.md +0 -19
- package/commands/pan/mcp-bridge.md +0 -143
- package/commands/pan/milestone-cleanup.md +0 -19
- package/commands/pan/milestone-gaps.md +0 -35
- package/commands/pan/optimize.md +0 -115
- package/commands/pan/profile.md +0 -76
- package/commands/pan/research-phase.md +0 -189
- package/pan-wizard-core/bin/lib/bridge.cjs +0 -269
- package/pan-wizard-core/templates/research-project/architecture.md +0 -204
- package/pan-wizard-core/templates/research-project/features.md +0 -147
- package/pan-wizard-core/templates/research-project/pitfalls.md +0 -200
- package/pan-wizard-core/templates/research-project/stack.md +0 -120
- package/pan-wizard-core/templates/research-project/summary.md +0 -170
package/agents/pan-reviewer.md
CHANGED
|
@@ -12,8 +12,7 @@ You are a PAN code reviewer. You perform read-only code review on files changed
|
|
|
12
12
|
|
|
13
13
|
Your job: Check convention compliance, security patterns, and code quality. You do NOT modify files — you report findings. This is authorized, defensive review of the user's own codebase — surface security-relevant findings for the user to remediate; never produce exploit code.
|
|
14
14
|
|
|
15
|
-
**
|
|
16
|
-
If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions. This is your primary context.
|
|
15
|
+
**Initial read.** If the prompt contains a `<files_to_read>` block, read every file it lists before doing anything else. This is your primary context.
|
|
17
16
|
|
|
18
17
|
**Read also:** `~/.claude/pan-wizard-core/references/guardrails.md` — anti-patterns and the Code Preservation Principle. Findings that violate Code Preservation (silent scope expansion, model swaps, refactor-while-here) should be flagged at high severity.
|
|
19
18
|
|
|
@@ -93,6 +92,10 @@ A fixed baseline that applies even when the project documents no standards (Fowl
|
|
|
93
92
|
|
|
94
93
|
## Scope (unrequested work)
|
|
95
94
|
|
|
95
|
+
When the prompt carries an `<intent>` block (the `review scope` JSON), it is what you judge the change against: each plan's `objective`, `must_haves` and `review_focus` (the risk the planner asked a reviewer to check, so check it first and say what you found), and the text of the requirements the plans claim. Its `unlisted` array names changed files no summary's key-files lists: review them as closely as the rest, and say in the report that the summary did not list them.
|
|
96
|
+
|
|
97
|
+
When the prompt carries an `<executor_concerns>` block, each entry is something an executor finished but was not sure of, with its cost if wrong. Check the high-cost ones against the code and report what you found: a concern that holds is a finding; one that does not, say so in a sentence.
|
|
98
|
+
|
|
96
99
|
Compare what the changed code does with what the phase's plans asked for (their tasks and `must_haves`). Code that adds behaviour no plan task or requirement mentions is a finding: a feature nobody asked for, an unrelated refactor folded into the change, or an option no requirement needs. Use category `Unrequested` at WARNING, or at ERROR when it changes existing behaviour without a plan saying so. Its class in the `pan-verdict` block is `unrequested`. Supporting code the tasks need (tests, types, wiring) is not a finding.
|
|
97
100
|
|
|
98
101
|
</review_checks>
|
|
@@ -128,7 +131,13 @@ Return a structured review report:
|
|
|
128
131
|
{PASS | PASS_WITH_WARNINGS | NEEDS_FIXES}
|
|
129
132
|
```
|
|
130
133
|
|
|
131
|
-
**
|
|
134
|
+
**Lens.** When the prompt names a `<lens>` (`correctness`, `security` or `maintainability`), review only through it. Two other passes cover the other lenses, and a vote keeps the findings at least two passes report. So report what your lens finds, and do not stretch it to cover the others.
|
|
135
|
+
|
|
136
|
+
**What you declined to judge.** If you set a behaviour aside (no way to run it, outside your lens, outside the diff), name it in the block's `declined` list as `{"behaviour": "...", "reason": "..."}`. Silence about a behaviour reads as a pass; a declined entry says it was not checked.
|
|
137
|
+
|
|
138
|
+
**Pre-existing problems.** A problem in code this phase did not change, such as an untouched file or untouched lines of a changed file, was there before the phase. Report it, tagged pre-existing, but leave it out of the verdict: it is the project's debt, not this change's defect. `review scope` and `git diff` tell you what the phase changed.
|
|
139
|
+
|
|
140
|
+
**Verdict rules** (pre-existing findings never count):
|
|
132
141
|
- **PASS**: Zero errors, zero warnings
|
|
133
142
|
- **PASS_WITH_WARNINGS**: Zero errors, warnings present
|
|
134
143
|
- **NEEDS_FIXES**: Any errors present
|
|
@@ -138,7 +147,9 @@ Return a structured review report:
|
|
|
138
147
|
- Add one finding per table row. ERROR → `high`, WARNING → `medium`, INFO → `info`.
|
|
139
148
|
- Category maps to class: Convention → `quality`, Security → `risk`, Code Quality → `defect`, Design smell → `quality`, Unrequested → `unrequested`.
|
|
140
149
|
- `where` is `file:line`.
|
|
150
|
+
- A pre-existing finding carries `"pre_existing": true`. The recorder files it as deferred debt with the reason, so it never blocks the phase, and the milestone audit still lists it.
|
|
141
151
|
- A clean review has `"findings": []`.
|
|
152
|
+
- **Dismissed findings are filtered by the recorder, not by you.** When the project dismissed a finding with a reason, recording filters the same finding again for as long as its file is unchanged, and lets it back in once the file changes. Security and logic findings are never filtered. So report everything you find; do not leave out a finding because you think it was dismissed before. To see what is being filtered: `node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings suppressions --phase {phase_number} --agent pan-reviewer`.
|
|
142
153
|
- **On a re-check you are given `<open_findings>`:** your earlier open findings on this phase, each with its `id`. Answer every one in a `resolutions` list in the block: `{"id":"f_…","status":"resolved","evidence":"what you checked and saw"}` when it is fixed, `still_present` when it is not, `cannot_tell` when you could not check it. A finding you leave out stays open: silence never closes a finding, and `resolved` without evidence closes nothing.
|
|
143
154
|
|
|
144
155
|
The orchestrator records this block. It is how your findings reach the phase's findings ledger and `/pan:review-deep`.
|
package/agents/pan-roadmapper.md
CHANGED
|
@@ -16,8 +16,7 @@ You are spawned by:
|
|
|
16
16
|
|
|
17
17
|
Your job: Transform requirements into a phase structure that delivers the project. Every v1 requirement maps to exactly one phase. Every phase has observable success criteria.
|
|
18
18
|
|
|
19
|
-
**
|
|
20
|
-
If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions. This is your primary context.
|
|
19
|
+
**Initial read.** If the prompt contains a `<files_to_read>` block, read every file it lists before doing anything else. This is your primary context.
|
|
21
20
|
|
|
22
21
|
**Core responsibilities:**
|
|
23
22
|
- Derive phases from requirements (not impose arbitrary structure)
|
|
@@ -334,7 +333,7 @@ Reference full template: `~/.claude/pan-wizard-core/templates/roadmap.md`
|
|
|
334
333
|
|
|
335
334
|
## state.md Structure
|
|
336
335
|
|
|
337
|
-
|
|
336
|
+
`pan-tools state init` writes it from the sections of `~/.claude/pan-wizard-core/templates/state.md`; you supply the values.
|
|
338
337
|
|
|
339
338
|
Key sections:
|
|
340
339
|
- Project Reference (core value, current focus)
|
|
@@ -352,7 +351,7 @@ Key sections:
|
|
|
352
351
|
Orchestrator provides:
|
|
353
352
|
- project.md content (core value, constraints)
|
|
354
353
|
- requirements.md content (v1 requirements with REQ-IDs)
|
|
355
|
-
- research/summary.md content (if exists - phase suggestions)
|
|
354
|
+
- research/research-summary.md content (if exists - phase suggestions; older projects have research/summary.md instead)
|
|
356
355
|
- config.json (depth setting)
|
|
357
356
|
|
|
358
357
|
Parse and confirm understanding before proceeding.
|
|
@@ -376,7 +375,7 @@ Total v1: 11 requirements
|
|
|
376
375
|
|
|
377
376
|
## Step 3: Load Research Context (if exists)
|
|
378
377
|
|
|
379
|
-
If research/summary.md provided:
|
|
378
|
+
If research/research-summary.md (or an older project's research/summary.md) provided:
|
|
380
379
|
- Extract suggested phase structure from "Implications for Roadmap"
|
|
381
380
|
- Note research flags (which phases need deeper research)
|
|
382
381
|
- Use as input, not mandate
|
|
@@ -415,7 +414,13 @@ If gaps found, resolve them (see Coverage Validation) and list each gap with the
|
|
|
415
414
|
|
|
416
415
|
1. **Write roadmap.md** using output format
|
|
417
416
|
|
|
418
|
-
2. **
|
|
417
|
+
2. **Initialise state.md through the engine**, not with Write:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state init --core-value "<core value from project.md>" --focus "<first phase name>" --phase <first phase number> --phase-name "<first phase name>" --total-phases <N>
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
When state.md already exists (a new milestone), add `--force --keep-context`: the old file is backed up and its Accumulated Context carried over. The engine writes every section of the template and keeps the frontmatter in sync; never write state.md with the Write or Edit tool (under `hooks.guard: enforce` the guard denies it).
|
|
419
424
|
|
|
420
425
|
3. **Update requirements.md traceability section**
|
|
421
426
|
|
|
@@ -500,7 +505,7 @@ After incorporating user feedback and updating files:
|
|
|
500
505
|
|
|
501
506
|
**Files updated:**
|
|
502
507
|
- .planning/roadmap.md
|
|
503
|
-
- .planning/state.md (if needed)
|
|
508
|
+
- .planning/state.md (if needed, through `pan-tools state apply` or `state section`)
|
|
504
509
|
- .planning/requirements.md (if traceability changed)
|
|
505
510
|
|
|
506
511
|
### Updated Summary
|
package/agents/pan-verifier.md
CHANGED
|
@@ -11,8 +11,7 @@ You are a PAN phase verifier. You verify that a phase achieved its GOAL, not jus
|
|
|
11
11
|
|
|
12
12
|
Your job: Goal-backward verification. Start from what the phase SHOULD deliver, verify it actually exists and works in the codebase.
|
|
13
13
|
|
|
14
|
-
**
|
|
15
|
-
If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions. This is your primary context.
|
|
14
|
+
**Initial read.** If the prompt contains a `<files_to_read>` block, read every file it lists before doing anything else. This is your primary context.
|
|
16
15
|
|
|
17
16
|
**Critical mindset:** Do NOT trust summary.md claims. SUMMARYs document what Claude SAID it did. You verify what ACTUALLY exists in the code. These often differ.
|
|
18
17
|
</role>
|
|
@@ -199,6 +198,12 @@ If no must_haves in frontmatter AND no Success Criteria in ROADMAP:
|
|
|
199
198
|
|
|
200
199
|
For each truth, determine if codebase enables it.
|
|
201
200
|
|
|
201
|
+
**Requirements with EARS criteria are read against their tests.** Run the trace matrix for the phase's requirement ids:
|
|
202
|
+
```bash
|
|
203
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify traceability <REQ-ID> <REQ-ID> …
|
|
204
|
+
```
|
|
205
|
+
`passed` means the mapped tests pass. `failing` is a gap. `not_checked` means no test is mapped to the requirement, so list it under `not_checked` and never as verified. `legacy` (no criteria) is judged as before.
|
|
206
|
+
|
|
202
207
|
**Verification status:**
|
|
203
208
|
|
|
204
209
|
- ✓ VERIFIED: All supporting artifacts pass all checks
|
|
@@ -486,9 +491,9 @@ Unrequested work never changes the status on its own; a phase can pass with it.
|
|
|
486
491
|
|
|
487
492
|
## Step 8b: Run the Test Gate
|
|
488
493
|
|
|
489
|
-
Run the
|
|
494
|
+
Run the test suite through the engine, as the verify-phase protocol's `run_test_suite` step says (`~/.claude/pan-wizard-core/workflows/verify-phase.md`): `pan-tools test run --phase <N>` detects the project's test command in any language, runs it, compares it with the phase's baseline and writes the record. Copy its `status` into the frontmatter as `test_gate: passed | failed | skipped`; do not run the suite yourself and do not re-judge the result. A failed record lowers a `passed` verification whatever you write, and reconcile refuses a `test_gate` that disagrees with it.
|
|
490
495
|
|
|
491
|
-
A
|
|
496
|
+
A `skipped` record goes in `not_checked` with the record's reason, e.g. `- check: "tests"` / `reason: "no test command: …"`. If the orchestrator already ran `test run` for this phase and gave you the result, record that result rather than running it again.
|
|
492
497
|
|
|
493
498
|
## Step 9: Determine Overall Status
|
|
494
499
|
|
package/bin/install-lib.cjs
CHANGED
|
@@ -130,6 +130,25 @@ function extractFrontmatterAndBody(content) {
|
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Mark a Claude Code command or skill as user-invoked only (market-ideas M49): add
|
|
135
|
+
* `disable-model-invocation: true` to its frontmatter. Claude Code then keeps it out
|
|
136
|
+
* of the listing it sends the model on every turn, and it still runs as /pan:<name>.
|
|
137
|
+
* Seen to work on Claude Code 2.1.302 against the harness model double
|
|
138
|
+
* (skill-listing-claude, skill-listing-claude-commands; 2026-10-20). Claude only:
|
|
139
|
+
* no other runtime was seen to read the field (MI-022). Idempotent; content without
|
|
140
|
+
* frontmatter is returned unchanged.
|
|
141
|
+
* @param {string} content
|
|
142
|
+
* @returns {string}
|
|
143
|
+
*/
|
|
144
|
+
function withClaudeUserInvokedOnly(content) {
|
|
145
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
146
|
+
if (!m || /^disable-model-invocation:/m.test(m[1])) return content;
|
|
147
|
+
const eol = content.includes('\r\n') ? '\r\n' : '\n';
|
|
148
|
+
const end = m.index + m[0].length - 3; // the closing ---
|
|
149
|
+
return content.slice(0, end) + 'disable-model-invocation: true' + eol + content.slice(end);
|
|
150
|
+
}
|
|
151
|
+
|
|
133
152
|
/** Extract a field value from YAML frontmatter string */
|
|
134
153
|
function extractFrontmatterField(frontmatter, fieldName) {
|
|
135
154
|
const regex = new RegExp(`^${fieldName}:\\s*(.+)$`, 'm');
|
|
@@ -593,6 +612,39 @@ function rewriteAgentFileRefs(content, runtime, pathPrefix) {
|
|
|
593
612
|
return content.replace(new RegExp(`(${prefix}agents/pan-[a-z0-9_-]+)\\.md\\b`, 'g'), (_, base) => base + ext);
|
|
594
613
|
}
|
|
595
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Build the alias command for a renamed command (program L7, COMMAND_ALIASES).
|
|
617
|
+
* The alias is the target command itself under the old name: its frontmatter `name`
|
|
618
|
+
* becomes the old one, its description says what it was renamed to, and a line after
|
|
619
|
+
* the frontmatter presets the flags. Carrying the whole body, rather than a pointer to
|
|
620
|
+
* the target's installed path, is what makes it resolve on every runtime: each one
|
|
621
|
+
* installs commands at a different path and in a different shape. Pure.
|
|
622
|
+
* @param {string} targetContent - the target command's source (commands/pan/<to>.md)
|
|
623
|
+
* @param {string} oldName - the old command name, without prefix
|
|
624
|
+
* @param {{to: string, args: string}} alias
|
|
625
|
+
* @returns {string}
|
|
626
|
+
*/
|
|
627
|
+
function renderCommandAlias(targetContent, oldName, alias) {
|
|
628
|
+
const now = alias.args ? `/pan:${alias.to} ${alias.args}` : `/pan:${alias.to}`;
|
|
629
|
+
const m = targetContent.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
630
|
+
if (!m) throw new Error(`renderCommandAlias: ${alias.to} has no frontmatter`);
|
|
631
|
+
const fm = m[1].split(/\r?\n/).map((line) => {
|
|
632
|
+
const name = line.match(/^name:\s*(pan:)?\S+/);
|
|
633
|
+
if (name) return `name: ${name[1] || ''}${oldName}`;
|
|
634
|
+
const desc = line.match(/^description:\s*(.*)$/);
|
|
635
|
+
if (desc) {
|
|
636
|
+
const raw = desc[1].trim();
|
|
637
|
+
const unq = raw.match(/^(["'])([\s\S]*)\1$/);
|
|
638
|
+
const text = (unq ? unq[2].replace(/\\"/g, '"') : raw).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
639
|
+
return `description: "Renamed: now ${now}. ${text}"`;
|
|
640
|
+
}
|
|
641
|
+
return line;
|
|
642
|
+
});
|
|
643
|
+
const preset = alias.args ? `${alias.args} $ARGUMENTS` : '$ARGUMENTS';
|
|
644
|
+
const note = `> \`/pan:${oldName}\` is now \`${now}\`. Run the command below with the arguments \`${preset}\`.\n\n`;
|
|
645
|
+
return `---\n${fm.join('\n')}\n---\n${note}${targetContent.slice(m[0].length)}`;
|
|
646
|
+
}
|
|
647
|
+
|
|
596
648
|
function rewriteAgentReferenceCopy(content, corePrefix) {
|
|
597
649
|
content = content.replace(/~\/\.claude\/pan-wizard-core\//g, `${corePrefix}pan-wizard-core/`);
|
|
598
650
|
content = content.replace(/\.\/\.claude\/pan-wizard-core\//g, `${corePrefix}pan-wizard-core/`);
|
|
@@ -708,7 +760,8 @@ function buildCopilotPluginHooksConfig(commands) {
|
|
|
708
760
|
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand } = commands || {};
|
|
709
761
|
const hooks = {};
|
|
710
762
|
if (updateCheckCommand) hooks.SessionStart = [{ type: 'command', command: updateCheckCommand }];
|
|
711
|
-
|
|
763
|
+
// No context monitor: it cannot measure on Copilot (HOOK_EVENT_MAP, M50).
|
|
764
|
+
if (contextMonitorCommand && HOOK_EVENT_MAP.copilot.postToolUse) hooks.PostToolUse = [{ type: 'command', command: contextMonitorCommand }];
|
|
712
765
|
const subagentStop = [];
|
|
713
766
|
if (costLoggerCommand) subagentStop.push({ type: 'command', command: costLoggerCommand });
|
|
714
767
|
if (traceLoggerCommand) subagentStop.push({ type: 'command', command: traceLoggerCommand });
|
|
@@ -1171,7 +1224,7 @@ function buildCopilotHooksConfig(commands) {
|
|
|
1171
1224
|
config.hooks.preToolUse = [{ type: 'command', command: guardCommand }];
|
|
1172
1225
|
}
|
|
1173
1226
|
const postToolUse = [];
|
|
1174
|
-
if (contextMonitorCommand) postToolUse.push({ type: 'command', command: contextMonitorCommand });
|
|
1227
|
+
if (contextMonitorCommand && HOOK_EVENT_MAP.copilot.postToolUse) postToolUse.push({ type: 'command', command: contextMonitorCommand });
|
|
1175
1228
|
// State re-injection after a compaction (M33): preCompact leaves the marker, the
|
|
1176
1229
|
// next postToolUse returns the block once (hooks/pan-state-reinject.js).
|
|
1177
1230
|
if (stateReinjectInjectCommand) postToolUse.push({ type: 'command', command: stateReinjectInjectCommand });
|
|
@@ -1241,12 +1294,19 @@ function buildCopilotHooksConfig(commands) {
|
|
|
1241
1294
|
* next tool result, the first point after it where both hosts take added context
|
|
1242
1295
|
* (gemini-cli v0.61.0 docs/hooks/reference.md; Copilot hooks reference; read
|
|
1243
1296
|
* 2026-10-03, and live on Copilot CLI 1.0.88 the same day).
|
|
1297
|
+
*
|
|
1298
|
+
* `postToolUse` is the context monitor's slot, and it is set only where the monitor
|
|
1299
|
+
* can measure (market-ideas M50). Its numbers come from Claude Code's status-line
|
|
1300
|
+
* bridge or a Claude-shaped transcript. Copilot sends camelCase `sessionId`, so the
|
|
1301
|
+
* hook exited at its session_id check on every call. Codex has no bridge, and its
|
|
1302
|
+
* transcripts are not Claude-shaped. Both events exist on those hosts, but PAN
|
|
1303
|
+
* registers nothing there (reality check 2026-10-19).
|
|
1244
1304
|
*/
|
|
1245
1305
|
const HOOK_EVENT_MAP = Object.freeze({
|
|
1246
1306
|
claude: { surface: 'settings.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1247
1307
|
gemini: { surface: 'settings.json', sessionStart: 'SessionStart', preToolUse: 'BeforeTool', postToolUse: null, subagentStop: null, stop: 'AfterAgent', compact: null, compactMark: 'PreCompress', compactInject: 'AfterTool' },
|
|
1248
|
-
codex: { surface: 'hooks.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse:
|
|
1249
|
-
copilot: { surface: 'hooks/pan.json', sessionStart: 'sessionStart', preToolUse: 'preToolUse', postToolUse:
|
|
1308
|
+
codex: { surface: 'hooks.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: null, subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1309
|
+
copilot: { surface: 'hooks/pan.json', sessionStart: 'sessionStart', preToolUse: 'preToolUse', postToolUse: null, subagentStop: 'subagentStop', stop: 'agentStop', compact: null, compactMark: 'preCompact', compactInject: 'postToolUse' },
|
|
1250
1310
|
opencode: null,
|
|
1251
1311
|
});
|
|
1252
1312
|
|
|
@@ -1543,7 +1603,7 @@ function mergeCodexHooksConfig(existing, commands) {
|
|
|
1543
1603
|
['SessionStart', updateCheckCommand, 'pan-check-update', true],
|
|
1544
1604
|
// The guard decides whether a call may run, which an async handler cannot (A7).
|
|
1545
1605
|
['PreToolUse', guardCommand, 'pan-guard', false],
|
|
1546
|
-
['PostToolUse', contextMonitorCommand, 'pan-context-monitor', false],
|
|
1606
|
+
['PostToolUse', HOOK_EVENT_MAP.codex.postToolUse ? contextMonitorCommand : null, 'pan-context-monitor', false],
|
|
1547
1607
|
['SubagentStop', costLoggerCommand, 'pan-cost-logger', true],
|
|
1548
1608
|
['SubagentStop', traceLoggerCommand, 'pan-trace-logger', true],
|
|
1549
1609
|
['Stop', stopGuardCommand, 'pan-stop-guard', false],
|
|
@@ -1572,6 +1632,14 @@ function mergeCodexHooksConfig(existing, commands) {
|
|
|
1572
1632
|
if (async) handler.async = true;
|
|
1573
1633
|
config.hooks[event].push({ ...(matcher ? { matcher } : {}), hooks: [handler] });
|
|
1574
1634
|
}
|
|
1635
|
+
// An install from before M50 registered the context monitor here; it cannot measure
|
|
1636
|
+
// on Codex, so an upgrade drops that handler (foreign hooks in the group stay).
|
|
1637
|
+
if (!HOOK_EVENT_MAP.codex.postToolUse && Array.isArray(config.hooks.PostToolUse)) {
|
|
1638
|
+
config.hooks.PostToolUse = config.hooks.PostToolUse
|
|
1639
|
+
.map((group) => (Array.isArray(group.hooks) ? { ...group, hooks: group.hooks.filter((h) => !(h && h.command && h.command.includes('pan-context-monitor'))) } : group))
|
|
1640
|
+
.filter((group) => !Array.isArray(group.hooks) || group.hooks.length > 0);
|
|
1641
|
+
if (config.hooks.PostToolUse.length === 0) delete config.hooks.PostToolUse;
|
|
1642
|
+
}
|
|
1575
1643
|
return config;
|
|
1576
1644
|
}
|
|
1577
1645
|
|
|
@@ -2338,6 +2406,7 @@ return { areas_mapped: maps.filter(Boolean).length, synthesis }
|
|
|
2338
2406
|
phases: [
|
|
2339
2407
|
{ title: 'Index', detail: 'plan inventory with wave grouping, from the PAN engine' },
|
|
2340
2408
|
{ title: 'Execute', detail: 'one executor per plan; waves in order, plans within a wave in parallel' },
|
|
2409
|
+
{ title: 'Review', detail: 'pan-reviewer over the phase diff (review scope); the verdict recorded, and the phase budget read' },
|
|
2341
2410
|
{ title: 'Verify', detail: 'the phase verifier over the completed plans' },
|
|
2342
2411
|
{ title: 'Gate', detail: 'the PAN phase gate: stops when the phase may not be completed' },
|
|
2343
2412
|
],
|
|
@@ -2361,8 +2430,10 @@ const INDEX = {
|
|
|
2361
2430
|
phase_name: { type: 'string' },
|
|
2362
2431
|
phase_dir: { type: 'string' },
|
|
2363
2432
|
parallelization: { type: 'boolean' },
|
|
2433
|
+
worktree_isolation: { type: 'boolean' },
|
|
2364
2434
|
verifier_enabled: { type: 'boolean' },
|
|
2365
2435
|
has_checkpoints: { type: 'boolean' },
|
|
2436
|
+
test_baseline: { type: 'string' },
|
|
2366
2437
|
plans: {
|
|
2367
2438
|
type: 'array',
|
|
2368
2439
|
items: {
|
|
@@ -2371,6 +2442,7 @@ const INDEX = {
|
|
|
2371
2442
|
id: { type: 'string' },
|
|
2372
2443
|
file: { type: 'string' },
|
|
2373
2444
|
wave: { type: 'integer' },
|
|
2445
|
+
sub_wave: { type: 'integer' },
|
|
2374
2446
|
autonomous: { type: 'boolean' },
|
|
2375
2447
|
has_summary: { type: 'boolean' },
|
|
2376
2448
|
objective: { type: 'string' },
|
|
@@ -2382,7 +2454,7 @@ const INDEX = {
|
|
|
2382
2454
|
required: ['phase_found', 'has_checkpoints', 'plans'],
|
|
2383
2455
|
}
|
|
2384
2456
|
const index = await agent(
|
|
2385
|
-
'Index phase ' + phaseArg + ' for execution using the ' + PAN_TOOLS + ' Run two verbs and merge their JSON: (1) init execute-phase ' + phaseArg + ' — take phase_found, phase_number, phase_name, phase_dir, parallelization, verifier_enabled; (2) phase-plan-index ' + phaseArg + ' — take has_checkpoints and plans[] (id, wave, autonomous, has_summary, objective; include each plan file path as file). Do not execute
|
|
2457
|
+
'Index phase ' + phaseArg + ' for execution using the ' + PAN_TOOLS + ' Run two verbs and merge their JSON: (1) init execute-phase ' + phaseArg + ' — take phase_found, phase_number, phase_name, phase_dir, parallelization, worktree_isolation, verifier_enabled; (2) phase-plan-index ' + phaseArg + ' — take has_checkpoints and plans[] (id, wave, sub_wave, autonomous, has_summary, objective; include each plan file path as file). Then, only if phase_found is true and has_checkpoints is false, (3) test run --phase ' + phaseArg + ' --baseline — it records what the test suite does before the first wave, so the verifier can tell a failure this phase caused from one it inherited; a phase that already has a baseline keeps it (kept_existing), and a failing or empty baseline is not an error. Put one line describing its result in test_baseline. Do not execute any plan; return only the merged index.',
|
|
2386
2458
|
{ label: 'index', phase: 'Index', schema: INDEX })
|
|
2387
2459
|
if (!index || !index.phase_found) return { error: 'phase ' + phaseArg + ' not found' }
|
|
2388
2460
|
if (index.has_checkpoints) {
|
|
@@ -2391,6 +2463,14 @@ if (index.has_checkpoints) {
|
|
|
2391
2463
|
const pending = index.plans.filter(p => !p.has_summary)
|
|
2392
2464
|
if (pending.length === 0) return { phase: phaseArg, done: true, message: 'every plan already has a summary — nothing to execute' }
|
|
2393
2465
|
const waveNumbers = [...new Set(pending.map(p => p.wave))].sort((a, b) => a - b)
|
|
2466
|
+
// A3: plans of one wave that modify the same file are in different sub-waves, run in turn.
|
|
2467
|
+
const groups = []
|
|
2468
|
+
for (const w of waveNumbers) {
|
|
2469
|
+
const inWave = pending.filter(p => p.wave === w)
|
|
2470
|
+
for (const sw of [...new Set(inWave.map(p => p.sub_wave || 0))].sort((a, b) => a - b)) groups.push({ wave: w, sub: sw, plans: inWave.filter(p => (p.sub_wave || 0) === sw) })
|
|
2471
|
+
}
|
|
2472
|
+
// workflow.worktree_isolation: each executor works in its own git worktree.
|
|
2473
|
+
const iso = index.worktree_isolation === true ? { isolation: 'worktree' } : {}
|
|
2394
2474
|
const parallelWithinWave = index.parallelization !== false
|
|
2395
2475
|
log(pending.length + ' plans across ' + waveNumbers.length + ' wave(s)' + (parallelWithinWave ? '' : ', sequential within waves'))
|
|
2396
2476
|
|
|
@@ -2414,17 +2494,18 @@ const executorPrompt = (p) =>
|
|
|
2414
2494
|
+ 'Report plan_id, status (complete | failed | checkpoint), summary_path, the number of commits you made, and self_check (passed if your summary carries no "Self-Check: FAILED" marker).'
|
|
2415
2495
|
const executed = []
|
|
2416
2496
|
let halted = null
|
|
2417
|
-
for (const
|
|
2418
|
-
const
|
|
2419
|
-
|
|
2497
|
+
for (const g of groups) {
|
|
2498
|
+
const w = g.wave
|
|
2499
|
+
const wavePlans = g.plans
|
|
2500
|
+
log('wave ' + w + (g.sub ? '.' + g.sub : '') + ': ' + wavePlans.map(p => p.id).join(', '))
|
|
2420
2501
|
let results
|
|
2421
2502
|
if (parallelWithinWave) {
|
|
2422
2503
|
results = await parallel(wavePlans.map(p => () =>
|
|
2423
|
-
agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT })))
|
|
2504
|
+
agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT, ...iso })))
|
|
2424
2505
|
} else {
|
|
2425
2506
|
results = []
|
|
2426
2507
|
for (const p of wavePlans) {
|
|
2427
|
-
results.push(await agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT }))
|
|
2508
|
+
results.push(await agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT, ...iso }))
|
|
2428
2509
|
}
|
|
2429
2510
|
}
|
|
2430
2511
|
const settled = results.filter(Boolean)
|
|
@@ -2441,9 +2522,44 @@ for (const w of waveNumbers) {
|
|
|
2441
2522
|
if (halted) {
|
|
2442
2523
|
return { phase: phaseArg, halted, executed, next: 'Inspect the failed plan(s), then re-run /pan-exec-waves ' + phaseArg + ' (completed plans are skipped) or fall back to /pan:exec-phase ' + phaseArg }
|
|
2443
2524
|
}
|
|
2525
|
+
|
|
2526
|
+
// Code review before verification, as in exec-phase.md (code_review). The reviewer is
|
|
2527
|
+
// read-only, so a second agent saves its report, records the verdict in the findings
|
|
2528
|
+
// ledger and reads the phase budget. A script cannot ask "fix before verification?",
|
|
2529
|
+
// so NEEDS_FIXES halts and hands the choice back. { skipReview: true } in args skips it,
|
|
2530
|
+
// like --skip-review.
|
|
2531
|
+
phase('Review')
|
|
2532
|
+
const skipReview = !!(args && typeof args === 'object' && args.skipReview === true)
|
|
2533
|
+
let review = null
|
|
2534
|
+
if (!skipReview) {
|
|
2535
|
+
const REPORT = { type: 'object', properties: { report: { type: 'string' } }, required: ['report'] }
|
|
2536
|
+
const reviewed = await agent(
|
|
2537
|
+
'Review the code phase ' + phaseArg + ' changed, following your agent definition. Get the scope with the ' + PAN_TOOLS + ' Run review scope ' + phaseArg + ' (JSON: the changed files, the unlisted ones no summary names, and the intent to judge them against: objectives, must_haves, Review Focus) and findings list --phase ' + phaseArg + ' --agent pan-reviewer --status open (your earlier open findings; answer each in resolutions). Review every file in the scope, unlisted ones included. Return your full report, verbatim, closing pan-verdict block included, as report.',
|
|
2538
|
+
{ agentType: 'pan-reviewer', label: 'review', phase: 'Review', schema: REPORT })
|
|
2539
|
+
const RECORD = {
|
|
2540
|
+
type: 'object',
|
|
2541
|
+
properties: {
|
|
2542
|
+
verdict: { type: 'string', enum: ['PASS', 'PASS_WITH_WARNINGS', 'NEEDS_FIXES', 'unknown'] },
|
|
2543
|
+
errors: { type: 'integer' },
|
|
2544
|
+
warnings: { type: 'integer' },
|
|
2545
|
+
review_path: { type: 'string' },
|
|
2546
|
+
budget_status: { type: 'string' },
|
|
2547
|
+
budget_line: { type: 'string' },
|
|
2548
|
+
},
|
|
2549
|
+
required: ['verdict'],
|
|
2550
|
+
}
|
|
2551
|
+
review = await agent(
|
|
2552
|
+
'Record a PAN code review for phase ' + phaseArg + ' with the ' + PAN_TOOLS + ' (1) Write the report below, verbatim and in full, to ' + (index.phase_dir || '.planning/phases/<phase dir>') + '/' + (index.phase_number || phaseArg) + '-review.md. (2) Run findings record --phase ' + phaseArg + ' --agent pan-reviewer --file <that path> --raw and take the verdict it prints (if it fails, read the word under ### Verdict in the report). (3) If the verdict is PASS_WITH_WARNINGS, run findings dispose --phase ' + phaseArg + ' --agent pan-reviewer --open --as deferred --reason "accepted at review: PASS_WITH_WARNINGS". (4) Run cost budget --phase ' + phaseArg + ' and report its status as budget_status; when it is near or over, set budget_line to "Spend: <spent_usd> of the <budget_usd> phase budget (<pct>%)", adding "over budget: the phase keeps running" for over. The budget warns, it never blocks. Return verdict, error and warning counts, review_path, budget_status and budget_line. Do not change any code.\\n\\nREPORT:\\n' + ((reviewed && reviewed.report) || '(the reviewer returned no report)'),
|
|
2553
|
+
{ label: 'review-record', phase: 'Review', schema: RECORD })
|
|
2554
|
+
if (review && review.budget_line) log(review.budget_line)
|
|
2555
|
+
if (!review || !review.verdict || review.verdict === 'NEEDS_FIXES' || review.verdict === 'unknown') {
|
|
2556
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, halted: 'review', next: 'The review ' + (review ? 'found errors (' + review.verdict + ')' : 'returned no verdict') + '. Fix them and re-run /pan-exec-waves ' + phaseArg + ', or continue past them with /pan:exec-phase ' + phaseArg + ', which asks and records why. Do not mark the phase complete yet.' }
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2444
2560
|
// workflow.verifier: false (/pan:settings) turns the phase verifier off, as in exec-phase.
|
|
2445
2561
|
if (index.verifier_enabled === false) {
|
|
2446
|
-
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: null, next: 'Verification skipped: workflow.verifier is off. /pan:verify-phase ' + phaseArg + ' verifies on demand; then continue with /pan:exec-phase ' + phaseArg + ' (transition)' }
|
|
2562
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, verification: null, next: 'Verification skipped: workflow.verifier is off. /pan:verify-phase ' + phaseArg + ' verifies on demand; then continue with /pan:exec-phase ' + phaseArg + ' (transition)' }
|
|
2447
2563
|
}
|
|
2448
2564
|
|
|
2449
2565
|
phase('Verify')
|
|
@@ -2476,9 +2592,9 @@ const gate = await agent(
|
|
|
2476
2592
|
{ label: 'gate', phase: 'Gate', schema: GATE })
|
|
2477
2593
|
const gateReasons = gate && Array.isArray(gate.reasons) ? gate.reasons : []
|
|
2478
2594
|
if (!gate || gate.ok !== true) {
|
|
2479
|
-
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: verdict, gate, halted: 'phase_gate', next: 'The phase gate refused: ' + (gateReasons.map((r) => r.code).join(', ') || 'the gate step returned no verdict') + '. Fix each reason (or close the gaps with /pan:plan-phase ' + phaseArg + ' --gaps), then re-run /pan:exec-phase ' + phaseArg + '. Do not mark the phase complete until the gate passes.' }
|
|
2595
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, verification: verdict, gate, halted: 'phase_gate', next: 'The phase gate refused: ' + (gateReasons.map((r) => r.code).join(', ') || 'the gate step returned no verdict') + '. Fix each reason (or close the gaps with /pan:plan-phase ' + phaseArg + ' --gaps), then re-run /pan:exec-phase ' + phaseArg + '. Do not mark the phase complete until the gate passes.' }
|
|
2480
2596
|
}
|
|
2481
|
-
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: verdict, gate, next: 'The phase gate passes. Continue with /pan:exec-phase ' + phaseArg + ' (transition) or /pan:plan-phase for the next phase' }
|
|
2597
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, verification: verdict, gate, next: 'The phase gate passes. Continue with /pan:exec-phase ' + phaseArg + ' (transition) or /pan:plan-phase for the next phase' }
|
|
2482
2598
|
`;
|
|
2483
2599
|
|
|
2484
2600
|
const diagnoseIssues = `export const meta = {
|
|
@@ -2589,6 +2705,7 @@ const {
|
|
|
2589
2705
|
PAN_AGENTS_END,
|
|
2590
2706
|
buildAgentsMdSection,
|
|
2591
2707
|
upsertAgentsMdSection,
|
|
2708
|
+
sectionState,
|
|
2592
2709
|
removeAgentsMdSection,
|
|
2593
2710
|
ensureClaudeMdImport,
|
|
2594
2711
|
removeClaudeMdImport,
|
|
@@ -2597,6 +2714,8 @@ const {
|
|
|
2597
2714
|
// ─── Exports ────────────────────────────────────────────────────────────────
|
|
2598
2715
|
|
|
2599
2716
|
module.exports = {
|
|
2717
|
+
withClaudeUserInvokedOnly,
|
|
2718
|
+
renderCommandAlias,
|
|
2600
2719
|
// Constants
|
|
2601
2720
|
colorNameToHex,
|
|
2602
2721
|
claudeToOpencodeTools,
|
|
@@ -2696,6 +2815,7 @@ module.exports = {
|
|
|
2696
2815
|
// AGENTS.md universal rules layer (ADR-0028 Phase 3)
|
|
2697
2816
|
buildAgentsMdSection,
|
|
2698
2817
|
upsertAgentsMdSection,
|
|
2818
|
+
sectionState,
|
|
2699
2819
|
removeAgentsMdSection,
|
|
2700
2820
|
ensureClaudeMdImport,
|
|
2701
2821
|
removeClaudeMdImport,
|
package/bin/install.js
CHANGED
|
@@ -47,7 +47,7 @@ const pkg = require('../package.json');
|
|
|
47
47
|
// that keep the advice actionable. Nothing in PAN gates on these values.
|
|
48
48
|
const RECOMMENDED_MODELS = {
|
|
49
49
|
flagship: 'claude-fable-5-1',
|
|
50
|
-
reasoningTier: 'claude-opus-5
|
|
50
|
+
reasoningTier: 'claude-opus-5-5',
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
// Source repo root — prevent installing PAN into its own source directory
|
|
@@ -673,7 +673,14 @@ function mirrorUnifiedSkillsForClaude(sharedSkillsDir, targetDir, prefix) {
|
|
|
673
673
|
try {
|
|
674
674
|
fs.mkdirSync(destDir, { recursive: true });
|
|
675
675
|
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
676
|
-
if (entry.isFile())
|
|
676
|
+
if (!entry.isFile()) continue;
|
|
677
|
+
// SKILL.md gains disable-model-invocation for Claude Code (M49); the shared
|
|
678
|
+
// tree keeps the plain file, since no other runtime was seen to read the field.
|
|
679
|
+
if (entry.name === 'SKILL.md') {
|
|
680
|
+
fs.writeFileSync(path.join(destDir, entry.name), lib.withClaudeUserInvokedOnly(fs.readFileSync(path.join(srcDir, entry.name), 'utf8')));
|
|
681
|
+
} else {
|
|
682
|
+
fs.copyFileSync(path.join(srcDir, entry.name), path.join(destDir, entry.name));
|
|
683
|
+
}
|
|
677
684
|
}
|
|
678
685
|
copied++;
|
|
679
686
|
} catch (err) { pushInstallWarning('claudeSkillMirror', `skills/${name}`, err); }
|
|
@@ -845,6 +852,33 @@ function copyCommandsAsCopilotSkills(srcDir, skillsDir, prefix, pathPrefix, runt
|
|
|
845
852
|
* @param {string} pathPrefix - Path prefix for file references
|
|
846
853
|
* @param {string} runtime - Target runtime ('claude', 'opencode', 'gemini', 'codex', 'copilot')
|
|
847
854
|
*/
|
|
855
|
+
/**
|
|
856
|
+
* The command source every runtime installs from: commands/pan/ plus an alias command
|
|
857
|
+
* for each renamed command (COMMAND_ALIASES, program L7), so an old name keeps working
|
|
858
|
+
* on all five runtimes. The aliases are generated into a staging copy in the OS temp
|
|
859
|
+
* directory, removed when the installer exits; with no aliases it is commands/pan/.
|
|
860
|
+
*/
|
|
861
|
+
let stagedCommandSource = null;
|
|
862
|
+
function stageCommandSource(src) {
|
|
863
|
+
const panSrc = path.join(src, 'commands', 'pan');
|
|
864
|
+
if (stagedCommandSource && stagedCommandSource.src === src) return stagedCommandSource.dir;
|
|
865
|
+
let aliases = {};
|
|
866
|
+
try { aliases = require(path.join(src, 'pan-wizard-core', 'bin', 'lib', 'constants.cjs')).COMMAND_ALIASES || {}; } catch {}
|
|
867
|
+
if (Object.keys(aliases).length === 0) return panSrc;
|
|
868
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pan-commands-'));
|
|
869
|
+
for (const f of fs.readdirSync(panSrc)) {
|
|
870
|
+
if (f.endsWith('.md')) fs.copyFileSync(path.join(panSrc, f), path.join(dir, f));
|
|
871
|
+
}
|
|
872
|
+
for (const [oldName, alias] of Object.entries(aliases)) {
|
|
873
|
+
const target = path.join(panSrc, `${alias.to}.md`);
|
|
874
|
+
if (!fs.existsSync(target) || fs.existsSync(path.join(panSrc, `${oldName}.md`))) continue;
|
|
875
|
+
fs.writeFileSync(path.join(dir, `${oldName}.md`), lib.renderCommandAlias(fs.readFileSync(target, 'utf8'), oldName, alias));
|
|
876
|
+
}
|
|
877
|
+
stagedCommandSource = { src, dir };
|
|
878
|
+
process.on('exit', () => { try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} });
|
|
879
|
+
return dir;
|
|
880
|
+
}
|
|
881
|
+
|
|
848
882
|
function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand = false) {
|
|
849
883
|
const isOpencode = runtime === 'opencode';
|
|
850
884
|
const isCodex = runtime === 'codex';
|
|
@@ -907,6 +941,9 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
|
|
|
907
941
|
content = convertClaudeToCopilotMarkdown(content);
|
|
908
942
|
fs.writeFileSync(destPath, content);
|
|
909
943
|
} else {
|
|
944
|
+
// Claude Code: PAN's commands are user-invoked only (M49), so their
|
|
945
|
+
// descriptions stay out of the listing the model gets every turn.
|
|
946
|
+
if (runtime === 'claude' && isCommand) content = lib.withClaudeUserInvokedOnly(content);
|
|
910
947
|
fs.writeFileSync(destPath, content);
|
|
911
948
|
}
|
|
912
949
|
} catch (err) {
|
|
@@ -2244,6 +2281,8 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2244
2281
|
// With its newline, as the per-runtime core writes it: `/pan:update` cats the file
|
|
2245
2282
|
// and prints the runtime flag next, which glued onto a bare version.
|
|
2246
2283
|
try { fs.writeFileSync(path.join(sharedCoreDest, 'VERSION'), pkg.version + '\n'); } catch { /* non-fatal */ }
|
|
2284
|
+
// `/pan:update` points at the changelog beside VERSION, so the shared core carries it too.
|
|
2285
|
+
try { fs.copyFileSync(path.join(src, 'CHANGELOG.md'), path.join(sharedCoreDest, 'CHANGELOG.md')); } catch { /* non-fatal */ }
|
|
2247
2286
|
|
|
2248
2287
|
// Canonical agent-definition reference copies (ADR-0028 agent-ref
|
|
2249
2288
|
// canonicalization): shared content references these instead of the
|
|
@@ -2264,7 +2303,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2264
2303
|
}
|
|
2265
2304
|
console.log(` ${green}✓${reset} Installed shared pan-wizard-core to ${isGlobal ? '~/.agents/' : '.agents/'}`);
|
|
2266
2305
|
|
|
2267
|
-
const panSrc =
|
|
2306
|
+
const panSrc = stageCommandSource(src);
|
|
2268
2307
|
copyCommandsAsUnifiedSkills(panSrc, skillsDir, 'pan', pathPrefix, corePrefix, runtime);
|
|
2269
2308
|
sweepProprietaryCommandSurfaces(targetDir, runtime);
|
|
2270
2309
|
|
|
@@ -2293,7 +2332,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2293
2332
|
fs.mkdirSync(commandDir, { recursive: true });
|
|
2294
2333
|
|
|
2295
2334
|
// Copy commands/pan/*.md as commands/pan-*.md (flatten structure)
|
|
2296
|
-
const panSrc =
|
|
2335
|
+
const panSrc = stageCommandSource(src);
|
|
2297
2336
|
copyFlattenedCommands(panSrc, commandDir, 'pan', pathPrefix, runtime);
|
|
2298
2337
|
|
|
2299
2338
|
// Upgrade path: remove PAN files left in the legacy singular command/
|
|
@@ -2317,7 +2356,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2317
2356
|
// Codex reads skills from the shared .agents/skills tree (repo or user
|
|
2318
2357
|
// scope) — $CODEX_HOME/skills is no longer a read location (2026-06).
|
|
2319
2358
|
const skillsDir = getCodexSkillsRoot(isGlobal);
|
|
2320
|
-
const panSrc =
|
|
2359
|
+
const panSrc = stageCommandSource(src);
|
|
2321
2360
|
copyCommandsAsCodexSkills(panSrc, skillsDir, 'pan', pathPrefix, runtime);
|
|
2322
2361
|
|
|
2323
2362
|
// Upgrade path: remove pan-* skills left in the legacy .codex/skills/
|
|
@@ -2340,7 +2379,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2340
2379
|
}
|
|
2341
2380
|
} else if (isCopilot) {
|
|
2342
2381
|
const skillsDir = path.join(targetDir, 'skills');
|
|
2343
|
-
const panSrc =
|
|
2382
|
+
const panSrc = stageCommandSource(src);
|
|
2344
2383
|
copyCommandsAsCopilotSkills(panSrc, skillsDir, 'pan', pathPrefix, runtime);
|
|
2345
2384
|
const installedSkills = fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
2346
2385
|
.filter(e => e.isDirectory() && e.name.startsWith('pan-'));
|
|
@@ -2354,7 +2393,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2354
2393
|
const commandsDir = path.join(targetDir, 'commands');
|
|
2355
2394
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
2356
2395
|
|
|
2357
|
-
const panSrc =
|
|
2396
|
+
const panSrc = stageCommandSource(src);
|
|
2358
2397
|
const panDest = path.join(commandsDir, 'pan');
|
|
2359
2398
|
copyWithPathReplacement(panSrc, panDest, pathPrefix, runtime, true);
|
|
2360
2399
|
if (verifyInstalled(panDest, 'commands/pan')) {
|
|
@@ -2671,15 +2710,23 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2671
2710
|
const agentsMdPath = path.join(process.cwd(), 'AGENTS.md');
|
|
2672
2711
|
let agentsExisting = null;
|
|
2673
2712
|
try { agentsExisting = fs.readFileSync(agentsMdPath, 'utf8'); } catch { /* absent */ }
|
|
2674
|
-
|
|
2675
|
-
|
|
2713
|
+
if (lib.sectionState(agentsExisting, 'agents') === 'edited') {
|
|
2714
|
+
// The project rewrote PAN's section for itself: an update must not put PAN's
|
|
2715
|
+
// generic text back over it (field report, 2026-10-21).
|
|
2716
|
+
console.log(` ${yellow}!${reset} AGENTS.md: kept the PAN section this project edited. To take PAN's current text, delete the section between the PAN WIZARD markers and run the installer again.`);
|
|
2717
|
+
} else {
|
|
2718
|
+
fs.writeFileSync(agentsMdPath, lib.upsertAgentsMdSection(agentsExisting, lib.buildAgentsMdSection()));
|
|
2719
|
+
console.log(` ${green}✓${reset} ${agentsExisting === null ? 'Created' : 'Updated'} AGENTS.md (PAN section)`);
|
|
2720
|
+
}
|
|
2676
2721
|
|
|
2677
2722
|
if (runtime === 'claude') {
|
|
2678
2723
|
const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
|
|
2679
2724
|
let claudeExisting = null;
|
|
2680
2725
|
try { claudeExisting = fs.readFileSync(claudeMdPath, 'utf8'); } catch { /* absent */ }
|
|
2681
2726
|
const bridged = lib.ensureClaudeMdImport(claudeExisting);
|
|
2682
|
-
if (
|
|
2727
|
+
if (lib.sectionState(claudeExisting, 'claude') === 'edited') {
|
|
2728
|
+
console.log(` ${yellow}!${reset} CLAUDE.md: kept the PAN block this project edited (the @AGENTS.md import and compact instructions).`);
|
|
2729
|
+
} else if (bridged !== claudeExisting) {
|
|
2683
2730
|
fs.writeFileSync(claudeMdPath, bridged);
|
|
2684
2731
|
console.log(` ${green}✓${reset} Bridged CLAUDE.md to AGENTS.md (@AGENTS.md import)`);
|
|
2685
2732
|
}
|
|
@@ -2795,7 +2842,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2795
2842
|
// Print the path we actually wrote. The hardcoded '.codex/hooks.json' was
|
|
2796
2843
|
// wrong for --global and for --config-dir, telling users to inspect a file
|
|
2797
2844
|
// that does not exist while the real one sat elsewhere.
|
|
2798
|
-
console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksJsonPath)}: update check,
|
|
2845
|
+
console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksJsonPath)}: update check, guard, cost + trace loggers, stop guard, state re-injection)`);
|
|
2799
2846
|
} catch (e) {
|
|
2800
2847
|
pushInstallWarning('codexHooks', 'hooks.json', e);
|
|
2801
2848
|
}
|
|
@@ -2812,7 +2859,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2812
2859
|
fs.mkdirSync(path.dirname(hooksConfigPath), { recursive: true });
|
|
2813
2860
|
fs.writeFileSync(hooksConfigPath, JSON.stringify(hooksConfig, null, 2) + '\n');
|
|
2814
2861
|
// Same as the Codex case: a global Copilot install writes to ~/.copilot/, not .github/.
|
|
2815
|
-
console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksConfigPath)}: update check,
|
|
2862
|
+
console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksConfigPath)}: update check, guard, cost + trace loggers, stop guard, state re-injection)`);
|
|
2816
2863
|
} catch (e) {
|
|
2817
2864
|
console.error(` ${yellow}✗${reset} Failed to write Copilot hooks config: ${e.message}`);
|
|
2818
2865
|
}
|
package/commands/pan/army.md
CHANGED
|
@@ -133,7 +133,7 @@ Spawn the conductor in campaign mode (it plans, it does not code). It decomposes
|
|
|
133
133
|
Spawn the Quality squad on the built tree (parallel, read-only). Merge findings into one verdict (`/pan:review-deep` if available). `block` / `review_required` → fix serially, then re-review. Never integrate red.
|
|
134
134
|
|
|
135
135
|
### Phase 5 — Integrate (Release, human-gated)
|
|
136
|
-
Spawn `pan-release`. It prepares the squash-merge, runs the configured `verification`, and surfaces an **always-ask** approval request. A human approves the merge to the protected branch; release then tags and records the rollback target. `--push` pushes the approved result.
|
|
136
|
+
Spawn `pan-release`. It prepares the squash-merge, runs the configured `verification`, stages the merge with `pan-tools merge request <branch> --phase <N>`, and surfaces an **always-ask** approval request. A human approves the merge to the protected branch by running `pan-tools merge confirm <branch>` in their own terminal. The command refuses without an interactive terminal, so no agent can approve its own merge. On a runtime where nobody is at a terminal, the campaign stops at this gate; release then tags and records the rollback target. `--push` pushes the approved result.
|
|
137
137
|
|
|
138
138
|
**Teardown after the merge lands (P-1815):** worktrees are scaffolding, not deliverables — the squash-merge is the permanent artifact. Once the approval lands, remove each integrated task's worktree **and** its branch in one call: `pan-tools worktree remove ../pan-army-<slug> --branch army/<slug>`. The `--branch` half is not optional: a squash-merged branch never looks merged to git, so nothing else will ever clean it. At campaign end — and on **any** abort path — sweep whatever remains: `pan-tools worktree cleanup` (`--force` also discards dirty worktrees and unintegrated branches; without it the sweep keeps anything that might hold the only copy of work, and says exactly why and how to delete it). A campaign that ends with `pan-tools worktree list` non-empty has skipped this step.
|
|
139
139
|
|