@sublang/playbook 0.4.2 → 0.6.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 +42 -19
- package/package.json +18 -6
- package/reference/sdlc/code.playbook/bin/playbook-code.js +277 -104
- package/reference/sdlc/code.playbook/code.fsm.d.ts +1 -0
- package/reference/sdlc/code.playbook/code.fsm.js +67 -29
- package/reference/sdlc/code.playbook/code.fsm.ts +74 -29
- package/reference/sdlc/code.playbook/code.gears.md +66 -30
- package/reference/sdlc/code.playbook/code.playbook.d.ts +19 -3
- package/reference/sdlc/code.playbook/code.playbook.js +292 -34
- package/reference/sdlc/code.playbook/code.playbook.ts +290 -35
- package/reference/sdlc/code.playbook/code.registry.d.ts +43 -0
- package/reference/sdlc/code.playbook/code.registry.js +109 -0
- package/reference/sdlc/code.playbook/code.registry.ts +159 -0
- package/reference/sdlc/code.playbook/code.tmux-play.d.ts +2 -0
- package/reference/sdlc/code.playbook/code.tmux-play.js +7 -93
- package/reference/sdlc/code.playbook/code.tmux-play.ts +20 -118
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +21 -0
- package/reference/sdlc/code.playbook/playbook-captain.js +491 -0
- package/reference/sdlc/code.playbook/playbook-captain.ts +701 -0
- package/reference/sdlc/code.playbook/playbook-code.config.template.yaml +50 -25
- package/reference/sdlc/code.playbook/tmux-play.config.yaml +13 -8
- package/reference/sdlc/code.playbook/tmux-play.production.config.yaml +8 -4
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
|
|
4
|
+
import createPlaybookRuntime, {
|
|
5
|
+
type CodePlaybookOptions,
|
|
6
|
+
type PlaybookRuntime,
|
|
7
|
+
} from './code.playbook.js';
|
|
8
|
+
|
|
9
|
+
// PBRT-29/30: CODE runtime options are carried under
|
|
10
|
+
// `captain.options.code`, a namespaced object the host forwards
|
|
11
|
+
// verbatim through `captain.options`. cligent neither reads nor
|
|
12
|
+
// validates `options.code`; the CODE registry entry is the sole
|
|
13
|
+
// validator. The CODE options schema defines one key, `committer`: an
|
|
14
|
+
// optional Committer-alias player id, one of the baked player ids
|
|
15
|
+
// `coder` / `reviewer`. A valid `options.code` is absent, `{}`, or
|
|
16
|
+
// `{ committer: 'coder' | 'reviewer' }`; every other key is unknown
|
|
17
|
+
// and rejected with a path-named error, and an out-of-range
|
|
18
|
+
// `committer` value is rejected naming `captain.options.code.committer`.
|
|
19
|
+
// A further CODE option shall be introduced as its own higher-numbered
|
|
20
|
+
// item that widens `CODE_OPTION_KEYS`; the validator still fails closed
|
|
21
|
+
// on stray keys.
|
|
22
|
+
const CODE_OPTION_KEYS = new Set<string>(['committer']);
|
|
23
|
+
const COMMITTER_PLAYER_IDS = new Set<string>(['coder', 'reviewer']);
|
|
24
|
+
export const codeCopyPasteGuardNames = [
|
|
25
|
+
'accepted',
|
|
26
|
+
'approved',
|
|
27
|
+
'challengeAccepted',
|
|
28
|
+
'challengeRejected',
|
|
29
|
+
'challengesRaised',
|
|
30
|
+
'changesMadeCode',
|
|
31
|
+
'changesMadeCodeAndChallenged',
|
|
32
|
+
'changesMadeMixed',
|
|
33
|
+
'changesMadeMixedAndChallenged',
|
|
34
|
+
'changesMadeSpecs',
|
|
35
|
+
'changesMadeSpecsAndChallenged',
|
|
36
|
+
'hasFindings',
|
|
37
|
+
'needsRevision',
|
|
38
|
+
'noFindings',
|
|
39
|
+
'noOpenItems',
|
|
40
|
+
] as const;
|
|
41
|
+
|
|
42
|
+
export const codeStateCountLabels = {
|
|
43
|
+
adjudicateChallenges: 'rebuttal',
|
|
44
|
+
reviewBossCommitSpecs: 'review round',
|
|
45
|
+
reviewBossCommitCode: 'review round',
|
|
46
|
+
reviewBossCommitMixed: 'review round',
|
|
47
|
+
reviewIrTaskCommitSpecs: 'review round',
|
|
48
|
+
reviewIrTaskCommitCode: 'review round',
|
|
49
|
+
reviewIrTaskCommitMixed: 'review round',
|
|
50
|
+
reviewChangesSpecs: 'review round',
|
|
51
|
+
reviewChangesCode: 'review round',
|
|
52
|
+
reviewChangesMixed: 'review round',
|
|
53
|
+
reviewChangesAndChallengesSpecs: 'review round',
|
|
54
|
+
reviewChangesAndChallengesCode: 'review round',
|
|
55
|
+
reviewChangesAndChallengesMixed: 'review round',
|
|
56
|
+
} as const;
|
|
57
|
+
|
|
58
|
+
// The validated CODE options set. `committer`, when present, is the
|
|
59
|
+
// resolved Committer-alias player id (PBRT-8 / PBRT-30); a future CODE
|
|
60
|
+
// option widens both this type and `CODE_OPTION_KEYS`.
|
|
61
|
+
export interface CodeOptions {
|
|
62
|
+
committer?: 'coder' | 'reviewer';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface RegistryPlayer {
|
|
66
|
+
id: string;
|
|
67
|
+
adapter?: string;
|
|
68
|
+
model?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface CreateCodeRuntimeOptions {
|
|
72
|
+
captainOptions: unknown;
|
|
73
|
+
players: readonly RegistryPlayer[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface CodePlaybookRegistryEntry {
|
|
77
|
+
id: 'code';
|
|
78
|
+
command: 'code';
|
|
79
|
+
intent: string;
|
|
80
|
+
idleStateId: 'ready';
|
|
81
|
+
finalStateId: 'done';
|
|
82
|
+
copyPasteGuardNames: readonly string[];
|
|
83
|
+
stateCountLabels: typeof codeStateCountLabels;
|
|
84
|
+
validateOptions(captainOptions: unknown): CodeOptions;
|
|
85
|
+
createRuntime(options: CreateCodeRuntimeOptions): PlaybookRuntime;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function validateCodeOptions(captainOptions: unknown): CodeOptions {
|
|
89
|
+
const code = readCodeNamespace(captainOptions);
|
|
90
|
+
if (code === undefined) return {};
|
|
91
|
+
if (typeof code !== 'object' || code === null || Array.isArray(code)) {
|
|
92
|
+
throw new Error('captain.options.code must be an object');
|
|
93
|
+
}
|
|
94
|
+
for (const key of Object.keys(code)) {
|
|
95
|
+
if (!CODE_OPTION_KEYS.has(key)) {
|
|
96
|
+
throw new Error(`Unknown config field captain.options.code.${key}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const options: CodeOptions = {};
|
|
100
|
+
const committer = (code as Record<string, unknown>).committer;
|
|
101
|
+
if (committer !== undefined) {
|
|
102
|
+
if (typeof committer !== 'string' || !COMMITTER_PLAYER_IDS.has(committer)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"captain.options.code.committer must be 'coder' or 'reviewer'",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
options.committer = committer as 'coder' | 'reviewer';
|
|
108
|
+
}
|
|
109
|
+
return options;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function readCodeNamespace(captainOptions: unknown): unknown {
|
|
113
|
+
if (
|
|
114
|
+
typeof captainOptions !== 'object' ||
|
|
115
|
+
captainOptions === null ||
|
|
116
|
+
Array.isArray(captainOptions)
|
|
117
|
+
) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return (captainOptions as Record<string, unknown>).code;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function playerIdentity(
|
|
124
|
+
players: readonly RegistryPlayer[],
|
|
125
|
+
id: string,
|
|
126
|
+
): string | undefined {
|
|
127
|
+
const entry = players.find((p) => p.id === id);
|
|
128
|
+
return entry?.model ?? entry?.adapter;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function createCodeRuntimeOptions({
|
|
132
|
+
captainOptions,
|
|
133
|
+
players,
|
|
134
|
+
}: CreateCodeRuntimeOptions): CodePlaybookOptions {
|
|
135
|
+
const codeOptions = validateCodeOptions(captainOptions);
|
|
136
|
+
const coderPlayer = playerIdentity(players, 'coder');
|
|
137
|
+
const reviewerPlayer = playerIdentity(players, 'reviewer');
|
|
138
|
+
return {
|
|
139
|
+
coderPlayer,
|
|
140
|
+
reviewerPlayer,
|
|
141
|
+
...(codeOptions.committer !== undefined
|
|
142
|
+
? { committerPlayer: codeOptions.committer }
|
|
143
|
+
: {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export const codePlaybookRegistryEntry: CodePlaybookRegistryEntry = {
|
|
148
|
+
id: 'code',
|
|
149
|
+
command: 'code',
|
|
150
|
+
intent: 'software development / SDLC coding workflow',
|
|
151
|
+
idleStateId: 'ready',
|
|
152
|
+
finalStateId: 'done',
|
|
153
|
+
copyPasteGuardNames: codeCopyPasteGuardNames,
|
|
154
|
+
stateCountLabels: codeStateCountLabels,
|
|
155
|
+
validateOptions: validateCodeOptions,
|
|
156
|
+
createRuntime(options) {
|
|
157
|
+
return createPlaybookRuntime(createCodeRuntimeOptions(options));
|
|
158
|
+
},
|
|
159
|
+
};
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type { Captain } from '@sublang/cligent/tmux-play';
|
|
2
|
+
export { codeCopyPasteGuardNames, codeStateCountLabels, codePlaybookRegistryEntry, createCodeRuntimeOptions, validateCodeOptions, } from './code.registry.js';
|
|
3
|
+
export type { CodeOptions, CodePlaybookRegistryEntry, CreateCodeRuntimeOptions, RegistryPlayer, } from './code.registry.js';
|
|
2
4
|
export default function createCodeTmuxPlayCaptain(options: unknown): Captain;
|
|
@@ -1,97 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// no model is pinned — so player prompts and commit-message trailers
|
|
10
|
-
// carry the concrete model identity (e.g. `claude-opus-4-7`) rather
|
|
11
|
-
// than the adapter family name (e.g. `claude`). Any same-named keys
|
|
12
|
-
// in `options` are ignored.
|
|
3
|
+
import createPlaybookCaptainShell from './playbook-captain.js';
|
|
4
|
+
export { codeCopyPasteGuardNames, codeStateCountLabels, codePlaybookRegistryEntry, createCodeRuntimeOptions, validateCodeOptions, } from './code.registry.js';
|
|
5
|
+
// Compatibility shim for the historic `./code/tmux-play` package
|
|
6
|
+
// export. Public launch paths now target the Playbook Captain shell
|
|
7
|
+
// directly; explicit configs that still import this module get the
|
|
8
|
+
// same shell with CODE registered.
|
|
13
9
|
export default function createCodeTmuxPlayCaptain(options) {
|
|
14
|
-
|
|
15
|
-
// CaptainContext is rebuilt per turn and carries the call
|
|
16
|
-
// primitives. The runtime is constructed in `init` so identity
|
|
17
|
-
// strings derived from `session.players` can flow into its options;
|
|
18
|
-
// PlaybookPorts is built once at init, so the per-turn context
|
|
19
|
-
// lives in a closure-scoped slot the port callbacks query lazily.
|
|
20
|
-
let runtime;
|
|
21
|
-
let activeContext;
|
|
22
|
-
return {
|
|
23
|
-
async init(session) {
|
|
24
|
-
const playerIdentity = (id) => {
|
|
25
|
-
const entry = session.players.find((p) => p.id === id);
|
|
26
|
-
return entry?.model ?? entry?.adapter;
|
|
27
|
-
};
|
|
28
|
-
const coderPlayer = playerIdentity('coder');
|
|
29
|
-
const reviewerPlayer = playerIdentity('reviewer');
|
|
30
|
-
runtime = createPlaybookRuntime({
|
|
31
|
-
...options,
|
|
32
|
-
coderPlayer,
|
|
33
|
-
reviewerPlayer,
|
|
34
|
-
});
|
|
35
|
-
const ports = {
|
|
36
|
-
callPlayer: async (playerId, prompt, _signal) => {
|
|
37
|
-
if (!activeContext) {
|
|
38
|
-
throw new Error('callPlayer invoked outside a Boss turn');
|
|
39
|
-
}
|
|
40
|
-
// PlayerRunResult per TMUX-033 already matches PlayerResult
|
|
41
|
-
// (`status: 'ok' | 'aborted' | 'error'`, `finalText?`,
|
|
42
|
-
// `error?`). cligent honors context.signal internally;
|
|
43
|
-
// the runtime's signal is the same source forwarded
|
|
44
|
-
// through handleBossInput, so dropping `_signal` is
|
|
45
|
-
// safe.
|
|
46
|
-
const r = await activeContext.callPlayer(playerId, prompt);
|
|
47
|
-
return {
|
|
48
|
-
status: r.status,
|
|
49
|
-
finalText: r.finalText,
|
|
50
|
-
error: r.error,
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
callJudge: async (prompt, _signal) => {
|
|
54
|
-
if (!activeContext) {
|
|
55
|
-
throw new Error('callJudge invoked outside a Boss turn');
|
|
56
|
-
}
|
|
57
|
-
const r = await activeContext.callCaptain(prompt);
|
|
58
|
-
if (r.status !== 'ok') {
|
|
59
|
-
throw new Error(r.error ?? `callCaptain status "${r.status}"`);
|
|
60
|
-
}
|
|
61
|
-
if (r.finalText === undefined) {
|
|
62
|
-
throw new Error('callCaptain returned status=ok with no finalText');
|
|
63
|
-
}
|
|
64
|
-
return r.finalText;
|
|
65
|
-
},
|
|
66
|
-
emitStatus: async (message, data) => {
|
|
67
|
-
await session.emitStatus(message, data);
|
|
68
|
-
},
|
|
69
|
-
emitTelemetry: async (event) => {
|
|
70
|
-
await session.emitTelemetry(event);
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
await runtime.init(ports);
|
|
74
|
-
},
|
|
75
|
-
async handleBossTurn(turn, context) {
|
|
76
|
-
if (!runtime) {
|
|
77
|
-
throw new Error('init must be called first');
|
|
78
|
-
}
|
|
79
|
-
activeContext = context;
|
|
80
|
-
try {
|
|
81
|
-
// Forward the Boss prompt + cligent's per-turn signal into
|
|
82
|
-
// the runtime; the runtime stashes the signal so the
|
|
83
|
-
// captain bridge passes it down to callPlayer / callJudge.
|
|
84
|
-
await runtime.handleBossInput({
|
|
85
|
-
text: turn.prompt,
|
|
86
|
-
signal: context.signal,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
finally {
|
|
90
|
-
activeContext = undefined;
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
async dispose() {
|
|
94
|
-
await runtime?.dispose();
|
|
95
|
-
},
|
|
96
|
-
};
|
|
10
|
+
return createPlaybookCaptainShell(options);
|
|
97
11
|
}
|
|
@@ -1,127 +1,29 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// shall not affect code.playbook.ts or its tests.
|
|
4
|
+
import type { Captain } from '@sublang/cligent/tmux-play';
|
|
5
|
+
import createPlaybookCaptainShell from './playbook-captain.js';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
export {
|
|
8
|
+
codeCopyPasteGuardNames,
|
|
9
|
+
codeStateCountLabels,
|
|
10
|
+
codePlaybookRegistryEntry,
|
|
11
|
+
createCodeRuntimeOptions,
|
|
12
|
+
validateCodeOptions,
|
|
13
|
+
} from './code.registry.js';
|
|
14
|
+
export type {
|
|
15
|
+
CodeOptions,
|
|
16
|
+
CodePlaybookRegistryEntry,
|
|
17
|
+
CreateCodeRuntimeOptions,
|
|
18
|
+
RegistryPlayer,
|
|
19
|
+
} from './code.registry.js';
|
|
19
20
|
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// preferring each entry's `model` and falling back to `adapter` when
|
|
25
|
-
// no model is pinned — so player prompts and commit-message trailers
|
|
26
|
-
// carry the concrete model identity (e.g. `claude-opus-4-7`) rather
|
|
27
|
-
// than the adapter family name (e.g. `claude`). Any same-named keys
|
|
28
|
-
// in `options` are ignored.
|
|
21
|
+
// Compatibility shim for the historic `./code/tmux-play` package
|
|
22
|
+
// export. Public launch paths now target the Playbook Captain shell
|
|
23
|
+
// directly; explicit configs that still import this module get the
|
|
24
|
+
// same shell with CODE registered.
|
|
29
25
|
export default function createCodeTmuxPlayCaptain(
|
|
30
26
|
options: unknown,
|
|
31
27
|
): Captain {
|
|
32
|
-
|
|
33
|
-
// CaptainContext is rebuilt per turn and carries the call
|
|
34
|
-
// primitives. The runtime is constructed in `init` so identity
|
|
35
|
-
// strings derived from `session.players` can flow into its options;
|
|
36
|
-
// PlaybookPorts is built once at init, so the per-turn context
|
|
37
|
-
// lives in a closure-scoped slot the port callbacks query lazily.
|
|
38
|
-
let runtime: PlaybookRuntime | undefined;
|
|
39
|
-
let activeContext: CaptainContext | undefined;
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
async init(session: CaptainSession): Promise<void> {
|
|
43
|
-
const playerIdentity = (id: string): string | undefined => {
|
|
44
|
-
const entry = session.players.find((p) => p.id === id);
|
|
45
|
-
return entry?.model ?? entry?.adapter;
|
|
46
|
-
};
|
|
47
|
-
const coderPlayer = playerIdentity('coder');
|
|
48
|
-
const reviewerPlayer = playerIdentity('reviewer');
|
|
49
|
-
runtime = createPlaybookRuntime({
|
|
50
|
-
...(options as CodePlaybookOptions),
|
|
51
|
-
coderPlayer,
|
|
52
|
-
reviewerPlayer,
|
|
53
|
-
});
|
|
54
|
-
const ports: PlaybookPorts = {
|
|
55
|
-
callPlayer: async (playerId, prompt, _signal) => {
|
|
56
|
-
if (!activeContext) {
|
|
57
|
-
throw new Error('callPlayer invoked outside a Boss turn');
|
|
58
|
-
}
|
|
59
|
-
// PlayerRunResult per TMUX-033 already matches PlayerResult
|
|
60
|
-
// (`status: 'ok' | 'aborted' | 'error'`, `finalText?`,
|
|
61
|
-
// `error?`). cligent honors context.signal internally;
|
|
62
|
-
// the runtime's signal is the same source forwarded
|
|
63
|
-
// through handleBossInput, so dropping `_signal` is
|
|
64
|
-
// safe.
|
|
65
|
-
const r = await activeContext.callPlayer(playerId, prompt);
|
|
66
|
-
return {
|
|
67
|
-
status: r.status,
|
|
68
|
-
finalText: r.finalText,
|
|
69
|
-
error: r.error,
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
callJudge: async (prompt, _signal) => {
|
|
73
|
-
if (!activeContext) {
|
|
74
|
-
throw new Error('callJudge invoked outside a Boss turn');
|
|
75
|
-
}
|
|
76
|
-
const r = await activeContext.callCaptain(prompt);
|
|
77
|
-
if (r.status !== 'ok') {
|
|
78
|
-
throw new Error(
|
|
79
|
-
r.error ?? `callCaptain status "${r.status}"`,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
if (r.finalText === undefined) {
|
|
83
|
-
throw new Error(
|
|
84
|
-
'callCaptain returned status=ok with no finalText',
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
return r.finalText;
|
|
88
|
-
},
|
|
89
|
-
emitStatus: async (message, data) => {
|
|
90
|
-
await session.emitStatus(
|
|
91
|
-
message,
|
|
92
|
-
data as Record<string, unknown> | undefined,
|
|
93
|
-
);
|
|
94
|
-
},
|
|
95
|
-
emitTelemetry: async (event) => {
|
|
96
|
-
await session.emitTelemetry(event);
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
await runtime.init(ports);
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
async handleBossTurn(
|
|
103
|
-
turn: BossTurn,
|
|
104
|
-
context: CaptainContext,
|
|
105
|
-
): Promise<void> {
|
|
106
|
-
if (!runtime) {
|
|
107
|
-
throw new Error('init must be called first');
|
|
108
|
-
}
|
|
109
|
-
activeContext = context;
|
|
110
|
-
try {
|
|
111
|
-
// Forward the Boss prompt + cligent's per-turn signal into
|
|
112
|
-
// the runtime; the runtime stashes the signal so the
|
|
113
|
-
// captain bridge passes it down to callPlayer / callJudge.
|
|
114
|
-
await runtime.handleBossInput({
|
|
115
|
-
text: turn.prompt,
|
|
116
|
-
signal: context.signal,
|
|
117
|
-
});
|
|
118
|
-
} finally {
|
|
119
|
-
activeContext = undefined;
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
async dispose(): Promise<void> {
|
|
124
|
-
await runtime?.dispose();
|
|
125
|
-
},
|
|
126
|
-
};
|
|
28
|
+
return createPlaybookCaptainShell(options);
|
|
127
29
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Captain } from '@sublang/cligent/tmux-play';
|
|
2
|
+
import type { PlaybookRuntime } from './code.playbook.js';
|
|
3
|
+
import { type RegistryPlayer } from './code.registry.js';
|
|
4
|
+
export interface CreatePlaybookRuntimeOptions {
|
|
5
|
+
captainOptions: unknown;
|
|
6
|
+
players: readonly RegistryPlayer[];
|
|
7
|
+
}
|
|
8
|
+
export interface PlaybookCaptainRegistryEntry {
|
|
9
|
+
id: string;
|
|
10
|
+
command: string;
|
|
11
|
+
intent: string;
|
|
12
|
+
idleStateId: string;
|
|
13
|
+
finalStateId: string;
|
|
14
|
+
copyPasteGuardNames: readonly string[];
|
|
15
|
+
stateCountLabels?: Readonly<Record<string, string>>;
|
|
16
|
+
validateOptions(captainOptions: unknown): unknown;
|
|
17
|
+
createRuntime(options: CreatePlaybookRuntimeOptions): PlaybookRuntime;
|
|
18
|
+
}
|
|
19
|
+
export declare const playbookCaptainRegistry: readonly PlaybookCaptainRegistryEntry[];
|
|
20
|
+
export declare function createPlaybookCaptainShell(options: unknown, registry?: readonly PlaybookCaptainRegistryEntry[]): Captain;
|
|
21
|
+
export default createPlaybookCaptainShell;
|