@caplets/core 0.18.3 → 0.18.5
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/caplet-files.d.ts +8 -0
- package/dist/cli/auth.d.ts +26 -2
- package/dist/cli/inspection.d.ts +2 -2
- package/dist/{completion-Cq1z7ci2.js → completion-DRPTunQd.js} +6 -5
- package/dist/config.d.ts +11 -0
- package/dist/engine.d.ts +2 -0
- package/dist/index.js +400 -136
- package/dist/native/process-cleanup.d.ts +4 -1
- package/dist/native/service.d.ts +6 -0
- package/dist/native.d.ts +1 -1
- package/dist/native.js +139 -20
- package/dist/{options-j9p3L3r1.js → options-BlNyqF_E.js} +277 -12
- package/package.json +6 -5
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import type { NativeCapletsService } from "./service";
|
|
2
|
-
export
|
|
2
|
+
export type NativeCapletsProcessCleanupOptions = {
|
|
3
|
+
writeErr?: (message: string) => void;
|
|
4
|
+
};
|
|
5
|
+
export declare function registerNativeCapletsProcessCleanup(service: NativeCapletsService, options?: NativeCapletsProcessCleanupOptions): void;
|
package/dist/native/service.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { NativeCapletsServiceResolutionInput } from "./options";
|
|
2
2
|
import { resolveNativeCapletsServiceOptions } from "./options";
|
|
3
3
|
import { type RemoteCapletsClient } from "./remote";
|
|
4
|
+
import { type CapletsConfig } from "../config";
|
|
4
5
|
import { generatedToolInputJsonSchemaForCaplet } from "../generated-tool-input-schema";
|
|
5
6
|
export type NativeCapletsServiceOptions = NativeCapletsServiceResolutionInput & {
|
|
6
7
|
configPath?: string;
|
|
@@ -12,6 +13,7 @@ export type NativeCapletsServiceOptions = NativeCapletsServiceResolutionInput &
|
|
|
12
13
|
remoteClientFactory?: (options: Extract<ReturnType<typeof resolveNativeCapletsServiceOptions>, {
|
|
13
14
|
mode: "remote";
|
|
14
15
|
}>["remote"]) => RemoteCapletsClient;
|
|
16
|
+
localServiceFactory?: (options: LocalNativeCapletsServiceOptions) => NativeCapletsService;
|
|
15
17
|
};
|
|
16
18
|
export type NativeCapletTool = {
|
|
17
19
|
caplet: string;
|
|
@@ -31,3 +33,7 @@ export type NativeCapletsService = {
|
|
|
31
33
|
close(): Promise<void>;
|
|
32
34
|
};
|
|
33
35
|
export declare function createNativeCapletsService(options?: NativeCapletsServiceOptions): NativeCapletsService;
|
|
36
|
+
type LocalNativeCapletsServiceOptions = NativeCapletsServiceOptions & {
|
|
37
|
+
configLoader?: (configPath: string, projectConfigPath: string) => CapletsConfig;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
package/dist/native.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createNativeCapletsService, type NativeCapletTool, type NativeCapletsService, type NativeCapletsServiceOptions, type NativeCapletsToolsChangedListener, } from "./native/service";
|
|
2
|
-
export { registerNativeCapletsProcessCleanup } from "./native/process-cleanup";
|
|
2
|
+
export { registerNativeCapletsProcessCleanup, type NativeCapletsProcessCleanupOptions, } 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";
|
package/dist/native.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Q as ToolListChangedNotificationSchema, _ as StreamableHTTPClientTransport, a as resolveCapletsServer, b as Client, bt as parseConfig, i as resolveCapletsMode, jt as CapletsError, l as capabilityDescription, n as mcpUrlForBase, o as CapletsEngine, vt as loadLocalOverlayConfigWithSources } from "./options-BlNyqF_E.js";
|
|
2
2
|
import { a as generatedToolInputJsonSchemaForCaplet, i as generatedToolInputJsonSchema, l as operations, o as generatedToolInputSchema } from "./generated-tool-input-schema-BYoyY-l-.js";
|
|
3
3
|
//#region src/native/options.ts
|
|
4
4
|
const DEFAULT_POLL_INTERVAL_MS = 3e4;
|
|
@@ -155,10 +155,10 @@ var RemoteNativeCapletsService = class {
|
|
|
155
155
|
await this.reloadFromClient();
|
|
156
156
|
return !this.closed;
|
|
157
157
|
} catch (retryError) {
|
|
158
|
-
this.warn(`Could not reload remote Caplets tools: ${errorMessage(retryError)}\n`);
|
|
158
|
+
this.warn(`Could not reload remote Caplets tools: ${errorMessage$2(retryError)}\n`);
|
|
159
159
|
return false;
|
|
160
160
|
}
|
|
161
|
-
this.warn(`Could not reload remote Caplets tools: ${errorMessage(error)}\n`);
|
|
161
|
+
this.warn(`Could not reload remote Caplets tools: ${errorMessage$2(error)}\n`);
|
|
162
162
|
return false;
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -213,11 +213,7 @@ var RemoteNativeCapletsService = class {
|
|
|
213
213
|
for (const listener of this.listeners) listener(tools);
|
|
214
214
|
}
|
|
215
215
|
warn(message) {
|
|
216
|
-
|
|
217
|
-
this.options.writeErr(message);
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
process.stderr.write(message);
|
|
216
|
+
this.options.writeErr?.(message);
|
|
221
217
|
}
|
|
222
218
|
};
|
|
223
219
|
function remoteToolToNativeTool(tool) {
|
|
@@ -248,14 +244,14 @@ function operationNamesFromSchema(schema) {
|
|
|
248
244
|
function isPlainObject(value) {
|
|
249
245
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
250
246
|
}
|
|
251
|
-
function errorMessage(error) {
|
|
247
|
+
function errorMessage$2(error) {
|
|
252
248
|
return error instanceof Error ? error.message : String(error);
|
|
253
249
|
}
|
|
254
250
|
function remoteAuthError() {
|
|
255
251
|
return new CapletsError("AUTH_FAILED", "Remote Caplets authentication failed; check CAPLETS_SERVER_USER and CAPLETS_SERVER_PASSWORD.");
|
|
256
252
|
}
|
|
257
253
|
function isSessionFailure(error) {
|
|
258
|
-
const message = errorMessage(error).toLowerCase();
|
|
254
|
+
const message = errorMessage$2(error).toLowerCase();
|
|
259
255
|
return /session|transport|connection|connect|closed|invalid/u.test(message);
|
|
260
256
|
}
|
|
261
257
|
function isAuthFailure(error) {
|
|
@@ -264,24 +260,42 @@ function isAuthFailure(error) {
|
|
|
264
260
|
const statusCode = typeof candidate?.statusCode === "number" ? candidate.statusCode : void 0;
|
|
265
261
|
const code = typeof candidate?.code === "number" ? candidate.code : void 0;
|
|
266
262
|
if (status === 401 || status === 403 || statusCode === 401 || statusCode === 403 || code === 401 || code === 403) return true;
|
|
267
|
-
return /\b(401|403|unauthorized|forbidden)\b/iu.test(errorMessage(error));
|
|
263
|
+
return /\b(401|403|unauthorized|forbidden)\b/iu.test(errorMessage$2(error));
|
|
268
264
|
}
|
|
269
265
|
//#endregion
|
|
270
266
|
//#region src/native/service.ts
|
|
271
267
|
function createNativeCapletsService(options = {}) {
|
|
272
268
|
const resolved = resolveNativeCapletsServiceOptions(options);
|
|
273
|
-
if (resolved.mode === "remote")
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
269
|
+
if (resolved.mode === "remote") {
|
|
270
|
+
const localOptions = {
|
|
271
|
+
...options,
|
|
272
|
+
mode: "local",
|
|
273
|
+
configLoader: createLocalOverlayConfigLoader(options)
|
|
274
|
+
};
|
|
275
|
+
const local = (options.localServiceFactory ?? createDefaultNativeCapletsService)(localOptions);
|
|
276
|
+
try {
|
|
277
|
+
return new CompositeNativeCapletsService(new RemoteNativeCapletsService({
|
|
278
|
+
client: (options.remoteClientFactory ?? createSdkRemoteCapletsClient)(resolved.remote),
|
|
279
|
+
clientFactory: () => (options.remoteClientFactory ?? createSdkRemoteCapletsClient)(resolved.remote),
|
|
280
|
+
pollIntervalMs: resolved.remote.pollIntervalMs,
|
|
281
|
+
...options.writeErr ? { writeErr: options.writeErr } : {}
|
|
282
|
+
}), local, options);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
local.close().catch((closeError) => {
|
|
285
|
+
writeErr(options, `Could not close local overlay Caplets service: ${errorMessage$1(closeError)}\n`);
|
|
286
|
+
});
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
279
290
|
return new DefaultNativeCapletsService(options);
|
|
280
291
|
}
|
|
281
292
|
var DefaultNativeCapletsService = class {
|
|
282
293
|
engine;
|
|
283
294
|
constructor(options) {
|
|
284
|
-
this.engine = new CapletsEngine(
|
|
295
|
+
this.engine = new CapletsEngine({
|
|
296
|
+
...options,
|
|
297
|
+
writeErr: options.writeErr ?? (() => void 0)
|
|
298
|
+
});
|
|
285
299
|
}
|
|
286
300
|
listTools() {
|
|
287
301
|
return this.engine.enabledServers().map((caplet) => {
|
|
@@ -311,9 +325,111 @@ var DefaultNativeCapletsService = class {
|
|
|
311
325
|
await this.engine.close();
|
|
312
326
|
}
|
|
313
327
|
};
|
|
328
|
+
function createDefaultNativeCapletsService(options) {
|
|
329
|
+
return new DefaultNativeCapletsService(options);
|
|
330
|
+
}
|
|
331
|
+
var CompositeNativeCapletsService = class {
|
|
332
|
+
remote;
|
|
333
|
+
local;
|
|
334
|
+
options;
|
|
335
|
+
listeners = /* @__PURE__ */ new Set();
|
|
336
|
+
unsubscribers;
|
|
337
|
+
tools = [];
|
|
338
|
+
closed = false;
|
|
339
|
+
batchingReload = false;
|
|
340
|
+
constructor(remote, local, options) {
|
|
341
|
+
this.remote = remote;
|
|
342
|
+
this.local = local;
|
|
343
|
+
this.options = options;
|
|
344
|
+
this.unsubscribers = [this.remote.onToolsChanged(() => this.updateMergedTools()), this.local.onToolsChanged(() => this.updateMergedTools())];
|
|
345
|
+
this.tools = this.mergeTools();
|
|
346
|
+
}
|
|
347
|
+
listTools() {
|
|
348
|
+
return [...this.tools];
|
|
349
|
+
}
|
|
350
|
+
async execute(capletId, request) {
|
|
351
|
+
if (this.local.listTools().some((tool) => tool.caplet === capletId)) return await this.local.execute(capletId, request);
|
|
352
|
+
return await this.remote.execute(capletId, request);
|
|
353
|
+
}
|
|
354
|
+
async reload() {
|
|
355
|
+
if (this.closed) return false;
|
|
356
|
+
this.batchingReload = true;
|
|
357
|
+
const remoteReloaded = await this.reloadChild(this.remote, "remote");
|
|
358
|
+
const localReloaded = await this.reloadChild(this.local, "local overlay");
|
|
359
|
+
this.batchingReload = false;
|
|
360
|
+
if (remoteReloaded === void 0 || localReloaded === void 0) return false;
|
|
361
|
+
this.updateMergedTools();
|
|
362
|
+
return remoteReloaded || localReloaded;
|
|
363
|
+
}
|
|
364
|
+
onToolsChanged(listener) {
|
|
365
|
+
this.listeners.add(listener);
|
|
366
|
+
return () => this.listeners.delete(listener);
|
|
367
|
+
}
|
|
368
|
+
async close() {
|
|
369
|
+
if (this.closed) return;
|
|
370
|
+
this.closed = true;
|
|
371
|
+
for (const unsubscribe of this.unsubscribers.splice(0)) unsubscribe();
|
|
372
|
+
this.listeners.clear();
|
|
373
|
+
await Promise.all([this.remote.close(), this.local.close()]);
|
|
374
|
+
}
|
|
375
|
+
updateMergedTools() {
|
|
376
|
+
if (this.closed || this.batchingReload) return;
|
|
377
|
+
const tools = this.mergeTools();
|
|
378
|
+
if (JSON.stringify(tools) === JSON.stringify(this.tools)) return;
|
|
379
|
+
this.tools = tools;
|
|
380
|
+
for (const listener of this.listeners) try {
|
|
381
|
+
listener(this.listTools());
|
|
382
|
+
} catch (error) {
|
|
383
|
+
writeErr(this.options, `Caplets tools-changed listener failed: ${errorMessage$1(error)}\n`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
mergeTools() {
|
|
387
|
+
const localTools = this.local.listTools();
|
|
388
|
+
const localIds = new Set(localTools.map((tool) => tool.caplet));
|
|
389
|
+
return [...this.remote.listTools().filter((tool) => !localIds.has(tool.caplet)), ...localTools];
|
|
390
|
+
}
|
|
391
|
+
async reloadChild(service, label) {
|
|
392
|
+
try {
|
|
393
|
+
return await service.reload();
|
|
394
|
+
} catch (error) {
|
|
395
|
+
writeErr(this.options, `Could not reload composite Caplets tools from ${label}: ${errorMessage$1(error)}\n`);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
function createLocalOverlayConfigLoader(options) {
|
|
401
|
+
let hasLoaded = false;
|
|
402
|
+
let previousWarnings = /* @__PURE__ */ new Set();
|
|
403
|
+
return (configPath, projectConfigPath) => {
|
|
404
|
+
let result;
|
|
405
|
+
try {
|
|
406
|
+
result = loadLocalOverlayConfigWithSources(configPath, projectConfigPath);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
writeErr(options, `Caplets local overlay warning: Could not load local overlay config: ${errorMessage$1(error)}\n`);
|
|
409
|
+
if (hasLoaded) throw new CapletsError("CONFIG_INVALID", "Caplets local overlay reload failed; keeping last known-good config.", error);
|
|
410
|
+
hasLoaded = true;
|
|
411
|
+
return parseConfig({});
|
|
412
|
+
}
|
|
413
|
+
for (const warning of result.warnings) writeErr(options, `Caplets local overlay warning${typeof warning.path === "string" ? ` at ${warning.path}` : ""}: ${warning.message}\n`);
|
|
414
|
+
const warnings = new Set(result.warnings.map(warningKey));
|
|
415
|
+
if (hasLoaded && [...warnings].some((warning) => !previousWarnings.has(warning))) throw new CapletsError("CONFIG_INVALID", "Caplets local overlay reload produced new warnings; keeping last known-good config.");
|
|
416
|
+
previousWarnings = warnings;
|
|
417
|
+
hasLoaded = true;
|
|
418
|
+
return result.config;
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function warningKey(warning) {
|
|
422
|
+
return `${warning.kind}\0${warning.path}\0${warning.message}`;
|
|
423
|
+
}
|
|
424
|
+
function writeErr(options, message) {
|
|
425
|
+
options.writeErr?.(message);
|
|
426
|
+
}
|
|
427
|
+
function errorMessage$1(error) {
|
|
428
|
+
return error instanceof Error ? error.message : String(error);
|
|
429
|
+
}
|
|
314
430
|
//#endregion
|
|
315
431
|
//#region src/native/process-cleanup.ts
|
|
316
|
-
function registerNativeCapletsProcessCleanup(service) {
|
|
432
|
+
function registerNativeCapletsProcessCleanup(service, options = {}) {
|
|
317
433
|
let closed = false;
|
|
318
434
|
const close = async () => {
|
|
319
435
|
if (closed) return;
|
|
@@ -321,7 +437,7 @@ function registerNativeCapletsProcessCleanup(service) {
|
|
|
321
437
|
try {
|
|
322
438
|
await service.close();
|
|
323
439
|
} catch (error) {
|
|
324
|
-
|
|
440
|
+
options.writeErr?.(`Failed to close Caplets service: ${errorMessage(error)}\n`);
|
|
325
441
|
process.exitCode = 1;
|
|
326
442
|
}
|
|
327
443
|
};
|
|
@@ -337,5 +453,8 @@ function registerNativeCapletsProcessCleanup(service) {
|
|
|
337
453
|
process.once("SIGINT", closeAndExit);
|
|
338
454
|
process.once("SIGTERM", closeAndExit);
|
|
339
455
|
}
|
|
456
|
+
function errorMessage(error) {
|
|
457
|
+
return error instanceof Error ? error.message : String(error);
|
|
458
|
+
}
|
|
340
459
|
//#endregion
|
|
341
460
|
export { RemoteNativeCapletsService, createNativeCapletsService, createSdkRemoteCapletsClient, generatedToolInputJsonSchema, generatedToolInputSchema, nativeCapletPromptGuidance, nativeCapletToolDescription, nativeCapletToolName, nativeCapletsSystemGuidance, registerNativeCapletsProcessCleanup, resolveNativeCapletsServiceOptions };
|
|
@@ -8380,6 +8380,82 @@ function loadCapletFilesWithPaths(root) {
|
|
|
8380
8380
|
paths
|
|
8381
8381
|
} : void 0;
|
|
8382
8382
|
}
|
|
8383
|
+
function loadCapletFilesWithPathsBestEffort(root) {
|
|
8384
|
+
if (!existsSync(root)) return;
|
|
8385
|
+
const warnings = [];
|
|
8386
|
+
return buildCapletFileLoadResult(root, discoverCapletFilesBestEffort(root, warnings), warnings);
|
|
8387
|
+
}
|
|
8388
|
+
function buildCapletFileLoadResult(root, candidates, warnings) {
|
|
8389
|
+
const servers = {};
|
|
8390
|
+
const openapiEndpoints = {};
|
|
8391
|
+
const graphqlEndpoints = {};
|
|
8392
|
+
const httpApis = {};
|
|
8393
|
+
const cliTools = {};
|
|
8394
|
+
const capletSets = {};
|
|
8395
|
+
const paths = {};
|
|
8396
|
+
function hasId(id) {
|
|
8397
|
+
return Boolean(servers[id] || openapiEndpoints[id] || graphqlEndpoints[id] || httpApis[id] || cliTools[id] || capletSets[id]);
|
|
8398
|
+
}
|
|
8399
|
+
for (const candidate of candidates) {
|
|
8400
|
+
if (hasId(candidate.id)) {
|
|
8401
|
+
const message = `Duplicate Caplet ID ${candidate.id} under ${root}`;
|
|
8402
|
+
if (!warnings) throw new CapletsError("CONFIG_INVALID", message);
|
|
8403
|
+
warnings.push({
|
|
8404
|
+
path: candidate.path,
|
|
8405
|
+
message: `${message}; skipping duplicate at ${candidate.path}`
|
|
8406
|
+
});
|
|
8407
|
+
continue;
|
|
8408
|
+
}
|
|
8409
|
+
let config;
|
|
8410
|
+
try {
|
|
8411
|
+
config = readCapletFile(candidate.path);
|
|
8412
|
+
} catch (error) {
|
|
8413
|
+
if (!warnings) throw error;
|
|
8414
|
+
warnings.push({
|
|
8415
|
+
path: candidate.path,
|
|
8416
|
+
message: `Skipping invalid Caplet file at ${candidate.path}: ${errorMessage$1(error)}`
|
|
8417
|
+
});
|
|
8418
|
+
continue;
|
|
8419
|
+
}
|
|
8420
|
+
paths[candidate.id] = candidate.path;
|
|
8421
|
+
if (isPlainObject$5(config) && config.backend === "openapi") {
|
|
8422
|
+
const { backend: _backend, ...endpoint } = config;
|
|
8423
|
+
openapiEndpoints[candidate.id] = endpoint;
|
|
8424
|
+
} else if (isPlainObject$5(config) && config.backend === "graphql") {
|
|
8425
|
+
const { backend: _backend, ...endpoint } = config;
|
|
8426
|
+
graphqlEndpoints[candidate.id] = endpoint;
|
|
8427
|
+
} else if (isPlainObject$5(config) && config.backend === "http") {
|
|
8428
|
+
const { backend: _backend, ...endpoint } = config;
|
|
8429
|
+
httpApis[candidate.id] = endpoint;
|
|
8430
|
+
} else if (isPlainObject$5(config) && config.backend === "cli") {
|
|
8431
|
+
const { backend: _backend, ...endpoint } = config;
|
|
8432
|
+
cliTools[candidate.id] = endpoint;
|
|
8433
|
+
} else if (isPlainObject$5(config) && config.backend === "caplets") {
|
|
8434
|
+
const { backend: _backend, ...endpoint } = config;
|
|
8435
|
+
capletSets[candidate.id] = endpoint;
|
|
8436
|
+
} else servers[candidate.id] = config;
|
|
8437
|
+
}
|
|
8438
|
+
const hasServers = Object.keys(servers).length > 0;
|
|
8439
|
+
const hasOpenApi = Object.keys(openapiEndpoints).length > 0;
|
|
8440
|
+
const hasGraphQl = Object.keys(graphqlEndpoints).length > 0;
|
|
8441
|
+
const hasHttpApis = Object.keys(httpApis).length > 0;
|
|
8442
|
+
const hasCliTools = Object.keys(cliTools).length > 0;
|
|
8443
|
+
const hasCapletSets = Object.keys(capletSets).length > 0;
|
|
8444
|
+
const config = {
|
|
8445
|
+
...hasServers ? { mcpServers: servers } : {},
|
|
8446
|
+
...hasOpenApi ? { openapiEndpoints } : {},
|
|
8447
|
+
...hasGraphQl ? { graphqlEndpoints } : {},
|
|
8448
|
+
...hasHttpApis ? { httpApis } : {},
|
|
8449
|
+
...hasCliTools ? { cliTools } : {},
|
|
8450
|
+
...hasCapletSets ? { capletSets } : {}
|
|
8451
|
+
};
|
|
8452
|
+
if (!(Object.keys(config).length > 0) && warnings?.length === 0) return;
|
|
8453
|
+
return {
|
|
8454
|
+
config,
|
|
8455
|
+
paths,
|
|
8456
|
+
warnings: warnings ?? []
|
|
8457
|
+
};
|
|
8458
|
+
}
|
|
8383
8459
|
function discoverCapletFiles(root) {
|
|
8384
8460
|
const entries = readdirSync(root, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
8385
8461
|
const candidates = [];
|
|
@@ -8404,6 +8480,82 @@ function discoverCapletFiles(root) {
|
|
|
8404
8480
|
}
|
|
8405
8481
|
return candidates;
|
|
8406
8482
|
}
|
|
8483
|
+
function discoverCapletFilesBestEffort(root, warnings) {
|
|
8484
|
+
const entries = readdirSync(root, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
8485
|
+
const byId = /* @__PURE__ */ new Map();
|
|
8486
|
+
const duplicateIds = /* @__PURE__ */ new Set();
|
|
8487
|
+
function addCandidate(id, path, isDirectoryCaplet) {
|
|
8488
|
+
try {
|
|
8489
|
+
validateCapletId(id, path);
|
|
8490
|
+
} catch (error) {
|
|
8491
|
+
warnings.push({
|
|
8492
|
+
path,
|
|
8493
|
+
message: `Skipping invalid Caplet file at ${path}: ${errorMessage$1(error)}`
|
|
8494
|
+
});
|
|
8495
|
+
return;
|
|
8496
|
+
}
|
|
8497
|
+
if (duplicateIds.has(id)) {
|
|
8498
|
+
warnings.push({
|
|
8499
|
+
path,
|
|
8500
|
+
message: `Duplicate Caplet ID ${id} under ${root}; skipping duplicate at ${path}`
|
|
8501
|
+
});
|
|
8502
|
+
return;
|
|
8503
|
+
}
|
|
8504
|
+
const existing = byId.get(id);
|
|
8505
|
+
if (!existing) {
|
|
8506
|
+
byId.set(id, {
|
|
8507
|
+
id,
|
|
8508
|
+
path,
|
|
8509
|
+
isDirectoryCaplet
|
|
8510
|
+
});
|
|
8511
|
+
return;
|
|
8512
|
+
}
|
|
8513
|
+
if (isDirectoryCaplet && !existing.isDirectoryCaplet) {
|
|
8514
|
+
warnings.push({
|
|
8515
|
+
path: existing.path,
|
|
8516
|
+
message: `Caplet file at ${existing.path} was shadowed by ${path}`
|
|
8517
|
+
});
|
|
8518
|
+
byId.set(id, {
|
|
8519
|
+
id,
|
|
8520
|
+
path,
|
|
8521
|
+
isDirectoryCaplet
|
|
8522
|
+
});
|
|
8523
|
+
return;
|
|
8524
|
+
}
|
|
8525
|
+
if (!isDirectoryCaplet && existing.isDirectoryCaplet) {
|
|
8526
|
+
warnings.push({
|
|
8527
|
+
path,
|
|
8528
|
+
message: `Caplet file at ${path} was shadowed by ${existing.path}`
|
|
8529
|
+
});
|
|
8530
|
+
return;
|
|
8531
|
+
}
|
|
8532
|
+
warnings.push({
|
|
8533
|
+
path,
|
|
8534
|
+
message: `Duplicate Caplet ID ${id} under ${root}; skipping ${existing.path} and ${path}`
|
|
8535
|
+
});
|
|
8536
|
+
byId.delete(id);
|
|
8537
|
+
duplicateIds.add(id);
|
|
8538
|
+
}
|
|
8539
|
+
for (const entry of entries) {
|
|
8540
|
+
if (entry.name === "auth" || entry.name === "config.json") continue;
|
|
8541
|
+
const path = join(root, entry.name);
|
|
8542
|
+
if (entry.isFile() && extname(entry.name).toLowerCase() === ".md") {
|
|
8543
|
+
addCandidate(basename(entry.name, extname(entry.name)), path, false);
|
|
8544
|
+
continue;
|
|
8545
|
+
}
|
|
8546
|
+
if (entry.isDirectory()) {
|
|
8547
|
+
const capletPath = join(path, "CAPLET.md");
|
|
8548
|
+
if (existsSync(capletPath) && statSync(capletPath).isFile()) addCandidate(entry.name, capletPath, true);
|
|
8549
|
+
}
|
|
8550
|
+
}
|
|
8551
|
+
return Array.from(byId.values()).map(({ id, path }) => ({
|
|
8552
|
+
id,
|
|
8553
|
+
path
|
|
8554
|
+
}));
|
|
8555
|
+
}
|
|
8556
|
+
function errorMessage$1(error) {
|
|
8557
|
+
return error instanceof Error ? error.message : String(error);
|
|
8558
|
+
}
|
|
8407
8559
|
function readCapletFile(path) {
|
|
8408
8560
|
if (statSync(path).size > MAX_CAPLET_FILE_BYTES) throw new CapletsError("CONFIG_INVALID", `Caplet file at ${path} exceeds the ${MAX_CAPLET_FILE_BYTES} byte limit`);
|
|
8409
8561
|
const { frontmatter, body } = parseFrontmatter(readFileSync(path, "utf8"), path);
|
|
@@ -9084,35 +9236,78 @@ function loadConfigWithSources(path = resolveConfigPath(), projectPath = resolve
|
|
|
9084
9236
|
const projectConfig = hasProjectConfig ? rejectProjectConfigExecutableBackendMaps(readPublicConfigInput(projectPath), projectPath) : void 0;
|
|
9085
9237
|
const projectCapletsRoot = resolveProjectCapletsRootForConfigPath(projectPath);
|
|
9086
9238
|
const projectCaplets = projectCapletsRoot ? loadCapletFilesWithPaths(projectCapletsRoot) : void 0;
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
const { input, sources, shadows } = mergeConfigInputsWithSources({
|
|
9239
|
+
return buildConfigWithSources([
|
|
9240
|
+
{
|
|
9090
9241
|
input: userConfig,
|
|
9091
9242
|
source: {
|
|
9092
9243
|
kind: "global-config",
|
|
9093
9244
|
path
|
|
9094
9245
|
}
|
|
9095
|
-
},
|
|
9246
|
+
},
|
|
9247
|
+
userCaplets ? {
|
|
9096
9248
|
input: userCaplets.config,
|
|
9097
9249
|
source: {
|
|
9098
9250
|
kind: "global-file",
|
|
9099
9251
|
path: userCaplets.paths
|
|
9100
9252
|
}
|
|
9101
|
-
} : void 0,
|
|
9253
|
+
} : void 0,
|
|
9254
|
+
{
|
|
9102
9255
|
input: projectConfig,
|
|
9103
9256
|
source: {
|
|
9104
9257
|
kind: "project-config",
|
|
9105
9258
|
path: projectPath
|
|
9106
9259
|
}
|
|
9107
|
-
},
|
|
9260
|
+
},
|
|
9261
|
+
projectCaplets ? {
|
|
9108
9262
|
input: projectCaplets.config,
|
|
9109
9263
|
source: {
|
|
9110
9264
|
kind: "project-file",
|
|
9111
9265
|
path: projectCaplets.paths
|
|
9112
9266
|
}
|
|
9113
|
-
} : void 0
|
|
9267
|
+
} : void 0
|
|
9268
|
+
], `Caplets config not found at ${path} or ${projectPath}`, "Caplets config must define at least one MCP server, OpenAPI endpoint, GraphQL endpoint, HTTP API, CLI tools backend, or Caplet set");
|
|
9269
|
+
}
|
|
9270
|
+
function loadGlobalConfig(path = resolveConfigPath()) {
|
|
9271
|
+
const userConfig = existsSync(path) ? readPublicConfigInput(path) : void 0;
|
|
9272
|
+
const userCaplets = loadCapletFilesWithPaths(resolveCapletsRoot(path));
|
|
9273
|
+
return buildConfigWithSources([{
|
|
9274
|
+
input: userConfig,
|
|
9275
|
+
source: {
|
|
9276
|
+
kind: "global-config",
|
|
9277
|
+
path
|
|
9278
|
+
}
|
|
9279
|
+
}, userCaplets ? {
|
|
9280
|
+
input: userCaplets.config,
|
|
9281
|
+
source: {
|
|
9282
|
+
kind: "global-file",
|
|
9283
|
+
path: userCaplets.paths
|
|
9284
|
+
}
|
|
9285
|
+
} : void 0], `Caplets user config not found at ${path}`, void 0).config;
|
|
9286
|
+
}
|
|
9287
|
+
function loadProjectConfig(projectPath = resolveProjectConfigPath()) {
|
|
9288
|
+
const projectConfig = existsSync(projectPath) ? rejectProjectConfigExecutableBackendMaps(readPublicConfigInput(projectPath), projectPath) : void 0;
|
|
9289
|
+
const projectCapletsRoot = resolveProjectCapletsRootForConfigPath(projectPath);
|
|
9290
|
+
const projectCaplets = projectCapletsRoot ? loadCapletFilesWithPaths(projectCapletsRoot) : void 0;
|
|
9291
|
+
return buildConfigWithSources([{
|
|
9292
|
+
input: projectConfig,
|
|
9293
|
+
source: {
|
|
9294
|
+
kind: "project-config",
|
|
9295
|
+
path: projectPath
|
|
9296
|
+
}
|
|
9297
|
+
}, projectCaplets ? {
|
|
9298
|
+
input: projectCaplets.config,
|
|
9299
|
+
source: {
|
|
9300
|
+
kind: "project-file",
|
|
9301
|
+
path: projectCaplets.paths
|
|
9302
|
+
}
|
|
9303
|
+
} : void 0], `Caplets project config not found at ${projectPath}`, void 0).config;
|
|
9304
|
+
}
|
|
9305
|
+
function buildConfigWithSources(inputs, notFoundMessage, emptyMessage) {
|
|
9306
|
+
if (!inputs.some((entry) => entry?.input !== void 0)) throw new CapletsError("CONFIG_NOT_FOUND", notFoundMessage);
|
|
9307
|
+
try {
|
|
9308
|
+
const { input, sources, shadows } = mergeConfigInputsWithSources(...inputs);
|
|
9114
9309
|
const config = parseConfig(input);
|
|
9115
|
-
if (Object.keys(config.mcpServers).length === 0 && Object.keys(config.openapiEndpoints).length === 0 && Object.keys(config.graphqlEndpoints).length === 0 && Object.keys(config.httpApis).length === 0 && Object.keys(config.cliTools).length === 0 && Object.keys(config.capletSets).length === 0) throw new CapletsError("CONFIG_INVALID",
|
|
9310
|
+
if (emptyMessage && Object.keys(config.mcpServers).length === 0 && Object.keys(config.openapiEndpoints).length === 0 && Object.keys(config.graphqlEndpoints).length === 0 && Object.keys(config.httpApis).length === 0 && Object.keys(config.cliTools).length === 0 && Object.keys(config.capletSets).length === 0) throw new CapletsError("CONFIG_INVALID", emptyMessage);
|
|
9116
9311
|
return {
|
|
9117
9312
|
config,
|
|
9118
9313
|
sources,
|
|
@@ -9123,6 +9318,74 @@ function loadConfigWithSources(path = resolveConfigPath(), projectPath = resolve
|
|
|
9123
9318
|
throw new CapletsError("CONFIG_INVALID", "Caplets config is not valid JSON", redactSecrets(error));
|
|
9124
9319
|
}
|
|
9125
9320
|
}
|
|
9321
|
+
function loadLocalOverlayConfigWithSources(path = resolveConfigPath(), projectPath = resolveProjectConfigPath()) {
|
|
9322
|
+
const warnings = [];
|
|
9323
|
+
const userConfig = existsSync(path) ? readBestEffortConfigInput(path, "global-config", warnings) : void 0;
|
|
9324
|
+
const userCaplets = loadBestEffortCapletFiles(resolveCapletsRoot(path), "global-file", warnings);
|
|
9325
|
+
const projectConfig = existsSync(projectPath) ? readBestEffortConfigInput(projectPath, "project-config", warnings, (input) => rejectProjectConfigExecutableBackendMaps(input, projectPath)) : void 0;
|
|
9326
|
+
const projectCapletsRoot = resolveProjectCapletsRootForConfigPath(projectPath);
|
|
9327
|
+
const projectCaplets = projectCapletsRoot ? loadBestEffortCapletFiles(projectCapletsRoot, "project-file", warnings) : void 0;
|
|
9328
|
+
const { input, sources, shadows } = mergeConfigInputsWithSources({
|
|
9329
|
+
input: userConfig,
|
|
9330
|
+
source: {
|
|
9331
|
+
kind: "global-config",
|
|
9332
|
+
path
|
|
9333
|
+
}
|
|
9334
|
+
}, userCaplets ? {
|
|
9335
|
+
input: userCaplets.config,
|
|
9336
|
+
source: {
|
|
9337
|
+
kind: "global-file",
|
|
9338
|
+
path: userCaplets.paths
|
|
9339
|
+
}
|
|
9340
|
+
} : void 0, {
|
|
9341
|
+
input: projectConfig,
|
|
9342
|
+
source: {
|
|
9343
|
+
kind: "project-config",
|
|
9344
|
+
path: projectPath
|
|
9345
|
+
}
|
|
9346
|
+
}, projectCaplets ? {
|
|
9347
|
+
input: projectCaplets.config,
|
|
9348
|
+
source: {
|
|
9349
|
+
kind: "project-file",
|
|
9350
|
+
path: projectCaplets.paths
|
|
9351
|
+
}
|
|
9352
|
+
} : void 0);
|
|
9353
|
+
return {
|
|
9354
|
+
config: parseConfig(input),
|
|
9355
|
+
sources,
|
|
9356
|
+
shadows,
|
|
9357
|
+
warnings
|
|
9358
|
+
};
|
|
9359
|
+
}
|
|
9360
|
+
function readBestEffortConfigInput(path, kind, warnings, transform) {
|
|
9361
|
+
try {
|
|
9362
|
+
const input = readPublicConfigInput(path);
|
|
9363
|
+
return transform ? transform(input) : input;
|
|
9364
|
+
} catch (error) {
|
|
9365
|
+
warnings.push({
|
|
9366
|
+
kind,
|
|
9367
|
+
path,
|
|
9368
|
+
message: errorMessage(error)
|
|
9369
|
+
});
|
|
9370
|
+
return;
|
|
9371
|
+
}
|
|
9372
|
+
}
|
|
9373
|
+
function loadBestEffortCapletFiles(root, kind, warnings) {
|
|
9374
|
+
const result = loadCapletFilesWithPathsBestEffort(root);
|
|
9375
|
+
if (!result) return;
|
|
9376
|
+
for (const warning of result.warnings) warnings.push({
|
|
9377
|
+
kind,
|
|
9378
|
+
path: warning.path ?? root,
|
|
9379
|
+
message: warning.message
|
|
9380
|
+
});
|
|
9381
|
+
return {
|
|
9382
|
+
config: result.config,
|
|
9383
|
+
paths: result.paths
|
|
9384
|
+
};
|
|
9385
|
+
}
|
|
9386
|
+
function errorMessage(error) {
|
|
9387
|
+
return error instanceof Error ? error.message : String(error);
|
|
9388
|
+
}
|
|
9126
9389
|
function loadIsolatedConfig(options) {
|
|
9127
9390
|
if (!options.configPath && !options.capletsRoot) throw new CapletsError("CONFIG_INVALID", "Nested Caplet set must define at least one source: configPath or capletsRoot");
|
|
9128
9391
|
const configInput = options.configPath ? readPublicConfigInput(options.configPath) : void 0;
|
|
@@ -53822,6 +54085,7 @@ var CapletsEngine = class {
|
|
|
53822
54085
|
watchDebounceMs;
|
|
53823
54086
|
watchEnabled;
|
|
53824
54087
|
writeErr;
|
|
54088
|
+
configLoader;
|
|
53825
54089
|
reloadListeners = /* @__PURE__ */ new Set();
|
|
53826
54090
|
watchers = [];
|
|
53827
54091
|
reloadTimer;
|
|
@@ -53834,7 +54098,8 @@ var CapletsEngine = class {
|
|
|
53834
54098
|
configPath: resolveConfigPath(options.configPath),
|
|
53835
54099
|
projectConfigPath: options.projectConfigPath ?? resolveProjectConfigPath()
|
|
53836
54100
|
};
|
|
53837
|
-
|
|
54101
|
+
this.configLoader = options.configLoader ?? loadConfig;
|
|
54102
|
+
const config = this.configLoader(this.paths.configPath, this.paths.projectConfigPath);
|
|
53838
54103
|
this.registry = new ServerRegistry(config);
|
|
53839
54104
|
this.downstream = new DownstreamManager(this.registry, selectAuthOptions(options.authDir));
|
|
53840
54105
|
this.openapi = new OpenApiManager(this.registry, selectAuthOptions(options.authDir));
|
|
@@ -53889,7 +54154,7 @@ var CapletsEngine = class {
|
|
|
53889
54154
|
}
|
|
53890
54155
|
}
|
|
53891
54156
|
async completeCliWords(words) {
|
|
53892
|
-
const { completeCliWords } = await import("./completion-
|
|
54157
|
+
const { completeCliWords } = await import("./completion-DRPTunQd.js").then((n) => n.r);
|
|
53893
54158
|
return await completeCliWords(words, {
|
|
53894
54159
|
config: this.registry.config,
|
|
53895
54160
|
managers: {
|
|
@@ -53949,7 +54214,7 @@ var CapletsEngine = class {
|
|
|
53949
54214
|
if (this.closed) return false;
|
|
53950
54215
|
let nextConfig;
|
|
53951
54216
|
try {
|
|
53952
|
-
nextConfig =
|
|
54217
|
+
nextConfig = this.configLoader(this.paths.configPath, this.paths.projectConfigPath);
|
|
53953
54218
|
} catch (error) {
|
|
53954
54219
|
this.writeErr(`Caplets config reload failed; keeping last known-good config.\n`);
|
|
53955
54220
|
this.writeErr(`${JSON.stringify(toSafeError(error, "CONFIG_INVALID"), null, 2)}\n`);
|
|
@@ -54229,4 +54494,4 @@ function hasEnv(value) {
|
|
|
54229
54494
|
return value !== void 0 && value.trim() !== "";
|
|
54230
54495
|
}
|
|
54231
54496
|
//#endregion
|
|
54232
|
-
export { assertCompleteRequestPrompt as $, CreateMessageResultSchema as A,
|
|
54497
|
+
export { assertCompleteRequestPrompt as $, CreateMessageResultSchema as A, CAPLETS_ERROR_CODES as At, JSONRPCMessageSchema as B, AjvJsonSchemaValidator as C, resolveCapletsRoot as Ct, CallToolRequestSchema as D, discoverCapletFiles as Dt, toJsonSchemaCompat as E, resolveProjectConfigPath as Et, EmptyResultSchema as F, __exportAll as Ft, ListRootsResultSchema as G, ListPromptsRequestSchema as H, ErrorCode as I, __require as It, McpError as J, ListToolsRequestSchema as K, GetPromptRequestSchema as L, __toESM as Lt, CreateTaskResultSchema as M, redactSecrets as Mt, DEFAULT_NEGOTIATED_PROTOCOL_VERSION as N, toSafeError as Nt, CallToolResultSchema as O, validateCapletFile as Ot, ElicitResultSchema as P, __commonJSMin as Pt, ToolListChangedNotificationSchema as Q, InitializeRequestSchema as R, assertToolsCallTaskCapability as S, DEFAULT_COMPLETION_CACHE_DIR as St, mergeCapabilities as T, resolveProjectCapletsRoot as Tt, ListResourceTemplatesRequestSchema as U, LATEST_PROTOCOL_VERSION as V, ListResourcesRequestSchema as W, SUPPORTED_PROTOCOL_VERSIONS as X, ReadResourceRequestSchema as Y, SetLevelRequestSchema as Z, StreamableHTTPClientTransport as _, loadGlobalConfig as _t, resolveCapletsServer as a, getLiteralValue as at, Client as b, parseConfig as bt, ServerRegistry as c, getSchemaDescription as ct, runOAuthFlow as d, normalizeObjectSchema as dt, assertCompleteRequestResourceTemplate as et, startGenericOAuthFlow as f, objectFromShape as ft, readTokenBundle as g, loadConfigWithSources as gt, isTokenBundleExpired as h, loadConfig as ht, resolveCapletsMode as i, isJSONRPCResultResponse as it, CreateMessageResultWithToolsSchema as j, CapletsError as jt, CompleteRequestSchema as k, SERVER_ID_PATTERN as kt, capabilityDescription as l, isSchemaOptional as lt, deleteTokenBundle as m, safeParseAsync as mt, mcpUrlForBase as n, isJSONRPCErrorResponse as nt, CapletsEngine as o, getObjectShape as ot, startOAuthFlow as p, safeParse as pt, LoggingLevelSchema as q, parseServerBaseUrl as r, isJSONRPCRequest as rt, handleServerTool as s, getParseErrorMessage as st, controlUrlForBase as t, isInitializeRequest as tt, runGenericOAuthFlow as u, isZ4Schema as ut, ReadBuffer as v, loadLocalOverlayConfigWithSources as vt, Protocol as w, resolveConfigPath as wt, assertClientRequestTaskCapability as x, DEFAULT_AUTH_DIR as xt, serializeMessage as y, loadProjectConfig as yt, InitializedNotificationSchema as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caplets/core",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
4
4
|
"description": "Core runtime library for Caplets progressive disclosure gateways.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"caplets",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
51
51
|
"commander": "^14.0.3",
|
|
52
52
|
"graphql": "^16.14.0",
|
|
53
|
-
"hono": "^4.12.
|
|
53
|
+
"hono": "^4.12.22",
|
|
54
54
|
"vfile": "^6.0.3",
|
|
55
55
|
"vfile-matter": "^5.0.1",
|
|
56
56
|
"yaml": "^2.9.0",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/node": "^25.9.1",
|
|
61
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
61
|
+
"@typescript/native-preview": "7.0.0-dev.20260523.1",
|
|
62
62
|
"rolldown": "^1.0.2",
|
|
63
63
|
"typescript": "^6.0.3",
|
|
64
64
|
"vitest": "^4.1.7"
|
|
@@ -67,8 +67,9 @@
|
|
|
67
67
|
"node": ">=22"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
|
-
"
|
|
71
|
-
"build
|
|
70
|
+
"clean": "rm -rf dist",
|
|
71
|
+
"build": "pnpm run clean && rolldown -c && tsc -p tsconfig.build.json",
|
|
72
|
+
"build:watch": "pnpm run clean && rolldown -c --watch",
|
|
72
73
|
"typecheck": "tsgo --noEmit",
|
|
73
74
|
"test": "vitest run"
|
|
74
75
|
}
|