@yaklabs-ai/plugin-sdk 0.12.5 → 0.13.1
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 +37 -33
- package/THIRD-PARTY-INVENTORY.json +1 -1
- package/dist/disclosure.d.ts +59 -77
- package/dist/disclosure.js +4 -14
- package/dist/fs.d.ts +156 -0
- package/dist/fs.js +895 -0
- package/dist/jev.d.ts +1 -1
- package/dist/kay-agent-testing.d.ts +58 -76
- package/dist/kay-agent-testing.js +4 -12
- package/dist/kay-agent.d.ts +65 -119
- package/dist/kay-agent.js +0 -11
- package/dist/kay-app.d.ts +156 -61
- package/dist/kay-app.js +22 -1
- package/dist/signals.d.ts +175 -1
- package/dist/signals.js +141 -2
- package/package.json +5 -1
- package/skills/directory-plugin-authoring/SKILL.md +18 -17
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @yaklabs-ai/plugin-sdk
|
|
2
2
|
|
|
3
|
-
The SDK for authoring a **
|
|
4
|
-
repository and add to
|
|
3
|
+
The SDK for authoring a **Bonsai directory plugin** — a plugin you write in a
|
|
4
|
+
repository and add to Bonsai through an approved plugin repository source.
|
|
5
5
|
|
|
6
6
|
Published to the public npm registry under the MIT licence.
|
|
7
7
|
|
|
@@ -13,13 +13,13 @@ it under the name your plugin code actually imports:
|
|
|
13
13
|
```json
|
|
14
14
|
{
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@kay/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.
|
|
16
|
+
"@kay/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.13.1"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
**The alias is not cosmetic.** The package is published as
|
|
22
|
-
`@yaklabs-ai/plugin-sdk`, but
|
|
22
|
+
`@yaklabs-ai/plugin-sdk`, but Bonsai's daemon resolves the specifier
|
|
23
23
|
`@kay/plugin-sdk` when it loads your entrypoint, so that is the name your source
|
|
24
24
|
must import. The alias installs the published package at
|
|
25
25
|
`node_modules/@kay/plugin-sdk`, satisfying both.
|
|
@@ -79,22 +79,22 @@ export default activate;
|
|
|
79
79
|
|
|
80
80
|
## Entrypoints
|
|
81
81
|
|
|
82
|
-
| Import | What it gives you
|
|
83
|
-
| ----------------------------------- |
|
|
84
|
-
| `@kay/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface
|
|
85
|
-
| `@kay/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules
|
|
86
|
-
| `@kay/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs
|
|
87
|
-
| `@kay/plugin-sdk/disclosure` | The conformance audit
|
|
82
|
+
| Import | What it gives you |
|
|
83
|
+
| ----------------------------------- | ---------------------------------------------------------------------------- |
|
|
84
|
+
| `@kay/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
|
|
85
|
+
| `@kay/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
|
|
86
|
+
| `@kay/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
|
|
87
|
+
| `@kay/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
|
|
88
88
|
|
|
89
|
-
`kay-agent/host` is intentionally not published; it is
|
|
89
|
+
`kay-agent/host` is intentionally not published; it is Bonsai's own loading
|
|
90
90
|
machinery, not an authoring API.
|
|
91
91
|
|
|
92
92
|
## Check yourself against the gate that can reject you
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
Bonsai runs `auditPluginDisclosure` against your `kay.agent` target **at load,
|
|
95
95
|
fail-closed**: one violation and the whole target fails — no tools, no URI
|
|
96
96
|
modules, no skills. It is the same function this entrypoint exports, so the
|
|
97
|
-
run below is the run
|
|
97
|
+
run below is the run Bonsai does.
|
|
98
98
|
|
|
99
99
|
```ts
|
|
100
100
|
import {
|
|
@@ -128,7 +128,7 @@ Pass the loader's inputs, not a subset — the audit judges what it is given:
|
|
|
128
128
|
- `commandBoundSkillIds` — the `localId` of every skill bound to a declared
|
|
129
129
|
command (`contributes.commands[].handler.kind === "skill"`). Omit it when
|
|
130
130
|
you have such commands and you will see `skill-link-missing-scheme`
|
|
131
|
-
violations
|
|
131
|
+
violations Bonsai itself would not report.
|
|
132
132
|
|
|
133
133
|
`auditSkillCodegenPairs({ declaredSkills, exportedSkills, packageDir })` is the
|
|
134
134
|
companion check for a bundled-skill plugin. It compares the decoded YAML
|
|
@@ -138,7 +138,7 @@ Both return violations rather than asserting, so any runner works. Both read fro
|
|
|
138
138
|
and call your own `help()`, so run them in Node, and keep `activate` free of
|
|
139
139
|
side effects: the probe calls it.
|
|
140
140
|
|
|
141
|
-
`PLUGIN_DISCLOSURE_CONTRACT` names the floor this SDK enforces.
|
|
141
|
+
`PLUGIN_DISCLOSURE_CONTRACT` names the floor this SDK enforces. Bonsai's load
|
|
142
142
|
failure names the floor **it** enforces. Different numbers mean the rules
|
|
143
143
|
moved, not your code — update this package and re-run.
|
|
144
144
|
|
|
@@ -149,47 +149,51 @@ someone remembering to cut one. If the numbers differ, a newer version exists.
|
|
|
149
149
|
## What this package is, and is not, at runtime
|
|
150
150
|
|
|
151
151
|
Installing this SDK gives you **types, editor completion, and a runtime you can
|
|
152
|
-
execute in your own tests**. It is not what runs inside
|
|
152
|
+
execute in your own tests**. It is not what runs inside Bonsai.
|
|
153
153
|
|
|
154
154
|
When the daemon loads your plugin, chord bundles its declared target and keeps
|
|
155
155
|
`@kay/plugin-sdk/*` as a host external. Those imports resolve to the SDK
|
|
156
|
-
**bundled with the
|
|
156
|
+
**bundled with the Bonsai app**. The host's copy always wins. That is deliberate —
|
|
157
157
|
one implementation, the one the daemon is built against — but it has a
|
|
158
158
|
consequence worth stating plainly:
|
|
159
159
|
|
|
160
|
-
> If your installed SDK is newer than your
|
|
160
|
+
> If your installed SDK is newer than your Bonsai app, code that typechecks against
|
|
161
161
|
> a newly-added API can still fail at load time, because the running host does
|
|
162
162
|
> not have it.
|
|
163
163
|
|
|
164
164
|
Importing an entire subpath the host does not know about fails loudly and
|
|
165
165
|
specifically (a `target-load` diagnostic naming the subpath, shown on the
|
|
166
|
-
|
|
167
|
-
not caught that way. Keep the SDK version in step with the
|
|
166
|
+
App Store on the app's detail page). A _symbol_ that exists here but not in the host's older copy is
|
|
167
|
+
not caught that way. Keep the SDK version in step with the Bonsai app you run.
|
|
168
168
|
|
|
169
169
|
The same skew applies to the conformance floor, and in the direction that
|
|
170
|
-
bites: if your
|
|
170
|
+
bites: if your Bonsai app is **newer** than this package, it can enforce a rule
|
|
171
171
|
your copy of the audit does not know about, so a green local run is not a
|
|
172
172
|
promise the host will load you. That is why the load failure names its
|
|
173
173
|
contract number — compare it against `PLUGIN_DISCLOSURE_CONTRACT` here, and if
|
|
174
174
|
they differ, update before you debug your code.
|
|
175
175
|
|
|
176
|
-
## Install the plugin in
|
|
176
|
+
## Install the plugin in Bonsai
|
|
177
177
|
|
|
178
178
|
The fastest route is the local plugin root. Put the plugin directory in
|
|
179
|
-
`~/.kay/plugins/<your-plugin>/` and
|
|
180
|
-
root is already consented, so there is no repository to stage and no Trust
|
|
181
|
-
|
|
179
|
+
`~/.kay/plugins/<your-plugin>/` and enable it in **App Store → Installed**.
|
|
180
|
+
That root is already consented, so there is no repository to stage and no Trust
|
|
181
|
+
step. Commit your edits to load them without restarting Bonsai; uncommitted edits
|
|
182
|
+
never execute.
|
|
182
183
|
|
|
183
184
|
To share a plugin with someone who does not have your files, commit it to a Git
|
|
184
|
-
repository and have them add it under **
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
repository and have them add it under **App Store → Sources → Add source**.
|
|
186
|
+
They stage and Trust the source, then add the plugin: **Get** in
|
|
187
|
+
**App Store → Browse** for a marketplace catalog, or **Turn on** on the
|
|
188
|
+
source's page under **App Store → Sources** for a plain Git repository.
|
|
189
|
+
Either action installs and enables that plugin; source Trust does not install
|
|
190
|
+
every item it contains.
|
|
187
191
|
|
|
188
192
|
A plugin executes as a trusted in-process Node module with the daemon's own
|
|
189
193
|
authority. **The SDK does not provide a sandbox.** Putting code in the local
|
|
190
|
-
plugin root
|
|
191
|
-
|
|
192
|
-
repository.
|
|
194
|
+
plugin root makes it discoverable without a source Trust prompt; enabling its install
|
|
195
|
+
row is still required. Treat that directory exactly as carefully as you would
|
|
196
|
+
Trust an unfamiliar repository.
|
|
193
197
|
|
|
194
198
|
## Requirements
|
|
195
199
|
|
|
@@ -200,8 +204,8 @@ checkout script is not the standalone path. The SDK's `kay-app` declarations
|
|
|
200
204
|
use `node:sqlite`, which TypeScript cannot resolve without the Node 24
|
|
201
205
|
typings.
|
|
202
206
|
|
|
203
|
-
When
|
|
207
|
+
When Bonsai loads your plugin, chord bundles the declared entrypoint and its
|
|
204
208
|
relative imports. Multi-file entrypoints are supported, and TypeScript syntax
|
|
205
209
|
that native stripping cannot execute, such as enums, namespaces, constructor
|
|
206
210
|
parameter properties, and decorators, is compiled into the bundle. The host
|
|
207
|
-
SDK remains external and is supplied by the running
|
|
211
|
+
SDK remains external and is supplied by the running Bonsai app.
|
package/dist/disclosure.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ declare interface AccountIdentity {
|
|
|
20
20
|
readonly displayName?: string;
|
|
21
21
|
/** Absolute URL of the account's avatar. */
|
|
22
22
|
readonly avatarUrl?: string;
|
|
23
|
-
/** Issuer-asserted beta-tester flag; only
|
|
23
|
+
/** Issuer-asserted beta-tester flag; only Bonsai's product-account service sets it. */
|
|
24
24
|
readonly betaTester?: boolean;
|
|
25
25
|
readonly activeOrganizationId?: string;
|
|
26
26
|
readonly organizationSelectionState?: "selected" | "unresolved";
|
|
@@ -28,7 +28,7 @@ declare interface AccountIdentity {
|
|
|
28
28
|
/**
|
|
29
29
|
* Provider-native session id claim (WorkOS's `sid`), needed to call the provider's own
|
|
30
30
|
* session-revocation endpoint at sign-out (`POST /user_management/sessions/revoke`, not yet
|
|
31
|
-
* wired — see `docs/kay-account-auth.md`'s "Sign-out guarantee" section). Only
|
|
31
|
+
* wired — see `docs/kay-account-auth.md`'s "Sign-out guarantee" section). Only Bonsai's WorkOS
|
|
32
32
|
* product-account exchange/refresh sets it; every other provider leaves it absent.
|
|
33
33
|
*/
|
|
34
34
|
readonly providerSessionId?: string;
|
|
@@ -164,7 +164,7 @@ declare interface ApiKeyAuthSchemeField {
|
|
|
164
164
|
readonly label: string;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
/** Provider-owned instructions for creating a credential outside
|
|
167
|
+
/** Provider-owned instructions for creating a credential outside Bonsai. */
|
|
168
168
|
declare interface ApiKeyAuthSchemeSetup {
|
|
169
169
|
readonly instructions: string;
|
|
170
170
|
/** Absolute HTTPS page where the user can create or manage the credential. */
|
|
@@ -755,7 +755,7 @@ declare interface InteractionCandidate {
|
|
|
755
755
|
declare type InteractionCandidateKind = "click" | "fill" | "select" | "scroll" | "wait" | "activate" | "press";
|
|
756
756
|
|
|
757
757
|
declare interface InteractionDriver {
|
|
758
|
-
/** Unique in the session. `builtin:` is reserved for
|
|
758
|
+
/** Unique in the session. `builtin:` is reserved for Bonsai's own drivers. */
|
|
759
759
|
readonly id: string;
|
|
760
760
|
/** Human-readable name the agent sees beside the driver's targets. */
|
|
761
761
|
readonly label: string;
|
|
@@ -778,7 +778,7 @@ declare interface InteractionDriver {
|
|
|
778
778
|
}
|
|
779
779
|
|
|
780
780
|
/**
|
|
781
|
-
* The Interaction driver contract: what a plugin implements to let
|
|
781
|
+
* The Interaction driver contract: what a plugin implements to let Bonsai's agent drive something
|
|
782
782
|
* on the user's machine (a browser, an app, a remote screen) through the harness-owned
|
|
783
783
|
* Interaction engine.
|
|
784
784
|
*
|
|
@@ -791,7 +791,7 @@ declare interface InteractionDriver {
|
|
|
791
791
|
* every tool work on every driver.
|
|
792
792
|
*
|
|
793
793
|
* Shape mirrors `SearchProvider` behind `web_search`: one tool set owned by the harness, many
|
|
794
|
-
* backends registered per session, the `builtin:` id namespace reserved for
|
|
794
|
+
* backends registered per session, the `builtin:` id namespace reserved for Bonsai's own.
|
|
795
795
|
*/
|
|
796
796
|
/** "Browser Interaction" drives web pages; "Computer Use Interaction" drives native apps. */
|
|
797
797
|
declare type InteractionDriverKind = "browser" | "computer-use";
|
|
@@ -850,7 +850,7 @@ declare interface InteractionRegion {
|
|
|
850
850
|
}
|
|
851
851
|
|
|
852
852
|
/**
|
|
853
|
-
* One surface
|
|
853
|
+
* One surface Bonsai ships, in the driver contract's own shape, so a plugin's driver is the surface
|
|
854
854
|
* plus an identity: `{ id, label, kind, ...api.interaction.desktop }`. Each call is checked
|
|
855
855
|
* against the plugin's `interaction.surface {surface}` grant, and then against the session's
|
|
856
856
|
* permissions exactly as the agent's `interaction_*` tools are: an act is judged as the plugin
|
|
@@ -972,7 +972,7 @@ declare interface JevScoreQuestion {
|
|
|
972
972
|
* Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
|
|
973
973
|
* ---
|
|
974
974
|
*
|
|
975
|
-
* The vocabulary is
|
|
975
|
+
* The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
|
|
976
976
|
* and plugins coded against a vendor's types. It follows pi's classifier contract, which the host
|
|
977
977
|
* runs Jev through: a yes/no question is `bool` and answers a `probability`, every instruction and
|
|
978
978
|
* criterion is text, and the state is a JSON object.
|
|
@@ -1004,7 +1004,7 @@ declare const JsonValue_2: z.ZodType<JsonValue_2>;
|
|
|
1004
1004
|
|
|
1005
1005
|
declare type JsonValue_3 = null | boolean | number | string | readonly JsonValue_3[] | JsonObject;
|
|
1006
1006
|
|
|
1007
|
-
/** A plugin's
|
|
1007
|
+
/** A plugin's Bonsai agent activation — receives only the brokered {@link KayAgentPluginApi}. */
|
|
1008
1008
|
declare type KayAgentActivate = (api: KayAgentPluginApi) => void;
|
|
1009
1009
|
|
|
1010
1010
|
/**
|
|
@@ -1024,52 +1024,14 @@ declare interface KayAgentEvents {
|
|
|
1024
1024
|
publish(localId: string, payload: unknown): void;
|
|
1025
1025
|
}
|
|
1026
1026
|
|
|
1027
|
-
/**
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
writeText(location: KayAgentFilesystemLocation, content: string, options?: KayAgentFilesystemWriteOptions): Promise<void>;
|
|
1036
|
-
/** The whole file, or the requested window of it. */
|
|
1037
|
-
readBytes(location: KayAgentFilesystemLocation, range?: KayAgentFilesystemByteRange): Promise<Uint8Array>;
|
|
1038
|
-
writeBytes(location: KayAgentFilesystemLocation, bytes: Uint8Array, options?: KayAgentFilesystemWriteOptions): Promise<void>;
|
|
1039
|
-
mkdir(location: KayAgentFilesystemLocation): Promise<void>;
|
|
1040
|
-
readDir(location: KayAgentFilesystemLocation): Promise<readonly KayAgentFilesystemEntry[]>;
|
|
1041
|
-
stat(location: KayAgentFilesystemLocation): Promise<KayAgentFilesystemStat>;
|
|
1042
|
-
rename(from: KayAgentFilesystemLocation, to: KayAgentFilesystemLocation): Promise<void>;
|
|
1043
|
-
/** Returns the canonical path relative to the selected grant root. */
|
|
1044
|
-
realpath(location: KayAgentFilesystemLocation): Promise<string>;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
/** A byte window of a file; `maxBytes` is capped by the host. */
|
|
1048
|
-
declare interface KayAgentFilesystemByteRange {
|
|
1049
|
-
readonly offset: number;
|
|
1050
|
-
readonly maxBytes: number;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
declare interface KayAgentFilesystemEntry {
|
|
1054
|
-
readonly name: string;
|
|
1055
|
-
readonly kind: "file" | "directory" | "symlink" | "other";
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
declare interface KayAgentFilesystemLocation {
|
|
1059
|
-
/** Exact `root` selector the host bound for this target, plus a path relative to it. */
|
|
1060
|
-
readonly root: string;
|
|
1061
|
-
readonly path: string;
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
declare interface KayAgentFilesystemStat {
|
|
1065
|
-
readonly kind: "file" | "directory" | "other";
|
|
1066
|
-
readonly size: number;
|
|
1067
|
-
readonly modifiedAtMs: number;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
declare interface KayAgentFilesystemWriteOptions {
|
|
1071
|
-
/** Fail with `already_exists` instead of replacing a file already at the location. */
|
|
1072
|
-
readonly exclusive?: boolean;
|
|
1027
|
+
/** This plugin's folder in the session family's shared Whiteboard. */
|
|
1028
|
+
declare interface KayAgentFamilyFolder {
|
|
1029
|
+
/**
|
|
1030
|
+
* The folder's absolute path, created on first use. The plugin that owns the Whiteboard gets
|
|
1031
|
+
* the whole family folder; every other plugin gets its own `plugins/<plugin-id>/` inside it.
|
|
1032
|
+
* Undefined outside a session.
|
|
1033
|
+
*/
|
|
1034
|
+
path(): Promise<string | undefined>;
|
|
1073
1035
|
}
|
|
1074
1036
|
|
|
1075
1037
|
declare interface KayAgentInteractionSurfaces {
|
|
@@ -1081,7 +1043,7 @@ declare interface KayAgentInteractionSurfaces {
|
|
|
1081
1043
|
readonly browserPane: InteractionSurface;
|
|
1082
1044
|
/**
|
|
1083
1045
|
* The user's desktop through the platform's accessibility APIs: native apps as targets
|
|
1084
|
-
* (`app://<bundle id>`), their windows' controls as elements. On macOS
|
|
1046
|
+
* (`app://<bundle id>`), their windows' controls as elements. On macOS Bonsai drives it with its
|
|
1085
1047
|
* bundled accessibility worker under the app's Accessibility permission; on a platform with no
|
|
1086
1048
|
* backend it reports itself unavailable.
|
|
1087
1049
|
*/
|
|
@@ -1211,11 +1173,8 @@ declare interface KayAgentPluginApi {
|
|
|
1211
1173
|
/** Register a whole URI module (a scheme handler that owns its address space, e.g. `drive://`). */
|
|
1212
1174
|
registerModule(module: UriExtensionModule): void;
|
|
1213
1175
|
};
|
|
1214
|
-
/**
|
|
1215
|
-
|
|
1216
|
-
* {root}` for the root it touches, and against the host's binding for that root.
|
|
1217
|
-
*/
|
|
1218
|
-
readonly filesystem: KayAgentFilesystem;
|
|
1176
|
+
/** This plugin's folder in the session family's shared Whiteboard, created on first use. Undefined outside a session. */
|
|
1177
|
+
readonly familyFolder: KayAgentFamilyFolder;
|
|
1219
1178
|
/** Absent unless the `knowledgeSearch` grant is requested and effectively granted. */
|
|
1220
1179
|
readonly knowledgeSearch?: KayAgentKnowledgeSearch;
|
|
1221
1180
|
/** Absent unless the `knownResources` grant is requested and effectively granted. */
|
|
@@ -1241,7 +1200,7 @@ declare interface KayAgentPluginApi {
|
|
|
1241
1200
|
*/
|
|
1242
1201
|
readonly process: KayAgentProcess;
|
|
1243
1202
|
/**
|
|
1244
|
-
* Always present; the interaction surfaces
|
|
1203
|
+
* Always present; the interaction surfaces Bonsai ships (its browser pane, and the desktop through
|
|
1245
1204
|
* the platform accessibility APIs), each call checked against `interaction.surface {surface}`
|
|
1246
1205
|
* and the session's permissions (see {@link InteractionSurface}).
|
|
1247
1206
|
* Wrap one in an {@link InteractionDriver} and register it with
|
|
@@ -1268,9 +1227,8 @@ declare interface KayAgentPluginApi {
|
|
|
1268
1227
|
readonly time: KayAppTime;
|
|
1269
1228
|
/**
|
|
1270
1229
|
* File I/O in user folders, run by the host on its own worker threads under a deadline and
|
|
1271
|
-
* answered as a typed result. Always present and ungated:
|
|
1272
|
-
*
|
|
1273
|
-
* already have. What it adds is that a slow or unresponsive folder never blocks the daemon. See
|
|
1230
|
+
* answered as a typed result. Always present and ungated: it takes absolute paths and checks no
|
|
1231
|
+
* grant, because it adds no authority a plugin's `node:fs` does not already have. What it adds is that a slow or unresponsive folder never blocks the daemon. See
|
|
1274
1232
|
* {@link KayAppUserFiles}.
|
|
1275
1233
|
*/
|
|
1276
1234
|
readonly userFiles: KayAppUserFiles;
|
|
@@ -1841,7 +1799,7 @@ declare type ModelPromptCache = Partial<Record<Exclude<CacheRetention, "none">,
|
|
|
1841
1799
|
declare type ModelThinkingLevel = "off" | ThinkingLevel;
|
|
1842
1800
|
|
|
1843
1801
|
/**
|
|
1844
|
-
* Who may supply the OAuth client for a scheme:
|
|
1802
|
+
* Who may supply the OAuth client for a scheme: Bonsai's embedded client, or one the user pastes in
|
|
1845
1803
|
* (BYOOC). An UNORDERED SET — list order carries no meaning (nothing reads it as a preference).
|
|
1846
1804
|
*/
|
|
1847
1805
|
declare type OAuthClientSupplier = "kay" | "user";
|
|
@@ -1854,7 +1812,7 @@ declare interface OAuthRedirectResult {
|
|
|
1854
1812
|
|
|
1855
1813
|
/**
|
|
1856
1814
|
* The two client-supply axes, structured so the illegal cell is unrepresentable: a `confidential`
|
|
1857
|
-
* exchange's secret may only ever be
|
|
1815
|
+
* exchange's secret may only ever be Bonsai's (held by the host's broker, never pasted by a
|
|
1858
1816
|
* customer), so `confidential` types `clientSuppliers` as `readonly ["kay"]` — `confidential ×
|
|
1859
1817
|
* user` is a compile-time impossibility in v1, not a runtime refusal. `pkce`'s `clientSuppliers`
|
|
1860
1818
|
* is a non-empty set; {@link createOAuthPkceAuthScheme} dedupes it and refuses empty.
|
|
@@ -2037,7 +1995,7 @@ declare interface OpenRouterRouting {
|
|
|
2037
1995
|
* {@link PLUGIN_DISCLOSURE_RULES} changes, and never for anything else.
|
|
2038
1996
|
*
|
|
2039
1997
|
* Two readers, and the second is why a number beats a changelog entry. A plugin author compares it
|
|
2040
|
-
* against the
|
|
1998
|
+
* against the Bonsai build they target. The daemon's loader NAMES it in the
|
|
2041
1999
|
* `disclosure-conformance-failed` diagnostic, so a plugin that passed its own suite against an
|
|
2042
2000
|
* older SDK and then failed at load says "this host enforces contract N, you audited against
|
|
2043
2001
|
* something older" instead of leaving the author to guess whether their code or their SDK moved.
|
|
@@ -2126,7 +2084,7 @@ declare interface PluginDelegatedScheme {
|
|
|
2126
2084
|
readonly connect: (ctx: PluginDelegatedConnectContext) => Promise<PluginDelegatedConnectResult>;
|
|
2127
2085
|
/**
|
|
2128
2086
|
* Mint fresh material from the current (expiring) material, including the `data` the last
|
|
2129
|
-
* connect or refresh returned.
|
|
2087
|
+
* connect or refresh returned. Bonsai calls this only inside its credential authority, which holds
|
|
2130
2088
|
* the refresh lease and saves the result; this hook performs the exchange and nothing else.
|
|
2131
2089
|
* Returned `data` replaces the stored `data`; omitted `data` keeps it. Returned `expiresAt`
|
|
2132
2090
|
* replaces the stored expiry; omitted `expiresAt` means the new material does not expire.
|
|
@@ -2203,7 +2161,7 @@ declare type PluginOAuthPkceScheme = PluginOAuthSchemeClientAxes & {
|
|
|
2203
2161
|
readonly summary?: string;
|
|
2204
2162
|
readonly authorizationUrl: string;
|
|
2205
2163
|
readonly tokenUrl: string;
|
|
2206
|
-
/** The
|
|
2164
|
+
/** The Bonsai-supplied embedded client id; omit for a `confidential` scheme or a `pkce` scheme
|
|
2207
2165
|
* the host ships no client for. */
|
|
2208
2166
|
readonly clientId?: string;
|
|
2209
2167
|
/**
|
|
@@ -2833,6 +2791,14 @@ declare interface ToolDefinition<TParams extends ToolParametersWire = ToolParame
|
|
|
2833
2791
|
* explicit Stop.
|
|
2834
2792
|
*/
|
|
2835
2793
|
durationClass?: "fast" | "long";
|
|
2794
|
+
/**
|
|
2795
|
+
* Set only for a tool whose rerun with the same arguments is harmless, such
|
|
2796
|
+
* as one keyed on its own call: after a crash cuts a call off, a pi-durable
|
|
2797
|
+
* session may rerun it with its recorded arguments (without `before_tool`)
|
|
2798
|
+
* instead of ending it as an interrupted error. Absent: never rerun. Ignored
|
|
2799
|
+
* on pi 0.99.1.
|
|
2800
|
+
*/
|
|
2801
|
+
replaySafe?: true;
|
|
2836
2802
|
/**
|
|
2837
2803
|
* Optional capability⇄scheme binding. When present this tool is auth-gated: discoverable when
|
|
2838
2804
|
* unauthed, callable once the binding is satisfied. The SDK's {@link withResolvedAuth}
|
|
@@ -2916,9 +2882,9 @@ declare type ToolParametersWire = unknown;
|
|
|
2916
2882
|
*
|
|
2917
2883
|
* The host is trusted to supply honest values; a declared `kind` of `read` moves a call below
|
|
2918
2884
|
* the protected-path hard-deny (which only fires for non-read kinds), so a tool that could
|
|
2919
|
-
* touch protected config must NOT declare `read`.
|
|
2885
|
+
* touch protected config must NOT declare `read`. Bonsai's embedded-experience tools never touch
|
|
2920
2886
|
* `configDir`, so this is safe for them. `read` is also what every capability surface reports as
|
|
2921
|
-
* "read-only" (
|
|
2887
|
+
* "read-only" (Bonsai's Permissions page groups and defaults on it), so it is a claim about what the
|
|
2922
2888
|
* tool DOES — never a way to buy silence. A tool that should raise no ask on its own account
|
|
2923
2889
|
* declares {@link ToolPermissionHint.quiet} and keeps its honest `kind`.
|
|
2924
2890
|
*/
|
|
@@ -2959,7 +2925,7 @@ declare interface ToolPermissionHint {
|
|
|
2959
2925
|
* because the same tool can read on one input and execute on another, which a static `kind`
|
|
2960
2926
|
* cannot express.
|
|
2961
2927
|
*
|
|
2962
|
-
* Exemplar —
|
|
2928
|
+
* Exemplar — Bonsai's `mcp` proxy tool, one tool spanning every server: `search`/`describe` derive
|
|
2963
2929
|
* `{ kind: "read" }` (metadata lookups), while `call` derives
|
|
2964
2930
|
* `{ kind: "execute", ruleKey: "mcp:<server>::<tool>", scheme: "<server>" }`, so a
|
|
2965
2931
|
* `{ scheme: "<server>" }` rule gates a whole server and a `{ ruleKey: "mcp:<server>::<tool>" }`
|
|
@@ -3000,7 +2966,7 @@ declare interface ToolPermissionHint {
|
|
|
3000
2966
|
* really had — not that the result is always stricter than the target's. How much gate is left
|
|
3001
2967
|
* on such a call is exactly how much the CARRIER carries: an `execute` carrier is stricter than
|
|
3002
2968
|
* a `read` target and equal to a `mutate`/`destructive` one outside allow mode, while a
|
|
3003
|
-
* {@link quiet} carrier (
|
|
2969
|
+
* {@link quiet} carrier (Bonsai's own `call_tool`) contributes no mode default at all, so the
|
|
3004
2970
|
* fallback leaves nothing but the carrier's rules and the protected-path deny — and the carrier
|
|
3005
2971
|
* names no path, so that deny has nothing to fire on. This is why a carrier must refuse a target
|
|
3006
2972
|
* that is itself a carrier: no chain long or circular enough to reach the fallback can be built,
|
|
@@ -3024,7 +2990,7 @@ declare interface ToolPermissionHint {
|
|
|
3024
2990
|
* whose only effect is invoking the target the gate is already classifying beside it: the
|
|
3025
2991
|
* target's kind, rules, resources and the protected-path deny all still decide, so a proxied
|
|
3026
2992
|
* call is gated exactly like the direct one — no more, and no ask the direct call would never
|
|
3027
|
-
* have raised.
|
|
2993
|
+
* have raised. Bonsai's `call_tool` declares `{ kind: "execute", quiet: true }` (owner ruling,
|
|
3028
2994
|
* 2026-08-18): honest about everything it can reach, silent on its own account.
|
|
3029
2995
|
*
|
|
3030
2996
|
* Quiet is not ungated, but it IS nearly all the gate a lone carrier has. On a call that
|
|
@@ -3214,13 +3180,19 @@ declare interface UriExtensionModule extends Omit<UriModule, "verbs"> {
|
|
|
3214
3180
|
readonly permissionDefaults?: UriPermissionDefaults;
|
|
3215
3181
|
/** Requires a resolved URI connection before any verb handler runs. */
|
|
3216
3182
|
readonly requiresConnection?: boolean;
|
|
3217
|
-
/** Pure route-aware permission facts;
|
|
3183
|
+
/** Pure route-aware permission facts; see {@link UriExtensionOperationPermissionPolicy}. */
|
|
3218
3184
|
readonly permission?: UriExtensionOperationPermissionPolicy;
|
|
3219
3185
|
/** False rejects generic write-tool `source` copies before source fetch. */
|
|
3220
3186
|
readonly acceptsSourceCopy?: boolean;
|
|
3221
3187
|
}
|
|
3222
3188
|
|
|
3223
3189
|
declare interface UriExtensionOperationPermissionPolicy {
|
|
3190
|
+
/**
|
|
3191
|
+
* Classify one canonical route, purely. `write`/`edit`/`delete` may only be made stricter
|
|
3192
|
+
* than the verb default; `help`/`read`/`list`/`search` must stay `"read"` (a `ruleKey` is
|
|
3193
|
+
* allowed), because the kernel reruns a crash-interrupted read without asking again. Any
|
|
3194
|
+
* other answer, or a throw, fails the call closed.
|
|
3195
|
+
*/
|
|
3224
3196
|
classifyOperation(request: {
|
|
3225
3197
|
readonly operation: UriOperation;
|
|
3226
3198
|
readonly uri: string;
|
|
@@ -3448,7 +3420,15 @@ declare interface UriModule {
|
|
|
3448
3420
|
normalize?(input: string, ctx: UriResolveContext): UriNormalizeResult | undefined;
|
|
3449
3421
|
describe?(input: string, ctx: UriDescribeContext): UriResourceDescription | undefined;
|
|
3450
3422
|
locate?(input: string, ctx: UriLocateContext): Promise<UriLocateResult>;
|
|
3423
|
+
/**
|
|
3424
|
+
* `read`, `help`, `list` and `search` observe; they never change the resource or anything
|
|
3425
|
+
* outside the host. Repeating one with the same input must be harmless: the kernel reruns a
|
|
3426
|
+
* call of these verbs that a crash cut off, with the same input, without asking the user
|
|
3427
|
+
* again. Idempotent bookkeeping (a cache fill, an index of what was read, a usage count) is
|
|
3428
|
+
* fine; a send, a mark-as-read or a create is not, and belongs on a mutating verb.
|
|
3429
|
+
*/
|
|
3451
3430
|
read(input: string, ctx: UriResolveContext): Promise<RawResource>;
|
|
3431
|
+
/** Observes only; see {@link read}. */
|
|
3452
3432
|
help?(input: string, ctx: UriResolveContext): Promise<UriHelp>;
|
|
3453
3433
|
write?(input: string, content: UriPayload, ctx: UriResolveContext): Promise<UriMutationResult | void>;
|
|
3454
3434
|
/** Opt-in structured write with one or more host-resolved resources delivered beside the content. */
|
|
@@ -3471,7 +3451,9 @@ declare interface UriModule {
|
|
|
3471
3451
|
*/
|
|
3472
3452
|
writeBytes?(input: string, bytes: Uint8Array, source: UriSourceDescriptor, ctx: UriResolveContext): Promise<UriMutationResult | void>;
|
|
3473
3453
|
edit?(input: string, patch: UriPayload, ctx: UriResolveContext): Promise<UriMutationResult>;
|
|
3454
|
+
/** Observes only; see {@link read}. */
|
|
3474
3455
|
list?(input: string, params: UriListParams, ctx: UriResolveContext): Promise<UriListResult>;
|
|
3456
|
+
/** Observes only; see {@link read}. */
|
|
3475
3457
|
search?(input: string, params: UriSearchParams, ctx: UriResolveContext): Promise<UriSearchResult>;
|
|
3476
3458
|
delete?(input: string, ctx: UriResolveContext): Promise<UriMutationResult>;
|
|
3477
3459
|
toMarkdown?(input: UriMarkdownRenderInput, ctx: UriResolveContext): string | undefined;
|
|
@@ -3689,7 +3671,7 @@ declare interface UriResolveContext {
|
|
|
3689
3671
|
* {@link UriResolveContext.sessionId} and just as un-influenceable by the caller — so a module
|
|
3690
3672
|
* writing to a store it owns can record the actor without the agent being able to choose one.
|
|
3691
3673
|
*
|
|
3692
|
-
* Free text minted by the host's own runtime (
|
|
3674
|
+
* Free text minted by the host's own runtime (Bonsai's form is `user`, `subagent`,
|
|
3693
3675
|
* `system/<surface>`, `followup/<surface>`) rather than a closed union: the surface half is the
|
|
3694
3676
|
* host's vocabulary, and a second enumeration of it here would drift from the first.
|
|
3695
3677
|
*
|
package/dist/disclosure.js
CHANGED
|
@@ -765,17 +765,6 @@ function unavailableInteractionSurfaces(message) {
|
|
|
765
765
|
// packages/plugin-sdk/dist/disclosure/probe-kay-agent-capabilities.js
|
|
766
766
|
var inertResult = () => new Promise(() => {
|
|
767
767
|
});
|
|
768
|
-
var INERT_FILESYSTEM = {
|
|
769
|
-
readText: inertResult,
|
|
770
|
-
writeText: inertResult,
|
|
771
|
-
readBytes: inertResult,
|
|
772
|
-
writeBytes: inertResult,
|
|
773
|
-
mkdir: inertResult,
|
|
774
|
-
readDir: inertResult,
|
|
775
|
-
stat: inertResult,
|
|
776
|
-
rename: inertResult,
|
|
777
|
-
realpath: inertResult
|
|
778
|
-
};
|
|
779
768
|
var INERT_NETWORK = {
|
|
780
769
|
fetch: inertResult
|
|
781
770
|
};
|
|
@@ -807,7 +796,6 @@ var INERT_WHITEBOARD = {
|
|
|
807
796
|
var INERT_WITH_JEV = async (_use, fallback) => fallback();
|
|
808
797
|
function createKayAgentProbeCapabilityHandles() {
|
|
809
798
|
return {
|
|
810
|
-
filesystem: INERT_FILESYSTEM,
|
|
811
799
|
network: INERT_NETWORK,
|
|
812
800
|
webSession: INERT_WEB_SESSION,
|
|
813
801
|
process: INERT_PROCESS,
|
|
@@ -825,7 +813,7 @@ function createKayAgentProbeCapabilityHandles() {
|
|
|
825
813
|
time: {
|
|
826
814
|
snapshot: () => ({ nowMs: 0, zone: "UTC", zoneSource: "utc-fallback" })
|
|
827
815
|
},
|
|
828
|
-
// Inert like the
|
|
816
|
+
// Inert like the process broker: a probe must never touch the user's disk.
|
|
829
817
|
userFiles: {
|
|
830
818
|
stat: inertResult,
|
|
831
819
|
readText: inertResult,
|
|
@@ -835,7 +823,9 @@ function createKayAgentProbeCapabilityHandles() {
|
|
|
835
823
|
writeText: inertResult,
|
|
836
824
|
mkdir: inertResult,
|
|
837
825
|
rename: inertResult
|
|
838
|
-
}
|
|
826
|
+
},
|
|
827
|
+
// A probe runs outside any session, and must not create a folder on the user's disk.
|
|
828
|
+
familyFolder: { path: async () => void 0 }
|
|
839
829
|
};
|
|
840
830
|
}
|
|
841
831
|
|