mandrel 1.57.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 +954 -0
- package/.agents/docs/SDLC.md +1420 -0
- package/.agents/docs/agentrc-reference.json +278 -0
- package/.agents/docs/configuration.md +1040 -0
- package/.agents/docs/workflows.md +59 -0
- package/.agents/instructions.md +384 -0
- package/.agents/personas/architect.md +107 -0
- package/.agents/personas/devops-engineer.md +36 -0
- package/.agents/personas/engineer-mobile.md +119 -0
- package/.agents/personas/engineer-web.md +110 -0
- package/.agents/personas/engineer.md +90 -0
- package/.agents/personas/product.md +88 -0
- package/.agents/personas/project-manager.md +110 -0
- package/.agents/personas/qa-engineer.md +91 -0
- package/.agents/personas/refactorer.md +110 -0
- package/.agents/personas/security-engineer.md +112 -0
- package/.agents/personas/sre.md +86 -0
- package/.agents/personas/technical-writer.md +100 -0
- package/.agents/personas/ux-designer.md +95 -0
- package/.agents/rules/api-conventions.md +75 -0
- package/.agents/rules/changelog-style.md +238 -0
- package/.agents/rules/gherkin-standards.md +146 -0
- package/.agents/rules/git-conventions.md +146 -0
- package/.agents/rules/orchestration-error-handling.md +35 -0
- package/.agents/rules/security-baseline.md +92 -0
- package/.agents/rules/shell-conventions.md +70 -0
- package/.agents/rules/test-seams.md +59 -0
- package/.agents/rules/testing-standards.md +177 -0
- package/.agents/runtime-deps.json +18 -0
- package/.agents/schemas/acceptance-eval-verdict.schema.json +93 -0
- package/.agents/schemas/agentrc.schema.json +1583 -0
- package/.agents/schemas/audit-results.schema.json +69 -0
- package/.agents/schemas/audit-rules.json +134 -0
- package/.agents/schemas/audit-rules.schema.json +69 -0
- package/.agents/schemas/baselines/baseline-envelope.schema.json +44 -0
- package/.agents/schemas/baselines/bundle-size.schema.json +47 -0
- package/.agents/schemas/baselines/coverage.schema.json +50 -0
- package/.agents/schemas/baselines/crap.schema.json +52 -0
- package/.agents/schemas/baselines/duplication.schema.json +62 -0
- package/.agents/schemas/baselines/lighthouse.schema.json +59 -0
- package/.agents/schemas/baselines/lint.schema.json +47 -0
- package/.agents/schemas/baselines/maintainability.schema.json +71 -0
- package/.agents/schemas/baselines/mutation.schema.json +52 -0
- package/.agents/schemas/crap-baseline.schema.json +57 -0
- package/.agents/schemas/crap-report.schema.json +102 -0
- package/.agents/schemas/dispatch-manifest.json +232 -0
- package/.agents/schemas/epic-perf-report.schema.json +89 -0
- package/.agents/schemas/epic-spec.schema.json +183 -0
- package/.agents/schemas/friction-event.schema.json +56 -0
- package/.agents/schemas/lifecycle/README.md +18 -0
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +13 -0
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +13 -0
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +13 -0
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +13 -0
- package/.agents/schemas/lifecycle/checkpoint.written.schema.json +13 -0
- package/.agents/schemas/lifecycle/close-validate.end.schema.json +18 -0
- package/.agents/schemas/lifecycle/close-validate.start.schema.json +13 -0
- package/.agents/schemas/lifecycle/code-review.end.schema.json +30 -0
- package/.agents/schemas/lifecycle/code-review.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +14 -0
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +13 -0
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +13 -0
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.complete.schema.json +13 -0
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +13 -0
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +13 -0
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +14 -0
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +17 -0
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +15 -0
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +18 -0
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +16 -0
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +28 -0
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +16 -0
- package/.agents/schemas/lifecycle/intervention.recorded.schema.json +15 -0
- package/.agents/schemas/lifecycle/ledger-record.schema.json +59 -0
- package/.agents/schemas/lifecycle/notification.emitted.schema.json +18 -0
- package/.agents/schemas/lifecycle/pr.created.schema.json +14 -0
- package/.agents/schemas/lifecycle/retro.end.schema.json +16 -0
- package/.agents/schemas/lifecycle/retro.start.schema.json +12 -0
- package/.agents/schemas/lifecycle/story.blocked.schema.json +13 -0
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +17 -0
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +15 -0
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +20 -0
- package/.agents/schemas/lifecycle/story.merged.schema.json +13 -0
- package/.agents/schemas/mi-report.schema.json +58 -0
- package/.agents/schemas/model-attribution.schema.json +49 -0
- package/.agents/schemas/qa-finding.schema.json +133 -0
- package/.agents/schemas/qa-ledger.schema.json +89 -0
- package/.agents/schemas/risk-verdict.schema.json +53 -0
- package/.agents/schemas/signal-event.schema.json +58 -0
- package/.agents/schemas/skill.schema.json +31 -0
- package/.agents/schemas/skills-index.schema.json +81 -0
- package/.agents/schemas/story-perf-summary.schema.json +73 -0
- package/.agents/schemas/validation-evidence.schema.json +78 -0
- package/.agents/scripts/README.md +93 -0
- package/.agents/scripts/acceptance-eval.js +284 -0
- package/.agents/scripts/acceptance-spec-reconciler.js +556 -0
- package/.agents/scripts/agents-bootstrap-github.js +634 -0
- package/.agents/scripts/analyze-execution.js +369 -0
- package/.agents/scripts/assert-branch.js +83 -0
- package/.agents/scripts/audit-labels-bootstrap.js +253 -0
- package/.agents/scripts/audit-to-stories.js +257 -0
- package/.agents/scripts/bootstrap.js +1378 -0
- package/.agents/scripts/check-baselines.js +81 -0
- package/.agents/scripts/check-dead-exports.js +311 -0
- package/.agents/scripts/check-doc-links.js +401 -0
- package/.agents/scripts/check-gherkin-placeholders.js +663 -0
- package/.agents/scripts/check-lifecycle-doc-drift.js +402 -0
- package/.agents/scripts/check-lifecycle-lint.js +379 -0
- package/.agents/scripts/check-prepush-recovery.js +90 -0
- package/.agents/scripts/check-windows-git-perf.js +138 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +67 -0
- package/.agents/scripts/coverage-capture.js +112 -0
- package/.agents/scripts/detect-merges.js +111 -0
- package/.agents/scripts/diagnose-friction.js +257 -0
- package/.agents/scripts/diagnose.js +240 -0
- package/.agents/scripts/dispatcher.js +295 -0
- package/.agents/scripts/drain-pending-cleanup.js +147 -0
- package/.agents/scripts/epic-audit-prepare.js +419 -0
- package/.agents/scripts/epic-audit-recheck.js +241 -0
- package/.agents/scripts/epic-deliver-note-intervention.js +192 -0
- package/.agents/scripts/epic-deliver-preflight.js +407 -0
- package/.agents/scripts/epic-deliver-prepare.js +383 -0
- package/.agents/scripts/epic-execute-record-wave.js +463 -0
- package/.agents/scripts/epic-plan-clarity.js +201 -0
- package/.agents/scripts/epic-plan-decompose.js +79 -0
- package/.agents/scripts/epic-plan-healthcheck.js +363 -0
- package/.agents/scripts/epic-plan-spec-validate.js +111 -0
- package/.agents/scripts/epic-plan-spec.js +198 -0
- package/.agents/scripts/epic-reconcile.js +637 -0
- package/.agents/scripts/evidence-gate.js +235 -0
- package/.agents/scripts/generate-config-docs.js +516 -0
- package/.agents/scripts/generate-lifecycle-docs.js +224 -0
- package/.agents/scripts/generate-skills-index.js +252 -0
- package/.agents/scripts/generate-workflows-doc.js +168 -0
- package/.agents/scripts/git-cleanup.js +124 -0
- package/.agents/scripts/git-pr-quality-gate.js +203 -0
- package/.agents/scripts/git-rebase-and-resolve.js +234 -0
- package/.agents/scripts/hierarchy-gate.js +176 -0
- package/.agents/scripts/hydrate-context.js +179 -0
- package/.agents/scripts/install-matrix-assert.js +282 -0
- package/.agents/scripts/lib/Graph.js +326 -0
- package/.agents/scripts/lib/ITicketingProvider.js +349 -0
- package/.agents/scripts/lib/Logger.js +194 -0
- package/.agents/scripts/lib/audit-suite/cli.js +64 -0
- package/.agents/scripts/lib/audit-suite/findings.js +164 -0
- package/.agents/scripts/lib/audit-suite/frontmatter-lint.js +32 -0
- package/.agents/scripts/lib/audit-suite/frontmatter.js +110 -0
- package/.agents/scripts/lib/audit-suite/index.js +22 -0
- package/.agents/scripts/lib/audit-suite/runner.js +233 -0
- package/.agents/scripts/lib/audit-suite/selector.js +235 -0
- package/.agents/scripts/lib/audit-suite/substitutions.js +124 -0
- package/.agents/scripts/lib/audit-suite/workflow-loader.js +49 -0
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +130 -0
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +114 -0
- package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +93 -0
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +265 -0
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +246 -0
- package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +160 -0
- package/.agents/scripts/lib/auto-refresh-baselines.js +308 -0
- package/.agents/scripts/lib/baseline-loader.js +0 -0
- package/.agents/scripts/lib/baseline-schema-registry.js +69 -0
- package/.agents/scripts/lib/baseline-snapshot.js +716 -0
- package/.agents/scripts/lib/baselines/component-matcher.js +21 -0
- package/.agents/scripts/lib/baselines/components.js +126 -0
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +203 -0
- package/.agents/scripts/lib/baselines/duplication-scanner.js +220 -0
- package/.agents/scripts/lib/baselines/env-overrides.js +129 -0
- package/.agents/scripts/lib/baselines/envelope.js +368 -0
- package/.agents/scripts/lib/baselines/exit-codes.js +89 -0
- package/.agents/scripts/lib/baselines/git-base.js +0 -0
- package/.agents/scripts/lib/baselines/kernel.js +111 -0
- package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +220 -0
- package/.agents/scripts/lib/baselines/kinds/bundle-size.js +157 -0
- package/.agents/scripts/lib/baselines/kinds/coverage.js +194 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +555 -0
- package/.agents/scripts/lib/baselines/kinds/duplication.js +197 -0
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +185 -0
- package/.agents/scripts/lib/baselines/kinds/lint.js +172 -0
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +340 -0
- package/.agents/scripts/lib/baselines/kinds/mutation.js +153 -0
- package/.agents/scripts/lib/baselines/path-canon.js +279 -0
- package/.agents/scripts/lib/baselines/preview-gates.js +298 -0
- package/.agents/scripts/lib/baselines/reader.js +321 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +733 -0
- package/.agents/scripts/lib/baselines/scope.js +291 -0
- package/.agents/scripts/lib/baselines/writer.js +312 -0
- package/.agents/scripts/lib/bdd-runner-detect.js +417 -0
- package/.agents/scripts/lib/bdd-scenario-scanner.js +310 -0
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +202 -0
- package/.agents/scripts/lib/bootstrap/branch-protection.js +222 -0
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +171 -0
- package/.agents/scripts/lib/bootstrap/commit-push.js +146 -0
- package/.agents/scripts/lib/bootstrap/gh-list.js +153 -0
- package/.agents/scripts/lib/bootstrap/gh-preflight.js +306 -0
- package/.agents/scripts/lib/bootstrap/hitl-confirm.js +89 -0
- package/.agents/scripts/lib/bootstrap/install-ledger.js +174 -0
- package/.agents/scripts/lib/bootstrap/manifest.js +272 -0
- package/.agents/scripts/lib/bootstrap/merge-methods.js +108 -0
- package/.agents/scripts/lib/bootstrap/preflight.js +195 -0
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +801 -0
- package/.agents/scripts/lib/bootstrap/prompt.js +480 -0
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +370 -0
- package/.agents/scripts/lib/bootstrap/summary.js +75 -0
- package/.agents/scripts/lib/bootstrap/workflow-audit.js +256 -0
- package/.agents/scripts/lib/branch-name-guard.js +98 -0
- package/.agents/scripts/lib/c8-cli-path.js +21 -0
- package/.agents/scripts/lib/changed-files.js +184 -0
- package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +104 -0
- package/.agents/scripts/lib/checks/core-bare-clean.js +48 -0
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +54 -0
- package/.agents/scripts/lib/checks/index.js +288 -0
- package/.agents/scripts/lib/checks/push-hook-parity.js +106 -0
- package/.agents/scripts/lib/checks/stale-origin-epic.js +49 -0
- package/.agents/scripts/lib/checks/state.js +558 -0
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +186 -0
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +182 -0
- package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +92 -0
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +81 -0
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +55 -0
- package/.agents/scripts/lib/cli/parse-numeric.js +60 -0
- package/.agents/scripts/lib/cli/standard-args.js +351 -0
- package/.agents/scripts/lib/cli-args.js +286 -0
- package/.agents/scripts/lib/cli-utils.js +69 -0
- package/.agents/scripts/lib/close-validation/projections/head-sha.js +44 -0
- package/.agents/scripts/lib/close-validation/projections/inputs.js +86 -0
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +286 -0
- package/.agents/scripts/lib/close-validation.js +897 -0
- package/.agents/scripts/lib/codebase-snapshot.js +513 -0
- package/.agents/scripts/lib/command-header.js +33 -0
- package/.agents/scripts/lib/config/acceptance-eval.js +95 -0
- package/.agents/scripts/lib/config/baselines.js +60 -0
- package/.agents/scripts/lib/config/ci.js +30 -0
- package/.agents/scripts/lib/config/commands.js +36 -0
- package/.agents/scripts/lib/config/defaults.js +119 -0
- package/.agents/scripts/lib/config/explain.js +348 -0
- package/.agents/scripts/lib/config/gates/bundle-size.schema.js +23 -0
- package/.agents/scripts/lib/config/gates/coverage.schema.js +18 -0
- package/.agents/scripts/lib/config/gates/crap.schema.js +33 -0
- package/.agents/scripts/lib/config/gates/duplication.schema.js +26 -0
- package/.agents/scripts/lib/config/gates/index.js +36 -0
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +23 -0
- package/.agents/scripts/lib/config/gates/lint.schema.js +9 -0
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +20 -0
- package/.agents/scripts/lib/config/gates/mutation.schema.js +12 -0
- package/.agents/scripts/lib/config/gates/shared.js +117 -0
- package/.agents/scripts/lib/config/github.js +122 -0
- package/.agents/scripts/lib/config/lifecycle.js +40 -0
- package/.agents/scripts/lib/config/limits.js +211 -0
- package/.agents/scripts/lib/config/paths.js +73 -0
- package/.agents/scripts/lib/config/preflight.js +58 -0
- package/.agents/scripts/lib/config/quality.js +665 -0
- package/.agents/scripts/lib/config/retro.js +77 -0
- package/.agents/scripts/lib/config/runners.js +105 -0
- package/.agents/scripts/lib/config/runtime.js +167 -0
- package/.agents/scripts/lib/config/shared.js +46 -0
- package/.agents/scripts/lib/config/sync-agentrc.js +243 -0
- package/.agents/scripts/lib/config/temp-paths.js +373 -0
- package/.agents/scripts/lib/config/validate-orchestration.js +81 -0
- package/.agents/scripts/lib/config/worktree-isolation.js +80 -0
- package/.agents/scripts/lib/config-resolver.js +298 -0
- package/.agents/scripts/lib/config-schema-shared.js +32 -0
- package/.agents/scripts/lib/config-schema.js +20 -0
- package/.agents/scripts/lib/config-settings-schema-delivery.js +332 -0
- package/.agents/scripts/lib/config-settings-schema-quality.js +165 -0
- package/.agents/scripts/lib/config-settings-schema.js +420 -0
- package/.agents/scripts/lib/coverage-baseline.js +352 -0
- package/.agents/scripts/lib/coverage-capture.js +195 -0
- package/.agents/scripts/lib/coverage-utils.js +239 -0
- package/.agents/scripts/lib/cpu-pool.js +223 -0
- package/.agents/scripts/lib/crap-engine.js +119 -0
- package/.agents/scripts/lib/crap-utils.js +479 -0
- package/.agents/scripts/lib/degraded-mode.js +69 -0
- package/.agents/scripts/lib/dependency-parser.js +129 -0
- package/.agents/scripts/lib/duplicate-search.js +189 -0
- package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +70 -0
- package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +197 -0
- package/.agents/scripts/lib/dynamic-workflow/capability.js +396 -0
- package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +80 -0
- package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +72 -0
- package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +90 -0
- package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +43 -0
- package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +83 -0
- package/.agents/scripts/lib/env-loader.js +52 -0
- package/.agents/scripts/lib/epic-merge-lock.js +239 -0
- package/.agents/scripts/lib/epic-plan-clarity.js +142 -0
- package/.agents/scripts/lib/epic-plan-ideation.js +228 -0
- package/.agents/scripts/lib/error-redactor.js +125 -0
- package/.agents/scripts/lib/errors/index.js +67 -0
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +230 -0
- package/.agents/scripts/lib/feedback-loop/code-review-graduator.js +207 -0
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +421 -0
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +480 -0
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +229 -0
- package/.agents/scripts/lib/findings/classify-finding.js +195 -0
- package/.agents/scripts/lib/findings/promote-finding.js +353 -0
- package/.agents/scripts/lib/findings/route-finding.js +283 -0
- package/.agents/scripts/lib/findings/semantic-issue-search.js +179 -0
- package/.agents/scripts/lib/findings/severity.js +102 -0
- package/.agents/scripts/lib/gates/baseline-store.js +106 -0
- package/.agents/scripts/lib/gates/friction.js +43 -0
- package/.agents/scripts/lib/gh-exec.js +553 -0
- package/.agents/scripts/lib/git/cached-fetch.js +0 -0
- package/.agents/scripts/lib/git/sync-from-base.js +162 -0
- package/.agents/scripts/lib/git-branch-cleanup.js +213 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +353 -0
- package/.agents/scripts/lib/git-merge-orchestrator.js +261 -0
- package/.agents/scripts/lib/git-utils.js +363 -0
- package/.agents/scripts/lib/github-url.js +29 -0
- package/.agents/scripts/lib/install-cmd-parser.js +51 -0
- package/.agents/scripts/lib/issue-link-parser.js +74 -0
- package/.agents/scripts/lib/json-utils.js +60 -0
- package/.agents/scripts/lib/label-constants.js +169 -0
- package/.agents/scripts/lib/label-taxonomy.js +200 -0
- package/.agents/scripts/lib/maintainability-engine.js +164 -0
- package/.agents/scripts/lib/maintainability-utils.js +343 -0
- package/.agents/scripts/lib/mandrel-catalog.js +170 -0
- package/.agents/scripts/lib/mutation/baseline-snapshot.js +238 -0
- package/.agents/scripts/lib/mutation/config-detector.js +119 -0
- package/.agents/scripts/lib/mutation/stryker-runner.js +306 -0
- package/.agents/scripts/lib/mutation/survivor-report.js +160 -0
- package/.agents/scripts/lib/notifications/notifier.js +75 -0
- package/.agents/scripts/lib/observability/active-story-env.js +182 -0
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +221 -0
- package/.agents/scripts/lib/observability/perf-aggregator.js +887 -0
- package/.agents/scripts/lib/observability/perf-report-readers.js +319 -0
- package/.agents/scripts/lib/observability/perf-report-render.js +182 -0
- package/.agents/scripts/lib/observability/signals-writer.js +296 -0
- package/.agents/scripts/lib/observability/source-classifier.js +103 -0
- package/.agents/scripts/lib/observability/tool-trace-hook.js +417 -0
- package/.agents/scripts/lib/onboard/detect-stack.js +300 -0
- package/.agents/scripts/lib/onboard/scaffold-docs.js +128 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +173 -0
- package/.agents/scripts/lib/orchestration/cascade-grouping.js +275 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +131 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +80 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +132 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +142 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +149 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +158 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +56 -0
- package/.agents/scripts/lib/orchestration/code-review.js +652 -0
- package/.agents/scripts/lib/orchestration/column-sync.js +286 -0
- package/.agents/scripts/lib/orchestration/context-envelope.js +280 -0
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +581 -0
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +88 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +188 -0
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +144 -0
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +206 -0
- package/.agents/scripts/lib/orchestration/doc-reader.js +94 -0
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +473 -0
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +310 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/cli.js +167 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +151 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +74 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +78 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +72 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +155 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +321 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +75 -0
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +86 -0
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +235 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +197 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +48 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +94 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +414 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +55 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +105 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +235 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +120 -0
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +118 -0
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +295 -0
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +186 -0
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +50 -0
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +146 -0
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +110 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +392 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +217 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +235 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +69 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +32 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +291 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +175 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +37 -0
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +127 -0
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +400 -0
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +285 -0
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +66 -0
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +797 -0
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +619 -0
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +335 -0
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +230 -0
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +363 -0
- package/.agents/scripts/lib/orchestration/error-journal.js +139 -0
- package/.agents/scripts/lib/orchestration/file-assumption-enum.js +31 -0
- package/.agents/scripts/lib/orchestration/file-assumptions.js +506 -0
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +116 -0
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +241 -0
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +489 -0
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +88 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +219 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +309 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +99 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +123 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +57 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +114 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +426 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +84 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +365 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +72 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +69 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +214 -0
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +137 -0
- package/.agents/scripts/lib/orchestration/label-transitions.js +43 -0
- package/.agents/scripts/lib/orchestration/lifecycle/bus.js +309 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +147 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +155 -0
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +226 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +69 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +378 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +248 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +527 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +259 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +278 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +355 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +647 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +331 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +140 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +421 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +168 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +668 -0
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +322 -0
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +114 -0
- package/.agents/scripts/lib/orchestration/manifest-builder.js +216 -0
- package/.agents/scripts/lib/orchestration/model-attribution.js +390 -0
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +147 -0
- package/.agents/scripts/lib/orchestration/phase-runner.js +87 -0
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +63 -0
- package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +86 -0
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +212 -0
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +213 -0
- package/.agents/scripts/lib/orchestration/planning-risk.js +155 -0
- package/.agents/scripts/lib/orchestration/planning-state-manager.js +318 -0
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +56 -0
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +33 -0
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +78 -0
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +68 -0
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +118 -0
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +396 -0
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +205 -0
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +47 -0
- package/.agents/scripts/lib/orchestration/preflight-cache.js +164 -0
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +202 -0
- package/.agents/scripts/lib/orchestration/reconciler.js +137 -0
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +152 -0
- package/.agents/scripts/lib/orchestration/recut.js +56 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +127 -0
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +94 -0
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +448 -0
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +335 -0
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +133 -0
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +57 -0
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +275 -0
- package/.agents/scripts/lib/orchestration/retro-proposals.js +395 -0
- package/.agents/scripts/lib/orchestration/retro-runner.js +171 -0
- package/.agents/scripts/lib/orchestration/review-depth.js +93 -0
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +363 -0
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +205 -0
- package/.agents/scripts/lib/orchestration/review-providers/native.js +805 -0
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +73 -0
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +396 -0
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +373 -0
- package/.agents/scripts/lib/orchestration/review-providers/types.js +89 -0
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +107 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +159 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +194 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +81 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +190 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +70 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +106 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +42 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +73 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +225 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +315 -0
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +149 -0
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +110 -0
- package/.agents/scripts/lib/orchestration/spec-freshness.js +320 -0
- package/.agents/scripts/lib/orchestration/spec-renderer.js +456 -0
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +80 -0
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +797 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +163 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +152 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +387 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +266 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +48 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +67 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +161 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +117 -0
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +86 -0
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +147 -0
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +142 -0
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +62 -0
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +221 -0
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +123 -0
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +216 -0
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +636 -0
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +198 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +105 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +222 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +220 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +291 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +234 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +110 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +86 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +112 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +157 -0
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +434 -0
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +290 -0
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +643 -0
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +67 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +391 -0
- package/.agents/scripts/lib/orchestration/ticket-lease.js +358 -0
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +783 -0
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +367 -0
- package/.agents/scripts/lib/orchestration/ticket-validator.js +691 -0
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +723 -0
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +474 -0
- package/.agents/scripts/lib/orchestration/ticketing/state.js +559 -0
- package/.agents/scripts/lib/orchestration/ticketing.js +55 -0
- package/.agents/scripts/lib/orchestration/wave-marker.js +28 -0
- package/.agents/scripts/lib/orchestration/wave-record-io.js +277 -0
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +189 -0
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +423 -0
- package/.agents/scripts/lib/path-security.js +25 -0
- package/.agents/scripts/lib/plan-phase-cleanup.js +125 -0
- package/.agents/scripts/lib/preflight-runner.js +196 -0
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +95 -0
- package/.agents/scripts/lib/presentation/manifest-builder.js +245 -0
- package/.agents/scripts/lib/presentation/manifest-formatter.js +243 -0
- package/.agents/scripts/lib/presentation/manifest-helpers.js +213 -0
- package/.agents/scripts/lib/presentation/manifest-persistence.js +262 -0
- package/.agents/scripts/lib/presentation/manifest-procedures.js +55 -0
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +252 -0
- package/.agents/scripts/lib/presentation/manifest-renderer.js +188 -0
- package/.agents/scripts/lib/presentation/manifest-story-views.js +119 -0
- package/.agents/scripts/lib/provider-factory.js +80 -0
- package/.agents/scripts/lib/push-epic-retry.js +209 -0
- package/.agents/scripts/lib/qa/console-allowlist.js +151 -0
- package/.agents/scripts/lib/qa/coverage-report.js +181 -0
- package/.agents/scripts/lib/qa/coverage-verdict.js +296 -0
- package/.agents/scripts/lib/qa/propose-missing-test.js +95 -0
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +296 -0
- package/.agents/scripts/lib/qa/qa-session.js +197 -0
- package/.agents/scripts/lib/qa/redact-evidence.js +245 -0
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +190 -0
- package/.agents/scripts/lib/qa/resolve-selection.js +373 -0
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +100 -0
- package/.agents/scripts/lib/runtime-deps/manifest.js +96 -0
- package/.agents/scripts/lib/runtime-deps/preflight.js +78 -0
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +202 -0
- package/.agents/scripts/lib/signals/detectors/common.js +36 -0
- package/.agents/scripts/lib/signals/detectors/hotspot.js +298 -0
- package/.agents/scripts/lib/signals/detectors/index.js +14 -0
- package/.agents/scripts/lib/signals/detectors/retry.js +289 -0
- package/.agents/scripts/lib/signals/detectors/rework.js +204 -0
- package/.agents/scripts/lib/signals/index.js +39 -0
- package/.agents/scripts/lib/signals/read.js +268 -0
- package/.agents/scripts/lib/signals/schema.js +225 -0
- package/.agents/scripts/lib/signals/span-tree.js +290 -0
- package/.agents/scripts/lib/signals/write.js +19 -0
- package/.agents/scripts/lib/single-story/confirm-merge.js +201 -0
- package/.agents/scripts/lib/single-story/story-merged-notify.js +126 -0
- package/.agents/scripts/lib/single-story-sweep/protection.js +274 -0
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +169 -0
- package/.agents/scripts/lib/single-story-sweep.js +329 -0
- package/.agents/scripts/lib/skills/parse-skill.js +202 -0
- package/.agents/scripts/lib/skills/walk-skill-files.js +56 -0
- package/.agents/scripts/lib/spec/index.js +36 -0
- package/.agents/scripts/lib/spec/loader.js +425 -0
- package/.agents/scripts/lib/spec/state.js +217 -0
- package/.agents/scripts/lib/story-body/story-body.js +743 -0
- package/.agents/scripts/lib/story-init/blocker-validator.js +68 -0
- package/.agents/scripts/lib/story-init/branch-initializer.js +422 -0
- package/.agents/scripts/lib/story-init/context-resolver.js +92 -0
- package/.agents/scripts/lib/story-init/donor-precheck.js +207 -0
- package/.agents/scripts/lib/story-init/hierarchy-tracer.js +36 -0
- package/.agents/scripts/lib/story-init/state-transitioner.js +80 -0
- package/.agents/scripts/lib/story-init/task-graph-builder.js +114 -0
- package/.agents/scripts/lib/story-init/transition-summary.js +34 -0
- package/.agents/scripts/lib/story-lifecycle.js +186 -0
- package/.agents/scripts/lib/story-plan.js +246 -0
- package/.agents/scripts/lib/task-utils.js +26 -0
- package/.agents/scripts/lib/templates/decomposer-prompts.js +168 -0
- package/.agents/scripts/lib/test-env.js +30 -0
- package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +52 -0
- package/.agents/scripts/lib/test-isolate/list-files.js +90 -0
- package/.agents/scripts/lib/test-isolate/parse-tap.js +75 -0
- package/.agents/scripts/lib/test-isolate/runner.js +483 -0
- package/.agents/scripts/lib/test-profile/parse-tap.js +136 -0
- package/.agents/scripts/lib/test-profile/render-report.js +45 -0
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +35 -0
- package/.agents/scripts/lib/test-tiers.js +94 -0
- package/.agents/scripts/lib/util/concurrent-map.js +59 -0
- package/.agents/scripts/lib/util/phase-timer-state.js +72 -0
- package/.agents/scripts/lib/util/phase-timer.js +163 -0
- package/.agents/scripts/lib/util/poll-loop.js +86 -0
- package/.agents/scripts/lib/util/with-timeout.js +32 -0
- package/.agents/scripts/lib/validation-evidence.js +323 -0
- package/.agents/scripts/lib/wave-runner/tick.js +665 -0
- package/.agents/scripts/lib/wave-runner/wave-checkpoint.js +91 -0
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +19 -0
- package/.agents/scripts/lib/workers/crap-worker.js +197 -0
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +137 -0
- package/.agents/scripts/lib/workers/maintainability-worker.js +79 -0
- package/.agents/scripts/lib/workspace-provisioner.js +189 -0
- package/.agents/scripts/lib/worktree/bootstrapper.js +48 -0
- package/.agents/scripts/lib/worktree/inspector.js +140 -0
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +118 -0
- package/.agents/scripts/lib/worktree/lifecycle/drift-detection.js +62 -0
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +276 -0
- package/.agents/scripts/lib/worktree/lifecycle/gc.js +49 -0
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +178 -0
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +264 -0
- package/.agents/scripts/lib/worktree/lifecycle/precheck.js +100 -0
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +588 -0
- package/.agents/scripts/lib/worktree/lifecycle/registry-sync.js +124 -0
- package/.agents/scripts/lib/worktree/lifecycle/shared.js +26 -0
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +40 -0
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +349 -0
- package/.agents/scripts/lib/worktree-manager.js +243 -0
- package/.agents/scripts/lifecycle-diff.js +206 -0
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +194 -0
- package/.agents/scripts/lifecycle-emit.js +479 -0
- package/.agents/scripts/lint-baseline.js +507 -0
- package/.agents/scripts/lint-label-vocabulary.js +237 -0
- package/.agents/scripts/loc-delta.js +205 -0
- package/.agents/scripts/notify.js +307 -0
- package/.agents/scripts/package.json +3 -0
- package/.agents/scripts/post-structured-comment.js +127 -0
- package/.agents/scripts/pr-watch-with-update.js +152 -0
- package/.agents/scripts/providers/github/auth.js +65 -0
- package/.agents/scripts/providers/github/board-add.js +63 -0
- package/.agents/scripts/providers/github/branch-protection.js +186 -0
- package/.agents/scripts/providers/github/cache.js +72 -0
- package/.agents/scripts/providers/github/comments.js +131 -0
- package/.agents/scripts/providers/github/compose.js +111 -0
- package/.agents/scripts/providers/github/errors.js +242 -0
- package/.agents/scripts/providers/github/issues.js +242 -0
- package/.agents/scripts/providers/github/labels.js +179 -0
- package/.agents/scripts/providers/github/mappers.js +126 -0
- package/.agents/scripts/providers/github/merge-methods.js +82 -0
- package/.agents/scripts/providers/github/project-board.js +47 -0
- package/.agents/scripts/providers/github/projects-v2-graphql.js +472 -0
- package/.agents/scripts/providers/github/prs.js +103 -0
- package/.agents/scripts/providers/github/request-helpers.js +110 -0
- package/.agents/scripts/providers/github/sub-issues.js +369 -0
- package/.agents/scripts/providers/github/tickets.js +381 -0
- package/.agents/scripts/providers/github/transient-retry.js +62 -0
- package/.agents/scripts/providers/github.js +157 -0
- package/.agents/scripts/quality-preview.js +327 -0
- package/.agents/scripts/quality-watch.js +223 -0
- package/.agents/scripts/render-manifest.js +143 -0
- package/.agents/scripts/resync-status-column.js +176 -0
- package/.agents/scripts/retro-run.js +167 -0
- package/.agents/scripts/run-audit-suite.js +97 -0
- package/.agents/scripts/run-coverage.js +103 -0
- package/.agents/scripts/run-lint.js +94 -0
- package/.agents/scripts/run-test-profile.js +126 -0
- package/.agents/scripts/run-tests.js +185 -0
- package/.agents/scripts/run-verify.js +56 -0
- package/.agents/scripts/select-audits.js +155 -0
- package/.agents/scripts/signals-view.js +294 -0
- package/.agents/scripts/single-story-close.js +83 -0
- package/.agents/scripts/single-story-confirm-merge.js +183 -0
- package/.agents/scripts/single-story-init.js +692 -0
- package/.agents/scripts/stories-wave-tick.js +415 -0
- package/.agents/scripts/story-close.js +246 -0
- package/.agents/scripts/story-deliver-prepare.js +267 -0
- package/.agents/scripts/story-init.js +516 -0
- package/.agents/scripts/story-phase.js +327 -0
- package/.agents/scripts/story-plan.js +284 -0
- package/.agents/scripts/sync-agentrc.js +71 -0
- package/.agents/scripts/sync-branch-from-base.js +138 -0
- package/.agents/scripts/sync-claude-commands.js +151 -0
- package/.agents/scripts/test-isolate.js +222 -0
- package/.agents/scripts/test-wrapper.js +108 -0
- package/.agents/scripts/update-coverage-baseline.js +129 -0
- package/.agents/scripts/update-crap-baseline.js +177 -0
- package/.agents/scripts/update-duplication-baseline.js +134 -0
- package/.agents/scripts/update-maintainability-baseline.js +183 -0
- package/.agents/scripts/update-mutation-baseline.js +189 -0
- package/.agents/scripts/update-ticket-state.js +107 -0
- package/.agents/scripts/validate-docs-freshness.js +259 -0
- package/.agents/scripts/validate-skills.js +278 -0
- package/.agents/scripts/wave-tick.js +335 -0
- package/.agents/skills/core/analyze-execution/SKILL.md +98 -0
- package/.agents/skills/core/api-and-interface-design/SKILL.md +327 -0
- package/.agents/skills/core/baseline-refresh/SKILL.md +181 -0
- package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +352 -0
- package/.agents/skills/core/ci-cd-and-automation/SKILL.md +274 -0
- package/.agents/skills/core/ci-cd-and-automation/examples.md +211 -0
- package/.agents/skills/core/code-review-and-quality/SKILL.md +421 -0
- package/.agents/skills/core/code-simplification/SKILL.md +389 -0
- package/.agents/skills/core/context-engineering/SKILL.md +309 -0
- package/.agents/skills/core/context-engineering/examples.md +58 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +338 -0
- package/.agents/skills/core/deprecation-and-migration/SKILL.md +250 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +79 -0
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +323 -0
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +145 -0
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +425 -0
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +393 -0
- package/.agents/skills/core/frontend-ui-engineering/SKILL.md +357 -0
- package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +352 -0
- package/.agents/skills/core/hydrate-context/SKILL.md +118 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +317 -0
- package/.agents/skills/core/idea-refinement/examples.md +437 -0
- package/.agents/skills/core/idea-refinement/frameworks.md +135 -0
- package/.agents/skills/core/idea-refinement/refinement-criteria.md +155 -0
- package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +15 -0
- package/.agents/skills/core/incremental-implementation/SKILL.md +271 -0
- package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +213 -0
- package/.agents/skills/core/knowledge-transfer/SKILL.md +175 -0
- package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +117 -0
- package/.agents/skills/core/performance-optimization/SKILL.md +314 -0
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +277 -0
- package/.agents/skills/core/property-based-testing/SKILL.md +148 -0
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +105 -0
- package/.agents/skills/core/refactoring-discipline/SKILL.md +111 -0
- package/.agents/skills/core/scope-triage/SKILL.md +127 -0
- package/.agents/skills/core/security-and-hardening/SKILL.md +400 -0
- package/.agents/skills/core/shipping-and-launch/SKILL.md +328 -0
- package/.agents/skills/core/spec-driven-development/SKILL.md +252 -0
- package/.agents/skills/core/test-driven-development/SKILL.md +475 -0
- package/.agents/skills/core/using-agent-skills/SKILL.md +232 -0
- package/.agents/skills/skills.index.json +596 -0
- package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +31 -0
- package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +51 -0
- package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +48 -0
- package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +31 -0
- package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +33 -0
- package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +31 -0
- package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +51 -0
- package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +54 -0
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +29 -0
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +30 -0
- package/.agents/skills/stack/backend/stripe-integration/SKILL.md +57 -0
- package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +9 -0
- package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +48 -0
- package/.agents/skills/stack/frontend/astro/SKILL.md +62 -0
- package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +30 -0
- package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +29 -0
- package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +50 -0
- package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +58 -0
- package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +34 -0
- package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +51 -0
- package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +257 -0
- package/.agents/skills/stack/qa/gherkin-authoring/examples/invoice-issue.feature +41 -0
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +199 -0
- package/.agents/skills/stack/qa/playwright/SKILL.md +50 -0
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +188 -0
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +142 -0
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +220 -0
- package/.agents/skills/stack/qa/vitest/SKILL.md +51 -0
- package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +68 -0
- package/.agents/starter-agentrc.json +22 -0
- package/.agents/templates/agent-protocol.md +72 -0
- package/.agents/templates/docs/architecture.md +30 -0
- package/.agents/templates/docs/decisions.md +24 -0
- package/.agents/templates/epic-from-idea.md +21 -0
- package/.agents/templates/single-story-body.md +17 -0
- package/.agents/workflows/agents-update.md +415 -0
- package/.agents/workflows/audit-architecture.md +312 -0
- package/.agents/workflows/audit-clean-code.md +179 -0
- package/.agents/workflows/audit-dependencies.md +91 -0
- package/.agents/workflows/audit-devops.md +110 -0
- package/.agents/workflows/audit-lighthouse.md +260 -0
- package/.agents/workflows/audit-performance.md +161 -0
- package/.agents/workflows/audit-privacy.md +104 -0
- package/.agents/workflows/audit-quality.md +191 -0
- package/.agents/workflows/audit-security.md +156 -0
- package/.agents/workflows/audit-seo.md +118 -0
- package/.agents/workflows/audit-sre.md +139 -0
- package/.agents/workflows/audit-to-stories.md +257 -0
- package/.agents/workflows/audit-ux-ui.md +102 -0
- package/.agents/workflows/epic-deliver.md +864 -0
- package/.agents/workflows/epic-plan.md +998 -0
- package/.agents/workflows/explain.md +118 -0
- package/.agents/workflows/git-cleanup.md +250 -0
- package/.agents/workflows/git-commit-all.md +15 -0
- package/.agents/workflows/git-merge-pr.md +377 -0
- package/.agents/workflows/git-pr-all.md +278 -0
- package/.agents/workflows/git-push.md +60 -0
- package/.agents/workflows/helpers/_merge-conflict-template.md +54 -0
- package/.agents/workflows/helpers/acceptance-self-eval.md +74 -0
- package/.agents/workflows/helpers/agents-sync-config.md +129 -0
- package/.agents/workflows/helpers/code-quality-guardrails.md +101 -0
- package/.agents/workflows/helpers/code-review.md +370 -0
- package/.agents/workflows/helpers/diagnose.md +117 -0
- package/.agents/workflows/helpers/epic-audit.md +295 -0
- package/.agents/workflows/helpers/epic-deliver-story.md +370 -0
- package/.agents/workflows/helpers/epic-plan-decompose.md +199 -0
- package/.agents/workflows/helpers/epic-plan-spec.md +184 -0
- package/.agents/workflows/helpers/epic-testing.md +125 -0
- package/.agents/workflows/helpers/parallel-tooling.md +88 -0
- package/.agents/workflows/helpers/signals.md +112 -0
- package/.agents/workflows/helpers/single-story-deliver.md +636 -0
- package/.agents/workflows/helpers/worktree-lifecycle.md +317 -0
- package/.agents/workflows/onboard.md +207 -0
- package/.agents/workflows/qa-assist.md +293 -0
- package/.agents/workflows/qa-explore.md +350 -0
- package/.agents/workflows/qa-run-harness.md +288 -0
- package/.agents/workflows/story-deliver.md +327 -0
- package/.agents/workflows/story-plan.md +233 -0
- package/LICENSE +21 -0
- package/README.md +193 -0
- package/bin/mandrel.js +56 -0
- package/bin/postinstall.js +195 -0
- package/lib/cli/__tests__/migrate.test.js +268 -0
- package/lib/cli/__tests__/sync-local-zone.test.js +247 -0
- package/lib/cli/__tests__/sync.test.js +372 -0
- package/lib/cli/__tests__/update-major.test.js +217 -0
- package/lib/cli/__tests__/update.test.js +696 -0
- package/lib/cli/__tests__/version-check.test.js +398 -0
- package/lib/cli/doctor.js +124 -0
- package/lib/cli/explain.js +107 -0
- package/lib/cli/migrate.js +260 -0
- package/lib/cli/registry.js +830 -0
- package/lib/cli/sync-commands.js +50 -0
- package/lib/cli/sync.js +200 -0
- package/lib/cli/uninstall.js +795 -0
- package/lib/cli/update.js +854 -0
- package/lib/cli/version-check.js +206 -0
- package/lib/migrations/README.md +69 -0
- package/lib/migrations/__tests__/index.test.js +216 -0
- package/lib/migrations/index.js +164 -0
- package/package.json +105 -0
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `tick({ epic, collaborators })` — single callable entry point for
|
|
3
|
+
* "advance this wave one step." Stateless planner: rebuilds wave state
|
|
4
|
+
* from the `epic-run-state` checkpoint plus fresh Story labels on every
|
|
5
|
+
* call, then returns a `WaveTickResult` describing the next action.
|
|
6
|
+
*
|
|
7
|
+
* Contract (Story #1430): stateless; caller owns concurrency,
|
|
8
|
+
* worktrees, and checkpointing. Expected failures (blocked stories,
|
|
9
|
+
* gate failures) flow back through result fields; unexpected failures
|
|
10
|
+
* (GH 5xx, malformed checkpoint) throw `WaveRunnerError`.
|
|
11
|
+
*
|
|
12
|
+
* @module lib/wave-runner/tick
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
import { epicLedgerPath } from '../config/temp-paths.js';
|
|
18
|
+
import { AGENT_LABELS } from '../label-constants.js';
|
|
19
|
+
import { appendEpicSignal } from '../observability/signals-writer.js';
|
|
20
|
+
import * as epicRunStateStoreModule from '../orchestration/epic-run-state-store.js';
|
|
21
|
+
import { detectRecurringFailures } from '../orchestration/recurring-failure-detector.js';
|
|
22
|
+
import { upsertStructuredComment as defaultUpsertStructuredComment } from '../orchestration/ticketing.js';
|
|
23
|
+
|
|
24
|
+
import { collectHaltedStoryIds } from './wave-checkpoint.js';
|
|
25
|
+
import { WaveRunnerError } from './wave-runner-error.js';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Advance the wave loop one step. Returns a `WaveTickResult`:
|
|
29
|
+
*
|
|
30
|
+
* nextAction: { kind: 'dispatch', stories: [{ id, title?, worktree? }, ...] }
|
|
31
|
+
* | { kind: 'observe', waitingOn: number[] }
|
|
32
|
+
* | { kind: 'wave-complete', index: number }
|
|
33
|
+
* | { kind: 'epic-complete' }
|
|
34
|
+
* blockedStories: [{ storyId, reason, detail? }, ...]
|
|
35
|
+
* gateFailures: [{ storyId, gate, detail? }, ...]
|
|
36
|
+
* currentWave: number
|
|
37
|
+
* totalWaves: number
|
|
38
|
+
*
|
|
39
|
+
* When `spec` is omitted, the planner falls back to the checkpoint's
|
|
40
|
+
* `state.plan` (the GH-derived dependency-DAG grouping originally seeded
|
|
41
|
+
* by /epic-plan) — behaviour is byte-identical to the pre-spec path.
|
|
42
|
+
* When `spec` is supplied, wave grouping is driven by `spec.stories[].wave`
|
|
43
|
+
* (the declarative SSOT from `.agents/epics/<epic-id>.yaml`) and slugs are
|
|
44
|
+
* resolved to GH issue numbers via the sibling `<epic-id>.state.json`
|
|
45
|
+
* mapping; the checkpoint is still consulted for `currentWave`,
|
|
46
|
+
* `totalWaves`, and `waves[]` history but its `plan[]` is overridden.
|
|
47
|
+
*
|
|
48
|
+
* @typedef {object} WaveTickArgs
|
|
49
|
+
* @property {number | { id: number }} epic
|
|
50
|
+
* @property {object} [spec] Parsed epic-spec (see lib/spec/loader.js). When
|
|
51
|
+
* provided, wave grouping comes from `spec.stories[].wave`.
|
|
52
|
+
* @property {object} [state] Parsed epic-state (see lib/spec/loader.js).
|
|
53
|
+
* When `spec` is provided, this must be supplied so slugs can resolve to
|
|
54
|
+
* issue numbers via `state.mapping[slug].issueNumber`.
|
|
55
|
+
* @property {{
|
|
56
|
+
* provider?: object,
|
|
57
|
+
* epicRunStateStore?: { read: () => Promise<object|null> },
|
|
58
|
+
* signalEmit?: (signal: object) => Promise<unknown>,
|
|
59
|
+
* inFlightReader?: () => Promise<number[]>,
|
|
60
|
+
* recurringFailureReporter?: () => Promise<void>,
|
|
61
|
+
* }} [collaborators]
|
|
62
|
+
* @property {{ provider?: object, config?: object }} [ctx]
|
|
63
|
+
*
|
|
64
|
+
* @param {WaveTickArgs} args
|
|
65
|
+
*/
|
|
66
|
+
export async function tick(args = {}) {
|
|
67
|
+
const epicId = resolveEpicId(args.epic);
|
|
68
|
+
const {
|
|
69
|
+
provider: collabProvider,
|
|
70
|
+
epicRunStateStore: collabStore,
|
|
71
|
+
signalEmit,
|
|
72
|
+
inFlightReader: collabInFlightReader,
|
|
73
|
+
recurringFailureReporter: collabRecurringFailureReporter,
|
|
74
|
+
} = args.collaborators ?? {};
|
|
75
|
+
const ctx = args.ctx ?? {};
|
|
76
|
+
const provider = collabProvider ?? ctx.provider;
|
|
77
|
+
const spec = args.spec ?? null;
|
|
78
|
+
const specState = args.state ?? null;
|
|
79
|
+
if (!provider) {
|
|
80
|
+
throw new WaveRunnerError('invalid-input', 'provider is required');
|
|
81
|
+
}
|
|
82
|
+
// Story #2409 — the wave-runner tick is stateless. When the caller
|
|
83
|
+
// does not supply a collaborator shim, we read the `epic-run-state`
|
|
84
|
+
// structured comment directly via the function-based store, mirroring
|
|
85
|
+
// the pre-migration `.read()` shape exactly.
|
|
86
|
+
const epicRunStateStore = collabStore ?? {
|
|
87
|
+
read: () => epicRunStateStoreModule.read({ provider, epicId }),
|
|
88
|
+
};
|
|
89
|
+
const emit = signalEmit ?? defaultSignalEmit(epicId, ctx);
|
|
90
|
+
const inFlightReader =
|
|
91
|
+
collabInFlightReader ?? (() => defaultInFlightReader(epicId, ctx?.config));
|
|
92
|
+
|
|
93
|
+
let state;
|
|
94
|
+
try {
|
|
95
|
+
state = await epicRunStateStore.read();
|
|
96
|
+
} catch (err) {
|
|
97
|
+
throw new WaveRunnerError('checkpoint-read', err);
|
|
98
|
+
}
|
|
99
|
+
if (!state || typeof state !== 'object') {
|
|
100
|
+
throw new WaveRunnerError(
|
|
101
|
+
'checkpoint-missing',
|
|
102
|
+
`no epic-run-state comment on Epic #${epicId}`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const currentWave = positiveIntOrZero(state.currentWave);
|
|
107
|
+
const { plan, totalWaves } = resolvePlan(state, spec, specState);
|
|
108
|
+
const history = Array.isArray(state.waves) ? state.waves : [];
|
|
109
|
+
|
|
110
|
+
if (totalWaves === 0 || currentWave >= totalWaves) {
|
|
111
|
+
return tickResult({
|
|
112
|
+
nextAction: { kind: 'epic-complete' },
|
|
113
|
+
currentWave,
|
|
114
|
+
totalWaves,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const wavePlan = Array.isArray(plan[currentWave]) ? plan[currentWave] : [];
|
|
119
|
+
if (wavePlan.length === 0) {
|
|
120
|
+
await emit({
|
|
121
|
+
kind: 'wave-complete',
|
|
122
|
+
index: currentWave,
|
|
123
|
+
totalWaves,
|
|
124
|
+
empty: true,
|
|
125
|
+
});
|
|
126
|
+
return tickResult({
|
|
127
|
+
nextAction: { kind: 'wave-complete', index: currentWave },
|
|
128
|
+
currentWave,
|
|
129
|
+
totalWaves,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Story #3026 — match the iterate-waves resume-check cache strategy:
|
|
134
|
+
// only Stories that the checkpoint marks as halted on a prior wave
|
|
135
|
+
// are force-refreshed. Every other Story serves the tick fetch from
|
|
136
|
+
// the provider's in-process cache, eliminating the per-wave
|
|
137
|
+
// `fresh: true` round-trip we historically issued for every Story.
|
|
138
|
+
const haltedStoryIds = collectHaltedStoryIds(state);
|
|
139
|
+
let waveStates;
|
|
140
|
+
try {
|
|
141
|
+
waveStates = await Promise.all(
|
|
142
|
+
wavePlan.map(async (s) => {
|
|
143
|
+
const id = storyIdOf(s);
|
|
144
|
+
const opts = haltedStoryIds.has(id) ? { fresh: true } : {};
|
|
145
|
+
const ticket = await provider.getTicket(id, opts);
|
|
146
|
+
return {
|
|
147
|
+
id,
|
|
148
|
+
title: s.title ?? ticket?.title,
|
|
149
|
+
worktree: s.worktree,
|
|
150
|
+
labels: Array.isArray(ticket?.labels) ? ticket.labels : [],
|
|
151
|
+
state: ticket?.state,
|
|
152
|
+
};
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
throw new WaveRunnerError('story-fetch', err);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Story #2891 — compute in-flight Stories from the lifecycle ledger.
|
|
160
|
+
// A Story is "in-flight" when the ledger carries a
|
|
161
|
+
// `story.dispatch.start` record for it without a matching
|
|
162
|
+
// `story.dispatch.end`. The reconciliation is purely additive on the
|
|
163
|
+
// result envelope so callers can surface dispatched-but-uncompleted
|
|
164
|
+
// Stories that the per-Wave label state alone cannot reveal.
|
|
165
|
+
//
|
|
166
|
+
// Story #3907 — the in-flight set is read **before** the dispatch
|
|
167
|
+
// classification so it can be subtracted from the dispatchable set below.
|
|
168
|
+
const inFlight = await safeReadInFlight(inFlightReader);
|
|
169
|
+
const inFlightSet = new Set(inFlight);
|
|
170
|
+
|
|
171
|
+
// Story #3907 — a Story is "done" when it carries `agent::done` OR its
|
|
172
|
+
// GitHub issue is `state === 'closed'`. Reading the closed state (not just
|
|
173
|
+
// the label) means a Story closed manually through the GitHub UI — which
|
|
174
|
+
// closes the issue but does not flip the `agent::*` label — is recognised
|
|
175
|
+
// as done and is never re-dispatched.
|
|
176
|
+
const done = waveStates.filter(isStoryDone);
|
|
177
|
+
const blocked = waveStates.filter((s) =>
|
|
178
|
+
s.labels.includes(AGENT_LABELS.BLOCKED),
|
|
179
|
+
);
|
|
180
|
+
const executing = waveStates.filter((s) =>
|
|
181
|
+
s.labels.includes(AGENT_LABELS.EXECUTING),
|
|
182
|
+
);
|
|
183
|
+
// Undispatched = no terminal/in-progress label AND not closed. The closed
|
|
184
|
+
// check rides on `isStoryDone` via the negation in `isUndispatched`.
|
|
185
|
+
const undispatchedByLabel = waveStates.filter(isUndispatched);
|
|
186
|
+
|
|
187
|
+
// Story #3907 — subtract ledger in-flight Stories from the dispatch set.
|
|
188
|
+
// A Story whose `story.dispatch.start` has been recorded but whose label
|
|
189
|
+
// has not yet flipped to `agent::executing` (the child is mid-`story-init`,
|
|
190
|
+
// or the host crashed after the dispatch-ledger write but before the label
|
|
191
|
+
// flip) still looks "undispatched" by label alone. Re-dispatching it would
|
|
192
|
+
// put a second agent on the same `story-<id>` branch — the worst failure
|
|
193
|
+
// mode in the system. The ledger in-flight signal is the authoritative
|
|
194
|
+
// "already dispatched" record, so it overrides the label view here.
|
|
195
|
+
const dispatchable = undispatchedByLabel.filter(
|
|
196
|
+
(s) => !inFlightSet.has(s.id),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const blockedStories = blocked.map((s) => ({
|
|
200
|
+
storyId: s.id,
|
|
201
|
+
reason: 'agent::blocked',
|
|
202
|
+
detail: s.title,
|
|
203
|
+
}));
|
|
204
|
+
const gateFailures = readGateFailures(history, currentWave);
|
|
205
|
+
|
|
206
|
+
// Story #3062 — scan the per-Epic lifecycle ledger for recurring
|
|
207
|
+
// failure classes (≥2 distinct Stories sharing the same
|
|
208
|
+
// `close-validate.end` failedGate) and upsert a
|
|
209
|
+
// `recurring-failure-class` structured comment on the Epic when
|
|
210
|
+
// findings are returned. Idempotent across re-ticks: the upsert path
|
|
211
|
+
// diffs body bytes, so a tick that produces the same findings does not
|
|
212
|
+
// duplicate the comment. Best-effort — a reporter throw must not crash
|
|
213
|
+
// the planner.
|
|
214
|
+
const recurringFailureReporter =
|
|
215
|
+
collabRecurringFailureReporter ??
|
|
216
|
+
defaultRecurringFailureReporter({ provider, epicId, config: ctx?.config });
|
|
217
|
+
await safeReportRecurringFailures(recurringFailureReporter);
|
|
218
|
+
|
|
219
|
+
// 6. Decide nextAction.
|
|
220
|
+
let nextAction;
|
|
221
|
+
|
|
222
|
+
// Stories that are label-undispatched but recorded in-flight on the ledger
|
|
223
|
+
// (subtracted out of `dispatchable`) must be observed, not re-dispatched —
|
|
224
|
+
// see the in-flight subtraction above.
|
|
225
|
+
const inFlightUndispatched = undispatchedByLabel.filter((s) =>
|
|
226
|
+
inFlightSet.has(s.id),
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
if (blockedStories.length) {
|
|
230
|
+
nextAction = { kind: 'observe', waitingOn: blocked.map((s) => s.id) };
|
|
231
|
+
} else if (dispatchable.length) {
|
|
232
|
+
// First dispatch of this wave fires `wave-start` exactly once — the
|
|
233
|
+
// perf-aggregator (`waveParallelism` report) brackets each wave's
|
|
234
|
+
// wall-clock from `wave-start` → `wave-complete`. The ledger in-flight
|
|
235
|
+
// set is consulted alongside the label view so a dispatched-but-not-yet-
|
|
236
|
+
// executing Story does not re-fire `wave-start`.
|
|
237
|
+
if (
|
|
238
|
+
executing.length === 0 &&
|
|
239
|
+
done.length === 0 &&
|
|
240
|
+
inFlightUndispatched.length === 0
|
|
241
|
+
) {
|
|
242
|
+
await emit({
|
|
243
|
+
kind: 'wave-start',
|
|
244
|
+
index: currentWave,
|
|
245
|
+
totalWaves,
|
|
246
|
+
stories: wavePlan.map((s) => ({ id: storyIdOf(s), title: s.title })),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
nextAction = {
|
|
250
|
+
kind: 'dispatch',
|
|
251
|
+
stories: dispatchable.map((s) => ({
|
|
252
|
+
id: s.id,
|
|
253
|
+
title: s.title,
|
|
254
|
+
worktree: s.worktree,
|
|
255
|
+
})),
|
|
256
|
+
};
|
|
257
|
+
} else if (executing.length || inFlightUndispatched.length) {
|
|
258
|
+
// Either a Story is `agent::executing`, or the ledger shows a
|
|
259
|
+
// dispatched-but-unflipped Story we just declined to re-dispatch. Both
|
|
260
|
+
// are in-flight — observe rather than collapse the wave.
|
|
261
|
+
const waitingOn = [
|
|
262
|
+
...executing.map((s) => s.id),
|
|
263
|
+
...inFlightUndispatched.map((s) => s.id),
|
|
264
|
+
].sort((a, b) => a - b);
|
|
265
|
+
nextAction = { kind: 'observe', waitingOn };
|
|
266
|
+
} else if (currentWave + 1 >= totalWaves) {
|
|
267
|
+
nextAction = { kind: 'epic-complete' };
|
|
268
|
+
} else {
|
|
269
|
+
// Closes the wave window for the perf-aggregator's wall-clock bracket.
|
|
270
|
+
await emit({ kind: 'wave-complete', index: currentWave, totalWaves });
|
|
271
|
+
nextAction = { kind: 'wave-complete', index: currentWave };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Story #2891 — attach the in-flight ledger reconciliation to the
|
|
275
|
+
// nextAction envelope. Always emit the field (empty array when the
|
|
276
|
+
// ledger is silent) so downstream consumers can pattern-match on
|
|
277
|
+
// presence without an existence check.
|
|
278
|
+
nextAction['in-flight'] = inFlight;
|
|
279
|
+
|
|
280
|
+
return tickResult({
|
|
281
|
+
nextAction,
|
|
282
|
+
blockedStories,
|
|
283
|
+
gateFailures,
|
|
284
|
+
currentWave,
|
|
285
|
+
totalWaves,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Wrap the configured `inFlightReader` with a defensive guard so an
|
|
291
|
+
* unreadable ledger never crashes the tick. The default reader already
|
|
292
|
+
* returns `[]` on missing files; this catches any other shape of
|
|
293
|
+
* accidental throw and degrades to an empty list so the planner can
|
|
294
|
+
* still make a decision.
|
|
295
|
+
*
|
|
296
|
+
* @param {() => Promise<number[]>} reader
|
|
297
|
+
* @returns {Promise<number[]>}
|
|
298
|
+
*/
|
|
299
|
+
async function safeReadInFlight(reader) {
|
|
300
|
+
try {
|
|
301
|
+
const raw = await reader();
|
|
302
|
+
return Array.isArray(raw) ? raw.filter((n) => Number.isInteger(n)) : [];
|
|
303
|
+
} catch {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Default `recurringFailureReporter` collaborator — reads the per-Epic
|
|
310
|
+
* lifecycle ledger via `detectRecurringFailures`, and when at least one
|
|
311
|
+
* recurring-failure-class finding is returned, upserts a
|
|
312
|
+
* `recurring-failure-class` structured comment on the Epic ticket.
|
|
313
|
+
*
|
|
314
|
+
* The body carries the findings array verbatim in a JSON fence plus a
|
|
315
|
+
* compact human-readable bullet list keyed by gate. Idempotent across
|
|
316
|
+
* re-ticks: `upsertStructuredComment` diffs body bytes, so a tick that
|
|
317
|
+
* produces the same findings does not generate a new comment.
|
|
318
|
+
*
|
|
319
|
+
* Story #3062 (Epic #3051).
|
|
320
|
+
*
|
|
321
|
+
* @param {object} args
|
|
322
|
+
* @param {object} args.provider Ticketing provider passed to upsert.
|
|
323
|
+
* @param {number} args.epicId
|
|
324
|
+
* @param {object} [args.config]
|
|
325
|
+
* @returns {() => Promise<void>}
|
|
326
|
+
*/
|
|
327
|
+
function defaultRecurringFailureReporter({ provider, epicId, config }) {
|
|
328
|
+
return async () => {
|
|
329
|
+
const ledgerPath = epicLedgerPath(epicId, config);
|
|
330
|
+
const findings = detectRecurringFailures(epicId, { ledgerPath });
|
|
331
|
+
if (findings.length === 0) return;
|
|
332
|
+
const body = renderRecurringFailureBody(findings);
|
|
333
|
+
await defaultUpsertStructuredComment(
|
|
334
|
+
provider,
|
|
335
|
+
epicId,
|
|
336
|
+
'recurring-failure-class',
|
|
337
|
+
body,
|
|
338
|
+
);
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Render the comment body the recurring-failure-class reporter upserts.
|
|
344
|
+
* The body is deterministic given a deterministic findings array (the
|
|
345
|
+
* detector sorts findings by gate and storyIds ascending), which is what
|
|
346
|
+
* makes the upsert idempotent across re-ticks.
|
|
347
|
+
*
|
|
348
|
+
* @param {Array<{gate: string, storyIds: number[], firstSeenAt: string, lastSeenAt: string}>} findings
|
|
349
|
+
* @returns {string}
|
|
350
|
+
*/
|
|
351
|
+
export function renderRecurringFailureBody(findings) {
|
|
352
|
+
const lines = ['### 🔁 Recurring failure classes detected', ''];
|
|
353
|
+
for (const f of findings) {
|
|
354
|
+
const storiesList = f.storyIds.map((id) => `#${id}`).join(', ');
|
|
355
|
+
lines.push(
|
|
356
|
+
`- **\`${f.gate}\`** — ${f.storyIds.length} stories (${storiesList}); first \`${f.firstSeenAt}\`, last \`${f.lastSeenAt}\``,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
lines.push('');
|
|
360
|
+
lines.push('```json');
|
|
361
|
+
lines.push(
|
|
362
|
+
JSON.stringify({ kind: 'recurring-failure-class', findings }, null, 2),
|
|
363
|
+
);
|
|
364
|
+
lines.push('```');
|
|
365
|
+
return lines.join('\n');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Wrap the reporter so a throw (e.g. transient provider error, malformed
|
|
370
|
+
* ledger) never crashes the stateless tick. Best-effort — the next tick
|
|
371
|
+
* will retry.
|
|
372
|
+
*
|
|
373
|
+
* @param {() => Promise<void>} reporter
|
|
374
|
+
*/
|
|
375
|
+
async function safeReportRecurringFailures(reporter) {
|
|
376
|
+
try {
|
|
377
|
+
await reporter();
|
|
378
|
+
} catch {
|
|
379
|
+
// best-effort
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Default `inFlightReader` — parses `temp/epic-<id>/lifecycle.ndjson`
|
|
385
|
+
* and returns the Story IDs that have a `story.dispatch.start`
|
|
386
|
+
* `emitted` record without a matching `story.dispatch.end` `emitted`
|
|
387
|
+
* record. The check is order-insensitive (the wave-runner records the
|
|
388
|
+
* pair on the same Bus, so the start always lands first, but we don't
|
|
389
|
+
* depend on that here).
|
|
390
|
+
*
|
|
391
|
+
* Returns `[]` when the ledger file does not yet exist or is empty —
|
|
392
|
+
* the tick is stateless and must not throw when nothing has been
|
|
393
|
+
* dispatched on this Epic yet.
|
|
394
|
+
*
|
|
395
|
+
* @param {number} epicId
|
|
396
|
+
* @param {object|undefined} config Resolved config (forwarded to
|
|
397
|
+
* `epicLedgerPath` so `project.paths.tempRoot` overrides apply).
|
|
398
|
+
* @returns {Promise<number[]>}
|
|
399
|
+
*/
|
|
400
|
+
async function defaultInFlightReader(epicId, config) {
|
|
401
|
+
const ledgerPath = epicLedgerPath(epicId, config);
|
|
402
|
+
if (!existsSync(ledgerPath)) return [];
|
|
403
|
+
let raw;
|
|
404
|
+
try {
|
|
405
|
+
raw = readFileSync(ledgerPath, 'utf8');
|
|
406
|
+
} catch {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
if (!raw) return [];
|
|
410
|
+
const started = new Set();
|
|
411
|
+
const ended = new Set();
|
|
412
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
413
|
+
if (!line) continue;
|
|
414
|
+
let record;
|
|
415
|
+
try {
|
|
416
|
+
record = JSON.parse(line);
|
|
417
|
+
} catch {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (!record || record.kind !== 'emitted') continue;
|
|
421
|
+
const storyId = record.payload?.storyId;
|
|
422
|
+
if (!Number.isInteger(storyId) || storyId <= 0) continue;
|
|
423
|
+
if (record.event === 'story.dispatch.start') started.add(storyId);
|
|
424
|
+
else if (record.event === 'story.dispatch.end') ended.add(storyId);
|
|
425
|
+
}
|
|
426
|
+
const inFlight = [];
|
|
427
|
+
for (const id of started) {
|
|
428
|
+
if (!ended.has(id)) inFlight.push(id);
|
|
429
|
+
}
|
|
430
|
+
return inFlight;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function tickResult({
|
|
434
|
+
nextAction,
|
|
435
|
+
blockedStories = [],
|
|
436
|
+
gateFailures = [],
|
|
437
|
+
currentWave,
|
|
438
|
+
totalWaves,
|
|
439
|
+
}) {
|
|
440
|
+
return { nextAction, blockedStories, gateFailures, currentWave, totalWaves };
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function resolveEpicId(epic) {
|
|
444
|
+
const id = typeof epic === 'number' ? epic : epic?.id;
|
|
445
|
+
if (Number.isInteger(id) && id > 0) return id;
|
|
446
|
+
throw new WaveRunnerError(
|
|
447
|
+
'invalid-input',
|
|
448
|
+
`epic must be a positive integer or { id: positiveInt }; got ${
|
|
449
|
+
epic === null ? 'null' : typeof epic
|
|
450
|
+
}`,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function positiveIntOrZero(v) {
|
|
455
|
+
return Number.isInteger(v) && v >= 0 ? v : 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function storyIdOf(s) {
|
|
459
|
+
if (typeof s === 'number') return s;
|
|
460
|
+
return s.id ?? s.storyId ?? s.number;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Walk `spec.features[].stories[]` and bucket entries by their `wave`
|
|
465
|
+
* value, mapping slugs → GH issue numbers via the sibling state file.
|
|
466
|
+
* Returns `Story[][]` indexed by wave number; missing waves between 0 and
|
|
467
|
+
* the highest declared wave are emitted as empty arrays so wave N is
|
|
468
|
+
* always reachable as `plan[N]`.
|
|
469
|
+
*
|
|
470
|
+
* Each emitted entry is shaped to match the checkpoint plan's
|
|
471
|
+
* `{ id, title }` contract that the rest of `tick()` already consumes:
|
|
472
|
+
*
|
|
473
|
+
* - `id` is the GH issue number resolved from `state.mapping[slug].issueNumber`
|
|
474
|
+
* so the same provider.getTicket(id) path used by the spec-less plan
|
|
475
|
+
* keeps working unchanged.
|
|
476
|
+
* - `title` is carried through from `story.title` so the wave-start
|
|
477
|
+
* signal can include the Story's human-readable name without an
|
|
478
|
+
* extra provider round-trip.
|
|
479
|
+
* - `slug` is preserved on the entry so observability + future
|
|
480
|
+
* re-resolution paths can re-key against the spec.
|
|
481
|
+
*
|
|
482
|
+
* When a Story slug has no resolved `issueNumber` in `state.mapping`
|
|
483
|
+
* (a fresh spec entry the reconciler has not materialised yet), the entry
|
|
484
|
+
* is skipped — un-materialised Stories cannot be dispatched anyway, and
|
|
485
|
+
* including them with a `null` id would surface as a `story-fetch`
|
|
486
|
+
* failure inside `tick()`. The reconciler will close the loop on the
|
|
487
|
+
* next apply; until then, an empty wave is a faithful reflection of
|
|
488
|
+
* GitHub state.
|
|
489
|
+
*
|
|
490
|
+
* Pure function — does not read disk, does not call GH. Callers are
|
|
491
|
+
* expected to compose it with `loadSpec` + `loadState` from
|
|
492
|
+
* `lib/spec/loader.js`.
|
|
493
|
+
*
|
|
494
|
+
* @param {object} spec Parsed epic-spec (see lib/spec/loader.js).
|
|
495
|
+
* @param {{mapping?: Record<string, {issueNumber?: number}>}|null} [state]
|
|
496
|
+
* Parsed epic-state. May be omitted; if missing, no entries can be
|
|
497
|
+
* resolved and `groupByWave` returns `[]`.
|
|
498
|
+
* @returns {Array<Array<{id: number, title?: string, slug: string}>>}
|
|
499
|
+
*/
|
|
500
|
+
export function groupByWave(spec, state = null) {
|
|
501
|
+
const mapping =
|
|
502
|
+
state && typeof state.mapping === 'object' && state.mapping !== null
|
|
503
|
+
? state.mapping
|
|
504
|
+
: {};
|
|
505
|
+
const entries = extractValidStoryEntries(spec, mapping);
|
|
506
|
+
if (entries.length === 0) return [];
|
|
507
|
+
const byWave = new Map();
|
|
508
|
+
let maxWave = -1;
|
|
509
|
+
for (const { wave, entry } of entries) {
|
|
510
|
+
if (!byWave.has(wave)) byWave.set(wave, []);
|
|
511
|
+
byWave.get(wave).push(entry);
|
|
512
|
+
if (wave > maxWave) maxWave = wave;
|
|
513
|
+
}
|
|
514
|
+
if (maxWave < 0) return [];
|
|
515
|
+
const out = [];
|
|
516
|
+
for (let i = 0; i <= maxWave; i += 1) {
|
|
517
|
+
out.push(byWave.get(i) ?? []);
|
|
518
|
+
}
|
|
519
|
+
return out;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Walk every feature/story pair in `spec` and emit only the entries that
|
|
524
|
+
* survive the spec-validity cascade: the story must be a non-null object,
|
|
525
|
+
* declare a non-negative integer `wave`, declare a string `slug`, and
|
|
526
|
+
* resolve to a numeric `issueNumber` in `mapping`. Each surviving entry
|
|
527
|
+
* is returned as `{ wave, entry }` where `entry` carries the same shape
|
|
528
|
+
* (`{ id, title, slug }`) that `groupByWave` previously pushed into its
|
|
529
|
+
* per-wave bucket.
|
|
530
|
+
*
|
|
531
|
+
* Extracted from `groupByWave` so the bucketing transform stays
|
|
532
|
+
* straight-line; this predicate owns the entire defensive guard cascade
|
|
533
|
+
* and is the right place to add new validation rules going forward.
|
|
534
|
+
*
|
|
535
|
+
* @param {object|null|undefined} spec Parsed epic-spec.
|
|
536
|
+
* @param {Record<string, {issueNumber?: number}>} mapping
|
|
537
|
+
* Slug → issue-number lookup from the sibling state file.
|
|
538
|
+
* @returns {Array<{wave: number, entry: {id: number, title?: string, slug: string}}>}
|
|
539
|
+
*/
|
|
540
|
+
export function extractValidStoryEntries(spec, mapping) {
|
|
541
|
+
const out = [];
|
|
542
|
+
const features = Array.isArray(spec?.features) ? spec.features : [];
|
|
543
|
+
for (const feature of features) {
|
|
544
|
+
const stories = Array.isArray(feature?.stories) ? feature.stories : [];
|
|
545
|
+
for (const story of stories) {
|
|
546
|
+
const resolved = resolveStoryEntry(story, mapping);
|
|
547
|
+
if (resolved) out.push(resolved);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return out;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Validate a single `story` against the spec-validity cascade and return
|
|
555
|
+
* `{ wave, entry }` when every guard passes, or `null` when any guard
|
|
556
|
+
* trips. Splitting the per-story cascade out keeps both
|
|
557
|
+
* `extractValidStoryEntries` (which owns iteration) and `resolveStoryEntry`
|
|
558
|
+
* (which owns validation) below CRAP 5 even when none of the branches are
|
|
559
|
+
* exercised at runtime — the predicate's cyclomatic footprint is small
|
|
560
|
+
* enough that uncovered branches do not blow the baseline budget.
|
|
561
|
+
*
|
|
562
|
+
* @param {*} story Candidate story from `spec.features[].stories[]`.
|
|
563
|
+
* @param {Record<string, {issueNumber?: number}>} mapping Slug → issue lookup.
|
|
564
|
+
* @returns {{wave: number, entry: {id: number, title?: string, slug: string}} | null}
|
|
565
|
+
*/
|
|
566
|
+
function resolveStoryEntry(story, mapping) {
|
|
567
|
+
if (!story || typeof story !== 'object') return null;
|
|
568
|
+
if (!Number.isInteger(story.wave) || story.wave < 0) return null;
|
|
569
|
+
if (typeof story.slug !== 'string' || !story.slug) return null;
|
|
570
|
+
const mapped = mapping[story.slug];
|
|
571
|
+
if (!mapped || typeof mapped.issueNumber !== 'number') return null;
|
|
572
|
+
return {
|
|
573
|
+
wave: story.wave,
|
|
574
|
+
entry: { id: mapped.issueNumber, title: story.title, slug: story.slug },
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Resolve which plan + totalWaves drive this tick. When `spec` is
|
|
580
|
+
* supplied, the spec-derived grouping wins (and totalWaves comes from
|
|
581
|
+
* the spec since the checkpoint may lag); otherwise the checkpoint's
|
|
582
|
+
* plan is used unchanged. Extracted so `tick()`'s cyclomatic complexity
|
|
583
|
+
* stays inside its baseline budget — the route choice is now a single
|
|
584
|
+
* call, not three ternaries inline.
|
|
585
|
+
*
|
|
586
|
+
* @param {object} state Checkpoint state (already validated as object).
|
|
587
|
+
* @param {object|null} spec Parsed epic-spec or `null` when omitted.
|
|
588
|
+
* @param {object|null} specState Parsed epic-state for slug mapping.
|
|
589
|
+
* @returns {{plan: Array<Array<object>>, totalWaves: number}}
|
|
590
|
+
*/
|
|
591
|
+
function resolvePlan(state, spec, specState) {
|
|
592
|
+
if (spec) {
|
|
593
|
+
const specPlan = groupByWave(spec, specState);
|
|
594
|
+
return { plan: specPlan, totalWaves: specPlan.length };
|
|
595
|
+
}
|
|
596
|
+
const plan = Array.isArray(state.plan) ? state.plan : [];
|
|
597
|
+
return { plan, totalWaves: positiveIntOrZero(state.totalWaves) };
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* A Story is "done" when it carries `agent::done` OR its GitHub issue is
|
|
602
|
+
* `state === 'closed'`. The closed-state arm (Story #3907) is what aligns the
|
|
603
|
+
* wave planner with the other done-predicates in the codebase
|
|
604
|
+
* (`reconciler.isDone`, `verifySingleResult`) so a Story closed manually
|
|
605
|
+
* through the GitHub UI — which closes the issue without flipping the
|
|
606
|
+
* `agent::*` label — is recognised as done and never re-dispatched.
|
|
607
|
+
*
|
|
608
|
+
* @param {{ labels: string[], state?: string }} s
|
|
609
|
+
* @returns {boolean}
|
|
610
|
+
*/
|
|
611
|
+
export function isStoryDone(s) {
|
|
612
|
+
const labels = Array.isArray(s?.labels) ? s.labels : [];
|
|
613
|
+
return labels.includes(AGENT_LABELS.DONE) || s?.state === 'closed';
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* A wave member is "undispatched" when it carries none of the terminal /
|
|
618
|
+
* in-progress labels AND is not a closed issue. The closed check (Story
|
|
619
|
+
* #3907) prevents a manually-closed Story (issue closed, label not flipped)
|
|
620
|
+
* from being re-dispatched.
|
|
621
|
+
*
|
|
622
|
+
* @param {{ labels: string[], state?: string }} s
|
|
623
|
+
* @returns {boolean}
|
|
624
|
+
*/
|
|
625
|
+
function isUndispatched(s) {
|
|
626
|
+
const labels = Array.isArray(s?.labels) ? s.labels : [];
|
|
627
|
+
return (
|
|
628
|
+
!isStoryDone(s) &&
|
|
629
|
+
!labels.includes(AGENT_LABELS.BLOCKED) &&
|
|
630
|
+
!labels.includes(AGENT_LABELS.EXECUTING)
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function readGateFailures(history, currentWave) {
|
|
635
|
+
const prior = history[currentWave - 1];
|
|
636
|
+
if (!prior || !Array.isArray(prior.stories)) return [];
|
|
637
|
+
return prior.stories
|
|
638
|
+
.filter((s) => s.status === 'failed' && typeof s.detail === 'string')
|
|
639
|
+
.map((s) => ({
|
|
640
|
+
storyId: s.storyId,
|
|
641
|
+
gate: s.gate ?? 'unspecified',
|
|
642
|
+
detail: s.detail,
|
|
643
|
+
}));
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Default emitter — appends to per-Epic `signals.ndjson`. Best-effort;
|
|
648
|
+
* never throws. Tests override via `collaborators.signalEmit`.
|
|
649
|
+
*
|
|
650
|
+
* Story #3909 — the planner now emits only the two wave events that have a
|
|
651
|
+
* live consumer: `wave-start` and `wave-complete`, which the perf-aggregator
|
|
652
|
+
* (`waveParallelism` report) brackets into per-wave wall-clock. The
|
|
653
|
+
* write-only `wave-tick` (per-call telemetry) and `epic-complete` (no reader)
|
|
654
|
+
* emits were dropped — they duplicated the `epic-run-state` checkpoint and the
|
|
655
|
+
* `epic-run-progress` rollup and nothing consumed them.
|
|
656
|
+
*/
|
|
657
|
+
function defaultSignalEmit(epicId, ctx) {
|
|
658
|
+
return async (signal) => {
|
|
659
|
+
await appendEpicSignal({
|
|
660
|
+
epicId,
|
|
661
|
+
signal: { ts: new Date().toISOString(), epic: epicId, ...signal },
|
|
662
|
+
config: ctx?.config,
|
|
663
|
+
});
|
|
664
|
+
};
|
|
665
|
+
}
|