pan-wizard 3.36.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 +36 -48
- 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 +1 -2
- package/agents/pan-document_code.md +1 -2
- package/agents/pan-hardener.md +2 -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 +79 -488
- package/agents/pan-plan-checker.md +12 -2
- package/agents/pan-planner.md +10 -6
- package/agents/pan-previewer.md +1 -2
- package/agents/pan-project-researcher.md +70 -499
- package/agents/pan-release.md +1 -1
- package/agents/pan-reviewer.md +9 -3
- package/agents/pan-roadmapper.md +12 -7
- package/agents/pan-verifier.md +7 -2
- 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/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/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 +31 -2
- package/pan-wizard-core/bin/lib/constants.cjs +27 -1
- package/pan-wizard-core/bin/lib/core.cjs +22 -10
- package/pan-wizard-core/bin/lib/cost.cjs +14 -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/failure-class.cjs +81 -0
- package/pan-wizard-core/bin/lib/findings.cjs +34 -4
- package/pan-wizard-core/bin/lib/focus.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 +16 -5
- 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.cjs +48 -4
- package/pan-wizard-core/bin/lib/plan-lint.cjs +150 -1
- package/pan-wizard-core/bin/lib/preview.cjs +23 -4
- package/pan-wizard-core/bin/lib/requirements-lint.cjs +130 -0
- package/pan-wizard-core/bin/lib/research-lint.cjs +150 -3
- 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/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/uat.cjs +149 -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 +37 -1
- package/pan-wizard-core/bin/lib/verify-retro.cjs +3 -2
- package/pan-wizard-core/bin/lib/verify.cjs +59 -4
- package/pan-wizard-core/bin/lib/worktree.cjs +70 -0
- package/pan-wizard-core/bin/pan-tools.cjs +168 -27
- package/pan-wizard-core/learnings/universal/autonomous-loop.md +2 -2
- package/pan-wizard-core/references/continuation-format.md +3 -3
- package/pan-wizard-core/references/guardrails.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 +5 -1
- package/pan-wizard-core/templates/debug.md +1 -0
- package/pan-wizard-core/templates/discovery.md +2 -2
- package/pan-wizard-core/templates/requirements.md +9 -0
- 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 +36 -8
- 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 +31 -53
- 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 +86 -43
- 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/research-phase.md +118 -40
- package/pan-wizard-core/workflows/resume-project.md +18 -2
- package/pan-wizard-core/workflows/settings.md +21 -24
- 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 +2 -2
- package/scripts/build-agent-plugin.js +35 -15
- 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/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 +9 -2
- 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 -210
- package/pan-wizard-core/templates/research-project/features.md +0 -153
- package/pan-wizard-core/templates/research-project/pitfalls.md +0 -206
- package/pan-wizard-core/templates/research-project/stack.md +0 -126
- package/pan-wizard-core/templates/research-project/summary.md +0 -170
package/scripts/build-plugin.js
CHANGED
|
@@ -111,7 +111,14 @@ function main() {
|
|
|
111
111
|
);
|
|
112
112
|
|
|
113
113
|
// 2. Commands (Claude flavor, plugin-root-relative paths)
|
|
114
|
-
|
|
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 (${
|
|
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}: ${
|
|
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 = {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
+
}
|
package/scripts/land.cjs
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* land.cjs — land a branch on main without a pull request (`npm run land -- <branch>`;
|
|
4
|
+
* local-first plan, phase 3). GitHub stays the mirror: main is pushed there, never forced.
|
|
5
|
+
*
|
|
6
|
+
* Refuses unless:
|
|
7
|
+
* - a full `npm run ci:local` passed on the branch's current HEAD, from a tree with no
|
|
8
|
+
* uncommitted changes, with no gate skipped (scripts/local-ci.cjs records the verdict in
|
|
9
|
+
* the git directory, pan-ci-local/<sha>.json, shared by every worktree);
|
|
10
|
+
* - the branch contains origin/main, so the squash commit's tree is exactly the tree
|
|
11
|
+
* ci:local passed (merge or rebase main into the branch and run ci:local again if not);
|
|
12
|
+
* - the checkout that has main (or a temporary one) is clean and main can fast-forward
|
|
13
|
+
* to origin/main.
|
|
14
|
+
*
|
|
15
|
+
* Then: fetch origin, fast-forward main to origin/main, `git merge --squash <branch>`, commit
|
|
16
|
+
* with the branch's summary (the title is its first commit's subject, or --title; the body
|
|
17
|
+
* lists every commit), and `git push origin main`. A rejected push leaves the commit on the
|
|
18
|
+
* local main and says so; nothing is forced, and the branch itself is left alone.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* node scripts/land.cjs <branch> [--title "..."] [--dry-run] [--no-push] [--allow-skips]
|
|
22
|
+
* [--remote origin] [--main main]
|
|
23
|
+
* Exit 0 landed (or the dry run would land), 1 refused or failed, 2 usage.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
'use strict';
|
|
27
|
+
|
|
28
|
+
const { spawnSync } = require('child_process');
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const os = require('os');
|
|
31
|
+
const path = require('path');
|
|
32
|
+
|
|
33
|
+
function git(cwd, args, opts = {}) {
|
|
34
|
+
const r = spawnSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, ...opts });
|
|
35
|
+
return { ok: r.status === 0, out: (r.stdout || '').trim(), err: (r.stderr || '').trim() || (r.error ? r.error.message : '') };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseArgs(argv) {
|
|
39
|
+
const a = { branch: null, title: null, dryRun: false, push: true, allowSkips: false, remote: 'origin', main: 'main' };
|
|
40
|
+
for (let i = 0; i < argv.length; i++) {
|
|
41
|
+
const k = argv[i];
|
|
42
|
+
if (k === '--title') a.title = argv[++i];
|
|
43
|
+
else if (k === '--dry-run') a.dryRun = true;
|
|
44
|
+
else if (k === '--no-push') a.push = false;
|
|
45
|
+
else if (k === '--allow-skips') a.allowSkips = true;
|
|
46
|
+
else if (k === '--remote') a.remote = argv[++i];
|
|
47
|
+
else if (k === '--main') a.main = argv[++i];
|
|
48
|
+
else if (k.startsWith('--')) throw new Error(`unknown option: ${k}`);
|
|
49
|
+
else if (!a.branch) a.branch = k;
|
|
50
|
+
else throw new Error(`one branch at a time (got ${a.branch} and ${k})`);
|
|
51
|
+
}
|
|
52
|
+
if (!a.branch) throw new Error('usage: land.cjs <branch> [--title T] [--dry-run] [--no-push] [--allow-skips]');
|
|
53
|
+
return a;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Why ci:local's verdict does not clear `sha` for landing, or null when it does. Pure. */
|
|
57
|
+
function verdictProblem(verdict, sha, { allowSkips = false } = {}) {
|
|
58
|
+
if (!verdict) return `no ci:local verdict for ${sha.slice(0, 9)} — run \`npm run ci:local\` on the branch at that commit`;
|
|
59
|
+
if (verdict.headFull !== sha) return `the verdict is for ${String(verdict.headFull).slice(0, 9)}, not ${sha.slice(0, 9)}`;
|
|
60
|
+
if (verdict.options && (verdict.options.only || verdict.options.fast)) return 'the verdict is from a partial run (--only or --fast); run the full ci:local';
|
|
61
|
+
if (verdict.dirtyAtStart !== false) return 'ci:local ran with uncommitted changes, so it did not test this commit alone; commit or stash them and run it again';
|
|
62
|
+
if (verdict.status !== 'pass') return `ci:local failed on ${sha.slice(0, 9)}: ${(verdict.gates || []).filter(g => g.status === 'fail').map(g => g.id).join(', ') || 'see its report'}`;
|
|
63
|
+
const skipped = (verdict.gates || []).filter(g => g.status === 'skip').map(g => g.id);
|
|
64
|
+
if (skipped.length && !allowSkips) return `ci:local skipped ${skipped.join(', ')}; install what they need, or pass --allow-skips`;
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The squash commit's message: a title, and the branch's commits as the body. Pure. */
|
|
69
|
+
function commitMessage(branch, subjects, title) {
|
|
70
|
+
const head = title || subjects[0] || `Land ${branch}`;
|
|
71
|
+
const body = subjects.length > 1 || (title && subjects.length) ? `\n\nSquashed from ${branch}:\n${subjects.map(s => `- ${s}`).join('\n')}` : '';
|
|
72
|
+
return `${head}${body}\n`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// The worktree that has `main` checked out, if any.
|
|
76
|
+
function mainCheckout(cwd, main) {
|
|
77
|
+
const list = git(cwd, ['worktree', 'list', '--porcelain']).out;
|
|
78
|
+
for (const block of list.split(/\n\n+/)) {
|
|
79
|
+
const wt = (block.match(/^worktree (.+)$/m) || [])[1];
|
|
80
|
+
if (wt && new RegExp(`^branch refs/heads/${main.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'm').test(block)) return path.resolve(wt);
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function land(argv, cwd = process.cwd(), log = console.log) {
|
|
86
|
+
let o;
|
|
87
|
+
try { o = parseArgs(argv); } catch (e) { log(`land: ${e.message}`); return 2; }
|
|
88
|
+
const refuse = (why) => { log(`land: refused — ${why}`); return 1; };
|
|
89
|
+
|
|
90
|
+
const sha = git(cwd, ['rev-parse', '--verify', `refs/heads/${o.branch}^{commit}`]);
|
|
91
|
+
if (!sha.ok) return refuse(`no local branch ${o.branch}`);
|
|
92
|
+
if (o.branch === o.main) return refuse(`${o.branch} is the branch it would land on`);
|
|
93
|
+
|
|
94
|
+
const common = path.resolve(cwd, git(cwd, ['rev-parse', '--git-common-dir']).out);
|
|
95
|
+
let verdict = null;
|
|
96
|
+
try { verdict = JSON.parse(fs.readFileSync(path.join(common, 'pan-ci-local', `${sha.out}.json`), 'utf8')); } catch { /* none */ }
|
|
97
|
+
const problem = verdictProblem(verdict, sha.out, o);
|
|
98
|
+
if (problem) return refuse(problem);
|
|
99
|
+
|
|
100
|
+
const fetched = git(cwd, ['fetch', o.remote, o.main]);
|
|
101
|
+
if (!fetched.ok) return refuse(`git fetch ${o.remote} ${o.main}: ${fetched.err}`);
|
|
102
|
+
const upstream = `refs/remotes/${o.remote}/${o.main}`;
|
|
103
|
+
if (!git(cwd, ['merge-base', '--is-ancestor', upstream, sha.out]).ok) {
|
|
104
|
+
return refuse(`${o.branch} does not contain ${o.remote}/${o.main}; merge or rebase it onto ${o.remote}/${o.main}, then run ci:local again`);
|
|
105
|
+
}
|
|
106
|
+
const subjects = git(cwd, ['log', '--reverse', '--format=%s', `${upstream}..${sha.out}`]).out.split('\n').filter(Boolean);
|
|
107
|
+
if (!subjects.length) return refuse(`${o.branch} has nothing that ${o.remote}/${o.main} lacks`);
|
|
108
|
+
const message = commitMessage(o.branch, subjects, o.title);
|
|
109
|
+
|
|
110
|
+
let where = mainCheckout(cwd, o.main);
|
|
111
|
+
if (where && git(where, ['status', '--porcelain']).out) return refuse(`the checkout with ${o.main} (${where}) has uncommitted changes`);
|
|
112
|
+
if (o.dryRun) {
|
|
113
|
+
log(`land: would squash ${subjects.length} commit(s) of ${o.branch} (${sha.out.slice(0, 9)}) onto ${o.remote}/${o.main} in ${where || 'a temporary worktree'}${o.push ? ` and push ${o.main} to ${o.remote}` : ''}:\n\n${message}`);
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let temp = null;
|
|
118
|
+
if (!where) {
|
|
119
|
+
temp = fs.mkdtempSync(path.join(os.tmpdir(), 'pan-land-'));
|
|
120
|
+
const hasMain = git(cwd, ['rev-parse', '--verify', `refs/heads/${o.main}`]).ok;
|
|
121
|
+
const add = git(cwd, hasMain ? ['worktree', 'add', temp, o.main] : ['worktree', 'add', '-b', o.main, temp, upstream]);
|
|
122
|
+
if (!add.ok) { fs.rmSync(temp, { recursive: true, force: true }); return refuse(`could not check out ${o.main}: ${add.err}`); }
|
|
123
|
+
where = temp;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const ff = git(where, ['merge', '--ff-only', upstream]);
|
|
127
|
+
if (!ff.ok) return refuse(`local ${o.main} cannot fast-forward to ${o.remote}/${o.main} (it has commits ${o.remote} lacks): ${ff.err}`);
|
|
128
|
+
const sq = git(where, ['merge', '--squash', sha.out]);
|
|
129
|
+
if (!sq.ok) { git(where, ['reset', '--merge']); return refuse(`the squash merge failed: ${sq.err}`); }
|
|
130
|
+
// The branch contains main, so the result is the branch's tree: anything else is a bug here.
|
|
131
|
+
const tree = git(where, ['write-tree']).out;
|
|
132
|
+
const want = git(cwd, ['rev-parse', `${sha.out}^{tree}`]).out;
|
|
133
|
+
if (tree !== want) { git(where, ['reset', '--hard', upstream]); return refuse(`the squashed tree ${tree.slice(0, 9)} is not the tree ci:local passed (${want.slice(0, 9)})`); }
|
|
134
|
+
const commit = git(where, ['commit', '--no-verify', '-F', '-'], { input: message });
|
|
135
|
+
if (!commit.ok) { git(where, ['reset', '--merge']); return refuse(`git commit: ${commit.err}`); }
|
|
136
|
+
const landed = git(where, ['rev-parse', 'HEAD']).out;
|
|
137
|
+
log(`land: ${o.branch} squashed onto ${o.main} as ${landed.slice(0, 9)}`);
|
|
138
|
+
if (!o.push) { log(`land: not pushed (--no-push); push with \`git push ${o.remote} ${o.main}\``); return 0; }
|
|
139
|
+
// Never forced: a push the remote rejects (it moved, or branch protection) stops here.
|
|
140
|
+
const push = git(where, ['push', o.remote, `refs/heads/${o.main}:refs/heads/${o.main}`]);
|
|
141
|
+
if (!push.ok) { log(`land: the push to ${o.remote} was rejected; ${landed.slice(0, 9)} is on the local ${o.main} only:\n${push.err}`); return 1; }
|
|
142
|
+
log(`land: pushed ${o.main} to ${o.remote}`);
|
|
143
|
+
return 0;
|
|
144
|
+
} finally {
|
|
145
|
+
if (temp) { git(cwd, ['worktree', 'remove', '--force', temp]); fs.rmSync(temp, { recursive: true, force: true }); }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { parseArgs, verdictProblem, commitMessage, mainCheckout, land };
|
|
150
|
+
|
|
151
|
+
if (require.main === module) process.exit(land(process.argv.slice(2)));
|