@gordon.gan/specflow 1.4.6-beta → 1.7.0-beta

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.
Files changed (41) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/commands/approval-assemble.d.ts +48 -5
  3. package/dist/cli/commands/approval-assemble.js +347 -34
  4. package/dist/core/approval/assemble.js +64 -17
  5. package/dist/core/approval/bundle.d.ts +9 -0
  6. package/dist/core/approval/bundle.js +172 -0
  7. package/dist/core/approval/forbidden-patterns.d.ts +6 -0
  8. package/dist/core/approval/forbidden-patterns.js +37 -0
  9. package/dist/core/approval/index-schema.d.ts +432 -0
  10. package/dist/core/approval/index-schema.js +103 -0
  11. package/dist/core/approval/index.d.ts +10 -2
  12. package/dist/core/approval/index.js +7 -1
  13. package/dist/core/approval/lint.d.ts +10 -0
  14. package/dist/core/approval/lint.js +302 -0
  15. package/dist/core/approval/paths.d.ts +5 -0
  16. package/dist/core/approval/paths.js +15 -0
  17. package/dist/core/approval/pipeline.d.ts +28 -0
  18. package/dist/core/approval/pipeline.js +146 -0
  19. package/dist/core/approval/playbook-schema.d.ts +182 -0
  20. package/dist/core/approval/playbook-schema.js +51 -0
  21. package/dist/core/approval/render.d.ts +20 -0
  22. package/dist/core/approval/render.js +210 -0
  23. package/dist/core/approval/review-pack.d.ts +26 -0
  24. package/dist/core/approval/review-pack.js +205 -0
  25. package/dist/core/approval/types.d.ts +131 -0
  26. package/dist/integrations/shared/capability-evidence.js +2 -0
  27. package/dist/integrations/shared/parity-manifest.js +2 -0
  28. package/package.json +2 -1
  29. package/prompts/approval/acp-pipeline.md +104 -0
  30. package/prompts/approval/ai-review.md +145 -0
  31. package/prompts/approval/api-guidance.md +179 -0
  32. package/prompts/approval/generate.md +164 -13
  33. package/prompts/approval/multi-repo-guidance.md +238 -0
  34. package/prompts/approval/project-conventions-guidance.md +1 -1
  35. package/prompts/approval/runtime-guidance.md +64 -0
  36. package/prompts/approval/segmented-generation.md +23 -11
  37. package/skills/GUIDANCE_PACKS.md +2 -2
  38. package/skills/specflow-approval/SKILL.md +80 -18
  39. package/templates/approval-index.yaml +41 -0
  40. package/templates/approval-part.md +1 -1
  41. package/templates/approval-playbook.yaml +28 -0
@@ -29,47 +29,88 @@ export declare const approvalIndexSchema: z.ZodObject<{
29
29
  name: z.ZodString;
30
30
  action: z.ZodString;
31
31
  part: z.ZodString;
32
+ repo: z.ZodOptional<z.ZodString>;
32
33
  }, "strip", z.ZodTypeAny, {
33
34
  id: string;
34
35
  name: string;
35
36
  action: string;
36
37
  part: string;
38
+ repo?: string | undefined;
37
39
  }, {
38
40
  id: string;
39
41
  name: string;
40
42
  action: string;
41
43
  part: string;
44
+ repo?: string | undefined;
42
45
  }>, "many">>;
43
46
  interfaces: z.ZodDefault<z.ZodArray<z.ZodObject<{
44
47
  id: z.ZodString;
45
48
  short: z.ZodString;
46
49
  change: z.ZodString;
47
50
  part: z.ZodString;
51
+ repo: z.ZodOptional<z.ZodString>;
52
+ layers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
53
+ pairs_with: z.ZodOptional<z.ZodString>;
54
+ feature_slice: z.ZodOptional<z.ZodString>;
55
+ frozen: z.ZodOptional<z.ZodObject<{
56
+ rpc: z.ZodOptional<z.ZodString>;
57
+ http_path: z.ZodOptional<z.ZodString>;
58
+ status_enum: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
59
+ }, "strip", z.ZodTypeAny, {
60
+ rpc?: string | undefined;
61
+ http_path?: string | undefined;
62
+ status_enum?: string[] | undefined;
63
+ }, {
64
+ rpc?: string | undefined;
65
+ http_path?: string | undefined;
66
+ status_enum?: string[] | undefined;
67
+ }>>;
48
68
  }, "strip", z.ZodTypeAny, {
49
69
  id: string;
50
70
  part: string;
51
71
  short: string;
52
72
  change: string;
73
+ repo?: string | undefined;
74
+ layers?: string[] | undefined;
75
+ pairs_with?: string | undefined;
76
+ feature_slice?: string | undefined;
77
+ frozen?: {
78
+ rpc?: string | undefined;
79
+ http_path?: string | undefined;
80
+ status_enum?: string[] | undefined;
81
+ } | undefined;
53
82
  }, {
54
83
  id: string;
55
84
  part: string;
56
85
  short: string;
57
86
  change: string;
87
+ repo?: string | undefined;
88
+ layers?: string[] | undefined;
89
+ pairs_with?: string | undefined;
90
+ feature_slice?: string | undefined;
91
+ frozen?: {
92
+ rpc?: string | undefined;
93
+ http_path?: string | undefined;
94
+ status_enum?: string[] | undefined;
95
+ } | undefined;
58
96
  }>, "many">>;
59
97
  pages: z.ZodDefault<z.ZodArray<z.ZodObject<{
60
98
  id: z.ZodString;
61
99
  route: z.ZodString;
62
100
  apis: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
63
101
  part: z.ZodString;
102
+ repo: z.ZodOptional<z.ZodString>;
64
103
  }, "strip", z.ZodTypeAny, {
65
104
  id: string;
66
105
  part: string;
67
106
  route: string;
68
107
  apis: string[];
108
+ repo?: string | undefined;
69
109
  }, {
70
110
  id: string;
71
111
  part: string;
72
112
  route: string;
113
+ repo?: string | undefined;
73
114
  apis?: string[] | undefined;
74
115
  }>, "many">>;
75
116
  capabilities: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -127,6 +168,281 @@ export declare const approvalIndexSchema: z.ZodObject<{
127
168
  tech_stack?: string | undefined;
128
169
  project_mode?: string | undefined;
129
170
  }>>;
171
+ multi_repo: z.ZodOptional<z.ZodEffects<z.ZodObject<{
172
+ enabled: z.ZodBoolean;
173
+ document_mode: z.ZodOptional<z.ZodEnum<["unified", "per_repo"]>>;
174
+ primary_repo: z.ZodOptional<z.ZodString>;
175
+ repos: z.ZodArray<z.ZodObject<{
176
+ id: z.ZodString;
177
+ label: z.ZodString;
178
+ role: z.ZodOptional<z.ZodEnum<["platform", "web", "worker", "hub", "other"]>>;
179
+ change: z.ZodString;
180
+ root_hint: z.ZodOptional<z.ZodString>;
181
+ }, "strip", z.ZodTypeAny, {
182
+ id: string;
183
+ change: string;
184
+ label: string;
185
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
186
+ root_hint?: string | undefined;
187
+ }, {
188
+ id: string;
189
+ change: string;
190
+ label: string;
191
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
192
+ root_hint?: string | undefined;
193
+ }>, "many">;
194
+ outputs: z.ZodOptional<z.ZodObject<{
195
+ unified: z.ZodOptional<z.ZodObject<{
196
+ repo: z.ZodString;
197
+ change: z.ZodString;
198
+ path: z.ZodString;
199
+ }, "strip", z.ZodTypeAny, {
200
+ path: string;
201
+ repo: string;
202
+ change: string;
203
+ }, {
204
+ path: string;
205
+ repo: string;
206
+ change: string;
207
+ }>>;
208
+ per_repo: z.ZodOptional<z.ZodArray<z.ZodObject<{
209
+ repo: z.ZodString;
210
+ change: z.ZodString;
211
+ path: z.ZodString;
212
+ }, "strip", z.ZodTypeAny, {
213
+ path: string;
214
+ repo: string;
215
+ change: string;
216
+ }, {
217
+ path: string;
218
+ repo: string;
219
+ change: string;
220
+ }>, "many">>;
221
+ }, "strip", z.ZodTypeAny, {
222
+ unified?: {
223
+ path: string;
224
+ repo: string;
225
+ change: string;
226
+ } | undefined;
227
+ per_repo?: {
228
+ path: string;
229
+ repo: string;
230
+ change: string;
231
+ }[] | undefined;
232
+ }, {
233
+ unified?: {
234
+ path: string;
235
+ repo: string;
236
+ change: string;
237
+ } | undefined;
238
+ per_repo?: {
239
+ path: string;
240
+ repo: string;
241
+ change: string;
242
+ }[] | undefined;
243
+ }>>;
244
+ bundle: z.ZodOptional<z.ZodObject<{
245
+ enabled: z.ZodOptional<z.ZodBoolean>;
246
+ playbook: z.ZodOptional<z.ZodString>;
247
+ output: z.ZodOptional<z.ZodString>;
248
+ readonly: z.ZodOptional<z.ZodBoolean>;
249
+ }, "strip", z.ZodTypeAny, {
250
+ output?: string | undefined;
251
+ enabled?: boolean | undefined;
252
+ playbook?: string | undefined;
253
+ readonly?: boolean | undefined;
254
+ }, {
255
+ output?: string | undefined;
256
+ enabled?: boolean | undefined;
257
+ playbook?: string | undefined;
258
+ readonly?: boolean | undefined;
259
+ }>>;
260
+ }, "strip", z.ZodTypeAny, {
261
+ enabled: boolean;
262
+ repos: {
263
+ id: string;
264
+ change: string;
265
+ label: string;
266
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
267
+ root_hint?: string | undefined;
268
+ }[];
269
+ document_mode?: "unified" | "per_repo" | undefined;
270
+ primary_repo?: string | undefined;
271
+ outputs?: {
272
+ unified?: {
273
+ path: string;
274
+ repo: string;
275
+ change: string;
276
+ } | undefined;
277
+ per_repo?: {
278
+ path: string;
279
+ repo: string;
280
+ change: string;
281
+ }[] | undefined;
282
+ } | undefined;
283
+ bundle?: {
284
+ output?: string | undefined;
285
+ enabled?: boolean | undefined;
286
+ playbook?: string | undefined;
287
+ readonly?: boolean | undefined;
288
+ } | undefined;
289
+ }, {
290
+ enabled: boolean;
291
+ repos: {
292
+ id: string;
293
+ change: string;
294
+ label: string;
295
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
296
+ root_hint?: string | undefined;
297
+ }[];
298
+ document_mode?: "unified" | "per_repo" | undefined;
299
+ primary_repo?: string | undefined;
300
+ outputs?: {
301
+ unified?: {
302
+ path: string;
303
+ repo: string;
304
+ change: string;
305
+ } | undefined;
306
+ per_repo?: {
307
+ path: string;
308
+ repo: string;
309
+ change: string;
310
+ }[] | undefined;
311
+ } | undefined;
312
+ bundle?: {
313
+ output?: string | undefined;
314
+ enabled?: boolean | undefined;
315
+ playbook?: string | undefined;
316
+ readonly?: boolean | undefined;
317
+ } | undefined;
318
+ }>, {
319
+ enabled: boolean;
320
+ repos: {
321
+ id: string;
322
+ change: string;
323
+ label: string;
324
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
325
+ root_hint?: string | undefined;
326
+ }[];
327
+ document_mode?: "unified" | "per_repo" | undefined;
328
+ primary_repo?: string | undefined;
329
+ outputs?: {
330
+ unified?: {
331
+ path: string;
332
+ repo: string;
333
+ change: string;
334
+ } | undefined;
335
+ per_repo?: {
336
+ path: string;
337
+ repo: string;
338
+ change: string;
339
+ }[] | undefined;
340
+ } | undefined;
341
+ bundle?: {
342
+ output?: string | undefined;
343
+ enabled?: boolean | undefined;
344
+ playbook?: string | undefined;
345
+ readonly?: boolean | undefined;
346
+ } | undefined;
347
+ }, {
348
+ enabled: boolean;
349
+ repos: {
350
+ id: string;
351
+ change: string;
352
+ label: string;
353
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
354
+ root_hint?: string | undefined;
355
+ }[];
356
+ document_mode?: "unified" | "per_repo" | undefined;
357
+ primary_repo?: string | undefined;
358
+ outputs?: {
359
+ unified?: {
360
+ path: string;
361
+ repo: string;
362
+ change: string;
363
+ } | undefined;
364
+ per_repo?: {
365
+ path: string;
366
+ repo: string;
367
+ change: string;
368
+ }[] | undefined;
369
+ } | undefined;
370
+ bundle?: {
371
+ output?: string | undefined;
372
+ enabled?: boolean | undefined;
373
+ playbook?: string | undefined;
374
+ readonly?: boolean | undefined;
375
+ } | undefined;
376
+ }>>;
377
+ acp: z.ZodOptional<z.ZodObject<{
378
+ pipeline: z.ZodOptional<z.ZodEnum<["acp/v1", "acp/v2"]>>;
379
+ context_budget_tokens: z.ZodOptional<z.ZodNumber>;
380
+ output_budget_tokens: z.ZodOptional<z.ZodNumber>;
381
+ feature_slices: z.ZodOptional<z.ZodArray<z.ZodObject<{
382
+ id: z.ZodString;
383
+ repos: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
384
+ interfaces: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
385
+ pages: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
386
+ design_points: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
387
+ parts: z.ZodArray<z.ZodString, "many">;
388
+ }, "strip", z.ZodTypeAny, {
389
+ id: string;
390
+ parts: string[];
391
+ repos?: string[] | undefined;
392
+ design_points?: string[] | undefined;
393
+ interfaces?: string[] | undefined;
394
+ pages?: string[] | undefined;
395
+ }, {
396
+ id: string;
397
+ parts: string[];
398
+ repos?: string[] | undefined;
399
+ design_points?: string[] | undefined;
400
+ interfaces?: string[] | undefined;
401
+ pages?: string[] | undefined;
402
+ }>, "many">>;
403
+ review: z.ZodOptional<z.ZodObject<{
404
+ enabled: z.ZodOptional<z.ZodBoolean>;
405
+ required_pass: z.ZodOptional<z.ZodBoolean>;
406
+ }, "strip", z.ZodTypeAny, {
407
+ enabled?: boolean | undefined;
408
+ required_pass?: boolean | undefined;
409
+ }, {
410
+ enabled?: boolean | undefined;
411
+ required_pass?: boolean | undefined;
412
+ }>>;
413
+ }, "strip", z.ZodTypeAny, {
414
+ review?: {
415
+ enabled?: boolean | undefined;
416
+ required_pass?: boolean | undefined;
417
+ } | undefined;
418
+ pipeline?: "acp/v1" | "acp/v2" | undefined;
419
+ context_budget_tokens?: number | undefined;
420
+ output_budget_tokens?: number | undefined;
421
+ feature_slices?: {
422
+ id: string;
423
+ parts: string[];
424
+ repos?: string[] | undefined;
425
+ design_points?: string[] | undefined;
426
+ interfaces?: string[] | undefined;
427
+ pages?: string[] | undefined;
428
+ }[] | undefined;
429
+ }, {
430
+ review?: {
431
+ enabled?: boolean | undefined;
432
+ required_pass?: boolean | undefined;
433
+ } | undefined;
434
+ pipeline?: "acp/v1" | "acp/v2" | undefined;
435
+ context_budget_tokens?: number | undefined;
436
+ output_budget_tokens?: number | undefined;
437
+ feature_slices?: {
438
+ id: string;
439
+ parts: string[];
440
+ repos?: string[] | undefined;
441
+ design_points?: string[] | undefined;
442
+ interfaces?: string[] | undefined;
443
+ pages?: string[] | undefined;
444
+ }[] | undefined;
445
+ }>>;
130
446
  }, "strip", z.ZodTypeAny, {
131
447
  schema: "specflow.approval.index/v1";
132
448
  conventions: {
@@ -154,18 +470,29 @@ export declare const approvalIndexSchema: z.ZodObject<{
154
470
  name: string;
155
471
  action: string;
156
472
  part: string;
473
+ repo?: string | undefined;
157
474
  }[];
158
475
  interfaces: {
159
476
  id: string;
160
477
  part: string;
161
478
  short: string;
162
479
  change: string;
480
+ repo?: string | undefined;
481
+ layers?: string[] | undefined;
482
+ pairs_with?: string | undefined;
483
+ feature_slice?: string | undefined;
484
+ frozen?: {
485
+ rpc?: string | undefined;
486
+ http_path?: string | undefined;
487
+ status_enum?: string[] | undefined;
488
+ } | undefined;
163
489
  }[];
164
490
  pages: {
165
491
  id: string;
166
492
  part: string;
167
493
  route: string;
168
494
  apis: string[];
495
+ repo?: string | undefined;
169
496
  }[];
170
497
  capabilities: {
171
498
  id: string;
@@ -182,6 +509,53 @@ export declare const approvalIndexSchema: z.ZodObject<{
182
509
  tech_stack?: string | undefined;
183
510
  project_mode?: string | undefined;
184
511
  } | undefined;
512
+ multi_repo?: {
513
+ enabled: boolean;
514
+ repos: {
515
+ id: string;
516
+ change: string;
517
+ label: string;
518
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
519
+ root_hint?: string | undefined;
520
+ }[];
521
+ document_mode?: "unified" | "per_repo" | undefined;
522
+ primary_repo?: string | undefined;
523
+ outputs?: {
524
+ unified?: {
525
+ path: string;
526
+ repo: string;
527
+ change: string;
528
+ } | undefined;
529
+ per_repo?: {
530
+ path: string;
531
+ repo: string;
532
+ change: string;
533
+ }[] | undefined;
534
+ } | undefined;
535
+ bundle?: {
536
+ output?: string | undefined;
537
+ enabled?: boolean | undefined;
538
+ playbook?: string | undefined;
539
+ readonly?: boolean | undefined;
540
+ } | undefined;
541
+ } | undefined;
542
+ acp?: {
543
+ review?: {
544
+ enabled?: boolean | undefined;
545
+ required_pass?: boolean | undefined;
546
+ } | undefined;
547
+ pipeline?: "acp/v1" | "acp/v2" | undefined;
548
+ context_budget_tokens?: number | undefined;
549
+ output_budget_tokens?: number | undefined;
550
+ feature_slices?: {
551
+ id: string;
552
+ parts: string[];
553
+ repos?: string[] | undefined;
554
+ design_points?: string[] | undefined;
555
+ interfaces?: string[] | undefined;
556
+ pages?: string[] | undefined;
557
+ }[] | undefined;
558
+ } | undefined;
185
559
  }, {
186
560
  schema: "specflow.approval.index/v1";
187
561
  change: string;
@@ -209,17 +583,28 @@ export declare const approvalIndexSchema: z.ZodObject<{
209
583
  name: string;
210
584
  action: string;
211
585
  part: string;
586
+ repo?: string | undefined;
212
587
  }[] | undefined;
213
588
  interfaces?: {
214
589
  id: string;
215
590
  part: string;
216
591
  short: string;
217
592
  change: string;
593
+ repo?: string | undefined;
594
+ layers?: string[] | undefined;
595
+ pairs_with?: string | undefined;
596
+ feature_slice?: string | undefined;
597
+ frozen?: {
598
+ rpc?: string | undefined;
599
+ http_path?: string | undefined;
600
+ status_enum?: string[] | undefined;
601
+ } | undefined;
218
602
  }[] | undefined;
219
603
  pages?: {
220
604
  id: string;
221
605
  part: string;
222
606
  route: string;
607
+ repo?: string | undefined;
223
608
  apis?: string[] | undefined;
224
609
  }[] | undefined;
225
610
  capabilities?: {
@@ -237,6 +622,53 @@ export declare const approvalIndexSchema: z.ZodObject<{
237
622
  tech_stack?: string | undefined;
238
623
  project_mode?: string | undefined;
239
624
  } | undefined;
625
+ multi_repo?: {
626
+ enabled: boolean;
627
+ repos: {
628
+ id: string;
629
+ change: string;
630
+ label: string;
631
+ role?: "platform" | "web" | "worker" | "hub" | "other" | undefined;
632
+ root_hint?: string | undefined;
633
+ }[];
634
+ document_mode?: "unified" | "per_repo" | undefined;
635
+ primary_repo?: string | undefined;
636
+ outputs?: {
637
+ unified?: {
638
+ path: string;
639
+ repo: string;
640
+ change: string;
641
+ } | undefined;
642
+ per_repo?: {
643
+ path: string;
644
+ repo: string;
645
+ change: string;
646
+ }[] | undefined;
647
+ } | undefined;
648
+ bundle?: {
649
+ output?: string | undefined;
650
+ enabled?: boolean | undefined;
651
+ playbook?: string | undefined;
652
+ readonly?: boolean | undefined;
653
+ } | undefined;
654
+ } | undefined;
655
+ acp?: {
656
+ review?: {
657
+ enabled?: boolean | undefined;
658
+ required_pass?: boolean | undefined;
659
+ } | undefined;
660
+ pipeline?: "acp/v1" | "acp/v2" | undefined;
661
+ context_budget_tokens?: number | undefined;
662
+ output_budget_tokens?: number | undefined;
663
+ feature_slices?: {
664
+ id: string;
665
+ parts: string[];
666
+ repos?: string[] | undefined;
667
+ design_points?: string[] | undefined;
668
+ interfaces?: string[] | undefined;
669
+ pages?: string[] | undefined;
670
+ }[] | undefined;
671
+ } | undefined;
240
672
  }>;
241
673
  export declare function parseApprovalIndex(raw: unknown): ApprovalIndex;
242
674
  /** Returns true when segmented fast-path (monolithic) is allowed. */
@@ -4,23 +4,102 @@ const tableRefSchema = z.object({
4
4
  name: z.string().min(1),
5
5
  action: z.string().min(1),
6
6
  part: z.string().min(1),
7
+ repo: z.string().min(1).optional(),
8
+ });
9
+ const interfaceFrozenSchema = z.object({
10
+ rpc: z.string().min(1).optional(),
11
+ http_path: z.string().min(1).optional(),
12
+ status_enum: z.array(z.string().min(1)).optional(),
7
13
  });
8
14
  const interfaceRefSchema = z.object({
9
15
  id: z.string().min(1),
10
16
  short: z.string().min(1),
11
17
  change: z.string().min(1),
12
18
  part: z.string().min(1),
19
+ repo: z.string().min(1).optional(),
20
+ layers: z.array(z.string().min(1)).optional(),
21
+ pairs_with: z.string().min(1).optional(),
22
+ feature_slice: z.string().min(1).optional(),
23
+ frozen: interfaceFrozenSchema.optional(),
13
24
  });
14
25
  const pageRefSchema = z.object({
15
26
  id: z.string().min(1),
16
27
  route: z.string().min(1),
17
28
  apis: z.array(z.string()).default([]),
18
29
  part: z.string().min(1),
30
+ repo: z.string().min(1).optional(),
19
31
  });
20
32
  const capabilityRefSchema = z.object({
21
33
  id: z.string().min(1),
22
34
  part: z.string().min(1),
23
35
  });
36
+ const outputRefSchema = z.object({
37
+ repo: z.string().min(1),
38
+ change: z.string().min(1),
39
+ path: z.string().min(1),
40
+ });
41
+ const multiRepoSchema = z
42
+ .object({
43
+ enabled: z.boolean(),
44
+ document_mode: z.enum(['unified', 'per_repo']).optional(),
45
+ primary_repo: z.string().min(1).optional(),
46
+ repos: z
47
+ .array(z.object({
48
+ id: z.string().min(1),
49
+ label: z.string().min(1),
50
+ role: z.enum(['platform', 'web', 'worker', 'hub', 'other']).optional(),
51
+ change: z.string().min(1),
52
+ root_hint: z.string().min(1).optional(),
53
+ }))
54
+ .min(1),
55
+ outputs: z
56
+ .object({
57
+ unified: outputRefSchema.optional(),
58
+ per_repo: z.array(outputRefSchema).optional(),
59
+ })
60
+ .optional(),
61
+ bundle: z
62
+ .object({
63
+ enabled: z.boolean().optional(),
64
+ playbook: z.string().min(1).optional(),
65
+ output: z.string().min(1).optional(),
66
+ readonly: z.boolean().optional(),
67
+ })
68
+ .optional(),
69
+ })
70
+ .superRefine((value, ctx) => {
71
+ if (!value.enabled) {
72
+ return;
73
+ }
74
+ if (value.repos.length < 2) {
75
+ ctx.addIssue({
76
+ code: z.ZodIssueCode.custom,
77
+ message: 'multi_repo.repos must have at least 2 entries when enabled',
78
+ path: ['repos'],
79
+ });
80
+ }
81
+ if (value.document_mode === 'unified' && !value.primary_repo) {
82
+ ctx.addIssue({
83
+ code: z.ZodIssueCode.custom,
84
+ message: 'multi_repo.primary_repo is required when document_mode is unified',
85
+ path: ['primary_repo'],
86
+ });
87
+ }
88
+ if (value.primary_repo && !value.repos.some((r) => r.id === value.primary_repo)) {
89
+ ctx.addIssue({
90
+ code: z.ZodIssueCode.custom,
91
+ message: 'multi_repo.primary_repo must match a repos[].id',
92
+ path: ['primary_repo'],
93
+ });
94
+ }
95
+ if (value.bundle?.enabled === true && !value.primary_repo) {
96
+ ctx.addIssue({
97
+ code: z.ZodIssueCode.custom,
98
+ message: 'multi_repo.primary_repo is required when bundle.enabled is true',
99
+ path: ['primary_repo'],
100
+ });
101
+ }
102
+ });
24
103
  export const approvalIndexSchema = z.object({
25
104
  schema: z.literal('specflow.approval.index/v1'),
26
105
  change: z.string().min(1),
@@ -71,6 +150,30 @@ export const approvalIndexSchema = z.object({
71
150
  project_mode: z.string().optional(),
72
151
  })
73
152
  .optional(),
153
+ multi_repo: multiRepoSchema.optional(),
154
+ acp: z
155
+ .object({
156
+ pipeline: z.enum(['acp/v1', 'acp/v2']).optional(),
157
+ context_budget_tokens: z.number().int().positive().optional(),
158
+ output_budget_tokens: z.number().int().positive().optional(),
159
+ feature_slices: z
160
+ .array(z.object({
161
+ id: z.string().min(1),
162
+ repos: z.array(z.string()).optional(),
163
+ interfaces: z.array(z.string()).optional(),
164
+ pages: z.array(z.string()).optional(),
165
+ design_points: z.array(z.string()).optional(),
166
+ parts: z.array(z.string().min(1)).min(1),
167
+ }))
168
+ .optional(),
169
+ review: z
170
+ .object({
171
+ enabled: z.boolean().optional(),
172
+ required_pass: z.boolean().optional(),
173
+ })
174
+ .optional(),
175
+ })
176
+ .optional(),
74
177
  });
75
178
  export function parseApprovalIndex(raw) {
76
179
  return approvalIndexSchema.parse(raw);
@@ -1,4 +1,12 @@
1
- export type { ApprovalAssembleResult, ApprovalDiagnostic, ApprovalIndex, ApprovalManifest, ApprovalGenerationMode, } from './types.js';
1
+ export type { ApprovalAssembleResult, ApprovalDiagnostic, ApprovalIndex, ApprovalManifest, ApprovalGenerationMode, ApprovalMultiRepo, ApprovalDocumentMode, ApprovalPlaybook, ApprovalBundleResult, ApprovalReviewPacket, ApprovalReviewResult, ApprovalAcpBlock, ApprovalFeatureSlice, } from './types.js';
2
2
  export { parseApprovalIndex, isLightweightApproval, shouldForceSegmented, approvalIndexSchema, } from './index-schema.js';
3
- export { getChangeDirectory, getApprovalWorkspaceDir, getApprovalIndexPath, getApprovalManifestPath, getApprovalPartsDir, getApprovalPartPath, getApprovalOutputPath, getApprovalAnalysisPath, } from './paths.js';
3
+ export { parseApprovalPlaybook, parseApprovalReviewResult } from './playbook-schema.js';
4
+ export { getChangeDirectory, getApprovalWorkspaceDir, getApprovalIndexPath, getApprovalManifestPath, getApprovalPartsDir, getApprovalPartPath, getApprovalOutputPath, getApprovalAnalysisPath, getApprovalReviewPacketPath, getApprovalReviewPath, getApprovalPlaybookPath, getApprovalBundleOutputPath, } from './paths.js';
4
5
  export { assembleApprovalDocument, readApprovalIndex, readApprovalManifest, } from './assemble.js';
6
+ export { lintApprovalDocument } from './lint.js';
7
+ export { bundleApprovalDocument, resolvePlaybookPath } from './bundle.js';
8
+ export { generateReviewPacket, checkApprovalReview, computeReviewPartHashes } from './review-pack.js';
9
+ export { finalizeApprovalDocument } from './pipeline.js';
10
+ export type { FinalizeApprovalResult, FinalizeApprovalOptions, ApprovalFinalizeStage } from './pipeline.js';
11
+ export { renderApprovalDocument, resolveApprovalRenderPaths } from './render.js';
12
+ export type { RenderApprovalOptions, RenderApprovalResult } from './render.js';
@@ -1,3 +1,9 @@
1
1
  export { parseApprovalIndex, isLightweightApproval, shouldForceSegmented, approvalIndexSchema, } from './index-schema.js';
2
- export { getChangeDirectory, getApprovalWorkspaceDir, getApprovalIndexPath, getApprovalManifestPath, getApprovalPartsDir, getApprovalPartPath, getApprovalOutputPath, getApprovalAnalysisPath, } from './paths.js';
2
+ export { parseApprovalPlaybook, parseApprovalReviewResult } from './playbook-schema.js';
3
+ export { getChangeDirectory, getApprovalWorkspaceDir, getApprovalIndexPath, getApprovalManifestPath, getApprovalPartsDir, getApprovalPartPath, getApprovalOutputPath, getApprovalAnalysisPath, getApprovalReviewPacketPath, getApprovalReviewPath, getApprovalPlaybookPath, getApprovalBundleOutputPath, } from './paths.js';
3
4
  export { assembleApprovalDocument, readApprovalIndex, readApprovalManifest, } from './assemble.js';
5
+ export { lintApprovalDocument } from './lint.js';
6
+ export { bundleApprovalDocument, resolvePlaybookPath } from './bundle.js';
7
+ export { generateReviewPacket, checkApprovalReview, computeReviewPartHashes } from './review-pack.js';
8
+ export { finalizeApprovalDocument } from './pipeline.js';
9
+ export { renderApprovalDocument, resolveApprovalRenderPaths } from './render.js';