mandrel 1.93.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +59 -73
- package/.agents/agents/acceptance-critic.md +129 -0
- package/.agents/agents/story-worker.md +161 -0
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +108 -136
- package/.agents/docs/execution-reference.md +44 -22
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +107 -108
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +224 -0
- package/.agents/rules/git-conventions.md +42 -223
- package/.agents/rules/security-baseline.md +5 -0
- package/.agents/rules/testing-standards.md +106 -13
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +71 -201
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/risk-verdict.schema.json +0 -13
- package/.agents/scripts/acceptance-eval.js +62 -18
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/analyze-execution.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/check-context-budget.js +62 -5
- package/.agents/scripts/check-lifecycle-lint.js +6 -9
- package/.agents/scripts/check-prepush-recovery.js +1 -1
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/diagnose-friction.js +0 -6
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
- package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
- package/.agents/scripts/lib/checks/index.js +2 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +16 -7
- package/.agents/scripts/lib/close-validation/gates.js +160 -22
- package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +103 -0
- package/.agents/scripts/lib/config/explain.js +57 -36
- package/.agents/scripts/lib/config/limits.js +17 -58
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +1 -1
- package/.agents/scripts/lib/config/runners.js +17 -50
- package/.agents/scripts/lib/config/temp-paths.js +19 -14
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +3 -8
- package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
- package/.agents/scripts/lib/config-settings-schema.js +52 -38
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +39 -4
- package/.agents/scripts/lib/duplicate-search.js +211 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +5 -5
- package/.agents/scripts/lib/framework-version.js +2 -3
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
- package/.agents/scripts/lib/git-utils.js +32 -6
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/label-constants.js +10 -23
- package/.agents/scripts/lib/label-taxonomy.js +9 -43
- package/.agents/scripts/lib/observability/active-story-env.js +112 -3
- package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
- package/.agents/scripts/lib/orchestration/code-review.js +20 -268
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
- package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
- package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
- package/.agents/scripts/lib/planning-corpus.js +16 -11
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/provider-factory.js +1 -1
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/story-adjacency.js +11 -14
- package/.agents/scripts/lib/story-body/story-body.js +124 -70
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
- package/.agents/scripts/lib/validation-evidence.js +1 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +64 -74
- package/.agents/scripts/plan-persist.js +121 -280
- package/.agents/scripts/plan-run-epilogue.js +97 -0
- package/.agents/scripts/post-structured-comment.js +38 -0
- package/.agents/scripts/providers/github/issues.js +17 -33
- package/.agents/scripts/providers/github/mappers.js +0 -12
- package/.agents/scripts/providers/github/tickets.js +2 -5
- package/.agents/scripts/resolve-plan-run.js +117 -0
- package/.agents/scripts/signals-view.js +24 -19
- package/.agents/scripts/single-story-close.js +11 -14
- package/.agents/scripts/single-story-confirm-merge.js +39 -23
- package/.agents/scripts/single-story-init.js +29 -20
- package/.agents/scripts/stories-wave-tick.js +6 -6
- package/.agents/scripts/story-plan.js +26 -47
- package/.agents/scripts/sync-claude-agents.js +165 -0
- package/.agents/scripts/update-ticket-state.js +37 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
- package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +8 -418
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +3 -3
- package/.agents/workflows/audit-clean-code.md +3 -3
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +5 -5
- package/.agents/workflows/audit-lighthouse.md +3 -3
- package/.agents/workflows/audit-navigability.md +3 -2
- package/.agents/workflows/audit-performance.md +3 -3
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +3 -3
- package/.agents/workflows/audit-security.md +3 -3
- package/.agents/workflows/audit-seo.md +3 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +3 -3
- package/.agents/workflows/deliver.md +122 -131
- package/.agents/workflows/git-cleanup.md +3 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
- package/.agents/workflows/helpers/code-review.md +70 -193
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
- package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
- package/.agents/workflows/mandrel-update.md +3 -2
- package/.agents/workflows/plan.md +112 -145
- package/.agents/workflows/qa-assist.md +24 -30
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -2
- package/README.md +9 -8
- package/docs/CHANGELOG.md +46 -0
- package/lib/cli/registry.js +95 -0
- package/lib/migrations/index.js +6 -5
- package/package.json +5 -3
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer-mobile.md +0 -120
- package/.agents/personas/engineer-web.md +0 -111
- package/.agents/personas/engineer.md +0 -119
- package/.agents/personas/product.md +0 -94
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/refactorer.md +0 -113
- package/.agents/personas/security-engineer.md +0 -112
- package/.agents/personas/sre.md +0 -86
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/personas/ux-designer.md +0 -95
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -590
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-decompose.js +0 -54
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-plan-spec.js +0 -64
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/plan-critics.js +0 -199
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -335
- package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
- package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
- package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
- package/.agents/skills/core/code-simplification/SKILL.md +0 -389
- package/.agents/skills/core/context-engineering/SKILL.md +0 -309
- package/.agents/skills/core/context-engineering/examples.md +0 -58
- package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
- package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
- package/.agents/skills/core/idea-refinement/examples.md +0 -437
- package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
- package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
- package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
- package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
- package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
- package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
- package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
- package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
- package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
- package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
- package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
- package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
- package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
- package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
- package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
- package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
- package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
- package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
- package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
- package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
- package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
- package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
- package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
- package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
- package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
- package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
- package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
- package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
- package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
- package/.agents/workflows/helpers/deliver-epic.md +0 -955
- package/.agents/workflows/helpers/deliver-stories.md +0 -440
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -351
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* story-phase.js — phase snapshot + heartbeat writer (2-tier).
|
|
5
|
-
*
|
|
6
|
-
* Replaces the deleted per-Task progress writer from the 4-tier era
|
|
7
|
-
* (removed under #3157). `/deliver` calls this CLI at each Story-
|
|
8
|
-
* level phase transition (init → implementing → closing → done, or any
|
|
9
|
-
* → blocked). Each call:
|
|
10
|
-
*
|
|
11
|
-
* 1. Renders the Story-phase snapshot for the requested phase (canonical
|
|
12
|
-
* init/implement/validate/close progression in the `phases[]` payload)
|
|
13
|
-
* and returns its markdown body for chat relay. Story #3909 — this no
|
|
14
|
-
* longer posts a `story-run-progress` comment (the redundant mid-flight
|
|
15
|
-
* progress surface was deleted); the snapshot is render-only.
|
|
16
|
-
* 2. Appends one `story.heartbeat` lifecycle record to
|
|
17
|
-
* `temp/epic-<epicId>/lifecycle.ndjson` so `/deliver`'s
|
|
18
|
-
* §2e Idle Watchdog (`wave-tick.js --check-idle 30`) can confirm
|
|
19
|
-
* forward progress without polling the Story comment.
|
|
20
|
-
*
|
|
21
|
-
* The heartbeat emit is best-effort: a missing/unreachable ledger,
|
|
22
|
-
* schema-validation hiccup, or absent `Epic: #N` body reference is
|
|
23
|
-
* logged and swallowed — the labels remain the source of truth, the
|
|
24
|
-
* ledger record is observability.
|
|
25
|
-
*
|
|
26
|
-
* CLI:
|
|
27
|
-
* --story <id> Story ID (required).
|
|
28
|
-
* --phase <init|implementing|closing|blocked|done>
|
|
29
|
-
* Phase the Story is entering (required).
|
|
30
|
-
* --epic <id> Parent Epic id from the Step 0 envelope.
|
|
31
|
-
* When supplied, skips the readEpicIdFromStory
|
|
32
|
-
* GitHub read.
|
|
33
|
-
* --branch <name> Story branch from the Step 0 envelope.
|
|
34
|
-
* When supplied, skips the resolveStoryBranch
|
|
35
|
-
* GitHub read.
|
|
36
|
-
* --no-heartbeat Suppress the lifecycle emit (tests).
|
|
37
|
-
*
|
|
38
|
-
* Stdout: a single JSON envelope
|
|
39
|
-
* { ok: true, storyId, phase, epicId, branch, heartbeatEmitted,
|
|
40
|
-
* ledgerPath, renderedBody }
|
|
41
|
-
*
|
|
42
|
-
* `renderedBody` is the markdown body upserted onto the Story so the
|
|
43
|
-
* caller can relay it to chat verbatim (mirrors the contract the deleted
|
|
44
|
-
* per-Task progress writer exposed and that `/deliver` Step 1 / 3
|
|
45
|
-
* already documents).
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
import { parseArgs } from 'node:util';
|
|
49
|
-
|
|
50
|
-
import { runAsCli } from './lib/cli-utils.js';
|
|
51
|
-
import { resolveConfig } from './lib/config-resolver.js';
|
|
52
|
-
import { Logger } from './lib/Logger.js';
|
|
53
|
-
import {
|
|
54
|
-
defaultStoryPhases,
|
|
55
|
-
STORY_PHASE_ORDER,
|
|
56
|
-
upsertStoryRunProgress,
|
|
57
|
-
} from './lib/orchestration/epic-runner/story-run-progress-writer.js';
|
|
58
|
-
import { emitStoryHeartbeat } from './lib/orchestration/lifecycle/emit-story-heartbeat.js';
|
|
59
|
-
import { parseFencedJsonComment } from './lib/orchestration/structured-comment-parser.js';
|
|
60
|
-
import { normalizeOperatorHandle } from './lib/orchestration/ticket-lease.js';
|
|
61
|
-
import { findStructuredComment } from './lib/orchestration/ticketing.js';
|
|
62
|
-
import { createProvider } from './lib/provider-factory.js';
|
|
63
|
-
import { resolveStoryHierarchy } from './lib/story-lifecycle.js';
|
|
64
|
-
import { notify } from './notify.js';
|
|
65
|
-
|
|
66
|
-
const VALID_PHASES = new Set([
|
|
67
|
-
'init',
|
|
68
|
-
'implementing',
|
|
69
|
-
'closing',
|
|
70
|
-
'blocked',
|
|
71
|
-
'done',
|
|
72
|
-
]);
|
|
73
|
-
|
|
74
|
-
const HELP = `Usage: node .agents/scripts/story-phase.js \\
|
|
75
|
-
--story <id> --phase <init|implementing|closing|blocked|done> \\
|
|
76
|
-
[--epic <id>] [--branch <name>] [--no-heartbeat]
|
|
77
|
-
|
|
78
|
-
Renders the Story-phase snapshot for Story #<id> at the requested phase
|
|
79
|
-
(returned as renderedBody for chat relay; no comment is posted) and
|
|
80
|
-
(unless --no-heartbeat) appends one story.heartbeat record to the parent
|
|
81
|
-
Epic's lifecycle ledger so the Idle Watchdog can confirm the Story is alive.
|
|
82
|
-
|
|
83
|
-
--epic / --branch let the caller pass the parent Epic id and Story branch
|
|
84
|
-
from story-init.js's Step 0 envelope, skipping the GitHub reads
|
|
85
|
-
(readEpicIdFromStory / resolveStoryBranch) that would otherwise re-fetch
|
|
86
|
-
these immutable values on every phase call. Omit both for interactive use.
|
|
87
|
-
`;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Map the workflow-level `--phase` value to the canonical phases[] row
|
|
91
|
-
* progression carried in the snapshot payload (init/implement/validate/
|
|
92
|
-
* close). The mapping is monotonic: each later phase marks every earlier
|
|
93
|
-
* row `done`, the current row `in-progress` (or `done` when the workflow
|
|
94
|
-
* phase itself is `done`), and any later rows `pending`. `blocked` leaves
|
|
95
|
-
* the in-progress row marked in-progress (the blocker is reflected in the
|
|
96
|
-
* header phase, not the row table).
|
|
97
|
-
*
|
|
98
|
-
* @param {string} workflowPhase
|
|
99
|
-
* @returns {Array<{ name: string, status: string, startedAt: string|null, endedAt: string|null }>}
|
|
100
|
-
*/
|
|
101
|
-
export function phasesForWorkflowPhase(workflowPhase, now = new Date()) {
|
|
102
|
-
const ts = now.toISOString();
|
|
103
|
-
const phases = defaultStoryPhases();
|
|
104
|
-
|
|
105
|
-
// Anchor row that should be "current" for each workflow phase.
|
|
106
|
-
const currentByPhase = {
|
|
107
|
-
init: 'init',
|
|
108
|
-
implementing: 'implement',
|
|
109
|
-
closing: 'validate',
|
|
110
|
-
blocked: 'implement',
|
|
111
|
-
done: 'close',
|
|
112
|
-
};
|
|
113
|
-
const current = currentByPhase[workflowPhase];
|
|
114
|
-
const currentIdx = STORY_PHASE_ORDER.indexOf(current);
|
|
115
|
-
|
|
116
|
-
for (let i = 0; i < phases.length; i++) {
|
|
117
|
-
if (i < currentIdx) {
|
|
118
|
-
phases[i].status = 'done';
|
|
119
|
-
phases[i].startedAt = ts;
|
|
120
|
-
phases[i].endedAt = ts;
|
|
121
|
-
} else if (i === currentIdx) {
|
|
122
|
-
if (workflowPhase === 'done') {
|
|
123
|
-
phases[i].status = 'done';
|
|
124
|
-
phases[i].startedAt = ts;
|
|
125
|
-
phases[i].endedAt = ts;
|
|
126
|
-
} else {
|
|
127
|
-
phases[i].status = 'in-progress';
|
|
128
|
-
phases[i].startedAt = ts;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return phases;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Hydrate the parent Epic id off the Story ticket body. Returns null when
|
|
137
|
-
* the Story has no `Epic: #N` reference (the heartbeat emit will be
|
|
138
|
-
* skipped because there is no Epic-scoped ledger path to write to).
|
|
139
|
-
*
|
|
140
|
-
* @param {{ provider: object, storyId: number }} args
|
|
141
|
-
* @returns {Promise<number|null>}
|
|
142
|
-
*/
|
|
143
|
-
export async function readEpicIdFromStory({ provider, storyId }) {
|
|
144
|
-
const story = await provider.getTicket(storyId);
|
|
145
|
-
const { epicId } = resolveStoryHierarchy(story?.body ?? '');
|
|
146
|
-
return epicId ?? null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Hydrate the prior story-run-progress branch off the Story ticket so a
|
|
151
|
-
* resumed run preserves the branch name rather than re-deriving it.
|
|
152
|
-
* Falls back to `story-<id>` when no prior snapshot exists.
|
|
153
|
-
*/
|
|
154
|
-
async function resolveStoryBranch({ provider, storyId }) {
|
|
155
|
-
const snapshot = await findStructuredComment(
|
|
156
|
-
provider,
|
|
157
|
-
storyId,
|
|
158
|
-
'story-run-progress',
|
|
159
|
-
);
|
|
160
|
-
if (snapshot) {
|
|
161
|
-
const parsed = parseFencedJsonComment(snapshot);
|
|
162
|
-
if (parsed && typeof parsed.branch === 'string' && parsed.branch) {
|
|
163
|
-
return parsed.branch;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const initComment = await findStructuredComment(
|
|
167
|
-
provider,
|
|
168
|
-
storyId,
|
|
169
|
-
'story-init',
|
|
170
|
-
);
|
|
171
|
-
if (initComment) {
|
|
172
|
-
const parsed = parseFencedJsonComment(initComment);
|
|
173
|
-
if (
|
|
174
|
-
parsed &&
|
|
175
|
-
typeof parsed.storyBranch === 'string' &&
|
|
176
|
-
parsed.storyBranch
|
|
177
|
-
) {
|
|
178
|
-
return parsed.storyBranch;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return `story-${storyId}`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Best-effort `story.heartbeat` emit for one phase transition. Resolves the
|
|
186
|
-
* lease-owner handle the SAME way the lease primitive does
|
|
187
|
-
* (`normalizeOperatorHandle(github.operatorHandle)`) and stamps it as
|
|
188
|
-
* `operator` so `latestHeartbeatForOwner({ epicId, owner })` resolves a real
|
|
189
|
-
* heartbeat — without it `isClaimLive(null)` is false and /deliver
|
|
190
|
-
* silently reclaims a live foreign claim (audit #3513). The field is attached
|
|
191
|
-
* only when a handle resolves, preserving the "omit when absent" shape for
|
|
192
|
-
* repos that have not configured `github.operatorHandle`. A failed append is
|
|
193
|
-
* logged and swallowed: the heartbeat is observability, not state.
|
|
194
|
-
*
|
|
195
|
-
* @param {{ storyId: number, epicId: number, phase: string, config: object|null, ledgerPath?: string, timestamp: string }} args
|
|
196
|
-
* @returns {{ heartbeatEmitted: boolean, ledgerPath: string|null }}
|
|
197
|
-
*/
|
|
198
|
-
function emitHeartbeatBestEffort({
|
|
199
|
-
storyId,
|
|
200
|
-
epicId,
|
|
201
|
-
phase,
|
|
202
|
-
config,
|
|
203
|
-
ledgerPath,
|
|
204
|
-
timestamp,
|
|
205
|
-
}) {
|
|
206
|
-
const operator = normalizeOperatorHandle(config?.github?.operatorHandle);
|
|
207
|
-
try {
|
|
208
|
-
const res = emitStoryHeartbeat({
|
|
209
|
-
storyId,
|
|
210
|
-
epicId,
|
|
211
|
-
phase,
|
|
212
|
-
timestamp,
|
|
213
|
-
...(operator !== null ? { operator } : {}),
|
|
214
|
-
config: config ?? undefined,
|
|
215
|
-
ledgerPath,
|
|
216
|
-
});
|
|
217
|
-
return { heartbeatEmitted: true, ledgerPath: res.ledgerPath };
|
|
218
|
-
} catch (err) {
|
|
219
|
-
Logger.warn(
|
|
220
|
-
`[story-phase] story.heartbeat emit failed (continuing): ${err.message}`,
|
|
221
|
-
);
|
|
222
|
-
return { heartbeatEmitted: false, ledgerPath: null };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* End-to-end phase writer. DI-friendly: tests pass `provider`, override
|
|
228
|
-
* the ledger path, and skip the heartbeat as needed.
|
|
229
|
-
*
|
|
230
|
-
* When `epicId` / `branch` are supplied (the `/deliver` worker passes them
|
|
231
|
-
* from `story-init.js`'s Step 0 envelope), the corresponding GitHub read is
|
|
232
|
-
* skipped entirely: `epicId` short-circuits `readEpicIdFromStory` and
|
|
233
|
-
* `branch` short-circuits `resolveStoryBranch`. Omit both for interactive
|
|
234
|
-
* use to restore the original GitHub-read resolution.
|
|
235
|
-
*
|
|
236
|
-
* @param {{
|
|
237
|
-
* storyId: number,
|
|
238
|
-
* phase: string,
|
|
239
|
-
* epicId?: number|null,
|
|
240
|
-
* branch?: string,
|
|
241
|
-
* noHeartbeat?: boolean,
|
|
242
|
-
* provider?: object,
|
|
243
|
-
* config?: object,
|
|
244
|
-
* ledgerPath?: string,
|
|
245
|
-
* now?: Date,
|
|
246
|
-
* }} args
|
|
247
|
-
*/
|
|
248
|
-
export async function runStoryPhase(args) {
|
|
249
|
-
const {
|
|
250
|
-
storyId,
|
|
251
|
-
phase,
|
|
252
|
-
epicId: epicIdOverride,
|
|
253
|
-
branch: branchOverride,
|
|
254
|
-
noHeartbeat = false,
|
|
255
|
-
provider: providerOverride,
|
|
256
|
-
config: configOverride,
|
|
257
|
-
ledgerPath: ledgerPathOverride,
|
|
258
|
-
now = new Date(),
|
|
259
|
-
} = args ?? {};
|
|
260
|
-
|
|
261
|
-
if (!Number.isInteger(storyId) || storyId <= 0) {
|
|
262
|
-
throw new Error('runStoryPhase: --story must be a positive integer');
|
|
263
|
-
}
|
|
264
|
-
if (!VALID_PHASES.has(phase)) {
|
|
265
|
-
throw new Error(
|
|
266
|
-
`runStoryPhase: --phase "${phase}" must be one of: ${[...VALID_PHASES].join(', ')}`,
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const config = configOverride ?? (providerOverride ? null : resolveConfig());
|
|
271
|
-
const provider = providerOverride ?? createProvider(config);
|
|
272
|
-
const notifyFn = providerOverride
|
|
273
|
-
? null
|
|
274
|
-
: (ticketId, payload, opts = {}) =>
|
|
275
|
-
notify(ticketId, payload, { config, provider, ...opts });
|
|
276
|
-
|
|
277
|
-
// When the Step 0 envelope supplied the branch / epicId (the /deliver
|
|
278
|
-
// worker passes them via --branch / --epic), skip the GitHub reads that
|
|
279
|
-
// would otherwise re-fetch these immutable values on every phase call.
|
|
280
|
-
const branch =
|
|
281
|
-
typeof branchOverride === 'string' && branchOverride
|
|
282
|
-
? branchOverride
|
|
283
|
-
: await resolveStoryBranch({ provider, storyId });
|
|
284
|
-
const epicId =
|
|
285
|
-
epicIdOverride !== undefined
|
|
286
|
-
? epicIdOverride
|
|
287
|
-
: await readEpicIdFromStory({ provider, storyId });
|
|
288
|
-
const phases = phasesForWorkflowPhase(phase, now);
|
|
289
|
-
|
|
290
|
-
const { body: renderedBody, payload: snapshot } =
|
|
291
|
-
await upsertStoryRunProgress({
|
|
292
|
-
provider,
|
|
293
|
-
storyId,
|
|
294
|
-
branch,
|
|
295
|
-
phase,
|
|
296
|
-
phases,
|
|
297
|
-
epicId: epicId ?? undefined,
|
|
298
|
-
updatedAt: now.toISOString(),
|
|
299
|
-
notify: notifyFn,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
let heartbeatEmitted = false;
|
|
303
|
-
let ledgerPath = null;
|
|
304
|
-
if (!noHeartbeat && epicId) {
|
|
305
|
-
({ heartbeatEmitted, ledgerPath } = emitHeartbeatBestEffort({
|
|
306
|
-
storyId,
|
|
307
|
-
epicId,
|
|
308
|
-
phase,
|
|
309
|
-
config,
|
|
310
|
-
ledgerPath: ledgerPathOverride,
|
|
311
|
-
timestamp: now.toISOString(),
|
|
312
|
-
}));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
ok: true,
|
|
317
|
-
storyId,
|
|
318
|
-
phase,
|
|
319
|
-
epicId,
|
|
320
|
-
branch,
|
|
321
|
-
heartbeatEmitted,
|
|
322
|
-
ledgerPath,
|
|
323
|
-
snapshot,
|
|
324
|
-
renderedBody,
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export function parseArgv(argv) {
|
|
329
|
-
const { values } = parseArgs({
|
|
330
|
-
args: argv,
|
|
331
|
-
options: {
|
|
332
|
-
story: { type: 'string' },
|
|
333
|
-
phase: { type: 'string' },
|
|
334
|
-
epic: { type: 'string' },
|
|
335
|
-
branch: { type: 'string' },
|
|
336
|
-
'no-heartbeat': { type: 'boolean' },
|
|
337
|
-
help: { type: 'boolean' },
|
|
338
|
-
},
|
|
339
|
-
strict: false,
|
|
340
|
-
});
|
|
341
|
-
// `--epic` absent → leave `epicId` undefined so runStoryPhase falls back to
|
|
342
|
-
// the readEpicIdFromStory GitHub read. `--branch` absent → leave `branch`
|
|
343
|
-
// undefined so it falls back to resolveStoryBranch.
|
|
344
|
-
const parsed = {
|
|
345
|
-
help: Boolean(values.help),
|
|
346
|
-
storyId: Number.parseInt(values.story ?? '', 10),
|
|
347
|
-
phase: values.phase,
|
|
348
|
-
noHeartbeat: Boolean(values['no-heartbeat']),
|
|
349
|
-
};
|
|
350
|
-
if (values.epic !== undefined) {
|
|
351
|
-
parsed.epicId = Number.parseInt(values.epic, 10);
|
|
352
|
-
}
|
|
353
|
-
if (typeof values.branch === 'string' && values.branch) {
|
|
354
|
-
parsed.branch = values.branch;
|
|
355
|
-
}
|
|
356
|
-
return parsed;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
export async function main(argv = process.argv.slice(2)) {
|
|
360
|
-
const parsed = parseArgv(argv);
|
|
361
|
-
if (parsed.help) {
|
|
362
|
-
process.stdout.write(HELP);
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const envelope = await runStoryPhase(parsed);
|
|
366
|
-
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
runAsCli(import.meta.url, main, { source: 'story-phase' });
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* node:coverage ignore file */
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* wave-tick.js — thin CLI shim around `lib/wave-runner/tick.js`.
|
|
6
|
-
*
|
|
7
|
-
* Reads the `epic-run-state` checkpoint plus fresh Story labels and
|
|
8
|
-
* prints one `WaveTickResult` envelope. The slash-command operator
|
|
9
|
-
* (`/deliver`) consumes the envelope to decide whether to dispatch
|
|
10
|
-
* the next wave, observe in-flight stories, or finalize the Epic.
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
|
|
14
|
-
*
|
|
15
|
-
* The tick is stateless — "loop until terminal" is the caller's job
|
|
16
|
-
* (today: the markdown's wave loop).
|
|
17
|
-
*
|
|
18
|
-
* Output: one JSON object on stdout. Schema in `lib/wave-runner/tick.js`.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { execFileSync } from 'node:child_process';
|
|
22
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
23
|
-
import { parseArgs } from 'node:util';
|
|
24
|
-
|
|
25
|
-
import { runAsCli } from './lib/cli-utils.js';
|
|
26
|
-
import { epicLedgerPath } from './lib/config/temp-paths.js';
|
|
27
|
-
import { resolveConfig } from './lib/config-resolver.js';
|
|
28
|
-
import { Logger } from './lib/Logger.js';
|
|
29
|
-
import { createProvider } from './lib/provider-factory.js';
|
|
30
|
-
import { tick } from './lib/wave-runner/tick.js';
|
|
31
|
-
|
|
32
|
-
const HELP = `Usage: node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
|
|
33
|
-
|
|
34
|
-
Stateless wave-loop planner. Reads the epic-run-state checkpoint on
|
|
35
|
-
Epic #<id>, evaluates the live story-label state, and prints one
|
|
36
|
-
WaveTickResult envelope describing the next dispatchable action.
|
|
37
|
-
|
|
38
|
-
When --check-idle <minutes> is supplied, the planner skips the normal
|
|
39
|
-
WaveTickResult emit and instead scans the per-Epic lifecycle ledger
|
|
40
|
-
(temp/epic-<id>/lifecycle.ndjson) for in-flight Stories whose most
|
|
41
|
-
recent lifecycle event is older than the threshold. Emits a single
|
|
42
|
-
JSON envelope on stdout and exits non-zero when at least one stalled
|
|
43
|
-
Story is detected. The envelope shape mirrors the wave-stall
|
|
44
|
-
structured-comment payload so the slash-command host can post it
|
|
45
|
-
verbatim.
|
|
46
|
-
`;
|
|
47
|
-
|
|
48
|
-
export async function runWaveTickCli({
|
|
49
|
-
epicId,
|
|
50
|
-
cwd,
|
|
51
|
-
injectedProvider,
|
|
52
|
-
injectedConfig,
|
|
53
|
-
} = {}) {
|
|
54
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
55
|
-
throw new TypeError('runWaveTickCli: --epic must be a positive integer');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const config = injectedConfig ?? resolveConfig({ cwd });
|
|
59
|
-
const provider = injectedProvider ?? createProvider(config);
|
|
60
|
-
|
|
61
|
-
const result = await tick({
|
|
62
|
-
epic: epicId,
|
|
63
|
-
collaborators: { provider },
|
|
64
|
-
ctx: { config },
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Scan the per-Epic lifecycle ledger and compute, per in-flight Story,
|
|
72
|
-
* the timestamp of its most recent lifecycle event. A Story is
|
|
73
|
-
* "in-flight" when the ledger carries a `story.dispatch.start` record
|
|
74
|
-
* without a matching `story.dispatch.end`. Any other `story.*` event
|
|
75
|
-
* (notably `story.heartbeat` from Story #3057) refreshes the Story's
|
|
76
|
-
* last-event timestamp.
|
|
77
|
-
*
|
|
78
|
-
* Pure helper — exported for unit tests.
|
|
79
|
-
*
|
|
80
|
-
* @param {string} ledgerPath Absolute path to `lifecycle.ndjson`.
|
|
81
|
-
* @returns {Map<number, string>} `storyId → ISO-8601 timestamp`. Empty
|
|
82
|
-
* when the ledger is missing, unreadable, or carries no in-flight
|
|
83
|
-
* Stories.
|
|
84
|
-
*/
|
|
85
|
-
export function readLedgerLastEvents(ledgerPath) {
|
|
86
|
-
if (!ledgerPath || !existsSync(ledgerPath)) return new Map();
|
|
87
|
-
let raw;
|
|
88
|
-
try {
|
|
89
|
-
raw = readFileSync(ledgerPath, 'utf8');
|
|
90
|
-
} catch {
|
|
91
|
-
return new Map();
|
|
92
|
-
}
|
|
93
|
-
if (!raw) return new Map();
|
|
94
|
-
const started = new Set();
|
|
95
|
-
const ended = new Set();
|
|
96
|
-
const lastTs = new Map();
|
|
97
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
98
|
-
if (!line) continue;
|
|
99
|
-
let record;
|
|
100
|
-
try {
|
|
101
|
-
record = JSON.parse(line);
|
|
102
|
-
} catch {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (!record || record.kind !== 'emitted') continue;
|
|
106
|
-
const event = typeof record.event === 'string' ? record.event : '';
|
|
107
|
-
if (!event.startsWith('story.')) continue;
|
|
108
|
-
const storyId = record.payload?.storyId;
|
|
109
|
-
if (!Number.isInteger(storyId) || storyId <= 0) continue;
|
|
110
|
-
if (event === 'story.dispatch.start') started.add(storyId);
|
|
111
|
-
else if (event === 'story.dispatch.end') ended.add(storyId);
|
|
112
|
-
const ts = typeof record.ts === 'string' ? record.ts : null;
|
|
113
|
-
if (ts) {
|
|
114
|
-
const prior = lastTs.get(storyId);
|
|
115
|
-
if (!prior || prior < ts) lastTs.set(storyId, ts);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const out = new Map();
|
|
119
|
-
for (const id of started) {
|
|
120
|
-
if (ended.has(id)) continue;
|
|
121
|
-
const ts = lastTs.get(id);
|
|
122
|
-
if (ts) out.set(id, ts);
|
|
123
|
-
}
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Deterministic branch-activity resolver (Story #3900). Returns the epoch-ms
|
|
129
|
-
* timestamp of the most recent commit on `story-<storyId>` via
|
|
130
|
-
* `git log -1 --format=%cI`, or `null` when the branch does not exist, has no
|
|
131
|
-
* commits, or git is unavailable.
|
|
132
|
-
*
|
|
133
|
-
* This is the secondary liveness signal the idle watchdog consults before
|
|
134
|
-
* flagging a Story as stalled: a healthy long-running Story routinely exceeds
|
|
135
|
-
* the heartbeat threshold during `implementing → closing` (heartbeats fire
|
|
136
|
-
* only at phase transitions), but its branch keeps gaining commits. A recent
|
|
137
|
-
* commit is hard, deterministic evidence of forward progress that does not
|
|
138
|
-
* depend on a heartbeat landing in the ledger. Pure-ish (shells out to git)
|
|
139
|
-
* and injectable so unit tests never spawn a subprocess.
|
|
140
|
-
*
|
|
141
|
-
* @param {number} storyId
|
|
142
|
-
* @param {{ cwd?: string, exec?: typeof execFileSync }} [deps]
|
|
143
|
-
* @returns {number|null} epoch-ms of the last commit, or null.
|
|
144
|
-
*/
|
|
145
|
-
export function branchLastCommitMs(storyId, deps = {}) {
|
|
146
|
-
const exec = deps.exec ?? execFileSync;
|
|
147
|
-
const cwd = deps.cwd ?? process.cwd();
|
|
148
|
-
try {
|
|
149
|
-
const out = exec(
|
|
150
|
-
'git',
|
|
151
|
-
['log', '-1', '--format=%cI', `story-${storyId}`, '--'],
|
|
152
|
-
{ cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },
|
|
153
|
-
).trim();
|
|
154
|
-
if (!out) return null;
|
|
155
|
-
const ms = Date.parse(out);
|
|
156
|
-
return Number.isFinite(ms) ? ms : null;
|
|
157
|
-
} catch {
|
|
158
|
-
// Branch absent / git unavailable — no deterministic signal.
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Build the wave-stall envelope. Pure helper — exported for unit tests.
|
|
165
|
-
*
|
|
166
|
-
* A Story whose latest ledger event is older than the threshold is *not*
|
|
167
|
-
* flagged as stalled when its `story-<id>` branch carries a commit newer
|
|
168
|
-
* than the threshold (Story #3900). Branch commits are deterministic
|
|
169
|
-
* forward-progress evidence that survives the heartbeat-cadence gap during
|
|
170
|
-
* `implementing → closing`, so consulting them eliminates the false-positive
|
|
171
|
-
* re-dispatch hazard (two agents on one branch) the watchdog otherwise
|
|
172
|
-
* manufactures for every healthy long-running Story.
|
|
173
|
-
*
|
|
174
|
-
* @param {object} args
|
|
175
|
-
* @param {number} args.epicId
|
|
176
|
-
* @param {number} args.thresholdMinutes
|
|
177
|
-
* @param {Map<number, string>} args.lastEvents `storyId → ISO-8601 ts`
|
|
178
|
-
* from {@link readLedgerLastEvents}.
|
|
179
|
-
* @param {Date} args.now Reference clock for the staleness comparison.
|
|
180
|
-
* @param {(storyId: number) => (number|null)} [args.branchActivity]
|
|
181
|
-
* Resolver for the last commit epoch-ms on `story-<id>`. Defaults to
|
|
182
|
-
* {@link branchLastCommitMs}. Injected for tests.
|
|
183
|
-
* @returns {{
|
|
184
|
-
* kind: 'wave-stall',
|
|
185
|
-
* epicId: number,
|
|
186
|
-
* thresholdMinutes: number,
|
|
187
|
-
* checkedAt: string,
|
|
188
|
-
* stalled: Array<{storyId: number, lastEventAt: string, idleMinutes: number}>,
|
|
189
|
-
* inFlight: number[]
|
|
190
|
-
* }}
|
|
191
|
-
*/
|
|
192
|
-
export function buildWaveStallEnvelope({
|
|
193
|
-
epicId,
|
|
194
|
-
thresholdMinutes,
|
|
195
|
-
lastEvents,
|
|
196
|
-
now,
|
|
197
|
-
branchActivity = branchLastCommitMs,
|
|
198
|
-
}) {
|
|
199
|
-
const checkedAt = now.toISOString();
|
|
200
|
-
const thresholdMs = thresholdMinutes * 60 * 1000;
|
|
201
|
-
const stalled = [];
|
|
202
|
-
const inFlight = [];
|
|
203
|
-
for (const [storyId, ts] of lastEvents) {
|
|
204
|
-
inFlight.push(storyId);
|
|
205
|
-
const eventMs = Date.parse(ts);
|
|
206
|
-
if (!Number.isFinite(eventMs)) continue;
|
|
207
|
-
const idleMs = now.getTime() - eventMs;
|
|
208
|
-
if (idleMs < thresholdMs) continue;
|
|
209
|
-
|
|
210
|
-
// Ledger says idle — consult the branch as a deterministic liveness
|
|
211
|
-
// signal before declaring a stall. A recent commit means the Story is
|
|
212
|
-
// making progress despite the heartbeat-cadence gap.
|
|
213
|
-
const commitMs = branchActivity(storyId);
|
|
214
|
-
if (
|
|
215
|
-
typeof commitMs === 'number' &&
|
|
216
|
-
Number.isFinite(commitMs) &&
|
|
217
|
-
now.getTime() - commitMs < thresholdMs
|
|
218
|
-
) {
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
stalled.push({
|
|
223
|
-
storyId,
|
|
224
|
-
lastEventAt: ts,
|
|
225
|
-
idleMinutes: Math.floor(idleMs / 60000),
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
inFlight.sort((a, b) => a - b);
|
|
229
|
-
stalled.sort((a, b) => a.storyId - b.storyId);
|
|
230
|
-
return {
|
|
231
|
-
kind: 'wave-stall',
|
|
232
|
-
epicId,
|
|
233
|
-
thresholdMinutes,
|
|
234
|
-
checkedAt,
|
|
235
|
-
stalled,
|
|
236
|
-
inFlight,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Run the `--check-idle` path. Exported so unit tests can drive the
|
|
242
|
-
* branch without spawning the CLI subprocess.
|
|
243
|
-
*
|
|
244
|
-
* @param {object} args
|
|
245
|
-
* @param {number} args.epicId
|
|
246
|
-
* @param {number} args.thresholdMinutes
|
|
247
|
-
* @param {string} [args.ledgerPath] Override for tests; defaults to the
|
|
248
|
-
* canonical `temp/epic-<id>/lifecycle.ndjson`.
|
|
249
|
-
* @param {Date} [args.now] Override for tests; defaults to wall clock.
|
|
250
|
-
* @param {object} [args.config] Optional resolved config for tempRoot.
|
|
251
|
-
* @param {(storyId: number) => (number|null)} [args.branchActivity]
|
|
252
|
-
* Branch-liveness resolver; defaults to {@link branchLastCommitMs}.
|
|
253
|
-
* Injected for tests so the watchdog never spawns git.
|
|
254
|
-
* @returns {{envelope: object, stalledCount: number}}
|
|
255
|
-
*/
|
|
256
|
-
export function runCheckIdle({
|
|
257
|
-
epicId,
|
|
258
|
-
thresholdMinutes,
|
|
259
|
-
ledgerPath,
|
|
260
|
-
now = new Date(),
|
|
261
|
-
config,
|
|
262
|
-
branchActivity = branchLastCommitMs,
|
|
263
|
-
}) {
|
|
264
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
265
|
-
throw new TypeError('runCheckIdle: epicId must be a positive integer');
|
|
266
|
-
}
|
|
267
|
-
if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
|
|
268
|
-
throw new TypeError(
|
|
269
|
-
'runCheckIdle: thresholdMinutes must be a positive integer',
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
const resolvedPath = ledgerPath ?? epicLedgerPath(epicId, config);
|
|
273
|
-
const lastEvents = readLedgerLastEvents(resolvedPath);
|
|
274
|
-
const envelope = buildWaveStallEnvelope({
|
|
275
|
-
epicId,
|
|
276
|
-
thresholdMinutes,
|
|
277
|
-
lastEvents,
|
|
278
|
-
now,
|
|
279
|
-
branchActivity,
|
|
280
|
-
});
|
|
281
|
-
return { envelope, stalledCount: envelope.stalled.length };
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
async function main(argv) {
|
|
285
|
-
const { values } = parseArgs({
|
|
286
|
-
args: argv,
|
|
287
|
-
options: {
|
|
288
|
-
epic: { type: 'string' },
|
|
289
|
-
'check-idle': { type: 'string' },
|
|
290
|
-
help: { type: 'boolean', short: 'h' },
|
|
291
|
-
},
|
|
292
|
-
strict: false,
|
|
293
|
-
allowPositionals: true,
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
if (values.help) {
|
|
297
|
-
process.stdout.write(`${HELP}\n`);
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const epicId = Number.parseInt(
|
|
302
|
-
String(values.epic ?? '').replace(/^#/, ''),
|
|
303
|
-
10,
|
|
304
|
-
);
|
|
305
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
306
|
-
Logger.error('wave-tick: --epic <id> is required (positive integer)');
|
|
307
|
-
process.exitCode = 2;
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (values['check-idle'] !== undefined) {
|
|
312
|
-
const thresholdMinutes = Number.parseInt(String(values['check-idle']), 10);
|
|
313
|
-
if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
|
|
314
|
-
Logger.error(
|
|
315
|
-
'wave-tick: --check-idle <minutes> must be a positive integer',
|
|
316
|
-
);
|
|
317
|
-
process.exitCode = 2;
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
const { envelope, stalledCount } = runCheckIdle({
|
|
321
|
-
epicId,
|
|
322
|
-
thresholdMinutes,
|
|
323
|
-
});
|
|
324
|
-
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
325
|
-
process.exitCode = stalledCount > 0 ? 1 : 0;
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const result = await runWaveTickCli({ epicId });
|
|
330
|
-
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
runAsCli(import.meta.url, () => main(process.argv.slice(2)), {
|
|
334
|
-
source: 'wave-tick',
|
|
335
|
-
});
|