@yaklabs-ai/plugin-sdk 0.35.0 → 0.37.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.35.0"
16
+ "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.37.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.35.0" },
65
+ "compatibility": { "sdk": "^0.37.0" },
66
66
  "targets": {
67
67
  "kay": {
68
68
  "agent": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@yaklabs-ai/plugin-sdk",
4
- "version": "0.35.0",
4
+ "version": "0.37.0",
5
5
  "target": "npm",
6
6
  "firstPartyLicense": "MIT",
7
7
  "bundled": [
@@ -2385,8 +2385,18 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2385
2385
  * names one of the plugin's `rows` data sources, an optional `where` and a plural `label`.
2386
2386
  * `app.skills` gains `listPendingSuggestions` and `subscribeSuggestions` under `skills.read`. A plugin
2387
2387
  * that declares a badge declares ^0.35.0.
2388
+ *
2389
+ * 0.36.0 lets a plugin declare its pages and which page an address opens (#15897, #15898). `pages`
2390
+ * under `kay.ui` `contributes` names each page's title, icon file, companion status and opened
2391
+ * event. A reference presentation that opens a page gains `scheme` and `addresses`, and may leave
2392
+ * out `uriModule` when another layer serves the address. A plugin using these declares ^0.36.0.
2393
+ *
2394
+ * 0.37.0 lets a notification rule's toast declare a preview (#15904). `toastPreviews` under `kay.ui`
2395
+ * `contributes` names the `rule`, the `body` that fills the preview, either a `contextOnly` app in
2396
+ * the plugin or a body the host ships, and the `address` it is about. Additive. A plugin that
2397
+ * declares a preview declares ^0.37.0.
2388
2398
  */
2389
- declare const KAY_PLUGIN_SDK_VERSION: "0.35.0";
2399
+ declare const KAY_PLUGIN_SDK_VERSION: "0.37.0";
2390
2400
 
2391
2401
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2392
2402
 
@@ -9873,12 +9883,13 @@ declare interface UriPatternInit {
9873
9883
  */
9874
9884
  readonly hostname?: string;
9875
9885
  /**
9876
- * Slash-delimited path pattern. A final capture may use `:name*` to consume
9877
- * the remaining path segments, preserving `/` in the captured value. Unless the pattern itself
9878
- * ends in `/`, an input path ending in one `/` matches as if the slash were absent, so
9879
- * `threads/t1/` is `threads/t1` (captures and official spelling included) and a lone `/` after a
9880
- * host is the empty path; a doubled `//` is never dropped, nor the root path of an address with
9881
- * no host (`bfs:///`).
9886
+ * Slash-delimited path pattern, starting with `/`. `""` matches only an address with no path. A
9887
+ * final capture may use `:name*` to consume the remaining path segments, preserving `/` in the
9888
+ * captured value. A capture may end in a literal extension: `:name.md` matches `billing.md` and
9889
+ * captures `billing`. Unless the pattern itself ends in `/`, an input path ending in one `/`
9890
+ * matches as if the slash were absent, so `threads/t1/` is `threads/t1` (captures and official
9891
+ * spelling included) and a lone `/` after a host is the empty path; a doubled `//` is never
9892
+ * dropped, nor the root path of an address with no host (`bfs:///`).
9882
9893
  */
9883
9894
  readonly pathname?: string;
9884
9895
  /** `&`-delimited query pattern; `""` matches only an address with no query. */
@@ -2439,8 +2439,18 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2439
2439
  * names one of the plugin's `rows` data sources, an optional `where` and a plural `label`.
2440
2440
  * `app.skills` gains `listPendingSuggestions` and `subscribeSuggestions` under `skills.read`. A plugin
2441
2441
  * that declares a badge declares ^0.35.0.
2442
+ *
2443
+ * 0.36.0 lets a plugin declare its pages and which page an address opens (#15897, #15898). `pages`
2444
+ * under `kay.ui` `contributes` names each page's title, icon file, companion status and opened
2445
+ * event. A reference presentation that opens a page gains `scheme` and `addresses`, and may leave
2446
+ * out `uriModule` when another layer serves the address. A plugin using these declares ^0.36.0.
2447
+ *
2448
+ * 0.37.0 lets a notification rule's toast declare a preview (#15904). `toastPreviews` under `kay.ui`
2449
+ * `contributes` names the `rule`, the `body` that fills the preview, either a `contextOnly` app in
2450
+ * the plugin or a body the host ships, and the `address` it is about. Additive. A plugin that
2451
+ * declares a preview declares ^0.37.0.
2442
2452
  */
2443
- declare const KAY_PLUGIN_SDK_VERSION: "0.35.0";
2453
+ declare const KAY_PLUGIN_SDK_VERSION: "0.37.0";
2444
2454
 
2445
2455
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2446
2456
 
@@ -5647,7 +5657,20 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5647
5657
  referencePresentations: z.ZodOptional<z.ZodArray<z.ZodObject<{
5648
5658
  localId: z.ZodString;
5649
5659
  globalId: z.ZodString;
5650
- uriModule: z.ZodString;
5660
+ uriModule: z.ZodOptional<z.ZodString>;
5661
+ schemes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5662
+ addresses: z.ZodOptional<z.ZodArray<z.ZodObject<{
5663
+ pattern: z.ZodObject<{
5664
+ protocol: z.ZodString;
5665
+ hostname: z.ZodString;
5666
+ pathname: z.ZodOptional<z.ZodString>;
5667
+ search: z.ZodOptional<z.ZodString>;
5668
+ }, z.core.$strict>;
5669
+ objectId: z.ZodOptional<z.ZodString>;
5670
+ open: z.ZodOptional<z.ZodObject<{
5671
+ kind: z.ZodLiteral<"none">;
5672
+ }, z.core.$strict>>;
5673
+ }, z.core.$strict>>>;
5651
5674
  resourceKind: z.ZodString;
5652
5675
  open: z.ZodDiscriminatedUnion<[z.ZodObject<{
5653
5676
  kind: z.ZodLiteral<"working-document">;
@@ -5711,6 +5734,7 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5711
5734
  "sessions.create": "sessions.create";
5712
5735
  "artifacts.read": "artifacts.read";
5713
5736
  "artifacts.preview": "artifacts.preview";
5737
+ "markdown.document-view": "markdown.document-view";
5714
5738
  "cost.read": "cost.read";
5715
5739
  "billing.read": "billing.read";
5716
5740
  "skills.read": "skills.read";
@@ -10944,12 +10968,13 @@ declare interface UriPatternInit {
10944
10968
  */
10945
10969
  readonly hostname?: string;
10946
10970
  /**
10947
- * Slash-delimited path pattern. A final capture may use `:name*` to consume
10948
- * the remaining path segments, preserving `/` in the captured value. Unless the pattern itself
10949
- * ends in `/`, an input path ending in one `/` matches as if the slash were absent, so
10950
- * `threads/t1/` is `threads/t1` (captures and official spelling included) and a lone `/` after a
10951
- * host is the empty path; a doubled `//` is never dropped, nor the root path of an address with
10952
- * no host (`bfs:///`).
10971
+ * Slash-delimited path pattern, starting with `/`. `""` matches only an address with no path. A
10972
+ * final capture may use `:name*` to consume the remaining path segments, preserving `/` in the
10973
+ * captured value. A capture may end in a literal extension: `:name.md` matches `billing.md` and
10974
+ * captures `billing`. Unless the pattern itself ends in `/`, an input path ending in one `/`
10975
+ * matches as if the slash were absent, so `threads/t1/` is `threads/t1` (captures and official
10976
+ * spelling included) and a lone `/` after a host is the empty path; a doubled `//` is never
10977
+ * dropped, nor the root path of an address with no host (`bfs:///`).
10953
10978
  */
10954
10979
  readonly pathname?: string;
10955
10980
  /** `&`-delimited query pattern; `""` matches only an address with no query. */
@@ -2714,8 +2714,18 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2714
2714
  * names one of the plugin's `rows` data sources, an optional `where` and a plural `label`.
2715
2715
  * `app.skills` gains `listPendingSuggestions` and `subscribeSuggestions` under `skills.read`. A plugin
2716
2716
  * that declares a badge declares ^0.35.0.
2717
+ *
2718
+ * 0.36.0 lets a plugin declare its pages and which page an address opens (#15897, #15898). `pages`
2719
+ * under `kay.ui` `contributes` names each page's title, icon file, companion status and opened
2720
+ * event. A reference presentation that opens a page gains `scheme` and `addresses`, and may leave
2721
+ * out `uriModule` when another layer serves the address. A plugin using these declares ^0.36.0.
2722
+ *
2723
+ * 0.37.0 lets a notification rule's toast declare a preview (#15904). `toastPreviews` under `kay.ui`
2724
+ * `contributes` names the `rule`, the `body` that fills the preview, either a `contextOnly` app in
2725
+ * the plugin or a body the host ships, and the `address` it is about. Additive. A plugin that
2726
+ * declares a preview declares ^0.37.0.
2717
2727
  */
2718
- declare const KAY_PLUGIN_SDK_VERSION: "0.35.0";
2728
+ declare const KAY_PLUGIN_SDK_VERSION: "0.37.0";
2719
2729
 
2720
2730
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2721
2731
 
@@ -11195,12 +11205,13 @@ declare interface UriPatternInit {
11195
11205
  */
11196
11206
  readonly hostname?: string;
11197
11207
  /**
11198
- * Slash-delimited path pattern. A final capture may use `:name*` to consume
11199
- * the remaining path segments, preserving `/` in the captured value. Unless the pattern itself
11200
- * ends in `/`, an input path ending in one `/` matches as if the slash were absent, so
11201
- * `threads/t1/` is `threads/t1` (captures and official spelling included) and a lone `/` after a
11202
- * host is the empty path; a doubled `//` is never dropped, nor the root path of an address with
11203
- * no host (`bfs:///`).
11208
+ * Slash-delimited path pattern, starting with `/`. `""` matches only an address with no path. A
11209
+ * final capture may use `:name*` to consume the remaining path segments, preserving `/` in the
11210
+ * captured value. A capture may end in a literal extension: `:name.md` matches `billing.md` and
11211
+ * captures `billing`. Unless the pattern itself ends in `/`, an input path ending in one `/`
11212
+ * matches as if the slash were absent, so `threads/t1/` is `threads/t1` (captures and official
11213
+ * spelling included) and a lone `/` after a host is the empty path; a doubled `//` is never
11214
+ * dropped, nor the root path of an address with no host (`bfs:///`).
11204
11215
  */
11205
11216
  readonly pathname?: string;
11206
11217
  /** `&`-delimited query pattern; `""` matches only an address with no query. */
package/dist/kay-agent.js CHANGED
@@ -2,7 +2,7 @@
2
2
  var SCHEME_RE = /^([a-z][a-z0-9+.-]*):\/\//i;
3
3
  var CAPTURE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
4
4
  var REST_CAPTURE_RE = /^:([A-Za-z_][A-Za-z0-9_]*)\*$/;
5
- var CONSTRAINED_CAPTURE_RE = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.*)\))?$/;
5
+ var CONSTRAINED_CAPTURE_RE = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.*)\))?(\.[A-Za-z0-9]+)?$/;
6
6
  var MAX_CAPTURE_CONSTRAINT_LENGTH = 64;
7
7
  function compileUriClaim(claim) {
8
8
  if (claim.kind === "scheme") {
@@ -144,8 +144,10 @@ function compileParts(value, separator, options = {}) {
144
144
  const constraint = match[2];
145
145
  if (constraint !== void 0)
146
146
  assertSupportedConstraint(constraint);
147
+ const suffix = match[3];
147
148
  return {
148
149
  capture,
150
+ ...suffix !== void 0 ? { suffix } : {},
149
151
  ...constraint !== void 0 ? { constraint: new RegExp(`^(?:${constraint})$`) } : {}
150
152
  };
151
153
  }
@@ -165,8 +167,11 @@ function matchRoute(pattern, input) {
165
167
  if (pattern.hostname !== void 0 && !matchParts(pattern.hostname, input.hostname, isLoneCapture(pattern.hostname) ? void 0 : ".", captures, true)) {
166
168
  return void 0;
167
169
  }
168
- if (pattern.pathname !== void 0 && !matchParts(pattern.pathname, pattern.pathnameEndsInSlash === true ? input.pathname : withoutTrailingSlash(input), "/", captures)) {
169
- return void 0;
170
+ if (pattern.pathname !== void 0) {
171
+ const pathname = pattern.pathnameEndsInSlash === true ? input.pathname : withoutTrailingSlash(input);
172
+ if (pattern.pathname.length === 0 ? pathname !== "" : !matchParts(pattern.pathname, pathname, "/", captures)) {
173
+ return void 0;
174
+ }
170
175
  }
171
176
  if (pattern.search !== void 0 && (pattern.search.length === 0 ? input.search !== "" : !matchParts(pattern.search, input.search, "&", captures))) {
172
177
  return void 0;
@@ -200,7 +205,11 @@ function matchParts(pattern, value, separator, captures, foldLiterals = false) {
200
205
  return false;
201
206
  const actual = parts[partIndex];
202
207
  if (expected.capture !== void 0) {
203
- const decoded = safeDecode(actual);
208
+ const { suffix } = expected;
209
+ if (suffix !== void 0 && (!actual.endsWith(suffix) || actual.length === suffix.length)) {
210
+ return false;
211
+ }
212
+ const decoded = safeDecode(suffix === void 0 ? actual : actual.slice(0, -suffix.length));
204
213
  if (expected.constraint !== void 0 && !expected.constraint.test(decoded)) {
205
214
  return false;
206
215
  }
package/dist/kay-app.d.ts CHANGED
@@ -2676,8 +2676,18 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2676
2676
  * names one of the plugin's `rows` data sources, an optional `where` and a plural `label`.
2677
2677
  * `app.skills` gains `listPendingSuggestions` and `subscribeSuggestions` under `skills.read`. A plugin
2678
2678
  * that declares a badge declares ^0.35.0.
2679
+ *
2680
+ * 0.36.0 lets a plugin declare its pages and which page an address opens (#15897, #15898). `pages`
2681
+ * under `kay.ui` `contributes` names each page's title, icon file, companion status and opened
2682
+ * event. A reference presentation that opens a page gains `scheme` and `addresses`, and may leave
2683
+ * out `uriModule` when another layer serves the address. A plugin using these declares ^0.36.0.
2684
+ *
2685
+ * 0.37.0 lets a notification rule's toast declare a preview (#15904). `toastPreviews` under `kay.ui`
2686
+ * `contributes` names the `rule`, the `body` that fills the preview, either a `contextOnly` app in
2687
+ * the plugin or a body the host ships, and the `address` it is about. Additive. A plugin that
2688
+ * declares a preview declares ^0.37.0.
2679
2689
  */
2680
- declare const KAY_PLUGIN_SDK_VERSION: "0.35.0";
2690
+ declare const KAY_PLUGIN_SDK_VERSION: "0.37.0";
2681
2691
 
2682
2692
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2683
2693
 
@@ -15980,12 +15990,13 @@ declare interface UriPatternInit {
15980
15990
  */
15981
15991
  readonly hostname?: string;
15982
15992
  /**
15983
- * Slash-delimited path pattern. A final capture may use `:name*` to consume
15984
- * the remaining path segments, preserving `/` in the captured value. Unless the pattern itself
15985
- * ends in `/`, an input path ending in one `/` matches as if the slash were absent, so
15986
- * `threads/t1/` is `threads/t1` (captures and official spelling included) and a lone `/` after a
15987
- * host is the empty path; a doubled `//` is never dropped, nor the root path of an address with
15988
- * no host (`bfs:///`).
15993
+ * Slash-delimited path pattern, starting with `/`. `""` matches only an address with no path. A
15994
+ * final capture may use `:name*` to consume the remaining path segments, preserving `/` in the
15995
+ * captured value. A capture may end in a literal extension: `:name.md` matches `billing.md` and
15996
+ * captures `billing`. Unless the pattern itself ends in `/`, an input path ending in one `/`
15997
+ * matches as if the slash were absent, so `threads/t1/` is `threads/t1` (captures and official
15998
+ * spelling included) and a lone `/` after a host is the empty path; a doubled `//` is never
15999
+ * dropped, nor the root path of an address with no host (`bfs:///`).
15989
16000
  */
15990
16001
  readonly pathname?: string;
15991
16002
  /** `&`-delimited query pattern; `""` matches only an address with no query. */
@@ -823,12 +823,13 @@ declare interface UriPatternInit {
823
823
  */
824
824
  readonly hostname?: string;
825
825
  /**
826
- * Slash-delimited path pattern. A final capture may use `:name*` to consume
827
- * the remaining path segments, preserving `/` in the captured value. Unless the pattern itself
828
- * ends in `/`, an input path ending in one `/` matches as if the slash were absent, so
829
- * `threads/t1/` is `threads/t1` (captures and official spelling included) and a lone `/` after a
830
- * host is the empty path; a doubled `//` is never dropped, nor the root path of an address with
831
- * no host (`bfs:///`).
826
+ * Slash-delimited path pattern, starting with `/`. `""` matches only an address with no path. A
827
+ * final capture may use `:name*` to consume the remaining path segments, preserving `/` in the
828
+ * captured value. A capture may end in a literal extension: `:name.md` matches `billing.md` and
829
+ * captures `billing`. Unless the pattern itself ends in `/`, an input path ending in one `/`
830
+ * matches as if the slash were absent, so `threads/t1/` is `threads/t1` (captures and official
831
+ * spelling included) and a lone `/` after a host is the empty path; a doubled `//` is never
832
+ * dropped, nor the root path of an address with no host (`bfs:///`).
832
833
  */
833
834
  readonly pathname?: string;
834
835
  /** `&`-delimited query pattern; `""` matches only an address with no query. */
@@ -73,7 +73,7 @@ function copyClaim(claim) {
73
73
  var SCHEME_RE = /^([a-z][a-z0-9+.-]*):\/\//i;
74
74
  var CAPTURE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
75
75
  var REST_CAPTURE_RE = /^:([A-Za-z_][A-Za-z0-9_]*)\*$/;
76
- var CONSTRAINED_CAPTURE_RE = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.*)\))?$/;
76
+ var CONSTRAINED_CAPTURE_RE = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.*)\))?(\.[A-Za-z0-9]+)?$/;
77
77
  var MAX_CAPTURE_CONSTRAINT_LENGTH = 64;
78
78
  function compileUriClaim(claim) {
79
79
  if (claim.kind === "scheme") {
@@ -215,8 +215,10 @@ function compileParts(value, separator, options = {}) {
215
215
  const constraint = match[2];
216
216
  if (constraint !== void 0)
217
217
  assertSupportedConstraint(constraint);
218
+ const suffix = match[3];
218
219
  return {
219
220
  capture,
221
+ ...suffix !== void 0 ? { suffix } : {},
220
222
  ...constraint !== void 0 ? { constraint: new RegExp(`^(?:${constraint})$`) } : {}
221
223
  };
222
224
  }
@@ -236,8 +238,11 @@ function matchRoute(pattern, input) {
236
238
  if (pattern.hostname !== void 0 && !matchParts(pattern.hostname, input.hostname, isLoneCapture(pattern.hostname) ? void 0 : ".", captures, true)) {
237
239
  return void 0;
238
240
  }
239
- if (pattern.pathname !== void 0 && !matchParts(pattern.pathname, pattern.pathnameEndsInSlash === true ? input.pathname : withoutTrailingSlash(input), "/", captures)) {
240
- return void 0;
241
+ if (pattern.pathname !== void 0) {
242
+ const pathname = pattern.pathnameEndsInSlash === true ? input.pathname : withoutTrailingSlash(input);
243
+ if (pattern.pathname.length === 0 ? pathname !== "" : !matchParts(pattern.pathname, pathname, "/", captures)) {
244
+ return void 0;
245
+ }
241
246
  }
242
247
  if (pattern.search !== void 0 && (pattern.search.length === 0 ? input.search !== "" : !matchParts(pattern.search, input.search, "&", captures))) {
243
248
  return void 0;
@@ -271,7 +276,11 @@ function matchParts(pattern, value, separator, captures, foldLiterals = false) {
271
276
  return false;
272
277
  const actual = parts[partIndex];
273
278
  if (expected.capture !== void 0) {
274
- const decoded = safeDecode(actual);
279
+ const { suffix } = expected;
280
+ if (suffix !== void 0 && (!actual.endsWith(suffix) || actual.length === suffix.length)) {
281
+ return false;
282
+ }
283
+ const decoded = safeDecode(suffix === void 0 ? actual : actual.slice(0, -suffix.length));
275
284
  if (expected.constraint !== void 0 && !expected.constraint.test(decoded)) {
276
285
  return false;
277
286
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaklabs-ai/plugin-sdk",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "description": "The Kay plugin SDK — types and helpers for authoring a Kay directory plugin.",
5
5
  "author": "YakLabs",
6
6
  "type": "module",
@@ -131,7 +131,10 @@ activity-rail button when the manifest declares it: `railEntries` under `targets
131
131
  with `id`, `title` and `page`, and optionally `icon`, `shortcut`, `order` and `section`. That
132
132
  declaration works with no `ui.tsx` at all. To give the entry a sidebar, add `panel: { body }` naming
133
133
  an app in the same manifest with `contextOnly: true`. The sidebar is always there once declared, so
134
- the app shows its own empty state.
134
+ the app shows its own empty state. To give a notification rule's toast a "Show changes" preview, add
135
+ a `toastPreviews` entry under `targets.kay.ui.contributes` with `rule` (the rule's `localId`), `body`
136
+ (a `contextOnly` app) and `address` (for example `${navigateTarget}/@diff/${revision}`). The app reads
137
+ the address with `useKayAppReference()`, and the toast's "Open history" opens the same address.
135
138
 
136
139
  **Icons: declare one plugin icon, override only where you mean it.** Set the manifest `icon` (a
137
140
  package-relative SVG) and every surface the plugin contributes inherits it: reference pills, its