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,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* context-resolver.js — Stage 1 of the story-init pipeline.
|
|
3
|
-
*
|
|
4
|
-
* Fetches the Story ticket, validates it carries `type::story`, parses its
|
|
5
|
-
* body for hierarchy markers, and (optionally) injects/validates the
|
|
6
|
-
* `recut-of` marker when `input.recutOf` is supplied.
|
|
7
|
-
*
|
|
8
|
-
* Pure stage signature: ({ provider, git, fs, logger, input }) → result.
|
|
9
|
-
* `git` and `fs` are accepted for signature conformance but unused here.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { TYPE_LABELS } from '../label-constants.js';
|
|
13
|
-
import { injectRecutMarker, parseRecutMarker } from '../orchestration/recut.js';
|
|
14
|
-
import { resolveStoryHierarchy } from '../story-lifecycle.js';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @param {object} deps
|
|
18
|
-
* @param {object} deps.provider Ticketing provider (getTicket, updateTicket).
|
|
19
|
-
* @param {object} [deps.logger] `{ progress?: (phase, msg) => void }`.
|
|
20
|
-
* @param {object} deps.input
|
|
21
|
-
* @param {number} deps.input.storyId
|
|
22
|
-
* @param {number|null} [deps.input.recutOf]
|
|
23
|
-
* @param {boolean} [deps.input.dryRun]
|
|
24
|
-
* @returns {Promise<{ story: object, body: string, epicId: number, parentId: number|null }>}
|
|
25
|
-
*/
|
|
26
|
-
export async function resolveContext({ provider, logger, input }) {
|
|
27
|
-
const { storyId, recutOf = null, dryRun = false } = input;
|
|
28
|
-
const progress = logger?.progress ?? (() => {});
|
|
29
|
-
|
|
30
|
-
let story;
|
|
31
|
-
try {
|
|
32
|
-
story = await provider.getTicket(storyId);
|
|
33
|
-
} catch (err) {
|
|
34
|
-
throw new Error(`Failed to fetch Story #${storyId}: ${err.message}`, {
|
|
35
|
-
cause: err,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (!story.labels.includes(TYPE_LABELS.STORY)) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
`Issue #${storyId} is not a Story (labels: ${story.labels.join(', ')}). Use the dispatcher for Epics.`,
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let body = story.body ?? '';
|
|
46
|
-
const { epicId, parentId } = resolveStoryHierarchy(body);
|
|
47
|
-
|
|
48
|
-
if (!epicId) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`Story #${storyId} has no "Epic: #N" reference in its body. Cannot resolve hierarchy.`,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (recutOf) {
|
|
55
|
-
if (recutOf === storyId) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
`[story-init] --recut-of #${recutOf} cannot point at the Story itself.`,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
const existing = parseRecutMarker(body);
|
|
61
|
-
if (existing && existing.parentStoryId !== recutOf) {
|
|
62
|
-
progress(
|
|
63
|
-
'RECUT',
|
|
64
|
-
`⚠️ Story #${storyId} already marked recut-of #${existing.parentStoryId}; overwriting with #${recutOf}.`,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
if (!existing || existing.parentStoryId !== recutOf) {
|
|
68
|
-
const patched = injectRecutMarker(body, recutOf);
|
|
69
|
-
if (!dryRun) {
|
|
70
|
-
await provider.updateTicket(storyId, { body: patched });
|
|
71
|
-
progress(
|
|
72
|
-
'RECUT',
|
|
73
|
-
`🪪 Marked Story #${storyId} as recut-of #${recutOf} on the ticket body.`,
|
|
74
|
-
);
|
|
75
|
-
} else {
|
|
76
|
-
progress(
|
|
77
|
-
'RECUT',
|
|
78
|
-
`[DRY-RUN] Would mark Story #${storyId} as recut-of #${recutOf}.`,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
body = patched;
|
|
82
|
-
story = { ...story, body: patched };
|
|
83
|
-
} else {
|
|
84
|
-
progress(
|
|
85
|
-
'RECUT',
|
|
86
|
-
`Story #${storyId} already carries recut-of #${recutOf} marker.`,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return { story, body, epicId, parentId };
|
|
92
|
-
}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* donor-precheck.js — verify the symlink-strategy donor is primed.
|
|
3
|
-
*
|
|
4
|
-
* When `delivery.worktreeIsolation.nodeModulesStrategy === 'symlink'`, every
|
|
5
|
-
* Story worktree junctions/symlinks its `node_modules/` from a donor (the
|
|
6
|
-
* `primeFromPath` directory, typically the repo root). If the donor lacks
|
|
7
|
-
* `node_modules/` the symlink will resolve to nothing and the worktree
|
|
8
|
-
* cannot install or run tests. This module runs once, just before
|
|
9
|
-
* `applyNodeModulesStrategy`, to make sure the donor is primed.
|
|
10
|
-
*
|
|
11
|
-
* The pre-check is idempotent across concurrent wave dispatches via a
|
|
12
|
-
* filesystem lock directory at `<donor>/.agents-donor-precheck.lock`. The
|
|
13
|
-
* first arrival creates the lock atomically (`fs.mkdirSync`), runs
|
|
14
|
-
* `npm ci`, and removes the lock. Concurrent callers either skip
|
|
15
|
-
* (donor already primed) or wait for the lock to clear and re-check
|
|
16
|
-
* existence — they do not double-run the installer.
|
|
17
|
-
*
|
|
18
|
-
* The helpers are split so the pure decision logic (`planDonorAction`) is
|
|
19
|
-
* trivially testable without filesystem or child-process side-effects.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { spawnSync } from 'node:child_process';
|
|
23
|
-
import nodeFs from 'node:fs';
|
|
24
|
-
import nodePath from 'node:path';
|
|
25
|
-
|
|
26
|
-
const LOCK_DIRNAME = '.agents-donor-precheck.lock';
|
|
27
|
-
const LOCK_POLL_INTERVAL_MS = 100;
|
|
28
|
-
const LOCK_WAIT_TIMEOUT_MS = 5 * 60_000;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Pure: decide whether the donor needs a one-shot install.
|
|
32
|
-
*
|
|
33
|
-
* Returns one of:
|
|
34
|
-
* - `{ action: 'skip', reason }` — strategy is not symlink, or donor
|
|
35
|
-
* already has node_modules.
|
|
36
|
-
* - `{ action: 'install', donorPath }` — caller should run install at
|
|
37
|
-
* `donorPath`.
|
|
38
|
-
*
|
|
39
|
-
* @param {object} opts
|
|
40
|
-
* @param {string} opts.strategy The configured `nodeModulesStrategy`.
|
|
41
|
-
* @param {string|null} opts.primeFromPath Relative donor path.
|
|
42
|
-
* @param {string} opts.repoRoot Absolute repo root.
|
|
43
|
-
* @param {{ existsSync: (p: string) => boolean }} [opts.fs]
|
|
44
|
-
* Filesystem facade for tests.
|
|
45
|
-
* @returns {{ action: 'skip', reason: string } | { action: 'install', donorPath: string }}
|
|
46
|
-
*/
|
|
47
|
-
export function planDonorAction({
|
|
48
|
-
strategy,
|
|
49
|
-
primeFromPath,
|
|
50
|
-
repoRoot,
|
|
51
|
-
fs = nodeFs,
|
|
52
|
-
path = nodePath,
|
|
53
|
-
}) {
|
|
54
|
-
if (strategy !== 'symlink') {
|
|
55
|
-
return { action: 'skip', reason: 'strategy-not-symlink' };
|
|
56
|
-
}
|
|
57
|
-
if (!primeFromPath) {
|
|
58
|
-
return { action: 'skip', reason: 'no-prime-from-path' };
|
|
59
|
-
}
|
|
60
|
-
const donorPath = path.resolve(repoRoot, primeFromPath);
|
|
61
|
-
if (fs.existsSync(path.join(donorPath, 'node_modules'))) {
|
|
62
|
-
return { action: 'skip', reason: 'donor-already-primed' };
|
|
63
|
-
}
|
|
64
|
-
return { action: 'install', donorPath };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Wait for the donor lock directory to be removed by the lock holder.
|
|
69
|
-
* Returns true if the lock cleared in time, false on timeout.
|
|
70
|
-
*
|
|
71
|
-
* Exported for tests.
|
|
72
|
-
*/
|
|
73
|
-
export function waitForLockClear({
|
|
74
|
-
lockPath,
|
|
75
|
-
fs = nodeFs,
|
|
76
|
-
pollIntervalMs = LOCK_POLL_INTERVAL_MS,
|
|
77
|
-
timeoutMs = LOCK_WAIT_TIMEOUT_MS,
|
|
78
|
-
now = () => Date.now(),
|
|
79
|
-
sleepFn,
|
|
80
|
-
}) {
|
|
81
|
-
const start = now();
|
|
82
|
-
const sleep =
|
|
83
|
-
sleepFn ??
|
|
84
|
-
((ms) => {
|
|
85
|
-
const signal = new Int32Array(new SharedArrayBuffer(4));
|
|
86
|
-
Atomics.wait(signal, 0, 0, ms);
|
|
87
|
-
});
|
|
88
|
-
while (fs.existsSync(lockPath)) {
|
|
89
|
-
if (now() - start >= timeoutMs) return false;
|
|
90
|
-
sleep(pollIntervalMs);
|
|
91
|
-
}
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Ensure the symlink-strategy donor is primed. Runs at most once per
|
|
97
|
-
* dispatch wave because the lock directory is created atomically with
|
|
98
|
-
* `fs.mkdirSync` (EEXIST = another concurrent process already won).
|
|
99
|
-
*
|
|
100
|
-
* Behaviour by lock outcome:
|
|
101
|
-
* - Lock acquired → run `npm ci`, then remove the lock.
|
|
102
|
-
* - Lock contended → wait for the lock to clear, then re-check
|
|
103
|
-
* existence. If `node_modules` is now present, skip; otherwise,
|
|
104
|
-
* surface an error (the lock holder failed and the caller cannot
|
|
105
|
-
* safely proceed).
|
|
106
|
-
*
|
|
107
|
-
* @param {object} opts
|
|
108
|
-
* @param {string} opts.strategy
|
|
109
|
-
* @param {string|null} opts.primeFromPath
|
|
110
|
-
* @param {string} opts.repoRoot
|
|
111
|
-
* @param {{ progress?: (kind: string, msg: string) => void }} [opts.logger]
|
|
112
|
-
* @param {{ existsSync: typeof nodeFs.existsSync, mkdirSync: typeof nodeFs.mkdirSync, rmSync: typeof nodeFs.rmSync }} [opts.fs]
|
|
113
|
-
* @param {typeof spawnSync} [opts.spawnFn] Injected installer for tests.
|
|
114
|
-
* @param {(opts: object) => boolean} [opts.waitFn] Injected lock waiter.
|
|
115
|
-
* @returns {{ action: 'skip' | 'installed' | 'waited', reason?: string, donorPath?: string, durationMs?: number }}
|
|
116
|
-
*/
|
|
117
|
-
export function ensureDonorPrimed({
|
|
118
|
-
strategy,
|
|
119
|
-
primeFromPath,
|
|
120
|
-
repoRoot,
|
|
121
|
-
logger,
|
|
122
|
-
fs = nodeFs,
|
|
123
|
-
path = nodePath,
|
|
124
|
-
spawnFn = spawnSync,
|
|
125
|
-
waitFn = waitForLockClear,
|
|
126
|
-
now = () => Date.now(),
|
|
127
|
-
}) {
|
|
128
|
-
const t0 = now();
|
|
129
|
-
const progress = logger?.progress ?? (() => {});
|
|
130
|
-
const plan = planDonorAction({ strategy, primeFromPath, repoRoot, fs, path });
|
|
131
|
-
if (plan.action === 'skip') {
|
|
132
|
-
return { action: 'skip', reason: plan.reason, durationMs: now() - t0 };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const { donorPath } = plan;
|
|
136
|
-
const lockPath = path.join(donorPath, LOCK_DIRNAME);
|
|
137
|
-
let lockAcquired = false;
|
|
138
|
-
try {
|
|
139
|
-
fs.mkdirSync(lockPath);
|
|
140
|
-
lockAcquired = true;
|
|
141
|
-
} catch (err) {
|
|
142
|
-
if (err.code !== 'EEXIST') throw err;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!lockAcquired) {
|
|
146
|
-
progress('DONOR-PRECHECK', `donor=${donorPath} lock contended, waiting...`);
|
|
147
|
-
const cleared = waitFn({ lockPath, fs });
|
|
148
|
-
if (!cleared) {
|
|
149
|
-
throw new Error(
|
|
150
|
-
`donor-precheck: timed out waiting for lock ${lockPath} to clear after ${LOCK_WAIT_TIMEOUT_MS}ms`,
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
if (!fs.existsSync(path.join(donorPath, 'node_modules'))) {
|
|
154
|
-
throw new Error(
|
|
155
|
-
`donor-precheck: lock holder released ${lockPath} without priming node_modules at ${donorPath}`,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
progress(
|
|
159
|
-
'DONOR-PRECHECK',
|
|
160
|
-
`donor=${donorPath} primed by concurrent dispatch, proceeding.`,
|
|
161
|
-
);
|
|
162
|
-
return { action: 'waited', donorPath, durationMs: now() - t0 };
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
try {
|
|
166
|
-
// Re-check between mkdir and install: another process could have run
|
|
167
|
-
// and finished while we were racing on mkdirSync.
|
|
168
|
-
if (fs.existsSync(path.join(donorPath, 'node_modules'))) {
|
|
169
|
-
progress(
|
|
170
|
-
'DONOR-PRECHECK',
|
|
171
|
-
`donor=${donorPath} already primed (post-lock recheck), skipping install.`,
|
|
172
|
-
);
|
|
173
|
-
return {
|
|
174
|
-
action: 'skip',
|
|
175
|
-
reason: 'donor-primed-post-lock',
|
|
176
|
-
donorPath,
|
|
177
|
-
durationMs: now() - t0,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
progress(
|
|
181
|
-
'DONOR-PRECHECK',
|
|
182
|
-
`donor=${donorPath} missing node_modules — running one-shot npm ci...`,
|
|
183
|
-
);
|
|
184
|
-
const result = spawnFn('npm', ['ci'], {
|
|
185
|
-
cwd: donorPath,
|
|
186
|
-
stdio: 'inherit',
|
|
187
|
-
shell: process.platform === 'win32',
|
|
188
|
-
timeout: 10 * 60_000,
|
|
189
|
-
});
|
|
190
|
-
if (result.status !== 0) {
|
|
191
|
-
throw new Error(
|
|
192
|
-
`donor-precheck: 'npm ci' at ${donorPath} exited with status ${result.status}`,
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
progress('DONOR-PRECHECK', `donor=${donorPath} primed in ${now() - t0}ms.`);
|
|
196
|
-
return { action: 'installed', donorPath, durationMs: now() - t0 };
|
|
197
|
-
} finally {
|
|
198
|
-
try {
|
|
199
|
-
fs.rmSync(lockPath, { recursive: true, force: true });
|
|
200
|
-
} catch (_err) {
|
|
201
|
-
// Best-effort lock release; subsequent runs will recover by
|
|
202
|
-
// re-checking node_modules existence.
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export const __LOCK_DIRNAME = LOCK_DIRNAME;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* state-transitioner.js — Stage 6 of the story-init pipeline.
|
|
3
|
-
*
|
|
4
|
-
* Flips the Story ticket to `agent::executing` at init time. Under the
|
|
5
|
-
* 2-tier hierarchy the Story has inline acceptance and no child Task
|
|
6
|
-
* lifecycle — `/deliver` runs a single Story-implementation phase.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
STATE_LABELS,
|
|
11
|
-
transitionTicketState,
|
|
12
|
-
} from '../orchestration/ticketing.js';
|
|
13
|
-
import { batchTransitionTickets } from '../story-lifecycle.js';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Flip the Story to `agent::executing` and cascade upward (Epic / Feature).
|
|
17
|
-
*
|
|
18
|
-
* @param {object} deps
|
|
19
|
-
* @param {object} deps.provider
|
|
20
|
-
* @param {object} [deps.logger]
|
|
21
|
-
* @param {object} deps.input
|
|
22
|
-
* @param {number} deps.input.storyId
|
|
23
|
-
* @param {object} deps.input.story - Prefetched Story ticket (`ticketSnapshot`).
|
|
24
|
-
* @param {Function|null} [deps.input.notify]
|
|
25
|
-
* @returns {Promise<{ ok: true }>}
|
|
26
|
-
*/
|
|
27
|
-
export async function transitionStoryToExecuting({ provider, logger, input }) {
|
|
28
|
-
const { storyId, story, notify = null } = input;
|
|
29
|
-
const progress = logger?.progress ?? (() => {});
|
|
30
|
-
|
|
31
|
-
progress('TICKETS', `Transitioning Story #${storyId} to agent::executing...`);
|
|
32
|
-
await transitionTicketState(provider, storyId, STATE_LABELS.EXECUTING, {
|
|
33
|
-
ticketSnapshot: story,
|
|
34
|
-
cascade: true,
|
|
35
|
-
notify,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return { ok: true };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Batch-transitions every child Task to a target label. Retained for
|
|
43
|
-
* `batchTransitionTickets` unit coverage and post-merge batch closes;
|
|
44
|
-
* story-init no longer calls this at startup.
|
|
45
|
-
*
|
|
46
|
-
* @param {object} deps
|
|
47
|
-
* @param {object} deps.provider
|
|
48
|
-
* @param {object} [deps.logger]
|
|
49
|
-
* @param {object} deps.input
|
|
50
|
-
* @param {Array<object>} deps.input.tasks
|
|
51
|
-
* @param {Function|null} [deps.input.notify]
|
|
52
|
-
* @returns {Promise<{
|
|
53
|
-
* ok: boolean,
|
|
54
|
-
* failed: Array<{id:number,attempts:number,error:string}>,
|
|
55
|
-
* transitioned: number[],
|
|
56
|
-
* skipped: number[],
|
|
57
|
-
* }>}
|
|
58
|
-
*/
|
|
59
|
-
export async function transitionTaskStates({ provider, logger, input }) {
|
|
60
|
-
const { tasks, notify = null } = input;
|
|
61
|
-
const progress = logger?.progress ?? (() => {});
|
|
62
|
-
|
|
63
|
-
progress(
|
|
64
|
-
'TICKETS',
|
|
65
|
-
`Transitioning ${tasks.length} Task(s) to agent::executing...`,
|
|
66
|
-
);
|
|
67
|
-
const transitionResult = await batchTransitionTickets(
|
|
68
|
-
provider,
|
|
69
|
-
tasks,
|
|
70
|
-
STATE_LABELS.EXECUTING,
|
|
71
|
-
{ progress, notify },
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
ok: transitionResult.failed.length === 0,
|
|
76
|
-
failed: transitionResult.failed,
|
|
77
|
-
transitioned: transitionResult.transitioned,
|
|
78
|
-
skipped: transitionResult.skipped,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* task-graph-builder.js — Stage 4 of the story-init pipeline.
|
|
3
|
-
*
|
|
4
|
-
* Enumerates child Tasks of the Story, then topologically sorts them using
|
|
5
|
-
* `blocked by` edges that reference other Tasks in the same set. Inter-Task
|
|
6
|
-
* dependencies outside the child set are ignored (they are handled by the
|
|
7
|
-
* Story-level blocker validator).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { parseBlockedBy } from '../dependency-parser.js';
|
|
11
|
-
import { buildGraph, detectCycle, topologicalSort } from '../Graph.js';
|
|
12
|
-
import { Logger } from '../Logger.js';
|
|
13
|
-
import { fetchChildTickets } from '../story-lifecycle.js';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Detect whether a Story body carries inline acceptance criteria, the
|
|
17
|
-
* structural signal that the Story is authored in the 2-tier
|
|
18
|
-
* (Story-with-inline-acceptance) shape and therefore should not be expected
|
|
19
|
-
* to enumerate child Task tickets. Recognises both `## Acceptance` and
|
|
20
|
-
* `## Acceptance Criteria` headings, with at least one list bullet under
|
|
21
|
-
* them (mirroring the heading set the manifest-builder extracts).
|
|
22
|
-
*
|
|
23
|
-
* @param {string} body
|
|
24
|
-
* @returns {boolean}
|
|
25
|
-
*/
|
|
26
|
-
export function hasInlineAcceptance(body) {
|
|
27
|
-
if (typeof body !== 'string' || body.length === 0) return false;
|
|
28
|
-
const headingRe = /^##\s+Acceptance(?:\s+Criteria)?\s*$/im;
|
|
29
|
-
const match = body.match(headingRe);
|
|
30
|
-
if (!match || match.index == null) return false;
|
|
31
|
-
const rest = body.slice(match.index + match[0].length);
|
|
32
|
-
const nextHeading = rest.search(/^##\s+/m);
|
|
33
|
-
const block = nextHeading === -1 ? rest : rest.slice(0, nextHeading);
|
|
34
|
-
for (const rawLine of block.split(/\r?\n/)) {
|
|
35
|
-
const line = rawLine.trim();
|
|
36
|
-
if (/^[-*]\s+(?:\[[ xX]\]\s+)?\S/.test(line)) return true;
|
|
37
|
-
}
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function sortTasksByDependencies(tasks) {
|
|
42
|
-
if (tasks.length <= 1) return tasks;
|
|
43
|
-
|
|
44
|
-
const graphTasks = tasks.map((t) => ({
|
|
45
|
-
...t,
|
|
46
|
-
dependsOn: parseBlockedBy(t.body ?? '').filter((dep) =>
|
|
47
|
-
tasks.some((tt) => tt.id === dep),
|
|
48
|
-
),
|
|
49
|
-
}));
|
|
50
|
-
const { adjacency, taskMap } = buildGraph(graphTasks);
|
|
51
|
-
|
|
52
|
-
const cycle = detectCycle(adjacency);
|
|
53
|
-
if (cycle) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
`[story-init] Dependency cycle detected among child tasks: ` +
|
|
56
|
-
`#${cycle.join(' → #')}. Fix the \`blocked by\` references before retrying.`,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return topologicalSort(adjacency, taskMap);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @param {object} deps
|
|
65
|
-
* @param {object} deps.provider
|
|
66
|
-
* @param {object} [deps.logger]
|
|
67
|
-
* @param {object} deps.input
|
|
68
|
-
* @param {number} deps.input.storyId
|
|
69
|
-
* @param {string} [deps.input.storyBody] Story body — used to detect
|
|
70
|
-
* whether the Story carries inline acceptance (2-tier shape) so the
|
|
71
|
-
* empty-Task-list path is treated as expected rather than as a warning.
|
|
72
|
-
*
|
|
73
|
-
* Task #3154 (Epic #3078) deleted the `planning.hierarchy` flag; the
|
|
74
|
-
* 2-tier vs 4-tier mode is now derived entirely from the ticket shape —
|
|
75
|
-
* inline acceptance + zero Tasks resolves to `'2-tier'`, otherwise
|
|
76
|
-
* `'4-tier'`.
|
|
77
|
-
*
|
|
78
|
-
* @returns {Promise<{ sortedTasks: Array<object>, mode: '2-tier'|'4-tier' }>}
|
|
79
|
-
*/
|
|
80
|
-
export async function buildTaskGraph({ provider, logger, input }) {
|
|
81
|
-
const { storyId, storyBody = '' } = input;
|
|
82
|
-
const warn = logger?.warn ?? ((msg) => Logger.error(msg));
|
|
83
|
-
const progress = logger?.progress ?? (() => {});
|
|
84
|
-
|
|
85
|
-
// Story #4251 — under the 2-tier hierarchy every Story is childless, so the
|
|
86
|
-
// `fetchChildTickets` call (a `getTicket` + empty sub-issues GraphQL query +
|
|
87
|
-
// a never-matching `/search/issues` fallback) is pure waste on every
|
|
88
|
-
// story-init. The Story body is already in scope, so detect the inline-
|
|
89
|
-
// acceptance 2-tier shape FIRST and short-circuit without any child fetch —
|
|
90
|
-
// sparing the most aggressively rate-limited GitHub endpoint exactly during
|
|
91
|
-
// wide wave fan-out. A body lacking inline acceptance still falls through to
|
|
92
|
-
// the legacy child-enumeration path below.
|
|
93
|
-
if (hasInlineAcceptance(storyBody)) {
|
|
94
|
-
progress(
|
|
95
|
-
'TASKS',
|
|
96
|
-
`Story #${storyId} has inline acceptance — no child Tasks expected (2-tier shape).`,
|
|
97
|
-
);
|
|
98
|
-
return { sortedTasks: [], mode: '2-tier' };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Legacy / 4-tier fall-through: a body lacking inline acceptance still
|
|
102
|
-
// enumerates child Tasks for the topological sort below.
|
|
103
|
-
const tasks = await fetchChildTickets(provider, storyId);
|
|
104
|
-
|
|
105
|
-
const mode = '4-tier';
|
|
106
|
-
|
|
107
|
-
if (tasks.length === 0) {
|
|
108
|
-
warn(
|
|
109
|
-
`[story-init] Warning: Story #${storyId} has no child Tasks. The agent will need to work from the Story body directly.`,
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const sortedTasks = sortTasksByDependencies(tasks);
|
|
114
|
-
if (sortedTasks.length > 0) {
|
|
115
|
-
progress(
|
|
116
|
-
'TASKS',
|
|
117
|
-
`Found ${sortedTasks.length} child Task(s) in dependency order`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return { sortedTasks, mode };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export { sortTasksByDependencies };
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* transition-summary.js — Story-level summary of the batched task-start
|
|
3
|
-
* fanout produced by `transitionTaskStates`.
|
|
4
|
-
*
|
|
5
|
-
* Replaces the previous N-per-Task `agent::executing` GitHub-comment fanout
|
|
6
|
-
* with a single `low` notification routed to the Story. The dispatch
|
|
7
|
-
* carries no `event` field, so under the curated `commentEvents` /
|
|
8
|
-
* `webhookEvents` allowlists it never reaches either channel — init stays
|
|
9
|
-
* silent on the GitHub timeline by default. The call remains as a sentinel
|
|
10
|
-
* for operators who curate a `story-task-summary` event into their
|
|
11
|
-
* `commentEvents` allowlist (out-of-tree extension).
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {object} deps
|
|
16
|
-
* @param {Function|null} deps.notify - The standard `notify(ticketId, payload)` hook.
|
|
17
|
-
* @param {number} deps.storyId
|
|
18
|
-
* @param {number[]} deps.transitioned - IDs of Tasks that flipped to `agent::executing`.
|
|
19
|
-
* @returns {Promise<{posted: boolean, message: string|null}>}
|
|
20
|
-
*/
|
|
21
|
-
export async function postBatchedTransitionSummary({
|
|
22
|
-
notify,
|
|
23
|
-
storyId,
|
|
24
|
-
transitioned,
|
|
25
|
-
}) {
|
|
26
|
-
if (typeof notify !== 'function') return { posted: false, message: null };
|
|
27
|
-
if (!Array.isArray(transitioned) || transitioned.length === 0) {
|
|
28
|
-
return { posted: false, message: null };
|
|
29
|
-
}
|
|
30
|
-
const taskList = transitioned.map((id) => `#${id}`).join(', ');
|
|
31
|
-
const message = `Story #${storyId} · ${transitioned.length} Task(s) transitioned to \`agent::executing\`: ${taskList}`;
|
|
32
|
-
await notify(storyId, { severity: 'low', message });
|
|
33
|
-
return { posted: true, message };
|
|
34
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Epic IDs reserved for tests that create `<repo>/temp/epic-<id>/` trees (or
|
|
3
|
-
* other on-disk artefacts keyed by Epic number in the framework repo).
|
|
4
|
-
*
|
|
5
|
-
* Real GitHub Epic / issue numbers live outside this inclusive band. Tests
|
|
6
|
-
* MUST use IDs in [TEST_EPIC_TEMP_ID_MIN, TEST_EPIC_TEMP_ID_MAX] whenever they
|
|
7
|
-
* write per-Epic temp paths under the repository root so post-test cleanup and
|
|
8
|
-
* tripwire helpers never collide with real delivery scratch.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export const TEST_EPIC_TEMP_ID_MIN = 999_000;
|
|
12
|
-
export const TEST_EPIC_TEMP_ID_MAX = 999_999;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {unknown} id
|
|
16
|
-
* @returns {boolean}
|
|
17
|
-
*/
|
|
18
|
-
export function isReservedTestEpicTempId(id) {
|
|
19
|
-
return (
|
|
20
|
-
typeof id === 'number' &&
|
|
21
|
-
Number.isInteger(id) &&
|
|
22
|
-
id >= TEST_EPIC_TEMP_ID_MIN &&
|
|
23
|
-
id <= TEST_EPIC_TEMP_ID_MAX
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @param {string} dirName Directory basename, e.g. `epic-999007`
|
|
29
|
-
* @returns {boolean}
|
|
30
|
-
*/
|
|
31
|
-
export function isReservedTestEpicTempDirName(dirName) {
|
|
32
|
-
const m = /^epic-([0-9]+)$/.exec(dirName);
|
|
33
|
-
if (!m) return false;
|
|
34
|
-
return isReservedTestEpicTempId(Number(m[1]));
|
|
35
|
-
}
|