mandrel 2.0.0 → 2.2.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 +59 -28
- package/.agents/agents/acceptance-critic.md +20 -9
- package/.agents/agents/story-worker.md +45 -48
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +60 -46
- package/.agents/docs/agentrc-reference.json +8 -13
- package/.agents/docs/configuration.md +33 -57
- package/.agents/docs/execution-reference.md +39 -10
- package/.agents/docs/quality-gates.md +17 -19
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +64 -79
- package/.agents/rules/ci-remediation.md +3 -3
- package/.agents/rules/gherkin-standards.md +10 -0
- package/.agents/rules/git-conventions-reference.md +42 -51
- package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
- package/.agents/schemas/agentrc.schema.json +35 -46
- package/.agents/schemas/audit-rules.json +59 -1
- package/.agents/schemas/audit-rules.schema.json +33 -1
- package/.agents/schemas/lifecycle/README.md +1 -2
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
- package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
- package/.agents/schemas/signal-event.schema.json +3 -3
- package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +24 -68
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/bootstrap.js +3 -3
- package/.agents/scripts/check-dead-exports.js +43 -104
- package/.agents/scripts/check-doc-links.js +2 -2
- package/.agents/scripts/check-lifecycle-lint.js +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/deliver-recover.js +122 -0
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +20 -50
- package/.agents/scripts/generate-skills-index.js +17 -1
- package/.agents/scripts/generate-workflows-doc.js +4 -4
- package/.agents/scripts/lib/ITicketingProvider.js +1 -19
- package/.agents/scripts/lib/audit-suite/selector.js +323 -23
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
- package/.agents/scripts/lib/checks/index.js +1 -1
- package/.agents/scripts/lib/checks/loop-health.js +12 -11
- package/.agents/scripts/lib/checks/state.js +17 -248
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
- package/.agents/scripts/lib/cli-args.js +23 -2
- package/.agents/scripts/lib/close-validation/gates.js +13 -13
- package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
- package/.agents/scripts/lib/close-validation/runner.js +13 -21
- package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
- package/.agents/scripts/lib/config/acceptance-eval.js +2 -2
- package/.agents/scripts/lib/config/delivery-routing.js +7 -6
- package/.agents/scripts/lib/config/explain.js +10 -16
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +15 -25
- package/.agents/scripts/lib/config/quality.js +11 -14
- package/.agents/scripts/lib/config/runners.js +8 -21
- package/.agents/scripts/lib/config/temp-paths.js +18 -56
- package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
- package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
- package/.agents/scripts/lib/config-settings-schema.js +48 -22
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/duplicate-search.js +38 -7
- package/.agents/scripts/lib/findings/promote-finding.js +23 -14
- package/.agents/scripts/lib/format-generated-json.js +97 -0
- package/.agents/scripts/lib/framework-version.js +19 -189
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
- package/.agents/scripts/lib/git-utils.js +0 -14
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +0 -15
- package/.agents/scripts/lib/label-taxonomy.js +1 -12
- package/.agents/scripts/lib/observability/active-story-env.js +42 -163
- package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
- package/.agents/scripts/lib/observability/signal-validator.js +4 -4
- package/.agents/scripts/lib/observability/signals-writer.js +6 -82
- package/.agents/scripts/lib/observability/source-classifier.js +2 -2
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
- package/.agents/scripts/lib/orchestration/change-set.js +103 -0
- package/.agents/scripts/lib/orchestration/code-review.js +70 -191
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
- package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
- package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
- package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
- package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
- package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
- package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +4 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
- package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
- package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
- package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
- package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
- package/.agents/scripts/lib/planning-corpus.js +12 -286
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
- package/.agents/scripts/lib/signals/index.js +4 -17
- package/.agents/scripts/lib/signals/read.js +35 -35
- package/.agents/scripts/lib/signals/schema.js +8 -11
- package/.agents/scripts/lib/signals/span-tree.js +7 -7
- package/.agents/scripts/lib/signals/write.js +0 -1
- package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +8 -7
- package/.agents/scripts/lib/story-body/story-body.js +81 -13
- package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/ticket-body-sections.js +0 -14
- package/.agents/scripts/lib/validation-evidence.js +31 -59
- package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/plan-context.js +38 -7
- package/.agents/scripts/plan-critics.js +203 -0
- package/.agents/scripts/plan-persist.js +145 -35
- package/.agents/scripts/plan-run-epilogue.js +83 -38
- package/.agents/scripts/post-structured-comment.js +0 -38
- package/.agents/scripts/pr-watch-with-update.js +43 -22
- package/.agents/scripts/providers/github/compose.js +0 -1
- package/.agents/scripts/providers/github/errors.js +0 -19
- package/.agents/scripts/providers/github/issues.js +1 -11
- package/.agents/scripts/providers/github/mappers.js +5 -0
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -153
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/quality-preview.js +13 -6
- package/.agents/scripts/resolve-stories.js +236 -0
- package/.agents/scripts/run-coverage.js +4 -1
- package/.agents/scripts/run-lint.js +2 -2
- package/.agents/scripts/run-verify.js +31 -2
- package/.agents/scripts/signals-view.js +9 -10
- package/.agents/scripts/single-story-close.js +173 -18
- package/.agents/scripts/single-story-confirm-merge.js +288 -15
- package/.agents/scripts/single-story-init.js +6 -10
- package/.agents/scripts/stories-wave-tick.js +380 -53
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/update-ticket-state.js +8 -50
- package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
- package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
- package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
- package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
- package/.agents/skills/core/scope-triage/SKILL.md +3 -0
- package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
- package/.agents/skills/core/security-and-hardening/reference.md +375 -0
- package/.agents/skills/skills.index.json +2 -12
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
- package/.agents/workflows/audit-architecture.md +3 -4
- package/.agents/workflows/audit-clean-code.md +4 -4
- package/.agents/workflows/audit-documentation.md +4 -5
- package/.agents/workflows/audit-lighthouse.md +8 -0
- package/.agents/workflows/audit-navigability.md +10 -0
- package/.agents/workflows/audit-performance.md +2 -3
- package/.agents/workflows/audit-quality.md +8 -9
- package/.agents/workflows/audit-security.md +1 -2
- package/.agents/workflows/audit-seo.md +10 -0
- package/.agents/workflows/audit-ux-ui.md +7 -0
- package/.agents/workflows/deliver.md +133 -45
- package/.agents/workflows/git-cleanup.md +2 -2
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
- package/.agents/workflows/helpers/code-review.md +14 -12
- package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
- package/.agents/workflows/helpers/deliver-story.md +209 -118
- package/.agents/workflows/helpers/parallel-tooling.md +2 -2
- package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
- package/.agents/workflows/plan.md +239 -19
- package/.agents/workflows/qa-assist.md +6 -6
- package/.agents/workflows/qa-explore.md +3 -3
- package/.agents/workflows/qa-run.md +1 -5
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +62 -0
- package/lib/cli/registry.js +262 -19
- package/lib/cli/sync-agents.js +157 -0
- package/lib/cli/sync-commands.js +115 -6
- package/lib/cli/sync.js +168 -6
- package/lib/cli/update.js +105 -8
- package/lib/cli/version-helpers.js +131 -0
- package/lib/migrations/README.md +7 -5
- package/lib/migrations/index.js +17 -9
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
- package/package.json +2 -2
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -53
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
- package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
- package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
- package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
- package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
- package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
- package/.agents/scripts/resolve-plan-run.js +0 -117
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
|
@@ -36,16 +36,28 @@
|
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
import { parseArgs } from 'node:util';
|
|
39
|
+
import { parseSprintArgs } from './lib/cli-args.js';
|
|
39
40
|
import { runAsCli } from './lib/cli-utils.js';
|
|
40
41
|
import { resolveConfig } from './lib/config-resolver.js';
|
|
42
|
+
import { formatCliError } from './lib/error-redactor.js';
|
|
41
43
|
import { gh as defaultGh } from './lib/gh-exec.js';
|
|
42
44
|
import { getStoryBranch } from './lib/git-utils.js';
|
|
43
45
|
import { Logger } from './lib/Logger.js';
|
|
46
|
+
import { emitTerminalFriction } from './lib/observability/runtime-friction.js';
|
|
47
|
+
import { MERGED_FLIP_FAILED_BLOCK_CLASS } from './lib/orchestration/lifecycle/emit-merge-flip-failed.js';
|
|
44
48
|
import { parsePrNumber } from './lib/orchestration/single-story-close/phases/code-review.js';
|
|
49
|
+
import { runConfirmMergePhase as defaultRunConfirmMergePhase } from './lib/orchestration/single-story-close/phases/confirm-merge.js';
|
|
45
50
|
import { parseCloseOptions } from './lib/orchestration/single-story-close/phases/options.js';
|
|
51
|
+
import { runPostLandTail } from './lib/orchestration/single-story-close/phases/post-land.js';
|
|
52
|
+
import {
|
|
53
|
+
buildTerminalEnvelope,
|
|
54
|
+
emitTerminalEnvelope,
|
|
55
|
+
exitCodeForTerminal,
|
|
56
|
+
NEXT_COMMANDS,
|
|
57
|
+
terminalFromWaitOutcome,
|
|
58
|
+
} from './lib/orchestration/story-deliver-terminal.js';
|
|
46
59
|
import { createProvider } from './lib/provider-factory.js';
|
|
47
60
|
import { confirmStoryMerged } from './lib/single-story/confirm-merge.js';
|
|
48
|
-
import { withConfirmFollowUps } from './lib/single-story/confirm-merge-follow-ups.js';
|
|
49
61
|
|
|
50
62
|
const progress = Logger.createProgress('single-story-confirm-merge', {
|
|
51
63
|
stderr: true,
|
|
@@ -71,6 +83,28 @@ function readPrFlag() {
|
|
|
71
83
|
}
|
|
72
84
|
}
|
|
73
85
|
|
|
86
|
+
/**
|
|
87
|
+
* `--wait`: resume the bounded merge wait rather than probing once.
|
|
88
|
+
*
|
|
89
|
+
* This CLI serves two callers behind one command string. `confirmMerge` wants
|
|
90
|
+
* a fast idempotent flip for a merge that ALREADY happened (an operator-merge
|
|
91
|
+
* flow, or a `merged-flip-failed` retry) and must not stall. `resumeLand`
|
|
92
|
+
* wants to pick up a merge wait the close handed off at its per-invocation
|
|
93
|
+
* bound — that one must actually wait, and must be able to give up.
|
|
94
|
+
*/
|
|
95
|
+
function readWaitFlag() {
|
|
96
|
+
try {
|
|
97
|
+
const { values } = parseArgs({
|
|
98
|
+
args: process.argv.slice(2),
|
|
99
|
+
options: { wait: { type: 'boolean', default: false } },
|
|
100
|
+
strict: false,
|
|
101
|
+
});
|
|
102
|
+
return values.wait === true;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
/**
|
|
75
109
|
* Resolve the PR number for the Story branch when one was not passed on
|
|
76
110
|
* the CLI. Probes `gh pr list --head <branch> --state all` (the merged PR
|
|
@@ -99,11 +133,107 @@ async function resolvePrNumber({ cwd, storyBranch, gh }) {
|
|
|
99
133
|
}
|
|
100
134
|
}
|
|
101
135
|
|
|
102
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Story #4578 — async so the runtime-derived friction emit can be awaited.
|
|
138
|
+
* This CLI is the resume path for a parked worker (`--wait`), so a `pending`
|
|
139
|
+
* terminal here means a bounded wait expired again with the PR still in
|
|
140
|
+
* flight: the exact observable the retro was blind to. The emit is
|
|
141
|
+
* best-effort and cannot throw; awaiting it matters because `runAsCli`
|
|
142
|
+
* exits via `process.exit` the moment `main` resolves.
|
|
143
|
+
*/
|
|
144
|
+
async function logConfirmResult(result, terminal, config) {
|
|
145
|
+
// Human-facing dump stays level-gated; the envelope is the machine
|
|
146
|
+
// contract and must survive AGENT_LOG_LEVEL=silent.
|
|
103
147
|
Logger.info(
|
|
104
148
|
`\n--- CONFIRM MERGE RESULT ---\n${JSON.stringify(result, null, 2)}\n--- END RESULT ---\n`,
|
|
105
149
|
);
|
|
106
|
-
|
|
150
|
+
emitTerminalEnvelope(terminal);
|
|
151
|
+
await emitTerminalFriction({ envelope: terminal, config });
|
|
152
|
+
return { success: terminal.status !== 'failed', result, terminal };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Map a `confirmStoryMerged` envelope onto the shared terminal envelope
|
|
157
|
+
* (Story #4543) so this CLI and the in-close land path report one shape.
|
|
158
|
+
*
|
|
159
|
+
* The three confirm outcomes map cleanly:
|
|
160
|
+
* - `done` / `noop` (already-done) → `landed`. Both mean the merge is on
|
|
161
|
+
* the base branch and the Story is `agent::done`.
|
|
162
|
+
* - `pending` (`pr-open` / `no-pr`) → `pending`. Re-run once the merge
|
|
163
|
+
* lands; nothing is wrong.
|
|
164
|
+
* - `flip-failed` → `blocked` with the shared `merged-flip-failed` class:
|
|
165
|
+
* the merge landed, so this is a label-write fault, and the remedy is
|
|
166
|
+
* re-running this very command (it is idempotent).
|
|
167
|
+
* - `pr-not-merged` (closed without merging) → `blocked`. The PR is gone;
|
|
168
|
+
* a re-run cannot fix it, so it needs a human.
|
|
169
|
+
*/
|
|
170
|
+
function buildConfirmTerminal({
|
|
171
|
+
storyId,
|
|
172
|
+
storyBranch,
|
|
173
|
+
baseBranch,
|
|
174
|
+
prNumber,
|
|
175
|
+
confirmation,
|
|
176
|
+
tail,
|
|
177
|
+
elapsedSeconds,
|
|
178
|
+
}) {
|
|
179
|
+
// `pr-not-merged` means the PR is CLOSED — reporting it as OPEN put a
|
|
180
|
+
// fact in the envelope that the blocked reason directly contradicts.
|
|
181
|
+
const prState = confirmation.merged
|
|
182
|
+
? 'MERGED'
|
|
183
|
+
: confirmation.reason === 'pr-not-merged'
|
|
184
|
+
? 'CLOSED'
|
|
185
|
+
: 'OPEN';
|
|
186
|
+
const pr =
|
|
187
|
+
Number.isInteger(prNumber) && prNumber > 0
|
|
188
|
+
? { number: prNumber, state: prState }
|
|
189
|
+
: null;
|
|
190
|
+
const common = { storyId, storyBranch, baseBranch, pr, elapsedSeconds };
|
|
191
|
+
|
|
192
|
+
if (confirmation.action === 'done' || confirmation.action === 'noop') {
|
|
193
|
+
return buildTerminalEnvelope({
|
|
194
|
+
...common,
|
|
195
|
+
status: 'landed',
|
|
196
|
+
phase: tail ? 'post-land' : 'done',
|
|
197
|
+
tail,
|
|
198
|
+
nextCommand: null,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (confirmation.action === 'flip-failed') {
|
|
202
|
+
return buildTerminalEnvelope({
|
|
203
|
+
...common,
|
|
204
|
+
status: 'blocked',
|
|
205
|
+
phase: 'confirm-merge',
|
|
206
|
+
blocked: {
|
|
207
|
+
blockClass: MERGED_FLIP_FAILED_BLOCK_CLASS,
|
|
208
|
+
reason:
|
|
209
|
+
'merge confirmed but the agent::closing → agent::done label write failed',
|
|
210
|
+
frictionCommentId: null,
|
|
211
|
+
},
|
|
212
|
+
nextCommand: NEXT_COMMANDS.confirmMerge(storyId),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (confirmation.reason === 'pr-not-merged') {
|
|
216
|
+
return buildTerminalEnvelope({
|
|
217
|
+
...common,
|
|
218
|
+
status: 'blocked',
|
|
219
|
+
phase: 'confirm-merge',
|
|
220
|
+
blocked: {
|
|
221
|
+
blockClass: 'api-race-other',
|
|
222
|
+
reason: 'the PR was closed without merging (state=CLOSED)',
|
|
223
|
+
frictionCommentId: null,
|
|
224
|
+
},
|
|
225
|
+
nextCommand: NEXT_COMMANDS.recover(storyId),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return buildTerminalEnvelope({
|
|
229
|
+
...common,
|
|
230
|
+
status: 'pending',
|
|
231
|
+
phase: 'confirm-merge',
|
|
232
|
+
nextCommand:
|
|
233
|
+
confirmation.reason === 'no-pr'
|
|
234
|
+
? NEXT_COMMANDS.recover(storyId)
|
|
235
|
+
: NEXT_COMMANDS.confirmMerge(storyId),
|
|
236
|
+
});
|
|
107
237
|
}
|
|
108
238
|
|
|
109
239
|
async function resolveConfirmPrNumber({ prParam, cwd, storyBranch, gh }) {
|
|
@@ -122,11 +252,13 @@ export async function runConfirmMerge({
|
|
|
122
252
|
storyId: storyIdParam,
|
|
123
253
|
cwd: cwdParam,
|
|
124
254
|
pr: prParam,
|
|
255
|
+
wait: waitParam,
|
|
125
256
|
injectedProvider,
|
|
126
257
|
injectedConfig,
|
|
127
258
|
injectedGh,
|
|
128
259
|
injectedNotify,
|
|
129
260
|
injectedReadPrMergeState,
|
|
261
|
+
runConfirmMergePhaseFn = defaultRunConfirmMergePhase,
|
|
130
262
|
} = {}) {
|
|
131
263
|
const { storyId, cwd } = parseCloseOptions({
|
|
132
264
|
storyIdParam,
|
|
@@ -135,14 +267,17 @@ export async function runConfirmMerge({
|
|
|
135
267
|
|
|
136
268
|
if (!storyId) {
|
|
137
269
|
throw new Error(
|
|
138
|
-
'Usage: node single-story-confirm-merge.js --story <STORY_ID> [--pr <n>] [--cwd <main-repo>]',
|
|
270
|
+
'Usage: node single-story-confirm-merge.js --story <STORY_ID> [--pr <n>] [--wait] [--cwd <main-repo>]',
|
|
139
271
|
);
|
|
140
272
|
}
|
|
273
|
+
const wait = waitParam ?? readWaitFlag();
|
|
141
274
|
|
|
275
|
+
const startedAtMs = Date.now();
|
|
142
276
|
const config = injectedConfig || resolveConfig({ cwd });
|
|
143
277
|
const provider = injectedProvider || createProvider(config);
|
|
144
278
|
const gh = injectedGh ?? defaultGh;
|
|
145
279
|
const storyBranch = getStoryBranch(storyId);
|
|
280
|
+
const baseBranch = config.project?.baseBranch ?? 'main';
|
|
146
281
|
|
|
147
282
|
progress('INIT', `Confirming merge for standalone Story #${storyId}...`);
|
|
148
283
|
|
|
@@ -157,13 +292,82 @@ export async function runConfirmMerge({
|
|
|
157
292
|
'CONFIRM',
|
|
158
293
|
`⚠️ No PR found for ${storyBranch}; cannot confirm merge. Story stays at agent::closing.`,
|
|
159
294
|
);
|
|
160
|
-
|
|
295
|
+
const noPr = {
|
|
161
296
|
storyId,
|
|
162
297
|
standalone: true,
|
|
163
298
|
action: 'pending',
|
|
164
299
|
reason: 'no-pr',
|
|
165
300
|
merged: false,
|
|
301
|
+
};
|
|
302
|
+
return await logConfirmResult(
|
|
303
|
+
noPr,
|
|
304
|
+
buildConfirmTerminal({
|
|
305
|
+
storyId,
|
|
306
|
+
storyBranch,
|
|
307
|
+
baseBranch,
|
|
308
|
+
prNumber: null,
|
|
309
|
+
confirmation: noPr,
|
|
310
|
+
tail: null,
|
|
311
|
+
elapsedSeconds: Math.round((Date.now() - startedAtMs) / 1000),
|
|
312
|
+
}),
|
|
313
|
+
config,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// `--wait` (what `NEXT_COMMANDS.resumeLand` passes): resume the merge wait
|
|
318
|
+
// the close handed off at its per-invocation bound, by running the SAME
|
|
319
|
+
// phase the in-close path runs. Without this the resume was a single probe
|
|
320
|
+
// that reported `pending` and exited, so the cumulative `maxBudgetSeconds`
|
|
321
|
+
// give-up — the only thing that ever emits `merge.unlanded` and flips a
|
|
322
|
+
// wedged Story to `agent::blocked` — was reachable ONLY inside the original
|
|
323
|
+
// close invocation. A PR that wedged after the close returned could be
|
|
324
|
+
// resumed forever, always answering `pending`, never escalating to anyone.
|
|
325
|
+
//
|
|
326
|
+
// The phase anchors its cumulative budget at the PR's `createdAt`, so the
|
|
327
|
+
// resume does not restart the clock — exactly what the envelope's
|
|
328
|
+
// `waitBudget` contract already promised.
|
|
329
|
+
if (wait) {
|
|
330
|
+
const waitOutcome = await runConfirmMergePhaseFn({
|
|
331
|
+
cwd,
|
|
332
|
+
storyId,
|
|
333
|
+
storyBranch,
|
|
334
|
+
baseBranch,
|
|
335
|
+
prNumber,
|
|
336
|
+
prUrl: `${storyBranch} PR #${prNumber}`,
|
|
337
|
+
// The close already armed it; this CLI is resuming that wait, not
|
|
338
|
+
// deciding whether to arm.
|
|
339
|
+
autoMergeEnabled: true,
|
|
340
|
+
provider,
|
|
341
|
+
config,
|
|
342
|
+
progress,
|
|
343
|
+
injectedGh: gh,
|
|
344
|
+
injectedNotify,
|
|
345
|
+
readPrMergeStateFn: injectedReadPrMergeState,
|
|
166
346
|
});
|
|
347
|
+
const terminal = terminalFromWaitOutcome({
|
|
348
|
+
waitOutcome,
|
|
349
|
+
storyId,
|
|
350
|
+
storyBranch,
|
|
351
|
+
baseBranch,
|
|
352
|
+
prNumber,
|
|
353
|
+
prUrl: null,
|
|
354
|
+
autoMergeEnabled: true,
|
|
355
|
+
// This CLI runs no close gates, so it reports none — `gates` is
|
|
356
|
+
// "each gate this invocation was responsible for".
|
|
357
|
+
gates: undefined,
|
|
358
|
+
elapsedSeconds: Math.round((Date.now() - startedAtMs) / 1000),
|
|
359
|
+
});
|
|
360
|
+
return await logConfirmResult(
|
|
361
|
+
{
|
|
362
|
+
storyId,
|
|
363
|
+
standalone: true,
|
|
364
|
+
action: waitOutcome.terminal,
|
|
365
|
+
resumed: true,
|
|
366
|
+
tail: waitOutcome.tail ?? null,
|
|
367
|
+
},
|
|
368
|
+
terminal,
|
|
369
|
+
config,
|
|
370
|
+
);
|
|
167
371
|
}
|
|
168
372
|
|
|
169
373
|
const confirmation = await confirmStoryMerged({
|
|
@@ -179,21 +383,90 @@ export async function runConfirmMerge({
|
|
|
179
383
|
readPrMergeStateFn: injectedReadPrMergeState,
|
|
180
384
|
});
|
|
181
385
|
|
|
182
|
-
|
|
183
|
-
|
|
386
|
+
// Story #4543 — reach the SAME shared land tail the in-close path reaches
|
|
387
|
+
// (`phases/post-land.js`), rather than this CLI's own follow-ups-only
|
|
388
|
+
// wrapper. That wrapper was the whole reason the two landing surfaces
|
|
389
|
+
// diverged: it captured follow-ups and nothing else, while the resync and
|
|
390
|
+
// cleanup steps lived in prose the caller had to remember to run.
|
|
391
|
+
//
|
|
392
|
+
// Gated on `merged`, NOT on `action === 'done'`. `done` means "this run
|
|
393
|
+
// flipped the label"; a Story already at `agent::done` returns
|
|
394
|
+
// `action: 'noop', merged: true`, and gating on `done` skipped the tail for
|
|
395
|
+
// exactly that case — the belated-manual-confirm backfill this tail exists
|
|
396
|
+
// to make possible (see `story-follow-ups.js`, which documents the gap).
|
|
397
|
+
// Re-running is safe: every step is idempotent (the follow-ups comment is
|
|
398
|
+
// an upsert, ref cleanup and base fast-forward no-op when already done).
|
|
399
|
+
const tail =
|
|
400
|
+
confirmation.merged === true
|
|
401
|
+
? await runPostLandTail({
|
|
402
|
+
storyId,
|
|
403
|
+
storyBranch,
|
|
404
|
+
baseBranch,
|
|
405
|
+
cwd,
|
|
406
|
+
provider,
|
|
407
|
+
config,
|
|
408
|
+
progress,
|
|
409
|
+
})
|
|
410
|
+
: null;
|
|
411
|
+
|
|
412
|
+
const terminal = buildConfirmTerminal({
|
|
184
413
|
storyId,
|
|
414
|
+
storyBranch,
|
|
415
|
+
baseBranch,
|
|
185
416
|
prNumber,
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
progress,
|
|
417
|
+
confirmation,
|
|
418
|
+
tail,
|
|
419
|
+
elapsedSeconds: Math.round((Date.now() - startedAtMs) / 1000),
|
|
190
420
|
});
|
|
191
|
-
if (
|
|
192
|
-
progress('DONE', `✅
|
|
421
|
+
if (confirmation.action === 'done') {
|
|
422
|
+
progress('DONE', `✅ Story #${storyId} → agent::done (merged).`);
|
|
423
|
+
}
|
|
424
|
+
return await logConfirmResult(
|
|
425
|
+
{ ...confirmation, standalone: true, tail },
|
|
426
|
+
terminal,
|
|
427
|
+
config,
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* CLI entry — mirrors `single-story-close.js`: the exit code comes from the
|
|
433
|
+
* terminal envelope's status, so a caller can tell `pending` (the PR has not
|
|
434
|
+
* merged yet; re-run me) from `landed` without parsing stdout.
|
|
435
|
+
*
|
|
436
|
+
* The catch mirrors close's for the same reason: `confirmStoryMerged`'s PR
|
|
437
|
+
* read is a live `gh` call that throws on a transient API error, and this CLI
|
|
438
|
+
* is a *landing surface* — the one `pending` tells the operator to re-run. If
|
|
439
|
+
* a flaked read exited 1 with no envelope, the surface would be silent exactly
|
|
440
|
+
* where the envelope is the contract. Both landing surfaces emit one envelope
|
|
441
|
+
* or none at all; "none at all" is what Story #4543 removes.
|
|
442
|
+
*/
|
|
443
|
+
async function main() {
|
|
444
|
+
try {
|
|
445
|
+
const outcome = await runConfirmMerge();
|
|
446
|
+
return exitCodeForTerminal(outcome?.terminal ?? { status: 'failed' });
|
|
447
|
+
} catch (err) {
|
|
448
|
+
const storyId = Number(parseSprintArgs().storyId);
|
|
449
|
+
// No story id → a usage error; there is nothing to report an envelope
|
|
450
|
+
// about, so let runAsCli surface it as a plain fatal.
|
|
451
|
+
if (!Number.isInteger(storyId) || storyId <= 0) throw err;
|
|
452
|
+
const terminal = buildTerminalEnvelope({
|
|
453
|
+
storyId,
|
|
454
|
+
status: 'failed',
|
|
455
|
+
phase: 'confirm-merge',
|
|
456
|
+
failure: { reason: String(err?.message ?? err) },
|
|
457
|
+
nextCommand: NEXT_COMMANDS.recover(storyId),
|
|
458
|
+
elapsedSeconds: 0,
|
|
459
|
+
});
|
|
460
|
+
Logger.error(
|
|
461
|
+
`[single-story-confirm-merge] Fatal error: ${formatCliError(err)}`,
|
|
462
|
+
);
|
|
463
|
+
emitTerminalEnvelope(terminal);
|
|
464
|
+
await emitTerminalFriction({ envelope: terminal });
|
|
465
|
+
return exitCodeForTerminal(terminal);
|
|
193
466
|
}
|
|
194
|
-
return logConfirmResult(result);
|
|
195
467
|
}
|
|
196
468
|
|
|
197
|
-
runAsCli(import.meta.url,
|
|
469
|
+
runAsCli(import.meta.url, main, {
|
|
198
470
|
source: 'single-story-confirm-merge',
|
|
471
|
+
propagateExitCode: true,
|
|
199
472
|
});
|
|
@@ -223,12 +223,10 @@ export async function reapMergedStoryBranches({
|
|
|
223
223
|
/**
|
|
224
224
|
* Fetch remote refs, reap merged story branches, and fast-forward the local
|
|
225
225
|
* base branch so new story branches seed from origin's tip. Exported for
|
|
226
|
-
* testing (owns the fast-forward cascade
|
|
227
|
-
* `ensureEpicBranch` in `branch-initializer.js`).
|
|
226
|
+
* testing (owns the fast-forward cascade).
|
|
228
227
|
*
|
|
229
|
-
* Routes the `origin` fetch through `cachedGitFetch` so concurrent
|
|
230
|
-
*
|
|
231
|
-
* stories get via `branch-initializer.js#fetchMainRefs`. Pass `fetchFn` to
|
|
228
|
+
* Routes the `origin` fetch through `cachedGitFetch` so concurrent Story
|
|
229
|
+
* waves share a per-process fetch-coalescing window. Pass `fetchFn` to
|
|
232
230
|
* inject a stub in tests without touching real git.
|
|
233
231
|
*
|
|
234
232
|
* @param {object} opts
|
|
@@ -413,12 +411,10 @@ export async function provisionWorktree({
|
|
|
413
411
|
}
|
|
414
412
|
|
|
415
413
|
try {
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
//
|
|
419
|
-
// standalone-trace branch on CC_EPIC_ID being absent.
|
|
414
|
+
// v2 Stories are standalone — no parent Epic. The helper omits
|
|
415
|
+
// CC_EPIC_ID from env + file; the trace hook keys its standalone-trace
|
|
416
|
+
// branch on CC_EPIC_ID being absent.
|
|
420
417
|
setActiveStoryEnv({
|
|
421
|
-
epicId: null,
|
|
422
418
|
storyId,
|
|
423
419
|
workCwd,
|
|
424
420
|
logger: {
|