mandrel 2.0.0 → 2.2.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 -28
- package/.agents/agents/acceptance-critic.md +20 -9
- package/.agents/agents/story-worker.md +45 -48
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +60 -46
- package/.agents/docs/agentrc-reference.json +8 -13
- package/.agents/docs/configuration.md +33 -57
- package/.agents/docs/execution-reference.md +39 -10
- package/.agents/docs/quality-gates.md +17 -19
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +64 -79
- package/.agents/rules/ci-remediation.md +3 -3
- package/.agents/rules/gherkin-standards.md +10 -0
- package/.agents/rules/git-conventions-reference.md +42 -51
- package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
- package/.agents/schemas/agentrc.schema.json +35 -46
- package/.agents/schemas/audit-rules.json +59 -1
- package/.agents/schemas/audit-rules.schema.json +33 -1
- package/.agents/schemas/lifecycle/README.md +1 -2
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
- package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
- package/.agents/schemas/signal-event.schema.json +3 -3
- package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +24 -68
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/bootstrap.js +3 -3
- package/.agents/scripts/check-dead-exports.js +43 -104
- package/.agents/scripts/check-doc-links.js +2 -2
- package/.agents/scripts/check-lifecycle-lint.js +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/deliver-recover.js +122 -0
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +20 -50
- package/.agents/scripts/generate-skills-index.js +17 -1
- package/.agents/scripts/generate-workflows-doc.js +4 -4
- package/.agents/scripts/lib/ITicketingProvider.js +1 -19
- package/.agents/scripts/lib/audit-suite/selector.js +323 -23
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
- package/.agents/scripts/lib/checks/index.js +1 -1
- package/.agents/scripts/lib/checks/loop-health.js +12 -11
- package/.agents/scripts/lib/checks/state.js +17 -248
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
- package/.agents/scripts/lib/cli-args.js +23 -2
- package/.agents/scripts/lib/close-validation/gates.js +13 -13
- package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
- package/.agents/scripts/lib/close-validation/runner.js +13 -21
- package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
- package/.agents/scripts/lib/config/acceptance-eval.js +2 -2
- package/.agents/scripts/lib/config/delivery-routing.js +7 -6
- package/.agents/scripts/lib/config/explain.js +10 -16
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +15 -25
- package/.agents/scripts/lib/config/quality.js +11 -14
- package/.agents/scripts/lib/config/runners.js +8 -21
- package/.agents/scripts/lib/config/temp-paths.js +18 -56
- package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
- package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
- package/.agents/scripts/lib/config-settings-schema.js +48 -22
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/duplicate-search.js +38 -7
- package/.agents/scripts/lib/findings/promote-finding.js +23 -14
- package/.agents/scripts/lib/format-generated-json.js +97 -0
- package/.agents/scripts/lib/framework-version.js +19 -189
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
- package/.agents/scripts/lib/git-utils.js +0 -14
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +0 -15
- package/.agents/scripts/lib/label-taxonomy.js +1 -12
- package/.agents/scripts/lib/observability/active-story-env.js +42 -163
- package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
- package/.agents/scripts/lib/observability/signal-validator.js +4 -4
- package/.agents/scripts/lib/observability/signals-writer.js +6 -82
- package/.agents/scripts/lib/observability/source-classifier.js +2 -2
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
- package/.agents/scripts/lib/orchestration/change-set.js +103 -0
- package/.agents/scripts/lib/orchestration/code-review.js +70 -191
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
- package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
- package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
- package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
- package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
- package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
- package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +4 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
- package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
- package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
- package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
- package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
- package/.agents/scripts/lib/planning-corpus.js +12 -286
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
- package/.agents/scripts/lib/signals/index.js +4 -17
- package/.agents/scripts/lib/signals/read.js +35 -35
- package/.agents/scripts/lib/signals/schema.js +8 -11
- package/.agents/scripts/lib/signals/span-tree.js +7 -7
- package/.agents/scripts/lib/signals/write.js +0 -1
- package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +8 -7
- package/.agents/scripts/lib/story-body/story-body.js +81 -13
- package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/ticket-body-sections.js +0 -14
- package/.agents/scripts/lib/validation-evidence.js +31 -59
- package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/plan-context.js +38 -7
- package/.agents/scripts/plan-critics.js +203 -0
- package/.agents/scripts/plan-persist.js +145 -35
- package/.agents/scripts/plan-run-epilogue.js +83 -38
- package/.agents/scripts/post-structured-comment.js +0 -38
- package/.agents/scripts/pr-watch-with-update.js +43 -22
- package/.agents/scripts/providers/github/compose.js +0 -1
- package/.agents/scripts/providers/github/errors.js +0 -19
- package/.agents/scripts/providers/github/issues.js +1 -11
- package/.agents/scripts/providers/github/mappers.js +5 -0
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -153
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/quality-preview.js +13 -6
- package/.agents/scripts/resolve-stories.js +236 -0
- package/.agents/scripts/run-coverage.js +4 -1
- package/.agents/scripts/run-lint.js +2 -2
- package/.agents/scripts/run-verify.js +31 -2
- package/.agents/scripts/signals-view.js +9 -10
- package/.agents/scripts/single-story-close.js +173 -18
- package/.agents/scripts/single-story-confirm-merge.js +288 -15
- package/.agents/scripts/single-story-init.js +6 -10
- package/.agents/scripts/stories-wave-tick.js +380 -53
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/update-ticket-state.js +8 -50
- package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
- package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
- package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
- package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
- package/.agents/skills/core/scope-triage/SKILL.md +3 -0
- package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
- package/.agents/skills/core/security-and-hardening/reference.md +375 -0
- package/.agents/skills/skills.index.json +2 -12
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
- package/.agents/workflows/audit-architecture.md +3 -4
- package/.agents/workflows/audit-clean-code.md +4 -4
- package/.agents/workflows/audit-documentation.md +4 -5
- package/.agents/workflows/audit-lighthouse.md +8 -0
- package/.agents/workflows/audit-navigability.md +10 -0
- package/.agents/workflows/audit-performance.md +2 -3
- package/.agents/workflows/audit-quality.md +8 -9
- package/.agents/workflows/audit-security.md +1 -2
- package/.agents/workflows/audit-seo.md +10 -0
- package/.agents/workflows/audit-ux-ui.md +7 -0
- package/.agents/workflows/deliver.md +133 -45
- package/.agents/workflows/git-cleanup.md +2 -2
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
- package/.agents/workflows/helpers/code-review.md +14 -12
- package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
- package/.agents/workflows/helpers/deliver-story.md +209 -118
- package/.agents/workflows/helpers/parallel-tooling.md +2 -2
- package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
- package/.agents/workflows/plan.md +239 -19
- package/.agents/workflows/qa-assist.md +6 -6
- package/.agents/workflows/qa-explore.md +3 -3
- package/.agents/workflows/qa-run.md +1 -5
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +62 -0
- package/lib/cli/registry.js +262 -19
- package/lib/cli/sync-agents.js +157 -0
- package/lib/cli/sync-commands.js +115 -6
- package/lib/cli/sync.js +168 -6
- package/lib/cli/update.js +105 -8
- package/lib/cli/version-helpers.js +131 -0
- package/lib/migrations/README.md +7 -5
- package/lib/migrations/index.js +17 -9
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
- package/package.json +2 -2
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -53
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
- package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
- package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
- package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
- package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
- package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
- package/.agents/scripts/resolve-plan-run.js +0 -117
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* story-run-progress-writer — render the per-story progress snapshot.
|
|
3
|
-
*
|
|
4
|
-
* Story #3909 — this module no longer **posts** a `story-run-progress`
|
|
5
|
-
* structured comment. That per-Story comment was the redundant mid-flight
|
|
6
|
-
* progress surface: an Epic run already keeps the operator-facing
|
|
7
|
-
* `epic-run-progress` rollup (one comment on the Epic) plus the
|
|
8
|
-
* `epic-run-state` checkpoint and the lifecycle ledger, and the rollup is
|
|
9
|
-
* rendered from the checkpoint `waves[]` — it never read the per-Story
|
|
10
|
-
* comment. The per-Story comment fired at five phase transitions each and
|
|
11
|
-
* duplicated state already on the labels + ledger, so the comment write was
|
|
12
|
-
* removed.
|
|
13
|
-
*
|
|
14
|
-
* The renderer survives because its `{ body, payload }` output still feeds
|
|
15
|
-
* two non-comment contracts: the `renderedBody` markdown the `/deliver`
|
|
16
|
-
* workflow (`helpers/deliver-story.md`, `story-phase.js`) relays to chat so
|
|
17
|
-
* the operator sees the phase table inline, and the snapshot payload returned
|
|
18
|
-
* in those CLIs' JSON envelopes. `upsertStoryRunProgress`
|
|
19
|
-
* therefore renders-only: it computes the body/payload and (optionally) mirrors
|
|
20
|
-
* a low-severity webhook event, but writes no GitHub comment.
|
|
21
|
-
*
|
|
22
|
-
* Payload shape — per tech spec #902 (kept stable; the CLI envelopes carry it
|
|
23
|
-
* verbatim):
|
|
24
|
-
*
|
|
25
|
-
* {
|
|
26
|
-
* "kind": "story-run-progress",
|
|
27
|
-
* "storyId": <number>,
|
|
28
|
-
* "branch": "story-<id>",
|
|
29
|
-
* "phase": "init|implementing|closing|blocked|done",
|
|
30
|
-
* "tasks": [
|
|
31
|
-
* { "id": <n>, "title": "...", "state": "done", "commitSha": "abc1234" },
|
|
32
|
-
* { "id": <n>, "title": "...", "state": "executing" },
|
|
33
|
-
* { "id": <n>, "title": "...", "state": "pending" }
|
|
34
|
-
* ],
|
|
35
|
-
* "updatedAt": "<iso8601>"
|
|
36
|
-
* }
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
export const STORY_RUN_PROGRESS_TYPE = 'story-run-progress';
|
|
40
|
-
|
|
41
|
-
const VALID_TASK_STATES = new Set([
|
|
42
|
-
'pending',
|
|
43
|
-
'executing',
|
|
44
|
-
'done',
|
|
45
|
-
'blocked',
|
|
46
|
-
'failed',
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
const VALID_PHASES = new Set([
|
|
50
|
-
'init',
|
|
51
|
-
'implementing',
|
|
52
|
-
'closing',
|
|
53
|
-
'blocked',
|
|
54
|
-
'done',
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
const TASK_STATE_EMOJI = {
|
|
58
|
-
pending: '⏳',
|
|
59
|
-
executing: '🔧',
|
|
60
|
-
done: '✅',
|
|
61
|
-
blocked: '🚧',
|
|
62
|
-
failed: '❌',
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const PHASE_EMOJI = {
|
|
66
|
-
init: '🌱',
|
|
67
|
-
implementing: '🔧',
|
|
68
|
-
closing: '🔒',
|
|
69
|
-
blocked: '🚧',
|
|
70
|
-
done: '✅',
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Canonical 2-tier Story-phase order. The Story-phase snapshot replaces the
|
|
75
|
-
* 4-tier per-Task list when the Story carries inline acceptance (no child
|
|
76
|
-
* Tasks). Each entry tracks `status` + `startedAt` / `endedAt` so the parent
|
|
77
|
-
* `/deliver` aggregator can render a coarse progress bar without
|
|
78
|
-
* walking Task tickets.
|
|
79
|
-
*/
|
|
80
|
-
export const STORY_PHASE_ORDER = ['init', 'implement', 'validate', 'close'];
|
|
81
|
-
|
|
82
|
-
const VALID_STORY_PHASE_STATUS = new Set(['pending', 'in-progress', 'done']);
|
|
83
|
-
|
|
84
|
-
const STORY_PHASE_STATUS_EMOJI = {
|
|
85
|
-
pending: '⏳',
|
|
86
|
-
'in-progress': '🔧',
|
|
87
|
-
done: '✅',
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Build the canonical default `phases[]` array for a freshly-initialized
|
|
92
|
-
* 2-tier Story snapshot. All entries are `pending`; timestamps are null.
|
|
93
|
-
* Exported so call sites (the story-init prepare step, story-phase) and
|
|
94
|
-
* tests can build the same shape without re-implementing it.
|
|
95
|
-
*
|
|
96
|
-
* @returns {Array<{ name: string, status: 'pending', startedAt: null, endedAt: null }>}
|
|
97
|
-
*/
|
|
98
|
-
export function defaultStoryPhases() {
|
|
99
|
-
return STORY_PHASE_ORDER.map((name) => ({
|
|
100
|
-
name,
|
|
101
|
-
status: 'pending',
|
|
102
|
-
startedAt: null,
|
|
103
|
-
endedAt: null,
|
|
104
|
-
}));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Normalize one Story-phase row into the canonical schema. Timestamps may be
|
|
109
|
-
* `null` (phase not yet started) or ISO-8601 strings; status is one of
|
|
110
|
-
* pending | in-progress | done.
|
|
111
|
-
*
|
|
112
|
-
* @param {object} phase
|
|
113
|
-
* @returns {object}
|
|
114
|
-
*/
|
|
115
|
-
function normalizeStoryPhase(phase) {
|
|
116
|
-
if (!phase || typeof phase !== 'object') {
|
|
117
|
-
throw new TypeError('story-run-progress phase rows must be objects');
|
|
118
|
-
}
|
|
119
|
-
const name = String(phase.name ?? '');
|
|
120
|
-
if (!STORY_PHASE_ORDER.includes(name)) {
|
|
121
|
-
throw new RangeError(
|
|
122
|
-
`story-run-progress invalid phase name "${name}"; ` +
|
|
123
|
-
`expected one of: ${STORY_PHASE_ORDER.join(', ')}`,
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
const status = String(phase.status ?? 'pending');
|
|
127
|
-
if (!VALID_STORY_PHASE_STATUS.has(status)) {
|
|
128
|
-
throw new RangeError(
|
|
129
|
-
`story-run-progress invalid phase status "${status}" for "${name}"; ` +
|
|
130
|
-
`expected one of: ${[...VALID_STORY_PHASE_STATUS].join(', ')}`,
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
name,
|
|
135
|
-
status,
|
|
136
|
-
startedAt: phase.startedAt == null ? null : String(phase.startedAt),
|
|
137
|
-
endedAt: phase.endedAt == null ? null : String(phase.endedAt),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Normalize one Task row into the canonical schema. `commitSha` is only
|
|
143
|
-
* carried on `done` rows (it has no meaning before the commit lands and is
|
|
144
|
-
* cleared on rollback).
|
|
145
|
-
*
|
|
146
|
-
* @param {object} task
|
|
147
|
-
* @returns {object}
|
|
148
|
-
*/
|
|
149
|
-
function normalizeTask(task) {
|
|
150
|
-
if (!task || typeof task !== 'object') {
|
|
151
|
-
throw new TypeError('story-run-progress task rows must be objects');
|
|
152
|
-
}
|
|
153
|
-
const id = Number(task.id ?? task.taskId);
|
|
154
|
-
if (!Number.isInteger(id) || id <= 0) {
|
|
155
|
-
throw new TypeError(
|
|
156
|
-
`story-run-progress task row missing valid id: ${JSON.stringify(task)}`,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
const state = String(task.state ?? 'pending');
|
|
160
|
-
if (!VALID_TASK_STATES.has(state)) {
|
|
161
|
-
throw new RangeError(
|
|
162
|
-
`story-run-progress invalid task state "${state}" for task #${id}; ` +
|
|
163
|
-
`expected one of: ${[...VALID_TASK_STATES].join(', ')}`,
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
const row = { id, title: String(task.title ?? ''), state };
|
|
167
|
-
if (state === 'done' && task.commitSha != null) {
|
|
168
|
-
row.commitSha = String(task.commitSha);
|
|
169
|
-
}
|
|
170
|
-
return row;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Build the markdown body the writer upserts. Pure: no IO, no provider call.
|
|
175
|
-
* Exported so tests can pin the rendered shape without going through the
|
|
176
|
-
* upsert path.
|
|
177
|
-
*
|
|
178
|
-
* Two shapes are supported, selected by whether `input.phases` (2-tier
|
|
179
|
-
* Story-phase snapshot) or `input.tasks` (legacy 4-tier per-Task list) is
|
|
180
|
-
* provided. Callers MUST pass exactly one of the two — passing both is
|
|
181
|
-
* rejected as a contract violation so a mistake at the call site fails
|
|
182
|
-
* loudly rather than silently dropping one shape.
|
|
183
|
-
*
|
|
184
|
-
* @param {{
|
|
185
|
-
* storyId: number,
|
|
186
|
-
* branch: string,
|
|
187
|
-
* phase: string,
|
|
188
|
-
* tasks?: object[],
|
|
189
|
-
* phases?: object[],
|
|
190
|
-
* updatedAt?: string,
|
|
191
|
-
* }} input
|
|
192
|
-
* @returns {{ body: string, payload: object }}
|
|
193
|
-
*/
|
|
194
|
-
export function renderStoryRunProgressBody(input) {
|
|
195
|
-
const storyId = Number(input?.storyId);
|
|
196
|
-
if (!Number.isInteger(storyId) || storyId <= 0) {
|
|
197
|
-
throw new TypeError(
|
|
198
|
-
'renderStoryRunProgressBody requires a numeric storyId',
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
const branch = String(input?.branch ?? '');
|
|
202
|
-
if (!branch) {
|
|
203
|
-
throw new TypeError(
|
|
204
|
-
'renderStoryRunProgressBody requires a non-empty branch',
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
const phase = String(input?.phase ?? '');
|
|
208
|
-
if (!VALID_PHASES.has(phase)) {
|
|
209
|
-
throw new RangeError(
|
|
210
|
-
`renderStoryRunProgressBody invalid phase "${phase}"; ` +
|
|
211
|
-
`expected one of: ${[...VALID_PHASES].join(', ')}`,
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const hasPhases = Array.isArray(input.phases);
|
|
216
|
-
const hasTasks = Array.isArray(input.tasks);
|
|
217
|
-
if (hasPhases && hasTasks) {
|
|
218
|
-
throw new TypeError(
|
|
219
|
-
'renderStoryRunProgressBody: pass either `phases` (2-tier) or `tasks` ' +
|
|
220
|
-
'(4-tier), not both — the snapshot shape is mutually exclusive.',
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const updatedAt = input.updatedAt ?? new Date().toISOString();
|
|
225
|
-
|
|
226
|
-
if (hasPhases) {
|
|
227
|
-
return renderPhasesBody({
|
|
228
|
-
storyId,
|
|
229
|
-
branch,
|
|
230
|
-
phase,
|
|
231
|
-
phases: input.phases,
|
|
232
|
-
updatedAt,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
return renderTasksBody({
|
|
236
|
-
storyId,
|
|
237
|
-
branch,
|
|
238
|
-
phase,
|
|
239
|
-
tasks: input.tasks ?? [],
|
|
240
|
-
updatedAt,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Render the 4-tier per-Task body. Pure helper for `renderStoryRunProgressBody`.
|
|
246
|
-
*/
|
|
247
|
-
function renderTasksBody({
|
|
248
|
-
storyId,
|
|
249
|
-
branch,
|
|
250
|
-
phase,
|
|
251
|
-
tasks: rawTasks,
|
|
252
|
-
updatedAt,
|
|
253
|
-
}) {
|
|
254
|
-
const tasks = rawTasks.map(normalizeTask);
|
|
255
|
-
const payload = {
|
|
256
|
-
kind: STORY_RUN_PROGRESS_TYPE,
|
|
257
|
-
storyId,
|
|
258
|
-
branch,
|
|
259
|
-
phase,
|
|
260
|
-
tasks,
|
|
261
|
-
updatedAt,
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const done = tasks.filter((t) => t.state === 'done').length;
|
|
265
|
-
const total = tasks.length;
|
|
266
|
-
const phaseEmoji = PHASE_EMOJI[phase] ?? '';
|
|
267
|
-
const header = `### 📖 Story #${storyId} — ${phaseEmoji} ${phase} · ${done}/${total} tasks done`;
|
|
268
|
-
const tableRows = tasks.length
|
|
269
|
-
? [
|
|
270
|
-
'| ID | State | Title | Commit |',
|
|
271
|
-
'| --- | --- | --- | --- |',
|
|
272
|
-
...tasks.map((t) => {
|
|
273
|
-
const emoji = TASK_STATE_EMOJI[t.state] ?? '';
|
|
274
|
-
const commit = t.commitSha
|
|
275
|
-
? `\`${String(t.commitSha).slice(0, 7)}\``
|
|
276
|
-
: '—';
|
|
277
|
-
const title = String(t.title).replace(/\|/g, '\\|');
|
|
278
|
-
return `| #${t.id} | ${emoji} ${t.state} | ${title} | ${commit} |`;
|
|
279
|
-
}),
|
|
280
|
-
].join('\n')
|
|
281
|
-
: '_(no tasks recorded for this story)_';
|
|
282
|
-
|
|
283
|
-
const body = [
|
|
284
|
-
header,
|
|
285
|
-
'',
|
|
286
|
-
`Branch: \`${branch}\``,
|
|
287
|
-
'',
|
|
288
|
-
tableRows,
|
|
289
|
-
'',
|
|
290
|
-
'```json',
|
|
291
|
-
JSON.stringify(payload, null, 2),
|
|
292
|
-
'```',
|
|
293
|
-
].join('\n');
|
|
294
|
-
|
|
295
|
-
return { body, payload };
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Render the 2-tier Story-phase body. Pure helper for
|
|
300
|
-
* `renderStoryRunProgressBody`. Emits a `phases[]` payload whose entries
|
|
301
|
-
* carry `{ name, status, startedAt, endedAt }` for init/implement/validate/close.
|
|
302
|
-
*/
|
|
303
|
-
function renderPhasesBody({ storyId, branch, phase, phases: raw, updatedAt }) {
|
|
304
|
-
const phases = raw.map(normalizeStoryPhase);
|
|
305
|
-
const payload = {
|
|
306
|
-
kind: STORY_RUN_PROGRESS_TYPE,
|
|
307
|
-
storyId,
|
|
308
|
-
branch,
|
|
309
|
-
phase,
|
|
310
|
-
phases,
|
|
311
|
-
updatedAt,
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
const done = phases.filter((p) => p.status === 'done').length;
|
|
315
|
-
const total = phases.length;
|
|
316
|
-
const phaseEmoji = PHASE_EMOJI[phase] ?? '';
|
|
317
|
-
const header = `### 📖 Story #${storyId} — ${phaseEmoji} ${phase} · ${done}/${total} phases done`;
|
|
318
|
-
const tableRows = phases.length
|
|
319
|
-
? [
|
|
320
|
-
'| Phase | Status | Started | Ended |',
|
|
321
|
-
'| --- | --- | --- | --- |',
|
|
322
|
-
...phases.map((p) => {
|
|
323
|
-
const emoji = STORY_PHASE_STATUS_EMOJI[p.status] ?? '';
|
|
324
|
-
const started = p.startedAt ?? '—';
|
|
325
|
-
const ended = p.endedAt ?? '—';
|
|
326
|
-
return `| ${p.name} | ${emoji} ${p.status} | ${started} | ${ended} |`;
|
|
327
|
-
}),
|
|
328
|
-
].join('\n')
|
|
329
|
-
: '_(no phases recorded for this story)_';
|
|
330
|
-
|
|
331
|
-
const body = [
|
|
332
|
-
header,
|
|
333
|
-
'',
|
|
334
|
-
`Branch: \`${branch}\``,
|
|
335
|
-
'',
|
|
336
|
-
tableRows,
|
|
337
|
-
'',
|
|
338
|
-
'```json',
|
|
339
|
-
JSON.stringify(payload, null, 2),
|
|
340
|
-
'```',
|
|
341
|
-
].join('\n');
|
|
342
|
-
|
|
343
|
-
return { body, payload };
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Render the story-run-progress snapshot for one phase transition and return
|
|
348
|
-
* `{ body, payload }` so callers can surface the markdown body to chat and
|
|
349
|
-
* carry the payload in their JSON envelope. Story #3909 — this no longer posts
|
|
350
|
-
* a GitHub comment (the redundant mid-flight progress surface was deleted); it
|
|
351
|
-
* renders only and, when `notify` is supplied, mirrors a low-severity webhook
|
|
352
|
-
* event for operators who wire one up.
|
|
353
|
-
*
|
|
354
|
-
* Two shapes are supported, selected by whether `args.phases` (2-tier
|
|
355
|
-
* Story-phase snapshot) or `args.tasks` (legacy 4-tier per-Task list) is
|
|
356
|
-
* provided. The webhook mirror's `done/total` count is computed from whichever
|
|
357
|
-
* shape is active.
|
|
358
|
-
*
|
|
359
|
-
* @param {{
|
|
360
|
-
* provider?: import('../../ITicketingProvider.js').ITicketingProvider,
|
|
361
|
-
* storyId: number,
|
|
362
|
-
* branch: string,
|
|
363
|
-
* phase: string,
|
|
364
|
-
* tasks?: object[],
|
|
365
|
-
* phases?: object[],
|
|
366
|
-
* epicId?: number,
|
|
367
|
-
* updatedAt?: string,
|
|
368
|
-
* notify?: Function,
|
|
369
|
-
* }} args
|
|
370
|
-
* @returns {Promise<{ body: string, payload: object }>}
|
|
371
|
-
*/
|
|
372
|
-
export async function upsertStoryRunProgress(args) {
|
|
373
|
-
const { notify, epicId, provider: _provider, ...rest } = args ?? {};
|
|
374
|
-
const { body, payload } = renderStoryRunProgressBody(rest);
|
|
375
|
-
if (typeof notify === 'function') {
|
|
376
|
-
const isPhases = Array.isArray(payload.phases);
|
|
377
|
-
const items = isPhases ? payload.phases : payload.tasks;
|
|
378
|
-
const done = isPhases
|
|
379
|
-
? items.filter((p) => p.status === 'done').length
|
|
380
|
-
: items.filter((t) => t.state === 'done').length;
|
|
381
|
-
const total = items.length;
|
|
382
|
-
const unit = isPhases ? 'phases' : 'tasks';
|
|
383
|
-
const message = `Story #${payload.storyId} · ${payload.phase} · ${done}/${total} ${unit} done`;
|
|
384
|
-
await Promise.resolve(
|
|
385
|
-
notify(
|
|
386
|
-
payload.storyId,
|
|
387
|
-
{
|
|
388
|
-
severity: 'low',
|
|
389
|
-
message,
|
|
390
|
-
event: STORY_RUN_PROGRESS_TYPE,
|
|
391
|
-
level: 'story',
|
|
392
|
-
epicId,
|
|
393
|
-
phase: payload.phase,
|
|
394
|
-
},
|
|
395
|
-
{ skipComment: true },
|
|
396
|
-
),
|
|
397
|
-
).catch(() => {});
|
|
398
|
-
}
|
|
399
|
-
return { body, payload };
|
|
400
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* confirm-merge-follow-ups.js — post-land follow-up capture seam for
|
|
3
|
-
* `single-story-confirm-merge.js` (keeps the CLI entry under the MI ceiling).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { captureFollowUpsAfterConfirm } from '../orchestration/story-follow-ups.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @param {object} args
|
|
10
|
-
* @param {object} args.confirmation
|
|
11
|
-
* @param {number} args.storyId
|
|
12
|
-
* @param {number|null} args.prNumber
|
|
13
|
-
* @param {object} args.provider
|
|
14
|
-
* @param {object} [args.config]
|
|
15
|
-
* @param {string} args.cwd
|
|
16
|
-
* @param {(tag: string, msg: string) => void} [args.progress]
|
|
17
|
-
* @returns {Promise<object>}
|
|
18
|
-
*/
|
|
19
|
-
export async function withConfirmFollowUps({
|
|
20
|
-
confirmation,
|
|
21
|
-
storyId,
|
|
22
|
-
prNumber,
|
|
23
|
-
provider,
|
|
24
|
-
config,
|
|
25
|
-
cwd,
|
|
26
|
-
progress,
|
|
27
|
-
}) {
|
|
28
|
-
const followUps = await captureFollowUpsAfterConfirm(confirmation, {
|
|
29
|
-
storyId,
|
|
30
|
-
provider,
|
|
31
|
-
config,
|
|
32
|
-
cwd,
|
|
33
|
-
progress,
|
|
34
|
-
});
|
|
35
|
-
return { standalone: true, prNumber, ...confirmation, followUps };
|
|
36
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* resolve-plan-run.js — resolve Stories labeled `plan-run::<id>` for
|
|
5
|
-
* `/deliver --run <planRunId>` (v2 Stage 4).
|
|
6
|
-
*
|
|
7
|
-
* Thin CLI over `lib/orchestration/resolve-plan-run.js`.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* node .agents/scripts/resolve-plan-run.js --run <planRunId>
|
|
11
|
-
* node .agents/scripts/resolve-plan-run.js --run <planRunId> --state all
|
|
12
|
-
* node .agents/scripts/resolve-plan-run.js --run <planRunId> --pretty
|
|
13
|
-
*
|
|
14
|
-
* Exit codes: 0 ok, 1 usage/error, 2 no Stories found for the run.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { parseArgs } from 'node:util';
|
|
18
|
-
|
|
19
|
-
import { runAsCli } from './lib/cli-utils.js';
|
|
20
|
-
import { resolveConfig } from './lib/config-resolver.js';
|
|
21
|
-
import {
|
|
22
|
-
assertIssueState,
|
|
23
|
-
buildPlanRunEnvelope,
|
|
24
|
-
fetchPlanRunIssues,
|
|
25
|
-
normalizePlanRunLabel,
|
|
26
|
-
planRunIdFromLabel,
|
|
27
|
-
resolvePlanRunFromIssues,
|
|
28
|
-
} from './lib/orchestration/resolve-plan-run.js';
|
|
29
|
-
import { createProvider } from './lib/provider-factory.js';
|
|
30
|
-
|
|
31
|
-
export {
|
|
32
|
-
buildPlanRunEnvelope,
|
|
33
|
-
fetchPlanRunIssues,
|
|
34
|
-
normalizePlanRunLabel,
|
|
35
|
-
planRunIdFromLabel,
|
|
36
|
-
resolvePlanRunFromIssues,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const HELP = `\
|
|
40
|
-
Usage:
|
|
41
|
-
resolve-plan-run.js --run <planRunId> [--state open|all|closed] [--pretty]
|
|
42
|
-
|
|
43
|
-
Resolve Stories labeled plan-run::<planRunId> for /deliver --run.
|
|
44
|
-
|
|
45
|
-
Options:
|
|
46
|
-
--run <id> Plan-run token (with or without the plan-run:: prefix).
|
|
47
|
-
--state <s> Issue state filter (default: open).
|
|
48
|
-
--pretty Pretty-print the JSON envelope.
|
|
49
|
-
--help Show this help.
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
|
-
function writeEnvelope(envelope, pretty) {
|
|
53
|
-
const text = pretty
|
|
54
|
-
? `${JSON.stringify(envelope, null, 2)}\n`
|
|
55
|
-
: `${JSON.stringify(envelope)}\n`;
|
|
56
|
-
process.stdout.write(text);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Resolve config once and pass it to the provider factory. Kept as an
|
|
61
|
-
* injectable seam so the CLI contract is covered without network access.
|
|
62
|
-
*
|
|
63
|
-
* @param {object} [deps]
|
|
64
|
-
* @param {Function} [deps.resolveConfigFn]
|
|
65
|
-
* @param {Function} [deps.createProviderFn]
|
|
66
|
-
* @returns {object}
|
|
67
|
-
*/
|
|
68
|
-
export function resolvePlanRunProvider({
|
|
69
|
-
resolveConfigFn = resolveConfig,
|
|
70
|
-
createProviderFn = createProvider,
|
|
71
|
-
} = {}) {
|
|
72
|
-
const config = resolveConfigFn();
|
|
73
|
-
return createProviderFn(config);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function main() {
|
|
77
|
-
const { values } = parseArgs({
|
|
78
|
-
options: {
|
|
79
|
-
run: { type: 'string' },
|
|
80
|
-
state: { type: 'string', default: 'open' },
|
|
81
|
-
pretty: { type: 'boolean', default: false },
|
|
82
|
-
help: { type: 'boolean', default: false },
|
|
83
|
-
},
|
|
84
|
-
allowPositionals: false,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
if (values.help) {
|
|
88
|
-
process.stdout.write(HELP);
|
|
89
|
-
return 0;
|
|
90
|
-
}
|
|
91
|
-
if (!values.run) {
|
|
92
|
-
process.stderr.write(HELP);
|
|
93
|
-
throw new Error('resolve-plan-run: --run <planRunId> is required');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const state = assertIssueState(values.state);
|
|
97
|
-
const planRunLabel = normalizePlanRunLabel(values.run);
|
|
98
|
-
const planRunId = planRunIdFromLabel(planRunLabel);
|
|
99
|
-
|
|
100
|
-
const provider = resolvePlanRunProvider();
|
|
101
|
-
const issues = await fetchPlanRunIssues(provider, { planRunLabel, state });
|
|
102
|
-
const envelope = buildPlanRunEnvelope(issues, { planRunId, planRunLabel });
|
|
103
|
-
writeEnvelope(envelope, values.pretty);
|
|
104
|
-
|
|
105
|
-
if (envelope.stories.length === 0) {
|
|
106
|
-
process.stderr.write(
|
|
107
|
-
`resolve-plan-run: no type::story issues with label ${planRunLabel} (state=${state})\n`,
|
|
108
|
-
);
|
|
109
|
-
return 2;
|
|
110
|
-
}
|
|
111
|
-
return 0;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
runAsCli(import.meta.url, main, {
|
|
115
|
-
source: 'resolve-plan-run',
|
|
116
|
-
propagateExitCode: true,
|
|
117
|
-
});
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: analyze-execution
|
|
3
|
-
description: >-
|
|
4
|
-
Aggregate per-Story or per-plan-run execution signals into a structured
|
|
5
|
-
perf-summary or perf-report and upsert it onto the corresponding GitHub
|
|
6
|
-
ticket. Use after a Story closes (Story mode) or during run closeout
|
|
7
|
-
(plan-run mode). Reads NDJSON via
|
|
8
|
-
`lib/signals/read` and writes a single structured comment.
|
|
9
|
-
allowed_tools:
|
|
10
|
-
- Read
|
|
11
|
-
- Bash
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# analyze-execution
|
|
15
|
-
|
|
16
|
-
## Policy Capsule
|
|
17
|
-
|
|
18
|
-
- Invoke via the wrapping CLI `node .agents/scripts/analyze-execution.js`; do not duplicate the read/write logic from this Skill body.
|
|
19
|
-
- Resolve mode strictly by flags: Story + run id → Story mode; run id alone → plan-run mode. The current CLI still spells the run-id flag as `--epic <id>`; treat that value as the run id and do not add a second executor path here.
|
|
20
|
-
- Read NDJSON signals only through `lib/signals/read` (the async-iterator entry point). Never open `<tempRoot>/run-<id>/stories/story-<sid>/signals.ndjson` directly — the reader owns the warn-once malformed-JSON policy.
|
|
21
|
-
- Emit a single structured GitHub comment per ticket (`<!-- structured:story-perf-summary -->` or `<!-- structured:epic-perf-report -->`); rely on `upsertStructuredComment` for idempotence — never post duplicates.
|
|
22
|
-
- Never rename or alter the structured-marker IDs; the retro composer and run dashboard grep them verbatim.
|
|
23
|
-
- Validate the structured payload against `docs/data-dictionary.md §StoryPerfSummary` or `§EpicPerfReport` before posting. Schema violations exit non-zero.
|
|
24
|
-
- Soft-fail (exit 0 with a warning) when NDJSON is missing for a Story or a plan-run has no children — observability output MUST NOT block the close pipeline.
|
|
25
|
-
- Do not write to disk. Persistence is GitHub; the Skill is read-NDJSON + post-comment only.
|
|
26
|
-
|
|
27
|
-
## Role
|
|
28
|
-
|
|
29
|
-
Observability writer. Composes the structured `story-perf-summary` /
|
|
30
|
-
`epic-perf-report` comment bodies the retro composer downstream renders
|
|
31
|
-
into the run dashboard.
|
|
32
|
-
|
|
33
|
-
## When to use
|
|
34
|
-
|
|
35
|
-
- **Story mode** — after `single-story-close.js` finishes, the close
|
|
36
|
-
pipeline dispatches this Skill (or the wrapping script) to roll up the
|
|
37
|
-
Story's NDJSON signals into a single `<!-- structured:story-perf-summary -->`
|
|
38
|
-
marker comment on the Story ticket.
|
|
39
|
-
- **Plan-run mode** — during run closeout (or the retro
|
|
40
|
-
composer), the Skill fans out across every Story under the plan-run,
|
|
41
|
-
reads each Story's structured perf summary, and posts a single
|
|
42
|
-
`<!-- structured:epic-perf-report -->` marker on the run ticket.
|
|
43
|
-
|
|
44
|
-
## Inputs
|
|
45
|
-
|
|
46
|
-
The Skill reads (never writes) the NDJSON signal stream at:
|
|
47
|
-
|
|
48
|
-
```text
|
|
49
|
-
<tempRoot>/run-<id>/stories/story-<sid>/signals.ndjson
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Use the `lib/signals/read` async-iterator entry point — never open the
|
|
53
|
-
file directly. Story mode also reads `phase-timings.json` written by
|
|
54
|
-
the close pipeline.
|
|
55
|
-
|
|
56
|
-
## Outputs
|
|
57
|
-
|
|
58
|
-
A single upserted GitHub comment per ticket. The Skill writes nothing to
|
|
59
|
-
disk — the persist path is GitHub. Idempotence: the underlying script's
|
|
60
|
-
`upsertStructuredComment` helper deletes any prior marker before posting
|
|
61
|
-
the new one.
|
|
62
|
-
|
|
63
|
-
## Procedure
|
|
64
|
-
|
|
65
|
-
### Step 1 — Resolve mode
|
|
66
|
-
|
|
67
|
-
If both Story id and run id are supplied → Story mode.
|
|
68
|
-
If only run id is supplied → plan-run mode. The script
|
|
69
|
-
`analyze-execution.js` is the dispatcher today; this Skill documents the
|
|
70
|
-
contract the dispatcher implements.
|
|
71
|
-
|
|
72
|
-
### Step 2 — Read signals via lib/signals/read
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
node .agents/scripts/analyze-execution.js --story <sid> --epic <eid>
|
|
76
|
-
# or
|
|
77
|
-
node .agents/scripts/analyze-execution.js --epic <eid>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
`--epic <eid>` is the legacy spelling of the run-id flag in the current
|
|
81
|
-
CLI; treat `<eid>` as the run id for path/layout purposes.
|
|
82
|
-
|
|
83
|
-
### Step 3 — Validate the structured payload before posting
|
|
84
|
-
|
|
85
|
-
The payload must conform to `docs/data-dictionary.md §StoryPerfSummary`
|
|
86
|
-
or §EpicPerfReport. Schema violations exit non-zero — the close
|
|
87
|
-
pipeline treats that as a non-fatal warning, but the smoke spec pins
|
|
88
|
-
the contract so we never silently emit malformed comments.
|
|
89
|
-
|
|
90
|
-
## Constraints
|
|
91
|
-
|
|
92
|
-
- Do **not** open `signals.ndjson` outside `lib/signals/read` — the
|
|
93
|
-
reader handles the warn-once policy for malformed JSON lines and
|
|
94
|
-
the streaming-iteration contract.
|
|
95
|
-
- Do **not** rename the structured-marker IDs
|
|
96
|
-
(`<!-- structured:story-perf-summary -->`,
|
|
97
|
-
`<!-- structured:epic-perf-report -->`); the retro composer and the
|
|
98
|
-
run dashboard both grep for them verbatim.
|
|
99
|
-
- Soft-failure mode is intentional: missing NDJSON for a Story or no
|
|
100
|
-
children for a plan-run returns exit 0 with a warning so close pipelines
|
|
101
|
-
never block on observability output.
|