mandrel 2.30.0 → 2.32.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 +4 -4
- package/.agents/docs/agentrc-reference.json +61 -57
- package/.agents/docs/configuration.md +274 -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/ci-remediation.md +44 -1
- 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 +0 -1
- package/.agents/schemas/agentrc.schema.json +1939 -1400
- 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 +7 -29
- package/.agents/scripts/apply-quality-bootstrap.js +27 -34
- 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 +136 -0
- package/.agents/scripts/check-lifecycle-lint.js +36 -112
- 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 +0 -1
- 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/temp-paths.js +6 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +237 -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/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/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-entry-sync.js +469 -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 +6 -0
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +0 -1
- package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
- package/.agents/scripts/lib/orchestration/resolve-stories.js +5 -15
- 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/push.js +17 -2
- 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 +65 -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-sizing.js +1 -1
- 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/story-body.js +12 -59
- 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/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/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 +0 -2
- 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/update-dead-exports-baseline.js +321 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
- package/.agents/skills/skills.index.json +2 -12
- package/.agents/skills/stack/qa/playwright/SKILL.md +48 -0
- package/.agents/workflows/audit-documentation.md +5 -6
- package/.agents/workflows/audit-to-stories.md +2 -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 +2 -1
- package/.agents/workflows/helpers/deliver-story-reference.md +27 -16
- 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 +49 -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 +12 -3
- 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,31 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* .agents/scripts/generate-config-docs.js —
|
|
3
|
+
* .agents/scripts/generate-config-docs.js — the `.agentrc` config surface
|
|
4
|
+
* generator (Story #5007).
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* **One annotated source, three generated artifacts.** The runtime AJV schema
|
|
7
|
+
* (`AGENTRC_SCHEMA`, composed from `lib/config-settings-schema*.js` and
|
|
8
|
+
* `lib/config/gates/*`) is the single hand-authored enumeration of the
|
|
9
|
+
* `.agentrc.json` surface. `description` and `default` annotations live on
|
|
10
|
+
* those literals — AJV ignores both — and this generator emits everything
|
|
11
|
+
* downstream of them:
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
13
|
+
* 1. `.agents/schemas/agentrc.schema.json` — the JSON-Schema mirror every
|
|
14
|
+
* consumer `.agentrc.json` points `$schema` at. Serialized 2020-12,
|
|
15
|
+
* fully inlined (no `$defs`): it IS the runtime schema, so the class of
|
|
16
|
+
* bug where a key exists in the mirror but not in the runtime AJV — and
|
|
17
|
+
* a consumer's whole config is therefore dead on arrival (Epic #4131) —
|
|
18
|
+
* cannot be expressed any more.
|
|
19
|
+
* 2. `.agents/docs/agentrc-reference.json` — the defaults inventory
|
|
20
|
+
* `lib/config/defaults.js` reads for `mandrel explain` and the
|
|
21
|
+
* sync-agentrc redundancy advisory. Built from the `default`
|
|
22
|
+
* annotations: a node carrying one contributes its value verbatim and is
|
|
23
|
+
* not descended into; a node carrying none contributes nothing.
|
|
24
|
+
* 3. The bounded key-table region inside `.agents/docs/configuration.md`,
|
|
25
|
+
* delimited by:
|
|
11
26
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
27
|
+
* <!-- BEGIN GENERATED:agentrc -->
|
|
28
|
+
* ...generated tables...
|
|
29
|
+
* <!-- END GENERATED:agentrc -->
|
|
14
30
|
*
|
|
15
|
-
*
|
|
31
|
+
* One Markdown section per top-level schema key, each table columned
|
|
32
|
+
* `| Key | Required | Type | Default | Description |`, with nested
|
|
33
|
+
* properties flattened into dot-paths (`paths.agentRoot`,
|
|
34
|
+
* `branchProtection.requiredChecks[]`).
|
|
16
35
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* render `—`.
|
|
36
|
+
* Until this Story the first two were hand-maintained alongside the runtime
|
|
37
|
+
* schema and reconciled by two parity suites; those suites are now
|
|
38
|
+
* generator-fidelity checks.
|
|
21
39
|
*
|
|
22
40
|
* Modes:
|
|
23
|
-
* (default) —
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
41
|
+
* (default) — rewrite any artifact whose content is stale.
|
|
42
|
+
* --check — exit 0 when all three are current, exit 1 naming the stale
|
|
43
|
+
* ones. Wired into `npm run docs:check`, hence `npm run lint`.
|
|
44
|
+
*
|
|
45
|
+
* **Whitespace is not content.** The two JSON artifacts are re-formatted by
|
|
46
|
+
* Biome via lint-staged after they are written, so comparing raw bytes would
|
|
47
|
+
* make the check fail on formatting alone. Both comparison and write go
|
|
48
|
+
* through {@link canonicalJson}: parse, re-serialize, compare. That is
|
|
49
|
+
* insensitive to whitespace and *sensitive* to key order, which is what
|
|
50
|
+
* actually matters — key order drives the doc-table order and the ordering a
|
|
51
|
+
* consumer's editor offers completions in.
|
|
29
52
|
*
|
|
30
53
|
* Per `.agents/rules/orchestration-error-handling.md`, unrecoverable
|
|
31
54
|
* failures surface via `throw new Error(...)` so `runAsCli` can map the
|
|
@@ -37,6 +60,7 @@ import path from 'node:path';
|
|
|
37
60
|
import { fileURLToPath } from 'node:url';
|
|
38
61
|
import { parseArgs } from 'node:util';
|
|
39
62
|
import { runAsCli } from './lib/cli-utils.js';
|
|
63
|
+
import { AGENTRC_SCHEMA } from './lib/config-settings-schema.js';
|
|
40
64
|
import { Logger } from './lib/Logger.js';
|
|
41
65
|
|
|
42
66
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -48,103 +72,139 @@ const SCHEMA_PATH = path.join(
|
|
|
48
72
|
'schemas',
|
|
49
73
|
'agentrc.schema.json',
|
|
50
74
|
);
|
|
75
|
+
const REFERENCE_PATH = path.join(
|
|
76
|
+
PROJECT_ROOT,
|
|
77
|
+
'.agents',
|
|
78
|
+
'docs',
|
|
79
|
+
'agentrc-reference.json',
|
|
80
|
+
);
|
|
51
81
|
const DOC_PATH = path.join(PROJECT_ROOT, '.agents', 'docs', 'configuration.md');
|
|
52
82
|
const REGION_BEGIN = '<!-- BEGIN GENERATED:agentrc -->';
|
|
53
83
|
const REGION_END = '<!-- END GENERATED:agentrc -->';
|
|
54
84
|
|
|
85
|
+
/** Envelope keys prepended to the serialized runtime schema. */
|
|
86
|
+
const MIRROR_ENVELOPE = {
|
|
87
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
88
|
+
$id: 'https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/agentrc.schema.json',
|
|
89
|
+
title: 'Mandrel .agentrc',
|
|
90
|
+
description:
|
|
91
|
+
'GENERATED — do not edit. Emitted by `node .agents/scripts/generate-config-docs.js` from the runtime AJV schema in `.agents/scripts/lib/config-settings-schema.js` (plus its `-delivery` / `-quality` / `config/gates/*` modules), which is the single source of truth for the `.agentrc.json` surface. This file exists for editor tooling and human readers; because it is a serialization of the runtime schema rather than a hand-kept mirror, the two cannot disagree. Edit the annotated schema literals and re-run `npm run docs:gen`.',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** `$schema` pointer written into the generated defaults inventory. */
|
|
95
|
+
const REFERENCE_SCHEMA_POINTER = '../schemas/agentrc.schema.json';
|
|
96
|
+
|
|
55
97
|
// Order matters — drives the per-section emission sequence.
|
|
56
|
-
const TOP_LEVEL_KEYS = ['project', 'github', 'planning', 'delivery'];
|
|
98
|
+
const TOP_LEVEL_KEYS = ['project', 'github', 'planning', 'delivery', 'qa'];
|
|
57
99
|
|
|
58
100
|
/**
|
|
59
|
-
*
|
|
101
|
+
* Canonical JSON text for comparison and for writing. Key order is preserved
|
|
102
|
+
* (and therefore compared); whitespace is normalized away.
|
|
60
103
|
*
|
|
61
|
-
* @param {
|
|
62
|
-
* @returns {
|
|
104
|
+
* @param {unknown} value
|
|
105
|
+
* @returns {string}
|
|
63
106
|
*/
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
107
|
+
function canonicalJson(value) {
|
|
108
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Read a JSON artifact and return its canonical text, or `null` when the file
|
|
113
|
+
* is absent (first generation) or unparseable (a hand-mangled artifact is
|
|
114
|
+
* treated as stale, not as a crash).
|
|
115
|
+
*
|
|
116
|
+
* @param {string} file
|
|
117
|
+
* @returns {string | null}
|
|
118
|
+
*/
|
|
119
|
+
function readCanonicalJson(file) {
|
|
120
|
+
if (!fs.existsSync(file)) return null;
|
|
74
121
|
try {
|
|
75
|
-
return JSON.parse(
|
|
76
|
-
} catch
|
|
77
|
-
|
|
122
|
+
return canonicalJson(JSON.parse(fs.readFileSync(file, 'utf8')));
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
78
125
|
}
|
|
79
126
|
}
|
|
80
127
|
|
|
81
128
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
129
|
+
* Build the shipped JSON-Schema mirror: the 2020-12 envelope followed by the
|
|
130
|
+
* runtime schema verbatim.
|
|
131
|
+
*
|
|
132
|
+
* The runtime schema is a plain, cycle-free object literal (no RegExp or
|
|
133
|
+
* function values), so `structuredClone` is a faithful serialization. Shared
|
|
134
|
+
* sub-schema objects — `TOLERANCE_SCHEMA` and friends, referenced by several
|
|
135
|
+
* gates — are inlined at each use rather than hoisted into `$defs`. The
|
|
136
|
+
* inlined document is smaller than the hand-maintained `$defs` mirror it
|
|
137
|
+
* replaces, and it removes the naming heuristic a hoisting pass would need.
|
|
84
138
|
*
|
|
85
|
-
* @param {object} schema
|
|
86
|
-
* @param {string} ref The `$ref` value.
|
|
139
|
+
* @param {object} schema
|
|
87
140
|
* @returns {object}
|
|
88
141
|
*/
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
142
|
+
function buildMirrorSchema(schema) {
|
|
143
|
+
return { ...MIRROR_ENVELOPE, ...structuredClone(schema) };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Collect the `default` annotations under `node` into a nested plain object.
|
|
148
|
+
*
|
|
149
|
+
* A node carrying `default` contributes that value verbatim and is NOT
|
|
150
|
+
* descended into — that is what lets an object-shaped or array-shaped default
|
|
151
|
+
* (`github.branchProtection.requiredChecks`, `qa.environments`) be declared in
|
|
152
|
+
* one place. A properties-bearing node with no `default` contributes an object
|
|
153
|
+
* built from whichever children contributed something, or nothing at all when
|
|
154
|
+
* none did.
|
|
155
|
+
*
|
|
156
|
+
* @param {object} node
|
|
157
|
+
* @returns {unknown} The built value, or `undefined` for "contributes nothing".
|
|
158
|
+
*/
|
|
159
|
+
function collectDefaults(node) {
|
|
160
|
+
if (!node || typeof node !== 'object') return undefined;
|
|
161
|
+
if (Object.hasOwn(node, 'default')) return structuredClone(node.default);
|
|
162
|
+
if (!node.properties) return undefined;
|
|
163
|
+
const out = {};
|
|
164
|
+
for (const [key, child] of Object.entries(node.properties)) {
|
|
165
|
+
const built = collectDefaults(child);
|
|
166
|
+
if (built !== undefined) out[key] = built;
|
|
97
167
|
}
|
|
98
|
-
return
|
|
168
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Build the defaults inventory shipped as `.agents/docs/agentrc-reference.json`.
|
|
173
|
+
*
|
|
174
|
+
* @param {object} schema
|
|
175
|
+
* @returns {object}
|
|
176
|
+
*/
|
|
177
|
+
function buildReferenceInventory(schema) {
|
|
178
|
+
return {
|
|
179
|
+
$schema: REFERENCE_SCHEMA_POINTER,
|
|
180
|
+
...(collectDefaults(schema) ?? {}),
|
|
181
|
+
};
|
|
99
182
|
}
|
|
100
183
|
|
|
101
184
|
/**
|
|
102
|
-
* Collapse an `allOf` envelope down
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* carries the type for documentation purposes.
|
|
185
|
+
* Collapse an `allOf` envelope down onto its base node. The schema uses
|
|
186
|
+
* `allOf` only to hang a conditional (`if`/`then`) constraint off a block, so
|
|
187
|
+
* the merged view carries the base type for documentation purposes.
|
|
106
188
|
*
|
|
107
|
-
* @param {object}
|
|
108
|
-
* @param {object} node The schema node to flatten.
|
|
189
|
+
* @param {object} node The schema node to flatten.
|
|
109
190
|
* @returns {object}
|
|
110
191
|
*/
|
|
111
|
-
function flattenAllOf(
|
|
192
|
+
function flattenAllOf(node) {
|
|
112
193
|
if (!node || typeof node !== 'object') return node;
|
|
113
194
|
if (!Array.isArray(node.allOf)) return node;
|
|
114
195
|
const merged = { ...node };
|
|
115
196
|
delete merged.allOf;
|
|
116
197
|
for (const member of node.allOf) {
|
|
117
|
-
const
|
|
118
|
-
for (const [key, value] of Object.entries(resolved)) {
|
|
198
|
+
for (const [key, value] of Object.entries(member)) {
|
|
119
199
|
if (merged[key] === undefined) merged[key] = value;
|
|
120
200
|
}
|
|
121
201
|
}
|
|
122
202
|
return merged;
|
|
123
203
|
}
|
|
124
204
|
|
|
125
|
-
/**
|
|
126
|
-
* Resolve a property node down to its first non-ref form. Returns the
|
|
127
|
-
* resolved node alongside the original ref name (if any) so callers can
|
|
128
|
-
* detect when to recurse into a referenced object def.
|
|
129
|
-
*
|
|
130
|
-
* @param {object} schema
|
|
131
|
-
* @param {object} node
|
|
132
|
-
* @returns {{ node: object, refName: string | null }}
|
|
133
|
-
*/
|
|
134
|
-
function resolveNode(schema, node) {
|
|
135
|
-
if (node && typeof node === 'object' && typeof node.$ref === 'string') {
|
|
136
|
-
const refName = node.$ref.startsWith('#/$defs/')
|
|
137
|
-
? node.$ref.slice('#/$defs/'.length)
|
|
138
|
-
: null;
|
|
139
|
-
return { node: resolveRef(schema, node.$ref), refName };
|
|
140
|
-
}
|
|
141
|
-
return { node, refName: null };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
205
|
/**
|
|
145
206
|
* Render the "Type" cell for an `array`-typed node by inspecting its `items`
|
|
146
|
-
* schema
|
|
147
|
-
* `array<RefName>`, an enum item renders `array<enum>`, a typed item renders
|
|
207
|
+
* schema: an enum item renders `array<enum>`, a typed item renders
|
|
148
208
|
* `array<type>`, and anything else collapses to a bare `array`.
|
|
149
209
|
*
|
|
150
210
|
* @param {object} flat Flattened array node.
|
|
@@ -153,12 +213,6 @@ function resolveNode(schema, node) {
|
|
|
153
213
|
function renderArrayType(flat) {
|
|
154
214
|
const items = flat.items;
|
|
155
215
|
if (items && typeof items === 'object') {
|
|
156
|
-
if (items.$ref) {
|
|
157
|
-
const refName = items.$ref.startsWith('#/$defs/')
|
|
158
|
-
? items.$ref.slice('#/$defs/'.length)
|
|
159
|
-
: items.$ref;
|
|
160
|
-
return `\`array<${refName}>\``;
|
|
161
|
-
}
|
|
162
216
|
if (Array.isArray(items.enum)) {
|
|
163
217
|
return `\`array<enum>\``;
|
|
164
218
|
}
|
|
@@ -194,16 +248,24 @@ function renderObjectType(flat) {
|
|
|
194
248
|
* row here rather than another nested branch.
|
|
195
249
|
*
|
|
196
250
|
* Order is load-bearing — `oneOf` and `enum` are matched before the plain
|
|
197
|
-
* `type` rules
|
|
251
|
+
* `type` rules.
|
|
198
252
|
*
|
|
199
253
|
* @type {Array<{ when: (flat: object) => boolean, render: (flat: object) => string }>}
|
|
200
254
|
*/
|
|
201
255
|
const TYPE_RULES = [
|
|
202
|
-
// The only oneOf in the schema is `listOrExtenderOfStrings`.
|
|
203
256
|
{
|
|
204
|
-
|
|
257
|
+
// The list-or-extender union: a plain `string[]` (replace) or an
|
|
258
|
+
// `{ append?, prepend? }` object that deep-merges with the framework list.
|
|
259
|
+
when: (flat) =>
|
|
260
|
+
Array.isArray(flat.oneOf) &&
|
|
261
|
+
flat.oneOf.some((m) => m?.properties?.append || m?.properties?.prepend),
|
|
205
262
|
render: () => '`string[]` or `{ append?, prepend? }`',
|
|
206
263
|
},
|
|
264
|
+
{
|
|
265
|
+
when: (flat) => Array.isArray(flat.oneOf),
|
|
266
|
+
render: (flat) =>
|
|
267
|
+
`one of: ${flat.oneOf.map((m) => `\`${m?.type ?? '?'}\``).join(', ')}`,
|
|
268
|
+
},
|
|
207
269
|
{
|
|
208
270
|
when: (flat) => Array.isArray(flat.enum),
|
|
209
271
|
render: (flat) =>
|
|
@@ -228,32 +290,31 @@ const TYPE_RULES = [
|
|
|
228
290
|
];
|
|
229
291
|
|
|
230
292
|
/**
|
|
231
|
-
* Render the "Type" cell for a schema node.
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
* variants. Anything else falls through to a `?` so missing coverage is
|
|
235
|
-
* visible rather than silently wrong.
|
|
293
|
+
* Render the "Type" cell for a schema node. Anything the table does not match
|
|
294
|
+
* falls through to a `?` so missing coverage is visible rather than silently
|
|
295
|
+
* wrong.
|
|
236
296
|
*
|
|
237
|
-
* @param {object} schema
|
|
238
297
|
* @param {object} node
|
|
239
298
|
* @returns {string}
|
|
240
299
|
*/
|
|
241
|
-
function renderType(
|
|
300
|
+
function renderType(node) {
|
|
242
301
|
if (!node || typeof node !== 'object') return '?';
|
|
243
|
-
const flat = flattenAllOf(
|
|
302
|
+
const flat = flattenAllOf(node);
|
|
244
303
|
const rule = TYPE_RULES.find((r) => r.when(flat));
|
|
245
304
|
return rule ? rule.render(flat) : '?';
|
|
246
305
|
}
|
|
247
306
|
|
|
248
307
|
/**
|
|
249
|
-
* Render the "Default" cell.
|
|
250
|
-
* em dash — the
|
|
308
|
+
* Render the "Default" cell. Nodes without an explicit `default` annotation
|
|
309
|
+
* get an em dash — see the annotation contract in `config-settings-schema.js`
|
|
310
|
+
* for why a key can have a runtime default and no annotation.
|
|
251
311
|
*
|
|
252
|
-
* @param {
|
|
312
|
+
* @param {object} node
|
|
253
313
|
* @returns {string}
|
|
254
314
|
*/
|
|
255
|
-
function renderDefault(
|
|
256
|
-
if (
|
|
315
|
+
function renderDefault(node) {
|
|
316
|
+
if (!node || !Object.hasOwn(node, 'default')) return '—';
|
|
317
|
+
const value = node.default;
|
|
257
318
|
if (value === null) return '`null`';
|
|
258
319
|
if (typeof value === 'string') return `\`"${value}"\``;
|
|
259
320
|
if (typeof value === 'boolean' || typeof value === 'number') {
|
|
@@ -282,11 +343,10 @@ function escapeCell(text) {
|
|
|
282
343
|
* Returns `null` when `flat` is not a properties-bearing object, so the
|
|
283
344
|
* caller can fall through to the next row shape.
|
|
284
345
|
*
|
|
285
|
-
* @param {object} schema
|
|
286
346
|
* @param {{flat: object, keyPath: string, pathParts: string[], propName: string, isRequired: boolean, description: string}} ctx
|
|
287
347
|
* @returns {Array<object> | null}
|
|
288
348
|
*/
|
|
289
|
-
function nestedObjectRows(
|
|
349
|
+
function nestedObjectRows(ctx) {
|
|
290
350
|
const { flat, keyPath, pathParts, propName, isRequired, description } = ctx;
|
|
291
351
|
if (flat.type !== 'object' || !flat.properties) return null;
|
|
292
352
|
const childRequired = new Set(
|
|
@@ -297,10 +357,10 @@ function nestedObjectRows(schema, ctx) {
|
|
|
297
357
|
key: keyPath,
|
|
298
358
|
required: isRequired ? 'Yes' : 'No',
|
|
299
359
|
type: '`object`',
|
|
300
|
-
def: renderDefault(flat
|
|
360
|
+
def: renderDefault(flat),
|
|
301
361
|
description: description || 'Nested configuration block.',
|
|
302
362
|
},
|
|
303
|
-
...flattenObject(
|
|
363
|
+
...flattenObject(flat, [...pathParts, propName], childRequired),
|
|
304
364
|
];
|
|
305
365
|
}
|
|
306
366
|
|
|
@@ -309,28 +369,24 @@ function nestedObjectRows(schema, ctx) {
|
|
|
309
369
|
* describing the item shape in the Description cell. Returns `null` when the
|
|
310
370
|
* property is not an array whose items are a properties-bearing object.
|
|
311
371
|
*
|
|
312
|
-
* @param {object} schema
|
|
313
372
|
* @param {{flat: object, keyPath: string, isRequired: boolean, description: string}} ctx
|
|
314
373
|
* @returns {Array<object> | null}
|
|
315
374
|
*/
|
|
316
|
-
function arrayOfObjectsRows(
|
|
375
|
+
function arrayOfObjectsRows(ctx) {
|
|
317
376
|
const { flat, keyPath, isRequired, description } = ctx;
|
|
318
377
|
if (flat.type !== 'array' || !flat.items) return null;
|
|
319
|
-
const
|
|
378
|
+
const itemNode = flat.items;
|
|
320
379
|
if (!itemNode || itemNode.type !== 'object' || !itemNode.properties) {
|
|
321
380
|
return null;
|
|
322
381
|
}
|
|
323
382
|
const itemKeys = Object.keys(itemNode.properties).join(', ');
|
|
324
|
-
const
|
|
325
|
-
const desc =
|
|
326
|
-
(description ? `${description} ` : '') +
|
|
327
|
-
`Each item${suffix} has: ${itemKeys}.`;
|
|
383
|
+
const desc = `${description ? `${description} ` : ''}Each item has: ${itemKeys}.`;
|
|
328
384
|
return [
|
|
329
385
|
{
|
|
330
386
|
key: `${keyPath}[]`,
|
|
331
387
|
required: isRequired ? 'Yes' : 'No',
|
|
332
|
-
type: renderType(
|
|
333
|
-
def: renderDefault(flat
|
|
388
|
+
type: renderType(flat),
|
|
389
|
+
def: renderDefault(flat),
|
|
334
390
|
description: desc,
|
|
335
391
|
},
|
|
336
392
|
];
|
|
@@ -341,66 +397,61 @@ function arrayOfObjectsRows(schema, ctx) {
|
|
|
341
397
|
* it is the fallthrough shape when neither the nested-object nor the
|
|
342
398
|
* array-of-objects builder applied.
|
|
343
399
|
*
|
|
344
|
-
* @param {object} schema
|
|
345
400
|
* @param {{flat: object, keyPath: string, isRequired: boolean, description: string}} ctx
|
|
346
401
|
* @returns {Array<object>}
|
|
347
402
|
*/
|
|
348
|
-
function leafRow(
|
|
403
|
+
function leafRow(ctx) {
|
|
349
404
|
const { flat, keyPath, isRequired, description } = ctx;
|
|
350
405
|
return [
|
|
351
406
|
{
|
|
352
407
|
key: keyPath,
|
|
353
408
|
required: isRequired ? 'Yes' : 'No',
|
|
354
|
-
type: renderType(
|
|
355
|
-
def: renderDefault(flat
|
|
409
|
+
type: renderType(flat),
|
|
410
|
+
def: renderDefault(flat),
|
|
356
411
|
description: description || '—',
|
|
357
412
|
},
|
|
358
413
|
];
|
|
359
414
|
}
|
|
360
415
|
|
|
361
416
|
// Ordered row-shape builders for one property. The loop in flattenObject
|
|
362
|
-
// returns the first builder that yields rows (non-null)
|
|
363
|
-
//
|
|
364
|
-
// scalar leaf as the always-matching fallthrough.
|
|
417
|
+
// returns the first builder that yields rows (non-null): nested-object first,
|
|
418
|
+
// array-of-objects next, scalar leaf as the always-matching fallthrough.
|
|
365
419
|
const ROW_BUILDERS = [nestedObjectRows, arrayOfObjectsRows, leafRow];
|
|
366
420
|
|
|
367
421
|
/**
|
|
368
|
-
* Flatten one object-typed schema node into table rows. Recurses into
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
* individual rows.
|
|
422
|
+
* Flatten one object-typed schema node into table rows. Recurses into nested
|
|
423
|
+
* `object` properties so dot-paths like `paths.agentRoot` and
|
|
424
|
+
* `branchProtection.requiredChecks` show up as individual rows.
|
|
372
425
|
*
|
|
373
|
-
* Arrays of objects (`requiredChecks[]`, `routes[]`, `bundles[]`) are
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
426
|
+
* Arrays of objects (`requiredChecks[]`, `routes[]`, `bundles[]`) are emitted
|
|
427
|
+
* as a single row whose Key column carries a `[]` suffix; the item shape is
|
|
428
|
+
* captured in the Description cell. This keeps the output legible without
|
|
429
|
+
* exploding into per-item-property rows.
|
|
377
430
|
*
|
|
378
|
-
* @param {object} schema Root schema (for ref resolution).
|
|
379
431
|
* @param {object} node Schema node to flatten.
|
|
380
432
|
* @param {string[]} pathParts Dot-path accumulator.
|
|
381
433
|
* @param {Set<string>} required Required-property names on the parent.
|
|
382
434
|
* @returns {Array<{key:string, required:string, type:string, def:string, description:string}>}
|
|
383
435
|
*/
|
|
384
|
-
function flattenObject(
|
|
436
|
+
function flattenObject(node, pathParts, required) {
|
|
385
437
|
const rows = [];
|
|
386
438
|
const properties = node.properties || {};
|
|
387
439
|
const localRequired = new Set(
|
|
388
440
|
Array.isArray(node.required) ? node.required : [],
|
|
389
441
|
);
|
|
390
442
|
|
|
391
|
-
for (const [propName,
|
|
392
|
-
const
|
|
393
|
-
const flat = flattenAllOf(schema, child);
|
|
443
|
+
for (const [propName, child] of Object.entries(properties)) {
|
|
444
|
+
const flat = flattenAllOf(child);
|
|
394
445
|
const ctx = {
|
|
395
446
|
flat,
|
|
396
447
|
keyPath: [...pathParts, propName].join('.'),
|
|
397
448
|
pathParts,
|
|
398
449
|
propName,
|
|
399
450
|
isRequired: required.has(propName) || localRequired.has(propName),
|
|
400
|
-
description: flat.description ||
|
|
451
|
+
description: flat.description || '',
|
|
401
452
|
};
|
|
402
453
|
for (const build of ROW_BUILDERS) {
|
|
403
|
-
const built = build(
|
|
454
|
+
const built = build(ctx);
|
|
404
455
|
if (built !== null) {
|
|
405
456
|
rows.push(...built);
|
|
406
457
|
break;
|
|
@@ -419,13 +470,11 @@ function flattenObject(schema, node, pathParts, required) {
|
|
|
419
470
|
* @returns {string}
|
|
420
471
|
*/
|
|
421
472
|
function renderSection(schema, topKey) {
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
if (!rawNode) {
|
|
473
|
+
const node = (schema.properties || {})[topKey];
|
|
474
|
+
if (!node) {
|
|
425
475
|
throw new Error(`Top-level key "${topKey}" missing from schema.properties`);
|
|
426
476
|
}
|
|
427
|
-
const
|
|
428
|
-
const flat = flattenAllOf(schema, node);
|
|
477
|
+
const flat = flattenAllOf(node);
|
|
429
478
|
|
|
430
479
|
if (flat.type !== 'object' || !flat.properties) {
|
|
431
480
|
throw new Error(
|
|
@@ -441,7 +490,7 @@ function renderSection(schema, topKey) {
|
|
|
441
490
|
Array.isArray(flat.required) ? flat.required : [],
|
|
442
491
|
);
|
|
443
492
|
|
|
444
|
-
const rows = flattenObject(
|
|
493
|
+
const rows = flattenObject(flat, [], childRequired);
|
|
445
494
|
const header = `### \`${topKey}\` ${sectionRequired ? '(required)' : '(optional)'}`;
|
|
446
495
|
const tableHeader = '| Key | Required | Type | Default | Description |';
|
|
447
496
|
const tableSep = '| --- | --- | --- | --- | --- |';
|
|
@@ -467,10 +516,13 @@ function renderSection(schema, topKey) {
|
|
|
467
516
|
function renderRegion(schema) {
|
|
468
517
|
const blocks = [
|
|
469
518
|
'',
|
|
470
|
-
'> Generated by `node .agents/scripts/generate-config-docs.js` from',
|
|
471
|
-
|
|
472
|
-
'>
|
|
473
|
-
'>
|
|
519
|
+
'> Generated by `node .agents/scripts/generate-config-docs.js` from the',
|
|
520
|
+
'> runtime AJV schema in',
|
|
521
|
+
'> [`.agents/scripts/lib/config-settings-schema.js`](../scripts/lib/config-settings-schema.js).',
|
|
522
|
+
'> Edit the `description` / `default` annotations on those schema literals',
|
|
523
|
+
'> and re-run `npm run docs:gen` — do not hand-edit this region, and do not',
|
|
524
|
+
'> hand-edit `agentrc.schema.json` or `agentrc-reference.json` either: both',
|
|
525
|
+
'> are emitted by the same generator.',
|
|
474
526
|
'',
|
|
475
527
|
];
|
|
476
528
|
for (const key of TOP_LEVEL_KEYS) {
|
|
@@ -541,21 +593,53 @@ function spliceRegion(original, body) {
|
|
|
541
593
|
}
|
|
542
594
|
|
|
543
595
|
/**
|
|
544
|
-
* Build
|
|
596
|
+
* Build every generated artifact from `schema` and pair each with what is on
|
|
597
|
+
* disk today.
|
|
598
|
+
*
|
|
599
|
+
* The JSON artifacts compare canonically (see the module header); the
|
|
600
|
+
* Markdown artifact compares raw, because its region is spliced into
|
|
601
|
+
* hand-authored prose that must survive byte-for-byte.
|
|
545
602
|
*
|
|
546
|
-
* @param {string
|
|
547
|
-
*
|
|
548
|
-
* @returns {{
|
|
603
|
+
* @param {{ schema?: object, schemaPath?: string, referencePath?: string,
|
|
604
|
+
* docPath?: string }} [opts]
|
|
605
|
+
* @returns {Array<{ name: string, file: string, generated: string,
|
|
606
|
+
* current: string | null, stale: boolean }>}
|
|
549
607
|
*/
|
|
550
|
-
function
|
|
608
|
+
function buildArtifacts(opts = {}) {
|
|
609
|
+
const {
|
|
610
|
+
schema = AGENTRC_SCHEMA,
|
|
611
|
+
schemaPath = SCHEMA_PATH,
|
|
612
|
+
referencePath = REFERENCE_PATH,
|
|
613
|
+
docPath = DOC_PATH,
|
|
614
|
+
} = opts;
|
|
615
|
+
|
|
551
616
|
if (!fs.existsSync(docPath)) {
|
|
552
617
|
throw new Error(`Target doc not found: ${docPath}`);
|
|
553
618
|
}
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
619
|
+
const docOriginal = fs.readFileSync(docPath, 'utf8');
|
|
620
|
+
|
|
621
|
+
const artifacts = [
|
|
622
|
+
{
|
|
623
|
+
name: 'mirror schema',
|
|
624
|
+
file: schemaPath,
|
|
625
|
+
generated: canonicalJson(buildMirrorSchema(schema)),
|
|
626
|
+
current: readCanonicalJson(schemaPath),
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
name: 'defaults inventory',
|
|
630
|
+
file: referencePath,
|
|
631
|
+
generated: canonicalJson(buildReferenceInventory(schema)),
|
|
632
|
+
current: readCanonicalJson(referencePath),
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
name: 'configuration.md key table',
|
|
636
|
+
file: docPath,
|
|
637
|
+
generated: spliceRegion(docOriginal, renderRegion(schema)),
|
|
638
|
+
current: docOriginal,
|
|
639
|
+
},
|
|
640
|
+
];
|
|
641
|
+
for (const a of artifacts) a.stale = a.generated !== a.current;
|
|
642
|
+
return artifacts;
|
|
559
643
|
}
|
|
560
644
|
|
|
561
645
|
/**
|
|
@@ -570,39 +654,47 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
570
654
|
allowPositionals: false,
|
|
571
655
|
});
|
|
572
656
|
|
|
573
|
-
const
|
|
657
|
+
const artifacts = buildArtifacts();
|
|
658
|
+
const stale = artifacts.filter((a) => a.stale);
|
|
659
|
+
const rel = (f) => path.relative(PROJECT_ROOT, f);
|
|
574
660
|
|
|
575
661
|
if (values.check) {
|
|
576
|
-
if (
|
|
662
|
+
if (stale.length === 0) {
|
|
577
663
|
Logger.info(
|
|
578
|
-
`generate-config-docs: ${
|
|
664
|
+
`generate-config-docs: all ${artifacts.length} generated config artifacts are up to date.`,
|
|
579
665
|
);
|
|
580
666
|
return;
|
|
581
667
|
}
|
|
582
|
-
|
|
583
|
-
`${
|
|
584
|
-
|
|
585
|
-
|
|
668
|
+
throw new Error(
|
|
669
|
+
`${stale.length} generated config artifact(s) drifted from the runtime schema: ` +
|
|
670
|
+
`${stale.map((a) => `${a.name} (${rel(a.file)})`).join(', ')}. ` +
|
|
671
|
+
'Run `node .agents/scripts/generate-config-docs.js` to regenerate.',
|
|
672
|
+
);
|
|
586
673
|
}
|
|
587
674
|
|
|
588
|
-
if (
|
|
675
|
+
if (stale.length === 0) {
|
|
589
676
|
Logger.info(
|
|
590
|
-
|
|
677
|
+
'generate-config-docs: every generated config artifact already current — no write.',
|
|
591
678
|
);
|
|
592
679
|
return;
|
|
593
680
|
}
|
|
594
|
-
|
|
681
|
+
for (const a of stale) {
|
|
682
|
+
fs.writeFileSync(a.file, a.generated, 'utf8');
|
|
683
|
+
}
|
|
595
684
|
Logger.info(
|
|
596
|
-
`generate-config-docs:
|
|
685
|
+
`generate-config-docs: rewrote ${stale.map((a) => rel(a.file)).join(', ')}.`,
|
|
597
686
|
);
|
|
598
687
|
}
|
|
599
688
|
|
|
600
689
|
export {
|
|
601
|
-
|
|
690
|
+
buildArtifacts,
|
|
691
|
+
buildMirrorSchema,
|
|
692
|
+
buildReferenceInventory,
|
|
693
|
+
canonicalJson,
|
|
694
|
+
collectDefaults,
|
|
602
695
|
flattenObject,
|
|
603
696
|
REGION_BEGIN,
|
|
604
697
|
REGION_END,
|
|
605
|
-
readSchema,
|
|
606
698
|
renderRegion,
|
|
607
699
|
renderSection,
|
|
608
700
|
spliceRegion,
|
|
@@ -613,11 +705,11 @@ runAsCli(import.meta.url, main, {
|
|
|
613
705
|
usage: {
|
|
614
706
|
invocation: 'node .agents/scripts/generate-config-docs.js [--check]',
|
|
615
707
|
summary:
|
|
616
|
-
'Regenerate the configuration
|
|
708
|
+
'Regenerate the three .agentrc config artifacts (JSON-Schema mirror, defaults inventory, configuration.md key table) from the runtime AJV schema. Writes only what drifted.',
|
|
617
709
|
flags: [
|
|
618
710
|
[
|
|
619
711
|
'--check',
|
|
620
|
-
'Verify
|
|
712
|
+
'Verify every artifact is current and fail naming the stale ones; write nothing.',
|
|
621
713
|
],
|
|
622
714
|
],
|
|
623
715
|
},
|