@yaklabs-ai/plugin-sdk 0.13.6 → 0.13.8
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 +21 -10
- package/THIRD-PARTY-INVENTORY.json +1 -1
- package/dist/agent-conversation.d.ts +93 -0
- package/dist/agent-conversation.js +174 -0
- package/dist/app-data.d.ts +7 -0
- package/dist/app-data.js +9 -0
- package/dist/disclosure.d.ts +298 -0
- package/dist/disclosure.js +64 -0
- package/dist/kay-agent-testing.d.ts +299 -1
- package/dist/kay-agent-testing.js +65 -0
- package/dist/kay-agent.d.ts +322 -0
- package/dist/kay-app.d.ts +325 -7
- package/dist/kay-app.js +13 -11
- package/dist/system-one.d.ts +321 -0
- package/dist/system-one.js +69 -0
- package/dist/transcript-review.d.ts +310 -0
- package/dist/transcript-review.js +680 -0
- package/dist/vendored-mcp.d.ts +1217 -0
- package/dist/vendored-mcp.js +471 -0
- package/package.json +21 -1
- package/skills/directory-plugin-authoring/SKILL.md +3 -2
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
// packages/herd-uri/dist/claims.js
|
|
2
|
+
var SCHEME_RE = /^([a-z][a-z0-9+.-]*):\/\//i;
|
|
3
|
+
var CAPTURE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
4
|
+
var REST_CAPTURE_RE = /^:([A-Za-z_][A-Za-z0-9_]*)\*$/;
|
|
5
|
+
var CONSTRAINED_CAPTURE_RE = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.*)\))?$/;
|
|
6
|
+
var MAX_CAPTURE_CONSTRAINT_LENGTH = 64;
|
|
7
|
+
function compileUriClaim(claim) {
|
|
8
|
+
if (claim.kind === "scheme") {
|
|
9
|
+
const scheme = normalizeProtocol(claim.scheme);
|
|
10
|
+
return {
|
|
11
|
+
claim,
|
|
12
|
+
match(input) {
|
|
13
|
+
const actual = SCHEME_RE.exec(input.trim())?.[1]?.toLowerCase();
|
|
14
|
+
if (actual !== scheme)
|
|
15
|
+
return void 0;
|
|
16
|
+
return { claimKind: claim.kind };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const pattern = compileRoutePattern(claim.pattern);
|
|
21
|
+
return {
|
|
22
|
+
claim,
|
|
23
|
+
match(input) {
|
|
24
|
+
const parsed = parsePatternInput(input);
|
|
25
|
+
if (parsed === void 0)
|
|
26
|
+
return void 0;
|
|
27
|
+
const captures = matchRoute(pattern, parsed);
|
|
28
|
+
if (captures === void 0)
|
|
29
|
+
return void 0;
|
|
30
|
+
return {
|
|
31
|
+
claimKind: claim.kind,
|
|
32
|
+
...Object.keys(captures).length > 0 ? { captures } : {},
|
|
33
|
+
...claim.normalizeTo !== void 0 ? {
|
|
34
|
+
normalizedUri: withInputSearch(claim, pattern, parsed, interpolateNormalizeTo(claim.normalizeTo, captures, pattern.restCaptures ?? []))
|
|
35
|
+
} : {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function normalizeProtocol(value) {
|
|
41
|
+
return value.replace(/:$/, "").toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
function parsePatternInput(input) {
|
|
44
|
+
try {
|
|
45
|
+
const url = new URL(input.trim());
|
|
46
|
+
return {
|
|
47
|
+
protocol: normalizeProtocol(url.protocol),
|
|
48
|
+
hostname: url.hostname.toLowerCase(),
|
|
49
|
+
pathname: url.pathname,
|
|
50
|
+
search: url.search.startsWith("?") ? url.search.slice(1) : url.search
|
|
51
|
+
};
|
|
52
|
+
} catch {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function compileRoutePattern(pattern) {
|
|
57
|
+
const pathname = pattern.pathname !== void 0 ? compileParts(pattern.pathname, "/", { allowRest: true }) : void 0;
|
|
58
|
+
return {
|
|
59
|
+
...pattern.protocol !== void 0 ? { protocol: normalizeProtocol(pattern.protocol) } : {},
|
|
60
|
+
...pattern.hostname !== void 0 ? { hostname: compileParts(pattern.hostname.toLowerCase(), ".") } : {},
|
|
61
|
+
...pathname !== void 0 ? { pathname } : {},
|
|
62
|
+
...pathname !== void 0 ? {
|
|
63
|
+
restCaptures: pathname.filter((part) => part.rest === true).map((part) => part.capture)
|
|
64
|
+
} : {},
|
|
65
|
+
...pattern.search !== void 0 ? { search: compileParts(pattern.search.replace(/^\?/, ""), "&") } : {}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function compileParts(value, separator, options = {}) {
|
|
69
|
+
if (value === "")
|
|
70
|
+
return [];
|
|
71
|
+
const parts = value.split(separator);
|
|
72
|
+
return parts.map((part, index) => {
|
|
73
|
+
const restMatch = REST_CAPTURE_RE.exec(part);
|
|
74
|
+
if (restMatch !== null) {
|
|
75
|
+
if (options.allowRest !== true || index !== parts.length - 1) {
|
|
76
|
+
throw new Error("URI claim rest captures must be final pathname segments.");
|
|
77
|
+
}
|
|
78
|
+
return { capture: restMatch[1], rest: true };
|
|
79
|
+
}
|
|
80
|
+
if (part.startsWith(":")) {
|
|
81
|
+
const rawCapture = part.slice(1);
|
|
82
|
+
const match = CONSTRAINED_CAPTURE_RE.exec(rawCapture);
|
|
83
|
+
if (match === null) {
|
|
84
|
+
throw new Error(`Invalid URI claim capture ':${rawCapture}'.`);
|
|
85
|
+
}
|
|
86
|
+
const capture = match[1];
|
|
87
|
+
if (!CAPTURE_RE.test(capture)) {
|
|
88
|
+
throw new Error(`Invalid URI claim capture ':${rawCapture}'.`);
|
|
89
|
+
}
|
|
90
|
+
const constraint = match[2];
|
|
91
|
+
if (constraint !== void 0)
|
|
92
|
+
assertSupportedConstraint(constraint);
|
|
93
|
+
return {
|
|
94
|
+
capture,
|
|
95
|
+
...constraint !== void 0 ? { constraint: new RegExp(`^(?:${constraint})$`) } : {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { literal: part };
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function assertSupportedConstraint(constraint) {
|
|
102
|
+
if (constraint.length > MAX_CAPTURE_CONSTRAINT_LENGTH || /[()|]/.test(constraint)) {
|
|
103
|
+
throw new Error("URI claim capture constraints must be short segment regexes without grouping or alternation.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function matchRoute(pattern, input) {
|
|
107
|
+
if (pattern.protocol !== void 0 && pattern.protocol !== input.protocol) {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
const captures = {};
|
|
111
|
+
if (pattern.hostname !== void 0 && !matchParts(pattern.hostname, input.hostname, ".", captures)) {
|
|
112
|
+
return void 0;
|
|
113
|
+
}
|
|
114
|
+
if (pattern.pathname !== void 0 && !matchParts(pattern.pathname, input.pathname, "/", captures)) {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
if (pattern.search !== void 0 && !matchParts(pattern.search, input.search, "&", captures)) {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
return captures;
|
|
121
|
+
}
|
|
122
|
+
function matchParts(pattern, value, separator, captures) {
|
|
123
|
+
const parts = value.split(separator);
|
|
124
|
+
let partIndex = 0;
|
|
125
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
126
|
+
const expected = pattern[i];
|
|
127
|
+
if (expected.rest === true) {
|
|
128
|
+
const remaining = parts.slice(partIndex);
|
|
129
|
+
if (remaining.every((part) => part === ""))
|
|
130
|
+
return false;
|
|
131
|
+
captures[expected.capture] = remaining.join(separator);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (partIndex >= parts.length)
|
|
135
|
+
return false;
|
|
136
|
+
const actual = parts[partIndex];
|
|
137
|
+
if (expected.capture !== void 0) {
|
|
138
|
+
const decoded = safeDecode(actual);
|
|
139
|
+
if (expected.constraint !== void 0 && !expected.constraint.test(decoded)) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
captures[expected.capture] = decoded;
|
|
143
|
+
partIndex += 1;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (expected.literal !== actual)
|
|
147
|
+
return false;
|
|
148
|
+
partIndex += 1;
|
|
149
|
+
}
|
|
150
|
+
return partIndex === parts.length;
|
|
151
|
+
}
|
|
152
|
+
function safeDecode(value) {
|
|
153
|
+
try {
|
|
154
|
+
return decodeURIComponent(value);
|
|
155
|
+
} catch {
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function withInputSearch(claim, pattern, input, normalized) {
|
|
160
|
+
if (claim.kind !== "uriPattern" || claim.normalizeTo === void 0 || pattern.search !== void 0 || input.search.length === 0 || claim.normalizeTo.includes("?") || templateProtocol(claim.normalizeTo) !== input.protocol) {
|
|
161
|
+
return normalized;
|
|
162
|
+
}
|
|
163
|
+
return `${normalized}?${input.search}`;
|
|
164
|
+
}
|
|
165
|
+
function templateProtocol(template) {
|
|
166
|
+
return SCHEME_RE.exec(template)?.[1]?.toLowerCase();
|
|
167
|
+
}
|
|
168
|
+
function interpolateNormalizeTo(template, captures, restCaptures) {
|
|
169
|
+
return template.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, (full, name, offset) => {
|
|
170
|
+
const value = captures[name];
|
|
171
|
+
if (value === void 0)
|
|
172
|
+
return full;
|
|
173
|
+
return encodeCaptureValue({
|
|
174
|
+
template,
|
|
175
|
+
offset,
|
|
176
|
+
value,
|
|
177
|
+
rest: restCaptures.includes(name)
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function encodeCaptureValue({ template, offset, value, rest }) {
|
|
182
|
+
const normalized = isAuthorityCapture(template, offset) ? value.toLowerCase() : value;
|
|
183
|
+
if (!rest)
|
|
184
|
+
return encodeURIComponent(normalized);
|
|
185
|
+
return normalized.split("/").join("/");
|
|
186
|
+
}
|
|
187
|
+
function isAuthorityCapture(template, offset) {
|
|
188
|
+
const prefix = template.slice(0, offset);
|
|
189
|
+
const schemeIndex = prefix.lastIndexOf("://");
|
|
190
|
+
if (schemeIndex === -1)
|
|
191
|
+
return false;
|
|
192
|
+
return !/[/?#]/.test(prefix.slice(schemeIndex + 3));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// packages/herd-uri/dist/errors.js
|
|
196
|
+
var UriError = class extends Error {
|
|
197
|
+
};
|
|
198
|
+
var UriValidationError = class extends UriError {
|
|
199
|
+
_tag = "UriValidationError";
|
|
200
|
+
constructor(message) {
|
|
201
|
+
super(message);
|
|
202
|
+
this.name = "UriValidationError";
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// packages/herd-uri/dist/operations.js
|
|
207
|
+
import { z } from "zod";
|
|
208
|
+
var URI_OPERATIONS = [
|
|
209
|
+
"help",
|
|
210
|
+
"read",
|
|
211
|
+
"write",
|
|
212
|
+
"edit",
|
|
213
|
+
"list",
|
|
214
|
+
"search",
|
|
215
|
+
"delete"
|
|
216
|
+
];
|
|
217
|
+
var UriOperationSchema = z.enum(URI_OPERATIONS);
|
|
218
|
+
|
|
219
|
+
// packages/herd-uri/dist/help-schema.js
|
|
220
|
+
import { z as z2 } from "zod";
|
|
221
|
+
var UriContractJsonSchema = z2.record(z2.string(), z2.unknown());
|
|
222
|
+
var UriParameterSchema = z2.strictObject({
|
|
223
|
+
name: z2.string().min(1),
|
|
224
|
+
in: z2.enum(["uri", "query", "selector"]),
|
|
225
|
+
required: z2.boolean(),
|
|
226
|
+
description: z2.string().optional(),
|
|
227
|
+
schema: UriContractJsonSchema,
|
|
228
|
+
examples: z2.array(z2.unknown()).optional()
|
|
229
|
+
});
|
|
230
|
+
var UriPayloadContractSchema = z2.strictObject({
|
|
231
|
+
name: z2.string().min(1),
|
|
232
|
+
mediaType: z2.string().optional(),
|
|
233
|
+
description: z2.string().optional(),
|
|
234
|
+
schema: UriContractJsonSchema.optional(),
|
|
235
|
+
semanticConstraints: z2.array(z2.string().min(1)).min(1).optional(),
|
|
236
|
+
examples: z2.array(z2.unknown()).optional()
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// packages/herd-uri/dist/text-edit.js
|
|
240
|
+
import { z as z3 } from "zod";
|
|
241
|
+
var findReplaceArm = z3.strictObject({
|
|
242
|
+
find: z3.string().min(1),
|
|
243
|
+
replace: z3.string(),
|
|
244
|
+
all: z3.boolean().optional()
|
|
245
|
+
});
|
|
246
|
+
var oldNewEntry = z3.strictObject({
|
|
247
|
+
oldText: z3.string().min(1),
|
|
248
|
+
newText: z3.string()
|
|
249
|
+
});
|
|
250
|
+
var uriTextEditPayloadArms = z3.union([
|
|
251
|
+
findReplaceArm,
|
|
252
|
+
z3.strictObject({ edits: z3.array(oldNewEntry).min(1) }),
|
|
253
|
+
oldNewEntry,
|
|
254
|
+
z3.array(oldNewEntry).min(1)
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
// packages/herd-uri/dist/schema/to-json-schema.js
|
|
258
|
+
import { z as z4 } from "zod";
|
|
259
|
+
|
|
260
|
+
// packages/herd-uri-extensions/dist/limits.js
|
|
261
|
+
var MAX_BYTES = 50 * 1024 * 1024;
|
|
262
|
+
|
|
263
|
+
// packages/herd-uri-extensions/dist/help.js
|
|
264
|
+
function basicUriHelp(options) {
|
|
265
|
+
return {
|
|
266
|
+
uri: options.uri,
|
|
267
|
+
title: options.title,
|
|
268
|
+
summary: options.summary,
|
|
269
|
+
capabilities: options.operations.map((operation) => ({
|
|
270
|
+
rel: operation,
|
|
271
|
+
operation,
|
|
272
|
+
uri: options.uri,
|
|
273
|
+
title: `${operation} ${options.uri}`
|
|
274
|
+
})),
|
|
275
|
+
...options.templates !== void 0 ? { templates: options.templates } : {},
|
|
276
|
+
...options.examples !== void 0 ? { examples: options.examples } : {},
|
|
277
|
+
...options.notes !== void 0 ? { notes: options.notes } : {}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function jsonResource(uri, value) {
|
|
281
|
+
return {
|
|
282
|
+
uri,
|
|
283
|
+
content: JSON.stringify(value, null, 2),
|
|
284
|
+
mimeType: "application/json"
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// packages/vendored-mcp-integration/dist/routes.js
|
|
289
|
+
var CANONICAL_ROUTE_RE = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]+)(\/[^?#]*)$/i;
|
|
290
|
+
var CAPTURE_RE2 = /:([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
291
|
+
var CONSTRAINED_CAPTURE_RE2 = /:[A-Za-z_][A-Za-z0-9_]*\(/;
|
|
292
|
+
var REST_CAPTURE_RE2 = /:[A-Za-z_][A-Za-z0-9_]*\*(?=\/|$)/;
|
|
293
|
+
function compileRoutes(namespace, routes) {
|
|
294
|
+
if (routes.length === 0) {
|
|
295
|
+
throw new Error(`Vendored MCP descriptor for '${namespace}' declares no routes; a module with no addressable shape can never resolve a link.`);
|
|
296
|
+
}
|
|
297
|
+
return routes.map((route) => {
|
|
298
|
+
const parts = CANONICAL_ROUTE_RE.exec(route.uri);
|
|
299
|
+
if (parts === null) {
|
|
300
|
+
throw new Error(`Vendored MCP route '${route.uri}' is not a '<scheme>://<segment>/<path>' template.`);
|
|
301
|
+
}
|
|
302
|
+
const [, protocol, authority, pathname] = parts;
|
|
303
|
+
if (protocol.toLowerCase() !== namespace.toLowerCase()) {
|
|
304
|
+
throw new Error(`Vendored MCP route '${route.uri}' uses scheme '${protocol}' but its plugin's namespace is '${namespace}'.`);
|
|
305
|
+
}
|
|
306
|
+
assertCaptureSymmetry(route);
|
|
307
|
+
assertPlainCaptures(route);
|
|
308
|
+
const pattern = { protocol, hostname: authority, pathname };
|
|
309
|
+
const compiled = {
|
|
310
|
+
route,
|
|
311
|
+
canonical: compileUriClaim({
|
|
312
|
+
kind: "uriPattern",
|
|
313
|
+
pattern,
|
|
314
|
+
normalizeTo: route.uri
|
|
315
|
+
}),
|
|
316
|
+
web: compileUriClaim({
|
|
317
|
+
kind: "uriPattern",
|
|
318
|
+
pattern,
|
|
319
|
+
normalizeTo: route.webUrl
|
|
320
|
+
})
|
|
321
|
+
};
|
|
322
|
+
assertExampleMatches(compiled);
|
|
323
|
+
return compiled;
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
function matchRoute2(compiled, input) {
|
|
327
|
+
const trimmed = input.trim().replace(/\/+$/, "");
|
|
328
|
+
for (const candidate of compiled) {
|
|
329
|
+
const canonical = candidate.canonical.match(trimmed);
|
|
330
|
+
if (canonical?.normalizedUri === void 0)
|
|
331
|
+
continue;
|
|
332
|
+
const web = candidate.web.match(trimmed);
|
|
333
|
+
if (web?.normalizedUri === void 0)
|
|
334
|
+
continue;
|
|
335
|
+
return {
|
|
336
|
+
route: candidate.route,
|
|
337
|
+
ids: canonical.captures ?? {},
|
|
338
|
+
canonicalUri: canonical.normalizedUri,
|
|
339
|
+
webUrl: web.normalizedUri
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return void 0;
|
|
343
|
+
}
|
|
344
|
+
function assertCaptureSymmetry(route) {
|
|
345
|
+
const inUri = captureNames(route.uri);
|
|
346
|
+
const inWeb = captureNames(route.webUrl);
|
|
347
|
+
const missing = [...inUri].filter((name) => !inWeb.has(name));
|
|
348
|
+
const extra = [...inWeb].filter((name) => !inUri.has(name));
|
|
349
|
+
if (missing.length === 0 && extra.length === 0)
|
|
350
|
+
return;
|
|
351
|
+
throw new Error(`Vendored MCP route '${route.uri}' and its web URL '${route.webUrl}' do not capture the same ids${missing.length > 0 ? `; the web URL drops ${missing.join(", ")}` : ""}${extra.length > 0 ? `; the web URL names unknown ${extra.join(", ")}` : ""}.`);
|
|
352
|
+
}
|
|
353
|
+
function assertPlainCaptures(route) {
|
|
354
|
+
for (const template of [route.uri, route.webUrl]) {
|
|
355
|
+
if (CONSTRAINED_CAPTURE_RE2.test(template)) {
|
|
356
|
+
throw new Error(`Vendored MCP route '${route.uri}' carries an inline capture constraint in '${template}'; constrain ids in claims[], not routes[] (a route constraint would interpolate literally into the URL).`);
|
|
357
|
+
}
|
|
358
|
+
if (REST_CAPTURE_RE2.test(template)) {
|
|
359
|
+
throw new Error(`Vendored MCP route '${route.uri}' declares a rest capture in '${template}'; rest values interpolate unencoded into the web URL, so routes name fixed segment shapes.`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function assertExampleMatches(compiled) {
|
|
364
|
+
const matched = compiled.canonical.match(compiled.route.example);
|
|
365
|
+
if (matched === void 0) {
|
|
366
|
+
throw new Error(`Vendored MCP route example '${compiled.route.example}' does not match its own template '${compiled.route.uri}'.`);
|
|
367
|
+
}
|
|
368
|
+
if (matched.normalizedUri === compiled.route.example)
|
|
369
|
+
return;
|
|
370
|
+
throw new Error(`Vendored MCP route example '${compiled.route.example}' is not canonical: its template '${compiled.route.uri}' rebuilds it as '${matched.normalizedUri}'. Write the example exactly as the pill would show it.`);
|
|
371
|
+
}
|
|
372
|
+
function captureNames(template) {
|
|
373
|
+
const names = /* @__PURE__ */ new Set();
|
|
374
|
+
for (const match of template.matchAll(CAPTURE_RE2)) {
|
|
375
|
+
names.add(match[1]);
|
|
376
|
+
}
|
|
377
|
+
return names;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// packages/vendored-mcp-integration/dist/uri-module.js
|
|
381
|
+
var MAX_HINT_FLOWS = 3;
|
|
382
|
+
var MAX_TRIGGER_KEYWORDS = 8;
|
|
383
|
+
function createVendoredMcpUriModule(descriptor) {
|
|
384
|
+
const { namespace, displayName, resourceKind, summary, mcpServerName, mcpSummary } = descriptor;
|
|
385
|
+
const schemeRoot = `${namespace}://`;
|
|
386
|
+
const compiled = compileRoutes(namespace, descriptor.routes);
|
|
387
|
+
return {
|
|
388
|
+
id: descriptor.moduleId,
|
|
389
|
+
title: displayName,
|
|
390
|
+
description: summary,
|
|
391
|
+
// The scheme claim is added here rather than asked for: a module with no `{ kind: "scheme" }`
|
|
392
|
+
// claim fails the SDK's disclosure floor (`scheme-claim-missing`), and for a directory-origin
|
|
393
|
+
// plugin that is a load-time rejection. Every descriptor gets it right by construction.
|
|
394
|
+
claims: [{ kind: "scheme", scheme: namespace }, ...descriptor.claims],
|
|
395
|
+
agentHint: {
|
|
396
|
+
summary,
|
|
397
|
+
triggers: {
|
|
398
|
+
keywords: descriptor.triggerKeywords.slice(0, MAX_TRIGGER_KEYWORDS)
|
|
399
|
+
},
|
|
400
|
+
commonFlows: descriptor.routes.slice(0, MAX_HINT_FLOWS).map((route) => ({
|
|
401
|
+
label: route.description,
|
|
402
|
+
example: `read(path: "${route.example}")`
|
|
403
|
+
})),
|
|
404
|
+
helpUri: schemeRoot,
|
|
405
|
+
skills: [...descriptor.skills]
|
|
406
|
+
},
|
|
407
|
+
verbs: {
|
|
408
|
+
readable: true,
|
|
409
|
+
listable: false,
|
|
410
|
+
writable: false,
|
|
411
|
+
editable: false
|
|
412
|
+
},
|
|
413
|
+
verbDocs: {
|
|
414
|
+
read: `Returns a reference card for a ${displayName} resource: what it is, its ids, and the ${displayName} URL that opens it. Reading calls no ${displayName} API.`
|
|
415
|
+
},
|
|
416
|
+
async help(input) {
|
|
417
|
+
return basicUriHelp({
|
|
418
|
+
uri: input,
|
|
419
|
+
title: displayName,
|
|
420
|
+
summary: `${summary} Kay recognises ${displayName} web links and stores them as ${schemeRoot} URIs. Use the '${mcpServerName}' MCP server for anything beyond the reference card: ${mcpSummary}`,
|
|
421
|
+
operations: ["help", "read"],
|
|
422
|
+
templates: descriptor.routes.map((route) => ({
|
|
423
|
+
uri: route.uri,
|
|
424
|
+
description: route.description,
|
|
425
|
+
operations: ["read"]
|
|
426
|
+
})),
|
|
427
|
+
examples: descriptor.routes.map((route) => ({
|
|
428
|
+
task: route.description,
|
|
429
|
+
uri: route.example,
|
|
430
|
+
operation: "read"
|
|
431
|
+
}))
|
|
432
|
+
});
|
|
433
|
+
},
|
|
434
|
+
matches: (input) => input.trim().toLowerCase().startsWith(schemeRoot),
|
|
435
|
+
describe(input) {
|
|
436
|
+
const match = matchRoute2(compiled, input);
|
|
437
|
+
if (match === void 0)
|
|
438
|
+
return void 0;
|
|
439
|
+
return {
|
|
440
|
+
uri: match.canonicalUri,
|
|
441
|
+
title: referenceTitle(match, resourceKind),
|
|
442
|
+
sourceUrl: match.webUrl
|
|
443
|
+
};
|
|
444
|
+
},
|
|
445
|
+
async read(input) {
|
|
446
|
+
const match = matchRoute2(compiled, input);
|
|
447
|
+
if (match === void 0) {
|
|
448
|
+
throw new UriValidationError(`Unsupported ${displayName} URI: '${input}'. Expected one of: ${descriptor.routes.map((route) => route.uri).join(", ")}.`);
|
|
449
|
+
}
|
|
450
|
+
return jsonResource(match.canonicalUri, {
|
|
451
|
+
uri: match.canonicalUri,
|
|
452
|
+
vendor: displayName,
|
|
453
|
+
resourceKind,
|
|
454
|
+
resource: match.route.description,
|
|
455
|
+
ids: match.ids,
|
|
456
|
+
url: match.webUrl,
|
|
457
|
+
// The one line that keeps this card from being a dead end. An agent that needs the
|
|
458
|
+
// resource's contents needs the vendor's tools, and this names the exact server to call.
|
|
459
|
+
tools: `Kay reads ${displayName} links but does not fetch their contents. For details, changes, or anything beyond these ids, call the '${mcpServerName}' MCP server: ${mcpSummary}`
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
function referenceTitle(match, resourceKind) {
|
|
465
|
+
const values = Object.values(match.ids);
|
|
466
|
+
const last = values.at(-1);
|
|
467
|
+
return last === void 0 || last.length === 0 ? resourceKind : last;
|
|
468
|
+
}
|
|
469
|
+
export {
|
|
470
|
+
createVendoredMcpUriModule
|
|
471
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yaklabs-ai/plugin-sdk",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.8",
|
|
4
4
|
"description": "The Kay plugin SDK — types and helpers for authoring a Kay directory plugin.",
|
|
5
5
|
"author": "YakLabs",
|
|
6
6
|
"type": "module",
|
|
@@ -48,6 +48,26 @@
|
|
|
48
48
|
"./time": {
|
|
49
49
|
"types": "./dist/time.d.ts",
|
|
50
50
|
"default": "./dist/time.js"
|
|
51
|
+
},
|
|
52
|
+
"./app-data": {
|
|
53
|
+
"types": "./dist/app-data.d.ts",
|
|
54
|
+
"default": "./dist/app-data.js"
|
|
55
|
+
},
|
|
56
|
+
"./transcript-review": {
|
|
57
|
+
"types": "./dist/transcript-review.d.ts",
|
|
58
|
+
"default": "./dist/transcript-review.js"
|
|
59
|
+
},
|
|
60
|
+
"./agent-conversation": {
|
|
61
|
+
"types": "./dist/agent-conversation.d.ts",
|
|
62
|
+
"default": "./dist/agent-conversation.js"
|
|
63
|
+
},
|
|
64
|
+
"./vendored-mcp": {
|
|
65
|
+
"types": "./dist/vendored-mcp.d.ts",
|
|
66
|
+
"default": "./dist/vendored-mcp.js"
|
|
67
|
+
},
|
|
68
|
+
"./system-one": {
|
|
69
|
+
"types": "./dist/system-one.d.ts",
|
|
70
|
+
"default": "./dist/system-one.js"
|
|
51
71
|
}
|
|
52
72
|
},
|
|
53
73
|
"files": [
|
|
@@ -95,8 +95,9 @@ claims all show only after enabling, in `read plugin://<id>`.
|
|
|
95
95
|
## The SDK resolution contract
|
|
96
96
|
|
|
97
97
|
- Plugin source imports `@bonsai/plugin-sdk/<subpath>` as a **bare specifier**
|
|
98
|
-
(`@bonsai/plugin-sdk/kay-agent`, `/kay-agent/testing`, `/kay-app`, `/disclosure`, `/
|
|
99
|
-
|
|
98
|
+
(`@bonsai/plugin-sdk/kay-agent`, `/kay-agent/testing`, `/kay-app`, `/disclosure`, `/fs`, `/jev`,
|
|
99
|
+
`/signals`, `/phase-shift`, `/time`, `/transcript`, `/transcript-review`, `/agent-conversation`,
|
|
100
|
+
`/app-data`, `/vendored-mcp` — only declared exports exist).
|
|
100
101
|
- The daemon's plugin loader bundles each declared TypeScript entrypoint and its relative imports.
|
|
101
102
|
It keeps `@bonsai/plugin-sdk` imports external and resolves them to the running app's own built SDK.
|
|
102
103
|
Multi-file plugins are supported, and no plugin-local build is needed for Bonsai to load them.
|