@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/src/runtime.ts CHANGED
@@ -492,6 +492,8 @@ export type PlaybookRunResult =
492
492
  };
493
493
 
494
494
  export interface PlaybookPorts {
495
+ /** Acknowledge the durable start before work and its result before transition. */
496
+ recordStep?(step: PlaybookStepRecord, position?: PlaybookRuntimeSnapshot): Promise<void>;
495
497
  callPlayer(
496
498
  roleId: string,
497
499
  prompt: string,
@@ -508,6 +510,7 @@ export interface PlaybookPorts {
508
510
  request: PlaybookCallRequest,
509
511
  signal: AbortSignal,
510
512
  ): Promise<PlaybookCallStart>;
513
+ /** Mark question presentation with data.kind = "boss-question"; Captain relays it from pendingQuestions. */
511
514
  emitStatus(message: string, data?: unknown): Promise<void>;
512
515
  emitTelemetry(event: { topic: string; payload: unknown }): Promise<void>;
513
516
  }
@@ -639,6 +642,8 @@ export interface PlaybookEffectBoundary {
639
642
  readonly baseline: PlaybookRepositoryObservation;
640
643
  readonly after?: PlaybookRepositoryObservation;
641
644
  readonly physicalReceipt?: PlaybookRepositoryReceipt;
645
+ /** A later exact restoration permits replay of this standalone read-only call. */
646
+ readonly restored?: PlaybookRepositoryObservation;
642
647
  readonly finalText?: string;
643
648
  readonly semanticCandidate?: JsonValue;
644
649
  readonly initialSemanticCandidate?: JsonValue;
@@ -655,6 +660,7 @@ export type PlaybookEffectBoundaryStart = Omit<
655
660
  | 'attemptNumber'
656
661
  | 'after'
657
662
  | 'physicalReceipt'
663
+ | 'restored'
658
664
  | 'finalText'
659
665
  | 'semanticCandidate'
660
666
  | 'initialSemanticCandidate'
@@ -774,9 +780,29 @@ export interface PlaybookRuntimeSnapshot {
774
780
  readonly boundaryPrefix: number;
775
781
  readonly attemptId: string | null;
776
782
  };
783
+ /** Interrupted invocation, captured before its external call (DR-069). */
784
+ recoveryCheckpoint?: PlaybookRecoveryCheckpoint;
777
785
  suspendedCall?: PlaybookSuspendedCall;
778
786
  }
779
787
 
788
+ export interface PlaybookRecoveryCheckpoint {
789
+ readonly id?: string;
790
+ readonly stateId: string;
791
+ readonly prompt: string;
792
+ readonly machine: JsonValue;
793
+ readonly boundaryPrefix: number;
794
+ /** Completed actor output supplied by the execution journal on restore. */
795
+ readonly result?: JsonValue;
796
+ readonly delivered?: true;
797
+ }
798
+
799
+ export interface PlaybookStepRecord {
800
+ readonly id: string;
801
+ readonly kind: 'player' | 'captain' | 'script';
802
+ readonly stateId: string;
803
+ readonly result?: JsonValue;
804
+ }
805
+
780
806
  // DR-063 §3: what running an advertised action would do. `ready` is the only
781
807
  // standing that can change anything; `no-op` runs and changes nothing; a
782
808
  // `blocked` action cannot run at all. An absent standing reads as `ready`, so
@@ -805,6 +831,16 @@ export interface PlaybookControlAction {
805
831
  // the Boss-appropriate grounding a host may speak from; the state id is
806
832
  // internal and is absent from it whenever the runtime's source declares
807
833
  // no description for the state it is in.
834
+ export interface PlaybookRecoveryOffer {
835
+ prompt: string;
836
+ description?: string;
837
+ /** Runtime-owned conditions to satisfy; these never authorize task completion. */
838
+ preparation?: string;
839
+ /** Saved observations and result choices for diagnosing the stopped step. */
840
+ evidence?: JsonValue;
841
+ continuation: { kind: 'reply' } | { kind: 'runtime'; actionId: string };
842
+ }
843
+
808
844
  export interface PlaybookControlView {
809
845
  state: PlaybookState;
810
846
  stateDescription?: string;
@@ -812,6 +848,8 @@ export interface PlaybookControlView {
812
848
  pendingQuestions: readonly PlaybookPendingBossQuestion[];
813
849
  lastError?: NormalizedError;
814
850
  actions: readonly PlaybookControlAction[];
851
+ /** Context only for an explicitly authorized Captain preparation call. */
852
+ recovery?: PlaybookRecoveryOffer;
815
853
  }
816
854
 
817
855
  // DR-029: the receipt `apply()` returns says which of three things
@@ -820,7 +858,7 @@ export interface PlaybookControlView {
820
858
  export type PlaybookControlReceipt =
821
859
  | { disposition: 'rejected'; reason: string }
822
860
  | { disposition: 'executed'; run: PlaybookRunResult }
823
- | { disposition: 'failed'; error: NormalizedError };
861
+ | { disposition: 'failed'; error: NormalizedError; run?: PlaybookRunResult };
824
862
 
825
863
  // DR-038 §2: link-authored metadata the Captain uses to decide whether a
826
864
  // quiescent generation is eligible for retention and whether a root terminal
@@ -838,7 +876,7 @@ export interface PlaybookRuntime {
838
876
  // a safe capture point (parked quiescence between public boundaries);
839
877
  // `restore` is an alternative to `init` that rehydrates the exported
840
878
  // snapshot under the same immutable session identity.
841
- exportSnapshot?(): PlaybookRuntimeSnapshot | undefined;
879
+ exportSnapshot?(checkpoint?: { child?: PlaybookPendingCall }): PlaybookRuntimeSnapshot | undefined;
842
880
  restore?(
843
881
  session: PlaybookSession,
844
882
  snapshot: PlaybookRuntimeSnapshot,
@@ -879,6 +917,8 @@ export interface PlaybookRuntime {
879
917
  handleBossInput(turn: {
880
918
  text: string;
881
919
  signal: AbortSignal;
920
+ /** Called synchronously just before accepting the event, at most once. */
921
+ onAccepted?: () => void;
882
922
  }): Promise<PlaybookRunResult>;
883
923
  resumePlaybookCall(input: {
884
924
  callId: string;
@@ -63,7 +63,7 @@ export interface RuntimeBoundaryCalls {
63
63
  * with the cause the boundary decided at the call itself, where the role,
64
64
  * the resolved player, and the reported error are known.
65
65
  */
66
- markPlayerResultFailure?(error: Error): Error;
66
+ markPlayerResultFailure?(error: Error, result?: PlayerResult): Error;
67
67
  callJudge(purpose: JudgePurpose, stateId: string | undefined, prompt: string, signal: AbortSignal): Promise<string>;
68
68
  callCaptain?(input: PlaybookCaptainInput, prompt: string, signal: AbortSignal, callOptions?: XStateCaptainCallOptions): Promise<CaptainResult>;
69
69
  }
@@ -125,17 +125,18 @@ export declare function playerFailureCause(input: {
125
125
  /**
126
126
  * DR-063 §1: the cause of an unresolved governed settlement. A reconciled
127
127
  * mismatch supplies its own receipt-read cause; the reasons a runtime owns map
128
- * to adjudication, abort, and runtime-defect codes. Shared with DECIDE's
129
- * bespoke runtime, which decides the same reasons.
128
+ * to adjudication, abort, and runtime-defect codes. Exported so linked
129
+ * machinery of an artifact's own decides the same reasons.
130
130
  */
131
131
  export declare function governedSettlementCause(reason: string, error: unknown, aborted: boolean, supplied: PlaybookFailureCause | undefined): PlaybookFailureCause;
132
132
  /**
133
133
  * DR-063 §2: the causes decided for thrown values that cannot carry the
134
- * marker — a string, a frozen error — kept by identity for as long as the
135
- * failure stands, so every surface that reads the FSM's own `lastError`
136
- * publishes the cause decided for exactly that value, whatever turn reads it.
137
- * A value that carries the marker answers from it; the map is bounded, since
138
- * only values that refuse the marker need an entry.
134
+ * marker — a string, a frozen error — and for the record a machine keeps in
135
+ * place of the thrown value, kept by identity for as long as the failure
136
+ * stands, so every surface that reads the FSM's own `lastError` publishes the
137
+ * cause decided for exactly that failure, whatever turn reads it. A value
138
+ * that carries the marker answers from it; the map is bounded, since only
139
+ * values that lack the marker need an entry.
139
140
  */
140
141
  export interface PlaybookFailureCauseRetention {
141
142
  retain(error: unknown, cause: PlaybookFailureCause): void;
@@ -195,7 +196,25 @@ interface XStateRepositoryDeferredRestoreResult {
195
196
  readonly effectLedger: PlaybookEffectLedger;
196
197
  }
197
198
  type XStateEffectBoundarySeed = Omit<PlaybookEffectBoundaryStart, 'playbookId' | 'canonicalWorktree' | 'baseline' | 'cohortId'>;
199
+ /** One member's completion inside a repository cohort (DR-067 §1). */
200
+ type XStateRepositoryCohortCompletion<T> = XStateRepositoryExclusiveCompletion<T> & {
201
+ readonly roleId: string;
202
+ };
203
+ interface XStateRepositoryCohortResult<T> {
204
+ readonly baseline: PlaybookRepositoryReceipt['baseline'];
205
+ readonly invocationId: string;
206
+ readonly operations: Readonly<Record<string, XStateRepositoryOperationSettlement<T> | XStateRepositoryOperationRejection>>;
207
+ readonly receipts: Readonly<Record<string, PlaybookRepositoryReceipt>>;
208
+ readonly effectLedger: PlaybookEffectLedger;
209
+ }
198
210
  export interface XStateRepositoryCapability {
211
+ observe?(): Promise<PlaybookRepositoryReceipt['baseline']>;
212
+ acquire?(options: {
213
+ readonly signal: AbortSignal;
214
+ }): Promise<{
215
+ assertOwner(): Promise<void>;
216
+ release(): Promise<void>;
217
+ }>;
199
218
  runExclusive<T>(options: {
200
219
  readonly signal: AbortSignal;
201
220
  readonly effectBoundary: XStateEffectBoundarySeed;
@@ -222,6 +241,27 @@ export interface XStateRepositoryCapability {
222
241
  readonly signal: AbortSignal;
223
242
  readonly operationId: string;
224
243
  }): Promise<XStateRepositoryDeferredParked | XStateRepositoryDeferredRestoreResult>;
244
+ /**
245
+ * DR-067 §1 / PBRT-73: one repository claim over the working leaves of a
246
+ * parallel state entered together — every member an `unchanged` boundary
247
+ * of one cohort, the operations run concurrently under that claim, and
248
+ * one completion callback per member. Required for an artifact that
249
+ * declares a parallel state.
250
+ */
251
+ runCohort?<T>(options: {
252
+ readonly signal: AbortSignal;
253
+ readonly invocationId: string;
254
+ readonly roleIds: readonly string[];
255
+ readonly dispositionsByRole: Readonly<Record<string, readonly ['unchanged']>>;
256
+ readonly effectBoundaries: Readonly<Record<string, XStateEffectBoundarySeed>>;
257
+ readonly operations: Readonly<Record<string, (context: {
258
+ readonly baseline: PlaybookRepositoryReceipt['baseline'];
259
+ readonly identity: unknown;
260
+ readonly invocationId: string;
261
+ readonly roleId: string;
262
+ }) => Promise<T>>>;
263
+ readonly completeEffectBoundary: (completion: XStateRepositoryCohortCompletion<T>) => XStateRepositoryCompletionEvidence | Promise<XStateRepositoryCompletionEvidence>;
264
+ }): Promise<XStateRepositoryCohortResult<T>>;
225
265
  }
226
266
  /** The runtime ABI this engine implements (DR-022). */
227
267
  export declare const RUNTIME_ABI = 1;
@@ -327,14 +367,7 @@ interface XStatePlaybookRuntimeSpecBase<TOptions> {
327
367
  entryEvent?: {
328
368
  type: string;
329
369
  textField: string;
330
- /**
331
- * DR-034: the FSM context member this machine's entry action copies the
332
- * exact Boss text into. Where it is named, the failure-state retry
333
- * builds its payload from that member of the live snapshot instead of
334
- * from the process-local recorded event, so the action derives the same
335
- * before and after `restore`. Absent: the recorded event stays the
336
- * source and the action lives only as long as the process.
337
- */
370
+ /** @deprecated Step checkpoints now carry the accepted input directly. */
338
371
  contextField?: string;
339
372
  };
340
373
  /**
@@ -458,8 +491,8 @@ export declare function defaultBuildJudgePrompt(input: PlaybookPlayerInput, fina
458
491
  * so the judge omits it. Rendering the clause verbatim asked the judge for
459
492
  * `question`, `planningResult`, or `evaluatedRevision`, which the reconciler
460
493
  * rejects as a structural error, spending the single correction on a
461
- * self-inflicted defect. Exported so a bespoke linked runtime (DECIDE's
462
- * parallel machinery) renders the identical contract instead of restating it.
494
+ * self-inflicted defect. Exported so linked machinery of an artifact's own
495
+ * renders the identical contract instead of restating it.
463
496
  */
464
497
  export declare function renderGovernedOutcomeContract(guard: string, description: string, outcome: XStateGovernedOutcomeSpec | undefined): string[];
465
498
  export interface PlayerAdjudicationSpec {
@@ -483,6 +516,7 @@ interface PlayerBridgeSpec {
483
516
  adjudication: PlayerAdjudicationSpec;
484
517
  resumableStateIds: ReadonlySet<string>;
485
518
  allowsCorrectiveReplay?: (result: PlayerResult) => boolean;
519
+ run?: (input: PlaybookPlayerInput, signal: AbortSignal, execute: () => Promise<PlaybookActorOutput>) => Promise<PlaybookActorOutput>;
486
520
  }
487
521
  export declare function createPlayerBridge(spec: PlayerBridgeSpec, ports: PlaybookPorts, getActiveSignal?: () => AbortSignal | undefined, boundary?: RuntimeBoundaryCalls, onControlPlaneError?: (error: unknown) => void): PromiseActorLogic<PlaybookActorOutput, PlaybookPlayerInput>;
488
522
  /**
@@ -495,7 +529,11 @@ export declare function defaultBuildCaptainJudgePrompt(input: {
495
529
  readonly sourceItem: string;
496
530
  readonly result: Readonly<Record<string, string>>;
497
531
  }, finalText: string): string;
498
- /** Targets of the FSM's `awaitBossReply` BOSS_REPLY transitions. */
532
+ /**
533
+ * Targets of the FSM's `awaitBossReply` BOSS_REPLY transitions, plus — for
534
+ * the parallel shape gears2fsm compiles (DR-067) — the targets of each
535
+ * region wait leaf's branch-local BOSS_REPLY arms, resolved to state ids.
536
+ */
499
537
  export declare function resumableStateIdsFromMachine(machine: AnyStateMachine): ReadonlySet<string>;
500
538
  /**
501
539
  * Source state descriptions by state key, node id, and `meta.playbook`
@@ -524,10 +562,12 @@ export declare function terminalOutcomesFromMachine(machine: AnyStateMachine, la
524
562
  * the optional parked-session snapshot capability (DR-014) and the retained-
525
563
  * snapshot adoption capability (DR-038).
526
564
  *
527
- * Scope: flat single-region machines — no parallel state, no compound
528
- * child states, and every root state's `meta.playbook.stateId` equal to its
529
- * state key — so each snapshot exposes exactly one playbook state id.
530
- * Parallel-region FSMs keep their own linked runtimes.
565
+ * Scope: flat single-region machines — every root state's
566
+ * `meta.playbook.stateId` equal to its state key, so each snapshot exposes
567
+ * exactly one playbook state id — plus the parallel profile of DR-067: root
568
+ * `type: 'parallel'` states of the shape gears2fsm compiles, whose regions
569
+ * run as one all-`unchanged` repository cohort with keyed pending questions.
570
+ * A machine declaring a parallel state omits `adopt`.
531
571
  */
532
572
  export declare function createXStatePlaybookRuntime<TOptions, THostCapabilities extends object>(machine: AnyStateMachine, spec: XStatePlaybookRuntimeSpecV3<TOptions>): XStatePlaybookRuntimeFactory<XStatePlaybookRuntimeConstruction<TOptions, THostCapabilities>, 3>;
533
573
  export {};