@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.
- package/dist/auth.d.ts +14 -0
- package/dist/cli/auth.d.ts +24 -0
- package/dist/cli/commands.d.ts +37 -0
- package/dist/cli/completion-cache.d.ts +30 -0
- package/dist/cli/completion-discovery.d.ts +30 -0
- package/dist/cli/completion.d.ts +15 -0
- package/dist/cli.d.ts +2 -0
- package/dist/completion-CxGG6ae3.js +560 -0
- package/dist/config/paths.d.ts +3 -0
- package/dist/config.d.ts +14 -1
- package/dist/downstream.d.ts +169 -1
- package/dist/engine.d.ts +2 -0
- package/dist/errors.d.ts +1 -1
- package/dist/generated-tool-input-schema-B6rce396.js +4720 -0
- package/dist/generated-tool-input-schema.d.ts +222 -9
- package/dist/generated-tool-input-schema.js +2 -59
- package/dist/index.js +1063 -207
- package/dist/native/options.d.ts +4 -5
- package/dist/native/remote.d.ts +1 -0
- package/dist/native/service.d.ts +3 -0
- package/dist/native.js +38 -64
- package/dist/{engine-Brwid_mq.js → options-DM1cMRcp.js} +888 -4851
- package/dist/remote-control/auth-flow.d.ts +22 -0
- package/dist/remote-control/client.d.ts +11 -0
- package/dist/remote-control/dispatch.d.ts +9 -0
- package/dist/remote-control/types.d.ts +17 -0
- package/dist/serve/http.d.ts +11 -0
- package/dist/serve/options.d.ts +3 -1
- package/dist/server/options.d.ts +41 -0
- package/dist/tools.d.ts +38 -20
- package/package.json +1 -1
|
@@ -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 };
|
package/dist/config/paths.d.ts
CHANGED
|
@@ -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>>>>;
|