riverbankcms 0.1.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/README.md +21 -0
- package/dist/acceptance/matrix.mjs +784 -0
- package/dist/cli/index.mjs +110989 -0
- package/dist/cli/init-docs/content/agents-section.md +67 -0
- package/dist/cli/init-docs/content/cli-reference.md +1238 -0
- package/dist/cli/init-docs/content/content-management.md +792 -0
- package/dist/cli/init-docs/content/context-brand.md +125 -0
- package/dist/cli/init-docs/content/context-brief.md +77 -0
- package/dist/cli/init-docs/content/context-knowledge.md +111 -0
- package/dist/cli/init-docs/content/getting-started.md +171 -0
- package/dist/cli/init-docs/content/site-workflows-readme.md +96 -0
- package/dist/cli/init-docs/content/workflow-add-block.md +299 -0
- package/dist/cli/init-docs/content/workflow-agent-safe-sync.md +83 -0
- package/dist/cli/init-docs/content/workflow-block-extensions.md +370 -0
- package/dist/cli/init-docs/content/workflow-cmsify-page.md +357 -0
- package/dist/cli/init-docs/content/workflow-content-types.md +330 -0
- package/dist/cli/init-docs/content/workflow-create-page.md +212 -0
- package/dist/cli/init-docs/content/workflow-custom-block.md +470 -0
- package/dist/cli/init-docs/content/workflow-editor-workflows.md +130 -0
- package/dist/cli/init-docs/content/workflow-isr-revalidation.md +158 -0
- package/dist/cli/init-docs/content/workflow-preview-mode.md +252 -0
- package/dist/cli/init-docs/content/workflow-publish.md +285 -0
- package/dist/cli/init-docs/content/workflow-remote-setup.md +51 -0
- package/dist/cli/init-docs/content/workflow-templates.md +381 -0
- package/dist/load-config-CRB4AHKq.mjs +5 -0
- package/dist/load-config-r1s4htWu.mjs +87 -0
- package/dist/sdk-peer-DrblJmno.mjs +217 -0
- package/dist/style-Chv9Gcwq.mjs +49167 -0
- package/dist/testing.mjs +5 -0
- package/package.json +76 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//#region src/acceptance/matrix-builders.ts
|
|
3
|
+
const workflow = (scenario, stepId) => ({
|
|
4
|
+
kind: "scratch_workflow",
|
|
5
|
+
scenario,
|
|
6
|
+
stepId
|
|
7
|
+
});
|
|
8
|
+
const localAdapter = (reason) => ({
|
|
9
|
+
kind: "local_adapter",
|
|
10
|
+
reason
|
|
11
|
+
});
|
|
12
|
+
const exploratory = (reason) => ({
|
|
13
|
+
kind: "exploratory_only",
|
|
14
|
+
reason
|
|
15
|
+
});
|
|
16
|
+
const scratchExecute = (args, options = {}) => ({
|
|
17
|
+
kind: "scratch_execute",
|
|
18
|
+
representative: {
|
|
19
|
+
args,
|
|
20
|
+
output: options.output ?? "json-envelope",
|
|
21
|
+
...options
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const scratchDryRun = (args, options = {}) => ({
|
|
25
|
+
kind: "scratch_dry_run",
|
|
26
|
+
representative: {
|
|
27
|
+
args,
|
|
28
|
+
output: options.output ?? "json-envelope",
|
|
29
|
+
...options
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const literal = (value) => ({
|
|
33
|
+
kind: "literal",
|
|
34
|
+
value
|
|
35
|
+
});
|
|
36
|
+
const capture = (stepId, ...path) => ({
|
|
37
|
+
kind: "capture",
|
|
38
|
+
stepId,
|
|
39
|
+
path
|
|
40
|
+
});
|
|
41
|
+
const commandStep = (id, path, args, options = {}) => ({
|
|
42
|
+
kind: "command",
|
|
43
|
+
id,
|
|
44
|
+
path,
|
|
45
|
+
args: args.map((arg) => typeof arg === "string" ? literal(arg) : arg),
|
|
46
|
+
output: options.output ?? "json-envelope",
|
|
47
|
+
...options
|
|
48
|
+
});
|
|
49
|
+
const writeFileStep = (id, path, content) => ({
|
|
50
|
+
kind: "write_file",
|
|
51
|
+
id,
|
|
52
|
+
path,
|
|
53
|
+
content: `${JSON.stringify(content, null, 2)}\n`
|
|
54
|
+
});
|
|
55
|
+
const richText = (text) => ({
|
|
56
|
+
type: "doc",
|
|
57
|
+
content: [{
|
|
58
|
+
type: "paragraph",
|
|
59
|
+
content: [{
|
|
60
|
+
type: "text",
|
|
61
|
+
text
|
|
62
|
+
}]
|
|
63
|
+
}]
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/acceptance/manifest-scenario.ts
|
|
68
|
+
const manifestFixture = {
|
|
69
|
+
blocks: [{
|
|
70
|
+
id: "custom.acceptance",
|
|
71
|
+
title: "Acceptance block",
|
|
72
|
+
titleSource: null,
|
|
73
|
+
description: null,
|
|
74
|
+
category: "marketing",
|
|
75
|
+
icon: null,
|
|
76
|
+
tags: null,
|
|
77
|
+
fields: [{
|
|
78
|
+
id: "headline",
|
|
79
|
+
type: "text",
|
|
80
|
+
label: "Headline",
|
|
81
|
+
description: null,
|
|
82
|
+
required: true,
|
|
83
|
+
defaultValue: null,
|
|
84
|
+
multiline: false,
|
|
85
|
+
maxLength: null
|
|
86
|
+
}],
|
|
87
|
+
layout: {
|
|
88
|
+
type: "section",
|
|
89
|
+
props: null,
|
|
90
|
+
children: [{
|
|
91
|
+
type: "text",
|
|
92
|
+
props: null,
|
|
93
|
+
children: null,
|
|
94
|
+
$bind: {
|
|
95
|
+
from: "content.headline",
|
|
96
|
+
fallback: null,
|
|
97
|
+
transforms: null
|
|
98
|
+
},
|
|
99
|
+
$repeat: null,
|
|
100
|
+
$when: null
|
|
101
|
+
}],
|
|
102
|
+
$bind: null,
|
|
103
|
+
$repeat: null,
|
|
104
|
+
$when: null
|
|
105
|
+
}
|
|
106
|
+
}],
|
|
107
|
+
themePatch: null,
|
|
108
|
+
customCssRules: null,
|
|
109
|
+
customCssAtRules: null,
|
|
110
|
+
fixRationale: null
|
|
111
|
+
};
|
|
112
|
+
const manifestScenario = {
|
|
113
|
+
id: "manifest-validation",
|
|
114
|
+
steps: [writeFileStep("fixture", ".acceptance/manifest.json", manifestFixture), commandStep("validate", "manifest validate", [
|
|
115
|
+
"manifest",
|
|
116
|
+
"validate",
|
|
117
|
+
"--file",
|
|
118
|
+
".acceptance/manifest.json",
|
|
119
|
+
"--json"
|
|
120
|
+
])]
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/acceptance/style-scenario.ts
|
|
125
|
+
const styleScenario = {
|
|
126
|
+
id: "style-apply",
|
|
127
|
+
steps: [{
|
|
128
|
+
kind: "read_style_selection",
|
|
129
|
+
id: "current-selection"
|
|
130
|
+
}, commandStep("apply", "style apply", [
|
|
131
|
+
"style",
|
|
132
|
+
"apply",
|
|
133
|
+
"--site-style-id",
|
|
134
|
+
"site-style:calm-studio",
|
|
135
|
+
"--base-selection-version",
|
|
136
|
+
capture("current-selection", "currentSelection", "selectionVersion"),
|
|
137
|
+
"--env=local",
|
|
138
|
+
"--json"
|
|
139
|
+
])]
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/acceptance/content-scenario.ts
|
|
144
|
+
const contentEditPage = {
|
|
145
|
+
identifier: "acceptance-content-edit",
|
|
146
|
+
title: "Content edit fixture",
|
|
147
|
+
path: "/acceptance-content-edit",
|
|
148
|
+
blocks: [{
|
|
149
|
+
identifier: "acceptance-first",
|
|
150
|
+
kind: "block.body-text",
|
|
151
|
+
data: { body: richText("First block") }
|
|
152
|
+
}, {
|
|
153
|
+
identifier: "acceptance-second",
|
|
154
|
+
kind: "block.body-text",
|
|
155
|
+
data: { body: richText("Second block") }
|
|
156
|
+
}]
|
|
157
|
+
};
|
|
158
|
+
const contentScenario = {
|
|
159
|
+
id: "local-content-edits",
|
|
160
|
+
steps: [
|
|
161
|
+
writeFileStep("remove-fixture", "content/pages/acceptance-content-edit.json", contentEditPage),
|
|
162
|
+
commandStep("remove", "content edit remove-page-block", [
|
|
163
|
+
"content",
|
|
164
|
+
"edit",
|
|
165
|
+
"remove-page-block",
|
|
166
|
+
"acceptance-content-edit",
|
|
167
|
+
"acceptance-first",
|
|
168
|
+
"--content-dir",
|
|
169
|
+
"content",
|
|
170
|
+
"--write",
|
|
171
|
+
"--json"
|
|
172
|
+
], { changedPath: "content/pages/acceptance-content-edit.json" }),
|
|
173
|
+
writeFileStep("move-fixture", "content/pages/acceptance-content-edit.json", contentEditPage),
|
|
174
|
+
commandStep("move", "content edit move-page-block", [
|
|
175
|
+
"content",
|
|
176
|
+
"edit",
|
|
177
|
+
"move-page-block",
|
|
178
|
+
"acceptance-content-edit",
|
|
179
|
+
"acceptance-first",
|
|
180
|
+
"--after",
|
|
181
|
+
"acceptance-second",
|
|
182
|
+
"--content-dir",
|
|
183
|
+
"content",
|
|
184
|
+
"--write",
|
|
185
|
+
"--json"
|
|
186
|
+
], { changedPath: "content/pages/acceptance-content-edit.json" }),
|
|
187
|
+
writeFileStep("field-fixture", "content/pages/acceptance-content-edit.json", contentEditPage),
|
|
188
|
+
commandStep("field", "content edit set-page-field", [
|
|
189
|
+
"content",
|
|
190
|
+
"edit",
|
|
191
|
+
"set-page-field",
|
|
192
|
+
"acceptance-content-edit",
|
|
193
|
+
"title",
|
|
194
|
+
"--value",
|
|
195
|
+
"Edited by CLI acceptance",
|
|
196
|
+
"--content-dir",
|
|
197
|
+
"content",
|
|
198
|
+
"--write",
|
|
199
|
+
"--json"
|
|
200
|
+
], { changedPath: "content/pages/acceptance-content-edit.json" })
|
|
201
|
+
]
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/acceptance/navigation-scenario.ts
|
|
206
|
+
const navigationScenario = {
|
|
207
|
+
id: "navigation-lifecycle",
|
|
208
|
+
steps: [
|
|
209
|
+
commandStep("upsert", "navigation upsert", [
|
|
210
|
+
"navigation",
|
|
211
|
+
"upsert",
|
|
212
|
+
"CLI Acceptance Menu",
|
|
213
|
+
"--identifier",
|
|
214
|
+
"cli-acceptance-menu",
|
|
215
|
+
"--data",
|
|
216
|
+
JSON.stringify([{
|
|
217
|
+
label: "Acceptance link",
|
|
218
|
+
link: {
|
|
219
|
+
kind: "external",
|
|
220
|
+
href: "https://example.com/acceptance"
|
|
221
|
+
}
|
|
222
|
+
}]),
|
|
223
|
+
"--env=local",
|
|
224
|
+
"--json"
|
|
225
|
+
]),
|
|
226
|
+
commandStep("get", "navigation get", [
|
|
227
|
+
"navigation",
|
|
228
|
+
"get",
|
|
229
|
+
capture("upsert", "result", "name"),
|
|
230
|
+
"--env=local",
|
|
231
|
+
"--json"
|
|
232
|
+
]),
|
|
233
|
+
commandStep("delete", "navigation delete", [
|
|
234
|
+
"navigation",
|
|
235
|
+
"delete",
|
|
236
|
+
capture("upsert", "result", "id"),
|
|
237
|
+
"--yes",
|
|
238
|
+
"--env=local",
|
|
239
|
+
"--json"
|
|
240
|
+
])
|
|
241
|
+
]
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/acceptance/matrix.ts
|
|
246
|
+
const entryScenario = {
|
|
247
|
+
id: "entry-lifecycle",
|
|
248
|
+
steps: [
|
|
249
|
+
commandStep("upsert", "entry upsert", [
|
|
250
|
+
"entry",
|
|
251
|
+
"upsert",
|
|
252
|
+
"post",
|
|
253
|
+
"acceptance-entry",
|
|
254
|
+
"--data",
|
|
255
|
+
JSON.stringify({
|
|
256
|
+
excerpt: "Entry created by the installed CLI acceptance workflow.",
|
|
257
|
+
body: richText("Acceptance entry body.")
|
|
258
|
+
}),
|
|
259
|
+
"--env=local",
|
|
260
|
+
"--json"
|
|
261
|
+
]),
|
|
262
|
+
commandStep("publish", "entry publish", [
|
|
263
|
+
"entry",
|
|
264
|
+
"publish",
|
|
265
|
+
"post",
|
|
266
|
+
capture("upsert", "result", "identifier"),
|
|
267
|
+
"--env=local",
|
|
268
|
+
"--json"
|
|
269
|
+
]),
|
|
270
|
+
commandStep("get", "entry get", [
|
|
271
|
+
"entry",
|
|
272
|
+
"get",
|
|
273
|
+
"post",
|
|
274
|
+
capture("upsert", "result", "identifier"),
|
|
275
|
+
"--env=local",
|
|
276
|
+
"--json"
|
|
277
|
+
]),
|
|
278
|
+
commandStep("unpublish", "entry unpublish", [
|
|
279
|
+
"entry",
|
|
280
|
+
"unpublish",
|
|
281
|
+
"post",
|
|
282
|
+
capture("upsert", "result", "identifier"),
|
|
283
|
+
"--env=local",
|
|
284
|
+
"--json"
|
|
285
|
+
]),
|
|
286
|
+
commandStep("delete", "delete entry", [
|
|
287
|
+
"delete",
|
|
288
|
+
"entry",
|
|
289
|
+
"post",
|
|
290
|
+
capture("upsert", "result", "identifier"),
|
|
291
|
+
"--yes",
|
|
292
|
+
"--env=local",
|
|
293
|
+
"--json"
|
|
294
|
+
])
|
|
295
|
+
]
|
|
296
|
+
};
|
|
297
|
+
const pageScenario = {
|
|
298
|
+
id: "page-lifecycle",
|
|
299
|
+
steps: [
|
|
300
|
+
commandStep("upsert", "page upsert", [
|
|
301
|
+
"page",
|
|
302
|
+
"upsert",
|
|
303
|
+
"acceptance-page",
|
|
304
|
+
"--title",
|
|
305
|
+
"CLI acceptance page",
|
|
306
|
+
"--path",
|
|
307
|
+
"/cli-acceptance-page",
|
|
308
|
+
"--env=local",
|
|
309
|
+
"--json"
|
|
310
|
+
]),
|
|
311
|
+
commandStep("publish", "page publish", [
|
|
312
|
+
"page",
|
|
313
|
+
"publish",
|
|
314
|
+
capture("upsert", "result", "identifier"),
|
|
315
|
+
"--env=local",
|
|
316
|
+
"--json"
|
|
317
|
+
]),
|
|
318
|
+
commandStep("unpublish", "page unpublish", [
|
|
319
|
+
"page",
|
|
320
|
+
"unpublish",
|
|
321
|
+
capture("upsert", "result", "identifier"),
|
|
322
|
+
"--env=local",
|
|
323
|
+
"--json"
|
|
324
|
+
]),
|
|
325
|
+
commandStep("get", "page get", [
|
|
326
|
+
"page",
|
|
327
|
+
"get",
|
|
328
|
+
capture("upsert", "result", "identifier"),
|
|
329
|
+
"--env=local",
|
|
330
|
+
"--json"
|
|
331
|
+
])
|
|
332
|
+
]
|
|
333
|
+
};
|
|
334
|
+
const blockScenario = {
|
|
335
|
+
id: "block-lifecycle",
|
|
336
|
+
steps: [
|
|
337
|
+
commandStep("page", "page upsert", [
|
|
338
|
+
"page",
|
|
339
|
+
"upsert",
|
|
340
|
+
"acceptance-block-page",
|
|
341
|
+
"--title",
|
|
342
|
+
"CLI acceptance block page",
|
|
343
|
+
"--path",
|
|
344
|
+
"/cli-acceptance-block-page",
|
|
345
|
+
"--env=local",
|
|
346
|
+
"--json"
|
|
347
|
+
]),
|
|
348
|
+
commandStep("first", "block upsert", [
|
|
349
|
+
"block",
|
|
350
|
+
"upsert",
|
|
351
|
+
capture("page", "result", "identifier"),
|
|
352
|
+
"acceptance-block-first",
|
|
353
|
+
"--kind",
|
|
354
|
+
"block.body-text",
|
|
355
|
+
"--data",
|
|
356
|
+
JSON.stringify({ body: richText("First block") }),
|
|
357
|
+
"--env=local",
|
|
358
|
+
"--json"
|
|
359
|
+
]),
|
|
360
|
+
commandStep("second", "block upsert", [
|
|
361
|
+
"block",
|
|
362
|
+
"upsert",
|
|
363
|
+
capture("page", "result", "identifier"),
|
|
364
|
+
"acceptance-block-second",
|
|
365
|
+
"--kind",
|
|
366
|
+
"block.body-text",
|
|
367
|
+
"--data",
|
|
368
|
+
JSON.stringify({ body: richText("Second block") }),
|
|
369
|
+
"--env=local",
|
|
370
|
+
"--json"
|
|
371
|
+
]),
|
|
372
|
+
commandStep("reorder", "block reorder", [
|
|
373
|
+
"block",
|
|
374
|
+
"reorder",
|
|
375
|
+
capture("page", "result", "identifier"),
|
|
376
|
+
capture("second", "result", "identifier"),
|
|
377
|
+
capture("first", "result", "identifier"),
|
|
378
|
+
"--env=local",
|
|
379
|
+
"--json"
|
|
380
|
+
]),
|
|
381
|
+
commandStep("get", "block get", [
|
|
382
|
+
"block",
|
|
383
|
+
"get",
|
|
384
|
+
capture("page", "result", "identifier"),
|
|
385
|
+
capture("first", "result", "identifier"),
|
|
386
|
+
"--env=local",
|
|
387
|
+
"--json"
|
|
388
|
+
]),
|
|
389
|
+
commandStep("delete", "delete block", [
|
|
390
|
+
"delete",
|
|
391
|
+
"block",
|
|
392
|
+
capture("page", "result", "identifier"),
|
|
393
|
+
capture("first", "result", "identifier"),
|
|
394
|
+
"--yes",
|
|
395
|
+
"--env=local",
|
|
396
|
+
"--json"
|
|
397
|
+
])
|
|
398
|
+
]
|
|
399
|
+
};
|
|
400
|
+
const eventScenario = {
|
|
401
|
+
id: "event-occurrence-lifecycle",
|
|
402
|
+
steps: [
|
|
403
|
+
commandStep("upsert", "event upsert", [
|
|
404
|
+
"event",
|
|
405
|
+
"upsert",
|
|
406
|
+
"acceptance-event",
|
|
407
|
+
"--data",
|
|
408
|
+
JSON.stringify({
|
|
409
|
+
title: "CLI acceptance event",
|
|
410
|
+
slug: "acceptance-event",
|
|
411
|
+
schedule: {
|
|
412
|
+
recurrenceRule: null,
|
|
413
|
+
defaultStartTime: "10:00:00",
|
|
414
|
+
durationMinutes: 60
|
|
415
|
+
},
|
|
416
|
+
pricing: { requiresPayment: false }
|
|
417
|
+
}),
|
|
418
|
+
"--env=local",
|
|
419
|
+
"--json"
|
|
420
|
+
]),
|
|
421
|
+
{
|
|
422
|
+
kind: "known_identifier",
|
|
423
|
+
id: "event-identifier",
|
|
424
|
+
value: "acceptance-event"
|
|
425
|
+
},
|
|
426
|
+
commandStep("get", "event get", [
|
|
427
|
+
"event",
|
|
428
|
+
"get",
|
|
429
|
+
capture("event-identifier"),
|
|
430
|
+
"--env=local",
|
|
431
|
+
"--json"
|
|
432
|
+
]),
|
|
433
|
+
commandStep("list-occurrences", "event occurrence list", [
|
|
434
|
+
"event",
|
|
435
|
+
"occurrence",
|
|
436
|
+
"list",
|
|
437
|
+
capture("event-identifier"),
|
|
438
|
+
"--env=local",
|
|
439
|
+
"--json"
|
|
440
|
+
]),
|
|
441
|
+
commandStep("add-occurrence", "event occurrence add", [
|
|
442
|
+
"event",
|
|
443
|
+
"occurrence",
|
|
444
|
+
"add",
|
|
445
|
+
capture("event-identifier"),
|
|
446
|
+
"--starts-at",
|
|
447
|
+
"2026-12-10T10:00:00Z",
|
|
448
|
+
"--duration-minutes",
|
|
449
|
+
"60",
|
|
450
|
+
"--env=local",
|
|
451
|
+
"--json"
|
|
452
|
+
]),
|
|
453
|
+
commandStep("update-occurrence", "event occurrence update", [
|
|
454
|
+
"event",
|
|
455
|
+
"occurrence",
|
|
456
|
+
"update",
|
|
457
|
+
capture("event-identifier"),
|
|
458
|
+
capture("add-occurrence", "result", "id"),
|
|
459
|
+
"--capacity",
|
|
460
|
+
"20",
|
|
461
|
+
"--env=local",
|
|
462
|
+
"--json"
|
|
463
|
+
]),
|
|
464
|
+
commandStep("cancel-occurrence", "event occurrence cancel", [
|
|
465
|
+
"event",
|
|
466
|
+
"occurrence",
|
|
467
|
+
"cancel",
|
|
468
|
+
capture("event-identifier"),
|
|
469
|
+
capture("add-occurrence", "result", "id"),
|
|
470
|
+
"--env=local",
|
|
471
|
+
"--json"
|
|
472
|
+
]),
|
|
473
|
+
commandStep("delete-occurrence", "event occurrence delete", [
|
|
474
|
+
"event",
|
|
475
|
+
"occurrence",
|
|
476
|
+
"delete",
|
|
477
|
+
capture("event-identifier"),
|
|
478
|
+
capture("add-occurrence", "result", "id"),
|
|
479
|
+
"--yes",
|
|
480
|
+
"--env=local",
|
|
481
|
+
"--json"
|
|
482
|
+
]),
|
|
483
|
+
commandStep("cancel-event", "event cancel", [
|
|
484
|
+
"event",
|
|
485
|
+
"cancel",
|
|
486
|
+
capture("event-identifier"),
|
|
487
|
+
"--env=local",
|
|
488
|
+
"--json"
|
|
489
|
+
]),
|
|
490
|
+
commandStep("delete-event", "event delete", [
|
|
491
|
+
"event",
|
|
492
|
+
"delete",
|
|
493
|
+
capture("event-identifier"),
|
|
494
|
+
"--yes",
|
|
495
|
+
"--env=local",
|
|
496
|
+
"--json"
|
|
497
|
+
])
|
|
498
|
+
]
|
|
499
|
+
};
|
|
500
|
+
/**
|
|
501
|
+
* Every entry is keyed by the complete Commander leaf path. The automated
|
|
502
|
+
* runner executes representatives and grouped scratch workflows; provider and
|
|
503
|
+
* uninitialized-state commands remain explicit guided QA cases instead of being
|
|
504
|
+
* faked with made-up identifiers.
|
|
505
|
+
*/
|
|
506
|
+
const acceptanceTuples = [
|
|
507
|
+
["push-config", scratchDryRun([
|
|
508
|
+
"push-config",
|
|
509
|
+
"--env=both",
|
|
510
|
+
"--dry-run",
|
|
511
|
+
"--json"
|
|
512
|
+
])],
|
|
513
|
+
["pull", scratchDryRun([
|
|
514
|
+
"pull",
|
|
515
|
+
"pages",
|
|
516
|
+
"--env=local",
|
|
517
|
+
"--dry-run",
|
|
518
|
+
"--json"
|
|
519
|
+
], {
|
|
520
|
+
expectedExitCode: 1,
|
|
521
|
+
untouchedPath: "content/pages/home.json"
|
|
522
|
+
})],
|
|
523
|
+
["push", scratchDryRun([
|
|
524
|
+
"push",
|
|
525
|
+
"pages",
|
|
526
|
+
"--env=both",
|
|
527
|
+
"--dry-run",
|
|
528
|
+
"--json"
|
|
529
|
+
])],
|
|
530
|
+
["entry upsert", workflow(entryScenario, "upsert")],
|
|
531
|
+
["entry publish", workflow(entryScenario, "publish")],
|
|
532
|
+
["entry unpublish", workflow(entryScenario, "unpublish")],
|
|
533
|
+
["entry get", workflow(entryScenario, "get")],
|
|
534
|
+
["entry list", scratchExecute([
|
|
535
|
+
"entry",
|
|
536
|
+
"list",
|
|
537
|
+
"post",
|
|
538
|
+
"--env=local",
|
|
539
|
+
"--json"
|
|
540
|
+
])],
|
|
541
|
+
["entry scaffold", scratchExecute([
|
|
542
|
+
"entry",
|
|
543
|
+
"scaffold",
|
|
544
|
+
"post",
|
|
545
|
+
"--env=local",
|
|
546
|
+
"--json"
|
|
547
|
+
])],
|
|
548
|
+
["page upsert", workflow(pageScenario, "upsert")],
|
|
549
|
+
["page publish", workflow(pageScenario, "publish")],
|
|
550
|
+
["page unpublish", workflow(pageScenario, "unpublish")],
|
|
551
|
+
["page get", workflow(pageScenario, "get")],
|
|
552
|
+
["page list", scratchExecute([
|
|
553
|
+
"page",
|
|
554
|
+
"list",
|
|
555
|
+
"--env=local",
|
|
556
|
+
"--json"
|
|
557
|
+
])],
|
|
558
|
+
["block upsert", workflow(blockScenario, "first")],
|
|
559
|
+
["block reorder", workflow(blockScenario, "reorder")],
|
|
560
|
+
["block list", scratchExecute([
|
|
561
|
+
"block",
|
|
562
|
+
"list",
|
|
563
|
+
"home",
|
|
564
|
+
"--env=local",
|
|
565
|
+
"--json"
|
|
566
|
+
])],
|
|
567
|
+
["block get", workflow(blockScenario, "get")],
|
|
568
|
+
["navigation upsert", workflow(navigationScenario, "upsert")],
|
|
569
|
+
["navigation delete", workflow(navigationScenario, "delete")],
|
|
570
|
+
["navigation get", workflow(navigationScenario, "get")],
|
|
571
|
+
["navigation list", scratchExecute([
|
|
572
|
+
"navigation",
|
|
573
|
+
"list",
|
|
574
|
+
"--env=local",
|
|
575
|
+
"--json"
|
|
576
|
+
])],
|
|
577
|
+
["delete entry", workflow(entryScenario, "delete")],
|
|
578
|
+
["delete block", workflow(blockScenario, "delete")],
|
|
579
|
+
["content edit remove-page-block", workflow(contentScenario, "remove")],
|
|
580
|
+
["content edit move-page-block", workflow(contentScenario, "move")],
|
|
581
|
+
["content edit set-page-field", workflow(contentScenario, "field")],
|
|
582
|
+
["drafts", scratchExecute([
|
|
583
|
+
"drafts",
|
|
584
|
+
"--env=local",
|
|
585
|
+
"--json"
|
|
586
|
+
])],
|
|
587
|
+
["init-docs", scratchExecute([
|
|
588
|
+
"init-docs",
|
|
589
|
+
"--path",
|
|
590
|
+
".acceptance-docs",
|
|
591
|
+
"--json"
|
|
592
|
+
], {
|
|
593
|
+
cwd: "nested",
|
|
594
|
+
output: "non-empty"
|
|
595
|
+
})],
|
|
596
|
+
["identifiers backfill", scratchExecute([
|
|
597
|
+
"identifiers",
|
|
598
|
+
"backfill",
|
|
599
|
+
"--env=local",
|
|
600
|
+
"--json"
|
|
601
|
+
])],
|
|
602
|
+
["deploy", localAdapter("Deploy provider/git effects require an injected adapter; use the deploy command contract tests.")],
|
|
603
|
+
["content-type list", scratchExecute([
|
|
604
|
+
"content-type",
|
|
605
|
+
"list",
|
|
606
|
+
"--env=local",
|
|
607
|
+
"--json"
|
|
608
|
+
])],
|
|
609
|
+
["verify", scratchExecute([
|
|
610
|
+
"verify",
|
|
611
|
+
"--env=local",
|
|
612
|
+
"--json"
|
|
613
|
+
], { expectedExitCode: 1 })],
|
|
614
|
+
["publish-all", scratchDryRun([
|
|
615
|
+
"publish-all",
|
|
616
|
+
"post",
|
|
617
|
+
"--env=local",
|
|
618
|
+
"--dry-run",
|
|
619
|
+
"--json"
|
|
620
|
+
])],
|
|
621
|
+
["audit", scratchExecute([
|
|
622
|
+
"audit",
|
|
623
|
+
"--env=local",
|
|
624
|
+
"--json"
|
|
625
|
+
])],
|
|
626
|
+
["compare", scratchExecute([
|
|
627
|
+
"compare",
|
|
628
|
+
"entries",
|
|
629
|
+
"post",
|
|
630
|
+
"--env=local",
|
|
631
|
+
"--json"
|
|
632
|
+
], { expectedExitCode: 1 })],
|
|
633
|
+
["event list", scratchExecute([
|
|
634
|
+
"event",
|
|
635
|
+
"list",
|
|
636
|
+
"--env=local",
|
|
637
|
+
"--json"
|
|
638
|
+
])],
|
|
639
|
+
["event get", workflow(eventScenario, "get")],
|
|
640
|
+
["event upsert", workflow(eventScenario, "upsert")],
|
|
641
|
+
["event cancel", workflow(eventScenario, "cancel-event")],
|
|
642
|
+
["event delete", workflow(eventScenario, "delete-event")],
|
|
643
|
+
["event occurrence list", workflow(eventScenario, "list-occurrences")],
|
|
644
|
+
["event occurrence add", workflow(eventScenario, "add-occurrence")],
|
|
645
|
+
["event occurrence update", workflow(eventScenario, "update-occurrence")],
|
|
646
|
+
["event occurrence cancel", workflow(eventScenario, "cancel-occurrence")],
|
|
647
|
+
["event occurrence delete", workflow(eventScenario, "delete-occurrence")],
|
|
648
|
+
["style list", scratchExecute(["style", "list"], {
|
|
649
|
+
cwd: "nested",
|
|
650
|
+
output: "non-empty"
|
|
651
|
+
})],
|
|
652
|
+
["style init", exploratory("Requires a curated style identifier and mutates generated site theme state.")],
|
|
653
|
+
["style apply", workflow(styleScenario, "apply")],
|
|
654
|
+
["webhooks setup", scratchDryRun([
|
|
655
|
+
"webhooks",
|
|
656
|
+
"setup",
|
|
657
|
+
"--env=local",
|
|
658
|
+
"--url",
|
|
659
|
+
"https://example.com/revalidate",
|
|
660
|
+
"--dry-run",
|
|
661
|
+
"--json"
|
|
662
|
+
])],
|
|
663
|
+
["manifest generate", localAdapter("AI generation requires the fake model adapter; validate local manifest output in guided QA.")],
|
|
664
|
+
["manifest validate", workflow(manifestScenario, "validate")],
|
|
665
|
+
["env status", scratchExecute([
|
|
666
|
+
"env",
|
|
667
|
+
"status",
|
|
668
|
+
"--env=both",
|
|
669
|
+
"--json"
|
|
670
|
+
])],
|
|
671
|
+
["setup plan", scratchExecute([
|
|
672
|
+
"setup",
|
|
673
|
+
"plan",
|
|
674
|
+
"--env=both",
|
|
675
|
+
"--json"
|
|
676
|
+
])],
|
|
677
|
+
["migrate entries", scratchDryRun([
|
|
678
|
+
"migrate",
|
|
679
|
+
"entries",
|
|
680
|
+
"--dry-run"
|
|
681
|
+
], {
|
|
682
|
+
cwd: "nested",
|
|
683
|
+
output: "non-empty"
|
|
684
|
+
})],
|
|
685
|
+
["migrate events", scratchDryRun([
|
|
686
|
+
"migrate",
|
|
687
|
+
"events",
|
|
688
|
+
"--dry-run"
|
|
689
|
+
], {
|
|
690
|
+
cwd: "nested",
|
|
691
|
+
output: "non-empty"
|
|
692
|
+
})]
|
|
693
|
+
];
|
|
694
|
+
const CLI_ACCEPTANCE_CASES = acceptanceTuples.map(([path, disposition]) => ({
|
|
695
|
+
path,
|
|
696
|
+
disposition
|
|
697
|
+
}));
|
|
698
|
+
function leafCommandPaths(program) {
|
|
699
|
+
const paths = [];
|
|
700
|
+
const visit = (command, parent) => {
|
|
701
|
+
const path = [...parent, command.name()];
|
|
702
|
+
if (command.commands.length === 0) {
|
|
703
|
+
paths.push(path.slice(1).join(" "));
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
command.commands.forEach((child) => visit(child, path));
|
|
707
|
+
};
|
|
708
|
+
visit(program, []);
|
|
709
|
+
return paths;
|
|
710
|
+
}
|
|
711
|
+
function assertRepresentativeParity(entry, disposition) {
|
|
712
|
+
if (disposition.representative.args.length === 0) {
|
|
713
|
+
throw new Error(`CLI acceptance case ${entry.path} has no representative scratch invocation`);
|
|
714
|
+
}
|
|
715
|
+
const pathTokens = entry.path.split(" ");
|
|
716
|
+
const representativePath = disposition.representative.args.slice(0, pathTokens.length);
|
|
717
|
+
if (!pathTokens.every((token, index) => representativePath[index] === token)) {
|
|
718
|
+
throw new Error(`CLI acceptance case ${entry.path} executes a different representative command`);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
function assertWorkflowScenarioReferences(scenario) {
|
|
722
|
+
const scenarioIndex = new Map(scenario.steps.map((step, index) => [step.id, index]));
|
|
723
|
+
for (const [index, step] of scenario.steps.entries()) {
|
|
724
|
+
if (step.kind !== "command") continue;
|
|
725
|
+
for (const argument of step.args) {
|
|
726
|
+
if (argument.kind !== "capture") continue;
|
|
727
|
+
const captureIndex = scenarioIndex.get(argument.stepId);
|
|
728
|
+
if (captureIndex === undefined || captureIndex >= index) {
|
|
729
|
+
throw new Error(`CLI acceptance scenario ${scenario.id} captures ${argument.stepId} before it is produced`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
function assertWorkflowParity(entry, disposition) {
|
|
735
|
+
const { scenario, stepId } = disposition;
|
|
736
|
+
if (scenario.id.trim().length === 0 || scenario.steps.length === 0) {
|
|
737
|
+
throw new Error(`CLI acceptance case ${entry.path} has an empty workflow scenario`);
|
|
738
|
+
}
|
|
739
|
+
const steps = new Map();
|
|
740
|
+
for (const step of scenario.steps) {
|
|
741
|
+
if (steps.has(step.id)) throw new Error(`CLI acceptance scenario ${scenario.id} repeats step ${step.id}`);
|
|
742
|
+
steps.set(step.id, step);
|
|
743
|
+
}
|
|
744
|
+
const target = steps.get(stepId);
|
|
745
|
+
if (!target || target.kind !== "command") {
|
|
746
|
+
throw new Error(`CLI acceptance case ${entry.path} targets unknown workflow command step ${stepId}`);
|
|
747
|
+
}
|
|
748
|
+
if (target.path !== entry.path) {
|
|
749
|
+
throw new Error(`CLI acceptance case ${entry.path} targets workflow step ${stepId} (${target.path})`);
|
|
750
|
+
}
|
|
751
|
+
assertWorkflowScenarioReferences(scenario);
|
|
752
|
+
}
|
|
753
|
+
function assertAcceptanceDisposition(entry) {
|
|
754
|
+
switch (entry.disposition.kind) {
|
|
755
|
+
case "scratch_execute":
|
|
756
|
+
case "scratch_dry_run":
|
|
757
|
+
assertRepresentativeParity(entry, entry.disposition);
|
|
758
|
+
return;
|
|
759
|
+
case "scratch_workflow":
|
|
760
|
+
assertWorkflowParity(entry, entry.disposition);
|
|
761
|
+
return;
|
|
762
|
+
case "local_adapter":
|
|
763
|
+
case "exploratory_only":
|
|
764
|
+
if (entry.disposition.reason.trim().length === 0) {
|
|
765
|
+
throw new Error(`CLI acceptance case ${entry.path} has no disposition rationale`);
|
|
766
|
+
}
|
|
767
|
+
return;
|
|
768
|
+
default: {
|
|
769
|
+
const unreachable = entry.disposition;
|
|
770
|
+
throw new Error(`CLI acceptance case ${entry.path} has no safety disposition: ${String(unreachable)}`);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function assertCliAcceptanceParity(program) {
|
|
775
|
+
const actual = new Set(leafCommandPaths(program));
|
|
776
|
+
const expected = new Set(CLI_ACCEPTANCE_CASES.map((entry) => entry.path));
|
|
777
|
+
const missing = [...actual].filter((path) => !expected.has(path));
|
|
778
|
+
const stale = [...expected].filter((path) => !actual.has(path));
|
|
779
|
+
if (missing.length > 0 || stale.length > 0 || expected.size !== CLI_ACCEPTANCE_CASES.length) throw new Error(`CLI acceptance matrix drifted (missing: ${missing.join(", ") || "none"}; stale: ${stale.join(", ") || "none"}).`);
|
|
780
|
+
CLI_ACCEPTANCE_CASES.forEach(assertAcceptanceDisposition);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
//#endregion
|
|
784
|
+
export { CLI_ACCEPTANCE_CASES, assertCliAcceptanceParity, leafCommandPaths };
|