@sublang/playbook 0.8.0 → 1.0.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 +243 -193
- package/package.json +52 -17
- package/reference/sdlc/captain.md +102 -0
- package/reference/sdlc/captain.playbook/captain.fsm.d.ts +227 -0
- package/reference/sdlc/captain.playbook/captain.fsm.js +628 -0
- package/reference/sdlc/captain.playbook/captain.fsm.ts +851 -0
- package/reference/sdlc/captain.playbook/captain.gears.md +60 -0
- package/reference/sdlc/captain.playbook/captain.playbook.d.ts +23 -0
- package/reference/sdlc/captain.playbook/captain.playbook.js +1053 -0
- package/reference/sdlc/captain.playbook/captain.playbook.ts +1144 -0
- package/reference/sdlc/code.playbook/bin/playbook.js +580 -0
- package/reference/sdlc/code.playbook/bin/run.js +893 -0
- package/reference/sdlc/code.playbook/code.fsm.d.ts +11 -4
- package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +2 -2
- package/reference/sdlc/code.playbook/code.fsm.introspect.js +1 -1
- package/reference/sdlc/code.playbook/code.fsm.introspect.ts +6 -6
- package/reference/sdlc/code.playbook/code.fsm.js +334 -102
- package/reference/sdlc/code.playbook/code.fsm.ts +470 -182
- package/reference/sdlc/code.playbook/code.gears.md +11 -10
- package/reference/sdlc/code.playbook/code.playbook.d.ts +18 -9
- package/reference/sdlc/code.playbook/code.playbook.js +1098 -202
- package/reference/sdlc/code.playbook/code.playbook.ts +1440 -258
- package/reference/sdlc/code.playbook/code.registry.d.ts +17 -5
- package/reference/sdlc/code.playbook/code.registry.js +49 -34
- package/reference/sdlc/code.playbook/code.registry.ts +75 -41
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +16 -8
- package/reference/sdlc/code.playbook/playbook-captain.js +1005 -240
- package/reference/sdlc/code.playbook/playbook-captain.ts +1310 -301
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +68 -0
- package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +396 -0
- package/reference/sdlc/discuss.playbook/discuss.fsm.js +2066 -0
- package/reference/sdlc/discuss.playbook/discuss.fsm.ts +2464 -0
- package/reference/sdlc/discuss.playbook/discuss.gears.md +251 -0
- package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +113 -0
- package/reference/sdlc/discuss.playbook/discuss.playbook.js +1514 -0
- package/reference/sdlc/discuss.playbook/discuss.playbook.ts +1926 -0
- package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +58 -0
- package/reference/sdlc/discuss.playbook/discuss.registry.js +97 -0
- package/reference/sdlc/discuss.playbook/discuss.registry.ts +153 -0
- package/slc/gears2fsm.md +557 -57
- package/slc/link.md +1097 -80
- package/slc/optimize.md +88 -0
- package/slc/text2gears.md +247 -5
- package/src/runtime.d.ts +145 -3
- package/src/runtime.ts +200 -2
- package/src/xstate-runtime.d.ts +94 -0
- package/src/xstate-runtime.js +1247 -0
- package/src/xstate-runtime.ts +1802 -0
- package/reference/sdlc/code.playbook/bin/playbook-code.js +0 -487
- package/reference/sdlc/code.playbook/code.tmux-play.d.ts +0 -4
- package/reference/sdlc/code.playbook/code.tmux-play.js +0 -11
- package/reference/sdlc/code.playbook/code.tmux-play.ts +0 -29
- package/reference/sdlc/code.playbook/playbook-code.config.template.yaml +0 -72
- package/reference/sdlc/code.playbook/tmux-play.config.yaml +0 -55
- package/reference/sdlc/code.playbook/tmux-play.production.config.yaml +0 -38
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
// XState v5's generics do not flow through helpers declared outside the
|
|
5
5
|
// machine (e.g., shared guard/action factories, the `readyEvents` block),
|
|
6
6
|
// so strict checking emits structural-mismatch noise without surfacing real
|
|
7
|
-
// bugs. The runner overrides `
|
|
7
|
+
// bugs. The runner overrides `player` via `.provide({ actors: { ... } })`
|
|
8
8
|
// and re-asserts the public surface (`CodingContext`, `CodingEvent`,
|
|
9
|
-
// `
|
|
9
|
+
// `PlayerInput`, `PlayerOutput`) at the boundary.
|
|
10
10
|
// @ts-nocheck
|
|
11
11
|
|
|
12
12
|
import { assign, fromPromise, setup } from 'xstate';
|
|
@@ -43,6 +43,7 @@ type AfterReview = 'continueIr' | 'summarizeSpecs' | 'done';
|
|
|
43
43
|
type ResumableStateId = Exclude<JumpableStateId, 'ready' | 'failed'>;
|
|
44
44
|
|
|
45
45
|
type PendingBossQuestion = {
|
|
46
|
+
questionId: ResumableStateId;
|
|
46
47
|
resumeStateId: ResumableStateId;
|
|
47
48
|
sourceItem: string;
|
|
48
49
|
player: Player;
|
|
@@ -50,7 +51,7 @@ type PendingBossQuestion = {
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
export type CaptainInput = {
|
|
53
|
-
|
|
54
|
+
stateId: ResumableStateId;
|
|
54
55
|
sourceItem: string;
|
|
55
56
|
prompt: string;
|
|
56
57
|
result: Record<string, string>;
|
|
@@ -67,8 +68,9 @@ export type CaptainInput = {
|
|
|
67
68
|
coderPlayer?: string;
|
|
68
69
|
reviewerPlayer?: string;
|
|
69
70
|
// Routing-only: the configured Committer-alias player id (`coder` /
|
|
70
|
-
// `reviewer`) threaded from
|
|
71
|
-
// (PBRT-8 / PBRT-30).
|
|
71
|
+
// `reviewer`) threaded from
|
|
72
|
+
// `captain.options.playbooks.code.options.committer` (PBRT-8 / PBRT-30).
|
|
73
|
+
// It selects which host pane runs a `Committer`
|
|
72
74
|
// commit; it is not a prompt-placeholder source, so it never affects
|
|
73
75
|
// <coder-llm> / <reviewer-llm> substitution or any labelled block,
|
|
74
76
|
// and `input.player` stays `Committer` (PLAYBOOK-3).
|
|
@@ -77,6 +79,10 @@ export type CaptainInput = {
|
|
|
77
79
|
bossReply?: string;
|
|
78
80
|
};
|
|
79
81
|
|
|
82
|
+
export type PlayerInput = CaptainInput & {
|
|
83
|
+
player: Player;
|
|
84
|
+
};
|
|
85
|
+
|
|
80
86
|
export type CaptainOutput = {
|
|
81
87
|
guard: string;
|
|
82
88
|
irNumber?: string;
|
|
@@ -88,6 +94,8 @@ export type CaptainOutput = {
|
|
|
88
94
|
[k: string]: unknown;
|
|
89
95
|
};
|
|
90
96
|
|
|
97
|
+
export type PlayerOutput = CaptainOutput;
|
|
98
|
+
|
|
91
99
|
export type CodingInput = {
|
|
92
100
|
intent?: string;
|
|
93
101
|
irNumber?: string;
|
|
@@ -120,7 +128,11 @@ export type CodingEvent =
|
|
|
120
128
|
intent?: string;
|
|
121
129
|
irNumber?: string;
|
|
122
130
|
}
|
|
123
|
-
| {
|
|
131
|
+
| {
|
|
132
|
+
type: 'BOSS_REPLY';
|
|
133
|
+
answer: string;
|
|
134
|
+
questionId?: ResumableStateId;
|
|
135
|
+
};
|
|
124
136
|
|
|
125
137
|
const jumpableStateIds = [
|
|
126
138
|
'ready',
|
|
@@ -168,39 +180,113 @@ const resumableStateIds = [
|
|
|
168
180
|
'commitJoint',
|
|
169
181
|
] as const satisfies readonly ResumableStateId[];
|
|
170
182
|
|
|
183
|
+
const stateDescriptions = {
|
|
184
|
+
ready: 'Idle hub: waits for Boss to start or resume a coding sub-procedure.',
|
|
185
|
+
awaitBossReply: 'Waiting for Boss to answer a player question.',
|
|
186
|
+
planAndImplement:
|
|
187
|
+
'CODE-1: Coder assesses a Boss intent and either implements a single-commit change or drafts an IR.',
|
|
188
|
+
respondToReview: 'CODE-2: Coder addresses or challenges Reviewer findings.',
|
|
189
|
+
continueIr:
|
|
190
|
+
'CODE-3: Coder continues an IR after the previous task or IR draft passed review.',
|
|
191
|
+
summarizeSpecs:
|
|
192
|
+
'CODE-4: Coder summarizes a completed IR into minimal spec items.',
|
|
193
|
+
reviewBossCommitSpecs:
|
|
194
|
+
'CODE-5: Reviewer reviews a Boss-intent commit whose changes are only in @specs/{user,dev,test}/.',
|
|
195
|
+
reviewBossCommitCode:
|
|
196
|
+
'CODE-6: Reviewer reviews a Boss-intent commit whose changes are only outside @specs/{user,dev,test}/.',
|
|
197
|
+
reviewBossCommitMixed:
|
|
198
|
+
'CODE-7: Reviewer reviews a Boss-intent commit whose changes span both @specs/{user,dev,test}/ and other files.',
|
|
199
|
+
reviewIrTaskCommitSpecs:
|
|
200
|
+
'CODE-8: Reviewer reviews an IR-task commit whose changes are only in @specs/{user,dev,test}/.',
|
|
201
|
+
reviewIrTaskCommitCode:
|
|
202
|
+
'CODE-9: Reviewer reviews an IR-task commit whose changes are only outside @specs/{user,dev,test}/.',
|
|
203
|
+
reviewIrTaskCommitMixed:
|
|
204
|
+
'CODE-10: Reviewer reviews an IR-task commit whose changes span both @specs/{user,dev,test}/ and other files.',
|
|
205
|
+
reviewChangesSpecs:
|
|
206
|
+
'CODE-11: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ with no accompanying rebuttals.',
|
|
207
|
+
reviewChangesCode:
|
|
208
|
+
'CODE-12: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ with no accompanying rebuttals.',
|
|
209
|
+
reviewChangesMixed:
|
|
210
|
+
'CODE-13: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files with no accompanying rebuttals.',
|
|
211
|
+
reviewChangesAndChallengesSpecs:
|
|
212
|
+
'CODE-15: Reviewer reviews uncommitted Coder changes that touch only @specs/{user,dev,test}/ and adjudicates accompanying rebuttals in one round.',
|
|
213
|
+
reviewChangesAndChallengesCode:
|
|
214
|
+
'CODE-16: Reviewer reviews uncommitted Coder changes that touch only files outside @specs/{user,dev,test}/ and adjudicates accompanying rebuttals in one round.',
|
|
215
|
+
reviewChangesAndChallengesMixed:
|
|
216
|
+
'CODE-17: Reviewer reviews uncommitted Coder changes that touch both @specs/{user,dev,test}/ and other files and adjudicates accompanying rebuttals in one round.',
|
|
217
|
+
adjudicateChallenges:
|
|
218
|
+
'CODE-14: Reviewer adjudicates Coder rebuttals against the prior review when Coder produced no code edits this round.',
|
|
219
|
+
commitCoderInitial:
|
|
220
|
+
'CODE-18: Committer commits Coder Initial Changes when Reviewer has not played since the last commit.',
|
|
221
|
+
commitJoint:
|
|
222
|
+
'CODE-19: Committer commits changes when both Coder and Reviewer have played since the last commit.',
|
|
223
|
+
failed:
|
|
224
|
+
'Captures the last Captain error so the runner can report it. Boss may resume from here.',
|
|
225
|
+
done: 'The selected coding workflow has completed.',
|
|
226
|
+
} as const satisfies Record<
|
|
227
|
+
JumpableStateId | 'awaitBossReply' | 'done',
|
|
228
|
+
string
|
|
229
|
+
>;
|
|
230
|
+
|
|
231
|
+
const playbookMeta = <StateId extends keyof typeof stateDescriptions>(
|
|
232
|
+
stateId: StateId,
|
|
233
|
+
) => ({
|
|
234
|
+
playbook: {
|
|
235
|
+
stateId,
|
|
236
|
+
description: stateDescriptions[stateId],
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
|
|
171
240
|
const outputOf = (event: unknown): CaptainOutput | undefined =>
|
|
172
241
|
(event as { output?: CaptainOutput }).output;
|
|
173
242
|
|
|
174
|
-
const guardIs =
|
|
175
|
-
(
|
|
243
|
+
const guardIs =
|
|
244
|
+
(guard: string) =>
|
|
245
|
+
({ event }: { event: unknown }) =>
|
|
246
|
+
outputOf(event)?.guard === guard;
|
|
176
247
|
|
|
177
|
-
const guardAndOrigin =
|
|
248
|
+
const guardAndOrigin =
|
|
249
|
+
(guard: string, origin: ChangeOrigin) =>
|
|
178
250
|
({ context, event }: { context: CodingContext; event: unknown }) =>
|
|
179
251
|
outputOf(event)?.guard === guard && context.changeOrigin === origin;
|
|
180
252
|
|
|
181
|
-
const acceptedAfter =
|
|
253
|
+
const acceptedAfter =
|
|
254
|
+
(subject: ReviewSubject) =>
|
|
182
255
|
({ context, event }: { context: CodingContext; event: unknown }) =>
|
|
183
256
|
outputOf(event)?.guard === 'accepted' && context.reviewSubject === subject;
|
|
184
257
|
|
|
185
|
-
const noFindingsAfter =
|
|
258
|
+
const noFindingsAfter =
|
|
259
|
+
(afterReview: AfterReview) =>
|
|
186
260
|
({ context, event }: { context: CodingContext; event: unknown }) =>
|
|
187
|
-
outputOf(event)?.guard === 'noFindings' &&
|
|
261
|
+
outputOf(event)?.guard === 'noFindings' &&
|
|
262
|
+
context.afterReview === afterReview;
|
|
188
263
|
|
|
189
264
|
const rememberCaptainOutput = assign({
|
|
190
265
|
lastResult: ({ event }: { event: unknown }) => outputOf(event),
|
|
191
266
|
lastError: () => undefined,
|
|
192
267
|
irNumber: ({ context, event }: { context: CodingContext; event: unknown }) =>
|
|
193
268
|
outputOf(event)?.irNumber ?? context.irNumber,
|
|
194
|
-
taskDescription: ({
|
|
195
|
-
|
|
269
|
+
taskDescription: ({
|
|
270
|
+
context,
|
|
271
|
+
event,
|
|
272
|
+
}: {
|
|
273
|
+
context: CodingContext;
|
|
274
|
+
event: unknown;
|
|
275
|
+
}) => outputOf(event)?.taskDescription ?? context.taskDescription,
|
|
196
276
|
reviews: ({ context, event }: { context: CodingContext; event: unknown }) =>
|
|
197
277
|
outputOf(event)?.reviews ?? context.reviews,
|
|
198
|
-
challenges: ({
|
|
199
|
-
|
|
278
|
+
challenges: ({
|
|
279
|
+
context,
|
|
280
|
+
event,
|
|
281
|
+
}: {
|
|
282
|
+
context: CodingContext;
|
|
283
|
+
event: unknown;
|
|
284
|
+
}) => outputOf(event)?.challenges ?? context.challenges,
|
|
200
285
|
});
|
|
201
286
|
|
|
202
287
|
const rememberCaptainError = assign({
|
|
203
|
-
lastError: ({ event }: { event: unknown }) =>
|
|
288
|
+
lastError: ({ event }: { event: unknown }) =>
|
|
289
|
+
(event as { error?: unknown }).error,
|
|
204
290
|
});
|
|
205
291
|
|
|
206
292
|
const rememberEmptyBossReplyError = assign({
|
|
@@ -214,10 +300,10 @@ const rememberBossInput = assign({
|
|
|
214
300
|
(event as { irNumber?: string }).irNumber ?? context.irNumber,
|
|
215
301
|
});
|
|
216
302
|
|
|
217
|
-
type
|
|
303
|
+
type PlayerInputFactory = (context: Partial<CodingContext>) => PlayerInput;
|
|
218
304
|
|
|
219
305
|
const needsBossReplyDescription =
|
|
220
|
-
"The
|
|
306
|
+
"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>`.";
|
|
221
307
|
|
|
222
308
|
const bossReplyInputFields = (context: Partial<CodingContext>) => ({
|
|
223
309
|
pendingBossQuestion: context.pendingBossQuestion,
|
|
@@ -243,9 +329,15 @@ const captainStateMetadata = {
|
|
|
243
329
|
reviewChangesSpecs: { sourceItem: 'CODE-11', player: 'Reviewer' },
|
|
244
330
|
reviewChangesCode: { sourceItem: 'CODE-12', player: 'Reviewer' },
|
|
245
331
|
reviewChangesMixed: { sourceItem: 'CODE-13', player: 'Reviewer' },
|
|
246
|
-
reviewChangesAndChallengesSpecs: {
|
|
332
|
+
reviewChangesAndChallengesSpecs: {
|
|
333
|
+
sourceItem: 'CODE-15',
|
|
334
|
+
player: 'Reviewer',
|
|
335
|
+
},
|
|
247
336
|
reviewChangesAndChallengesCode: { sourceItem: 'CODE-16', player: 'Reviewer' },
|
|
248
|
-
reviewChangesAndChallengesMixed: {
|
|
337
|
+
reviewChangesAndChallengesMixed: {
|
|
338
|
+
sourceItem: 'CODE-17',
|
|
339
|
+
player: 'Reviewer',
|
|
340
|
+
},
|
|
249
341
|
adjudicateChallenges: { sourceItem: 'CODE-14', player: 'Reviewer' },
|
|
250
342
|
commitCoderInitial: { sourceItem: 'CODE-18', player: 'Committer' },
|
|
251
343
|
commitJoint: { sourceItem: 'CODE-19', player: 'Committer' },
|
|
@@ -254,7 +346,8 @@ const captainStateMetadata = {
|
|
|
254
346
|
{ sourceItem: string; player: Player }
|
|
255
347
|
>;
|
|
256
348
|
|
|
257
|
-
const planAndImplementInput:
|
|
349
|
+
const planAndImplementInput: PlayerInputFactory = (context) => ({
|
|
350
|
+
stateId: 'planAndImplement',
|
|
258
351
|
player: 'Coder',
|
|
259
352
|
sourceItem: 'CODE-1',
|
|
260
353
|
intent: context.intent,
|
|
@@ -274,7 +367,8 @@ const planAndImplementInput: CaptainInputFactory = (context) => ({
|
|
|
274
367
|
}),
|
|
275
368
|
});
|
|
276
369
|
|
|
277
|
-
const continueIrInput:
|
|
370
|
+
const continueIrInput: PlayerInputFactory = (context) => ({
|
|
371
|
+
stateId: 'continueIr',
|
|
278
372
|
player: 'Coder',
|
|
279
373
|
sourceItem: 'CODE-3',
|
|
280
374
|
irNumber: context.irNumber,
|
|
@@ -292,7 +386,8 @@ const continueIrInput: CaptainInputFactory = (context) => ({
|
|
|
292
386
|
}),
|
|
293
387
|
});
|
|
294
388
|
|
|
295
|
-
const summarizeSpecsInput:
|
|
389
|
+
const summarizeSpecsInput: PlayerInputFactory = (context) => ({
|
|
390
|
+
stateId: 'summarizeSpecs',
|
|
296
391
|
player: 'Coder',
|
|
297
392
|
sourceItem: 'CODE-4',
|
|
298
393
|
irNumber: context.irNumber,
|
|
@@ -328,6 +423,7 @@ const setPendingBossQuestion = (resumeStateId: ResumableStateId) =>
|
|
|
328
423
|
}) => {
|
|
329
424
|
const input = captainStateMetadata[resumeStateId];
|
|
330
425
|
return {
|
|
426
|
+
questionId: resumeStateId,
|
|
331
427
|
resumeStateId,
|
|
332
428
|
sourceItem: input.sourceItem,
|
|
333
429
|
player: input.player,
|
|
@@ -350,7 +446,9 @@ const clearBossReplyContext = assign({
|
|
|
350
446
|
const actionsArray = (actions: unknown) =>
|
|
351
447
|
actions === undefined ? [] : Array.isArray(actions) ? actions : [actions];
|
|
352
448
|
|
|
353
|
-
const withClearBossReplyContext = <T extends { actions?: unknown }>(
|
|
449
|
+
const withClearBossReplyContext = <T extends { actions?: unknown }>(
|
|
450
|
+
transition: T,
|
|
451
|
+
): T => ({
|
|
354
452
|
...transition,
|
|
355
453
|
actions: [clearBossReplyContext, ...actionsArray(transition.actions)],
|
|
356
454
|
});
|
|
@@ -370,9 +468,17 @@ const bossInterrupts = (
|
|
|
370
468
|
const resumableStates = (ids: readonly ResumableStateId[]) =>
|
|
371
469
|
ids.map((id) => ({
|
|
372
470
|
target: `#${id}` as const,
|
|
373
|
-
guard: ({
|
|
471
|
+
guard: ({
|
|
472
|
+
context,
|
|
473
|
+
event,
|
|
474
|
+
}: {
|
|
475
|
+
context: CodingContext;
|
|
476
|
+
event: CodingEvent;
|
|
477
|
+
}) =>
|
|
374
478
|
event.type === 'BOSS_REPLY' &&
|
|
375
|
-
context.pendingBossQuestion?.resumeStateId === id
|
|
479
|
+
context.pendingBossQuestion?.resumeStateId === id &&
|
|
480
|
+
(event.questionId === undefined ||
|
|
481
|
+
event.questionId === context.pendingBossQuestion.questionId),
|
|
376
482
|
reenter: true,
|
|
377
483
|
actions: rememberBossReply,
|
|
378
484
|
}));
|
|
@@ -450,8 +556,8 @@ const awaitBossReplyEvents = {
|
|
|
450
556
|
],
|
|
451
557
|
};
|
|
452
558
|
|
|
453
|
-
const
|
|
454
|
-
throw new Error('
|
|
559
|
+
const playerPlaceholder = fromPromise<PlayerOutput, PlayerInput>(async () => {
|
|
560
|
+
throw new Error('player actor must be provided by the runner');
|
|
455
561
|
});
|
|
456
562
|
|
|
457
563
|
export const codingMachine = setup({
|
|
@@ -461,7 +567,7 @@ export const codingMachine = setup({
|
|
|
461
567
|
input: CodingInput | undefined;
|
|
462
568
|
},
|
|
463
569
|
actors: {
|
|
464
|
-
|
|
570
|
+
player: playerPlaceholder,
|
|
465
571
|
},
|
|
466
572
|
}).createMachine({
|
|
467
573
|
id: 'coding',
|
|
@@ -479,23 +585,28 @@ export const codingMachine = setup({
|
|
|
479
585
|
states: {
|
|
480
586
|
ready: {
|
|
481
587
|
id: 'ready',
|
|
482
|
-
description:
|
|
588
|
+
description: stateDescriptions.ready,
|
|
589
|
+
meta: playbookMeta('ready'),
|
|
590
|
+
tags: ['playbook.parked'],
|
|
483
591
|
on: readyEvents,
|
|
484
592
|
},
|
|
485
593
|
|
|
486
594
|
awaitBossReply: {
|
|
487
595
|
id: 'awaitBossReply',
|
|
488
|
-
description:
|
|
596
|
+
description: stateDescriptions.awaitBossReply,
|
|
597
|
+
meta: playbookMeta('awaitBossReply'),
|
|
598
|
+
tags: ['playbook.parked'],
|
|
489
599
|
on: awaitBossReplyEvents,
|
|
490
600
|
},
|
|
491
601
|
|
|
492
602
|
planAndImplement: {
|
|
493
603
|
id: 'planAndImplement',
|
|
494
|
-
description:
|
|
495
|
-
|
|
604
|
+
description: stateDescriptions.planAndImplement,
|
|
605
|
+
meta: playbookMeta('planAndImplement'),
|
|
606
|
+
tags: ['playbook.busy'],
|
|
496
607
|
invoke: {
|
|
497
|
-
src: '
|
|
498
|
-
input: ({ context }):
|
|
608
|
+
src: 'player',
|
|
609
|
+
input: ({ context }): PlayerInput => planAndImplementInput(context),
|
|
499
610
|
onDone: withNeedsBossReplyTransition('planAndImplement', [
|
|
500
611
|
{
|
|
501
612
|
guard: guardIs('singleCommitReady'),
|
|
@@ -528,10 +639,13 @@ export const codingMachine = setup({
|
|
|
528
639
|
|
|
529
640
|
respondToReview: {
|
|
530
641
|
id: 'respondToReview',
|
|
531
|
-
description:
|
|
642
|
+
description: stateDescriptions.respondToReview,
|
|
643
|
+
meta: playbookMeta('respondToReview'),
|
|
644
|
+
tags: ['playbook.busy'],
|
|
532
645
|
invoke: {
|
|
533
|
-
src: '
|
|
534
|
-
input: ({ context }):
|
|
646
|
+
src: 'player',
|
|
647
|
+
input: ({ context }): PlayerInput => ({
|
|
648
|
+
stateId: 'respondToReview',
|
|
535
649
|
player: 'Coder',
|
|
536
650
|
sourceItem: 'CODE-2',
|
|
537
651
|
...bossReplyInputFields(context),
|
|
@@ -632,11 +746,12 @@ export const codingMachine = setup({
|
|
|
632
746
|
|
|
633
747
|
continueIr: {
|
|
634
748
|
id: 'continueIr',
|
|
635
|
-
description:
|
|
636
|
-
|
|
749
|
+
description: stateDescriptions.continueIr,
|
|
750
|
+
meta: playbookMeta('continueIr'),
|
|
751
|
+
tags: ['playbook.busy'],
|
|
637
752
|
invoke: {
|
|
638
|
-
src: '
|
|
639
|
-
input: ({ context }):
|
|
753
|
+
src: 'player',
|
|
754
|
+
input: ({ context }): PlayerInput => continueIrInput(context),
|
|
640
755
|
onDone: withNeedsBossReplyTransition('continueIr', [
|
|
641
756
|
{
|
|
642
757
|
guard: guardIs('taskReady'),
|
|
@@ -668,10 +783,12 @@ export const codingMachine = setup({
|
|
|
668
783
|
|
|
669
784
|
summarizeSpecs: {
|
|
670
785
|
id: 'summarizeSpecs',
|
|
671
|
-
description:
|
|
786
|
+
description: stateDescriptions.summarizeSpecs,
|
|
787
|
+
meta: playbookMeta('summarizeSpecs'),
|
|
788
|
+
tags: ['playbook.busy'],
|
|
672
789
|
invoke: {
|
|
673
|
-
src: '
|
|
674
|
-
input: ({ context }):
|
|
790
|
+
src: 'player',
|
|
791
|
+
input: ({ context }): PlayerInput => summarizeSpecsInput(context),
|
|
675
792
|
onDone: withNeedsBossReplyTransition('summarizeSpecs', [
|
|
676
793
|
{
|
|
677
794
|
guard: guardIs('specsReady'),
|
|
@@ -697,11 +814,13 @@ export const codingMachine = setup({
|
|
|
697
814
|
|
|
698
815
|
reviewBossCommitSpecs: {
|
|
699
816
|
id: 'reviewBossCommitSpecs',
|
|
700
|
-
description:
|
|
701
|
-
|
|
817
|
+
description: stateDescriptions.reviewBossCommitSpecs,
|
|
818
|
+
meta: playbookMeta('reviewBossCommitSpecs'),
|
|
819
|
+
tags: ['playbook.busy'],
|
|
702
820
|
invoke: {
|
|
703
|
-
src: '
|
|
704
|
-
input: ({ context }):
|
|
821
|
+
src: 'player',
|
|
822
|
+
input: ({ context }): PlayerInput => ({
|
|
823
|
+
stateId: 'reviewBossCommitSpecs',
|
|
705
824
|
player: 'Reviewer',
|
|
706
825
|
sourceItem: 'CODE-5',
|
|
707
826
|
...bossReplyInputFields(context),
|
|
@@ -730,13 +849,28 @@ export const codingMachine = setup({
|
|
|
730
849
|
},
|
|
731
850
|
}),
|
|
732
851
|
onDone: withNeedsBossReplyTransition('reviewBossCommitSpecs', [
|
|
733
|
-
{
|
|
734
|
-
|
|
735
|
-
|
|
852
|
+
{
|
|
853
|
+
guard: noFindingsAfter('continueIr'),
|
|
854
|
+
target: '#continueIr',
|
|
855
|
+
actions: rememberCaptainOutput,
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
guard: noFindingsAfter('summarizeSpecs'),
|
|
859
|
+
target: '#summarizeSpecs',
|
|
860
|
+
actions: rememberCaptainOutput,
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
guard: noFindingsAfter('done'),
|
|
864
|
+
target: '#done',
|
|
865
|
+
actions: rememberCaptainOutput,
|
|
866
|
+
},
|
|
736
867
|
{
|
|
737
868
|
guard: guardIs('hasFindings'),
|
|
738
869
|
target: '#respondToReview',
|
|
739
|
-
actions: [
|
|
870
|
+
actions: [
|
|
871
|
+
rememberCaptainOutput,
|
|
872
|
+
assign({ reviewSubject: () => 'commit' as const }),
|
|
873
|
+
],
|
|
740
874
|
},
|
|
741
875
|
]),
|
|
742
876
|
onError: captainError,
|
|
@@ -745,11 +879,13 @@ export const codingMachine = setup({
|
|
|
745
879
|
|
|
746
880
|
reviewBossCommitCode: {
|
|
747
881
|
id: 'reviewBossCommitCode',
|
|
748
|
-
description:
|
|
749
|
-
|
|
882
|
+
description: stateDescriptions.reviewBossCommitCode,
|
|
883
|
+
meta: playbookMeta('reviewBossCommitCode'),
|
|
884
|
+
tags: ['playbook.busy'],
|
|
750
885
|
invoke: {
|
|
751
|
-
src: '
|
|
752
|
-
input: ({ context }):
|
|
886
|
+
src: 'player',
|
|
887
|
+
input: ({ context }): PlayerInput => ({
|
|
888
|
+
stateId: 'reviewBossCommitCode',
|
|
753
889
|
player: 'Reviewer',
|
|
754
890
|
sourceItem: 'CODE-6',
|
|
755
891
|
...bossReplyInputFields(context),
|
|
@@ -772,13 +908,28 @@ export const codingMachine = setup({
|
|
|
772
908
|
},
|
|
773
909
|
}),
|
|
774
910
|
onDone: withNeedsBossReplyTransition('reviewBossCommitCode', [
|
|
775
|
-
{
|
|
776
|
-
|
|
777
|
-
|
|
911
|
+
{
|
|
912
|
+
guard: noFindingsAfter('continueIr'),
|
|
913
|
+
target: '#continueIr',
|
|
914
|
+
actions: rememberCaptainOutput,
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
guard: noFindingsAfter('summarizeSpecs'),
|
|
918
|
+
target: '#summarizeSpecs',
|
|
919
|
+
actions: rememberCaptainOutput,
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
guard: noFindingsAfter('done'),
|
|
923
|
+
target: '#done',
|
|
924
|
+
actions: rememberCaptainOutput,
|
|
925
|
+
},
|
|
778
926
|
{
|
|
779
927
|
guard: guardIs('hasFindings'),
|
|
780
928
|
target: '#respondToReview',
|
|
781
|
-
actions: [
|
|
929
|
+
actions: [
|
|
930
|
+
rememberCaptainOutput,
|
|
931
|
+
assign({ reviewSubject: () => 'commit' as const }),
|
|
932
|
+
],
|
|
782
933
|
},
|
|
783
934
|
]),
|
|
784
935
|
onError: captainError,
|
|
@@ -787,11 +938,13 @@ export const codingMachine = setup({
|
|
|
787
938
|
|
|
788
939
|
reviewBossCommitMixed: {
|
|
789
940
|
id: 'reviewBossCommitMixed',
|
|
790
|
-
description:
|
|
791
|
-
|
|
941
|
+
description: stateDescriptions.reviewBossCommitMixed,
|
|
942
|
+
meta: playbookMeta('reviewBossCommitMixed'),
|
|
943
|
+
tags: ['playbook.busy'],
|
|
792
944
|
invoke: {
|
|
793
|
-
src: '
|
|
794
|
-
input: ({ context }):
|
|
945
|
+
src: 'player',
|
|
946
|
+
input: ({ context }): PlayerInput => ({
|
|
947
|
+
stateId: 'reviewBossCommitMixed',
|
|
795
948
|
player: 'Reviewer',
|
|
796
949
|
sourceItem: 'CODE-7',
|
|
797
950
|
...bossReplyInputFields(context),
|
|
@@ -799,6 +952,8 @@ export const codingMachine = setup({
|
|
|
799
952
|
prompt: [
|
|
800
953
|
'Review the latest commit.',
|
|
801
954
|
'Refer to the commit message.',
|
|
955
|
+
'Flag any issues or improvements (numbered; no duplication).',
|
|
956
|
+
"Think thoroughly — don't just approve or reject.",
|
|
802
957
|
'Verify any affected spec items are:',
|
|
803
958
|
'',
|
|
804
959
|
'- Complete & coherent: sufficient for you to reimplement code.',
|
|
@@ -807,8 +962,6 @@ export const codingMachine = setup({
|
|
|
807
962
|
'- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
|
|
808
963
|
'',
|
|
809
964
|
'Flag anything missing, redundant, over-specified, or under-specified.',
|
|
810
|
-
'Flag any issues or improvements (numbered; no duplication).',
|
|
811
|
-
"Think thoroughly — don't just approve or reject.",
|
|
812
965
|
'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
|
|
813
966
|
'Verify @specs/map.md reflects the changes.',
|
|
814
967
|
"If the change is ready to commit or push, don't raise nitpicks.",
|
|
@@ -822,13 +975,28 @@ export const codingMachine = setup({
|
|
|
822
975
|
},
|
|
823
976
|
}),
|
|
824
977
|
onDone: withNeedsBossReplyTransition('reviewBossCommitMixed', [
|
|
825
|
-
{
|
|
826
|
-
|
|
827
|
-
|
|
978
|
+
{
|
|
979
|
+
guard: noFindingsAfter('continueIr'),
|
|
980
|
+
target: '#continueIr',
|
|
981
|
+
actions: rememberCaptainOutput,
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
guard: noFindingsAfter('summarizeSpecs'),
|
|
985
|
+
target: '#summarizeSpecs',
|
|
986
|
+
actions: rememberCaptainOutput,
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
guard: noFindingsAfter('done'),
|
|
990
|
+
target: '#done',
|
|
991
|
+
actions: rememberCaptainOutput,
|
|
992
|
+
},
|
|
828
993
|
{
|
|
829
994
|
guard: guardIs('hasFindings'),
|
|
830
995
|
target: '#respondToReview',
|
|
831
|
-
actions: [
|
|
996
|
+
actions: [
|
|
997
|
+
rememberCaptainOutput,
|
|
998
|
+
assign({ reviewSubject: () => 'commit' as const }),
|
|
999
|
+
],
|
|
832
1000
|
},
|
|
833
1001
|
]),
|
|
834
1002
|
onError: captainError,
|
|
@@ -837,11 +1005,13 @@ export const codingMachine = setup({
|
|
|
837
1005
|
|
|
838
1006
|
reviewIrTaskCommitSpecs: {
|
|
839
1007
|
id: 'reviewIrTaskCommitSpecs',
|
|
840
|
-
description:
|
|
841
|
-
|
|
1008
|
+
description: stateDescriptions.reviewIrTaskCommitSpecs,
|
|
1009
|
+
meta: playbookMeta('reviewIrTaskCommitSpecs'),
|
|
1010
|
+
tags: ['playbook.busy'],
|
|
842
1011
|
invoke: {
|
|
843
|
-
src: '
|
|
844
|
-
input: ({ context }):
|
|
1012
|
+
src: 'player',
|
|
1013
|
+
input: ({ context }): PlayerInput => ({
|
|
1014
|
+
stateId: 'reviewIrTaskCommitSpecs',
|
|
845
1015
|
player: 'Reviewer',
|
|
846
1016
|
sourceItem: 'CODE-8',
|
|
847
1017
|
...bossReplyInputFields(context),
|
|
@@ -871,13 +1041,28 @@ export const codingMachine = setup({
|
|
|
871
1041
|
},
|
|
872
1042
|
}),
|
|
873
1043
|
onDone: withNeedsBossReplyTransition('reviewIrTaskCommitSpecs', [
|
|
874
|
-
{
|
|
875
|
-
|
|
876
|
-
|
|
1044
|
+
{
|
|
1045
|
+
guard: noFindingsAfter('continueIr'),
|
|
1046
|
+
target: '#continueIr',
|
|
1047
|
+
actions: rememberCaptainOutput,
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
guard: noFindingsAfter('summarizeSpecs'),
|
|
1051
|
+
target: '#summarizeSpecs',
|
|
1052
|
+
actions: rememberCaptainOutput,
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
guard: noFindingsAfter('done'),
|
|
1056
|
+
target: '#done',
|
|
1057
|
+
actions: rememberCaptainOutput,
|
|
1058
|
+
},
|
|
877
1059
|
{
|
|
878
1060
|
guard: guardIs('hasFindings'),
|
|
879
1061
|
target: '#respondToReview',
|
|
880
|
-
actions: [
|
|
1062
|
+
actions: [
|
|
1063
|
+
rememberCaptainOutput,
|
|
1064
|
+
assign({ reviewSubject: () => 'commit' as const }),
|
|
1065
|
+
],
|
|
881
1066
|
},
|
|
882
1067
|
]),
|
|
883
1068
|
onError: captainError,
|
|
@@ -886,11 +1071,13 @@ export const codingMachine = setup({
|
|
|
886
1071
|
|
|
887
1072
|
reviewIrTaskCommitCode: {
|
|
888
1073
|
id: 'reviewIrTaskCommitCode',
|
|
889
|
-
description:
|
|
890
|
-
|
|
1074
|
+
description: stateDescriptions.reviewIrTaskCommitCode,
|
|
1075
|
+
meta: playbookMeta('reviewIrTaskCommitCode'),
|
|
1076
|
+
tags: ['playbook.busy'],
|
|
891
1077
|
invoke: {
|
|
892
|
-
src: '
|
|
893
|
-
input: ({ context }):
|
|
1078
|
+
src: 'player',
|
|
1079
|
+
input: ({ context }): PlayerInput => ({
|
|
1080
|
+
stateId: 'reviewIrTaskCommitCode',
|
|
894
1081
|
player: 'Reviewer',
|
|
895
1082
|
sourceItem: 'CODE-9',
|
|
896
1083
|
...bossReplyInputFields(context),
|
|
@@ -914,13 +1101,28 @@ export const codingMachine = setup({
|
|
|
914
1101
|
},
|
|
915
1102
|
}),
|
|
916
1103
|
onDone: withNeedsBossReplyTransition('reviewIrTaskCommitCode', [
|
|
917
|
-
{
|
|
918
|
-
|
|
919
|
-
|
|
1104
|
+
{
|
|
1105
|
+
guard: noFindingsAfter('continueIr'),
|
|
1106
|
+
target: '#continueIr',
|
|
1107
|
+
actions: rememberCaptainOutput,
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
guard: noFindingsAfter('summarizeSpecs'),
|
|
1111
|
+
target: '#summarizeSpecs',
|
|
1112
|
+
actions: rememberCaptainOutput,
|
|
1113
|
+
},
|
|
1114
|
+
{
|
|
1115
|
+
guard: noFindingsAfter('done'),
|
|
1116
|
+
target: '#done',
|
|
1117
|
+
actions: rememberCaptainOutput,
|
|
1118
|
+
},
|
|
920
1119
|
{
|
|
921
1120
|
guard: guardIs('hasFindings'),
|
|
922
1121
|
target: '#respondToReview',
|
|
923
|
-
actions: [
|
|
1122
|
+
actions: [
|
|
1123
|
+
rememberCaptainOutput,
|
|
1124
|
+
assign({ reviewSubject: () => 'commit' as const }),
|
|
1125
|
+
],
|
|
924
1126
|
},
|
|
925
1127
|
]),
|
|
926
1128
|
onError: captainError,
|
|
@@ -929,11 +1131,13 @@ export const codingMachine = setup({
|
|
|
929
1131
|
|
|
930
1132
|
reviewIrTaskCommitMixed: {
|
|
931
1133
|
id: 'reviewIrTaskCommitMixed',
|
|
932
|
-
description:
|
|
933
|
-
|
|
1134
|
+
description: stateDescriptions.reviewIrTaskCommitMixed,
|
|
1135
|
+
meta: playbookMeta('reviewIrTaskCommitMixed'),
|
|
1136
|
+
tags: ['playbook.busy'],
|
|
934
1137
|
invoke: {
|
|
935
|
-
src: '
|
|
936
|
-
input: ({ context }):
|
|
1138
|
+
src: 'player',
|
|
1139
|
+
input: ({ context }): PlayerInput => ({
|
|
1140
|
+
stateId: 'reviewIrTaskCommitMixed',
|
|
937
1141
|
player: 'Reviewer',
|
|
938
1142
|
sourceItem: 'CODE-10',
|
|
939
1143
|
...bossReplyInputFields(context),
|
|
@@ -942,6 +1146,8 @@ export const codingMachine = setup({
|
|
|
942
1146
|
prompt: [
|
|
943
1147
|
'Review the latest commit.',
|
|
944
1148
|
'Refer to the commit message.',
|
|
1149
|
+
'Flag any issues or improvements (numbered; no duplication).',
|
|
1150
|
+
"Think thoroughly — don't just approve or reject.",
|
|
945
1151
|
'Verify any affected spec items are:',
|
|
946
1152
|
'',
|
|
947
1153
|
'- Complete & coherent: sufficient for you to reimplement code.',
|
|
@@ -950,8 +1156,6 @@ export const codingMachine = setup({
|
|
|
950
1156
|
'- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
|
|
951
1157
|
'',
|
|
952
1158
|
'Flag anything missing, redundant, over-specified, or under-specified.',
|
|
953
|
-
'Flag any issues or improvements (numbered; no duplication).',
|
|
954
|
-
"Think thoroughly — don't just approve or reject.",
|
|
955
1159
|
'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
|
|
956
1160
|
'Verify @specs/map.md reflects the changes.',
|
|
957
1161
|
"If the change is ready to commit or push, don't raise nitpicks.",
|
|
@@ -965,13 +1169,28 @@ export const codingMachine = setup({
|
|
|
965
1169
|
},
|
|
966
1170
|
}),
|
|
967
1171
|
onDone: withNeedsBossReplyTransition('reviewIrTaskCommitMixed', [
|
|
968
|
-
{
|
|
969
|
-
|
|
970
|
-
|
|
1172
|
+
{
|
|
1173
|
+
guard: noFindingsAfter('continueIr'),
|
|
1174
|
+
target: '#continueIr',
|
|
1175
|
+
actions: rememberCaptainOutput,
|
|
1176
|
+
},
|
|
1177
|
+
{
|
|
1178
|
+
guard: noFindingsAfter('summarizeSpecs'),
|
|
1179
|
+
target: '#summarizeSpecs',
|
|
1180
|
+
actions: rememberCaptainOutput,
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
guard: noFindingsAfter('done'),
|
|
1184
|
+
target: '#done',
|
|
1185
|
+
actions: rememberCaptainOutput,
|
|
1186
|
+
},
|
|
971
1187
|
{
|
|
972
1188
|
guard: guardIs('hasFindings'),
|
|
973
1189
|
target: '#respondToReview',
|
|
974
|
-
actions: [
|
|
1190
|
+
actions: [
|
|
1191
|
+
rememberCaptainOutput,
|
|
1192
|
+
assign({ reviewSubject: () => 'commit' as const }),
|
|
1193
|
+
],
|
|
975
1194
|
},
|
|
976
1195
|
]),
|
|
977
1196
|
onError: captainError,
|
|
@@ -980,11 +1199,13 @@ export const codingMachine = setup({
|
|
|
980
1199
|
|
|
981
1200
|
reviewChangesSpecs: {
|
|
982
1201
|
id: 'reviewChangesSpecs',
|
|
983
|
-
description:
|
|
984
|
-
|
|
1202
|
+
description: stateDescriptions.reviewChangesSpecs,
|
|
1203
|
+
meta: playbookMeta('reviewChangesSpecs'),
|
|
1204
|
+
tags: ['playbook.busy'],
|
|
985
1205
|
invoke: {
|
|
986
|
-
src: '
|
|
987
|
-
input: ({ context }):
|
|
1206
|
+
src: 'player',
|
|
1207
|
+
input: ({ context }): PlayerInput => ({
|
|
1208
|
+
stateId: 'reviewChangesSpecs',
|
|
988
1209
|
player: 'Reviewer',
|
|
989
1210
|
sourceItem: 'CODE-11',
|
|
990
1211
|
...bossReplyInputFields(context),
|
|
@@ -1005,7 +1226,8 @@ export const codingMachine = setup({
|
|
|
1005
1226
|
'Do not edit files or commit; report findings only.',
|
|
1006
1227
|
].join('\n'),
|
|
1007
1228
|
result: {
|
|
1008
|
-
noFindings:
|
|
1229
|
+
noFindings:
|
|
1230
|
+
'The uncommitted spec-only changes are ready to commit.',
|
|
1009
1231
|
hasFindings:
|
|
1010
1232
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
1011
1233
|
needsBossReply: needsBossReplyDescription,
|
|
@@ -1020,7 +1242,10 @@ export const codingMachine = setup({
|
|
|
1020
1242
|
{
|
|
1021
1243
|
guard: guardIs('hasFindings'),
|
|
1022
1244
|
target: '#respondToReview',
|
|
1023
|
-
actions: [
|
|
1245
|
+
actions: [
|
|
1246
|
+
rememberCaptainOutput,
|
|
1247
|
+
assign({ reviewSubject: () => 'changes' as const }),
|
|
1248
|
+
],
|
|
1024
1249
|
},
|
|
1025
1250
|
]),
|
|
1026
1251
|
onError: captainError,
|
|
@@ -1029,11 +1254,13 @@ export const codingMachine = setup({
|
|
|
1029
1254
|
|
|
1030
1255
|
reviewChangesCode: {
|
|
1031
1256
|
id: 'reviewChangesCode',
|
|
1032
|
-
description:
|
|
1033
|
-
|
|
1257
|
+
description: stateDescriptions.reviewChangesCode,
|
|
1258
|
+
meta: playbookMeta('reviewChangesCode'),
|
|
1259
|
+
tags: ['playbook.busy'],
|
|
1034
1260
|
invoke: {
|
|
1035
|
-
src: '
|
|
1036
|
-
input: ({ context }):
|
|
1261
|
+
src: 'player',
|
|
1262
|
+
input: ({ context }): PlayerInput => ({
|
|
1263
|
+
stateId: 'reviewChangesCode',
|
|
1037
1264
|
player: 'Reviewer',
|
|
1038
1265
|
sourceItem: 'CODE-12',
|
|
1039
1266
|
...bossReplyInputFields(context),
|
|
@@ -1048,7 +1275,8 @@ export const codingMachine = setup({
|
|
|
1048
1275
|
'Do not edit files or commit; report findings only.',
|
|
1049
1276
|
].join('\n'),
|
|
1050
1277
|
result: {
|
|
1051
|
-
noFindings:
|
|
1278
|
+
noFindings:
|
|
1279
|
+
'The uncommitted code-only changes are ready to commit.',
|
|
1052
1280
|
hasFindings:
|
|
1053
1281
|
'The review produced findings for Coder. Output shall include `reviews: <numbered list of findings, no duplication>`.',
|
|
1054
1282
|
needsBossReply: needsBossReplyDescription,
|
|
@@ -1063,7 +1291,10 @@ export const codingMachine = setup({
|
|
|
1063
1291
|
{
|
|
1064
1292
|
guard: guardIs('hasFindings'),
|
|
1065
1293
|
target: '#respondToReview',
|
|
1066
|
-
actions: [
|
|
1294
|
+
actions: [
|
|
1295
|
+
rememberCaptainOutput,
|
|
1296
|
+
assign({ reviewSubject: () => 'changes' as const }),
|
|
1297
|
+
],
|
|
1067
1298
|
},
|
|
1068
1299
|
]),
|
|
1069
1300
|
onError: captainError,
|
|
@@ -1072,17 +1303,21 @@ export const codingMachine = setup({
|
|
|
1072
1303
|
|
|
1073
1304
|
reviewChangesMixed: {
|
|
1074
1305
|
id: 'reviewChangesMixed',
|
|
1075
|
-
description:
|
|
1076
|
-
|
|
1306
|
+
description: stateDescriptions.reviewChangesMixed,
|
|
1307
|
+
meta: playbookMeta('reviewChangesMixed'),
|
|
1308
|
+
tags: ['playbook.busy'],
|
|
1077
1309
|
invoke: {
|
|
1078
|
-
src: '
|
|
1079
|
-
input: ({ context }):
|
|
1310
|
+
src: 'player',
|
|
1311
|
+
input: ({ context }): PlayerInput => ({
|
|
1312
|
+
stateId: 'reviewChangesMixed',
|
|
1080
1313
|
player: 'Reviewer',
|
|
1081
1314
|
sourceItem: 'CODE-13',
|
|
1082
1315
|
...bossReplyInputFields(context),
|
|
1083
1316
|
prompt: [
|
|
1084
1317
|
'Review the unstaged and untracked changes in the context of the staged changes.',
|
|
1085
1318
|
'Understand the intent.',
|
|
1319
|
+
'Flag any issues or improvements (numbered; no duplication).',
|
|
1320
|
+
"Think thoroughly — don't just approve or reject.",
|
|
1086
1321
|
'Verify any affected spec items are:',
|
|
1087
1322
|
'',
|
|
1088
1323
|
'- Complete & coherent: sufficient for you to reimplement code.',
|
|
@@ -1091,8 +1326,6 @@ export const codingMachine = setup({
|
|
|
1091
1326
|
'- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
|
|
1092
1327
|
'',
|
|
1093
1328
|
'Flag anything missing, redundant, over-specified, or under-specified.',
|
|
1094
|
-
'Flag any issues or improvements (numbered; no duplication).',
|
|
1095
|
-
"Think thoroughly — don't just approve or reject.",
|
|
1096
1329
|
'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
|
|
1097
1330
|
'Verify @specs/map.md reflects the changes.',
|
|
1098
1331
|
"If the change is ready to commit or push, don't raise nitpicks.",
|
|
@@ -1114,7 +1347,10 @@ export const codingMachine = setup({
|
|
|
1114
1347
|
{
|
|
1115
1348
|
guard: guardIs('hasFindings'),
|
|
1116
1349
|
target: '#respondToReview',
|
|
1117
|
-
actions: [
|
|
1350
|
+
actions: [
|
|
1351
|
+
rememberCaptainOutput,
|
|
1352
|
+
assign({ reviewSubject: () => 'changes' as const }),
|
|
1353
|
+
],
|
|
1118
1354
|
},
|
|
1119
1355
|
]),
|
|
1120
1356
|
onError: captainError,
|
|
@@ -1123,11 +1359,13 @@ export const codingMachine = setup({
|
|
|
1123
1359
|
|
|
1124
1360
|
reviewChangesAndChallengesSpecs: {
|
|
1125
1361
|
id: 'reviewChangesAndChallengesSpecs',
|
|
1126
|
-
description:
|
|
1127
|
-
|
|
1362
|
+
description: stateDescriptions.reviewChangesAndChallengesSpecs,
|
|
1363
|
+
meta: playbookMeta('reviewChangesAndChallengesSpecs'),
|
|
1364
|
+
tags: ['playbook.busy'],
|
|
1128
1365
|
invoke: {
|
|
1129
|
-
src: '
|
|
1130
|
-
input: ({ context }):
|
|
1366
|
+
src: 'player',
|
|
1367
|
+
input: ({ context }): PlayerInput => ({
|
|
1368
|
+
stateId: 'reviewChangesAndChallengesSpecs',
|
|
1131
1369
|
player: 'Reviewer',
|
|
1132
1370
|
sourceItem: 'CODE-15',
|
|
1133
1371
|
...bossReplyInputFields(context),
|
|
@@ -1158,29 +1396,37 @@ export const codingMachine = setup({
|
|
|
1158
1396
|
needsBossReply: needsBossReplyDescription,
|
|
1159
1397
|
},
|
|
1160
1398
|
}),
|
|
1161
|
-
onDone: withNeedsBossReplyTransition(
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1399
|
+
onDone: withNeedsBossReplyTransition(
|
|
1400
|
+
'reviewChangesAndChallengesSpecs',
|
|
1401
|
+
[
|
|
1402
|
+
{
|
|
1403
|
+
guard: guardIs('approved'),
|
|
1404
|
+
target: '#commitJoint',
|
|
1405
|
+
actions: rememberCaptainOutput,
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
guard: guardIs('needsRevision'),
|
|
1409
|
+
target: '#respondToReview',
|
|
1410
|
+
actions: [
|
|
1411
|
+
rememberCaptainOutput,
|
|
1412
|
+
assign({ reviewSubject: () => 'changes' as const }),
|
|
1413
|
+
],
|
|
1414
|
+
},
|
|
1415
|
+
],
|
|
1416
|
+
),
|
|
1173
1417
|
onError: captainError,
|
|
1174
1418
|
},
|
|
1175
1419
|
},
|
|
1176
1420
|
|
|
1177
1421
|
reviewChangesAndChallengesCode: {
|
|
1178
1422
|
id: 'reviewChangesAndChallengesCode',
|
|
1179
|
-
description:
|
|
1180
|
-
|
|
1423
|
+
description: stateDescriptions.reviewChangesAndChallengesCode,
|
|
1424
|
+
meta: playbookMeta('reviewChangesAndChallengesCode'),
|
|
1425
|
+
tags: ['playbook.busy'],
|
|
1181
1426
|
invoke: {
|
|
1182
|
-
src: '
|
|
1183
|
-
input: ({ context }):
|
|
1427
|
+
src: 'player',
|
|
1428
|
+
input: ({ context }): PlayerInput => ({
|
|
1429
|
+
stateId: 'reviewChangesAndChallengesCode',
|
|
1184
1430
|
player: 'Reviewer',
|
|
1185
1431
|
sourceItem: 'CODE-16',
|
|
1186
1432
|
...bossReplyInputFields(context),
|
|
@@ -1214,7 +1460,10 @@ export const codingMachine = setup({
|
|
|
1214
1460
|
{
|
|
1215
1461
|
guard: guardIs('needsRevision'),
|
|
1216
1462
|
target: '#respondToReview',
|
|
1217
|
-
actions: [
|
|
1463
|
+
actions: [
|
|
1464
|
+
rememberCaptainOutput,
|
|
1465
|
+
assign({ reviewSubject: () => 'changes' as const }),
|
|
1466
|
+
],
|
|
1218
1467
|
},
|
|
1219
1468
|
]),
|
|
1220
1469
|
onError: captainError,
|
|
@@ -1223,11 +1472,13 @@ export const codingMachine = setup({
|
|
|
1223
1472
|
|
|
1224
1473
|
reviewChangesAndChallengesMixed: {
|
|
1225
1474
|
id: 'reviewChangesAndChallengesMixed',
|
|
1226
|
-
description:
|
|
1227
|
-
|
|
1475
|
+
description: stateDescriptions.reviewChangesAndChallengesMixed,
|
|
1476
|
+
meta: playbookMeta('reviewChangesAndChallengesMixed'),
|
|
1477
|
+
tags: ['playbook.busy'],
|
|
1228
1478
|
invoke: {
|
|
1229
|
-
src: '
|
|
1230
|
-
input: ({ context }):
|
|
1479
|
+
src: 'player',
|
|
1480
|
+
input: ({ context }): PlayerInput => ({
|
|
1481
|
+
stateId: 'reviewChangesAndChallengesMixed',
|
|
1231
1482
|
player: 'Reviewer',
|
|
1232
1483
|
sourceItem: 'CODE-17',
|
|
1233
1484
|
...bossReplyInputFields(context),
|
|
@@ -1236,6 +1487,8 @@ export const codingMachine = setup({
|
|
|
1236
1487
|
prompt: [
|
|
1237
1488
|
'Review the unstaged and untracked changes in the context of the staged changes.',
|
|
1238
1489
|
'Understand the intent.',
|
|
1490
|
+
'Flag any issues or improvements (numbered; no duplication).',
|
|
1491
|
+
"Think thoroughly — don't just approve or reject.",
|
|
1239
1492
|
'Verify any affected spec items are:',
|
|
1240
1493
|
'',
|
|
1241
1494
|
'- Complete & coherent: sufficient for you to reimplement code.',
|
|
@@ -1244,8 +1497,6 @@ export const codingMachine = setup({
|
|
|
1244
1497
|
'- Well organized: spec packages are finely scoped, with high cohesion and low coupling.',
|
|
1245
1498
|
'',
|
|
1246
1499
|
'Flag anything missing, redundant, over-specified, or under-specified.',
|
|
1247
|
-
'Flag any issues or improvements (numbered; no duplication).',
|
|
1248
|
-
"Think thoroughly — don't just approve or reject.",
|
|
1249
1500
|
'For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.',
|
|
1250
1501
|
'Verify @specs/map.md reflects the changes.',
|
|
1251
1502
|
"If the change is ready to commit or push, don't raise nitpicks.",
|
|
@@ -1260,28 +1511,37 @@ export const codingMachine = setup({
|
|
|
1260
1511
|
needsBossReply: needsBossReplyDescription,
|
|
1261
1512
|
},
|
|
1262
1513
|
}),
|
|
1263
|
-
onDone: withNeedsBossReplyTransition(
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1514
|
+
onDone: withNeedsBossReplyTransition(
|
|
1515
|
+
'reviewChangesAndChallengesMixed',
|
|
1516
|
+
[
|
|
1517
|
+
{
|
|
1518
|
+
guard: guardIs('approved'),
|
|
1519
|
+
target: '#commitJoint',
|
|
1520
|
+
actions: rememberCaptainOutput,
|
|
1521
|
+
},
|
|
1522
|
+
{
|
|
1523
|
+
guard: guardIs('needsRevision'),
|
|
1524
|
+
target: '#respondToReview',
|
|
1525
|
+
actions: [
|
|
1526
|
+
rememberCaptainOutput,
|
|
1527
|
+
assign({ reviewSubject: () => 'changes' as const }),
|
|
1528
|
+
],
|
|
1529
|
+
},
|
|
1530
|
+
],
|
|
1531
|
+
),
|
|
1275
1532
|
onError: captainError,
|
|
1276
1533
|
},
|
|
1277
1534
|
},
|
|
1278
1535
|
|
|
1279
1536
|
adjudicateChallenges: {
|
|
1280
1537
|
id: 'adjudicateChallenges',
|
|
1281
|
-
description:
|
|
1538
|
+
description: stateDescriptions.adjudicateChallenges,
|
|
1539
|
+
meta: playbookMeta('adjudicateChallenges'),
|
|
1540
|
+
tags: ['playbook.busy'],
|
|
1282
1541
|
invoke: {
|
|
1283
|
-
src: '
|
|
1284
|
-
input: ({ context }):
|
|
1542
|
+
src: 'player',
|
|
1543
|
+
input: ({ context }): PlayerInput => ({
|
|
1544
|
+
stateId: 'adjudicateChallenges',
|
|
1285
1545
|
player: 'Reviewer',
|
|
1286
1546
|
sourceItem: 'CODE-14',
|
|
1287
1547
|
...bossReplyInputFields(context),
|
|
@@ -1348,11 +1608,13 @@ export const codingMachine = setup({
|
|
|
1348
1608
|
|
|
1349
1609
|
commitCoderInitial: {
|
|
1350
1610
|
id: 'commitCoderInitial',
|
|
1351
|
-
description:
|
|
1352
|
-
|
|
1611
|
+
description: stateDescriptions.commitCoderInitial,
|
|
1612
|
+
meta: playbookMeta('commitCoderInitial'),
|
|
1613
|
+
tags: ['playbook.busy'],
|
|
1353
1614
|
invoke: {
|
|
1354
|
-
src: '
|
|
1355
|
-
input: ({ context }):
|
|
1615
|
+
src: 'player',
|
|
1616
|
+
input: ({ context }): PlayerInput => ({
|
|
1617
|
+
stateId: 'commitCoderInitial',
|
|
1356
1618
|
player: 'Committer',
|
|
1357
1619
|
sourceItem: 'CODE-18',
|
|
1358
1620
|
...bossReplyInputFields(context),
|
|
@@ -1360,14 +1622,17 @@ export const codingMachine = setup({
|
|
|
1360
1622
|
committerPlayer: context.committerPlayer,
|
|
1361
1623
|
prompt: [
|
|
1362
1624
|
'Make a commit of the changes that belong in the repo, following @specs/dev/git.md (reread if necessary).',
|
|
1363
|
-
'Write concisely.',
|
|
1625
|
+
'Write the commit message concisely.',
|
|
1364
1626
|
'Coder is <coder-llm>.',
|
|
1365
1627
|
'Format the `Co-authored-by` `<model>` token as the conventional human form of the substituted id (e.g., `claude-opus-4-7` → `Claude-Opus-4.7`, `gpt-5.5` → `GPT-5.5`).',
|
|
1366
1628
|
].join('\n'),
|
|
1367
1629
|
result: {
|
|
1368
|
-
committedSpecs:
|
|
1369
|
-
|
|
1370
|
-
|
|
1630
|
+
committedSpecs:
|
|
1631
|
+
'Committed changes that touch only @specs/{user,dev,test}/.',
|
|
1632
|
+
committedCode:
|
|
1633
|
+
'Committed changes that touch only files outside @specs/{user,dev,test}/.',
|
|
1634
|
+
committedMixed:
|
|
1635
|
+
'Committed changes that span both @specs/{user,dev,test}/ and other files.',
|
|
1371
1636
|
noRelevantChanges: 'There are no relevant changes to commit.',
|
|
1372
1637
|
needsBossInput: 'Committing requires additional Boss input.',
|
|
1373
1638
|
needsBossReply: needsBossReplyDescription,
|
|
@@ -1404,8 +1669,16 @@ export const codingMachine = setup({
|
|
|
1404
1669
|
target: '#reviewIrTaskCommitMixed',
|
|
1405
1670
|
actions: rememberCaptainOutput,
|
|
1406
1671
|
},
|
|
1407
|
-
{
|
|
1408
|
-
|
|
1672
|
+
{
|
|
1673
|
+
guard: guardIs('noRelevantChanges'),
|
|
1674
|
+
target: '#ready',
|
|
1675
|
+
actions: rememberCaptainOutput,
|
|
1676
|
+
},
|
|
1677
|
+
{
|
|
1678
|
+
guard: guardIs('needsBossInput'),
|
|
1679
|
+
target: '#ready',
|
|
1680
|
+
actions: rememberCaptainOutput,
|
|
1681
|
+
},
|
|
1409
1682
|
]),
|
|
1410
1683
|
onError: captainError,
|
|
1411
1684
|
},
|
|
@@ -1413,11 +1686,13 @@ export const codingMachine = setup({
|
|
|
1413
1686
|
|
|
1414
1687
|
commitJoint: {
|
|
1415
1688
|
id: 'commitJoint',
|
|
1416
|
-
description:
|
|
1417
|
-
|
|
1689
|
+
description: stateDescriptions.commitJoint,
|
|
1690
|
+
meta: playbookMeta('commitJoint'),
|
|
1691
|
+
tags: ['playbook.busy'],
|
|
1418
1692
|
invoke: {
|
|
1419
|
-
src: '
|
|
1420
|
-
input: ({ context }):
|
|
1693
|
+
src: 'player',
|
|
1694
|
+
input: ({ context }): PlayerInput => ({
|
|
1695
|
+
stateId: 'commitJoint',
|
|
1421
1696
|
player: 'Committer',
|
|
1422
1697
|
sourceItem: 'CODE-19',
|
|
1423
1698
|
...bossReplyInputFields(context),
|
|
@@ -1426,7 +1701,7 @@ export const codingMachine = setup({
|
|
|
1426
1701
|
committerPlayer: context.committerPlayer,
|
|
1427
1702
|
prompt: [
|
|
1428
1703
|
'Make a commit of the changes that belong in the repo, following @specs/dev/git.md (reread if necessary).',
|
|
1429
|
-
'Write concisely.',
|
|
1704
|
+
'Write the commit message concisely.',
|
|
1430
1705
|
'Coder is <coder-llm>; Reviewer is <reviewer-llm>.',
|
|
1431
1706
|
'Format the `Co-authored-by` `<model>` token as the conventional human form of the substituted id (e.g., `claude-opus-4-7` → `Claude-Opus-4.7`, `gpt-5.5` → `GPT-5.5`).',
|
|
1432
1707
|
].join('\n'),
|
|
@@ -1440,24 +1715,35 @@ export const codingMachine = setup({
|
|
|
1440
1715
|
onDone: withNeedsBossReplyTransition('commitJoint', [
|
|
1441
1716
|
{
|
|
1442
1717
|
guard: ({ context, event }) =>
|
|
1443
|
-
outputOf(event)?.guard === 'committed' &&
|
|
1718
|
+
outputOf(event)?.guard === 'committed' &&
|
|
1719
|
+
context.afterReview === 'continueIr',
|
|
1444
1720
|
target: '#continueIr',
|
|
1445
1721
|
actions: rememberCaptainOutput,
|
|
1446
1722
|
},
|
|
1447
1723
|
{
|
|
1448
1724
|
guard: ({ context, event }) =>
|
|
1449
|
-
outputOf(event)?.guard === 'committed' &&
|
|
1725
|
+
outputOf(event)?.guard === 'committed' &&
|
|
1726
|
+
context.afterReview === 'summarizeSpecs',
|
|
1450
1727
|
target: '#summarizeSpecs',
|
|
1451
1728
|
actions: rememberCaptainOutput,
|
|
1452
1729
|
},
|
|
1453
1730
|
{
|
|
1454
1731
|
guard: ({ context, event }) =>
|
|
1455
|
-
outputOf(event)?.guard === 'committed' &&
|
|
1732
|
+
outputOf(event)?.guard === 'committed' &&
|
|
1733
|
+
context.afterReview === 'done',
|
|
1734
|
+
target: '#done',
|
|
1735
|
+
actions: rememberCaptainOutput,
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
guard: guardIs('noRelevantChanges'),
|
|
1456
1739
|
target: '#done',
|
|
1457
1740
|
actions: rememberCaptainOutput,
|
|
1458
1741
|
},
|
|
1459
|
-
{
|
|
1460
|
-
|
|
1742
|
+
{
|
|
1743
|
+
guard: guardIs('needsBossInput'),
|
|
1744
|
+
target: '#ready',
|
|
1745
|
+
actions: rememberCaptainOutput,
|
|
1746
|
+
},
|
|
1461
1747
|
]),
|
|
1462
1748
|
onError: captainError,
|
|
1463
1749
|
},
|
|
@@ -1465,14 +1751,16 @@ export const codingMachine = setup({
|
|
|
1465
1751
|
|
|
1466
1752
|
failed: {
|
|
1467
1753
|
id: 'failed',
|
|
1468
|
-
description:
|
|
1469
|
-
|
|
1754
|
+
description: stateDescriptions.failed,
|
|
1755
|
+
meta: playbookMeta('failed'),
|
|
1756
|
+
tags: ['playbook.parked'],
|
|
1470
1757
|
on: readyEvents,
|
|
1471
1758
|
},
|
|
1472
1759
|
|
|
1473
1760
|
done: {
|
|
1474
1761
|
id: 'done',
|
|
1475
|
-
description:
|
|
1762
|
+
description: stateDescriptions.done,
|
|
1763
|
+
meta: playbookMeta('done'),
|
|
1476
1764
|
type: 'final',
|
|
1477
1765
|
},
|
|
1478
1766
|
},
|