@sublang/playbook 7.0.0 → 8.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 +17 -4
- package/docs/cli.md +74 -29
- package/docs/configuration.md +209 -112
- package/docs/embedding.md +71 -25
- package/package.json +4 -3
- package/reference/sdlc/captain.playbook/captain.playbook.js +3 -3
- package/reference/sdlc/captain.playbook/captain.playbook.ts +3 -3
- package/reference/sdlc/code.md +1 -1
- package/reference/sdlc/code.playbook/bin/interactive-session.js +816 -0
- package/reference/sdlc/code.playbook/bin/launch-config.js +1078 -116
- package/reference/sdlc/code.playbook/bin/playbook.js +489 -34
- package/reference/sdlc/code.playbook/bin/run.js +283 -298
- package/reference/sdlc/code.playbook/bin/session-store.js +818 -26
- package/reference/sdlc/code.playbook/code.fsm.d.ts +5 -5
- package/reference/sdlc/code.playbook/code.fsm.introspect.js +2 -2
- package/reference/sdlc/code.playbook/code.fsm.introspect.ts +2 -2
- package/reference/sdlc/code.playbook/code.fsm.js +7 -11
- package/reference/sdlc/code.playbook/code.fsm.ts +9 -17
- package/reference/sdlc/code.playbook/code.gears.md +1 -1
- package/reference/sdlc/code.playbook/code.playbook.d.ts +2 -1
- package/reference/sdlc/code.playbook/code.playbook.js +12 -13
- package/reference/sdlc/code.playbook/code.playbook.ts +22 -15
- package/reference/sdlc/code.playbook/code.registry.d.ts +5 -13
- package/reference/sdlc/code.playbook/code.registry.js +3 -10
- package/reference/sdlc/code.playbook/code.registry.ts +7 -32
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +39 -14
- package/reference/sdlc/code.playbook/playbook-captain.js +970 -289
- package/reference/sdlc/code.playbook/playbook-captain.ts +1403 -396
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +41 -49
- package/reference/sdlc/decide.md +4 -4
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +9 -9
- package/reference/sdlc/decide.playbook/decide.fsm.js +21 -14
- package/reference/sdlc/decide.playbook/decide.fsm.ts +27 -23
- package/reference/sdlc/decide.playbook/decide.gears.md +3 -5
- package/reference/sdlc/decide.playbook/decide.playbook.d.ts +9 -13
- package/reference/sdlc/decide.playbook/decide.playbook.js +171 -134
- package/reference/sdlc/decide.playbook/decide.playbook.ts +238 -162
- package/reference/sdlc/decide.playbook/decide.registry.d.ts +5 -13
- package/reference/sdlc/decide.playbook/decide.registry.js +3 -9
- package/reference/sdlc/decide.playbook/decide.registry.ts +7 -31
- package/reference/sdlc/review.md +4 -5
- package/reference/sdlc/review.playbook/review.fsm.d.ts +9 -11
- package/reference/sdlc/review.playbook/review.fsm.js +30 -24
- package/reference/sdlc/review.playbook/review.fsm.ts +39 -35
- package/reference/sdlc/review.playbook/review.gears.md +6 -5
- package/reference/sdlc/review.playbook/review.playbook.d.ts +2 -1
- package/reference/sdlc/review.playbook/review.playbook.js +16 -21
- package/reference/sdlc/review.playbook/review.playbook.ts +26 -26
- package/reference/sdlc/review.playbook/review.registry.d.ts +5 -13
- package/reference/sdlc/review.playbook/review.registry.js +3 -16
- package/reference/sdlc/review.playbook/review.registry.ts +7 -38
- package/slc/gears2fsm.md +27 -23
- package/slc/link.md +113 -93
- package/slc/text2gears.md +19 -18
- package/src/runtime.d.ts +20 -16
- package/src/runtime.ts +19 -23
- package/src/xstate-playbook-runtime.d.ts +21 -17
- package/src/xstate-playbook-runtime.js +241 -149
- package/src/xstate-playbook-runtime.ts +331 -178
- package/src/xstate-runtime.js +63 -24
- package/src/xstate-runtime.ts +96 -28
|
@@ -8,18 +8,20 @@ export type PendingBossQuestion = {
|
|
|
8
8
|
readonly questionId: 'runFirstPhase' | 'runIrTask';
|
|
9
9
|
readonly resumeStateId: 'runFirstPhase' | 'runIrTask';
|
|
10
10
|
readonly sourceItem: 'CODE-1' | 'CODE-3';
|
|
11
|
-
readonly
|
|
11
|
+
readonly asker: {
|
|
12
|
+
readonly kind: 'role';
|
|
13
|
+
readonly roleId: 'coder';
|
|
14
|
+
};
|
|
12
15
|
readonly question: string;
|
|
13
16
|
};
|
|
14
17
|
export type PlayerInput = {
|
|
15
18
|
readonly stateId: 'runFirstPhase' | 'runIrTask';
|
|
16
|
-
readonly
|
|
19
|
+
readonly role: 'coder';
|
|
17
20
|
readonly sourceItem: 'CODE-1' | 'CODE-3';
|
|
18
21
|
readonly prompt: string;
|
|
19
22
|
readonly result: Readonly<Record<string, string>>;
|
|
20
23
|
readonly callerInput: string;
|
|
21
24
|
readonly runResults: string;
|
|
22
|
-
readonly coderPlayer: string;
|
|
23
25
|
readonly irNumber?: string;
|
|
24
26
|
readonly irTask?: string;
|
|
25
27
|
readonly pendingBossQuestion?: PendingBossQuestion;
|
|
@@ -77,11 +79,9 @@ export type CodePlaybookOutput = {
|
|
|
77
79
|
readonly error: CompactError;
|
|
78
80
|
};
|
|
79
81
|
export type CodingInput = {
|
|
80
|
-
readonly coderPlayer?: string;
|
|
81
82
|
readonly runResults?: string;
|
|
82
83
|
};
|
|
83
84
|
export type CodingContext = {
|
|
84
|
-
readonly coderPlayer: string;
|
|
85
85
|
readonly runResults: string;
|
|
86
86
|
readonly callerInput?: string;
|
|
87
87
|
readonly coderOutput?: string;
|
|
@@ -27,7 +27,7 @@ export function enumeratePlayerStates(machine) {
|
|
|
27
27
|
if (invoke?.src !== 'player' || invoke.input === undefined)
|
|
28
28
|
return [];
|
|
29
29
|
const getInput = (context) => invoke.input?.({ context });
|
|
30
|
-
const input = getInput({
|
|
30
|
+
const input = getInput({ runResults: '' });
|
|
31
31
|
return [
|
|
32
32
|
{
|
|
33
33
|
stateId,
|
|
@@ -47,7 +47,7 @@ export function enumerateNestedPlaybookStates(machine) {
|
|
|
47
47
|
if (invoke?.src !== 'playbook' || invoke.input === undefined)
|
|
48
48
|
return [];
|
|
49
49
|
const getInput = (context) => invoke.input?.({ context });
|
|
50
|
-
const input = getInput({
|
|
50
|
+
const input = getInput({ runResults: '' });
|
|
51
51
|
return [
|
|
52
52
|
{
|
|
53
53
|
stateId,
|
|
@@ -92,7 +92,7 @@ export function enumeratePlayerStates(
|
|
|
92
92
|
if (invoke?.src !== 'player' || invoke.input === undefined) return [];
|
|
93
93
|
const getInput = (context: CodingContext): PlayerInput =>
|
|
94
94
|
invoke.input?.({ context }) as PlayerInput;
|
|
95
|
-
const input = getInput({
|
|
95
|
+
const input = getInput({ runResults: '' });
|
|
96
96
|
return [
|
|
97
97
|
{
|
|
98
98
|
stateId,
|
|
@@ -116,7 +116,7 @@ export function enumerateNestedPlaybookStates(
|
|
|
116
116
|
if (invoke?.src !== 'playbook' || invoke.input === undefined) return [];
|
|
117
117
|
const getInput = (context: CodingContext): PlaybookInput =>
|
|
118
118
|
invoke.input?.({ context }) as PlaybookInput;
|
|
119
|
-
const input = getInput({
|
|
119
|
+
const input = getInput({ runResults: '' });
|
|
120
120
|
return [
|
|
121
121
|
{
|
|
122
122
|
stateId,
|
|
@@ -55,12 +55,12 @@ const STATE_DESCRIPTIONS = {
|
|
|
55
55
|
failed: 'The coding workflow failed and is waiting for a new coding intent.',
|
|
56
56
|
done: 'The coding workflow completed after REVIEW found no unsettled findings.',
|
|
57
57
|
};
|
|
58
|
-
function playbookMeta(stateId,
|
|
58
|
+
function playbookMeta(stateId, role) {
|
|
59
59
|
return {
|
|
60
60
|
playbook: {
|
|
61
61
|
stateId,
|
|
62
62
|
description: STATE_DESCRIPTIONS[stateId],
|
|
63
|
-
...(
|
|
63
|
+
...(role === undefined ? {} : { role }),
|
|
64
64
|
},
|
|
65
65
|
};
|
|
66
66
|
}
|
|
@@ -324,7 +324,6 @@ const machineSetup = setup({
|
|
|
324
324
|
if (event.type !== 'START_CODE')
|
|
325
325
|
return {};
|
|
326
326
|
return {
|
|
327
|
-
coderPlayer: context.coderPlayer,
|
|
328
327
|
runResults: context.runResults,
|
|
329
328
|
callerInput: event.callerInput,
|
|
330
329
|
coderOutput: undefined,
|
|
@@ -389,7 +388,7 @@ const machineSetup = setup({
|
|
|
389
388
|
questionId: stateId,
|
|
390
389
|
resumeStateId: stateId,
|
|
391
390
|
sourceItem: stateId === 'runFirstPhase' ? 'CODE-1' : 'CODE-3',
|
|
392
|
-
|
|
391
|
+
asker: { kind: 'role', roleId: 'coder' },
|
|
393
392
|
question,
|
|
394
393
|
},
|
|
395
394
|
bossReply: undefined,
|
|
@@ -430,7 +429,6 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
430
429
|
id: 'code',
|
|
431
430
|
initial: 'ready',
|
|
432
431
|
context: ({ input }) => ({
|
|
433
|
-
coderPlayer: isNonEmptyString(input.coderPlayer) ? input.coderPlayer : 'Coder',
|
|
434
432
|
runResults: typeof input.runResults === 'string' ? input.runResults : '',
|
|
435
433
|
}),
|
|
436
434
|
output: ({ context }) => {
|
|
@@ -465,19 +463,18 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
465
463
|
runFirstPhase: {
|
|
466
464
|
id: 'runFirstPhase',
|
|
467
465
|
description: STATE_DESCRIPTIONS.runFirstPhase,
|
|
468
|
-
meta: playbookMeta('runFirstPhase', '
|
|
466
|
+
meta: playbookMeta('runFirstPhase', 'coder'),
|
|
469
467
|
tags: ['playbook.busy'],
|
|
470
468
|
invoke: {
|
|
471
469
|
src: 'player',
|
|
472
470
|
input: ({ context }) => ({
|
|
473
471
|
stateId: 'runFirstPhase',
|
|
474
|
-
|
|
472
|
+
role: 'coder',
|
|
475
473
|
sourceItem: 'CODE-1',
|
|
476
474
|
prompt: FIRST_PHASE_PROMPT,
|
|
477
475
|
result: FIRST_PHASE_RESULTS,
|
|
478
476
|
callerInput: context.callerInput ?? '',
|
|
479
477
|
runResults: context.runResults,
|
|
480
|
-
coderPlayer: context.coderPlayer,
|
|
481
478
|
...(context.pendingBossQuestion === undefined
|
|
482
479
|
? {}
|
|
483
480
|
: { pendingBossQuestion: context.pendingBossQuestion }),
|
|
@@ -550,19 +547,18 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
550
547
|
runIrTask: {
|
|
551
548
|
id: 'runIrTask',
|
|
552
549
|
description: STATE_DESCRIPTIONS.runIrTask,
|
|
553
|
-
meta: playbookMeta('runIrTask', '
|
|
550
|
+
meta: playbookMeta('runIrTask', 'coder'),
|
|
554
551
|
tags: ['playbook.busy'],
|
|
555
552
|
invoke: {
|
|
556
553
|
src: 'player',
|
|
557
554
|
input: ({ context }) => ({
|
|
558
555
|
stateId: 'runIrTask',
|
|
559
|
-
|
|
556
|
+
role: 'coder',
|
|
560
557
|
sourceItem: 'CODE-3',
|
|
561
558
|
prompt: IR_TASK_PROMPT,
|
|
562
559
|
result: IR_TASK_RESULTS,
|
|
563
560
|
callerInput: context.callerInput ?? '',
|
|
564
561
|
runResults: context.runResults,
|
|
565
|
-
coderPlayer: context.coderPlayer,
|
|
566
562
|
...(context.irNumber === undefined
|
|
567
563
|
? {}
|
|
568
564
|
: { irNumber: context.irNumber }),
|
|
@@ -31,19 +31,18 @@ export type PendingBossQuestion = {
|
|
|
31
31
|
readonly questionId: 'runFirstPhase' | 'runIrTask';
|
|
32
32
|
readonly resumeStateId: 'runFirstPhase' | 'runIrTask';
|
|
33
33
|
readonly sourceItem: 'CODE-1' | 'CODE-3';
|
|
34
|
-
readonly
|
|
34
|
+
readonly asker: { readonly kind: 'role'; readonly roleId: 'coder' };
|
|
35
35
|
readonly question: string;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
export type PlayerInput = {
|
|
39
39
|
readonly stateId: 'runFirstPhase' | 'runIrTask';
|
|
40
|
-
readonly
|
|
40
|
+
readonly role: 'coder';
|
|
41
41
|
readonly sourceItem: 'CODE-1' | 'CODE-3';
|
|
42
42
|
readonly prompt: string;
|
|
43
43
|
readonly result: Readonly<Record<string, string>>;
|
|
44
44
|
readonly callerInput: string;
|
|
45
45
|
readonly runResults: string;
|
|
46
|
-
readonly coderPlayer: string;
|
|
47
46
|
readonly irNumber?: string;
|
|
48
47
|
readonly irTask?: string;
|
|
49
48
|
readonly pendingBossQuestion?: PendingBossQuestion;
|
|
@@ -114,12 +113,10 @@ export type CodePlaybookOutput =
|
|
|
114
113
|
};
|
|
115
114
|
|
|
116
115
|
export type CodingInput = {
|
|
117
|
-
readonly coderPlayer?: string;
|
|
118
116
|
readonly runResults?: string;
|
|
119
117
|
};
|
|
120
118
|
|
|
121
119
|
export type CodingContext = {
|
|
122
|
-
readonly coderPlayer: string;
|
|
123
120
|
readonly runResults: string;
|
|
124
121
|
readonly callerInput?: string;
|
|
125
122
|
readonly coderOutput?: string;
|
|
@@ -210,13 +207,13 @@ const STATE_DESCRIPTIONS = {
|
|
|
210
207
|
|
|
211
208
|
function playbookMeta<StateId extends keyof typeof STATE_DESCRIPTIONS>(
|
|
212
209
|
stateId: StateId,
|
|
213
|
-
|
|
210
|
+
role?: 'coder',
|
|
214
211
|
) {
|
|
215
212
|
return {
|
|
216
213
|
playbook: {
|
|
217
214
|
stateId,
|
|
218
215
|
description: STATE_DESCRIPTIONS[stateId],
|
|
219
|
-
...(
|
|
216
|
+
...(role === undefined ? {} : { role }),
|
|
220
217
|
},
|
|
221
218
|
};
|
|
222
219
|
}
|
|
@@ -557,7 +554,6 @@ const machineSetup = setup({
|
|
|
557
554
|
startCoding: assign(({ context, event }) => {
|
|
558
555
|
if (event.type !== 'START_CODE') return {};
|
|
559
556
|
return {
|
|
560
|
-
coderPlayer: context.coderPlayer,
|
|
561
557
|
runResults: context.runResults,
|
|
562
558
|
callerInput: event.callerInput,
|
|
563
559
|
coderOutput: undefined,
|
|
@@ -623,7 +619,7 @@ const machineSetup = setup({
|
|
|
623
619
|
questionId: stateId,
|
|
624
620
|
resumeStateId: stateId,
|
|
625
621
|
sourceItem: stateId === 'runFirstPhase' ? 'CODE-1' : 'CODE-3',
|
|
626
|
-
|
|
622
|
+
asker: { kind: 'role', roleId: 'coder' },
|
|
627
623
|
question,
|
|
628
624
|
},
|
|
629
625
|
bossReply: undefined,
|
|
@@ -670,8 +666,6 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
670
666
|
id: 'code',
|
|
671
667
|
initial: 'ready',
|
|
672
668
|
context: ({ input }) => ({
|
|
673
|
-
coderPlayer:
|
|
674
|
-
isNonEmptyString(input.coderPlayer) ? input.coderPlayer : 'Coder',
|
|
675
669
|
runResults: typeof input.runResults === 'string' ? input.runResults : '',
|
|
676
670
|
}),
|
|
677
671
|
output: ({ context }): CodePlaybookOutput => {
|
|
@@ -707,19 +701,18 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
707
701
|
runFirstPhase: {
|
|
708
702
|
id: 'runFirstPhase',
|
|
709
703
|
description: STATE_DESCRIPTIONS.runFirstPhase,
|
|
710
|
-
meta: playbookMeta('runFirstPhase', '
|
|
704
|
+
meta: playbookMeta('runFirstPhase', 'coder'),
|
|
711
705
|
tags: ['playbook.busy'],
|
|
712
706
|
invoke: {
|
|
713
707
|
src: 'player',
|
|
714
708
|
input: ({ context }): PlayerInput => ({
|
|
715
709
|
stateId: 'runFirstPhase',
|
|
716
|
-
|
|
710
|
+
role: 'coder',
|
|
717
711
|
sourceItem: 'CODE-1',
|
|
718
712
|
prompt: FIRST_PHASE_PROMPT,
|
|
719
713
|
result: FIRST_PHASE_RESULTS,
|
|
720
714
|
callerInput: context.callerInput ?? '',
|
|
721
715
|
runResults: context.runResults,
|
|
722
|
-
coderPlayer: context.coderPlayer,
|
|
723
716
|
...(context.pendingBossQuestion === undefined
|
|
724
717
|
? {}
|
|
725
718
|
: { pendingBossQuestion: context.pendingBossQuestion }),
|
|
@@ -792,19 +785,18 @@ export const codingMachine = machineSetup.createMachine({
|
|
|
792
785
|
runIrTask: {
|
|
793
786
|
id: 'runIrTask',
|
|
794
787
|
description: STATE_DESCRIPTIONS.runIrTask,
|
|
795
|
-
meta: playbookMeta('runIrTask', '
|
|
788
|
+
meta: playbookMeta('runIrTask', 'coder'),
|
|
796
789
|
tags: ['playbook.busy'],
|
|
797
790
|
invoke: {
|
|
798
791
|
src: 'player',
|
|
799
792
|
input: ({ context }): PlayerInput => ({
|
|
800
793
|
stateId: 'runIrTask',
|
|
801
|
-
|
|
794
|
+
role: 'coder',
|
|
802
795
|
sourceItem: 'CODE-3',
|
|
803
796
|
prompt: IR_TASK_PROMPT,
|
|
804
797
|
result: IR_TASK_RESULTS,
|
|
805
798
|
callerInput: context.callerInput ?? '',
|
|
806
799
|
runResults: context.runResults,
|
|
807
|
-
coderPlayer: context.coderPlayer,
|
|
808
800
|
...(context.irNumber === undefined
|
|
809
801
|
? {}
|
|
810
802
|
: { irNumber: context.irNumber }),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type XStatePromptIdentity } from '@sublang/playbook/xstate-runtime';
|
|
1
2
|
import { type CodingInput, type PlayerInput } from './code.fsm.js';
|
|
2
3
|
import type { CaptainCallOptions, CaptainResult, JsonValue, NormalizedError, PlayerCallOptions, PlaybookCallRequest, PlaybookCallResult, PlaybookCallStart, PlaybookControlReceipt, PlaybookControlView, PlaybookPendingCall, PlaybookPorts, PlaybookRunResult, PlaybookRuntime, PlaybookRuntimeFactory, PlaybookRuntimeSnapshot, PlaybookSession, PlaybookState, PlaybookStateValue, PlaybookTraceEvent, PlaybookTraceType, PlayerResult, PlayerSessionStore } from '@sublang/playbook/runtime';
|
|
3
4
|
export type { CaptainCallOptions, CaptainResult, JsonValue, NormalizedError, PlayerCallOptions, PlaybookCallRequest, PlaybookCallResult, PlaybookCallStart, PlaybookControlReceipt, PlaybookControlView, PlaybookPendingCall, PlaybookPorts, PlaybookRunResult, PlaybookRuntime, PlaybookRuntimeFactory, PlaybookRuntimeSnapshot, PlaybookSession, PlaybookState, PlaybookStateValue, PlaybookTraceEvent, PlaybookTraceType, PlayerResult, PlayerSessionStore, };
|
|
@@ -7,7 +8,7 @@ export type CodePlaybookOptions = CodingInput;
|
|
|
7
8
|
* runtime text. The generic composer preserves the marker itself; CODE's
|
|
8
9
|
* override additionally keeps a multiline value inside that quote.
|
|
9
10
|
*/
|
|
10
|
-
declare function composePlayerPrompt(input: PlayerInput): string;
|
|
11
|
+
declare function composePlayerPrompt(input: PlayerInput, promptIdentity: XStatePromptIdentity): string;
|
|
11
12
|
export declare const _internal: {
|
|
12
13
|
composePlayerPrompt: typeof composePlayerPrompt;
|
|
13
14
|
VERBATIM_PAYLOAD_FIELDS: ReadonlySet<string>;
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Generated by slc/link.md (FSM-to-Runtime linker).
|
|
5
5
|
// Source FSM: ./code.fsm.ts
|
|
6
|
-
//
|
|
6
|
+
// Role metadata: Coder→coder (canonical local role)
|
|
7
7
|
// Boss event: deterministic START_CODE entry; exact Boss text becomes
|
|
8
8
|
// callerInput; pending Coder questions retain BOSS_REPLY
|
|
9
9
|
// Adjudication: LLM judge per player state; coderOutput is carried verbatim
|
|
10
10
|
// Nested call: literal review target through the shared bridge
|
|
11
|
-
// Compat: artifact schema
|
|
11
|
+
// Compat: artifact schema 2 / runtime ABI 1
|
|
12
12
|
import { RUNTIME_ABI, createXStatePlaybookRuntime, snapshotJsonValue, } from '@sublang/playbook/xstate-runtime';
|
|
13
13
|
import { codingMachine, } from './code.fsm.js';
|
|
14
|
-
const OPTION_KEYS = new Set(['
|
|
14
|
+
const OPTION_KEYS = new Set(['runResults']);
|
|
15
15
|
const PLACEHOLDER = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g;
|
|
16
16
|
const CONTINUATION_PREAMBLE = 'You previously paused this task to ask Boss a question; Boss has now replied. Continue the same task using the reply below.';
|
|
17
17
|
const VERBATIM_PAYLOAD_FIELDS = new Set([
|
|
@@ -38,8 +38,6 @@ function snapshotCodeOptions(value) {
|
|
|
38
38
|
function placeholderField(token) {
|
|
39
39
|
if (token === '#')
|
|
40
40
|
return 'irNumber';
|
|
41
|
-
if (token === 'coder-llm')
|
|
42
|
-
return 'coderPlayer';
|
|
43
41
|
return token.replace(/-([A-Za-z0-9_$])/g, (_match, next) => next.toUpperCase());
|
|
44
42
|
}
|
|
45
43
|
function quoteContinuation(value) {
|
|
@@ -50,14 +48,16 @@ function quoteContinuation(value) {
|
|
|
50
48
|
* runtime text. The generic composer preserves the marker itself; CODE's
|
|
51
49
|
* override additionally keeps a multiline value inside that quote.
|
|
52
50
|
*/
|
|
53
|
-
function composePlayerPrompt(input) {
|
|
51
|
+
function composePlayerPrompt(input, promptIdentity) {
|
|
54
52
|
const fields = input;
|
|
55
53
|
const template = input.prompt
|
|
56
54
|
.split('\n')
|
|
57
55
|
.filter((line) => !(line === '> <run-results>' && input.runResults.length === 0))
|
|
58
56
|
.join('\n');
|
|
59
57
|
const body = template.replace(PLACEHOLDER, (match, token, offset, source) => {
|
|
60
|
-
const value =
|
|
58
|
+
const value = token === 'coder-llm'
|
|
59
|
+
? promptIdentity('coder')
|
|
60
|
+
: fields[placeholderField(token)];
|
|
61
61
|
if (typeof value !== 'string')
|
|
62
62
|
return match;
|
|
63
63
|
const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
|
|
@@ -81,21 +81,20 @@ export const _internal = {
|
|
|
81
81
|
};
|
|
82
82
|
const runtimeSpec = {
|
|
83
83
|
label: 'CODE',
|
|
84
|
-
compat: { artifactSchema:
|
|
84
|
+
compat: { artifactSchema: 2, runtimeAbi: RUNTIME_ABI },
|
|
85
85
|
snapshotOptions: snapshotCodeOptions,
|
|
86
86
|
entryEvent: { type: 'START_CODE', textField: 'callerInput' },
|
|
87
|
-
|
|
87
|
+
roleStates: {
|
|
88
88
|
runFirstPhase: {
|
|
89
|
-
|
|
89
|
+
role: 'coder',
|
|
90
90
|
label: 'Coder is implementing one direct phase or committing a new intent record.',
|
|
91
91
|
},
|
|
92
92
|
runIrTask: {
|
|
93
|
-
|
|
93
|
+
role: 'coder',
|
|
94
94
|
label: 'Coder is implementing exactly one unfinished intent-record task.',
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
|
-
|
|
98
|
-
composePlayerPrompt: (input) => composePlayerPrompt(input),
|
|
97
|
+
composePlayerPrompt: (input, promptIdentity) => composePlayerPrompt(input, promptIdentity),
|
|
99
98
|
verbatimPayloadFields: VERBATIM_PAYLOAD_FIELDS,
|
|
100
99
|
controlContextFields: ['phase'],
|
|
101
100
|
transitionEventFields: ['callerInput', 'answer', 'questionId'],
|
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Generated by slc/link.md (FSM-to-Runtime linker).
|
|
5
5
|
// Source FSM: ./code.fsm.ts
|
|
6
|
-
//
|
|
6
|
+
// Role metadata: Coder→coder (canonical local role)
|
|
7
7
|
// Boss event: deterministic START_CODE entry; exact Boss text becomes
|
|
8
8
|
// callerInput; pending Coder questions retain BOSS_REPLY
|
|
9
9
|
// Adjudication: LLM judge per player state; coderOutput is carried verbatim
|
|
10
10
|
// Nested call: literal review target through the shared bridge
|
|
11
|
-
// Compat: artifact schema
|
|
11
|
+
// Compat: artifact schema 2 / runtime ABI 1
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
RUNTIME_ABI,
|
|
15
15
|
createXStatePlaybookRuntime,
|
|
16
16
|
snapshotJsonValue,
|
|
17
17
|
type PlaybookPlayerInput,
|
|
18
|
+
type XStatePromptIdentity,
|
|
18
19
|
type XStatePlaybookRuntimeSpec,
|
|
19
20
|
} from '@sublang/playbook/xstate-runtime';
|
|
20
21
|
import {
|
|
@@ -76,7 +77,7 @@ export type {
|
|
|
76
77
|
|
|
77
78
|
export type CodePlaybookOptions = CodingInput;
|
|
78
79
|
|
|
79
|
-
const OPTION_KEYS = new Set(['
|
|
80
|
+
const OPTION_KEYS = new Set(['runResults']);
|
|
80
81
|
const PLACEHOLDER = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g;
|
|
81
82
|
const CONTINUATION_PREAMBLE =
|
|
82
83
|
'You previously paused this task to ask Boss a question; Boss has now replied. Continue the same task using the reply below.';
|
|
@@ -108,7 +109,6 @@ function snapshotCodeOptions(value: unknown): CodePlaybookOptions {
|
|
|
108
109
|
|
|
109
110
|
function placeholderField(token: string): string {
|
|
110
111
|
if (token === '#') return 'irNumber';
|
|
111
|
-
if (token === 'coder-llm') return 'coderPlayer';
|
|
112
112
|
return token.replace(/-([A-Za-z0-9_$])/g, (_match, next: string) =>
|
|
113
113
|
next.toUpperCase(),
|
|
114
114
|
);
|
|
@@ -123,7 +123,10 @@ function quoteContinuation(value: string): string {
|
|
|
123
123
|
* runtime text. The generic composer preserves the marker itself; CODE's
|
|
124
124
|
* override additionally keeps a multiline value inside that quote.
|
|
125
125
|
*/
|
|
126
|
-
function composePlayerPrompt(
|
|
126
|
+
function composePlayerPrompt(
|
|
127
|
+
input: PlayerInput,
|
|
128
|
+
promptIdentity: XStatePromptIdentity,
|
|
129
|
+
): string {
|
|
127
130
|
const fields = input as unknown as Record<string, unknown>;
|
|
128
131
|
const template = input.prompt
|
|
129
132
|
.split('\n')
|
|
@@ -134,7 +137,10 @@ function composePlayerPrompt(input: PlayerInput): string {
|
|
|
134
137
|
const body = template.replace(
|
|
135
138
|
PLACEHOLDER,
|
|
136
139
|
(match: string, token: string, offset: number, source: string) => {
|
|
137
|
-
const value =
|
|
140
|
+
const value =
|
|
141
|
+
token === 'coder-llm'
|
|
142
|
+
? promptIdentity('coder')
|
|
143
|
+
: fields[placeholderField(token)];
|
|
138
144
|
if (typeof value !== 'string') return match;
|
|
139
145
|
const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
|
|
140
146
|
const literal = source.slice(lineStart, offset);
|
|
@@ -160,29 +166,30 @@ export const _internal = {
|
|
|
160
166
|
VERBATIM_PAYLOAD_FIELDS,
|
|
161
167
|
};
|
|
162
168
|
|
|
163
|
-
const runtimeSpec
|
|
169
|
+
const runtimeSpec = {
|
|
164
170
|
label: 'CODE',
|
|
165
|
-
compat: { artifactSchema:
|
|
171
|
+
compat: { artifactSchema: 2, runtimeAbi: RUNTIME_ABI },
|
|
166
172
|
snapshotOptions: snapshotCodeOptions,
|
|
167
173
|
entryEvent: { type: 'START_CODE', textField: 'callerInput' },
|
|
168
|
-
|
|
174
|
+
roleStates: {
|
|
169
175
|
runFirstPhase: {
|
|
170
|
-
|
|
176
|
+
role: 'coder',
|
|
171
177
|
label:
|
|
172
178
|
'Coder is implementing one direct phase or committing a new intent record.',
|
|
173
179
|
},
|
|
174
180
|
runIrTask: {
|
|
175
|
-
|
|
181
|
+
role: 'coder',
|
|
176
182
|
label: 'Coder is implementing exactly one unfinished intent-record task.',
|
|
177
183
|
},
|
|
178
184
|
},
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
composePlayerPrompt: (
|
|
186
|
+
input: PlaybookPlayerInput,
|
|
187
|
+
promptIdentity: XStatePromptIdentity,
|
|
188
|
+
) => composePlayerPrompt(input as PlayerInput, promptIdentity),
|
|
182
189
|
verbatimPayloadFields: VERBATIM_PAYLOAD_FIELDS,
|
|
183
190
|
controlContextFields: ['phase'],
|
|
184
191
|
transitionEventFields: ['callerInput', 'answer', 'questionId'],
|
|
185
|
-
}
|
|
192
|
+
} satisfies XStatePlaybookRuntimeSpec<CodePlaybookOptions>;
|
|
186
193
|
|
|
187
194
|
const createPlaybookRuntime: PlaybookRuntimeFactory<CodePlaybookOptions> =
|
|
188
195
|
createXStatePlaybookRuntime(codingMachine, runtimeSpec);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PlaybookRuntime } from './code.playbook.js';
|
|
2
2
|
export interface PlaybookSummaryPolicy {
|
|
3
3
|
stateCountLabels: Readonly<Record<string, string>>;
|
|
4
4
|
copyPasteGuardNames: readonly string[];
|
|
@@ -7,24 +7,17 @@ export interface PlaybookSummaryPolicy {
|
|
|
7
7
|
copyPastes: number;
|
|
8
8
|
}, rounds: number): string;
|
|
9
9
|
}
|
|
10
|
-
export interface RegistryPlayer {
|
|
11
|
-
id: string;
|
|
12
|
-
adapter?: string;
|
|
13
|
-
model?: string;
|
|
14
|
-
}
|
|
15
|
-
export interface CreateCodeRuntimeOptions {
|
|
16
|
-
captainOptions: unknown;
|
|
17
|
-
players: readonly RegistryPlayer[];
|
|
18
|
-
}
|
|
19
10
|
export type CodeOptions = Readonly<Record<string, never>>;
|
|
20
11
|
export interface CodePlaybookRegistryEntry {
|
|
21
12
|
id: 'code';
|
|
22
13
|
command: 'code';
|
|
23
14
|
intent: string;
|
|
15
|
+
artifactSchema: 2;
|
|
24
16
|
requiredRoleIds: readonly ['coder'];
|
|
17
|
+
concurrentRoleSets: readonly [];
|
|
25
18
|
summaryPolicy: PlaybookSummaryPolicy;
|
|
26
|
-
validateOptions(
|
|
27
|
-
createRuntime(options:
|
|
19
|
+
validateOptions(optionSlice: unknown): CodeOptions;
|
|
20
|
+
createRuntime(options: CodeOptions): PlaybookRuntime;
|
|
28
21
|
}
|
|
29
22
|
export declare const codeStateCountLabels: {};
|
|
30
23
|
export declare const codeCopyPasteGuardNames: readonly ["directCommit", "irCommit", "moreTasks", "finalTask"];
|
|
@@ -34,6 +27,5 @@ export declare function codeSavedCountsLine(counts: {
|
|
|
34
27
|
}, rounds: number): string;
|
|
35
28
|
export declare const codeSummaryPolicy: PlaybookSummaryPolicy;
|
|
36
29
|
export declare function validateCodeOptions(optionSlice: unknown): CodeOptions;
|
|
37
|
-
export declare function createCodeRuntimeOptions({ captainOptions, players, }: CreateCodeRuntimeOptions): CodePlaybookOptions;
|
|
38
30
|
export declare const codePlaybookRegistryEntry: CodePlaybookRegistryEntry;
|
|
39
31
|
export default codePlaybookRegistryEntry;
|
|
@@ -43,24 +43,17 @@ export function validateCodeOptions(optionSlice) {
|
|
|
43
43
|
}
|
|
44
44
|
return Object.freeze({});
|
|
45
45
|
}
|
|
46
|
-
function playerIdentity(players, id) {
|
|
47
|
-
const player = players.find((entry) => entry.id === id);
|
|
48
|
-
return player?.model ?? player?.adapter;
|
|
49
|
-
}
|
|
50
|
-
export function createCodeRuntimeOptions({ captainOptions, players, }) {
|
|
51
|
-
validateCodeOptions(captainOptions);
|
|
52
|
-
const coderPlayer = playerIdentity(players, 'coder');
|
|
53
|
-
return coderPlayer === undefined ? {} : { coderPlayer };
|
|
54
|
-
}
|
|
55
46
|
export const codePlaybookRegistryEntry = {
|
|
56
47
|
id: 'code',
|
|
57
48
|
command: 'code',
|
|
58
49
|
intent: 'implement a coding intent in reviewed, one-commit phases, using an intent record when needed',
|
|
50
|
+
artifactSchema: 2,
|
|
59
51
|
requiredRoleIds: ['coder'],
|
|
52
|
+
concurrentRoleSets: [],
|
|
60
53
|
summaryPolicy: codeSummaryPolicy,
|
|
61
54
|
validateOptions: validateCodeOptions,
|
|
62
55
|
createRuntime(options) {
|
|
63
|
-
return createPlaybookRuntime(
|
|
56
|
+
return createPlaybookRuntime(options);
|
|
64
57
|
},
|
|
65
58
|
};
|
|
66
59
|
export default codePlaybookRegistryEntry;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
3
|
|
|
4
4
|
import createPlaybookRuntime, {
|
|
5
|
-
type CodePlaybookOptions,
|
|
6
5
|
type PlaybookRuntime,
|
|
7
6
|
} from './code.playbook.js';
|
|
8
7
|
|
|
@@ -15,27 +14,18 @@ export interface PlaybookSummaryPolicy {
|
|
|
15
14
|
): string;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export interface RegistryPlayer {
|
|
19
|
-
id: string;
|
|
20
|
-
adapter?: string;
|
|
21
|
-
model?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface CreateCodeRuntimeOptions {
|
|
25
|
-
captainOptions: unknown;
|
|
26
|
-
players: readonly RegistryPlayer[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
17
|
export type CodeOptions = Readonly<Record<string, never>>;
|
|
30
18
|
|
|
31
19
|
export interface CodePlaybookRegistryEntry {
|
|
32
20
|
id: 'code';
|
|
33
21
|
command: 'code';
|
|
34
22
|
intent: string;
|
|
23
|
+
artifactSchema: 2;
|
|
35
24
|
requiredRoleIds: readonly ['coder'];
|
|
25
|
+
concurrentRoleSets: readonly [];
|
|
36
26
|
summaryPolicy: PlaybookSummaryPolicy;
|
|
37
|
-
validateOptions(
|
|
38
|
-
createRuntime(options:
|
|
27
|
+
validateOptions(optionSlice: unknown): CodeOptions;
|
|
28
|
+
createRuntime(options: CodeOptions): PlaybookRuntime;
|
|
39
29
|
}
|
|
40
30
|
|
|
41
31
|
// REVIEW owns and labels its real review rounds. CODE's two suspended wrapper
|
|
@@ -96,33 +86,18 @@ export function validateCodeOptions(optionSlice: unknown): CodeOptions {
|
|
|
96
86
|
return Object.freeze({});
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
function playerIdentity(
|
|
100
|
-
players: readonly RegistryPlayer[],
|
|
101
|
-
id: string,
|
|
102
|
-
): string | undefined {
|
|
103
|
-
const player = players.find((entry) => entry.id === id);
|
|
104
|
-
return player?.model ?? player?.adapter;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function createCodeRuntimeOptions({
|
|
108
|
-
captainOptions,
|
|
109
|
-
players,
|
|
110
|
-
}: CreateCodeRuntimeOptions): CodePlaybookOptions {
|
|
111
|
-
validateCodeOptions(captainOptions);
|
|
112
|
-
const coderPlayer = playerIdentity(players, 'coder');
|
|
113
|
-
return coderPlayer === undefined ? {} : { coderPlayer };
|
|
114
|
-
}
|
|
115
|
-
|
|
116
89
|
export const codePlaybookRegistryEntry: CodePlaybookRegistryEntry = {
|
|
117
90
|
id: 'code',
|
|
118
91
|
command: 'code',
|
|
119
92
|
intent:
|
|
120
93
|
'implement a coding intent in reviewed, one-commit phases, using an intent record when needed',
|
|
94
|
+
artifactSchema: 2,
|
|
121
95
|
requiredRoleIds: ['coder'],
|
|
96
|
+
concurrentRoleSets: [],
|
|
122
97
|
summaryPolicy: codeSummaryPolicy,
|
|
123
98
|
validateOptions: validateCodeOptions,
|
|
124
99
|
createRuntime(options) {
|
|
125
|
-
return createPlaybookRuntime(
|
|
100
|
+
return createPlaybookRuntime(options);
|
|
126
101
|
},
|
|
127
102
|
};
|
|
128
103
|
|