@caplets/core 0.18.2 → 0.18.4

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.
@@ -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
- if (!hasUserConfig && !hasProjectConfig && !userCaplets && !projectCaplets) throw new CapletsError("CONFIG_NOT_FOUND", `Caplets config not found at ${path} or ${projectPath}`);
9088
- try {
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
- }, userCaplets ? {
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
- }, projectCaplets ? {
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", "Caplets config must define at least one MCP server, OpenAPI endpoint, GraphQL endpoint, HTTP API, CLI tools backend, or Caplet set");
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;
@@ -52655,8 +52918,21 @@ async function loadOpenApiSource(endpoint, authDir) {
52655
52918
  if (endpoint.specPath) return endpoint.specPath;
52656
52919
  if (!endpoint.specUrl) throw new CapletsError("CONFIG_INVALID", `${endpoint.server} is missing OpenAPI spec source`);
52657
52920
  if (!endpoint.baseUrl) throw new CapletsError("CONFIG_INVALID", `${endpoint.server} must configure baseUrl when using remote specUrl`);
52658
- const response = await fetchWithLimit(endpoint.specUrl, endpoint.requestTimeoutMs, shouldSendSpecAuth(endpoint) ? authHeaders(endpoint, authDir) : {});
52659
- return JSON.parse(response);
52921
+ return parseOpenApiSourceText(await fetchWithLimit(endpoint.specUrl, endpoint.requestTimeoutMs, shouldSendSpecAuth(endpoint) ? authHeaders(endpoint, authDir) : {}));
52922
+ }
52923
+ function parseOpenApiSourceText(source) {
52924
+ let parsed;
52925
+ try {
52926
+ parsed = JSON.parse(source);
52927
+ } catch (jsonError) {
52928
+ try {
52929
+ parsed = (0, import_dist$1.parse)(source);
52930
+ } catch {
52931
+ throw jsonError instanceof Error ? jsonError : new Error(String(jsonError));
52932
+ }
52933
+ }
52934
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI source must parse to an object");
52935
+ return parsed;
52660
52936
  }
52661
52937
  function extractOperations(endpoint, document) {
52662
52938
  const operations = [];
@@ -52674,6 +52950,7 @@ function extractOperations(endpoint, document) {
52674
52950
  const requestBody = requestBodyFor(operation);
52675
52951
  const outputSchema = outputSchemaFor(operation);
52676
52952
  const baseUrl = endpoint.baseUrl ?? firstServerUrl(document);
52953
+ const staticHeaders = staticHeaderDefaultsFor(endpoint, parameters);
52677
52954
  validateOperationBaseUrl(endpoint, baseUrl);
52678
52955
  operations.push({
52679
52956
  name,
@@ -52681,15 +52958,32 @@ function extractOperations(endpoint, document) {
52681
52958
  path,
52682
52959
  ...typeof operation.summary === "string" ? { summary: operation.summary } : {},
52683
52960
  ...typeof operation.description === "string" ? { description: operation.description } : {},
52684
- inputSchema: inputSchemaFor(parameters, requestBody),
52961
+ inputSchema: inputSchemaFor(parameters, requestBody, staticHeaders),
52685
52962
  ...outputSchema ? { outputSchema } : {},
52686
52963
  ...requestBody?.contentType ? { requestBodyContentType: requestBody.contentType } : {},
52687
- ...baseUrl ? { baseUrl } : {}
52964
+ ...baseUrl ? { baseUrl } : {},
52965
+ ...Object.keys(staticHeaders).length ? { staticHeaders } : {}
52688
52966
  });
52689
52967
  }
52690
52968
  }
52691
52969
  return operations.sort((left, right) => left.name.localeCompare(right.name));
52692
52970
  }
52971
+ function staticHeaderDefaultsFor(endpoint, parameters) {
52972
+ const configuredHeaderNames = configuredAuthHeaderNames(endpoint);
52973
+ const headers = {};
52974
+ for (const parameter of parameters) {
52975
+ if (parameter?.in !== "header" || typeof parameter.name !== "string") continue;
52976
+ const normalized = parameter.name.toLowerCase();
52977
+ if (configuredHeaderNames.has(normalized) || FORBIDDEN_ARGUMENT_HEADERS.has(normalized) && normalized !== "accept") continue;
52978
+ const defaultValue = parameter.schema?.default;
52979
+ if ([
52980
+ "string",
52981
+ "number",
52982
+ "boolean"
52983
+ ].includes(typeof defaultValue)) headers[parameter.name] = String(defaultValue);
52984
+ }
52985
+ return headers;
52986
+ }
52693
52987
  function requestBodyFor(operation) {
52694
52988
  const requestBody = operation.requestBody;
52695
52989
  if (!requestBody || typeof requestBody !== "object") return;
@@ -52750,19 +53044,20 @@ function structuredOutputSchema(bodySchema) {
52750
53044
  }
52751
53045
  };
52752
53046
  }
52753
- function inputSchemaFor(parameters, requestBody) {
53047
+ function inputSchemaFor(parameters, requestBody, staticHeaders = {}) {
52754
53048
  const schema = {
52755
53049
  type: "object",
52756
53050
  additionalProperties: false,
52757
53051
  properties: {}
52758
53052
  };
52759
53053
  const required = [];
53054
+ const protectedStaticHeaders = new Set(Object.keys(staticHeaders).map((key) => key.toLowerCase()).filter((key) => FORBIDDEN_ARGUMENT_HEADERS.has(key)));
52760
53055
  for (const location of [
52761
53056
  "path",
52762
53057
  "query",
52763
53058
  "header"
52764
53059
  ]) {
52765
- const locationParameters = parameters.filter((parameter) => parameter?.in === location);
53060
+ const locationParameters = parameters.filter((parameter) => parameter?.in === location && !(location === "header" && protectedStaticHeaders.has(parameter.name?.toLowerCase())));
52766
53061
  if (locationParameters.length === 0) continue;
52767
53062
  const nestedRequired = locationParameters.filter((parameter) => parameter.required === true || location === "path").map((parameter) => parameter.name);
52768
53063
  schema.properties[location] = {
@@ -52801,7 +53096,8 @@ function buildRequest(endpoint, operation, args, authDir) {
52801
53096
  for (const [key, value] of Object.entries(asRecord(args.query))) if (value !== void 0 && value !== null) url.searchParams.append(key, serializeHttpValue("query", key, value));
52802
53097
  const headers = new Headers();
52803
53098
  applyAuth(headers, endpoint, authDir);
52804
- const configuredHeaderNames = endpoint.auth.type === "headers" ? new Set(Object.keys(endpoint.auth.headers).map((key) => key.toLowerCase())) : /* @__PURE__ */ new Set();
53099
+ const configuredHeaderNames = configuredAuthHeaderNames(endpoint);
53100
+ for (const [key, value] of Object.entries(operation.staticHeaders ?? {})) if (!headers.has(key) && !configuredHeaderNames.has(key.toLowerCase())) headers.set(key, value);
52805
53101
  for (const [key, value] of Object.entries(asRecord(args.header))) if (value !== void 0 && value !== null) {
52806
53102
  const normalized = key.toLowerCase();
52807
53103
  if (FORBIDDEN_ARGUMENT_HEADERS.has(normalized) || configuredHeaderNames.has(normalized)) throw new CapletsError("REQUEST_INVALID", `Header ${key} cannot be supplied by arguments`);
@@ -52847,6 +53143,9 @@ function asRecord(value) {
52847
53143
  function applyAuth(headers, endpoint, authDir) {
52848
53144
  for (const [key, value] of Object.entries(authHeaders(endpoint, authDir))) headers.set(key, value);
52849
53145
  }
53146
+ function configuredAuthHeaderNames(endpoint) {
53147
+ return endpoint.auth.type === "headers" ? new Set(Object.keys(endpoint.auth.headers).map((key) => key.toLowerCase())) : /* @__PURE__ */ new Set();
53148
+ }
52850
53149
  function authHeaders(endpoint, authDir) {
52851
53150
  switch (endpoint.auth.type) {
52852
53151
  case "none": return {};
@@ -53786,6 +54085,7 @@ var CapletsEngine = class {
53786
54085
  watchDebounceMs;
53787
54086
  watchEnabled;
53788
54087
  writeErr;
54088
+ configLoader;
53789
54089
  reloadListeners = /* @__PURE__ */ new Set();
53790
54090
  watchers = [];
53791
54091
  reloadTimer;
@@ -53798,7 +54098,8 @@ var CapletsEngine = class {
53798
54098
  configPath: resolveConfigPath(options.configPath),
53799
54099
  projectConfigPath: options.projectConfigPath ?? resolveProjectConfigPath()
53800
54100
  };
53801
- const config = loadConfig(this.paths.configPath, this.paths.projectConfigPath);
54101
+ this.configLoader = options.configLoader ?? loadConfig;
54102
+ const config = this.configLoader(this.paths.configPath, this.paths.projectConfigPath);
53802
54103
  this.registry = new ServerRegistry(config);
53803
54104
  this.downstream = new DownstreamManager(this.registry, selectAuthOptions(options.authDir));
53804
54105
  this.openapi = new OpenApiManager(this.registry, selectAuthOptions(options.authDir));
@@ -53853,7 +54154,7 @@ var CapletsEngine = class {
53853
54154
  }
53854
54155
  }
53855
54156
  async completeCliWords(words) {
53856
- const { completeCliWords } = await import("./completion-L23s2FGB.js").then((n) => n.r);
54157
+ const { completeCliWords } = await import("./completion-DRPTunQd.js").then((n) => n.r);
53857
54158
  return await completeCliWords(words, {
53858
54159
  config: this.registry.config,
53859
54160
  managers: {
@@ -53913,7 +54214,7 @@ var CapletsEngine = class {
53913
54214
  if (this.closed) return false;
53914
54215
  let nextConfig;
53915
54216
  try {
53916
- nextConfig = loadConfig(this.paths.configPath, this.paths.projectConfigPath);
54217
+ nextConfig = this.configLoader(this.paths.configPath, this.paths.projectConfigPath);
53917
54218
  } catch (error) {
53918
54219
  this.writeErr(`Caplets config reload failed; keeping last known-good config.\n`);
53919
54220
  this.writeErr(`${JSON.stringify(toSafeError(error, "CONFIG_INVALID"), null, 2)}\n`);
@@ -54193,4 +54494,4 @@ function hasEnv(value) {
54193
54494
  return value !== void 0 && value.trim() !== "";
54194
54495
  }
54195
54496
  //#endregion
54196
- export { assertCompleteRequestPrompt as $, CreateMessageResultSchema as A, toSafeError as At, JSONRPCMessageSchema as B, AjvJsonSchemaValidator as C, resolveProjectConfigPath as Ct, CallToolRequestSchema as D, CAPLETS_ERROR_CODES as Dt, toJsonSchemaCompat as E, SERVER_ID_PATTERN as Et, EmptyResultSchema as F, ListRootsResultSchema as G, ListPromptsRequestSchema as H, ErrorCode as I, McpError as J, ListToolsRequestSchema as K, GetPromptRequestSchema as L, CreateTaskResultSchema as M, __exportAll as Mt, DEFAULT_NEGOTIATED_PROTOCOL_VERSION as N, __require as Nt, CallToolResultSchema as O, CapletsError as Ot, ElicitResultSchema as P, __toESM as Pt, ToolListChangedNotificationSchema as Q, InitializeRequestSchema as R, assertToolsCallTaskCapability as S, resolveProjectCapletsRoot as St, mergeCapabilities as T, validateCapletFile 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 _, parseConfig as _t, resolveCapletsServer as a, getLiteralValue as at, Client as b, resolveCapletsRoot 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, __commonJSMin as jt, CompleteRequestSchema as k, redactSecrets 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, DEFAULT_AUTH_DIR as vt, Protocol as w, discoverCapletFiles as wt, assertClientRequestTaskCapability as x, resolveConfigPath as xt, serializeMessage as y, DEFAULT_COMPLETION_CACHE_DIR as yt, InitializedNotificationSchema as z };
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.2",
3
+ "version": "0.18.4",
4
4
  "description": "Core runtime library for Caplets progressive disclosure gateways.",
5
5
  "keywords": [
6
6
  "caplets",
@@ -50,14 +50,15 @@
50
50
  "@modelcontextprotocol/sdk": "^1.29.0",
51
51
  "commander": "^14.0.3",
52
52
  "graphql": "^16.14.0",
53
- "hono": "^4.12.21",
53
+ "hono": "^4.12.22",
54
54
  "vfile": "^6.0.3",
55
55
  "vfile-matter": "^5.0.1",
56
+ "yaml": "^2.9.0",
56
57
  "zod": "^4.4.3"
57
58
  },
58
59
  "devDependencies": {
59
60
  "@types/node": "^25.9.1",
60
- "@typescript/native-preview": "7.0.0-dev.20260519.1",
61
+ "@typescript/native-preview": "7.0.0-dev.20260523.1",
61
62
  "rolldown": "^1.0.2",
62
63
  "typescript": "^6.0.3",
63
64
  "vitest": "^4.1.7"
@@ -66,8 +67,9 @@
66
67
  "node": ">=22"
67
68
  },
68
69
  "scripts": {
69
- "build": "rm -rf dist && rolldown -c && tsc -p tsconfig.build.json",
70
- "build:watch": "rolldown -c --watch",
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",
71
73
  "typecheck": "tsgo --noEmit",
72
74
  "test": "vitest run"
73
75
  }