@yaklabs-ai/plugin-sdk 0.53.0 → 0.54.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 CHANGED
@@ -13,7 +13,7 @@ it under the name your plugin code actually imports:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.53.0"
16
+ "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.54.0"
17
17
  }
18
18
  }
19
19
  ```
@@ -62,7 +62,7 @@ Every tool the entrypoint registers is declared in the manifest too:
62
62
  "description": "Greets people by name.",
63
63
  "version": "0.1.0",
64
64
  "namespace": "widgets",
65
- "compatibility": { "sdk": "^0.53.0" },
65
+ "compatibility": { "sdk": "^0.54.0" },
66
66
  "targets": {
67
67
  "kay": {
68
68
  "agent": {
@@ -134,24 +134,26 @@ naming both versions, instead of loading it and finding no `activate`.
134
134
 
135
135
  ## Entrypoints
136
136
 
137
- | Import | What it gives you |
138
- | --------------------------------------- | ---------------------------------------------------------------------------------------- |
139
- | `@bonsai/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
140
- | `@bonsai/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
141
- | `@bonsai/plugin-sdk/uri` | Sessionless resource caller types, revision digest and unavailable fallback, from 0.49.0 |
142
- | `@bonsai/plugin-sdk/endpoints` | Sessionless cross-plugin endpoint caller and outcome types, from 0.50.0 |
143
- | `@bonsai/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
144
- | `@bonsai/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
145
- | `@bonsai/plugin-sdk/time` | `Temporal` (Bonsai's own instance) and the time-zone helpers, from 0.13.6 |
146
- | `@bonsai/plugin-sdk/transcript` | The active-branch walk; the turn walk and run records from 0.13.6 |
147
- | `@bonsai/plugin-sdk/transcript-review` | The review fold: a session's spans, tool-call attempts and records, from 0.13.7 |
148
- | `@bonsai/plugin-sdk/agent-conversation` | How a session's agent-to-agent traffic groups into conversations, from 0.13.7 |
149
- | `@bonsai/plugin-sdk/app-data` | The app-data size caps, on an entry with no other import, from 0.13.7 |
150
- | `@bonsai/plugin-sdk/vendored-mcp` | The kit for a plugin built on a vendor's hosted MCP server, from 0.13.7 |
151
- | `@bonsai/plugin-sdk/system-one` | The types and error class for `api.systemOne` / `app.systemOne`, from 0.13.8 |
152
- | `@bonsai/plugin-sdk/zod` | `z` (the host's in the daemon), on an entry with no other import, from 0.13.9 |
153
-
154
- A plugin that imports these subpaths declares the current supported SDK range (`^0.53.0`).
137
+ | Import | What it gives you |
138
+ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
139
+ | `@bonsai/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
140
+ | `@bonsai/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
141
+ | `@bonsai/plugin-sdk/uri` | Sessionless resource caller types, revision digest and unavailable fallback, from 0.49.0 |
142
+ | `@bonsai/plugin-sdk/endpoints` | Sessionless cross-plugin endpoint caller and outcome types, from 0.50.0; `projectDirectories` endpoint shapes |
143
+ | `@bonsai/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
144
+ | `@bonsai/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
145
+ | `@bonsai/plugin-sdk/time` | `Temporal` (Bonsai's own instance) and the time-zone helpers, from 0.13.6 |
146
+ | `@bonsai/plugin-sdk/transcript` | Active-branch and turn walks, message origin, preceding messages, and skill evidence folds |
147
+ | `@bonsai/plugin-sdk/transcript-review` | The review fold: a session's spans, tool-call attempts and records, from 0.13.7 |
148
+ | `@bonsai/plugin-sdk/agent-conversation` | How a session's agent-to-agent traffic groups into conversations, from 0.13.7 |
149
+ | `@bonsai/plugin-sdk/text-diff` | Word-level draft comparison and Unicode-safe text clipping |
150
+ | `@bonsai/plugin-sdk/fs` | File I/O, shared keyed work ordering and committed-change notices |
151
+ | `@bonsai/plugin-sdk/app-data` | The app-data size caps, on an entry with no other import, from 0.13.7 |
152
+ | `@bonsai/plugin-sdk/vendored-mcp` | The kit for a plugin built on a vendor's hosted MCP server, from 0.13.7 |
153
+ | `@bonsai/plugin-sdk/system-one` | The types and error class for `api.systemOne` / `app.systemOne`, from 0.13.8 |
154
+ | `@bonsai/plugin-sdk/zod` | `z` (the host's in the daemon), on an entry with no other import, from 0.13.9 |
155
+
156
+ A plugin that imports these subpaths declares the current supported SDK range (`^0.54.0`).
155
157
  The rows record when each subpath appeared, not retained runtime compatibility. `vendored-mcp` builds the plugin's URI module (its link cards and help); hosting the
156
158
  vendor's MCP server itself is a separate host decision: Bonsai hosts it once a person approves
157
159
  the plugin's `mcp.host-server` grant for that server's name and URL. A server that needs an OAuth
@@ -159,7 +161,7 @@ sign-in names one of the plugin's auth services in `authService`; that service m
159
161
  one `delegated` scheme, which Bonsai uses to sign the person in to the server. Bonsai declares that
160
162
  scheme at runtime; the plugin's code must not declare it again. From 0.16.2 a plugin's code can also
161
163
  call the server's tools through `api.vendoredMcp.port(<server>)`, typed by this subpath's
162
- `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.53.0`).
164
+ `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.54.0`).
163
165
 
164
166
  From 0.13.10 the manifest schema carries two facts Bonsai reads for its own plugins only; another
165
167
  plugin's are ignored, with a load diagnostic. An `external-cli` auth scheme's `cli` says how Bonsai
@@ -241,7 +243,7 @@ Provider schemas remain authoritative; declaring a dependency grants no authorit
241
243
  through `app.uri`, parse returned Markdown in the consuming plugin, and retain the read's
242
244
  revision (or `contentDigest` from `/uri`) for edits. The old `memory.read` and `memory.write`
243
245
  grants do not authorize the replacement scheme-and-verb calls. Contracts before 0.49.0 are
244
- refused; migrate and declare `^0.53.0`. The current host also serves the 0.49.0 resource contract.
246
+ refused; migrate and declare `^0.54.0`. The current host also serves the 0.49.0 resource contract.
245
247
 
246
248
  ## What this package is, and is not, at runtime
247
249
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@yaklabs-ai/plugin-sdk",
4
- "version": "0.53.0",
4
+ "version": "0.54.0",
5
5
  "target": "npm",
6
6
  "firstPartyLicense": "MIT",
7
7
  "bundled": [
@@ -2466,8 +2466,12 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2466
2466
  * 0.53.0 adds declared working-content layouts, family-root authority, draft projection discovery
2467
2467
  * and session-bound page references. Older customized Whiteboard copies must accept the plugin
2468
2468
  * update before using these interfaces.
2469
+ *
2470
+ * 0.54.0 adds named UI host grants for shared configuration/auth/account reads, retained connection
2471
+ * progress/dismissal and support. Built-in-only page capability scopes are removed; executable
2472
+ * pages declare capabilities on apps[].
2469
2473
  */
2470
- declare const KAY_PLUGIN_SDK_VERSION: "0.53.0";
2474
+ declare const KAY_PLUGIN_SDK_VERSION: "0.54.0";
2471
2475
 
2472
2476
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2473
2477
 
@@ -737,6 +737,31 @@ function createUnavailableUriCaller(message) {
737
737
  };
738
738
  }
739
739
 
740
+ // packages/plugin-protocol/dist/project-directories.js
741
+ import { z as z5 } from "zod";
742
+ var PluginProjectDirectories = z5.strictObject({
743
+ /** An endpoint this plugin's app target declares; called with a {@link ProjectDirectoryRequest}. */
744
+ endpoint: z5.string().min(1),
745
+ /** A scheme this plugin's URI modules serve; a project is addressed as `<scheme>://<id>`. */
746
+ scheme: z5.string().min(1)
747
+ });
748
+ var ProjectDirectoryRequest = z5.strictObject({
749
+ /** The project's stable id. */
750
+ id: z5.string().min(1)
751
+ });
752
+ var ProjectDirectory = z5.strictObject({
753
+ id: z5.string().min(1),
754
+ /** Absolute path of the project's folder. */
755
+ path: z5.string().min(1),
756
+ /** Absolute path a new session in this project starts in. */
757
+ defaultCwd: z5.string().min(1),
758
+ /** Ancestor project ids, root first. */
759
+ ancestorIds: z5.array(z5.string().min(1))
760
+ });
761
+ var ProjectDirectoryResponse = z5.strictObject({
762
+ project: ProjectDirectory.nullable()
763
+ });
764
+
740
765
  // packages/plugin-sdk/dist/endpoints.js
741
766
  function createUnavailablePluginEndpointCaller(message) {
742
767
  return {
@@ -1,3 +1,5 @@
1
+ import { z } from 'zod';
2
+
1
3
  export declare function createUnavailablePluginEndpointCaller(message: string): PluginEndpointCaller;
2
4
 
3
5
  /** Sessionless JSON calls to another plugin's declared, publicly reachable endpoint. */
@@ -22,4 +24,31 @@ export declare type PluginEndpointOutcome = {
22
24
  readonly message: string;
23
25
  };
24
26
 
27
+ export declare const ProjectDirectory: z.ZodObject<{
28
+ id: z.ZodString;
29
+ path: z.ZodString;
30
+ defaultCwd: z.ZodString;
31
+ ancestorIds: z.ZodArray<z.ZodString>;
32
+ }, z.core.$strict>;
33
+
34
+ export declare type ProjectDirectory = z.infer<typeof ProjectDirectory>;
35
+
36
+ export declare const ProjectDirectoryRequest: z.ZodObject<{
37
+ id: z.ZodString;
38
+ }, z.core.$strict>;
39
+
40
+ export declare type ProjectDirectoryRequest = z.infer<typeof ProjectDirectoryRequest>;
41
+
42
+ /** `project` is null when no project has the requested id. */
43
+ export declare const ProjectDirectoryResponse: z.ZodObject<{
44
+ project: z.ZodNullable<z.ZodObject<{
45
+ id: z.ZodString;
46
+ path: z.ZodString;
47
+ defaultCwd: z.ZodString;
48
+ ancestorIds: z.ZodArray<z.ZodString>;
49
+ }, z.core.$strict>>;
50
+ }, z.core.$strict>;
51
+
52
+ export declare type ProjectDirectoryResponse = z.infer<typeof ProjectDirectoryResponse>;
53
+
25
54
  export { }
package/dist/endpoints.js CHANGED
@@ -1,3 +1,28 @@
1
+ // packages/plugin-protocol/dist/project-directories.js
2
+ import { z } from "zod";
3
+ var PluginProjectDirectories = z.strictObject({
4
+ /** An endpoint this plugin's app target declares; called with a {@link ProjectDirectoryRequest}. */
5
+ endpoint: z.string().min(1),
6
+ /** A scheme this plugin's URI modules serve; a project is addressed as `<scheme>://<id>`. */
7
+ scheme: z.string().min(1)
8
+ });
9
+ var ProjectDirectoryRequest = z.strictObject({
10
+ /** The project's stable id. */
11
+ id: z.string().min(1)
12
+ });
13
+ var ProjectDirectory = z.strictObject({
14
+ id: z.string().min(1),
15
+ /** Absolute path of the project's folder. */
16
+ path: z.string().min(1),
17
+ /** Absolute path a new session in this project starts in. */
18
+ defaultCwd: z.string().min(1),
19
+ /** Ancestor project ids, root first. */
20
+ ancestorIds: z.array(z.string().min(1))
21
+ });
22
+ var ProjectDirectoryResponse = z.strictObject({
23
+ project: ProjectDirectory.nullable()
24
+ });
25
+
1
26
  // packages/plugin-sdk/dist/endpoints.js
2
27
  function createUnavailablePluginEndpointCaller(message) {
3
28
  return {
@@ -5,5 +30,8 @@ function createUnavailablePluginEndpointCaller(message) {
5
30
  };
6
31
  }
7
32
  export {
33
+ ProjectDirectory,
34
+ ProjectDirectoryRequest,
35
+ ProjectDirectoryResponse,
8
36
  createUnavailablePluginEndpointCaller
9
37
  };
package/dist/fs.d.ts CHANGED
@@ -10,6 +10,9 @@ export declare const chmod: typeof nodeFsp.chmod;
10
10
 
11
11
  export declare const chown: typeof nodeFsp.chown;
12
12
 
13
+ /** Receives the committed paths under the folder it subscribed to. */
14
+ export declare type CommittedChangeListener = (paths: readonly string[]) => void;
15
+
13
16
  export { constants }
14
17
 
15
18
  export declare const copyFile: typeof nodeFsp.copyFile;
@@ -59,6 +62,21 @@ declare const _default: {
59
62
  };
60
63
  export default _default;
61
64
 
65
+ /**
66
+ * Report paths whose writes have landed: created, replaced, moved or removed. A path is a source
67
+ * that changed, never a claim that anything is gone. Never throws: a subscriber's failure goes
68
+ * to its own `warn`, and a failing `warn` is ignored, because a report cannot undo the write.
69
+ */
70
+ export declare function emitCommittedChanges(paths: readonly string[]): void;
71
+
72
+ /**
73
+ * Run `work` after every task queued earlier under `key` in this process, and
74
+ * before every task queued later. Nothing touches the filesystem: `key` is an
75
+ * opaque string, and there is no cross-process lock. Use it when this process
76
+ * is the only writer and only same-process ordering matters.
77
+ */
78
+ export declare function enqueueInProcess<T>(key: string, work: () => Promise<T>): Promise<T>;
79
+
62
80
  export { FileHandle }
63
81
 
64
82
  export declare const glob: typeof nodeFsp.glob;
@@ -124,6 +142,14 @@ export declare const stat: typeof nodeFsp.stat;
124
142
 
125
143
  export declare const statfs: typeof nodeFsp.statfs;
126
144
 
145
+ /**
146
+ * Hear about writes any plugin in this process reports with {@link emitCommittedChanges} under
147
+ * `folder`. `listener` receives the absolute, deduplicated paths inside `folder` (the folder
148
+ * itself included), synchronously from the emit. A throw from `listener` goes to `warn`. Returns
149
+ * the function that stops delivery.
150
+ */
151
+ export declare function subscribeCommittedChanges(folder: string, listener: CommittedChangeListener, warn: (error: unknown) => void): () => void;
152
+
127
153
  export declare const symlink: typeof nodeFsp.symlink;
128
154
 
129
155
  export declare const truncate: typeof nodeFsp.truncate;
package/dist/fs.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { Buffer as Buffer3 } from "node:buffer";
3
3
  import { constants } from "node:fs";
4
4
  import * as nodeFsp from "node:fs/promises";
5
- import { basename, dirname, join, resolve as resolve2 } from "node:path";
5
+ import { basename, dirname, join, resolve as resolve3 } from "node:path";
6
6
 
7
7
  // packages/plugin-sdk/dist/fs/handle.js
8
8
  import { Buffer as Buffer2 } from "node:buffer";
@@ -611,6 +611,50 @@ function currentKayFsBackend() {
611
611
  return globalThis[KAY_FS_BACKEND];
612
612
  }
613
613
 
614
+ // packages/plugin-sdk/dist/fs/mutation-queue.js
615
+ var mutationQueues = /* @__PURE__ */ new Map();
616
+ async function enqueueInProcess(key, work) {
617
+ const previous = mutationQueues.get(key) ?? Promise.resolve();
618
+ const next = previous.catch(() => void 0).then(work);
619
+ mutationQueues.set(key, next);
620
+ try {
621
+ return await next;
622
+ } finally {
623
+ if (mutationQueues.get(key) === next)
624
+ mutationQueues.delete(key);
625
+ }
626
+ }
627
+
628
+ // packages/plugin-sdk/dist/fs/committed-changes.js
629
+ import { isAbsolute, relative, resolve as resolve2 } from "node:path";
630
+ var subscriptions = /* @__PURE__ */ new Set();
631
+ function subscribeCommittedChanges(folder, listener, warn) {
632
+ const subscription = { folder: resolve2(folder), listener, warn };
633
+ subscriptions.add(subscription);
634
+ return () => {
635
+ subscriptions.delete(subscription);
636
+ };
637
+ }
638
+ function emitCommittedChanges(paths) {
639
+ const resolved = [...new Set(paths.map((path) => resolve2(path)))];
640
+ for (const subscription of subscriptions) {
641
+ const owned = resolved.filter((path) => {
642
+ const fromFolder = relative(subscription.folder, path);
643
+ return fromFolder === "" || !fromFolder.startsWith("..") && !isAbsolute(fromFolder);
644
+ });
645
+ if (owned.length === 0)
646
+ continue;
647
+ try {
648
+ subscription.listener(owned);
649
+ } catch (error) {
650
+ try {
651
+ subscription.warn(error);
652
+ } catch {
653
+ }
654
+ }
655
+ }
656
+ }
657
+
614
658
  // packages/plugin-sdk/dist/fs/index.js
615
659
  function route(node, host) {
616
660
  return ((...args) => {
@@ -766,7 +810,7 @@ var glob2 = route(() => nodeFsp.glob, (backend, pattern, options) => {
766
810
  pattern,
767
811
  wire === void 0 ? {} : { ...wire, ...cwd === void 0 ? {} : { cwd: wirePath(cwd) } }
768
812
  ], {
769
- paths: [cwd === void 0 ? resolve2(".") : keyPath(cwd)],
813
+ paths: [cwd === void 0 ? resolve3(".") : keyPath(cwd)],
770
814
  timeoutMs: timeoutOf(options),
771
815
  walksTree: true
772
816
  });
@@ -864,6 +908,8 @@ export {
864
908
  copyFile2 as copyFile,
865
909
  cp2 as cp,
866
910
  index_default as default,
911
+ emitCommittedChanges,
912
+ enqueueInProcess,
867
913
  glob2 as glob,
868
914
  lchmod2 as lchmod,
869
915
  lchown2 as lchown,
@@ -884,6 +930,7 @@ export {
884
930
  rmdir2 as rmdir,
885
931
  stat2 as stat,
886
932
  statfs2 as statfs,
933
+ subscribeCommittedChanges,
887
934
  symlink2 as symlink,
888
935
  truncate2 as truncate,
889
936
  unlink2 as unlink,
@@ -2520,8 +2520,12 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2520
2520
  * 0.53.0 adds declared working-content layouts, family-root authority, draft projection discovery
2521
2521
  * and session-bound page references. Older customized Whiteboard copies must accept the plugin
2522
2522
  * update before using these interfaces.
2523
+ *
2524
+ * 0.54.0 adds named UI host grants for shared configuration/auth/account reads, retained connection
2525
+ * progress/dismissal and support. Built-in-only page capability scopes are removed; executable
2526
+ * pages declare capabilities on apps[].
2523
2527
  */
2524
- declare const KAY_PLUGIN_SDK_VERSION: "0.53.0";
2528
+ declare const KAY_PLUGIN_SDK_VERSION: "0.54.0";
2525
2529
 
2526
2530
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2527
2531
 
@@ -4959,6 +4963,10 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
4959
4963
  usage: z.ZodString;
4960
4964
  endpointId: z.ZodString;
4961
4965
  }, z.core.$strict>>>;
4966
+ projectDirectories: z.ZodOptional<z.ZodObject<{
4967
+ scheme: z.ZodString;
4968
+ endpointId: z.ZodString;
4969
+ }, z.core.$strict>>;
4962
4970
  authServices: z.ZodArray<z.ZodObject<{
4963
4971
  localId: z.ZodString;
4964
4972
  globalId: z.ZodString;
@@ -5001,9 +5009,11 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5001
5009
  globalId: z.ZodString;
5002
5010
  kind: z.ZodLiteral<"oauth2">;
5003
5011
  scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5012
+ connectScopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5004
5013
  authorizationUrl: z.ZodURL;
5005
5014
  tokenUrl: z.ZodURL;
5006
5015
  extraAuthorizeParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
5016
+ extraAuthorizeParamsWhenAccountHeld: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
5007
5017
  displayName: z.ZodOptional<z.ZodString>;
5008
5018
  agentHint: z.ZodOptional<z.ZodString>;
5009
5019
  summary: z.ZodOptional<z.ZodString>;
@@ -5032,9 +5042,11 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5032
5042
  globalId: z.ZodString;
5033
5043
  kind: z.ZodLiteral<"oauth2">;
5034
5044
  scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5045
+ connectScopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5035
5046
  authorizationUrl: z.ZodURL;
5036
5047
  tokenUrl: z.ZodURL;
5037
5048
  extraAuthorizeParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
5049
+ extraAuthorizeParamsWhenAccountHeld: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
5038
5050
  displayName: z.ZodOptional<z.ZodString>;
5039
5051
  agentHint: z.ZodOptional<z.ZodString>;
5040
5052
  summary: z.ZodOptional<z.ZodString>;
@@ -5668,6 +5680,7 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5668
5680
  skills: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
5669
5681
  }, z.core.$strict>>;
5670
5682
  localId: z.ZodString;
5683
+ adapterId: z.ZodOptional<z.ZodString>;
5671
5684
  globalId: z.ZodString;
5672
5685
  schemes: z.ZodArray<z.ZodString>;
5673
5686
  displayName: z.ZodOptional<z.ZodString>;
@@ -6140,6 +6153,13 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
6140
6153
  }, z.core.$strict>]>>>;
6141
6154
  host: z.ZodOptional<z.ZodArray<z.ZodEnum<{
6142
6155
  "navigation.open-session": "navigation.open-session";
6156
+ "navigation.open-external": "navigation.open-external";
6157
+ "configuration.read": "configuration.read";
6158
+ "auth-services.read": "auth-services.read";
6159
+ "connect-flows.read": "connect-flows.read";
6160
+ "connect-flows.dismiss": "connect-flows.dismiss";
6161
+ "support.report": "support.report";
6162
+ "navigation.open-page": "navigation.open-page";
6143
6163
  "sessions.create": "sessions.create";
6144
6164
  "models.complete": "models.complete";
6145
6165
  "artifacts.read": "artifacts.read";
@@ -6147,6 +6167,10 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
6147
6167
  "markdown.document-view": "markdown.document-view";
6148
6168
  "references.open": "references.open";
6149
6169
  "billing.read": "billing.read";
6170
+ "account.read": "account.read";
6171
+ "plugins.read": "plugins.read";
6172
+ "plugins.settings": "plugins.settings";
6173
+ "permissions.manage": "permissions.manage";
6150
6174
  "automations.read": "automations.read";
6151
6175
  "automations.run": "automations.run";
6152
6176
  "shared-artifacts.read": "shared-artifacts.read";
@@ -2799,8 +2799,12 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2799
2799
  * 0.53.0 adds declared working-content layouts, family-root authority, draft projection discovery
2800
2800
  * and session-bound page references. Older customized Whiteboard copies must accept the plugin
2801
2801
  * update before using these interfaces.
2802
+ *
2803
+ * 0.54.0 adds named UI host grants for shared configuration/auth/account reads, retained connection
2804
+ * progress/dismissal and support. Built-in-only page capability scopes are removed; executable
2805
+ * pages declare capabilities on apps[].
2802
2806
  */
2803
- declare const KAY_PLUGIN_SDK_VERSION: "0.53.0";
2807
+ declare const KAY_PLUGIN_SDK_VERSION: "0.54.0";
2804
2808
 
2805
2809
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2806
2810
 
@@ -5134,6 +5138,18 @@ declare const PluginCapabilityRefusalV1: z.ZodObject<{
5134
5138
  target: z.ZodLiteral<"kay.app">;
5135
5139
  slug: z.ZodLiteral<"plugins.set-enabled">;
5136
5140
  envelope: z.ZodObject<{}, z.core.$strict>;
5141
+ }, z.core.$strict>, z.ZodObject<{
5142
+ target: z.ZodLiteral<"kay.app">;
5143
+ slug: z.ZodLiteral<"sessions.assign-project">;
5144
+ envelope: z.ZodObject<{}, z.core.$strict>;
5145
+ }, z.core.$strict>, z.ZodObject<{
5146
+ target: z.ZodLiteral<"kay.app">;
5147
+ slug: z.ZodLiteral<"artifacts.resolve-file">;
5148
+ envelope: z.ZodObject<{}, z.core.$strict>;
5149
+ }, z.core.$strict>, z.ZodObject<{
5150
+ target: z.ZodLiteral<"kay.app">;
5151
+ slug: z.ZodLiteral<"process.run">;
5152
+ envelope: z.ZodObject<{}, z.core.$strict>;
5137
5153
  }, z.core.$strict>, z.ZodObject<{
5138
5154
  target: z.ZodLiteral<"kay.app">;
5139
5155
  slug: z.ZodLiteral<"sessions.annotate">;
@@ -5678,6 +5694,33 @@ export declare interface ProducedResourceDeclaration {
5678
5694
  readonly action: ProducedResourceAction;
5679
5695
  }
5680
5696
 
5697
+ export declare const ProjectDirectory: z.ZodObject<{
5698
+ id: z.ZodString;
5699
+ path: z.ZodString;
5700
+ defaultCwd: z.ZodString;
5701
+ ancestorIds: z.ZodArray<z.ZodString>;
5702
+ }, z.core.$strict>;
5703
+
5704
+ export declare type ProjectDirectory = z.infer<typeof ProjectDirectory>;
5705
+
5706
+ export declare const ProjectDirectoryRequest: z.ZodObject<{
5707
+ id: z.ZodString;
5708
+ }, z.core.$strict>;
5709
+
5710
+ export declare type ProjectDirectoryRequest = z.infer<typeof ProjectDirectoryRequest>;
5711
+
5712
+ /** `project` is null when no project has the requested id. */
5713
+ export declare const ProjectDirectoryResponse: z.ZodObject<{
5714
+ project: z.ZodNullable<z.ZodObject<{
5715
+ id: z.ZodString;
5716
+ path: z.ZodString;
5717
+ defaultCwd: z.ZodString;
5718
+ ancestorIds: z.ZodArray<z.ZodString>;
5719
+ }, z.core.$strict>>;
5720
+ }, z.core.$strict>;
5721
+
5722
+ export declare type ProjectDirectoryResponse = z.infer<typeof ProjectDirectoryResponse>;
5723
+
5681
5724
  declare const Properties: (input: string) => [unknown, string] | [];
5682
5725
 
5683
5726
  declare function PropertiesMapping(input: [unknown, unknown, unknown]): unknown;
package/dist/kay-agent.js CHANGED
@@ -999,6 +999,31 @@ function createUnavailableUriCaller(message) {
999
999
  };
1000
1000
  }
1001
1001
 
1002
+ // packages/plugin-protocol/dist/project-directories.js
1003
+ import { z as z5 } from "zod";
1004
+ var PluginProjectDirectories = z5.strictObject({
1005
+ /** An endpoint this plugin's app target declares; called with a {@link ProjectDirectoryRequest}. */
1006
+ endpoint: z5.string().min(1),
1007
+ /** A scheme this plugin's URI modules serve; a project is addressed as `<scheme>://<id>`. */
1008
+ scheme: z5.string().min(1)
1009
+ });
1010
+ var ProjectDirectoryRequest = z5.strictObject({
1011
+ /** The project's stable id. */
1012
+ id: z5.string().min(1)
1013
+ });
1014
+ var ProjectDirectory = z5.strictObject({
1015
+ id: z5.string().min(1),
1016
+ /** Absolute path of the project's folder. */
1017
+ path: z5.string().min(1),
1018
+ /** Absolute path a new session in this project starts in. */
1019
+ defaultCwd: z5.string().min(1),
1020
+ /** Ancestor project ids, root first. */
1021
+ ancestorIds: z5.array(z5.string().min(1))
1022
+ });
1023
+ var ProjectDirectoryResponse = z5.strictObject({
1024
+ project: ProjectDirectory.nullable()
1025
+ });
1026
+
1002
1027
  // packages/plugin-sdk/dist/endpoints.js
1003
1028
  function createUnavailablePluginEndpointCaller(message) {
1004
1029
  return {
@@ -1171,7 +1196,7 @@ async function readBodyWithByteCap(response, maxBytes) {
1171
1196
  }
1172
1197
 
1173
1198
  // packages/plugin-primitives/dist/tool-parameters.js
1174
- import { z as z5 } from "zod";
1199
+ import { z as z6 } from "zod";
1175
1200
  var URI_PAYLOAD_MARKER = "x-kay-uri-payload";
1176
1201
  var URI_PAYLOAD_WIRE_TYPES = [
1177
1202
  "string",
@@ -1181,16 +1206,16 @@ var URI_PAYLOAD_WIRE_TYPES = [
1181
1206
  "boolean",
1182
1207
  "null"
1183
1208
  ];
1184
- var uriPayloadSchema = z5.union([
1185
- z5.string(),
1186
- z5.record(z5.string(), z5.unknown()),
1187
- z5.array(z5.unknown()),
1188
- z5.number(),
1189
- z5.boolean(),
1190
- z5.null()
1209
+ var uriPayloadSchema = z6.union([
1210
+ z6.string(),
1211
+ z6.record(z6.string(), z6.unknown()),
1212
+ z6.array(z6.unknown()),
1213
+ z6.number(),
1214
+ z6.boolean(),
1215
+ z6.null()
1191
1216
  ]).meta({ [URI_PAYLOAD_MARKER]: true });
1192
1217
  function toToolParameters(schema) {
1193
- const jsonSchema = z5.toJSONSchema(schema, {
1218
+ const jsonSchema = z6.toJSONSchema(schema, {
1194
1219
  io: "input",
1195
1220
  override(ctx) {
1196
1221
  const node = ctx.jsonSchema;
@@ -1331,7 +1356,7 @@ function jsonValue(value) {
1331
1356
  }
1332
1357
 
1333
1358
  // packages/plugin-sdk/dist/kay-agent/index.js
1334
- import { z as z7 } from "zod";
1359
+ import { z as z8 } from "zod";
1335
1360
 
1336
1361
  // packages/plugin-sdk/dist/kay-agent/http-client.js
1337
1362
  var PluginApiError = class extends Error {
@@ -1507,7 +1532,7 @@ function createUnavailableEndpoints(message) {
1507
1532
  }
1508
1533
 
1509
1534
  // packages/plugin-sdk/dist/kay-agent/osascript.js
1510
- import { z as z6 } from "zod";
1535
+ import { z as z7 } from "zod";
1511
1536
  var OSASCRIPT_TIMEOUT_MS = 3e4;
1512
1537
  var OSASCRIPT_ENVELOPE_JXA = `
1513
1538
  function jsonOk(data) {
@@ -1517,11 +1542,11 @@ function jsonFail(code, message) {
1517
1542
  return JSON.stringify({ ok: false, error: { code: String(code), message: String(message) } });
1518
1543
  }
1519
1544
  `;
1520
- var envelopeSchema = z6.discriminatedUnion("ok", [
1521
- z6.object({ ok: z6.literal(true), data: z6.unknown() }),
1522
- z6.object({
1523
- ok: z6.literal(false),
1524
- error: z6.object({ code: z6.string(), message: z6.string() })
1545
+ var envelopeSchema = z7.discriminatedUnion("ok", [
1546
+ z7.object({ ok: z7.literal(true), data: z7.unknown() }),
1547
+ z7.object({
1548
+ ok: z7.literal(false),
1549
+ error: z7.object({ code: z7.string(), message: z7.string() })
1525
1550
  })
1526
1551
  ]);
1527
1552
  function readOsascriptOutput(stdout) {
@@ -1717,6 +1742,9 @@ export {
1717
1742
  OSASCRIPT_ENVELOPE_JXA,
1718
1743
  OSASCRIPT_TIMEOUT_MS,
1719
1744
  PluginApiError,
1745
+ ProjectDirectory,
1746
+ ProjectDirectoryRequest,
1747
+ ProjectDirectoryResponse,
1720
1748
  SearchProviderError,
1721
1749
  SecureTransportError,
1722
1750
  URI_TEXT_EDIT_SHAPE_SUMMARY,
@@ -1787,5 +1815,5 @@ export {
1787
1815
  uriTextEditPayloadSchema,
1788
1816
  withResolvedAuth,
1789
1817
  withResolvedSearchProvider,
1790
- z7 as z
1818
+ z8 as z
1791
1819
  };
@@ -1824,6 +1824,18 @@ declare type KayAppSessionPageItem = (Omit<Extract<TranscriptPageItem, {
1824
1824
  readonly unreadable: unknown;
1825
1825
  }>;
1826
1826
 
1827
+ /** One write for {@link KayAppSessions.assignProject}. */
1828
+ declare interface KayAppSessionProjectAssignment {
1829
+ readonly sessionId: string;
1830
+ /**
1831
+ * The project the session must still hold for the write to land: a project id, `null` for "no
1832
+ * project" chosen on purpose, or absent for a session whose project was never decided.
1833
+ */
1834
+ readonly expectedProjectId?: string | null;
1835
+ /** The project to set; `null` sets "no project". */
1836
+ readonly projectId: string | null;
1837
+ }
1838
+
1827
1839
  /**
1828
1840
  * What one headless system run reports back. The run's spend is read from the
1829
1841
  * ledger after the turn settles; `cost` is absent when no spend rows were
@@ -2158,6 +2170,15 @@ declare interface KayAppSessions {
2158
2170
  } | {
2159
2171
  readonly kind: "unavailable";
2160
2172
  }>;
2173
+ /**
2174
+ * Private API: only plugins Bonsai ships; refused for any other. Set the project of any stored
2175
+ * sessions, each only while it still holds the project the caller last saw (a compare-and-set,
2176
+ * so a person's own choice made meanwhile always wins). Answers one boolean per assignment, in
2177
+ * order: `false` when the session is gone or its project changed. A written session's project
2178
+ * folder and prompt block are refreshed. Checked against `sessions.assign-project`; a refused
2179
+ * call rejects.
2180
+ */
2181
+ assignProject?(assignments: readonly KayAppSessionProjectAssignment[]): Promise<readonly boolean[]>;
2161
2182
  /**
2162
2183
  * Run one hidden headless system session through Bonsai's harness and resolve
2163
2184
  * with its final output - the sole sanctioned way for a `kay.app` plugin to