@cleocode/contracts 2026.6.12 → 2026.6.14
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/__tests__/operation-def.test.js +5 -1
- package/dist/__tests__/operation-def.test.js.map +1 -1
- package/dist/__tests__/provider-def.test.d.ts +12 -0
- package/dist/__tests__/provider-def.test.d.ts.map +1 -0
- package/dist/__tests__/provider-def.test.js +84 -0
- package/dist/__tests__/provider-def.test.js.map +1 -0
- package/dist/__tests__/sealed-credential.test.d.ts +19 -0
- package/dist/__tests__/sealed-credential.test.d.ts.map +1 -0
- package/dist/__tests__/sealed-credential.test.js +74 -0
- package/dist/__tests__/sealed-credential.test.js.map +1 -0
- package/dist/__tests__/service-provider.test.d.ts +17 -0
- package/dist/__tests__/service-provider.test.d.ts.map +1 -0
- package/dist/__tests__/service-provider.test.js +108 -0
- package/dist/__tests__/service-provider.test.js.map +1 -0
- package/dist/__tests__/skill-executor-contract.test.js +3 -0
- package/dist/__tests__/skill-executor-contract.test.js.map +1 -1
- package/dist/acceptance-gate.d.ts +2 -3
- package/dist/acceptance-gate.d.ts.map +1 -1
- package/dist/boundary.d.ts +52 -0
- package/dist/boundary.d.ts.map +1 -1
- package/dist/boundary.js +24 -19
- package/dist/boundary.js.map +1 -1
- package/dist/conduit.d.ts +171 -0
- package/dist/conduit.d.ts.map +1 -1
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +22 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config.d.ts +104 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/data-accessor.d.ts +21 -1
- package/dist/data-accessor.d.ts.map +1 -1
- package/dist/data-accessor.js.map +1 -1
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts +21 -0
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts.map +1 -0
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js +84 -0
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js.map +1 -0
- package/dist/dispatch/identity.d.ts +1 -1
- package/dist/dispatch/identity.d.ts.map +1 -1
- package/dist/dispatch/identity.js +25 -0
- package/dist/dispatch/identity.js.map +1 -1
- package/dist/dispatch/operation-def.d.ts +20 -0
- package/dist/dispatch/operation-def.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +1044 -182
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/docs/read.d.ts +2 -2
- package/dist/index.d.ts +25 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/lease-ipc/__tests__/freeze.test.d.ts +15 -0
- package/dist/lease-ipc/__tests__/freeze.test.d.ts.map +1 -0
- package/dist/lease-ipc/__tests__/freeze.test.js +313 -0
- package/dist/lease-ipc/__tests__/freeze.test.js.map +1 -0
- package/dist/lease-ipc/index.d.ts +17 -0
- package/dist/lease-ipc/index.d.ts.map +1 -0
- package/dist/lease-ipc/index.js +16 -0
- package/dist/lease-ipc/index.js.map +1 -0
- package/dist/lease-ipc/messages.d.ts +918 -0
- package/dist/lease-ipc/messages.d.ts.map +1 -0
- package/dist/lease-ipc/messages.js +476 -0
- package/dist/lease-ipc/messages.js.map +1 -0
- package/dist/lease-ipc/version.d.ts +41 -0
- package/dist/lease-ipc/version.d.ts.map +1 -0
- package/dist/lease-ipc/version.js +43 -0
- package/dist/lease-ipc/version.js.map +1 -0
- package/dist/llm/catalog-schema.d.ts +242 -0
- package/dist/llm/catalog-schema.d.ts.map +1 -0
- package/dist/llm/catalog-schema.js +153 -0
- package/dist/llm/catalog-schema.js.map +1 -0
- package/dist/llm/catalog-schema.json +139 -0
- package/dist/llm/index.d.ts +15 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +14 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/interfaces.d.ts +23 -0
- package/dist/llm/interfaces.d.ts.map +1 -1
- package/dist/llm/oauth.d.ts +16 -2
- package/dist/llm/oauth.d.ts.map +1 -1
- package/dist/llm/onboarding.d.ts +126 -0
- package/dist/llm/onboarding.d.ts.map +1 -0
- package/dist/llm/onboarding.js +34 -0
- package/dist/llm/onboarding.js.map +1 -0
- package/dist/llm/provider-def.d.ts +254 -0
- package/dist/llm/provider-def.d.ts.map +1 -0
- package/dist/llm/provider-def.js +93 -0
- package/dist/llm/provider-def.js.map +1 -0
- package/dist/llm/sealed-credential.d.ts +164 -0
- package/dist/llm/sealed-credential.d.ts.map +1 -0
- package/dist/llm/sealed-credential.js +43 -0
- package/dist/llm/sealed-credential.js.map +1 -0
- package/dist/llm/system-of-use.d.ts +383 -0
- package/dist/llm/system-of-use.d.ts.map +1 -0
- package/dist/llm/system-of-use.js +238 -0
- package/dist/llm/system-of-use.js.map +1 -0
- package/dist/llm/system-resolver.d.ts +87 -11
- package/dist/llm/system-resolver.d.ts.map +1 -1
- package/dist/llm/system-resolver.js +14 -7
- package/dist/llm/system-resolver.js.map +1 -1
- package/dist/operations/__tests__/ensures-schema-registry.test.d.ts +17 -0
- package/dist/operations/__tests__/ensures-schema-registry.test.d.ts.map +1 -0
- package/dist/operations/__tests__/ensures-schema-registry.test.js +113 -0
- package/dist/operations/__tests__/ensures-schema-registry.test.js.map +1 -0
- package/dist/operations/admin.d.ts +124 -1
- package/dist/operations/admin.d.ts.map +1 -1
- package/dist/operations/ensures-schema-registry.d.ts +172 -0
- package/dist/operations/ensures-schema-registry.d.ts.map +1 -0
- package/dist/operations/ensures-schema-registry.js +226 -0
- package/dist/operations/ensures-schema-registry.js.map +1 -0
- package/dist/operations/entities.d.ts +110 -0
- package/dist/operations/entities.d.ts.map +1 -0
- package/dist/operations/entities.js +695 -0
- package/dist/operations/entities.js.map +1 -0
- package/dist/operations/llm.d.ts +116 -9
- package/dist/operations/llm.d.ts.map +1 -1
- package/dist/operations/output-contracts-data.d.ts.map +1 -1
- package/dist/operations/output-contracts-data.js +230 -0
- package/dist/operations/output-contracts-data.js.map +1 -1
- package/dist/operations/service.d.ts +68 -0
- package/dist/operations/service.d.ts.map +1 -0
- package/dist/operations/service.js +336 -0
- package/dist/operations/service.js.map +1 -0
- package/dist/operations/tasks.d.ts +109 -0
- package/dist/operations/tasks.d.ts.map +1 -1
- package/dist/operations/tasks.js.map +1 -1
- package/dist/operations/validate.d.ts +1 -12
- package/dist/operations/validate.d.ts.map +1 -1
- package/dist/operations/validate.js +1 -1
- package/dist/playbook.d.ts +116 -0
- package/dist/playbook.d.ts.map +1 -1
- package/dist/release/plan.d.ts +5 -5
- package/dist/session.d.ts +11 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js.map +1 -1
- package/dist/templates/manifest.d.ts +1 -1
- package/dist/tools/agent-tools.d.ts +231 -0
- package/dist/tools/agent-tools.d.ts.map +1 -0
- package/dist/tools/agent-tools.js +25 -0
- package/dist/tools/agent-tools.js.map +1 -0
- package/dist/tools/atomic.d.ts +19 -0
- package/dist/tools/atomic.d.ts.map +1 -1
- package/dist/tools/atomic.js +17 -0
- package/dist/tools/atomic.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/skill-executor.d.ts +7 -0
- package/dist/tools/skill-executor.d.ts.map +1 -1
- package/dist/tools/web-tools.d.ts +217 -0
- package/dist/tools/web-tools.d.ts.map +1 -0
- package/dist/tools/web-tools.js +31 -0
- package/dist/tools/web-tools.js.map +1 -0
- package/dist/vault/service-provider.d.ts +343 -0
- package/dist/vault/service-provider.d.ts.map +1 -0
- package/dist/vault/service-provider.js +857 -0
- package/dist/vault/service-provider.js.map +1 -0
- package/dist/workgraph.d.ts +12 -12
- package/package.json +14 -2
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/__tests__/operation-def.test.ts +7 -1
- package/src/__tests__/provider-def.test.ts +93 -0
- package/src/__tests__/sealed-credential.test.ts +100 -0
- package/src/__tests__/service-provider.test.ts +129 -0
- package/src/__tests__/skill-executor-contract.test.ts +3 -0
- package/src/acceptance-gate.ts +2 -3
- package/src/boundary.ts +70 -20
- package/src/conduit.ts +200 -0
- package/src/config/index.ts +35 -0
- package/src/config.ts +106 -1
- package/src/data-accessor.ts +22 -1
- package/src/dispatch/__tests__/tasks-gateway-crud-ops.test.ts +99 -0
- package/src/dispatch/identity.ts +25 -0
- package/src/dispatch/operation-def.ts +21 -0
- package/src/dispatch/operations-registry.ts +1083 -176
- package/src/index.ts +240 -25
- package/src/lease-ipc/__tests__/freeze.test.ts +342 -0
- package/src/lease-ipc/index.ts +75 -0
- package/src/lease-ipc/messages.ts +588 -0
- package/src/lease-ipc/version.ts +46 -0
- package/src/llm/catalog-schema.json +139 -0
- package/src/llm/catalog-schema.ts +184 -0
- package/src/llm/index.ts +29 -0
- package/src/llm/interfaces.ts +23 -0
- package/src/llm/oauth.ts +16 -2
- package/src/llm/onboarding.ts +131 -0
- package/src/llm/provider-def.ts +291 -0
- package/src/llm/sealed-credential.ts +166 -0
- package/src/llm/system-of-use.ts +503 -0
- package/src/llm/system-resolver.ts +91 -11
- package/src/operations/__tests__/ensures-schema-registry.test.ts +169 -0
- package/src/operations/admin.ts +144 -0
- package/src/operations/ensures-schema-registry.ts +260 -0
- package/src/operations/entities.ts +758 -0
- package/src/operations/llm.ts +120 -8
- package/src/operations/output-contracts-data.ts +264 -0
- package/src/operations/service.ts +360 -0
- package/src/operations/tasks.ts +119 -0
- package/src/operations/validate.ts +1 -14
- package/src/playbook.ts +117 -0
- package/src/session.ts +11 -0
- package/src/tools/agent-tools.ts +270 -0
- package/src/tools/atomic.ts +21 -0
- package/src/tools/index.ts +46 -0
- package/src/tools/skill-executor.ts +7 -0
- package/src/tools/web-tools.ts +247 -0
- package/src/vault/service-provider.ts +1137 -0
- package/dist/tessera.d.ts +0 -32
- package/dist/tessera.d.ts.map +0 -1
- package/dist/tessera.js +0 -11
- package/dist/tessera.js.map +0 -1
- package/dist/warp-chain.d.ts +0 -129
- package/dist/warp-chain.d.ts.map +0 -1
- package/dist/warp-chain.js +0 -13
- package/dist/warp-chain.js.map +0 -1
- package/src/tessera.ts +0 -35
- package/src/warp-chain.ts +0 -185
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service-vault CLI operation contracts — INPUT + OUTPUT schemas (T11941).
|
|
3
|
+
*
|
|
4
|
+
* The schema-first I/O contracts for the four user-facing service-vault CLI
|
|
5
|
+
* verbs (`cleo service connect|list|revoke|status`). They live HERE in the
|
|
6
|
+
* `contracts` leaf package — alongside `tasks.ts` and the OUTPUT-contracts
|
|
7
|
+
* registry — so every consumer (CLI `--describe`, the SDK `describeOperation`,
|
|
8
|
+
* REST clients) resolves the I/O shape against ONE source of truth.
|
|
9
|
+
*
|
|
10
|
+
* AC4 (T11941): each new op carries an INPUT and an OUTPUT schema and appears in
|
|
11
|
+
* the output-contract data. `connect`/`list`/`revoke`/`status` are registered in
|
|
12
|
+
* `INPUT_CONTRACTS` (core) and `OUTPUT_CONTRACTS` (this package) so
|
|
13
|
+
* `cleo service <verb> --describe` resolves a non-null contract pair.
|
|
14
|
+
*
|
|
15
|
+
* ## Secrets never surfaced
|
|
16
|
+
*
|
|
17
|
+
* Every OUTPUT schema describes a NON-SECRET view: `list`/`status` carry
|
|
18
|
+
* `provider`/`label`/`status`/`scopes`/`expiresAt`/`hasCredentials` only —
|
|
19
|
+
* NEVER the decrypted token. `connect` returns the non-secret connection
|
|
20
|
+
* identity. `revoke` returns the `{count, deleted, grantsRemoved}` cascade
|
|
21
|
+
* report. There is no `--field` pointer that resolves to a token, by design.
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
* @module @cleocode/contracts/operations/service
|
|
25
|
+
*
|
|
26
|
+
* @epic T11765
|
|
27
|
+
* @saga T10409
|
|
28
|
+
* @task T11941 — M2-W4 service CLI verbs
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { JsonSchema, OperationInputContract } from './input-contract.js';
|
|
32
|
+
import type { OperationOutputContract } from './output-contract.js';
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// service.connect — store a service credential (token-direct or paste-code)
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Accepted input shape for `service.connect`.
|
|
40
|
+
*
|
|
41
|
+
* Two non-interactive modes (v1, browser-free + testable):
|
|
42
|
+
* - token-direct: `provider` + `token` (+ optional `refreshToken`, `expiresAt`,
|
|
43
|
+
* `scopes`) — stores the token blob `encryptGlobal`-encrypted.
|
|
44
|
+
* - paste-code: `provider` + `code` + `codeVerifier` + `redirectUri` — runs the
|
|
45
|
+
* OAuth `exchangeCode` dance (the interactive flow is a thin wrapper over it).
|
|
46
|
+
*
|
|
47
|
+
* `additionalProperties: false` so a typo'd flag is rejected loudly (DHQ-033).
|
|
48
|
+
*
|
|
49
|
+
* @task T11941
|
|
50
|
+
*/
|
|
51
|
+
export const SERVICE_CONNECT_INPUT_SCHEMA: JsonSchema = {
|
|
52
|
+
type: 'object',
|
|
53
|
+
required: ['provider'],
|
|
54
|
+
additionalProperties: false,
|
|
55
|
+
properties: {
|
|
56
|
+
provider: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
minLength: 1,
|
|
59
|
+
description: 'Service provider key (e.g. github, google, notion).',
|
|
60
|
+
},
|
|
61
|
+
label: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
description: "Connection label, unique within the provider (default: 'default').",
|
|
64
|
+
},
|
|
65
|
+
token: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description:
|
|
68
|
+
'Direct access token to store (token-direct mode). SECRET — never logged/echoed.',
|
|
69
|
+
},
|
|
70
|
+
refreshToken: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'Optional refresh token paired with --token. SECRET.',
|
|
73
|
+
},
|
|
74
|
+
expiresAt: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
description: 'ISO-8601 access-token expiry (token-direct mode).',
|
|
77
|
+
},
|
|
78
|
+
scopes: {
|
|
79
|
+
type: 'array',
|
|
80
|
+
items: { type: 'string' },
|
|
81
|
+
description: 'Granted scope list (non-secret).',
|
|
82
|
+
},
|
|
83
|
+
code: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'OAuth authorization code from the redirect callback (paste-code mode).',
|
|
86
|
+
},
|
|
87
|
+
codeVerifier: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
description: 'PKCE code verifier from service.auth-url, round-tripped (paste-code mode).',
|
|
90
|
+
},
|
|
91
|
+
redirectUri: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
description: 'Redirect URI used in service.auth-url; must match (paste-code mode).',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** Schema-first INPUT contract for `service.connect`. */
|
|
99
|
+
export const serviceConnectInputContract: OperationInputContract<Record<string, unknown>> = {
|
|
100
|
+
operation: 'service.connect',
|
|
101
|
+
schema: SERVICE_CONNECT_INPUT_SCHEMA,
|
|
102
|
+
examples: [
|
|
103
|
+
{
|
|
104
|
+
name: 'token-direct',
|
|
105
|
+
value: { provider: 'github', token: 'gho_xxx', label: 'personal' },
|
|
106
|
+
description: 'Store an already-obtained access token (browser-free v1).',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'paste-code',
|
|
110
|
+
value: {
|
|
111
|
+
provider: 'github',
|
|
112
|
+
code: 'auth-code',
|
|
113
|
+
codeVerifier: 'pkce-verifier',
|
|
114
|
+
redirectUri: 'http://127.0.0.1:0/callback',
|
|
115
|
+
},
|
|
116
|
+
description: 'Exchange an OAuth code + PKCE verifier for tokens.',
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/** OUTPUT contract for `service.connect` — the non-secret mutate envelope. */
|
|
122
|
+
export const serviceConnectOutputContract: OperationOutputContract = {
|
|
123
|
+
operation: 'service.connect',
|
|
124
|
+
shapeNote:
|
|
125
|
+
'Mutate envelope: count=1, created=[connectionId]. `connection` carries the NON-SECRET identity (provider/label/expiresAt). No token is ever returned.',
|
|
126
|
+
dataSchema: {
|
|
127
|
+
type: 'object',
|
|
128
|
+
required: ['count', 'created'],
|
|
129
|
+
additionalProperties: true,
|
|
130
|
+
properties: {
|
|
131
|
+
count: { type: 'number', description: 'Number of connections created/updated (1).' },
|
|
132
|
+
created: {
|
|
133
|
+
type: 'array',
|
|
134
|
+
items: { type: 'string' },
|
|
135
|
+
description: 'The connection id(s) created/updated, as strings.',
|
|
136
|
+
},
|
|
137
|
+
connection: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
description: 'Non-secret connection identity.',
|
|
140
|
+
properties: {
|
|
141
|
+
connectionId: { type: 'number' },
|
|
142
|
+
provider: { type: 'string' },
|
|
143
|
+
label: { type: 'string' },
|
|
144
|
+
expiresAt: { type: ['string', 'null'] },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
fieldPointers: [
|
|
150
|
+
'/data/count',
|
|
151
|
+
'/data/created/0',
|
|
152
|
+
'/data/connection/provider',
|
|
153
|
+
'/data/connection/label',
|
|
154
|
+
'/data/connection/expiresAt',
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// service.list — redacted connection views
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
/** Accepted input shape for `service.list`. */
|
|
163
|
+
export const SERVICE_LIST_INPUT_SCHEMA: JsonSchema = {
|
|
164
|
+
type: 'object',
|
|
165
|
+
required: [],
|
|
166
|
+
additionalProperties: false,
|
|
167
|
+
properties: {
|
|
168
|
+
provider: {
|
|
169
|
+
type: 'string',
|
|
170
|
+
description: 'Optional provider filter; lists all providers when omitted.',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/** Schema-first INPUT contract for `service.list`. */
|
|
176
|
+
export const serviceListInputContract: OperationInputContract<Record<string, unknown>> = {
|
|
177
|
+
operation: 'service.list',
|
|
178
|
+
schema: SERVICE_LIST_INPUT_SCHEMA,
|
|
179
|
+
examples: [
|
|
180
|
+
{ name: 'all', value: {}, description: 'List every service connection (redacted).' },
|
|
181
|
+
{ name: 'one-provider', value: { provider: 'github' }, description: 'Filter to one provider.' },
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/** The redacted per-connection view schema (shared by list + status). */
|
|
186
|
+
const SERVICE_CONNECTION_VIEW_SCHEMA: JsonSchema = {
|
|
187
|
+
type: 'object',
|
|
188
|
+
required: ['provider', 'label', 'status', 'scopes', 'hasCredentials'],
|
|
189
|
+
additionalProperties: true,
|
|
190
|
+
properties: {
|
|
191
|
+
id: { type: 'number' },
|
|
192
|
+
provider: { type: 'string' },
|
|
193
|
+
label: { type: 'string' },
|
|
194
|
+
status: { type: 'string', enum: ['active', 'expired', 'revoked'] },
|
|
195
|
+
scopes: { type: 'array', items: { type: 'string' } },
|
|
196
|
+
expiresAt: { type: ['string', 'null'] },
|
|
197
|
+
connectedAt: { type: 'string' },
|
|
198
|
+
updatedAt: { type: 'string' },
|
|
199
|
+
hasCredentials: {
|
|
200
|
+
type: 'boolean',
|
|
201
|
+
description: 'Whether a credential blob is present — NEVER the token itself.',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/** OUTPUT contract for `service.list` — redacted connection views. */
|
|
207
|
+
export const serviceListOutputContract: OperationOutputContract = {
|
|
208
|
+
operation: 'service.list',
|
|
209
|
+
shapeNote:
|
|
210
|
+
'connections[] are NON-SECRET views — provider/label/status/scopes/expiresAt/hasCredentials only. The decrypted token is NEVER present in any field.',
|
|
211
|
+
dataSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
required: ['connections'],
|
|
214
|
+
additionalProperties: true,
|
|
215
|
+
properties: {
|
|
216
|
+
connections: {
|
|
217
|
+
type: 'array',
|
|
218
|
+
items: SERVICE_CONNECTION_VIEW_SCHEMA,
|
|
219
|
+
description: 'Redacted connection views.',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
fieldPointers: [
|
|
224
|
+
'/data/connections',
|
|
225
|
+
'/data/connections/0/provider',
|
|
226
|
+
'/data/connections/0/label',
|
|
227
|
+
'/data/connections/0/status',
|
|
228
|
+
'/data/connections/0/expiresAt',
|
|
229
|
+
'/data/connections/0/hasCredentials',
|
|
230
|
+
],
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
// service.revoke — hard delete + cascade grants
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
/** Accepted input shape for `service.revoke`. */
|
|
238
|
+
export const SERVICE_REVOKE_INPUT_SCHEMA: JsonSchema = {
|
|
239
|
+
type: 'object',
|
|
240
|
+
required: ['provider', 'label'],
|
|
241
|
+
additionalProperties: false,
|
|
242
|
+
properties: {
|
|
243
|
+
provider: { type: 'string', minLength: 1, description: 'Service provider key.' },
|
|
244
|
+
label: { type: 'string', minLength: 1, description: 'Connection label to revoke.' },
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/** Schema-first INPUT contract for `service.revoke`. */
|
|
249
|
+
export const serviceRevokeInputContract: OperationInputContract<Record<string, unknown>> = {
|
|
250
|
+
operation: 'service.revoke',
|
|
251
|
+
schema: SERVICE_REVOKE_INPUT_SCHEMA,
|
|
252
|
+
examples: [
|
|
253
|
+
{
|
|
254
|
+
name: 'revoke',
|
|
255
|
+
value: { provider: 'github', label: 'personal' },
|
|
256
|
+
description: 'Delete the connection and cascade its agent grants.',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/** OUTPUT contract for `service.revoke` — the cascade-delete report. */
|
|
262
|
+
export const serviceRevokeOutputContract: OperationOutputContract = {
|
|
263
|
+
operation: 'service.revoke',
|
|
264
|
+
shapeNote:
|
|
265
|
+
'Mutate envelope: count=1 + deleted=[provider:label] on success (0 + [] when no such connection). `grantsRemoved` counts the cascaded agent_service_grants rows.',
|
|
266
|
+
dataSchema: {
|
|
267
|
+
type: 'object',
|
|
268
|
+
required: ['count', 'deleted'],
|
|
269
|
+
additionalProperties: true,
|
|
270
|
+
properties: {
|
|
271
|
+
count: { type: 'number', description: '1 when a connection was deleted, else 0.' },
|
|
272
|
+
deleted: {
|
|
273
|
+
type: 'array',
|
|
274
|
+
items: { type: 'string' },
|
|
275
|
+
description: 'The `provider:label` identifier(s) deleted.',
|
|
276
|
+
},
|
|
277
|
+
grantsRemoved: {
|
|
278
|
+
type: 'number',
|
|
279
|
+
description: 'How many agent_service_grants rows were cascaded-deleted.',
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
fieldPointers: ['/data/count', '/data/deleted/0', '/data/grantsRemoved'],
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
// service.status — connection health (expired? needs refresh?)
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
|
|
290
|
+
/** Accepted input shape for `service.status`. */
|
|
291
|
+
export const SERVICE_STATUS_INPUT_SCHEMA: JsonSchema = {
|
|
292
|
+
type: 'object',
|
|
293
|
+
required: [],
|
|
294
|
+
additionalProperties: false,
|
|
295
|
+
properties: {
|
|
296
|
+
provider: {
|
|
297
|
+
type: 'string',
|
|
298
|
+
description: 'Optional provider filter; reports all connections when omitted.',
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/** Schema-first INPUT contract for `service.status`. */
|
|
304
|
+
export const serviceStatusInputContract: OperationInputContract<Record<string, unknown>> = {
|
|
305
|
+
operation: 'service.status',
|
|
306
|
+
schema: SERVICE_STATUS_INPUT_SCHEMA,
|
|
307
|
+
examples: [
|
|
308
|
+
{ name: 'all', value: {}, description: 'Health of every connection.' },
|
|
309
|
+
{
|
|
310
|
+
name: 'one-provider',
|
|
311
|
+
value: { provider: 'github' },
|
|
312
|
+
description: 'Health for one provider.',
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/** OUTPUT contract for `service.status` — per-connection health. */
|
|
318
|
+
export const serviceStatusOutputContract: OperationOutputContract = {
|
|
319
|
+
operation: 'service.status',
|
|
320
|
+
shapeNote:
|
|
321
|
+
'connections[] are NON-SECRET health views: each adds `expired` + `needsRefresh` booleans computed from expiresAt. No token is ever present.',
|
|
322
|
+
dataSchema: {
|
|
323
|
+
type: 'object',
|
|
324
|
+
required: ['connections'],
|
|
325
|
+
additionalProperties: true,
|
|
326
|
+
properties: {
|
|
327
|
+
connections: {
|
|
328
|
+
type: 'array',
|
|
329
|
+
items: {
|
|
330
|
+
type: 'object',
|
|
331
|
+
required: ['provider', 'label', 'status', 'expired', 'needsRefresh'],
|
|
332
|
+
additionalProperties: true,
|
|
333
|
+
properties: {
|
|
334
|
+
provider: { type: 'string' },
|
|
335
|
+
label: { type: 'string' },
|
|
336
|
+
status: { type: 'string', enum: ['active', 'expired', 'revoked'] },
|
|
337
|
+
expiresAt: { type: ['string', 'null'] },
|
|
338
|
+
expired: {
|
|
339
|
+
type: 'boolean',
|
|
340
|
+
description: 'True when expiresAt is in the past (or status=expired).',
|
|
341
|
+
},
|
|
342
|
+
needsRefresh: {
|
|
343
|
+
type: 'boolean',
|
|
344
|
+
description: 'True when the connection is expired and has stored credentials.',
|
|
345
|
+
},
|
|
346
|
+
hasCredentials: { type: 'boolean' },
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
fieldPointers: [
|
|
353
|
+
'/data/connections',
|
|
354
|
+
'/data/connections/0/provider',
|
|
355
|
+
'/data/connections/0/label',
|
|
356
|
+
'/data/connections/0/status',
|
|
357
|
+
'/data/connections/0/expired',
|
|
358
|
+
'/data/connections/0/needsRefresh',
|
|
359
|
+
],
|
|
360
|
+
};
|
package/src/operations/tasks.ts
CHANGED
|
@@ -1078,6 +1078,113 @@ export interface TasksReorderDispatchResult {
|
|
|
1078
1078
|
totalSiblings: number;
|
|
1079
1079
|
}
|
|
1080
1080
|
|
|
1081
|
+
// ---------------------------------------------------------------------------
|
|
1082
|
+
// tasks.reorder-rank / tasks.bulk-move / tasks.assignee
|
|
1083
|
+
// (T11786 · epic T11556 · E1-GATEWAY-CRUD — bulk task mutate ops Studio's
|
|
1084
|
+
// interactive Kanban binds to)
|
|
1085
|
+
// ---------------------------------------------------------------------------
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* Params for `tasks.reorder-rank` — explicit within-column positional ordering.
|
|
1089
|
+
*
|
|
1090
|
+
* Unlike `tasks.reorder` (which moves ONE task to a 1-based index and recomputes
|
|
1091
|
+
* every sibling), this op takes the FULL desired ordering of a sibling/column
|
|
1092
|
+
* scope as a task-ID array and writes each task's `position` to its index in the
|
|
1093
|
+
* array. This is the Kanban "drag a card and the whole column re-ranks" shape:
|
|
1094
|
+
* the client sends the new column order, the op persists it in one pass.
|
|
1095
|
+
*
|
|
1096
|
+
* @task T11786
|
|
1097
|
+
*/
|
|
1098
|
+
export interface TasksReorderRankParams {
|
|
1099
|
+
/**
|
|
1100
|
+
* Ordered task IDs describing the desired top-to-bottom column order. Each
|
|
1101
|
+
* task's `position` is set to its (1-based) index in this array. All IDs
|
|
1102
|
+
* SHOULD share a sibling scope (same `parentId`); IDs not found are reported
|
|
1103
|
+
* in {@link TasksReorderRankResult.skipped} rather than failing the batch.
|
|
1104
|
+
*/
|
|
1105
|
+
orderedIds: string[];
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Result of `tasks.reorder-rank` — within-column rank confirmation.
|
|
1109
|
+
*
|
|
1110
|
+
* @task T11786
|
|
1111
|
+
*/
|
|
1112
|
+
export interface TasksReorderRankResult {
|
|
1113
|
+
/** Task IDs whose `position` was written, in the new top-to-bottom order. */
|
|
1114
|
+
ranked: string[];
|
|
1115
|
+
/** Task IDs from the request that did not resolve to a task (no-op for these). */
|
|
1116
|
+
skipped: string[];
|
|
1117
|
+
/** Number of tasks re-ranked (= `ranked.length`). */
|
|
1118
|
+
count: number;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Params for `tasks.bulk-move` — atomic status/stage transition for N tasks.
|
|
1123
|
+
*
|
|
1124
|
+
* Moves a set of tasks to a new `status` (and optionally `pipelineStage`) inside
|
|
1125
|
+
* a SINGLE DB transaction — the Kanban "select N cards, drop them in a new
|
|
1126
|
+
* column" shape. Either `status` or `pipelineStage` (or both) MUST be supplied;
|
|
1127
|
+
* an empty target is rejected. All-or-nothing: any failure rolls back every move.
|
|
1128
|
+
*
|
|
1129
|
+
* @task T11786
|
|
1130
|
+
*/
|
|
1131
|
+
export interface TasksBulkMoveParams {
|
|
1132
|
+
/** Task IDs to move. Non-empty. */
|
|
1133
|
+
taskIds: string[];
|
|
1134
|
+
/** Target lifecycle status applied to every task. */
|
|
1135
|
+
status?: string;
|
|
1136
|
+
/** Target pipeline stage applied to every task (forward-only validation). */
|
|
1137
|
+
pipelineStage?: string;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Result of `tasks.bulk-move` — atomic multi-move confirmation.
|
|
1141
|
+
*
|
|
1142
|
+
* @task T11786
|
|
1143
|
+
*/
|
|
1144
|
+
export interface TasksBulkMoveResult {
|
|
1145
|
+
/** Task IDs successfully moved (all-or-nothing — empty only when count is 0). */
|
|
1146
|
+
moved: string[];
|
|
1147
|
+
/** The status applied, when supplied. */
|
|
1148
|
+
status?: string;
|
|
1149
|
+
/** The pipeline stage applied, when supplied. */
|
|
1150
|
+
pipelineStage?: string;
|
|
1151
|
+
/** Number of tasks moved (= `moved.length`). */
|
|
1152
|
+
count: number;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Params for `tasks.assignee` — set/clear a task's first-class assignee.
|
|
1157
|
+
*
|
|
1158
|
+
* A first-class human/owner assignee surface, DISTINCT from the agent
|
|
1159
|
+
* claim/unclaim lock (`tasks.claim` does a conditional atomic claim with
|
|
1160
|
+
* agent-lock semantics; `tasks.assignee` is a direct unconditional set/clear an
|
|
1161
|
+
* operator or Studio board uses). Pass `assignee: null` (or omit it) to clear.
|
|
1162
|
+
*
|
|
1163
|
+
* @task T11786
|
|
1164
|
+
*/
|
|
1165
|
+
export interface TasksAssigneeParams {
|
|
1166
|
+
/** Task ID whose assignee is being set or cleared. */
|
|
1167
|
+
taskId: string;
|
|
1168
|
+
/**
|
|
1169
|
+
* The assignee to set. `null` / empty / omitted CLEARS the assignee. A
|
|
1170
|
+
* non-empty string assigns the task to that owner.
|
|
1171
|
+
*/
|
|
1172
|
+
assignee?: string | null;
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Result of `tasks.assignee` — assignee set/clear confirmation.
|
|
1176
|
+
*
|
|
1177
|
+
* @task T11786
|
|
1178
|
+
*/
|
|
1179
|
+
export interface TasksAssigneeResult {
|
|
1180
|
+
/** The task ID whose assignee changed. */
|
|
1181
|
+
taskId: string;
|
|
1182
|
+
/** The new assignee value (null when cleared). */
|
|
1183
|
+
assignee: string | null;
|
|
1184
|
+
/** True when an assignee was set; false when it was cleared. */
|
|
1185
|
+
assigned: boolean;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1081
1188
|
// tasks.relates.add — relatedId is canonical; targetId kept for backward compat (T5149)
|
|
1082
1189
|
export interface TasksRelatesAddParams {
|
|
1083
1190
|
taskId: string;
|
|
@@ -1469,6 +1576,14 @@ export interface TasksCompleteQueryParams {
|
|
|
1469
1576
|
* @saga T10538 (PM-Core V2 agent-trust)
|
|
1470
1577
|
*/
|
|
1471
1578
|
cancelledChildWaiverReason?: string;
|
|
1579
|
+
/**
|
|
1580
|
+
* Reason for waiving the `E_CLEO_DEPENDENCY` gate when this task's own work
|
|
1581
|
+
* is done but its `depends` edges point at not-yet-terminal tasks (a stale or
|
|
1582
|
+
* over-specified dependency). Recorded to `.cleo/audit/depends-waiver.jsonl`.
|
|
1583
|
+
*
|
|
1584
|
+
* @task T11954 (DHQ-071)
|
|
1585
|
+
*/
|
|
1586
|
+
waiveDependsReason?: string;
|
|
1472
1587
|
}
|
|
1473
1588
|
/**
|
|
1474
1589
|
* Result of `tasks.complete` — completion confirmation with unblocked tasks.
|
|
@@ -2004,6 +2119,10 @@ export type TasksOps = {
|
|
|
2004
2119
|
readonly restore: readonly [TasksRestoreParams, TasksRestoreResult];
|
|
2005
2120
|
readonly reparent: readonly [TasksReparentQueryParams, TasksReparentDispatchResult];
|
|
2006
2121
|
readonly reorder: readonly [TasksReorderQueryParams, TasksReorderDispatchResult];
|
|
2122
|
+
// T11786 (epic T11556) — bulk task mutate ops Studio's interactive Kanban binds to.
|
|
2123
|
+
readonly 'reorder-rank': readonly [TasksReorderRankParams, TasksReorderRankResult];
|
|
2124
|
+
readonly 'bulk-move': readonly [TasksBulkMoveParams, TasksBulkMoveResult];
|
|
2125
|
+
readonly assignee: readonly [TasksAssigneeParams, TasksAssigneeResult];
|
|
2007
2126
|
readonly 'relates.add': readonly [TasksRelatesAddParams, TasksRelatesAddResult];
|
|
2008
2127
|
readonly 'relates.add-batch': readonly [TasksRelatesAddBatchParams, TasksRelatesAddBatchResult];
|
|
2009
2128
|
readonly 'relates.remove': readonly [TasksRelatesRemoveParams, TasksRelatesRemoveResult];
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* Validate / Check Domain Operations
|
|
3
3
|
*
|
|
4
4
|
* T982 extension: Added new types for gate, archive, coherence, compliance-sync,
|
|
5
|
-
*
|
|
5
|
+
* grade, canon, workflow-compliance, verify-explain, and all protocol subtypes.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { WarpChain } from '../warp-chain.js';
|
|
9
|
-
|
|
10
8
|
export type ValidationSeverity = 'error' | 'warning' | 'info';
|
|
11
9
|
|
|
12
10
|
export interface ValidationViolation {
|
|
@@ -242,16 +240,6 @@ export interface ValidateArchiveStatsParams {
|
|
|
242
240
|
}
|
|
243
241
|
export type ValidateArchiveStatsResult = Record<string, unknown>;
|
|
244
242
|
|
|
245
|
-
export interface ValidateChainParams {
|
|
246
|
-
chain: WarpChain;
|
|
247
|
-
}
|
|
248
|
-
export interface ValidateChainResult {
|
|
249
|
-
wellFormed: boolean;
|
|
250
|
-
gateSatisfiable: boolean;
|
|
251
|
-
errors: string[];
|
|
252
|
-
warnings: string[];
|
|
253
|
-
}
|
|
254
|
-
|
|
255
243
|
export interface ValidateGradeParams {
|
|
256
244
|
sessionId: string;
|
|
257
245
|
}
|
|
@@ -379,7 +367,6 @@ export type CheckOps = {
|
|
|
379
367
|
readonly 'gate.set': readonly [ValidateGateParams, ValidateGateResult];
|
|
380
368
|
readonly 'verify.explain': readonly [ValidateVerifyExplainParams, ValidateVerifyExplainResult];
|
|
381
369
|
readonly 'archive.stats': readonly [ValidateArchiveStatsParams, ValidateArchiveStatsResult];
|
|
382
|
-
readonly 'chain.validate': readonly [ValidateChainParams, ValidateChainResult];
|
|
383
370
|
readonly grade: readonly [ValidateGradeParams, ValidateGradeResult];
|
|
384
371
|
readonly 'grade.list': readonly [ValidateGradeListParams, ValidateGradeListResult];
|
|
385
372
|
readonly canon: readonly [ValidateCanonParams, ValidateCanonResult];
|
package/src/playbook.ts
CHANGED
|
@@ -58,6 +58,62 @@ export interface PlaybookAgenticNode extends PlaybookNodeBase {
|
|
|
58
58
|
* Enforced at spawn time by composeSpawnPayload (T1261 PSYCHE E4).
|
|
59
59
|
*/
|
|
60
60
|
context_files?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Pin this stage's LLM to a named profile from `llm.profiles` (T11759 · M4).
|
|
63
|
+
*
|
|
64
|
+
* When present, the dispatcher resolves the stage's LLM through the E9
|
|
65
|
+
* chokepoint (`resolveLLMForSystem`) keyed by the cantbook node identity
|
|
66
|
+
* (`cantbook:<playbook>#<nodeId>`) with this profile name threaded as the
|
|
67
|
+
* pin — so the named profile's provider/model/credential win over the
|
|
68
|
+
* background role default. Additive: a node without `profile`/`model`/
|
|
69
|
+
* `provider` resolves exactly as before.
|
|
70
|
+
*/
|
|
71
|
+
profile?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Pin this stage's LLM to an explicit model id (T11759 · M4).
|
|
74
|
+
*
|
|
75
|
+
* A lower-precedence escape hatch than {@link profile}: when no `profile` is
|
|
76
|
+
* declared the dispatcher threads this model id as the resolution hint. The
|
|
77
|
+
* runtime never constructs a transport from it — it is a resolution hint
|
|
78
|
+
* consumed by the Pi runner / model-runner downstream (Gate-13).
|
|
79
|
+
*/
|
|
80
|
+
model?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Pin this stage's LLM to an explicit provider transport (T11759 · M4).
|
|
83
|
+
*
|
|
84
|
+
* Paired with {@link model} as the inline escape hatch when no {@link profile}
|
|
85
|
+
* is declared. A resolution hint only — never used to build a client here.
|
|
86
|
+
*/
|
|
87
|
+
provider?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Per-step skill allowlist enforced at spawn time (T1947 · M4 cantbook
|
|
90
|
+
* done-gate, Gap E/F).
|
|
91
|
+
*
|
|
92
|
+
* When present, the spawned agent's effective skill set is the INTERSECTION
|
|
93
|
+
* of the agent's resolved skills (the Tier-0/1/2 baseline) and this list — a
|
|
94
|
+
* skill not in both is dropped. The allowlist can only RESTRICT the baseline,
|
|
95
|
+
* never expand it: a skill named here that the agent does not already carry is
|
|
96
|
+
* NOT added. Additive: a node without `allowed_skills` spawns with its full
|
|
97
|
+
* baseline skill set, exactly as before.
|
|
98
|
+
*
|
|
99
|
+
* Enforced by `composeSpawnPayload` (it intersects `resolvedAgent.skills` with
|
|
100
|
+
* this list). An empty set after intersection is logged as a warning and the
|
|
101
|
+
* spawn proceeds with no skills.
|
|
102
|
+
*/
|
|
103
|
+
allowed_skills?: string[];
|
|
104
|
+
/**
|
|
105
|
+
* Per-step tool allowlist enforced at spawn time (T1947 · M4 cantbook
|
|
106
|
+
* done-gate, Gap E/F).
|
|
107
|
+
*
|
|
108
|
+
* When present, the spawned agent's effective tool set is the INTERSECTION of
|
|
109
|
+
* the agent's resolved tool baseline and this list — a tool not in both is
|
|
110
|
+
* dropped. Like {@link allowed_skills}, this can only RESTRICT the baseline,
|
|
111
|
+
* never expand it. Additive: a node without `allowed_tools` is unaffected.
|
|
112
|
+
*
|
|
113
|
+
* Enforced by `composeSpawnPayload` AFTER the thin-agent guard, so a worker
|
|
114
|
+
* still cannot acquire a spawn-capable tool it was never granted.
|
|
115
|
+
*/
|
|
116
|
+
allowed_tools?: string[];
|
|
61
117
|
}
|
|
62
118
|
|
|
63
119
|
export interface PlaybookDeterministicNode extends PlaybookNodeBase {
|
|
@@ -77,6 +133,55 @@ export interface PlaybookApprovalNode extends PlaybookNodeBase {
|
|
|
77
133
|
|
|
78
134
|
export type PlaybookNode = PlaybookAgenticNode | PlaybookDeterministicNode | PlaybookApprovalNode;
|
|
79
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Declarative, eval-free predicate over the playbook run `context` used to
|
|
138
|
+
* guard a conditional branch edge (T11806).
|
|
139
|
+
*
|
|
140
|
+
* The predicate is intentionally a *pure data* description — never an
|
|
141
|
+
* arbitrary expression — so the runtime stays deterministic and sandbox-safe.
|
|
142
|
+
* The named `field` is resolved against the accumulated run context
|
|
143
|
+
* (`context[field]`) and compared by exactly one of the optional operators
|
|
144
|
+
* below. When a `PlaybookEdge` carries a `when` predicate, the runtime only
|
|
145
|
+
* traverses that edge if the predicate evaluates to `true`.
|
|
146
|
+
*
|
|
147
|
+
* Exactly one comparison operator (`equals`, `notEquals`, `exists`, `in`, or
|
|
148
|
+
* `truthy`) should be supplied; the parser enforces this so an ambiguous
|
|
149
|
+
* predicate is rejected at parse time rather than mis-routing at runtime.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```yaml
|
|
153
|
+
* edges:
|
|
154
|
+
* - from: classify
|
|
155
|
+
* to: deep-research # taken when context.needsResearch === true
|
|
156
|
+
* when: { field: needsResearch, equals: true }
|
|
157
|
+
* - from: classify
|
|
158
|
+
* to: skip-research # taken when context.needsResearch !== true
|
|
159
|
+
* when: { field: needsResearch, notEquals: true }
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @task T11806 — cantbook runtime branching
|
|
163
|
+
*/
|
|
164
|
+
export interface PlaybookEdgeCondition {
|
|
165
|
+
/** Context key whose value the predicate is evaluated against. */
|
|
166
|
+
field: string;
|
|
167
|
+
/** Edge is satisfied when `context[field]` strictly equals this value. */
|
|
168
|
+
equals?: unknown;
|
|
169
|
+
/** Edge is satisfied when `context[field]` strictly does NOT equal this value. */
|
|
170
|
+
notEquals?: unknown;
|
|
171
|
+
/**
|
|
172
|
+
* When `true`, edge is satisfied iff `field` is present in context;
|
|
173
|
+
* when `false`, satisfied iff `field` is absent from context.
|
|
174
|
+
*/
|
|
175
|
+
exists?: boolean;
|
|
176
|
+
/** Edge is satisfied when `context[field]` is one of these values. */
|
|
177
|
+
in?: unknown[];
|
|
178
|
+
/**
|
|
179
|
+
* When `true`, edge is satisfied iff `context[field]` is truthy;
|
|
180
|
+
* when `false`, satisfied iff `context[field]` is falsy.
|
|
181
|
+
*/
|
|
182
|
+
truthy?: boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
80
185
|
export interface PlaybookEdge {
|
|
81
186
|
from: string;
|
|
82
187
|
to: string;
|
|
@@ -84,6 +189,18 @@ export interface PlaybookEdge {
|
|
|
84
189
|
requires?: string[];
|
|
85
190
|
ensures?: string[];
|
|
86
191
|
};
|
|
192
|
+
/**
|
|
193
|
+
* Optional declarative branch guard (T11806). When present, the edge is
|
|
194
|
+
* only traversed if the {@link PlaybookEdgeCondition} predicate over the
|
|
195
|
+
* run `context` is satisfied. Edges without `when` are unconditional.
|
|
196
|
+
*
|
|
197
|
+
* A node may have multiple outgoing edges as long as every additional
|
|
198
|
+
* edge carries a `when` guard — the runtime evaluates them against the
|
|
199
|
+
* current context and routes to the single satisfied successor. More than
|
|
200
|
+
* one *unconditional* successor remains a fail-closed error (genuine
|
|
201
|
+
* ambiguity).
|
|
202
|
+
*/
|
|
203
|
+
when?: PlaybookEdgeCondition;
|
|
87
204
|
}
|
|
88
205
|
|
|
89
206
|
export interface PlaybookErrorHandler {
|
package/src/session.ts
CHANGED
|
@@ -121,6 +121,17 @@ export interface Session {
|
|
|
121
121
|
previousSessionId?: string | null;
|
|
122
122
|
/** ID of the session that follows this one. @defaultValue undefined */
|
|
123
123
|
nextSessionId?: string | null;
|
|
124
|
+
/**
|
|
125
|
+
* ID of the fork-tree PARENT session that spawned this one (T11639).
|
|
126
|
+
*
|
|
127
|
+
* Sourced from `CLEO_PARENT_SESSION_ID` (stamped by the supervisor — T11629).
|
|
128
|
+
* Distinct from {@link Session.previousSessionId} (the linear resume chain):
|
|
129
|
+
* `parentSessionId` is the orchestrator→worker spawn edge. NULL/undefined for a
|
|
130
|
+
* root session with no spawning parent.
|
|
131
|
+
*
|
|
132
|
+
* @defaultValue undefined
|
|
133
|
+
*/
|
|
134
|
+
parentSessionId?: string | null;
|
|
124
135
|
/** Provider-specific agent identifier string. @defaultValue undefined */
|
|
125
136
|
agentIdentifier?: string | null;
|
|
126
137
|
/** ISO 8601 timestamp of when the handoff was consumed. @defaultValue undefined */
|