@cleocode/playbooks 2026.4.94 → 2026.4.96
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/dist/approval.d.ts +113 -0
- package/dist/approval.js +244 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +34 -0
- package/dist/parser.d.ts +60 -0
- package/dist/parser.js +509 -0
- package/dist/policy.d.ts +55 -0
- package/dist/policy.js +85 -0
- package/dist/runtime.d.ts +206 -0
- package/dist/runtime.js +601 -0
- package/dist/schema.d.ts +374 -0
- package/dist/schema.js +34 -0
- package/dist/state.d.ts +96 -0
- package/dist/state.js +322 -0
- package/package.json +3 -3
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMAC-SHA256 resume tokens for HITL approval gates.
|
|
3
|
+
*
|
|
4
|
+
* Tokens bind `{runId, nodeId, bindings}` so they cannot be forged or replayed
|
|
5
|
+
* across different executions. The secret defaults to a well-known dev value —
|
|
6
|
+
* production deployments MUST set the `CLEO_PLAYBOOK_SECRET` env var to a
|
|
7
|
+
* high-entropy secret. If the secret rotates, existing tokens are invalidated
|
|
8
|
+
* because the HMAC output changes.
|
|
9
|
+
*
|
|
10
|
+
* Binding canonicalization uses sorted-keys JSON so that `{a:1,b:2}` and
|
|
11
|
+
* `{b:2,a:1}` produce the same token — semantically identical payloads
|
|
12
|
+
* should always yield the same gate identity.
|
|
13
|
+
*
|
|
14
|
+
* @task T889 / T908 / W4-16
|
|
15
|
+
*/
|
|
16
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
17
|
+
import type { PlaybookApproval } from '@cleocode/contracts';
|
|
18
|
+
/**
|
|
19
|
+
* Error code: approval token not found in the DB.
|
|
20
|
+
* Raised by {@link approveGate} / {@link rejectGate}.
|
|
21
|
+
*/
|
|
22
|
+
export declare const E_APPROVAL_NOT_FOUND: "E_APPROVAL_NOT_FOUND";
|
|
23
|
+
/**
|
|
24
|
+
* Error code: approval has already transitioned out of `pending`.
|
|
25
|
+
* Raised by {@link approveGate} / {@link rejectGate} to prevent re-decisions.
|
|
26
|
+
*/
|
|
27
|
+
export declare const E_APPROVAL_ALREADY_DECIDED: "E_APPROVAL_ALREADY_DECIDED";
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the HMAC secret for resume-token generation.
|
|
30
|
+
*
|
|
31
|
+
* @param env - Override env source (defaults to `process.env`). Used in tests.
|
|
32
|
+
* @returns The configured secret, or a dev-only fallback if unset.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getPlaybookSecret(env?: NodeJS.ProcessEnv): string;
|
|
35
|
+
/**
|
|
36
|
+
* Generate a deterministic 32-char hex HMAC-SHA256 resume token.
|
|
37
|
+
*
|
|
38
|
+
* The token is derived from `HMAC(secret, "runId:nodeId:canonicalBindings")`
|
|
39
|
+
* and truncated to 32 hex chars (128 bits). Determinism is an intentional
|
|
40
|
+
* design choice: the same (runId, nodeId, bindings, secret) tuple always
|
|
41
|
+
* produces the same token, preventing duplicate gates for the same step.
|
|
42
|
+
*
|
|
43
|
+
* @param runId - Playbook run identifier.
|
|
44
|
+
* @param nodeId - Node identifier within the run graph.
|
|
45
|
+
* @param bindings - Current runtime bindings (canonicalized via sorted-keys JSON).
|
|
46
|
+
* @param secret - HMAC secret (defaults to {@link getPlaybookSecret}).
|
|
47
|
+
* @returns A 32-char lowercase hex string.
|
|
48
|
+
*/
|
|
49
|
+
export declare function generateResumeToken(runId: string, nodeId: string, bindings: Record<string, unknown>, secret?: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Input for {@link createApprovalGate}.
|
|
52
|
+
*/
|
|
53
|
+
export interface CreateApprovalGateInput {
|
|
54
|
+
/** Run identifier (FK to `playbook_runs.run_id`). */
|
|
55
|
+
runId: string;
|
|
56
|
+
/** Node identifier within the run graph. */
|
|
57
|
+
nodeId: string;
|
|
58
|
+
/** Runtime bindings at gate creation time. */
|
|
59
|
+
bindings: Record<string, unknown>;
|
|
60
|
+
/** If true, gate is created pre-approved (policy auto-pass). Default false. */
|
|
61
|
+
autoPassed?: boolean;
|
|
62
|
+
/** Optional approver identity (required if `autoPassed=true` recorded by policy). */
|
|
63
|
+
approver?: string;
|
|
64
|
+
/** Optional human-readable reason (policy name, approval note, etc.). */
|
|
65
|
+
reason?: string;
|
|
66
|
+
/** Override secret for token generation. Defaults to env-resolved secret. */
|
|
67
|
+
secret?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create an HITL approval gate row in `playbook_approvals`.
|
|
71
|
+
*
|
|
72
|
+
* If `autoPassed` is true, the gate is written with `status='approved'`
|
|
73
|
+
* and `auto_passed=1` — used by the policy engine to short-circuit gates
|
|
74
|
+
* that match auto-pass rules. Otherwise status is `'pending'` and the
|
|
75
|
+
* runtime blocks until {@link approveGate} or {@link rejectGate} is called.
|
|
76
|
+
*
|
|
77
|
+
* @param db - Open `node:sqlite` handle with the T889 migration applied.
|
|
78
|
+
* @param input - Gate parameters.
|
|
79
|
+
* @returns The inserted {@link PlaybookApproval}, round-tripped from the DB.
|
|
80
|
+
*/
|
|
81
|
+
export declare function createApprovalGate(db: DatabaseSync, input: CreateApprovalGateInput): PlaybookApproval;
|
|
82
|
+
/**
|
|
83
|
+
* Transition an approval gate to `approved` state.
|
|
84
|
+
*
|
|
85
|
+
* @param db - Open sqlite handle.
|
|
86
|
+
* @param token - The resume token returned from {@link createApprovalGate}.
|
|
87
|
+
* @param approver - Identity of the approver (agent id, user email, etc.).
|
|
88
|
+
* @param reason - Optional justification note.
|
|
89
|
+
* @returns The updated {@link PlaybookApproval} record.
|
|
90
|
+
* @throws Error with `E_APPROVAL_NOT_FOUND` code if no gate matches the token.
|
|
91
|
+
* @throws Error with `E_APPROVAL_ALREADY_DECIDED` code if the gate is not pending.
|
|
92
|
+
*/
|
|
93
|
+
export declare function approveGate(db: DatabaseSync, token: string, approver: string, reason?: string): PlaybookApproval;
|
|
94
|
+
/**
|
|
95
|
+
* Transition an approval gate to `rejected` state. Same semantics as
|
|
96
|
+
* {@link approveGate} but records a rejection — runtime will halt the run.
|
|
97
|
+
*
|
|
98
|
+
* @param db - Open sqlite handle.
|
|
99
|
+
* @param token - The resume token.
|
|
100
|
+
* @param approver - Identity of the rejector.
|
|
101
|
+
* @param reason - Optional justification.
|
|
102
|
+
* @returns The updated {@link PlaybookApproval} record.
|
|
103
|
+
* @throws Error with `E_APPROVAL_NOT_FOUND` if the token is unknown.
|
|
104
|
+
* @throws Error with `E_APPROVAL_ALREADY_DECIDED` if the gate is not pending.
|
|
105
|
+
*/
|
|
106
|
+
export declare function rejectGate(db: DatabaseSync, token: string, approver: string, reason?: string): PlaybookApproval;
|
|
107
|
+
/**
|
|
108
|
+
* List all gates that are still awaiting a decision, oldest first.
|
|
109
|
+
*
|
|
110
|
+
* @param db - Open sqlite handle.
|
|
111
|
+
* @returns Pending {@link PlaybookApproval} records ordered by `requested_at`.
|
|
112
|
+
*/
|
|
113
|
+
export declare function getPendingApprovals(db: DatabaseSync): PlaybookApproval[];
|
package/dist/approval.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMAC-SHA256 resume tokens for HITL approval gates.
|
|
3
|
+
*
|
|
4
|
+
* Tokens bind `{runId, nodeId, bindings}` so they cannot be forged or replayed
|
|
5
|
+
* across different executions. The secret defaults to a well-known dev value —
|
|
6
|
+
* production deployments MUST set the `CLEO_PLAYBOOK_SECRET` env var to a
|
|
7
|
+
* high-entropy secret. If the secret rotates, existing tokens are invalidated
|
|
8
|
+
* because the HMAC output changes.
|
|
9
|
+
*
|
|
10
|
+
* Binding canonicalization uses sorted-keys JSON so that `{a:1,b:2}` and
|
|
11
|
+
* `{b:2,a:1}` produce the same token — semantically identical payloads
|
|
12
|
+
* should always yield the same gate identity.
|
|
13
|
+
*
|
|
14
|
+
* @task T889 / T908 / W4-16
|
|
15
|
+
*/
|
|
16
|
+
import { createHmac, randomUUID } from 'node:crypto';
|
|
17
|
+
/**
|
|
18
|
+
* Dev-only fallback secret. Surfaced through {@link getPlaybookSecret} so
|
|
19
|
+
* production code paths can override via `CLEO_PLAYBOOK_SECRET`.
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_SECRET = 'cleo-playbook-dev-secret-do-not-use-in-production';
|
|
22
|
+
/**
|
|
23
|
+
* Token length (hex chars). 32 hex chars = 128 bits of HMAC output — enough
|
|
24
|
+
* for collision resistance while keeping tokens URL-safe and log-friendly.
|
|
25
|
+
*/
|
|
26
|
+
const TOKEN_LENGTH = 32;
|
|
27
|
+
/**
|
|
28
|
+
* Error code: approval token not found in the DB.
|
|
29
|
+
* Raised by {@link approveGate} / {@link rejectGate}.
|
|
30
|
+
*/
|
|
31
|
+
export const E_APPROVAL_NOT_FOUND = 'E_APPROVAL_NOT_FOUND';
|
|
32
|
+
/**
|
|
33
|
+
* Error code: approval has already transitioned out of `pending`.
|
|
34
|
+
* Raised by {@link approveGate} / {@link rejectGate} to prevent re-decisions.
|
|
35
|
+
*/
|
|
36
|
+
export const E_APPROVAL_ALREADY_DECIDED = 'E_APPROVAL_ALREADY_DECIDED';
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the HMAC secret for resume-token generation.
|
|
39
|
+
*
|
|
40
|
+
* @param env - Override env source (defaults to `process.env`). Used in tests.
|
|
41
|
+
* @returns The configured secret, or a dev-only fallback if unset.
|
|
42
|
+
*/
|
|
43
|
+
export function getPlaybookSecret(env = process.env) {
|
|
44
|
+
return env['CLEO_PLAYBOOK_SECRET'] ?? DEFAULT_SECRET;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate a deterministic 32-char hex HMAC-SHA256 resume token.
|
|
48
|
+
*
|
|
49
|
+
* The token is derived from `HMAC(secret, "runId:nodeId:canonicalBindings")`
|
|
50
|
+
* and truncated to 32 hex chars (128 bits). Determinism is an intentional
|
|
51
|
+
* design choice: the same (runId, nodeId, bindings, secret) tuple always
|
|
52
|
+
* produces the same token, preventing duplicate gates for the same step.
|
|
53
|
+
*
|
|
54
|
+
* @param runId - Playbook run identifier.
|
|
55
|
+
* @param nodeId - Node identifier within the run graph.
|
|
56
|
+
* @param bindings - Current runtime bindings (canonicalized via sorted-keys JSON).
|
|
57
|
+
* @param secret - HMAC secret (defaults to {@link getPlaybookSecret}).
|
|
58
|
+
* @returns A 32-char lowercase hex string.
|
|
59
|
+
*/
|
|
60
|
+
export function generateResumeToken(runId, nodeId, bindings, secret = getPlaybookSecret()) {
|
|
61
|
+
// Canonicalize bindings via sorted-keys JSON for determinism.
|
|
62
|
+
const canonical = JSON.stringify(bindings, Object.keys(bindings).sort());
|
|
63
|
+
const payload = `${runId}:${nodeId}:${canonical}`;
|
|
64
|
+
return createHmac('sha256', secret).update(payload).digest('hex').slice(0, TOKEN_LENGTH);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Narrow a raw status string to {@link PlaybookApprovalStatus}, guarding
|
|
68
|
+
* against unexpected DB values that would otherwise poison downstream types.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
function narrowStatus(s) {
|
|
73
|
+
if (s === 'pending' || s === 'approved' || s === 'rejected')
|
|
74
|
+
return s;
|
|
75
|
+
throw new Error(`invariant: unknown playbook_approvals.status '${s}'`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Read a required string column from a raw sqlite row.
|
|
79
|
+
*
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
function readString(row, key) {
|
|
83
|
+
const v = row[key];
|
|
84
|
+
if (typeof v !== 'string') {
|
|
85
|
+
throw new Error(`invariant: expected string for column ${key}, got ${typeof v}`);
|
|
86
|
+
}
|
|
87
|
+
return v;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Read a required integer column from a raw sqlite row.
|
|
91
|
+
*
|
|
92
|
+
* @internal
|
|
93
|
+
*/
|
|
94
|
+
function readInt(row, key) {
|
|
95
|
+
const v = row[key];
|
|
96
|
+
if (typeof v === 'number')
|
|
97
|
+
return v;
|
|
98
|
+
if (typeof v === 'bigint')
|
|
99
|
+
return Number(v);
|
|
100
|
+
throw new Error(`invariant: expected integer for column ${key}, got ${typeof v}`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Read an optional string column. Returns `undefined` for both `null`
|
|
104
|
+
* (SQL NULL) and missing keys.
|
|
105
|
+
*
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
function readOptionalString(row, key) {
|
|
109
|
+
const v = row[key];
|
|
110
|
+
if (v === null || v === undefined)
|
|
111
|
+
return undefined;
|
|
112
|
+
if (typeof v !== 'string') {
|
|
113
|
+
throw new Error(`invariant: expected string|null for column ${key}, got ${typeof v}`);
|
|
114
|
+
}
|
|
115
|
+
return v;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Map a raw `playbook_approvals` row to the camelCase {@link PlaybookApproval}
|
|
119
|
+
* contract shape. Validates types, converts the `auto_passed` 0/1 integer to
|
|
120
|
+
* a boolean, and strips nullable fields rather than emitting `null`.
|
|
121
|
+
*
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
function rowToApproval(row) {
|
|
125
|
+
const approval = {
|
|
126
|
+
approvalId: readString(row, 'approval_id'),
|
|
127
|
+
runId: readString(row, 'run_id'),
|
|
128
|
+
nodeId: readString(row, 'node_id'),
|
|
129
|
+
token: readString(row, 'token'),
|
|
130
|
+
requestedAt: readString(row, 'requested_at'),
|
|
131
|
+
status: narrowStatus(readString(row, 'status')),
|
|
132
|
+
autoPassed: readInt(row, 'auto_passed') === 1,
|
|
133
|
+
};
|
|
134
|
+
const approvedAt = readOptionalString(row, 'approved_at');
|
|
135
|
+
const approver = readOptionalString(row, 'approver');
|
|
136
|
+
const reason = readOptionalString(row, 'reason');
|
|
137
|
+
if (approvedAt !== undefined)
|
|
138
|
+
approval.approvedAt = approvedAt;
|
|
139
|
+
if (approver !== undefined)
|
|
140
|
+
approval.approver = approver;
|
|
141
|
+
if (reason !== undefined)
|
|
142
|
+
approval.reason = reason;
|
|
143
|
+
return approval;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create an HITL approval gate row in `playbook_approvals`.
|
|
147
|
+
*
|
|
148
|
+
* If `autoPassed` is true, the gate is written with `status='approved'`
|
|
149
|
+
* and `auto_passed=1` — used by the policy engine to short-circuit gates
|
|
150
|
+
* that match auto-pass rules. Otherwise status is `'pending'` and the
|
|
151
|
+
* runtime blocks until {@link approveGate} or {@link rejectGate} is called.
|
|
152
|
+
*
|
|
153
|
+
* @param db - Open `node:sqlite` handle with the T889 migration applied.
|
|
154
|
+
* @param input - Gate parameters.
|
|
155
|
+
* @returns The inserted {@link PlaybookApproval}, round-tripped from the DB.
|
|
156
|
+
*/
|
|
157
|
+
export function createApprovalGate(db, input) {
|
|
158
|
+
const token = generateResumeToken(input.runId, input.nodeId, input.bindings, input.secret);
|
|
159
|
+
const approvalId = randomUUID();
|
|
160
|
+
const autoPassed = input.autoPassed ?? false;
|
|
161
|
+
const status = autoPassed ? 'approved' : 'pending';
|
|
162
|
+
const stmt = db.prepare(`
|
|
163
|
+
INSERT INTO playbook_approvals
|
|
164
|
+
(approval_id, run_id, node_id, token, status, auto_passed, approver, reason)
|
|
165
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
166
|
+
`);
|
|
167
|
+
stmt.run(approvalId, input.runId, input.nodeId, token, status, autoPassed ? 1 : 0, input.approver ?? null, input.reason ?? null);
|
|
168
|
+
const row = db
|
|
169
|
+
.prepare('SELECT * FROM playbook_approvals WHERE approval_id = ?')
|
|
170
|
+
.get(approvalId);
|
|
171
|
+
if (row === undefined) {
|
|
172
|
+
throw new Error(`${E_APPROVAL_NOT_FOUND}: insert did not round-trip (approval_id=${approvalId})`);
|
|
173
|
+
}
|
|
174
|
+
return rowToApproval(row);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Transition an approval gate to `approved` state.
|
|
178
|
+
*
|
|
179
|
+
* @param db - Open sqlite handle.
|
|
180
|
+
* @param token - The resume token returned from {@link createApprovalGate}.
|
|
181
|
+
* @param approver - Identity of the approver (agent id, user email, etc.).
|
|
182
|
+
* @param reason - Optional justification note.
|
|
183
|
+
* @returns The updated {@link PlaybookApproval} record.
|
|
184
|
+
* @throws Error with `E_APPROVAL_NOT_FOUND` code if no gate matches the token.
|
|
185
|
+
* @throws Error with `E_APPROVAL_ALREADY_DECIDED` code if the gate is not pending.
|
|
186
|
+
*/
|
|
187
|
+
export function approveGate(db, token, approver, reason) {
|
|
188
|
+
return transitionGate(db, token, 'approved', approver, reason);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Transition an approval gate to `rejected` state. Same semantics as
|
|
192
|
+
* {@link approveGate} but records a rejection — runtime will halt the run.
|
|
193
|
+
*
|
|
194
|
+
* @param db - Open sqlite handle.
|
|
195
|
+
* @param token - The resume token.
|
|
196
|
+
* @param approver - Identity of the rejector.
|
|
197
|
+
* @param reason - Optional justification.
|
|
198
|
+
* @returns The updated {@link PlaybookApproval} record.
|
|
199
|
+
* @throws Error with `E_APPROVAL_NOT_FOUND` if the token is unknown.
|
|
200
|
+
* @throws Error with `E_APPROVAL_ALREADY_DECIDED` if the gate is not pending.
|
|
201
|
+
*/
|
|
202
|
+
export function rejectGate(db, token, approver, reason) {
|
|
203
|
+
return transitionGate(db, token, 'rejected', approver, reason);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Internal shared transition logic for approve/reject. Performs row lookup,
|
|
207
|
+
* state validation, update, and round-trip fetch in a single atomic flow.
|
|
208
|
+
*
|
|
209
|
+
* @internal
|
|
210
|
+
*/
|
|
211
|
+
function transitionGate(db, token, next, approver, reason) {
|
|
212
|
+
const existing = db.prepare('SELECT * FROM playbook_approvals WHERE token = ?').get(token);
|
|
213
|
+
if (existing === undefined) {
|
|
214
|
+
throw new Error(`${E_APPROVAL_NOT_FOUND}: no approval gate for token`);
|
|
215
|
+
}
|
|
216
|
+
const existingStatus = narrowStatus(readString(existing, 'status'));
|
|
217
|
+
if (existingStatus !== 'pending') {
|
|
218
|
+
const approvalId = readString(existing, 'approval_id');
|
|
219
|
+
throw new Error(`${E_APPROVAL_ALREADY_DECIDED}: gate ${approvalId} is already ${existingStatus}`);
|
|
220
|
+
}
|
|
221
|
+
db.prepare(`UPDATE playbook_approvals
|
|
222
|
+
SET status = ?, approved_at = datetime('now'), approver = ?, reason = ?
|
|
223
|
+
WHERE token = ?`).run(next, approver, reason ?? null, token);
|
|
224
|
+
const row = db.prepare('SELECT * FROM playbook_approvals WHERE token = ?').get(token);
|
|
225
|
+
if (row === undefined) {
|
|
226
|
+
// Unreachable: UPDATE just succeeded on this token.
|
|
227
|
+
throw new Error(`${E_APPROVAL_NOT_FOUND}: row vanished after update (token=${token})`);
|
|
228
|
+
}
|
|
229
|
+
return rowToApproval(row);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* List all gates that are still awaiting a decision, oldest first.
|
|
233
|
+
*
|
|
234
|
+
* @param db - Open sqlite handle.
|
|
235
|
+
* @returns Pending {@link PlaybookApproval} records ordered by `requested_at`.
|
|
236
|
+
*/
|
|
237
|
+
export function getPendingApprovals(db) {
|
|
238
|
+
const rows = db
|
|
239
|
+
.prepare(`SELECT * FROM playbook_approvals
|
|
240
|
+
WHERE status = 'pending'
|
|
241
|
+
ORDER BY requested_at ASC, approval_id ASC`)
|
|
242
|
+
.all();
|
|
243
|
+
return rows.map(rowToApproval);
|
|
244
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cleocode/playbooks — Playbook DSL + runtime for T889 Orchestration Coherence v3.
|
|
3
|
+
*
|
|
4
|
+
* This package is scaffolded in Wave 0. Subsequent waves will populate:
|
|
5
|
+
* - `schema.ts` (W4-6) — types + Drizzle table defs
|
|
6
|
+
* - `parser.ts` (W4-7) — .cantbook YAML parser
|
|
7
|
+
* - `state.ts` (W4-8) — DB CRUD for playbook_runs + playbook_approvals
|
|
8
|
+
* - `policy.ts` (W4-9) — HITL auto-policy rules
|
|
9
|
+
* - `runtime.ts` (W4-10) — state machine executor
|
|
10
|
+
* - `approval.ts` (W4-16) — resume token generation + approval ops
|
|
11
|
+
* - `skill-composer.ts` (W4-2..5) — three-source skill bundle composer
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Only the {@link PLAYBOOKS_PACKAGE_VERSION} constant is exported from the
|
|
15
|
+
* Wave 0 scaffold. Each follow-up wave adds a named barrel export here.
|
|
16
|
+
*
|
|
17
|
+
* @task T889 Orchestration Coherence v3 — Wave 0 scaffold
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Package version string matching the monorepo's CalVer cadence.
|
|
21
|
+
*
|
|
22
|
+
* Consumers can use this to assert dependency alignment at runtime
|
|
23
|
+
* (e.g. ensuring the `@cleocode/playbooks` runtime matches CLEO core).
|
|
24
|
+
*/
|
|
25
|
+
export declare const PLAYBOOKS_PACKAGE_VERSION: string;
|
|
26
|
+
export { approveGate, type CreateApprovalGateInput, createApprovalGate, E_APPROVAL_ALREADY_DECIDED, E_APPROVAL_NOT_FOUND, generateResumeToken, getPendingApprovals, getPlaybookSecret, rejectGate, } from './approval.js';
|
|
27
|
+
export { type ParsePlaybookResult, PlaybookParseError, parsePlaybook, } from './parser.js';
|
|
28
|
+
export { DEFAULT_POLICY_RULES, type EvaluatePolicyResult, evaluatePolicy, type PolicyRule, } from './policy.js';
|
|
29
|
+
export { type AgentDispatcher, type AgentDispatchInput, type AgentDispatchResult, type DeterministicRunInput, type DeterministicRunner, type DeterministicRunResult, E_PLAYBOOK_RESUME_BLOCKED, E_PLAYBOOK_RUNTIME_INVALID, type ExecutePlaybookOptions, type ExecutePlaybookResult, executePlaybook, type PlaybookTerminalStatus, type ResumePlaybookOptions, resumePlaybook, } from './runtime.js';
|
|
30
|
+
export { type CreatePlaybookApprovalInput, type CreatePlaybookRunInput, createPlaybookApproval, createPlaybookRun, deletePlaybookRun, getPlaybookApprovalByToken, getPlaybookRun, type ListPlaybookRunsOptions, listPlaybookApprovals, listPlaybookRuns, updatePlaybookApproval, updatePlaybookRun, } from './state.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cleocode/playbooks — Playbook DSL + runtime for T889 Orchestration Coherence v3.
|
|
3
|
+
*
|
|
4
|
+
* This package is scaffolded in Wave 0. Subsequent waves will populate:
|
|
5
|
+
* - `schema.ts` (W4-6) — types + Drizzle table defs
|
|
6
|
+
* - `parser.ts` (W4-7) — .cantbook YAML parser
|
|
7
|
+
* - `state.ts` (W4-8) — DB CRUD for playbook_runs + playbook_approvals
|
|
8
|
+
* - `policy.ts` (W4-9) — HITL auto-policy rules
|
|
9
|
+
* - `runtime.ts` (W4-10) — state machine executor
|
|
10
|
+
* - `approval.ts` (W4-16) — resume token generation + approval ops
|
|
11
|
+
* - `skill-composer.ts` (W4-2..5) — three-source skill bundle composer
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Only the {@link PLAYBOOKS_PACKAGE_VERSION} constant is exported from the
|
|
15
|
+
* Wave 0 scaffold. Each follow-up wave adds a named barrel export here.
|
|
16
|
+
*
|
|
17
|
+
* @task T889 Orchestration Coherence v3 — Wave 0 scaffold
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Package version string matching the monorepo's CalVer cadence.
|
|
21
|
+
*
|
|
22
|
+
* Consumers can use this to assert dependency alignment at runtime
|
|
23
|
+
* (e.g. ensuring the `@cleocode/playbooks` runtime matches CLEO core).
|
|
24
|
+
*/
|
|
25
|
+
export const PLAYBOOKS_PACKAGE_VERSION = '2026.4.85';
|
|
26
|
+
export { approveGate, createApprovalGate, E_APPROVAL_ALREADY_DECIDED, E_APPROVAL_NOT_FOUND, generateResumeToken, getPendingApprovals, getPlaybookSecret, rejectGate, } from './approval.js';
|
|
27
|
+
// W4-7: .cantbook YAML parser → PlaybookDefinition
|
|
28
|
+
export { PlaybookParseError, parsePlaybook, } from './parser.js';
|
|
29
|
+
// W4-9: HITL auto-policy evaluator
|
|
30
|
+
export { DEFAULT_POLICY_RULES, evaluatePolicy, } from './policy.js';
|
|
31
|
+
// W4-10 / T930: playbook runtime state machine + HITL resume
|
|
32
|
+
export { E_PLAYBOOK_RESUME_BLOCKED, E_PLAYBOOK_RUNTIME_INVALID, executePlaybook, resumePlaybook, } from './runtime.js';
|
|
33
|
+
// W4-8: state layer CRUD for playbook_runs + playbook_approvals
|
|
34
|
+
export { createPlaybookApproval, createPlaybookRun, deletePlaybookRun, getPlaybookApprovalByToken, getPlaybookRun, listPlaybookApprovals, listPlaybookRuns, updatePlaybookApproval, updatePlaybookRun, } from './state.js';
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .cantbook YAML parser → PlaybookDefinition.
|
|
3
|
+
*
|
|
4
|
+
* Grammar (see contracts/playbook.ts):
|
|
5
|
+
* version: "1.0"
|
|
6
|
+
* name: <string>
|
|
7
|
+
* description?: <string>
|
|
8
|
+
* inputs?: [{name, required?, default?, description?}]
|
|
9
|
+
* nodes: [<agentic | deterministic | approval node>]
|
|
10
|
+
* edges: [{from, to, contract?:{requires?[], ensures?[]}}]
|
|
11
|
+
* error_handlers?: [{on, action, message?}]
|
|
12
|
+
*
|
|
13
|
+
* Validation:
|
|
14
|
+
* - version MUST be "1.0"
|
|
15
|
+
* - name MUST be non-empty
|
|
16
|
+
* - node ids MUST be unique
|
|
17
|
+
* - every edge.from + edge.to MUST reference a known node id
|
|
18
|
+
* - nodes form a DAG when combined with edges (no cycles)
|
|
19
|
+
* - agentic nodes MUST have skill OR agent (at least one)
|
|
20
|
+
* - deterministic nodes MUST have command + args
|
|
21
|
+
* - approval nodes MUST have prompt
|
|
22
|
+
* - depends[] entries MUST be valid node ids
|
|
23
|
+
* - iteration_cap (max_iterations) MUST be 0..10 (hard limit)
|
|
24
|
+
*
|
|
25
|
+
* @task T889 / T904 / W4-7
|
|
26
|
+
*/
|
|
27
|
+
import type { PlaybookDefinition } from '@cleocode/contracts';
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown on any structural or semantic parse failure. Carries a
|
|
30
|
+
* `code`/`exitCode` pair so callers can bubble up consistent LAFS envelopes.
|
|
31
|
+
*/
|
|
32
|
+
export declare class PlaybookParseError extends Error {
|
|
33
|
+
readonly field?: string | undefined;
|
|
34
|
+
readonly value?: unknown | undefined;
|
|
35
|
+
/** Stable envelope error code for LAFS. */
|
|
36
|
+
readonly code = "E_PLAYBOOK_PARSE";
|
|
37
|
+
/** Process exit code used by CLI wrappers when a parse fails. */
|
|
38
|
+
readonly exitCode = 70;
|
|
39
|
+
/**
|
|
40
|
+
* @param message - Human-readable reason the playbook is invalid.
|
|
41
|
+
* @param field - Offending field path (e.g. `"nodes[0].id"`).
|
|
42
|
+
* @param value - Offending value for diagnostics (never re-thrown).
|
|
43
|
+
*/
|
|
44
|
+
constructor(message: string, field?: string | undefined, value?: unknown | undefined);
|
|
45
|
+
}
|
|
46
|
+
/** Result of a successful {@link parsePlaybook} call. */
|
|
47
|
+
export interface ParsePlaybookResult {
|
|
48
|
+
/** Validated, normalized definition ready for runtime execution. */
|
|
49
|
+
definition: PlaybookDefinition;
|
|
50
|
+
/** SHA-256 hex of the input source (for tamper detection). */
|
|
51
|
+
sourceHash: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse raw .cantbook YAML text into a validated {@link PlaybookDefinition}.
|
|
55
|
+
*
|
|
56
|
+
* @param source - Raw .cantbook YAML text.
|
|
57
|
+
* @returns The validated definition plus a deterministic SHA-256 source hash.
|
|
58
|
+
* @throws {PlaybookParseError} On any structural or semantic violation.
|
|
59
|
+
*/
|
|
60
|
+
export declare function parsePlaybook(source: string): ParsePlaybookResult;
|