mandrel 2.60.0 → 2.61.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 +10 -10
- package/.agents/agents/story-worker.md +1 -1
- package/.agents/docs/agentrc-reference.json +4 -82
- package/.agents/docs/configuration.md +20 -87
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +1 -3
- package/.agents/rules/gherkin-standards.md +4 -0
- package/.agents/schemas/agentrc.schema.json +11 -486
- package/.agents/schemas/story-deliver-terminal.schema.json +10 -0
- package/.agents/schemas/validation-evidence.schema.json +2 -1
- package/.agents/scripts/README.md +14 -14
- package/.agents/scripts/acceptance-eval.js +32 -164
- package/.agents/scripts/agents-bootstrap-github.js +27 -129
- package/.agents/scripts/apply-quality-bootstrap.js +4 -40
- package/.agents/scripts/audit-baselines.js +6 -27
- package/.agents/scripts/audit-labels-bootstrap.js +5 -29
- package/.agents/scripts/audit-to-stories.js +91 -361
- package/.agents/scripts/boot-sweep.js +19 -72
- package/.agents/scripts/bootstrap.js +74 -395
- package/.agents/scripts/ceremony-derive.js +9 -45
- package/.agents/scripts/check-arch-cycles.js +14 -64
- package/.agents/scripts/check-baselines.js +8 -48
- package/.agents/scripts/check-context-budget.js +46 -172
- package/.agents/scripts/check-cyclomatic.js +12 -44
- package/.agents/scripts/check-dead-exports.js +13 -64
- package/.agents/scripts/check-doc-links.js +38 -186
- package/.agents/scripts/check-gherkin-corpus.js +24 -127
- package/.agents/scripts/check-test-temp-hygiene.js +28 -169
- package/.agents/scripts/coverage-capture.js +32 -99
- package/.agents/scripts/deliver-light.js +14 -101
- package/.agents/scripts/deliver-recover.js +6 -42
- package/.agents/scripts/deliver-run.js +36 -133
- package/.agents/scripts/diagnose-friction.js +24 -116
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +23 -85
- package/.agents/scripts/file-ci-gap.js +10 -50
- package/.agents/scripts/generate-config-docs.js +30 -170
- package/.agents/scripts/generate-lens-checklists.js +8 -52
- package/.agents/scripts/generate-skills-index.js +14 -112
- package/.agents/scripts/generate-workflows-doc.js +10 -70
- package/.agents/scripts/git-cleanup.js +2 -34
- package/.agents/scripts/lib/Graph.js +24 -81
- package/.agents/scripts/lib/ITicketingProvider.js +47 -143
- package/.agents/scripts/lib/Logger.js +14 -76
- package/.agents/scripts/lib/audit-baselines/engine.js +11 -31
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +3 -17
- package/.agents/scripts/lib/audit-baselines/headroom.js +4 -20
- package/.agents/scripts/lib/audit-baselines/hotspots.js +3 -15
- package/.agents/scripts/lib/audit-baselines/kinds.js +23 -89
- package/.agents/scripts/lib/audit-baselines/outliers.js +6 -23
- package/.agents/scripts/lib/audit-baselines/read.js +3 -16
- package/.agents/scripts/lib/audit-baselines/staleness.js +7 -26
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +7 -28
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -20
- package/.agents/scripts/lib/audit-baselines/weights.js +9 -37
- package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +3 -18
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -124
- package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +14 -45
- package/.agents/scripts/lib/audit-suite/findings.js +12 -52
- package/.agents/scripts/lib/audit-suite/frontmatter.js +5 -29
- package/.agents/scripts/lib/audit-suite/index.js +1 -15
- package/.agents/scripts/lib/audit-suite/lens-checklist.js +10 -45
- package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +11 -76
- package/.agents/scripts/lib/audit-suite/runner.js +13 -43
- package/.agents/scripts/lib/audit-suite/selector.js +49 -349
- package/.agents/scripts/lib/audit-suite/substitutions.js +12 -40
- package/.agents/scripts/lib/audit-suite/workflow-loader.js +3 -15
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +11 -73
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +8 -37
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +25 -143
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +14 -80
- package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +4 -18
- package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +7 -40
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +9 -39
- package/.agents/scripts/lib/audit-to-stories/issue-corpus.js +10 -66
- package/.agents/scripts/lib/audit-to-stories/issue-index.js +6 -30
- package/.agents/scripts/lib/audit-to-stories/issues-file.js +6 -36
- package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +17 -69
- package/.agents/scripts/lib/audit-to-stories/ledger-pr.js +17 -85
- package/.agents/scripts/lib/audit-to-stories/ledger-record.js +10 -48
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +38 -146
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +7 -42
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +10 -57
- package/.agents/scripts/lib/baseline-loader.js +12 -51
- package/.agents/scripts/lib/baseline-schema-registry.js +5 -22
- package/.agents/scripts/lib/baselines/component-matcher.js +3 -12
- package/.agents/scripts/lib/baselines/components.js +10 -61
- package/.agents/scripts/lib/baselines/coverage-updater-cli.js +7 -36
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +5 -21
- package/.agents/scripts/lib/baselines/crap-preview-scan.js +19 -45
- package/.agents/scripts/lib/baselines/crap-updater-cli.js +16 -65
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +5 -33
- package/.agents/scripts/lib/baselines/duplication-scanner.js +11 -60
- package/.agents/scripts/lib/baselines/env-overrides.js +12 -67
- package/.agents/scripts/lib/baselines/envelope.js +13 -129
- package/.agents/scripts/lib/baselines/exit-codes.js +6 -49
- package/.agents/scripts/lib/baselines/git-base.js +23 -142
- package/.agents/scripts/lib/baselines/kernel.js +11 -111
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +9 -47
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +8 -51
- package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +7 -62
- package/.agents/scripts/lib/baselines/kinds/bundle-size.js +8 -29
- package/.agents/scripts/lib/baselines/kinds/coverage.js +3 -15
- package/.agents/scripts/lib/baselines/kinds/crap.js +94 -415
- package/.agents/scripts/lib/baselines/kinds/duplication.js +4 -30
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +7 -53
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +15 -80
- package/.agents/scripts/lib/baselines/kinds/mutation.js +12 -72
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +4 -11
- package/.agents/scripts/lib/baselines/merge-envelopes.js +30 -146
- package/.agents/scripts/lib/baselines/path-canon.js +19 -128
- package/.agents/scripts/lib/baselines/preview-gates.js +8 -37
- package/.agents/scripts/lib/baselines/reader.js +14 -107
- package/.agents/scripts/lib/baselines/refresh-service.js +35 -252
- package/.agents/scripts/lib/baselines/scope.js +11 -135
- package/.agents/scripts/lib/baselines/writer.js +16 -149
- package/.agents/scripts/lib/bdd-runner-detect.js +18 -113
- package/.agents/scripts/lib/bdd-scenario-budget.js +9 -36
- package/.agents/scripts/lib/bdd-scenario-scanner.js +11 -73
- package/.agents/scripts/lib/bdd-step-index.js +26 -100
- package/.agents/scripts/lib/bootstrap/baseline-merge-driver.js +23 -103
- package/.agents/scripts/lib/bootstrap/branch-protection.js +2 -5
- package/.agents/scripts/lib/bootstrap/commit-push.js +12 -50
- package/.agents/scripts/lib/bootstrap/gh-preflight.js +14 -101
- package/.agents/scripts/lib/bootstrap/hitl-confirm.js +5 -30
- package/.agents/scripts/lib/bootstrap/install-ledger.js +17 -73
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +17 -121
- package/.agents/scripts/lib/bootstrap/manifest.js +15 -86
- package/.agents/scripts/lib/bootstrap/merge-methods.js +4 -33
- package/.agents/scripts/lib/bootstrap/preflight.js +12 -61
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +34 -235
- package/.agents/scripts/lib/bootstrap/prompt.js +21 -129
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +27 -141
- package/.agents/scripts/lib/bootstrap/summary.js +1 -8
- package/.agents/scripts/lib/bootstrap/workflow-audit.js +11 -84
- package/.agents/scripts/lib/branch-name-guard.js +4 -23
- package/.agents/scripts/lib/changed-files.js +31 -143
- package/.agents/scripts/lib/checks/core-bare-clean.js +4 -24
- package/.agents/scripts/lib/checks/index.js +18 -101
- package/.agents/scripts/lib/checks/loop-health.js +11 -53
- package/.agents/scripts/lib/checks/state.js +16 -91
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +10 -61
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +14 -83
- package/.agents/scripts/lib/child-exec.js +39 -108
- package/.agents/scripts/lib/cli/standard-args.js +9 -116
- package/.agents/scripts/lib/cli-args.js +31 -146
- package/.agents/scripts/lib/cli-usage.js +5 -27
- package/.agents/scripts/lib/cli-utils.js +2 -12
- package/.agents/scripts/lib/close-validation/commands.js +13 -76
- package/.agents/scripts/lib/close-validation/gates.js +92 -331
- package/.agents/scripts/lib/close-validation/process.js +121 -151
- package/.agents/scripts/lib/close-validation/projections/advisories.js +5 -31
- package/.agents/scripts/lib/close-validation/projections/crap.js +19 -67
- package/.agents/scripts/lib/close-validation/projections/head-sha.js +1 -17
- package/.agents/scripts/lib/close-validation/projections/inputs.js +4 -34
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +11 -58
- package/.agents/scripts/lib/close-validation/runner.js +53 -110
- package/.agents/scripts/lib/command-header.js +6 -28
- package/.agents/scripts/lib/config/acceptance-eval.js +4 -30
- package/.agents/scripts/lib/config/baselines.js +3 -14
- package/.agents/scripts/lib/config/ci.js +8 -38
- package/.agents/scripts/lib/config/commands.js +1 -15
- package/.agents/scripts/lib/config/defaults.js +4 -33
- package/.agents/scripts/lib/config/delivery-routing.js +6 -35
- package/.agents/scripts/lib/config/explain.js +9 -80
- package/.agents/scripts/lib/config/gates/coverage.schema.js +0 -12
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +2 -30
- package/.agents/scripts/lib/config/gates/crap.schema.js +1 -34
- package/.agents/scripts/lib/config/gates/duplication.schema.js +1 -8
- package/.agents/scripts/lib/config/gates/index.js +2 -17
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +1 -20
- package/.agents/scripts/lib/config/gates/mutation.schema.js +1 -7
- package/.agents/scripts/lib/config/gates/shared.js +4 -64
- package/.agents/scripts/lib/config/github.js +4 -22
- package/.agents/scripts/lib/config/limits.js +4 -57
- package/.agents/scripts/lib/config/paths.js +2 -21
- package/.agents/scripts/lib/config/qa.js +4 -38
- package/.agents/scripts/lib/config/quality.js +76 -432
- package/.agents/scripts/lib/config/runners.js +12 -56
- package/.agents/scripts/lib/config/runtime.js +13 -57
- package/.agents/scripts/lib/config/shared.js +2 -16
- package/.agents/scripts/lib/config/sync-agentrc.js +9 -50
- package/.agents/scripts/lib/config/temp-paths.js +40 -280
- package/.agents/scripts/lib/config/validate-orchestration.js +5 -17
- package/.agents/scripts/lib/config/worktree-isolation.js +9 -28
- package/.agents/scripts/lib/config-resolver.js +10 -52
- package/.agents/scripts/lib/config-schema-shared.js +1 -4
- package/.agents/scripts/lib/config-settings-schema-delivery.js +12 -294
- package/.agents/scripts/lib/config-settings-schema-quality.js +7 -219
- package/.agents/scripts/lib/config-settings-schema.js +37 -274
- package/.agents/scripts/lib/coverage-baseline.js +20 -110
- package/.agents/scripts/lib/coverage-capture-fullscope.js +12 -37
- package/.agents/scripts/lib/coverage-capture-incremental.js +12 -43
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -24
- package/.agents/scripts/lib/coverage-capture.js +99 -224
- package/.agents/scripts/lib/coverage-utils.js +14 -79
- package/.agents/scripts/lib/cpu-pool.js +17 -123
- package/.agents/scripts/lib/crap-baseline-join.js +16 -88
- package/.agents/scripts/lib/crap-coordinates.js +6 -25
- package/.agents/scripts/lib/crap-engine.js +40 -153
- package/.agents/scripts/lib/crap-method-identity.js +16 -78
- package/.agents/scripts/lib/crap-utils.js +31 -155
- package/.agents/scripts/lib/cyclomatic-ceiling.js +14 -87
- package/.agents/scripts/lib/cyclomatic-scope.js +10 -50
- package/.agents/scripts/lib/dead-exports-knip.js +18 -56
- package/.agents/scripts/lib/dead-exports-mode.js +5 -24
- package/.agents/scripts/lib/degraded-mode.js +3 -26
- package/.agents/scripts/lib/dependency-parser.js +8 -40
- package/.agents/scripts/lib/dependency-version.js +13 -35
- package/.agents/scripts/lib/detect-package-manager.js +6 -36
- package/.agents/scripts/lib/doc-tiers.js +22 -126
- package/.agents/scripts/lib/duplicate-search.js +8 -72
- package/.agents/scripts/lib/env-loader.js +5 -27
- package/.agents/scripts/lib/error-redactor.js +6 -31
- package/.agents/scripts/lib/errors/index.js +2 -22
- package/.agents/scripts/lib/escomplex-ast-compat.js +22 -163
- package/.agents/scripts/lib/escomplex-kernel.js +21 -123
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +93 -419
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +20 -98
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +27 -151
- package/.agents/scripts/lib/findings/audit-ledger.js +23 -97
- package/.agents/scripts/lib/findings/classify-finding.js +14 -69
- package/.agents/scripts/lib/findings/promote-finding.js +14 -112
- package/.agents/scripts/lib/findings/provenance-field.js +11 -52
- package/.agents/scripts/lib/findings/route-finding.js +37 -255
- package/.agents/scripts/lib/findings/semantic-issue-search.js +14 -59
- package/.agents/scripts/lib/findings/severity.js +18 -104
- package/.agents/scripts/lib/format-generated-json.js +12 -44
- package/.agents/scripts/lib/full-suite-lock.js +160 -429
- package/.agents/scripts/lib/full-suite-queue.js +213 -0
- package/.agents/scripts/lib/gates/baseline-store.js +5 -9
- package/.agents/scripts/lib/gates/friction.js +1 -3
- package/.agents/scripts/lib/generated/agentrc-validator.js +2 -2
- package/.agents/scripts/lib/gh-exec.js +31 -259
- package/.agents/scripts/lib/git/cached-fetch.js +9 -52
- package/.agents/scripts/lib/git/sync-from-base.js +15 -107
- package/.agents/scripts/lib/git-branch-cleanup.js +14 -61
- package/.agents/scripts/lib/git-branch-lifecycle.js +16 -87
- package/.agents/scripts/lib/git-utils.js +37 -161
- package/.agents/scripts/lib/github/framework-repo.js +8 -71
- package/.agents/scripts/lib/github-url.js +2 -17
- package/.agents/scripts/lib/import-graph.js +11 -38
- package/.agents/scripts/lib/install-cmd-parser.js +4 -13
- package/.agents/scripts/lib/json-utils.js +3 -18
- package/.agents/scripts/lib/label-constants.js +16 -111
- package/.agents/scripts/lib/label-taxonomy.js +4 -30
- package/.agents/scripts/lib/maintainability-engine.js +12 -80
- package/.agents/scripts/lib/maintainability-unscorable.js +5 -25
- package/.agents/scripts/lib/maintainability-utils.js +16 -92
- package/.agents/scripts/lib/mandrel-catalog.js +12 -70
- package/.agents/scripts/lib/notifications/notifier.js +13 -38
- package/.agents/scripts/lib/npm-scripts.js +4 -23
- package/.agents/scripts/lib/observability/metrics-ledger.js +16 -76
- package/.agents/scripts/lib/observability/runtime-friction.js +44 -286
- package/.agents/scripts/lib/observability/signal-validator.js +5 -37
- package/.agents/scripts/lib/observability/signals-writer.js +11 -121
- package/.agents/scripts/lib/observability/source-classifier.js +21 -203
- package/.agents/scripts/lib/observability/terse-result.js +14 -47
- package/.agents/scripts/lib/onboard/init-tail.js +13 -74
- package/.agents/scripts/lib/onboard/scaffold-docs.js +11 -34
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +25 -139
- package/.agents/scripts/lib/orchestration/auto-merge-cwd.js +11 -66
- package/.agents/scripts/lib/orchestration/behind-recovery.js +10 -55
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +5 -75
- package/.agents/scripts/lib/orchestration/change-set.js +7 -36
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +9 -46
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +11 -44
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +5 -24
- package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +3 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +5 -38
- package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +3 -8
- package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +28 -136
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +3 -13
- package/.agents/scripts/lib/orchestration/check-state.js +92 -0
- package/.agents/scripts/lib/orchestration/ci-gap-intake.js +37 -144
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +42 -189
- package/.agents/scripts/lib/orchestration/code-review.js +24 -128
- package/.agents/scripts/lib/orchestration/column-sync.js +23 -111
- package/.agents/scripts/lib/orchestration/complexity-gate.js +42 -214
- package/.agents/scripts/lib/orchestration/deliver-recover.js +36 -168
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +4 -35
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +9 -41
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +25 -115
- package/.agents/scripts/lib/orchestration/doc-reader.js +2 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +13 -51
- package/.agents/scripts/lib/orchestration/epic-candidates.js +13 -53
- package/.agents/scripts/lib/orchestration/epic-checklist.js +9 -33
- package/.agents/scripts/lib/orchestration/epic-container.js +41 -167
- package/.agents/scripts/lib/orchestration/epic-expansion.js +10 -40
- package/.agents/scripts/lib/orchestration/epic-rollup.js +55 -207
- package/.agents/scripts/lib/orchestration/file-assumption-enum.js +2 -22
- package/.agents/scripts/lib/orchestration/file-assumptions.js +45 -253
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-detect.js +9 -46
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +7 -57
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +21 -126
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +2 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +9 -34
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +41 -190
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/merged-tip.js +9 -45
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +19 -85
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +3 -17
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +16 -100
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +1 -4
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +16 -67
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +9 -33
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +8 -29
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +15 -68
- package/.agents/scripts/lib/orchestration/light-backstop.js +11 -49
- package/.agents/scripts/lib/orchestration/light-escalation.js +21 -89
- package/.agents/scripts/lib/orchestration/light-suitability.js +26 -231
- package/.agents/scripts/lib/orchestration/merge-block-class.js +39 -216
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -377
- package/.agents/scripts/lib/orchestration/pinned-identifier-lint.js +17 -57
- package/.agents/scripts/lib/orchestration/plan-context.js +52 -303
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +22 -79
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +5 -31
- package/.agents/scripts/lib/orchestration/plan-metrics.js +29 -108
- package/.agents/scripts/lib/orchestration/plan-navigation.js +8 -27
- package/.agents/scripts/lib/orchestration/plan-persist/acceptance-handle-repair.js +12 -49
- package/.agents/scripts/lib/orchestration/plan-persist/audit-provenance.js +18 -73
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +14 -78
- package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +6 -30
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +14 -65
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +21 -76
- package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +6 -43
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +14 -68
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +9 -41
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +49 -248
- package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +2 -12
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +85 -368
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +8 -38
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +30 -190
- package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +9 -49
- package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +7 -28
- package/.agents/scripts/lib/orchestration/plan-reachability.js +13 -42
- package/.agents/scripts/lib/orchestration/plan-run-labels/reap.js +16 -91
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +16 -54
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +10 -52
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +14 -109
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +11 -83
- package/.agents/scripts/lib/orchestration/pr-watch.js +48 -306
- package/.agents/scripts/lib/orchestration/project-meta-cache.js +15 -80
- package/.agents/scripts/lib/orchestration/project-meta-resolver.js +10 -51
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +12 -76
- package/.agents/scripts/lib/orchestration/remote-verifier.js +12 -36
- package/.agents/scripts/lib/orchestration/resolve-stories.js +33 -164
- package/.agents/scripts/lib/orchestration/retro-proposals.js +66 -361
- package/.agents/scripts/lib/orchestration/review-base-ref.js +9 -43
- package/.agents/scripts/lib/orchestration/review-depth.js +12 -94
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +10 -111
- package/.agents/scripts/lib/orchestration/review-providers/degraded-gates.js +13 -71
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +7 -51
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +8 -53
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -214
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +7 -52
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +4 -33
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +11 -71
- package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +19 -131
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +6 -89
- package/.agents/scripts/lib/orchestration/review-providers/types.js +26 -56
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +3 -46
- package/.agents/scripts/lib/orchestration/run-epilogue.js +40 -199
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +13 -81
- package/.agents/scripts/lib/orchestration/single-story-close/close-note.js +7 -34
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +16 -89
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +18 -109
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +83 -239
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +18 -80
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +103 -97
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -64
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +136 -486
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +30 -134
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +9 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/lock-wait-pending.js +49 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +13 -86
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +20 -95
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +46 -203
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pre-gate-steps.js +8 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +12 -83
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -39
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-outcome.js +4 -28
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +6 -51
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +6 -34
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +23 -121
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +110 -290
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +15 -69
- package/.agents/scripts/lib/orchestration/story-body-gate.js +4 -23
- package/.agents/scripts/lib/orchestration/story-close/baseline-upward-writeback.js +50 -179
- package/.agents/scripts/lib/orchestration/story-close/context-budget-writeback.js +11 -41
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +23 -311
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +22 -147
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +16 -67
- package/.agents/scripts/lib/orchestration/story-deliver-terminal-schema.js +12 -68
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +42 -201
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +43 -245
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +4 -23
- package/.agents/scripts/lib/orchestration/story-init-remote.js +2 -6
- package/.agents/scripts/lib/orchestration/story-reachability.js +3 -23
- package/.agents/scripts/lib/orchestration/task-body-validator.js +12 -126
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -131
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +15 -149
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +5 -33
- package/.agents/scripts/lib/orchestration/ticket-validator.js +39 -181
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +51 -244
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +39 -250
- package/.agents/scripts/lib/orchestration/ticketing/state.js +14 -68
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +46 -263
- package/.agents/scripts/lib/orchestration/ticketing.js +2 -26
- package/.agents/scripts/lib/orchestration/verify-credit.js +18 -79
- package/.agents/scripts/lib/orchestration/worktree-dirty.js +5 -30
- package/.agents/scripts/lib/path-security.js +3 -6
- package/.agents/scripts/lib/plan-phase-cleanup.js +9 -49
- package/.agents/scripts/lib/preflight-runner.js +13 -69
- package/.agents/scripts/lib/process-group.js +143 -0
- package/.agents/scripts/lib/project-root.js +2 -8
- package/.agents/scripts/lib/provider-factory.js +2 -25
- package/.agents/scripts/lib/qa/console-allowlist.js +10 -59
- package/.agents/scripts/lib/qa/qa-session.js +15 -69
- package/.agents/scripts/lib/qa/redact-evidence.js +18 -129
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +26 -135
- package/.agents/scripts/lib/qa/resolve-selection.js +16 -84
- package/.agents/scripts/lib/reserved-test-ids.js +9 -47
- package/.agents/scripts/lib/runtime-deps/dep-resolution.js +13 -53
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +10 -44
- package/.agents/scripts/lib/runtime-deps/manifest.js +10 -30
- package/.agents/scripts/lib/runtime-deps/parser-major.js +15 -51
- package/.agents/scripts/lib/runtime-deps/preflight.js +4 -22
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +11 -55
- package/.agents/scripts/lib/signals/detectors/common.js +12 -38
- package/.agents/scripts/lib/signals/index.js +2 -19
- package/.agents/scripts/lib/signals/schema.js +14 -109
- package/.agents/scripts/lib/signals/write.js +2 -11
- package/.agents/scripts/lib/single-story/confirm-merge.js +31 -72
- package/.agents/scripts/lib/single-story/story-merged-notify.js +8 -49
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +4 -26
- package/.agents/scripts/lib/single-story-sweep/protection.js +13 -100
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +60 -258
- package/.agents/scripts/lib/single-story-sweep.js +14 -97
- package/.agents/scripts/lib/skills/parse-skill.js +13 -59
- package/.agents/scripts/lib/skills/skills-index.js +8 -29
- package/.agents/scripts/lib/skills/walk-skill-files.js +17 -78
- package/.agents/scripts/lib/source-extensions.js +11 -42
- package/.agents/scripts/lib/source-text/strip-js-comments.js +8 -41
- package/.agents/scripts/lib/stdio-flush.js +9 -36
- package/.agents/scripts/lib/story-adjacency.js +8 -40
- package/.agents/scripts/lib/story-body/body-format-lints.js +22 -83
- package/.agents/scripts/lib/story-body/footer-block.js +11 -44
- package/.agents/scripts/lib/story-body/story-body.js +83 -358
- package/.agents/scripts/lib/temp-retention.js +42 -143
- package/.agents/scripts/lib/templates/decomposer-prompts.js +11 -65
- package/.agents/scripts/lib/test-env.js +12 -65
- package/.agents/scripts/lib/test-run-credit.js +10 -65
- package/.agents/scripts/lib/test-runner-contract.js +19 -74
- package/.agents/scripts/lib/test-temp.js +38 -184
- package/.agents/scripts/lib/test-tiers.js +12 -96
- package/.agents/scripts/lib/ticket-body-sections.js +21 -96
- package/.agents/scripts/lib/transpile.js +15 -74
- package/.agents/scripts/lib/util/concurrent-map.js +6 -25
- package/.agents/scripts/lib/util/parse-id-list.js +8 -34
- package/.agents/scripts/lib/util/poll-loop.js +8 -28
- package/.agents/scripts/lib/util/with-timeout.js +2 -11
- package/.agents/scripts/lib/validation-evidence.js +21 -96
- package/.agents/scripts/lib/wave-runner/footprint.js +17 -70
- package/.agents/scripts/lib/wave-runner/live-probe.js +53 -221
- package/.agents/scripts/lib/wave-runner/ready-set.js +72 -301
- package/.agents/scripts/lib/workers/crap-worker.js +11 -64
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +8 -45
- package/.agents/scripts/lib/workers/maintainability-worker.js +5 -21
- package/.agents/scripts/lib/workers/serve-worker-messages.js +2 -18
- package/.agents/scripts/lib/workflow-closure.js +22 -105
- package/.agents/scripts/lib/workspace-provisioner.js +16 -54
- package/.agents/scripts/lib/worktree/git-hooks.js +15 -60
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +20 -60
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +10 -62
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +22 -86
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +24 -126
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +2 -20
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +46 -180
- package/.agents/scripts/lib/worktree-manager.js +15 -40
- package/.agents/scripts/lint-issue-body.js +12 -68
- package/.agents/scripts/mandrel-update-preflight.js +10 -70
- package/.agents/scripts/merge-baseline.js +30 -104
- package/.agents/scripts/nav-registry-diff.js +22 -108
- package/.agents/scripts/notify.js +12 -69
- package/.agents/scripts/plan-context.js +27 -111
- package/.agents/scripts/plan-critics.js +12 -66
- package/.agents/scripts/plan-persist.js +31 -148
- package/.agents/scripts/plan-run-epilogue.js +11 -37
- package/.agents/scripts/pr-watch-with-update.js +76 -267
- package/.agents/scripts/providers/github/auth.js +3 -8
- package/.agents/scripts/providers/github/blocked-by-add.js +14 -61
- package/.agents/scripts/providers/github/board-add.js +5 -21
- package/.agents/scripts/providers/github/branch-protection.js +11 -43
- package/.agents/scripts/providers/github/cache.js +2 -14
- package/.agents/scripts/providers/github/comments.js +7 -40
- package/.agents/scripts/providers/github/compose.js +3 -19
- package/.agents/scripts/providers/github/errors.js +22 -125
- package/.agents/scripts/providers/github/issues.js +31 -123
- package/.agents/scripts/providers/github/labels.js +24 -124
- package/.agents/scripts/providers/github/mappers.js +5 -27
- package/.agents/scripts/providers/github/merge-methods.js +3 -22
- package/.agents/scripts/providers/github/project-board.js +2 -17
- package/.agents/scripts/providers/github/projects-v2-graphql.js +3 -6
- package/.agents/scripts/providers/github/request-helpers.js +5 -32
- package/.agents/scripts/providers/github/search-budget.js +9 -39
- package/.agents/scripts/providers/github/search-query.js +5 -26
- package/.agents/scripts/providers/github/sub-issue-add.js +15 -65
- package/.agents/scripts/providers/github/sub-issues.js +7 -36
- package/.agents/scripts/providers/github/tickets.js +32 -134
- package/.agents/scripts/providers/github.js +18 -59
- package/.agents/scripts/prune-plan-run-labels.js +12 -46
- package/.agents/scripts/quality-preview.js +35 -220
- package/.agents/scripts/resolve-doc-tiers.js +3 -26
- package/.agents/scripts/resolve-stories.js +16 -67
- package/.agents/scripts/resync-status-column.js +6 -25
- package/.agents/scripts/run-tests.js +29 -104
- package/.agents/scripts/single-story-close.js +23 -135
- package/.agents/scripts/single-story-confirm-merge.js +32 -139
- package/.agents/scripts/single-story-init.js +47 -209
- package/.agents/scripts/stories-wave-tick.js +102 -472
- package/.agents/scripts/sync-agentrc.js +3 -21
- package/.agents/scripts/sync-claude-agents.js +9 -55
- package/.agents/scripts/sync-claude-commands.js +20 -110
- package/.agents/scripts/test-wrapper.js +6 -43
- package/.agents/scripts/update-coverage-baseline.js +5 -22
- package/.agents/scripts/update-crap-baseline.js +7 -30
- package/.agents/scripts/update-duplication-baseline.js +16 -92
- package/.agents/scripts/update-maintainability-baseline.js +8 -62
- package/.agents/scripts/update-ticket-state.js +1 -7
- package/.agents/scripts/validate-skills.js +6 -26
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/templates/docs/audit-sweep-runbook.md +3 -4
- package/.agents/workflows/audit-accessibility.md +4 -7
- package/.agents/workflows/audit-adrs.md +3 -6
- package/.agents/workflows/audit-architecture.md +3 -11
- package/.agents/workflows/audit-baselines.md +6 -9
- package/.agents/workflows/audit-clean-code.md +8 -12
- package/.agents/workflows/audit-data-model.md +3 -7
- package/.agents/workflows/audit-dependencies.md +4 -7
- package/.agents/workflows/audit-devops.md +4 -8
- package/.agents/workflows/audit-documentation.md +1 -4
- package/.agents/workflows/audit-mobile.md +4 -7
- package/.agents/workflows/audit-navigability.md +3 -6
- package/.agents/workflows/audit-performance.md +2 -4
- package/.agents/workflows/audit-privacy.md +4 -7
- package/.agents/workflows/audit-quality.md +4 -7
- package/.agents/workflows/audit-security.md +4 -7
- package/.agents/workflows/audit-seo.md +4 -7
- package/.agents/workflows/audit-sre.md +4 -7
- package/.agents/workflows/audit-to-stories.md +17 -30
- package/.agents/workflows/audit-ux-ui.md +4 -7
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-quality-guardrails.md +12 -15
- package/.agents/workflows/helpers/deliver-digest.md +6 -4
- package/.agents/workflows/helpers/deliver-reference.md +114 -188
- package/.agents/workflows/helpers/deliver-story-reference.md +189 -533
- package/.agents/workflows/helpers/plan-reference.md +86 -139
- package/.agents/workflows/helpers/qa-core.md +12 -0
- package/.agents/workflows/memory-consolidate.md +1 -1
- package/.agents/workflows/qa-assist.md +27 -71
- package/.agents/workflows/qa-explore.md +19 -59
- package/.agents/workflows/qa-run.md +11 -33
- package/README.md +1 -1
- package/bin/mandrel.js +5 -46
- package/bin/postinstall.js +18 -107
- package/docs/CHANGELOG.md +25 -0
- package/lib/cli/doctor.js +11 -71
- package/lib/cli/init.js +26 -165
- package/lib/cli/migrate.js +5 -64
- package/lib/cli/registry.js +84 -467
- package/lib/cli/sync-agents.js +4 -64
- package/lib/cli/sync-commands.js +11 -64
- package/lib/cli/sync.js +34 -213
- package/lib/cli/uninstall.js +40 -219
- package/lib/cli/update.js +105 -661
- package/lib/cli/version-check.js +8 -72
- package/lib/cli/version-helpers.js +14 -87
- package/lib/migrations/helpers/retire-agentrc-key.js +11 -52
- package/lib/migrations/index.js +15 -92
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +2 -15
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +1 -13
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +2 -15
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +9 -38
- package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +1 -13
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +2 -27
- package/lib/migrations/steps/2.57.0-retire-delivery-limit-knobs.js +2 -23
- package/lib/migrations/steps/2.57.0-retire-planning-limit-knobs.js +2 -27
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +2 -21
- package/lib/migrations/steps/strip-removed-agentrc-keys.js +333 -0
- package/package.json +16 -14
- package/.agents/docs/SDLC.md +0 -590
- package/.agents/docs/quality-gates.md +0 -1183
- package/.agents/rules/known-tooling-behavior.md +0 -200
- package/.agents/rules/orchestration-error-handling.md +0 -61
- package/.agents/rules/test-seams.md +0 -59
- package/.agents/schemas/baselines/lighthouse.schema.json +0 -59
- package/.agents/schemas/baselines/lint.schema.json +0 -47
- package/.agents/scripts/check-action-pinning.js +0 -260
- package/.agents/scripts/check-audit-attribution.js +0 -302
- package/.agents/scripts/check-baseline-drift.js +0 -211
- package/.agents/scripts/check-baseline-scope.js +0 -362
- package/.agents/scripts/check-generated-validator.js +0 -202
- package/.agents/scripts/check-knip-entries.js +0 -159
- package/.agents/scripts/check-lifecycle-lint.js +0 -294
- package/.agents/scripts/check-pinned-override-notes.js +0 -102
- package/.agents/scripts/check-schema-references.js +0 -368
- package/.agents/scripts/check-test-portability.js +0 -512
- package/.agents/scripts/check-workflow-citations.js +0 -218
- package/.agents/scripts/check-workflow-cli-lint.js +0 -299
- package/.agents/scripts/check-workflow-timeouts.js +0 -291
- package/.agents/scripts/install-matrix-assert.js +0 -326
- package/.agents/scripts/lib/audit-advisories.js +0 -195
- package/.agents/scripts/lib/audit-attribution.js +0 -134
- package/.agents/scripts/lib/baselines/drift-detector.js +0 -351
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +0 -87
- package/.agents/scripts/lib/baselines/kinds/lint.js +0 -184
- package/.agents/scripts/lib/baselines/orphan-pruner.js +0 -233
- package/.agents/scripts/lib/baselines/scope-assert.js +0 -223
- package/.agents/scripts/lib/baselines/scope-inventory.js +0 -314
- package/.agents/scripts/lib/c8-cli-path.js +0 -21
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +0 -51
- package/.agents/scripts/lib/config/gates/lint.schema.js +0 -18
- package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +0 -70
- package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +0 -284
- package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +0 -80
- package/.agents/scripts/lib/dynamic-workflow/degraded-coverage.js +0 -81
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +0 -87
- package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +0 -74
- package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +0 -90
- package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +0 -43
- package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +0 -83
- package/.agents/scripts/lib/fs-walk.js +0 -52
- package/.agents/scripts/lib/knip-config-resolver.js +0 -181
- package/.agents/scripts/lib/knip-entry-sync.js +0 -452
- package/.agents/scripts/lib/pinned-override-notes.js +0 -88
- package/.agents/scripts/lib/pinned-override-resolve.js +0 -212
- package/.agents/scripts/lib/test-isolate/cli-options.js +0 -93
- package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +0 -52
- package/.agents/scripts/lib/test-isolate/list-files.js +0 -90
- package/.agents/scripts/lib/test-isolate/parse-tap.js +0 -75
- package/.agents/scripts/lib/test-isolate/progress-log.js +0 -45
- package/.agents/scripts/lib/test-isolate/render-report.js +0 -97
- package/.agents/scripts/lib/test-isolate/run-isolate.js +0 -87
- package/.agents/scripts/lib/test-isolate/runner.js +0 -483
- package/.agents/scripts/lib/test-profile/parse-tap.js +0 -136
- package/.agents/scripts/lib/test-profile/render-report.js +0 -45
- package/.agents/scripts/lint-label-vocabulary.js +0 -214
- package/.agents/scripts/post-structured-comment.js +0 -127
- package/.agents/scripts/provision-git-hooks.js +0 -85
- package/.agents/scripts/prune-baseline-orphans.js +0 -181
- package/.agents/scripts/run-coverage.js +0 -197
- package/.agents/scripts/run-lint.js +0 -133
- package/.agents/scripts/run-test-profile.js +0 -129
- package/.agents/scripts/run-verify.js +0 -125
- package/.agents/scripts/test-isolate.js +0 -55
- package/.agents/scripts/update-dead-exports-baseline.js +0 -321
|
@@ -1,41 +1,9 @@
|
|
|
1
1
|
// .agents/scripts/lib/story-body/story-body.js
|
|
2
2
|
/**
|
|
3
|
-
* Canonical Story-body parser/serializer
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* through these exports — do not inline ad-hoc parsing elsewhere.
|
|
8
|
-
*
|
|
9
|
-
* ## Structured Story body shape
|
|
10
|
-
*
|
|
11
|
-
* ```js
|
|
12
|
-
* {
|
|
13
|
-
* goal: string, // one-sentence purpose
|
|
14
|
-
* slicing: string, // v2 intra-Story delivery slice plan (optional; '' when absent)
|
|
15
|
-
* spec: string, // folded Tech Spec text block (optional; '' when absent)
|
|
16
|
-
* changes: PathEntry[], // files/globs this Story touches
|
|
17
|
-
* acceptance: string[], // observable criteria
|
|
18
|
-
* verify: string[], // exact commands / tier annotation
|
|
19
|
-
* references: PathEntry[], // read-only paths (optional)
|
|
20
|
-
* non_goals: string[], // negative-scope bullets (optional, advisory)
|
|
21
|
-
* depends_on: string[], // blocker story slugs or #ids
|
|
22
|
-
* }
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* Where `PathEntry` is:
|
|
26
|
-
* - `{ path: string, assumption: "creates"|"refactors-existing"|"exists"|"deletes" }`
|
|
27
|
-
* (canonical form — string bullets are rejected at parse time)
|
|
28
|
-
*
|
|
29
|
-
* ## Round-trip contract
|
|
30
|
-
*
|
|
31
|
-
* `serialize(parse(markdown)) === markdown` when the input is already
|
|
32
|
-
* in the canonical serialized form. Non-canonical whitespace or
|
|
33
|
-
* section ordering may produce a normalized (but equivalent) output.
|
|
34
|
-
*
|
|
35
|
-
* The parser MUST fail closed: a body that cannot be mapped to the
|
|
36
|
-
* canonical shape throws `StoryBodyParseError` — it does NOT silently
|
|
37
|
-
* coerce malformed input. This prevents a corrupt body from supplying
|
|
38
|
-
* wrong `depends_on` edges that reorder the wave DAG.
|
|
3
|
+
* Canonical Story-body parser/serializer — the single source of truth for
|
|
4
|
+
* the Story body shape. The parser fails closed: a body that cannot be mapped
|
|
5
|
+
* to the canonical shape throws, so a corrupt body cannot supply wrong
|
|
6
|
+
* `depends_on` edges. `serialize(parse(md)) === md` for canonical input.
|
|
39
7
|
*
|
|
40
8
|
* @module story-body
|
|
41
9
|
*/
|
|
@@ -48,10 +16,6 @@ import {
|
|
|
48
16
|
} from './body-format-lints.js';
|
|
49
17
|
import { isFooterSeparator, parseFooterBlockedByRefs } from './footer-block.js';
|
|
50
18
|
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// Public types (JSDoc only — no runtime schema file)
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
19
|
/**
|
|
56
20
|
* @typedef {'creates'|'refactors-existing'|'exists'|'deletes'} AssumptionEnum
|
|
57
21
|
*/
|
|
@@ -66,52 +30,45 @@ import { isFooterSeparator, parseFooterBlockedByRefs } from './footer-block.js';
|
|
|
66
30
|
|
|
67
31
|
/**
|
|
68
32
|
* @typedef {object} StoryBody
|
|
69
|
-
* @property {string} goal
|
|
70
|
-
* @property {string} slicing -
|
|
71
|
-
* @property {string} spec -
|
|
72
|
-
* @property {PathEntry[]} changes
|
|
73
|
-
* @property {string[]} acceptance
|
|
74
|
-
* @property {string[]} verify
|
|
75
|
-
* @property {PathEntry[]} references - Read-only paths
|
|
76
|
-
* @property {string[]} non_goals -
|
|
33
|
+
* @property {string} goal
|
|
34
|
+
* @property {string} slicing - Intra-Story slice plan; '' when absent.
|
|
35
|
+
* @property {string} spec - Folded Tech Spec; '' when absent.
|
|
36
|
+
* @property {PathEntry[]} changes
|
|
37
|
+
* @property {string[]} acceptance
|
|
38
|
+
* @property {string[]} verify
|
|
39
|
+
* @property {PathEntry[]} references - Read-only paths.
|
|
40
|
+
* @property {string[]} non_goals - Advisory negative scope.
|
|
77
41
|
* @property {string[]} depends_on - Blocking story slugs / issue refs.
|
|
78
42
|
*/
|
|
79
43
|
|
|
80
44
|
/**
|
|
81
45
|
* @typedef {object} ParseResult
|
|
82
|
-
* @property {StoryBody} body
|
|
83
|
-
* @property {string[]} warnings
|
|
84
|
-
* @property {ParseInfo} info
|
|
46
|
+
* @property {StoryBody} body
|
|
47
|
+
* @property {string[]} warnings
|
|
48
|
+
* @property {ParseInfo} info
|
|
85
49
|
*/
|
|
86
50
|
|
|
87
51
|
/**
|
|
88
52
|
* @typedef {object} ParseInfo
|
|
89
|
-
* @property {boolean} hasGoalSection
|
|
90
|
-
* @property {boolean} hasChangesSection
|
|
91
|
-
* @property {boolean} hasAcceptanceSection
|
|
92
|
-
* @property {boolean} hasVerifySection
|
|
93
|
-
* @property {boolean} hasReferencesSection
|
|
94
|
-
* @property {boolean} hasNonGoalsSection
|
|
95
|
-
* @property {boolean} hasSlicingSection
|
|
96
|
-
* @property {boolean} hasSpecSection
|
|
53
|
+
* @property {boolean} hasGoalSection
|
|
54
|
+
* @property {boolean} hasChangesSection
|
|
55
|
+
* @property {boolean} hasAcceptanceSection
|
|
56
|
+
* @property {boolean} hasVerifySection
|
|
57
|
+
* @property {boolean} hasReferencesSection
|
|
58
|
+
* @property {boolean} hasNonGoalsSection
|
|
59
|
+
* @property {boolean} hasSlicingSection
|
|
60
|
+
* @property {boolean} hasSpecSection
|
|
97
61
|
* @property {boolean} isUnstructuredBody - True when no structured sections were found.
|
|
98
62
|
*/
|
|
99
63
|
|
|
100
64
|
/**
|
|
101
65
|
* @typedef {object} SerializeOptions
|
|
102
66
|
* @property {boolean} [includeFooter=false] - Include `---\nparent/blocked-by` footer.
|
|
103
|
-
* @property {object} [footer]
|
|
104
|
-
* @property {number} [footer.parent]
|
|
67
|
+
* @property {object} [footer]
|
|
68
|
+
* @property {number} [footer.parent]
|
|
105
69
|
*/
|
|
106
70
|
|
|
107
|
-
|
|
108
|
-
// Error class
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Thrown when the Story body cannot be parsed into the canonical shape.
|
|
113
|
-
* The parser fails closed — do not catch this to silently continue.
|
|
114
|
-
*/
|
|
71
|
+
/** Thrown when a Story body cannot be parsed; never catch to continue. */
|
|
115
72
|
export class StoryBodyParseError extends Error {
|
|
116
73
|
/**
|
|
117
74
|
* @param {string} message
|
|
@@ -125,13 +82,7 @@ export class StoryBodyParseError extends Error {
|
|
|
125
82
|
}
|
|
126
83
|
}
|
|
127
84
|
|
|
128
|
-
//
|
|
129
|
-
// Section heading map
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
|
|
132
|
-
// Heading text → body field name. Keys are normalized: lower-cased with `-`
|
|
133
|
-
// folded to `_` (see splitSections), so the hyphenated `## Non-Goals` heading
|
|
134
|
-
// maps to the `non_goals` field.
|
|
85
|
+
// Keys are lower-cased with `-` folded to `_` (see splitSections).
|
|
135
86
|
const HEADING_TO_FIELD = new Map([
|
|
136
87
|
['goal', 'goal'],
|
|
137
88
|
['slicing', 'slicing'],
|
|
@@ -144,14 +95,7 @@ const HEADING_TO_FIELD = new Map([
|
|
|
144
95
|
]);
|
|
145
96
|
const TEXT_BLOCK_FIELDS = new Set(['slicing', 'spec']);
|
|
146
97
|
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Helpers
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
|
|
151
98
|
/**
|
|
152
|
-
* Strip leading `- ` or `- [ ] ` from a markdown list item, returning the
|
|
153
|
-
* raw content.
|
|
154
|
-
*
|
|
155
99
|
* @param {string} line
|
|
156
100
|
* @returns {string}
|
|
157
101
|
*/
|
|
@@ -159,66 +103,30 @@ function stripListMarker(line) {
|
|
|
159
103
|
return line.replace(/^-\s+(?:\[\s*[xX ]?\s*\]\s+)?/, '').trim();
|
|
160
104
|
}
|
|
161
105
|
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
// inline-JSON object bullet remains accepted at parse time indefinitely (live
|
|
165
|
-
// issue bodies are never rewritten).
|
|
106
|
+
// `path` — assumption: the shape serialize() emits. The inline-JSON bullet is
|
|
107
|
+
// still accepted at parse time because live issue bodies are never rewritten.
|
|
166
108
|
const HUMANIZED_PATH_ENTRY_RE = /^`([^`]+)`\s+—\s+(\S+)$/;
|
|
167
109
|
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
// author knows better than a probe does, so the default authored form omits
|
|
171
|
-
// it and persist derives it. The grammar itself — a single whitespace-free
|
|
172
|
-
// token, so prose bullets do not match and are still rejected — is
|
|
173
|
-
// `body-format-lints.js#matchBarePathToken`, the one definition the persist
|
|
174
|
-
// repair pass scores against too (Story #5361).
|
|
175
|
-
|
|
176
|
-
// AC-<n> presentation prefix on acceptance checkboxes (Story #4600). The
|
|
177
|
-
// numbering is a stable 1-based human handle only — parse() strips it so the
|
|
178
|
-
// top-level acceptance[] machine contract round-trips byte-identical.
|
|
179
|
-
//
|
|
180
|
-
// The lettered form (`AC-14a:`) is accepted too (Story #5323). Nothing emits
|
|
181
|
-
// one — `serialize()` numbers from the array index — but a Story planned from
|
|
182
|
-
// an existing ticket can copy one out of the source issue's rendered
|
|
183
|
-
// checkboxes, and a body that already carries one must still parse to the
|
|
184
|
-
// handle-free text or the round-trip invariant breaks for it alone. Trailing
|
|
185
|
-
// whitespace is optional so `AC-3:text` normalises as readily as `AC-3: text`.
|
|
110
|
+
// Presentation-only `AC-<n>:` handle (lettered `AC-14a:` too, copied from
|
|
111
|
+
// source tickets); parse() strips it so acceptance[] round-trips.
|
|
186
112
|
const AC_PREFIX_RE = /^AC-\d+[a-z]?:\s*/i;
|
|
187
113
|
|
|
188
|
-
//
|
|
189
|
-
// carry
|
|
190
|
-
//
|
|
191
|
-
// `<!-- meta: {...} -->` block. Nothing writes them any more — the `wide` /
|
|
192
|
-
// `reason_to_exist` fields and the provenance stamp went with the plan-time
|
|
193
|
-
// sizing model — but live issue bodies are never rewritten, so the parser
|
|
194
|
-
// still skips them wherever they appear rather than absorbing a stray line
|
|
195
|
-
// into the last structured section. A skipped block is dropped on
|
|
196
|
-
// re-serialize, which is the cutover working as intended.
|
|
114
|
+
// Retired machine-managed marker lines nothing writes any more. Live bodies
|
|
115
|
+
// still carry them, so the parser skips them rather than absorbing them into
|
|
116
|
+
// the last section; they are dropped on re-serialize.
|
|
197
117
|
const WIDE_MARKER_LINE_RE = /^>\s*\*\*Wide:\*\*/;
|
|
198
118
|
const AUTHORED_MARKER_LINE_RE = /^\s*>\s*🏷️\s+Authored with Mandrel\b/;
|
|
199
119
|
const META_BLOCK_RE = /<!--\s*meta:[\s\S]*?-->/;
|
|
200
120
|
|
|
201
121
|
/**
|
|
202
|
-
* Parse
|
|
203
|
-
*
|
|
204
|
-
* Accepted markdown shapes (all parsed indefinitely — live issue bodies
|
|
205
|
-
* are never rewritten):
|
|
206
|
-
* - Bare path (the default authored form since Story #5342):
|
|
207
|
-
* `` `src/x.js` `` or `src/x.js`, parsed with `assumption: null`
|
|
208
|
-
* - Humanized bullet (canonical serialize() output since Story #4600):
|
|
209
|
-
* `` `src/x.js` — refactors-existing ``
|
|
210
|
-
* - Legacy inline-JSON object bullet:
|
|
211
|
-
* `- { "path": "...", "assumption": "..." }`
|
|
212
|
-
*
|
|
213
|
-
* A structured object entry (from a parsed JSON body that was never
|
|
214
|
-
* serialized to markdown) arrives as-is and is validated directly.
|
|
122
|
+
* Parse one `changes` / `references` bullet: bare path (`assumption: null`),
|
|
123
|
+
* humanized `` `path` — assumption ``, or inline-JSON object.
|
|
215
124
|
*
|
|
216
125
|
* @param {string|object} raw
|
|
217
126
|
* @param {string[]} warnings
|
|
218
127
|
* @returns {PathEntry}
|
|
219
128
|
*/
|
|
220
129
|
function parsePathEntry(raw, warnings) {
|
|
221
|
-
// Already a structured object (from a parsed JSON body, not markdown).
|
|
222
130
|
if (raw !== null && typeof raw === 'object') {
|
|
223
131
|
return pathEntryFromObject(raw);
|
|
224
132
|
}
|
|
@@ -232,17 +140,9 @@ function parsePathEntry(raw, warnings) {
|
|
|
232
140
|
}
|
|
233
141
|
|
|
234
142
|
/**
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* `assumption: null` records only what the author said; persist derives the
|
|
240
|
-
* rest by probing the base branch. A `{`-leading string reached here because
|
|
241
|
-
* it failed to parse as the inline JSON object it announced itself as, so it
|
|
242
|
-
* is malformed JSON rather than a path and keeps failing closed.
|
|
243
|
-
*
|
|
244
|
-
* Story #5361: the two failures need different fixes, so they get different
|
|
245
|
-
* refusals — rewrite a sentence as a path, versus fix a token that is not one.
|
|
143
|
+
* Last shape tried, so it owns the rejection. A `{`-leading string here is
|
|
144
|
+
* malformed JSON, not a path. Prose and non-path tokens get distinct refusals
|
|
145
|
+
* because they need different fixes.
|
|
246
146
|
*
|
|
247
147
|
* @param {string} str
|
|
248
148
|
* @returns {PathEntry}
|
|
@@ -263,16 +163,8 @@ function pathEntryFromBare(str) {
|
|
|
263
163
|
}
|
|
264
164
|
|
|
265
165
|
/**
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* - a canonical `FILE_ASSUMPTION_VALUES` member — the author pinned one;
|
|
270
|
-
* - `null` — the author named no assumption at all. Since Story #5342 that
|
|
271
|
-
* is the **bare form**, and persist derives the value by probing the base
|
|
272
|
-
* branch rather than the author guessing it;
|
|
273
|
-
* - `undefined` — the author named something that is not an assumption.
|
|
274
|
-
* Distinct from absent on purpose: a typo must fail closed where an
|
|
275
|
-
* omission is the default shape.
|
|
166
|
+
* A canonical value (pinned), `null` (omitted — persist derives it), or
|
|
167
|
+
* `undefined` (not an assumption — a typo must fail closed).
|
|
276
168
|
*
|
|
277
169
|
* @param {unknown} raw
|
|
278
170
|
* @returns {string|null|undefined}
|
|
@@ -283,9 +175,6 @@ function readAssumption(raw) {
|
|
|
283
175
|
}
|
|
284
176
|
|
|
285
177
|
/**
|
|
286
|
-
* Validate an already-structured `{ path, assumption }` object. Fails closed
|
|
287
|
-
* on a malformed object.
|
|
288
|
-
*
|
|
289
178
|
* @param {object} raw
|
|
290
179
|
* @returns {PathEntry}
|
|
291
180
|
*/
|
|
@@ -295,7 +184,6 @@ function pathEntryFromObject(raw) {
|
|
|
295
184
|
if (path !== '' && assumption !== undefined) {
|
|
296
185
|
return { path, assumption };
|
|
297
186
|
}
|
|
298
|
-
// Malformed object: fail closed.
|
|
299
187
|
throw new StoryBodyParseError(
|
|
300
188
|
`changes/references entry is an object but not a valid PathEntry: ${JSON.stringify(raw)}`,
|
|
301
189
|
{ field: 'changes', raw: JSON.stringify(raw) },
|
|
@@ -303,10 +191,7 @@ function pathEntryFromObject(raw) {
|
|
|
303
191
|
}
|
|
304
192
|
|
|
305
193
|
/**
|
|
306
|
-
*
|
|
307
|
-
* Story #4600): `` `path` — assumption ``. Returns `null` when the line is
|
|
308
|
-
* not that shape at all; fails closed when the shape is recognized but the
|
|
309
|
-
* fields are invalid.
|
|
194
|
+
* `null` when not the humanized shape; throws when recognized but invalid.
|
|
310
195
|
*
|
|
311
196
|
* @param {string} str
|
|
312
197
|
* @returns {PathEntry|null}
|
|
@@ -318,7 +203,6 @@ function pathEntryFromHumanized(str) {
|
|
|
318
203
|
if (path.length > 0 && FILE_ASSUMPTION_VALUES.includes(humanized[2])) {
|
|
319
204
|
return { path, assumption: humanized[2] };
|
|
320
205
|
}
|
|
321
|
-
// Recognized the humanized shape but the fields are invalid: fail closed.
|
|
322
206
|
throw new StoryBodyParseError(
|
|
323
207
|
`changes/references entry is a humanized bullet but not a valid PathEntry: ${str.slice(0, 120)}${pathEntryFixIt(str)}`,
|
|
324
208
|
{ field: 'changes', raw: str },
|
|
@@ -326,12 +210,7 @@ function pathEntryFromHumanized(str) {
|
|
|
326
210
|
}
|
|
327
211
|
|
|
328
212
|
/**
|
|
329
|
-
*
|
|
330
|
-
* `{ "path": "...", "assumption": "..." }`. Returns `null` when the line is
|
|
331
|
-
* not a JSON object at all (including a JSON parse failure — the caller then
|
|
332
|
-
* tries the bare-path form and finally rejects the bullet); delegates the
|
|
333
|
-
* field check to {@link pathEntryFromObject}, which is the same judgment on
|
|
334
|
-
* the same shape and fails closed the same way.
|
|
213
|
+
* `null` when not a JSON object (the caller then tries the bare form).
|
|
335
214
|
*
|
|
336
215
|
* @param {string} str
|
|
337
216
|
* @returns {PathEntry|null}
|
|
@@ -342,7 +221,6 @@ function pathEntryFromInlineJson(str) {
|
|
|
342
221
|
try {
|
|
343
222
|
parsed = JSON.parse(str);
|
|
344
223
|
} catch {
|
|
345
|
-
// JSON parse failed — the caller falls through to the bare-path form.
|
|
346
224
|
return null;
|
|
347
225
|
}
|
|
348
226
|
return parsed !== null && typeof parsed === 'object'
|
|
@@ -351,10 +229,8 @@ function pathEntryFromInlineJson(str) {
|
|
|
351
229
|
}
|
|
352
230
|
|
|
353
231
|
/**
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
* an empty string when nothing is inferable, so callers can append it
|
|
357
|
-
* unconditionally (Story #4684 — mechanical auto-fix in the failure output).
|
|
232
|
+
* ` Suggested fix: …` suffix for a rejected bullet, or '' when nothing is
|
|
233
|
+
* inferable.
|
|
358
234
|
*
|
|
359
235
|
* @param {string} raw The rejected bullet text.
|
|
360
236
|
* @returns {string}
|
|
@@ -366,11 +242,7 @@ function pathEntryFixIt(raw) {
|
|
|
366
242
|
}
|
|
367
243
|
|
|
368
244
|
/**
|
|
369
|
-
*
|
|
370
|
-
* the last `---` separator). Returns an array of "#N" strings.
|
|
371
|
-
*
|
|
372
|
-
* Delegates to `./footer-block.js`, which owns the footer-block grammar
|
|
373
|
-
* (Story #5046) so the body parser and the dispatch-edge parser cannot
|
|
245
|
+
* Delegates to footer-block.js so the body and dispatch-edge parsers cannot
|
|
374
246
|
* disagree about what declares an edge.
|
|
375
247
|
*
|
|
376
248
|
* @param {string} footerBlock
|
|
@@ -381,15 +253,8 @@ function extractBlockedBy(footerBlock) {
|
|
|
381
253
|
}
|
|
382
254
|
|
|
383
255
|
/**
|
|
384
|
-
* Split markdown into named sections plus
|
|
385
|
-
*
|
|
386
|
-
* Returns `{ sections: Map<string, string[]>, footer: string }`.
|
|
387
|
-
* Each map value is the raw non-empty content lines under that heading
|
|
388
|
-
* (heading line stripped).
|
|
389
|
-
*
|
|
390
|
-
* A `---` followed by recognised footer keys (`parent:`, `Epic:`,
|
|
391
|
-
* `blocked by`) marks the start of the footer block. Content after the
|
|
392
|
-
* footer separator is NOT parsed as sections.
|
|
256
|
+
* Split markdown into named sections plus the footer block; content after
|
|
257
|
+
* the footer separator is not parsed as sections.
|
|
393
258
|
*
|
|
394
259
|
* @param {string} markdown
|
|
395
260
|
* @returns {{ sections: Map<string, string[]>, footer: string, preamble: string }}
|
|
@@ -410,20 +275,9 @@ function splitSections(markdown) {
|
|
|
410
275
|
break;
|
|
411
276
|
}
|
|
412
277
|
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
// parser accepts both levels. Any other heading depth is ignored.
|
|
417
|
-
//
|
|
418
|
-
// The token class is `[\w-]+` (not bare `\w+`) so a single hyphenated
|
|
419
|
-
// heading word — the canonical `## Non-Goals` negative-scope section —
|
|
420
|
-
// matches as one token. The captured name is normalized (lower-cased,
|
|
421
|
-
// `-` folded to `_`) before the HEADING_TO_FIELD lookup, so `Non-Goals`
|
|
422
|
-
// resolves to the `non_goals` field. Multi-word headings that contain a
|
|
423
|
-
// space (`## Out of Scope`, `## Agent Prompts`) still do NOT match this
|
|
424
|
-
// single-token shape — they fall through to the section-terminator branch
|
|
425
|
-
// below, which closes the open section. The chosen canonical spelling is
|
|
426
|
-
// therefore the hyphenated single token `## Non-Goals`.
|
|
278
|
+
// `##` or `###` (GitHub Issue Forms render labels as level 3). The token
|
|
279
|
+
// is a single `[\w-]+` word so `Non-Goals` matches; multi-word headings
|
|
280
|
+
// fall through to the terminator branch below.
|
|
427
281
|
const fieldHeadingMatch = line.match(/^#{2,3}\s+([\w-]+)\s*$/i);
|
|
428
282
|
const fieldName = fieldHeadingMatch?.[1]?.toLowerCase().replace(/-/g, '_');
|
|
429
283
|
if (HEADING_TO_FIELD.has(fieldName)) {
|
|
@@ -454,14 +308,9 @@ function splitSections(markdown) {
|
|
|
454
308
|
}
|
|
455
309
|
|
|
456
310
|
/**
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* / `## Sequencing` blocks, for instance — must not bleed into the last
|
|
461
|
-
* structured section's bullet list (Story #4270). Without this, those
|
|
462
|
-
* lines were silently absorbed into `verify[]` / `acceptance[]`. The
|
|
463
|
-
* heading and everything under it is dropped from structured parsing
|
|
464
|
-
* (it is extended, non-canonical markdown).
|
|
311
|
+
* A non-canonical heading closes the current section so appended extended
|
|
312
|
+
* content (e.g. `## Agent Prompts`) never bleeds into `verify[]` /
|
|
313
|
+
* `acceptance[]`. Text-block sections keep their own headings.
|
|
465
314
|
*
|
|
466
315
|
* @param {string} line
|
|
467
316
|
* @param {boolean} inPreamble
|
|
@@ -477,11 +326,6 @@ function isSectionTerminatorHeading(line, inPreamble, currentSection) {
|
|
|
477
326
|
}
|
|
478
327
|
|
|
479
328
|
/**
|
|
480
|
-
* True for the legacy machine-managed marker lines section parsing skips
|
|
481
|
-
* wherever they appear (see the regexes above): a `## References` section
|
|
482
|
-
* immediately followed by a retired meta block must not swallow the comment
|
|
483
|
-
* as a references entry.
|
|
484
|
-
*
|
|
485
329
|
* @param {string} line
|
|
486
330
|
* @returns {boolean}
|
|
487
331
|
*/
|
|
@@ -493,19 +337,13 @@ function isMachineMarkerLine(line) {
|
|
|
493
337
|
);
|
|
494
338
|
}
|
|
495
339
|
|
|
496
|
-
// ---------------------------------------------------------------------------
|
|
497
|
-
// Parser — per-section sub-parsers
|
|
498
|
-
// ---------------------------------------------------------------------------
|
|
499
|
-
|
|
500
340
|
/**
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* back to the preamble text (or the whole trimmed input), `depends_on` is
|
|
504
|
-
* still recovered from the footer, and all section arrays are empty.
|
|
341
|
+
* Minimal result for a body with no structured section: goal falls back to
|
|
342
|
+
* the preamble, `depends_on` is still read from the footer.
|
|
505
343
|
*
|
|
506
|
-
* @param {string} input
|
|
507
|
-
* @param {string} preamble
|
|
508
|
-
* @param {string} footer
|
|
344
|
+
* @param {string} input
|
|
345
|
+
* @param {string} preamble
|
|
346
|
+
* @param {string} footer
|
|
509
347
|
* @returns {ParseResult}
|
|
510
348
|
*/
|
|
511
349
|
function parseUnstructuredBody(input, preamble, footer) {
|
|
@@ -541,10 +379,7 @@ function parseUnstructuredBody(input, preamble, footer) {
|
|
|
541
379
|
}
|
|
542
380
|
|
|
543
381
|
/**
|
|
544
|
-
*
|
|
545
|
-
* single one-line goal string.
|
|
546
|
-
*
|
|
547
|
-
* @param {string[]} lines - Raw content lines under the heading.
|
|
382
|
+
* @param {string[]} lines
|
|
548
383
|
* @returns {string}
|
|
549
384
|
*/
|
|
550
385
|
function parseGoalSection(lines) {
|
|
@@ -555,10 +390,8 @@ function parseGoalSection(lines) {
|
|
|
555
390
|
}
|
|
556
391
|
|
|
557
392
|
/**
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
* preserved so a bullet list, compact table, or folded Tech Spec survives the
|
|
561
|
-
* round-trip; only blank lines and trailing whitespace are normalized.
|
|
393
|
+
* Line breaks are preserved so lists and tables round-trip; only blank edge
|
|
394
|
+
* lines and trailing whitespace are normalized.
|
|
562
395
|
*
|
|
563
396
|
* @param {string[]} lines
|
|
564
397
|
* @returns {string}
|
|
@@ -571,12 +404,8 @@ function parseTextBlockSection(lines) {
|
|
|
571
404
|
}
|
|
572
405
|
|
|
573
406
|
/**
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
* dropped, and each surviving entry is normalized via {@link parsePathEntry}.
|
|
577
|
-
*
|
|
578
|
-
* @param {string[]} lines - Raw content lines under the heading.
|
|
579
|
-
* @param {string[]} warnings - Mutable warnings sink.
|
|
407
|
+
* @param {string[]} lines
|
|
408
|
+
* @param {string[]} warnings
|
|
580
409
|
* @returns {PathEntry[]}
|
|
581
410
|
*/
|
|
582
411
|
function parsePathEntrySection(lines, warnings) {
|
|
@@ -591,46 +420,17 @@ function parsePathEntrySection(lines, warnings) {
|
|
|
591
420
|
}
|
|
592
421
|
|
|
593
422
|
/**
|
|
594
|
-
*
|
|
595
|
-
* list of trimmed strings, dropping blank entries.
|
|
596
|
-
*
|
|
597
|
-
* @param {string[]} lines - Raw content lines under the heading.
|
|
423
|
+
* @param {string[]} lines
|
|
598
424
|
* @returns {string[]}
|
|
599
425
|
*/
|
|
600
426
|
function parseTextListSection(lines) {
|
|
601
427
|
return lines.map((l) => stripListMarker(l)).filter(Boolean);
|
|
602
428
|
}
|
|
603
429
|
|
|
604
|
-
// ---------------------------------------------------------------------------
|
|
605
|
-
// Parser
|
|
606
|
-
// ---------------------------------------------------------------------------
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* Parse a GitHub Story issue body (markdown string) into a structured
|
|
610
|
-
* {@link StoryBody}. Fails closed on malformed input.
|
|
611
|
-
*
|
|
612
|
-
* Returns a {@link ParseResult} containing the body, any non-fatal
|
|
613
|
-
* warnings, and parse metadata. Use `result.body` directly; inspect
|
|
614
|
-
* `result.warnings` to detect legacy path entries that should be
|
|
615
|
-
* migrated.
|
|
616
|
-
*
|
|
617
|
-
* @param {string|object} input - Markdown string or already-structured body object.
|
|
618
|
-
* @returns {ParseResult}
|
|
619
|
-
* @throws {StoryBodyParseError} When the body is structurally unrecoverable.
|
|
620
|
-
*/
|
|
621
430
|
/**
|
|
622
|
-
* Strip
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
* its position in `acceptance[]`; an authored item that already carries one
|
|
626
|
-
* would render doubled (`- [ ] AC-1: AC-1: …`) and a lettered handle copied
|
|
627
|
-
* from a source ticket would survive into the machine contract. Both parse
|
|
628
|
-
* and the persist-side normalisation resolve the grammar here so the two can
|
|
629
|
-
* never disagree about what a handle is (Story #5323).
|
|
630
|
-
*
|
|
631
|
-
* Stacked handles are peeled in full — a body persisted while the doubling
|
|
632
|
-
* was live carries two, and leaving the inner one would normalise to
|
|
633
|
-
* something that still is not the authored text.
|
|
431
|
+
* Strip every stacked `AC-<n>:` handle. serialize() numbers checkboxes from
|
|
432
|
+
* position, so a kept handle would render doubled; parse and persist share
|
|
433
|
+
* this so they agree on the grammar.
|
|
634
434
|
*
|
|
635
435
|
* @param {string} item
|
|
636
436
|
* @returns {{ text: string, stripped: boolean }} The handle-free text, and
|
|
@@ -645,6 +445,13 @@ export function stripAcceptanceHandle(item) {
|
|
|
645
445
|
return { text, stripped: text !== original };
|
|
646
446
|
}
|
|
647
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Parse a Story issue body (markdown or structured object).
|
|
450
|
+
*
|
|
451
|
+
* @param {string|object} input - Markdown string or already-structured body object.
|
|
452
|
+
* @returns {ParseResult}
|
|
453
|
+
* @throws {StoryBodyParseError} When the body is structurally unrecoverable.
|
|
454
|
+
*/
|
|
648
455
|
export function parse(input) {
|
|
649
456
|
if (input === null || input === undefined) {
|
|
650
457
|
throw new StoryBodyParseError('Story body is null or undefined', {
|
|
@@ -652,8 +459,6 @@ export function parse(input) {
|
|
|
652
459
|
});
|
|
653
460
|
}
|
|
654
461
|
|
|
655
|
-
// If the caller already has a structured object (e.g. from the decomposer
|
|
656
|
-
// before it's serialized to markdown), parse it directly.
|
|
657
462
|
if (typeof input === 'object' && !Array.isArray(input)) {
|
|
658
463
|
return parseStructuredObject(input);
|
|
659
464
|
}
|
|
@@ -677,7 +482,6 @@ export function parse(input) {
|
|
|
677
482
|
const hasSlicingSection = sections.has('slicing');
|
|
678
483
|
const hasSpecSection = sections.has('spec');
|
|
679
484
|
|
|
680
|
-
// If no structured sections found, treat as unstructured body.
|
|
681
485
|
const isUnstructuredBody =
|
|
682
486
|
!hasGoalSection &&
|
|
683
487
|
!hasChangesSection &&
|
|
@@ -689,19 +493,12 @@ export function parse(input) {
|
|
|
689
493
|
}
|
|
690
494
|
|
|
691
495
|
const goal = parseGoalSection(sections.get('goal') ?? []);
|
|
692
|
-
// Optional v2 intra-Story delivery slice plan (`## Slicing`). Preserved as
|
|
693
|
-
// a verbatim text block — a large Story (what v1 called an Epic) folds its
|
|
694
|
-
// Delivery Slicing here instead of fanning out into sibling Stories; a
|
|
695
|
-
// trivial Story omits it entirely. Parsed as a text block so a bullet list
|
|
696
|
-
// or compact table round-trips.
|
|
697
496
|
const slicing = parseTextBlockSection(sections.get('slicing') ?? []);
|
|
698
497
|
const spec = parseTextBlockSection(sections.get('spec') ?? []);
|
|
699
498
|
const changes = parsePathEntrySection(
|
|
700
499
|
sections.get('changes') ?? [],
|
|
701
500
|
warnings,
|
|
702
501
|
);
|
|
703
|
-
// The AC-<n> checkbox prefix is presentation-only (Story #4600): strip it
|
|
704
|
-
// so acceptance[] round-trips byte-identical to the authored array.
|
|
705
502
|
const acceptance = parseTextListSection(sections.get('acceptance') ?? []).map(
|
|
706
503
|
(a) => stripAcceptanceHandle(a).text,
|
|
707
504
|
);
|
|
@@ -743,9 +540,7 @@ export function parse(input) {
|
|
|
743
540
|
}
|
|
744
541
|
|
|
745
542
|
/**
|
|
746
|
-
*
|
|
747
|
-
* output, before markdown serialization). Normalizes all fields to the
|
|
748
|
-
* canonical shape.
|
|
543
|
+
* Normalize a structured body object (pre-serialization decomposer output).
|
|
749
544
|
*
|
|
750
545
|
* @param {object} obj
|
|
751
546
|
* @returns {ParseResult}
|
|
@@ -753,10 +548,6 @@ export function parse(input) {
|
|
|
753
548
|
function parseStructuredObject(obj) {
|
|
754
549
|
const warnings = [];
|
|
755
550
|
|
|
756
|
-
// The declarative half of the normalization: every field whose value is a
|
|
757
|
-
// pure function of its raw input (plus the shared warnings sink) is one
|
|
758
|
-
// table row, walked in canonical body-key order. Adding a field of an
|
|
759
|
-
// existing kind is a one-row change.
|
|
760
551
|
const body = {};
|
|
761
552
|
for (const { name, kind } of STRUCTURED_FIELD_SPECS) {
|
|
762
553
|
body[name] = STRUCTURED_FIELD_NORMALIZERS[kind](obj[name], warnings);
|
|
@@ -780,36 +571,23 @@ function parseStructuredObject(obj) {
|
|
|
780
571
|
}
|
|
781
572
|
|
|
782
573
|
/**
|
|
783
|
-
*
|
|
784
|
-
* body-key order. `kind` selects the normalizer from
|
|
785
|
-
* {@link STRUCTURED_FIELD_NORMALIZERS}:
|
|
786
|
-
* - `text` — trimmed string, or `''` when absent/non-string.
|
|
787
|
-
* - `stringList` — array filtered to non-empty strings, else `[]`.
|
|
788
|
-
* - `pathEntryList` — array normalized entry-wise via `parsePathEntry`
|
|
789
|
-
* (fails closed on a malformed entry), else `[]`.
|
|
574
|
+
* Field specs in canonical body-key order.
|
|
790
575
|
*
|
|
791
576
|
* @type {Array<{ name: string, kind: keyof typeof STRUCTURED_FIELD_NORMALIZERS }>}
|
|
792
577
|
*/
|
|
793
578
|
const STRUCTURED_FIELD_SPECS = [
|
|
794
579
|
{ name: 'goal', kind: 'text' },
|
|
795
|
-
// slicing — optional v2 intra-Story delivery slice plan (verbatim text).
|
|
796
580
|
{ name: 'slicing', kind: 'text' },
|
|
797
|
-
// spec — optional folded Tech Spec (verbatim text).
|
|
798
581
|
{ name: 'spec', kind: 'text' },
|
|
799
582
|
{ name: 'changes', kind: 'pathEntryList' },
|
|
800
583
|
{ name: 'acceptance', kind: 'stringList' },
|
|
801
584
|
{ name: 'verify', kind: 'stringList' },
|
|
802
585
|
{ name: 'references', kind: 'pathEntryList' },
|
|
803
|
-
// non_goals — advisory negative-scope bullets.
|
|
804
586
|
{ name: 'non_goals', kind: 'stringList' },
|
|
805
|
-
// depends_on — may be at top level or in body.
|
|
806
587
|
{ name: 'depends_on', kind: 'stringList' },
|
|
807
588
|
];
|
|
808
589
|
|
|
809
590
|
/**
|
|
810
|
-
* One normalizer per {@link STRUCTURED_FIELD_SPECS} kind. Each takes the raw
|
|
811
|
-
* field value plus the shared warnings sink and returns the canonical value.
|
|
812
|
-
*
|
|
813
591
|
* @type {Record<string, (raw: unknown, warnings: string[]) => unknown>}
|
|
814
592
|
*/
|
|
815
593
|
const STRUCTURED_FIELD_NORMALIZERS = {
|
|
@@ -828,37 +606,19 @@ const STRUCTURED_FIELD_NORMALIZERS = {
|
|
|
828
606
|
},
|
|
829
607
|
};
|
|
830
608
|
|
|
831
|
-
// ---------------------------------------------------------------------------
|
|
832
|
-
// Serializer
|
|
833
|
-
// ---------------------------------------------------------------------------
|
|
834
|
-
|
|
835
609
|
/**
|
|
836
|
-
* Render a `PathEntry | string` as a markdown list item.
|
|
837
|
-
*
|
|
838
610
|
* @param {PathEntry | string} entry
|
|
839
611
|
* @returns {string}
|
|
840
612
|
*/
|
|
841
613
|
function serializePathEntry(entry) {
|
|
842
614
|
if (typeof entry === 'string') return entry;
|
|
843
|
-
//
|
|
844
|
-
// backticks, em-dash, assumption. parsePathEntry recognizes this shape (and
|
|
845
|
-
// the legacy inline-JSON one) for round-trip fidelity. Story #5342: a bare
|
|
846
|
-
// entry — a path the author wrote with no assumption — serializes back bare
|
|
847
|
-
// rather than silently acquiring a derivation they never made; persist
|
|
848
|
-
// fills it in by probing base before it writes a body.
|
|
615
|
+
// A bare entry (no assumption) stays bare; persist derives the assumption.
|
|
849
616
|
return [`\`${entry.path}\``, entry.assumption].filter(Boolean).join(' — ');
|
|
850
617
|
}
|
|
851
618
|
|
|
852
619
|
/**
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* `## Acceptance`, `## Verify`, `## References`, `## Non-Goals`). Each
|
|
856
|
-
* descriptor reads one body field and returns the section's markdown block
|
|
857
|
-
* when the field is present and non-empty, or `null` to omit the section.
|
|
858
|
-
*
|
|
859
|
-
* Standardising the section ladder as a single data table makes adding a new
|
|
860
|
-
* optional section a one-line edit here rather than a new control-flow branch
|
|
861
|
-
* in {@link serialize}.
|
|
620
|
+
* Sections in canonical emit order; `render` returns `null` to omit, so an
|
|
621
|
+
* absent optional field keeps older bodies round-tripping byte-identically.
|
|
862
622
|
*
|
|
863
623
|
* @type {Array<{ field: string, render: (value: unknown) => string | null }>}
|
|
864
624
|
*/
|
|
@@ -871,10 +631,6 @@ const SERIALIZE_SECTIONS = [
|
|
|
871
631
|
: null,
|
|
872
632
|
},
|
|
873
633
|
{
|
|
874
|
-
// Optional v2 intra-Story delivery slice plan. Single-token `## Slicing`
|
|
875
|
-
// heading (recognized by the `[\w-]+` field-heading regex). Verbatim text
|
|
876
|
-
// block. Render-when-non-empty: an absent/empty `slicing` emits nothing,
|
|
877
|
-
// so every pre-v2 body round-trips byte-identically.
|
|
878
634
|
field: 'slicing',
|
|
879
635
|
render: (slicing) =>
|
|
880
636
|
typeof slicing === 'string' && slicing.trim().length > 0
|
|
@@ -882,8 +638,6 @@ const SERIALIZE_SECTIONS = [
|
|
|
882
638
|
: null,
|
|
883
639
|
},
|
|
884
640
|
{
|
|
885
|
-
// Optional folded Tech Spec. Like `## Slicing`, this is a verbatim text
|
|
886
|
-
// block and emits nothing for absent/empty pre-v2 bodies.
|
|
887
641
|
field: 'spec',
|
|
888
642
|
render: (spec) =>
|
|
889
643
|
typeof spec === 'string' && spec.trim().length > 0
|
|
@@ -898,10 +652,6 @@ const SERIALIZE_SECTIONS = [
|
|
|
898
652
|
: null,
|
|
899
653
|
},
|
|
900
654
|
{
|
|
901
|
-
// Each checkbox carries a stable 1-based `AC-<n>:` handle (Story #4600)
|
|
902
|
-
// so humans and reviewers can reference criteria by number. The prefix
|
|
903
|
-
// is presentation-only — parse() strips it, and validators compare the
|
|
904
|
-
// top-level acceptance[] array, so numbering never affects gating.
|
|
905
655
|
field: 'acceptance',
|
|
906
656
|
render: (acceptance) =>
|
|
907
657
|
Array.isArray(acceptance) && acceptance.length > 0
|
|
@@ -923,11 +673,6 @@ const SERIALIZE_SECTIONS = [
|
|
|
923
673
|
: null,
|
|
924
674
|
},
|
|
925
675
|
{
|
|
926
|
-
// Advisory negative-scope bullets. Rendered as the hyphenated canonical
|
|
927
|
-
// `## Non-Goals` heading (the spelling the parser's widened
|
|
928
|
-
// `[\w-]+` field-heading regex recognizes). Render-when-non-empty: an
|
|
929
|
-
// empty or absent `non_goals` emits nothing, so every pre-existing body
|
|
930
|
-
// round-trips byte-identically.
|
|
931
676
|
field: 'non_goals',
|
|
932
677
|
render: (nonGoals) =>
|
|
933
678
|
Array.isArray(nonGoals) && nonGoals.length > 0
|
|
@@ -937,9 +682,6 @@ const SERIALIZE_SECTIONS = [
|
|
|
937
682
|
];
|
|
938
683
|
|
|
939
684
|
/**
|
|
940
|
-
* Build the optional `---` footer block (`parent` / `blocked by` lines).
|
|
941
|
-
* Returns the empty string when `opts.includeFooter` is falsy.
|
|
942
|
-
*
|
|
943
685
|
* @param {StoryBody} body
|
|
944
686
|
* @param {SerializeOptions} opts
|
|
945
687
|
* @returns {string}
|
|
@@ -948,9 +690,7 @@ function serializeFooter(body, opts) {
|
|
|
948
690
|
if (!opts.includeFooter) return '';
|
|
949
691
|
const footerLines = ['---'];
|
|
950
692
|
if (opts.footer?.parent) footerLines.push(`parent: #${opts.footer.parent}`);
|
|
951
|
-
//
|
|
952
|
-
// Story body carrying that footer, so composing one here would let the
|
|
953
|
-
// framework generate work it would then reject at delivery.
|
|
693
|
+
// Never an `Epic: #N` line: pr-base-guard.js refuses a body carrying one.
|
|
954
694
|
if (Array.isArray(body.depends_on)) {
|
|
955
695
|
for (const dep of body.depends_on) {
|
|
956
696
|
footerLines.push(`blocked by ${dep}`);
|
|
@@ -960,13 +700,6 @@ function serializeFooter(body, opts) {
|
|
|
960
700
|
}
|
|
961
701
|
|
|
962
702
|
/**
|
|
963
|
-
* Serialize a structured {@link StoryBody} back to the canonical markdown
|
|
964
|
-
* format written to GitHub issue bodies.
|
|
965
|
-
*
|
|
966
|
-
* The output matches the section order the spec-renderer uses:
|
|
967
|
-
* `## Goal`, `## Slicing`, `## Spec`, `## Changes`, `## Acceptance`,
|
|
968
|
-
* `## Verify`, `## References`, `## Non-Goals` (each omitted when empty).
|
|
969
|
-
*
|
|
970
703
|
* @param {StoryBody} body
|
|
971
704
|
* @param {SerializeOptions} [opts]
|
|
972
705
|
* @returns {string}
|
|
@@ -987,17 +720,9 @@ export function serialize(body, opts = {}) {
|
|
|
987
720
|
return sections.join('\n\n') + serializeFooter(body, opts);
|
|
988
721
|
}
|
|
989
722
|
|
|
990
|
-
// ---------------------------------------------------------------------------
|
|
991
|
-
// Convenience: extract changes paths for the wave planner
|
|
992
|
-
// ---------------------------------------------------------------------------
|
|
993
|
-
|
|
994
723
|
/**
|
|
995
|
-
*
|
|
996
|
-
*
|
|
997
|
-
*
|
|
998
|
-
* The wave planner (Feature 3) uses this to compute file-overlap
|
|
999
|
-
* serialization between Stories: if any entry `isGlob`, the Story's
|
|
1000
|
-
* footprint is `unknown-width`.
|
|
724
|
+
* Path strings from `changes[]`; any glob entry makes the footprint
|
|
725
|
+
* unknown-width for the wave planner.
|
|
1001
726
|
*
|
|
1002
727
|
* @param {ChangeEntry[]} changes
|
|
1003
728
|
* @returns {Array<{ path: string, isGlob: boolean }>}
|