@sublang/playbook 10.0.0 → 12.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 (59) hide show
  1. package/README.md +1 -1
  2. package/docs/cli.md +67 -19
  3. package/docs/configuration.md +103 -40
  4. package/docs/embedding.md +88 -0
  5. package/package.json +30 -4
  6. package/reference/sdlc/code.md +35 -15
  7. package/reference/sdlc/code.playbook/bin/interactive-session.js +58 -6
  8. package/reference/sdlc/code.playbook/bin/launch-config.js +499 -241
  9. package/reference/sdlc/code.playbook/bin/playbook.js +236 -187
  10. package/reference/sdlc/code.playbook/bin/replay-observer.js +221 -0
  11. package/reference/sdlc/code.playbook/bin/run.js +355 -203
  12. package/reference/sdlc/code.playbook/bin/session-store.js +1512 -136
  13. package/reference/sdlc/code.playbook/code.fsm.d.ts +22 -19
  14. package/reference/sdlc/code.playbook/code.fsm.js +116 -52
  15. package/reference/sdlc/code.playbook/code.fsm.ts +149 -64
  16. package/reference/sdlc/code.playbook/code.gears.md +40 -20
  17. package/reference/sdlc/code.playbook/code.playbook.js +23 -2
  18. package/reference/sdlc/code.playbook/code.playbook.ts +23 -2
  19. package/reference/sdlc/code.playbook/playbook-captain.d.ts +4 -1
  20. package/reference/sdlc/code.playbook/playbook-captain.js +21 -3
  21. package/reference/sdlc/code.playbook/playbook-captain.ts +42 -6
  22. package/reference/sdlc/code.playbook/playbook.config.template.yaml +31 -11
  23. package/reference/sdlc/code.playbook/session-store.d.ts +82 -0
  24. package/reference/sdlc/code.playbook/session-store.js +113 -0
  25. package/reference/sdlc/decide.md +24 -15
  26. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +13 -6
  27. package/reference/sdlc/decide.playbook/decide.fsm.js +54 -27
  28. package/reference/sdlc/decide.playbook/decide.fsm.ts +68 -29
  29. package/reference/sdlc/decide.playbook/decide.gears.md +25 -19
  30. package/reference/sdlc/decide.playbook/decide.playbook.js +11 -3
  31. package/reference/sdlc/decide.playbook/decide.playbook.ts +11 -3
  32. package/reference/sdlc/decide.playbook/decide.registry.js +1 -1
  33. package/reference/sdlc/decide.playbook/decide.registry.ts +1 -1
  34. package/reference/sdlc/dev.md +52 -0
  35. package/reference/sdlc/dev.playbook/dev.fsm.d.ts +261 -0
  36. package/reference/sdlc/dev.playbook/dev.fsm.js +723 -0
  37. package/reference/sdlc/dev.playbook/dev.fsm.ts +988 -0
  38. package/reference/sdlc/dev.playbook/dev.gears.md +91 -0
  39. package/reference/sdlc/dev.playbook/dev.playbook.d.ts +21 -0
  40. package/reference/sdlc/dev.playbook/dev.playbook.js +143 -0
  41. package/reference/sdlc/dev.playbook/dev.playbook.ts +246 -0
  42. package/reference/sdlc/dev.playbook/dev.registry.d.ts +40 -0
  43. package/reference/sdlc/dev.playbook/dev.registry.js +64 -0
  44. package/reference/sdlc/dev.playbook/dev.registry.ts +120 -0
  45. package/reference/sdlc/review.md +36 -18
  46. package/reference/sdlc/review.playbook/review.fsm.d.ts +15 -2
  47. package/reference/sdlc/review.playbook/review.fsm.js +77 -27
  48. package/reference/sdlc/review.playbook/review.fsm.ts +96 -30
  49. package/reference/sdlc/review.playbook/review.gears.md +52 -26
  50. package/reference/sdlc/review.playbook/review.playbook.js +17 -7
  51. package/reference/sdlc/review.playbook/review.playbook.ts +17 -7
  52. package/reference/sdlc/review.playbook/review.registry.js +1 -1
  53. package/reference/sdlc/review.playbook/review.registry.ts +1 -1
  54. package/slc/link.md +12 -5
  55. package/slc/text2gears.md +3 -0
  56. package/src/xstate-playbook-runtime.js +5 -2
  57. package/src/xstate-playbook-runtime.ts +5 -2
  58. package/src/xstate-runtime.js +13 -1
  59. package/src/xstate-runtime.ts +13 -1
@@ -8,35 +8,44 @@ Roles:
8
8
 
9
9
  - Coder
10
10
 
11
- The caller supplies the coding intent including any specific context.
11
+ The caller supplies a coding request together with any relevant context.
12
12
 
13
- A coding intent follows either one direct implementation phase or an IR sequence consisting of a new-IR phase and one phase for each IR task.
13
+ A new coding intent follows either one direct implementation phase or an IR sequence consisting of a new-IR phase followed by one phase for each IR task.
14
+ An existing IR follows one IR-task phase for each remaining unfinished task, starting with its next unfinished task.
14
15
  Each phase ends with one new Coder commit (owned by `code`).
15
16
  After each `code`-owned commit, Captain shall call the `review` playbook and wait until it passes with no unsettled findings.
16
17
  Playbook `review` owns every review round and every review-fix commit.
17
- Do not amend any reviewed commit.
18
+ Do not rewrite any existing commit.
18
19
 
19
20
  When `review` passes a direct implementation phase, `code` is complete.
20
21
  When `review` passes a new IR or a nonfinal IR-task phase, Captain shall continue with the next unfinished IR-task phase.
21
22
  When `review` passes the final IR-task phase, `code` is complete.
22
- When `review` returns an authored abort or failure, or a terminal result that does not prove exact approval, `code` shall start no further phase and shall report the failure and the last `code`-owned commit to its caller.
23
+ When `review` returns an authored abort or failure, or a terminal result that does not establish that the supplied scope was evaluated with no unsettled findings, `code` shall start no further phase and shall report the failure and the last `code`-owned commit to its caller.
23
24
  When the nested `review` call fails outside that authored result contract, `code` shall park as failed and retain the control-plane error instead of reporting an authored review outcome.
24
25
 
25
26
  At the start of the first phase, Captain shall relay to Coder the complete caller input and any relevant run results in quotes (`>`), along with the following instruction:
26
27
 
27
28
  ```markdown
28
- Assess whether the coding intent can be completed well in one commit.
29
- If yes, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.
30
- Otherwise, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.
29
+ First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.
30
+ If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.
31
+
32
+ For a new coding intent, assess whether it can be completed well in one commit.
33
+ If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.
34
+ If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.
31
35
  Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.
32
36
 
37
+ For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
38
+ Do not implement a later task in this phase.
39
+ Mark the IR's progress and deliverables when relevant.
40
+ If the IR will be finished after this phase, double-check that all acceptance criteria are met.
41
+
33
42
  Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.
34
43
  ```
35
44
 
36
- At the start of every IR-task phase, Captain shall relay to Coder the exact next task and any relevant run results in quotes (`>`), along with the following instruction:
45
+ At the start of every later IR-task phase, Captain shall relay to Coder the original caller input, the IR identity, and any relevant run results in quotes (`>`), along with the following instruction:
37
46
 
38
47
  ```markdown
39
- Read IR-<#> and implement exactly the next unfinished task, including corresponding tests or specs if any.
48
+ Read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
40
49
  Do not implement a later task in this phase.
41
50
  Mark the IR's progress and deliverables when relevant.
42
51
  If the IR will be finished after this phase, double-check that all acceptance criteria are met.
@@ -45,18 +54,29 @@ If the IR will be finished after this phase, double-check that all acceptance cr
45
54
  At the start of *every* phase, Captain shall append the following instruction:
46
55
 
47
56
  ```markdown
57
+ Keep to the original intent and follow what it asks.
48
58
  Do not re-run tests or builds whose inputs have not changed since any previous reported run.
49
59
  Make the phase's minimal changes and then one new commit, following @specs/packages/git.md; never amend an existing commit.
50
60
  Make the commit message explain concisely what changed and why, including relevant verification.
51
- Coder is <coder-llm>; format the model token in conventional human form.
61
+ Identify every new commit you make.
62
+ Coder is <coder-llm>.
52
63
  ```
53
64
 
54
- After the first phase (either direct implementation or a new-IR phase), Captain shall call playbook `review` and input the following in quotes (`>`):
65
+ Every new-intent phase has two semantic outcomes: direct implementation and new IR; the new-IR outcome identifies the created IR.
66
+ Every IR-task phase, including the first phase for an existing IR, identifies the IR and the implemented task, and has two semantic outcomes: more tasks and final task.
67
+ The first phase therefore has four semantic outcomes — direct implementation, new IR, more tasks, and final task — plus the Boss question when the continued IR is ambiguous.
68
+ Each semantic outcome requires affirmative support in Coder's result, but no phase transition shall depend on a fixed presentation format of Coder's reply.
69
+ Captain shall use the repository-effect receipt as the authoritative identity of the phase's new commit.
70
+
71
+ At the end of every phase, Captain shall call playbook `review` and input the following in quotes (`>`):
55
72
 
56
- > Initial intent: \<caller-input\>
73
+ > Original intent: \<caller-input\>
74
+ > Review scope: the commit \<code-commit\> from this coding phase and its resulting repository state.
57
75
  > Coder output: \<coder-output\>
58
76
 
59
- After every IR-task phase, Captain shall call playbook `review` and input the following in quotes (`>`):
77
+ For an IR-task phase, Captain shall additionally input the following in quotes (`>`):
60
78
 
61
- > IR task: \<ir-task\>
62
- > Coder output: \<coder-output\>
79
+ > Current IR task: \<ir-task\>
80
+
81
+ A nested `review` passes the phase only when its result applies to that supplied review scope, returns the exact evaluated repository revision, and affirmatively establishes that no unsettled findings remain.
82
+ On successful completion, `code` returns the exact last `code`-owned commit, the exact final evaluated repository revision, and the fact that every phase's review passed with no unsettled findings.
@@ -35,6 +35,10 @@ import {
35
35
  validateFrozenExecutionConfig,
36
36
  } from './run.js';
37
37
  import { prepareConfiguredRegistries } from './provision.js';
38
+ import {
39
+ createReplayRecordObserver,
40
+ replayIncompleteMessage,
41
+ } from './replay-observer.js';
38
42
  import {
39
43
  assertCaptainSessionExecutionCompatible,
40
44
  createCaptainSessionStore,
@@ -86,10 +90,7 @@ export function validateManagedInteractivePayload(value) {
86
90
  }
87
91
  assertUuid(value.sessionId, 'managed interactive session id');
88
92
  assertCanonicalAbsolutePath(value.cwd, 'managed interactive working directory');
89
- assertCanonicalAbsolutePath(
90
- value.sessionsDir,
91
- 'managed interactive sessions directory',
92
- );
93
+ assertAbsolutePath(value.sessionsDir, 'managed interactive sessions directory');
93
94
  if (typeof value.noProvision !== 'boolean') {
94
95
  throw new Error('managed interactive noProvision must be a boolean');
95
96
  }
@@ -317,11 +318,19 @@ export function createManagedInteractiveLifecycle(payloadValue, options = {}) {
317
318
  let activeTurn;
318
319
  let executionProjection;
319
320
  let freshLaunchRecord;
321
+ let replayChannel;
320
322
 
321
323
  const release = async () => {
322
324
  if (released || lease === undefined) return;
323
325
  const owned = lease;
324
- await owned.release();
326
+ let status;
327
+ try {
328
+ status = await owned.release();
329
+ } catch (error) {
330
+ await replayChannel?.reportIfIncomplete();
331
+ throw error;
332
+ }
333
+ await replayChannel?.reportIfIncomplete(status);
325
334
  if (lease === owned) lease = undefined;
326
335
  released = true;
327
336
  };
@@ -369,6 +378,11 @@ export function createManagedInteractiveLifecycle(payloadValue, options = {}) {
369
378
  let host;
370
379
  try {
371
380
  lease = await store.acquire(payload.sessionId);
381
+ replayChannel = createManagedReplayChannel({
382
+ lease,
383
+ sessionId: payload.sessionId,
384
+ presentationGate: context.observers[0],
385
+ });
372
386
  const authoritative =
373
387
  typeof lease.recoverUnresolvedEffectAbandonment === 'function'
374
388
  ? await lease.recoverUnresolvedEffectAbandonment()
@@ -435,7 +449,12 @@ export function createManagedInteractiveLifecycle(payloadValue, options = {}) {
435
449
  cwd: payload.cwd,
436
450
  sessionLease: lease,
437
451
  loadModule,
438
- observers: context.observers,
452
+ observers: [
453
+ ...context.observers,
454
+ ...(replayChannel === undefined
455
+ ? []
456
+ : [replayChannel.observer]),
457
+ ],
439
458
  ...(options.adapterImports
440
459
  ? { adapterImports: options.adapterImports }
441
460
  : {}),
@@ -491,6 +510,7 @@ export function createManagedInteractiveLifecycle(payloadValue, options = {}) {
491
510
  retainedGenerations,
492
511
  reconcileRepositoryEffects: created.reconcileRepositoryEffects,
493
512
  });
513
+ await replayChannel?.reportIfIncomplete();
494
514
  initialized = true;
495
515
  return {
496
516
  abortActiveTurn: (...args) => host.abortActiveTurn(...args),
@@ -600,6 +620,7 @@ export function createManagedInteractiveLifecycle(payloadValue, options = {}) {
600
620
  unresolvedEffects: settlement.unresolvedEffects,
601
621
  retentionUpdates: settlement.retentionUpdates,
602
622
  });
623
+ await replayChannel?.reportIfIncomplete();
603
624
  activeTurn = undefined;
604
625
  },
605
626
 
@@ -631,6 +652,31 @@ export function createManagedInteractiveLifecycle(payloadValue, options = {}) {
631
652
  });
632
653
  }
633
654
 
655
+ function createManagedReplayChannel({
656
+ lease,
657
+ sessionId,
658
+ presentationGate,
659
+ }) {
660
+ if (
661
+ typeof lease?.append !== 'function' ||
662
+ typeof lease?.streamStatus !== 'function'
663
+ ) {
664
+ return undefined;
665
+ }
666
+ return createReplayRecordObserver({
667
+ lease,
668
+ async onIncomplete() {
669
+ if (typeof presentationGate?.onRecord !== 'function') return;
670
+ await presentationGate.onRecord({
671
+ type: 'captain_status',
672
+ turnId: null,
673
+ timestamp: Date.now(),
674
+ message: replayIncompleteMessage(sessionId),
675
+ });
676
+ },
677
+ });
678
+ }
679
+
634
680
  async function writeManagedInteractiveReadinessClaim({
635
681
  workDir,
636
682
  sessionId,
@@ -912,6 +958,12 @@ function assertCanonicalAbsolutePath(value, path) {
912
958
  }
913
959
  }
914
960
 
961
+ function assertAbsolutePath(value, path) {
962
+ if (typeof value !== 'string' || !isAbsolute(value)) {
963
+ throw new Error(`${path} must be an absolute path`);
964
+ }
965
+ }
966
+
915
967
  function assertManagedDescriptorPath(path) {
916
968
  if (basename(path) !== MANAGED_INTERACTIVE_PAYLOAD_FILE) {
917
969
  throw new Error(