@cleocode/contracts 2026.10.27 → 2026.11.1-canary.2
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/dist/.source-stamp.json +4 -0
- package/dist/__tests__/acceptance-gate.test.js +15 -3
- package/dist/__tests__/acceptance-gate.test.js.map +1 -1
- package/dist/__tests__/evidence-atom-schema.test.js +3 -1
- package/dist/__tests__/evidence-atom-schema.test.js.map +1 -1
- package/dist/__tests__/memory-wire-shapes.test.js.map +1 -1
- package/dist/acceptance-gate-schema.d.ts +25 -0
- package/dist/acceptance-gate-schema.d.ts.map +1 -1
- package/dist/acceptance-gate-schema.js +5 -0
- package/dist/acceptance-gate-schema.js.map +1 -1
- package/dist/acceptance-gate.d.ts +8 -0
- package/dist/acceptance-gate.d.ts.map +1 -1
- package/dist/data-accessor.d.ts +7 -0
- package/dist/data-accessor.d.ts.map +1 -1
- package/dist/data-accessor.js.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +198 -0
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/docs/modernize.d.ts +409 -0
- package/dist/docs/modernize.d.ts.map +1 -0
- package/dist/docs/modernize.js +129 -0
- package/dist/docs/modernize.js.map +1 -0
- package/dist/docs-taxonomy.d.ts +6 -0
- package/dist/docs-taxonomy.d.ts.map +1 -1
- package/dist/docs-taxonomy.js +38 -1
- package/dist/docs-taxonomy.js.map +1 -1
- package/dist/done-plan.d.ts +27 -2
- package/dist/done-plan.d.ts.map +1 -1
- package/dist/evidence-atom-schema.d.ts +47 -1
- package/dist/evidence-atom-schema.d.ts.map +1 -1
- package/dist/evidence-atom-schema.js +83 -0
- package/dist/evidence-atom-schema.js.map +1 -1
- package/dist/exit-codes.d.ts +41 -0
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +41 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/invariants/sync-write-invariants.d.ts.map +1 -1
- package/dist/invariants/sync-write-invariants.js +15 -0
- package/dist/invariants/sync-write-invariants.js.map +1 -1
- package/dist/memory/search.d.ts +13 -0
- package/dist/memory/search.d.ts.map +1 -1
- package/dist/merge-close.d.ts +167 -0
- package/dist/merge-close.d.ts.map +1 -0
- package/dist/merge-close.js +16 -0
- package/dist/merge-close.js.map +1 -0
- package/dist/operations/admin.d.ts +6 -0
- package/dist/operations/admin.d.ts.map +1 -1
- package/dist/operations/docs.d.ts +174 -3
- package/dist/operations/docs.d.ts.map +1 -1
- package/dist/operations/docs.js.map +1 -1
- package/dist/operations/worktree.d.ts +63 -0
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/project-context.d.ts +31 -0
- package/dist/project-context.d.ts.map +1 -1
- package/dist/release/authorization.d.ts +46 -0
- package/dist/release/authorization.d.ts.map +1 -0
- package/dist/release/authorization.js +10 -0
- package/dist/release/authorization.js.map +1 -0
- package/dist/review-verdict.d.ts +125 -0
- package/dist/review-verdict.d.ts.map +1 -0
- package/dist/review-verdict.js +14 -0
- package/dist/review-verdict.js.map +1 -0
- package/dist/session-journal.d.ts.map +1 -1
- package/dist/session-journal.js +7 -1
- package/dist/session-journal.js.map +1 -1
- package/dist/task-record.d.ts +6 -1
- package/dist/task-record.d.ts.map +1 -1
- package/dist/task.d.ts +130 -3
- package/dist/task.d.ts.map +1 -1
- package/package.json +2 -2
- package/schemas/acceptance-gate.schema.json +24 -0
- package/schemas/task.schema.json +24 -0
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/__tests__/acceptance-gate.test.ts +16 -3
- package/src/__tests__/evidence-atom-schema.test.ts +3 -1
- package/src/__tests__/memory-wire-shapes.test.ts +2 -0
- package/src/acceptance-gate-schema.ts +5 -0
- package/src/acceptance-gate.ts +9 -0
- package/src/data-accessor.ts +8 -0
- package/src/dispatch/operations-registry.ts +207 -0
- package/src/docs/modernize.ts +376 -0
- package/src/docs-taxonomy.ts +44 -1
- package/src/done-plan.ts +27 -2
- package/src/evidence-atom-schema.ts +97 -0
- package/src/exit-codes.ts +41 -0
- package/src/index.ts +51 -0
- package/src/invariants/sync-write-invariants.ts +16 -0
- package/src/memory/search.ts +10 -0
- package/src/merge-close.ts +168 -0
- package/src/operations/admin.ts +6 -0
- package/src/operations/docs.ts +180 -4
- package/src/operations/worktree.ts +66 -0
- package/src/project-context.ts +33 -0
- package/src/release/authorization.ts +48 -0
- package/src/review-verdict.ts +122 -0
- package/src/session-journal.ts +7 -1
- package/src/task-record.ts +6 -1
- package/src/task.ts +124 -3
|
@@ -193,12 +193,14 @@ describe('CommandGate schema', () => {
|
|
|
193
193
|
it('round-trips a minimal command gate', () => {
|
|
194
194
|
const input = {
|
|
195
195
|
kind: 'command' as const,
|
|
196
|
-
cmd: 'cleo
|
|
196
|
+
cmd: 'cleo',
|
|
197
|
+
args: ['doctor'],
|
|
197
198
|
description: 'cleo doctor must exit 0',
|
|
198
199
|
};
|
|
199
200
|
const result = commandGateSchema.parse(input);
|
|
200
201
|
expect(result.kind).toBe('command');
|
|
201
|
-
expect(result.cmd).toBe('cleo
|
|
202
|
+
expect(result.cmd).toBe('cleo');
|
|
203
|
+
expect(result.args).toEqual(['doctor']);
|
|
202
204
|
// exitCode defaults to undefined (not set in schema default)
|
|
203
205
|
expect(result.exitCode).toBeUndefined();
|
|
204
206
|
});
|
|
@@ -370,12 +372,23 @@ describe('acceptanceGateSchema (discriminated union)', () => {
|
|
|
370
372
|
it('routes command gate by kind', () => {
|
|
371
373
|
const result = acceptanceGateSchema.parse({
|
|
372
374
|
kind: 'command',
|
|
373
|
-
cmd: 'pnpm
|
|
375
|
+
cmd: 'pnpm',
|
|
376
|
+
args: ['doctor'],
|
|
374
377
|
description: 'doctor must succeed',
|
|
375
378
|
});
|
|
376
379
|
expect(result.kind).toBe('command');
|
|
377
380
|
});
|
|
378
381
|
|
|
382
|
+
it('parse still accepts a legacy stored command gate whose cmd carries arguments (T14155)', () => {
|
|
383
|
+
// Writes refuse this shape (cleo req add / replace); reading a stored one never does.
|
|
384
|
+
const result = acceptanceGateSchema.parse({
|
|
385
|
+
kind: 'command',
|
|
386
|
+
cmd: 'pnpm doctor',
|
|
387
|
+
description: 'doctor must succeed',
|
|
388
|
+
});
|
|
389
|
+
expect(result.kind === 'command' && result.cmd).toBe('pnpm doctor');
|
|
390
|
+
});
|
|
391
|
+
|
|
379
392
|
it('routes lint gate by kind', () => {
|
|
380
393
|
const result = acceptanceGateSchema.parse({
|
|
381
394
|
kind: 'lint',
|
|
@@ -32,7 +32,7 @@ describe('EvidenceAtomSchema (T10337)', () => {
|
|
|
32
32
|
// Verify the shared constant is in sync with the zod discriminated union.
|
|
33
33
|
// The discriminated union keys are 'commit','files','test-run','qa-run',
|
|
34
34
|
// 'tool','url','note','decision','pr','ci','loc-drop','callsite-coverage',
|
|
35
|
-
// 'satisfies' ('qa-run': T13427).
|
|
35
|
+
// 'satisfies' ('qa-run': T13427), 'deploy' (T14083), 'ci-run' (T14149).
|
|
36
36
|
const expected = [
|
|
37
37
|
'commit',
|
|
38
38
|
'files',
|
|
@@ -44,6 +44,8 @@ describe('EvidenceAtomSchema (T10337)', () => {
|
|
|
44
44
|
'decision',
|
|
45
45
|
'pr',
|
|
46
46
|
'ci',
|
|
47
|
+
'ci-run',
|
|
48
|
+
'deploy',
|
|
47
49
|
'loc-drop',
|
|
48
50
|
'callsite-coverage',
|
|
49
51
|
'satisfies',
|
|
@@ -68,6 +68,7 @@ type _BrainCompactHitShape = {
|
|
|
68
68
|
bm25Score?: number;
|
|
69
69
|
_next?: Record<string, string>;
|
|
70
70
|
scope?: 'project' | 'global';
|
|
71
|
+
docs?: string[];
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
type _AssertBrainCompactHitPinned = AssertEquals1<Equals<BrainCompactHit, _BrainCompactHitShape>>;
|
|
@@ -99,6 +100,7 @@ type _SearchBrainCompactResultShape = {
|
|
|
99
100
|
results: BrainCompactHit[];
|
|
100
101
|
total: number;
|
|
101
102
|
tokensEstimated: number;
|
|
103
|
+
taskDocs?: Array<{ taskId: string; docs: string[] }>;
|
|
102
104
|
};
|
|
103
105
|
|
|
104
106
|
type _AssertSearchResultPinned = AssertEquals1<
|
|
@@ -34,6 +34,11 @@ export const gateBaseSchema = z.object({
|
|
|
34
34
|
advisory: z.boolean().optional(),
|
|
35
35
|
/** Per-gate timeout override in milliseconds. */
|
|
36
36
|
timeoutMs: z.number().int().positive().optional(),
|
|
37
|
+
/** Declared evidence repository the gate runs in (T14078). */
|
|
38
|
+
repo: z
|
|
39
|
+
.string()
|
|
40
|
+
.regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/)
|
|
41
|
+
.optional(),
|
|
37
42
|
});
|
|
38
43
|
|
|
39
44
|
// ─── File assertion schemas ───────────────────────────────────────────────────
|
package/src/acceptance-gate.ts
CHANGED
|
@@ -122,6 +122,15 @@ export interface GateBase {
|
|
|
122
122
|
* covers only the surrounding bookkeeping, never a gate (T12621).
|
|
123
123
|
*/
|
|
124
124
|
timeoutMs?: number;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Name of an evidence repository the project declares in
|
|
128
|
+
* `.cleo/project-context.json` (`evidence.repositories`, T14078): the gate
|
|
129
|
+
* runs in that checkout, its inputs are captured there and it is
|
|
130
|
+
* revalidated there. A name the project does not declare is refused.
|
|
131
|
+
* Absent, the gate runs in the task's evidence tree.
|
|
132
|
+
*/
|
|
133
|
+
repo?: string;
|
|
125
134
|
}
|
|
126
135
|
|
|
127
136
|
// ─── Variants ────────────────────────────────────────────────────────────────
|
package/src/data-accessor.ts
CHANGED
|
@@ -743,6 +743,14 @@ export interface DataAccessor {
|
|
|
743
743
|
*/
|
|
744
744
|
getAcRows(taskId: string): Promise<AcRow[]>;
|
|
745
745
|
|
|
746
|
+
/**
|
|
747
|
+
* Read the AC rows of many tasks in bulk (ordered by task, then ordinal),
|
|
748
|
+
* for whole-store scans such as `cleo doctor --coherence` (T12883). Optional:
|
|
749
|
+
* callers fall back to {@link getAcRows} per task when it is absent.
|
|
750
|
+
* @task T12883
|
|
751
|
+
*/
|
|
752
|
+
getAcRowsForTasks?(taskIds: readonly string[]): Promise<AcRow[]>;
|
|
753
|
+
|
|
746
754
|
/**
|
|
747
755
|
* Read `evidence_ac_bindings` rows whose `ac_id` ∈ the given set.
|
|
748
756
|
* Powers the AC-coverage gate (T10509). Returns the empty array when
|
|
@@ -8780,6 +8780,29 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
8780
8780
|
requiredParams: [],
|
|
8781
8781
|
params: [],
|
|
8782
8782
|
},
|
|
8783
|
+
// ── docs.rot (T14111 — Epic T14106) ──────────────────────────────────────
|
|
8784
|
+
{
|
|
8785
|
+
gateway: 'query',
|
|
8786
|
+
domain: 'docs',
|
|
8787
|
+
operation: 'rot',
|
|
8788
|
+
description:
|
|
8789
|
+
'docs.rot (query) — docs-rot report from git alone: docs whose covers: code changed ' +
|
|
8790
|
+
'after them (stale), duplicate docs, and orphaned docs (dead covers globs, ' +
|
|
8791
|
+
'unreferenced docs/ files). changed:<base>..<head> also lists the docs that merged ' +
|
|
8792
|
+
'change left stale. Read-only.',
|
|
8793
|
+
tier: 1,
|
|
8794
|
+
idempotent: true,
|
|
8795
|
+
sessionRequired: false,
|
|
8796
|
+
requiredParams: [],
|
|
8797
|
+
params: [
|
|
8798
|
+
{
|
|
8799
|
+
name: 'changed',
|
|
8800
|
+
type: 'string' as const,
|
|
8801
|
+
required: false,
|
|
8802
|
+
description: 'Git range <base>..<head> of a merged change to flag docs for',
|
|
8803
|
+
},
|
|
8804
|
+
],
|
|
8805
|
+
},
|
|
8783
8806
|
{
|
|
8784
8807
|
gateway: 'mutate',
|
|
8785
8808
|
domain: 'docs',
|
|
@@ -8836,6 +8859,90 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
8836
8859
|
requiredParams: [],
|
|
8837
8860
|
params: [],
|
|
8838
8861
|
},
|
|
8862
|
+
// ── docs.modernize (T14113 — Epic T14106) ─────────────────────────────────
|
|
8863
|
+
{
|
|
8864
|
+
gateway: 'mutate',
|
|
8865
|
+
domain: 'docs',
|
|
8866
|
+
operation: 'modernize',
|
|
8867
|
+
description:
|
|
8868
|
+
'docs.modernize (mutate) — turn a messy docs folder into clean, linked CleoDocs. Dry run ' +
|
|
8869
|
+
'by default: proposes per file a kind, a stable slug (no task, session or date tokens) ' +
|
|
8870
|
+
'and keep/rename/merge-into/delete with reasons and any System One judgment. --apply ' +
|
|
8871
|
+
'stores, merges, supersedes, moves files and writes wikilink edges with a receipt; ' +
|
|
8872
|
+
'--rollback <runId> reverses a run.',
|
|
8873
|
+
tier: 1,
|
|
8874
|
+
idempotent: false,
|
|
8875
|
+
sessionRequired: false,
|
|
8876
|
+
requiredParams: [],
|
|
8877
|
+
params: [
|
|
8878
|
+
{
|
|
8879
|
+
name: 'path',
|
|
8880
|
+
type: 'string' as const,
|
|
8881
|
+
required: false,
|
|
8882
|
+
description: 'Folder to modernize (required unless --rollback)',
|
|
8883
|
+
},
|
|
8884
|
+
{
|
|
8885
|
+
name: 'apply',
|
|
8886
|
+
type: 'boolean' as const,
|
|
8887
|
+
required: false,
|
|
8888
|
+
description: 'Execute the plan (default: dry run, nothing written)',
|
|
8889
|
+
},
|
|
8890
|
+
{
|
|
8891
|
+
name: 'planFile',
|
|
8892
|
+
type: 'string' as const,
|
|
8893
|
+
required: false,
|
|
8894
|
+
description: 'Apply this saved plan JSON verbatim',
|
|
8895
|
+
},
|
|
8896
|
+
{
|
|
8897
|
+
name: 'out',
|
|
8898
|
+
type: 'string' as const,
|
|
8899
|
+
required: false,
|
|
8900
|
+
description: 'Save the plan JSON to this path',
|
|
8901
|
+
},
|
|
8902
|
+
{
|
|
8903
|
+
name: 'rollback',
|
|
8904
|
+
type: 'string' as const,
|
|
8905
|
+
required: false,
|
|
8906
|
+
description: 'Roll back the apply run with this id',
|
|
8907
|
+
},
|
|
8908
|
+
{
|
|
8909
|
+
name: 'exclude',
|
|
8910
|
+
type: 'string' as const,
|
|
8911
|
+
required: false,
|
|
8912
|
+
description: 'Extra folder names to skip, comma-separated',
|
|
8913
|
+
},
|
|
8914
|
+
{
|
|
8915
|
+
name: 'overrides',
|
|
8916
|
+
type: 'string' as const,
|
|
8917
|
+
required: false,
|
|
8918
|
+
description: 'Reviewer decisions JSON keyed by path (DocsModernizeOverrides)',
|
|
8919
|
+
},
|
|
8920
|
+
{
|
|
8921
|
+
name: 'kind',
|
|
8922
|
+
type: 'string' as const,
|
|
8923
|
+
required: false,
|
|
8924
|
+
description: 'Use this kind for every file instead of classifying',
|
|
8925
|
+
},
|
|
8926
|
+
{
|
|
8927
|
+
name: 'storeOnly',
|
|
8928
|
+
type: 'boolean' as const,
|
|
8929
|
+
required: false,
|
|
8930
|
+
description: 'Ingest every file into the store and leave the folder untouched',
|
|
8931
|
+
},
|
|
8932
|
+
{
|
|
8933
|
+
name: 'allowDirty',
|
|
8934
|
+
type: 'boolean' as const,
|
|
8935
|
+
required: false,
|
|
8936
|
+
description: 'Apply even when the root is not a clean git checkout',
|
|
8937
|
+
},
|
|
8938
|
+
{
|
|
8939
|
+
name: 'store',
|
|
8940
|
+
type: 'boolean' as const,
|
|
8941
|
+
required: false,
|
|
8942
|
+
description: 'Modernize the docs already in the store instead of a folder',
|
|
8943
|
+
},
|
|
8944
|
+
],
|
|
8945
|
+
},
|
|
8839
8946
|
// ── docs.generate (T798) ─────────────────────────────────────────────────
|
|
8840
8947
|
{
|
|
8841
8948
|
gateway: 'query',
|
|
@@ -9782,6 +9889,106 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
9782
9889
|
] satisfies ParamDef[],
|
|
9783
9890
|
},
|
|
9784
9891
|
|
|
9892
|
+
// release mutate: cut (T14102 — one-command release from the newest green
|
|
9893
|
+
// default-branch commit; replaces plan → open → bump-PR → hand tag).
|
|
9894
|
+
{
|
|
9895
|
+
gateway: 'mutate',
|
|
9896
|
+
domain: 'release',
|
|
9897
|
+
operation: 'cut',
|
|
9898
|
+
description:
|
|
9899
|
+
'release.cut (mutate) — tag the newest default-branch commit with green CI as v<version> once confirmed with --yes (D11211/D11212); release.yml writes the CHANGELOG from changesets and publishes. Without --yes it reports the commit, notes, packages and task status and prints the confirm command (T14102).',
|
|
9900
|
+
tier: 1,
|
|
9901
|
+
idempotent: false,
|
|
9902
|
+
sessionRequired: false,
|
|
9903
|
+
requiredParams: ['version'],
|
|
9904
|
+
params: [
|
|
9905
|
+
{
|
|
9906
|
+
name: 'version',
|
|
9907
|
+
type: 'string',
|
|
9908
|
+
required: true,
|
|
9909
|
+
description: 'Release version (accepts v2026.10.28 or 2026.10.28)',
|
|
9910
|
+
cli: { positional: true },
|
|
9911
|
+
},
|
|
9912
|
+
{
|
|
9913
|
+
name: 'sha',
|
|
9914
|
+
type: 'string',
|
|
9915
|
+
required: false,
|
|
9916
|
+
description: 'Pin the commit instead of the newest green one; it must itself be green',
|
|
9917
|
+
},
|
|
9918
|
+
{
|
|
9919
|
+
name: 'lead',
|
|
9920
|
+
type: 'string',
|
|
9921
|
+
required: false,
|
|
9922
|
+
description: 'Markdown file that leads the notes (Update now + Highlights)',
|
|
9923
|
+
},
|
|
9924
|
+
{
|
|
9925
|
+
name: 'dryRun',
|
|
9926
|
+
type: 'boolean',
|
|
9927
|
+
required: false,
|
|
9928
|
+
description: 'Report the commit, notes, packages and tasks without creating the tag',
|
|
9929
|
+
},
|
|
9930
|
+
{
|
|
9931
|
+
name: 'yes',
|
|
9932
|
+
type: 'boolean',
|
|
9933
|
+
required: false,
|
|
9934
|
+
description:
|
|
9935
|
+
'Create the tag (D11212): the version typed on the controlling terminal (/dev/tty), or a standing release authorization (T14141), allows it. Without it the cut only reports and prints the confirm command',
|
|
9936
|
+
},
|
|
9937
|
+
] satisfies ParamDef[],
|
|
9938
|
+
},
|
|
9939
|
+
|
|
9940
|
+
// release mutate: write-changelog (T14102 — CHANGELOG section from the
|
|
9941
|
+
// changesets since the previous tag; run by release.yml on the tagged checkout).
|
|
9942
|
+
{
|
|
9943
|
+
gateway: 'mutate',
|
|
9944
|
+
domain: 'release',
|
|
9945
|
+
operation: 'write-changelog',
|
|
9946
|
+
description:
|
|
9947
|
+
'release.write-changelog (mutate) — write the ## [VERSION] CHANGELOG.md section from the changesets added since the previous release tag, led by the tag annotation; leaves an existing section untouched (T14102).',
|
|
9948
|
+
tier: 1,
|
|
9949
|
+
idempotent: true,
|
|
9950
|
+
sessionRequired: false,
|
|
9951
|
+
requiredParams: ['version'],
|
|
9952
|
+
params: [
|
|
9953
|
+
{
|
|
9954
|
+
name: 'version',
|
|
9955
|
+
type: 'string',
|
|
9956
|
+
required: true,
|
|
9957
|
+
description: 'Release version (accepts v2026.10.28 or 2026.10.28)',
|
|
9958
|
+
cli: { positional: true },
|
|
9959
|
+
},
|
|
9960
|
+
{
|
|
9961
|
+
name: 'ref',
|
|
9962
|
+
type: 'string',
|
|
9963
|
+
required: false,
|
|
9964
|
+
description: 'Commit the release was cut from (default: tag v<version>, else HEAD)',
|
|
9965
|
+
},
|
|
9966
|
+
] satisfies ParamDef[],
|
|
9967
|
+
},
|
|
9968
|
+
|
|
9969
|
+
// release query: verify-tag (T14102 — release.yml refuses to publish a tag
|
|
9970
|
+
// that is not a green first-parent commit of the default branch).
|
|
9971
|
+
{
|
|
9972
|
+
gateway: 'query',
|
|
9973
|
+
domain: 'release',
|
|
9974
|
+
operation: 'verify-tag',
|
|
9975
|
+
description:
|
|
9976
|
+
'release.verify-tag (query) — refuse a release tag whose commit is not a first-parent commit of origin/main with every required check (release.prRequiredWorkflows, app-pinned) green on its push run. Run by release.yml before publishing (T14102).',
|
|
9977
|
+
tier: 1,
|
|
9978
|
+
idempotent: true,
|
|
9979
|
+
sessionRequired: false,
|
|
9980
|
+
requiredParams: ['version'],
|
|
9981
|
+
params: [
|
|
9982
|
+
{
|
|
9983
|
+
name: 'version',
|
|
9984
|
+
type: 'string',
|
|
9985
|
+
required: true,
|
|
9986
|
+
description: 'Release version whose tag is checked (accepts v2026.10.28 or 2026.10.28)',
|
|
9987
|
+
cli: { positional: true },
|
|
9988
|
+
},
|
|
9989
|
+
] satisfies ParamDef[],
|
|
9990
|
+
},
|
|
9991
|
+
|
|
9785
9992
|
// release query: validate-changelog (T9937 / Saga T9862 — canonical CHANGELOG
|
|
9786
9993
|
// header validator that replaces the brittle inline grep step in
|
|
9787
9994
|
// .github/workflows/release.yml). Read-only — exposed only under the query
|