@sublang/playbook 5.0.0 → 6.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 (65) hide show
  1. package/README.md +11 -7
  2. package/docs/cli.md +38 -35
  3. package/docs/configuration.md +58 -15
  4. package/docs/embedding.md +24 -16
  5. package/package.json +40 -21
  6. package/reference/sdlc/captain.playbook/captain.playbook.js +2 -0
  7. package/reference/sdlc/captain.playbook/captain.playbook.ts +2 -0
  8. package/reference/sdlc/code.md +55 -97
  9. package/reference/sdlc/code.playbook/code.fsm.d.ts +229 -94
  10. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +26 -44
  11. package/reference/sdlc/code.playbook/code.fsm.introspect.js +61 -66
  12. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +100 -149
  13. package/reference/sdlc/code.playbook/code.fsm.js +587 -1347
  14. package/reference/sdlc/code.playbook/code.fsm.ts +809 -1650
  15. package/reference/sdlc/code.playbook/code.gears.md +51 -263
  16. package/reference/sdlc/code.playbook/code.playbook.d.ts +8 -47
  17. package/reference/sdlc/code.playbook/code.playbook.js +69 -656
  18. package/reference/sdlc/code.playbook/code.playbook.ts +90 -867
  19. package/reference/sdlc/code.playbook/code.registry.d.ts +9 -25
  20. package/reference/sdlc/code.playbook/code.registry.js +20 -78
  21. package/reference/sdlc/code.playbook/code.registry.ts +58 -122
  22. package/reference/sdlc/code.playbook/playbook-captain.js +93 -15
  23. package/reference/sdlc/code.playbook/playbook-captain.ts +115 -19
  24. package/reference/sdlc/code.playbook/playbook.config.template.yaml +33 -22
  25. package/reference/sdlc/decide.md +54 -0
  26. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +261 -0
  27. package/reference/sdlc/decide.playbook/decide.fsm.js +894 -0
  28. package/reference/sdlc/decide.playbook/decide.fsm.ts +1152 -0
  29. package/reference/sdlc/decide.playbook/decide.gears.md +88 -0
  30. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +67 -0
  31. package/reference/sdlc/{discuss.playbook/discuss.playbook.js → decide.playbook/decide.playbook.js} +471 -362
  32. package/reference/sdlc/{discuss.playbook/discuss.playbook.ts → decide.playbook/decide.playbook.ts} +575 -443
  33. package/reference/sdlc/decide.playbook/decide.registry.d.ts +41 -0
  34. package/reference/sdlc/decide.playbook/decide.registry.js +60 -0
  35. package/reference/sdlc/decide.playbook/decide.registry.ts +125 -0
  36. package/reference/sdlc/review.md +81 -0
  37. package/reference/sdlc/review.playbook/review.fsm.d.ts +183 -0
  38. package/reference/sdlc/review.playbook/review.fsm.js +524 -0
  39. package/reference/sdlc/review.playbook/review.fsm.ts +652 -0
  40. package/reference/sdlc/review.playbook/review.gears.md +112 -0
  41. package/reference/sdlc/review.playbook/review.playbook.d.ts +12 -0
  42. package/reference/sdlc/review.playbook/review.playbook.js +112 -0
  43. package/reference/sdlc/review.playbook/review.playbook.ts +201 -0
  44. package/reference/sdlc/review.playbook/review.registry.d.ts +43 -0
  45. package/reference/sdlc/review.playbook/review.registry.js +73 -0
  46. package/reference/sdlc/review.playbook/review.registry.ts +138 -0
  47. package/slc/gears2fsm.md +13 -4
  48. package/slc/link.md +48 -2
  49. package/slc/text2gears.md +22 -2
  50. package/src/runtime.d.ts +7 -0
  51. package/src/runtime.ts +12 -0
  52. package/src/xstate-playbook-runtime.d.ts +9 -2
  53. package/src/xstate-playbook-runtime.js +255 -21
  54. package/src/xstate-playbook-runtime.ts +333 -28
  55. package/src/xstate-runtime.js +25 -0
  56. package/src/xstate-runtime.ts +51 -0
  57. package/reference/sdlc/discuss.md +0 -93
  58. package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +0 -396
  59. package/reference/sdlc/discuss.playbook/discuss.fsm.js +0 -2067
  60. package/reference/sdlc/discuss.playbook/discuss.fsm.ts +0 -2465
  61. package/reference/sdlc/discuss.playbook/discuss.gears.md +0 -258
  62. package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +0 -113
  63. package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +0 -58
  64. package/reference/sdlc/discuss.playbook/discuss.registry.js +0 -97
  65. package/reference/sdlc/discuss.playbook/discuss.registry.ts +0 -153
@@ -20,6 +20,7 @@ import type {
20
20
  PlaybookPorts,
21
21
  PlaybookRunResult,
22
22
  PlaybookRuntime,
23
+ PlayerSessionStore,
23
24
  PlaybookState,
24
25
  } from '@sublang/playbook/runtime';
25
26
  import {
@@ -71,7 +72,11 @@ interface Enablement {
71
72
  optionInput: unknown;
72
73
  boundPlayers: readonly RegistryPlayer[];
73
74
  hostPlayerId: (localRole: string) => string;
74
- visiblePlayerIds?: readonly string[];
75
+ }
76
+
77
+ interface EffectivePlayerBinding {
78
+ readonly hostPlayerId: string;
79
+ readonly player: RegistryPlayer;
75
80
  }
76
81
 
77
82
  interface EngagementFrame {
@@ -81,6 +86,8 @@ interface EngagementFrame {
81
86
  sessionId: string;
82
87
  rootSessionId: string;
83
88
  depth: number;
89
+ playerBindings: ReadonlyMap<string, EffectivePlayerBinding>;
90
+ playerResumeTokens: Map<string, string>;
84
91
  parent?: {
85
92
  frame: EngagementFrame;
86
93
  callId: string;
@@ -874,9 +881,6 @@ async function buildEnablements(
874
881
  optionInput: record.options,
875
882
  boundPlayers,
876
883
  hostPlayerId: (localRole) => `${entry.id}-${localRole}`,
877
- visiblePlayerIds: entry.requiredRoleIds.map(
878
- (role) => `${entry.id}-${role}`,
879
- ),
880
884
  });
881
885
  }
882
886
  return { entries, byCommand, byId, enablementById };
@@ -956,6 +960,29 @@ export function createPlaybookCaptainShell(
956
960
  const frameLabel = (frame: EngagementFrame): string =>
957
961
  `/${frame.enablement.command}`;
958
962
 
963
+ const bindingFor = (
964
+ frame: EngagementFrame,
965
+ localRole: string,
966
+ ): EffectivePlayerBinding => {
967
+ const binding = frame.playerBindings.get(localRole);
968
+ if (!binding) {
969
+ throw new Error(
970
+ `${frameLabel(frame)} resolved undeclared player role ${JSON.stringify(localRole)}`,
971
+ );
972
+ }
973
+ return binding;
974
+ };
975
+
976
+ const summaryIncludes = (frame: EngagementFrame): boolean => {
977
+ const owner = activeTurnSummary?.owner;
978
+ if (!owner) return false;
979
+ for (let current: EngagementFrame | undefined = frame; current; ) {
980
+ if (current === owner) return true;
981
+ current = current.parent?.frame;
982
+ }
983
+ return false;
984
+ };
985
+
959
986
  const requireSession = (): CaptainSession => {
960
987
  if (!session) {
961
988
  throw new Error('init must be called first');
@@ -1170,7 +1197,8 @@ export function createPlaybookCaptainShell(
1170
1197
  const previousActiveIds = new Set(frame.state?.activeStateIds ?? []);
1171
1198
  frame.state = state;
1172
1199
 
1173
- if (activeTurnSummary?.owner === frame) {
1200
+ const summary = activeTurnSummary;
1201
+ if (summary && summaryIncludes(frame)) {
1174
1202
  for (const stateId of state.activeStateIds) {
1175
1203
  const newlyActive = !previousActiveIds.has(stateId);
1176
1204
  const structuredEntry =
@@ -1179,9 +1207,9 @@ export function createPlaybookCaptainShell(
1179
1207
  if (!newlyActive && !structuredEntry) continue;
1180
1208
  const countLabel = stateCountLabel(stateId, frame.entry);
1181
1209
  if (countLabel) {
1182
- activeTurnSummary.stateCounts.set(
1210
+ summary.stateCounts.set(
1183
1211
  countLabel,
1184
- (activeTurnSummary.stateCounts.get(countLabel) ?? 0) + 1,
1212
+ (summary.stateCounts.get(countLabel) ?? 0) + 1,
1185
1213
  );
1186
1214
  }
1187
1215
  }
@@ -1213,7 +1241,7 @@ export function createPlaybookCaptainShell(
1213
1241
  }
1214
1242
  const context = activeContext;
1215
1243
  signal.throwIfAborted();
1216
- const hostPlayerId = frame.enablement.hostPlayerId(playerId);
1244
+ const hostPlayerId = bindingFor(frame, playerId).hostPlayerId;
1217
1245
  const result = await trackHostCall(
1218
1246
  frame,
1219
1247
  context.callPlayer(hostPlayerId, prompt, {
@@ -1228,8 +1256,9 @@ export function createPlaybookCaptainShell(
1228
1256
  // CAPTAIN-20: only a player call that actually produced work is an
1229
1257
  // interruption the Boss was spared. A call that errored or aborted
1230
1258
  // saved nothing, so it never feeds the saved-counts gate.
1231
- if (activeTurnSummary?.owner === frame && result.status === 'ok') {
1232
- activeTurnSummary.counts.interruptions++;
1259
+ const summary = activeTurnSummary;
1260
+ if (summary && summaryIncludes(frame) && result.status === 'ok') {
1261
+ summary.counts.interruptions++;
1233
1262
  }
1234
1263
  return {
1235
1264
  status: result.status,
@@ -1289,12 +1318,14 @@ export function createPlaybookCaptainShell(
1289
1318
  throw new Error('callCaptain returned status=ok with no finalText');
1290
1319
  }
1291
1320
  const guard = guardFromJudgeReply(result.finalText);
1321
+ const summary = activeTurnSummary;
1292
1322
  if (
1293
1323
  guard &&
1294
- activeTurnSummary?.owner === frame &&
1324
+ summary &&
1325
+ summaryIncludes(frame) &&
1295
1326
  frame.entry.summaryPolicy?.copyPasteGuardNames.includes(guard)
1296
1327
  ) {
1297
- activeTurnSummary.counts.copyPastes++;
1328
+ summary.counts.copyPastes++;
1298
1329
  }
1299
1330
  return result.finalText;
1300
1331
  },
@@ -1329,8 +1360,10 @@ export function createPlaybookCaptainShell(
1329
1360
  // visibility for that playbook's generated host players. A pane
1330
1361
  // reconciliation failure is display-only in tmux-play and does not
1331
1362
  // reject; the legacy path carries no generated set and skips this.
1332
- const requestVisibility = async (enablement: Enablement): Promise<void> => {
1333
- const ids = enablement.visiblePlayerIds;
1363
+ const requestVisibility = async (frame: EngagementFrame): Promise<void> => {
1364
+ const ids = [...new Set(
1365
+ [...frame.playerBindings.values()].map(({ hostPlayerId }) => hostPlayerId),
1366
+ )];
1334
1367
  if (!ids || ids.length === 0 || !activeContext) return;
1335
1368
  try {
1336
1369
  await activeContext.setVisiblePlayers(ids);
@@ -1375,9 +1408,37 @@ export function createPlaybookCaptainShell(
1375
1408
  ): EngagementFrame => {
1376
1409
  const entry = enablement.entry;
1377
1410
  const sessionId = allocateSessionId();
1411
+ const playerBindings = new Map<string, EffectivePlayerBinding>();
1412
+ for (const role of entry.requiredRoleIds) {
1413
+ let inherited: EffectivePlayerBinding | undefined;
1414
+ for (
1415
+ let ancestor = parent?.frame;
1416
+ ancestor && inherited === undefined;
1417
+ ancestor = ancestor.parent?.frame
1418
+ ) {
1419
+ inherited = ancestor.playerBindings.get(role);
1420
+ }
1421
+ if (inherited) {
1422
+ playerBindings.set(role, inherited);
1423
+ continue;
1424
+ }
1425
+ const configured = enablement.boundPlayers.find(
1426
+ (player) => player.id === role,
1427
+ ) ?? { id: role };
1428
+ playerBindings.set(role, {
1429
+ hostPlayerId: enablement.hostPlayerId(role),
1430
+ player: configured,
1431
+ });
1432
+ }
1433
+ const playerResumeTokens =
1434
+ parent?.frame.playerResumeTokens ?? new Map<string, string>();
1378
1435
  const runtime = entry.createRuntime({
1379
1436
  captainOptions: enablement.optionInput,
1380
- players: enablement.boundPlayers,
1437
+ players: [...playerBindings].map(([role, { player }]) => ({
1438
+ id: role,
1439
+ ...(player.adapter === undefined ? {} : { adapter: player.adapter }),
1440
+ ...(player.model === undefined ? {} : { model: player.model }),
1441
+ })),
1381
1442
  });
1382
1443
  return {
1383
1444
  entry,
@@ -1386,11 +1447,45 @@ export function createPlaybookCaptainShell(
1386
1447
  sessionId,
1387
1448
  rootSessionId: parent?.frame.rootSessionId ?? sessionId,
1388
1449
  depth: parent ? parent.frame.depth + 1 : 0,
1450
+ playerBindings,
1451
+ playerResumeTokens,
1389
1452
  ...(parent ? { parent } : {}),
1390
1453
  inFlightHostCalls: new Set(),
1391
1454
  };
1392
1455
  };
1393
1456
 
1457
+ const playerSessionStore = (frame: EngagementFrame): PlayerSessionStore => ({
1458
+ select(playerId) {
1459
+ const binding = bindingFor(frame, playerId);
1460
+ return frame.playerResumeTokens.get(binding.hostPlayerId) ?? false;
1461
+ },
1462
+ update(playerId, resumeToken) {
1463
+ const binding = bindingFor(frame, playerId);
1464
+ if (resumeToken === undefined) {
1465
+ frame.playerResumeTokens.delete(binding.hostPlayerId);
1466
+ } else {
1467
+ frame.playerResumeTokens.set(binding.hostPlayerId, resumeToken);
1468
+ }
1469
+ },
1470
+ snapshot() {
1471
+ const tokens: Record<string, string> = {};
1472
+ for (const [playerId, binding] of frame.playerBindings) {
1473
+ const token = frame.playerResumeTokens.get(binding.hostPlayerId);
1474
+ if (token !== undefined) tokens[playerId] = token;
1475
+ }
1476
+ return tokens;
1477
+ },
1478
+ restore(tokens) {
1479
+ for (const binding of frame.playerBindings.values()) {
1480
+ frame.playerResumeTokens.delete(binding.hostPlayerId);
1481
+ }
1482
+ for (const [playerId, token] of Object.entries(tokens)) {
1483
+ const binding = bindingFor(frame, playerId);
1484
+ frame.playerResumeTokens.set(binding.hostPlayerId, token);
1485
+ }
1486
+ },
1487
+ });
1488
+
1394
1489
  const initFrame = async (frame: EngagementFrame): Promise<void> => {
1395
1490
  await frame.runtime.init({
1396
1491
  sessionId: frame.sessionId,
@@ -1403,6 +1498,7 @@ export function createPlaybookCaptainShell(
1403
1498
  }
1404
1499
  : {}),
1405
1500
  depth: frame.depth,
1501
+ playerSessions: playerSessionStore(frame),
1406
1502
  ports: createPorts(frame),
1407
1503
  });
1408
1504
  };
@@ -1599,7 +1695,7 @@ export function createPlaybookCaptainShell(
1599
1695
  }
1600
1696
  let visibilityError: unknown;
1601
1697
  try {
1602
- await requestVisibility(parent.enablement);
1698
+ await requestVisibility(parent);
1603
1699
  } catch (error) {
1604
1700
  visibilityError = error;
1605
1701
  }
@@ -1720,7 +1816,7 @@ export function createPlaybookCaptainShell(
1720
1816
  // boundary — a `setVisiblePlayers` or telemetry rejection here leaves the
1721
1817
  // runtime uninvoked and owes the Boss the CAPTAIN-34 reply rather than an
1722
1818
  // exception filed against an effect that never ran.
1723
- await requestVisibility(frame.enablement);
1819
+ await requestVisibility(frame);
1724
1820
  await setMode('engaged.driving', 'submit');
1725
1821
  const result = await runEffect(() =>
1726
1822
  frame.runtime.handleBossInput({ text, signal }),
@@ -1867,7 +1963,7 @@ export function createPlaybookCaptainShell(
1867
1963
  cleanupError = error;
1868
1964
  }
1869
1965
  if (frames.includes(parent)) {
1870
- await requestVisibility(parent.enablement);
1966
+ await requestVisibility(parent);
1871
1967
  }
1872
1968
  if (cleanupError !== undefined) throw cleanupError;
1873
1969
  };
@@ -2005,7 +2101,7 @@ export function createPlaybookCaptainShell(
2005
2101
  }
2006
2102
  if (frames.includes(parent)) {
2007
2103
  try {
2008
- await requestVisibility(parent.enablement);
2104
+ await requestVisibility(parent);
2009
2105
  } catch (visibilityError) {
2010
2106
  visibilityControlFailure = true;
2011
2107
  boundaryError = new AggregateError(
@@ -20,7 +20,7 @@
20
20
  # Every seeded agent runs in cligent's protected auto mode
21
21
  # (permissions.mode: auto): claude maps it to permissionMode auto, codex to
22
22
  # on-request + auto_review. Codex roles also grant writablePaths: ['.git']
23
- # so commit turns can write git metadata under the codex sandbox.
23
+ # so they can inspect and work with repository metadata under the sandbox.
24
24
 
25
25
  # The Captain/Judge agent.
26
26
  # Captain routing/adjudication calls run tool-free. Claude enforces that at
@@ -40,11 +40,25 @@ notifications:
40
40
 
41
41
  # Enabled playbooks. Each is loaded from its explicit `from` module; the
42
42
  # `<id>` key must equal that module's manifest id. `from`, `command`, and
43
- # `players` are launcher-owned; every other key (e.g. CODE's `committer`)
44
- # is that playbook's option slice.
43
+ # `players` are launcher-owned; every other key is that playbook's option
44
+ # slice.
45
+ #
46
+ # Nested calls map roles by exact id. CODE and DECIDE call REVIEW with the
47
+ # same `coder` and `reviewer` ids, so those child roles continue the nearest
48
+ # ancestor sessions. A standalone REVIEW uses its own bindings below.
45
49
  playbooks:
46
50
  code:
47
51
  from: "@sublang/playbook/code/registry"
52
+ players:
53
+ coder:
54
+ adapter: claude
55
+ model: claude-opus-4-8[1m]
56
+ effort: xhigh
57
+ permissions:
58
+ mode: auto
59
+
60
+ review:
61
+ from: "@sublang/playbook/review/registry"
48
62
  players:
49
63
  coder:
50
64
  adapter: claude
@@ -59,26 +73,23 @@ playbooks:
59
73
  permissions:
60
74
  mode: auto
61
75
  writablePaths: ['.git']
62
- committer: coder
63
76
 
64
- # The DISCUSS playbook: two agents converge on spec items or decision
65
- # records. `committer` picks which player runs Committer commits
66
- # (default: host).
67
- # discuss:
68
- # from: "@sublang/playbook/discuss/registry"
69
- # players:
70
- # host:
71
- # adapter: claude
72
- # model: claude-opus-4-8
73
- # permissions:
74
- # mode: auto
75
- # participant:
76
- # adapter: codex
77
- # model: gpt-5.5
78
- # permissions:
79
- # mode: auto
80
- # writablePaths: ['.git']
81
- # committer: host
77
+ decide:
78
+ from: "@sublang/playbook/decide/registry"
79
+ players:
80
+ coder:
81
+ adapter: claude
82
+ model: claude-opus-4-8[1m]
83
+ effort: xhigh
84
+ permissions:
85
+ mode: auto
86
+ reviewer:
87
+ adapter: codex
88
+ model: gpt-5.5
89
+ effort: xhigh
90
+ permissions:
91
+ mode: auto
92
+ writablePaths: ['.git']
82
93
 
83
94
  # Non-interactive `playbook run` defaults (optional). Each value is an
84
95
  # agent string <adapter>[:<model>][@<effort>]; `player` is the catch-all
@@ -0,0 +1,54 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
3
+ <!-- AI agents: do not edit this file without human approval. -->
4
+
5
+ # Decide
6
+
7
+ Players:
8
+
9
+ - Coder
10
+ - Reviewer
11
+
12
+ The caller supplies the topic including any specific context.
13
+
14
+ When the caller gives a topic, Captain shall relay the complete topic in quotes (`>`) to Coder and Reviewer concurrently and independently.
15
+ Captain shall not wait for either proposal before requesting the other.
16
+ Captain shall give each player the following instruction:
17
+
18
+ ```markdown
19
+ Assess whether the topic is better expressed as a few spec items under @specs/packages/ or requires one or more DRs under @specs/decisions/.
20
+ Propose your design.
21
+ Keep your proposal coherent, focused, and concise.
22
+ Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.
23
+ Do not change any files.
24
+ ```
25
+
26
+ Neither player shall receive the other's proposal until both proposals are complete and Coder has committed Coder's own proposal.
27
+ A Boss interrupt during the parallel proposal pair shall restart the whole pair so both players receive the same new topic and remain independent.
28
+
29
+ When both proposals are complete, Captain shall then give Coder the following instruction:
30
+
31
+ ```markdown
32
+ Turn your proposal into the necessary spec items or DRs.
33
+ Follow @specs/meta.md and update @specs/map.md when needed.
34
+ Do not inspect or incorporate Reviewer's proposal before this commit.
35
+ Do not change code or implement the proposal.
36
+
37
+ Commit the result as one new commit, following @specs/packages/git.md.
38
+ Make the commit message explain concisely what changed and why.
39
+ Report it as exactly one final-response line beginning `Commit: `, followed only by the exact commit identity.
40
+ Coder is <coder-llm>; format the model token in conventional human form.
41
+ ```
42
+
43
+ After Coder commits, Captain shall call playbook `review`:
44
+
45
+ > Review the latest commit as a spec-design change against the initial intent.
46
+ > Compare it with your independent proposal and take the best of both.
47
+ > Make your suggestions.
48
+ >
49
+ > Initial intent: \<caller-topic\>.
50
+ > Coder's independent proposal: \<coder-proposal\>.
51
+
52
+ `decide` is complete when `review` returns the approved latest commit and the fact that no unsettled findings remain.
53
+ When `review` returns an authored abort or failure, or a terminal result that does not prove exact approval, `decide` shall report the failure and the last `decide`-owned commit to its caller.
54
+ When the nested `review` call fails outside that authored result contract, `decide` shall park as failed and retain the control-plane error instead of reporting an authored review outcome.
@@ -0,0 +1,261 @@
1
+ export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
2
+ readonly [key: string]: JsonValue;
3
+ };
4
+ type Player = 'Coder' | 'Reviewer';
5
+ type JumpableStateId = 'independentProposals';
6
+ type ResumableStateId = 'askCoderProposal' | 'askReviewerProposal' | 'commitCoderProposal';
7
+ export interface PendingBossQuestion {
8
+ questionId: ResumableStateId;
9
+ resumeStateId: ResumableStateId;
10
+ sourceItem: string;
11
+ player: Player;
12
+ question: string;
13
+ }
14
+ type PendingBossQuestions = Partial<Record<ResumableStateId, PendingBossQuestion>>;
15
+ type BossReplies = Partial<Record<ResumableStateId, string>>;
16
+ type PendingBossQuestionParams = Omit<PendingBossQuestion, 'questionId'>;
17
+ export interface ReviewSuccessOutput {
18
+ approvedCommit: 'latest';
19
+ noUnsettledFindings: true;
20
+ }
21
+ export interface DecideFailureOutput {
22
+ lastDecideCommit: string;
23
+ noUnsettledFindings: false;
24
+ reviewStatus: 'aborted' | 'error';
25
+ error?: {
26
+ name: string;
27
+ message: string;
28
+ };
29
+ }
30
+ export type DecideOutput = ReviewSuccessOutput | DecideFailureOutput;
31
+ interface ChildFailure {
32
+ status: 'aborted' | 'error';
33
+ playbookId: 'review';
34
+ error?: {
35
+ name: string;
36
+ message: string;
37
+ };
38
+ }
39
+ export interface DecideContext {
40
+ coderLlm: string;
41
+ callerTopic?: string;
42
+ coderProposal?: string;
43
+ reviewerProposal?: string;
44
+ latestCommit?: string;
45
+ reviewResult?: ReviewSuccessOutput;
46
+ reviewFailure?: ChildFailure;
47
+ lastResult?: PlayerOutput;
48
+ lastError?: unknown;
49
+ pendingBossQuestions?: PendingBossQuestions;
50
+ bossReplies?: BossReplies;
51
+ stagedCoderResult?: PlayerOutput;
52
+ stagedReviewerResult?: PlayerOutput;
53
+ }
54
+ export type DecideEvent = {
55
+ type: 'START_DECIDE';
56
+ callerTopic: string;
57
+ } | {
58
+ type: 'BOSS_INTERRUPT';
59
+ targetId: JumpableStateId;
60
+ bossIntent: string;
61
+ } | {
62
+ type: 'BOSS_REPLY';
63
+ questionId?: ResumableStateId;
64
+ answer: string;
65
+ };
66
+ export interface DecideInput {
67
+ coderLlm: string;
68
+ }
69
+ export interface PlayerInput {
70
+ stateId: ResumableStateId;
71
+ sourceItem: string;
72
+ prompt: string;
73
+ result: Record<string, string>;
74
+ player: Player;
75
+ callerTopic?: string;
76
+ coderLlm?: string;
77
+ pendingBossQuestion?: PendingBossQuestion;
78
+ bossReply?: string;
79
+ }
80
+ type AdditionalPlayerFields = {
81
+ coderProposal?: string;
82
+ reviewerProposal?: string;
83
+ coderOutput?: string;
84
+ latestCommit?: string;
85
+ question?: string;
86
+ readonly [key: string]: unknown;
87
+ };
88
+ export type PlayerOutput = ({
89
+ guard: 'proposed';
90
+ coderProposal: string;
91
+ } & AdditionalPlayerFields) | ({
92
+ guard: 'proposed';
93
+ reviewerProposal: string;
94
+ } & AdditionalPlayerFields) | ({
95
+ guard: 'committed';
96
+ coderOutput: string;
97
+ latestCommit: string;
98
+ } & AdditionalPlayerFields) | ({
99
+ guard: 'needsBossReply';
100
+ question: string;
101
+ } & AdditionalPlayerFields);
102
+ export interface PlaybookInput {
103
+ stateId: 'reviewCommit';
104
+ sourceItem: 'DECIDE-4';
105
+ playbookId: 'review';
106
+ text: string;
107
+ }
108
+ export declare const decideMachine: import("xstate").StateMachine<DecideContext, {
109
+ type: "START_DECIDE";
110
+ callerTopic: string;
111
+ } | {
112
+ type: "BOSS_INTERRUPT";
113
+ targetId: JumpableStateId;
114
+ bossIntent: string;
115
+ } | {
116
+ type: "BOSS_REPLY";
117
+ questionId?: ResumableStateId;
118
+ answer: string;
119
+ }, {
120
+ [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<JsonValue | undefined, PlaybookInput, import("xstate").EventObject>> | import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>> | undefined;
121
+ }, {
122
+ src: "playbook";
123
+ logic: import("xstate").PromiseActorLogic<JsonValue | undefined, PlaybookInput, import("xstate").EventObject>;
124
+ id: string | undefined;
125
+ } | {
126
+ src: "player";
127
+ logic: import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>;
128
+ id: string | undefined;
129
+ }, {
130
+ type: "rememberActorError";
131
+ params: import("xstate").NonReducibleUnknown;
132
+ } | {
133
+ type: "rememberBossReply";
134
+ params: import("xstate").NonReducibleUnknown;
135
+ } | {
136
+ type: "clearBossReplyContext";
137
+ params: import("xstate").NonReducibleUnknown;
138
+ } | {
139
+ type: "copyInterruptedTopic";
140
+ params: import("xstate").NonReducibleUnknown;
141
+ } | {
142
+ type: "copyStartTopic";
143
+ params: import("xstate").NonReducibleUnknown;
144
+ } | {
145
+ type: "stageCoderProposal";
146
+ params: import("xstate").NonReducibleUnknown;
147
+ } | {
148
+ type: "stageReviewerProposal";
149
+ params: import("xstate").NonReducibleUnknown;
150
+ } | {
151
+ type: "promoteProposals";
152
+ params: import("xstate").NonReducibleUnknown;
153
+ } | {
154
+ type: "rememberCommit";
155
+ params: import("xstate").NonReducibleUnknown;
156
+ } | {
157
+ type: "rememberReviewSuccess";
158
+ params: import("xstate").NonReducibleUnknown;
159
+ } | {
160
+ type: "rememberReviewFailure";
161
+ params: import("xstate").NonReducibleUnknown;
162
+ } | {
163
+ type: "rememberReviewProtocolFailure";
164
+ params: import("xstate").NonReducibleUnknown;
165
+ } | {
166
+ type: "rememberMalformedActorOutput";
167
+ params: import("xstate").NonReducibleUnknown;
168
+ } | {
169
+ type: "rememberMalformedBossReply";
170
+ params: import("xstate").NonReducibleUnknown;
171
+ } | {
172
+ type: "setPendingBossQuestion";
173
+ params: PendingBossQuestionParams;
174
+ } | {
175
+ type: "clearBranchBossReplyContext";
176
+ params: {
177
+ stateId: ResumableStateId;
178
+ };
179
+ } | {
180
+ type: "clearProposalRoundContext";
181
+ params: import("xstate").NonReducibleUnknown;
182
+ }, {
183
+ type: "authoredReviewFailure";
184
+ params: unknown;
185
+ } | {
186
+ type: "committed";
187
+ params: unknown;
188
+ } | {
189
+ type: "coderProposed";
190
+ params: unknown;
191
+ } | {
192
+ type: "reviewerProposed";
193
+ params: unknown;
194
+ } | {
195
+ type: "needsBossReplyWithQuestion";
196
+ params: unknown;
197
+ } | {
198
+ type: "needsBossReplyWithoutQuestion";
199
+ params: unknown;
200
+ } | {
201
+ type: "validReviewSuccess";
202
+ params: unknown;
203
+ }, never, "done" | "failed" | "awaitBossReply" | "ready" | "commitCoderProposal" | "reviewCommit" | "reportedReviewFailure" | {
204
+ independentProposals: {
205
+ coder: "complete" | "working" | "waiting";
206
+ reviewer: "complete" | "working" | "waiting";
207
+ };
208
+ }, string, DecideInput, ReviewSuccessOutput | DecideFailureOutput, import("xstate").EventObject, import("xstate").MetaObject, {
209
+ id: "decide";
210
+ states: {
211
+ readonly ready: {
212
+ id: "ready";
213
+ };
214
+ readonly independentProposals: {
215
+ id: "independentProposals";
216
+ states: {
217
+ readonly coder: {
218
+ states: {
219
+ readonly working: {
220
+ id: "askCoderProposal";
221
+ };
222
+ readonly waiting: {
223
+ id: "waitCoderProposalReply";
224
+ };
225
+ readonly complete: {};
226
+ };
227
+ };
228
+ readonly reviewer: {
229
+ states: {
230
+ readonly working: {
231
+ id: "askReviewerProposal";
232
+ };
233
+ readonly waiting: {
234
+ id: "waitReviewerProposalReply";
235
+ };
236
+ readonly complete: {};
237
+ };
238
+ };
239
+ };
240
+ };
241
+ readonly commitCoderProposal: {
242
+ id: "commitCoderProposal";
243
+ };
244
+ readonly awaitBossReply: {
245
+ id: "awaitBossReply";
246
+ };
247
+ readonly reviewCommit: {
248
+ id: "reviewCommit";
249
+ };
250
+ readonly failed: {
251
+ id: "failed";
252
+ };
253
+ readonly reportedReviewFailure: {
254
+ id: "reportedReviewFailure";
255
+ };
256
+ readonly done: {
257
+ id: "done";
258
+ };
259
+ };
260
+ }>;
261
+ export default decideMachine;