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,897 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* close-validation.js — Shift-left validation gates for story-close.
|
|
3
|
+
*
|
|
4
|
+
* Runs typecheck, lint, test, format check, and maintainability/coverage/
|
|
5
|
+
* CRAP regression checks before the story merge so drift is caught in the
|
|
6
|
+
* worktree rather than at pre-push time on the Epic branch. Format command
|
|
7
|
+
* is configurable via `project.commands.formatCheck`; default is
|
|
8
|
+
* `npx biome format .`. All gates inherit stdio so the operator sees the
|
|
9
|
+
* raw output; the returned summary surfaces actionable hints on failure.
|
|
10
|
+
*
|
|
11
|
+
* Pre-merge MI projection (Story #781) is re-exported from
|
|
12
|
+
* `close-validation/projections/maintainability.js` — the engine that
|
|
13
|
+
* surfaces, by name, the files that would breach their per-file MI
|
|
14
|
+
* baseline post-merge so the operator can ship a `baseline-refresh:`
|
|
15
|
+
* commit atomically with the Story PR.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
19
|
+
import { writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
20
|
+
import { diffNameOnly } from './changed-files.js';
|
|
21
|
+
import { defaultGetHeadSha } from './close-validation/projections/head-sha.js';
|
|
22
|
+
import { getCommands } from './config/commands.js';
|
|
23
|
+
import { storyArtifactPath } from './config/temp-paths.js';
|
|
24
|
+
import { getSpawnCount as defaultGetSpawnCount } from './gh-exec.js';
|
|
25
|
+
import {
|
|
26
|
+
recordPass as defaultRecordPass,
|
|
27
|
+
shouldSkip as defaultShouldSkip,
|
|
28
|
+
hashCommandConfig,
|
|
29
|
+
} from './validation-evidence.js';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {Object} Gate
|
|
33
|
+
* @property {string} name - Short label used in progress logs.
|
|
34
|
+
* @property {string} cmd - Executable to run.
|
|
35
|
+
* @property {string[]} args - Arguments passed to `cmd`.
|
|
36
|
+
* @property {string} [hint] - Remediation hint shown on failure.
|
|
37
|
+
* @property {{ baseRef: string }} [changedFileScope] - Optional Story-diff scope.
|
|
38
|
+
* @property {Record<string, string>} [env] - Optional per-gate environment
|
|
39
|
+
* overlay. Merged over `process.env` for this gate's spawned child only.
|
|
40
|
+
* Used to thread the epic baseRef into the `check-baselines` gate via
|
|
41
|
+
* `BASELINE_REF` (Story #3890) so baseline regressions compare against the
|
|
42
|
+
* epic integration branch rather than `origin/main`.
|
|
43
|
+
* @property {(cmd: string, args: string[], opts: { cwd: string, gateName?: string, log?: (m: string) => void, signal?: AbortSignal, env?: Record<string, string> }) => Promise<{ status: number }> | { status: number }} [run]
|
|
44
|
+
* - Optional in-process runner. Story #1973: when present, the gate
|
|
45
|
+
* executes via this callable instead of spawning `cmd`/`args` through
|
|
46
|
+
* the default runner — used for per-kind baseline gates that import
|
|
47
|
+
* `compare(head, base)` directly.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Fallback typecheck command — the gate is mandatory by design (Epic-branch
|
|
52
|
+
* type regressions surface in the next Story's pre-push otherwise).
|
|
53
|
+
*/
|
|
54
|
+
const TYPECHECK_FALLBACK = 'npm run typecheck';
|
|
55
|
+
|
|
56
|
+
const TYPECHECK_HINT =
|
|
57
|
+
'TypeScript regression — fix type errors on the Story branch before retrying close. If the failure is a stale generated type (e.g. wrangler types), regenerate locally and commit before the close.';
|
|
58
|
+
|
|
59
|
+
/** Default formatter command when `project.commands.formatCheck` is unset. */
|
|
60
|
+
const FORMAT_CHECK_FALLBACK = 'npx biome format .';
|
|
61
|
+
|
|
62
|
+
/** Default formatter command in write mode. */
|
|
63
|
+
const FORMAT_WRITE_FALLBACK = 'npx biome format --write .';
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Build the format-gate hint dynamically from the resolved write command so
|
|
67
|
+
* a Prettier-only repo gets `prettier --write` in its hint, not biome.
|
|
68
|
+
*/
|
|
69
|
+
function buildFormatHint(writeCmd) {
|
|
70
|
+
const cmd =
|
|
71
|
+
writeCmd && writeCmd.trim().length > 0 ? writeCmd : FORMAT_WRITE_FALLBACK;
|
|
72
|
+
return `Run \`${cmd}\` to auto-fix formatting drift.`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Resolve a string `project.commands.<key>` with a fallback when the
|
|
77
|
+
* value is missing, empty, or the resolver throws on malformed config.
|
|
78
|
+
* Shared engine behind the three resolveX command helpers.
|
|
79
|
+
*
|
|
80
|
+
* @param {{ project?: { commands?: object } } | null | undefined} config
|
|
81
|
+
* Canonical resolved config (or a bare `{ project: { commands } }` bag).
|
|
82
|
+
* @param {string} key
|
|
83
|
+
* @param {string} fallback
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
function resolveCommandWithFallback(config, key, fallback) {
|
|
87
|
+
try {
|
|
88
|
+
// `getCommands` reads `config.project.commands` from the canonical
|
|
89
|
+
// resolved config.
|
|
90
|
+
const cmds = getCommands(config);
|
|
91
|
+
const value = cmds[key];
|
|
92
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
93
|
+
return value.trim();
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// Malformed config — fall through to the framework default.
|
|
97
|
+
}
|
|
98
|
+
return fallback;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Resolve the typecheck command. Reads `project.commands.typecheck`;
|
|
103
|
+
* falls back to `npm run typecheck`. The framework-wide
|
|
104
|
+
* `COMMANDS_DEFAULTS.typecheck` is `null` but this gate is mandatory, so
|
|
105
|
+
* we apply the fallback here. Exported for testing.
|
|
106
|
+
*
|
|
107
|
+
* @param {{ project?: { commands?: object } } | null | undefined} config
|
|
108
|
+
* @returns {string}
|
|
109
|
+
*/
|
|
110
|
+
export function resolveTypecheckCommand(config) {
|
|
111
|
+
return resolveCommandWithFallback(config, 'typecheck', TYPECHECK_FALLBACK);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolve the format-check command. Reads `project.commands.formatCheck`;
|
|
116
|
+
* falls back to `npx biome format .` so existing repos keep working byte-
|
|
117
|
+
* for-byte. Exported for testing.
|
|
118
|
+
*
|
|
119
|
+
* @param {{ project?: { commands?: object } } | null | undefined} config
|
|
120
|
+
* @returns {string}
|
|
121
|
+
*/
|
|
122
|
+
export function resolveFormatCheckCommand(config) {
|
|
123
|
+
return resolveCommandWithFallback(
|
|
124
|
+
config,
|
|
125
|
+
'formatCheck',
|
|
126
|
+
FORMAT_CHECK_FALLBACK,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Resolve the format-write command used by story-close format-autofix (and
|
|
132
|
+
* surfaced in the format-gate hint). Reads `project.commands.formatWrite`;
|
|
133
|
+
* falls back to `npx biome format --write .`. Exported for testing.
|
|
134
|
+
*
|
|
135
|
+
* @param {{ project?: { commands?: object } } | null | undefined} config
|
|
136
|
+
* @returns {string}
|
|
137
|
+
*/
|
|
138
|
+
export function resolveFormatWriteCommand(config) {
|
|
139
|
+
return resolveCommandWithFallback(
|
|
140
|
+
config,
|
|
141
|
+
'formatWrite',
|
|
142
|
+
FORMAT_WRITE_FALLBACK,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Compute the Story-diff file scope for formatter gates. The default Biome
|
|
148
|
+
* formatter used to run against `.` from inside `.worktrees/story-*`, which
|
|
149
|
+
* lets consumer ignore globs that exclude `.worktrees` self-exclude the whole
|
|
150
|
+
* run. Scoping to changed paths keeps verification real without depending on
|
|
151
|
+
* how consumers spell root ignore patterns.
|
|
152
|
+
*
|
|
153
|
+
* @param {{ cwd: string, baseRef: string }} opts
|
|
154
|
+
* @returns {string[]}
|
|
155
|
+
*/
|
|
156
|
+
export function listChangedFilesForFormatGate({ cwd, baseRef }) {
|
|
157
|
+
if (!cwd) throw new Error('listChangedFilesForFormatGate: cwd is required');
|
|
158
|
+
if (!baseRef)
|
|
159
|
+
throw new Error('listChangedFilesForFormatGate: baseRef is required');
|
|
160
|
+
// Bridge execFileSync into the gitSpawn(cwd, ...args) contract so
|
|
161
|
+
// diffNameOnly owns the stdout → path-list conversion.
|
|
162
|
+
const gitSpawn = (_cwd, ...args) => {
|
|
163
|
+
try {
|
|
164
|
+
const stdout = execFileSync('git', args, {
|
|
165
|
+
cwd: _cwd,
|
|
166
|
+
encoding: 'utf8',
|
|
167
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
168
|
+
});
|
|
169
|
+
return { status: 0, stdout, stderr: '' };
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return {
|
|
172
|
+
status: err.status ?? 1,
|
|
173
|
+
stdout: err.stdout ?? '',
|
|
174
|
+
stderr: err.stderr ?? err.message,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
return diffNameOnly({ baseRef, cwd, gitSpawn });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function buildChangedFileScope(baseRef) {
|
|
182
|
+
if (!baseRef) return null;
|
|
183
|
+
return { baseRef };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Derive the per-gate `env` overlay that pins the `check-baselines`
|
|
188
|
+
* regression-compare base to the close run's integration branch
|
|
189
|
+
* (Story #3890).
|
|
190
|
+
*
|
|
191
|
+
* The baselines gate resolves its compare ref through `resolveScope`,
|
|
192
|
+
* whose environment layer reads `BASELINE_REF`. Threading
|
|
193
|
+
* `origin/<epicBranch>` here makes the gate diff head against the epic
|
|
194
|
+
* integration branch instead of the framework-default `origin/main`, so
|
|
195
|
+
* drift that already landed on `main` but is outside the Story's own diff
|
|
196
|
+
* does not surface as a phantom regression. The same convention
|
|
197
|
+
* (`origin/<epicBranch>`) is used by the baseline-attribution and
|
|
198
|
+
* auto-refresh paths, keeping read/compare bases aligned.
|
|
199
|
+
*
|
|
200
|
+
* Returns `null` when no integration branch is supplied (the gate then
|
|
201
|
+
* keeps its existing default-ref / consumer-config behaviour untouched).
|
|
202
|
+
*
|
|
203
|
+
* @param {string|undefined|null} epicBranch
|
|
204
|
+
* @returns {{ BASELINE_REF: string } | null}
|
|
205
|
+
*/
|
|
206
|
+
function buildBaselinesGateEnv(epicBranch) {
|
|
207
|
+
if (typeof epicBranch !== 'string' || epicBranch.length === 0) return null;
|
|
208
|
+
return { BASELINE_REF: `origin/${epicBranch}` };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* File extensions Biome's formatter can process. Used to filter the
|
|
213
|
+
* changed-file scope down to the formatter-eligible subset (Story #3410):
|
|
214
|
+
* passing only ineligible paths (e.g. a docs-only Story whose diff is all
|
|
215
|
+
* markdown) makes `biome format <files>` report "No files were processed"
|
|
216
|
+
* and exit 1, failing the gate for a Story that has nothing to format.
|
|
217
|
+
*
|
|
218
|
+
* The set mirrors Biome's handled languages (JS/TS family + JSON + CSS).
|
|
219
|
+
* Markdown, YAML, and other unhandled types are intentionally absent — the
|
|
220
|
+
* default formatter is biome, so the scope is keyed to what biome formats.
|
|
221
|
+
* Consumers who swap the formatter via `project.commands.formatCheck`
|
|
222
|
+
* do not get `changedFileScope` at all (see `buildDefaultGates`), so this
|
|
223
|
+
* filter only ever runs against the default biome command.
|
|
224
|
+
*/
|
|
225
|
+
const FORMATTER_ELIGIBLE_EXTENSIONS = new Set([
|
|
226
|
+
'ts',
|
|
227
|
+
'tsx',
|
|
228
|
+
'js',
|
|
229
|
+
'jsx',
|
|
230
|
+
'mjs',
|
|
231
|
+
'cjs',
|
|
232
|
+
'json',
|
|
233
|
+
'jsonc',
|
|
234
|
+
'css',
|
|
235
|
+
]);
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Whether a changed path is eligible for the default (biome) formatter,
|
|
239
|
+
* decided purely by file extension. Pure function — no I/O. Exported for
|
|
240
|
+
* unit coverage (Story #3410).
|
|
241
|
+
*
|
|
242
|
+
* @param {string} filePath - A repo-relative path (forward-slash normalized).
|
|
243
|
+
* @returns {boolean}
|
|
244
|
+
*/
|
|
245
|
+
export function isFormatterEligible(filePath) {
|
|
246
|
+
if (typeof filePath !== 'string') return false;
|
|
247
|
+
const lastSlash = Math.max(
|
|
248
|
+
filePath.lastIndexOf('/'),
|
|
249
|
+
filePath.lastIndexOf('\\'),
|
|
250
|
+
);
|
|
251
|
+
const base = filePath.slice(lastSlash + 1);
|
|
252
|
+
const dot = base.lastIndexOf('.');
|
|
253
|
+
// No extension (dotfile-only or extensionless) → not formatter-eligible.
|
|
254
|
+
if (dot <= 0) return false;
|
|
255
|
+
const ext = base.slice(dot + 1).toLowerCase();
|
|
256
|
+
return FORMATTER_ELIGIBLE_EXTENSIONS.has(ext);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function applyChangedFileScope({ gate, spawnCwd, log }) {
|
|
260
|
+
if (!gate.changedFileScope) {
|
|
261
|
+
return { gate, cmd: gate.cmd, args: gate.args, skip: false };
|
|
262
|
+
}
|
|
263
|
+
const changedFiles = listChangedFilesForFormatGate({
|
|
264
|
+
cwd: spawnCwd,
|
|
265
|
+
baseRef: gate.changedFileScope.baseRef,
|
|
266
|
+
});
|
|
267
|
+
// Filter to the formatter-eligible subset before deciding to skip. A
|
|
268
|
+
// non-empty diff that contains zero formatter-eligible files (e.g. a
|
|
269
|
+
// docs-only Story) must take the skip path, not invoke biome with only
|
|
270
|
+
// ineligible paths — biome reports "No files were processed" and exits 1
|
|
271
|
+
// in that case (Story #3410).
|
|
272
|
+
const eligibleFiles = changedFiles.filter(isFormatterEligible);
|
|
273
|
+
if (eligibleFiles.length === 0) {
|
|
274
|
+
log(
|
|
275
|
+
`[close-validation] ⏭ ${gate.name} skipped (no formatter-eligible changed files)`,
|
|
276
|
+
);
|
|
277
|
+
return { gate, cmd: gate.cmd, args: gate.args, skip: true };
|
|
278
|
+
}
|
|
279
|
+
const args =
|
|
280
|
+
gate.args[gate.args.length - 1] === '.'
|
|
281
|
+
? gate.args.slice(0, -1)
|
|
282
|
+
: gate.args;
|
|
283
|
+
log(
|
|
284
|
+
`[close-validation] ↳ ${gate.name} scoped to ${eligibleFiles.length} formatter-eligible changed file(s) from ${gate.changedFileScope.baseRef}...HEAD`,
|
|
285
|
+
);
|
|
286
|
+
return {
|
|
287
|
+
gate,
|
|
288
|
+
cmd: gate.cmd,
|
|
289
|
+
args: [...args, ...eligibleFiles],
|
|
290
|
+
skip: false,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Resolve whether the CRAP gate is enabled. When enabled, the close-
|
|
296
|
+
* validation graph drops the standalone `test` gate because coverage-
|
|
297
|
+
* capture already runs the suite under c8 instrumentation (Story #1798).
|
|
298
|
+
*
|
|
299
|
+
* Reads the single canonical shape `delivery.quality.gates.crap.enabled`
|
|
300
|
+
* from the resolved config. Defaults to `true` so an omitted setting
|
|
301
|
+
* matches `CRAP_GATE_DEFAULTS.enabled`. We deliberately do NOT round-trip
|
|
302
|
+
* through `getQuality()` here because that resolver expects the unresolved
|
|
303
|
+
* `gates.crap.*` shape.
|
|
304
|
+
*
|
|
305
|
+
* @param {object|undefined|null} config - Canonical resolved config.
|
|
306
|
+
* @returns {boolean}
|
|
307
|
+
*/
|
|
308
|
+
function isCrapGateEnabled(config) {
|
|
309
|
+
if (!config || typeof config !== 'object') return true;
|
|
310
|
+
const enabled = config?.delivery?.quality?.gates?.crap?.enabled;
|
|
311
|
+
return typeof enabled === 'boolean' ? enabled : true;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Conditionally produce the standalone `test` gate entry. Returns an empty
|
|
316
|
+
* array when the CRAP gate is enabled (Story #1798: coverage-capture is the
|
|
317
|
+
* canonical test runner in that mode); returns the legacy single-entry
|
|
318
|
+
* gate otherwise. Splitting this out keeps `buildDefaultGates` flat for
|
|
319
|
+
* the CRAP-cyclomatic gate.
|
|
320
|
+
*
|
|
321
|
+
* @param {object|undefined|null} config - Canonical resolved config.
|
|
322
|
+
* @returns {Gate[]}
|
|
323
|
+
*/
|
|
324
|
+
function buildTestGateEntry(config) {
|
|
325
|
+
if (isCrapGateEnabled(config)) return [];
|
|
326
|
+
return [{ name: 'test', cmd: 'npm', args: ['test'] }];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Build the canonical close-validation gate list.
|
|
331
|
+
*
|
|
332
|
+
* Ordering (cheapest fast-fail first): typecheck → lint → [test] →
|
|
333
|
+
* format → coverage-capture → check-baselines. The standalone `test`
|
|
334
|
+
* gate is dropped when `crap.enabled === true` (Story #1798) because
|
|
335
|
+
* coverage-capture carries test-failure signalling under c8 in that
|
|
336
|
+
* mode.
|
|
337
|
+
*
|
|
338
|
+
* `typecheck` is mandatory; consumers may customise the command via
|
|
339
|
+
* `project.commands.typecheck` (default `npm run typecheck`).
|
|
340
|
+
*
|
|
341
|
+
* Story #2210 retired the legacy per-kind in-process regression gates
|
|
342
|
+
* (`check-maintainability`, `check-crap`, `check-mutation`) and their
|
|
343
|
+
* shared `buildInProcessBaselineGate` runner. The unified
|
|
344
|
+
* `check-baselines` gate is now the single source of truth for per-kind
|
|
345
|
+
* regression enforcement (attribution-wired floor + tolerance + schema).
|
|
346
|
+
* The `epicBranch` parameter threads the close run's integration branch
|
|
347
|
+
* into two gates: the `format` gate's `changedFileScope` (existing) and —
|
|
348
|
+
* since Story #3890 — the `check-baselines` gate's `BASELINE_REF` env, so
|
|
349
|
+
* the baselines regression compare diffs head against the epic integration
|
|
350
|
+
* branch (`origin/<epicBranch>`) rather than the framework-default
|
|
351
|
+
* `origin/main`. Without this, every child Story on an `epic/<id>` branch
|
|
352
|
+
* re-discovered inherited main-vs-epic drift in untouched files as phantom
|
|
353
|
+
* regressions and worked around it by hand-setting `BASELINE_REF`.
|
|
354
|
+
*
|
|
355
|
+
* @param {{ config?: object, epicBranch?: string }} [opts] - `config` is the
|
|
356
|
+
* canonical resolved config (`{ project, delivery, ... }`); gate commands
|
|
357
|
+
* resolve from `project.commands` and the CRAP toggle from
|
|
358
|
+
* `delivery.quality.gates.crap.enabled`. `epicBranch` is the close run's
|
|
359
|
+
* integration branch (`epic/<id>` for Epic-attached Stories, the base
|
|
360
|
+
* branch for standalone Stories).
|
|
361
|
+
* @returns {Gate[]}
|
|
362
|
+
*/
|
|
363
|
+
export function buildDefaultGates({ config, epicBranch } = {}) {
|
|
364
|
+
const typecheckCmdString = resolveTypecheckCommand(config);
|
|
365
|
+
const [typecheckCmd, ...typecheckArgs] = typecheckCmdString
|
|
366
|
+
.split(/\s+/)
|
|
367
|
+
.filter(Boolean);
|
|
368
|
+
const formatCheckString = resolveFormatCheckCommand(config);
|
|
369
|
+
const [formatCmd, ...formatArgs] = formatCheckString
|
|
370
|
+
.split(/\s+/)
|
|
371
|
+
.filter(Boolean);
|
|
372
|
+
const formatWriteString = resolveFormatWriteCommand(config);
|
|
373
|
+
const formatChangedFileScope =
|
|
374
|
+
formatCheckString === FORMAT_CHECK_FALLBACK
|
|
375
|
+
? buildChangedFileScope(epicBranch)
|
|
376
|
+
: null;
|
|
377
|
+
const baselinesGateEnv = buildBaselinesGateEnv(epicBranch);
|
|
378
|
+
return [
|
|
379
|
+
{
|
|
380
|
+
name: 'typecheck',
|
|
381
|
+
cmd: typecheckCmd,
|
|
382
|
+
args: typecheckArgs,
|
|
383
|
+
hint: TYPECHECK_HINT,
|
|
384
|
+
},
|
|
385
|
+
{ name: 'lint', cmd: 'npm', args: ['run', 'lint'] },
|
|
386
|
+
...buildTestGateEntry(config),
|
|
387
|
+
{
|
|
388
|
+
// Gate name kept generic ("format") so the close-orchestrator log line
|
|
389
|
+
// and the per-gate phase-timer key don't shift when a repo swaps biome
|
|
390
|
+
// for Prettier / dprint via `project.commands.formatCheck`. The
|
|
391
|
+
// actual command and the remediation hint resolve from config.
|
|
392
|
+
name: 'format',
|
|
393
|
+
cmd: formatCmd,
|
|
394
|
+
args: formatArgs,
|
|
395
|
+
hint: buildFormatHint(formatWriteString),
|
|
396
|
+
...(formatChangedFileScope
|
|
397
|
+
? { changedFileScope: formatChangedFileScope }
|
|
398
|
+
: {}),
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
name: 'coverage-capture',
|
|
402
|
+
cmd: 'node',
|
|
403
|
+
args: ['.agents/scripts/coverage-capture.js'],
|
|
404
|
+
hint: 'Coverage capture failed — `npm run test:coverage` exited non-zero. Fix failing tests or coverage-threshold breaches, then re-run close.',
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
// Story #2210 — unified `check-baselines` gate is the only path for
|
|
408
|
+
// per-kind regression enforcement. The legacy per-kind in-process
|
|
409
|
+
// gates (`check-maintainability`, `check-crap`, `check-mutation`)
|
|
410
|
+
// were retired with `buildInProcessBaselineGate` because their
|
|
411
|
+
// regression-compare semantics are fully subsumed by this gate's
|
|
412
|
+
// attribution-wired floor + tolerance + schema enforcement, and
|
|
413
|
+
// running both paths in series was redundant and conflict-prone.
|
|
414
|
+
//
|
|
415
|
+
// `check-baselines.js` self-skips per-kind gates whose
|
|
416
|
+
// `enabled === false` is configured, so registering it
|
|
417
|
+
// unconditionally is safe.
|
|
418
|
+
name: 'check-baselines',
|
|
419
|
+
cmd: 'node',
|
|
420
|
+
args: ['.agents/scripts/check-baselines.js', '--format', 'text'],
|
|
421
|
+
hint: 'Unified baselines gate breached. Inspect the JSON report (`node .agents/scripts/check-baselines.js`) to see which kind/component/axis fell below floor; remediate the underlying file(s) or — when the regression is intentional — refresh the relevant baseline through its per-kind update script and commit with a `baseline-refresh:` tagged subject.',
|
|
422
|
+
...(baselinesGateEnv ? { env: baselinesGateEnv } : {}),
|
|
423
|
+
},
|
|
424
|
+
];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Default gate list resolved with no consumer config — uses the
|
|
429
|
+
* `npm run typecheck` fallback for the typecheck gate. Call sites that have a
|
|
430
|
+
* resolved config object in scope (e.g. `story-close.js`) should
|
|
431
|
+
* prefer `buildDefaultGates({ config })` so a configured
|
|
432
|
+
* `project.commands.typecheck` is honoured.
|
|
433
|
+
*
|
|
434
|
+
* @type {Gate[]}
|
|
435
|
+
*/
|
|
436
|
+
export const DEFAULT_GATES = buildDefaultGates();
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Gates whose I/O is read-only against the working tree (no shared mutable
|
|
440
|
+
* state, no overlapping ports/sockets). Safe to run concurrently — see
|
|
441
|
+
* `runCloseValidation` for the Promise.all + AbortController plumbing.
|
|
442
|
+
*/
|
|
443
|
+
export const INDEPENDENT_GATE_NAMES = new Set(['lint', 'format', 'typecheck']);
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Partition a gate list into the parallel-safe set and the order-sensitive
|
|
447
|
+
* remainder. Order is preserved within each bucket so the serial walk stays
|
|
448
|
+
* cheapest-fast-fail-first (test → coverage-capture → check-baselines).
|
|
449
|
+
*
|
|
450
|
+
* @param {Gate[]} gates
|
|
451
|
+
* @returns {{ independent: Gate[], serial: Gate[] }}
|
|
452
|
+
*/
|
|
453
|
+
export function partitionGates(gates) {
|
|
454
|
+
const independent = [];
|
|
455
|
+
const serial = [];
|
|
456
|
+
for (const gate of gates) {
|
|
457
|
+
if (INDEPENDENT_GATE_NAMES.has(gate.name)) independent.push(gate);
|
|
458
|
+
else serial.push(gate);
|
|
459
|
+
}
|
|
460
|
+
return { independent, serial };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Pipe a child stream's output line-by-line through `emit`, prepending
|
|
465
|
+
* `prefix` to each line. Tail bytes without a trailing newline flush on
|
|
466
|
+
* `end` so the operator never loses the last line of a gate's output.
|
|
467
|
+
*/
|
|
468
|
+
function pipePrefixed(stream, prefix, emit) {
|
|
469
|
+
let buf = '';
|
|
470
|
+
stream.setEncoding('utf8');
|
|
471
|
+
stream.on('data', (chunk) => {
|
|
472
|
+
buf += chunk;
|
|
473
|
+
while (true) {
|
|
474
|
+
const nl = buf.indexOf('\n');
|
|
475
|
+
if (nl === -1) break;
|
|
476
|
+
emit(prefix + buf.slice(0, nl));
|
|
477
|
+
buf = buf.slice(nl + 1);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
stream.on('end', () => {
|
|
481
|
+
if (buf.length > 0) emit(prefix + buf);
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Default async gate runner — used by `runCloseValidation` when no `runner`
|
|
487
|
+
* is injected. Spawns the gate via `child_process.spawn`, prefixes every
|
|
488
|
+
* stdout/stderr line with `[gate-name] ` (so concurrent gates don't bleed
|
|
489
|
+
* into each other in the operator's terminal), and resolves only when the
|
|
490
|
+
* child exits.
|
|
491
|
+
*
|
|
492
|
+
* Honours `opts.signal`: a TERM is delivered to the child the moment the
|
|
493
|
+
* signal fires, so a sibling gate's failure aborts the rest of the wave
|
|
494
|
+
* promptly. The promise still resolves (rather than rejecting) on abort —
|
|
495
|
+
* `runCloseValidation` sees a non-zero status and folds it into the
|
|
496
|
+
* already-recorded first-failure.
|
|
497
|
+
*
|
|
498
|
+
* @param {string} cmd
|
|
499
|
+
* @param {string[]} args
|
|
500
|
+
* @param {{ cwd: string, signal?: AbortSignal, gateName?: string, log?: (m: string) => void, env?: Record<string, string> }} opts
|
|
501
|
+
* @returns {Promise<{ status: number }>}
|
|
502
|
+
*/
|
|
503
|
+
/** Wire the AbortSignal so an abort kills the child. Returns the cleanup fn. */
|
|
504
|
+
export function attachGateAbortHandler(child, signal) {
|
|
505
|
+
if (!signal) return () => {};
|
|
506
|
+
const killChild = () => {
|
|
507
|
+
try {
|
|
508
|
+
child.kill('SIGTERM');
|
|
509
|
+
} catch {
|
|
510
|
+
/* race: already exited */
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
if (signal.aborted) {
|
|
514
|
+
killChild();
|
|
515
|
+
return () => {};
|
|
516
|
+
}
|
|
517
|
+
signal.addEventListener('abort', killChild, { once: true });
|
|
518
|
+
return () => signal.removeEventListener('abort', killChild);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/** SIGTERM (no exit code) on abort → non-zero so the gate counts as failed. */
|
|
522
|
+
export function gateExitCode(code, sig) {
|
|
523
|
+
if (typeof code === 'number') return code;
|
|
524
|
+
return sig ? 143 : 1;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function defaultGateRunner(cmd, args, opts = {}) {
|
|
528
|
+
const { cwd, signal, gateName, log, env } = opts;
|
|
529
|
+
const child = spawn(cmd, args, {
|
|
530
|
+
cwd,
|
|
531
|
+
shell: process.platform === 'win32',
|
|
532
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
533
|
+
// Per-gate env overlay (Story #3890): merged over the inherited
|
|
534
|
+
// environment so a gate-scoped `BASELINE_REF` reaches the spawned
|
|
535
|
+
// `check-baselines` child without mutating the parent process env.
|
|
536
|
+
...(env ? { env: { ...process.env, ...env } } : {}),
|
|
537
|
+
});
|
|
538
|
+
const prefix = gateName ? `[${gateName}] ` : '';
|
|
539
|
+
const emit =
|
|
540
|
+
typeof log === 'function' ? log : (m) => process.stdout.write(`${m}\n`);
|
|
541
|
+
pipePrefixed(child.stdout, prefix, emit);
|
|
542
|
+
pipePrefixed(child.stderr, prefix, emit);
|
|
543
|
+
const detach = attachGateAbortHandler(child, signal);
|
|
544
|
+
return new Promise((resolve) => {
|
|
545
|
+
child.on('exit', (code, sig) => {
|
|
546
|
+
detach();
|
|
547
|
+
resolve({ status: gateExitCode(code, sig) });
|
|
548
|
+
});
|
|
549
|
+
child.on('error', () => {
|
|
550
|
+
detach();
|
|
551
|
+
resolve({ status: 1 });
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Run every gate sequentially. Stops collecting after the first failure but
|
|
558
|
+
* still returns a summary so the caller decides how to surface the result.
|
|
559
|
+
*
|
|
560
|
+
* Worktree locality (Story #1120): when `worktreePath` is supplied, every
|
|
561
|
+
* gate runner is spawned with `cwd: worktreePath` so the gate sees the
|
|
562
|
+
* Story branch's post-rebase tree. Evidence reads/writes still key against
|
|
563
|
+
* `cwd` (the main checkout) because the per-Epic temp tree lives under
|
|
564
|
+
* the main `.git/`. Failure messages name the worktree path.
|
|
565
|
+
*
|
|
566
|
+
* Evidence-aware: when both `storyId` and `epicId` are provided and
|
|
567
|
+
* `useEvidence !== false`, each gate consults `validation-evidence
|
|
568
|
+
* .shouldSkip()` against current HEAD + the gate's command-config hash. A
|
|
569
|
+
* matching record skips the gate; a successful run is recorded so the
|
|
570
|
+
* next caller in the local hot path can skip in turn.
|
|
571
|
+
*
|
|
572
|
+
* `onGateStart` is invoked immediately before each gate's runner spawn.
|
|
573
|
+
* story-close uses it to drive `phaseTimer.mark(...)` for per-gate
|
|
574
|
+
* wall-clock telemetry. Errors thrown from the hook propagate.
|
|
575
|
+
*
|
|
576
|
+
* @param {{
|
|
577
|
+
* cwd: string,
|
|
578
|
+
* worktreePath?: string,
|
|
579
|
+
* gates?: Gate[],
|
|
580
|
+
* runner?: (cmd: string, args: string[], opts: { cwd: string, signal?: AbortSignal, gateName?: string, log?: (m: string) => void }) => Promise<{ status: number }> | { status: number },
|
|
581
|
+
* log?: (m: string) => void,
|
|
582
|
+
* onGateStart?: (gate: Gate) => void,
|
|
583
|
+
* storyId?: number|null,
|
|
584
|
+
* epicId?: number|null,
|
|
585
|
+
* useEvidence?: boolean,
|
|
586
|
+
* evidenceClock?: () => number,
|
|
587
|
+
* getHeadSha?: (cwd: string) => string|null,
|
|
588
|
+
* recordPass?: typeof defaultRecordPass,
|
|
589
|
+
* shouldSkip?: typeof defaultShouldSkip,
|
|
590
|
+
* }} opts
|
|
591
|
+
* @returns {{ ok: boolean, failed: Array<{ gate: Gate, status: number, cwd: string }>, skipped: Array<{ gate: Gate, reason: string }> }}
|
|
592
|
+
*/
|
|
593
|
+
export async function runCloseValidation({
|
|
594
|
+
cwd,
|
|
595
|
+
worktreePath,
|
|
596
|
+
gates = DEFAULT_GATES,
|
|
597
|
+
runner = defaultGateRunner,
|
|
598
|
+
log = () => {},
|
|
599
|
+
onGateStart,
|
|
600
|
+
storyId = null,
|
|
601
|
+
epicId = null,
|
|
602
|
+
useEvidence = true,
|
|
603
|
+
evidenceClock = () => Date.now(),
|
|
604
|
+
getHeadSha = (resolvedCwd) => defaultGetHeadSha(resolvedCwd),
|
|
605
|
+
recordPass = defaultRecordPass,
|
|
606
|
+
shouldSkip = defaultShouldSkip,
|
|
607
|
+
} = {}) {
|
|
608
|
+
const failed = [];
|
|
609
|
+
const skipped = [];
|
|
610
|
+
const evidenceActive = useEvidence && storyId != null && epicId != null;
|
|
611
|
+
// Evidence keys against the main checkout's HEAD because the per-Epic
|
|
612
|
+
// evidence file lives under the main `.git/`. Gate spawn, in contrast,
|
|
613
|
+
// runs in the worktree when one is supplied — that's the whole point of
|
|
614
|
+
// Story #1120.
|
|
615
|
+
const spawnCwd = worktreePath ?? cwd;
|
|
616
|
+
const headSha = evidenceActive ? getHeadSha(spawnCwd) : null;
|
|
617
|
+
|
|
618
|
+
// Helper closures so the parallel and serial passes share evidence
|
|
619
|
+
// bookkeeping bit-for-bit.
|
|
620
|
+
|
|
621
|
+
/** Returns a `{ skip: true }` verdict when evidence makes the gate redundant. */
|
|
622
|
+
const evidenceVerdict = (gate, configHash) => {
|
|
623
|
+
if (!(evidenceActive && headSha)) return { skip: false };
|
|
624
|
+
const verdict = shouldSkip(
|
|
625
|
+
{
|
|
626
|
+
storyId,
|
|
627
|
+
gateName: gate.name,
|
|
628
|
+
currentSha: headSha,
|
|
629
|
+
configHash,
|
|
630
|
+
inputFingerprint: gate.inputFingerprint ?? null,
|
|
631
|
+
},
|
|
632
|
+
{ cwd, epicId },
|
|
633
|
+
);
|
|
634
|
+
if (verdict.skip) {
|
|
635
|
+
const tsHint = verdict.record?.timestamp
|
|
636
|
+
? ` recorded ${verdict.record.timestamp}`
|
|
637
|
+
: '';
|
|
638
|
+
log(
|
|
639
|
+
`[close-validation] ⏭ ${gate.name} skipped (${verdict.reason}: SHA=${headSha.slice(0, 7)}${tsHint})`,
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
return verdict;
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
const recordIfActive = (gate, configHash, durationMs) => {
|
|
646
|
+
if (!(evidenceActive && headSha)) return;
|
|
647
|
+
try {
|
|
648
|
+
recordPass(
|
|
649
|
+
{
|
|
650
|
+
storyId,
|
|
651
|
+
gateName: gate.name,
|
|
652
|
+
sha: headSha,
|
|
653
|
+
configHash,
|
|
654
|
+
exitCode: 0,
|
|
655
|
+
durationMs,
|
|
656
|
+
inputFingerprint: gate.inputFingerprint ?? null,
|
|
657
|
+
},
|
|
658
|
+
{ cwd, epicId },
|
|
659
|
+
);
|
|
660
|
+
} catch (err) {
|
|
661
|
+
log(
|
|
662
|
+
`[close-validation] ⚠ failed to record evidence for ${gate.name}: ${err?.message ?? err}`,
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Run a single gate. When `gate.run` is a function the gate executes
|
|
669
|
+
* **in process** (Story #1973 / Task #1984 — per-kind baseline gates
|
|
670
|
+
* removed their `child_process.spawn(node check-<kind>.js)` arm and
|
|
671
|
+
* call `compare(head, base)` directly). The `run` callable receives
|
|
672
|
+
* the same `(cmd, args, opts)` argv shape as `runner` so it slots into
|
|
673
|
+
* the existing contract without churn at the runner boundary.
|
|
674
|
+
* Otherwise the supplied `runner` is used (default: spawn).
|
|
675
|
+
*
|
|
676
|
+
* @returns {Promise<{ status: number }>}
|
|
677
|
+
*/
|
|
678
|
+
const dispatchGate = async (gate, signal) => {
|
|
679
|
+
log(
|
|
680
|
+
`[close-validation] ▶ ${gate.name}${worktreePath ? ` (cwd=${worktreePath})` : ''}`,
|
|
681
|
+
);
|
|
682
|
+
if (typeof onGateStart === 'function') onGateStart(gate);
|
|
683
|
+
const dispatcher = typeof gate.run === 'function' ? gate.run : runner;
|
|
684
|
+
const result = await dispatcher(gate.cmd, gate.args, {
|
|
685
|
+
cwd: spawnCwd,
|
|
686
|
+
gateName: gate.name,
|
|
687
|
+
log,
|
|
688
|
+
signal,
|
|
689
|
+
...(gate.env ? { env: gate.env } : {}),
|
|
690
|
+
});
|
|
691
|
+
return { status: result?.status ?? 1 };
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
const { independent, serial } = partitionGates(gates);
|
|
695
|
+
|
|
696
|
+
// ── Phase 1: independent gates in parallel ──────────────────────────
|
|
697
|
+
// First non-zero exit pins `firstFailure` and aborts every in-flight
|
|
698
|
+
// sibling via SIGTERM. Other gates' results are still awaited (so we
|
|
699
|
+
// never leak children) but their non-zero status is intentionally
|
|
700
|
+
// dropped: only one error surfaces.
|
|
701
|
+
const ac = new AbortController();
|
|
702
|
+
let firstIndepFailure = null;
|
|
703
|
+
|
|
704
|
+
const indepTasks = independent.map(async (gate) => {
|
|
705
|
+
let execution;
|
|
706
|
+
try {
|
|
707
|
+
execution = applyChangedFileScope({ gate, spawnCwd, log });
|
|
708
|
+
} catch (err) {
|
|
709
|
+
if (!firstIndepFailure) {
|
|
710
|
+
firstIndepFailure = { gate, status: 1, cwd: spawnCwd };
|
|
711
|
+
log(
|
|
712
|
+
`[close-validation] ✖ ${gate.name} failed to resolve changed-file scope: ${err?.message ?? err}`,
|
|
713
|
+
);
|
|
714
|
+
ac.abort();
|
|
715
|
+
}
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
if (execution.skip) {
|
|
719
|
+
skipped.push({ gate, reason: 'no-changed-files' });
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const configHash = hashCommandConfig({
|
|
723
|
+
cmd: execution.cmd,
|
|
724
|
+
args: execution.args,
|
|
725
|
+
cwd: spawnCwd,
|
|
726
|
+
});
|
|
727
|
+
const verdict = evidenceVerdict(gate, configHash);
|
|
728
|
+
if (verdict.skip) {
|
|
729
|
+
skipped.push({ gate, reason: verdict.reason });
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const startedAt = evidenceActive ? evidenceClock() : 0;
|
|
733
|
+
let result;
|
|
734
|
+
try {
|
|
735
|
+
result = await dispatchGate(
|
|
736
|
+
{ ...gate, cmd: execution.cmd, args: execution.args },
|
|
737
|
+
ac.signal,
|
|
738
|
+
);
|
|
739
|
+
} catch (err) {
|
|
740
|
+
result = { status: 1, error: err };
|
|
741
|
+
}
|
|
742
|
+
if (result.status !== 0) {
|
|
743
|
+
if (!firstIndepFailure) {
|
|
744
|
+
firstIndepFailure = { gate, status: result.status, cwd: spawnCwd };
|
|
745
|
+
ac.abort();
|
|
746
|
+
}
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
log(`[close-validation] ✓ ${gate.name}`);
|
|
750
|
+
recordIfActive(
|
|
751
|
+
gate,
|
|
752
|
+
configHash,
|
|
753
|
+
evidenceActive ? evidenceClock() - startedAt : 0,
|
|
754
|
+
);
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
await Promise.all(indepTasks);
|
|
758
|
+
|
|
759
|
+
if (firstIndepFailure) {
|
|
760
|
+
failed.push(firstIndepFailure);
|
|
761
|
+
log(
|
|
762
|
+
`[close-validation] ✖ ${firstIndepFailure.gate.name} failed (exit ${firstIndepFailure.status}) in ${spawnCwd}`,
|
|
763
|
+
);
|
|
764
|
+
if (firstIndepFailure.gate.hint) {
|
|
765
|
+
log(`[close-validation] hint: ${firstIndepFailure.gate.hint}`);
|
|
766
|
+
}
|
|
767
|
+
return { ok: false, failed, skipped };
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// ── Phase 2: serial gates in declared order ─────────────────────────
|
|
771
|
+
for (const gate of serial) {
|
|
772
|
+
let execution;
|
|
773
|
+
try {
|
|
774
|
+
execution = applyChangedFileScope({ gate, spawnCwd, log });
|
|
775
|
+
} catch (err) {
|
|
776
|
+
failed.push({ gate, status: 1, cwd: spawnCwd });
|
|
777
|
+
log(
|
|
778
|
+
`[close-validation] ✖ ${gate.name} failed to resolve changed-file scope: ${err?.message ?? err}`,
|
|
779
|
+
);
|
|
780
|
+
if (gate.hint) log(`[close-validation] hint: ${gate.hint}`);
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
if (execution.skip) {
|
|
784
|
+
skipped.push({ gate, reason: 'no-changed-files' });
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
const configHash = hashCommandConfig({
|
|
788
|
+
cmd: execution.cmd,
|
|
789
|
+
args: execution.args,
|
|
790
|
+
cwd: spawnCwd,
|
|
791
|
+
});
|
|
792
|
+
const verdict = evidenceVerdict(gate, configHash);
|
|
793
|
+
if (verdict.skip) {
|
|
794
|
+
skipped.push({ gate, reason: verdict.reason });
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
const startedAt = evidenceActive ? evidenceClock() : 0;
|
|
798
|
+
const result = await dispatchGate({
|
|
799
|
+
...gate,
|
|
800
|
+
cmd: execution.cmd,
|
|
801
|
+
args: execution.args,
|
|
802
|
+
});
|
|
803
|
+
if (result.status !== 0) {
|
|
804
|
+
failed.push({ gate, status: result.status, cwd: spawnCwd });
|
|
805
|
+
log(
|
|
806
|
+
`[close-validation] ✖ ${gate.name} failed (exit ${result.status}) in ${spawnCwd}`,
|
|
807
|
+
);
|
|
808
|
+
if (gate.hint) log(`[close-validation] hint: ${gate.hint}`);
|
|
809
|
+
break;
|
|
810
|
+
}
|
|
811
|
+
log(`[close-validation] ✓ ${gate.name}`);
|
|
812
|
+
recordIfActive(
|
|
813
|
+
gate,
|
|
814
|
+
configHash,
|
|
815
|
+
evidenceActive ? evidenceClock() - startedAt : 0,
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
return { ok: failed.length === 0, failed, skipped };
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Pre-merge MI ceiling projection helpers — `projectMaintainabilityRegressions`
|
|
824
|
+
* and `formatMaintainabilityProjection` were extracted to
|
|
825
|
+
* `close-validation/projections/maintainability.js` (Story #1850) so the
|
|
826
|
+
* parent module stays below the 700-LOC ceiling and the inline guard
|
|
827
|
+
* cascade collapses into the shared `validateProjectionInputs` predicate.
|
|
828
|
+
* The re-export below preserves the public contract — every existing call
|
|
829
|
+
* site continues to import from `./close-validation.js`.
|
|
830
|
+
*/
|
|
831
|
+
export {
|
|
832
|
+
formatMaintainabilityProjection,
|
|
833
|
+
projectMaintainabilityRegressions,
|
|
834
|
+
} from './close-validation/projections/maintainability.js';
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Throw-away ghSpawnCount emitter (Story #1795 / Epic #1788).
|
|
838
|
+
*
|
|
839
|
+
* Writes the current `gh-exec` spawn counter to
|
|
840
|
+
* `temp/epic-<eid>/stories/story-<sid>/gh-spawn-count.json` so the
|
|
841
|
+
* `analyze-execution.js` child process can read it and emit a
|
|
842
|
+
* `ghSpawnCount` field on the `story-perf-summary` payload. The Story-
|
|
843
|
+
* close orchestrator calls this inside `runPostMergeClose` right before
|
|
844
|
+
* the perf-summary phase, capturing every `gh` invocation from preflight
|
|
845
|
+
* through the merge in one counter snapshot.
|
|
846
|
+
*
|
|
847
|
+
* @param {object} opts
|
|
848
|
+
* @param {number|string} opts.epicId
|
|
849
|
+
* @param {number|string} opts.storyId
|
|
850
|
+
* @param {object} [opts.config] - Resolved config bag so `tempRoot`
|
|
851
|
+
* resolution honours the consumer's configured path.
|
|
852
|
+
* @param {() => number} [opts.getSpawnCountFn=defaultGetSpawnCount] - Test seam.
|
|
853
|
+
* @param {typeof defaultWriteFile} [opts.writeFileFn=defaultWriteFile] - Test seam.
|
|
854
|
+
* @param {{ warn?: (s: string) => void }} [opts.logger] - Best-effort
|
|
855
|
+
* failure-path logger; never throws.
|
|
856
|
+
* @returns {Promise<{ status: 'ok'|'failed', path?: string, ghSpawnCount?: number, reason?: string }>}
|
|
857
|
+
*/
|
|
858
|
+
export async function emitGhSpawnCount({
|
|
859
|
+
epicId,
|
|
860
|
+
storyId,
|
|
861
|
+
config,
|
|
862
|
+
getSpawnCountFn = defaultGetSpawnCount,
|
|
863
|
+
writeFileFn = defaultWriteFile,
|
|
864
|
+
logger,
|
|
865
|
+
} = {}) {
|
|
866
|
+
const eid = Number(epicId);
|
|
867
|
+
const sid = Number(storyId);
|
|
868
|
+
if (!Number.isInteger(eid) || eid < 1 || !Number.isInteger(sid) || sid < 1) {
|
|
869
|
+
return { status: 'failed', reason: 'invalid-ids' };
|
|
870
|
+
}
|
|
871
|
+
let ghSpawnCount;
|
|
872
|
+
try {
|
|
873
|
+
ghSpawnCount = getSpawnCountFn();
|
|
874
|
+
} catch (err) {
|
|
875
|
+
logger?.warn?.(
|
|
876
|
+
`[close-validation] gh-spawn-count read failed: ${err?.message ?? err}`,
|
|
877
|
+
);
|
|
878
|
+
return { status: 'failed', reason: 'counter-read-failed' };
|
|
879
|
+
}
|
|
880
|
+
const targetPath = storyArtifactPath(eid, sid, 'gh-spawn-count.json', config);
|
|
881
|
+
const payload = {
|
|
882
|
+
kind: 'gh-spawn-count',
|
|
883
|
+
epicId: eid,
|
|
884
|
+
storyId: sid,
|
|
885
|
+
ghSpawnCount,
|
|
886
|
+
capturedAt: new Date().toISOString(),
|
|
887
|
+
};
|
|
888
|
+
try {
|
|
889
|
+
await writeFileFn(targetPath, JSON.stringify(payload, null, 2));
|
|
890
|
+
return { status: 'ok', path: targetPath, ghSpawnCount };
|
|
891
|
+
} catch (err) {
|
|
892
|
+
logger?.warn?.(
|
|
893
|
+
`[close-validation] gh-spawn-count emit failed: ${err?.message ?? err}`,
|
|
894
|
+
);
|
|
895
|
+
return { status: 'failed', reason: 'write-failed' };
|
|
896
|
+
}
|
|
897
|
+
}
|