@happyvertical/smrt-playbooks 0.44.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.
@@ -0,0 +1,367 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "sensitiveFieldsExcluded": true,
4
+ "generatedAt": "1970-01-01T00:00:00.000Z",
5
+ "packageName": "@happyvertical/smrt-playbooks",
6
+ "packageVersion": "0.44.0",
7
+ "sourceManifestPath": "dist/manifest.json",
8
+ "agentDocPath": "AGENTS.md",
9
+ "sourceHashes": {
10
+ "manifest": "8a46a95d6f2703a4455c1650d24d6e87dc8639e7a1571e2422c7a03b24144f58",
11
+ "packageJson": "33280f99cc18eb097a57756d77e767daec0b2fba6ab17ba56e1fe808714cafd4",
12
+ "agents": "7166afd02b405a200e1bd7a99eab2cb83f3fe12f700b5ce91a5ebfcdd7e1117a"
13
+ },
14
+ "exports": [
15
+ ".",
16
+ "./manifest",
17
+ "./manifest.json"
18
+ ],
19
+ "dependencies": {
20
+ "@happyvertical/smrt-config": "workspace:*",
21
+ "@happyvertical/smrt-core": "workspace:*",
22
+ "@happyvertical/smrt-tenancy": "workspace:*",
23
+ "@happyvertical/smrt-types": "workspace:*",
24
+ "@happyvertical/sql": "catalog:",
25
+ "@happyvertical/smrt-vitest": "workspace:*",
26
+ "@types/node": "24.13.2",
27
+ "typescript": "5.9.3",
28
+ "vite": "8.1.4",
29
+ "vitest": "4.1.10"
30
+ },
31
+ "smrtDependencies": [
32
+ "@happyvertical/smrt-config",
33
+ "@happyvertical/smrt-core",
34
+ "@happyvertical/smrt-tenancy",
35
+ "@happyvertical/smrt-types",
36
+ "@happyvertical/smrt-vitest"
37
+ ],
38
+ "sdkDependencies": [
39
+ "@happyvertical/sql"
40
+ ],
41
+ "tags": [],
42
+ "risks": [],
43
+ "objects": [
44
+ {
45
+ "name": "PlaybookOverrideCollection",
46
+ "qualifiedName": "@happyvertical/smrt-playbooks:PlaybookOverrideCollection",
47
+ "collection": "playbookoverrides",
48
+ "tableName": "_smrt_playbook_overrides",
49
+ "packageName": "@happyvertical/smrt-playbooks",
50
+ "extends": "SmrtCollection",
51
+ "fields": [],
52
+ "relationships": [],
53
+ "methods": [
54
+ "getAppOverride",
55
+ "getResolutionLayers",
56
+ "getTenantOverride"
57
+ ],
58
+ "methodSignatures": [
59
+ {
60
+ "name": "getAppOverride",
61
+ "async": true,
62
+ "params": [
63
+ "key: string",
64
+ "options?: object"
65
+ ],
66
+ "returns": "Promise<PlaybookOverride | null>"
67
+ },
68
+ {
69
+ "name": "getResolutionLayers",
70
+ "async": true,
71
+ "params": [
72
+ "key: string",
73
+ "tenantId?: string | null",
74
+ "options?: object"
75
+ ],
76
+ "returns": "Promise<object>"
77
+ },
78
+ {
79
+ "name": "getTenantOverride",
80
+ "async": true,
81
+ "params": [
82
+ "key: string",
83
+ "tenantId: string",
84
+ "options?: object"
85
+ ],
86
+ "returns": "Promise<PlaybookOverride | null>"
87
+ }
88
+ ],
89
+ "surfaces": [],
90
+ "relationshipFeatures": [
91
+ "uuidColumns"
92
+ ],
93
+ "tags": [],
94
+ "risks": []
95
+ },
96
+ {
97
+ "name": "PlaybookOverride",
98
+ "qualifiedName": "@happyvertical/smrt-playbooks:PlaybookOverride",
99
+ "collection": "playbookoverrides",
100
+ "tableName": "_smrt_playbook_overrides",
101
+ "packageName": "@happyvertical/smrt-playbooks",
102
+ "extends": "SmrtObject",
103
+ "fields": [
104
+ {
105
+ "name": "key",
106
+ "type": "text",
107
+ "required": true,
108
+ "columnType": "TEXT",
109
+ "default": ""
110
+ },
111
+ {
112
+ "name": "tenantId",
113
+ "type": "text",
114
+ "required": false,
115
+ "columnType": "TEXT"
116
+ },
117
+ {
118
+ "name": "title",
119
+ "type": "text",
120
+ "required": false,
121
+ "columnType": "TEXT"
122
+ },
123
+ {
124
+ "name": "description",
125
+ "type": "text",
126
+ "required": false,
127
+ "columnType": "TEXT"
128
+ },
129
+ {
130
+ "name": "planes",
131
+ "type": "text",
132
+ "required": false,
133
+ "columnType": "TEXT"
134
+ },
135
+ {
136
+ "name": "onStepFailure",
137
+ "type": "text",
138
+ "required": false,
139
+ "columnType": "TEXT"
140
+ },
141
+ {
142
+ "name": "enabled",
143
+ "type": "boolean",
144
+ "required": false,
145
+ "columnType": "BOOLEAN"
146
+ },
147
+ {
148
+ "name": "metadata",
149
+ "type": "text",
150
+ "required": false,
151
+ "columnType": "TEXT"
152
+ }
153
+ ],
154
+ "relationships": [],
155
+ "methods": [
156
+ "delete",
157
+ "getMetadata",
158
+ "getPlanes",
159
+ "save",
160
+ "setMetadata",
161
+ "setPlanes",
162
+ "toPlaybookLayer"
163
+ ],
164
+ "methodSignatures": [
165
+ {
166
+ "name": "delete",
167
+ "async": true,
168
+ "returns": "Promise<void>"
169
+ },
170
+ {
171
+ "name": "getMetadata",
172
+ "returns": "PlaybookMetadata"
173
+ },
174
+ {
175
+ "name": "getPlanes",
176
+ "returns": "null"
177
+ },
178
+ {
179
+ "name": "save",
180
+ "async": true,
181
+ "returns": "Promise"
182
+ },
183
+ {
184
+ "name": "setMetadata",
185
+ "params": [
186
+ "metadata: PlaybookMetadata | null"
187
+ ],
188
+ "returns": "void"
189
+ },
190
+ {
191
+ "name": "setPlanes",
192
+ "params": [
193
+ "planes: null"
194
+ ],
195
+ "returns": "void"
196
+ },
197
+ {
198
+ "name": "toPlaybookLayer",
199
+ "returns": "PlaybookLayer"
200
+ }
201
+ ],
202
+ "conflictColumns": [
203
+ "key",
204
+ "context"
205
+ ],
206
+ "surfaces": [
207
+ {
208
+ "kind": "api",
209
+ "name": "playbookoverrides.list",
210
+ "operation": "list",
211
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
212
+ "path": "/playbookoverrides",
213
+ "method": "GET"
214
+ },
215
+ {
216
+ "kind": "api",
217
+ "name": "playbookoverrides.get",
218
+ "operation": "get",
219
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
220
+ "path": "/playbookoverrides/[id]",
221
+ "method": "GET"
222
+ },
223
+ {
224
+ "kind": "api",
225
+ "name": "playbookoverrides.create",
226
+ "operation": "create",
227
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
228
+ "path": "/playbookoverrides",
229
+ "method": "POST"
230
+ },
231
+ {
232
+ "kind": "api",
233
+ "name": "playbookoverrides.update",
234
+ "operation": "update",
235
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
236
+ "path": "/playbookoverrides/[id]",
237
+ "method": "PATCH"
238
+ },
239
+ {
240
+ "kind": "api",
241
+ "name": "playbookoverrides.delete",
242
+ "operation": "delete",
243
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
244
+ "path": "/playbookoverrides/[id]",
245
+ "method": "DELETE"
246
+ },
247
+ {
248
+ "kind": "cli",
249
+ "name": "playbookoverride_list",
250
+ "operation": "list",
251
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
252
+ },
253
+ {
254
+ "kind": "cli",
255
+ "name": "playbookoverride_get",
256
+ "operation": "get",
257
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
258
+ },
259
+ {
260
+ "kind": "cli",
261
+ "name": "playbookoverride_create",
262
+ "operation": "create",
263
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
264
+ },
265
+ {
266
+ "kind": "cli",
267
+ "name": "playbookoverride_update",
268
+ "operation": "update",
269
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
270
+ },
271
+ {
272
+ "kind": "cli",
273
+ "name": "playbookoverride_delete",
274
+ "operation": "delete",
275
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
276
+ }
277
+ ],
278
+ "relationshipFeatures": [
279
+ "uuidColumns"
280
+ ],
281
+ "tags": [],
282
+ "risks": []
283
+ }
284
+ ],
285
+ "surfaces": [
286
+ {
287
+ "kind": "api",
288
+ "name": "playbookoverrides.list",
289
+ "operation": "list",
290
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
291
+ "path": "/playbookoverrides",
292
+ "method": "GET"
293
+ },
294
+ {
295
+ "kind": "api",
296
+ "name": "playbookoverrides.get",
297
+ "operation": "get",
298
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
299
+ "path": "/playbookoverrides/[id]",
300
+ "method": "GET"
301
+ },
302
+ {
303
+ "kind": "api",
304
+ "name": "playbookoverrides.create",
305
+ "operation": "create",
306
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
307
+ "path": "/playbookoverrides",
308
+ "method": "POST"
309
+ },
310
+ {
311
+ "kind": "api",
312
+ "name": "playbookoverrides.update",
313
+ "operation": "update",
314
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
315
+ "path": "/playbookoverrides/[id]",
316
+ "method": "PATCH"
317
+ },
318
+ {
319
+ "kind": "api",
320
+ "name": "playbookoverrides.delete",
321
+ "operation": "delete",
322
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride",
323
+ "path": "/playbookoverrides/[id]",
324
+ "method": "DELETE"
325
+ },
326
+ {
327
+ "kind": "cli",
328
+ "name": "playbookoverride_list",
329
+ "operation": "list",
330
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
331
+ },
332
+ {
333
+ "kind": "cli",
334
+ "name": "playbookoverride_get",
335
+ "operation": "get",
336
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
337
+ },
338
+ {
339
+ "kind": "cli",
340
+ "name": "playbookoverride_create",
341
+ "operation": "create",
342
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
343
+ },
344
+ {
345
+ "kind": "cli",
346
+ "name": "playbookoverride_update",
347
+ "operation": "update",
348
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
349
+ },
350
+ {
351
+ "kind": "cli",
352
+ "name": "playbookoverride_delete",
353
+ "operation": "delete",
354
+ "objectName": "@happyvertical/smrt-playbooks:PlaybookOverride"
355
+ }
356
+ ],
357
+ "prompts": [],
358
+ "relationshipsV2": {
359
+ "foreignKeyFields": 0,
360
+ "crossPackageRefFields": 0,
361
+ "junctionCollections": 0,
362
+ "hierarchicalObjects": 0,
363
+ "polymorphicAssociations": 0,
364
+ "uuidColumns": 2
365
+ },
366
+ "agentDoc": "# smrt-playbooks\n\nLayered playbook registry, app/tenant overrides, and plan resolution. A\nplaybook is a named, described, layered sequence of steps an agent follows;\nbrowser agents, in-app agents, the Node MCP server, and the CLI all follow the\nsame resolved plan. Fourth instance of the `smrt-prompts` layered-override\npattern — keep it consistent with `prompts`, `languages`, and `features`.\n\n## Core pieces\n\n- `definePlaybook()` registers code defaults in a global process registry\n (`globalThis.__smrtPlaybookRegistry`), so a package-bundled playbook resolves\n with no application registration\n- `resolvePlaybook()` merges the layers and returns a `PlaybookResolution`\n- `PlaybookOverride` (`_smrt_playbook_overrides`) stores partial app-level and\n tenant-level overrides with write-time validation\n- `PlaybookOverrideCollection` exposes the standard SmrtCollection CRUD surface\n\n## Resolution layers (priority low → high)\n\n1. Code default — `definePlaybook({ key, title, description, steps })`\n2. File/config override — `getPackageConfig<PlaybookPackageConfig>('playbooks', defaults)`\n3. App-level stored override — `PlaybookOverride` row with `tenantId = null`\n4. Tenant-level stored override — `PlaybookOverride` row with the current tenant\n5. Runtime override — passed to `resolvePlaybook(key, { override })`\n\nInheritance is field-by-field: a stored column is nullable, and `null` means\n\"use the lower layer\".\n\n## Script semantics\n\nA playbook resolves to a plan the agent executes step by step. **It never\nexecutes as a unit** (epic #2585 invariant 4), so it is never an authority\nboundary and adds no new security object to review. Each step is authorized\nindependently — at the REST boundary in the browser, or by\n`PrincipalRun.assertToolAllowed()` server-side. Nothing in this package\nexecutes a step, and there is deliberately no executor export.\n\nPlaybooks are consequently never atomic and have no compensation.\n`onStepFailure` (`'abort'` | `'continue'`) is the whole of the contract for\nwhat an agent does when step 3 of 5 fails.\n\n## Steps\n\nExactly two kinds in v1, and playbooks cannot nest:\n\n- `{ kind: 'operation', model: '@happyvertical/smrt-commerce:Order', action: 'submit' }`\n — the qualified pair already used by STI discriminators and\n `@crossPackageRef`. **Never a generated tool name**: that is derived from\n model, action, and namespace, and would silently orphan stored tenant\n overrides on a namespace change.\n- `{ kind: 'intent', id }` — a view intent named by its declared #2588\n identity. Valid only where a surface is mounted.\n\nA step referencing another playbook is rejected in `normalizeSteps()` at\ndefinition time.\n\n### Classification is inherited, never self-declared\n\nA step never classifies itself. `resolvePlaybook()` takes a\n`classifier` (and, for intents, an `intents` registry) supplied by the host,\nwhich returns the `CapabilityDeclaration` emitted for the referenced operation\nby `@happyvertical/smrt-types`. Anything undeclared resolves fail-closed to\n`{ effect: 'destructive', idempotent: false, openWorld: true }`. The\nvocabulary itself is older and lower and shared with model tools — it lives in\n`smrt-types`, not here (owning it here would close a\ncore → playbooks → core cycle).\n\n## Plane validity\n\nA playbook declares `planes: readonly ('browser' | 'server')[]`. Resolution for\na caller on an undeclared plane fails closed with reason\n`'plane-not-declared'`.\n\n- Operation-only playbooks default to both planes.\n- A playbook containing a view-intent step defaults to `['browser']`. Server\n validity rides the shipped #2446 browser command/ack bridge, which lets a\n server-side agent drive mounted surfaces with acknowledgement — it must be\n **declared explicitly**, never assumed.\n- The same default applies one level down: a `PlaybookIntentRecord` that\n declares no `planes` is browser-only, so server validity must be declared at\n **both** the playbook and the intent. Silence from the intent registry never\n widens a plane (`'intent-plane-not-declared'`).\n\nThe `#2588` intent registry does not exist yet, so an intent step with no\n`intents` resolver supplied fails closed with\n`'intent-registry-unavailable'`. That resolver is the seam #2588 wires into.\n\n## Editability\n\n`editable` defaults **all-false**, matching `normalizeEditableConfig` in\n`smrt-prompts`. Every stored column has a flag — `title`, `description`,\n`planes`, `onStepFailure`, `enabled`, `metadata` — and `save()` rejects a\nnon-null value for any field the definition has not opted in. `onStepFailure`\nis gated like the rest: flipping a locked playbook from `'abort'` to\n`'continue'` would change what an agent does after a failed prerequisite.\n\n`steps` is **structurally** non-editable, not merely defaulted false:\n\n- `PlaybookEditableConfig` has no `steps` key, and marking one throws at\n definition time\n- `_smrt_playbook_overrides` has **no `steps` column**, so no write of any kind\n has anywhere to put a step list\n- `PlaybookOverride.save()` rejects a `steps` property assigned through the\n untyped option bag rather than dropping it silently\n- `normalizePlaybookLayer()` throws on a `steps` key from the config or runtime\n layer\n- the resolver reads steps only from `PlaybookRegistry`\n\nThe reason is not escalation — under the script model a tenant cannot escalate,\nsince every step is authorized independently regardless of who wrote the list.\nIt is that an agent announcing \"checking out your cart\" while an overridden\nstep list does something else is a description-behavior mismatch.\n\nEnablement overrides are one-directional: a layer may disable, never re-enable\nwhat a lower layer disabled. Enforced in `mergePlaybookLayers()` (`enabled &&\nlayer.enabled`) and rejected at `save()` with a specific message. Plane lists\nnarrow the same way.\n\n## Caching\n\nResolutions are cached per `(key, tenantId, db)` with a TTL. The cache is\ninvalidated on `PlaybookOverride.save()` and `.delete()`; an app-level write\n(`tenantId = null`) clears every tenant's entry for that key, because each\ntenant inherits from it. Use `clearPlaybookCache()` in tests.\n\nA monotonic per-`(db, key)` invalidation generation closes the read-racing-a-\nwrite window; see the Gotchas entry below before touching `cache.ts`.\n\n## Gotchas\n\n- **`context` carries the tenant scope.** `save()` sets\n `this.context = this.tenantId ?? '__app__'` and `conflictColumns` is\n `['key', 'context']`. `tenantId` is nullable, and a unique index over it\n would let multiple NULL rows coexist on PostgreSQL and DuckDB. The `context`\n trick (from `smrt-languages`) is what makes the same upsert correct on all\n three dialects — do not \"simplify\" it to `['key', 'tenantId']`.\n- **Identity changes need the delete-then-insert dance.** Changing `key` or\n `tenantId` on an existing row changes the conflict identity, so a plain\n `super.save()` writes the old primary key under a new one. Same handling as\n `PromptOverride` / `LanguageOverride`: a transaction where the driver has\n one, otherwise a staged replacement row deleted only after the new row is\n durable.\n- **JSON fields are stored as strings.** `planes` and `metadata` are text\n columns with guarded `getPlanes()` / `setPlanes()` / `getMetadata()` /\n `setMetadata()` helpers that swallow parse errors. Never override\n `toJSON()`; extend serialization through `transformJSON()`.\n- **`resolvePlaybook()` returns a result, it does not throw for policy.**\n Unknown key, disabled, wrong plane, and unresolvable intents all come back as\n `{ ok: false, reason, message }`. It *does* throw for programming errors —\n notably a `steps` key on an override layer.\n- **The cache carries an invalidation generation, and this is where it\n diverges from `smrt-prompts`.** A resolution captures\n `getPlaybookCacheGeneration(key, db)` before its asynchronous layer loads and\n hands it back to `setCachedPlaybookBase()`; a concurrent `save()` / `delete()`\n bumps the generation, and the in-flight resolution is then refused the cache\n write instead of repopulating the key it just invalidated with the pre-write\n value. Without it, \"a stale entry is never served after a write\" held only\n until a read raced a write, and then failed for the full 30s TTL. Generations\n are tracked per `(db, key)`, not per tenant, because an app-level row is\n inherited by every tenant. `clearPlaybookCache()` bumps rather than resets\n them, so a resolution that started before the clear cannot write back either.\n `smrt-prompts` and `smrt-languages` still carry the unguarded version of this\n race; fixing them is separate work.\n- **Restart vitest after adding a decorated class**; the manifest is generated\n at startup.\n\n## Related\n\n- `@happyvertical/smrt-prompts` — the pattern this package clones\n- `@happyvertical/smrt-languages` — source of the `context` column convention\n- `@happyvertical/smrt-features` — parallel package for feature flags\n- Epic #2585 — declared agent surface; #2587 capability vocabulary,\n #2588 view intents, #2590 preflight, #2591 manifest emission\n"
367
+ }
@@ -0,0 +1,241 @@
1
+ import { CapabilityClassification } from '@happyvertical/smrt-types';
2
+ import { CapabilityDeclaration } from '@happyvertical/smrt-types';
3
+ import { SmrtClassOptions } from '@happyvertical/smrt-core';
4
+
5
+ export declare const PLAYBOOK_PLANES: readonly PlaybookPlane[];
6
+
7
+ export declare interface PlaybookAcceptance {
8
+ ok: true;
9
+ plan: PlaybookPlan;
10
+ }
11
+
12
+ export declare interface PlaybookCacheValue {
13
+ key: string;
14
+ title: string;
15
+ description: string;
16
+ planes: readonly PlaybookPlane[];
17
+ onStepFailure: PlaybookFailurePolicy;
18
+ enabled: boolean;
19
+ metadata: PlaybookMetadata;
20
+ }
21
+
22
+ /**
23
+ * A partial override from any layer above the code default. There is no
24
+ * `steps` key, and supplying one is rejected rather than ignored.
25
+ */
26
+ export declare interface PlaybookConfigOverrideInput {
27
+ title?: string | null;
28
+ description?: string | null;
29
+ planes?: readonly PlaybookPlane[] | null;
30
+ onStepFailure?: PlaybookFailurePolicy | null;
31
+ enabled?: boolean | null;
32
+ metadata?: PlaybookMetadata | null;
33
+ [key: string]: unknown;
34
+ }
35
+
36
+ export declare interface PlaybookDefinition {
37
+ key: string;
38
+ title: string;
39
+ description: string;
40
+ steps: readonly PlaybookStep[];
41
+ planes: readonly PlaybookPlane[];
42
+ onStepFailure: PlaybookFailurePolicy;
43
+ enabled: boolean;
44
+ metadata: PlaybookMetadata;
45
+ editable: PlaybookEditableConfig;
46
+ }
47
+
48
+ export declare interface PlaybookDefinitionInput {
49
+ key: string;
50
+ title: string;
51
+ description: string;
52
+ steps: readonly PlaybookStep[];
53
+ /**
54
+ * Planes this playbook is valid on. Defaults to both planes when every step
55
+ * is a model operation, and to `['browser']` when any step is a view intent
56
+ * — server validity for an intent-bearing playbook rides the #2446 browser
57
+ * command/ack bridge and must be declared explicitly.
58
+ */
59
+ planes?: readonly PlaybookPlane[];
60
+ onStepFailure?: PlaybookFailurePolicy;
61
+ enabled?: boolean;
62
+ metadata?: PlaybookMetadata | null;
63
+ editable?: Partial<PlaybookEditableConfig>;
64
+ }
65
+
66
+ /**
67
+ * Fields a stored override layer may change when the definition opts in.
68
+ *
69
+ * `steps` is deliberately absent: it is structurally non-editable, not merely
70
+ * defaulted false. No override layer can carry a step list at all.
71
+ */
72
+ export declare interface PlaybookEditableConfig {
73
+ title: boolean;
74
+ description: boolean;
75
+ planes: boolean;
76
+ onStepFailure: boolean;
77
+ enabled: boolean;
78
+ metadata: boolean;
79
+ }
80
+
81
+ /**
82
+ * What an agent does when a step fails partway through a plan. Playbooks are
83
+ * scripts, never atomic units, so there is no compensation: the definition
84
+ * says only whether the remainder of the plan is abandoned.
85
+ */
86
+ export declare type PlaybookFailurePolicy = 'abort' | 'continue';
87
+
88
+ /**
89
+ * Record returned by an intent registry for a declared view intent.
90
+ *
91
+ * Seam for #2588: until an intent registry exists, no resolver is supplied and
92
+ * an intent step fails resolution closed.
93
+ */
94
+ export declare interface PlaybookIntentRecord {
95
+ id: string;
96
+ classification?: CapabilityDeclaration | null;
97
+ planes?: readonly PlaybookPlane[] | null;
98
+ }
99
+
100
+ /** Seam for #2588. */
101
+ export declare type PlaybookIntentResolver = (id: string) => PlaybookIntentRecord | null | undefined;
102
+
103
+ /**
104
+ * A step naming a declared view intent by its identity (#2588). Valid only
105
+ * where a surface is mounted.
106
+ */
107
+ export declare interface PlaybookIntentStep {
108
+ kind: 'intent';
109
+ /** Declared intent identity from the #2588 intent registry. */
110
+ id: string;
111
+ label?: string;
112
+ description?: string;
113
+ optional?: boolean;
114
+ }
115
+
116
+ /** One normalized override layer. `null` means "clear"; `undefined` means "inherit". */
117
+ export declare interface PlaybookLayer {
118
+ title?: string | null;
119
+ description?: string | null;
120
+ planes?: readonly PlaybookPlane[] | null;
121
+ onStepFailure?: PlaybookFailurePolicy | null;
122
+ enabled?: boolean | null;
123
+ metadata?: PlaybookMetadata | null;
124
+ }
125
+
126
+ export declare type PlaybookMetadata = Record<string, unknown>;
127
+
128
+ /**
129
+ * Resolves the capability classification of a referenced model operation.
130
+ *
131
+ * Playbooks never classify a step themselves. A host that knows the emitted
132
+ * build-time classification (core's `tool-schema.ts` output, or the runtime
133
+ * manifest) supplies it here; anything it does not know resolves fail-closed
134
+ * to `{ effect: 'destructive', idempotent: false, openWorld: true }`.
135
+ */
136
+ export declare type PlaybookOperationClassifier = (step: PlaybookOperationStep) => CapabilityDeclaration | null | undefined;
137
+
138
+ /**
139
+ * A step naming a model operation by qualified pair — the same qualified
140
+ * form STI discriminators and `@crossPackageRef` already use. Never a
141
+ * generated tool name: that is derived from model, action, and namespace and
142
+ * would silently orphan stored tenant overrides on a namespace change.
143
+ *
144
+ * The step never classifies itself; classification is inherited from the
145
+ * referenced operation (see {@link PlaybookOperationClassifier}).
146
+ */
147
+ export declare interface PlaybookOperationStep {
148
+ kind: 'operation';
149
+ /** Qualified model name, e.g. `@happyvertical/smrt-commerce:Order`. */
150
+ model: string;
151
+ /** Operation name exposed by the model's `@smrt({ api })` surface. */
152
+ action: string;
153
+ /** Human-facing label for the agent's narration of this step. */
154
+ label?: string;
155
+ /** Longer human-facing description of the step. */
156
+ description?: string;
157
+ /** When true, an agent may skip this step without abandoning the plan. */
158
+ optional?: boolean;
159
+ }
160
+
161
+ export declare interface PlaybookOverrideOptions {
162
+ key?: string;
163
+ tenantId?: string | null;
164
+ title?: string | null;
165
+ description?: string | null;
166
+ planes?: string | readonly PlaybookPlane[] | null;
167
+ onStepFailure?: PlaybookFailurePolicy | null;
168
+ enabled?: boolean | null;
169
+ metadata?: string | PlaybookMetadata | null;
170
+ }
171
+
172
+ export declare interface PlaybookPackageConfig {
173
+ playbooks?: Record<string, PlaybookConfigOverrideInput>;
174
+ [key: string]: unknown;
175
+ }
176
+
177
+ /**
178
+ * The output of resolution: a plan an agent follows step by step. Nothing in
179
+ * this package executes a step, and the plan is not an authority boundary —
180
+ * every step is authorized independently where it runs.
181
+ */
182
+ export declare interface PlaybookPlan {
183
+ key: string;
184
+ title: string;
185
+ description: string;
186
+ plane: PlaybookPlane;
187
+ planes: readonly PlaybookPlane[];
188
+ onStepFailure: PlaybookFailurePolicy;
189
+ metadata: PlaybookMetadata;
190
+ steps: readonly PlaybookPlanStep[];
191
+ }
192
+
193
+ /**
194
+ * Execution planes a playbook can declare validity for.
195
+ *
196
+ * `browser` covers WebMCP / in-page agents driving mounted surfaces;
197
+ * `server` covers Node MCP, CLI, and in-app agents running under
198
+ * `executeAsPrincipal`.
199
+ */
200
+ export declare type PlaybookPlane = 'browser' | 'server';
201
+
202
+ /** One step of a resolved plan, with its inherited classification. */
203
+ export declare interface PlaybookPlanStep {
204
+ index: number;
205
+ step: PlaybookStep;
206
+ classification: CapabilityClassification;
207
+ /** True when the classification is the fail-closed default. */
208
+ classificationDeclared: boolean;
209
+ }
210
+
211
+ export declare interface PlaybookRejection {
212
+ ok: false;
213
+ reason: PlaybookRejectionReason;
214
+ message: string;
215
+ key: string;
216
+ /** Index of the offending step, when the rejection is step-scoped. */
217
+ stepIndex?: number;
218
+ }
219
+
220
+ export declare type PlaybookRejectionReason = 'unknown-playbook' | 'disabled' | 'plane-not-declared' | 'intent-registry-unavailable' | 'unknown-intent' | 'intent-plane-not-declared';
221
+
222
+ /** Resolution fails closed: every rejection carries a specific reason. */
223
+ export declare type PlaybookResolution = PlaybookAcceptance | PlaybookRejection;
224
+
225
+ /** A playbook step. Exactly two kinds exist in v1; playbooks cannot nest. */
226
+ export declare type PlaybookStep = PlaybookOperationStep | PlaybookIntentStep;
227
+
228
+ export declare interface ResolvePlaybookOptions {
229
+ db?: SmrtClassOptions['db'];
230
+ tenantId?: string | null;
231
+ /** Plane the calling agent runs on. Defaults to `'server'`. */
232
+ plane?: PlaybookPlane;
233
+ /** Highest-precedence layer, supplied per call. */
234
+ override?: PlaybookConfigOverrideInput;
235
+ /** Host-supplied classification source for model-operation steps. */
236
+ classifier?: PlaybookOperationClassifier;
237
+ /** Host-supplied intent registry (#2588). */
238
+ intents?: PlaybookIntentResolver;
239
+ }
240
+
241
+ export { }
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ //#region src/types.ts
2
+ var PLAYBOOK_PLANES = Object.freeze(["browser", "server"]);
3
+ //#endregion
4
+ export { PLAYBOOK_PLANES };
5
+
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport type {\n CapabilityClassification,\n CapabilityDeclaration,\n} from '@happyvertical/smrt-types';\n\n/**\n * Execution planes a playbook can declare validity for.\n *\n * `browser` covers WebMCP / in-page agents driving mounted surfaces;\n * `server` covers Node MCP, CLI, and in-app agents running under\n * `executeAsPrincipal`.\n */\nexport type PlaybookPlane = 'browser' | 'server';\n\nexport const PLAYBOOK_PLANES: readonly PlaybookPlane[] = Object.freeze([\n 'browser',\n 'server',\n]);\n\n/**\n * A step naming a model operation by qualified pair — the same qualified\n * form STI discriminators and `@crossPackageRef` already use. Never a\n * generated tool name: that is derived from model, action, and namespace and\n * would silently orphan stored tenant overrides on a namespace change.\n *\n * The step never classifies itself; classification is inherited from the\n * referenced operation (see {@link PlaybookOperationClassifier}).\n */\nexport interface PlaybookOperationStep {\n kind: 'operation';\n /** Qualified model name, e.g. `@happyvertical/smrt-commerce:Order`. */\n model: string;\n /** Operation name exposed by the model's `@smrt({ api })` surface. */\n action: string;\n /** Human-facing label for the agent's narration of this step. */\n label?: string;\n /** Longer human-facing description of the step. */\n description?: string;\n /** When true, an agent may skip this step without abandoning the plan. */\n optional?: boolean;\n}\n\n/**\n * A step naming a declared view intent by its identity (#2588). Valid only\n * where a surface is mounted.\n */\nexport interface PlaybookIntentStep {\n kind: 'intent';\n /** Declared intent identity from the #2588 intent registry. */\n id: string;\n label?: string;\n description?: string;\n optional?: boolean;\n}\n\n/** A playbook step. Exactly two kinds exist in v1; playbooks cannot nest. */\nexport type PlaybookStep = PlaybookOperationStep | PlaybookIntentStep;\n\n/**\n * What an agent does when a step fails partway through a plan. Playbooks are\n * scripts, never atomic units, so there is no compensation: the definition\n * says only whether the remainder of the plan is abandoned.\n */\nexport type PlaybookFailurePolicy = 'abort' | 'continue';\n\n/**\n * Fields a stored override layer may change when the definition opts in.\n *\n * `steps` is deliberately absent: it is structurally non-editable, not merely\n * defaulted false. No override layer can carry a step list at all.\n */\nexport interface PlaybookEditableConfig {\n title: boolean;\n description: boolean;\n planes: boolean;\n onStepFailure: boolean;\n enabled: boolean;\n metadata: boolean;\n}\n\nexport type PlaybookMetadata = Record<string, unknown>;\n\nexport interface PlaybookDefinitionInput {\n key: string;\n title: string;\n description: string;\n steps: readonly PlaybookStep[];\n /**\n * Planes this playbook is valid on. Defaults to both planes when every step\n * is a model operation, and to `['browser']` when any step is a view intent\n * — server validity for an intent-bearing playbook rides the #2446 browser\n * command/ack bridge and must be declared explicitly.\n */\n planes?: readonly PlaybookPlane[];\n onStepFailure?: PlaybookFailurePolicy;\n enabled?: boolean;\n metadata?: PlaybookMetadata | null;\n editable?: Partial<PlaybookEditableConfig>;\n}\n\nexport interface PlaybookDefinition {\n key: string;\n title: string;\n description: string;\n steps: readonly PlaybookStep[];\n planes: readonly PlaybookPlane[];\n onStepFailure: PlaybookFailurePolicy;\n enabled: boolean;\n metadata: PlaybookMetadata;\n editable: PlaybookEditableConfig;\n}\n\n/**\n * A partial override from any layer above the code default. There is no\n * `steps` key, and supplying one is rejected rather than ignored.\n */\nexport interface PlaybookConfigOverrideInput {\n title?: string | null;\n description?: string | null;\n planes?: readonly PlaybookPlane[] | null;\n onStepFailure?: PlaybookFailurePolicy | null;\n enabled?: boolean | null;\n metadata?: PlaybookMetadata | null;\n [key: string]: unknown;\n}\n\nexport interface PlaybookPackageConfig {\n playbooks?: Record<string, PlaybookConfigOverrideInput>;\n [key: string]: unknown;\n}\n\n/** One normalized override layer. `null` means \"clear\"; `undefined` means \"inherit\". */\nexport interface PlaybookLayer {\n title?: string | null;\n description?: string | null;\n planes?: readonly PlaybookPlane[] | null;\n onStepFailure?: PlaybookFailurePolicy | null;\n enabled?: boolean | null;\n metadata?: PlaybookMetadata | null;\n}\n\nexport interface PlaybookOverrideOptions {\n key?: string;\n tenantId?: string | null;\n title?: string | null;\n description?: string | null;\n planes?: string | readonly PlaybookPlane[] | null;\n onStepFailure?: PlaybookFailurePolicy | null;\n enabled?: boolean | null;\n metadata?: string | PlaybookMetadata | null;\n}\n\n/**\n * Resolves the capability classification of a referenced model operation.\n *\n * Playbooks never classify a step themselves. A host that knows the emitted\n * build-time classification (core's `tool-schema.ts` output, or the runtime\n * manifest) supplies it here; anything it does not know resolves fail-closed\n * to `{ effect: 'destructive', idempotent: false, openWorld: true }`.\n */\nexport type PlaybookOperationClassifier = (\n step: PlaybookOperationStep,\n) => CapabilityDeclaration | null | undefined;\n\n/**\n * Record returned by an intent registry for a declared view intent.\n *\n * Seam for #2588: until an intent registry exists, no resolver is supplied and\n * an intent step fails resolution closed.\n */\nexport interface PlaybookIntentRecord {\n id: string;\n classification?: CapabilityDeclaration | null;\n planes?: readonly PlaybookPlane[] | null;\n}\n\n/** Seam for #2588. */\nexport type PlaybookIntentResolver = (\n id: string,\n) => PlaybookIntentRecord | null | undefined;\n\nexport interface ResolvePlaybookOptions {\n db?: SmrtClassOptions['db'];\n tenantId?: string | null;\n /** Plane the calling agent runs on. Defaults to `'server'`. */\n plane?: PlaybookPlane;\n /** Highest-precedence layer, supplied per call. */\n override?: PlaybookConfigOverrideInput;\n /** Host-supplied classification source for model-operation steps. */\n classifier?: PlaybookOperationClassifier;\n /** Host-supplied intent registry (#2588). */\n intents?: PlaybookIntentResolver;\n}\n\n/** One step of a resolved plan, with its inherited classification. */\nexport interface PlaybookPlanStep {\n index: number;\n step: PlaybookStep;\n classification: CapabilityClassification;\n /** True when the classification is the fail-closed default. */\n classificationDeclared: boolean;\n}\n\n/**\n * The output of resolution: a plan an agent follows step by step. Nothing in\n * this package executes a step, and the plan is not an authority boundary —\n * every step is authorized independently where it runs.\n */\nexport interface PlaybookPlan {\n key: string;\n title: string;\n description: string;\n plane: PlaybookPlane;\n planes: readonly PlaybookPlane[];\n onStepFailure: PlaybookFailurePolicy;\n metadata: PlaybookMetadata;\n steps: readonly PlaybookPlanStep[];\n}\n\nexport type PlaybookRejectionReason =\n | 'unknown-playbook'\n | 'disabled'\n | 'plane-not-declared'\n | 'intent-registry-unavailable'\n | 'unknown-intent'\n | 'intent-plane-not-declared';\n\nexport interface PlaybookRejection {\n ok: false;\n reason: PlaybookRejectionReason;\n message: string;\n key: string;\n /** Index of the offending step, when the rejection is step-scoped. */\n stepIndex?: number;\n}\n\nexport interface PlaybookAcceptance {\n ok: true;\n plan: PlaybookPlan;\n}\n\n/** Resolution fails closed: every rejection carries a specific reason. */\nexport type PlaybookResolution = PlaybookAcceptance | PlaybookRejection;\n\nexport interface PlaybookCacheValue {\n key: string;\n title: string;\n description: string;\n planes: readonly PlaybookPlane[];\n onStepFailure: PlaybookFailurePolicy;\n enabled: boolean;\n metadata: PlaybookMetadata;\n}\n"],"mappings":";AAeO,IAAM,kBAA4C,OAAO,OAAO,CACrE,WACA,QACF,CAAC"}