caplets 0.16.0 → 0.17.0

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 +1938 -702
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -15,455 +15,19 @@ import { createServer as createServer$1 } from "http";
15
15
  import { Http2ServerRequest, constants as constants$1 } from "http2";
16
16
  import { Readable } from "stream";
17
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."
18
+ //#region \0rolldown/runtime.js
19
+ var __defProp$1 = Object.defineProperty;
20
+ var __exportAll$1 = (all, no_symbols) => {
21
+ let target = {};
22
+ for (var name in all) __defProp$1(target, name, {
23
+ get: all[name],
24
+ enumerable: true
25
+ });
26
+ if (!no_symbols) __defProp$1(target, Symbol.toStringTag, { value: "Module" });
27
+ return target;
34
28
  };
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
29
  //#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
- }
30
+ //#region ../core/dist/generated-tool-input-schema-B6rce396.js
467
31
  var _a$1;
468
32
  /** A special constant with type `never` */
469
33
  const NEVER = /* @__PURE__ */ Object.freeze({ status: "aborted" });
@@ -607,7 +171,7 @@ const allowsEval = /* @__PURE__ */ cached(() => {
607
171
  return false;
608
172
  }
609
173
  });
610
- function isPlainObject$6(o) {
174
+ function isPlainObject$8(o) {
611
175
  if (isObject(o) === false) return false;
612
176
  const ctor = o.constructor;
613
177
  if (ctor === void 0) return true;
@@ -618,7 +182,7 @@ function isPlainObject$6(o) {
618
182
  return true;
619
183
  }
620
184
  function shallowClone(o) {
621
- if (isPlainObject$6(o)) return { ...o };
185
+ if (isPlainObject$8(o)) return { ...o };
622
186
  if (Array.isArray(o)) return [...o];
623
187
  if (o instanceof Map) return new Map(o);
624
188
  if (o instanceof Set) return new Set(o);
@@ -701,7 +265,7 @@ function omit(schema, mask) {
701
265
  }));
702
266
  }
703
267
  function extend(schema, shape) {
704
- if (!isPlainObject$6(shape)) throw new Error("Invalid input to extend: expected a plain object");
268
+ if (!isPlainObject$8(shape)) throw new Error("Invalid input to extend: expected a plain object");
705
269
  const checks = schema._zod.def.checks;
706
270
  if (checks && checks.length > 0) {
707
271
  const existingShape = schema._zod.def.shape;
@@ -717,7 +281,7 @@ function extend(schema, shape) {
717
281
  } }));
718
282
  }
719
283
  function safeExtend(schema, shape) {
720
- if (!isPlainObject$6(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
284
+ if (!isPlainObject$8(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
721
285
  return clone(schema, mergeDefs(schema._zod.def, { get shape() {
722
286
  const _shape = {
723
287
  ...schema._zod.def.shape,
@@ -908,7 +472,7 @@ const _parse = (_Err) => (schema, value, _ctx, _params) => {
908
472
  }
909
473
  return result.value;
910
474
  };
911
- const parse$3 = /* @__PURE__ */ _parse($ZodRealError);
475
+ const parse$1 = /* @__PURE__ */ _parse($ZodRealError);
912
476
  const _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
913
477
  const ctx = _ctx ? {
914
478
  ..._ctx,
@@ -945,7 +509,7 @@ const _safeParse = (_Err) => (schema, value, _ctx) => {
945
509
  data: result.value
946
510
  };
947
511
  };
948
- const safeParse$2 = /* @__PURE__ */ _safeParse($ZodRealError);
512
+ const safeParse$1 = /* @__PURE__ */ _safeParse($ZodRealError);
949
513
  const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
950
514
  const ctx = _ctx ? {
951
515
  ..._ctx,
@@ -964,7 +528,7 @@ const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
964
528
  data: result.value
965
529
  };
966
530
  };
967
- const safeParseAsync$2 = /* @__PURE__ */ _safeParseAsync($ZodRealError);
531
+ const safeParseAsync$1 = /* @__PURE__ */ _safeParseAsync($ZodRealError);
968
532
  const _encode = (_Err) => (schema, value, _ctx) => {
969
533
  const ctx = _ctx ? {
970
534
  ..._ctx,
@@ -1063,7 +627,7 @@ const string$1 = (params) => {
1063
627
  return new RegExp(`^${regex}$`);
1064
628
  };
1065
629
  const integer = /^-?\d+$/;
1066
- const number$2 = /^-?\d+(?:\.\d+)?$/;
630
+ const number$1 = /^-?\d+(?:\.\d+)?$/;
1067
631
  const boolean$1 = /^(?:true|false)$/i;
1068
632
  const _null$2 = /^null$/i;
1069
633
  const lowercase = /^[^A-Z]*$/;
@@ -1537,10 +1101,10 @@ const $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
1537
1101
  defineLazy(inst, "~standard", () => ({
1538
1102
  validate: (value) => {
1539
1103
  try {
1540
- const r = safeParse$2(inst, value);
1104
+ const r = safeParse$1(inst, value);
1541
1105
  return r.success ? { value: r.data } : { issues: r.error?.issues };
1542
1106
  } catch (_) {
1543
- return safeParseAsync$2(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues });
1107
+ return safeParseAsync$1(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues });
1544
1108
  }
1545
1109
  },
1546
1110
  vendor: "zod",
@@ -1830,7 +1394,7 @@ const $ZodJWT = /* @__PURE__ */ $constructor("$ZodJWT", (inst, def) => {
1830
1394
  });
1831
1395
  const $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => {
1832
1396
  $ZodType.init(inst, def);
1833
- inst._zod.pattern = inst._zod.bag.pattern ?? number$2;
1397
+ inst._zod.pattern = inst._zod.bag.pattern ?? number$1;
1834
1398
  inst._zod.parse = (payload, _ctx) => {
1835
1399
  if (def.coerce) try {
1836
1400
  payload.value = Number(payload.value);
@@ -2317,7 +1881,7 @@ function mergeValues$1(a, b) {
2317
1881
  valid: true,
2318
1882
  data: a
2319
1883
  };
2320
- if (isPlainObject$6(a) && isPlainObject$6(b)) {
1884
+ if (isPlainObject$8(a) && isPlainObject$8(b)) {
2321
1885
  const bKeys = Object.keys(b);
2322
1886
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
2323
1887
  const newObj = {
@@ -2393,7 +1957,7 @@ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
2393
1957
  $ZodType.init(inst, def);
2394
1958
  inst._zod.parse = (payload, ctx) => {
2395
1959
  const input = payload.value;
2396
- if (!isPlainObject$6(input)) {
1960
+ if (!isPlainObject$8(input)) {
2397
1961
  payload.issues.push({
2398
1962
  expected: "record",
2399
1963
  code: "invalid_type",
@@ -2460,7 +2024,7 @@ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
2460
2024
  issues: []
2461
2025
  }, ctx);
2462
2026
  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) {
2027
+ if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) {
2464
2028
  const retryResult = def.keyType._zod.run({
2465
2029
  value: Number(key),
2466
2030
  issues: []
@@ -4135,8 +3699,8 @@ const initializer = (inst, issues) => {
4135
3699
  const ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer, { Parent: Error });
4136
3700
  const parse$2 = /* @__PURE__ */ _parse(ZodRealError);
4137
3701
  const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
4138
- const safeParse$1 = /* @__PURE__ */ _safeParse(ZodRealError);
4139
- const safeParseAsync$1 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
3702
+ const safeParse$2 = /* @__PURE__ */ _safeParse(ZodRealError);
3703
+ const safeParseAsync$2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
4140
3704
  const encode = /* @__PURE__ */ _encode(ZodRealError);
4141
3705
  const decode = /* @__PURE__ */ _decode(ZodRealError);
4142
3706
  const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError);
@@ -4192,9 +3756,9 @@ const ZodType$1 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
4192
3756
  inst.type = def.type;
4193
3757
  Object.defineProperty(inst, "_def", { value: def });
4194
3758
  inst.parse = (data, params) => parse$2(inst, data, params, { callee: inst.parse });
4195
- inst.safeParse = (data, params) => safeParse$1(inst, data, params);
3759
+ inst.safeParse = (data, params) => safeParse$2(inst, data, params);
4196
3760
  inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync });
4197
- inst.safeParseAsync = async (data, params) => safeParseAsync$1(inst, data, params);
3761
+ inst.safeParseAsync = async (data, params) => safeParseAsync$2(inst, data, params);
4198
3762
  inst.spa = inst.safeParseAsync;
4199
3763
  inst.encode = (data, params) => encode(inst, data, params);
4200
3764
  inst.decode = (data, params) => decode(inst, data, params);
@@ -4543,7 +4107,7 @@ const ZodNumber$1 = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
4543
4107
  inst.isFinite = true;
4544
4108
  inst.format = bag.format ?? null;
4545
4109
  });
4546
- function number$1(params) {
4110
+ function number$2(params) {
4547
4111
  return /* @__PURE__ */ _number(ZodNumber$1, params);
4548
4112
  }
4549
4113
  const ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, def) => {
@@ -4989,6 +4553,571 @@ function preprocess(fn, schema) {
4989
4553
  out: schema
4990
4554
  });
4991
4555
  }
4556
+ const operations = [
4557
+ "get_caplet",
4558
+ "check_backend",
4559
+ "list_tools",
4560
+ "search_tools",
4561
+ "get_tool",
4562
+ "call_tool"
4563
+ ];
4564
+ const mcpOperations = [
4565
+ ...operations,
4566
+ "list_resources",
4567
+ "search_resources",
4568
+ "list_resource_templates",
4569
+ "read_resource",
4570
+ "list_prompts",
4571
+ "search_prompts",
4572
+ "get_prompt",
4573
+ "complete"
4574
+ ];
4575
+ const generatedToolInputDescriptions = {
4576
+ operation: "Wrapper operation: get_caplet, check_backend, list_tools, search_tools, get_tool, call_tool. MCP Caplets also expose resources, prompts, and completions.",
4577
+ query: "Required for search operations only.",
4578
+ limit: "Optional list/search result limit.",
4579
+ tool: "Exact downstream tool name for get_tool or call_tool.",
4580
+ arguments: "JSON object for call_tool arguments/downstream inputs or get_prompt arguments.",
4581
+ fields: "Optional call_tool structured output paths when outputSchema allows it.",
4582
+ uri: "Exact downstream resource URI for read_resource.",
4583
+ prompt: "Exact downstream prompt name for get_prompt.",
4584
+ ref: "Completion target reference for complete.",
4585
+ argument: "Completion argument object for complete."
4586
+ };
4587
+ const completionRefSchema = union([object$1({
4588
+ type: literal("prompt"),
4589
+ name: string().min(1)
4590
+ }).strict(), object$1({
4591
+ type: literal("resourceTemplate"),
4592
+ uri: string().min(1)
4593
+ }).strict()]);
4594
+ const completionArgumentSchema = object$1({
4595
+ name: string().min(1),
4596
+ value: string()
4597
+ }).strict();
4598
+ const baseShape = {
4599
+ query: string().optional().describe(generatedToolInputDescriptions.query),
4600
+ limit: number$2().int().positive().optional().describe(generatedToolInputDescriptions.limit),
4601
+ tool: string().optional().describe(generatedToolInputDescriptions.tool),
4602
+ arguments: object$1({}).catchall(any()).optional().describe(generatedToolInputDescriptions.arguments),
4603
+ fields: array(string().min(1)).min(1).optional().describe(generatedToolInputDescriptions.fields)
4604
+ };
4605
+ function generatedToolInputSchemaForCaplet(caplet) {
4606
+ return object$1({
4607
+ operation: (caplet.backend === "mcp" ? _enum(mcpOperations) : _enum(operations)).describe(generatedToolInputDescriptions.operation),
4608
+ ...baseShape,
4609
+ ...caplet.backend === "mcp" ? {
4610
+ uri: string().optional().describe(generatedToolInputDescriptions.uri),
4611
+ prompt: string().optional().describe(generatedToolInputDescriptions.prompt),
4612
+ ref: completionRefSchema.optional().describe(generatedToolInputDescriptions.ref),
4613
+ argument: completionArgumentSchema.optional().describe(generatedToolInputDescriptions.argument)
4614
+ } : {}
4615
+ }).strict();
4616
+ }
4617
+ object$1({
4618
+ operation: _enum(operations).describe(generatedToolInputDescriptions.operation),
4619
+ ...baseShape
4620
+ }).strict();
4621
+ function generatedToolInputJsonSchemaForCaplet(caplet) {
4622
+ const mcp = caplet.backend === "mcp";
4623
+ return {
4624
+ type: "object",
4625
+ properties: {
4626
+ operation: {
4627
+ type: "string",
4628
+ enum: mcp ? mcpOperations : operations,
4629
+ description: generatedToolInputDescriptions.operation
4630
+ },
4631
+ query: {
4632
+ type: "string",
4633
+ description: generatedToolInputDescriptions.query
4634
+ },
4635
+ limit: {
4636
+ type: "integer",
4637
+ minimum: 1,
4638
+ description: generatedToolInputDescriptions.limit
4639
+ },
4640
+ tool: {
4641
+ type: "string",
4642
+ description: generatedToolInputDescriptions.tool
4643
+ },
4644
+ arguments: {
4645
+ type: "object",
4646
+ description: generatedToolInputDescriptions.arguments
4647
+ },
4648
+ fields: {
4649
+ type: "array",
4650
+ items: {
4651
+ type: "string",
4652
+ minLength: 1
4653
+ },
4654
+ minItems: 1,
4655
+ description: generatedToolInputDescriptions.fields
4656
+ },
4657
+ ...mcp ? {
4658
+ uri: {
4659
+ type: "string",
4660
+ description: generatedToolInputDescriptions.uri
4661
+ },
4662
+ prompt: {
4663
+ type: "string",
4664
+ description: generatedToolInputDescriptions.prompt
4665
+ },
4666
+ ref: {
4667
+ oneOf: [{
4668
+ type: "object",
4669
+ properties: {
4670
+ type: { const: "prompt" },
4671
+ name: {
4672
+ type: "string",
4673
+ minLength: 1
4674
+ }
4675
+ },
4676
+ required: ["type", "name"],
4677
+ additionalProperties: false
4678
+ }, {
4679
+ type: "object",
4680
+ properties: {
4681
+ type: { const: "resourceTemplate" },
4682
+ uri: {
4683
+ type: "string",
4684
+ minLength: 1
4685
+ }
4686
+ },
4687
+ required: ["type", "uri"],
4688
+ additionalProperties: false
4689
+ }],
4690
+ description: generatedToolInputDescriptions.ref
4691
+ },
4692
+ argument: {
4693
+ type: "object",
4694
+ properties: {
4695
+ name: {
4696
+ type: "string",
4697
+ minLength: 1
4698
+ },
4699
+ value: { type: "string" }
4700
+ },
4701
+ required: ["name", "value"],
4702
+ additionalProperties: false,
4703
+ description: generatedToolInputDescriptions.argument
4704
+ }
4705
+ } : {}
4706
+ },
4707
+ required: ["operation"],
4708
+ additionalProperties: false
4709
+ };
4710
+ }
4711
+ function generatedToolInputJsonSchema() {
4712
+ return generatedToolInputJsonSchemaForCaplet({ backend: "tool" });
4713
+ }
4714
+ //#endregion
4715
+ //#region ../core/dist/options-DM1cMRcp.js
4716
+ var __create = Object.create;
4717
+ var __defProp = Object.defineProperty;
4718
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4719
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4720
+ var __getProtoOf = Object.getPrototypeOf;
4721
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4722
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4723
+ var __exportAll = (all, no_symbols) => {
4724
+ let target = {};
4725
+ for (var name in all) __defProp(target, name, {
4726
+ get: all[name],
4727
+ enumerable: true
4728
+ });
4729
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
4730
+ return target;
4731
+ };
4732
+ var __copyProps = (to, from, except, desc) => {
4733
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
4734
+ key = keys[i];
4735
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
4736
+ get: ((k) => from[k]).bind(null, key),
4737
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
4738
+ });
4739
+ }
4740
+ return to;
4741
+ };
4742
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
4743
+ value: mod,
4744
+ enumerable: true
4745
+ }) : target, mod));
4746
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4747
+ const CAPLETS_ERROR_CODES = [
4748
+ "CONFIG_NOT_FOUND",
4749
+ "CONFIG_EXISTS",
4750
+ "CONFIG_INVALID",
4751
+ "REQUEST_INVALID",
4752
+ "SERVER_NOT_FOUND",
4753
+ "SERVER_UNAVAILABLE",
4754
+ "SERVER_START_TIMEOUT",
4755
+ "UNKNOWN_OPERATION",
4756
+ "TOOL_NOT_FOUND",
4757
+ "TOOL_CALL_TIMEOUT",
4758
+ "AUTH_REQUIRED",
4759
+ "AUTH_FAILED",
4760
+ "AUTH_REFRESH_FAILED",
4761
+ "DOWNSTREAM_PROTOCOL_ERROR",
4762
+ "DOWNSTREAM_TOOL_ERROR",
4763
+ "UNSUPPORTED_OPERATION",
4764
+ "UNSUPPORTED_CAPABILITY",
4765
+ "PROMPT_NOT_FOUND",
4766
+ "DOWNSTREAM_RESOURCE_ERROR",
4767
+ "DOWNSTREAM_PROMPT_ERROR",
4768
+ "DOWNSTREAM_COMPLETION_ERROR",
4769
+ "UNSUPPORTED_TRANSPORT",
4770
+ "INTERNAL_ERROR"
4771
+ ];
4772
+ var CapletsError = class extends Error {
4773
+ code;
4774
+ details;
4775
+ constructor(code, message, details) {
4776
+ super(message);
4777
+ this.name = "CapletsError";
4778
+ this.code = code;
4779
+ this.details = details;
4780
+ }
4781
+ };
4782
+ const SECRET_KEY_PATTERN = /(token|secret|authorization|auth|api[-_]?key|password|credential|clientsecret|client_secret|code|refresh)/i;
4783
+ const SECRET_VALUE_PATTERN = /(bearer\s+)[a-z0-9._~+/=-]+|([?&](?:access_token|refresh_token|token|code)=)[^&\s]+/gi;
4784
+ function redactSecrets(value) {
4785
+ if (typeof value === "string") return value.replace(SECRET_VALUE_PATTERN, "$1$2[REDACTED]");
4786
+ if (Array.isArray(value)) return value.map((item) => redactSecrets(item));
4787
+ if (value && typeof value === "object") {
4788
+ const redacted = {};
4789
+ for (const [key, nested] of Object.entries(value)) redacted[key] = SECRET_KEY_PATTERN.test(key) ? "[REDACTED]" : redactSecrets(nested);
4790
+ return redacted;
4791
+ }
4792
+ return value;
4793
+ }
4794
+ function toSafeError(error, fallback = "INTERNAL_ERROR") {
4795
+ if (error instanceof CapletsError) return {
4796
+ code: error.code,
4797
+ message: String(redactSecrets(error.message)),
4798
+ ...error.details === void 0 ? {} : { details: redactSecrets(error.details) }
4799
+ };
4800
+ if (error instanceof Error) return {
4801
+ code: fallback,
4802
+ message: String(redactSecrets(error.message))
4803
+ };
4804
+ return {
4805
+ code: fallback,
4806
+ message: String(redactSecrets(error))
4807
+ };
4808
+ }
4809
+ function errorResult(error, fallback) {
4810
+ const safe = toSafeError(error, fallback);
4811
+ return {
4812
+ isError: true,
4813
+ content: [{
4814
+ type: "text",
4815
+ text: `${safe.code}: ${safe.message}`
4816
+ }],
4817
+ structuredContent: { error: safe }
4818
+ };
4819
+ }
4820
+ function textContent(text) {
4821
+ return text ? [{
4822
+ type: "text",
4823
+ text
4824
+ }] : [];
4825
+ }
4826
+ function compactJsonText(value, maxLength = 600) {
4827
+ return compactText(JSON.stringify(value) ?? String(value), maxLength);
4828
+ }
4829
+ function compactText(value, maxLength = 600) {
4830
+ const collapsed = value.replace(/\s+/gu, " ").trim();
4831
+ return collapsed.length > maxLength ? `${collapsed.slice(0, maxLength - 1).trimEnd()}…` : collapsed;
4832
+ }
4833
+ function resultKeys(value) {
4834
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "scalar result";
4835
+ const keys = Object.keys(value).filter((key) => key !== "elapsedMs");
4836
+ return keys.length > 0 ? `structured keys: ${keys.join(", ")}` : "empty structured result";
4837
+ }
4838
+ function statusSummary(value) {
4839
+ if (!value || typeof value !== "object" || Array.isArray(value)) return compactJsonText(value);
4840
+ const record = value;
4841
+ return [
4842
+ typeof record.status === "number" ? `status ${record.status}` : void 0,
4843
+ typeof record.statusText === "string" && record.statusText ? record.statusText : void 0,
4844
+ typeof record.exitCode === "number" ? `exit ${record.exitCode}` : void 0,
4845
+ "body" in record ? "body" : void 0,
4846
+ "json" in record ? "json" : void 0,
4847
+ typeof record.stdout === "string" && record.stdout ? "stdout" : void 0,
4848
+ typeof record.stderr === "string" && record.stderr ? "stderr" : void 0
4849
+ ].filter((part) => Boolean(part)).join("; ") || resultKeys(record);
4850
+ }
4851
+ function compactStructuredContent(value) {
4852
+ return textContent(statusSummary(value));
4853
+ }
4854
+ function searchToolList(tools, query, limit, compact) {
4855
+ const tokens = query.toLocaleLowerCase().split(/\s+/).filter(Boolean);
4856
+ return tools.filter((tool) => {
4857
+ const haystack = `${tool.name}\n${tool.description ?? ""}`.toLocaleLowerCase();
4858
+ return tokens.some((token) => haystack.includes(token));
4859
+ }).sort((left, right) => left.name.localeCompare(right.name)).slice(0, limit).map(compact);
4860
+ }
4861
+ const DEFAULT_INPUT_SCHEMA$1 = {
4862
+ type: "object",
4863
+ additionalProperties: true
4864
+ };
4865
+ var CliToolsManager = class {
4866
+ registry;
4867
+ constructor(registry) {
4868
+ this.registry = registry;
4869
+ }
4870
+ updateRegistry(registry) {
4871
+ this.registry = registry;
4872
+ }
4873
+ invalidate(_serverId) {}
4874
+ async checkTools(config) {
4875
+ const startedAt = Date.now();
4876
+ try {
4877
+ for (const action of actionsFor(config)) {
4878
+ const cwdTemplate = action.cwd ?? config.cwd;
4879
+ if (cwdTemplate && !cwdTemplate.includes("$input")) {
4880
+ if (!existsSync(interpolateRequiredString(cwdTemplate, {}, "cwd"))) throw new CapletsError("CONFIG_INVALID", `CLI cwd does not exist for ${config.server}/${action.name}`);
4881
+ }
4882
+ if (!action.command.includes("$input")) resolveCommandPath(action.command);
4883
+ }
4884
+ this.registry.setStatus(config.server, "available");
4885
+ return {
4886
+ id: config.server,
4887
+ status: "available",
4888
+ toolCount: Object.keys(config.actions).length,
4889
+ elapsedMs: Date.now() - startedAt
4890
+ };
4891
+ } catch (error) {
4892
+ const safe = toSafeError(error, "SERVER_UNAVAILABLE");
4893
+ this.registry.setStatus(config.server, "unavailable", safe);
4894
+ return {
4895
+ id: config.server,
4896
+ status: "unavailable",
4897
+ elapsedMs: Date.now() - startedAt,
4898
+ error: safe
4899
+ };
4900
+ }
4901
+ }
4902
+ async listTools(config) {
4903
+ return actionsFor(config).map((action) => this.toTool(action));
4904
+ }
4905
+ async getTool(config, toolName) {
4906
+ return this.toTool(getAction(config, toolName));
4907
+ }
4908
+ async callTool(config, toolName, args) {
4909
+ const action = getAction(config, toolName);
4910
+ validateInput(action, args);
4911
+ const execution = resolveExecution(config, action, args);
4912
+ const startedAt = Date.now();
4913
+ const controller = new AbortController();
4914
+ const timeout = setTimeout(() => controller.abort(), execution.timeoutMs);
4915
+ try {
4916
+ const result = await spawnCommand(execution, controller.signal, () => Date.now() - startedAt);
4917
+ const structured = parseStructuredResult(action, result, result.exitCode !== 0);
4918
+ return {
4919
+ content: compactStructuredContent(structured),
4920
+ structuredContent: structured,
4921
+ isError: result.exitCode !== 0
4922
+ };
4923
+ } catch (error) {
4924
+ if (isAbortError$1(error)) throw new CapletsError("TOOL_CALL_TIMEOUT", `CLI tool timed out for ${config.server}/${toolName}`);
4925
+ if (error instanceof CapletsError) throw error;
4926
+ throw new CapletsError("DOWNSTREAM_TOOL_ERROR", `CLI tool failed for ${config.server}/${toolName}`, toSafeError(error));
4927
+ } finally {
4928
+ clearTimeout(timeout);
4929
+ }
4930
+ }
4931
+ compact(config, tool) {
4932
+ return {
4933
+ id: config.server,
4934
+ tool: tool.name,
4935
+ ...tool.description ? { description: tool.description } : {},
4936
+ hasInputSchema: Boolean(tool.inputSchema),
4937
+ hasOutputSchema: Boolean(tool.outputSchema)
4938
+ };
4939
+ }
4940
+ search(config, tools, query, limit) {
4941
+ return searchToolList(tools, query, limit, (tool) => this.compact(config, tool));
4942
+ }
4943
+ toTool(action) {
4944
+ return {
4945
+ name: action.name,
4946
+ ...action.description ? { description: action.description } : {},
4947
+ inputSchema: action.inputSchema ?? DEFAULT_INPUT_SCHEMA$1,
4948
+ ...action.outputSchema ? { outputSchema: action.outputSchema } : {},
4949
+ ...action.annotations ? { annotations: action.annotations } : {}
4950
+ };
4951
+ }
4952
+ };
4953
+ function actionsFor(config) {
4954
+ return Object.entries(config.actions).map(([name, action]) => ({
4955
+ name,
4956
+ ...action
4957
+ })).sort((left, right) => left.name.localeCompare(right.name));
4958
+ }
4959
+ function getAction(config, toolName) {
4960
+ const actions = actionsFor(config);
4961
+ const action = actions.find((candidate) => candidate.name === toolName);
4962
+ if (!action) throw new CapletsError("TOOL_NOT_FOUND", `Tool ${toolName} was not found on ${config.server}`, {
4963
+ server: config.server,
4964
+ tool: toolName,
4965
+ suggestions: actions.map((candidate) => candidate.name).filter((name) => name.toLocaleLowerCase().includes(toolName.toLocaleLowerCase()[0] ?? "")).slice(0, 5)
4966
+ });
4967
+ return action;
4968
+ }
4969
+ function resolveExecution(config, action, input) {
4970
+ const cwd = interpolateString(action.cwd ?? config.cwd, input, "cwd");
4971
+ if (cwd && !existsSync(cwd)) throw new CapletsError("CONFIG_INVALID", `CLI cwd does not exist for ${config.server}/${action.name}`);
4972
+ const env = {
4973
+ ...process.env,
4974
+ ...resolveEnv(config.env, input),
4975
+ ...resolveEnv(action.env, input)
4976
+ };
4977
+ return {
4978
+ command: interpolateString(action.command, input, "command") ?? action.command,
4979
+ args: (action.args ?? []).map((arg, index) => interpolateRequiredString(arg, input, `args.${index}`)),
4980
+ ...cwd ? { cwd } : {},
4981
+ env,
4982
+ timeoutMs: action.timeoutMs ?? config.timeoutMs,
4983
+ maxOutputBytes: action.maxOutputBytes ?? config.maxOutputBytes
4984
+ };
4985
+ }
4986
+ function resolveEnv(env, input) {
4987
+ if (!env) return {};
4988
+ return Object.fromEntries(Object.entries(env).map(([key, value]) => [key, interpolateRequiredString(value, input, `env.${key}`)]));
4989
+ }
4990
+ function interpolateString(value, input, field) {
4991
+ return value === void 0 ? void 0 : interpolateRequiredString(value, input, field);
4992
+ }
4993
+ function interpolateRequiredString(value, input, field) {
4994
+ return value.replace(/\$input(?:\.([A-Za-z0-9_.-]+))?/g, (_match, path) => {
4995
+ if (!path) throw new CapletsError("REQUEST_INVALID", `CLI ${field} cannot interpolate $input directly`);
4996
+ const selected = valueAtPath$1(input, path);
4997
+ if (selected === void 0 || selected === null) throw new CapletsError("REQUEST_INVALID", `CLI ${field} references missing input ${path}`);
4998
+ 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`);
4999
+ return String(selected);
5000
+ });
5001
+ }
5002
+ function valueAtPath$1(input, path) {
5003
+ let current = input;
5004
+ for (const segment of path.split(".")) {
5005
+ if (!current || typeof current !== "object" || Array.isArray(current)) return;
5006
+ current = current[segment];
5007
+ }
5008
+ return current;
5009
+ }
5010
+ function validateInput(action, input) {
5011
+ const schema = action.inputSchema;
5012
+ if (!schema) return;
5013
+ const required = Array.isArray(schema.required) ? schema.required : [];
5014
+ 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}`);
5015
+ const properties = isPlainObject$6(schema.properties) ? schema.properties : {};
5016
+ for (const [key, property] of Object.entries(properties)) {
5017
+ if (input[key] === void 0 || !isPlainObject$6(property) || typeof property.type !== "string") continue;
5018
+ if (!matchesJsonType(input[key], property.type)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} input ${key} must be ${property.type}`);
5019
+ }
5020
+ }
5021
+ function matchesJsonType(value, type) {
5022
+ switch (type) {
5023
+ case "string": return typeof value === "string";
5024
+ case "number":
5025
+ case "integer": return typeof value === "number" && (type === "number" || Number.isInteger(value));
5026
+ case "boolean": return typeof value === "boolean";
5027
+ case "object": return isPlainObject$6(value);
5028
+ case "array": return Array.isArray(value);
5029
+ case "null": return value === null;
5030
+ default: return true;
5031
+ }
5032
+ }
5033
+ function spawnCommand(execution, signal, elapsedMs) {
5034
+ return new Promise((resolve, reject) => {
5035
+ let stdout = "";
5036
+ let stderr = "";
5037
+ let outputBytes = 0;
5038
+ const child = spawn(execution.command, execution.args, {
5039
+ cwd: execution.cwd,
5040
+ env: execution.env,
5041
+ shell: false,
5042
+ signal,
5043
+ windowsHide: true
5044
+ });
5045
+ child.on("error", reject);
5046
+ const append = (stream, chunk) => {
5047
+ outputBytes += chunk.byteLength;
5048
+ if (outputBytes > execution.maxOutputBytes) {
5049
+ child.kill();
5050
+ reject(new CapletsError("DOWNSTREAM_TOOL_ERROR", "CLI tool output exceeded byte limit"));
5051
+ return;
5052
+ }
5053
+ if (stream === "stdout") stdout += chunk.toString("utf8");
5054
+ else stderr += chunk.toString("utf8");
5055
+ };
5056
+ child.stdout?.on("data", (chunk) => append("stdout", chunk));
5057
+ child.stderr?.on("data", (chunk) => append("stderr", chunk));
5058
+ child.on("close", (exitCode, childSignal) => {
5059
+ resolve({
5060
+ exitCode,
5061
+ signal: childSignal,
5062
+ stdout,
5063
+ stderr,
5064
+ elapsedMs: elapsedMs()
5065
+ });
5066
+ });
5067
+ });
5068
+ }
5069
+ function parseStructuredResult(action, result, tolerateInvalidJson = false) {
5070
+ const structured = {
5071
+ exitCode: result.exitCode,
5072
+ stdout: result.stdout,
5073
+ stderr: result.stderr,
5074
+ elapsedMs: result.elapsedMs,
5075
+ ...result.signal ? { signal: result.signal } : {}
5076
+ };
5077
+ if (action.output?.type === "json" && result.stdout.trim()) try {
5078
+ structured.json = JSON.parse(result.stdout);
5079
+ } catch (error) {
5080
+ if (tolerateInvalidJson) {
5081
+ structured.jsonParseError = toSafeError(error);
5082
+ return structured;
5083
+ }
5084
+ throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", `CLI tool ${action.name} stdout was not valid JSON`, toSafeError(error));
5085
+ }
5086
+ return structured;
5087
+ }
5088
+ function resolveCommandPath(command) {
5089
+ if (isAbsolute(command) || /[\\/]/.test(command)) {
5090
+ assertExecutable(command);
5091
+ return command;
5092
+ }
5093
+ for (const directory of (process.env.PATH ?? "").split(delimiter)) {
5094
+ if (!directory) continue;
5095
+ const candidate = join(directory, command);
5096
+ if (isExecutable(candidate)) return candidate;
5097
+ if (process.platform === "win32") for (const ext of (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")) {
5098
+ const windowsCandidate = join(directory, `${command}${ext.toLowerCase()}`);
5099
+ if (isExecutable(windowsCandidate)) return windowsCandidate;
5100
+ }
5101
+ }
5102
+ throw new CapletsError("SERVER_UNAVAILABLE", `CLI command ${command} was not found on PATH`);
5103
+ }
5104
+ function assertExecutable(path) {
5105
+ if (!isExecutable(path)) throw new CapletsError("SERVER_UNAVAILABLE", `CLI command ${path} is not executable`);
5106
+ }
5107
+ function isExecutable(path) {
5108
+ try {
5109
+ accessSync(path, constants.X_OK);
5110
+ return true;
5111
+ } catch {
5112
+ return false;
5113
+ }
5114
+ }
5115
+ function isAbortError$1(error) {
5116
+ return error instanceof Error && error.name === "AbortError";
5117
+ }
5118
+ function isPlainObject$6(value) {
5119
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5120
+ }
4992
5121
  /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
4993
5122
  const ZodIssueCode$1 = {
4994
5123
  invalid_type: "invalid_type",
@@ -12509,9 +12638,9 @@ const capletMcpServerSchema = object$1({
12509
12638
  cwd: string().min(1).optional().describe("Working directory for stdio servers."),
12510
12639
  url: string().min(1).optional().describe("Remote MCP server URL for http or sse transport."),
12511
12640
  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."),
12641
+ startupTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for starting or checking a downstream server."),
12642
+ callTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for downstream tool calls."),
12643
+ toolCacheTtlMs: number$2().int().nonnegative().optional().describe("Milliseconds downstream tool metadata stays fresh. Set 0 to refresh every time."),
12515
12644
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery and do not start its MCP server.")
12516
12645
  }).strict().superRefine((server, ctx) => {
12517
12646
  const effectiveTransport = server.transport ?? (server.command ? "stdio" : void 0);
@@ -12566,8 +12695,8 @@ const capletOpenApiEndpointSchema = object$1({
12566
12695
  specUrl: string().min(1).optional().describe("Remote OpenAPI specification URL."),
12567
12696
  baseUrl: string().min(1).optional().describe("Override base URL for OpenAPI requests."),
12568
12697
  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."),
12698
+ requestTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for OpenAPI HTTP requests."),
12699
+ operationCacheTtlMs: number$2().int().nonnegative().optional().describe("Milliseconds OpenAPI operation metadata stays fresh. Set 0 to refresh every time."),
12571
12700
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12572
12701
  }).strict().superRefine((endpoint, ctx) => {
12573
12702
  if (Boolean(endpoint.specPath) === Boolean(endpoint.specUrl)) ctx.addIssue({
@@ -12604,9 +12733,9 @@ const capletGraphQlEndpointSchema = object$1({
12604
12733
  introspection: literal(true).optional().describe("Load schema through endpoint introspection."),
12605
12734
  operations: record(string().regex(SERVER_ID_PATTERN), capletGraphQlOperationSchema).optional().describe("Configured GraphQL operations keyed by stable tool name."),
12606
12735
  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."),
12736
+ requestTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for GraphQL HTTP requests."),
12737
+ operationCacheTtlMs: number$2().int().nonnegative().optional().describe("Milliseconds GraphQL operation metadata stays fresh. Set 0 to refresh every time."),
12738
+ selectionDepth: number$2().int().positive().max(5).optional().describe("Maximum depth for auto-generated GraphQL selection sets."),
12610
12739
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12611
12740
  }).strict().superRefine((endpoint, ctx) => {
12612
12741
  if (Number(Boolean(endpoint.schemaPath)) + Number(Boolean(endpoint.schemaUrl)) + Number(endpoint.introspection === true) !== 1) ctx.addIssue({
@@ -12627,7 +12756,7 @@ const capletGraphQlEndpointSchema = object$1({
12627
12756
  });
12628
12757
  const httpScalarMappingSchema$1 = record(string(), union([
12629
12758
  string(),
12630
- number$1(),
12759
+ number$2(),
12631
12760
  boolean()
12632
12761
  ]));
12633
12762
  const capletHttpActionSchema = object$1({
@@ -12655,8 +12784,8 @@ const capletHttpApiSchema = object$1({
12655
12784
  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
12785
  auth: capletEndpointAuthSchema.describe("Explicit HTTP API request auth config. Use {\"type\":\"none\"} for public APIs."),
12657
12786
  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."),
12787
+ requestTimeoutMs: number$2().int().positive().optional().describe("Timeout in milliseconds for HTTP action requests."),
12788
+ maxResponseBytes: number$2().int().positive().optional().describe("Maximum HTTP action response body bytes to read."),
12660
12789
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12661
12790
  }).strict().superRefine((api, ctx) => {
12662
12791
  if (api.baseUrl && !hasEnvReference$1(api.baseUrl) && !isAllowedHttpBaseUrl(api.baseUrl)) ctx.addIssue({
@@ -12686,8 +12815,8 @@ const capletCliToolActionSchema = object$1({
12686
12815
  args: array(string()).optional().describe("Arguments passed to the command."),
12687
12816
  env: record(string(), string()).optional().describe("Additional environment variables."),
12688
12817
  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(),
12818
+ timeoutMs: number$2().int().positive().optional(),
12819
+ maxOutputBytes: number$2().int().positive().optional(),
12691
12820
  output: capletCliToolOutputSchema.optional(),
12692
12821
  annotations: capletCliToolAnnotationsSchema.optional()
12693
12822
  }).strict();
@@ -12695,16 +12824,16 @@ const capletCliToolsSchema = object$1({
12695
12824
  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
12825
  cwd: string().min(1).optional().describe("Default working directory for CLI actions."),
12697
12826
  env: record(string(), string()).optional().describe("Default environment variables."),
12698
- timeoutMs: number$1().int().positive().optional(),
12699
- maxOutputBytes: number$1().int().positive().optional(),
12827
+ timeoutMs: number$2().int().positive().optional(),
12828
+ maxOutputBytes: number$2().int().positive().optional(),
12700
12829
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12701
12830
  }).strict();
12702
12831
  const capletSetSchema = object$1({
12703
12832
  configPath: string().min(1).optional().describe("Child Caplets config.json path."),
12704
12833
  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(),
12834
+ defaultSearchLimit: number$2().int().positive().optional(),
12835
+ maxSearchLimit: number$2().int().positive().max(50).optional(),
12836
+ toolCacheTtlMs: number$2().int().nonnegative().optional(),
12708
12837
  disabled: boolean().optional().describe("When true, omit this Caplet from discovery.")
12709
12838
  }).strict().superRefine((set, ctx) => {
12710
12839
  if (!set.configPath && !set.capletsRoot) ctx.addIssue({
@@ -12942,14 +13071,24 @@ function defaultStateBaseDir(env = process.env, home = homedir(), platform = pro
12942
13071
  if (platform === "win32") return env.LOCALAPPDATA && win32.isAbsolute(env.LOCALAPPDATA) ? env.LOCALAPPDATA : win32.join(home, "AppData", "Local");
12943
13072
  return env.XDG_STATE_HOME && posix.isAbsolute(env.XDG_STATE_HOME) ? env.XDG_STATE_HOME : posix.join(home, ".local", "state");
12944
13073
  }
13074
+ function defaultCacheBaseDir(env = process.env, home = homedir(), platform = process.platform) {
13075
+ if (platform === "win32") return env.LOCALAPPDATA && win32.isAbsolute(env.LOCALAPPDATA) ? env.LOCALAPPDATA : win32.join(home, "AppData", "Local");
13076
+ if (platform === "darwin") return posix.join(home, "Library", "Caches");
13077
+ return env.XDG_CACHE_HOME && posix.isAbsolute(env.XDG_CACHE_HOME) ? env.XDG_CACHE_HOME : posix.join(home, ".cache");
13078
+ }
12945
13079
  function defaultConfigPath(env = process.env, home = homedir(), platform = process.platform) {
12946
13080
  return (platform === "win32" ? win32.join : posix.join)(defaultConfigBaseDir(env, home, platform), "caplets", "config.json");
12947
13081
  }
12948
13082
  function defaultAuthDir(env = process.env, home = homedir(), platform = process.platform) {
12949
13083
  return (platform === "win32" ? win32.join : posix.join)(defaultStateBaseDir(env, home, platform), "caplets", "auth");
12950
13084
  }
13085
+ function defaultCompletionCacheDir(env = process.env, home = homedir(), platform = process.platform) {
13086
+ const pathJoin = platform === "win32" ? win32.join : posix.join;
13087
+ return platform === "win32" ? pathJoin(defaultCacheBaseDir(env, home, platform), "caplets", "cache", "completions") : pathJoin(defaultCacheBaseDir(env, home, platform), "caplets", "completions");
13088
+ }
12951
13089
  const DEFAULT_CONFIG_PATH = defaultConfigPath();
12952
13090
  const DEFAULT_AUTH_DIR = defaultAuthDir();
13091
+ const DEFAULT_COMPLETION_CACHE_DIR = defaultCompletionCacheDir();
12953
13092
  const PROJECT_CONFIG_FILE = join(".caplets", "config.json");
12954
13093
  function resolveConfigPath(path) {
12955
13094
  return path ?? DEFAULT_CONFIG_PATH;
@@ -13062,9 +13201,9 @@ const publicServerSchema = object$1({
13062
13201
  url: string().url().optional().describe("Remote MCP server URL for http or sse transport."),
13063
13202
  auth: remoteAuthSchema.optional(),
13064
13203
  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."),
13204
+ startupTimeoutMs: number$2().int().positive().default(1e4).describe("Timeout in milliseconds for starting or checking a downstream server."),
13205
+ callTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for downstream tool calls."),
13206
+ toolCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds downstream tool metadata stays fresh. Set 0 to refresh every time."),
13068
13207
  disabled: boolean().default(false).describe("When true, omit this server from Caplets discovery and do not start it.")
13069
13208
  }).strict();
13070
13209
  const normalizedServerSchema = publicServerSchema.extend({ body: string().optional() });
@@ -13076,8 +13215,8 @@ const publicOpenApiEndpointSchema = object$1({
13076
13215
  baseUrl: string().url().optional().describe("Override base URL for OpenAPI requests."),
13077
13216
  auth: openApiAuthSchema.describe("Explicit OpenAPI request auth config. Use {\"type\":\"none\"} for public APIs."),
13078
13217
  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."),
13218
+ requestTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for OpenAPI HTTP requests."),
13219
+ operationCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds OpenAPI operation metadata stays fresh. Set 0 to refresh every time."),
13081
13220
  disabled: boolean().default(false).describe("When true, omit this OpenAPI Caplet from discovery.")
13082
13221
  }).strict();
13083
13222
  const normalizedOpenApiEndpointSchema = publicOpenApiEndpointSchema.extend({ body: string().optional() });
@@ -13102,9 +13241,9 @@ const publicGraphQlEndpointSchema = object$1({
13102
13241
  operations: record(string().regex(SERVER_ID_PATTERN), graphQlOperationSchema).optional().describe("Configured GraphQL operations keyed by stable tool name."),
13103
13242
  auth: openApiAuthSchema.describe("Explicit GraphQL request auth config. Use {\"type\":\"none\"} for public APIs."),
13104
13243
  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."),
13244
+ requestTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for GraphQL HTTP requests."),
13245
+ operationCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds GraphQL operation metadata stays fresh. Set 0 to refresh every time."),
13246
+ selectionDepth: number$2().int().positive().max(5).default(2).describe("Maximum depth for auto-generated GraphQL selection sets."),
13108
13247
  disabled: boolean().default(false).describe("When true, omit this GraphQL Caplet.")
13109
13248
  }).strict().superRefine((endpoint, ctx) => {
13110
13249
  if (Number(Boolean(endpoint.schemaPath)) + Number(Boolean(endpoint.schemaUrl)) + Number(endpoint.introspection === true) !== 1) ctx.addIssue({
@@ -13115,7 +13254,7 @@ const publicGraphQlEndpointSchema = object$1({
13115
13254
  const normalizedGraphQlEndpointSchema = publicGraphQlEndpointSchema.extend({ body: string().optional() });
13116
13255
  const httpScalarMappingSchema = record(string(), union([
13117
13256
  string(),
13118
- number$1(),
13257
+ number$2(),
13119
13258
  boolean()
13120
13259
  ]));
13121
13260
  const httpActionSchema = object$1({
@@ -13147,8 +13286,8 @@ const publicHttpApiSchema = object$1({
13147
13286
  auth: openApiAuthSchema.describe("Explicit HTTP API request auth config. Use {\"type\":\"none\"} for public APIs."),
13148
13287
  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
13288
  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."),
13289
+ requestTimeoutMs: number$2().int().positive().default(6e4).describe("Timeout in milliseconds for HTTP action requests."),
13290
+ maxResponseBytes: number$2().int().positive().default(2e5).describe("Maximum HTTP action response body bytes to read."),
13152
13291
  disabled: boolean().default(false).describe("When true, omit this HTTP API Caplet.")
13153
13292
  }).strict();
13154
13293
  const normalizedHttpApiSchema = publicHttpApiSchema.extend({ body: string().optional() });
@@ -13167,8 +13306,8 @@ const cliToolActionSchema = object$1({
13167
13306
  args: array(string()).optional().describe("Arguments passed to the command."),
13168
13307
  env: record(string(), string()).optional().describe("Additional environment variables for the command."),
13169
13308
  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."),
13309
+ timeoutMs: number$2().int().positive().optional().describe("Command timeout in milliseconds."),
13310
+ maxOutputBytes: number$2().int().positive().optional().describe("Maximum combined stdout and stderr bytes to keep."),
13172
13311
  output: cliToolOutputSchema.optional(),
13173
13312
  annotations: cliToolAnnotationsSchema.optional()
13174
13313
  }).strict();
@@ -13179,8 +13318,8 @@ const publicCliToolsSchema = object$1({
13179
13318
  cwd: string().min(1).optional().describe("Default working directory for CLI actions."),
13180
13319
  env: record(string(), string()).optional().describe("Default environment variables for CLI actions."),
13181
13320
  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."),
13321
+ timeoutMs: number$2().int().positive().default(6e4).describe("Default timeout in milliseconds for CLI actions."),
13322
+ maxOutputBytes: number$2().int().positive().default(2e5).describe("Default maximum combined stdout and stderr bytes to keep."),
13184
13323
  disabled: boolean().default(false).describe("When true, omit this CLI tools Caplet.")
13185
13324
  }).strict();
13186
13325
  const normalizedCliToolsSchema = publicCliToolsSchema.extend({ body: string().optional() });
@@ -13189,9 +13328,9 @@ const publicCapletSetSchema = object$1({
13189
13328
  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
13329
  configPath: string().min(1).optional().describe("Child Caplets config.json path."),
13191
13330
  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."),
13331
+ defaultSearchLimit: number$2().int().positive().default(20).describe("Default maximum number of child Caplet search results."),
13332
+ maxSearchLimit: number$2().int().positive().max(50).default(50).describe("Maximum accepted child Caplet search result limit."),
13333
+ toolCacheTtlMs: number$2().int().nonnegative().default(3e4).describe("Milliseconds child Caplet metadata stays fresh. Set 0 to refresh every time."),
13195
13334
  tags: array(string().trim().min(1).max(80)).optional(),
13196
13335
  disabled: boolean().default(false).describe("When true, omit this Caplet set.")
13197
13336
  }).strict().superRefine((set, ctx) => {
@@ -13210,8 +13349,19 @@ function configSchemaFor(serverValueSchema, openApiEndpointValueSchema, graphQlE
13210
13349
  return object$1({
13211
13350
  $schema: string().url().optional().describe("Optional JSON Schema URL for editor validation."),
13212
13351
  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."),
13352
+ defaultSearchLimit: number$2().int().positive().default(20).describe("Default maximum number of same-server search results."),
13353
+ maxSearchLimit: number$2().int().positive().max(50).default(50).describe("Maximum accepted search_tools limit."),
13354
+ completion: object$1({
13355
+ discoveryTimeoutMs: number$2().int().positive().default(750),
13356
+ overallTimeoutMs: number$2().int().positive().default(1500),
13357
+ cacheTtlMs: number$2().int().nonnegative().default(3e5),
13358
+ negativeCacheTtlMs: number$2().int().nonnegative().default(3e4)
13359
+ }).strict().default({
13360
+ discoveryTimeoutMs: 750,
13361
+ overallTimeoutMs: 1500,
13362
+ cacheTtlMs: 3e5,
13363
+ negativeCacheTtlMs: 3e4
13364
+ }).describe("Shell completion discovery timeout and cache settings."),
13215
13365
  mcpServers: record(string().regex(SERVER_ID_PATTERN), serverValueSchema).default({}).describe("Downstream MCP servers keyed by stable server ID."),
13216
13366
  openapiEndpoints: record(string().regex(SERVER_ID_PATTERN), openApiEndpointValueSchema).default({}).describe("OpenAPI endpoints keyed by stable Caplet ID."),
13217
13367
  graphqlEndpoints: record(string().regex(SERVER_ID_PATTERN), graphQlEndpointValueSchema).default({}).describe("GraphQL endpoints keyed by stable Caplet ID."),
@@ -13726,7 +13876,8 @@ function parseConfig(input) {
13726
13876
  version: parsed.data.version,
13727
13877
  options: {
13728
13878
  defaultSearchLimit: parsed.data.defaultSearchLimit,
13729
- maxSearchLimit: parsed.data.maxSearchLimit
13879
+ maxSearchLimit: parsed.data.maxSearchLimit,
13880
+ completion: parsed.data.completion
13730
13881
  },
13731
13882
  mcpServers: servers,
13732
13883
  openapiEndpoints,
@@ -17306,10 +17457,10 @@ const ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
17306
17457
  $ZodType.init(inst, def);
17307
17458
  inst.def = def;
17308
17459
  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);
17460
+ inst.parse = (data, params) => parse$1(inst, data, params, { callee: inst.parse });
17461
+ inst.safeParse = (data, params) => safeParse$1(inst, data, params);
17311
17462
  inst.parseAsync = async (data, params) => parseAsync$1(inst, data, params, { callee: inst.parseAsync });
17312
- inst.safeParseAsync = async (data, params) => safeParseAsync$2(inst, data, params);
17463
+ inst.safeParseAsync = async (data, params) => safeParseAsync$1(inst, data, params);
17313
17464
  inst.check = (...checks) => {
17314
17465
  return inst.clone({
17315
17466
  ...def,
@@ -17355,11 +17506,11 @@ function objectFromShape(shape) {
17355
17506
  throw new Error("Mixed Zod versions detected in object shape.");
17356
17507
  }
17357
17508
  function safeParse(schema, data) {
17358
- if (isZ4Schema(schema)) return safeParse$2(schema, data);
17509
+ if (isZ4Schema(schema)) return safeParse$1(schema, data);
17359
17510
  return schema.safeParse(data);
17360
17511
  }
17361
17512
  async function safeParseAsync(schema, data) {
17362
- if (isZ4Schema(schema)) return await safeParseAsync$2(schema, data);
17513
+ if (isZ4Schema(schema)) return await safeParseAsync$1(schema, data);
17363
17514
  return await schema.safeParseAsync(data);
17364
17515
  }
17365
17516
  function getObjectShape(schema) {
@@ -17473,7 +17624,7 @@ const AssertObjectSchema = custom((v) => v !== null && (typeof v === "object" ||
17473
17624
  /**
17474
17625
  * A progress token, used to associate progress notifications with the original request.
17475
17626
  */
17476
- const ProgressTokenSchema = union([string(), number$1().int()]);
17627
+ const ProgressTokenSchema = union([string(), number$2().int()]);
17477
17628
  /**
17478
17629
  * An opaque token used to represent a cursor for pagination.
17479
17630
  */
@@ -17482,13 +17633,13 @@ looseObject({
17482
17633
  /**
17483
17634
  * Requested duration in milliseconds to retain task from creation.
17484
17635
  */
17485
- ttl: number$1().optional(),
17636
+ ttl: number$2().optional(),
17486
17637
  /**
17487
17638
  * Time in milliseconds to wait between task status requests.
17488
17639
  */
17489
- pollInterval: number$1().optional()
17640
+ pollInterval: number$2().optional()
17490
17641
  });
17491
- const TaskMetadataSchema = object$1({ ttl: number$1().optional() });
17642
+ const TaskMetadataSchema = object$1({ ttl: number$2().optional() });
17492
17643
  /**
17493
17644
  * Metadata for associating messages with a task.
17494
17645
  * Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`.
@@ -17555,7 +17706,7 @@ _meta: RequestMetaSchema.optional() });
17555
17706
  /**
17556
17707
  * A uniquely identifying ID for a request in JSON-RPC.
17557
17708
  */
17558
- const RequestIdSchema = union([string(), number$1().int()]);
17709
+ const RequestIdSchema = union([string(), number$2().int()]);
17559
17710
  /**
17560
17711
  * A request that expects a response.
17561
17712
  */
@@ -17612,7 +17763,7 @@ const JSONRPCErrorResponseSchema = object$1({
17612
17763
  /**
17613
17764
  * The error type that occurred.
17614
17765
  */
17615
- code: number$1().int(),
17766
+ code: number$2().int(),
17616
17767
  /**
17617
17768
  * A short description of the error. The message SHOULD be limited to a concise single sentence.
17618
17769
  */
@@ -17948,11 +18099,11 @@ const ProgressSchema = object$1({
17948
18099
  /**
17949
18100
  * The progress thus far. This should increase every time progress is made, even if the total is unknown.
17950
18101
  */
17951
- progress: number$1(),
18102
+ progress: number$2(),
17952
18103
  /**
17953
18104
  * Total number of items to process (or total progress required), if known.
17954
18105
  */
17955
- total: optional(number$1()),
18106
+ total: optional(number$2()),
17956
18107
  /**
17957
18108
  * An optional message describing the current progress.
17958
18109
  */
@@ -18008,7 +18159,7 @@ const TaskSchema = object$1({
18008
18159
  * Time in milliseconds to keep task results available after completion.
18009
18160
  * If null, the task has unlimited lifetime until manually cleaned up.
18010
18161
  */
18011
- ttl: union([number$1(), _null()]),
18162
+ ttl: union([number$2(), _null()]),
18012
18163
  /**
18013
18164
  * ISO 8601 timestamp when the task was created.
18014
18165
  */
@@ -18017,7 +18168,7 @@ const TaskSchema = object$1({
18017
18168
  * ISO 8601 timestamp when the task was last updated.
18018
18169
  */
18019
18170
  lastUpdatedAt: string(),
18020
- pollInterval: optional(number$1()),
18171
+ pollInterval: optional(number$2()),
18021
18172
  /**
18022
18173
  * Optional diagnostic message for failed tasks or other status information.
18023
18174
  */
@@ -18132,7 +18283,7 @@ const AnnotationsSchema = object$1({
18132
18283
  /**
18133
18284
  * Importance hint for the resource, from 0 (least) to 1 (most).
18134
18285
  */
18135
- priority: number$1().min(0).max(1).optional(),
18286
+ priority: number$2().min(0).max(1).optional(),
18136
18287
  /**
18137
18288
  * ISO 8601 timestamp for the most recent modification.
18138
18289
  */
@@ -18163,7 +18314,7 @@ const ResourceSchema = object$1({
18163
18314
  *
18164
18315
  * This can be used by Hosts to display file sizes and estimate context window usage.
18165
18316
  */
18166
- size: optional(number$1()),
18317
+ size: optional(number$2()),
18167
18318
  /**
18168
18319
  * Optional annotations for the client.
18169
18320
  */
@@ -18690,7 +18841,7 @@ const ListChangedOptionsBaseSchema = object$1({
18690
18841
  *
18691
18842
  * @default 300
18692
18843
  */
18693
- debounceMs: number$1().int().nonnegative().default(300)
18844
+ debounceMs: number$2().int().nonnegative().default(300)
18694
18845
  });
18695
18846
  /**
18696
18847
  * The severity of a log message.
@@ -18759,15 +18910,15 @@ name: string().optional() })).optional(),
18759
18910
  /**
18760
18911
  * How much to prioritize cost when selecting a model.
18761
18912
  */
18762
- costPriority: number$1().min(0).max(1).optional(),
18913
+ costPriority: number$2().min(0).max(1).optional(),
18763
18914
  /**
18764
18915
  * How much to prioritize sampling speed (latency) when selecting a model.
18765
18916
  */
18766
- speedPriority: number$1().min(0).max(1).optional(),
18917
+ speedPriority: number$2().min(0).max(1).optional(),
18767
18918
  /**
18768
18919
  * How much to prioritize intelligence and capabilities when selecting a model.
18769
18920
  */
18770
- intelligencePriority: number$1().min(0).max(1).optional()
18921
+ intelligencePriority: number$2().min(0).max(1).optional()
18771
18922
  });
18772
18923
  /**
18773
18924
  * Controls tool usage behavior in sampling requests.
@@ -18857,13 +19008,13 @@ const CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend
18857
19008
  "thisServer",
18858
19009
  "allServers"
18859
19010
  ]).optional(),
18860
- temperature: number$1().optional(),
19011
+ temperature: number$2().optional(),
18861
19012
  /**
18862
19013
  * The requested maximum number of tokens to sample (to prevent runaway completions).
18863
19014
  *
18864
19015
  * The client MAY choose to sample fewer tokens than the requested maximum.
18865
19016
  */
18866
- maxTokens: number$1().int(),
19017
+ maxTokens: number$2().int(),
18867
19018
  stopSequences: array(string()).optional(),
18868
19019
  /**
18869
19020
  * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
@@ -18967,8 +19118,8 @@ const StringSchemaSchema = object$1({
18967
19118
  type: literal("string"),
18968
19119
  title: string().optional(),
18969
19120
  description: string().optional(),
18970
- minLength: number$1().optional(),
18971
- maxLength: number$1().optional(),
19121
+ minLength: number$2().optional(),
19122
+ maxLength: number$2().optional(),
18972
19123
  format: _enum([
18973
19124
  "email",
18974
19125
  "uri",
@@ -18984,9 +19135,9 @@ const NumberSchemaSchema = object$1({
18984
19135
  type: _enum(["number", "integer"]),
18985
19136
  title: string().optional(),
18986
19137
  description: string().optional(),
18987
- minimum: number$1().optional(),
18988
- maximum: number$1().optional(),
18989
- default: number$1().optional()
19138
+ minimum: number$2().optional(),
19139
+ maximum: number$2().optional(),
19140
+ default: number$2().optional()
18990
19141
  });
18991
19142
  /**
18992
19143
  * Schema for single-selection enumeration without display titles for options.
@@ -19029,8 +19180,8 @@ const PrimitiveSchemaDefinitionSchema = union([
19029
19180
  type: literal("array"),
19030
19181
  title: string().optional(),
19031
19182
  description: string().optional(),
19032
- minItems: number$1().optional(),
19033
- maxItems: number$1().optional(),
19183
+ minItems: number$2().optional(),
19184
+ maxItems: number$2().optional(),
19034
19185
  items: object$1({
19035
19186
  type: literal("string"),
19036
19187
  enum: array(string())
@@ -19040,8 +19191,8 @@ const PrimitiveSchemaDefinitionSchema = union([
19040
19191
  type: literal("array"),
19041
19192
  title: string().optional(),
19042
19193
  description: string().optional(),
19043
- minItems: number$1().optional(),
19044
- maxItems: number$1().optional(),
19194
+ minItems: number$2().optional(),
19195
+ maxItems: number$2().optional(),
19045
19196
  items: object$1({ anyOf: array(object$1({
19046
19197
  const: string(),
19047
19198
  title: string()
@@ -19146,7 +19297,7 @@ const ElicitResultSchema = ResultSchema.extend({
19146
19297
  */
19147
19298
  content: preprocess((val) => val === null ? void 0 : val, record(string(), union([
19148
19299
  string(),
19149
- number$1(),
19300
+ number$2(),
19150
19301
  boolean(),
19151
19302
  array(string())
19152
19303
  ])).optional())
@@ -19219,7 +19370,7 @@ const CompleteResultSchema = ResultSchema.extend({ completion: looseObject({
19219
19370
  /**
19220
19371
  * The total number of completion options available. This can exceed the number of values actually sent in the response.
19221
19372
  */
19222
- total: optional(number$1().int()),
19373
+ total: optional(number$2().int()),
19223
19374
  /**
19224
19375
  * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
19225
19376
  */
@@ -28891,8 +29042,8 @@ const OAuthClientMetadataSchema = object$1({
28891
29042
  const OAuthClientInformationSchema = object$1({
28892
29043
  client_id: string(),
28893
29044
  client_secret: string().optional(),
28894
- client_id_issued_at: number$1().optional(),
28895
- client_secret_expires_at: number$1().optional()
29045
+ client_id_issued_at: number$2().optional(),
29046
+ client_secret_expires_at: number$2().optional()
28896
29047
  }).strip();
28897
29048
  /**
28898
29049
  * RFC 7591 OAuth 2.0 Dynamic Client Registration full response (client information plus metadata)
@@ -31267,14 +31418,28 @@ var DownstreamManager = class {
31267
31418
  async checkServer(server) {
31268
31419
  const startedAt = Date.now();
31269
31420
  try {
31421
+ const capabilities = (await this.connect(server)).client.getServerCapabilities() ?? {};
31270
31422
  const tools = await this.refreshTools(server, true);
31271
31423
  this.registry.setStatus(server.server, "available");
31272
- return {
31424
+ const result = {
31273
31425
  id: server.server,
31274
31426
  status: "available",
31427
+ capabilities: {
31428
+ tools: Boolean(capabilities.tools),
31429
+ resources: Boolean(capabilities.resources),
31430
+ resourceTemplates: Boolean(capabilities.resources),
31431
+ prompts: Boolean(capabilities.prompts),
31432
+ completions: Boolean(capabilities.completions)
31433
+ },
31275
31434
  toolCount: tools.length,
31276
31435
  elapsedMs: Date.now() - startedAt
31277
31436
  };
31437
+ if (capabilities.resources) Object.assign(result, {
31438
+ resourceCount: (await this.listResources(server, true)).length,
31439
+ resourceTemplateCount: (await this.listResourceTemplates(server, true)).length
31440
+ });
31441
+ if (capabilities.prompts) Object.assign(result, { promptCount: (await this.listPrompts(server, true)).length });
31442
+ return result;
31278
31443
  } catch (error) {
31279
31444
  const safe = toSafeError(error, "SERVER_UNAVAILABLE");
31280
31445
  this.registry.setStatus(server.server, "unavailable", safe);
@@ -31316,6 +31481,86 @@ var DownstreamManager = class {
31316
31481
  throw new CapletsError("DOWNSTREAM_TOOL_ERROR", `Downstream tool failed for ${server.server}/${toolName}`, toSafeError(error));
31317
31482
  }
31318
31483
  }
31484
+ async listResources(server, force = false) {
31485
+ const connection = await this.assertCapability(server, "resources");
31486
+ if (!force && connection.resources && this.isCacheFresh(connection.resourcesFetchedAt, server.toolCacheTtlMs)) return connection.resources;
31487
+ const resources = [];
31488
+ let cursor;
31489
+ do {
31490
+ const result = await connection.client.listResources(cursor ? { cursor } : void 0, { timeout: server.startupTimeoutMs });
31491
+ resources.push(...result.resources ?? []);
31492
+ cursor = result.nextCursor;
31493
+ } while (cursor);
31494
+ connection.resources = resources;
31495
+ connection.resourcesFetchedAt = Date.now();
31496
+ return resources;
31497
+ }
31498
+ async listResourceTemplates(server, force = false) {
31499
+ const connection = await this.assertCapability(server, "resources");
31500
+ if (!force && connection.resourceTemplates && this.isCacheFresh(connection.resourceTemplatesFetchedAt, server.toolCacheTtlMs)) return connection.resourceTemplates;
31501
+ const resourceTemplates = [];
31502
+ let cursor;
31503
+ do {
31504
+ const result = await connection.client.listResourceTemplates(cursor ? { cursor } : void 0, { timeout: server.startupTimeoutMs });
31505
+ resourceTemplates.push(...result.resourceTemplates ?? []);
31506
+ cursor = result.nextCursor;
31507
+ } while (cursor);
31508
+ connection.resourceTemplates = resourceTemplates;
31509
+ connection.resourceTemplatesFetchedAt = Date.now();
31510
+ return resourceTemplates;
31511
+ }
31512
+ async readResource(server, uri) {
31513
+ const connection = await this.assertCapability(server, "resources");
31514
+ try {
31515
+ return await connection.client.readResource({ uri }, { timeout: server.callTimeoutMs });
31516
+ } catch (error) {
31517
+ throw new CapletsError("DOWNSTREAM_RESOURCE_ERROR", `Downstream resource read failed for ${server.server}/${uri}`, toSafeError(error));
31518
+ }
31519
+ }
31520
+ async listPrompts(server, force = false) {
31521
+ const connection = await this.assertCapability(server, "prompts");
31522
+ if (!force && connection.prompts && this.isCacheFresh(connection.promptsFetchedAt, server.toolCacheTtlMs)) return connection.prompts;
31523
+ const prompts = [];
31524
+ let cursor;
31525
+ do {
31526
+ const result = await connection.client.listPrompts(cursor ? { cursor } : void 0, { timeout: server.startupTimeoutMs });
31527
+ prompts.push(...result.prompts ?? []);
31528
+ cursor = result.nextCursor;
31529
+ } while (cursor);
31530
+ connection.prompts = prompts;
31531
+ connection.promptsFetchedAt = Date.now();
31532
+ return prompts;
31533
+ }
31534
+ async getPrompt(server, promptName, args) {
31535
+ if (!(await this.listPrompts(server)).some((prompt) => prompt.name === promptName)) throw new CapletsError("PROMPT_NOT_FOUND", `Prompt ${promptName} was not found on ${server.server}`);
31536
+ const connection = await this.connect(server);
31537
+ try {
31538
+ return await connection.client.getPrompt({
31539
+ name: promptName,
31540
+ arguments: stringifyPromptArgs(args)
31541
+ }, { timeout: server.callTimeoutMs });
31542
+ } catch (error) {
31543
+ throw new CapletsError("DOWNSTREAM_PROMPT_ERROR", `Downstream prompt failed for ${server.server}/${promptName}`, toSafeError(error));
31544
+ }
31545
+ }
31546
+ async complete(server, request) {
31547
+ const connection = await this.assertCapability(server, "completions");
31548
+ const params = {
31549
+ ref: request.ref.type === "prompt" ? {
31550
+ type: "ref/prompt",
31551
+ name: request.ref.name
31552
+ } : {
31553
+ type: "ref/resource",
31554
+ uri: request.ref.uri
31555
+ },
31556
+ argument: request.argument
31557
+ };
31558
+ try {
31559
+ return await connection.client.complete(params, { timeout: server.callTimeoutMs });
31560
+ } catch (error) {
31561
+ throw new CapletsError("DOWNSTREAM_COMPLETION_ERROR", `Downstream completion failed for ${server.server}`, toSafeError(error));
31562
+ }
31563
+ }
31319
31564
  compact(server, tool) {
31320
31565
  return {
31321
31566
  id: server.server,
@@ -31325,9 +31570,75 @@ var DownstreamManager = class {
31325
31570
  hasOutputSchema: Boolean(tool.outputSchema)
31326
31571
  };
31327
31572
  }
31573
+ compactResource(server, resource) {
31574
+ return {
31575
+ id: server.server,
31576
+ kind: "resource",
31577
+ uri: resource.uri,
31578
+ ...resource.name ? { name: resource.name } : {},
31579
+ ...resource.description ? { description: resource.description } : {},
31580
+ ...resource.mimeType ? { mimeType: resource.mimeType } : {},
31581
+ ...typeof resource.size === "number" ? { size: resource.size } : {}
31582
+ };
31583
+ }
31584
+ compactResourceTemplate(server, template) {
31585
+ return {
31586
+ id: server.server,
31587
+ kind: "resourceTemplate",
31588
+ uriTemplate: template.uriTemplate,
31589
+ ...template.name ? { name: template.name } : {},
31590
+ ...template.description ? { description: template.description } : {},
31591
+ ...template.mimeType ? { mimeType: template.mimeType } : {}
31592
+ };
31593
+ }
31594
+ compactPrompt(server, prompt) {
31595
+ return {
31596
+ id: server.server,
31597
+ prompt: prompt.name,
31598
+ ...prompt.description ? { description: prompt.description } : {},
31599
+ ...prompt.arguments ? { arguments: prompt.arguments } : {}
31600
+ };
31601
+ }
31602
+ searchResources(server, resources, query, limit) {
31603
+ const lower = query.toLocaleLowerCase();
31604
+ return resources.map((resource) => this.compactResource(server, resource)).filter((resource) => [
31605
+ resource.uri,
31606
+ resource.name,
31607
+ resource.description,
31608
+ resource.mimeType
31609
+ ].some((value) => value?.toLocaleLowerCase().includes(lower))).slice(0, limit);
31610
+ }
31611
+ searchResourceTemplates(server, templates, query, limit) {
31612
+ const lower = query.toLocaleLowerCase();
31613
+ return templates.map((template) => this.compactResourceTemplate(server, template)).filter((template) => [
31614
+ template.uriTemplate,
31615
+ template.name,
31616
+ template.description,
31617
+ template.mimeType
31618
+ ].some((value) => value?.toLocaleLowerCase().includes(lower))).slice(0, limit);
31619
+ }
31620
+ searchPrompts(server, prompts, query, limit) {
31621
+ const lower = query.toLocaleLowerCase();
31622
+ return prompts.map((prompt) => this.compactPrompt(server, prompt)).filter((prompt) => [
31623
+ prompt.prompt,
31624
+ prompt.description,
31625
+ ...(prompt.arguments ?? []).flatMap((arg) => [arg.name, arg.description])
31626
+ ].some((value) => value?.toLocaleLowerCase().includes(lower))).slice(0, limit);
31627
+ }
31328
31628
  search(server, tools, query, limit) {
31329
31629
  return searchToolList(tools, query, limit, (tool) => this.compact(server, tool));
31330
31630
  }
31631
+ async assertCapability(server, capability) {
31632
+ const connection = await this.connect(server);
31633
+ if (!connection.client.getServerCapabilities()?.[capability]) throw new CapletsError("UNSUPPORTED_CAPABILITY", `${server.server} does not advertise MCP ${capability}`, {
31634
+ server: server.server,
31635
+ capability
31636
+ });
31637
+ return connection;
31638
+ }
31639
+ isCacheFresh(fetchedAt, ttlMs) {
31640
+ return fetchedAt !== void 0 && ttlMs > 0 && Date.now() - fetchedAt <= ttlMs;
31641
+ }
31331
31642
  async refreshTools(server, force) {
31332
31643
  const connection = await this.connect(server);
31333
31644
  const now = Date.now();
@@ -31371,6 +31682,20 @@ var DownstreamManager = class {
31371
31682
  transport,
31372
31683
  configFingerprint: expectedFingerprint
31373
31684
  };
31685
+ client.setNotificationHandler(ToolListChangedNotificationSchema, () => {
31686
+ connection.tools = void 0;
31687
+ connection.toolsFetchedAt = void 0;
31688
+ });
31689
+ client.setNotificationHandler(ResourceListChangedNotificationSchema, () => {
31690
+ connection.resources = void 0;
31691
+ connection.resourcesFetchedAt = void 0;
31692
+ connection.resourceTemplates = void 0;
31693
+ connection.resourceTemplatesFetchedAt = void 0;
31694
+ });
31695
+ client.setNotificationHandler(PromptListChangedNotificationSchema, () => {
31696
+ connection.prompts = void 0;
31697
+ connection.promptsFetchedAt = void 0;
31698
+ });
31374
31699
  pendingConnection = connection;
31375
31700
  this.connecting.set(server.server, connection);
31376
31701
  transport.onclose = () => {
@@ -31501,6 +31826,18 @@ function nearbyToolNames(tools, needle) {
31501
31826
  function isTimeoutLike(error) {
31502
31827
  return error instanceof Error && /timeout|timed out|aborted/i.test(error.message);
31503
31828
  }
31829
+ function stringifyPromptArgs(args) {
31830
+ const stringified = {};
31831
+ for (const [key, value] of Object.entries(args)) {
31832
+ if (typeof value === "string") {
31833
+ stringified[key] = value;
31834
+ continue;
31835
+ }
31836
+ const serialized = JSON.stringify(value);
31837
+ if (typeof serialized === "string") stringified[key] = serialized;
31838
+ }
31839
+ return stringified;
31840
+ }
31504
31841
  function isAuthRemediationError(error) {
31505
31842
  return error instanceof CapletsError && (error.code === "AUTH_REQUIRED" || error.code === "AUTH_FAILED");
31506
31843
  }
@@ -56362,7 +56699,7 @@ function capabilityDescription(server) {
56362
56699
  return [
56363
56700
  `${server.name} Caplet.`,
56364
56701
  server.description,
56365
- "Use get_caplet for details when needed; use search_tools or list_tools to discover downstream operations."
56702
+ 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
56703
  ].filter(Boolean).join(" ");
56367
56704
  }
56368
56705
  var ServerRegistry = class {
@@ -56578,17 +56915,9 @@ function cloneJsonValue(value) {
56578
56915
  function throwInvalid(message) {
56579
56916
  throw new CapletsError("REQUEST_INVALID", message);
56580
56917
  }
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
56918
  async function handleServerTool(server, request, registry, downstream, openapi, graphql, http, cli, caplets) {
56590
56919
  const startedAt = Date.now();
56591
- const parsed = validateOperationRequest(request, registry.config.options.maxSearchLimit);
56920
+ const parsed = validateOperationRequest(request, registry.config.options.maxSearchLimit, server.backend);
56592
56921
  switch (parsed.operation) {
56593
56922
  case "get_caplet": return jsonResult(registry.detail(server), metadataFor(server, "get_caplet", void 0, startedAt));
56594
56923
  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 +56958,75 @@ async function handleServerTool(server, request, registry, downstream, openapi,
56629
56958
  validateFieldSelection(tool.outputSchema, parsed.fields);
56630
56959
  return annotateCallToolResult(projectCallToolResult(await backend.callTool(server, parsed.tool, parsed.arguments), tool.outputSchema, parsed.fields), metadataFor(server, "call_tool", parsed.tool, startedAt));
56631
56960
  }
56961
+ case "list_resources": {
56962
+ const backend = mcpBackendFor(server, downstream);
56963
+ const resources = await backend.listResources(server);
56964
+ const templates = await backend.listResourceTemplates(server);
56965
+ const limit = parsed.limit ?? resources.length + templates.length;
56966
+ return jsonResult({
56967
+ id: server.server,
56968
+ name: server.name,
56969
+ resources: resources.slice(0, limit).map((resource) => backend.compactResource(server, resource)),
56970
+ resourceTemplates: templates.slice(0, Math.max(0, limit - resources.length)).map((template) => backend.compactResourceTemplate(server, template))
56971
+ }, metadataFor(server, "list_resources", void 0, startedAt));
56972
+ }
56973
+ case "search_resources": {
56974
+ const backend = mcpBackendFor(server, downstream);
56975
+ const resources = await backend.listResources(server);
56976
+ const templates = await backend.listResourceTemplates(server);
56977
+ const limit = parsed.limit ?? registry.config.options.defaultSearchLimit;
56978
+ const resourceMatches = backend.searchResources(server, resources, parsed.query, limit);
56979
+ const templateMatches = backend.searchResourceTemplates(server, templates, parsed.query, Math.max(0, limit - resourceMatches.length));
56980
+ return jsonResult({
56981
+ id: server.server,
56982
+ name: server.name,
56983
+ query: parsed.query,
56984
+ matches: [...resourceMatches, ...templateMatches]
56985
+ }, metadataFor(server, "search_resources", void 0, startedAt));
56986
+ }
56987
+ case "list_resource_templates": {
56988
+ const backend = mcpBackendFor(server, downstream);
56989
+ const templates = await backend.listResourceTemplates(server);
56990
+ const limit = parsed.limit ?? templates.length;
56991
+ return jsonResult({
56992
+ id: server.server,
56993
+ name: server.name,
56994
+ resourceTemplates: templates.slice(0, limit).map((template) => backend.compactResourceTemplate(server, template))
56995
+ }, metadataFor(server, "list_resource_templates", void 0, startedAt));
56996
+ }
56997
+ case "read_resource": return annotateMcpResult(await mcpBackendFor(server, downstream).readResource(server, parsed.uri), metadataFor(server, "read_resource", { uri: parsed.uri }, startedAt));
56998
+ case "list_prompts": {
56999
+ const backend = mcpBackendFor(server, downstream);
57000
+ const prompts = await backend.listPrompts(server);
57001
+ const limit = parsed.limit ?? prompts.length;
57002
+ return jsonResult({
57003
+ id: server.server,
57004
+ name: server.name,
57005
+ prompts: prompts.slice(0, limit).map((prompt) => backend.compactPrompt(server, prompt))
57006
+ }, metadataFor(server, "list_prompts", void 0, startedAt));
57007
+ }
57008
+ case "search_prompts": {
57009
+ const backend = mcpBackendFor(server, downstream);
57010
+ const prompts = await backend.listPrompts(server);
57011
+ const limit = parsed.limit ?? registry.config.options.defaultSearchLimit;
57012
+ return jsonResult({
57013
+ id: server.server,
57014
+ name: server.name,
57015
+ query: parsed.query,
57016
+ prompts: backend.searchPrompts(server, prompts, parsed.query, limit)
57017
+ }, metadataFor(server, "search_prompts", void 0, startedAt));
57018
+ }
57019
+ case "get_prompt": return annotateMcpResult(await mcpBackendFor(server, downstream).getPrompt(server, parsed.prompt, parsed.arguments), metadataFor(server, "get_prompt", { prompt: parsed.prompt }, startedAt));
57020
+ case "complete": return annotateMcpResult(await mcpBackendFor(server, downstream).complete(server, {
57021
+ ref: parsed.ref,
57022
+ argument: parsed.argument
57023
+ }), metadataFor(server, "complete", void 0, startedAt));
56632
57024
  }
56633
57025
  }
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);
57026
+ function validateOperationRequest(request, maxSearchLimit, backend = "tool") {
57027
+ const result = generatedToolInputSchemaForCaplet({ backend }).safeParse(request);
57028
+ 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}`);
57029
+ 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
57030
  if (!result.success) throw new CapletsError("REQUEST_INVALID", "Generated server tool request is invalid", result.error.issues);
56638
57031
  const value = result.data;
56639
57032
  const keys = Object.keys(value).sort();
@@ -56680,7 +57073,7 @@ function validateOperationRequest(request, maxSearchLimit) {
56680
57073
  "fields"
56681
57074
  ]);
56682
57075
  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");
57076
+ if (!isPlainObject$7(value.arguments)) throw new CapletsError("REQUEST_INVALID", "call_tool.arguments must be a JSON object");
56684
57077
  return value.fields === void 0 ? {
56685
57078
  operation: "call_tool",
56686
57079
  tool: value.tool,
@@ -56691,23 +57084,82 @@ function validateOperationRequest(request, maxSearchLimit) {
56691
57084
  arguments: value.arguments,
56692
57085
  fields: value.fields
56693
57086
  };
57087
+ case "list_resources":
57088
+ case "list_resource_templates":
57089
+ case "list_prompts":
57090
+ allowed(["limit"]);
57091
+ if (value.limit !== void 0 && value.limit > maxSearchLimit) throw new CapletsError("REQUEST_INVALID", `${value.operation} limit must be <= ${maxSearchLimit}`);
57092
+ return value.limit === void 0 ? { operation: value.operation } : {
57093
+ operation: value.operation,
57094
+ limit: value.limit
57095
+ };
57096
+ case "search_resources":
57097
+ case "search_prompts":
57098
+ allowed(["query", "limit"]);
57099
+ if (!value.query) throw new CapletsError("REQUEST_INVALID", `${value.operation} requires query`);
57100
+ if (value.limit !== void 0 && value.limit > maxSearchLimit) throw new CapletsError("REQUEST_INVALID", `${value.operation} limit must be <= ${maxSearchLimit}`);
57101
+ return value.limit === void 0 ? {
57102
+ operation: value.operation,
57103
+ query: value.query
57104
+ } : {
57105
+ operation: value.operation,
57106
+ query: value.query,
57107
+ limit: value.limit
57108
+ };
57109
+ case "read_resource":
57110
+ allowed(["uri"]);
57111
+ if (!value.uri) throw new CapletsError("REQUEST_INVALID", "read_resource requires uri");
57112
+ return {
57113
+ operation: "read_resource",
57114
+ uri: value.uri
57115
+ };
57116
+ case "get_prompt":
57117
+ allowed(["prompt", "arguments"]);
57118
+ if (!value.prompt) throw new CapletsError("REQUEST_INVALID", "get_prompt requires prompt");
57119
+ if (value.arguments !== void 0 && !isPlainObject$7(value.arguments)) throw new CapletsError("REQUEST_INVALID", "get_prompt.arguments must be a JSON object");
57120
+ return {
57121
+ operation: "get_prompt",
57122
+ prompt: value.prompt,
57123
+ arguments: value.arguments ?? {}
57124
+ };
57125
+ case "complete":
57126
+ allowed(["ref", "argument"]);
57127
+ if (!value.ref) throw new CapletsError("REQUEST_INVALID", "complete requires ref");
57128
+ if (!value.argument) throw new CapletsError("REQUEST_INVALID", "complete requires argument");
57129
+ return {
57130
+ operation: "complete",
57131
+ ref: value.ref,
57132
+ argument: value.argument
57133
+ };
56694
57134
  }
56695
- return assertNever(value.operation);
57135
+ throw new CapletsError("INTERNAL_ERROR", "Unhandled operation");
56696
57136
  }
56697
- function assertNever(value) {
56698
- throw new CapletsError("INTERNAL_ERROR", `Unhandled operation: ${String(value)}`);
57137
+ function mcpBackendFor(server, downstream) {
57138
+ if (server.backend !== "mcp") throw new CapletsError("UNSUPPORTED_OPERATION", "MCP resource, prompt, and completion operations require an MCP-backed Caplet");
57139
+ return downstream;
56699
57140
  }
56700
- function metadataFor(server, operation, tool, startedAt) {
57141
+ function metadataFor(server, operation, target, startedAt) {
57142
+ const targetFields = typeof target === "string" ? { tool: target } : target ?? {};
56701
57143
  return {
56702
57144
  id: server.server,
56703
57145
  name: server.name,
56704
57146
  backend: server.backend,
56705
57147
  operation,
56706
- ...tool === void 0 ? {} : { tool },
57148
+ ...targetFields,
56707
57149
  status: "ok",
56708
57150
  ...startedAt === void 0 ? {} : { elapsedMs: Date.now() - startedAt }
56709
57151
  };
56710
57152
  }
57153
+ function annotateMcpResult(result, metadata) {
57154
+ const existingMeta = result._meta;
57155
+ return {
57156
+ ...result,
57157
+ _meta: {
57158
+ ...isPlainObject$7(existingMeta) ? existingMeta : {},
57159
+ caplets: metadata
57160
+ }
57161
+ };
57162
+ }
56711
57163
  function jsonResult(value, metadata) {
56712
57164
  return {
56713
57165
  content: [{
@@ -56731,7 +57183,7 @@ function annotateCallToolResult(result, metadata) {
56731
57183
  return {
56732
57184
  ...result,
56733
57185
  _meta: {
56734
- ...isPlainObject$8(existingMeta) ? existingMeta : {},
57186
+ ...isPlainObject$7(existingMeta) ? existingMeta : {},
56735
57187
  caplets: annotatedMetadata
56736
57188
  }
56737
57189
  };
@@ -56739,7 +57191,7 @@ function annotateCallToolResult(result, metadata) {
56739
57191
  function projectCallToolResult(result, outputSchema, fields) {
56740
57192
  if (result.isError === true) return result;
56741
57193
  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");
57194
+ if (!isPlainObject$7(structuredContent)) throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", "Field selection requires the downstream tool to return object structuredContent");
56743
57195
  const projected = projectStructuredContent(structuredContent, outputSchema, fields);
56744
57196
  return {
56745
57197
  ...result,
@@ -56748,11 +57200,11 @@ function projectCallToolResult(result, outputSchema, fields) {
56748
57200
  };
56749
57201
  }
56750
57202
  function extractArtifacts(result) {
56751
- if (!isPlainObject$8(result) || !Array.isArray(result.content)) return [];
57203
+ if (!isPlainObject$7(result) || !Array.isArray(result.content)) return [];
56752
57204
  const artifacts = [];
56753
57205
  const seen = /* @__PURE__ */ new Set();
56754
57206
  for (const item of result.content) {
56755
- if (!isPlainObject$8(item) || item.type !== "text" || typeof item.text !== "string") continue;
57207
+ if (!isPlainObject$7(item) || item.type !== "text" || typeof item.text !== "string") continue;
56756
57208
  const text = item.text;
56757
57209
  for (const link of parseMarkdownLinks(text)) {
56758
57210
  const label = link.label;
@@ -56867,7 +57319,7 @@ function artifactKindFromText(text) {
56867
57319
  if (/network[-_ ]?(?:log)?|har\b/.test(text)) return "network-log";
56868
57320
  return "file";
56869
57321
  }
56870
- function isPlainObject$8(value) {
57322
+ function isPlainObject$7(value) {
56871
57323
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
56872
57324
  }
56873
57325
  function backendFor(server, downstream, openapi, graphql, http, cli, caplets) {
@@ -57175,6 +57627,38 @@ var CapletsEngine = class {
57175
57627
  return errorResult(error);
57176
57628
  }
57177
57629
  }
57630
+ async completeCliWords(words) {
57631
+ const { completeCliWords } = await Promise.resolve().then(() => completion_CxGG6ae3_exports).then((n) => n.r);
57632
+ return await completeCliWords(words, {
57633
+ config: this.registry.config,
57634
+ managers: {
57635
+ listTools: async (server) => this.listCompletionTools(server),
57636
+ listPrompts: async (server) => {
57637
+ if (server.backend !== "mcp") return [];
57638
+ return (await this.downstream.listPrompts(server)).map((prompt) => ({
57639
+ name: prompt.name,
57640
+ ...prompt.description ? { description: prompt.description } : {}
57641
+ }));
57642
+ },
57643
+ listResources: async (server) => {
57644
+ if (server.backend !== "mcp") return [];
57645
+ return (await this.downstream.listResources(server)).map((resource) => ({
57646
+ uri: resource.uri,
57647
+ ...resource.name ? { name: resource.name } : {},
57648
+ ...resource.description ? { description: resource.description } : {}
57649
+ }));
57650
+ },
57651
+ listResourceTemplates: async (server) => {
57652
+ if (server.backend !== "mcp") return [];
57653
+ return (await this.downstream.listResourceTemplates(server)).map((template) => ({
57654
+ uriTemplate: template.uriTemplate,
57655
+ ...template.name ? { name: template.name } : {},
57656
+ ...template.description ? { description: template.description } : {}
57657
+ }));
57658
+ }
57659
+ }
57660
+ });
57661
+ }
57178
57662
  async close() {
57179
57663
  this.closed = true;
57180
57664
  try {
@@ -57194,6 +57678,12 @@ var CapletsEngine = class {
57194
57678
  this.reloadListeners.clear();
57195
57679
  }
57196
57680
  }
57681
+ async listCompletionTools(server) {
57682
+ 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) => ({
57683
+ name: tool.name,
57684
+ ...tool.description ? { description: tool.description } : {}
57685
+ }));
57686
+ }
57197
57687
  async reloadOnce() {
57198
57688
  if (this.closed) return false;
57199
57689
  let nextConfig;
@@ -57476,6 +57966,565 @@ function hasEnv$1(value) {
57476
57966
  return value !== void 0 && value.trim() !== "";
57477
57967
  }
57478
57968
  //#endregion
57969
+ //#region ../core/dist/completion-CxGG6ae3.js
57970
+ var completion_CxGG6ae3_exports = /* @__PURE__ */ __exportAll$1({
57971
+ a: () => formatCapletList,
57972
+ c: () => resolveCliConfigPaths,
57973
+ i: () => trailingSpaceCompletionToken,
57974
+ l: () => cliCommands,
57975
+ n: () => completionScript,
57976
+ o: () => formatConfigPaths,
57977
+ r: () => completion_exports,
57978
+ s: () => listCaplets,
57979
+ t: () => completeCliWords,
57980
+ u: () => completionShells
57981
+ });
57982
+ const completionShells = [
57983
+ "bash",
57984
+ "zsh",
57985
+ "fish",
57986
+ "powershell",
57987
+ "cmd"
57988
+ ];
57989
+ const cliCommands = {
57990
+ completion: "completion",
57991
+ completeHidden: "__complete",
57992
+ serve: "serve",
57993
+ init: "init",
57994
+ list: "list",
57995
+ install: "install",
57996
+ add: "add",
57997
+ getCaplet: "get-caplet",
57998
+ checkBackend: "check-backend",
57999
+ listTools: "list-tools",
58000
+ searchTools: "search-tools",
58001
+ getTool: "get-tool",
58002
+ callTool: "call-tool",
58003
+ listResources: "list-resources",
58004
+ searchResources: "search-resources",
58005
+ listResourceTemplates: "list-resource-templates",
58006
+ readResource: "read-resource",
58007
+ listPrompts: "list-prompts",
58008
+ searchPrompts: "search-prompts",
58009
+ getPrompt: "get-prompt",
58010
+ complete: "complete",
58011
+ config: "config",
58012
+ auth: "auth"
58013
+ };
58014
+ const topLevelCommandNames = [
58015
+ cliCommands.serve,
58016
+ cliCommands.init,
58017
+ cliCommands.list,
58018
+ cliCommands.install,
58019
+ cliCommands.add,
58020
+ cliCommands.getCaplet,
58021
+ cliCommands.checkBackend,
58022
+ cliCommands.listTools,
58023
+ cliCommands.searchTools,
58024
+ cliCommands.getTool,
58025
+ cliCommands.callTool,
58026
+ cliCommands.listResources,
58027
+ cliCommands.searchResources,
58028
+ cliCommands.listResourceTemplates,
58029
+ cliCommands.readResource,
58030
+ cliCommands.listPrompts,
58031
+ cliCommands.searchPrompts,
58032
+ cliCommands.getPrompt,
58033
+ cliCommands.complete,
58034
+ cliCommands.config,
58035
+ cliCommands.auth,
58036
+ cliCommands.completion
58037
+ ];
58038
+ const cliSubcommands = {
58039
+ [cliCommands.add]: [
58040
+ "cli",
58041
+ "mcp",
58042
+ "openapi",
58043
+ "graphql",
58044
+ "http"
58045
+ ],
58046
+ [cliCommands.auth]: [
58047
+ "login",
58048
+ "logout",
58049
+ "list"
58050
+ ],
58051
+ [cliCommands.completion]: [...completionShells],
58052
+ [cliCommands.config]: ["path", "paths"]
58053
+ };
58054
+ const capletIdCommands = new Set([
58055
+ cliCommands.getCaplet,
58056
+ cliCommands.checkBackend,
58057
+ cliCommands.listTools,
58058
+ cliCommands.searchTools,
58059
+ cliCommands.listResources,
58060
+ cliCommands.searchResources,
58061
+ cliCommands.listResourceTemplates,
58062
+ cliCommands.readResource,
58063
+ cliCommands.listPrompts,
58064
+ cliCommands.searchPrompts,
58065
+ cliCommands.complete
58066
+ ]);
58067
+ const qualifiedToolCommands = new Set([cliCommands.getTool, cliCommands.callTool]);
58068
+ const qualifiedPromptCommands = new Set([cliCommands.getPrompt]);
58069
+ function listCaplets(configWithSources, options) {
58070
+ const { config, sources, shadows } = configWithSources;
58071
+ return allCaplets(config).filter((server) => options.includeDisabled || !server.disabled).map((server) => ({
58072
+ server: server.server,
58073
+ backend: server.backend,
58074
+ name: server.name,
58075
+ description: server.description,
58076
+ disabled: server.disabled,
58077
+ status: initialServerStatus(server),
58078
+ source: sources[server.server]?.kind ?? "unknown",
58079
+ path: sources[server.server]?.path ?? null,
58080
+ shadows: shadows[server.server] ?? []
58081
+ })).sort((left, right) => left.server.localeCompare(right.server));
58082
+ }
58083
+ function initialServerStatus(server) {
58084
+ return server.disabled ? "disabled" : "not_started";
58085
+ }
58086
+ function allCaplets(config) {
58087
+ return [
58088
+ ...Object.values(config.mcpServers),
58089
+ ...Object.values(config.openapiEndpoints),
58090
+ ...Object.values(config.graphqlEndpoints),
58091
+ ...Object.values(config.httpApis),
58092
+ ...Object.values(config.cliTools)
58093
+ ];
58094
+ }
58095
+ function formatCapletList(rows, format = "plain") {
58096
+ return format === "markdown" ? formatCapletListMarkdown(rows) : formatCapletListPlain(rows);
58097
+ }
58098
+ function formatCapletListMarkdown(rows) {
58099
+ if (rows.length === 0) return "## Configured Caplets\n\nNo configured Caplets found.\n";
58100
+ const heading = [
58101
+ "## Configured Caplets",
58102
+ "",
58103
+ `${rows.length} ${rows.length === 1 ? "Caplet" : "Caplets"} shown.`,
58104
+ ""
58105
+ ];
58106
+ const entries = rows.flatMap((row) => [
58107
+ `- \`${row.server}\` — ${row.name}`,
58108
+ ` - Backend: ${row.backend}`,
58109
+ ` - Status: ${row.status}`,
58110
+ ` - Source: ${row.source}`,
58111
+ ...row.disabled ? [" - Disabled: true"] : [],
58112
+ ...row.path ? [` - Path: ${row.path}`] : []
58113
+ ]);
58114
+ const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
58115
+ if (warnings.length === 0) return `${[...heading, ...entries].join("\n")}\n`;
58116
+ return `${[
58117
+ ...heading,
58118
+ ...entries,
58119
+ "",
58120
+ "Warnings:",
58121
+ ...warnings.map((warning) => `- ${warning}`)
58122
+ ].join("\n")}\n`;
58123
+ }
58124
+ function formatCapletListPlain(rows) {
58125
+ if (rows.length === 0) return "No configured Caplets found.\n";
58126
+ const entries = rows.map((row) => [
58127
+ row.server,
58128
+ ` Name: ${row.name}`,
58129
+ ` Backend: ${row.backend}`,
58130
+ ` Status: ${row.status}`,
58131
+ ` Source: ${row.source}`,
58132
+ ...row.disabled ? [" Disabled: true"] : [],
58133
+ ...row.path ? [` Path: ${row.path}`] : []
58134
+ ].join("\n")).join("\n\n");
58135
+ const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
58136
+ if (warnings.length === 0) return `Configured Caplets (${rows.length})\n\n${entries}\n`;
58137
+ return `Configured Caplets (${rows.length})\n\n${entries}\n\n${warnings.join("\n")}\n`;
58138
+ }
58139
+ function formatSourceKind(kind) {
58140
+ if (kind.startsWith("project")) return "project";
58141
+ if (kind.startsWith("global")) return "global";
58142
+ return kind;
58143
+ }
58144
+ function resolveCliConfigPaths(envConfigPath, authDir) {
58145
+ const configPath = resolveConfigPath(envConfigPath);
58146
+ const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
58147
+ return {
58148
+ userConfig: configPath,
58149
+ projectConfig: resolveProjectConfigPath(),
58150
+ userRoot: resolveCapletsRoot(configPath),
58151
+ stateRoot: dirname(effectiveAuthDir),
58152
+ projectRoot: resolveProjectCapletsRoot(),
58153
+ authDir: effectiveAuthDir,
58154
+ envConfig: envConfigPath ?? null
58155
+ };
58156
+ }
58157
+ function formatConfigPaths(paths, format = "plain") {
58158
+ if (format === "markdown") return formatConfigPathsMarkdown(paths);
58159
+ return formatConfigPathsPlain(paths);
58160
+ }
58161
+ function formatConfigPathsMarkdown(paths) {
58162
+ return [
58163
+ "## Caplets paths",
58164
+ "",
58165
+ `- User config: ${paths.userConfig}`,
58166
+ `- Project config: ${paths.projectConfig}`,
58167
+ `- User Caplets root: ${paths.userRoot}`,
58168
+ `- State root: ${paths.stateRoot}`,
58169
+ `- Project Caplets root: ${paths.projectRoot}`,
58170
+ `- Auth directory: ${paths.authDir}`,
58171
+ `- CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
58172
+ ].join("\n") + "\n";
58173
+ }
58174
+ function formatConfigPathsPlain(paths) {
58175
+ return [
58176
+ "Caplets paths",
58177
+ "",
58178
+ `User config: ${paths.userConfig}`,
58179
+ `Project config: ${paths.projectConfig}`,
58180
+ `User root: ${paths.userRoot}`,
58181
+ `State root: ${paths.stateRoot}`,
58182
+ `Project root: ${paths.projectRoot}`,
58183
+ `Auth directory: ${paths.authDir}`,
58184
+ `CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
58185
+ ].join("\n") + "\n";
58186
+ }
58187
+ function completionCacheKey(input) {
58188
+ return createHash("sha256").update(JSON.stringify(input)).digest("hex");
58189
+ }
58190
+ function readCompletionCacheEntry(cacheDir, key, now = Date.now()) {
58191
+ try {
58192
+ const parsed = JSON.parse(readFileSync(cachePath(cacheDir, key), "utf8"));
58193
+ if (parsed.status === "positive" && Array.isArray(parsed.candidates)) return {
58194
+ ...parsed,
58195
+ fresh: now <= parsed.expiresAt
58196
+ };
58197
+ if (parsed.status === "negative" && typeof parsed.reason === "string") return {
58198
+ ...parsed,
58199
+ fresh: now <= parsed.expiresAt
58200
+ };
58201
+ } catch {
58202
+ return;
58203
+ }
58204
+ }
58205
+ function writeCompletionCacheEntry(cacheDir, key, entry) {
58206
+ mkdirSync(cacheDir, { recursive: true });
58207
+ const path = cachePath(cacheDir, key);
58208
+ const tempPath = `${path}.${process.pid}.tmp`;
58209
+ writeFileSync(tempPath, JSON.stringify(entry), { mode: 384 });
58210
+ renameSync(tempPath, path);
58211
+ }
58212
+ function cachePath(cacheDir, key) {
58213
+ return join(cacheDir, `${key}.json`);
58214
+ }
58215
+ async function discoverCompletionCandidates(serverId, kind, options) {
58216
+ const server = enabledServer(serverId, options.config);
58217
+ if (!server) return [];
58218
+ const completion = options.completion ?? options.config.options.completion;
58219
+ const now = options.now ?? Date.now();
58220
+ const configCandidates = configDefinedCandidates(serverId, kind, options.config);
58221
+ const cacheDir = options.cacheDir ?? DEFAULT_COMPLETION_CACHE_DIR;
58222
+ const key = completionCacheKey({
58223
+ server: server.server,
58224
+ backend: server.backend,
58225
+ kind,
58226
+ fingerprint: completionFingerprint(server, kind, completion)
58227
+ });
58228
+ const cached = readCompletionCacheEntry(cacheDir, key, now);
58229
+ if (cached?.status === "positive" && cached.fresh) return cached.candidates;
58230
+ if (cached?.status === "negative" && cached.fresh) return cached.candidates ?? configCandidates;
58231
+ try {
58232
+ const live = await withTimeout(liveCandidates(server, kind, options.managers), Math.min(completion.discoveryTimeoutMs, completion.overallTimeoutMs));
58233
+ const candidates = dedupeCandidates([...configCandidates, ...live]);
58234
+ writeCompletionCacheEntry(cacheDir, key, {
58235
+ status: "positive",
58236
+ fetchedAt: now,
58237
+ expiresAt: now + completion.cacheTtlMs,
58238
+ candidates
58239
+ });
58240
+ return candidates;
58241
+ } catch (error) {
58242
+ writeCompletionCacheEntry(cacheDir, key, {
58243
+ status: "negative",
58244
+ fetchedAt: now,
58245
+ expiresAt: now + completion.negativeCacheTtlMs,
58246
+ reason: negativeReason(error),
58247
+ ...cached?.status === "positive" ? { candidates: cached.candidates } : {}
58248
+ });
58249
+ if (cached?.status === "positive") return cached.candidates;
58250
+ return configCandidates;
58251
+ }
58252
+ }
58253
+ function configDefinedCandidates(serverId, kind, config) {
58254
+ if (kind !== "tools") return [];
58255
+ const cli = config.cliTools[serverId];
58256
+ if (cli && !cli.disabled) return Object.keys(cli.actions).map((name) => ({ value: `${serverId}.${name}` }));
58257
+ const http = config.httpApis[serverId];
58258
+ if (http && !http.disabled) return Object.keys(http.actions).map((name) => ({ value: `${serverId}.${name}` }));
58259
+ const graphql = config.graphqlEndpoints[serverId];
58260
+ if (graphql && !graphql.disabled && graphql.operations) return Object.keys(graphql.operations).map((name) => ({ value: `${serverId}.${name}` }));
58261
+ return [];
58262
+ }
58263
+ async function liveCandidates(server, kind, managers) {
58264
+ if (kind === "tools" && managers?.listTools) return (await managers.listTools(server)).map((tool) => ({
58265
+ value: `${server.server}.${tool.name}`,
58266
+ description: tool.description
58267
+ }));
58268
+ if (kind === "tools") return [];
58269
+ if (server.backend !== "mcp") return [];
58270
+ if (kind === "prompts" && managers?.listPrompts) return (await managers.listPrompts(server)).map((prompt) => ({
58271
+ value: `${server.server}.${prompt.name}`,
58272
+ description: prompt.description
58273
+ }));
58274
+ if (kind === "resources" && managers?.listResources) return (await managers.listResources(server)).map((resource) => ({
58275
+ value: resource.uri,
58276
+ label: resource.name,
58277
+ description: resource.description
58278
+ }));
58279
+ if (kind === "resourceTemplates" && managers?.listResourceTemplates) return (await managers.listResourceTemplates(server)).map((template) => ({
58280
+ value: template.uriTemplate,
58281
+ label: template.name,
58282
+ description: template.description
58283
+ }));
58284
+ throw new CapletsError("UNSUPPORTED_CAPABILITY", `Completion discovery is unsupported for ${kind}`);
58285
+ }
58286
+ function completionFingerprint(server, kind, completion) {
58287
+ return JSON.stringify({
58288
+ kind,
58289
+ completion: {
58290
+ discoveryTimeoutMs: completion.discoveryTimeoutMs,
58291
+ cacheTtlMs: completion.cacheTtlMs,
58292
+ negativeCacheTtlMs: completion.negativeCacheTtlMs
58293
+ },
58294
+ server: secretFreeServerShape(server)
58295
+ });
58296
+ }
58297
+ function secretFreeServerShape(server) {
58298
+ const base = {
58299
+ server: server.server,
58300
+ backend: server.backend,
58301
+ name: server.name,
58302
+ description: server.description,
58303
+ tags: server.tags,
58304
+ disabled: server.disabled
58305
+ };
58306
+ switch (server.backend) {
58307
+ case "mcp": return {
58308
+ ...base,
58309
+ transport: server.transport,
58310
+ command: server.command,
58311
+ args: server.args,
58312
+ cwd: server.cwd,
58313
+ url: server.url,
58314
+ authType: server.auth?.type,
58315
+ startupTimeoutMs: server.startupTimeoutMs,
58316
+ callTimeoutMs: server.callTimeoutMs
58317
+ };
58318
+ case "openapi": return {
58319
+ ...base,
58320
+ specPath: server.specPath,
58321
+ specUrl: server.specUrl,
58322
+ baseUrl: server.baseUrl,
58323
+ authType: server.auth.type,
58324
+ requestTimeoutMs: server.requestTimeoutMs
58325
+ };
58326
+ case "graphql": return {
58327
+ ...base,
58328
+ endpointUrl: server.endpointUrl,
58329
+ schemaPath: server.schemaPath,
58330
+ schemaUrl: server.schemaUrl,
58331
+ authType: server.auth.type,
58332
+ operationNames: server.operations ? Object.keys(server.operations) : void 0
58333
+ };
58334
+ case "http": return {
58335
+ ...base,
58336
+ baseUrl: server.baseUrl,
58337
+ authType: server.auth.type,
58338
+ actions: Object.fromEntries(Object.entries(server.actions).map(([name, action]) => [name, {
58339
+ method: action.method,
58340
+ path: action.path
58341
+ }])),
58342
+ requestTimeoutMs: server.requestTimeoutMs
58343
+ };
58344
+ case "cli": return {
58345
+ ...base,
58346
+ cwd: server.cwd,
58347
+ actions: Object.fromEntries(Object.entries(server.actions).map(([name, action]) => [name, {
58348
+ command: action.command,
58349
+ args: action.args,
58350
+ cwd: action.cwd
58351
+ }])),
58352
+ timeoutMs: server.timeoutMs,
58353
+ maxOutputBytes: server.maxOutputBytes
58354
+ };
58355
+ case "caplets": return {
58356
+ ...base,
58357
+ configPath: server.configPath,
58358
+ capletsRoot: server.capletsRoot,
58359
+ defaultSearchLimit: server.defaultSearchLimit,
58360
+ maxSearchLimit: server.maxSearchLimit
58361
+ };
58362
+ }
58363
+ }
58364
+ function negativeReason(error) {
58365
+ if (error instanceof CapletsError) {
58366
+ if (error.code === "AUTH_REQUIRED" || error.code === "AUTH_FAILED" || error.code === "AUTH_REFRESH_FAILED") return "auth_required";
58367
+ if (error.code === "SERVER_UNAVAILABLE" || error.code === "SERVER_START_TIMEOUT") return "unavailable";
58368
+ if (error.code === "UNSUPPORTED_CAPABILITY" || error.code === "UNSUPPORTED_OPERATION") return "unsupported";
58369
+ if (error.code === "TOOL_CALL_TIMEOUT" || error.code === "DOWNSTREAM_COMPLETION_ERROR") return "timeout";
58370
+ }
58371
+ return error instanceof Error && error.message.includes("timeout") ? "timeout" : "error";
58372
+ }
58373
+ async function withTimeout(promise, timeoutMs) {
58374
+ let timeout;
58375
+ try {
58376
+ return await Promise.race([promise, new Promise((_, reject) => {
58377
+ timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("completion discovery timeout")), timeoutMs);
58378
+ })]);
58379
+ } finally {
58380
+ if (timeout) clearTimeout(timeout);
58381
+ }
58382
+ }
58383
+ function enabledServer(serverId, config) {
58384
+ const server = config.mcpServers[serverId] ?? config.openapiEndpoints[serverId] ?? config.graphqlEndpoints[serverId] ?? config.httpApis[serverId] ?? config.cliTools[serverId] ?? config.capletSets[serverId];
58385
+ return server && !server.disabled ? server : void 0;
58386
+ }
58387
+ function dedupeCandidates(candidates) {
58388
+ const seen = /* @__PURE__ */ new Set();
58389
+ return candidates.filter((candidate) => {
58390
+ if (seen.has(candidate.value)) return false;
58391
+ seen.add(candidate.value);
58392
+ return true;
58393
+ });
58394
+ }
58395
+ var completion_exports = /* @__PURE__ */ __exportAll({
58396
+ completeCliWords: () => completeCliWords,
58397
+ completionScript: () => completionScript,
58398
+ trailingSpaceCompletionToken: () => trailingSpaceCompletionToken
58399
+ });
58400
+ const trailingSpaceCompletionToken = "__CAPLETS_TRAILING_SPACE__";
58401
+ const optionValueSuggestions = {
58402
+ "*": { "--format": [
58403
+ "markdown",
58404
+ "md",
58405
+ "plain",
58406
+ "json"
58407
+ ] },
58408
+ serve: { "--transport": ["stdio", "http"] },
58409
+ "add:mcp": { "--transport": ["http", "sse"] },
58410
+ "add:cli": { "--include": [
58411
+ "git",
58412
+ "gh",
58413
+ "package"
58414
+ ] }
58415
+ };
58416
+ function completionScript(shell) {
58417
+ switch (shell) {
58418
+ case "bash": return bashCompletionScript();
58419
+ case "zsh": return zshCompletionScript();
58420
+ case "fish": return fishCompletionScript();
58421
+ case "powershell": return powershellCompletionScript();
58422
+ case "cmd": return cmdCompletionScript();
58423
+ default: throw new CapletsError("REQUEST_INVALID", "completion shell must be bash, zsh, fish, powershell, or cmd");
58424
+ }
58425
+ }
58426
+ async function completeCliWords(words, options = {}) {
58427
+ try {
58428
+ const normalized = words.length === 0 ? [""] : words;
58429
+ const current = normalized.at(-1) ?? "";
58430
+ const previous = normalized.at(-2);
58431
+ const command = normalized[0] ?? "";
58432
+ const subcommand = normalized[1] ?? "";
58433
+ if (command === cliCommands.complete && previous === "--prompt" && subcommand) return prefixFilter((await discoverCompletionCandidates(subcommand, "prompts", discoveryOptions(options))).map((candidate) => candidate.value.replace(`${subcommand}.`, "")), current);
58434
+ if (command === cliCommands.complete && previous === "--resource-template" && subcommand) return prefixFilter((await discoverCompletionCandidates(subcommand, "resourceTemplates", discoveryOptions(options))).map((candidate) => candidate.value), current);
58435
+ const optionValues = suggestionsForOptionValue(command, subcommand, previous);
58436
+ if (optionValues) return prefixFilter(optionValues, current);
58437
+ if (normalized.length === 1) return prefixFilter([...topLevelCommandNames], current);
58438
+ if (normalized.length === 2 && command in cliSubcommands) return prefixFilter(cliSubcommands[command], current);
58439
+ if (normalized.length === 2 && capletIdCommands.has(command)) return prefixFilter(promptResourceCommands.has(command) ? configuredCapletIds(options, { backend: "mcp" }) : configuredCapletIds(options), current);
58440
+ if (normalized.length === 2 && (qualifiedToolCommands.has(command) || qualifiedPromptCommands.has(command))) {
58441
+ if (current.includes(".")) return prefixFilter((await discoverCompletionCandidates(current.slice(0, current.indexOf(".")), qualifiedToolCommands.has(command) ? "tools" : "prompts", discoveryOptions(options))).map((candidate) => candidate.value), current);
58442
+ return prefixFilter(configuredCapletIds(options, qualifiedPromptCommands.has(command) ? { backend: "mcp" } : void 0).map((id) => `${id}.`), current);
58443
+ }
58444
+ if (command === cliCommands.readResource && normalized.length === 3) return prefixFilter((await discoverCompletionCandidates(subcommand, "resources", discoveryOptions(options))).map((candidate) => candidate.value), current);
58445
+ if (command === cliCommands.auth && ["login", "logout"].includes(subcommand) && normalized.length === 3) return prefixFilter(configuredCapletIds(options), current);
58446
+ return [];
58447
+ } catch {
58448
+ return [];
58449
+ }
58450
+ }
58451
+ function suggestionsForOptionValue(command, subcommand, previous) {
58452
+ if (!previous) return void 0;
58453
+ return optionValueSuggestions[`${command}:${subcommand}`]?.[previous] ?? optionValueSuggestions[command]?.[previous] ?? optionValueSuggestions["*"]?.[previous];
58454
+ }
58455
+ const promptResourceCommands = new Set([
58456
+ cliCommands.getPrompt,
58457
+ cliCommands.readResource,
58458
+ cliCommands.complete
58459
+ ]);
58460
+ function configuredCapletIds(options, filter = {}) {
58461
+ return listCaplets(options.config ? {
58462
+ config: options.config,
58463
+ sources: {},
58464
+ shadows: {}
58465
+ } : loadConfigWithSources(options.configPath, options.projectConfigPath), { includeDisabled: false }).filter((row) => !filter.backend || row.backend === filter.backend).map((row) => row.server);
58466
+ }
58467
+ function discoveryOptions(options) {
58468
+ return {
58469
+ config: options.config ?? loadConfigWithSources(options.configPath, options.projectConfigPath).config,
58470
+ completion: options.completion,
58471
+ cacheDir: options.cacheDir,
58472
+ managers: options.managers
58473
+ };
58474
+ }
58475
+ function prefixFilter(values, prefix) {
58476
+ return values.filter((value) => value.startsWith(prefix));
58477
+ }
58478
+ function bashCompletionScript() {
58479
+ return `# caplets bash completion
58480
+ _caplets_completions() {
58481
+ local IFS=$'\n'
58482
+ COMPREPLY=( $(caplets __complete --shell bash -- "\${COMP_WORDS[@]:1}" 2>/dev/null) )
58483
+ }
58484
+ complete -o default -F _caplets_completions caplets
58485
+ `;
58486
+ }
58487
+ function zshCompletionScript() {
58488
+ return `#compdef caplets
58489
+ _caplets() {
58490
+ local -a suggestions
58491
+ suggestions=("\${(@f)$(caplets __complete --shell zsh -- "\${words[@]:1}" 2>/dev/null)}")
58492
+ compadd -- $suggestions
58493
+ }
58494
+ _caplets "$@"
58495
+ `;
58496
+ }
58497
+ function fishCompletionScript() {
58498
+ return `# caplets fish completion
58499
+ function __caplets_complete
58500
+ set -l tokens (commandline -opc)
58501
+ set -l current (commandline -ct)
58502
+ caplets __complete --shell fish -- $tokens[2..-1] $current 2>/dev/null
58503
+ end
58504
+ complete -c caplets -f -a '(__caplets_complete)'
58505
+ `;
58506
+ }
58507
+ function powershellCompletionScript() {
58508
+ return `# caplets PowerShell completion
58509
+ Register-ArgumentCompleter -Native -CommandName caplets -ScriptBlock {
58510
+ param($wordToComplete, $commandAst, $cursorPosition)
58511
+ $tokens = @($commandAst.CommandElements | Select-Object -Skip 1 | ForEach-Object { $_.ToString() })
58512
+ if ($tokens.Count -eq 0 -or $commandAst.Extent.Text.EndsWith(' ')) { $tokens += '${trailingSpaceCompletionToken}' }
58513
+ caplets __complete --shell powershell -- @tokens 2>$null | ForEach-Object {
58514
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
58515
+ }
58516
+ }
58517
+ `;
58518
+ }
58519
+ function cmdCompletionScript() {
58520
+ return `@echo off
58521
+ REM caplets cmd completion helper
58522
+ REM cmd.exe has no native programmable completion API. This doskey macro prints suggestions for the current words.
58523
+ doskey caplets-complete=caplets __complete --shell cmd -- $* 2^>nul
58524
+ REM Usage: caplets-complete get-caplet
58525
+ `;
58526
+ }
58527
+ //#endregion
57479
58528
  //#region ../core/dist/index.js
57480
58529
  /**
57481
58530
  * Experimental server task features for MCP SDK.
@@ -58773,7 +59822,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
58773
59822
  values: [],
58774
59823
  hasMore: false
58775
59824
  } };
58776
- var version$1 = "0.17.0";
59825
+ var version$1 = "0.18.0";
58777
59826
  var CapletsMcpSession = class {
58778
59827
  engine;
58779
59828
  server;
@@ -58815,6 +59864,7 @@ var CapletsMcpSession = class {
58815
59864
  if (!previousCaplet || serializeCaplet(previousCaplet) !== serializeCaplet(caplet)) tool.update({
58816
59865
  title: caplet.name,
58817
59866
  description: capabilityDescription(caplet),
59867
+ paramsSchema: generatedToolInputSchemaForCaplet(caplet).shape,
58818
59868
  callback: async (request) => this.handleTool(serverId, request),
58819
59869
  enabled: true
58820
59870
  });
@@ -58828,7 +59878,7 @@ var CapletsMcpSession = class {
58828
59878
  return this.server.registerTool(caplet.server, {
58829
59879
  title: caplet.name,
58830
59880
  description: capabilityDescription(caplet),
58831
- inputSchema: generatedToolInputSchema
59881
+ inputSchema: generatedToolInputSchemaForCaplet(caplet).shape
58832
59882
  }, async (request) => this.handleTool(caplet.server, request));
58833
59883
  }
58834
59884
  async handleTool(serverId, request) {
@@ -62424,124 +63474,6 @@ function starterConfig() {
62424
63474
  } }
62425
63475
  }, null, 2);
62426
63476
  }
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
63477
  function installCaplets(repo, options = {}) {
62546
63478
  const source = resolveInstallSource(repo);
62547
63479
  try {
@@ -65738,7 +66670,15 @@ const ENGINE_COMMANDS = new Set([
65738
66670
  "list_tools",
65739
66671
  "search_tools",
65740
66672
  "get_tool",
65741
- "call_tool"
66673
+ "call_tool",
66674
+ "list_resources",
66675
+ "search_resources",
66676
+ "list_resource_templates",
66677
+ "read_resource",
66678
+ "list_prompts",
66679
+ "search_prompts",
66680
+ "get_prompt",
66681
+ "complete"
65742
66682
  ]);
65743
66683
  async function dispatchRemoteCliRequest(request, context) {
65744
66684
  try {
@@ -65789,6 +66729,16 @@ async function dispatch(request, context) {
65789
66729
  ...optionalProp("force", optionalBoolean(request.arguments, "force"))
65790
66730
  })
65791
66731
  };
66732
+ if (request.command === "complete_cli") {
66733
+ const shell = optionalString(request.arguments, "shell") ?? "bash";
66734
+ if (!completionShells.includes(shell)) return [];
66735
+ const engine = new CapletsEngine(context);
66736
+ try {
66737
+ return await engine.completeCliWords(optionalStringArray(request.arguments, "words") ?? [""]);
66738
+ } finally {
66739
+ await engine.close();
66740
+ }
66741
+ }
65792
66742
  if (request.command === "auth_list") return listAuthRows({
65793
66743
  ...optionalProp("configPath", context.configPath),
65794
66744
  ...optionalProp("authDir", context.authDir)
@@ -65905,6 +66855,12 @@ function requiredString(args, key) {
65905
66855
  if (typeof value !== "string" || value.length === 0) throw new CapletsError("REQUEST_INVALID", `${key} must be a non-empty string`);
65906
66856
  return value;
65907
66857
  }
66858
+ function optionalString(args, key) {
66859
+ const value = args[key];
66860
+ if (value === void 0) return;
66861
+ if (typeof value !== "string") throw new CapletsError("REQUEST_INVALID", `${key} must be a string`);
66862
+ return value;
66863
+ }
65908
66864
  function optionalObject(args, key) {
65909
66865
  const value = args[key];
65910
66866
  if (value === void 0) return {};
@@ -66467,6 +67423,9 @@ async function runCli(args, io = {}) {
66467
67423
  throw error;
66468
67424
  }
66469
67425
  }
67426
+ function normalizeCompletionWords(words) {
67427
+ return words.map((word) => word === "__CAPLETS_TRAILING_SPACE__" ? "" : word);
67428
+ }
66470
67429
  function createProgram(io = {}) {
66471
67430
  const writeOut = io.writeOut ?? ((value) => process.stdout.write(value));
66472
67431
  const writeErr = io.writeErr ?? ((value) => process.stderr.write(value));
@@ -66481,7 +67440,27 @@ function createProgram(io = {}) {
66481
67440
  writeErr,
66482
67441
  outputError: (value, write) => write(value)
66483
67442
  });
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) => {
67443
+ program.command(cliCommands.completion).description("Print a shell completion script.").argument("<shell>", "completion shell: bash, zsh, fish, powershell, or cmd").action((shell) => {
67444
+ if (!completionShells.includes(shell)) throw new CapletsError("REQUEST_INVALID", "completion shell must be bash, zsh, fish, powershell, or cmd");
67445
+ writeOut(completionScript(shell));
67446
+ });
67447
+ 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) => {
67448
+ const shell = completionShells.includes(options.shell) ? options.shell : "bash";
67449
+ const remote = remoteClientForCli(io);
67450
+ const configPath = currentConfigPath();
67451
+ const completionWords = normalizeCompletionWords(words);
67452
+ let suggestions = [];
67453
+ try {
67454
+ suggestions = remote ? await remote.request("complete_cli", {
67455
+ shell,
67456
+ words: completionWords
67457
+ }) : await completeCliWords(completionWords, configPath ? { configPath } : {});
67458
+ } catch {
67459
+ suggestions = [];
67460
+ }
67461
+ if (suggestions.length > 0) writeOut(`${suggestions.join("\n")}\n`);
67462
+ });
67463
+ 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
67464
  const resolved = resolveServeOptions(options);
66486
67465
  const configPath = currentConfigPath();
66487
67466
  await (io.serve ?? ((serveOptions) => serveResolvedCaplets(serveOptions, {
@@ -66489,7 +67468,7 @@ function createProgram(io = {}) {
66489
67468
  ...io.authDir ? { authDir: io.authDir } : {}
66490
67469
  }, writeErr)))(resolved);
66491
67470
  });
66492
- program.command("init").description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
67471
+ program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
66493
67472
  const remote = remoteClientForCli(io);
66494
67473
  if (remote) {
66495
67474
  writeOut(`Created remote Caplets config at ${(await remote.request("init", { force: Boolean(options.force) })).path}\n`);
@@ -66501,7 +67480,7 @@ function createProgram(io = {}) {
66501
67480
  force: Boolean(options.force)
66502
67481
  })}\n`);
66503
67482
  });
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) => {
67483
+ 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
67484
  const includeDisabled = Boolean(options.all);
66506
67485
  const remote = remoteClientForCli(io);
66507
67486
  if (remote) {
@@ -66520,7 +67499,7 @@ function createProgram(io = {}) {
66520
67499
  }
66521
67500
  writeOut(formatCapletList(rows, options.format ?? "plain"));
66522
67501
  });
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) => {
67502
+ 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
67503
  const remote = remoteClientForCli(io);
66525
67504
  if (remote) {
66526
67505
  if (options.global) writeErr("Warning: --global is not supported in remote mode; the server controls the installation destination.\n");
@@ -66539,7 +67518,7 @@ function createProgram(io = {}) {
66539
67518
  });
66540
67519
  for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${caplet.destination}\n`);
66541
67520
  });
66542
- const add = program.command("add").description("Add generated Caplet files.");
67521
+ const add = program.command(cliCommands.add).description("Add generated Caplet files.");
66543
67522
  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
67523
  const remote = remoteClientForCli(io);
66545
67524
  if (remote) {
@@ -66620,7 +67599,7 @@ function createProgram(io = {}) {
66620
67599
  destinationRoot: addDestinationRoot(options, currentConfigPath())
66621
67600
  }));
66622
67601
  });
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) => {
67602
+ 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
67603
  await executeOperation(caplet, { operation: "get_caplet" }, {
66625
67604
  writeOut,
66626
67605
  writeErr,
@@ -66631,7 +67610,7 @@ function createProgram(io = {}) {
66631
67610
  format: options.format
66632
67611
  });
66633
67612
  });
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) => {
67613
+ 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
67614
  await executeOperation(caplet, { operation: "check_backend" }, {
66636
67615
  writeOut,
66637
67616
  writeErr,
@@ -66642,7 +67621,7 @@ function createProgram(io = {}) {
66642
67621
  format: options.format
66643
67622
  });
66644
67623
  });
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) => {
67624
+ 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
67625
  await executeOperation(caplet, { operation: "list_tools" }, {
66647
67626
  writeOut,
66648
67627
  writeErr,
@@ -66653,7 +67632,7 @@ function createProgram(io = {}) {
66653
67632
  format: options.format
66654
67633
  });
66655
67634
  });
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) => {
67635
+ 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
67636
  await executeOperation(caplet, options.limit === void 0 ? {
66658
67637
  operation: "search_tools",
66659
67638
  query
@@ -66671,7 +67650,7 @@ function createProgram(io = {}) {
66671
67650
  format: options.format
66672
67651
  });
66673
67652
  });
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) => {
67653
+ 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
67654
  const { caplet, tool } = parseQualifiedTarget(target);
66676
67655
  await executeOperation(caplet, {
66677
67656
  operation: "get_tool",
@@ -66686,7 +67665,7 @@ function createProgram(io = {}) {
66686
67665
  format: options.format
66687
67666
  });
66688
67667
  });
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) => {
67668
+ 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
67669
  const { caplet, tool } = parseQualifiedTarget(target);
66691
67670
  await executeOperation(caplet, {
66692
67671
  operation: "call_tool",
@@ -66703,7 +67682,119 @@ function createProgram(io = {}) {
66703
67682
  format: options.format
66704
67683
  });
66705
67684
  });
66706
- const config = program.command("config").description("Inspect Caplets config locations.");
67685
+ 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" } : {
67686
+ operation: "list_resources",
67687
+ limit: options.limit
67688
+ }, {
67689
+ writeOut,
67690
+ writeErr,
67691
+ setExitCode,
67692
+ authDir: io.authDir,
67693
+ env,
67694
+ remote: remoteClientForCli(io),
67695
+ format: options.format
67696
+ }));
67697
+ 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 ? {
67698
+ operation: "search_resources",
67699
+ query
67700
+ } : {
67701
+ operation: "search_resources",
67702
+ query,
67703
+ limit: options.limit
67704
+ }, {
67705
+ writeOut,
67706
+ writeErr,
67707
+ setExitCode,
67708
+ authDir: io.authDir,
67709
+ env,
67710
+ remote: remoteClientForCli(io),
67711
+ format: options.format
67712
+ }));
67713
+ 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" } : {
67714
+ operation: "list_resource_templates",
67715
+ limit: options.limit
67716
+ }, {
67717
+ writeOut,
67718
+ writeErr,
67719
+ setExitCode,
67720
+ authDir: io.authDir,
67721
+ env,
67722
+ remote: remoteClientForCli(io),
67723
+ format: options.format
67724
+ }));
67725
+ 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, {
67726
+ operation: "read_resource",
67727
+ uri
67728
+ }, {
67729
+ writeOut,
67730
+ writeErr,
67731
+ setExitCode,
67732
+ authDir: io.authDir,
67733
+ env,
67734
+ remote: remoteClientForCli(io),
67735
+ format: options.format
67736
+ }));
67737
+ 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" } : {
67738
+ operation: "list_prompts",
67739
+ limit: options.limit
67740
+ }, {
67741
+ writeOut,
67742
+ writeErr,
67743
+ setExitCode,
67744
+ authDir: io.authDir,
67745
+ env,
67746
+ remote: remoteClientForCli(io),
67747
+ format: options.format
67748
+ }));
67749
+ 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 ? {
67750
+ operation: "search_prompts",
67751
+ query
67752
+ } : {
67753
+ operation: "search_prompts",
67754
+ query,
67755
+ limit: options.limit
67756
+ }, {
67757
+ writeOut,
67758
+ writeErr,
67759
+ setExitCode,
67760
+ authDir: io.authDir,
67761
+ env,
67762
+ remote: remoteClientForCli(io),
67763
+ format: options.format
67764
+ }));
67765
+ 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) => {
67766
+ const { caplet, tool: prompt } = parseQualifiedTarget(target);
67767
+ await executeOperation(caplet, {
67768
+ operation: "get_prompt",
67769
+ prompt,
67770
+ arguments: parseJsonObjectOption(options.args, "get-prompt --args")
67771
+ }, {
67772
+ writeOut,
67773
+ writeErr,
67774
+ setExitCode,
67775
+ authDir: io.authDir,
67776
+ env,
67777
+ remote: remoteClientForCli(io),
67778
+ format: options.format
67779
+ });
67780
+ });
67781
+ 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, {
67782
+ operation: "complete",
67783
+ ref: completionRefFromOptions(options),
67784
+ argument: {
67785
+ name: options.argument,
67786
+ value: options.value
67787
+ }
67788
+ }, {
67789
+ writeOut,
67790
+ writeErr,
67791
+ setExitCode,
67792
+ authDir: io.authDir,
67793
+ env,
67794
+ remote: remoteClientForCli(io),
67795
+ format: options.format
67796
+ }));
67797
+ const config = program.command(cliCommands.config).description("Inspect Caplets config locations.");
66707
67798
  config.command("path").description("Print the effective user config path.").action(() => {
66708
67799
  writeOut(`${resolveConfigPath(currentConfigPath())}\n`);
66709
67800
  });
@@ -66715,7 +67806,7 @@ function createProgram(io = {}) {
66715
67806
  }
66716
67807
  writeOut(formatConfigPaths(paths, options.format ?? "plain"));
66717
67808
  });
66718
- const auth = program.command("auth").description("Manage OAuth credentials for remote servers.");
67809
+ const auth = program.command(cliCommands.auth).description("Manage OAuth credentials for remote servers.");
66719
67810
  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
67811
  const remote = remoteClientForCli(io);
66721
67812
  if (remote) {
@@ -66800,7 +67891,15 @@ function remoteCommandForOperation(operation) {
66800
67891
  case "list_tools":
66801
67892
  case "search_tools":
66802
67893
  case "get_tool":
66803
- case "call_tool": return operation;
67894
+ case "call_tool":
67895
+ case "list_resources":
67896
+ case "search_resources":
67897
+ case "list_resource_templates":
67898
+ case "read_resource":
67899
+ case "list_prompts":
67900
+ case "search_prompts":
67901
+ case "get_prompt":
67902
+ case "complete": return operation;
66804
67903
  default: return;
66805
67904
  }
66806
67905
  }
@@ -66848,6 +67947,29 @@ function parseCallToolArgs(value) {
66848
67947
  if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", "call-tool --args must be a JSON object");
66849
67948
  return parsed;
66850
67949
  }
67950
+ function parseJsonObjectOption(value, label) {
67951
+ if (value === void 0) return {};
67952
+ let parsed;
67953
+ try {
67954
+ parsed = JSON.parse(value);
67955
+ } catch (error) {
67956
+ throw new CapletsError("REQUEST_INVALID", `${label} must be valid JSON`, error);
67957
+ }
67958
+ if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", `${label} must be a JSON object`);
67959
+ return parsed;
67960
+ }
67961
+ function completionRefFromOptions(options) {
67962
+ if (options.prompt && options.resourceTemplate) throw new CapletsError("REQUEST_INVALID", "complete accepts either --prompt or --resource-template, not both");
67963
+ if (options.prompt) return {
67964
+ type: "prompt",
67965
+ name: options.prompt
67966
+ };
67967
+ if (options.resourceTemplate) return {
67968
+ type: "resourceTemplate",
67969
+ uri: options.resourceTemplate
67970
+ };
67971
+ throw new CapletsError("REQUEST_INVALID", "complete requires --prompt or --resource-template");
67972
+ }
66851
67973
  function isPlainObject(value) {
66852
67974
  return value !== null && typeof value === "object" && !Array.isArray(value);
66853
67975
  }
@@ -66978,6 +68100,55 @@ function markdownSummaryForOperation(result, request) {
66978
68100
  "",
66979
68101
  "Use `--format json` to inspect the full structured result."
66980
68102
  ].filter((line) => line !== void 0).join("\n");
68103
+ case "list_resources":
68104
+ case "search_resources": {
68105
+ const resources = Array.isArray(payload.resources) ? payload.resources : [];
68106
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68107
+ const matches = Array.isArray(payload.matches) ? payload.matches : [...resources, ...templates];
68108
+ return [
68109
+ `## MCP resources for \`${id}\``,
68110
+ "",
68111
+ `${matches.length} item${matches.length === 1 ? "" : "s"} found.`,
68112
+ "",
68113
+ ...formatResourceLines(matches, "markdown")
68114
+ ].join("\n");
68115
+ }
68116
+ case "list_resource_templates": {
68117
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68118
+ return [
68119
+ `## MCP resource templates for \`${id}\``,
68120
+ "",
68121
+ ...formatResourceLines(templates, "markdown")
68122
+ ].join("\n");
68123
+ }
68124
+ case "read_resource": return [
68125
+ `## Resource \`${String(request.uri ?? "")}\``,
68126
+ "",
68127
+ summarizeResourceRead(payload),
68128
+ "",
68129
+ "Use `--format json` to inspect all contents."
68130
+ ].join("\n");
68131
+ case "list_prompts":
68132
+ case "search_prompts": {
68133
+ const prompts = Array.isArray(payload.prompts) ? payload.prompts : [];
68134
+ return [
68135
+ `## MCP prompts for \`${id}\``,
68136
+ "",
68137
+ ...formatPromptLines(prompts, "markdown")
68138
+ ].join("\n");
68139
+ }
68140
+ case "get_prompt": return [
68141
+ `## Prompt \`${String(request.caplet)}.${String(request.prompt)}\``,
68142
+ "",
68143
+ summarizePromptResult(payload),
68144
+ "",
68145
+ "Use `--format json` to inspect all messages."
68146
+ ].join("\n");
68147
+ case "complete": return [
68148
+ `## Completion for \`${id}\``,
68149
+ "",
68150
+ summarizeCompletionResult(payload)
68151
+ ].join("\n");
66981
68152
  default: return JSON.stringify(payload, null, 2);
66982
68153
  }
66983
68154
  }
@@ -67034,6 +68205,33 @@ function plainSummaryForOperation(result, request) {
67034
68205
  `Result: ${summarizeCallResult(payload)}`,
67035
68206
  "Use --format json to inspect the full structured result."
67036
68207
  ].filter((line) => Boolean(line)).join("\n");
68208
+ case "list_resources":
68209
+ case "search_resources": {
68210
+ const resources = Array.isArray(payload.resources) ? payload.resources : [];
68211
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68212
+ const matches = Array.isArray(payload.matches) ? payload.matches : [...resources, ...templates];
68213
+ return [`MCP resources for ${id} (${matches.length}):`, ...formatResourceLines(matches, "plain")].join("\n");
68214
+ }
68215
+ case "list_resource_templates": {
68216
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
68217
+ return [`MCP resource templates for ${id}:`, ...formatResourceLines(templates, "plain")].join("\n");
68218
+ }
68219
+ case "read_resource": return [
68220
+ `Resource ${String(request.uri ?? "")}`,
68221
+ summarizeResourceRead(payload),
68222
+ "Use --format json to inspect all contents."
68223
+ ].join("\n");
68224
+ case "list_prompts":
68225
+ case "search_prompts": {
68226
+ const prompts = Array.isArray(payload.prompts) ? payload.prompts : [];
68227
+ return [`MCP prompts for ${id}:`, ...formatPromptLines(prompts, "plain")].join("\n");
68228
+ }
68229
+ case "get_prompt": return [
68230
+ `Prompt ${String(request.caplet)}.${String(request.prompt)}`,
68231
+ summarizePromptResult(payload),
68232
+ "Use --format json to inspect all messages."
68233
+ ].join("\n");
68234
+ case "complete": return [`Completion for ${id}`, summarizeCompletionResult(payload)].join("\n");
67037
68235
  default: return JSON.stringify(payload, null, 2);
67038
68236
  }
67039
68237
  }
@@ -67050,6 +68248,44 @@ function formatToolLines(tools, format) {
67050
68248
  return `- ${displayName}${flags ? ` (${flags})` : ""}${tool.description ? ` — ${compactDescription(String(tool.description))}` : ""}`;
67051
68249
  });
67052
68250
  }
68251
+ function formatResourceLines(resources, format) {
68252
+ if (resources.length === 0) return ["- none"];
68253
+ return resources.map((resource) => {
68254
+ if (!isPlainObject(resource)) return `- ${String(resource)}`;
68255
+ const name = String(resource.uri ?? resource.uriTemplate ?? "unknown");
68256
+ const displayName = format === "markdown" ? `\`${name}\`` : name;
68257
+ const label = typeof resource.name === "string" ? ` (${resource.name})` : "";
68258
+ return `- ${typeof resource.kind === "string" ? `${resource.kind}: ` : ""}${displayName}${label}${resource.description ? ` — ${compactDescription(String(resource.description))}` : ""}`;
68259
+ });
68260
+ }
68261
+ function formatPromptLines(prompts, format) {
68262
+ if (prompts.length === 0) return ["- none"];
68263
+ return prompts.map((prompt) => {
68264
+ if (!isPlainObject(prompt)) return `- ${String(prompt)}`;
68265
+ const name = String(prompt.prompt ?? prompt.name ?? "unknown");
68266
+ return `- ${format === "markdown" ? `\`${name}\`` : name}${Array.isArray(prompt.arguments) ? ` (${prompt.arguments.length} args)` : ""}${prompt.description ? ` — ${compactDescription(String(prompt.description))}` : ""}`;
68267
+ });
68268
+ }
68269
+ function summarizeResourceRead(payload) {
68270
+ const contents = Array.isArray(payload.contents) ? payload.contents : [];
68271
+ if (contents.length === 0) return "No contents returned.";
68272
+ const first = contents.find(isPlainObject);
68273
+ if (!first) return `${contents.length} content item${contents.length === 1 ? "" : "s"} returned.`;
68274
+ return previewValue(typeof first.text === "string" ? first.text : first.blob) ?? `${contents.length} content item${contents.length === 1 ? "" : "s"} returned.`;
68275
+ }
68276
+ function summarizePromptResult(payload) {
68277
+ const messages = Array.isArray(payload.messages) ? payload.messages : [];
68278
+ if (messages.length === 0) return "No messages returned.";
68279
+ const first = messages.find(isPlainObject);
68280
+ if (!first) return `${messages.length} message${messages.length === 1 ? "" : "s"} returned.`;
68281
+ return previewValue((isPlainObject(first.content) ? first.content : void 0)?.text ?? first.content) ?? `${messages.length} message${messages.length === 1 ? "" : "s"} returned.`;
68282
+ }
68283
+ function summarizeCompletionResult(payload) {
68284
+ const completion = isPlainObject(payload.completion) ? payload.completion : void 0;
68285
+ const values = Array.isArray(completion?.values) ? completion.values : [];
68286
+ if (values.length > 0) return values.map((value) => `- ${String(value)}`).join("\n");
68287
+ return previewValue(payload) ?? "No completions returned.";
68288
+ }
67053
68289
  function compactDescription(value) {
67054
68290
  const firstParagraph = value.trim().split(/\n\s*\n/u)[0] ?? "";
67055
68291
  const collapsed = (firstParagraph.match(/^.*?(?:[.!?](?=\s|$)|$)/u)?.[0] ?? firstParagraph).replace(/\s+/gu, " ").trim();
@@ -67124,7 +68360,7 @@ function writeAddResult(writeOut, label, result) {
67124
68360
  }
67125
68361
  //#endregion
67126
68362
  //#region package.json
67127
- var version = "0.16.0";
68363
+ var version = "0.17.0";
67128
68364
  //#endregion
67129
68365
  //#region src/index.ts
67130
68366
  async function main() {