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
|
@@ -139,7 +139,7 @@ export function makeGhRunner(cwd) {
|
|
|
139
139
|
export function assertDeliverableStory(story, storyId) {
|
|
140
140
|
if (!story.labels.includes(TYPE_LABELS.STORY)) {
|
|
141
141
|
throw new Error(
|
|
142
|
-
`Issue #${storyId} is not a Story (labels: ${story.labels.join(', ')}). Use /
|
|
142
|
+
`Issue #${storyId} is not a Story (labels: ${story.labels.join(', ')}). Use /deliver or /deliver for Epic-attached work.`,
|
|
143
143
|
);
|
|
144
144
|
}
|
|
145
145
|
if (story.state === 'closed') {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* stories-wave-tick.js — DAG/wave engine for the top-level /
|
|
4
|
+
* stories-wave-tick.js — DAG/wave engine for the top-level /deliver workflow.
|
|
5
5
|
*
|
|
6
6
|
* Consumes an operator-supplied dependency DAG of standalone Story IDs and
|
|
7
7
|
* emits ordered execution waves. Analogous to wave-tick.js but for standalone
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
* }
|
|
27
27
|
*
|
|
28
28
|
* The per-wave concurrency cap is resolved from the same config seam
|
|
29
|
-
* `/
|
|
29
|
+
* `/deliver` uses — `resolveConfig` + `getRunners` reading
|
|
30
30
|
* `delivery.deliverRunner.concurrencyCap` (default 3) — so a
|
|
31
31
|
* `.agentrc.local.json` override is honored. A `--concurrency <n>` CLI flag
|
|
32
32
|
* overrides the config-resolved value for that run only. This puts both the
|
|
33
|
-
* standalone (`/
|
|
33
|
+
* standalone (`/deliver`) and Epic (`/deliver`) delivery paths on
|
|
34
34
|
* one deterministic config source.
|
|
35
35
|
*
|
|
36
36
|
* On cycle detection, exits with code 2 and sets cycleError in the envelope.
|
|
@@ -43,6 +43,7 @@ import { runAsCli } from './lib/cli-utils.js';
|
|
|
43
43
|
import { getRunners, resolveConfig } from './lib/config-resolver.js';
|
|
44
44
|
import { assignLayers, detectCycle } from './lib/Graph.js';
|
|
45
45
|
import { Logger } from './lib/Logger.js';
|
|
46
|
+
import { buildStoryAdjacency } from './lib/story-adjacency.js';
|
|
46
47
|
|
|
47
48
|
const HELP = `Usage: node .agents/scripts/stories-wave-tick.js --dag '<json>' | --dag-file <path> [--concurrency <n>]
|
|
48
49
|
|
|
@@ -132,21 +133,23 @@ export function parseDag(raw) {
|
|
|
132
133
|
* Build an adjacency map from parsed DAG nodes.
|
|
133
134
|
* Returns Map<id, id[]> where each id maps to its dependencies.
|
|
134
135
|
*
|
|
136
|
+
* Delegates to the shared story-level builder
|
|
137
|
+
* (`lib/story-adjacency.js#buildStoryAdjacency`) with `dropForeign: false`
|
|
138
|
+
* to preserve the operator-DAG contract: a `dependsOn` id absent from the
|
|
139
|
+
* input set still deepens the dependent's layer (assignLayers treats the
|
|
140
|
+
* unknown id as a root).
|
|
141
|
+
*
|
|
135
142
|
* @param {Array<{id: number, dependsOn: number[]}>} nodes
|
|
136
143
|
* @returns {Map<number, number[]>}
|
|
137
144
|
*/
|
|
138
145
|
export function buildAdjacency(nodes) {
|
|
139
|
-
|
|
140
|
-
for (const node of nodes) {
|
|
141
|
-
adjacency.set(node.id, [...node.dependsOn]);
|
|
142
|
-
}
|
|
143
|
-
return adjacency;
|
|
146
|
+
return buildStoryAdjacency(nodes, { dropForeign: false });
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
/**
|
|
147
150
|
* Resolve the per-wave concurrency cap.
|
|
148
151
|
*
|
|
149
|
-
* Mirrors the `/
|
|
152
|
+
* Mirrors the `/deliver` seam (`epic-deliver-prepare.js`): resolve the
|
|
150
153
|
* project config (which deep-merges `.agentrc.local.json` over `.agentrc.json`)
|
|
151
154
|
* then read `delivery.deliverRunner.concurrencyCap` via `getRunners` (default
|
|
152
155
|
* 3). An explicit `override` (the `--concurrency <n>` CLI flag) wins over
|
|
@@ -174,7 +177,7 @@ export function resolveConcurrencyCap({ cwd, config, override } = {}) {
|
|
|
174
177
|
*
|
|
175
178
|
* Uses detectCycle from Graph.js to validate the DAG before computing
|
|
176
179
|
* layers via assignLayers. Returns the wave envelope, carrying the resolved
|
|
177
|
-
* per-wave `concurrencyCap` so the `/
|
|
180
|
+
* per-wave `concurrencyCap` so the `/deliver` workflow dispatches
|
|
178
181
|
* `min(wave.stories.length, concurrencyCap)` from a deterministic field rather
|
|
179
182
|
* than from recalled prose.
|
|
180
183
|
*
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 5. branch-initializer — materialise the story branch (single-tree
|
|
16
16
|
* checkout or isolated worktree).
|
|
17
17
|
* 6. state-transitioner — flip the Story to `agent::executing`. Under
|
|
18
|
-
* the
|
|
18
|
+
* the 2-tier hierarchy the Story has inline
|
|
19
19
|
* acceptance and no child Task lifecycle.
|
|
20
20
|
*
|
|
21
21
|
* Usage:
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 0 — Initialization complete. Agent can start implementation.
|
|
26
26
|
* 1 — Blocked or error (details in stderr).
|
|
27
27
|
*
|
|
28
|
-
* @see .agents/workflows/
|
|
28
|
+
* @see .agents/workflows/helpers/deliver-stories.md
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import path from 'node:path';
|
|
@@ -38,8 +38,13 @@ import {
|
|
|
38
38
|
} from './lib/config-resolver.js';
|
|
39
39
|
import { parseBlockedBy } from './lib/dependency-parser.js';
|
|
40
40
|
import { getEpicBranch, getStoryBranch } from './lib/git-utils.js';
|
|
41
|
+
import { runInstallCommand } from './lib/install-cmd-parser.js';
|
|
41
42
|
import { Logger } from './lib/Logger.js';
|
|
42
43
|
import { setActiveStoryEnv } from './lib/observability/active-story-env.js';
|
|
44
|
+
import {
|
|
45
|
+
defaultStoryPhases,
|
|
46
|
+
upsertStoryRunProgress,
|
|
47
|
+
} from './lib/orchestration/epic-runner/story-run-progress-writer.js';
|
|
43
48
|
import { upsertStructuredComment } from './lib/orchestration/ticketing.js';
|
|
44
49
|
import { createProvider } from './lib/provider-factory.js';
|
|
45
50
|
import { validateBlockers } from './lib/story-init/blocker-validator.js';
|
|
@@ -136,7 +141,7 @@ export async function runStoryInit({
|
|
|
136
141
|
progress('INIT', `Initializing Story #${storyId}...`);
|
|
137
142
|
|
|
138
143
|
// Stage 1 — context.
|
|
139
|
-
const { story, body, epicId,
|
|
144
|
+
const { story, body, epicId, parentId } = await resolveContext({
|
|
140
145
|
provider,
|
|
141
146
|
logger: stageLogger,
|
|
142
147
|
input: { storyId, recutOf, dryRun },
|
|
@@ -149,10 +154,7 @@ export async function runStoryInit({
|
|
|
149
154
|
input: { epicId },
|
|
150
155
|
});
|
|
151
156
|
|
|
152
|
-
progress(
|
|
153
|
-
'CONTEXT',
|
|
154
|
-
`Epic: #${epicId}, Feature/Parent: #${featureId ?? 'none'}`,
|
|
155
|
-
);
|
|
157
|
+
progress('CONTEXT', `Epic: #${epicId}, Parent: #${parentId ?? 'none'}`);
|
|
156
158
|
progress(
|
|
157
159
|
'CONTEXT',
|
|
158
160
|
`PRD: #${prdId ?? 'none'}, Tech Spec: #${techSpecId ?? 'none'}`,
|
|
@@ -187,8 +189,8 @@ export async function runStoryInit({
|
|
|
187
189
|
progress('BLOCKERS', '✅ All blockers resolved');
|
|
188
190
|
|
|
189
191
|
// Stage 4 — task graph. Pass the Story body so buildTaskGraph can detect
|
|
190
|
-
// the inline-acceptance
|
|
191
|
-
// hierarchy flag,
|
|
192
|
+
// the inline-acceptance 2-tier shape. After Task #3154 collapsed the
|
|
193
|
+
// hierarchy flag, 2-tier is the only supported shape.
|
|
192
194
|
const { sortedTasks, mode: hierarchyMode } = await buildTaskGraph({
|
|
193
195
|
provider,
|
|
194
196
|
logger: stageLogger,
|
|
@@ -322,7 +324,7 @@ export async function runStoryInit({
|
|
|
322
324
|
worktreeCreated,
|
|
323
325
|
installStatus,
|
|
324
326
|
sortedTasks,
|
|
325
|
-
|
|
327
|
+
parentId,
|
|
326
328
|
prdId,
|
|
327
329
|
techSpecId,
|
|
328
330
|
dryRun,
|
|
@@ -330,11 +332,6 @@ export async function runStoryInit({
|
|
|
330
332
|
hierarchy: hierarchyMode,
|
|
331
333
|
});
|
|
332
334
|
|
|
333
|
-
emitStoryInitResult(result, {
|
|
334
|
-
storyId,
|
|
335
|
-
dryRun,
|
|
336
|
-
});
|
|
337
|
-
|
|
338
335
|
if (!dryRun) {
|
|
339
336
|
await postStoryInitComment({
|
|
340
337
|
provider,
|
|
@@ -342,11 +339,153 @@ export async function runStoryInit({
|
|
|
342
339
|
result,
|
|
343
340
|
logger: stageLogger,
|
|
344
341
|
});
|
|
342
|
+
|
|
343
|
+
// Story #4017 — the formerly standalone prepare CLI (which
|
|
344
|
+
// re-read the story-init structured comment seconds after this process
|
|
345
|
+
// wrote it) is inlined here: apply the install tri-state and render the
|
|
346
|
+
// initial Story-phase snapshot in-process, off the result we already
|
|
347
|
+
// hold.
|
|
348
|
+
result.prepare = await runStoryInitPrepare({
|
|
349
|
+
provider,
|
|
350
|
+
storyId,
|
|
351
|
+
result,
|
|
352
|
+
notify: _notifyFn,
|
|
353
|
+
logger: stageLogger,
|
|
354
|
+
});
|
|
345
355
|
}
|
|
346
356
|
|
|
357
|
+
emitStoryInitResult(result, {
|
|
358
|
+
storyId,
|
|
359
|
+
dryRun,
|
|
360
|
+
});
|
|
361
|
+
|
|
347
362
|
return { success: true, result };
|
|
348
363
|
}
|
|
349
364
|
|
|
365
|
+
const VALID_INSTALLED_STATES = new Set(['true', 'false', 'skipped']);
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Apply the dependenciesInstalled tri-state to derive the next install
|
|
369
|
+
* action. Pure helper — exposes the Step 0.5 truth table as data so tests
|
|
370
|
+
* can pin each branch without spinning up a child process.
|
|
371
|
+
*
|
|
372
|
+
* @param {'true' | 'false' | 'skipped'} dependenciesInstalled
|
|
373
|
+
* @param {{ skipInstall?: boolean }} [options]
|
|
374
|
+
* @returns {'skip' | 'install'}
|
|
375
|
+
*/
|
|
376
|
+
export function deriveInstallAction(dependenciesInstalled, options = {}) {
|
|
377
|
+
if (!VALID_INSTALLED_STATES.has(dependenciesInstalled)) {
|
|
378
|
+
throw new RangeError(
|
|
379
|
+
`deriveInstallAction: dependenciesInstalled "${dependenciesInstalled}" must be one of: ${[...VALID_INSTALLED_STATES].join(', ')}`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
if (options.skipInstall) return 'skip';
|
|
383
|
+
return dependenciesInstalled === 'false' ? 'install' : 'skip';
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Resolve the install command to run when `dependenciesInstalled === 'false'`.
|
|
388
|
+
* `project.commands` does not currently carry a dedicated install key,
|
|
389
|
+
* so this defaults to `npm ci`. Operators can override per-invocation via
|
|
390
|
+
* the `installCmd` option.
|
|
391
|
+
*
|
|
392
|
+
* @param {{ override?: string }} [options]
|
|
393
|
+
* @returns {string}
|
|
394
|
+
*/
|
|
395
|
+
export function resolveInstallCommand(options = {}) {
|
|
396
|
+
const trimmed = options.override?.trim();
|
|
397
|
+
if (trimmed) {
|
|
398
|
+
return trimmed;
|
|
399
|
+
}
|
|
400
|
+
return 'npm ci';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Post-init prepare step (Story #4017 — formerly a standalone prepare
|
|
405
|
+
* CLI, now consuming the in-process init result
|
|
406
|
+
* instead of re-reading the `story-init` structured comment):
|
|
407
|
+
*
|
|
408
|
+
* 1. Apply the `dependenciesInstalled` tri-state truth table — `'false'`
|
|
409
|
+
* (install attempted and failed) retries the install command in the
|
|
410
|
+
* worktree; `'true'` / `'skipped'` proceed.
|
|
411
|
+
* 2. Render the initial Story-phase snapshot with every phase pinned to
|
|
412
|
+
* `pending` and `phase: 'init'` via `upsertStoryRunProgress`
|
|
413
|
+
* (render-only since Story #3909 — no comment is posted). The
|
|
414
|
+
* `renderedBody` markdown is relayed to chat by the delivery
|
|
415
|
+
* workflows so operators see the initial progress block before the
|
|
416
|
+
* first commit lands.
|
|
417
|
+
*
|
|
418
|
+
* Install failure throws (init exits non-zero); a snapshot-render failure
|
|
419
|
+
* is non-fatal observability loss and only warns.
|
|
420
|
+
*
|
|
421
|
+
* @param {{
|
|
422
|
+
* provider: object,
|
|
423
|
+
* storyId: number,
|
|
424
|
+
* result: { workCwd?: string, dependenciesInstalled?: string, storyBranch?: string },
|
|
425
|
+
* notify?: Function | null,
|
|
426
|
+
* runInstall?: (cmd: string, cwd: string) => { status: number, stderr?: string },
|
|
427
|
+
* skipInstall?: boolean,
|
|
428
|
+
* installCmd?: string,
|
|
429
|
+
* logger?: object,
|
|
430
|
+
* }} args
|
|
431
|
+
* @returns {Promise<{
|
|
432
|
+
* installAction: 'skip' | 'install',
|
|
433
|
+
* installCmd: string | null,
|
|
434
|
+
* installResult: { status: number, stderr?: string } | null,
|
|
435
|
+
* snapshot: object | null,
|
|
436
|
+
* renderedBody: string | null,
|
|
437
|
+
* }>}
|
|
438
|
+
*/
|
|
439
|
+
export async function runStoryInitPrepare({
|
|
440
|
+
provider,
|
|
441
|
+
storyId,
|
|
442
|
+
result,
|
|
443
|
+
notify: notifyFn = null,
|
|
444
|
+
runInstall = runInstallCommand,
|
|
445
|
+
skipInstall = false,
|
|
446
|
+
installCmd: installCmdOverride,
|
|
447
|
+
logger = stageLogger,
|
|
448
|
+
}) {
|
|
449
|
+
const dependenciesInstalled = String(
|
|
450
|
+
result?.dependenciesInstalled ?? 'skipped',
|
|
451
|
+
);
|
|
452
|
+
const installAction = deriveInstallAction(dependenciesInstalled, {
|
|
453
|
+
skipInstall,
|
|
454
|
+
});
|
|
455
|
+
let installCmd = null;
|
|
456
|
+
let installResult = null;
|
|
457
|
+
if (installAction === 'install') {
|
|
458
|
+
installCmd = resolveInstallCommand({ override: installCmdOverride });
|
|
459
|
+
installResult = runInstall(installCmd, result.workCwd);
|
|
460
|
+
if (installResult.status !== 0) {
|
|
461
|
+
throw new Error(
|
|
462
|
+
`runStoryInitPrepare: install command \`${installCmd}\` failed with status ${installResult.status}: ${installResult.stderr ?? ''}`,
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let snapshot = null;
|
|
468
|
+
let renderedBody = null;
|
|
469
|
+
try {
|
|
470
|
+
const { body, payload } = await upsertStoryRunProgress({
|
|
471
|
+
provider,
|
|
472
|
+
storyId,
|
|
473
|
+
branch: result?.storyBranch ?? `story-${storyId}`,
|
|
474
|
+
phase: 'init',
|
|
475
|
+
phases: defaultStoryPhases(),
|
|
476
|
+
notify: notifyFn,
|
|
477
|
+
});
|
|
478
|
+
snapshot = payload;
|
|
479
|
+
renderedBody = body;
|
|
480
|
+
} catch (err) {
|
|
481
|
+
logger?.warn?.(
|
|
482
|
+
`[story-init] ⚠️ Failed to render initial story-run-progress snapshot: ${err?.message ?? err}`,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return { installAction, installCmd, installResult, snapshot, renderedBody };
|
|
487
|
+
}
|
|
488
|
+
|
|
350
489
|
function buildStoryInitResult({
|
|
351
490
|
storyId,
|
|
352
491
|
epicId,
|
|
@@ -358,7 +497,7 @@ function buildStoryInitResult({
|
|
|
358
497
|
worktreeCreated,
|
|
359
498
|
installStatus,
|
|
360
499
|
sortedTasks,
|
|
361
|
-
|
|
500
|
+
parentId,
|
|
362
501
|
prdId,
|
|
363
502
|
techSpecId,
|
|
364
503
|
dryRun,
|
|
@@ -372,11 +511,11 @@ function buildStoryInitResult({
|
|
|
372
511
|
storyBranch,
|
|
373
512
|
epicBranch,
|
|
374
513
|
storyTitle: story.title,
|
|
375
|
-
// Hierarchy mode resolved by buildTaskGraph.
|
|
514
|
+
// Hierarchy mode resolved by buildTaskGraph. 2-tier is the only
|
|
376
515
|
// supported shape after Task #3154 deleted the `planning.hierarchy`
|
|
377
516
|
// flag; this is retained as a constant marker for downstream
|
|
378
517
|
// consumers and persisted artefacts.
|
|
379
|
-
hierarchy: hierarchy ?? '
|
|
518
|
+
hierarchy: hierarchy ?? '2-tier',
|
|
380
519
|
worktreeEnabled,
|
|
381
520
|
workCwd,
|
|
382
521
|
worktreeCreated,
|
|
@@ -392,7 +531,7 @@ function buildStoryInitResult({
|
|
|
392
531
|
labels: t.labels,
|
|
393
532
|
dependencies: t.dependsOn ?? parseBlockedBy(t.body ?? ''),
|
|
394
533
|
})),
|
|
395
|
-
context: {
|
|
534
|
+
context: { parentId, prdId, techSpecId },
|
|
396
535
|
dryRun,
|
|
397
536
|
};
|
|
398
537
|
}
|
|
@@ -449,20 +588,17 @@ export function renderStoryInitCommentBody(result) {
|
|
|
449
588
|
epicId: result.epicId,
|
|
450
589
|
storyBranch: result.storyBranch,
|
|
451
590
|
epicBranch: result.epicBranch,
|
|
452
|
-
// Hierarchy mode is always `'
|
|
591
|
+
// Hierarchy mode is always `'2-tier'` after Task #3154 deleted the
|
|
453
592
|
// `planning.hierarchy` flag. Persisted so resumed runs can read it
|
|
454
593
|
// without re-resolving anything in the worker.
|
|
455
|
-
hierarchy: result.hierarchy ?? '
|
|
594
|
+
hierarchy: result.hierarchy ?? '2-tier',
|
|
456
595
|
worktreeEnabled: result.worktreeEnabled,
|
|
457
596
|
workCwd: result.workCwd,
|
|
458
597
|
worktreeCreated: result.worktreeCreated,
|
|
459
598
|
dependenciesInstalled: result.dependenciesInstalled,
|
|
460
599
|
installStatus: result.installStatus,
|
|
461
|
-
// Embed the canonical task list so
|
|
462
|
-
//
|
|
463
|
-
// Without this field, the prepare CLI silently seeded an empty snapshot,
|
|
464
|
-
// breaking every subsequent phase-writer call (it asserts the
|
|
465
|
-
// task id is present in the snapshot).
|
|
600
|
+
// Embed the canonical task list so downstream snapshot consumers can
|
|
601
|
+
// seed phase-writer calls without re-fetching the task graph.
|
|
466
602
|
tasks: Array.isArray(result.tasks)
|
|
467
603
|
? result.tasks.map((t) => ({ id: t.id, title: t.title }))
|
|
468
604
|
: [],
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* story-phase.js — phase snapshot + heartbeat writer (
|
|
4
|
+
* story-phase.js — phase snapshot + heartbeat writer (2-tier).
|
|
5
5
|
*
|
|
6
6
|
* Replaces the deleted per-Task progress writer from the 4-tier era
|
|
7
|
-
* (removed under #3157). `/
|
|
7
|
+
* (removed under #3157). `/deliver` calls this CLI at each Story-
|
|
8
8
|
* level phase transition (init → implementing → closing → done, or any
|
|
9
9
|
* → blocked). Each call:
|
|
10
10
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* longer posts a `story-run-progress` comment (the redundant mid-flight
|
|
15
15
|
* progress surface was deleted); the snapshot is render-only.
|
|
16
16
|
* 2. Appends one `story.heartbeat` lifecycle record to
|
|
17
|
-
* `temp/epic-<epicId>/lifecycle.ndjson` so `/
|
|
17
|
+
* `temp/epic-<epicId>/lifecycle.ndjson` so `/deliver`'s
|
|
18
18
|
* §2e Idle Watchdog (`wave-tick.js --check-idle 30`) can confirm
|
|
19
19
|
* forward progress without polling the Story comment.
|
|
20
20
|
*
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
*
|
|
36
36
|
* `renderedBody` is the markdown body upserted onto the Story so the
|
|
37
37
|
* caller can relay it to chat verbatim (mirrors the contract the deleted
|
|
38
|
-
* per-Task progress writer exposed and that `/
|
|
38
|
+
* per-Task progress writer exposed and that `/deliver` Step 1 / 3
|
|
39
39
|
* already documents).
|
|
40
40
|
*/
|
|
41
41
|
|
|
@@ -175,7 +175,7 @@ async function resolveStoryBranch({ provider, storyId }) {
|
|
|
175
175
|
* lease-owner handle the SAME way the lease primitive does
|
|
176
176
|
* (`normalizeOperatorHandle(github.operatorHandle)`) and stamps it as
|
|
177
177
|
* `operator` so `latestHeartbeatForOwner({ epicId, owner })` resolves a real
|
|
178
|
-
* heartbeat — without it `isClaimLive(null)` is false and /
|
|
178
|
+
* heartbeat — without it `isClaimLive(null)` is false and /deliver
|
|
179
179
|
* silently reclaims a live foreign claim (audit #3513). The field is attached
|
|
180
180
|
* only when a handle resolves, preserving the "omit when absent" shape for
|
|
181
181
|
* repos that have not configured `github.operatorHandle`. A failed append is
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/* node:coverage ignore file */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* story-plan.js — Local `/
|
|
5
|
+
* story-plan.js — Local `/plan` wrapper.
|
|
6
6
|
*
|
|
7
|
-
* Standalone counterpart to `/
|
|
7
|
+
* Standalone counterpart to `/plan` for Stories that do **not**
|
|
8
8
|
* attach to an Epic. The script is deliberately a thin CLI around the
|
|
9
9
|
* pure helpers in `lib/story-plan.js`:
|
|
10
10
|
*
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* GitHub. Echoes the rendered body and the `gh` argv it would
|
|
25
25
|
* have run.
|
|
26
26
|
*
|
|
27
|
-
* Mirrors the `/
|
|
27
|
+
* Mirrors the `/plan` pattern: deterministic Node I/O wrappers
|
|
28
28
|
* with HITL gating handled by the host LLM in chat. No external LLM
|
|
29
29
|
* APIs are called from this script.
|
|
30
30
|
*/
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Use this from workflow markdown when the operator needs to sync a
|
|
8
8
|
* working branch with `origin/<baseBranch>` before opening a PR — for
|
|
9
|
-
* example as a pre-Phase-6 step in `/
|
|
9
|
+
* example as a pre-Phase-6 step in `/deliver` so the Epic→main PR
|
|
10
10
|
* opens with the latest `main` commits already integrated.
|
|
11
11
|
*
|
|
12
12
|
* For `/single-story-deliver`, the sync runs in-process inside
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
import path from 'node:path';
|
|
32
32
|
import { parseArgs } from 'node:util';
|
|
33
33
|
import { runAsCli } from './lib/cli-utils.js';
|
|
34
|
-
import { PROJECT_ROOT } from './lib/config-resolver.js';
|
|
35
34
|
import { syncBranchFromBase } from './lib/git/sync-from-base.js';
|
|
36
35
|
import { gitSpawn, gitSync } from './lib/git-utils.js';
|
|
37
36
|
import { Logger } from './lib/Logger.js';
|
|
37
|
+
import { PROJECT_ROOT } from './lib/project-root.js';
|
|
38
38
|
|
|
39
39
|
const progress = Logger.createProgress('sync-branch-from-base', {
|
|
40
40
|
stderr: true,
|
|
@@ -201,7 +201,7 @@ export function renderFreshnessFailureMessage(epicId) {
|
|
|
201
201
|
return (
|
|
202
202
|
`[docs-freshness] ❌ Documentation freshness gate FAILED for Epic #${epicId}.\n\n` +
|
|
203
203
|
`Update each failing file so its commit message or body references #${epicId}, ` +
|
|
204
|
-
`then re-run /
|
|
204
|
+
`then re-run /deliver.`
|
|
205
205
|
);
|
|
206
206
|
}
|
|
207
207
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reads the `epic-run-state` checkpoint plus fresh Story labels and
|
|
8
8
|
* prints one `WaveTickResult` envelope. The slash-command operator
|
|
9
|
-
* (`/
|
|
9
|
+
* (`/deliver`) consumes the envelope to decide whether to dispatch
|
|
10
10
|
* the next wave, observe in-flight stories, or finalize the Epic.
|
|
11
11
|
*
|
|
12
12
|
* Usage:
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Aggregate per-Story or per-Epic execution signals into a structured
|
|
5
5
|
perf-summary or perf-report and upsert it onto the corresponding GitHub
|
|
6
6
|
ticket. Use after a Story closes (Story mode) or as part of
|
|
7
|
-
`/
|
|
7
|
+
`/deliver` Phase 6 (Epic mode). Reads NDJSON via
|
|
8
8
|
`lib/signals/read` and writes a single structured comment.
|
|
9
9
|
allowed_tools:
|
|
10
10
|
- Read
|
|
@@ -36,7 +36,7 @@ into the Epic dashboard.
|
|
|
36
36
|
pipeline dispatches this Skill (or the wrapping script) to roll up the
|
|
37
37
|
Story's NDJSON signals into a single `<!-- structured:story-perf-summary -->`
|
|
38
38
|
marker comment on the Story ticket.
|
|
39
|
-
- **Epic mode** — during `/
|
|
39
|
+
- **Epic mode** — during `/deliver` Phase 6.0 (or the retro
|
|
40
40
|
composer), the Skill fans out across every Story under the Epic,
|
|
41
41
|
reads each Story's structured perf summary, and posts a single
|
|
42
42
|
`<!-- structured:epic-perf-report -->` marker on the Epic ticket.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: epic-plan-consolidate
|
|
3
3
|
description: >-
|
|
4
|
-
Run a holistic, pre-persist consolidation pass over the draft
|
|
4
|
+
Run a holistic, pre-persist consolidation pass over the draft Story
|
|
5
5
|
ticket array an Epic's decompose phase produced. Use during Phase 8 of
|
|
6
|
-
`/
|
|
6
|
+
`/plan`, after `epic-plan-decompose-author` writes
|
|
7
7
|
`temp/epic-<Epic_ID>/tickets.json` and before `epic-plan-decompose.js`
|
|
8
8
|
validates and persists it. Reconciles the draft against the Tech Spec
|
|
9
9
|
"Delivery Slicing" target via scope-preserving operations only.
|
|
@@ -19,13 +19,12 @@ allowed_tools:
|
|
|
19
19
|
|
|
20
20
|
- Run only after `epic-plan-decompose-author` has written `temp/epic-<Epic_ID>/tickets.json`; fail loudly if the draft array is missing. Read the PRD / Tech Spec from `temp/epic-<Epic_ID>/decomposer-context.json` (the same envelope the author skill consumed) — never re-fetch from GitHub, and never call the GitHub API from this Skill.
|
|
21
21
|
- Emit exactly two artifacts inside `temp/epic-<Epic_ID>/`: the **consolidated** `tickets.json` (overwriting the draft array in place) and a human-readable `consolidation-report.md` (the rationale + before/after diff the operator reviews at the HITL gate). Both MUST exist before returning.
|
|
22
|
-
- **Scope conservation is the load-bearing invariant.** You are a *critic*, not a second author: you MUST NOT add scope, invent tickets, or drop acceptance criteria. Every acceptance item and every `verify` entry present in the draft MUST survive into the consolidated array (possibly re-homed onto a merged Story). **This is your contract, not a machine guarantee:** there is **no runtime acceptance-union diff** on your output. The only deterministic runtime backstop the validator applies after you run is
|
|
23
|
-
- Your operations are constrained to exactly
|
|
24
|
-
- Consume the Tech Spec **"Delivery Slicing"** section as the authoritative target grouping when one is present: cluster the draft's Stories toward the N shippable Stories the Architect proposed. When the section is **absent**, degrade gracefully — apply only the cohesion
|
|
25
|
-
- Implement rec #2: resolve every single-Story Feature by **collapsing** it into a sibling (operation 2), not by splitting its lone Story into two. The `assertNoSingleStoryFeature` validator from Story #3777 stays as the post-consolidation backstop — your output must already satisfy it.
|
|
22
|
+
- **Scope conservation is the load-bearing invariant.** You are a *critic*, not a second author: you MUST NOT add scope, invent tickets, or drop acceptance criteria. Every acceptance item and every `verify` entry present in the draft MUST survive into the consolidated array (possibly re-homed onto a merged Story). **This is your contract, not a machine guarantee:** there is **no runtime acceptance-union diff** on your output. The only deterministic runtime backstop the validator applies after you run is the standard ticket-structure validation — it does not re-derive the pre-consolidation acceptance/verify union, so a critic that silently dropped an acceptance item would **not** be caught downstream. (The repo's unit test exercises a *pure model* of the merge over an over-fragmented fixture to document the intended invariant; it does not inspect this Skill's actual output.) Conserve scope yourself, deliberately, on every merge.
|
|
23
|
+
- Your operations are constrained to exactly two shapes: **(1) merge two or more Stories** into one (union their `changes`/`acceptance`/`verify`/`references`, keep one coherent `goal`); **(2) rewire `depends_on`** so the edges still reference surviving sibling-Story slugs. No other mutation is permitted.
|
|
24
|
+
- Consume the Tech Spec **"Delivery Slicing"** section as the authoritative target grouping when one is present: cluster the draft's Stories toward the N shippable Stories the Architect proposed. When the section is **absent**, degrade gracefully — apply only the cohesion rules below and leave the rest of the draft shape intact.
|
|
26
25
|
- Apply the same cohesion heuristic the author skill leads with: **one Story = one coherent change with one reason to exist**, and the **single-consumer merge rule** (a Story whose only consumer is one sibling Story is merged into that sibling). Lead every merge decision with the change's reason, not its file count.
|
|
27
|
-
- After every merge
|
|
28
|
-
- The consolidation report MUST name each operation applied (merged slugs → surviving slug,
|
|
26
|
+
- After every merge, **rewire `depends_on`**: drop self-edges, collapse edges that now point at the absorbing Story onto itself, and re-point any edge that named a now-deleted slug at its surviving successor. Never leave a `depends_on` referencing a slug absent from the consolidated array — the validator HARD-rejects unknown deps.
|
|
27
|
+
- The consolidation report MUST name each operation applied (merged slugs → surviving slug, rewired edges) with a one-line reason, plus a before/after Story-count line, so the operator can approve or reject at the HITL diff gate before the persist call.
|
|
29
28
|
|
|
30
29
|
## Role
|
|
31
30
|
|
|
@@ -38,7 +37,7 @@ against the Tech Spec's intentional grouping before any GitHub write.
|
|
|
38
37
|
|
|
39
38
|
## When to use
|
|
40
39
|
|
|
41
|
-
`/
|
|
40
|
+
`/plan` Phase 8, as the **8.3 — Holistic Consolidation** sub-step:
|
|
42
41
|
immediately after `epic-plan-decompose-author` writes
|
|
43
42
|
`temp/epic-<Epic_ID>/tickets.json` and **before**
|
|
44
43
|
`epic-plan-decompose.js --tickets …` validates and persists. The pass operates
|
|
@@ -51,7 +50,7 @@ emit a plan the validator would reject.
|
|
|
51
50
|
The dispatcher passes the Epic ID as the Skill argument. The Skill itself
|
|
52
51
|
reads:
|
|
53
52
|
|
|
54
|
-
- `temp/epic-<Epic_ID>/tickets.json` — the **draft**
|
|
53
|
+
- `temp/epic-<Epic_ID>/tickets.json` — the **draft** Story array the
|
|
55
54
|
`epic-plan-decompose-author` Skill wrote. This is the consolidation input.
|
|
56
55
|
- `temp/epic-<Epic_ID>/decomposer-context.json` — the authoring envelope
|
|
57
56
|
emitted by `epic-plan-decompose.js --emit-context`. Read `prd.body` /
|
|
@@ -62,7 +61,7 @@ reads:
|
|
|
62
61
|
## Outputs
|
|
63
62
|
|
|
64
63
|
- `temp/epic-<Epic_ID>/tickets.json` — the **consolidated** array, overwriting
|
|
65
|
-
the draft. Same schema as the author skill emits (
|
|
64
|
+
the draft. Same schema as the author skill emits (flat Story array; Stories
|
|
66
65
|
carry top-level `acceptance[]` / `verify[]`; `body` is a serialized string).
|
|
67
66
|
The downstream `epic-plan-decompose.js --tickets …` validator is the final
|
|
68
67
|
gate — author for its rules, not for "looks right."
|
|
@@ -83,21 +82,18 @@ anything:
|
|
|
83
82
|
|
|
84
83
|
1. The **target grouping** — the N shippable Stories the Architect proposed in
|
|
85
84
|
Delivery Slicing, or `null` when the section is absent (graceful-degrade
|
|
86
|
-
mode: cohesion
|
|
87
|
-
2. The **draft Story count
|
|
88
|
-
|
|
85
|
+
mode: cohesion rules only).
|
|
86
|
+
2. The **draft Story count** — so you can spot over-fragmented capability
|
|
87
|
+
clusters.
|
|
89
88
|
|
|
90
89
|
### Step 2 — Plan the consolidation
|
|
91
90
|
|
|
92
|
-
|
|
91
|
+
Across the draft Story array, decide which Stories merge:
|
|
93
92
|
|
|
94
|
-
- **Single-Story Feature** → collapse its lone Story into a sibling Feature
|
|
95
|
-
whose capability is closest (Delivery-Slicing target, else thematic
|
|
96
|
-
proximity). Drop the now-empty Feature. Never split the lone Story.
|
|
97
93
|
- **Over-fragmented capability** → when several draft Stories map to one
|
|
98
94
|
Delivery-Slicing target (or one coherent reason to exist), merge them into a
|
|
99
95
|
single Story: union their `changes` / `acceptance` / `verify` / `references`,
|
|
100
|
-
write one `goal
|
|
96
|
+
write one coherent `goal`, and keep the union of labels.
|
|
101
97
|
- **Single-consumer Story** → merge into the one sibling that consumes it.
|
|
102
98
|
|
|
103
99
|
Record each decision with its one-line reason for the report.
|
|
@@ -120,7 +116,7 @@ Write the consolidated array to `temp/epic-<Epic_ID>/tickets.json` (2-space
|
|
|
120
116
|
indent, machine-consumed) and the rationale + before/after diff to
|
|
121
117
|
`temp/epic-<Epic_ID>/consolidation-report.md`.
|
|
122
118
|
|
|
123
|
-
### Step 5 — Hand back to `/
|
|
119
|
+
### Step 5 — Hand back to `/plan`
|
|
124
120
|
|
|
125
121
|
Return control. The workflow shows the operator the consolidation report at the
|
|
126
122
|
HITL diff gate; on approval it runs
|
|
@@ -133,13 +129,12 @@ persists the hierarchy, and flips the Epic to `agent::ready`.
|
|
|
133
129
|
- Do **not** call the GitHub API from this Skill. It reads two temp artifacts
|
|
134
130
|
and writes two temp artifacts; persistence belongs to the script.
|
|
135
131
|
- Do **not** write outside `temp/epic-<Epic_ID>/`.
|
|
136
|
-
- Do **not** add scope or invent tickets. The
|
|
137
|
-
Stories,
|
|
138
|
-
|
|
132
|
+
- Do **not** add scope or invent tickets. The two permitted operations (merge
|
|
133
|
+
Stories, rewire `depends_on`) are exhaustive — anything else is out of
|
|
134
|
+
contract.
|
|
139
135
|
- If `temp/epic-<Epic_ID>/tickets.json` is missing, fail loudly and instruct
|
|
140
136
|
the caller to run the `epic-plan-decompose-author` Skill first.
|
|
141
137
|
- The validator
|
|
142
138
|
([`lib/orchestration/ticket-validator.js`](../../../scripts/lib/orchestration/ticket-validator.js))
|
|
143
|
-
is the authoritative post-consolidation gate
|
|
144
|
-
|
|
145
|
-
patching tickets by hand.
|
|
139
|
+
is the authoritative post-consolidation gate. Re-consolidate when it
|
|
140
|
+
rejects rather than patching tickets by hand.
|