@caplets/core 0.14.0 → 0.16.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/store.d.ts +22 -0
- package/dist/auth.d.ts +77 -0
- package/dist/capability-description.d.ts +2 -0
- package/dist/caplet-files.d.ts +266 -0
- package/dist/caplet-sets.d.ts +33 -0
- package/dist/cli/add.d.ts +62 -0
- package/dist/cli/auth.d.ts +20 -0
- package/dist/cli/author.d.ts +11 -0
- package/dist/cli/init.d.ts +5 -0
- package/dist/cli/inspection.d.ts +30 -0
- package/dist/cli/install.d.ts +15 -0
- package/dist/cli-tools.d.ts +23 -0
- package/dist/cli.d.ts +15 -0
- package/dist/config/paths.d.ts +14 -0
- package/dist/config/validation.d.ts +16 -0
- package/dist/config.d.ts +227 -0
- package/dist/downstream.d.ts +41 -0
- package/dist/engine-Brwid_mq.js +58159 -0
- package/dist/engine.d.ts +52 -0
- package/dist/errors.d.ts +24 -0
- package/dist/field-selection.d.ts +4 -0
- package/dist/generated-tool-input-schema.d.ts +47 -0
- package/dist/generated-tool-input-schema.js +59 -0
- package/dist/graphql.d.ts +30 -0
- package/dist/http/utils.d.ts +7 -0
- package/dist/http-actions.d.ts +26 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6390 -61147
- package/dist/native/options.d.ts +34 -0
- package/dist/native/process-cleanup.d.ts +2 -0
- package/dist/native/remote.d.ts +46 -0
- package/dist/native/service.d.ts +30 -0
- package/dist/native/tools.d.ts +5 -0
- package/dist/native.d.ts +7 -0
- package/dist/native.js +367 -0
- package/dist/openapi.d.ts +29 -0
- package/dist/registry.d.ts +68 -0
- package/dist/result-content.d.ts +14 -0
- package/dist/runtime.d.ts +25 -0
- package/dist/schema-hash.d.ts +1 -0
- package/dist/schema-utils.d.ts +2 -0
- package/dist/serve/http.d.ts +12 -0
- package/dist/serve/index.d.ts +14 -0
- package/dist/serve/options.d.ts +34 -0
- package/dist/serve/session.d.ts +21 -0
- package/dist/serve/stdio.d.ts +5 -0
- package/dist/tool-search.d.ts +2 -0
- package/dist/tools.d.ts +67 -0
- package/package.json +22 -9
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type NativeCapletsMode = "auto" | "local" | "remote";
|
|
2
|
+
export type NativeRemoteCapletsOptions = {
|
|
3
|
+
url?: string;
|
|
4
|
+
user?: string;
|
|
5
|
+
password?: string;
|
|
6
|
+
pollIntervalMs?: number;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
};
|
|
9
|
+
export type NativeCapletsServiceResolutionInput = {
|
|
10
|
+
mode?: NativeCapletsMode;
|
|
11
|
+
remote?: NativeRemoteCapletsOptions;
|
|
12
|
+
};
|
|
13
|
+
export type NativeCapletsEnv = Partial<Record<"CAPLETS_NATIVE_MODE" | "CAPLETS_REMOTE_URL" | "CAPLETS_REMOTE_USER" | "CAPLETS_REMOTE_PASSWORD", string>>;
|
|
14
|
+
export type NativeRemoteAuthOptions = {
|
|
15
|
+
enabled: false;
|
|
16
|
+
user: string;
|
|
17
|
+
} | {
|
|
18
|
+
enabled: true;
|
|
19
|
+
user: string;
|
|
20
|
+
password: string;
|
|
21
|
+
};
|
|
22
|
+
export type ResolvedNativeCapletsServiceOptions = {
|
|
23
|
+
mode: "local";
|
|
24
|
+
} | {
|
|
25
|
+
mode: "remote";
|
|
26
|
+
remote: {
|
|
27
|
+
url: URL;
|
|
28
|
+
auth: NativeRemoteAuthOptions;
|
|
29
|
+
pollIntervalMs: number;
|
|
30
|
+
requestInit: RequestInit;
|
|
31
|
+
fetch?: typeof fetch;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export declare function resolveNativeCapletsServiceOptions(input?: NativeCapletsServiceResolutionInput, env?: NativeCapletsEnv): ResolvedNativeCapletsServiceOptions;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ResolvedNativeCapletsServiceOptions } from "./options";
|
|
2
|
+
import type { NativeCapletsService, NativeCapletsToolsChangedListener, NativeCapletTool } from "./service";
|
|
3
|
+
export type RemoteCapletsTool = {
|
|
4
|
+
name: string;
|
|
5
|
+
title?: string | undefined;
|
|
6
|
+
description?: string | undefined;
|
|
7
|
+
};
|
|
8
|
+
export type RemoteCapletsClient = {
|
|
9
|
+
listTools(): Promise<RemoteCapletsTool[]>;
|
|
10
|
+
callTool(name: string, args: unknown): Promise<unknown>;
|
|
11
|
+
onToolsChanged(listener: () => void): () => void;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
export type RemoteCapletsClientOptions = ResolvedNativeCapletsServiceOptions & {
|
|
15
|
+
mode: "remote";
|
|
16
|
+
};
|
|
17
|
+
export type RemoteNativeCapletsServiceOptions = {
|
|
18
|
+
client: RemoteCapletsClient;
|
|
19
|
+
clientFactory?: () => RemoteCapletsClient;
|
|
20
|
+
pollIntervalMs: number;
|
|
21
|
+
writeErr?: (value: string) => void;
|
|
22
|
+
};
|
|
23
|
+
export declare function createSdkRemoteCapletsClient(options: RemoteCapletsClientOptions["remote"]): RemoteCapletsClient;
|
|
24
|
+
export declare class RemoteNativeCapletsService implements NativeCapletsService {
|
|
25
|
+
private readonly options;
|
|
26
|
+
private tools;
|
|
27
|
+
private readonly listeners;
|
|
28
|
+
private readonly clientFactory;
|
|
29
|
+
private client;
|
|
30
|
+
private unsubscribeRemote;
|
|
31
|
+
private readonly pollTimer;
|
|
32
|
+
private closed;
|
|
33
|
+
private resetInFlight;
|
|
34
|
+
constructor(options: RemoteNativeCapletsServiceOptions);
|
|
35
|
+
listTools(): NativeCapletTool[];
|
|
36
|
+
execute(capletId: string, request: unknown): Promise<unknown>;
|
|
37
|
+
reload(): Promise<boolean>;
|
|
38
|
+
onToolsChanged(listener: NativeCapletsToolsChangedListener): () => void;
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
private reloadFromClient;
|
|
41
|
+
private subscribeRemote;
|
|
42
|
+
private resetClient;
|
|
43
|
+
private doResetClient;
|
|
44
|
+
private emitToolsChanged;
|
|
45
|
+
private warn;
|
|
46
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { NativeCapletsServiceResolutionInput } from "./options";
|
|
2
|
+
import { resolveNativeCapletsServiceOptions } from "./options";
|
|
3
|
+
import { type RemoteCapletsClient } from "./remote";
|
|
4
|
+
export type NativeCapletsServiceOptions = NativeCapletsServiceResolutionInput & {
|
|
5
|
+
configPath?: string;
|
|
6
|
+
projectConfigPath?: string;
|
|
7
|
+
authDir?: string;
|
|
8
|
+
watchDebounceMs?: number;
|
|
9
|
+
watch?: boolean;
|
|
10
|
+
writeErr?: (value: string) => void;
|
|
11
|
+
remoteClientFactory?: (options: Extract<ReturnType<typeof resolveNativeCapletsServiceOptions>, {
|
|
12
|
+
mode: "remote";
|
|
13
|
+
}>["remote"]) => RemoteCapletsClient;
|
|
14
|
+
};
|
|
15
|
+
export type NativeCapletTool = {
|
|
16
|
+
caplet: string;
|
|
17
|
+
toolName: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
promptGuidance: string[];
|
|
21
|
+
};
|
|
22
|
+
export type NativeCapletsToolsChangedListener = (tools: NativeCapletTool[]) => void;
|
|
23
|
+
export type NativeCapletsService = {
|
|
24
|
+
listTools(): NativeCapletTool[];
|
|
25
|
+
execute(capletId: string, request: unknown): Promise<unknown>;
|
|
26
|
+
reload(): Promise<boolean>;
|
|
27
|
+
onToolsChanged(listener: NativeCapletsToolsChangedListener): () => void;
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
export declare function createNativeCapletsService(options?: NativeCapletsServiceOptions): NativeCapletsService;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CapletConfig } from "../config";
|
|
2
|
+
export declare function nativeCapletToolName(capletId: string): string;
|
|
3
|
+
export declare function nativeCapletsSystemGuidance(toolNames: string[]): string;
|
|
4
|
+
export declare function nativeCapletPromptGuidance(toolName: string, caplet: CapletConfig): string[];
|
|
5
|
+
export declare function nativeCapletToolDescription(toolName: string, caplet: CapletConfig): string;
|
package/dist/native.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createNativeCapletsService, type NativeCapletTool, type NativeCapletsService, type NativeCapletsServiceOptions, type NativeCapletsToolsChangedListener, } from "./native/service";
|
|
2
|
+
export { registerNativeCapletsProcessCleanup } from "./native/process-cleanup";
|
|
3
|
+
export { nativeCapletPromptGuidance, nativeCapletToolDescription, nativeCapletToolName, nativeCapletsSystemGuidance, } from "./native/tools";
|
|
4
|
+
export { generatedToolInputSchema } from "./tools";
|
|
5
|
+
export { generatedToolInputJsonSchema } from "./generated-tool-input-schema";
|
|
6
|
+
export { resolveNativeCapletsServiceOptions, type NativeCapletsEnv, type NativeCapletsMode, type NativeCapletsServiceResolutionInput, type NativeRemoteAuthOptions, type NativeRemoteCapletsOptions, type ResolvedNativeCapletsServiceOptions, } from "./native/options";
|
|
7
|
+
export { createSdkRemoteCapletsClient, RemoteNativeCapletsService, type RemoteCapletsClient, type RemoteCapletsClientOptions, type RemoteCapletsTool, type RemoteNativeCapletsServiceOptions, } from "./native/remote";
|
package/dist/native.js
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { K as ToolListChangedNotificationSchema, Tt as CapletsError, a as capabilityDescription, d as StreamableHTTPClientTransport, m as Client, n as generatedToolInputSchema, t as CapletsEngine } from "./engine-Brwid_mq.js";
|
|
2
|
+
import { generatedToolInputJsonSchema } from "./generated-tool-input-schema.js";
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
//#region src/native/options.ts
|
|
5
|
+
const DEFAULT_REMOTE_USER = "caplets";
|
|
6
|
+
const DEFAULT_POLL_INTERVAL_MS = 3e4;
|
|
7
|
+
function resolveNativeCapletsServiceOptions(input = {}, env = process.env) {
|
|
8
|
+
const mode = parseMode(input.mode ?? env.CAPLETS_NATIVE_MODE ?? "auto");
|
|
9
|
+
if (mode === "local") return { mode: "local" };
|
|
10
|
+
const rawUrl = nonEmpty(input.remote?.url, "remote.url") ?? nonEmpty(env.CAPLETS_REMOTE_URL, "CAPLETS_REMOTE_URL");
|
|
11
|
+
if (mode === "remote" && rawUrl === void 0) throw new CapletsError("REQUEST_INVALID", "CAPLETS_NATIVE_MODE=remote requires CAPLETS_REMOTE_URL or remote.url.");
|
|
12
|
+
if (rawUrl === void 0) return { mode: "local" };
|
|
13
|
+
const url = parseRemoteUrl(rawUrl);
|
|
14
|
+
const userWasExplicit = input.remote?.user !== void 0 || hasEnv(env.CAPLETS_REMOTE_USER);
|
|
15
|
+
const user = nonEmpty(input.remote?.user, "remote.user") ?? nonEmpty(env.CAPLETS_REMOTE_USER, "CAPLETS_REMOTE_USER") ?? DEFAULT_REMOTE_USER;
|
|
16
|
+
const password = nonEmpty(input.remote?.password, "remote.password") ?? nonEmpty(env.CAPLETS_REMOTE_PASSWORD, "CAPLETS_REMOTE_PASSWORD");
|
|
17
|
+
if (userWasExplicit && password === void 0) throw new CapletsError("REQUEST_INVALID", "Remote Caplets Basic Auth requires a password; set CAPLETS_REMOTE_PASSWORD or remote.password.");
|
|
18
|
+
const auth = password === void 0 ? {
|
|
19
|
+
enabled: false,
|
|
20
|
+
user
|
|
21
|
+
} : {
|
|
22
|
+
enabled: true,
|
|
23
|
+
user,
|
|
24
|
+
password
|
|
25
|
+
};
|
|
26
|
+
const requestInit = auth.enabled ? { headers: { Authorization: basicAuthHeader(auth.user, auth.password) } } : {};
|
|
27
|
+
return {
|
|
28
|
+
mode: "remote",
|
|
29
|
+
remote: {
|
|
30
|
+
url,
|
|
31
|
+
auth,
|
|
32
|
+
pollIntervalMs: parsePollInterval(input.remote?.pollIntervalMs),
|
|
33
|
+
requestInit,
|
|
34
|
+
...input.remote?.fetch ? { fetch: input.remote.fetch } : {}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function parseMode(value) {
|
|
39
|
+
if (value === "auto" || value === "local" || value === "remote") return value;
|
|
40
|
+
throw new CapletsError("REQUEST_INVALID", `Expected CAPLETS_NATIVE_MODE to be auto, local, or remote, got ${value}`);
|
|
41
|
+
}
|
|
42
|
+
function parseRemoteUrl(value) {
|
|
43
|
+
let url;
|
|
44
|
+
try {
|
|
45
|
+
url = new URL(value);
|
|
46
|
+
} catch {
|
|
47
|
+
throw new CapletsError("REQUEST_INVALID", "Invalid remote Caplets URL.");
|
|
48
|
+
}
|
|
49
|
+
if (url.username !== "" || url.password !== "") throw new CapletsError("REQUEST_INVALID", "Remote Caplets URL must not include username or password; use CAPLETS_REMOTE_USER/CAPLETS_REMOTE_PASSWORD or remote.user/remote.password instead.");
|
|
50
|
+
if (url.protocol === "https:") return url;
|
|
51
|
+
if (url.protocol === "http:" && isLoopbackHost(url.hostname)) return url;
|
|
52
|
+
throw new CapletsError("REQUEST_INVALID", "Remote Caplets URL must use https except loopback development URLs.");
|
|
53
|
+
}
|
|
54
|
+
function isLoopbackHost(host) {
|
|
55
|
+
return host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host === "::1";
|
|
56
|
+
}
|
|
57
|
+
function parsePollInterval(value) {
|
|
58
|
+
if (value === void 0) return DEFAULT_POLL_INTERVAL_MS;
|
|
59
|
+
if (!Number.isInteger(value) || value < 1e3) throw new CapletsError("REQUEST_INVALID", "remote.pollIntervalMs must be an integer >= 1000.");
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
function basicAuthHeader(user, password) {
|
|
63
|
+
return `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`;
|
|
64
|
+
}
|
|
65
|
+
function nonEmpty(value, label) {
|
|
66
|
+
if (value === void 0) return;
|
|
67
|
+
const trimmed = value.trim();
|
|
68
|
+
if (!trimmed) throw new CapletsError("REQUEST_INVALID", `${label} must not be empty`);
|
|
69
|
+
return trimmed;
|
|
70
|
+
}
|
|
71
|
+
function hasEnv(value) {
|
|
72
|
+
return value !== void 0 && value.trim() !== "";
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/native/tools.ts
|
|
76
|
+
function nativeCapletToolName(capletId) {
|
|
77
|
+
return `caplets_${capletId.replace(/_/g, "__").replace(/-/g, "_")}`;
|
|
78
|
+
}
|
|
79
|
+
function nativeCapletsSystemGuidance(toolNames) {
|
|
80
|
+
return [
|
|
81
|
+
"## Caplets Native Tools",
|
|
82
|
+
"",
|
|
83
|
+
"Caplets tools expose configured capability domains through progressive discovery.",
|
|
84
|
+
"",
|
|
85
|
+
"Available Caplets native tools:",
|
|
86
|
+
toolNames.length > 0 ? toolNames.map((tool) => `- ${tool}`).join("\n") : "- none",
|
|
87
|
+
"",
|
|
88
|
+
"Flow: get_caplet when the domain is unfamiliar; search_tools or list_tools to find exact downstream names; get_tool only when schemas are unclear; call_tool with downstream inputs inside arguments.",
|
|
89
|
+
"Use fields on call_tool when a non-GraphQL downstream outputSchema allows selecting only needed structured paths."
|
|
90
|
+
].join("\n");
|
|
91
|
+
}
|
|
92
|
+
function nativeCapletPromptGuidance(toolName, caplet) {
|
|
93
|
+
return [`Use ${toolName} for the ${caplet.name} Caplet capability domain.`];
|
|
94
|
+
}
|
|
95
|
+
function nativeCapletToolDescription(toolName, caplet) {
|
|
96
|
+
return [
|
|
97
|
+
capabilityDescription(caplet),
|
|
98
|
+
"",
|
|
99
|
+
`Native tool name: ${toolName}`,
|
|
100
|
+
`Original Caplet ID: ${caplet.server}`
|
|
101
|
+
].join("\n");
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/native/remote.ts
|
|
105
|
+
function createSdkRemoteCapletsClient(options) {
|
|
106
|
+
const client = new Client({
|
|
107
|
+
name: "caplets-native",
|
|
108
|
+
version: "1.0.0"
|
|
109
|
+
}, { capabilities: {} });
|
|
110
|
+
const transport = new StreamableHTTPClientTransport(options.url, {
|
|
111
|
+
requestInit: options.requestInit,
|
|
112
|
+
...options.fetch ? { fetch: options.fetch } : {}
|
|
113
|
+
});
|
|
114
|
+
const ready = client.connect(transport);
|
|
115
|
+
const readyObserved = ready.catch(() => void 0);
|
|
116
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
117
|
+
client.setNotificationHandler(ToolListChangedNotificationSchema, () => {
|
|
118
|
+
for (const listener of listeners) listener();
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
async listTools() {
|
|
122
|
+
await ready;
|
|
123
|
+
return ((await client.listTools()).tools ?? []).map((tool) => ({
|
|
124
|
+
name: tool.name,
|
|
125
|
+
...tool.title ? { title: tool.title } : {},
|
|
126
|
+
...tool.description ? { description: tool.description } : {}
|
|
127
|
+
}));
|
|
128
|
+
},
|
|
129
|
+
async callTool(name, args) {
|
|
130
|
+
await ready;
|
|
131
|
+
const toolArguments = args && typeof args === "object" && !Array.isArray(args) ? args : void 0;
|
|
132
|
+
return await client.callTool({
|
|
133
|
+
name,
|
|
134
|
+
arguments: toolArguments
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
onToolsChanged(listener) {
|
|
138
|
+
listeners.add(listener);
|
|
139
|
+
return () => listeners.delete(listener);
|
|
140
|
+
},
|
|
141
|
+
async close() {
|
|
142
|
+
listeners.clear();
|
|
143
|
+
await readyObserved;
|
|
144
|
+
await transport.terminateSession().catch(() => void 0);
|
|
145
|
+
await client.close();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
var RemoteNativeCapletsService = class {
|
|
150
|
+
options;
|
|
151
|
+
tools = [];
|
|
152
|
+
listeners = /* @__PURE__ */ new Set();
|
|
153
|
+
clientFactory;
|
|
154
|
+
client;
|
|
155
|
+
unsubscribeRemote;
|
|
156
|
+
pollTimer;
|
|
157
|
+
closed = false;
|
|
158
|
+
resetInFlight;
|
|
159
|
+
constructor(options) {
|
|
160
|
+
this.options = options;
|
|
161
|
+
this.client = options.client;
|
|
162
|
+
this.clientFactory = options.clientFactory ?? (() => options.client);
|
|
163
|
+
this.unsubscribeRemote = this.subscribeRemote(this.client);
|
|
164
|
+
this.pollTimer = setInterval(() => {
|
|
165
|
+
this.reload();
|
|
166
|
+
}, options.pollIntervalMs);
|
|
167
|
+
this.pollTimer.unref?.();
|
|
168
|
+
}
|
|
169
|
+
listTools() {
|
|
170
|
+
return [...this.tools];
|
|
171
|
+
}
|
|
172
|
+
async execute(capletId, request) {
|
|
173
|
+
try {
|
|
174
|
+
return await this.client.callTool(capletId, request);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (isAuthFailure(error)) throw remoteAuthError();
|
|
177
|
+
if (isSessionFailure(error)) {
|
|
178
|
+
if (!await this.resetClient() || this.closed) throw error;
|
|
179
|
+
try {
|
|
180
|
+
return await this.client.callTool(capletId, request);
|
|
181
|
+
} catch (retryError) {
|
|
182
|
+
if (isAuthFailure(retryError)) throw remoteAuthError();
|
|
183
|
+
throw retryError;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async reload() {
|
|
190
|
+
if (this.closed) return false;
|
|
191
|
+
try {
|
|
192
|
+
await this.reloadFromClient();
|
|
193
|
+
return true;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (isSessionFailure(error)) try {
|
|
196
|
+
if (!await this.resetClient() || this.closed) return false;
|
|
197
|
+
await this.reloadFromClient();
|
|
198
|
+
return !this.closed;
|
|
199
|
+
} catch (retryError) {
|
|
200
|
+
this.warn(`Could not reload remote Caplets tools: ${errorMessage(retryError)}\n`);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
this.warn(`Could not reload remote Caplets tools: ${errorMessage(error)}\n`);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
onToolsChanged(listener) {
|
|
208
|
+
this.listeners.add(listener);
|
|
209
|
+
return () => this.listeners.delete(listener);
|
|
210
|
+
}
|
|
211
|
+
async close() {
|
|
212
|
+
if (this.closed) return;
|
|
213
|
+
this.closed = true;
|
|
214
|
+
clearInterval(this.pollTimer);
|
|
215
|
+
this.unsubscribeRemote();
|
|
216
|
+
this.listeners.clear();
|
|
217
|
+
await this.client.close();
|
|
218
|
+
}
|
|
219
|
+
async reloadFromClient() {
|
|
220
|
+
const tools = (await this.client.listTools()).map(remoteToolToNativeTool);
|
|
221
|
+
const changed = JSON.stringify(tools) !== JSON.stringify(this.tools);
|
|
222
|
+
this.tools = tools;
|
|
223
|
+
if (changed) this.emitToolsChanged();
|
|
224
|
+
}
|
|
225
|
+
subscribeRemote(client) {
|
|
226
|
+
return client.onToolsChanged(() => {
|
|
227
|
+
this.reload();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async resetClient() {
|
|
231
|
+
if (this.resetInFlight) return await this.resetInFlight;
|
|
232
|
+
this.resetInFlight = this.doResetClient();
|
|
233
|
+
try {
|
|
234
|
+
return await this.resetInFlight;
|
|
235
|
+
} finally {
|
|
236
|
+
this.resetInFlight = void 0;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async doResetClient() {
|
|
240
|
+
if (this.closed) return false;
|
|
241
|
+
this.unsubscribeRemote();
|
|
242
|
+
await this.client.close().catch(() => void 0);
|
|
243
|
+
if (this.closed) return false;
|
|
244
|
+
const nextClient = this.clientFactory();
|
|
245
|
+
if (this.closed) {
|
|
246
|
+
await nextClient.close().catch(() => void 0);
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
this.client = nextClient;
|
|
250
|
+
this.unsubscribeRemote = this.subscribeRemote(this.client);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
emitToolsChanged() {
|
|
254
|
+
const tools = this.listTools();
|
|
255
|
+
for (const listener of this.listeners) listener(tools);
|
|
256
|
+
}
|
|
257
|
+
warn(message) {
|
|
258
|
+
if (this.options.writeErr) {
|
|
259
|
+
this.options.writeErr(message);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
process.stderr.write(message);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
function remoteToolToNativeTool(tool) {
|
|
266
|
+
const toolName = nativeCapletToolName(tool.name);
|
|
267
|
+
return {
|
|
268
|
+
caplet: tool.name,
|
|
269
|
+
toolName,
|
|
270
|
+
title: tool.title ?? tool.name,
|
|
271
|
+
description: [
|
|
272
|
+
tool.description ?? "Remote Caplets tool.",
|
|
273
|
+
"",
|
|
274
|
+
`Native tool name: ${toolName}`,
|
|
275
|
+
`Remote Caplet ID: ${tool.name}`
|
|
276
|
+
].join("\n"),
|
|
277
|
+
promptGuidance: [`Use ${toolName} through the remote Caplets service.`]
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function errorMessage(error) {
|
|
281
|
+
return error instanceof Error ? error.message : String(error);
|
|
282
|
+
}
|
|
283
|
+
function remoteAuthError() {
|
|
284
|
+
return new CapletsError("AUTH_FAILED", "Remote Caplets authentication failed; check CAPLETS_REMOTE_USER and CAPLETS_REMOTE_PASSWORD.");
|
|
285
|
+
}
|
|
286
|
+
function isSessionFailure(error) {
|
|
287
|
+
const message = errorMessage(error).toLowerCase();
|
|
288
|
+
return /session|transport|connection|connect|closed|invalid/u.test(message);
|
|
289
|
+
}
|
|
290
|
+
function isAuthFailure(error) {
|
|
291
|
+
const candidate = error;
|
|
292
|
+
const status = typeof candidate?.status === "number" ? candidate.status : void 0;
|
|
293
|
+
const statusCode = typeof candidate?.statusCode === "number" ? candidate.statusCode : void 0;
|
|
294
|
+
const code = typeof candidate?.code === "number" ? candidate.code : void 0;
|
|
295
|
+
if (status === 401 || status === 403 || statusCode === 401 || statusCode === 403 || code === 401 || code === 403) return true;
|
|
296
|
+
return /\b(401|403|unauthorized|forbidden)\b/iu.test(errorMessage(error));
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region src/native/service.ts
|
|
300
|
+
function createNativeCapletsService(options = {}) {
|
|
301
|
+
const resolved = resolveNativeCapletsServiceOptions(options);
|
|
302
|
+
if (resolved.mode === "remote") return new RemoteNativeCapletsService({
|
|
303
|
+
client: (options.remoteClientFactory ?? createSdkRemoteCapletsClient)(resolved.remote),
|
|
304
|
+
clientFactory: () => (options.remoteClientFactory ?? createSdkRemoteCapletsClient)(resolved.remote),
|
|
305
|
+
pollIntervalMs: resolved.remote.pollIntervalMs,
|
|
306
|
+
...options.writeErr ? { writeErr: options.writeErr } : {}
|
|
307
|
+
});
|
|
308
|
+
return new DefaultNativeCapletsService(options);
|
|
309
|
+
}
|
|
310
|
+
var DefaultNativeCapletsService = class {
|
|
311
|
+
engine;
|
|
312
|
+
constructor(options) {
|
|
313
|
+
this.engine = new CapletsEngine(options);
|
|
314
|
+
}
|
|
315
|
+
listTools() {
|
|
316
|
+
return this.engine.enabledServers().map((caplet) => {
|
|
317
|
+
const toolName = nativeCapletToolName(caplet.server);
|
|
318
|
+
return {
|
|
319
|
+
caplet: caplet.server,
|
|
320
|
+
toolName,
|
|
321
|
+
title: caplet.name,
|
|
322
|
+
description: nativeCapletToolDescription(toolName, caplet),
|
|
323
|
+
promptGuidance: nativeCapletPromptGuidance(toolName, caplet)
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
async execute(capletId, request) {
|
|
328
|
+
return await this.engine.execute(capletId, request);
|
|
329
|
+
}
|
|
330
|
+
async reload() {
|
|
331
|
+
return await this.engine.reload();
|
|
332
|
+
}
|
|
333
|
+
onToolsChanged(listener) {
|
|
334
|
+
return this.engine.onReload(() => listener(this.listTools()));
|
|
335
|
+
}
|
|
336
|
+
async close() {
|
|
337
|
+
await this.engine.close();
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/native/process-cleanup.ts
|
|
342
|
+
function registerNativeCapletsProcessCleanup(service) {
|
|
343
|
+
let closed = false;
|
|
344
|
+
const close = async () => {
|
|
345
|
+
if (closed) return;
|
|
346
|
+
closed = true;
|
|
347
|
+
try {
|
|
348
|
+
await service.close();
|
|
349
|
+
} catch (error) {
|
|
350
|
+
console.error("Failed to close Caplets service:", error);
|
|
351
|
+
process.exitCode = 1;
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
const closeBeforeExit = () => {
|
|
355
|
+
close();
|
|
356
|
+
};
|
|
357
|
+
const closeAndExit = () => {
|
|
358
|
+
close().finally(() => {
|
|
359
|
+
process.exit(process.exitCode ?? 0);
|
|
360
|
+
});
|
|
361
|
+
};
|
|
362
|
+
process.once("beforeExit", closeBeforeExit);
|
|
363
|
+
process.once("SIGINT", closeAndExit);
|
|
364
|
+
process.once("SIGTERM", closeAndExit);
|
|
365
|
+
}
|
|
366
|
+
//#endregion
|
|
367
|
+
export { RemoteNativeCapletsService, createNativeCapletsService, createSdkRemoteCapletsClient, generatedToolInputJsonSchema, generatedToolInputSchema, nativeCapletPromptGuidance, nativeCapletToolDescription, nativeCapletToolName, nativeCapletsSystemGuidance, registerNativeCapletsProcessCleanup, resolveNativeCapletsServiceOptions };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CompatibilityCallToolResult, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { OpenApiEndpointConfig } from "./config";
|
|
3
|
+
import type { CompactTool } from "./downstream";
|
|
4
|
+
import type { ServerRegistry } from "./registry";
|
|
5
|
+
export declare class OpenApiManager {
|
|
6
|
+
private registry;
|
|
7
|
+
private readonly options;
|
|
8
|
+
private readonly cache;
|
|
9
|
+
constructor(registry: ServerRegistry, options?: {
|
|
10
|
+
authDir?: string;
|
|
11
|
+
});
|
|
12
|
+
updateRegistry(registry: ServerRegistry): void;
|
|
13
|
+
invalidate(serverId: string): void;
|
|
14
|
+
checkEndpoint(endpoint: OpenApiEndpointConfig): Promise<{
|
|
15
|
+
id: string;
|
|
16
|
+
status: string;
|
|
17
|
+
toolCount?: number;
|
|
18
|
+
elapsedMs: number;
|
|
19
|
+
error?: unknown;
|
|
20
|
+
}>;
|
|
21
|
+
listTools(endpoint: OpenApiEndpointConfig): Promise<Tool[]>;
|
|
22
|
+
getTool(endpoint: OpenApiEndpointConfig, toolName: string): Promise<Tool>;
|
|
23
|
+
callTool(endpoint: OpenApiEndpointConfig, toolName: string, args: Record<string, unknown>): Promise<CompatibilityCallToolResult>;
|
|
24
|
+
compact(endpoint: OpenApiEndpointConfig, tool: Tool): CompactTool;
|
|
25
|
+
search(endpoint: OpenApiEndpointConfig, tools: Tool[], query: string, limit: number): CompactTool[];
|
|
26
|
+
private getOperation;
|
|
27
|
+
private refreshOperations;
|
|
28
|
+
private toTool;
|
|
29
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { CapletConfig, CapletsConfig, CapletServerConfig } from "./config";
|
|
2
|
+
import type { SafeErrorSummary } from "./errors";
|
|
3
|
+
export { capabilityDescription } from "./capability-description";
|
|
4
|
+
export type ServerStatus = "disabled" | "not_started" | "starting" | "available" | "unavailable";
|
|
5
|
+
export type CapletServerSummary = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
status: ServerStatus;
|
|
11
|
+
lastError?: SafeErrorSummary;
|
|
12
|
+
};
|
|
13
|
+
export type CapletServerDetail = {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
tags?: string[];
|
|
18
|
+
backend: {
|
|
19
|
+
type: "mcp";
|
|
20
|
+
transport: CapletServerConfig["transport"];
|
|
21
|
+
disabled: boolean;
|
|
22
|
+
startupTimeoutMs: number;
|
|
23
|
+
callTimeoutMs: number;
|
|
24
|
+
toolCacheTtlMs: number;
|
|
25
|
+
} | {
|
|
26
|
+
type: "openapi";
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
requestTimeoutMs: number;
|
|
29
|
+
operationCacheTtlMs: number;
|
|
30
|
+
source: "specPath" | "specUrl";
|
|
31
|
+
} | {
|
|
32
|
+
type: "graphql";
|
|
33
|
+
disabled: boolean;
|
|
34
|
+
requestTimeoutMs: number;
|
|
35
|
+
operationCacheTtlMs: number;
|
|
36
|
+
source: "schemaPath" | "schemaUrl" | "introspection";
|
|
37
|
+
configuredOperations: boolean;
|
|
38
|
+
} | {
|
|
39
|
+
type: "http";
|
|
40
|
+
disabled: boolean;
|
|
41
|
+
requestTimeoutMs: number;
|
|
42
|
+
configuredActions: number;
|
|
43
|
+
} | {
|
|
44
|
+
type: "cli";
|
|
45
|
+
disabled: boolean;
|
|
46
|
+
timeoutMs: number;
|
|
47
|
+
maxOutputBytes: number;
|
|
48
|
+
configuredActions: number;
|
|
49
|
+
} | {
|
|
50
|
+
type: "caplets";
|
|
51
|
+
disabled: boolean;
|
|
52
|
+
source: "configPath" | "capletsRoot" | "both";
|
|
53
|
+
toolCacheTtlMs: number;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
export declare class ServerRegistry {
|
|
57
|
+
readonly config: CapletsConfig;
|
|
58
|
+
private readonly statuses;
|
|
59
|
+
constructor(config: CapletsConfig);
|
|
60
|
+
enabledServers(): CapletConfig[];
|
|
61
|
+
get(serverId: string): CapletConfig | undefined;
|
|
62
|
+
require(serverId: string): CapletConfig;
|
|
63
|
+
setStatus(serverId: string, status: ServerStatus, lastError?: SafeErrorSummary): void;
|
|
64
|
+
getStatus(serverId: string): ServerStatus;
|
|
65
|
+
summary(server: CapletConfig): CapletServerSummary;
|
|
66
|
+
detail(server: CapletConfig): CapletServerDetail;
|
|
67
|
+
private allCaplets;
|
|
68
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export type TextContentBlock = {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function structuredOnlyContent(): [];
|
|
7
|
+
export declare function textContent(text: string): TextContentBlock[];
|
|
8
|
+
export declare function compactJsonText(value: unknown, maxLength?: number): string;
|
|
9
|
+
export declare function compactText(value: string, maxLength?: number): string;
|
|
10
|
+
export declare function resultKeys(value: unknown): string;
|
|
11
|
+
export declare function statusSummary(value: unknown): string;
|
|
12
|
+
export declare function compactStructuredContent(value: unknown): TextContentBlock[];
|
|
13
|
+
export declare function compactCallToolResultContent(result: CallToolResult): TextContentBlock[];
|
|
14
|
+
export declare function byteLimitHint(maxBytes: number): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
+
import type { CapletsConfig } from "./config";
|
|
3
|
+
import { type ToolServer } from "./serve/session";
|
|
4
|
+
type CapletsRuntimeOptions = {
|
|
5
|
+
configPath?: string;
|
|
6
|
+
projectConfigPath?: string;
|
|
7
|
+
authDir?: string;
|
|
8
|
+
watchDebounceMs?: number;
|
|
9
|
+
server?: ToolServer;
|
|
10
|
+
writeErr?: (value: string) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare class CapletsRuntime {
|
|
13
|
+
readonly server: ToolServer;
|
|
14
|
+
private readonly engine;
|
|
15
|
+
private readonly session;
|
|
16
|
+
constructor(options?: CapletsRuntimeOptions);
|
|
17
|
+
connect(transport: Transport): Promise<void>;
|
|
18
|
+
scheduleReload(): void;
|
|
19
|
+
reload(): Promise<boolean>;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
currentConfig(): CapletsConfig;
|
|
22
|
+
registeredToolIds(): string[];
|
|
23
|
+
watchedPaths(): string[];
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function schemaHash(schema: unknown | undefined): string | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { CapletsEngine, type CapletsEngineOptions } from "../engine";
|
|
3
|
+
import type { HttpServeOptions } from "./options";
|
|
4
|
+
type HttpServeIo = {
|
|
5
|
+
writeErr?: (value: string) => void;
|
|
6
|
+
};
|
|
7
|
+
export type CapletsHttpApp = Hono & {
|
|
8
|
+
closeCapletsSessions: () => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
export declare function createHttpServeApp(options: HttpServeOptions, engine: CapletsEngine, io?: HttpServeIo): CapletsHttpApp;
|
|
11
|
+
export declare function serveHttp(options: HttpServeOptions, engineOptions?: CapletsEngineOptions, writeErr?: (value: string) => void): Promise<void>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CapletsEngineOptions } from "../engine";
|
|
2
|
+
import { type RawServeOptions, type ServeOptions } from "./options";
|
|
3
|
+
export { serveHttp } from "./http";
|
|
4
|
+
export { resolveServeOptions } from "./options";
|
|
5
|
+
export type { HttpServeOptions, RawServeOptions, ServeOptions, StdioServeOptions } from "./options";
|
|
6
|
+
export { serveStdio } from "./stdio";
|
|
7
|
+
export type ServeCapletsOptions = {
|
|
8
|
+
raw: RawServeOptions;
|
|
9
|
+
engine?: CapletsEngineOptions;
|
|
10
|
+
env?: NodeJS.ProcessEnv;
|
|
11
|
+
writeErr?: (value: string) => void;
|
|
12
|
+
};
|
|
13
|
+
export declare function serveCaplets(options: ServeCapletsOptions): Promise<void>;
|
|
14
|
+
export declare function serveResolvedCaplets(resolved: ServeOptions, engineOptions?: CapletsEngineOptions, writeErr?: (value: string) => void): Promise<void>;
|