mandrel 1.94.0 → 2.0.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 -73
- package/.agents/agents/story-worker.md +12 -13
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +104 -138
- package/.agents/docs/execution-reference.md +17 -20
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +70 -81
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +6 -7
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +54 -214
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/risk-verdict.schema.json +0 -13
- package/.agents/scripts/analyze-execution.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/check-lifecycle-lint.js +6 -9
- package/.agents/scripts/check-prepush-recovery.js +1 -1
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
- package/.agents/scripts/lib/checks/index.js +2 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +16 -7
- package/.agents/scripts/lib/close-validation/gates.js +2 -2
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +45 -29
- package/.agents/scripts/lib/config/explain.js +55 -36
- package/.agents/scripts/lib/config/limits.js +17 -58
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +1 -1
- package/.agents/scripts/lib/config/runners.js +17 -50
- package/.agents/scripts/lib/config/temp-paths.js +19 -14
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +24 -148
- package/.agents/scripts/lib/config-settings-schema-quality.js +8 -14
- package/.agents/scripts/lib/config-settings-schema.js +52 -38
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +2 -2
- package/.agents/scripts/lib/duplicate-search.js +211 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +5 -5
- package/.agents/scripts/lib/framework-version.js +2 -3
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
- package/.agents/scripts/lib/git-utils.js +32 -6
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/label-constants.js +10 -23
- package/.agents/scripts/lib/label-taxonomy.js +9 -43
- package/.agents/scripts/lib/observability/active-story-env.js +1 -1
- package/.agents/scripts/lib/observability/hook-heartbeat.js +20 -52
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +8 -5
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +83 -20
- package/.agents/scripts/lib/orchestration/code-review.js +20 -268
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +13 -13
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
- package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
- package/.agents/scripts/lib/orchestration/ticket-validator.js +2 -7
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
- package/.agents/scripts/lib/planning-corpus.js +16 -11
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/story-adjacency.js +11 -14
- package/.agents/scripts/lib/story-body/story-body.js +124 -70
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
- package/.agents/scripts/lib/validation-evidence.js +1 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +64 -74
- package/.agents/scripts/plan-persist.js +121 -280
- package/.agents/scripts/plan-run-epilogue.js +97 -0
- package/.agents/scripts/providers/github/issues.js +17 -33
- package/.agents/scripts/providers/github/mappers.js +0 -12
- package/.agents/scripts/providers/github/tickets.js +2 -5
- package/.agents/scripts/resolve-plan-run.js +117 -0
- package/.agents/scripts/signals-view.js +24 -19
- package/.agents/scripts/single-story-close.js +11 -14
- package/.agents/scripts/single-story-confirm-merge.js +39 -23
- package/.agents/scripts/single-story-init.js +29 -20
- package/.agents/scripts/stories-wave-tick.js +6 -6
- package/.agents/scripts/story-plan.js +26 -47
- package/.agents/scripts/update-ticket-state.js +6 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +3 -43
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +3 -3
- package/.agents/workflows/audit-clean-code.md +3 -3
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +5 -5
- package/.agents/workflows/audit-lighthouse.md +3 -3
- package/.agents/workflows/audit-navigability.md +3 -2
- package/.agents/workflows/audit-performance.md +3 -3
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +3 -3
- package/.agents/workflows/audit-security.md +3 -3
- package/.agents/workflows/audit-seo.md +3 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +3 -3
- package/.agents/workflows/deliver.md +122 -174
- package/.agents/workflows/git-cleanup.md +3 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +16 -29
- package/.agents/workflows/helpers/code-review.md +70 -193
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
- package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
- package/.agents/workflows/mandrel-update.md +2 -1
- package/.agents/workflows/plan.md +112 -145
- package/.agents/workflows/qa-assist.md +24 -30
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -2
- package/README.md +9 -8
- package/docs/CHANGELOG.md +30 -0
- package/lib/migrations/index.js +6 -5
- package/package.json +2 -2
- package/.agents/agents/retro.md +0 -42
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer.md +0 -33
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/security-engineer.md +0 -111
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
- package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
- package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -852
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
- package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/slice-phase.js +0 -361
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -464
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
- package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
- package/.agents/workflows/helpers/deliver-epic.md +0 -998
- package/.agents/workflows/helpers/deliver-stories.md +0 -450
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -353
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* node:coverage ignore file */
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* retro-run.js — execute the `/deliver` Phase 6 retro from a CLI.
|
|
6
|
-
*
|
|
7
|
-
* Phase 6 of `/deliver` posts the Epic retro by invoking the
|
|
8
|
-
* in-process retro module (`lib/orchestration/retro-runner.js`'s
|
|
9
|
-
* `runRetro`). That module is a library entry point — it has no CLI
|
|
10
|
-
* wrapper and hard-requires both a GitHub `provider` and a lifecycle
|
|
11
|
-
* `bus` (Epic #2646 Story C made `bus` a non-optional input). Without a
|
|
12
|
-
* wrapper the host LLM driving Phase 6 had to hand-improvise a bus, and
|
|
13
|
-
* a bare bus with no `LedgerWriter` registered means `retro.start` /
|
|
14
|
-
* `retro.end` never reach the Epic-scoped `lifecycle.ndjson` ledger.
|
|
15
|
-
*
|
|
16
|
-
* This CLI mirrors `epic-deliver-note-intervention.js`: it resolves the
|
|
17
|
-
* config and provider, constructs a lifecycle bus with a `LedgerWriter`
|
|
18
|
-
* bound to the Epic's temp tree, calls `runRetro`, and prints the result
|
|
19
|
-
* envelope. `--full-retro` forces the six-section retro regardless of
|
|
20
|
-
* manifest cleanliness (maps to `runRetro`'s `forceFull`).
|
|
21
|
-
*
|
|
22
|
-
* Usage:
|
|
23
|
-
* node .agents/scripts/retro-run.js --epic <epicId> [--full-retro]
|
|
24
|
-
*
|
|
25
|
-
* Output: a single JSON envelope
|
|
26
|
-
* `{ epicId, posted, compact, ledgerPath, commentId? }`.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
import { parseArgs } from 'node:util';
|
|
30
|
-
|
|
31
|
-
import { runAsCli } from './lib/cli-utils.js';
|
|
32
|
-
import { tempRootFrom } from './lib/config/temp-paths.js';
|
|
33
|
-
import { resolveConfig } from './lib/config-resolver.js';
|
|
34
|
-
import { Logger } from './lib/Logger.js';
|
|
35
|
-
import { createBus } from './lib/orchestration/lifecycle/bus.js';
|
|
36
|
-
import { createLedgerWriter } from './lib/orchestration/lifecycle/ledger-writer.js';
|
|
37
|
-
import { runRetro } from './lib/orchestration/retro-runner.js';
|
|
38
|
-
import { createProvider } from './lib/provider-factory.js';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Pure: resolve the framework/consumer repo slugs (`"<owner>/<repo>"`)
|
|
42
|
-
* from a resolved config's `github` block, for threading into the retro's
|
|
43
|
-
* routed-proposal composer.
|
|
44
|
-
*
|
|
45
|
-
* - `consumerRepo` is the project's OWN repo (`github.owner/github.repo`).
|
|
46
|
-
* It has **no** silent fallback: when `github.owner` / `github.repo` are
|
|
47
|
-
* absent the slug is `''`, which `gatherRetroSignals` treats as "disable
|
|
48
|
-
* the consumer pane loudly" rather than routing consumer-tagged friction
|
|
49
|
-
* at the framework mirror (Story #4417).
|
|
50
|
-
* - `frameworkRepo` is the distinct framework mirror
|
|
51
|
-
* (`github.frameworkRepo.{owner,repo}`) when configured, otherwise `''`
|
|
52
|
-
* — `gatherRetroSignals` then falls back to its `DEFAULT_FRAMEWORK_REPO`
|
|
53
|
-
* constant (a stable, known default is legitimate for the framework).
|
|
54
|
-
*
|
|
55
|
-
* Exported for tests.
|
|
56
|
-
*
|
|
57
|
-
* @param {object} [config]
|
|
58
|
-
* @returns {{ frameworkRepo: string, consumerRepo: string }}
|
|
59
|
-
*/
|
|
60
|
-
export function resolveRetroRepos(config) {
|
|
61
|
-
const gh = config?.github ?? {};
|
|
62
|
-
const consumerRepo =
|
|
63
|
-
typeof gh.owner === 'string' &&
|
|
64
|
-
gh.owner.length > 0 &&
|
|
65
|
-
typeof gh.repo === 'string' &&
|
|
66
|
-
gh.repo.length > 0
|
|
67
|
-
? `${gh.owner}/${gh.repo}`
|
|
68
|
-
: '';
|
|
69
|
-
const fw = gh.frameworkRepo ?? {};
|
|
70
|
-
const frameworkRepo =
|
|
71
|
-
typeof fw.owner === 'string' &&
|
|
72
|
-
fw.owner.length > 0 &&
|
|
73
|
-
typeof fw.repo === 'string' &&
|
|
74
|
-
fw.repo.length > 0
|
|
75
|
-
? `${fw.owner}/${fw.repo}`
|
|
76
|
-
: '';
|
|
77
|
-
return { frameworkRepo, consumerRepo };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const HELP = `Usage: node .agents/scripts/retro-run.js --epic <epicId> [--full-retro]
|
|
81
|
-
|
|
82
|
-
Composes and posts the Epic retro structured comment for Epic #<epicId>,
|
|
83
|
-
wiring a lifecycle bus + LedgerWriter so the run's \`retro.start\` /
|
|
84
|
-
\`retro.end\` boundaries land in temp/epic-<epicId>/lifecycle.ndjson.
|
|
85
|
-
|
|
86
|
-
--epic <epicId> Epic to run the retro for (required, positive integer).
|
|
87
|
-
--full-retro Force the full six-section retro regardless of
|
|
88
|
-
manifest cleanliness (maps to runRetro forceFull).
|
|
89
|
-
`;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Pure: parse argv into the normalized option bag. Exported for tests.
|
|
93
|
-
*
|
|
94
|
-
* @param {string[]} argv
|
|
95
|
-
* @returns {{ epicId: number|null, fullRetro: boolean, help: boolean }}
|
|
96
|
-
*/
|
|
97
|
-
export function parseRetroRunArgs(argv) {
|
|
98
|
-
const { values } = parseArgs({
|
|
99
|
-
args: argv,
|
|
100
|
-
options: {
|
|
101
|
-
epic: { type: 'string' },
|
|
102
|
-
'full-retro': { type: 'boolean' },
|
|
103
|
-
help: { type: 'boolean', short: 'h' },
|
|
104
|
-
},
|
|
105
|
-
strict: false,
|
|
106
|
-
});
|
|
107
|
-
const epicId = Number.parseInt(values.epic ?? '', 10);
|
|
108
|
-
return {
|
|
109
|
-
epicId: Number.isNaN(epicId) || epicId <= 0 ? null : epicId,
|
|
110
|
-
fullRetro: values['full-retro'] === true,
|
|
111
|
-
help: values.help === true,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Runner-shaped entry point. DI-friendly so tests can stub the provider,
|
|
117
|
-
* the bus, the ledger writer, and `runRetro` without touching disk or the
|
|
118
|
-
* GitHub API.
|
|
119
|
-
*
|
|
120
|
-
* Wires the lifecycle bus and registers a `LedgerWriter` bound to the
|
|
121
|
-
* Epic's temp tree before invoking `runRetro`, so the run's
|
|
122
|
-
* `retro.start` / `retro.end` boundaries persist to
|
|
123
|
-
* `temp/epic-<epicId>/lifecycle.ndjson` rather than evaporating into a
|
|
124
|
-
* bare bus.
|
|
125
|
-
*
|
|
126
|
-
* @param {{
|
|
127
|
-
* epicId: number,
|
|
128
|
-
* fullRetro?: boolean,
|
|
129
|
-
* injectedConfig?: object,
|
|
130
|
-
* injectedProvider?: object,
|
|
131
|
-
* busFactory?: () => object,
|
|
132
|
-
* ledgerFactory?: (deps: { epicId: number, tempRoot: string }) => { register: Function, ledgerPath?: string },
|
|
133
|
-
* runRetroFn?: typeof runRetro,
|
|
134
|
-
* logger?: { info?: Function, warn?: Function },
|
|
135
|
-
* }} args
|
|
136
|
-
* @returns {Promise<{
|
|
137
|
-
* epicId: number,
|
|
138
|
-
* posted: boolean,
|
|
139
|
-
* compact: boolean,
|
|
140
|
-
* ledgerPath: string|null,
|
|
141
|
-
* commentId?: number,
|
|
142
|
-
* }>}
|
|
143
|
-
*/
|
|
144
|
-
export async function runRetroCli({
|
|
145
|
-
epicId,
|
|
146
|
-
fullRetro = false,
|
|
147
|
-
injectedConfig,
|
|
148
|
-
injectedProvider,
|
|
149
|
-
busFactory,
|
|
150
|
-
ledgerFactory,
|
|
151
|
-
runRetroFn = runRetro,
|
|
152
|
-
logger,
|
|
153
|
-
} = {}) {
|
|
154
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
155
|
-
throw new TypeError('runRetroCli: epicId must be a positive integer');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const config = injectedConfig ?? resolveConfig();
|
|
159
|
-
const provider = injectedProvider ?? createProvider(config);
|
|
160
|
-
const bus = busFactory ? busFactory() : createBus();
|
|
161
|
-
|
|
162
|
-
const tempRoot = tempRootFrom(config);
|
|
163
|
-
const ledger = ledgerFactory
|
|
164
|
-
? ledgerFactory({ epicId, tempRoot })
|
|
165
|
-
: createLedgerWriter({ epicId, tempRoot });
|
|
166
|
-
ledger.register(bus);
|
|
167
|
-
|
|
168
|
-
// Story #4417 — thread the framework/consumer repo slugs resolved from
|
|
169
|
-
// `config.github` into the retro so the routed-proposal composer files
|
|
170
|
-
// consumer-tagged friction at the project's own repo (not the framework
|
|
171
|
-
// mirror), and disables the consumer pane loudly when unresolved.
|
|
172
|
-
const { frameworkRepo, consumerRepo } = resolveRetroRepos(config);
|
|
173
|
-
|
|
174
|
-
const result = await runRetroFn({
|
|
175
|
-
epicId,
|
|
176
|
-
provider,
|
|
177
|
-
bus,
|
|
178
|
-
forceFull: fullRetro,
|
|
179
|
-
frameworkRepo,
|
|
180
|
-
consumerRepo,
|
|
181
|
-
// Story #4418 — thread the resolved config so the retro auto-filer can
|
|
182
|
-
// read the `delivery.feedbackLoop.retroProposals` toggle.
|
|
183
|
-
config,
|
|
184
|
-
logger,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
const envelope = {
|
|
188
|
-
epicId,
|
|
189
|
-
posted: result?.posted === true,
|
|
190
|
-
compact: result?.compact === true,
|
|
191
|
-
ledgerPath: ledger.ledgerPath ?? null,
|
|
192
|
-
};
|
|
193
|
-
if (Number.isInteger(result?.commentId)) {
|
|
194
|
-
envelope.commentId = result.commentId;
|
|
195
|
-
}
|
|
196
|
-
return envelope;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async function main() {
|
|
200
|
-
const args = parseRetroRunArgs(process.argv.slice(2));
|
|
201
|
-
if (args.help) {
|
|
202
|
-
Logger.info(HELP);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
if (args.epicId === null) {
|
|
206
|
-
Logger.error('[retro-run] ERROR: --epic <epicId> is required.');
|
|
207
|
-
Logger.error(HELP);
|
|
208
|
-
process.exit(2);
|
|
209
|
-
}
|
|
210
|
-
const out = await runRetroCli({
|
|
211
|
-
epicId: args.epicId,
|
|
212
|
-
fullRetro: args.fullRetro,
|
|
213
|
-
logger: Logger,
|
|
214
|
-
});
|
|
215
|
-
Logger.info(JSON.stringify(out, null, 2));
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
runAsCli(import.meta.url, main, { source: 'retro-run' });
|
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* slice-phase.js — single-delivery slice lifecycle + checkpoint writer
|
|
5
|
-
* (Epic #4475, M4-B). The single-delivery analogue of `story-phase.js`.
|
|
6
|
-
*
|
|
7
|
-
* A single-delivery run collapses the whole Epic into one long guarded session
|
|
8
|
-
* walking the Epic body's `## Delivery Slicing` table on `epic/<id>` (there is
|
|
9
|
-
* no per-Story fan-out, so no `story.heartbeat`). The `deliver-epic-single.md`
|
|
10
|
-
* executor calls this CLI at each slice boundary so the run has:
|
|
11
|
-
*
|
|
12
|
-
* 1. A ledger signal — one `slice.start` / `slice.end` / `slice.heartbeat`
|
|
13
|
-
* record appended to `temp/epic-<epicId>/lifecycle.ndjson` (via the M4-A
|
|
14
|
-
* `emit-slice-lifecycle.js` emitters). `slice.heartbeat` is the
|
|
15
|
-
* forward-progress signal the `/deliver` §2e Idle Watchdog reads to tell
|
|
16
|
-
* the one long session apart from a dead one; `slice.start`/`.end` bracket
|
|
17
|
-
* each slice.
|
|
18
|
-
* 2. A durable checkpoint flip — when `--record <status>` is passed (the
|
|
19
|
-
* executor passes `--record done` after a slice commits to `epic/<id>`),
|
|
20
|
-
* `slices[sliceId].status` is spliced `pending → done` on the
|
|
21
|
-
* `epic-run-state` checkpoint so a resumed run SKIPS the already-landed
|
|
22
|
-
* slice (the branch already carries the work — no re-pay).
|
|
23
|
-
*
|
|
24
|
-
* The ledger emit is best-effort: a missing/unreachable ledger or a schema
|
|
25
|
-
* hiccup is logged and swallowed — the checkpoint is the source of truth, the
|
|
26
|
-
* ledger record is observability (mirrors `story-phase.js`). The checkpoint
|
|
27
|
-
* flip (when requested) is authoritative and its failure propagates.
|
|
28
|
-
*
|
|
29
|
-
* CLI:
|
|
30
|
-
* --epic <id> Epic ID (required).
|
|
31
|
-
* --slice <sliceId> Slice-map key, e.g. slice-1 (required).
|
|
32
|
-
* --event <start|end|heartbeat> Lifecycle event to emit (required).
|
|
33
|
-
* --outcome <done|blocked|failed|skipped>
|
|
34
|
-
* Required for --event end.
|
|
35
|
-
* --record <pending|done|blocked|failed>
|
|
36
|
-
* Flip slices[sliceId].status on the
|
|
37
|
-
* checkpoint. Omit to leave it untouched.
|
|
38
|
-
* --slice-index <n> Zero-based table position (metadata).
|
|
39
|
-
* --title <str> Human-readable slice label.
|
|
40
|
-
* --phase <init|implementing|closing|blocked|done>
|
|
41
|
-
* Heartbeat phase (default implementing).
|
|
42
|
-
* --duration-ms <n> Slice duration for --event end.
|
|
43
|
-
* --work-cwd <path> Single worktree root for the
|
|
44
|
-
* active-slice env export (--event
|
|
45
|
-
* start). Defaults to the process cwd.
|
|
46
|
-
* --no-emit Suppress the ledger emit (tests).
|
|
47
|
-
*
|
|
48
|
-
* Stdout: a single JSON envelope
|
|
49
|
-
* { ok, epicId, sliceId, event, emitted, ledgerPath, recorded, status }
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
import { parseArgs } from 'node:util';
|
|
53
|
-
|
|
54
|
-
import { runAsCli } from './lib/cli-utils.js';
|
|
55
|
-
import { resolveConfig } from './lib/config-resolver.js';
|
|
56
|
-
import { Logger } from './lib/Logger.js';
|
|
57
|
-
import { setActiveSliceEnv } from './lib/observability/active-story-env.js';
|
|
58
|
-
import { recordSliceStatus } from './lib/orchestration/epic-run-state-store.js';
|
|
59
|
-
import {
|
|
60
|
-
emitSliceEnd,
|
|
61
|
-
emitSliceHeartbeat,
|
|
62
|
-
emitSliceStart,
|
|
63
|
-
} from './lib/orchestration/lifecycle/emit-slice-lifecycle.js';
|
|
64
|
-
import { normalizeOperatorHandle } from './lib/orchestration/ticket-lease.js';
|
|
65
|
-
import { createProvider } from './lib/provider-factory.js';
|
|
66
|
-
|
|
67
|
-
const VALID_EVENTS = new Set(['start', 'end', 'heartbeat']);
|
|
68
|
-
const VALID_OUTCOMES = new Set(['done', 'blocked', 'failed', 'skipped']);
|
|
69
|
-
const VALID_HEARTBEAT_PHASES = new Set([
|
|
70
|
-
'init',
|
|
71
|
-
'implementing',
|
|
72
|
-
'closing',
|
|
73
|
-
'blocked',
|
|
74
|
-
'done',
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
const HELP = `Usage: node .agents/scripts/slice-phase.js \\
|
|
78
|
-
--epic <id> --slice <sliceId> --event <start|end|heartbeat> \\
|
|
79
|
-
[--outcome <done|blocked|failed|skipped>] [--record <pending|done|blocked|failed>] \\
|
|
80
|
-
[--slice-index <n>] [--title <str>] [--phase <phase>] [--duration-ms <n>] [--no-emit]
|
|
81
|
-
|
|
82
|
-
Emits one slice.start / slice.end / slice.heartbeat record to the Epic's
|
|
83
|
-
lifecycle ledger and, when --record is supplied, flips slices[sliceId].status
|
|
84
|
-
on the epic-run-state checkpoint (the M4-B single-delivery slice walk uses
|
|
85
|
-
--record done after each slice commits to epic/<id> so resume skips it).
|
|
86
|
-
`;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Best-effort ledger emit for one slice boundary. Dispatches to the matching
|
|
90
|
-
* `emit-slice-lifecycle.js` emitter and swallows any append failure (logged,
|
|
91
|
-
* never fatal) — the checkpoint is state, the ledger is observability. A
|
|
92
|
-
* programming error (bad event / missing outcome) still throws so it surfaces
|
|
93
|
-
* in tests.
|
|
94
|
-
*
|
|
95
|
-
* @param {object} args
|
|
96
|
-
* @returns {{ emitted: boolean, ledgerPath: string|null }}
|
|
97
|
-
*/
|
|
98
|
-
function emitSliceEventBestEffort({
|
|
99
|
-
event,
|
|
100
|
-
epicId,
|
|
101
|
-
sliceId,
|
|
102
|
-
sliceIndex,
|
|
103
|
-
title,
|
|
104
|
-
outcome,
|
|
105
|
-
durationMs,
|
|
106
|
-
phase,
|
|
107
|
-
operator,
|
|
108
|
-
config,
|
|
109
|
-
ledgerPath,
|
|
110
|
-
timestamp,
|
|
111
|
-
}) {
|
|
112
|
-
try {
|
|
113
|
-
let res;
|
|
114
|
-
if (event === 'start') {
|
|
115
|
-
res = emitSliceStart({
|
|
116
|
-
epicId,
|
|
117
|
-
sliceId,
|
|
118
|
-
...(Number.isInteger(sliceIndex) ? { sliceIndex } : {}),
|
|
119
|
-
...(typeof title === 'string' ? { title } : {}),
|
|
120
|
-
timestamp,
|
|
121
|
-
config: config ?? undefined,
|
|
122
|
-
ledgerPath,
|
|
123
|
-
});
|
|
124
|
-
} else if (event === 'end') {
|
|
125
|
-
res = emitSliceEnd({
|
|
126
|
-
epicId,
|
|
127
|
-
sliceId,
|
|
128
|
-
outcome,
|
|
129
|
-
...(Number.isInteger(sliceIndex) ? { sliceIndex } : {}),
|
|
130
|
-
...(Number.isInteger(durationMs) ? { durationMs } : {}),
|
|
131
|
-
timestamp,
|
|
132
|
-
config: config ?? undefined,
|
|
133
|
-
ledgerPath,
|
|
134
|
-
});
|
|
135
|
-
} else {
|
|
136
|
-
res = emitSliceHeartbeat({
|
|
137
|
-
epicId,
|
|
138
|
-
sliceId,
|
|
139
|
-
phase,
|
|
140
|
-
timestamp,
|
|
141
|
-
...(operator !== null && operator !== undefined ? { operator } : {}),
|
|
142
|
-
config: config ?? undefined,
|
|
143
|
-
ledgerPath,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
return { emitted: true, ledgerPath: res.ledgerPath };
|
|
147
|
-
} catch (err) {
|
|
148
|
-
Logger.warn(
|
|
149
|
-
`[slice-phase] slice.${event} emit failed (continuing): ${err.message}`,
|
|
150
|
-
);
|
|
151
|
-
return { emitted: false, ledgerPath: null };
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* End-to-end slice-phase writer. DI-friendly: tests pass `provider`, override
|
|
157
|
-
* the ledger path, and skip the emit as needed.
|
|
158
|
-
*
|
|
159
|
-
* @param {{
|
|
160
|
-
* epicId: number,
|
|
161
|
-
* sliceId: string,
|
|
162
|
-
* event: string,
|
|
163
|
-
* outcome?: string,
|
|
164
|
-
* record?: string,
|
|
165
|
-
* sliceIndex?: number,
|
|
166
|
-
* title?: string,
|
|
167
|
-
* phase?: string,
|
|
168
|
-
* durationMs?: number,
|
|
169
|
-
* noEmit?: boolean,
|
|
170
|
-
* provider?: object,
|
|
171
|
-
* config?: object,
|
|
172
|
-
* ledgerPath?: string,
|
|
173
|
-
* now?: Date,
|
|
174
|
-
* }} args
|
|
175
|
-
*/
|
|
176
|
-
export async function runSlicePhase(args) {
|
|
177
|
-
const {
|
|
178
|
-
epicId,
|
|
179
|
-
sliceId,
|
|
180
|
-
event,
|
|
181
|
-
outcome,
|
|
182
|
-
record,
|
|
183
|
-
sliceIndex,
|
|
184
|
-
title,
|
|
185
|
-
phase = 'implementing',
|
|
186
|
-
durationMs,
|
|
187
|
-
noEmit = false,
|
|
188
|
-
provider: providerOverride,
|
|
189
|
-
config: configOverride,
|
|
190
|
-
ledgerPath: ledgerPathOverride,
|
|
191
|
-
workCwd: workCwdOverride,
|
|
192
|
-
now = new Date(),
|
|
193
|
-
} = args ?? {};
|
|
194
|
-
|
|
195
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
196
|
-
throw new Error('runSlicePhase: --epic must be a positive integer');
|
|
197
|
-
}
|
|
198
|
-
if (typeof sliceId !== 'string' || sliceId.length === 0) {
|
|
199
|
-
throw new Error('runSlicePhase: --slice must be a non-empty string');
|
|
200
|
-
}
|
|
201
|
-
if (!VALID_EVENTS.has(event)) {
|
|
202
|
-
throw new Error(
|
|
203
|
-
`runSlicePhase: --event "${event}" must be one of: ${[...VALID_EVENTS].join(', ')}`,
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
if (event === 'end' && !VALID_OUTCOMES.has(outcome)) {
|
|
207
|
-
throw new Error(
|
|
208
|
-
`runSlicePhase: --event end requires --outcome one of: ${[...VALID_OUTCOMES].join(', ')}`,
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
if (event === 'heartbeat' && !VALID_HEARTBEAT_PHASES.has(phase)) {
|
|
212
|
-
throw new Error(
|
|
213
|
-
`runSlicePhase: --phase "${phase}" must be one of: ${[...VALID_HEARTBEAT_PHASES].join(', ')}`,
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const config = configOverride ?? (providerOverride ? null : resolveConfig());
|
|
218
|
-
const operator = normalizeOperatorHandle(config?.github?.operatorHandle);
|
|
219
|
-
const timestamp = now.toISOString();
|
|
220
|
-
|
|
221
|
-
// Epic #4476 (M5): at each slice boundary START, export the active-slice
|
|
222
|
-
// env (`CC_EPIC_ID` / `CC_SLICE_ID` / `CC_OPERATOR`) into the single
|
|
223
|
-
// worktree's `.env.local` so the PostToolUse hook emits `slice.heartbeat`
|
|
224
|
-
// off the token stream for the duration of this slice — no per-step
|
|
225
|
-
// heartbeat CLI turn. Best-effort: a write failure never blocks the slice.
|
|
226
|
-
// Gated on an explicit `workCwd` (the CLI supplies `process.cwd()`); a bare
|
|
227
|
-
// `runSlicePhase` call in a unit test passes none and never touches the env
|
|
228
|
-
// or writes a `.env.local`.
|
|
229
|
-
let sliceEnvWritten = false;
|
|
230
|
-
if (
|
|
231
|
-
event === 'start' &&
|
|
232
|
-
typeof workCwdOverride === 'string' &&
|
|
233
|
-
workCwdOverride.length > 0
|
|
234
|
-
) {
|
|
235
|
-
try {
|
|
236
|
-
const res = setActiveSliceEnv({
|
|
237
|
-
epicId,
|
|
238
|
-
sliceId,
|
|
239
|
-
...(operator ? { operator } : {}),
|
|
240
|
-
workCwd: workCwdOverride,
|
|
241
|
-
logger: Logger,
|
|
242
|
-
});
|
|
243
|
-
sliceEnvWritten = res.fileWritten;
|
|
244
|
-
} catch (err) {
|
|
245
|
-
Logger.warn(
|
|
246
|
-
`[slice-phase] active-slice env export failed (continuing): ${err.message}`,
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
let emitted = false;
|
|
252
|
-
let ledgerPath = null;
|
|
253
|
-
if (!noEmit) {
|
|
254
|
-
({ emitted, ledgerPath } = emitSliceEventBestEffort({
|
|
255
|
-
event,
|
|
256
|
-
epicId,
|
|
257
|
-
sliceId,
|
|
258
|
-
sliceIndex,
|
|
259
|
-
title,
|
|
260
|
-
outcome,
|
|
261
|
-
durationMs,
|
|
262
|
-
phase,
|
|
263
|
-
operator,
|
|
264
|
-
config,
|
|
265
|
-
ledgerPath: ledgerPathOverride,
|
|
266
|
-
timestamp,
|
|
267
|
-
}));
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Authoritative checkpoint flip — only when --record is supplied. Unlike the
|
|
271
|
-
// best-effort emit, a record failure propagates (the slice-map marker is the
|
|
272
|
-
// resume contract; a silent failure would re-pay the slice on resume).
|
|
273
|
-
let recorded = false;
|
|
274
|
-
let status = null;
|
|
275
|
-
if (typeof record === 'string' && record.length > 0) {
|
|
276
|
-
const provider =
|
|
277
|
-
providerOverride ?? createProvider(config ?? resolveConfig());
|
|
278
|
-
await recordSliceStatus({
|
|
279
|
-
provider,
|
|
280
|
-
epicId,
|
|
281
|
-
sliceId,
|
|
282
|
-
status: record,
|
|
283
|
-
...(typeof title === 'string' && title ? { title } : {}),
|
|
284
|
-
});
|
|
285
|
-
recorded = true;
|
|
286
|
-
status = record;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
ok: true,
|
|
291
|
-
epicId,
|
|
292
|
-
sliceId,
|
|
293
|
-
event,
|
|
294
|
-
emitted,
|
|
295
|
-
ledgerPath,
|
|
296
|
-
recorded,
|
|
297
|
-
status,
|
|
298
|
-
sliceEnvWritten,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export function parseArgv(argv) {
|
|
303
|
-
const { values } = parseArgs({
|
|
304
|
-
args: argv,
|
|
305
|
-
options: {
|
|
306
|
-
epic: { type: 'string' },
|
|
307
|
-
slice: { type: 'string' },
|
|
308
|
-
event: { type: 'string' },
|
|
309
|
-
outcome: { type: 'string' },
|
|
310
|
-
record: { type: 'string' },
|
|
311
|
-
'slice-index': { type: 'string' },
|
|
312
|
-
title: { type: 'string' },
|
|
313
|
-
phase: { type: 'string' },
|
|
314
|
-
'duration-ms': { type: 'string' },
|
|
315
|
-
'work-cwd': { type: 'string' },
|
|
316
|
-
'no-emit': { type: 'boolean' },
|
|
317
|
-
help: { type: 'boolean' },
|
|
318
|
-
},
|
|
319
|
-
strict: false,
|
|
320
|
-
});
|
|
321
|
-
const parsed = {
|
|
322
|
-
help: Boolean(values.help),
|
|
323
|
-
epicId: Number.parseInt(values.epic ?? '', 10),
|
|
324
|
-
sliceId: values.slice,
|
|
325
|
-
event: values.event,
|
|
326
|
-
noEmit: Boolean(values['no-emit']),
|
|
327
|
-
};
|
|
328
|
-
if (typeof values.outcome === 'string') parsed.outcome = values.outcome;
|
|
329
|
-
if (typeof values.record === 'string') parsed.record = values.record;
|
|
330
|
-
if (typeof values.title === 'string') parsed.title = values.title;
|
|
331
|
-
if (typeof values.phase === 'string') parsed.phase = values.phase;
|
|
332
|
-
if (typeof values['work-cwd'] === 'string' && values['work-cwd']) {
|
|
333
|
-
parsed.workCwd = values['work-cwd'];
|
|
334
|
-
}
|
|
335
|
-
if (values['slice-index'] !== undefined) {
|
|
336
|
-
parsed.sliceIndex = Number.parseInt(values['slice-index'], 10);
|
|
337
|
-
}
|
|
338
|
-
if (values['duration-ms'] !== undefined) {
|
|
339
|
-
parsed.durationMs = Number.parseInt(values['duration-ms'], 10);
|
|
340
|
-
}
|
|
341
|
-
return parsed;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
export async function main(argv = process.argv.slice(2)) {
|
|
345
|
-
const parsed = parseArgv(argv);
|
|
346
|
-
if (parsed.help) {
|
|
347
|
-
process.stdout.write(HELP);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
// The CLI runs from inside the single worktree (the executor `cd`s there),
|
|
351
|
-
// so default the active-slice env target to the process cwd unless an
|
|
352
|
-
// explicit --work-cwd overrides it. runSlicePhase only writes the
|
|
353
|
-
// `.env.local` for --event start.
|
|
354
|
-
const envelope = await runSlicePhase({
|
|
355
|
-
...parsed,
|
|
356
|
-
workCwd: parsed.workCwd ?? process.cwd(),
|
|
357
|
-
});
|
|
358
|
-
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
runAsCli(import.meta.url, main, { source: 'slice-phase' });
|