mandrel 1.58.0 → 1.60.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 +100 -98
- package/.agents/docs/SDLC.md +140 -141
- package/.agents/docs/configuration.md +16 -16
- package/.agents/docs/workflows.md +7 -8
- package/.agents/instructions.md +12 -11
- package/.agents/personas/architect.md +1 -1
- package/.agents/personas/product.md +1 -1
- package/.agents/personas/project-manager.md +14 -14
- package/.agents/personas/technical-writer.md +1 -1
- package/.agents/rules/changelog-style.md +5 -5
- package/.agents/rules/git-conventions.md +3 -3
- package/.agents/schemas/agentrc.schema.json +3 -3
- package/.agents/schemas/audit-rules.json +20 -0
- package/.agents/schemas/dispatch-manifest.json +4 -4
- package/.agents/schemas/epic-spec.schema.json +15 -45
- package/.agents/schemas/lifecycle/README.md +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/README.md +1 -1
- package/.agents/scripts/acceptance-eval.js +21 -4
- package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
- package/.agents/scripts/analyze-execution.js +2 -2
- package/.agents/scripts/assert-branch.js +1 -3
- package/.agents/scripts/audit-to-stories.js +1 -1
- package/.agents/scripts/bootstrap.js +1 -1
- package/.agents/scripts/check-arch-cycles.js +360 -0
- package/.agents/scripts/check-doc-links.js +2 -3
- package/.agents/scripts/coverage-capture.js +24 -3
- package/.agents/scripts/diagnose-friction.js +1 -1
- package/.agents/scripts/dispatcher.js +2 -2
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/epic-audit-prepare.js +3 -3
- package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
- package/.agents/scripts/epic-deliver-preflight.js +11 -9
- package/.agents/scripts/epic-deliver-prepare.js +13 -5
- package/.agents/scripts/epic-execute-record-wave.js +5 -5
- package/.agents/scripts/epic-plan-healthcheck.js +6 -10
- package/.agents/scripts/epic-plan-spec-validate.js +1 -1
- package/.agents/scripts/epic-reconcile.js +11 -29
- package/.agents/scripts/evidence-gate.js +2 -2
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/git-rebase-and-resolve.js +1 -1
- package/.agents/scripts/hierarchy-gate.js +40 -24
- package/.agents/scripts/lib/ITicketingProvider.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
- package/.agents/scripts/lib/baseline-snapshot.js +7 -7
- package/.agents/scripts/lib/baselines/kinds/coverage.js +33 -149
- package/.agents/scripts/lib/baselines/kinds/duplication.js +27 -116
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +192 -0
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +34 -133
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +31 -124
- package/.agents/scripts/lib/baselines/kinds/mutation.js +25 -111
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +59 -0
- package/.agents/scripts/lib/baselines/maintainability-baseline-save.js +37 -0
- package/.agents/scripts/lib/baselines/writer.js +1 -1
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/close-validation/commands.js +188 -0
- package/.agents/scripts/lib/close-validation/gates.js +235 -0
- package/.agents/scripts/lib/close-validation/process.js +101 -0
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +1 -1
- package/.agents/scripts/lib/close-validation/runner.js +325 -0
- package/.agents/scripts/lib/close-validation/telemetry.js +70 -0
- package/.agents/scripts/lib/codebase-snapshot.js +1 -1
- package/.agents/scripts/lib/config/explain.js +1 -1
- package/.agents/scripts/lib/config/quality.js +6 -6
- package/.agents/scripts/lib/config/runners.js +2 -2
- package/.agents/scripts/lib/config/runtime.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-resolver.js +2 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
- package/.agents/scripts/lib/config-settings-schema.js +3 -3
- package/.agents/scripts/lib/coverage-capture.js +147 -4
- package/.agents/scripts/lib/cpu-pool.js +14 -0
- package/.agents/scripts/lib/crap-utils.js +6 -11
- package/.agents/scripts/lib/duplicate-search.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +87 -0
- package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
- package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +10 -10
- package/.agents/scripts/lib/git-utils.js +24 -22
- package/.agents/scripts/lib/label-constants.js +3 -4
- package/.agents/scripts/lib/label-taxonomy.js +3 -8
- package/.agents/scripts/lib/maintainability-engine.js +1 -1
- package/.agents/scripts/lib/maintainability-utils.js +4 -187
- package/.agents/scripts/lib/observability/perf-report-readers.js +32 -23
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +81 -7
- package/.agents/scripts/lib/orchestration/code-review.js +95 -82
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
- package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +14 -37
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +22 -22
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +206 -58
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +27 -3
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +28 -8
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +13 -41
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +2 -3
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -8
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +103 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +22 -64
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +38 -76
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +10 -10
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +8 -20
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
- package/.agents/scripts/lib/orchestration/file-assumptions.js +6 -5
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +144 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +3 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +8 -8
- package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +3 -3
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +7 -7
- package/.agents/scripts/lib/orchestration/preflight-cache.js +36 -13
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
- package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
- package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +5 -60
- package/.agents/scripts/lib/orchestration/review-providers/native.js +7 -6
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +105 -0
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +7 -59
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +2 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +2 -4
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +32 -35
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +1 -2
- package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +451 -503
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +8 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +47 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +2 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +358 -54
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +3 -2
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +32 -5
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +5 -18
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +3 -3
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +33 -16
- package/.agents/scripts/lib/orchestration/story-reachability.js +47 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
- package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +4 -35
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
- package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +44 -73
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +16 -7
- package/.agents/scripts/lib/orchestration/ticketing/state.js +53 -439
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +471 -0
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +3 -3
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +2 -8
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +1 -1
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
- package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
- package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
- package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
- package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
- package/.agents/scripts/lib/project-root.js +17 -0
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/spec/index.js +1 -1
- package/.agents/scripts/lib/spec/loader.js +2 -2
- package/.agents/scripts/lib/spec/state.js +7 -16
- package/.agents/scripts/lib/story-adjacency.js +76 -0
- package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
- package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
- package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
- package/.agents/scripts/lib/story-lifecycle.js +9 -9
- package/.agents/scripts/lib/story-plan.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
- package/.agents/scripts/lib/transpile.js +93 -0
- package/.agents/scripts/lib/wave-runner/tick.js +4 -153
- package/.agents/scripts/lib/workers/crap-worker.js +1 -1
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +20 -2
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +90 -0
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +26 -8
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +74 -0
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
- package/.agents/scripts/lifecycle-emit.js +1 -1
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/mappers.js +2 -2
- package/.agents/scripts/providers/github/tickets.js +114 -10
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/retro-run.js +2 -2
- package/.agents/scripts/run-lint.js +10 -1
- package/.agents/scripts/run-tests.js +24 -4
- package/.agents/scripts/single-story-init.js +1 -1
- package/.agents/scripts/stories-wave-tick.js +13 -10
- package/.agents/scripts/story-close.js +1 -1
- package/.agents/scripts/story-init.js +162 -26
- package/.agents/scripts/story-phase.js +5 -5
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/sync-branch-from-base.js +2 -2
- package/.agents/scripts/validate-docs-freshness.js +1 -1
- package/.agents/scripts/wave-tick.js +1 -1
- package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
- package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
- package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
- package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
- package/.agents/skills/core/scope-triage/SKILL.md +9 -10
- package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
- package/.agents/skills/skills.index.json +7 -7
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +1 -1
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/workflows/agents-update.md +2 -2
- package/.agents/workflows/audit-architecture.md +2 -2
- package/.agents/workflows/audit-clean-code.md +2 -2
- package/.agents/workflows/audit-dependencies.md +1 -1
- package/.agents/workflows/audit-devops.md +1 -1
- package/.agents/workflows/audit-documentation.md +226 -0
- package/.agents/workflows/audit-lighthouse.md +1 -1
- package/.agents/workflows/audit-performance.md +2 -2
- package/.agents/workflows/audit-privacy.md +1 -1
- package/.agents/workflows/audit-quality.md +2 -2
- package/.agents/workflows/audit-security.md +2 -2
- package/.agents/workflows/audit-seo.md +1 -1
- package/.agents/workflows/audit-sre.md +1 -1
- package/.agents/workflows/audit-to-stories.md +10 -10
- package/.agents/workflows/audit-ux-ui.md +1 -1
- package/.agents/workflows/deliver.md +85 -0
- package/.agents/workflows/explain.md +3 -3
- package/.agents/workflows/git-merge-pr.md +1 -1
- package/.agents/workflows/git-pr-all.md +13 -10
- package/.agents/workflows/git-push.md +6 -3
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
- package/.agents/workflows/helpers/code-review.md +5 -5
- package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +59 -66
- package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
- package/.agents/workflows/helpers/diagnose.md +1 -1
- package/.agents/workflows/helpers/epic-audit.md +6 -6
- package/.agents/workflows/helpers/epic-deliver-story.md +28 -39
- package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
- package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
- package/.agents/workflows/helpers/epic-testing.md +3 -3
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
- package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
- package/.agents/workflows/helpers/signals.md +1 -1
- package/.agents/workflows/helpers/single-story-deliver.md +12 -11
- package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
- package/.agents/workflows/onboard.md +21 -20
- package/.agents/workflows/plan.md +89 -0
- package/.agents/workflows/qa-explore.md +1 -1
- package/.agents/workflows/qa-run-harness.md +1 -1
- package/README.md +17 -20
- package/docs/CHANGELOG.md +1149 -0
- package/lib/cli/__tests__/update-changelog-surface.test.js +357 -0
- package/lib/cli/__tests__/update-reexec.test.js +513 -0
- package/lib/cli/init.js +338 -0
- package/lib/cli/update.js +413 -52
- package/package.json +3 -1
- package/.agents/scripts/lib/auto-refresh-baselines.js +0 -308
- package/.agents/scripts/lib/close-validation.js +0 -897
- package/.agents/scripts/lib/orchestration/cascade-grouping.js +0 -275
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +0 -69
- package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +0 -221
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +0 -123
- package/.agents/scripts/lib/task-utils.js +0 -26
- package/.agents/scripts/story-deliver-prepare.js +0 -267
|
@@ -163,7 +163,7 @@ function getVersion() {
|
|
|
163
163
|
/**
|
|
164
164
|
* Parse the work-breakdown hierarchy from a Task ticket body.
|
|
165
165
|
*
|
|
166
|
-
* Looks for patterns like: `Epic: #1`, `
|
|
166
|
+
* Looks for patterns like: `Epic: #1`, `Story: #3`,
|
|
167
167
|
* `PRD: #4`, `Tech Spec: #5`.
|
|
168
168
|
*
|
|
169
169
|
* @param {string} body
|
|
@@ -177,7 +177,7 @@ export function parseHierarchy(body) {
|
|
|
177
177
|
for (const match of matches) {
|
|
178
178
|
const key = match[1].trim().toLowerCase().replace(/\s+/g, '');
|
|
179
179
|
const val = Number.parseInt(match[2], 10);
|
|
180
|
-
result[key] = val; // e.g. { epic: 1,
|
|
180
|
+
result[key] = val; // e.g. { epic: 1, story: 3, prd: 4, techspec: 5 }
|
|
181
181
|
}
|
|
182
182
|
return result;
|
|
183
183
|
}
|
|
@@ -217,9 +217,9 @@ function extractSectionList(body, heading) {
|
|
|
217
217
|
|
|
218
218
|
/**
|
|
219
219
|
* Extract the inline `## Acceptance` / `## Acceptance Criteria` and
|
|
220
|
-
* `## Verify` checklists from a Story body. Used by
|
|
220
|
+
* `## Verify` checklists from a Story body. Used by 2-tier hydration to
|
|
221
221
|
* populate the `acceptanceCriteria` and `verificationCommands` envelope
|
|
222
|
-
* sections directly from the dispatched Story ticket — under
|
|
222
|
+
* sections directly from the dispatched Story ticket — under 2-tier the
|
|
223
223
|
* Story IS the unit of execution and carries acceptance/verify inline
|
|
224
224
|
* (no child tickets to walk).
|
|
225
225
|
*
|
|
@@ -235,18 +235,18 @@ export function extractStorySections(body) {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
/**
|
|
238
|
-
* Detect whether the dispatched unit is a
|
|
238
|
+
* Detect whether the dispatched unit is a 2-tier Story (Story is the
|
|
239
239
|
* leaf, carries inline acceptance/verify) vs. a 4-tier Task (Task is
|
|
240
240
|
* the leaf, Story is one level up). The decision is made off the
|
|
241
241
|
* `type::*` label the dispatcher already stamps on every ticket; it
|
|
242
242
|
* does not depend on `planning.hierarchy`, so this engine
|
|
243
|
-
* stays correct even when a 4-tier Epic ships in a
|
|
243
|
+
* stays correct even when a 4-tier Epic ships in a 2-tier-default repo
|
|
244
244
|
* (or vice versa) during the Epic #3078 dual-shape window.
|
|
245
245
|
*
|
|
246
246
|
* @param {object} task
|
|
247
247
|
* @returns {boolean}
|
|
248
248
|
*/
|
|
249
|
-
function
|
|
249
|
+
function isTwoTierStoryTask(task) {
|
|
250
250
|
const labels = task?.labels ?? [];
|
|
251
251
|
return labels.includes('type::story');
|
|
252
252
|
}
|
|
@@ -355,7 +355,6 @@ async function buildHierarchySections(task, provider, epicId, agentSettings) {
|
|
|
355
355
|
idsToFetch.push({ key: 'Epic', id: epicId || hierarchyKeys.epic });
|
|
356
356
|
idsToFetch.push({ key: 'PRD', id: hierarchyKeys.prd });
|
|
357
357
|
idsToFetch.push({ key: 'Tech Spec', id: hierarchyKeys.techspec });
|
|
358
|
-
idsToFetch.push({ key: 'Feature', id: hierarchyKeys.feature });
|
|
359
358
|
idsToFetch.push({ key: 'Story', id: hierarchyKeys.story });
|
|
360
359
|
} else if (depth === 'standard') {
|
|
361
360
|
idsToFetch.push({ key: 'Epic', id: epicId || hierarchyKeys.epic });
|
|
@@ -475,7 +474,7 @@ function buildStaticSections(
|
|
|
475
474
|
}
|
|
476
475
|
}
|
|
477
476
|
|
|
478
|
-
if (
|
|
477
|
+
if (isTwoTierStoryTask(task)) {
|
|
479
478
|
const { acceptance, verify } = extractStorySections(task.body ?? '');
|
|
480
479
|
if (acceptance.length > 0) {
|
|
481
480
|
sections.push({
|
|
@@ -6,8 +6,8 @@ import { assignLayers, detectCycle } from '../Graph.js';
|
|
|
6
6
|
*
|
|
7
7
|
* Sources of story dependencies:
|
|
8
8
|
* 1. **Implicit (cross-story tasks)**: Task T in Story A depends on Task T'
|
|
9
|
-
* in Story B → Story A depends on Story B. Under the
|
|
10
|
-
* (Epic →
|
|
9
|
+
* in Story B → Story A depends on Story B. Under the 2-tier hierarchy
|
|
10
|
+
* (Epic → Story) Stories carry no child Tasks, so this source
|
|
11
11
|
* is empty in practice; it is retained for callers that adapt a
|
|
12
12
|
* task-bearing shape into `storyGroups`.
|
|
13
13
|
* 2. **Explicit (story body)**: Story A body contains `blocked by #B` →
|
|
@@ -18,7 +18,7 @@ import { assignLayers, detectCycle } from '../Graph.js';
|
|
|
18
18
|
* > **Focus-overlap engine removed (Story #3906).** A third source — a
|
|
19
19
|
* > focus-area overlap engine that rolled task-level `focusAreas` / `scope`
|
|
20
20
|
* > up to the Story level and serialized "overlapping" Stories — was deleted
|
|
21
|
-
* > because Task deletion in the
|
|
21
|
+
* > because Task deletion in the 2-tier migration left every Story's task
|
|
22
22
|
* > list empty, so the rollup produced empty focus bags and the engine added
|
|
23
23
|
* > **zero** edges on every real plan. It advertised file-contention
|
|
24
24
|
* > serialization it never delivered. Cross-Story prerequisites are carried
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
* (`detectors: rework=N retry=M`) is the only stdout signal — one
|
|
30
30
|
* line per Story rather than two per detector + N per event.
|
|
31
31
|
*
|
|
32
|
-
* - **
|
|
33
|
-
* empty (the
|
|
32
|
+
* - **2-tier (Storyless) closure (Story #3127).** When `tasks` is
|
|
33
|
+
* empty (the 2-tier hierarchy shape), `resolveLastTaskId` returns
|
|
34
34
|
* `null` and both detectors run with `taskId: null`. The detector
|
|
35
35
|
* modules already accept a nullable `taskId` (see
|
|
36
36
|
* `lib/signals/detectors/{rework,retry}.js`), so no branching on
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Thin facade composing:
|
|
5
5
|
* - `dispatch-pipeline.js` — internal resolve/fetch/reconcile/graph helpers
|
|
6
6
|
*
|
|
7
|
-
* Every Epic is
|
|
8
|
-
* Story-level wave plan and emits a
|
|
7
|
+
* Every Epic is 2-tier (Epic → Story); `dispatch()` computes a
|
|
8
|
+
* Story-level wave plan and emits a 2-tier manifest. The legacy Task-tier
|
|
9
9
|
* dispatch runtime (Task fetcher, single-Story executor, the per-Task
|
|
10
10
|
* wave fan-out, and the Epic-completion detector) was removed in Epic
|
|
11
11
|
* #3163.
|
|
@@ -20,8 +20,7 @@ import { createProvider } from '../provider-factory.js';
|
|
|
20
20
|
import {
|
|
21
21
|
buildStoryDispatchGraph,
|
|
22
22
|
fetchEpicContext,
|
|
23
|
-
|
|
24
|
-
reconcileEpicState,
|
|
23
|
+
isTwoTierDispatch,
|
|
25
24
|
resolveDispatchContext,
|
|
26
25
|
} from './dispatch-pipeline.js';
|
|
27
26
|
import { buildManifest } from './manifest-builder.js';
|
|
@@ -60,14 +59,13 @@ export async function resolveAndDispatch(options) {
|
|
|
60
59
|
|
|
61
60
|
const isStory = labels.includes(TYPE_LABELS.STORY);
|
|
62
61
|
const isEpic = labels.includes(TYPE_LABELS.EPIC);
|
|
63
|
-
const isFeature = labels.includes(TYPE_LABELS.FEATURE);
|
|
64
62
|
|
|
65
63
|
if (isStory) {
|
|
66
64
|
throw new Error(
|
|
67
65
|
`[Dispatcher] Ticket #${ticketId} is a **Story**. Stories are dispatched ` +
|
|
68
|
-
'through the
|
|
69
|
-
`Run \`/
|
|
70
|
-
`or dispatch its parent Epic with \`/
|
|
66
|
+
'through the Story delivery path, not directly via the dispatcher. ' +
|
|
67
|
+
`Run \`/deliver ${ticketId}\` to execute this Story, ` +
|
|
68
|
+
`or dispatch its parent Epic with \`/deliver #<epicId>\`.`,
|
|
71
69
|
);
|
|
72
70
|
}
|
|
73
71
|
|
|
@@ -75,14 +73,6 @@ export async function resolveAndDispatch(options) {
|
|
|
75
73
|
return dispatch({ epicId: ticketId, dryRun, provider });
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
if (isFeature) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
`[Dispatcher] Ticket #${ticketId} is a **Feature**. Features are containers and cannot be executed directly. ` +
|
|
81
|
-
`Please execute individual Stories within this Feature using \`/epic-deliver #[Story ID]\`, ` +
|
|
82
|
-
`or dispatch the entire Epic using \`/epic-deliver #${ticket.body?.match(/^parent:\s*#(\d+)/m)?.[1] || 'ID'}\`.`,
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
76
|
const typeLabel = labels.find((l) => l.startsWith('type::')) || 'unknown';
|
|
87
77
|
throw new Error(
|
|
88
78
|
`[Dispatcher] Ticket #${ticketId} has type "${typeLabel.replace('type::', '')}". ` +
|
|
@@ -100,17 +90,16 @@ export async function dispatch(options) {
|
|
|
100
90
|
const { epicId, dryRun } = ctx;
|
|
101
91
|
|
|
102
92
|
const fetched = await fetchEpicContext(ctx);
|
|
103
|
-
await reconcileEpicState(ctx, fetched);
|
|
104
93
|
|
|
105
|
-
// Every Epic is
|
|
106
|
-
// waves directly from the Story tickets and emit a
|
|
94
|
+
// Every Epic is 2-tier (Epic → Story). Compute Story-level
|
|
95
|
+
// waves directly from the Story tickets and emit a 2-tier-shaped
|
|
107
96
|
// manifest with `waves[].stories[]` so downstream consumers (manifest
|
|
108
|
-
// renderer, /
|
|
109
|
-
// Per-Story execution is owned by `/
|
|
97
|
+
// renderer, /deliver wave planner) see the correct execution plan.
|
|
98
|
+
// Per-Story execution is owned by `/deliver` (story-init →
|
|
110
99
|
// story-close), not by this dispatcher.
|
|
111
|
-
if (
|
|
100
|
+
if (isTwoTierDispatch(fetched.allTickets)) {
|
|
112
101
|
Logger.info(
|
|
113
|
-
'Detected
|
|
102
|
+
'Detected 2-tier hierarchy — computing Story-level execution waves.',
|
|
114
103
|
);
|
|
115
104
|
const { allWaves: storyWaves } = buildStoryDispatchGraph(
|
|
116
105
|
fetched.allTickets,
|
|
@@ -123,22 +112,25 @@ export async function dispatch(options) {
|
|
|
123
112
|
waves: storyWaves,
|
|
124
113
|
dispatched: [],
|
|
125
114
|
dryRun,
|
|
126
|
-
hierarchy: '
|
|
115
|
+
hierarchy: '2-tier',
|
|
127
116
|
});
|
|
128
117
|
}
|
|
129
118
|
|
|
130
|
-
// No Story tickets under the Epic —
|
|
131
|
-
// manifest
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
119
|
+
// No Story tickets under the Epic — throw loudly rather than emit an
|
|
120
|
+
// empty manifest, matching the wave-loop's behavior (build-wave-dag.js
|
|
121
|
+
// throws the same message shape on this input). A silently-empty
|
|
122
|
+
// manifest masks a pre-cutover Epic whose children are legacy Features.
|
|
123
|
+
const typedChildren = (fetched.allTickets ?? [])
|
|
124
|
+
.map((t) => (t.labels ?? []).find((l) => l.startsWith('type::')))
|
|
125
|
+
.filter(Boolean);
|
|
126
|
+
const legacyHint =
|
|
127
|
+
typedChildren.length > 0
|
|
128
|
+
? ` Found ${typedChildren.length} non-Story child ticket(s) ` +
|
|
129
|
+
`(${[...new Set(typedChildren)].join(', ')}) — this Epic looks ` +
|
|
130
|
+
`pre-cutover (legacy Feature children) and needs migration to the ` +
|
|
131
|
+
`2-tier (Epic → Story) hierarchy before dispatch.`
|
|
132
|
+
: '';
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Epic #${epicId} has no child stories to dispatch.${legacyHint}`,
|
|
135
|
+
);
|
|
144
136
|
}
|
|
@@ -3,24 +3,23 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Internal pipeline helpers composed by `dispatch-engine.js::dispatch()`.
|
|
5
5
|
* Keeping these out of the coordinator keeps the public entry point compact
|
|
6
|
-
* and focused on the
|
|
6
|
+
* and focused on the 2-tier flow: resolve → fetch → Story-graph.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { PROJECT_ROOT, resolveConfig } from '../config-resolver.js';
|
|
10
|
-
import { parseBlockedBy } from '../dependency-parser.js';
|
|
11
10
|
import { getEpicBranch } from '../git-utils.js';
|
|
12
11
|
import { Logger } from '../Logger.js';
|
|
13
12
|
import { TYPE_LABELS } from '../label-constants.js';
|
|
14
13
|
import { createProvider } from '../provider-factory.js';
|
|
14
|
+
import { buildStoryAdjacency } from '../story-adjacency.js';
|
|
15
15
|
import { WorktreeManager } from '../worktree-manager.js';
|
|
16
16
|
import { computeStoryWaves } from './dependency-analyzer.js';
|
|
17
|
-
import { reconcileHierarchy } from './reconciler.js';
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Runtime context for a single dispatch cycle.
|
|
21
20
|
*
|
|
22
21
|
* Produced by {@link resolveDispatchContext} and consumed by every pipeline
|
|
23
|
-
* stage (fetch →
|
|
22
|
+
* stage (fetch → graph → scaffold → GC → dispatch). All fields
|
|
24
23
|
* are resolved once up-front so downstream helpers can stay free of
|
|
25
24
|
* configuration look-ups.
|
|
26
25
|
*
|
|
@@ -40,7 +39,7 @@ import { reconcileHierarchy } from './reconciler.js';
|
|
|
40
39
|
*
|
|
41
40
|
* @typedef {object} FetchedEpic
|
|
42
41
|
* @property {object} epic The Epic ticket record.
|
|
43
|
-
* @property {object[]} allTickets Every ticket under the Epic (stories +
|
|
42
|
+
* @property {object[]} allTickets Every ticket under the Epic (stories + health).
|
|
44
43
|
* @property {Map<number, object>} allTicketsById Index of `allTickets` by ticket id.
|
|
45
44
|
*/
|
|
46
45
|
|
|
@@ -106,30 +105,15 @@ export async function fetchEpicContext(ctx) {
|
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
/**
|
|
109
|
-
*
|
|
110
|
-
* reality before dispatch. Walks Stories → Features bottom-up.
|
|
111
|
-
*
|
|
112
|
-
* @param {DispatchContext} ctx Dispatch context.
|
|
113
|
-
* @param {FetchedEpic} fetched Result of {@link fetchEpicContext}.
|
|
114
|
-
* @returns {Promise<void>}
|
|
115
|
-
*/
|
|
116
|
-
export async function reconcileEpicState(ctx, fetched) {
|
|
117
|
-
const { provider, dryRun, epicId } = ctx;
|
|
118
|
-
const { epic, allTickets } = fetched;
|
|
119
|
-
|
|
120
|
-
await reconcileHierarchy(provider, epicId, epic, allTickets, dryRun);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Detect 3-tier hierarchy from the fetched ticket graph. After Epic #3163's
|
|
108
|
+
* Detect 2-tier hierarchy from the fetched ticket graph. After Epic #3163's
|
|
125
109
|
* hard cutover deleted the `type::task` ticket layer, shape selection is
|
|
126
110
|
* purely structural: any Epic carrying at least one `type::story` ticket
|
|
127
|
-
* resolves to
|
|
111
|
+
* resolves to 2-tier.
|
|
128
112
|
*
|
|
129
113
|
* @param {object[]} allTickets
|
|
130
114
|
* @returns {boolean}
|
|
131
115
|
*/
|
|
132
|
-
export function
|
|
116
|
+
export function isTwoTierDispatch(allTickets) {
|
|
133
117
|
if (!Array.isArray(allTickets) || allTickets.length === 0) return false;
|
|
134
118
|
return allTickets.some((t) =>
|
|
135
119
|
(t.labelSet ?? new Set(t.labels ?? [])).has(TYPE_LABELS.STORY),
|
|
@@ -137,7 +121,7 @@ export function isThreeTierDispatch(allTickets) {
|
|
|
137
121
|
}
|
|
138
122
|
|
|
139
123
|
/**
|
|
140
|
-
* Build the Story-level dispatch graph for a
|
|
124
|
+
* Build the Story-level dispatch graph for a 2-tier Epic. Reads story
|
|
141
125
|
* tickets from `allTickets`, parses cross-Story `blocked by` references
|
|
142
126
|
* from each Story body (also honoring an optional `dependencies[]`
|
|
143
127
|
* field set by fixture providers), and computes wave indices via
|
|
@@ -151,7 +135,7 @@ export function isThreeTierDispatch(allTickets) {
|
|
|
151
135
|
* are placed in their own trailing wave so they remain visible in the
|
|
152
136
|
* manifest output.
|
|
153
137
|
*
|
|
154
|
-
* @param {object[]} allTickets Fetched ticket graph (Epic +
|
|
138
|
+
* @param {object[]} allTickets Fetched ticket graph (Epic + Stories).
|
|
155
139
|
* @returns {{ allWaves: object[][], storyMap: Map<number, object> }}
|
|
156
140
|
* @throws {Error} When the Story dependency graph contains a cycle.
|
|
157
141
|
*/
|
|
@@ -161,17 +145,10 @@ export function buildStoryDispatchGraph(allTickets) {
|
|
|
161
145
|
);
|
|
162
146
|
const storyMap = new Map(stories.map((s) => [s.id, s]));
|
|
163
147
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
? story.dependencies.map(Number)
|
|
169
|
-
: [];
|
|
170
|
-
const merged = [...new Set([...fromBody, ...fromField])].filter(
|
|
171
|
-
(id) => Number.isInteger(id) && id !== story.id && storyMap.has(id),
|
|
172
|
-
);
|
|
173
|
-
if (merged.length > 0) explicitDeps.set(story.id, merged);
|
|
174
|
-
}
|
|
148
|
+
// Shared story-level adjacency builder (lib/story-adjacency.js) owns the
|
|
149
|
+
// dependency-source ordering contract: body `blocked by` references via
|
|
150
|
+
// `parseBlockedBy`, then explicit `dependencies[]`, foreign edges dropped.
|
|
151
|
+
const explicitDeps = buildStoryAdjacency(stories);
|
|
175
152
|
|
|
176
153
|
// computeStoryWaves expects a Map<storyId, { tasks: [] }>; with no Tasks
|
|
177
154
|
// present, only explicitDeps + focus-area rollup (no-op for empty
|
|
@@ -200,7 +177,7 @@ export function buildStoryDispatchGraph(allTickets) {
|
|
|
200
177
|
if (byWave.has(-1)) allWaves.push(byWave.get(-1));
|
|
201
178
|
|
|
202
179
|
Logger.info(
|
|
203
|
-
`Computed ${allWaves.length} Story-level execution wave(s) (
|
|
180
|
+
`Computed ${allWaves.length} Story-level execution wave(s) (2-tier).`,
|
|
204
181
|
);
|
|
205
182
|
return { allWaves, storyMap };
|
|
206
183
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* node:coverage ignore file -- MI 0 orchestration glue; reaps live worktrees + runs `git branch -D` — testing requires mocking real worktree/git state to the point of asserting only the mock structure */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Epic-cleanup primitives — local branch + worktree reap for `/
|
|
4
|
+
* Epic-cleanup primitives — local branch + worktree reap for `/deliver`
|
|
5
5
|
* Phase 8.
|
|
6
6
|
*
|
|
7
7
|
* Once a PR has merged (auto or operator-button), the Epic branch and every
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* epic-deliver-lease-guard.js — preflight guards for `/
|
|
2
|
+
* epic-deliver-lease-guard.js — preflight guards for `/deliver`
|
|
3
3
|
* (Story #3482, Epic #3457).
|
|
4
4
|
*
|
|
5
|
-
* `/
|
|
5
|
+
* `/deliver`'s prepare phase used to checkout `epic/<id>` over whatever
|
|
6
6
|
* the operator had checked out, yanking HEAD and resetting baselines under a
|
|
7
7
|
* live working session (the documented "epic-deliver shares the main checkout"
|
|
8
8
|
* footgun). This module supplies the two preflight guards the Tech Spec
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
* `process.exit(1)` by the `runAsCli` boundary), never `Logger.fatal`.
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
acquireLeaseFailClosed,
|
|
34
|
+
resolveOperatorFromCandidates,
|
|
35
|
+
} from './lease-guard-shared.js';
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* Resolve the acquiring operator's identity. Precedence (Tech Spec #3476):
|
|
@@ -37,8 +40,11 @@ import { acquireLease, normalizeOperatorHandle } from './ticket-lease.js';
|
|
|
37
40
|
* 2. `github.operatorHandle` in `.agentrc.json`.
|
|
38
41
|
* 3. The local `git config user.email`.
|
|
39
42
|
*
|
|
40
|
-
* The `@`-prefix some operators carry on `operatorHandle` is stripped
|
|
41
|
-
* value matches the bare login written
|
|
43
|
+
* The `@`-prefix some operators carry on `operatorHandle` is stripped (via
|
|
44
|
+
* the shared lease-guard kernel) so the value matches the bare login written
|
|
45
|
+
* to a ticket's `assignees`. This surface's missing-handle policy is `'null'`
|
|
46
|
+
* — `runPrepareGuards` fails closed on a null operator with deliver-specific
|
|
47
|
+
* wording after the (cheap, local) checkout-safety guard has run.
|
|
42
48
|
*
|
|
43
49
|
* @param {object} args
|
|
44
50
|
* @param {string} [args.asFlag] Explicit `--as` value.
|
|
@@ -48,16 +54,13 @@ import { acquireLease, normalizeOperatorHandle } from './ticket-lease.js';
|
|
|
48
54
|
* be determined.
|
|
49
55
|
*/
|
|
50
56
|
export function resolveOperator({ asFlag, config, gitUserEmail } = {}) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (normalized !== null) return normalized;
|
|
55
|
-
}
|
|
56
|
-
return null;
|
|
57
|
+
return resolveOperatorFromCandidates({
|
|
58
|
+
candidates: [asFlag, config?.github?.operatorHandle, gitUserEmail],
|
|
59
|
+
});
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
/**
|
|
60
|
-
* Normalise the expected-branch argument into a non-empty list. `/
|
|
63
|
+
* Normalise the expected-branch argument into a non-empty list. `/deliver`
|
|
61
64
|
* may legitimately start from either the Epic integration branch (`epic/<id>`,
|
|
62
65
|
* on a resume) or the project base branch (`main`, on a fresh run), so the
|
|
63
66
|
* guard accepts a set rather than a single name.
|
|
@@ -150,20 +153,20 @@ export function renderCheckoutRefusal(result) {
|
|
|
150
153
|
if (result.reason === 'dirty') {
|
|
151
154
|
return (
|
|
152
155
|
`[epic-deliver] Refusing to start: the working tree is dirty. ` +
|
|
153
|
-
`/
|
|
156
|
+
`/deliver will not check out ${expected} over uncommitted ` +
|
|
154
157
|
`or untracked changes — commit, stash, or clean them, then re-run.\n` +
|
|
155
158
|
`--- dirty entries ---\n${result.dirtyEntries ?? '(unavailable)'}`
|
|
156
159
|
);
|
|
157
160
|
}
|
|
158
161
|
if (result.reason === 'detached-head') {
|
|
159
162
|
return (
|
|
160
|
-
`[epic-deliver] Refusing to start: HEAD is detached. /
|
|
163
|
+
`[epic-deliver] Refusing to start: HEAD is detached. /deliver ` +
|
|
161
164
|
`expects HEAD on ${expected}. Check one out before re-running.`
|
|
162
165
|
);
|
|
163
166
|
}
|
|
164
167
|
return (
|
|
165
168
|
`[epic-deliver] Refusing to start: HEAD is on '${result.currentBranch}', ` +
|
|
166
|
-
`not the expected ${expected}. /
|
|
169
|
+
`not the expected ${expected}. /deliver will not yank HEAD ` +
|
|
167
170
|
`away from your branch — switch to ${expected} yourself before re-running.`
|
|
168
171
|
);
|
|
169
172
|
}
|
|
@@ -179,7 +182,7 @@ export function renderLeaseRefusal(lease, epicId) {
|
|
|
179
182
|
return (
|
|
180
183
|
`[epic-deliver] Refusing to start: Epic #${epicId} is already claimed by ` +
|
|
181
184
|
`'${lease.owner}' with a live lease (recent heartbeat within the TTL). ` +
|
|
182
|
-
`Another /
|
|
185
|
+
`Another /deliver run is driving this Epic. Wait for it to finish, ` +
|
|
183
186
|
`or pass --steal to forcibly transfer the claim.`
|
|
184
187
|
);
|
|
185
188
|
}
|
|
@@ -208,7 +211,7 @@ export async function acquireEpicLease({
|
|
|
208
211
|
config,
|
|
209
212
|
now,
|
|
210
213
|
}) {
|
|
211
|
-
|
|
214
|
+
return acquireLeaseFailClosed({
|
|
212
215
|
provider,
|
|
213
216
|
ticketId: epicId,
|
|
214
217
|
operator,
|
|
@@ -216,11 +219,8 @@ export async function acquireEpicLease({
|
|
|
216
219
|
steal,
|
|
217
220
|
config,
|
|
218
221
|
now,
|
|
222
|
+
renderRefusal: renderLeaseRefusal,
|
|
219
223
|
});
|
|
220
|
-
if (!result.acquired) {
|
|
221
|
-
throw new Error(renderLeaseRefusal(result, epicId));
|
|
222
|
-
}
|
|
223
|
-
return result;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/**
|
|
@@ -281,7 +281,7 @@ export async function runPrepareGuards({
|
|
|
281
281
|
'[epic-deliver] Refusing to start: no operator identity could be ' +
|
|
282
282
|
'resolved. --as, github.operatorHandle (unset or still the shipped ' +
|
|
283
283
|
'`@[USERNAME]` placeholder), and git user.email are all empty, so the ' +
|
|
284
|
-
'Epic-lease has no owner and concurrent /
|
|
284
|
+
'Epic-lease has no owner and concurrent /deliver runs cannot be ' +
|
|
285
285
|
'serialised. Set your own handle in .agentrc.local.json (e.g. ' +
|
|
286
286
|
'{ "github": { "operatorHandle": "@your-login" } }), pass --as <handle>, ' +
|
|
287
287
|
'or configure git user.email, then re-run.',
|
|
@@ -69,6 +69,6 @@ export function warnTicketCapNearLimit(
|
|
|
69
69
|
) {
|
|
70
70
|
if (tickets.length < maxTickets) return;
|
|
71
71
|
logger.warn(
|
|
72
|
-
`[${tag}] ⚠️ Received ${tickets.length} tickets against a reviewability budget of ${maxTickets}. Review the
|
|
72
|
+
`[${tag}] ⚠️ Received ${tickets.length} tickets against a reviewability budget of ${maxTickets}. Review the Story decomposition before persisting; over-budget persistence requires --allow-over-budget.`,
|
|
73
73
|
);
|
|
74
74
|
}
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Owns the deterministic DAG helpers used by the reconciler pipeline:
|
|
5
5
|
* - `resolveDependencies(ticket, slugMap)`
|
|
6
|
-
* - `orderTicketsForCreation(validated)` (topological sort
|
|
7
|
-
*
|
|
8
|
-
* order so parents always exist before their children get created)
|
|
6
|
+
* - `orderTicketsForCreation(validated)` (topological sort of the
|
|
7
|
+
* Story set so dependency producers are created before consumers)
|
|
9
8
|
*
|
|
10
9
|
* Extracted verbatim from `epic-plan-decompose.js` so the named exports
|
|
11
10
|
* (`resolveDependencies`, `orderTicketsForCreation`) that the
|
|
@@ -53,26 +52,13 @@ function topoSortGroup(group) {
|
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
/**
|
|
56
|
-
* Topologically sort
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
55
|
+
* Topologically sort the Story set so intra-set dep chains resolve
|
|
56
|
+
* before their dependents are created. The 2-tier hierarchy has a
|
|
57
|
+
* single ticket type (story) attached directly to the Epic, so there
|
|
58
|
+
* is no parent-type ordering to interleave.
|
|
60
59
|
*/
|
|
61
60
|
export function orderTicketsForCreation(validated) {
|
|
62
|
-
const typeOrder = { feature: 0, story: 1, task: 2 };
|
|
63
|
-
const groups = new Map();
|
|
64
|
-
for (const t of validated) {
|
|
65
|
-
const parentKey = t.parent_slug ?? '__epic__';
|
|
66
|
-
const key = `${t.type}::${parentKey}`;
|
|
67
|
-
if (!groups.has(key)) groups.set(key, { type: t.type, items: [] });
|
|
68
|
-
groups.get(key).items.push(t);
|
|
69
|
-
}
|
|
70
|
-
const ordered = [...groups.values()].sort(
|
|
71
|
-
(a, b) => typeOrder[a.type] - typeOrder[b.type],
|
|
72
|
-
);
|
|
73
61
|
const result = [];
|
|
74
|
-
for (const
|
|
75
|
-
for (const t of topoSortGroup(group.items)) result.push(t);
|
|
76
|
-
}
|
|
62
|
+
for (const t of topoSortGroup([...validated])) result.push(t);
|
|
77
63
|
return result;
|
|
78
64
|
}
|
|
@@ -16,8 +16,8 @@ import { TYPE_LABELS } from '../../../label-constants.js';
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Count open child tickets under the Epic without distinguishing by
|
|
19
|
-
* type. Under the
|
|
20
|
-
* tickets are always
|
|
19
|
+
* type. Under the 2-tier hierarchy (Epic → Story), child
|
|
20
|
+
* tickets are always Stories.
|
|
21
21
|
*/
|
|
22
22
|
async function emitOpenChildrenDiagnostic(provider, epicId) {
|
|
23
23
|
if (typeof provider.getSubTickets !== 'function') return;
|
|
@@ -27,7 +27,7 @@ async function emitOpenChildrenDiagnostic(provider, epicId) {
|
|
|
27
27
|
// closed children) yields the same open-child count without paging
|
|
28
28
|
// every issue in the repo.
|
|
29
29
|
const existing = await provider.getSubTickets(epicId);
|
|
30
|
-
const childTypes = [TYPE_LABELS.
|
|
30
|
+
const childTypes = [TYPE_LABELS.STORY];
|
|
31
31
|
const created = (existing || []).filter(
|
|
32
32
|
(t) =>
|
|
33
33
|
(t.labels || []).some((l) => childTypes.includes(l)) &&
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { resolveListValue } from '../../../config/shared.js';
|
|
14
|
-
import {
|
|
14
|
+
import { DEFAULT_REGISTRY_PATTERNS } from '../../ticket-validator-conflicts.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Ensure the supplied Epic body carries a `## Planning Artifacts` section.
|
|
@@ -67,7 +67,7 @@ export function resolveConflictPolicy(cfg) {
|
|
|
67
67
|
}
|
|
68
68
|
if (planning?.crossCuttingRegistries !== undefined) {
|
|
69
69
|
policy.registries = resolveListValue(
|
|
70
|
-
|
|
70
|
+
DEFAULT_REGISTRY_PATTERNS,
|
|
71
71
|
planning.crossCuttingRegistries,
|
|
72
72
|
);
|
|
73
73
|
}
|