@yaklabs-ai/plugin-sdk 0.13.5 → 0.13.7
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 +19 -8
- package/THIRD-PARTY-INVENTORY.json +8 -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 +5 -7
- package/dist/kay-agent-testing.d.ts +30 -7
- package/dist/kay-agent-testing.js +37 -0
- package/dist/kay-agent.d.ts +43 -8
- package/dist/kay-agent.js +197 -2
- package/dist/kay-app.d.ts +60 -55
- package/dist/kay-app.js +66 -50
- package/dist/time.d.ts +157 -0
- package/dist/time.js +37 -0
- package/dist/transcript-review.d.ts +310 -0
- package/dist/transcript-review.js +680 -0
- package/dist/transcript.d.ts +109 -0
- package/dist/transcript.js +83 -1
- package/dist/vendored-mcp.d.ts +1217 -0
- package/dist/vendored-mcp.js +471 -0
- package/package.json +23 -2
- package/skills/directory-plugin-authoring/SKILL.md +9 -8
|
@@ -0,0 +1,1217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The URI module for one vendored-MCP integration plugin.
|
|
3
|
+
*
|
|
4
|
+
* What this module is FOR is worth stating plainly, because it is not what Linear's module does.
|
|
5
|
+
* A vendored-MCP plugin's value is three things: the vendor's MCP server (the whole action
|
|
6
|
+
* surface), recognition of the vendor's public links, and a branded, openable pill for them. This
|
|
7
|
+
* module is the second and third. It projects a pasted vendor URL onto a canonical `<ns>://` URI
|
|
8
|
+
* and back, and it answers `read` from the URI alone.
|
|
9
|
+
*
|
|
10
|
+
* ## Why `read` does not call MCP
|
|
11
|
+
*
|
|
12
|
+
* It could, and V1 deliberately does not. These servers have no uniform read: several expose only
|
|
13
|
+
* tools, and PostHog's is a single `exec` tool over a CLI-style DSL. There is no shape to project
|
|
14
|
+
* generically, so a generic MCP read would be a guess per vendor wearing one function's clothes.
|
|
15
|
+
* Instead `read` returns a reference card — what the resource is, its captured ids, the URL that
|
|
16
|
+
* opens it, and the server to call for anything deeper. When a vendor earns a real projection, it
|
|
17
|
+
* attaches as a per-vendor `read` beside this one; the shared card stays the floor.
|
|
18
|
+
*
|
|
19
|
+
* ## Why there is no `requiresAuth`
|
|
20
|
+
*
|
|
21
|
+
* Linear's module declares one because its `read` calls MCP and genuinely needs a credential.
|
|
22
|
+
* This module's `read` is a pure projection of the URI it was handed — no network, no credential.
|
|
23
|
+
* Declaring `requiresAuth` anyway would not be a harmless formality: an auth-gated module whose
|
|
24
|
+
* binding is unsatisfied has its public-web `urlPattern` claims suppressed and its `matches()`
|
|
25
|
+
* wrapped to decline `http(s)` (`agent-session.ts` `_suppressPublicUrlClaims`, and
|
|
26
|
+
* `authSuppressedCatalogModule` for discovery). A pasted Supabase link would therefore stay
|
|
27
|
+
* unbranded for every user who has not yet connected Supabase — which is exactly the user the
|
|
28
|
+
* branded pill is for. The vendor's MCP tools remain gated on their own, by the MCP host.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createVendoredMcpUriModule(descriptor: VendoredMcpDescriptor): UriExtensionModule;
|
|
31
|
+
|
|
32
|
+
declare type JsonPrimitive = string | number | boolean | null;
|
|
33
|
+
|
|
34
|
+
declare type JsonSchema = Record<string, unknown>;
|
|
35
|
+
|
|
36
|
+
declare type JsonValue = JsonPrimitive | {
|
|
37
|
+
readonly [key: string]: JsonValue;
|
|
38
|
+
} | readonly JsonValue[];
|
|
39
|
+
|
|
40
|
+
declare interface LineRange {
|
|
41
|
+
readonly start: number;
|
|
42
|
+
readonly end: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare interface LineSelector {
|
|
46
|
+
readonly ranges: readonly LineRange[];
|
|
47
|
+
readonly raw: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
declare interface RawResource {
|
|
51
|
+
readonly uri: string;
|
|
52
|
+
readonly content: string | Uint8Array;
|
|
53
|
+
readonly mimeType: string;
|
|
54
|
+
readonly metadata?: RawResourceMetadata;
|
|
55
|
+
readonly selector?: SelectorDisposition;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
declare interface RawResourceCacheControl {
|
|
59
|
+
/** False marks degraded/fallback content that read-through caches must not store. */
|
|
60
|
+
readonly store?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare interface RawResourceIdentity {
|
|
64
|
+
readonly id: string;
|
|
65
|
+
readonly version: string;
|
|
66
|
+
readonly variantId?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare interface RawResourceMetadata {
|
|
70
|
+
readonly size?: number;
|
|
71
|
+
readonly finalUrl?: string;
|
|
72
|
+
/** Provider resource MIME type; absent when the source does not report one. */
|
|
73
|
+
readonly sourceMimeType?: string;
|
|
74
|
+
readonly notes?: readonly string[];
|
|
75
|
+
readonly cache?: RawResourceCacheControl;
|
|
76
|
+
/**
|
|
77
|
+
* The absolute local filesystem path the resource's bytes were read from,
|
|
78
|
+
* when the transport read them from local disk. Converter-facing
|
|
79
|
+
* provenance: finalize threads it into the content probe so a converter
|
|
80
|
+
* can direct shell tools at the file (e.g. archive extraction). Absent for
|
|
81
|
+
* remote/synthesized content.
|
|
82
|
+
*/
|
|
83
|
+
readonly localPath?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Opaque source-native revision suitable only for a later equality check.
|
|
86
|
+
* A host records it as the session's witness for this resource; when a
|
|
87
|
+
* module reports none, the host records a content digest of `content`
|
|
88
|
+
* instead (`contentDigest`, prefixed `sha256:`), which the module can
|
|
89
|
+
* reproduce at mutation time from the same content its read returns.
|
|
90
|
+
*/
|
|
91
|
+
readonly revision?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Opaque immutable identity for the exact resource bytes returned by a
|
|
94
|
+
* provider. Transport preserves it for observers; it never parses it.
|
|
95
|
+
*/
|
|
96
|
+
readonly resourceIdentity?: RawResourceIdentity;
|
|
97
|
+
/**
|
|
98
|
+
* The resource's stable public address when `uri` reports something more
|
|
99
|
+
* specific than the address a consumer names it by — a retained revision
|
|
100
|
+
* (`skill://<id>/@revision/<version>`) served for a `skill://<source>/<name>`
|
|
101
|
+
* read. Present only when the two differ. Consumers that attribute by name
|
|
102
|
+
* (the read tool's `skillName` detail, and everything keyed off it) read
|
|
103
|
+
* this; consumers that need the exact bytes keep `uri`.
|
|
104
|
+
*/
|
|
105
|
+
readonly canonicalUri?: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** One all-of arm in an ordered scope requirement. */
|
|
109
|
+
declare interface ScopeAlternative {
|
|
110
|
+
readonly allOf: readonly ScopeNeed[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** One scope in an authorization requirement; `reason` is presentation metadata only. */
|
|
114
|
+
declare interface ScopeNeed {
|
|
115
|
+
readonly scope: string;
|
|
116
|
+
readonly reason?: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The minimum OAuth authority for one action.
|
|
121
|
+
*
|
|
122
|
+
* Alternatives are ordered by acquisition preference. Evaluation accepts the first covered arm;
|
|
123
|
+
* when none is covered, callers request only the first arm rather than unioning unrelated grants.
|
|
124
|
+
*/
|
|
125
|
+
declare interface ScopeRequirement {
|
|
126
|
+
readonly purpose: string;
|
|
127
|
+
readonly alternatives: readonly ScopeAlternative[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
declare type SelectorDisposition = {
|
|
131
|
+
readonly kind: "deferred";
|
|
132
|
+
readonly window?: LineSelector;
|
|
133
|
+
} | {
|
|
134
|
+
readonly kind: "applied";
|
|
135
|
+
} | {
|
|
136
|
+
readonly kind: "invalid";
|
|
137
|
+
readonly message: string;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
declare interface UriAgentHint {
|
|
141
|
+
readonly summary: string;
|
|
142
|
+
readonly commonFlows?: readonly UriCommonFlow[];
|
|
143
|
+
readonly helpUri?: string;
|
|
144
|
+
readonly triggers?: UriHintTriggers;
|
|
145
|
+
/**
|
|
146
|
+
* Skill invocation names (flat `localId`s, e.g. `"gmail-email-triage"`) that hold this module's
|
|
147
|
+
* deeper workflow judgment — the name a `read skill://<name>` dispatch resolves, not a display
|
|
148
|
+
* title or a path. Point here only at skills that actually exist in the composed skill roster;
|
|
149
|
+
* a dangling name sends the agent to a `skill://` read for nothing.
|
|
150
|
+
*/
|
|
151
|
+
readonly skills?: readonly string[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
declare type UriAuthActionClassification = {
|
|
155
|
+
readonly kind: "action";
|
|
156
|
+
readonly actionId: string;
|
|
157
|
+
} | {
|
|
158
|
+
readonly kind: "public";
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Finite authorization actions plus the pure route classifier that selects one before dispatch.
|
|
163
|
+
* An exception, an unknown action id, or `undefined` classification fails closed in the host.
|
|
164
|
+
*/
|
|
165
|
+
declare interface UriAuthActionPolicy {
|
|
166
|
+
readonly actions: Readonly<Record<string, ScopeRequirement>>;
|
|
167
|
+
classifyOperation(request: {
|
|
168
|
+
readonly operation: UriOperation;
|
|
169
|
+
readonly uri: string;
|
|
170
|
+
}): UriAuthActionClassification | undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
declare interface UriAuthRef {
|
|
174
|
+
readonly serviceId: string;
|
|
175
|
+
readonly schemeId: string;
|
|
176
|
+
readonly accountId?: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
declare interface UriAuthRequirement {
|
|
180
|
+
readonly serviceId: string;
|
|
181
|
+
/**
|
|
182
|
+
* Optional scheme preference. Absent binds service-level: any injectable scheme of the
|
|
183
|
+
* service satisfies the module, and an explicit account resolves against its own backing
|
|
184
|
+
* scheme. Present, it names the scheme resolution tries first.
|
|
185
|
+
*/
|
|
186
|
+
readonly schemeId?: string;
|
|
187
|
+
/**
|
|
188
|
+
* The scopes this module needs its resolved credential to carry. Threaded by
|
|
189
|
+
* the host's dispatch into every credential load, so a grant-enforcing vault
|
|
190
|
+
* can refuse the module per call. Absent declares no scope requirement.
|
|
191
|
+
*/
|
|
192
|
+
readonly requiredScopes?: readonly string[];
|
|
193
|
+
/**
|
|
194
|
+
* The service id connect guidance should NAME when this module is gated — a host-composed
|
|
195
|
+
* front door whose connect grants exactly this module's scopes (e.g. `gmail` expanding onto
|
|
196
|
+
* the shared `google.account` credential). Guidance only; resolution keys on
|
|
197
|
+
* `(serviceId, schemeId)`. Absent, guidance names `serviceId`.
|
|
198
|
+
*/
|
|
199
|
+
readonly connectServiceId?: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
declare type UriBackingCandidate = {
|
|
203
|
+
readonly path: string;
|
|
204
|
+
readonly root: string;
|
|
205
|
+
readonly relativePath?: never;
|
|
206
|
+
/** Optional display label for where the content canonically comes from (e.g. its source repository), rendered beside the path in projection metadata. Opaque display text; never parsed. */
|
|
207
|
+
readonly sourceRepositoryLabel?: string;
|
|
208
|
+
} | {
|
|
209
|
+
/** Path relative to the sole host-protected root owned by this module. */
|
|
210
|
+
readonly relativePath: string;
|
|
211
|
+
readonly path?: never;
|
|
212
|
+
readonly root?: never;
|
|
213
|
+
/** Optional display label for where the content canonically comes from (e.g. its source repository), rendered beside the path in projection metadata. Opaque display text; never parsed. */
|
|
214
|
+
readonly sourceRepositoryLabel?: string;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
declare interface UriCacheInvalidation {
|
|
218
|
+
/** Drop cached entries whose cache URI starts with this prefix. */
|
|
219
|
+
readonly prefix?: string;
|
|
220
|
+
/** Drop the exact cache URI. */
|
|
221
|
+
readonly uri?: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
declare interface UriCachePolicy {
|
|
225
|
+
/** Read-family cache TTL in milliseconds; absent or zero means not cached. */
|
|
226
|
+
readonly ttlMs?: number;
|
|
227
|
+
/** Mutation directive applied after a successful write/edit/delete. */
|
|
228
|
+
readonly invalidate?: readonly UriCacheInvalidation[];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Resolve cache policy for a concrete URI operation. User-specific modules that
|
|
233
|
+
* return a policy must declare `requiresAuth` or `requiresConnection` so hosts
|
|
234
|
+
* can partition cache keys by identity.
|
|
235
|
+
*/
|
|
236
|
+
declare type UriCachePolicyResolver = (operation: UriOperation, cacheUri: string, ctx: UriResolveContext) => UriCachePolicy | undefined;
|
|
237
|
+
|
|
238
|
+
declare type UriClaim = UriSchemeClaim | UriPatternClaim | UrlPatternClaim;
|
|
239
|
+
|
|
240
|
+
declare interface UriCommonFlow {
|
|
241
|
+
readonly label: string;
|
|
242
|
+
readonly when?: string;
|
|
243
|
+
readonly example: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
declare interface UriConnection {
|
|
247
|
+
readonly id: string;
|
|
248
|
+
readonly moduleId: string;
|
|
249
|
+
readonly adapterId: string;
|
|
250
|
+
readonly displayName: string;
|
|
251
|
+
readonly authRef?: UriAuthRef;
|
|
252
|
+
readonly metadata?: Record<string, unknown>;
|
|
253
|
+
/**
|
|
254
|
+
* Carries the vault's default flag for the account behind this row. A
|
|
255
|
+
* selector-less address resolves to the single flagged row; the flag is per
|
|
256
|
+
* service + scheme, so a module that accepts two schemes (GitHub OAuth and
|
|
257
|
+
* PAT) can see two, which resolves as ambiguous rather than guessing.
|
|
258
|
+
*/
|
|
259
|
+
readonly isDefault?: boolean;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* The typed answer to "can this be undone?" for a route's `delete` verb.
|
|
264
|
+
*
|
|
265
|
+
* - `trash`: moved somewhere recoverable; `restore` names the address or payload that
|
|
266
|
+
* brings it back ("edit with {addLabels:['INBOX']}").
|
|
267
|
+
* - `permanent`: gone on success.
|
|
268
|
+
* - `conditional`: depends on the address or payload; `how` states the rule
|
|
269
|
+
* ("trash by default; ?permanent=true deletes permanently").
|
|
270
|
+
*/
|
|
271
|
+
declare type UriDeleteEffect = {
|
|
272
|
+
readonly kind: "trash";
|
|
273
|
+
readonly restore?: string;
|
|
274
|
+
} | {
|
|
275
|
+
readonly kind: "permanent";
|
|
276
|
+
} | {
|
|
277
|
+
readonly kind: "conditional";
|
|
278
|
+
readonly how: string;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
declare type UriDescribeContext = Pick<UriResolveContext, "cwd" | "sessionId">;
|
|
282
|
+
|
|
283
|
+
declare interface UriExample {
|
|
284
|
+
readonly task: string;
|
|
285
|
+
readonly uri: string;
|
|
286
|
+
readonly operation?: UriOperation;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
declare interface UriExtensionModule extends Omit<UriModule, "verbs"> {
|
|
290
|
+
readonly verbs: UriVerbSupport;
|
|
291
|
+
/** Human-facing per-verb effect docs; see {@link UriVerbDocs}. */
|
|
292
|
+
readonly verbDocs?: UriVerbDocs;
|
|
293
|
+
/**
|
|
294
|
+
* Plugin-declared default permission per verb group. A verb group set to `"ask"`
|
|
295
|
+
* compiles into a defaults-level ask rule — the user is prompted by default but can
|
|
296
|
+
* override with an explicit allow. Undeclared = `"allow"` (fail-open).
|
|
297
|
+
* See {@link UriPermissionDefaults}.
|
|
298
|
+
*/
|
|
299
|
+
readonly permissionDefaults?: UriPermissionDefaults;
|
|
300
|
+
/** Requires a resolved URI connection before any verb handler runs. */
|
|
301
|
+
readonly requiresConnection?: boolean;
|
|
302
|
+
/** Pure route-aware permission facts; see {@link UriExtensionOperationPermissionPolicy}. */
|
|
303
|
+
readonly permission?: UriExtensionOperationPermissionPolicy;
|
|
304
|
+
/** False rejects generic write-tool `source` copies before source fetch. */
|
|
305
|
+
readonly acceptsSourceCopy?: boolean;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
declare interface UriExtensionOperationPermissionPolicy {
|
|
309
|
+
/**
|
|
310
|
+
* Classify one canonical route, purely. `write`/`edit`/`delete` may only be made stricter
|
|
311
|
+
* than the verb default; `help`/`read`/`list`/`search` must stay `"read"` (a `ruleKey` is
|
|
312
|
+
* allowed), because the kernel reruns a crash-interrupted read without asking again. Any
|
|
313
|
+
* other answer, or a throw, fails the call closed.
|
|
314
|
+
*/
|
|
315
|
+
classifyOperation(request: {
|
|
316
|
+
readonly operation: UriOperation;
|
|
317
|
+
readonly uri: string;
|
|
318
|
+
}): {
|
|
319
|
+
readonly kind: "read" | "mutate" | "destructive" | "execute";
|
|
320
|
+
readonly ruleKey?: string;
|
|
321
|
+
} | undefined;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
declare interface UriExternalCliRunner {
|
|
325
|
+
readonly run: (request: UriExternalCliRunRequest) => Promise<UriExternalCliRunResult>;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
declare interface UriExternalCliRunRequest {
|
|
329
|
+
readonly args: readonly string[];
|
|
330
|
+
readonly cwd?: string;
|
|
331
|
+
readonly timeoutMs?: number;
|
|
332
|
+
readonly maxOutputChars?: number;
|
|
333
|
+
readonly signal?: AbortSignal;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
declare interface UriExternalCliRunResult {
|
|
337
|
+
readonly exitCode: number;
|
|
338
|
+
readonly stdout: string;
|
|
339
|
+
readonly stderr: string;
|
|
340
|
+
readonly stdoutTruncated?: boolean;
|
|
341
|
+
readonly stderrTruncated?: boolean;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
declare interface UriHelp {
|
|
345
|
+
readonly uri: string;
|
|
346
|
+
readonly title: string;
|
|
347
|
+
readonly summary: string;
|
|
348
|
+
readonly capabilities?: readonly UriNodeCapability[];
|
|
349
|
+
readonly templates?: readonly UriTemplate[];
|
|
350
|
+
readonly examples?: readonly UriExample[];
|
|
351
|
+
readonly notes?: readonly string[];
|
|
352
|
+
/**
|
|
353
|
+
* Set when this help, for the address it was asked about, carries text a third party wrote and
|
|
354
|
+
* the module relays as it received it (an MCP server's own tool names and descriptions), rather
|
|
355
|
+
* than text the module's author wrote. Absent: the module's own text.
|
|
356
|
+
*/
|
|
357
|
+
readonly thirdPartyContent?: true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
declare interface UriHintTriggers {
|
|
361
|
+
readonly keywords?: readonly string[];
|
|
362
|
+
readonly patterns?: readonly string[];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
declare interface UriListItem {
|
|
366
|
+
readonly uri: string;
|
|
367
|
+
readonly title?: string;
|
|
368
|
+
readonly summary?: string;
|
|
369
|
+
/** Provider resource MIME type; absent when the source does not report one. */
|
|
370
|
+
readonly sourceMimeType?: string;
|
|
371
|
+
readonly operations?: readonly UriOperation[];
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
declare interface UriListMetadata {
|
|
375
|
+
readonly totalCount?: number;
|
|
376
|
+
readonly totalCountLabel?: string;
|
|
377
|
+
readonly returnedCount?: number;
|
|
378
|
+
/**
|
|
379
|
+
* True when the provider could not search/enumerate the whole corpus for this
|
|
380
|
+
* page, so the result may be missing matches (e.g. a federated query that spans
|
|
381
|
+
* multiple stores and timed out part way). The caller should treat the result as
|
|
382
|
+
* partial and, where possible, narrow the scope. Omit when results are complete.
|
|
383
|
+
*/
|
|
384
|
+
readonly incompleteSearch?: boolean;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
declare interface UriListParams {
|
|
388
|
+
readonly cursor?: string;
|
|
389
|
+
readonly limit?: number;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
declare interface UriListResult {
|
|
393
|
+
readonly uri: string;
|
|
394
|
+
readonly items: readonly UriListItem[];
|
|
395
|
+
readonly nextCursor?: string;
|
|
396
|
+
readonly metadata?: UriListMetadata;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
declare type UriLocateContext = Pick<UriResolveContext, "cwd" | "signal" | "connection" | "sessionId" | "paths"> & {
|
|
400
|
+
/** Exact resource returned by the read whose supplemental backing is being located. */
|
|
401
|
+
readonly readResource?: RawResource;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
declare type UriLocateResult = {
|
|
405
|
+
readonly kind: "candidate";
|
|
406
|
+
readonly candidate: UriBackingCandidate;
|
|
407
|
+
} | {
|
|
408
|
+
readonly kind: "malformed";
|
|
409
|
+
readonly message: string;
|
|
410
|
+
} | {
|
|
411
|
+
readonly kind: "not-disk-backed";
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
declare type UriMarkdownRenderInput = {
|
|
415
|
+
readonly operation: "help";
|
|
416
|
+
readonly uri: string;
|
|
417
|
+
readonly result: UriHelp;
|
|
418
|
+
} | {
|
|
419
|
+
readonly operation: "list";
|
|
420
|
+
readonly uri: string;
|
|
421
|
+
readonly result: UriListResult;
|
|
422
|
+
} | {
|
|
423
|
+
readonly operation: "search";
|
|
424
|
+
readonly uri: string;
|
|
425
|
+
readonly result: UriSearchResult;
|
|
426
|
+
} | {
|
|
427
|
+
readonly operation: Extract<UriOperation, "write" | "edit" | "delete">;
|
|
428
|
+
readonly uri: string;
|
|
429
|
+
readonly result: UriMutationResult;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
declare interface UriModule {
|
|
433
|
+
readonly id: string;
|
|
434
|
+
/**
|
|
435
|
+
* Explicit human-readable name for catalog/display purposes (the plugin
|
|
436
|
+
* manifest's `contributes.uriModules[].displayName`, threaded through by
|
|
437
|
+
* hand since there is no automatic manifest→runtime-module composition
|
|
438
|
+
* step). Falls back to a mechanical id-derived title when absent — see
|
|
439
|
+
* `uriCatalogTitle`.
|
|
440
|
+
*/
|
|
441
|
+
readonly title?: string;
|
|
442
|
+
readonly fallback?: boolean;
|
|
443
|
+
/**
|
|
444
|
+
* Whether this module parses the read tool's trailing line selector out of its own addresses.
|
|
445
|
+
* Absent or false: the host owns the explicit forms (`:50-200`, `:50-`, `:50+10`, `:raw`). The
|
|
446
|
+
* read tool strips one before dispatch, hands `read` the bare address, and applies the window
|
|
447
|
+
* to what comes back, so a module never has to know the grammar for the read tool's own
|
|
448
|
+
* `Continue with '<address>:N-M'` banner to work on its addresses (#10754). A bare trailing
|
|
449
|
+
* `:<digits>` is never taken from such a module: it is too common inside real ids (a Figma
|
|
450
|
+
* node `1:2`), so it reaches the module as written.
|
|
451
|
+
*
|
|
452
|
+
* Declare `true` only when the module must see the raw address: its grammar can end in an
|
|
453
|
+
* explicit-range shape, it wants the bare `:50` form too, or it windows the content itself
|
|
454
|
+
* (streaming a large file, skipping a cap it applies to an unwindowed read). Such a module
|
|
455
|
+
* calls `parseLineSelector` itself and reports what it did through `RawResource.selector`.
|
|
456
|
+
*/
|
|
457
|
+
readonly ownsLineSelectors?: boolean;
|
|
458
|
+
readonly claims?: readonly UriClaim[];
|
|
459
|
+
/** Migration-only prompt summary until structured help/catalog coverage replaces prose. */
|
|
460
|
+
readonly description?: string;
|
|
461
|
+
readonly agentHint?: UriAgentHint;
|
|
462
|
+
readonly requiresAuth?: UriAuthRequirement;
|
|
463
|
+
readonly authActions?: UriAuthActionPolicy;
|
|
464
|
+
/** Pure route/payload validation applied before a consequential permission ask. */
|
|
465
|
+
readonly preflight?: UriOperationPreflightPolicy;
|
|
466
|
+
/**
|
|
467
|
+
* Structured facts for approval surfaces, or `undefined` when unavailable.
|
|
468
|
+
* A one-line description must name the whole consequence; `preview` instead
|
|
469
|
+
* supplies expanded, literal-text detail, and without a `quote` it suppresses one-line
|
|
470
|
+
* approval (a module that quotes the whole message keeps its line beside it). The module
|
|
471
|
+
* owns the static action phrase, target resolution, payload decoding and declaration
|
|
472
|
+
* of covered payload fields and query parameters. Unknown fields cost the summary.
|
|
473
|
+
* The host owns framing, the whole-quote fit (no elision) and display-safety admission.
|
|
474
|
+
*
|
|
475
|
+
* Unlike preflight, this hook is async and may do I/O. Resolve names through `ctx`,
|
|
476
|
+
* the same dispatch context used by execution, never an ambient or cached account. A name
|
|
477
|
+
* the module resolved under that account may be cached for a bounded time, keyed by that
|
|
478
|
+
* account's identity and never answered to another account or after a failed lookup.
|
|
479
|
+
* The host calls it once before raising the ask, enforces the short `ctx.signal`
|
|
480
|
+
* deadline and discards late answers. A throw yields no summary and a module-attributed
|
|
481
|
+
* diagnostic; declining costs a click into the app, never an under-described approval.
|
|
482
|
+
*/
|
|
483
|
+
describeOperation?(request: {
|
|
484
|
+
readonly operation: UriOperation;
|
|
485
|
+
readonly uri: string;
|
|
486
|
+
readonly payload: unknown;
|
|
487
|
+
}, ctx: UriResolveContext): Promise<UriOperationDescription | undefined>;
|
|
488
|
+
/**
|
|
489
|
+
* Rebuild a call from the person's "Allow with edits" answer: the same payload
|
|
490
|
+
* {@link describeOperation} was given, with the values the person typed into the preview's
|
|
491
|
+
* `editable` fields put in their place. Implement it beside any preview that marks a field
|
|
492
|
+
* `editable`; without it the host drops every editable marker from that module's previews, so
|
|
493
|
+
* a field is never offered for editing that cannot be honoured.
|
|
494
|
+
*
|
|
495
|
+
* Pure and fast: it must not send, write or otherwise act, and it should not do I/O (it gets
|
|
496
|
+
* the dispatch context `ctx` only so a name can be resolved the way `describeOperation` does).
|
|
497
|
+
* Return the COMPLETE amended payload in the shape the module's own handler reads. Validate it
|
|
498
|
+
* with the handler's own schema, so an amended call is exactly as valid as one the model made.
|
|
499
|
+
* Decline by returning `undefined` or throwing; either denies the call with nothing done.
|
|
500
|
+
*
|
|
501
|
+
* The host calls it once, after the person allowed the call, never for a denial, and only for
|
|
502
|
+
* a `write` whose payload this module described. The kernel passes the `edits` through
|
|
503
|
+
* unchanged. Bonsai's daemon has already refused, before the ask settled, a key that is not an
|
|
504
|
+
* `editable` field of the preview it showed, a repeated key, a blank value and a value past the
|
|
505
|
+
* field's `maxLength`, but another host may not, so refuse each of those here yourself (return
|
|
506
|
+
* `undefined`).
|
|
507
|
+
*
|
|
508
|
+
* The host then holds the amended call to what the person was shown, in two steps, and runs it
|
|
509
|
+
* only if both pass. It classifies the amended call again and requires the same tool, rule key,
|
|
510
|
+
* kind, resources, scheme and target address, so an edit cannot reach a different route. It then
|
|
511
|
+
* calls {@link describeOperation} on the amended call and requires that preview to read exactly
|
|
512
|
+
* as the one the person saw, apart from the values of the fields they edited: the same title, the
|
|
513
|
+
* same fields in the same order, each with the same label, key, `editable` marker and
|
|
514
|
+
* `maxLength`, and every read-only field with the same value. Anything else refuses the call
|
|
515
|
+
* with nothing done: a mismatch, and also a describer that is missing, declines, throws or
|
|
516
|
+
* overruns its deadline. The `description` line is not compared.
|
|
517
|
+
*
|
|
518
|
+
* So rebuild from the original payload and change only the fields you offered. A recipient, a
|
|
519
|
+
* thread or an attachment list that an amendment changed is caught by the second step, but only
|
|
520
|
+
* where the preview shows it: put whatever says where a call goes, or what it does beyond its
|
|
521
|
+
* editable fields, in the preview's `title` or a field, never only in its `description`, and
|
|
522
|
+
* keep recipients, destinations and thread bindings out of `editable` fields.
|
|
523
|
+
*/
|
|
524
|
+
amendOperation?(request: {
|
|
525
|
+
readonly operation: UriOperation;
|
|
526
|
+
readonly uri: string;
|
|
527
|
+
readonly payload: unknown;
|
|
528
|
+
readonly edits: readonly UriPreviewEdit[];
|
|
529
|
+
}, ctx: UriResolveContext): Promise<UriOperationAmendment | undefined>;
|
|
530
|
+
/**
|
|
531
|
+
* A short, render-only name for the resource a settled call on `request.uri` touched, which the
|
|
532
|
+
* host stamps on the tool result's `details` so a transcript row can name it where it would
|
|
533
|
+
* otherwise print the address (`#lane-analytics` and `thread`, not a channel id). Answer
|
|
534
|
+
* `undefined` for any address you cannot honestly name.
|
|
535
|
+
*
|
|
536
|
+
* Called once per successful URI verb call, AFTER the verb handler has returned, with the same
|
|
537
|
+
* dispatch context. Resolve names through `ctx` and nothing else, and prefer a cache your own
|
|
538
|
+
* verb handlers warm, keyed by the executing account: a name one account saw is never answered
|
|
539
|
+
* to another, and a failed, blank or aborted lookup is never cached. The host bounds the wait
|
|
540
|
+
* (a finished result is held at most a quarter of a second), gives `ctx.signal` a hard deadline,
|
|
541
|
+
* and drops a late, thrown or refused answer without failing the call; a throw is reported as a
|
|
542
|
+
* module-attributed diagnostic. The label is a label, never an identity: the address remains the
|
|
543
|
+
* click target, hover text and accessible name. It is UI-only, so it never enters the tool
|
|
544
|
+
* result's content and no telemetry reads it.
|
|
545
|
+
*
|
|
546
|
+
* Unlike `describeOperation` this is not an approval surface: it carries no consequence, no
|
|
547
|
+
* quote and no coverage claim, and nothing may gate a permission on it.
|
|
548
|
+
*/
|
|
549
|
+
labelResource?(request: UriResourceLabelRequest, ctx: UriResolveContext): Promise<UriResourceLabel | undefined>;
|
|
550
|
+
/**
|
|
551
|
+
* Per-resource observability: does a `format: "observation"` read of THIS
|
|
552
|
+
* uri render source-native material ({@link UriResolveContext.format})?
|
|
553
|
+
* Route-parse only — cheap, side-effect-free, no I/O, no auth (the same
|
|
554
|
+
* discipline as `matches`); a throw is treated as `false`. Returning true
|
|
555
|
+
* is the resource's contract that its observation read returns an
|
|
556
|
+
* observation render and that failures under that format throw typed,
|
|
557
|
+
* status-bearing errors rather than resolving a friendly fallback page.
|
|
558
|
+
* The kernel stamps the answer onto the resource's access events, which is
|
|
559
|
+
* what ambient index consumers replay on — so "PRs are observable" is
|
|
560
|
+
* declared here, route by route, never module-wide. Absent means no read
|
|
561
|
+
* of this module is observable. A vendor's own gone-vocabulary (HTTP 410,
|
|
562
|
+
* a 200-body "ok:false"/"archived:true"/"status:cancelled", or a
|
|
563
|
+
* 403/404-ambiguous lost-access response) is this module's job to
|
|
564
|
+
* translate into `UriNotFoundError` or a `status: 404` error under the
|
|
565
|
+
* observation format — the fold that retires a doc never learns vendor
|
|
566
|
+
* vocabulary (see `ObservationMaterial`'s doc comment).
|
|
567
|
+
*/
|
|
568
|
+
observes?(uri: string): boolean;
|
|
569
|
+
/**
|
|
570
|
+
* Head-only revision probe: the resource's CURRENT source-native revision
|
|
571
|
+
* without fetching its body, or `undefined` when that cannot be known
|
|
572
|
+
* cheaply. The host calls it before a repeat `read` of an address the
|
|
573
|
+
* session already holds, with `ctx.expectedRevision` set to the revision
|
|
574
|
+
* that read reported (`RawResourceMetadata.revision`); a value equal to it
|
|
575
|
+
* means "unchanged" and the fetch is skipped, anything else falls through
|
|
576
|
+
* to the ordinary read. A module whose read revision embeds more than the
|
|
577
|
+
* head can know (a content digest beside a stat stamp) may answer relative
|
|
578
|
+
* to `expectedRevision` — return it when the cheap part matches, `undefined`
|
|
579
|
+
* when it does not — but must never return a value it has not verified.
|
|
580
|
+
* `undefined` is always safe: it costs one fetch, never a wrong answer.
|
|
581
|
+
* Must be cheaper than the read (a metadata request, a `stat`); a throw is
|
|
582
|
+
* treated as `undefined`.
|
|
583
|
+
*/
|
|
584
|
+
revision?(uri: string, ctx: UriResolveContext): Promise<string | undefined>;
|
|
585
|
+
readonly getCachePolicy?: UriCachePolicyResolver;
|
|
586
|
+
/** Retained matching escape hatch; future dispatch should prefer compiled claims. */
|
|
587
|
+
matches(input: string, ctx: UriResolveContext): boolean;
|
|
588
|
+
normalize?(input: string, ctx: UriResolveContext): UriNormalizeResult | undefined;
|
|
589
|
+
describe?(input: string, ctx: UriDescribeContext): UriResourceDescription | undefined;
|
|
590
|
+
locate?(input: string, ctx: UriLocateContext): Promise<UriLocateResult>;
|
|
591
|
+
/**
|
|
592
|
+
* `read`, `help`, `list` and `search` observe; they never change the resource or anything
|
|
593
|
+
* outside the host. Repeating one with the same input must be harmless: the kernel reruns a
|
|
594
|
+
* call of these verbs that a crash cut off, with the same input, without asking the user
|
|
595
|
+
* again. Idempotent bookkeeping (a cache fill, an index of what was read, a usage count) is
|
|
596
|
+
* fine; a send, a mark-as-read or a create is not, and belongs on a mutating verb.
|
|
597
|
+
*/
|
|
598
|
+
read(input: string, ctx: UriResolveContext): Promise<RawResource>;
|
|
599
|
+
/** Observes only; see {@link read}. */
|
|
600
|
+
help?(input: string, ctx: UriResolveContext): Promise<UriHelp>;
|
|
601
|
+
write?(input: string, content: UriPayload, ctx: UriResolveContext): Promise<UriMutationResult | void>;
|
|
602
|
+
/** Opt-in structured write with one or more host-resolved resources delivered beside the content. */
|
|
603
|
+
writeWithSources?(input: string, content: UriPayload, sources: readonly UriWriteSource[], ctx: UriResolveContext): Promise<UriMutationResult | void>;
|
|
604
|
+
/**
|
|
605
|
+
* Opt-in byte sink: write RAW BYTES to this address, no UTF-8 round trip.
|
|
606
|
+
* `UriPayload` is text/JSON by contract, so a module that can store bytes
|
|
607
|
+
* declares it here instead of stretching `write`. The only caller today is
|
|
608
|
+
* the `write` tool's `source` copy leg, which is how a provider's binary
|
|
609
|
+
* resource — a Gmail attachment, an image, a PDF, a zip — reaches a
|
|
610
|
+
* byte-capable destination without ever being decoded into the model's
|
|
611
|
+
* context. A module that omits it is text-only, and a binary copy targeting
|
|
612
|
+
* it is refused with an error naming a byte-capable destination.
|
|
613
|
+
*
|
|
614
|
+
* `source` describes what the bytes are: a filesystem-backed sink can ignore
|
|
615
|
+
* it (the target path already carries the name), while a remote provider
|
|
616
|
+
* sink needs it to name and type the stored file. It sits before `ctx` so a
|
|
617
|
+
* forwarding wrapper that fails to thread it is a compile error, not a
|
|
618
|
+
* silent drop.
|
|
619
|
+
*/
|
|
620
|
+
writeBytes?(input: string, bytes: Uint8Array, source: UriSourceDescriptor, ctx: UriResolveContext): Promise<UriMutationResult | void>;
|
|
621
|
+
edit?(input: string, patch: UriPayload, ctx: UriResolveContext): Promise<UriMutationResult>;
|
|
622
|
+
/** Observes only; see {@link read}. */
|
|
623
|
+
list?(input: string, params: UriListParams, ctx: UriResolveContext): Promise<UriListResult>;
|
|
624
|
+
/** Observes only; see {@link read}. */
|
|
625
|
+
search?(input: string, params: UriSearchParams, ctx: UriResolveContext): Promise<UriSearchResult>;
|
|
626
|
+
delete?(input: string, ctx: UriResolveContext): Promise<UriMutationResult>;
|
|
627
|
+
toMarkdown?(input: UriMarkdownRenderInput, ctx: UriResolveContext): string | undefined;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/** Authoritative lifecycle facts for a successful record-like URI mutation. */
|
|
631
|
+
declare interface UriMutationReceipt {
|
|
632
|
+
readonly uri: string;
|
|
633
|
+
readonly operation: "create" | "update" | "trash" | "restore" | "delete";
|
|
634
|
+
readonly state: "active" | "trashed" | "deleted";
|
|
635
|
+
readonly revision?: string;
|
|
636
|
+
readonly changedFields?: readonly string[];
|
|
637
|
+
readonly recoverable: boolean;
|
|
638
|
+
readonly recoveryUri?: string;
|
|
639
|
+
readonly originalUri?: string;
|
|
640
|
+
readonly restoreTarget?: string;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
declare interface UriMutationResult {
|
|
644
|
+
readonly uri: string;
|
|
645
|
+
readonly summary?: string;
|
|
646
|
+
readonly resource?: RawResource | JsonValue;
|
|
647
|
+
readonly validation?: readonly UriValidationMessage[];
|
|
648
|
+
readonly metadata?: Record<string, unknown>;
|
|
649
|
+
/** Typed state/recovery evidence; successful callers may trust it without a proof read. */
|
|
650
|
+
readonly receipt?: UriMutationReceipt;
|
|
651
|
+
/** Opaque source-native revision after this successful mutation. */
|
|
652
|
+
readonly revision?: string;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
declare interface UriNodeCapability {
|
|
656
|
+
readonly rel: string;
|
|
657
|
+
readonly operation: UriOperation;
|
|
658
|
+
readonly uri: string;
|
|
659
|
+
readonly title: string;
|
|
660
|
+
readonly description?: string;
|
|
661
|
+
readonly parameters?: readonly UriParameter[];
|
|
662
|
+
readonly accepts?: UriPayloadContract;
|
|
663
|
+
readonly returns?: UriPayloadContract;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
declare interface UriNormalizeResult {
|
|
667
|
+
readonly uri: string;
|
|
668
|
+
readonly source: string;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
declare type UriOperation = "help" | "read" | "write" | "edit" | "list" | "search" | "delete";
|
|
672
|
+
|
|
673
|
+
/** The call {@link UriModule.amendOperation} rebuilt: the whole payload, in the shape the module reads. */
|
|
674
|
+
declare interface UriOperationAmendment {
|
|
675
|
+
readonly payload: unknown;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
declare interface UriOperationDescription {
|
|
679
|
+
/** Static verb phrase authored by the module. Never interpolated from input. */
|
|
680
|
+
readonly action: string;
|
|
681
|
+
/** Human name resolved through the connection that will execute the call. */
|
|
682
|
+
readonly target: string;
|
|
683
|
+
/** Model-authored content; the host flattens, budgets, elides and bounds it. */
|
|
684
|
+
readonly quote?: string;
|
|
685
|
+
/** Full, render-only detail. Hosts must not turn a rich preview into one-line approval. */
|
|
686
|
+
readonly preview?: {
|
|
687
|
+
readonly title: string;
|
|
688
|
+
readonly description?: string;
|
|
689
|
+
readonly fields?: readonly {
|
|
690
|
+
readonly label: string;
|
|
691
|
+
readonly value: string;
|
|
692
|
+
readonly oldValue?: string;
|
|
693
|
+
/**
|
|
694
|
+
* A stable, module-defined id for this field, unique within the preview (`subject`,
|
|
695
|
+
* `body`, `text`). It names the field in an "Allow with edits" answer, so it never
|
|
696
|
+
* depends on the displayed label. Required for an `editable` field.
|
|
697
|
+
*/
|
|
698
|
+
readonly key?: string;
|
|
699
|
+
/**
|
|
700
|
+
* `true` offers this field to the person for editing on the approval card. Offer it only
|
|
701
|
+
* when the module implements {@link UriModule.amendOperation} for this call and can honour
|
|
702
|
+
* any value within `maxLength`; the host drops the offer otherwise. Absent means read-only.
|
|
703
|
+
*/
|
|
704
|
+
readonly editable?: true;
|
|
705
|
+
/** Longest edited value, in UTF-16 code units. Meaningful only with `editable`. */
|
|
706
|
+
readonly maxLength?: number;
|
|
707
|
+
}[];
|
|
708
|
+
};
|
|
709
|
+
/** True only when every displayed fact comes from the input, independent of the executing account. */
|
|
710
|
+
readonly accountIndependent?: true;
|
|
711
|
+
/** What this description accounts for; the host refuses undeclared input. */
|
|
712
|
+
readonly accounts: {
|
|
713
|
+
/** The payload actually read by the module, after its own decoding. */
|
|
714
|
+
readonly payload: unknown;
|
|
715
|
+
readonly payloadFields: readonly string[];
|
|
716
|
+
readonly queryParams?: readonly string[];
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Pure, route-aware validation that runs before permission policy can surface an ask.
|
|
722
|
+
*
|
|
723
|
+
* This is deliberately narrower than execution: it receives only the canonical URI,
|
|
724
|
+
* operation, and operation payload, performs no I/O, and returns a user-actionable
|
|
725
|
+
* rejection for calls that the module already knows cannot succeed. The handler must
|
|
726
|
+
* still validate again when it executes because approval is not an authority boundary.
|
|
727
|
+
*/
|
|
728
|
+
declare interface UriOperationPreflightPolicy {
|
|
729
|
+
/**
|
|
730
|
+
* The rejection half. Optional since kay#7684: a module whose only preflight
|
|
731
|
+
* fact is affirmative (`acceptsPayloadlessWrite`) must not have to stub a
|
|
732
|
+
* validator that never rejects.
|
|
733
|
+
*/
|
|
734
|
+
validateOperation?(request: {
|
|
735
|
+
readonly operation: UriOperation;
|
|
736
|
+
readonly uri: string;
|
|
737
|
+
readonly payload: unknown;
|
|
738
|
+
}): string | undefined;
|
|
739
|
+
/**
|
|
740
|
+
* Route-level affirmative: may a `write` to this URI carry NO payload at all
|
|
741
|
+
* — neither `content` nor `source`? (The canonical case is folder creation,
|
|
742
|
+
* e.g. `?type=folder`.) The write tool's generic shape rule requires exactly
|
|
743
|
+
* one payload form; a route answers `true` here when a payloadless write is
|
|
744
|
+
* meaningful FOR THAT ROUTE, and the rule then admits the call.
|
|
745
|
+
*
|
|
746
|
+
* This exists because an empty body is not always sendable: on some
|
|
747
|
+
* model/provider paths a top-level empty-string argument (`content: ""`)
|
|
748
|
+
* never reaches the host — the key arrives absent, indistinguishable from an
|
|
749
|
+
* omitted argument (kay#7684). A contract that can only be invoked with an
|
|
750
|
+
* empty string is unreachable on those paths, so a route whose write is
|
|
751
|
+
* meaningful with no body must declare it and let the caller omit the
|
|
752
|
+
* payload instead.
|
|
753
|
+
*
|
|
754
|
+
* Pure and side-effect-free like {@link validateOperation}: route-parse
|
|
755
|
+
* only, no I/O. A throw NEVER admits the write, but the two consult paths
|
|
756
|
+
* disagree on purpose about what happens next: pre-ask (permission
|
|
757
|
+
* resolution, which must never crash the gate) answers no and records a
|
|
758
|
+
* module-attributed diagnostic; at execute time the write tool asks only
|
|
759
|
+
* when the call genuinely carries no payload, and a throw there is the
|
|
760
|
+
* module's own bug surfacing as the call's error — louder than a misleading
|
|
761
|
+
* \"provide exactly one of content or source\" the model could never
|
|
762
|
+
* satisfy. Absent means no route of this module accepts a payloadless
|
|
763
|
+
* write.
|
|
764
|
+
*/
|
|
765
|
+
acceptsPayloadlessWrite?(request: {
|
|
766
|
+
readonly uri: string;
|
|
767
|
+
}): boolean;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
declare interface UriParameter {
|
|
771
|
+
readonly name: string;
|
|
772
|
+
readonly in: "uri" | "query" | "selector";
|
|
773
|
+
readonly required: boolean;
|
|
774
|
+
readonly description?: string;
|
|
775
|
+
readonly schema: JsonSchema;
|
|
776
|
+
readonly examples?: readonly unknown[];
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
declare interface UriPatternClaim {
|
|
780
|
+
readonly kind: "uriPattern";
|
|
781
|
+
readonly pattern: UriPatternInit;
|
|
782
|
+
/**
|
|
783
|
+
* Canonical spelling rebuilt from the captures. When the template keeps the
|
|
784
|
+
* input's scheme (the module's own addressing), the input's query string is
|
|
785
|
+
* carried over verbatim so a route flag such as `?permanent=true` survives
|
|
786
|
+
* canonicalization (kay#7859); a template that re-targets to another scheme
|
|
787
|
+
* (a projection to a web link) drops it, as does a pattern that consumed the
|
|
788
|
+
* query itself or a template that spells its own.
|
|
789
|
+
*/
|
|
790
|
+
readonly normalizeTo?: string;
|
|
791
|
+
readonly examples?: readonly string[];
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
declare interface UriPatternInit {
|
|
795
|
+
readonly protocol?: string;
|
|
796
|
+
readonly hostname?: string;
|
|
797
|
+
/**
|
|
798
|
+
* Slash-delimited path pattern. A final capture may use `:name*` to consume
|
|
799
|
+
* the remaining path segments, preserving `/` in the captured value.
|
|
800
|
+
*/
|
|
801
|
+
readonly pathname?: string;
|
|
802
|
+
readonly search?: string;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
declare type UriPayload = string | JsonValue;
|
|
806
|
+
|
|
807
|
+
declare interface UriPayloadContract {
|
|
808
|
+
readonly name: string;
|
|
809
|
+
readonly mediaType?: string;
|
|
810
|
+
readonly description?: string;
|
|
811
|
+
/** Omitted when the node accepts or returns an unstructured payload. */
|
|
812
|
+
readonly schema?: JsonSchema;
|
|
813
|
+
/** Cross-value invariants the module enforces but plain JSON Schema cannot express. */
|
|
814
|
+
readonly semanticConstraints?: readonly string[];
|
|
815
|
+
readonly examples?: readonly unknown[];
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* The three-state permission vocabulary a plugin declares for its default permissions.
|
|
820
|
+
* Maps to `PermissionRule.effect`: `allow` → allow, `ask` → ask, `never` → deny.
|
|
821
|
+
*/
|
|
822
|
+
declare type UriPermissionDefault = "allow" | "ask" | "never";
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Plugin-declared default permission for each verb group (read/write/edit/delete).
|
|
826
|
+
* Undeclared verb groups default to `"allow"` (fail-open, same optionality as
|
|
827
|
+
* {@link UriVerbDocs}). Lives here in the protocol layer (beside `UriVerbDocs`)
|
|
828
|
+
* so both `@herd/uri-extensions`' `UriExtensionModule` and herd-agent's kernel
|
|
829
|
+
* `UriModule` can carry it.
|
|
830
|
+
*/
|
|
831
|
+
declare interface UriPermissionDefaults {
|
|
832
|
+
readonly read?: UriPermissionDefault;
|
|
833
|
+
readonly write?: UriPermissionDefault;
|
|
834
|
+
readonly edit?: UriPermissionDefault;
|
|
835
|
+
readonly delete?: UriPermissionDefault;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* One change a person made to an `editable` field of a call's action preview ("Allow with
|
|
840
|
+
* edits"): the field's `key` and the value they want it to hold. Values are message content, so
|
|
841
|
+
* a module must not log or persist them.
|
|
842
|
+
*/
|
|
843
|
+
declare interface UriPreviewEdit {
|
|
844
|
+
readonly key: string;
|
|
845
|
+
readonly value: string;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/** The read shape a caller may request via {@link UriResolveContext.format}. */
|
|
849
|
+
declare type UriReadFormat = "observation";
|
|
850
|
+
|
|
851
|
+
declare interface UriResolveContext {
|
|
852
|
+
readonly cwd: string;
|
|
853
|
+
readonly signal?: AbortSignal;
|
|
854
|
+
readonly connection?: UriConnection;
|
|
855
|
+
/** Host-populated execution auth for verb handlers; always absent during matching. */
|
|
856
|
+
readonly auth?: UriResolvedAuth;
|
|
857
|
+
/**
|
|
858
|
+
* Id of the session dispatching this call, stamped by the host at the dispatch site.
|
|
859
|
+
* It never originates from anything the caller can influence — no verb argument, no write
|
|
860
|
+
* body — so a module may treat it as trustworthy caller identity and stamp it onto writes.
|
|
861
|
+
*
|
|
862
|
+
* Absent when no session owns the dispatch: registry matching and permission pre-checks
|
|
863
|
+
* resolve a URI outside any verb call.
|
|
864
|
+
*/
|
|
865
|
+
readonly sessionId?: string;
|
|
866
|
+
/**
|
|
867
|
+
* WHO the dispatching session acts as, stamped by the host at the same dispatch site as
|
|
868
|
+
* {@link UriResolveContext.sessionId} and just as un-influenceable by the caller — so a module
|
|
869
|
+
* writing to a store it owns can record the actor without the agent being able to choose one.
|
|
870
|
+
*
|
|
871
|
+
* Free text minted by the host's own runtime (Bonsai's form is `user`, `subagent`,
|
|
872
|
+
* `system/<surface>`, `followup/<surface>`) rather than a closed union: the surface half is the
|
|
873
|
+
* host's vocabulary, and a second enumeration of it here would drift from the first.
|
|
874
|
+
*
|
|
875
|
+
* Absent whenever the host has nothing to say — no session owns the dispatch, or the session
|
|
876
|
+
* predates the host recording an origin. A module must then omit the actor rather than assume
|
|
877
|
+
* one; an invented actor written into a durable artifact can never be walked back.
|
|
878
|
+
*/
|
|
879
|
+
readonly actor?: string;
|
|
880
|
+
/**
|
|
881
|
+
* Identity of the tool invocation that owns this dispatch, stamped by the host from its
|
|
882
|
+
* execution frame. Like `sessionId`, this is never accepted from URI arguments or payloads.
|
|
883
|
+
* Absent for dispatches that do not run inside a session-owned tool invocation.
|
|
884
|
+
*/
|
|
885
|
+
readonly invocation?: {
|
|
886
|
+
readonly toolCallId: string;
|
|
887
|
+
readonly sessionId: string;
|
|
888
|
+
readonly origin: "model" | "host";
|
|
889
|
+
/**
|
|
890
|
+
* The daemon-assigned id of the run driving this invocation, when the host's own execution
|
|
891
|
+
* frame carried one. Absent means the frame carried none — never a reason to guess one: a
|
|
892
|
+
* module recording this onto a durable artifact must treat absence as unresolved provenance,
|
|
893
|
+
* not as "no run was active".
|
|
894
|
+
*/
|
|
895
|
+
readonly runId?: string;
|
|
896
|
+
/** The registered name of the tool making this call, when the host's frame carried one. */
|
|
897
|
+
readonly toolName?: string;
|
|
898
|
+
};
|
|
899
|
+
/**
|
|
900
|
+
* An OPAQUE, host-captured context for the mutation this dispatch is about to make —
|
|
901
|
+
* the artifact-provenance counterpart of `sessionId`/`actor`, and stamped at the same
|
|
902
|
+
* un-influenceable dispatch site.
|
|
903
|
+
*
|
|
904
|
+
* The host composes it from facts a caller cannot supply: which session is acting, the
|
|
905
|
+
* run driving it, the tool invocation, and whatever the host resolved about how that
|
|
906
|
+
* session came to exist. The kernel treats it as an uninterpreted JSON value — it never
|
|
907
|
+
* reads a field, only checks that the value is lossless JSON before it crosses the
|
|
908
|
+
* dispatch boundary — so this layer stays ignorant of any one product's provenance
|
|
909
|
+
* semantics. A module that owns a durable artifact carries it to its store and validates
|
|
910
|
+
* it against its OWN schema at the point it persists, where the target revision is known.
|
|
911
|
+
*
|
|
912
|
+
* Absent means the host captured nothing for this dispatch (a read, a host with no
|
|
913
|
+
* capture resolver, or a capture that failed) — never a claim that there was nothing to
|
|
914
|
+
* capture. Present only on mutating dispatches (`write`/`edit`/`delete`); reads never pay
|
|
915
|
+
* for it.
|
|
916
|
+
*/
|
|
917
|
+
readonly captureContext?: Readonly<Record<string, unknown>>;
|
|
918
|
+
/**
|
|
919
|
+
* Requested read shape. A module may ignore this and return its normal read; honoring
|
|
920
|
+
* it means returning an `ObservationMaterial` via `observationResource(...)` instead.
|
|
921
|
+
* Opt-in only — there is no advertisement surface or capability flag.
|
|
922
|
+
*/
|
|
923
|
+
readonly format?: UriReadFormat;
|
|
924
|
+
/**
|
|
925
|
+
* Host-provided writable data root for the OWNING extension of the module handling this call —
|
|
926
|
+
* structurally identical to the per-extension `paths` a tool/handler context already receives, so
|
|
927
|
+
* a module authored against both surfaces reads `ctx.paths?.dataDir` uniformly. Lets a URI module
|
|
928
|
+
* own durable local state (a JSON store, a small file tree) instead of the host constructing and
|
|
929
|
+
* injecting it. Host-populated after dispatch selects a module and keyed to that module's owner;
|
|
930
|
+
* always absent during matching, and absent for modules with no owning extension (builtins) or a
|
|
931
|
+
* host that wires no per-module data dir. Unlike a tool context, the host only NAMES this path for
|
|
932
|
+
* a URI module and does NOT pre-create the directory — create it on first write and tolerate its
|
|
933
|
+
* absence on read.
|
|
934
|
+
*/
|
|
935
|
+
readonly paths?: {
|
|
936
|
+
readonly dataDir: string;
|
|
937
|
+
};
|
|
938
|
+
/**
|
|
939
|
+
* What this session last saw of the resource, handed to every mutation: the
|
|
940
|
+
* module's own `RawResourceMetadata.revision` from the last read, else the
|
|
941
|
+
* host's content digest of what that read returned. Never model input. A
|
|
942
|
+
* module holding the current content compares with `assertResourceUnchanged`;
|
|
943
|
+
* absent means the host requires no witness for this call and the module
|
|
944
|
+
* proceeds as before.
|
|
945
|
+
*/
|
|
946
|
+
readonly expectedRevision?: string;
|
|
947
|
+
/** Host marks a mediated session that enforces its private revision witness ledger. */
|
|
948
|
+
readonly requiresRevisionWitness?: boolean;
|
|
949
|
+
/** Host-derived descriptor for a top-level copied resource; absent for inline writes. */
|
|
950
|
+
readonly writeSource?: UriSourceDescriptor;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
declare interface UriResolvedAuth {
|
|
954
|
+
readonly connection?: UriConnection;
|
|
955
|
+
/** Present only for verb handlers of a module declaring `requiresAuth`; absent during matching. */
|
|
956
|
+
readonly credential?: UriResolvedCredential;
|
|
957
|
+
/** Present for handlers gated by a non-injectable external-CLI readiness scheme. */
|
|
958
|
+
readonly externalCli?: UriExternalCliRunner;
|
|
959
|
+
/** Opaque host metadata; not a credential channel. */
|
|
960
|
+
readonly metadata?: Record<string, unknown>;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
declare interface UriResolvedCredential {
|
|
964
|
+
/** Bearer for OAuth schemes, apiKey for api-key schemes. Host-resolved and refreshed. */
|
|
965
|
+
readonly accessToken: string;
|
|
966
|
+
readonly accountId: string;
|
|
967
|
+
readonly schemeId: string;
|
|
968
|
+
readonly scopes?: readonly string[];
|
|
969
|
+
/**
|
|
970
|
+
* Every value of a multi-field api-key credential, keyed by the scheme's declared field id
|
|
971
|
+
* (`accessToken` mirrors the primary field). Absent for single-secret schemes.
|
|
972
|
+
*/
|
|
973
|
+
readonly fields?: Readonly<Record<string, string>>;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
declare interface UriResourceDescription {
|
|
977
|
+
readonly uri: string;
|
|
978
|
+
/** Absent when the caller should retain its existing label. */
|
|
979
|
+
readonly title?: string;
|
|
980
|
+
/** Provider-owned public URL when the resource also has a web address. */
|
|
981
|
+
readonly sourceUrl?: string;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* What a settled call touched, as a person would name it.
|
|
986
|
+
*
|
|
987
|
+
* `name` is the resource itself (`#lane-analytics`). `section` is the part of it the address
|
|
988
|
+
* reaches into (`thread`), and is absent when the address is the resource.
|
|
989
|
+
*/
|
|
990
|
+
declare interface UriResourceLabel {
|
|
991
|
+
readonly name: string;
|
|
992
|
+
readonly section?: string;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/** The call a module is asked to label. */
|
|
996
|
+
declare interface UriResourceLabelRequest {
|
|
997
|
+
readonly operation: UriOperation;
|
|
998
|
+
/** The dispatch address: selector-stripped, the exact form the module's verb handler received. */
|
|
999
|
+
readonly uri: string;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
declare interface UriSchemeClaim {
|
|
1003
|
+
readonly kind: "scheme";
|
|
1004
|
+
readonly scheme: string;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
declare interface UriSearchItem {
|
|
1008
|
+
readonly uri: string;
|
|
1009
|
+
readonly title?: string;
|
|
1010
|
+
readonly summary?: string;
|
|
1011
|
+
/** Provider resource MIME type; absent when the source does not report one. */
|
|
1012
|
+
readonly sourceMimeType?: string;
|
|
1013
|
+
readonly score?: number;
|
|
1014
|
+
readonly reason?: string;
|
|
1015
|
+
readonly operations?: readonly UriOperation[];
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
declare interface UriSearchParams {
|
|
1019
|
+
readonly query: string;
|
|
1020
|
+
readonly limit?: number;
|
|
1021
|
+
readonly cursor?: string;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
declare interface UriSearchResult {
|
|
1025
|
+
readonly uri: string;
|
|
1026
|
+
readonly query: string;
|
|
1027
|
+
readonly items: readonly UriSearchItem[];
|
|
1028
|
+
readonly nextCursor?: string;
|
|
1029
|
+
/**
|
|
1030
|
+
* Optional result-set metadata, mirroring {@link UriListResult.metadata}. Lets a
|
|
1031
|
+
* search surface completeness signals such as {@link UriListMetadata.incompleteSearch}
|
|
1032
|
+
* so the caller knows the matches may be partial.
|
|
1033
|
+
*/
|
|
1034
|
+
readonly metadata?: UriListMetadata;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* What a copied resource IS, minus its bytes: the identity half of a mediated
|
|
1039
|
+
* source. The host derives it once (filename inferred from the source address,
|
|
1040
|
+
* `mimeType` carried from the source module's own `RawResource.mimeType`) and
|
|
1041
|
+
* delivers it on both byte-bearing write hooks — inside each `UriWriteSource`,
|
|
1042
|
+
* and as the standalone third argument to `writeBytes` — so a remote sink can
|
|
1043
|
+
* name and type what it stores without re-deriving either from raw bytes.
|
|
1044
|
+
*/
|
|
1045
|
+
declare interface UriSourceDescriptor {
|
|
1046
|
+
readonly uri: string;
|
|
1047
|
+
readonly filename: string;
|
|
1048
|
+
readonly mimeType?: string;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
declare interface UriTemplate {
|
|
1052
|
+
readonly uri: string;
|
|
1053
|
+
readonly description: string;
|
|
1054
|
+
readonly operations?: readonly UriOperation[];
|
|
1055
|
+
/**
|
|
1056
|
+
* Per-operation effect docs for this route, keyed by operation. A route
|
|
1057
|
+
* whose shared {@link description} spans several verbs ("Read, edit, or
|
|
1058
|
+
* trash a thread") is ambiguous for any surface that groups by verb — a
|
|
1059
|
+
* permission view must not describe `read` with a sentence that mentions
|
|
1060
|
+
* trashing. Each entry says what THAT operation concretely does at THIS
|
|
1061
|
+
* route; operations without an entry fall back to the shared description.
|
|
1062
|
+
* Additive and optional — existing templates are unaffected.
|
|
1063
|
+
*/
|
|
1064
|
+
readonly operationDocs?: Partial<Record<UriOperation, string>>;
|
|
1065
|
+
/**
|
|
1066
|
+
* Per-operation default permission for this route, keyed by operation.
|
|
1067
|
+
* When present, overrides the module-level {@link UriPermissionDefaults}
|
|
1068
|
+
* for the named operations at this specific route (resource-glob scoped).
|
|
1069
|
+
* Undeclared operations fall back to the module-level default, then to
|
|
1070
|
+
* `"allow"` (fail-open).
|
|
1071
|
+
*/
|
|
1072
|
+
readonly operationDefaults?: Partial<Record<UriOperation, UriPermissionDefault>>;
|
|
1073
|
+
/**
|
|
1074
|
+
* Parameters are DERIVED from the address pattern by `deriveTemplateParameters`
|
|
1075
|
+
* (`template-route.ts`): every `<placeholder>` path segment and every `?key=<value>`
|
|
1076
|
+
* query key becomes one. Author an entry only to add a description, a tighter schema,
|
|
1077
|
+
* or examples; it overrides the derived entry with the same name. An authored name
|
|
1078
|
+
* that is not a placeholder in `uri` is a lint failure, not a hidden extra.
|
|
1079
|
+
*/
|
|
1080
|
+
readonly parameters?: readonly UriParameter[];
|
|
1081
|
+
/**
|
|
1082
|
+
* The payload contract for each mutating verb at THIS route, built with `payload()`
|
|
1083
|
+
* from the same Zod validator the handler parses with. A contract without a `schema`
|
|
1084
|
+
* is the typed "unstructured" declaration (raw text, YAML, a file body) and must be
|
|
1085
|
+
* true of the handler. This is the only place a route's write or edit shape is
|
|
1086
|
+
* disclosed; `help` renders it at the route and the tool catalog derives its facets
|
|
1087
|
+
* from it.
|
|
1088
|
+
*/
|
|
1089
|
+
readonly accepts?: Partial<Record<"write" | "edit", UriPayloadContract>>;
|
|
1090
|
+
/** What `delete` does at this route and whether it can be undone. Required by lint on
|
|
1091
|
+
* every route that lists `delete`. */
|
|
1092
|
+
readonly deleteEffect?: UriDeleteEffect;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
declare interface UriValidationMessage {
|
|
1096
|
+
readonly path?: string;
|
|
1097
|
+
readonly message: string;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* Author-declared, human-facing documentation of what each supported verb
|
|
1102
|
+
* CONCRETELY does against the provider — the capability half of a module's
|
|
1103
|
+
* boolean verb-support declaration. Written for a permission/capability
|
|
1104
|
+
* surface ("what am I allowing?"), not for the model: one plain sentence per
|
|
1105
|
+
* verb naming the real-world effect ("Sends mail, creates/updates drafts,
|
|
1106
|
+
* applies label changes"), never wire mechanics or URI shapes. Verbs the
|
|
1107
|
+
* module does not support are omitted; at runtime a supported verb with no
|
|
1108
|
+
* entry simply renders undocumented (fail-open metadata) — but for a plugin's
|
|
1109
|
+
* `kay.agent` URI modules, `auditPluginDisclosure` (`@bonsai/plugin-sdk/
|
|
1110
|
+
* disclosure`) enforces coverage of every supported verb at authoring/load
|
|
1111
|
+
* time.
|
|
1112
|
+
*
|
|
1113
|
+
* Lives here in the protocol layer (beside {@link UriTemplate.operationDocs},
|
|
1114
|
+
* its per-route sibling) so both `@herd/uri-extensions`' `UriExtensionModule`
|
|
1115
|
+
* and herd-agent's kernel `UriModule` can carry it without inverting the
|
|
1116
|
+
* `@herd/uri` ← `@herd/uri-extensions` dependency.
|
|
1117
|
+
*/
|
|
1118
|
+
declare interface UriVerbDocs {
|
|
1119
|
+
/** What a `read` of this address space returns (also covers `help`). */
|
|
1120
|
+
readonly read?: string;
|
|
1121
|
+
/** What `list` enumerates, when it differs meaningfully from `read`. */
|
|
1122
|
+
readonly list?: string;
|
|
1123
|
+
/** What `search` queries, when it differs meaningfully from `read`. */
|
|
1124
|
+
readonly search?: string;
|
|
1125
|
+
/** What a `write` creates or overwrites at the provider. */
|
|
1126
|
+
readonly write?: string;
|
|
1127
|
+
/** What an `edit` changes in place at the provider. */
|
|
1128
|
+
readonly edit?: string;
|
|
1129
|
+
/** What a `delete` destroys or removes at the provider (and how recoverable it is). */
|
|
1130
|
+
readonly delete?: string;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
declare interface UriVerbSupport {
|
|
1134
|
+
readonly readable: boolean;
|
|
1135
|
+
readonly writable: boolean;
|
|
1136
|
+
readonly editable: boolean;
|
|
1137
|
+
readonly deletable?: boolean;
|
|
1138
|
+
readonly listable: boolean;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
/** A mediated resource supplied beside structured write content without entering model context. */
|
|
1142
|
+
declare interface UriWriteSource extends UriSourceDescriptor {
|
|
1143
|
+
readonly content: string | Uint8Array;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
declare interface UrlPatternClaim {
|
|
1147
|
+
readonly kind: "urlPattern";
|
|
1148
|
+
readonly pattern: UriPatternInit;
|
|
1149
|
+
readonly normalizeTo?: string;
|
|
1150
|
+
readonly examples?: readonly string[];
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/** The claim shape a module declares, sourced from the module contract rather than re-declared. */
|
|
1154
|
+
export declare type VendoredMcpClaim = NonNullable<UriExtensionModule["claims"]>[number];
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Everything a vendored-MCP plugin's URI module is, expressed as data.
|
|
1158
|
+
*
|
|
1159
|
+
* The plugin package supplies one of these and gets back a conformant {@link UriExtensionModule};
|
|
1160
|
+
* it writes no read projection, no help document, and no route parsing. That is deliberate — this
|
|
1161
|
+
* kit exists because five pilot plugins were about to become five copies of one 460-line module,
|
|
1162
|
+
* and ~40 more are queued behind them.
|
|
1163
|
+
*/
|
|
1164
|
+
export declare interface VendoredMcpDescriptor {
|
|
1165
|
+
/** Global module id, e.g. `supabase.resources`. Matches the manifest's resolved uriModule id. */
|
|
1166
|
+
readonly moduleId: string;
|
|
1167
|
+
/** The plugin namespace and canonical scheme, e.g. `supabase`. */
|
|
1168
|
+
readonly namespace: string;
|
|
1169
|
+
/** The vendor's display name, e.g. `Supabase`. */
|
|
1170
|
+
readonly displayName: string;
|
|
1171
|
+
/**
|
|
1172
|
+
* What one of these resources IS, in the user's words, e.g. `Supabase project`. Keep it equal
|
|
1173
|
+
* to the manifest's `referencePresentations[].resourceKind` so the pill and the card agree.
|
|
1174
|
+
*/
|
|
1175
|
+
readonly resourceKind: string;
|
|
1176
|
+
/** One sentence for the module description and the agent hint. Clamped at 220 chars upstream. */
|
|
1177
|
+
readonly summary: string;
|
|
1178
|
+
/**
|
|
1179
|
+
* The public-web `urlPattern` claims that recognise this vendor's links. The scheme claim for
|
|
1180
|
+
* {@link namespace} is added by the factory, so a descriptor can never forget the one claim the
|
|
1181
|
+
* disclosure floor requires.
|
|
1182
|
+
*/
|
|
1183
|
+
readonly claims: readonly VendoredMcpClaim[];
|
|
1184
|
+
/** The canonical shapes this module addresses. At least one. */
|
|
1185
|
+
readonly routes: readonly VendoredMcpRoute[];
|
|
1186
|
+
/** Up to 8 keywords that should surface this module. */
|
|
1187
|
+
readonly triggerKeywords: readonly string[];
|
|
1188
|
+
/** The vendored MCP server's flat name, exactly as keyed in the manifest's `mcpServers`. */
|
|
1189
|
+
readonly mcpServerName: string;
|
|
1190
|
+
/** One line naming what the vendor's MCP tools cover, shown on every read card. */
|
|
1191
|
+
readonly mcpSummary: string;
|
|
1192
|
+
/** The plugin's own skill local ids, primer first. */
|
|
1193
|
+
readonly skills: readonly string[];
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* One addressable resource shape, as the PAIR that makes the whole pattern work: the canonical
|
|
1198
|
+
* `<ns>://…` URI Bonsai stores, and the public web URL that URI came from and opens back to.
|
|
1199
|
+
*
|
|
1200
|
+
* Both templates use the same `:name` capture syntax and MUST name exactly the same captures —
|
|
1201
|
+
* {@link createVendoredMcpUriModule} throws otherwise. That symmetry is the point: a canonical
|
|
1202
|
+
* URI carrying an id the web URL drops is a pill that cannot be opened, and a web URL naming a
|
|
1203
|
+
* capture the canonical URI never captured renders a literal `:pageId` into the user's browser.
|
|
1204
|
+
* Both are silent in a type system and loud here.
|
|
1205
|
+
*/
|
|
1206
|
+
export declare interface VendoredMcpRoute {
|
|
1207
|
+
/** Canonical URI template, e.g. `supabase://project/:projectRef`. Needs at least one path segment. */
|
|
1208
|
+
readonly uri: string;
|
|
1209
|
+
/** Public web URL template over the same captures, e.g. `https://supabase.com/dashboard/project/:projectRef`. */
|
|
1210
|
+
readonly webUrl: string;
|
|
1211
|
+
/** One line naming what this address is, for `help()` templates and the read card. */
|
|
1212
|
+
readonly description: string;
|
|
1213
|
+
/** A concrete canonical URI for `help()`'s examples. Must match {@link uri}. */
|
|
1214
|
+
readonly example: string;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
export { }
|