@sublang/playbook 15.1.0 → 17.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.
Files changed (102) hide show
  1. package/README.md +2 -0
  2. package/docs/cli.md +36 -18
  3. package/docs/configuration.md +7 -5
  4. package/docs/embedding.md +28 -7
  5. package/package.json +4 -4
  6. package/reference/sdlc/branch.playbook/branch.fsm.d.ts +63 -33
  7. package/reference/sdlc/branch.playbook/branch.fsm.js +190 -108
  8. package/reference/sdlc/branch.playbook/branch.fsm.ts +269 -147
  9. package/reference/sdlc/branch.playbook/branch.gears.md +7 -17
  10. package/reference/sdlc/branch.playbook/branch.playbook.d.ts +12 -16
  11. package/reference/sdlc/branch.playbook/branch.playbook.js +112 -101
  12. package/reference/sdlc/branch.playbook/branch.playbook.ts +128 -171
  13. package/reference/sdlc/branch.playbook/branch.registry.d.ts +3 -2
  14. package/reference/sdlc/branch.playbook/branch.registry.ts +6 -2
  15. package/reference/sdlc/captain.md +19 -10
  16. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +6 -2
  17. package/reference/sdlc/captain.playbook/captain.fsm.js +19 -7
  18. package/reference/sdlc/captain.playbook/captain.fsm.ts +25 -10
  19. package/reference/sdlc/captain.playbook/captain.gears.md +16 -8
  20. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +1 -1
  21. package/reference/sdlc/captain.playbook/captain.playbook.js +3 -2
  22. package/reference/sdlc/captain.playbook/captain.playbook.ts +4 -3
  23. package/reference/sdlc/code.playbook/bin/interactive-session.js +14 -1
  24. package/reference/sdlc/code.playbook/bin/portable-codec.js +3 -0
  25. package/reference/sdlc/code.playbook/bin/repository-effects.js +1 -0
  26. package/reference/sdlc/code.playbook/bin/run.js +128 -85
  27. package/reference/sdlc/code.playbook/bin/session-host.js +40 -8
  28. package/reference/sdlc/code.playbook/bin/session-store.js +162 -34
  29. package/reference/sdlc/code.playbook/code.fsm.d.ts +146 -93
  30. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +8 -8
  31. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +13 -13
  32. package/reference/sdlc/code.playbook/code.fsm.js +609 -649
  33. package/reference/sdlc/code.playbook/code.fsm.ts +890 -821
  34. package/reference/sdlc/code.playbook/code.gears.md +39 -29
  35. package/reference/sdlc/code.playbook/code.playbook.d.ts +13 -16
  36. package/reference/sdlc/code.playbook/code.playbook.js +166 -147
  37. package/reference/sdlc/code.playbook/code.playbook.ts +180 -229
  38. package/reference/sdlc/code.playbook/code.registry.d.ts +3 -2
  39. package/reference/sdlc/code.playbook/code.registry.ts +6 -2
  40. package/reference/sdlc/code.playbook/host-capabilities.d.ts +3 -0
  41. package/reference/sdlc/code.playbook/playbook-captain.d.ts +74 -2
  42. package/reference/sdlc/code.playbook/playbook-captain.js +1548 -468
  43. package/reference/sdlc/code.playbook/playbook-captain.ts +1993 -573
  44. package/reference/sdlc/code.playbook/session-host.d.ts +4 -1
  45. package/reference/sdlc/code.playbook/session-store.d.ts +17 -0
  46. package/reference/sdlc/code.playbook/session-store.js +1 -0
  47. package/reference/sdlc/decide.md +1 -0
  48. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +273 -157
  49. package/reference/sdlc/decide.playbook/decide.fsm.js +765 -732
  50. package/reference/sdlc/decide.playbook/decide.fsm.ts +1167 -945
  51. package/reference/sdlc/decide.playbook/decide.gears.md +28 -21
  52. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +11 -59
  53. package/reference/sdlc/decide.playbook/decide.playbook.js +155 -3696
  54. package/reference/sdlc/decide.playbook/decide.playbook.ts +186 -5244
  55. package/reference/sdlc/decide.playbook/decide.registry.d.ts +8 -4
  56. package/reference/sdlc/decide.playbook/decide.registry.js +2 -2
  57. package/reference/sdlc/decide.playbook/decide.registry.ts +13 -6
  58. package/reference/sdlc/dev.playbook/dev.fsm.d.ts +116 -134
  59. package/reference/sdlc/dev.playbook/dev.fsm.js +517 -575
  60. package/reference/sdlc/dev.playbook/dev.fsm.ts +667 -787
  61. package/reference/sdlc/dev.playbook/dev.gears.md +52 -54
  62. package/reference/sdlc/dev.playbook/dev.playbook.d.ts +13 -10
  63. package/reference/sdlc/dev.playbook/dev.playbook.js +128 -120
  64. package/reference/sdlc/dev.playbook/dev.playbook.ts +143 -193
  65. package/reference/sdlc/dev.playbook/dev.registry.d.ts +3 -2
  66. package/reference/sdlc/dev.playbook/dev.registry.ts +6 -2
  67. package/reference/sdlc/pr.playbook/pr.fsm.d.ts +95 -88
  68. package/reference/sdlc/pr.playbook/pr.fsm.js +461 -518
  69. package/reference/sdlc/pr.playbook/pr.fsm.ts +533 -663
  70. package/reference/sdlc/pr.playbook/pr.gears.md +47 -63
  71. package/reference/sdlc/pr.playbook/pr.playbook.d.ts +13 -23
  72. package/reference/sdlc/pr.playbook/pr.playbook.js +118 -112
  73. package/reference/sdlc/pr.playbook/pr.playbook.ts +136 -190
  74. package/reference/sdlc/pr.playbook/pr.registry.d.ts +3 -2
  75. package/reference/sdlc/pr.playbook/pr.registry.ts +4 -2
  76. package/reference/sdlc/review.md +3 -3
  77. package/reference/sdlc/review.playbook/review.fsm.d.ts +150 -116
  78. package/reference/sdlc/review.playbook/review.fsm.js +479 -550
  79. package/reference/sdlc/review.playbook/review.fsm.ts +717 -662
  80. package/reference/sdlc/review.playbook/review.gears.md +32 -29
  81. package/reference/sdlc/review.playbook/review.playbook.d.ts +12 -12
  82. package/reference/sdlc/review.playbook/review.playbook.js +180 -155
  83. package/reference/sdlc/review.playbook/review.playbook.ts +190 -230
  84. package/reference/sdlc/review.playbook/review.registry.d.ts +6 -5
  85. package/reference/sdlc/review.playbook/review.registry.js +3 -3
  86. package/reference/sdlc/review.playbook/review.registry.ts +9 -5
  87. package/slc/gears2fsm.md +77 -8
  88. package/slc/link.md +127 -60
  89. package/slc/materialize-link.mjs +51 -13
  90. package/slc/optimize.md +4 -1
  91. package/slc/prefix-prompts.mjs +29 -28
  92. package/slc/prefix.md +27 -24
  93. package/slc/slc.pin-inputs.json +11 -2
  94. package/slc/text2gears.md +71 -11
  95. package/src/runtime.d.ts +46 -2
  96. package/src/runtime.ts +42 -2
  97. package/src/xstate-playbook-runtime.d.ts +63 -23
  98. package/src/xstate-playbook-runtime.js +1637 -475
  99. package/src/xstate-playbook-runtime.ts +2105 -532
  100. package/src/xstate-runtime.d.ts +3 -4
  101. package/src/xstate-runtime.js +52 -0
  102. package/src/xstate-runtime.ts +59 -4
@@ -1,287 +1,238 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
- //
4
- // Generated by slc/link.md (FSM-to-Runtime linker).
5
- // Source FSM: ./code.fsm.ts
6
- // Role metadata: Coder→coder (canonical local role)
7
- // Boss event: deterministic START_CODE entry; exact Boss text becomes
8
- // callerInput; pending Coder questions retain BOSS_REPLY
9
- // Adjudication: LLM judge per player state; coderOutput is carried verbatim;
10
- // the first phase decides among four semantic outcomes
11
- // Nested call: literal review target through the shared bridge
12
- // Compat: artifact schema 3 / runtime ABI 1
13
-
3
+ // Generated by slc/materialize-link.mjs; governed by the complete slc/link.md.
4
+ // FSM: "./code.fsm.js"; export: codeMachine; strategies: shared defaults with labelled string relays and nested actors.
5
+ import { codeMachine as machine } from "./code.fsm.js";
6
+ import type { PlayerInput as SourcePlayerInput } from "./code.fsm.js";
14
7
  import {
15
- createXStatePlaybookRuntime,
16
- composePlayerContinuation,
17
- snapshotJsonValue,
8
+ createXStatePlaybookRuntime, snapshotJsonValue,
9
+ composePlayerContinuation, type XStatePromptIdentity,
18
10
  type PlaybookPlayerInput,
19
- type XStatePlaybookRuntimeFactory,
20
11
  type XStatePlaybookRuntimeConstruction,
21
- type XStatePromptIdentity,
12
+ type XStatePlaybookRuntimeFactory,
22
13
  type XStatePlaybookRuntimeSpecV3,
23
14
  } from '@sublang/playbook/xstate-runtime';
24
- import {
25
- codingMachine,
26
- type CodingInput,
27
- type PlayerInput,
28
- } from './code.fsm.js';
29
- import type { PlaybookHostConstructionCapabilities } from './playbook-captain.js';
30
- import type {
31
- CaptainCallOptions,
32
- CaptainResult,
33
- JsonValue,
34
- NormalizedError,
35
- PlayerCallOptions,
36
- PlaybookCallRequest,
37
- PlaybookCallResult,
38
- PlaybookCallStart,
39
- PlaybookControlReceipt,
40
- PlaybookControlView,
41
- PlaybookPendingCall,
42
- PlaybookPorts,
43
- PlaybookRunResult,
44
- PlaybookRuntime,
45
- PlaybookRuntimeFactory,
46
- PlaybookRuntimeSnapshot,
47
- PlaybookSession,
48
- PlaybookState,
49
- PlaybookStateValue,
50
- PlaybookTraceEvent,
51
- PlaybookTraceType,
15
+ export type {
52
16
  PlayerResult,
17
+ PlayerCallOptions,
53
18
  PlayerSessionStore,
54
- } from '@sublang/playbook/runtime';
55
-
56
- export type {
57
- CaptainCallOptions,
58
19
  CaptainResult,
20
+ CaptainCallOptions,
59
21
  JsonValue,
60
22
  NormalizedError,
61
- PlayerCallOptions,
62
23
  PlaybookCallRequest,
63
24
  PlaybookCallResult,
64
25
  PlaybookCallStart,
65
- PlaybookControlReceipt,
66
- PlaybookControlView,
26
+ PlaybookStateValue,
27
+ PlaybookState,
67
28
  PlaybookPendingCall,
68
- PlaybookPorts,
69
29
  PlaybookRunResult,
70
30
  PlaybookRuntime,
71
31
  PlaybookRuntimeFactory,
72
32
  PlaybookRuntimeSnapshot,
73
33
  PlaybookSession,
74
- PlaybookState,
75
- PlaybookStateValue,
34
+ PlaybookPorts,
76
35
  PlaybookTraceEvent,
77
36
  PlaybookTraceType,
78
- PlayerResult,
79
- PlayerSessionStore,
80
- };
81
-
82
- export type CodePlaybookOptions = CodingInput;
83
- export type CodePlaybookHostCapabilities =
84
- PlaybookHostConstructionCapabilities &
85
- XStatePlaybookRuntimeConstruction<CodePlaybookOptions, object>['hostCapabilities'];
37
+ PlaybookControlReceipt,
38
+ PlaybookControlView,
39
+ } from '@sublang/playbook/runtime';
86
40
 
87
- const OPTION_KEYS = new Set(['runResults']);
88
- const PLACEHOLDER = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g;
41
+ export interface PlaybookRuntimeOptions {
42
+ readonly "runResults"?: string;
43
+ }
44
+ export type PlaybookHostCapabilities = XStatePlaybookRuntimeConstruction<
45
+ PlaybookRuntimeOptions, { readonly authority: object }
46
+ >['hostCapabilities'];
89
47
 
90
- const VERBATIM_PAYLOAD_FIELDS: ReadonlySet<string> = new Set([
91
- 'coderOutput',
48
+ const OPTION_SCHEMA = {
49
+ "runResults": {
50
+ "type": "string",
51
+ "required": false
52
+ }
53
+ } as const;
54
+ const INPUT_MAPPING = {
55
+ "runResults": "runResults"
56
+ } as const;
57
+ const RESUMABLE_STATE_IDS: ReadonlySet<string> = new Set([
58
+ "firstPhase",
59
+ "irTaskPhase"
92
60
  ]);
93
61
  const UNFINISHED_FINAL_STATE_IDS: ReadonlySet<string> = new Set([
94
- 'reportedReviewFailure',
62
+ "reviewFailed"
95
63
  ]);
96
-
97
- function snapshotCodeOptions(value: unknown): CodePlaybookOptions {
98
- const captured = snapshotJsonValue(value, 'CODE runtime options');
99
- if (
100
- captured === null ||
101
- typeof captured !== 'object' ||
102
- Array.isArray(captured)
103
- ) {
104
- throw new TypeError('CODE runtime options must be an object');
64
+ const VERBATIM_PAYLOAD_FIELDS: ReadonlySet<string> = new Set([
65
+ "coderOutput"
66
+ ]);
67
+ export function validateOptions(value: unknown): PlaybookRuntimeOptions {
68
+ const captured = snapshotJsonValue(value === undefined ? {} : value, "CODE runtime options");
69
+ if (captured === null || typeof captured !== 'object' || Array.isArray(captured)) {
70
+ throw new TypeError("CODE runtime options must be an object");
105
71
  }
106
- const record = captured as Readonly<Record<string, JsonValue>>;
107
- for (const [key, option] of Object.entries(record)) {
108
- if (!OPTION_KEYS.has(key)) {
109
- throw new TypeError(`CODE runtime options.${key} is not declared`);
110
- }
111
- if (typeof option !== 'string') {
112
- throw new TypeError(`CODE runtime options.${key} must be a string`);
72
+ const fields = captured as Readonly<Record<string, unknown>>;
73
+ for (const key of Object.keys(captured)) {
74
+ if (!Object.hasOwn(OPTION_SCHEMA, key)) throw new TypeError("CODE runtime options." + key + ' is not declared');
75
+ }
76
+ for (const [key, schema] of Object.entries(OPTION_SCHEMA) as [string, { type: string; required: boolean }][]) {
77
+ if (!Object.hasOwn(captured, key)) {
78
+ if (schema.required) throw new TypeError("CODE runtime options." + key + ' is required');
79
+ } else if (typeof fields[key] !== schema.type || (schema.type === 'number' && !Number.isFinite(fields[key]))) {
80
+ throw new TypeError("CODE runtime options." + key + ' must be a ' + schema.type);
113
81
  }
114
82
  }
115
- return captured as unknown as CodePlaybookOptions;
116
- }
117
-
118
- function placeholderField(token: string): string {
119
- if (token === '#') return 'irNumber';
120
- return token.replace(/-([A-Za-z0-9_$])/g, (_match, next: string) =>
121
- next.toUpperCase(),
122
- );
83
+ return captured as unknown as PlaybookRuntimeOptions;
123
84
  }
124
-
125
- function quoteContinuation(value: string): string {
126
- return value.replaceAll('\n', '\n> ');
127
- }
128
-
129
- /**
130
- * Preserve authored Markdown quote markers around every line of relayed
131
- * runtime text. The generic composer preserves the marker itself; CODE's
132
- * override additionally keeps a multiline value inside that quote.
133
- */
134
- function composePlayerPrompt(
135
- input: PlayerInput,
136
- promptIdentity: XStatePromptIdentity,
137
- resuming = false,
138
- ): string {
139
- const fields = input as unknown as Record<string, unknown>;
140
- const template = input.prompt
141
- .split('\n')
142
- .filter(
143
- (line) => !(line === '> Run results: <run-results>' && input.runResults.length === 0),
144
- )
145
- .join('\n');
146
- const body = template.replace(
147
- PLACEHOLDER,
148
- (match: string, token: string, offset: number, source: string) => {
149
- const value =
150
- token === 'coder-llm'
151
- ? promptIdentity('coder')
152
- : fields[placeholderField(token)];
85
+ function renderPlayerPrompt(input: SourcePlayerInput, promptIdentity: XStatePromptIdentity, resuming = false): string {
86
+ const fields = input as unknown as Readonly<Record<string, unknown>>;
87
+ const mapping: Readonly<Record<string, string>> = {};
88
+ const identities: Readonly<Record<string, string>> = {"coder-llm":"coder"};
89
+ const omitted = new Set<string>(["> Run results: <run-results>"]);
90
+ const fieldFor = (token: string): string => Object.hasOwn(mapping, token) ? mapping[token]! : (token === '#' ? 'irNumber' : token.replace(/-([A-Za-z0-9_$])/g, (_match: string, next: string) => next.toUpperCase()));
91
+ const parts = input.prompt.split(/(\r?\n)/);
92
+ let body = '';
93
+ for (let index = 0; index < parts.length; index += 2) {
94
+ const line = parts[index]!;
95
+ if (omitted.has(line)) {
96
+ const token = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>$/.exec(line)![1]!;
97
+ if (fields[fieldFor(token)] === '') continue;
98
+ }
99
+ body += line.replace(/<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g, (match: string, token: string): string => {
100
+ const value = Object.hasOwn(identities, token) ? promptIdentity(identities[token]!) : fields[fieldFor(token)];
153
101
  if (typeof value !== 'string') return match;
154
- const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
155
- const literal = source.slice(lineStart, offset);
156
- return literal.startsWith('> ') ? quoteContinuation(value) : value;
157
- },
158
- );
102
+ return line.startsWith('> ') ? value.replace(/\r?\n/g, (ending: string) => ending + '> ') : value;
103
+ }) + (parts[index + 1] ?? '');
104
+ }
159
105
  return composePlayerContinuation(input, body, resuming);
160
106
  }
161
-
162
- export const _internal = {
163
- composePlayerPrompt,
164
- VERBATIM_PAYLOAD_FIELDS,
165
- UNFINISHED_FINAL_STATE_IDS,
166
- };
167
-
107
+ const composePlayerPrompt = (input: PlaybookPlayerInput, promptIdentity: XStatePromptIdentity, resuming?: boolean): string =>
108
+ renderPlayerPrompt(input as SourcePlayerInput, promptIdentity, resuming);
168
109
  const runtimeSpec = {
169
- label: 'CODE',
170
- // DR-022 / slc/link.md: the declaration carries the value current at link
171
- // time — a literal, never the loading engine's RUNTIME_ABI self-report,
172
- // which would follow whatever engine loads the module and make the
173
- // factory's skew check compare that engine with itself.
174
- compat: { artifactSchema: 3, runtimeAbi: 1 },
175
- snapshotOptions: snapshotCodeOptions,
176
- entryEvent: {
177
- type: 'START_CODE',
178
- textField: 'callerInput',
179
- // `startCoding` copies the entry text here, so the failure-state retry
180
- // reads it back from the persisted machine snapshot and survives a
181
- // continued session (DR-034).
182
- contextField: 'callerInput',
110
+ composePlayerPrompt,
111
+ ...{
112
+ "label": "CODE",
113
+ "compat": {
114
+ "artifactSchema": 3,
115
+ "runtimeAbi": 1
183
116
  },
184
- roleStates: {
185
- runFirstPhase: {
186
- role: 'coder',
187
- label:
188
- 'Coder is running the first coding phase: a direct implementation, a new intent record, or an existing intent-record task.',
189
- },
190
- runIrTask: {
191
- role: 'coder',
192
- label: 'Coder is implementing exactly one unfinished intent-record task.',
117
+ "entryEvent": {
118
+ "type": "START_CODE",
119
+ "textField": "callerInput",
120
+ "contextField": "callerInput"
121
+ },
122
+ "bossEvents": [],
123
+ "roleStates": {
124
+ "firstPhase": {
125
+ "role": "coder",
126
+ "label": "Coder runs the first coding phase: a direct implementation, a new IR, or the next task of an existing IR."
193
127
  },
128
+ "irTaskPhase": {
129
+ "role": "coder",
130
+ "label": "Coder implements the identified IR's next unfinished task."
131
+ }
194
132
  },
195
- outcomeAuthority: {
196
- governedPlayerStates: {
197
- runFirstPhase: {
198
- directCommit: {
199
- fields: {
200
- coderOutput: 'presentation',
201
- latestCommit: 'effect',
133
+ "outcomeAuthority": {
134
+ "governedPlayerStates": {
135
+ "firstPhase": {
136
+ "directCommit": {
137
+ "fields": {
138
+ "coderOutput": "presentation",
139
+ "latestCommit": "effect"
202
140
  },
203
- repositoryDisposition: 'one-descendant-commit',
141
+ "repositoryDisposition": "one-descendant-commit"
204
142
  },
205
- irCommit: {
206
- fields: {
207
- coderOutput: 'presentation',
208
- latestCommit: 'effect',
209
- irNumber: 'semantic',
143
+ "irCommit": {
144
+ "fields": {
145
+ "coderOutput": "presentation",
146
+ "latestCommit": "effect",
147
+ "irNumber": "semantic"
210
148
  },
211
- repositoryDisposition: 'one-descendant-commit',
149
+ "repositoryDisposition": "one-descendant-commit"
212
150
  },
213
- moreTasks: {
214
- fields: {
215
- coderOutput: 'presentation',
216
- latestCommit: 'effect',
217
- irNumber: 'semantic',
218
- irTask: 'semantic',
151
+ "moreTasks": {
152
+ "fields": {
153
+ "coderOutput": "presentation",
154
+ "latestCommit": "effect",
155
+ "irNumber": "semantic",
156
+ "irTask": "semantic"
219
157
  },
220
- repositoryDisposition: 'one-descendant-commit',
158
+ "repositoryDisposition": "one-descendant-commit"
221
159
  },
222
- finalTask: {
223
- fields: {
224
- coderOutput: 'presentation',
225
- latestCommit: 'effect',
226
- irNumber: 'semantic',
227
- irTask: 'semantic',
160
+ "finalTask": {
161
+ "fields": {
162
+ "coderOutput": "presentation",
163
+ "latestCommit": "effect",
164
+ "irNumber": "semantic",
165
+ "irTask": "semantic"
228
166
  },
229
- repositoryDisposition: 'one-descendant-commit',
230
- },
231
- needsBossReply: {
232
- fields: { question: 'presentation' },
233
- repositoryDisposition: 'deferred',
167
+ "repositoryDisposition": "one-descendant-commit"
234
168
  },
169
+ "needsBossReply": {
170
+ "fields": {
171
+ "question": "presentation"
172
+ },
173
+ "repositoryDisposition": "deferred"
174
+ }
235
175
  },
236
- runIrTask: {
237
- moreTasks: {
238
- fields: {
239
- coderOutput: 'presentation',
240
- latestCommit: 'effect',
241
- irNumber: 'semantic',
242
- irTask: 'semantic',
176
+ "irTaskPhase": {
177
+ "moreTasks": {
178
+ "fields": {
179
+ "coderOutput": "presentation",
180
+ "latestCommit": "effect",
181
+ "irNumber": "semantic",
182
+ "irTask": "semantic"
243
183
  },
244
- repositoryDisposition: 'one-descendant-commit',
184
+ "repositoryDisposition": "one-descendant-commit"
245
185
  },
246
- finalTask: {
247
- fields: {
248
- coderOutput: 'presentation',
249
- latestCommit: 'effect',
250
- irNumber: 'semantic',
251
- irTask: 'semantic',
186
+ "finalTask": {
187
+ "fields": {
188
+ "coderOutput": "presentation",
189
+ "latestCommit": "effect",
190
+ "irNumber": "semantic",
191
+ "irTask": "semantic"
252
192
  },
253
- repositoryDisposition: 'one-descendant-commit',
193
+ "repositoryDisposition": "one-descendant-commit"
254
194
  },
255
- needsBossReply: {
256
- fields: { question: 'presentation' },
257
- repositoryDisposition: 'deferred',
258
- },
259
- },
260
- },
195
+ "needsBossReply": {
196
+ "fields": {
197
+ "question": "presentation"
198
+ },
199
+ "repositoryDisposition": "deferred"
200
+ }
201
+ }
202
+ }
261
203
  },
262
- composePlayerPrompt: (
263
- input: PlaybookPlayerInput,
264
- promptIdentity: XStatePromptIdentity,
265
- resuming?: boolean,
266
- ) => composePlayerPrompt(input as PlayerInput, promptIdentity, resuming),
204
+ "placeholderFields": {},
205
+ "transitionEventFields": [
206
+ "callerInput",
207
+ "runResults",
208
+ "targetId",
209
+ "answer",
210
+ "questionId"
211
+ ],
212
+ "controlContextFields": [
213
+ "phaseOutcome",
214
+ "irNumber",
215
+ "codeCommit",
216
+ "evaluatedRevision"
217
+ ]
218
+ },
219
+ snapshotOptions: validateOptions,
220
+ machineInput: (options: PlaybookRuntimeOptions) => Object.fromEntries(
221
+ Object.entries(INPUT_MAPPING).filter(([, key]) => options[key as keyof PlaybookRuntimeOptions] !== undefined)
222
+ .map(([field, key]) => [field, options[key as keyof PlaybookRuntimeOptions]]),
223
+ ),
267
224
  verbatimPayloadFields: VERBATIM_PAYLOAD_FIELDS,
268
- controlContextFields: ['phase'],
225
+ resumableStateIds: RESUMABLE_STATE_IDS,
269
226
  unfinishedFinalStateIds: UNFINISHED_FINAL_STATE_IDS,
270
- transitionEventFields: ['callerInput', 'answer', 'questionId'],
271
- } satisfies XStatePlaybookRuntimeSpecV3<CodePlaybookOptions>;
227
+ } satisfies XStatePlaybookRuntimeSpecV3<PlaybookRuntimeOptions>;
272
228
 
229
+ export const _internal = {
230
+ composePlayerPrompt,
231
+ RESUMABLE_STATE_IDS,
232
+ UNFINISHED_FINAL_STATE_IDS,
233
+ VERBATIM_PAYLOAD_FIELDS,
234
+ };
273
235
  const createPlaybookRuntime: XStatePlaybookRuntimeFactory<
274
- XStatePlaybookRuntimeConstruction<
275
- CodePlaybookOptions,
276
- CodePlaybookHostCapabilities
277
- >,
278
- 3
279
- > = createXStatePlaybookRuntime<
280
- CodePlaybookOptions,
281
- CodePlaybookHostCapabilities
282
- >(
283
- codingMachine,
284
- runtimeSpec,
285
- );
286
-
236
+ XStatePlaybookRuntimeConstruction<PlaybookRuntimeOptions, PlaybookHostCapabilities>, 3
237
+ > = createXStatePlaybookRuntime<PlaybookRuntimeOptions, PlaybookHostCapabilities>(machine, runtimeSpec);
287
238
  export default createPlaybookRuntime;
@@ -1,4 +1,5 @@
1
- import { type CodePlaybookHostCapabilities, type PlaybookRuntime } from './code.playbook.js';
1
+ import { type PlaybookHostCapabilities, type PlaybookRuntime } from './code.playbook.js';
2
+ import type { PlaybookHostConstructionCapabilities } from './playbook-captain.js';
2
3
  export interface PlaybookSummaryPolicy {
3
4
  stateCountLabels: Readonly<Record<string, string>>;
4
5
  copyPasteGuardNames: readonly string[];
@@ -24,7 +25,7 @@ export interface CodePlaybookRegistryEntry {
24
25
  concurrentRoleSets: readonly [];
25
26
  summaryPolicy: PlaybookSummaryPolicy;
26
27
  validateOptions(optionSlice: unknown): CodeOptions;
27
- createRuntime(options: CodeOptions, hostCapabilities: CodePlaybookHostCapabilities): PlaybookRuntime;
28
+ createRuntime(options: CodeOptions, hostCapabilities: PlaybookHostConstructionCapabilities & PlaybookHostCapabilities): PlaybookRuntime;
28
29
  }
29
30
  export declare const codeStateCountLabels: {};
30
31
  export declare const codeCopyPasteGuardNames: readonly ["directCommit", "irCommit", "moreTasks", "finalTask"];
@@ -2,9 +2,10 @@
2
2
  // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
3
 
4
4
  import createPlaybookRuntime, {
5
- type CodePlaybookHostCapabilities,
5
+ type PlaybookHostCapabilities,
6
6
  type PlaybookRuntime,
7
7
  } from './code.playbook.js';
8
+ import type { PlaybookHostConstructionCapabilities } from './playbook-captain.js';
8
9
 
9
10
  export interface PlaybookSummaryPolicy {
10
11
  stateCountLabels: Readonly<Record<string, string>>;
@@ -33,9 +34,12 @@ export interface CodePlaybookRegistryEntry {
33
34
  concurrentRoleSets: readonly [];
34
35
  summaryPolicy: PlaybookSummaryPolicy;
35
36
  validateOptions(optionSlice: unknown): CodeOptions;
37
+ // The linked module types live authority as opaque (link-materialization);
38
+ // the Captain entry binds its own construction capabilities here.
36
39
  createRuntime(
37
40
  options: CodeOptions,
38
- hostCapabilities: CodePlaybookHostCapabilities,
41
+ hostCapabilities: PlaybookHostConstructionCapabilities &
42
+ PlaybookHostCapabilities,
39
43
  ): PlaybookRuntime;
40
44
  }
41
45
 
@@ -86,6 +86,7 @@ export interface PlaybookEffectBoundary {
86
86
  readonly baseline: PlaybookRepositoryObservation;
87
87
  readonly after?: PlaybookRepositoryObservation;
88
88
  readonly physicalReceipt?: PlaybookRepositoryReceipt;
89
+ readonly restored?: PlaybookRepositoryObservation;
89
90
  readonly finalText?: string;
90
91
  readonly semanticCandidate?: JsonValue;
91
92
  readonly initialSemanticCandidate?: JsonValue;
@@ -103,6 +104,7 @@ export type PlaybookEffectBoundaryStart = Omit<
103
104
  | 'attemptNumber'
104
105
  | 'after'
105
106
  | 'physicalReceipt'
107
+ | 'restored'
106
108
  | 'finalText'
107
109
  | 'semanticCandidate'
108
110
  | 'initialSemanticCandidate'
@@ -278,6 +280,7 @@ export interface HostCapabilities {
278
280
  readonly effectLedger: PlaybookEffectLedgerCapability;
279
281
  }
280
282
  export interface WorktreeRepositoryCapability extends RepositoryCapability {
283
+ acquire(options?: { signal?: AbortSignal }): Promise<{ assertOwner(): Promise<void>; release(): Promise<void> }>;
281
284
  readonly identity: RepositoryIdentity;
282
285
  observe(): Promise<PlaybookRepositoryObservation>;
283
286
  }
@@ -1,6 +1,6 @@
1
1
  import { type Captain, type CaptainSession, type TuningSelection } from '@sublang/cligent/tmux-play';
2
2
  import type { Effort, PermissionPolicy } from '@sublang/cligent';
3
- import type { JsonValue, PlaybookEffectLedger, PlaybookEffectLedgerCommandBatch, PlaybookControlAction, PlaybookFailureCause, PlaybookRuntime, PlaybookRuntimeSnapshot } from '@sublang/playbook/runtime';
3
+ import type { JsonValue, PlaybookEffectLedger, PlaybookEffectLedgerCommandBatch, PlaybookControlAction, PlaybookFailureCause, PlaybookRuntime, PlaybookRuntimeSnapshot, PlaybookStepRecord } from '@sublang/playbook/runtime';
4
4
  import { type CaptainControllerPort } from '../captain.playbook/captain.playbook.js';
5
5
  import type { PlaybookSummaryPolicy } from './code.registry.js';
6
6
  interface SessionAgent {
@@ -34,7 +34,24 @@ interface PlaybookCaptainUnresolvedEffectSettlementInput {
34
34
  }
35
35
  type SnapshotAgentEnvelope = DeepReadonly<Omit<SessionAgent, 'model' | 'effort' | 'fastMode'>>;
36
36
  type PlayerLedgerSnapshotEntry = DeepReadonly<PlayerLedgerEntry>;
37
+ export interface ProgressChange {
38
+ snapshot?: PlaybookCaptainShellSnapshot | null;
39
+ step?: Omit<PlaybookStepRecord, 'kind'> & {
40
+ kind: PlaybookStepRecord['kind'] | 'preparation' | 'completion' | 'answer';
41
+ runtimeSessionId: string;
42
+ playbookId: string;
43
+ };
44
+ }
45
+ export interface InterruptedReport {
46
+ text: string;
47
+ effects: readonly PlaybookCaptainUnresolvedEffect[];
48
+ retentionUpdates?: readonly PlaybookCaptainRetentionUpdate[];
49
+ unresolvedEffects?: readonly PlaybookCaptainUnresolvedEffect[];
50
+ }
37
51
  export interface PlaybookCaptainDeps {
52
+ /** Stop the host's active turn, including admitted tool calls, on preparation expiry or a required save failure. */
53
+ abortPreparation?: (reason?: string) => void;
54
+ recordProgress?: (change: ProgressChange) => Promise<void>;
38
55
  continuity?: {
39
56
  beforeCall(participantId: string): Promise<void>;
40
57
  acknowledged(participantId: string, token: string): void;
@@ -137,6 +154,8 @@ export interface PlaybookCaptainFrameSnapshot {
137
154
  readonly depth: number;
138
155
  readonly parentSessionId?: string;
139
156
  readonly parentCallId?: string;
157
+ readonly request?: string;
158
+ readonly inputs?: readonly string[];
140
159
  readonly options: JsonValue;
141
160
  readonly roleBindings: Readonly<Record<string, string>>;
142
161
  readonly runtime: DeepReadonly<PlaybookRuntimeSnapshot>;
@@ -144,6 +163,7 @@ export interface PlaybookCaptainFrameSnapshot {
144
163
  interface PlaybookCaptainShellSnapshotFields {
145
164
  readonly schemaVersion: 4;
146
165
  readonly effectLedger: DeepReadonly<PlaybookEffectLedger>;
166
+ readonly presentedEffectPrefix?: number;
147
167
  readonly captain: {
148
168
  readonly sessionId: string;
149
169
  readonly runtime: DeepReadonly<PlaybookRuntimeSnapshot>;
@@ -158,7 +178,7 @@ interface PlaybookCaptainShellSnapshotFields {
158
178
  readonly journal: number;
159
179
  };
160
180
  readonly journal: readonly PlaybookCaptainJournalRecord[];
161
- readonly lastAction?: 'respond' | 'start' | 'switch' | 'resume' | 'dismiss' | 'deliver' | 'runtime';
181
+ readonly lastAction?: 'respond' | 'start' | 'switch' | 'resume' | 'dismiss' | 'deliver' | 'runtime' | 'recover';
162
182
  readonly lastSettlementStatus?: 'ok' | 'rejected' | 'failed';
163
183
  }
164
184
  /**
@@ -242,9 +262,61 @@ export interface PlaybookCaptainShell extends Captain {
242
262
  * `handleBossTurn` (CAPTAIN-7).
243
263
  */
244
264
  submitShellAction?(actionId: string): string;
265
+ /** Report an interrupted attempt without dispatching work. */
266
+ selectInterruptedReport?(input: string, report: InterruptedReport): void;
267
+ }
268
+ /**
269
+ * Whether words may stand outside a code span in a statement the shell says
270
+ * (CAPTAIN-9); the pure renderer accepts everything, and the shell passes its
271
+ * guard.
272
+ */
273
+ type Speakable = (text: string) => boolean;
274
+ /**
275
+ * What the shell recorded of a failure: an error, which may carry the cause
276
+ * the runtime decided (DR-063 §2), or that cause alone.
277
+ */
278
+ interface RecordedFailure {
279
+ readonly message?: string;
280
+ readonly cause?: unknown;
245
281
  }
282
+ type DescribePlaybook = (playbookId: string) => string;
283
+ /**
284
+ * CAPTAIN-71: the one way a failure is put into words — `<Subject> failed:
285
+ * <reason>.` — `subject` naming what failed in the Boss's words and `failure`
286
+ * the error or cause the shell recorded.
287
+ */
288
+ declare function failureStatement(subject: string, failure: RecordedFailure | undefined, describePlaybook?: DescribePlaybook, speakable?: Speakable): string;
289
+ /**
290
+ * The three kinds of statement a report the shell says holds (CAPTAIN-69):
291
+ * a listed fact, a numbered unresolved-effect entry, and the `Failure:` line.
292
+ */
293
+ type StatementKind = 'fact' | 'entry' | 'failure';
294
+ /** A statement the report assembly weighs. */
295
+ interface BossStatement {
296
+ readonly text: string;
297
+ /** Its kind, which decides what may drop it; a fact where absent. */
298
+ readonly kind?: StatementKind;
299
+ /** The reason a `Failure:` line states (CAPTAIN-67). */
300
+ readonly reason?: string;
301
+ }
302
+ /** The statements of `statements` that stay, as CAPTAIN-69 assembles them. */
303
+ declare function bossReport(statements: readonly (string | BossStatement)[], reasons?: Iterable<string>): string[];
246
304
  export declare function assertPlaybookCaptainUnresolvedEffects(value: unknown): readonly PlaybookCaptainUnresolvedEffect[];
247
305
  /** Validate, detach, and freeze one untrusted shell snapshot. */
248
306
  export declare function assertPlaybookCaptainShellSnapshot(value: unknown): PlaybookCaptainShellSnapshot;
307
+ export type PlaybookCaptainUnresolvedEffectReference = {
308
+ readonly kind: 'boundary';
309
+ readonly boundaryId: string;
310
+ } | {
311
+ readonly kind: 'logical-operation';
312
+ readonly operationId: string;
313
+ };
314
+ export declare const projectUnresolvedEffects: (ledger: PlaybookEffectLedger, references: readonly PlaybookCaptainUnresolvedEffectReference[]) => readonly PlaybookCaptainUnresolvedEffect[];
249
315
  export declare function createPlaybookCaptainShell(options: unknown, deps?: PlaybookCaptainDeps): PlaybookCaptainShell;
316
+ export declare const _internal: {
317
+ failureStatement: typeof failureStatement;
318
+ bossReport: typeof bossReport;
319
+ RUNTIME_REASON_PHRASES: Readonly<Record<string, string>>;
320
+ LABELLED_RUNTIME_REASONS: readonly (readonly [RegExp, string])[];
321
+ };
250
322
  export default createPlaybookCaptainShell;