@sublang/playbook 0.9.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +190 -151
  2. package/package.json +50 -6
  3. package/reference/sdlc/captain.md +102 -0
  4. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +227 -0
  5. package/reference/sdlc/captain.playbook/captain.fsm.js +628 -0
  6. package/reference/sdlc/captain.playbook/captain.fsm.ts +851 -0
  7. package/reference/sdlc/captain.playbook/captain.gears.md +60 -0
  8. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +23 -0
  9. package/reference/sdlc/captain.playbook/captain.playbook.js +1053 -0
  10. package/reference/sdlc/captain.playbook/captain.playbook.ts +1144 -0
  11. package/reference/sdlc/code.playbook/bin/playbook.js +158 -12
  12. package/reference/sdlc/code.playbook/bin/run.js +999 -0
  13. package/reference/sdlc/code.playbook/code.fsm.d.ts +11 -4
  14. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +2 -2
  15. package/reference/sdlc/code.playbook/code.fsm.introspect.js +1 -1
  16. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +6 -6
  17. package/reference/sdlc/code.playbook/code.fsm.js +334 -102
  18. package/reference/sdlc/code.playbook/code.fsm.ts +467 -180
  19. package/reference/sdlc/code.playbook/code.gears.md +11 -10
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +16 -19
  21. package/reference/sdlc/code.playbook/code.playbook.js +199 -488
  22. package/reference/sdlc/code.playbook/code.playbook.ts +327 -566
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +0 -3
  24. package/reference/sdlc/code.playbook/code.registry.js +0 -3
  25. package/reference/sdlc/code.playbook/code.registry.ts +0 -6
  26. package/reference/sdlc/code.playbook/playbook-captain.d.ts +9 -4
  27. package/reference/sdlc/code.playbook/playbook-captain.js +889 -210
  28. package/reference/sdlc/code.playbook/playbook-captain.ts +1136 -257
  29. package/reference/sdlc/code.playbook/playbook.config.template.yaml +21 -0
  30. package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +396 -0
  31. package/reference/sdlc/discuss.playbook/discuss.fsm.js +2066 -0
  32. package/reference/sdlc/discuss.playbook/discuss.fsm.ts +2464 -0
  33. package/reference/sdlc/discuss.playbook/discuss.gears.md +251 -0
  34. package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +113 -0
  35. package/reference/sdlc/discuss.playbook/discuss.playbook.js +1514 -0
  36. package/reference/sdlc/discuss.playbook/discuss.playbook.ts +1926 -0
  37. package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +58 -0
  38. package/reference/sdlc/discuss.playbook/discuss.registry.js +97 -0
  39. package/reference/sdlc/discuss.playbook/discuss.registry.ts +153 -0
  40. package/slc/gears2fsm.md +557 -57
  41. package/slc/link.md +1165 -89
  42. package/slc/optimize.md +92 -0
  43. package/slc/text2gears.md +255 -7
  44. package/src/runtime.d.ts +146 -3
  45. package/src/runtime.ts +201 -2
  46. package/src/xstate-playbook-runtime.d.ts +201 -0
  47. package/src/xstate-playbook-runtime.js +2058 -0
  48. package/src/xstate-playbook-runtime.ts +2792 -0
  49. package/src/xstate-runtime.d.ts +95 -0
  50. package/src/xstate-runtime.js +1258 -0
  51. package/src/xstate-runtime.ts +1816 -0
@@ -0,0 +1,92 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
3
+
4
+ # GEARS Optimization Pass
5
+
6
+ Optional optimization pass of a playbook (a state-machine agent orchestrating other agents).
7
+ Rewrites deterministic mechanical behaviors into
8
+ [script behaviors](text2gears.md#script-behaviors-optimizer-introduced) so the
9
+ compiled playbook performs them directly, without an agent call.
10
+
11
+ - Source: a package of GEARS spec items produced by [text2gears](text2gears.md).
12
+ - Target: the same package with eligible items rewritten as script items.
13
+
14
+ The pass is format-preserving: source and target are both GEARS packages, and
15
+ the pass sits between [text2gears](text2gears.md) and
16
+ [gears2fsm](gears2fsm.md) only when the compile requests optimization.
17
+ A playbook compiled without this pass has identical observable behavior; the
18
+ pass trades a compile-time rewrite for cheaper, deterministic runtime steps.
19
+
20
+ ## Formats
21
+
22
+ | Role | Format | Extension |
23
+ | ------ | ------ | --------- |
24
+ | source | gears | .md |
25
+ | target | gears | .md |
26
+
27
+ ## Eligibility
28
+
29
+ The pass shall rewrite an item only when **all** of the following hold:
30
+
31
+ - The item's behavior is mechanical: a fixed shell command performs it
32
+ completely, with no judgment, no natural-language generation, and no
33
+ reading of conversational context.
34
+ - The command is static: it needs no `<placeholder>` and no runtime value
35
+ beyond the working directory the runtime executes in.
36
+ - No other item's condition or prompt consumes prose this item's acting agent
37
+ would have produced; the item's effect is entirely on the environment
38
+ (files, repository state, directories) plus a success/failure signal.
39
+ - The item's outcome contract collapses to a two-way split decidable by the
40
+ command's exit status. An item whose declared `Results:` distinguish more
41
+ than success/failure, or whose outcomes require extracted output fields,
42
+ is ineligible.
43
+
44
+ The canonical example is environment setup, such as ensuring the working
45
+ directory is a version-control repository before committing to it:
46
+ `git rev-parse --is-inside-work-tree 2>/dev/null || git init`.
47
+
48
+ Judgment stays conservative: when eligibility is uncertain, the pass shall
49
+ leave the item unchanged rather than guess.
50
+ The pass shall not invent items, commands stronger than the item's stated
51
+ behavior, or requirements the source does not state.
52
+
53
+ ## Rewriting
54
+
55
+ For each eligible item, the pass shall:
56
+
57
+ - Keep the item's ID, heading form, and condition text unchanged.
58
+ - Replace the acting clause with the literal script form `Captain shall run:`.
59
+ Like guard names, the script clause is fixed machine syntax [[1]] and
60
+ stays in this exact English form even when the surrounding item text is
61
+ in another language.
62
+ - Replace the blockquoted prompt with the exact POSIX shell script that
63
+ performs the behavior, static text only.
64
+ - Emit exactly two `Results:` bullets per
65
+ [text2gears "Script behaviors"](text2gears.md#script-behaviors-optimizer-introduced):
66
+ first the zero-exit guard, then the nonzero-exit guard. When the original
67
+ item declared exactly two guards that align with success and failure, keep
68
+ those guard names in that order; otherwise use `ok` and `failed`.
69
+ - Preserve every other item and every non-item section byte-for-byte.
70
+
71
+ Target shall be written in the same language as Source: rewritten conditions
72
+ and result descriptions stay in the source language; only guard names and the
73
+ shell script are language-independent.
74
+
75
+ ## Provenance
76
+
77
+ The pass shall append one `## Optimizations` section at the end of the target
78
+ listing every rewritten item, one bullet per item:
79
+ `- <ITEM-ID>: <original behavior kind> → script`.
80
+ When no item is eligible, the target shall be the source content unchanged,
81
+ with no `## Optimizations` section.
82
+
83
+ ## Out of scope
84
+
85
+ - Rewriting captain, player, or nested-playbook behaviors into one another.
86
+ - Reordering, merging, splitting, or deleting items.
87
+ - Any change to prompts, conditions, or result contracts of items the pass
88
+ does not rewrite.
89
+
90
+ ## References
91
+
92
+ [1]: GEARS definition shipped by the installed `@sublang/spex` package: `@sublang/spex/scaffold/specs/meta.md` (English) and `@sublang/spex/scaffold/i18n/zh/specs/meta.md` (Chinese); canonical renditions [GEARS: AI-Ready Spec Syntax](https://sublang.ai/ref/gears-ai-ready-spec-syntax) (en) and [GEARS:面向 AI 的规约语法](https://sublang.ai/zh/ref/gears-ai-ready-spec-syntax) (zh)
package/slc/text2gears.md CHANGED
@@ -13,10 +13,10 @@ The second phase (spec items → state machine) is out of scope.
13
13
 
14
14
  ## Formats
15
15
 
16
- | Role | Format | Extension |
17
- | --- | --- | --- |
18
- | source | text | .md |
19
- | target | gears | .md |
16
+ | Role | Format | Extension |
17
+ | ------ | ------ | --------- |
18
+ | source | text | .md |
19
+ | target | gears | .md |
20
20
 
21
21
  ## Players
22
22
 
@@ -39,8 +39,50 @@ Capitalize English player names (e.g., `Writer`); quote non-English names (e.g.,
39
39
 
40
40
  ## Behaviors
41
41
 
42
- Each spec item names a condition, the player to prompt, and the prompt itself.
42
+ Each spec item names a condition, one behavior kind, and the complete prompt
43
+ for that behavior.
44
+ Every emitted item shall use the exact Markdown heading form `### <ITEM-ID>`.
45
+ An item heading at `##`, `####`, or another level is not GEARS item syntax and
46
+ will not be visible to downstream compilers or verification.
47
+ The behavior kind shall be one of:
48
+
49
+ - direct Captain work, written `Captain shall <behavior>:` without naming a
50
+ delegated player;
51
+ - delegated player work, written `Captain shall prompt <Player>:` or the
52
+ existing `Captain shall relay ... to <Player> ...:` form; or
53
+ - a literal or dynamic nested playbook call as defined below.
54
+
55
+ Direct Captain work means the coordinating Captain performs the behavior
56
+ itself. It shall not be rewritten as `Captain shall prompt Captain`, because
57
+ Captain is a distinct runtime actor rather than a player binding.
58
+ Delegated work shall name the declared player that receives the prompt.
43
59
  Prompts shall be blockquoted, one point per line.
60
+ When Source already supplies the complete blockquoted acting prompt for a
61
+ behavior, text2gears shall preserve those prompt lines exactly (apart from the
62
+ documented Markdown unescaping) and shall not promote surrounding conditions,
63
+ invariants, result fields, or continuation mechanics into that blockquote.
64
+ Those requirements remain in the item's condition or `Results:` metadata.
65
+ Adding control-oriented prompt lines merely to restate them changes the
66
+ Boss-visible contract and is nonconformant.
67
+
68
+ Source statements that assign active-leaf routing, call identity, suspension,
69
+ or return matching to the host describe execution preconditions rather than
70
+ behaviors for Captain to perform. text2gears shall use such a statement only as
71
+ a condition on an actual behavior when needed and shall not emit a standalone
72
+ direct-Captain item that asks Captain to implement host stack bookkeeping.
73
+ The same applies to a host-owned input catalog's immutability: retain it as a
74
+ condition/invariant on the behaviors that consume the catalog, never as an LLM
75
+ action that can replace or mutate host configuration.
76
+ Opening source invariants consumed by later behaviors shall remain explicit in
77
+ the emitted conditions or prompts rather than being summarized away. In
78
+ particular, preserve the declared exact entry shape of a structured host
79
+ catalog and any progress invariant that makes a decide-call-observe plan
80
+ finite, such as `remainingPlan` containing only calls after the selected call
81
+ and strictly shrinking on continuation.
82
+ Likewise, a source invariant that restricts a nested-call target to a
83
+ non-empty member of an input catalog is a condition on that call item, not a
84
+ separate Captain rejection behavior, unless Source requires an observable
85
+ response distinct from taking or skipping the call.
44
86
 
45
87
  E.g.:
46
88
 
@@ -48,13 +90,217 @@ E.g.:
48
90
  ### CODE-10
49
91
 
50
92
  When Reviewer is about to review any change, Captain shall prompt Reviewer:
93
+
51
94
  > Flag any issues or improvements (numbered; no duplication).
52
95
  > Think thoroughly — don't just approve or reject.
53
96
  > If the change is ready to commit or push, don't raise nitpicks.
54
97
  > Do not edit files or commit; report findings only.
55
98
  ```
56
99
 
57
- Target should be written in the same language as Source.
100
+ Direct Captain example:
101
+
102
+ ```markdown
103
+ ### ROUTE-1
104
+
105
+ When Boss gives an intent, Captain shall decide how to handle it:
106
+
107
+ > Preserve Boss's intended outcome and constraints.
108
+ > Ask one question only when its answer would materially change routing.
109
+ ```
110
+
111
+ ### Result contracts
112
+
113
+ When Source gives an acting behavior more than one possible outcome,
114
+ text2gears shall emit its machine-facing result contract immediately after the
115
+ complete blockquote, outside the acting prompt, in this exact form:
116
+
117
+ ```markdown
118
+ Results:
119
+ - `question`: Captain asked one material question. Output shall include `question: <verbatim final text>`.
120
+ - `delegation`: Captain selected a call. Output shall include `remainingPlan: <JSON-safe array>`, `nextPlaybookId: <stable id>`, and `nextPlaybookInput: <complete request>`.
121
+ ```
122
+
123
+ `Results:` shall be a plain label rather than a heading.
124
+ Every result shall occupy one bullet with exactly a backtick-delimited guard
125
+ name, a colon, and a non-empty description.
126
+ The guard name shall match the ASCII identifier pattern
127
+ `[A-Za-z_$][A-Za-z0-9_$]*`.
128
+ The bullet order is authoritative, guard names are unique within the item, and
129
+ the description shall name every required output property with its exact
130
+ case-sensitive identifier.
131
+
132
+ A produced value consumed later shall have a declared producer: where any
133
+ later item's blockquote reads a value through a `<placeholder>`, the item
134
+ whose behavior produces that value shall declare the `Results:` contract
135
+ whose relevant description names the produced output property, using the
136
+ placeholder's exact identifier — this is what lets the FSM thread the value
137
+ through typed context.
138
+ A single-outcome producer then declares exactly one bullet naming the
139
+ property; this consumed-output case is the sole one in which a
140
+ single-outcome behavior carries a `Results:` label.
141
+
142
+ Result metadata is compiler control data, not part of the acting agent's
143
+ prompt.
144
+ text2gears shall not put guard names, result-property schema, JSON control
145
+ instructions, or adjudicator instructions inside the blockquote unless Source
146
+ explicitly requires the acting agent to show that machine syntax to the user.
147
+ It shall move Source's outcome contract into `Results:` while preserving the
148
+ human domain instructions in the blockquote.
149
+ It shall not emit the framework-owned `needsBossReply` result; gears2fsm adds
150
+ that universal result for every Captain- or player-invoking state.
151
+
152
+ Where Source restricts an initial Captain to routing, text2gears shall preserve
153
+ only the authored question and delegation outcomes and shall not infer a
154
+ direct-answer or terminal result merely because Captain is the acting agent.
155
+
156
+ A single-outcome behavior whose output no later item consumes carries no
157
+ `Results:` label; downstream,
158
+ [gears2fsm](gears2fsm.md#setup) gives its state the default single-outcome
159
+ contract, so text2gears shall not invent a one-bullet `Results:` block for it.
160
+ When a later item does consume its output, the produced-value rule above
161
+ applies instead.
162
+
163
+ ### Boss-reply continuation
164
+
165
+ Where a direct-Captain or delegated-player behavior may ask Boss a question
166
+ and wait, Boss's answer resumes that same behavior with continuation context;
167
+ it is not a distinct behavior item. text2gears shall keep the question result,
168
+ the wait, and the answer-dependent continuation on the originating item even
169
+ when the answer changes its complete runtime prompt. It shall not emit a
170
+ second item solely for "Boss answers," "after the question," or clearing the
171
+ consumed question/reply. The FSM and linker own the same-leaf suspension,
172
+ continuation blocks, and consumed-context cleanup.
173
+
174
+ This rule is an exception to splitting by accumulated prompt content below.
175
+ Split only when Source requires a genuinely different acting behavior after
176
+ the reply, not when the same decision or task continues with Boss's answer.
177
+
178
+ The same consolidation applies when Source says a fresh directive interrupts
179
+ parked work and *restarts the same behavior* with cleared context. When the
180
+ acting prompt and result contract are identical, retain the interrupt as an
181
+ entry condition on the originating item; do not duplicate that item solely to
182
+ describe the restart. Split only when the fresh directive invokes genuinely
183
+ different acting work or a different prompt/result contract.
184
+
185
+ ### Parallel behaviors
186
+
187
+ Where two or more delegated-player items share one trigger and Source requires
188
+ them to run independently before later work uses all results, text2gears shall
189
+ place `Parallel group: <stable-kebab-case-id>` immediately below each item
190
+ heading.
191
+ Every item in one parallel group shall receive the same completed-prior-group
192
+ inputs; no item prompt may depend on another member's result from the current
193
+ group.
194
+ Every member shall delegate to a named player, and the source shall permit
195
+ those members to resolve to distinct players. Direct-Captain work shares one
196
+ Captain session and nested calls share one pending-child stack slot, so neither
197
+ kind may receive parallel-group metadata. If Source explicitly requires either
198
+ unsupported kind to run concurrently, text2gears shall report that the source
199
+ cannot be represented rather than silently serialize it or emit metadata the
200
+ next phase cannot compile.
201
+
202
+ Example:
203
+
204
+ ```markdown
205
+ ### DISCUSS-1
206
+
207
+ Parallel group: initial-proposals
208
+
209
+ When Boss gives a topic, Captain shall prompt Host:
210
+
211
+ > Propose your design independently.
212
+ ```
213
+
214
+ ### Nested playbook calls
215
+
216
+ Where Source requires one playbook to call a statically known playbook,
217
+ text2gears shall emit an item whose behavior uses
218
+ `Captain shall call playbook <playbook-id>:` and whose blockquote is the
219
+ complete JSON-safe input-text template for that call.
220
+ The literal target id shall be a stable configured playbook id, not a slash
221
+ command or module specifier.
222
+
223
+ Example:
224
+
225
+ ```markdown
226
+ ### RELEASE-8
227
+
228
+ When implementation is ready for review, Captain shall call playbook `code-review`:
229
+
230
+ > Review these changes:
231
+ > <changes>
232
+ ```
233
+
234
+ Where Source selects the target at runtime, text2gears shall instead emit the
235
+ first-class dynamic form
236
+ ``Captain shall call playbook selected by `<playbook-id-context>`:``.
237
+ The backtick-delimited name identifies a typed FSM context field whose runtime
238
+ value is the target playbook id; it is not itself a target id.
239
+ The blockquote shall be exactly one placeholder naming the typed context field
240
+ whose runtime string is the complete child input text.
241
+
242
+ Example:
243
+
244
+ ```markdown
245
+ ### CAPTAIN-2
246
+
247
+ When Captain selects a next call, Captain shall call playbook selected by `nextPlaybookId`:
248
+
249
+ > <nextPlaybookInput>
250
+ ```
251
+
252
+ Here `nextPlaybookId` and `nextPlaybookInput` are stable context-field names.
253
+ The dynamic form shall not use a slash command, module specifier, opaque
254
+ expression, or prose from which a downstream compiler would have to infer
255
+ either field.
256
+
257
+ ### Script behaviors (optimizer-introduced)
258
+
259
+ A GEARS package may also contain deterministic script behaviors, written
260
+ `Captain shall run:` followed by a blockquote whose lines are the exact POSIX
261
+ shell script to execute.
262
+ text2gears shall never emit this kind: script items enter a GEARS package only
263
+ through the separate [optimize](optimize.md) pass, which rewrites eligible
264
+ compiled items.
265
+ The kind is defined here so every consumer of the GEARS format shares one
266
+ item-syntax contract.
267
+
268
+ A script item's blockquote is static shell text: it shall contain no
269
+ `<placeholder>`, and Markdown escapes resolve exactly as in acting prompts.
270
+ A script item shall carry a `Results:` label with exactly two bullets in this
271
+ fixed interpretation: the first guard reports the script exiting with status
272
+ zero, the second reports a nonzero exit status.
273
+ No other result, and no `needsBossReply`, applies to a script item — a script
274
+ has no agent to surface questions.
275
+
276
+ Example:
277
+
278
+ ```markdown
279
+ ### CODE-1
280
+
281
+ When the workflow starts, Captain shall run:
282
+
283
+ > git rev-parse --is-inside-work-tree 2>/dev/null || git init
284
+
285
+ Results:
286
+ - `ok`: The command exited with status zero.
287
+ - `failed`: The command exited with a nonzero status.
288
+ ```
289
+
290
+ Target shall be written in the same language as Source: an item's condition
291
+ prose, acting prompts, and result descriptions follow the Source language,
292
+ read per the matching localization of the GEARS definition [[1]].
293
+ The four `Captain shall` acting-clause forms defined above (direct,
294
+ delegated, nested playbook call, and script), guard names, and the
295
+ `Players:` and `Results:` labels are fixed machine syntax and stay in this
296
+ exact English form regardless of Source language.
297
+
298
+ ## Transformation-spec sources
299
+
300
+ A Source may itself be the normative specification of a transformation — e.g., a compiler phase definition, as when a meta pipeline compiles this file.
301
+ Such a Source declares no players and prompts none; its implied procedure is that Captain performs the specified transformation on request.
302
+ Compose Captain-acting spec items for it: when a transformation request names the specification's source and target, Captain shall carry out the transformation as specified.
303
+ Prompts shall carry the specification's normative requirements as instructions to Captain — deduplicated, one point per line — without inventing players, triggers, or requirements the specification does not state.
58
304
 
59
305
  ## Composition
60
306
 
@@ -71,6 +317,8 @@ Test: a human shall be able to simulate a run by copying any single item's promp
71
317
  Use `<placeholder>` for dynamic values in blockquoted prompts.
72
318
  Everything else inside a blockquote is static text, not an example; examples belong in surrounding prose.
73
319
 
320
+ Markdown escaping is Source syntax, not content: extraction shall resolve escapes (e.g. `\<placeholder\>` becomes `<placeholder>`), so compiled artifacts carry plain text.
321
+
74
322
  ### Split by content discriminator
75
323
 
76
324
  Partition items by every variable that determines prompt content — including accumulated state when the trigger alone doesn't.
@@ -82,4 +330,4 @@ Dead branches mislead readers and downstream phases.
82
330
 
83
331
  ## References
84
332
 
85
- [1]: [GEARS syntax](/specs/meta.md#item-syntax)
333
+ [1]: GEARS definition shipped by the installed `@sublang/spex` package: `@sublang/spex/scaffold/specs/meta.md` (English) and `@sublang/spex/scaffold/i18n/zh/specs/meta.md` (Chinese); canonical renditions [GEARS: AI-Ready Spec Syntax](https://sublang.ai/ref/gears-ai-ready-spec-syntax) (en) and [GEARS:面向 AI 的规约语法](https://sublang.ai/zh/ref/gears-ai-ready-spec-syntax) (zh)
package/src/runtime.d.ts CHANGED
@@ -1,23 +1,166 @@
1
1
  export interface PlayerResult {
2
2
  status: 'ok' | 'aborted' | 'error';
3
+ resumeToken?: string;
3
4
  finalText?: string;
4
5
  error?: string;
5
6
  }
7
+ export interface PlayerCallOptions {
8
+ resume: string | false;
9
+ }
10
+ export interface CaptainCallOptions {
11
+ visibility: 'visible' | 'hidden';
12
+ resume: string | false;
13
+ allowedTools?: readonly string[];
14
+ }
15
+ export interface CaptainResult {
16
+ status: 'ok' | 'aborted' | 'error';
17
+ finalText?: string;
18
+ error?: string;
19
+ }
20
+ export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
21
+ readonly [key: string]: JsonValue;
22
+ };
23
+ export interface NormalizedError {
24
+ name: string;
25
+ message: string;
26
+ stack?: string;
27
+ }
28
+ export type PlaybookStateValue = string | {
29
+ readonly [key: string]: PlaybookStateValue;
30
+ };
31
+ export interface PlaybookState {
32
+ value: PlaybookStateValue;
33
+ activeStateIds: readonly string[];
34
+ tags: readonly string[];
35
+ status: 'active' | 'done' | 'error' | 'stopped';
36
+ quiescent: boolean;
37
+ stateId?: string;
38
+ }
39
+ export interface PlaybookPendingCall {
40
+ callId: string;
41
+ playbookId: string;
42
+ childSessionId: string;
43
+ }
44
+ export interface PlaybookCallRequest {
45
+ callId: string;
46
+ playbookId: string;
47
+ text: string;
48
+ }
49
+ export type PlaybookCallResult = {
50
+ status: 'ok';
51
+ playbookId: string;
52
+ childSessionId: string;
53
+ state?: PlaybookState;
54
+ output?: JsonValue;
55
+ } | {
56
+ status: 'aborted';
57
+ playbookId: string;
58
+ childSessionId?: string;
59
+ state?: PlaybookState;
60
+ error?: NormalizedError;
61
+ } | {
62
+ status: 'error';
63
+ playbookId: string;
64
+ childSessionId?: string;
65
+ state?: PlaybookState;
66
+ error: NormalizedError;
67
+ };
68
+ export type PlaybookCallStart = {
69
+ state: 'settled';
70
+ result: PlaybookCallResult;
71
+ } | {
72
+ state: 'suspended';
73
+ childSessionId: string;
74
+ };
75
+ export type PlaybookRunResult = {
76
+ outcome: 'quiescent' | 'no-action';
77
+ state: PlaybookState;
78
+ } | {
79
+ outcome: 'failed' | 'aborted';
80
+ state: PlaybookState;
81
+ error?: NormalizedError;
82
+ } | {
83
+ outcome: 'terminal';
84
+ state: PlaybookState;
85
+ output?: JsonValue;
86
+ } | {
87
+ outcome: 'suspended';
88
+ state: PlaybookState;
89
+ pendingCall: PlaybookPendingCall;
90
+ };
6
91
  export interface PlaybookPorts {
7
- callPlayer(playerId: string, prompt: string, signal: AbortSignal): Promise<PlayerResult>;
92
+ callPlayer(playerId: string, prompt: string, signal: AbortSignal, options: PlayerCallOptions): Promise<PlayerResult>;
93
+ callCaptain(prompt: string, signal: AbortSignal, options: CaptainCallOptions): Promise<CaptainResult>;
8
94
  callJudge(prompt: string, signal: AbortSignal): Promise<string>;
95
+ callPlaybook(request: PlaybookCallRequest, signal: AbortSignal): Promise<PlaybookCallStart>;
9
96
  emitStatus(message: string, data?: unknown): Promise<void>;
10
97
  emitTelemetry(event: {
11
98
  topic: string;
12
99
  payload: unknown;
13
100
  }): Promise<void>;
14
101
  }
102
+ export interface PlaybookSession {
103
+ sessionId: string;
104
+ playbookId: string;
105
+ rootSessionId: string;
106
+ parentSessionId?: string;
107
+ parentCallId?: string;
108
+ depth: number;
109
+ ports: PlaybookPorts;
110
+ }
111
+ export type PlaybookTraceType = 'session.started' | 'boss.input.received' | 'judge.call.started' | 'judge.call.finished' | 'player.call.started' | 'player.call.finished' | 'captain.call.started' | 'captain.call.finished' | 'playbook.call.started' | 'playbook.call.finished' | 'fsm.transition' | 'status.emitted' | 'boss.input.settled' | 'session.disposed';
112
+ export interface PlaybookTraceEvent {
113
+ schemaVersion: 2;
114
+ sessionId: string;
115
+ playbookId: string;
116
+ rootSessionId: string;
117
+ parentSessionId?: string;
118
+ parentCallId?: string;
119
+ depth: number;
120
+ sequence: number;
121
+ timestamp: number;
122
+ type: PlaybookTraceType;
123
+ turnId?: number;
124
+ callId?: string;
125
+ payload: JsonValue;
126
+ }
127
+ export interface PlaybookPendingBossQuestion {
128
+ questionId: string;
129
+ player: string;
130
+ question: string;
131
+ sourceItem?: string;
132
+ }
133
+ export interface PlaybookRuntimeSnapshot {
134
+ schemaVersion: 1;
135
+ playbookId: string;
136
+ machine: JsonValue;
137
+ playerResumeTokens: {
138
+ readonly [playerId: string]: string;
139
+ };
140
+ sequences: {
141
+ trace: number;
142
+ turn: number;
143
+ judgeCall: number;
144
+ playerCall: number;
145
+ playbookCall: number;
146
+ captainCall?: number;
147
+ };
148
+ state: PlaybookState;
149
+ pendingBossQuestions: readonly PlaybookPendingBossQuestion[];
150
+ }
15
151
  export interface PlaybookRuntime {
16
- init(ports: PlaybookPorts): Promise<void>;
152
+ init(session: PlaybookSession): Promise<void>;
153
+ exportSnapshot?(): PlaybookRuntimeSnapshot | undefined;
154
+ restore?(session: PlaybookSession, snapshot: PlaybookRuntimeSnapshot): Promise<void>;
17
155
  handleBossInput(turn: {
18
156
  text: string;
19
157
  signal: AbortSignal;
20
- }): Promise<void>;
158
+ }): Promise<PlaybookRunResult>;
159
+ resumePlaybookCall(input: {
160
+ callId: string;
161
+ result: PlaybookCallResult;
162
+ signal: AbortSignal;
163
+ }): Promise<PlaybookRunResult>;
21
164
  dispose(): Promise<void>;
22
165
  }
23
166
  export type PlaybookRuntimeFactory<Options = unknown> = (options: Options) => PlaybookRuntime;