@sublang/playbook 13.1.0 → 13.3.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 +27 -14
- package/docs/embedding.md +1 -1
- package/package.json +40 -2
- 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.playbook/bin/session-host.js +13 -3
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +26 -1
- package/reference/sdlc/code.playbook/playbook-captain.js +218 -6
- package/reference/sdlc/code.playbook/playbook-captain.ts +281 -6
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +21 -8
- package/reference/sdlc/code.playbook/session-host.d.ts +26 -0
- package/reference/sdlc/dev.md +24 -3
- package/reference/sdlc/dev.playbook/dev.fsm.d.ts +100 -9
- package/reference/sdlc/dev.playbook/dev.fsm.js +235 -18
- package/reference/sdlc/dev.playbook/dev.fsm.ts +368 -24
- package/reference/sdlc/dev.playbook/dev.gears.md +45 -7
- package/reference/sdlc/dev.playbook/dev.playbook.js +13 -1
- package/reference/sdlc/dev.playbook/dev.playbook.ts +13 -1
- 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
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
2
2
|
readonly [key: string]: JsonValue;
|
|
3
3
|
};
|
|
4
|
-
export type DevStateId = 'planAnalysis' | 'callCode' | 'callDecide' | 'callCodeAfterDecide';
|
|
5
|
-
export type DevSourceItem = 'DEV-1' | 'DEV-2' | 'DEV-3' | 'DEV-4';
|
|
6
|
-
export type DevChildPlaybookId = 'code' | 'decide';
|
|
4
|
+
export type DevStateId = 'planAnalysis' | 'createBranch' | 'callCode' | 'callDecide' | 'callCodeAfterDecide' | 'openPullRequest';
|
|
5
|
+
export type DevSourceItem = 'DEV-1' | 'DEV-2' | 'DEV-3' | 'DEV-4' | 'DEV-5' | 'DEV-6';
|
|
6
|
+
export type DevChildPlaybookId = 'code' | 'decide' | 'branch' | 'pr';
|
|
7
|
+
/**
|
|
8
|
+
* DR-050: the development path a pull-request planning outcome selected. It
|
|
9
|
+
* routes the `branch` success into `callCode` or `callDecide`, so the plain
|
|
10
|
+
* `code` and `decide then code` paths keep their items, prompts, and edges.
|
|
11
|
+
*/
|
|
12
|
+
export type DevPullRequestPath = 'code' | 'decide-then-code';
|
|
7
13
|
export type PendingBossQuestion = {
|
|
8
14
|
readonly questionId: 'planAnalysis';
|
|
9
15
|
readonly resumeStateId: 'planAnalysis';
|
|
@@ -38,13 +44,19 @@ export type PlayerOutput = {
|
|
|
38
44
|
} | {
|
|
39
45
|
readonly guard: 'decideThenCode';
|
|
40
46
|
readonly planningResult: string;
|
|
47
|
+
} | {
|
|
48
|
+
readonly guard: 'codeViaPullRequest';
|
|
49
|
+
readonly planningResult: string;
|
|
50
|
+
} | {
|
|
51
|
+
readonly guard: 'decideThenCodeViaPullRequest';
|
|
52
|
+
readonly planningResult: string;
|
|
41
53
|
} | {
|
|
42
54
|
readonly guard: 'needsBossReply';
|
|
43
55
|
readonly question: string;
|
|
44
56
|
};
|
|
45
57
|
export type PlaybookInput = {
|
|
46
|
-
readonly stateId: 'callCode' | 'callDecide' | 'callCodeAfterDecide';
|
|
47
|
-
readonly sourceItem: 'DEV-2' | 'DEV-3' | 'DEV-4';
|
|
58
|
+
readonly stateId: 'createBranch' | 'callCode' | 'callDecide' | 'callCodeAfterDecide' | 'openPullRequest';
|
|
59
|
+
readonly sourceItem: 'DEV-2' | 'DEV-3' | 'DEV-4' | 'DEV-5' | 'DEV-6';
|
|
48
60
|
readonly playbookId: DevChildPlaybookId;
|
|
49
61
|
readonly text: string;
|
|
50
62
|
};
|
|
@@ -60,6 +72,27 @@ export type DecideSuccessOutput = {
|
|
|
60
72
|
readonly evaluatedRevision: string;
|
|
61
73
|
readonly noUnsettledFindings: true;
|
|
62
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* The fields DEV consumes from `branch`'s canonical structured terminal
|
|
77
|
+
* output before continuing a pull-request path: the exact branch name, the
|
|
78
|
+
* exact base revision, and the issue summary. Additional members belong to
|
|
79
|
+
* BRANCH's own contract and do not disprove success; a missing member is an
|
|
80
|
+
* insufficient result, never an empty default.
|
|
81
|
+
*/
|
|
82
|
+
export type BranchSuccessOutput = {
|
|
83
|
+
readonly branch: string;
|
|
84
|
+
readonly baseRevision: string;
|
|
85
|
+
readonly issueSummary: string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* The fields DEV consumes from `code`'s canonical structured terminal output
|
|
89
|
+
* before starting the dependent `pr` call: the exact last `code`-owned commit
|
|
90
|
+
* and the exact final evaluated repository revision.
|
|
91
|
+
*/
|
|
92
|
+
export type CodeSuccessOutput = {
|
|
93
|
+
readonly lastCodeCommit: string;
|
|
94
|
+
readonly finalEvaluatedRevision: string;
|
|
95
|
+
};
|
|
63
96
|
export type CompactError = {
|
|
64
97
|
readonly name: string;
|
|
65
98
|
readonly message: string;
|
|
@@ -78,7 +111,8 @@ export type DevPlaybookOutput = {
|
|
|
78
111
|
readonly status: 'discussion-complete';
|
|
79
112
|
} | {
|
|
80
113
|
readonly status: 'complete';
|
|
81
|
-
|
|
114
|
+
/** The final child of the selected path: `pr` on a pull-request path. */
|
|
115
|
+
readonly childPlaybookId: 'code' | 'pr';
|
|
82
116
|
/** The successful result of DEV's final child call, when it has one. */
|
|
83
117
|
readonly childOutput?: JsonValue;
|
|
84
118
|
} | {
|
|
@@ -96,6 +130,14 @@ export type DevContext = {
|
|
|
96
130
|
readonly planningResult?: string;
|
|
97
131
|
readonly decideCommit?: string;
|
|
98
132
|
readonly evaluatedRevision?: string;
|
|
133
|
+
/** DR-050: whether the accepted planning outcome selected a pull-request path. */
|
|
134
|
+
readonly deliveryViaPullRequest: boolean;
|
|
135
|
+
readonly pullRequestPath?: DevPullRequestPath;
|
|
136
|
+
readonly branch?: string;
|
|
137
|
+
readonly baseRevision?: string;
|
|
138
|
+
readonly issueSummary?: string;
|
|
139
|
+
readonly lastCodeCommit?: string;
|
|
140
|
+
readonly finalEvaluatedRevision?: string;
|
|
99
141
|
readonly completion?: 'discussion-complete' | 'complete' | 'child-failed';
|
|
100
142
|
readonly childOutput?: JsonValue;
|
|
101
143
|
readonly childFailure?: CompletedChildResult;
|
|
@@ -164,24 +206,45 @@ export declare const devMachine: import("xstate").StateMachine<DevContext, {
|
|
|
164
206
|
} | {
|
|
165
207
|
type: "rememberDecidePath";
|
|
166
208
|
params: import("xstate").NonReducibleUnknown;
|
|
209
|
+
} | {
|
|
210
|
+
type: "rememberCodeViaPullRequestPath";
|
|
211
|
+
params: import("xstate").NonReducibleUnknown;
|
|
212
|
+
} | {
|
|
213
|
+
type: "rememberDecideThenCodeViaPullRequestPath";
|
|
214
|
+
params: import("xstate").NonReducibleUnknown;
|
|
215
|
+
} | {
|
|
216
|
+
type: "rememberBranchResult";
|
|
217
|
+
params: import("xstate").NonReducibleUnknown;
|
|
167
218
|
} | {
|
|
168
219
|
type: "rememberDecideResult";
|
|
169
220
|
params: import("xstate").NonReducibleUnknown;
|
|
221
|
+
} | {
|
|
222
|
+
type: "rememberCodeResult";
|
|
223
|
+
params: import("xstate").NonReducibleUnknown;
|
|
170
224
|
} | {
|
|
171
225
|
type: "completeWithChildSuccess";
|
|
172
226
|
params: import("xstate").NonReducibleUnknown;
|
|
227
|
+
} | {
|
|
228
|
+
type: "completeWithInsufficientBranchResult";
|
|
229
|
+
params: import("xstate").NonReducibleUnknown;
|
|
173
230
|
} | {
|
|
174
231
|
type: "completeWithInsufficientCodeResult";
|
|
175
232
|
params: import("xstate").NonReducibleUnknown;
|
|
176
233
|
} | {
|
|
177
234
|
type: "completeWithInsufficientDecideResult";
|
|
178
235
|
params: import("xstate").NonReducibleUnknown;
|
|
236
|
+
} | {
|
|
237
|
+
type: "completeWithBranchFailure";
|
|
238
|
+
params: import("xstate").NonReducibleUnknown;
|
|
179
239
|
} | {
|
|
180
240
|
type: "completeWithCodeFailure";
|
|
181
241
|
params: import("xstate").NonReducibleUnknown;
|
|
182
242
|
} | {
|
|
183
243
|
type: "completeWithDecideFailure";
|
|
184
244
|
params: import("xstate").NonReducibleUnknown;
|
|
245
|
+
} | {
|
|
246
|
+
type: "completeWithPrFailure";
|
|
247
|
+
params: import("xstate").NonReducibleUnknown;
|
|
185
248
|
}, {
|
|
186
249
|
type: "needsBossReply";
|
|
187
250
|
params: unknown;
|
|
@@ -198,25 +261,47 @@ export declare const devMachine: import("xstate").StateMachine<DevContext, {
|
|
|
198
261
|
type: "isDecideThenCode";
|
|
199
262
|
params: unknown;
|
|
200
263
|
} | {
|
|
201
|
-
type: "
|
|
264
|
+
type: "isCodeViaPullRequest";
|
|
265
|
+
params: unknown;
|
|
266
|
+
} | {
|
|
267
|
+
type: "isDecideThenCodeViaPullRequest";
|
|
268
|
+
params: unknown;
|
|
269
|
+
} | {
|
|
270
|
+
type: "isBranchSuccessForCode";
|
|
271
|
+
params: unknown;
|
|
272
|
+
} | {
|
|
273
|
+
type: "isBranchSuccessForDecide";
|
|
274
|
+
params: unknown;
|
|
275
|
+
} | {
|
|
276
|
+
type: "isCodeSuccessViaPullRequest";
|
|
277
|
+
params: unknown;
|
|
278
|
+
} | {
|
|
279
|
+
type: "isPlainCodeSuccess";
|
|
202
280
|
params: unknown;
|
|
203
281
|
} | {
|
|
204
282
|
type: "isDecideSuccess";
|
|
205
283
|
params: unknown;
|
|
284
|
+
} | {
|
|
285
|
+
type: "authoredBranchFailure";
|
|
286
|
+
params: unknown;
|
|
206
287
|
} | {
|
|
207
288
|
type: "authoredCodeFailure";
|
|
208
289
|
params: unknown;
|
|
209
290
|
} | {
|
|
210
291
|
type: "authoredDecideFailure";
|
|
211
292
|
params: unknown;
|
|
293
|
+
} | {
|
|
294
|
+
type: "authoredPrFailure";
|
|
295
|
+
params: unknown;
|
|
212
296
|
} | {
|
|
213
297
|
type: "resumesPlanAnalysis";
|
|
214
298
|
params: unknown;
|
|
215
|
-
}, never, "done" | "failed" | "awaitBossReply" | "ready" | "planAnalysis" | "callCode" | "callDecide" | "callCodeAfterDecide" | "discussionComplete" | "reportedChildFailure", string, DevInput, {
|
|
299
|
+
}, never, "done" | "failed" | "awaitBossReply" | "ready" | "planAnalysis" | "createBranch" | "callCode" | "callDecide" | "callCodeAfterDecide" | "openPullRequest" | "discussionComplete" | "reportedChildFailure", string, DevInput, {
|
|
216
300
|
readonly status: "discussion-complete";
|
|
217
301
|
} | {
|
|
218
302
|
readonly status: "complete";
|
|
219
|
-
|
|
303
|
+
/** The final child of the selected path: `pr` on a pull-request path. */
|
|
304
|
+
readonly childPlaybookId: "code" | "pr";
|
|
220
305
|
/** The successful result of DEV's final child call, when it has one. */
|
|
221
306
|
readonly childOutput?: JsonValue;
|
|
222
307
|
} | {
|
|
@@ -232,6 +317,9 @@ export declare const devMachine: import("xstate").StateMachine<DevContext, {
|
|
|
232
317
|
readonly planAnalysis: {
|
|
233
318
|
id: "planAnalysis";
|
|
234
319
|
};
|
|
320
|
+
readonly createBranch: {
|
|
321
|
+
id: "createBranch";
|
|
322
|
+
};
|
|
235
323
|
readonly callCode: {
|
|
236
324
|
id: "callCode";
|
|
237
325
|
};
|
|
@@ -241,6 +329,9 @@ export declare const devMachine: import("xstate").StateMachine<DevContext, {
|
|
|
241
329
|
readonly callCodeAfterDecide: {
|
|
242
330
|
id: "callCodeAfterDecide";
|
|
243
331
|
};
|
|
332
|
+
readonly openPullRequest: {
|
|
333
|
+
id: "openPullRequest";
|
|
334
|
+
};
|
|
244
335
|
readonly awaitBossReply: {
|
|
245
336
|
id: "awaitBossReply";
|
|
246
337
|
};
|
|
@@ -15,6 +15,7 @@ const PLAN_ANALYSIS_PROMPT = [
|
|
|
15
15
|
'- If the discussion has concluded after a Boss reply and no repository work should follow, choose `discussion complete`.',
|
|
16
16
|
'- If implementation can proceed under the existing decisions, choose `code`.',
|
|
17
17
|
'- If implementation first requires a new or amended durable decision that the existing specs do not settle, choose `decide then code`.',
|
|
18
|
+
'- 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`.',
|
|
18
19
|
'',
|
|
19
20
|
'A question or exploratory discussion is not by itself authorization to create a durable decision or implement changes.',
|
|
20
21
|
'Do not choose `decide then code` merely because the work is large.',
|
|
@@ -24,14 +25,18 @@ const PLAN_ANALYSIS_RESULTS = {
|
|
|
24
25
|
discussionComplete: 'Analyst concluded the discussion after a Boss reply, with no repository work to follow.',
|
|
25
26
|
code: 'Analyst determined implementation can proceed under the existing decisions. Output shall include `planningResult: <verbatim final text>`.',
|
|
26
27
|
decideThenCode: '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>`.',
|
|
28
|
+
codeViaPullRequest: '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>`.',
|
|
29
|
+
decideThenCodeViaPullRequest: '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>`.',
|
|
27
30
|
needsBossReply: "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>`.",
|
|
28
31
|
};
|
|
29
32
|
const STATE_DESCRIPTIONS = {
|
|
30
33
|
ready: 'Waiting for a development request.',
|
|
31
34
|
planAnalysis: 'Analyst is analyzing the development request to choose the smallest sound next step.',
|
|
35
|
+
createBranch: 'The BRANCH playbook is preparing the pull-request branch for the planned development path.',
|
|
32
36
|
callCode: 'The CODE playbook is implementing the planned development path.',
|
|
33
37
|
callDecide: 'The DECIDE playbook is settling the durable decision the planned path requires.',
|
|
34
38
|
callCodeAfterDecide: 'The CODE playbook is implementing the decided development path.',
|
|
39
|
+
openPullRequest: 'The PR playbook is delivering the implemented branch through a pull request.',
|
|
35
40
|
awaitBossReply: 'Waiting for Boss to answer Analyst.',
|
|
36
41
|
failed: 'The development planning workflow failed and is waiting for a new development request.',
|
|
37
42
|
discussionComplete: 'The planning discussion concluded after a Boss reply with no repository work to follow.',
|
|
@@ -89,6 +94,16 @@ function isDecideThenCode({ event }) {
|
|
|
89
94
|
return (outputGuard(event, 'decideThenCode') &&
|
|
90
95
|
outputString(event, 'planningResult') !== undefined);
|
|
91
96
|
}
|
|
97
|
+
// DR-050: the two pull-request outcomes select the same development paths
|
|
98
|
+
// as `code` and `decide then code`, entered through `branch` first.
|
|
99
|
+
function isCodeViaPullRequest({ event }) {
|
|
100
|
+
return (outputGuard(event, 'codeViaPullRequest') &&
|
|
101
|
+
outputString(event, 'planningResult') !== undefined);
|
|
102
|
+
}
|
|
103
|
+
function isDecideThenCodeViaPullRequest({ event, }) {
|
|
104
|
+
return (outputGuard(event, 'decideThenCodeViaPullRequest') &&
|
|
105
|
+
outputString(event, 'planningResult') !== undefined);
|
|
106
|
+
}
|
|
92
107
|
// Discussion complete is available only after a Boss reply: the round that
|
|
93
108
|
// produced it must itself have been resumed with Boss's answer.
|
|
94
109
|
function isDiscussionComplete({ context, event, }) {
|
|
@@ -111,6 +126,24 @@ function isDecideSuccessValue(value) {
|
|
|
111
126
|
function isDecideSuccess({ event }) {
|
|
112
127
|
return isDecideSuccessValue(childOutputOf(event));
|
|
113
128
|
}
|
|
129
|
+
// BRANCH's canonical successful terminal output carries the exact name of
|
|
130
|
+
// the new checked-out branch, the exact receipt-owned base revision, and the
|
|
131
|
+
// issue summary; DEV consumes exactly those three by name and never defaults
|
|
132
|
+
// a missing one.
|
|
133
|
+
function isBranchSuccessValue(value) {
|
|
134
|
+
return (isRecord(value) &&
|
|
135
|
+
isNonEmptyString(value.branch) &&
|
|
136
|
+
isNonEmptyString(value.baseRevision) &&
|
|
137
|
+
isNonEmptyString(value.issueSummary));
|
|
138
|
+
}
|
|
139
|
+
function isBranchSuccessForCode({ context, event, }) {
|
|
140
|
+
return (context.pullRequestPath === 'code' &&
|
|
141
|
+
isBranchSuccessValue(childOutputOf(event)));
|
|
142
|
+
}
|
|
143
|
+
function isBranchSuccessForDecide({ context, event, }) {
|
|
144
|
+
return (context.pullRequestPath === 'decide-then-code' &&
|
|
145
|
+
isBranchSuccessValue(childOutputOf(event)));
|
|
146
|
+
}
|
|
114
147
|
// CODE's canonical successful terminal output discriminates completion with
|
|
115
148
|
// `status: 'complete'`, carries the exact last CODE-owned commit, and
|
|
116
149
|
// affirms that every phase's review passed.
|
|
@@ -120,8 +153,22 @@ function isCodeSuccessValue(value) {
|
|
|
120
153
|
isNonEmptyString(value.lastCodeCommit) &&
|
|
121
154
|
value.allReviewsPassed === true);
|
|
122
155
|
}
|
|
123
|
-
|
|
124
|
-
|
|
156
|
+
// A plain path completes DEV on that proof alone, exactly as before DR-050.
|
|
157
|
+
function isPlainCodeSuccess({ context, event, }) {
|
|
158
|
+
return (context.deliveryViaPullRequest !== true &&
|
|
159
|
+
isCodeSuccessValue(childOutputOf(event)));
|
|
160
|
+
}
|
|
161
|
+
// A pull-request path additionally consumes the exact final evaluated
|
|
162
|
+
// repository revision for the `pr` call, so a CODE result lacking it does not
|
|
163
|
+
// prove the success that path requires.
|
|
164
|
+
function isCodeSuccessValueForPullRequest(value) {
|
|
165
|
+
return (isCodeSuccessValue(value) &&
|
|
166
|
+
isRecord(value) &&
|
|
167
|
+
isNonEmptyString(value.finalEvaluatedRevision));
|
|
168
|
+
}
|
|
169
|
+
function isCodeSuccessViaPullRequest({ context, event, }) {
|
|
170
|
+
return (context.deliveryViaPullRequest === true &&
|
|
171
|
+
isCodeSuccessValueForPullRequest(childOutputOf(event)));
|
|
125
172
|
}
|
|
126
173
|
function isStateValue(value, ancestors = new Set()) {
|
|
127
174
|
if (typeof value === 'string')
|
|
@@ -361,6 +408,31 @@ function codeAfterDecideCallText(context) {
|
|
|
361
408
|
['Evaluated revision', context.evaluatedRevision ?? ''],
|
|
362
409
|
]);
|
|
363
410
|
}
|
|
411
|
+
function branchCallText(context) {
|
|
412
|
+
return quotedRelay(planningRelayValues(context));
|
|
413
|
+
}
|
|
414
|
+
// DEV-6: every placeholder is substituted from typed context that only a
|
|
415
|
+
// child's canonical structured result populated — never from player prose.
|
|
416
|
+
function pullRequestCallText(context) {
|
|
417
|
+
return quotedRelay([
|
|
418
|
+
['Original request', context.developmentRequest ?? ''],
|
|
419
|
+
['Issue summary', context.issueSummary ?? ''],
|
|
420
|
+
['Branch', context.branch ?? ''],
|
|
421
|
+
['Base revision', context.baseRevision ?? ''],
|
|
422
|
+
['CODE commit', context.lastCodeCommit ?? ''],
|
|
423
|
+
['Evaluated revision', context.finalEvaluatedRevision ?? ''],
|
|
424
|
+
]);
|
|
425
|
+
}
|
|
426
|
+
function acceptedPlanningPath(context, event, pullRequestPath) {
|
|
427
|
+
return {
|
|
428
|
+
planningResult: outputString(event, 'planningResult'),
|
|
429
|
+
discussionExchanges: archivedExchanges(context),
|
|
430
|
+
deliveryViaPullRequest: pullRequestPath !== undefined,
|
|
431
|
+
pullRequestPath,
|
|
432
|
+
pendingBossQuestion: undefined,
|
|
433
|
+
bossReply: undefined,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
364
436
|
const machineSetup = setup({
|
|
365
437
|
types: {},
|
|
366
438
|
actors: {
|
|
@@ -375,11 +447,18 @@ const machineSetup = setup({
|
|
|
375
447
|
isDiscussionComplete,
|
|
376
448
|
isCodePath,
|
|
377
449
|
isDecideThenCode,
|
|
450
|
+
isCodeViaPullRequest,
|
|
451
|
+
isDecideThenCodeViaPullRequest,
|
|
378
452
|
needsBossReply,
|
|
379
|
-
|
|
453
|
+
isBranchSuccessForCode,
|
|
454
|
+
isBranchSuccessForDecide,
|
|
455
|
+
isCodeSuccessViaPullRequest,
|
|
456
|
+
isPlainCodeSuccess,
|
|
380
457
|
isDecideSuccess,
|
|
458
|
+
authoredBranchFailure: authoredChildFailureGuard('branch'),
|
|
381
459
|
authoredCodeFailure: authoredChildFailureGuard('code'),
|
|
382
460
|
authoredDecideFailure: authoredChildFailureGuard('decide'),
|
|
461
|
+
authoredPrFailure: authoredChildFailureGuard('pr'),
|
|
383
462
|
emptyBossReply: ({ event }) => event.type === 'BOSS_REPLY' && event.answer.trim().length === 0,
|
|
384
463
|
resumesPlanAnalysis: ({ context, event }) => event.type === 'BOSS_REPLY' &&
|
|
385
464
|
event.answer.trim().length > 0 &&
|
|
@@ -398,6 +477,13 @@ const machineSetup = setup({
|
|
|
398
477
|
planningResult: undefined,
|
|
399
478
|
decideCommit: undefined,
|
|
400
479
|
evaluatedRevision: undefined,
|
|
480
|
+
deliveryViaPullRequest: false,
|
|
481
|
+
pullRequestPath: undefined,
|
|
482
|
+
branch: undefined,
|
|
483
|
+
baseRevision: undefined,
|
|
484
|
+
issueSummary: undefined,
|
|
485
|
+
lastCodeCommit: undefined,
|
|
486
|
+
finalEvaluatedRevision: undefined,
|
|
401
487
|
completion: undefined,
|
|
402
488
|
childOutput: undefined,
|
|
403
489
|
childFailure: undefined,
|
|
@@ -412,18 +498,10 @@ const machineSetup = setup({
|
|
|
412
498
|
pendingBossQuestion: undefined,
|
|
413
499
|
bossReply: undefined,
|
|
414
500
|
})),
|
|
415
|
-
rememberCodePath: assign(({ context, event }) => (
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
bossReply: undefined,
|
|
420
|
-
})),
|
|
421
|
-
rememberDecidePath: assign(({ context, event }) => ({
|
|
422
|
-
planningResult: outputString(event, 'planningResult'),
|
|
423
|
-
discussionExchanges: archivedExchanges(context),
|
|
424
|
-
pendingBossQuestion: undefined,
|
|
425
|
-
bossReply: undefined,
|
|
426
|
-
})),
|
|
501
|
+
rememberCodePath: assign(({ context, event }) => acceptedPlanningPath(context, event)),
|
|
502
|
+
rememberDecidePath: assign(({ context, event }) => acceptedPlanningPath(context, event)),
|
|
503
|
+
rememberCodeViaPullRequestPath: assign(({ context, event }) => acceptedPlanningPath(context, event, 'code')),
|
|
504
|
+
rememberDecideThenCodeViaPullRequestPath: assign(({ context, event }) => acceptedPlanningPath(context, event, 'decide-then-code')),
|
|
427
505
|
rememberPendingQuestion: assign(({ context, event }) => {
|
|
428
506
|
const question = outputString(event, 'question');
|
|
429
507
|
if (question === undefined || !outputGuard(event, 'needsBossReply')) {
|
|
@@ -447,6 +525,16 @@ const machineSetup = setup({
|
|
|
447
525
|
pendingBossQuestion: undefined,
|
|
448
526
|
bossReply: undefined,
|
|
449
527
|
}),
|
|
528
|
+
rememberBranchResult: assign(({ event }) => {
|
|
529
|
+
const output = childOutputOf(event);
|
|
530
|
+
if (!isBranchSuccessValue(output))
|
|
531
|
+
return {};
|
|
532
|
+
return {
|
|
533
|
+
branch: output.branch,
|
|
534
|
+
baseRevision: output.baseRevision,
|
|
535
|
+
issueSummary: output.issueSummary,
|
|
536
|
+
};
|
|
537
|
+
}),
|
|
450
538
|
rememberDecideResult: assign(({ event }) => {
|
|
451
539
|
const output = childOutputOf(event);
|
|
452
540
|
if (!isDecideSuccessValue(output))
|
|
@@ -456,6 +544,15 @@ const machineSetup = setup({
|
|
|
456
544
|
evaluatedRevision: output.evaluatedRevision,
|
|
457
545
|
};
|
|
458
546
|
}),
|
|
547
|
+
rememberCodeResult: assign(({ event }) => {
|
|
548
|
+
const output = childOutputOf(event);
|
|
549
|
+
if (!isCodeSuccessValueForPullRequest(output))
|
|
550
|
+
return {};
|
|
551
|
+
return {
|
|
552
|
+
lastCodeCommit: output.lastCodeCommit,
|
|
553
|
+
finalEvaluatedRevision: output.finalEvaluatedRevision,
|
|
554
|
+
};
|
|
555
|
+
}),
|
|
459
556
|
completeWithChildSuccess: assign(({ event }) => {
|
|
460
557
|
const output = childOutputOf(event);
|
|
461
558
|
return {
|
|
@@ -463,6 +560,10 @@ const machineSetup = setup({
|
|
|
463
560
|
...(output === undefined ? {} : { childOutput: output }),
|
|
464
561
|
};
|
|
465
562
|
}),
|
|
563
|
+
completeWithInsufficientBranchResult: assign(({ event }) => ({
|
|
564
|
+
completion: 'child-failed',
|
|
565
|
+
childFailure: insufficientChildResult(event, 'branch'),
|
|
566
|
+
})),
|
|
466
567
|
completeWithInsufficientCodeResult: assign(({ event }) => ({
|
|
467
568
|
completion: 'child-failed',
|
|
468
569
|
childFailure: insufficientChildResult(event, 'code'),
|
|
@@ -471,6 +572,10 @@ const machineSetup = setup({
|
|
|
471
572
|
completion: 'child-failed',
|
|
472
573
|
childFailure: insufficientChildResult(event, 'decide'),
|
|
473
574
|
})),
|
|
575
|
+
completeWithBranchFailure: assign(({ event }) => ({
|
|
576
|
+
completion: 'child-failed',
|
|
577
|
+
childFailure: relayedChildFailure(event, 'branch'),
|
|
578
|
+
})),
|
|
474
579
|
completeWithCodeFailure: assign(({ event }) => ({
|
|
475
580
|
completion: 'child-failed',
|
|
476
581
|
childFailure: relayedChildFailure(event, 'code'),
|
|
@@ -479,6 +584,10 @@ const machineSetup = setup({
|
|
|
479
584
|
completion: 'child-failed',
|
|
480
585
|
childFailure: relayedChildFailure(event, 'decide'),
|
|
481
586
|
})),
|
|
587
|
+
completeWithPrFailure: assign(({ event }) => ({
|
|
588
|
+
completion: 'child-failed',
|
|
589
|
+
childFailure: relayedChildFailure(event, 'pr'),
|
|
590
|
+
})),
|
|
482
591
|
rememberActorError: assign(({ event }) => ({
|
|
483
592
|
lastError: event.error,
|
|
484
593
|
})),
|
|
@@ -493,6 +602,7 @@ export const devMachine = machineSetup.createMachine({
|
|
|
493
602
|
context: ({ input }) => ({
|
|
494
603
|
runResults: typeof input.runResults === 'string' ? input.runResults : '',
|
|
495
604
|
discussionExchanges: [],
|
|
605
|
+
deliveryViaPullRequest: false,
|
|
496
606
|
}),
|
|
497
607
|
output: ({ context }) => {
|
|
498
608
|
if (context.completion === 'discussion-complete') {
|
|
@@ -501,7 +611,9 @@ export const devMachine = machineSetup.createMachine({
|
|
|
501
611
|
if (context.completion === 'complete') {
|
|
502
612
|
return {
|
|
503
613
|
status: 'complete',
|
|
504
|
-
|
|
614
|
+
// `done` is entered by `pr` on a pull-request path and by `code` on a
|
|
615
|
+
// plain path; no other arm completes the workflow.
|
|
616
|
+
childPlaybookId: context.deliveryViaPullRequest ? 'pr' : 'code',
|
|
505
617
|
...(context.childOutput === undefined
|
|
506
618
|
? {}
|
|
507
619
|
: { childOutput: context.childOutput }),
|
|
@@ -594,6 +706,36 @@ export const devMachine = machineSetup.createMachine({
|
|
|
594
706
|
'rememberDecidePath',
|
|
595
707
|
],
|
|
596
708
|
},
|
|
709
|
+
{
|
|
710
|
+
guard: 'isCodeViaPullRequest',
|
|
711
|
+
target: 'createBranch',
|
|
712
|
+
actions: [
|
|
713
|
+
{
|
|
714
|
+
type: 'playbook.acceptedOutcome',
|
|
715
|
+
params: {
|
|
716
|
+
source: 'planAnalysis',
|
|
717
|
+
target: 'createBranch',
|
|
718
|
+
acceptedOutcome: 'codeViaPullRequest',
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
'rememberCodeViaPullRequestPath',
|
|
722
|
+
],
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
guard: 'isDecideThenCodeViaPullRequest',
|
|
726
|
+
target: 'createBranch',
|
|
727
|
+
actions: [
|
|
728
|
+
{
|
|
729
|
+
type: 'playbook.acceptedOutcome',
|
|
730
|
+
params: {
|
|
731
|
+
source: 'planAnalysis',
|
|
732
|
+
target: 'createBranch',
|
|
733
|
+
acceptedOutcome: 'decideThenCodeViaPullRequest',
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
'rememberDecideThenCodeViaPullRequestPath',
|
|
737
|
+
],
|
|
738
|
+
},
|
|
597
739
|
{
|
|
598
740
|
guard: 'needsBossReply',
|
|
599
741
|
target: 'awaitBossReply',
|
|
@@ -617,6 +759,45 @@ export const devMachine = machineSetup.createMachine({
|
|
|
617
759
|
onError: { target: 'failed', actions: 'rememberActorError' },
|
|
618
760
|
},
|
|
619
761
|
},
|
|
762
|
+
createBranch: {
|
|
763
|
+
id: 'createBranch',
|
|
764
|
+
description: STATE_DESCRIPTIONS.createBranch,
|
|
765
|
+
meta: playbookMeta('createBranch'),
|
|
766
|
+
tags: ['playbook.suspended'],
|
|
767
|
+
invoke: {
|
|
768
|
+
src: 'playbook',
|
|
769
|
+
input: ({ context }) => ({
|
|
770
|
+
stateId: 'createBranch',
|
|
771
|
+
sourceItem: 'DEV-5',
|
|
772
|
+
playbookId: 'branch',
|
|
773
|
+
text: branchCallText(context),
|
|
774
|
+
}),
|
|
775
|
+
onDone: [
|
|
776
|
+
{
|
|
777
|
+
guard: 'isBranchSuccessForCode',
|
|
778
|
+
target: 'callCode',
|
|
779
|
+
actions: 'rememberBranchResult',
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
guard: 'isBranchSuccessForDecide',
|
|
783
|
+
target: 'callDecide',
|
|
784
|
+
actions: 'rememberBranchResult',
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
target: 'reportedChildFailure',
|
|
788
|
+
actions: 'completeWithInsufficientBranchResult',
|
|
789
|
+
},
|
|
790
|
+
],
|
|
791
|
+
onError: [
|
|
792
|
+
{
|
|
793
|
+
guard: 'authoredBranchFailure',
|
|
794
|
+
target: 'reportedChildFailure',
|
|
795
|
+
actions: 'completeWithBranchFailure',
|
|
796
|
+
},
|
|
797
|
+
{ target: 'failed', actions: 'rememberActorError' },
|
|
798
|
+
],
|
|
799
|
+
},
|
|
800
|
+
},
|
|
620
801
|
callCode: {
|
|
621
802
|
id: 'callCode',
|
|
622
803
|
description: STATE_DESCRIPTIONS.callCode,
|
|
@@ -632,7 +813,12 @@ export const devMachine = machineSetup.createMachine({
|
|
|
632
813
|
}),
|
|
633
814
|
onDone: [
|
|
634
815
|
{
|
|
635
|
-
guard: '
|
|
816
|
+
guard: 'isCodeSuccessViaPullRequest',
|
|
817
|
+
target: 'openPullRequest',
|
|
818
|
+
actions: 'rememberCodeResult',
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
guard: 'isPlainCodeSuccess',
|
|
636
822
|
target: 'done',
|
|
637
823
|
actions: 'completeWithChildSuccess',
|
|
638
824
|
},
|
|
@@ -700,7 +886,12 @@ export const devMachine = machineSetup.createMachine({
|
|
|
700
886
|
}),
|
|
701
887
|
onDone: [
|
|
702
888
|
{
|
|
703
|
-
guard: '
|
|
889
|
+
guard: 'isCodeSuccessViaPullRequest',
|
|
890
|
+
target: 'openPullRequest',
|
|
891
|
+
actions: 'rememberCodeResult',
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
guard: 'isPlainCodeSuccess',
|
|
704
895
|
target: 'done',
|
|
705
896
|
actions: 'completeWithChildSuccess',
|
|
706
897
|
},
|
|
@@ -719,6 +910,32 @@ export const devMachine = machineSetup.createMachine({
|
|
|
719
910
|
],
|
|
720
911
|
},
|
|
721
912
|
},
|
|
913
|
+
openPullRequest: {
|
|
914
|
+
id: 'openPullRequest',
|
|
915
|
+
description: STATE_DESCRIPTIONS.openPullRequest,
|
|
916
|
+
meta: playbookMeta('openPullRequest'),
|
|
917
|
+
tags: ['playbook.suspended'],
|
|
918
|
+
invoke: {
|
|
919
|
+
src: 'playbook',
|
|
920
|
+
input: ({ context }) => ({
|
|
921
|
+
stateId: 'openPullRequest',
|
|
922
|
+
sourceItem: 'DEV-6',
|
|
923
|
+
playbookId: 'pr',
|
|
924
|
+
text: pullRequestCallText(context),
|
|
925
|
+
}),
|
|
926
|
+
// DR-048: `pr` declares its terminal kinds, so `onDone` alone proves
|
|
927
|
+
// its success; DEV consumes none of its fields by name.
|
|
928
|
+
onDone: { target: 'done', actions: 'completeWithChildSuccess' },
|
|
929
|
+
onError: [
|
|
930
|
+
{
|
|
931
|
+
guard: 'authoredPrFailure',
|
|
932
|
+
target: 'reportedChildFailure',
|
|
933
|
+
actions: 'completeWithPrFailure',
|
|
934
|
+
},
|
|
935
|
+
{ target: 'failed', actions: 'rememberActorError' },
|
|
936
|
+
],
|
|
937
|
+
},
|
|
938
|
+
},
|
|
722
939
|
awaitBossReply: {
|
|
723
940
|
id: 'awaitBossReply',
|
|
724
941
|
description: STATE_DESCRIPTIONS.awaitBossReply,
|