mandrel 1.94.0 → 2.1.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 +116 -99
- package/.agents/agents/acceptance-critic.md +9 -7
- package/.agents/agents/story-worker.md +45 -51
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +498 -1287
- package/.agents/docs/agentrc-reference.json +185 -80
- package/.agents/docs/configuration.md +132 -190
- package/.agents/docs/execution-reference.md +51 -25
- package/.agents/docs/quality-gates.md +25 -33
- package/.agents/docs/workflows.md +8 -8
- package/.agents/instructions.md +113 -139
- package/.agents/rules/ci-remediation.md +11 -15
- package/.agents/rules/git-conventions-reference.md +48 -58
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +83 -254
- 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/retro.end.schema.json +1 -1
- 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 +22 -66
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.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 +7 -10
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- 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/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +328 -28
- 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 -15
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -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 +6 -3
- package/.agents/scripts/lib/checks/index.js +3 -2
- 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 +26 -24
- 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/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +39 -9
- package/.agents/scripts/lib/close-validation/gates.js +15 -15
- 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/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +52 -35
- package/.agents/scripts/lib/config/explain.js +61 -48
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +29 -80
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +12 -15
- package/.agents/scripts/lib/config/runners.js +20 -66
- package/.agents/scripts/lib/config/temp-paths.js +30 -63
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
- package/.agents/scripts/lib/config-settings-schema.js +100 -60
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +2 -2
- package/.agents/scripts/lib/duplicate-search.js +242 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- 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 -190
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
- package/.agents/scripts/lib/git-utils.js +32 -20
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +10 -38
- package/.agents/scripts/lib/label-taxonomy.js +10 -55
- package/.agents/scripts/lib/observability/active-story-env.js +44 -165
- 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 +5 -5
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- 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 +105 -44
- package/.agents/scripts/lib/orchestration/code-review.js +78 -436
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- 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/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/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 +17 -19
- 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/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
- 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/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- 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 +52 -51
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- 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/review-provider-factory.js +21 -56
- 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 +784 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
- 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 +86 -41
- 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 +77 -32
- 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 +44 -0
- 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 +275 -46
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- 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/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
- package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
- 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 -281
- package/.agents/scripts/lib/preflight-runner.js +4 -4
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- 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/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +17 -19
- package/.agents/scripts/lib/story-body/story-body.js +130 -75
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
- package/.agents/scripts/lib/validation-evidence.js +32 -60
- package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- 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 +102 -80
- package/.agents/scripts/plan-persist.js +230 -279
- package/.agents/scripts/plan-run-epilogue.js +142 -0
- 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 +13 -39
- package/.agents/scripts/providers/github/mappers.js +5 -12
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -156
- package/.agents/scripts/providers/github.js +17 -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 +25 -21
- package/.agents/scripts/single-story-close.js +178 -26
- package/.agents/scripts/single-story-confirm-merge.js +313 -24
- package/.agents/scripts/single-story-init.js +35 -30
- package/.agents/scripts/stories-wave-tick.js +85 -10
- package/.agents/scripts/story-plan.js +28 -49
- package/.agents/scripts/update-ticket-state.js +14 -65
- 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 +9 -9
- package/.agents/skills/core/scope-triage/SKILL.md +31 -172
- 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 +3 -53
- 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/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +6 -7
- package/.agents/workflows/audit-clean-code.md +7 -7
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +9 -10
- package/.agents/workflows/audit-lighthouse.md +11 -3
- package/.agents/workflows/audit-navigability.md +13 -2
- package/.agents/workflows/audit-performance.md +5 -6
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +11 -12
- package/.agents/workflows/audit-security.md +4 -5
- package/.agents/workflows/audit-seo.md +13 -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 +10 -3
- package/.agents/workflows/deliver.md +177 -176
- package/.agents/workflows/git-cleanup.md +5 -6
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
- package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
- package/.agents/workflows/helpers/code-review.md +75 -196
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
- package/.agents/workflows/helpers/deliver-story.md +606 -0
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/parallel-tooling.md +3 -3
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
- package/.agents/workflows/mandrel-update.md +2 -1
- package/.agents/workflows/plan.md +277 -145
- package/.agents/workflows/qa-assist.md +27 -33
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -6
- package/README.md +9 -8
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +70 -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 +12 -8
- 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/package.json +2 -2
- package/.agents/agents/retro.md +0 -42
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer.md +0 -33
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/security-engineer.md +0 -111
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/epic-spec.schema.json +0 -153
- 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/slice.end.schema.json +0 -21
- package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
- package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -66
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- 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 -852
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- 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/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 -219
- 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/bookkeeping-outbox.js +0 -270
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
- package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
- 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/risk-verdict.js +0 -105
- 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 -621
- 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/story-run-progress-writer.js +0 -400
- 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/error-journal.js +0 -139
- 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-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- 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/acceptance-reconciler.js +0 -465
- 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 -284
- 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/merge-watcher.js +0 -665
- 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/plan-review-routing.js +0 -63
- 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 -33
- 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 -396
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- 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-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- 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 -302
- 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/retro-run.js +0 -218
- package/.agents/scripts/slice-phase.js +0 -361
- 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 -464
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
- 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 -383
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
- package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
- package/.agents/workflows/helpers/deliver-epic.md +0 -998
- package/.agents/workflows/helpers/deliver-stories.md +0 -450
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
- 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 -353
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- package/.agents/workflows/helpers/single-story-deliver.md +0 -557
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* plan-context.js — single planner-context envelope build
|
|
3
|
-
* PR2 — `/plan` collapse step 1).
|
|
2
|
+
* plan-context.js — single planner-context envelope build for `/plan`.
|
|
4
3
|
*
|
|
5
|
-
* Folds the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `epic-plan-decompose/phases/context.js`) plus the three currently-no-CLI
|
|
9
|
-
* library calls (`findSimilarOpenEpics`, clarity scoring, re-plan
|
|
10
|
-
* detection) into ONE JSON envelope, so the authoring middle reads a single
|
|
11
|
-
* file instead of shim-scripting library imports (the bench measured
|
|
12
|
-
* ~12–15 turns of shim-writing for the dup search alone).
|
|
4
|
+
* Folds the authoring-context builders plus the cross-Story dup search into
|
|
5
|
+
* ONE JSON envelope, so the authoring middle reads a single file instead of
|
|
6
|
+
* shim-scripting library imports.
|
|
13
7
|
*
|
|
14
|
-
*
|
|
15
|
-
* - `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `duplicates[]` (cross-Epic dup search). Clarity is not
|
|
21
|
-
* scored — the ideation path is definitionally clear.
|
|
22
|
-
* - `seed` — headless ideation entry (#4496 fix 1): the one-pager
|
|
23
|
-
* does not exist yet either. The dup search runs off the
|
|
24
|
-
* raw seed text, and the envelope additively carries
|
|
25
|
-
* `seed`, `scopeTriage` (the scope-triage rubric applied
|
|
26
|
-
* CLI-side — no skill Reads on the headless path) and
|
|
27
|
-
* `onePagerSpec` (the canonical one-pager sections, so
|
|
28
|
-
* the authoring pass writes the one-pager in the SAME
|
|
29
|
-
* batched write as the spec artifacts).
|
|
8
|
+
* Two operator modes (v2 Story-only):
|
|
9
|
+
* - `seed` / `seed-file` — freeform text (chat or on-disk). Carries
|
|
10
|
+
* `seed` plus `duplicates[]` (open-Story dup search).
|
|
11
|
+
* - `tickets` — one or more existing issue ids to analyze into proper
|
|
12
|
+
* Stories. Carries `sourceTickets[]` plus `duplicates[]` (excluding
|
|
13
|
+
* the source ids themselves).
|
|
30
14
|
*
|
|
31
15
|
* All fields are JSON-serialisable; the module performs no GitHub writes.
|
|
32
16
|
* The only I/O surfaces are the injected `provider` (reads) and the
|
|
@@ -34,36 +18,99 @@
|
|
|
34
18
|
*/
|
|
35
19
|
|
|
36
20
|
import { readFile } from 'node:fs/promises';
|
|
37
|
-
import { getLimits
|
|
38
|
-
import {
|
|
39
|
-
import { hasEpicSection, hasTechSpecContent } from '../epic-body-sections.js';
|
|
40
|
-
import { scoreEpicBody } from '../epic-plan-clarity.js';
|
|
21
|
+
import { getLimits } from '../config-resolver.js';
|
|
22
|
+
import { findSimilarOpenStories } from '../duplicate-search.js';
|
|
41
23
|
import { Logger } from '../Logger.js';
|
|
42
24
|
import {
|
|
43
25
|
renderAcceptanceSpecSystemPrompt,
|
|
44
26
|
renderTechSpecSystemPrompt,
|
|
45
27
|
} from '../templates/spec-author-prompts.js';
|
|
28
|
+
import { concurrentMap } from '../util/concurrent-map.js';
|
|
46
29
|
import { parseDeliverySlicingTable } from './consolidation-precondition.js';
|
|
47
30
|
import { buildDocsDigest } from './docs-digest.js';
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import { read as readPlanState } from './epic-plan-state-store.js';
|
|
31
|
+
import { buildAuthoringContext } from './planning/authoring-context.js';
|
|
32
|
+
import { buildDecomposerSystemPrompt } from './planning/decomposer-context.js';
|
|
51
33
|
|
|
34
|
+
/** Bounded concurrency for `--tickets` source-ticket hydration. */
|
|
35
|
+
const SOURCE_TICKET_FETCH_CONCURRENCY = 4;
|
|
52
36
|
/**
|
|
53
37
|
* Envelope byte ceiling (regression guard for the design's named PR2 risk:
|
|
54
|
-
* two envelopes → one bigger one).
|
|
55
|
-
* the `applyBudget
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
38
|
+
* two envelopes → one bigger one). This is the **only** live bound on
|
|
39
|
+
* envelope size: Story #4541 removed the `applyBudget` pass from
|
|
40
|
+
* `buildAuthoringContext`, because both builders below discard that budgeted
|
|
41
|
+
* body and ship the raw seed on `seed.content` instead — the budget bounded
|
|
42
|
+
* a field that never left the function.
|
|
43
|
+
*
|
|
44
|
+
* The envelope's bounded parts are: the tier-capped codebase snapshot
|
|
45
|
+
* (~35 KB skinny on this repo), the three rendered system prompts (~15 KB),
|
|
46
|
+
* and the digest-first `docsContext` (outline-only, or inline digest in
|
|
47
|
+
* one-pager/seed mode). The seed itself is operator-supplied and carried
|
|
48
|
+
* verbatim. Measured folded envelopes on this repo land at ~42 KB; 256 KB
|
|
49
|
+
* (~64K tokens at the ≈4-chars/token estimate) gives >2× headroom over a
|
|
50
|
+
* worst-case seed + medium-tier snapshot while staying an order of magnitude
|
|
51
|
+
* under the session budget. The test suite asserts serialized envelopes stay
|
|
52
|
+
* under this value — raise it only with a measured justification.
|
|
64
53
|
*/
|
|
65
54
|
export const PLAN_CONTEXT_ENVELOPE_BYTE_CEILING = 256_000;
|
|
66
55
|
|
|
56
|
+
/** Fields named in the over-ceiling error, to point at what to trim. */
|
|
57
|
+
const OVERSIZE_REPORT_FIELDS = 3;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fail closed when an assembled envelope exceeds
|
|
61
|
+
* {@link PLAN_CONTEXT_ENVELOPE_BYTE_CEILING}.
|
|
62
|
+
*
|
|
63
|
+
* Until now the ceiling was enforced *only* by a test assertion over this
|
|
64
|
+
* repo's own fixtures, which bounds nothing at runtime: the value it actually
|
|
65
|
+
* has to hold for is a consumer's seed or `--tickets` source bodies, and no
|
|
66
|
+
* test sees those. That left the documented planner-context cap resting
|
|
67
|
+
* entirely on `planning.context.maxBytes` — which resolved but was wired to
|
|
68
|
+
* nothing (its `applyBudget` pass lost its last caller in the v2 cutover), so
|
|
69
|
+
* in practice no bound existed at all on the path that needed one. That key
|
|
70
|
+
* and its budget module were removed outright in Story #4541; this ceiling is
|
|
71
|
+
* the replacement.
|
|
72
|
+
*
|
|
73
|
+
* Failing closed is the right direction here and matches how an over-budget
|
|
74
|
+
* `## Spec` is handled (`spec-spill.js`): an envelope this size does not
|
|
75
|
+
* degrade the planner gracefully, it silently produces garbage Stories from a
|
|
76
|
+
* truncated-by-the-host context. Better to refuse and say what to trim. The
|
|
77
|
+
* bound is deliberately a fixed framework constant rather than an operator
|
|
78
|
+
* knob — a cap the operator can raise past what the model can read is a cap
|
|
79
|
+
* that fails silently again.
|
|
80
|
+
*
|
|
81
|
+
* Deliberately **not** exported: its only external caller would be a test, and
|
|
82
|
+
* a test-only export is a production-dead one. It is reachable end to end
|
|
83
|
+
* through {@link buildPlanContext}, which is where the behaviour matters.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} envelope
|
|
86
|
+
* @param {{ ceiling?: number }} [opts]
|
|
87
|
+
* @returns {object} `envelope`, unchanged, when it fits.
|
|
88
|
+
*/
|
|
89
|
+
function assertPlanContextWithinCeiling(envelope, opts = {}) {
|
|
90
|
+
const ceiling = opts.ceiling ?? PLAN_CONTEXT_ENVELOPE_BYTE_CEILING;
|
|
91
|
+
const bytes = Buffer.byteLength(JSON.stringify(envelope) ?? '', 'utf-8');
|
|
92
|
+
if (bytes <= ceiling) return envelope;
|
|
93
|
+
|
|
94
|
+
const largest = Object.entries(envelope)
|
|
95
|
+
.map(([field, value]) => [
|
|
96
|
+
field,
|
|
97
|
+
Buffer.byteLength(JSON.stringify(value) ?? '', 'utf-8'),
|
|
98
|
+
])
|
|
99
|
+
.sort((a, b) => b[1] - a[1])
|
|
100
|
+
.slice(0, OVERSIZE_REPORT_FIELDS)
|
|
101
|
+
.map(([field, size]) => `${field} (${Math.round(size / 1024)} KB)`)
|
|
102
|
+
.join(', ');
|
|
103
|
+
|
|
104
|
+
throw new Error(
|
|
105
|
+
`[plan-context] the assembled "${envelope?.mode}" envelope is ` +
|
|
106
|
+
`${Math.round(bytes / 1024)} KB, over the ` +
|
|
107
|
+
`${Math.round(ceiling / 1024)} KB planner-context ceiling. Largest ` +
|
|
108
|
+
`fields: ${largest}. Trim the seed, plan fewer --tickets source issues ` +
|
|
109
|
+
'in one run, or narrow `planning.codebaseSnapshot`. Raising the ceiling ' +
|
|
110
|
+
'needs a measured justification — see PLAN_CONTEXT_ENVELOPE_BYTE_CEILING.',
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
67
114
|
/**
|
|
68
115
|
* Compact, machine-readable descriptor of the `tickets.json` array the
|
|
69
116
|
* authoring pass writes and `validateAndNormalizeTickets` gates at persist
|
|
@@ -77,47 +124,23 @@ export const TICKET_SCHEMA_DESCRIPTOR = Object.freeze({
|
|
|
77
124
|
slug: 'string — ^[a-z0-9][a-z0-9-]*$ (hyphen-case, unique per decompose)',
|
|
78
125
|
type: "string — literal 'story' (2-tier hierarchy: Epic → Story only)",
|
|
79
126
|
title: 'string — short descriptive title',
|
|
80
|
-
body: 'string — serialized Story-body markdown (never a JSON object)',
|
|
81
|
-
acceptance:
|
|
82
|
-
|
|
83
|
-
|
|
127
|
+
body: 'string — serialized Story-body markdown (never a JSON object); omit the ## Acceptance / ## Verify sections, persist syncs them in',
|
|
128
|
+
acceptance:
|
|
129
|
+
'string[] — top-level testable criteria; the machine contract, authored here and not in the body',
|
|
130
|
+
verify:
|
|
131
|
+
'string[] — top-level exact commands/test paths with (<tier>); the machine contract, authored here and not in the body',
|
|
132
|
+
labels:
|
|
133
|
+
"string[]? — extra labels to apply; 'type::story' is applied automatically. agent::*, type::*, and persona::* are rejected (runtime-owned or retired axes)",
|
|
84
134
|
depends_on: 'string[]? — sibling Story slugs that block execution',
|
|
85
135
|
}),
|
|
86
136
|
validatedBy:
|
|
87
137
|
'validateAndNormalizeTickets (lib/orchestration/ticket-validator.js) at persist time',
|
|
88
138
|
});
|
|
89
139
|
|
|
90
|
-
/**
|
|
91
|
-
* Canonical one-pager authoring descriptor for the `seed` envelope
|
|
92
|
-
* (#4496 fix 1). The section names are the ones `plan-epic.md`'s ideation
|
|
93
|
-
* entry has always named, chosen so the authored headings parse against
|
|
94
|
-
* the `SECTION_RE` map in `lib/epic-plan-ideation.js` (which renders the
|
|
95
|
-
* Epic body from the one-pager at persist time via
|
|
96
|
-
* `.agents/templates/epic-from-idea.md`).
|
|
97
|
-
*/
|
|
98
|
-
export const ONE_PAGER_AUTHORING_SPEC = Object.freeze({
|
|
99
|
-
sections: Object.freeze([
|
|
100
|
-
'Problem Statement',
|
|
101
|
-
'Recommended Direction',
|
|
102
|
-
'Key Assumptions',
|
|
103
|
-
'MVP Scope',
|
|
104
|
-
'Not Doing',
|
|
105
|
-
]),
|
|
106
|
-
instruction:
|
|
107
|
-
'Author the one-pager markdown (the canonical sections above, as `## ` ' +
|
|
108
|
-
'headings) in the SAME batched write as the other planning artifacts — ' +
|
|
109
|
-
'no separate ideation pass and no idea-refinement skill activation on ' +
|
|
110
|
-
'this path. Every unresolved unknown lands in Key Assumptions instead ' +
|
|
111
|
-
'of a question.',
|
|
112
|
-
consumedBy:
|
|
113
|
-
'plan-persist.js --one-pager (ideation Epic creation via ' +
|
|
114
|
-
'.agents/templates/epic-from-idea.md)',
|
|
115
|
-
});
|
|
116
|
-
|
|
117
140
|
/**
|
|
118
141
|
* Count top-level enumerated items (`- `, `* `, `1. `) anywhere in a
|
|
119
142
|
* free-form seed text. Unlike {@link countScopeItems} this does not require
|
|
120
|
-
* a scope-shaped heading — a raw `--
|
|
143
|
+
* a scope-shaped heading — a raw `--seed` text rarely has one.
|
|
121
144
|
*
|
|
122
145
|
* @param {string} text
|
|
123
146
|
* @returns {number}
|
|
@@ -138,13 +161,13 @@ const DELTA_VERB_RE =
|
|
|
138
161
|
/\b(fix(?:es)?|tweak(?:s)?|extend(?:s)?|update(?:s)?|adjust(?:s)?|rename(?:s)?|correct(?:s)?|patch(?:es)?|bug|regression|flaky)\b/i;
|
|
139
162
|
|
|
140
163
|
/**
|
|
141
|
-
* Deterministic, CLI-applied scope-triage verdict over a raw `--
|
|
164
|
+
* Deterministic, CLI-applied scope-triage verdict over a raw `--seed` text
|
|
142
165
|
* (#4496 fix 6). Embedding the verdict in the `--seed` envelope removes the
|
|
143
166
|
* two skill Reads (`core/scope-triage` + the gate fragment's rubric pass)
|
|
144
167
|
* from the headless path; the attended path keeps the skill-based judgment.
|
|
145
168
|
*
|
|
146
169
|
* The heuristics anchor to the same sizing SSOT the skill anchors to —
|
|
147
|
-
* `DELIVERABLE_GRANULARITY_GUIDANCE` / `
|
|
170
|
+
* `DELIVERABLE_GRANULARITY_GUIDANCE` / `DEFAULT_MODEL_CAPACITY` in
|
|
148
171
|
* `ticket-validator-sizing.js` (one Story = one coherent capability slice;
|
|
149
172
|
* multiple independent capabilities = an Epic) — and to the skill's
|
|
150
173
|
* change-request delta rubric. Like the skill, the verdict is **advisory**:
|
|
@@ -223,7 +246,7 @@ function resolveRiskHeuristics(config = {}) {
|
|
|
223
246
|
if (Array.isArray(config.planning?.riskHeuristics)) {
|
|
224
247
|
return config.planning.riskHeuristics;
|
|
225
248
|
}
|
|
226
|
-
return
|
|
249
|
+
return [];
|
|
227
250
|
}
|
|
228
251
|
|
|
229
252
|
/**
|
|
@@ -331,43 +354,6 @@ export function buildDeliveryShapeSignal({ body } = {}) {
|
|
|
331
354
|
};
|
|
332
355
|
}
|
|
333
356
|
|
|
334
|
-
/**
|
|
335
|
-
* Re-plan detection signals (folds the workflow's Phase 5 into the
|
|
336
|
-
* envelope): the Tech Spec sections alone are the already-planned signal;
|
|
337
|
-
* the open-Story count and section presence let the authoring middle (and
|
|
338
|
-
* the persist half's `--force` prompt) cite concrete numbers.
|
|
339
|
-
*
|
|
340
|
-
* `openStoryCount` is best-effort: a provider listing failure degrades to
|
|
341
|
-
* `null` rather than aborting the envelope build.
|
|
342
|
-
*
|
|
343
|
-
* @param {{ epicBody: string, provider: object, epicId: number }} args
|
|
344
|
-
* @returns {Promise<{
|
|
345
|
-
* alreadyPlanned: boolean,
|
|
346
|
-
* planningSections: { techSpec: boolean, acceptanceTable: boolean },
|
|
347
|
-
* openStoryCount: number|null,
|
|
348
|
-
* }>}
|
|
349
|
-
*/
|
|
350
|
-
export async function buildReplanSignal({ epicBody, provider, epicId }) {
|
|
351
|
-
const body = epicBody ?? '';
|
|
352
|
-
let openStoryCount = null;
|
|
353
|
-
try {
|
|
354
|
-
const tickets = await provider.getTickets(epicId, { state: 'open' });
|
|
355
|
-
if (Array.isArray(tickets)) openStoryCount = tickets.length;
|
|
356
|
-
} catch (err) {
|
|
357
|
-
Logger.warn(
|
|
358
|
-
`[plan-context] open-children listing skipped: ${err?.message ?? err}`,
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
return {
|
|
362
|
-
alreadyPlanned: hasTechSpecContent(body),
|
|
363
|
-
planningSections: {
|
|
364
|
-
techSpec: hasEpicSection(body, 'techSpec'),
|
|
365
|
-
acceptanceTable: hasEpicSection(body, 'acceptanceTable'),
|
|
366
|
-
},
|
|
367
|
-
openStoryCount,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
357
|
/**
|
|
372
358
|
* Render the three authoring system prompts the collapsed pipeline's
|
|
373
359
|
* single authoring pass consumes. The spec/acceptance prompts render from
|
|
@@ -375,89 +361,134 @@ export async function buildReplanSignal({ epicBody, provider, epicId }) {
|
|
|
375
361
|
* authoritative from day one); the decompose prompt reuses the existing
|
|
376
362
|
* Story #4162 carrier including the risk-heuristics suffix.
|
|
377
363
|
*
|
|
378
|
-
* @param {{ heuristics?: string[], maxTickets?: number,
|
|
364
|
+
* @param {{ heuristics?: string[], maxTickets?: number, epicId?: number|null }} args
|
|
379
365
|
* @returns {{ spec: string, acceptance: string, decompose: string }}
|
|
380
366
|
*/
|
|
381
367
|
export function buildSystemPrompts({
|
|
382
368
|
heuristics = [],
|
|
383
369
|
maxTickets,
|
|
384
|
-
maxTokenBudget,
|
|
385
370
|
epicId = null,
|
|
386
371
|
} = {}) {
|
|
372
|
+
const decompose = buildDecomposerSystemPrompt(heuristics, {
|
|
373
|
+
maxTickets,
|
|
374
|
+
epicId,
|
|
375
|
+
});
|
|
387
376
|
return {
|
|
388
377
|
spec: renderTechSpecSystemPrompt(),
|
|
389
378
|
acceptance: renderAcceptanceSpecSystemPrompt(),
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
379
|
+
// v2 Stage 3: default-single author prompt (decompose text + split policy).
|
|
380
|
+
story: `${decompose}
|
|
381
|
+
|
|
382
|
+
#### v2 DEFAULT-SINGLE SPLIT POLICY:
|
|
383
|
+
|
|
384
|
+
Emit **exactly one Story** in \`stories.json\` unless the pieces have
|
|
385
|
+
near-zero overlap or sit across an architectural seam. Coupled work stays
|
|
386
|
+
one Story — put intra-session checkpoints in \`## Slicing\` and fold the
|
|
387
|
+
Tech Spec into \`## Spec\` (inline only; over-budget Specs mean split or
|
|
388
|
+
tighten — never write under \`docs/\`). Do **not** emit \`deliveryShape\`.
|
|
389
|
+
When N>1, every acceptance criterion must belong to exactly one Story,
|
|
390
|
+
and each Story carries its own \`## Spec\` (no shared techspec.md fold).
|
|
391
|
+
`,
|
|
392
|
+
decompose,
|
|
395
393
|
};
|
|
396
394
|
}
|
|
397
395
|
|
|
398
396
|
/**
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
* tolerance the decompose context applies).
|
|
397
|
+
* Run the open-Story duplicate search. Failures degrade to [] — triage
|
|
398
|
+
* signal, not a gate.
|
|
402
399
|
*
|
|
403
|
-
* @param {{
|
|
404
|
-
*
|
|
400
|
+
* @param {{
|
|
401
|
+
* seed: string,
|
|
402
|
+
* provider: object,
|
|
403
|
+
* config: object,
|
|
404
|
+
* excludeIds?: Iterable<number|string>,
|
|
405
|
+
* }} args
|
|
406
|
+
* @returns {Promise<Array<object>>}
|
|
405
407
|
*/
|
|
406
|
-
async function
|
|
408
|
+
async function searchStoryDuplicates({
|
|
409
|
+
seed,
|
|
410
|
+
provider,
|
|
411
|
+
config,
|
|
412
|
+
excludeIds = [],
|
|
413
|
+
}) {
|
|
407
414
|
try {
|
|
408
|
-
return await
|
|
409
|
-
|
|
410
|
-
|
|
415
|
+
return await findSimilarOpenStories({
|
|
416
|
+
seed,
|
|
417
|
+
provider,
|
|
418
|
+
owner: config.github?.owner,
|
|
419
|
+
repo: config.github?.repo,
|
|
420
|
+
excludeIds,
|
|
421
|
+
});
|
|
422
|
+
} catch (err) {
|
|
423
|
+
Logger.warn(
|
|
424
|
+
`[plan-context] duplicate search degraded to no candidates: ${err?.message ?? err}`,
|
|
425
|
+
);
|
|
426
|
+
return [];
|
|
411
427
|
}
|
|
412
428
|
}
|
|
413
429
|
|
|
414
430
|
/**
|
|
415
|
-
* Build the
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
431
|
+
* Build the seed-file (ideation) envelope. No parent ticket
|
|
432
|
+
* exists yet — creation moves to the persist half — so the open-Story
|
|
433
|
+
* dup search is the mode's gating input. `docsContext` is inline-digest:
|
|
434
|
+
* there is no plan temp directory to anchor a digest file to yet.
|
|
419
435
|
*/
|
|
420
|
-
async function
|
|
421
|
-
|
|
436
|
+
async function buildSeedFileModeEnvelope({
|
|
437
|
+
seedFilePath,
|
|
438
|
+
seedFileContent,
|
|
422
439
|
provider,
|
|
423
440
|
config,
|
|
424
441
|
settings,
|
|
425
|
-
fullContext,
|
|
426
442
|
cwd,
|
|
443
|
+
modeLabel = 'seed-file',
|
|
427
444
|
}) {
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
445
|
+
const content =
|
|
446
|
+
seedFileContent ?? (await readFile(seedFilePath ?? '', 'utf-8'));
|
|
447
|
+
if (typeof content !== 'string' || content.trim().length === 0) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
`[plan-context] seed-file at ${seedFilePath ?? '(inline)'} is empty — nothing to plan from.`,
|
|
450
|
+
);
|
|
431
451
|
}
|
|
432
|
-
const body = epic.body ?? '';
|
|
433
452
|
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
fullContext,
|
|
437
|
-
github: config.github ?? null,
|
|
438
|
-
};
|
|
439
|
-
if (cwd) authoringOpts.cwd = cwd;
|
|
440
|
-
const authoring = await buildAuthoringContext(
|
|
441
|
-
epicId,
|
|
453
|
+
const duplicates = await searchStoryDuplicates({
|
|
454
|
+
seed: content,
|
|
442
455
|
provider,
|
|
443
|
-
|
|
444
|
-
|
|
456
|
+
config,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// Fold the authoring-context builders grounded in the seed prose.
|
|
460
|
+
// `docsContextFiles` is emptied for this call: the per-plan digest-file
|
|
461
|
+
// path needs a plan id that does not exist yet — the inline digest
|
|
462
|
+
// below replaces it.
|
|
463
|
+
const authoring = await buildAuthoringContext(
|
|
464
|
+
0,
|
|
465
|
+
/* provider (unused behind the prefetch seam) */ {},
|
|
466
|
+
{ ...settings, docsContextFiles: [] },
|
|
467
|
+
{
|
|
468
|
+
epic: { id: 0, title: seedFilePath ?? 'seed', body: content },
|
|
469
|
+
github: config.github ?? null,
|
|
470
|
+
cwd,
|
|
471
|
+
},
|
|
445
472
|
);
|
|
446
473
|
|
|
474
|
+
const paths = settings?.paths ?? {};
|
|
475
|
+
const inlineDigest = await buildDocsDigest({
|
|
476
|
+
docsContextFiles: settings?.docsContextFiles,
|
|
477
|
+
docsRoot: paths.docsRoot,
|
|
478
|
+
});
|
|
479
|
+
const docsContext =
|
|
480
|
+
inlineDigest == null
|
|
481
|
+
? null
|
|
482
|
+
: { mode: 'digest-inline', digest: inlineDigest };
|
|
483
|
+
|
|
447
484
|
const limits = getLimits(config);
|
|
448
485
|
const heuristics = resolveRiskHeuristics(config);
|
|
449
|
-
const clarityScore = scoreEpicBody({ body });
|
|
450
|
-
const [replan, planState] = await Promise.all([
|
|
451
|
-
buildReplanSignal({ epicBody: body, provider, epicId }),
|
|
452
|
-
readPlanStateTolerant({ provider, epicId }),
|
|
453
|
-
]);
|
|
454
486
|
|
|
455
487
|
return {
|
|
456
|
-
mode:
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
docsContext: authoring.docsContext,
|
|
488
|
+
mode: modeLabel,
|
|
489
|
+
seed: { path: seedFilePath ?? null, content },
|
|
490
|
+
duplicates,
|
|
491
|
+
docsContext,
|
|
461
492
|
codebaseSnapshot: authoring.codebaseSnapshot,
|
|
462
493
|
bddRunner: authoring.bddRunner,
|
|
463
494
|
bddScenarios: authoring.bddScenarios,
|
|
@@ -465,84 +496,134 @@ async function buildEpicModeEnvelope({
|
|
|
465
496
|
priorFeedback: authoring.priorFeedback,
|
|
466
497
|
ticketSchema: TICKET_SCHEMA_DESCRIPTOR,
|
|
467
498
|
maxTickets: limits.maxTickets,
|
|
468
|
-
maxTokenBudget: limits.maxTokenBudget,
|
|
469
|
-
preflightCeilings: resolvePreflightCeilings(config),
|
|
470
499
|
riskHeuristics: heuristics,
|
|
471
500
|
systemPrompts: buildSystemPrompts({
|
|
472
501
|
heuristics,
|
|
473
502
|
maxTickets: limits.maxTickets,
|
|
474
|
-
|
|
475
|
-
epicId,
|
|
503
|
+
epicId: null,
|
|
476
504
|
}),
|
|
477
|
-
|
|
478
|
-
|
|
505
|
+
planState: null,
|
|
506
|
+
// N=1 default: author one Story; skip Epic-scale decompose ceremony.
|
|
507
|
+
planProfile: 'story-default',
|
|
479
508
|
};
|
|
480
509
|
}
|
|
481
510
|
|
|
482
511
|
/**
|
|
483
|
-
* Build the
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
* mode's gating input. `docsContext` is inline-digest (the standalone
|
|
487
|
-
* `story-plan.js --emit-context` convention): there is no per-Epic temp
|
|
488
|
-
* directory to anchor a digest file to yet.
|
|
512
|
+
* Build the seed-mode (chat text) envelope. The seed-file does not exist
|
|
513
|
+
* yet: the dup search and the authoring-context fold both run off the raw
|
|
514
|
+
* seed text (N=1 default — no Epic-scale decompose).
|
|
489
515
|
*/
|
|
490
|
-
async function
|
|
491
|
-
|
|
492
|
-
onePagerContent,
|
|
516
|
+
async function buildSeedModeEnvelope({
|
|
517
|
+
seedText,
|
|
493
518
|
provider,
|
|
494
519
|
config,
|
|
495
520
|
settings,
|
|
496
|
-
fullContext,
|
|
497
521
|
cwd,
|
|
498
522
|
}) {
|
|
499
|
-
|
|
500
|
-
onePagerContent ?? (await readFile(onePagerPath ?? '', 'utf-8'));
|
|
501
|
-
if (typeof content !== 'string' || content.trim().length === 0) {
|
|
523
|
+
if (typeof seedText !== 'string' || seedText.trim().length === 0) {
|
|
502
524
|
throw new Error(
|
|
503
|
-
|
|
525
|
+
'[plan-context] --seed requires non-empty seed text — nothing to plan from.',
|
|
504
526
|
);
|
|
505
527
|
}
|
|
528
|
+
const base = await buildSeedFileModeEnvelope({
|
|
529
|
+
seedFilePath: undefined,
|
|
530
|
+
seedFileContent: seedText,
|
|
531
|
+
provider,
|
|
532
|
+
config,
|
|
533
|
+
settings,
|
|
534
|
+
cwd,
|
|
535
|
+
modeLabel: 'seed',
|
|
536
|
+
});
|
|
537
|
+
const { seed: _seed, ...rest } = base;
|
|
538
|
+
return {
|
|
539
|
+
...rest,
|
|
540
|
+
mode: 'seed',
|
|
541
|
+
seed: { text: seedText, path: null },
|
|
542
|
+
};
|
|
543
|
+
}
|
|
506
544
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
545
|
+
/**
|
|
546
|
+
* Fetch source tickets for `--tickets` mode.
|
|
547
|
+
* Hydrates ids concurrently (bounded) while preserving input order.
|
|
548
|
+
*
|
|
549
|
+
* @param {number[]} ticketIds
|
|
550
|
+
* @param {object} provider
|
|
551
|
+
* @returns {Promise<Array<{ id:number, title:string, body:string, labels:string[], url?:string }>>}
|
|
552
|
+
*/
|
|
553
|
+
async function fetchSourceTickets(ticketIds, provider) {
|
|
554
|
+
if (!provider || typeof provider.getTicket !== 'function') {
|
|
555
|
+
throw new Error(
|
|
556
|
+
'[plan-context] tickets mode requires provider.getTicket()',
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
return concurrentMap(
|
|
560
|
+
ticketIds,
|
|
561
|
+
async (id) => {
|
|
562
|
+
const ticket = await provider.getTicket(id);
|
|
563
|
+
if (!ticket) {
|
|
564
|
+
throw new Error(`[plan-context] ticket #${id} not found`);
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
id: Number(ticket.id ?? ticket.number ?? id),
|
|
568
|
+
title: ticket.title ?? '',
|
|
569
|
+
body: ticket.body ?? '',
|
|
570
|
+
labels: Array.isArray(ticket.labels)
|
|
571
|
+
? ticket.labels
|
|
572
|
+
.map((l) => (typeof l === 'string' ? l : l?.name))
|
|
573
|
+
.filter(Boolean)
|
|
574
|
+
: [],
|
|
575
|
+
url: ticket.html_url ?? ticket.url ?? undefined,
|
|
576
|
+
state: ticket.state ?? undefined,
|
|
577
|
+
};
|
|
578
|
+
},
|
|
579
|
+
{ concurrency: SOURCE_TICKET_FETCH_CONCURRENCY },
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Build the tickets-mode envelope — analyze existing issue(s) into proper
|
|
585
|
+
* Stories. Dup search excludes the source ids so a ticket is not reported
|
|
586
|
+
* as a duplicate of itself.
|
|
587
|
+
*/
|
|
588
|
+
async function buildTicketsModeEnvelope({
|
|
589
|
+
ticketIds,
|
|
590
|
+
provider,
|
|
591
|
+
config,
|
|
592
|
+
settings,
|
|
593
|
+
cwd,
|
|
594
|
+
}) {
|
|
595
|
+
if (!Array.isArray(ticketIds) || ticketIds.length === 0) {
|
|
596
|
+
throw new Error(
|
|
597
|
+
'[plan-context] --tickets requires one or more positive issue ids.',
|
|
521
598
|
);
|
|
522
|
-
duplicates = [];
|
|
523
599
|
}
|
|
600
|
+
const sourceTickets = await fetchSourceTickets(ticketIds, provider);
|
|
601
|
+
const seed = sourceTickets
|
|
602
|
+
.map((t) => `# ${t.title}\n\n${t.body}`)
|
|
603
|
+
.join('\n\n---\n\n');
|
|
604
|
+
|
|
605
|
+
const duplicates = await searchStoryDuplicates({
|
|
606
|
+
seed,
|
|
607
|
+
provider,
|
|
608
|
+
config,
|
|
609
|
+
excludeIds: ticketIds,
|
|
610
|
+
});
|
|
524
611
|
|
|
525
|
-
// Fold the same authoring-context builders the epic path uses, grounded
|
|
526
|
-
// in the one-pager prose instead of an Epic body. Reuse
|
|
527
|
-
// `buildAuthoringContext` via the prefetch seam so the fold has exactly
|
|
528
|
-
// one implementation of the snapshot/BDD/memory/feedback pipeline to
|
|
529
|
-
// drift from. `docsContextFiles` is emptied for this call: the per-Epic
|
|
530
|
-
// digest-file path needs an Epic id (and a temp directory) that does not
|
|
531
|
-
// exist yet — the inline digest below replaces it.
|
|
532
612
|
const authoring = await buildAuthoringContext(
|
|
533
613
|
0,
|
|
534
|
-
|
|
614
|
+
{},
|
|
535
615
|
{ ...settings, docsContextFiles: [] },
|
|
536
616
|
{
|
|
537
|
-
epic: {
|
|
538
|
-
|
|
617
|
+
epic: {
|
|
618
|
+
id: 0,
|
|
619
|
+
title: sourceTickets[0]?.title ?? 'tickets',
|
|
620
|
+
body: seed,
|
|
621
|
+
},
|
|
539
622
|
github: config.github ?? null,
|
|
540
623
|
cwd,
|
|
541
624
|
},
|
|
542
625
|
);
|
|
543
626
|
|
|
544
|
-
// Replace the per-Epic digest-file pointer with an inline digest — the
|
|
545
|
-
// Epic (and its temp directory) does not exist yet.
|
|
546
627
|
const paths = settings?.paths ?? {};
|
|
547
628
|
const inlineDigest = await buildDocsDigest({
|
|
548
629
|
docsContextFiles: settings?.docsContextFiles,
|
|
@@ -557,8 +638,9 @@ async function buildOnePagerModeEnvelope({
|
|
|
557
638
|
const heuristics = resolveRiskHeuristics(config);
|
|
558
639
|
|
|
559
640
|
return {
|
|
560
|
-
mode: '
|
|
561
|
-
|
|
641
|
+
mode: 'tickets',
|
|
642
|
+
sourceTickets,
|
|
643
|
+
seed: { text: seed, path: null },
|
|
562
644
|
duplicates,
|
|
563
645
|
docsContext,
|
|
564
646
|
codebaseSnapshot: authoring.codebaseSnapshot,
|
|
@@ -568,70 +650,36 @@ async function buildOnePagerModeEnvelope({
|
|
|
568
650
|
priorFeedback: authoring.priorFeedback,
|
|
569
651
|
ticketSchema: TICKET_SCHEMA_DESCRIPTOR,
|
|
570
652
|
maxTickets: limits.maxTickets,
|
|
571
|
-
maxTokenBudget: limits.maxTokenBudget,
|
|
572
|
-
preflightCeilings: resolvePreflightCeilings(config),
|
|
573
653
|
riskHeuristics: heuristics,
|
|
574
654
|
systemPrompts: buildSystemPrompts({
|
|
575
655
|
heuristics,
|
|
576
656
|
maxTickets: limits.maxTickets,
|
|
577
|
-
maxTokenBudget: limits.maxTokenBudget,
|
|
578
657
|
epicId: null,
|
|
579
658
|
}),
|
|
580
|
-
deliveryShapeSignal: buildDeliveryShapeSignal({ body: content }),
|
|
581
659
|
planState: null,
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
* uses), and the envelope additively carries `seed`, the CLI-applied
|
|
590
|
-
* `scopeTriage` verdict (fix 6 — no skill Reads on the headless path), and
|
|
591
|
-
* `onePagerSpec` so the one-pager sections are authored in the same batched
|
|
592
|
-
* write as the spec artifacts.
|
|
593
|
-
*/
|
|
594
|
-
async function buildSeedModeEnvelope({
|
|
595
|
-
seedText,
|
|
596
|
-
provider,
|
|
597
|
-
config,
|
|
598
|
-
settings,
|
|
599
|
-
fullContext,
|
|
600
|
-
cwd,
|
|
601
|
-
}) {
|
|
602
|
-
if (typeof seedText !== 'string' || seedText.trim().length === 0) {
|
|
603
|
-
throw new Error(
|
|
604
|
-
'[plan-context] --seed requires non-empty seed text — nothing to plan from.',
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
const base = await buildOnePagerModeEnvelope({
|
|
608
|
-
onePagerPath: undefined,
|
|
609
|
-
onePagerContent: seedText,
|
|
610
|
-
provider,
|
|
611
|
-
config,
|
|
612
|
-
settings,
|
|
613
|
-
fullContext,
|
|
614
|
-
cwd,
|
|
615
|
-
});
|
|
616
|
-
const { onePager: _onePager, ...rest } = base;
|
|
617
|
-
return {
|
|
618
|
-
...rest,
|
|
619
|
-
mode: 'seed',
|
|
620
|
-
seed: { text: seedText },
|
|
621
|
-
scopeTriage: buildScopeTriageSignal({ seedText }),
|
|
622
|
-
onePagerSpec: ONE_PAGER_AUTHORING_SPEC,
|
|
660
|
+
planProfile:
|
|
661
|
+
ticketIds.length === 1 ? 'story-default' : 'story-from-tickets',
|
|
662
|
+
instruction:
|
|
663
|
+
'Analyze the source ticket(s) and author proper type::story ' +
|
|
664
|
+
'ticket(s) under the default-single split policy. Prefer rewriting ' +
|
|
665
|
+
'the source into one well-formed Story (N=1) unless the split policy ' +
|
|
666
|
+
'applies. Do not open an Epic.',
|
|
623
667
|
};
|
|
624
668
|
}
|
|
625
669
|
|
|
626
670
|
/**
|
|
627
671
|
* Build the single planner-context envelope.
|
|
628
672
|
*
|
|
673
|
+
* Every mode returns through here, which makes this the one place the
|
|
674
|
+
* envelope's total size is decided — and therefore the only honest place to
|
|
675
|
+
* bound it (see {@link assertPlanContextWithinCeiling}).
|
|
676
|
+
*
|
|
629
677
|
* @param {{
|
|
630
|
-
* mode: '
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
* onePagerContent?: string,
|
|
678
|
+
* mode: 'seed-file'|'seed'|'tickets',
|
|
679
|
+
* seedFilePath?: string,
|
|
680
|
+
* seedFileContent?: string,
|
|
634
681
|
* seedText?: string,
|
|
682
|
+
* ticketIds?: number[],
|
|
635
683
|
* provider: object,
|
|
636
684
|
* config: object,
|
|
637
685
|
* settings: object,
|
|
@@ -641,43 +689,59 @@ async function buildSeedModeEnvelope({
|
|
|
641
689
|
*/
|
|
642
690
|
export async function buildPlanContext({
|
|
643
691
|
mode,
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
onePagerContent,
|
|
692
|
+
seedFilePath,
|
|
693
|
+
seedFileContent,
|
|
647
694
|
seedText,
|
|
695
|
+
ticketIds,
|
|
648
696
|
provider,
|
|
649
697
|
config = {},
|
|
650
698
|
settings = {},
|
|
651
|
-
fullContext = false,
|
|
652
699
|
cwd,
|
|
653
700
|
}) {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
701
|
+
return assertPlanContextWithinCeiling(
|
|
702
|
+
await buildPlanContextEnvelope({
|
|
703
|
+
mode,
|
|
704
|
+
seedFilePath,
|
|
705
|
+
seedFileContent,
|
|
706
|
+
seedText,
|
|
707
|
+
ticketIds,
|
|
660
708
|
provider,
|
|
661
709
|
config,
|
|
662
710
|
settings,
|
|
663
|
-
fullContext,
|
|
664
711
|
cwd,
|
|
665
|
-
})
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
712
|
+
}),
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Mode dispatch for {@link buildPlanContext}. Split out so the ceiling check
|
|
718
|
+
* wraps every mode exactly once.
|
|
719
|
+
*/
|
|
720
|
+
async function buildPlanContextEnvelope({
|
|
721
|
+
mode,
|
|
722
|
+
seedFilePath,
|
|
723
|
+
seedFileContent,
|
|
724
|
+
seedText,
|
|
725
|
+
ticketIds,
|
|
726
|
+
provider,
|
|
727
|
+
config,
|
|
728
|
+
settings,
|
|
729
|
+
cwd,
|
|
730
|
+
}) {
|
|
731
|
+
if (mode === 'seed-file') {
|
|
732
|
+
if (!seedFilePath && typeof seedFileContent !== 'string') {
|
|
669
733
|
throw new Error(
|
|
670
|
-
'[plan-context]
|
|
734
|
+
'[plan-context] seed-file mode requires --seed-file <path>.',
|
|
671
735
|
);
|
|
672
736
|
}
|
|
673
|
-
return
|
|
674
|
-
|
|
675
|
-
|
|
737
|
+
return buildSeedFileModeEnvelope({
|
|
738
|
+
seedFilePath,
|
|
739
|
+
seedFileContent,
|
|
676
740
|
provider,
|
|
677
741
|
config,
|
|
678
742
|
settings,
|
|
679
|
-
fullContext,
|
|
680
743
|
cwd,
|
|
744
|
+
modeLabel: 'seed-file',
|
|
681
745
|
});
|
|
682
746
|
}
|
|
683
747
|
if (mode === 'seed') {
|
|
@@ -686,11 +750,19 @@ export async function buildPlanContext({
|
|
|
686
750
|
provider,
|
|
687
751
|
config,
|
|
688
752
|
settings,
|
|
689
|
-
|
|
753
|
+
cwd,
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
if (mode === 'tickets') {
|
|
757
|
+
return buildTicketsModeEnvelope({
|
|
758
|
+
ticketIds,
|
|
759
|
+
provider,
|
|
760
|
+
config,
|
|
761
|
+
settings,
|
|
690
762
|
cwd,
|
|
691
763
|
});
|
|
692
764
|
}
|
|
693
765
|
throw new Error(
|
|
694
|
-
`[plan-context] unknown mode "${mode}" — expected "
|
|
766
|
+
`[plan-context] unknown mode "${mode}" — expected "seed", "seed-file", or "tickets".`,
|
|
695
767
|
);
|
|
696
768
|
}
|