@caplets/core 0.17.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ export declare const completionShells: readonly ["bash", "zsh", "fish", "powershell", "cmd"];
2
+ export type CompletionShell = (typeof completionShells)[number];
3
+ export declare const cliCommands: {
4
+ readonly completion: "completion";
5
+ readonly completeHidden: "__complete";
6
+ readonly serve: "serve";
7
+ readonly init: "init";
8
+ readonly list: "list";
9
+ readonly install: "install";
10
+ readonly add: "add";
11
+ readonly getCaplet: "get-caplet";
12
+ readonly checkBackend: "check-backend";
13
+ readonly listTools: "list-tools";
14
+ readonly searchTools: "search-tools";
15
+ readonly getTool: "get-tool";
16
+ readonly callTool: "call-tool";
17
+ readonly listResources: "list-resources";
18
+ readonly searchResources: "search-resources";
19
+ readonly listResourceTemplates: "list-resource-templates";
20
+ readonly readResource: "read-resource";
21
+ readonly listPrompts: "list-prompts";
22
+ readonly searchPrompts: "search-prompts";
23
+ readonly getPrompt: "get-prompt";
24
+ readonly complete: "complete";
25
+ readonly config: "config";
26
+ readonly auth: "auth";
27
+ };
28
+ export declare const topLevelCommandNames: readonly ["serve", "init", "list", "install", "add", "get-caplet", "check-backend", "list-tools", "search-tools", "get-tool", "call-tool", "list-resources", "search-resources", "list-resource-templates", "read-resource", "list-prompts", "search-prompts", "get-prompt", "complete", "config", "auth", "completion"];
29
+ export declare const cliSubcommands: {
30
+ readonly add: readonly ["cli", "mcp", "openapi", "graphql", "http"];
31
+ readonly auth: readonly ["login", "logout", "list"];
32
+ readonly completion: readonly ["bash", "zsh", "fish", "powershell", "cmd"];
33
+ readonly config: readonly ["path", "paths"];
34
+ };
35
+ export declare const capletIdCommands: Set<string>;
36
+ export declare const qualifiedToolCommands: Set<string>;
37
+ export declare const qualifiedPromptCommands: Set<string>;
@@ -0,0 +1,30 @@
1
+ export type CompletionDiscoveryKind = "tools" | "prompts" | "resources" | "resourceTemplates";
2
+ export type CompletionCandidate = {
3
+ value: string;
4
+ label?: string | undefined;
5
+ description?: string | undefined;
6
+ };
7
+ export type CompletionCacheKeyInput = {
8
+ server: string;
9
+ backend: string;
10
+ kind: CompletionDiscoveryKind;
11
+ fingerprint: string;
12
+ };
13
+ export type CompletionCacheEntry = {
14
+ status: "positive";
15
+ fetchedAt: number;
16
+ expiresAt: number;
17
+ candidates: CompletionCandidate[];
18
+ } | {
19
+ status: "negative";
20
+ fetchedAt: number;
21
+ expiresAt: number;
22
+ reason: "auth_required" | "timeout" | "unavailable" | "unsupported" | "error";
23
+ candidates?: CompletionCandidate[];
24
+ };
25
+ export type ReadCompletionCacheEntry = CompletionCacheEntry & {
26
+ fresh: boolean;
27
+ };
28
+ export declare function completionCacheKey(input: CompletionCacheKeyInput): string;
29
+ export declare function readCompletionCacheEntry(cacheDir: string, key: string, now?: number): ReadCompletionCacheEntry | undefined;
30
+ export declare function writeCompletionCacheEntry(cacheDir: string, key: string, entry: CompletionCacheEntry): void;
@@ -0,0 +1,30 @@
1
+ import { type CapletConfig, type CapletsConfig, type CompletionConfig } from "../config";
2
+ import { type CompletionCandidate, type CompletionDiscoveryKind } from "./completion-cache";
3
+ export type CompletionDiscoveryManagers = {
4
+ listTools?: (server: CapletConfig) => Promise<Array<{
5
+ name: string;
6
+ description?: string;
7
+ }>>;
8
+ listPrompts?: (server: CapletConfig) => Promise<Array<{
9
+ name: string;
10
+ description?: string;
11
+ }>>;
12
+ listResources?: (server: CapletConfig) => Promise<Array<{
13
+ uri: string;
14
+ name?: string;
15
+ description?: string;
16
+ }>>;
17
+ listResourceTemplates?: (server: CapletConfig) => Promise<Array<{
18
+ uriTemplate: string;
19
+ name?: string;
20
+ description?: string;
21
+ }>>;
22
+ };
23
+ export type CompletionDiscoveryOptions = {
24
+ config: CapletsConfig;
25
+ completion?: CompletionConfig | undefined;
26
+ cacheDir?: string | undefined;
27
+ managers?: CompletionDiscoveryManagers | undefined;
28
+ now?: number | undefined;
29
+ };
30
+ export declare function discoverCompletionCandidates(serverId: string, kind: CompletionDiscoveryKind, options: CompletionDiscoveryOptions): Promise<CompletionCandidate[]>;
@@ -0,0 +1,15 @@
1
+ import { type CapletsConfig, type CompletionConfig } from "../config";
2
+ import { type CompletionShell } from "./commands";
3
+ import { type CompletionDiscoveryManagers } from "./completion-discovery";
4
+ export { completionShells, type CompletionShell } from "./commands";
5
+ export declare const trailingSpaceCompletionToken = "__CAPLETS_TRAILING_SPACE__";
6
+ export type CompletionOptions = {
7
+ configPath?: string;
8
+ projectConfigPath?: string;
9
+ config?: CapletsConfig;
10
+ completion?: CompletionConfig;
11
+ cacheDir?: string;
12
+ managers?: CompletionDiscoveryManagers;
13
+ };
14
+ export declare function completionScript(shell: CompletionShell): string;
15
+ export declare function completeCliWords(words: string[], options?: CompletionOptions): Promise<string[]>;
@@ -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-BqibJVxq.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;