@cleocode/contracts 2026.5.77 → 2026.5.79
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/config.d.ts +66 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/credentials.d.ts +20 -0
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +7 -0
- package/dist/credentials.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 +52 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/operations/worktree.d.ts +251 -0
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/release/plan.d.ts +533 -0
- package/dist/release/plan.d.ts.map +1 -0
- package/dist/release/plan.js +393 -0
- package/dist/release/plan.js.map +1 -0
- package/dist/release/plan.test.d.ts +17 -0
- package/dist/release/plan.test.d.ts.map +1 -0
- package/dist/release/plan.test.js +414 -0
- package/dist/release/plan.test.js.map +1 -0
- package/dist/tasks/archive.d.ts +3 -3
- package/package.json +2 -2
- package/src/config.ts +67 -7
- package/src/credentials.ts +29 -0
- package/src/exit-codes.ts +54 -0
- package/src/index.ts +79 -0
- package/src/operations/worktree.ts +274 -0
- package/src/release/plan.test.ts +501 -0
- package/src/release/plan.ts +493 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema tests for the Release Plan envelope (T9527).
|
|
3
|
+
*
|
|
4
|
+
* Validates the canonical SPEC-T9345 §6.1 shape against the Zod schema defined
|
|
5
|
+
* in {@link ./plan.ts}. Coverage targets:
|
|
6
|
+
*
|
|
7
|
+
* - Happy-path parse round-trip
|
|
8
|
+
* - Each enum field rejects unknown literal values
|
|
9
|
+
* - Required fields cannot be missing
|
|
10
|
+
* - `evidenceAtoms` stays permissive (verb-level enforcement, NOT contract)
|
|
11
|
+
* - All 8 `status` FSM values parse
|
|
12
|
+
* - `meta` is forward-compat (unknown keys pass through via `.catchall`)
|
|
13
|
+
*
|
|
14
|
+
* @task T9527
|
|
15
|
+
*/
|
|
16
|
+
import { describe, expect, it } from 'vitest';
|
|
17
|
+
import { GATE_NAME, GATE_STATUS, IMPACT, PLATFORM_TUPLE, PUBLISHER, parseReleasePlan, RELEASE_CHANNEL, RELEASE_KIND, RELEASE_PLAN_SCHEMA_URL, RELEASE_PLAN_SCHEMA_VERSION, RELEASE_SCHEME, RELEASE_STATUS, RESOLVED_SOURCE, ReleaseGateSchema, ReleasePlanChangelogSchema, ReleasePlanMetaSchema, ReleasePlanSchema, ReleasePlanTaskSchema, ReleasePlatformMatrixEntrySchema, ReleasePreflightSummarySchema, safeParseReleasePlan, TASK_KIND, } from './plan.js';
|
|
18
|
+
// ─── Fixtures ────────────────────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Returns a fresh deep clone of a minimal-but-complete valid plan. Each test
|
|
21
|
+
* mutates its own copy to test field-level rejection paths.
|
|
22
|
+
*/
|
|
23
|
+
function makeValidPlan() {
|
|
24
|
+
return {
|
|
25
|
+
$schema: RELEASE_PLAN_SCHEMA_URL,
|
|
26
|
+
version: 'v2026.6.0',
|
|
27
|
+
resolvedVersion: 'v2026.6.0',
|
|
28
|
+
suffixApplied: false,
|
|
29
|
+
scheme: 'calver',
|
|
30
|
+
channel: 'latest',
|
|
31
|
+
epicId: 'T9999',
|
|
32
|
+
releaseKind: 'regular',
|
|
33
|
+
createdAt: '2026-06-01T12:00:00Z',
|
|
34
|
+
createdBy: 'cleo-prime',
|
|
35
|
+
previousVersion: 'v2026.5.74',
|
|
36
|
+
previousTag: 'v2026.5.74',
|
|
37
|
+
previousShippedAt: '2026-05-15T08:00:00Z',
|
|
38
|
+
tasks: [
|
|
39
|
+
{
|
|
40
|
+
id: 'T10001',
|
|
41
|
+
kind: 'feat',
|
|
42
|
+
impact: 'minor',
|
|
43
|
+
userFacingSummary: 'Add release plan schema',
|
|
44
|
+
evidenceAtoms: ['commit:abc123', 'test-run:vitest.json', 'tool:lint'],
|
|
45
|
+
ivtrPhaseAtPlan: 'released',
|
|
46
|
+
epicAncestor: 'T9999',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
changelog: {
|
|
50
|
+
features: ['T10001'],
|
|
51
|
+
fixes: [],
|
|
52
|
+
chores: [],
|
|
53
|
+
breaking: [],
|
|
54
|
+
},
|
|
55
|
+
gates: [
|
|
56
|
+
{
|
|
57
|
+
name: 'test',
|
|
58
|
+
atom: 'tool:test',
|
|
59
|
+
status: 'passed',
|
|
60
|
+
lastVerifiedAt: '2026-06-01T11:50:00Z',
|
|
61
|
+
resolvedCommand: 'pnpm run test',
|
|
62
|
+
resolvedSource: 'project-context',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
platformMatrix: [
|
|
66
|
+
{
|
|
67
|
+
platform: 'linux-x64',
|
|
68
|
+
publisher: 'npm',
|
|
69
|
+
package: '@cleocode/cleo',
|
|
70
|
+
smoke: true,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
preflightSummary: {
|
|
74
|
+
esbuildExternalsDrift: false,
|
|
75
|
+
lockfileDrift: false,
|
|
76
|
+
epicCompletenessClean: true,
|
|
77
|
+
doubleListingClean: true,
|
|
78
|
+
preflightWarnings: [],
|
|
79
|
+
},
|
|
80
|
+
workflowRunUrl: null,
|
|
81
|
+
prUrl: null,
|
|
82
|
+
mergeCommitSha: null,
|
|
83
|
+
status: 'planned',
|
|
84
|
+
meta: {
|
|
85
|
+
firstEverRelease: false,
|
|
86
|
+
unresolvedTools: [],
|
|
87
|
+
archetype: 'monorepo-w-workspaces',
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// ─── Constant tuples ─────────────────────────────────────────────────────────
|
|
92
|
+
describe('Release plan constant tuples', () => {
|
|
93
|
+
it('exports an 8-state status FSM', () => {
|
|
94
|
+
expect(RELEASE_STATUS).toEqual([
|
|
95
|
+
'planned',
|
|
96
|
+
'pr-opened',
|
|
97
|
+
'pr-merged',
|
|
98
|
+
'published',
|
|
99
|
+
'reconciled',
|
|
100
|
+
'rolled_back',
|
|
101
|
+
'failed',
|
|
102
|
+
'cancelled',
|
|
103
|
+
]);
|
|
104
|
+
expect(RELEASE_STATUS).toHaveLength(8);
|
|
105
|
+
});
|
|
106
|
+
it('exports the 4-channel set (latest|beta|alpha|rc)', () => {
|
|
107
|
+
expect(new Set(RELEASE_CHANNEL)).toEqual(new Set(['latest', 'beta', 'alpha', 'rc']));
|
|
108
|
+
});
|
|
109
|
+
it('exports the 3-scheme set including calver-suffix', () => {
|
|
110
|
+
expect(RELEASE_SCHEME).toContain('calver');
|
|
111
|
+
expect(RELEASE_SCHEME).toContain('semver');
|
|
112
|
+
expect(RELEASE_SCHEME).toContain('calver-suffix');
|
|
113
|
+
});
|
|
114
|
+
it('exports release-kind variants', () => {
|
|
115
|
+
expect(new Set(RELEASE_KIND)).toEqual(new Set(['regular', 'hotfix', 'prerelease']));
|
|
116
|
+
});
|
|
117
|
+
it('exports the 4-status gate enum', () => {
|
|
118
|
+
expect(new Set(GATE_STATUS)).toEqual(new Set(['passed', 'failed', 'skipped', 'unresolved']));
|
|
119
|
+
});
|
|
120
|
+
it('exports canonical gate names (R-310)', () => {
|
|
121
|
+
expect(GATE_NAME).toContain('test');
|
|
122
|
+
expect(GATE_NAME).toContain('build');
|
|
123
|
+
expect(GATE_NAME).toContain('lint');
|
|
124
|
+
expect(GATE_NAME).toContain('typecheck');
|
|
125
|
+
expect(GATE_NAME).toContain('audit');
|
|
126
|
+
expect(GATE_NAME).toContain('security-scan');
|
|
127
|
+
});
|
|
128
|
+
it('exports platform tuples aligned with T1737', () => {
|
|
129
|
+
expect(PLATFORM_TUPLE).toContain('linux-x64');
|
|
130
|
+
expect(PLATFORM_TUPLE).toContain('linux-arm64');
|
|
131
|
+
expect(PLATFORM_TUPLE).toContain('macos-x64');
|
|
132
|
+
expect(PLATFORM_TUPLE).toContain('macos-arm64');
|
|
133
|
+
expect(PLATFORM_TUPLE).toContain('windows-x64');
|
|
134
|
+
expect(PLATFORM_TUPLE).toContain('any');
|
|
135
|
+
});
|
|
136
|
+
it('exports publisher backends covering npm/cargo/docker/pypi/github-release/binary', () => {
|
|
137
|
+
expect(new Set(PUBLISHER)).toEqual(new Set(['npm', 'cargo', 'docker', 'pypi', 'github-release', 'binary']));
|
|
138
|
+
});
|
|
139
|
+
it('exports task-kind classification', () => {
|
|
140
|
+
expect(TASK_KIND).toContain('feat');
|
|
141
|
+
expect(TASK_KIND).toContain('fix');
|
|
142
|
+
expect(TASK_KIND).toContain('hotfix');
|
|
143
|
+
expect(TASK_KIND).toContain('breaking');
|
|
144
|
+
});
|
|
145
|
+
it('exports SemVer impact tuple', () => {
|
|
146
|
+
expect(IMPACT).toEqual(['major', 'minor', 'patch']);
|
|
147
|
+
});
|
|
148
|
+
it('exports resolved-source attribution per ADR-061', () => {
|
|
149
|
+
expect(RESOLVED_SOURCE).toEqual(['project-context', 'language-default', 'legacy-alias']);
|
|
150
|
+
});
|
|
151
|
+
it('exposes a stable schema version + URL', () => {
|
|
152
|
+
expect(RELEASE_PLAN_SCHEMA_VERSION).toBe('1.0.0');
|
|
153
|
+
expect(RELEASE_PLAN_SCHEMA_URL).toBe('https://cleocode.io/schemas/release-plan/v1.json');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
// ─── Happy path ──────────────────────────────────────────────────────────────
|
|
157
|
+
describe('ReleasePlanSchema — happy path', () => {
|
|
158
|
+
it('parses a complete valid plan', () => {
|
|
159
|
+
const plan = parseReleasePlan(makeValidPlan());
|
|
160
|
+
expect(plan.version).toBe('v2026.6.0');
|
|
161
|
+
expect(plan.status).toBe('planned');
|
|
162
|
+
expect(plan.tasks).toHaveLength(1);
|
|
163
|
+
expect(plan.tasks[0]?.id).toBe('T10001');
|
|
164
|
+
expect(plan.platformMatrix[0]?.publisher).toBe('npm');
|
|
165
|
+
});
|
|
166
|
+
it('safeParse returns success for a valid plan', () => {
|
|
167
|
+
const result = safeParseReleasePlan(makeValidPlan());
|
|
168
|
+
expect(result.success).toBe(true);
|
|
169
|
+
});
|
|
170
|
+
it('round-trips through JSON.stringify / parse', () => {
|
|
171
|
+
const original = makeValidPlan();
|
|
172
|
+
const serialized = JSON.stringify(original);
|
|
173
|
+
const reparsed = parseReleasePlan(JSON.parse(serialized));
|
|
174
|
+
expect(reparsed).toEqual(original);
|
|
175
|
+
});
|
|
176
|
+
it('accepts a first-ever release with null previousVersion + meta.firstEverRelease', () => {
|
|
177
|
+
const plan = makeValidPlan();
|
|
178
|
+
plan.previousVersion = null;
|
|
179
|
+
plan.previousTag = null;
|
|
180
|
+
plan.previousShippedAt = null;
|
|
181
|
+
plan.meta = { firstEverRelease: true };
|
|
182
|
+
expect(() => parseReleasePlan(plan)).not.toThrow();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
// ─── Status FSM coverage ─────────────────────────────────────────────────────
|
|
186
|
+
describe('ReleasePlanSchema — status FSM', () => {
|
|
187
|
+
it.each(RELEASE_STATUS)('accepts status = "%s"', (status) => {
|
|
188
|
+
const plan = makeValidPlan();
|
|
189
|
+
plan.status = status;
|
|
190
|
+
expect(() => parseReleasePlan(plan)).not.toThrow();
|
|
191
|
+
});
|
|
192
|
+
it('rejects unknown status literals', () => {
|
|
193
|
+
const plan = { ...makeValidPlan(), status: 'in-flight' };
|
|
194
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
// ─── Enum rejection per field ────────────────────────────────────────────────
|
|
198
|
+
describe('ReleasePlanSchema — enum rejection', () => {
|
|
199
|
+
it('rejects unknown channel', () => {
|
|
200
|
+
const plan = { ...makeValidPlan(), channel: 'canary' };
|
|
201
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
202
|
+
});
|
|
203
|
+
it('rejects unknown scheme', () => {
|
|
204
|
+
const plan = { ...makeValidPlan(), scheme: 'rolling' };
|
|
205
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
206
|
+
});
|
|
207
|
+
it('rejects unknown releaseKind', () => {
|
|
208
|
+
const plan = { ...makeValidPlan(), releaseKind: 'patch' };
|
|
209
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
210
|
+
});
|
|
211
|
+
it('rejects unknown task kind', () => {
|
|
212
|
+
const plan = makeValidPlan();
|
|
213
|
+
plan.tasks[0] = { ...plan.tasks[0], kind: 'misc' };
|
|
214
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
215
|
+
});
|
|
216
|
+
it('rejects unknown impact', () => {
|
|
217
|
+
const plan = makeValidPlan();
|
|
218
|
+
plan.tasks[0] = { ...plan.tasks[0], impact: 'huge' };
|
|
219
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
220
|
+
});
|
|
221
|
+
it('rejects unknown gate name', () => {
|
|
222
|
+
const plan = makeValidPlan();
|
|
223
|
+
plan.gates[0] = { ...plan.gates[0], name: 'fmt' };
|
|
224
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
225
|
+
});
|
|
226
|
+
it('rejects unknown gate status', () => {
|
|
227
|
+
const plan = makeValidPlan();
|
|
228
|
+
plan.gates[0] = { ...plan.gates[0], status: 'flaky' };
|
|
229
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
230
|
+
});
|
|
231
|
+
it('rejects unknown platform tuple', () => {
|
|
232
|
+
const plan = makeValidPlan();
|
|
233
|
+
plan.platformMatrix[0] = { ...plan.platformMatrix[0], platform: 'haiku-x64' };
|
|
234
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
235
|
+
});
|
|
236
|
+
it('rejects unknown publisher', () => {
|
|
237
|
+
const plan = makeValidPlan();
|
|
238
|
+
plan.platformMatrix[0] = { ...plan.platformMatrix[0], publisher: 'gemfury' };
|
|
239
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
240
|
+
});
|
|
241
|
+
it('rejects unknown resolvedSource', () => {
|
|
242
|
+
const plan = makeValidPlan();
|
|
243
|
+
plan.gates[0] = { ...plan.gates[0], resolvedSource: 'env-override' };
|
|
244
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
// ─── Required-field rejection ────────────────────────────────────────────────
|
|
248
|
+
describe('ReleasePlanSchema — required fields', () => {
|
|
249
|
+
it('rejects missing version', () => {
|
|
250
|
+
const plan = makeValidPlan();
|
|
251
|
+
delete plan.version;
|
|
252
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
253
|
+
});
|
|
254
|
+
it('rejects missing epicId', () => {
|
|
255
|
+
const plan = makeValidPlan();
|
|
256
|
+
delete plan.epicId;
|
|
257
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
258
|
+
});
|
|
259
|
+
it('rejects empty epicId string', () => {
|
|
260
|
+
const plan = { ...makeValidPlan(), epicId: '' };
|
|
261
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
262
|
+
});
|
|
263
|
+
it('rejects missing tasks array', () => {
|
|
264
|
+
const plan = makeValidPlan();
|
|
265
|
+
delete plan.tasks;
|
|
266
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
267
|
+
});
|
|
268
|
+
it('rejects missing changelog object', () => {
|
|
269
|
+
const plan = makeValidPlan();
|
|
270
|
+
delete plan.changelog;
|
|
271
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
272
|
+
});
|
|
273
|
+
it('rejects missing preflightSummary', () => {
|
|
274
|
+
const plan = makeValidPlan();
|
|
275
|
+
delete plan.preflightSummary;
|
|
276
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
277
|
+
});
|
|
278
|
+
it('rejects missing epicAncestor on a task row', () => {
|
|
279
|
+
const plan = makeValidPlan();
|
|
280
|
+
const taskWithoutAncestor = { ...plan.tasks[0] };
|
|
281
|
+
delete taskWithoutAncestor.epicAncestor;
|
|
282
|
+
plan.tasks[0] = taskWithoutAncestor;
|
|
283
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
284
|
+
});
|
|
285
|
+
it('rejects malformed createdAt timestamp', () => {
|
|
286
|
+
const plan = { ...makeValidPlan(), createdAt: 'yesterday' };
|
|
287
|
+
expect(() => parseReleasePlan(plan)).toThrow();
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
// ─── Evidence atoms (contract permissive — R-301 verb-enforced) ─────────────
|
|
291
|
+
describe('ReleasePlanTaskSchema — evidenceAtoms', () => {
|
|
292
|
+
it('accepts a string[] for evidenceAtoms', () => {
|
|
293
|
+
const result = ReleasePlanTaskSchema.parse({
|
|
294
|
+
id: 'T1',
|
|
295
|
+
kind: 'feat',
|
|
296
|
+
impact: 'patch',
|
|
297
|
+
userFacingSummary: '',
|
|
298
|
+
evidenceAtoms: ['commit:abc'],
|
|
299
|
+
epicAncestor: 'E1',
|
|
300
|
+
});
|
|
301
|
+
expect(result.evidenceAtoms).toEqual(['commit:abc']);
|
|
302
|
+
});
|
|
303
|
+
it('permits an empty evidenceAtoms array at the contract layer (R-301 is verb-enforced)', () => {
|
|
304
|
+
const result = ReleasePlanTaskSchema.safeParse({
|
|
305
|
+
id: 'T1',
|
|
306
|
+
kind: 'feat',
|
|
307
|
+
impact: 'patch',
|
|
308
|
+
userFacingSummary: '',
|
|
309
|
+
evidenceAtoms: [],
|
|
310
|
+
epicAncestor: 'E1',
|
|
311
|
+
});
|
|
312
|
+
expect(result.success).toBe(true);
|
|
313
|
+
});
|
|
314
|
+
it('rejects non-array evidenceAtoms', () => {
|
|
315
|
+
const result = ReleasePlanTaskSchema.safeParse({
|
|
316
|
+
id: 'T1',
|
|
317
|
+
kind: 'feat',
|
|
318
|
+
impact: 'patch',
|
|
319
|
+
userFacingSummary: '',
|
|
320
|
+
evidenceAtoms: 'commit:abc',
|
|
321
|
+
epicAncestor: 'E1',
|
|
322
|
+
});
|
|
323
|
+
expect(result.success).toBe(false);
|
|
324
|
+
});
|
|
325
|
+
it('rejects empty-string atom entries (NonEmptyString)', () => {
|
|
326
|
+
const result = ReleasePlanTaskSchema.safeParse({
|
|
327
|
+
id: 'T1',
|
|
328
|
+
kind: 'feat',
|
|
329
|
+
impact: 'patch',
|
|
330
|
+
userFacingSummary: '',
|
|
331
|
+
evidenceAtoms: [''],
|
|
332
|
+
epicAncestor: 'E1',
|
|
333
|
+
});
|
|
334
|
+
expect(result.success).toBe(false);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
// ─── meta forward-compat ─────────────────────────────────────────────────────
|
|
338
|
+
describe('ReleasePlanMetaSchema — forward compatibility', () => {
|
|
339
|
+
it('preserves unknown keys via catchall', () => {
|
|
340
|
+
const result = ReleasePlanMetaSchema.parse({
|
|
341
|
+
firstEverRelease: false,
|
|
342
|
+
futureField: 'someValue',
|
|
343
|
+
anotherUnknown: { nested: true },
|
|
344
|
+
});
|
|
345
|
+
expect(result.futureField).toBe('someValue');
|
|
346
|
+
expect(result.anotherUnknown).toEqual({ nested: true });
|
|
347
|
+
});
|
|
348
|
+
it('still validates known fields strictly', () => {
|
|
349
|
+
const result = ReleasePlanMetaSchema.safeParse({
|
|
350
|
+
firstEverRelease: 'yes',
|
|
351
|
+
});
|
|
352
|
+
expect(result.success).toBe(false);
|
|
353
|
+
});
|
|
354
|
+
it('accepts a fully-empty meta object', () => {
|
|
355
|
+
expect(() => ReleasePlanMetaSchema.parse({})).not.toThrow();
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
// ─── Nested-schema sanity ────────────────────────────────────────────────────
|
|
359
|
+
describe('Nested schemas — sanity', () => {
|
|
360
|
+
it('ReleaseGateSchema requires lastVerifiedAt to be ISO-8601', () => {
|
|
361
|
+
const result = ReleaseGateSchema.safeParse({
|
|
362
|
+
name: 'test',
|
|
363
|
+
atom: 'tool:test',
|
|
364
|
+
status: 'passed',
|
|
365
|
+
lastVerifiedAt: 'Tuesday',
|
|
366
|
+
});
|
|
367
|
+
expect(result.success).toBe(false);
|
|
368
|
+
});
|
|
369
|
+
it('ReleasePlatformMatrixEntrySchema applies smoke=true default when omitted', () => {
|
|
370
|
+
const result = ReleasePlatformMatrixEntrySchema.parse({
|
|
371
|
+
platform: 'any',
|
|
372
|
+
publisher: 'npm',
|
|
373
|
+
package: '@cleocode/lafs',
|
|
374
|
+
});
|
|
375
|
+
expect(result.smoke).toBe(true);
|
|
376
|
+
});
|
|
377
|
+
it('ReleasePreflightSummarySchema requires the four boolean preflight gates', () => {
|
|
378
|
+
const result = ReleasePreflightSummarySchema.safeParse({
|
|
379
|
+
esbuildExternalsDrift: false,
|
|
380
|
+
lockfileDrift: false,
|
|
381
|
+
epicCompletenessClean: true,
|
|
382
|
+
// doubleListingClean omitted
|
|
383
|
+
});
|
|
384
|
+
expect(result.success).toBe(false);
|
|
385
|
+
});
|
|
386
|
+
it('ReleasePlanChangelogSchema applies empty-array defaults for omitted buckets', () => {
|
|
387
|
+
const result = ReleasePlanChangelogSchema.parse({});
|
|
388
|
+
expect(result.features).toEqual([]);
|
|
389
|
+
expect(result.fixes).toEqual([]);
|
|
390
|
+
expect(result.chores).toEqual([]);
|
|
391
|
+
expect(result.breaking).toEqual([]);
|
|
392
|
+
});
|
|
393
|
+
it('ReleasePlanSchema accepts plans with no tasks (e.g. config-only releases)', () => {
|
|
394
|
+
const plan = makeValidPlan();
|
|
395
|
+
plan.tasks = [];
|
|
396
|
+
plan.changelog.features = [];
|
|
397
|
+
expect(() => parseReleasePlan(plan)).not.toThrow();
|
|
398
|
+
});
|
|
399
|
+
it('safeParseReleasePlan surfaces issues for bad enums', () => {
|
|
400
|
+
const result = safeParseReleasePlan({ ...makeValidPlan(), channel: 'invalid-channel' });
|
|
401
|
+
expect(result.success).toBe(false);
|
|
402
|
+
if (!result.success) {
|
|
403
|
+
expect(result.error.issues.length).toBeGreaterThan(0);
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
// ─── Schema export sanity ────────────────────────────────────────────────────
|
|
408
|
+
describe('ReleasePlanSchema — module surface', () => {
|
|
409
|
+
it('exports a Zod object schema at the top level', () => {
|
|
410
|
+
expect(typeof ReleasePlanSchema.parse).toBe('function');
|
|
411
|
+
expect(typeof ReleasePlanSchema.safeParse).toBe('function');
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
//# sourceMappingURL=plan.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.test.js","sourceRoot":"","sources":["../../src/release/plan.test.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/archive.d.ts
CHANGED
|
@@ -51,8 +51,8 @@ import { z } from 'zod';
|
|
|
51
51
|
export declare const ArchiveReason: z.ZodEnum<{
|
|
52
52
|
cancelled: "cancelled";
|
|
53
53
|
superseded: "superseded";
|
|
54
|
-
verified: "verified";
|
|
55
54
|
reconciled: "reconciled";
|
|
55
|
+
verified: "verified";
|
|
56
56
|
shadowed: "shadowed";
|
|
57
57
|
"completed-unverified": "completed-unverified";
|
|
58
58
|
}>;
|
|
@@ -67,8 +67,8 @@ export declare const ArchiveReason: z.ZodEnum<{
|
|
|
67
67
|
export declare const ArchiveReasonSchema: z.ZodEnum<{
|
|
68
68
|
cancelled: "cancelled";
|
|
69
69
|
superseded: "superseded";
|
|
70
|
-
verified: "verified";
|
|
71
70
|
reconciled: "reconciled";
|
|
71
|
+
verified: "verified";
|
|
72
72
|
shadowed: "shadowed";
|
|
73
73
|
"completed-unverified": "completed-unverified";
|
|
74
74
|
}>;
|
|
@@ -93,7 +93,7 @@ export type ArchiveReasonValue = z.infer<typeof ArchiveReason>;
|
|
|
93
93
|
* Useful when a Drizzle column or a discriminated union needs the raw
|
|
94
94
|
* tuple form (e.g. `text('archive_reason', { enum: ARCHIVE_REASON_VALUES })`).
|
|
95
95
|
*/
|
|
96
|
-
export declare const ARCHIVE_REASON_VALUES: ("cancelled" | "superseded" | "
|
|
96
|
+
export declare const ARCHIVE_REASON_VALUES: ("cancelled" | "superseded" | "reconciled" | "verified" | "shadowed" | "completed-unverified")[];
|
|
97
97
|
/**
|
|
98
98
|
* The single tombstone value within {@link ArchiveReason}.
|
|
99
99
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/contracts",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.79",
|
|
4
4
|
"description": "Domain types, interfaces, and contracts for the CLEO ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"dependencies": {
|
|
99
99
|
"zod": "^4.3.6",
|
|
100
100
|
"zod-to-json-schema": "^3.25.2",
|
|
101
|
-
"@cleocode/lafs": "2026.5.
|
|
101
|
+
"@cleocode/lafs": "2026.5.79"
|
|
102
102
|
},
|
|
103
103
|
"scripts": {
|
|
104
104
|
"build": "tsc -b --force && node scripts/emit-schemas.mjs",
|
package/src/config.ts
CHANGED
|
@@ -175,14 +175,19 @@ export interface SharingConfig {
|
|
|
175
175
|
/**
|
|
176
176
|
* Memory bridge injection mode.
|
|
177
177
|
*
|
|
178
|
-
* - `'cli'`
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
178
|
+
* - `'cli'` — AGENTS.md receives a `cleo memory digest --brief` CLI directive instead of
|
|
179
|
+
* `@.cleo/memory-bridge.md`. The bridge markdown file is NOT written on refresh.
|
|
180
|
+
* This is the default for new installations (T999). Also surfaced to operators
|
|
181
|
+
* as the `digest` mode in `cleo setup` (T9425) — the wire value stays `'cli'`
|
|
182
|
+
* so existing project configs keep working unchanged.
|
|
183
|
+
* - `'file'` — Legacy behavior: `.cleo/memory-bridge.md` is written on refresh and
|
|
184
|
+
* `@.cleo/memory-bridge.md` is injected into AGENTS.md verbatim.
|
|
185
|
+
* Use this for backcompat with tooling that reads the file directly.
|
|
186
|
+
* - `'disabled'` — Bridge injection is suppressed entirely; AGENTS.md gets neither a CLI
|
|
187
|
+
* directive nor a file include. Operators select this from `cleo setup`
|
|
188
|
+
* when they want to opt out of BRAIN-driven AGENTS.md augmentation (T9425).
|
|
184
189
|
*/
|
|
185
|
-
export type MemoryBridgeMode = 'cli' | 'file';
|
|
190
|
+
export type MemoryBridgeMode = 'cli' | 'file' | 'disabled';
|
|
186
191
|
|
|
187
192
|
/**
|
|
188
193
|
* Brain memory bridge refresh configuration.
|
|
@@ -588,6 +593,61 @@ export interface CleoConfig {
|
|
|
588
593
|
* @defaultValue undefined
|
|
589
594
|
*/
|
|
590
595
|
briefing?: BriefingConfig;
|
|
596
|
+
/**
|
|
597
|
+
* Auth-source consent gates for credential seeders.
|
|
598
|
+
*
|
|
599
|
+
* Gates third-party credential imports (e.g. Claude Code OAuth) behind
|
|
600
|
+
* explicit operator opt-in. Mirrors Hermes Agent's PR #4210 consent gate.
|
|
601
|
+
*
|
|
602
|
+
* @defaultValue undefined
|
|
603
|
+
* @task T9410
|
|
604
|
+
*/
|
|
605
|
+
auth?: AuthConfig;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Auth-source consent configuration.
|
|
610
|
+
*
|
|
611
|
+
* Concrete `CredentialSeeder` implementations consult these flags before
|
|
612
|
+
* reading any third-party credential file (e.g. `~/.claude/.credentials.json`).
|
|
613
|
+
* Defaulting every flag to `false` keeps auxiliary fallback chains opt-in:
|
|
614
|
+
* aux callers cannot silently read user credentials they were never granted.
|
|
615
|
+
*
|
|
616
|
+
* @task T9410
|
|
617
|
+
*/
|
|
618
|
+
export interface AuthConfig {
|
|
619
|
+
/**
|
|
620
|
+
* Whether the operator has explicitly opted in to import the Claude Code
|
|
621
|
+
* OAuth token (`~/.claude/.credentials.json`) into the CLEO credential
|
|
622
|
+
* pool.
|
|
623
|
+
*
|
|
624
|
+
* When `false` (default), the `claude-code` seeder MUST NOT read the file
|
|
625
|
+
* and MUST return an empty seeder result. When `true`, the seeder reads
|
|
626
|
+
* the file and emits a single `source: 'claude-code'` entry for the
|
|
627
|
+
* `anthropic` provider.
|
|
628
|
+
*
|
|
629
|
+
* @defaultValue false
|
|
630
|
+
*/
|
|
631
|
+
claudeCodeConsentGiven?: boolean;
|
|
632
|
+
/**
|
|
633
|
+
* Whether CLEO writes refreshed Anthropic OAuth tokens back to Claude
|
|
634
|
+
* Code's credential file (`~/.claude/.credentials.json`) in addition to
|
|
635
|
+
* CLEO's own canonical token file (`${getCleoHome()}/anthropic-oauth.json`).
|
|
636
|
+
*
|
|
637
|
+
* CLEO ALWAYS writes its own file on every refresh. The cooperative write
|
|
638
|
+
* to Claude Code's file is gated by this flag AND by either
|
|
639
|
+
* (a) the Claude Code file already existing on disk, or
|
|
640
|
+
* (b) `claudeCodeConsentGiven` being `true`.
|
|
641
|
+
*
|
|
642
|
+
* This mirrors the OQ-1 decision in `docs/plans/E-CONFIG-AUTH-UNIFY.md`:
|
|
643
|
+
* cooperative write-back is enabled by default so two CLIs sharing one
|
|
644
|
+
* machine stay token-coherent, but CLEO never creates Claude Code's file
|
|
645
|
+
* unless the operator has explicitly opted in.
|
|
646
|
+
*
|
|
647
|
+
* @defaultValue true
|
|
648
|
+
* @task T9411
|
|
649
|
+
*/
|
|
650
|
+
cooperativeWriteBack?: boolean;
|
|
591
651
|
}
|
|
592
652
|
|
|
593
653
|
/**
|
package/src/credentials.ts
CHANGED
|
@@ -32,6 +32,16 @@ export interface ClaudeCodeOAuthBlock {
|
|
|
32
32
|
expiresAt?: number;
|
|
33
33
|
/** Refresh token for obtaining new access tokens. Optional. */
|
|
34
34
|
refreshToken?: string;
|
|
35
|
+
/**
|
|
36
|
+
* OAuth scopes granted to the token, e.g. `['user:inference']`.
|
|
37
|
+
*
|
|
38
|
+
* Claude Code >= 2.1.81 requires the `user:inference` scope on its OAuth
|
|
39
|
+
* tokens; cooperative write-back (T9411) preserves whatever scopes are
|
|
40
|
+
* already on disk so we never strip the field on refresh.
|
|
41
|
+
*
|
|
42
|
+
* @task T9411
|
|
43
|
+
*/
|
|
44
|
+
scopes?: string[];
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
/**
|
|
@@ -47,6 +57,16 @@ export interface ParsedClaudeCodeCredential {
|
|
|
47
57
|
expiresAt?: number;
|
|
48
58
|
/** Refresh token, if present in the credentials file. */
|
|
49
59
|
refreshToken?: string;
|
|
60
|
+
/**
|
|
61
|
+
* OAuth scopes granted to the token, if present in the credentials file.
|
|
62
|
+
*
|
|
63
|
+
* Preserved verbatim by the parser — `parseClaudeCodeCredentials` does not
|
|
64
|
+
* filter or normalize the array. Cooperative write-back (T9411) relies on
|
|
65
|
+
* this to keep Claude Code's `user:inference` scope intact across refreshes.
|
|
66
|
+
*
|
|
67
|
+
* @task T9411
|
|
68
|
+
*/
|
|
69
|
+
scopes?: string[];
|
|
50
70
|
}
|
|
51
71
|
|
|
52
72
|
// ---------------------------------------------------------------------------
|
|
@@ -103,10 +123,19 @@ export function parseClaudeCodeCredentials(
|
|
|
103
123
|
? block['refreshToken']
|
|
104
124
|
: undefined;
|
|
105
125
|
|
|
126
|
+
// T9411 — preserve `scopes` verbatim so cooperative write-back keeps
|
|
127
|
+
// Claude Code's `user:inference` grant intact across refreshes.
|
|
128
|
+
const rawScopes = block['scopes'];
|
|
129
|
+
const scopes =
|
|
130
|
+
Array.isArray(rawScopes) && rawScopes.every((s) => typeof s === 'string')
|
|
131
|
+
? (rawScopes as string[])
|
|
132
|
+
: undefined;
|
|
133
|
+
|
|
106
134
|
return {
|
|
107
135
|
accessToken: accessToken.trim(),
|
|
108
136
|
...(expiresAt !== undefined ? { expiresAt } : {}),
|
|
109
137
|
...(refreshToken !== undefined ? { refreshToken } : {}),
|
|
138
|
+
...(scopes !== undefined ? { scopes } : {}),
|
|
110
139
|
};
|
|
111
140
|
} catch {
|
|
112
141
|
return null;
|