@yaklabs-ai/plugin-sdk 0.55.0 → 0.55.2

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.55.0"
16
+ "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.55.2"
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.55.0" },
65
+ "compatibility": { "sdk": "^0.55.2" },
66
66
  "targets": {
67
67
  "kay": {
68
68
  "agent": {
@@ -153,7 +153,7 @@ naming both versions, instead of loading it and finding no `activate`.
153
153
  | `@bonsai/plugin-sdk/system-one` | The types and error class for `api.systemOne` / `app.systemOne`, from 0.13.8 |
154
154
  | `@bonsai/plugin-sdk/zod` | `z` (the host's in the daemon), on an entry with no other import, from 0.13.9 |
155
155
 
156
- A plugin that imports these subpaths declares the current supported SDK range (`^0.55.0`).
156
+ A plugin that imports these subpaths declares the current supported SDK range (`^0.55.2`).
157
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
158
158
  vendor's MCP server itself is a separate host decision: Bonsai hosts it once a person approves
159
159
  the plugin's `mcp.host-server` grant for that server's name and URL. A server that needs an OAuth
@@ -161,7 +161,7 @@ sign-in names one of the plugin's auth services in `authService`; that service m
161
161
  one `delegated` scheme, which Bonsai uses to sign the person in to the server. Bonsai declares that
162
162
  scheme at runtime; the plugin's code must not declare it again. From 0.16.2 a plugin's code can also
163
163
  call the server's tools through `api.vendoredMcp.port(<server>)`, typed by this subpath's
164
- `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.55.0`).
164
+ `VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.55.2`).
165
165
 
166
166
  From 0.13.10 the manifest schema carries two facts Bonsai reads for its own plugins only; another
167
167
  plugin's are ignored, with a load diagnostic. An `external-cli` auth scheme's `cli` says how Bonsai
@@ -243,7 +243,7 @@ Provider schemas remain authoritative; declaring a dependency grants no authorit
243
243
  through `app.uri`, parse returned Markdown in the consuming plugin, and retain the read's
244
244
  revision (or `contentDigest` from `/uri`) for edits. The old `memory.read` and `memory.write`
245
245
  grants do not authorize the replacement scheme-and-verb calls. Contracts before 0.49.0 are
246
- refused; migrate and declare `^0.55.0`. The current host also serves the 0.49.0 resource contract.
246
+ refused; migrate and declare `^0.55.2`. The current host also serves the 0.49.0 resource contract.
247
247
 
248
248
  ## What this package is, and is not, at runtime
249
249
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@yaklabs-ai/plugin-sdk",
4
- "version": "0.55.0",
4
+ "version": "0.55.2",
5
5
  "target": "npm",
6
6
  "firstPartyLicense": "MIT",
7
7
  "bundled": [
@@ -1723,7 +1723,7 @@ declare type InteractionSurface = Pick<InteractionDriver, "isAvailable" | "targe
1723
1723
 
1724
1724
  /**
1725
1725
  * One thing a driver can be pointed at: a browser page, a running app. `id` is the driver-owned
1726
- * address the agent passes back as `target` (`kay://tabs/.../items/<item>`, `app://<bundle id>`).
1726
+ * address the agent passes back as `target` (`bonsai://tabs/.../items/<item>`, `app://<bundle id>`).
1727
1727
  * `active` marks the default target (the page the user is looking at, the front app).
1728
1728
  */
1729
1729
  declare const InteractionTarget: z.ZodObject<{
@@ -2676,8 +2676,14 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2676
2676
  *
2677
2677
  * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
2678
2678
  * Existing agent and background MCP call shapes remain supported.
2679
+ *
2680
+ * 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
2681
+ * tool previews with cancellation, app-scoped availability snapshots and app-target output
2682
+ * artifact usage declarations. A plugin using these declares ^0.55.1.
2683
+ *
2684
+ * 0.55.2 adds opt-in query and connection-selector preservation during URI claim normalization.
2679
2685
  */
2680
- declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
2686
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.2";
2681
2687
 
2682
2688
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2683
2689
 
@@ -8374,9 +8380,10 @@ declare interface ToolPermissionHint {
8374
8380
  * labelled facts. Render-only: never matched against a rule, never one-tap approval grounds.
8375
8381
  * The tool says what its input claims, so the gate shows it as the tool's claim, not as the
8376
8382
  * daemon's attestation. The host admits only display-safe text; a throw, a blank title or an
8377
- * unsafe string costs the description and the call is asked about as before.
8383
+ * unsafe string costs the description and the call is asked about as before. A promise is
8384
+ * bounded by the host description timeout; forward its optional cancellation signal to reads.
8378
8385
  */
8379
- readonly describePreview?: (input: Record<string, unknown>) => ToolPreviewDescription | undefined;
8386
+ readonly describePreview?: (input: Record<string, unknown>, signal?: AbortSignal) => ToolPreviewDescription | undefined | Promise<ToolPreviewDescription | undefined>;
8380
8387
  readonly kind?: ToolActionKind;
8381
8388
  readonly scheme?: string;
8382
8389
  readonly ruleKey?: string;
@@ -10220,7 +10227,7 @@ declare interface UriParameter {
10220
10227
  /**
10221
10228
  * A claim on a module's own custom-scheme addresses. The pattern matches with or without an
10222
10229
  * account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
10223
- * back on the official spelling, so one claim covers both spellings.
10230
+ * back on the same-scheme official spelling, so one claim covers both spellings.
10224
10231
  */
10225
10232
  declare interface UriPatternClaim {
10226
10233
  readonly kind: "uriPattern";
@@ -10231,9 +10238,13 @@ declare interface UriPatternClaim {
10231
10238
  * carried over verbatim so a route flag such as `?permanent=true` survives
10232
10239
  * canonicalization (kay#7859); a template that re-targets to another scheme
10233
10240
  * (a projection to a web link) drops it, as does a pattern that consumed the
10234
- * query itself or a template that spells its own.
10241
+ * query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
10235
10242
  */
10236
10243
  readonly normalizeTo?: UriClaimTemplate;
10244
+ /** Carry the matched query verbatim across normalization; incompatible with a target query. */
10245
+ readonly preserveQuery?: true;
10246
+ /** Carry the input's account selector even when normalization changes scheme. */
10247
+ readonly preserveConnection?: true;
10237
10248
  /**
10238
10249
  * Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
10239
10250
  * can say which addresses it means. Several claims may name the same route.
@@ -817,7 +817,7 @@ declare interface DerivedToolClassification {
817
817
  * `execute`: name, parameters, auth binding and permission all come from the manifest, as in a
818
818
  * session.
819
819
  */
820
- export declare function describedToolForTest(contract: ResolvedPluginContractV1, localId: string, execute: KayAgentToolExecute): ToolDefinition;
820
+ export declare function describedToolForTest(contract: ResolvedPluginContractV1, localId: string, execute: KayAgentToolExecute, environment?: ToolPermissionEnvironment): ToolDefinition;
821
821
 
822
822
  declare const Digit: TDigit;
823
823
 
@@ -1759,7 +1759,7 @@ declare type InteractionSurface = Pick<InteractionDriver, "isAvailable" | "targe
1759
1759
 
1760
1760
  /**
1761
1761
  * One thing a driver can be pointed at: a browser page, a running app. `id` is the driver-owned
1762
- * address the agent passes back as `target` (`kay://tabs/.../items/<item>`, `app://<bundle id>`).
1762
+ * address the agent passes back as `target` (`bonsai://tabs/.../items/<item>`, `app://<bundle id>`).
1763
1763
  * `active` marks the default target (the page the user is looking at, the front app).
1764
1764
  */
1765
1765
  declare const InteractionTarget: z.ZodObject<{
@@ -2730,8 +2730,14 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2730
2730
  *
2731
2731
  * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
2732
2732
  * Existing agent and background MCP call shapes remain supported.
2733
+ *
2734
+ * 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
2735
+ * tool previews with cancellation, app-scoped availability snapshots and app-target output
2736
+ * artifact usage declarations. A plugin using these declares ^0.55.1.
2737
+ *
2738
+ * 0.55.2 adds opt-in query and connection-selector preservation during URI claim normalization.
2733
2739
  */
2734
- declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
2740
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.2";
2735
2741
 
2736
2742
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2737
2743
 
@@ -5137,9 +5143,9 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5137
5143
  resource: "resource";
5138
5144
  storage: "storage";
5139
5145
  uriModule: "uriModule";
5146
+ app: "app";
5140
5147
  authService: "authService";
5141
5148
  command: "command";
5142
- app: "app";
5143
5149
  skill: "skill";
5144
5150
  converter: "converter";
5145
5151
  artifactUriModule: "artifactUriModule";
@@ -5759,6 +5765,8 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5759
5765
  search: z.ZodExactOptional<z.ZodString>;
5760
5766
  }, z.core.$strict>;
5761
5767
  normalizeTo: z.ZodExactOptional<z.ZodString>;
5768
+ preserveQuery: z.ZodExactOptional<z.ZodLiteral<true>>;
5769
+ preserveConnection: z.ZodExactOptional<z.ZodLiteral<true>>;
5762
5770
  route: z.ZodExactOptional<z.ZodString>;
5763
5771
  sourceUrl: z.ZodExactOptional<z.ZodString>;
5764
5772
  title: z.ZodExactOptional<z.ZodString>;
@@ -5913,6 +5921,7 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5913
5921
  displayName: z.ZodOptional<z.ZodString>;
5914
5922
  authServiceId: z.ZodOptional<z.ZodString>;
5915
5923
  authSchemeId: z.ZodOptional<z.ZodString>;
5924
+ requiredScopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5916
5925
  knownResources: z.ZodOptional<z.ZodLiteral<true>>;
5917
5926
  describesOperations: z.ZodOptional<z.ZodLiteral<true>>;
5918
5927
  looksUpWebLinks: z.ZodOptional<z.ZodLiteral<true>>;
@@ -5971,6 +5980,9 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5971
5980
  resourcePrefix: z.ZodOptional<z.ZodString>;
5972
5981
  resourceArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
5973
5982
  resourceTrim: z.ZodOptional<z.ZodLiteral<true>>;
5983
+ resourcePathNormalization: z.ZodOptional<z.ZodObject<{
5984
+ preserveUriSchemes: z.ZodOptional<z.ZodArray<z.ZodString>>;
5985
+ }, z.core.$strict>>;
5974
5986
  defaultPermission: z.ZodOptional<z.ZodEnum<{
5975
5987
  never: "never";
5976
5988
  allow: "allow";
@@ -5997,6 +6009,211 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
5997
6009
  globalId: z.ZodString;
5998
6010
  toolName: z.ZodString;
5999
6011
  }, z.core.$strict>>>;
6012
+ kayAppArtifacts: z.ZodOptional<z.ZodObject<{
6013
+ outputs: z.ZodLiteral<true>;
6014
+ }, z.core.$strict>>;
6015
+ kayAppUriModules: z.ZodOptional<z.ZodArray<z.ZodObject<{
6016
+ revisionBacked: z.ZodOptional<z.ZodLiteral<true>>;
6017
+ mailCalibrationSource: z.ZodOptional<z.ZodLiteral<true>>;
6018
+ screenActions: z.ZodExactOptional<z.ZodObject<{
6019
+ scheme: z.ZodString;
6020
+ hosts: z.ZodArray<z.ZodString>;
6021
+ paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
6022
+ apps: z.ZodArray<z.ZodString>;
6023
+ options: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
6024
+ kind: z.ZodLiteral<"exact">;
6025
+ description: z.ZodString;
6026
+ verb: z.ZodEnum<{
6027
+ read: "read";
6028
+ write: "write";
6029
+ edit: "edit";
6030
+ delete: "delete";
6031
+ }>;
6032
+ uri: z.ZodString;
6033
+ }, z.core.$strict>, z.ZodObject<{
6034
+ kind: z.ZodLiteral<"catch-all">;
6035
+ description: z.ZodString;
6036
+ verb: z.ZodEnum<{
6037
+ read: "read";
6038
+ write: "write";
6039
+ edit: "edit";
6040
+ delete: "delete";
6041
+ }>;
6042
+ }, z.core.$strict>], "kind">>;
6043
+ }, z.core.$strict>>;
6044
+ claims: z.ZodExactOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
6045
+ kind: z.ZodLiteral<"scheme">;
6046
+ scheme: z.ZodString;
6047
+ }, z.core.$strict>, z.ZodObject<{
6048
+ kind: z.ZodLiteral<"uriPattern">;
6049
+ pattern: z.ZodObject<{
6050
+ protocol: z.ZodExactOptional<z.ZodString>;
6051
+ hostname: z.ZodExactOptional<z.ZodString>;
6052
+ pathname: z.ZodExactOptional<z.ZodString>;
6053
+ search: z.ZodExactOptional<z.ZodString>;
6054
+ }, z.core.$strict>;
6055
+ normalizeTo: z.ZodExactOptional<z.ZodString>;
6056
+ preserveQuery: z.ZodExactOptional<z.ZodLiteral<true>>;
6057
+ preserveConnection: z.ZodExactOptional<z.ZodLiteral<true>>;
6058
+ route: z.ZodExactOptional<z.ZodString>;
6059
+ sourceUrl: z.ZodExactOptional<z.ZodString>;
6060
+ title: z.ZodExactOptional<z.ZodString>;
6061
+ examples: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6062
+ }, z.core.$strict>, z.ZodObject<{
6063
+ kind: z.ZodLiteral<"urlPattern">;
6064
+ pattern: z.ZodObject<{
6065
+ protocol: z.ZodExactOptional<z.ZodString>;
6066
+ hostname: z.ZodExactOptional<z.ZodString>;
6067
+ pathname: z.ZodExactOptional<z.ZodString>;
6068
+ search: z.ZodExactOptional<z.ZodString>;
6069
+ }, z.core.$strict>;
6070
+ normalizeTo: z.ZodExactOptional<z.ZodString>;
6071
+ route: z.ZodExactOptional<z.ZodString>;
6072
+ examples: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6073
+ }, z.core.$strict>], "kind">>>;
6074
+ templates: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
6075
+ uri: z.ZodString;
6076
+ description: z.ZodString;
6077
+ operations: z.ZodExactOptional<z.ZodArray<z.ZodEnum<{
6078
+ search: "search";
6079
+ read: "read";
6080
+ list: "list";
6081
+ write: "write";
6082
+ edit: "edit";
6083
+ delete: "delete";
6084
+ help: "help";
6085
+ }>>>;
6086
+ operationDocs: z.ZodExactOptional<z.ZodRecord<z.ZodEnum<{
6087
+ search: "search";
6088
+ read: "read";
6089
+ list: "list";
6090
+ write: "write";
6091
+ edit: "edit";
6092
+ delete: "delete";
6093
+ help: "help";
6094
+ }> & z.core.$partial, z.ZodString>>;
6095
+ operationDefaults: z.ZodExactOptional<z.ZodRecord<z.ZodEnum<{
6096
+ search: "search";
6097
+ read: "read";
6098
+ list: "list";
6099
+ write: "write";
6100
+ edit: "edit";
6101
+ delete: "delete";
6102
+ help: "help";
6103
+ }> & z.core.$partial, z.ZodEnum<{
6104
+ never: "never";
6105
+ allow: "allow";
6106
+ ask: "ask";
6107
+ }>>>;
6108
+ }, z.core.$strict>>>;
6109
+ verbs: z.ZodExactOptional<z.ZodObject<{
6110
+ readable: z.ZodBoolean;
6111
+ writable: z.ZodBoolean;
6112
+ editable: z.ZodBoolean;
6113
+ deletable: z.ZodExactOptional<z.ZodBoolean>;
6114
+ listable: z.ZodBoolean;
6115
+ searchable: z.ZodExactOptional<z.ZodBoolean>;
6116
+ }, z.core.$strict>>;
6117
+ verbDocs: z.ZodExactOptional<z.ZodObject<{
6118
+ read: z.ZodExactOptional<z.ZodString>;
6119
+ list: z.ZodExactOptional<z.ZodString>;
6120
+ search: z.ZodExactOptional<z.ZodString>;
6121
+ write: z.ZodExactOptional<z.ZodString>;
6122
+ edit: z.ZodExactOptional<z.ZodString>;
6123
+ delete: z.ZodExactOptional<z.ZodString>;
6124
+ }, z.core.$strict>>;
6125
+ permissionDefaults: z.ZodExactOptional<z.ZodObject<{
6126
+ read: z.ZodExactOptional<z.ZodEnum<{
6127
+ never: "never";
6128
+ allow: "allow";
6129
+ ask: "ask";
6130
+ }>>;
6131
+ write: z.ZodExactOptional<z.ZodEnum<{
6132
+ never: "never";
6133
+ allow: "allow";
6134
+ ask: "ask";
6135
+ }>>;
6136
+ edit: z.ZodExactOptional<z.ZodEnum<{
6137
+ never: "never";
6138
+ allow: "allow";
6139
+ ask: "ask";
6140
+ }>>;
6141
+ delete: z.ZodExactOptional<z.ZodEnum<{
6142
+ never: "never";
6143
+ allow: "allow";
6144
+ ask: "ask";
6145
+ }>>;
6146
+ }, z.core.$strict>>;
6147
+ authActions: z.ZodExactOptional<z.ZodObject<{
6148
+ actions: z.ZodRecord<z.ZodString, z.ZodObject<{
6149
+ purpose: z.ZodString;
6150
+ alternatives: z.ZodArray<z.ZodObject<{
6151
+ allOf: z.ZodArray<z.ZodObject<{
6152
+ scope: z.ZodString;
6153
+ reason: z.ZodExactOptional<z.ZodString>;
6154
+ }, z.core.$strict>>;
6155
+ }, z.core.$strict>>;
6156
+ }, z.core.$strict>>;
6157
+ rules: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
6158
+ action: z.ZodString;
6159
+ operations: z.ZodExactOptional<z.ZodArray<z.ZodEnum<{
6160
+ search: "search";
6161
+ read: "read";
6162
+ list: "list";
6163
+ write: "write";
6164
+ edit: "edit";
6165
+ delete: "delete";
6166
+ help: "help";
6167
+ }>>>;
6168
+ routes: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6169
+ query: z.ZodExactOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
6170
+ }, z.core.$strict>, z.ZodObject<{
6171
+ public: z.ZodLiteral<true>;
6172
+ operations: z.ZodExactOptional<z.ZodArray<z.ZodEnum<{
6173
+ search: "search";
6174
+ read: "read";
6175
+ list: "list";
6176
+ write: "write";
6177
+ edit: "edit";
6178
+ delete: "delete";
6179
+ help: "help";
6180
+ }>>>;
6181
+ routes: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6182
+ query: z.ZodExactOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
6183
+ }, z.core.$strict>]>>;
6184
+ }, z.core.$strict>>;
6185
+ requiresConnection: z.ZodExactOptional<z.ZodLiteral<true>>;
6186
+ acceptsSourceCopy: z.ZodExactOptional<z.ZodLiteral<false>>;
6187
+ acceptsWriteSources: z.ZodExactOptional<z.ZodLiteral<true>>;
6188
+ acceptsBytes: z.ZodExactOptional<z.ZodLiteral<true>>;
6189
+ ownsLineSelectors: z.ZodExactOptional<z.ZodLiteral<true>>;
6190
+ description: z.ZodExactOptional<z.ZodString>;
6191
+ agentHint: z.ZodExactOptional<z.ZodObject<{
6192
+ summary: z.ZodString;
6193
+ commonFlows: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
6194
+ label: z.ZodString;
6195
+ when: z.ZodExactOptional<z.ZodString>;
6196
+ example: z.ZodString;
6197
+ }, z.core.$strict>>>;
6198
+ helpUri: z.ZodExactOptional<z.ZodString>;
6199
+ triggers: z.ZodExactOptional<z.ZodObject<{
6200
+ keywords: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6201
+ patterns: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6202
+ }, z.core.$strict>>;
6203
+ skills: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
6204
+ }, z.core.$strict>>;
6205
+ localId: z.ZodString;
6206
+ adapterId: z.ZodOptional<z.ZodString>;
6207
+ globalId: z.ZodString;
6208
+ schemes: z.ZodArray<z.ZodString>;
6209
+ displayName: z.ZodOptional<z.ZodString>;
6210
+ authServiceId: z.ZodOptional<z.ZodString>;
6211
+ authSchemeId: z.ZodOptional<z.ZodString>;
6212
+ requiredScopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
6213
+ knownResources: z.ZodOptional<z.ZodLiteral<true>>;
6214
+ describesOperations: z.ZodOptional<z.ZodLiteral<true>>;
6215
+ looksUpWebLinks: z.ZodOptional<z.ZodLiteral<true>>;
6216
+ }, z.core.$strict>>>;
6000
6217
  kayAppTools: z.ZodOptional<z.ZodArray<z.ZodObject<{
6001
6218
  description: z.ZodOptional<z.ZodString>;
6002
6219
  toolName: z.ZodString;
@@ -6021,6 +6238,9 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
6021
6238
  resourcePrefix: z.ZodOptional<z.ZodString>;
6022
6239
  resourceArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
6023
6240
  resourceTrim: z.ZodOptional<z.ZodLiteral<true>>;
6241
+ resourcePathNormalization: z.ZodOptional<z.ZodObject<{
6242
+ preserveUriSchemes: z.ZodOptional<z.ZodArray<z.ZodString>>;
6243
+ }, z.core.$strict>>;
6024
6244
  defaultPermission: z.ZodOptional<z.ZodEnum<{
6025
6245
  never: "never";
6026
6246
  allow: "allow";
@@ -6044,6 +6264,9 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
6044
6264
  }, z.core.$strict>>>;
6045
6265
  }, z.core.$strict>>;
6046
6266
  globalId: z.ZodString;
6267
+ availability: z.ZodOptional<z.ZodObject<{
6268
+ scope: z.ZodLiteral<"app">;
6269
+ }, z.core.$strict>>;
6047
6270
  }, z.core.$strict>>>;
6048
6271
  kayAppApprovalTypes: z.ZodOptional<z.ZodArray<z.ZodObject<{
6049
6272
  kind: z.ZodLiteral<"message">;
@@ -6404,6 +6627,7 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
6404
6627
  "connect-flows.read": "connect-flows.read";
6405
6628
  "connect-flows.dismiss": "connect-flows.dismiss";
6406
6629
  "support.report": "support.report";
6630
+ "report-evidence.read": "report-evidence.read";
6407
6631
  "navigation.open-page": "navigation.open-page";
6408
6632
  "sessions.create": "sessions.create";
6409
6633
  "models.complete": "models.complete";
@@ -9756,6 +9980,11 @@ declare interface ToolExecutionPolicyDefaults {
9756
9980
  */
9757
9981
  declare type ToolParametersWire = unknown;
9758
9982
 
9983
+ /** Explicit host environment used to expand manifest permission paths. */
9984
+ declare interface ToolPermissionEnvironment {
9985
+ readonly homeDirectory: string;
9986
+ }
9987
+
9759
9988
  /**
9760
9989
  * A tool's own declaration of how a call to it should classify, supplied on the tool
9761
9990
  * definition (the same shape of author-declared, kernel-read fact as `requiresAuth` and
@@ -9779,9 +10008,10 @@ declare interface ToolPermissionHint {
9779
10008
  * labelled facts. Render-only: never matched against a rule, never one-tap approval grounds.
9780
10009
  * The tool says what its input claims, so the gate shows it as the tool's claim, not as the
9781
10010
  * daemon's attestation. The host admits only display-safe text; a throw, a blank title or an
9782
- * unsafe string costs the description and the call is asked about as before.
10011
+ * unsafe string costs the description and the call is asked about as before. A promise is
10012
+ * bounded by the host description timeout; forward its optional cancellation signal to reads.
9783
10013
  */
9784
- readonly describePreview?: (input: Record<string, unknown>) => ToolPreviewDescription | undefined;
10014
+ readonly describePreview?: (input: Record<string, unknown>, signal?: AbortSignal) => ToolPreviewDescription | undefined | Promise<ToolPreviewDescription | undefined>;
9785
10015
  readonly kind?: ToolActionKind;
9786
10016
  readonly scheme?: string;
9787
10017
  readonly ruleKey?: string;
@@ -11625,7 +11855,7 @@ declare interface UriParameter {
11625
11855
  /**
11626
11856
  * A claim on a module's own custom-scheme addresses. The pattern matches with or without an
11627
11857
  * account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
11628
- * back on the official spelling, so one claim covers both spellings.
11858
+ * back on the same-scheme official spelling, so one claim covers both spellings.
11629
11859
  */
11630
11860
  declare interface UriPatternClaim {
11631
11861
  readonly kind: "uriPattern";
@@ -11636,9 +11866,13 @@ declare interface UriPatternClaim {
11636
11866
  * carried over verbatim so a route flag such as `?permanent=true` survives
11637
11867
  * canonicalization (kay#7859); a template that re-targets to another scheme
11638
11868
  * (a projection to a web link) drops it, as does a pattern that consumed the
11639
- * query itself or a template that spells its own.
11869
+ * query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
11640
11870
  */
11641
11871
  readonly normalizeTo?: UriClaimTemplate;
11872
+ /** Carry the matched query verbatim across normalization; incompatible with a target query. */
11873
+ readonly preserveQuery?: true;
11874
+ /** Carry the input's account selector even when normalization changes scheme. */
11875
+ readonly preserveConnection?: true;
11642
11876
  /**
11643
11877
  * Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
11644
11878
  * can say which addresses it means. Several claims may name the same route.
@@ -123,8 +123,12 @@ function createKayPluginLog(write, bound = {}) {
123
123
  }
124
124
 
125
125
  // packages/plugin-sdk/dist/kay-agent/declared-tool.js
126
- function declaredToolPermission(permission) {
127
- const { kind, ruleKey, resourceArgs, scheme, resourcePrefix, resourceTrim, defaultPermission, classificationRules } = permission;
126
+ import { isAbsolute, join, normalize, resolve } from "node:path";
127
+ function declaredToolPermission(permission, environment) {
128
+ const { kind, ruleKey, resourceArgs, scheme, resourcePrefix, resourceTrim, resourcePathNormalization, defaultPermission, classificationRules } = permission;
129
+ if (resourcePathNormalization !== void 0 && environment === void 0) {
130
+ throw new Error("Path-normalized tool resources require a home directory.");
131
+ }
128
132
  return {
129
133
  kind,
130
134
  ...scheme === void 0 ? {} : { scheme },
@@ -145,14 +149,22 @@ function declaredToolPermission(permission) {
145
149
  ...resourceArgs === void 0 ? {} : {
146
150
  deriveResources: (input) => resourceArgs.flatMap((arg) => {
147
151
  const value = input[arg];
148
- return typeof value === "string" ? [
149
- `${resourcePrefix ?? ""}${resourceTrim === true ? value.trim() : value}`
150
- ] : [];
152
+ if (typeof value !== "string")
153
+ return [];
154
+ let resource = resourceTrim === true ? value.trim() : value;
155
+ if (resourcePathNormalization !== void 0 && environment !== void 0) {
156
+ const preserved = resourcePathNormalization.preserveUriSchemes?.some((preservedScheme) => resource.toLowerCase().startsWith(`${preservedScheme.toLowerCase()}://`)) ?? false;
157
+ if (!preserved) {
158
+ const expanded = resource === "~" ? environment.homeDirectory : resource.startsWith("~/") ? join(environment.homeDirectory, resource.slice(2)) : resource;
159
+ resource = isAbsolute(expanded) ? resolve(expanded) : normalize(expanded);
160
+ }
161
+ }
162
+ return [`${resourcePrefix ?? ""}${resource}`];
151
163
  })
152
164
  }
153
165
  };
154
166
  }
155
- function declaredToolDefinition(tool, execute) {
167
+ function declaredToolDefinition(tool, execute, environment) {
156
168
  const { parameters, description, requiresAuth, permission } = tool;
157
169
  if (parameters === void 0 || description === void 0) {
158
170
  throw new Error(`Tool '${tool.toolName}' declares no parameters in kay-plugin.json, so its definition comes from code.`);
@@ -171,7 +183,7 @@ function declaredToolDefinition(tool, execute) {
171
183
  ...requiresAuth.schemeId === void 0 ? {} : { schemeId: requiresAuth.schemeId }
172
184
  }
173
185
  },
174
- ...permission === void 0 ? {} : { permission: declaredToolPermission(permission) },
186
+ ...permission === void 0 ? {} : { permission: declaredToolPermission(permission, environment) },
175
187
  execute
176
188
  };
177
189
  }
@@ -405,12 +417,12 @@ function defaultTestToolContext() {
405
417
  async function invokeToolForTest(tool, params, ctx = defaultTestToolContext()) {
406
418
  return tool.execute("test-call", params, void 0, void 0, ctx);
407
419
  }
408
- function describedToolForTest(contract, localId, execute) {
420
+ function describedToolForTest(contract, localId, execute, environment) {
409
421
  const tool = contract.kayAgentTools?.find((declared) => declared.localId === localId);
410
422
  if (tool === void 0) {
411
423
  throw new Error(`The contract declares no kay.agent tool '${localId}'.`);
412
424
  }
413
- return declaredToolDefinition(tool, execute);
425
+ return declaredToolDefinition(tool, execute, environment);
414
426
  }
415
427
  function producedResourcesForTest(result) {
416
428
  const recorded = recordProducedResources(result.details).details;
@@ -2107,7 +2107,7 @@ export declare type InteractionTarget = ReadonlyContract<InteractionTarget_2>;
2107
2107
 
2108
2108
  /**
2109
2109
  * One thing a driver can be pointed at: a browser page, a running app. `id` is the driver-owned
2110
- * address the agent passes back as `target` (`kay://tabs/.../items/<item>`, `app://<bundle id>`).
2110
+ * address the agent passes back as `target` (`bonsai://tabs/.../items/<item>`, `app://<bundle id>`).
2111
2111
  * `active` marks the default target (the page the user is looking at, the front app).
2112
2112
  */
2113
2113
  declare const InteractionTarget_2: z.ZodObject<{
@@ -3084,8 +3084,14 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
3084
3084
  *
3085
3085
  * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
3086
3086
  * Existing agent and background MCP call shapes remain supported.
3087
+ *
3088
+ * 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
3089
+ * tool previews with cancellation, app-scoped availability snapshots and app-target output
3090
+ * artifact usage declarations. A plugin using these declares ^0.55.1.
3091
+ *
3092
+ * 0.55.2 adds opt-in query and connection-selector preservation during URI claim normalization.
3087
3093
  */
3088
- declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
3094
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.2";
3089
3095
 
3090
3096
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
3091
3097
 
@@ -9805,9 +9811,10 @@ declare interface ToolPermissionHint {
9805
9811
  * labelled facts. Render-only: never matched against a rule, never one-tap approval grounds.
9806
9812
  * The tool says what its input claims, so the gate shows it as the tool's claim, not as the
9807
9813
  * daemon's attestation. The host admits only display-safe text; a throw, a blank title or an
9808
- * unsafe string costs the description and the call is asked about as before.
9814
+ * unsafe string costs the description and the call is asked about as before. A promise is
9815
+ * bounded by the host description timeout; forward its optional cancellation signal to reads.
9809
9816
  */
9810
- readonly describePreview?: (input: Record<string, unknown>) => ToolPreviewDescription | undefined;
9817
+ readonly describePreview?: (input: Record<string, unknown>, signal?: AbortSignal) => ToolPreviewDescription | undefined | Promise<ToolPreviewDescription | undefined>;
9811
9818
  readonly kind?: ToolActionKind;
9812
9819
  readonly scheme?: string;
9813
9820
  readonly ruleKey?: string;
@@ -11748,7 +11755,7 @@ export declare interface UriParameterOptions {
11748
11755
  /**
11749
11756
  * A claim on a module's own custom-scheme addresses. The pattern matches with or without an
11750
11757
  * account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
11751
- * back on the official spelling, so one claim covers both spellings.
11758
+ * back on the same-scheme official spelling, so one claim covers both spellings.
11752
11759
  */
11753
11760
  declare interface UriPatternClaim {
11754
11761
  readonly kind: "uriPattern";
@@ -11759,9 +11766,13 @@ declare interface UriPatternClaim {
11759
11766
  * carried over verbatim so a route flag such as `?permanent=true` survives
11760
11767
  * canonicalization (kay#7859); a template that re-targets to another scheme
11761
11768
  * (a projection to a web link) drops it, as does a pattern that consumed the
11762
- * query itself or a template that spells its own.
11769
+ * query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
11763
11770
  */
11764
11771
  readonly normalizeTo?: UriClaimTemplate;
11772
+ /** Carry the matched query verbatim across normalization; incompatible with a target query. */
11773
+ readonly preserveQuery?: true;
11774
+ /** Carry the input's account selector even when normalization changes scheme. */
11775
+ readonly preserveConnection?: true;
11765
11776
  /**
11766
11777
  * Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
11767
11778
  * can say which addresses it means. Several claims may name the same route.
package/dist/kay-agent.js CHANGED
@@ -37,6 +37,9 @@ function compileClaim(claim) {
37
37
  }
38
38
  };
39
39
  }
40
+ if (claim.kind === "uriPattern" && claim.preserveQuery === true && claim.normalizeTo?.split("#", 1)[0]?.includes("?") === true) {
41
+ throw new Error("URI claim preserveQuery cannot use normalizeTo with a query.");
42
+ }
40
43
  const pattern = compileRoutePattern(claim.pattern);
41
44
  const normalizeTo = claim.normalizeTo === void 0 ? void 0 : compileTemplate(claim.normalizeTo);
42
45
  const sourceUrl = claim.kind === "uriPattern" && claim.sourceUrl !== void 0 ? compileTemplate(claim.sourceUrl) : void 0;
@@ -55,7 +58,7 @@ function compileClaim(claim) {
55
58
  claimKind: claim.kind,
56
59
  ...Object.keys(captures).length > 0 ? { captures } : {},
57
60
  ...normalized !== void 0 ? {
58
- normalizedUri: withSelector(withInputSearch(claim, pattern, parsed, normalized), parsed.protocol, selector)
61
+ normalizedUri: withSelector(withInputSearch(claim, pattern, parsed, normalized), parsed.protocol, selector, claim.kind === "uriPattern" && claim.preserveConnection === true)
59
62
  } : {},
60
63
  ...claim.route !== void 0 ? { route: claim.route } : {},
61
64
  ...filledSourceUrl !== void 0 ? { sourceUrl: filledSourceUrl } : {},
@@ -88,11 +91,13 @@ function parseUriConnectionSelector(input) {
88
91
  }
89
92
  return { selector: match[2], rest: `${match[1]}${match[3] ?? ""}` };
90
93
  }
91
- function withSelector(normalized, inputProtocol, selector) {
94
+ function withSelector(normalized, inputProtocol, selector, preserveConnection) {
92
95
  if (selector === void 0)
93
96
  return normalized;
94
- if (templateProtocol(normalized) !== inputProtocol)
97
+ const targetProtocol = templateProtocol(normalized);
98
+ if (targetProtocol === void 0 || !preserveConnection && targetProtocol !== inputProtocol) {
95
99
  return normalized;
100
+ }
96
101
  const schemeEnd = normalized.indexOf("://") + 3;
97
102
  return `${normalized.slice(0, schemeEnd)}@${selector}/${normalized.slice(schemeEnd)}`;
98
103
  }
@@ -253,7 +258,14 @@ function safeDecode(value) {
253
258
  }
254
259
  }
255
260
  function withInputSearch(claim, pattern, input, normalized) {
256
- if (claim.kind !== "uriPattern" || claim.normalizeTo === void 0 || pattern.search !== void 0 || input.search.length === 0 || claim.normalizeTo.includes("?") || templateProtocol(claim.normalizeTo) !== input.protocol) {
261
+ if (claim.kind !== "uriPattern" || claim.normalizeTo === void 0 || input.search.length === 0) {
262
+ return normalized;
263
+ }
264
+ if (claim.preserveQuery === true) {
265
+ const fragment = normalized.indexOf("#");
266
+ return fragment === -1 ? `${normalized}?${input.search}` : `${normalized.slice(0, fragment)}?${input.search}${normalized.slice(fragment)}`;
267
+ }
268
+ if (pattern.search !== void 0 || claim.normalizeTo.includes("?") || templateProtocol(claim.normalizeTo) !== input.protocol) {
257
269
  return normalized;
258
270
  }
259
271
  return `${normalized}?${input.search}`;
package/dist/kay-app.d.ts CHANGED
@@ -153,6 +153,80 @@ declare const AgentRuntimeAutomationFactSource: z.ZodEnum<{
153
153
 
154
154
  declare type AgentRuntimeAutomationFactSource = z.infer<typeof AgentRuntimeAutomationFactSource>;
155
155
 
156
+ /**
157
+ * The failure record the automation lane mints for a failure it observed itself (domain
158
+ * `automation`). A producer passes `AgentRuntimeAutomationFailureCode`, so an undeclared code
159
+ * fails to compile; the reader takes any `automation.` code, so a stored run still reads after
160
+ * a code is renamed.
161
+ */
162
+ declare type AgentRuntimeAutomationFailure<Code extends string = string> = FailureOccurrence<AgentRuntimeAutomationFailureCause, Code, "automation">;
163
+
164
+ declare const AgentRuntimeAutomationFailure: z.ZodType<AgentRuntimeAutomationFailure>;
165
+
166
+ /**
167
+ * The cause on a failure the automation lane observes itself: the closed facts the daemon saw,
168
+ * keyed by the same `kind` as its `AutomationFailureCause`, plus the engine's own
169
+ * ({@link AgentRuntimeAutomationEngineFailureCause}). No message, stderr, URI or path: these
170
+ * records are exported with the run's log rows. A script's stderr tail stays on the outcome's
171
+ * `message`.
172
+ */
173
+ declare const AgentRuntimeAutomationFailureCause: z.ZodDiscriminatedUnion<[z.ZodObject<{
174
+ kind: z.ZodLiteral<"effect_threw">;
175
+ }, z.core.$strict>, z.ZodObject<{
176
+ kind: z.ZodLiteral<"effect_unsupported">;
177
+ }, z.core.$strict>, z.ZodObject<{
178
+ kind: z.ZodLiteral<"switched_off_across_restart">;
179
+ }, z.core.$strict>, z.ZodObject<{
180
+ kind: z.ZodLiteral<"probe_failed">;
181
+ consecutiveFailures: z.ZodNumber;
182
+ retired: z.ZodBoolean;
183
+ }, z.core.$strict>, z.ZodObject<{
184
+ kind: z.ZodLiteral<"run_start_failed">;
185
+ }, z.core.$strict>, z.ZodObject<{
186
+ kind: z.ZodLiteral<"plugin_revision_moving">;
187
+ }, z.core.$strict>, z.ZodObject<{
188
+ kind: z.ZodLiteral<"owner_unsupported">;
189
+ }, z.core.$strict>, z.ZodObject<{
190
+ kind: z.ZodLiteral<"turn_target_missing">;
191
+ }, z.core.$strict>, z.ZodObject<{
192
+ kind: z.ZodLiteral<"target_missing">;
193
+ }, z.core.$strict>, z.ZodObject<{
194
+ kind: z.ZodLiteral<"declaration_gone">;
195
+ }, z.core.$strict>, z.ZodObject<{
196
+ kind: z.ZodLiteral<"turn_delivery_failed">;
197
+ }, z.core.$strict>, z.ZodObject<{
198
+ kind: z.ZodLiteral<"handler_failed">;
199
+ }, z.core.$strict>, z.ZodObject<{
200
+ kind: z.ZodLiteral<"network_unreachable">;
201
+ }, z.core.$strict>, z.ZodObject<{
202
+ kind: z.ZodLiteral<"script_timed_out">;
203
+ }, z.core.$strict>, z.ZodObject<{
204
+ kind: z.ZodLiteral<"script_cwd_unset">;
205
+ }, z.core.$strict>, z.ZodObject<{
206
+ kind: z.ZodLiteral<"script_result_invalid">;
207
+ }, z.core.$strict>, z.ZodObject<{
208
+ kind: z.ZodLiteral<"script_failed">;
209
+ }, z.core.$strict>, z.ZodObject<{
210
+ kind: z.ZodLiteral<"turn_failed">;
211
+ }, z.core.$strict>, z.ZodObject<{
212
+ kind: z.ZodLiteral<"workflow_failed">;
213
+ }, z.core.$strict>, z.ZodObject<{
214
+ kind: z.ZodLiteral<"surface_unavailable">;
215
+ why: z.ZodEnum<{
216
+ starting: "starting";
217
+ script_unreadable: "script_unreadable";
218
+ }>;
219
+ }, z.core.$strict>, z.ZodObject<{
220
+ kind: z.ZodLiteral<"script_exited">;
221
+ signal: z.ZodNullable<z.ZodString>;
222
+ }, z.core.$strict>, z.ZodObject<{
223
+ kind: z.ZodLiteral<"script_process_error">;
224
+ errorCode: z.ZodOptional<z.ZodString>;
225
+ cwdExists: z.ZodBoolean;
226
+ }, z.core.$strict>], "kind">;
227
+
228
+ declare type AgentRuntimeAutomationFailureCause = z.infer<typeof AgentRuntimeAutomationFailureCause>;
229
+
156
230
  /** One automation run's provenance detail (RFC Release 2). */
157
231
  declare const AgentRuntimeAutomationRunDetail: z.ZodObject<{
158
232
  run: z.ZodObject<{
@@ -324,7 +398,7 @@ declare const AgentRuntimeAutomationRunDetail: z.ZodObject<{
324
398
  retryable: z.ZodBoolean;
325
399
  retryAfterMs: z.ZodOptional<z.ZodNumber>;
326
400
  }, z.core.$strict>>;
327
- failure: z.ZodOptional<z.ZodType<RunFailureOccurrence<string, string>, unknown, z.core.$ZodTypeInternals<RunFailureOccurrence<string, string>, unknown>>>;
401
+ failure: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<RunFailureOccurrence<string, string>, unknown, z.core.$ZodTypeInternals<RunFailureOccurrence<string, string>, unknown>>, z.ZodType<AgentRuntimeAutomationFailure<string>, unknown, z.core.$ZodTypeInternals<AgentRuntimeAutomationFailure<string>, unknown>>]>>;
328
402
  sessionId: z.ZodOptional<z.ZodString>;
329
403
  retryAtMs: z.ZodOptional<z.ZodNumber>;
330
404
  tries: z.ZodOptional<z.ZodNumber>;
@@ -2511,7 +2585,7 @@ declare interface Decision<Q extends DecideQuestions = DecideQuestions> {
2511
2585
  }
2512
2586
 
2513
2587
  /** Builds an app tool from manifest facts, retaining its execution, availability and preview callbacks. */
2514
- export declare function declaredAppToolDefinition(tool: ToolContribution, implementation: KayAppToolImplementation): KayAppToolDefinition;
2588
+ export declare function declaredAppToolDefinition(tool: ToolContribution, implementation: KayAppToolImplementation, environment?: ToolPermissionEnvironment): KayAppToolDefinition;
2515
2589
 
2516
2590
  /** Createsa uni-directional Codec with Decode only. The Decode function is called on Value.Decode */
2517
2591
  declare function Decode<Type extends TSchema, Callback extends TDecodeCallback<StaticDecode<Type>, unknown>>(type: Type, callback: Callback): TCodec<Type, ReturnType<Callback>>;
@@ -4312,8 +4386,14 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
4312
4386
  *
4313
4387
  * 0.55.0 carries managed MCP calls over resource writes in both daemon and plugin-host code.
4314
4388
  * Existing agent and background MCP call shapes remain supported.
4389
+ *
4390
+ * 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
4391
+ * tool previews with cancellation, app-scoped availability snapshots and app-target output
4392
+ * artifact usage declarations. A plugin using these declares ^0.55.1.
4393
+ *
4394
+ * 0.55.2 adds opt-in query and connection-selector preservation during URI claim normalization.
4315
4395
  */
4316
- declare const KAY_PLUGIN_SDK_VERSION: "0.55.0";
4396
+ declare const KAY_PLUGIN_SDK_VERSION: "0.55.2";
4317
4397
 
4318
4398
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
4319
4399
 
@@ -6064,6 +6144,8 @@ export declare interface KayAppKnowledgeSearchOptions {
6064
6144
  readonly limit?: number;
6065
6145
  /** Treat the last query term as a prefix, for search as the person types. */
6066
6146
  readonly prefixLastTerm?: boolean;
6147
+ /** Skip vector eligibility and query embedding; false or absent keeps hybrid search. */
6148
+ readonly lexicalOnly?: boolean;
6067
6149
  /** Drop vector-leg hits below this cosine similarity. */
6068
6150
  readonly minCosineSimilarity?: number;
6069
6151
  /** Relative weights of the lexical and vector legs in rank fusion. */
@@ -15928,6 +16010,9 @@ export declare const ToolContribution: z.ZodObject<{
15928
16010
  resourcePrefix: z.ZodOptional<z.ZodString>;
15929
16011
  resourceArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
15930
16012
  resourceTrim: z.ZodOptional<z.ZodLiteral<true>>;
16013
+ resourcePathNormalization: z.ZodOptional<z.ZodObject<{
16014
+ preserveUriSchemes: z.ZodOptional<z.ZodArray<z.ZodString>>;
16015
+ }, z.core.$strict>>;
15931
16016
  defaultPermission: z.ZodOptional<z.ZodEnum<{
15932
16017
  never: "never";
15933
16018
  allow: "allow";
@@ -15950,6 +16035,9 @@ export declare const ToolContribution: z.ZodObject<{
15950
16035
  ruleKey: z.ZodOptional<z.ZodString>;
15951
16036
  }, z.core.$strict>>>;
15952
16037
  }, z.core.$strict>>;
16038
+ availability: z.ZodOptional<z.ZodObject<{
16039
+ scope: z.ZodLiteral<"app">;
16040
+ }, z.core.$strict>>;
15953
16041
  localId: z.ZodString;
15954
16042
  toolName: z.ZodString;
15955
16043
  displayName: z.ZodOptional<z.ZodString>;
@@ -16076,6 +16164,11 @@ declare interface ToolExecutionPolicyDefaults {
16076
16164
  */
16077
16165
  export declare type ToolParametersWire = unknown;
16078
16166
 
16167
+ /** Explicit host environment used to expand manifest permission paths. */
16168
+ export declare interface ToolPermissionEnvironment {
16169
+ readonly homeDirectory: string;
16170
+ }
16171
+
16079
16172
  /**
16080
16173
  * A tool's own declaration of how a call to it should classify, supplied on the tool
16081
16174
  * definition (the same shape of author-declared, kernel-read fact as `requiresAuth` and
@@ -16099,9 +16192,10 @@ export declare interface ToolPermissionHint {
16099
16192
  * labelled facts. Render-only: never matched against a rule, never one-tap approval grounds.
16100
16193
  * The tool says what its input claims, so the gate shows it as the tool's claim, not as the
16101
16194
  * daemon's attestation. The host admits only display-safe text; a throw, a blank title or an
16102
- * unsafe string costs the description and the call is asked about as before.
16195
+ * unsafe string costs the description and the call is asked about as before. A promise is
16196
+ * bounded by the host description timeout; forward its optional cancellation signal to reads.
16103
16197
  */
16104
- readonly describePreview?: (input: Record<string, unknown>) => ToolPreviewDescription | undefined;
16198
+ readonly describePreview?: (input: Record<string, unknown>, signal?: AbortSignal) => ToolPreviewDescription | undefined | Promise<ToolPreviewDescription | undefined>;
16105
16199
  readonly kind?: ToolActionKind;
16106
16200
  readonly scheme?: string;
16107
16201
  readonly ruleKey?: string;
@@ -18171,7 +18265,7 @@ declare interface UriParameter {
18171
18265
  /**
18172
18266
  * A claim on a module's own custom-scheme addresses. The pattern matches with or without an
18173
18267
  * account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
18174
- * back on the official spelling, so one claim covers both spellings.
18268
+ * back on the same-scheme official spelling, so one claim covers both spellings.
18175
18269
  */
18176
18270
  declare interface UriPatternClaim {
18177
18271
  readonly kind: "uriPattern";
@@ -18182,9 +18276,13 @@ declare interface UriPatternClaim {
18182
18276
  * carried over verbatim so a route flag such as `?permanent=true` survives
18183
18277
  * canonicalization (kay#7859); a template that re-targets to another scheme
18184
18278
  * (a projection to a web link) drops it, as does a pattern that consumed the
18185
- * query itself or a template that spells its own.
18279
+ * query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
18186
18280
  */
18187
18281
  readonly normalizeTo?: UriClaimTemplate;
18282
+ /** Carry the matched query verbatim across normalization; incompatible with a target query. */
18283
+ readonly preserveQuery?: true;
18284
+ /** Carry the input's account selector even when normalization changes scheme. */
18285
+ readonly preserveConnection?: true;
18188
18286
  /**
18189
18287
  * Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
18190
18288
  * can say which addresses it means. Several claims may name the same route.
package/dist/kay-app.js CHANGED
@@ -1007,8 +1007,12 @@ function refusedCountOf(error) {
1007
1007
  }
1008
1008
 
1009
1009
  // packages/plugin-sdk/dist/kay-agent/declared-tool.js
1010
- function declaredToolPermission(permission) {
1011
- const { kind, ruleKey, resourceArgs, scheme, resourcePrefix, resourceTrim, defaultPermission, classificationRules } = permission;
1010
+ import { isAbsolute, join, normalize, resolve } from "node:path";
1011
+ function declaredToolPermission(permission, environment) {
1012
+ const { kind, ruleKey, resourceArgs, scheme, resourcePrefix, resourceTrim, resourcePathNormalization, defaultPermission, classificationRules } = permission;
1013
+ if (resourcePathNormalization !== void 0 && environment === void 0) {
1014
+ throw new Error("Path-normalized tool resources require a home directory.");
1015
+ }
1012
1016
  return {
1013
1017
  kind,
1014
1018
  ...scheme === void 0 ? {} : { scheme },
@@ -1029,16 +1033,24 @@ function declaredToolPermission(permission) {
1029
1033
  ...resourceArgs === void 0 ? {} : {
1030
1034
  deriveResources: (input) => resourceArgs.flatMap((arg) => {
1031
1035
  const value = input[arg];
1032
- return typeof value === "string" ? [
1033
- `${resourcePrefix ?? ""}${resourceTrim === true ? value.trim() : value}`
1034
- ] : [];
1036
+ if (typeof value !== "string")
1037
+ return [];
1038
+ let resource = resourceTrim === true ? value.trim() : value;
1039
+ if (resourcePathNormalization !== void 0 && environment !== void 0) {
1040
+ const preserved = resourcePathNormalization.preserveUriSchemes?.some((preservedScheme) => resource.toLowerCase().startsWith(`${preservedScheme.toLowerCase()}://`)) ?? false;
1041
+ if (!preserved) {
1042
+ const expanded = resource === "~" ? environment.homeDirectory : resource.startsWith("~/") ? join(environment.homeDirectory, resource.slice(2)) : resource;
1043
+ resource = isAbsolute(expanded) ? resolve(expanded) : normalize(expanded);
1044
+ }
1045
+ }
1046
+ return [`${resourcePrefix ?? ""}${resource}`];
1035
1047
  })
1036
1048
  }
1037
1049
  };
1038
1050
  }
1039
1051
 
1040
1052
  // packages/plugin-sdk/dist/kay-app/declared-tool.js
1041
- function declaredAppToolDefinition(tool, implementation) {
1053
+ function declaredAppToolDefinition(tool, implementation, environment) {
1042
1054
  if (tool.parameters === void 0 || tool.description === void 0) {
1043
1055
  throw new Error(`Tool '${tool.toolName}' declares no parameters or description.`);
1044
1056
  }
@@ -1053,7 +1065,7 @@ function declaredAppToolDefinition(tool, implementation) {
1053
1065
  ...tool.promptGuidelines === void 0 ? {} : { promptGuidelines: tool.promptGuidelines },
1054
1066
  ...tool.permission === void 0 ? {} : {
1055
1067
  permission: {
1056
- ...declaredToolPermission(tool.permission),
1068
+ ...declaredToolPermission(tool.permission, environment),
1057
1069
  ...preview?.describePreview === void 0 ? {} : { describePreview: preview.describePreview }
1058
1070
  }
1059
1071
  }
@@ -865,7 +865,7 @@ declare interface UriParameter {
865
865
  /**
866
866
  * A claim on a module's own custom-scheme addresses. The pattern matches with or without an
867
867
  * account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
868
- * back on the official spelling, so one claim covers both spellings.
868
+ * back on the same-scheme official spelling, so one claim covers both spellings.
869
869
  */
870
870
  declare interface UriPatternClaim {
871
871
  readonly kind: "uriPattern";
@@ -876,9 +876,13 @@ declare interface UriPatternClaim {
876
876
  * carried over verbatim so a route flag such as `?permanent=true` survives
877
877
  * canonicalization (kay#7859); a template that re-targets to another scheme
878
878
  * (a projection to a web link) drops it, as does a pattern that consumed the
879
- * query itself or a template that spells its own.
879
+ * query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
880
880
  */
881
881
  readonly normalizeTo?: UriClaimTemplate;
882
+ /** Carry the matched query verbatim across normalization; incompatible with a target query. */
883
+ readonly preserveQuery?: true;
884
+ /** Carry the input's account selector even when normalization changes scheme. */
885
+ readonly preserveConnection?: true;
882
886
  /**
883
887
  * Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
884
888
  * can say which addresses it means. Several claims may name the same route.
@@ -91,6 +91,9 @@ function compileClaim(claim) {
91
91
  }
92
92
  };
93
93
  }
94
+ if (claim.kind === "uriPattern" && claim.preserveQuery === true && claim.normalizeTo?.split("#", 1)[0]?.includes("?") === true) {
95
+ throw new Error("URI claim preserveQuery cannot use normalizeTo with a query.");
96
+ }
94
97
  const pattern = compileRoutePattern(claim.pattern);
95
98
  const normalizeTo = claim.normalizeTo === void 0 ? void 0 : compileTemplate(claim.normalizeTo);
96
99
  const sourceUrl = claim.kind === "uriPattern" && claim.sourceUrl !== void 0 ? compileTemplate(claim.sourceUrl) : void 0;
@@ -109,7 +112,7 @@ function compileClaim(claim) {
109
112
  claimKind: claim.kind,
110
113
  ...Object.keys(captures).length > 0 ? { captures } : {},
111
114
  ...normalized !== void 0 ? {
112
- normalizedUri: withSelector(withInputSearch(claim, pattern, parsed, normalized), parsed.protocol, selector)
115
+ normalizedUri: withSelector(withInputSearch(claim, pattern, parsed, normalized), parsed.protocol, selector, claim.kind === "uriPattern" && claim.preserveConnection === true)
113
116
  } : {},
114
117
  ...claim.route !== void 0 ? { route: claim.route } : {},
115
118
  ...filledSourceUrl !== void 0 ? { sourceUrl: filledSourceUrl } : {},
@@ -142,11 +145,13 @@ function parseUriConnectionSelector(input) {
142
145
  }
143
146
  return { selector: match[2], rest: `${match[1]}${match[3] ?? ""}` };
144
147
  }
145
- function withSelector(normalized, inputProtocol, selector) {
148
+ function withSelector(normalized, inputProtocol, selector, preserveConnection) {
146
149
  if (selector === void 0)
147
150
  return normalized;
148
- if (templateProtocol(normalized) !== inputProtocol)
151
+ const targetProtocol = templateProtocol(normalized);
152
+ if (targetProtocol === void 0 || !preserveConnection && targetProtocol !== inputProtocol) {
149
153
  return normalized;
154
+ }
150
155
  const schemeEnd = normalized.indexOf("://") + 3;
151
156
  return `${normalized.slice(0, schemeEnd)}@${selector}/${normalized.slice(schemeEnd)}`;
152
157
  }
@@ -307,7 +312,14 @@ function safeDecode(value) {
307
312
  }
308
313
  }
309
314
  function withInputSearch(claim, pattern, input, normalized) {
310
- if (claim.kind !== "uriPattern" || claim.normalizeTo === void 0 || pattern.search !== void 0 || input.search.length === 0 || claim.normalizeTo.includes("?") || templateProtocol(claim.normalizeTo) !== input.protocol) {
315
+ if (claim.kind !== "uriPattern" || claim.normalizeTo === void 0 || input.search.length === 0) {
316
+ return normalized;
317
+ }
318
+ if (claim.preserveQuery === true) {
319
+ const fragment = normalized.indexOf("#");
320
+ return fragment === -1 ? `${normalized}?${input.search}` : `${normalized.slice(0, fragment)}?${input.search}${normalized.slice(fragment)}`;
321
+ }
322
+ if (pattern.search !== void 0 || claim.normalizeTo.includes("?") || templateProtocol(claim.normalizeTo) !== input.protocol) {
311
323
  return normalized;
312
324
  }
313
325
  return `${normalized}?${input.search}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaklabs-ai/plugin-sdk",
3
- "version": "0.55.0",
3
+ "version": "0.55.2",
4
4
  "description": "The Kay plugin SDK — types and helpers for authoring a Kay directory plugin.",
5
5
  "author": "YakLabs",
6
6
  "type": "module",