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,797 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/orchestration/epic-spec-reconciler-apply.js — apply engine for the
|
|
3
|
+
* epic-spec reconciler (Epic #1182 / Tech Spec #1483 / Story #1494).
|
|
4
|
+
*
|
|
5
|
+
* Consumes a `Plan` produced by `epic-spec-reconciler-diff.js#diff()` and
|
|
6
|
+
* materialises the operations against an `ITicketingProvider` with
|
|
7
|
+
* bounded concurrency. The apply engine is the only place in the
|
|
8
|
+
* structural reconciler that touches the world — every other module in
|
|
9
|
+
* the surface (`epic-spec-reconciler-ops.js`,
|
|
10
|
+
* `epic-spec-reconciler-diff.js`,
|
|
11
|
+
* `epic-spec-reconciler-discriminator.js`,
|
|
12
|
+
* `epic-spec-reconciler-format.js`) is intentionally I/O-free so the
|
|
13
|
+
* data path can be unit-tested in isolation.
|
|
14
|
+
*
|
|
15
|
+
* ## Contract
|
|
16
|
+
*
|
|
17
|
+
* - `apply(plan, opts)` — executes the plan and returns a typed result
|
|
18
|
+
* envelope describing what was created, updated, closed, or
|
|
19
|
+
* relinked. The envelope's shape is stable and machine-readable.
|
|
20
|
+
* - Concurrency is bounded at 4 via `concurrentMap` from
|
|
21
|
+
* `lib/util/concurrent-map.js`. The cap matches the
|
|
22
|
+
* `RECONCILE_CONCURRENCY` constant in
|
|
23
|
+
* `lib/orchestration/reconciler.js:18` so structural and
|
|
24
|
+
* label-hygiene reconciliation operate at the same provider load.
|
|
25
|
+
* - `opts.dryRun === true` short-circuits with zero provider calls.
|
|
26
|
+
* The returned envelope echoes the plan's intent (`created`,
|
|
27
|
+
* `updated`, `closed`, `relinked` arrays populated from the plan
|
|
28
|
+
* ops, marked `dryRun: true`).
|
|
29
|
+
* - The discriminator gates (`mayClose`, `mayUpdate`) are re-asserted
|
|
30
|
+
* before any mutation runs. A plan op that fails the gate aborts
|
|
31
|
+
* `apply` synchronously (Promise rejection) **before** any provider
|
|
32
|
+
* call is dispatched, so partial failure of a forbidden op is
|
|
33
|
+
* impossible.
|
|
34
|
+
* - `assertPlanLabelAllowList` is invoked unconditionally at entry to
|
|
35
|
+
* re-prove the safety net even on hand-built plans (diff already
|
|
36
|
+
* asserts; we double-check at apply because tests and CLI callers
|
|
37
|
+
* may bypass the diff path).
|
|
38
|
+
*
|
|
39
|
+
* ## Result envelope
|
|
40
|
+
*
|
|
41
|
+
* @typedef {object} ApplyResultEntry
|
|
42
|
+
* @property {string} slug
|
|
43
|
+
* @property {string} entity
|
|
44
|
+
* @property {string} kind 'create'|'update'|'close'|'relink'
|
|
45
|
+
* @property {number} [issueNumber] Resulting issue number (post-create)
|
|
46
|
+
* or the targeted issue number for
|
|
47
|
+
* update/close/relink.
|
|
48
|
+
* @property {string} [url] Issue URL when the provider returned one.
|
|
49
|
+
*
|
|
50
|
+
* @typedef {object} ApplyResult
|
|
51
|
+
* @property {boolean} dryRun
|
|
52
|
+
* @property {ApplyResultEntry[]} created
|
|
53
|
+
* @property {ApplyResultEntry[]} updated
|
|
54
|
+
* @property {ApplyResultEntry[]} closed
|
|
55
|
+
* @property {ApplyResultEntry[]} relinked
|
|
56
|
+
* @property {Record<string, number>} slugToIssue
|
|
57
|
+
* Post-apply slug → issue mapping. On full success, this is the
|
|
58
|
+
* complete map; on partial failure, it reflects creates that landed
|
|
59
|
+
* before the failure.
|
|
60
|
+
* @property {object} [state] The state object the apply
|
|
61
|
+
* pipeline persisted via the
|
|
62
|
+
* `writeState` hook. Omitted when
|
|
63
|
+
* `opts.spec` was not supplied.
|
|
64
|
+
* @property {string} [statePath] Absolute path the default
|
|
65
|
+
* writer returned; omitted when a
|
|
66
|
+
* custom `writeState` hook ran or
|
|
67
|
+
* when no spec was supplied.
|
|
68
|
+
* @property {Error} [failure] Present only when apply exited
|
|
69
|
+
* via partial-failure: the
|
|
70
|
+
* provider error that aborted
|
|
71
|
+
* further dispatch. The state file
|
|
72
|
+
* was still written to reflect the
|
|
73
|
+
* successful ops so the operator
|
|
74
|
+
* can resume cleanly.
|
|
75
|
+
*
|
|
76
|
+
* @typedef {object} ApplyOptions
|
|
77
|
+
* @property {boolean} [dryRun] Skip provider calls; echo plan.
|
|
78
|
+
* @property {number} [concurrency] Override the default cap (4).
|
|
79
|
+
* Tests use 1 to assert order.
|
|
80
|
+
* @property {number} [epicId] Required for create ops — the
|
|
81
|
+
* parent Epic issue number that
|
|
82
|
+
* feeds into createTicket's
|
|
83
|
+
* ticketData.epicId field.
|
|
84
|
+
* @property {Record<string, number>} [slugToIssue]
|
|
85
|
+
* Pre-seeded slug → issue map.
|
|
86
|
+
* Apply populates it as creates
|
|
87
|
+
* land so child creates can
|
|
88
|
+
* resolve parentSlug → parentId.
|
|
89
|
+
* Callers (state writer) may
|
|
90
|
+
* read the post-apply state from
|
|
91
|
+
* the returned envelope's
|
|
92
|
+
* `slugToIssue` field.
|
|
93
|
+
* @property {object} [storySnapshots] Optional snapshot map keyed
|
|
94
|
+
* by slug carrying live
|
|
95
|
+
* execution state for the
|
|
96
|
+
* close-discriminator. When
|
|
97
|
+
* absent, close ops require
|
|
98
|
+
* `explicitDelete: true` per
|
|
99
|
+
* the discriminator's default.
|
|
100
|
+
* @property {boolean} [explicitDelete] Operator opt-in: passes
|
|
101
|
+
* through to `mayClose`.
|
|
102
|
+
* @property {object} [spec] Parsed spec used to derive
|
|
103
|
+
* the post-apply state-file
|
|
104
|
+
* mapping (Task #1518). When
|
|
105
|
+
* omitted, apply does not
|
|
106
|
+
* touch state.json — useful
|
|
107
|
+
* for tests that only want to
|
|
108
|
+
* drive the provider surface.
|
|
109
|
+
* @property {object} [priorState] Prior state loaded from
|
|
110
|
+
* `<epicId>.state.json` (carries
|
|
111
|
+
* pre-existing slug → issue
|
|
112
|
+
* mappings and observed agent
|
|
113
|
+
* states for slugs unchanged
|
|
114
|
+
* by this apply).
|
|
115
|
+
* @property {string} [stateNow] Override for the
|
|
116
|
+
* `lastReconciledAt` timestamp.
|
|
117
|
+
* Tests pass a fixed string so
|
|
118
|
+
* the rendered state is
|
|
119
|
+
* byte-stable.
|
|
120
|
+
* @property {(epicId: number, state: object) => string} [writeState]
|
|
121
|
+
* Optional state writer
|
|
122
|
+
* injection point. Defaults to
|
|
123
|
+
* `lib/spec/loader.js#writeState`.
|
|
124
|
+
* Tests pass an in-memory
|
|
125
|
+
* spy so apply does not touch
|
|
126
|
+
* the real on-disk file.
|
|
127
|
+
* @property {{epicsDir?: string}} [writeStateOpts]
|
|
128
|
+
* Forwarded to the default
|
|
129
|
+
* `writeState` adapter so tests
|
|
130
|
+
* can redirect the on-disk
|
|
131
|
+
* output to a tmp dir.
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
import { Logger } from '../Logger.js';
|
|
135
|
+
import { writeState as defaultWriteState } from '../spec/loader.js';
|
|
136
|
+
import { buildState } from '../spec/state.js';
|
|
137
|
+
import { concurrentMap } from '../util/concurrent-map.js';
|
|
138
|
+
import {
|
|
139
|
+
assertPlanLabelAllowList,
|
|
140
|
+
mayClose,
|
|
141
|
+
mayUpdate,
|
|
142
|
+
} from './epic-spec-reconciler-discriminator.js';
|
|
143
|
+
import { isPlan, OP_KINDS } from './epic-spec-reconciler-ops.js';
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Default concurrency cap. Hard-pinned to 4 to match
|
|
147
|
+
* `RECONCILE_CONCURRENCY` declared in
|
|
148
|
+
* `.agents/scripts/lib/orchestration/reconciler.js:18`. That constant is
|
|
149
|
+
* file-local in `reconciler.js`; rather than widen its surface for one
|
|
150
|
+
* caller, we duplicate the value with a documented cross-reference. The
|
|
151
|
+
* sibling `concurrency-wiring.test.js` suite owns the invariant that
|
|
152
|
+
* these two values stay in sync.
|
|
153
|
+
*/
|
|
154
|
+
export const APPLY_CONCURRENCY = 4;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Error class thrown when a plan operation fails a discriminator gate.
|
|
158
|
+
* Carrying structured metadata (`slug`, `field`, `reason`) lets the CLI
|
|
159
|
+
* report which op was rejected without re-parsing the message.
|
|
160
|
+
*/
|
|
161
|
+
export class ApplyGateViolation extends Error {
|
|
162
|
+
/**
|
|
163
|
+
* @param {string} message
|
|
164
|
+
* @param {{slug?: string, kind?: string, field?: string, reason?: string}} [meta]
|
|
165
|
+
*/
|
|
166
|
+
constructor(message, meta = {}) {
|
|
167
|
+
super(message);
|
|
168
|
+
this.name = 'ApplyGateViolation';
|
|
169
|
+
if (meta.slug !== undefined) this.slug = meta.slug;
|
|
170
|
+
if (meta.kind !== undefined) this.kind = meta.kind;
|
|
171
|
+
if (meta.field !== undefined) this.field = meta.field;
|
|
172
|
+
if (meta.reason !== undefined) this.reason = meta.reason;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Pre-flight gate check. Walks every op in the plan and asserts each one
|
|
178
|
+
* passes its discriminator. Throws `ApplyGateViolation` on the first
|
|
179
|
+
* failure so apply aborts before dispatching any provider call.
|
|
180
|
+
*
|
|
181
|
+
* Update ops are checked field-by-field: every key in `op.changes` must
|
|
182
|
+
* pass `mayUpdate(_, field)`. The diff engine already constrains keys to
|
|
183
|
+
* the structural allow-list, but we re-check here so a hand-built plan
|
|
184
|
+
* cannot bypass the safety net.
|
|
185
|
+
*
|
|
186
|
+
* Close ops consult `mayClose(snapshot, { explicitDelete })`. The
|
|
187
|
+
* snapshot is looked up from `opts.storySnapshots` keyed by slug;
|
|
188
|
+
* absence is fine — `mayClose` defaults to the conservative "require
|
|
189
|
+
* explicit delete" path.
|
|
190
|
+
*
|
|
191
|
+
* @param {import('./epic-spec-reconciler-ops.js').Plan} plan
|
|
192
|
+
* @param {ApplyOptions} opts
|
|
193
|
+
* @returns {void}
|
|
194
|
+
*/
|
|
195
|
+
function assertGates(plan, opts) {
|
|
196
|
+
for (const op of plan.updates) {
|
|
197
|
+
for (const field of Object.keys(op.changes ?? {})) {
|
|
198
|
+
const result = mayUpdate(undefined, field);
|
|
199
|
+
if (!result.allowed) {
|
|
200
|
+
throw new ApplyGateViolation(
|
|
201
|
+
`update for slug=${op.slug} field=${field} blocked: ${result.reason}`,
|
|
202
|
+
{ slug: op.slug, kind: 'update', field, reason: result.reason },
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
for (const op of plan.closes) {
|
|
208
|
+
const snapshot = opts.storySnapshots?.[op.slug];
|
|
209
|
+
const result = mayClose(snapshot, {
|
|
210
|
+
explicitDelete: opts.explicitDelete === true,
|
|
211
|
+
});
|
|
212
|
+
if (!result.allowed) {
|
|
213
|
+
throw new ApplyGateViolation(
|
|
214
|
+
`close for slug=${op.slug} blocked: ${result.reason}`,
|
|
215
|
+
{ slug: op.slug, kind: 'close', reason: result.reason },
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Build a dry-run envelope that echoes the plan's intent without making
|
|
223
|
+
* provider calls. Useful for CLI `--dry-run` output and for the apply
|
|
224
|
+
* pipeline's preview path.
|
|
225
|
+
*
|
|
226
|
+
* @param {import('./epic-spec-reconciler-ops.js').Plan} plan
|
|
227
|
+
* @param {Record<string, number>} slugToIssue
|
|
228
|
+
* @returns {ApplyResult}
|
|
229
|
+
*/
|
|
230
|
+
/**
|
|
231
|
+
* Seed `slugToIssue.epic` so child features can resolve
|
|
232
|
+
* `parentSlug: 'epic'` through `resolveParentId`. Story #1820: the CLI
|
|
233
|
+
* seeds `state.mapping.epic` so diff no longer emits a Create for the
|
|
234
|
+
* epic; without this matching seed on the apply side, `slugToIssue.epic`
|
|
235
|
+
* is never populated and the first feature create throws "parent slug
|
|
236
|
+
* epic has no mapped issue number". Priority order:
|
|
237
|
+
* 1. Existing `slugToIssue.epic` (caller-supplied) — wins.
|
|
238
|
+
* 2. `opts.priorState.mapping.epic.issueNumber`.
|
|
239
|
+
* 3. `opts.epicId`.
|
|
240
|
+
*
|
|
241
|
+
* @param {Record<string, number>} slugToIssue cloned mapping (mutated in place)
|
|
242
|
+
* @param {ApplyOptions} opts
|
|
243
|
+
* @returns {Record<string, number>} same mapping, returned for chaining
|
|
244
|
+
*/
|
|
245
|
+
function seedEpicSlug(slugToIssue, opts) {
|
|
246
|
+
if (typeof slugToIssue.epic === 'number') return slugToIssue;
|
|
247
|
+
const priorEpicNumber = opts.priorState?.mapping?.epic?.issueNumber;
|
|
248
|
+
const seed =
|
|
249
|
+
typeof priorEpicNumber === 'number'
|
|
250
|
+
? priorEpicNumber
|
|
251
|
+
: typeof opts.epicId === 'number'
|
|
252
|
+
? opts.epicId
|
|
253
|
+
: null;
|
|
254
|
+
if (seed !== null) slugToIssue.epic = seed;
|
|
255
|
+
return slugToIssue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function buildDryRunResult(plan, slugToIssue) {
|
|
259
|
+
return {
|
|
260
|
+
dryRun: true,
|
|
261
|
+
created: plan.creates.map((op) => ({
|
|
262
|
+
slug: op.slug,
|
|
263
|
+
entity: op.entity,
|
|
264
|
+
kind: OP_KINDS.CREATE,
|
|
265
|
+
})),
|
|
266
|
+
updated: plan.updates.map((op) => ({
|
|
267
|
+
slug: op.slug,
|
|
268
|
+
entity: op.entity,
|
|
269
|
+
kind: OP_KINDS.UPDATE,
|
|
270
|
+
issueNumber: op.issueNumber,
|
|
271
|
+
})),
|
|
272
|
+
closed: plan.closes.map((op) => ({
|
|
273
|
+
slug: op.slug,
|
|
274
|
+
entity: op.entity,
|
|
275
|
+
kind: OP_KINDS.CLOSE,
|
|
276
|
+
issueNumber: op.issueNumber,
|
|
277
|
+
})),
|
|
278
|
+
relinked: plan.relinks.map((op) => ({
|
|
279
|
+
slug: op.slug,
|
|
280
|
+
entity: op.entity,
|
|
281
|
+
kind: OP_KINDS.RELINK,
|
|
282
|
+
issueNumber: op.issueNumber,
|
|
283
|
+
})),
|
|
284
|
+
slugToIssue: { ...slugToIssue },
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Resolve a parent slug to an issue number using the running map. Throws
|
|
290
|
+
* a structured error if the slug is required but unknown — apply must
|
|
291
|
+
* not silently drop a parent edge.
|
|
292
|
+
*
|
|
293
|
+
* @param {string|undefined} slug
|
|
294
|
+
* @param {Record<string, number>} slugToIssue
|
|
295
|
+
* @returns {number|undefined}
|
|
296
|
+
*/
|
|
297
|
+
function resolveParentId(slug, slugToIssue) {
|
|
298
|
+
if (!slug) return undefined;
|
|
299
|
+
const id = slugToIssue[slug];
|
|
300
|
+
if (typeof id !== 'number') {
|
|
301
|
+
throw new ApplyGateViolation(
|
|
302
|
+
`apply: parent slug ${slug} has no mapped issue number`,
|
|
303
|
+
{ slug, kind: 'create', reason: 'unmapped-parent' },
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
return id;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Resolve a dependsOn slug list to its issue numbers, failing loud on any
|
|
311
|
+
* unresolved slug. The reconciler hands the resolved numbers to
|
|
312
|
+
* `createTicket` as `ticketData.dependencies`; the provider's
|
|
313
|
+
* `composeStoryBody` is the single owner that renders the canonical
|
|
314
|
+
* `blocked by #N` footer from them (Story #3958). The reconciler must NOT
|
|
315
|
+
* also pre-append a footer to the body — doing so doubled every dependency
|
|
316
|
+
* line, since `composeStoryBody` appends from `dependencies` independently.
|
|
317
|
+
*
|
|
318
|
+
* Fail-loud is preserved here (not delegated to the body composer): an
|
|
319
|
+
* unresolved slug means `topoSortCreates` failed to order a dependency
|
|
320
|
+
* ahead of its dependent, which would otherwise be silently dropped by
|
|
321
|
+
* `dependencies`' number filter. Returns `[]` when no deps.
|
|
322
|
+
*
|
|
323
|
+
* @param {string[]|undefined} dependsOn
|
|
324
|
+
* @param {Record<string, number>} slugToIssue
|
|
325
|
+
* @returns {number[]}
|
|
326
|
+
*/
|
|
327
|
+
function resolveDependencies(dependsOn, slugToIssue) {
|
|
328
|
+
if (!Array.isArray(dependsOn) || dependsOn.length === 0) return [];
|
|
329
|
+
const resolved = [];
|
|
330
|
+
const unresolved = [];
|
|
331
|
+
for (const slug of dependsOn) {
|
|
332
|
+
const issueNumber = slugToIssue[slug];
|
|
333
|
+
if (typeof issueNumber === 'number') {
|
|
334
|
+
resolved.push(issueNumber);
|
|
335
|
+
} else {
|
|
336
|
+
unresolved.push(slug);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (unresolved.length > 0) {
|
|
340
|
+
throw new Error(
|
|
341
|
+
`[reconciler] resolveDependencies: unresolved dependsOn slugs: ${unresolved.join(', ')}. ` +
|
|
342
|
+
`topoSortCreates must order dependencies ahead of dependents.`,
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return resolved;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Materialise a single create op. The provider returns
|
|
350
|
+
* `{ id, url }`; we record the slug → id mapping and reflect it in the
|
|
351
|
+
* envelope.
|
|
352
|
+
*
|
|
353
|
+
* @param {import('./epic-spec-reconciler-ops.js').CreateOp} op
|
|
354
|
+
* @param {object} provider
|
|
355
|
+
* @param {ApplyOptions} opts
|
|
356
|
+
* @param {Record<string, number>} slugToIssue
|
|
357
|
+
* @returns {Promise<ApplyResultEntry>}
|
|
358
|
+
*/
|
|
359
|
+
async function applyCreate(op, provider, opts, slugToIssue) {
|
|
360
|
+
const parentId = resolveParentId(op.parentSlug, slugToIssue);
|
|
361
|
+
const epicId = typeof opts.epicId === 'number' ? opts.epicId : parentId;
|
|
362
|
+
// Story #3958 — resolve (and fail-loud validate) the dependency issue
|
|
363
|
+
// numbers, but do NOT pre-append a `blocked by #N` footer to the body.
|
|
364
|
+
// `composeStoryBody` (the provider's createTicket renderer) is the single
|
|
365
|
+
// owner of that footer; appending here too doubled every dependency line.
|
|
366
|
+
const dependencies = resolveDependencies(op.dependsOn, slugToIssue);
|
|
367
|
+
const ticketData = {
|
|
368
|
+
epicId,
|
|
369
|
+
title: op.title,
|
|
370
|
+
body: op.body ?? '',
|
|
371
|
+
labels: op.labels ?? [],
|
|
372
|
+
dependencies,
|
|
373
|
+
};
|
|
374
|
+
// Epic-level create has no parent — the provider's createTicket
|
|
375
|
+
// expects a parent for sub-issue linkage. For the epic op we route to
|
|
376
|
+
// the same surface but the parentId fallback (epicId) is fine since
|
|
377
|
+
// the epic *is* its own anchor; the diff engine never emits this in
|
|
378
|
+
// practice (the epic is bootstrapped before reconciliation), but we
|
|
379
|
+
// keep the path safe.
|
|
380
|
+
const created = await provider.createTicket(parentId ?? epicId, ticketData);
|
|
381
|
+
if (created && typeof created.id === 'number') {
|
|
382
|
+
slugToIssue[op.slug] = created.id;
|
|
383
|
+
}
|
|
384
|
+
// Defence — Story #2063. GitHubProvider.createTicket captures a
|
|
385
|
+
// failed addSubIssue mutation into `{ subIssueLinked: false,
|
|
386
|
+
// subIssueError }` rather than throwing, so a transient GraphQL
|
|
387
|
+
// failure (secondary rate-limit, "Something went wrong" envelope,
|
|
388
|
+
// etc.) leaves the issue created on GH but with no native sub-issue
|
|
389
|
+
// link to its parent. The previous behaviour swallowed this
|
|
390
|
+
// entirely — a partial backlog persisted with no operator-visible
|
|
391
|
+
// signal. Surface it here at WARN so the breadcrumb is visible; the
|
|
392
|
+
// canonical repair runs in `runDecomposePhase` via
|
|
393
|
+
// `reconcileSubIssueLinks(epicId)` after every apply pass.
|
|
394
|
+
if (created && created.subIssueLinked === false) {
|
|
395
|
+
const reason =
|
|
396
|
+
created.subIssueError?.message ?? 'no error message captured';
|
|
397
|
+
Logger.warn(
|
|
398
|
+
`[reconciler.apply] sub-issue link failed for child #${created.id} (parent #${parentId ?? epicId}): ${reason}. The runDecomposePhase safety net will retry.`,
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
slug: op.slug,
|
|
403
|
+
entity: op.entity,
|
|
404
|
+
kind: OP_KINDS.CREATE,
|
|
405
|
+
issueNumber: created?.id,
|
|
406
|
+
url: created?.url,
|
|
407
|
+
subIssueLinked: created?.subIssueLinked,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Materialise a single update op. Translates the plan's `changes` map
|
|
413
|
+
* into the provider's `mutations` shape: `title`/`body` map directly,
|
|
414
|
+
* `labels` becomes `{ add, remove }` derived from the before/after
|
|
415
|
+
* difference, and `wave` is appended to the body marker (the wave
|
|
416
|
+
* integer lives in the body, not on a label).
|
|
417
|
+
*
|
|
418
|
+
* @param {import('./epic-spec-reconciler-ops.js').UpdateOp} op
|
|
419
|
+
* @param {object} provider
|
|
420
|
+
* @returns {Promise<ApplyResultEntry>}
|
|
421
|
+
*/
|
|
422
|
+
async function applyUpdate(op, provider) {
|
|
423
|
+
const mutations = {};
|
|
424
|
+
const changes = op.changes ?? {};
|
|
425
|
+
if (changes.title) {
|
|
426
|
+
mutations.title = changes.title.after;
|
|
427
|
+
}
|
|
428
|
+
if (changes.body) {
|
|
429
|
+
mutations.body = changes.body.after;
|
|
430
|
+
}
|
|
431
|
+
if (changes.labels) {
|
|
432
|
+
const before = new Set(changes.labels.before ?? []);
|
|
433
|
+
const after = new Set(changes.labels.after ?? []);
|
|
434
|
+
const add = [...after].filter((l) => !before.has(l));
|
|
435
|
+
const remove = [...before].filter((l) => !after.has(l));
|
|
436
|
+
if (add.length || remove.length) {
|
|
437
|
+
mutations.labels = { add, remove };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
await provider.updateTicket(op.issueNumber, mutations);
|
|
441
|
+
return {
|
|
442
|
+
slug: op.slug,
|
|
443
|
+
entity: op.entity,
|
|
444
|
+
kind: OP_KINDS.UPDATE,
|
|
445
|
+
issueNumber: op.issueNumber,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Materialise a single close op. The provider's `updateTicket`
|
|
451
|
+
* mutation surface accepts `{ state: 'closed' }`, matching the mock
|
|
452
|
+
* provider in `tests/fixtures/mock-provider.js`.
|
|
453
|
+
*
|
|
454
|
+
* @param {import('./epic-spec-reconciler-ops.js').CloseOp} op
|
|
455
|
+
* @param {object} provider
|
|
456
|
+
* @returns {Promise<ApplyResultEntry>}
|
|
457
|
+
*/
|
|
458
|
+
async function applyClose(op, provider) {
|
|
459
|
+
await provider.updateTicket(op.issueNumber, { state: 'closed' });
|
|
460
|
+
return {
|
|
461
|
+
slug: op.slug,
|
|
462
|
+
entity: op.entity,
|
|
463
|
+
kind: OP_KINDS.CLOSE,
|
|
464
|
+
issueNumber: op.issueNumber,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Materialise a single relink op. Parent edge changes are written by
|
|
470
|
+
* removing the existing sub-issue link (when present) and adding the
|
|
471
|
+
* new one. DependsOn edge changes rewrite the body's `blocked by`
|
|
472
|
+
* footer; we surface the new edge list to the provider via an
|
|
473
|
+
* `updateTicket` body mutation. The plan carries before/after so the
|
|
474
|
+
* caller can render the body locally without re-fetching the ticket
|
|
475
|
+
* (`opts.bodyRenderer` injects the renderer; absence = no-op on body).
|
|
476
|
+
*
|
|
477
|
+
* @param {import('./epic-spec-reconciler-ops.js').RelinkOp} op
|
|
478
|
+
* @param {object} provider
|
|
479
|
+
* @param {Record<string, number>} slugToIssue
|
|
480
|
+
* @returns {Promise<ApplyResultEntry>}
|
|
481
|
+
*/
|
|
482
|
+
async function applyRelink(op, provider, slugToIssue) {
|
|
483
|
+
if (op.parent) {
|
|
484
|
+
const before = op.parent.before;
|
|
485
|
+
const after = op.parent.after;
|
|
486
|
+
if (before) {
|
|
487
|
+
const beforeId = slugToIssue[before];
|
|
488
|
+
if (typeof beforeId === 'number') {
|
|
489
|
+
await provider.removeSubIssue(beforeId, op.issueNumber);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (after) {
|
|
493
|
+
const afterId = slugToIssue[after];
|
|
494
|
+
if (typeof afterId === 'number') {
|
|
495
|
+
await provider.addSubIssue(afterId, op.issueNumber);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
// Story #2982 — dependsOn edge changes no longer write the body here.
|
|
500
|
+
// The diff engine recomposes the canonical orchestrator footer
|
|
501
|
+
// (`---\nparent:`/`Epic:`/`blocked by`) and routes a body change
|
|
502
|
+
// through `applyUpdate`. Writing it from the relink path stripped
|
|
503
|
+
// description + parent + Epic on every dep change. The relink op
|
|
504
|
+
// remains the authoritative carrier of the dependsOn delta for the
|
|
505
|
+
// state writer and for the parent sub-issue add/remove above.
|
|
506
|
+
return {
|
|
507
|
+
slug: op.slug,
|
|
508
|
+
entity: op.entity,
|
|
509
|
+
kind: OP_KINDS.RELINK,
|
|
510
|
+
issueNumber: op.issueNumber,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Apply a plan against an `ITicketingProvider`.
|
|
516
|
+
*
|
|
517
|
+
* Execution order: creates → updates → closes → relinks. Creates run
|
|
518
|
+
* first so subsequent updates/relinks can target the newly minted
|
|
519
|
+
* issue numbers (the running `slugToIssue` map propagates IDs across
|
|
520
|
+
* phases). Within each phase, ops are dispatched through `concurrentMap`
|
|
521
|
+
* at cap=4.
|
|
522
|
+
*
|
|
523
|
+
* Errors:
|
|
524
|
+
* - `ApplyGateViolation` — pre-flight gate failed; no provider call
|
|
525
|
+
* was issued.
|
|
526
|
+
* - Provider errors — `concurrentMap`'s first-rejection-wins semantics
|
|
527
|
+
* surface the first failure; later rejections are swallowed. The
|
|
528
|
+
* `slugToIssue` map reflects whatever creates completed before the
|
|
529
|
+
* failure, so the caller (state writer) can persist a partial
|
|
530
|
+
* mapping if desired.
|
|
531
|
+
*
|
|
532
|
+
* @param {import('./epic-spec-reconciler-ops.js').Plan} plan
|
|
533
|
+
* @param {object} provider ITicketingProvider instance.
|
|
534
|
+
* @param {ApplyOptions} [opts]
|
|
535
|
+
* @returns {Promise<ApplyResult>}
|
|
536
|
+
*/
|
|
537
|
+
export async function apply(plan, provider, opts = {}) {
|
|
538
|
+
if (!isPlan(plan)) {
|
|
539
|
+
throw new TypeError('apply: plan must conform to the Plan shape');
|
|
540
|
+
}
|
|
541
|
+
if (!provider || typeof provider !== 'object') {
|
|
542
|
+
throw new TypeError('apply: provider is required');
|
|
543
|
+
}
|
|
544
|
+
// Re-prove the label allow-list safety net at the apply boundary.
|
|
545
|
+
assertPlanLabelAllowList(plan);
|
|
546
|
+
|
|
547
|
+
const concurrency =
|
|
548
|
+
typeof opts.concurrency === 'number' && opts.concurrency > 0
|
|
549
|
+
? opts.concurrency
|
|
550
|
+
: APPLY_CONCURRENCY;
|
|
551
|
+
const slugToIssue = seedEpicSlug({ ...(opts.slugToIssue ?? {}) }, opts);
|
|
552
|
+
|
|
553
|
+
if (opts.dryRun === true) {
|
|
554
|
+
return buildDryRunResult(plan, slugToIssue);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Pre-flight gates. Throws synchronously before any provider call.
|
|
558
|
+
assertGates(plan, opts);
|
|
559
|
+
|
|
560
|
+
const created = [];
|
|
561
|
+
const updated = [];
|
|
562
|
+
const closed = [];
|
|
563
|
+
const relinked = [];
|
|
564
|
+
let failure = null;
|
|
565
|
+
|
|
566
|
+
// Phase 1: creates. Topo-batched so parent issues materialise before
|
|
567
|
+
// their children.
|
|
568
|
+
try {
|
|
569
|
+
const orderedCreates = topoSortCreates(plan.creates, slugToIssue);
|
|
570
|
+
for (const batch of orderedCreates) {
|
|
571
|
+
const batchResults = await concurrentMap(
|
|
572
|
+
batch,
|
|
573
|
+
(op) => applyCreate(op, provider, opts, slugToIssue),
|
|
574
|
+
{ concurrency },
|
|
575
|
+
);
|
|
576
|
+
created.push(...batchResults);
|
|
577
|
+
}
|
|
578
|
+
// Phase 2: updates. Independent — run in parallel.
|
|
579
|
+
updated.push(
|
|
580
|
+
...(await concurrentMap(plan.updates, (op) => applyUpdate(op, provider), {
|
|
581
|
+
concurrency,
|
|
582
|
+
})),
|
|
583
|
+
);
|
|
584
|
+
// Phase 3: closes. Independent — run in parallel. Note we remove the
|
|
585
|
+
// slug from `slugToIssue` so the projected state mapping drops it
|
|
586
|
+
// (matches the AC: closes disappear from state).
|
|
587
|
+
closed.push(
|
|
588
|
+
...(await concurrentMap(
|
|
589
|
+
plan.closes,
|
|
590
|
+
async (op) => {
|
|
591
|
+
const entry = await applyClose(op, provider);
|
|
592
|
+
delete slugToIssue[op.slug];
|
|
593
|
+
return entry;
|
|
594
|
+
},
|
|
595
|
+
{ concurrency },
|
|
596
|
+
)),
|
|
597
|
+
);
|
|
598
|
+
// Phase 4: relinks. Independent — run in parallel.
|
|
599
|
+
relinked.push(
|
|
600
|
+
...(await concurrentMap(
|
|
601
|
+
plan.relinks,
|
|
602
|
+
(op) => applyRelink(op, provider, slugToIssue),
|
|
603
|
+
{ concurrency },
|
|
604
|
+
)),
|
|
605
|
+
);
|
|
606
|
+
} catch (err) {
|
|
607
|
+
failure = err;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const result = {
|
|
611
|
+
dryRun: false,
|
|
612
|
+
created,
|
|
613
|
+
updated,
|
|
614
|
+
closed,
|
|
615
|
+
relinked,
|
|
616
|
+
slugToIssue: { ...slugToIssue },
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
// State writer integration (Task #1518). When the caller provided a
|
|
620
|
+
// spec, project the resulting state and persist it. On partial failure
|
|
621
|
+
// the state reflects only completed operations — the `slugToIssue` map
|
|
622
|
+
// above already encodes that (failed creates never landed; closed
|
|
623
|
+
// slugs were removed; failed closes leave the slug present).
|
|
624
|
+
if (opts.spec && typeof opts.spec === 'object') {
|
|
625
|
+
const writeStateFn = opts.writeState ?? defaultWriteState;
|
|
626
|
+
const epicId =
|
|
627
|
+
typeof opts.epicId === 'number'
|
|
628
|
+
? opts.epicId
|
|
629
|
+
: typeof opts.spec?.epic?.id === 'number'
|
|
630
|
+
? opts.spec.epic.id
|
|
631
|
+
: undefined;
|
|
632
|
+
const state = projectStateForWrite({
|
|
633
|
+
spec: opts.spec,
|
|
634
|
+
priorState: opts.priorState,
|
|
635
|
+
slugToIssue,
|
|
636
|
+
now: opts.stateNow,
|
|
637
|
+
});
|
|
638
|
+
const writeArgs = [epicId, state];
|
|
639
|
+
if (opts.writeStateOpts) writeArgs.push(opts.writeStateOpts);
|
|
640
|
+
const writePath = writeStateFn(...writeArgs);
|
|
641
|
+
result.state = state;
|
|
642
|
+
if (typeof writePath === 'string') {
|
|
643
|
+
result.statePath = writePath;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (failure) {
|
|
648
|
+
result.failure = failure;
|
|
649
|
+
}
|
|
650
|
+
return result;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Project a state object from `(spec, priorState, slugToIssue)` for the
|
|
655
|
+
* state writer. Layers the post-apply slug → issue map onto the
|
|
656
|
+
* canonical `buildState` output so newly-created issues get their fresh
|
|
657
|
+
* numbers, dropped slugs disappear, and pre-existing observed agent
|
|
658
|
+
* state is preserved for slugs unchanged by this apply.
|
|
659
|
+
*
|
|
660
|
+
* Idempotency contract (AC: "successful apply followed by an immediate
|
|
661
|
+
* second apply is a no-op"). The diff engine's empty plan, the projected
|
|
662
|
+
* mapping, and the byte-identical state writer compose to produce the
|
|
663
|
+
* same on-disk state across re-runs.
|
|
664
|
+
*
|
|
665
|
+
* @param {{spec: object, priorState?: object, slugToIssue: Record<string, number>, now?: string}} input
|
|
666
|
+
* @returns {{epicId: number, lastReconciledAt: string, mapping: object}}
|
|
667
|
+
*/
|
|
668
|
+
function projectStateForWrite({ spec, priorState, slugToIssue, now }) {
|
|
669
|
+
const base = buildState(spec, priorState ?? {}, now ? { now } : {});
|
|
670
|
+
// `buildState` projects feature/story/task slugs — `iterSpecEntries`
|
|
671
|
+
// intentionally walks features down, so the epic slug is not yielded.
|
|
672
|
+
// The reconciler's contract (Tech Spec §"state.json") expects the
|
|
673
|
+
// epic to appear in the mapping too: layer it on explicitly here so
|
|
674
|
+
// a follow-up diff sees the epic mapped and emits no create for it.
|
|
675
|
+
if (spec?.epic && typeof spec.epic.id === 'number' && !base.mapping.epic) {
|
|
676
|
+
const priorEpic = priorState?.mapping?.epic ? priorState.mapping.epic : {};
|
|
677
|
+
base.mapping.epic = {
|
|
678
|
+
issueNumber:
|
|
679
|
+
typeof slugToIssue.epic === 'number'
|
|
680
|
+
? slugToIssue.epic
|
|
681
|
+
: typeof priorEpic.issueNumber === 'number'
|
|
682
|
+
? priorEpic.issueNumber
|
|
683
|
+
: spec.epic.id,
|
|
684
|
+
contentHash:
|
|
685
|
+
typeof priorEpic.contentHash === 'string' ? priorEpic.contentHash : '',
|
|
686
|
+
lastObservedAgentState:
|
|
687
|
+
typeof priorEpic.lastObservedAgentState === 'string'
|
|
688
|
+
? priorEpic.lastObservedAgentState
|
|
689
|
+
: null,
|
|
690
|
+
entity: 'epic',
|
|
691
|
+
parentSlug: null,
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
// Layer structural edge metadata (entity, parentSlug, dependsOn) onto
|
|
695
|
+
// each mapping entry. The diff engine reads these fields to decide
|
|
696
|
+
// whether a Relink op should fire; without them every follow-up diff
|
|
697
|
+
// would re-emit a relink for the parent edge that already exists in
|
|
698
|
+
// GH. The AC's idempotency invariant requires this layering — the
|
|
699
|
+
// pure mapping projection (`spec/state.js`) intentionally does not
|
|
700
|
+
// carry edge data so the hashing path can stay isolated.
|
|
701
|
+
const edgeLookup = collectStructuralEdges(spec);
|
|
702
|
+
for (const slug of Object.keys(base.mapping)) {
|
|
703
|
+
const entry = base.mapping[slug];
|
|
704
|
+
const issueNumber = slugToIssue[slug];
|
|
705
|
+
if (typeof issueNumber === 'number') {
|
|
706
|
+
entry.issueNumber = issueNumber;
|
|
707
|
+
}
|
|
708
|
+
const edges = edgeLookup[slug];
|
|
709
|
+
if (edges) {
|
|
710
|
+
entry.entity = edges.entity;
|
|
711
|
+
entry.parentSlug = edges.parentSlug;
|
|
712
|
+
if (edges.dependsOn) entry.dependsOn = edges.dependsOn;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
// Closed slugs (dropped from spec) are absent from `base.mapping`
|
|
716
|
+
// because `buildState` walks the spec. That matches the AC: closed
|
|
717
|
+
// entries do not appear in state.
|
|
718
|
+
return base;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Walk the spec once and emit `{ slug → { entity, parentSlug, dependsOn? } }`
|
|
723
|
+
* so `projectStateForWrite` can layer the edges back onto the state
|
|
724
|
+
* mapping. Pure / allocation-bounded; runs O(spec size).
|
|
725
|
+
*
|
|
726
|
+
* @param {object} spec
|
|
727
|
+
* @returns {Record<string, {entity: string, parentSlug: string|null, dependsOn?: string[]}>}
|
|
728
|
+
*/
|
|
729
|
+
function collectStructuralEdges(spec) {
|
|
730
|
+
const out = {};
|
|
731
|
+
if (!spec || typeof spec !== 'object') return out;
|
|
732
|
+
const epicSlug = 'epic';
|
|
733
|
+
for (const feature of spec.features ?? []) {
|
|
734
|
+
if (!feature?.slug) continue;
|
|
735
|
+
out[feature.slug] = { entity: 'feature', parentSlug: epicSlug };
|
|
736
|
+
for (const story of feature.stories ?? []) {
|
|
737
|
+
if (!story?.slug) continue;
|
|
738
|
+
out[story.slug] = {
|
|
739
|
+
entity: 'story',
|
|
740
|
+
parentSlug: feature.slug,
|
|
741
|
+
dependsOn: [...(story.dependsOn ?? [])].sort(),
|
|
742
|
+
};
|
|
743
|
+
for (const task of story.tasks ?? []) {
|
|
744
|
+
if (!task?.slug) continue;
|
|
745
|
+
out[task.slug] = { entity: 'task', parentSlug: story.slug };
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return out;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Topologically sort the create ops into dependency batches. Each batch
|
|
754
|
+
* is a list of ops whose parents are already in `slugToIssue` or in an
|
|
755
|
+
* earlier batch. This keeps parent creates ahead of child creates
|
|
756
|
+
* without forcing a global single-file execution.
|
|
757
|
+
*
|
|
758
|
+
* @param {import('./epic-spec-reconciler-ops.js').CreateOp[]} creates
|
|
759
|
+
* @param {Record<string, number>} slugToIssue
|
|
760
|
+
* @returns {import('./epic-spec-reconciler-ops.js').CreateOp[][]}
|
|
761
|
+
*/
|
|
762
|
+
function topoSortCreates(creates, slugToIssue) {
|
|
763
|
+
if (!creates.length) return [];
|
|
764
|
+
const remaining = [...creates];
|
|
765
|
+
const knownSlugs = new Set(Object.keys(slugToIssue));
|
|
766
|
+
// dependsOn slugs may reference siblings that are themselves in the
|
|
767
|
+
// create batch — those become known once their batch lands. Any slug
|
|
768
|
+
// that is neither pre-known nor will be created here is an external
|
|
769
|
+
// reference we can't satisfy via topo order; treat it as "satisfiable
|
|
770
|
+
// outside the batch" so we don't deadlock. The fail-loud renderer
|
|
771
|
+
// catches truly unresolved slugs at apply time.
|
|
772
|
+
const createSlugs = new Set(creates.map((op) => op.slug));
|
|
773
|
+
const batches = [];
|
|
774
|
+
while (remaining.length) {
|
|
775
|
+
const ready = remaining.filter((op) => {
|
|
776
|
+
const parentReady = !op.parentSlug || knownSlugs.has(op.parentSlug);
|
|
777
|
+
const depsReady =
|
|
778
|
+
!Array.isArray(op.dependsOn) ||
|
|
779
|
+
op.dependsOn.every((d) => knownSlugs.has(d) || !createSlugs.has(d));
|
|
780
|
+
return parentReady && depsReady;
|
|
781
|
+
});
|
|
782
|
+
if (ready.length === 0) {
|
|
783
|
+
// Cycle or missing parent — break out by emitting the rest as one
|
|
784
|
+
// batch and letting `resolveParentId` / footer renderer raise the
|
|
785
|
+
// structured error.
|
|
786
|
+
batches.push(remaining.splice(0));
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
batches.push(ready);
|
|
790
|
+
for (const op of ready) knownSlugs.add(op.slug);
|
|
791
|
+
for (const op of ready) {
|
|
792
|
+
const idx = remaining.indexOf(op);
|
|
793
|
+
if (idx >= 0) remaining.splice(idx, 1);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return batches;
|
|
797
|
+
}
|