@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.
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as assertCompleteRequestPrompt, A as CreateMessageResultSchema, At as toSafeError, B as JSONRPCMessageSchema, C as AjvJsonSchemaValidator, D as CallToolRequestSchema, Dt as CAPLETS_ERROR_CODES, E as toJsonSchemaCompat, Et as SERVER_ID_PATTERN, F as EmptyResultSchema, G as ListRootsResultSchema, H as ListPromptsRequestSchema, I as ErrorCode, J as McpError, K as ListToolsRequestSchema, L as GetPromptRequestSchema, M as CreateTaskResultSchema, Nt as __require, O as CallToolResultSchema, Ot as CapletsError, P as ElicitResultSchema, Pt as __toESM, R as InitializeRequestSchema, S as assertToolsCallTaskCapability, St as resolveProjectCapletsRoot, T as mergeCapabilities, Tt as validateCapletFile, U as ListResourceTemplatesRequestSchema, V as LATEST_PROTOCOL_VERSION, W as ListResourcesRequestSchema, X as SUPPORTED_PROTOCOL_VERSIONS, Y as ReadResourceRequestSchema, Z as SetLevelRequestSchema, _t as parseConfig, a as resolveCapletsServer, at as getLiteralValue, bt as resolveCapletsRoot, c as ServerRegistry, ct as getSchemaDescription, d as runOAuthFlow, dt as normalizeObjectSchema, et as assertCompleteRequestResourceTemplate, f as startGenericOAuthFlow, ft as objectFromShape, g as readTokenBundle, gt as loadConfigWithSources, h as isTokenBundleExpired, ht as loadConfig, i as resolveCapletsMode, it as isJSONRPCResultResponse, j as CreateMessageResultWithToolsSchema, jt as __commonJSMin, k as CompleteRequestSchema, kt as redactSecrets, l as capabilityDescription, lt as isSchemaOptional, m as deleteTokenBundle, mt as safeParseAsync, nt as isJSONRPCErrorResponse, o as CapletsEngine, ot as getObjectShape, p as startOAuthFlow, pt as safeParse, q as LoggingLevelSchema, r as parseServerBaseUrl, rt as isJSONRPCRequest, s as handleServerTool, st as getParseErrorMessage, t as controlUrlForBase, tt as isInitializeRequest, u as runGenericOAuthFlow, ut as isZ4Schema, v as ReadBuffer, w as Protocol, wt as discoverCapletFiles, x as assertClientRequestTaskCapability, xt as resolveConfigPath, y as serializeMessage, z as InitializedNotificationSchema } from "./options-bnsSREid.js";
1
+ import { $ as assertCompleteRequestPrompt, A as CreateMessageResultSchema, At as CAPLETS_ERROR_CODES, B as JSONRPCMessageSchema, C as AjvJsonSchemaValidator, Ct as resolveCapletsRoot, D as CallToolRequestSchema, Dt as discoverCapletFiles, E as toJsonSchemaCompat, Et as resolveProjectConfigPath, F as EmptyResultSchema, G as ListRootsResultSchema, H as ListPromptsRequestSchema, I as ErrorCode, It as __require, J as McpError, K as ListToolsRequestSchema, L as GetPromptRequestSchema, Lt as __toESM, M as CreateTaskResultSchema, Mt as redactSecrets, Nt as toSafeError, O as CallToolResultSchema, Ot as validateCapletFile, P as ElicitResultSchema, Pt as __commonJSMin, R as InitializeRequestSchema, S as assertToolsCallTaskCapability, T as mergeCapabilities, Tt as resolveProjectCapletsRoot, U as ListResourceTemplatesRequestSchema, V as LATEST_PROTOCOL_VERSION, W as ListResourcesRequestSchema, X as SUPPORTED_PROTOCOL_VERSIONS, Y as ReadResourceRequestSchema, Z as SetLevelRequestSchema, _t as loadGlobalConfig, a as resolveCapletsServer, at as getLiteralValue, bt as parseConfig, c as ServerRegistry, ct as getSchemaDescription, d as runOAuthFlow, dt as normalizeObjectSchema, et as assertCompleteRequestResourceTemplate, f as startGenericOAuthFlow, ft as objectFromShape, g as readTokenBundle, gt as loadConfigWithSources, h as isTokenBundleExpired, ht as loadConfig, i as resolveCapletsMode, it as isJSONRPCResultResponse, j as CreateMessageResultWithToolsSchema, jt as CapletsError, k as CompleteRequestSchema, kt as SERVER_ID_PATTERN, l as capabilityDescription, lt as isSchemaOptional, m as deleteTokenBundle, mt as safeParseAsync, nt as isJSONRPCErrorResponse, o as CapletsEngine, ot as getObjectShape, p as startOAuthFlow, pt as safeParse, q as LoggingLevelSchema, r as parseServerBaseUrl, rt as isJSONRPCRequest, s as handleServerTool, st as getParseErrorMessage, t as controlUrlForBase, tt as isInitializeRequest, u as runGenericOAuthFlow, ut as isZ4Schema, v as ReadBuffer, vt as loadLocalOverlayConfigWithSources, w as Protocol, wt as resolveConfigPath, x as assertClientRequestTaskCapability, y as serializeMessage, yt as loadProjectConfig, z as InitializedNotificationSchema } from "./options-BlNyqF_E.js";
2
2
  import { A as url, C as object, D as string, b as literal, d as ZodOptional, o as generatedToolInputSchema, s as generatedToolInputSchemaForCaplet } from "./generated-tool-input-schema-BYoyY-l-.js";
3
- import { a as formatCapletList, c as resolveCliConfigPaths, l as cliCommands, n as completionScript, o as formatConfigPaths, s as listCaplets, t as completeCliWords, u as completionShells } from "./completion-L23s2FGB.js";
4
- import { accessSync, chmodSync, closeSync, constants, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
5
- import { basename, dirname, join, parse, relative, resolve } from "node:path";
3
+ import { a as formatCapletList, c as resolveCliConfigPaths, l as cliCommands, n as completionScript, o as formatConfigPaths, s as listCaplets, t as completeCliWords, u as completionShells } from "./completion-DRPTunQd.js";
4
+ import { accessSync, chmodSync, closeSync, constants, copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
5
+ import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
6
6
  import { execFileSync } from "node:child_process";
7
7
  import process$1, { stdin, stdout } from "node:process";
8
8
  import { tmpdir } from "node:os";
@@ -1320,7 +1320,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
1320
1320
  } };
1321
1321
  //#endregion
1322
1322
  //#region package.json
1323
- var version = "0.18.2";
1323
+ var version = "0.18.4";
1324
1324
  //#endregion
1325
1325
  //#region src/serve/session.ts
1326
1326
  var CapletsMcpSession = class {
@@ -4905,7 +4905,7 @@ function isUrlLike(value) {
4905
4905
  //#endregion
4906
4906
  //#region src/cli/auth.ts
4907
4907
  async function loginAuth(serverId, options) {
4908
- const server = findAuthTarget(serverId, loadConfig(options.configPath));
4908
+ const server = findAuthTarget(serverId, options.config ?? loadConfig(options.configPath));
4909
4909
  assertLoginTarget(server, serverId);
4910
4910
  try {
4911
4911
  const flowOptions = {
@@ -4927,40 +4927,64 @@ function logoutAuth(serverId, options) {
4927
4927
  else options.writeOut(`No OAuth credentials found for \`${serverId}\`.\n`);
4928
4928
  }
4929
4929
  function logoutAuthResult(serverId, options) {
4930
- assertLoginTarget(findAuthTarget(serverId, loadConfig(options.configPath)), serverId);
4930
+ assertLoginTarget(findAuthTarget(serverId, options.config ?? loadConfig(options.configPath)), serverId);
4931
4931
  return {
4932
4932
  server: serverId,
4933
4933
  deleted: deleteTokenBundle(serverId, options.authDir)
4934
4934
  };
4935
4935
  }
4936
- function listAuth(options) {
4937
- const rows = listAuthRows(options);
4938
- const format = options.format ?? "plain";
4939
- if (format === "json") {
4940
- options.writeOut(`${JSON.stringify(rows, null, 2)}\n`);
4941
- return;
4936
+ function listAuthRows(options) {
4937
+ return authRowsForTargets(authTargets(loadConfig(options.configPath)), options.authDir);
4938
+ }
4939
+ function listLocalAuthRows(options) {
4940
+ return authRowsForTargets(localAuthTargets(options), options.authDir);
4941
+ }
4942
+ function localAuthTargets(options) {
4943
+ return [...options.source === "project" ? [] : authTargetsForSource("global", options), ...options.source === "global" ? [] : authTargetsForSource("project", options)].filter((target) => !options.source || target.source === options.source);
4944
+ }
4945
+ function localAuthConfigForTarget(options) {
4946
+ assertLoginTarget(localAuthTargets(options).find((candidate) => candidate.server === options.serverId), options.serverId);
4947
+ return loadConfigForSource(options.source, options);
4948
+ }
4949
+ function authTargetsForSource(source, options) {
4950
+ try {
4951
+ return authTargets(loadConfigForSource(source, options)).map((target) => ({
4952
+ ...target,
4953
+ source
4954
+ }));
4955
+ } catch (error) {
4956
+ if (error instanceof CapletsError && error.code === "CONFIG_NOT_FOUND") return [];
4957
+ throw error;
4942
4958
  }
4943
- options.writeOut(formatAuthRows(rows, format));
4944
4959
  }
4945
- function listAuthRows(options) {
4946
- return authTargets(loadConfig(options.configPath)).sort((left, right) => left.server.localeCompare(right.server)).map((server) => {
4947
- const bundle = readTokenBundle(server.server, options.authDir);
4960
+ function loadConfigForSource(source, options) {
4961
+ if (source === "global") return loadGlobalConfig(options.configPath);
4962
+ return loadProjectConfig(options.projectConfigPath);
4963
+ }
4964
+ function authRowsForTargets(targets, authDir) {
4965
+ return targets.sort((left, right) => left.server.localeCompare(right.server)).map((server) => {
4966
+ const bundle = readTokenBundle(server.server, authDir);
4948
4967
  const status = !bundle ? "missing" : isTokenBundleExpired(bundle) ? "expired" : "authenticated";
4949
4968
  return {
4950
4969
  server: server.server,
4951
4970
  status,
4952
4971
  ...bundle?.expiresAt ? { expiresAt: bundle.expiresAt } : {},
4953
- ...bundle?.scope ? { scope: bundle.scope } : {}
4972
+ ...bundle?.scope ? { scope: bundle.scope } : {},
4973
+ ...server.source ? { source: server.source } : {}
4954
4974
  };
4955
4975
  });
4956
4976
  }
4957
4977
  function formatAuthRows(rows, format) {
4958
- if (rows.length === 0) return format === "markdown" ? "## OAuth credentials\n\nNo configured remote OAuth servers found.\n" : "No configured remote OAuth servers found.\n";
4978
+ if (rows.length === 0) return format === "markdown" ? "## OAuth credentials\n\nNo configured OAuth servers found.\n" : "No configured OAuth servers found.\n";
4959
4979
  let output = "";
4960
4980
  if (format === "markdown") output += "## OAuth credentials\n\n";
4961
4981
  else output += "OAuth credentials\n\n";
4962
4982
  for (const row of rows) {
4963
- const details = [row.expiresAt ? `expires ${row.expiresAt}` : void 0, row.scope ? `scope ${row.scope}` : void 0].filter(Boolean).join("; ");
4983
+ const details = [
4984
+ row.source ? `source ${row.source}` : void 0,
4985
+ row.expiresAt ? `expires ${row.expiresAt}` : void 0,
4986
+ row.scope ? `scope ${row.scope}` : void 0
4987
+ ].filter(Boolean).join("; ");
4964
4988
  if (format === "markdown") {
4965
4989
  output += `- \`${row.server}\` — ${row.status}${details ? ` (${details})` : ""}\n`;
4966
4990
  continue;
@@ -4968,6 +4992,7 @@ function formatAuthRows(rows, format) {
4968
4992
  output += [
4969
4993
  row.server,
4970
4994
  ` Status: ${row.status}`,
4995
+ ...row.source ? [` Source: ${row.source}`] : [],
4971
4996
  ...row.expiresAt ? [` Expires: ${row.expiresAt}`] : [],
4972
4997
  ...row.scope ? [` Scope: ${row.scope}`] : []
4973
4998
  ].join("\n") + "\n\n";
@@ -5192,12 +5217,14 @@ function rejectCrossKindDestinationCollision(plan, destinationRoot) {
5192
5217
  function installPlan(caplet, options) {
5193
5218
  const isDirectory = basename(caplet.path) === "CAPLET.md";
5194
5219
  const sourcePath = isDirectory ? dirname(caplet.path) : caplet.path;
5220
+ const sourceBoundary = dirname(sourcePath);
5195
5221
  const sourcePathRelative = relative(options.repoRoot, sourcePath);
5196
5222
  const destination = isDirectory ? join(options.destinationRoot, caplet.id) : join(options.destinationRoot, `${caplet.id}.md`);
5197
5223
  return {
5198
5224
  id: caplet.id,
5199
5225
  source: `${options.sourceId}#${sourcePathRelative}`,
5200
5226
  sourcePath,
5227
+ sourceBoundary,
5201
5228
  destination,
5202
5229
  kind: isDirectory ? "directory" : "file"
5203
5230
  };
@@ -5259,16 +5286,40 @@ function removeInstallPath(path, label, force) {
5259
5286
  }
5260
5287
  function copyInstallPath(plan) {
5261
5288
  try {
5289
+ if (plan.kind === "directory") {
5290
+ copyDirectoryCaplet(plan.sourcePath, plan.destination, realpathSync(plan.sourceBoundary));
5291
+ return;
5292
+ }
5262
5293
  cpSync(plan.sourcePath, plan.destination, {
5263
- recursive: plan.kind === "directory",
5294
+ recursive: false,
5264
5295
  force: false,
5265
5296
  errorOnExist: true
5266
5297
  });
5267
5298
  } catch (error) {
5299
+ if (error instanceof CapletsError) throw error;
5268
5300
  if (isFsError(error, "EEXIST") || isFsError(error, "EISDIR")) throw new CapletsError("CONFIG_EXISTS", `Caplet ${plan.id} already exists at ${plan.destination}; pass --force to overwrite it`, toSafeError(error));
5269
5301
  throw new CapletsError("CONFIG_INVALID", `Could not install Caplet ${plan.id} to ${plan.destination}`, toSafeError(error));
5270
5302
  }
5271
5303
  }
5304
+ function copyDirectoryCaplet(source, destination, sourceBoundary, seenDirectories = /* @__PURE__ */ new Set()) {
5305
+ const resolvedSource = lstatSync(source).isSymbolicLink() ? resolveDirectoryCapletSymlink(source, sourceBoundary) : source;
5306
+ if (statSync(resolvedSource).isDirectory()) {
5307
+ const realDirectory = realpathSync(resolvedSource);
5308
+ if (seenDirectories.has(realDirectory)) throw new CapletsError("CONFIG_INVALID", `Directory Caplet symlink ${source} creates a copy cycle`);
5309
+ const childSeenDirectories = new Set(seenDirectories);
5310
+ childSeenDirectories.add(realDirectory);
5311
+ mkdirSync(destination);
5312
+ for (const entry of readdirSync(resolvedSource)) copyDirectoryCaplet(join(resolvedSource, entry), join(destination, entry), sourceBoundary, childSeenDirectories);
5313
+ return;
5314
+ }
5315
+ copyFileSync(resolvedSource, destination);
5316
+ }
5317
+ function resolveDirectoryCapletSymlink(source, sourceBoundary) {
5318
+ const target = readlinkSync(source);
5319
+ const resolvedTarget = realpathSync(isAbsolute(target) ? target : resolve(dirname(source), target));
5320
+ if (resolvedTarget !== sourceBoundary && !resolvedTarget.startsWith(`${sourceBoundary}${sep}`)) throw new CapletsError("CONFIG_INVALID", `Directory Caplet symlink ${source} resolves outside source Caplets boundary`);
5321
+ return resolvedTarget;
5322
+ }
5272
5323
  function isFsError(error, code) {
5273
5324
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
5274
5325
  }
@@ -5369,7 +5420,7 @@ function redactRemoteMessage(message) {
5369
5420
  return String(redactSecrets(message)).replace(/\b(authorization\s*:\s*(?:basic|bearer)\s+)[^\s,;]+/giu, "$1[REDACTED]").replace(/\b((?:access_)?token=)[^\s,;]+/giu, "$1[REDACTED]").replace(/\b((?:token|secret|authorization|auth|api[-_]?key|password|credential|clientsecret|client_secret|code|refresh(?:_token)?)\s*[=:]\s*)[^\s,;]+/giu, "$1[REDACTED]");
5370
5421
  }
5371
5422
  //#endregion
5372
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/compose.js
5423
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/compose.js
5373
5424
  var compose = (middleware, onError, onNotFound) => {
5374
5425
  return (context, next) => {
5375
5426
  let index = -1;
@@ -5400,7 +5451,7 @@ var compose = (middleware, onError, onNotFound) => {
5400
5451
  };
5401
5452
  };
5402
5453
  //#endregion
5403
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/http-exception.js
5454
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/http-exception.js
5404
5455
  var HTTPException = class extends Error {
5405
5456
  res;
5406
5457
  status;
@@ -5428,10 +5479,10 @@ var HTTPException = class extends Error {
5428
5479
  }
5429
5480
  };
5430
5481
  //#endregion
5431
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/request/constants.js
5482
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/request/constants.js
5432
5483
  var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
5433
5484
  //#endregion
5434
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/utils/body.js
5485
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/utils/body.js
5435
5486
  var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
5436
5487
  const { all = false, dot = false } = options;
5437
5488
  const contentType = (request instanceof HonoRequest ? request.raw.headers : request.headers).get("Content-Type");
@@ -5479,7 +5530,7 @@ var handleParsingNestedValues = (form, key, value) => {
5479
5530
  });
5480
5531
  };
5481
5532
  //#endregion
5482
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/utils/url.js
5533
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/utils/url.js
5483
5534
  var splitPath = (path) => {
5484
5535
  const paths = path.split("/");
5485
5536
  if (paths[0] === "") paths.shift();
@@ -5643,7 +5694,7 @@ var getQueryParams = (url, key) => {
5643
5694
  };
5644
5695
  var decodeURIComponent_ = decodeURIComponent;
5645
5696
  //#endregion
5646
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/request.js
5697
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/request.js
5647
5698
  var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
5648
5699
  var HonoRequest = class {
5649
5700
  /**
@@ -5915,7 +5966,7 @@ var HonoRequest = class {
5915
5966
  }
5916
5967
  };
5917
5968
  //#endregion
5918
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/utils/html.js
5969
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/utils/html.js
5919
5970
  var HtmlEscapedCallbackPhase = {
5920
5971
  Stringify: 1,
5921
5972
  BeforeStream: 2,
@@ -5945,7 +5996,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
5945
5996
  else return resStr;
5946
5997
  };
5947
5998
  //#endregion
5948
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/context.js
5999
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/context.js
5949
6000
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
5950
6001
  var setDefaultContentType = (contentType, headers) => {
5951
6002
  return {
@@ -6306,7 +6357,7 @@ var Context = class {
6306
6357
  };
6307
6358
  };
6308
6359
  //#endregion
6309
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router.js
6360
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router.js
6310
6361
  var METHODS = [
6311
6362
  "get",
6312
6363
  "post",
@@ -6318,10 +6369,10 @@ var METHODS = [
6318
6369
  var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
6319
6370
  var UnsupportedPathError = class extends Error {};
6320
6371
  //#endregion
6321
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/utils/constants.js
6372
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/utils/constants.js
6322
6373
  var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
6323
6374
  //#endregion
6324
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/hono-base.js
6375
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/hono-base.js
6325
6376
  var notFoundHandler = (c) => {
6326
6377
  return c.text("404 Not Found", 404);
6327
6378
  };
@@ -6655,7 +6706,7 @@ var Hono$1 = class _Hono {
6655
6706
  };
6656
6707
  };
6657
6708
  //#endregion
6658
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/reg-exp-router/matcher.js
6709
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/reg-exp-router/matcher.js
6659
6710
  var emptyParam = [];
6660
6711
  function match(method, path) {
6661
6712
  const matchers = this.buildAllMatchers();
@@ -6672,7 +6723,7 @@ function match(method, path) {
6672
6723
  return match2(method, path);
6673
6724
  }
6674
6725
  //#endregion
6675
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/reg-exp-router/node.js
6726
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/reg-exp-router/node.js
6676
6727
  var LABEL_REG_EXP_STR = "[^/]+";
6677
6728
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
6678
6729
  var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
@@ -6751,7 +6802,7 @@ var Node$1 = class _Node {
6751
6802
  }
6752
6803
  };
6753
6804
  //#endregion
6754
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/reg-exp-router/trie.js
6805
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/reg-exp-router/trie.js
6755
6806
  var Trie = class {
6756
6807
  #context = { varIndex: 0 };
6757
6808
  #root = new Node$1();
@@ -6809,7 +6860,7 @@ var Trie = class {
6809
6860
  }
6810
6861
  };
6811
6862
  //#endregion
6812
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/reg-exp-router/router.js
6863
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/reg-exp-router/router.js
6813
6864
  var nullMatcher = [
6814
6865
  /^$/,
6815
6866
  [],
@@ -6940,7 +6991,7 @@ var RegExpRouter = class {
6940
6991
  }
6941
6992
  };
6942
6993
  //#endregion
6943
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/smart-router/router.js
6994
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/smart-router/router.js
6944
6995
  var SmartRouter = class {
6945
6996
  name = "SmartRouter";
6946
6997
  #routers = [];
@@ -6987,7 +7038,7 @@ var SmartRouter = class {
6987
7038
  }
6988
7039
  };
6989
7040
  //#endregion
6990
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/trie-router/node.js
7041
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/trie-router/node.js
6991
7042
  var emptyParams = /* @__PURE__ */ Object.create(null);
6992
7043
  var hasChildren = (children) => {
6993
7044
  for (const _ in children) return true;
@@ -7140,7 +7191,7 @@ var Node = class _Node {
7140
7191
  }
7141
7192
  };
7142
7193
  //#endregion
7143
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/router/trie-router/router.js
7194
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/router/trie-router/router.js
7144
7195
  var TrieRouter = class {
7145
7196
  name = "TrieRouter";
7146
7197
  #node;
@@ -7160,7 +7211,7 @@ var TrieRouter = class {
7160
7211
  }
7161
7212
  };
7162
7213
  //#endregion
7163
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/hono.js
7214
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/hono.js
7164
7215
  var Hono = class extends Hono$1 {
7165
7216
  /**
7166
7217
  * Creates an instance of the Hono class.
@@ -7201,7 +7252,7 @@ object({
7201
7252
  client_secret: string().optional()
7202
7253
  });
7203
7254
  //#endregion
7204
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/utils/stream.js
7255
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/utils/stream.js
7205
7256
  var StreamingApi = class {
7206
7257
  writer;
7207
7258
  encoder;
@@ -7274,7 +7325,7 @@ var StreamingApi = class {
7274
7325
  }
7275
7326
  };
7276
7327
  //#endregion
7277
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/helper/streaming/sse.js
7328
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/helper/streaming/sse.js
7278
7329
  var SSEStreamingApi = class extends StreamingApi {
7279
7330
  constructor(writable, readable) {
7280
7331
  super(writable, readable);
@@ -7298,7 +7349,7 @@ var SSEStreamingApi = class extends StreamingApi {
7298
7349
  }
7299
7350
  };
7300
7351
  //#endregion
7301
- //#region ../../node_modules/.pnpm/@hono+mcp@0.3.0_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__hono-rate-limiter@0.5.3_hono@4.12.21__hono@4.12.21_zod@4.4.3/node_modules/@hono/mcp/dist/index.js
7352
+ //#region ../../node_modules/.pnpm/@hono+mcp@0.3.0_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__hono-rate-limiter@0.5.3_hono@4.12.22__hono@4.12.22_zod@4.4.3/node_modules/@hono/mcp/dist/index.js
7302
7353
  let isOldBunVersion = () => {
7303
7354
  const version = typeof Bun !== "undefined" ? Bun.version : void 0;
7304
7355
  if (version === void 0) return false;
@@ -7739,7 +7790,7 @@ var StreamableHTTPTransport = class {
7739
7790
  }
7740
7791
  };
7741
7792
  //#endregion
7742
- //#region ../../node_modules/.pnpm/@hono+node-server@2.0.3_hono@4.12.21/node_modules/@hono/node-server/dist/index.mjs
7793
+ //#region ../../node_modules/.pnpm/@hono+node-server@2.0.3_hono@4.12.22/node_modules/@hono/node-server/dist/index.mjs
7743
7794
  var RequestError = class extends Error {
7744
7795
  constructor(message, options) {
7745
7796
  super(message, options);
@@ -8662,7 +8713,7 @@ const serve = (options, listeningListener) => {
8662
8713
  return server;
8663
8714
  };
8664
8715
  //#endregion
8665
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/utils/color.js
8716
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/utils/color.js
8666
8717
  function getColorEnabled() {
8667
8718
  const { process, Deno } = globalThis;
8668
8719
  return !(typeof Deno?.noColor === "boolean" ? Deno.noColor : process !== void 0 ? "NO_COLOR" in process?.env : false);
@@ -8679,7 +8730,7 @@ async function getColorEnabledAsync() {
8679
8730
  })() : !getColorEnabled());
8680
8731
  }
8681
8732
  //#endregion
8682
- //#region ../../node_modules/.pnpm/hono@4.12.21/node_modules/hono/dist/middleware/logger/index.js
8733
+ //#region ../../node_modules/.pnpm/hono@4.12.22/node_modules/hono/dist/middleware/logger/index.js
8683
8734
  var humanize = (times) => {
8684
8735
  const [delimiter, separator] = [",", "."];
8685
8736
  return times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter)).join(separator);
@@ -9517,15 +9568,29 @@ function createProgram(io = {}) {
9517
9568
  const completionWords = normalizeCompletionWords(words);
9518
9569
  let suggestions = [];
9519
9570
  try {
9520
- suggestions = remote ? await remote.request("complete_cli", {
9521
- shell,
9522
- words: completionWords
9523
- }) : await completeCliWordsLocally(completionWords, {
9571
+ if (remote) {
9572
+ const localOverlay = loadLocalOverlayForCli(io, () => {});
9573
+ const localSuggestions = await completeCliWordsLocally(completionWords, {
9574
+ ...configPath ? { configPath } : {},
9575
+ projectConfigPath: envProjectConfigPath(env),
9576
+ ...io.authDir ? { authDir: io.authDir } : {},
9577
+ config: localOverlay.config
9578
+ });
9579
+ if (localShadowedCompletionTarget(completionWords, localOverlay.config)) suggestions = localSuggestions;
9580
+ else suggestions = mergeCompletionSuggestions(localSuggestions, await remote.request("complete_cli", {
9581
+ shell,
9582
+ words: completionWords
9583
+ }));
9584
+ } else suggestions = await completeCliWordsLocally(completionWords, {
9524
9585
  ...configPath ? { configPath } : {},
9586
+ projectConfigPath: envProjectConfigPath(env),
9525
9587
  ...io.authDir ? { authDir: io.authDir } : {}
9526
9588
  });
9527
9589
  } catch {
9528
- suggestions = remote ? [] : await completeCliWords(completionWords, configPath ? { configPath } : {});
9590
+ suggestions = remote ? [] : await completeCliWords(completionWords, {
9591
+ ...configPath ? { configPath } : {},
9592
+ projectConfigPath: envProjectConfigPath(env)
9593
+ });
9529
9594
  }
9530
9595
  if (suggestions.length > 0) writeOut(`${suggestions.join("\n")}\n`);
9531
9596
  });
@@ -9537,23 +9602,26 @@ function createProgram(io = {}) {
9537
9602
  ...io.authDir ? { authDir: io.authDir } : {}
9538
9603
  }, writeErr)))(resolved);
9539
9604
  });
9540
- program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
9541
- const remote = remoteClientForCli(io);
9542
- if (remote) {
9543
- writeOut(`Created remote Caplets config at ${(await remote.request("init", { force: Boolean(options.force) })).path}\n`);
9605
+ program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--project", "create the project Caplets config").option("-g, --global", "create the user Caplets config").option("--remote", "create the remote Caplets config").option("--force", "overwrite an existing config file").action(async (options) => {
9606
+ const target = parseMutationTarget(options);
9607
+ if (target === "remote") {
9608
+ writeOut(`Created remote Caplets config at ${(await requireRemoteClientForTarget(io).request("init", { force: Boolean(options.force) })).path}\n`);
9544
9609
  return;
9545
9610
  }
9546
- const configPath = currentConfigPath();
9547
- writeOut(`Created Caplets config at ${initConfig({
9548
- ...configPath ? { path: configPath } : {},
9611
+ const path = initConfig({
9612
+ path: target === "global" ? resolveConfigPath(currentConfigPath()) : envProjectConfigPath(env),
9549
9613
  force: Boolean(options.force)
9550
- })}\n`);
9614
+ });
9615
+ writeOut(`Created ${localMutationTargetLabel(target, io)}Caplets config at ${path}\n`);
9551
9616
  });
9552
9617
  program.command(cliCommands.list).description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action(async (options) => {
9553
9618
  const includeDisabled = Boolean(options.all);
9554
9619
  const remote = remoteClientForCli(io);
9555
9620
  if (remote) {
9556
- const rows = await remote.request("list", { includeDisabled });
9621
+ const rows = mergeRemoteAndLocalRows(await remote.request("list", { includeDisabled }), tryLoadLocalOverlayForCli(io, writeErr), {
9622
+ includeDisabled,
9623
+ writeErr
9624
+ });
9557
9625
  if (options.json || options.format === "json") {
9558
9626
  writeOut(`${JSON.stringify(rows, null, 2)}\n`);
9559
9627
  return;
@@ -9561,18 +9629,17 @@ function createProgram(io = {}) {
9561
9629
  writeOut(formatCapletList(rows, options.format ?? "plain"));
9562
9630
  return;
9563
9631
  }
9564
- const rows = listCaplets(loadConfigWithSources(currentConfigPath()), { includeDisabled });
9632
+ const rows = listCaplets(loadConfigWithSources(currentConfigPath(), envProjectConfigPath(env)), { includeDisabled });
9565
9633
  if (options.json || options.format === "json") {
9566
9634
  writeOut(`${JSON.stringify(rows, null, 2)}\n`);
9567
9635
  return;
9568
9636
  }
9569
9637
  writeOut(formatCapletList(rows, options.format ?? "plain"));
9570
9638
  });
9571
- program.command(cliCommands.install).description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("-g, --global", "install to the user Caplets root").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
9572
- const remote = remoteClientForCli(io);
9573
- if (remote) {
9574
- if (options.global) writeErr("Warning: --global is not supported in remote mode; the server controls the installation destination.\n");
9575
- const result = await remote.request("install", {
9639
+ program.command(cliCommands.install).description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("--project", "install to the project Caplets root").option("-g, --global", "install to the user Caplets root").option("--remote", "install through remote control").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
9640
+ const target = parseMutationTarget(options);
9641
+ if (target === "remote") {
9642
+ const result = await requireRemoteClientForTarget(io).request("install", {
9576
9643
  repo,
9577
9644
  capletIds,
9578
9645
  force: Boolean(options.force)
@@ -9583,15 +9650,15 @@ function createProgram(io = {}) {
9583
9650
  const result = installCaplets(repo, {
9584
9651
  capletIds,
9585
9652
  force: Boolean(options.force),
9586
- destinationRoot: options.global ? resolveCapletsRoot(resolveConfigPath(currentConfigPath())) : resolveProjectCapletsRoot()
9653
+ destinationRoot: target === "global" ? resolveCapletsRoot(resolveConfigPath(currentConfigPath())) : envProjectCapletsRoot(env)
9587
9654
  });
9588
- for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${caplet.destination}\n`);
9655
+ for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${localMutationTargetLabel(target, io)}${caplet.destination}\n`);
9589
9656
  });
9590
9657
  const add = program.command(cliCommands.add).description("Add generated Caplet files.");
9591
- add.command("cli").description("Add a CLI tools Caplet.").argument("<id>", "Caplet ID/display seed").option("--repo <path>", "repository path to inspect").option("--include <items>", "comma-separated generators to include: git,gh,package").option("--command <name>", "single CLI command template to generate").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9592
- const remote = remoteClientForCli(io);
9593
- if (remote) {
9594
- writeAddResult(writeOut, "CLI", await remote.request("add", {
9658
+ add.command("cli").description("Add a CLI tools Caplet.").argument("<id>", "Caplet ID/display seed").option("--repo <path>", "repository path to inspect").option("--include <items>", "comma-separated generators to include: git,gh,package").option("--command <name>", "single CLI command template to generate").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9659
+ const target = parseMutationTarget(options);
9660
+ if (target === "remote") {
9661
+ writeAddResult(writeOut, "CLI", await requireRemoteClientForTarget(io).request("add", {
9595
9662
  kind: "cli",
9596
9663
  id,
9597
9664
  options: remoteAddOptions(options)
@@ -9600,73 +9667,77 @@ function createProgram(io = {}) {
9600
9667
  }
9601
9668
  const result = addCliCaplet(id, {
9602
9669
  ...options,
9603
- destinationRoot: options.global ? resolveCapletsRoot(resolveConfigPath(currentConfigPath())) : resolveProjectCapletsRoot()
9670
+ destinationRoot: target === "global" ? resolveCapletsRoot(resolveConfigPath(currentConfigPath())) : envProjectCapletsRoot(env)
9604
9671
  });
9605
9672
  if (result.path) {
9606
- writeOut(`Wrote CLI Caplet to ${result.path}\n`);
9673
+ writeOut(`Wrote ${localMutationTargetLabel(target, io)}CLI Caplet to ${result.path}\n`);
9607
9674
  return;
9608
9675
  }
9609
9676
  writeOut(result.text);
9610
9677
  });
9611
- add.command("mcp").description("Add an MCP backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--command <name>", "stdio command").option("--arg <value>", "stdio command argument", collect, []).option("--cwd <path>", "stdio working directory").option("--env <KEY=VALUE>", "stdio environment variable", collect, []).option("--url <url>", "remote MCP server URL").option("--transport <transport>", "remote transport: http or sse").option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9612
- const remote = remoteClientForCli(io);
9613
- if (remote) {
9614
- writeAddResult(writeOut, "MCP", await remote.request("add", {
9678
+ add.command("mcp").description("Add an MCP backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--command <name>", "stdio command").option("--arg <value>", "stdio command argument", collect, []).option("--cwd <path>", "stdio working directory").option("--env <KEY=VALUE>", "stdio environment variable", collect, []).option("--url <url>", "remote MCP server URL").option("--transport <transport>", "remote transport: http or sse").option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9679
+ const target = parseMutationTarget(options);
9680
+ if (target === "remote") {
9681
+ writeAddResult(writeOut, "MCP", await requireRemoteClientForTarget(io).request("add", {
9615
9682
  kind: "mcp",
9616
9683
  id,
9617
9684
  options: remoteAddOptions(options)
9618
9685
  }));
9619
9686
  return;
9620
9687
  }
9621
- writeAddResult(writeOut, "MCP", addMcpCaplet(id, {
9688
+ const result = addMcpCaplet(id, {
9622
9689
  ...options,
9623
- destinationRoot: addDestinationRoot(options, currentConfigPath())
9624
- }));
9690
+ destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
9691
+ });
9692
+ writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}MCP`, result);
9625
9693
  });
9626
- add.command("openapi").description("Add an OpenAPI backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--spec <path-or-url>", "OpenAPI spec path or URL").option("--base-url <url>", "request base URL override").option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9627
- const remote = remoteClientForCli(io);
9628
- if (remote) {
9629
- writeAddResult(writeOut, "OpenAPI", await remote.request("add", {
9694
+ add.command("openapi").description("Add an OpenAPI backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--spec <path-or-url>", "OpenAPI spec path or URL").option("--base-url <url>", "request base URL override").option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9695
+ const target = parseMutationTarget(options);
9696
+ if (target === "remote") {
9697
+ writeAddResult(writeOut, "OpenAPI", await requireRemoteClientForTarget(io).request("add", {
9630
9698
  kind: "openapi",
9631
9699
  id,
9632
9700
  options: remoteAddOptions(options)
9633
9701
  }));
9634
9702
  return;
9635
9703
  }
9636
- writeAddResult(writeOut, "OpenAPI", addOpenApiCaplet(id, {
9704
+ const result = addOpenApiCaplet(id, {
9637
9705
  ...options,
9638
- destinationRoot: addDestinationRoot(options, currentConfigPath())
9639
- }));
9706
+ destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
9707
+ });
9708
+ writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}OpenAPI`, result);
9640
9709
  });
9641
- add.command("graphql").description("Add a GraphQL backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--endpoint-url <url>", "GraphQL endpoint URL").option("--schema <path-or-url>", "GraphQL schema path or URL").option("--introspection", "load schema through endpoint introspection").option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9642
- const remote = remoteClientForCli(io);
9643
- if (remote) {
9644
- writeAddResult(writeOut, "GraphQL", await remote.request("add", {
9710
+ add.command("graphql").description("Add a GraphQL backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--endpoint-url <url>", "GraphQL endpoint URL").option("--schema <path-or-url>", "GraphQL schema path or URL").option("--introspection", "load schema through endpoint introspection").option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9711
+ const target = parseMutationTarget(options);
9712
+ if (target === "remote") {
9713
+ writeAddResult(writeOut, "GraphQL", await requireRemoteClientForTarget(io).request("add", {
9645
9714
  kind: "graphql",
9646
9715
  id,
9647
9716
  options: remoteAddOptions(options)
9648
9717
  }));
9649
9718
  return;
9650
9719
  }
9651
- writeAddResult(writeOut, "GraphQL", addGraphqlCaplet(id, {
9720
+ const result = addGraphqlCaplet(id, {
9652
9721
  ...options,
9653
- destinationRoot: addDestinationRoot(options, currentConfigPath())
9654
- }));
9722
+ destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
9723
+ });
9724
+ writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}GraphQL`, result);
9655
9725
  });
9656
- add.command("http").description("Add an HTTP actions backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--base-url <url>", "HTTP API base URL").option("--action <name:METHOD:/path>", "HTTP action", collect, []).option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9657
- const remote = remoteClientForCli(io);
9658
- if (remote) {
9659
- writeAddResult(writeOut, "HTTP", await remote.request("add", {
9726
+ add.command("http").description("Add an HTTP actions backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--base-url <url>", "HTTP API base URL").option("--action <name:METHOD:/path>", "HTTP action", collect, []).option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9727
+ const target = parseMutationTarget(options);
9728
+ if (target === "remote") {
9729
+ writeAddResult(writeOut, "HTTP", await requireRemoteClientForTarget(io).request("add", {
9660
9730
  kind: "http",
9661
9731
  id,
9662
9732
  options: remoteAddOptions(options)
9663
9733
  }));
9664
9734
  return;
9665
9735
  }
9666
- writeAddResult(writeOut, "HTTP", addHttpCaplet(id, {
9736
+ const result = addHttpCaplet(id, {
9667
9737
  ...options,
9668
- destinationRoot: addDestinationRoot(options, currentConfigPath())
9669
- }));
9738
+ destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
9739
+ });
9740
+ writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}HTTP`, result);
9670
9741
  });
9671
9742
  program.command(cliCommands.getCaplet).description("Print a configured Caplet card.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9672
9743
  await executeOperation(caplet, { operation: "get_caplet" }, {
@@ -9868,7 +9939,7 @@ function createProgram(io = {}) {
9868
9939
  writeOut(`${resolveConfigPath(currentConfigPath())}\n`);
9869
9940
  });
9870
9941
  config.command("paths").description("Print resolved Caplets config, root, and auth paths.").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action((options) => {
9871
- const paths = resolveCliConfigPaths(currentConfigPath(), io.authDir);
9942
+ const paths = resolveCliConfigPaths(currentConfigPath(), envProjectConfigPath(env), io.authDir);
9872
9943
  if (options.json || options.format === "json") {
9873
9944
  writeOut(`${JSON.stringify(paths, null, 2)}\n`);
9874
9945
  return;
@@ -9876,60 +9947,59 @@ function createProgram(io = {}) {
9876
9947
  writeOut(formatConfigPaths(paths, options.format ?? "plain"));
9877
9948
  });
9878
9949
  const auth = program.command(cliCommands.auth).description("Manage OAuth credentials for remote servers.");
9879
- auth.command("login").description("Authenticate a configured remote OAuth server.").argument("<server>", "configured server ID").option("--no-open", "print the authorization URL without opening a browser").action(async (serverId, options) => {
9880
- const remote = remoteClientForCli(io);
9881
- if (remote) {
9882
- const started = await remote.request("auth_login_start", { server: serverId });
9883
- if (started.authorizationUrl) {
9884
- writeOut(`Open this URL to authorize ${serverId}:\n${started.authorizationUrl}\n`);
9885
- if (options.open !== false) await openBrowser(started.authorizationUrl);
9886
- writeOut("Complete authentication in your browser. The server callback will store credentials.\n");
9887
- return;
9888
- }
9889
- if (started.authenticated) writeOut(`Authenticated \`${serverId}\`.\n`);
9950
+ auth.command("login").description("Authenticate a configured remote OAuth server.").argument("<server>", "configured server ID").option("--project", "authenticate using the project Caplets config").option("-g, --global", "authenticate using the user Caplets config").option("--remote", "authenticate using the remote server auth store").option("--no-open", "print the authorization URL without opening a browser").action(async (serverId, options) => {
9951
+ const target = await resolveAuthTarget(serverId, options, io);
9952
+ if (target === "remote") {
9953
+ await remoteAuthLogin(requireRemoteClientForTarget(io), serverId, options.open !== false, writeOut);
9890
9954
  return;
9891
9955
  }
9892
9956
  const configPath = currentConfigPath();
9957
+ const projectConfigPath = envProjectConfigPath(env);
9893
9958
  await loginAuth(serverId, {
9894
9959
  noOpen: options.open === false,
9895
9960
  writeOut,
9896
9961
  writeErr,
9897
9962
  ...configPath ? { configPath } : {},
9963
+ ...projectConfigPath ? { projectConfigPath } : {},
9964
+ config: localAuthConfigForTarget({
9965
+ serverId,
9966
+ ...configPath ? { configPath } : {},
9967
+ ...projectConfigPath ? { projectConfigPath } : {},
9968
+ source: target
9969
+ }),
9898
9970
  ...io.authDir ? { authDir: io.authDir } : {}
9899
9971
  });
9900
9972
  });
9901
- auth.command("logout").description("Delete stored OAuth credentials for a server.").argument("<server>", "configured server ID").action(async (serverId) => {
9902
- const remote = remoteClientForCli(io);
9903
- if (remote) {
9904
- writeOut((await remote.request("auth_logout", { server: serverId })).deleted ? `Deleted remote OAuth credentials for \`${serverId}\`.\n` : `No remote OAuth credentials found for \`${serverId}\`.\n`);
9973
+ auth.command("logout").description("Delete stored OAuth credentials for a server.").argument("<server>", "configured server ID").option("--project", "delete credentials for the project Caplets config target").option("-g, --global", "delete credentials for the user Caplets config target").option("--remote", "delete credentials from the remote server auth store").action(async (serverId, options) => {
9974
+ const target = await resolveAuthTarget(serverId, options, io);
9975
+ if (target === "remote") {
9976
+ writeOut((await requireRemoteClientForTarget(io).request("auth_logout", { server: serverId })).deleted ? `Deleted remote OAuth credentials for \`${serverId}\`.\n` : `No remote OAuth credentials found for \`${serverId}\`.\n`);
9905
9977
  return;
9906
9978
  }
9907
9979
  const configPath = currentConfigPath();
9980
+ const projectConfigPath = envProjectConfigPath(env);
9908
9981
  logoutAuth(serverId, {
9909
9982
  writeOut,
9910
9983
  ...configPath ? { configPath } : {},
9984
+ config: localAuthConfigForTarget({
9985
+ serverId,
9986
+ ...configPath ? { configPath } : {},
9987
+ ...projectConfigPath ? { projectConfigPath } : {},
9988
+ source: target
9989
+ }),
9911
9990
  ...io.authDir ? { authDir: io.authDir } : {}
9912
9991
  });
9913
9992
  });
9914
- auth.command("list").description("List servers with stored OAuth credentials.").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action(async (options) => {
9993
+ auth.command("list").description("List servers with stored OAuth credentials.").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).option("--project", "list auth targets from the project Caplets config").option("-g, --global", "list auth targets from the user Caplets config").option("--remote", "list auth targets from the remote server auth store").action(async (options) => {
9915
9994
  const configPath = currentConfigPath();
9995
+ const projectConfigPath = envProjectConfigPath(env);
9916
9996
  const format = options.json || options.format === "json" ? "json" : options.format ?? "plain";
9917
- const remote = remoteClientForCli(io);
9918
- if (remote) {
9919
- const rows = await remote.request("auth_list", {});
9920
- if (format === "json") {
9921
- writeOut(`${JSON.stringify(rows, null, 2)}\n`);
9922
- return;
9923
- }
9924
- writeOut(formatAuthRows(rows, format));
9997
+ const rows = await authListRowsForCli(parseAuthFlagTarget(options), io, configPath, projectConfigPath);
9998
+ if (format === "json") {
9999
+ writeOut(`${JSON.stringify(rows, null, 2)}\n`);
9925
10000
  return;
9926
10001
  }
9927
- listAuth({
9928
- writeOut,
9929
- format,
9930
- ...configPath ? { configPath } : {},
9931
- ...io.authDir ? { authDir: io.authDir } : {}
9932
- });
10002
+ writeOut(formatAuthRows(rows, format));
9933
10003
  });
9934
10004
  return program;
9935
10005
  }
@@ -9973,12 +10043,90 @@ function remoteCommandForOperation(operation) {
9973
10043
  }
9974
10044
  }
9975
10045
  function remoteAddOptions(options) {
9976
- const { output, print, global, destinationRoot, ...remoteOptions } = options;
9977
- if (global) throw new CapletsError("REQUEST_INVALID", "--global is not supported in remote mode; the server controls the add destination.");
10046
+ const { output, print, global, project, remote, destinationRoot, ...remoteOptions } = options;
9978
10047
  if (print) throw new CapletsError("REQUEST_INVALID", "--print is not supported in remote mode; the server controls add output.");
9979
10048
  if (output !== void 0) throw new CapletsError("REQUEST_INVALID", "--output is not supported in remote mode; the server controls the add destination.");
9980
10049
  return remoteOptions;
9981
10050
  }
10051
+ function parseMutationTarget(options) {
10052
+ const selected = [
10053
+ options.project ? "--project" : void 0,
10054
+ options.global ? "--global" : void 0,
10055
+ options.remote ? "--remote" : void 0
10056
+ ].filter((value) => value !== void 0);
10057
+ if (selected.length > 1) throw new CapletsError("REQUEST_INVALID", `Cannot combine mutation target flags: ${selected.join(", ")}`);
10058
+ if (options.global) return "global";
10059
+ if (options.remote) return "remote";
10060
+ return "project";
10061
+ }
10062
+ function localMutationTargetLabel(target, io) {
10063
+ return remoteClientForCli(io) ? `${target} ` : "";
10064
+ }
10065
+ function parseAuthFlagTarget(options) {
10066
+ const selected = [
10067
+ options.project ? "--project" : void 0,
10068
+ options.global ? "--global" : void 0,
10069
+ options.remote ? "--remote" : void 0
10070
+ ].filter((value) => value !== void 0);
10071
+ if (selected.length > 1) throw new CapletsError("REQUEST_INVALID", `Cannot combine auth target flags: ${selected.join(", ")}`);
10072
+ if (options.project) return "project";
10073
+ if (options.global) return "global";
10074
+ if (options.remote) return "remote";
10075
+ }
10076
+ async function resolveAuthTarget(serverId, options, io) {
10077
+ const explicit = parseAuthFlagTarget(options);
10078
+ if (explicit) return explicit;
10079
+ const env = io.env ?? process.env;
10080
+ const configPath = envConfigPath(env);
10081
+ const projectConfigPath = envProjectConfigPath(env);
10082
+ const matches = localAuthTargets({
10083
+ ...configPath ? { configPath } : {},
10084
+ ...projectConfigPath ? { projectConfigPath } : {}
10085
+ }).filter((target) => target.server === serverId).map((target) => target.source);
10086
+ const remote = remoteClientForCli(io);
10087
+ if (remote) {
10088
+ if (matches.length === 0) matches.push("remote");
10089
+ else if ((await remoteAuthRows(remote)).some((row) => row.server === serverId)) matches.push("remote");
10090
+ }
10091
+ const unique = [...new Set(matches)];
10092
+ if (unique.length === 1) return unique[0];
10093
+ if (unique.length > 1) throw new CapletsError("REQUEST_INVALID", `Auth target \`${serverId}\` exists in multiple scopes. Pass --project, --global, or --remote.`);
10094
+ throw new CapletsError("SERVER_NOT_FOUND", `Server ${serverId} is not configured for OAuth`);
10095
+ }
10096
+ async function authListRowsForCli(target, io, configPath, projectConfigPath) {
10097
+ if (target === "remote") return remoteAuthRows(requireRemoteClientForTarget(io));
10098
+ const localRows = listLocalAuthRows({
10099
+ ...configPath ? { configPath } : {},
10100
+ ...projectConfigPath ? { projectConfigPath } : {},
10101
+ ...io.authDir ? { authDir: io.authDir } : {},
10102
+ ...target ? { source: target } : {}
10103
+ });
10104
+ if (target) return localRows;
10105
+ const remote = remoteClientForCli(io);
10106
+ if (!remote) return localRows;
10107
+ return [...localRows, ...await remoteAuthRows(remote)].sort((left, right) => left.server.localeCompare(right.server));
10108
+ }
10109
+ async function remoteAuthRows(remote) {
10110
+ return (await remote.request("auth_list", {})).map((row) => ({
10111
+ ...row,
10112
+ source: "remote"
10113
+ }));
10114
+ }
10115
+ async function remoteAuthLogin(remote, serverId, open, writeOut) {
10116
+ const started = await remote.request("auth_login_start", { server: serverId });
10117
+ if (started.authorizationUrl) {
10118
+ writeOut(`Open this URL to authorize ${serverId}:\n${started.authorizationUrl}\n`);
10119
+ if (open) await openBrowser(started.authorizationUrl);
10120
+ writeOut("Complete authentication in your browser. The server callback will store credentials.\n");
10121
+ return;
10122
+ }
10123
+ if (started.authenticated) writeOut(`Authenticated \`${serverId}\`.\n`);
10124
+ }
10125
+ function requireRemoteClientForTarget(io) {
10126
+ const remote = remoteClientForCli(io);
10127
+ if (!remote) throw new CapletsError("REQUEST_INVALID", "--remote requires CAPLETS_MODE=remote and CAPLETS_SERVER_URL");
10128
+ return remote;
10129
+ }
9982
10130
  function collect(value, previous) {
9983
10131
  previous.push(value);
9984
10132
  return previous;
@@ -10015,8 +10163,10 @@ function parseQualifiedTarget(capletOrTarget, toolArgument) {
10015
10163
  async function completeCliWordsLocally(words, options) {
10016
10164
  const engine = new CapletsEngine({
10017
10165
  ...options.configPath ? { configPath: options.configPath } : {},
10166
+ ...options.projectConfigPath ? { projectConfigPath: options.projectConfigPath } : {},
10018
10167
  ...options.authDir ? { authDir: options.authDir } : {},
10019
- watch: false
10168
+ watch: false,
10169
+ ...options.config ? { configLoader: () => options.config } : {}
10020
10170
  });
10021
10171
  try {
10022
10172
  return await engine.completeCliWords(words);
@@ -10024,6 +10174,34 @@ async function completeCliWordsLocally(words, options) {
10024
10174
  await engine.close();
10025
10175
  }
10026
10176
  }
10177
+ function mergeCompletionSuggestions(...groups) {
10178
+ return [...new Set(groups.flat())];
10179
+ }
10180
+ function localShadowedCompletionTarget(words, config) {
10181
+ const command = words[0];
10182
+ const target = words[1];
10183
+ if (!command || !target || target.startsWith("-")) return;
10184
+ const qualifiedCommands = new Set([
10185
+ cliCommands.getTool,
10186
+ cliCommands.callTool,
10187
+ cliCommands.getPrompt
10188
+ ]);
10189
+ const capletCommands = new Set([
10190
+ cliCommands.getCaplet,
10191
+ cliCommands.checkBackend,
10192
+ cliCommands.listTools,
10193
+ cliCommands.searchTools,
10194
+ cliCommands.listResources,
10195
+ cliCommands.searchResources,
10196
+ cliCommands.listResourceTemplates,
10197
+ cliCommands.readResource,
10198
+ cliCommands.listPrompts,
10199
+ cliCommands.searchPrompts,
10200
+ cliCommands.complete
10201
+ ]);
10202
+ const caplet = qualifiedCommands.has(command) ? target.slice(0, target.includes(".") ? target.indexOf(".") : target.length) : capletCommands.has(command) ? target : void 0;
10203
+ return caplet && hasEnabledCaplet(config, caplet) ? caplet : void 0;
10204
+ }
10027
10205
  function parseCallToolArgs(value) {
10028
10206
  if (value === void 0) return {};
10029
10207
  let parsed;
@@ -10064,6 +10242,11 @@ function isPlainObject(value) {
10064
10242
  async function executeOperation(caplet, request, io) {
10065
10243
  const command = remoteCommandForOperation(request.operation);
10066
10244
  if (io.remote && command) {
10245
+ const localOverlay = tryLoadLocalOverlayForCli(io, io.writeErr);
10246
+ if (localOverlay && hasEnabledCaplet(localOverlay.config, caplet)) {
10247
+ await executeLocalOperation(caplet, request, io, localOverlay.config);
10248
+ return;
10249
+ }
10067
10250
  const result = await io.remote.request(command, {
10068
10251
  caplet,
10069
10252
  request
@@ -10076,12 +10259,119 @@ async function executeOperation(caplet, request, io) {
10076
10259
  if (isPlainObject(result) && result.isError === true) io.setExitCode(1);
10077
10260
  return;
10078
10261
  }
10262
+ await executeLocalOperation(caplet, request, io);
10263
+ }
10264
+ function loadLocalOverlayForCli(io, writeErr) {
10265
+ const env = io.env ?? process.env;
10266
+ const overlay = loadLocalOverlayConfigWithSources(resolveConfigPath(envConfigPath(env)), envProjectConfigPath(env));
10267
+ for (const warning of overlay.warnings) writeErr(`Warning: ${warning.kind} at ${warning.path}: ${warning.message}\n`);
10268
+ return overlay;
10269
+ }
10270
+ function tryLoadLocalOverlayForCli(io, writeErr) {
10271
+ try {
10272
+ return loadLocalOverlayForCli(io, writeErr);
10273
+ } catch (error) {
10274
+ writeErr(`Warning: Could not load local Caplets overlay: ${formatErrorMessage(error)}\n`);
10275
+ return loadPartialLocalOverlayForCli(io, writeErr);
10276
+ }
10277
+ }
10278
+ function loadPartialLocalOverlayForCli(io, writeErr) {
10279
+ const env = io.env ?? process.env;
10280
+ const configPath = resolveConfigPath(envConfigPath(env));
10281
+ const projectConfigPath = envProjectConfigPath(env);
10282
+ const absentProjectPath = join(dirname(configPath), ".caplets-overlay-recovery", "config.json");
10283
+ const absentGlobalPath = join(dirname(projectConfigPath), ".caplets-overlay-recovery", "config.json");
10284
+ const globalOverlay = tryLoadPartialOverlayLayer("global", configPath, absentProjectPath, writeErr);
10285
+ const projectOverlay = tryLoadPartialOverlayLayer("project", absentGlobalPath, projectConfigPath, writeErr);
10286
+ if (!globalOverlay) return projectOverlay;
10287
+ if (!projectOverlay) return globalOverlay;
10288
+ return mergePartialLocalOverlays(globalOverlay, projectOverlay);
10289
+ }
10290
+ function tryLoadPartialOverlayLayer(label, configPath, projectConfigPath, writeErr) {
10291
+ try {
10292
+ const overlay = loadLocalOverlayConfigWithSources(configPath, projectConfigPath);
10293
+ for (const warning of overlay.warnings) writeErr(`Warning: ${warning.kind} at ${warning.path}: ${warning.message}\n`);
10294
+ return overlay;
10295
+ } catch (error) {
10296
+ writeErr(`Warning: Could not load ${label} Caplets overlay: ${formatErrorMessage(error)}\n`);
10297
+ return;
10298
+ }
10299
+ }
10300
+ function mergePartialLocalOverlays(globalOverlay, projectOverlay) {
10301
+ const config = { ...globalOverlay.config };
10302
+ const sources = { ...globalOverlay.sources };
10303
+ const shadows = { ...globalOverlay.shadows };
10304
+ for (const kind of capletConfigKinds) config[kind] = { ...globalOverlay.config[kind] };
10305
+ for (const kind of capletConfigKinds) for (const id of Object.keys(projectOverlay.config[kind])) {
10306
+ removeCapletFromPartialOverlay(config, sources, shadows, id);
10307
+ config[kind][id] = projectOverlay.config[kind][id];
10308
+ }
10309
+ for (const [id, source] of Object.entries(projectOverlay.sources)) sources[id] = source;
10310
+ for (const [id, shadowedSources] of Object.entries(projectOverlay.shadows)) shadows[id] = [...shadows[id] ?? [], ...shadowedSources];
10311
+ return {
10312
+ config,
10313
+ sources,
10314
+ shadows,
10315
+ warnings: [...globalOverlay.warnings, ...projectOverlay.warnings]
10316
+ };
10317
+ }
10318
+ const capletConfigKinds = [
10319
+ "mcpServers",
10320
+ "openapiEndpoints",
10321
+ "graphqlEndpoints",
10322
+ "httpApis",
10323
+ "cliTools",
10324
+ "capletSets"
10325
+ ];
10326
+ function removeCapletFromPartialOverlay(config, sources, shadows, id) {
10327
+ for (const kind of capletConfigKinds) delete config[kind][id];
10328
+ if (sources[id]) shadows[id] = [...shadows[id] ?? [], sources[id]];
10329
+ delete sources[id];
10330
+ }
10331
+ function formatErrorMessage(error) {
10332
+ return error instanceof Error ? error.message : String(error);
10333
+ }
10334
+ function envProjectConfigPath(env) {
10335
+ return env.CAPLETS_PROJECT_CONFIG?.trim() || resolveProjectConfigPath();
10336
+ }
10337
+ function envProjectCapletsRoot(env) {
10338
+ const projectConfigPath = env.CAPLETS_PROJECT_CONFIG?.trim();
10339
+ return projectConfigPath ? dirname(projectConfigPath) : resolveProjectCapletsRoot();
10340
+ }
10341
+ function mergeRemoteAndLocalRows(remoteRows, localOverlay, options) {
10342
+ const rows = /* @__PURE__ */ new Map();
10343
+ for (const row of remoteRows) rows.set(row.server, {
10344
+ ...row,
10345
+ source: "remote"
10346
+ });
10347
+ if (!localOverlay) return [...rows.values()].filter((row) => options.includeDisabled || !row.disabled).sort((left, right) => left.server.localeCompare(right.server));
10348
+ for (const row of listCaplets(localOverlay, { includeDisabled: true })) {
10349
+ if (rows.get(row.server)) {
10350
+ if (row.disabled) continue;
10351
+ options.writeErr(`Warning: ${formatOverlaySource(row.source)} Caplet ${row.server} shadows remote Caplet\n`);
10352
+ }
10353
+ rows.set(row.server, row);
10354
+ }
10355
+ return [...rows.values()].filter((row) => options.includeDisabled || !row.disabled).sort((left, right) => left.server.localeCompare(right.server));
10356
+ }
10357
+ function formatOverlaySource(kind) {
10358
+ if (kind.startsWith("project")) return "project";
10359
+ if (kind.startsWith("global")) return "global";
10360
+ return kind;
10361
+ }
10362
+ function hasEnabledCaplet(config, id) {
10363
+ const caplet = config.mcpServers[id] ?? config.openapiEndpoints[id] ?? config.graphqlEndpoints[id] ?? config.httpApis[id] ?? config.cliTools[id] ?? config.capletSets[id];
10364
+ return Boolean(caplet && !caplet.disabled);
10365
+ }
10366
+ async function executeLocalOperation(caplet, request, io, config) {
10079
10367
  const configPath = envConfigPath(io.env ?? process.env);
10080
10368
  const engine = new CapletsEngine({
10081
10369
  ...configPath ? { configPath } : {},
10370
+ projectConfigPath: envProjectConfigPath(io.env ?? process.env),
10082
10371
  ...io.authDir ? { authDir: io.authDir } : {},
10083
10372
  watch: false,
10084
- writeErr: io.writeErr
10373
+ writeErr: io.writeErr,
10374
+ ...config ? { configLoader: () => config } : {}
10085
10375
  });
10086
10376
  try {
10087
10377
  const result = await engine.execute(caplet, request);
@@ -10436,8 +10726,8 @@ function schemaSummary(schema) {
10436
10726
  required.length > 0 ? `required ${required.join(", ")}` : "no required fields"
10437
10727
  ].filter((part) => Boolean(part)).join("; ");
10438
10728
  }
10439
- function addDestinationRoot(options, configPath) {
10440
- return options.global ? resolveCapletsRoot(resolveConfigPath(configPath)) : resolveProjectCapletsRoot();
10729
+ function addDestinationRoot(target, configPath, env) {
10730
+ return target === "global" ? resolveCapletsRoot(resolveConfigPath(configPath)) : envProjectCapletsRoot(env);
10441
10731
  }
10442
10732
  function writeAddResult(writeOut, label, result) {
10443
10733
  if (result.path) {