@caplets/opencode 0.5.2 → 0.5.3

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