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,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/findings/route-finding.js — Shared dedup/route helper for findings.
|
|
3
|
+
*
|
|
4
|
+
* This module is the single dedup/route implementation that both
|
|
5
|
+
* `audit-to-stories` and `qa-explore` consume. It does three things:
|
|
6
|
+
*
|
|
7
|
+
* 1. `fingerprintFinding(finding)` — a stable sha1 over the finding's
|
|
8
|
+
* identity fields (`title`, `area`, `primaryFile`, `severity`,
|
|
9
|
+
* `labels`). Two runs over the same finding MUST produce the same
|
|
10
|
+
* sha, and unrelated prose drift MUST NOT change it.
|
|
11
|
+
* 2. `fingerprintFooter(sha)` / `parseFingerprintFooter(body)` — round-trip
|
|
12
|
+
* the machine-readable `<!-- audit-fingerprints: sha,sha,... -->` marker
|
|
13
|
+
* stamped into Issue bodies.
|
|
14
|
+
* 3. `routeFinding(finding, { searchIssues, searchCandidates })` — classify a
|
|
15
|
+
* finding against existing Issues into one of `new | update-existing |
|
|
16
|
+
* duplicate | regression-of-closed`. Routing is a two-stage pass: a
|
|
17
|
+
* meaning-first **semantic candidate** pass runs FIRST (when a
|
|
18
|
+
* `searchCandidates` port is injected, e.g. wired to
|
|
19
|
+
* `semantic-issue-search.js`), then the exact **fingerprint
|
|
20
|
+
* confirmation** pass runs SECOND over that candidate pool. When no
|
|
21
|
+
* semantic port is injected the helper falls back to a fingerprint-only
|
|
22
|
+
* lookup via the `searchIssues` port. Either way the ports query BOTH
|
|
23
|
+
* open and closed issues; a closed fingerprint match yields
|
|
24
|
+
* `regression-of-closed`.
|
|
25
|
+
*
|
|
26
|
+
* Pure orchestration: no network I/O lives here. The `searchIssues` /
|
|
27
|
+
* `searchCandidates` ports are injected by the caller (production wires them
|
|
28
|
+
* to the GitHub provider; tests pass an in-memory stub).
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import crypto from 'node:crypto';
|
|
32
|
+
|
|
33
|
+
const SEP = '␟'; // unit separator — keeps fingerprint fields unambiguous
|
|
34
|
+
const MARKER = 'audit-fingerprints:';
|
|
35
|
+
const SHA1_RE = /^[0-9a-f]{40}$/;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Normalise a single scalar identity field to a stable string.
|
|
39
|
+
* @param {unknown} value
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function normaliseField(value) {
|
|
43
|
+
if (value === null || value === undefined) return '';
|
|
44
|
+
return String(value).toLowerCase().trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Normalise the `labels` array into a stable, order-independent string.
|
|
49
|
+
* @param {unknown} labels
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
function normaliseLabels(labels) {
|
|
53
|
+
if (!Array.isArray(labels)) return '';
|
|
54
|
+
return labels
|
|
55
|
+
.map((l) => normaliseField(l))
|
|
56
|
+
.filter((l) => l.length > 0)
|
|
57
|
+
.sort()
|
|
58
|
+
.join(',');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Compute the stable identity payload for a finding.
|
|
63
|
+
* @param {object} finding
|
|
64
|
+
* @returns {{ title: string, area: string, primaryFile: string, severity: string, labels: string }}
|
|
65
|
+
*/
|
|
66
|
+
function fingerprintComponents(finding) {
|
|
67
|
+
return {
|
|
68
|
+
title: normaliseField(finding?.title),
|
|
69
|
+
area: normaliseField(finding?.area),
|
|
70
|
+
primaryFile: normaliseField(finding?.primaryFile),
|
|
71
|
+
severity: normaliseField(finding?.severity),
|
|
72
|
+
labels: normaliseLabels(finding?.labels),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Stable per-finding fingerprint over {title, area, primaryFile, severity, labels}.
|
|
78
|
+
*
|
|
79
|
+
* @param {object} finding
|
|
80
|
+
* @returns {{ short: string, full: string, components: object }}
|
|
81
|
+
*/
|
|
82
|
+
export function fingerprintFinding(finding) {
|
|
83
|
+
const components = fingerprintComponents(finding);
|
|
84
|
+
const payload = [
|
|
85
|
+
components.title,
|
|
86
|
+
components.area,
|
|
87
|
+
components.primaryFile,
|
|
88
|
+
components.severity,
|
|
89
|
+
components.labels,
|
|
90
|
+
].join(SEP);
|
|
91
|
+
const full = crypto.createHash('sha1').update(payload).digest('hex');
|
|
92
|
+
return { short: full.slice(0, 12), full, components };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Render the machine-readable fingerprint footer for one or more shas.
|
|
97
|
+
*
|
|
98
|
+
* Accepts either a single 40-char sha1 or an array of them, so a footer
|
|
99
|
+
* can carry every finding sha that a grouped Issue tracks
|
|
100
|
+
* (`<!-- audit-fingerprints: sha,sha,... -->`). The comma-joined form
|
|
101
|
+
* round-trips through {@link parseFingerprintFooter}. This is the single
|
|
102
|
+
* footer renderer shared by `audit-to-stories` and `qa-explore`; neither
|
|
103
|
+
* consumer defines its own marker.
|
|
104
|
+
*
|
|
105
|
+
* @param {string | string[]} shas — full 40-char sha1, or an array of them.
|
|
106
|
+
* @returns {string}
|
|
107
|
+
*/
|
|
108
|
+
export function fingerprintFooter(shas) {
|
|
109
|
+
const list = Array.isArray(shas) ? shas : [shas];
|
|
110
|
+
for (const sha of list) {
|
|
111
|
+
if (typeof sha !== 'string' || !SHA1_RE.test(sha)) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
'fingerprintFooter: every sha must be a 40-char sha1 hex string',
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return `<!-- ${MARKER} ${list.join(',')} -->`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract fingerprint sha1s from an Issue body carrying the footer marker.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} body
|
|
124
|
+
* @returns {string[]}
|
|
125
|
+
*/
|
|
126
|
+
export function parseFingerprintFooter(body) {
|
|
127
|
+
if (typeof body !== 'string') return [];
|
|
128
|
+
const match = body.match(/<!--\s*audit-fingerprints:\s*([^>]+?)\s*-->/);
|
|
129
|
+
if (!match) return [];
|
|
130
|
+
return match[1]
|
|
131
|
+
.split(',')
|
|
132
|
+
.map((s) => s.trim())
|
|
133
|
+
.filter((s) => SHA1_RE.test(s));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Confirm an issue body's footer actually carries the target sha. Guards
|
|
138
|
+
* against a false-positive search hit (e.g. a body that mentions the sha in
|
|
139
|
+
* prose rather than in the fingerprint footer).
|
|
140
|
+
*
|
|
141
|
+
* @param {{ body?: string }} issue
|
|
142
|
+
* @param {string} sha
|
|
143
|
+
* @returns {boolean}
|
|
144
|
+
*/
|
|
145
|
+
function issueCarriesFingerprint(issue, sha) {
|
|
146
|
+
if (typeof issue?.body !== 'string') return true;
|
|
147
|
+
return parseFingerprintFooter(issue.body).includes(sha);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Decide the route decision from a confirmed matched issue's state.
|
|
152
|
+
* @param {{ state?: string }} issue
|
|
153
|
+
* @returns {'update-existing'|'regression-of-closed'}
|
|
154
|
+
*/
|
|
155
|
+
function decisionForIssue(issue) {
|
|
156
|
+
const state = normaliseField(issue?.state);
|
|
157
|
+
return state === 'closed' ? 'regression-of-closed' : 'update-existing';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Decide the final route from a confirmed-match pool (issues that both
|
|
162
|
+
* surfaced in the candidate/search pass AND carry the finding's fingerprint
|
|
163
|
+
* in their footer). Shared by both the semantic-first and fingerprint-only
|
|
164
|
+
* code paths so the decision enum is identical regardless of how candidates
|
|
165
|
+
* were gathered.
|
|
166
|
+
*
|
|
167
|
+
* @param {Array<{ number: number, state: string }>} confirmed
|
|
168
|
+
* @param {string} sha
|
|
169
|
+
* @returns {{ decision: 'new'|'update-existing'|'duplicate'|'regression-of-closed', matchedIssue: object|null, fingerprint: string }}
|
|
170
|
+
*/
|
|
171
|
+
function decideFromConfirmed(confirmed, sha) {
|
|
172
|
+
if (confirmed.length === 0) {
|
|
173
|
+
return { decision: 'new', matchedIssue: null, fingerprint: sha };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const open = confirmed.filter((h) => normaliseField(h.state) === 'open');
|
|
177
|
+
if (open.length > 1) {
|
|
178
|
+
return { decision: 'duplicate', matchedIssue: open[0], fingerprint: sha };
|
|
179
|
+
}
|
|
180
|
+
if (open.length === 1) {
|
|
181
|
+
return {
|
|
182
|
+
decision: 'update-existing',
|
|
183
|
+
matchedIssue: open[0],
|
|
184
|
+
fingerprint: sha,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const closed = confirmed[0];
|
|
189
|
+
return {
|
|
190
|
+
decision: decisionForIssue(closed),
|
|
191
|
+
matchedIssue: closed,
|
|
192
|
+
fingerprint: sha,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Keep only the issue records that have the right wire shape AND carry the
|
|
198
|
+
* target fingerprint in their footer. A semantic candidate that merely *looks*
|
|
199
|
+
* similar but does not carry the sha is dropped here — semantic similarity
|
|
200
|
+
* widens the net; the fingerprint footer is what confirms identity.
|
|
201
|
+
*
|
|
202
|
+
* @param {Array<unknown>} hits
|
|
203
|
+
* @param {string} sha
|
|
204
|
+
* @returns {Array<{ number: number, state: string }>}
|
|
205
|
+
*/
|
|
206
|
+
function confirmFingerprint(hits, sha) {
|
|
207
|
+
if (!Array.isArray(hits)) return [];
|
|
208
|
+
return hits.filter(
|
|
209
|
+
(h) =>
|
|
210
|
+
h &&
|
|
211
|
+
typeof h.number === 'number' &&
|
|
212
|
+
typeof h.state === 'string' &&
|
|
213
|
+
issueCarriesFingerprint(h, sha),
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Route a finding against existing Issues with a two-stage pass.
|
|
219
|
+
*
|
|
220
|
+
* **Stage 1 — semantic candidate search (first).** When a `searchCandidates`
|
|
221
|
+
* port is injected, it runs first to surface issues that *describe the same
|
|
222
|
+
* problem by meaning* across BOTH open and closed issues (and, when the
|
|
223
|
+
* caller wires it, an Epic's sub-issues). This widens the net beyond an exact
|
|
224
|
+
* fingerprint so a reworded title or a moved file does not hide a real
|
|
225
|
+
* duplicate. When no `searchCandidates` port is supplied the helper skips
|
|
226
|
+
* straight to Stage 2 over the `searchIssues` lookup — the legacy
|
|
227
|
+
* fingerprint-only behaviour, preserved verbatim.
|
|
228
|
+
*
|
|
229
|
+
* **Stage 2 — fingerprint confirmation (second).** Whatever candidates Stage 1
|
|
230
|
+
* produced are filtered down to those that actually carry the finding's
|
|
231
|
+
* fingerprint footer, then resolved:
|
|
232
|
+
* - An open match → `update-existing` (or `duplicate` when more than one
|
|
233
|
+
* open issue carries the fingerprint).
|
|
234
|
+
* - A closed match (no open match) → `regression-of-closed`.
|
|
235
|
+
* - No confirmed match → `new`.
|
|
236
|
+
*
|
|
237
|
+
* The decision enum is identical on both paths.
|
|
238
|
+
*
|
|
239
|
+
* @param {object} finding
|
|
240
|
+
* @param {object} ports
|
|
241
|
+
* @param {(sha: string) => Promise<Array<{ number: number, state: string, body?: string }>>} [ports.searchIssues]
|
|
242
|
+
* Fingerprint-keyed lookup over open+closed issues. Required when
|
|
243
|
+
* `searchCandidates` is not supplied.
|
|
244
|
+
* @param {(finding: object) => Promise<Array<{ number: number, state: string, title?: string, body?: string }>>} [ports.searchCandidates]
|
|
245
|
+
* Meaning-first candidate search over open+closed issues (and Epic
|
|
246
|
+
* sub-issues). When supplied, runs FIRST; its candidates are then
|
|
247
|
+
* fingerprint-confirmed.
|
|
248
|
+
* @returns {Promise<{ decision: 'new'|'update-existing'|'duplicate'|'regression-of-closed', matchedIssue: object|null, fingerprint: string }>}
|
|
249
|
+
*/
|
|
250
|
+
export async function routeFinding(
|
|
251
|
+
finding,
|
|
252
|
+
{ searchIssues, searchCandidates } = {},
|
|
253
|
+
) {
|
|
254
|
+
if (
|
|
255
|
+
typeof searchCandidates !== 'function' &&
|
|
256
|
+
typeof searchIssues !== 'function'
|
|
257
|
+
) {
|
|
258
|
+
throw new Error(
|
|
259
|
+
'routeFinding: a searchCandidates or searchIssues port is required',
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const { full: sha } = fingerprintFinding(finding);
|
|
264
|
+
|
|
265
|
+
// Stage 1: semantic candidate pass first (when wired); else fingerprint
|
|
266
|
+
// lookup. Both yield a candidate pool drawn from open AND closed issues.
|
|
267
|
+
const hits =
|
|
268
|
+
typeof searchCandidates === 'function'
|
|
269
|
+
? await searchCandidates(finding)
|
|
270
|
+
: await searchIssues(sha);
|
|
271
|
+
|
|
272
|
+
// Stage 2: confirm identity by fingerprint footer over the candidate pool.
|
|
273
|
+
const confirmed = confirmFingerprint(hits, sha);
|
|
274
|
+
|
|
275
|
+
return decideFromConfirmed(confirmed, sha);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export const __testing = {
|
|
279
|
+
MARKER,
|
|
280
|
+
SEP,
|
|
281
|
+
confirmFingerprint,
|
|
282
|
+
decideFromConfirmed,
|
|
283
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/findings/semantic-issue-search.js — Semantic candidate search for findings.
|
|
3
|
+
*
|
|
4
|
+
* Dedup has two stages. This module owns the **first** stage: a meaning-first
|
|
5
|
+
* candidate search that surfaces issues likely to describe the same problem as
|
|
6
|
+
* a finding, *before* the exact fingerprint confirmation in
|
|
7
|
+
* `route-finding.js` runs. The fingerprint is precise but brittle — a reworded
|
|
8
|
+
* title or a moved file produces a fresh sha even when the underlying problem
|
|
9
|
+
* is the same. The semantic pass casts a wider net so the confirmation stage
|
|
10
|
+
* has the right candidates to inspect.
|
|
11
|
+
*
|
|
12
|
+
* The search scans BOTH open and closed issues, and explicitly includes the
|
|
13
|
+
* sub-issues of any in-scope Epic (a regression that was closed under a prior
|
|
14
|
+
* Epic, or a still-open sibling Story, must be reachable). Epic sub-issues are
|
|
15
|
+
* fetched through the same injected port so a closed-then-reopened problem is
|
|
16
|
+
* never missed.
|
|
17
|
+
*
|
|
18
|
+
* Pure orchestration: no network I/O lives here. The `search` port — and the
|
|
19
|
+
* optional `listEpicSubIssues` port — are injected by the caller (production
|
|
20
|
+
* wires them to the GitHub provider; tests pass in-memory stubs). The unit
|
|
21
|
+
* test for this module performs no network calls.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const DEFAULT_LIMIT = 25;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalise a free-text string for token comparison: lowercased, trimmed,
|
|
28
|
+
* punctuation collapsed to spaces.
|
|
29
|
+
* @param {unknown} value
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
function normaliseText(value) {
|
|
33
|
+
if (value === null || value === undefined) return '';
|
|
34
|
+
return String(value)
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^a-z0-9]+/g, ' ')
|
|
37
|
+
.trim();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Tokenise normalised text into a Set of words, dropping very short noise
|
|
42
|
+
* tokens that carry no discriminating signal.
|
|
43
|
+
* @param {string} text
|
|
44
|
+
* @returns {Set<string>}
|
|
45
|
+
*/
|
|
46
|
+
function tokenize(text) {
|
|
47
|
+
return new Set(
|
|
48
|
+
normaliseText(text)
|
|
49
|
+
.split(' ')
|
|
50
|
+
.filter((t) => t.length >= 2),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Jaccard similarity between two token sets. Returns 0 when either set is
|
|
56
|
+
* empty so an empty query never spuriously matches.
|
|
57
|
+
* @param {Set<string>} a
|
|
58
|
+
* @param {Set<string>} b
|
|
59
|
+
* @returns {number} similarity in [0, 1]
|
|
60
|
+
*/
|
|
61
|
+
function jaccard(a, b) {
|
|
62
|
+
if (a.size === 0 || b.size === 0) return 0;
|
|
63
|
+
let intersection = 0;
|
|
64
|
+
for (const token of a) {
|
|
65
|
+
if (b.has(token)) intersection += 1;
|
|
66
|
+
}
|
|
67
|
+
const union = a.size + b.size - intersection;
|
|
68
|
+
return union === 0 ? 0 : intersection / union;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build the search query text for a finding. The title carries the strongest
|
|
73
|
+
* signal; area and primaryFile sharpen it. This is the text both the
|
|
74
|
+
* (production) full-text search port and the local relevance scorer key on.
|
|
75
|
+
* @param {object} finding
|
|
76
|
+
* @returns {string}
|
|
77
|
+
*/
|
|
78
|
+
export function buildQuery(finding) {
|
|
79
|
+
return [finding?.title, finding?.area, finding?.primaryFile]
|
|
80
|
+
.map((v) => normaliseText(v))
|
|
81
|
+
.filter((v) => v.length > 0)
|
|
82
|
+
.join(' ');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Score a candidate issue against the finding's query tokens. Title overlap
|
|
87
|
+
* dominates; body overlap is a weaker secondary signal so a verbose body
|
|
88
|
+
* cannot drown out a precise title match.
|
|
89
|
+
* @param {Set<string>} queryTokens
|
|
90
|
+
* @param {{ title?: string, body?: string }} issue
|
|
91
|
+
* @returns {number} relevance score in [0, 1]
|
|
92
|
+
*/
|
|
93
|
+
function scoreIssue(queryTokens, issue) {
|
|
94
|
+
const titleScore = jaccard(queryTokens, tokenize(issue?.title));
|
|
95
|
+
const bodyScore = jaccard(queryTokens, tokenize(issue?.body));
|
|
96
|
+
return titleScore * 0.75 + bodyScore * 0.25;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* De-duplicate issue records by `number`, keeping the first occurrence.
|
|
101
|
+
* @param {Array<{ number?: number }>} issues
|
|
102
|
+
* @returns {Array<object>}
|
|
103
|
+
*/
|
|
104
|
+
function dedupeByNumber(issues) {
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
const out = [];
|
|
107
|
+
for (const issue of issues) {
|
|
108
|
+
const number = issue?.number;
|
|
109
|
+
if (typeof number !== 'number' || seen.has(number)) continue;
|
|
110
|
+
seen.add(number);
|
|
111
|
+
out.push(issue);
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Find semantically-similar candidate issues for a finding.
|
|
118
|
+
*
|
|
119
|
+
* The `search` port runs the host's issue search (production: GitHub
|
|
120
|
+
* full-text search across open AND closed issues). When an `epicId` is in
|
|
121
|
+
* scope and a `listEpicSubIssues` port is supplied, that Epic's sub-issues
|
|
122
|
+
* are folded into the candidate pool so a regression closed under a prior
|
|
123
|
+
* Epic — or an open sibling Story — is never missed. The pooled candidates
|
|
124
|
+
* are scored locally by token overlap and returned best-first.
|
|
125
|
+
*
|
|
126
|
+
* @param {object} finding — canonical finding ({ title, area, primaryFile, ... }).
|
|
127
|
+
* @param {object} ports
|
|
128
|
+
* @param {(query: string) => Promise<Array<{ number: number, state: string, title?: string, body?: string }>>} ports.search
|
|
129
|
+
* Required. Queries both open and closed issues for the finding's query text.
|
|
130
|
+
* @param {(epicId: number) => Promise<Array<{ number: number, state: string, title?: string, body?: string }>>} [ports.listEpicSubIssues]
|
|
131
|
+
* Optional. Lists the sub-issues of the in-scope Epic.
|
|
132
|
+
* @param {object} [options]
|
|
133
|
+
* @param {number|null} [options.epicId] — Epic whose sub-issues to include.
|
|
134
|
+
* @param {number} [options.limit] — max candidates to return (default 25).
|
|
135
|
+
* @param {number} [options.minScore] — drop candidates scoring below this
|
|
136
|
+
* (default 0; every scanned issue is a candidate).
|
|
137
|
+
* @returns {Promise<Array<{ number: number, state: string, title?: string, body?: string, score: number }>>}
|
|
138
|
+
* candidates sorted by descending relevance score.
|
|
139
|
+
*/
|
|
140
|
+
export async function searchSemanticCandidates(
|
|
141
|
+
finding,
|
|
142
|
+
ports = {},
|
|
143
|
+
options = {},
|
|
144
|
+
) {
|
|
145
|
+
const { search, listEpicSubIssues } = ports;
|
|
146
|
+
if (typeof search !== 'function') {
|
|
147
|
+
throw new Error('searchSemanticCandidates: search port is required');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const { epicId = null, limit = DEFAULT_LIMIT, minScore = 0 } = options;
|
|
151
|
+
|
|
152
|
+
const query = buildQuery(finding);
|
|
153
|
+
const queryTokens = tokenize(query);
|
|
154
|
+
|
|
155
|
+
const pool = [];
|
|
156
|
+
|
|
157
|
+
const searchHits = await search(query);
|
|
158
|
+
if (Array.isArray(searchHits)) pool.push(...searchHits);
|
|
159
|
+
|
|
160
|
+
if (epicId != null && typeof listEpicSubIssues === 'function') {
|
|
161
|
+
const subIssues = await listEpicSubIssues(epicId);
|
|
162
|
+
if (Array.isArray(subIssues)) pool.push(...subIssues);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const candidates = dedupeByNumber(pool).filter(
|
|
166
|
+
(issue) =>
|
|
167
|
+
issue &&
|
|
168
|
+
typeof issue.number === 'number' &&
|
|
169
|
+
typeof issue.state === 'string',
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return candidates
|
|
173
|
+
.map((issue) => ({ ...issue, score: scoreIssue(queryTokens, issue) }))
|
|
174
|
+
.filter((issue) => issue.score >= minScore)
|
|
175
|
+
.sort((a, b) => b.score - a.score)
|
|
176
|
+
.slice(0, limit);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const __testing = { tokenize, jaccard, scoreIssue, dedupeByNumber };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/findings/severity.js — Canonical severity vocabulary for the findings core.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for finding severity (Story #3816). Three modules in
|
|
5
|
+
* the shared findings core previously each declared their own severity list —
|
|
6
|
+
* `classify-finding.js` (`[unknown, low, medium, high, critical]`),
|
|
7
|
+
* `promote-finding.js` (`SEVERITY_RANK` over `[critical … info]`), and the
|
|
8
|
+
* `qa-finding` / `qa-ledger` JSON schemas (`[critical, high, medium, low,
|
|
9
|
+
* info]`). Because `severity` is a `fingerprintFinding` identity field
|
|
10
|
+
* (`route-finding.js`), the same finding could hash to different SHAs depending
|
|
11
|
+
* on which path normalised its severity, silently weakening dedup. This module
|
|
12
|
+
* collapses all three onto one enum + one normaliser so the fingerprint is
|
|
13
|
+
* stable regardless of the code path that produced the severity.
|
|
14
|
+
*
|
|
15
|
+
* The canonical order is `critical | high | medium | low | info`, highest →
|
|
16
|
+
* lowest, and it MUST match the `severity` enum in
|
|
17
|
+
* `.agents/schemas/qa-ledger.schema.json` (and the mirrored `qa-finding`
|
|
18
|
+
* schema). Pure module: no I/O, no module-level state beyond the frozen
|
|
19
|
+
* constants.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The closed, canonical set of severity values, ordered highest → lowest.
|
|
24
|
+
* This is the ONLY definition of the severity vocabulary in the findings core;
|
|
25
|
+
* `classify-finding.js` and `promote-finding.js` re-export / import it rather
|
|
26
|
+
* than re-declaring their own list. Mirrors the `severity` enum in
|
|
27
|
+
* `qa-ledger.schema.json` / `qa-finding.schema.json`.
|
|
28
|
+
*/
|
|
29
|
+
export const SEVERITIES = Object.freeze([
|
|
30
|
+
'critical',
|
|
31
|
+
'high',
|
|
32
|
+
'medium',
|
|
33
|
+
'low',
|
|
34
|
+
'info',
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The severity applied when a finding carries no recognisable severity. `info`
|
|
39
|
+
* is the canonical floor (lowest level). The ledger/finding schemas REQUIRE a
|
|
40
|
+
* severity drawn from {@link SEVERITIES}, so this fallback only fires on
|
|
41
|
+
* malformed input — and because both the classify and promote paths share it,
|
|
42
|
+
* malformed input still fingerprints identically across the two paths.
|
|
43
|
+
*/
|
|
44
|
+
export const DEFAULT_SEVERITY = 'info';
|
|
45
|
+
|
|
46
|
+
const SEVERITY_SET = new Set(SEVERITIES);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Numeric rank for "highest severity wins" comparisons, derived from the
|
|
50
|
+
* canonical order so the ranking has exactly one source. `critical` is the
|
|
51
|
+
* highest rank (`SEVERITIES.length - 1`); `info` is `0`.
|
|
52
|
+
*
|
|
53
|
+
* @type {Readonly<Record<string, number>>}
|
|
54
|
+
*/
|
|
55
|
+
export const SEVERITY_RANK = Object.freeze(
|
|
56
|
+
Object.fromEntries(
|
|
57
|
+
SEVERITIES.map((severity, index) => [
|
|
58
|
+
severity,
|
|
59
|
+
SEVERITIES.length - 1 - index,
|
|
60
|
+
]),
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Normalise an arbitrary severity input to one of {@link SEVERITIES}. Case- and
|
|
66
|
+
* whitespace-insensitive. A non-string, empty, or unrecognised value resolves
|
|
67
|
+
* to `fallback` (default {@link DEFAULT_SEVERITY}) rather than throwing — the
|
|
68
|
+
* findings pipeline treats severity as advisory signal, never a hard gate.
|
|
69
|
+
*
|
|
70
|
+
* @param {unknown} value — the raw severity field off a finding/ledger item.
|
|
71
|
+
* @param {string} [fallback=DEFAULT_SEVERITY] — canonical value to return when
|
|
72
|
+
* `value` is absent or unrecognised.
|
|
73
|
+
* @returns {string} one of {@link SEVERITIES}.
|
|
74
|
+
*/
|
|
75
|
+
export function normalizeSeverity(value, fallback = DEFAULT_SEVERITY) {
|
|
76
|
+
if (typeof value !== 'string') return fallback;
|
|
77
|
+
const normalized = value.trim().toLowerCase();
|
|
78
|
+
return SEVERITY_SET.has(normalized) ? normalized : fallback;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The highest-ranked severity across a list of raw severity values. Returns
|
|
83
|
+
* {@link DEFAULT_SEVERITY} for an empty list. Each value is normalised through
|
|
84
|
+
* {@link normalizeSeverity}, so the result is always one of {@link SEVERITIES}.
|
|
85
|
+
*
|
|
86
|
+
* @param {Iterable<unknown>} values — raw severity strings (or anything
|
|
87
|
+
* `normalizeSeverity` accepts).
|
|
88
|
+
* @returns {string} one of {@link SEVERITIES}.
|
|
89
|
+
*/
|
|
90
|
+
export function highestSeverity(values) {
|
|
91
|
+
let best = DEFAULT_SEVERITY;
|
|
92
|
+
let bestRank = -1;
|
|
93
|
+
for (const value of values) {
|
|
94
|
+
const severity = normalizeSeverity(value);
|
|
95
|
+
const rank = SEVERITY_RANK[severity];
|
|
96
|
+
if (rank > bestRank) {
|
|
97
|
+
bestRank = rank;
|
|
98
|
+
best = severity;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return best;
|
|
102
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-I/O baseline-JSON store: encapsulates the Story #1120 `--epic-ref`
|
|
3
|
+
* fallback chain (try `readAtRef` → fall back to fs with a warning) and
|
|
4
|
+
* an atomic tmp-rename write. Shape validation stays in each gate.
|
|
5
|
+
* Missing files throw `BaselineNotFoundError`; write failures throw
|
|
6
|
+
* `BaselineWriteError` — no swallowing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { readBaselineAtRef as defaultReadAtRef } from '../baseline-loader.js';
|
|
12
|
+
import { Logger } from '../Logger.js';
|
|
13
|
+
|
|
14
|
+
export class BaselineNotFoundError extends Error {
|
|
15
|
+
constructor(message, details = {}) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'BaselineNotFoundError';
|
|
18
|
+
Object.assign(this, details);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class BaselineWriteError extends Error {
|
|
23
|
+
constructor(message, details = {}) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = 'BaselineWriteError';
|
|
26
|
+
Object.assign(this, details);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function absPath(baselinePath, projectRoot) {
|
|
31
|
+
if (typeof baselinePath !== 'string' || baselinePath.length === 0) {
|
|
32
|
+
throw new TypeError('[baseline-store] baselinePath is required');
|
|
33
|
+
}
|
|
34
|
+
return path.isAbsolute(baselinePath)
|
|
35
|
+
? baselinePath
|
|
36
|
+
: path.resolve(projectRoot ?? process.cwd(), baselinePath);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Default working-tree reader. Throws `BaselineNotFoundError` when absent.
|
|
40
|
+
function defaultReadFromTree({ baselinePath, projectRoot } = {}) {
|
|
41
|
+
const abs = absPath(baselinePath, projectRoot);
|
|
42
|
+
if (!fs.existsSync(abs)) {
|
|
43
|
+
throw new BaselineNotFoundError(`baseline not found at ${baselinePath}`, {
|
|
44
|
+
path: abs,
|
|
45
|
+
baselinePath,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return JSON.parse(fs.readFileSync(abs, 'utf8'));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load a baseline JSON file with the Story #1120 `--epic-ref` fallback
|
|
53
|
+
* chain. Gates may supply a `readFromTree` to preserve a "missing →
|
|
54
|
+
* empty" bootstrap (e.g. MI returns `{}`); otherwise the default throws
|
|
55
|
+
* `BaselineNotFoundError`.
|
|
56
|
+
*/
|
|
57
|
+
export function loadBaseline({
|
|
58
|
+
baselinePath,
|
|
59
|
+
epicRef = null,
|
|
60
|
+
projectRoot,
|
|
61
|
+
readAtRef = defaultReadAtRef,
|
|
62
|
+
readFromTree = defaultReadFromTree,
|
|
63
|
+
logger = Logger,
|
|
64
|
+
label = 'baseline-store',
|
|
65
|
+
} = {}) {
|
|
66
|
+
if (epicRef) {
|
|
67
|
+
try {
|
|
68
|
+
const parsed = readAtRef(epicRef, baselinePath);
|
|
69
|
+
if (parsed !== null && parsed !== undefined) return parsed;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
logger.warn(
|
|
72
|
+
`[${label}] ⚠ failed to read baseline at ref "${epicRef}": ${err?.message ?? err}. Falling back to working-tree read.`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return readFromTree({ baselinePath, projectRoot });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Atomic write via temp-file + rename. 2-space indent + trailing newline.
|
|
81
|
+
*/
|
|
82
|
+
export function writeBaseline({
|
|
83
|
+
baselinePath,
|
|
84
|
+
data,
|
|
85
|
+
projectRoot,
|
|
86
|
+
indent = 2,
|
|
87
|
+
} = {}) {
|
|
88
|
+
const abs = absPath(baselinePath, projectRoot);
|
|
89
|
+
const tmp = `${abs}.tmp`;
|
|
90
|
+
try {
|
|
91
|
+
const serialised = `${JSON.stringify(data, null, indent)}\n`;
|
|
92
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
93
|
+
fs.writeFileSync(tmp, serialised, 'utf8');
|
|
94
|
+
fs.renameSync(tmp, abs);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
try {
|
|
97
|
+
fs.rmSync(tmp, { force: true });
|
|
98
|
+
} catch {
|
|
99
|
+
/* best-effort cleanup */
|
|
100
|
+
}
|
|
101
|
+
throw new BaselineWriteError(
|
|
102
|
+
`[baseline-store] failed to write baseline at ${baselinePath}: ${err?.message ?? err}`,
|
|
103
|
+
{ path: abs, cause: err },
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|