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,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* dispatch-manifest-render.js — pure helper that renders the
|
|
3
|
-
* `dispatch-manifest` structured-comment body posted on an Epic.
|
|
4
|
-
*
|
|
5
|
-
* Extracted from `manifest-renderer.js::postManifestEpicComment` so the
|
|
6
|
-
* wave-runner's manifest refresh hop can render the same Markdown in
|
|
7
|
-
* process without spawning `dispatcher.js --dry-run`.
|
|
8
|
-
*
|
|
9
|
-
* No top-level side effects — safe to import from tests without
|
|
10
|
-
* triggering GitHub I/O.
|
|
11
|
-
*
|
|
12
|
-
* Story #4157 — each projected story's `wave` is a **render-time
|
|
13
|
-
* dependency depth** derived from the manifest's `dependsOn` edges via the
|
|
14
|
-
* shared `deriveStoryDepths` lens (`manifest-render-waves.js`, built on
|
|
15
|
-
* `assignLayers`), not the persisted `earliestWave`. Scheduling no longer
|
|
16
|
-
* stamps a wave field onto the run checkpoint (Epic #4151 / Story #4155),
|
|
17
|
-
* so the rollup re-derives depth from the dependency graph at render time.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { deriveStoryDepths } from './manifest-render-waves.js';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Pure: project a full dispatch manifest into the `{ stories }` shape
|
|
24
|
-
* `renderManifest` accepts. Returns the canonical, non-ungrouped story
|
|
25
|
-
* rows used by the Epic-level dispatch-manifest comment.
|
|
26
|
-
*
|
|
27
|
-
* The `wave` field is the render-time dependency depth (Story #4157):
|
|
28
|
-
* `deriveStoryDepths` runs `assignLayers` over the entries' `dependsOn`
|
|
29
|
-
* edges, so a Story with no in-set dependency is wave 0 and a dependent
|
|
30
|
-
* sits one layer deeper than its deepest dependency. Entries the lens
|
|
31
|
-
* cannot place (e.g. a non-integer storyId that survives the sentinel
|
|
32
|
-
* filter) fall back to `-1`.
|
|
33
|
-
*
|
|
34
|
-
* @param {object} manifest
|
|
35
|
-
* @returns {{ storyId: number|string, wave: number, title: string }[]}
|
|
36
|
-
*/
|
|
37
|
-
export function projectStoriesFromManifest(manifest) {
|
|
38
|
-
const storyManifest = manifest?.storyManifest ?? [];
|
|
39
|
-
const depths = deriveStoryDepths(storyManifest);
|
|
40
|
-
return storyManifest
|
|
41
|
-
.filter((s) => s && s.storyId !== '__ungrouped__')
|
|
42
|
-
.map((s) => ({
|
|
43
|
-
storyId: s.storyId,
|
|
44
|
-
wave: depths.get(s.storyId) ?? -1,
|
|
45
|
-
title: s.storyTitle ?? s.storySlug ?? '',
|
|
46
|
-
}));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Pure: count distinct, non-(-1) wave indexes across `stories`.
|
|
51
|
-
*
|
|
52
|
-
* @param {{ wave: number }[]} stories
|
|
53
|
-
*/
|
|
54
|
-
export function countWaves(stories) {
|
|
55
|
-
const set = new Set();
|
|
56
|
-
for (const s of stories ?? []) {
|
|
57
|
-
if (s && typeof s.wave === 'number' && s.wave !== -1) set.add(s.wave);
|
|
58
|
-
}
|
|
59
|
-
return set.size;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Pure: render the dispatch-manifest comment body for an Epic.
|
|
64
|
-
*
|
|
65
|
-
* The output is byte-identical to the body
|
|
66
|
-
* `postManifestEpicComment` historically built inline, so it can be
|
|
67
|
-
* upserted by either the dispatcher (CLI path) or the wave-runner
|
|
68
|
-
* (in-process refresh path) without behavioural drift.
|
|
69
|
-
*
|
|
70
|
-
* @param {{
|
|
71
|
-
* epicId: number,
|
|
72
|
-
* stories: { storyId: number|string, wave: number, title: string }[],
|
|
73
|
-
* generatedAt: string,
|
|
74
|
-
* }} args
|
|
75
|
-
* @returns {string}
|
|
76
|
-
*/
|
|
77
|
-
export function renderManifest({ epicId, stories, generatedAt }) {
|
|
78
|
-
if (!Number.isFinite(epicId) && typeof epicId !== 'number') {
|
|
79
|
-
throw new TypeError('renderManifest: epicId is required');
|
|
80
|
-
}
|
|
81
|
-
const list = Array.isArray(stories) ? stories : [];
|
|
82
|
-
const waveCount = countWaves(list);
|
|
83
|
-
return [
|
|
84
|
-
`## 📋 Dispatch Manifest — Epic #${epicId}`,
|
|
85
|
-
'',
|
|
86
|
-
`- **Waves:** ${waveCount || 1}`,
|
|
87
|
-
`- **Stories:** ${list.length}`,
|
|
88
|
-
`- **Generated:** ${generatedAt}`,
|
|
89
|
-
'',
|
|
90
|
-
'Source of truth for the wave-completeness gate run at `/deliver`.',
|
|
91
|
-
'',
|
|
92
|
-
'```json',
|
|
93
|
-
JSON.stringify({ stories: list }, null, 2),
|
|
94
|
-
'```',
|
|
95
|
-
].join('\n');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Convenience: render directly from a full manifest object. Equivalent
|
|
100
|
-
* to `renderManifest({ epicId, stories: projectStoriesFromManifest(m),
|
|
101
|
-
* generatedAt: m.generatedAt })`.
|
|
102
|
-
*
|
|
103
|
-
* @param {object} manifest
|
|
104
|
-
*/
|
|
105
|
-
export function renderManifestFromManifest(manifest) {
|
|
106
|
-
return renderManifest({
|
|
107
|
-
epicId: manifest?.epicId,
|
|
108
|
-
stories: projectStoriesFromManifest(manifest),
|
|
109
|
-
generatedAt: manifest?.generatedAt,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* manifest-builder.js
|
|
3
|
-
*
|
|
4
|
-
* Pure projection: builds a manifest-shaped object from a structural spec
|
|
5
|
-
* (the `.agents/epics/<epic-id>.yaml` shape returned by
|
|
6
|
-
* `lib/spec/loader.js#loadSpec`) plus a state mapping (the sibling
|
|
7
|
-
* `<epic-id>.state.json` shape returned by `loadState`).
|
|
8
|
-
*
|
|
9
|
-
* Extracted from `manifest-formatter.js` (Story #1849 Task #1869). The
|
|
10
|
-
* shape projection used to be inlined in the formatter; pulling it out
|
|
11
|
-
* isolates the spec → manifest projection from the Markdown renderer and
|
|
12
|
-
* lets the per-story guard cascade live behind a single
|
|
13
|
-
* private predicate (`validateSpecShape`) so the orchestrator function's
|
|
14
|
-
* CRAP score drops below 12.
|
|
15
|
-
*
|
|
16
|
-
* Story #3413 (2-tier cutover, final): the residual per-Task projection
|
|
17
|
-
* (the Task projector, the per-Story Task array, and the Task-count
|
|
18
|
-
* rollup) has been deleted. The walker (`projectStories`) counts
|
|
19
|
-
* Stories directly, and `summary` carries Story-tier counts only
|
|
20
|
-
* (`totalStories` / `doneStories` / `progressPercent`), matching the
|
|
21
|
-
* canonical producer in `lib/orchestration/manifest-builder.js`.
|
|
22
|
-
*
|
|
23
|
-
* Story-level status surfaces on each `storyEntry.status` so downstream
|
|
24
|
-
* renderers read the Story's own `agent::*` label directly — the
|
|
25
|
-
* "Stories are first-class lifecycle units" invariant.
|
|
26
|
-
*
|
|
27
|
-
* No fs / network access; pure transform. Caller supplies `state` from
|
|
28
|
-
* `lib/spec/loader.js#loadState`.
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
import { AGENT_LABELS } from '../label-constants.js';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Private: validate the per-level shape of a spec node before we project
|
|
35
|
-
* it into the manifest. Centralising the guards keeps
|
|
36
|
-
* `buildManifestFromSpec` linear instead of branching at every level — the
|
|
37
|
-
* function reads as a straight projection and the predicate carries the
|
|
38
|
-
* "is this thing iterable / object-shaped?" decisions.
|
|
39
|
-
*
|
|
40
|
-
* `level` describes which spec node we are validating:
|
|
41
|
-
* - `'stories'` → the spec-level `stories` array
|
|
42
|
-
* - `'story'` → a single Story object (must be a non-null object)
|
|
43
|
-
*
|
|
44
|
-
* Returns `true` when the node satisfies the shape contract for that
|
|
45
|
-
* level, `false` otherwise. The caller substitutes an empty array (for
|
|
46
|
-
* iterable levels) or skips the node (for object levels) on `false`.
|
|
47
|
-
*
|
|
48
|
-
* @param {string} level
|
|
49
|
-
* @param {unknown} value
|
|
50
|
-
* @returns {boolean}
|
|
51
|
-
*/
|
|
52
|
-
function validateSpecShape(level, value) {
|
|
53
|
-
switch (level) {
|
|
54
|
-
case 'stories':
|
|
55
|
-
return Array.isArray(value);
|
|
56
|
-
case 'story':
|
|
57
|
-
return value !== null && typeof value === 'object';
|
|
58
|
-
default:
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Private factory: build the slug→id and slug→status resolvers from a
|
|
65
|
-
* state mapping. Returning the two closures from one factory keeps the
|
|
66
|
-
* branching that interprets the optional `state.mapping` shape out of
|
|
67
|
-
* `buildManifestFromSpec`'s body.
|
|
68
|
-
*
|
|
69
|
-
* Per Tech Spec #1483, agent::* status labels do not live in the spec.
|
|
70
|
-
* `resolveStatus` reads `state.mapping[slug].lastObservedAgentState` when
|
|
71
|
-
* present and falls back to `agent::ready` for un-mapped Stories.
|
|
72
|
-
* `resolveId` falls back to a deterministic `slug:<slug>` sentinel so
|
|
73
|
-
* the renderer never sees a null id.
|
|
74
|
-
*
|
|
75
|
-
* @param {{ mapping?: Record<string, { issueNumber?: number|null, lastObservedAgentState?: string|null }> }|null} state
|
|
76
|
-
* @returns {{ resolveId: (slug: string) => number|string, resolveStatus: (slug: string) => string }}
|
|
77
|
-
*/
|
|
78
|
-
function buildResolvers(state) {
|
|
79
|
-
const mapping =
|
|
80
|
-
state && typeof state.mapping === 'object' && state.mapping !== null
|
|
81
|
-
? state.mapping
|
|
82
|
-
: {};
|
|
83
|
-
|
|
84
|
-
const resolveId = (slug) => {
|
|
85
|
-
const entry = mapping[slug];
|
|
86
|
-
const id =
|
|
87
|
-
entry && typeof entry.issueNumber === 'number' ? entry.issueNumber : null;
|
|
88
|
-
return id ?? `slug:${slug}`;
|
|
89
|
-
};
|
|
90
|
-
const resolveStatus = (slug) => {
|
|
91
|
-
const entry = mapping[slug];
|
|
92
|
-
return entry && typeof entry.lastObservedAgentState === 'string'
|
|
93
|
-
? entry.lastObservedAgentState
|
|
94
|
-
: 'agent::ready';
|
|
95
|
-
};
|
|
96
|
-
return { resolveId, resolveStatus };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Private: project a single spec Story into a manifest Story entry. The
|
|
101
|
-
* Story's status is resolved directly from the Story-level label
|
|
102
|
-
* (`state.mapping[slug].lastObservedAgentState`) and surfaces on
|
|
103
|
-
* `storyEntry.status` — Stories carry their own lifecycle state and are
|
|
104
|
-
* leaves with no child tickets. Caller
|
|
105
|
-
* filters non-object stories with `validateSpecShape('story', ...)`
|
|
106
|
-
* before invoking.
|
|
107
|
-
*
|
|
108
|
-
* @param {object} story
|
|
109
|
-
* @param {{ resolveId: Function, resolveStatus: Function }} resolvers
|
|
110
|
-
* @returns {{ storyEntry: object, wave: number }}
|
|
111
|
-
*/
|
|
112
|
-
function projectStory(story, resolvers) {
|
|
113
|
-
const wave = Number.isInteger(story.wave) ? story.wave : -1;
|
|
114
|
-
const storyId = resolvers.resolveId(story.slug);
|
|
115
|
-
const status = resolvers.resolveStatus(story.slug);
|
|
116
|
-
const storyEntry = {
|
|
117
|
-
storyId,
|
|
118
|
-
storyTitle: story.title ?? '',
|
|
119
|
-
storySlug: story.slug ?? '',
|
|
120
|
-
type: 'story',
|
|
121
|
-
branchName:
|
|
122
|
-
typeof storyId === 'number' ? `story-${storyId}` : `story-${story.slug}`,
|
|
123
|
-
earliestWave: wave,
|
|
124
|
-
status,
|
|
125
|
-
};
|
|
126
|
-
return { storyEntry, wave };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Private: walk every Story in a spec and collect the per-story
|
|
131
|
-
* projections + Story-tier roll-up counters. Keeps the loop machinery
|
|
132
|
-
* out of `buildManifestFromSpec` so the entry point reads as a straight
|
|
133
|
-
* assembly of the result envelope.
|
|
134
|
-
*
|
|
135
|
-
* Under the 2-tier hierarchy (Story #4041) Stories are direct Epic
|
|
136
|
-
* children and leaves, so the rollup counts Stories directly:
|
|
137
|
-
* `totalStories` is every projected Story and `doneStories` is the
|
|
138
|
-
* subset carrying `agent::done`.
|
|
139
|
-
*
|
|
140
|
-
* @param {object[]} stories
|
|
141
|
-
* @param {{ resolveId: Function, resolveStatus: Function }} resolvers
|
|
142
|
-
* @returns {{
|
|
143
|
-
* storyManifest: object[],
|
|
144
|
-
* totalStories: number,
|
|
145
|
-
* doneStories: number,
|
|
146
|
-
* waveSet: Set<number>,
|
|
147
|
-
* }}
|
|
148
|
-
*/
|
|
149
|
-
function projectStories(stories, resolvers) {
|
|
150
|
-
const storyManifest = [];
|
|
151
|
-
let totalStories = 0;
|
|
152
|
-
let doneStories = 0;
|
|
153
|
-
const waveSet = new Set();
|
|
154
|
-
for (const story of stories) {
|
|
155
|
-
if (!validateSpecShape('story', story)) continue;
|
|
156
|
-
const { storyEntry, wave } = projectStory(story, resolvers);
|
|
157
|
-
storyManifest.push(storyEntry);
|
|
158
|
-
totalStories++;
|
|
159
|
-
if (storyEntry.status === AGENT_LABELS.DONE) doneStories++;
|
|
160
|
-
if (wave >= 0) waveSet.add(wave);
|
|
161
|
-
}
|
|
162
|
-
return { storyManifest, totalStories, doneStories, waveSet };
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Build a manifest-shaped object from a spec entry. Mirrors the contract
|
|
167
|
-
* produced by `lib/orchestration/manifest-builder.js#buildManifest` so
|
|
168
|
-
* `formatManifestMarkdown` (the renderer that backs `fromManifest`)
|
|
169
|
-
* accepts it without modification.
|
|
170
|
-
*
|
|
171
|
-
* Slug→issue-number resolution prefers `state.mapping[slug].issueNumber`
|
|
172
|
-
* when present and falls back to a deterministic `slug:<slug>` sentinel
|
|
173
|
-
* so the renderer never sees a null id. Status labels prefer
|
|
174
|
-
* `state.mapping[slug].lastObservedAgentState` and fall back to
|
|
175
|
-
* `agent::ready` per Tech Spec #1483.
|
|
176
|
-
*
|
|
177
|
-
* Pure — does not touch fs or the network. Caller supplies `state` from
|
|
178
|
-
* `lib/spec/loader.js#loadState`.
|
|
179
|
-
*
|
|
180
|
-
* @param {object} spec — parsed epic-spec (see `lib/spec/loader.js`).
|
|
181
|
-
* @param {{
|
|
182
|
-
* state?: { mapping?: Record<string, { issueNumber?: number|null, lastObservedAgentState?: string|null }> },
|
|
183
|
-
* generatedAt?: string,
|
|
184
|
-
* executor?: string,
|
|
185
|
-
* dryRun?: boolean,
|
|
186
|
-
* agentTelemetry?: object|null,
|
|
187
|
-
* }} [opts]
|
|
188
|
-
* @returns {object} manifest object matching the shape `formatManifestMarkdown` consumes.
|
|
189
|
-
*/
|
|
190
|
-
export function buildManifestFromSpec(spec, opts = {}) {
|
|
191
|
-
const resolvers = buildResolvers(opts.state ?? null);
|
|
192
|
-
const epicId =
|
|
193
|
-
spec?.epic && typeof spec.epic.id === 'number' ? spec.epic.id : null;
|
|
194
|
-
const epicTitle =
|
|
195
|
-
spec?.epic && typeof spec.epic.title === 'string' ? spec.epic.title : '';
|
|
196
|
-
const stories = validateSpecShape('stories', spec?.stories)
|
|
197
|
-
? spec.stories
|
|
198
|
-
: [];
|
|
199
|
-
|
|
200
|
-
const { storyManifest, totalStories, doneStories, waveSet } = projectStories(
|
|
201
|
-
stories,
|
|
202
|
-
resolvers,
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
const progressPercent =
|
|
206
|
-
totalStories > 0 ? Math.round((doneStories / totalStories) * 100) : 0;
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
schemaVersion: '1.0.0',
|
|
210
|
-
generatedAt: opts.generatedAt ?? new Date().toISOString(),
|
|
211
|
-
epicId,
|
|
212
|
-
epicTitle,
|
|
213
|
-
executor: opts.executor ?? 'spec',
|
|
214
|
-
dryRun: opts.dryRun ?? false,
|
|
215
|
-
summary: {
|
|
216
|
-
totalStories,
|
|
217
|
-
doneStories,
|
|
218
|
-
progressPercent,
|
|
219
|
-
totalWaves: waveSet.size,
|
|
220
|
-
dispatched: 0,
|
|
221
|
-
},
|
|
222
|
-
waves: [],
|
|
223
|
-
storyManifest,
|
|
224
|
-
dispatched: [],
|
|
225
|
-
agentTelemetry: opts.agentTelemetry ?? null,
|
|
226
|
-
// Cross-Story conflict findings forwarded by the validator (Story
|
|
227
|
-
// #2296). The formatter only emits the hazards block when this key
|
|
228
|
-
// is *defined* — undefined means the caller didn't compute findings
|
|
229
|
-
// for this manifest (e.g. live progress reporter ticks), so the
|
|
230
|
-
// section is suppressed rather than showing a misleading "no
|
|
231
|
-
// hazards" line.
|
|
232
|
-
concurrencyFindings: opts.concurrencyFindings,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Test-only: surface the private predicate so the sibling unit test can
|
|
237
|
-
// exercise each branch without going through the full builder. Export
|
|
238
|
-
// stays underscored to signal "internal" to production callers.
|
|
239
|
-
export const __testables = { validateSpecShape };
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* manifest-formatter.js
|
|
3
|
-
*
|
|
4
|
-
* Wiring facade for the dispatch-manifest presentation layer. Composes:
|
|
5
|
-
* - `manifest-builder.js` — spec → manifest projection.
|
|
6
|
-
* - `manifest-helpers.js` — small pure helpers (progress, slug,
|
|
7
|
-
* wave-status, topo sort, …).
|
|
8
|
-
* - `manifest-render-waves.js` — per-wave H2 sections + Story H3 list.
|
|
9
|
-
* - `manifest-procedures.js` — bottom `<details>` block.
|
|
10
|
-
* - `manifest-story-views.js` — story-execution manifest + CLI table.
|
|
11
|
-
*
|
|
12
|
-
* Exposes `formatManifestMarkdown` (memoised on per-input content hash)
|
|
13
|
-
* plus `fromManifest` / `fromSpec` entry points, and re-exports every
|
|
14
|
-
* symbol the older monolithic formatter used to host so existing
|
|
15
|
-
* imports off this path keep resolving without change.
|
|
16
|
-
*
|
|
17
|
-
* Pure: no fs / provider / config I/O. Callers that need injected values
|
|
18
|
-
* (e.g. `renderStoryManifestMarkdown`'s script-path hints) pass them via
|
|
19
|
-
* `opts`. The outer façade `manifest-renderer.js` re-exports this module
|
|
20
|
-
* and owns the one impure helper that reads config to build the options
|
|
21
|
-
* bag.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import { createHash } from 'node:crypto';
|
|
25
|
-
import { buildManifestFromSpec } from './manifest-builder.js';
|
|
26
|
-
import {
|
|
27
|
-
computeProgress,
|
|
28
|
-
deriveStorySymbol,
|
|
29
|
-
deriveWaveStatus,
|
|
30
|
-
renderProgressBar,
|
|
31
|
-
renderWaveSections,
|
|
32
|
-
slugifyHeading,
|
|
33
|
-
waveHeadingText,
|
|
34
|
-
} from './manifest-helpers.js';
|
|
35
|
-
import { renderProceduresAndLegendDetails } from './manifest-procedures.js';
|
|
36
|
-
import {
|
|
37
|
-
renderConcurrencyHazards,
|
|
38
|
-
renderNestedWaveSections,
|
|
39
|
-
} from './manifest-render-waves.js';
|
|
40
|
-
import {
|
|
41
|
-
formatStoryManifestMarkdown,
|
|
42
|
-
printStoryDispatchTable,
|
|
43
|
-
} from './manifest-story-views.js';
|
|
44
|
-
|
|
45
|
-
// Re-export every name that used to live in this file so external
|
|
46
|
-
// call-sites and tests keep importing them from here without a path
|
|
47
|
-
// change (Story #1849 split).
|
|
48
|
-
export {
|
|
49
|
-
buildManifestFromSpec,
|
|
50
|
-
computeProgress,
|
|
51
|
-
deriveStorySymbol,
|
|
52
|
-
deriveWaveStatus,
|
|
53
|
-
formatStoryManifestMarkdown,
|
|
54
|
-
printStoryDispatchTable,
|
|
55
|
-
renderConcurrencyHazards,
|
|
56
|
-
renderNestedWaveSections,
|
|
57
|
-
renderProceduresAndLegendDetails,
|
|
58
|
-
renderProgressBar,
|
|
59
|
-
renderWaveSections,
|
|
60
|
-
slugifyHeading,
|
|
61
|
-
waveHeadingText,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Dispatch manifest (Epic-level) Markdown — memoised public entry
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
let _lastManifestRef = null;
|
|
69
|
-
let _lastManifestHash = null;
|
|
70
|
-
let _lastManifestOutput = null;
|
|
71
|
-
|
|
72
|
-
function hashManifest(manifest) {
|
|
73
|
-
return createHash('sha1')
|
|
74
|
-
.update(JSON.stringify(manifest ?? null))
|
|
75
|
-
.digest('hex');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Clear the content-hash cache for `formatManifestMarkdown`. Intended
|
|
80
|
-
* for tests and for callers that mutate manifest objects in place
|
|
81
|
-
* between renders.
|
|
82
|
-
*/
|
|
83
|
-
export function __resetManifestFormatterCache() {
|
|
84
|
-
_lastManifestRef = null;
|
|
85
|
-
_lastManifestHash = null;
|
|
86
|
-
_lastManifestOutput = null;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function formatManifestMarkdown(manifest) {
|
|
90
|
-
// Fast path: same manifest instance as last call (progress-reporter
|
|
91
|
-
// reuses the same object across ticks when nothing has changed).
|
|
92
|
-
if (manifest === _lastManifestRef && _lastManifestOutput !== null) {
|
|
93
|
-
return _lastManifestOutput;
|
|
94
|
-
}
|
|
95
|
-
// Slow path: content-hash comparison for cases where the caller built
|
|
96
|
-
// a fresh manifest object with identical content.
|
|
97
|
-
const hash = hashManifest(manifest);
|
|
98
|
-
if (hash === _lastManifestHash && _lastManifestOutput !== null) {
|
|
99
|
-
_lastManifestRef = manifest;
|
|
100
|
-
return _lastManifestOutput;
|
|
101
|
-
}
|
|
102
|
-
const output = _formatManifestMarkdownUncached(manifest);
|
|
103
|
-
_lastManifestRef = manifest;
|
|
104
|
-
_lastManifestHash = hash;
|
|
105
|
-
_lastManifestOutput = output;
|
|
106
|
-
return output;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function _formatManifestMarkdownUncached(manifest) {
|
|
110
|
-
const lines = [
|
|
111
|
-
...renderManifestHeader(manifest),
|
|
112
|
-
...renderManifestBody(manifest),
|
|
113
|
-
];
|
|
114
|
-
/* node:coverage ignore next */
|
|
115
|
-
if (manifest.agentTelemetry) {
|
|
116
|
-
lines.push(...renderManifestTelemetry(manifest.agentTelemetry));
|
|
117
|
-
}
|
|
118
|
-
return lines.join('\n');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Private: emit the manifest header — title, subtitle, the single
|
|
123
|
-
* `_Generated …_` meta line, and the operating-procedures `<details>`
|
|
124
|
-
* block that sits directly under the meta. Pure.
|
|
125
|
-
*
|
|
126
|
-
* @param {object} manifest
|
|
127
|
-
* @returns {string[]}
|
|
128
|
-
*/
|
|
129
|
-
function renderManifestHeader(manifest) {
|
|
130
|
-
const { epicId, epicTitle, generatedAt } = manifest;
|
|
131
|
-
const progress = computeProgress(manifest);
|
|
132
|
-
const waveCount = progress.storyWaveCount;
|
|
133
|
-
return [
|
|
134
|
-
`# 📋 Dispatch Manifest — Epic #${epicId}`,
|
|
135
|
-
'',
|
|
136
|
-
`> **${epicTitle}**`,
|
|
137
|
-
'',
|
|
138
|
-
`_Generated ${generatedAt} · ${progress.doneStories}/${progress.totalStories} stories · ${waveCount} wave${waveCount === 1 ? '' : 's'}_`,
|
|
139
|
-
'',
|
|
140
|
-
renderProceduresAndLegendDetails(epicId),
|
|
141
|
-
'',
|
|
142
|
-
];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Private: emit the Wave Summary table plus the per-wave H2 sections.
|
|
147
|
-
*
|
|
148
|
-
* @param {object} manifest
|
|
149
|
-
* @returns {string[]}
|
|
150
|
-
*/
|
|
151
|
-
function renderManifestBody(manifest) {
|
|
152
|
-
const allItems =
|
|
153
|
-
manifest.storyManifest ||
|
|
154
|
-
manifest.stories ||
|
|
155
|
-
manifest.summary?.stories ||
|
|
156
|
-
[];
|
|
157
|
-
const waveEligible = allItems;
|
|
158
|
-
const lines = [];
|
|
159
|
-
const waveBlock = renderWaveSections(waveEligible);
|
|
160
|
-
if (waveBlock) lines.push(waveBlock);
|
|
161
|
-
const storyManifest = manifest.storyManifest;
|
|
162
|
-
if (storyManifest && storyManifest.length > 0) {
|
|
163
|
-
const nestedBlock = renderNestedWaveSections(storyManifest);
|
|
164
|
-
if (nestedBlock) lines.push(nestedBlock);
|
|
165
|
-
}
|
|
166
|
-
// Cross-Story concurrency hazards block — only emitted when the caller
|
|
167
|
-
// attaches `concurrencyFindings` to the manifest (i.e. `/plan`
|
|
168
|
-
// Phase 9 dispatcher dry-run forwards the validator's findings array).
|
|
169
|
-
// Absent for live progress-reporter manifests where the block would
|
|
170
|
-
// duplicate Story-level state already shown above.
|
|
171
|
-
if (manifest.concurrencyFindings !== undefined) {
|
|
172
|
-
const hazardsBlock = renderConcurrencyHazards(manifest.concurrencyFindings);
|
|
173
|
-
if (hazardsBlock) lines.push(hazardsBlock);
|
|
174
|
-
}
|
|
175
|
-
return lines;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Private: emit the agent-telemetry trailer (friction count + recent
|
|
180
|
-
* friction list) when the manifest carries one. Under the 2-tier
|
|
181
|
-
* hierarchy (Epic #3163) friction records are Story-scoped, so each
|
|
182
|
-
* recent-friction item is keyed by its `storyId`.
|
|
183
|
-
*
|
|
184
|
-
* @param {{ totalFriction: number, recentFriction: Array<{ message: string, storyId: number|string }> }} agentTelemetry
|
|
185
|
-
* @returns {string[]}
|
|
186
|
-
*/
|
|
187
|
-
/* node:coverage ignore next */
|
|
188
|
-
function renderManifestTelemetry(agentTelemetry) {
|
|
189
|
-
const lines = [
|
|
190
|
-
'## 📈 Agent Telemetry & Diagnostics',
|
|
191
|
-
'',
|
|
192
|
-
`- **Total Friction Events:** ${agentTelemetry.totalFriction}`,
|
|
193
|
-
];
|
|
194
|
-
if (agentTelemetry.recentFriction.length > 0) {
|
|
195
|
-
lines.push('- **Active Issues & Friction:**');
|
|
196
|
-
for (const item of agentTelemetry.recentFriction) {
|
|
197
|
-
const safeMessage = item.message
|
|
198
|
-
.replace(/\s+/g, ' ')
|
|
199
|
-
.replace(/\n/g, ' ')
|
|
200
|
-
.trim();
|
|
201
|
-
lines.push(` - Story **#${item.storyId}**: ${safeMessage}`);
|
|
202
|
-
}
|
|
203
|
-
} else {
|
|
204
|
-
lines.push('- **Active Issues:** None recorded.');
|
|
205
|
-
}
|
|
206
|
-
lines.push('');
|
|
207
|
-
lines.push('---');
|
|
208
|
-
lines.push('');
|
|
209
|
-
return lines;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Backward-compat alias (existing callers and tests import this name).
|
|
213
|
-
export const renderManifestMarkdown = formatManifestMarkdown;
|
|
214
|
-
|
|
215
|
-
// ---------------------------------------------------------------------------
|
|
216
|
-
// Dual entry points: fromManifest / fromSpec (Epic #1182 Story #1501)
|
|
217
|
-
// ---------------------------------------------------------------------------
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Canonical alias for `formatManifestMarkdown`. Existing callers should
|
|
221
|
-
* migrate to this name; the underlying function is unchanged.
|
|
222
|
-
*/
|
|
223
|
-
export const fromManifest = formatManifestMarkdown;
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Render a Markdown dispatch manifest from a structural spec. Funnels
|
|
227
|
-
* through `formatManifestMarkdown` so the output is byte-identical to
|
|
228
|
-
* `fromManifest` when given an equivalent manifest fixture (round-trip
|
|
229
|
-
* parity AC for Story #1501).
|
|
230
|
-
*
|
|
231
|
-
* @param {object} spec — parsed epic-spec.
|
|
232
|
-
* @param {Parameters<typeof buildManifestFromSpec>[1]} [opts]
|
|
233
|
-
* @returns {string}
|
|
234
|
-
*/
|
|
235
|
-
export function fromSpec(spec, opts = {}) {
|
|
236
|
-
const manifest = buildManifestFromSpec(spec, opts);
|
|
237
|
-
// Bust the cache so callers toggling fromSpec / fromManifest in the
|
|
238
|
-
// same process don't get a stale render from a content-hash collision
|
|
239
|
-
// on a different manifest instance.
|
|
240
|
-
__resetManifestFormatterCache();
|
|
241
|
-
return formatManifestMarkdown(manifest);
|
|
242
|
-
}
|