@yaklabs-ai/plugin-sdk 0.13.4 → 0.13.5
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 +45 -8
- package/THIRD-PARTY-INVENTORY.json +9 -19
- package/THIRD-PARTY-NOTICES.md +9 -15
- package/dist/disclosure.d.ts +6181 -713
- package/dist/disclosure.js +9 -30
- package/dist/kay-agent-testing.d.ts +6189 -721
- package/dist/kay-agent-testing.js +3 -15
- package/dist/kay-agent.d.ts +6237 -757
- package/dist/kay-agent.js +80 -78
- package/dist/kay-app.d.ts +6910 -780
- package/dist/kay-app.js +4 -0
- package/dist/phase-shift.d.ts +4 -4
- package/dist/phase-shift.js +31 -25
- package/dist/transcript.d.ts +6 -6
- package/dist/transcript.js +6 -0
- package/package.json +1 -1
- package/skills/directory-plugin-authoring/SKILL.md +34 -22
package/dist/kay-app.js
CHANGED
|
@@ -258,6 +258,8 @@ var UriProviderError = class extends UriError {
|
|
|
258
258
|
retryable;
|
|
259
259
|
/** Provider-directed delay before retrying, in milliseconds. */
|
|
260
260
|
retryAfterMs;
|
|
261
|
+
/** See {@link UriProviderErrorOptions.effect}. */
|
|
262
|
+
effect;
|
|
261
263
|
constructor(options) {
|
|
262
264
|
super(options.message);
|
|
263
265
|
this.name = "UriProviderError";
|
|
@@ -276,6 +278,8 @@ var UriProviderError = class extends UriError {
|
|
|
276
278
|
}
|
|
277
279
|
this.retryAfterMs = options.retryAfterMs;
|
|
278
280
|
}
|
|
281
|
+
if (options.effect !== void 0)
|
|
282
|
+
this.effect = options.effect;
|
|
279
283
|
}
|
|
280
284
|
};
|
|
281
285
|
var UriNotFoundError = class extends UriError {
|
package/dist/phase-shift.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export declare interface PhaseShiftTimelineChange {
|
|
|
62
62
|
* version-1 record's source timestamps from the entries it referenced. Those
|
|
63
63
|
* references are branch-validated by the fold, so the resolution is total.
|
|
64
64
|
*/
|
|
65
|
-
export declare function phaseShiftTimelineFromEntries(entries: readonly
|
|
65
|
+
export declare function phaseShiftTimelineFromEntries(entries: readonly TranscriptSourceEntryLike[]): readonly PhaseShiftTimelineRecord[];
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* One accepted detector check, as a surface reads it.
|
|
@@ -96,7 +96,7 @@ export declare interface PhaseShiftTimelineRecord {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/** The fields the customType selector needs off a session entry. */
|
|
99
|
-
declare interface
|
|
99
|
+
declare interface TranscriptEntryLike {
|
|
100
100
|
readonly id: string;
|
|
101
101
|
readonly type: string;
|
|
102
102
|
readonly customType?: string;
|
|
@@ -108,7 +108,7 @@ declare interface TranscriptEntry {
|
|
|
108
108
|
* A tree entry plus the ISO timestamp the timeline projections read alongside
|
|
109
109
|
* the walk result (`turnSegments`, `phaseShiftTimelineFromEntries`).
|
|
110
110
|
*/
|
|
111
|
-
declare interface
|
|
111
|
+
declare interface TranscriptSourceEntryLike extends TranscriptTreeEntryLike {
|
|
112
112
|
readonly timestamp: string;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -119,7 +119,7 @@ declare interface TranscriptSourceEntry extends TranscriptTreeEntry {
|
|
|
119
119
|
* v3 log carries an ISO string, so requiring either shape here would force one
|
|
120
120
|
* class of caller to convert entries it only wants walked.
|
|
121
121
|
*/
|
|
122
|
-
declare interface
|
|
122
|
+
declare interface TranscriptTreeEntryLike extends TranscriptEntryLike {
|
|
123
123
|
readonly parentId?: string | null;
|
|
124
124
|
readonly targetId?: string | null;
|
|
125
125
|
}
|
package/dist/phase-shift.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// packages/plugin-protocol/dist/phase-shift.js
|
|
2
|
-
import { z } from "zod";
|
|
2
|
+
import { z as z2 } from "zod";
|
|
3
3
|
|
|
4
4
|
// packages/plugin-protocol/dist/transcript.js
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var WorkBlockCoverageSchema = z.strictObject({
|
|
7
|
+
firstToolResultEntryId: z.string().min(1),
|
|
8
|
+
lastToolResultEntryId: z.string().min(1),
|
|
9
|
+
toolResultEntryIds: z.array(z.string().min(1)).min(1).max(4096)
|
|
10
|
+
}).refine((value) => value.firstToolResultEntryId === value.toolResultEntryIds[0] && value.lastToolResultEntryId === value.toolResultEntryIds.at(-1) && new Set(value.toolResultEntryIds).size === value.toolResultEntryIds.length);
|
|
5
11
|
function branchEntryIds(entries) {
|
|
6
12
|
const last = entries[entries.length - 1];
|
|
7
13
|
if (last === void 0)
|
|
@@ -23,48 +29,48 @@ var PHASE_SHIFT_ENTRY_NAME = "observation";
|
|
|
23
29
|
var PHASE_SHIFT_CUSTOM_TYPE = `ext:${PHASE_SHIFT_EXTENSION_ID}:${PHASE_SHIFT_ENTRY_NAME}`;
|
|
24
30
|
var PHASE_SHIFT_TIMELINE_CUSTOM_TYPE = `ext:${PHASE_SHIFT_EXTENSION_ID}:timeline`;
|
|
25
31
|
var PHASE_SHIFT_DETECTOR_VERSION = "activity-memory-v1";
|
|
26
|
-
var entryId =
|
|
27
|
-
var purpose =
|
|
28
|
-
var sourceTime =
|
|
29
|
-
var phaseShiftMemorySchema =
|
|
32
|
+
var entryId = z2.string().min(1).max(256);
|
|
33
|
+
var purpose = z2.string().trim().min(1).max(320);
|
|
34
|
+
var sourceTime = z2.iso.datetime();
|
|
35
|
+
var phaseShiftMemorySchema = z2.object({
|
|
30
36
|
startEntryId: entryId,
|
|
31
37
|
purpose,
|
|
32
|
-
anchors:
|
|
38
|
+
anchors: z2.array(z2.object({ entryId, excerpt: z2.string().max(250) })).min(1).max(3)
|
|
33
39
|
});
|
|
34
|
-
var phaseShiftCostSchema =
|
|
35
|
-
amountUsd:
|
|
36
|
-
amountBasis:
|
|
37
|
-
inputTokens:
|
|
38
|
-
outputTokens:
|
|
40
|
+
var phaseShiftCostSchema = z2.object({
|
|
41
|
+
amountUsd: z2.number().nonnegative(),
|
|
42
|
+
amountBasis: z2.enum(["measured", "list-estimate", "unknown"]),
|
|
43
|
+
inputTokens: z2.number().int().nonnegative(),
|
|
44
|
+
outputTokens: z2.number().int().nonnegative(),
|
|
39
45
|
/**
|
|
40
46
|
* The highest provider-attempt ordinal this check accounted for; recovery
|
|
41
47
|
* after a failure makes it more than one. An attempt that threw before
|
|
42
48
|
* reporting usage is invisible to accounting, so this is a lower bound on
|
|
43
49
|
* what the provider was actually asked to do.
|
|
44
50
|
*/
|
|
45
|
-
attempts:
|
|
51
|
+
attempts: z2.number().int().positive()
|
|
46
52
|
});
|
|
47
53
|
var observationFields = {
|
|
48
|
-
detectorVersion:
|
|
49
|
-
modelReference:
|
|
50
|
-
observedAt:
|
|
54
|
+
detectorVersion: z2.literal(PHASE_SHIFT_DETECTOR_VERSION),
|
|
55
|
+
modelReference: z2.string().min(1).max(256),
|
|
56
|
+
observedAt: z2.iso.datetime(),
|
|
51
57
|
throughEntryId: entryId,
|
|
52
|
-
windowEntryIds:
|
|
58
|
+
windowEntryIds: z2.array(entryId).min(1).max(40),
|
|
53
59
|
memory: phaseShiftMemorySchema
|
|
54
60
|
};
|
|
55
61
|
var changeFields = {
|
|
56
62
|
startEntryId: entryId,
|
|
57
|
-
relation:
|
|
58
|
-
reason:
|
|
63
|
+
relation: z2.enum(["outcome", "phase"]),
|
|
64
|
+
reason: z2.string().trim().min(1).max(2e3),
|
|
59
65
|
purposeAfter: purpose
|
|
60
66
|
};
|
|
61
|
-
var phaseShiftObservationV1Schema =
|
|
62
|
-
version:
|
|
67
|
+
var phaseShiftObservationV1Schema = z2.object({
|
|
68
|
+
version: z2.literal(1),
|
|
63
69
|
...observationFields,
|
|
64
|
-
changes:
|
|
70
|
+
changes: z2.array(z2.object(changeFields)).max(39)
|
|
65
71
|
});
|
|
66
|
-
var phaseShiftObservationV2Schema =
|
|
67
|
-
version:
|
|
72
|
+
var phaseShiftObservationV2Schema = z2.object({
|
|
73
|
+
version: z2.literal(2),
|
|
68
74
|
...observationFields,
|
|
69
75
|
/** Timestamp of the `windowEntryIds[0]` entry: where this check's coverage starts. */
|
|
70
76
|
windowStartAt: sourceTime,
|
|
@@ -72,13 +78,13 @@ var phaseShiftObservationV2Schema = z.object({
|
|
|
72
78
|
throughAt: sourceTime,
|
|
73
79
|
/** What this check cost to run; absent on a record written before it was accounted. */
|
|
74
80
|
cost: phaseShiftCostSchema.optional(),
|
|
75
|
-
changes:
|
|
81
|
+
changes: z2.array(z2.object({
|
|
76
82
|
...changeFields,
|
|
77
83
|
/** Timestamp of the `startEntryId` entry: when the new work began. */
|
|
78
84
|
startedAt: sourceTime
|
|
79
85
|
})).max(39)
|
|
80
86
|
});
|
|
81
|
-
var phaseShiftObservationSchema =
|
|
87
|
+
var phaseShiftObservationSchema = z2.discriminatedUnion("version", [
|
|
82
88
|
phaseShiftObservationV1Schema,
|
|
83
89
|
phaseShiftObservationV2Schema
|
|
84
90
|
]);
|
package/dist/transcript.d.ts
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
* moment it revisits an id, so a cycle yields the cycle's own ids rather than
|
|
9
9
|
* looping forever.
|
|
10
10
|
*/
|
|
11
|
-
export declare function branchEntryIds(entries: readonly
|
|
11
|
+
export declare function branchEntryIds(entries: readonly TranscriptTreeEntryLike[]): ReadonlySet<string>;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Every `type: "custom"` entry of one `customType`, oldest→newest, with every
|
|
15
|
-
* field ({@link
|
|
15
|
+
* field ({@link TranscriptSourceEntryLike}'s id/timestamp/tree links plus the
|
|
16
16
|
* entry's own `data`) preserved unchanged — `data` is returned exactly as it
|
|
17
17
|
* arrived, opaque and unvalidated, never coerced toward a schema this module
|
|
18
18
|
* cannot know.
|
|
@@ -24,12 +24,12 @@ export declare function branchEntryIds(entries: readonly TranscriptTreeEntry[]):
|
|
|
24
24
|
* itself needs to reason about abandoned entries (an audit, a recovery
|
|
25
25
|
* tool); an ordinary reader states `"active"` explicitly.
|
|
26
26
|
*/
|
|
27
|
-
export declare function customEntriesFromEntries<T extends
|
|
27
|
+
export declare function customEntriesFromEntries<T extends TranscriptSourceEntryLike = TranscriptSourceEntryLike>(entries: readonly T[], customType: string, options: {
|
|
28
28
|
readonly branch: "active" | "all";
|
|
29
29
|
}): readonly T[];
|
|
30
30
|
|
|
31
31
|
/** The fields the customType selector needs off a session entry. */
|
|
32
|
-
export declare interface
|
|
32
|
+
export declare interface TranscriptEntryLike {
|
|
33
33
|
readonly id: string;
|
|
34
34
|
readonly type: string;
|
|
35
35
|
readonly customType?: string;
|
|
@@ -41,7 +41,7 @@ export declare interface TranscriptEntry {
|
|
|
41
41
|
* A tree entry plus the ISO timestamp the timeline projections read alongside
|
|
42
42
|
* the walk result (`turnSegments`, `phaseShiftTimelineFromEntries`).
|
|
43
43
|
*/
|
|
44
|
-
export declare interface
|
|
44
|
+
export declare interface TranscriptSourceEntryLike extends TranscriptTreeEntryLike {
|
|
45
45
|
readonly timestamp: string;
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -52,7 +52,7 @@ export declare interface TranscriptSourceEntry extends TranscriptTreeEntry {
|
|
|
52
52
|
* v3 log carries an ISO string, so requiring either shape here would force one
|
|
53
53
|
* class of caller to convert entries it only wants walked.
|
|
54
54
|
*/
|
|
55
|
-
declare interface
|
|
55
|
+
declare interface TranscriptTreeEntryLike extends TranscriptEntryLike {
|
|
56
56
|
readonly parentId?: string | null;
|
|
57
57
|
readonly targetId?: string | null;
|
|
58
58
|
}
|
package/dist/transcript.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
// packages/plugin-protocol/dist/transcript.js
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var WorkBlockCoverageSchema = z.strictObject({
|
|
4
|
+
firstToolResultEntryId: z.string().min(1),
|
|
5
|
+
lastToolResultEntryId: z.string().min(1),
|
|
6
|
+
toolResultEntryIds: z.array(z.string().min(1)).min(1).max(4096)
|
|
7
|
+
}).refine((value) => value.firstToolResultEntryId === value.toolResultEntryIds[0] && value.lastToolResultEntryId === value.toolResultEntryIds.at(-1) && new Set(value.toolResultEntryIds).size === value.toolResultEntryIds.length);
|
|
2
8
|
function branchEntryIds(entries) {
|
|
3
9
|
const last = entries[entries.length - 1];
|
|
4
10
|
if (last === void 0)
|
package/package.json
CHANGED
|
@@ -55,37 +55,49 @@ and symlinking `node_modules/@bonsai` into the copy does not rescue it either: p
|
|
|
55
55
|
layout does not expose workspace packages that way. The scaffold exists precisely so this
|
|
56
56
|
cannot happen.
|
|
57
57
|
|
|
58
|
+
The entrypoint default-exports the function Bonsai calls with the plugin API:
|
|
59
|
+
`export default function activate(api: KayAgentPluginApi): void`, and the same with
|
|
60
|
+
`KayAppPluginApi` for `kay.app`. An older plugin's named `activate` export still loads. Set the
|
|
61
|
+
manifest's `entrypoint.export` only to run a different export, such as one module serving both
|
|
62
|
+
daemon targets. Bonsai reads the default export from plugin SDK 0.13.5 on. The scaffold's
|
|
63
|
+
`compatibility.sdk` range makes an older Bonsai refuse the plugin ("needs plugin SDK ^0.13.5");
|
|
64
|
+
a hand-written manifest with no range loads there and then fails with "has no 'activate' export".
|
|
65
|
+
|
|
58
66
|
## Check the manifest before you wait for a load
|
|
59
67
|
|
|
60
68
|
```
|
|
61
69
|
pnpm plugin:check ~/.kay/plugins/widgets
|
|
62
70
|
```
|
|
63
71
|
|
|
64
|
-
Run from the root of a Bonsai checkout, against the plugin directory. It
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
Run from the root of a Bonsai checkout, against the plugin directory. It prints the verdict the
|
|
73
|
+
daemon's directory scan reaches, from the same function (`judgeKayPluginDirectory`,
|
|
74
|
+
`@bonsai/plugin-protocol`), judged against that checkout's plugin SDK, whose version it prints. So
|
|
75
|
+
it answers "would Bonsai refuse this plugin?" in about a second instead of after a load cycle. Run
|
|
76
|
+
it after every manifest edit, and before concluding a plugin is broken for some deeper reason.
|
|
77
|
+
|
|
78
|
+
It prints the resolved global contribution ids, exits non-zero unless the plugin would load, and
|
|
79
|
+
separates:
|
|
80
|
+
|
|
81
|
+
- **Refused outright** — an SDK range or protocol this Bonsai does not support (checked before
|
|
82
|
+
the schema, so a manifest for another SDK names the version, not its unknown key), a
|
|
83
|
+
schema-invalid manifest, a reserved `kay.*` / `herd.*` id, a declared path escaping the plugin
|
|
84
|
+
directory, or contributions that do not resolve. Every contribution shares ONE flat
|
|
85
|
+
`<namespace>.<localId>` space ACROSS kinds, so a tool and an endpoint both called `inspect`
|
|
86
|
+
collide and the whole plugin is refused (#8936).
|
|
76
87
|
- **Loads, minus something** — a retired `compatibility` / `permissions.byTarget` key the parser
|
|
77
|
-
strips silently
|
|
78
|
-
nothing tells the user), a missing entrypoint or skill file.
|
|
88
|
+
strips silently; plus compatibility notes (no declared SDK range).
|
|
79
89
|
|
|
80
|
-
It reads the
|
|
81
|
-
|
|
90
|
+
It never reads the declared files or applies the roster's rules: a missing entrypoint or skill
|
|
91
|
+
file, a `toolName` that is not the namespace-derived name, an `activate()` that throws, the
|
|
92
|
+
disclosure audit, and an id another installed plugin already claims all show only after enabling,
|
|
93
|
+
in `read plugin://<id>`.
|
|
82
94
|
|
|
83
95
|
## The SDK resolution contract
|
|
84
96
|
|
|
85
97
|
- Plugin source imports `@bonsai/plugin-sdk/<subpath>` as a **bare specifier**
|
|
86
98
|
(`@bonsai/plugin-sdk/kay-agent`, `/kay-agent/testing`, `/kay-app`, `/disclosure` — only declared
|
|
87
99
|
exports exist).
|
|
88
|
-
- The daemon's
|
|
100
|
+
- The daemon's plugin loader bundles each declared TypeScript entrypoint and its relative imports.
|
|
89
101
|
It keeps `@bonsai/plugin-sdk` imports external and resolves them to the running app's own built SDK.
|
|
90
102
|
Multi-file plugins are supported, and no plugin-local build is needed for Bonsai to load them.
|
|
91
103
|
- Corollary: **bare `node` outside the daemon cannot resolve `@bonsai/plugin-sdk`** from the plugin
|
|
@@ -94,7 +106,7 @@ disclosure audit, or an id another installed plugin already claims.
|
|
|
94
106
|
standalone test; a published SDK dependency is the other standalone option.
|
|
95
107
|
- Typecheck with `npm run typecheck` inside the plugin directory; the scaffold's generated
|
|
96
108
|
tsconfig maps the SDK's types via `paths`.
|
|
97
|
-
-
|
|
109
|
+
- The loader compiles TypeScript syntax that native type stripping cannot execute, including `enum`,
|
|
98
110
|
`namespace` blocks, constructor parameter properties, and decorators. Typecheck before enabling
|
|
99
111
|
the plugin; a bundle error is reported as a target-load diagnostic.
|
|
100
112
|
|
|
@@ -208,10 +220,10 @@ list` names the exact local root — because writing into the wrong one produces
|
|
|
208
220
|
The commit is the activation boundary, so run these against the working tree first. Each catches
|
|
209
221
|
a failure class the load would otherwise be the first thing to surface:
|
|
210
222
|
|
|
211
|
-
1. **Run `pnpm plugin:check <dir>`** from a Bonsai checkout. It
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
223
|
+
1. **Run `pnpm plugin:check <dir>`** from a Bonsai checkout. It prints the verdict of the function
|
|
224
|
+
the daemon's directory scan runs (`judgeKayPluginDirectory`): SDK compatibility, the manifest
|
|
225
|
+
schema, reserved ids, contract resolution and path containment, not just "it is valid JSON". A
|
|
226
|
+
non-zero exit means the plugin would be refused.
|
|
215
227
|
2. **Run the disclosure audit yourself**: `auditPluginDisclosure` from `@bonsai/plugin-sdk/disclosure`.
|
|
216
228
|
It is not redundant with typecheck. A plugin shipped a `search` verb with no `verbDocs` entry
|
|
217
229
|
that typechecked clean and would have failed the whole `kay.agent` target.
|