@sublang/playbook 0.9.0 → 1.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 (48) hide show
  1. package/README.md +183 -151
  2. package/package.json +46 -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 +152 -10
  12. package/reference/sdlc/code.playbook/bin/run.js +893 -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 +18 -9
  21. package/reference/sdlc/code.playbook/code.playbook.js +1095 -200
  22. package/reference/sdlc/code.playbook/code.playbook.ts +1437 -256
  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 +10 -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 +1097 -80
  42. package/slc/optimize.md +88 -0
  43. package/slc/text2gears.md +247 -5
  44. package/src/runtime.d.ts +145 -3
  45. package/src/runtime.ts +200 -2
  46. package/src/xstate-runtime.d.ts +94 -0
  47. package/src/xstate-runtime.js +1247 -0
  48. package/src/xstate-runtime.ts +1802 -0
package/src/runtime.ts CHANGED
@@ -10,24 +10,222 @@
10
10
 
11
11
  export interface PlayerResult {
12
12
  status: 'ok' | 'aborted' | 'error';
13
+ resumeToken?: string;
13
14
  finalText?: string;
14
15
  error?: string;
15
16
  }
16
17
 
18
+ export interface PlayerCallOptions {
19
+ resume: string | false;
20
+ }
21
+
22
+ export interface CaptainCallOptions {
23
+ visibility: 'visible' | 'hidden';
24
+ resume: string | false;
25
+ allowedTools?: readonly string[];
26
+ }
27
+
28
+ export interface CaptainResult {
29
+ status: 'ok' | 'aborted' | 'error';
30
+ finalText?: string;
31
+ error?: string;
32
+ }
33
+
34
+ export type JsonValue =
35
+ | null
36
+ | boolean
37
+ | number
38
+ | string
39
+ | readonly JsonValue[]
40
+ | { readonly [key: string]: JsonValue };
41
+
42
+ export interface NormalizedError {
43
+ name: string;
44
+ message: string;
45
+ stack?: string;
46
+ }
47
+
48
+ export type PlaybookStateValue =
49
+ | string
50
+ | { readonly [key: string]: PlaybookStateValue };
51
+
52
+ export interface PlaybookState {
53
+ value: PlaybookStateValue;
54
+ activeStateIds: readonly string[];
55
+ tags: readonly string[];
56
+ status: 'active' | 'done' | 'error' | 'stopped';
57
+ quiescent: boolean;
58
+ stateId?: string;
59
+ }
60
+
61
+ export interface PlaybookPendingCall {
62
+ callId: string;
63
+ playbookId: string;
64
+ childSessionId: string;
65
+ }
66
+
67
+ export interface PlaybookCallRequest {
68
+ callId: string;
69
+ playbookId: string;
70
+ text: string;
71
+ }
72
+
73
+ export type PlaybookCallResult =
74
+ | {
75
+ status: 'ok';
76
+ playbookId: string;
77
+ childSessionId: string;
78
+ state?: PlaybookState;
79
+ output?: JsonValue;
80
+ }
81
+ | {
82
+ status: 'aborted';
83
+ playbookId: string;
84
+ childSessionId?: string;
85
+ state?: PlaybookState;
86
+ error?: NormalizedError;
87
+ }
88
+ | {
89
+ status: 'error';
90
+ playbookId: string;
91
+ childSessionId?: string;
92
+ state?: PlaybookState;
93
+ error: NormalizedError;
94
+ };
95
+
96
+ export type PlaybookCallStart =
97
+ | { state: 'settled'; result: PlaybookCallResult }
98
+ | { state: 'suspended'; childSessionId: string };
99
+
100
+ export type PlaybookRunResult =
101
+ | { outcome: 'quiescent' | 'no-action'; state: PlaybookState }
102
+ | {
103
+ outcome: 'failed' | 'aborted';
104
+ state: PlaybookState;
105
+ error?: NormalizedError;
106
+ }
107
+ | {
108
+ outcome: 'terminal';
109
+ state: PlaybookState;
110
+ output?: JsonValue;
111
+ }
112
+ | {
113
+ outcome: 'suspended';
114
+ state: PlaybookState;
115
+ pendingCall: PlaybookPendingCall;
116
+ };
117
+
17
118
  export interface PlaybookPorts {
18
119
  callPlayer(
19
120
  playerId: string,
20
121
  prompt: string,
21
122
  signal: AbortSignal,
123
+ options: PlayerCallOptions,
22
124
  ): Promise<PlayerResult>;
125
+ callCaptain(
126
+ prompt: string,
127
+ signal: AbortSignal,
128
+ options: CaptainCallOptions,
129
+ ): Promise<CaptainResult>;
23
130
  callJudge(prompt: string, signal: AbortSignal): Promise<string>;
131
+ callPlaybook(
132
+ request: PlaybookCallRequest,
133
+ signal: AbortSignal,
134
+ ): Promise<PlaybookCallStart>;
24
135
  emitStatus(message: string, data?: unknown): Promise<void>;
25
136
  emitTelemetry(event: { topic: string; payload: unknown }): Promise<void>;
26
137
  }
27
138
 
139
+ export interface PlaybookSession {
140
+ sessionId: string;
141
+ playbookId: string;
142
+ rootSessionId: string;
143
+ parentSessionId?: string;
144
+ parentCallId?: string;
145
+ depth: number;
146
+ ports: PlaybookPorts;
147
+ }
148
+
149
+ export type PlaybookTraceType =
150
+ | 'session.started'
151
+ | 'boss.input.received'
152
+ | 'judge.call.started'
153
+ | 'judge.call.finished'
154
+ | 'player.call.started'
155
+ | 'player.call.finished'
156
+ | 'captain.call.started'
157
+ | 'captain.call.finished'
158
+ | 'playbook.call.started'
159
+ | 'playbook.call.finished'
160
+ | 'fsm.transition'
161
+ | 'status.emitted'
162
+ | 'boss.input.settled'
163
+ | 'session.disposed';
164
+
165
+ export interface PlaybookTraceEvent {
166
+ schemaVersion: 2;
167
+ sessionId: string;
168
+ playbookId: string;
169
+ rootSessionId: string;
170
+ parentSessionId?: string;
171
+ parentCallId?: string;
172
+ depth: number;
173
+ sequence: number;
174
+ timestamp: number;
175
+ type: PlaybookTraceType;
176
+ turnId?: number;
177
+ callId?: string;
178
+ payload: JsonValue;
179
+ }
180
+
181
+ export interface PlaybookPendingBossQuestion {
182
+ questionId: string;
183
+ player: string;
184
+ question: string;
185
+ sourceItem?: string;
186
+ }
187
+
188
+ // DR-014 §1: JSON-safe capture of a parked session. `machine` is the
189
+ // XState persisted snapshot and is opaque to hosts; the pending Boss
190
+ // questions are first-class so a host can surface what was asked
191
+ // without parsing status lines or telemetry.
192
+ export interface PlaybookRuntimeSnapshot {
193
+ schemaVersion: 1;
194
+ playbookId: string;
195
+ machine: JsonValue;
196
+ playerResumeTokens: { readonly [playerId: string]: string };
197
+ sequences: {
198
+ trace: number;
199
+ turn: number;
200
+ judgeCall: number;
201
+ playerCall: number;
202
+ playbookCall: number;
203
+ };
204
+ state: PlaybookState;
205
+ pendingBossQuestions: readonly PlaybookPendingBossQuestion[];
206
+ }
207
+
28
208
  export interface PlaybookRuntime {
29
- init(ports: PlaybookPorts): Promise<void>;
30
- handleBossInput(turn: { text: string; signal: AbortSignal }): Promise<void>;
209
+ init(session: PlaybookSession): Promise<void>;
210
+ // DR-014 §1 optional durable-session capability: a runtime implements
211
+ // both members or neither. `exportSnapshot` returns undefined outside
212
+ // a safe capture point (parked quiescence between public boundaries);
213
+ // `restore` is an alternative to `init` that rehydrates the exported
214
+ // snapshot under the same immutable session identity.
215
+ exportSnapshot?(): PlaybookRuntimeSnapshot | undefined;
216
+ restore?(
217
+ session: PlaybookSession,
218
+ snapshot: PlaybookRuntimeSnapshot,
219
+ ): Promise<void>;
220
+ handleBossInput(turn: {
221
+ text: string;
222
+ signal: AbortSignal;
223
+ }): Promise<PlaybookRunResult>;
224
+ resumePlaybookCall(input: {
225
+ callId: string;
226
+ result: PlaybookCallResult;
227
+ signal: AbortSignal;
228
+ }): Promise<PlaybookRunResult>;
31
229
  dispose(): Promise<void>;
32
230
  }
33
231
 
@@ -0,0 +1,94 @@
1
+ import { type AnyActorRef, type PromiseActorLogic, type SnapshotFrom } from 'xstate';
2
+ import type { CaptainResult, JsonValue, NormalizedError, PlaybookCallRequest, PlaybookCallResult, PlaybookCallStart, PlaybookPendingCall, PlaybookRuntimeSnapshot, PlaybookSession, PlaybookState, PlayerResult } from './runtime.js';
3
+ /**
4
+ * Compose invocation-lifetime and imperative-boundary cancellation without
5
+ * installing a second forwarding listener in each generated runtime.
6
+ */
7
+ export declare function combineAbortSignals(...signals: readonly (AbortSignal | undefined)[]): AbortSignal;
8
+ /**
9
+ * Register host cleanup started synchronously by an invocation abort.
10
+ * The nested bridge drains these promises before it publishes the matching
11
+ * call-finish boundary, without widening the public six-port contract.
12
+ */
13
+ export declare function registerPlaybookAbortCleanup(signal: AbortSignal, cleanup: Promise<unknown>): void;
14
+ /** Reject values that would be changed, omitted, or rejected by JSON. */
15
+ export declare function assertJsonSafe(value: unknown, path?: string, ancestors?: ReadonlySet<object>): asserts value is JsonValue;
16
+ /** Validate, detach, and recursively freeze host-owned JSON input. */
17
+ export declare function snapshotJsonValue(value: unknown, path?: string): JsonValue;
18
+ /** Validate session causality and detach its immutable identity from the host. */
19
+ export declare function snapshotPlaybookSession(session: PlaybookSession): PlaybookSession;
20
+ export declare function normalizeError(error: unknown): NormalizedError;
21
+ export interface PlaybookStateMetadata {
22
+ stateId: string;
23
+ description: string;
24
+ }
25
+ /** Read stable state identity without consulting XState's private `_nodes`. */
26
+ export declare function activePlaybookStateMetadata(snapshot: unknown): readonly PlaybookStateMetadata[];
27
+ export interface SnapshotNormalizationOptions {
28
+ pendingCall?: PlaybookPendingCall;
29
+ }
30
+ export declare function normalizePlaybookSnapshot(snapshot: unknown, options?: SnapshotNormalizationOptions): PlaybookState;
31
+ export declare function detachPersistedMachineSnapshot(persisted: unknown): JsonValue;
32
+ export declare function assertPlaybookRuntimeSnapshot(value: unknown, expectedPlaybookId: string): PlaybookRuntimeSnapshot;
33
+ export interface NestedPlaybookInput {
34
+ stateId: string;
35
+ playbookId: string;
36
+ text: string;
37
+ }
38
+ export interface PlaybookCallStarted {
39
+ callId: string;
40
+ stateId: string;
41
+ playbookId: string;
42
+ text: string;
43
+ }
44
+ export interface PlaybookCallFinished extends PlaybookCallStarted {
45
+ result: PlaybookCallResult;
46
+ }
47
+ export interface NestedPlaybookBridgeOptions {
48
+ nextCallId(): string;
49
+ /** Active public runtime boundary whose abort also owns a new child call. */
50
+ getBoundarySignal?(): AbortSignal | undefined;
51
+ callPlaybook(request: PlaybookCallRequest, signal: AbortSignal): Promise<PlaybookCallStart>;
52
+ emitStarted(event: PlaybookCallStarted): Promise<void>;
53
+ emitFinished(event: PlaybookCallFinished): Promise<void>;
54
+ drain(): Promise<void>;
55
+ bindResumeSignal?(signal: AbortSignal): void;
56
+ onControlPlaneError?(error: unknown): void;
57
+ onBackgroundError?(error: unknown): void;
58
+ }
59
+ export declare class NestedPlaybookCallError extends Error {
60
+ readonly result: PlaybookCallResult;
61
+ constructor(result: PlaybookCallResult);
62
+ }
63
+ export interface PendingCallObserver {
64
+ getPendingCall(): PlaybookPendingCall | undefined;
65
+ subscribePendingCall(listener: (pendingCall: PlaybookPendingCall) => void): () => void;
66
+ }
67
+ export interface NestedPlaybookBridge<TInput extends NestedPlaybookInput = NestedPlaybookInput> extends PendingCallObserver {
68
+ actorLogic: PromiseActorLogic<JsonValue | undefined, TInput>;
69
+ resume(input: {
70
+ callId: string;
71
+ result: PlaybookCallResult;
72
+ signal: AbortSignal;
73
+ }): Promise<void>;
74
+ abortPending(error?: unknown): Promise<void>;
75
+ dispose(): Promise<void>;
76
+ }
77
+ /** Validate, detach, and freeze a host direct-Captain result. */
78
+ export declare function validateCaptainResult(value: unknown, path?: string): CaptainResult;
79
+ /** Validate, detach, and freeze a host delegated-player result. */
80
+ export declare function validatePlayerResult(value: unknown, path?: string): PlayerResult;
81
+ export declare function validatePlaybookCallResult(result: unknown, expectedPlaybookId: string, expectedChildSessionId?: string): PlaybookCallResult;
82
+ export declare function validatePlaybookCallStart(start: unknown, expectedPlaybookId: string): PlaybookCallStart;
83
+ export declare function createNestedPlaybookBridge<TInput extends NestedPlaybookInput = NestedPlaybookInput>(options: NestedPlaybookBridgeOptions): NestedPlaybookBridge<TInput>;
84
+ export interface WaitForPlaybookQuiescenceOptions {
85
+ signal?: AbortSignal;
86
+ timeout?: number;
87
+ pendingCalls?: PendingCallObserver;
88
+ }
89
+ /**
90
+ * Wait at the imperative runtime boundary; workflow waiting remains in XState.
91
+ * A pending-call notification covers the case where the suspended state was
92
+ * entered before its host returned the child session id.
93
+ */
94
+ export declare function waitForPlaybookQuiescence<TActorRef extends AnyActorRef>(actor: TActorRef, options?: WaitForPlaybookQuiescenceOptions): Promise<SnapshotFrom<TActorRef>>;