@sublang/playbook 10.0.0 → 11.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.
- package/README.md +1 -1
- package/docs/cli.md +58 -13
- package/docs/configuration.md +89 -40
- package/docs/embedding.md +88 -0
- package/package.json +9 -2
- package/reference/sdlc/code.md +35 -15
- package/reference/sdlc/code.playbook/bin/interactive-session.js +58 -6
- package/reference/sdlc/code.playbook/bin/launch-config.js +499 -241
- package/reference/sdlc/code.playbook/bin/playbook.js +236 -187
- package/reference/sdlc/code.playbook/bin/replay-observer.js +221 -0
- package/reference/sdlc/code.playbook/bin/run.js +355 -203
- package/reference/sdlc/code.playbook/bin/session-store.js +1512 -136
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +4 -1
- package/reference/sdlc/code.playbook/playbook-captain.js +21 -3
- package/reference/sdlc/code.playbook/playbook-captain.ts +42 -6
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +14 -10
- package/reference/sdlc/code.playbook/session-store.d.ts +82 -0
- package/reference/sdlc/code.playbook/session-store.js +113 -0
- package/reference/sdlc/decide.md +24 -15
- package/reference/sdlc/review.md +36 -18
|
@@ -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
|
-
|
|
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
|
-
|
|
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:
|
|
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(
|