mandrel 1.58.0 → 1.60.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 +100 -98
- package/.agents/docs/SDLC.md +140 -141
- package/.agents/docs/configuration.md +16 -16
- package/.agents/docs/workflows.md +7 -8
- package/.agents/instructions.md +12 -11
- package/.agents/personas/architect.md +1 -1
- package/.agents/personas/product.md +1 -1
- package/.agents/personas/project-manager.md +14 -14
- package/.agents/personas/technical-writer.md +1 -1
- package/.agents/rules/changelog-style.md +5 -5
- package/.agents/rules/git-conventions.md +3 -3
- package/.agents/schemas/agentrc.schema.json +3 -3
- package/.agents/schemas/audit-rules.json +20 -0
- package/.agents/schemas/dispatch-manifest.json +4 -4
- package/.agents/schemas/epic-spec.schema.json +15 -45
- package/.agents/schemas/lifecycle/README.md +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/README.md +1 -1
- package/.agents/scripts/acceptance-eval.js +21 -4
- package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
- package/.agents/scripts/analyze-execution.js +2 -2
- package/.agents/scripts/assert-branch.js +1 -3
- package/.agents/scripts/audit-to-stories.js +1 -1
- package/.agents/scripts/bootstrap.js +1 -1
- package/.agents/scripts/check-arch-cycles.js +360 -0
- package/.agents/scripts/check-doc-links.js +2 -3
- package/.agents/scripts/coverage-capture.js +24 -3
- package/.agents/scripts/diagnose-friction.js +1 -1
- package/.agents/scripts/dispatcher.js +2 -2
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/epic-audit-prepare.js +3 -3
- package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
- package/.agents/scripts/epic-deliver-preflight.js +11 -9
- package/.agents/scripts/epic-deliver-prepare.js +13 -5
- package/.agents/scripts/epic-execute-record-wave.js +5 -5
- package/.agents/scripts/epic-plan-healthcheck.js +6 -10
- package/.agents/scripts/epic-plan-spec-validate.js +1 -1
- package/.agents/scripts/epic-reconcile.js +11 -29
- package/.agents/scripts/evidence-gate.js +2 -2
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/git-rebase-and-resolve.js +1 -1
- package/.agents/scripts/hierarchy-gate.js +40 -24
- package/.agents/scripts/lib/ITicketingProvider.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
- package/.agents/scripts/lib/baseline-snapshot.js +7 -7
- package/.agents/scripts/lib/baselines/kinds/coverage.js +33 -149
- package/.agents/scripts/lib/baselines/kinds/duplication.js +27 -116
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +192 -0
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +34 -133
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +31 -124
- package/.agents/scripts/lib/baselines/kinds/mutation.js +25 -111
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +59 -0
- package/.agents/scripts/lib/baselines/maintainability-baseline-save.js +37 -0
- package/.agents/scripts/lib/baselines/writer.js +1 -1
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/close-validation/commands.js +188 -0
- package/.agents/scripts/lib/close-validation/gates.js +235 -0
- package/.agents/scripts/lib/close-validation/process.js +101 -0
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +1 -1
- package/.agents/scripts/lib/close-validation/runner.js +325 -0
- package/.agents/scripts/lib/close-validation/telemetry.js +70 -0
- package/.agents/scripts/lib/codebase-snapshot.js +1 -1
- package/.agents/scripts/lib/config/explain.js +1 -1
- package/.agents/scripts/lib/config/quality.js +6 -6
- package/.agents/scripts/lib/config/runners.js +2 -2
- package/.agents/scripts/lib/config/runtime.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-resolver.js +2 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
- package/.agents/scripts/lib/config-settings-schema.js +3 -3
- package/.agents/scripts/lib/coverage-capture.js +147 -4
- package/.agents/scripts/lib/cpu-pool.js +14 -0
- package/.agents/scripts/lib/crap-utils.js +6 -11
- package/.agents/scripts/lib/duplicate-search.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +87 -0
- package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
- package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +10 -10
- package/.agents/scripts/lib/git-utils.js +24 -22
- package/.agents/scripts/lib/label-constants.js +3 -4
- package/.agents/scripts/lib/label-taxonomy.js +3 -8
- package/.agents/scripts/lib/maintainability-engine.js +1 -1
- package/.agents/scripts/lib/maintainability-utils.js +4 -187
- package/.agents/scripts/lib/observability/perf-report-readers.js +32 -23
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +81 -7
- package/.agents/scripts/lib/orchestration/code-review.js +95 -82
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
- package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +14 -37
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +22 -22
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +206 -58
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +27 -3
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +28 -8
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +13 -41
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +2 -3
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -8
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +103 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +22 -64
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +38 -76
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +10 -10
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +8 -20
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
- package/.agents/scripts/lib/orchestration/file-assumptions.js +6 -5
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +144 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +3 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +8 -8
- package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +3 -3
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +7 -7
- package/.agents/scripts/lib/orchestration/preflight-cache.js +36 -13
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
- package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
- package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +5 -60
- package/.agents/scripts/lib/orchestration/review-providers/native.js +7 -6
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +105 -0
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +7 -59
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +2 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +2 -4
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +32 -35
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +1 -2
- package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +451 -503
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +8 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +47 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +2 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +358 -54
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +3 -2
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +32 -5
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +5 -18
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +3 -3
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +33 -16
- package/.agents/scripts/lib/orchestration/story-reachability.js +47 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
- package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +4 -35
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
- package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +44 -73
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +16 -7
- package/.agents/scripts/lib/orchestration/ticketing/state.js +53 -439
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +471 -0
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +3 -3
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +2 -8
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +1 -1
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
- package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
- package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
- package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
- package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
- package/.agents/scripts/lib/project-root.js +17 -0
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/spec/index.js +1 -1
- package/.agents/scripts/lib/spec/loader.js +2 -2
- package/.agents/scripts/lib/spec/state.js +7 -16
- package/.agents/scripts/lib/story-adjacency.js +76 -0
- package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
- package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
- package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
- package/.agents/scripts/lib/story-lifecycle.js +9 -9
- package/.agents/scripts/lib/story-plan.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
- package/.agents/scripts/lib/transpile.js +93 -0
- package/.agents/scripts/lib/wave-runner/tick.js +4 -153
- package/.agents/scripts/lib/workers/crap-worker.js +1 -1
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +20 -2
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +90 -0
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +26 -8
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +74 -0
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
- package/.agents/scripts/lifecycle-emit.js +1 -1
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/mappers.js +2 -2
- package/.agents/scripts/providers/github/tickets.js +114 -10
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/retro-run.js +2 -2
- package/.agents/scripts/run-lint.js +10 -1
- package/.agents/scripts/run-tests.js +24 -4
- package/.agents/scripts/single-story-init.js +1 -1
- package/.agents/scripts/stories-wave-tick.js +13 -10
- package/.agents/scripts/story-close.js +1 -1
- package/.agents/scripts/story-init.js +162 -26
- package/.agents/scripts/story-phase.js +5 -5
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/sync-branch-from-base.js +2 -2
- package/.agents/scripts/validate-docs-freshness.js +1 -1
- package/.agents/scripts/wave-tick.js +1 -1
- package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
- package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
- package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
- package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
- package/.agents/skills/core/scope-triage/SKILL.md +9 -10
- package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
- package/.agents/skills/skills.index.json +7 -7
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +1 -1
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/workflows/agents-update.md +2 -2
- package/.agents/workflows/audit-architecture.md +2 -2
- package/.agents/workflows/audit-clean-code.md +2 -2
- package/.agents/workflows/audit-dependencies.md +1 -1
- package/.agents/workflows/audit-devops.md +1 -1
- package/.agents/workflows/audit-documentation.md +226 -0
- package/.agents/workflows/audit-lighthouse.md +1 -1
- package/.agents/workflows/audit-performance.md +2 -2
- package/.agents/workflows/audit-privacy.md +1 -1
- package/.agents/workflows/audit-quality.md +2 -2
- package/.agents/workflows/audit-security.md +2 -2
- package/.agents/workflows/audit-seo.md +1 -1
- package/.agents/workflows/audit-sre.md +1 -1
- package/.agents/workflows/audit-to-stories.md +10 -10
- package/.agents/workflows/audit-ux-ui.md +1 -1
- package/.agents/workflows/deliver.md +85 -0
- package/.agents/workflows/explain.md +3 -3
- package/.agents/workflows/git-merge-pr.md +1 -1
- package/.agents/workflows/git-pr-all.md +13 -10
- package/.agents/workflows/git-push.md +6 -3
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
- package/.agents/workflows/helpers/code-review.md +5 -5
- package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +59 -66
- package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
- package/.agents/workflows/helpers/diagnose.md +1 -1
- package/.agents/workflows/helpers/epic-audit.md +6 -6
- package/.agents/workflows/helpers/epic-deliver-story.md +28 -39
- package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
- package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
- package/.agents/workflows/helpers/epic-testing.md +3 -3
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
- package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
- package/.agents/workflows/helpers/signals.md +1 -1
- package/.agents/workflows/helpers/single-story-deliver.md +12 -11
- package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
- package/.agents/workflows/onboard.md +21 -20
- package/.agents/workflows/plan.md +89 -0
- package/.agents/workflows/qa-explore.md +1 -1
- package/.agents/workflows/qa-run-harness.md +1 -1
- package/README.md +17 -20
- package/docs/CHANGELOG.md +1149 -0
- package/lib/cli/__tests__/update-changelog-surface.test.js +357 -0
- package/lib/cli/__tests__/update-reexec.test.js +513 -0
- package/lib/cli/init.js +338 -0
- package/lib/cli/update.js +413 -52
- package/package.json +3 -1
- package/.agents/scripts/lib/auto-refresh-baselines.js +0 -308
- package/.agents/scripts/lib/close-validation.js +0 -897
- package/.agents/scripts/lib/orchestration/cascade-grouping.js +0 -275
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +0 -69
- package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +0 -221
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +0 -123
- package/.agents/scripts/lib/task-utils.js +0 -26
- package/.agents/scripts/story-deliver-prepare.js +0 -267
|
@@ -5,7 +5,7 @@ events and performs a single side effect. The canonical close-tail roster
|
|
|
5
5
|
— in registration order — is wired by
|
|
6
6
|
[`index.js`](./index.js) (`buildDefaultListenerChain`), the production
|
|
7
7
|
entrypoint the standalone `lifecycle-emit.js` CLI shells in for
|
|
8
|
-
`/
|
|
8
|
+
`/deliver`'s Phase 6 / 7.5 / 8 / 8.5 markdown invocations:
|
|
9
9
|
|
|
10
10
|
- `ledger-writer.js` — privileged `onEmitted` hook that lands every
|
|
11
11
|
`emitted` record on disk before any listener body runs (MUST be first).
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
* This is the bus-level replay defence.
|
|
42
42
|
* 2. The `gh pr view` probe — short-circuits across process
|
|
43
43
|
* boundaries when a prior run already armed auto-merge. This is
|
|
44
|
-
* the recovery defence: `/
|
|
44
|
+
* the recovery defence: `/deliver` restarted on the same PR
|
|
45
45
|
* will see the existing arm and emit `epic.merge.armed` exactly
|
|
46
46
|
* once.
|
|
47
47
|
*
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Subscribes to:
|
|
9
9
|
* - `epic.automerge.start` (production path, Story #3901) → the
|
|
10
|
-
* `/
|
|
10
|
+
* `/deliver` Phase 8.5 boundary that the `lifecycle-emit.js`
|
|
11
11
|
* CLI actually fires. This event carries `prUrl` but NO
|
|
12
12
|
* `checkOutcomes` (Phase 8's `pr-watch-with-update.js` has already
|
|
13
13
|
* polled every required check to green before Phase 8.5 runs), so
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// .agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js
|
|
2
2
|
/**
|
|
3
3
|
* BranchCleaner — lifecycle listener that owns post-merge **branch** reap
|
|
4
|
-
* for `/
|
|
4
|
+
* for `/deliver`. Story #2398 (companion to Cleaner, which owns the
|
|
5
5
|
* temp-tree archival half of end-of-Epic cleanup).
|
|
6
6
|
*
|
|
7
7
|
* Subscribes to:
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
* level replays short-circuit.
|
|
50
50
|
* 2. The `gh pr list --head` probe + `openOrLocatePr`'s internal
|
|
51
51
|
* locate path — both defend against cross-process re-runs
|
|
52
|
-
* (`/
|
|
52
|
+
* (`/deliver` restarted on the same branch after a crash).
|
|
53
53
|
*
|
|
54
54
|
* Side-effect firewall: the listener emits on the bus, shells out to
|
|
55
55
|
* `gh`/`git` (via the helpers), and upserts the `epic-handoff`
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* mirrored this roster for an in-session runner was deleted with the
|
|
9
9
|
* dead epic-runner stratum in Story #3908; the host-LLM-drives-CLIs
|
|
10
10
|
* model reaches every close-tail listener through the `lifecycle-emit.js`
|
|
11
|
-
* CLI shells in `/
|
|
11
|
+
* CLI shells in `/deliver`'s Phase 6 / 7.5 / 8 markdown invocations,
|
|
12
12
|
* which call this builder.)
|
|
13
13
|
*
|
|
14
14
|
* Canonical roster (registration order):
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* `{ epicId, prNumber, mergeCommitSha, mergedAt, pollAttempts }`.
|
|
21
21
|
* 4. If the budget is exceeded without observing a merge, return
|
|
22
22
|
* a `failed` classification with reason `budget-exceeded` and
|
|
23
|
-
* do NOT emit `epic.merge.confirmed`. The /
|
|
23
|
+
* do NOT emit `epic.merge.confirmed`. The /deliver
|
|
24
24
|
* blocker-handler flow surfaces this via `agent::blocked`.
|
|
25
25
|
*
|
|
26
26
|
* Resume contract (AC of Task #2907): the ledger is the source of
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* webhookEvents entry lifecycle event
|
|
16
16
|
* -------------------- ---------------------
|
|
17
|
-
* `epic-started` (emitted at /
|
|
17
|
+
* `epic-started` (emitted at /deliver kickoff;
|
|
18
18
|
* this listener handles `epic.snapshot.start`)
|
|
19
19
|
* `epic-blocked` `epic.blocked`
|
|
20
20
|
* `epic-complete` `epic.complete`
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Idempotency contract (AC-10): per-instance `Set<string>` of
|
|
24
24
|
* `${event}:${seqId}` keys. A repeat `(event, seqId)` short-circuits
|
|
25
25
|
* without re-polling and emits nothing. Combined with the bus-level
|
|
26
|
-
* replay defence, this is sufficient — re-running `/
|
|
26
|
+
* replay defence, this is sufficient — re-running `/deliver` after
|
|
27
27
|
* a crash will produce a NEW seqId and the listener legitimately
|
|
28
28
|
* re-runs the poll loop (which is itself idempotent: the outcome map
|
|
29
29
|
* always reflects the live GitHub state).
|
|
@@ -109,7 +109,7 @@ export const extractPrNumber = parsePrNumberFromUrl;
|
|
|
109
109
|
*
|
|
110
110
|
* Exported so tests can stub.
|
|
111
111
|
*/
|
|
112
|
-
|
|
112
|
+
function ghPrChecks({ prUrl, cwd, spawnFn = spawnSync }) {
|
|
113
113
|
const result = spawnFn(
|
|
114
114
|
'gh',
|
|
115
115
|
[
|
|
@@ -134,7 +134,7 @@ export function ghPrChecks({ prUrl, cwd, spawnFn = spawnSync }) {
|
|
|
134
134
|
* can detect the BEHIND condition (PR head is behind its base branch)
|
|
135
135
|
* AFTER every required check is green. Exported so tests can stub.
|
|
136
136
|
*/
|
|
137
|
-
|
|
137
|
+
function ghPrView({ prUrl, cwd, spawnFn = spawnSync }) {
|
|
138
138
|
const result = spawnFn(
|
|
139
139
|
'gh',
|
|
140
140
|
['pr', 'view', prUrl, '--json', 'mergeStateStatus'],
|
|
@@ -154,7 +154,7 @@ export function ghPrView({ prUrl, cwd, spawnFn = spawnSync }) {
|
|
|
154
154
|
* BEHIND" (the conservative recovery branch). Pure — exported for
|
|
155
155
|
* tests.
|
|
156
156
|
*/
|
|
157
|
-
|
|
157
|
+
function parseMergeStateStatus(stdout) {
|
|
158
158
|
const trimmed = String(stdout ?? '').trim();
|
|
159
159
|
if (trimmed.length === 0) return '';
|
|
160
160
|
try {
|
|
@@ -172,7 +172,7 @@ export function parseMergeStateStatus(stdout) {
|
|
|
172
172
|
* loop to fast-forward the PR head with its base branch. Exported so
|
|
173
173
|
* tests can stub and assert call counts.
|
|
174
174
|
*/
|
|
175
|
-
|
|
175
|
+
function ghPrUpdateBranch({ prUrl, cwd, spawnFn = spawnSync }) {
|
|
176
176
|
const result = spawnFn('gh', ['pr', 'update-branch', prUrl], {
|
|
177
177
|
cwd,
|
|
178
178
|
encoding: 'utf-8',
|
|
@@ -192,7 +192,7 @@ export function ghPrUpdateBranch({ prUrl, cwd, spawnFn = spawnSync }) {
|
|
|
192
192
|
* the same definition as the downstream predicate. Pure — exported
|
|
193
193
|
* for tests.
|
|
194
194
|
*/
|
|
195
|
-
|
|
195
|
+
const GREEN_CHECK_OUTCOMES = Object.freeze(
|
|
196
196
|
new Set(['success', 'neutral', 'skipped']),
|
|
197
197
|
);
|
|
198
198
|
|
|
@@ -202,7 +202,7 @@ export const GREEN_CHECK_OUTCOMES = Object.freeze(
|
|
|
202
202
|
* regardless of mergeStateStatus, so we never auto-recover into a
|
|
203
203
|
* failing PR.
|
|
204
204
|
*/
|
|
205
|
-
|
|
205
|
+
function allGreen(outcomes) {
|
|
206
206
|
const values = Object.values(outcomes);
|
|
207
207
|
if (values.length === 0) return false;
|
|
208
208
|
for (const v of values) {
|
|
@@ -271,7 +271,7 @@ export function allTerminal(outcomes) {
|
|
|
271
271
|
* behaviour is reviewable. Called only when the poll loop exits via
|
|
272
272
|
* the iteration cap.
|
|
273
273
|
*/
|
|
274
|
-
|
|
274
|
+
function promotePendingToTimedOut(outcomes) {
|
|
275
275
|
const out = {};
|
|
276
276
|
for (const [k, v] of Object.entries(outcomes)) {
|
|
277
277
|
out[k] = v === 'pending' ? 'timed_out' : v;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/orchestration/manifest-builder.js — Manifest Building Logic
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 2-tier-only producer. Reads Story tickets from `allTickets` directly,
|
|
5
5
|
* computes Story-scoped waves, and emits the `waves[].stories[]` /
|
|
6
6
|
* Story-only `storyManifest` shape. The pre-Epic-#3163 Task-tier branch
|
|
7
7
|
* has been removed; the framework no longer carries a Task-tier
|
|
@@ -48,7 +48,7 @@ function extractSectionList(body, heading) {
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Project a Story ticket into the inline-acceptance/verify shape required by
|
|
51
|
-
* the
|
|
51
|
+
* the 2-tier waves[].stories[] schema. Reads `## Acceptance` /
|
|
52
52
|
* `## Acceptance Criteria` and `## Verify` sections from the body.
|
|
53
53
|
*
|
|
54
54
|
* @param {object} story
|
|
@@ -95,7 +95,7 @@ function projectStoryForWave(story, epicId) {
|
|
|
95
95
|
const AGENT_DONE_LABEL = STATE_LABELS.DONE;
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
* Build the Story-only manifest array used by the
|
|
98
|
+
* Build the Story-only manifest array used by the 2-tier hierarchy path.
|
|
99
99
|
* Reads Story tickets directly from `allTickets`; there is no Task tier
|
|
100
100
|
* to walk. Each entry exposes an empty `tasks: []` to keep downstream
|
|
101
101
|
* consumers (renderers, dispatch helpers) on a single per-Story shape
|
|
@@ -145,7 +145,7 @@ function buildStoryOnlyManifest(stories, epicId) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
|
-
* Build the wave records for a
|
|
148
|
+
* Build the wave records for a 2-tier manifest. Each wave entry exposes a
|
|
149
149
|
* `stories[]` projection (instead of the legacy `tasks[]`) so dispatch
|
|
150
150
|
* consumers can fan Story execution out wave-by-wave without ever seeing
|
|
151
151
|
* a `type::task` ticket.
|
|
@@ -200,7 +200,7 @@ export function buildManifest({
|
|
|
200
200
|
epicTitle: epic?.title ?? '',
|
|
201
201
|
executor: 'claude-code',
|
|
202
202
|
dryRun,
|
|
203
|
-
hierarchy: '
|
|
203
|
+
hierarchy: '2-tier',
|
|
204
204
|
summary: {
|
|
205
205
|
totalStories,
|
|
206
206
|
doneStories,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - "parked" — the Story is genuinely outside the manifest (carved off
|
|
10
10
|
* mid-sprint, no recut lineage). The operator should explicitly
|
|
11
11
|
* adopt it into the current Epic or defer it. Surfaced as a
|
|
12
|
-
* structured comment so `/
|
|
12
|
+
* structured comment so `/deliver` has a single checkpoint.
|
|
13
13
|
*
|
|
14
14
|
* Both categories are informational at the wave-completeness gate — they do
|
|
15
15
|
* not fail closure by themselves. The gate continues to enforce that every
|
|
@@ -81,7 +81,7 @@ export function renderParkedFollowOnsComment(epicId, classification) {
|
|
|
81
81
|
`## 🪝 Parked Follow-Ons & Recuts — Epic #${epicId}`,
|
|
82
82
|
'',
|
|
83
83
|
'Stories created under this Epic that are **not** in the frozen dispatch',
|
|
84
|
-
'manifest. Surfaced here so `/
|
|
84
|
+
'manifest. Surfaced here so `/deliver` can gate on them at the',
|
|
85
85
|
'completeness check.',
|
|
86
86
|
'',
|
|
87
87
|
`- **Recuts** (attributable to a manifest Story): ${recuts.length}`,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* plan-router — given an Epic's current labels, decide which plan-phase CLI
|
|
3
3
|
* should run next.
|
|
4
4
|
*
|
|
5
|
-
* Used by the local `/
|
|
5
|
+
* Used by the local `/plan` wrapper (chains spec → decompose).
|
|
6
6
|
*
|
|
7
7
|
* The router is intentionally stateless. Callers feed the current label set
|
|
8
8
|
* (a string array, usually from `provider.getEpic(id).labels`) and receive a
|
|
@@ -21,7 +21,7 @@ export const PLAN_PHASE_NAMES = Object.freeze({
|
|
|
21
21
|
* path used by the local wrapper; `command` is the slash-command invocation
|
|
22
22
|
* operators fire.
|
|
23
23
|
*
|
|
24
|
-
* Spec and Decompose are served by the unified `/
|
|
24
|
+
* Spec and Decompose are served by the unified `/plan` wrapper with a
|
|
25
25
|
* `--phase` flag — the phase workflows themselves live at
|
|
26
26
|
* `.agents/workflows/helpers/epic-plan-{spec,decompose}.md` and are not
|
|
27
27
|
* directly invokable slash commands.
|
|
@@ -33,20 +33,20 @@ export const PLAN_PHASE_DESCRIPTORS = Object.freeze({
|
|
|
33
33
|
[PLAN_PHASE_NAMES.SPEC]: {
|
|
34
34
|
phase: PLAN_PHASE_NAMES.SPEC,
|
|
35
35
|
script: '.agents/scripts/epic-plan-spec.js',
|
|
36
|
-
command: '/
|
|
36
|
+
command: '/plan --phase spec',
|
|
37
37
|
parkingLabel: AGENT_LABELS.REVIEW_SPEC,
|
|
38
38
|
},
|
|
39
39
|
[PLAN_PHASE_NAMES.DECOMPOSE]: {
|
|
40
40
|
phase: PLAN_PHASE_NAMES.DECOMPOSE,
|
|
41
41
|
script: '.agents/scripts/epic-plan-decompose.js',
|
|
42
|
-
command: '/
|
|
42
|
+
command: '/plan --phase decompose',
|
|
43
43
|
parkingLabel: AGENT_LABELS.READY,
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Given the Epic's current labels, pick the next plan phase to run in the
|
|
49
|
-
* local `/
|
|
49
|
+
* local `/plan` wrapper.
|
|
50
50
|
*
|
|
51
51
|
* Precedence:
|
|
52
52
|
* 1. If the Epic already carries `agent::ready`, there is nothing left to
|
|
@@ -21,7 +21,7 @@ export async function notificationPhase(ctx, state) {
|
|
|
21
21
|
storyId,
|
|
22
22
|
story,
|
|
23
23
|
epicBranch,
|
|
24
|
-
|
|
24
|
+
config,
|
|
25
25
|
progress,
|
|
26
26
|
provider,
|
|
27
27
|
notifyFn = notify,
|
|
@@ -39,7 +39,7 @@ export async function notificationPhase(ctx, state) {
|
|
|
39
39
|
level: 'story',
|
|
40
40
|
epicId,
|
|
41
41
|
},
|
|
42
|
-
{
|
|
42
|
+
{ config },
|
|
43
43
|
);
|
|
44
44
|
// Fire a rolled-up `epic-progress` webhook so operators see the Epic's
|
|
45
45
|
// overall stories-done count tick up at each story-close, without
|
|
@@ -66,7 +66,7 @@ export async function notificationPhase(ctx, state) {
|
|
|
66
66
|
level: 'epic',
|
|
67
67
|
epicId,
|
|
68
68
|
},
|
|
69
|
-
{
|
|
69
|
+
{ config, skipComment: true },
|
|
70
70
|
);
|
|
71
71
|
} catch (err) {
|
|
72
72
|
logger?.warn?.(
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* phases/ticket-closure.js — post-merge ticket transition + cascade phase.
|
|
3
3
|
*
|
|
4
4
|
* Transitions the Story to `agent::done`, then runs cascade completion
|
|
5
|
-
* so any parent
|
|
5
|
+
* so any parent Epic-side rollup that is now fully resolved closes too.
|
|
6
6
|
*
|
|
7
|
-
* **
|
|
7
|
+
* **2-tier closure (Story #3127).** Under the 2-tier hierarchy a Story
|
|
8
8
|
* is the leaf unit of execution and has no child tickets — `tasks`
|
|
9
9
|
* arrives as an empty array. `batchTransitionTickets` handles the empty
|
|
10
10
|
* input cleanly (the loop trivially completes), the Story is
|
|
11
11
|
* transitioned alone, and cascade completion walks upward to
|
|
12
|
-
*
|
|
12
|
+
* parent. No branch on hierarchy mode is required here.
|
|
13
13
|
*
|
|
14
14
|
* Notifications are intentionally
|
|
15
15
|
* NOT routed through the per-ticket transitions here — `notificationPhase`
|
|
@@ -54,9 +54,9 @@ function findStillRegisteredEntry(entries, storyId) {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function resolveWorktreeRoot(repoRoot,
|
|
57
|
+
function resolveWorktreeRoot(repoRoot, delivery) {
|
|
58
58
|
if (!repoRoot) return null;
|
|
59
|
-
const configuredRoot =
|
|
59
|
+
const configuredRoot = delivery?.worktreeIsolation?.root ?? '.worktrees';
|
|
60
60
|
return path.join(repoRoot, configuredRoot);
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -263,7 +263,7 @@ function logStaleRegistryEntry({ state, stillRegistered, logger }) {
|
|
|
263
263
|
|
|
264
264
|
export async function worktreeReapPhase(ctx) {
|
|
265
265
|
const {
|
|
266
|
-
|
|
266
|
+
delivery,
|
|
267
267
|
storyId,
|
|
268
268
|
epicId,
|
|
269
269
|
epicBranch,
|
|
@@ -276,7 +276,7 @@ export async function worktreeReapPhase(ctx) {
|
|
|
276
276
|
recordPendingCleanupFn = recordPendingCleanup,
|
|
277
277
|
pathExistsFn = fs.existsSync,
|
|
278
278
|
} = ctx;
|
|
279
|
-
const wtConfig =
|
|
279
|
+
const wtConfig = delivery?.worktreeIsolation;
|
|
280
280
|
const log = reapPhaseLogger(progress);
|
|
281
281
|
const skipState = resolveSkipState(wtConfig, log);
|
|
282
282
|
if (skipState) return skipState;
|
|
@@ -309,7 +309,7 @@ export async function worktreeReapPhase(ctx) {
|
|
|
309
309
|
stillRegistered,
|
|
310
310
|
reapResult,
|
|
311
311
|
storyId,
|
|
312
|
-
|
|
312
|
+
delivery,
|
|
313
313
|
repoRoot,
|
|
314
314
|
logger,
|
|
315
315
|
recordPendingCleanupFn,
|
|
@@ -352,7 +352,7 @@ function applyStillRegisteredState({
|
|
|
352
352
|
stillRegistered,
|
|
353
353
|
reapResult,
|
|
354
354
|
storyId,
|
|
355
|
-
|
|
355
|
+
delivery,
|
|
356
356
|
repoRoot,
|
|
357
357
|
logger,
|
|
358
358
|
recordPendingCleanupFn,
|
|
@@ -370,7 +370,7 @@ function applyStillRegisteredState({
|
|
|
370
370
|
reason: 'still-registered-after-reap',
|
|
371
371
|
};
|
|
372
372
|
}
|
|
373
|
-
const worktreeRoot = resolveWorktreeRoot(repoRoot,
|
|
373
|
+
const worktreeRoot = resolveWorktreeRoot(repoRoot, delivery);
|
|
374
374
|
let manifestEntry = null;
|
|
375
375
|
if (worktreeRoot) {
|
|
376
376
|
try {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Cache adapter for the snapshot/DAG envelope produced by
|
|
5
5
|
* `epic-deliver-preflight.js` so `epic-deliver-prepare.js` can skip the
|
|
6
|
-
* second walk of Epic →
|
|
6
|
+
* second walk of Epic → Story when the underlying Epic ticket
|
|
7
7
|
* has not drifted between the two operator invocations.
|
|
8
8
|
*
|
|
9
9
|
* Contract:
|
|
@@ -53,28 +53,51 @@ export function preflightCachePath({ epicId, cwd }) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* Per-ticket fingerprint fields shared by the Epic and each Story in the
|
|
57
|
+
* cache key: id, body, sorted labels, and updatedAt. Story bodies carry
|
|
58
|
+
* the dependency edges, so hashing them means a Story-dependency edit
|
|
59
|
+
* forces a cache miss (Story #4019 — the previous Epic-only key let
|
|
60
|
+
* dependency edits slip through unnoticed).
|
|
61
|
+
*
|
|
62
|
+
* @param {{ id?: number|string, number?: number|string, body?: string, labels?: string[], updatedAt?: string }} ticket
|
|
63
|
+
* @returns {{ id: number|string|null, body: string, labels: string[], updatedAt: string|null }}
|
|
64
|
+
*/
|
|
65
|
+
function ticketFingerprint(ticket) {
|
|
66
|
+
const t = ticket && typeof ticket === 'object' ? ticket : {};
|
|
67
|
+
return {
|
|
68
|
+
id: t.id ?? t.number ?? null,
|
|
69
|
+
body: typeof t.body === 'string' ? t.body : '',
|
|
70
|
+
labels: Array.isArray(t.labels) ? [...t.labels].map(String).sort() : [],
|
|
71
|
+
updatedAt: typeof t.updatedAt === 'string' ? t.updatedAt : null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Stable string fingerprint of an Epic snapshot **plus its Story
|
|
77
|
+
* dependency state**. The hash is keyed on the exact fields
|
|
78
|
+
* `runSnapshotPhase` reads (`getTicket(epicId)` return value) and on each
|
|
79
|
+
* Story's id/body/labels/updatedAt, so that any drift the snapshot or
|
|
80
|
+
* wave-DAG phases would observe — including a Story-dependency edit —
|
|
81
|
+
* forces a cache miss (Story #4019).
|
|
59
82
|
*
|
|
60
83
|
* Labels are sorted to absorb GitHub's non-deterministic label order
|
|
61
|
-
* across responses
|
|
84
|
+
* across responses; stories are sorted by id so enumeration order never
|
|
85
|
+
* perturbs the key. The hash is sha256; we return the full hex digest so
|
|
62
86
|
* the cache key is collision-resistant for the lifetime of a delivery.
|
|
63
87
|
*
|
|
64
88
|
* @param {{ id?: number|string, number?: number|string, body?: string, labels?: string[], updatedAt?: string }} epic
|
|
89
|
+
* @param {Array<{ id?: number|string, number?: number|string, body?: string, labels?: string[], updatedAt?: string }>} [stories]
|
|
65
90
|
* @returns {string}
|
|
66
91
|
*/
|
|
67
|
-
export function computeBaseSha(epic) {
|
|
92
|
+
export function computeBaseSha(epic, stories = []) {
|
|
68
93
|
if (!epic || typeof epic !== 'object') {
|
|
69
94
|
throw new TypeError('computeBaseSha: epic snapshot must be an object');
|
|
70
95
|
}
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const updatedAt = typeof epic.updatedAt === 'string' ? epic.updatedAt : null;
|
|
77
|
-
const payload = JSON.stringify({ id, body, labels, updatedAt });
|
|
96
|
+
const epicPrint = ticketFingerprint(epic);
|
|
97
|
+
const storyPrints = (Array.isArray(stories) ? stories : [])
|
|
98
|
+
.map(ticketFingerprint)
|
|
99
|
+
.sort((a, b) => Number(a.id ?? 0) - Number(b.id ?? 0));
|
|
100
|
+
const payload = JSON.stringify({ ...epicPrint, stories: storyPrints });
|
|
78
101
|
return createHash('sha256').update(payload).digest('hex');
|
|
79
102
|
}
|
|
80
103
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `close-validate.end` `emitted` records and groups them by `failedGate`.
|
|
7
7
|
* Returns one finding per gate that appears in **two or more distinct
|
|
8
8
|
* Stories** within the same Epic. Findings are the substrate
|
|
9
|
-
* `/
|
|
9
|
+
* `/deliver` consumes when upserting the cross-Story
|
|
10
10
|
* `recurring-failure-class` structured comment on the Epic ticket.
|
|
11
11
|
*
|
|
12
12
|
* The helper is intentionally pure: no GitHub I/O, no global state. It
|
|
@@ -328,7 +328,7 @@ function followOnBody(s) {
|
|
|
328
328
|
``,
|
|
329
329
|
`Trigger: ${trigger}.`,
|
|
330
330
|
``,
|
|
331
|
-
`Apply the meta::framework-gap label so /
|
|
331
|
+
`Apply the meta::framework-gap label so /plan Phase 0 surfaces it on the next planning pass.`,
|
|
332
332
|
].join('\n');
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -130,8 +130,8 @@ async function warnIfEpicLooksPopulated({ epicId, provider, logger }) {
|
|
|
130
130
|
* `logger` so the silent failure becomes visible. Probe failure degrades
|
|
131
131
|
* gracefully — the function never throws on the guard alone.
|
|
132
132
|
*
|
|
133
|
-
* **
|
|
134
|
-
* hierarchy (Epic →
|
|
133
|
+
* **2-tier ledgers (Story #3151, Story #3200).** Under the 2-tier
|
|
134
|
+
* hierarchy (Epic → Story; no Task-tier children), `friction`
|
|
135
135
|
* / `parked` / `recuts` / `storyPerfSummaries` are all Story-scoped, so
|
|
136
136
|
* the function continues to produce a non-empty signals report. The
|
|
137
137
|
* empty-walk guard above is **not** triggered for this shape because
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Story #1155 (Epic #1142, 5.40.0) — extracts the helper-driven
|
|
5
5
|
* `epic-retro` invocation into a callable module so the
|
|
6
|
-
* `/
|
|
6
|
+
* `/deliver` runner can fire Phase E without a separate LLM
|
|
7
7
|
* helper turn. (Story #2259, Epic #2172: the legacy deliver-runner
|
|
8
8
|
* CLI was retired once delivery moved entirely into the slash
|
|
9
|
-
* command.) The retro fires before `/
|
|
9
|
+
* command.) The retro fires before `/deliver`'s finalize step
|
|
10
10
|
* opens the PR — the operator's PR-merge is the final human gate, not
|
|
11
11
|
* the retro itself.
|
|
12
12
|
*
|
|
@@ -56,7 +56,7 @@ export { gatherRetroSignals } from './retro/phases/gather-signals.js';
|
|
|
56
56
|
/**
|
|
57
57
|
* Public: compose and post the retro structured comment on the Epic.
|
|
58
58
|
*
|
|
59
|
-
* Story #1290 (Epic #1143) — at /
|
|
59
|
+
* Story #1290 (Epic #1143) — at /deliver Phase 5, the runner invokes
|
|
60
60
|
* the self-healing checks registry with `scope: 'retro'` and
|
|
61
61
|
* `autoFix: false`. The retro is **read-only by construction**: the
|
|
62
62
|
* registry runner enforces the invariant by throwing if any caller flips
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* is enumerated).
|
|
23
23
|
* - `standard` — everything else, including absent/malformed risk envelopes
|
|
24
24
|
* and a `medium` level. Fail toward the middle, never toward
|
|
25
|
-
* `light`: an Epic that skipped `/
|
|
25
|
+
* `light`: an Epic that skipped `/plan` has no risk
|
|
26
26
|
* verdict, and treating it as `light` would under-review
|
|
27
27
|
* unjudged work while `standard` preserves today's behaviour.
|
|
28
28
|
*
|
|
@@ -31,6 +31,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
31
31
|
import fs from 'node:fs';
|
|
32
32
|
import os from 'node:os';
|
|
33
33
|
import path from 'node:path';
|
|
34
|
+
import { parseProviderFindings } from './parse-findings.js';
|
|
34
35
|
import { renderDepthDirective } from './review-depth.js';
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -173,66 +174,10 @@ export function mapCodexSeverity(raw) {
|
|
|
173
174
|
* @throws {Error} when stdout is not parseable JSON.
|
|
174
175
|
*/
|
|
175
176
|
export function parseCodexFindings(rawStdout) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
try {
|
|
181
|
-
parsed = JSON.parse(text);
|
|
182
|
-
} catch (err) {
|
|
183
|
-
throw new Error(
|
|
184
|
-
`[codex-review] Failed to parse /codex:review stdout as JSON: ${
|
|
185
|
-
err?.message ?? err
|
|
186
|
-
}`,
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Unwrap a single layer of envelope when present.
|
|
191
|
-
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
192
|
-
if (Array.isArray(parsed.findings)) parsed = parsed.findings;
|
|
193
|
-
else if (parsed.result !== undefined) parsed = parsed.result;
|
|
194
|
-
else if (parsed.data !== undefined) parsed = parsed.data;
|
|
195
|
-
}
|
|
196
|
-
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
197
|
-
if (Array.isArray(parsed.findings)) parsed = parsed.findings;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (!Array.isArray(parsed)) return [];
|
|
201
|
-
|
|
202
|
-
/** @type {Finding[]} */
|
|
203
|
-
const findings = [];
|
|
204
|
-
for (const entry of parsed) {
|
|
205
|
-
if (!entry || typeof entry !== 'object') continue;
|
|
206
|
-
const title =
|
|
207
|
-
typeof entry.title === 'string' && entry.title.trim().length > 0
|
|
208
|
-
? entry.title.trim()
|
|
209
|
-
: null;
|
|
210
|
-
const body =
|
|
211
|
-
typeof entry.body === 'string' && entry.body.trim().length > 0
|
|
212
|
-
? entry.body
|
|
213
|
-
: typeof entry.message === 'string' && entry.message.trim().length > 0
|
|
214
|
-
? entry.message
|
|
215
|
-
: null;
|
|
216
|
-
if (!title || !body) continue;
|
|
217
|
-
|
|
218
|
-
/** @type {Finding} */
|
|
219
|
-
const finding = {
|
|
220
|
-
severity: mapCodexSeverity(entry.severity),
|
|
221
|
-
title,
|
|
222
|
-
body,
|
|
223
|
-
};
|
|
224
|
-
if (typeof entry.file === 'string' && entry.file.length > 0) {
|
|
225
|
-
finding.file = entry.file;
|
|
226
|
-
}
|
|
227
|
-
if (Number.isInteger(entry.line) && entry.line > 0) {
|
|
228
|
-
finding.line = entry.line;
|
|
229
|
-
}
|
|
230
|
-
if (typeof entry.category === 'string' && entry.category.length > 0) {
|
|
231
|
-
finding.category = entry.category;
|
|
232
|
-
}
|
|
233
|
-
findings.push(finding);
|
|
234
|
-
}
|
|
235
|
-
return findings;
|
|
177
|
+
return parseProviderFindings(rawStdout, {
|
|
178
|
+
errorPrefix: '[codex-review] Failed to parse /codex:review stdout as JSON',
|
|
179
|
+
mapSeverity: mapCodexSeverity,
|
|
180
|
+
});
|
|
236
181
|
}
|
|
237
182
|
|
|
238
183
|
/**
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
|
|
43
43
|
import { spawnSync } from 'node:child_process';
|
|
44
44
|
import path from 'node:path';
|
|
45
|
-
import {
|
|
46
|
-
import { runOnPool } from '../../cpu-pool.js';
|
|
45
|
+
import { POOL_SERIAL_THRESHOLD, runOnPool } from '../../cpu-pool.js';
|
|
47
46
|
import { gitSpawn } from '../../git-utils.js';
|
|
48
47
|
import {
|
|
49
48
|
calculateReport,
|
|
50
49
|
classifyReport,
|
|
51
50
|
} from '../../maintainability-engine.js';
|
|
52
|
-
import {
|
|
51
|
+
import { PROJECT_ROOT } from '../../project-root.js';
|
|
52
|
+
import { transpileIfNeeded } from '../../transpile.js';
|
|
53
53
|
import {
|
|
54
54
|
hashCommandConfig,
|
|
55
55
|
recordPass,
|
|
@@ -67,10 +67,11 @@ const MAINTAINABILITY_REPORT_WORKER_URL = new URL(
|
|
|
67
67
|
* `analyzeChangedFiles` scores in-process (the pre-pool serial path). At or
|
|
68
68
|
* above it, per-file `calculateReportForFile` scoring is offloaded to the
|
|
69
69
|
* shared worker pool so the event loop is not blocked during epic-scoped
|
|
70
|
-
* reviews (f-performance).
|
|
71
|
-
*
|
|
70
|
+
* reviews (f-performance). Single-sourced in `cpu-pool.js` (see the
|
|
71
|
+
* `POOL_SERIAL_THRESHOLD` docstring for the tuning rationale); the
|
|
72
|
+
* `SERIAL_THRESHOLD` export name is preserved as this module's public API.
|
|
72
73
|
*/
|
|
73
|
-
export const SERIAL_THRESHOLD =
|
|
74
|
+
export const SERIAL_THRESHOLD = POOL_SERIAL_THRESHOLD;
|
|
74
75
|
|
|
75
76
|
const JS_MAINTAINABILITY_EXTS = new Set(['.js', '.mjs', '.cjs']);
|
|
76
77
|
|