mandrel 2.31.0 → 2.33.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 +13 -17
- package/.agents/agents/acceptance-critic.md +1 -2
- package/.agents/docs/SDLC.md +12 -9
- package/.agents/docs/agentrc-reference.json +63 -58
- package/.agents/docs/configuration.md +275 -227
- package/.agents/docs/execution-reference.md +13 -14
- package/.agents/docs/quality-gates.md +195 -23
- package/.agents/instructions.md +2 -5
- package/.agents/rules/git-conventions-reference.md +27 -27
- package/.agents/rules/git-conventions.md +4 -2
- package/.agents/rules/known-tooling-behavior.md +66 -30
- package/.agents/rules/testing-standards.md +35 -71
- package/.agents/runtime-deps.json +2 -2
- package/.agents/schemas/agentrc.schema.json +1955 -1410
- package/.agents/schemas/lifecycle/README.md +21 -14
- package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
- package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
- package/.agents/scripts/README.md +16 -29
- package/.agents/scripts/apply-quality-bootstrap.js +27 -34
- package/.agents/scripts/audit-to-stories.js +160 -41
- package/.agents/scripts/bootstrap.js +28 -26
- package/.agents/scripts/check-baseline-drift.js +73 -13
- package/.agents/scripts/check-baseline-scope.js +362 -0
- package/.agents/scripts/check-dead-exports.js +9 -1
- package/.agents/scripts/check-gherkin-corpus.js +508 -0
- package/.agents/scripts/check-knip-entries.js +159 -0
- package/.agents/scripts/check-lifecycle-lint.js +108 -124
- package/.agents/scripts/check-schema-references.js +1 -1
- package/.agents/scripts/diagnose-friction.js +7 -4
- package/.agents/scripts/generate-config-docs.js +263 -171
- package/.agents/scripts/install-matrix-assert.js +0 -1
- package/.agents/scripts/lib/ITicketingProvider.js +0 -58
- package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
- package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +81 -35
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +185 -0
- package/.agents/scripts/lib/baselines/envelope.js +41 -60
- package/.agents/scripts/lib/baselines/git-base.js +30 -37
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
- package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
- package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
- package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
- package/.agents/scripts/lib/bdd-step-index.js +326 -0
- package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
- package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
- package/.agents/scripts/lib/checks/loop-health.js +9 -37
- package/.agents/scripts/lib/child-exec.js +193 -0
- package/.agents/scripts/lib/cli/standard-args.js +1 -1
- package/.agents/scripts/lib/cli-args.js +64 -0
- package/.agents/scripts/lib/close-validation/gates.js +2 -2
- package/.agents/scripts/lib/close-validation/runner.js +3 -3
- package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
- package/.agents/scripts/lib/config/commands.js +3 -5
- package/.agents/scripts/lib/config/explain.js +5 -7
- package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
- package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
- package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
- package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
- package/.agents/scripts/lib/config/gates/index.js +5 -2
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
- package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
- package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
- package/.agents/scripts/lib/config/gates/shared.js +58 -9
- package/.agents/scripts/lib/config/github.js +0 -1
- package/.agents/scripts/lib/config/limits.js +3 -48
- package/.agents/scripts/lib/config/qa.js +105 -0
- package/.agents/scripts/lib/config/runners.js +38 -16
- package/.agents/scripts/lib/config/temp-paths.js +6 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +245 -56
- package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
- package/.agents/scripts/lib/config-settings-schema.js +386 -39
- package/.agents/scripts/lib/crap-baseline-join.js +126 -9
- package/.agents/scripts/lib/crap-utils.js +84 -520
- package/.agents/scripts/lib/dead-exports-knip.js +79 -10
- package/.agents/scripts/lib/degraded-mode.js +2 -2
- package/.agents/scripts/lib/dependency-parser.js +20 -7
- package/.agents/scripts/lib/doc-tiers.js +3 -3
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
- package/.agents/scripts/lib/findings/provenance-field.js +135 -0
- package/.agents/scripts/lib/findings/route-finding.js +57 -8
- package/.agents/scripts/lib/fs-walk.js +52 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/git-utils.js +16 -36
- package/.agents/scripts/lib/knip-config-resolver.js +181 -0
- package/.agents/scripts/lib/knip-entry-sync.js +508 -0
- package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
- package/.agents/scripts/lib/observability/signal-validator.js +5 -85
- package/.agents/scripts/lib/observability/signals-writer.js +19 -62
- package/.agents/scripts/lib/observability/source-classifier.js +5 -7
- package/.agents/scripts/lib/observability/terse-result.js +3 -3
- package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
- package/.agents/scripts/lib/orchestration/code-review.js +2 -2
- package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
- package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
- package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +7 -26
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +69 -5
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +69 -13
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +49 -0
- package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
- package/.agents/scripts/lib/orchestration/resolve-stories.js +77 -50
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +59 -25
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
- package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +116 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator.js +38 -0
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
- package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
- package/.agents/scripts/lib/signals/detectors/common.js +1 -1
- package/.agents/scripts/lib/signals/index.js +8 -6
- package/.agents/scripts/lib/signals/schema.js +20 -25
- package/.agents/scripts/lib/signals/write.js +8 -8
- package/.agents/scripts/lib/story-body/footer-block.js +97 -0
- package/.agents/scripts/lib/story-body/story-body.js +18 -81
- package/.agents/scripts/lib/temp-retention.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
- package/.agents/scripts/lib/ticket-body-sections.js +4 -5
- package/.agents/scripts/lib/wave-runner/footprint.js +306 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +198 -181
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
- package/.agents/scripts/lib/worktree-manager.js +2 -3
- package/.agents/scripts/lint-label-vocabulary.js +2 -24
- package/.agents/scripts/pr-watch-with-update.js +7 -5
- package/.agents/scripts/providers/github/blocked-by-add.js +25 -10
- package/.agents/scripts/providers/github/cache.js +2 -2
- package/.agents/scripts/providers/github/comments.js +6 -28
- package/.agents/scripts/providers/github/compose.js +0 -15
- package/.agents/scripts/providers/github/errors.js +10 -27
- package/.agents/scripts/providers/github/request-helpers.js +1 -2
- package/.agents/scripts/providers/github/sub-issues.js +10 -218
- package/.agents/scripts/providers/github.js +4 -7
- package/.agents/scripts/prune-baseline-orphans.js +181 -0
- package/.agents/scripts/resolve-stories.js +21 -7
- package/.agents/scripts/run-lint.js +61 -61
- package/.agents/scripts/run-test-profile.js +6 -6
- package/.agents/scripts/run-verify.js +48 -30
- package/.agents/scripts/single-story-close.js +20 -0
- package/.agents/scripts/single-story-init.js +12 -35
- package/.agents/scripts/stories-wave-tick.js +192 -9
- package/.agents/scripts/update-dead-exports-baseline.js +321 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
- package/.agents/skills/skills.index.json +1 -11
- package/.agents/workflows/audit-documentation.md +5 -6
- package/.agents/workflows/audit-to-stories.md +28 -2
- package/.agents/workflows/helpers/audit-lens-core.md +11 -12
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
- package/.agents/workflows/helpers/code-review.md +3 -8
- package/.agents/workflows/helpers/deliver-reference.md +30 -2
- package/.agents/workflows/helpers/deliver-story-reference.md +84 -16
- package/.agents/workflows/helpers/plan-reference.md +76 -0
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
- package/.agents/workflows/mandrel-update.md +10 -10
- package/.agents/workflows/qa-assist.md +15 -20
- package/.agents/workflows/qa-explore.md +9 -8
- package/README.md +1 -1
- package/docs/CHANGELOG.md +58 -0
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
- package/package.json +14 -5
- package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
- package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
- package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
- package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
- package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
- package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
- package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
- package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
- package/.agents/scripts/check-gherkin-placeholders.js +0 -663
- package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
- package/.agents/scripts/lib/audit-suite/cli.js +0 -64
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
- package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
- package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
- package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
- package/.agents/scripts/lib/crap-baseline-index.js +0 -46
- package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
- package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
- package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
- package/.agents/scripts/lib/mutation/config-detector.js +0 -119
- package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
- package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
- package/.agents/scripts/lib/observability/active-story-env.js +0 -170
- package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
- package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
- package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
- package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
- package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
- package/.agents/scripts/lib/planning-corpus.js +0 -37
- package/.agents/scripts/lib/qa/coverage-report.js +0 -181
- package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
- package/.agents/scripts/lib/signals/detectors/index.js +0 -14
- package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
- package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
- package/.agents/scripts/lib/signals/read.js +0 -268
- package/.agents/scripts/lib/signals/span-tree.js +0 -291
- package/.agents/scripts/lib/story-lifecycle.js +0 -194
- package/.agents/scripts/lib/story-plan.js +0 -379
- package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
- package/.agents/scripts/lib/util/phase-timer.js +0 -163
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
- package/.agents/scripts/lint-baseline.js +0 -507
- package/.agents/scripts/providers/github/prs.js +0 -103
- package/.agents/scripts/signals-view.js +0 -309
- package/.agents/scripts/story-plan.js +0 -370
- package/.agents/scripts/sync-branch-from-base.js +0 -149
- package/.agents/scripts/validate-docs-freshness.js +0 -314
- package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
- package/.agents/workflows/helpers/signals.md +0 -112
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
# Lifecycle event schemas
|
|
2
2
|
|
|
3
|
-
JSON Schemas for the
|
|
4
|
-
|
|
5
|
-
(`lib/orchestration/lifecycle/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
throw.
|
|
3
|
+
JSON Schemas for the two events a delivery run can append to its per-run
|
|
4
|
+
lifecycle ledger. `appendLedgerEvent`
|
|
5
|
+
(`lib/orchestration/lifecycle/emit-ledger-event.js`) validates every payload
|
|
6
|
+
against one of these before the write; a schema mismatch throws and nothing is
|
|
7
|
+
appended.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`ledger-writer.js`.
|
|
9
|
+
`ledger-record.schema.json` is the NDJSON record envelope
|
|
10
|
+
(`emitted | completed | failed`), not an event. Only `emitted` has a writer —
|
|
11
|
+
see the schema's own description for why the other two kinds remain.
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
**A schema belongs here only while code emits its event.** Story #4545 applied
|
|
14
|
+
that rule to the `epic.*` and `acceptance.reconcile.*` families; Story #5024
|
|
15
|
+
applied it to the remaining fifteen when it retired the lifecycle bus that had
|
|
16
|
+
been their only publish path. `tests/lifecycle/schema-registry.test.js` enforces
|
|
17
|
+
it in both directions, so a schema file for an event nobody emits fails the
|
|
18
|
+
suite rather than reading green.
|
|
19
|
+
|
|
20
|
+
Schemas are intentionally permissive (`additionalProperties: true`) on inner
|
|
21
|
+
objects whose shape is dictated by upstream tooling (e.g. `gh pr view` JSON).
|
|
22
|
+
The required-key set is the contract.
|
|
23
|
+
|
|
24
|
+
Full reference:
|
|
25
|
+
[`docs/LIFECYCLE.md`](https://github.com/dsj1984/mandrel/blob/main/docs/LIFECYCLE.md).
|
|
@@ -2,22 +2,41 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/ledger-record.schema.json",
|
|
4
4
|
"title": "Lifecycle ledger record (emitted | completed | failed)",
|
|
5
|
-
"description": "Append-only NDJSON record shape for
|
|
5
|
+
"description": "Append-only NDJSON record shape for the per-run lifecycle ledger. Three discriminated kinds keyed on `kind`. Only `emitted` has a writer: Story #5024 retired the lifecycle bus, so the `completed` / `failed` kinds are a READ contract for ledgers archived from the bus era (`failed` requires a `listener`, which only a listener chain could supply). Reading a ledger never consults this schema; validation happens on the write path only.",
|
|
6
6
|
"oneOf": [
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
{
|
|
8
|
+
"$ref": "#/$defs/emitted"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"$ref": "#/$defs/completed"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"$ref": "#/$defs/failed"
|
|
15
|
+
}
|
|
10
16
|
],
|
|
11
17
|
"$defs": {
|
|
12
18
|
"emitted": {
|
|
13
19
|
"type": "object",
|
|
14
20
|
"required": ["kind", "seqId", "ts", "event", "payload"],
|
|
15
21
|
"properties": {
|
|
16
|
-
"kind": {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
22
|
+
"kind": {
|
|
23
|
+
"const": "emitted"
|
|
24
|
+
},
|
|
25
|
+
"seqId": {
|
|
26
|
+
"type": "integer",
|
|
27
|
+
"minimum": 1
|
|
28
|
+
},
|
|
29
|
+
"ts": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"format": "date-time"
|
|
32
|
+
},
|
|
33
|
+
"event": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"minLength": 1
|
|
36
|
+
},
|
|
37
|
+
"payload": {
|
|
38
|
+
"type": "object"
|
|
39
|
+
}
|
|
21
40
|
},
|
|
22
41
|
"additionalProperties": false
|
|
23
42
|
},
|
|
@@ -25,11 +44,25 @@
|
|
|
25
44
|
"type": "object",
|
|
26
45
|
"required": ["kind", "seqId", "ts", "event"],
|
|
27
46
|
"properties": {
|
|
28
|
-
"kind": {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
47
|
+
"kind": {
|
|
48
|
+
"const": "completed"
|
|
49
|
+
},
|
|
50
|
+
"seqId": {
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"minimum": 1
|
|
53
|
+
},
|
|
54
|
+
"ts": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"format": "date-time"
|
|
57
|
+
},
|
|
58
|
+
"event": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"minLength": 1
|
|
61
|
+
},
|
|
62
|
+
"listener": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"minLength": 1
|
|
65
|
+
}
|
|
33
66
|
},
|
|
34
67
|
"additionalProperties": false
|
|
35
68
|
},
|
|
@@ -37,18 +70,39 @@
|
|
|
37
70
|
"type": "object",
|
|
38
71
|
"required": ["kind", "seqId", "ts", "event", "listener", "error"],
|
|
39
72
|
"properties": {
|
|
40
|
-
"kind": {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
73
|
+
"kind": {
|
|
74
|
+
"const": "failed"
|
|
75
|
+
},
|
|
76
|
+
"seqId": {
|
|
77
|
+
"type": "integer",
|
|
78
|
+
"minimum": 1
|
|
79
|
+
},
|
|
80
|
+
"ts": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"format": "date-time"
|
|
83
|
+
},
|
|
84
|
+
"event": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"minLength": 1
|
|
87
|
+
},
|
|
88
|
+
"listener": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"minLength": 1
|
|
91
|
+
},
|
|
45
92
|
"error": {
|
|
46
93
|
"type": "object",
|
|
47
94
|
"required": ["name", "message"],
|
|
48
95
|
"properties": {
|
|
49
|
-
"name": {
|
|
50
|
-
|
|
51
|
-
|
|
96
|
+
"name": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"minLength": 1
|
|
99
|
+
},
|
|
100
|
+
"message": {
|
|
101
|
+
"type": "string"
|
|
102
|
+
},
|
|
103
|
+
"stack": {
|
|
104
|
+
"type": "string"
|
|
105
|
+
}
|
|
52
106
|
},
|
|
53
107
|
"additionalProperties": false
|
|
54
108
|
}
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
},
|
|
74
74
|
"gates": {
|
|
75
75
|
"type": "object",
|
|
76
|
-
"description": "Outcome of each close gate this invocation was responsible for. A gate the run skipped (--skip-validation, or a phase it never reached) reports \"skipped\" rather than being omitted, so a missing gate is never mistaken for a passing one.",
|
|
76
|
+
"description": "Outcome of each close gate this invocation was responsible for. A gate the run skipped (--skip-validation, or a phase it never reached) reports \"skipped\" rather than being omitted, so a missing gate is never mistaken for a passing one. \"overridden\" is distinct from both: the gate ran, it FAILED, and an operator authorized delivery anyway via --override-review-block with a recorded reason. Reporting that as \"passed\" would erase the one fact a reader of this envelope most needs, and reporting it as \"skipped\" would claim the gate never ran.",
|
|
77
77
|
"additionalProperties": {
|
|
78
78
|
"type": "string",
|
|
79
|
-
"enum": ["passed", "failed", "skipped"]
|
|
79
|
+
"enum": ["passed", "failed", "skipped", "overridden"]
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
"tail": {
|
|
@@ -5,35 +5,22 @@ invoked indirectly by `npm run …`, slash-command workflows
|
|
|
5
5
|
(`.agents/workflows/*.md`), or Husky / GitHub Actions hooks; you rarely
|
|
6
6
|
need to call them by hand.
|
|
7
7
|
|
|
8
|
-
This file is **not** an exhaustive index of the ~90 top-level entrypoints
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
that the file was meaningfully updated during this Epic's lifecycle
|
|
25
|
-
(commit message references `#<epicId>` or the file body does).
|
|
26
|
-
|
|
27
|
-
**When to run.** Optional. Useful as a pre-merge spot check when an
|
|
28
|
-
Epic should have produced documentation updates; the standard
|
|
29
|
-
`/deliver` flow does **not** invoke this gate today.
|
|
30
|
-
|
|
31
|
-
**Usage.**
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
node .agents/scripts/validate-docs-freshness.js --epic <id> \
|
|
35
|
-
[--base main] [--docs <comma-separated>] [--json]
|
|
36
|
-
```
|
|
8
|
+
This file is **not** an exhaustive index of the ~90 top-level entrypoints —
|
|
9
|
+
it is the orientation pointer for the directory. Every script documents
|
|
10
|
+
its own flags under `--help`, and each is reachable from a real caller:
|
|
11
|
+
search `package.json` scripts, `.agents/workflows/`, and the Husky /
|
|
12
|
+
GitHub Actions surfaces first. `check-knip-entries.js` derives that
|
|
13
|
+
caller set mechanically, so a CLI no invoker names is dead, not
|
|
14
|
+
operator-only.
|
|
15
|
+
|
|
16
|
+
It reads the entry list from whatever configuration knip itself would
|
|
17
|
+
load — `knip.json`, `knip.jsonc`, `.knip.json(c)`, `knip.ts`, `knip.js`,
|
|
18
|
+
`knip.config.ts`, `knip.config.js`, or `package.json#knip` — evaluating
|
|
19
|
+
TS/JS modules rather than parsing them, and counting entries declared
|
|
20
|
+
per-workspace as well as at the top level. A project with no knip
|
|
21
|
+
configuration at all exits 0 with a skip line, so the gate is safe to
|
|
22
|
+
wire everywhere; a configuration that exists but cannot be resolved
|
|
23
|
+
still exits 2.
|
|
37
24
|
|
|
38
25
|
## See Also
|
|
39
26
|
|
|
@@ -11,63 +11,56 @@
|
|
|
11
11
|
* had no test so it silently drifted when the two helper signatures moved, and
|
|
12
12
|
* it could not be invoked or dry-run independently.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* the
|
|
14
|
+
* The script runs one install against the consumer repo root:
|
|
15
|
+
* `applyQualityBootstrap` — copies the code-quality-guardrails helper,
|
|
16
|
+
* installs the `.husky/pre-commit` quality:preview line, backfills the
|
|
17
|
+
* `quality:preview` / `quality:watch` npm scripts, seeds the
|
|
18
|
+
* `delivery.quality.{codingGuardrails,autoRefresh}` defaults, and prunes a
|
|
19
|
+
* committed pre-v2 `baselines/epic/` tree.
|
|
16
20
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Story #5007 retired the second step. `migrateBaselinesLayout` relocated
|
|
22
|
+
* per-Epic ratchet snapshots into `temp/epic/<id>/baselines/` on the contract
|
|
23
|
+
* that `/deliver` reaps that namespace on merge — a mechanism the Story-only
|
|
24
|
+
* v2 model deleted, so the migration moved dead data into a namespace no code
|
|
25
|
+
* path writes, reads, or reaps. Its one residual hygiene value (getting the
|
|
26
|
+
* committed `baselines/epic/` tree out of version control) survives as
|
|
27
|
+
* `pruneLegacyEpicBaselines`, the quality install's fifth step.
|
|
23
28
|
*
|
|
24
|
-
*
|
|
25
|
-
* on every install path — so this wrapper is safe
|
|
26
|
-
*
|
|
27
|
-
* stdout, so any tooling that parsed the old output keeps working.
|
|
29
|
+
* The helper is idempotent by contract — a second run reports `no-change` /
|
|
30
|
+
* `already-present` / `absent` on every install path — so this wrapper is safe
|
|
31
|
+
* to re-run. It prints `{ quality }` JSON to stdout.
|
|
28
32
|
*
|
|
29
33
|
* The effectful work is a thin pure function (`applyBootstrapAndMigration`)
|
|
30
|
-
* that takes the
|
|
31
|
-
*
|
|
32
|
-
*
|
|
34
|
+
* that takes the helper and the project root, so the test suite can drive it
|
|
35
|
+
* against a tmp directory without spawning a child process. The CLI wrapper
|
|
36
|
+
* wires the real helper and `process.cwd()`.
|
|
33
37
|
*/
|
|
34
38
|
|
|
35
|
-
import path from 'node:path';
|
|
36
|
-
import { migrateBaselinesLayout } from './lib/bootstrap/baselines-layout-migration.js';
|
|
37
39
|
import { applyQualityBootstrap } from './lib/bootstrap/quality-bootstrap.js';
|
|
38
40
|
import { runAsCli } from './lib/cli-utils.js';
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
|
-
* Run the quality-bootstrap install
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* the composition in isolation.
|
|
43
|
+
* Run the quality-bootstrap install against `projectRoot`, returning the
|
|
44
|
+
* `{ quality }` envelope. Pure relative to its injected helper: the default
|
|
45
|
+
* helper touches the filesystem under `projectRoot`, but tests can pass a stub
|
|
46
|
+
* to exercise the composition in isolation.
|
|
46
47
|
*
|
|
47
48
|
* @param {object} options
|
|
48
49
|
* @param {string} options.projectRoot Absolute consumer repo root.
|
|
49
50
|
* @param {typeof applyQualityBootstrap} [options.applyQualityBootstrap]
|
|
50
|
-
* @
|
|
51
|
-
* @returns {{ quality: object, baselines: object }}
|
|
51
|
+
* @returns {{ quality: object }}
|
|
52
52
|
*/
|
|
53
53
|
export function applyBootstrapAndMigration({
|
|
54
54
|
projectRoot,
|
|
55
55
|
applyQualityBootstrap: applyQuality = applyQualityBootstrap,
|
|
56
|
-
migrateBaselinesLayout: migrateBaselines = migrateBaselinesLayout,
|
|
57
56
|
}) {
|
|
58
|
-
|
|
59
|
-
const baselines = migrateBaselines({
|
|
60
|
-
baselinesDir: path.join(projectRoot, 'baselines'),
|
|
61
|
-
repoRoot: projectRoot,
|
|
62
|
-
});
|
|
63
|
-
return { quality, baselines };
|
|
57
|
+
return { quality: applyQuality({ projectRoot }) };
|
|
64
58
|
}
|
|
65
59
|
|
|
66
60
|
async function main() {
|
|
67
61
|
const projectRoot = process.cwd();
|
|
68
62
|
const result = applyBootstrapAndMigration({ projectRoot });
|
|
69
|
-
//
|
|
70
|
-
// to stdout. Use process.stdout.write (not console.log) per the no-console
|
|
63
|
+
// Use process.stdout.write (not console.log) per the no-console
|
|
71
64
|
// enforcement boundary.
|
|
72
65
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
73
66
|
return 0;
|
|
@@ -79,7 +72,7 @@ runAsCli(import.meta.url, main, {
|
|
|
79
72
|
usage: {
|
|
80
73
|
invocation: 'node .agents/scripts/apply-quality-bootstrap.js',
|
|
81
74
|
summary:
|
|
82
|
-
'Install the quality-gate surface into the consumer repo (guardrails helper, pre-commit line, npm scripts, config defaults
|
|
75
|
+
'Install the quality-gate surface into the consumer repo (guardrails helper, pre-commit line, npm scripts, config defaults, legacy baselines/epic prune). Idempotent; prints { quality } JSON to stdout.',
|
|
83
76
|
flags: [],
|
|
84
77
|
},
|
|
85
78
|
});
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
} from './lib/audit-to-stories/ledger.js';
|
|
46
46
|
import { parseAuditReports } from './lib/audit-to-stories/parse-audit-md.js';
|
|
47
47
|
import { buildPlanSeedMarkdown } from './lib/audit-to-stories/seed-from-findings.js';
|
|
48
|
+
import { wireAuditStoryEdges } from './lib/audit-to-stories/wire-dependencies.js';
|
|
48
49
|
import { runAsCli } from './lib/cli-utils.js';
|
|
49
50
|
import { searchSemanticCandidates } from './lib/findings/semantic-issue-search.js';
|
|
50
51
|
import { SEVERITIES, SEVERITY_RANK } from './lib/findings/severity.js';
|
|
@@ -583,6 +584,81 @@ function buildAndGateStories(eligible, edges) {
|
|
|
583
584
|
return built;
|
|
584
585
|
}
|
|
585
586
|
|
|
587
|
+
/**
|
|
588
|
+
* The `--wire-edges` pass: hand the opened issue numbers back so the cohort's
|
|
589
|
+
* detected group edges become declared ordering (Story #5044).
|
|
590
|
+
*
|
|
591
|
+
* This is the second half of the two-pass crossing `--emit-stories` starts. The
|
|
592
|
+
* host opens one Issue per group from the emitted drafts, then replays the
|
|
593
|
+
* `groupKey → issueNumber` map here; each Story whose blockers now exist is
|
|
594
|
+
* re-rendered with a canonical `blocked by #N` footer and the same edges are
|
|
595
|
+
* mirrored as native `blocked_by` relations.
|
|
596
|
+
*
|
|
597
|
+
* @param {object} params
|
|
598
|
+
* @param {object} params.plan A `--scan` plan envelope.
|
|
599
|
+
* @param {Record<string, number>} params.issueByGroupKey
|
|
600
|
+
* @param {object} [deps]
|
|
601
|
+
* @param {Function} [deps.loadProviderImpl]
|
|
602
|
+
* @param {Function} [deps.wireImpl]
|
|
603
|
+
* @returns {Promise<object>} the wiring summary.
|
|
604
|
+
*/
|
|
605
|
+
async function wireEdges({ plan, issueByGroupKey }, deps = {}) {
|
|
606
|
+
const { loadProviderImpl = loadProvider, wireImpl = wireAuditStoryEdges } =
|
|
607
|
+
deps;
|
|
608
|
+
const groups = (plan.classifications ?? [])
|
|
609
|
+
.filter((c) => c.action === 'create')
|
|
610
|
+
.map((c) => c.group);
|
|
611
|
+
const provider = await loadProviderImpl();
|
|
612
|
+
if (typeof provider?.updateTicket !== 'function') {
|
|
613
|
+
throw new Error(
|
|
614
|
+
'--wire-edges needs a provider exposing updateTicket to rewrite the ' +
|
|
615
|
+
'Story bodies with their `blocked by #N` footers. Configure ' +
|
|
616
|
+
'github.owner/repo (and auth), or wire the edges by hand.',
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
return wireImpl({
|
|
620
|
+
groups,
|
|
621
|
+
edges: plan.edges ?? [],
|
|
622
|
+
issueByGroupKey,
|
|
623
|
+
provider,
|
|
624
|
+
updateBody: (issueNumber, body) =>
|
|
625
|
+
provider.updateTicket(issueNumber, { body }),
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Parse the `--ids` argument: a JSON object mapping group key → issue number,
|
|
631
|
+
* or a path to a file containing one.
|
|
632
|
+
*
|
|
633
|
+
* @param {string|undefined} raw
|
|
634
|
+
* @returns {Record<string, number>}
|
|
635
|
+
*/
|
|
636
|
+
function parseIssueMap(raw) {
|
|
637
|
+
if (!raw) {
|
|
638
|
+
throw new Error(
|
|
639
|
+
'--wire-edges requires --ids \'{"<groupKey>": <issueNumber>, ...}\' ' +
|
|
640
|
+
'(or a path to a JSON file with that shape) — the issue numbers the ' +
|
|
641
|
+
'create pass opened. Without them there is nothing to resolve the ' +
|
|
642
|
+
'group edges against.',
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
const text = raw.trimStart().startsWith('{')
|
|
646
|
+
? raw
|
|
647
|
+
: fs.readFileSync(raw, 'utf8');
|
|
648
|
+
const parsed = JSON.parse(text);
|
|
649
|
+
const out = {};
|
|
650
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
651
|
+
const n = Number(value);
|
|
652
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
653
|
+
throw new Error(
|
|
654
|
+
`--ids: "${key}" maps to ${JSON.stringify(value)}, which is not a positive issue number.`,
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
out[key] = n;
|
|
658
|
+
}
|
|
659
|
+
return out;
|
|
660
|
+
}
|
|
661
|
+
|
|
586
662
|
function persist(text, outPath) {
|
|
587
663
|
if (!outPath) {
|
|
588
664
|
process.stdout.write(text);
|
|
@@ -604,6 +680,8 @@ export const __testing = {
|
|
|
604
680
|
resolveSeverityFloor,
|
|
605
681
|
reconcileScanLedger,
|
|
606
682
|
issueStatesFromClassifications,
|
|
683
|
+
wireEdges,
|
|
684
|
+
parseIssueMap,
|
|
607
685
|
};
|
|
608
686
|
|
|
609
687
|
/**
|
|
@@ -637,6 +715,8 @@ export async function runAuditToStories(
|
|
|
637
715
|
loadPlanImpl = loadPlan,
|
|
638
716
|
buildAndGateStoriesImpl = buildAndGateStories,
|
|
639
717
|
buildPlanSeedMarkdownImpl = buildPlanSeedMarkdown,
|
|
718
|
+
wireEdgesImpl = wireEdges,
|
|
719
|
+
parseIssueMapImpl = parseIssueMap,
|
|
640
720
|
persistImpl = persist,
|
|
641
721
|
stdout = process.stdout,
|
|
642
722
|
} = deps;
|
|
@@ -648,6 +728,8 @@ export async function runAuditToStories(
|
|
|
648
728
|
'dry-run': { type: 'boolean' },
|
|
649
729
|
'emit-plan-seed': { type: 'boolean' },
|
|
650
730
|
'emit-stories': { type: 'boolean' },
|
|
731
|
+
'wire-edges': { type: 'boolean' },
|
|
732
|
+
ids: { type: 'string' },
|
|
651
733
|
glob: { type: 'string' },
|
|
652
734
|
severity: { type: 'string' },
|
|
653
735
|
ledger: { type: 'string' },
|
|
@@ -659,64 +741,93 @@ export async function runAuditToStories(
|
|
|
659
741
|
strict: false,
|
|
660
742
|
});
|
|
661
743
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
744
|
+
const json = (value) => JSON.stringify(value, null, 2);
|
|
745
|
+
|
|
746
|
+
const runAutoSummary = async () =>
|
|
747
|
+
(
|
|
748
|
+
await runAutoImpl({
|
|
749
|
+
glob: values.glob,
|
|
750
|
+
severity: values.severity,
|
|
751
|
+
dryRun: values['dry-run'],
|
|
752
|
+
useProvider: !values['no-provider'],
|
|
753
|
+
ledgerPath: values.ledger,
|
|
754
|
+
})
|
|
755
|
+
).summary;
|
|
756
|
+
|
|
757
|
+
const scanPlan = () =>
|
|
758
|
+
buildPlanImpl({
|
|
677
759
|
glob: values.glob,
|
|
678
760
|
severity: values.severity,
|
|
679
761
|
useProvider: !values['no-provider'],
|
|
680
762
|
});
|
|
681
|
-
const out = JSON.stringify(plan, null, 2);
|
|
682
|
-
persistImpl(out, values.out);
|
|
683
|
-
if (!values.out) stdout.write('\n');
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
763
|
|
|
687
|
-
|
|
764
|
+
const seedMarkdown = () => {
|
|
688
765
|
const plan = loadPlanImpl(values.plan);
|
|
689
|
-
|
|
766
|
+
return buildPlanSeedMarkdownImpl({
|
|
690
767
|
groups: plan.groups ?? [],
|
|
691
768
|
findings: plan.findings ?? [],
|
|
692
769
|
sourceReports: plan.sourceReports ?? [],
|
|
693
770
|
});
|
|
694
|
-
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
771
|
+
};
|
|
697
772
|
|
|
698
|
-
|
|
773
|
+
const emittedStories = () => {
|
|
699
774
|
const plan = loadPlanImpl(values.plan);
|
|
700
775
|
const eligible = (plan.classifications ?? [])
|
|
701
776
|
.filter((c) => c.action === 'create')
|
|
702
777
|
.map((c) => c.group);
|
|
703
778
|
const built = buildAndGateStoriesImpl(eligible, plan.edges ?? []);
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
779
|
+
return values.json ? json(built) : renderStoryDrafts(built);
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
const wiredEdges = () =>
|
|
783
|
+
wireEdgesImpl({
|
|
784
|
+
plan: loadPlanImpl(values.plan),
|
|
785
|
+
issueByGroupKey: parseIssueMapImpl(values.ids),
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
// One table, not a chain of `if (values.X) { …; return; }`. Each entry
|
|
789
|
+
// renders its sub-command's output; persisting it — and the stdout newline a
|
|
790
|
+
// piped run needs — happens once, below. The chain restated that tail in
|
|
791
|
+
// every arm, so each new sub-command paid for it twice: once in the branch
|
|
792
|
+
// and once in the complexity budget.
|
|
793
|
+
const subcommands = [
|
|
794
|
+
['auto', async () => json(await runAutoSummary()), true],
|
|
795
|
+
['scan', async () => json(await scanPlan()), true],
|
|
796
|
+
['emit-plan-seed', () => seedMarkdown(), false],
|
|
797
|
+
['emit-stories', () => emittedStories(), true],
|
|
798
|
+
['wire-edges', async () => json(await wiredEdges()), true],
|
|
799
|
+
];
|
|
800
|
+
|
|
801
|
+
const entry = subcommands.find(([flag]) => values[flag]);
|
|
802
|
+
if (!entry) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
'Usage: node audit-to-stories.js (--scan | --emit-plan-seed | --emit-stories | --wire-edges) [options]',
|
|
805
|
+
);
|
|
715
806
|
}
|
|
807
|
+
const [, render, newlineOnStdout] = entry;
|
|
808
|
+
persistImpl(await render(), values.out);
|
|
809
|
+
if (newlineOnStdout && !values.out) stdout.write('\n');
|
|
810
|
+
}
|
|
716
811
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
812
|
+
/**
|
|
813
|
+
* Render the Story drafts as the human-readable `--emit-stories` transcript
|
|
814
|
+
* (the `--json` form is the machine one). `dependsOn` is surfaced because the
|
|
815
|
+
* group edges no longer ride the body at emit time — the blockers have no issue
|
|
816
|
+
* numbers yet — so this is where a human driving the create pass by hand sees
|
|
817
|
+
* the ordering they will replay through `--wire-edges` (Story #5044).
|
|
818
|
+
*
|
|
819
|
+
* @param {Array<{ title: string, labels: string[], body: string, groupKey?: string, dependsOn?: string[] }>} built
|
|
820
|
+
* @returns {string}
|
|
821
|
+
*/
|
|
822
|
+
function renderStoryDrafts(built) {
|
|
823
|
+
return built
|
|
824
|
+
.map((s, i) => {
|
|
825
|
+
const deps = (s.dependsOn ?? []).length
|
|
826
|
+
? `\nDepends on group(s): ${s.dependsOn.join(', ')}`
|
|
827
|
+
: '';
|
|
828
|
+
return `--- story ${i + 1} ---\nTitle: ${s.title}\nLabels: ${s.labels.join(', ')}\nGroup key: ${s.groupKey}${deps}\n\n${s.body}\n`;
|
|
829
|
+
})
|
|
830
|
+
.join('\n');
|
|
720
831
|
}
|
|
721
832
|
|
|
722
833
|
async function main() {
|
|
@@ -727,7 +838,7 @@ runAsCli(import.meta.url, main, {
|
|
|
727
838
|
source: 'audit-to-stories',
|
|
728
839
|
usage: {
|
|
729
840
|
invocation:
|
|
730
|
-
'node .agents/scripts/audit-to-stories.js (--scan | --auto | --emit-plan-seed | --emit-stories) [options]',
|
|
841
|
+
'node .agents/scripts/audit-to-stories.js (--scan | --auto | --emit-plan-seed | --emit-stories | --wire-edges) [options]',
|
|
731
842
|
summary:
|
|
732
843
|
'Turn audit-lens findings under temp/audits/ into a dedup-checked plan seed or standalone Stories.',
|
|
733
844
|
flags: [
|
|
@@ -735,6 +846,14 @@ runAsCli(import.meta.url, main, {
|
|
|
735
846
|
['--auto', 'Run the full scan → file pipeline and print the summary.'],
|
|
736
847
|
['--emit-plan-seed', 'Emit a /plan --seed-file document.'],
|
|
737
848
|
['--emit-stories', 'Emit the Story drafts as JSON.'],
|
|
849
|
+
[
|
|
850
|
+
'--wire-edges',
|
|
851
|
+
'Second pass: resolve the detected group edges to blocked by #N footers plus native blocked_by relations. Needs --plan and --ids.',
|
|
852
|
+
],
|
|
853
|
+
[
|
|
854
|
+
'--ids <json|path>',
|
|
855
|
+
'Group key → opened issue number, as JSON or a path to a JSON file. Required by --wire-edges.',
|
|
856
|
+
],
|
|
738
857
|
['--glob <pattern>', 'Override the audit-results glob.'],
|
|
739
858
|
['--severity <level>', 'Lowest severity to include (high|medium|low).'],
|
|
740
859
|
['--ledger <path>', 'Path to the dedup ledger.'],
|