api-documentation-mcp 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +61 -17
  2. package/dist/index.js +2091 -922
  3. package/package.json +19 -5
package/dist/index.js CHANGED
@@ -86,23 +86,23 @@ var require_code = __commonJS({
86
86
  };
87
87
  exports._Code = _Code;
88
88
  exports.nil = new _Code("");
89
- function _(strs, ...args) {
89
+ function _(strs, ...args2) {
90
90
  const code = [strs[0]];
91
91
  let i = 0;
92
- while (i < args.length) {
93
- addCodeArg(code, args[i]);
92
+ while (i < args2.length) {
93
+ addCodeArg(code, args2[i]);
94
94
  code.push(strs[++i]);
95
95
  }
96
96
  return new _Code(code);
97
97
  }
98
98
  exports._ = _;
99
99
  var plus = new _Code("+");
100
- function str(strs, ...args) {
100
+ function str(strs, ...args2) {
101
101
  const expr = [safeStringify(strs[0])];
102
102
  let i = 0;
103
- while (i < args.length) {
103
+ while (i < args2.length) {
104
104
  expr.push(plus);
105
- addCodeArg(expr, args[i]);
105
+ addCodeArg(expr, args2[i]);
106
106
  expr.push(plus, safeStringify(strs[++i]));
107
107
  }
108
108
  optimize(expr);
@@ -657,10 +657,10 @@ var require_codegen = __commonJS({
657
657
  }
658
658
  };
659
659
  var Func = class extends BlockNode {
660
- constructor(name, args, async) {
660
+ constructor(name, args2, async) {
661
661
  super();
662
662
  this.name = name;
663
- this.args = args;
663
+ this.args = args2;
664
664
  this.async = async;
665
665
  }
666
666
  render(opts) {
@@ -935,8 +935,8 @@ var require_codegen = __commonJS({
935
935
  return this;
936
936
  }
937
937
  // `function` heading (or definition if funcBody is passed)
938
- func(name, args = code_1.nil, async, funcBody) {
939
- this._blockNode(new Func(name, args, async));
938
+ func(name, args2 = code_1.nil, async, funcBody) {
939
+ this._blockNode(new Func(name, args2, async));
940
940
  if (funcBody)
941
941
  this.code(funcBody).endFunc();
942
942
  return this;
@@ -1030,13 +1030,13 @@ var require_codegen = __commonJS({
1030
1030
  }
1031
1031
  exports.not = not;
1032
1032
  var andCode = mappend(exports.operators.AND);
1033
- function and(...args) {
1034
- return args.reduce(andCode);
1033
+ function and(...args2) {
1034
+ return args2.reduce(andCode);
1035
1035
  }
1036
1036
  exports.and = and;
1037
1037
  var orCode = mappend(exports.operators.OR);
1038
- function or(...args) {
1039
- return args.reduce(orCode);
1038
+ function or(...args2) {
1039
+ return args2.reduce(orCode);
1040
1040
  }
1041
1041
  exports.or = or;
1042
1042
  function mappend(op) {
@@ -1769,8 +1769,8 @@ var require_code2 = __commonJS({
1769
1769
  ];
1770
1770
  if (it.opts.dynamicRef)
1771
1771
  valCxt.push([names_1.default.dynamicAnchors, names_1.default.dynamicAnchors]);
1772
- const args = (0, codegen_1._)`${dataAndSchema}, ${gen.object(...valCxt)}`;
1773
- return context !== codegen_1.nil ? (0, codegen_1._)`${func}.call(${context}, ${args})` : (0, codegen_1._)`${func}(${args})`;
1772
+ const args2 = (0, codegen_1._)`${dataAndSchema}, ${gen.object(...valCxt)}`;
1773
+ return context !== codegen_1.nil ? (0, codegen_1._)`${func}.call(${context}, ${args2})` : (0, codegen_1._)`${func}(${args2})`;
1774
1774
  }
1775
1775
  exports.callValidateCode = callValidateCode;
1776
1776
  var newRegExp = (0, codegen_1._)`new RegExp`;
@@ -3333,6 +3333,37 @@ var require_utils = __commonJS({
3333
3333
  }
3334
3334
  return output.join("");
3335
3335
  }
3336
+ function removeDotSegmentsRelative(path) {
3337
+ if (path === "" || path[0] === "/") {
3338
+ return removeDotSegments(path);
3339
+ }
3340
+ const segments = path.split("/");
3341
+ const last = segments.length - 1;
3342
+ const output = [];
3343
+ let trailingDirectory = false;
3344
+ for (let i = 0; i <= last; i++) {
3345
+ const segment = segments[i];
3346
+ if (segment === "." || segment === "..") {
3347
+ if (segment === "..") {
3348
+ if (output.length !== 0 && output[output.length - 1] !== "..") {
3349
+ output.pop();
3350
+ } else {
3351
+ output.push("..");
3352
+ }
3353
+ }
3354
+ trailingDirectory = i === last;
3355
+ } else {
3356
+ output.push(segment);
3357
+ }
3358
+ }
3359
+ if (trailingDirectory && output[output.length - 1] !== "..") {
3360
+ output.push("");
3361
+ }
3362
+ if (output.length === 0 || output[0] === "" || output[0].includes(":")) {
3363
+ output.unshift(".");
3364
+ }
3365
+ return output.join("/");
3366
+ }
3336
3367
  var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
3337
3368
  var HOST_DELIM_RE = /[@/?#:]/g;
3338
3369
  var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
@@ -3593,6 +3624,7 @@ var require_utils = __commonJS({
3593
3624
  encodeFragment,
3594
3625
  escapePreservingEscapes,
3595
3626
  removeDotSegments,
3627
+ removeDotSegmentsRelative,
3596
3628
  isIPv4,
3597
3629
  isUUID,
3598
3630
  normalizeIPv6,
@@ -3816,16 +3848,18 @@ var require_schemes = __commonJS({
3816
3848
  var require_fast_uri = __commonJS({
3817
3849
  "node_modules/fast-uri/index.js"(exports, module) {
3818
3850
  "use strict";
3819
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3851
+ var { normalizeIPv6, removeDotSegments, removeDotSegmentsRelative, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3820
3852
  var { SCHEMES, getSchemeHandler } = require_schemes();
3821
3853
  var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
3822
3854
  var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
3823
- function decodeValidScheme(scheme) {
3824
- const decodedScheme = unescape(String(scheme));
3825
- if (!VALID_SCHEME.test(decodedScheme)) {
3855
+ var MALFORMED_HOST_ERROR = "URI host is malformed.";
3856
+ var FORBIDDEN_DOMAIN_HOST_CHARACTER = /[\0-\x20"#/:<>?@[\\\]^`{|}\x7F]/u;
3857
+ function validateScheme(scheme) {
3858
+ const stringScheme = String(scheme);
3859
+ if (!VALID_SCHEME.test(stringScheme)) {
3826
3860
  throw new TypeError(MALFORMED_SCHEME_ERROR);
3827
3861
  }
3828
- return decodedScheme;
3862
+ return stringScheme;
3829
3863
  }
3830
3864
  function normalize(uri, options) {
3831
3865
  if (typeof uri === "string") {
@@ -3862,6 +3896,9 @@ var require_fast_uri = __commonJS({
3862
3896
  const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
3863
3897
  const resolvedHost = resolved.host;
3864
3898
  const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
3899
+ if (hasForbiddenDomainHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP)) {
3900
+ throw new Error(MALFORMED_HOST_ERROR);
3901
+ }
3865
3902
  canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
3866
3903
  const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
3867
3904
  if (resolved.error && !encodedASCIIHost) {
@@ -3903,14 +3940,15 @@ var require_fast_uri = __commonJS({
3903
3940
  if (relative.path[0] === "/") {
3904
3941
  target.path = removeDotSegments(relative.path);
3905
3942
  } else {
3906
- if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3943
+ const baseHasAuthority = base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0;
3944
+ if (baseHasAuthority && !base.path) {
3907
3945
  target.path = "/" + relative.path;
3908
3946
  } else if (!base.path) {
3909
3947
  target.path = relative.path;
3910
3948
  } else {
3911
3949
  target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
3912
3950
  }
3913
- target.path = removeDotSegments(target.path);
3951
+ target.path = base.scheme === void 0 && !baseHasAuthority && target.path[0] !== "/" ? removeDotSegmentsRelative(target.path) : removeDotSegments(target.path);
3914
3952
  }
3915
3953
  target.query = relative.query;
3916
3954
  }
@@ -3948,12 +3986,13 @@ var require_fast_uri = __commonJS({
3948
3986
  const options = Object.assign({}, opts);
3949
3987
  const uriTokens = [];
3950
3988
  if (component.scheme) {
3951
- component.scheme = decodeValidScheme(component.scheme);
3989
+ component.scheme = validateScheme(component.scheme);
3952
3990
  }
3953
3991
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
3954
3992
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
3955
3993
  const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
3956
- const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
3994
+ const schemelessReference = (component.scheme === void 0 || options.reference === "suffix") && !hasAuthority;
3995
+ const pathNoScheme = !options.skipEscape && schemelessReference;
3957
3996
  if (component.path !== void 0) {
3958
3997
  if (!options.skipEscape) {
3959
3998
  component.path = serializePathEncoding(component.path, pathNoScheme);
@@ -3962,7 +4001,7 @@ var require_fast_uri = __commonJS({
3962
4001
  }
3963
4002
  }
3964
4003
  if (options.reference !== "suffix" && component.scheme) {
3965
- component.scheme = decodeValidScheme(component.scheme);
4004
+ component.scheme = validateScheme(component.scheme);
3966
4005
  uriTokens.push(component.scheme, ":");
3967
4006
  }
3968
4007
  const authority = recomposeAuthority(component);
@@ -3978,9 +4017,9 @@ var require_fast_uri = __commonJS({
3978
4017
  if (component.path !== void 0) {
3979
4018
  let s = component.path;
3980
4019
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
3981
- s = removeDotSegments(s);
4020
+ s = schemelessReference && s[0] !== "/" ? removeDotSegmentsRelative(s) : removeDotSegments(s);
3982
4021
  }
3983
- if (pathNoScheme) {
4022
+ if (schemelessReference) {
3984
4023
  s = serializePathEncoding(s, true);
3985
4024
  }
3986
4025
  if (authority === void 0 && s[0] === "/" && s[1] === "/") {
@@ -4027,16 +4066,34 @@ var require_fast_uri = __commonJS({
4027
4066
  return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
4028
4067
  }
4029
4068
  function canonicalizeHost(parsed, options, schemeHandler, isIP) {
4069
+ if (hasForbiddenDomainHost(parsed, options, schemeHandler, isIP)) {
4070
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
4071
+ return true;
4072
+ }
4030
4073
  if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
4074
+ let url;
4031
4075
  try {
4032
- parsed.host = new URL("http://" + parsed.host).hostname;
4076
+ url = new URL("http://" + parsed.host);
4033
4077
  } catch (e) {
4034
4078
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
4035
4079
  return true;
4036
4080
  }
4081
+ if (!isHostOnlyURL(url)) {
4082
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
4083
+ return true;
4084
+ }
4085
+ parsed.host = url.hostname;
4037
4086
  }
4038
4087
  return false;
4039
4088
  }
4089
+ function hasForbiddenDomainHost(parsed, options, schemeHandler, isIP) {
4090
+ return Boolean(
4091
+ parsed.host && isIP === false && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && FORBIDDEN_DOMAIN_HOST_CHARACTER.test(parsed.host)
4092
+ );
4093
+ }
4094
+ function isHostOnlyURL(url) {
4095
+ return url.username === "" && url.password === "" && url.port === "" && url.pathname === "/" && url.search === "" && url.hash === "" && url.hostname !== "";
4096
+ }
4040
4097
  function parseWithStatus(uri, opts) {
4041
4098
  const options = Object.assign({}, opts);
4042
4099
  const parsed = {
@@ -4091,9 +4148,8 @@ var require_fast_uri = __commonJS({
4091
4148
  parsed.query = matches[7];
4092
4149
  parsed.fragment = matches[8];
4093
4150
  if (parsed.scheme !== void 0) {
4094
- const decodedScheme = unescape(parsed.scheme);
4095
- if (VALID_SCHEME.test(decodedScheme)) {
4096
- parsed.scheme = decodedScheme.toLowerCase();
4151
+ if (VALID_SCHEME.test(parsed.scheme)) {
4152
+ parsed.scheme = parsed.scheme.toLowerCase();
4097
4153
  } else {
4098
4154
  parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
4099
4155
  malformedScheme = true;
@@ -4121,7 +4177,7 @@ var require_fast_uri = __commonJS({
4121
4177
  malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
4122
4178
  parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
4123
4179
  if (malformedIPLiteral) {
4124
- parsed.error = parsed.error || "URI host is malformed.";
4180
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
4125
4181
  malformedAuthorityOrPort = true;
4126
4182
  }
4127
4183
  } else {
@@ -4149,7 +4205,7 @@ var require_fast_uri = __commonJS({
4149
4205
  if (!isIP) {
4150
4206
  host = normalizePercentEncoding(host.toLowerCase());
4151
4207
  }
4152
- parsed.host = reescapeHostDelimiters(host, isIP);
4208
+ parsed.host = isIP || options.scheme !== "null" ? reescapeHostDelimiters(host, isIP) : host;
4153
4209
  }
4154
4210
  if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4155
4211
  if (parsed.path) {
@@ -7195,12 +7251,65 @@ var require_dist = __commonJS({
7195
7251
  }
7196
7252
  });
7197
7253
 
7198
- // src/mcp/server.ts
7199
- import { createHash, randomUUID } from "node:crypto";
7200
- import { DatabaseSync } from "node:sqlite";
7201
- import { existsSync } from "node:fs";
7202
- import { homedir } from "node:os";
7203
- import { join } from "node:path";
7254
+ // src/cli.ts
7255
+ import { readFileSync } from "node:fs";
7256
+
7257
+ // src/registry.ts
7258
+ function parseInput(schema, rawInput) {
7259
+ const result = schema.safeParse(rawInput ?? {});
7260
+ if (result.success) return result.data;
7261
+ const lines = result.error.issues.map((issue2) => `${issue2.path.join(".") || "params"}: ${issue2.message}`);
7262
+ throw new Error(`Invalid parameters: ${lines.join("; ")}`);
7263
+ }
7264
+ function defineCommand(definition) {
7265
+ return {
7266
+ id: definition.id,
7267
+ group: definition.group,
7268
+ title: definition.title,
7269
+ description: definition.description,
7270
+ params: definition.params,
7271
+ readOnly: definition.readOnly,
7272
+ destructive: definition.destructive === true,
7273
+ run: (rawInput) => definition.run(parseInput(definition.params, rawInput))
7274
+ };
7275
+ }
7276
+ function unwrap(schema) {
7277
+ let current = schema;
7278
+ for (let depth = 0; depth < 10; depth += 1) {
7279
+ const def = current._def;
7280
+ if (def.innerType) current = def.innerType;
7281
+ else if (def.schema) current = def.schema;
7282
+ else break;
7283
+ }
7284
+ return current;
7285
+ }
7286
+ function typeName(schema) {
7287
+ const inner = unwrap(schema);
7288
+ const kind = inner._def.typeName ?? "unknown";
7289
+ return kind.replace(/^Zod/, "").toLowerCase();
7290
+ }
7291
+ function describeParams(schema) {
7292
+ return Object.entries(schema.shape).map(([name, field]) => {
7293
+ const field_ = field;
7294
+ return {
7295
+ name,
7296
+ type: typeName(field_),
7297
+ required: !field_.isOptional(),
7298
+ ...field_.description ? { description: field_.description } : {}
7299
+ };
7300
+ });
7301
+ }
7302
+ function describeCommand(command) {
7303
+ return {
7304
+ id: command.id,
7305
+ group: command.group,
7306
+ title: command.title,
7307
+ description: command.description,
7308
+ readOnly: command.readOnly,
7309
+ destructive: command.destructive,
7310
+ params: describeParams(command.params)
7311
+ };
7312
+ }
7204
7313
 
7205
7314
  // node_modules/zod/v3/external.js
7206
7315
  var external_exports = {};
@@ -8158,24 +8267,24 @@ var base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=)
8158
8267
  var base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/;
8159
8268
  var dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
8160
8269
  var dateRegex = new RegExp(`^${dateRegexSource}$`);
8161
- function timeRegexSource(args) {
8270
+ function timeRegexSource(args2) {
8162
8271
  let secondsRegexSource = `[0-5]\\d`;
8163
- if (args.precision) {
8164
- secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
8165
- } else if (args.precision == null) {
8272
+ if (args2.precision) {
8273
+ secondsRegexSource = `${secondsRegexSource}\\.\\d{${args2.precision}}`;
8274
+ } else if (args2.precision == null) {
8166
8275
  secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
8167
8276
  }
8168
- const secondsQuantifier = args.precision ? "+" : "?";
8277
+ const secondsQuantifier = args2.precision ? "+" : "?";
8169
8278
  return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
8170
8279
  }
8171
- function timeRegex(args) {
8172
- return new RegExp(`^${timeRegexSource(args)}$`);
8280
+ function timeRegex(args2) {
8281
+ return new RegExp(`^${timeRegexSource(args2)}$`);
8173
8282
  }
8174
- function datetimeRegex(args) {
8175
- let regex = `${dateRegexSource}T${timeRegexSource(args)}`;
8283
+ function datetimeRegex(args2) {
8284
+ let regex = `${dateRegexSource}T${timeRegexSource(args2)}`;
8176
8285
  const opts = [];
8177
- opts.push(args.local ? `Z?` : `Z`);
8178
- if (args.offset)
8286
+ opts.push(args2.local ? `Z?` : `Z`);
8287
+ if (args2.offset)
8179
8288
  opts.push(`([+-]\\d{2}:?\\d{2})`);
8180
8289
  regex = `${regex}(${opts.join("|")})`;
8181
8290
  return new RegExp(`^${regex}$`);
@@ -10483,9 +10592,9 @@ var ZodFunction = class _ZodFunction extends ZodType {
10483
10592
  });
10484
10593
  return INVALID;
10485
10594
  }
10486
- function makeArgsIssue(args, error2) {
10595
+ function makeArgsIssue(args2, error2) {
10487
10596
  return makeIssue({
10488
- data: args,
10597
+ data: args2,
10489
10598
  path: ctx.path,
10490
10599
  errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en_default].filter((x) => !!x),
10491
10600
  issueData: {
@@ -10509,10 +10618,10 @@ var ZodFunction = class _ZodFunction extends ZodType {
10509
10618
  const fn = ctx.data;
10510
10619
  if (this._def.returns instanceof ZodPromise) {
10511
10620
  const me = this;
10512
- return OK(async function(...args) {
10621
+ return OK(async function(...args2) {
10513
10622
  const error2 = new ZodError([]);
10514
- const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => {
10515
- error2.addIssue(makeArgsIssue(args, e));
10623
+ const parsedArgs = await me._def.args.parseAsync(args2, params).catch((e) => {
10624
+ error2.addIssue(makeArgsIssue(args2, e));
10516
10625
  throw error2;
10517
10626
  });
10518
10627
  const result = await Reflect.apply(fn, this, parsedArgs);
@@ -10524,10 +10633,10 @@ var ZodFunction = class _ZodFunction extends ZodType {
10524
10633
  });
10525
10634
  } else {
10526
10635
  const me = this;
10527
- return OK(function(...args) {
10528
- const parsedArgs = me._def.args.safeParse(args, params);
10636
+ return OK(function(...args2) {
10637
+ const parsedArgs = me._def.args.safeParse(args2, params);
10529
10638
  if (!parsedArgs.success) {
10530
- throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
10639
+ throw new ZodError([makeArgsIssue(args2, parsedArgs.error)]);
10531
10640
  }
10532
10641
  const result = Reflect.apply(fn, this, parsedArgs.data);
10533
10642
  const parsedReturns = me._def.returns.safeParse(result, params);
@@ -10564,9 +10673,9 @@ var ZodFunction = class _ZodFunction extends ZodType {
10564
10673
  const validatedFunc = this.parse(func);
10565
10674
  return validatedFunc;
10566
10675
  }
10567
- static create(args, returns, params) {
10676
+ static create(args2, returns, params) {
10568
10677
  return new _ZodFunction({
10569
- args: args ? args : ZodTuple.create([]).rest(ZodUnknown.create()),
10678
+ args: args2 ? args2 : ZodTuple.create([]).rest(ZodUnknown.create()),
10570
10679
  returns: returns || ZodUnknown.create(),
10571
10680
  typeName: ZodFirstPartyTypeKind.ZodFunction,
10572
10681
  ...processCreateParams(params)
@@ -11243,163 +11352,1460 @@ var coerce = {
11243
11352
  };
11244
11353
  var NEVER = INVALID;
11245
11354
 
11246
- // node_modules/zod/v4/core/core.js
11247
- var NEVER2 = Object.freeze({
11248
- status: "aborted"
11249
- });
11250
- // @__NO_SIDE_EFFECTS__
11251
- function $constructor(name, initializer3, params) {
11252
- function init(inst, def) {
11253
- var _a;
11254
- Object.defineProperty(inst, "_zod", {
11255
- value: inst._zod ?? {},
11256
- enumerable: false
11257
- });
11258
- (_a = inst._zod).traits ?? (_a.traits = /* @__PURE__ */ new Set());
11259
- inst._zod.traits.add(name);
11260
- initializer3(inst, def);
11261
- for (const k in _.prototype) {
11262
- if (!(k in inst))
11263
- Object.defineProperty(inst, k, { value: _.prototype[k].bind(inst) });
11355
+ // src/commands/changes.ts
11356
+ import { randomUUID as randomUUID4 } from "node:crypto";
11357
+
11358
+ // src/operations.ts
11359
+ import { randomUUID as randomUUID2 } from "node:crypto";
11360
+
11361
+ // src/tree.ts
11362
+ import { randomUUID } from "node:crypto";
11363
+ function isFolder(node) {
11364
+ return node.kind === "folder";
11365
+ }
11366
+ function findNode(nodes, id) {
11367
+ for (const node of nodes) {
11368
+ if (node.id === id) return node;
11369
+ if (isFolder(node)) {
11370
+ const nested = findNode(node.children, id);
11371
+ if (nested) return nested;
11264
11372
  }
11265
- inst._zod.constr = _;
11266
- inst._zod.def = def;
11267
- }
11268
- const Parent = params?.Parent ?? Object;
11269
- class Definition extends Parent {
11270
11373
  }
11271
- Object.defineProperty(Definition, "name", { value: name });
11272
- function _(def) {
11273
- var _a;
11274
- const inst = params?.Parent ? new Definition() : this;
11275
- init(inst, def);
11276
- (_a = inst._zod).deferred ?? (_a.deferred = []);
11277
- for (const fn of inst._zod.deferred) {
11278
- fn();
11374
+ return void 0;
11375
+ }
11376
+ function findRequest(nodes, id) {
11377
+ const node = findNode(nodes, id);
11378
+ if (!node || isFolder(node)) throw new Error(`Request "${id}" was not found.`);
11379
+ return node;
11380
+ }
11381
+ function findParentId(nodes, id, parentId3 = null) {
11382
+ for (const node of nodes) {
11383
+ if (node.id === id) return parentId3;
11384
+ if (isFolder(node)) {
11385
+ const nested = findParentId(node.children, id, node.id);
11386
+ if (nested !== void 0) return nested;
11279
11387
  }
11280
- return inst;
11281
11388
  }
11282
- Object.defineProperty(_, "init", { value: init });
11283
- Object.defineProperty(_, Symbol.hasInstance, {
11284
- value: (inst) => {
11285
- if (params?.Parent && inst instanceof params.Parent)
11286
- return true;
11287
- return inst?._zod?.traits?.has(name);
11288
- }
11289
- });
11290
- Object.defineProperty(_, "name", { value: name });
11291
- return _;
11389
+ return void 0;
11292
11390
  }
11293
- var $brand = Symbol("zod_brand");
11294
- var $ZodAsyncError = class extends Error {
11295
- constructor() {
11296
- super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
11391
+ function insertNode(nodes, parentId3, node, index) {
11392
+ if (parentId3 === null) {
11393
+ const next = [...nodes];
11394
+ next.splice(index === void 0 ? next.length : Math.min(index, next.length), 0, node);
11395
+ return next;
11297
11396
  }
11298
- };
11299
- var globalConfig = {};
11300
- function config(newConfig) {
11301
- if (newConfig)
11302
- Object.assign(globalConfig, newConfig);
11303
- return globalConfig;
11304
- }
11305
-
11306
- // node_modules/zod/v4/core/util.js
11307
- var util_exports = {};
11308
- __export(util_exports, {
11309
- BIGINT_FORMAT_RANGES: () => BIGINT_FORMAT_RANGES,
11310
- Class: () => Class,
11311
- NUMBER_FORMAT_RANGES: () => NUMBER_FORMAT_RANGES,
11312
- aborted: () => aborted,
11313
- allowsEval: () => allowsEval,
11314
- assert: () => assert,
11315
- assertEqual: () => assertEqual,
11316
- assertIs: () => assertIs,
11317
- assertNever: () => assertNever,
11318
- assertNotEqual: () => assertNotEqual,
11319
- assignProp: () => assignProp,
11320
- cached: () => cached,
11321
- captureStackTrace: () => captureStackTrace,
11322
- cleanEnum: () => cleanEnum,
11323
- cleanRegex: () => cleanRegex,
11324
- clone: () => clone,
11325
- createTransparentProxy: () => createTransparentProxy,
11326
- defineLazy: () => defineLazy,
11327
- esc: () => esc,
11328
- escapeRegex: () => escapeRegex,
11329
- extend: () => extend,
11330
- finalizeIssue: () => finalizeIssue,
11331
- floatSafeRemainder: () => floatSafeRemainder2,
11332
- getElementAtPath: () => getElementAtPath,
11333
- getEnumValues: () => getEnumValues,
11334
- getLengthableOrigin: () => getLengthableOrigin,
11335
- getParsedType: () => getParsedType2,
11336
- getSizableOrigin: () => getSizableOrigin,
11337
- isObject: () => isObject,
11338
- isPlainObject: () => isPlainObject,
11339
- issue: () => issue,
11340
- joinValues: () => joinValues,
11341
- jsonStringifyReplacer: () => jsonStringifyReplacer,
11342
- merge: () => merge,
11343
- normalizeParams: () => normalizeParams,
11344
- nullish: () => nullish,
11345
- numKeys: () => numKeys,
11346
- omit: () => omit,
11347
- optionalKeys: () => optionalKeys,
11348
- partial: () => partial,
11349
- pick: () => pick,
11350
- prefixIssues: () => prefixIssues,
11351
- primitiveTypes: () => primitiveTypes,
11352
- promiseAllObject: () => promiseAllObject,
11353
- propertyKeyTypes: () => propertyKeyTypes,
11354
- randomString: () => randomString,
11355
- required: () => required,
11356
- stringifyPrimitive: () => stringifyPrimitive,
11357
- unwrapMessage: () => unwrapMessage
11358
- });
11359
- function assertEqual(val) {
11360
- return val;
11361
- }
11362
- function assertNotEqual(val) {
11363
- return val;
11364
- }
11365
- function assertIs(_arg) {
11366
- }
11367
- function assertNever(_x) {
11368
- throw new Error();
11369
- }
11370
- function assert(_) {
11397
+ const insertInto = (siblings) => {
11398
+ for (let position = 0; position < siblings.length; position += 1) {
11399
+ const child = siblings[position];
11400
+ if (!isFolder(child)) continue;
11401
+ if (child.id === parentId3) {
11402
+ const children = [...child.children];
11403
+ children.splice(index === void 0 ? children.length : Math.min(index, children.length), 0, node);
11404
+ const next = [...siblings];
11405
+ next[position] = { ...child, children };
11406
+ return { nodes: next, found: true };
11407
+ }
11408
+ const nested = insertInto(child.children);
11409
+ if (nested.found) {
11410
+ const next = [...siblings];
11411
+ next[position] = { ...child, children: nested.nodes };
11412
+ return { nodes: next, found: true };
11413
+ }
11414
+ }
11415
+ return { nodes: siblings, found: false };
11416
+ };
11417
+ const result = insertInto(nodes);
11418
+ if (!result.found) throw new Error(`Parent folder "${parentId3}" was not found.`);
11419
+ return result.nodes;
11371
11420
  }
11372
- function getEnumValues(entries) {
11373
- const numericValues = Object.values(entries).filter((v) => typeof v === "number");
11374
- const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
11375
- return values;
11421
+ function removeNode(nodes, id) {
11422
+ const directIndex = nodes.findIndex((node) => node.id === id);
11423
+ if (directIndex >= 0) {
11424
+ const next = [...nodes];
11425
+ const [removed] = next.splice(directIndex, 1);
11426
+ return { tree: next, removed };
11427
+ }
11428
+ for (let index = 0; index < nodes.length; index += 1) {
11429
+ const node = nodes[index];
11430
+ if (!isFolder(node)) continue;
11431
+ const result = removeNode(node.children, id);
11432
+ if (!result.removed) continue;
11433
+ const next = [...nodes];
11434
+ next[index] = { ...node, children: result.tree };
11435
+ return { tree: next, removed: result.removed };
11436
+ }
11437
+ return { tree: nodes };
11376
11438
  }
11377
- function joinValues(array2, separator = "|") {
11378
- return array2.map((val) => stringifyPrimitive(val)).join(separator);
11439
+ function updateNode(nodes, id, update) {
11440
+ let found = false;
11441
+ const tree = nodes.map((node) => {
11442
+ if (node.id === id) {
11443
+ found = true;
11444
+ return update(node);
11445
+ }
11446
+ if (!isFolder(node)) return node;
11447
+ const nested = updateNode(node.children, id, update);
11448
+ if (!nested.found) return node;
11449
+ found = true;
11450
+ return { ...node, children: nested.tree };
11451
+ });
11452
+ return { tree, found };
11379
11453
  }
11380
- function jsonStringifyReplacer(_, value) {
11381
- if (typeof value === "bigint")
11382
- return value.toString();
11383
- return value;
11454
+ function requestList(nodes) {
11455
+ return nodes.flatMap((node) => isFolder(node) ? requestList(node.children) : [node]);
11384
11456
  }
11385
- function cached(getter) {
11386
- const set = false;
11457
+ function cloneWithNewIds(node) {
11458
+ if (isFolder(node)) return { ...node, id: randomUUID(), children: node.children.map(cloneWithNewIds) };
11387
11459
  return {
11388
- get value() {
11389
- if (!set) {
11390
- const value = getter();
11391
- Object.defineProperty(this, "value", { value });
11392
- return value;
11393
- }
11394
- throw new Error("cached value already set");
11395
- }
11460
+ ...node,
11461
+ id: randomUUID(),
11462
+ headers: node.headers?.map((item) => ({ ...item, id: randomUUID() })),
11463
+ params: node.params?.map((item) => ({ ...item, id: randomUUID() })),
11464
+ pathParams: node.pathParams?.map((item) => ({ ...item, id: randomUUID() })),
11465
+ bodyFields: node.bodyFields?.map((item) => ({ ...item, id: randomUUID() }))
11396
11466
  };
11397
11467
  }
11398
- function nullish(input) {
11399
- return input === null || input === void 0;
11400
- }
11401
- function cleanRegex(source) {
11402
- const start = source.startsWith("^") ? 1 : 0;
11468
+ function normalizeRequest(input, existing) {
11469
+ const headers = input.headers ?? existing?.headers ?? [];
11470
+ const params = input.params ?? existing?.params ?? [];
11471
+ const pathParams = input.pathParams ?? existing?.pathParams ?? [];
11472
+ const bodyFields = input.bodyFields ?? existing?.bodyFields ?? [];
11473
+ const responses = input.responses ?? existing?.responses ?? [];
11474
+ return {
11475
+ ...existing,
11476
+ ...input,
11477
+ id: existing?.id ?? input.id ?? randomUUID(),
11478
+ kind: "request",
11479
+ name: input.name,
11480
+ method: input.method.toUpperCase(),
11481
+ url: input.url,
11482
+ body: input.body ?? existing?.body ?? "",
11483
+ headers: headers.map((item) => ({ ...item, id: item.id || randomUUID() })),
11484
+ params: params.map((item) => ({ ...item, id: item.id || randomUUID() })),
11485
+ pathParams: pathParams.map((item) => ({ ...item, id: item.id || randomUUID() })),
11486
+ bodyFields: bodyFields.map((item) => ({ ...item, id: item.id || randomUUID() })),
11487
+ responses: responses.map((response) => ({
11488
+ ...response,
11489
+ id: response.id || randomUUID(),
11490
+ content: response.content.map((content) => ({ ...content, id: content.id || randomUUID() }))
11491
+ }))
11492
+ };
11493
+ }
11494
+
11495
+ // src/redact.ts
11496
+ var referencePattern = /^\s*\{\{[^{}]+\}\}\s*$/;
11497
+ function maskSecret(value) {
11498
+ return referencePattern.test(value) ? value : "<redacted>";
11499
+ }
11500
+ function sanitizeUrl(value) {
11501
+ try {
11502
+ const url = new URL(value);
11503
+ if (url.username) url.username = "<redacted>";
11504
+ if (url.password) url.password = "<redacted>";
11505
+ for (const key of [...url.searchParams.keys()]) {
11506
+ if (isSensitiveName(key)) url.searchParams.set(key, maskSecret(url.searchParams.get(key) ?? ""));
11507
+ }
11508
+ return url.toString();
11509
+ } catch {
11510
+ return value;
11511
+ }
11512
+ }
11513
+ function isSensitiveName(value) {
11514
+ return /authorization|cookie|token|secret|password|\bkey\b|api[-_]?key|client[-_]?secret/i.test(value);
11515
+ }
11516
+ function redactBody(value) {
11517
+ try {
11518
+ const parsed = JSON.parse(value);
11519
+ const redact = (item) => {
11520
+ if (Array.isArray(item)) return item.map(redact);
11521
+ if (!item || typeof item !== "object") return item;
11522
+ return Object.fromEntries(Object.entries(item).map(([key, entry]) => [key, isSensitiveName(key) ? "<redacted>" : redact(entry)]));
11523
+ };
11524
+ return JSON.stringify(redact(parsed), null, 2);
11525
+ } catch {
11526
+ return value.replace(
11527
+ /\b(authorization|cookie|token|secret|password|api[-_]?key|client[-_]?secret|key)\b\s*[:=]\s*(?:Bearer\s+)?(?:"[^"]*"|'[^']*'|[^,\r\n;}]+)/gi,
11528
+ "$1: <redacted>"
11529
+ );
11530
+ }
11531
+ }
11532
+ function safeRequest(request) {
11533
+ return {
11534
+ ...request,
11535
+ url: sanitizeUrl(request.url),
11536
+ body: redactBody(request.body),
11537
+ ...request.documentation ? { documentation: redactBody(request.documentation) } : {},
11538
+ ...request.responses ? {
11539
+ responses: request.responses.map((response) => ({
11540
+ ...response,
11541
+ content: response.content.map((content) => ({ ...content, example: redactBody(content.example) }))
11542
+ }))
11543
+ } : {},
11544
+ ...request.openApiSchemas ? { openApiSchemas: JSON.parse(redactBody(JSON.stringify(request.openApiSchemas))) } : {},
11545
+ ...request.headers ? { headers: request.headers.map((header) => ({ ...header, value: isSensitiveName(header.name) ? maskSecret(header.value) : header.value })) } : {},
11546
+ ...request.params ? { params: request.params.map((param) => ({ ...param, value: isSensitiveName(param.name) ? maskSecret(param.value) : param.value })) } : {},
11547
+ ...request.pathParams ? { pathParams: request.pathParams.map((param) => ({ ...param, value: isSensitiveName(param.name) ? maskSecret(param.value) : param.value })) } : {},
11548
+ ...request.bodyFields ? { bodyFields: request.bodyFields.map((field) => ({ ...field, value: isSensitiveName(field.name) ? maskSecret(field.value) : field.value, filePath: void 0 })) } : {},
11549
+ ...request.auth?.type === "bearer" ? { auth: { type: "bearer", token: maskSecret(request.auth.token) } } : {},
11550
+ ...request.auth?.type === "basic" ? { auth: { type: "basic", username: maskSecret(request.auth.username), password: maskSecret(request.auth.password) } } : {},
11551
+ ...request.auth?.type === "api-key" ? { auth: { ...request.auth, value: maskSecret(request.auth.value) } } : {},
11552
+ bodyPath: void 0
11553
+ };
11554
+ }
11555
+ function safeTree(nodes) {
11556
+ return nodes.map(
11557
+ (node) => isFolder(node) ? { id: node.id, kind: node.kind, name: node.name, children: safeTree(node.children) } : { id: node.id, kind: node.kind, name: node.name, method: node.method, url: sanitizeUrl(node.url), deprecated: node.deprecated === true }
11558
+ );
11559
+ }
11560
+ function summarize(node) {
11561
+ if (!node) return void 0;
11562
+ return isFolder(node) ? { id: node.id, kind: node.kind, name: node.name, childCount: node.children.length } : safeRequest(node);
11563
+ }
11564
+
11565
+ // src/operations.ts
11566
+ function applyOperation(tree, operation) {
11567
+ if (operation.action === "create_folder") {
11568
+ const parent = operation.parentId ? findNode(tree, operation.parentId) : void 0;
11569
+ if (operation.parentId && (!parent || !isFolder(parent))) throw new Error(`Parent folder "${operation.parentId}" was not found.`);
11570
+ const folder = { id: randomUUID2(), kind: "folder", name: operation.name.trim(), children: [] };
11571
+ return { tree: insertNode(tree, operation.parentId, folder), summary: { action: operation.action, target: folder.name, after: summarize(folder) } };
11572
+ }
11573
+ if (operation.action === "create_request") {
11574
+ const parent = operation.parentId ? findNode(tree, operation.parentId) : void 0;
11575
+ if (operation.parentId && (!parent || !isFolder(parent))) throw new Error(`Parent folder "${operation.parentId}" was not found.`);
11576
+ const request = normalizeRequest(operation.request);
11577
+ return { tree: insertNode(tree, operation.parentId, request), summary: { action: operation.action, target: request.name, after: summarize(request) } };
11578
+ }
11579
+ if (operation.action === "update_request") {
11580
+ const before2 = findNode(tree, operation.requestId);
11581
+ if (!before2 || isFolder(before2)) throw new Error(`Request "${operation.requestId}" was not found.`);
11582
+ const updated = normalizeRequest(
11583
+ { ...before2, ...operation.patch, name: operation.patch.name ?? before2.name, method: operation.patch.method ?? before2.method, url: operation.patch.url ?? before2.url },
11584
+ before2
11585
+ );
11586
+ const result = updateNode(tree, operation.requestId, () => updated);
11587
+ return { tree: result.tree, summary: { action: operation.action, target: updated.name, before: summarize(before2), after: summarize(updated) } };
11588
+ }
11589
+ if (operation.action === "rename_folder") {
11590
+ const before2 = findNode(tree, operation.folderId);
11591
+ if (!before2 || !isFolder(before2)) throw new Error(`Folder "${operation.folderId}" was not found.`);
11592
+ const result = updateNode(tree, operation.folderId, (node) => isFolder(node) ? { ...node, name: operation.name.trim() } : node);
11593
+ return {
11594
+ tree: result.tree,
11595
+ summary: { action: operation.action, target: operation.name.trim(), before: summarize(before2), after: { ...summarize(before2), name: operation.name.trim() } }
11596
+ };
11597
+ }
11598
+ if (operation.action === "move_node") {
11599
+ const before2 = findNode(tree, operation.nodeId);
11600
+ if (!before2) throw new Error(`Collection item "${operation.nodeId}" was not found.`);
11601
+ const parent = operation.parentId ? findNode(tree, operation.parentId) : void 0;
11602
+ if (operation.parentId && (!parent || !isFolder(parent))) throw new Error(`Parent folder "${operation.parentId}" was not found.`);
11603
+ if (isFolder(before2) && (before2.id === operation.parentId || findNode(before2.children, operation.parentId ?? "")?.kind === "folder"))
11604
+ throw new Error("A folder cannot be moved inside itself or one of its descendants.");
11605
+ const oldParentId = findParentId(tree, before2.id);
11606
+ const removed2 = removeNode(tree, before2.id);
11607
+ if (!removed2.removed) throw new Error(`Collection item "${operation.nodeId}" could not be moved.`);
11608
+ const next = insertNode(removed2.tree, operation.parentId, removed2.removed, operation.index);
11609
+ return { tree: next, summary: { action: operation.action, target: before2.name, before: { parentId: oldParentId }, after: { parentId: operation.parentId, index: operation.index } } };
11610
+ }
11611
+ if (operation.action === "deprecate_request") {
11612
+ const before2 = findNode(tree, operation.requestId);
11613
+ if (!before2 || isFolder(before2)) throw new Error(`Request "${operation.requestId}" was not found.`);
11614
+ const updated = {
11615
+ ...before2,
11616
+ deprecated: operation.deprecated,
11617
+ ...operation.deprecated && operation.reason?.trim() ? { deprecationReason: operation.reason.trim() } : {},
11618
+ ...!operation.deprecated ? { deprecationReason: void 0 } : {}
11619
+ };
11620
+ const result = updateNode(tree, operation.requestId, () => updated);
11621
+ return {
11622
+ tree: result.tree,
11623
+ summary: {
11624
+ action: operation.action,
11625
+ target: updated.name,
11626
+ before: { deprecated: before2.deprecated === true, deprecationReason: before2.deprecationReason },
11627
+ after: { deprecated: updated.deprecated, deprecationReason: updated.deprecationReason }
11628
+ }
11629
+ };
11630
+ }
11631
+ const before = findNode(tree, operation.nodeId);
11632
+ if (!before) throw new Error(`Collection item "${operation.nodeId}" was not found.`);
11633
+ const removed = removeNode(tree, operation.nodeId);
11634
+ return { tree: removed.tree, summary: { action: operation.action, target: before.name, before: summarize(before) } };
11635
+ }
11636
+ function applyOperations(tree, operations) {
11637
+ let next = tree;
11638
+ const summary = [];
11639
+ for (const operation of operations) {
11640
+ const result = applyOperation(next, operation);
11641
+ next = result.tree;
11642
+ summary.push(result.summary);
11643
+ }
11644
+ return { tree: next, summary };
11645
+ }
11646
+
11647
+ // src/store.ts
11648
+ import { createHash, randomUUID as randomUUID3 } from "node:crypto";
11649
+ import { existsSync } from "node:fs";
11650
+ import { homedir } from "node:os";
11651
+ import { join } from "node:path";
11652
+ import { DatabaseSync } from "node:sqlite";
11653
+ function dataDirectory() {
11654
+ const appName = "api-documentation-bit";
11655
+ if (process.env.API_DOCS_USER_DATA_DIR) return process.env.API_DOCS_USER_DATA_DIR;
11656
+ const base = process.platform === "win32" ? process.env.APPDATA || join(homedir(), "AppData", "Roaming") : process.platform === "darwin" ? join(homedir(), "Library", "Application Support") : process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
11657
+ return join(base, appName);
11658
+ }
11659
+ var localDatabase;
11660
+ var openedPath;
11661
+ function database() {
11662
+ const path = join(dataDirectory(), "workspace.sqlite");
11663
+ if (!existsSync(path)) {
11664
+ throw new Error(`Workspace database was not found at ${path}. Open API Documentation once to create the local workspace.`);
11665
+ }
11666
+ if (!localDatabase || openedPath !== path) {
11667
+ localDatabase?.close();
11668
+ localDatabase = new DatabaseSync(path);
11669
+ localDatabase.exec("PRAGMA busy_timeout = 5000;");
11670
+ openedPath = path;
11671
+ }
11672
+ return localDatabase;
11673
+ }
11674
+ function hashRaw(raw) {
11675
+ return createHash("sha256").update(raw).digest("hex");
11676
+ }
11677
+ function secretFingerprint(workspaceId5, variableId) {
11678
+ try {
11679
+ const row = database().prepare("SELECT value FROM secrets WHERE key = ?").get(`workspace-variable:${workspaceId5}:${variableId}`);
11680
+ return row ? createHash("sha256").update(row.value).digest("hex") : "";
11681
+ } catch (error2) {
11682
+ if (error2 instanceof Error && /no such table/.test(error2.message)) return "";
11683
+ throw error2;
11684
+ }
11685
+ }
11686
+ var activeAccountKey = "active-account";
11687
+ function activeAccountId() {
11688
+ try {
11689
+ const row = database().prepare("SELECT value FROM app_settings WHERE key = ?").get(activeAccountKey);
11690
+ return row?.value ?? null;
11691
+ } catch (error2) {
11692
+ if (error2 instanceof Error && /no such table/.test(error2.message)) return null;
11693
+ throw error2;
11694
+ }
11695
+ }
11696
+ function visibleTo(workspace, accountId) {
11697
+ if (!workspace.cloudId || !accountId) return true;
11698
+ return !workspace.accountId || workspace.accountId === accountId;
11699
+ }
11700
+ function listWorkspaces() {
11701
+ const accountId = activeAccountId();
11702
+ const rows = database().prepare("SELECT data FROM workspaces ORDER BY rowid").all();
11703
+ return rows.map(({ data }) => JSON.parse(data)).filter((workspace) => visibleTo(workspace, accountId)).map((workspace) => ({ id: workspace.id, name: workspace.name, cloudId: workspace.cloudId ?? null, role: workspace.role ?? null }));
11704
+ }
11705
+ function readWorkspace(workspaceId5) {
11706
+ const row = database().prepare("SELECT data FROM workspaces WHERE id = ?").get(workspaceId5);
11707
+ if (!row) throw new Error(`Workspace "${workspaceId5}" was not found.`);
11708
+ const workspace = JSON.parse(row.data);
11709
+ if (!visibleTo(workspace, activeAccountId())) throw new Error(`Workspace "${workspaceId5}" was not found.`);
11710
+ if (!Array.isArray(workspace.tree)) throw new Error("Workspace collection data is invalid.");
11711
+ return { raw: row.data, workspace };
11712
+ }
11713
+ function assertCanEdit(workspace) {
11714
+ if (workspace.role === "viewer") throw new Error("This workspace is read-only for the current account.");
11715
+ }
11716
+ function updateWorkspace(workspaceId5, change) {
11717
+ const db = database();
11718
+ db.exec("BEGIN IMMEDIATE;");
11719
+ try {
11720
+ const { raw, workspace } = readWorkspace(workspaceId5);
11721
+ assertCanEdit(workspace);
11722
+ const next = change(workspace, raw);
11723
+ db.prepare("UPDATE workspaces SET data = ? WHERE id = ?").run(JSON.stringify(next), workspaceId5);
11724
+ db.exec("COMMIT;");
11725
+ return next;
11726
+ } catch (error2) {
11727
+ db.exec("ROLLBACK;");
11728
+ throw error2;
11729
+ }
11730
+ }
11731
+ function insertWorkspace(workspace) {
11732
+ database().prepare("INSERT INTO workspaces (id, data) VALUES (?, ?)").run(workspace.id, JSON.stringify(workspace));
11733
+ }
11734
+ function deleteWorkspace(workspaceId5) {
11735
+ const db = database();
11736
+ db.exec("BEGIN IMMEDIATE;");
11737
+ try {
11738
+ const { workspace } = readWorkspace(workspaceId5);
11739
+ if (workspace.cloudId) throw new Error("Cloud workspaces are managed in the desktop app, not from the CLI.");
11740
+ db.prepare("DELETE FROM commits WHERE workspace_id = ?").run(workspaceId5);
11741
+ db.prepare("DELETE FROM workspaces WHERE id = ?").run(workspaceId5);
11742
+ db.exec("COMMIT;");
11743
+ } catch (error2) {
11744
+ db.exec("ROLLBACK;");
11745
+ throw error2;
11746
+ }
11747
+ }
11748
+
11749
+ // src/schemas.ts
11750
+ var bodyModes = ["form-data", "urlencoded", "graphql", "json", "xml", "yaml", "edn", "text", "other", "file", "none"];
11751
+ var authSchema = external_exports.discriminatedUnion("type", [
11752
+ external_exports.object({ type: external_exports.literal("none") }),
11753
+ external_exports.object({ type: external_exports.literal("bearer"), token: external_exports.string().max(65536) }),
11754
+ external_exports.object({ type: external_exports.literal("basic"), username: external_exports.string().max(8192), password: external_exports.string().max(65536) }),
11755
+ external_exports.object({ type: external_exports.literal("api-key"), name: external_exports.string().max(8192), value: external_exports.string().max(65536), location: external_exports.enum(["header", "query"]) })
11756
+ ]);
11757
+ var fieldSchema = external_exports.object({
11758
+ id: external_exports.string().optional(),
11759
+ name: external_exports.string().max(8192),
11760
+ value: external_exports.string().max(65536),
11761
+ enabled: external_exports.boolean().default(true),
11762
+ description: external_exports.string().max(4096).optional()
11763
+ });
11764
+ var bodyFieldSchema = external_exports.object({
11765
+ id: external_exports.string().optional(),
11766
+ name: external_exports.string().max(8192),
11767
+ value: external_exports.string().max(65536),
11768
+ enabled: external_exports.boolean().default(true),
11769
+ type: external_exports.enum(["text", "file"]).default("text"),
11770
+ fileName: external_exports.string().max(1024).optional()
11771
+ });
11772
+ var responseContentSchema = external_exports.object({
11773
+ id: external_exports.string().optional(),
11774
+ mediaType: external_exports.string().max(160),
11775
+ schema: external_exports.string().max(1e6),
11776
+ example: external_exports.string().max(1e6)
11777
+ });
11778
+ var responseDefinitionSchema = external_exports.object({
11779
+ id: external_exports.string().optional(),
11780
+ statusCode: external_exports.string().trim().min(1).max(12),
11781
+ description: external_exports.string().max(500),
11782
+ content: external_exports.array(responseContentSchema).max(20)
11783
+ });
11784
+ var method = external_exports.string().trim().min(1).max(32).transform((value) => value.toUpperCase());
11785
+ var requestFields = {
11786
+ name: external_exports.string().trim().min(1).max(160),
11787
+ method,
11788
+ url: external_exports.string().max(8192),
11789
+ body: external_exports.string().max(1e6).optional(),
11790
+ bodyMode: external_exports.enum(bodyModes).optional(),
11791
+ bodyFields: external_exports.array(bodyFieldSchema).max(100).optional(),
11792
+ bodyVariables: external_exports.string().max(1e6).optional(),
11793
+ bodyMimeType: external_exports.string().max(1024).optional(),
11794
+ bodyFileName: external_exports.string().max(1024).optional(),
11795
+ headers: external_exports.array(fieldSchema).max(100).optional(),
11796
+ params: external_exports.array(fieldSchema).max(100).optional(),
11797
+ pathParams: external_exports.array(fieldSchema).max(100).optional(),
11798
+ auth: authSchema.optional(),
11799
+ documentation: external_exports.string().max(1e5).optional(),
11800
+ responses: external_exports.array(responseDefinitionSchema).max(100).optional(),
11801
+ deprecated: external_exports.boolean().optional(),
11802
+ deprecationReason: external_exports.string().max(4096).optional()
11803
+ };
11804
+ var requestSchema = external_exports.object(requestFields);
11805
+ var requestPatchSchema = external_exports.object(requestFields).partial();
11806
+ var operationSchema = external_exports.discriminatedUnion("action", [
11807
+ external_exports.object({ action: external_exports.literal("create_folder"), parentId: external_exports.string().nullable().default(null), name: external_exports.string().trim().min(1).max(160) }),
11808
+ external_exports.object({ action: external_exports.literal("create_request"), parentId: external_exports.string().nullable().default(null), request: requestSchema }),
11809
+ external_exports.object({ action: external_exports.literal("update_request"), requestId: external_exports.string().min(1), patch: requestPatchSchema }),
11810
+ external_exports.object({ action: external_exports.literal("rename_folder"), folderId: external_exports.string().min(1), name: external_exports.string().trim().min(1).max(160) }),
11811
+ external_exports.object({ action: external_exports.literal("move_node"), nodeId: external_exports.string().min(1), parentId: external_exports.string().nullable().default(null), index: external_exports.number().int().min(0).optional() }),
11812
+ external_exports.object({ action: external_exports.literal("deprecate_request"), requestId: external_exports.string().min(1), deprecated: external_exports.boolean().default(true), reason: external_exports.string().max(4096).optional() }),
11813
+ external_exports.object({ action: external_exports.literal("delete_node"), nodeId: external_exports.string().min(1) })
11814
+ ]);
11815
+ var variableNameSchema = external_exports.string().trim().min(1).max(160);
11816
+ var variableValueSchema = external_exports.string().max(65536);
11817
+
11818
+ // src/commands/changes.ts
11819
+ var plans = /* @__PURE__ */ new Map();
11820
+ var planLifetimeMs = 10 * 60 * 1e3;
11821
+ var changeCommands = [
11822
+ defineCommand({
11823
+ id: "changes.preview",
11824
+ group: "changes",
11825
+ title: "Preview collection changes",
11826
+ description: "Validate a batch of collection operations and return sanitized before/after data without changing anything. Show the preview to the user, then call changes.apply only after they approve it.",
11827
+ params: external_exports.object({ workspaceId: external_exports.string().min(1), operations: external_exports.array(operationSchema).min(1).max(100) }),
11828
+ readOnly: true,
11829
+ run: ({ workspaceId: id, operations }) => {
11830
+ const { raw, workspace } = readWorkspace(id);
11831
+ if (workspace.role === "viewer") throw new Error("This workspace is read-only for the current account.");
11832
+ const result = applyOperations(structuredClone(workspace.tree), operations);
11833
+ const previewId = randomUUID4();
11834
+ const plan = {
11835
+ id: previewId,
11836
+ workspaceId: id,
11837
+ sourceHash: hashRaw(raw),
11838
+ operations,
11839
+ nextTree: result.tree,
11840
+ summary: result.summary,
11841
+ includesDelete: operations.some((operation) => operation.action === "delete_node"),
11842
+ expiresAt: Date.now() + planLifetimeMs
11843
+ };
11844
+ plans.set(previewId, plan);
11845
+ return {
11846
+ previewId,
11847
+ workspaceId: id,
11848
+ workspaceName: workspace.name,
11849
+ changes: result.summary,
11850
+ deletesItems: plan.includesDelete,
11851
+ expiresInSeconds: planLifetimeMs / 1e3
11852
+ };
11853
+ }
11854
+ }),
11855
+ defineCommand({
11856
+ id: "changes.apply",
11857
+ group: "changes",
11858
+ title: "Apply previewed changes",
11859
+ description: "Apply a batch returned by changes.preview. Only call after the user approved that exact preview. Requires confirmDelete=true when the batch deletes anything.",
11860
+ params: external_exports.object({ previewId: external_exports.string().min(1), confirmDelete: external_exports.boolean().default(false) }),
11861
+ readOnly: false,
11862
+ destructive: true,
11863
+ run: ({ previewId, confirmDelete }) => {
11864
+ const plan = plans.get(previewId);
11865
+ if (!plan || plan.expiresAt < Date.now()) {
11866
+ plans.delete(previewId);
11867
+ throw new Error("This preview expired or was not found. Run changes.preview again.");
11868
+ }
11869
+ if (plan.includesDelete && !confirmDelete) {
11870
+ throw new Error("This batch includes deletion. Ask the user to confirm the listed deletions, then retry with confirmDelete=true.");
11871
+ }
11872
+ const updated = updateWorkspace(plan.workspaceId, (workspace, raw) => {
11873
+ if (hashRaw(raw) !== plan.sourceHash) {
11874
+ throw new Error("The workspace changed after this preview. Run changes.preview again to avoid overwriting newer edits.");
11875
+ }
11876
+ return { ...workspace, tree: structuredClone(plan.nextTree) };
11877
+ });
11878
+ plans.delete(previewId);
11879
+ return { applied: true, workspaceId: plan.workspaceId, workspaceName: updated.name, changes: plan.summary };
11880
+ }
11881
+ })
11882
+ ];
11883
+
11884
+ // src/commands/collection.ts
11885
+ var workspaceId = external_exports.string().min(1).describe("Workspace id from workspace.list");
11886
+ var folderId = external_exports.string().min(1).describe("Folder id from tree.get");
11887
+ var nodeId = external_exports.string().min(1).describe("Folder or request id from tree.get");
11888
+ var parentId = external_exports.string().nullable().default(null).describe("Parent folder id, or null for the root");
11889
+ var confirm = external_exports.literal(true).describe("Must be true; ask the user first");
11890
+ var collectionCommands = [
11891
+ defineCommand({
11892
+ id: "folder.create",
11893
+ group: "collection",
11894
+ title: "Create folder",
11895
+ description: "Create a folder under a parent folder, or at the root when parentId is null.",
11896
+ params: external_exports.object({ workspaceId, parentId, name: external_exports.string().trim().min(1).max(160) }),
11897
+ readOnly: false,
11898
+ run: ({ workspaceId: id, parentId: parent, name }) => {
11899
+ let created;
11900
+ updateWorkspace(id, (workspace) => {
11901
+ const result = applyOperation(workspace.tree, { action: "create_folder", parentId: parent, name });
11902
+ created = result.summary.after;
11903
+ return { ...workspace, tree: result.tree };
11904
+ });
11905
+ return created;
11906
+ }
11907
+ }),
11908
+ defineCommand({
11909
+ id: "folder.rename",
11910
+ group: "collection",
11911
+ title: "Rename folder",
11912
+ description: "Rename a folder.",
11913
+ params: external_exports.object({ workspaceId, folderId, name: external_exports.string().trim().min(1).max(160) }),
11914
+ readOnly: false,
11915
+ run: ({ workspaceId: id, folderId: folder, name }) => {
11916
+ updateWorkspace(id, (workspace) => ({ ...workspace, tree: applyOperation(workspace.tree, { action: "rename_folder", folderId: folder, name }).tree }));
11917
+ return { renamed: true, folderId: folder, name };
11918
+ }
11919
+ }),
11920
+ defineCommand({
11921
+ id: "folder.delete",
11922
+ group: "collection",
11923
+ title: "Delete folder",
11924
+ description: "Delete a folder and everything in it. Requires confirm=true after the user confirms the listed deletions.",
11925
+ params: external_exports.object({ workspaceId, folderId, confirm }),
11926
+ readOnly: false,
11927
+ destructive: true,
11928
+ run: ({ workspaceId: id, folderId: folder }) => {
11929
+ updateWorkspace(id, (workspace) => ({ ...workspace, tree: applyOperation(workspace.tree, { action: "delete_node", nodeId: folder }).tree }));
11930
+ return { deleted: true, folderId: folder };
11931
+ }
11932
+ }),
11933
+ defineCommand({
11934
+ id: "node.move",
11935
+ group: "collection",
11936
+ title: "Move folder or request",
11937
+ description: "Move a folder or request under another folder (or the root), optionally at a position.",
11938
+ params: external_exports.object({ workspaceId, nodeId, parentId, index: external_exports.number().int().min(0).optional() }),
11939
+ readOnly: false,
11940
+ run: ({ workspaceId: id, nodeId: node, parentId: parent, index }) => {
11941
+ updateWorkspace(id, (workspace) => ({
11942
+ ...workspace,
11943
+ tree: applyOperation(workspace.tree, { action: "move_node", nodeId: node, parentId: parent, index }).tree
11944
+ }));
11945
+ return { moved: true, nodeId: node, parentId: parent, index: index ?? null };
11946
+ }
11947
+ })
11948
+ ];
11949
+
11950
+ // src/commands/environments.ts
11951
+ import { randomUUID as randomUUID5 } from "node:crypto";
11952
+ var workspaceId2 = external_exports.string().min(1).describe("Workspace id from workspace.list");
11953
+ var environmentId = external_exports.string().min(1).describe("Environment id from environment.list");
11954
+ var confirm2 = external_exports.literal(true).describe("Must be true; ask the user first");
11955
+ var maxEnvironments = 100;
11956
+ function variablesOf(workspace) {
11957
+ return workspace.variables ?? { globals: [], environments: [] };
11958
+ }
11959
+ function withVariables(workspace, variables) {
11960
+ return { ...workspace, variables };
11961
+ }
11962
+ function masked(row) {
11963
+ return { id: row.id, name: row.name, secret: row.secret, value: row.secret ? "<secret>" : row.value };
11964
+ }
11965
+ function findEnvironment(variables, id) {
11966
+ const environment = variables.environments.find((item) => item.id === id);
11967
+ if (!environment) throw new Error(`Environment "${id}" was not found.`);
11968
+ return environment;
11969
+ }
11970
+ var scopeSchema = external_exports.enum(["global", "environment"]).describe("global for workspace-wide values, environment for one environment");
11971
+ function rowsFor(variables, scope, env) {
11972
+ if (scope === "global") return variables.globals;
11973
+ if (!env) throw new Error("environmentId is required for an environment variable.");
11974
+ return findEnvironment(variables, env).variables;
11975
+ }
11976
+ function variableRevision(workspaceId5, row) {
11977
+ if (!row) return null;
11978
+ const sealed = row.secret ? secretFingerprint(workspaceId5, row.id) : "";
11979
+ return hashRaw(JSON.stringify({ id: row.id, name: row.name, secret: row.secret, value: row.secret ? "" : row.value, sealed }));
11980
+ }
11981
+ function changedSinceRead(name) {
11982
+ return new Error(`"${name}" changed since you read it. Read it again with variable.get and review the change before writing.`);
11983
+ }
11984
+ var environmentCommands = [
11985
+ defineCommand({
11986
+ id: "environment.list",
11987
+ group: "environment",
11988
+ title: "List environments and variables",
11989
+ description: "List globals and environments with their variables. Secret values are shown as <secret>.",
11990
+ params: external_exports.object({ workspaceId: workspaceId2 }),
11991
+ readOnly: true,
11992
+ run: ({ workspaceId: id }) => {
11993
+ const { workspace } = readWorkspace(id);
11994
+ const variables = variablesOf(workspace);
11995
+ return {
11996
+ activeEnvironmentId: workspace.activeEnvironmentId ?? null,
11997
+ globals: variables.globals.map(masked),
11998
+ environments: variables.environments.map((environment) => ({
11999
+ id: environment.id,
12000
+ name: environment.name,
12001
+ variables: environment.variables.map(masked)
12002
+ }))
12003
+ };
12004
+ }
12005
+ }),
12006
+ defineCommand({
12007
+ id: "environment.create",
12008
+ group: "environment",
12009
+ title: "Create environment",
12010
+ description: "Create an empty environment. It is not activated until environment.activate.",
12011
+ params: external_exports.object({ workspaceId: workspaceId2, name: external_exports.string().trim().min(1).max(160) }),
12012
+ readOnly: false,
12013
+ run: ({ workspaceId: id, name }) => {
12014
+ let created;
12015
+ updateWorkspace(id, (workspace) => {
12016
+ const variables = variablesOf(workspace);
12017
+ if (variables.environments.length >= maxEnvironments) throw new Error(`A workspace can have at most ${maxEnvironments} environments.`);
12018
+ created = { id: randomUUID5(), name, variables: [] };
12019
+ return withVariables(workspace, { ...variables, environments: [...variables.environments, created] });
12020
+ });
12021
+ return { id: created?.id, name };
12022
+ }
12023
+ }),
12024
+ defineCommand({
12025
+ id: "environment.rename",
12026
+ group: "environment",
12027
+ title: "Rename environment",
12028
+ description: "Rename an environment.",
12029
+ params: external_exports.object({ workspaceId: workspaceId2, environmentId, name: external_exports.string().trim().min(1).max(160) }),
12030
+ readOnly: false,
12031
+ run: ({ workspaceId: id, environmentId: env, name }) => {
12032
+ updateWorkspace(id, (workspace) => {
12033
+ const variables = variablesOf(workspace);
12034
+ findEnvironment(variables, env);
12035
+ return withVariables(workspace, {
12036
+ ...variables,
12037
+ environments: variables.environments.map((item) => item.id === env ? { ...item, name } : item)
12038
+ });
12039
+ });
12040
+ return { id: env, name };
12041
+ }
12042
+ }),
12043
+ defineCommand({
12044
+ id: "environment.duplicate",
12045
+ group: "environment",
12046
+ title: "Duplicate environment",
12047
+ description: 'Copy an environment as "<name>_copy" with new variable ids. Secret values are copied as empty and must be set in the app.',
12048
+ params: external_exports.object({ workspaceId: workspaceId2, environmentId }),
12049
+ readOnly: false,
12050
+ run: ({ workspaceId: id, environmentId: env }) => {
12051
+ let copy;
12052
+ updateWorkspace(id, (workspace) => {
12053
+ const variables = variablesOf(workspace);
12054
+ const source = findEnvironment(variables, env);
12055
+ if (variables.environments.length >= maxEnvironments) throw new Error(`A workspace can have at most ${maxEnvironments} environments.`);
12056
+ copy = {
12057
+ id: randomUUID5(),
12058
+ name: `${source.name}_copy`,
12059
+ variables: source.variables.map((row) => ({ ...row, id: randomUUID5(), value: row.secret ? "" : row.value }))
12060
+ };
12061
+ return withVariables(workspace, { ...variables, environments: [...variables.environments, copy] });
12062
+ });
12063
+ return { id: copy?.id, name: copy?.name };
12064
+ }
12065
+ }),
12066
+ defineCommand({
12067
+ id: "environment.delete",
12068
+ group: "environment",
12069
+ title: "Delete environment",
12070
+ description: "Delete an environment and its variables. Requires confirm=true after the user confirms.",
12071
+ params: external_exports.object({ workspaceId: workspaceId2, environmentId, confirm: confirm2 }),
12072
+ readOnly: false,
12073
+ destructive: true,
12074
+ run: ({ workspaceId: id, environmentId: env }) => {
12075
+ updateWorkspace(id, (workspace) => {
12076
+ const variables = variablesOf(workspace);
12077
+ findEnvironment(variables, env);
12078
+ return {
12079
+ ...withVariables(workspace, { ...variables, environments: variables.environments.filter((item) => item.id !== env) }),
12080
+ activeEnvironmentId: workspace.activeEnvironmentId === env ? null : workspace.activeEnvironmentId
12081
+ };
12082
+ });
12083
+ return { deleted: true, environmentId: env };
12084
+ }
12085
+ }),
12086
+ defineCommand({
12087
+ id: "environment.activate",
12088
+ group: "environment",
12089
+ title: "Set active environment",
12090
+ description: "Make an environment the active one that requests use, or pass null to use none.",
12091
+ params: external_exports.object({ workspaceId: workspaceId2, environmentId: external_exports.string().min(1).nullable() }),
12092
+ readOnly: false,
12093
+ run: ({ workspaceId: id, environmentId: env }) => {
12094
+ updateWorkspace(id, (workspace) => {
12095
+ if (env !== null) findEnvironment(variablesOf(workspace), env);
12096
+ return { ...workspace, activeEnvironmentId: env };
12097
+ });
12098
+ return { activeEnvironmentId: env };
12099
+ }
12100
+ }),
12101
+ defineCommand({
12102
+ id: "variable.get",
12103
+ group: "environment",
12104
+ title: "Get variable",
12105
+ description: "Read one variable and its revision. Secret values are never returned. Pass the revision to variable.set or variable.delete, so a change made since this read is refused.",
12106
+ params: external_exports.object({
12107
+ workspaceId: workspaceId2,
12108
+ scope: scopeSchema,
12109
+ environmentId: external_exports.string().min(1).optional().describe("Required when scope is environment"),
12110
+ name: variableNameSchema
12111
+ }),
12112
+ readOnly: true,
12113
+ run: ({ workspaceId: id, scope, environmentId: env, name }) => {
12114
+ const { workspace } = readWorkspace(id);
12115
+ const existing = rowsFor(variablesOf(workspace), scope, env).find((row) => row.name === name);
12116
+ if (!existing) return { exists: false, name, scope, environmentId: env ?? null, revision: null };
12117
+ return { exists: true, ...masked(existing), scope, environmentId: env ?? null, revision: variableRevision(id, existing) };
12118
+ }
12119
+ }),
12120
+ defineCommand({
12121
+ id: "variable.set",
12122
+ group: "environment",
12123
+ title: "Set variable",
12124
+ description: "Create or update a variable in globals or one environment. Read the variable with variable.get first and pass its revision as expectedRevision (null when it does not exist yet). A secret variable is created with an empty value; its value must be entered in the desktop app, and an existing secret cannot be changed here.",
12125
+ params: external_exports.object({
12126
+ workspaceId: workspaceId2,
12127
+ scope: scopeSchema,
12128
+ environmentId: external_exports.string().min(1).optional().describe("Required when scope is environment"),
12129
+ name: variableNameSchema,
12130
+ value: variableValueSchema.optional(),
12131
+ secret: external_exports.boolean().optional().describe("Secret variables keep their value in the app only"),
12132
+ expectedRevision: external_exports.string().min(1).nullable().optional().describe("Revision from variable.get; null when the variable does not exist yet")
12133
+ }),
12134
+ readOnly: false,
12135
+ run: ({ workspaceId: id, scope, environmentId: env, name, value, secret, expectedRevision }) => {
12136
+ const updated = updateWorkspace(id, (workspace) => {
12137
+ const variables = variablesOf(workspace);
12138
+ if (scope === "environment" && !env) throw new Error("environmentId is required for an environment variable.");
12139
+ const rows = rowsFor(variables, scope, env);
12140
+ const existing = rows.find((row2) => row2.name === name);
12141
+ if (expectedRevision !== void 0) {
12142
+ if (existing && expectedRevision === null) throw new Error(`"${name}" already exists. Read it with variable.get and pass its revision.`);
12143
+ if (variableRevision(id, existing) !== expectedRevision) throw changedSinceRead(name);
12144
+ }
12145
+ if (existing?.secret && value !== void 0 && value !== "") {
12146
+ throw new Error(`"${name}" is a secret. Change its value in the desktop app.`);
12147
+ }
12148
+ if (secret === true && value) throw new Error(`"${name}" is a secret. Enter its value in the desktop app.`);
12149
+ const row = {
12150
+ id: existing?.id ?? randomUUID5(),
12151
+ name,
12152
+ value: secret ? "" : value ?? existing?.value ?? "",
12153
+ secret: secret ?? existing?.secret ?? false
12154
+ };
12155
+ const nextRows = existing ? rows.map((item) => item.id === existing.id ? row : item) : [...rows, row];
12156
+ if (scope === "global") return withVariables(workspace, { ...variables, globals: nextRows });
12157
+ return withVariables(workspace, {
12158
+ ...variables,
12159
+ environments: variables.environments.map((item) => item.id === env ? { ...item, variables: nextRows } : item)
12160
+ });
12161
+ });
12162
+ const written = rowsFor(variablesOf(updated), scope, env).find((row) => row.name === name);
12163
+ return { name, scope, environmentId: env ?? null, secret: secret ?? null, revision: variableRevision(id, written) };
12164
+ }
12165
+ }),
12166
+ defineCommand({
12167
+ id: "variable.delete",
12168
+ group: "environment",
12169
+ title: "Delete variable",
12170
+ description: "Delete a variable from globals or one environment. Read it with variable.get first and pass its revision as expectedRevision. Requires confirm=true after the user confirms.",
12171
+ params: external_exports.object({
12172
+ workspaceId: workspaceId2,
12173
+ scope: scopeSchema,
12174
+ environmentId: external_exports.string().min(1).optional(),
12175
+ name: variableNameSchema,
12176
+ expectedRevision: external_exports.string().min(1).nullable().optional().describe("Revision from variable.get"),
12177
+ confirm: confirm2
12178
+ }),
12179
+ readOnly: false,
12180
+ destructive: true,
12181
+ run: ({ workspaceId: id, scope, environmentId: env, name, expectedRevision }) => {
12182
+ updateWorkspace(id, (workspace) => {
12183
+ const variables = variablesOf(workspace);
12184
+ if (expectedRevision !== void 0) {
12185
+ const existing = rowsFor(variables, scope, env).find((row) => row.name === name);
12186
+ if (variableRevision(id, existing) !== expectedRevision) throw changedSinceRead(name);
12187
+ }
12188
+ if (scope === "global") {
12189
+ return withVariables(workspace, { ...variables, globals: variables.globals.filter((row) => row.name !== name) });
12190
+ }
12191
+ if (!env) throw new Error("environmentId is required for an environment variable.");
12192
+ return withVariables(workspace, {
12193
+ ...variables,
12194
+ environments: variables.environments.map(
12195
+ (item) => item.id === env ? { ...item, variables: item.variables.filter((row) => row.name !== name) } : item
12196
+ )
12197
+ });
12198
+ });
12199
+ return { deleted: true, name, scope };
12200
+ }
12201
+ })
12202
+ ];
12203
+
12204
+ // src/send.ts
12205
+ import { readFile } from "node:fs/promises";
12206
+ import { basename } from "node:path";
12207
+ var timeoutMs = 3e4;
12208
+ var maxBodyChars = 1e6;
12209
+ var variablePattern = /\{\{\s*([^{}]+?)\s*\}\}/g;
12210
+ function resolveVariables(workspace, environmentId2) {
12211
+ const variables = workspace.variables ?? { globals: [], environments: [] };
12212
+ const environment = variables.environments.find((item) => item.id === (environmentId2 ?? workspace.activeEnvironmentId ?? ""));
12213
+ const rows = [...variables.globals, ...environment?.variables ?? []];
12214
+ const values = /* @__PURE__ */ new Map();
12215
+ const blocked = /* @__PURE__ */ new Set();
12216
+ for (const row of rows) {
12217
+ if (row.secret || row.value === "") {
12218
+ blocked.add(row.name);
12219
+ values.delete(row.name);
12220
+ } else {
12221
+ values.set(row.name, row.value);
12222
+ blocked.delete(row.name);
12223
+ }
12224
+ }
12225
+ return { values, blocked };
12226
+ }
12227
+ function fill(text, values, missing) {
12228
+ return text.replace(variablePattern, (match, name) => {
12229
+ const value = values.get(name);
12230
+ if (value === void 0) {
12231
+ missing.add(name);
12232
+ return match;
12233
+ }
12234
+ return value;
12235
+ });
12236
+ }
12237
+ var defaultMime = {
12238
+ json: "application/json",
12239
+ graphql: "application/json",
12240
+ xml: "application/xml",
12241
+ yaml: "application/yaml",
12242
+ edn: "application/edn",
12243
+ text: "text/plain",
12244
+ other: "text/plain"
12245
+ };
12246
+ async function sendRequest(request, workspace, environmentId2, options = {}) {
12247
+ const { values, blocked } = resolveVariables(workspace, environmentId2);
12248
+ const missing = /* @__PURE__ */ new Set();
12249
+ const f = (text2) => fill(text2, values, missing);
12250
+ const headers = new Headers({ Accept: "*/*", "User-Agent": "API-Documentation-CLI/0.2.0" });
12251
+ for (const header of request.headers ?? []) {
12252
+ if (header.enabled && header.name.trim()) headers.set(f(header.name.trim()), f(header.value));
12253
+ }
12254
+ const url = new URL(f(request.url));
12255
+ url.pathname = url.pathname.split("/").map((segment) => {
12256
+ if (!segment.startsWith(":")) return segment;
12257
+ const name = segment.slice(1);
12258
+ const param = (request.pathParams ?? []).find((item) => item.enabled && item.name.trim() === name);
12259
+ if (!param) {
12260
+ missing.add(name);
12261
+ return segment;
12262
+ }
12263
+ return encodeURIComponent(f(param.value));
12264
+ }).join("/");
12265
+ for (const param of request.params ?? []) {
12266
+ if (param.enabled && param.name.trim()) url.searchParams.append(f(param.name.trim()), f(param.value));
12267
+ }
12268
+ const auth = request.auth ?? { type: "none" };
12269
+ if (auth.type === "bearer") headers.set("Authorization", `Bearer ${f(auth.token)}`);
12270
+ if (auth.type === "basic") headers.set("Authorization", `Basic ${Buffer.from(`${f(auth.username)}:${f(auth.password)}`).toString("base64")}`);
12271
+ if (auth.type === "api-key") {
12272
+ if (auth.location === "query") url.searchParams.set(f(auth.name), f(auth.value));
12273
+ else headers.set(f(auth.name), f(auth.value));
12274
+ }
12275
+ let body;
12276
+ const mode = request.bodyMode ?? "none";
12277
+ if (mode === "urlencoded") {
12278
+ const form = new URLSearchParams();
12279
+ for (const field of request.bodyFields ?? []) if (field.enabled && field.type === "text") form.append(f(field.name), f(field.value));
12280
+ body = form.toString();
12281
+ headers.set("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
12282
+ } else if (mode === "form-data") {
12283
+ const form = new FormData();
12284
+ for (const field of request.bodyFields ?? []) {
12285
+ if (!field.enabled) continue;
12286
+ if (field.type === "text") form.append(f(field.name), f(field.value));
12287
+ else if (field.filePath) form.append(f(field.name), new Blob([await readFile(field.filePath)]), field.fileName || basename(field.filePath));
12288
+ }
12289
+ body = form;
12290
+ } else if (mode === "file") {
12291
+ if (!request.bodyPath) throw new Error("This request has no file to send as its body.");
12292
+ body = new Blob([await readFile(request.bodyPath)]);
12293
+ if (!headers.has("Content-Type")) headers.set("Content-Type", request.bodyMimeType || "application/octet-stream");
12294
+ } else if (mode !== "none" && request.body) {
12295
+ body = f(request.body);
12296
+ if (!headers.has("Content-Type")) headers.set("Content-Type", request.bodyMimeType || defaultMime[mode] || "text/plain");
12297
+ }
12298
+ if (missing.size) {
12299
+ const names = [...missing];
12300
+ const secretNames = names.filter((name) => blocked.has(name));
12301
+ const hint = secretNames.length ? ` Enter the secret values (${secretNames.join(", ")}) in the desktop app.` : "";
12302
+ throw new Error(`Variables need a value before sending: ${names.join(", ")}.${hint} Set other values with variable.set.`);
12303
+ }
12304
+ const method2 = request.method.toUpperCase();
12305
+ const target = sanitizeUrl(url.toString());
12306
+ if (options.dryRun) return { dryRun: true, method: method2, url: target };
12307
+ if (options.confirmUrl !== void 0 && options.confirmUrl !== target) {
12308
+ throw new Error(`The target changed. This request now goes to ${target}. Confirm that URL with a dry run before sending.`);
12309
+ }
12310
+ const started = Date.now();
12311
+ const response = await fetch(url, {
12312
+ method: method2,
12313
+ headers,
12314
+ body: method2 === "GET" || method2 === "HEAD" ? void 0 : body,
12315
+ signal: AbortSignal.timeout(timeoutMs)
12316
+ });
12317
+ const text = await response.text();
12318
+ return {
12319
+ status: response.status,
12320
+ statusText: response.statusText,
12321
+ url: sanitizeUrl(response.url || url.toString()),
12322
+ durationMs: Date.now() - started,
12323
+ headers: Object.fromEntries(response.headers.entries()),
12324
+ body: text.length > maxBodyChars ? text.slice(0, maxBodyChars) : text,
12325
+ bodyTruncated: text.length > maxBodyChars
12326
+ };
12327
+ }
12328
+
12329
+ // src/commands/requests.ts
12330
+ var workspaceId3 = external_exports.string().min(1).describe("Workspace id from workspace.list");
12331
+ var requestId = external_exports.string().min(1).describe("Request id from tree.get or request.search");
12332
+ var parentId2 = external_exports.string().nullable().default(null).describe("Folder id, or null for the root");
12333
+ var confirm3 = external_exports.literal(true).describe("Must be true; ask the user first");
12334
+ var requestCommands = [
12335
+ defineCommand({
12336
+ id: "request.search",
12337
+ group: "request",
12338
+ title: "Search requests",
12339
+ description: "Search request names, methods, URLs, documentation, and response descriptions. Sensitive URL values are masked.",
12340
+ params: external_exports.object({ workspaceId: workspaceId3, query: external_exports.string().trim().min(1).max(200) }),
12341
+ readOnly: true,
12342
+ run: ({ workspaceId: id, query }) => {
12343
+ const { workspace } = readWorkspace(id);
12344
+ const needle = query.toLocaleLowerCase();
12345
+ return requestList(workspace.tree).filter((request) => {
12346
+ const haystack = [request.name, request.method, request.url, request.documentation ?? "", ...(request.responses ?? []).map((item) => item.description)];
12347
+ return haystack.join("\n").toLocaleLowerCase().includes(needle);
12348
+ }).map((request) => safeRequest(request));
12349
+ }
12350
+ }),
12351
+ defineCommand({
12352
+ id: "request.get",
12353
+ group: "request",
12354
+ title: "Read request",
12355
+ description: "Read one request definition: params, body, auth, headers, documented responses, and documentation. Literal secrets are redacted; {{variable}} references are shown as written.",
12356
+ params: external_exports.object({ workspaceId: workspaceId3, requestId }),
12357
+ readOnly: true,
12358
+ run: ({ workspaceId: id, requestId: request }) => safeRequest(findRequest(readWorkspace(id).workspace.tree, request))
12359
+ }),
12360
+ defineCommand({
12361
+ id: "request.create",
12362
+ group: "request",
12363
+ title: "Create request",
12364
+ description: "Create a request under a folder, or at the root when parentId is null. Use {{variableName}} for environment-specific values.",
12365
+ params: external_exports.object({ workspaceId: workspaceId3, parentId: parentId2, request: external_exports.object(requestFields) }),
12366
+ readOnly: false,
12367
+ run: ({ workspaceId: id, parentId: parent, request }) => {
12368
+ let created;
12369
+ updateWorkspace(id, (workspace) => {
12370
+ const result = applyOperation(workspace.tree, { action: "create_request", parentId: parent, request });
12371
+ created = result.summary.after;
12372
+ return { ...workspace, tree: result.tree };
12373
+ });
12374
+ return created;
12375
+ }
12376
+ }),
12377
+ defineCommand({
12378
+ id: "request.update",
12379
+ group: "request",
12380
+ title: "Update request",
12381
+ description: "Change fields of a request. Only the fields you send are changed; existing auth is kept unless you send auth.",
12382
+ params: external_exports.object({ workspaceId: workspaceId3, requestId, patch: external_exports.object(requestFields).partial() }),
12383
+ readOnly: false,
12384
+ run: ({ workspaceId: id, requestId: request, patch }) => {
12385
+ updateWorkspace(id, (workspace) => ({
12386
+ ...workspace,
12387
+ tree: applyOperation(workspace.tree, { action: "update_request", requestId: request, patch }).tree
12388
+ }));
12389
+ return { updated: true, requestId: request };
12390
+ }
12391
+ }),
12392
+ defineCommand({
12393
+ id: "request.duplicate",
12394
+ group: "request",
12395
+ title: "Duplicate request",
12396
+ description: 'Copy a request into the same folder as "<name>_copy", with new ids, and return the copy.',
12397
+ params: external_exports.object({ workspaceId: workspaceId3, requestId }),
12398
+ readOnly: false,
12399
+ run: ({ workspaceId: id, requestId: request }) => {
12400
+ let copyResult;
12401
+ updateWorkspace(id, (workspace) => {
12402
+ const original = findRequest(workspace.tree, request);
12403
+ const parent = findParentId(workspace.tree, original.id) ?? null;
12404
+ const copy = { ...cloneWithNewIds(original), name: `${original.name}_copy` };
12405
+ copyResult = safeRequest(copy);
12406
+ return { ...workspace, tree: insertNode(workspace.tree, parent, copy) };
12407
+ });
12408
+ return copyResult;
12409
+ }
12410
+ }),
12411
+ defineCommand({
12412
+ id: "request.deprecate",
12413
+ group: "request",
12414
+ title: "Mark request deprecated",
12415
+ description: "Mark a request as deprecated (or clear it) with an optional reason.",
12416
+ params: external_exports.object({ workspaceId: workspaceId3, requestId, deprecated: external_exports.boolean(), reason: external_exports.string().max(4096).optional() }),
12417
+ readOnly: false,
12418
+ run: ({ workspaceId: id, requestId: request, deprecated, reason }) => {
12419
+ updateWorkspace(id, (workspace) => ({
12420
+ ...workspace,
12421
+ tree: applyOperation(workspace.tree, { action: "deprecate_request", requestId: request, deprecated, reason }).tree
12422
+ }));
12423
+ return { requestId: request, deprecated };
12424
+ }
12425
+ }),
12426
+ defineCommand({
12427
+ id: "request.delete",
12428
+ group: "request",
12429
+ title: "Delete request",
12430
+ description: "Delete a request. Requires confirm=true after the user confirms.",
12431
+ params: external_exports.object({ workspaceId: workspaceId3, requestId, confirm: confirm3 }),
12432
+ readOnly: false,
12433
+ destructive: true,
12434
+ run: ({ workspaceId: id, requestId: request }) => {
12435
+ updateWorkspace(id, (workspace) => ({ ...workspace, tree: applyOperation(workspace.tree, { action: "delete_node", nodeId: request }).tree }));
12436
+ return { deleted: true, requestId: request };
12437
+ }
12438
+ }),
12439
+ defineCommand({
12440
+ id: "request.send",
12441
+ group: "request",
12442
+ title: "Send request",
12443
+ description: "Send a request over HTTP and return status, headers, and body. {{variables}} are filled from the active or given environment and globals. Secret variables must be set in the desktop app first.",
12444
+ params: external_exports.object({
12445
+ workspaceId: workspaceId3,
12446
+ requestId,
12447
+ environmentId: external_exports.string().min(1).nullable().optional().describe("Environment id; defaults to the active one, or null for none"),
12448
+ dryRun: external_exports.boolean().optional().describe("Return the URL the request would call, without sending it"),
12449
+ confirmUrl: external_exports.string().min(1).optional().describe("Send only if the request still goes to this URL, as shown by a dry run")
12450
+ }),
12451
+ readOnly: false,
12452
+ run: async ({ workspaceId: id, requestId: request, environmentId: environmentId2, dryRun, confirmUrl }) => {
12453
+ const { workspace } = readWorkspace(id);
12454
+ return sendRequest(findRequest(workspace.tree, request), workspace, environmentId2 ?? null, { dryRun, confirmUrl });
12455
+ }
12456
+ })
12457
+ ];
12458
+
12459
+ // src/commands/workspace.ts
12460
+ import { randomUUID as randomUUID6 } from "node:crypto";
12461
+ var workspaceId4 = external_exports.string().min(1).describe("Workspace id from workspace.list");
12462
+ var emptyVariables = () => ({ globals: [], environments: [] });
12463
+ var workspaceCommands = [
12464
+ defineCommand({
12465
+ id: "workspace.list",
12466
+ group: "workspace",
12467
+ title: "List workspaces",
12468
+ description: "List the workspaces in the desktop app. Use the returned id for every other command.",
12469
+ params: external_exports.object({}),
12470
+ readOnly: true,
12471
+ run: () => listWorkspaces()
12472
+ }),
12473
+ defineCommand({
12474
+ id: "workspace.create",
12475
+ group: "workspace",
12476
+ title: "Create local workspace",
12477
+ description: "Create an empty local workspace. Cloud workspaces are created in the desktop app.",
12478
+ params: external_exports.object({ name: external_exports.string().trim().min(1).max(160).describe("Workspace name") }),
12479
+ readOnly: false,
12480
+ run: ({ name }) => {
12481
+ const workspace = {
12482
+ id: randomUUID6(),
12483
+ cloudId: null,
12484
+ name,
12485
+ tree: [],
12486
+ baseTree: [],
12487
+ variables: emptyVariables(),
12488
+ baseVariables: emptyVariables(),
12489
+ activeEnvironmentId: null,
12490
+ baseCommitId: null,
12491
+ localHeadId: null
12492
+ };
12493
+ insertWorkspace(workspace);
12494
+ return { id: workspace.id, name: workspace.name };
12495
+ }
12496
+ }),
12497
+ defineCommand({
12498
+ id: "workspace.rename",
12499
+ group: "workspace",
12500
+ title: "Rename workspace",
12501
+ description: "Change the name of a local workspace.",
12502
+ params: external_exports.object({ workspaceId: workspaceId4, name: external_exports.string().trim().min(1).max(160) }),
12503
+ readOnly: false,
12504
+ run: ({ workspaceId: id, name }) => {
12505
+ const workspace = updateWorkspace(id, (current) => ({ ...current, name }));
12506
+ return { id, name: workspace.name };
12507
+ }
12508
+ }),
12509
+ defineCommand({
12510
+ id: "workspace.delete",
12511
+ group: "workspace",
12512
+ title: "Delete local workspace",
12513
+ description: "Delete a local workspace and its commit history. Requires confirm=true after the user confirms. Cloud workspaces are refused.",
12514
+ params: external_exports.object({ workspaceId: workspaceId4, confirm: external_exports.literal(true).describe("Must be true; ask the user first") }),
12515
+ readOnly: false,
12516
+ destructive: true,
12517
+ run: ({ workspaceId: id }) => {
12518
+ const { workspace } = readWorkspace(id);
12519
+ deleteWorkspace(id);
12520
+ return { deleted: true, id, name: workspace.name };
12521
+ }
12522
+ }),
12523
+ defineCommand({
12524
+ id: "tree.get",
12525
+ group: "workspace",
12526
+ title: "Read collection tree",
12527
+ description: "Read the folder hierarchy and request summaries of a workspace. Credentials and secret-like values are redacted.",
12528
+ params: external_exports.object({ workspaceId: workspaceId4 }),
12529
+ readOnly: true,
12530
+ run: ({ workspaceId: id }) => {
12531
+ const { workspace } = readWorkspace(id);
12532
+ return { workspaceId: id, workspaceName: workspace.name, tree: safeTree(workspace.tree) };
12533
+ }
12534
+ })
12535
+ ];
12536
+
12537
+ // src/commands/index.ts
12538
+ var listCommand = defineCommand({
12539
+ id: "commands.list",
12540
+ group: "meta",
12541
+ title: "List commands",
12542
+ description: "List every command with its parameters, so an agent can discover what the desktop app can do. Filter with a text query.",
12543
+ params: external_exports.object({ filter: external_exports.string().trim().max(200).optional().describe("Text to match in id, title, or description") }),
12544
+ readOnly: true,
12545
+ run: ({ filter }) => {
12546
+ const needle = filter?.toLocaleLowerCase();
12547
+ return allCommands.filter((command) => !needle || `${command.id} ${command.title} ${command.description}`.toLocaleLowerCase().includes(needle)).map(describeCommand);
12548
+ }
12549
+ });
12550
+ var allCommands = [
12551
+ listCommand,
12552
+ ...workspaceCommands,
12553
+ ...collectionCommands,
12554
+ ...requestCommands,
12555
+ ...environmentCommands,
12556
+ ...changeCommands
12557
+ ];
12558
+ function findCommand(id) {
12559
+ const command = allCommands.find((item) => item.id === id);
12560
+ if (!command) throw new Error(`Unknown command "${id}". Run "api-documentation-mcp commands" to list them.`);
12561
+ return command;
12562
+ }
12563
+ async function executeCommand(id, params) {
12564
+ return findCommand(id).run(params);
12565
+ }
12566
+
12567
+ // src/cli.ts
12568
+ var usage = `api-documentation-mcp: drive the API Documentation desktop app from the command line or an AI agent
12569
+
12570
+ USAGE:
12571
+ api-documentation-mcp commands [--json] [--filter TEXT] list every command and its parameters
12572
+ api-documentation-mcp call <command> [json-params] run one command, print its JSON result
12573
+ api-documentation-mcp run <script.json|-> [--json] run a JSON array or JSON lines of {"command", "params"}
12574
+ api-documentation-mcp mcp start the MCP server (stdio); also the default with no arguments
12575
+ api-documentation-mcp help
12576
+
12577
+ Commands read and write the app's local workspace database. Keep the desktop app open to see changes live.
12578
+ Destructive commands need "confirm": true, and collection writes that go through changes.preview need changes.apply.`;
12579
+ function printJson(value) {
12580
+ process.stdout.write(`${JSON.stringify(value, null, 2)}
12581
+ `);
12582
+ }
12583
+ function parseParams(text) {
12584
+ if (!text) return {};
12585
+ try {
12586
+ return JSON.parse(text);
12587
+ } catch {
12588
+ throw new Error(`Parameters must be JSON, for example '{"workspaceId":"..."}'.`);
12589
+ }
12590
+ }
12591
+ function listCommands(args2) {
12592
+ const filterAt = args2.indexOf("--filter");
12593
+ const filter = filterAt >= 0 ? args2[filterAt + 1]?.toLocaleLowerCase() : void 0;
12594
+ const commands = allCommands.map(describeCommand).filter((command) => !filter || `${command.id} ${command.title} ${command.description}`.toLocaleLowerCase().includes(filter));
12595
+ if (args2.includes("--json")) return printJson(commands);
12596
+ for (const command of commands) {
12597
+ const flags = [command.readOnly ? "read-only" : "write", command.destructive ? "destructive" : null].filter(Boolean).join(", ");
12598
+ const params = command.params.map((param) => `${param.name}${param.required ? "" : "?"}`).join(" ");
12599
+ process.stdout.write(`${command.id.padEnd(24)} ${command.title} [${flags}]
12600
+ ${params}
12601
+ `);
12602
+ }
12603
+ }
12604
+ function readScript(path) {
12605
+ const text = path === "-" ? readFileSync(0, "utf8") : readFileSync(path, "utf8");
12606
+ const trimmed = text.trim();
12607
+ if (!trimmed) return [];
12608
+ if (trimmed.startsWith("[")) return JSON.parse(trimmed);
12609
+ return trimmed.split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
12610
+ }
12611
+ async function runScript(path) {
12612
+ if (!path) throw new Error("run needs a script path, or - for stdin.");
12613
+ const steps = readScript(path);
12614
+ let failures = 0;
12615
+ for (const [index, step] of steps.entries()) {
12616
+ const { command, params } = step ?? {};
12617
+ if (typeof command !== "string") {
12618
+ failures += 1;
12619
+ process.stdout.write(`${JSON.stringify({ step: index + 1, ok: false, error: 'Each step needs a "command" string.' })}
12620
+ `);
12621
+ continue;
12622
+ }
12623
+ try {
12624
+ const result = await executeCommand(command, params ?? {});
12625
+ process.stdout.write(`${JSON.stringify({ step: index + 1, command, ok: true, result })}
12626
+ `);
12627
+ } catch (error2) {
12628
+ failures += 1;
12629
+ const message = error2 instanceof Error ? error2.message : String(error2);
12630
+ process.stdout.write(`${JSON.stringify({ step: index + 1, command, ok: false, error: message })}
12631
+ `);
12632
+ }
12633
+ }
12634
+ if (failures) process.exitCode = 1;
12635
+ }
12636
+ async function runCli(args2) {
12637
+ const [name, ...rest] = args2;
12638
+ if (name === "help" || name === "--help" || name === "-h") return void process.stdout.write(`${usage}
12639
+ `);
12640
+ if (name === "commands") return listCommands(rest);
12641
+ if (name === "call") {
12642
+ const [command, params] = rest;
12643
+ if (!command) throw new Error('call needs a command id. Run "api-documentation-mcp commands" to list them.');
12644
+ return printJson(await executeCommand(command, parseParams(params)));
12645
+ }
12646
+ if (name === "run") return runScript(rest.find((item) => !item.startsWith("--")));
12647
+ throw new Error(`Unknown subcommand "${name}".
12648
+
12649
+ ${usage}`);
12650
+ }
12651
+
12652
+ // node_modules/zod/v4/core/core.js
12653
+ var NEVER2 = Object.freeze({
12654
+ status: "aborted"
12655
+ });
12656
+ // @__NO_SIDE_EFFECTS__
12657
+ function $constructor(name, initializer3, params) {
12658
+ function init(inst, def) {
12659
+ var _a;
12660
+ Object.defineProperty(inst, "_zod", {
12661
+ value: inst._zod ?? {},
12662
+ enumerable: false
12663
+ });
12664
+ (_a = inst._zod).traits ?? (_a.traits = /* @__PURE__ */ new Set());
12665
+ inst._zod.traits.add(name);
12666
+ initializer3(inst, def);
12667
+ for (const k in _.prototype) {
12668
+ if (!(k in inst))
12669
+ Object.defineProperty(inst, k, { value: _.prototype[k].bind(inst) });
12670
+ }
12671
+ inst._zod.constr = _;
12672
+ inst._zod.def = def;
12673
+ }
12674
+ const Parent = params?.Parent ?? Object;
12675
+ class Definition extends Parent {
12676
+ }
12677
+ Object.defineProperty(Definition, "name", { value: name });
12678
+ function _(def) {
12679
+ var _a;
12680
+ const inst = params?.Parent ? new Definition() : this;
12681
+ init(inst, def);
12682
+ (_a = inst._zod).deferred ?? (_a.deferred = []);
12683
+ for (const fn of inst._zod.deferred) {
12684
+ fn();
12685
+ }
12686
+ return inst;
12687
+ }
12688
+ Object.defineProperty(_, "init", { value: init });
12689
+ Object.defineProperty(_, Symbol.hasInstance, {
12690
+ value: (inst) => {
12691
+ if (params?.Parent && inst instanceof params.Parent)
12692
+ return true;
12693
+ return inst?._zod?.traits?.has(name);
12694
+ }
12695
+ });
12696
+ Object.defineProperty(_, "name", { value: name });
12697
+ return _;
12698
+ }
12699
+ var $brand = Symbol("zod_brand");
12700
+ var $ZodAsyncError = class extends Error {
12701
+ constructor() {
12702
+ super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
12703
+ }
12704
+ };
12705
+ var globalConfig = {};
12706
+ function config(newConfig) {
12707
+ if (newConfig)
12708
+ Object.assign(globalConfig, newConfig);
12709
+ return globalConfig;
12710
+ }
12711
+
12712
+ // node_modules/zod/v4/core/util.js
12713
+ var util_exports = {};
12714
+ __export(util_exports, {
12715
+ BIGINT_FORMAT_RANGES: () => BIGINT_FORMAT_RANGES,
12716
+ Class: () => Class,
12717
+ NUMBER_FORMAT_RANGES: () => NUMBER_FORMAT_RANGES,
12718
+ aborted: () => aborted,
12719
+ allowsEval: () => allowsEval,
12720
+ assert: () => assert,
12721
+ assertEqual: () => assertEqual,
12722
+ assertIs: () => assertIs,
12723
+ assertNever: () => assertNever,
12724
+ assertNotEqual: () => assertNotEqual,
12725
+ assignProp: () => assignProp,
12726
+ cached: () => cached,
12727
+ captureStackTrace: () => captureStackTrace,
12728
+ cleanEnum: () => cleanEnum,
12729
+ cleanRegex: () => cleanRegex,
12730
+ clone: () => clone,
12731
+ createTransparentProxy: () => createTransparentProxy,
12732
+ defineLazy: () => defineLazy,
12733
+ esc: () => esc,
12734
+ escapeRegex: () => escapeRegex,
12735
+ extend: () => extend,
12736
+ finalizeIssue: () => finalizeIssue,
12737
+ floatSafeRemainder: () => floatSafeRemainder2,
12738
+ getElementAtPath: () => getElementAtPath,
12739
+ getEnumValues: () => getEnumValues,
12740
+ getLengthableOrigin: () => getLengthableOrigin,
12741
+ getParsedType: () => getParsedType2,
12742
+ getSizableOrigin: () => getSizableOrigin,
12743
+ isObject: () => isObject,
12744
+ isPlainObject: () => isPlainObject,
12745
+ issue: () => issue,
12746
+ joinValues: () => joinValues,
12747
+ jsonStringifyReplacer: () => jsonStringifyReplacer,
12748
+ merge: () => merge,
12749
+ normalizeParams: () => normalizeParams,
12750
+ nullish: () => nullish,
12751
+ numKeys: () => numKeys,
12752
+ omit: () => omit,
12753
+ optionalKeys: () => optionalKeys,
12754
+ partial: () => partial,
12755
+ pick: () => pick,
12756
+ prefixIssues: () => prefixIssues,
12757
+ primitiveTypes: () => primitiveTypes,
12758
+ promiseAllObject: () => promiseAllObject,
12759
+ propertyKeyTypes: () => propertyKeyTypes,
12760
+ randomString: () => randomString,
12761
+ required: () => required,
12762
+ stringifyPrimitive: () => stringifyPrimitive,
12763
+ unwrapMessage: () => unwrapMessage
12764
+ });
12765
+ function assertEqual(val) {
12766
+ return val;
12767
+ }
12768
+ function assertNotEqual(val) {
12769
+ return val;
12770
+ }
12771
+ function assertIs(_arg) {
12772
+ }
12773
+ function assertNever(_x) {
12774
+ throw new Error();
12775
+ }
12776
+ function assert(_) {
12777
+ }
12778
+ function getEnumValues(entries) {
12779
+ const numericValues = Object.values(entries).filter((v) => typeof v === "number");
12780
+ const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
12781
+ return values;
12782
+ }
12783
+ function joinValues(array2, separator = "|") {
12784
+ return array2.map((val) => stringifyPrimitive(val)).join(separator);
12785
+ }
12786
+ function jsonStringifyReplacer(_, value) {
12787
+ if (typeof value === "bigint")
12788
+ return value.toString();
12789
+ return value;
12790
+ }
12791
+ function cached(getter) {
12792
+ const set = false;
12793
+ return {
12794
+ get value() {
12795
+ if (!set) {
12796
+ const value = getter();
12797
+ Object.defineProperty(this, "value", { value });
12798
+ return value;
12799
+ }
12800
+ throw new Error("cached value already set");
12801
+ }
12802
+ };
12803
+ }
12804
+ function nullish(input) {
12805
+ return input === null || input === void 0;
12806
+ }
12807
+ function cleanRegex(source) {
12808
+ const start = source.startsWith("^") ? 1 : 0;
11403
12809
  const end = source.endsWith("$") ? source.length - 1 : source.length;
11404
12810
  return source.slice(start, end);
11405
12811
  }
@@ -11802,8 +13208,8 @@ function getLengthableOrigin(input) {
11802
13208
  return "string";
11803
13209
  return "unknown";
11804
13210
  }
11805
- function issue(...args) {
11806
- const [iss, input, inst] = args;
13211
+ function issue(...args2) {
13212
+ const [iss, input, inst] = args2;
11807
13213
  if (typeof iss === "string") {
11808
13214
  return {
11809
13215
  message: iss,
@@ -11980,20 +13386,20 @@ var hostname = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/;
11980
13386
  var e164 = /^\+(?:[0-9]){6,14}[0-9]$/;
11981
13387
  var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
11982
13388
  var date = /* @__PURE__ */ new RegExp(`^${dateSource}$`);
11983
- function timeSource(args) {
13389
+ function timeSource(args2) {
11984
13390
  const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`;
11985
- const regex = typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`;
13391
+ const regex = typeof args2.precision === "number" ? args2.precision === -1 ? `${hhmm}` : args2.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args2.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`;
11986
13392
  return regex;
11987
13393
  }
11988
- function time(args) {
11989
- return new RegExp(`^${timeSource(args)}$`);
13394
+ function time(args2) {
13395
+ return new RegExp(`^${timeSource(args2)}$`);
11990
13396
  }
11991
- function datetime(args) {
11992
- const time3 = timeSource({ precision: args.precision });
13397
+ function datetime(args2) {
13398
+ const time3 = timeSource({ precision: args2.precision });
11993
13399
  const opts = ["Z"];
11994
- if (args.local)
13400
+ if (args2.local)
11995
13401
  opts.push("");
11996
- if (args.offset)
13402
+ if (args2.offset)
11997
13403
  opts.push(`([+-]\\d{2}:\\d{2})`);
11998
13404
  const timeRegex2 = `${time3}(?:${opts.join("|")})`;
11999
13405
  return new RegExp(`^${dateSource}T(?:${timeRegex2})$`);
@@ -12396,11 +13802,11 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
12396
13802
 
12397
13803
  // node_modules/zod/v4/core/doc.js
12398
13804
  var Doc = class {
12399
- constructor(args = []) {
13805
+ constructor(args2 = []) {
12400
13806
  this.content = [];
12401
13807
  this.indent = 0;
12402
13808
  if (this)
12403
- this.args = args;
13809
+ this.args = args2;
12404
13810
  }
12405
13811
  indented(fn) {
12406
13812
  this.indent += 1;
@@ -12423,10 +13829,10 @@ var Doc = class {
12423
13829
  }
12424
13830
  compile() {
12425
13831
  const F = Function;
12426
- const args = this?.args;
13832
+ const args2 = this?.args;
12427
13833
  const content = this?.content ?? [``];
12428
13834
  const lines = [...content.map((x) => ` ${x}`)];
12429
- return new F(...args, lines.join("\n"));
13835
+ return new F(...args2, lines.join("\n"));
12430
13836
  }
12431
13837
  };
12432
13838
 
@@ -15391,12 +16797,12 @@ var ZodType2 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
15391
16797
  },
15392
16798
  configurable: true
15393
16799
  });
15394
- inst.meta = (...args) => {
15395
- if (args.length === 0) {
16800
+ inst.meta = (...args2) => {
16801
+ if (args2.length === 0) {
15396
16802
  return globalRegistry.get(inst);
15397
16803
  }
15398
16804
  const cl = inst.clone();
15399
- globalRegistry.add(cl, args[0]);
16805
+ globalRegistry.add(cl, args2[0]);
15400
16806
  return cl;
15401
16807
  };
15402
16808
  inst.isOptional = () => inst.safeParse(void 0).success;
@@ -15410,18 +16816,18 @@ var _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => {
15410
16816
  inst.format = bag.format ?? null;
15411
16817
  inst.minLength = bag.minimum ?? null;
15412
16818
  inst.maxLength = bag.maximum ?? null;
15413
- inst.regex = (...args) => inst.check(_regex(...args));
15414
- inst.includes = (...args) => inst.check(_includes(...args));
15415
- inst.startsWith = (...args) => inst.check(_startsWith(...args));
15416
- inst.endsWith = (...args) => inst.check(_endsWith(...args));
15417
- inst.min = (...args) => inst.check(_minLength(...args));
15418
- inst.max = (...args) => inst.check(_maxLength(...args));
15419
- inst.length = (...args) => inst.check(_length(...args));
15420
- inst.nonempty = (...args) => inst.check(_minLength(1, ...args));
16819
+ inst.regex = (...args2) => inst.check(_regex(...args2));
16820
+ inst.includes = (...args2) => inst.check(_includes(...args2));
16821
+ inst.startsWith = (...args2) => inst.check(_startsWith(...args2));
16822
+ inst.endsWith = (...args2) => inst.check(_endsWith(...args2));
16823
+ inst.min = (...args2) => inst.check(_minLength(...args2));
16824
+ inst.max = (...args2) => inst.check(_maxLength(...args2));
16825
+ inst.length = (...args2) => inst.check(_length(...args2));
16826
+ inst.nonempty = (...args2) => inst.check(_minLength(1, ...args2));
15421
16827
  inst.lowercase = (params) => inst.check(_lowercase(params));
15422
16828
  inst.uppercase = (params) => inst.check(_uppercase(params));
15423
16829
  inst.trim = () => inst.check(_trim());
15424
- inst.normalize = (...args) => inst.check(_normalize(...args));
16830
+ inst.normalize = (...args2) => inst.check(_normalize(...args2));
15425
16831
  inst.toLowerCase = () => inst.check(_toLowerCase());
15426
16832
  inst.toUpperCase = () => inst.check(_toUpperCase());
15427
16833
  });
@@ -15631,8 +17037,8 @@ var ZodObject2 = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
15631
17037
  inst.merge = (other) => util_exports.merge(inst, other);
15632
17038
  inst.pick = (mask) => util_exports.pick(inst, mask);
15633
17039
  inst.omit = (mask) => util_exports.omit(inst, mask);
15634
- inst.partial = (...args) => util_exports.partial(ZodOptional2, inst, args[0]);
15635
- inst.required = (...args) => util_exports.required(ZodNonOptional, inst, args[0]);
17040
+ inst.partial = (...args2) => util_exports.partial(ZodOptional2, inst, args2[0]);
17041
+ inst.required = (...args2) => util_exports.required(ZodNonOptional, inst, args2[0]);
15636
17042
  });
15637
17043
  function object2(shape, params) {
15638
17044
  const def = {
@@ -18577,8 +19983,8 @@ var parseReadonlyDef = (def, refs) => {
18577
19983
  };
18578
19984
 
18579
19985
  // node_modules/zod-to-json-schema/dist/esm/selectParser.js
18580
- var selectParser = (def, typeName, refs) => {
18581
- switch (typeName) {
19986
+ var selectParser = (def, typeName2, refs) => {
19987
+ switch (typeName2) {
18582
19988
  case ZodFirstPartyTypeKind.ZodString:
18583
19989
  return parseStringDef(def, refs);
18584
19990
  case ZodFirstPartyTypeKind.ZodNumber:
@@ -18648,7 +20054,7 @@ var selectParser = (def, typeName, refs) => {
18648
20054
  case ZodFirstPartyTypeKind.ZodSymbol:
18649
20055
  return void 0;
18650
20056
  default:
18651
- return /* @__PURE__ */ ((_) => void 0)(typeName);
20057
+ return /* @__PURE__ */ ((_) => void 0)(typeName2);
18652
20058
  }
18653
20059
  };
18654
20060
 
@@ -18861,10 +20267,10 @@ var Protocol = class {
18861
20267
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
18862
20268
  if (queuedMessage.type === "response" || queuedMessage.type === "error") {
18863
20269
  const message = queuedMessage.message;
18864
- const requestId = message.id;
18865
- const resolver = this._requestResolvers.get(requestId);
20270
+ const requestId2 = message.id;
20271
+ const resolver = this._requestResolvers.get(requestId2);
18866
20272
  if (resolver) {
18867
- this._requestResolvers.delete(requestId);
20273
+ this._requestResolvers.delete(requestId2);
18868
20274
  if (queuedMessage.type === "response") {
18869
20275
  resolver(message);
18870
20276
  } else {
@@ -18874,7 +20280,7 @@ var Protocol = class {
18874
20280
  }
18875
20281
  } else {
18876
20282
  const messageType = queuedMessage.type === "response" ? "Response" : "Error";
18877
- this._onerror(new Error(`${messageType} handler missing for request ${requestId}`));
20283
+ this._onerror(new Error(`${messageType} handler missing for request ${requestId2}`));
18878
20284
  }
18879
20285
  continue;
18880
20286
  }
@@ -19583,26 +20989,26 @@ var Protocol = class {
19583
20989
  *
19584
20990
  * Note that this will replace any previous request handler for the same method.
19585
20991
  */
19586
- setRequestHandler(requestSchema, handler) {
19587
- const method = getMethodLiteral(requestSchema);
19588
- this.assertRequestHandlerCapability(method);
19589
- this._requestHandlers.set(method, (request, extra) => {
19590
- const parsed = parseWithCompat(requestSchema, request);
20992
+ setRequestHandler(requestSchema2, handler) {
20993
+ const method2 = getMethodLiteral(requestSchema2);
20994
+ this.assertRequestHandlerCapability(method2);
20995
+ this._requestHandlers.set(method2, (request, extra) => {
20996
+ const parsed = parseWithCompat(requestSchema2, request);
19591
20997
  return Promise.resolve(handler(parsed, extra));
19592
20998
  });
19593
20999
  }
19594
21000
  /**
19595
21001
  * Removes the request handler for the given method.
19596
21002
  */
19597
- removeRequestHandler(method) {
19598
- this._requestHandlers.delete(method);
21003
+ removeRequestHandler(method2) {
21004
+ this._requestHandlers.delete(method2);
19599
21005
  }
19600
21006
  /**
19601
21007
  * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
19602
21008
  */
19603
- assertCanSetRequestHandler(method) {
19604
- if (this._requestHandlers.has(method)) {
19605
- throw new Error(`A request handler for ${method} already exists, which would be overridden`);
21009
+ assertCanSetRequestHandler(method2) {
21010
+ if (this._requestHandlers.has(method2)) {
21011
+ throw new Error(`A request handler for ${method2} already exists, which would be overridden`);
19606
21012
  }
19607
21013
  }
19608
21014
  /**
@@ -19611,8 +21017,8 @@ var Protocol = class {
19611
21017
  * Note that this will replace any previous notification handler for the same method.
19612
21018
  */
19613
21019
  setNotificationHandler(notificationSchema, handler) {
19614
- const method = getMethodLiteral(notificationSchema);
19615
- this._notificationHandlers.set(method, (notification) => {
21020
+ const method2 = getMethodLiteral(notificationSchema);
21021
+ this._notificationHandlers.set(method2, (notification) => {
19616
21022
  const parsed = parseWithCompat(notificationSchema, notification);
19617
21023
  return Promise.resolve(handler(parsed));
19618
21024
  });
@@ -19620,8 +21026,8 @@ var Protocol = class {
19620
21026
  /**
19621
21027
  * Removes the notification handler for the given method.
19622
21028
  */
19623
- removeNotificationHandler(method) {
19624
- this._notificationHandlers.delete(method);
21029
+ removeNotificationHandler(method2) {
21030
+ this._notificationHandlers.delete(method2);
19625
21031
  }
19626
21032
  /**
19627
21033
  * Cleans up the progress handler associated with a task.
@@ -19662,13 +21068,13 @@ var Protocol = class {
19662
21068
  const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId);
19663
21069
  for (const message of messages) {
19664
21070
  if (message.type === "request" && isJSONRPCRequest(message.message)) {
19665
- const requestId = message.message.id;
19666
- const resolver = this._requestResolvers.get(requestId);
21071
+ const requestId2 = message.message.id;
21072
+ const resolver = this._requestResolvers.get(requestId2);
19667
21073
  if (resolver) {
19668
21074
  resolver(new McpError(ErrorCode.InternalError, "Task cancelled or completed"));
19669
- this._requestResolvers.delete(requestId);
21075
+ this._requestResolvers.delete(requestId2);
19670
21076
  } else {
19671
- this._onerror(new Error(`Resolver missing for request ${requestId} during task ${taskId} cleanup`));
21077
+ this._onerror(new Error(`Resolver missing for request ${requestId2} during task ${taskId} cleanup`));
19672
21078
  }
19673
21079
  }
19674
21080
  }
@@ -20071,33 +21477,33 @@ var ExperimentalServerTasks = class {
20071
21477
  };
20072
21478
 
20073
21479
  // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
20074
- function assertToolsCallTaskCapability(requests, method, entityName) {
21480
+ function assertToolsCallTaskCapability(requests, method2, entityName) {
20075
21481
  if (!requests) {
20076
- throw new Error(`${entityName} does not support task creation (required for ${method})`);
21482
+ throw new Error(`${entityName} does not support task creation (required for ${method2})`);
20077
21483
  }
20078
- switch (method) {
21484
+ switch (method2) {
20079
21485
  case "tools/call":
20080
21486
  if (!requests.tools?.call) {
20081
- throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
21487
+ throw new Error(`${entityName} does not support task creation for tools/call (required for ${method2})`);
20082
21488
  }
20083
21489
  break;
20084
21490
  default:
20085
21491
  break;
20086
21492
  }
20087
21493
  }
20088
- function assertClientRequestTaskCapability(requests, method, entityName) {
21494
+ function assertClientRequestTaskCapability(requests, method2, entityName) {
20089
21495
  if (!requests) {
20090
- throw new Error(`${entityName} does not support task creation (required for ${method})`);
21496
+ throw new Error(`${entityName} does not support task creation (required for ${method2})`);
20091
21497
  }
20092
- switch (method) {
21498
+ switch (method2) {
20093
21499
  case "sampling/createMessage":
20094
21500
  if (!requests.sampling?.createMessage) {
20095
- throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
21501
+ throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method2})`);
20096
21502
  }
20097
21503
  break;
20098
21504
  case "elicitation/create":
20099
21505
  if (!requests.elicitation?.create) {
20100
- throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
21506
+ throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method2})`);
20101
21507
  }
20102
21508
  break;
20103
21509
  default:
@@ -20165,8 +21571,8 @@ var Server = class extends Protocol {
20165
21571
  /**
20166
21572
  * Override request handler registration to enforce server-side validation for tools/call.
20167
21573
  */
20168
- setRequestHandler(requestSchema, handler) {
20169
- const shape = getObjectShape(requestSchema);
21574
+ setRequestHandler(requestSchema2, handler) {
21575
+ const shape = getObjectShape(requestSchema2);
20170
21576
  const methodSchema = shape?.method;
20171
21577
  if (!methodSchema) {
20172
21578
  throw new Error("Schema is missing a method literal");
@@ -20175,8 +21581,8 @@ var Server = class extends Protocol {
20175
21581
  if (typeof methodValue !== "string") {
20176
21582
  throw new Error("Schema method literal must be a string");
20177
21583
  }
20178
- const method = methodValue;
20179
- if (method === "tools/call") {
21584
+ const method2 = methodValue;
21585
+ if (method2 === "tools/call") {
20180
21586
  const wrappedHandler = async (request, extra) => {
20181
21587
  const validatedRequest = safeParse2(CallToolRequestSchema, request);
20182
21588
  if (!validatedRequest.success) {
@@ -20200,57 +21606,57 @@ var Server = class extends Protocol {
20200
21606
  }
20201
21607
  return validationResult.data;
20202
21608
  };
20203
- return super.setRequestHandler(requestSchema, wrappedHandler);
21609
+ return super.setRequestHandler(requestSchema2, wrappedHandler);
20204
21610
  }
20205
- return super.setRequestHandler(requestSchema, handler);
21611
+ return super.setRequestHandler(requestSchema2, handler);
20206
21612
  }
20207
- assertCapabilityForMethod(method) {
20208
- switch (method) {
21613
+ assertCapabilityForMethod(method2) {
21614
+ switch (method2) {
20209
21615
  case "sampling/createMessage":
20210
21616
  if (!this._clientCapabilities?.sampling) {
20211
- throw new Error(`Client does not support sampling (required for ${method})`);
21617
+ throw new Error(`Client does not support sampling (required for ${method2})`);
20212
21618
  }
20213
21619
  break;
20214
21620
  case "elicitation/create":
20215
21621
  if (!this._clientCapabilities?.elicitation) {
20216
- throw new Error(`Client does not support elicitation (required for ${method})`);
21622
+ throw new Error(`Client does not support elicitation (required for ${method2})`);
20217
21623
  }
20218
21624
  break;
20219
21625
  case "roots/list":
20220
21626
  if (!this._clientCapabilities?.roots) {
20221
- throw new Error(`Client does not support listing roots (required for ${method})`);
21627
+ throw new Error(`Client does not support listing roots (required for ${method2})`);
20222
21628
  }
20223
21629
  break;
20224
21630
  case "ping":
20225
21631
  break;
20226
21632
  }
20227
21633
  }
20228
- assertNotificationCapability(method) {
20229
- switch (method) {
21634
+ assertNotificationCapability(method2) {
21635
+ switch (method2) {
20230
21636
  case "notifications/message":
20231
21637
  if (!this._capabilities.logging) {
20232
- throw new Error(`Server does not support logging (required for ${method})`);
21638
+ throw new Error(`Server does not support logging (required for ${method2})`);
20233
21639
  }
20234
21640
  break;
20235
21641
  case "notifications/resources/updated":
20236
21642
  case "notifications/resources/list_changed":
20237
21643
  if (!this._capabilities.resources) {
20238
- throw new Error(`Server does not support notifying about resources (required for ${method})`);
21644
+ throw new Error(`Server does not support notifying about resources (required for ${method2})`);
20239
21645
  }
20240
21646
  break;
20241
21647
  case "notifications/tools/list_changed":
20242
21648
  if (!this._capabilities.tools) {
20243
- throw new Error(`Server does not support notifying of tool list changes (required for ${method})`);
21649
+ throw new Error(`Server does not support notifying of tool list changes (required for ${method2})`);
20244
21650
  }
20245
21651
  break;
20246
21652
  case "notifications/prompts/list_changed":
20247
21653
  if (!this._capabilities.prompts) {
20248
- throw new Error(`Server does not support notifying of prompt list changes (required for ${method})`);
21654
+ throw new Error(`Server does not support notifying of prompt list changes (required for ${method2})`);
20249
21655
  }
20250
21656
  break;
20251
21657
  case "notifications/elicitation/complete":
20252
21658
  if (!this._clientCapabilities?.elicitation?.url) {
20253
- throw new Error(`Client does not support URL elicitation (required for ${method})`);
21659
+ throw new Error(`Client does not support URL elicitation (required for ${method2})`);
20254
21660
  }
20255
21661
  break;
20256
21662
  case "notifications/cancelled":
@@ -20259,38 +21665,38 @@ var Server = class extends Protocol {
20259
21665
  break;
20260
21666
  }
20261
21667
  }
20262
- assertRequestHandlerCapability(method) {
21668
+ assertRequestHandlerCapability(method2) {
20263
21669
  if (!this._capabilities) {
20264
21670
  return;
20265
21671
  }
20266
- switch (method) {
21672
+ switch (method2) {
20267
21673
  case "completion/complete":
20268
21674
  if (!this._capabilities.completions) {
20269
- throw new Error(`Server does not support completions (required for ${method})`);
21675
+ throw new Error(`Server does not support completions (required for ${method2})`);
20270
21676
  }
20271
21677
  break;
20272
21678
  case "logging/setLevel":
20273
21679
  if (!this._capabilities.logging) {
20274
- throw new Error(`Server does not support logging (required for ${method})`);
21680
+ throw new Error(`Server does not support logging (required for ${method2})`);
20275
21681
  }
20276
21682
  break;
20277
21683
  case "prompts/get":
20278
21684
  case "prompts/list":
20279
21685
  if (!this._capabilities.prompts) {
20280
- throw new Error(`Server does not support prompts (required for ${method})`);
21686
+ throw new Error(`Server does not support prompts (required for ${method2})`);
20281
21687
  }
20282
21688
  break;
20283
21689
  case "resources/list":
20284
21690
  case "resources/templates/list":
20285
21691
  case "resources/read":
20286
21692
  if (!this._capabilities.resources) {
20287
- throw new Error(`Server does not support resources (required for ${method})`);
21693
+ throw new Error(`Server does not support resources (required for ${method2})`);
20288
21694
  }
20289
21695
  break;
20290
21696
  case "tools/call":
20291
21697
  case "tools/list":
20292
21698
  if (!this._capabilities.tools) {
20293
- throw new Error(`Server does not support tools (required for ${method})`);
21699
+ throw new Error(`Server does not support tools (required for ${method2})`);
20294
21700
  }
20295
21701
  break;
20296
21702
  case "tasks/get":
@@ -20298,7 +21704,7 @@ var Server = class extends Protocol {
20298
21704
  case "tasks/result":
20299
21705
  case "tasks/cancel":
20300
21706
  if (!this._capabilities.tasks) {
20301
- throw new Error(`Server does not support tasks capability (required for ${method})`);
21707
+ throw new Error(`Server does not support tasks capability (required for ${method2})`);
20302
21708
  }
20303
21709
  break;
20304
21710
  case "ping":
@@ -20306,14 +21712,14 @@ var Server = class extends Protocol {
20306
21712
  break;
20307
21713
  }
20308
21714
  }
20309
- assertTaskCapability(method) {
20310
- assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
21715
+ assertTaskCapability(method2) {
21716
+ assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method2, "Client");
20311
21717
  }
20312
- assertTaskHandlerCapability(method) {
21718
+ assertTaskHandlerCapability(method2) {
20313
21719
  if (!this._capabilities) {
20314
21720
  return;
20315
21721
  }
20316
- assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method, "Server");
21722
+ assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method2, "Server");
20317
21723
  }
20318
21724
  async _oninitialize(request) {
20319
21725
  const requestedVersion = request.params.protocolVersion;
@@ -20612,6 +22018,15 @@ var McpServer = class {
20612
22018
  this._promptHandlersInitialized = false;
20613
22019
  this.server = new Server(serverInfo, options);
20614
22020
  this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
22021
+ if (options?.capabilities?.tools) {
22022
+ this.setToolRequestHandlers();
22023
+ }
22024
+ if (options?.capabilities?.resources) {
22025
+ this.setResourceRequestHandlers();
22026
+ }
22027
+ if (options?.capabilities?.prompts) {
22028
+ this.setPromptRequestHandlers();
22029
+ }
20615
22030
  }
20616
22031
  /**
20617
22032
  * Access experimental features.
@@ -20703,8 +22118,8 @@ var McpServer = class {
20703
22118
  if (taskSupport === "optional" && !isTaskRequest && isTaskHandler) {
20704
22119
  return await this.handleAutomaticTaskPolling(tool, request, extra);
20705
22120
  }
20706
- const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
20707
- const result = await this.executeToolHandler(tool, args, extra);
22121
+ const args2 = await this.validateToolInput(tool, request.params.arguments, request.params.name);
22122
+ const result = await this.executeToolHandler(tool, args2, extra);
20708
22123
  if (isTaskRequest) {
20709
22124
  return result;
20710
22125
  }
@@ -20741,27 +22156,27 @@ var McpServer = class {
20741
22156
  /**
20742
22157
  * Validates tool input arguments against the tool's input schema.
20743
22158
  */
20744
- async validateToolInput(tool, args, toolName) {
20745
- if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
20746
- throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
22159
+ async validateToolInput(tool, args2, toolName2) {
22160
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args2, this._maxToolInputElements) > this._maxToolInputElements) {
22161
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName2}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
20747
22162
  }
20748
22163
  if (!tool.inputSchema) {
20749
22164
  return void 0;
20750
22165
  }
20751
22166
  const inputObj = normalizeObjectSchema(tool.inputSchema);
20752
22167
  const schemaToParse = inputObj ?? tool.inputSchema;
20753
- const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
22168
+ const parseResult = await safeParseAsync2(schemaToParse, args2 ?? {});
20754
22169
  if (!parseResult.success) {
20755
22170
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
20756
22171
  const errorMessage = getParseErrorMessage(error2);
20757
- throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage}`);
22172
+ throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName2}: ${errorMessage}`);
20758
22173
  }
20759
22174
  return parseResult.data;
20760
22175
  }
20761
22176
  /**
20762
22177
  * Validates tool output against the tool's output schema.
20763
22178
  */
20764
- async validateToolOutput(tool, result, toolName) {
22179
+ async validateToolOutput(tool, result, toolName2) {
20765
22180
  if (!tool.outputSchema) {
20766
22181
  return;
20767
22182
  }
@@ -20772,20 +22187,20 @@ var McpServer = class {
20772
22187
  return;
20773
22188
  }
20774
22189
  if (!result.structuredContent) {
20775
- throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName} has an output schema but no structured content was provided`);
22190
+ throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName2} has an output schema but no structured content was provided`);
20776
22191
  }
20777
22192
  const outputObj = normalizeObjectSchema(tool.outputSchema);
20778
22193
  const parseResult = await safeParseAsync2(outputObj, result.structuredContent);
20779
22194
  if (!parseResult.success) {
20780
22195
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
20781
22196
  const errorMessage = getParseErrorMessage(error2);
20782
- throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage}`);
22197
+ throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName2}: ${errorMessage}`);
20783
22198
  }
20784
22199
  }
20785
22200
  /**
20786
22201
  * Executes a tool handler (either regular or task-based).
20787
22202
  */
20788
- async executeToolHandler(tool, args, extra) {
22203
+ async executeToolHandler(tool, args2, extra) {
20789
22204
  const handler = tool.handler;
20790
22205
  const isTaskHandler = "createTask" in handler;
20791
22206
  if (isTaskHandler) {
@@ -20795,7 +22210,7 @@ var McpServer = class {
20795
22210
  const taskExtra = { ...extra, taskStore: extra.taskStore };
20796
22211
  if (tool.inputSchema) {
20797
22212
  const typedHandler = handler;
20798
- return await Promise.resolve(typedHandler.createTask(args, taskExtra));
22213
+ return await Promise.resolve(typedHandler.createTask(args2, taskExtra));
20799
22214
  } else {
20800
22215
  const typedHandler = handler;
20801
22216
  return await Promise.resolve(typedHandler.createTask(taskExtra));
@@ -20803,7 +22218,7 @@ var McpServer = class {
20803
22218
  }
20804
22219
  if (tool.inputSchema) {
20805
22220
  const typedHandler = handler;
20806
- return await Promise.resolve(typedHandler(args, extra));
22221
+ return await Promise.resolve(typedHandler(args2, extra));
20807
22222
  } else {
20808
22223
  const typedHandler = handler;
20809
22224
  return await Promise.resolve(typedHandler(extra));
@@ -20816,10 +22231,10 @@ var McpServer = class {
20816
22231
  if (!extra.taskStore) {
20817
22232
  throw new Error("No task store provided for task-capable tool.");
20818
22233
  }
20819
- const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
22234
+ const args2 = await this.validateToolInput(tool, request.params.arguments, request.params.name);
20820
22235
  const handler = tool.handler;
20821
22236
  const taskExtra = { ...extra, taskStore: extra.taskStore };
20822
- const createTaskResult = args ? await Promise.resolve(handler.createTask(args, taskExtra)) : (
22237
+ const createTaskResult = args2 ? await Promise.resolve(handler.createTask(args2, taskExtra)) : (
20823
22238
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20824
22239
  await Promise.resolve(handler.createTask(taskExtra))
20825
22240
  );
@@ -20994,9 +22409,9 @@ var McpServer = class {
20994
22409
  const errorMessage = getParseErrorMessage(error2);
20995
22410
  throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request.params.name}: ${errorMessage}`);
20996
22411
  }
20997
- const args = parseResult.data;
22412
+ const args2 = parseResult.data;
20998
22413
  const cb = prompt.callback;
20999
- return await Promise.resolve(cb(args, extra));
22414
+ return await Promise.resolve(cb(args2, extra));
21000
22415
  } else {
21001
22416
  const cb = prompt.callback;
21002
22417
  return await Promise.resolve(cb(extra));
@@ -21286,654 +22701,408 @@ var McpServer = class {
21286
22701
  }
21287
22702
  /**
21288
22703
  * Sends a logging message to the client, if connected.
21289
- * Note: You only need to send the parameters object, not the entire JSON RPC message
21290
- * @see LoggingMessageNotification
21291
- * @param params
21292
- * @param sessionId optional for stateless and backward compatibility
21293
- */
21294
- async sendLoggingMessage(params, sessionId) {
21295
- return this.server.sendLoggingMessage(params, sessionId);
21296
- }
21297
- /**
21298
- * Sends a resource list changed event to the client, if connected.
21299
- */
21300
- sendResourceListChanged() {
21301
- if (this.isConnected()) {
21302
- this.server.sendResourceListChanged();
21303
- }
21304
- }
21305
- /**
21306
- * Sends a tool list changed event to the client, if connected.
21307
- */
21308
- sendToolListChanged() {
21309
- if (this.isConnected()) {
21310
- this.server.sendToolListChanged();
21311
- }
21312
- }
21313
- /**
21314
- * Sends a prompt list changed event to the client, if connected.
21315
- */
21316
- sendPromptListChanged() {
21317
- if (this.isConnected()) {
21318
- this.server.sendPromptListChanged();
21319
- }
21320
- }
21321
- };
21322
- var EMPTY_OBJECT_JSON_SCHEMA = {
21323
- type: "object",
21324
- properties: {}
21325
- };
21326
- function isZodTypeLike(value) {
21327
- return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function";
21328
- }
21329
- function isZodSchemaInstance(obj) {
21330
- return "_def" in obj || "_zod" in obj || isZodTypeLike(obj);
21331
- }
21332
- function isZodRawShapeCompat(obj) {
21333
- if (typeof obj !== "object" || obj === null) {
21334
- return false;
21335
- }
21336
- if (isZodSchemaInstance(obj)) {
21337
- return false;
21338
- }
21339
- if (Object.keys(obj).length === 0) {
21340
- return true;
21341
- }
21342
- return Object.values(obj).some(isZodTypeLike);
21343
- }
21344
- function getZodSchemaObject(schema) {
21345
- if (!schema) {
21346
- return void 0;
21347
- }
21348
- if (isZodRawShapeCompat(schema)) {
21349
- return objectFromShape(schema);
21350
- }
21351
- if (!isZodSchemaInstance(schema)) {
21352
- throw new Error("inputSchema must be a Zod schema or raw shape, received an unrecognized object");
21353
- }
21354
- return schema;
21355
- }
21356
- function promptArgumentsFromSchema(schema) {
21357
- const shape = getObjectShape(schema);
21358
- if (!shape)
21359
- return [];
21360
- return Object.entries(shape).map(([name, field]) => {
21361
- const description = getSchemaDescription(field);
21362
- const isOptional = isSchemaOptional(field);
21363
- return {
21364
- name,
21365
- description,
21366
- required: !isOptional
21367
- };
21368
- });
21369
- }
21370
- function getMethodValue(schema) {
21371
- const shape = getObjectShape(schema);
21372
- const methodSchema = shape?.method;
21373
- if (!methodSchema) {
21374
- throw new Error("Schema is missing a method literal");
21375
- }
21376
- const value = getLiteralValue(methodSchema);
21377
- if (typeof value === "string") {
21378
- return value;
21379
- }
21380
- throw new Error("Schema method literal must be a string");
21381
- }
21382
- function createCompletionResult(suggestions) {
21383
- return {
21384
- completion: {
21385
- values: suggestions.slice(0, 100),
21386
- total: suggestions.length,
21387
- hasMore: suggestions.length > 100
21388
- }
21389
- };
21390
- }
21391
- var EMPTY_COMPLETION_RESULT = {
21392
- completion: {
21393
- values: [],
21394
- hasMore: false
21395
- }
21396
- };
21397
-
21398
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
21399
- import process2 from "node:process";
21400
-
21401
- // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
21402
- var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
21403
- var ReadBuffer = class {
21404
- constructor(options) {
21405
- this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
21406
- }
21407
- append(chunk) {
21408
- const newSize = (this._buffer?.length ?? 0) + chunk.length;
21409
- if (newSize > this._maxBufferSize) {
21410
- this.clear();
21411
- throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
21412
- }
21413
- this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
21414
- }
21415
- readMessage() {
21416
- if (!this._buffer) {
21417
- return null;
21418
- }
21419
- const index = this._buffer.indexOf("\n");
21420
- if (index === -1) {
21421
- return null;
21422
- }
21423
- const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
21424
- this._buffer = this._buffer.subarray(index + 1);
21425
- return deserializeMessage(line);
21426
- }
21427
- clear() {
21428
- this._buffer = void 0;
21429
- }
21430
- };
21431
- function deserializeMessage(line) {
21432
- return JSONRPCMessageSchema.parse(JSON.parse(line));
21433
- }
21434
- function serializeMessage(message) {
21435
- return JSON.stringify(message) + "\n";
21436
- }
21437
-
21438
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
21439
- var StdioServerTransport = class {
21440
- constructor(_stdin = process2.stdin, _stdout = process2.stdout, options) {
21441
- this._stdin = _stdin;
21442
- this._stdout = _stdout;
21443
- this._started = false;
21444
- this._ondata = (chunk) => {
21445
- try {
21446
- this._readBuffer.append(chunk);
21447
- this.processReadBuffer();
21448
- } catch (error2) {
21449
- this.onerror?.(error2);
21450
- this.close().catch(() => {
21451
- });
21452
- }
21453
- };
21454
- this._onerror = (error2) => {
21455
- this.onerror?.(error2);
21456
- };
21457
- this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
22704
+ * Note: You only need to send the parameters object, not the entire JSON RPC message
22705
+ * @see LoggingMessageNotification
22706
+ * @param params
22707
+ * @param sessionId optional for stateless and backward compatibility
22708
+ */
22709
+ async sendLoggingMessage(params, sessionId) {
22710
+ return this.server.sendLoggingMessage(params, sessionId);
21458
22711
  }
21459
22712
  /**
21460
- * Starts listening for messages on stdin.
22713
+ * Sends a resource list changed event to the client, if connected.
21461
22714
  */
21462
- async start() {
21463
- if (this._started) {
21464
- throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
22715
+ sendResourceListChanged() {
22716
+ if (this.isConnected()) {
22717
+ this.server.sendResourceListChanged();
21465
22718
  }
21466
- this._started = true;
21467
- this._stdin.on("data", this._ondata);
21468
- this._stdin.on("error", this._onerror);
21469
22719
  }
21470
- processReadBuffer() {
21471
- while (true) {
21472
- try {
21473
- const message = this._readBuffer.readMessage();
21474
- if (message === null) {
21475
- break;
21476
- }
21477
- this.onmessage?.(message);
21478
- } catch (error2) {
21479
- this.onerror?.(error2);
21480
- }
22720
+ /**
22721
+ * Sends a tool list changed event to the client, if connected.
22722
+ */
22723
+ sendToolListChanged() {
22724
+ if (this.isConnected()) {
22725
+ this.server.sendToolListChanged();
21481
22726
  }
21482
22727
  }
21483
- async close() {
21484
- this._stdin.off("data", this._ondata);
21485
- this._stdin.off("error", this._onerror);
21486
- const remainingDataListeners = this._stdin.listenerCount("data");
21487
- if (remainingDataListeners === 0) {
21488
- this._stdin.pause();
22728
+ /**
22729
+ * Sends a prompt list changed event to the client, if connected.
22730
+ */
22731
+ sendPromptListChanged() {
22732
+ if (this.isConnected()) {
22733
+ this.server.sendPromptListChanged();
21489
22734
  }
21490
- this._readBuffer.clear();
21491
- this.onclose?.();
21492
- }
21493
- send(message) {
21494
- return new Promise((resolve) => {
21495
- const json = serializeMessage(message);
21496
- if (this._stdout.write(json)) {
21497
- resolve();
21498
- } else {
21499
- this._stdout.once("drain", resolve);
21500
- }
21501
- });
21502
22735
  }
21503
22736
  };
21504
-
21505
- // src/mcp/server.ts
21506
- var appName = "api-documentation-bit";
21507
- var defaultAppData = process.platform === "win32" ? process.env.APPDATA || join(homedir(), "AppData", "Roaming") : process.platform === "darwin" ? join(homedir(), "Library", "Application Support") : process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
21508
- var dataDirectory = process.env.API_DOCS_USER_DATA_DIR || join(defaultAppData, appName);
21509
- var databasePath = join(dataDirectory, "workspace.sqlite");
21510
- var plans = /* @__PURE__ */ new Map();
21511
- var localDatabase;
21512
- var bodyModes = ["form-data", "urlencoded", "graphql", "json", "xml", "yaml", "edn", "text", "other", "file", "none"];
21513
- var authSchema = external_exports.discriminatedUnion("type", [
21514
- external_exports.object({ type: external_exports.literal("none") }),
21515
- external_exports.object({ type: external_exports.literal("bearer"), token: external_exports.string().max(65536) }),
21516
- external_exports.object({ type: external_exports.literal("basic"), username: external_exports.string().max(8192), password: external_exports.string().max(65536) }),
21517
- external_exports.object({ type: external_exports.literal("api-key"), name: external_exports.string().max(8192), value: external_exports.string().max(65536), location: external_exports.enum(["header", "query"]) })
21518
- ]);
21519
- var fieldSchema = external_exports.object({
21520
- id: external_exports.string().optional(),
21521
- name: external_exports.string().max(8192),
21522
- value: external_exports.string().max(65536),
21523
- enabled: external_exports.boolean().default(true),
21524
- description: external_exports.string().max(4096).optional()
21525
- });
21526
- var bodyFieldSchema = external_exports.object({
21527
- id: external_exports.string().optional(),
21528
- name: external_exports.string().max(8192),
21529
- value: external_exports.string().max(65536),
21530
- enabled: external_exports.boolean().default(true),
21531
- type: external_exports.enum(["text", "file"]).default("text"),
21532
- fileName: external_exports.string().max(1024).optional()
21533
- });
21534
- var responseContentSchema = external_exports.object({
21535
- id: external_exports.string().optional(),
21536
- mediaType: external_exports.string().max(160),
21537
- schema: external_exports.string().max(1e6),
21538
- example: external_exports.string().max(1e6)
21539
- });
21540
- var responseDefinitionSchema = external_exports.object({
21541
- id: external_exports.string().optional(),
21542
- statusCode: external_exports.string().trim().min(1).max(12),
21543
- description: external_exports.string().max(500),
21544
- content: external_exports.array(responseContentSchema).max(20)
21545
- });
21546
- var requestShape = {
21547
- name: external_exports.string().trim().min(1).max(160),
21548
- method: external_exports.string().trim().min(1).max(32),
21549
- url: external_exports.string().max(8192),
21550
- body: external_exports.string().max(1e6).optional(),
21551
- bodyMode: external_exports.enum(bodyModes).optional(),
21552
- bodyFields: external_exports.array(bodyFieldSchema).max(100).optional(),
21553
- bodyVariables: external_exports.string().max(1e6).optional(),
21554
- bodyMimeType: external_exports.string().max(1024).optional(),
21555
- bodyFileName: external_exports.string().max(1024).optional(),
21556
- headers: external_exports.array(fieldSchema).max(100).optional(),
21557
- params: external_exports.array(fieldSchema).max(100).optional(),
21558
- pathParams: external_exports.array(fieldSchema).max(100).optional(),
21559
- auth: authSchema.optional(),
21560
- documentation: external_exports.string().max(1e5).optional(),
21561
- responses: external_exports.array(responseDefinitionSchema).max(100).optional(),
21562
- deprecated: external_exports.boolean().optional(),
21563
- deprecationReason: external_exports.string().max(4096).optional()
22737
+ var EMPTY_OBJECT_JSON_SCHEMA = {
22738
+ type: "object",
22739
+ properties: {}
21564
22740
  };
21565
- var operationSchema = external_exports.discriminatedUnion("action", [
21566
- external_exports.object({ action: external_exports.literal("create_folder"), parentId: external_exports.string().nullable().default(null), name: external_exports.string().trim().min(1).max(160) }),
21567
- external_exports.object({ action: external_exports.literal("create_request"), parentId: external_exports.string().nullable().default(null), request: external_exports.object(requestShape).extend({ method: requestShape.method.transform((method) => method.toUpperCase()) }) }),
21568
- external_exports.object({ action: external_exports.literal("update_request"), requestId: external_exports.string().min(1), patch: external_exports.object({
21569
- ...requestShape,
21570
- name: requestShape.name.optional(),
21571
- method: requestShape.method.transform((method) => method.toUpperCase()).optional(),
21572
- url: requestShape.url.optional()
21573
- }).partial() }),
21574
- external_exports.object({ action: external_exports.literal("rename_folder"), folderId: external_exports.string().min(1), name: external_exports.string().trim().min(1).max(160) }),
21575
- external_exports.object({ action: external_exports.literal("move_node"), nodeId: external_exports.string().min(1), parentId: external_exports.string().nullable().default(null), index: external_exports.number().int().min(0).optional() }),
21576
- external_exports.object({ action: external_exports.literal("deprecate_request"), requestId: external_exports.string().min(1), deprecated: external_exports.boolean().default(true), reason: external_exports.string().max(4096).optional() }),
21577
- external_exports.object({ action: external_exports.literal("delete_node"), nodeId: external_exports.string().min(1) })
21578
- ]);
21579
- function database() {
21580
- if (!existsSync(databasePath)) {
21581
- throw new Error(`Workspace database was not found at ${databasePath}. Open API Documentation once to create the local workspace.`);
21582
- }
21583
- if (!localDatabase) {
21584
- localDatabase = new DatabaseSync(databasePath);
21585
- localDatabase.exec("PRAGMA busy_timeout = 5000;");
21586
- }
21587
- return localDatabase;
21588
- }
21589
- function jsonResult(value) {
21590
- return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
21591
- }
21592
- function loadRawWorkspace(workspaceId) {
21593
- const row = database().prepare("SELECT data FROM workspaces WHERE id = ?").get(workspaceId);
21594
- if (!row) throw new Error(`Workspace "${workspaceId}" was not found.`);
21595
- const workspace = JSON.parse(row.data);
21596
- if (!Array.isArray(workspace.tree)) throw new Error("Workspace collection data is invalid.");
21597
- return { raw: row.data, workspace };
21598
- }
21599
- function assertCanEdit(workspace) {
21600
- if (workspace.role === "viewer") throw new Error("This workspace is read-only for the current account.");
22741
+ function isZodTypeLike(value) {
22742
+ return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function";
21601
22743
  }
21602
- function isFolder(node) {
21603
- return node.kind === "folder";
22744
+ function isZodSchemaInstance(obj) {
22745
+ return "_def" in obj || "_zod" in obj || isZodTypeLike(obj);
21604
22746
  }
21605
- function findNode(nodes, id) {
21606
- for (const node of nodes) {
21607
- if (node.id === id) return node;
21608
- if (isFolder(node)) {
21609
- const nested = findNode(node.children, id);
21610
- if (nested) return nested;
21611
- }
22747
+ function isZodRawShapeCompat(obj) {
22748
+ if (typeof obj !== "object" || obj === null) {
22749
+ return false;
21612
22750
  }
21613
- return void 0;
21614
- }
21615
- function findParentId(nodes, id, parentId = null) {
21616
- for (const node of nodes) {
21617
- if (node.id === id) return parentId;
21618
- if (isFolder(node)) {
21619
- const nested = findParentId(node.children, id, node.id);
21620
- if (nested !== void 0) return nested;
21621
- }
22751
+ if (isZodSchemaInstance(obj)) {
22752
+ return false;
21622
22753
  }
21623
- return void 0;
21624
- }
21625
- function insertNode(nodes, parentId, node, index) {
21626
- if (parentId === null) {
21627
- const next = [...nodes];
21628
- next.splice(index === void 0 ? next.length : Math.min(index, next.length), 0, node);
21629
- return next;
22754
+ if (Object.keys(obj).length === 0) {
22755
+ return true;
21630
22756
  }
21631
- const insertInto = (siblings) => {
21632
- for (let position = 0; position < siblings.length; position += 1) {
21633
- const child = siblings[position];
21634
- if (!isFolder(child)) continue;
21635
- if (child.id === parentId) {
21636
- const children = [...child.children];
21637
- children.splice(index === void 0 ? children.length : Math.min(index, children.length), 0, node);
21638
- const next = [...siblings];
21639
- next[position] = { ...child, children };
21640
- return { nodes: next, found: true };
21641
- }
21642
- const nested = insertInto(child.children);
21643
- if (nested.found) {
21644
- const next = [...siblings];
21645
- next[position] = { ...child, children: nested.nodes };
21646
- return { nodes: next, found: true };
21647
- }
21648
- }
21649
- return { nodes: siblings, found: false };
21650
- };
21651
- const result = insertInto(nodes);
21652
- if (!result.found) throw new Error(`Parent folder "${parentId}" was not found.`);
21653
- return result.nodes;
22757
+ return Object.values(obj).some(isZodTypeLike);
21654
22758
  }
21655
- function removeNode(nodes, id) {
21656
- const directIndex = nodes.findIndex((node) => node.id === id);
21657
- if (directIndex >= 0) {
21658
- const next = [...nodes];
21659
- const [removed] = next.splice(directIndex, 1);
21660
- return { tree: next, removed };
22759
+ function getZodSchemaObject(schema) {
22760
+ if (!schema) {
22761
+ return void 0;
21661
22762
  }
21662
- for (let index = 0; index < nodes.length; index += 1) {
21663
- const node = nodes[index];
21664
- if (!isFolder(node)) continue;
21665
- const result = removeNode(node.children, id);
21666
- if (!result.removed) continue;
21667
- const next = [...nodes];
21668
- next[index] = { ...node, children: result.tree };
21669
- return { tree: next, removed: result.removed };
22763
+ if (isZodRawShapeCompat(schema)) {
22764
+ return objectFromShape(schema);
21670
22765
  }
21671
- return { tree: nodes };
21672
- }
21673
- function updateNode(nodes, id, update) {
21674
- let found = false;
21675
- const tree = nodes.map((node) => {
21676
- if (node.id === id) {
21677
- found = true;
21678
- return update(node);
21679
- }
21680
- if (!isFolder(node)) return node;
21681
- const nested = updateNode(node.children, id, update);
21682
- if (!nested.found) return node;
21683
- found = true;
21684
- return { ...node, children: nested.tree };
21685
- });
21686
- return { tree, found };
21687
- }
21688
- function sanitizeUrl(value) {
21689
- try {
21690
- const url = new URL(value);
21691
- if (url.username) url.username = "<redacted>";
21692
- if (url.password) url.password = "<redacted>";
21693
- for (const key of [...url.searchParams.keys()]) {
21694
- if (isSensitiveName(key)) url.searchParams.set(key, "<redacted>");
21695
- }
21696
- return url.toString();
21697
- } catch {
21698
- return value;
22766
+ if (!isZodSchemaInstance(schema)) {
22767
+ throw new Error("inputSchema must be a Zod schema or raw shape, received an unrecognized object");
21699
22768
  }
22769
+ return schema;
21700
22770
  }
21701
- function isSensitiveName(value) {
21702
- return /authorization|cookie|token|secret|password|\bkey\b|api[-_]?key|client[-_]?secret/i.test(value);
21703
- }
21704
- function redactBody(value) {
21705
- try {
21706
- const parsed = JSON.parse(value);
21707
- const redact = (item) => {
21708
- if (Array.isArray(item)) return item.map(redact);
21709
- if (!item || typeof item !== "object") return item;
21710
- return Object.fromEntries(Object.entries(item).map(([key, entry]) => [key, isSensitiveName(key) ? "<redacted>" : redact(entry)]));
22771
+ function promptArgumentsFromSchema(schema) {
22772
+ const shape = getObjectShape(schema);
22773
+ if (!shape)
22774
+ return [];
22775
+ return Object.entries(shape).map(([name, field]) => {
22776
+ const description = getSchemaDescription(field);
22777
+ const isOptional = isSchemaOptional(field);
22778
+ return {
22779
+ name,
22780
+ description,
22781
+ required: !isOptional
21711
22782
  };
21712
- return JSON.stringify(redact(parsed), null, 2);
21713
- } catch {
21714
- return value.replace(/\b(authorization|cookie|token|secret|password|api[-_]?key|client[-_]?secret|key)\b\s*[:=]\s*(?:Bearer\s+)?(?:"[^"]*"|'[^']*'|[^,\r\n;}]+)/gi, "$1: <redacted>");
22783
+ });
22784
+ }
22785
+ function getMethodValue(schema) {
22786
+ const shape = getObjectShape(schema);
22787
+ const methodSchema = shape?.method;
22788
+ if (!methodSchema) {
22789
+ throw new Error("Schema is missing a method literal");
22790
+ }
22791
+ const value = getLiteralValue(methodSchema);
22792
+ if (typeof value === "string") {
22793
+ return value;
21715
22794
  }
22795
+ throw new Error("Schema method literal must be a string");
21716
22796
  }
21717
- function safeRequest(request) {
22797
+ function createCompletionResult(suggestions) {
21718
22798
  return {
21719
- ...request,
21720
- url: sanitizeUrl(request.url),
21721
- body: redactBody(request.body),
21722
- ...request.documentation ? { documentation: redactBody(request.documentation) } : {},
21723
- ...request.responses ? { responses: request.responses.map((response) => ({ ...response, content: response.content.map((content) => ({ ...content, example: redactBody(content.example) })) })) } : {},
21724
- ...request.openApiSchemas ? { openApiSchemas: JSON.parse(redactBody(JSON.stringify(request.openApiSchemas))) } : {},
21725
- ...request.headers ? { headers: request.headers.map((header) => ({ ...header, value: isSensitiveName(header.name) ? "<redacted>" : header.value })) } : {},
21726
- ...request.params ? { params: request.params.map((param) => ({ ...param, value: isSensitiveName(param.name) ? "<redacted>" : param.value })) } : {},
21727
- ...request.pathParams ? { pathParams: request.pathParams.map((param) => ({ ...param, value: isSensitiveName(param.name) ? "<redacted>" : param.value })) } : {},
21728
- ...request.bodyFields ? { bodyFields: request.bodyFields.map((field) => ({ ...field, value: isSensitiveName(field.name) ? "<redacted>" : field.value, filePath: void 0 })) } : {},
21729
- ...request.auth?.type === "bearer" ? { auth: { type: "bearer", token: "<redacted>" } } : {},
21730
- ...request.auth?.type === "basic" ? { auth: { type: "basic", username: "<redacted>", password: "<redacted>" } } : {},
21731
- ...request.auth?.type === "api-key" ? { auth: { ...request.auth, value: "<redacted>" } } : {},
21732
- bodyPath: void 0
22799
+ completion: {
22800
+ values: suggestions.slice(0, 100),
22801
+ total: suggestions.length,
22802
+ hasMore: suggestions.length > 100
22803
+ }
21733
22804
  };
21734
22805
  }
21735
- function safeTree(nodes) {
21736
- return nodes.map((node) => isFolder(node) ? { id: node.id, kind: node.kind, name: node.name, children: safeTree(node.children) } : { id: node.id, kind: node.kind, name: node.name, method: node.method, url: sanitizeUrl(node.url), deprecated: node.deprecated === true });
21737
- }
21738
- function summarize(node) {
21739
- if (!node) return void 0;
21740
- return isFolder(node) ? { id: node.id, kind: node.kind, name: node.name, childCount: node.children.length } : safeRequest(node);
22806
+ var EMPTY_COMPLETION_RESULT = {
22807
+ completion: {
22808
+ values: [],
22809
+ hasMore: false
22810
+ }
22811
+ };
22812
+
22813
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
22814
+ import process2 from "node:process";
22815
+
22816
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
22817
+ var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
22818
+ var ReadBuffer = class {
22819
+ constructor(options) {
22820
+ this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
22821
+ }
22822
+ append(chunk) {
22823
+ const newSize = (this._buffer?.length ?? 0) + chunk.length;
22824
+ if (newSize > this._maxBufferSize) {
22825
+ this.clear();
22826
+ throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
22827
+ }
22828
+ this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
22829
+ }
22830
+ readMessage() {
22831
+ if (!this._buffer) {
22832
+ return null;
22833
+ }
22834
+ const index = this._buffer.indexOf("\n");
22835
+ if (index === -1) {
22836
+ return null;
22837
+ }
22838
+ const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
22839
+ this._buffer = this._buffer.subarray(index + 1);
22840
+ return deserializeMessage(line);
22841
+ }
22842
+ clear() {
22843
+ this._buffer = void 0;
22844
+ }
22845
+ };
22846
+ function deserializeMessage(line) {
22847
+ return JSONRPCMessageSchema.parse(JSON.parse(line));
21741
22848
  }
21742
- function normalizeRequest(input, existing) {
21743
- const headers = input.headers ?? existing?.headers ?? [];
21744
- const params = input.params ?? existing?.params ?? [];
21745
- const pathParams = input.pathParams ?? existing?.pathParams ?? [];
21746
- const bodyFields = input.bodyFields ?? existing?.bodyFields ?? [];
21747
- const responses = input.responses ?? existing?.responses ?? [];
21748
- return {
21749
- ...existing,
21750
- ...input,
21751
- id: existing?.id ?? input.id ?? randomUUID(),
21752
- kind: "request",
21753
- name: input.name,
21754
- method: input.method.toUpperCase(),
21755
- url: input.url,
21756
- body: input.body ?? existing?.body ?? "",
21757
- headers: headers.map((item) => ({ ...item, id: item.id || randomUUID() })),
21758
- params: params.map((item) => ({ ...item, id: item.id || randomUUID() })),
21759
- pathParams: pathParams.map((item) => ({ ...item, id: item.id || randomUUID() })),
21760
- bodyFields: bodyFields.map((item) => ({ ...item, id: item.id || randomUUID() })),
21761
- responses: responses.map((response) => ({ ...response, id: response.id || randomUUID(), content: response.content.map((content) => ({ ...content, id: content.id || randomUUID() })) }))
21762
- };
22849
+ function serializeMessage(message) {
22850
+ return JSON.stringify(message) + "\n";
21763
22851
  }
21764
- function collectSummary(tree, operation) {
21765
- if (operation.action === "create_folder") {
21766
- const parent = operation.parentId ? findNode(tree, operation.parentId) : void 0;
21767
- if (operation.parentId && (!parent || !isFolder(parent))) throw new Error(`Parent folder "${operation.parentId}" was not found.`);
21768
- const folder = { id: randomUUID(), kind: "folder", name: operation.name.trim(), children: [] };
21769
- return { tree: insertNode(tree, operation.parentId, folder), summary: { action: operation.action, target: folder.name, after: summarize(folder) } };
21770
- }
21771
- if (operation.action === "create_request") {
21772
- const parent = operation.parentId ? findNode(tree, operation.parentId) : void 0;
21773
- if (operation.parentId && (!parent || !isFolder(parent))) throw new Error(`Parent folder "${operation.parentId}" was not found.`);
21774
- const request = normalizeRequest(operation.request);
21775
- return { tree: insertNode(tree, operation.parentId, request), summary: { action: operation.action, target: request.name, after: summarize(request) } };
22852
+
22853
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
22854
+ var StdioServerTransport = class {
22855
+ constructor(_stdin = process2.stdin, _stdout = process2.stdout, options) {
22856
+ this._stdin = _stdin;
22857
+ this._stdout = _stdout;
22858
+ this._started = false;
22859
+ this._ondata = (chunk) => {
22860
+ try {
22861
+ this._readBuffer.append(chunk);
22862
+ this.processReadBuffer();
22863
+ } catch (error2) {
22864
+ this.onerror?.(error2);
22865
+ this.close().catch(() => {
22866
+ });
22867
+ }
22868
+ };
22869
+ this._onerror = (error2) => {
22870
+ this.onerror?.(error2);
22871
+ };
22872
+ this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
21776
22873
  }
21777
- if (operation.action === "update_request") {
21778
- const before2 = findNode(tree, operation.requestId);
21779
- if (!before2 || isFolder(before2)) throw new Error(`Request "${operation.requestId}" was not found.`);
21780
- const updated = normalizeRequest({ ...before2, ...operation.patch, name: operation.patch.name ?? before2.name, method: operation.patch.method ?? before2.method, url: operation.patch.url ?? before2.url }, before2);
21781
- const result = updateNode(tree, operation.requestId, () => updated);
21782
- return { tree: result.tree, summary: { action: operation.action, target: updated.name, before: summarize(before2), after: summarize(updated) } };
22874
+ /**
22875
+ * Starts listening for messages on stdin.
22876
+ */
22877
+ async start() {
22878
+ if (this._started) {
22879
+ throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
22880
+ }
22881
+ this._started = true;
22882
+ this._stdin.on("data", this._ondata);
22883
+ this._stdin.on("error", this._onerror);
21783
22884
  }
21784
- if (operation.action === "rename_folder") {
21785
- const before2 = findNode(tree, operation.folderId);
21786
- if (!before2 || !isFolder(before2)) throw new Error(`Folder "${operation.folderId}" was not found.`);
21787
- const result = updateNode(tree, operation.folderId, (node) => isFolder(node) ? { ...node, name: operation.name.trim() } : node);
21788
- return { tree: result.tree, summary: { action: operation.action, target: operation.name.trim(), before: summarize(before2), after: { ...summarize(before2), name: operation.name.trim() } } };
22885
+ processReadBuffer() {
22886
+ while (true) {
22887
+ try {
22888
+ const message = this._readBuffer.readMessage();
22889
+ if (message === null) {
22890
+ break;
22891
+ }
22892
+ this.onmessage?.(message);
22893
+ } catch (error2) {
22894
+ this.onerror?.(error2);
22895
+ }
22896
+ }
21789
22897
  }
21790
- if (operation.action === "move_node") {
21791
- const before2 = findNode(tree, operation.nodeId);
21792
- if (!before2) throw new Error(`Collection item "${operation.nodeId}" was not found.`);
21793
- const parent = operation.parentId ? findNode(tree, operation.parentId) : void 0;
21794
- if (operation.parentId && (!parent || !isFolder(parent))) throw new Error(`Parent folder "${operation.parentId}" was not found.`);
21795
- if (isFolder(before2) && (before2.id === operation.parentId || findNode(before2.children, operation.parentId ?? "")?.kind === "folder")) throw new Error("A folder cannot be moved inside itself or one of its descendants.");
21796
- const oldParentId = findParentId(tree, before2.id);
21797
- const removed2 = removeNode(tree, before2.id);
21798
- if (!removed2.removed) throw new Error(`Collection item "${operation.nodeId}" could not be moved.`);
21799
- const next = insertNode(removed2.tree, operation.parentId, removed2.removed, operation.index);
21800
- return { tree: next, summary: { action: operation.action, target: before2.name, before: { parentId: oldParentId }, after: { parentId: operation.parentId, index: operation.index } } };
22898
+ async close() {
22899
+ this._stdin.off("data", this._ondata);
22900
+ this._stdin.off("error", this._onerror);
22901
+ const remainingDataListeners = this._stdin.listenerCount("data");
22902
+ if (remainingDataListeners === 0) {
22903
+ this._stdin.pause();
22904
+ }
22905
+ this._readBuffer.clear();
22906
+ this.onclose?.();
21801
22907
  }
21802
- if (operation.action === "deprecate_request") {
21803
- const before2 = findNode(tree, operation.requestId);
21804
- if (!before2 || isFolder(before2)) throw new Error(`Request "${operation.requestId}" was not found.`);
21805
- const updated = { ...before2, deprecated: operation.deprecated, ...operation.deprecated && operation.reason?.trim() ? { deprecationReason: operation.reason.trim() } : {}, ...!operation.deprecated ? { deprecationReason: void 0 } : {} };
21806
- const result = updateNode(tree, operation.requestId, () => updated);
21807
- return { tree: result.tree, summary: { action: operation.action, target: updated.name, before: { deprecated: before2.deprecated === true, deprecationReason: before2.deprecationReason }, after: { deprecated: updated.deprecated, deprecationReason: updated.deprecationReason } } };
22908
+ send(message) {
22909
+ return new Promise((resolve) => {
22910
+ const json = serializeMessage(message);
22911
+ if (this._stdout.write(json)) {
22912
+ resolve();
22913
+ } else {
22914
+ this._stdout.once("drain", resolve);
22915
+ }
22916
+ });
21808
22917
  }
21809
- const before = findNode(tree, operation.nodeId);
21810
- if (!before) throw new Error(`Collection item "${operation.nodeId}" was not found.`);
21811
- const removed = removeNode(tree, operation.nodeId);
21812
- return { tree: removed.tree, summary: { action: operation.action, target: before.name, before: summarize(before) } };
22918
+ };
22919
+
22920
+ // src/mcp-surface.ts
22921
+ var directCollectionWrites = /* @__PURE__ */ new Set([
22922
+ "folder.create",
22923
+ "folder.rename",
22924
+ "folder.delete",
22925
+ "node.move",
22926
+ "request.create",
22927
+ "request.update",
22928
+ "request.duplicate",
22929
+ "request.deprecate",
22930
+ "request.delete"
22931
+ ]);
22932
+ function mcpCommands() {
22933
+ return allCommands.filter((command) => !directCollectionWrites.has(command.id));
21813
22934
  }
21814
- function requestMap(nodes) {
21815
- return nodes.flatMap((node) => isFolder(node) ? requestMap(node.children) : [node]);
22935
+ function missingVariableRevision(commandId, params) {
22936
+ if (commandId !== "variable.set" && commandId !== "variable.delete") return null;
22937
+ if (params.expectedRevision !== void 0) return null;
22938
+ return "Read the variable with variable.get first, then pass its revision as expectedRevision. Pass null when the variable does not exist yet.";
21816
22939
  }
21817
- function findWorkspaceIds() {
21818
- const rows = database().prepare("SELECT data FROM workspaces ORDER BY rowid").all();
21819
- return rows.map(({ data }) => {
21820
- const workspace = JSON.parse(data);
21821
- return { id: workspace.id, name: workspace.name, cloudId: workspace.cloudId, role: workspace.role ?? null };
21822
- });
22940
+ function missingTargetConfirmation(commandId, params) {
22941
+ if (commandId !== "request.send") return null;
22942
+ if (params.dryRun === true || typeof params.confirmUrl === "string") return null;
22943
+ return "Run request.send with dryRun set to true first, show the URL to the user, then send with confirmUrl set to that URL.";
21823
22944
  }
21824
- function registerTools(server) {
21825
- server.registerTool("list_workspaces", {
21826
- title: "List workspaces",
21827
- description: "List local workspaces available in the desktop app. Use the returned workspace id for other tools.",
21828
- annotations: { readOnlyHint: true, openWorldHint: false }
21829
- }, async () => jsonResult(findWorkspaceIds()));
21830
- server.registerTool("get_collection_tree", {
21831
- title: "Read collection tree",
21832
- description: "Read folder hierarchy and request summaries for a workspace. Request names, methods, URLs, and deprecated status are included; credentials and environment values are not.",
21833
- inputSchema: { workspaceId: external_exports.string().min(1) },
21834
- annotations: { readOnlyHint: true, openWorldHint: false }
21835
- }, async ({ workspaceId }) => {
21836
- const { workspace } = loadRawWorkspace(workspaceId);
21837
- return jsonResult({ workspaceId, workspaceName: workspace.name, tree: safeTree(workspace.tree) });
21838
- });
21839
- server.registerTool("search_requests", {
21840
- title: "Search requests",
21841
- description: "Search request names, methods, and URLs in a workspace. Sensitive URL query values are masked.",
21842
- inputSchema: { workspaceId: external_exports.string().min(1), query: external_exports.string().trim().min(1).max(200) },
21843
- annotations: { readOnlyHint: true, openWorldHint: false }
21844
- }, async ({ workspaceId, query }) => {
21845
- const { workspace } = loadRawWorkspace(workspaceId);
21846
- const needle = query.toLocaleLowerCase();
21847
- const matches = requestMap(workspace.tree).filter((request) => `${request.name}
21848
- ${request.method}
21849
- ${request.url}
21850
- ${request.documentation ?? ""}
21851
- ${(request.responses ?? []).map((response) => `${response.statusCode} ${response.description} ${response.content.map((content) => `${content.schema} ${content.example}`).join(" ")}`).join("\n")}`.toLocaleLowerCase().includes(needle));
21852
- return jsonResult(matches.map((request) => safeRequest(request)));
21853
- });
21854
- server.registerTool("get_request", {
21855
- title: "Read request",
21856
- description: "Read one request definition. Auth credentials, secret-like header/parameter/body values, and local file paths are redacted.",
21857
- inputSchema: { workspaceId: external_exports.string().min(1), requestId: external_exports.string().min(1) },
21858
- annotations: { readOnlyHint: true, openWorldHint: false }
21859
- }, async ({ workspaceId, requestId }) => {
21860
- const { workspace } = loadRawWorkspace(workspaceId);
21861
- const request = findNode(workspace.tree, requestId);
21862
- if (!request || isFolder(request)) throw new Error(`Request "${requestId}" was not found.`);
21863
- return jsonResult(safeRequest(request));
21864
- });
21865
- server.registerTool("preview_changes", {
21866
- title: "Preview collection changes",
21867
- description: "Validate a proposed batch and return sanitized before/after request data. The agent must render a readable diff in chat, including workspace and collection paths, changed request fields, and nested deletion impact, then wait for explicit user approval before apply_changes. Deletions also require confirmDelete=true when applying.",
21868
- inputSchema: { workspaceId: external_exports.string().min(1), operations: external_exports.array(operationSchema).min(1).max(100) },
21869
- annotations: { readOnlyHint: true, openWorldHint: false }
21870
- }, async ({ workspaceId, operations }) => {
21871
- const { raw, workspace } = loadRawWorkspace(workspaceId);
21872
- assertCanEdit(workspace);
21873
- let tree = structuredClone(workspace.tree);
21874
- const summary = [];
21875
- for (const operation of operations) {
21876
- const result = collectSummary(tree, operation);
21877
- tree = result.tree;
21878
- summary.push(result.summary);
21879
- }
21880
- const id = randomUUID();
21881
- const plan = {
21882
- id,
21883
- workspaceId,
21884
- sourceHash: createHash("sha256").update(raw).digest("hex"),
21885
- operations,
21886
- nextTree: tree,
21887
- summary,
21888
- includesDelete: operations.some((operation) => operation.action === "delete_node"),
21889
- expiresAt: Date.now() + 10 * 60 * 1e3
21890
- };
21891
- plans.set(id, plan);
21892
- return jsonResult({ previewId: id, workspaceId, workspaceName: workspace.name, changes: summary, deletesItems: plan.includesDelete, expiresInSeconds: 600 });
21893
- });
21894
- server.registerTool("apply_changes", {
21895
- title: "Apply collection changes",
21896
- description: "Apply a previously previewed batch to the local workspace only after the user explicitly approved the readable preview shown in chat. Requires the workspace to be unchanged since preview. Set confirmDelete=true only when the user explicitly approved deleting the listed items.",
21897
- inputSchema: { previewId: external_exports.string().min(1), confirmDelete: external_exports.boolean().default(false) },
21898
- annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
21899
- }, async ({ previewId, confirmDelete }) => {
21900
- const plan = plans.get(previewId);
21901
- if (!plan || plan.expiresAt < Date.now()) {
21902
- plans.delete(previewId);
21903
- throw new Error("This preview expired or was not found. Run preview_changes again.");
21904
- }
21905
- if (plan.includesDelete && !confirmDelete) throw new Error("This batch includes deletion. Ask the user to confirm the listed deletions, then retry with confirmDelete=true.");
21906
- const db = database();
21907
- db.exec("BEGIN IMMEDIATE;");
21908
- let updated;
21909
- try {
21910
- const { raw, workspace } = loadRawWorkspace(plan.workspaceId);
21911
- assertCanEdit(workspace);
21912
- const currentHash = createHash("sha256").update(raw).digest("hex");
21913
- if (currentHash !== plan.sourceHash) throw new Error("The workspace changed after this preview. Run preview_changes again to avoid overwriting newer edits.");
21914
- updated = { ...workspace, tree: structuredClone(plan.nextTree) };
21915
- db.prepare("UPDATE workspaces SET data = ? WHERE id = ?").run(JSON.stringify(updated), plan.workspaceId);
21916
- db.exec("COMMIT;");
21917
- } catch (error2) {
21918
- db.exec("ROLLBACK;");
21919
- throw error2;
22945
+
22946
+ // src/guide.ts
22947
+ var guideText = `# API Documentation: how to build and change the workspace
22948
+
22949
+ Read this before any change. It sets how requests, variables, folders, and docs are made, so the result matches the API's real flows.
22950
+
22951
+ ## 0. Start every task the same way
22952
+ 1. Call list_commands for the parameters and whether a command is read-only or destructive.
22953
+ 2. Read what exists first: workspace_list, tree_get, request_search, and request_get. Never create something that already exists under another name.
22954
+ 3. Read the variables that are already there with variable_get before you add one. Reuse a name that exists.
22955
+ 4. If the API contract is unknown, say what is unknown and ask. Do not guess a route, a field, or a status code.
22956
+
22957
+ ## 1. Folders: one top-level folder per service
22958
+ - Top level: one folder per service or segment of the API, named in Title Case: Auth, Users, Billing, Orders. Create it with folder_create and parentId null.
22959
+ - Second level: one folder per business flow (for example "Checkout") or per resource (for example "Invoices"). Use a flow folder when several requests happen in order. Use a resource folder for standalone CRUD.
22960
+ - Put requests that every service needs (health check, token refresh) in a "Shared" folder at the top level.
22961
+ - Keep the tree at most three levels deep. Deeper nesting is hard to scan.
22962
+ - Move an existing item with node_move. Rename a folder with folder_rename. Do not delete and recreate a folder to move it, because its requests lose their place.
22963
+
22964
+ ## 2. Requests: name and order
22965
+ - Name a request "METHOD resource action", for example "POST /invoices create". Keep the method visible in the name.
22966
+ - In a flow folder, prefix each request with its step: "1 Create cart", "2 Add item", "3 Checkout". The order must match the real order of calls.
22967
+
22968
+ ## 3. Auth: set it for every request that needs it
22969
+ - Look at the endpoint's contract before you create the request.
22970
+ - JWT or any Authorization header: auth type bearer, token {{accessToken}}. Never a literal token.
22971
+ - API key: auth type api-key, with name, location (header or query), and value {{apiKey}}.
22972
+ - Username and password: auth type basic, with {{username}} and {{password}}.
22973
+ - Public endpoint: auth type none, and only when the contract says it is public.
22974
+ - request_update keeps the existing auth unless you send auth again. When you change how a request is called, send auth again so it is set on purpose.
22975
+ - Never write a real token, password, or key into a request. The variable holds it, and the value is entered in the app.
22976
+
22977
+ ## 4. Variables: when a value becomes one
22978
+ Make a variable when a value does at least one of these:
22979
+ - It differs between environments, such as baseUrl, host, or tenantId. Use scope environment.
22980
+ - It is the same in every request, such as apiVersion or a tenant header name. Use scope global.
22981
+ - It is a credential, such as accessToken, apiKey, or password. Use secret true, with no value. The value is entered in the app.
22982
+
22983
+ Keep a literal value in the request when it is used once, does not change between environments, and is not a credential.
22984
+
22985
+ Naming: lowerCamelCase, specific, and the same name everywhere. Do not create baseUrl and base_url for the same thing.
22986
+
22987
+ Where a variable works: {{name}} resolves in the URL, params, headers, body, and auth when a request is sent. Globals apply everywhere. An active environment overrides a global of the same name. Set the active environment with environment_activate, and tell the user which one it is.
22988
+
22989
+ Writes: variable_set and variable_delete take the revision from variable_get as expectedRevision. Use null for a variable that does not exist yet. A stale revision is refused, so read again and retry.
22990
+
22991
+ ## 5. Documentation: complete, and per business flow
22992
+ Every request gets:
22993
+ - Purpose: what the endpoint does, in one or two sentences.
22994
+ - Place in the flow: "Step 2 of Checkout. Before: Create cart. After: Confirm order." Name the requests.
22995
+ - Preconditions: what must be true first, and which variables must be set.
22996
+ - Auth: which variable provides it.
22997
+ - Request: each param, header, and body field, with its type, whether it is required, what it means, and a realistic example. Use {{variables}} in examples, never a real value.
22998
+ - Responses: one entry per status code the contract lists, with an example body. Include the error responses: which code, which error body, and when it happens.
22999
+ - Side effects: what changes on the server or in other requests.
23000
+
23001
+ Write it in the request's documentation field and its responses. Put the flow overview in the flow folder's first request. If a part is unknown, write "Unknown: ..." and ask the user. Do not fill it with a guess.
23002
+
23003
+ ## 6. Changing collections: preview, ask, then apply
23004
+ - Every change to folders, requests, or moves goes through changes_preview. Apply it with changes_apply only after the user approves that exact preview.
23005
+ - Show the preview in chat: the workspace, the full path of each item, the before and after of each changed field, and what a deletion removes.
23006
+ - Ask the user to approve it, then stop. Do not call changes_apply in the same turn as the preview.
23007
+ - changes_apply refuses a preview when the workspace changed after it. Preview again.
23008
+ - Direct write commands (request_create, request_update, folder_create, node_move) are for the user's explicit request, and still need the approval above.
23009
+
23010
+ ## 7. Deleting and deprecating
23011
+ - Prefer request_deprecate with a reason over deleting a request that other people may use.
23012
+ - Delete only when the user asks, and set confirm=true only after the user has confirmed that exact deletion.
23013
+
23014
+ ## 8. Sending requests
23015
+ - Send only when the user asks. Say which environment is active first.
23016
+ - A variable with no value stops the send, and the error names it. Fill it in the app, or ask.
23017
+ - Do not send a request that changes data on a production server without asking.
23018
+
23019
+ ## 9. Limits
23020
+ - Cloud workspaces are read-only over MCP. Changes to a cloud copy are made in the desktop app.
23021
+ - Viewer workspaces refuse writes.
23022
+ - Secret values are never returned. environment_list shows them as <secret>.
23023
+ `;
23024
+ function createGuideGate() {
23025
+ let read = false;
23026
+ return {
23027
+ markRead() {
23028
+ read = true;
23029
+ },
23030
+ refusal(command) {
23031
+ if (command.readOnly || read) return null;
23032
+ return "Read the guide first: call the guide tool, then retry this command.";
21920
23033
  }
21921
- plans.delete(previewId);
21922
- process.stderr.write(`Applied MCP changes to workspace ${plan.workspaceId}.
21923
- `);
21924
- return jsonResult({ applied: true, workspaceId: plan.workspaceId, workspaceName: updated.name, changes: plan.summary });
21925
- });
23034
+ };
21926
23035
  }
21927
- async function main() {
21928
- const server = new McpServer({ name: "api-documentation-local", version: "1.0.0" }, {
21929
- instructions: "Use this server to maintain API endpoint documentation in local desktop workspaces. Search and read requests first. Record all known applicable route, params, headers, body, auth, response contracts, and documentation; do not invent missing details. Use {{baseUrl}} or other descriptive {{variableName}} references for reusable or environment-specific values, and {{accessToken}} for credentials; never write a real secret. Global variables are workspace-wide defaults, environment values can override them, and credentials should be marked Secret in the desktop Variables UI. This MCP can write request references but cannot read or manage variable definitions or values; tell the user when a referenced variable must be configured in the UI. Always call preview_changes, then render a readable diff directly in chat showing the workspace, full collection paths, each changed field before and after, response/body details, variable-definition gaps, and nested deletion impact. Redact secret values. Ask the user to approve that exact preview and stop; never call apply_changes in the same turn as the preview. Preserve existing auth and variable references unless asked to change them. Delete only when the user explicitly asks and confirms."
21930
- });
21931
- registerTools(server);
21932
- const transport = new StdioServerTransport();
21933
- await server.connect(transport);
23036
+
23037
+ // src/mcp.ts
23038
+ var toolName = (commandId) => commandId.replace(/\./g, "_");
23039
+ var legacyTools = {
23040
+ list_workspaces: "workspace.list",
23041
+ get_collection_tree: "tree.get",
23042
+ search_requests: "request.search",
23043
+ get_request: "request.get",
23044
+ preview_changes: "changes.preview",
23045
+ apply_changes: "changes.apply"
23046
+ };
23047
+ var instructions = "Drive the API Documentation desktop app: list workspaces, read and change collections, requests, environments, and variables, and send requests. Call list_commands first to see every command and its parameters. Search and read requests before changing them. Record known route, parameters, headers, body, auth, and response contracts, and do not invent missing details. Use {{baseUrl}} or other descriptive {{variableName}} references for environment-specific values, and {{accessToken}} for credentials. Never write a real secret: secret variables are created empty, and their values are entered in the desktop app. Changes to collections go through changes.preview; render the diff in chat (workspace, full collection paths, before and after for each field, nested deletion impact), ask the user to approve that exact preview, and stop. Never call changes.apply in the same turn as the preview. Destructive commands require confirm=true, which is only set after the user explicitly confirms. Call guide before the first change: write commands are refused until it has been read in this session.";
23048
+ async function startMcpServer() {
23049
+ const server = new McpServer({ name: "api-documentation-local", version: "0.2.0" }, { instructions });
23050
+ const guide = createGuideGate();
23051
+ const register = (name, commandId, title, description) => {
23052
+ const command = allCommands.find((item) => item.id === commandId);
23053
+ if (!command) throw new Error(`Command ${commandId} is not registered.`);
23054
+ server.registerTool(
23055
+ name,
23056
+ {
23057
+ title,
23058
+ description,
23059
+ inputSchema: command.params.shape,
23060
+ annotations: { readOnlyHint: command.readOnly, destructiveHint: command.destructive, openWorldHint: command.id === "request.send" }
23061
+ },
23062
+ async (params) => {
23063
+ const input = params ?? {};
23064
+ const refusal = guide.refusal(command) ?? missingTargetConfirmation(commandId, input) ?? missingVariableRevision(commandId, input);
23065
+ if (refusal) throw new Error(refusal);
23066
+ return { content: [{ type: "text", text: JSON.stringify(await executeCommand(commandId, params), null, 2) }] };
23067
+ }
23068
+ );
23069
+ };
23070
+ for (const command of mcpCommands()) {
23071
+ register(toolName(command.id), command.id, command.title, command.description);
23072
+ }
23073
+ for (const [name, commandId] of Object.entries(legacyTools)) {
23074
+ const command = allCommands.find((item) => item.id === commandId);
23075
+ if (command) register(name, commandId, command.title, `${command.description} (Same as ${toolName(commandId)}.)`);
23076
+ }
23077
+ server.registerTool(
23078
+ "guide",
23079
+ {
23080
+ title: "Guide",
23081
+ description: "The rules for changing the app safely: read first, preview before apply, confirm deletes, and never write a secret. Read it before any write.",
23082
+ annotations: { readOnlyHint: true, openWorldHint: false }
23083
+ },
23084
+ async () => {
23085
+ guide.markRead();
23086
+ return { content: [{ type: "text", text: guideText }] };
23087
+ }
23088
+ );
23089
+ server.registerTool(
23090
+ "list_commands",
23091
+ {
23092
+ title: "List commands",
23093
+ description: "List every desktop app command with its parameters and whether it is read-only or destructive.",
23094
+ annotations: { readOnlyHint: true, openWorldHint: false }
23095
+ },
23096
+ async () => ({ content: [{ type: "text", text: JSON.stringify(mcpCommands().map(describeCommand), null, 2) }] })
23097
+ );
23098
+ await server.connect(new StdioServerTransport());
21934
23099
  }
21935
- main().catch((error2) => {
21936
- const message = error2 instanceof Error ? error2.stack || error2.message : String(error2);
23100
+
23101
+ // src/index.ts
23102
+ var args = process.argv.slice(2);
23103
+ var main = args.length === 0 || args[0] === "mcp" ? startMcpServer() : runCli(args);
23104
+ main.catch((error2) => {
23105
+ const message = error2 instanceof Error ? error2.message : String(error2);
21937
23106
  process.stderr.write(`${message}
21938
23107
  `);
21939
23108
  process.exitCode = 1;