@yaklabs-ai/plugin-sdk 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/THIRD-PARTY-INVENTORY.json +1 -1
- package/dist/artifact-provenance.d.ts +956 -0
- package/dist/artifact-provenance.js +565 -0
- package/dist/canonical-transcript.js +7 -5
- package/dist/disclosure.d.ts +30 -2
- package/dist/kay-agent-testing.d.ts +58 -2
- package/dist/kay-agent.d.ts +30 -2
- package/dist/kay-agent.js +19 -8
- package/dist/kay-app.d.ts +36 -7
- package/dist/vendored-mcp.d.ts +17 -0
- package/dist/vendored-mcp.js +19 -8
- package/package.json +5 -1
- package/skills/directory-plugin-authoring/SKILL.md +19 -20
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
// packages/plugin-protocol/dist/artifact-provenance.js
|
|
2
|
+
import { z as z2 } from "zod";
|
|
3
|
+
|
|
4
|
+
// packages/plugin-protocol/dist/session-provenance.js
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var NonEmptyString = z.string().min(1);
|
|
7
|
+
var SessionId = NonEmptyString;
|
|
8
|
+
var SessionRelationship = z.discriminatedUnion("kind", [
|
|
9
|
+
/** Spawn lineage: this session is a subagent child of `sessionId`. */
|
|
10
|
+
z.strictObject({ kind: z.literal("child-of"), sessionId: SessionId }),
|
|
11
|
+
/**
|
|
12
|
+
* This session was forked from a point in `sessionId`'s transcript - `/fork`, and every
|
|
13
|
+
* hindsight followup. `atEntryId` pins the fork point when one was given.
|
|
14
|
+
*/
|
|
15
|
+
z.strictObject({
|
|
16
|
+
kind: z.literal("forked-from"),
|
|
17
|
+
sessionId: SessionId,
|
|
18
|
+
atEntryId: NonEmptyString.optional()
|
|
19
|
+
})
|
|
20
|
+
]);
|
|
21
|
+
var SdkSessionDoor = z.enum([
|
|
22
|
+
"sessions.create",
|
|
23
|
+
"sessions.run",
|
|
24
|
+
"hindsight.runFollowup",
|
|
25
|
+
"agents.run"
|
|
26
|
+
]);
|
|
27
|
+
var SessionCreator = z.discriminatedUnion("kind", [
|
|
28
|
+
/** A person, at the keyboard. `surface` names a scripted experience when one minted it. */
|
|
29
|
+
z.strictObject({
|
|
30
|
+
kind: z.literal("human"),
|
|
31
|
+
surface: NonEmptyString.optional()
|
|
32
|
+
}),
|
|
33
|
+
/** Another session's agent, through a tool call. */
|
|
34
|
+
z.strictObject({
|
|
35
|
+
kind: z.literal("agent"),
|
|
36
|
+
sessionId: SessionId,
|
|
37
|
+
tool: NonEmptyString,
|
|
38
|
+
/**
|
|
39
|
+
* The PARENT SESSION RUN that was driving when this session was minted
|
|
40
|
+
* (R2 provenance). Optional at parse so old rows stay readable; required
|
|
41
|
+
* of new agent producers. Absence on a new row is reported as a
|
|
42
|
+
* `legacy-run-id-missing` gap, never synthesized.
|
|
43
|
+
*/
|
|
44
|
+
runId: NonEmptyString.optional(),
|
|
45
|
+
/**
|
|
46
|
+
* Correlation only; never part of identity. A missing or reused
|
|
47
|
+
* `toolCallId` must not block the exact parent-run link and never
|
|
48
|
+
* participates in mutation-result identity.
|
|
49
|
+
*/
|
|
50
|
+
toolCallId: NonEmptyString.optional()
|
|
51
|
+
}),
|
|
52
|
+
/** A plugin, through one of its SDK doors. */
|
|
53
|
+
z.strictObject({
|
|
54
|
+
kind: z.literal("plugin"),
|
|
55
|
+
pluginId: NonEmptyString,
|
|
56
|
+
door: SdkSessionDoor,
|
|
57
|
+
callerSessionId: SessionId.optional()
|
|
58
|
+
}),
|
|
59
|
+
/** An automation binding that fired; the run id links its durable execution. */
|
|
60
|
+
z.strictObject({
|
|
61
|
+
kind: z.literal("trigger"),
|
|
62
|
+
automationId: NonEmptyString,
|
|
63
|
+
/**
|
|
64
|
+
* The AUTOMATION RUN that fired the binding (R2 provenance). Optional at
|
|
65
|
+
* parse so old rows stay readable; required of new automation producers.
|
|
66
|
+
* Absence on a new row is reported as a `legacy-run-id-missing` gap,
|
|
67
|
+
* never synthesized from the binding or a timestamp.
|
|
68
|
+
*/
|
|
69
|
+
runId: NonEmptyString.optional(),
|
|
70
|
+
bindingName: NonEmptyString,
|
|
71
|
+
triggerKind: z.enum([
|
|
72
|
+
"cron",
|
|
73
|
+
"time",
|
|
74
|
+
"occurrence",
|
|
75
|
+
"uri-change",
|
|
76
|
+
"plugin-event",
|
|
77
|
+
"manual"
|
|
78
|
+
])
|
|
79
|
+
}),
|
|
80
|
+
/** The daemon itself, for one of its own capabilities. */
|
|
81
|
+
z.strictObject({ kind: z.literal("daemon"), capability: NonEmptyString })
|
|
82
|
+
]);
|
|
83
|
+
var SessionDefiner = z.discriminatedUnion("layer", [
|
|
84
|
+
z.strictObject({
|
|
85
|
+
layer: z.literal("plugin"),
|
|
86
|
+
pluginId: NonEmptyString,
|
|
87
|
+
capability: NonEmptyString,
|
|
88
|
+
/** See the type docblock: unpopulated by design until #5230's children land. */
|
|
89
|
+
version: NonEmptyString.optional()
|
|
90
|
+
}),
|
|
91
|
+
z.strictObject({ layer: z.literal("host"), capability: NonEmptyString })
|
|
92
|
+
]);
|
|
93
|
+
var SessionIntent = z.enum(["interactive", "headless"]);
|
|
94
|
+
var SessionCausedByEventShape = z.strictObject({
|
|
95
|
+
/** The plugin's own name for the subscribe handler that made this run, e.g. `"work-record"`. */
|
|
96
|
+
handler: NonEmptyString,
|
|
97
|
+
/** Absent reads as `"session-event"` - see this type's own doc comment. */
|
|
98
|
+
kind: z.enum(["session-event", "backfill"]).optional(),
|
|
99
|
+
/** Required when `kind` is `"session-event"` or absent; must be omitted when `kind` is `"backfill"`. */
|
|
100
|
+
event: z.strictObject({
|
|
101
|
+
/** {@link KayAppSessionEventType} in `@bonsai/plugin-sdk`, mirrored: a closed, extensible union. */
|
|
102
|
+
type: z.enum([
|
|
103
|
+
"turn-settled",
|
|
104
|
+
"phase-shift",
|
|
105
|
+
"human-message",
|
|
106
|
+
"assistant-message",
|
|
107
|
+
"ui-action"
|
|
108
|
+
]),
|
|
109
|
+
entryId: NonEmptyString,
|
|
110
|
+
/** The source run captured at the event boundary; absence remains unresolved. */
|
|
111
|
+
runId: NonEmptyString.optional(),
|
|
112
|
+
/** Exact prior persisted boundary for a projected human-message event; null means empty history. */
|
|
113
|
+
throughEntryId: NonEmptyString.nullable().optional()
|
|
114
|
+
}).optional(),
|
|
115
|
+
/**
|
|
116
|
+
* The plugin-supplied exact-match dedupe key, when it gave one. Absent when the handler chose
|
|
117
|
+
* not to dedupe this run (every call is admitted). Carried here (not just checked and
|
|
118
|
+
* discarded) so a later reader can explain WHY the host refused a same-keyed second run. A
|
|
119
|
+
* `"backfill"` cause always supplies one (`backfill:${sessionId}`) so a sweep can never
|
|
120
|
+
* double-run the same historical session, but that is a caller convention, not a schema rule.
|
|
121
|
+
*/
|
|
122
|
+
dedupeKey: NonEmptyString.optional()
|
|
123
|
+
});
|
|
124
|
+
var SessionCausedByEvent = SessionCausedByEventShape.refine((value) => (value.kind ?? "session-event") === "backfill" || value.event !== void 0, {
|
|
125
|
+
message: 'event is required unless kind is "backfill"',
|
|
126
|
+
path: ["event"]
|
|
127
|
+
}).refine((value) => value.kind !== "backfill" || value.event === void 0, {
|
|
128
|
+
message: 'event must be omitted when kind is "backfill"',
|
|
129
|
+
path: ["event"]
|
|
130
|
+
});
|
|
131
|
+
var SessionProvenanceRecord = z.strictObject({
|
|
132
|
+
relationships: z.array(SessionRelationship),
|
|
133
|
+
createdBy: SessionCreator,
|
|
134
|
+
definedBy: SessionDefiner,
|
|
135
|
+
intent: SessionIntent,
|
|
136
|
+
/** See {@link SessionCausedByEvent}. Present only alongside `createdBy.door === "agents.run"`. */
|
|
137
|
+
causedByEvent: SessionCausedByEvent.optional()
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// packages/plugin-protocol/dist/artifact-provenance.js
|
|
141
|
+
var ARTIFACT_PROVENANCE_VERSION = "kay.artifact-provenance.v1";
|
|
142
|
+
function hasControlCharacter(value) {
|
|
143
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
144
|
+
const code = value.charCodeAt(index);
|
|
145
|
+
if (code <= 31 || code === 127)
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
function isProvenanceJson(input) {
|
|
151
|
+
const active = /* @__PURE__ */ new Set();
|
|
152
|
+
const stack = [{ value: input }];
|
|
153
|
+
while (stack.length > 0) {
|
|
154
|
+
const { value, leave } = stack.pop();
|
|
155
|
+
if (value === null || typeof value === "boolean")
|
|
156
|
+
continue;
|
|
157
|
+
if (typeof value === "string") {
|
|
158
|
+
if (hasControlCharacter(value))
|
|
159
|
+
return false;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (typeof value === "number") {
|
|
163
|
+
if (!Number.isFinite(value) || Object.is(value, -0))
|
|
164
|
+
return false;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (typeof value !== "object")
|
|
168
|
+
return false;
|
|
169
|
+
if (leave) {
|
|
170
|
+
active.delete(value);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (active.has(value))
|
|
174
|
+
return false;
|
|
175
|
+
const array = Array.isArray(value);
|
|
176
|
+
const prototype = Object.getPrototypeOf(value);
|
|
177
|
+
if (!array && prototype !== Object.prototype && prototype !== null)
|
|
178
|
+
return false;
|
|
179
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
180
|
+
const keys = Reflect.ownKeys(descriptors).filter((key) => !array || key !== "length");
|
|
181
|
+
if (array && (keys.length !== value.length || keys.some((key, index) => key !== String(index))))
|
|
182
|
+
return false;
|
|
183
|
+
active.add(value);
|
|
184
|
+
stack.push({ value, leave: true });
|
|
185
|
+
for (const key of keys) {
|
|
186
|
+
if (typeof key !== "string" || hasControlCharacter(key))
|
|
187
|
+
return false;
|
|
188
|
+
const descriptor = descriptors[key];
|
|
189
|
+
if (!descriptor.enumerable || !("value" in descriptor))
|
|
190
|
+
return false;
|
|
191
|
+
stack.push({ value: descriptor.value });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
var Text = z2.string().min(1).refine((value) => !hasControlCharacter(value), {
|
|
197
|
+
message: "Provenance text must not contain control characters"
|
|
198
|
+
});
|
|
199
|
+
var ArtifactProvenanceRevision = z2.strictObject({
|
|
200
|
+
storeId: Text,
|
|
201
|
+
artifactId: Text,
|
|
202
|
+
uri: Text.optional(),
|
|
203
|
+
/** The enclosing commit is resolved by the reader, avoiding a self-referential commit hash. */
|
|
204
|
+
revision: z2.union([
|
|
205
|
+
Text,
|
|
206
|
+
z2.strictObject({ kind: z2.literal("enclosing-commit") }),
|
|
207
|
+
z2.null()
|
|
208
|
+
]),
|
|
209
|
+
operationId: Text.nullable(),
|
|
210
|
+
/** Optional when the store identifies revisions without content addressing (including tombstones). */
|
|
211
|
+
digest: z2.strictObject({ algorithm: Text, value: Text }).optional()
|
|
212
|
+
});
|
|
213
|
+
var ArtifactProvenanceActor = z2.discriminatedUnion("kind", [
|
|
214
|
+
z2.strictObject({
|
|
215
|
+
kind: z2.literal("session"),
|
|
216
|
+
sessionId: Text,
|
|
217
|
+
runId: Text.nullable()
|
|
218
|
+
}),
|
|
219
|
+
z2.strictObject({
|
|
220
|
+
kind: z2.literal("human"),
|
|
221
|
+
userId: Text.optional(),
|
|
222
|
+
surface: Text
|
|
223
|
+
}),
|
|
224
|
+
z2.strictObject({
|
|
225
|
+
kind: z2.literal("plugin"),
|
|
226
|
+
pluginId: Text,
|
|
227
|
+
capability: Text
|
|
228
|
+
}),
|
|
229
|
+
z2.strictObject({ kind: z2.literal("host"), capability: Text }),
|
|
230
|
+
z2.strictObject({ kind: z2.literal("import"), source: Text }),
|
|
231
|
+
z2.strictObject({ kind: z2.literal("unknown") })
|
|
232
|
+
]);
|
|
233
|
+
var ArtifactProvenanceCause = z2.discriminatedUnion("kind", [
|
|
234
|
+
z2.strictObject({
|
|
235
|
+
kind: z2.literal("session"),
|
|
236
|
+
sessionId: Text,
|
|
237
|
+
runId: Text.nullable()
|
|
238
|
+
}),
|
|
239
|
+
z2.strictObject({
|
|
240
|
+
kind: z2.literal("session-event"),
|
|
241
|
+
sessionId: Text,
|
|
242
|
+
cause: SessionCausedByEvent
|
|
243
|
+
}),
|
|
244
|
+
z2.strictObject({
|
|
245
|
+
kind: z2.literal("automation"),
|
|
246
|
+
automationId: Text,
|
|
247
|
+
runId: Text.nullable()
|
|
248
|
+
}),
|
|
249
|
+
z2.strictObject({ kind: z2.literal("operation"), operationId: Text })
|
|
250
|
+
]);
|
|
251
|
+
var ArtifactProvenanceOperation = z2.strictObject({
|
|
252
|
+
id: Text.nullable(),
|
|
253
|
+
at: z2.iso.datetime().nullable(),
|
|
254
|
+
name: Text,
|
|
255
|
+
actor: ArtifactProvenanceActor,
|
|
256
|
+
/** Null means no tool invocation; a known invocation with an unknown id records a gap. */
|
|
257
|
+
invocation: z2.strictObject({
|
|
258
|
+
tool: Text,
|
|
259
|
+
toolCallId: Text.nullable(),
|
|
260
|
+
origin: z2.enum(["model", "host"])
|
|
261
|
+
}).nullable(),
|
|
262
|
+
/** Known causes only; unavailable cause capture requires a gap, never a guessed creation cause. */
|
|
263
|
+
causes: z2.array(ArtifactProvenanceCause)
|
|
264
|
+
});
|
|
265
|
+
var ArtifactProvenanceReference = z2.discriminatedUnion("kind", [
|
|
266
|
+
z2.strictObject({
|
|
267
|
+
kind: z2.literal("session"),
|
|
268
|
+
sessionId: Text,
|
|
269
|
+
runId: Text.optional()
|
|
270
|
+
}),
|
|
271
|
+
z2.strictObject({
|
|
272
|
+
kind: z2.literal("artifact"),
|
|
273
|
+
revision: ArtifactProvenanceRevision
|
|
274
|
+
}),
|
|
275
|
+
z2.strictObject({
|
|
276
|
+
kind: z2.literal("resource"),
|
|
277
|
+
uri: Text,
|
|
278
|
+
revision: Text.nullable()
|
|
279
|
+
})
|
|
280
|
+
]);
|
|
281
|
+
var ArtifactProvenanceGap = z2.strictObject({
|
|
282
|
+
code: z2.enum([
|
|
283
|
+
"unknown",
|
|
284
|
+
"capture-failed",
|
|
285
|
+
"legacy-derived",
|
|
286
|
+
"ambiguous-predecessor",
|
|
287
|
+
"unverified-index",
|
|
288
|
+
"missing-ancestor",
|
|
289
|
+
"cycle",
|
|
290
|
+
"truncated",
|
|
291
|
+
"metadata-write-failed",
|
|
292
|
+
"invalid-record"
|
|
293
|
+
]),
|
|
294
|
+
/** JSON Pointer into this envelope; the empty pointer covers the whole capture. */
|
|
295
|
+
at: z2.string().regex(/^(?:\/(?:[^~/]|~[01])*)*$/).refine((value) => !hasControlCharacter(value)),
|
|
296
|
+
detail: Text.optional()
|
|
297
|
+
}).refine((gap) => gap.at !== "" || gap.code === "capture-failed", {
|
|
298
|
+
message: "Only a whole-capture failure may cover the entire envelope"
|
|
299
|
+
});
|
|
300
|
+
var ArtifactProvenanceSession = z2.strictObject({
|
|
301
|
+
sessionId: Text,
|
|
302
|
+
basis: z2.enum(["recorded", "legacy-derived", "unverified-index", "missing"]),
|
|
303
|
+
record: SessionProvenanceRecord.nullable()
|
|
304
|
+
});
|
|
305
|
+
var ArtifactProvenanceSource = z2.strictObject({
|
|
306
|
+
relationship: z2.enum([
|
|
307
|
+
"revision-of",
|
|
308
|
+
"copied-from",
|
|
309
|
+
"harvested-from",
|
|
310
|
+
"restored-from",
|
|
311
|
+
"accepted-from",
|
|
312
|
+
"imported-from"
|
|
313
|
+
]),
|
|
314
|
+
revision: ArtifactProvenanceRevision
|
|
315
|
+
});
|
|
316
|
+
var ArtifactProvenanceMutation = z2.strictObject({
|
|
317
|
+
kind: z2.enum([
|
|
318
|
+
"create",
|
|
319
|
+
"update",
|
|
320
|
+
"delete",
|
|
321
|
+
"copy",
|
|
322
|
+
"harvest",
|
|
323
|
+
"restore",
|
|
324
|
+
"accept",
|
|
325
|
+
"import"
|
|
326
|
+
]),
|
|
327
|
+
target: ArtifactProvenanceRevision,
|
|
328
|
+
/** Retained from the source on copies/acceptance; operation.actor is the persistence actor. */
|
|
329
|
+
producer: ArtifactProvenanceOperation,
|
|
330
|
+
sources: z2.array(ArtifactProvenanceSource)
|
|
331
|
+
});
|
|
332
|
+
var Envelope = z2.strictObject({
|
|
333
|
+
version: z2.literal(ARTIFACT_PROVENANCE_VERSION),
|
|
334
|
+
operation: ArtifactProvenanceOperation,
|
|
335
|
+
artifacts: z2.array(ArtifactProvenanceMutation).min(1),
|
|
336
|
+
sessions: z2.array(ArtifactProvenanceSession),
|
|
337
|
+
subjects: z2.array(ArtifactProvenanceReference),
|
|
338
|
+
evidence: z2.array(ArtifactProvenanceReference),
|
|
339
|
+
gaps: z2.array(ArtifactProvenanceGap)
|
|
340
|
+
});
|
|
341
|
+
var UNKNOWN = [
|
|
342
|
+
"unknown",
|
|
343
|
+
"capture-failed",
|
|
344
|
+
"metadata-write-failed",
|
|
345
|
+
"invalid-record"
|
|
346
|
+
];
|
|
347
|
+
var MISSING = ["missing-ancestor", "truncated"];
|
|
348
|
+
function checkOperation(operation, path, gap, session) {
|
|
349
|
+
if (operation.id === null)
|
|
350
|
+
gap(`${path}/id`, UNKNOWN);
|
|
351
|
+
if (operation.at === null)
|
|
352
|
+
gap(`${path}/at`, UNKNOWN);
|
|
353
|
+
if (operation.actor.kind === "unknown")
|
|
354
|
+
gap(`${path}/actor`, UNKNOWN);
|
|
355
|
+
if (operation.actor.kind === "session") {
|
|
356
|
+
session(operation.actor.sessionId, `${path}/actor/sessionId`);
|
|
357
|
+
if (operation.actor.runId === null)
|
|
358
|
+
gap(`${path}/actor/runId`, UNKNOWN);
|
|
359
|
+
}
|
|
360
|
+
if (operation.invocation?.toolCallId === null)
|
|
361
|
+
gap(`${path}/invocation/toolCallId`, UNKNOWN);
|
|
362
|
+
operation.causes.forEach((cause, index) => {
|
|
363
|
+
const causePath = `${path}/causes/${index}`;
|
|
364
|
+
if (cause.kind === "session" || cause.kind === "session-event")
|
|
365
|
+
session(cause.sessionId, `${causePath}/sessionId`);
|
|
366
|
+
if (cause.kind === "session-event" && (cause.cause.kind ?? "session-event") !== "backfill" && cause.cause.event?.runId === void 0) {
|
|
367
|
+
gap(`${causePath}/cause/event/runId`, UNKNOWN);
|
|
368
|
+
}
|
|
369
|
+
if ("runId" in cause && cause.runId === null)
|
|
370
|
+
gap(`${causePath}/runId`, UNKNOWN);
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
function checkRevision(revision, path, gap, issue, currentTarget = false) {
|
|
374
|
+
if (revision.revision === null)
|
|
375
|
+
gap(`${path}/revision`, UNKNOWN);
|
|
376
|
+
else if (typeof revision.revision === "object") {
|
|
377
|
+
if (!currentTarget)
|
|
378
|
+
issue(path.slice(1).split("/"), "Only the current target may refer to its enclosing commit");
|
|
379
|
+
if (revision.digest === void 0)
|
|
380
|
+
issue(path.slice(1).split("/"), "An enclosing-commit target must bind the exact content digest before commit");
|
|
381
|
+
}
|
|
382
|
+
if (revision.operationId === null)
|
|
383
|
+
gap(`${path}/operationId`, UNKNOWN);
|
|
384
|
+
}
|
|
385
|
+
function checkGraph(envelope, gap, issue) {
|
|
386
|
+
const nodes = new Map(envelope.sessions.map((node, index) => [node.sessionId, index]));
|
|
387
|
+
const edges = /* @__PURE__ */ new Map();
|
|
388
|
+
envelope.sessions.forEach((node, index) => {
|
|
389
|
+
const path = `/sessions/${index}`;
|
|
390
|
+
if (nodes.get(node.sessionId) !== index)
|
|
391
|
+
issue(["sessions", index, "sessionId"], "Session snapshots must be deduplicated by sessionId");
|
|
392
|
+
if (node.basis === "missing") {
|
|
393
|
+
if (node.record !== null)
|
|
394
|
+
issue(["sessions", index, "record"], "A missing snapshot cannot carry a creation record");
|
|
395
|
+
gap(path, MISSING);
|
|
396
|
+
} else if (node.record === null) {
|
|
397
|
+
issue(["sessions", index, "record"], "A non-missing snapshot requires its creation record");
|
|
398
|
+
}
|
|
399
|
+
if (node.basis === "legacy-derived")
|
|
400
|
+
gap(path, ["legacy-derived"]);
|
|
401
|
+
if (node.basis === "unverified-index")
|
|
402
|
+
gap(path, ["unverified-index"]);
|
|
403
|
+
const record = node.record;
|
|
404
|
+
if (record === null)
|
|
405
|
+
return;
|
|
406
|
+
const outgoing = record.relationships.map((relationship, edgeIndex) => ({
|
|
407
|
+
id: relationship.sessionId,
|
|
408
|
+
path: `${path}/record/relationships/${edgeIndex}/sessionId`
|
|
409
|
+
}));
|
|
410
|
+
const creator = record.createdBy;
|
|
411
|
+
if (creator.kind === "agent")
|
|
412
|
+
outgoing.push({
|
|
413
|
+
id: creator.sessionId,
|
|
414
|
+
path: `${path}/record/createdBy/sessionId`
|
|
415
|
+
});
|
|
416
|
+
if (creator.kind === "plugin" && creator.callerSessionId !== void 0)
|
|
417
|
+
outgoing.push({
|
|
418
|
+
id: creator.callerSessionId,
|
|
419
|
+
path: `${path}/record/createdBy/callerSessionId`
|
|
420
|
+
});
|
|
421
|
+
if ((creator.kind === "agent" || creator.kind === "trigger") && creator.runId === void 0 && node.basis === "recorded")
|
|
422
|
+
gap(`${path}/record/createdBy/runId`, UNKNOWN);
|
|
423
|
+
const eventCause = record.causedByEvent;
|
|
424
|
+
if (eventCause !== void 0 && (eventCause.kind ?? "session-event") !== "backfill" && eventCause.event?.runId === void 0 && node.basis === "recorded") {
|
|
425
|
+
gap(`${path}/record/causedByEvent/event/runId`, UNKNOWN);
|
|
426
|
+
}
|
|
427
|
+
edges.set(node.sessionId, outgoing);
|
|
428
|
+
outgoing.forEach((edge) => {
|
|
429
|
+
if (!nodes.has(edge.id))
|
|
430
|
+
gap(edge.path, MISSING);
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
const state = /* @__PURE__ */ new Map();
|
|
434
|
+
for (const node of envelope.sessions) {
|
|
435
|
+
if (state.has(node.sessionId))
|
|
436
|
+
continue;
|
|
437
|
+
const stack = [{ id: node.sessionId, next: 0 }];
|
|
438
|
+
state.set(node.sessionId, "active");
|
|
439
|
+
while (stack.length > 0) {
|
|
440
|
+
const current = stack[stack.length - 1];
|
|
441
|
+
const edge = edges.get(current.id)?.[current.next++];
|
|
442
|
+
if (edge === void 0) {
|
|
443
|
+
state.set(current.id, "done");
|
|
444
|
+
stack.pop();
|
|
445
|
+
} else if (state.get(edge.id) === "active") {
|
|
446
|
+
gap(edge.path, ["cycle"]);
|
|
447
|
+
} else if (nodes.has(edge.id) && !state.has(edge.id)) {
|
|
448
|
+
state.set(edge.id, "active");
|
|
449
|
+
stack.push({ id: edge.id, next: 0 });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function validateEnvelope(envelope, context) {
|
|
455
|
+
const issue = (path, message) => context.addIssue({ code: "custom", path, message });
|
|
456
|
+
const gap = (path, codes) => {
|
|
457
|
+
if (!envelope.gaps.some((entry) => entry.code === "capture-failed" && entry.at === "" || codes.includes(entry.code) && (path === entry.at || path.startsWith(`${entry.at}/`)))) {
|
|
458
|
+
issue(path.slice(1).split("/"), `Unresolved provenance requires an explicit ${codes.join(" or ")} gap`);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
const nodes = new Set(envelope.sessions.map((node) => node.sessionId));
|
|
462
|
+
const session = (id, path) => {
|
|
463
|
+
if (!nodes.has(id))
|
|
464
|
+
gap(path, MISSING);
|
|
465
|
+
};
|
|
466
|
+
if (envelope.operation.id === null)
|
|
467
|
+
issue(["operation", "id"], "The current mutation requires a fresh operation identity");
|
|
468
|
+
checkOperation(envelope.operation, "/operation", gap, session);
|
|
469
|
+
const targets = /* @__PURE__ */ new Set();
|
|
470
|
+
envelope.artifacts.forEach((artifact, index) => {
|
|
471
|
+
const path = `/artifacts/${index}`;
|
|
472
|
+
const key = JSON.stringify([
|
|
473
|
+
artifact.target.storeId,
|
|
474
|
+
artifact.target.artifactId
|
|
475
|
+
]);
|
|
476
|
+
if (targets.has(key))
|
|
477
|
+
issue(["artifacts", index, "target"], "One operation records each target artifact once");
|
|
478
|
+
targets.add(key);
|
|
479
|
+
if (artifact.target.operationId !== envelope.operation.id)
|
|
480
|
+
issue(["artifacts", index, "target", "operationId"], "The target must name the current persistence operation");
|
|
481
|
+
checkRevision(artifact.target, `${path}/target`, gap, issue, true);
|
|
482
|
+
checkOperation(artifact.producer, `${path}/producer`, gap, session);
|
|
483
|
+
artifact.sources.forEach((source, sourceIndex) => checkRevision(source.revision, `${path}/sources/${sourceIndex}/revision`, gap, issue));
|
|
484
|
+
const requiredSource = {
|
|
485
|
+
create: void 0,
|
|
486
|
+
update: "revision-of",
|
|
487
|
+
delete: "revision-of",
|
|
488
|
+
copy: "copied-from",
|
|
489
|
+
harvest: "harvested-from",
|
|
490
|
+
restore: "restored-from",
|
|
491
|
+
accept: "accepted-from",
|
|
492
|
+
import: "imported-from"
|
|
493
|
+
}[artifact.kind];
|
|
494
|
+
if (requiredSource !== void 0 && !artifact.sources.some((source) => source.relationship === requiredSource))
|
|
495
|
+
gap(`${path}/sources`, UNKNOWN);
|
|
496
|
+
});
|
|
497
|
+
for (const role of ["subjects", "evidence"]) {
|
|
498
|
+
envelope[role].forEach((reference, index) => {
|
|
499
|
+
const path = `/${role}/${index}`;
|
|
500
|
+
if (reference.kind === "session")
|
|
501
|
+
session(reference.sessionId, `${path}/sessionId`);
|
|
502
|
+
if (reference.kind === "artifact")
|
|
503
|
+
checkRevision(reference.revision, `${path}/revision`, gap, issue);
|
|
504
|
+
if (reference.kind === "resource" && reference.revision === null)
|
|
505
|
+
gap(`${path}/revision`, UNKNOWN);
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
checkGraph(envelope, gap, issue);
|
|
509
|
+
}
|
|
510
|
+
var ArtifactProvenanceEnvelopeV1 = z2.unknown().refine(isProvenanceJson, {
|
|
511
|
+
message: "Provenance must be plain, acyclic, lossless JSON without control characters"
|
|
512
|
+
}).pipe(Envelope.superRefine(validateEnvelope));
|
|
513
|
+
function parseArtifactProvenanceEnvelope(input) {
|
|
514
|
+
return ArtifactProvenanceEnvelopeV1.parse(input);
|
|
515
|
+
}
|
|
516
|
+
var ArtifactProvenanceCaptureContextSchema = z2.strictObject({
|
|
517
|
+
operation: ArtifactProvenanceOperation,
|
|
518
|
+
sessions: z2.array(ArtifactProvenanceSession),
|
|
519
|
+
subjects: z2.array(ArtifactProvenanceReference),
|
|
520
|
+
evidence: z2.array(ArtifactProvenanceReference),
|
|
521
|
+
gaps: z2.array(ArtifactProvenanceGap)
|
|
522
|
+
});
|
|
523
|
+
function parseArtifactProvenanceCaptureContext(input) {
|
|
524
|
+
return ArtifactProvenanceCaptureContextSchema.parse(input);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// packages/plugin-protocol/dist/artifact-provenance-capture.js
|
|
528
|
+
function finalizeArtifactProvenanceEnvelope(capture, artifacts) {
|
|
529
|
+
const artifactGaps = [];
|
|
530
|
+
const blanket = capture.gaps.some((gap) => gap.code === "capture-failed" && gap.at === "");
|
|
531
|
+
if (!blanket) {
|
|
532
|
+
artifacts.forEach((artifact, index) => {
|
|
533
|
+
if (artifact.target.revision === null) {
|
|
534
|
+
artifactGaps.push({
|
|
535
|
+
code: "unknown",
|
|
536
|
+
at: `/artifacts/${index}/target/revision`
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
if (artifact.producer === capture.operation) {
|
|
540
|
+
for (const gap of capture.gaps) {
|
|
541
|
+
if (gap.at === "/operation" || gap.at.startsWith("/operation/")) {
|
|
542
|
+
artifactGaps.push({
|
|
543
|
+
...gap,
|
|
544
|
+
at: `/artifacts/${index}/producer${gap.at.slice("/operation".length)}`
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
return parseArtifactProvenanceEnvelope({
|
|
552
|
+
version: ARTIFACT_PROVENANCE_VERSION,
|
|
553
|
+
operation: capture.operation,
|
|
554
|
+
artifacts,
|
|
555
|
+
sessions: capture.sessions,
|
|
556
|
+
subjects: capture.subjects,
|
|
557
|
+
evidence: capture.evidence,
|
|
558
|
+
gaps: [...capture.gaps, ...artifactGaps]
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
export {
|
|
562
|
+
finalizeArtifactProvenanceEnvelope,
|
|
563
|
+
parseArtifactProvenanceCaptureContext,
|
|
564
|
+
parseArtifactProvenanceEnvelope
|
|
565
|
+
};
|
|
@@ -543,11 +543,6 @@ function isKernelMessageRole(role) {
|
|
|
543
543
|
return Object.hasOwn(KERNEL_MESSAGE_ROLES, role);
|
|
544
544
|
}
|
|
545
545
|
|
|
546
|
-
// packages/herd-transcript/dist/is-object.js
|
|
547
|
-
function isObject(value) {
|
|
548
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
546
|
// packages/herd-transcript/dist/run-failure-classifier.js
|
|
552
547
|
var MAX_FAILURE_TEXT_CHARS = 2e3;
|
|
553
548
|
function boundedFailureText(text) {
|
|
@@ -625,6 +620,13 @@ function parsePresentationAnchor(value) {
|
|
|
625
620
|
|
|
626
621
|
// packages/herd-transcript/dist/tool-call-failure.js
|
|
627
622
|
import { z as z5 } from "zod";
|
|
623
|
+
|
|
624
|
+
// packages/herd-transcript/dist/is-object.js
|
|
625
|
+
function isObject(value) {
|
|
626
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// packages/herd-transcript/dist/tool-call-failure.js
|
|
628
630
|
var TOOL_CALL_FAILURE_DETAILS_KEY = "toolCallFailure";
|
|
629
631
|
var TOOL_CALL_FAILURE_DOMAIN = "tool-call";
|
|
630
632
|
var TOOL_CALL_FAILURE_CATEGORIES = [
|
package/dist/disclosure.d.ts
CHANGED
|
@@ -2431,9 +2431,19 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
|
|
|
2431
2431
|
* 0.44.0 adds `words.kinds` to a reference presentation (#15905): an ordered list of address patterns
|
|
2432
2432
|
* and the kind each one names. Additive: a plugin that lists them declares ^0.44.0.
|
|
2433
2433
|
*
|
|
2434
|
-
* 0.45.0 adds declared plugin cards and app.implementCard for their read/submit endpoints.
|
|
2434
|
+
* 0.45.0 adds declared plugin cards and app.implementCard for their read/submit endpoints. It also
|
|
2435
|
+
* lets a plugin declare what the window hardcoded about it (#15906). A reference presentation gains
|
|
2436
|
+
* `accountLinks`, how a page opens under the account an address means, and a `local-app` open, for
|
|
2437
|
+
* an item an app on this machine shows; a plugin the person installed can't declare that open. A
|
|
2438
|
+
* `webSession` gains `signInFirst`. A URI module defines `lookupWebLink` and sets `looksUpWebLinks`
|
|
2439
|
+
* to find a page when someone opens the address, and a preview field marks which `part` of a message
|
|
2440
|
+
* it is. A claim's `brandIcon` is a file path and no longer inline markup, which only this repo's
|
|
2441
|
+
* Microsoft plugin used. Otherwise additive: a plugin using any of these declares ^0.45.0.
|
|
2442
|
+
*
|
|
2443
|
+
* 0.46.0 adds `@bonsai/plugin-sdk/artifact-provenance`, so a plugin shipped as files can finalize
|
|
2444
|
+
* and read the provenance the host captured. Additive: a plugin that imports it declares ^0.46.0.
|
|
2435
2445
|
*/
|
|
2436
|
-
declare const KAY_PLUGIN_SDK_VERSION: "0.
|
|
2446
|
+
declare const KAY_PLUGIN_SDK_VERSION: "0.46.0";
|
|
2437
2447
|
|
|
2438
2448
|
declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
|
|
2439
2449
|
|
|
@@ -4703,6 +4713,7 @@ declare function refineWebSessionScopeConfined(webSession: {
|
|
|
4703
4713
|
readonly probe: {
|
|
4704
4714
|
readonly url: string;
|
|
4705
4715
|
};
|
|
4716
|
+
readonly signInFirst?: string | undefined;
|
|
4706
4717
|
}, ctx: z.RefinementCtx): void;
|
|
4707
4718
|
|
|
4708
4719
|
declare const RegistrableDomain: z.ZodString;
|
|
@@ -9521,6 +9532,11 @@ declare type UriClaim = UriSchemeClaim | UriPatternClaim | UrlPatternClaim;
|
|
|
9521
9532
|
* - `base64`: unpadded base64 of the UTF-8 text (`{base64(:id :calendar)}`).
|
|
9522
9533
|
* - `slackTimestamp`: a Slack archive message token as the API's timestamp
|
|
9523
9534
|
* (`p1783350000000100` becomes `1783350000.000100`).
|
|
9535
|
+
* - `beforeColon`: the part of a `<team>:<user>` id before the colon. It fills nothing for an id
|
|
9536
|
+
* with no colon or nothing before it.
|
|
9537
|
+
* - `beforeTilde`: the part of an id before its last `~`. It fills nothing with no `~`.
|
|
9538
|
+
* - `encoded`: every reserved character escaped, `:` and `@` too, for a whole URL carried as a
|
|
9539
|
+
* query value (`continue={encoded(:url)}`).
|
|
9524
9540
|
*
|
|
9525
9541
|
* A transform that cannot read its input fills nothing. A claim whose `normalizeTo` fills nothing
|
|
9526
9542
|
* does not match; a `sourceUrl` that fills nothing paints no link.
|
|
@@ -9779,6 +9795,13 @@ declare interface UriModule {
|
|
|
9779
9795
|
readonly uri: string;
|
|
9780
9796
|
readonly payload: unknown;
|
|
9781
9797
|
}, ctx: UriResolveContext): Promise<UriOperationDescription | undefined>;
|
|
9798
|
+
/**
|
|
9799
|
+
* Find the web address of `uri` by asking the provider, for a resource whose address alone can't
|
|
9800
|
+
* name its page. Called only when someone opens the address, under the account it means, and never
|
|
9801
|
+
* to draw a reference. `undefined` means there's no page to open. A plugin module that defines
|
|
9802
|
+
* this sets `looksUpWebLinks` in its manifest.
|
|
9803
|
+
*/
|
|
9804
|
+
lookupWebLink?(uri: string, ctx: UriResolveContext): Promise<string | undefined>;
|
|
9782
9805
|
readonly getCachePolicy?: UriCachePolicyResolver;
|
|
9783
9806
|
/**
|
|
9784
9807
|
* Code matching, for the host's own modules whose addresses no claim can describe (a bare file
|
|
@@ -9900,6 +9923,11 @@ declare interface UriOperationDescription {
|
|
|
9900
9923
|
readonly editable?: true;
|
|
9901
9924
|
/** Longest edited value, in UTF-16 code units. Meaningful only with `editable`. */
|
|
9902
9925
|
readonly maxLength?: number;
|
|
9926
|
+
/**
|
|
9927
|
+
* Which part of a message this field is, when the call sends one. A preview with a `to` and
|
|
9928
|
+
* a `text` is drawn as a message; without them it stays labelled rows.
|
|
9929
|
+
*/
|
|
9930
|
+
readonly part?: "to" | "cc" | "bcc" | "subject" | "text";
|
|
9903
9931
|
}[];
|
|
9904
9932
|
};
|
|
9905
9933
|
/** True only when every displayed fact comes from the input, independent of the executing account. */
|