@caplets/core 0.16.0 → 0.18.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.
@@ -0,0 +1,560 @@
1
+ import { Ct as resolveProjectConfigPath, Mt as __exportAll, Ot as CapletsError, St as resolveProjectCapletsRoot, bt as resolveCapletsRoot, gt as loadConfigWithSources, vt as DEFAULT_AUTH_DIR, xt as resolveConfigPath, yt as DEFAULT_COMPLETION_CACHE_DIR } from "./options-DM1cMRcp.js";
2
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ //#region src/cli/commands.ts
6
+ const completionShells = [
7
+ "bash",
8
+ "zsh",
9
+ "fish",
10
+ "powershell",
11
+ "cmd"
12
+ ];
13
+ const cliCommands = {
14
+ completion: "completion",
15
+ completeHidden: "__complete",
16
+ serve: "serve",
17
+ init: "init",
18
+ list: "list",
19
+ install: "install",
20
+ add: "add",
21
+ getCaplet: "get-caplet",
22
+ checkBackend: "check-backend",
23
+ listTools: "list-tools",
24
+ searchTools: "search-tools",
25
+ getTool: "get-tool",
26
+ callTool: "call-tool",
27
+ listResources: "list-resources",
28
+ searchResources: "search-resources",
29
+ listResourceTemplates: "list-resource-templates",
30
+ readResource: "read-resource",
31
+ listPrompts: "list-prompts",
32
+ searchPrompts: "search-prompts",
33
+ getPrompt: "get-prompt",
34
+ complete: "complete",
35
+ config: "config",
36
+ auth: "auth"
37
+ };
38
+ const topLevelCommandNames = [
39
+ cliCommands.serve,
40
+ cliCommands.init,
41
+ cliCommands.list,
42
+ cliCommands.install,
43
+ cliCommands.add,
44
+ cliCommands.getCaplet,
45
+ cliCommands.checkBackend,
46
+ cliCommands.listTools,
47
+ cliCommands.searchTools,
48
+ cliCommands.getTool,
49
+ cliCommands.callTool,
50
+ cliCommands.listResources,
51
+ cliCommands.searchResources,
52
+ cliCommands.listResourceTemplates,
53
+ cliCommands.readResource,
54
+ cliCommands.listPrompts,
55
+ cliCommands.searchPrompts,
56
+ cliCommands.getPrompt,
57
+ cliCommands.complete,
58
+ cliCommands.config,
59
+ cliCommands.auth,
60
+ cliCommands.completion
61
+ ];
62
+ const cliSubcommands = {
63
+ [cliCommands.add]: [
64
+ "cli",
65
+ "mcp",
66
+ "openapi",
67
+ "graphql",
68
+ "http"
69
+ ],
70
+ [cliCommands.auth]: [
71
+ "login",
72
+ "logout",
73
+ "list"
74
+ ],
75
+ [cliCommands.completion]: [...completionShells],
76
+ [cliCommands.config]: ["path", "paths"]
77
+ };
78
+ const capletIdCommands = new Set([
79
+ cliCommands.getCaplet,
80
+ cliCommands.checkBackend,
81
+ cliCommands.listTools,
82
+ cliCommands.searchTools,
83
+ cliCommands.listResources,
84
+ cliCommands.searchResources,
85
+ cliCommands.listResourceTemplates,
86
+ cliCommands.readResource,
87
+ cliCommands.listPrompts,
88
+ cliCommands.searchPrompts,
89
+ cliCommands.complete
90
+ ]);
91
+ const qualifiedToolCommands = new Set([cliCommands.getTool, cliCommands.callTool]);
92
+ const qualifiedPromptCommands = new Set([cliCommands.getPrompt]);
93
+ //#endregion
94
+ //#region src/cli/inspection.ts
95
+ function listCaplets(configWithSources, options) {
96
+ const { config, sources, shadows } = configWithSources;
97
+ return allCaplets(config).filter((server) => options.includeDisabled || !server.disabled).map((server) => ({
98
+ server: server.server,
99
+ backend: server.backend,
100
+ name: server.name,
101
+ description: server.description,
102
+ disabled: server.disabled,
103
+ status: initialServerStatus(server),
104
+ source: sources[server.server]?.kind ?? "unknown",
105
+ path: sources[server.server]?.path ?? null,
106
+ shadows: shadows[server.server] ?? []
107
+ })).sort((left, right) => left.server.localeCompare(right.server));
108
+ }
109
+ function initialServerStatus(server) {
110
+ return server.disabled ? "disabled" : "not_started";
111
+ }
112
+ function allCaplets(config) {
113
+ return [
114
+ ...Object.values(config.mcpServers),
115
+ ...Object.values(config.openapiEndpoints),
116
+ ...Object.values(config.graphqlEndpoints),
117
+ ...Object.values(config.httpApis),
118
+ ...Object.values(config.cliTools)
119
+ ];
120
+ }
121
+ function formatCapletList(rows, format = "plain") {
122
+ return format === "markdown" ? formatCapletListMarkdown(rows) : formatCapletListPlain(rows);
123
+ }
124
+ function formatCapletListMarkdown(rows) {
125
+ if (rows.length === 0) return "## Configured Caplets\n\nNo configured Caplets found.\n";
126
+ const heading = [
127
+ "## Configured Caplets",
128
+ "",
129
+ `${rows.length} ${rows.length === 1 ? "Caplet" : "Caplets"} shown.`,
130
+ ""
131
+ ];
132
+ const entries = rows.flatMap((row) => [
133
+ `- \`${row.server}\` — ${row.name}`,
134
+ ` - Backend: ${row.backend}`,
135
+ ` - Status: ${row.status}`,
136
+ ` - Source: ${row.source}`,
137
+ ...row.disabled ? [" - Disabled: true"] : [],
138
+ ...row.path ? [` - Path: ${row.path}`] : []
139
+ ]);
140
+ const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
141
+ if (warnings.length === 0) return `${[...heading, ...entries].join("\n")}\n`;
142
+ return `${[
143
+ ...heading,
144
+ ...entries,
145
+ "",
146
+ "Warnings:",
147
+ ...warnings.map((warning) => `- ${warning}`)
148
+ ].join("\n")}\n`;
149
+ }
150
+ function formatCapletListPlain(rows) {
151
+ if (rows.length === 0) return "No configured Caplets found.\n";
152
+ const entries = rows.map((row) => [
153
+ row.server,
154
+ ` Name: ${row.name}`,
155
+ ` Backend: ${row.backend}`,
156
+ ` Status: ${row.status}`,
157
+ ` Source: ${row.source}`,
158
+ ...row.disabled ? [" Disabled: true"] : [],
159
+ ...row.path ? [` Path: ${row.path}`] : []
160
+ ].join("\n")).join("\n\n");
161
+ const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
162
+ if (warnings.length === 0) return `Configured Caplets (${rows.length})\n\n${entries}\n`;
163
+ return `Configured Caplets (${rows.length})\n\n${entries}\n\n${warnings.join("\n")}\n`;
164
+ }
165
+ function formatSourceKind(kind) {
166
+ if (kind.startsWith("project")) return "project";
167
+ if (kind.startsWith("global")) return "global";
168
+ return kind;
169
+ }
170
+ function resolveCliConfigPaths(envConfigPath, authDir) {
171
+ const configPath = resolveConfigPath(envConfigPath);
172
+ const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
173
+ return {
174
+ userConfig: configPath,
175
+ projectConfig: resolveProjectConfigPath(),
176
+ userRoot: resolveCapletsRoot(configPath),
177
+ stateRoot: dirname(effectiveAuthDir),
178
+ projectRoot: resolveProjectCapletsRoot(),
179
+ authDir: effectiveAuthDir,
180
+ envConfig: envConfigPath ?? null
181
+ };
182
+ }
183
+ function formatConfigPaths(paths, format = "plain") {
184
+ if (format === "markdown") return formatConfigPathsMarkdown(paths);
185
+ return formatConfigPathsPlain(paths);
186
+ }
187
+ function formatConfigPathsMarkdown(paths) {
188
+ return [
189
+ "## Caplets paths",
190
+ "",
191
+ `- User config: ${paths.userConfig}`,
192
+ `- Project config: ${paths.projectConfig}`,
193
+ `- User Caplets root: ${paths.userRoot}`,
194
+ `- State root: ${paths.stateRoot}`,
195
+ `- Project Caplets root: ${paths.projectRoot}`,
196
+ `- Auth directory: ${paths.authDir}`,
197
+ `- CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
198
+ ].join("\n") + "\n";
199
+ }
200
+ function formatConfigPathsPlain(paths) {
201
+ return [
202
+ "Caplets paths",
203
+ "",
204
+ `User config: ${paths.userConfig}`,
205
+ `Project config: ${paths.projectConfig}`,
206
+ `User root: ${paths.userRoot}`,
207
+ `State root: ${paths.stateRoot}`,
208
+ `Project root: ${paths.projectRoot}`,
209
+ `Auth directory: ${paths.authDir}`,
210
+ `CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
211
+ ].join("\n") + "\n";
212
+ }
213
+ //#endregion
214
+ //#region src/cli/completion-cache.ts
215
+ function completionCacheKey(input) {
216
+ return createHash("sha256").update(JSON.stringify(input)).digest("hex");
217
+ }
218
+ function readCompletionCacheEntry(cacheDir, key, now = Date.now()) {
219
+ try {
220
+ const parsed = JSON.parse(readFileSync(cachePath(cacheDir, key), "utf8"));
221
+ if (parsed.status === "positive" && Array.isArray(parsed.candidates)) return {
222
+ ...parsed,
223
+ fresh: now <= parsed.expiresAt
224
+ };
225
+ if (parsed.status === "negative" && typeof parsed.reason === "string") return {
226
+ ...parsed,
227
+ fresh: now <= parsed.expiresAt
228
+ };
229
+ } catch {
230
+ return;
231
+ }
232
+ }
233
+ function writeCompletionCacheEntry(cacheDir, key, entry) {
234
+ mkdirSync(cacheDir, { recursive: true });
235
+ const path = cachePath(cacheDir, key);
236
+ const tempPath = `${path}.${process.pid}.tmp`;
237
+ writeFileSync(tempPath, JSON.stringify(entry), { mode: 384 });
238
+ renameSync(tempPath, path);
239
+ }
240
+ function cachePath(cacheDir, key) {
241
+ return join(cacheDir, `${key}.json`);
242
+ }
243
+ //#endregion
244
+ //#region src/cli/completion-discovery.ts
245
+ async function discoverCompletionCandidates(serverId, kind, options) {
246
+ const server = enabledServer(serverId, options.config);
247
+ if (!server) return [];
248
+ const completion = options.completion ?? options.config.options.completion;
249
+ const now = options.now ?? Date.now();
250
+ const configCandidates = configDefinedCandidates(serverId, kind, options.config);
251
+ const cacheDir = options.cacheDir ?? DEFAULT_COMPLETION_CACHE_DIR;
252
+ const key = completionCacheKey({
253
+ server: server.server,
254
+ backend: server.backend,
255
+ kind,
256
+ fingerprint: completionFingerprint(server, kind, completion)
257
+ });
258
+ const cached = readCompletionCacheEntry(cacheDir, key, now);
259
+ if (cached?.status === "positive" && cached.fresh) return cached.candidates;
260
+ if (cached?.status === "negative" && cached.fresh) return cached.candidates ?? configCandidates;
261
+ try {
262
+ const live = await withTimeout(liveCandidates(server, kind, options.managers), Math.min(completion.discoveryTimeoutMs, completion.overallTimeoutMs));
263
+ const candidates = dedupeCandidates([...configCandidates, ...live]);
264
+ writeCompletionCacheEntry(cacheDir, key, {
265
+ status: "positive",
266
+ fetchedAt: now,
267
+ expiresAt: now + completion.cacheTtlMs,
268
+ candidates
269
+ });
270
+ return candidates;
271
+ } catch (error) {
272
+ writeCompletionCacheEntry(cacheDir, key, {
273
+ status: "negative",
274
+ fetchedAt: now,
275
+ expiresAt: now + completion.negativeCacheTtlMs,
276
+ reason: negativeReason(error),
277
+ ...cached?.status === "positive" ? { candidates: cached.candidates } : {}
278
+ });
279
+ if (cached?.status === "positive") return cached.candidates;
280
+ return configCandidates;
281
+ }
282
+ }
283
+ function configDefinedCandidates(serverId, kind, config) {
284
+ if (kind !== "tools") return [];
285
+ const cli = config.cliTools[serverId];
286
+ if (cli && !cli.disabled) return Object.keys(cli.actions).map((name) => ({ value: `${serverId}.${name}` }));
287
+ const http = config.httpApis[serverId];
288
+ if (http && !http.disabled) return Object.keys(http.actions).map((name) => ({ value: `${serverId}.${name}` }));
289
+ const graphql = config.graphqlEndpoints[serverId];
290
+ if (graphql && !graphql.disabled && graphql.operations) return Object.keys(graphql.operations).map((name) => ({ value: `${serverId}.${name}` }));
291
+ return [];
292
+ }
293
+ async function liveCandidates(server, kind, managers) {
294
+ if (kind === "tools" && managers?.listTools) return (await managers.listTools(server)).map((tool) => ({
295
+ value: `${server.server}.${tool.name}`,
296
+ description: tool.description
297
+ }));
298
+ if (kind === "tools") return [];
299
+ if (server.backend !== "mcp") return [];
300
+ if (kind === "prompts" && managers?.listPrompts) return (await managers.listPrompts(server)).map((prompt) => ({
301
+ value: `${server.server}.${prompt.name}`,
302
+ description: prompt.description
303
+ }));
304
+ if (kind === "resources" && managers?.listResources) return (await managers.listResources(server)).map((resource) => ({
305
+ value: resource.uri,
306
+ label: resource.name,
307
+ description: resource.description
308
+ }));
309
+ if (kind === "resourceTemplates" && managers?.listResourceTemplates) return (await managers.listResourceTemplates(server)).map((template) => ({
310
+ value: template.uriTemplate,
311
+ label: template.name,
312
+ description: template.description
313
+ }));
314
+ throw new CapletsError("UNSUPPORTED_CAPABILITY", `Completion discovery is unsupported for ${kind}`);
315
+ }
316
+ function completionFingerprint(server, kind, completion) {
317
+ return JSON.stringify({
318
+ kind,
319
+ completion: {
320
+ discoveryTimeoutMs: completion.discoveryTimeoutMs,
321
+ cacheTtlMs: completion.cacheTtlMs,
322
+ negativeCacheTtlMs: completion.negativeCacheTtlMs
323
+ },
324
+ server: secretFreeServerShape(server)
325
+ });
326
+ }
327
+ function secretFreeServerShape(server) {
328
+ const base = {
329
+ server: server.server,
330
+ backend: server.backend,
331
+ name: server.name,
332
+ description: server.description,
333
+ tags: server.tags,
334
+ disabled: server.disabled
335
+ };
336
+ switch (server.backend) {
337
+ case "mcp": return {
338
+ ...base,
339
+ transport: server.transport,
340
+ command: server.command,
341
+ args: server.args,
342
+ cwd: server.cwd,
343
+ url: server.url,
344
+ authType: server.auth?.type,
345
+ startupTimeoutMs: server.startupTimeoutMs,
346
+ callTimeoutMs: server.callTimeoutMs
347
+ };
348
+ case "openapi": return {
349
+ ...base,
350
+ specPath: server.specPath,
351
+ specUrl: server.specUrl,
352
+ baseUrl: server.baseUrl,
353
+ authType: server.auth.type,
354
+ requestTimeoutMs: server.requestTimeoutMs
355
+ };
356
+ case "graphql": return {
357
+ ...base,
358
+ endpointUrl: server.endpointUrl,
359
+ schemaPath: server.schemaPath,
360
+ schemaUrl: server.schemaUrl,
361
+ authType: server.auth.type,
362
+ operationNames: server.operations ? Object.keys(server.operations) : void 0
363
+ };
364
+ case "http": return {
365
+ ...base,
366
+ baseUrl: server.baseUrl,
367
+ authType: server.auth.type,
368
+ actions: Object.fromEntries(Object.entries(server.actions).map(([name, action]) => [name, {
369
+ method: action.method,
370
+ path: action.path
371
+ }])),
372
+ requestTimeoutMs: server.requestTimeoutMs
373
+ };
374
+ case "cli": return {
375
+ ...base,
376
+ cwd: server.cwd,
377
+ actions: Object.fromEntries(Object.entries(server.actions).map(([name, action]) => [name, {
378
+ command: action.command,
379
+ args: action.args,
380
+ cwd: action.cwd
381
+ }])),
382
+ timeoutMs: server.timeoutMs,
383
+ maxOutputBytes: server.maxOutputBytes
384
+ };
385
+ case "caplets": return {
386
+ ...base,
387
+ configPath: server.configPath,
388
+ capletsRoot: server.capletsRoot,
389
+ defaultSearchLimit: server.defaultSearchLimit,
390
+ maxSearchLimit: server.maxSearchLimit
391
+ };
392
+ }
393
+ }
394
+ function negativeReason(error) {
395
+ if (error instanceof CapletsError) {
396
+ if (error.code === "AUTH_REQUIRED" || error.code === "AUTH_FAILED" || error.code === "AUTH_REFRESH_FAILED") return "auth_required";
397
+ if (error.code === "SERVER_UNAVAILABLE" || error.code === "SERVER_START_TIMEOUT") return "unavailable";
398
+ if (error.code === "UNSUPPORTED_CAPABILITY" || error.code === "UNSUPPORTED_OPERATION") return "unsupported";
399
+ if (error.code === "TOOL_CALL_TIMEOUT" || error.code === "DOWNSTREAM_COMPLETION_ERROR") return "timeout";
400
+ }
401
+ return error instanceof Error && error.message.includes("timeout") ? "timeout" : "error";
402
+ }
403
+ async function withTimeout(promise, timeoutMs) {
404
+ let timeout;
405
+ try {
406
+ return await Promise.race([promise, new Promise((_, reject) => {
407
+ timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("completion discovery timeout")), timeoutMs);
408
+ })]);
409
+ } finally {
410
+ if (timeout) clearTimeout(timeout);
411
+ }
412
+ }
413
+ function enabledServer(serverId, config) {
414
+ const server = config.mcpServers[serverId] ?? config.openapiEndpoints[serverId] ?? config.graphqlEndpoints[serverId] ?? config.httpApis[serverId] ?? config.cliTools[serverId] ?? config.capletSets[serverId];
415
+ return server && !server.disabled ? server : void 0;
416
+ }
417
+ function dedupeCandidates(candidates) {
418
+ const seen = /* @__PURE__ */ new Set();
419
+ return candidates.filter((candidate) => {
420
+ if (seen.has(candidate.value)) return false;
421
+ seen.add(candidate.value);
422
+ return true;
423
+ });
424
+ }
425
+ //#endregion
426
+ //#region src/cli/completion.ts
427
+ var completion_exports = /* @__PURE__ */ __exportAll({
428
+ completeCliWords: () => completeCliWords,
429
+ completionScript: () => completionScript,
430
+ trailingSpaceCompletionToken: () => trailingSpaceCompletionToken
431
+ });
432
+ const trailingSpaceCompletionToken = "__CAPLETS_TRAILING_SPACE__";
433
+ const optionValueSuggestions = {
434
+ "*": { "--format": [
435
+ "markdown",
436
+ "md",
437
+ "plain",
438
+ "json"
439
+ ] },
440
+ serve: { "--transport": ["stdio", "http"] },
441
+ "add:mcp": { "--transport": ["http", "sse"] },
442
+ "add:cli": { "--include": [
443
+ "git",
444
+ "gh",
445
+ "package"
446
+ ] }
447
+ };
448
+ function completionScript(shell) {
449
+ switch (shell) {
450
+ case "bash": return bashCompletionScript();
451
+ case "zsh": return zshCompletionScript();
452
+ case "fish": return fishCompletionScript();
453
+ case "powershell": return powershellCompletionScript();
454
+ case "cmd": return cmdCompletionScript();
455
+ default: throw new CapletsError("REQUEST_INVALID", "completion shell must be bash, zsh, fish, powershell, or cmd");
456
+ }
457
+ }
458
+ async function completeCliWords(words, options = {}) {
459
+ try {
460
+ const normalized = words.length === 0 ? [""] : words;
461
+ const current = normalized.at(-1) ?? "";
462
+ const previous = normalized.at(-2);
463
+ const command = normalized[0] ?? "";
464
+ const subcommand = normalized[1] ?? "";
465
+ if (command === cliCommands.complete && previous === "--prompt" && subcommand) return prefixFilter((await discoverCompletionCandidates(subcommand, "prompts", discoveryOptions(options))).map((candidate) => candidate.value.replace(`${subcommand}.`, "")), current);
466
+ if (command === cliCommands.complete && previous === "--resource-template" && subcommand) return prefixFilter((await discoverCompletionCandidates(subcommand, "resourceTemplates", discoveryOptions(options))).map((candidate) => candidate.value), current);
467
+ const optionValues = suggestionsForOptionValue(command, subcommand, previous);
468
+ if (optionValues) return prefixFilter(optionValues, current);
469
+ if (normalized.length === 1) return prefixFilter([...topLevelCommandNames], current);
470
+ if (normalized.length === 2 && command in cliSubcommands) return prefixFilter(cliSubcommands[command], current);
471
+ if (normalized.length === 2 && capletIdCommands.has(command)) return prefixFilter(promptResourceCommands.has(command) ? configuredCapletIds(options, { backend: "mcp" }) : configuredCapletIds(options), current);
472
+ if (normalized.length === 2 && (qualifiedToolCommands.has(command) || qualifiedPromptCommands.has(command))) {
473
+ if (current.includes(".")) return prefixFilter((await discoverCompletionCandidates(current.slice(0, current.indexOf(".")), qualifiedToolCommands.has(command) ? "tools" : "prompts", discoveryOptions(options))).map((candidate) => candidate.value), current);
474
+ return prefixFilter(configuredCapletIds(options, qualifiedPromptCommands.has(command) ? { backend: "mcp" } : void 0).map((id) => `${id}.`), current);
475
+ }
476
+ if (command === cliCommands.readResource && normalized.length === 3) return prefixFilter((await discoverCompletionCandidates(subcommand, "resources", discoveryOptions(options))).map((candidate) => candidate.value), current);
477
+ if (command === cliCommands.auth && ["login", "logout"].includes(subcommand) && normalized.length === 3) return prefixFilter(configuredCapletIds(options), current);
478
+ return [];
479
+ } catch {
480
+ return [];
481
+ }
482
+ }
483
+ function suggestionsForOptionValue(command, subcommand, previous) {
484
+ if (!previous) return void 0;
485
+ return optionValueSuggestions[`${command}:${subcommand}`]?.[previous] ?? optionValueSuggestions[command]?.[previous] ?? optionValueSuggestions["*"]?.[previous];
486
+ }
487
+ const promptResourceCommands = new Set([
488
+ cliCommands.getPrompt,
489
+ cliCommands.readResource,
490
+ cliCommands.complete
491
+ ]);
492
+ function configuredCapletIds(options, filter = {}) {
493
+ return listCaplets(options.config ? {
494
+ config: options.config,
495
+ sources: {},
496
+ shadows: {}
497
+ } : loadConfigWithSources(options.configPath, options.projectConfigPath), { includeDisabled: false }).filter((row) => !filter.backend || row.backend === filter.backend).map((row) => row.server);
498
+ }
499
+ function discoveryOptions(options) {
500
+ return {
501
+ config: options.config ?? loadConfigWithSources(options.configPath, options.projectConfigPath).config,
502
+ completion: options.completion,
503
+ cacheDir: options.cacheDir,
504
+ managers: options.managers
505
+ };
506
+ }
507
+ function prefixFilter(values, prefix) {
508
+ return values.filter((value) => value.startsWith(prefix));
509
+ }
510
+ function bashCompletionScript() {
511
+ return `# caplets bash completion
512
+ _caplets_completions() {
513
+ local IFS=$'\n'
514
+ COMPREPLY=( $(caplets __complete --shell bash -- "\${COMP_WORDS[@]:1}" 2>/dev/null) )
515
+ }
516
+ complete -o default -F _caplets_completions caplets
517
+ `;
518
+ }
519
+ function zshCompletionScript() {
520
+ return `#compdef caplets
521
+ _caplets() {
522
+ local -a suggestions
523
+ suggestions=("\${(@f)$(caplets __complete --shell zsh -- "\${words[@]:1}" 2>/dev/null)}")
524
+ compadd -- $suggestions
525
+ }
526
+ _caplets "$@"
527
+ `;
528
+ }
529
+ function fishCompletionScript() {
530
+ return `# caplets fish completion
531
+ function __caplets_complete
532
+ set -l tokens (commandline -opc)
533
+ set -l current (commandline -ct)
534
+ caplets __complete --shell fish -- $tokens[2..-1] $current 2>/dev/null
535
+ end
536
+ complete -c caplets -f -a '(__caplets_complete)'
537
+ `;
538
+ }
539
+ function powershellCompletionScript() {
540
+ return `# caplets PowerShell completion
541
+ Register-ArgumentCompleter -Native -CommandName caplets -ScriptBlock {
542
+ param($wordToComplete, $commandAst, $cursorPosition)
543
+ $tokens = @($commandAst.CommandElements | Select-Object -Skip 1 | ForEach-Object { $_.ToString() })
544
+ if ($tokens.Count -eq 0 -or $commandAst.Extent.Text.EndsWith(' ')) { $tokens += '${trailingSpaceCompletionToken}' }
545
+ caplets __complete --shell powershell -- @tokens 2>$null | ForEach-Object {
546
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
547
+ }
548
+ }
549
+ `;
550
+ }
551
+ function cmdCompletionScript() {
552
+ return `@echo off
553
+ REM caplets cmd completion helper
554
+ REM cmd.exe has no native programmable completion API. This doskey macro prints suggestions for the current words.
555
+ doskey caplets-complete=caplets __complete --shell cmd -- $* 2^>nul
556
+ REM Usage: caplets-complete get-caplet
557
+ `;
558
+ }
559
+ //#endregion
560
+ export { formatCapletList as a, resolveCliConfigPaths as c, trailingSpaceCompletionToken as i, cliCommands as l, completionScript as n, formatConfigPaths as o, completion_exports as r, listCaplets as s, completeCliWords as t, completionShells as u };
@@ -2,10 +2,13 @@ type Platform = NodeJS.Platform;
2
2
  type PathEnv = NodeJS.ProcessEnv;
3
3
  export declare function defaultConfigBaseDir(env?: PathEnv, home?: string, platform?: Platform): string;
4
4
  export declare function defaultStateBaseDir(env?: PathEnv, home?: string, platform?: Platform): string;
5
+ export declare function defaultCacheBaseDir(env?: PathEnv, home?: string, platform?: Platform): string;
5
6
  export declare function defaultConfigPath(env?: PathEnv, home?: string, platform?: Platform): string;
6
7
  export declare function defaultAuthDir(env?: PathEnv, home?: string, platform?: Platform): string;
8
+ export declare function defaultCompletionCacheDir(env?: PathEnv, home?: string, platform?: Platform): string;
7
9
  export declare const DEFAULT_CONFIG_PATH: string;
8
10
  export declare const DEFAULT_AUTH_DIR: string;
11
+ export declare const DEFAULT_COMPLETION_CACHE_DIR: string;
9
12
  export declare const PROJECT_CONFIG_FILE: string;
10
13
  export declare function resolveConfigPath(path?: string): string;
11
14
  export declare function resolveProjectConfigPath(cwd?: string): string;
package/dist/config.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- export { DEFAULT_AUTH_DIR, DEFAULT_CONFIG_PATH, PROJECT_CONFIG_FILE, resolveCapletsRoot, resolveConfigPath, resolveProjectCapletsRoot, resolveProjectConfigPath, } from "./config/paths";
2
+ export { DEFAULT_AUTH_DIR, DEFAULT_COMPLETION_CACHE_DIR, DEFAULT_CONFIG_PATH, PROJECT_CONFIG_FILE, defaultCacheBaseDir, defaultCompletionCacheDir, resolveCapletsRoot, resolveConfigPath, resolveProjectCapletsRoot, resolveProjectConfigPath, } from "./config/paths";
3
3
  export type RemoteAuthConfig = {
4
4
  type: "none";
5
5
  } | {
@@ -181,6 +181,13 @@ export type CapletConfig = CapletServerConfig | OpenApiEndpointConfig | GraphQlE
181
181
  export type CapletsOptions = {
182
182
  defaultSearchLimit: number;
183
183
  maxSearchLimit: number;
184
+ completion: CompletionConfig;
185
+ };
186
+ export type CompletionConfig = {
187
+ discoveryTimeoutMs: number;
188
+ overallTimeoutMs: number;
189
+ cacheTtlMs: number;
190
+ negativeCacheTtlMs: number;
184
191
  };
185
192
  export type CapletsConfig = {
186
193
  version: 1;
@@ -207,6 +214,12 @@ export declare const configFileSchema: z.ZodObject<{
207
214
  version: z.ZodDefault<z.ZodLiteral<1>>;
208
215
  defaultSearchLimit: z.ZodDefault<z.ZodNumber>;
209
216
  maxSearchLimit: z.ZodDefault<z.ZodNumber>;
217
+ completion: z.ZodDefault<z.ZodObject<{
218
+ discoveryTimeoutMs: z.ZodDefault<z.ZodNumber>;
219
+ overallTimeoutMs: z.ZodDefault<z.ZodNumber>;
220
+ cacheTtlMs: z.ZodDefault<z.ZodNumber>;
221
+ negativeCacheTtlMs: z.ZodDefault<z.ZodNumber>;
222
+ }, z.core.$strict>>;
210
223
  mcpServers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
211
224
  openapiEndpoints: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
212
225
  graphqlEndpoints: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;