mandrel 1.93.0 → 2.0.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 +59 -73
- package/.agents/agents/acceptance-critic.md +129 -0
- package/.agents/agents/story-worker.md +161 -0
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +108 -136
- package/.agents/docs/execution-reference.md +44 -22
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +107 -108
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +224 -0
- package/.agents/rules/git-conventions.md +42 -223
- package/.agents/rules/security-baseline.md +5 -0
- package/.agents/rules/testing-standards.md +106 -13
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +71 -201
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/risk-verdict.schema.json +0 -13
- package/.agents/scripts/acceptance-eval.js +62 -18
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/analyze-execution.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/check-context-budget.js +62 -5
- package/.agents/scripts/check-lifecycle-lint.js +6 -9
- package/.agents/scripts/check-prepush-recovery.js +1 -1
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/diagnose-friction.js +0 -6
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
- package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
- package/.agents/scripts/lib/checks/index.js +2 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +16 -7
- package/.agents/scripts/lib/close-validation/gates.js +160 -22
- package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +103 -0
- package/.agents/scripts/lib/config/explain.js +57 -36
- package/.agents/scripts/lib/config/limits.js +17 -58
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +1 -1
- package/.agents/scripts/lib/config/runners.js +17 -50
- package/.agents/scripts/lib/config/temp-paths.js +19 -14
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +3 -8
- package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
- package/.agents/scripts/lib/config-settings-schema.js +52 -38
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +39 -4
- package/.agents/scripts/lib/duplicate-search.js +211 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +5 -5
- package/.agents/scripts/lib/framework-version.js +2 -3
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
- package/.agents/scripts/lib/git-utils.js +32 -6
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/label-constants.js +10 -23
- package/.agents/scripts/lib/label-taxonomy.js +9 -43
- package/.agents/scripts/lib/observability/active-story-env.js +112 -3
- package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
- package/.agents/scripts/lib/orchestration/code-review.js +20 -268
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
- package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
- package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
- package/.agents/scripts/lib/planning-corpus.js +16 -11
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/provider-factory.js +1 -1
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/story-adjacency.js +11 -14
- package/.agents/scripts/lib/story-body/story-body.js +124 -70
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
- package/.agents/scripts/lib/validation-evidence.js +1 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +64 -74
- package/.agents/scripts/plan-persist.js +121 -280
- package/.agents/scripts/plan-run-epilogue.js +97 -0
- package/.agents/scripts/post-structured-comment.js +38 -0
- package/.agents/scripts/providers/github/issues.js +17 -33
- package/.agents/scripts/providers/github/mappers.js +0 -12
- package/.agents/scripts/providers/github/tickets.js +2 -5
- package/.agents/scripts/resolve-plan-run.js +117 -0
- package/.agents/scripts/signals-view.js +24 -19
- package/.agents/scripts/single-story-close.js +11 -14
- package/.agents/scripts/single-story-confirm-merge.js +39 -23
- package/.agents/scripts/single-story-init.js +29 -20
- package/.agents/scripts/stories-wave-tick.js +6 -6
- package/.agents/scripts/story-plan.js +26 -47
- package/.agents/scripts/sync-claude-agents.js +165 -0
- package/.agents/scripts/update-ticket-state.js +37 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
- package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +8 -418
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +3 -3
- package/.agents/workflows/audit-clean-code.md +3 -3
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +5 -5
- package/.agents/workflows/audit-lighthouse.md +3 -3
- package/.agents/workflows/audit-navigability.md +3 -2
- package/.agents/workflows/audit-performance.md +3 -3
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +3 -3
- package/.agents/workflows/audit-security.md +3 -3
- package/.agents/workflows/audit-seo.md +3 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +3 -3
- package/.agents/workflows/deliver.md +122 -131
- package/.agents/workflows/git-cleanup.md +3 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
- package/.agents/workflows/helpers/code-review.md +70 -193
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
- package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
- package/.agents/workflows/mandrel-update.md +3 -2
- package/.agents/workflows/plan.md +112 -145
- package/.agents/workflows/qa-assist.md +24 -30
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -2
- package/README.md +9 -8
- package/docs/CHANGELOG.md +46 -0
- package/lib/cli/registry.js +95 -0
- package/lib/migrations/index.js +6 -5
- package/package.json +5 -3
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer-mobile.md +0 -120
- package/.agents/personas/engineer-web.md +0 -111
- package/.agents/personas/engineer.md +0 -119
- package/.agents/personas/product.md +0 -94
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/refactorer.md +0 -113
- package/.agents/personas/security-engineer.md +0 -112
- package/.agents/personas/sre.md +0 -86
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/personas/ux-designer.md +0 -95
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -590
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-decompose.js +0 -54
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-plan-spec.js +0 -64
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/plan-critics.js +0 -199
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -335
- package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
- package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
- package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
- package/.agents/skills/core/code-simplification/SKILL.md +0 -389
- package/.agents/skills/core/context-engineering/SKILL.md +0 -309
- package/.agents/skills/core/context-engineering/examples.md +0 -58
- package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
- package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
- package/.agents/skills/core/idea-refinement/examples.md +0 -437
- package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
- package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
- package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
- package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
- package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
- package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
- package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
- package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
- package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
- package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
- package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
- package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
- package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
- package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
- package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
- package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
- package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
- package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
- package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
- package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
- package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
- package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
- package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
- package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
- package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
- package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
- package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
- package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
- package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
- package/.agents/workflows/helpers/deliver-epic.md +0 -955
- package/.agents/workflows/helpers/deliver-stories.md +0 -440
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -351
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* progress-reporter/signals.js — parsing and aggregation helpers for the
|
|
3
|
-
* `story-run-progress` and `phase-timings` structured comments.
|
|
4
|
-
*
|
|
5
|
-
* Extracted from the parent `progress-reporter.js` so the aggregator
|
|
6
|
-
* surface (phase percentile rollups, story-run-progress parsing) is
|
|
7
|
-
* testable independently of the comment composition (`composition.js`)
|
|
8
|
-
* and webhook transport (`transport.js`). Pure functions only — no
|
|
9
|
-
* provider calls, no I/O — which makes this the natural home for the
|
|
10
|
-
* shared state lookup tables (`PHASE_TO_STATE`, `PHASE_ORDER`,
|
|
11
|
-
* `STATE_EMOJI`) and the structured-comment kind constants.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { parseFencedJsonComment } from '../../structured-comment-parser.js';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Structured-comment kind for the rolled-up Epic-level progress
|
|
18
|
-
* comment. Persisted via `composition.upsertEpicRunProgress` and read
|
|
19
|
-
* back by tests + reconcilers.
|
|
20
|
-
*/
|
|
21
|
-
export const EPIC_RUN_PROGRESS_TYPE = 'epic-run-progress';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Structured-comment kind for the per-Story phase-timings summary
|
|
25
|
-
* posted by `story-close.js`. Read back by the ProgressReporter so the
|
|
26
|
-
* Epic-level snapshot can aggregate median/p95 across waves.
|
|
27
|
-
*/
|
|
28
|
-
export const PHASE_TIMINGS_TYPE = 'phase-timings';
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Structured-comment kind for the per-Story run-progress snapshot that
|
|
32
|
-
* `/deliver` upserts on every Task transition. Read by
|
|
33
|
-
* ProgressReporter so the Epic-level table reflects sub-agent state in
|
|
34
|
-
* near-real time instead of label-derived classifications.
|
|
35
|
-
*/
|
|
36
|
-
export const STORY_RUN_PROGRESS_TYPE = 'story-run-progress';
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Phase → high-level state classification. Lookup table flattens the
|
|
40
|
-
* previous switch so cyclomatic complexity stays at 1 (one branch in the
|
|
41
|
-
* `??` fallback) rather than 6 — keeps the CRAP score floor-bound under
|
|
42
|
-
* coverage variance.
|
|
43
|
-
*/
|
|
44
|
-
export const PHASE_TO_STATE = {
|
|
45
|
-
done: 'done',
|
|
46
|
-
blocked: 'blocked',
|
|
47
|
-
implementing: 'in-flight',
|
|
48
|
-
closing: 'in-flight',
|
|
49
|
-
init: 'queued',
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Fixed ordering for the rendered phase-timings table. Matches the enum
|
|
54
|
-
* in lib/util/phase-timer.js so rows line up with how operators think
|
|
55
|
-
* about the story lifecycle rather than re-sorting by alphabet or
|
|
56
|
-
* frequency.
|
|
57
|
-
*/
|
|
58
|
-
export const PHASE_ORDER = [
|
|
59
|
-
'worktree-create',
|
|
60
|
-
'bootstrap',
|
|
61
|
-
'install',
|
|
62
|
-
'implement',
|
|
63
|
-
'lint',
|
|
64
|
-
'test',
|
|
65
|
-
'close',
|
|
66
|
-
'api-sync',
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Emoji prefix per high-level state. Consumed by the rolled-up Epic table
|
|
71
|
-
* (`composition.upsertEpicRunProgress`) so operators see a consistent icon
|
|
72
|
-
* per state across the progress surface.
|
|
73
|
-
*/
|
|
74
|
-
export const STATE_EMOJI = {
|
|
75
|
-
done: '✅',
|
|
76
|
-
blocked: '🚧',
|
|
77
|
-
'in-flight': '🔧',
|
|
78
|
-
queued: '⏳',
|
|
79
|
-
unknown: '❓',
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Map a `story-run-progress` phase to the high-level state label used
|
|
84
|
-
* by the rendered tables. Returns `'unknown'` for any phase value that
|
|
85
|
-
* isn't in the lookup table so an unexpected phase surfaces as an
|
|
86
|
-
* unreadable row rather than a crash.
|
|
87
|
-
*/
|
|
88
|
-
export function phaseToState(phase) {
|
|
89
|
-
return PHASE_TO_STATE[phase] ?? 'unknown';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Parse a `story-run-progress` structured comment posted by `/deliver`.
|
|
94
|
-
* Returns `null` for any malformed body — the caller falls back to the
|
|
95
|
-
* ticket-label state derivation in that case.
|
|
96
|
-
*
|
|
97
|
-
* Expected payload shape (JSON inside a fenced json codeblock):
|
|
98
|
-
* {
|
|
99
|
-
* storyId: number,
|
|
100
|
-
* branch?: string,
|
|
101
|
-
* phase: 'init'|'implementing'|'closing'|'blocked'|'done',
|
|
102
|
-
* title?: string,
|
|
103
|
-
* updatedAt?: string,
|
|
104
|
-
* }
|
|
105
|
-
*/
|
|
106
|
-
export function parseStoryRunProgressComment(comment) {
|
|
107
|
-
const payload = parseFencedJsonComment(comment);
|
|
108
|
-
if (!payload || typeof payload !== 'object') return null;
|
|
109
|
-
const phase = typeof payload.phase === 'string' ? payload.phase : undefined;
|
|
110
|
-
return {
|
|
111
|
-
storyId: Number(payload.storyId),
|
|
112
|
-
title: typeof payload.title === 'string' ? payload.title : '',
|
|
113
|
-
phase,
|
|
114
|
-
state: phaseToState(phase),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Extract the `{ phases, ... }` payload from a `phase-timings` structured
|
|
120
|
-
* comment. Comment body is the fenced-JSON format produced by
|
|
121
|
-
* `renderPhaseTimingsCommentBody` in story-close. Returns `null`
|
|
122
|
-
* for any parse failure — the caller treats that as "no summary
|
|
123
|
-
* available" without erroring out progress rendering.
|
|
124
|
-
*/
|
|
125
|
-
export function parsePhaseTimingsComment(comment) {
|
|
126
|
-
const payload = parseFencedJsonComment(comment);
|
|
127
|
-
if (!payload || typeof payload !== 'object') return null;
|
|
128
|
-
if (!Array.isArray(payload.phases)) return null;
|
|
129
|
-
return {
|
|
130
|
-
storyId: Number(payload.storyId),
|
|
131
|
-
totalMs: Number(payload.totalMs) || 0,
|
|
132
|
-
phases: payload.phases
|
|
133
|
-
.filter(
|
|
134
|
-
(p) =>
|
|
135
|
-
p &&
|
|
136
|
-
typeof p.name === 'string' &&
|
|
137
|
-
Number.isFinite(Number(p.elapsedMs)),
|
|
138
|
-
)
|
|
139
|
-
.map((p) => ({ name: p.name, elapsedMs: Number(p.elapsedMs) })),
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Aggregate a list of `phase-timings` summaries into per-phase median,
|
|
145
|
-
* p95, and sample count. Returns phases ordered by the canonical
|
|
146
|
-
* `PHASE_ORDER` so the rendered table always has the same row sequence —
|
|
147
|
-
* operators should never have to hunt for the `install` row.
|
|
148
|
-
*/
|
|
149
|
-
export function aggregatePhaseTimings(summaries) {
|
|
150
|
-
const buckets = new Map();
|
|
151
|
-
for (const s of summaries) {
|
|
152
|
-
if (!s || !Array.isArray(s.phases)) continue;
|
|
153
|
-
for (const p of s.phases) {
|
|
154
|
-
if (!buckets.has(p.name)) buckets.set(p.name, []);
|
|
155
|
-
buckets.get(p.name).push(p.elapsedMs);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const rows = [];
|
|
159
|
-
for (const name of PHASE_ORDER) {
|
|
160
|
-
const samples = buckets.get(name);
|
|
161
|
-
if (!samples || samples.length === 0) continue;
|
|
162
|
-
rows.push({
|
|
163
|
-
name,
|
|
164
|
-
median: percentile(samples, 0.5),
|
|
165
|
-
p95: percentile(samples, 0.95),
|
|
166
|
-
n: samples.length,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
// Include any unexpected phase names at the tail so a future enum
|
|
170
|
-
// addition surfaces in the table instead of being silently dropped.
|
|
171
|
-
for (const [name, samples] of buckets.entries()) {
|
|
172
|
-
if (PHASE_ORDER.includes(name)) continue;
|
|
173
|
-
rows.push({
|
|
174
|
-
name,
|
|
175
|
-
median: percentile(samples, 0.5),
|
|
176
|
-
p95: percentile(samples, 0.95),
|
|
177
|
-
n: samples.length,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
return rows;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function percentile(samples, q) {
|
|
184
|
-
const sorted = [...samples].sort((a, b) => a - b);
|
|
185
|
-
if (sorted.length === 0) return 0;
|
|
186
|
-
// Nearest-rank method — clamped so q=1 picks the last element.
|
|
187
|
-
const idx = Math.min(
|
|
188
|
-
sorted.length - 1,
|
|
189
|
-
Math.max(0, Math.ceil(q * sorted.length) - 1),
|
|
190
|
-
);
|
|
191
|
-
return sorted[idx];
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Render the aggregated phase-timings table. Returns `null` when there
|
|
196
|
-
* are no summaries to render so the caller can elide the section
|
|
197
|
-
* entirely rather than emitting an empty stub.
|
|
198
|
-
*/
|
|
199
|
-
export function renderPhaseTimingsSection(summaries) {
|
|
200
|
-
if (!Array.isArray(summaries) || summaries.length === 0) return null;
|
|
201
|
-
const rows = aggregatePhaseTimings(summaries);
|
|
202
|
-
if (rows.length === 0) return null;
|
|
203
|
-
const header = `### Phase timings (last ${summaries.length} completed stor${summaries.length === 1 ? 'y' : 'ies'})`;
|
|
204
|
-
const table = [
|
|
205
|
-
'| Phase | median ms | p95 ms | n |',
|
|
206
|
-
'| --- | --- | --- | --- |',
|
|
207
|
-
...rows.map((r) => `| ${r.name} | ${r.median} | ${r.p95} | ${r.n} |`),
|
|
208
|
-
].join('\n');
|
|
209
|
-
return `${header}\n\n${table}`;
|
|
210
|
-
}
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* progress-reporter/transport.js — outbound I/O for the
|
|
3
|
-
* `/deliver` progress narrative.
|
|
4
|
-
*
|
|
5
|
-
* Extracted from the parent `progress-reporter.js` so the
|
|
6
|
-
* GitHub-comment posting surface (in `composition.js`) and the
|
|
7
|
-
* progress-signal aggregation (in `signals.js`) can be reasoned about
|
|
8
|
-
* independently of the webhook fan-out.
|
|
9
|
-
*
|
|
10
|
-
* Each `emit*` helper dispatches a curated event-shaped payload through
|
|
11
|
-
* the caller-supplied `notify` function. The `notify` contract is owned
|
|
12
|
-
* by `lib/notifications/*` and ultimately reaches the configured webhook
|
|
13
|
-
* via gh-exec (the retry/backoff loop lives there, not here — this
|
|
14
|
-
* module's role is the boundary). Failures from `notify` are swallowed
|
|
15
|
-
* by design: a flaky webhook URL must never crash the runner mid-wave.
|
|
16
|
-
*
|
|
17
|
-
* The webhook events emitted from this module are:
|
|
18
|
-
*
|
|
19
|
-
* - `epic-started` — fired once at /deliver kickoff
|
|
20
|
-
* - `epic-progress` — fired at wave boundaries / blocker transitions
|
|
21
|
-
* - `epic-blocked` — wave aggregated to blocked/failed outside halt path
|
|
22
|
-
* - `epic-unblocked` — operator flipped back to executing
|
|
23
|
-
*
|
|
24
|
-
* Each fire passes `skipComment: true` so the operator-facing GitHub
|
|
25
|
-
* comments stay owned by `composition.js` (`upsertEpicRunProgress` and
|
|
26
|
-
* `ProgressReporter.fire()`) — there is exactly one comment writer and
|
|
27
|
-
* exactly one webhook writer per event.
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Webhook event name for the curated epic-progress rollup. Distinct from
|
|
32
|
-
* the `epic-run-progress` structured-comment kind in `signals.js` — the
|
|
33
|
-
* comment is the operator-facing per-poll snapshot on the Epic ticket,
|
|
34
|
-
* the webhook event is the coarse-grained rollup that fires at wave
|
|
35
|
-
* boundaries and after blocker transitions.
|
|
36
|
-
*/
|
|
37
|
-
export const EPIC_PROGRESS_EVENT = 'epic-progress';
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Fire a curated `epic-progress` webhook event. Event-driven only — called
|
|
41
|
-
* per recorder beat and after blocker raise/clear transitions. Carries the
|
|
42
|
-
* rollup payload `{ pct, done, total, phase, openBlockers }`, which Slack
|
|
43
|
-
* consumers and downstream subscribers use to track epic progress without
|
|
44
|
-
* subscribing to per-story chatter.
|
|
45
|
-
*
|
|
46
|
-
* The dispatch passes `skipComment: true` — the operator-facing GitHub
|
|
47
|
-
* comment is owned by `ProgressReporter.fire()` and `upsertEpicRunProgress`,
|
|
48
|
-
* not by this webhook fire.
|
|
49
|
-
*
|
|
50
|
-
* Failures are swallowed by design: the runner must keep moving even if
|
|
51
|
-
* the webhook URL is misconfigured or the network is flaky.
|
|
52
|
-
*
|
|
53
|
-
* Story #4155 — the Epic `/deliver` runtime cut over to the continuous
|
|
54
|
-
* ready-set scheduler, which has **no wave index**. The wave segment was
|
|
55
|
-
* dropped from the message and the rollup payload entirely (rather than
|
|
56
|
-
* rendered as `Wave undefined/undefined`); the sole live caller
|
|
57
|
-
* (`wave-record-notifications.js`) never supplied wave coordinates.
|
|
58
|
-
*
|
|
59
|
-
* @param {{
|
|
60
|
-
* notify: Function|null,
|
|
61
|
-
* epicId: number,
|
|
62
|
-
* done: number,
|
|
63
|
-
* total: number,
|
|
64
|
-
* phase?: string,
|
|
65
|
-
* openBlockers?: Array<{ reason: string, storyId?: number }>,
|
|
66
|
-
* logger?: { warn?: Function },
|
|
67
|
-
* }} args
|
|
68
|
-
* @returns {Promise<{ payload: object } | null>}
|
|
69
|
-
*/
|
|
70
|
-
export async function emitEpicProgress({
|
|
71
|
-
notify,
|
|
72
|
-
epicId,
|
|
73
|
-
done,
|
|
74
|
-
total,
|
|
75
|
-
phase,
|
|
76
|
-
openBlockers = [],
|
|
77
|
-
logger,
|
|
78
|
-
}) {
|
|
79
|
-
if (typeof notify !== 'function') return null;
|
|
80
|
-
const epicIdNum = Number(epicId);
|
|
81
|
-
if (!Number.isInteger(epicIdNum) || epicIdNum <= 0) return null;
|
|
82
|
-
const totalN = Math.max(0, Number(total) || 0);
|
|
83
|
-
const doneN = Math.max(0, Math.min(totalN, Number(done) || 0));
|
|
84
|
-
const pct = totalN === 0 ? 0 : Math.round((doneN / totalN) * 100);
|
|
85
|
-
const blockerCount = Array.isArray(openBlockers) ? openBlockers.length : 0;
|
|
86
|
-
const blockerSuffix =
|
|
87
|
-
blockerCount > 0
|
|
88
|
-
? ` · 🚧 ${blockerCount} blocker${blockerCount === 1 ? '' : 's'}`
|
|
89
|
-
: '';
|
|
90
|
-
const message = `Epic #${epicIdNum} progress · ${doneN}/${totalN} stories done (${pct}%)${blockerSuffix}`;
|
|
91
|
-
|
|
92
|
-
const payload = {
|
|
93
|
-
severity: blockerCount > 0 ? 'high' : 'medium',
|
|
94
|
-
message,
|
|
95
|
-
event: EPIC_PROGRESS_EVENT,
|
|
96
|
-
level: 'epic',
|
|
97
|
-
epicId: epicIdNum,
|
|
98
|
-
};
|
|
99
|
-
if (phase) payload.phase = phase;
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
await notify(epicIdNum, payload, { skipComment: true });
|
|
103
|
-
} catch (err) {
|
|
104
|
-
logger?.warn?.(
|
|
105
|
-
`[emitEpicProgress] notify dispatch failed (swallowed): ${err?.message ?? err}`,
|
|
106
|
-
);
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
payload: {
|
|
111
|
-
pct,
|
|
112
|
-
done: doneN,
|
|
113
|
-
total: totalN,
|
|
114
|
-
phase,
|
|
115
|
-
openBlockers: openBlockers ?? [],
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Fire a curated `epic-started` webhook event at /deliver kickoff.
|
|
122
|
-
* The Slack consumer anchors the rest of the epic narrative to this fire.
|
|
123
|
-
* Failures are swallowed.
|
|
124
|
-
*
|
|
125
|
-
* Story #4155 — the ready-set runtime has no wave count, so the wave
|
|
126
|
-
* segment was dropped from the message (rather than rendered as
|
|
127
|
-
* `undefined wave(s)`); the sole live caller never supplied one.
|
|
128
|
-
*/
|
|
129
|
-
export async function emitEpicStarted({
|
|
130
|
-
notify,
|
|
131
|
-
epicId,
|
|
132
|
-
totalStories,
|
|
133
|
-
title,
|
|
134
|
-
logger,
|
|
135
|
-
}) {
|
|
136
|
-
if (typeof notify !== 'function') return null;
|
|
137
|
-
const epicIdNum = Number(epicId);
|
|
138
|
-
if (!Number.isInteger(epicIdNum) || epicIdNum <= 0) return null;
|
|
139
|
-
const message = `Epic #${epicIdNum} started · ${totalStories} stor${totalStories === 1 ? 'y' : 'ies'}${title ? ` — ${title}` : ''}`;
|
|
140
|
-
try {
|
|
141
|
-
await notify(
|
|
142
|
-
epicIdNum,
|
|
143
|
-
{
|
|
144
|
-
severity: 'medium',
|
|
145
|
-
message,
|
|
146
|
-
event: 'epic-started',
|
|
147
|
-
level: 'epic',
|
|
148
|
-
epicId: epicIdNum,
|
|
149
|
-
},
|
|
150
|
-
{ skipComment: true },
|
|
151
|
-
);
|
|
152
|
-
} catch (err) {
|
|
153
|
-
logger?.warn?.(
|
|
154
|
-
`[emitEpicStarted] notify dispatch failed (swallowed): ${err?.message ?? err}`,
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Fire a curated `epic-blocked` webhook event when a wave aggregates to
|
|
162
|
-
* `blocked` or `failed` outside the `BlockerHandler.halt` code path (the
|
|
163
|
-
* /deliver host-LLM loop has no handler instance — it calls this
|
|
164
|
-
* helper directly from `epic-execute-record-wave.js`). The payload shape
|
|
165
|
-
* matches the inline emit in `BlockerHandler.halt` so downstream consumers
|
|
166
|
-
* see one canonical envelope regardless of which entry point fired.
|
|
167
|
-
* Failures are swallowed.
|
|
168
|
-
*/
|
|
169
|
-
export async function emitEpicBlocked({
|
|
170
|
-
notify,
|
|
171
|
-
epicId,
|
|
172
|
-
reason,
|
|
173
|
-
storyId,
|
|
174
|
-
logger,
|
|
175
|
-
}) {
|
|
176
|
-
if (typeof notify !== 'function') return null;
|
|
177
|
-
const epicIdNum = Number(epicId);
|
|
178
|
-
if (!Number.isInteger(epicIdNum) || epicIdNum <= 0) return null;
|
|
179
|
-
const storyPart = storyId ? ` (story #${storyId})` : '';
|
|
180
|
-
const message = `🚨 Action Required: Epic #${epicIdNum}${storyPart} blocked: ${reason}`;
|
|
181
|
-
try {
|
|
182
|
-
await notify(
|
|
183
|
-
epicIdNum,
|
|
184
|
-
{
|
|
185
|
-
severity: 'high',
|
|
186
|
-
message,
|
|
187
|
-
event: 'epic-blocked',
|
|
188
|
-
level: 'epic',
|
|
189
|
-
epicId: epicIdNum,
|
|
190
|
-
},
|
|
191
|
-
{ skipComment: true },
|
|
192
|
-
);
|
|
193
|
-
} catch (err) {
|
|
194
|
-
logger?.warn?.(
|
|
195
|
-
`[emitEpicBlocked] notify dispatch failed (swallowed): ${err?.message ?? err}`,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Fire a curated `epic-unblocked` webhook event after the operator flips
|
|
203
|
-
* the Epic label back to `agent::executing`. Paired with `epic-blocked` so
|
|
204
|
-
* downstream consumers can track open-blocker lifecycle. Failures are
|
|
205
|
-
* swallowed.
|
|
206
|
-
*/
|
|
207
|
-
export async function emitEpicUnblocked({
|
|
208
|
-
notify,
|
|
209
|
-
epicId,
|
|
210
|
-
resolvedBlocker,
|
|
211
|
-
logger,
|
|
212
|
-
}) {
|
|
213
|
-
if (typeof notify !== 'function') return null;
|
|
214
|
-
const epicIdNum = Number(epicId);
|
|
215
|
-
if (!Number.isInteger(epicIdNum) || epicIdNum <= 0) return null;
|
|
216
|
-
const reasonPart = resolvedBlocker?.reason
|
|
217
|
-
? ` (${resolvedBlocker.reason})`
|
|
218
|
-
: '';
|
|
219
|
-
const message = `Epic #${epicIdNum} unblocked${reasonPart} · resuming.`;
|
|
220
|
-
try {
|
|
221
|
-
await notify(
|
|
222
|
-
epicIdNum,
|
|
223
|
-
{
|
|
224
|
-
severity: 'medium',
|
|
225
|
-
message,
|
|
226
|
-
event: 'epic-unblocked',
|
|
227
|
-
level: 'epic',
|
|
228
|
-
epicId: epicIdNum,
|
|
229
|
-
},
|
|
230
|
-
{ skipComment: true },
|
|
231
|
-
);
|
|
232
|
-
} catch (err) {
|
|
233
|
-
logger?.warn?.(
|
|
234
|
-
`[emitEpicUnblocked] notify dispatch failed (swallowed): ${err?.message ?? err}`,
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared bullet-formatting helpers for progress-signal detectors.
|
|
3
|
-
*
|
|
4
|
-
* Both crap-drift and maintainability-drift produce component-level
|
|
5
|
-
* regression bullets and need the same two pure utilities — hoisted here
|
|
6
|
-
* so they are maintained in one place (Story #3631, refs #3631).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Comparator that sorts the wildcard component `'*'` before all named
|
|
11
|
-
* components, with named components in locale order.
|
|
12
|
-
*
|
|
13
|
-
* @param {string} a
|
|
14
|
-
* @param {string} b
|
|
15
|
-
* @returns {number}
|
|
16
|
-
*/
|
|
17
|
-
export function componentOrder(a, b) {
|
|
18
|
-
if (a === '*') return -1;
|
|
19
|
-
if (b === '*') return 1;
|
|
20
|
-
return a.localeCompare(b);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Formats a numeric gate value for display: integers render without a
|
|
25
|
-
* decimal point; non-integers are fixed to two decimal places.
|
|
26
|
-
*
|
|
27
|
-
* @param {number} value
|
|
28
|
-
* @returns {string}
|
|
29
|
-
*/
|
|
30
|
-
export function formatNumber(value) {
|
|
31
|
-
return Number.isInteger(value) ? String(value) : value.toFixed(2);
|
|
32
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import nodeFs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { resolveComponents } from '../../../baselines/components.js';
|
|
4
|
-
import { componentOrder } from './_bullet-format.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Shared component-regression walk for the progress-signal drift detectors
|
|
8
|
-
* (Story #3984). `crap-drift.js` and `maintainability-drift.js` previously
|
|
9
|
-
* duplicated this baseline-rollup → per-component compare → bullet-list
|
|
10
|
-
* shape verbatim; the only divergence was the breach comparator (CRAP is
|
|
11
|
-
* "lower is better", maintainability is "higher is better") and the bullet
|
|
12
|
-
* text. Both detectors now parameterize this walk.
|
|
13
|
-
*
|
|
14
|
-
* Pure — the caller loads the baseline via `lib/baselines/reader.js#load(...)`
|
|
15
|
-
* and passes the resulting `{ rollup }` plus the gate config block.
|
|
16
|
-
*
|
|
17
|
-
* Only components whose rollup breaches the configured floor surface — a
|
|
18
|
-
* breach in a component-scoped floor does NOT report against `*` unless
|
|
19
|
-
* `*` itself breaches. This keeps the rollout narrowly targeted: when an
|
|
20
|
-
* operator wires up a per-component floor for `api`, regressing `api`
|
|
21
|
-
* names `api` — not `*`.
|
|
22
|
-
*
|
|
23
|
-
* @param {{
|
|
24
|
-
* rollup?: Record<string, Record<string, number>>,
|
|
25
|
-
* gateConfig?: { floors?: Record<string, Record<string, number>> } & object,
|
|
26
|
-
* }} params
|
|
27
|
-
* @param {{
|
|
28
|
-
* isBreach: (value: number, floor: number) => boolean,
|
|
29
|
-
* formatBullet: (name: string, axis: string, value: number, floor: number) => string,
|
|
30
|
-
* }} spec
|
|
31
|
-
* @returns {string[]}
|
|
32
|
-
*/
|
|
33
|
-
export function walkComponentRegressions(params = {}, spec) {
|
|
34
|
-
const rollup = params.rollup ?? {};
|
|
35
|
-
const gateConfig = params.gateConfig ?? {};
|
|
36
|
-
const floors = gateConfig.floors ?? {};
|
|
37
|
-
const components = resolveComponents(gateConfig);
|
|
38
|
-
const names = new Set([
|
|
39
|
-
...Object.keys(components),
|
|
40
|
-
...Object.keys(floors),
|
|
41
|
-
...Object.keys(rollup),
|
|
42
|
-
]);
|
|
43
|
-
const bullets = [];
|
|
44
|
-
for (const name of [...names].sort(componentOrder)) {
|
|
45
|
-
const aggregate = rollup[name];
|
|
46
|
-
if (!aggregate || typeof aggregate !== 'object') continue;
|
|
47
|
-
const floor = floors[name] ?? floors['*'];
|
|
48
|
-
if (!floor || typeof floor !== 'object') continue;
|
|
49
|
-
for (const axis of Object.keys(floor).sort()) {
|
|
50
|
-
const target = floor[axis];
|
|
51
|
-
const value = aggregate[axis];
|
|
52
|
-
if (typeof target !== 'number' || !Number.isFinite(target)) continue;
|
|
53
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) continue;
|
|
54
|
-
if (!spec.isBreach(value, target)) continue;
|
|
55
|
-
bullets.push(spec.formatBullet(name, axis, value, target));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return bullets;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Shared wave-start snapshot persistence for the drift detectors. Both
|
|
63
|
-
* detectors persist a `{ capturedAt, ...metadata, scores }` JSON document
|
|
64
|
-
* under `<cwd>/<baselineDir>/<filename>` so a resumed epic run can re-read
|
|
65
|
-
* the wave-start anchor rather than lose it, and both treat persistence as
|
|
66
|
-
* best-effort (the in-memory baseline still works when a write fails).
|
|
67
|
-
*
|
|
68
|
-
* @param {{
|
|
69
|
-
* fs: { readFileSync?: Function, writeFileSync?: Function, mkdirSync?: Function },
|
|
70
|
-
* baselinePath: string,
|
|
71
|
-
* metadata?: Record<string, unknown>,
|
|
72
|
-
* }} opts
|
|
73
|
-
*/
|
|
74
|
-
function createSnapshotStore({ fs, baselinePath, metadata = {} }) {
|
|
75
|
-
return {
|
|
76
|
-
persist(scores) {
|
|
77
|
-
if (!fs.writeFileSync) return;
|
|
78
|
-
try {
|
|
79
|
-
fs.mkdirSync?.(path.dirname(baselinePath), { recursive: true });
|
|
80
|
-
fs.writeFileSync(
|
|
81
|
-
baselinePath,
|
|
82
|
-
JSON.stringify(
|
|
83
|
-
{ capturedAt: new Date().toISOString(), ...metadata, scores },
|
|
84
|
-
null,
|
|
85
|
-
2,
|
|
86
|
-
),
|
|
87
|
-
);
|
|
88
|
-
} catch {
|
|
89
|
-
// persistence is best-effort; the in-memory baseline still works
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
load() {
|
|
94
|
-
if (!fs.readFileSync) return null;
|
|
95
|
-
try {
|
|
96
|
-
const raw = fs.readFileSync(baselinePath, 'utf-8');
|
|
97
|
-
const parsed = JSON.parse(raw);
|
|
98
|
-
return parsed?.scores ?? null;
|
|
99
|
-
} catch {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Shared per-file/per-method drift-detector skeleton for the progress-signal
|
|
108
|
-
* detectors (Story #4076). `crap-drift.js` and `maintainability-drift.js`
|
|
109
|
-
* previously duplicated the same `{ baselinePath, captureBaseline,
|
|
110
|
-
* loadBaseline, detect }` shape — identical snapshot-store wiring, identical
|
|
111
|
-
* "distinct from canonical baseline" framing, and identical
|
|
112
|
-
* swallow-and-warn resilience. The only divergence is the per-axis scoring
|
|
113
|
-
* (`scoreFile`), the snapshot value extracted from a score (`captureScore`),
|
|
114
|
-
* and the per-detect comparison that emits bullets (`detect`). Both detectors
|
|
115
|
-
* now supply those deltas to this factory, mirroring the "shared walker +
|
|
116
|
-
* per-axis delta" pattern already established by `walkComponentRegressions`.
|
|
117
|
-
*
|
|
118
|
-
* The factory owns:
|
|
119
|
-
*
|
|
120
|
-
* - `fs` / `cwd` / `files` resolution from `opts`.
|
|
121
|
-
* - The `<cwd>/<baselineDir>/<baselineFilename>` baseline path and the
|
|
122
|
-
* `createSnapshotStore` wiring (with caller-supplied `metadata`).
|
|
123
|
-
* - The in-memory `baseline` cache and the `captureBaseline` /
|
|
124
|
-
* `loadBaseline` lifecycle.
|
|
125
|
-
*
|
|
126
|
-
* The caller owns:
|
|
127
|
-
*
|
|
128
|
-
* - `scoreFile(relPath, ctx)` — returns the per-file score (any shape) or
|
|
129
|
-
* `null` when the file can't be scored. `ctx` is whatever
|
|
130
|
-
* `beforeScore()` returned for this pass (e.g. a coverage map), or
|
|
131
|
-
* `undefined` when `beforeScore` is omitted.
|
|
132
|
-
* - `captureScore(score)` — maps a `scoreFile` result to the value
|
|
133
|
-
* persisted in the snapshot (e.g. extract `crap` from each method row).
|
|
134
|
-
* - `detect({ baseline, scoreFile })` — async; returns the bullet list.
|
|
135
|
-
* Receives the loaded baseline and a `scoreFile(relPath)` bound to this
|
|
136
|
-
* pass's score context so the per-axis compare stays free of plumbing.
|
|
137
|
-
* - `beforeScore()` (optional) — runs once per `captureBaseline` / `detect`
|
|
138
|
-
* pass and returns the score context threaded into `scoreFile`.
|
|
139
|
-
*
|
|
140
|
-
* @param {{
|
|
141
|
-
* cwd?: string,
|
|
142
|
-
* files?: string[],
|
|
143
|
-
* fs?: { readFileSync?: Function, writeFileSync?: Function, mkdirSync?: Function, existsSync?: Function },
|
|
144
|
-
* baselineDir?: string,
|
|
145
|
-
* baselineFilename: string,
|
|
146
|
-
* metadata?: Record<string, unknown>,
|
|
147
|
-
* beforeScore?: () => unknown,
|
|
148
|
-
* scoreFile: (relPath: string, ctx: unknown) => unknown,
|
|
149
|
-
* captureScore: (score: unknown) => unknown,
|
|
150
|
-
* detect: (args: { baseline: Record<string, unknown>, scoreFile: (relPath: string) => unknown }) => Promise<string[]>,
|
|
151
|
-
* }} opts
|
|
152
|
-
*/
|
|
153
|
-
export function createDriftDetector(opts = {}) {
|
|
154
|
-
const fs = opts.fs ?? nodeFs;
|
|
155
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
156
|
-
const files = Array.isArray(opts.files) ? [...opts.files] : [];
|
|
157
|
-
const baselineDir = opts.baselineDir ?? '.agents/state';
|
|
158
|
-
const baselinePath = path.join(cwd, baselineDir, opts.baselineFilename);
|
|
159
|
-
const beforeScore = opts.beforeScore ?? (() => undefined);
|
|
160
|
-
const scoreFile = opts.scoreFile;
|
|
161
|
-
const captureScore = opts.captureScore;
|
|
162
|
-
const runDetect = opts.detect;
|
|
163
|
-
const store = createSnapshotStore({
|
|
164
|
-
fs,
|
|
165
|
-
baselinePath,
|
|
166
|
-
metadata: opts.metadata ?? {},
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
let baseline = null;
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
get baselinePath() {
|
|
173
|
-
return baselinePath;
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
captureBaseline() {
|
|
177
|
-
const ctx = beforeScore();
|
|
178
|
-
const snapshot = {};
|
|
179
|
-
for (const f of files) {
|
|
180
|
-
const score = scoreFile(f, ctx);
|
|
181
|
-
if (score == null) continue;
|
|
182
|
-
snapshot[f] = captureScore(score);
|
|
183
|
-
}
|
|
184
|
-
baseline = snapshot;
|
|
185
|
-
store.persist(snapshot);
|
|
186
|
-
return snapshot;
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
loadBaseline() {
|
|
190
|
-
baseline = store.load();
|
|
191
|
-
return baseline;
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
async detect() {
|
|
195
|
-
if (!baseline) return [];
|
|
196
|
-
const ctx = beforeScore();
|
|
197
|
-
return runDetect({
|
|
198
|
-
baseline,
|
|
199
|
-
scoreFile: (relPath) => scoreFile(relPath, ctx),
|
|
200
|
-
});
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
|
-
}
|