@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
package/README.md CHANGED
@@ -83,6 +83,8 @@ playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 "continue"
83
83
 
84
84
  `playbook run` prints the one Boss-visible Captain reply to stdout and operational status to stderr; CODE and DECIDE can complete their nested REVIEW calls there too.
85
85
 
86
+ If a step fails or needs preparation before your answer, ask Captain to fix the prerequisite and resume; see [Preparing a stopped step](docs/cli.md#preparing-a-stopped-step).
87
+
86
88
  See [Using the CLI](docs/cli.md) for flags and durable continuation, [Configuring agents](docs/configuration.md) for the shared lineup, [Embedding](docs/embedding.md) for custom hosts, and the [changelog](https://github.com/sublang-ai/playbook/blob/main/CHANGELOG.md) for releases.
87
89
 
88
90
  ## Create your own playbook
package/docs/cli.md CHANGED
@@ -144,17 +144,16 @@ uses the exact stable player IDs configured under its `roles` map. Equal IDs
144
144
  share one pane and provider conversation across nested and later root
145
145
  engagements; distinct IDs remain isolated even when their agent settings are
146
146
  identical. When a player surfaces a
147
- clarifying question the FSM parks, the pane shows the question, and a
148
- judge classifies your next turn as its reply or a fresh directive that
149
- abandons it
147
+ clarifying question, the playbook pauses and Captain explains the complete question briefly.
148
+ Answer or ask for clarification through Captain; reading a player pane is unnecessary.
149
+ A request to explain preserves the pending question, while an answer or explicit player follow-up reaches the waiting player
150
150
  ([[playbook-runtime-2](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-runtime.md#playbook-runtime-2)]).
151
151
 
152
152
  The Captain pane shows start/stop/finished status with `◇` lines and
153
- streams progress with captain-speech classification and questions
153
+ streams progress; Captain relays pending questions in its reply
154
154
  ([[playbook-runtime-3](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-runtime.md#playbook-runtime-3)]), while player
155
155
  prompts ride their own panes. A turn that actually did something ends
156
- with one Captain reply summarizing what changed, composed only from that
157
- turn's reported outcome; a turn that changed nothing ends with an
156
+ with one Captain reply summarizing what changed, grounded in that turn's reported outcome and current pending questions; a turn that changed nothing ends with an
158
157
  ordinary reply and no saved-counts line
159
158
  ([[playbook-captain-19](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-captain.md#playbook-captain-19)]).
160
159
 
@@ -187,8 +186,8 @@ stderr, and `--verbose` adds only telemetry topic names to stderr.
187
186
  | `--verbose` | add Captain telemetry topic names to stderr |
188
187
  | `--continue` | continue the newest Captain session stored for this working directory, or the reported global fallback |
189
188
  | `--session <id>` | continue one durable Captain session explicitly |
190
- | `--retry-uncertain` | with `--session`, retry its exact recorded uncertain input |
191
- | `--discard-uncertain` | with `--session`, abandon its uncertain attempt |
189
+ | `--retry-uncertain` | with `--session`, restore and report interrupted work; then choose a continuation |
190
+ | `--discard-uncertain` | with `--session`, discard an attempt only if no work was recorded |
192
191
  | `--` | end options before one literal input or reply |
193
192
  | `-h`, `--help` | print the complete grammar without reading stdin or config |
194
193
 
@@ -196,8 +195,7 @@ Exit `0` means the Captain turn and its durable hand-off were presented,
196
195
  even when the selected action reported rejection or failure through the
197
196
  Captain reply. Argument, config, catalog, readiness, or pre-turn setup errors
198
197
  exit `1`; a started-turn, persistence, lease-release, or presentation failure
199
- exits `2` with stdout empty. SIGINT, SIGTERM, and SIGHUP preserve the
200
- uncertain boundary, withhold stdout, and are re-raised after lease retirement
198
+ exits `2` with stdout empty. SIGINT, SIGTERM, and SIGHUP withhold stdout, preserve uncertainty unless stopped recovery can save its current work, and are re-raised after lease retirement
201
199
  ([[playbook-cli-18](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-cli.md#playbook-cli-18)]).
202
200
 
203
201
  The former positional `<from>`, `resume`, `--player`, `--captain`,
@@ -369,27 +367,47 @@ abandonment disposes the complete engagement without claiming an authored
369
367
  workflow outcome. The same restricted recovery survives process restart
370
368
  ([DR-040](https://github.com/sublang-ai/playbook/blob/main/specs/decisions/040-outcome-authority-effect-reconciliation.md)).
371
369
 
370
+ ### Preparing a stopped step
371
+
372
+ Captain automatically tries to prepare and resume a step stopped by an operation in the current turn. You can also supply a missing answer or ask for a repair:
373
+
374
+ ```sh
375
+ playbook run --session <id> "Install the missing dependency and continue."
376
+ ```
377
+
378
+ This also works in the interactive Boss pane. Captain may inspect prerequisites, prepare local tools, put generated files aside, and adjust local ignore settings. It preserves user work and the task's scope. It cannot do the remaining specialist work, change saved session data, invent a result, or skip a step.
379
+
380
+ The runtime checks the continuation. It retries the interrupted step, keeps earlier commits, and uses saved output when only its assessment was interrupted. If a read-only check left unwanted files, retry requires restoring its original files and HEAD; the original failure stays recorded. A waiting player's repository checkpoint must remain intact.
381
+
382
+ Captain asks Boss for a real missing decision, uncertain permission, or a missing or contradictory playbook transition. Repository checks alone cannot prove that publishing or another outside action is safe to repeat; Captain must check that separately.
383
+
384
+ Preparation allows at most two automatic attempts, each following a stop produced by work in this turn. Resuming saved work or refusing new text does not start preparation. Each preparation has a 150-second deadline. When a turn with recorded progress throws and its calls drain safely, the latest stopped step is saved and accepts a new instruction; the interactive pane stays open. Before every player, script or preparation step, the runner saves its position; it saves the result before advancing. After process loss, Retry only restores and reports. Boss chooses what happens next. Custom hosts must provide cancellation before preparation is available.
385
+
386
+ Custom runtimes can provide the same recovery offer: step prompt, optional preparation conditions and evidence, and a continuation they will validate. Captain needs no list of repair tools or error strings. Failed checkpoints without an invocation position have no step retry; restarting the whole playbook could repeat completed work.
387
+
388
+ Captain may answer a player from the original task when it already answers the question. It reports what it reused, respects later Boss instructions and never sends that original answer twice automatically.
389
+
390
+ If a process loses the exact stopping point, retry settles the attempt in chat without repeating player work. Files and recorded evidence remain; unrelated saved workflows remain available. This also works when the attempt began from chat or used a custom runtime.
391
+
392
+ All applications sharing a session store, including Spex and the CLI, must upgrade together before running this version: every step writes the new progress fields, and every saved shell snapshot carries `presentedEffectPrefix`. Hosts through 16.0.x reject those fields as unknown, so they cannot open any session this version saves.
393
+
372
394
  ### Recovering an uncertain turn
373
395
 
374
396
  Before model work, the runner takes one exclusive session lease and writes an
375
397
  uncertain marker. If the process is interrupted after effects may
376
398
  have begun but before settlement is durable, ordinary continuation refuses
377
- to guess. Choose explicitly:
399
+ to guess. Retry restores the saved position and reports what happened, without running any work. Discard is a separate explicit request:
378
400
 
379
401
  ```sh
380
402
  playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 --retry-uncertain
381
403
  playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 --discard-uncertain
382
404
  ```
383
405
 
384
- Retry reads no input and reuses the byte-exact recorded turn and its exact
385
- attempted Captain, player, and per-role model, effort, and fast-mode settings;
386
- current config cannot retune that attempt, and retry may duplicate external
387
- effects. Discard
406
+ Retry reads no input and restores the recorded attempt only to report it. It runs no model work. Later turns use the current compatible configuration. A completed step can use its saved result without running again. Before repeating an unfinished step, Boss must confirm that the old worker has stopped and check any outside actions; unchanged files do not prove nothing happened. A runtime that cannot save its position returns to Captain with the work preserved. Discard
388
407
  reads no input and runs no model: it restores the exact prior settled boundary,
389
408
  or deletes a never-settled fresh session, while abandoning the attempted work.
390
- An interrupted interactive turn uses the same uncertain record and these
391
- headless recovery commands. Discard preserves the attempt's replay history and
392
- refuses if the effect ledger has advanced beyond the prior checkpoint.
409
+ An interrupted interactive turn that could not save a normal pause uses the same uncertain record and these headless recovery commands. Discard preserves the attempt's replay history and
410
+ refuses if the effect ledger has advanced beyond the prior checkpoint or any step was recorded. It does not undo files or commits. Captain never selects discard automatically.
393
411
 
394
412
  Stop old writers before upgrading. When using the ordinary `~/.spex/sessions`
395
413
  default, the CLI imports sessions from
@@ -215,15 +215,18 @@ before registry import, host creation, or agent work.
215
215
 
216
216
  ## Choosing the Captain agent
217
217
 
218
- Every session-Captain call and adjudication call is hidden and runs
219
- tool-free, which is what keeps the Captain deciding and reporting
220
- instead of doing the work itself. Claude and Gemini enforce that at the
218
+ Ordinary Captain decisions, replies, question checks and adjudication are hidden and tool-free.
219
+ Claude and Gemini enforce the tool restriction at the
221
220
  provider level. The Codex, Kimi, and OpenCode adapters cannot — they
222
221
  reject any tool list — so a `captain:` using one of them falls back to a
223
222
  prompt-level restriction
224
223
  ([DR-013](https://github.com/sublang-ai/playbook/blob/main/specs/decisions/013-routing-only-captain-control.md) A1).
225
224
  Those adapters remain good choices for *players*, where full tools are wanted.
226
225
 
226
+ Recovery preparation is separate: Captain may use its configured tools and permissions to repair prerequisites for the paused step, within the existing task.
227
+ It may not finish the specialist’s task or invent a decision; discarding work or rewriting history requires your explicit instruction.
228
+ Preparation has a 150-second limit.
229
+
227
230
  Adapter readiness is intentionally light: `claude` is ready with local
228
231
  Claude Code auth or `ANTHROPIC_API_KEY`; `codex` with local Codex CLI
229
232
  auth or `OPENAI_API_KEY`. A known adapter that is not ready blocks the
@@ -271,8 +274,7 @@ compatible ordinary reopen. A selected session keeps its stored catalog,
271
274
  player roster, role bindings, adapter, instruction, permissions, and working
272
275
  directory; only model, effort, and fast mode may change. The next call reapplies
273
276
  both complete model and effort selections and the optional effective fast-mode
274
- boolean. An uncertain retry accepts no tuning overlay and uses the exact
275
- attempted settings already stored with that turn.
277
+ boolean. An uncertain retry accepts no tuning overlay and only restores and reports the recorded attempt. Later turns use the current compatible settings.
276
278
 
277
279
  ## Session storage
278
280
 
package/docs/embedding.md CHANGED
@@ -38,7 +38,7 @@ tree, which pnpm's strict linking will not allow.
38
38
 
39
39
  ```ts
40
40
  import createPlaybookRuntime, {
41
- type ReviewPlaybookHostCapabilities,
41
+ type PlaybookHostCapabilities,
42
42
  } from '@sublang/playbook/review/playbook';
43
43
  import type {
44
44
  CaptainCallOptions,
@@ -156,7 +156,7 @@ const playbookSessionId = randomUUID();
156
156
  // machine input, or a persisted snapshot. A host outside the CLI constructs
157
157
  // the repository and effect-ledger members through the facade described in
158
158
  // "Constructing worktree host capabilities" below.
159
- declare const hostCapabilities: ReviewPlaybookHostCapabilities;
159
+ declare const hostCapabilities: PlaybookHostCapabilities;
160
160
 
161
161
  const runtime = createPlaybookRuntime({
162
162
  configuredOptions: {},
@@ -258,7 +258,7 @@ const inert = createPlaybookRuntime({
258
258
  ```
259
259
 
260
260
  `createWorktreeHostCapabilities()` requires only that `cwd` exist and returns
261
- exactly `repository: { identity, observe, runExclusive, runDeferred }` and
261
+ exactly `repository: { identity, observe, acquire, runExclusive, runDeferred }` and
262
262
  `effectLedger: { snapshot, writeAhead }`. The governed worktree is bound at
263
263
  every governed call and observation rather than fixed at construction: it is
264
264
  the canonical root of the nearest Git worktree containing `cwd`, or — when
@@ -279,6 +279,7 @@ CLI uses (process-local until the repository exists, since there is no `.git`
279
279
  to publish it in), observe before and after the operation, apply the engine's
280
280
  correction-budget `writeAhead` mid-completion, and bind, park, continue, and
281
281
  restore deferred Boss questions with the engine's exact checkpoint semantics.
282
+ `acquire({signal})` holds that same worktree claim for preparation checks; call `assertOwner()` before checking and `release()` in `finally`.
282
283
  Overlapping calls on one worktree run one at a time, in no guaranteed order.
283
284
  A write the ledger rejects after a boundary has started leaves the worktree
284
285
  claim quarantined, exactly as it would under `playbook run`: treat that
@@ -413,10 +414,30 @@ Automatic discovery belongs only to the ordinary
413
414
  `~/.spex/sessions` profile with no `SPEX_HOME` or `sessions` override; custom
414
415
  profiles require an explicit migration request.
415
416
 
416
- For an uncertain session, reopen with `mode:'retry'` and call `retry()`. It uses
417
- the exact recorded input and attempted configuration. Module-free
418
- `discardSessionUncertain(shared, sessionId)` restores the prior recovery only
419
- when no effect-ledger advancement prevents discard.
417
+ Captain may answer a player from the original task when it already answers the question. It reports what it reused, respects later Boss instructions and never sends that original answer twice automatically.
418
+
419
+ If a process loses the exact stopping point, retry settles the attempt in chat without repeating player work. Files and recorded evidence remain; unrelated saved workflows remain available. This also works when the attempt began from chat or used a custom runtime.
420
+
421
+ All applications sharing a session store, including Spex and the CLI, must upgrade together before running this version. Every saved shell snapshot carries `presentedEffectPrefix`, which hosts through 16.0.x reject as unknown, so they cannot open any session this version saves.
422
+
423
+ A single recovery entry point handles either a paused step or an uncertain attempt:
424
+
425
+ ```ts
426
+ const controller = await openSessionHost({ store: shared, sessionId, mode: 'recover' });
427
+ try {
428
+ const record = await controller.read();
429
+ await controller.recover(record?.state === 'uncertain' ? undefined : bossInstruction);
430
+ } finally { await controller.dispose(); }
431
+ ```
432
+
433
+ For uncertainty it restores the saved position and reports the recorded work using the attempted settings. It runs no player, script or preparation. Boss then chooses an available action or supplies input. Completed results are reused; before repeating unfinished work, Boss must stop any old worker and check outside actions. A runtime without a saved position returns to Captain with work preserved. It never chooses discard. For an already settled pause, `recover(bossInstruction)` requires Boss's instruction or answer and passes it through the same Captain turn as CLI input; an ordinary answer does not force preparation. New input cannot replace an uncertain instruction before recovery.
434
+
435
+ If a turn fails and leaves this open controller uncertain, dispose it and reopen with `mode:'recover'` before calling `recover()` without new input.
436
+
437
+ Explicit `mode:'retry'` and `retry()` remain supported. Module-free
438
+ `discardSessionUncertain(shared, sessionId)` restores the prior recovery, or
439
+ deletes a never-settled fresh session and resolves `undefined`,
440
+ only when `isUncertainTurnDiscardable(record)` returns true: no abandonment, no recorded steps, and a ledger equal to the pre-turn snapshot. Use the same exported predicate to enable a Discard control.
420
441
 
421
442
  `readHistory()` returns readable history and a damaged boundary, including a
422
443
  clearly marked synthetic projection when a validated legacy journal has no
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sublang/playbook",
3
- "version": "15.1.0",
3
+ "version": "17.0.0",
4
4
  "type": "module",
5
5
  "description": "Composable XState v5 playbook runtime with compiled Captain, CODE, REVIEW, DECIDE, DEV, BRANCH, and PR workflows driven by GEARS specs.",
6
6
  "license": "Apache-2.0",
@@ -243,15 +243,15 @@
243
243
  "provenance": true
244
244
  },
245
245
  "dependencies": {
246
- "@sublang/cligent": "^0.26.0",
246
+ "@sublang/cligent": "^0.27.0",
247
247
  "@sublang/spex": "^3.0.0",
248
248
  "p-queue": "^9.3.1",
249
249
  "xstate": "^5.19.4",
250
250
  "yaml": "^2.9.0"
251
251
  },
252
252
  "devDependencies": {
253
- "@anthropic-ai/claude-agent-sdk": "^0.3.223",
254
- "@openai/codex-sdk": "^0.146.0",
253
+ "@anthropic-ai/claude-agent-sdk": "^0.3.283",
254
+ "@openai/codex-sdk": "^0.157.1",
255
255
  "@types/node": "^22.0.0",
256
256
  "typescript": "^5.8.0",
257
257
  "vitest": "^3.0.0"
@@ -1,34 +1,46 @@
1
1
  export type BranchStateId = 'createBranch';
2
2
  export type BranchSourceItem = 'BRANCH-1';
3
+ /**
4
+ * Stable working-leaf ids that may suspend on a Boss question and be resumed
5
+ * by `BOSS_REPLY`. The machine has at most one active player task, so the
6
+ * scalar Boss-reply form applies.
7
+ */
8
+ declare const RESUMABLE_STATE_IDS: readonly ["createBranch"];
9
+ export type ResumableStateId = (typeof RESUMABLE_STATE_IDS)[number];
10
+ /** JSON-safe normalization of a rejected invocation, retained for inspection. */
11
+ export type NormalizedError = {
12
+ readonly name: string;
13
+ readonly message: string;
14
+ readonly stack?: string;
15
+ };
16
+ /** Question record raised by the suspended Coder working leaf. */
3
17
  export type PendingBossQuestion = {
4
- readonly questionId: 'createBranch';
5
- readonly resumeStateId: 'createBranch';
6
- readonly sourceItem: 'BRANCH-1';
18
+ readonly questionId: ResumableStateId;
19
+ readonly resumeStateId: ResumableStateId;
20
+ readonly sourceItem: BranchSourceItem;
7
21
  readonly asker: {
8
22
  readonly kind: 'role';
9
23
  readonly roleId: 'coder';
10
24
  };
11
25
  readonly question: string;
12
26
  };
27
+ /** Typed input for the delegated `player` actor. */
13
28
  export type PlayerInput = {
14
29
  readonly stateId: 'createBranch';
15
30
  readonly role: 'coder';
16
31
  readonly sourceItem: 'BRANCH-1';
17
32
  readonly prompt: string;
18
33
  readonly result: Readonly<Record<string, string>>;
34
+ /** Backs the prompt's `<caller-input>` placeholder with the exact caller input. */
19
35
  readonly callerInput: string;
20
36
  readonly pendingBossQuestion?: PendingBossQuestion;
21
37
  readonly bossReply?: string;
22
38
  };
39
+ /** Discriminated result contract of the delegated `player` actor. */
23
40
  export type PlayerOutput = {
24
41
  readonly guard: 'branched';
25
42
  readonly branch: string;
26
- /**
27
- * Receipt-owned effect evidence (DR-045): the branching call's
28
- * `unchanged` receipt observes the commit the branch was created from
29
- * as HEAD, so the linked runtime injects it and never takes it from
30
- * Coder's prose.
31
- */
43
+ /** Exact base revision from repository authority, not from Coder's prose. */
32
44
  readonly baseRevision: string;
33
45
  readonly issueSummary: string;
34
46
  } | {
@@ -38,47 +50,55 @@ export type PlayerOutput = {
38
50
  readonly guard: 'needsBossReply';
39
51
  readonly question: string;
40
52
  };
53
+ /**
54
+ * Terminal result: exactly the packaged `branch` workflow's public output
55
+ * interface (workflow-contracts.json), derived from typed context.
56
+ */
41
57
  export type BranchPlaybookOutput = {
42
58
  readonly status: 'branched';
43
- /** Exact name of the new branch now checked out. */
59
+ /** Exact new branch name. */
44
60
  readonly branch: string;
45
- /** Exact receipt-observed revision the branch was created from. */
61
+ /** Exact receipt-observed repository revision the branch was created from. */
46
62
  readonly baseRevision: string;
47
- /** Coder's concise summary of the issue and its comments, or of the request. */
63
+ /** Concise issue-and-comments or request summary. */
48
64
  readonly issueSummary: string;
49
65
  } | {
50
66
  readonly status: 'refused';
51
- /** Coder's complete report carrying the reason no branch was created. */
67
+ /** Complete refusal report. */
52
68
  readonly coderOutput: string;
53
69
  };
54
- export type BranchInput = Readonly<Record<string, never>>;
70
+ /** The machine reads no input: the caller input arrives on `START_BRANCH`. */
71
+ export type BranchInput = Readonly<Record<never, never>>;
72
+ export type BranchCompletion = 'branched' | 'refused';
55
73
  export type BranchContext = {
56
74
  readonly callerInput?: string;
57
75
  readonly branch?: string;
58
- /** Observed HEAD of the branching call's unchanged receipt (DR-045). */
59
76
  readonly baseRevision?: string;
60
77
  readonly issueSummary?: string;
61
78
  readonly coderOutput?: string;
62
- readonly completion?: 'branched' | 'refused';
63
- readonly lastError?: unknown;
79
+ readonly completion?: BranchCompletion;
80
+ readonly lastError?: NormalizedError;
64
81
  readonly pendingBossQuestion?: PendingBossQuestion;
65
82
  readonly bossReply?: string;
66
83
  };
84
+ /** Typed Boss surfaces: the caller's entry event and the Boss reply. */
67
85
  export type BranchEvent = {
68
86
  readonly type: 'START_BRANCH';
69
87
  readonly callerInput: string;
70
88
  } | {
71
89
  readonly type: 'BOSS_REPLY';
72
90
  readonly answer: string;
73
- readonly questionId?: 'createBranch';
91
+ readonly questionId?: ResumableStateId;
74
92
  };
93
+ /** No parallel group in this playbook. */
94
+ export declare const concurrentRoleSets: readonly (readonly string[])[];
75
95
  export declare const branchMachine: import("xstate").StateMachine<BranchContext, {
76
96
  readonly type: "START_BRANCH";
77
97
  readonly callerInput: string;
78
98
  } | {
79
99
  readonly type: "BOSS_REPLY";
80
100
  readonly answer: string;
81
- readonly questionId?: "createBranch";
101
+ readonly questionId?: ResumableStateId;
82
102
  }, {
83
103
  [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>> | undefined;
84
104
  }, {
@@ -96,16 +116,22 @@ export declare const branchMachine: import("xstate").StateMachine<BranchContext,
96
116
  type: "rememberActorError";
97
117
  params: import("xstate").NonReducibleUnknown;
98
118
  } | {
99
- type: "rememberPendingQuestion";
119
+ type: "rememberMalformedPlayerOutput";
100
120
  params: import("xstate").NonReducibleUnknown;
101
121
  } | {
102
- type: "rememberBossReply";
122
+ type: "clearBossReplyContext";
103
123
  params: import("xstate").NonReducibleUnknown;
104
124
  } | {
105
- type: "rememberEmptyBossReplyError";
125
+ type: "setPendingBossQuestion";
126
+ params: {
127
+ readonly stateId: ResumableStateId;
128
+ readonly sourceItem: BranchSourceItem;
129
+ };
130
+ } | {
131
+ type: "rememberMalformedBossReply";
106
132
  params: import("xstate").NonReducibleUnknown;
107
133
  } | {
108
- type: "rememberMalformedPlayerOutput";
134
+ type: "acceptBossReply";
109
135
  params: import("xstate").NonReducibleUnknown;
110
136
  } | {
111
137
  type: "startBranch";
@@ -118,9 +144,16 @@ export declare const branchMachine: import("xstate").StateMachine<BranchContext,
118
144
  params: import("xstate").NonReducibleUnknown;
119
145
  }, {
120
146
  type: "needsBossReply";
121
- params: unknown;
147
+ params: {
148
+ readonly stateId: ResumableStateId;
149
+ };
122
150
  } | {
123
- type: "emptyBossReply";
151
+ type: "canResume";
152
+ params: {
153
+ readonly stateId: ResumableStateId;
154
+ };
155
+ } | {
156
+ type: "givesRequest";
124
157
  params: unknown;
125
158
  } | {
126
159
  type: "isBranched";
@@ -128,20 +161,17 @@ export declare const branchMachine: import("xstate").StateMachine<BranchContext,
128
161
  } | {
129
162
  type: "isRefused";
130
163
  params: unknown;
131
- } | {
132
- type: "resumesCreateBranch";
133
- params: unknown;
134
- }, never, "failed" | "ready" | "awaitBossReply" | "refused" | "createBranch" | "branched", string, Readonly<Record<string, never>>, {
164
+ }, never, "failed" | "ready" | "awaitBossReply" | "refused" | "createBranch" | "branched", string, Readonly<Record<never, never>>, {
135
165
  readonly status: "branched";
136
- /** Exact name of the new branch now checked out. */
166
+ /** Exact new branch name. */
137
167
  readonly branch: string;
138
- /** Exact receipt-observed revision the branch was created from. */
168
+ /** Exact receipt-observed repository revision the branch was created from. */
139
169
  readonly baseRevision: string;
140
- /** Coder's concise summary of the issue and its comments, or of the request. */
170
+ /** Concise issue-and-comments or request summary. */
141
171
  readonly issueSummary: string;
142
172
  } | {
143
173
  readonly status: "refused";
144
- /** Coder's complete report carrying the reason no branch was created. */
174
+ /** Complete refusal report. */
145
175
  readonly coderOutput: string;
146
176
  }, import("xstate").EventObject, import("xstate").MetaObject, {
147
177
  id: "branch";