@sublang/playbook 13.0.0 → 13.2.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 +7 -5
- package/docs/cli.md +28 -9
- package/docs/configuration.md +21 -5
- package/docs/embedding.md +1 -1
- package/package.json +41 -3
- package/reference/sdlc/branch.md +37 -0
- package/reference/sdlc/branch.playbook/branch.fsm.d.ts +169 -0
- package/reference/sdlc/branch.playbook/branch.fsm.js +325 -0
- package/reference/sdlc/branch.playbook/branch.fsm.ts +458 -0
- package/reference/sdlc/branch.playbook/branch.gears.md +44 -0
- package/reference/sdlc/branch.playbook/branch.playbook.d.ts +20 -0
- package/reference/sdlc/branch.playbook/branch.playbook.js +121 -0
- package/reference/sdlc/branch.playbook/branch.playbook.ts +217 -0
- package/reference/sdlc/branch.playbook/branch.registry.d.ts +40 -0
- package/reference/sdlc/branch.playbook/branch.registry.js +63 -0
- package/reference/sdlc/branch.playbook/branch.registry.ts +121 -0
- package/reference/sdlc/code.md +7 -0
- package/reference/sdlc/code.playbook/code.fsm.js +5 -5
- package/reference/sdlc/code.playbook/code.fsm.ts +5 -5
- package/reference/sdlc/code.playbook/code.gears.md +5 -5
- package/reference/sdlc/code.playbook/code.playbook.d.ts +1 -1
- package/reference/sdlc/code.playbook/code.playbook.js +6 -16
- package/reference/sdlc/code.playbook/code.playbook.ts +7 -17
- package/reference/sdlc/code.playbook/playbook-captain.js +4 -1
- package/reference/sdlc/code.playbook/playbook-captain.ts +4 -1
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +16 -2
- package/reference/sdlc/decide.md +2 -0
- package/reference/sdlc/decide.playbook/decide.fsm.js +1 -1
- package/reference/sdlc/decide.playbook/decide.fsm.ts +1 -1
- package/reference/sdlc/decide.playbook/decide.gears.md +2 -2
- package/reference/sdlc/decide.playbook/decide.playbook.d.ts +1 -2
- package/reference/sdlc/decide.playbook/decide.playbook.js +8 -22
- package/reference/sdlc/decide.playbook/decide.playbook.ts +8 -25
- package/reference/sdlc/dev.md +45 -4
- package/reference/sdlc/dev.playbook/dev.fsm.d.ts +100 -9
- package/reference/sdlc/dev.playbook/dev.fsm.js +245 -28
- package/reference/sdlc/dev.playbook/dev.fsm.ts +381 -37
- package/reference/sdlc/dev.playbook/dev.gears.md +60 -22
- package/reference/sdlc/dev.playbook/dev.playbook.d.ts +1 -1
- package/reference/sdlc/dev.playbook/dev.playbook.js +20 -18
- package/reference/sdlc/dev.playbook/dev.playbook.ts +21 -21
- package/reference/sdlc/dev.playbook/dev.registry.d.ts +1 -1
- package/reference/sdlc/dev.playbook/dev.registry.js +7 -2
- package/reference/sdlc/dev.playbook/dev.registry.ts +7 -2
- package/reference/sdlc/pr.md +108 -0
- package/reference/sdlc/pr.playbook/pr.fsm.d.ts +352 -0
- package/reference/sdlc/pr.playbook/pr.fsm.js +902 -0
- package/reference/sdlc/pr.playbook/pr.fsm.ts +1251 -0
- package/reference/sdlc/pr.playbook/pr.gears.md +155 -0
- package/reference/sdlc/pr.playbook/pr.playbook.d.ts +27 -0
- package/reference/sdlc/pr.playbook/pr.playbook.js +133 -0
- package/reference/sdlc/pr.playbook/pr.playbook.ts +235 -0
- package/reference/sdlc/pr.playbook/pr.registry.d.ts +40 -0
- package/reference/sdlc/pr.playbook/pr.registry.js +68 -0
- package/reference/sdlc/pr.playbook/pr.registry.ts +124 -0
- package/reference/sdlc/review.md +18 -0
- package/reference/sdlc/review.playbook/review.fsm.js +8 -8
- package/reference/sdlc/review.playbook/review.fsm.ts +8 -8
- package/reference/sdlc/review.playbook/review.gears.md +8 -8
- package/reference/sdlc/review.playbook/review.playbook.d.ts +1 -1
- package/reference/sdlc/review.playbook/review.playbook.js +5 -15
- package/reference/sdlc/review.playbook/review.playbook.ts +6 -16
- package/slc/link.md +12 -24
- package/src/runtime.d.ts +2 -0
- package/src/runtime.ts +2 -0
- package/src/xstate-playbook-runtime.d.ts +4 -2
- package/src/xstate-playbook-runtime.js +18 -13
- package/src/xstate-playbook-runtime.ts +26 -14
|
@@ -15,13 +15,28 @@ export type JsonValue =
|
|
|
15
15
|
|
|
16
16
|
export type DevStateId =
|
|
17
17
|
| 'planAnalysis'
|
|
18
|
+
| 'createBranch'
|
|
18
19
|
| 'callCode'
|
|
19
20
|
| 'callDecide'
|
|
20
|
-
| 'callCodeAfterDecide'
|
|
21
|
+
| 'callCodeAfterDecide'
|
|
22
|
+
| 'openPullRequest';
|
|
21
23
|
|
|
22
|
-
export type DevSourceItem =
|
|
24
|
+
export type DevSourceItem =
|
|
25
|
+
| 'DEV-1'
|
|
26
|
+
| 'DEV-2'
|
|
27
|
+
| 'DEV-3'
|
|
28
|
+
| 'DEV-4'
|
|
29
|
+
| 'DEV-5'
|
|
30
|
+
| 'DEV-6';
|
|
23
31
|
|
|
24
|
-
export type DevChildPlaybookId = 'code' | 'decide';
|
|
32
|
+
export type DevChildPlaybookId = 'code' | 'decide' | 'branch' | 'pr';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* DR-050: the development path a pull-request planning outcome selected. It
|
|
36
|
+
* routes the `branch` success into `callCode` or `callDecide`, so the plain
|
|
37
|
+
* `code` and `decide then code` paths keep their items, prompts, and edges.
|
|
38
|
+
*/
|
|
39
|
+
export type DevPullRequestPath = 'code' | 'decide-then-code';
|
|
25
40
|
|
|
26
41
|
export type PendingBossQuestion = {
|
|
27
42
|
readonly questionId: 'planAnalysis';
|
|
@@ -53,11 +68,21 @@ export type PlayerOutput =
|
|
|
53
68
|
| { readonly guard: 'discussionComplete' }
|
|
54
69
|
| { readonly guard: 'code'; readonly planningResult: string }
|
|
55
70
|
| { readonly guard: 'decideThenCode'; readonly planningResult: string }
|
|
71
|
+
| { readonly guard: 'codeViaPullRequest'; readonly planningResult: string }
|
|
72
|
+
| {
|
|
73
|
+
readonly guard: 'decideThenCodeViaPullRequest';
|
|
74
|
+
readonly planningResult: string;
|
|
75
|
+
}
|
|
56
76
|
| { readonly guard: 'needsBossReply'; readonly question: string };
|
|
57
77
|
|
|
58
78
|
export type PlaybookInput = {
|
|
59
|
-
readonly stateId:
|
|
60
|
-
|
|
79
|
+
readonly stateId:
|
|
80
|
+
| 'createBranch'
|
|
81
|
+
| 'callCode'
|
|
82
|
+
| 'callDecide'
|
|
83
|
+
| 'callCodeAfterDecide'
|
|
84
|
+
| 'openPullRequest';
|
|
85
|
+
readonly sourceItem: 'DEV-2' | 'DEV-3' | 'DEV-4' | 'DEV-5' | 'DEV-6';
|
|
61
86
|
readonly playbookId: DevChildPlaybookId;
|
|
62
87
|
readonly text: string;
|
|
63
88
|
};
|
|
@@ -75,6 +100,29 @@ export type DecideSuccessOutput = {
|
|
|
75
100
|
readonly noUnsettledFindings: true;
|
|
76
101
|
};
|
|
77
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The fields DEV consumes from `branch`'s canonical structured terminal
|
|
105
|
+
* output before continuing a pull-request path: the exact branch name, the
|
|
106
|
+
* exact base revision, and the issue summary. Additional members belong to
|
|
107
|
+
* BRANCH's own contract and do not disprove success; a missing member is an
|
|
108
|
+
* insufficient result, never an empty default.
|
|
109
|
+
*/
|
|
110
|
+
export type BranchSuccessOutput = {
|
|
111
|
+
readonly branch: string;
|
|
112
|
+
readonly baseRevision: string;
|
|
113
|
+
readonly issueSummary: string;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The fields DEV consumes from `code`'s canonical structured terminal output
|
|
118
|
+
* before starting the dependent `pr` call: the exact last `code`-owned commit
|
|
119
|
+
* and the exact final evaluated repository revision.
|
|
120
|
+
*/
|
|
121
|
+
export type CodeSuccessOutput = {
|
|
122
|
+
readonly lastCodeCommit: string;
|
|
123
|
+
readonly finalEvaluatedRevision: string;
|
|
124
|
+
};
|
|
125
|
+
|
|
78
126
|
export type CompactError = {
|
|
79
127
|
readonly name: string;
|
|
80
128
|
readonly message: string;
|
|
@@ -99,7 +147,8 @@ export type DevPlaybookOutput =
|
|
|
99
147
|
}
|
|
100
148
|
| {
|
|
101
149
|
readonly status: 'complete';
|
|
102
|
-
|
|
150
|
+
/** The final child of the selected path: `pr` on a pull-request path. */
|
|
151
|
+
readonly childPlaybookId: 'code' | 'pr';
|
|
103
152
|
/** The successful result of DEV's final child call, when it has one. */
|
|
104
153
|
readonly childOutput?: JsonValue;
|
|
105
154
|
}
|
|
@@ -120,6 +169,14 @@ export type DevContext = {
|
|
|
120
169
|
readonly planningResult?: string;
|
|
121
170
|
readonly decideCommit?: string;
|
|
122
171
|
readonly evaluatedRevision?: string;
|
|
172
|
+
/** DR-050: whether the accepted planning outcome selected a pull-request path. */
|
|
173
|
+
readonly deliveryViaPullRequest: boolean;
|
|
174
|
+
readonly pullRequestPath?: DevPullRequestPath;
|
|
175
|
+
readonly branch?: string;
|
|
176
|
+
readonly baseRevision?: string;
|
|
177
|
+
readonly issueSummary?: string;
|
|
178
|
+
readonly lastCodeCommit?: string;
|
|
179
|
+
readonly finalEvaluatedRevision?: string;
|
|
123
180
|
readonly completion?: 'discussion-complete' | 'complete' | 'child-failed';
|
|
124
181
|
readonly childOutput?: JsonValue;
|
|
125
182
|
readonly childFailure?: CompletedChildResult;
|
|
@@ -137,9 +194,9 @@ export type DevEvent =
|
|
|
137
194
|
};
|
|
138
195
|
|
|
139
196
|
const PLAN_ANALYSIS_PROMPT = [
|
|
140
|
-
'> <development-request>',
|
|
141
|
-
'> <discussion-context>',
|
|
142
|
-
'> <run-results>',
|
|
197
|
+
'> Original request: <development-request>',
|
|
198
|
+
'> Prior discussion: <discussion-context>',
|
|
199
|
+
'> Run results: <run-results>',
|
|
143
200
|
'',
|
|
144
201
|
'Inspect the request and the relevant repository and specs only as needed to determine the smallest sound next step.',
|
|
145
202
|
'Do not change files or commit while planning or discussing the request.',
|
|
@@ -148,6 +205,7 @@ const PLAN_ANALYSIS_PROMPT = [
|
|
|
148
205
|
'- If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.',
|
|
149
206
|
'- If implementation can proceed under the existing decisions, choose `code`.',
|
|
150
207
|
'- If implementation first requires a new or amended durable decision that the existing specs do not settle, choose `decide then code`.',
|
|
208
|
+
'- If the request names a GitHub issue (number or URL) or explicitly asks for pull-request delivery, read the issue and its comments as part of the analysis (`gh issue view --comments` with the issue number) and choose `code via pull request` or `decide then code via pull request` in place of `code` or `decide then code`.',
|
|
151
209
|
'',
|
|
152
210
|
'A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.',
|
|
153
211
|
'Do not choose `decide then code` merely because the work is large.',
|
|
@@ -161,6 +219,10 @@ const PLAN_ANALYSIS_RESULTS = {
|
|
|
161
219
|
'Analyst determined implementation can proceed under the existing decisions. Output shall include `planningResult: <verbatim final text>`.',
|
|
162
220
|
decideThenCode:
|
|
163
221
|
'Analyst determined implementation first requires a new or amended durable decision that the existing specs do not settle. Output shall include `planningResult: <verbatim final text>`.',
|
|
222
|
+
codeViaPullRequest:
|
|
223
|
+
'Analyst determined implementation can proceed under the existing decisions and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
224
|
+
decideThenCodeViaPullRequest:
|
|
225
|
+
'Analyst determined implementation first requires a new or amended durable decision that the existing specs do not settle and the request names a GitHub issue or explicitly asks for pull-request delivery. Output shall include `planningResult: <verbatim final text>`.',
|
|
164
226
|
needsBossReply:
|
|
165
227
|
"The acting agent's prose surfaces a clarifying question for Boss that the agent cannot answer alone. Output shall include `question: <verbatim question text from the acting agent's prose>`.",
|
|
166
228
|
} as const;
|
|
@@ -169,11 +231,15 @@ const STATE_DESCRIPTIONS = {
|
|
|
169
231
|
ready: 'Waiting for a development request.',
|
|
170
232
|
planAnalysis:
|
|
171
233
|
'Analyst is analyzing the development request to choose the smallest sound next step.',
|
|
234
|
+
createBranch:
|
|
235
|
+
'The BRANCH playbook is preparing the pull-request branch for the planned development path.',
|
|
172
236
|
callCode: 'The CODE playbook is implementing the planned development path.',
|
|
173
237
|
callDecide:
|
|
174
238
|
'The DECIDE playbook is settling the durable decision the planned path requires.',
|
|
175
239
|
callCodeAfterDecide:
|
|
176
240
|
'The CODE playbook is implementing the decided development path.',
|
|
241
|
+
openPullRequest:
|
|
242
|
+
'The PR playbook is delivering the implemented branch through a pull request.',
|
|
177
243
|
awaitBossReply: 'Waiting for Boss to answer Analyst.',
|
|
178
244
|
failed:
|
|
179
245
|
'The development planning workflow failed and is waiting for a new development request.',
|
|
@@ -253,6 +319,26 @@ function isDecideThenCode({ event }: { event: unknown }): boolean {
|
|
|
253
319
|
);
|
|
254
320
|
}
|
|
255
321
|
|
|
322
|
+
// DR-050: the two pull-request outcomes select the same development paths
|
|
323
|
+
// as `code` and `decide then code`, entered through `branch` first.
|
|
324
|
+
function isCodeViaPullRequest({ event }: { event: unknown }): boolean {
|
|
325
|
+
return (
|
|
326
|
+
outputGuard(event, 'codeViaPullRequest') &&
|
|
327
|
+
outputString(event, 'planningResult') !== undefined
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function isDecideThenCodeViaPullRequest({
|
|
332
|
+
event,
|
|
333
|
+
}: {
|
|
334
|
+
event: unknown;
|
|
335
|
+
}): boolean {
|
|
336
|
+
return (
|
|
337
|
+
outputGuard(event, 'decideThenCodeViaPullRequest') &&
|
|
338
|
+
outputString(event, 'planningResult') !== undefined
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
256
342
|
// Discussion complete is available only after a Boss reply: the round that
|
|
257
343
|
// produced it must itself have been resumed with Boss's answer.
|
|
258
344
|
function isDiscussionComplete({
|
|
@@ -292,6 +378,45 @@ function isDecideSuccess({ event }: { event: unknown }): boolean {
|
|
|
292
378
|
return isDecideSuccessValue(childOutputOf(event));
|
|
293
379
|
}
|
|
294
380
|
|
|
381
|
+
// BRANCH's canonical successful terminal output carries the exact name of
|
|
382
|
+
// the new checked-out branch, the exact receipt-owned base revision, and the
|
|
383
|
+
// issue summary; DEV consumes exactly those three by name and never defaults
|
|
384
|
+
// a missing one.
|
|
385
|
+
function isBranchSuccessValue(value: unknown): value is BranchSuccessOutput {
|
|
386
|
+
return (
|
|
387
|
+
isRecord(value) &&
|
|
388
|
+
isNonEmptyString(value.branch) &&
|
|
389
|
+
isNonEmptyString(value.baseRevision) &&
|
|
390
|
+
isNonEmptyString(value.issueSummary)
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function isBranchSuccessForCode({
|
|
395
|
+
context,
|
|
396
|
+
event,
|
|
397
|
+
}: {
|
|
398
|
+
context: DevContext;
|
|
399
|
+
event: unknown;
|
|
400
|
+
}): boolean {
|
|
401
|
+
return (
|
|
402
|
+
context.pullRequestPath === 'code' &&
|
|
403
|
+
isBranchSuccessValue(childOutputOf(event))
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function isBranchSuccessForDecide({
|
|
408
|
+
context,
|
|
409
|
+
event,
|
|
410
|
+
}: {
|
|
411
|
+
context: DevContext;
|
|
412
|
+
event: unknown;
|
|
413
|
+
}): boolean {
|
|
414
|
+
return (
|
|
415
|
+
context.pullRequestPath === 'decide-then-code' &&
|
|
416
|
+
isBranchSuccessValue(childOutputOf(event))
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
295
420
|
// CODE's canonical successful terminal output discriminates completion with
|
|
296
421
|
// `status: 'complete'`, carries the exact last CODE-owned commit, and
|
|
297
422
|
// affirms that every phase's review passed.
|
|
@@ -304,8 +429,44 @@ function isCodeSuccessValue(value: unknown): boolean {
|
|
|
304
429
|
);
|
|
305
430
|
}
|
|
306
431
|
|
|
307
|
-
|
|
308
|
-
|
|
432
|
+
// A plain path completes DEV on that proof alone, exactly as before DR-050.
|
|
433
|
+
function isPlainCodeSuccess({
|
|
434
|
+
context,
|
|
435
|
+
event,
|
|
436
|
+
}: {
|
|
437
|
+
context: DevContext;
|
|
438
|
+
event: unknown;
|
|
439
|
+
}): boolean {
|
|
440
|
+
return (
|
|
441
|
+
context.deliveryViaPullRequest !== true &&
|
|
442
|
+
isCodeSuccessValue(childOutputOf(event))
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// A pull-request path additionally consumes the exact final evaluated
|
|
447
|
+
// repository revision for the `pr` call, so a CODE result lacking it does not
|
|
448
|
+
// prove the success that path requires.
|
|
449
|
+
function isCodeSuccessValueForPullRequest(
|
|
450
|
+
value: unknown,
|
|
451
|
+
): value is CodeSuccessOutput & Record<string, unknown> {
|
|
452
|
+
return (
|
|
453
|
+
isCodeSuccessValue(value) &&
|
|
454
|
+
isRecord(value) &&
|
|
455
|
+
isNonEmptyString(value.finalEvaluatedRevision)
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function isCodeSuccessViaPullRequest({
|
|
460
|
+
context,
|
|
461
|
+
event,
|
|
462
|
+
}: {
|
|
463
|
+
context: DevContext;
|
|
464
|
+
event: unknown;
|
|
465
|
+
}): boolean {
|
|
466
|
+
return (
|
|
467
|
+
context.deliveryViaPullRequest === true &&
|
|
468
|
+
isCodeSuccessValueForPullRequest(childOutputOf(event))
|
|
469
|
+
);
|
|
309
470
|
}
|
|
310
471
|
|
|
311
472
|
function isStateValue(value: unknown, ancestors = new Set<object>()): boolean {
|
|
@@ -590,11 +751,11 @@ function archivedExchanges(
|
|
|
590
751
|
];
|
|
591
752
|
}
|
|
592
753
|
|
|
593
|
-
function quotedRelay(values: readonly string[]): string {
|
|
754
|
+
function quotedRelay(values: readonly (readonly [string, string])[]): string {
|
|
594
755
|
return values
|
|
595
|
-
.filter((value) => value.length > 0)
|
|
596
|
-
.map((value) =>
|
|
597
|
-
value
|
|
756
|
+
.filter(([, value]) => value.length > 0)
|
|
757
|
+
.map(([label, value]) =>
|
|
758
|
+
`${label}: ${value}`
|
|
598
759
|
.split('\n')
|
|
599
760
|
.map((line) => `> ${line}`)
|
|
600
761
|
.join('\n'),
|
|
@@ -602,11 +763,11 @@ function quotedRelay(values: readonly string[]): string {
|
|
|
602
763
|
.join('\n');
|
|
603
764
|
}
|
|
604
765
|
|
|
605
|
-
function planningRelayValues(context: DevContext): readonly string[] {
|
|
766
|
+
function planningRelayValues(context: DevContext): readonly (readonly [string, string])[] {
|
|
606
767
|
return [
|
|
607
|
-
context.developmentRequest ?? '',
|
|
608
|
-
renderDiscussionContext(context.discussionExchanges),
|
|
609
|
-
context.planningResult ?? '',
|
|
768
|
+
['Original request', context.developmentRequest ?? ''],
|
|
769
|
+
['Prior discussion', renderDiscussionContext(context.discussionExchanges)],
|
|
770
|
+
['Planning result', context.planningResult ?? ''],
|
|
610
771
|
];
|
|
611
772
|
}
|
|
612
773
|
|
|
@@ -621,11 +782,43 @@ function decideCallText(context: DevContext): string {
|
|
|
621
782
|
function codeAfterDecideCallText(context: DevContext): string {
|
|
622
783
|
return quotedRelay([
|
|
623
784
|
...planningRelayValues(context),
|
|
624
|
-
context.decideCommit ?? '',
|
|
625
|
-
context.evaluatedRevision ?? '',
|
|
785
|
+
['DECIDE commit', context.decideCommit ?? ''],
|
|
786
|
+
['Evaluated revision', context.evaluatedRevision ?? ''],
|
|
787
|
+
]);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function branchCallText(context: DevContext): string {
|
|
791
|
+
return quotedRelay(planningRelayValues(context));
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// DEV-6: every placeholder is substituted from typed context that only a
|
|
795
|
+
// child's canonical structured result populated — never from player prose.
|
|
796
|
+
function pullRequestCallText(context: DevContext): string {
|
|
797
|
+
return quotedRelay([
|
|
798
|
+
['Original request', context.developmentRequest ?? ''],
|
|
799
|
+
['Issue summary', context.issueSummary ?? ''],
|
|
800
|
+
['Branch', context.branch ?? ''],
|
|
801
|
+
['Base revision', context.baseRevision ?? ''],
|
|
802
|
+
['CODE commit', context.lastCodeCommit ?? ''],
|
|
803
|
+
['Evaluated revision', context.finalEvaluatedRevision ?? ''],
|
|
626
804
|
]);
|
|
627
805
|
}
|
|
628
806
|
|
|
807
|
+
function acceptedPlanningPath(
|
|
808
|
+
context: DevContext,
|
|
809
|
+
event: unknown,
|
|
810
|
+
pullRequestPath?: DevPullRequestPath,
|
|
811
|
+
) {
|
|
812
|
+
return {
|
|
813
|
+
planningResult: outputString(event, 'planningResult'),
|
|
814
|
+
discussionExchanges: archivedExchanges(context),
|
|
815
|
+
deliveryViaPullRequest: pullRequestPath !== undefined,
|
|
816
|
+
pullRequestPath,
|
|
817
|
+
pendingBossQuestion: undefined,
|
|
818
|
+
bossReply: undefined,
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
629
822
|
const machineSetup = setup({
|
|
630
823
|
types: {} as {
|
|
631
824
|
context: DevContext;
|
|
@@ -645,11 +838,18 @@ const machineSetup = setup({
|
|
|
645
838
|
isDiscussionComplete,
|
|
646
839
|
isCodePath,
|
|
647
840
|
isDecideThenCode,
|
|
841
|
+
isCodeViaPullRequest,
|
|
842
|
+
isDecideThenCodeViaPullRequest,
|
|
648
843
|
needsBossReply,
|
|
649
|
-
|
|
844
|
+
isBranchSuccessForCode,
|
|
845
|
+
isBranchSuccessForDecide,
|
|
846
|
+
isCodeSuccessViaPullRequest,
|
|
847
|
+
isPlainCodeSuccess,
|
|
650
848
|
isDecideSuccess,
|
|
849
|
+
authoredBranchFailure: authoredChildFailureGuard('branch'),
|
|
651
850
|
authoredCodeFailure: authoredChildFailureGuard('code'),
|
|
652
851
|
authoredDecideFailure: authoredChildFailureGuard('decide'),
|
|
852
|
+
authoredPrFailure: authoredChildFailureGuard('pr'),
|
|
653
853
|
emptyBossReply: ({ event }) =>
|
|
654
854
|
event.type === 'BOSS_REPLY' && event.answer.trim().length === 0,
|
|
655
855
|
resumesPlanAnalysis: ({ context, event }) =>
|
|
@@ -676,6 +876,13 @@ const machineSetup = setup({
|
|
|
676
876
|
planningResult: undefined,
|
|
677
877
|
decideCommit: undefined,
|
|
678
878
|
evaluatedRevision: undefined,
|
|
879
|
+
deliveryViaPullRequest: false,
|
|
880
|
+
pullRequestPath: undefined,
|
|
881
|
+
branch: undefined,
|
|
882
|
+
baseRevision: undefined,
|
|
883
|
+
issueSummary: undefined,
|
|
884
|
+
lastCodeCommit: undefined,
|
|
885
|
+
finalEvaluatedRevision: undefined,
|
|
679
886
|
completion: undefined,
|
|
680
887
|
childOutput: undefined,
|
|
681
888
|
childFailure: undefined,
|
|
@@ -690,18 +897,18 @@ const machineSetup = setup({
|
|
|
690
897
|
pendingBossQuestion: undefined,
|
|
691
898
|
bossReply: undefined,
|
|
692
899
|
})),
|
|
693
|
-
rememberCodePath: assign(({ context, event }) =>
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
900
|
+
rememberCodePath: assign(({ context, event }) =>
|
|
901
|
+
acceptedPlanningPath(context, event),
|
|
902
|
+
),
|
|
903
|
+
rememberDecidePath: assign(({ context, event }) =>
|
|
904
|
+
acceptedPlanningPath(context, event),
|
|
905
|
+
),
|
|
906
|
+
rememberCodeViaPullRequestPath: assign(({ context, event }) =>
|
|
907
|
+
acceptedPlanningPath(context, event, 'code'),
|
|
908
|
+
),
|
|
909
|
+
rememberDecideThenCodeViaPullRequestPath: assign(({ context, event }) =>
|
|
910
|
+
acceptedPlanningPath(context, event, 'decide-then-code'),
|
|
911
|
+
),
|
|
705
912
|
rememberPendingQuestion: assign(({ context, event }) => {
|
|
706
913
|
const question = outputString(event, 'question');
|
|
707
914
|
if (question === undefined || !outputGuard(event, 'needsBossReply')) {
|
|
@@ -727,6 +934,15 @@ const machineSetup = setup({
|
|
|
727
934
|
pendingBossQuestion: undefined,
|
|
728
935
|
bossReply: undefined,
|
|
729
936
|
}),
|
|
937
|
+
rememberBranchResult: assign(({ event }) => {
|
|
938
|
+
const output = childOutputOf(event);
|
|
939
|
+
if (!isBranchSuccessValue(output)) return {};
|
|
940
|
+
return {
|
|
941
|
+
branch: output.branch,
|
|
942
|
+
baseRevision: output.baseRevision,
|
|
943
|
+
issueSummary: output.issueSummary,
|
|
944
|
+
};
|
|
945
|
+
}),
|
|
730
946
|
rememberDecideResult: assign(({ event }) => {
|
|
731
947
|
const output = childOutputOf(event);
|
|
732
948
|
if (!isDecideSuccessValue(output)) return {};
|
|
@@ -735,6 +951,14 @@ const machineSetup = setup({
|
|
|
735
951
|
evaluatedRevision: output.evaluatedRevision,
|
|
736
952
|
};
|
|
737
953
|
}),
|
|
954
|
+
rememberCodeResult: assign(({ event }) => {
|
|
955
|
+
const output = childOutputOf(event);
|
|
956
|
+
if (!isCodeSuccessValueForPullRequest(output)) return {};
|
|
957
|
+
return {
|
|
958
|
+
lastCodeCommit: output.lastCodeCommit,
|
|
959
|
+
finalEvaluatedRevision: output.finalEvaluatedRevision,
|
|
960
|
+
};
|
|
961
|
+
}),
|
|
738
962
|
completeWithChildSuccess: assign(({ event }) => {
|
|
739
963
|
const output = childOutputOf(event);
|
|
740
964
|
return {
|
|
@@ -742,6 +966,10 @@ const machineSetup = setup({
|
|
|
742
966
|
...(output === undefined ? {} : { childOutput: output as JsonValue }),
|
|
743
967
|
};
|
|
744
968
|
}),
|
|
969
|
+
completeWithInsufficientBranchResult: assign(({ event }) => ({
|
|
970
|
+
completion: 'child-failed' as const,
|
|
971
|
+
childFailure: insufficientChildResult(event, 'branch'),
|
|
972
|
+
})),
|
|
745
973
|
completeWithInsufficientCodeResult: assign(({ event }) => ({
|
|
746
974
|
completion: 'child-failed' as const,
|
|
747
975
|
childFailure: insufficientChildResult(event, 'code'),
|
|
@@ -750,6 +978,10 @@ const machineSetup = setup({
|
|
|
750
978
|
completion: 'child-failed' as const,
|
|
751
979
|
childFailure: insufficientChildResult(event, 'decide'),
|
|
752
980
|
})),
|
|
981
|
+
completeWithBranchFailure: assign(({ event }) => ({
|
|
982
|
+
completion: 'child-failed' as const,
|
|
983
|
+
childFailure: relayedChildFailure(event, 'branch'),
|
|
984
|
+
})),
|
|
753
985
|
completeWithCodeFailure: assign(({ event }) => ({
|
|
754
986
|
completion: 'child-failed' as const,
|
|
755
987
|
childFailure: relayedChildFailure(event, 'code'),
|
|
@@ -758,6 +990,10 @@ const machineSetup = setup({
|
|
|
758
990
|
completion: 'child-failed' as const,
|
|
759
991
|
childFailure: relayedChildFailure(event, 'decide'),
|
|
760
992
|
})),
|
|
993
|
+
completeWithPrFailure: assign(({ event }) => ({
|
|
994
|
+
completion: 'child-failed' as const,
|
|
995
|
+
childFailure: relayedChildFailure(event, 'pr'),
|
|
996
|
+
})),
|
|
761
997
|
rememberActorError: assign(({ event }) => ({
|
|
762
998
|
lastError: (event as unknown as { readonly error?: unknown }).error,
|
|
763
999
|
})),
|
|
@@ -774,6 +1010,7 @@ export const devMachine = machineSetup.createMachine({
|
|
|
774
1010
|
context: ({ input }) => ({
|
|
775
1011
|
runResults: typeof input.runResults === 'string' ? input.runResults : '',
|
|
776
1012
|
discussionExchanges: [],
|
|
1013
|
+
deliveryViaPullRequest: false,
|
|
777
1014
|
}),
|
|
778
1015
|
output: ({ context }): DevPlaybookOutput => {
|
|
779
1016
|
if (context.completion === 'discussion-complete') {
|
|
@@ -782,7 +1019,9 @@ export const devMachine = machineSetup.createMachine({
|
|
|
782
1019
|
if (context.completion === 'complete') {
|
|
783
1020
|
return {
|
|
784
1021
|
status: 'complete',
|
|
785
|
-
|
|
1022
|
+
// `done` is entered by `pr` on a pull-request path and by `code` on a
|
|
1023
|
+
// plain path; no other arm completes the workflow.
|
|
1024
|
+
childPlaybookId: context.deliveryViaPullRequest ? 'pr' : 'code',
|
|
786
1025
|
...(context.childOutput === undefined
|
|
787
1026
|
? {}
|
|
788
1027
|
: { childOutput: context.childOutput }),
|
|
@@ -877,6 +1116,36 @@ export const devMachine = machineSetup.createMachine({
|
|
|
877
1116
|
'rememberDecidePath',
|
|
878
1117
|
],
|
|
879
1118
|
},
|
|
1119
|
+
{
|
|
1120
|
+
guard: 'isCodeViaPullRequest',
|
|
1121
|
+
target: 'createBranch',
|
|
1122
|
+
actions: [
|
|
1123
|
+
{
|
|
1124
|
+
type: 'playbook.acceptedOutcome',
|
|
1125
|
+
params: {
|
|
1126
|
+
source: 'planAnalysis',
|
|
1127
|
+
target: 'createBranch',
|
|
1128
|
+
acceptedOutcome: 'codeViaPullRequest',
|
|
1129
|
+
},
|
|
1130
|
+
},
|
|
1131
|
+
'rememberCodeViaPullRequestPath',
|
|
1132
|
+
],
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
guard: 'isDecideThenCodeViaPullRequest',
|
|
1136
|
+
target: 'createBranch',
|
|
1137
|
+
actions: [
|
|
1138
|
+
{
|
|
1139
|
+
type: 'playbook.acceptedOutcome',
|
|
1140
|
+
params: {
|
|
1141
|
+
source: 'planAnalysis',
|
|
1142
|
+
target: 'createBranch',
|
|
1143
|
+
acceptedOutcome: 'decideThenCodeViaPullRequest',
|
|
1144
|
+
},
|
|
1145
|
+
},
|
|
1146
|
+
'rememberDecideThenCodeViaPullRequestPath',
|
|
1147
|
+
],
|
|
1148
|
+
},
|
|
880
1149
|
{
|
|
881
1150
|
guard: 'needsBossReply',
|
|
882
1151
|
target: 'awaitBossReply',
|
|
@@ -900,6 +1169,45 @@ export const devMachine = machineSetup.createMachine({
|
|
|
900
1169
|
onError: { target: 'failed', actions: 'rememberActorError' },
|
|
901
1170
|
},
|
|
902
1171
|
},
|
|
1172
|
+
createBranch: {
|
|
1173
|
+
id: 'createBranch',
|
|
1174
|
+
description: STATE_DESCRIPTIONS.createBranch,
|
|
1175
|
+
meta: playbookMeta('createBranch'),
|
|
1176
|
+
tags: ['playbook.suspended'],
|
|
1177
|
+
invoke: {
|
|
1178
|
+
src: 'playbook',
|
|
1179
|
+
input: ({ context }): PlaybookInput => ({
|
|
1180
|
+
stateId: 'createBranch',
|
|
1181
|
+
sourceItem: 'DEV-5',
|
|
1182
|
+
playbookId: 'branch',
|
|
1183
|
+
text: branchCallText(context),
|
|
1184
|
+
}),
|
|
1185
|
+
onDone: [
|
|
1186
|
+
{
|
|
1187
|
+
guard: 'isBranchSuccessForCode',
|
|
1188
|
+
target: 'callCode',
|
|
1189
|
+
actions: 'rememberBranchResult',
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
guard: 'isBranchSuccessForDecide',
|
|
1193
|
+
target: 'callDecide',
|
|
1194
|
+
actions: 'rememberBranchResult',
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
target: 'reportedChildFailure',
|
|
1198
|
+
actions: 'completeWithInsufficientBranchResult',
|
|
1199
|
+
},
|
|
1200
|
+
],
|
|
1201
|
+
onError: [
|
|
1202
|
+
{
|
|
1203
|
+
guard: 'authoredBranchFailure',
|
|
1204
|
+
target: 'reportedChildFailure',
|
|
1205
|
+
actions: 'completeWithBranchFailure',
|
|
1206
|
+
},
|
|
1207
|
+
{ target: 'failed', actions: 'rememberActorError' },
|
|
1208
|
+
],
|
|
1209
|
+
},
|
|
1210
|
+
},
|
|
903
1211
|
callCode: {
|
|
904
1212
|
id: 'callCode',
|
|
905
1213
|
description: STATE_DESCRIPTIONS.callCode,
|
|
@@ -915,7 +1223,12 @@ export const devMachine = machineSetup.createMachine({
|
|
|
915
1223
|
}),
|
|
916
1224
|
onDone: [
|
|
917
1225
|
{
|
|
918
|
-
guard: '
|
|
1226
|
+
guard: 'isCodeSuccessViaPullRequest',
|
|
1227
|
+
target: 'openPullRequest',
|
|
1228
|
+
actions: 'rememberCodeResult',
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
guard: 'isPlainCodeSuccess',
|
|
919
1232
|
target: 'done',
|
|
920
1233
|
actions: 'completeWithChildSuccess',
|
|
921
1234
|
},
|
|
@@ -983,7 +1296,12 @@ export const devMachine = machineSetup.createMachine({
|
|
|
983
1296
|
}),
|
|
984
1297
|
onDone: [
|
|
985
1298
|
{
|
|
986
|
-
guard: '
|
|
1299
|
+
guard: 'isCodeSuccessViaPullRequest',
|
|
1300
|
+
target: 'openPullRequest',
|
|
1301
|
+
actions: 'rememberCodeResult',
|
|
1302
|
+
},
|
|
1303
|
+
{
|
|
1304
|
+
guard: 'isPlainCodeSuccess',
|
|
987
1305
|
target: 'done',
|
|
988
1306
|
actions: 'completeWithChildSuccess',
|
|
989
1307
|
},
|
|
@@ -1002,6 +1320,32 @@ export const devMachine = machineSetup.createMachine({
|
|
|
1002
1320
|
],
|
|
1003
1321
|
},
|
|
1004
1322
|
},
|
|
1323
|
+
openPullRequest: {
|
|
1324
|
+
id: 'openPullRequest',
|
|
1325
|
+
description: STATE_DESCRIPTIONS.openPullRequest,
|
|
1326
|
+
meta: playbookMeta('openPullRequest'),
|
|
1327
|
+
tags: ['playbook.suspended'],
|
|
1328
|
+
invoke: {
|
|
1329
|
+
src: 'playbook',
|
|
1330
|
+
input: ({ context }): PlaybookInput => ({
|
|
1331
|
+
stateId: 'openPullRequest',
|
|
1332
|
+
sourceItem: 'DEV-6',
|
|
1333
|
+
playbookId: 'pr',
|
|
1334
|
+
text: pullRequestCallText(context),
|
|
1335
|
+
}),
|
|
1336
|
+
// DR-048: `pr` declares its terminal kinds, so `onDone` alone proves
|
|
1337
|
+
// its success; DEV consumes none of its fields by name.
|
|
1338
|
+
onDone: { target: 'done', actions: 'completeWithChildSuccess' },
|
|
1339
|
+
onError: [
|
|
1340
|
+
{
|
|
1341
|
+
guard: 'authoredPrFailure',
|
|
1342
|
+
target: 'reportedChildFailure',
|
|
1343
|
+
actions: 'completeWithPrFailure',
|
|
1344
|
+
},
|
|
1345
|
+
{ target: 'failed', actions: 'rememberActorError' },
|
|
1346
|
+
],
|
|
1347
|
+
},
|
|
1348
|
+
},
|
|
1005
1349
|
awaitBossReply: {
|
|
1006
1350
|
id: 'awaitBossReply',
|
|
1007
1351
|
description: STATE_DESCRIPTIONS.awaitBossReply,
|