mandrel 2.60.0 → 2.62.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/.agents/README.md +10 -10
- package/.agents/agents/story-worker.md +1 -1
- package/.agents/docs/agentrc-reference.json +4 -82
- package/.agents/docs/configuration.md +20 -87
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +1 -3
- package/.agents/rules/gherkin-standards.md +4 -0
- package/.agents/schemas/agentrc.schema.json +11 -486
- package/.agents/schemas/story-deliver-terminal.schema.json +10 -0
- package/.agents/schemas/validation-evidence.schema.json +2 -1
- package/.agents/scripts/README.md +14 -14
- package/.agents/scripts/acceptance-eval.js +32 -164
- package/.agents/scripts/agents-bootstrap-github.js +27 -129
- package/.agents/scripts/apply-quality-bootstrap.js +4 -40
- package/.agents/scripts/audit-baselines.js +6 -27
- package/.agents/scripts/audit-labels-bootstrap.js +5 -29
- package/.agents/scripts/audit-to-stories.js +91 -361
- package/.agents/scripts/boot-sweep.js +19 -72
- package/.agents/scripts/bootstrap.js +74 -395
- package/.agents/scripts/ceremony-derive.js +9 -45
- package/.agents/scripts/check-arch-cycles.js +14 -64
- package/.agents/scripts/check-baselines.js +8 -48
- package/.agents/scripts/check-context-budget.js +46 -172
- package/.agents/scripts/check-cyclomatic.js +12 -44
- package/.agents/scripts/check-dead-exports.js +13 -64
- package/.agents/scripts/check-doc-links.js +38 -186
- package/.agents/scripts/check-gherkin-corpus.js +24 -127
- package/.agents/scripts/check-test-temp-hygiene.js +28 -169
- package/.agents/scripts/coverage-capture.js +32 -99
- package/.agents/scripts/deliver-light.js +14 -101
- package/.agents/scripts/deliver-recover.js +6 -42
- package/.agents/scripts/deliver-run.js +36 -133
- package/.agents/scripts/diagnose-friction.js +24 -116
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +23 -85
- package/.agents/scripts/file-ci-gap.js +10 -50
- package/.agents/scripts/generate-config-docs.js +30 -170
- package/.agents/scripts/generate-lens-checklists.js +8 -52
- package/.agents/scripts/generate-skills-index.js +14 -112
- package/.agents/scripts/generate-workflows-doc.js +10 -70
- package/.agents/scripts/git-cleanup.js +2 -34
- package/.agents/scripts/lib/Graph.js +24 -81
- package/.agents/scripts/lib/ITicketingProvider.js +47 -143
- package/.agents/scripts/lib/Logger.js +14 -76
- package/.agents/scripts/lib/audit-baselines/engine.js +11 -31
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +3 -17
- package/.agents/scripts/lib/audit-baselines/headroom.js +4 -20
- package/.agents/scripts/lib/audit-baselines/hotspots.js +3 -15
- package/.agents/scripts/lib/audit-baselines/kinds.js +23 -89
- package/.agents/scripts/lib/audit-baselines/outliers.js +6 -23
- package/.agents/scripts/lib/audit-baselines/read.js +3 -16
- package/.agents/scripts/lib/audit-baselines/staleness.js +7 -26
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +7 -28
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -20
- package/.agents/scripts/lib/audit-baselines/weights.js +9 -37
- package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +3 -18
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -124
- package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +14 -45
- package/.agents/scripts/lib/audit-suite/findings.js +12 -52
- package/.agents/scripts/lib/audit-suite/frontmatter.js +5 -29
- package/.agents/scripts/lib/audit-suite/index.js +1 -15
- package/.agents/scripts/lib/audit-suite/lens-checklist.js +10 -45
- package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +11 -76
- package/.agents/scripts/lib/audit-suite/runner.js +13 -43
- package/.agents/scripts/lib/audit-suite/selector.js +49 -349
- package/.agents/scripts/lib/audit-suite/substitutions.js +12 -40
- package/.agents/scripts/lib/audit-suite/workflow-loader.js +3 -15
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +11 -73
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +8 -37
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +25 -143
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +14 -80
- package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +4 -18
- package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +7 -40
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +9 -39
- package/.agents/scripts/lib/audit-to-stories/issue-corpus.js +10 -66
- package/.agents/scripts/lib/audit-to-stories/issue-index.js +6 -30
- package/.agents/scripts/lib/audit-to-stories/issues-file.js +6 -36
- package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +17 -69
- package/.agents/scripts/lib/audit-to-stories/ledger-pr.js +17 -85
- package/.agents/scripts/lib/audit-to-stories/ledger-record.js +10 -48
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +38 -146
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +7 -42
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +10 -57
- package/.agents/scripts/lib/baseline-loader.js +12 -51
- package/.agents/scripts/lib/baseline-schema-registry.js +5 -22
- package/.agents/scripts/lib/baselines/component-matcher.js +3 -12
- package/.agents/scripts/lib/baselines/components.js +10 -61
- package/.agents/scripts/lib/baselines/coverage-updater-cli.js +7 -36
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +5 -21
- package/.agents/scripts/lib/baselines/crap-preview-scan.js +19 -45
- package/.agents/scripts/lib/baselines/crap-updater-cli.js +16 -65
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +5 -33
- package/.agents/scripts/lib/baselines/duplication-scanner.js +11 -60
- package/.agents/scripts/lib/baselines/env-overrides.js +12 -67
- package/.agents/scripts/lib/baselines/envelope.js +13 -129
- package/.agents/scripts/lib/baselines/exit-codes.js +6 -49
- package/.agents/scripts/lib/baselines/git-base.js +23 -142
- package/.agents/scripts/lib/baselines/kernel.js +11 -111
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +9 -47
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +8 -51
- package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +7 -62
- package/.agents/scripts/lib/baselines/kinds/bundle-size.js +8 -29
- package/.agents/scripts/lib/baselines/kinds/coverage.js +3 -15
- package/.agents/scripts/lib/baselines/kinds/crap.js +94 -415
- package/.agents/scripts/lib/baselines/kinds/duplication.js +4 -30
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +7 -53
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +15 -80
- package/.agents/scripts/lib/baselines/kinds/mutation.js +12 -72
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +4 -11
- package/.agents/scripts/lib/baselines/merge-envelopes.js +30 -146
- package/.agents/scripts/lib/baselines/path-canon.js +19 -128
- package/.agents/scripts/lib/baselines/preview-gates.js +8 -37
- package/.agents/scripts/lib/baselines/reader.js +14 -107
- package/.agents/scripts/lib/baselines/refresh-service.js +35 -252
- package/.agents/scripts/lib/baselines/scope.js +11 -135
- package/.agents/scripts/lib/baselines/writer.js +16 -149
- package/.agents/scripts/lib/bdd-runner-detect.js +18 -113
- package/.agents/scripts/lib/bdd-scenario-budget.js +9 -36
- package/.agents/scripts/lib/bdd-scenario-scanner.js +11 -73
- package/.agents/scripts/lib/bdd-step-index.js +26 -100
- package/.agents/scripts/lib/bootstrap/baseline-merge-driver.js +23 -103
- package/.agents/scripts/lib/bootstrap/branch-protection.js +2 -5
- package/.agents/scripts/lib/bootstrap/commit-push.js +12 -50
- package/.agents/scripts/lib/bootstrap/gh-preflight.js +14 -101
- package/.agents/scripts/lib/bootstrap/hitl-confirm.js +5 -30
- package/.agents/scripts/lib/bootstrap/install-ledger.js +17 -73
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +17 -121
- package/.agents/scripts/lib/bootstrap/manifest.js +15 -86
- package/.agents/scripts/lib/bootstrap/merge-methods.js +4 -33
- package/.agents/scripts/lib/bootstrap/preflight.js +12 -61
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +34 -235
- package/.agents/scripts/lib/bootstrap/prompt.js +21 -129
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +27 -141
- package/.agents/scripts/lib/bootstrap/summary.js +1 -8
- package/.agents/scripts/lib/bootstrap/workflow-audit.js +11 -84
- package/.agents/scripts/lib/branch-name-guard.js +4 -23
- package/.agents/scripts/lib/changed-files.js +31 -143
- package/.agents/scripts/lib/checks/core-bare-clean.js +4 -24
- package/.agents/scripts/lib/checks/index.js +18 -101
- package/.agents/scripts/lib/checks/loop-health.js +11 -53
- package/.agents/scripts/lib/checks/state.js +16 -91
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +10 -61
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +14 -83
- package/.agents/scripts/lib/child-exec.js +39 -108
- package/.agents/scripts/lib/cli/standard-args.js +9 -116
- package/.agents/scripts/lib/cli-args.js +31 -146
- package/.agents/scripts/lib/cli-usage.js +5 -27
- package/.agents/scripts/lib/cli-utils.js +2 -12
- package/.agents/scripts/lib/close-validation/commands.js +13 -76
- package/.agents/scripts/lib/close-validation/gates.js +92 -331
- package/.agents/scripts/lib/close-validation/process.js +121 -151
- package/.agents/scripts/lib/close-validation/projections/advisories.js +5 -31
- package/.agents/scripts/lib/close-validation/projections/crap.js +19 -67
- package/.agents/scripts/lib/close-validation/projections/head-sha.js +1 -17
- package/.agents/scripts/lib/close-validation/projections/inputs.js +4 -34
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +11 -58
- package/.agents/scripts/lib/close-validation/runner.js +53 -110
- package/.agents/scripts/lib/command-header.js +6 -28
- package/.agents/scripts/lib/config/acceptance-eval.js +4 -30
- package/.agents/scripts/lib/config/baselines.js +3 -14
- package/.agents/scripts/lib/config/ci.js +8 -38
- package/.agents/scripts/lib/config/commands.js +1 -15
- package/.agents/scripts/lib/config/defaults.js +4 -33
- package/.agents/scripts/lib/config/delivery-routing.js +6 -35
- package/.agents/scripts/lib/config/explain.js +9 -80
- package/.agents/scripts/lib/config/gates/coverage.schema.js +0 -12
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +2 -30
- package/.agents/scripts/lib/config/gates/crap.schema.js +1 -34
- package/.agents/scripts/lib/config/gates/duplication.schema.js +1 -8
- package/.agents/scripts/lib/config/gates/index.js +2 -17
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +1 -20
- package/.agents/scripts/lib/config/gates/mutation.schema.js +1 -7
- package/.agents/scripts/lib/config/gates/shared.js +4 -64
- package/.agents/scripts/lib/config/github.js +4 -22
- package/.agents/scripts/lib/config/limits.js +4 -57
- package/.agents/scripts/lib/config/paths.js +2 -21
- package/.agents/scripts/lib/config/qa.js +4 -38
- package/.agents/scripts/lib/config/quality.js +76 -432
- package/.agents/scripts/lib/config/runners.js +12 -56
- package/.agents/scripts/lib/config/runtime.js +13 -57
- package/.agents/scripts/lib/config/shared.js +2 -16
- package/.agents/scripts/lib/config/sync-agentrc.js +9 -50
- package/.agents/scripts/lib/config/temp-paths.js +40 -280
- package/.agents/scripts/lib/config/validate-orchestration.js +5 -17
- package/.agents/scripts/lib/config/worktree-isolation.js +9 -28
- package/.agents/scripts/lib/config-resolver.js +10 -52
- package/.agents/scripts/lib/config-schema-shared.js +1 -4
- package/.agents/scripts/lib/config-settings-schema-delivery.js +12 -294
- package/.agents/scripts/lib/config-settings-schema-quality.js +7 -219
- package/.agents/scripts/lib/config-settings-schema.js +37 -274
- package/.agents/scripts/lib/coverage-baseline.js +20 -110
- package/.agents/scripts/lib/coverage-capture-fullscope.js +12 -37
- package/.agents/scripts/lib/coverage-capture-incremental.js +12 -43
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -24
- package/.agents/scripts/lib/coverage-capture.js +99 -224
- package/.agents/scripts/lib/coverage-utils.js +14 -79
- package/.agents/scripts/lib/cpu-pool.js +17 -123
- package/.agents/scripts/lib/crap-baseline-join.js +16 -88
- package/.agents/scripts/lib/crap-coordinates.js +6 -25
- package/.agents/scripts/lib/crap-engine.js +40 -153
- package/.agents/scripts/lib/crap-method-identity.js +16 -78
- package/.agents/scripts/lib/crap-utils.js +31 -155
- package/.agents/scripts/lib/cyclomatic-ceiling.js +14 -87
- package/.agents/scripts/lib/cyclomatic-scope.js +10 -50
- package/.agents/scripts/lib/dead-exports-knip.js +18 -56
- package/.agents/scripts/lib/dead-exports-mode.js +5 -24
- package/.agents/scripts/lib/degraded-mode.js +3 -26
- package/.agents/scripts/lib/dependency-parser.js +8 -40
- package/.agents/scripts/lib/dependency-version.js +13 -35
- package/.agents/scripts/lib/detect-package-manager.js +6 -36
- package/.agents/scripts/lib/doc-tiers.js +22 -126
- package/.agents/scripts/lib/duplicate-search.js +8 -72
- package/.agents/scripts/lib/env-loader.js +5 -27
- package/.agents/scripts/lib/error-redactor.js +6 -31
- package/.agents/scripts/lib/errors/index.js +2 -22
- package/.agents/scripts/lib/escomplex-ast-compat.js +22 -163
- package/.agents/scripts/lib/escomplex-kernel.js +21 -123
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +93 -419
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +20 -98
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +27 -151
- package/.agents/scripts/lib/findings/audit-ledger.js +23 -97
- package/.agents/scripts/lib/findings/classify-finding.js +14 -69
- package/.agents/scripts/lib/findings/promote-finding.js +14 -112
- package/.agents/scripts/lib/findings/provenance-field.js +11 -52
- package/.agents/scripts/lib/findings/route-finding.js +37 -255
- package/.agents/scripts/lib/findings/semantic-issue-search.js +14 -59
- package/.agents/scripts/lib/findings/severity.js +18 -104
- package/.agents/scripts/lib/format-generated-json.js +12 -44
- package/.agents/scripts/lib/full-suite-lock.js +160 -429
- package/.agents/scripts/lib/full-suite-queue.js +213 -0
- package/.agents/scripts/lib/gates/baseline-store.js +5 -9
- package/.agents/scripts/lib/gates/friction.js +1 -3
- package/.agents/scripts/lib/generated/agentrc-validator.js +2 -2
- package/.agents/scripts/lib/gh-exec.js +31 -259
- package/.agents/scripts/lib/git/cached-fetch.js +9 -52
- package/.agents/scripts/lib/git/sync-from-base.js +15 -107
- package/.agents/scripts/lib/git-branch-cleanup.js +14 -61
- package/.agents/scripts/lib/git-branch-lifecycle.js +16 -87
- package/.agents/scripts/lib/git-utils.js +37 -161
- package/.agents/scripts/lib/github/framework-repo.js +8 -71
- package/.agents/scripts/lib/github-url.js +2 -17
- package/.agents/scripts/lib/import-graph.js +11 -38
- package/.agents/scripts/lib/install-cmd-parser.js +4 -13
- package/.agents/scripts/lib/json-utils.js +3 -18
- package/.agents/scripts/lib/label-constants.js +16 -111
- package/.agents/scripts/lib/label-taxonomy.js +4 -30
- package/.agents/scripts/lib/maintainability-engine.js +12 -80
- package/.agents/scripts/lib/maintainability-unscorable.js +5 -25
- package/.agents/scripts/lib/maintainability-utils.js +16 -92
- package/.agents/scripts/lib/mandrel-catalog.js +12 -70
- package/.agents/scripts/lib/notifications/notifier.js +13 -38
- package/.agents/scripts/lib/npm-scripts.js +4 -23
- package/.agents/scripts/lib/observability/metrics-ledger.js +16 -76
- package/.agents/scripts/lib/observability/runtime-friction.js +44 -286
- package/.agents/scripts/lib/observability/signal-validator.js +5 -37
- package/.agents/scripts/lib/observability/signals-writer.js +11 -121
- package/.agents/scripts/lib/observability/source-classifier.js +21 -203
- package/.agents/scripts/lib/observability/terse-result.js +14 -47
- package/.agents/scripts/lib/onboard/init-tail.js +13 -74
- package/.agents/scripts/lib/onboard/scaffold-docs.js +11 -34
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +25 -139
- package/.agents/scripts/lib/orchestration/auto-merge-cwd.js +11 -66
- package/.agents/scripts/lib/orchestration/behind-recovery.js +10 -55
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +5 -75
- package/.agents/scripts/lib/orchestration/change-set.js +7 -36
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +9 -46
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +11 -44
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +5 -24
- package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +3 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +5 -38
- package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +3 -8
- package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +28 -136
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +3 -13
- package/.agents/scripts/lib/orchestration/check-state.js +92 -0
- package/.agents/scripts/lib/orchestration/ci-gap-intake.js +37 -144
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +42 -189
- package/.agents/scripts/lib/orchestration/code-review.js +24 -128
- package/.agents/scripts/lib/orchestration/column-sync.js +23 -111
- package/.agents/scripts/lib/orchestration/complexity-gate.js +42 -214
- package/.agents/scripts/lib/orchestration/deliver-recover.js +36 -168
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +4 -35
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +9 -41
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +25 -115
- package/.agents/scripts/lib/orchestration/doc-reader.js +2 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +13 -51
- package/.agents/scripts/lib/orchestration/epic-candidates.js +13 -53
- package/.agents/scripts/lib/orchestration/epic-checklist.js +9 -33
- package/.agents/scripts/lib/orchestration/epic-container.js +41 -167
- package/.agents/scripts/lib/orchestration/epic-expansion.js +10 -40
- package/.agents/scripts/lib/orchestration/epic-rollup.js +55 -207
- package/.agents/scripts/lib/orchestration/file-assumption-enum.js +2 -22
- package/.agents/scripts/lib/orchestration/file-assumptions.js +45 -253
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-detect.js +9 -46
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +7 -57
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +21 -126
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +2 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +9 -34
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +41 -190
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/merged-tip.js +9 -45
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +19 -85
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +3 -17
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +16 -100
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +1 -4
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +16 -67
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +9 -33
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +8 -29
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +15 -68
- package/.agents/scripts/lib/orchestration/light-backstop.js +11 -49
- package/.agents/scripts/lib/orchestration/light-escalation.js +21 -89
- package/.agents/scripts/lib/orchestration/light-suitability.js +26 -231
- package/.agents/scripts/lib/orchestration/merge-block-class.js +39 -216
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -377
- package/.agents/scripts/lib/orchestration/merge-queue.js +158 -0
- package/.agents/scripts/lib/orchestration/pinned-identifier-lint.js +17 -57
- package/.agents/scripts/lib/orchestration/plan-context.js +52 -303
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +22 -79
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +5 -31
- package/.agents/scripts/lib/orchestration/plan-metrics.js +29 -108
- package/.agents/scripts/lib/orchestration/plan-navigation.js +8 -27
- package/.agents/scripts/lib/orchestration/plan-persist/acceptance-handle-repair.js +12 -49
- package/.agents/scripts/lib/orchestration/plan-persist/audit-provenance.js +18 -73
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +14 -78
- package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +6 -30
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +14 -65
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +21 -76
- package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +6 -43
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +14 -68
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +9 -41
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +49 -248
- package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +2 -12
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +85 -368
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +8 -38
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +30 -190
- package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +9 -49
- package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +7 -28
- package/.agents/scripts/lib/orchestration/plan-reachability.js +13 -42
- package/.agents/scripts/lib/orchestration/plan-run-labels/reap.js +16 -91
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +16 -54
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +10 -52
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +14 -109
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +11 -83
- package/.agents/scripts/lib/orchestration/pr-watch.js +48 -306
- package/.agents/scripts/lib/orchestration/project-meta-cache.js +15 -80
- package/.agents/scripts/lib/orchestration/project-meta-resolver.js +10 -51
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +12 -76
- package/.agents/scripts/lib/orchestration/remote-verifier.js +12 -36
- package/.agents/scripts/lib/orchestration/resolve-stories.js +33 -164
- package/.agents/scripts/lib/orchestration/retro-proposals.js +66 -361
- package/.agents/scripts/lib/orchestration/review-base-ref.js +9 -43
- package/.agents/scripts/lib/orchestration/review-depth.js +12 -94
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +10 -111
- package/.agents/scripts/lib/orchestration/review-providers/degraded-gates.js +13 -71
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +7 -51
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +8 -53
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -214
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +7 -52
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +4 -33
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +11 -71
- package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +19 -131
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +6 -89
- package/.agents/scripts/lib/orchestration/review-providers/types.js +26 -56
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +3 -46
- package/.agents/scripts/lib/orchestration/run-epilogue.js +40 -199
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +13 -81
- package/.agents/scripts/lib/orchestration/single-story-close/close-note.js +7 -34
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +16 -89
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +18 -109
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +190 -280
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +18 -80
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +103 -97
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -64
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +183 -485
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +30 -134
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +9 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/lock-wait-pending.js +49 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +13 -86
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +20 -95
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +46 -203
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pre-gate-steps.js +8 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +12 -83
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -39
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-outcome.js +4 -28
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +6 -51
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +6 -34
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +23 -121
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +110 -290
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +15 -69
- package/.agents/scripts/lib/orchestration/story-body-gate.js +4 -23
- package/.agents/scripts/lib/orchestration/story-close/baseline-upward-writeback.js +50 -179
- package/.agents/scripts/lib/orchestration/story-close/context-budget-writeback.js +11 -41
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +23 -311
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +22 -147
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +16 -67
- package/.agents/scripts/lib/orchestration/story-deliver-terminal-schema.js +12 -68
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +42 -201
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +43 -245
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +4 -23
- package/.agents/scripts/lib/orchestration/story-init-remote.js +2 -6
- package/.agents/scripts/lib/orchestration/story-reachability.js +3 -23
- package/.agents/scripts/lib/orchestration/task-body-validator.js +12 -126
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -131
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +15 -149
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +5 -33
- package/.agents/scripts/lib/orchestration/ticket-validator.js +39 -181
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +51 -244
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +39 -250
- package/.agents/scripts/lib/orchestration/ticketing/state.js +14 -68
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +46 -263
- package/.agents/scripts/lib/orchestration/ticketing.js +2 -26
- package/.agents/scripts/lib/orchestration/verify-credit.js +18 -79
- package/.agents/scripts/lib/orchestration/worktree-dirty.js +5 -30
- package/.agents/scripts/lib/path-security.js +3 -6
- package/.agents/scripts/lib/plan-phase-cleanup.js +9 -49
- package/.agents/scripts/lib/preflight-runner.js +13 -69
- package/.agents/scripts/lib/process-group.js +143 -0
- package/.agents/scripts/lib/project-root.js +2 -8
- package/.agents/scripts/lib/provider-factory.js +2 -25
- package/.agents/scripts/lib/qa/console-allowlist.js +10 -59
- package/.agents/scripts/lib/qa/qa-session.js +15 -69
- package/.agents/scripts/lib/qa/redact-evidence.js +18 -129
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +26 -135
- package/.agents/scripts/lib/qa/resolve-selection.js +16 -84
- package/.agents/scripts/lib/reserved-test-ids.js +9 -47
- package/.agents/scripts/lib/runtime-deps/dep-resolution.js +13 -53
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +10 -44
- package/.agents/scripts/lib/runtime-deps/manifest.js +10 -30
- package/.agents/scripts/lib/runtime-deps/parser-major.js +15 -51
- package/.agents/scripts/lib/runtime-deps/preflight.js +4 -22
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +11 -55
- package/.agents/scripts/lib/signals/detectors/common.js +12 -38
- package/.agents/scripts/lib/signals/index.js +2 -19
- package/.agents/scripts/lib/signals/schema.js +14 -109
- package/.agents/scripts/lib/signals/write.js +2 -11
- package/.agents/scripts/lib/single-story/confirm-merge.js +31 -72
- package/.agents/scripts/lib/single-story/story-merged-notify.js +8 -49
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +4 -26
- package/.agents/scripts/lib/single-story-sweep/protection.js +13 -100
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +60 -258
- package/.agents/scripts/lib/single-story-sweep.js +14 -97
- package/.agents/scripts/lib/skills/parse-skill.js +13 -59
- package/.agents/scripts/lib/skills/skills-index.js +8 -29
- package/.agents/scripts/lib/skills/walk-skill-files.js +17 -78
- package/.agents/scripts/lib/source-extensions.js +11 -42
- package/.agents/scripts/lib/source-text/strip-js-comments.js +8 -41
- package/.agents/scripts/lib/stdio-flush.js +9 -36
- package/.agents/scripts/lib/story-adjacency.js +8 -40
- package/.agents/scripts/lib/story-body/body-format-lints.js +22 -83
- package/.agents/scripts/lib/story-body/footer-block.js +11 -44
- package/.agents/scripts/lib/story-body/story-body.js +83 -358
- package/.agents/scripts/lib/temp-retention.js +42 -143
- package/.agents/scripts/lib/templates/decomposer-prompts.js +11 -65
- package/.agents/scripts/lib/test-env.js +12 -65
- package/.agents/scripts/lib/test-run-credit.js +10 -65
- package/.agents/scripts/lib/test-runner-contract.js +19 -74
- package/.agents/scripts/lib/test-temp.js +38 -184
- package/.agents/scripts/lib/test-tiers.js +12 -96
- package/.agents/scripts/lib/ticket-body-sections.js +21 -96
- package/.agents/scripts/lib/transpile.js +15 -74
- package/.agents/scripts/lib/util/concurrent-map.js +6 -25
- package/.agents/scripts/lib/util/parse-id-list.js +8 -34
- package/.agents/scripts/lib/util/poll-loop.js +8 -28
- package/.agents/scripts/lib/util/with-timeout.js +2 -11
- package/.agents/scripts/lib/validation-evidence.js +21 -96
- package/.agents/scripts/lib/wave-runner/footprint.js +17 -70
- package/.agents/scripts/lib/wave-runner/live-probe.js +53 -221
- package/.agents/scripts/lib/wave-runner/ready-set.js +72 -301
- package/.agents/scripts/lib/workers/crap-worker.js +11 -64
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +8 -45
- package/.agents/scripts/lib/workers/maintainability-worker.js +5 -21
- package/.agents/scripts/lib/workers/serve-worker-messages.js +2 -18
- package/.agents/scripts/lib/workflow-closure.js +22 -105
- package/.agents/scripts/lib/workspace-provisioner.js +16 -54
- package/.agents/scripts/lib/worktree/git-hooks.js +15 -60
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +20 -60
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +10 -62
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +22 -86
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +24 -126
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +2 -20
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +46 -180
- package/.agents/scripts/lib/worktree-manager.js +15 -40
- package/.agents/scripts/lint-issue-body.js +12 -68
- package/.agents/scripts/mandrel-update-preflight.js +10 -70
- package/.agents/scripts/merge-baseline.js +30 -104
- package/.agents/scripts/nav-registry-diff.js +22 -108
- package/.agents/scripts/notify.js +12 -69
- package/.agents/scripts/plan-context.js +27 -111
- package/.agents/scripts/plan-critics.js +12 -66
- package/.agents/scripts/plan-persist.js +31 -148
- package/.agents/scripts/plan-run-epilogue.js +11 -37
- package/.agents/scripts/pr-watch-with-update.js +76 -267
- package/.agents/scripts/providers/github/auth.js +3 -8
- package/.agents/scripts/providers/github/blocked-by-add.js +14 -61
- package/.agents/scripts/providers/github/board-add.js +5 -21
- package/.agents/scripts/providers/github/branch-protection.js +11 -43
- package/.agents/scripts/providers/github/cache.js +2 -14
- package/.agents/scripts/providers/github/comments.js +7 -40
- package/.agents/scripts/providers/github/compose.js +3 -19
- package/.agents/scripts/providers/github/errors.js +22 -125
- package/.agents/scripts/providers/github/issues.js +31 -123
- package/.agents/scripts/providers/github/labels.js +24 -124
- package/.agents/scripts/providers/github/mappers.js +5 -27
- package/.agents/scripts/providers/github/merge-methods.js +3 -22
- package/.agents/scripts/providers/github/project-board.js +2 -17
- package/.agents/scripts/providers/github/projects-v2-graphql.js +3 -6
- package/.agents/scripts/providers/github/request-helpers.js +5 -32
- package/.agents/scripts/providers/github/search-budget.js +9 -39
- package/.agents/scripts/providers/github/search-query.js +5 -26
- package/.agents/scripts/providers/github/sub-issue-add.js +15 -65
- package/.agents/scripts/providers/github/sub-issues.js +7 -36
- package/.agents/scripts/providers/github/tickets.js +32 -134
- package/.agents/scripts/providers/github.js +18 -59
- package/.agents/scripts/prune-plan-run-labels.js +12 -46
- package/.agents/scripts/quality-preview.js +35 -220
- package/.agents/scripts/resolve-doc-tiers.js +3 -26
- package/.agents/scripts/resolve-stories.js +16 -67
- package/.agents/scripts/resync-status-column.js +6 -25
- package/.agents/scripts/run-tests.js +29 -104
- package/.agents/scripts/single-story-close.js +23 -135
- package/.agents/scripts/single-story-confirm-merge.js +32 -139
- package/.agents/scripts/single-story-init.js +47 -209
- package/.agents/scripts/stories-wave-tick.js +102 -472
- package/.agents/scripts/sync-agentrc.js +3 -21
- package/.agents/scripts/sync-claude-agents.js +9 -55
- package/.agents/scripts/sync-claude-commands.js +20 -110
- package/.agents/scripts/test-wrapper.js +6 -43
- package/.agents/scripts/update-coverage-baseline.js +5 -22
- package/.agents/scripts/update-crap-baseline.js +7 -30
- package/.agents/scripts/update-duplication-baseline.js +16 -92
- package/.agents/scripts/update-maintainability-baseline.js +8 -62
- package/.agents/scripts/update-ticket-state.js +1 -7
- package/.agents/scripts/validate-skills.js +6 -26
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/templates/docs/audit-sweep-runbook.md +3 -4
- package/.agents/workflows/audit-accessibility.md +4 -7
- package/.agents/workflows/audit-adrs.md +3 -6
- package/.agents/workflows/audit-architecture.md +3 -11
- package/.agents/workflows/audit-baselines.md +6 -9
- package/.agents/workflows/audit-clean-code.md +8 -12
- package/.agents/workflows/audit-data-model.md +3 -7
- package/.agents/workflows/audit-dependencies.md +4 -7
- package/.agents/workflows/audit-devops.md +4 -8
- package/.agents/workflows/audit-documentation.md +1 -4
- package/.agents/workflows/audit-mobile.md +4 -7
- package/.agents/workflows/audit-navigability.md +3 -6
- package/.agents/workflows/audit-performance.md +2 -4
- package/.agents/workflows/audit-privacy.md +4 -7
- package/.agents/workflows/audit-quality.md +4 -7
- package/.agents/workflows/audit-security.md +4 -7
- package/.agents/workflows/audit-seo.md +4 -7
- package/.agents/workflows/audit-sre.md +4 -7
- package/.agents/workflows/audit-to-stories.md +17 -30
- package/.agents/workflows/audit-ux-ui.md +4 -7
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-quality-guardrails.md +12 -15
- package/.agents/workflows/helpers/deliver-digest.md +6 -4
- package/.agents/workflows/helpers/deliver-reference.md +114 -188
- package/.agents/workflows/helpers/deliver-story-reference.md +189 -533
- package/.agents/workflows/helpers/plan-reference.md +86 -139
- package/.agents/workflows/helpers/qa-core.md +12 -0
- package/.agents/workflows/memory-consolidate.md +1 -1
- package/.agents/workflows/qa-assist.md +27 -71
- package/.agents/workflows/qa-explore.md +19 -59
- package/.agents/workflows/qa-run.md +11 -33
- package/README.md +1 -1
- package/bin/mandrel.js +5 -46
- package/bin/postinstall.js +18 -107
- package/docs/CHANGELOG.md +32 -0
- package/lib/cli/doctor.js +11 -71
- package/lib/cli/init.js +26 -165
- package/lib/cli/migrate.js +5 -64
- package/lib/cli/registry.js +84 -467
- package/lib/cli/sync-agents.js +4 -64
- package/lib/cli/sync-commands.js +11 -64
- package/lib/cli/sync.js +34 -213
- package/lib/cli/uninstall.js +40 -219
- package/lib/cli/update.js +105 -661
- package/lib/cli/version-check.js +8 -72
- package/lib/cli/version-helpers.js +14 -87
- package/lib/migrations/helpers/retire-agentrc-key.js +11 -52
- package/lib/migrations/index.js +15 -92
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +2 -15
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +1 -13
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +2 -15
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +9 -38
- package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +1 -13
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +2 -27
- package/lib/migrations/steps/2.57.0-retire-delivery-limit-knobs.js +2 -23
- package/lib/migrations/steps/2.57.0-retire-planning-limit-knobs.js +2 -27
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +2 -21
- package/lib/migrations/steps/strip-removed-agentrc-keys.js +333 -0
- package/package.json +16 -14
- package/.agents/docs/SDLC.md +0 -590
- package/.agents/docs/quality-gates.md +0 -1183
- package/.agents/rules/known-tooling-behavior.md +0 -200
- package/.agents/rules/orchestration-error-handling.md +0 -61
- package/.agents/rules/test-seams.md +0 -59
- package/.agents/schemas/baselines/lighthouse.schema.json +0 -59
- package/.agents/schemas/baselines/lint.schema.json +0 -47
- package/.agents/scripts/check-action-pinning.js +0 -260
- package/.agents/scripts/check-audit-attribution.js +0 -302
- package/.agents/scripts/check-baseline-drift.js +0 -211
- package/.agents/scripts/check-baseline-scope.js +0 -362
- package/.agents/scripts/check-generated-validator.js +0 -202
- package/.agents/scripts/check-knip-entries.js +0 -159
- package/.agents/scripts/check-lifecycle-lint.js +0 -294
- package/.agents/scripts/check-pinned-override-notes.js +0 -102
- package/.agents/scripts/check-schema-references.js +0 -368
- package/.agents/scripts/check-test-portability.js +0 -512
- package/.agents/scripts/check-workflow-citations.js +0 -218
- package/.agents/scripts/check-workflow-cli-lint.js +0 -299
- package/.agents/scripts/check-workflow-timeouts.js +0 -291
- package/.agents/scripts/install-matrix-assert.js +0 -326
- package/.agents/scripts/lib/audit-advisories.js +0 -195
- package/.agents/scripts/lib/audit-attribution.js +0 -134
- package/.agents/scripts/lib/baselines/drift-detector.js +0 -351
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +0 -87
- package/.agents/scripts/lib/baselines/kinds/lint.js +0 -184
- package/.agents/scripts/lib/baselines/orphan-pruner.js +0 -233
- package/.agents/scripts/lib/baselines/scope-assert.js +0 -223
- package/.agents/scripts/lib/baselines/scope-inventory.js +0 -314
- package/.agents/scripts/lib/c8-cli-path.js +0 -21
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +0 -51
- package/.agents/scripts/lib/config/gates/lint.schema.js +0 -18
- package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +0 -70
- package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +0 -284
- package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +0 -80
- package/.agents/scripts/lib/dynamic-workflow/degraded-coverage.js +0 -81
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +0 -87
- package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +0 -74
- package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +0 -90
- package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +0 -43
- package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +0 -83
- package/.agents/scripts/lib/fs-walk.js +0 -52
- package/.agents/scripts/lib/knip-config-resolver.js +0 -181
- package/.agents/scripts/lib/knip-entry-sync.js +0 -452
- package/.agents/scripts/lib/pinned-override-notes.js +0 -88
- package/.agents/scripts/lib/pinned-override-resolve.js +0 -212
- package/.agents/scripts/lib/test-isolate/cli-options.js +0 -93
- package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +0 -52
- package/.agents/scripts/lib/test-isolate/list-files.js +0 -90
- package/.agents/scripts/lib/test-isolate/parse-tap.js +0 -75
- package/.agents/scripts/lib/test-isolate/progress-log.js +0 -45
- package/.agents/scripts/lib/test-isolate/render-report.js +0 -97
- package/.agents/scripts/lib/test-isolate/run-isolate.js +0 -87
- package/.agents/scripts/lib/test-isolate/runner.js +0 -483
- package/.agents/scripts/lib/test-profile/parse-tap.js +0 -136
- package/.agents/scripts/lib/test-profile/render-report.js +0 -45
- package/.agents/scripts/lint-label-vocabulary.js +0 -214
- package/.agents/scripts/post-structured-comment.js +0 -127
- package/.agents/scripts/provision-git-hooks.js +0 -85
- package/.agents/scripts/prune-baseline-orphans.js +0 -181
- package/.agents/scripts/run-coverage.js +0 -197
- package/.agents/scripts/run-lint.js +0 -133
- package/.agents/scripts/run-test-profile.js +0 -129
- package/.agents/scripts/run-verify.js +0 -125
- package/.agents/scripts/test-isolate.js +0 -55
- package/.agents/scripts/update-dead-exports-baseline.js +0 -321
|
@@ -1,55 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* bootstrap.js — single-command consumer setup for Mandrel.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* bootstrap-new.js fork into this file). Key behaviours:
|
|
7
|
-
* - No config profiles — `.agentrc.json` always seeds from the bundled
|
|
8
|
-
* `.agents/starter-agentrc.json` starter reference.
|
|
9
|
-
* - Runs even when the directory is NOT a git repo yet (preflight detects
|
|
10
|
-
* git state instead of failing on it).
|
|
11
|
-
* - Adds a Projects V2 permission check to preflight (warns rather than
|
|
12
|
-
* failing when classic token scopes cannot be read, e.g. fine-grained
|
|
13
|
-
* PATs).
|
|
14
|
-
* - Uses a plain summary + confirm loop (interactive runs can go back and
|
|
15
|
-
* re-answer) instead of a phased-approval manifest.
|
|
16
|
-
* - Provisions the missing pieces of a cold start: initializes the local
|
|
17
|
-
* git repo (with a first commit) when absent, creates the GitHub repo
|
|
18
|
-
* (linking + pushing the local tree), and creates the Projects V2 board
|
|
19
|
-
* from a typed name — capturing its number for the rest of the run.
|
|
20
|
-
*
|
|
21
|
-
* Usage:
|
|
22
|
-
* node .agents/scripts/bootstrap.js [flags]
|
|
23
|
-
*
|
|
24
|
-
* Flags:
|
|
25
|
-
* --owner <name> GitHub owner (default: parsed from origin remote)
|
|
26
|
-
* --repo <name> GitHub repo (default: parsed from origin remote)
|
|
27
|
-
* --visibility <v> Visibility for a newly created repo:
|
|
28
|
-
* private | public | internal (default: private)
|
|
29
|
-
* --operator-handle <name> GitHub handle for github.operatorHandle
|
|
30
|
-
* --base-branch <name> Base branch (default: origin/HEAD or 'main')
|
|
31
|
-
* --project-number <n> Projects V2 number/name (optional)
|
|
32
|
-
* --assume-yes Accept every default + approve GitHub-admin
|
|
33
|
-
* mutations. A non-TTY run requires this (or
|
|
34
|
-
* --approve-github-admin) — there is no operator
|
|
35
|
-
* to confirm the summary.
|
|
36
|
-
* --approve-github-admin Consent to the irreversible GitHub-admin phase
|
|
37
|
-
* (labels, Projects V2, branch protection, merge
|
|
38
|
-
* methods) without accepting every other default.
|
|
39
|
-
* --skip-github Skip the GitHub-side bootstrap entirely
|
|
40
|
-
* --with-quality Opt-in: install local quality gates (pre-commit
|
|
41
|
-
* hook + quality:preview/watch scripts). Off by
|
|
42
|
-
* default — prompted y/N.
|
|
43
|
-
* --dry-run Collect info and print the plan; change nothing
|
|
44
|
-
* --with-project-board Opt-in: provision the Projects V2 Status field
|
|
45
|
-
* and custom fields. Off by default — the project
|
|
46
|
-
* board object is still created when a project
|
|
47
|
-
* name is supplied, but decoration is skipped.
|
|
48
|
-
* --with-issue-forms Opt-in: generate .github/ISSUE_TEMPLATE/story.yml.
|
|
49
|
-
* Off by default.
|
|
50
|
-
* --reap-conflicting-workflows Delete Projects V2 built-in workflows that
|
|
51
|
-
* race against the orchestrator (destructive)
|
|
52
|
-
* --help Print this help
|
|
3
|
+
* bootstrap.js — single-command consumer setup for Mandrel (flags: see HELP).
|
|
4
|
+
* Works on a folder that is not yet a git repo, and provisions the missing
|
|
5
|
+
* pieces of a cold start: local repo, GitHub repo, Projects V2 board.
|
|
53
6
|
*/
|
|
54
7
|
|
|
55
8
|
import { spawnSync } from 'node:child_process';
|
|
@@ -58,7 +11,6 @@ import path from 'node:path';
|
|
|
58
11
|
import readline from 'node:readline/promises';
|
|
59
12
|
import { fileURLToPath } from 'node:url';
|
|
60
13
|
|
|
61
|
-
// Reused bootstrap library helpers (unchanged).
|
|
62
14
|
import {
|
|
63
15
|
buildManualInstructions,
|
|
64
16
|
COMMIT_SUBJECT,
|
|
@@ -118,27 +70,14 @@ Flags:
|
|
|
118
70
|
--help Print this help
|
|
119
71
|
`;
|
|
120
72
|
|
|
121
|
-
// ---------------------------------------------------------------------------
|
|
122
|
-
// Small helpers
|
|
123
|
-
// ---------------------------------------------------------------------------
|
|
124
|
-
|
|
125
|
-
/** Strip an `owner/` prefix off a repo slug, leaving the bare repo name. */
|
|
126
73
|
function bareRepoName(slug) {
|
|
127
74
|
const slash = slug.indexOf('/');
|
|
128
75
|
return slash === -1 ? slug : slug.slice(slash + 1);
|
|
129
76
|
}
|
|
130
77
|
|
|
131
78
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* The starter `.agentrc.json` carries `"operatorHandle": "@[USERNAME]"` and the
|
|
135
|
-
* seed step substitutes `[USERNAME]` with this answer — so the answer MUST be
|
|
136
|
-
* the bare handle (no leading `@`), or the seeded value becomes `@@foo`. The
|
|
137
|
-
* interactive validator already rejects a leading `@`, but the
|
|
138
|
-
* `--operator-handle @x` flag and `GH_OPERATOR_HANDLE=@x` env paths skip that
|
|
139
|
-
* validator (Story #3700). Stripping a single leading `@` here closes that gap
|
|
140
|
-
* for every resolution path. Idempotent: a bare handle is returned unchanged,
|
|
141
|
-
* so a re-run never re-strips or re-accumulates.
|
|
79
|
+
* Strip one leading `@`: the starter template's `@[USERNAME]` would otherwise
|
|
80
|
+
* seed `@@foo`, and the flag/env paths bypass the interactive validator.
|
|
142
81
|
*
|
|
143
82
|
* @param {string|undefined|null} handle
|
|
144
83
|
* @returns {string|undefined|null} the input with a single leading `@` removed
|
|
@@ -148,7 +87,6 @@ export function normalizeHandleAnswer(handle) {
|
|
|
148
87
|
return handle.replace(/^@/, '');
|
|
149
88
|
}
|
|
150
89
|
|
|
151
|
-
/** Run a list-producing fn, returning [] on any throw. */
|
|
152
90
|
function safeList(fn) {
|
|
153
91
|
try {
|
|
154
92
|
return fn() ?? [];
|
|
@@ -171,11 +109,7 @@ export function resolveOwnerForPicker(defaults, flags, env = process.env) {
|
|
|
171
109
|
return null;
|
|
172
110
|
}
|
|
173
111
|
|
|
174
|
-
/**
|
|
175
|
-
* Ask a yes/no question. `defaultAnswer` controls the default when the
|
|
176
|
-
* operator presses Enter without typing (true = Y/n, false = y/N). In
|
|
177
|
-
* non-interactive mode the default is returned immediately.
|
|
178
|
-
*/
|
|
112
|
+
/** Yes/no prompt; non-interactive returns `defaultAnswer`. */
|
|
179
113
|
async function confirmYesNo(message, interactive, defaultAnswer = true) {
|
|
180
114
|
if (!interactive) return defaultAnswer;
|
|
181
115
|
const rl = readline.createInterface({
|
|
@@ -194,12 +128,7 @@ async function confirmYesNo(message, interactive, defaultAnswer = true) {
|
|
|
194
128
|
}
|
|
195
129
|
}
|
|
196
130
|
|
|
197
|
-
/**
|
|
198
|
-
* Run a git command in `cwd`. Returns the normalized
|
|
199
|
-
* `{ ok, status, stdout, stderr, error }` shape (mirroring the bootstrap
|
|
200
|
-
* preflight/gh-list runners) so callers branch on `ok` without juggling
|
|
201
|
-
* spawnSync internals.
|
|
202
|
-
*/
|
|
131
|
+
/** Run git in `cwd` → `{ ok, status, stdout, stderr, error }`. */
|
|
203
132
|
function runGit(args, cwd) {
|
|
204
133
|
const result = spawnSync('git', args, { cwd, encoding: 'utf8' });
|
|
205
134
|
return {
|
|
@@ -211,11 +140,7 @@ function runGit(args, cwd) {
|
|
|
211
140
|
};
|
|
212
141
|
}
|
|
213
142
|
|
|
214
|
-
/**
|
|
215
|
-
* Surface a `gh`/exec failure with the same detail the GitHub bootstrap
|
|
216
|
-
* step prints — message plus the real gh stderr/stdout/args carried on a
|
|
217
|
-
* `GhExecError` — so a bare "gh exited with code 1" is actually diagnosable.
|
|
218
|
-
*/
|
|
143
|
+
/** Log a `GhExecError` with its gh stderr/stdout/args so it is diagnosable. */
|
|
219
144
|
function logGhError(label, err) {
|
|
220
145
|
Logger.error(`[Bootstrap] ${label} failed: ${err.message}`);
|
|
221
146
|
if (err.stderr)
|
|
@@ -228,11 +153,8 @@ function logGhError(label, err) {
|
|
|
228
153
|
}
|
|
229
154
|
|
|
230
155
|
/**
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* a freshly provisioned machine. When either is missing we supply a
|
|
234
|
-
* non-persistent identity via `-c` (derived from the operator handle) so the
|
|
235
|
-
* commit succeeds without mutating the operator's git config.
|
|
156
|
+
* A non-persistent `-c` identity when `user.name`/`user.email` is unset (fresh
|
|
157
|
+
* machine), so the commit succeeds without mutating the operator's config.
|
|
236
158
|
*/
|
|
237
159
|
function gitIdentityArgs(cwd, answers) {
|
|
238
160
|
const haveName = runGit(['config', 'user.name'], cwd).ok;
|
|
@@ -248,19 +170,15 @@ function gitIdentityArgs(cwd, answers) {
|
|
|
248
170
|
}
|
|
249
171
|
|
|
250
172
|
/**
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* something to push. Idempotent: a repo that already resolves `HEAD` is left
|
|
254
|
-
* untouched. Returns `{ ok, initialized, committed }` (or `{ ok:false, error }`
|
|
255
|
-
* on failure).
|
|
173
|
+
* Idempotently init the repo and ensure a commit exists for
|
|
174
|
+
* `gh repo create --push`.
|
|
256
175
|
*/
|
|
257
176
|
function ensureGitInitialized(state) {
|
|
258
177
|
const cwd = state.projectRoot;
|
|
259
178
|
const branch = state.answers.baseBranch || 'main';
|
|
260
179
|
let initialized = false;
|
|
261
180
|
if (!state.gitInitialized) {
|
|
262
|
-
// `
|
|
263
|
-
// fall back to a plain init + symbolic-ref for older git.
|
|
181
|
+
// `init -b` needs git ≥ 2.28; fall back to init + symbolic-ref.
|
|
264
182
|
let init = runGit(['init', '-b', branch], cwd);
|
|
265
183
|
if (!init.ok) {
|
|
266
184
|
init = runGit(['init'], cwd);
|
|
@@ -275,18 +193,8 @@ function ensureGitInitialized(state) {
|
|
|
275
193
|
);
|
|
276
194
|
}
|
|
277
195
|
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
// SECURITY (Story #3894): do NOT `git add -A` here. `.gitignore` seeding
|
|
281
|
-
// (`ensureGitignore`) runs two phases later in the pipeline, so at this
|
|
282
|
-
// point a cold-start folder may still contain secret-bearing files
|
|
283
|
-
// (`.env`, `.mcp.json`). Staging the whole tree before any gitignore
|
|
284
|
-
// exists — followed immediately by `gh repo create --push` — would push
|
|
285
|
-
// those secrets to a brand-new (often public) remote with no per-file
|
|
286
|
-
// consent, violating `security-baseline.md` § Secrets Management. The
|
|
287
|
-
// push only needs a commit to *exist*, so we create an empty one; the
|
|
288
|
-
// operator's own first content commit lands after the gitignore phase has
|
|
289
|
-
// already excluded the secret-bearing paths.
|
|
196
|
+
// SECURITY: the commit is EMPTY, never `git add -A` — `.gitignore` is seeded
|
|
197
|
+
// later, so staging now would push `.env` / `.mcp.json` to the new remote.
|
|
290
198
|
let committed = false;
|
|
291
199
|
if (!runGit(['rev-parse', '--verify', 'HEAD'], cwd).ok) {
|
|
292
200
|
const commit = runGit(
|
|
@@ -309,14 +217,9 @@ function ensureGitInitialized(state) {
|
|
|
309
217
|
}
|
|
310
218
|
|
|
311
219
|
/**
|
|
312
|
-
* Wire
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* `origin` itself via `--remote origin`, but a repo that already exists (or
|
|
316
|
-
* a re-run after a partial failure) leaves the local folder unlinked. Only
|
|
317
|
-
* acts when the repo actually exists on GitHub; pushes the base branch to
|
|
318
|
-
* set upstream, downgrading a rejected push to a warning since the bootstrap
|
|
319
|
-
* only needs the remote to resolve (content sync is the operator's to settle).
|
|
220
|
+
* Wire a missing `origin` to an existing GitHub repo (the GitHub bootstrap
|
|
221
|
+
* infers its target from it). A rejected push only warns: the remote just
|
|
222
|
+
* needs to resolve.
|
|
320
223
|
*/
|
|
321
224
|
async function ensureGitRemote(state, execImpl = exec) {
|
|
322
225
|
const cwd = state.projectRoot;
|
|
@@ -345,12 +248,8 @@ async function ensureGitRemote(state, execImpl = exec) {
|
|
|
345
248
|
}
|
|
346
249
|
|
|
347
250
|
/**
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
* resolves, and true on any other error (auth/network/etc.) so a transient
|
|
351
|
-
* failure never triggers a spurious create attempt. Used instead of an
|
|
352
|
-
* `is it in the repo-list?` heuristic, which mis-fires for a brand-new
|
|
353
|
-
* account whose `gh repo list` is empty.
|
|
251
|
+
* `gh repo view` probe: false only on not-found, so a transient error never
|
|
252
|
+
* triggers a spurious create. (A repo-list check mis-fires on empty accounts.)
|
|
354
253
|
*/
|
|
355
254
|
async function repoExists(owner, repo, execImpl = exec) {
|
|
356
255
|
try {
|
|
@@ -364,14 +263,7 @@ async function repoExists(owner, repo, execImpl = exec) {
|
|
|
364
263
|
}
|
|
365
264
|
}
|
|
366
265
|
|
|
367
|
-
/**
|
|
368
|
-
* Link the repo to the Projects V2 board (`gh project link`) so issues and
|
|
369
|
-
* PRs from the repo surface on the project. Runs whenever both a numeric
|
|
370
|
-
* project number and a repo are resolved — a freshly created project or an
|
|
371
|
-
* existing one picked from the list. Non-fatal and re-run-safe: an
|
|
372
|
-
* already-linked repo or a transient hiccup is downgraded to a warning so it
|
|
373
|
-
* never fails the bootstrap.
|
|
374
|
-
*/
|
|
266
|
+
/** `gh project link` the repo to the board; non-fatal and re-run-safe. */
|
|
375
267
|
async function ensureProjectLinked(state, execImpl = exec) {
|
|
376
268
|
const { owner, repo } = state.answers;
|
|
377
269
|
const pn = String(state.answers.projectNumber ?? '');
|
|
@@ -397,11 +289,7 @@ export const REPO_VISIBILITIES = Object.freeze([
|
|
|
397
289
|
'internal',
|
|
398
290
|
]);
|
|
399
291
|
|
|
400
|
-
/**
|
|
401
|
-
* Resolve the new-repo visibility from `--visibility` (default `private`).
|
|
402
|
-
* Case-insensitive. Returns `null` for an unrecognized value so the caller
|
|
403
|
-
* can reject it with a clear message instead of silently defaulting.
|
|
404
|
-
*/
|
|
292
|
+
/** `--visibility` (default `private`); `null` for an unknown value. */
|
|
405
293
|
export function resolveRepoVisibility(flags = {}) {
|
|
406
294
|
const raw = flags.visibility;
|
|
407
295
|
if (typeof raw !== 'string' || raw.length === 0) return 'private';
|
|
@@ -409,14 +297,7 @@ export function resolveRepoVisibility(flags = {}) {
|
|
|
409
297
|
return REPO_VISIBILITIES.includes(value) ? value : null;
|
|
410
298
|
}
|
|
411
299
|
|
|
412
|
-
/**
|
|
413
|
-
* Create the GitHub repo from the resolved owner/repo. `--source` links the
|
|
414
|
-
* existing local repo, `--remote origin` wires the remote, and `--push`
|
|
415
|
-
* uploads the current branch — so the local tree and the new remote stay in
|
|
416
|
-
* lockstep and Step 1's auto-detection works on a re-run. Visibility comes
|
|
417
|
-
* from `--visibility` (default private). Throws GhExecError on failure
|
|
418
|
-
* (surfaced by the caller).
|
|
419
|
-
*/
|
|
300
|
+
/** Create, link as `origin`, and push the repo. Throws GhExecError. */
|
|
420
301
|
async function createGithubRepo(state, execImpl = exec) {
|
|
421
302
|
const { owner, repo } = state.answers;
|
|
422
303
|
const slug = `${owner}/${repo}`;
|
|
@@ -440,13 +321,8 @@ async function createGithubRepo(state, execImpl = exec) {
|
|
|
440
321
|
}
|
|
441
322
|
|
|
442
323
|
/**
|
|
443
|
-
*
|
|
444
|
-
* `
|
|
445
|
-
* `null` when none matches. Lists through the injected `execImpl` seam (the
|
|
446
|
-
* same `gh project list --owner X --format json` shape `gh-list` parses) so
|
|
447
|
-
* the dedupe is unit-testable without spawning a real `gh`. Any non-zero
|
|
448
|
-
* exit, spawn error, or unparseable payload degrades to `null` (no match) so
|
|
449
|
-
* a transient list failure never blocks creation.
|
|
324
|
+
* The number of the owner's board titled `title` (case-insensitive), or
|
|
325
|
+
* `null` — including on any list failure, which must not block creation.
|
|
450
326
|
*
|
|
451
327
|
* @param {string} owner
|
|
452
328
|
* @param {string} title
|
|
@@ -486,14 +362,8 @@ async function findExistingProjectNumber(owner, title, execImpl) {
|
|
|
486
362
|
}
|
|
487
363
|
|
|
488
364
|
/**
|
|
489
|
-
* Resolve the typed
|
|
490
|
-
*
|
|
491
|
-
* steps treat it as an existing project (and never create a duplicate). Before
|
|
492
|
-
* creating, it **dedupes against the owner's existing project titles**: if a
|
|
493
|
-
* board with the same title already exists, that board is adopted instead of
|
|
494
|
-
* running `gh project create` — so a re-run that re-types the same name never
|
|
495
|
-
* spawns a second same-titled board (Story #3896 / review Finding B.3). Throws
|
|
496
|
-
* on create failure or when gh returns no number.
|
|
365
|
+
* Resolve the typed board name to a number (adopting a same-titled board so a
|
|
366
|
+
* re-run never duplicates it) and write it onto `answers.projectNumber`.
|
|
497
367
|
*/
|
|
498
368
|
async function createGithubProject(state, execImpl = exec) {
|
|
499
369
|
const { owner } = state.answers;
|
|
@@ -506,8 +376,7 @@ async function createGithubProject(state, execImpl = exec) {
|
|
|
506
376
|
);
|
|
507
377
|
return existing;
|
|
508
378
|
}
|
|
509
|
-
//
|
|
510
|
-
// the raw `{ stdout }` envelope — parse the number ourselves.
|
|
379
|
+
// `--format json` (not `--json`): exec returns raw stdout to parse.
|
|
511
380
|
const res = await execImpl({
|
|
512
381
|
args: [
|
|
513
382
|
'project',
|
|
@@ -536,32 +405,16 @@ async function createGithubProject(state, execImpl = exec) {
|
|
|
536
405
|
return number;
|
|
537
406
|
}
|
|
538
407
|
|
|
539
|
-
|
|
540
|
-
// Question list (Step 3).
|
|
541
|
-
// ---------------------------------------------------------------------------
|
|
542
|
-
|
|
543
|
-
/**
|
|
544
|
-
* Build the Step 3 question list. `silentAccept` keys (owner/repo/baseBranch/
|
|
545
|
-
* operatorHandle) are git-inferred and accepted without prompting unless an
|
|
546
|
-
* override is supplied. The `operatorHandle` and `projectNumber` defaults
|
|
547
|
-
* track the repo owner / repo name respectively (see post-processing in
|
|
548
|
-
* `collectAndConfirm`).
|
|
549
|
-
*/
|
|
408
|
+
/** The Step 3 question list. */
|
|
550
409
|
export function buildQuestions(defaults, flags, env = process.env, lists = {}) {
|
|
551
410
|
const owner = resolveOwnerForPicker(defaults, flags, env);
|
|
552
|
-
// Pre-fetched lists
|
|
553
|
-
//
|
|
554
|
-
// (a folder with no git remote), so the pickers fall back to a live fetch
|
|
555
|
-
// keyed off the owner the operator just typed (`answers.owner`).
|
|
411
|
+
// Pre-fetched lists are empty when the owner was unknown up front, so the
|
|
412
|
+
// pickers fall back to a live fetch keyed off the typed `answers.owner`.
|
|
556
413
|
const reposList = lists.reposList;
|
|
557
414
|
const projectsList = lists.projectsList;
|
|
558
415
|
const pickerOwner = (answers) => answers?.owner || owner;
|
|
559
|
-
//
|
|
560
|
-
//
|
|
561
|
-
// non-interactive `--assume-yes --skip-github` run materialize and configure
|
|
562
|
-
// a fresh non-git directory (no inferable remote) without hard-failing on
|
|
563
|
-
// `missing required answers: owner, repo`. With GitHub bootstrap active they
|
|
564
|
-
// remain required (the target repo must be resolvable).
|
|
416
|
+
// owner/repo are optional under --skip-github, so a remote-less folder can
|
|
417
|
+
// still be configured non-interactively.
|
|
565
418
|
const skipGithub = Boolean(flags?.['skip-github']);
|
|
566
419
|
return [
|
|
567
420
|
{
|
|
@@ -580,7 +433,6 @@ export function buildQuestions(defaults, flags, env = process.env, lists = {}) {
|
|
|
580
433
|
env: 'GH_OPERATOR_HANDLE',
|
|
581
434
|
message:
|
|
582
435
|
'GitHub username/handle without preceding@ (default: same as owner)',
|
|
583
|
-
// Default tracks the repo owner; resolved post-collect if left blank.
|
|
584
436
|
default: defaults.owner,
|
|
585
437
|
required: false,
|
|
586
438
|
validate: (v) =>
|
|
@@ -624,11 +476,7 @@ export function buildQuestions(defaults, flags, env = process.env, lists = {}) {
|
|
|
624
476
|
message: 'New GitHub Project V2 name',
|
|
625
477
|
pickerMessage:
|
|
626
478
|
'GitHub Project V2 name - Select existing or press ENTER to create',
|
|
627
|
-
//
|
|
628
|
-
// already-provisioned project on a re-run) so `--assume-yes` resolves a
|
|
629
|
-
// numeric answer that `detectCreation` treats as existing — never a
|
|
630
|
-
// duplicate board (Story #3896). Falls back to the repo name only on a
|
|
631
|
-
// genuine first run where nothing is stored yet.
|
|
479
|
+
// A stored number first, so a re-run never reads as a new board.
|
|
632
480
|
default: defaults.projectNumber || defaults.repo,
|
|
633
481
|
required: false,
|
|
634
482
|
picker: {
|
|
@@ -640,8 +488,7 @@ export function buildQuestions(defaults, flags, env = process.env, lists = {}) {
|
|
|
640
488
|
return o ? listProjects({ owner: o }) : [];
|
|
641
489
|
},
|
|
642
490
|
},
|
|
643
|
-
//
|
|
644
|
-
// name (letters/digits/space/._-).
|
|
491
|
+
// Blank (skip), an existing number, or a new project name.
|
|
645
492
|
validate: (v) =>
|
|
646
493
|
v.length === 0 || /^\d+$/.test(v) || /^[A-Za-z0-9 ._-]+$/.test(v)
|
|
647
494
|
? null
|
|
@@ -682,10 +529,6 @@ export function resolveSilentAccept(defaults, flags, env = process.env) {
|
|
|
682
529
|
return out;
|
|
683
530
|
}
|
|
684
531
|
|
|
685
|
-
// ---------------------------------------------------------------------------
|
|
686
|
-
// GitHub-side bootstrap (Step 6) — same wiring as bootstrap.js.
|
|
687
|
-
// ---------------------------------------------------------------------------
|
|
688
|
-
|
|
689
532
|
async function runGithubBootstrap(answers, opts) {
|
|
690
533
|
const { runBootstrap, preflightGh, preflightRuntimeDeps } = await import(
|
|
691
534
|
'./agents-bootstrap-github.js'
|
|
@@ -695,10 +538,8 @@ async function runGithubBootstrap(answers, opts) {
|
|
|
695
538
|
const { resolveConfig, validateOrchestrationConfig } = await import(
|
|
696
539
|
'./lib/config-resolver.js'
|
|
697
540
|
);
|
|
698
|
-
//
|
|
699
|
-
//
|
|
700
|
-
// the existing project instead of creating a new one (Bug: gave #8, created
|
|
701
|
-
// #12 because the number never reached the provider config).
|
|
541
|
+
// persistProjectNumber has already written the number, so the provider
|
|
542
|
+
// reuses the board instead of creating another.
|
|
702
543
|
const config = resolveConfig();
|
|
703
544
|
validateOrchestrationConfig(config);
|
|
704
545
|
return runBootstrap(config, {
|
|
@@ -706,15 +547,9 @@ async function runGithubBootstrap(answers, opts) {
|
|
|
706
547
|
github: config.github,
|
|
707
548
|
assumeYes: opts.assumeYes,
|
|
708
549
|
baseBranch: answers.baseBranch,
|
|
709
|
-
//
|
|
710
|
-
// interactive operator confirmation, `--assume-yes`, or
|
|
711
|
-
// `--approve-github-admin`. Default-deny at the boundary gate when absent.
|
|
550
|
+
// Default-deny at the boundary gate (see parseAndValidate).
|
|
712
551
|
githubAdminApproved: opts.githubAdminApproved === true,
|
|
713
|
-
// Opt-in: provision Status field + custom fields on the project board.
|
|
714
|
-
// Default off — prompted y/N during collect/confirm or via --with-project-board.
|
|
715
552
|
withProjectBoard: opts.withProjectBoard === true,
|
|
716
|
-
// Opt-in: delete the Projects V2 built-in workflows that race against the
|
|
717
|
-
// orchestrator's ColumnSync (e.g. "Pull request merged"). Off by default.
|
|
718
553
|
reapConflictingWorkflows: Boolean(opts.reapConflictingWorkflows),
|
|
719
554
|
});
|
|
720
555
|
}
|
|
@@ -727,13 +562,8 @@ function githubSubMutationsSucceeded(gh) {
|
|
|
727
562
|
}
|
|
728
563
|
|
|
729
564
|
/**
|
|
730
|
-
* Phase groups
|
|
731
|
-
*
|
|
732
|
-
* Every project-side group runs on every install (Story #3690 replaced the
|
|
733
|
-
* consent-first phased-approval install with a plain summary+confirm loop),
|
|
734
|
-
* so the only variable is whether the irreversible GitHub-admin mutations
|
|
735
|
-
* landed. Story #5007 collapsed the set-threading this used to carry down to
|
|
736
|
-
* that one boolean.
|
|
565
|
+
* Phase groups that landed, for the install ledger. Every project-side group
|
|
566
|
+
* always runs; only GitHub-admin is variable.
|
|
737
567
|
*
|
|
738
568
|
* @param {object|undefined} report — the live execution report.
|
|
739
569
|
* @returns {Set<string>}
|
|
@@ -748,29 +578,11 @@ function resolveAppliedGroups(report) {
|
|
|
748
578
|
return applied;
|
|
749
579
|
}
|
|
750
580
|
|
|
751
|
-
// ---------------------------------------------------------------------------
|
|
752
|
-
// Pipeline phases
|
|
753
|
-
// ---------------------------------------------------------------------------
|
|
754
|
-
|
|
755
581
|
/**
|
|
756
|
-
* Step 1 —
|
|
757
|
-
*
|
|
758
|
-
*
|
|
759
|
-
*
|
|
760
|
-
* mutations cannot ride on a real confirmation — they need an explicit
|
|
761
|
-
* up-front signal. The gate therefore requires **either** `--assume-yes`
|
|
762
|
-
* **or** `--approve-github-admin` on any non-TTY run (matching the
|
|
763
|
-
* `--help` text), and computes `githubAdminApproved` once for the whole run:
|
|
764
|
-
*
|
|
765
|
-
* - **interactive (TTY)** → consent is the operator's `Is this correct?`
|
|
766
|
-
* confirmation in `collectAndConfirm`, so the run is approved.
|
|
767
|
-
* - **non-TTY** → consent is `--assume-yes` or `--approve-github-admin`;
|
|
768
|
-
* without one of those the run halts before any mutation.
|
|
769
|
-
*
|
|
770
|
-
* `githubAdminApproved` flows down to `runGithubBootstrap`, which forwards it
|
|
771
|
-
* to the boundary gate in `agents-bootstrap-github.js#runBootstrap`. That
|
|
772
|
-
* gate is default-deny, so a non-approved value makes the GitHub-admin phase
|
|
773
|
-
* a verified no-op instead of a silent mutation.
|
|
582
|
+
* Step 1 — parse argv and compute GitHub-admin consent once: an interactive
|
|
583
|
+
* run consents via the summary confirmation; a non-TTY run MUST pass
|
|
584
|
+
* `--assume-yes` or `--approve-github-admin` or halts before any mutation.
|
|
585
|
+
* The downstream gate in `runBootstrap` is default-deny.
|
|
774
586
|
*/
|
|
775
587
|
export function parseAndValidate(argv, opts = {}) {
|
|
776
588
|
const stdout = opts.stdout ?? process.stdout;
|
|
@@ -783,12 +595,6 @@ export function parseAndValidate(argv, opts = {}) {
|
|
|
783
595
|
const interactive = Boolean(stdin.isTTY) && !flags['assume-yes'];
|
|
784
596
|
const assumeYes = Boolean(flags['assume-yes']);
|
|
785
597
|
const approveGithubAdmin = Boolean(flags['approve-github-admin']);
|
|
786
|
-
// A non-TTY run cannot collect operator consent interactively, so it MUST
|
|
787
|
-
// carry an explicit consent signal. This restores parity with the --help
|
|
788
|
-
// text, which has always claimed --assume-yes is required for non-TTY runs.
|
|
789
|
-
// (owner/repo are resolved from flags/env/git-remote downstream — a consent
|
|
790
|
-
// signal alone is sufficient to advance, exactly as the pre-Story #3897
|
|
791
|
-
// `--assume-yes` path did.)
|
|
792
598
|
if (!interactive && !assumeYes && !approveGithubAdmin) {
|
|
793
599
|
Logger.error(
|
|
794
600
|
'[Bootstrap] non-TTY run requires --assume-yes or --approve-github-admin ' +
|
|
@@ -796,8 +602,6 @@ export function parseAndValidate(argv, opts = {}) {
|
|
|
796
602
|
);
|
|
797
603
|
return { ok: false, exit: 1 };
|
|
798
604
|
}
|
|
799
|
-
// Real GitHub-admin consent: an interactive run confirms it in
|
|
800
|
-
// `collectAndConfirm`; a non-TTY run signals it via flag (above).
|
|
801
605
|
const githubAdminApproved = interactive || assumeYes || approveGithubAdmin;
|
|
802
606
|
if (resolveRepoVisibility(flags) === null) {
|
|
803
607
|
Logger.error(
|
|
@@ -812,10 +616,7 @@ export function parseAndValidate(argv, opts = {}) {
|
|
|
812
616
|
};
|
|
813
617
|
}
|
|
814
618
|
|
|
815
|
-
/**
|
|
816
|
-
* Step 1b — Resolve paths, infer defaults from git, and echo the detected
|
|
817
|
-
* values back to the operator (the "share found values" requirement).
|
|
818
|
-
*/
|
|
619
|
+
/** Step 1b — resolve paths, infer defaults from git, and echo them. */
|
|
819
620
|
export function prepareContext(state, opts = {}) {
|
|
820
621
|
const scriptUrl = opts.scriptUrl ?? import.meta.url;
|
|
821
622
|
const here = path.dirname(fileURLToPath(scriptUrl));
|
|
@@ -837,11 +638,7 @@ export function prepareContext(state, opts = {}) {
|
|
|
837
638
|
};
|
|
838
639
|
}
|
|
839
640
|
|
|
840
|
-
/**
|
|
841
|
-
* Step 2 — Preflight. Work-tree check is informational (does not fail the
|
|
842
|
-
* gate); adds the Projects V2 permission check. Prints a pass/fail line for
|
|
843
|
-
* every check.
|
|
844
|
-
*/
|
|
641
|
+
/** Step 2 — preflight; the work-tree check is informational only. */
|
|
845
642
|
export async function runPreflightPhase(state, opts = {}) {
|
|
846
643
|
const run = opts.run ?? runPreflight;
|
|
847
644
|
const skipGithub = Boolean(state.flags['skip-github']);
|
|
@@ -853,10 +650,7 @@ export async function runPreflightPhase(state, opts = {}) {
|
|
|
853
650
|
|
|
854
651
|
for (const check of result.checks) {
|
|
855
652
|
if (check.ok) {
|
|
856
|
-
//
|
|
857
|
-
// glyph reflecting the real state rather than its always-true gate pass:
|
|
858
|
-
// ✓ when the git repo exists, ✗ when it does not (bootstrap initialises
|
|
859
|
-
// it in a later phase regardless — the ✗ never aborts the run).
|
|
653
|
+
// The informational git check shows the real state; its ✗ never aborts.
|
|
860
654
|
const glyph =
|
|
861
655
|
typeof check.gitInitialized === 'boolean' && !check.gitInitialized
|
|
862
656
|
? '✗'
|
|
@@ -876,18 +670,12 @@ export async function runPreflightPhase(state, opts = {}) {
|
|
|
876
670
|
return { ok: false, exit: 1 };
|
|
877
671
|
}
|
|
878
672
|
|
|
879
|
-
// The git-repo state is already reported by the (non-fatal) "Local git
|
|
880
|
-
// initialized" check above — both derive from the same
|
|
881
|
-
// `git rev-parse --is-inside-work-tree` probe — so there is no separate
|
|
882
|
-
// "git initialized" line here (it would duplicate, and contradict, that
|
|
883
|
-
// check). The boolean is still threaded through the payload for later phases.
|
|
884
673
|
return {
|
|
885
674
|
ok: true,
|
|
886
675
|
payload: { preflight: result, gitInitialized: result.gitInitialized },
|
|
887
676
|
};
|
|
888
677
|
}
|
|
889
678
|
|
|
890
|
-
/** Render the resolved answers as a human-readable summary block. */
|
|
891
679
|
function renderAnswerSummary(
|
|
892
680
|
answers,
|
|
893
681
|
creation,
|
|
@@ -912,14 +700,8 @@ function renderAnswerSummary(
|
|
|
912
700
|
}
|
|
913
701
|
|
|
914
702
|
/**
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
* exist — an authoritative per-repo probe rather than an "is it in the
|
|
918
|
-
* repo-list?" check, which mis-fired for a brand-new account whose
|
|
919
|
-
* `gh repo list` is empty (it then assumed the repo already existed and
|
|
920
|
-
* skipped creation). A non-numeric project answer (a typed name, not a
|
|
921
|
-
* picked number) is "new". When GitHub is skipped there is nothing to
|
|
922
|
-
* create, so detection is bypassed.
|
|
703
|
+
* Which answers name resources that do not exist yet: a repo `repoExists`
|
|
704
|
+
* denies, or a non-numeric (typed) project answer.
|
|
923
705
|
*/
|
|
924
706
|
async function detectCreation(answers, skipGithub) {
|
|
925
707
|
const creation = { newRepo: false, newProject: false };
|
|
@@ -935,10 +717,8 @@ async function detectCreation(answers, skipGithub) {
|
|
|
935
717
|
}
|
|
936
718
|
|
|
937
719
|
/**
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
* project (numeric answer) we look the name up in the owner's project list.
|
|
941
|
-
* A typed answer (non-numeric) is a new project name with no number yet.
|
|
720
|
+
* `{ name, number }` for the summary; the picker stores only the number, so
|
|
721
|
+
* an existing project's name is looked up.
|
|
942
722
|
*/
|
|
943
723
|
function resolveProjectDisplay(answers, skipGithub, projectsList) {
|
|
944
724
|
const pn = answers.projectNumber;
|
|
@@ -956,23 +736,17 @@ function resolveProjectDisplay(answers, skipGithub, projectsList) {
|
|
|
956
736
|
}
|
|
957
737
|
return { name, number: pn };
|
|
958
738
|
}
|
|
959
|
-
// Typed name → new project; number is assigned at creation time.
|
|
960
739
|
return { name: pn, number: '(new)' };
|
|
961
740
|
}
|
|
962
741
|
|
|
963
742
|
/**
|
|
964
|
-
* Steps 3 + 4 —
|
|
965
|
-
*
|
|
966
|
-
* auto-accept. Then collect creation approval when a new repo/project was
|
|
967
|
-
* requested.
|
|
743
|
+
* Steps 3 + 4 — collect answers and loop until the summary is confirmed, then
|
|
744
|
+
* get creation approval and the opt-ins.
|
|
968
745
|
*/
|
|
969
746
|
export async function collectAndConfirm(state) {
|
|
970
747
|
const skipGithub = Boolean(state.flags['skip-github']);
|
|
971
748
|
const owner = resolveOwnerForPicker(state.defaults, state.flags);
|
|
972
|
-
//
|
|
973
|
-
// the summary display — so the resolved project name never depends on a
|
|
974
|
-
// second (flaky) `gh` call. (Repo existence for the creation check is a
|
|
975
|
-
// separate, authoritative `gh repo view` probe in `detectCreation`.)
|
|
749
|
+
// Fetched once for pickers and summary, so the name never needs a second call.
|
|
976
750
|
const reposList =
|
|
977
751
|
!skipGithub && owner
|
|
978
752
|
? safeList(() => listRepos({ owner }).map(bareRepoName))
|
|
@@ -981,7 +755,6 @@ export async function collectAndConfirm(state) {
|
|
|
981
755
|
!skipGithub && owner ? safeList(() => listProjects({ owner })) : [];
|
|
982
756
|
|
|
983
757
|
let silentAccept = state.silentAccept;
|
|
984
|
-
// Loop until the operator confirms the summary (or we auto-accept).
|
|
985
758
|
for (;;) {
|
|
986
759
|
const { answers, missing } = await collectAnswers({
|
|
987
760
|
questions: buildQuestions(state.defaults, state.flags, process.env, {
|
|
@@ -1002,12 +775,7 @@ export async function collectAndConfirm(state) {
|
|
|
1002
775
|
);
|
|
1003
776
|
return { ok: false, exit: 1 };
|
|
1004
777
|
}
|
|
1005
|
-
// Defaults that track another answer: handle ⇐ owner, project ⇐ repo.
|
|
1006
778
|
if (!answers.operatorHandle) answers.operatorHandle = answers.owner;
|
|
1007
|
-
// Strip a single leading `@` so the starter template's `@[USERNAME]`
|
|
1008
|
-
// substitution yields `@foo`, not `@@foo` (Story #3700). The flag/env
|
|
1009
|
-
// paths bypass the interactive validator that already rejects a leading
|
|
1010
|
-
// `@`, so normalize uniformly here.
|
|
1011
779
|
answers.operatorHandle = normalizeHandleAnswer(answers.operatorHandle);
|
|
1012
780
|
|
|
1013
781
|
const creation = await detectCreation(answers, skipGithub);
|
|
@@ -1024,12 +792,10 @@ export async function collectAndConfirm(state) {
|
|
|
1024
792
|
const correct = await confirmYesNo('Is this correct?', state.interactive);
|
|
1025
793
|
if (!correct) {
|
|
1026
794
|
Logger.info('[Bootstrap] Okay — let’s try again.');
|
|
1027
|
-
// Re-prompt everything on the next pass (drop silent-accept).
|
|
1028
795
|
silentAccept = [];
|
|
1029
796
|
continue;
|
|
1030
797
|
}
|
|
1031
798
|
|
|
1032
|
-
// In --dry-run we only collect/confirm info, so never ask to create.
|
|
1033
799
|
if (!state.flags['dry-run'] && (creation.newRepo || creation.newProject)) {
|
|
1034
800
|
const approved = await confirmYesNo(
|
|
1035
801
|
'Create the new GitHub repo/project listed above?',
|
|
@@ -1043,8 +809,7 @@ export async function collectAndConfirm(state) {
|
|
|
1043
809
|
}
|
|
1044
810
|
}
|
|
1045
811
|
|
|
1046
|
-
// Opt-
|
|
1047
|
-
// Dry-run halts immediately after this step — resolve without prompting.
|
|
812
|
+
// Opt-ins default off; dry-run resolves them without prompting.
|
|
1048
813
|
let withProjectBoard = Boolean(state.flags['with-project-board']);
|
|
1049
814
|
if (!state.flags['dry-run'] && !withProjectBoard) {
|
|
1050
815
|
withProjectBoard = await confirmYesNo(
|
|
@@ -1054,7 +819,6 @@ export async function collectAndConfirm(state) {
|
|
|
1054
819
|
);
|
|
1055
820
|
}
|
|
1056
821
|
|
|
1057
|
-
// Opt-in: GitHub Issue Form templates. Default off.
|
|
1058
822
|
let withIssueForms = Boolean(state.flags['with-issue-forms']);
|
|
1059
823
|
if (!state.flags['dry-run'] && !withIssueForms) {
|
|
1060
824
|
withIssueForms = await confirmYesNo(
|
|
@@ -1064,7 +828,6 @@ export async function collectAndConfirm(state) {
|
|
|
1064
828
|
);
|
|
1065
829
|
}
|
|
1066
830
|
|
|
1067
|
-
// Opt-in: local quality gates. Default off.
|
|
1068
831
|
let withQuality = Boolean(state.flags['with-quality']);
|
|
1069
832
|
if (!state.flags['dry-run'] && !withQuality) {
|
|
1070
833
|
withQuality = await confirmYesNo(
|
|
@@ -1087,12 +850,6 @@ export async function collectAndConfirm(state) {
|
|
|
1087
850
|
}
|
|
1088
851
|
}
|
|
1089
852
|
|
|
1090
|
-
/**
|
|
1091
|
-
* --dry-run gate — print the resolved answers and the full mutation plan,
|
|
1092
|
-
* then halt BEFORE any file write, GitHub change, or label creation. Runs
|
|
1093
|
-
* after collect/confirm so the operator sees exactly what would happen.
|
|
1094
|
-
*/
|
|
1095
|
-
/** Render the dry-run plan as a per-section layout (no mutations happen). */
|
|
1096
853
|
function renderDryRunPlan(state) {
|
|
1097
854
|
const a = state.answers ?? {};
|
|
1098
855
|
const c = state.creation ?? {};
|
|
@@ -1118,6 +875,7 @@ function renderDryRunPlan(state) {
|
|
|
1118
875
|
].join('\n');
|
|
1119
876
|
}
|
|
1120
877
|
|
|
878
|
+
/** --dry-run gate: print the plan and halt before any mutation. */
|
|
1121
879
|
export function dryRunPlan(state) {
|
|
1122
880
|
if (!state.flags['dry-run']) return { ok: true, payload: {} };
|
|
1123
881
|
Logger.info(
|
|
@@ -1128,34 +886,14 @@ export function dryRunPlan(state) {
|
|
|
1128
886
|
}
|
|
1129
887
|
|
|
1130
888
|
/**
|
|
1131
|
-
* Step 5 —
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
* repo yet (so the repo create below has something to push).
|
|
1135
|
-
* 2. GitHub repo — `gh repo create --source --remote --push` when the repo
|
|
1136
|
-
* does not exist for the owner; otherwise wire the `origin` remote to the
|
|
1137
|
-
* existing repo when the local folder is not yet linked. Either way the
|
|
1138
|
-
* GitHub bootstrap can resolve the target from the local remote.
|
|
1139
|
-
* 3. GitHub Project V2 — `gh project create` from the typed name when the
|
|
1140
|
-
* project answer is a name rather than an existing number; the assigned
|
|
1141
|
-
* number is written back onto `state.answers.projectNumber`.
|
|
1142
|
-
* 4. Link — `gh project link` ties the repo to the project board so its
|
|
1143
|
-
* issues/PRs surface there (non-fatal; safe to re-run).
|
|
1144
|
-
*
|
|
1145
|
-
* Every action is idempotent and guarded by the detection done in
|
|
1146
|
-
* `collectAndConfirm`, so a re-run on an already-provisioned project is a
|
|
1147
|
-
* no-op. `--skip-github` suppresses the GitHub mutations but still runs the
|
|
1148
|
-
* local git init. `--dry-run` never reaches this step (it halts earlier).
|
|
1149
|
-
*
|
|
1150
|
-
* `deps.exec` injects the `gh-exec` seam so the GitHub-touching branches
|
|
1151
|
-
* (`gh repo create`, `gh project create`, `gh project link`) are unit-testable
|
|
1152
|
-
* without spawning a real `gh`; it defaults to the module's `exec`.
|
|
889
|
+
* Step 5 — provision a cold start in dependency order: local git, GitHub repo
|
|
890
|
+
* (or `origin` wiring), Projects V2 board, repo↔board link. Every step is
|
|
891
|
+
* idempotent; `--skip-github` still runs the local git init.
|
|
1153
892
|
*/
|
|
1154
893
|
export async function provisionResources(state, deps = {}) {
|
|
1155
894
|
const execImpl = deps.exec ?? exec;
|
|
1156
895
|
const skipGithub = Boolean(state.flags['skip-github']);
|
|
1157
896
|
|
|
1158
|
-
// 1. Local git — initialize + first commit when missing (idempotent).
|
|
1159
897
|
const git = ensureGitInitialized(state);
|
|
1160
898
|
if (!git.ok) {
|
|
1161
899
|
Logger.error(`[Bootstrap] git initialization failed: ${git.error}`);
|
|
@@ -1175,10 +913,6 @@ export async function provisionResources(state, deps = {}) {
|
|
|
1175
913
|
return { ok: true, payload: {} };
|
|
1176
914
|
}
|
|
1177
915
|
|
|
1178
|
-
// 2. GitHub repo — create + link + push when it does not exist yet;
|
|
1179
|
-
// otherwise ensure the local `origin` remote points at the existing repo
|
|
1180
|
-
// so the GitHub bootstrap can resolve the target (idempotent re-runs and
|
|
1181
|
-
// pre-created repos would otherwise leave the folder unlinked).
|
|
1182
916
|
if (newRepo) {
|
|
1183
917
|
try {
|
|
1184
918
|
await createGithubRepo(state, execImpl);
|
|
@@ -1190,12 +924,9 @@ export async function provisionResources(state, deps = {}) {
|
|
|
1190
924
|
await ensureGitRemote(state, execImpl);
|
|
1191
925
|
}
|
|
1192
926
|
|
|
1193
|
-
// 3. GitHub Project V2 — create from the typed name; capture its number so
|
|
1194
|
-
// the persist + GitHub bootstrap steps reuse it instead of duplicating.
|
|
1195
927
|
if (newProject) {
|
|
1196
928
|
try {
|
|
1197
929
|
await createGithubProject(state, execImpl);
|
|
1198
|
-
// It now exists with a real number; downstream treats it as existing.
|
|
1199
930
|
state.creation.newProject = false;
|
|
1200
931
|
} catch (err) {
|
|
1201
932
|
logGhError('project create', err);
|
|
@@ -1207,19 +938,12 @@ export async function provisionResources(state, deps = {}) {
|
|
|
1207
938
|
Logger.info('[Bootstrap] No new GitHub resources needed.');
|
|
1208
939
|
}
|
|
1209
940
|
|
|
1210
|
-
// 4. Link the repo to the project board so issues/PRs surface on it
|
|
1211
|
-
// (idempotent + non-fatal; runs for both freshly created and existing
|
|
1212
|
-
// repo/project pairs).
|
|
1213
941
|
await ensureProjectLinked(state, execImpl);
|
|
1214
942
|
|
|
1215
943
|
return { ok: true, payload: {} };
|
|
1216
944
|
}
|
|
1217
945
|
|
|
1218
|
-
/**
|
|
1219
|
-
* Step 6a — Project-side bootstrap. Every project-side phase runs; the
|
|
1220
|
-
* install ledger decides afterwards which phase groups actually landed
|
|
1221
|
-
* ({@link resolveAppliedGroups}).
|
|
1222
|
-
*/
|
|
946
|
+
/** Step 6a — project-side bootstrap (every phase runs). */
|
|
1223
947
|
export async function executeBootstrap(state) {
|
|
1224
948
|
Logger.info(
|
|
1225
949
|
`[Bootstrap] Starting project bootstrap at ${state.projectRoot} (owner=${state.answers.owner} repo=${state.answers.repo} base=${state.answers.baseBranch})`,
|
|
@@ -1235,13 +959,9 @@ export async function executeBootstrap(state) {
|
|
|
1235
959
|
}
|
|
1236
960
|
|
|
1237
961
|
/**
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
* bootstrap has ensured .agentrc.json exists and BEFORE the GitHub bootstrap,
|
|
1242
|
-
* so the provider reuses the existing project instead of creating a new one.
|
|
1243
|
-
* Merges into an existing file (ensureAgentrc never overwrites one). Stored as
|
|
1244
|
-
* an integer per the schema; a blank/new-project answer stores nothing.
|
|
962
|
+
* Persist the numeric project number into `.agentrc.json` — after the
|
|
963
|
+
* project-side bootstrap creates the file, before the GitHub bootstrap reads
|
|
964
|
+
* it, so the provider reuses the board.
|
|
1245
965
|
*/
|
|
1246
966
|
export function persistProjectNumber(state) {
|
|
1247
967
|
const pn = String(state.answers.projectNumber ?? '');
|
|
@@ -1259,10 +979,7 @@ export function persistProjectNumber(state) {
|
|
|
1259
979
|
return { ok: true, payload: {} };
|
|
1260
980
|
}
|
|
1261
981
|
config.github = config.github ?? {};
|
|
1262
|
-
//
|
|
1263
|
-
// when the stored number actually changes. When the value is already present
|
|
1264
|
-
// and equal, leave the file byte-for-byte untouched — a re-run must not churn
|
|
1265
|
-
// the consumer's hand-formatting or whitespace.
|
|
982
|
+
// Unchanged → leave the file byte-for-byte (keep the consumer's formatting).
|
|
1266
983
|
if (config.github.projectNumber === Number(pn)) {
|
|
1267
984
|
return { ok: true, payload: {} };
|
|
1268
985
|
}
|
|
@@ -1288,8 +1005,6 @@ export async function executeGithubBootstrap(state) {
|
|
|
1288
1005
|
),
|
|
1289
1006
|
});
|
|
1290
1007
|
} catch (err) {
|
|
1291
|
-
// GhExecError carries the real gh stderr/stdout/exit code — surface it so
|
|
1292
|
-
// a generic "gh exited with code 1" is actually diagnosable.
|
|
1293
1008
|
logGhError('GitHub bootstrap', err);
|
|
1294
1009
|
state.report.github = { error: err.message };
|
|
1295
1010
|
}
|
|
@@ -1304,10 +1019,6 @@ export function recordLedger(state) {
|
|
|
1304
1019
|
skipGithub: Boolean(state.flags['skip-github']),
|
|
1305
1020
|
withQuality: state.withQuality === true,
|
|
1306
1021
|
};
|
|
1307
|
-
// The manifest always carries the unconditional ide-wiring / repo-config
|
|
1308
|
-
// entries and `appliedGroups` always contains those groups, so the filter
|
|
1309
|
-
// never empties. (Story #5007 removed the phased-approval gate that was the
|
|
1310
|
-
// only way to reach an empty set.)
|
|
1311
1022
|
const entries = buildMutationManifest(manifestCtx).filter((e) =>
|
|
1312
1023
|
appliedGroups.has(e.phaseGroup),
|
|
1313
1024
|
);
|
|
@@ -1315,9 +1026,8 @@ export function recordLedger(state) {
|
|
|
1315
1026
|
entries,
|
|
1316
1027
|
approvedGroups: appliedGroups,
|
|
1317
1028
|
answers: state.answers,
|
|
1318
|
-
//
|
|
1319
|
-
//
|
|
1320
|
-
// `.agentrc.json` the install merely left in place (Story #3895).
|
|
1029
|
+
// Records `already-present` vs `seeded`, so uninstall never deletes a
|
|
1030
|
+
// pre-existing `.agentrc.json`.
|
|
1321
1031
|
report: state.report,
|
|
1322
1032
|
});
|
|
1323
1033
|
const result = writeInstallLedger(state.projectRoot, record);
|
|
@@ -1326,32 +1036,11 @@ export function recordLedger(state) {
|
|
|
1326
1036
|
}
|
|
1327
1037
|
|
|
1328
1038
|
/**
|
|
1329
|
-
* Step 7 —
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
*
|
|
1334
|
-
* the commit + push at the end of the run.
|
|
1335
|
-
*
|
|
1336
|
-
* Ordering: this phase runs LAST in the pipeline, after `executeBootstrap`
|
|
1337
|
-
* (which seeds the secret-safe `.gitignore`) and `recordLedger`. The stage
|
|
1338
|
-
* step also uses an explicit allowlist and refuses to stage `.env` /
|
|
1339
|
-
* `.mcp.json` / `.agentrc.local.json` regardless of `.gitignore` state, so the
|
|
1340
|
-
* commit never carries a secret even before the gitignore-ordering Story
|
|
1341
|
-
* (#3894) lands.
|
|
1342
|
-
*
|
|
1343
|
-
* Behaviour:
|
|
1344
|
-
* - `--dry-run` → no-op (the dry-run gate already halted earlier; this is a
|
|
1345
|
-
* belt-and-braces guard for direct calls).
|
|
1346
|
-
* - Interactive + accept → stage the allowlist, commit with a conventional
|
|
1347
|
-
* subject, push the base branch.
|
|
1348
|
-
* - Interactive + decline → print the exact manual commands; no git mutation.
|
|
1349
|
-
* - Non-interactive (`--assume-yes` / no TTY) → the defined safe path is to
|
|
1350
|
-
* print the manual commands and make NO git mutation, so a CI run never
|
|
1351
|
-
* surprises the operator with a push it did not ask for.
|
|
1352
|
-
*
|
|
1353
|
-
* `deps.runGit` injects the git seam and `deps.confirm` the yes/no prompt seam
|
|
1354
|
-
* for unit testing; both default to the module's implementations.
|
|
1039
|
+
* Step 7 — offer to commit + push the wiring: delivery worktrees check out
|
|
1040
|
+
* tracked files only, so an uncommitted `.agents/` breaks every Story. Runs
|
|
1041
|
+
* last, after `.gitignore` is seeded; staging is an allowlist that refuses
|
|
1042
|
+
* secret files regardless. Non-interactive runs only print the commands —
|
|
1043
|
+
* never an unasked-for push.
|
|
1355
1044
|
*/
|
|
1356
1045
|
export async function offerCommitPush(state, deps = {}) {
|
|
1357
1046
|
if (state.flags['dry-run']) return { ok: true, payload: {} };
|
|
@@ -1365,8 +1054,6 @@ export async function offerCommitPush(state, deps = {}) {
|
|
|
1365
1054
|
baseBranch: branch,
|
|
1366
1055
|
});
|
|
1367
1056
|
|
|
1368
|
-
// Non-interactive (--assume-yes / no TTY): never push unprompted. Print the
|
|
1369
|
-
// exact commands and leave the working tree untouched.
|
|
1370
1057
|
if (!state.interactive) {
|
|
1371
1058
|
Logger.info(`\n[Bootstrap] ${instructions}`);
|
|
1372
1059
|
return { ok: true, payload: { commitPush: { action: 'instructed' } } };
|
|
@@ -1392,7 +1079,7 @@ export async function offerCommitPush(state, deps = {}) {
|
|
|
1392
1079
|
cwd,
|
|
1393
1080
|
);
|
|
1394
1081
|
if (!commit.ok) {
|
|
1395
|
-
//
|
|
1082
|
+
// Benign when the wiring is already committed.
|
|
1396
1083
|
Logger.warn(
|
|
1397
1084
|
`[Bootstrap] git commit did not create a commit (already committed?): ${commit.stderr || commit.stdout}`,
|
|
1398
1085
|
);
|
|
@@ -1411,7 +1098,6 @@ export async function offerCommitPush(state, deps = {}) {
|
|
|
1411
1098
|
return { ok: true, payload: { commitPush: { action: 'committed-pushed' } } };
|
|
1412
1099
|
}
|
|
1413
1100
|
|
|
1414
|
-
/** Pipeline driver — threads accumulated state through each phase. */
|
|
1415
1101
|
export async function runPipeline(phases) {
|
|
1416
1102
|
let state = {};
|
|
1417
1103
|
for (const phase of phases) {
|
|
@@ -1423,9 +1109,6 @@ export async function runPipeline(phases) {
|
|
|
1423
1109
|
}
|
|
1424
1110
|
|
|
1425
1111
|
export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
1426
|
-
// `deps.phases` lets tests inject a substitute pipeline so the
|
|
1427
|
-
// post-pipeline GitHub-failure detection can be exercised
|
|
1428
|
-
// deterministically without spawning `gh` (Story #3898).
|
|
1429
1112
|
const phases = deps.phases ?? [
|
|
1430
1113
|
() => parseAndValidate(argv),
|
|
1431
1114
|
(s) => prepareContext(s),
|
|
@@ -1442,12 +1125,8 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
1442
1125
|
const result = await runPipeline(phases);
|
|
1443
1126
|
if (!result.ok) return result.exit;
|
|
1444
1127
|
|
|
1445
|
-
// GitHub
|
|
1446
|
-
//
|
|
1447
|
-
// the failure is surfaced, not silently rolled back), but they MUST NOT
|
|
1448
|
-
// exit 0. `executeGithubBootstrap` records `report.github.error` instead
|
|
1449
|
-
// of throwing; detect it here and exit non-zero with a distinct final
|
|
1450
|
-
// status line so `mandrel init` and CI see the failure (Story #3898).
|
|
1128
|
+
// A GitHub failure is non-fatal to the pipeline (the ledger still records
|
|
1129
|
+
// what landed) but MUST NOT exit 0.
|
|
1451
1130
|
const githubError = result.state?.report?.github?.error;
|
|
1452
1131
|
if (githubError) {
|
|
1453
1132
|
Logger.error(
|