@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.
- 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/completion-dbB1hc97.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-BYoyY-l-.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 +888 -279
- package/dist/native/remote.d.ts +1 -0
- package/dist/native/service.d.ts +3 -0
- package/dist/native.js +24 -7
- package/dist/{options-CJEOqS87.js → options-BqibJVxq.js} +684 -4865
- package/dist/remote-control/types.d.ts +1 -1
- package/dist/tools.d.ts +38 -20
- package/package.json +7 -7
|
@@ -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 };
|
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;
|