@clemrig/factory 0.19.0 → 0.21.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.
Files changed (65) hide show
  1. package/README.md +21 -14
  2. package/dist/app/board.js +1 -0
  3. package/dist/app/board.js.map +1 -1
  4. package/dist/app/prototype.d.ts +15 -0
  5. package/dist/app/prototype.js +65 -0
  6. package/dist/app/prototype.js.map +1 -0
  7. package/dist/app/review.js +3 -2
  8. package/dist/app/review.js.map +1 -1
  9. package/dist/app/spec-page.d.ts +24 -0
  10. package/dist/app/spec-page.js +72 -0
  11. package/dist/app/spec-page.js.map +1 -0
  12. package/dist/app/workflows/issue-save.d.ts +4 -1
  13. package/dist/app/workflows/issue-save.js +83 -9
  14. package/dist/app/workflows/issue-save.js.map +1 -1
  15. package/dist/app/workflows/stages/agents.d.ts +5 -0
  16. package/dist/app/workflows/stages/agents.js +5 -0
  17. package/dist/app/workflows/stages/agents.js.map +1 -1
  18. package/dist/app/workflows/stages/deliver.js +11 -3
  19. package/dist/app/workflows/stages/deliver.js.map +1 -1
  20. package/dist/app/workflows/stages/implement.js +8 -2
  21. package/dist/app/workflows/stages/implement.js.map +1 -1
  22. package/dist/app/workflows/stages/plan.js +2 -0
  23. package/dist/app/workflows/stages/plan.js.map +1 -1
  24. package/dist/app/workflows/stages/prepare.js +15 -1
  25. package/dist/app/workflows/stages/prepare.js.map +1 -1
  26. package/dist/app/workflows/stages/review.js +9 -2
  27. package/dist/app/workflows/stages/review.js.map +1 -1
  28. package/dist/app/workflows/stages/run.d.ts +14 -1
  29. package/dist/app/workflows/stages/run.js.map +1 -1
  30. package/dist/cli/ui.d.ts +4 -3
  31. package/dist/cli/ui.js +12 -4
  32. package/dist/cli/ui.js.map +1 -1
  33. package/dist/domain/board.d.ts +4 -0
  34. package/dist/domain/board.js +1 -0
  35. package/dist/domain/board.js.map +1 -1
  36. package/dist/domain/pull-request.d.ts +9 -2
  37. package/dist/domain/pull-request.js +12 -2
  38. package/dist/domain/pull-request.js.map +1 -1
  39. package/dist/domain/spec-page.d.ts +188 -0
  40. package/dist/domain/spec-page.js +242 -0
  41. package/dist/domain/spec-page.js.map +1 -0
  42. package/dist/domain/spec.d.ts +13 -1
  43. package/dist/domain/spec.js +60 -8
  44. package/dist/domain/spec.js.map +1 -1
  45. package/dist/domain/tidy.d.ts +2 -1
  46. package/dist/domain/tidy.js +5 -1
  47. package/dist/domain/tidy.js.map +1 -1
  48. package/dist/system/git.d.ts +4 -0
  49. package/dist/system/git.js +13 -0
  50. package/dist/system/git.js.map +1 -1
  51. package/dist/system/images.d.ts +16 -0
  52. package/dist/system/images.js +51 -0
  53. package/dist/system/images.js.map +1 -0
  54. package/dist/system/issues.d.ts +27 -0
  55. package/dist/system/issues.js +117 -1
  56. package/dist/system/issues.js.map +1 -1
  57. package/dist/system/run-files.d.ts +0 -8
  58. package/dist/system/run-files.js +1 -28
  59. package/dist/system/run-files.js.map +1 -1
  60. package/package.json +2 -2
  61. package/prompts/implement.md +11 -1
  62. package/prompts/plan.md +17 -6
  63. package/prompts/review.md +11 -4
  64. package/templates/init/gitignore +1 -0
  65. package/templates/skills/issue/SKILL.md +85 -13
@@ -0,0 +1,188 @@
1
+ import { z } from "@clemrig/flow";
2
+ import type { Parsed } from "./parsed.js";
3
+ import { type Prototype, type Spec } from "./spec.js";
4
+ /** Above this size, a mockup is refused: a sketch of an interface fits well below it. */
5
+ export declare const maxMockupBytes: number;
6
+ /** Above this size, a capture is refused: a screen fits well below it, as JPEG or WebP above all. */
7
+ export declare const maxCaptureBytes: number;
8
+ /** A sketch of an interface the agent draws: an HTML page, shown at `width` × `height` CSS pixels. */
9
+ declare const drawnMockup: z.ZodObject<{
10
+ caption: z.ZodString;
11
+ html: z.ZodString;
12
+ width: z.ZodNumber;
13
+ height: z.ZodNumber;
14
+ }, z.core.$strict>;
15
+ export type DrawnMockup = z.output<typeof drawnMockup>;
16
+ /**
17
+ * How the agent that wrote a spec with the operator presents it, for the
18
+ * operator to validate it on the spec page: in plain words, in the spec's
19
+ * language, each change with a mockup when it brings an interface.
20
+ */
21
+ export declare const specPresentation: z.ZodObject<{
22
+ need: z.ZodString;
23
+ changes: z.ZodArray<z.ZodObject<{
24
+ title: z.ZodString;
25
+ text: z.ZodString;
26
+ mockup: z.ZodOptional<z.ZodPipe<z.ZodUnknown, z.ZodTransform<{
27
+ caption: string;
28
+ html: string;
29
+ width: number;
30
+ height: number;
31
+ } | {
32
+ caption: string;
33
+ image: string;
34
+ }, unknown>>>;
35
+ }, z.core.$strict>>;
36
+ decisions: z.ZodArray<z.ZodObject<{
37
+ id: z.ZodString;
38
+ title: z.ZodString;
39
+ why: z.ZodString;
40
+ options: z.ZodArray<z.ZodObject<{
41
+ id: z.ZodString;
42
+ title: z.ZodString;
43
+ text: z.ZodString;
44
+ }, z.core.$strict>>;
45
+ chosen: z.ZodString;
46
+ }, z.core.$strict>>;
47
+ criteria: z.ZodArray<z.ZodObject<{
48
+ title: z.ZodString;
49
+ criteria: z.ZodArray<z.ZodObject<{
50
+ id: z.ZodString;
51
+ plain: z.ZodString;
52
+ check: z.ZodString;
53
+ }, z.core.$strict>>;
54
+ }, z.core.$strict>>;
55
+ outOfScope: z.ZodArray<z.ZodString>;
56
+ }, z.core.$strict>;
57
+ export type SpecPresentation = z.output<typeof specPresentation>;
58
+ /**
59
+ * What the factory keeps of a presented spec: the presentation, each capture
60
+ * named as kept, and the spec it presents, word for word.
61
+ */
62
+ export declare const presentedSpec: z.ZodObject<{
63
+ spec: z.ZodString;
64
+ presentation: z.ZodObject<{
65
+ need: z.ZodString;
66
+ changes: z.ZodArray<z.ZodObject<{
67
+ title: z.ZodString;
68
+ text: z.ZodString;
69
+ mockup: z.ZodOptional<z.ZodPipe<z.ZodUnknown, z.ZodTransform<{
70
+ caption: string;
71
+ html: string;
72
+ width: number;
73
+ height: number;
74
+ } | {
75
+ caption: string;
76
+ image: string;
77
+ }, unknown>>>;
78
+ }, z.core.$strict>>;
79
+ decisions: z.ZodArray<z.ZodObject<{
80
+ id: z.ZodString;
81
+ title: z.ZodString;
82
+ why: z.ZodString;
83
+ options: z.ZodArray<z.ZodObject<{
84
+ id: z.ZodString;
85
+ title: z.ZodString;
86
+ text: z.ZodString;
87
+ }, z.core.$strict>>;
88
+ chosen: z.ZodString;
89
+ }, z.core.$strict>>;
90
+ criteria: z.ZodArray<z.ZodObject<{
91
+ title: z.ZodString;
92
+ criteria: z.ZodArray<z.ZodObject<{
93
+ id: z.ZodString;
94
+ plain: z.ZodString;
95
+ check: z.ZodString;
96
+ }, z.core.$strict>>;
97
+ }, z.core.$strict>>;
98
+ outOfScope: z.ZodArray<z.ZodString>;
99
+ }, z.core.$strict>;
100
+ }, z.core.$strict>;
101
+ export type PresentedSpec = z.output<typeof presentedSpec>;
102
+ /** What is wrong with a presentation of `spec`: criteria not presented once each, choices whose options do not hold. */
103
+ export declare function presentationProblems(presentation: SpecPresentation, spec: Spec): string[];
104
+ /** A presentation an agent drafted, checked against the spec it presents. */
105
+ export declare function parsePresentation(draft: string, spec: Spec): Parsed<SpecPresentation>;
106
+ /** The changes whose mockup is a capture, by position, with its caption and the image it names. */
107
+ export declare function capturesOf(presentation: SpecPresentation): {
108
+ change: number;
109
+ caption: string;
110
+ image: string;
111
+ }[];
112
+ /**
113
+ * The captures of the screens the operator validated for `spec`: those of
114
+ * its presentation, none when the presentation shows another text of it.
115
+ */
116
+ export declare function validatedCaptures({ spec: presented, presentation }: PresentedSpec, spec: string): {
117
+ caption: string;
118
+ image: string;
119
+ }[];
120
+ /**
121
+ * The name the capture of change `change` (from 0) is kept under, from the
122
+ * media type of its image; `undefined` for an image no capture can be.
123
+ */
124
+ export declare function captureName(change: number, type: string): string | undefined;
125
+ /** `presentation` with each capture named as kept, by the position of its change: each must have its name. */
126
+ export declare function namingCaptures(presentation: SpecPresentation, names: ReadonlyMap<number, string>): SpecPresentation;
127
+ /** A mockup as the page shows it: drawn, or captured and loaded from `url`. */
128
+ export type PageMockup = (DrawnMockup & {
129
+ kind: "drawn";
130
+ }) | {
131
+ kind: "captured";
132
+ caption: string;
133
+ url: string;
134
+ };
135
+ /** What the spec page shows of a presented spec; `@clemrig/factory-ui` draws it. */
136
+ export interface SpecPage {
137
+ issue: string;
138
+ title: string;
139
+ stale: boolean;
140
+ /** The prototype the spec it presents draws on. */
141
+ prototype?: Prototype;
142
+ need: string;
143
+ changes: {
144
+ title: string;
145
+ text: string;
146
+ mockup?: PageMockup;
147
+ }[];
148
+ decisions: SpecPresentation["decisions"];
149
+ criteria: {
150
+ title: string;
151
+ criteria: {
152
+ id: string;
153
+ text: string;
154
+ plain: string;
155
+ check: string;
156
+ }[];
157
+ }[];
158
+ outOfScope: string[];
159
+ spec: {
160
+ objective: string;
161
+ scope: string;
162
+ outOfScope: string;
163
+ constraints: string;
164
+ };
165
+ }
166
+ /**
167
+ * The page of issue `slug`'s presented spec, in the words of the spec it
168
+ * presents; stale when `current`, the spec now, says something else.
169
+ * `undefined` when the spec it presents no longer reads. `captureUrl` says
170
+ * where the page loads a capture.
171
+ */
172
+ export declare function specPage(slug: string, { spec: text, presentation }: PresentedSpec, current: string | undefined, captureUrl: (file: string) => string): SpecPage | undefined;
173
+ /** Where a person is in a spec's validation, as the page sends it: the review's answers, and the options taken. */
174
+ export declare const specAnswers: z.ZodObject<{
175
+ answers: z.ZodRecord<z.ZodString, z.ZodEnum<{
176
+ no: "no";
177
+ ok: "ok";
178
+ skip: "skip";
179
+ }>>;
180
+ notes: z.ZodRecord<z.ZodString, z.ZodString>;
181
+ seen: z.ZodArray<z.ZodString>;
182
+ position: z.ZodNumber;
183
+ startedAt: z.ZodNullable<z.ZodNumber>;
184
+ endedAt: z.ZodNullable<z.ZodNumber>;
185
+ choices: z.ZodRecord<z.ZodString, z.ZodString>;
186
+ }, z.core.$strict>;
187
+ export type SpecAnswers = z.output<typeof specAnswers>;
188
+ export {};
@@ -0,0 +1,242 @@
1
+ import { z } from "@clemrig/flow";
2
+ import { reviewAnswers } from "./review-page.js";
3
+ import { parseSpec } from "./spec.js";
4
+ /** An id a card is kept under: a choice's, an option's. */
5
+ const id = z
6
+ .string()
7
+ .regex(/^[a-z][a-z0-9-]{0,39}$/, "Expected a lowercase letter, then lowercase letters, digits or hyphens: 40 characters at most");
8
+ const text = (max) => z.string().trim().min(1).max(max);
9
+ /** Above this size, a mockup is refused: a sketch of an interface fits well below it. */
10
+ export const maxMockupBytes = 256 * 1024;
11
+ /** Above this size, a capture is refused: a screen fits well below it, as JPEG or WebP above all. */
12
+ export const maxCaptureBytes = 2 * 1024 * 1024;
13
+ /** The images a capture may be, by media type, with the extension it is kept under. */
14
+ const captureExtensions = {
15
+ "image/png": "png",
16
+ "image/jpeg": "jpg",
17
+ "image/webp": "webp",
18
+ };
19
+ /** A sketch of an interface the agent draws: an HTML page, shown at `width` × `height` CSS pixels. */
20
+ const drawnMockup = z.strictObject({
21
+ caption: text(300),
22
+ html: z
23
+ .string()
24
+ .min(1)
25
+ .refine((html) => new TextEncoder().encode(html).length <= maxMockupBytes, `At most ${maxMockupBytes / 1024} KiB`),
26
+ width: z.number().int().min(320).max(1600),
27
+ height: z.number().int().min(200).max(4000),
28
+ });
29
+ /**
30
+ * A capture of a screen the operator validated, its prototype's: in a draft,
31
+ * the path of an image file; as kept, its name in the issue's captures.
32
+ */
33
+ const capturedMockup = z.strictObject({
34
+ caption: text(300),
35
+ image: text(4096),
36
+ });
37
+ /**
38
+ * A mockup, drawn or captured: one with `image` is a capture. Chosen by that
39
+ * key rather than as a union, so that a malformed mockup says what it lacks.
40
+ */
41
+ const mockup = z.unknown().transform((value, context) => {
42
+ const schema = typeof value === "object" && value !== null && "image" in value
43
+ ? capturedMockup
44
+ : drawnMockup;
45
+ const parsed = schema.safeParse(value);
46
+ if (parsed.success)
47
+ return parsed.data;
48
+ for (const { message, path } of parsed.error.issues)
49
+ context.addIssue({ code: "custom", message, path });
50
+ return z.NEVER;
51
+ });
52
+ /**
53
+ * How the agent that wrote a spec with the operator presents it, for the
54
+ * operator to validate it on the spec page: in plain words, in the spec's
55
+ * language, each change with a mockup when it brings an interface.
56
+ */
57
+ export const specPresentation = z.strictObject({
58
+ need: text(4000),
59
+ changes: z
60
+ .array(z.strictObject({
61
+ title: text(200),
62
+ text: text(4000),
63
+ mockup: mockup.optional(),
64
+ }))
65
+ .min(1)
66
+ .max(20),
67
+ decisions: z
68
+ .array(z.strictObject({
69
+ id,
70
+ title: text(300),
71
+ why: text(2000),
72
+ options: z
73
+ .array(z.strictObject({ id, title: text(200), text: text(2000) }))
74
+ .min(2)
75
+ .max(5),
76
+ chosen: id,
77
+ }))
78
+ .max(20),
79
+ criteria: z
80
+ .array(z.strictObject({
81
+ title: text(200),
82
+ criteria: z
83
+ .array(z.strictObject({
84
+ id: z.string().regex(/^AC[1-9]\d*$/, "Expected AC<n>"),
85
+ plain: text(1000),
86
+ check: text(500),
87
+ }))
88
+ .min(1),
89
+ }))
90
+ .min(1)
91
+ .max(20),
92
+ outOfScope: z.array(text(500)).max(30),
93
+ });
94
+ /** The name a capture is kept under in its issue's folder: after its change, with its image's extension. */
95
+ const keptCapture = /^change-[1-9]\d*\.(?:png|jpg|webp)$/;
96
+ /**
97
+ * What the factory keeps of a presented spec: the presentation, each capture
98
+ * named as kept, and the spec it presents, word for word.
99
+ */
100
+ export const presentedSpec = z.strictObject({
101
+ spec: z.string(),
102
+ presentation: specPresentation.refine((presentation) => capturesOf(presentation).every(({ image }) => keptCapture.test(image)), "A capture is kept as change-<n>.<png|jpg|webp>"),
103
+ });
104
+ /** What is wrong with a presentation of `spec`: criteria not presented once each, choices whose options do not hold. */
105
+ export function presentationProblems(presentation, spec) {
106
+ const problems = [];
107
+ const presented = presentation.criteria.flatMap(({ criteria }) => criteria.map(({ id }) => id));
108
+ const known = new Set(spec.criteria.map(({ id }) => id));
109
+ for (const criterion of spec.criteria)
110
+ if (!presented.includes(criterion.id))
111
+ problems.push(`criteria: ${criterion.id} is not presented`);
112
+ for (const criterion of new Set(presented)) {
113
+ if (!known.has(criterion))
114
+ problems.push(`criteria: ${criterion} is not a criterion of the spec`);
115
+ if (presented.indexOf(criterion) !== presented.lastIndexOf(criterion))
116
+ problems.push(`criteria: ${criterion} is presented more than once`);
117
+ }
118
+ const decisions = presentation.decisions.map(({ id }) => id);
119
+ presentation.decisions.forEach((decision, index) => {
120
+ const where = `decisions[${index}]`;
121
+ if (decisions.indexOf(decision.id) !== index)
122
+ problems.push(`${where}: ${decision.id} is the id of another choice`);
123
+ const options = decision.options.map(({ id }) => id);
124
+ for (const option of new Set(options))
125
+ if (options.indexOf(option) !== options.lastIndexOf(option))
126
+ problems.push(`${where}: option ${option} is listed twice`);
127
+ if (!options.includes(decision.chosen))
128
+ problems.push(`${where}.chosen: ${decision.chosen} is not an option`);
129
+ });
130
+ return problems;
131
+ }
132
+ /** A presentation an agent drafted, checked against the spec it presents. */
133
+ export function parsePresentation(draft, spec) {
134
+ let value;
135
+ try {
136
+ value = JSON.parse(draft);
137
+ }
138
+ catch (error) {
139
+ return {
140
+ ok: false,
141
+ problems: [`Not JSON: ${error instanceof Error ? error.message : error}`],
142
+ };
143
+ }
144
+ const parsed = specPresentation.safeParse(value);
145
+ if (!parsed.success)
146
+ return { ok: false, problems: [z.prettifyError(parsed.error)] };
147
+ const problems = presentationProblems(parsed.data, spec);
148
+ return problems.length > 0
149
+ ? { ok: false, problems }
150
+ : { ok: true, value: parsed.data };
151
+ }
152
+ /** The changes whose mockup is a capture, by position, with its caption and the image it names. */
153
+ export function capturesOf(presentation) {
154
+ return presentation.changes.flatMap(({ mockup }, change) => mockup && "image" in mockup
155
+ ? [{ change, caption: mockup.caption, image: mockup.image }]
156
+ : []);
157
+ }
158
+ /**
159
+ * The captures of the screens the operator validated for `spec`: those of
160
+ * its presentation, none when the presentation shows another text of it.
161
+ */
162
+ export function validatedCaptures({ spec: presented, presentation }, spec) {
163
+ return presented === spec
164
+ ? capturesOf(presentation).map(({ caption, image }) => ({ caption, image }))
165
+ : [];
166
+ }
167
+ /**
168
+ * The name the capture of change `change` (from 0) is kept under, from the
169
+ * media type of its image; `undefined` for an image no capture can be.
170
+ */
171
+ export function captureName(change, type) {
172
+ const extension = captureExtensions[type];
173
+ return extension && `change-${change + 1}.${extension}`;
174
+ }
175
+ /** `presentation` with each capture named as kept, by the position of its change: each must have its name. */
176
+ export function namingCaptures(presentation, names) {
177
+ return {
178
+ ...presentation,
179
+ changes: presentation.changes.map((change, index) => {
180
+ if (!change.mockup || !("image" in change.mockup))
181
+ return change;
182
+ const image = names.get(index);
183
+ if (image === undefined)
184
+ throw new Error(`The capture of change ${index + 1} has no name`);
185
+ return { ...change, mockup: { ...change.mockup, image } };
186
+ }),
187
+ };
188
+ }
189
+ /**
190
+ * The page of issue `slug`'s presented spec, in the words of the spec it
191
+ * presents; stale when `current`, the spec now, says something else.
192
+ * `undefined` when the spec it presents no longer reads. `captureUrl` says
193
+ * where the page loads a capture.
194
+ */
195
+ export function specPage(slug, { spec: text, presentation }, current, captureUrl) {
196
+ const parsed = parseSpec(text, slug);
197
+ if (!parsed.ok)
198
+ return undefined;
199
+ const spec = parsed.value;
200
+ const words = new Map(spec.criteria.map(({ id, text }) => [id, text]));
201
+ return {
202
+ issue: slug,
203
+ title: spec.title,
204
+ stale: current !== text,
205
+ ...(spec.prototype ? { prototype: spec.prototype } : {}),
206
+ need: presentation.need,
207
+ changes: presentation.changes.map(({ mockup, ...change }) => !mockup
208
+ ? change
209
+ : "image" in mockup
210
+ ? {
211
+ ...change,
212
+ mockup: {
213
+ kind: "captured",
214
+ caption: mockup.caption,
215
+ url: captureUrl(mockup.image),
216
+ },
217
+ }
218
+ : { ...change, mockup: { kind: "drawn", ...mockup } }),
219
+ decisions: presentation.decisions,
220
+ criteria: presentation.criteria.map((group) => ({
221
+ title: group.title,
222
+ criteria: group.criteria.map((criterion) => ({
223
+ id: criterion.id,
224
+ text: words.get(criterion.id) ?? "",
225
+ plain: criterion.plain,
226
+ check: criterion.check,
227
+ })),
228
+ })),
229
+ outOfScope: presentation.outOfScope,
230
+ spec: {
231
+ objective: spec.objective,
232
+ scope: spec.scope,
233
+ outOfScope: spec.outOfScope,
234
+ constraints: spec.constraints,
235
+ },
236
+ };
237
+ }
238
+ /** Where a person is in a spec's validation, as the page sends it: the review's answers, and the options taken. */
239
+ export const specAnswers = reviewAnswers.extend({
240
+ choices: z.record(id, id),
241
+ });
242
+ //# sourceMappingURL=spec-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-page.js","sourceRoot":"","sources":["../../src/domain/spec-page.ts"],"names":[],"mappings":"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"}
@@ -13,8 +13,20 @@ export interface Spec {
13
13
  constraints: string;
14
14
  /** The issues that must be delivered before this one starts, by slug. */
15
15
  dependencies: string[];
16
+ /** The throwaway prototype the operator validated and the spec draws on, when there is one. */
17
+ prototype?: Prototype;
16
18
  }
17
- /** Reads issue `slug`'s spec.md: a `# ` title, then exactly the six sections, in order. */
19
+ /**
20
+ * A prototype, as a spec names it: the commit the operator validated, on a
21
+ * branch of its own that origin keeps, never rewritten, until the issue is
22
+ * delivered.
23
+ */
24
+ export interface Prototype {
25
+ branch: string;
26
+ /** Its full id: the version validated, whatever the branch becomes. */
27
+ commit: string;
28
+ }
29
+ /** Reads issue `slug`'s spec.md: a `# ` title, then exactly the six sections, in order, and its prototype's if it has one. */
18
30
  export declare function parseSpec(text: string, slug: string): Parsed<Spec>;
19
31
  export declare function specCommitMessage(slug: string): string;
20
32
  /** What is wrong with the criteria a response cites: all of the spec's, no other, and each once if required. */
@@ -7,12 +7,15 @@ const sectionHeadings = [
7
7
  "Constraints",
8
8
  "Dependencies",
9
9
  ];
10
+ /** The section a spec has only when it draws on a prototype: after the others. */
11
+ const prototypeHeading = "Prototype";
10
12
  /** How to write the items of the sections that hold them, as their problems recall it. */
11
13
  const itemFormats = {
12
14
  "Acceptance criteria": 'write "- AC<n>: <criterion>"',
13
15
  Dependencies: 'write "- <slug>" for each issue this one depends on, or None.',
16
+ [prototypeHeading]: 'write "- Branch: <branch>" then "- Commit: <full commit id>", or leave the section out',
14
17
  };
15
- /** Reads issue `slug`'s spec.md: a `# ` title, then exactly the six sections, in order. */
18
+ /** Reads issue `slug`'s spec.md: a `# ` title, then exactly the six sections, in order, and its prototype's if it has one. */
16
19
  export function parseSpec(text, slug) {
17
20
  const [first = "", ...lines] = text.trim().split(/\r?\n/);
18
21
  const title = /^# (.*)$/.exec(first)?.[1]?.trim() ?? "";
@@ -33,17 +36,21 @@ export function parseSpec(text, slug) {
33
36
  const body = (heading) => (sections.get(heading) ?? []).join("\n").trim();
34
37
  const { criteria, problems: criteriaProblems } = parseCriteria(sections.get("Acceptance criteria") ?? []);
35
38
  const { dependencies, problems: dependencyProblems } = parseDependencies(sections.get("Dependencies") ?? [], slug);
39
+ const { prototype, problems: prototypeProblems } = body(prototypeHeading)
40
+ ? parsePrototype(sections.get(prototypeHeading) ?? [], slug)
41
+ : { problems: [] };
36
42
  const problems = [
37
43
  ...(title ? [] : ["The first line must be a title: # <Title>"]),
38
44
  ...(preamble.join("").trim()
39
45
  ? ["Unexpected text before the first section"]
40
46
  : []),
41
47
  ...sectionProblems(headings),
42
- ...sectionHeadings
48
+ ...[...sectionHeadings, prototypeHeading]
43
49
  .filter((heading) => sections.has(heading) && !body(heading))
44
50
  .map((heading) => `Empty section: ## ${heading}`),
45
51
  ...criteriaProblems,
46
52
  ...dependencyProblems,
53
+ ...prototypeProblems,
47
54
  ];
48
55
  if (problems.length > 0)
49
56
  return { ok: false, problems };
@@ -57,13 +64,15 @@ export function parseSpec(text, slug) {
57
64
  criteria,
58
65
  constraints: body("Constraints"),
59
66
  dependencies,
67
+ ...(prototype ? { prototype } : {}),
60
68
  },
61
69
  };
62
70
  }
63
- /** Exactly the expected headings, each once, in order. */
71
+ /** Exactly the expected headings, each once, in order, the prototype's last if there. */
64
72
  function sectionProblems(headings) {
65
- const unknown = headings.filter((heading) => !sectionHeadings.includes(heading));
66
- const duplicate = sectionHeadings.filter((heading) => headings.indexOf(heading) !== headings.lastIndexOf(heading));
73
+ const known = [...sectionHeadings, prototypeHeading];
74
+ const unknown = headings.filter((heading) => !known.includes(heading));
75
+ const duplicate = known.filter((heading) => headings.indexOf(heading) !== headings.lastIndexOf(heading));
67
76
  const missing = sectionHeadings.filter((heading) => !headings.includes(heading));
68
77
  const problems = [
69
78
  ...[...new Set(unknown)].map((heading) => `Unknown section: ## ${heading}`),
@@ -73,9 +82,11 @@ function sectionProblems(headings) {
73
82
  return `Missing section: ## ${heading}${format ? ` (${format})` : ""}`;
74
83
  }),
75
84
  ];
76
- if (problems.length === 0 &&
77
- headings.join("\n") !== sectionHeadings.join("\n"))
78
- problems.push(`Sections must appear in this order: ${sectionHeadings.join(", ")}`);
85
+ const order = headings.includes(prototypeHeading)
86
+ ? [...sectionHeadings, prototypeHeading]
87
+ : sectionHeadings;
88
+ if (problems.length === 0 && headings.join("\n") !== order.join("\n"))
89
+ problems.push(`Sections must appear in this order: ${sectionHeadings.join(", ")}, then ${prototypeHeading} if the spec draws on one`);
79
90
  return problems;
80
91
  }
81
92
  /** `- AC<n>: <text>` items numbered from 1; an indented line continues the item above it. */
@@ -133,6 +144,47 @@ function parseDependencies(lines, slug) {
133
144
  }
134
145
  return { dependencies, problems };
135
146
  }
147
+ /** A full commit id: SHA-1, or SHA-256 in a repository that uses it. */
148
+ const commitId = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
149
+ /** What no branch name holds, as markdown tempts to write one; Git judges the rest. */
150
+ const notBranch = /\s|`/;
151
+ /**
152
+ * `- Branch: <branch>` then `- Commit: <full commit id>`: the prototype the
153
+ * spec draws on. Its branch has a slash, as `prototype/<slug>`: no run takes
154
+ * such a branch, since an issue's is its slug and a cleanup's `tidy-<run>`.
155
+ */
156
+ function parsePrototype(lines, slug) {
157
+ const items = lines.map((line) => line.trim()).filter(Boolean);
158
+ const labels = ["Branch", "Commit"];
159
+ const values = [];
160
+ const problems = [];
161
+ for (const line of items) {
162
+ const label = labels[values.length];
163
+ const value = label && new RegExp(`^- ${label}:(.*)$`).exec(line)?.[1];
164
+ if (value?.trim())
165
+ values.push(value.trim());
166
+ else
167
+ problems.push(`Prototype: unexpected line "${line}" (${itemFormats[prototypeHeading]})`);
168
+ }
169
+ if (problems.length > 0)
170
+ return { problems };
171
+ const [branch, commit] = values;
172
+ if (branch === undefined || commit === undefined)
173
+ return {
174
+ problems: [
175
+ `Prototype: missing ${labels[values.length]} (${itemFormats[prototypeHeading]})`,
176
+ ],
177
+ };
178
+ if (notBranch.test(branch))
179
+ problems.push(`Prototype: "${branch}" is not a branch name: write the name alone`);
180
+ else if (!branch.includes("/"))
181
+ problems.push(`Prototype: ${branch} may be the branch of a run, which replaces it: keep the prototype on a branch named with a slash, such as prototype/${slug}`);
182
+ if (!commitId.test(commit))
183
+ problems.push(`Prototype: "${commit}" is not a full commit id: write the whole id of the commit the operator validated, as git rev-parse prints it`);
184
+ return problems.length > 0
185
+ ? { problems }
186
+ : { prototype: { branch, commit }, problems };
187
+ }
136
188
  export function specCommitMessage(slug) {
137
189
  return `docs: spec ${slug}`;
138
190
  }
@@ -1 +1 @@
1
- {"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/domain/spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/domain/spec.ts"],"names":[],"mappings":"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"}
@@ -53,6 +53,7 @@ export type Choice = z.output<typeof choiceOutput>;
53
53
  export type Cleanup = NonNullable<Choice["cleanup"]>;
54
54
  /**
55
55
  * The cleanup's spec, once its issue and spec have the formats of any issue's;
56
- * a cleanup starts from the main branch alone, so it depends on no issue.
56
+ * a cleanup starts from the main branch alone, so it depends on no issue,
57
+ * and nobody validated a prototype of it.
57
58
  */
58
59
  export declare function cleanupSpec(cleanup: Cleanup, slug: string): Parsed<Spec>;
@@ -40,7 +40,8 @@ export const choiceOutput = z.strictObject({
40
40
  });
41
41
  /**
42
42
  * The cleanup's spec, once its issue and spec have the formats of any issue's;
43
- * a cleanup starts from the main branch alone, so it depends on no issue.
43
+ * a cleanup starts from the main branch alone, so it depends on no issue,
44
+ * and nobody validated a prototype of it.
44
45
  */
45
46
  export function cleanupSpec(cleanup, slug) {
46
47
  const issue = parseIssue(cleanup.issue);
@@ -51,6 +52,9 @@ export function cleanupSpec(cleanup, slug) {
51
52
  ...(spec.ok && spec.value.dependencies.length > 0
52
53
  ? ["spec: a cleanup depends on no issue: write None. under Dependencies"]
53
54
  : []),
55
+ ...(spec.ok && spec.value.prototype
56
+ ? ["spec: a cleanup draws on no prototype: leave the section out"]
57
+ : []),
54
58
  ];
55
59
  return problems.length > 0 || !spec.ok ? { ok: false, problems } : spec;
56
60
  }