caplets 0.16.0 → 0.17.1

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.
Files changed (3) hide show
  1. package/README.md +87 -0
  2. package/dist/index.js +2480 -824
  3. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -6,464 +6,25 @@ import { execFileSync, spawn } from "node:child_process";
6
6
  import process$1, { stdin, stdout } from "node:process";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { homedir, tmpdir } from "node:os";
9
- import { PassThrough } from "node:stream";
10
- import { createServer } from "node:http";
9
+ import { PassThrough, Readable } from "node:stream";
10
+ import { STATUS_CODES, createServer } from "node:http";
11
11
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
12
12
  import { Buffer as Buffer$1 } from "node:buffer";
13
13
  import { createInterface } from "node:readline/promises";
14
- import { createServer as createServer$1 } from "http";
15
- import { Http2ServerRequest, constants as constants$1 } from "http2";
16
- import { Readable } from "stream";
17
- import crypto$1 from "crypto";
18
- //#region ../core/dist/generated-tool-input-schema.js
19
- const operations = [
20
- "get_caplet",
21
- "check_backend",
22
- "list_tools",
23
- "search_tools",
24
- "get_tool",
25
- "call_tool"
26
- ];
27
- const generatedToolInputDescriptions = {
28
- operation: "Wrapper operation: get_caplet, check_backend, list_tools, search_tools, get_tool, or call_tool.",
29
- query: "Required for search_tools only.",
30
- limit: "Optional search_tools result limit.",
31
- tool: "Exact downstream tool name for get_tool or call_tool.",
32
- arguments: "Required JSON object for call_tool arguments/downstream inputs.",
33
- fields: "Optional call_tool structured output paths when outputSchema allows it."
14
+ import { Http2ServerRequest, constants as constants$1 } from "node:http2";
15
+ //#region \0rolldown/runtime.js
16
+ var __defProp$1 = Object.defineProperty;
17
+ var __exportAll$1 = (all, no_symbols) => {
18
+ let target = {};
19
+ for (var name in all) __defProp$1(target, name, {
20
+ get: all[name],
21
+ enumerable: true
22
+ });
23
+ if (!no_symbols) __defProp$1(target, Symbol.toStringTag, { value: "Module" });
24
+ return target;
34
25
  };
35
- function generatedToolInputJsonSchema() {
36
- return {
37
- type: "object",
38
- properties: {
39
- operation: {
40
- type: "string",
41
- enum: operations,
42
- description: generatedToolInputDescriptions.operation
43
- },
44
- query: {
45
- type: "string",
46
- description: generatedToolInputDescriptions.query
47
- },
48
- limit: {
49
- type: "integer",
50
- minimum: 1,
51
- description: generatedToolInputDescriptions.limit
52
- },
53
- tool: {
54
- type: "string",
55
- description: generatedToolInputDescriptions.tool
56
- },
57
- arguments: {
58
- type: "object",
59
- description: generatedToolInputDescriptions.arguments
60
- },
61
- fields: {
62
- type: "array",
63
- items: {
64
- type: "string",
65
- minLength: 1
66
- },
67
- minItems: 1,
68
- description: generatedToolInputDescriptions.fields
69
- }
70
- },
71
- required: ["operation"],
72
- additionalProperties: false
73
- };
74
- }
75
26
  //#endregion
76
- //#region ../core/dist/options-CJEOqS87.js
77
- var __create = Object.create;
78
- var __defProp = Object.defineProperty;
79
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
80
- var __getOwnPropNames = Object.getOwnPropertyNames;
81
- var __getProtoOf = Object.getPrototypeOf;
82
- var __hasOwnProp = Object.prototype.hasOwnProperty;
83
- var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
84
- var __copyProps = (to, from, except, desc) => {
85
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
86
- key = keys[i];
87
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
88
- get: ((k) => from[k]).bind(null, key),
89
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
90
- });
91
- }
92
- return to;
93
- };
94
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
95
- value: mod,
96
- enumerable: true
97
- }) : target, mod));
98
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
99
- const CAPLETS_ERROR_CODES = [
100
- "CONFIG_NOT_FOUND",
101
- "CONFIG_EXISTS",
102
- "CONFIG_INVALID",
103
- "REQUEST_INVALID",
104
- "SERVER_NOT_FOUND",
105
- "SERVER_UNAVAILABLE",
106
- "SERVER_START_TIMEOUT",
107
- "UNKNOWN_OPERATION",
108
- "TOOL_NOT_FOUND",
109
- "TOOL_CALL_TIMEOUT",
110
- "AUTH_REQUIRED",
111
- "AUTH_FAILED",
112
- "AUTH_REFRESH_FAILED",
113
- "DOWNSTREAM_PROTOCOL_ERROR",
114
- "DOWNSTREAM_TOOL_ERROR",
115
- "UNSUPPORTED_TRANSPORT",
116
- "INTERNAL_ERROR"
117
- ];
118
- var CapletsError = class extends Error {
119
- code;
120
- details;
121
- constructor(code, message, details) {
122
- super(message);
123
- this.name = "CapletsError";
124
- this.code = code;
125
- this.details = details;
126
- }
127
- };
128
- const SECRET_KEY_PATTERN = /(token|secret|authorization|auth|api[-_]?key|password|credential|clientsecret|client_secret|code|refresh)/i;
129
- const SECRET_VALUE_PATTERN = /(bearer\s+)[a-z0-9._~+/=-]+|([?&](?:access_token|refresh_token|token|code)=)[^&\s]+/gi;
130
- function redactSecrets(value) {
131
- if (typeof value === "string") return value.replace(SECRET_VALUE_PATTERN, "$1$2[REDACTED]");
132
- if (Array.isArray(value)) return value.map((item) => redactSecrets(item));
133
- if (value && typeof value === "object") {
134
- const redacted = {};
135
- for (const [key, nested] of Object.entries(value)) redacted[key] = SECRET_KEY_PATTERN.test(key) ? "[REDACTED]" : redactSecrets(nested);
136
- return redacted;
137
- }
138
- return value;
139
- }
140
- function toSafeError(error, fallback = "INTERNAL_ERROR") {
141
- if (error instanceof CapletsError) return {
142
- code: error.code,
143
- message: String(redactSecrets(error.message)),
144
- ...error.details === void 0 ? {} : { details: redactSecrets(error.details) }
145
- };
146
- if (error instanceof Error) return {
147
- code: fallback,
148
- message: String(redactSecrets(error.message))
149
- };
150
- return {
151
- code: fallback,
152
- message: String(redactSecrets(error))
153
- };
154
- }
155
- function errorResult(error, fallback) {
156
- const safe = toSafeError(error, fallback);
157
- return {
158
- isError: true,
159
- content: [{
160
- type: "text",
161
- text: `${safe.code}: ${safe.message}`
162
- }],
163
- structuredContent: { error: safe }
164
- };
165
- }
166
- function textContent(text) {
167
- return text ? [{
168
- type: "text",
169
- text
170
- }] : [];
171
- }
172
- function compactJsonText(value, maxLength = 600) {
173
- return compactText(JSON.stringify(value) ?? String(value), maxLength);
174
- }
175
- function compactText(value, maxLength = 600) {
176
- const collapsed = value.replace(/\s+/gu, " ").trim();
177
- return collapsed.length > maxLength ? `${collapsed.slice(0, maxLength - 1).trimEnd()}…` : collapsed;
178
- }
179
- function resultKeys(value) {
180
- if (!value || typeof value !== "object" || Array.isArray(value)) return "scalar result";
181
- const keys = Object.keys(value).filter((key) => key !== "elapsedMs");
182
- return keys.length > 0 ? `structured keys: ${keys.join(", ")}` : "empty structured result";
183
- }
184
- function statusSummary(value) {
185
- if (!value || typeof value !== "object" || Array.isArray(value)) return compactJsonText(value);
186
- const record = value;
187
- return [
188
- typeof record.status === "number" ? `status ${record.status}` : void 0,
189
- typeof record.statusText === "string" && record.statusText ? record.statusText : void 0,
190
- typeof record.exitCode === "number" ? `exit ${record.exitCode}` : void 0,
191
- "body" in record ? "body" : void 0,
192
- "json" in record ? "json" : void 0,
193
- typeof record.stdout === "string" && record.stdout ? "stdout" : void 0,
194
- typeof record.stderr === "string" && record.stderr ? "stderr" : void 0
195
- ].filter((part) => Boolean(part)).join("; ") || resultKeys(record);
196
- }
197
- function compactStructuredContent(value) {
198
- return textContent(statusSummary(value));
199
- }
200
- function searchToolList(tools, query, limit, compact) {
201
- const tokens = query.toLocaleLowerCase().split(/\s+/).filter(Boolean);
202
- return tools.filter((tool) => {
203
- const haystack = `${tool.name}\n${tool.description ?? ""}`.toLocaleLowerCase();
204
- return tokens.some((token) => haystack.includes(token));
205
- }).sort((left, right) => left.name.localeCompare(right.name)).slice(0, limit).map(compact);
206
- }
207
- const DEFAULT_INPUT_SCHEMA$1 = {
208
- type: "object",
209
- additionalProperties: true
210
- };
211
- var CliToolsManager = class {
212
- registry;
213
- constructor(registry) {
214
- this.registry = registry;
215
- }
216
- updateRegistry(registry) {
217
- this.registry = registry;
218
- }
219
- invalidate(_serverId) {}
220
- async checkTools(config) {
221
- const startedAt = Date.now();
222
- try {
223
- for (const action of actionsFor(config)) {
224
- const cwdTemplate = action.cwd ?? config.cwd;
225
- if (cwdTemplate && !cwdTemplate.includes("$input")) {
226
- if (!existsSync(interpolateRequiredString(cwdTemplate, {}, "cwd"))) throw new CapletsError("CONFIG_INVALID", `CLI cwd does not exist for ${config.server}/${action.name}`);
227
- }
228
- if (!action.command.includes("$input")) resolveCommandPath(action.command);
229
- }
230
- this.registry.setStatus(config.server, "available");
231
- return {
232
- id: config.server,
233
- status: "available",
234
- toolCount: Object.keys(config.actions).length,
235
- elapsedMs: Date.now() - startedAt
236
- };
237
- } catch (error) {
238
- const safe = toSafeError(error, "SERVER_UNAVAILABLE");
239
- this.registry.setStatus(config.server, "unavailable", safe);
240
- return {
241
- id: config.server,
242
- status: "unavailable",
243
- elapsedMs: Date.now() - startedAt,
244
- error: safe
245
- };
246
- }
247
- }
248
- async listTools(config) {
249
- return actionsFor(config).map((action) => this.toTool(action));
250
- }
251
- async getTool(config, toolName) {
252
- return this.toTool(getAction(config, toolName));
253
- }
254
- async callTool(config, toolName, args) {
255
- const action = getAction(config, toolName);
256
- validateInput(action, args);
257
- const execution = resolveExecution(config, action, args);
258
- const startedAt = Date.now();
259
- const controller = new AbortController();
260
- const timeout = setTimeout(() => controller.abort(), execution.timeoutMs);
261
- try {
262
- const result = await spawnCommand(execution, controller.signal, () => Date.now() - startedAt);
263
- const structured = parseStructuredResult(action, result, result.exitCode !== 0);
264
- return {
265
- content: compactStructuredContent(structured),
266
- structuredContent: structured,
267
- isError: result.exitCode !== 0
268
- };
269
- } catch (error) {
270
- if (isAbortError$1(error)) throw new CapletsError("TOOL_CALL_TIMEOUT", `CLI tool timed out for ${config.server}/${toolName}`);
271
- if (error instanceof CapletsError) throw error;
272
- throw new CapletsError("DOWNSTREAM_TOOL_ERROR", `CLI tool failed for ${config.server}/${toolName}`, toSafeError(error));
273
- } finally {
274
- clearTimeout(timeout);
275
- }
276
- }
277
- compact(config, tool) {
278
- return {
279
- id: config.server,
280
- tool: tool.name,
281
- ...tool.description ? { description: tool.description } : {},
282
- hasInputSchema: Boolean(tool.inputSchema),
283
- hasOutputSchema: Boolean(tool.outputSchema)
284
- };
285
- }
286
- search(config, tools, query, limit) {
287
- return searchToolList(tools, query, limit, (tool) => this.compact(config, tool));
288
- }
289
- toTool(action) {
290
- return {
291
- name: action.name,
292
- ...action.description ? { description: action.description } : {},
293
- inputSchema: action.inputSchema ?? DEFAULT_INPUT_SCHEMA$1,
294
- ...action.outputSchema ? { outputSchema: action.outputSchema } : {},
295
- ...action.annotations ? { annotations: action.annotations } : {}
296
- };
297
- }
298
- };
299
- function actionsFor(config) {
300
- return Object.entries(config.actions).map(([name, action]) => ({
301
- name,
302
- ...action
303
- })).sort((left, right) => left.name.localeCompare(right.name));
304
- }
305
- function getAction(config, toolName) {
306
- const actions = actionsFor(config);
307
- const action = actions.find((candidate) => candidate.name === toolName);
308
- if (!action) throw new CapletsError("TOOL_NOT_FOUND", `Tool ${toolName} was not found on ${config.server}`, {
309
- server: config.server,
310
- tool: toolName,
311
- suggestions: actions.map((candidate) => candidate.name).filter((name) => name.toLocaleLowerCase().includes(toolName.toLocaleLowerCase()[0] ?? "")).slice(0, 5)
312
- });
313
- return action;
314
- }
315
- function resolveExecution(config, action, input) {
316
- const cwd = interpolateString(action.cwd ?? config.cwd, input, "cwd");
317
- if (cwd && !existsSync(cwd)) throw new CapletsError("CONFIG_INVALID", `CLI cwd does not exist for ${config.server}/${action.name}`);
318
- const env = {
319
- ...process.env,
320
- ...resolveEnv(config.env, input),
321
- ...resolveEnv(action.env, input)
322
- };
323
- return {
324
- command: interpolateString(action.command, input, "command") ?? action.command,
325
- args: (action.args ?? []).map((arg, index) => interpolateRequiredString(arg, input, `args.${index}`)),
326
- ...cwd ? { cwd } : {},
327
- env,
328
- timeoutMs: action.timeoutMs ?? config.timeoutMs,
329
- maxOutputBytes: action.maxOutputBytes ?? config.maxOutputBytes
330
- };
331
- }
332
- function resolveEnv(env, input) {
333
- if (!env) return {};
334
- return Object.fromEntries(Object.entries(env).map(([key, value]) => [key, interpolateRequiredString(value, input, `env.${key}`)]));
335
- }
336
- function interpolateString(value, input, field) {
337
- return value === void 0 ? void 0 : interpolateRequiredString(value, input, field);
338
- }
339
- function interpolateRequiredString(value, input, field) {
340
- return value.replace(/\$input(?:\.([A-Za-z0-9_.-]+))?/g, (_match, path) => {
341
- if (!path) throw new CapletsError("REQUEST_INVALID", `CLI ${field} cannot interpolate $input directly`);
342
- const selected = valueAtPath$1(input, path);
343
- if (selected === void 0 || selected === null) throw new CapletsError("REQUEST_INVALID", `CLI ${field} references missing input ${path}`);
344
- if (typeof selected !== "string" && typeof selected !== "number" && typeof selected !== "boolean") throw new CapletsError("REQUEST_INVALID", `CLI ${field} input ${path} must be a string, number, or boolean`);
345
- return String(selected);
346
- });
347
- }
348
- function valueAtPath$1(input, path) {
349
- let current = input;
350
- for (const segment of path.split(".")) {
351
- if (!current || typeof current !== "object" || Array.isArray(current)) return;
352
- current = current[segment];
353
- }
354
- return current;
355
- }
356
- function validateInput(action, input) {
357
- const schema = action.inputSchema;
358
- if (!schema) return;
359
- const required = Array.isArray(schema.required) ? schema.required : [];
360
- for (const key of required) if (typeof key === "string" && (input[key] === void 0 || input[key] === null)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} requires input ${key}`);
361
- const properties = isPlainObject$7(schema.properties) ? schema.properties : {};
362
- for (const [key, property] of Object.entries(properties)) {
363
- if (input[key] === void 0 || !isPlainObject$7(property) || typeof property.type !== "string") continue;
364
- if (!matchesJsonType(input[key], property.type)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} input ${key} must be ${property.type}`);
365
- }
366
- }
367
- function matchesJsonType(value, type) {
368
- switch (type) {
369
- case "string": return typeof value === "string";
370
- case "number":
371
- case "integer": return typeof value === "number" && (type === "number" || Number.isInteger(value));
372
- case "boolean": return typeof value === "boolean";
373
- case "object": return isPlainObject$7(value);
374
- case "array": return Array.isArray(value);
375
- case "null": return value === null;
376
- default: return true;
377
- }
378
- }
379
- function spawnCommand(execution, signal, elapsedMs) {
380
- return new Promise((resolve, reject) => {
381
- let stdout = "";
382
- let stderr = "";
383
- let outputBytes = 0;
384
- const child = spawn(execution.command, execution.args, {
385
- cwd: execution.cwd,
386
- env: execution.env,
387
- shell: false,
388
- signal,
389
- windowsHide: true
390
- });
391
- child.on("error", reject);
392
- const append = (stream, chunk) => {
393
- outputBytes += chunk.byteLength;
394
- if (outputBytes > execution.maxOutputBytes) {
395
- child.kill();
396
- reject(new CapletsError("DOWNSTREAM_TOOL_ERROR", "CLI tool output exceeded byte limit"));
397
- return;
398
- }
399
- if (stream === "stdout") stdout += chunk.toString("utf8");
400
- else stderr += chunk.toString("utf8");
401
- };
402
- child.stdout?.on("data", (chunk) => append("stdout", chunk));
403
- child.stderr?.on("data", (chunk) => append("stderr", chunk));
404
- child.on("close", (exitCode, childSignal) => {
405
- resolve({
406
- exitCode,
407
- signal: childSignal,
408
- stdout,
409
- stderr,
410
- elapsedMs: elapsedMs()
411
- });
412
- });
413
- });
414
- }
415
- function parseStructuredResult(action, result, tolerateInvalidJson = false) {
416
- const structured = {
417
- exitCode: result.exitCode,
418
- stdout: result.stdout,
419
- stderr: result.stderr,
420
- elapsedMs: result.elapsedMs,
421
- ...result.signal ? { signal: result.signal } : {}
422
- };
423
- if (action.output?.type === "json" && result.stdout.trim()) try {
424
- structured.json = JSON.parse(result.stdout);
425
- } catch (error) {
426
- if (tolerateInvalidJson) {
427
- structured.jsonParseError = toSafeError(error);
428
- return structured;
429
- }
430
- throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", `CLI tool ${action.name} stdout was not valid JSON`, toSafeError(error));
431
- }
432
- return structured;
433
- }
434
- function resolveCommandPath(command) {
435
- if (isAbsolute(command) || /[\\/]/.test(command)) {
436
- assertExecutable(command);
437
- return command;
438
- }
439
- for (const directory of (process.env.PATH ?? "").split(delimiter)) {
440
- if (!directory) continue;
441
- const candidate = join(directory, command);
442
- if (isExecutable(candidate)) return candidate;
443
- if (process.platform === "win32") for (const ext of (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")) {
444
- const windowsCandidate = join(directory, `${command}${ext.toLowerCase()}`);
445
- if (isExecutable(windowsCandidate)) return windowsCandidate;
446
- }
447
- }
448
- throw new CapletsError("SERVER_UNAVAILABLE", `CLI command ${command} was not found on PATH`);
449
- }
450
- function assertExecutable(path) {
451
- if (!isExecutable(path)) throw new CapletsError("SERVER_UNAVAILABLE", `CLI command ${path} is not executable`);
452
- }
453
- function isExecutable(path) {
454
- try {
455
- accessSync(path, constants.X_OK);
456
- return true;
457
- } catch {
458
- return false;
459
- }
460
- }
461
- function isAbortError$1(error) {
462
- return error instanceof Error && error.name === "AbortError";
463
- }
464
- function isPlainObject$7(value) {
465
- return value !== null && typeof value === "object" && !Array.isArray(value);
466
- }
27
+ //#region ../core/dist/generated-tool-input-schema-BYoyY-l-.js
467
28
  var _a$1;
468
29
  /** A special constant with type `never` */
469
30
  const NEVER = /* @__PURE__ */ Object.freeze({ status: "aborted" });
@@ -607,7 +168,7 @@ const allowsEval = /* @__PURE__ */ cached(() => {
607
168
  return false;
608
169
  }
609
170
  });
610
- function isPlainObject$6(o) {
171
+ function isPlainObject$8(o) {
611
172
  if (isObject(o) === false) return false;
612
173
  const ctor = o.constructor;
613
174
  if (ctor === void 0) return true;
@@ -618,7 +179,7 @@ function isPlainObject$6(o) {
618
179
  return true;
619
180
  }
620
181
  function shallowClone(o) {
621
- if (isPlainObject$6(o)) return { ...o };
182
+ if (isPlainObject$8(o)) return { ...o };
622
183
  if (Array.isArray(o)) return [...o];
623
184
  if (o instanceof Map) return new Map(o);
624
185
  if (o instanceof Set) return new Set(o);
@@ -701,7 +262,7 @@ function omit(schema, mask) {
701
262
  }));
702
263
  }
703
264
  function extend(schema, shape) {
704
- if (!isPlainObject$6(shape)) throw new Error("Invalid input to extend: expected a plain object");
265
+ if (!isPlainObject$8(shape)) throw new Error("Invalid input to extend: expected a plain object");
705
266
  const checks = schema._zod.def.checks;
706
267
  if (checks && checks.length > 0) {
707
268
  const existingShape = schema._zod.def.shape;
@@ -717,7 +278,7 @@ function extend(schema, shape) {
717
278
  } }));
718
279
  }
719
280
  function safeExtend(schema, shape) {
720
- if (!isPlainObject$6(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
281
+ if (!isPlainObject$8(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
721
282
  return clone(schema, mergeDefs(schema._zod.def, { get shape() {
722
283
  const _shape = {
723
284
  ...schema._zod.def.shape,
@@ -908,7 +469,7 @@ const _parse = (_Err) => (schema, value, _ctx, _params) => {
908
469
  }
909
470
  return result.value;
910
471
  };
911
- const parse$3 = /* @__PURE__ */ _parse($ZodRealError);
472
+ const parse$1 = /* @__PURE__ */ _parse($ZodRealError);
912
473
  const _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
913
474
  const ctx = _ctx ? {
914
475
  ..._ctx,
@@ -945,7 +506,7 @@ const _safeParse = (_Err) => (schema, value, _ctx) => {
945
506
  data: result.value
946
507
  };
947
508
  };
948
- const safeParse$2 = /* @__PURE__ */ _safeParse($ZodRealError);
509
+ const safeParse$1 = /* @__PURE__ */ _safeParse($ZodRealError);
949
510
  const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
950
511
  const ctx = _ctx ? {
951
512
  ..._ctx,
@@ -964,7 +525,7 @@ const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
964
525
  data: result.value
965
526
  };
966
527
  };
967
- const safeParseAsync$2 = /* @__PURE__ */ _safeParseAsync($ZodRealError);
528
+ const safeParseAsync$1 = /* @__PURE__ */ _safeParseAsync($ZodRealError);
968
529
  const _encode = (_Err) => (schema, value, _ctx) => {
969
530
  const ctx = _ctx ? {
970
531
  ..._ctx,
@@ -1063,7 +624,7 @@ const string$1 = (params) => {
1063
624
  return new RegExp(`^${regex}$`);
1064
625
  };
1065
626
  const integer = /^-?\d+$/;
1066
- const number$2 = /^-?\d+(?:\.\d+)?$/;
627
+ const number$1 = /^-?\d+(?:\.\d+)?$/;
1067
628
  const boolean$1 = /^(?:true|false)$/i;
1068
629
  const _null$2 = /^null$/i;
1069
630
  const lowercase = /^[^A-Z]*$/;
@@ -1537,10 +1098,10 @@ const $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
1537
1098
  defineLazy(inst, "~standard", () => ({
1538
1099
  validate: (value) => {
1539
1100
  try {
1540
- const r = safeParse$2(inst, value);
1101
+ const r = safeParse$1(inst, value);
1541
1102
  return r.success ? { value: r.data } : { issues: r.error?.issues };
1542
1103
  } catch (_) {
1543
- return safeParseAsync$2(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues });
1104
+ return safeParseAsync$1(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues });
1544
1105
  }
1545
1106
  },
1546
1107
  vendor: "zod",
@@ -1830,7 +1391,7 @@ const $ZodJWT = /* @__PURE__ */ $constructor("$ZodJWT", (inst, def) => {
1830
1391
  });
1831
1392
  const $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => {
1832
1393
  $ZodType.init(inst, def);
1833
- inst._zod.pattern = inst._zod.bag.pattern ?? number$2;
1394
+ inst._zod.pattern = inst._zod.bag.pattern ?? number$1;
1834
1395
  inst._zod.parse = (payload, _ctx) => {
1835
1396
  if (def.coerce) try {
1836
1397
  payload.value = Number(payload.value);
@@ -2317,7 +1878,7 @@ function mergeValues$1(a, b) {
2317
1878
  valid: true,
2318
1879
  data: a
2319
1880
  };
2320
- if (isPlainObject$6(a) && isPlainObject$6(b)) {
1881
+ if (isPlainObject$8(a) && isPlainObject$8(b)) {
2321
1882
  const bKeys = Object.keys(b);
2322
1883
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
2323
1884
  const newObj = {
@@ -2393,7 +1954,7 @@ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
2393
1954
  $ZodType.init(inst, def);
2394
1955
  inst._zod.parse = (payload, ctx) => {
2395
1956
  const input = payload.value;
2396
- if (!isPlainObject$6(input)) {
1957
+ if (!isPlainObject$8(input)) {
2397
1958
  payload.issues.push({
2398
1959
  expected: "record",
2399
1960
  code: "invalid_type",
@@ -2460,7 +2021,7 @@ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
2460
2021
  issues: []
2461
2022
  }, ctx);
2462
2023
  if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
2463
- if (typeof key === "string" && number$2.test(key) && keyResult.issues.length) {
2024
+ if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) {
2464
2025
  const retryResult = def.keyType._zod.run({
2465
2026
  value: Number(key),
2466
2027
  issues: []
@@ -4135,8 +3696,8 @@ const initializer = (inst, issues) => {
4135
3696
  const ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer, { Parent: Error });
4136
3697
  const parse$2 = /* @__PURE__ */ _parse(ZodRealError);
4137
3698
  const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
4138
- const safeParse$1 = /* @__PURE__ */ _safeParse(ZodRealError);
4139
- const safeParseAsync$1 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
3699
+ const safeParse$2 = /* @__PURE__ */ _safeParse(ZodRealError);
3700
+ const safeParseAsync$2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
4140
3701
  const encode = /* @__PURE__ */ _encode(ZodRealError);
4141
3702
  const decode = /* @__PURE__ */ _decode(ZodRealError);
4142
3703
  const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError);
@@ -4192,9 +3753,9 @@ const ZodType$1 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
4192
3753
  inst.type = def.type;
4193
3754
  Object.defineProperty(inst, "_def", { value: def });
4194
3755
  inst.parse = (data, params) => parse$2(inst, data, params, { callee: inst.parse });
4195
- inst.safeParse = (data, params) => safeParse$1(inst, data, params);
3756
+ inst.safeParse = (data, params) => safeParse$2(inst, data, params);
4196
3757
  inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync });
4197
- inst.safeParseAsync = async (data, params) => safeParseAsync$1(inst, data, params);
3758
+ inst.safeParseAsync = async (data, params) => safeParseAsync$2(inst, data, params);
4198
3759
  inst.spa = inst.safeParseAsync;
4199
3760
  inst.encode = (data, params) => encode(inst, data, params);
4200
3761
  inst.decode = (data, params) => decode(inst, data, params);
@@ -4543,7 +4104,7 @@ const ZodNumber$1 = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
4543
4104
  inst.isFinite = true;
4544
4105
  inst.format = bag.format ?? null;
4545
4106
  });
4546
- function number$1(params) {
4107
+ function number$2(params) {
4547
4108
  return /* @__PURE__ */ _number(ZodNumber$1, params);
4548
4109
  }
4549
4110
  const ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, def) => {
@@ -4989,6 +4550,571 @@ function preprocess(fn, schema) {
4989
4550
  out: schema
4990
4551
  });
4991
4552
  }
4553
+ const operations = [
4554
+ "get_caplet",
4555
+ "check_backend",
4556
+ "list_tools",
4557
+ "search_tools",
4558
+ "get_tool",
4559
+ "call_tool"
4560
+ ];
4561
+ const mcpOperations = [
4562
+ ...operations,
4563
+ "list_resources",
4564
+ "search_resources",
4565
+ "list_resource_templates",
4566
+ "read_resource",
4567
+ "list_prompts",
4568
+ "search_prompts",
4569
+ "get_prompt",
4570
+ "complete"
4571
+ ];
4572
+ const generatedToolInputDescriptions = {
4573
+ operation: "Wrapper operation: get_caplet, check_backend, list_tools, search_tools, get_tool, call_tool. MCP Caplets also expose resources, prompts, and completions.",
4574
+ query: "Required for search operations only.",
4575
+ limit: "Optional list/search result limit.",
4576
+ tool: "Exact downstream tool name for get_tool or call_tool.",
4577
+ arguments: "JSON object for call_tool arguments/downstream inputs or get_prompt arguments.",
4578
+ fields: "Optional call_tool structured output paths when outputSchema allows it.",
4579
+ uri: "Exact downstream resource URI for read_resource.",
4580
+ prompt: "Exact downstream prompt name for get_prompt.",
4581
+ ref: "Completion target reference for complete.",
4582
+ argument: "Completion argument object for complete."
4583
+ };
4584
+ const completionRefSchema = union([object$1({
4585
+ type: literal("prompt"),
4586
+ name: string().min(1)
4587
+ }).strict(), object$1({
4588
+ type: literal("resourceTemplate"),
4589
+ uri: string().min(1)
4590
+ }).strict()]);
4591
+ const completionArgumentSchema = object$1({
4592
+ name: string().min(1),
4593
+ value: string()
4594
+ }).strict();
4595
+ const baseShape = {
4596
+ query: string().optional().describe(generatedToolInputDescriptions.query),
4597
+ limit: number$2().int().positive().optional().describe(generatedToolInputDescriptions.limit),
4598
+ tool: string().optional().describe(generatedToolInputDescriptions.tool),
4599
+ arguments: object$1({}).catchall(any()).optional().describe(generatedToolInputDescriptions.arguments),
4600
+ fields: array(string().min(1)).min(1).optional().describe(generatedToolInputDescriptions.fields)
4601
+ };
4602
+ function generatedToolInputSchemaForCaplet(caplet) {
4603
+ return object$1({
4604
+ operation: (caplet.backend === "mcp" ? _enum(mcpOperations) : _enum(operations)).describe(generatedToolInputDescriptions.operation),
4605
+ ...baseShape,
4606
+ ...caplet.backend === "mcp" ? {
4607
+ uri: string().optional().describe(generatedToolInputDescriptions.uri),
4608
+ prompt: string().optional().describe(generatedToolInputDescriptions.prompt),
4609
+ ref: completionRefSchema.optional().describe(generatedToolInputDescriptions.ref),
4610
+ argument: completionArgumentSchema.optional().describe(generatedToolInputDescriptions.argument)
4611
+ } : {}
4612
+ }).strict();
4613
+ }
4614
+ object$1({
4615
+ operation: _enum(operations).describe(generatedToolInputDescriptions.operation),
4616
+ ...baseShape
4617
+ }).strict();
4618
+ function generatedToolInputJsonSchemaForCaplet(caplet) {
4619
+ const mcp = caplet.backend === "mcp";
4620
+ return {
4621
+ type: "object",
4622
+ properties: {
4623
+ operation: {
4624
+ type: "string",
4625
+ enum: mcp ? mcpOperations : operations,
4626
+ description: generatedToolInputDescriptions.operation
4627
+ },
4628
+ query: {
4629
+ type: "string",
4630
+ description: generatedToolInputDescriptions.query
4631
+ },
4632
+ limit: {
4633
+ type: "integer",
4634
+ minimum: 1,
4635
+ description: generatedToolInputDescriptions.limit
4636
+ },
4637
+ tool: {
4638
+ type: "string",
4639
+ description: generatedToolInputDescriptions.tool
4640
+ },
4641
+ arguments: {
4642
+ type: "object",
4643
+ description: generatedToolInputDescriptions.arguments
4644
+ },
4645
+ fields: {
4646
+ type: "array",
4647
+ items: {
4648
+ type: "string",
4649
+ minLength: 1
4650
+ },
4651
+ minItems: 1,
4652
+ description: generatedToolInputDescriptions.fields
4653
+ },
4654
+ ...mcp ? {
4655
+ uri: {
4656
+ type: "string",
4657
+ description: generatedToolInputDescriptions.uri
4658
+ },
4659
+ prompt: {
4660
+ type: "string",
4661
+ description: generatedToolInputDescriptions.prompt
4662
+ },
4663
+ ref: {
4664
+ oneOf: [{
4665
+ type: "object",
4666
+ properties: {
4667
+ type: { const: "prompt" },
4668
+ name: {
4669
+ type: "string",
4670
+ minLength: 1
4671
+ }
4672
+ },
4673
+ required: ["type", "name"],
4674
+ additionalProperties: false
4675
+ }, {
4676
+ type: "object",
4677
+ properties: {
4678
+ type: { const: "resourceTemplate" },
4679
+ uri: {
4680
+ type: "string",
4681
+ minLength: 1
4682
+ }
4683
+ },
4684
+ required: ["type", "uri"],
4685
+ additionalProperties: false
4686
+ }],
4687
+ description: generatedToolInputDescriptions.ref
4688
+ },
4689
+ argument: {
4690
+ type: "object",
4691
+ properties: {
4692
+ name: {
4693
+ type: "string",
4694
+ minLength: 1
4695
+ },
4696
+ value: { type: "string" }
4697
+ },
4698
+ required: ["name", "value"],
4699
+ additionalProperties: false,
4700
+ description: generatedToolInputDescriptions.argument
4701
+ }
4702
+ } : {}
4703
+ },
4704
+ required: ["operation"],
4705
+ additionalProperties: false
4706
+ };
4707
+ }
4708
+ function generatedToolInputJsonSchema() {
4709
+ return generatedToolInputJsonSchemaForCaplet({ backend: "tool" });
4710
+ }
4711
+ //#endregion
4712
+ //#region ../core/dist/options-BqibJVxq.js
4713
+ var __create = Object.create;
4714
+ var __defProp = Object.defineProperty;
4715
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4716
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4717
+ var __getProtoOf = Object.getPrototypeOf;
4718
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4719
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4720
+ var __exportAll = (all, no_symbols) => {
4721
+ let target = {};
4722
+ for (var name in all) __defProp(target, name, {
4723
+ get: all[name],
4724
+ enumerable: true
4725
+ });
4726
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
4727
+ return target;
4728
+ };
4729
+ var __copyProps = (to, from, except, desc) => {
4730
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
4731
+ key = keys[i];
4732
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
4733
+ get: ((k) => from[k]).bind(null, key),
4734
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
4735
+ });
4736
+ }
4737
+ return to;
4738
+ };
4739
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
4740
+ value: mod,
4741
+ enumerable: true
4742
+ }) : target, mod));
4743
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4744
+ const CAPLETS_ERROR_CODES = [
4745
+ "CONFIG_NOT_FOUND",
4746
+ "CONFIG_EXISTS",
4747
+ "CONFIG_INVALID",
4748
+ "REQUEST_INVALID",
4749
+ "SERVER_NOT_FOUND",
4750
+ "SERVER_UNAVAILABLE",
4751
+ "SERVER_START_TIMEOUT",
4752
+ "UNKNOWN_OPERATION",
4753
+ "TOOL_NOT_FOUND",
4754
+ "TOOL_CALL_TIMEOUT",
4755
+ "AUTH_REQUIRED",
4756
+ "AUTH_FAILED",
4757
+ "AUTH_REFRESH_FAILED",
4758
+ "DOWNSTREAM_PROTOCOL_ERROR",
4759
+ "DOWNSTREAM_TOOL_ERROR",
4760
+ "UNSUPPORTED_OPERATION",
4761
+ "UNSUPPORTED_CAPABILITY",
4762
+ "PROMPT_NOT_FOUND",
4763
+ "DOWNSTREAM_RESOURCE_ERROR",
4764
+ "DOWNSTREAM_PROMPT_ERROR",
4765
+ "DOWNSTREAM_COMPLETION_ERROR",
4766
+ "UNSUPPORTED_TRANSPORT",
4767
+ "INTERNAL_ERROR"
4768
+ ];
4769
+ var CapletsError = class extends Error {
4770
+ code;
4771
+ details;
4772
+ constructor(code, message, details) {
4773
+ super(message);
4774
+ this.name = "CapletsError";
4775
+ this.code = code;
4776
+ this.details = details;
4777
+ }
4778
+ };
4779
+ const SECRET_KEY_PATTERN = /(token|secret|authorization|auth|api[-_]?key|password|credential|clientsecret|client_secret|code|refresh)/i;
4780
+ const SECRET_VALUE_PATTERN = /(bearer\s+)[a-z0-9._~+/=-]+|([?&](?:access_token|refresh_token|token|code)=)[^&\s]+/gi;
4781
+ function redactSecrets(value) {
4782
+ if (typeof value === "string") return value.replace(SECRET_VALUE_PATTERN, "$1$2[REDACTED]");
4783
+ if (Array.isArray(value)) return value.map((item) => redactSecrets(item));
4784
+ if (value && typeof value === "object") {
4785
+ const redacted = {};
4786
+ for (const [key, nested] of Object.entries(value)) redacted[key] = SECRET_KEY_PATTERN.test(key) ? "[REDACTED]" : redactSecrets(nested);
4787
+ return redacted;
4788
+ }
4789
+ return value;
4790
+ }
4791
+ function toSafeError(error, fallback = "INTERNAL_ERROR") {
4792
+ if (error instanceof CapletsError) return {
4793
+ code: error.code,
4794
+ message: String(redactSecrets(error.message)),
4795
+ ...error.details === void 0 ? {} : { details: redactSecrets(error.details) }
4796
+ };
4797
+ if (error instanceof Error) return {
4798
+ code: fallback,
4799
+ message: String(redactSecrets(error.message))
4800
+ };
4801
+ return {
4802
+ code: fallback,
4803
+ message: String(redactSecrets(error))
4804
+ };
4805
+ }
4806
+ function errorResult(error, fallback) {
4807
+ const safe = toSafeError(error, fallback);
4808
+ return {
4809
+ isError: true,
4810
+ content: [{
4811
+ type: "text",
4812
+ text: `${safe.code}: ${safe.message}`
4813
+ }],
4814
+ structuredContent: { error: safe }
4815
+ };
4816
+ }
4817
+ function textContent(text) {
4818
+ return text ? [{
4819
+ type: "text",
4820
+ text
4821
+ }] : [];
4822
+ }
4823
+ function compactJsonText(value, maxLength = 600) {
4824
+ return compactText(JSON.stringify(value) ?? String(value), maxLength);
4825
+ }
4826
+ function compactText(value, maxLength = 600) {
4827
+ const collapsed = value.replace(/\s+/gu, " ").trim();
4828
+ return collapsed.length > maxLength ? `${collapsed.slice(0, maxLength - 1).trimEnd()}…` : collapsed;
4829
+ }
4830
+ function resultKeys(value) {
4831
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "scalar result";
4832
+ const keys = Object.keys(value).filter((key) => key !== "elapsedMs");
4833
+ return keys.length > 0 ? `structured keys: ${keys.join(", ")}` : "empty structured result";
4834
+ }
4835
+ function statusSummary(value) {
4836
+ if (!value || typeof value !== "object" || Array.isArray(value)) return compactJsonText(value);
4837
+ const record = value;
4838
+ return [
4839
+ typeof record.status === "number" ? `status ${record.status}` : void 0,
4840
+ typeof record.statusText === "string" && record.statusText ? record.statusText : void 0,
4841
+ typeof record.exitCode === "number" ? `exit ${record.exitCode}` : void 0,
4842
+ "body" in record ? "body" : void 0,
4843
+ "json" in record ? "json" : void 0,
4844
+ typeof record.stdout === "string" && record.stdout ? "stdout" : void 0,
4845
+ typeof record.stderr === "string" && record.stderr ? "stderr" : void 0
4846
+ ].filter((part) => Boolean(part)).join("; ") || resultKeys(record);
4847
+ }
4848
+ function compactStructuredContent(value) {
4849
+ return textContent(statusSummary(value));
4850
+ }
4851
+ function searchToolList(tools, query, limit, compact) {
4852
+ const tokens = query.toLocaleLowerCase().split(/\s+/).filter(Boolean);
4853
+ return tools.filter((tool) => {
4854
+ const haystack = `${tool.name}\n${tool.description ?? ""}`.toLocaleLowerCase();
4855
+ return tokens.some((token) => haystack.includes(token));
4856
+ }).sort((left, right) => left.name.localeCompare(right.name)).slice(0, limit).map(compact);
4857
+ }
4858
+ const DEFAULT_INPUT_SCHEMA$1 = {
4859
+ type: "object",
4860
+ additionalProperties: true
4861
+ };
4862
+ var CliToolsManager = class {
4863
+ registry;
4864
+ constructor(registry) {
4865
+ this.registry = registry;
4866
+ }
4867
+ updateRegistry(registry) {
4868
+ this.registry = registry;
4869
+ }
4870
+ invalidate(_serverId) {}
4871
+ async checkTools(config) {
4872
+ const startedAt = Date.now();
4873
+ try {
4874
+ for (const action of actionsFor(config)) {
4875
+ const cwdTemplate = action.cwd ?? config.cwd;
4876
+ if (cwdTemplate && !cwdTemplate.includes("$input")) {
4877
+ if (!existsSync(interpolateRequiredString(cwdTemplate, {}, "cwd"))) throw new CapletsError("CONFIG_INVALID", `CLI cwd does not exist for ${config.server}/${action.name}`);
4878
+ }
4879
+ if (!action.command.includes("$input")) resolveCommandPath(action.command);
4880
+ }
4881
+ this.registry.setStatus(config.server, "available");
4882
+ return {
4883
+ id: config.server,
4884
+ status: "available",
4885
+ toolCount: Object.keys(config.actions).length,
4886
+ elapsedMs: Date.now() - startedAt
4887
+ };
4888
+ } catch (error) {
4889
+ const safe = toSafeError(error, "SERVER_UNAVAILABLE");
4890
+ this.registry.setStatus(config.server, "unavailable", safe);
4891
+ return {
4892
+ id: config.server,
4893
+ status: "unavailable",
4894
+ elapsedMs: Date.now() - startedAt,
4895
+ error: safe
4896
+ };
4897
+ }
4898
+ }
4899
+ async listTools(config) {
4900
+ return actionsFor(config).map((action) => this.toTool(action));
4901
+ }
4902
+ async getTool(config, toolName) {
4903
+ return this.toTool(getAction(config, toolName));
4904
+ }
4905
+ async callTool(config, toolName, args) {
4906
+ const action = getAction(config, toolName);
4907
+ validateInput(action, args);
4908
+ const execution = resolveExecution(config, action, args);
4909
+ const startedAt = Date.now();
4910
+ const controller = new AbortController();
4911
+ const timeout = setTimeout(() => controller.abort(), execution.timeoutMs);
4912
+ try {
4913
+ const result = await spawnCommand(execution, controller.signal, () => Date.now() - startedAt);
4914
+ const structured = parseStructuredResult(action, result, result.exitCode !== 0);
4915
+ return {
4916
+ content: compactStructuredContent(structured),
4917
+ structuredContent: structured,
4918
+ isError: result.exitCode !== 0
4919
+ };
4920
+ } catch (error) {
4921
+ if (isAbortError$1(error)) throw new CapletsError("TOOL_CALL_TIMEOUT", `CLI tool timed out for ${config.server}/${toolName}`);
4922
+ if (error instanceof CapletsError) throw error;
4923
+ throw new CapletsError("DOWNSTREAM_TOOL_ERROR", `CLI tool failed for ${config.server}/${toolName}`, toSafeError(error));
4924
+ } finally {
4925
+ clearTimeout(timeout);
4926
+ }
4927
+ }
4928
+ compact(config, tool) {
4929
+ return {
4930
+ id: config.server,
4931
+ tool: tool.name,
4932
+ ...tool.description ? { description: tool.description } : {},
4933
+ hasInputSchema: Boolean(tool.inputSchema),
4934
+ hasOutputSchema: Boolean(tool.outputSchema)
4935
+ };
4936
+ }
4937
+ search(config, tools, query, limit) {
4938
+ return searchToolList(tools, query, limit, (tool) => this.compact(config, tool));
4939
+ }
4940
+ toTool(action) {
4941
+ return {
4942
+ name: action.name,
4943
+ ...action.description ? { description: action.description } : {},
4944
+ inputSchema: action.inputSchema ?? DEFAULT_INPUT_SCHEMA$1,
4945
+ ...action.outputSchema ? { outputSchema: action.outputSchema } : {},
4946
+ ...action.annotations ? { annotations: action.annotations } : {}
4947
+ };
4948
+ }
4949
+ };
4950
+ function actionsFor(config) {
4951
+ return Object.entries(config.actions).map(([name, action]) => ({
4952
+ name,
4953
+ ...action
4954
+ })).sort((left, right) => left.name.localeCompare(right.name));
4955
+ }
4956
+ function getAction(config, toolName) {
4957
+ const actions = actionsFor(config);
4958
+ const action = actions.find((candidate) => candidate.name === toolName);
4959
+ if (!action) throw new CapletsError("TOOL_NOT_FOUND", `Tool ${toolName} was not found on ${config.server}`, {
4960
+ server: config.server,
4961
+ tool: toolName,
4962
+ suggestions: actions.map((candidate) => candidate.name).filter((name) => name.toLocaleLowerCase().includes(toolName.toLocaleLowerCase()[0] ?? "")).slice(0, 5)
4963
+ });
4964
+ return action;
4965
+ }
4966
+ function resolveExecution(config, action, input) {
4967
+ const cwd = interpolateString(action.cwd ?? config.cwd, input, "cwd");
4968
+ if (cwd && !existsSync(cwd)) throw new CapletsError("CONFIG_INVALID", `CLI cwd does not exist for ${config.server}/${action.name}`);
4969
+ const env = {
4970
+ ...process.env,
4971
+ ...resolveEnv(config.env, input),
4972
+ ...resolveEnv(action.env, input)
4973
+ };
4974
+ return {
4975
+ command: interpolateString(action.command, input, "command") ?? action.command,
4976
+ args: (action.args ?? []).map((arg, index) => interpolateRequiredString(arg, input, `args.${index}`)),
4977
+ ...cwd ? { cwd } : {},
4978
+ env,
4979
+ timeoutMs: action.timeoutMs ?? config.timeoutMs,
4980
+ maxOutputBytes: action.maxOutputBytes ?? config.maxOutputBytes
4981
+ };
4982
+ }
4983
+ function resolveEnv(env, input) {
4984
+ if (!env) return {};
4985
+ return Object.fromEntries(Object.entries(env).map(([key, value]) => [key, interpolateRequiredString(value, input, `env.${key}`)]));
4986
+ }
4987
+ function interpolateString(value, input, field) {
4988
+ return value === void 0 ? void 0 : interpolateRequiredString(value, input, field);
4989
+ }
4990
+ function interpolateRequiredString(value, input, field) {
4991
+ return value.replace(/\$input(?:\.([A-Za-z0-9_.-]+))?/g, (_match, path) => {
4992
+ if (!path) throw new CapletsError("REQUEST_INVALID", `CLI ${field} cannot interpolate $input directly`);
4993
+ const selected = valueAtPath$1(input, path);
4994
+ if (selected === void 0 || selected === null) throw new CapletsError("REQUEST_INVALID", `CLI ${field} references missing input ${path}`);
4995
+ if (typeof selected !== "string" && typeof selected !== "number" && typeof selected !== "boolean") throw new CapletsError("REQUEST_INVALID", `CLI ${field} input ${path} must be a string, number, or boolean`);
4996
+ return String(selected);
4997
+ });
4998
+ }
4999
+ function valueAtPath$1(input, path) {
5000
+ let current = input;
5001
+ for (const segment of path.split(".")) {
5002
+ if (!current || typeof current !== "object" || Array.isArray(current)) return;
5003
+ current = current[segment];
5004
+ }
5005
+ return current;
5006
+ }
5007
+ function validateInput(action, input) {
5008
+ const schema = action.inputSchema;
5009
+ if (!schema) return;
5010
+ const required = Array.isArray(schema.required) ? schema.required : [];
5011
+ for (const key of required) if (typeof key === "string" && (input[key] === void 0 || input[key] === null)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} requires input ${key}`);
5012
+ const properties = isPlainObject$6(schema.properties) ? schema.properties : {};
5013
+ for (const [key, property] of Object.entries(properties)) {
5014
+ if (input[key] === void 0 || !isPlainObject$6(property) || typeof property.type !== "string") continue;
5015
+ if (!matchesJsonType(input[key], property.type)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} input ${key} must be ${property.type}`);
5016
+ }
5017
+ }
5018
+ function matchesJsonType(value, type) {
5019
+ switch (type) {
5020
+ case "string": return typeof value === "string";
5021
+ case "number":
5022
+ case "integer": return typeof value === "number" && (type === "number" || Number.isInteger(value));
5023
+ case "boolean": return typeof value === "boolean";
5024
+ case "object": return isPlainObject$6(value);
5025
+ case "array": return Array.isArray(value);
5026
+ case "null": return value === null;
5027
+ default: return true;
5028
+ }
5029
+ }
5030
+ function spawnCommand(execution, signal, elapsedMs) {
5031
+ return new Promise((resolve, reject) => {
5032
+ let stdout = "";
5033
+ let stderr = "";
5034
+ let outputBytes = 0;
5035
+ const child = spawn(execution.command, execution.args, {
5036
+ cwd: execution.cwd,
5037
+ env: execution.env,
5038
+ shell: false,
5039
+ signal,
5040
+ windowsHide: true
5041
+ });
5042
+ child.on("error", reject);
5043
+ const append = (stream, chunk) => {
5044
+ outputBytes += chunk.byteLength;
5045
+ if (outputBytes > execution.maxOutputBytes) {
5046
+ child.kill();
5047
+ reject(new CapletsError("DOWNSTREAM_TOOL_ERROR", "CLI tool output exceeded byte limit"));
5048
+ return;
5049
+ }
5050
+ if (stream === "stdout") stdout += chunk.toString("utf8");
5051
+ else stderr += chunk.toString("utf8");
5052
+ };
5053
+ child.stdout?.on("data", (chunk) => append("stdout", chunk));
5054
+ child.stderr?.on("data", (chunk) => append("stderr", chunk));
5055
+ child.on("close", (exitCode, childSignal) => {
5056
+ resolve({
5057
+ exitCode,
5058
+ signal: childSignal,
5059
+ stdout,
5060
+ stderr,
5061
+ elapsedMs: elapsedMs()
5062
+ });
5063
+ });
5064
+ });
5065
+ }
5066
+ function parseStructuredResult(action, result, tolerateInvalidJson = false) {
5067
+ const structured = {
5068
+ exitCode: result.exitCode,
5069
+ stdout: result.stdout,
5070
+ stderr: result.stderr,
5071
+ elapsedMs: result.elapsedMs,
5072
+ ...result.signal ? { signal: result.signal } : {}
5073
+ };
5074
+ if (action.output?.type === "json" && result.stdout.trim()) try {
5075
+ structured.json = JSON.parse(result.stdout);
5076
+ } catch (error) {
5077
+ if (tolerateInvalidJson) {
5078
+ structured.jsonParseError = toSafeError(error);
5079
+ return structured;
5080
+ }
5081
+ throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", `CLI tool ${action.name} stdout was not valid JSON`, toSafeError(error));
5082
+ }
5083
+ return structured;
5084
+ }
5085
+ function resolveCommandPath(command) {
5086
+ if (isAbsolute(command) || /[\\/]/.test(command)) {
5087
+ assertExecutable(command);
5088
+ return command;
5089
+ }
5090
+ for (const directory of (process.env.PATH ?? "").split(delimiter)) {
5091
+ if (!directory) continue;
5092
+ const candidate = join(directory, command);
5093
+ if (isExecutable(candidate)) return candidate;
5094
+ if (process.platform === "win32") for (const ext of (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")) {
5095
+ const windowsCandidate = join(directory, `${command}${ext.toLowerCase()}`);
5096
+ if (isExecutable(windowsCandidate)) return windowsCandidate;
5097
+ }
5098
+ }
5099
+ throw new CapletsError("SERVER_UNAVAILABLE", `CLI command ${command} was not found on PATH`);
5100
+ }
5101
+ function assertExecutable(path) {
5102
+ if (!isExecutable(path)) throw new CapletsError("SERVER_UNAVAILABLE", `CLI command ${path} is not executable`);
5103
+ }
5104
+ function isExecutable(path) {
5105
+ try {
5106
+ accessSync(path, constants.X_OK);
5107
+ return true;
5108
+ } catch {
5109
+ return false;
5110
+ }
5111
+ }
5112
+ function isAbortError$1(error) {
5113
+ return error instanceof Error && error.name === "AbortError";
5114
+ }
5115
+ function isPlainObject$6(value) {
5116
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5117
+ }
4992
5118
  /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
4993
5119
  const ZodIssueCode$1 = {
4994
5120
  invalid_type: "invalid_type",
@@ -12509,9 +12635,9 @@ const capletMcpServerSchema = object$1({
12509
12635
  cwd: string().min(1).optional().describe("Working directory for stdio servers."),
12510
12636
  url: string().min(1).optional().describe("Remote MCP server URL for http or sse transport."),
12511
12637
  auth: capletRemoteAuthSchema.optional(),
12512
- startupTimeoutMs: number$1().int().positive().optional().describe("Timeout in milliseconds for starting or checking a downstream server."),
12513
- callTimeoutMs: number$1().int().positive().optional().describe("Timeout in milliseconds for downstream tool calls."),
12514
- toolCacheTtlMs: number$1().int().nonnegative().optional().describe("Milliseconds downstream tool metadata stays fresh. Set 0 to refresh every time."),
12638
+ startupTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for starting or checking a downstream server."),
12639
+ callTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for downstream tool calls."),
12640
+ toolCacheTtlMs: number$2().int().nonnegative().optional().describe("Milliseconds downstream tool metadata stays fresh. Set 0 to refresh every time."),
12515
12641
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery and do not start its MCP server.")
12516
12642
  }).strict().superRefine((server, ctx) => {
12517
12643
  const effectiveTransport = server.transport ?? (server.command ? "stdio" : void 0);
@@ -12566,8 +12692,8 @@ const capletOpenApiEndpointSchema = object$1({
12566
12692
  specUrl: string().min(1).optional().describe("Remote OpenAPI specification URL."),
12567
12693
  baseUrl: string().min(1).optional().describe("Override base URL for OpenAPI requests."),
12568
12694
  auth: capletEndpointAuthSchema.describe("Explicit OpenAPI request auth config. Use {\"type\":\"none\"} for public APIs."),
12569
- requestTimeoutMs: number$1().int().positive().optional().describe("Timeout in milliseconds for OpenAPI HTTP requests."),
12570
- operationCacheTtlMs: number$1().int().nonnegative().optional().describe("Milliseconds OpenAPI operation metadata stays fresh. Set 0 to refresh every time."),
12695
+ requestTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for OpenAPI HTTP requests."),
12696
+ operationCacheTtlMs: number$2().int().nonnegative().optional().describe("Milliseconds OpenAPI operation metadata stays fresh. Set 0 to refresh every time."),
12571
12697
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12572
12698
  }).strict().superRefine((endpoint, ctx) => {
12573
12699
  if (Boolean(endpoint.specPath) === Boolean(endpoint.specUrl)) ctx.addIssue({
@@ -12604,9 +12730,9 @@ const capletGraphQlEndpointSchema = object$1({
12604
12730
  introspection: literal(true).optional().describe("Load schema through endpoint introspection."),
12605
12731
  operations: record(string().regex(SERVER_ID_PATTERN), capletGraphQlOperationSchema).optional().describe("Configured GraphQL operations keyed by stable tool name."),
12606
12732
  auth: capletEndpointAuthSchema.describe("Explicit GraphQL request auth config. Use {\"type\":\"none\"} for public APIs."),
12607
- requestTimeoutMs: number$1().int().positive().optional().describe("Timeout in milliseconds for GraphQL HTTP requests."),
12608
- operationCacheTtlMs: number$1().int().nonnegative().optional().describe("Milliseconds GraphQL operation metadata stays fresh. Set 0 to refresh every time."),
12609
- selectionDepth: number$1().int().positive().max(5).optional().describe("Maximum depth for auto-generated GraphQL selection sets."),
12733
+ requestTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for GraphQL HTTP requests."),
12734
+ operationCacheTtlMs: number$2().int().nonnegative().optional().describe("Milliseconds GraphQL operation metadata stays fresh. Set 0 to refresh every time."),
12735
+ selectionDepth: number$2().int().positive().max(5).optional().describe("Maximum depth for auto-generated GraphQL selection sets."),
12610
12736
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12611
12737
  }).strict().superRefine((endpoint, ctx) => {
12612
12738
  if (Number(Boolean(endpoint.schemaPath)) + Number(Boolean(endpoint.schemaUrl)) + Number(endpoint.introspection === true) !== 1) ctx.addIssue({
@@ -12627,7 +12753,7 @@ const capletGraphQlEndpointSchema = object$1({
12627
12753
  });
12628
12754
  const httpScalarMappingSchema$1 = record(string(), union([
12629
12755
  string(),
12630
- number$1(),
12756
+ number$2(),
12631
12757
  boolean()
12632
12758
  ]));
12633
12759
  const capletHttpActionSchema = object$1({
@@ -12655,8 +12781,8 @@ const capletHttpApiSchema = object$1({
12655
12781
  baseUrl: string().min(1).regex(HTTP_BASE_URL_PATTERN, "HTTP API baseUrl must not include credentials, query, or fragment").describe("Base URL for HTTP action requests."),
12656
12782
  auth: capletEndpointAuthSchema.describe("Explicit HTTP API request auth config. Use {\"type\":\"none\"} for public APIs."),
12657
12783
  actions: record(string().regex(SERVER_ID_PATTERN), capletHttpActionSchema).refine((actions) => Object.keys(actions).length > 0, "HTTP API must define at least one action").describe("Configured HTTP actions keyed by stable tool name."),
12658
- requestTimeoutMs: number$1().int().positive().optional().describe("Timeout in milliseconds for HTTP action requests."),
12659
- maxResponseBytes: number$1().int().positive().optional().describe("Maximum HTTP action response body bytes to read."),
12784
+ requestTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for HTTP action requests."),
12785
+ maxResponseBytes: number$2().int().positive().optional().describe("Maximum HTTP action response body bytes to read."),
12660
12786
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12661
12787
  }).strict().superRefine((api, ctx) => {
12662
12788
  if (api.baseUrl && !hasEnvReference$1(api.baseUrl) && !isAllowedHttpBaseUrl(api.baseUrl)) ctx.addIssue({
@@ -12686,8 +12812,8 @@ const capletCliToolActionSchema = object$1({
12686
12812
  args: array(string()).optional().describe("Arguments passed to the command."),
12687
12813
  env: record(string(), string()).optional().describe("Additional environment variables."),
12688
12814
  cwd: string().min(1).optional().describe("Working directory for this action."),
12689
- timeoutMs: number$1().int().positive().optional(),
12690
- maxOutputBytes: number$1().int().positive().optional(),
12815
+ timeoutMs: number$2().int().positive().optional(),
12816
+ maxOutputBytes: number$2().int().positive().optional(),
12691
12817
  output: capletCliToolOutputSchema.optional(),
12692
12818
  annotations: capletCliToolAnnotationsSchema.optional()
12693
12819
  }).strict();
@@ -12695,16 +12821,16 @@ const capletCliToolsSchema = object$1({
12695
12821
  actions: record(string().regex(SERVER_ID_PATTERN), capletCliToolActionSchema).refine((actions) => Object.keys(actions).length > 0, "CLI tools backend must define at least one action").describe("Configured CLI actions keyed by stable tool name."),
12696
12822
  cwd: string().min(1).optional().describe("Default working directory for CLI actions."),
12697
12823
  env: record(string(), string()).optional().describe("Default environment variables."),
12698
- timeoutMs: number$1().int().positive().optional(),
12699
- maxOutputBytes: number$1().int().positive().optional(),
12824
+ timeoutMs: number$2().int().positive().optional(),
12825
+ maxOutputBytes: number$2().int().positive().optional(),
12700
12826
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12701
12827
  }).strict();
12702
12828
  const capletSetSchema = object$1({
12703
12829
  configPath: string().min(1).optional().describe("Child Caplets config.json path."),
12704
12830
  capletsRoot: string().min(1).optional().describe("Child Markdown Caplets root directory."),
12705
- defaultSearchLimit: number$1().int().positive().optional(),
12706
- maxSearchLimit: number$1().int().positive().max(50).optional(),
12707
- toolCacheTtlMs: number$1().int().nonnegative().optional(),
12831
+ defaultSearchLimit: number$2().int().positive().optional(),
12832
+ maxSearchLimit: number$2().int().positive().max(50).optional(),
12833
+ toolCacheTtlMs: number$2().int().nonnegative().optional(),
12708
12834
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12709
12835
  }).strict().superRefine((set, ctx) => {
12710
12836
  if (!set.configPath && !set.capletsRoot) ctx.addIssue({
@@ -12942,14 +13068,24 @@ function defaultStateBaseDir(env = process.env, home = homedir(), platform = pro
12942
13068
  if (platform === "win32") return env.LOCALAPPDATA && win32.isAbsolute(env.LOCALAPPDATA) ? env.LOCALAPPDATA : win32.join(home, "AppData", "Local");
12943
13069
  return env.XDG_STATE_HOME && posix.isAbsolute(env.XDG_STATE_HOME) ? env.XDG_STATE_HOME : posix.join(home, ".local", "state");
12944
13070
  }
13071
+ function defaultCacheBaseDir(env = process.env, home = homedir(), platform = process.platform) {
13072
+ if (platform === "win32") return env.LOCALAPPDATA && win32.isAbsolute(env.LOCALAPPDATA) ? env.LOCALAPPDATA : win32.join(home, "AppData", "Local");
13073
+ if (platform === "darwin") return posix.join(home, "Library", "Caches");
13074
+ return env.XDG_CACHE_HOME && posix.isAbsolute(env.XDG_CACHE_HOME) ? env.XDG_CACHE_HOME : posix.join(home, ".cache");
13075
+ }
12945
13076
  function defaultConfigPath(env = process.env, home = homedir(), platform = process.platform) {
12946
13077
  return (platform === "win32" ? win32.join : posix.join)(defaultConfigBaseDir(env, home, platform), "caplets", "config.json");
12947
13078
  }
12948
13079
  function defaultAuthDir(env = process.env, home = homedir(), platform = process.platform) {
12949
13080
  return (platform === "win32" ? win32.join : posix.join)(defaultStateBaseDir(env, home, platform), "caplets", "auth");
12950
13081
  }
13082
+ function defaultCompletionCacheDir(env = process.env, home = homedir(), platform = process.platform) {
13083
+ const pathJoin = platform === "win32" ? win32.join : posix.join;
13084
+ return platform === "win32" ? pathJoin(defaultCacheBaseDir(env, home, platform), "caplets", "cache", "completions") : pathJoin(defaultCacheBaseDir(env, home, platform), "caplets", "completions");
13085
+ }
12951
13086
  const DEFAULT_CONFIG_PATH = defaultConfigPath();
12952
13087
  const DEFAULT_AUTH_DIR = defaultAuthDir();
13088
+ const DEFAULT_COMPLETION_CACHE_DIR = defaultCompletionCacheDir();
12953
13089
  const PROJECT_CONFIG_FILE = join(".caplets", "config.json");
12954
13090
  function resolveConfigPath(path) {
12955
13091
  return path ?? DEFAULT_CONFIG_PATH;
@@ -13062,9 +13198,9 @@ const publicServerSchema = object$1({
13062
13198
  url: string().url().optional().describe("Remote MCP server URL for http or sse transport."),
13063
13199
  auth: remoteAuthSchema.optional(),
13064
13200
  tags: array(string().trim().min(1).max(80)).optional(),
13065
- startupTimeoutMs: number$1().int().positive().default(1e4).describe("Timeout in milliseconds for starting or checking a downstream server."),
13066
- callTimeoutMs: number$1().int().positive().default(6e4).describe("Timeout in milliseconds for downstream tool calls."),
13067
- toolCacheTtlMs: number$1().int().nonnegative().default(3e4).describe("Milliseconds downstream tool metadata stays fresh. Set 0 to refresh every time."),
13201
+ startupTimeoutMs: number$2().int().positive().default(1e4).describe("Timeout in milliseconds for starting or checking a downstream server."),
13202
+ callTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for downstream tool calls."),
13203
+ toolCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds downstream tool metadata stays fresh. Set 0 to refresh every time."),
13068
13204
  disabled: boolean().default(false).describe("When true, omit this server from Caplets discovery and do not start it.")
13069
13205
  }).strict();
13070
13206
  const normalizedServerSchema = publicServerSchema.extend({ body: string().optional() });
@@ -13076,8 +13212,8 @@ const publicOpenApiEndpointSchema = object$1({
13076
13212
  baseUrl: string().url().optional().describe("Override base URL for OpenAPI requests."),
13077
13213
  auth: openApiAuthSchema.describe("Explicit OpenAPI request auth config. Use {\"type\":\"none\"} for public APIs."),
13078
13214
  tags: array(string().trim().min(1).max(80)).optional(),
13079
- requestTimeoutMs: number$1().int().positive().default(6e4).describe("Timeout in milliseconds for OpenAPI HTTP requests."),
13080
- operationCacheTtlMs: number$1().int().nonnegative().default(3e4).describe("Milliseconds OpenAPI operation metadata stays fresh. Set 0 to refresh every time."),
13215
+ requestTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for OpenAPI HTTP requests."),
13216
+ operationCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds OpenAPI operation metadata stays fresh. Set 0 to refresh every time."),
13081
13217
  disabled: boolean().default(false).describe("When true, omit this OpenAPI Caplet from discovery.")
13082
13218
  }).strict();
13083
13219
  const normalizedOpenApiEndpointSchema = publicOpenApiEndpointSchema.extend({ body: string().optional() });
@@ -13102,9 +13238,9 @@ const publicGraphQlEndpointSchema = object$1({
13102
13238
  operations: record(string().regex(SERVER_ID_PATTERN), graphQlOperationSchema).optional().describe("Configured GraphQL operations keyed by stable tool name."),
13103
13239
  auth: openApiAuthSchema.describe("Explicit GraphQL request auth config. Use {\"type\":\"none\"} for public APIs."),
13104
13240
  tags: array(string().trim().min(1).max(80)).optional(),
13105
- requestTimeoutMs: number$1().int().positive().default(6e4).describe("Timeout in milliseconds for GraphQL HTTP requests."),
13106
- operationCacheTtlMs: number$1().int().nonnegative().default(3e4).describe("Milliseconds GraphQL operation metadata stays fresh. Set 0 to refresh every time."),
13107
- selectionDepth: number$1().int().positive().max(5).default(2).describe("Maximum depth for auto-generated GraphQL selection sets."),
13241
+ requestTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for GraphQL HTTP requests."),
13242
+ operationCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds GraphQL operation metadata stays fresh. Set 0 to refresh every time."),
13243
+ selectionDepth: number$2().int().positive().max(5).default(2).describe("Maximum depth for auto-generated GraphQL selection sets."),
13108
13244
  disabled: boolean().default(false).describe("When true, omit this GraphQL Caplet.")
13109
13245
  }).strict().superRefine((endpoint, ctx) => {
13110
13246
  if (Number(Boolean(endpoint.schemaPath)) + Number(Boolean(endpoint.schemaUrl)) + Number(endpoint.introspection === true) !== 1) ctx.addIssue({
@@ -13115,7 +13251,7 @@ const publicGraphQlEndpointSchema = object$1({
13115
13251
  const normalizedGraphQlEndpointSchema = publicGraphQlEndpointSchema.extend({ body: string().optional() });
13116
13252
  const httpScalarMappingSchema = record(string(), union([
13117
13253
  string(),
13118
- number$1(),
13254
+ number$2(),
13119
13255
  boolean()
13120
13256
  ]));
13121
13257
  const httpActionSchema = object$1({
@@ -13147,8 +13283,8 @@ const publicHttpApiSchema = object$1({
13147
13283
  auth: openApiAuthSchema.describe("Explicit HTTP API request auth config. Use {\"type\":\"none\"} for public APIs."),
13148
13284
  actions: record(string().regex(SERVER_ID_PATTERN), httpActionSchema).refine((actions) => Object.keys(actions).length > 0, "HTTP API must define at least one action").describe("Configured HTTP actions keyed by stable tool name."),
13149
13285
  tags: array(string().trim().min(1).max(80)).optional(),
13150
- requestTimeoutMs: number$1().int().positive().default(6e4).describe("Timeout in milliseconds for HTTP action requests."),
13151
- maxResponseBytes: number$1().int().positive().default(2e5).describe("Maximum HTTP action response body bytes to read."),
13286
+ requestTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for HTTP action requests."),
13287
+ maxResponseBytes: number$2().int().positive().default(2e5).describe("Maximum HTTP action response body bytes to read."),
13152
13288
  disabled: boolean().default(false).describe("When true, omit this HTTP API Caplet.")
13153
13289
  }).strict();
13154
13290
  const normalizedHttpApiSchema = publicHttpApiSchema.extend({ body: string().optional() });
@@ -13167,8 +13303,8 @@ const cliToolActionSchema = object$1({
13167
13303
  args: array(string()).optional().describe("Arguments passed to the command."),
13168
13304
  env: record(string(), string()).optional().describe("Additional environment variables for the command."),
13169
13305
  cwd: string().min(1).optional().describe("Working directory for this action."),
13170
- timeoutMs: number$1().int().positive().optional().describe("Command timeout in milliseconds."),
13171
- maxOutputBytes: number$1().int().positive().optional().describe("Maximum combined stdout and stderr bytes to keep."),
13306
+ timeoutMs: number$2().int().positive().optional().describe("Command timeout in milliseconds."),
13307
+ maxOutputBytes: number$2().int().positive().optional().describe("Maximum combined stdout and stderr bytes to keep."),
13172
13308
  output: cliToolOutputSchema.optional(),
13173
13309
  annotations: cliToolAnnotationsSchema.optional()
13174
13310
  }).strict();
@@ -13179,8 +13315,8 @@ const publicCliToolsSchema = object$1({
13179
13315
  cwd: string().min(1).optional().describe("Default working directory for CLI actions."),
13180
13316
  env: record(string(), string()).optional().describe("Default environment variables for CLI actions."),
13181
13317
  tags: array(string().trim().min(1).max(80)).optional(),
13182
- timeoutMs: number$1().int().positive().default(6e4).describe("Default timeout in milliseconds for CLI actions."),
13183
- maxOutputBytes: number$1().int().positive().default(2e5).describe("Default maximum combined stdout and stderr bytes to keep."),
13318
+ timeoutMs: number$2().int().positive().default(6e4).describe("Default timeout in milliseconds for CLI actions."),
13319
+ maxOutputBytes: number$2().int().positive().default(2e5).describe("Default maximum combined stdout and stderr bytes to keep."),
13184
13320
  disabled: boolean().default(false).describe("When true, omit this CLI tools Caplet.")
13185
13321
  }).strict();
13186
13322
  const normalizedCliToolsSchema = publicCliToolsSchema.extend({ body: string().optional() });
@@ -13189,9 +13325,9 @@ const publicCapletSetSchema = object$1({
13189
13325
  description: string().describe("Capability description shown before child Caplets are disclosed.").refine((value) => value.trim().length >= 10, "description must contain at least 10 non-whitespace characters").refine((value) => value.length <= 1500, "description must be at most 1500 characters"),
13190
13326
  configPath: string().min(1).optional().describe("Child Caplets config.json path."),
13191
13327
  capletsRoot: string().min(1).optional().describe("Child Markdown Caplets root directory."),
13192
- defaultSearchLimit: number$1().int().positive().default(20).describe("Default maximum number of child Caplet search results."),
13193
- maxSearchLimit: number$1().int().positive().max(50).default(50).describe("Maximum accepted child Caplet search result limit."),
13194
- toolCacheTtlMs: number$1().int().nonnegative().default(3e4).describe("Milliseconds child Caplet metadata stays fresh. Set 0 to refresh every time."),
13328
+ defaultSearchLimit: number$2().int().positive().default(20).describe("Default maximum number of child Caplet search results."),
13329
+ maxSearchLimit: number$2().int().positive().max(50).default(50).describe("Maximum accepted child Caplet search result limit."),
13330
+ toolCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds child Caplet metadata stays fresh. Set 0 to refresh every time."),
13195
13331
  tags: array(string().trim().min(1).max(80)).optional(),
13196
13332
  disabled: boolean().default(false).describe("When true, omit this Caplet set.")
13197
13333
  }).strict().superRefine((set, ctx) => {
@@ -13210,8 +13346,19 @@ function configSchemaFor(serverValueSchema, openApiEndpointValueSchema, graphQlE
13210
13346
  return object$1({
13211
13347
  $schema: string().url().optional().describe("Optional JSON Schema URL for editor validation."),
13212
13348
  version: literal(1).default(1).describe("Caplets config schema version."),
13213
- defaultSearchLimit: number$1().int().positive().default(20).describe("Default maximum number of same-server search results."),
13214
- maxSearchLimit: number$1().int().positive().max(50).default(50).describe("Maximum accepted search_tools limit."),
13349
+ defaultSearchLimit: number$2().int().positive().default(20).describe("Default maximum number of same-server search results."),
13350
+ maxSearchLimit: number$2().int().positive().max(50).default(50).describe("Maximum accepted search_tools limit."),
13351
+ completion: object$1({
13352
+ discoveryTimeoutMs: number$2().int().positive().default(750),
13353
+ overallTimeoutMs: number$2().int().positive().default(1500),
13354
+ cacheTtlMs: number$2().int().nonnegative().default(3e5),
13355
+ negativeCacheTtlMs: number$2().int().nonnegative().default(3e4)
13356
+ }).strict().default({
13357
+ discoveryTimeoutMs: 750,
13358
+ overallTimeoutMs: 1500,
13359
+ cacheTtlMs: 3e5,
13360
+ negativeCacheTtlMs: 3e4
13361
+ }).describe("Shell completion discovery timeout and cache settings."),
13215
13362
  mcpServers: record(string().regex(SERVER_ID_PATTERN), serverValueSchema).default({}).describe("Downstream MCP servers keyed by stable server ID."),
13216
13363
  openapiEndpoints: record(string().regex(SERVER_ID_PATTERN), openApiEndpointValueSchema).default({}).describe("OpenAPI endpoints keyed by stable Caplet ID."),
13217
13364
  graphqlEndpoints: record(string().regex(SERVER_ID_PATTERN), graphQlEndpointValueSchema).default({}).describe("GraphQL endpoints keyed by stable Caplet ID."),
@@ -13726,7 +13873,8 @@ function parseConfig(input) {
13726
13873
  version: parsed.data.version,
13727
13874
  options: {
13728
13875
  defaultSearchLimit: parsed.data.defaultSearchLimit,
13729
- maxSearchLimit: parsed.data.maxSearchLimit
13876
+ maxSearchLimit: parsed.data.maxSearchLimit,
13877
+ completion: parsed.data.completion
13730
13878
  },
13731
13879
  mcpServers: servers,
13732
13880
  openapiEndpoints,
@@ -17306,10 +17454,10 @@ const ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
17306
17454
  $ZodType.init(inst, def);
17307
17455
  inst.def = def;
17308
17456
  inst.type = def.type;
17309
- inst.parse = (data, params) => parse$3(inst, data, params, { callee: inst.parse });
17310
- inst.safeParse = (data, params) => safeParse$2(inst, data, params);
17457
+ inst.parse = (data, params) => parse$1(inst, data, params, { callee: inst.parse });
17458
+ inst.safeParse = (data, params) => safeParse$1(inst, data, params);
17311
17459
  inst.parseAsync = async (data, params) => parseAsync$1(inst, data, params, { callee: inst.parseAsync });
17312
- inst.safeParseAsync = async (data, params) => safeParseAsync$2(inst, data, params);
17460
+ inst.safeParseAsync = async (data, params) => safeParseAsync$1(inst, data, params);
17313
17461
  inst.check = (...checks) => {
17314
17462
  return inst.clone({
17315
17463
  ...def,
@@ -17355,11 +17503,11 @@ function objectFromShape(shape) {
17355
17503
  throw new Error("Mixed Zod versions detected in object shape.");
17356
17504
  }
17357
17505
  function safeParse(schema, data) {
17358
- if (isZ4Schema(schema)) return safeParse$2(schema, data);
17506
+ if (isZ4Schema(schema)) return safeParse$1(schema, data);
17359
17507
  return schema.safeParse(data);
17360
17508
  }
17361
17509
  async function safeParseAsync(schema, data) {
17362
- if (isZ4Schema(schema)) return await safeParseAsync$2(schema, data);
17510
+ if (isZ4Schema(schema)) return await safeParseAsync$1(schema, data);
17363
17511
  return await schema.safeParseAsync(data);
17364
17512
  }
17365
17513
  function getObjectShape(schema) {
@@ -17473,7 +17621,7 @@ const AssertObjectSchema = custom((v) => v !== null && (typeof v === "object" ||
17473
17621
  /**
17474
17622
  * A progress token, used to associate progress notifications with the original request.
17475
17623
  */
17476
- const ProgressTokenSchema = union([string(), number$1().int()]);
17624
+ const ProgressTokenSchema = union([string(), number$2().int()]);
17477
17625
  /**
17478
17626
  * An opaque token used to represent a cursor for pagination.
17479
17627
  */
@@ -17482,13 +17630,13 @@ looseObject({
17482
17630
  /**
17483
17631
  * Requested duration in milliseconds to retain task from creation.
17484
17632
  */
17485
- ttl: number$1().optional(),
17633
+ ttl: number$2().optional(),
17486
17634
  /**
17487
17635
  * Time in milliseconds to wait between task status requests.
17488
17636
  */
17489
- pollInterval: number$1().optional()
17637
+ pollInterval: number$2().optional()
17490
17638
  });
17491
- const TaskMetadataSchema = object$1({ ttl: number$1().optional() });
17639
+ const TaskMetadataSchema = object$1({ ttl: number$2().optional() });
17492
17640
  /**
17493
17641
  * Metadata for associating messages with a task.
17494
17642
  * Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`.
@@ -17555,7 +17703,7 @@ _meta: RequestMetaSchema.optional() });
17555
17703
  /**
17556
17704
  * A uniquely identifying ID for a request in JSON-RPC.
17557
17705
  */
17558
- const RequestIdSchema = union([string(), number$1().int()]);
17706
+ const RequestIdSchema = union([string(), number$2().int()]);
17559
17707
  /**
17560
17708
  * A request that expects a response.
17561
17709
  */
@@ -17612,7 +17760,7 @@ const JSONRPCErrorResponseSchema = object$1({
17612
17760
  /**
17613
17761
  * The error type that occurred.
17614
17762
  */
17615
- code: number$1().int(),
17763
+ code: number$2().int(),
17616
17764
  /**
17617
17765
  * A short description of the error. The message SHOULD be limited to a concise single sentence.
17618
17766
  */
@@ -17948,11 +18096,11 @@ const ProgressSchema = object$1({
17948
18096
  /**
17949
18097
  * The progress thus far. This should increase every time progress is made, even if the total is unknown.
17950
18098
  */
17951
- progress: number$1(),
18099
+ progress: number$2(),
17952
18100
  /**
17953
18101
  * Total number of items to process (or total progress required), if known.
17954
18102
  */
17955
- total: optional(number$1()),
18103
+ total: optional(number$2()),
17956
18104
  /**
17957
18105
  * An optional message describing the current progress.
17958
18106
  */
@@ -18008,7 +18156,7 @@ const TaskSchema = object$1({
18008
18156
  * Time in milliseconds to keep task results available after completion.
18009
18157
  * If null, the task has unlimited lifetime until manually cleaned up.
18010
18158
  */
18011
- ttl: union([number$1(), _null()]),
18159
+ ttl: union([number$2(), _null()]),
18012
18160
  /**
18013
18161
  * ISO 8601 timestamp when the task was created.
18014
18162
  */
@@ -18017,7 +18165,7 @@ const TaskSchema = object$1({
18017
18165
  * ISO 8601 timestamp when the task was last updated.
18018
18166
  */
18019
18167
  lastUpdatedAt: string(),
18020
- pollInterval: optional(number$1()),
18168
+ pollInterval: optional(number$2()),
18021
18169
  /**
18022
18170
  * Optional diagnostic message for failed tasks or other status information.
18023
18171
  */
@@ -18132,7 +18280,7 @@ const AnnotationsSchema = object$1({
18132
18280
  /**
18133
18281
  * Importance hint for the resource, from 0 (least) to 1 (most).
18134
18282
  */
18135
- priority: number$1().min(0).max(1).optional(),
18283
+ priority: number$2().min(0).max(1).optional(),
18136
18284
  /**
18137
18285
  * ISO 8601 timestamp for the most recent modification.
18138
18286
  */
@@ -18163,7 +18311,7 @@ const ResourceSchema = object$1({
18163
18311
  *
18164
18312
  * This can be used by Hosts to display file sizes and estimate context window usage.
18165
18313
  */
18166
- size: optional(number$1()),
18314
+ size: optional(number$2()),
18167
18315
  /**
18168
18316
  * Optional annotations for the client.
18169
18317
  */
@@ -18690,7 +18838,7 @@ const ListChangedOptionsBaseSchema = object$1({
18690
18838
  *
18691
18839
  * @default 300
18692
18840
  */
18693
- debounceMs: number$1().int().nonnegative().default(300)
18841
+ debounceMs: number$2().int().nonnegative().default(300)
18694
18842
  });
18695
18843
  /**
18696
18844
  * The severity of a log message.
@@ -18759,15 +18907,15 @@ name: string().optional() })).optional(),
18759
18907
  /**
18760
18908
  * How much to prioritize cost when selecting a model.
18761
18909
  */
18762
- costPriority: number$1().min(0).max(1).optional(),
18910
+ costPriority: number$2().min(0).max(1).optional(),
18763
18911
  /**
18764
18912
  * How much to prioritize sampling speed (latency) when selecting a model.
18765
18913
  */
18766
- speedPriority: number$1().min(0).max(1).optional(),
18914
+ speedPriority: number$2().min(0).max(1).optional(),
18767
18915
  /**
18768
18916
  * How much to prioritize intelligence and capabilities when selecting a model.
18769
18917
  */
18770
- intelligencePriority: number$1().min(0).max(1).optional()
18918
+ intelligencePriority: number$2().min(0).max(1).optional()
18771
18919
  });
18772
18920
  /**
18773
18921
  * Controls tool usage behavior in sampling requests.
@@ -18857,13 +19005,13 @@ const CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend
18857
19005
  "thisServer",
18858
19006
  "allServers"
18859
19007
  ]).optional(),
18860
- temperature: number$1().optional(),
19008
+ temperature: number$2().optional(),
18861
19009
  /**
18862
19010
  * The requested maximum number of tokens to sample (to prevent runaway completions).
18863
19011
  *
18864
19012
  * The client MAY choose to sample fewer tokens than the requested maximum.
18865
19013
  */
18866
- maxTokens: number$1().int(),
19014
+ maxTokens: number$2().int(),
18867
19015
  stopSequences: array(string()).optional(),
18868
19016
  /**
18869
19017
  * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
@@ -18967,8 +19115,8 @@ const StringSchemaSchema = object$1({
18967
19115
  type: literal("string"),
18968
19116
  title: string().optional(),
18969
19117
  description: string().optional(),
18970
- minLength: number$1().optional(),
18971
- maxLength: number$1().optional(),
19118
+ minLength: number$2().optional(),
19119
+ maxLength: number$2().optional(),
18972
19120
  format: _enum([
18973
19121
  "email",
18974
19122
  "uri",
@@ -18984,9 +19132,9 @@ const NumberSchemaSchema = object$1({
18984
19132
  type: _enum(["number", "integer"]),
18985
19133
  title: string().optional(),
18986
19134
  description: string().optional(),
18987
- minimum: number$1().optional(),
18988
- maximum: number$1().optional(),
18989
- default: number$1().optional()
19135
+ minimum: number$2().optional(),
19136
+ maximum: number$2().optional(),
19137
+ default: number$2().optional()
18990
19138
  });
18991
19139
  /**
18992
19140
  * Schema for single-selection enumeration without display titles for options.
@@ -19029,8 +19177,8 @@ const PrimitiveSchemaDefinitionSchema = union([
19029
19177
  type: literal("array"),
19030
19178
  title: string().optional(),
19031
19179
  description: string().optional(),
19032
- minItems: number$1().optional(),
19033
- maxItems: number$1().optional(),
19180
+ minItems: number$2().optional(),
19181
+ maxItems: number$2().optional(),
19034
19182
  items: object$1({
19035
19183
  type: literal("string"),
19036
19184
  enum: array(string())
@@ -19040,8 +19188,8 @@ const PrimitiveSchemaDefinitionSchema = union([
19040
19188
  type: literal("array"),
19041
19189
  title: string().optional(),
19042
19190
  description: string().optional(),
19043
- minItems: number$1().optional(),
19044
- maxItems: number$1().optional(),
19191
+ minItems: number$2().optional(),
19192
+ maxItems: number$2().optional(),
19045
19193
  items: object$1({ anyOf: array(object$1({
19046
19194
  const: string(),
19047
19195
  title: string()
@@ -19146,7 +19294,7 @@ const ElicitResultSchema = ResultSchema.extend({
19146
19294
  */
19147
19295
  content: preprocess((val) => val === null ? void 0 : val, record(string(), union([
19148
19296
  string(),
19149
- number$1(),
19297
+ number$2(),
19150
19298
  boolean(),
19151
19299
  array(string())
19152
19300
  ])).optional())
@@ -19219,7 +19367,7 @@ const CompleteResultSchema = ResultSchema.extend({ completion: looseObject({
19219
19367
  /**
19220
19368
  * The total number of completion options available. This can exceed the number of values actually sent in the response.
19221
19369
  */
19222
- total: optional(number$1().int()),
19370
+ total: optional(number$2().int()),
19223
19371
  /**
19224
19372
  * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
19225
19373
  */
@@ -28684,15 +28832,15 @@ function createFetchWithInit(baseFetch = fetch, baseInit) {
28684
28832
  });
28685
28833
  };
28686
28834
  }
28687
- let crypto$2;
28688
- crypto$2 = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("node:crypto").then((m) => m.webcrypto);
28835
+ let crypto$1;
28836
+ crypto$1 = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("node:crypto").then((m) => m.webcrypto);
28689
28837
  /**
28690
28838
  * Creates an array of length `size` of random bytes
28691
28839
  * @param size
28692
28840
  * @returns Array of random ints (0 to 255)
28693
28841
  */
28694
28842
  async function getRandomValues(size) {
28695
- return (await crypto$2).getRandomValues(new Uint8Array(size));
28843
+ return (await crypto$1).getRandomValues(new Uint8Array(size));
28696
28844
  }
28697
28845
  /** Generate cryptographically strong random string
28698
28846
  * @param size The desired length of the string
@@ -28720,7 +28868,7 @@ async function generateVerifier(length) {
28720
28868
  * @returns The base64 url encoded code challenge
28721
28869
  */
28722
28870
  async function generateChallenge(code_verifier) {
28723
- const buffer = await (await crypto$2).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
28871
+ const buffer = await (await crypto$1).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
28724
28872
  return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
28725
28873
  }
28726
28874
  /** Generate a PKCE challenge pair
@@ -28891,8 +29039,8 @@ const OAuthClientMetadataSchema = object$1({
28891
29039
  const OAuthClientInformationSchema = object$1({
28892
29040
  client_id: string(),
28893
29041
  client_secret: string().optional(),
28894
- client_id_issued_at: number$1().optional(),
28895
- client_secret_expires_at: number$1().optional()
29042
+ client_id_issued_at: number$2().optional(),
29043
+ client_secret_expires_at: number$2().optional()
28896
29044
  }).strip();
28897
29045
  /**
28898
29046
  * RFC 7591 OAuth 2.0 Dynamic Client Registration full response (client information plus metadata)
@@ -31267,14 +31415,28 @@ var DownstreamManager = class {
31267
31415
  async checkServer(server) {
31268
31416
  const startedAt = Date.now();
31269
31417
  try {
31418
+ const capabilities = (await this.connect(server)).client.getServerCapabilities() ?? {};
31270
31419
  const tools = await this.refreshTools(server, true);
31271
31420
  this.registry.setStatus(server.server, "available");
31272
- return {
31421
+ const result = {
31273
31422
  id: server.server,
31274
31423
  status: "available",
31424
+ capabilities: {
31425
+ tools: Boolean(capabilities.tools),
31426
+ resources: Boolean(capabilities.resources),
31427
+ resourceTemplates: Boolean(capabilities.resources),
31428
+ prompts: Boolean(capabilities.prompts),
31429
+ completions: Boolean(capabilities.completions)
31430
+ },
31275
31431
  toolCount: tools.length,
31276
31432
  elapsedMs: Date.now() - startedAt
31277
31433
  };
31434
+ if (capabilities.resources) Object.assign(result, {
31435
+ resourceCount: (await this.listResources(server, true)).length,
31436
+ resourceTemplateCount: (await this.listResourceTemplates(server, true)).length
31437
+ });
31438
+ if (capabilities.prompts) Object.assign(result, { promptCount: (await this.listPrompts(server, true)).length });
31439
+ return result;
31278
31440
  } catch (error) {
31279
31441
  const safe = toSafeError(error, "SERVER_UNAVAILABLE");
31280
31442
  this.registry.setStatus(server.server, "unavailable", safe);
@@ -31316,6 +31478,86 @@ var DownstreamManager = class {
31316
31478
  throw new CapletsError("DOWNSTREAM_TOOL_ERROR", `Downstream tool failed for ${server.server}/${toolName}`, toSafeError(error));
31317
31479
  }
31318
31480
  }
31481
+ async listResources(server, force = false) {
31482
+ const connection = await this.assertCapability(server, "resources");
31483
+ if (!force && connection.resources && this.isCacheFresh(connection.resourcesFetchedAt, server.toolCacheTtlMs)) return connection.resources;
31484
+ const resources = [];
31485
+ let cursor;
31486
+ do {
31487
+ const result = await connection.client.listResources(cursor ? { cursor } : void 0, { timeout: server.startupTimeoutMs });
31488
+ resources.push(...result.resources ?? []);
31489
+ cursor = result.nextCursor;
31490
+ } while (cursor);
31491
+ connection.resources = resources;
31492
+ connection.resourcesFetchedAt = Date.now();
31493
+ return resources;
31494
+ }
31495
+ async listResourceTemplates(server, force = false) {
31496
+ const connection = await this.assertCapability(server, "resources");
31497
+ if (!force && connection.resourceTemplates && this.isCacheFresh(connection.resourceTemplatesFetchedAt, server.toolCacheTtlMs)) return connection.resourceTemplates;
31498
+ const resourceTemplates = [];
31499
+ let cursor;
31500
+ do {
31501
+ const result = await connection.client.listResourceTemplates(cursor ? { cursor } : void 0, { timeout: server.startupTimeoutMs });
31502
+ resourceTemplates.push(...result.resourceTemplates ?? []);
31503
+ cursor = result.nextCursor;
31504
+ } while (cursor);
31505
+ connection.resourceTemplates = resourceTemplates;
31506
+ connection.resourceTemplatesFetchedAt = Date.now();
31507
+ return resourceTemplates;
31508
+ }
31509
+ async readResource(server, uri) {
31510
+ const connection = await this.assertCapability(server, "resources");
31511
+ try {
31512
+ return await connection.client.readResource({ uri }, { timeout: server.callTimeoutMs });
31513
+ } catch (error) {
31514
+ throw new CapletsError("DOWNSTREAM_RESOURCE_ERROR", `Downstream resource read failed for ${server.server}/${uri}`, toSafeError(error));
31515
+ }
31516
+ }
31517
+ async listPrompts(server, force = false) {
31518
+ const connection = await this.assertCapability(server, "prompts");
31519
+ if (!force && connection.prompts && this.isCacheFresh(connection.promptsFetchedAt, server.toolCacheTtlMs)) return connection.prompts;
31520
+ const prompts = [];
31521
+ let cursor;
31522
+ do {
31523
+ const result = await connection.client.listPrompts(cursor ? { cursor } : void 0, { timeout: server.startupTimeoutMs });
31524
+ prompts.push(...result.prompts ?? []);
31525
+ cursor = result.nextCursor;
31526
+ } while (cursor);
31527
+ connection.prompts = prompts;
31528
+ connection.promptsFetchedAt = Date.now();
31529
+ return prompts;
31530
+ }
31531
+ async getPrompt(server, promptName, args) {
31532
+ if (!(await this.listPrompts(server)).some((prompt) => prompt.name === promptName)) throw new CapletsError("PROMPT_NOT_FOUND", `Prompt ${promptName} was not found on ${server.server}`);
31533
+ const connection = await this.connect(server);
31534
+ try {
31535
+ return await connection.client.getPrompt({
31536
+ name: promptName,
31537
+ arguments: stringifyPromptArgs(args)
31538
+ }, { timeout: server.callTimeoutMs });
31539
+ } catch (error) {
31540
+ throw new CapletsError("DOWNSTREAM_PROMPT_ERROR", `Downstream prompt failed for ${server.server}/${promptName}`, toSafeError(error));
31541
+ }
31542
+ }
31543
+ async complete(server, request) {
31544
+ const connection = await this.assertCapability(server, "completions");
31545
+ const params = {
31546
+ ref: request.ref.type === "prompt" ? {
31547
+ type: "ref/prompt",
31548
+ name: request.ref.name
31549
+ } : {
31550
+ type: "ref/resource",
31551
+ uri: request.ref.uri
31552
+ },
31553
+ argument: request.argument
31554
+ };
31555
+ try {
31556
+ return await connection.client.complete(params, { timeout: server.callTimeoutMs });
31557
+ } catch (error) {
31558
+ throw new CapletsError("DOWNSTREAM_COMPLETION_ERROR", `Downstream completion failed for ${server.server}`, toSafeError(error));
31559
+ }
31560
+ }
31319
31561
  compact(server, tool) {
31320
31562
  return {
31321
31563
  id: server.server,
@@ -31325,9 +31567,75 @@ var DownstreamManager = class {
31325
31567
  hasOutputSchema: Boolean(tool.outputSchema)
31326
31568
  };
31327
31569
  }
31570
+ compactResource(server, resource) {
31571
+ return {
31572
+ id: server.server,
31573
+ kind: "resource",
31574
+ uri: resource.uri,
31575
+ ...resource.name ? { name: resource.name } : {},
31576
+ ...resource.description ? { description: resource.description } : {},
31577
+ ...resource.mimeType ? { mimeType: resource.mimeType } : {},
31578
+ ...typeof resource.size === "number" ? { size: resource.size } : {}
31579
+ };
31580
+ }
31581
+ compactResourceTemplate(server, template) {
31582
+ return {
31583
+ id: server.server,
31584
+ kind: "resourceTemplate",
31585
+ uriTemplate: template.uriTemplate,
31586
+ ...template.name ? { name: template.name } : {},
31587
+ ...template.description ? { description: template.description } : {},
31588
+ ...template.mimeType ? { mimeType: template.mimeType } : {}
31589
+ };
31590
+ }
31591
+ compactPrompt(server, prompt) {
31592
+ return {
31593
+ id: server.server,
31594
+ prompt: prompt.name,
31595
+ ...prompt.description ? { description: prompt.description } : {},
31596
+ ...prompt.arguments ? { arguments: prompt.arguments } : {}
31597
+ };
31598
+ }
31599
+ searchResources(server, resources, query, limit) {
31600
+ const lower = query.toLocaleLowerCase();
31601
+ return resources.map((resource) => this.compactResource(server, resource)).filter((resource) => [
31602
+ resource.uri,
31603
+ resource.name,
31604
+ resource.description,
31605
+ resource.mimeType
31606
+ ].some((value) => value?.toLocaleLowerCase().includes(lower))).slice(0, limit);
31607
+ }
31608
+ searchResourceTemplates(server, templates, query, limit) {
31609
+ const lower = query.toLocaleLowerCase();
31610
+ return templates.map((template) => this.compactResourceTemplate(server, template)).filter((template) => [
31611
+ template.uriTemplate,
31612
+ template.name,
31613
+ template.description,
31614
+ template.mimeType
31615
+ ].some((value) => value?.toLocaleLowerCase().includes(lower))).slice(0, limit);
31616
+ }
31617
+ searchPrompts(server, prompts, query, limit) {
31618
+ const lower = query.toLocaleLowerCase();
31619
+ return prompts.map((prompt) => this.compactPrompt(server, prompt)).filter((prompt) => [
31620
+ prompt.prompt,
31621
+ prompt.description,
31622
+ ...(prompt.arguments ?? []).flatMap((arg) => [arg.name, arg.description])
31623
+ ].some((value) => value?.toLocaleLowerCase().includes(lower))).slice(0, limit);
31624
+ }
31328
31625
  search(server, tools, query, limit) {
31329
31626
  return searchToolList(tools, query, limit, (tool) => this.compact(server, tool));
31330
31627
  }
31628
+ async assertCapability(server, capability) {
31629
+ const connection = await this.connect(server);
31630
+ if (!connection.client.getServerCapabilities()?.[capability]) throw new CapletsError("UNSUPPORTED_CAPABILITY", `${server.server} does not advertise MCP ${capability}`, {
31631
+ server: server.server,
31632
+ capability
31633
+ });
31634
+ return connection;
31635
+ }
31636
+ isCacheFresh(fetchedAt, ttlMs) {
31637
+ return fetchedAt !== void 0 && ttlMs > 0 && Date.now() - fetchedAt <= ttlMs;
31638
+ }
31331
31639
  async refreshTools(server, force) {
31332
31640
  const connection = await this.connect(server);
31333
31641
  const now = Date.now();
@@ -31371,6 +31679,20 @@ var DownstreamManager = class {
31371
31679
  transport,
31372
31680
  configFingerprint: expectedFingerprint
31373
31681
  };
31682
+ client.setNotificationHandler(ToolListChangedNotificationSchema, () => {
31683
+ connection.tools = void 0;
31684
+ connection.toolsFetchedAt = void 0;
31685
+ });
31686
+ client.setNotificationHandler(ResourceListChangedNotificationSchema, () => {
31687
+ connection.resources = void 0;
31688
+ connection.resourcesFetchedAt = void 0;
31689
+ connection.resourceTemplates = void 0;
31690
+ connection.resourceTemplatesFetchedAt = void 0;
31691
+ });
31692
+ client.setNotificationHandler(PromptListChangedNotificationSchema, () => {
31693
+ connection.prompts = void 0;
31694
+ connection.promptsFetchedAt = void 0;
31695
+ });
31374
31696
  pendingConnection = connection;
31375
31697
  this.connecting.set(server.server, connection);
31376
31698
  transport.onclose = () => {
@@ -31501,6 +31823,18 @@ function nearbyToolNames(tools, needle) {
31501
31823
  function isTimeoutLike(error) {
31502
31824
  return error instanceof Error && /timeout|timed out|aborted/i.test(error.message);
31503
31825
  }
31826
+ function stringifyPromptArgs(args) {
31827
+ const stringified = {};
31828
+ for (const [key, value] of Object.entries(args)) {
31829
+ if (typeof value === "string") {
31830
+ stringified[key] = value;
31831
+ continue;
31832
+ }
31833
+ const serialized = JSON.stringify(value);
31834
+ if (typeof serialized === "string") stringified[key] = serialized;
31835
+ }
31836
+ return stringified;
31837
+ }
31504
31838
  function isAuthRemediationError(error) {
31505
31839
  return error instanceof CapletsError && (error.code === "AUTH_REQUIRED" || error.code === "AUTH_FAILED");
31506
31840
  }
@@ -56362,7 +56696,7 @@ function capabilityDescription(server) {
56362
56696
  return [
56363
56697
  `${server.name} Caplet.`,
56364
56698
  server.description,
56365
- "Use get_caplet for details when needed; use search_tools or list_tools to discover downstream operations."
56699
+ server.backend === "mcp" ? "Use get_caplet for details when needed; use tools for actions, resources for readable context, prompts for reusable workflows, and complete for prompt/resource-template arguments." : "Use get_caplet for details when needed; use search_tools or list_tools to discover downstream operations."
56366
56700
  ].filter(Boolean).join(" ");
56367
56701
  }
56368
56702
  var ServerRegistry = class {
@@ -56578,17 +56912,9 @@ function cloneJsonValue(value) {
56578
56912
  function throwInvalid(message) {
56579
56913
  throw new CapletsError("REQUEST_INVALID", message);
56580
56914
  }
56581
- const generatedToolInputSchema = object$1({
56582
- operation: _enum(operations).describe(generatedToolInputDescriptions.operation),
56583
- query: string().optional().describe(generatedToolInputDescriptions.query),
56584
- limit: number$1().int().positive().optional().describe(generatedToolInputDescriptions.limit),
56585
- tool: string().optional().describe(generatedToolInputDescriptions.tool),
56586
- arguments: record(string(), unknown()).optional().describe(generatedToolInputDescriptions.arguments),
56587
- fields: array(string().min(1)).min(1).optional().describe(generatedToolInputDescriptions.fields)
56588
- }).strict();
56589
56915
  async function handleServerTool(server, request, registry, downstream, openapi, graphql, http, cli, caplets) {
56590
56916
  const startedAt = Date.now();
56591
- const parsed = validateOperationRequest(request, registry.config.options.maxSearchLimit);
56917
+ const parsed = validateOperationRequest(request, registry.config.options.maxSearchLimit, server.backend);
56592
56918
  switch (parsed.operation) {
56593
56919
  case "get_caplet": return jsonResult(registry.detail(server), metadataFor(server, "get_caplet", void 0, startedAt));
56594
56920
  case "check_backend": return jsonResult(await backendFor(server, downstream, openapi, graphql, http, cli, caplets).check(server), metadataFor(server, "check_backend", void 0, startedAt));
@@ -56629,11 +56955,75 @@ async function handleServerTool(server, request, registry, downstream, openapi,
56629
56955
  validateFieldSelection(tool.outputSchema, parsed.fields);
56630
56956
  return annotateCallToolResult(projectCallToolResult(await backend.callTool(server, parsed.tool, parsed.arguments), tool.outputSchema, parsed.fields), metadataFor(server, "call_tool", parsed.tool, startedAt));
56631
56957
  }
56958
+ case "list_resources": {
56959
+ const backend = mcpBackendFor(server, downstream);
56960
+ const resources = await backend.listResources(server);
56961
+ const templates = await backend.listResourceTemplates(server);
56962
+ const limit = parsed.limit ?? resources.length + templates.length;
56963
+ return jsonResult({
56964
+ id: server.server,
56965
+ name: server.name,
56966
+ resources: resources.slice(0, limit).map((resource) => backend.compactResource(server, resource)),
56967
+ resourceTemplates: templates.slice(0, Math.max(0, limit - resources.length)).map((template) => backend.compactResourceTemplate(server, template))
56968
+ }, metadataFor(server, "list_resources", void 0, startedAt));
56969
+ }
56970
+ case "search_resources": {
56971
+ const backend = mcpBackendFor(server, downstream);
56972
+ const resources = await backend.listResources(server);
56973
+ const templates = await backend.listResourceTemplates(server);
56974
+ const limit = parsed.limit ?? registry.config.options.defaultSearchLimit;
56975
+ const resourceMatches = backend.searchResources(server, resources, parsed.query, limit);
56976
+ const templateMatches = backend.searchResourceTemplates(server, templates, parsed.query, Math.max(0, limit - resourceMatches.length));
56977
+ return jsonResult({
56978
+ id: server.server,
56979
+ name: server.name,
56980
+ query: parsed.query,
56981
+ matches: [...resourceMatches, ...templateMatches]
56982
+ }, metadataFor(server, "search_resources", void 0, startedAt));
56983
+ }
56984
+ case "list_resource_templates": {
56985
+ const backend = mcpBackendFor(server, downstream);
56986
+ const templates = await backend.listResourceTemplates(server);
56987
+ const limit = parsed.limit ?? templates.length;
56988
+ return jsonResult({
56989
+ id: server.server,
56990
+ name: server.name,
56991
+ resourceTemplates: templates.slice(0, limit).map((template) => backend.compactResourceTemplate(server, template))
56992
+ }, metadataFor(server, "list_resource_templates", void 0, startedAt));
56993
+ }
56994
+ case "read_resource": return annotateMcpResult(await mcpBackendFor(server, downstream).readResource(server, parsed.uri), metadataFor(server, "read_resource", { uri: parsed.uri }, startedAt));
56995
+ case "list_prompts": {
56996
+ const backend = mcpBackendFor(server, downstream);
56997
+ const prompts = await backend.listPrompts(server);
56998
+ const limit = parsed.limit ?? prompts.length;
56999
+ return jsonResult({
57000
+ id: server.server,
57001
+ name: server.name,
57002
+ prompts: prompts.slice(0, limit).map((prompt) => backend.compactPrompt(server, prompt))
57003
+ }, metadataFor(server, "list_prompts", void 0, startedAt));
57004
+ }
57005
+ case "search_prompts": {
57006
+ const backend = mcpBackendFor(server, downstream);
57007
+ const prompts = await backend.listPrompts(server);
57008
+ const limit = parsed.limit ?? registry.config.options.defaultSearchLimit;
57009
+ return jsonResult({
57010
+ id: server.server,
57011
+ name: server.name,
57012
+ query: parsed.query,
57013
+ prompts: backend.searchPrompts(server, prompts, parsed.query, limit)
57014
+ }, metadataFor(server, "search_prompts", void 0, startedAt));
57015
+ }
57016
+ case "get_prompt": return annotateMcpResult(await mcpBackendFor(server, downstream).getPrompt(server, parsed.prompt, parsed.arguments), metadataFor(server, "get_prompt", { prompt: parsed.prompt }, startedAt));
57017
+ case "complete": return annotateMcpResult(await mcpBackendFor(server, downstream).complete(server, {
57018
+ ref: parsed.ref,
57019
+ argument: parsed.argument
57020
+ }), metadataFor(server, "complete", void 0, startedAt));
56632
57021
  }
56633
57022
  }
56634
- function validateOperationRequest(request, maxSearchLimit) {
56635
- if (request && typeof request === "object" && "operation" in request && typeof request.operation === "string" && !operations.includes(request.operation)) throw new CapletsError("UNKNOWN_OPERATION", `Unknown operation: ${request.operation}`);
56636
- const result = generatedToolInputSchema.safeParse(request);
57023
+ function validateOperationRequest(request, maxSearchLimit, backend = "tool") {
57024
+ const result = generatedToolInputSchemaForCaplet({ backend }).safeParse(request);
57025
+ if (request && typeof request === "object" && "operation" in request && typeof request.operation === "string" && !mcpOperations.includes(request.operation)) throw new CapletsError("UNKNOWN_OPERATION", `Unknown operation: ${request.operation}`);
57026
+ if (request && typeof request === "object" && "operation" in request && typeof request.operation === "string" && backend !== "mcp" && mcpOperations.includes(request.operation) && !operations.includes(request.operation)) throw new CapletsError("UNSUPPORTED_OPERATION", `${request.operation} is only available for MCP-backed Caplets`);
56637
57027
  if (!result.success) throw new CapletsError("REQUEST_INVALID", "Generated server tool request is invalid", result.error.issues);
56638
57028
  const value = result.data;
56639
57029
  const keys = Object.keys(value).sort();
@@ -56680,7 +57070,7 @@ function validateOperationRequest(request, maxSearchLimit) {
56680
57070
  "fields"
56681
57071
  ]);
56682
57072
  if (!value.tool) throw new CapletsError("REQUEST_INVALID", "call_tool requires tool");
56683
- if (!isPlainObject$8(value.arguments)) throw new CapletsError("REQUEST_INVALID", "call_tool.arguments must be a JSON object");
57073
+ if (!isPlainObject$7(value.arguments)) throw new CapletsError("REQUEST_INVALID", "call_tool.arguments must be a JSON object");
56684
57074
  return value.fields === void 0 ? {
56685
57075
  operation: "call_tool",
56686
57076
  tool: value.tool,
@@ -56691,23 +57081,82 @@ function validateOperationRequest(request, maxSearchLimit) {
56691
57081
  arguments: value.arguments,
56692
57082
  fields: value.fields
56693
57083
  };
57084
+ case "list_resources":
57085
+ case "list_resource_templates":
57086
+ case "list_prompts":
57087
+ allowed(["limit"]);
57088
+ if (value.limit !== void 0 && value.limit > maxSearchLimit) throw new CapletsError("REQUEST_INVALID", `${value.operation} limit must be <= ${maxSearchLimit}`);
57089
+ return value.limit === void 0 ? { operation: value.operation } : {
57090
+ operation: value.operation,
57091
+ limit: value.limit
57092
+ };
57093
+ case "search_resources":
57094
+ case "search_prompts":
57095
+ allowed(["query", "limit"]);
57096
+ if (!value.query) throw new CapletsError("REQUEST_INVALID", `${value.operation} requires query`);
57097
+ if (value.limit !== void 0 && value.limit > maxSearchLimit) throw new CapletsError("REQUEST_INVALID", `${value.operation} limit must be <= ${maxSearchLimit}`);
57098
+ return value.limit === void 0 ? {
57099
+ operation: value.operation,
57100
+ query: value.query
57101
+ } : {
57102
+ operation: value.operation,
57103
+ query: value.query,
57104
+ limit: value.limit
57105
+ };
57106
+ case "read_resource":
57107
+ allowed(["uri"]);
57108
+ if (!value.uri) throw new CapletsError("REQUEST_INVALID", "read_resource requires uri");
57109
+ return {
57110
+ operation: "read_resource",
57111
+ uri: value.uri
57112
+ };
57113
+ case "get_prompt":
57114
+ allowed(["prompt", "arguments"]);
57115
+ if (!value.prompt) throw new CapletsError("REQUEST_INVALID", "get_prompt requires prompt");
57116
+ if (value.arguments !== void 0 && !isPlainObject$7(value.arguments)) throw new CapletsError("REQUEST_INVALID", "get_prompt.arguments must be a JSON object");
57117
+ return {
57118
+ operation: "get_prompt",
57119
+ prompt: value.prompt,
57120
+ arguments: value.arguments ?? {}
57121
+ };
57122
+ case "complete":
57123
+ allowed(["ref", "argument"]);
57124
+ if (!value.ref) throw new CapletsError("REQUEST_INVALID", "complete requires ref");
57125
+ if (!value.argument) throw new CapletsError("REQUEST_INVALID", "complete requires argument");
57126
+ return {
57127
+ operation: "complete",
57128
+ ref: value.ref,
57129
+ argument: value.argument
57130
+ };
56694
57131
  }
56695
- return assertNever(value.operation);
57132
+ throw new CapletsError("INTERNAL_ERROR", "Unhandled operation");
56696
57133
  }
56697
- function assertNever(value) {
56698
- throw new CapletsError("INTERNAL_ERROR", `Unhandled operation: ${String(value)}`);
57134
+ function mcpBackendFor(server, downstream) {
57135
+ if (server.backend !== "mcp") throw new CapletsError("UNSUPPORTED_OPERATION", "MCP resource, prompt, and completion operations require an MCP-backed Caplet");
57136
+ return downstream;
56699
57137
  }
56700
- function metadataFor(server, operation, tool, startedAt) {
57138
+ function metadataFor(server, operation, target, startedAt) {
57139
+ const targetFields = typeof target === "string" ? { tool: target } : target ?? {};
56701
57140
  return {
56702
57141
  id: server.server,
56703
57142
  name: server.name,
56704
57143
  backend: server.backend,
56705
57144
  operation,
56706
- ...tool === void 0 ? {} : { tool },
57145
+ ...targetFields,
56707
57146
  status: "ok",
56708
57147
  ...startedAt === void 0 ? {} : { elapsedMs: Date.now() - startedAt }
56709
57148
  };
56710
57149
  }
57150
+ function annotateMcpResult(result, metadata) {
57151
+ const existingMeta = result._meta;
57152
+ return {
57153
+ ...result,
57154
+ _meta: {
57155
+ ...isPlainObject$7(existingMeta) ? existingMeta : {},
57156
+ caplets: metadata
57157
+ }
57158
+ };
57159
+ }
56711
57160
  function jsonResult(value, metadata) {
56712
57161
  return {
56713
57162
  content: [{
@@ -56731,7 +57180,7 @@ function annotateCallToolResult(result, metadata) {
56731
57180
  return {
56732
57181
  ...result,
56733
57182
  _meta: {
56734
- ...isPlainObject$8(existingMeta) ? existingMeta : {},
57183
+ ...isPlainObject$7(existingMeta) ? existingMeta : {},
56735
57184
  caplets: annotatedMetadata
56736
57185
  }
56737
57186
  };
@@ -56739,7 +57188,7 @@ function annotateCallToolResult(result, metadata) {
56739
57188
  function projectCallToolResult(result, outputSchema, fields) {
56740
57189
  if (result.isError === true) return result;
56741
57190
  const structuredContent = result.structuredContent;
56742
- if (!isPlainObject$8(structuredContent)) throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", "Field selection requires the downstream tool to return object structuredContent");
57191
+ if (!isPlainObject$7(structuredContent)) throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", "Field selection requires the downstream tool to return object structuredContent");
56743
57192
  const projected = projectStructuredContent(structuredContent, outputSchema, fields);
56744
57193
  return {
56745
57194
  ...result,
@@ -56748,11 +57197,11 @@ function projectCallToolResult(result, outputSchema, fields) {
56748
57197
  };
56749
57198
  }
56750
57199
  function extractArtifacts(result) {
56751
- if (!isPlainObject$8(result) || !Array.isArray(result.content)) return [];
57200
+ if (!isPlainObject$7(result) || !Array.isArray(result.content)) return [];
56752
57201
  const artifacts = [];
56753
57202
  const seen = /* @__PURE__ */ new Set();
56754
57203
  for (const item of result.content) {
56755
- if (!isPlainObject$8(item) || item.type !== "text" || typeof item.text !== "string") continue;
57204
+ if (!isPlainObject$7(item) || item.type !== "text" || typeof item.text !== "string") continue;
56756
57205
  const text = item.text;
56757
57206
  for (const link of parseMarkdownLinks(text)) {
56758
57207
  const label = link.label;
@@ -56867,7 +57316,7 @@ function artifactKindFromText(text) {
56867
57316
  if (/network[-_ ]?(?:log)?|har\b/.test(text)) return "network-log";
56868
57317
  return "file";
56869
57318
  }
56870
- function isPlainObject$8(value) {
57319
+ function isPlainObject$7(value) {
56871
57320
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
56872
57321
  }
56873
57322
  function backendFor(server, downstream, openapi, graphql, http, cli, caplets) {
@@ -57175,6 +57624,38 @@ var CapletsEngine = class {
57175
57624
  return errorResult(error);
57176
57625
  }
57177
57626
  }
57627
+ async completeCliWords(words) {
57628
+ const { completeCliWords } = await Promise.resolve().then(() => completion_dbB1hc97_exports).then((n) => n.r);
57629
+ return await completeCliWords(words, {
57630
+ config: this.registry.config,
57631
+ managers: {
57632
+ listTools: async (server) => this.listCompletionTools(server),
57633
+ listPrompts: async (server) => {
57634
+ if (server.backend !== "mcp") return [];
57635
+ return (await this.downstream.listPrompts(server)).map((prompt) => ({
57636
+ name: prompt.name,
57637
+ ...prompt.description ? { description: prompt.description } : {}
57638
+ }));
57639
+ },
57640
+ listResources: async (server) => {
57641
+ if (server.backend !== "mcp") return [];
57642
+ return (await this.downstream.listResources(server)).map((resource) => ({
57643
+ uri: resource.uri,
57644
+ ...resource.name ? { name: resource.name } : {},
57645
+ ...resource.description ? { description: resource.description } : {}
57646
+ }));
57647
+ },
57648
+ listResourceTemplates: async (server) => {
57649
+ if (server.backend !== "mcp") return [];
57650
+ return (await this.downstream.listResourceTemplates(server)).map((template) => ({
57651
+ uriTemplate: template.uriTemplate,
57652
+ ...template.name ? { name: template.name } : {},
57653
+ ...template.description ? { description: template.description } : {}
57654
+ }));
57655
+ }
57656
+ }
57657
+ });
57658
+ }
57178
57659
  async close() {
57179
57660
  this.closed = true;
57180
57661
  try {
@@ -57194,6 +57675,12 @@ var CapletsEngine = class {
57194
57675
  this.reloadListeners.clear();
57195
57676
  }
57196
57677
  }
57678
+ async listCompletionTools(server) {
57679
+ return (server.backend === "mcp" ? await this.downstream.listTools(server) : server.backend === "openapi" ? await this.openapi.listTools(server) : server.backend === "graphql" ? await this.graphql.listTools(server) : server.backend === "http" ? await this.http.listTools(server) : server.backend === "cli" ? await this.cli.listTools(server) : await this.capletSets.listTools(server)).map((tool) => ({
57680
+ name: tool.name,
57681
+ ...tool.description ? { description: tool.description } : {}
57682
+ }));
57683
+ }
57197
57684
  async reloadOnce() {
57198
57685
  if (this.closed) return false;
57199
57686
  let nextConfig;
@@ -57476,6 +57963,565 @@ function hasEnv$1(value) {
57476
57963
  return value !== void 0 && value.trim() !== "";
57477
57964
  }
57478
57965
  //#endregion
57966
+ //#region ../core/dist/completion-dbB1hc97.js
57967
+ var completion_dbB1hc97_exports = /* @__PURE__ */ __exportAll$1({
57968
+ a: () => formatCapletList,
57969
+ c: () => resolveCliConfigPaths,
57970
+ i: () => trailingSpaceCompletionToken,
57971
+ l: () => cliCommands,
57972
+ n: () => completionScript,
57973
+ o: () => formatConfigPaths,
57974
+ r: () => completion_exports,
57975
+ s: () => listCaplets,
57976
+ t: () => completeCliWords,
57977
+ u: () => completionShells
57978
+ });
57979
+ const completionShells = [
57980
+ "bash",
57981
+ "zsh",
57982
+ "fish",
57983
+ "powershell",
57984
+ "cmd"
57985
+ ];
57986
+ const cliCommands = {
57987
+ completion: "completion",
57988
+ completeHidden: "__complete",
57989
+ serve: "serve",
57990
+ init: "init",
57991
+ list: "list",
57992
+ install: "install",
57993
+ add: "add",
57994
+ getCaplet: "get-caplet",
57995
+ checkBackend: "check-backend",
57996
+ listTools: "list-tools",
57997
+ searchTools: "search-tools",
57998
+ getTool: "get-tool",
57999
+ callTool: "call-tool",
58000
+ listResources: "list-resources",
58001
+ searchResources: "search-resources",
58002
+ listResourceTemplates: "list-resource-templates",
58003
+ readResource: "read-resource",
58004
+ listPrompts: "list-prompts",
58005
+ searchPrompts: "search-prompts",
58006
+ getPrompt: "get-prompt",
58007
+ complete: "complete",
58008
+ config: "config",
58009
+ auth: "auth"
58010
+ };
58011
+ const topLevelCommandNames = [
58012
+ cliCommands.serve,
58013
+ cliCommands.init,
58014
+ cliCommands.list,
58015
+ cliCommands.install,
58016
+ cliCommands.add,
58017
+ cliCommands.getCaplet,
58018
+ cliCommands.checkBackend,
58019
+ cliCommands.listTools,
58020
+ cliCommands.searchTools,
58021
+ cliCommands.getTool,
58022
+ cliCommands.callTool,
58023
+ cliCommands.listResources,
58024
+ cliCommands.searchResources,
58025
+ cliCommands.listResourceTemplates,
58026
+ cliCommands.readResource,
58027
+ cliCommands.listPrompts,
58028
+ cliCommands.searchPrompts,
58029
+ cliCommands.getPrompt,
58030
+ cliCommands.complete,
58031
+ cliCommands.config,
58032
+ cliCommands.auth,
58033
+ cliCommands.completion
58034
+ ];
58035
+ const cliSubcommands = {
58036
+ [cliCommands.add]: [
58037
+ "cli",
58038
+ "mcp",
58039
+ "openapi",
58040
+ "graphql",
58041
+ "http"
58042
+ ],
58043
+ [cliCommands.auth]: [
58044
+ "login",
58045
+ "logout",
58046
+ "list"
58047
+ ],
58048
+ [cliCommands.completion]: [...completionShells],
58049
+ [cliCommands.config]: ["path", "paths"]
58050
+ };
58051
+ const capletIdCommands = new Set([
58052
+ cliCommands.getCaplet,
58053
+ cliCommands.checkBackend,
58054
+ cliCommands.listTools,
58055
+ cliCommands.searchTools,
58056
+ cliCommands.listResources,
58057
+ cliCommands.searchResources,
58058
+ cliCommands.listResourceTemplates,
58059
+ cliCommands.readResource,
58060
+ cliCommands.listPrompts,
58061
+ cliCommands.searchPrompts,
58062
+ cliCommands.complete
58063
+ ]);
58064
+ const qualifiedToolCommands = new Set([cliCommands.getTool, cliCommands.callTool]);
58065
+ const qualifiedPromptCommands = new Set([cliCommands.getPrompt]);
58066
+ function listCaplets(configWithSources, options) {
58067
+ const { config, sources, shadows } = configWithSources;
58068
+ return allCaplets(config).filter((server) => options.includeDisabled || !server.disabled).map((server) => ({
58069
+ server: server.server,
58070
+ backend: server.backend,
58071
+ name: server.name,
58072
+ description: server.description,
58073
+ disabled: server.disabled,
58074
+ status: initialServerStatus(server),
58075
+ source: sources[server.server]?.kind ?? "unknown",
58076
+ path: sources[server.server]?.path ?? null,
58077
+ shadows: shadows[server.server] ?? []
58078
+ })).sort((left, right) => left.server.localeCompare(right.server));
58079
+ }
58080
+ function initialServerStatus(server) {
58081
+ return server.disabled ? "disabled" : "not_started";
58082
+ }
58083
+ function allCaplets(config) {
58084
+ return [
58085
+ ...Object.values(config.mcpServers),
58086
+ ...Object.values(config.openapiEndpoints),
58087
+ ...Object.values(config.graphqlEndpoints),
58088
+ ...Object.values(config.httpApis),
58089
+ ...Object.values(config.cliTools)
58090
+ ];
58091
+ }
58092
+ function formatCapletList(rows, format = "plain") {
58093
+ return format === "markdown" ? formatCapletListMarkdown(rows) : formatCapletListPlain(rows);
58094
+ }
58095
+ function formatCapletListMarkdown(rows) {
58096
+ if (rows.length === 0) return "## Configured Caplets\n\nNo configured Caplets found.\n";
58097
+ const heading = [
58098
+ "## Configured Caplets",
58099
+ "",
58100
+ `${rows.length} ${rows.length === 1 ? "Caplet" : "Caplets"} shown.`,
58101
+ ""
58102
+ ];
58103
+ const entries = rows.flatMap((row) => [
58104
+ `- \`${row.server}\` — ${row.name}`,
58105
+ ` - Backend: ${row.backend}`,
58106
+ ` - Status: ${row.status}`,
58107
+ ` - Source: ${row.source}`,
58108
+ ...row.disabled ? [" - Disabled: true"] : [],
58109
+ ...row.path ? [` - Path: ${row.path}`] : []
58110
+ ]);
58111
+ const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
58112
+ if (warnings.length === 0) return `${[...heading, ...entries].join("\n")}\n`;
58113
+ return `${[
58114
+ ...heading,
58115
+ ...entries,
58116
+ "",
58117
+ "Warnings:",
58118
+ ...warnings.map((warning) => `- ${warning}`)
58119
+ ].join("\n")}\n`;
58120
+ }
58121
+ function formatCapletListPlain(rows) {
58122
+ if (rows.length === 0) return "No configured Caplets found.\n";
58123
+ const entries = rows.map((row) => [
58124
+ row.server,
58125
+ ` Name: ${row.name}`,
58126
+ ` Backend: ${row.backend}`,
58127
+ ` Status: ${row.status}`,
58128
+ ` Source: ${row.source}`,
58129
+ ...row.disabled ? [" Disabled: true"] : [],
58130
+ ...row.path ? [` Path: ${row.path}`] : []
58131
+ ].join("\n")).join("\n\n");
58132
+ const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
58133
+ if (warnings.length === 0) return `Configured Caplets (${rows.length})\n\n${entries}\n`;
58134
+ return `Configured Caplets (${rows.length})\n\n${entries}\n\n${warnings.join("\n")}\n`;
58135
+ }
58136
+ function formatSourceKind(kind) {
58137
+ if (kind.startsWith("project")) return "project";
58138
+ if (kind.startsWith("global")) return "global";
58139
+ return kind;
58140
+ }
58141
+ function resolveCliConfigPaths(envConfigPath, authDir) {
58142
+ const configPath = resolveConfigPath(envConfigPath);
58143
+ const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
58144
+ return {
58145
+ userConfig: configPath,
58146
+ projectConfig: resolveProjectConfigPath(),
58147
+ userRoot: resolveCapletsRoot(configPath),
58148
+ stateRoot: dirname(effectiveAuthDir),
58149
+ projectRoot: resolveProjectCapletsRoot(),
58150
+ authDir: effectiveAuthDir,
58151
+ envConfig: envConfigPath ?? null
58152
+ };
58153
+ }
58154
+ function formatConfigPaths(paths, format = "plain") {
58155
+ if (format === "markdown") return formatConfigPathsMarkdown(paths);
58156
+ return formatConfigPathsPlain(paths);
58157
+ }
58158
+ function formatConfigPathsMarkdown(paths) {
58159
+ return [
58160
+ "## Caplets paths",
58161
+ "",
58162
+ `- User config: ${paths.userConfig}`,
58163
+ `- Project config: ${paths.projectConfig}`,
58164
+ `- User Caplets root: ${paths.userRoot}`,
58165
+ `- State root: ${paths.stateRoot}`,
58166
+ `- Project Caplets root: ${paths.projectRoot}`,
58167
+ `- Auth directory: ${paths.authDir}`,
58168
+ `- CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
58169
+ ].join("\n") + "\n";
58170
+ }
58171
+ function formatConfigPathsPlain(paths) {
58172
+ return [
58173
+ "Caplets paths",
58174
+ "",
58175
+ `User config: ${paths.userConfig}`,
58176
+ `Project config: ${paths.projectConfig}`,
58177
+ `User root: ${paths.userRoot}`,
58178
+ `State root: ${paths.stateRoot}`,
58179
+ `Project root: ${paths.projectRoot}`,
58180
+ `Auth directory: ${paths.authDir}`,
58181
+ `CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
58182
+ ].join("\n") + "\n";
58183
+ }
58184
+ function completionCacheKey(input) {
58185
+ return createHash("sha256").update(JSON.stringify(input)).digest("hex");
58186
+ }
58187
+ function readCompletionCacheEntry(cacheDir, key, now = Date.now()) {
58188
+ try {
58189
+ const parsed = JSON.parse(readFileSync(cachePath(cacheDir, key), "utf8"));
58190
+ if (parsed.status === "positive" && Array.isArray(parsed.candidates)) return {
58191
+ ...parsed,
58192
+ fresh: now <= parsed.expiresAt
58193
+ };
58194
+ if (parsed.status === "negative" && typeof parsed.reason === "string") return {
58195
+ ...parsed,
58196
+ fresh: now <= parsed.expiresAt
58197
+ };
58198
+ } catch {
58199
+ return;
58200
+ }
58201
+ }
58202
+ function writeCompletionCacheEntry(cacheDir, key, entry) {
58203
+ mkdirSync(cacheDir, { recursive: true });
58204
+ const path = cachePath(cacheDir, key);
58205
+ const tempPath = `${path}.${process.pid}.tmp`;
58206
+ writeFileSync(tempPath, JSON.stringify(entry), { mode: 384 });
58207
+ renameSync(tempPath, path);
58208
+ }
58209
+ function cachePath(cacheDir, key) {
58210
+ return join(cacheDir, `${key}.json`);
58211
+ }
58212
+ async function discoverCompletionCandidates(serverId, kind, options) {
58213
+ const server = enabledServer(serverId, options.config);
58214
+ if (!server) return [];
58215
+ const completion = options.completion ?? options.config.options.completion;
58216
+ const now = options.now ?? Date.now();
58217
+ const configCandidates = configDefinedCandidates(serverId, kind, options.config);
58218
+ const cacheDir = options.cacheDir ?? DEFAULT_COMPLETION_CACHE_DIR;
58219
+ const key = completionCacheKey({
58220
+ server: server.server,
58221
+ backend: server.backend,
58222
+ kind,
58223
+ fingerprint: completionFingerprint(server, kind, completion)
58224
+ });
58225
+ const cached = readCompletionCacheEntry(cacheDir, key, now);
58226
+ if (cached?.status === "positive" && cached.fresh) return cached.candidates;
58227
+ if (cached?.status === "negative" && cached.fresh) return cached.candidates ?? configCandidates;
58228
+ try {
58229
+ const live = await withTimeout(liveCandidates(server, kind, options.managers), Math.min(completion.discoveryTimeoutMs, completion.overallTimeoutMs));
58230
+ const candidates = dedupeCandidates([...configCandidates, ...live]);
58231
+ writeCompletionCacheEntry(cacheDir, key, {
58232
+ status: "positive",
58233
+ fetchedAt: now,
58234
+ expiresAt: now + completion.cacheTtlMs,
58235
+ candidates
58236
+ });
58237
+ return candidates;
58238
+ } catch (error) {
58239
+ writeCompletionCacheEntry(cacheDir, key, {
58240
+ status: "negative",
58241
+ fetchedAt: now,
58242
+ expiresAt: now + completion.negativeCacheTtlMs,
58243
+ reason: negativeReason(error),
58244
+ ...cached?.status === "positive" ? { candidates: cached.candidates } : {}
58245
+ });
58246
+ if (cached?.status === "positive") return cached.candidates;
58247
+ return configCandidates;
58248
+ }
58249
+ }
58250
+ function configDefinedCandidates(serverId, kind, config) {
58251
+ if (kind !== "tools") return [];
58252
+ const cli = config.cliTools[serverId];
58253
+ if (cli && !cli.disabled) return Object.keys(cli.actions).map((name) => ({ value: `${serverId}.${name}` }));
58254
+ const http = config.httpApis[serverId];
58255
+ if (http && !http.disabled) return Object.keys(http.actions).map((name) => ({ value: `${serverId}.${name}` }));
58256
+ const graphql = config.graphqlEndpoints[serverId];
58257
+ if (graphql && !graphql.disabled && graphql.operations) return Object.keys(graphql.operations).map((name) => ({ value: `${serverId}.${name}` }));
58258
+ return [];
58259
+ }
58260
+ async function liveCandidates(server, kind, managers) {
58261
+ if (kind === "tools" && managers?.listTools) return (await managers.listTools(server)).map((tool) => ({
58262
+ value: `${server.server}.${tool.name}`,
58263
+ description: tool.description
58264
+ }));
58265
+ if (kind === "tools") return [];
58266
+ if (server.backend !== "mcp") return [];
58267
+ if (kind === "prompts" && managers?.listPrompts) return (await managers.listPrompts(server)).map((prompt) => ({
58268
+ value: `${server.server}.${prompt.name}`,
58269
+ description: prompt.description
58270
+ }));
58271
+ if (kind === "resources" && managers?.listResources) return (await managers.listResources(server)).map((resource) => ({
58272
+ value: resource.uri,
58273
+ label: resource.name,
58274
+ description: resource.description
58275
+ }));
58276
+ if (kind === "resourceTemplates" && managers?.listResourceTemplates) return (await managers.listResourceTemplates(server)).map((template) => ({
58277
+ value: template.uriTemplate,
58278
+ label: template.name,
58279
+ description: template.description
58280
+ }));
58281
+ throw new CapletsError("UNSUPPORTED_CAPABILITY", `Completion discovery is unsupported for ${kind}`);
58282
+ }
58283
+ function completionFingerprint(server, kind, completion) {
58284
+ return JSON.stringify({
58285
+ kind,
58286
+ completion: {
58287
+ discoveryTimeoutMs: completion.discoveryTimeoutMs,
58288
+ cacheTtlMs: completion.cacheTtlMs,
58289
+ negativeCacheTtlMs: completion.negativeCacheTtlMs
58290
+ },
58291
+ server: secretFreeServerShape(server)
58292
+ });
58293
+ }
58294
+ function secretFreeServerShape(server) {
58295
+ const base = {
58296
+ server: server.server,
58297
+ backend: server.backend,
58298
+ name: server.name,
58299
+ description: server.description,
58300
+ tags: server.tags,
58301
+ disabled: server.disabled
58302
+ };
58303
+ switch (server.backend) {
58304
+ case "mcp": return {
58305
+ ...base,
58306
+ transport: server.transport,
58307
+ command: server.command,
58308
+ args: server.args,
58309
+ cwd: server.cwd,
58310
+ url: server.url,
58311
+ authType: server.auth?.type,
58312
+ startupTimeoutMs: server.startupTimeoutMs,
58313
+ callTimeoutMs: server.callTimeoutMs
58314
+ };
58315
+ case "openapi": return {
58316
+ ...base,
58317
+ specPath: server.specPath,
58318
+ specUrl: server.specUrl,
58319
+ baseUrl: server.baseUrl,
58320
+ authType: server.auth.type,
58321
+ requestTimeoutMs: server.requestTimeoutMs
58322
+ };
58323
+ case "graphql": return {
58324
+ ...base,
58325
+ endpointUrl: server.endpointUrl,
58326
+ schemaPath: server.schemaPath,
58327
+ schemaUrl: server.schemaUrl,
58328
+ authType: server.auth.type,
58329
+ operationNames: server.operations ? Object.keys(server.operations) : void 0
58330
+ };
58331
+ case "http": return {
58332
+ ...base,
58333
+ baseUrl: server.baseUrl,
58334
+ authType: server.auth.type,
58335
+ actions: Object.fromEntries(Object.entries(server.actions).map(([name, action]) => [name, {
58336
+ method: action.method,
58337
+ path: action.path
58338
+ }])),
58339
+ requestTimeoutMs: server.requestTimeoutMs
58340
+ };
58341
+ case "cli": return {
58342
+ ...base,
58343
+ cwd: server.cwd,
58344
+ actions: Object.fromEntries(Object.entries(server.actions).map(([name, action]) => [name, {
58345
+ command: action.command,
58346
+ args: action.args,
58347
+ cwd: action.cwd
58348
+ }])),
58349
+ timeoutMs: server.timeoutMs,
58350
+ maxOutputBytes: server.maxOutputBytes
58351
+ };
58352
+ case "caplets": return {
58353
+ ...base,
58354
+ configPath: server.configPath,
58355
+ capletsRoot: server.capletsRoot,
58356
+ defaultSearchLimit: server.defaultSearchLimit,
58357
+ maxSearchLimit: server.maxSearchLimit
58358
+ };
58359
+ }
58360
+ }
58361
+ function negativeReason(error) {
58362
+ if (error instanceof CapletsError) {
58363
+ if (error.code === "AUTH_REQUIRED" || error.code === "AUTH_FAILED" || error.code === "AUTH_REFRESH_FAILED") return "auth_required";
58364
+ if (error.code === "SERVER_UNAVAILABLE" || error.code === "SERVER_START_TIMEOUT") return "unavailable";
58365
+ if (error.code === "UNSUPPORTED_CAPABILITY" || error.code === "UNSUPPORTED_OPERATION") return "unsupported";
58366
+ if (error.code === "TOOL_CALL_TIMEOUT" || error.code === "DOWNSTREAM_COMPLETION_ERROR") return "timeout";
58367
+ }
58368
+ return error instanceof Error && error.message.includes("timeout") ? "timeout" : "error";
58369
+ }
58370
+ async function withTimeout(promise, timeoutMs) {
58371
+ let timeout;
58372
+ try {
58373
+ return await Promise.race([promise, new Promise((_, reject) => {
58374
+ timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("completion discovery timeout")), timeoutMs);
58375
+ })]);
58376
+ } finally {
58377
+ if (timeout) clearTimeout(timeout);
58378
+ }
58379
+ }
58380
+ function enabledServer(serverId, config) {
58381
+ const server = config.mcpServers[serverId] ?? config.openapiEndpoints[serverId] ?? config.graphqlEndpoints[serverId] ?? config.httpApis[serverId] ?? config.cliTools[serverId] ?? config.capletSets[serverId];
58382
+ return server && !server.disabled ? server : void 0;
58383
+ }
58384
+ function dedupeCandidates(candidates) {
58385
+ const seen = /* @__PURE__ */ new Set();
58386
+ return candidates.filter((candidate) => {
58387
+ if (seen.has(candidate.value)) return false;
58388
+ seen.add(candidate.value);
58389
+ return true;
58390
+ });
58391
+ }
58392
+ var completion_exports = /* @__PURE__ */ __exportAll({
58393
+ completeCliWords: () => completeCliWords,
58394
+ completionScript: () => completionScript,
58395
+ trailingSpaceCompletionToken: () => trailingSpaceCompletionToken
58396
+ });
58397
+ const trailingSpaceCompletionToken = "__CAPLETS_TRAILING_SPACE__";
58398
+ const optionValueSuggestions = {
58399
+ "*": { "--format": [
58400
+ "markdown",
58401
+ "md",
58402
+ "plain",
58403
+ "json"
58404
+ ] },
58405
+ serve: { "--transport": ["stdio", "http"] },
58406
+ "add:mcp": { "--transport": ["http", "sse"] },
58407
+ "add:cli": { "--include": [
58408
+ "git",
58409
+ "gh",
58410
+ "package"
58411
+ ] }
58412
+ };
58413
+ function completionScript(shell) {
58414
+ switch (shell) {
58415
+ case "bash": return bashCompletionScript();
58416
+ case "zsh": return zshCompletionScript();
58417
+ case "fish": return fishCompletionScript();
58418
+ case "powershell": return powershellCompletionScript();
58419
+ case "cmd": return cmdCompletionScript();
58420
+ default: throw new CapletsError("REQUEST_INVALID", "completion shell must be bash, zsh, fish, powershell, or cmd");
58421
+ }
58422
+ }
58423
+ async function completeCliWords(words, options = {}) {
58424
+ try {
58425
+ const normalized = words.length === 0 ? [""] : words;
58426
+ const current = normalized.at(-1) ?? "";
58427
+ const previous = normalized.at(-2);
58428
+ const command = normalized[0] ?? "";
58429
+ const subcommand = normalized[1] ?? "";
58430
+ if (command === cliCommands.complete && previous === "--prompt" && subcommand) return prefixFilter((await discoverCompletionCandidates(subcommand, "prompts", discoveryOptions(options))).map((candidate) => candidate.value.replace(`${subcommand}.`, "")), current);
58431
+ if (command === cliCommands.complete && previous === "--resource-template" && subcommand) return prefixFilter((await discoverCompletionCandidates(subcommand, "resourceTemplates", discoveryOptions(options))).map((candidate) => candidate.value), current);
58432
+ const optionValues = suggestionsForOptionValue(command, subcommand, previous);
58433
+ if (optionValues) return prefixFilter(optionValues, current);
58434
+ if (normalized.length === 1) return prefixFilter([...topLevelCommandNames], current);
58435
+ if (normalized.length === 2 && command in cliSubcommands) return prefixFilter(cliSubcommands[command], current);
58436
+ if (normalized.length === 2 && capletIdCommands.has(command)) return prefixFilter(promptResourceCommands.has(command) ? configuredCapletIds(options, { backend: "mcp" }) : configuredCapletIds(options), current);
58437
+ if (normalized.length === 2 && (qualifiedToolCommands.has(command) || qualifiedPromptCommands.has(command))) {
58438
+ if (current.includes(".")) return prefixFilter((await discoverCompletionCandidates(current.slice(0, current.indexOf(".")), qualifiedToolCommands.has(command) ? "tools" : "prompts", discoveryOptions(options))).map((candidate) => candidate.value), current);
58439
+ return prefixFilter(configuredCapletIds(options, qualifiedPromptCommands.has(command) ? { backend: "mcp" } : void 0).map((id) => `${id}.`), current);
58440
+ }
58441
+ if (command === cliCommands.readResource && normalized.length === 3) return prefixFilter((await discoverCompletionCandidates(subcommand, "resources", discoveryOptions(options))).map((candidate) => candidate.value), current);
58442
+ if (command === cliCommands.auth && ["login", "logout"].includes(subcommand) && normalized.length === 3) return prefixFilter(configuredCapletIds(options), current);
58443
+ return [];
58444
+ } catch {
58445
+ return [];
58446
+ }
58447
+ }
58448
+ function suggestionsForOptionValue(command, subcommand, previous) {
58449
+ if (!previous) return void 0;
58450
+ return optionValueSuggestions[`${command}:${subcommand}`]?.[previous] ?? optionValueSuggestions[command]?.[previous] ?? optionValueSuggestions["*"]?.[previous];
58451
+ }
58452
+ const promptResourceCommands = new Set([
58453
+ cliCommands.getPrompt,
58454
+ cliCommands.readResource,
58455
+ cliCommands.complete
58456
+ ]);
58457
+ function configuredCapletIds(options, filter = {}) {
58458
+ return listCaplets(options.config ? {
58459
+ config: options.config,
58460
+ sources: {},
58461
+ shadows: {}
58462
+ } : loadConfigWithSources(options.configPath, options.projectConfigPath), { includeDisabled: false }).filter((row) => !filter.backend || row.backend === filter.backend).map((row) => row.server);
58463
+ }
58464
+ function discoveryOptions(options) {
58465
+ return {
58466
+ config: options.config ?? loadConfigWithSources(options.configPath, options.projectConfigPath).config,
58467
+ completion: options.completion,
58468
+ cacheDir: options.cacheDir,
58469
+ managers: options.managers
58470
+ };
58471
+ }
58472
+ function prefixFilter(values, prefix) {
58473
+ return values.filter((value) => value.startsWith(prefix));
58474
+ }
58475
+ function bashCompletionScript() {
58476
+ return `# caplets bash completion
58477
+ _caplets_completions() {
58478
+ local IFS=$'\n'
58479
+ COMPREPLY=( $(caplets __complete --shell bash -- "\${COMP_WORDS[@]:1}" 2>/dev/null) )
58480
+ }
58481
+ complete -o default -F _caplets_completions caplets
58482
+ `;
58483
+ }
58484
+ function zshCompletionScript() {
58485
+ return `#compdef caplets
58486
+ _caplets() {
58487
+ local -a suggestions
58488
+ suggestions=("\${(@f)$(caplets __complete --shell zsh -- "\${words[@]:1}" 2>/dev/null)}")
58489
+ compadd -- $suggestions
58490
+ }
58491
+ _caplets "$@"
58492
+ `;
58493
+ }
58494
+ function fishCompletionScript() {
58495
+ return `# caplets fish completion
58496
+ function __caplets_complete
58497
+ set -l tokens (commandline -opc)
58498
+ set -l current (commandline -ct)
58499
+ caplets __complete --shell fish -- $tokens[2..-1] $current 2>/dev/null
58500
+ end
58501
+ complete -c caplets -f -a '(__caplets_complete)'
58502
+ `;
58503
+ }
58504
+ function powershellCompletionScript() {
58505
+ return `# caplets PowerShell completion
58506
+ Register-ArgumentCompleter -Native -CommandName caplets -ScriptBlock {
58507
+ param($wordToComplete, $commandAst, $cursorPosition)
58508
+ $tokens = @($commandAst.CommandElements | Select-Object -Skip 1 | ForEach-Object { $_.ToString() })
58509
+ if ($tokens.Count -eq 0 -or $commandAst.Extent.Text.EndsWith(' ')) { $tokens += '${trailingSpaceCompletionToken}' }
58510
+ caplets __complete --shell powershell -- @tokens 2>$null | ForEach-Object {
58511
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
58512
+ }
58513
+ }
58514
+ `;
58515
+ }
58516
+ function cmdCompletionScript() {
58517
+ return `@echo off
58518
+ REM caplets cmd completion helper
58519
+ REM cmd.exe has no native programmable completion API. This doskey macro prints suggestions for the current words.
58520
+ doskey caplets-complete=caplets __complete --shell cmd -- $* 2^>nul
58521
+ REM Usage: caplets-complete get-caplet
58522
+ `;
58523
+ }
58524
+ //#endregion
57479
58525
  //#region ../core/dist/index.js
57480
58526
  /**
57481
58527
  * Experimental server task features for MCP SDK.
@@ -58773,7 +59819,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
58773
59819
  values: [],
58774
59820
  hasMore: false
58775
59821
  } };
58776
- var version$1 = "0.17.0";
59822
+ var version$1 = "0.18.1";
58777
59823
  var CapletsMcpSession = class {
58778
59824
  engine;
58779
59825
  server;
@@ -58815,6 +59861,7 @@ var CapletsMcpSession = class {
58815
59861
  if (!previousCaplet || serializeCaplet(previousCaplet) !== serializeCaplet(caplet)) tool.update({
58816
59862
  title: caplet.name,
58817
59863
  description: capabilityDescription(caplet),
59864
+ paramsSchema: generatedToolInputSchemaForCaplet(caplet).shape,
58818
59865
  callback: async (request) => this.handleTool(serverId, request),
58819
59866
  enabled: true
58820
59867
  });
@@ -58828,7 +59875,7 @@ var CapletsMcpSession = class {
58828
59875
  return this.server.registerTool(caplet.server, {
58829
59876
  title: caplet.name,
58830
59877
  description: capabilityDescription(caplet),
58831
- inputSchema: generatedToolInputSchema
59878
+ inputSchema: generatedToolInputSchemaForCaplet(caplet).shape
58832
59879
  }, async (request) => this.handleTool(caplet.server, request));
58833
59880
  }
58834
59881
  async handleTool(serverId, request) {
@@ -62424,124 +63471,6 @@ function starterConfig() {
62424
63471
  } }
62425
63472
  }, null, 2);
62426
63473
  }
62427
- function listCaplets(configWithSources, options) {
62428
- const { config, sources, shadows } = configWithSources;
62429
- return allCaplets(config).filter((server) => options.includeDisabled || !server.disabled).map((server) => ({
62430
- server: server.server,
62431
- backend: server.backend,
62432
- name: server.name,
62433
- description: server.description,
62434
- disabled: server.disabled,
62435
- status: initialServerStatus(server),
62436
- source: sources[server.server]?.kind ?? "unknown",
62437
- path: sources[server.server]?.path ?? null,
62438
- shadows: shadows[server.server] ?? []
62439
- })).sort((left, right) => left.server.localeCompare(right.server));
62440
- }
62441
- function initialServerStatus(server) {
62442
- return server.disabled ? "disabled" : "not_started";
62443
- }
62444
- function allCaplets(config) {
62445
- return [
62446
- ...Object.values(config.mcpServers),
62447
- ...Object.values(config.openapiEndpoints),
62448
- ...Object.values(config.graphqlEndpoints),
62449
- ...Object.values(config.httpApis),
62450
- ...Object.values(config.cliTools)
62451
- ];
62452
- }
62453
- function formatCapletList(rows, format = "plain") {
62454
- return format === "markdown" ? formatCapletListMarkdown(rows) : formatCapletListPlain(rows);
62455
- }
62456
- function formatCapletListMarkdown(rows) {
62457
- if (rows.length === 0) return "## Configured Caplets\n\nNo configured Caplets found.\n";
62458
- const heading = [
62459
- "## Configured Caplets",
62460
- "",
62461
- `${rows.length} ${rows.length === 1 ? "Caplet" : "Caplets"} shown.`,
62462
- ""
62463
- ];
62464
- const entries = rows.flatMap((row) => [
62465
- `- \`${row.server}\` — ${row.name}`,
62466
- ` - Backend: ${row.backend}`,
62467
- ` - Status: ${row.status}`,
62468
- ` - Source: ${row.source}`,
62469
- ...row.disabled ? [" - Disabled: true"] : [],
62470
- ...row.path ? [` - Path: ${row.path}`] : []
62471
- ]);
62472
- const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
62473
- if (warnings.length === 0) return `${[...heading, ...entries].join("\n")}\n`;
62474
- return `${[
62475
- ...heading,
62476
- ...entries,
62477
- "",
62478
- "Warnings:",
62479
- ...warnings.map((warning) => `- ${warning}`)
62480
- ].join("\n")}\n`;
62481
- }
62482
- function formatCapletListPlain(rows) {
62483
- if (rows.length === 0) return "No configured Caplets found.\n";
62484
- const entries = rows.map((row) => [
62485
- row.server,
62486
- ` Name: ${row.name}`,
62487
- ` Backend: ${row.backend}`,
62488
- ` Status: ${row.status}`,
62489
- ` Source: ${row.source}`,
62490
- ...row.disabled ? [" Disabled: true"] : [],
62491
- ...row.path ? [` Path: ${row.path}`] : []
62492
- ].join("\n")).join("\n\n");
62493
- const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
62494
- if (warnings.length === 0) return `Configured Caplets (${rows.length})\n\n${entries}\n`;
62495
- return `Configured Caplets (${rows.length})\n\n${entries}\n\n${warnings.join("\n")}\n`;
62496
- }
62497
- function formatSourceKind(kind) {
62498
- if (kind.startsWith("project")) return "project";
62499
- if (kind.startsWith("global")) return "global";
62500
- return kind;
62501
- }
62502
- function resolveCliConfigPaths(envConfigPath, authDir) {
62503
- const configPath = resolveConfigPath(envConfigPath);
62504
- const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
62505
- return {
62506
- userConfig: configPath,
62507
- projectConfig: resolveProjectConfigPath(),
62508
- userRoot: resolveCapletsRoot(configPath),
62509
- stateRoot: dirname(effectiveAuthDir),
62510
- projectRoot: resolveProjectCapletsRoot(),
62511
- authDir: effectiveAuthDir,
62512
- envConfig: envConfigPath ?? null
62513
- };
62514
- }
62515
- function formatConfigPaths(paths, format = "plain") {
62516
- if (format === "markdown") return formatConfigPathsMarkdown(paths);
62517
- return formatConfigPathsPlain(paths);
62518
- }
62519
- function formatConfigPathsMarkdown(paths) {
62520
- return [
62521
- "## Caplets paths",
62522
- "",
62523
- `- User config: ${paths.userConfig}`,
62524
- `- Project config: ${paths.projectConfig}`,
62525
- `- User Caplets root: ${paths.userRoot}`,
62526
- `- State root: ${paths.stateRoot}`,
62527
- `- Project Caplets root: ${paths.projectRoot}`,
62528
- `- Auth directory: ${paths.authDir}`,
62529
- `- CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
62530
- ].join("\n") + "\n";
62531
- }
62532
- function formatConfigPathsPlain(paths) {
62533
- return [
62534
- "Caplets paths",
62535
- "",
62536
- `User config: ${paths.userConfig}`,
62537
- `Project config: ${paths.projectConfig}`,
62538
- `User root: ${paths.userRoot}`,
62539
- `State root: ${paths.stateRoot}`,
62540
- `Project root: ${paths.projectRoot}`,
62541
- `Auth directory: ${paths.authDir}`,
62542
- `CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
62543
- ].join("\n") + "\n";
62544
- }
62545
63474
  function installCaplets(repo, options = {}) {
62546
63475
  const source = resolveInstallSource(repo);
62547
63476
  try {
@@ -63895,7 +64824,7 @@ var Hono$1 = class _Hono {
63895
64824
  handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
63896
64825
  handler[COMPOSED_HANDLER] = r.handler;
63897
64826
  }
63898
- subApp.#addRoute(r.method, r.path, handler);
64827
+ subApp.#addRoute(r.method, r.path, handler, r.basePath);
63899
64828
  });
63900
64829
  return this;
63901
64830
  }
@@ -64012,7 +64941,7 @@ var Hono$1 = class _Hono {
64012
64941
  const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
64013
64942
  return (request) => {
64014
64943
  const url = new URL(request.url);
64015
- url.pathname = url.pathname.slice(pathPrefixLength) || "/";
64944
+ url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
64016
64945
  return new Request(url, request);
64017
64946
  };
64018
64947
  })();
@@ -64024,11 +64953,11 @@ var Hono$1 = class _Hono {
64024
64953
  this.#addRoute("ALL", mergePath(path, "*"), handler);
64025
64954
  return this;
64026
64955
  }
64027
- #addRoute(method, path, handler) {
64956
+ #addRoute(method, path, handler, baseRoutePath) {
64028
64957
  method = method.toUpperCase();
64029
64958
  path = mergePath(this._basePath, path);
64030
64959
  const r = {
64031
- basePath: this._basePath,
64960
+ basePath: baseRoutePath !== void 0 ? mergePath(this._basePath, baseRoutePath) : this._basePath,
64032
64961
  path,
64033
64962
  method,
64034
64963
  handler
@@ -65195,29 +66124,49 @@ var RequestError = class extends Error {
65195
66124
  this.name = "RequestError";
65196
66125
  }
65197
66126
  };
65198
- var toRequestError = (e) => {
66127
+ const reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
66128
+ const reDotSegment = /\/\.\.?(?:[/?#]|$)/;
66129
+ const reValidHost = /^[a-z0-9._-]+(?::(?:[1-5]\d{3,4}|[6-9]\d{3}))?$/;
66130
+ const buildUrl = (scheme, host, incomingUrl) => {
66131
+ const url = `${scheme}://${host}${incomingUrl}`;
66132
+ if (!reValidHost.test(host)) {
66133
+ const urlObj = new URL(url);
66134
+ if (urlObj.hostname.length !== host.length && urlObj.hostname !== (host.includes(":") ? host.replace(/:\d+$/, "") : host).toLowerCase()) throw new RequestError("Invalid host header");
66135
+ return urlObj.href;
66136
+ } else if (incomingUrl.length === 0) return url + "/";
66137
+ else {
66138
+ if (incomingUrl.charCodeAt(0) !== 47) throw new RequestError("Invalid URL");
66139
+ if (!reValidRequestUrl.test(incomingUrl) || reDotSegment.test(incomingUrl)) return new URL(url).href;
66140
+ return url;
66141
+ }
66142
+ };
66143
+ const toRequestError = (e) => {
65199
66144
  if (e instanceof RequestError) return e;
65200
66145
  return new RequestError(e.message, { cause: e });
65201
66146
  };
65202
- var GlobalRequest = global.Request;
66147
+ const GlobalRequest = global.Request;
65203
66148
  var Request$1 = class extends GlobalRequest {
65204
66149
  constructor(input, options) {
65205
- if (typeof input === "object" && getRequestCache in input) input = input[getRequestCache]();
65206
- if (typeof options?.body?.getReader !== "undefined") options.duplex ??= "half";
66150
+ if (typeof input === "object" && getRequestCache in input) {
66151
+ const hasReplacementBody = options !== void 0 && "body" in options && options.body != null;
66152
+ if (input[bodyConsumedDirectlyKey] && !hasReplacementBody) throw new TypeError("Cannot construct a Request with a Request object that has already been used.");
66153
+ input = input[getRequestCache]();
66154
+ }
66155
+ if (typeof (options?.body)?.getReader !== "undefined") options.duplex ??= "half";
65207
66156
  super(input, options);
65208
66157
  }
65209
66158
  };
65210
- var newHeadersFromIncoming = (incoming) => {
66159
+ const newHeadersFromIncoming = (incoming) => {
65211
66160
  const headerRecord = [];
65212
66161
  const rawHeaders = incoming.rawHeaders;
65213
- for (let i = 0; i < rawHeaders.length; i += 2) {
65214
- const { [i]: key, [i + 1]: value } = rawHeaders;
65215
- if (key.charCodeAt(0) !== 58) headerRecord.push([key, value]);
66162
+ for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
66163
+ const key = rawHeaders[i];
66164
+ if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
65216
66165
  }
65217
66166
  return new Headers(headerRecord);
65218
66167
  };
65219
- var wrapBodyStream = Symbol("wrapBodyStream");
65220
- var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
66168
+ const wrapBodyStream = Symbol("wrapBodyStream");
66169
+ const newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
65221
66170
  const init = {
65222
66171
  method,
65223
66172
  headers,
@@ -65250,15 +66199,162 @@ var newRequestFromIncoming = (method, url, headers, incoming, abortController) =
65250
66199
  } else init.body = Readable.toWeb(incoming);
65251
66200
  return new Request$1(url, init);
65252
66201
  };
65253
- var getRequestCache = Symbol("getRequestCache");
65254
- var requestCache = Symbol("requestCache");
65255
- var incomingKey = Symbol("incomingKey");
65256
- var urlKey = Symbol("urlKey");
65257
- var headersKey = Symbol("headersKey");
65258
- var abortControllerKey = Symbol("abortControllerKey");
65259
- var requestPrototype = {
66202
+ const getRequestCache = Symbol("getRequestCache");
66203
+ const requestCache = Symbol("requestCache");
66204
+ const incomingKey = Symbol("incomingKey");
66205
+ const urlKey = Symbol("urlKey");
66206
+ const methodKey = Symbol("methodKey");
66207
+ const headersKey = Symbol("headersKey");
66208
+ const abortControllerKey = Symbol("abortControllerKey");
66209
+ const getAbortController = Symbol("getAbortController");
66210
+ const abortRequest = Symbol("abortRequest");
66211
+ const bodyBufferKey = Symbol("bodyBuffer");
66212
+ const bodyReadPromiseKey = Symbol("bodyReadPromise");
66213
+ const bodyConsumedDirectlyKey = Symbol("bodyConsumedDirectly");
66214
+ const bodyLockReaderKey = Symbol("bodyLockReader");
66215
+ const abortReasonKey = Symbol("abortReason");
66216
+ const newBodyUnusableError = () => {
66217
+ return /* @__PURE__ */ new TypeError("Body is unusable");
66218
+ };
66219
+ const rejectBodyUnusable = () => {
66220
+ return Promise.reject(newBodyUnusableError());
66221
+ };
66222
+ const textDecoder = new TextDecoder();
66223
+ const consumeBodyDirectOnce = (request) => {
66224
+ if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
66225
+ request[bodyConsumedDirectlyKey] = true;
66226
+ };
66227
+ const toArrayBuffer = (buf) => {
66228
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
66229
+ };
66230
+ const contentType = (request) => {
66231
+ return (request[headersKey] ||= newHeadersFromIncoming(request[incomingKey])).get("content-type") || "";
66232
+ };
66233
+ const methodTokenRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
66234
+ const normalizeIncomingMethod = (method) => {
66235
+ if (typeof method !== "string" || method.length === 0) return "GET";
66236
+ switch (method) {
66237
+ case "DELETE":
66238
+ case "GET":
66239
+ case "HEAD":
66240
+ case "OPTIONS":
66241
+ case "POST":
66242
+ case "PUT": return method;
66243
+ }
66244
+ const upper = method.toUpperCase();
66245
+ switch (upper) {
66246
+ case "DELETE":
66247
+ case "GET":
66248
+ case "HEAD":
66249
+ case "OPTIONS":
66250
+ case "POST":
66251
+ case "PUT": return upper;
66252
+ default: return method;
66253
+ }
66254
+ };
66255
+ const validateDirectReadMethod = (method) => {
66256
+ if (!methodTokenRegExp.test(method)) return /* @__PURE__ */ new TypeError(`'${method}' is not a valid HTTP method.`);
66257
+ const normalized = method.toUpperCase();
66258
+ if (normalized === "CONNECT" || normalized === "TRACK" || normalized === "TRACE" && method !== "TRACE") return /* @__PURE__ */ new TypeError(`'${method}' HTTP method is unsupported.`);
66259
+ };
66260
+ const readBodyWithFastPath = (request, method, fromBuffer) => {
66261
+ if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
66262
+ const methodName = request.method;
66263
+ if (methodName === "GET" || methodName === "HEAD") return request[getRequestCache]()[method]();
66264
+ const methodValidationError = validateDirectReadMethod(methodName);
66265
+ if (methodValidationError) return Promise.reject(methodValidationError);
66266
+ if (request[requestCache]) {
66267
+ if (methodName !== "TRACE") return request[requestCache][method]();
66268
+ }
66269
+ const alreadyUsedError = consumeBodyDirectOnce(request);
66270
+ if (alreadyUsedError) return alreadyUsedError;
66271
+ const raw = readRawBodyIfAvailable(request);
66272
+ if (raw) {
66273
+ const result = Promise.resolve(fromBuffer(raw, request));
66274
+ request[bodyBufferKey] = void 0;
66275
+ return result;
66276
+ }
66277
+ return readBodyDirect(request).then((buf) => {
66278
+ const result = fromBuffer(buf, request);
66279
+ request[bodyBufferKey] = void 0;
66280
+ return result;
66281
+ });
66282
+ };
66283
+ const readRawBodyIfAvailable = (request) => {
66284
+ const incoming = request[incomingKey];
66285
+ if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;
66286
+ };
66287
+ const readBodyDirect = (request) => {
66288
+ if (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);
66289
+ if (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];
66290
+ const incoming = request[incomingKey];
66291
+ if (Readable.isDisturbed(incoming)) return rejectBodyUnusable();
66292
+ const promise = new Promise((resolve, reject) => {
66293
+ const chunks = [];
66294
+ let settled = false;
66295
+ const finish = (callback) => {
66296
+ if (settled) return;
66297
+ settled = true;
66298
+ cleanup();
66299
+ callback();
66300
+ };
66301
+ const onData = (chunk) => {
66302
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
66303
+ };
66304
+ const onEnd = () => {
66305
+ finish(() => {
66306
+ const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
66307
+ request[bodyBufferKey] = buffer;
66308
+ resolve(buffer);
66309
+ });
66310
+ };
66311
+ const onError = (error) => {
66312
+ finish(() => {
66313
+ reject(error);
66314
+ });
66315
+ };
66316
+ const onClose = () => {
66317
+ if (incoming.readableEnded) {
66318
+ onEnd();
66319
+ return;
66320
+ }
66321
+ finish(() => {
66322
+ if (incoming.errored) {
66323
+ reject(incoming.errored);
66324
+ return;
66325
+ }
66326
+ const reason = request[abortReasonKey];
66327
+ if (reason !== void 0) {
66328
+ reject(reason instanceof Error ? reason : new Error(String(reason)));
66329
+ return;
66330
+ }
66331
+ reject(/* @__PURE__ */ new Error("Client connection prematurely closed."));
66332
+ });
66333
+ };
66334
+ const cleanup = () => {
66335
+ incoming.off("data", onData);
66336
+ incoming.off("end", onEnd);
66337
+ incoming.off("error", onError);
66338
+ incoming.off("close", onClose);
66339
+ request[bodyReadPromiseKey] = void 0;
66340
+ };
66341
+ incoming.on("data", onData);
66342
+ incoming.on("end", onEnd);
66343
+ incoming.on("error", onError);
66344
+ incoming.on("close", onClose);
66345
+ queueMicrotask(() => {
66346
+ if (settled) return;
66347
+ if (incoming.readableEnded) onEnd();
66348
+ else if (incoming.errored) onError(incoming.errored);
66349
+ else if (incoming.destroyed) onClose();
66350
+ });
66351
+ });
66352
+ request[bodyReadPromiseKey] = promise;
66353
+ return promise;
66354
+ };
66355
+ const requestPrototype = {
65260
66356
  get method() {
65261
- return this[incomingKey].method || "GET";
66357
+ return this[methodKey];
65262
66358
  },
65263
66359
  get url() {
65264
66360
  return this[urlKey];
@@ -65266,18 +66362,57 @@ var requestPrototype = {
65266
66362
  get headers() {
65267
66363
  return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
65268
66364
  },
65269
- [Symbol("getAbortController")]() {
65270
- this[getRequestCache]();
66365
+ [abortRequest](reason) {
66366
+ if (this[abortReasonKey] === void 0) this[abortReasonKey] = reason;
66367
+ const abortController = this[abortControllerKey];
66368
+ if (abortController && !abortController.signal.aborted) abortController.abort(reason);
66369
+ },
66370
+ [getAbortController]() {
66371
+ this[abortControllerKey] ||= new AbortController();
66372
+ if (this[abortReasonKey] !== void 0 && !this[abortControllerKey].signal.aborted) this[abortControllerKey].abort(this[abortReasonKey]);
65271
66373
  return this[abortControllerKey];
65272
66374
  },
65273
66375
  [getRequestCache]() {
65274
- this[abortControllerKey] ||= new AbortController();
65275
- return this[requestCache] ||= newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], this[abortControllerKey]);
66376
+ const abortController = this[getAbortController]();
66377
+ if (this[requestCache]) return this[requestCache];
66378
+ const method = this.method;
66379
+ if (this[bodyConsumedDirectlyKey] && !(method === "GET" || method === "HEAD")) {
66380
+ this[bodyBufferKey] = void 0;
66381
+ const init = {
66382
+ method: method === "TRACE" ? "GET" : method,
66383
+ headers: this.headers,
66384
+ signal: abortController.signal
66385
+ };
66386
+ if (method !== "TRACE") {
66387
+ init.body = new ReadableStream({ start(c) {
66388
+ c.close();
66389
+ } });
66390
+ init.duplex = "half";
66391
+ }
66392
+ const req = new Request$1(this[urlKey], init);
66393
+ if (method === "TRACE") Object.defineProperty(req, "method", { get() {
66394
+ return "TRACE";
66395
+ } });
66396
+ return this[requestCache] = req;
66397
+ }
66398
+ return this[requestCache] = newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], abortController);
66399
+ },
66400
+ get body() {
66401
+ if (!this[bodyConsumedDirectlyKey]) return this[getRequestCache]().body;
66402
+ const request = this[getRequestCache]();
66403
+ if (!this[bodyLockReaderKey] && request.body) this[bodyLockReaderKey] = request.body.getReader();
66404
+ return request.body;
66405
+ },
66406
+ get bodyUsed() {
66407
+ if (this[bodyConsumedDirectlyKey]) return true;
66408
+ if (this[requestCache]) return this[requestCache].bodyUsed;
66409
+ return false;
65276
66410
  }
65277
66411
  };
66412
+ Object.defineProperty(requestPrototype, "signal", { get() {
66413
+ return this[getAbortController]().signal;
66414
+ } });
65278
66415
  [
65279
- "body",
65280
- "bodyUsed",
65281
66416
  "cache",
65282
66417
  "credentials",
65283
66418
  "destination",
@@ -65286,25 +66421,37 @@ var requestPrototype = {
65286
66421
  "redirect",
65287
66422
  "referrer",
65288
66423
  "referrerPolicy",
65289
- "signal",
65290
66424
  "keepalive"
65291
66425
  ].forEach((k) => {
65292
66426
  Object.defineProperty(requestPrototype, k, { get() {
65293
66427
  return this[getRequestCache]()[k];
65294
66428
  } });
65295
66429
  });
65296
- [
65297
- "arrayBuffer",
65298
- "blob",
65299
- "clone",
65300
- "formData",
65301
- "json",
65302
- "text"
65303
- ].forEach((k) => {
66430
+ ["clone", "formData"].forEach((k) => {
65304
66431
  Object.defineProperty(requestPrototype, k, { value: function() {
66432
+ if (this[bodyConsumedDirectlyKey]) {
66433
+ if (k === "clone") throw newBodyUnusableError();
66434
+ return rejectBodyUnusable();
66435
+ }
65305
66436
  return this[getRequestCache]()[k]();
65306
66437
  } });
65307
66438
  });
66439
+ Object.defineProperty(requestPrototype, "text", { value: function() {
66440
+ return readBodyWithFastPath(this, "text", (buf) => textDecoder.decode(buf));
66441
+ } });
66442
+ Object.defineProperty(requestPrototype, "arrayBuffer", { value: function() {
66443
+ return readBodyWithFastPath(this, "arrayBuffer", (buf) => toArrayBuffer(buf));
66444
+ } });
66445
+ Object.defineProperty(requestPrototype, "blob", { value: function() {
66446
+ return readBodyWithFastPath(this, "blob", (buf, request) => {
66447
+ const type = contentType(request);
66448
+ return new Response(buf, type ? { headers: { "content-type": type } } : void 0).blob();
66449
+ });
66450
+ } });
66451
+ Object.defineProperty(requestPrototype, "json", { value: function() {
66452
+ if (this[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
66453
+ return this.text().then(JSON.parse);
66454
+ } });
65308
66455
  Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
65309
66456
  return `Request (lightweight) ${inspectFn({
65310
66457
  method: this.method,
@@ -65317,9 +66464,10 @@ Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom")
65317
66464
  })}`;
65318
66465
  } });
65319
66466
  Object.setPrototypeOf(requestPrototype, Request$1.prototype);
65320
- var newRequest = (incoming, defaultHostname) => {
66467
+ const newRequest = (incoming, defaultHostname) => {
65321
66468
  const req = Object.create(requestPrototype);
65322
66469
  req[incomingKey] = incoming;
66470
+ req[methodKey] = normalizeIncomingMethod(incoming.method);
65323
66471
  const incomingUrl = incoming.url || "";
65324
66472
  if (incomingUrl[0] !== "/" && (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
65325
66473
  if (incoming instanceof Http2ServerRequest) throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
@@ -65337,26 +66485,35 @@ var newRequest = (incoming, defaultHostname) => {
65337
66485
  scheme = incoming.scheme;
65338
66486
  if (!(scheme === "http" || scheme === "https")) throw new RequestError("Unsupported scheme");
65339
66487
  } else scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
65340
- const url = new URL(`${scheme}://${host}${incomingUrl}`);
65341
- if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) throw new RequestError("Invalid host header");
65342
- req[urlKey] = url.href;
66488
+ try {
66489
+ req[urlKey] = buildUrl(scheme, host, incomingUrl);
66490
+ } catch (e) {
66491
+ if (e instanceof RequestError) throw e;
66492
+ else throw new RequestError("Invalid URL", { cause: e });
66493
+ }
65343
66494
  return req;
65344
66495
  };
65345
- var responseCache = Symbol("responseCache");
65346
- var getResponseCache = Symbol("getResponseCache");
65347
- var cacheKey = Symbol("cache");
65348
- var GlobalResponse = global.Response;
65349
- var Response2 = class _Response {
66496
+ const defaultContentType = "text/plain; charset=UTF-8";
66497
+ const responseCache = Symbol("responseCache");
66498
+ const getResponseCache = Symbol("getResponseCache");
66499
+ const cacheKey = Symbol("cache");
66500
+ const GlobalResponse = global.Response;
66501
+ var Response$1 = class Response$1 {
65350
66502
  #body;
65351
66503
  #init;
65352
66504
  [getResponseCache]() {
66505
+ const cache = this[cacheKey];
66506
+ const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
65353
66507
  delete this[cacheKey];
65354
- return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
66508
+ return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
66509
+ ...this.#init,
66510
+ headers: liveHeaders
66511
+ } : this.#init);
65355
66512
  }
65356
66513
  constructor(body, init) {
65357
66514
  let headers;
65358
66515
  this.#body = body;
65359
- if (init instanceof _Response) {
66516
+ if (init instanceof Response$1) {
65360
66517
  const cachedGlobalResponse = init[responseCache];
65361
66518
  if (cachedGlobalResponse) {
65362
66519
  this.#init = cachedGlobalResponse;
@@ -65364,19 +66521,19 @@ var Response2 = class _Response {
65364
66521
  return;
65365
66522
  } else {
65366
66523
  this.#init = init.#init;
65367
- headers = new Headers(init.#init.headers);
66524
+ headers = new Headers(init.headers);
65368
66525
  }
65369
66526
  } else this.#init = init;
65370
- if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
66527
+ if (body == null || typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
65371
66528
  init?.status || 200,
65372
- body,
66529
+ body ?? null,
65373
66530
  headers || init?.headers
65374
66531
  ];
65375
66532
  }
65376
66533
  get headers() {
65377
66534
  const cache = this[cacheKey];
65378
66535
  if (cache) {
65379
- if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || { "content-type": "text/plain; charset=UTF-8" });
66536
+ if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { "content-type": defaultContentType }));
65380
66537
  return cache[2];
65381
66538
  }
65382
66539
  return this[getResponseCache]().headers;
@@ -65398,7 +66555,7 @@ var Response2 = class _Response {
65398
66555
  "type",
65399
66556
  "url"
65400
66557
  ].forEach((k) => {
65401
- Object.defineProperty(Response2.prototype, k, { get() {
66558
+ Object.defineProperty(Response$1.prototype, k, { get() {
65402
66559
  return this[getResponseCache]()[k];
65403
66560
  } });
65404
66561
  });
@@ -65410,11 +66567,11 @@ var Response2 = class _Response {
65410
66567
  "json",
65411
66568
  "text"
65412
66569
  ].forEach((k) => {
65413
- Object.defineProperty(Response2.prototype, k, { value: function() {
66570
+ Object.defineProperty(Response$1.prototype, k, { value: function() {
65414
66571
  return this[getResponseCache]()[k]();
65415
66572
  } });
65416
66573
  });
65417
- Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
66574
+ Object.defineProperty(Response$1.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
65418
66575
  return `Response (lightweight) ${inspectFn({
65419
66576
  status: this.status,
65420
66577
  headers: this.headers,
@@ -65425,8 +66582,51 @@ Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custo
65425
66582
  depth: depth == null ? null : depth - 1
65426
66583
  })}`;
65427
66584
  } });
65428
- Object.setPrototypeOf(Response2, GlobalResponse);
65429
- Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
66585
+ Object.setPrototypeOf(Response$1, GlobalResponse);
66586
+ Object.setPrototypeOf(Response$1.prototype, GlobalResponse.prototype);
66587
+ const validRedirectUrl = /^https?:\/\/[!#-;=?-[\]_a-z~A-Z]+$/;
66588
+ const parseRedirectUrl = (url) => {
66589
+ if (url instanceof URL) return url.href;
66590
+ if (validRedirectUrl.test(url)) return url;
66591
+ return new URL(url).href;
66592
+ };
66593
+ const validRedirectStatuses = new Set([
66594
+ 301,
66595
+ 302,
66596
+ 303,
66597
+ 307,
66598
+ 308
66599
+ ]);
66600
+ Object.defineProperty(Response$1, "redirect", {
66601
+ value: function redirect(url, status = 302) {
66602
+ if (!validRedirectStatuses.has(status)) throw new RangeError("Invalid status code");
66603
+ return new Response$1(null, {
66604
+ status,
66605
+ headers: { location: parseRedirectUrl(url) }
66606
+ });
66607
+ },
66608
+ writable: true,
66609
+ configurable: true
66610
+ });
66611
+ Object.defineProperty(Response$1, "json", {
66612
+ value: function json(data, init) {
66613
+ const body = JSON.stringify(data);
66614
+ if (body === void 0) throw new TypeError("The data is not JSON serializable");
66615
+ const initHeaders = init?.headers;
66616
+ let headers;
66617
+ if (initHeaders) {
66618
+ headers = new Headers(initHeaders);
66619
+ if (!headers.has("content-type")) headers.set("content-type", "application/json");
66620
+ } else headers = { "content-type": "application/json" };
66621
+ return new Response$1(body, {
66622
+ status: init?.status ?? 200,
66623
+ statusText: init?.statusText,
66624
+ headers
66625
+ });
66626
+ },
66627
+ writable: true,
66628
+ configurable: true
66629
+ });
65430
66630
  async function readWithoutBlocking(readPromise) {
65431
66631
  return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
65432
66632
  }
@@ -65462,23 +66662,23 @@ function writeFromReadableStream(stream, writable) {
65462
66662
  else if (writable.destroyed) return;
65463
66663
  return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
65464
66664
  }
65465
- var buildOutgoingHttpHeaders = (headers) => {
66665
+ const buildOutgoingHttpHeaders = (headers, defaultContentType) => {
65466
66666
  const res = {};
65467
66667
  if (!(headers instanceof Headers)) headers = new Headers(headers ?? void 0);
65468
- const cookies = [];
65469
- for (const [k, v] of headers) if (k === "set-cookie") cookies.push(v);
65470
- else res[k] = v;
65471
- if (cookies.length > 0) res["set-cookie"] = cookies;
65472
- res["content-type"] ??= "text/plain; charset=UTF-8";
66668
+ if (headers.has("set-cookie")) {
66669
+ const cookies = [];
66670
+ for (const [k, v] of headers) if (k === "set-cookie") cookies.push(v);
66671
+ else res[k] = v;
66672
+ if (cookies.length > 0) res["set-cookie"] = cookies;
66673
+ } else for (const [k, v] of headers) res[k] = v;
66674
+ if (defaultContentType) res["content-type"] ??= defaultContentType;
65473
66675
  return res;
65474
66676
  };
65475
- var X_ALREADY_SENT = "x-hono-already-sent";
65476
- if (typeof global.crypto === "undefined") global.crypto = crypto$1;
65477
- var outgoingEnded = Symbol("outgoingEnded");
65478
- var incomingDraining = Symbol("incomingDraining");
65479
- var DRAIN_TIMEOUT_MS = 500;
65480
- var MAX_DRAIN_BYTES = 64 * 1024 * 1024;
65481
- var drainIncoming = (incoming) => {
66677
+ const outgoingEnded = Symbol("outgoingEnded");
66678
+ const incomingDraining = Symbol("incomingDraining");
66679
+ const DRAIN_TIMEOUT_MS = 500;
66680
+ const MAX_DRAIN_BYTES = 64 * 1024 * 1024;
66681
+ const drainIncoming = (incoming) => {
65482
66682
  const incomingWithDrainState = incoming;
65483
66683
  if (incoming.destroyed || incomingWithDrainState[incomingDraining]) return;
65484
66684
  incomingWithDrainState[incomingDraining] = true;
@@ -65511,9 +66711,23 @@ var drainIncoming = (incoming) => {
65511
66711
  incoming.on("error", cleanup);
65512
66712
  incoming.resume();
65513
66713
  };
65514
- var handleRequestError = () => new Response(null, { status: 400 });
65515
- var handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500 });
65516
- var handleResponseError = (e, outgoing) => {
66714
+ const makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
66715
+ if (incoming.errored) req[abortRequest](incoming.errored.toString());
66716
+ else if (!outgoing.writableFinished) req[abortRequest]("Client connection prematurely closed.");
66717
+ if (needsBodyCleanup && !incoming.readableEnded) setTimeout(() => {
66718
+ if (!incoming.readableEnded) setTimeout(() => {
66719
+ drainIncoming(incoming);
66720
+ });
66721
+ });
66722
+ };
66723
+ const isImmediateCacheableResponse = (res) => {
66724
+ if (!(cacheKey in res)) return false;
66725
+ const body = res[cacheKey][1];
66726
+ return body === null || typeof body === "string" || body instanceof Uint8Array;
66727
+ };
66728
+ const handleRequestError = () => new Response(null, { status: 400 });
66729
+ const handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500 });
66730
+ const handleResponseError = (e, outgoing) => {
65517
66731
  const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
65518
66732
  if (err.code === "ERR_STREAM_PREMATURE_CLOSE") console.info("The user aborted a request.");
65519
66733
  else {
@@ -65523,20 +66737,49 @@ var handleResponseError = (e, outgoing) => {
65523
66737
  outgoing.destroy(err);
65524
66738
  }
65525
66739
  };
65526
- var flushHeaders = (outgoing) => {
66740
+ const flushHeaders = (outgoing) => {
65527
66741
  if ("flushHeaders" in outgoing && outgoing.writable) outgoing.flushHeaders();
65528
66742
  };
65529
- var responseViaCache = async (res, outgoing) => {
66743
+ const responseViaCache = async (res, outgoing) => {
65530
66744
  let [status, body, header] = res[cacheKey];
66745
+ if (!header) {
66746
+ if (body === null) {
66747
+ outgoing.writeHead(status);
66748
+ outgoing.end();
66749
+ } else if (typeof body === "string") {
66750
+ outgoing.writeHead(status, {
66751
+ "Content-Type": defaultContentType,
66752
+ "Content-Length": Buffer.byteLength(body)
66753
+ });
66754
+ outgoing.end(body);
66755
+ } else if (body instanceof Uint8Array) {
66756
+ outgoing.writeHead(status, {
66757
+ "Content-Type": defaultContentType,
66758
+ "Content-Length": body.byteLength
66759
+ });
66760
+ outgoing.end(body);
66761
+ } else if (body instanceof Blob) {
66762
+ outgoing.writeHead(status, {
66763
+ "Content-Type": defaultContentType,
66764
+ "Content-Length": body.size
66765
+ });
66766
+ outgoing.end(new Uint8Array(await body.arrayBuffer()));
66767
+ } else {
66768
+ outgoing.writeHead(status, { "Content-Type": defaultContentType });
66769
+ flushHeaders(outgoing);
66770
+ await writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));
66771
+ }
66772
+ outgoing[outgoingEnded]?.();
66773
+ return;
66774
+ }
65531
66775
  let hasContentLength = false;
65532
- if (!header) header = { "content-type": "text/plain; charset=UTF-8" };
65533
- else if (header instanceof Headers) {
66776
+ if (header instanceof Headers) {
65534
66777
  hasContentLength = header.has("content-length");
65535
- header = buildOutgoingHttpHeaders(header);
66778
+ header = buildOutgoingHttpHeaders(header, body === null ? void 0 : defaultContentType);
65536
66779
  } else if (Array.isArray(header)) {
65537
66780
  const headerObj = new Headers(header);
65538
66781
  hasContentLength = headerObj.has("content-length");
65539
- header = buildOutgoingHttpHeaders(headerObj);
66782
+ header = buildOutgoingHttpHeaders(headerObj, body === null ? void 0 : defaultContentType);
65540
66783
  } else for (const key in header) if (key.length === 14 && key.toLowerCase() === "content-length") {
65541
66784
  hasContentLength = true;
65542
66785
  break;
@@ -65547,7 +66790,8 @@ var responseViaCache = async (res, outgoing) => {
65547
66790
  else if (body instanceof Blob) header["Content-Length"] = body.size;
65548
66791
  }
65549
66792
  outgoing.writeHead(status, header);
65550
- if (typeof body === "string" || body instanceof Uint8Array) outgoing.end(body);
66793
+ if (body == null) outgoing.end();
66794
+ else if (typeof body === "string" || body instanceof Uint8Array) outgoing.end(body);
65551
66795
  else if (body instanceof Blob) outgoing.end(new Uint8Array(await body.arrayBuffer()));
65552
66796
  else {
65553
66797
  flushHeaders(outgoing);
@@ -65555,8 +66799,8 @@ var responseViaCache = async (res, outgoing) => {
65555
66799
  }
65556
66800
  outgoing[outgoingEnded]?.();
65557
66801
  };
65558
- var isPromise = (res) => typeof res.then === "function";
65559
- var responseViaResponseObject = async (res, outgoing, options = {}) => {
66802
+ const isPromise = (res) => typeof res.then === "function";
66803
+ const responseViaResponseObject = async (res, outgoing, options = {}) => {
65560
66804
  if (isPromise(res)) if (options.errorHandler) try {
65561
66805
  res = await res;
65562
66806
  } catch (err) {
@@ -65566,7 +66810,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
65566
66810
  }
65567
66811
  else res = await res.catch(handleFetchError);
65568
66812
  if (cacheKey in res) return responseViaCache(res, outgoing);
65569
- const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
66813
+ const resHeaderRecord = buildOutgoingHttpHeaders(res.headers, res.body === null ? void 0 : defaultContentType);
65570
66814
  if (res.body) {
65571
66815
  const reader = res.body.getReader();
65572
66816
  const values = [];
@@ -65606,57 +66850,55 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
65606
66850
  if (values.length === 0) flushHeaders(outgoing);
65607
66851
  await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
65608
66852
  }
65609
- } else if (resHeaderRecord[X_ALREADY_SENT]) {} else {
66853
+ } else if (resHeaderRecord["x-hono-already-sent"]) {} else {
65610
66854
  outgoing.writeHead(res.status, resHeaderRecord);
65611
66855
  outgoing.end();
65612
66856
  }
65613
66857
  outgoing[outgoingEnded]?.();
65614
66858
  };
65615
- var getRequestListener = (fetchCallback, options = {}) => {
66859
+ const getRequestListener = (fetchCallback, options = {}) => {
65616
66860
  const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
65617
66861
  if (options.overrideGlobalObjects !== false && global.Request !== Request$1) {
65618
66862
  Object.defineProperty(global, "Request", { value: Request$1 });
65619
- Object.defineProperty(global, "Response", { value: Response2 });
66863
+ Object.defineProperty(global, "Response", { value: Response$1 });
65620
66864
  }
65621
66865
  return async (incoming, outgoing) => {
65622
66866
  let res, req;
66867
+ let needsBodyCleanup = false;
66868
+ let closeHandlerAttached = false;
66869
+ const ensureCloseHandler = () => {
66870
+ if (!req || closeHandlerAttached) return;
66871
+ closeHandlerAttached = true;
66872
+ outgoing.on("close", makeCloseHandler(req, incoming, outgoing, needsBodyCleanup));
66873
+ };
65623
66874
  try {
65624
66875
  req = newRequest(incoming, options.hostname);
65625
- let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
65626
- if (!incomingEnded) {
66876
+ needsBodyCleanup = autoCleanupIncoming && !(incoming.method === "GET" || incoming.method === "HEAD");
66877
+ if (needsBodyCleanup) {
65627
66878
  incoming[wrapBodyStream] = true;
65628
- incoming.on("end", () => {
65629
- incomingEnded = true;
65630
- });
65631
66879
  if (incoming instanceof Http2ServerRequest) outgoing[outgoingEnded] = () => {
65632
- if (!incomingEnded) setTimeout(() => {
65633
- if (!incomingEnded) setTimeout(() => {
65634
- drainIncoming(incoming);
66880
+ if (!incoming.readableEnded) setTimeout(() => {
66881
+ if (!incoming.readableEnded) setTimeout(() => {
66882
+ incoming.destroy();
66883
+ outgoing.destroy();
65635
66884
  });
65636
66885
  });
65637
66886
  };
65638
- outgoing.on("finish", () => {
65639
- if (!incomingEnded) drainIncoming(incoming);
65640
- });
65641
66887
  }
65642
- outgoing.on("close", () => {
65643
- if (req[abortControllerKey]) {
65644
- if (incoming.errored) req[abortControllerKey].abort(incoming.errored.toString());
65645
- else if (!outgoing.writableFinished) req[abortControllerKey].abort("Client connection prematurely closed.");
65646
- }
65647
- if (!incomingEnded) setTimeout(() => {
65648
- if (!incomingEnded) setTimeout(() => {
65649
- drainIncoming(incoming);
65650
- });
65651
- });
65652
- });
65653
66888
  res = fetchCallback(req, {
65654
66889
  incoming,
65655
66890
  outgoing
65656
66891
  });
65657
- if (cacheKey in res) return responseViaCache(res, outgoing);
66892
+ if (!isPromise(res) && isImmediateCacheableResponse(res)) {
66893
+ if (needsBodyCleanup && !incoming.readableEnded) outgoing.once("finish", () => {
66894
+ if (!incoming.readableEnded) drainIncoming(incoming);
66895
+ });
66896
+ return responseViaCache(res, outgoing);
66897
+ }
66898
+ ensureCloseHandler();
65658
66899
  } catch (e) {
65659
66900
  if (!res) if (options.errorHandler) {
66901
+ ensureCloseHandler();
65660
66902
  res = await options.errorHandler(req ? e : toRequestError(e));
65661
66903
  if (!res) return;
65662
66904
  } else if (!req) res = handleRequestError();
@@ -65670,16 +66912,126 @@ var getRequestListener = (fetchCallback, options = {}) => {
65670
66912
  }
65671
66913
  };
65672
66914
  };
65673
- var createAdaptorServer = (options) => {
66915
+ globalThis.CloseEvent;
66916
+ const CONNECTION_SYMBOL_KEY = Symbol("CONNECTION_SYMBOL_KEY");
66917
+ const WAIT_FOR_WEBSOCKET_SYMBOL = Symbol("WAIT_FOR_WEBSOCKET_SYMBOL");
66918
+ const responseHeadersToSkip = new Set([
66919
+ "connection",
66920
+ "content-length",
66921
+ "keep-alive",
66922
+ "proxy-authenticate",
66923
+ "proxy-authorization",
66924
+ "te",
66925
+ "trailer",
66926
+ "transfer-encoding",
66927
+ "upgrade",
66928
+ "sec-websocket-accept",
66929
+ "sec-websocket-extensions",
66930
+ "sec-websocket-protocol"
66931
+ ]);
66932
+ const appendResponseHeaders = (headers, responseHeaders) => {
66933
+ if (!responseHeaders) return;
66934
+ responseHeaders.forEach((value, key) => {
66935
+ if (responseHeadersToSkip.has(key.toLowerCase())) return;
66936
+ headers.push(`${key}: ${value}`);
66937
+ });
66938
+ };
66939
+ const rejectUpgradeRequest = (socket, status, responseHeaders) => {
66940
+ const responseLines = ["Connection: close", "Content-Length: 0"];
66941
+ appendResponseHeaders(responseLines, responseHeaders);
66942
+ socket.end(`HTTP/1.1 ${status.toString()} ${STATUS_CODES[status] ?? ""}\r\n${responseLines.join("\r\n")}\r\n\r
66943
+ `);
66944
+ };
66945
+ const createUpgradeRequest = (request) => {
66946
+ const protocol = request.socket.encrypted ? "https" : "http";
66947
+ const url = new URL(request.url ?? "/", `${protocol}://${request.headers.host ?? "localhost"}`);
66948
+ const headers = new Headers();
66949
+ for (const key in request.headers) {
66950
+ const value = request.headers[key];
66951
+ if (!value) continue;
66952
+ headers.append(key, Array.isArray(value) ? value[0] : value);
66953
+ }
66954
+ return new Request(url, { headers });
66955
+ };
66956
+ const setupWebSocket = (options) => {
66957
+ const { server, fetchCallback, wss } = options;
66958
+ const waiterMap = /* @__PURE__ */ new Map();
66959
+ wss.on("connection", (ws, request) => {
66960
+ const waiter = waiterMap.get(request);
66961
+ if (waiter) {
66962
+ waiter.resolve(ws);
66963
+ waiterMap.delete(request);
66964
+ }
66965
+ });
66966
+ const waitForWebSocket = (request, connectionSymbol) => {
66967
+ return new Promise((resolve) => {
66968
+ waiterMap.set(request, {
66969
+ resolve,
66970
+ connectionSymbol
66971
+ });
66972
+ });
66973
+ };
66974
+ server.on("upgrade", async (request, socket, head) => {
66975
+ if (request.headers.upgrade?.toLowerCase() !== "websocket") return;
66976
+ const env = {
66977
+ incoming: request,
66978
+ outgoing: void 0,
66979
+ wss,
66980
+ [WAIT_FOR_WEBSOCKET_SYMBOL]: waitForWebSocket
66981
+ };
66982
+ let status = 400;
66983
+ let responseHeaders;
66984
+ try {
66985
+ const response = await fetchCallback(createUpgradeRequest(request), env);
66986
+ if (response instanceof Response) {
66987
+ status = response.status;
66988
+ responseHeaders = response.headers;
66989
+ }
66990
+ } catch {
66991
+ if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, 500);
66992
+ return;
66993
+ }
66994
+ const waiter = waiterMap.get(request);
66995
+ if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
66996
+ waiterMap.delete(request);
66997
+ if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, status, responseHeaders);
66998
+ return;
66999
+ }
67000
+ const addResponseHeaders = (headers) => {
67001
+ appendResponseHeaders(headers, responseHeaders);
67002
+ };
67003
+ wss.on("headers", addResponseHeaders);
67004
+ try {
67005
+ wss.handleUpgrade(request, socket, head, (ws) => {
67006
+ wss.emit("connection", ws, request);
67007
+ });
67008
+ } finally {
67009
+ wss.off("headers", addResponseHeaders);
67010
+ }
67011
+ });
67012
+ server.on("close", () => {
67013
+ wss.close();
67014
+ });
67015
+ };
67016
+ const createAdaptorServer = (options) => {
65674
67017
  const fetchCallback = options.fetch;
65675
67018
  const requestListener = getRequestListener(fetchCallback, {
65676
67019
  hostname: options.hostname,
65677
67020
  overrideGlobalObjects: options.overrideGlobalObjects,
65678
67021
  autoCleanupIncoming: options.autoCleanupIncoming
65679
67022
  });
65680
- return (options.createServer || createServer$1)(options.serverOptions || {}, requestListener);
67023
+ const server = (options.createServer || createServer)(options.serverOptions || {}, requestListener);
67024
+ if (options.websocket && options.websocket.server) {
67025
+ if (options.websocket.server.options.noServer !== true) throw new Error("WebSocket server must be created with { noServer: true } option");
67026
+ setupWebSocket({
67027
+ server,
67028
+ fetchCallback,
67029
+ wss: options.websocket.server
67030
+ });
67031
+ }
67032
+ return server;
65681
67033
  };
65682
- var serve = (options, listeningListener) => {
67034
+ const serve = (options, listeningListener) => {
65683
67035
  const server = createAdaptorServer(options);
65684
67036
  server.listen(options?.port ?? 3e3, options.hostname, () => {
65685
67037
  const serverInfo = server.address();
@@ -65738,7 +67090,15 @@ const ENGINE_COMMANDS = new Set([
65738
67090
  "list_tools",
65739
67091
  "search_tools",
65740
67092
  "get_tool",
65741
- "call_tool"
67093
+ "call_tool",
67094
+ "list_resources",
67095
+ "search_resources",
67096
+ "list_resource_templates",
67097
+ "read_resource",
67098
+ "list_prompts",
67099
+ "search_prompts",
67100
+ "get_prompt",
67101
+ "complete"
65742
67102
  ]);
65743
67103
  async function dispatchRemoteCliRequest(request, context) {
65744
67104
  try {
@@ -65789,6 +67149,16 @@ async function dispatch(request, context) {
65789
67149
  ...optionalProp("force", optionalBoolean(request.arguments, "force"))
65790
67150
  })
65791
67151
  };
67152
+ if (request.command === "complete_cli") {
67153
+ const shell = optionalString(request.arguments, "shell") ?? "bash";
67154
+ if (!completionShells.includes(shell)) return [];
67155
+ const engine = new CapletsEngine(context);
67156
+ try {
67157
+ return await engine.completeCliWords(optionalStringArray(request.arguments, "words") ?? [""]);
67158
+ } finally {
67159
+ await engine.close();
67160
+ }
67161
+ }
65792
67162
  if (request.command === "auth_list") return listAuthRows({
65793
67163
  ...optionalProp("configPath", context.configPath),
65794
67164
  ...optionalProp("authDir", context.authDir)
@@ -65905,6 +67275,12 @@ function requiredString(args, key) {
65905
67275
  if (typeof value !== "string" || value.length === 0) throw new CapletsError("REQUEST_INVALID", `${key} must be a non-empty string`);
65906
67276
  return value;
65907
67277
  }
67278
+ function optionalString(args, key) {
67279
+ const value = args[key];
67280
+ if (value === void 0) return;
67281
+ if (typeof value !== "string") throw new CapletsError("REQUEST_INVALID", `${key} must be a string`);
67282
+ return value;
67283
+ }
65908
67284
  function optionalObject(args, key) {
65909
67285
  const value = args[key];
65910
67286
  if (value === void 0) return {};
@@ -66467,6 +67843,9 @@ async function runCli(args, io = {}) {
66467
67843
  throw error;
66468
67844
  }
66469
67845
  }
67846
+ function normalizeCompletionWords(words) {
67847
+ return words.map((word) => word === "__CAPLETS_TRAILING_SPACE__" ? "" : word);
67848
+ }
66470
67849
  function createProgram(io = {}) {
66471
67850
  const writeOut = io.writeOut ?? ((value) => process.stdout.write(value));
66472
67851
  const writeErr = io.writeErr ?? ((value) => process.stderr.write(value));
@@ -66481,7 +67860,27 @@ function createProgram(io = {}) {
66481
67860
  writeErr,
66482
67861
  outputError: (value, write) => write(value)
66483
67862
  });
66484
- program.command("serve").description("Serve configured Caplets as an MCP server.").option("--transport <transport>", "server transport: stdio or http").option("--host <host>", "HTTP bind host").option("--port <port>", "HTTP bind port").option("--path <path>", "HTTP service base path").option("--user <user>", "HTTP Basic Auth username").option("--password <password>", "HTTP Basic Auth password").option("--allow-unauthenticated-http", "allow unauthenticated HTTP serving on non-loopback hosts").option("--trust-proxy", "trust X-Forwarded-* headers from a reverse proxy").action(async (options) => {
67863
+ program.command(cliCommands.completion).description("Print a shell completion script.").argument("<shell>", "completion shell: bash, zsh, fish, powershell, or cmd").action((shell) => {
67864
+ if (!completionShells.includes(shell)) throw new CapletsError("REQUEST_INVALID", "completion shell must be bash, zsh, fish, powershell, or cmd");
67865
+ writeOut(completionScript(shell));
67866
+ });
67867
+ program.command(cliCommands.completeHidden, { hidden: true }).description("Internal shell completion endpoint.").option("--shell <shell>", "completion shell").allowUnknownOption(true).argument("[words...]", "words to complete").action(async (words, options) => {
67868
+ const shell = completionShells.includes(options.shell) ? options.shell : "bash";
67869
+ const remote = remoteClientForCli(io);
67870
+ const configPath = currentConfigPath();
67871
+ const completionWords = normalizeCompletionWords(words);
67872
+ let suggestions = [];
67873
+ try {
67874
+ suggestions = remote ? await remote.request("complete_cli", {
67875
+ shell,
67876
+ words: completionWords
67877
+ }) : await completeCliWords(completionWords, configPath ? { configPath } : {});
67878
+ } catch {
67879
+ suggestions = [];
67880
+ }
67881
+ if (suggestions.length > 0) writeOut(`${suggestions.join("\n")}\n`);
67882
+ });
67883
+ program.command(cliCommands.serve).description("Serve configured Caplets as an MCP server.").option("--transport <transport>", "server transport: stdio or http").option("--host <host>", "HTTP bind host").option("--port <port>", "HTTP bind port").option("--path <path>", "HTTP service base path").option("--user <user>", "HTTP Basic Auth username").option("--password <password>", "HTTP Basic Auth password").option("--allow-unauthenticated-http", "allow unauthenticated HTTP serving on non-loopback hosts").option("--trust-proxy", "trust X-Forwarded-* headers from a reverse proxy").action(async (options) => {
66485
67884
  const resolved = resolveServeOptions(options);
66486
67885
  const configPath = currentConfigPath();
66487
67886
  await (io.serve ?? ((serveOptions) => serveResolvedCaplets(serveOptions, {
@@ -66489,7 +67888,7 @@ function createProgram(io = {}) {
66489
67888
  ...io.authDir ? { authDir: io.authDir } : {}
66490
67889
  }, writeErr)))(resolved);
66491
67890
  });
66492
- program.command("init").description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
67891
+ program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
66493
67892
  const remote = remoteClientForCli(io);
66494
67893
  if (remote) {
66495
67894
  writeOut(`Created remote Caplets config at ${(await remote.request("init", { force: Boolean(options.force) })).path}\n`);
@@ -66501,7 +67900,7 @@ function createProgram(io = {}) {
66501
67900
  force: Boolean(options.force)
66502
67901
  })}\n`);
66503
67902
  });
66504
- program.command("list").description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action(async (options) => {
67903
+ program.command(cliCommands.list).description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action(async (options) => {
66505
67904
  const includeDisabled = Boolean(options.all);
66506
67905
  const remote = remoteClientForCli(io);
66507
67906
  if (remote) {
@@ -66520,7 +67919,7 @@ function createProgram(io = {}) {
66520
67919
  }
66521
67920
  writeOut(formatCapletList(rows, options.format ?? "plain"));
66522
67921
  });
66523
- program.command("install").description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("-g, --global", "install to the user Caplets root").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
67922
+ program.command(cliCommands.install).description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("-g, --global", "install to the user Caplets root").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
66524
67923
  const remote = remoteClientForCli(io);
66525
67924
  if (remote) {
66526
67925
  if (options.global) writeErr("Warning: --global is not supported in remote mode; the server controls the installation destination.\n");
@@ -66539,7 +67938,7 @@ function createProgram(io = {}) {
66539
67938
  });
66540
67939
  for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${caplet.destination}\n`);
66541
67940
  });
66542
- const add = program.command("add").description("Add generated Caplet files.");
67941
+ const add = program.command(cliCommands.add).description("Add generated Caplet files.");
66543
67942
  add.command("cli").description("Add a CLI tools Caplet.").argument("<id>", "Caplet ID/display seed").option("--repo <path>", "repository path to inspect").option("--include <items>", "comma-separated generators to include: git,gh,package").option("--command <name>", "single CLI command template to generate").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
66544
67943
  const remote = remoteClientForCli(io);
66545
67944
  if (remote) {
@@ -66620,7 +68019,7 @@ function createProgram(io = {}) {
66620
68019
  destinationRoot: addDestinationRoot(options, currentConfigPath())
66621
68020
  }));
66622
68021
  });
66623
- program.command("get-caplet").description("Print a configured Caplet card.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
68022
+ program.command(cliCommands.getCaplet).description("Print a configured Caplet card.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
66624
68023
  await executeOperation(caplet, { operation: "get_caplet" }, {
66625
68024
  writeOut,
66626
68025
  writeErr,
@@ -66631,7 +68030,7 @@ function createProgram(io = {}) {
66631
68030
  format: options.format
66632
68031
  });
66633
68032
  });
66634
- program.command("check-backend").description("Check backend availability for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
68033
+ program.command(cliCommands.checkBackend).description("Check backend availability for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
66635
68034
  await executeOperation(caplet, { operation: "check_backend" }, {
66636
68035
  writeOut,
66637
68036
  writeErr,
@@ -66642,7 +68041,7 @@ function createProgram(io = {}) {
66642
68041
  format: options.format
66643
68042
  });
66644
68043
  });
66645
- program.command("list-tools").description("List downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
68044
+ program.command(cliCommands.listTools).description("List downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
66646
68045
  await executeOperation(caplet, { operation: "list_tools" }, {
66647
68046
  writeOut,
66648
68047
  writeErr,
@@ -66653,7 +68052,7 @@ function createProgram(io = {}) {
66653
68052
  format: options.format
66654
68053
  });
66655
68054
  });
66656
- program.command("search-tools").description("Search downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").argument("<query>", "search query").option("--limit <n>", "maximum number of tools to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => {
68055
+ program.command(cliCommands.searchTools).description("Search downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").argument("<query>", "search query").option("--limit <n>", "maximum number of tools to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => {
66657
68056
  await executeOperation(caplet, options.limit === void 0 ? {
66658
68057
  operation: "search_tools",
66659
68058
  query
@@ -66671,7 +68070,7 @@ function createProgram(io = {}) {
66671
68070
  format: options.format
66672
68071
  });
66673
68072
  });
66674
- program.command("get-tool").description("Print one downstream tool schema.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
68073
+ program.command(cliCommands.getTool).description("Print one downstream tool schema.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
66675
68074
  const { caplet, tool } = parseQualifiedTarget(target);
66676
68075
  await executeOperation(caplet, {
66677
68076
  operation: "get_tool",
@@ -66686,7 +68085,7 @@ function createProgram(io = {}) {
66686
68085
  format: options.format
66687
68086
  });
66688
68087
  });
66689
- program.command("call-tool").description("Call one downstream tool.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
68088
+ program.command(cliCommands.callTool).description("Call one downstream tool.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
66690
68089
  const { caplet, tool } = parseQualifiedTarget(target);
66691
68090
  await executeOperation(caplet, {
66692
68091
  operation: "call_tool",
@@ -66703,7 +68102,119 @@ function createProgram(io = {}) {
66703
68102
  format: options.format
66704
68103
  });
66705
68104
  });
66706
- const config = program.command("config").description("Inspect Caplets config locations.");
68105
+ program.command(cliCommands.listResources).description("List MCP resources for a configured MCP Caplet.").argument("<caplet>").option("--limit <n>", "maximum number of resources to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, options.limit === void 0 ? { operation: "list_resources" } : {
68106
+ operation: "list_resources",
68107
+ limit: options.limit
68108
+ }, {
68109
+ writeOut,
68110
+ writeErr,
68111
+ setExitCode,
68112
+ authDir: io.authDir,
68113
+ env,
68114
+ remote: remoteClientForCli(io),
68115
+ format: options.format
68116
+ }));
68117
+ program.command(cliCommands.searchResources).description("Search MCP resources and resource templates for a configured MCP Caplet.").argument("<caplet>").argument("<query>").option("--limit <n>", "maximum number of matches to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => executeOperation(caplet, options.limit === void 0 ? {
68118
+ operation: "search_resources",
68119
+ query
68120
+ } : {
68121
+ operation: "search_resources",
68122
+ query,
68123
+ limit: options.limit
68124
+ }, {
68125
+ writeOut,
68126
+ writeErr,
68127
+ setExitCode,
68128
+ authDir: io.authDir,
68129
+ env,
68130
+ remote: remoteClientForCli(io),
68131
+ format: options.format
68132
+ }));
68133
+ program.command(cliCommands.listResourceTemplates).description("List MCP resource templates for a configured MCP Caplet.").argument("<caplet>").option("--limit <n>", "maximum number of templates to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, options.limit === void 0 ? { operation: "list_resource_templates" } : {
68134
+ operation: "list_resource_templates",
68135
+ limit: options.limit
68136
+ }, {
68137
+ writeOut,
68138
+ writeErr,
68139
+ setExitCode,
68140
+ authDir: io.authDir,
68141
+ env,
68142
+ remote: remoteClientForCli(io),
68143
+ format: options.format
68144
+ }));
68145
+ program.command(cliCommands.readResource).description("Read one MCP resource by URI.").argument("<caplet>").argument("<uri>").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, uri, options) => executeOperation(caplet, {
68146
+ operation: "read_resource",
68147
+ uri
68148
+ }, {
68149
+ writeOut,
68150
+ writeErr,
68151
+ setExitCode,
68152
+ authDir: io.authDir,
68153
+ env,
68154
+ remote: remoteClientForCli(io),
68155
+ format: options.format
68156
+ }));
68157
+ program.command(cliCommands.listPrompts).description("List MCP prompts for a configured MCP Caplet.").argument("<caplet>").option("--limit <n>", "maximum number of prompts to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, options.limit === void 0 ? { operation: "list_prompts" } : {
68158
+ operation: "list_prompts",
68159
+ limit: options.limit
68160
+ }, {
68161
+ writeOut,
68162
+ writeErr,
68163
+ setExitCode,
68164
+ authDir: io.authDir,
68165
+ env,
68166
+ remote: remoteClientForCli(io),
68167
+ format: options.format
68168
+ }));
68169
+ program.command(cliCommands.searchPrompts).description("Search MCP prompts for a configured MCP Caplet.").argument("<caplet>").argument("<query>").option("--limit <n>", "maximum number of prompts to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => executeOperation(caplet, options.limit === void 0 ? {
68170
+ operation: "search_prompts",
68171
+ query
68172
+ } : {
68173
+ operation: "search_prompts",
68174
+ query,
68175
+ limit: options.limit
68176
+ }, {
68177
+ writeOut,
68178
+ writeErr,
68179
+ setExitCode,
68180
+ authDir: io.authDir,
68181
+ env,
68182
+ remote: remoteClientForCli(io),
68183
+ format: options.format
68184
+ }));
68185
+ program.command(cliCommands.getPrompt).description("Get one MCP prompt by name.").argument("<caplet.prompt>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of prompt arguments").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
68186
+ const { caplet, tool: prompt } = parseQualifiedTarget(target);
68187
+ await executeOperation(caplet, {
68188
+ operation: "get_prompt",
68189
+ prompt,
68190
+ arguments: parseJsonObjectOption(options.args, "get-prompt --args")
68191
+ }, {
68192
+ writeOut,
68193
+ writeErr,
68194
+ setExitCode,
68195
+ authDir: io.authDir,
68196
+ env,
68197
+ remote: remoteClientForCli(io),
68198
+ format: options.format
68199
+ });
68200
+ });
68201
+ program.command(cliCommands.complete).description("Complete an MCP prompt or resource-template argument.").argument("<caplet>").requiredOption("--argument <name>", "argument name").option("--value <value>", "argument prefix", "").option("--prompt <name>", "prompt name to complete").option("--resource-template <uri-template>", "resource template URI to complete").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, {
68202
+ operation: "complete",
68203
+ ref: completionRefFromOptions(options),
68204
+ argument: {
68205
+ name: options.argument,
68206
+ value: options.value
68207
+ }
68208
+ }, {
68209
+ writeOut,
68210
+ writeErr,
68211
+ setExitCode,
68212
+ authDir: io.authDir,
68213
+ env,
68214
+ remote: remoteClientForCli(io),
68215
+ format: options.format
68216
+ }));
68217
+ const config = program.command(cliCommands.config).description("Inspect Caplets config locations.");
66707
68218
  config.command("path").description("Print the effective user config path.").action(() => {
66708
68219
  writeOut(`${resolveConfigPath(currentConfigPath())}\n`);
66709
68220
  });
@@ -66715,7 +68226,7 @@ function createProgram(io = {}) {
66715
68226
  }
66716
68227
  writeOut(formatConfigPaths(paths, options.format ?? "plain"));
66717
68228
  });
66718
- const auth = program.command("auth").description("Manage OAuth credentials for remote servers.");
68229
+ const auth = program.command(cliCommands.auth).description("Manage OAuth credentials for remote servers.");
66719
68230
  auth.command("login").description("Authenticate a configured remote OAuth server.").argument("<server>", "configured server ID").option("--no-open", "print the authorization URL without opening a browser").action(async (serverId, options) => {
66720
68231
  const remote = remoteClientForCli(io);
66721
68232
  if (remote) {
@@ -66800,7 +68311,15 @@ function remoteCommandForOperation(operation) {
66800
68311
  case "list_tools":
66801
68312
  case "search_tools":
66802
68313
  case "get_tool":
66803
- case "call_tool": return operation;
68314
+ case "call_tool":
68315
+ case "list_resources":
68316
+ case "search_resources":
68317
+ case "list_resource_templates":
68318
+ case "read_resource":
68319
+ case "list_prompts":
68320
+ case "search_prompts":
68321
+ case "get_prompt":
68322
+ case "complete": return operation;
66804
68323
  default: return;
66805
68324
  }
66806
68325
  }
@@ -66848,6 +68367,29 @@ function parseCallToolArgs(value) {
66848
68367
  if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", "call-tool --args must be a JSON object");
66849
68368
  return parsed;
66850
68369
  }
68370
+ function parseJsonObjectOption(value, label) {
68371
+ if (value === void 0) return {};
68372
+ let parsed;
68373
+ try {
68374
+ parsed = JSON.parse(value);
68375
+ } catch (error) {
68376
+ throw new CapletsError("REQUEST_INVALID", `${label} must be valid JSON`, error);
68377
+ }
68378
+ if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", `${label} must be a JSON object`);
68379
+ return parsed;
68380
+ }
68381
+ function completionRefFromOptions(options) {
68382
+ if (options.prompt && options.resourceTemplate) throw new CapletsError("REQUEST_INVALID", "complete accepts either --prompt or --resource-template, not both");
68383
+ if (options.prompt) return {
68384
+ type: "prompt",
68385
+ name: options.prompt
68386
+ };
68387
+ if (options.resourceTemplate) return {
68388
+ type: "resourceTemplate",
68389
+ uri: options.resourceTemplate
68390
+ };
68391
+ throw new CapletsError("REQUEST_INVALID", "complete requires --prompt or --resource-template");
68392
+ }
66851
68393
  function isPlainObject(value) {
66852
68394
  return value !== null && typeof value === "object" && !Array.isArray(value);
66853
68395
  }
@@ -66978,6 +68520,55 @@ function markdownSummaryForOperation(result, request) {
66978
68520
  "",
66979
68521
  "Use `--format json` to inspect the full structured result."
66980
68522
  ].filter((line) => line !== void 0).join("\n");
68523
+ case "list_resources":
68524
+ case "search_resources": {
68525
+ const resources = Array.isArray(payload.resources) ? payload.resources : [];
68526
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68527
+ const matches = Array.isArray(payload.matches) ? payload.matches : [...resources, ...templates];
68528
+ return [
68529
+ `## MCP resources for \`${id}\``,
68530
+ "",
68531
+ `${matches.length} item${matches.length === 1 ? "" : "s"} found.`,
68532
+ "",
68533
+ ...formatResourceLines(matches, "markdown")
68534
+ ].join("\n");
68535
+ }
68536
+ case "list_resource_templates": {
68537
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68538
+ return [
68539
+ `## MCP resource templates for \`${id}\``,
68540
+ "",
68541
+ ...formatResourceLines(templates, "markdown")
68542
+ ].join("\n");
68543
+ }
68544
+ case "read_resource": return [
68545
+ `## Resource \`${String(request.uri ?? "")}\``,
68546
+ "",
68547
+ summarizeResourceRead(payload),
68548
+ "",
68549
+ "Use `--format json` to inspect all contents."
68550
+ ].join("\n");
68551
+ case "list_prompts":
68552
+ case "search_prompts": {
68553
+ const prompts = Array.isArray(payload.prompts) ? payload.prompts : [];
68554
+ return [
68555
+ `## MCP prompts for \`${id}\``,
68556
+ "",
68557
+ ...formatPromptLines(prompts, "markdown")
68558
+ ].join("\n");
68559
+ }
68560
+ case "get_prompt": return [
68561
+ `## Prompt \`${String(request.caplet)}.${String(request.prompt)}\``,
68562
+ "",
68563
+ summarizePromptResult(payload),
68564
+ "",
68565
+ "Use `--format json` to inspect all messages."
68566
+ ].join("\n");
68567
+ case "complete": return [
68568
+ `## Completion for \`${id}\``,
68569
+ "",
68570
+ summarizeCompletionResult(payload)
68571
+ ].join("\n");
66981
68572
  default: return JSON.stringify(payload, null, 2);
66982
68573
  }
66983
68574
  }
@@ -67034,6 +68625,33 @@ function plainSummaryForOperation(result, request) {
67034
68625
  `Result: ${summarizeCallResult(payload)}`,
67035
68626
  "Use --format json to inspect the full structured result."
67036
68627
  ].filter((line) => Boolean(line)).join("\n");
68628
+ case "list_resources":
68629
+ case "search_resources": {
68630
+ const resources = Array.isArray(payload.resources) ? payload.resources : [];
68631
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68632
+ const matches = Array.isArray(payload.matches) ? payload.matches : [...resources, ...templates];
68633
+ return [`MCP resources for ${id} (${matches.length}):`, ...formatResourceLines(matches, "plain")].join("\n");
68634
+ }
68635
+ case "list_resource_templates": {
68636
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68637
+ return [`MCP resource templates for ${id}:`, ...formatResourceLines(templates, "plain")].join("\n");
68638
+ }
68639
+ case "read_resource": return [
68640
+ `Resource ${String(request.uri ?? "")}`,
68641
+ summarizeResourceRead(payload),
68642
+ "Use --format json to inspect all contents."
68643
+ ].join("\n");
68644
+ case "list_prompts":
68645
+ case "search_prompts": {
68646
+ const prompts = Array.isArray(payload.prompts) ? payload.prompts : [];
68647
+ return [`MCP prompts for ${id}:`, ...formatPromptLines(prompts, "plain")].join("\n");
68648
+ }
68649
+ case "get_prompt": return [
68650
+ `Prompt ${String(request.caplet)}.${String(request.prompt)}`,
68651
+ summarizePromptResult(payload),
68652
+ "Use --format json to inspect all messages."
68653
+ ].join("\n");
68654
+ case "complete": return [`Completion for ${id}`, summarizeCompletionResult(payload)].join("\n");
67037
68655
  default: return JSON.stringify(payload, null, 2);
67038
68656
  }
67039
68657
  }
@@ -67050,6 +68668,44 @@ function formatToolLines(tools, format) {
67050
68668
  return `- ${displayName}${flags ? ` (${flags})` : ""}${tool.description ? ` — ${compactDescription(String(tool.description))}` : ""}`;
67051
68669
  });
67052
68670
  }
68671
+ function formatResourceLines(resources, format) {
68672
+ if (resources.length === 0) return ["- none"];
68673
+ return resources.map((resource) => {
68674
+ if (!isPlainObject(resource)) return `- ${String(resource)}`;
68675
+ const name = String(resource.uri ?? resource.uriTemplate ?? "unknown");
68676
+ const displayName = format === "markdown" ? `\`${name}\`` : name;
68677
+ const label = typeof resource.name === "string" ? ` (${resource.name})` : "";
68678
+ return `- ${typeof resource.kind === "string" ? `${resource.kind}: ` : ""}${displayName}${label}${resource.description ? ` — ${compactDescription(String(resource.description))}` : ""}`;
68679
+ });
68680
+ }
68681
+ function formatPromptLines(prompts, format) {
68682
+ if (prompts.length === 0) return ["- none"];
68683
+ return prompts.map((prompt) => {
68684
+ if (!isPlainObject(prompt)) return `- ${String(prompt)}`;
68685
+ const name = String(prompt.prompt ?? prompt.name ?? "unknown");
68686
+ return `- ${format === "markdown" ? `\`${name}\`` : name}${Array.isArray(prompt.arguments) ? ` (${prompt.arguments.length} args)` : ""}${prompt.description ? ` — ${compactDescription(String(prompt.description))}` : ""}`;
68687
+ });
68688
+ }
68689
+ function summarizeResourceRead(payload) {
68690
+ const contents = Array.isArray(payload.contents) ? payload.contents : [];
68691
+ if (contents.length === 0) return "No contents returned.";
68692
+ const first = contents.find(isPlainObject);
68693
+ if (!first) return `${contents.length} content item${contents.length === 1 ? "" : "s"} returned.`;
68694
+ return previewValue(typeof first.text === "string" ? first.text : first.blob) ?? `${contents.length} content item${contents.length === 1 ? "" : "s"} returned.`;
68695
+ }
68696
+ function summarizePromptResult(payload) {
68697
+ const messages = Array.isArray(payload.messages) ? payload.messages : [];
68698
+ if (messages.length === 0) return "No messages returned.";
68699
+ const first = messages.find(isPlainObject);
68700
+ if (!first) return `${messages.length} message${messages.length === 1 ? "" : "s"} returned.`;
68701
+ return previewValue((isPlainObject(first.content) ? first.content : void 0)?.text ?? first.content) ?? `${messages.length} message${messages.length === 1 ? "" : "s"} returned.`;
68702
+ }
68703
+ function summarizeCompletionResult(payload) {
68704
+ const completion = isPlainObject(payload.completion) ? payload.completion : void 0;
68705
+ const values = Array.isArray(completion?.values) ? completion.values : [];
68706
+ if (values.length > 0) return values.map((value) => `- ${String(value)}`).join("\n");
68707
+ return previewValue(payload) ?? "No completions returned.";
68708
+ }
67053
68709
  function compactDescription(value) {
67054
68710
  const firstParagraph = value.trim().split(/\n\s*\n/u)[0] ?? "";
67055
68711
  const collapsed = (firstParagraph.match(/^.*?(?:[.!?](?=\s|$)|$)/u)?.[0] ?? firstParagraph).replace(/\s+/gu, " ").trim();
@@ -67124,7 +68780,7 @@ function writeAddResult(writeOut, label, result) {
67124
68780
  }
67125
68781
  //#endregion
67126
68782
  //#region package.json
67127
- var version = "0.16.0";
68783
+ var version = "0.17.1";
67128
68784
  //#endregion
67129
68785
  //#region src/index.ts
67130
68786
  async function main() {