@sublang/playbook 5.0.0 → 7.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 +22 -14
- package/docs/cli.md +138 -90
- package/docs/configuration.md +113 -29
- package/docs/embedding.md +24 -16
- package/package.json +42 -21
- package/reference/sdlc/captain.playbook/captain.playbook.js +2 -0
- package/reference/sdlc/captain.playbook/captain.playbook.ts +2 -0
- package/reference/sdlc/code.md +55 -97
- package/reference/sdlc/code.playbook/bin/launch-config.js +938 -0
- package/reference/sdlc/code.playbook/bin/playbook.js +145 -562
- package/reference/sdlc/code.playbook/bin/provision.js +84 -38
- package/reference/sdlc/code.playbook/bin/run.js +1171 -983
- package/reference/sdlc/code.playbook/bin/session-store.js +1169 -0
- package/reference/sdlc/code.playbook/code.fsm.d.ts +229 -94
- package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +26 -44
- package/reference/sdlc/code.playbook/code.fsm.introspect.js +61 -66
- package/reference/sdlc/code.playbook/code.fsm.introspect.ts +100 -149
- package/reference/sdlc/code.playbook/code.fsm.js +587 -1347
- package/reference/sdlc/code.playbook/code.fsm.ts +809 -1650
- package/reference/sdlc/code.playbook/code.gears.md +51 -263
- package/reference/sdlc/code.playbook/code.playbook.d.ts +8 -47
- package/reference/sdlc/code.playbook/code.playbook.js +69 -656
- package/reference/sdlc/code.playbook/code.playbook.ts +90 -867
- package/reference/sdlc/code.playbook/code.registry.d.ts +9 -25
- package/reference/sdlc/code.playbook/code.registry.js +20 -78
- package/reference/sdlc/code.playbook/code.registry.ts +58 -122
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +70 -3
- package/reference/sdlc/code.playbook/playbook-captain.js +954 -80
- package/reference/sdlc/code.playbook/playbook-captain.ts +1408 -80
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +37 -36
- package/reference/sdlc/decide.md +54 -0
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +261 -0
- package/reference/sdlc/decide.playbook/decide.fsm.js +894 -0
- package/reference/sdlc/decide.playbook/decide.fsm.ts +1152 -0
- package/reference/sdlc/decide.playbook/decide.gears.md +88 -0
- package/reference/sdlc/decide.playbook/decide.playbook.d.ts +67 -0
- package/reference/sdlc/{discuss.playbook/discuss.playbook.js → decide.playbook/decide.playbook.js} +545 -372
- package/reference/sdlc/{discuss.playbook/discuss.playbook.ts → decide.playbook/decide.playbook.ts} +665 -454
- package/reference/sdlc/decide.playbook/decide.registry.d.ts +41 -0
- package/reference/sdlc/decide.playbook/decide.registry.js +60 -0
- package/reference/sdlc/decide.playbook/decide.registry.ts +125 -0
- package/reference/sdlc/review.md +81 -0
- package/reference/sdlc/review.playbook/review.fsm.d.ts +183 -0
- package/reference/sdlc/review.playbook/review.fsm.js +524 -0
- package/reference/sdlc/review.playbook/review.fsm.ts +652 -0
- package/reference/sdlc/review.playbook/review.gears.md +112 -0
- package/reference/sdlc/review.playbook/review.playbook.d.ts +12 -0
- package/reference/sdlc/review.playbook/review.playbook.js +112 -0
- package/reference/sdlc/review.playbook/review.playbook.ts +201 -0
- package/reference/sdlc/review.playbook/review.registry.d.ts +43 -0
- package/reference/sdlc/review.playbook/review.registry.js +73 -0
- package/reference/sdlc/review.playbook/review.registry.ts +138 -0
- package/slc/gears2fsm.md +13 -4
- package/slc/link.md +83 -14
- package/slc/text2gears.md +22 -2
- package/src/runtime.d.ts +21 -2
- package/src/runtime.ts +38 -6
- package/src/xstate-playbook-runtime.d.ts +9 -2
- package/src/xstate-playbook-runtime.js +319 -35
- package/src/xstate-playbook-runtime.ts +412 -41
- package/src/xstate-runtime.d.ts +19 -2
- package/src/xstate-runtime.js +384 -57
- package/src/xstate-runtime.ts +542 -71
- package/reference/sdlc/discuss.md +0 -93
- package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +0 -396
- package/reference/sdlc/discuss.playbook/discuss.fsm.js +0 -2067
- package/reference/sdlc/discuss.playbook/discuss.fsm.ts +0 -2465
- package/reference/sdlc/discuss.playbook/discuss.gears.md +0 -258
- package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +0 -113
- package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +0 -58
- package/reference/sdlc/discuss.playbook/discuss.registry.js +0 -97
- package/reference/sdlc/discuss.playbook/discuss.registry.ts +0 -153
|
@@ -1,196 +1,147 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
3
|
|
|
4
|
-
// FSM introspection helpers — IR-005 Task 2.
|
|
5
|
-
// Static walkers over `codingMachine.config` consumed by the
|
|
6
|
-
// conformance, coverage, and prompt-contract tests landing in
|
|
7
|
-
// Tasks 3–5. Reaching into `machine.config` is internal but stable
|
|
8
|
-
// in xstate v5: it preserves the literal `createMachine` argument,
|
|
9
|
-
// so `invoke.input` is still the original `({ context }) =>
|
|
10
|
-
// PlayerInput` function and `invoke.onDone` is still the per-arm
|
|
11
|
-
// array with `guard` / `target` / `actions` keys.
|
|
12
|
-
|
|
13
4
|
import type {
|
|
14
5
|
CodingContext,
|
|
6
|
+
PlaybookInput,
|
|
15
7
|
PlayerInput,
|
|
16
8
|
codingMachine,
|
|
17
9
|
} from './code.fsm.js';
|
|
18
10
|
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
readonly transitions: ReadonlyArray<CaptainTransition>;
|
|
24
|
-
}
|
|
11
|
+
export type TransitionGuard = (args: {
|
|
12
|
+
context: CodingContext;
|
|
13
|
+
event: unknown;
|
|
14
|
+
}) => boolean;
|
|
25
15
|
|
|
26
|
-
export interface
|
|
27
|
-
// Position in the state's `invoke.onDone` array. Stable per FSM
|
|
28
|
-
// source — the coverage test's fixture table keys
|
|
29
|
-
// `(stateId, index)` to address each arm uniquely, since
|
|
30
|
-
// `(stateId, target)` collides for arms that share a target
|
|
31
|
-
// (e.g., `commitReviewerCleared` and `commitJoint` each route
|
|
32
|
-
// both `committed && afterReview === 'done'` and
|
|
33
|
-
// `noRelevantChanges` to `done`).
|
|
16
|
+
export interface InvokingTransition {
|
|
34
17
|
readonly index: number;
|
|
35
18
|
readonly target: string;
|
|
36
|
-
readonly guard
|
|
19
|
+
readonly guard?: TransitionGuard;
|
|
37
20
|
readonly actions: unknown;
|
|
38
21
|
}
|
|
39
22
|
|
|
40
|
-
export interface
|
|
23
|
+
export interface PlayerStateInfo {
|
|
41
24
|
readonly stateId: string;
|
|
42
|
-
readonly
|
|
43
|
-
readonly
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
export interface BossReplyTransition {
|
|
47
|
-
readonly index: number;
|
|
48
|
-
readonly target: string;
|
|
49
|
-
readonly guard: TransitionGuard;
|
|
50
|
-
readonly actions: unknown;
|
|
25
|
+
readonly sourceItem: string;
|
|
26
|
+
readonly getInput: (context: CodingContext) => PlayerInput;
|
|
27
|
+
readonly transitions: readonly InvokingTransition[];
|
|
51
28
|
}
|
|
52
29
|
|
|
53
|
-
export interface
|
|
54
|
-
readonly
|
|
55
|
-
readonly
|
|
56
|
-
readonly
|
|
57
|
-
readonly
|
|
58
|
-
readonly actions: unknown;
|
|
30
|
+
export interface NestedPlaybookStateInfo {
|
|
31
|
+
readonly stateId: string;
|
|
32
|
+
readonly sourceItem: string;
|
|
33
|
+
readonly getInput: (context: CodingContext) => PlaybookInput;
|
|
34
|
+
readonly transitions: readonly InvokingTransition[];
|
|
59
35
|
}
|
|
60
36
|
|
|
61
|
-
export
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}) => boolean;
|
|
65
|
-
|
|
66
|
-
export interface RootEventTable {
|
|
67
|
-
readonly startCoding: { readonly target: string };
|
|
68
|
-
readonly continueIr: { readonly target: string };
|
|
69
|
-
readonly summarizeIr: { readonly target: string };
|
|
70
|
-
readonly bossInterruptTargets: ReadonlyArray<string>;
|
|
71
|
-
readonly bossInterruptTargetDescriptions: ReadonlyArray<{
|
|
72
|
-
readonly stateId: string;
|
|
73
|
-
readonly description: string;
|
|
74
|
-
}>;
|
|
37
|
+
export interface AwaitBossReplyInfo {
|
|
38
|
+
readonly stateId: 'awaitBossReply';
|
|
39
|
+
readonly bossReplyTransitions: readonly InvokingTransition[];
|
|
75
40
|
}
|
|
76
41
|
|
|
77
42
|
type RawInvoke = {
|
|
78
43
|
src?: unknown;
|
|
79
|
-
input?: (args: { context:
|
|
44
|
+
input?: (args: { context: CodingContext }) => PlayerInput | PlaybookInput;
|
|
80
45
|
onDone?: unknown;
|
|
81
46
|
};
|
|
82
47
|
|
|
83
|
-
type
|
|
84
|
-
description?: unknown;
|
|
48
|
+
type RawState = {
|
|
85
49
|
invoke?: RawInvoke;
|
|
86
|
-
on?: Record<string, unknown
|
|
50
|
+
on?: Readonly<Record<string, unknown>>;
|
|
87
51
|
};
|
|
88
52
|
|
|
89
|
-
type RawArm = {
|
|
90
|
-
|
|
53
|
+
type RawArm = {
|
|
54
|
+
target?: unknown;
|
|
55
|
+
guard?: TransitionGuard;
|
|
56
|
+
actions?: unknown;
|
|
57
|
+
};
|
|
91
58
|
|
|
92
59
|
type RawConfig = {
|
|
93
|
-
states?: Record<string,
|
|
94
|
-
on?: Record<string, unknown>;
|
|
60
|
+
states?: Readonly<Record<string, RawState>>;
|
|
95
61
|
};
|
|
96
62
|
|
|
97
|
-
|
|
63
|
+
function rawConfig(machine: typeof codingMachine): RawConfig {
|
|
64
|
+
return (machine as unknown as { config: RawConfig }).config;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function arms(value: unknown): readonly RawArm[] {
|
|
68
|
+
if (value === undefined || value === null) return [];
|
|
69
|
+
return (Array.isArray(value) ? value : [value]) as readonly RawArm[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function targetName(target: unknown): string {
|
|
73
|
+
const value = String(target ?? '');
|
|
74
|
+
return value.startsWith('#') ? value.slice(1) : value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function transitions(value: unknown): readonly InvokingTransition[] {
|
|
78
|
+
return arms(value).map((arm, index) => ({
|
|
79
|
+
index,
|
|
80
|
+
target: targetName(arm.target),
|
|
81
|
+
...(arm.guard === undefined ? {} : { guard: arm.guard }),
|
|
82
|
+
actions: arm.actions,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function enumeratePlayerStates(
|
|
98
87
|
machine: typeof codingMachine,
|
|
99
|
-
): readonly
|
|
100
|
-
const states =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
actions: arm.actions,
|
|
117
|
-
}),
|
|
118
|
-
);
|
|
119
|
-
out.push({
|
|
120
|
-
stateId,
|
|
121
|
-
sourceItem: probe.sourceItem,
|
|
122
|
-
getInput,
|
|
123
|
-
transitions,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
return out;
|
|
88
|
+
): readonly PlayerStateInfo[] {
|
|
89
|
+
const states = rawConfig(machine).states ?? {};
|
|
90
|
+
return Object.entries(states).flatMap(([stateId, state]) => {
|
|
91
|
+
const invoke = state.invoke;
|
|
92
|
+
if (invoke?.src !== 'player' || invoke.input === undefined) return [];
|
|
93
|
+
const getInput = (context: CodingContext): PlayerInput =>
|
|
94
|
+
invoke.input?.({ context }) as PlayerInput;
|
|
95
|
+
const input = getInput({ coderPlayer: 'Coder', runResults: '' });
|
|
96
|
+
return [
|
|
97
|
+
{
|
|
98
|
+
stateId,
|
|
99
|
+
sourceItem: input.sourceItem,
|
|
100
|
+
getInput,
|
|
101
|
+
transitions: transitions(invoke.onDone),
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
});
|
|
127
105
|
}
|
|
128
106
|
|
|
129
|
-
|
|
107
|
+
// Backward-compatible internal name retained for repository conformance tools.
|
|
108
|
+
export const enumerateCaptainStates = enumeratePlayerStates;
|
|
109
|
+
|
|
110
|
+
export function enumerateNestedPlaybookStates(
|
|
130
111
|
machine: typeof codingMachine,
|
|
131
|
-
):
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
startCoding: { target: stripIdPrefix(String(readyOn.START_CODING?.target ?? '')) },
|
|
143
|
-
continueIr: { target: stripIdPrefix(String(readyOn.CONTINUE_IR?.target ?? '')) },
|
|
144
|
-
summarizeIr: { target: stripIdPrefix(String(readyOn.SUMMARIZE_IR?.target ?? '')) },
|
|
145
|
-
bossInterruptTargets,
|
|
146
|
-
bossInterruptTargetDescriptions: bossInterruptTargets.map((stateId) => {
|
|
147
|
-
const description = cfg.states?.[stateId]?.description;
|
|
148
|
-
return {
|
|
112
|
+
): readonly NestedPlaybookStateInfo[] {
|
|
113
|
+
const states = rawConfig(machine).states ?? {};
|
|
114
|
+
return Object.entries(states).flatMap(([stateId, state]) => {
|
|
115
|
+
const invoke = state.invoke;
|
|
116
|
+
if (invoke?.src !== 'playbook' || invoke.input === undefined) return [];
|
|
117
|
+
const getInput = (context: CodingContext): PlaybookInput =>
|
|
118
|
+
invoke.input?.({ context }) as PlaybookInput;
|
|
119
|
+
const input = getInput({ coderPlayer: 'Coder', runResults: '' });
|
|
120
|
+
return [
|
|
121
|
+
{
|
|
149
122
|
stateId,
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
123
|
+
sourceItem: input.sourceItem,
|
|
124
|
+
getInput,
|
|
125
|
+
transitions: transitions(invoke.onDone),
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
});
|
|
154
129
|
}
|
|
155
130
|
|
|
156
131
|
export function enumerateAwaitBossReply(
|
|
157
132
|
machine: typeof codingMachine,
|
|
158
133
|
): AwaitBossReplyInfo {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
eventType,
|
|
165
|
-
index,
|
|
166
|
-
target: stripIdPrefix(String(arm.target ?? '')),
|
|
167
|
-
guard: arm.guard ?? alwaysTrue,
|
|
168
|
-
actions: arm.actions,
|
|
169
|
-
}),
|
|
170
|
-
),
|
|
171
|
-
);
|
|
172
|
-
const bossReplyTransitions = toArmArray(awaitOn.BOSS_REPLY).map(
|
|
173
|
-
(arm, index): BossReplyTransition => ({
|
|
174
|
-
index,
|
|
175
|
-
target: stripIdPrefix(String(arm.target ?? '')),
|
|
176
|
-
guard: arm.guard ?? alwaysTrue,
|
|
177
|
-
actions: arm.actions,
|
|
178
|
-
}),
|
|
179
|
-
);
|
|
180
|
-
return { stateId, bossReplyTransitions, transitions };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function getRawConfig(machine: typeof codingMachine): RawConfig {
|
|
184
|
-
return (machine as unknown as { config: RawConfig }).config;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function toArmArray(value: unknown): RawArmWithActions[] {
|
|
188
|
-
if (value === undefined || value === null) return [];
|
|
189
|
-
return (Array.isArray(value) ? value : [value]) as RawArmWithActions[];
|
|
134
|
+
const on = rawConfig(machine).states?.awaitBossReply?.on ?? {};
|
|
135
|
+
return {
|
|
136
|
+
stateId: 'awaitBossReply',
|
|
137
|
+
bossReplyTransitions: transitions(on.BOSS_REPLY),
|
|
138
|
+
};
|
|
190
139
|
}
|
|
191
140
|
|
|
192
|
-
function
|
|
193
|
-
|
|
141
|
+
export function enumerateRootEvents(machine: typeof codingMachine): {
|
|
142
|
+
readonly startCode: { readonly target: string };
|
|
143
|
+
} {
|
|
144
|
+
const on = rawConfig(machine).states?.ready?.on ?? {};
|
|
145
|
+
const start = arms(on.START_CODE)[0];
|
|
146
|
+
return { startCode: { target: targetName(start?.target) } };
|
|
194
147
|
}
|
|
195
|
-
|
|
196
|
-
const alwaysTrue: TransitionGuard = () => true;
|