@yaklabs-ai/plugin-sdk 0.55.1 → 0.55.3
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 +5 -5
- package/THIRD-PARTY-INVENTORY.json +1 -1
- package/dist/disclosure.d.ts +15 -4
- package/dist/kay-agent-testing.d.ts +19 -4
- package/dist/kay-agent.d.ts +15 -4
- package/dist/kay-agent.js +16 -4
- package/dist/kay-app-session-summary.d.ts +8 -0
- package/dist/kay-app.d.ts +134 -10
- package/dist/kay-app.js +2 -0
- package/dist/vendored-mcp.d.ts +6 -2
- package/dist/vendored-mcp.js +16 -4
- package/package.json +1 -1
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.
|
|
16
|
+
"@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.55.3"
|
|
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.
|
|
65
|
+
"compatibility": { "sdk": "^0.55.3" },
|
|
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.
|
|
156
|
+
A plugin that imports these subpaths declares the current supported SDK range (`^0.55.3`).
|
|
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.
|
|
164
|
+
`VendoredMcpPort` and `VendoredMcpOutcome` (declare `^0.55.3`).
|
|
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.
|
|
246
|
+
refused; migrate and declare `^0.55.3`. 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
|
|
package/dist/disclosure.d.ts
CHANGED
|
@@ -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` (`
|
|
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<{
|
|
@@ -2680,8 +2680,15 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
|
|
|
2680
2680
|
* 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
|
|
2681
2681
|
* tool previews with cancellation, app-scoped availability snapshots and app-target output
|
|
2682
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.
|
|
2685
|
+
*
|
|
2686
|
+
* 0.55.3 lets a signal carry the item's own text. `PluginSignal` gains an optional `body`: plain
|
|
2687
|
+
* text, at most `PLUGIN_SIGNAL_BODY_MAX` (20,000) characters. Gmail puts a mail's text there, so
|
|
2688
|
+
* Flows can keep the messages a task came from. Additive: a plugin that publishes a body declares
|
|
2689
|
+
* ^0.55.3.
|
|
2683
2690
|
*/
|
|
2684
|
-
declare const KAY_PLUGIN_SDK_VERSION: "0.55.
|
|
2691
|
+
declare const KAY_PLUGIN_SDK_VERSION: "0.55.3";
|
|
2685
2692
|
|
|
2686
2693
|
declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
|
|
2687
2694
|
|
|
@@ -10225,7 +10232,7 @@ declare interface UriParameter {
|
|
|
10225
10232
|
/**
|
|
10226
10233
|
* A claim on a module's own custom-scheme addresses. The pattern matches with or without an
|
|
10227
10234
|
* account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
|
|
10228
|
-
* back on the official spelling, so one claim covers both spellings.
|
|
10235
|
+
* back on the same-scheme official spelling, so one claim covers both spellings.
|
|
10229
10236
|
*/
|
|
10230
10237
|
declare interface UriPatternClaim {
|
|
10231
10238
|
readonly kind: "uriPattern";
|
|
@@ -10236,9 +10243,13 @@ declare interface UriPatternClaim {
|
|
|
10236
10243
|
* carried over verbatim so a route flag such as `?permanent=true` survives
|
|
10237
10244
|
* canonicalization (kay#7859); a template that re-targets to another scheme
|
|
10238
10245
|
* (a projection to a web link) drops it, as does a pattern that consumed the
|
|
10239
|
-
* query itself or a template that spells its own.
|
|
10246
|
+
* query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
|
|
10240
10247
|
*/
|
|
10241
10248
|
readonly normalizeTo?: UriClaimTemplate;
|
|
10249
|
+
/** Carry the matched query verbatim across normalization; incompatible with a target query. */
|
|
10250
|
+
readonly preserveQuery?: true;
|
|
10251
|
+
/** Carry the input's account selector even when normalization changes scheme. */
|
|
10252
|
+
readonly preserveConnection?: true;
|
|
10242
10253
|
/**
|
|
10243
10254
|
* Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
|
|
10244
10255
|
* can say which addresses it means. Several claims may name the same route.
|
|
@@ -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` (`
|
|
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<{
|
|
@@ -2734,8 +2734,15 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
|
|
|
2734
2734
|
* 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
|
|
2735
2735
|
* tool previews with cancellation, app-scoped availability snapshots and app-target output
|
|
2736
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.
|
|
2739
|
+
*
|
|
2740
|
+
* 0.55.3 lets a signal carry the item's own text. `PluginSignal` gains an optional `body`: plain
|
|
2741
|
+
* text, at most `PLUGIN_SIGNAL_BODY_MAX` (20,000) characters. Gmail puts a mail's text there, so
|
|
2742
|
+
* Flows can keep the messages a task came from. Additive: a plugin that publishes a body declares
|
|
2743
|
+
* ^0.55.3.
|
|
2737
2744
|
*/
|
|
2738
|
-
declare const KAY_PLUGIN_SDK_VERSION: "0.55.
|
|
2745
|
+
declare const KAY_PLUGIN_SDK_VERSION: "0.55.3";
|
|
2739
2746
|
|
|
2740
2747
|
declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
|
|
2741
2748
|
|
|
@@ -5763,6 +5770,8 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
|
|
|
5763
5770
|
search: z.ZodExactOptional<z.ZodString>;
|
|
5764
5771
|
}, z.core.$strict>;
|
|
5765
5772
|
normalizeTo: z.ZodExactOptional<z.ZodString>;
|
|
5773
|
+
preserveQuery: z.ZodExactOptional<z.ZodLiteral<true>>;
|
|
5774
|
+
preserveConnection: z.ZodExactOptional<z.ZodLiteral<true>>;
|
|
5766
5775
|
route: z.ZodExactOptional<z.ZodString>;
|
|
5767
5776
|
sourceUrl: z.ZodExactOptional<z.ZodString>;
|
|
5768
5777
|
title: z.ZodExactOptional<z.ZodString>;
|
|
@@ -6049,6 +6058,8 @@ declare const ResolvedPluginContractV1: z.ZodObject<{
|
|
|
6049
6058
|
search: z.ZodExactOptional<z.ZodString>;
|
|
6050
6059
|
}, z.core.$strict>;
|
|
6051
6060
|
normalizeTo: z.ZodExactOptional<z.ZodString>;
|
|
6061
|
+
preserveQuery: z.ZodExactOptional<z.ZodLiteral<true>>;
|
|
6062
|
+
preserveConnection: z.ZodExactOptional<z.ZodLiteral<true>>;
|
|
6052
6063
|
route: z.ZodExactOptional<z.ZodString>;
|
|
6053
6064
|
sourceUrl: z.ZodExactOptional<z.ZodString>;
|
|
6054
6065
|
title: z.ZodExactOptional<z.ZodString>;
|
|
@@ -11849,7 +11860,7 @@ declare interface UriParameter {
|
|
|
11849
11860
|
/**
|
|
11850
11861
|
* A claim on a module's own custom-scheme addresses. The pattern matches with or without an
|
|
11851
11862
|
* account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
|
|
11852
|
-
* back on the official spelling, so one claim covers both spellings.
|
|
11863
|
+
* back on the same-scheme official spelling, so one claim covers both spellings.
|
|
11853
11864
|
*/
|
|
11854
11865
|
declare interface UriPatternClaim {
|
|
11855
11866
|
readonly kind: "uriPattern";
|
|
@@ -11860,9 +11871,13 @@ declare interface UriPatternClaim {
|
|
|
11860
11871
|
* carried over verbatim so a route flag such as `?permanent=true` survives
|
|
11861
11872
|
* canonicalization (kay#7859); a template that re-targets to another scheme
|
|
11862
11873
|
* (a projection to a web link) drops it, as does a pattern that consumed the
|
|
11863
|
-
* query itself or a template that spells its own.
|
|
11874
|
+
* query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
|
|
11864
11875
|
*/
|
|
11865
11876
|
readonly normalizeTo?: UriClaimTemplate;
|
|
11877
|
+
/** Carry the matched query verbatim across normalization; incompatible with a target query. */
|
|
11878
|
+
readonly preserveQuery?: true;
|
|
11879
|
+
/** Carry the input's account selector even when normalization changes scheme. */
|
|
11880
|
+
readonly preserveConnection?: true;
|
|
11866
11881
|
/**
|
|
11867
11882
|
* Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
|
|
11868
11883
|
* can say which addresses it means. Several claims may name the same route.
|
package/dist/kay-agent.d.ts
CHANGED
|
@@ -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` (`
|
|
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<{
|
|
@@ -3088,8 +3088,15 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
|
|
|
3088
3088
|
* 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
|
|
3089
3089
|
* tool previews with cancellation, app-scoped availability snapshots and app-target output
|
|
3090
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.
|
|
3093
|
+
*
|
|
3094
|
+
* 0.55.3 lets a signal carry the item's own text. `PluginSignal` gains an optional `body`: plain
|
|
3095
|
+
* text, at most `PLUGIN_SIGNAL_BODY_MAX` (20,000) characters. Gmail puts a mail's text there, so
|
|
3096
|
+
* Flows can keep the messages a task came from. Additive: a plugin that publishes a body declares
|
|
3097
|
+
* ^0.55.3.
|
|
3091
3098
|
*/
|
|
3092
|
-
declare const KAY_PLUGIN_SDK_VERSION: "0.55.
|
|
3099
|
+
declare const KAY_PLUGIN_SDK_VERSION: "0.55.3";
|
|
3093
3100
|
|
|
3094
3101
|
declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
|
|
3095
3102
|
|
|
@@ -11753,7 +11760,7 @@ export declare interface UriParameterOptions {
|
|
|
11753
11760
|
/**
|
|
11754
11761
|
* A claim on a module's own custom-scheme addresses. The pattern matches with or without an
|
|
11755
11762
|
* account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
|
|
11756
|
-
* back on the official spelling, so one claim covers both spellings.
|
|
11763
|
+
* back on the same-scheme official spelling, so one claim covers both spellings.
|
|
11757
11764
|
*/
|
|
11758
11765
|
declare interface UriPatternClaim {
|
|
11759
11766
|
readonly kind: "uriPattern";
|
|
@@ -11764,9 +11771,13 @@ declare interface UriPatternClaim {
|
|
|
11764
11771
|
* carried over verbatim so a route flag such as `?permanent=true` survives
|
|
11765
11772
|
* canonicalization (kay#7859); a template that re-targets to another scheme
|
|
11766
11773
|
* (a projection to a web link) drops it, as does a pattern that consumed the
|
|
11767
|
-
* query itself or a template that spells its own.
|
|
11774
|
+
* query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
|
|
11768
11775
|
*/
|
|
11769
11776
|
readonly normalizeTo?: UriClaimTemplate;
|
|
11777
|
+
/** Carry the matched query verbatim across normalization; incompatible with a target query. */
|
|
11778
|
+
readonly preserveQuery?: true;
|
|
11779
|
+
/** Carry the input's account selector even when normalization changes scheme. */
|
|
11780
|
+
readonly preserveConnection?: true;
|
|
11770
11781
|
/**
|
|
11771
11782
|
* Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
|
|
11772
11783
|
* 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
|
-
|
|
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 ||
|
|
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}`;
|
|
@@ -2230,6 +2230,14 @@ declare interface KayAppSessions {
|
|
|
2230
2230
|
* against `sessions.read`. Unsupported hosts may omit it.
|
|
2231
2231
|
*/
|
|
2232
2232
|
listSessionPage?(request: KayAppSessionListRequest): Promise<KayAppSessionList>;
|
|
2233
|
+
/**
|
|
2234
|
+
* Called after a stored session's index row changes (its title, folder or project, or its
|
|
2235
|
+
* removal); a change without `sessionId` means any session may have changed. Checked against
|
|
2236
|
+
* `sessions.read`. Returns the unsubscribe. Unsupported hosts may omit it.
|
|
2237
|
+
*/
|
|
2238
|
+
subscribeChanges?(listener: (change: {
|
|
2239
|
+
readonly sessionId?: string;
|
|
2240
|
+
}) => void): () => void;
|
|
2233
2241
|
/**
|
|
2234
2242
|
* Read a cheap transcript change marker without loading the entry log. Unknown or deleted
|
|
2235
2243
|
* sessions yield `undefined`.
|
package/dist/kay-app.d.ts
CHANGED
|
@@ -4390,8 +4390,15 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
|
|
|
4390
4390
|
* 0.55.1 adds canonical path resources on declared tool permissions, asynchronous display-only
|
|
4391
4391
|
* tool previews with cancellation, app-scoped availability snapshots and app-target output
|
|
4392
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.
|
|
4395
|
+
*
|
|
4396
|
+
* 0.55.3 lets a signal carry the item's own text. `PluginSignal` gains an optional `body`: plain
|
|
4397
|
+
* text, at most `PLUGIN_SIGNAL_BODY_MAX` (20,000) characters. Gmail puts a mail's text there, so
|
|
4398
|
+
* Flows can keep the messages a task came from. Additive: a plugin that publishes a body declares
|
|
4399
|
+
* ^0.55.3.
|
|
4393
4400
|
*/
|
|
4394
|
-
declare const KAY_PLUGIN_SDK_VERSION: "0.55.
|
|
4401
|
+
declare const KAY_PLUGIN_SDK_VERSION: "0.55.3";
|
|
4395
4402
|
|
|
4396
4403
|
declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
|
|
4397
4404
|
|
|
@@ -6142,6 +6149,8 @@ export declare interface KayAppKnowledgeSearchOptions {
|
|
|
6142
6149
|
readonly limit?: number;
|
|
6143
6150
|
/** Treat the last query term as a prefix, for search as the person types. */
|
|
6144
6151
|
readonly prefixLastTerm?: boolean;
|
|
6152
|
+
/** Skip vector eligibility and query embedding; false or absent keeps hybrid search. */
|
|
6153
|
+
readonly lexicalOnly?: boolean;
|
|
6145
6154
|
/** Drop vector-leg hits below this cosine similarity. */
|
|
6146
6155
|
readonly minCosineSimilarity?: number;
|
|
6147
6156
|
/** Relative weights of the lexical and vector legs in rank fusion. */
|
|
@@ -6977,8 +6986,19 @@ export declare interface KayAppPluginApi {
|
|
|
6977
6986
|
implementWorkflow(localId: string, run: KayAppWorkflowImplementation): void;
|
|
6978
6987
|
}
|
|
6979
6988
|
|
|
6989
|
+
/** What `kay.app` code may add to one publish beyond the event itself. */
|
|
6990
|
+
export declare interface KayAppPluginEventPublishOptions {
|
|
6991
|
+
/**
|
|
6992
|
+
* A session this plugin created through `sessions.create`: the host records it as the event's
|
|
6993
|
+
* session, so a notification rule's `session-unfocused` stays quiet while that session is the
|
|
6994
|
+
* focused pane. The host refuses a session this plugin did not create. Absent publishes an
|
|
6995
|
+
* app-lifetime event, as before.
|
|
6996
|
+
*/
|
|
6997
|
+
readonly sessionId?: string;
|
|
6998
|
+
}
|
|
6999
|
+
|
|
6980
7000
|
export declare interface KayAppPluginEvents {
|
|
6981
|
-
publish(localId: string, input: PluginEventPublishInput): void;
|
|
7001
|
+
publish(localId: string, input: PluginEventPublishInput, options?: KayAppPluginEventPublishOptions): void;
|
|
6982
7002
|
}
|
|
6983
7003
|
|
|
6984
7004
|
/**
|
|
@@ -7923,6 +7943,14 @@ export declare interface KayAppSessions {
|
|
|
7923
7943
|
* against `sessions.read`. Unsupported hosts may omit it.
|
|
7924
7944
|
*/
|
|
7925
7945
|
listSessionPage?(request: KayAppSessionListRequest): Promise<KayAppSessionList>;
|
|
7946
|
+
/**
|
|
7947
|
+
* Called after a stored session's index row changes (its title, folder or project, or its
|
|
7948
|
+
* removal); a change without `sessionId` means any session may have changed. Checked against
|
|
7949
|
+
* `sessions.read`. Returns the unsubscribe. Unsupported hosts may omit it.
|
|
7950
|
+
*/
|
|
7951
|
+
subscribeChanges?(listener: (change: {
|
|
7952
|
+
readonly sessionId?: string;
|
|
7953
|
+
}) => void): () => void;
|
|
7926
7954
|
/**
|
|
7927
7955
|
* Read a cheap transcript change marker without loading the entry log. Unknown or deleted
|
|
7928
7956
|
* sessions yield `undefined`.
|
|
@@ -10051,13 +10079,20 @@ export declare interface KayAppWorkingDocuments {
|
|
|
10051
10079
|
* recovery data.
|
|
10052
10080
|
*/
|
|
10053
10081
|
export declare interface KayAppWorkspace {
|
|
10082
|
+
/**
|
|
10083
|
+
* Called after the window publishes a new snapshot (tabs, groups, panes or titles changed). Read
|
|
10084
|
+
* `snapshot()` for the new state. Returns the unsubscribe.
|
|
10085
|
+
*/
|
|
10086
|
+
subscribe(listener: () => void): () => void;
|
|
10054
10087
|
snapshot(): Promise<{
|
|
10055
10088
|
readonly kind: "snapshot";
|
|
10056
10089
|
readonly snapshot: KayAppWorkspaceSnapshot;
|
|
10057
10090
|
} | {
|
|
10058
10091
|
readonly kind: "unavailable";
|
|
10059
10092
|
}>;
|
|
10060
|
-
execute(command: KayAppWorkspaceCommand,
|
|
10093
|
+
execute(command: KayAppWorkspaceCommand,
|
|
10094
|
+
/** The session the command is issued for; absent for a plugin's own background work. */
|
|
10095
|
+
ctx?: KayAppWorkspaceExecuteContext): Promise<{
|
|
10061
10096
|
readonly kind: "outcome";
|
|
10062
10097
|
readonly outcome: KayAppWorkspaceCommandOutcome;
|
|
10063
10098
|
readonly validPageIds?: readonly string[];
|
|
@@ -10101,6 +10136,23 @@ export declare type KayAppWorkspaceCommand = {
|
|
|
10101
10136
|
} | {
|
|
10102
10137
|
verb: "tabs.ungroup";
|
|
10103
10138
|
tabIds: readonly string[];
|
|
10139
|
+
} | {
|
|
10140
|
+
/**
|
|
10141
|
+
* Set the membership and look of this plugin's own linked tab groups, computed from the
|
|
10142
|
+
* snapshot numbered `rev` (`stale` when the tabs changed since). Each listed group ends up
|
|
10143
|
+
* holding exactly `tabIds` plus its guests, created when missing; only ungrouped Tabs join.
|
|
10144
|
+
* One of this plugin's groups left unlisted keeps only its guests. Never recorded as the
|
|
10145
|
+
* person's own edit.
|
|
10146
|
+
*/
|
|
10147
|
+
verb: "tabs.syncLinkedGroups";
|
|
10148
|
+
rev: number;
|
|
10149
|
+
groups: readonly {
|
|
10150
|
+
readonly key: string;
|
|
10151
|
+
readonly name: string;
|
|
10152
|
+
readonly color?: KayAppWorkspaceTabGroupColor | undefined;
|
|
10153
|
+
readonly icon?: string | undefined;
|
|
10154
|
+
readonly tabIds: readonly string[];
|
|
10155
|
+
}[];
|
|
10104
10156
|
} | {
|
|
10105
10157
|
verb: "panes.split";
|
|
10106
10158
|
tabId: string;
|
|
@@ -10259,15 +10311,21 @@ export declare type KayAppWorkspacePlaceContent = {
|
|
|
10259
10311
|
};
|
|
10260
10312
|
|
|
10261
10313
|
/** The full workspace tree, app-wide (every tab, not one session's). */
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10314
|
+
/**
|
|
10315
|
+
* The workspace as the window last published it: every Tab, the tab groups (`link` present only on
|
|
10316
|
+
* a linked tab group), and the person's linked-group guests and dismissals in this window.
|
|
10317
|
+
*/
|
|
10318
|
+
export declare type KayAppWorkspaceSnapshot = ReadonlyContract<WorkspaceSnapshot>;
|
|
10267
10319
|
|
|
10268
10320
|
/** The tab-group colour palette, by name (Chrome's nine); mirrors the wire schema's enum. */
|
|
10269
10321
|
export declare type KayAppWorkspaceTabGroupColor = "grey" | "blue" | "red" | "yellow" | "green" | "pink" | "purple" | "cyan" | "orange";
|
|
10270
10322
|
|
|
10323
|
+
/** The plugin a linked tab group belongs to and the key that plugin chose for it. */
|
|
10324
|
+
export declare type KayAppWorkspaceTabGroupLink = NonNullable<KayAppWorkspaceTabGroupSnapshot["link"]>;
|
|
10325
|
+
|
|
10326
|
+
/** One tab group in the strip. */
|
|
10327
|
+
export declare type KayAppWorkspaceTabGroupSnapshot = NonNullable<KayAppWorkspaceSnapshot["groups"]>[number];
|
|
10328
|
+
|
|
10271
10329
|
export declare type KayAppWorkspaceTabSnapshot = ReadonlyContract<WorkspaceTabSnapshot>;
|
|
10272
10330
|
|
|
10273
10331
|
/**
|
|
@@ -11530,6 +11588,12 @@ export declare const PLUGIN_SIGNAL_ATTACHMENT_TYPE_MAX = 127;
|
|
|
11530
11588
|
/** At most this many entries in a signal's `attachments`; a source lists the first ones. */
|
|
11531
11589
|
export declare const PLUGIN_SIGNAL_ATTACHMENTS_MAX = 10;
|
|
11532
11590
|
|
|
11591
|
+
/**
|
|
11592
|
+
* A signal's `body`, the item's own text, at most this many characters: a source cuts longer text
|
|
11593
|
+
* and marks the cut. Enough for a long email with its quoted history.
|
|
11594
|
+
*/
|
|
11595
|
+
export declare const PLUGIN_SIGNAL_BODY_MAX = 20000;
|
|
11596
|
+
|
|
11533
11597
|
/** The `kind` values of `PluginSignal` v1. `status` is system state that clears itself. */
|
|
11534
11598
|
export declare const PLUGIN_SIGNAL_KINDS: readonly ["message", "request", "mention", "invite", "status"];
|
|
11535
11599
|
|
|
@@ -11711,6 +11775,7 @@ export declare const PluginSignal: z.ZodObject<{
|
|
|
11711
11775
|
}>>;
|
|
11712
11776
|
title: z.ZodOptional<z.ZodString>;
|
|
11713
11777
|
snippet: z.ZodOptional<z.ZodString>;
|
|
11778
|
+
body: z.ZodOptional<z.ZodString>;
|
|
11714
11779
|
actor: z.ZodOptional<z.ZodObject<{
|
|
11715
11780
|
name: z.ZodOptional<z.ZodString>;
|
|
11716
11781
|
uri: z.ZodString;
|
|
@@ -11755,6 +11820,7 @@ export declare const PluginSignalPublish: z.ZodObject<{
|
|
|
11755
11820
|
}>>;
|
|
11756
11821
|
title: z.ZodOptional<z.ZodString>;
|
|
11757
11822
|
snippet: z.ZodOptional<z.ZodString>;
|
|
11823
|
+
body: z.ZodOptional<z.ZodString>;
|
|
11758
11824
|
actor: z.ZodOptional<z.ZodObject<{
|
|
11759
11825
|
name: z.ZodOptional<z.ZodString>;
|
|
11760
11826
|
uri: z.ZodString;
|
|
@@ -18261,7 +18327,7 @@ declare interface UriParameter {
|
|
|
18261
18327
|
/**
|
|
18262
18328
|
* A claim on a module's own custom-scheme addresses. The pattern matches with or without an
|
|
18263
18329
|
* account prefix: `gcal://@work/events/x` is matched as `gcal://events/x`, and the prefix is put
|
|
18264
|
-
* back on the official spelling, so one claim covers both spellings.
|
|
18330
|
+
* back on the same-scheme official spelling, so one claim covers both spellings.
|
|
18265
18331
|
*/
|
|
18266
18332
|
declare interface UriPatternClaim {
|
|
18267
18333
|
readonly kind: "uriPattern";
|
|
@@ -18272,9 +18338,13 @@ declare interface UriPatternClaim {
|
|
|
18272
18338
|
* carried over verbatim so a route flag such as `?permanent=true` survives
|
|
18273
18339
|
* canonicalization (kay#7859); a template that re-targets to another scheme
|
|
18274
18340
|
* (a projection to a web link) drops it, as does a pattern that consumed the
|
|
18275
|
-
* query itself or a template that spells its own.
|
|
18341
|
+
* query itself or a template that spells its own. `preserveQuery` opts out of those defaults.
|
|
18276
18342
|
*/
|
|
18277
18343
|
readonly normalizeTo?: UriClaimTemplate;
|
|
18344
|
+
/** Carry the matched query verbatim across normalization; incompatible with a target query. */
|
|
18345
|
+
readonly preserveQuery?: true;
|
|
18346
|
+
/** Carry the input's account selector even when normalization changes scheme. */
|
|
18347
|
+
readonly preserveConnection?: true;
|
|
18278
18348
|
/**
|
|
18279
18349
|
* Names the route this claim matches, so data keyed by route (a module's sign-in action rules)
|
|
18280
18350
|
* can say which addresses it means. Several claims may name the same route.
|
|
@@ -19162,6 +19232,7 @@ declare const WorkspaceCommandOutcome: z.ZodEnum<{
|
|
|
19162
19232
|
"no-window": "no-window";
|
|
19163
19233
|
"not-found": "not-found";
|
|
19164
19234
|
applied: "applied";
|
|
19235
|
+
stale: "stale";
|
|
19165
19236
|
}>;
|
|
19166
19237
|
|
|
19167
19238
|
declare type WorkspaceCommandOutcome = z.infer<typeof WorkspaceCommandOutcome>;
|
|
@@ -19214,11 +19285,64 @@ declare type WorkspacePaneNode = {
|
|
|
19214
19285
|
|
|
19215
19286
|
declare const WorkspacePaneNode: z.ZodType<WorkspacePaneNode>;
|
|
19216
19287
|
|
|
19288
|
+
/**
|
|
19289
|
+
* The full workspace tree, app-wide (every tab, not one session's). `rev` is a monotonic counter the
|
|
19290
|
+
* renderer stamps on push (mirroring the `<kay_tab_context>` block's `rev`), so a reader can tell a
|
|
19291
|
+
* pulled snapshot apart from one already in hand.
|
|
19292
|
+
*/
|
|
19293
|
+
declare const WorkspaceSnapshot: z.ZodObject<{
|
|
19294
|
+
rev: z.ZodNumber;
|
|
19295
|
+
activeTabId: z.ZodString;
|
|
19296
|
+
tabs: z.ZodArray<z.ZodObject<{
|
|
19297
|
+
id: z.ZodString;
|
|
19298
|
+
label: z.ZodString;
|
|
19299
|
+
active: z.ZodBoolean;
|
|
19300
|
+
variable: z.ZodOptional<z.ZodBoolean>;
|
|
19301
|
+
preview: z.ZodOptional<z.ZodBoolean>;
|
|
19302
|
+
groupId: z.ZodOptional<z.ZodString>;
|
|
19303
|
+
sessionIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
19304
|
+
focusedPaneId: z.ZodString;
|
|
19305
|
+
maximizedPaneId: z.ZodNullable<z.ZodString>;
|
|
19306
|
+
root: z.ZodType<WorkspacePaneNode, unknown, z.core.$ZodTypeInternals<WorkspacePaneNode, unknown>>;
|
|
19307
|
+
}, z.core.$strict>>;
|
|
19308
|
+
groups: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
19309
|
+
id: z.ZodString;
|
|
19310
|
+
name: z.ZodString;
|
|
19311
|
+
color: z.ZodEnum<{
|
|
19312
|
+
grey: "grey";
|
|
19313
|
+
blue: "blue";
|
|
19314
|
+
red: "red";
|
|
19315
|
+
yellow: "yellow";
|
|
19316
|
+
green: "green";
|
|
19317
|
+
pink: "pink";
|
|
19318
|
+
purple: "purple";
|
|
19319
|
+
cyan: "cyan";
|
|
19320
|
+
orange: "orange";
|
|
19321
|
+
}>;
|
|
19322
|
+
collapsed: z.ZodOptional<z.ZodBoolean>;
|
|
19323
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
19324
|
+
link: z.ZodOptional<z.ZodObject<{
|
|
19325
|
+
pluginId: z.ZodString;
|
|
19326
|
+
key: z.ZodString;
|
|
19327
|
+
}, z.core.$strict>>;
|
|
19328
|
+
}, z.core.$strict>>>;
|
|
19329
|
+
linkedGroupGuests: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
19330
|
+
linkedGroupsDismissed: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
19331
|
+
pluginId: z.ZodString;
|
|
19332
|
+
key: z.ZodString;
|
|
19333
|
+
}, z.core.$strict>>>;
|
|
19334
|
+
}, z.core.$strict>;
|
|
19335
|
+
|
|
19336
|
+
declare type WorkspaceSnapshot = z.infer<typeof WorkspaceSnapshot>;
|
|
19337
|
+
|
|
19217
19338
|
declare const WorkspaceTabSnapshot: z.ZodObject<{
|
|
19218
19339
|
id: z.ZodString;
|
|
19219
19340
|
label: z.ZodString;
|
|
19220
19341
|
active: z.ZodBoolean;
|
|
19221
19342
|
variable: z.ZodOptional<z.ZodBoolean>;
|
|
19343
|
+
preview: z.ZodOptional<z.ZodBoolean>;
|
|
19344
|
+
groupId: z.ZodOptional<z.ZodString>;
|
|
19345
|
+
sessionIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
19222
19346
|
focusedPaneId: z.ZodString;
|
|
19223
19347
|
maximizedPaneId: z.ZodNullable<z.ZodString>;
|
|
19224
19348
|
root: z.ZodType<WorkspacePaneNode, unknown, z.core.$ZodTypeInternals<WorkspacePaneNode, unknown>>;
|
package/dist/kay-app.js
CHANGED
|
@@ -371,6 +371,7 @@ var PLUGIN_SIGNAL_KINDS = [
|
|
|
371
371
|
];
|
|
372
372
|
var PLUGIN_SIGNAL_TITLE_MAX = 300;
|
|
373
373
|
var PLUGIN_SIGNAL_SNIPPET_MAX = 500;
|
|
374
|
+
var PLUGIN_SIGNAL_BODY_MAX = 2e4;
|
|
374
375
|
var PLUGIN_SIGNAL_LABELS_MAX = 20;
|
|
375
376
|
var PLUGIN_SIGNAL_LABEL_MAX = 64;
|
|
376
377
|
var PLUGIN_SIGNAL_ATTACHMENTS_MAX = 10;
|
|
@@ -1205,6 +1206,7 @@ export {
|
|
|
1205
1206
|
PLUGIN_SIGNAL_ATTACHMENTS_MAX,
|
|
1206
1207
|
PLUGIN_SIGNAL_ATTACHMENT_NAME_MAX,
|
|
1207
1208
|
PLUGIN_SIGNAL_ATTACHMENT_TYPE_MAX,
|
|
1209
|
+
PLUGIN_SIGNAL_BODY_MAX,
|
|
1208
1210
|
PLUGIN_SIGNAL_KINDS,
|
|
1209
1211
|
PLUGIN_SIGNAL_LABELS_MAX,
|
|
1210
1212
|
PLUGIN_SIGNAL_LABEL_MAX,
|
package/dist/vendored-mcp.d.ts
CHANGED
|
@@ -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.
|
package/dist/vendored-mcp.js
CHANGED
|
@@ -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
|
-
|
|
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 ||
|
|
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}`;
|