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,723 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/orchestration/ticketing/bulk.js — Cascade + batch ticketing surface.
|
|
3
|
+
*
|
|
4
|
+
* Owns the multi-ticket, cross-parent operations: the cascade walk that
|
|
5
|
+
* fires when a child ticket reaches `agent::done`, the per-parent
|
|
6
|
+
* sequencing lock, the transient-error classifier and retry budget, and
|
|
7
|
+
* the partial-failure log helper. Pulled out of `../ticketing.js` under
|
|
8
|
+
* Story #1848 so the verb-family split (`reads` / `state` / `bulk`) is
|
|
9
|
+
* complete and the parent collapses to a pure re-export facade.
|
|
10
|
+
*
|
|
11
|
+
* Note on the cycle with `./state.js`: `cascadeCompletion` recursively
|
|
12
|
+
* calls `transitionTicketState`, which in turn — when the cascade flag is
|
|
13
|
+
* on — calls back into `cascadeCompletion`. ESM tolerates the cycle
|
|
14
|
+
* because every binding is resolved at call-time. Both modules complete
|
|
15
|
+
* evaluation before any of their exported functions run.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { Logger } from '../../Logger.js';
|
|
19
|
+
import { TYPE_LABELS } from '../../label-constants.js';
|
|
20
|
+
import { dispatchCascadeGroups, groupByAncestor } from '../cascade-grouping.js';
|
|
21
|
+
import { ALL_STATES, STATE_LABELS } from './reads.js';
|
|
22
|
+
import {
|
|
23
|
+
postStructuredComment,
|
|
24
|
+
toggleTasklistCheckbox,
|
|
25
|
+
transitionTicketState,
|
|
26
|
+
} from './state.js';
|
|
27
|
+
|
|
28
|
+
// Re-export `groupByAncestor` so external callers that imported it from
|
|
29
|
+
// the ticketing facade continue to work after the verb-family split.
|
|
30
|
+
export { groupByAncestor };
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Retry budget for transient `gh` failures (rate limit, secondary rate limit,
|
|
34
|
+
* 5xx, transport timeouts) inside the cascade transition. Three attempts with
|
|
35
|
+
* exponential backoff (250ms / 500ms / 1000ms) mirrors the budget used by
|
|
36
|
+
* `gitFetchWithRetry` (see `lib/git-utils.js`) and the HTTP-client retry path
|
|
37
|
+
* referenced by `epic-plan-decompose.js`. Backoff is overridable via
|
|
38
|
+
* {@link __setCascadeRetryDelays} so tests don't pay real wall-clock time.
|
|
39
|
+
*/
|
|
40
|
+
const CASCADE_RETRY_BACKOFF_MS = [250, 500, 1000];
|
|
41
|
+
const defaultCascadeSleep = (ms) =>
|
|
42
|
+
new Promise((resolve) => setTimeout(resolve, ms));
|
|
43
|
+
let _cascadeRetryDelays = CASCADE_RETRY_BACKOFF_MS;
|
|
44
|
+
let _cascadeSleep = defaultCascadeSleep;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Test seam — replace the backoff schedule and/or the sleep implementation
|
|
48
|
+
* used by the cascade retry loop. Restore by calling with no arguments.
|
|
49
|
+
*
|
|
50
|
+
* @param {{ delays?: number[], sleep?: (ms: number) => Promise<void> }} [opts]
|
|
51
|
+
*/
|
|
52
|
+
export function __setCascadeRetryDelays(opts = {}) {
|
|
53
|
+
_cascadeRetryDelays = Array.isArray(opts.delays)
|
|
54
|
+
? opts.delays
|
|
55
|
+
: CASCADE_RETRY_BACKOFF_MS;
|
|
56
|
+
_cascadeSleep =
|
|
57
|
+
typeof opts.sleep === 'function' ? opts.sleep : defaultCascadeSleep;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Per-parent serial lock used to prevent two concurrent cascades within the
|
|
62
|
+
* same wave from racing the parent's "all children done?" check (Story
|
|
63
|
+
* #1817). The map is keyed by parent issue number; entries are reclaimed
|
|
64
|
+
* once the last awaiter finishes. The lock is scoped to a single Node
|
|
65
|
+
* process — cross-process races (multiple worktrees closing in parallel)
|
|
66
|
+
* still rely on the retry/idempotency path.
|
|
67
|
+
*
|
|
68
|
+
* @type {Map<number, Promise<unknown>>}
|
|
69
|
+
*/
|
|
70
|
+
const parentCascadeLocks = new Map();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Acquire the per-parent cascade lock, run `fn`, then release. Awaiters
|
|
74
|
+
* queue strictly in invocation order. Failures of prior holders do not
|
|
75
|
+
* propagate — each acquirer sees a clean entry into `fn`.
|
|
76
|
+
*
|
|
77
|
+
* @template R
|
|
78
|
+
* @param {number} parentId
|
|
79
|
+
* @param {() => Promise<R>} fn
|
|
80
|
+
* @returns {Promise<R>}
|
|
81
|
+
*/
|
|
82
|
+
async function withParentCascadeLock(parentId, fn) {
|
|
83
|
+
const prev = parentCascadeLocks.get(parentId) ?? Promise.resolve();
|
|
84
|
+
const current = prev.then(
|
|
85
|
+
() => fn(),
|
|
86
|
+
() => fn(),
|
|
87
|
+
);
|
|
88
|
+
parentCascadeLocks.set(parentId, current);
|
|
89
|
+
try {
|
|
90
|
+
return await current;
|
|
91
|
+
} finally {
|
|
92
|
+
if (parentCascadeLocks.get(parentId) === current) {
|
|
93
|
+
parentCascadeLocks.delete(parentId);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Test seam — clear the per-parent cascade lock map between tests so a
|
|
100
|
+
* pending entry from one scenario does not leak into the next.
|
|
101
|
+
*/
|
|
102
|
+
export function __resetParentCascadeLocks() {
|
|
103
|
+
parentCascadeLocks.clear();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Classifies a thrown cascade error as "transient" (rate limit, secondary
|
|
108
|
+
* rate limit, 5xx, transport timeout / reset) so the retry loop can back
|
|
109
|
+
* off instead of surfacing the failure to the operator. Provider-agnostic:
|
|
110
|
+
* matches on typed error names (`GhRateLimitError`), HTTP status, and
|
|
111
|
+
* conservative regex over stderr + message.
|
|
112
|
+
*
|
|
113
|
+
* @param {unknown} err
|
|
114
|
+
* @returns {boolean}
|
|
115
|
+
*/
|
|
116
|
+
function isTransientCascadeError(err) {
|
|
117
|
+
if (!err || typeof err !== 'object') return false;
|
|
118
|
+
if (err.name === 'GhRateLimitError') return true;
|
|
119
|
+
const status = typeof err.status === 'number' ? err.status : null;
|
|
120
|
+
if (status === 429) return true;
|
|
121
|
+
if (status !== null && status >= 500) return true;
|
|
122
|
+
const haystack = `${err.message ?? ''}\n${err.stderr ?? ''}`.toLowerCase();
|
|
123
|
+
if (
|
|
124
|
+
/secondary rate limit|api rate limit exceeded|rate limit exceeded/.test(
|
|
125
|
+
haystack,
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
return true;
|
|
129
|
+
if (/abuse detection/.test(haystack)) return true;
|
|
130
|
+
if (/econnreset|etimedout|enotfound|eai_again|abort_err/.test(haystack))
|
|
131
|
+
return true;
|
|
132
|
+
if (/timed out|timeout|aborted|fetch failed|network/.test(haystack))
|
|
133
|
+
return true;
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Render a cascade-failure error into a single log-friendly string that
|
|
139
|
+
* preserves stderr and exit-code context. The legacy log line collapsed
|
|
140
|
+
* `gh-exec`-thrown errors to a bare "exit 1" message, which made the
|
|
141
|
+
* failure mode unclassifiable post-hoc (see Story #1817).
|
|
142
|
+
*
|
|
143
|
+
* @param {unknown} err
|
|
144
|
+
* @returns {string}
|
|
145
|
+
*/
|
|
146
|
+
function formatCascadeError(err) {
|
|
147
|
+
if (!err) return 'unknown error';
|
|
148
|
+
if (typeof err !== 'object') return String(err);
|
|
149
|
+
const parts = [];
|
|
150
|
+
if (err.name && err.name !== 'Error') parts.push(`${err.name}`);
|
|
151
|
+
if (err.message) parts.push(err.message);
|
|
152
|
+
if (typeof err.code === 'number') parts.push(`exit=${err.code}`);
|
|
153
|
+
if (typeof err.status === 'number') parts.push(`http=${err.status}`);
|
|
154
|
+
if (typeof err.stderr === 'string' && err.stderr.trim()) {
|
|
155
|
+
const trimmed = err.stderr.trim().replace(/\s+/g, ' ');
|
|
156
|
+
const capped = trimmed.length > 400 ? `${trimmed.slice(0, 400)}…` : trimmed;
|
|
157
|
+
parts.push(`stderr=${capped}`);
|
|
158
|
+
}
|
|
159
|
+
return parts.join(' | ') || String(err);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Run `fn` with exponential backoff on transient errors. Non-transient
|
|
164
|
+
* errors propagate immediately on the first attempt. The total attempt
|
|
165
|
+
* count is `delays.length + 1` (one initial attempt plus one retry per
|
|
166
|
+
* delay).
|
|
167
|
+
*
|
|
168
|
+
* @template R
|
|
169
|
+
* @param {() => Promise<R>} fn
|
|
170
|
+
* @param {{ onRetry?: (err: unknown, attempt: number, delayMs: number) => void }} [opts]
|
|
171
|
+
* @returns {Promise<R>}
|
|
172
|
+
*/
|
|
173
|
+
async function retryTransient(fn, opts = {}) {
|
|
174
|
+
const delays = _cascadeRetryDelays;
|
|
175
|
+
let attempt = 0;
|
|
176
|
+
for (;;) {
|
|
177
|
+
try {
|
|
178
|
+
return await fn();
|
|
179
|
+
} catch (err) {
|
|
180
|
+
if (!isTransientCascadeError(err)) throw err;
|
|
181
|
+
if (attempt >= delays.length) throw err;
|
|
182
|
+
const delay = delays[attempt];
|
|
183
|
+
if (typeof opts.onRetry === 'function') {
|
|
184
|
+
try {
|
|
185
|
+
opts.onRetry(err, attempt + 1, delay);
|
|
186
|
+
} catch {
|
|
187
|
+
// listener failures must not abort the retry
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
await _cascadeSleep(delay);
|
|
191
|
+
attempt += 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Emit a warn line for every per-parent cascade failure captured by
|
|
198
|
+
* {@link cascadeCompletion}. Each `error` string is pre-formatted with
|
|
199
|
+
* stderr + exit-code by `formatCascadeError`, so callers can pass the
|
|
200
|
+
* raw envelope through without further wrapping. Called from
|
|
201
|
+
* `state.js`'s `transitionTicketState` to keep its cyclomatic
|
|
202
|
+
* complexity inside the project's per-method CRAP ceiling (Story #1817,
|
|
203
|
+
* Story #1848).
|
|
204
|
+
*
|
|
205
|
+
* @param {number} ticketId The ticket whose `agent::done` transition
|
|
206
|
+
* triggered the cascade.
|
|
207
|
+
* @param {{ failed?: Array<{ parentId: number, error: string }> } | null} cascade
|
|
208
|
+
*/
|
|
209
|
+
export function logCascadePartialFailures(ticketId, cascade) {
|
|
210
|
+
const cascadeFailures = cascade?.failed ?? [];
|
|
211
|
+
for (const { parentId, error } of cascadeFailures) {
|
|
212
|
+
Logger.warn(
|
|
213
|
+
`[Ticketing] Cascade from #${ticketId} hit partial-failure on parent #${parentId}: ${error}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Per-parent body of {@link cascadeCompletion}. Pulled out so the outer
|
|
220
|
+
* function can dispatch disjoint groups in parallel while each parent
|
|
221
|
+
* still runs against its own captured logger, ensuring byte-identical
|
|
222
|
+
* log output across serial and parallel execution paths.
|
|
223
|
+
*
|
|
224
|
+
* @param {import('../../ITicketingProvider.js').ITicketingProvider} provider
|
|
225
|
+
* @param {number} ticketId - The ticket whose `agent::done` transition
|
|
226
|
+
* triggered the cascade.
|
|
227
|
+
* @param {number} parentId - The parent currently being processed.
|
|
228
|
+
* @param {{ notify?: Function, _logger?: object }} opts
|
|
229
|
+
* @returns {Promise<{ cascadedTo: number[], failed: Array<{ parentId: number, error: string }>, error?: Error }>}
|
|
230
|
+
*/
|
|
231
|
+
async function processCascadeParent(provider, ticketId, parentId, opts) {
|
|
232
|
+
const logger = opts._logger ?? Logger;
|
|
233
|
+
return withParentCascadeLock(parentId, () =>
|
|
234
|
+
processCascadeParentLocked(provider, ticketId, parentId, opts, logger),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Body of {@link processCascadeParent} that runs under the per-parent lock.
|
|
240
|
+
* Split out so the lock-acquire scaffolding stays a one-liner and the
|
|
241
|
+
* cyclomatic complexity of the per-parent worker doesn't drift over the
|
|
242
|
+
* project's CRAP ceiling once the retry / idempotency branches are added.
|
|
243
|
+
*
|
|
244
|
+
* @returns {Promise<{ cascadedTo: number[], failed: Array<{ parentId: number, error: string }> }>}
|
|
245
|
+
*/
|
|
246
|
+
async function processCascadeParentLocked(
|
|
247
|
+
provider,
|
|
248
|
+
ticketId,
|
|
249
|
+
parentId,
|
|
250
|
+
opts,
|
|
251
|
+
logger,
|
|
252
|
+
) {
|
|
253
|
+
const cascadedTo = [];
|
|
254
|
+
const failed = [];
|
|
255
|
+
try {
|
|
256
|
+
await toggleTasklistCheckbox(provider, parentId, ticketId, {
|
|
257
|
+
checked: true,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Idempotency check (Story #1817): re-fetch the parent under the lock
|
|
261
|
+
// so a concurrent cascade winner that already flipped this parent to
|
|
262
|
+
// `agent::done` short-circuits us without re-running the transition.
|
|
263
|
+
// The provider cache may still hold a stale row from before the
|
|
264
|
+
// winner's PATCH — invalidate first when supported.
|
|
265
|
+
if (typeof provider.invalidateTicket === 'function') {
|
|
266
|
+
try {
|
|
267
|
+
provider.invalidateTicket(parentId);
|
|
268
|
+
} catch {
|
|
269
|
+
// best-effort cache invalidation
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const parentSnapshot = await provider.getTicket(parentId);
|
|
273
|
+
if (parentSnapshot?.labels?.includes(STATE_LABELS.DONE)) {
|
|
274
|
+
logger.debug(
|
|
275
|
+
`[Ticketing] Cascade to parent #${parentId} skipped: already agent::done (concurrent winner).`,
|
|
276
|
+
);
|
|
277
|
+
return { cascadedTo, failed };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Fetch siblings with fresh reads to defend against stale-CLOSED entries.
|
|
281
|
+
// `{ fresh: true }` threads into the per-child `getTicket` inside
|
|
282
|
+
// `getSubTickets`, bypassing the cache in one pass rather than two.
|
|
283
|
+
// The per-child try/catch fallback-to-null is preserved by `getSubTickets`
|
|
284
|
+
// itself, so a transient read failure cannot silently flip the all-done
|
|
285
|
+
// check. The concurrency cap (SUBTICKET_HYDRATION_CONCURRENCY = 8) is
|
|
286
|
+
// applied inside `getSubTickets`.
|
|
287
|
+
const freshSubTickets = await provider.getSubTickets(parentId, {
|
|
288
|
+
fresh: true,
|
|
289
|
+
});
|
|
290
|
+
const allDone = freshSubTickets.every(
|
|
291
|
+
(st) => st.labels.includes(STATE_LABELS.DONE) || st.state === 'closed',
|
|
292
|
+
);
|
|
293
|
+
if (!allDone) return { cascadedTo, failed };
|
|
294
|
+
|
|
295
|
+
// EXCLUSION: Epics do not auto-close via cascade. Epics close via
|
|
296
|
+
// formal /epic-deliver (its own machinery handles branch merges,
|
|
297
|
+
// PR-driven `Closes #N` auto-close, and a recovery transition in
|
|
298
|
+
// `epic-deliver-finalize.js`).
|
|
299
|
+
//
|
|
300
|
+
// Planning tickets (context::prd, context::tech-spec) DO close via
|
|
301
|
+
// cascade now (Story #1951). Previously they were excluded under
|
|
302
|
+
// the assumption that the operator would close them manually
|
|
303
|
+
// post-merge — but that step never reliably happened and leaving
|
|
304
|
+
// them open as native sub-issues of the Epic blocks GitHub from
|
|
305
|
+
// honoring the Epic's `Closes #N` footer. The Epic finalize phase
|
|
306
|
+
// also closes them explicitly; this cascade branch is the
|
|
307
|
+
// defense-in-depth path when a Story's tasklist references a
|
|
308
|
+
// planning ticket directly.
|
|
309
|
+
//
|
|
310
|
+
// Features auto-close via cascade. A Feature is a purely
|
|
311
|
+
// hierarchical grouping — no standalone branch, no merge step.
|
|
312
|
+
// When its last child Story closes, the Feature is complete by
|
|
313
|
+
// definition. Operators who need Feature-level AC verification
|
|
314
|
+
// should encode it in the final child Story, not rely on a manual
|
|
315
|
+
// close step.
|
|
316
|
+
//
|
|
317
|
+
// Reuse the parentSnapshot from the idempotency check above — it is
|
|
318
|
+
// a fresh read (cache was invalidated before the getTicket call) and
|
|
319
|
+
// the parent's type label is invariant within a single cascade lock
|
|
320
|
+
// hold, so a second getTicket is wasteful and redundant.
|
|
321
|
+
const isEpic = parentSnapshot.labels.includes(TYPE_LABELS.EPIC);
|
|
322
|
+
if (isEpic) {
|
|
323
|
+
logger.warn(
|
|
324
|
+
`[Ticketing] Cascade reached Epic #${parentId}. Skipping auto-close (Epics close via the operator's PR merge).`,
|
|
325
|
+
);
|
|
326
|
+
return { cascadedTo, failed };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Retry the parent transition on transient `gh` failures (rate limit,
|
|
330
|
+
// 5xx, transport timeouts). Permanent failures fall through to the
|
|
331
|
+
// outer catch on the first attempt so the operator sees the real
|
|
332
|
+
// error rather than three retries' worth of noise.
|
|
333
|
+
await retryTransient(
|
|
334
|
+
() =>
|
|
335
|
+
transitionTicketState(provider, parentId, STATE_LABELS.DONE, {
|
|
336
|
+
notify: opts.notify,
|
|
337
|
+
}),
|
|
338
|
+
{
|
|
339
|
+
onRetry: (err, attempt, delayMs) => {
|
|
340
|
+
logger.warn(
|
|
341
|
+
`[Ticketing] Cascade to parent #${parentId} hit transient ${err?.name ?? 'error'} ` +
|
|
342
|
+
`(attempt ${attempt}); retrying in ${delayMs}ms. ${formatCascadeError(err)}`,
|
|
343
|
+
);
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
);
|
|
347
|
+
await postStructuredComment(
|
|
348
|
+
provider,
|
|
349
|
+
parentId,
|
|
350
|
+
'progress',
|
|
351
|
+
'All child tickets completed via recursive cascade.',
|
|
352
|
+
);
|
|
353
|
+
cascadedTo.push(parentId);
|
|
354
|
+
|
|
355
|
+
const nested = await cascadeCompletion(provider, parentId, {
|
|
356
|
+
notify: opts.notify,
|
|
357
|
+
_logger: logger,
|
|
358
|
+
});
|
|
359
|
+
cascadedTo.push(...nested.cascadedTo);
|
|
360
|
+
failed.push(...nested.failed);
|
|
361
|
+
} catch (err) {
|
|
362
|
+
const detail = formatCascadeError(err);
|
|
363
|
+
failed.push({ parentId, error: detail });
|
|
364
|
+
logger.warn(`[Ticketing] Cascade to parent #${parentId} failed: ${detail}`);
|
|
365
|
+
}
|
|
366
|
+
return { cascadedTo, failed };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Recursively cascade upward.
|
|
371
|
+
* If ticket reaches DONE, it toggles its checkbox in its parent.
|
|
372
|
+
* Then checks if parent's sub-tickets are ALL DONE.
|
|
373
|
+
* If yes, transitions parent to DONE and cascades up.
|
|
374
|
+
*
|
|
375
|
+
* Parents are partitioned into disjoint groups by shared ancestor
|
|
376
|
+
* ({@link groupByAncestor}). Groups run in parallel via `Promise.all`,
|
|
377
|
+
* but parents **within** a group run strictly sequentially in input
|
|
378
|
+
* order — concurrent transitions against a shared ancestor would race
|
|
379
|
+
* the "all children done?" check. Within each parent, sibling reads
|
|
380
|
+
* fan out via `getSubTickets(parentId, { fresh: true })` with the
|
|
381
|
+
* concurrency cap (8) applied inside `getSubTickets`.
|
|
382
|
+
*
|
|
383
|
+
* Log output is captured per parent into a buffered logger and flushed
|
|
384
|
+
* to the real {@link Logger} after all groups resolve, in the original
|
|
385
|
+
* `parsedParents` order. The visible log stream is therefore
|
|
386
|
+
* byte-identical to a serial baseline; only the I/O between parents in
|
|
387
|
+
* disjoint groups overlaps.
|
|
388
|
+
*
|
|
389
|
+
* Per-parent errors are isolated: a failure updating one parent (network,
|
|
390
|
+
* permission, stale ticket) never discards progress on sibling parents.
|
|
391
|
+
* Failures are collected and returned so callers can log them with full
|
|
392
|
+
* ticket context instead of seeing a single rejection.
|
|
393
|
+
*
|
|
394
|
+
* @param {import('../../ITicketingProvider.js').ITicketingProvider} provider
|
|
395
|
+
* @param {number} ticketId
|
|
396
|
+
* @param {{ notify?: Function, _logger?: object }} [opts] - `notify` is
|
|
397
|
+
* forwarded to any recursive `transitionTicketState` fired on parent
|
|
398
|
+
* tickets. `_logger` is an internal hook used by nested cascade calls
|
|
399
|
+
* to keep buffered output coherent — external callers should leave it
|
|
400
|
+
* unset so the module-level {@link Logger} is used.
|
|
401
|
+
* @returns {Promise<{ cascadedTo: number[], failed: Array<{ parentId: number, error: string }> }>}
|
|
402
|
+
*/
|
|
403
|
+
export async function cascadeCompletion(provider, ticketId, opts = {}) {
|
|
404
|
+
const ticket = await provider.getTicket(ticketId);
|
|
405
|
+
|
|
406
|
+
// Determine if this ticket is agent::done
|
|
407
|
+
if (!ticket.labels.includes(STATE_LABELS.DONE)) {
|
|
408
|
+
return { cascadedTo: [], failed: [] };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const { blocks: parentIds } = await provider.getTicketDependencies(ticketId);
|
|
412
|
+
|
|
413
|
+
// Fallback: parse `parent: #NNN` from the body when `blocks` syntax isn't used (C-5).
|
|
414
|
+
let parsedParents = parentIds;
|
|
415
|
+
if (!parsedParents || parsedParents.length === 0) {
|
|
416
|
+
const parentMatch = ticket.body
|
|
417
|
+
? [...ticket.body.matchAll(/parent:\s*#(\d+)/gi)]
|
|
418
|
+
: [];
|
|
419
|
+
parsedParents = parentMatch.map((m) => Number.parseInt(m[1], 10));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Story #2982 — third fallback: GitHub's native Sub-Issues API. The
|
|
423
|
+
// resume reconciler can strip the `parent: #N` orchestrator footer
|
|
424
|
+
// from a Story body (see Issue 2 in #2982); without the body marker
|
|
425
|
+
// the cascade silently returned `{ cascadedTo: [], failed: [] }` and
|
|
426
|
+
// left intermediate Feature tickets stranded OPEN. The native link is
|
|
427
|
+
// independent of body text, so consult it when the first two
|
|
428
|
+
// strategies came back empty.
|
|
429
|
+
if (
|
|
430
|
+
parsedParents.length === 0 &&
|
|
431
|
+
typeof provider._getNativeParent === 'function' &&
|
|
432
|
+
ticket.nodeId
|
|
433
|
+
) {
|
|
434
|
+
try {
|
|
435
|
+
const nativeParent = await provider._getNativeParent(
|
|
436
|
+
ticket.nodeId,
|
|
437
|
+
ticketId,
|
|
438
|
+
);
|
|
439
|
+
if (typeof nativeParent === 'number') {
|
|
440
|
+
parsedParents = [nativeParent];
|
|
441
|
+
}
|
|
442
|
+
} catch (err) {
|
|
443
|
+
Logger.warn(
|
|
444
|
+
`[cascadeCompletion] native parent lookup failed for #${ticketId}: ${err.message}`,
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (parsedParents.length === 0) {
|
|
450
|
+
return { cascadedTo: [], failed: [] };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Partition parents by shared ancestor (disjoint groups run in
|
|
454
|
+
// parallel; within-group parents stay sequential to avoid racing the
|
|
455
|
+
// shared ancestor's "all children done?" check), then dispatch the
|
|
456
|
+
// per-parent work via `dispatchCascadeGroups` so the buffered-flush
|
|
457
|
+
// bookkeeping lives in `cascade-grouping.js`.
|
|
458
|
+
const groups = await groupByAncestor(parsedParents, provider);
|
|
459
|
+
const results = await dispatchCascadeGroups({
|
|
460
|
+
parsedParents,
|
|
461
|
+
groups,
|
|
462
|
+
flushLogger: opts._logger ?? Logger,
|
|
463
|
+
processParent: (parentId, logger) =>
|
|
464
|
+
processCascadeParent(provider, ticketId, parentId, {
|
|
465
|
+
notify: opts.notify,
|
|
466
|
+
_logger: logger,
|
|
467
|
+
}),
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
const cascadedTo = [];
|
|
471
|
+
const failed = [];
|
|
472
|
+
for (const r of results) {
|
|
473
|
+
cascadedTo.push(...r.cascadedTo);
|
|
474
|
+
failed.push(...r.failed);
|
|
475
|
+
}
|
|
476
|
+
return { cascadedTo, failed };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Derive the parent `agent::*` state from the composition of its children.
|
|
481
|
+
*
|
|
482
|
+
* Rules (Story #2676):
|
|
483
|
+
* - Any child carrying `agent::blocked` → parent should be `agent::blocked`.
|
|
484
|
+
* - Otherwise, every child is `agent::done` (or closed) → parent should be
|
|
485
|
+
* `agent::done`.
|
|
486
|
+
* - Otherwise, any child carrying `agent::executing` or `agent::closing` →
|
|
487
|
+
* parent should be `agent::executing`.
|
|
488
|
+
* - Otherwise (e.g. all children still `agent::ready`) → return `null` to
|
|
489
|
+
* signal "leave the parent unchanged". A parent already partway through
|
|
490
|
+
* the lifecycle MUST NOT be downgraded just because one child reverted.
|
|
491
|
+
*
|
|
492
|
+
* The function is pure and exported so the rule can be exercised in
|
|
493
|
+
* isolation by unit tests without dragging the cascade I/O surface in.
|
|
494
|
+
*
|
|
495
|
+
* @param {Array<{ labels?: string[], state?: string }>} siblings
|
|
496
|
+
* @returns {string|null} A `STATE_LABELS.*` value, or `null` for no-op.
|
|
497
|
+
*/
|
|
498
|
+
export function deriveParentState(siblings) {
|
|
499
|
+
if (!Array.isArray(siblings) || siblings.length === 0) return null;
|
|
500
|
+
const labelsOf = (s) => (Array.isArray(s?.labels) ? s.labels : []);
|
|
501
|
+
if (siblings.some((s) => labelsOf(s).includes(STATE_LABELS.BLOCKED))) {
|
|
502
|
+
return STATE_LABELS.BLOCKED;
|
|
503
|
+
}
|
|
504
|
+
const allDone = siblings.every(
|
|
505
|
+
(s) => labelsOf(s).includes(STATE_LABELS.DONE) || s?.state === 'closed',
|
|
506
|
+
);
|
|
507
|
+
if (allDone) return STATE_LABELS.DONE;
|
|
508
|
+
const anyActive = siblings.some(
|
|
509
|
+
(s) =>
|
|
510
|
+
labelsOf(s).includes(STATE_LABELS.EXECUTING) ||
|
|
511
|
+
labelsOf(s).includes(STATE_LABELS.CLOSING),
|
|
512
|
+
);
|
|
513
|
+
if (anyActive) return STATE_LABELS.EXECUTING;
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Parent-state cascade for non-terminal transitions. Story #2676.
|
|
519
|
+
*
|
|
520
|
+
* When a child ticket transitions to any `agent::*` state, this function
|
|
521
|
+
* walks the parent chain and updates each parent's state to the value
|
|
522
|
+
* derived by {@link deriveParentState} — so that moving a Task to
|
|
523
|
+
* `agent::executing` propagates "in progress" up to the Story and the
|
|
524
|
+
* Epic on the Project board, and moving a Task to `agent::blocked`
|
|
525
|
+
* surfaces the HITL signal at every ancestor.
|
|
526
|
+
*
|
|
527
|
+
* For `agent::done` transitions, propagation is delegated to the
|
|
528
|
+
* existing {@link cascadeCompletion} so the long-standing semantics
|
|
529
|
+
* (tasklist checkbox toggling, the "All child tickets completed via
|
|
530
|
+
* recursive cascade" progress comment, Epic exclusion) are preserved
|
|
531
|
+
* verbatim.
|
|
532
|
+
*
|
|
533
|
+
* Resilience matches {@link cascadeCompletion}: disjoint parent groups
|
|
534
|
+
* run in parallel via {@link dispatchCascadeGroups}; parents within a
|
|
535
|
+
* group run sequentially; the per-parent lock from
|
|
536
|
+
* {@link withParentCascadeLock} prevents races on shared ancestors; and
|
|
537
|
+
* per-parent errors are isolated so a sibling parent's failure does not
|
|
538
|
+
* discard work on the others.
|
|
539
|
+
*
|
|
540
|
+
* @param {import('../../ITicketingProvider.js').ITicketingProvider} provider
|
|
541
|
+
* @param {number} ticketId
|
|
542
|
+
* @param {{ notify?: Function, _logger?: object }} [opts]
|
|
543
|
+
* @returns {Promise<{ cascadedTo: number[], failed: Array<{ parentId: number, error: string }> }>}
|
|
544
|
+
*/
|
|
545
|
+
export async function cascadeParentState(provider, ticketId, opts = {}) {
|
|
546
|
+
// Provider-capability guard. Cascade derivation needs both
|
|
547
|
+
// `getTicketDependencies` (to walk the `blocks:` parent edge) and
|
|
548
|
+
// `getSubTickets` (to inspect the parent's children). Test fakes
|
|
549
|
+
// that stub only the single-ticket surface (e.g. the column-sync
|
|
550
|
+
// sibling tests) MUST still be able to drive `transitionTicketState`
|
|
551
|
+
// without the cascade blowing up. Silently no-op when the surface
|
|
552
|
+
// is missing — propagation is best-effort, matching the contract
|
|
553
|
+
// already documented for the column-sync mirror.
|
|
554
|
+
if (
|
|
555
|
+
typeof provider?.getTicketDependencies !== 'function' ||
|
|
556
|
+
typeof provider?.getSubTickets !== 'function'
|
|
557
|
+
) {
|
|
558
|
+
return { cascadedTo: [], failed: [] };
|
|
559
|
+
}
|
|
560
|
+
const ticket = await provider.getTicket(ticketId);
|
|
561
|
+
const labels = Array.isArray(ticket?.labels) ? ticket.labels : [];
|
|
562
|
+
const childState = labels.find((l) => ALL_STATES.includes(l));
|
|
563
|
+
if (!childState) return { cascadedTo: [], failed: [] };
|
|
564
|
+
|
|
565
|
+
// DONE-cascade keeps the existing path: tasklist checkbox toggle,
|
|
566
|
+
// progress comment, Epic-close exclusion, and the legacy log shape are
|
|
567
|
+
// all encoded in `cascadeCompletion` and externally observed by tests.
|
|
568
|
+
if (childState === STATE_LABELS.DONE) {
|
|
569
|
+
return cascadeCompletion(provider, ticketId, opts);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const parsedParents = await resolveParentIds(provider, ticket, ticketId);
|
|
573
|
+
if (parsedParents.length === 0) return { cascadedTo: [], failed: [] };
|
|
574
|
+
|
|
575
|
+
const groups = await groupByAncestor(parsedParents, provider);
|
|
576
|
+
const results = await dispatchCascadeGroups({
|
|
577
|
+
parsedParents,
|
|
578
|
+
groups,
|
|
579
|
+
flushLogger: opts._logger ?? Logger,
|
|
580
|
+
processParent: (parentId, logger) =>
|
|
581
|
+
processStateCascadeParent(provider, parentId, {
|
|
582
|
+
notify: opts.notify,
|
|
583
|
+
_logger: logger,
|
|
584
|
+
}),
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
const cascadedTo = [];
|
|
588
|
+
const failed = [];
|
|
589
|
+
for (const r of results) {
|
|
590
|
+
cascadedTo.push(...r.cascadedTo);
|
|
591
|
+
failed.push(...r.failed);
|
|
592
|
+
}
|
|
593
|
+
return { cascadedTo, failed };
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Resolve the parent issue ids for a ticket: native `blocks:` dependency
|
|
598
|
+
* annotations first, then `parent: #NNN` body references as a fallback.
|
|
599
|
+
* Mirrors the resolution path used by {@link cascadeCompletion}.
|
|
600
|
+
*
|
|
601
|
+
* @param {import('../../ITicketingProvider.js').ITicketingProvider} provider
|
|
602
|
+
* @param {object} ticket
|
|
603
|
+
* @param {number} ticketId
|
|
604
|
+
* @returns {Promise<number[]>}
|
|
605
|
+
*/
|
|
606
|
+
async function resolveParentIds(provider, ticket, ticketId) {
|
|
607
|
+
const { blocks: parentIds } = await provider.getTicketDependencies(ticketId);
|
|
608
|
+
if (Array.isArray(parentIds) && parentIds.length > 0) return parentIds;
|
|
609
|
+
const parentMatch = ticket?.body
|
|
610
|
+
? [...ticket.body.matchAll(/parent:\s*#(\d+)/gi)]
|
|
611
|
+
: [];
|
|
612
|
+
return parentMatch.map((m) => Number.parseInt(m[1], 10));
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Per-parent worker for {@link cascadeParentState}. Acquires the shared
|
|
617
|
+
* per-parent cascade lock so concurrent transitions on sibling children
|
|
618
|
+
* cannot race on the parent's derived-state check.
|
|
619
|
+
*
|
|
620
|
+
* @returns {Promise<{ cascadedTo: number[], failed: Array<{ parentId: number, error: string }> }>}
|
|
621
|
+
*/
|
|
622
|
+
async function processStateCascadeParent(provider, parentId, opts) {
|
|
623
|
+
const logger = opts._logger ?? Logger;
|
|
624
|
+
return withParentCascadeLock(parentId, () =>
|
|
625
|
+
processStateCascadeParentLocked(provider, parentId, opts, logger),
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Body of {@link processStateCascadeParent} under the per-parent lock.
|
|
631
|
+
* Computes the derived state from a fresh sibling read, applies the
|
|
632
|
+
* idempotency guard, and recurses upward.
|
|
633
|
+
*/
|
|
634
|
+
async function processStateCascadeParentLocked(
|
|
635
|
+
provider,
|
|
636
|
+
parentId,
|
|
637
|
+
opts,
|
|
638
|
+
logger,
|
|
639
|
+
) {
|
|
640
|
+
const cascadedTo = [];
|
|
641
|
+
const failed = [];
|
|
642
|
+
try {
|
|
643
|
+
if (typeof provider.invalidateTicket === 'function') {
|
|
644
|
+
try {
|
|
645
|
+
provider.invalidateTicket(parentId);
|
|
646
|
+
} catch {
|
|
647
|
+
// best-effort cache invalidation
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
// Fetch siblings fresh in one pass — `{ fresh: true }` threads into the
|
|
651
|
+
// per-child `getTicket` inside `getSubTickets`, replacing the previous
|
|
652
|
+
// two-step pattern of `getSubTickets` + a second `concurrentMap` fan-out
|
|
653
|
+
// with `invalidateTicket` + `getTicket(id, { fresh:true })`.
|
|
654
|
+
const freshSubs = await provider.getSubTickets(parentId, { fresh: true });
|
|
655
|
+
|
|
656
|
+
const derived = deriveParentState(freshSubs);
|
|
657
|
+
if (derived === null) return { cascadedTo, failed };
|
|
658
|
+
|
|
659
|
+
// Defer the all-done case to the legacy DONE-cascade so it
|
|
660
|
+
// owns the Epic exclusion, the tasklist toggle, the progress
|
|
661
|
+
// comment, and the recursive walk that already pin its
|
|
662
|
+
// behaviour via the existing test surface. The closing child's
|
|
663
|
+
// id is taken from `freshSubs` — any DONE child suffices because
|
|
664
|
+
// cascadeCompletion only uses the child to look up its parents.
|
|
665
|
+
if (derived === STATE_LABELS.DONE) {
|
|
666
|
+
const doneChild = freshSubs.find(
|
|
667
|
+
(s) => Array.isArray(s?.labels) && s.labels.includes(STATE_LABELS.DONE),
|
|
668
|
+
);
|
|
669
|
+
if (!doneChild) return { cascadedTo, failed };
|
|
670
|
+
const nested = await cascadeCompletion(provider, doneChild.id, {
|
|
671
|
+
notify: opts.notify,
|
|
672
|
+
_logger: logger,
|
|
673
|
+
});
|
|
674
|
+
cascadedTo.push(...nested.cascadedTo);
|
|
675
|
+
failed.push(...nested.failed);
|
|
676
|
+
return { cascadedTo, failed };
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const parent = await provider.getTicket(parentId);
|
|
680
|
+
const parentLabels = Array.isArray(parent?.labels) ? parent.labels : [];
|
|
681
|
+
const currentState = parentLabels.find((l) => ALL_STATES.includes(l));
|
|
682
|
+
if (currentState === derived) {
|
|
683
|
+
// Idempotency guard — Project board is already in the derived
|
|
684
|
+
// column. Skip the transition entirely so we do not burn a
|
|
685
|
+
// GraphQL write for a no-op.
|
|
686
|
+
return { cascadedTo, failed };
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
await retryTransient(
|
|
690
|
+
() =>
|
|
691
|
+
transitionTicketState(provider, parentId, derived, {
|
|
692
|
+
notify: opts.notify,
|
|
693
|
+
// Recursion is handled explicitly below — passing cascade:false
|
|
694
|
+
// prevents state.js from firing its own cascadeParentState on the
|
|
695
|
+
// parent and double-walking the tree.
|
|
696
|
+
cascade: false,
|
|
697
|
+
}),
|
|
698
|
+
{
|
|
699
|
+
onRetry: (err, attempt, delayMs) => {
|
|
700
|
+
logger.warn(
|
|
701
|
+
`[Ticketing] State cascade to parent #${parentId} hit transient ${err?.name ?? 'error'} ` +
|
|
702
|
+
`(attempt ${attempt}); retrying in ${delayMs}ms. ${formatCascadeError(err)}`,
|
|
703
|
+
);
|
|
704
|
+
},
|
|
705
|
+
},
|
|
706
|
+
);
|
|
707
|
+
cascadedTo.push(parentId);
|
|
708
|
+
|
|
709
|
+
const nested = await cascadeParentState(provider, parentId, {
|
|
710
|
+
notify: opts.notify,
|
|
711
|
+
_logger: logger,
|
|
712
|
+
});
|
|
713
|
+
cascadedTo.push(...nested.cascadedTo);
|
|
714
|
+
failed.push(...nested.failed);
|
|
715
|
+
} catch (err) {
|
|
716
|
+
const detail = formatCascadeError(err);
|
|
717
|
+
failed.push({ parentId, error: detail });
|
|
718
|
+
logger.warn(
|
|
719
|
+
`[Ticketing] State cascade to parent #${parentId} failed: ${detail}`,
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
return { cascadedTo, failed };
|
|
723
|
+
}
|