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,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/spec/loader.js — spec + state file I/O for the epic-spec reconciler.
|
|
3
|
+
*
|
|
4
|
+
* Owns the two files that bracket the structural SSOT migration (Epic
|
|
5
|
+
* #1182 / Tech Spec #1483):
|
|
6
|
+
*
|
|
7
|
+
* - `temp/epic-<epic-id>/<epic-id>.yaml` — declarative spec (regenerated)
|
|
8
|
+
* - `temp/epic-<epic-id>/<epic-id>.state.json` — slug→issue mapping (observed)
|
|
9
|
+
*
|
|
10
|
+
* Both files live under the per-Epic ephemeral tree `temp/epic-<id>/`
|
|
11
|
+
* (already gitignored) so /epic-plan reruns don't churn a tracked path
|
|
12
|
+
* and so concurrent Epics never collide on a single shared directory.
|
|
13
|
+
* Tests inject `opts.epicsDir` to point at a sandbox; the default for
|
|
14
|
+
* production callers is derived from `lib/config/temp-paths.js#epicTempDir`.
|
|
15
|
+
*
|
|
16
|
+
* The module is intentionally a thin, dependency-light I/O layer:
|
|
17
|
+
*
|
|
18
|
+
* • `loadSpec(epicId)` → parses YAML, validates against
|
|
19
|
+
* `.agents/schemas/epic-spec.schema.json` (Ajv2020). Throws a
|
|
20
|
+
* `SpecValidationError` carrying the offending JSON Pointer paths
|
|
21
|
+
* when the spec is structurally invalid. Missing file throws
|
|
22
|
+
* `SpecNotFoundError`.
|
|
23
|
+
* • `loadState(epicId)` → returns `{ epicId, mapping: {} }` (with
|
|
24
|
+
* `lastReconciledAt` omitted) when the state file is missing, so
|
|
25
|
+
* callers can start reconciling against a fresh Epic without a
|
|
26
|
+
* pre-existing state file.
|
|
27
|
+
* • `writeState(epicId, state)` → writes pretty-printed JSON with
|
|
28
|
+
* deterministically sorted keys (recursive). Repeated writes of an
|
|
29
|
+
* equivalent state produce a byte-identical file. Trailing newline
|
|
30
|
+
* included so the file behaves well under git + POSIX `cat`.
|
|
31
|
+
*
|
|
32
|
+
* The loader does **not** make any GitHub calls; it is pure file I/O
|
|
33
|
+
* over the two on-disk artefacts. The reconciler (Wave 1) layers diff
|
|
34
|
+
* + apply on top of this surface.
|
|
35
|
+
*
|
|
36
|
+
* All public functions accept an optional `{ epicsDir, schemaPath, fs }`
|
|
37
|
+
* options bag so tests can point the loader at a sandbox directory
|
|
38
|
+
* without monkey-patching `process.cwd()` or the project schema path.
|
|
39
|
+
*
|
|
40
|
+
* Cross-references:
|
|
41
|
+
* - Schema: `.agents/schemas/epic-spec.schema.json` (Story #1490)
|
|
42
|
+
* - Fixtures: `tests/fixtures/epic-specs/*.json` (Story #1490)
|
|
43
|
+
* - Tech Spec §"`.agents/epics/<epic-id>.yaml` (spec)" + §"state.json"
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import {
|
|
47
|
+
existsSync as defaultExistsSync,
|
|
48
|
+
mkdirSync as defaultMkdirSync,
|
|
49
|
+
readFileSync as defaultReadFileSync,
|
|
50
|
+
writeFileSync as defaultWriteFileSync,
|
|
51
|
+
} from 'node:fs';
|
|
52
|
+
import path from 'node:path';
|
|
53
|
+
import { fileURLToPath } from 'node:url';
|
|
54
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
55
|
+
import addFormats from 'ajv-formats';
|
|
56
|
+
import yaml from 'js-yaml';
|
|
57
|
+
|
|
58
|
+
import { epicTempDir } from '../config/temp-paths.js';
|
|
59
|
+
|
|
60
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
61
|
+
|
|
62
|
+
// scripts/lib/spec/ → scripts/lib/ → scripts/ → .agents/
|
|
63
|
+
const PROJECT_AGENTS_DIR = path.resolve(__dirname, '..', '..', '..');
|
|
64
|
+
const DEFAULT_SCHEMA_PATH = path.join(
|
|
65
|
+
PROJECT_AGENTS_DIR,
|
|
66
|
+
'schemas',
|
|
67
|
+
'epic-spec.schema.json',
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Resolve the default per-Epic spec directory under `temp/epic-<id>/`.
|
|
71
|
+
// Caller-injected `opts.epicsDir` still wins for tests and any external
|
|
72
|
+
// tooling that wants to point at a sandbox. Production callers omit the
|
|
73
|
+
// option and route through this helper.
|
|
74
|
+
function defaultEpicsDir(epicId) {
|
|
75
|
+
return epicTempDir(epicId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const defaultFsAdapter = Object.freeze({
|
|
79
|
+
existsSync: defaultExistsSync,
|
|
80
|
+
mkdirSync: defaultMkdirSync,
|
|
81
|
+
readFileSync: defaultReadFileSync,
|
|
82
|
+
writeFileSync: defaultWriteFileSync,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
let cachedValidator = null;
|
|
86
|
+
let cachedValidatorKey = null;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Compile (and cache) the Ajv2020 validator for the epic-spec schema.
|
|
90
|
+
* Cached by absolute schema path so tests can swap to a sandbox schema.
|
|
91
|
+
*
|
|
92
|
+
* @param {string} schemaPath
|
|
93
|
+
* @param {{ readFileSync: typeof defaultReadFileSync }} fs
|
|
94
|
+
* @returns {(data: unknown) => boolean}
|
|
95
|
+
*/
|
|
96
|
+
function getValidator(schemaPath, fs) {
|
|
97
|
+
if (cachedValidator && cachedValidatorKey === schemaPath) {
|
|
98
|
+
return cachedValidator;
|
|
99
|
+
}
|
|
100
|
+
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
101
|
+
addFormats(ajv);
|
|
102
|
+
const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8'));
|
|
103
|
+
cachedValidator = ajv.compile(schema);
|
|
104
|
+
cachedValidatorKey = schemaPath;
|
|
105
|
+
return cachedValidator;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Test-only hook: drop the cached validator so a subsequent call
|
|
110
|
+
* recompiles. Safe to leave exported — production code never invokes it.
|
|
111
|
+
*/
|
|
112
|
+
export function _resetValidatorCacheForTests() {
|
|
113
|
+
cachedValidator = null;
|
|
114
|
+
cachedValidatorKey = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Structured error raised by `loadSpec` when the YAML parses but fails
|
|
119
|
+
* schema validation. The Ajv error list is normalised to an array of
|
|
120
|
+
* `{ path, message }` so callers (reconciler CLI, tests) can render the
|
|
121
|
+
* offending JSON Pointer without re-parsing the Ajv envelope.
|
|
122
|
+
*/
|
|
123
|
+
export class SpecValidationError extends Error {
|
|
124
|
+
/**
|
|
125
|
+
* @param {string} epicId
|
|
126
|
+
* @param {Array<{path: string, message: string, params?: object}>} issues
|
|
127
|
+
*/
|
|
128
|
+
constructor(epicId, issues) {
|
|
129
|
+
const head = issues[0] ?? { path: '/', message: 'unknown' };
|
|
130
|
+
super(
|
|
131
|
+
`Spec for epic ${epicId} failed schema validation at ${head.path}: ${head.message}`,
|
|
132
|
+
);
|
|
133
|
+
this.name = 'SpecValidationError';
|
|
134
|
+
this.epicId = epicId;
|
|
135
|
+
this.issues = issues;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Raised by `loadSpec` when the on-disk YAML file does not exist.
|
|
141
|
+
*/
|
|
142
|
+
export class SpecNotFoundError extends Error {
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} epicId
|
|
145
|
+
* @param {string} filePath
|
|
146
|
+
*/
|
|
147
|
+
constructor(epicId, filePath) {
|
|
148
|
+
super(`Spec file missing for epic ${epicId}: ${filePath}`);
|
|
149
|
+
this.name = 'SpecNotFoundError';
|
|
150
|
+
this.epicId = epicId;
|
|
151
|
+
this.filePath = filePath;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Raised by `loadSpec` when the file exists but is not parseable YAML.
|
|
157
|
+
*/
|
|
158
|
+
export class SpecParseError extends Error {
|
|
159
|
+
/**
|
|
160
|
+
* @param {string} epicId
|
|
161
|
+
* @param {string} filePath
|
|
162
|
+
* @param {Error} cause
|
|
163
|
+
*/
|
|
164
|
+
constructor(epicId, filePath, cause) {
|
|
165
|
+
super(
|
|
166
|
+
`Spec file for epic ${epicId} is not valid YAML (${filePath}): ${cause.message}`,
|
|
167
|
+
);
|
|
168
|
+
this.name = 'SpecParseError';
|
|
169
|
+
this.epicId = epicId;
|
|
170
|
+
this.filePath = filePath;
|
|
171
|
+
this.cause = cause;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function resolveOpts(epicId, opts = {}) {
|
|
176
|
+
return {
|
|
177
|
+
epicsDir: opts.epicsDir ?? defaultEpicsDir(epicId),
|
|
178
|
+
schemaPath: opts.schemaPath ?? DEFAULT_SCHEMA_PATH,
|
|
179
|
+
fs: opts.fs ?? defaultFsAdapter,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Resolve the on-disk spec path for `epicId` under the configured
|
|
185
|
+
* epics dir. Exported for tests and for the reconciler CLI's error
|
|
186
|
+
* messages.
|
|
187
|
+
*
|
|
188
|
+
* @param {number|string} epicId
|
|
189
|
+
* @param {{epicsDir?: string}} [opts]
|
|
190
|
+
* @returns {string}
|
|
191
|
+
*/
|
|
192
|
+
export function specPath(epicId, opts = {}) {
|
|
193
|
+
const { epicsDir } = resolveOpts(epicId, opts);
|
|
194
|
+
return path.join(epicsDir, `${String(epicId)}.yaml`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Resolve the on-disk state path for `epicId` under the configured
|
|
199
|
+
* epics dir.
|
|
200
|
+
*
|
|
201
|
+
* @param {number|string} epicId
|
|
202
|
+
* @param {{epicsDir?: string}} [opts]
|
|
203
|
+
* @returns {string}
|
|
204
|
+
*/
|
|
205
|
+
export function statePath(epicId, opts = {}) {
|
|
206
|
+
const { epicsDir } = resolveOpts(epicId, opts);
|
|
207
|
+
return path.join(epicsDir, `${String(epicId)}.state.json`);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Convert Ajv's error array into the loader's `{ path, message }`
|
|
212
|
+
* shape. Ajv2020 uses `instancePath` for the JSON Pointer into the
|
|
213
|
+
* data; for `required` errors it leaves the missing property in
|
|
214
|
+
* `params.missingProperty` rather than the path, so we append it so
|
|
215
|
+
* the caller sees `/epic` instead of `` (root) for the canonical
|
|
216
|
+
* `epic required` failure.
|
|
217
|
+
*
|
|
218
|
+
* @param {Array<{instancePath:string,message:string,keyword:string,params?:Record<string,unknown>}>} ajvErrors
|
|
219
|
+
* @returns {Array<{path:string,message:string,params?:object}>}
|
|
220
|
+
*/
|
|
221
|
+
function normaliseAjvErrors(ajvErrors) {
|
|
222
|
+
return ajvErrors.map((err) => {
|
|
223
|
+
let p = err.instancePath || '/';
|
|
224
|
+
if (
|
|
225
|
+
err.keyword === 'required' &&
|
|
226
|
+
typeof err.params?.missingProperty === 'string'
|
|
227
|
+
) {
|
|
228
|
+
const sep = p === '/' ? '' : '/';
|
|
229
|
+
p = `${p}${sep}${err.params.missingProperty}`;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
path: p,
|
|
233
|
+
message: err.message ?? 'validation failed',
|
|
234
|
+
params: err.params,
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Load and validate the spec YAML for `epicId`. Returns the parsed
|
|
241
|
+
* JavaScript object on success. Throws `SpecNotFoundError`,
|
|
242
|
+
* `SpecParseError`, or `SpecValidationError` otherwise.
|
|
243
|
+
*
|
|
244
|
+
* @param {number|string} epicId
|
|
245
|
+
* @param {{epicsDir?: string, schemaPath?: string, fs?: typeof defaultFsAdapter}} [opts]
|
|
246
|
+
* @returns {object}
|
|
247
|
+
*/
|
|
248
|
+
export function loadSpec(epicId, opts = {}) {
|
|
249
|
+
const { schemaPath, fs } = resolveOpts(epicId, opts);
|
|
250
|
+
const filePath = specPath(epicId, opts);
|
|
251
|
+
|
|
252
|
+
if (!fs.existsSync(filePath)) {
|
|
253
|
+
throw new SpecNotFoundError(String(epicId), filePath);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
257
|
+
let parsed;
|
|
258
|
+
try {
|
|
259
|
+
parsed = yaml.load(raw, { filename: filePath });
|
|
260
|
+
} catch (err) {
|
|
261
|
+
throw new SpecParseError(String(epicId), filePath, err);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (parsed == null || typeof parsed !== 'object') {
|
|
265
|
+
throw new SpecValidationError(String(epicId), [
|
|
266
|
+
{
|
|
267
|
+
path: '/',
|
|
268
|
+
message: 'spec root must be an object',
|
|
269
|
+
},
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const validate = getValidator(schemaPath, fs);
|
|
274
|
+
const ok = validate(parsed);
|
|
275
|
+
if (!ok) {
|
|
276
|
+
throw new SpecValidationError(
|
|
277
|
+
String(epicId),
|
|
278
|
+
normaliseAjvErrors(validate.errors ?? []),
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return parsed;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Empty-state default. `loadState` returns this shape when the state
|
|
287
|
+
* file does not exist; callers can rely on `mapping` being a plain
|
|
288
|
+
* object (never undefined).
|
|
289
|
+
*
|
|
290
|
+
* @param {number|string} epicId
|
|
291
|
+
* @returns {{epicId: number, mapping: Record<string, never>}}
|
|
292
|
+
*/
|
|
293
|
+
function emptyState(epicId) {
|
|
294
|
+
return { epicId: Number(epicId), mapping: {} };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Load the state file for `epicId`. Returns an empty mapping when the
|
|
299
|
+
* file is missing (the canonical "fresh Epic" case the reconciler
|
|
300
|
+
* faces on first apply). Throws if the file exists but is not valid
|
|
301
|
+
* JSON.
|
|
302
|
+
*
|
|
303
|
+
* @param {number|string} epicId
|
|
304
|
+
* @param {{epicsDir?: string, fs?: typeof defaultFsAdapter}} [opts]
|
|
305
|
+
* @returns {{epicId: number, mapping: object, lastReconciledAt?: string}}
|
|
306
|
+
*/
|
|
307
|
+
export function loadState(epicId, opts = {}) {
|
|
308
|
+
const { fs } = resolveOpts(epicId, opts);
|
|
309
|
+
const filePath = statePath(epicId, opts);
|
|
310
|
+
|
|
311
|
+
if (!fs.existsSync(filePath)) {
|
|
312
|
+
return emptyState(epicId);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
316
|
+
return JSON.parse(raw);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Recursively sort object keys (arrays preserve order). Returns a new
|
|
321
|
+
* value with the same shape — leaves are returned unchanged.
|
|
322
|
+
*
|
|
323
|
+
* Exported for `state-writer.js` so the hashing path can share the
|
|
324
|
+
* exact same canonicalisation as the file writer.
|
|
325
|
+
*
|
|
326
|
+
* @param {unknown} value
|
|
327
|
+
* @returns {unknown}
|
|
328
|
+
*/
|
|
329
|
+
export function sortKeysDeep(value) {
|
|
330
|
+
if (Array.isArray(value)) {
|
|
331
|
+
return value.map(sortKeysDeep);
|
|
332
|
+
}
|
|
333
|
+
if (value && typeof value === 'object') {
|
|
334
|
+
const out = {};
|
|
335
|
+
for (const key of Object.keys(value).sort()) {
|
|
336
|
+
out[key] = sortKeysDeep(value[key]);
|
|
337
|
+
}
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
return value;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Render `state` to deterministic JSON. Public so the test suite can
|
|
345
|
+
* assert the byte-identical-roundtrip property without re-implementing
|
|
346
|
+
* the formatter.
|
|
347
|
+
*
|
|
348
|
+
* @param {object} state
|
|
349
|
+
* @returns {string} pretty-printed JSON, terminated by a single newline.
|
|
350
|
+
*/
|
|
351
|
+
export function renderStateJson(state) {
|
|
352
|
+
return `${JSON.stringify(sortKeysDeep(state), null, 2)}\n`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Write the state file for `epicId`. Creates the parent directory
|
|
357
|
+
* lazily. Object keys are recursively sorted so re-writing the same
|
|
358
|
+
* logical state produces a byte-identical file (AC: "diffs stay
|
|
359
|
+
* stable", "byte-identical when written twice").
|
|
360
|
+
*
|
|
361
|
+
* Returns the absolute path written so callers can log it.
|
|
362
|
+
*
|
|
363
|
+
* @param {number|string} epicId
|
|
364
|
+
* @param {object} state
|
|
365
|
+
* @param {{epicsDir?: string, fs?: typeof defaultFsAdapter}} [opts]
|
|
366
|
+
* @returns {string}
|
|
367
|
+
*/
|
|
368
|
+
export function writeState(epicId, state, opts = {}) {
|
|
369
|
+
const { epicsDir, fs } = resolveOpts(epicId, opts);
|
|
370
|
+
if (!fs.existsSync(epicsDir)) {
|
|
371
|
+
fs.mkdirSync(epicsDir, { recursive: true });
|
|
372
|
+
}
|
|
373
|
+
const filePath = statePath(epicId, opts);
|
|
374
|
+
fs.writeFileSync(filePath, renderStateJson(state), 'utf8');
|
|
375
|
+
return filePath;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Write the spec YAML file for `epicId`. Creates the parent directory
|
|
380
|
+
* lazily and emits a top-level `$schema` reference so editors with
|
|
381
|
+
* YAML-schema autocomplete (e.g. the Red Hat YAML extension) resolve
|
|
382
|
+
* the schema from the file itself.
|
|
383
|
+
*
|
|
384
|
+
* Story #1498 / Task #1525 introduced this writer so the rewritten
|
|
385
|
+
* `/epic-plan` halves can persist the spec from the decomposer's
|
|
386
|
+
* ticket-array projection (`renderSpec`) without reaching into raw
|
|
387
|
+
* `js-yaml` calls scattered across the planning scripts.
|
|
388
|
+
*
|
|
389
|
+
* The function validates the spec via the same Ajv2020 compiler the
|
|
390
|
+
* loader caches — a malformed spec is rejected synchronously instead of
|
|
391
|
+
* being persisted and tripping `loadSpec` on the next reconciler run.
|
|
392
|
+
*
|
|
393
|
+
* @param {number|string} epicId
|
|
394
|
+
* @param {object} spec spec object matching `epic-spec.schema.json`.
|
|
395
|
+
* @param {{epicsDir?: string, schemaPath?: string, fs?: typeof defaultFsAdapter}} [opts]
|
|
396
|
+
* @returns {string} the absolute path written.
|
|
397
|
+
*/
|
|
398
|
+
export function writeSpec(epicId, spec, opts = {}) {
|
|
399
|
+
const { epicsDir, schemaPath, fs } = resolveOpts(epicId, opts);
|
|
400
|
+
if (!spec || typeof spec !== 'object') {
|
|
401
|
+
throw new TypeError('[writeSpec] spec must be an object');
|
|
402
|
+
}
|
|
403
|
+
const validate = getValidator(schemaPath, fs);
|
|
404
|
+
const ok = validate(spec);
|
|
405
|
+
if (!ok) {
|
|
406
|
+
throw new SpecValidationError(
|
|
407
|
+
String(epicId),
|
|
408
|
+
normaliseAjvErrors(validate.errors ?? []),
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
if (!fs.existsSync(epicsDir)) {
|
|
412
|
+
fs.mkdirSync(epicsDir, { recursive: true });
|
|
413
|
+
}
|
|
414
|
+
const filePath = specPath(epicId, opts);
|
|
415
|
+
// Lazy require: `js-yaml` is already a runtime dep of the loader, but
|
|
416
|
+
// keeping the import top-level would force every consumer of `loader.js`
|
|
417
|
+
// to pay the parse cost even when they only need state helpers.
|
|
418
|
+
const yamlDump = yaml.dump(spec, {
|
|
419
|
+
noRefs: true,
|
|
420
|
+
sortKeys: false,
|
|
421
|
+
lineWidth: 120,
|
|
422
|
+
});
|
|
423
|
+
fs.writeFileSync(filePath, yamlDump, 'utf8');
|
|
424
|
+
return filePath;
|
|
425
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/spec/state.js — state-file shape helpers.
|
|
3
|
+
*
|
|
4
|
+
* Owns the canonical content-hashing and the
|
|
5
|
+
* `<epic-id>.state.json` mapping projection used by the reconciler
|
|
6
|
+
* (Wave 1) to decide what changed between two reconciliations.
|
|
7
|
+
*
|
|
8
|
+
* Tech Spec #1483 §"`.agents/epics/<epic-id>.state.json`" pins the
|
|
9
|
+
* file shape:
|
|
10
|
+
*
|
|
11
|
+
* ```json
|
|
12
|
+
* {
|
|
13
|
+
* "epicId": 1182,
|
|
14
|
+
* "lastReconciledAt": "2026-05-12T12:34:56Z",
|
|
15
|
+
* "mapping": {
|
|
16
|
+
* "<slug>": {
|
|
17
|
+
* "issueNumber": 1190,
|
|
18
|
+
* "contentHash": "sha256:...",
|
|
19
|
+
* "lastObservedAgentState": "agent::ready"
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The hashing contract:
|
|
26
|
+
*
|
|
27
|
+
* • `canonicalStringify(value)` produces a deterministic string for
|
|
28
|
+
* `value` by recursively sorting object keys. This guarantees that
|
|
29
|
+
* two objects with the same logical content but different in-memory
|
|
30
|
+
* key order hash to the same digest, which is the foundation of the
|
|
31
|
+
* reconciler's "did this entry change?" check.
|
|
32
|
+
* • `hashSpecEntry(entry)` returns `sha256:<hex>` over the
|
|
33
|
+
* canonical-stringified entry. The `sha256:` prefix makes the hash
|
|
34
|
+
* algorithm self-describing in the on-disk state file (so future
|
|
35
|
+
* migrations can multiplex algorithms without a schema bump).
|
|
36
|
+
*
|
|
37
|
+
* The mapping-projection contract (`projectMapping`):
|
|
38
|
+
*
|
|
39
|
+
* • Given a `spec` and a `prior` state, project a fresh `mapping`
|
|
40
|
+
* entry per slug found in the spec, preserving the prior
|
|
41
|
+
* `issueNumber` + `lastObservedAgentState` where present and
|
|
42
|
+
* re-hashing the entry's structural content. Slugs absent from the
|
|
43
|
+
* spec are dropped (a spec→state projection — execution-drift
|
|
44
|
+
* handling lives in the reconciler, not here).
|
|
45
|
+
*
|
|
46
|
+
* • The projection is pure: it does not read or write disk, and it
|
|
47
|
+
* does not call `Date.now()`. Callers compose it with
|
|
48
|
+
* `writeState(epicId, { ...projected, lastReconciledAt: now() })`.
|
|
49
|
+
*
|
|
50
|
+
* The whole module is import-light and side-effect-free so the
|
|
51
|
+
* reconciler diff path can unit-test it in isolation.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
import { createHash } from 'node:crypto';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Recursively sort object keys so two equivalent objects produce the
|
|
58
|
+
* same canonical serialisation. Arrays preserve their order (array
|
|
59
|
+
* order is semantically meaningful in the spec — feature order, task
|
|
60
|
+
* order, dependsOn order).
|
|
61
|
+
*
|
|
62
|
+
* Exported because the loader's `sortKeysDeep` lives in `loader.js` and
|
|
63
|
+
* we want a single canonicalisation entry point for the hash path. Both
|
|
64
|
+
* implementations agree on object-key sort; only this one is the
|
|
65
|
+
* documented hashing-input contract.
|
|
66
|
+
*
|
|
67
|
+
* @param {unknown} value
|
|
68
|
+
* @returns {unknown}
|
|
69
|
+
*/
|
|
70
|
+
export function canonicalise(value) {
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
return value.map(canonicalise);
|
|
73
|
+
}
|
|
74
|
+
if (value && typeof value === 'object') {
|
|
75
|
+
const out = {};
|
|
76
|
+
for (const key of Object.keys(value).sort()) {
|
|
77
|
+
out[key] = canonicalise(value[key]);
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Stringify `value` deterministically. Two objects with the same
|
|
86
|
+
* logical content always produce the same string regardless of how
|
|
87
|
+
* their keys are inserted in memory.
|
|
88
|
+
*
|
|
89
|
+
* Used as the hashing input for `hashSpecEntry`; also exported so the
|
|
90
|
+
* reconciler can log diffs in canonical form.
|
|
91
|
+
*
|
|
92
|
+
* @param {unknown} value
|
|
93
|
+
* @returns {string}
|
|
94
|
+
*/
|
|
95
|
+
export function canonicalStringify(value) {
|
|
96
|
+
return JSON.stringify(canonicalise(value));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* SHA-256 over `input`, hex-encoded, prefixed with `sha256:` so the
|
|
101
|
+
* algorithm is self-describing in the state file.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} input
|
|
104
|
+
* @returns {string}
|
|
105
|
+
*/
|
|
106
|
+
export function sha256Hex(input) {
|
|
107
|
+
return `sha256:${createHash('sha256').update(input).digest('hex')}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Hash a spec entry (a Feature, Story, or Task object) deterministically.
|
|
112
|
+
* The entry is canonicalised (recursive key-sort), serialised, and
|
|
113
|
+
* sha256'd. Equivalent entries (any key order, equivalent nested order
|
|
114
|
+
* for the object-valued fields) hash to the same digest.
|
|
115
|
+
*
|
|
116
|
+
* The reconciler stores the resulting hash in `mapping[slug].contentHash`
|
|
117
|
+
* so the next reconciliation can decide whether a `Update` operation is
|
|
118
|
+
* needed without comparing the entries property-by-property.
|
|
119
|
+
*
|
|
120
|
+
* @param {object} entry
|
|
121
|
+
* @returns {string} `sha256:<hex>`
|
|
122
|
+
*/
|
|
123
|
+
export function hashSpecEntry(entry) {
|
|
124
|
+
return sha256Hex(canonicalStringify(entry));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Iterate every slug-bearing entity in the spec. Yields tuples of
|
|
129
|
+
* `[slug, entry]` where `entry` is the raw object as authored in the
|
|
130
|
+
* spec (feature/story/task). Order is feature-major, story-minor,
|
|
131
|
+
* task-tertiary — the natural read order, useful for deterministic
|
|
132
|
+
* mapping iteration.
|
|
133
|
+
*
|
|
134
|
+
* Exported for tests; the reconciler diff path uses `projectMapping`
|
|
135
|
+
* (below) rather than this generator directly.
|
|
136
|
+
*
|
|
137
|
+
* @param {object} spec
|
|
138
|
+
* @returns {Generator<[string, object]>}
|
|
139
|
+
*/
|
|
140
|
+
export function* iterSpecEntries(spec) {
|
|
141
|
+
if (!spec || !Array.isArray(spec.features)) return;
|
|
142
|
+
for (const feature of spec.features) {
|
|
143
|
+
if (feature?.slug) yield [feature.slug, feature];
|
|
144
|
+
if (!Array.isArray(feature?.stories)) continue;
|
|
145
|
+
for (const story of feature.stories) {
|
|
146
|
+
if (story?.slug) yield [story.slug, story];
|
|
147
|
+
if (!Array.isArray(story?.tasks)) continue;
|
|
148
|
+
for (const task of story.tasks) {
|
|
149
|
+
if (task?.slug) yield [task.slug, task];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Project a fresh `mapping` over `spec`, carrying forward whatever the
|
|
157
|
+
* `prior` state already knows for each slug (`issueNumber` and
|
|
158
|
+
* `lastObservedAgentState`) and re-hashing the entry's structural
|
|
159
|
+
* content via `hashSpecEntry`.
|
|
160
|
+
*
|
|
161
|
+
* Pure function — does not read or write disk, does not touch
|
|
162
|
+
* `Date.now()`. Callers fold the result into `writeState` along with a
|
|
163
|
+
* caller-supplied `lastReconciledAt`.
|
|
164
|
+
*
|
|
165
|
+
* Entries newly added in the spec start with `issueNumber: null` and
|
|
166
|
+
* `lastObservedAgentState: null`. Entries dropped from the spec are
|
|
167
|
+
* absent from the returned mapping (the reconciler decides separately
|
|
168
|
+
* whether to retain a tombstone — that lives in Wave 1's diff layer).
|
|
169
|
+
*
|
|
170
|
+
* @param {object} spec
|
|
171
|
+
* @param {{mapping?: Record<string,object>}} [prior]
|
|
172
|
+
* @returns {Record<string,{issueNumber:number|null,contentHash:string,lastObservedAgentState:string|null}>}
|
|
173
|
+
*/
|
|
174
|
+
export function projectMapping(spec, prior = {}) {
|
|
175
|
+
const priorMapping =
|
|
176
|
+
prior && typeof prior.mapping === 'object' && prior.mapping !== null
|
|
177
|
+
? prior.mapping
|
|
178
|
+
: {};
|
|
179
|
+
const next = {};
|
|
180
|
+
for (const [slug, entry] of iterSpecEntries(spec)) {
|
|
181
|
+
const previous = priorMapping[slug] ?? {};
|
|
182
|
+
next[slug] = {
|
|
183
|
+
issueNumber:
|
|
184
|
+
typeof previous.issueNumber === 'number' ? previous.issueNumber : null,
|
|
185
|
+
contentHash: hashSpecEntry(entry),
|
|
186
|
+
lastObservedAgentState:
|
|
187
|
+
typeof previous.lastObservedAgentState === 'string'
|
|
188
|
+
? previous.lastObservedAgentState
|
|
189
|
+
: null,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return next;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Build a complete state object from a spec, a prior state, and an
|
|
197
|
+
* optional `now` timestamp (defaults to the current UTC ISO string).
|
|
198
|
+
*
|
|
199
|
+
* This is the canonical convenience wrapper the reconciler calls right
|
|
200
|
+
* before `writeState`. Tests can pass `now: '2026-05-12T00:00:00Z'` to
|
|
201
|
+
* make the resulting state byte-stable.
|
|
202
|
+
*
|
|
203
|
+
* @param {object} spec
|
|
204
|
+
* @param {{mapping?: object}} [prior]
|
|
205
|
+
* @param {{now?: string}} [opts]
|
|
206
|
+
* @returns {{epicId: number, lastReconciledAt: string, mapping: object}}
|
|
207
|
+
*/
|
|
208
|
+
export function buildState(spec, prior = {}, opts = {}) {
|
|
209
|
+
const epicId =
|
|
210
|
+
typeof spec?.epic?.id === 'number' ? spec.epic.id : Number(prior?.epicId);
|
|
211
|
+
const lastReconciledAt = opts.now ?? new Date().toISOString();
|
|
212
|
+
return {
|
|
213
|
+
epicId,
|
|
214
|
+
lastReconciledAt,
|
|
215
|
+
mapping: projectMapping(spec, prior),
|
|
216
|
+
};
|
|
217
|
+
}
|