@caplets/core 0.15.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/cli.d.ts +2 -0
- package/dist/{engine-Bh55p8Lm.js → engine-Brwid_mq.js} +26370 -26368
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3340 -53
- package/dist/native/options.d.ts +34 -0
- package/dist/native/remote.d.ts +46 -0
- package/dist/native/service.d.ts +7 -1
- package/dist/native.d.ts +2 -0
- package/dist/native.js +276 -2
- package/dist/runtime.d.ts +3 -8
- 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/package.json +4 -1
|
@@ -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
|
+
}
|
package/dist/native/service.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import type { NativeCapletsServiceResolutionInput } from "./options";
|
|
2
|
+
import { resolveNativeCapletsServiceOptions } from "./options";
|
|
3
|
+
import { type RemoteCapletsClient } from "./remote";
|
|
4
|
+
export type NativeCapletsServiceOptions = NativeCapletsServiceResolutionInput & {
|
|
2
5
|
configPath?: string;
|
|
3
6
|
projectConfigPath?: string;
|
|
4
7
|
authDir?: string;
|
|
5
8
|
watchDebounceMs?: number;
|
|
6
9
|
watch?: boolean;
|
|
7
10
|
writeErr?: (value: string) => void;
|
|
11
|
+
remoteClientFactory?: (options: Extract<ReturnType<typeof resolveNativeCapletsServiceOptions>, {
|
|
12
|
+
mode: "remote";
|
|
13
|
+
}>["remote"]) => RemoteCapletsClient;
|
|
8
14
|
};
|
|
9
15
|
export type NativeCapletTool = {
|
|
10
16
|
caplet: string;
|
package/dist/native.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export { registerNativeCapletsProcessCleanup } from "./native/process-cleanup";
|
|
|
3
3
|
export { nativeCapletPromptGuidance, nativeCapletToolDescription, nativeCapletToolName, nativeCapletsSystemGuidance, } from "./native/tools";
|
|
4
4
|
export { generatedToolInputSchema } from "./tools";
|
|
5
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
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
|
-
import { a as capabilityDescription, n as generatedToolInputSchema, t as CapletsEngine } from "./engine-
|
|
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
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
|
|
3
75
|
//#region src/native/tools.ts
|
|
4
76
|
function nativeCapletToolName(capletId) {
|
|
5
77
|
return `caplets_${capletId.replace(/_/g, "__").replace(/-/g, "_")}`;
|
|
@@ -29,8 +101,210 @@ function nativeCapletToolDescription(toolName, caplet) {
|
|
|
29
101
|
].join("\n");
|
|
30
102
|
}
|
|
31
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
|
|
32
299
|
//#region src/native/service.ts
|
|
33
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
|
+
});
|
|
34
308
|
return new DefaultNativeCapletsService(options);
|
|
35
309
|
}
|
|
36
310
|
var DefaultNativeCapletsService = class {
|
|
@@ -90,4 +364,4 @@ function registerNativeCapletsProcessCleanup(service) {
|
|
|
90
364
|
process.once("SIGTERM", closeAndExit);
|
|
91
365
|
}
|
|
92
366
|
//#endregion
|
|
93
|
-
export { createNativeCapletsService, generatedToolInputJsonSchema, generatedToolInputSchema, nativeCapletPromptGuidance, nativeCapletToolDescription, nativeCapletToolName, nativeCapletsSystemGuidance, registerNativeCapletsProcessCleanup };
|
|
367
|
+
export { RemoteNativeCapletsService, createNativeCapletsService, createSdkRemoteCapletsClient, generatedToolInputJsonSchema, generatedToolInputSchema, nativeCapletPromptGuidance, nativeCapletToolDescription, nativeCapletToolName, nativeCapletsSystemGuidance, registerNativeCapletsProcessCleanup, resolveNativeCapletsServiceOptions };
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
1
|
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
3
|
-
import {
|
|
4
|
-
type ToolServer
|
|
2
|
+
import type { CapletsConfig } from "./config";
|
|
3
|
+
import { type ToolServer } from "./serve/session";
|
|
5
4
|
type CapletsRuntimeOptions = {
|
|
6
5
|
configPath?: string;
|
|
7
6
|
projectConfigPath?: string;
|
|
@@ -13,8 +12,7 @@ type CapletsRuntimeOptions = {
|
|
|
13
12
|
export declare class CapletsRuntime {
|
|
14
13
|
readonly server: ToolServer;
|
|
15
14
|
private readonly engine;
|
|
16
|
-
private readonly
|
|
17
|
-
private readonly unsubscribeReload;
|
|
15
|
+
private readonly session;
|
|
18
16
|
constructor(options?: CapletsRuntimeOptions);
|
|
19
17
|
connect(transport: Transport): Promise<void>;
|
|
20
18
|
scheduleReload(): void;
|
|
@@ -23,8 +21,5 @@ export declare class CapletsRuntime {
|
|
|
23
21
|
currentConfig(): CapletsConfig;
|
|
24
22
|
registeredToolIds(): string[];
|
|
25
23
|
watchedPaths(): string[];
|
|
26
|
-
private reconcileTools;
|
|
27
|
-
private registerCapletTool;
|
|
28
|
-
private handleTool;
|
|
29
24
|
}
|
|
30
25
|
export {};
|
|
@@ -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>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type ServeTransport = "stdio" | "http";
|
|
2
|
+
export type RawServeOptions = {
|
|
3
|
+
transport?: string;
|
|
4
|
+
host?: string;
|
|
5
|
+
port?: string | number;
|
|
6
|
+
path?: string;
|
|
7
|
+
user?: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
allowUnauthenticatedHttp?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type StdioServeOptions = {
|
|
12
|
+
transport: "stdio";
|
|
13
|
+
};
|
|
14
|
+
export type HttpServeOptions = {
|
|
15
|
+
transport: "http";
|
|
16
|
+
host: string;
|
|
17
|
+
port: number;
|
|
18
|
+
path: string;
|
|
19
|
+
auth: HttpBasicAuthOptions;
|
|
20
|
+
warnUnauthenticatedNetwork: boolean;
|
|
21
|
+
loopback: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type HttpBasicAuthOptions = {
|
|
24
|
+
enabled: false;
|
|
25
|
+
user: string;
|
|
26
|
+
} | {
|
|
27
|
+
enabled: true;
|
|
28
|
+
user: string;
|
|
29
|
+
password: string;
|
|
30
|
+
};
|
|
31
|
+
export type ServeOptions = StdioServeOptions | HttpServeOptions;
|
|
32
|
+
export type ServeEnv = Partial<Record<"CAPLETS_SERVER_USER" | "CAPLETS_SERVER_PASSWORD", string>>;
|
|
33
|
+
export declare function resolveServeOptions(raw: RawServeOptions, env?: ServeEnv): ServeOptions;
|
|
34
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
3
|
+
import type { CapletsEngine } from "../engine";
|
|
4
|
+
export type ToolServer = Pick<McpServer, "registerTool" | "connect" | "close">;
|
|
5
|
+
export type CapletsMcpSessionOptions = {
|
|
6
|
+
server?: ToolServer;
|
|
7
|
+
};
|
|
8
|
+
export declare class CapletsMcpSession {
|
|
9
|
+
private readonly engine;
|
|
10
|
+
readonly server: ToolServer;
|
|
11
|
+
private readonly tools;
|
|
12
|
+
private readonly unsubscribeReload;
|
|
13
|
+
private closed;
|
|
14
|
+
constructor(engine: CapletsEngine, options?: CapletsMcpSessionOptions);
|
|
15
|
+
connect(transport: Transport): Promise<void>;
|
|
16
|
+
registeredToolIds(): string[];
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
private reconcileTools;
|
|
19
|
+
private registerCapletTool;
|
|
20
|
+
private handleTool;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caplets/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Core runtime library for Caplets progressive disclosure gateways.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"caplets",
|
|
@@ -45,9 +45,12 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@apidevtools/swagger-parser": "^12.1.0",
|
|
48
|
+
"@hono/mcp": "^0.3.0",
|
|
49
|
+
"@hono/node-server": "^1.19.14",
|
|
48
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
51
|
"commander": "^14.0.3",
|
|
50
52
|
"graphql": "^16.14.0",
|
|
53
|
+
"hono": "^4.12.19",
|
|
51
54
|
"vfile": "^6.0.3",
|
|
52
55
|
"vfile-matter": "^5.0.1",
|
|
53
56
|
"zod": "^4.4.3"
|