goatedit-mcp 1.1.9 → 1.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/goatedit-mcp.js +3485 -180
- package/package.json +1 -1
package/bundle/goatedit-mcp.js
CHANGED
|
@@ -3232,8 +3232,8 @@ var require_utils = __commonJS({
|
|
|
3232
3232
|
}
|
|
3233
3233
|
return ind;
|
|
3234
3234
|
}
|
|
3235
|
-
function removeDotSegments(
|
|
3236
|
-
let input =
|
|
3235
|
+
function removeDotSegments(path4) {
|
|
3236
|
+
let input = path4;
|
|
3237
3237
|
const output = [];
|
|
3238
3238
|
let nextSlash = -1;
|
|
3239
3239
|
let len = 0;
|
|
@@ -3485,8 +3485,8 @@ var require_schemes = __commonJS({
|
|
|
3485
3485
|
wsComponent.secure = void 0;
|
|
3486
3486
|
}
|
|
3487
3487
|
if (wsComponent.resourceName) {
|
|
3488
|
-
const [
|
|
3489
|
-
wsComponent.path =
|
|
3488
|
+
const [path4, query] = wsComponent.resourceName.split("?");
|
|
3489
|
+
wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
|
|
3490
3490
|
wsComponent.query = query;
|
|
3491
3491
|
wsComponent.resourceName = void 0;
|
|
3492
3492
|
}
|
|
@@ -6586,7 +6586,7 @@ var require_formats = __commonJS({
|
|
|
6586
6586
|
}
|
|
6587
6587
|
exports.fullFormats = {
|
|
6588
6588
|
// date: http://tools.ietf.org/html/rfc3339#section-5.6
|
|
6589
|
-
date: fmtDef(
|
|
6589
|
+
date: fmtDef(date4, compareDate),
|
|
6590
6590
|
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
|
|
6591
6591
|
time: fmtDef(getTime(true), compareTime),
|
|
6592
6592
|
"date-time": fmtDef(getDateTime(true), compareDateTime),
|
|
@@ -6652,7 +6652,7 @@ var require_formats = __commonJS({
|
|
|
6652
6652
|
}
|
|
6653
6653
|
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
6654
6654
|
var DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
6655
|
-
function
|
|
6655
|
+
function date4(str2) {
|
|
6656
6656
|
const matches = DATE.exec(str2);
|
|
6657
6657
|
if (!matches)
|
|
6658
6658
|
return false;
|
|
@@ -6721,7 +6721,7 @@ var require_formats = __commonJS({
|
|
|
6721
6721
|
const time3 = getTime(strictTimeZone);
|
|
6722
6722
|
return function date_time(str2) {
|
|
6723
6723
|
const dateTime = str2.split(DATE_TIME_SEPARATOR);
|
|
6724
|
-
return dateTime.length === 2 &&
|
|
6724
|
+
return dateTime.length === 2 && date4(dateTime[0]) && time3(dateTime[1]);
|
|
6725
6725
|
};
|
|
6726
6726
|
}
|
|
6727
6727
|
function compareDateTime(dt1, dt2) {
|
|
@@ -6879,12 +6879,12 @@ var require_dist = __commonJS({
|
|
|
6879
6879
|
throw new Error(`Unknown format "${name}"`);
|
|
6880
6880
|
return f;
|
|
6881
6881
|
};
|
|
6882
|
-
function addFormats(ajv, list,
|
|
6882
|
+
function addFormats(ajv, list, fs4, exportName) {
|
|
6883
6883
|
var _a3;
|
|
6884
6884
|
var _b;
|
|
6885
6885
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
6886
6886
|
for (const f of list)
|
|
6887
|
-
ajv.addFormat(f,
|
|
6887
|
+
ajv.addFormat(f, fs4[f]);
|
|
6888
6888
|
}
|
|
6889
6889
|
module.exports = exports = formatsPlugin;
|
|
6890
6890
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -9138,10 +9138,10 @@ var require_websocket = __commonJS({
|
|
|
9138
9138
|
var EventEmitter = __require("events");
|
|
9139
9139
|
var https = __require("https");
|
|
9140
9140
|
var http2 = __require("http");
|
|
9141
|
-
var
|
|
9141
|
+
var net2 = __require("net");
|
|
9142
9142
|
var tls = __require("tls");
|
|
9143
9143
|
var { randomBytes, createHash } = __require("crypto");
|
|
9144
|
-
var { Duplex, Readable } = __require("stream");
|
|
9144
|
+
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
9145
9145
|
var { URL: URL2 } = __require("url");
|
|
9146
9146
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
9147
9147
|
var Receiver2 = require_receiver();
|
|
@@ -9882,12 +9882,12 @@ var require_websocket = __commonJS({
|
|
|
9882
9882
|
}
|
|
9883
9883
|
function netConnect(options) {
|
|
9884
9884
|
options.path = options.socketPath;
|
|
9885
|
-
return
|
|
9885
|
+
return net2.connect(options);
|
|
9886
9886
|
}
|
|
9887
9887
|
function tlsConnect(options) {
|
|
9888
9888
|
options.path = void 0;
|
|
9889
9889
|
if (!options.servername && options.servername !== "") {
|
|
9890
|
-
options.servername =
|
|
9890
|
+
options.servername = net2.isIP(options.host) ? "" : options.host;
|
|
9891
9891
|
}
|
|
9892
9892
|
return tls.connect(options);
|
|
9893
9893
|
}
|
|
@@ -10571,8 +10571,508 @@ var require_websocket_server = __commonJS({
|
|
|
10571
10571
|
}
|
|
10572
10572
|
});
|
|
10573
10573
|
|
|
10574
|
+
// node_modules/isexe/windows.js
|
|
10575
|
+
var require_windows = __commonJS({
|
|
10576
|
+
"node_modules/isexe/windows.js"(exports, module) {
|
|
10577
|
+
module.exports = isexe;
|
|
10578
|
+
isexe.sync = sync;
|
|
10579
|
+
var fs4 = __require("fs");
|
|
10580
|
+
function checkPathExt(path4, options) {
|
|
10581
|
+
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
10582
|
+
if (!pathext) {
|
|
10583
|
+
return true;
|
|
10584
|
+
}
|
|
10585
|
+
pathext = pathext.split(";");
|
|
10586
|
+
if (pathext.indexOf("") !== -1) {
|
|
10587
|
+
return true;
|
|
10588
|
+
}
|
|
10589
|
+
for (var i = 0; i < pathext.length; i++) {
|
|
10590
|
+
var p = pathext[i].toLowerCase();
|
|
10591
|
+
if (p && path4.substr(-p.length).toLowerCase() === p) {
|
|
10592
|
+
return true;
|
|
10593
|
+
}
|
|
10594
|
+
}
|
|
10595
|
+
return false;
|
|
10596
|
+
}
|
|
10597
|
+
function checkStat(stat, path4, options) {
|
|
10598
|
+
if (!stat.isSymbolicLink() && !stat.isFile()) {
|
|
10599
|
+
return false;
|
|
10600
|
+
}
|
|
10601
|
+
return checkPathExt(path4, options);
|
|
10602
|
+
}
|
|
10603
|
+
function isexe(path4, options, cb) {
|
|
10604
|
+
fs4.stat(path4, function(er, stat) {
|
|
10605
|
+
cb(er, er ? false : checkStat(stat, path4, options));
|
|
10606
|
+
});
|
|
10607
|
+
}
|
|
10608
|
+
function sync(path4, options) {
|
|
10609
|
+
return checkStat(fs4.statSync(path4), path4, options);
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
});
|
|
10613
|
+
|
|
10614
|
+
// node_modules/isexe/mode.js
|
|
10615
|
+
var require_mode = __commonJS({
|
|
10616
|
+
"node_modules/isexe/mode.js"(exports, module) {
|
|
10617
|
+
module.exports = isexe;
|
|
10618
|
+
isexe.sync = sync;
|
|
10619
|
+
var fs4 = __require("fs");
|
|
10620
|
+
function isexe(path4, options, cb) {
|
|
10621
|
+
fs4.stat(path4, function(er, stat) {
|
|
10622
|
+
cb(er, er ? false : checkStat(stat, options));
|
|
10623
|
+
});
|
|
10624
|
+
}
|
|
10625
|
+
function sync(path4, options) {
|
|
10626
|
+
return checkStat(fs4.statSync(path4), options);
|
|
10627
|
+
}
|
|
10628
|
+
function checkStat(stat, options) {
|
|
10629
|
+
return stat.isFile() && checkMode(stat, options);
|
|
10630
|
+
}
|
|
10631
|
+
function checkMode(stat, options) {
|
|
10632
|
+
var mod = stat.mode;
|
|
10633
|
+
var uid = stat.uid;
|
|
10634
|
+
var gid = stat.gid;
|
|
10635
|
+
var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
|
|
10636
|
+
var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
|
|
10637
|
+
var u = parseInt("100", 8);
|
|
10638
|
+
var g = parseInt("010", 8);
|
|
10639
|
+
var o = parseInt("001", 8);
|
|
10640
|
+
var ug = u | g;
|
|
10641
|
+
var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
|
|
10642
|
+
return ret;
|
|
10643
|
+
}
|
|
10644
|
+
}
|
|
10645
|
+
});
|
|
10646
|
+
|
|
10647
|
+
// node_modules/isexe/index.js
|
|
10648
|
+
var require_isexe = __commonJS({
|
|
10649
|
+
"node_modules/isexe/index.js"(exports, module) {
|
|
10650
|
+
var fs4 = __require("fs");
|
|
10651
|
+
var core;
|
|
10652
|
+
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
10653
|
+
core = require_windows();
|
|
10654
|
+
} else {
|
|
10655
|
+
core = require_mode();
|
|
10656
|
+
}
|
|
10657
|
+
module.exports = isexe;
|
|
10658
|
+
isexe.sync = sync;
|
|
10659
|
+
function isexe(path4, options, cb) {
|
|
10660
|
+
if (typeof options === "function") {
|
|
10661
|
+
cb = options;
|
|
10662
|
+
options = {};
|
|
10663
|
+
}
|
|
10664
|
+
if (!cb) {
|
|
10665
|
+
if (typeof Promise !== "function") {
|
|
10666
|
+
throw new TypeError("callback not provided");
|
|
10667
|
+
}
|
|
10668
|
+
return new Promise(function(resolve, reject) {
|
|
10669
|
+
isexe(path4, options || {}, function(er, is) {
|
|
10670
|
+
if (er) {
|
|
10671
|
+
reject(er);
|
|
10672
|
+
} else {
|
|
10673
|
+
resolve(is);
|
|
10674
|
+
}
|
|
10675
|
+
});
|
|
10676
|
+
});
|
|
10677
|
+
}
|
|
10678
|
+
core(path4, options || {}, function(er, is) {
|
|
10679
|
+
if (er) {
|
|
10680
|
+
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
10681
|
+
er = null;
|
|
10682
|
+
is = false;
|
|
10683
|
+
}
|
|
10684
|
+
}
|
|
10685
|
+
cb(er, is);
|
|
10686
|
+
});
|
|
10687
|
+
}
|
|
10688
|
+
function sync(path4, options) {
|
|
10689
|
+
try {
|
|
10690
|
+
return core.sync(path4, options || {});
|
|
10691
|
+
} catch (er) {
|
|
10692
|
+
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
10693
|
+
return false;
|
|
10694
|
+
} else {
|
|
10695
|
+
throw er;
|
|
10696
|
+
}
|
|
10697
|
+
}
|
|
10698
|
+
}
|
|
10699
|
+
}
|
|
10700
|
+
});
|
|
10701
|
+
|
|
10702
|
+
// node_modules/which/which.js
|
|
10703
|
+
var require_which = __commonJS({
|
|
10704
|
+
"node_modules/which/which.js"(exports, module) {
|
|
10705
|
+
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
10706
|
+
var path4 = __require("path");
|
|
10707
|
+
var COLON = isWindows ? ";" : ":";
|
|
10708
|
+
var isexe = require_isexe();
|
|
10709
|
+
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
10710
|
+
var getPathInfo = (cmd, opt) => {
|
|
10711
|
+
const colon = opt.colon || COLON;
|
|
10712
|
+
const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [
|
|
10713
|
+
// windows always checks the cwd first
|
|
10714
|
+
...isWindows ? [process.cwd()] : [],
|
|
10715
|
+
...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */
|
|
10716
|
+
"").split(colon)
|
|
10717
|
+
];
|
|
10718
|
+
const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
|
|
10719
|
+
const pathExt = isWindows ? pathExtExe.split(colon) : [""];
|
|
10720
|
+
if (isWindows) {
|
|
10721
|
+
if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
|
|
10722
|
+
pathExt.unshift("");
|
|
10723
|
+
}
|
|
10724
|
+
return {
|
|
10725
|
+
pathEnv,
|
|
10726
|
+
pathExt,
|
|
10727
|
+
pathExtExe
|
|
10728
|
+
};
|
|
10729
|
+
};
|
|
10730
|
+
var which = (cmd, opt, cb) => {
|
|
10731
|
+
if (typeof opt === "function") {
|
|
10732
|
+
cb = opt;
|
|
10733
|
+
opt = {};
|
|
10734
|
+
}
|
|
10735
|
+
if (!opt)
|
|
10736
|
+
opt = {};
|
|
10737
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
10738
|
+
const found = [];
|
|
10739
|
+
const step = (i) => new Promise((resolve, reject) => {
|
|
10740
|
+
if (i === pathEnv.length)
|
|
10741
|
+
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
10742
|
+
const ppRaw = pathEnv[i];
|
|
10743
|
+
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
10744
|
+
const pCmd = path4.join(pathPart, cmd);
|
|
10745
|
+
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
10746
|
+
resolve(subStep(p, i, 0));
|
|
10747
|
+
});
|
|
10748
|
+
const subStep = (p, i, ii) => new Promise((resolve, reject) => {
|
|
10749
|
+
if (ii === pathExt.length)
|
|
10750
|
+
return resolve(step(i + 1));
|
|
10751
|
+
const ext = pathExt[ii];
|
|
10752
|
+
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
|
|
10753
|
+
if (!er && is) {
|
|
10754
|
+
if (opt.all)
|
|
10755
|
+
found.push(p + ext);
|
|
10756
|
+
else
|
|
10757
|
+
return resolve(p + ext);
|
|
10758
|
+
}
|
|
10759
|
+
return resolve(subStep(p, i, ii + 1));
|
|
10760
|
+
});
|
|
10761
|
+
});
|
|
10762
|
+
return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
|
|
10763
|
+
};
|
|
10764
|
+
var whichSync = (cmd, opt) => {
|
|
10765
|
+
opt = opt || {};
|
|
10766
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
10767
|
+
const found = [];
|
|
10768
|
+
for (let i = 0; i < pathEnv.length; i++) {
|
|
10769
|
+
const ppRaw = pathEnv[i];
|
|
10770
|
+
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
10771
|
+
const pCmd = path4.join(pathPart, cmd);
|
|
10772
|
+
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
10773
|
+
for (let j = 0; j < pathExt.length; j++) {
|
|
10774
|
+
const cur = p + pathExt[j];
|
|
10775
|
+
try {
|
|
10776
|
+
const is = isexe.sync(cur, { pathExt: pathExtExe });
|
|
10777
|
+
if (is) {
|
|
10778
|
+
if (opt.all)
|
|
10779
|
+
found.push(cur);
|
|
10780
|
+
else
|
|
10781
|
+
return cur;
|
|
10782
|
+
}
|
|
10783
|
+
} catch (ex) {
|
|
10784
|
+
}
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
if (opt.all && found.length)
|
|
10788
|
+
return found;
|
|
10789
|
+
if (opt.nothrow)
|
|
10790
|
+
return null;
|
|
10791
|
+
throw getNotFoundError(cmd);
|
|
10792
|
+
};
|
|
10793
|
+
module.exports = which;
|
|
10794
|
+
which.sync = whichSync;
|
|
10795
|
+
}
|
|
10796
|
+
});
|
|
10797
|
+
|
|
10798
|
+
// node_modules/path-key/index.js
|
|
10799
|
+
var require_path_key = __commonJS({
|
|
10800
|
+
"node_modules/path-key/index.js"(exports, module) {
|
|
10801
|
+
"use strict";
|
|
10802
|
+
var pathKey = (options = {}) => {
|
|
10803
|
+
const environment = options.env || process.env;
|
|
10804
|
+
const platform = options.platform || process.platform;
|
|
10805
|
+
if (platform !== "win32") {
|
|
10806
|
+
return "PATH";
|
|
10807
|
+
}
|
|
10808
|
+
return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
|
|
10809
|
+
};
|
|
10810
|
+
module.exports = pathKey;
|
|
10811
|
+
module.exports.default = pathKey;
|
|
10812
|
+
}
|
|
10813
|
+
});
|
|
10814
|
+
|
|
10815
|
+
// node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
10816
|
+
var require_resolveCommand = __commonJS({
|
|
10817
|
+
"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
|
|
10818
|
+
"use strict";
|
|
10819
|
+
var path4 = __require("path");
|
|
10820
|
+
var which = require_which();
|
|
10821
|
+
var getPathKey = require_path_key();
|
|
10822
|
+
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
10823
|
+
const env = parsed.options.env || process.env;
|
|
10824
|
+
const cwd = process.cwd();
|
|
10825
|
+
const hasCustomCwd = parsed.options.cwd != null;
|
|
10826
|
+
const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled;
|
|
10827
|
+
if (shouldSwitchCwd) {
|
|
10828
|
+
try {
|
|
10829
|
+
process.chdir(parsed.options.cwd);
|
|
10830
|
+
} catch (err) {
|
|
10831
|
+
}
|
|
10832
|
+
}
|
|
10833
|
+
let resolved;
|
|
10834
|
+
try {
|
|
10835
|
+
resolved = which.sync(parsed.command, {
|
|
10836
|
+
path: env[getPathKey({ env })],
|
|
10837
|
+
pathExt: withoutPathExt ? path4.delimiter : void 0
|
|
10838
|
+
});
|
|
10839
|
+
} catch (e) {
|
|
10840
|
+
} finally {
|
|
10841
|
+
if (shouldSwitchCwd) {
|
|
10842
|
+
process.chdir(cwd);
|
|
10843
|
+
}
|
|
10844
|
+
}
|
|
10845
|
+
if (resolved) {
|
|
10846
|
+
resolved = path4.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
10847
|
+
}
|
|
10848
|
+
return resolved;
|
|
10849
|
+
}
|
|
10850
|
+
function resolveCommand(parsed) {
|
|
10851
|
+
return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
|
|
10852
|
+
}
|
|
10853
|
+
module.exports = resolveCommand;
|
|
10854
|
+
}
|
|
10855
|
+
});
|
|
10856
|
+
|
|
10857
|
+
// node_modules/cross-spawn/lib/util/escape.js
|
|
10858
|
+
var require_escape = __commonJS({
|
|
10859
|
+
"node_modules/cross-spawn/lib/util/escape.js"(exports, module) {
|
|
10860
|
+
"use strict";
|
|
10861
|
+
var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
|
|
10862
|
+
function escapeCommand(arg) {
|
|
10863
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
10864
|
+
return arg;
|
|
10865
|
+
}
|
|
10866
|
+
function escapeArgument(arg, doubleEscapeMetaChars) {
|
|
10867
|
+
arg = `${arg}`;
|
|
10868
|
+
arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
|
|
10869
|
+
arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
|
|
10870
|
+
arg = `"${arg}"`;
|
|
10871
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
10872
|
+
if (doubleEscapeMetaChars) {
|
|
10873
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
10874
|
+
}
|
|
10875
|
+
return arg;
|
|
10876
|
+
}
|
|
10877
|
+
module.exports.command = escapeCommand;
|
|
10878
|
+
module.exports.argument = escapeArgument;
|
|
10879
|
+
}
|
|
10880
|
+
});
|
|
10881
|
+
|
|
10882
|
+
// node_modules/shebang-regex/index.js
|
|
10883
|
+
var require_shebang_regex = __commonJS({
|
|
10884
|
+
"node_modules/shebang-regex/index.js"(exports, module) {
|
|
10885
|
+
"use strict";
|
|
10886
|
+
module.exports = /^#!(.*)/;
|
|
10887
|
+
}
|
|
10888
|
+
});
|
|
10889
|
+
|
|
10890
|
+
// node_modules/shebang-command/index.js
|
|
10891
|
+
var require_shebang_command = __commonJS({
|
|
10892
|
+
"node_modules/shebang-command/index.js"(exports, module) {
|
|
10893
|
+
"use strict";
|
|
10894
|
+
var shebangRegex = require_shebang_regex();
|
|
10895
|
+
module.exports = (string4 = "") => {
|
|
10896
|
+
const match = string4.match(shebangRegex);
|
|
10897
|
+
if (!match) {
|
|
10898
|
+
return null;
|
|
10899
|
+
}
|
|
10900
|
+
const [path4, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
10901
|
+
const binary = path4.split("/").pop();
|
|
10902
|
+
if (binary === "env") {
|
|
10903
|
+
return argument;
|
|
10904
|
+
}
|
|
10905
|
+
return argument ? `${binary} ${argument}` : binary;
|
|
10906
|
+
};
|
|
10907
|
+
}
|
|
10908
|
+
});
|
|
10909
|
+
|
|
10910
|
+
// node_modules/cross-spawn/lib/util/readShebang.js
|
|
10911
|
+
var require_readShebang = __commonJS({
|
|
10912
|
+
"node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
|
|
10913
|
+
"use strict";
|
|
10914
|
+
var fs4 = __require("fs");
|
|
10915
|
+
var shebangCommand = require_shebang_command();
|
|
10916
|
+
function readShebang(command) {
|
|
10917
|
+
const size = 150;
|
|
10918
|
+
const buffer = Buffer.alloc(size);
|
|
10919
|
+
let fd;
|
|
10920
|
+
try {
|
|
10921
|
+
fd = fs4.openSync(command, "r");
|
|
10922
|
+
fs4.readSync(fd, buffer, 0, size, 0);
|
|
10923
|
+
fs4.closeSync(fd);
|
|
10924
|
+
} catch (e) {
|
|
10925
|
+
}
|
|
10926
|
+
return shebangCommand(buffer.toString());
|
|
10927
|
+
}
|
|
10928
|
+
module.exports = readShebang;
|
|
10929
|
+
}
|
|
10930
|
+
});
|
|
10931
|
+
|
|
10932
|
+
// node_modules/cross-spawn/lib/parse.js
|
|
10933
|
+
var require_parse = __commonJS({
|
|
10934
|
+
"node_modules/cross-spawn/lib/parse.js"(exports, module) {
|
|
10935
|
+
"use strict";
|
|
10936
|
+
var path4 = __require("path");
|
|
10937
|
+
var resolveCommand = require_resolveCommand();
|
|
10938
|
+
var escape2 = require_escape();
|
|
10939
|
+
var readShebang = require_readShebang();
|
|
10940
|
+
var isWin = process.platform === "win32";
|
|
10941
|
+
var isExecutableRegExp = /\.(?:com|exe)$/i;
|
|
10942
|
+
var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
|
|
10943
|
+
function detectShebang(parsed) {
|
|
10944
|
+
parsed.file = resolveCommand(parsed);
|
|
10945
|
+
const shebang = parsed.file && readShebang(parsed.file);
|
|
10946
|
+
if (shebang) {
|
|
10947
|
+
parsed.args.unshift(parsed.file);
|
|
10948
|
+
parsed.command = shebang;
|
|
10949
|
+
return resolveCommand(parsed);
|
|
10950
|
+
}
|
|
10951
|
+
return parsed.file;
|
|
10952
|
+
}
|
|
10953
|
+
function parseNonShell(parsed) {
|
|
10954
|
+
if (!isWin) {
|
|
10955
|
+
return parsed;
|
|
10956
|
+
}
|
|
10957
|
+
const commandFile = detectShebang(parsed);
|
|
10958
|
+
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
10959
|
+
if (parsed.options.forceShell || needsShell) {
|
|
10960
|
+
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
10961
|
+
parsed.command = path4.normalize(parsed.command);
|
|
10962
|
+
parsed.command = escape2.command(parsed.command);
|
|
10963
|
+
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
10964
|
+
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
10965
|
+
parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
|
|
10966
|
+
parsed.command = process.env.comspec || "cmd.exe";
|
|
10967
|
+
parsed.options.windowsVerbatimArguments = true;
|
|
10968
|
+
}
|
|
10969
|
+
return parsed;
|
|
10970
|
+
}
|
|
10971
|
+
function parse3(command, args, options) {
|
|
10972
|
+
if (args && !Array.isArray(args)) {
|
|
10973
|
+
options = args;
|
|
10974
|
+
args = null;
|
|
10975
|
+
}
|
|
10976
|
+
args = args ? args.slice(0) : [];
|
|
10977
|
+
options = Object.assign({}, options);
|
|
10978
|
+
const parsed = {
|
|
10979
|
+
command,
|
|
10980
|
+
args,
|
|
10981
|
+
options,
|
|
10982
|
+
file: void 0,
|
|
10983
|
+
original: {
|
|
10984
|
+
command,
|
|
10985
|
+
args
|
|
10986
|
+
}
|
|
10987
|
+
};
|
|
10988
|
+
return options.shell ? parsed : parseNonShell(parsed);
|
|
10989
|
+
}
|
|
10990
|
+
module.exports = parse3;
|
|
10991
|
+
}
|
|
10992
|
+
});
|
|
10993
|
+
|
|
10994
|
+
// node_modules/cross-spawn/lib/enoent.js
|
|
10995
|
+
var require_enoent = __commonJS({
|
|
10996
|
+
"node_modules/cross-spawn/lib/enoent.js"(exports, module) {
|
|
10997
|
+
"use strict";
|
|
10998
|
+
var isWin = process.platform === "win32";
|
|
10999
|
+
function notFoundError(original, syscall) {
|
|
11000
|
+
return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
|
|
11001
|
+
code: "ENOENT",
|
|
11002
|
+
errno: "ENOENT",
|
|
11003
|
+
syscall: `${syscall} ${original.command}`,
|
|
11004
|
+
path: original.command,
|
|
11005
|
+
spawnargs: original.args
|
|
11006
|
+
});
|
|
11007
|
+
}
|
|
11008
|
+
function hookChildProcess(cp, parsed) {
|
|
11009
|
+
if (!isWin) {
|
|
11010
|
+
return;
|
|
11011
|
+
}
|
|
11012
|
+
const originalEmit = cp.emit;
|
|
11013
|
+
cp.emit = function(name, arg1) {
|
|
11014
|
+
if (name === "exit") {
|
|
11015
|
+
const err = verifyENOENT(arg1, parsed);
|
|
11016
|
+
if (err) {
|
|
11017
|
+
return originalEmit.call(cp, "error", err);
|
|
11018
|
+
}
|
|
11019
|
+
}
|
|
11020
|
+
return originalEmit.apply(cp, arguments);
|
|
11021
|
+
};
|
|
11022
|
+
}
|
|
11023
|
+
function verifyENOENT(status, parsed) {
|
|
11024
|
+
if (isWin && status === 1 && !parsed.file) {
|
|
11025
|
+
return notFoundError(parsed.original, "spawn");
|
|
11026
|
+
}
|
|
11027
|
+
return null;
|
|
11028
|
+
}
|
|
11029
|
+
function verifyENOENTSync(status, parsed) {
|
|
11030
|
+
if (isWin && status === 1 && !parsed.file) {
|
|
11031
|
+
return notFoundError(parsed.original, "spawnSync");
|
|
11032
|
+
}
|
|
11033
|
+
return null;
|
|
11034
|
+
}
|
|
11035
|
+
module.exports = {
|
|
11036
|
+
hookChildProcess,
|
|
11037
|
+
verifyENOENT,
|
|
11038
|
+
verifyENOENTSync,
|
|
11039
|
+
notFoundError
|
|
11040
|
+
};
|
|
11041
|
+
}
|
|
11042
|
+
});
|
|
11043
|
+
|
|
11044
|
+
// node_modules/cross-spawn/index.js
|
|
11045
|
+
var require_cross_spawn = __commonJS({
|
|
11046
|
+
"node_modules/cross-spawn/index.js"(exports, module) {
|
|
11047
|
+
"use strict";
|
|
11048
|
+
var cp = __require("child_process");
|
|
11049
|
+
var parse3 = require_parse();
|
|
11050
|
+
var enoent = require_enoent();
|
|
11051
|
+
function spawn2(command, args, options) {
|
|
11052
|
+
const parsed = parse3(command, args, options);
|
|
11053
|
+
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
|
|
11054
|
+
enoent.hookChildProcess(spawned, parsed);
|
|
11055
|
+
return spawned;
|
|
11056
|
+
}
|
|
11057
|
+
function spawnSync(command, args, options) {
|
|
11058
|
+
const parsed = parse3(command, args, options);
|
|
11059
|
+
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
|
|
11060
|
+
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
|
|
11061
|
+
return result;
|
|
11062
|
+
}
|
|
11063
|
+
module.exports = spawn2;
|
|
11064
|
+
module.exports.spawn = spawn2;
|
|
11065
|
+
module.exports.sync = spawnSync;
|
|
11066
|
+
module.exports._parse = parse3;
|
|
11067
|
+
module.exports._enoent = enoent;
|
|
11068
|
+
}
|
|
11069
|
+
});
|
|
11070
|
+
|
|
10574
11071
|
// node_modules/zod/v4/core/core.js
|
|
10575
11072
|
var _a;
|
|
11073
|
+
var NEVER = /* @__PURE__ */ Object.freeze({
|
|
11074
|
+
status: "aborted"
|
|
11075
|
+
});
|
|
10576
11076
|
// @__NO_SIDE_EFFECTS__
|
|
10577
11077
|
function $constructor(name, initializer3, params) {
|
|
10578
11078
|
function init(inst, def) {
|
|
@@ -10811,10 +11311,10 @@ function mergeDefs(...defs) {
|
|
|
10811
11311
|
function cloneDef(schema) {
|
|
10812
11312
|
return mergeDefs(schema._zod.def);
|
|
10813
11313
|
}
|
|
10814
|
-
function getElementAtPath(obj,
|
|
10815
|
-
if (!
|
|
11314
|
+
function getElementAtPath(obj, path4) {
|
|
11315
|
+
if (!path4)
|
|
10816
11316
|
return obj;
|
|
10817
|
-
return
|
|
11317
|
+
return path4.reduce((acc, key) => acc?.[key], obj);
|
|
10818
11318
|
}
|
|
10819
11319
|
function promiseAllObject(promisesObj) {
|
|
10820
11320
|
const keys = Object.keys(promisesObj);
|
|
@@ -11223,11 +11723,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
11223
11723
|
}
|
|
11224
11724
|
return false;
|
|
11225
11725
|
}
|
|
11226
|
-
function prefixIssues(
|
|
11726
|
+
function prefixIssues(path4, issues) {
|
|
11227
11727
|
return issues.map((iss) => {
|
|
11228
11728
|
var _a3;
|
|
11229
11729
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
11230
|
-
iss.path.unshift(
|
|
11730
|
+
iss.path.unshift(path4);
|
|
11231
11731
|
return iss;
|
|
11232
11732
|
});
|
|
11233
11733
|
}
|
|
@@ -11374,16 +11874,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
|
|
|
11374
11874
|
}
|
|
11375
11875
|
function formatError(error2, mapper = (issue2) => issue2.message) {
|
|
11376
11876
|
const fieldErrors = { _errors: [] };
|
|
11377
|
-
const processError = (error3,
|
|
11877
|
+
const processError = (error3, path4 = []) => {
|
|
11378
11878
|
for (const issue2 of error3.issues) {
|
|
11379
11879
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
11380
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
11880
|
+
issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
|
|
11381
11881
|
} else if (issue2.code === "invalid_key") {
|
|
11382
|
-
processError({ issues: issue2.issues }, [...
|
|
11882
|
+
processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
|
|
11383
11883
|
} else if (issue2.code === "invalid_element") {
|
|
11384
|
-
processError({ issues: issue2.issues }, [...
|
|
11884
|
+
processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
|
|
11385
11885
|
} else {
|
|
11386
|
-
const fullpath = [...
|
|
11886
|
+
const fullpath = [...path4, ...issue2.path];
|
|
11387
11887
|
if (fullpath.length === 0) {
|
|
11388
11888
|
fieldErrors._errors.push(mapper(issue2));
|
|
11389
11889
|
} else {
|
|
@@ -11538,6 +12038,7 @@ var string = (params) => {
|
|
|
11538
12038
|
const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
11539
12039
|
return new RegExp(`^${regex}$`);
|
|
11540
12040
|
};
|
|
12041
|
+
var bigint = /^-?\d+n?$/;
|
|
11541
12042
|
var integer = /^-?\d+$/;
|
|
11542
12043
|
var number = /^-?\d+(?:\.\d+)?$/;
|
|
11543
12044
|
var boolean = /^(?:true|false)$/i;
|
|
@@ -12160,10 +12661,10 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
|
|
|
12160
12661
|
return;
|
|
12161
12662
|
}
|
|
12162
12663
|
}
|
|
12163
|
-
const
|
|
12664
|
+
const url2 = new URL(trimmed);
|
|
12164
12665
|
if (def.hostname) {
|
|
12165
12666
|
def.hostname.lastIndex = 0;
|
|
12166
|
-
if (!def.hostname.test(
|
|
12667
|
+
if (!def.hostname.test(url2.hostname)) {
|
|
12167
12668
|
payload.issues.push({
|
|
12168
12669
|
code: "invalid_format",
|
|
12169
12670
|
format: "url",
|
|
@@ -12177,7 +12678,7 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
|
|
|
12177
12678
|
}
|
|
12178
12679
|
if (def.protocol) {
|
|
12179
12680
|
def.protocol.lastIndex = 0;
|
|
12180
|
-
if (!def.protocol.test(
|
|
12681
|
+
if (!def.protocol.test(url2.protocol.endsWith(":") ? url2.protocol.slice(0, -1) : url2.protocol)) {
|
|
12181
12682
|
payload.issues.push({
|
|
12182
12683
|
code: "invalid_format",
|
|
12183
12684
|
format: "url",
|
|
@@ -12190,7 +12691,7 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
|
|
|
12190
12691
|
}
|
|
12191
12692
|
}
|
|
12192
12693
|
if (def.normalize) {
|
|
12193
|
-
payload.value =
|
|
12694
|
+
payload.value = url2.href;
|
|
12194
12695
|
} else {
|
|
12195
12696
|
payload.value = trimmed;
|
|
12196
12697
|
}
|
|
@@ -12445,6 +12946,26 @@ var $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
|
|
|
12445
12946
|
return payload;
|
|
12446
12947
|
};
|
|
12447
12948
|
});
|
|
12949
|
+
var $ZodBigInt = /* @__PURE__ */ $constructor("$ZodBigInt", (inst, def) => {
|
|
12950
|
+
$ZodType.init(inst, def);
|
|
12951
|
+
inst._zod.pattern = bigint;
|
|
12952
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
12953
|
+
if (def.coerce)
|
|
12954
|
+
try {
|
|
12955
|
+
payload.value = BigInt(payload.value);
|
|
12956
|
+
} catch (_) {
|
|
12957
|
+
}
|
|
12958
|
+
if (typeof payload.value === "bigint")
|
|
12959
|
+
return payload;
|
|
12960
|
+
payload.issues.push({
|
|
12961
|
+
expected: "bigint",
|
|
12962
|
+
code: "invalid_type",
|
|
12963
|
+
input: payload.value,
|
|
12964
|
+
inst
|
|
12965
|
+
});
|
|
12966
|
+
return payload;
|
|
12967
|
+
};
|
|
12968
|
+
});
|
|
12448
12969
|
var $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
|
|
12449
12970
|
$ZodType.init(inst, def);
|
|
12450
12971
|
inst._zod.pattern = _null;
|
|
@@ -12462,6 +12983,10 @@ var $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
|
|
|
12462
12983
|
return payload;
|
|
12463
12984
|
};
|
|
12464
12985
|
});
|
|
12986
|
+
var $ZodAny = /* @__PURE__ */ $constructor("$ZodAny", (inst, def) => {
|
|
12987
|
+
$ZodType.init(inst, def);
|
|
12988
|
+
inst._zod.parse = (payload) => payload;
|
|
12989
|
+
});
|
|
12465
12990
|
var $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
|
|
12466
12991
|
$ZodType.init(inst, def);
|
|
12467
12992
|
inst._zod.parse = (payload) => payload;
|
|
@@ -12478,6 +13003,30 @@ var $ZodNever = /* @__PURE__ */ $constructor("$ZodNever", (inst, def) => {
|
|
|
12478
13003
|
return payload;
|
|
12479
13004
|
};
|
|
12480
13005
|
});
|
|
13006
|
+
var $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
|
|
13007
|
+
$ZodType.init(inst, def);
|
|
13008
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
13009
|
+
if (def.coerce) {
|
|
13010
|
+
try {
|
|
13011
|
+
payload.value = new Date(payload.value);
|
|
13012
|
+
} catch (_err) {
|
|
13013
|
+
}
|
|
13014
|
+
}
|
|
13015
|
+
const input = payload.value;
|
|
13016
|
+
const isDate = input instanceof Date;
|
|
13017
|
+
const isValidDate = isDate && !Number.isNaN(input.getTime());
|
|
13018
|
+
if (isValidDate)
|
|
13019
|
+
return payload;
|
|
13020
|
+
payload.issues.push({
|
|
13021
|
+
expected: "date",
|
|
13022
|
+
code: "invalid_type",
|
|
13023
|
+
input,
|
|
13024
|
+
...isDate ? { received: "Invalid Date" } : {},
|
|
13025
|
+
inst
|
|
13026
|
+
});
|
|
13027
|
+
return payload;
|
|
13028
|
+
};
|
|
13029
|
+
});
|
|
12481
13030
|
function handleArrayResult(result, final, index) {
|
|
12482
13031
|
if (result.issues.length) {
|
|
12483
13032
|
final.issues.push(...prefixIssues(index, result.issues));
|
|
@@ -13628,6 +14177,14 @@ function _string(Class2, params) {
|
|
|
13628
14177
|
});
|
|
13629
14178
|
}
|
|
13630
14179
|
// @__NO_SIDE_EFFECTS__
|
|
14180
|
+
function _coercedString(Class2, params) {
|
|
14181
|
+
return new Class2({
|
|
14182
|
+
type: "string",
|
|
14183
|
+
coerce: true,
|
|
14184
|
+
...normalizeParams(params)
|
|
14185
|
+
});
|
|
14186
|
+
}
|
|
14187
|
+
// @__NO_SIDE_EFFECTS__
|
|
13631
14188
|
function _email(Class2, params) {
|
|
13632
14189
|
return new Class2({
|
|
13633
14190
|
type: "string",
|
|
@@ -13899,6 +14456,15 @@ function _number(Class2, params) {
|
|
|
13899
14456
|
});
|
|
13900
14457
|
}
|
|
13901
14458
|
// @__NO_SIDE_EFFECTS__
|
|
14459
|
+
function _coercedNumber(Class2, params) {
|
|
14460
|
+
return new Class2({
|
|
14461
|
+
type: "number",
|
|
14462
|
+
coerce: true,
|
|
14463
|
+
checks: [],
|
|
14464
|
+
...normalizeParams(params)
|
|
14465
|
+
});
|
|
14466
|
+
}
|
|
14467
|
+
// @__NO_SIDE_EFFECTS__
|
|
13902
14468
|
function _int(Class2, params) {
|
|
13903
14469
|
return new Class2({
|
|
13904
14470
|
type: "number",
|
|
@@ -13916,6 +14482,22 @@ function _boolean(Class2, params) {
|
|
|
13916
14482
|
});
|
|
13917
14483
|
}
|
|
13918
14484
|
// @__NO_SIDE_EFFECTS__
|
|
14485
|
+
function _coercedBoolean(Class2, params) {
|
|
14486
|
+
return new Class2({
|
|
14487
|
+
type: "boolean",
|
|
14488
|
+
coerce: true,
|
|
14489
|
+
...normalizeParams(params)
|
|
14490
|
+
});
|
|
14491
|
+
}
|
|
14492
|
+
// @__NO_SIDE_EFFECTS__
|
|
14493
|
+
function _coercedBigint(Class2, params) {
|
|
14494
|
+
return new Class2({
|
|
14495
|
+
type: "bigint",
|
|
14496
|
+
coerce: true,
|
|
14497
|
+
...normalizeParams(params)
|
|
14498
|
+
});
|
|
14499
|
+
}
|
|
14500
|
+
// @__NO_SIDE_EFFECTS__
|
|
13919
14501
|
function _null2(Class2, params) {
|
|
13920
14502
|
return new Class2({
|
|
13921
14503
|
type: "null",
|
|
@@ -13923,6 +14505,12 @@ function _null2(Class2, params) {
|
|
|
13923
14505
|
});
|
|
13924
14506
|
}
|
|
13925
14507
|
// @__NO_SIDE_EFFECTS__
|
|
14508
|
+
function _any(Class2) {
|
|
14509
|
+
return new Class2({
|
|
14510
|
+
type: "any"
|
|
14511
|
+
});
|
|
14512
|
+
}
|
|
14513
|
+
// @__NO_SIDE_EFFECTS__
|
|
13926
14514
|
function _unknown(Class2) {
|
|
13927
14515
|
return new Class2({
|
|
13928
14516
|
type: "unknown"
|
|
@@ -13936,6 +14524,14 @@ function _never(Class2, params) {
|
|
|
13936
14524
|
});
|
|
13937
14525
|
}
|
|
13938
14526
|
// @__NO_SIDE_EFFECTS__
|
|
14527
|
+
function _coercedDate(Class2, params) {
|
|
14528
|
+
return new Class2({
|
|
14529
|
+
type: "date",
|
|
14530
|
+
coerce: true,
|
|
14531
|
+
...normalizeParams(params)
|
|
14532
|
+
});
|
|
14533
|
+
}
|
|
14534
|
+
// @__NO_SIDE_EFFECTS__
|
|
13939
14535
|
function _lt(value, params) {
|
|
13940
14536
|
return new $ZodCheckLessThan({
|
|
13941
14537
|
check: "less_than",
|
|
@@ -14583,6 +15179,11 @@ var numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
14583
15179
|
var booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
14584
15180
|
json.type = "boolean";
|
|
14585
15181
|
};
|
|
15182
|
+
var bigintProcessor = (_schema, ctx, _json, _params) => {
|
|
15183
|
+
if (ctx.unrepresentable === "throw") {
|
|
15184
|
+
throw new Error("BigInt cannot be represented in JSON Schema");
|
|
15185
|
+
}
|
|
15186
|
+
};
|
|
14586
15187
|
var nullProcessor = (_schema, ctx, json, _params) => {
|
|
14587
15188
|
if (ctx.target === "openapi-3.0") {
|
|
14588
15189
|
json.type = "string";
|
|
@@ -14595,8 +15196,15 @@ var nullProcessor = (_schema, ctx, json, _params) => {
|
|
|
14595
15196
|
var neverProcessor = (_schema, _ctx, json, _params) => {
|
|
14596
15197
|
json.not = {};
|
|
14597
15198
|
};
|
|
15199
|
+
var anyProcessor = (_schema, _ctx, _json, _params) => {
|
|
15200
|
+
};
|
|
14598
15201
|
var unknownProcessor = (_schema, _ctx, _json, _params) => {
|
|
14599
15202
|
};
|
|
15203
|
+
var dateProcessor = (_schema, ctx, _json, _params) => {
|
|
15204
|
+
if (ctx.unrepresentable === "throw") {
|
|
15205
|
+
throw new Error("Date cannot be represented in JSON Schema");
|
|
15206
|
+
}
|
|
15207
|
+
};
|
|
14600
15208
|
var enumProcessor = (schema, _ctx, json, _params) => {
|
|
14601
15209
|
const def = schema._zod.def;
|
|
14602
15210
|
const values = getEnumValues(def.entries);
|
|
@@ -15273,6 +15881,9 @@ var ZodURL = /* @__PURE__ */ $constructor("ZodURL", (inst, def) => {
|
|
|
15273
15881
|
$ZodURL.init(inst, def);
|
|
15274
15882
|
ZodStringFormat.init(inst, def);
|
|
15275
15883
|
});
|
|
15884
|
+
function url(params) {
|
|
15885
|
+
return _url(ZodURL, params);
|
|
15886
|
+
}
|
|
15276
15887
|
var ZodEmoji = /* @__PURE__ */ $constructor("ZodEmoji", (inst, def) => {
|
|
15277
15888
|
$ZodEmoji.init(inst, def);
|
|
15278
15889
|
ZodStringFormat.init(inst, def);
|
|
@@ -15409,6 +16020,28 @@ var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
|
|
|
15409
16020
|
function boolean2(params) {
|
|
15410
16021
|
return _boolean(ZodBoolean, params);
|
|
15411
16022
|
}
|
|
16023
|
+
var ZodBigInt = /* @__PURE__ */ $constructor("ZodBigInt", (inst, def) => {
|
|
16024
|
+
$ZodBigInt.init(inst, def);
|
|
16025
|
+
ZodType.init(inst, def);
|
|
16026
|
+
inst._zod.processJSONSchema = (ctx, json, params) => bigintProcessor(inst, ctx, json, params);
|
|
16027
|
+
inst.gte = (value, params) => inst.check(_gte(value, params));
|
|
16028
|
+
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
16029
|
+
inst.gt = (value, params) => inst.check(_gt(value, params));
|
|
16030
|
+
inst.gte = (value, params) => inst.check(_gte(value, params));
|
|
16031
|
+
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
16032
|
+
inst.lt = (value, params) => inst.check(_lt(value, params));
|
|
16033
|
+
inst.lte = (value, params) => inst.check(_lte(value, params));
|
|
16034
|
+
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
16035
|
+
inst.positive = (params) => inst.check(_gt(BigInt(0), params));
|
|
16036
|
+
inst.negative = (params) => inst.check(_lt(BigInt(0), params));
|
|
16037
|
+
inst.nonpositive = (params) => inst.check(_lte(BigInt(0), params));
|
|
16038
|
+
inst.nonnegative = (params) => inst.check(_gte(BigInt(0), params));
|
|
16039
|
+
inst.multipleOf = (value, params) => inst.check(_multipleOf(value, params));
|
|
16040
|
+
const bag = inst._zod.bag;
|
|
16041
|
+
inst.minValue = bag.minimum ?? null;
|
|
16042
|
+
inst.maxValue = bag.maximum ?? null;
|
|
16043
|
+
inst.format = bag.format ?? null;
|
|
16044
|
+
});
|
|
15412
16045
|
var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
|
|
15413
16046
|
$ZodNull.init(inst, def);
|
|
15414
16047
|
ZodType.init(inst, def);
|
|
@@ -15417,6 +16050,14 @@ var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
|
|
|
15417
16050
|
function _null3(params) {
|
|
15418
16051
|
return _null2(ZodNull, params);
|
|
15419
16052
|
}
|
|
16053
|
+
var ZodAny = /* @__PURE__ */ $constructor("ZodAny", (inst, def) => {
|
|
16054
|
+
$ZodAny.init(inst, def);
|
|
16055
|
+
ZodType.init(inst, def);
|
|
16056
|
+
inst._zod.processJSONSchema = (ctx, json, params) => anyProcessor(inst, ctx, json, params);
|
|
16057
|
+
});
|
|
16058
|
+
function any() {
|
|
16059
|
+
return _any(ZodAny);
|
|
16060
|
+
}
|
|
15420
16061
|
var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
|
|
15421
16062
|
$ZodUnknown.init(inst, def);
|
|
15422
16063
|
ZodType.init(inst, def);
|
|
@@ -15433,6 +16074,16 @@ var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => {
|
|
|
15433
16074
|
function never(params) {
|
|
15434
16075
|
return _never(ZodNever, params);
|
|
15435
16076
|
}
|
|
16077
|
+
var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
16078
|
+
$ZodDate.init(inst, def);
|
|
16079
|
+
ZodType.init(inst, def);
|
|
16080
|
+
inst._zod.processJSONSchema = (ctx, json, params) => dateProcessor(inst, ctx, json, params);
|
|
16081
|
+
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
16082
|
+
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
16083
|
+
const c = inst._zod.bag;
|
|
16084
|
+
inst.minDate = c.minimum ? new Date(c.minimum) : null;
|
|
16085
|
+
inst.maxDate = c.maximum ? new Date(c.maximum) : null;
|
|
16086
|
+
});
|
|
15436
16087
|
var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
|
|
15437
16088
|
$ZodArray.init(inst, def);
|
|
15438
16089
|
ZodType.init(inst, def);
|
|
@@ -15838,6 +16489,49 @@ function preprocess(fn, schema) {
|
|
|
15838
16489
|
});
|
|
15839
16490
|
}
|
|
15840
16491
|
|
|
16492
|
+
// node_modules/zod/v4/classic/compat.js
|
|
16493
|
+
var ZodIssueCode = {
|
|
16494
|
+
invalid_type: "invalid_type",
|
|
16495
|
+
too_big: "too_big",
|
|
16496
|
+
too_small: "too_small",
|
|
16497
|
+
invalid_format: "invalid_format",
|
|
16498
|
+
not_multiple_of: "not_multiple_of",
|
|
16499
|
+
unrecognized_keys: "unrecognized_keys",
|
|
16500
|
+
invalid_union: "invalid_union",
|
|
16501
|
+
invalid_key: "invalid_key",
|
|
16502
|
+
invalid_element: "invalid_element",
|
|
16503
|
+
invalid_value: "invalid_value",
|
|
16504
|
+
custom: "custom"
|
|
16505
|
+
};
|
|
16506
|
+
var ZodFirstPartyTypeKind;
|
|
16507
|
+
/* @__PURE__ */ (function(ZodFirstPartyTypeKind2) {
|
|
16508
|
+
})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
16509
|
+
|
|
16510
|
+
// node_modules/zod/v4/classic/coerce.js
|
|
16511
|
+
var coerce_exports = {};
|
|
16512
|
+
__export(coerce_exports, {
|
|
16513
|
+
bigint: () => bigint2,
|
|
16514
|
+
boolean: () => boolean3,
|
|
16515
|
+
date: () => date3,
|
|
16516
|
+
number: () => number3,
|
|
16517
|
+
string: () => string3
|
|
16518
|
+
});
|
|
16519
|
+
function string3(params) {
|
|
16520
|
+
return _coercedString(ZodString, params);
|
|
16521
|
+
}
|
|
16522
|
+
function number3(params) {
|
|
16523
|
+
return _coercedNumber(ZodNumber, params);
|
|
16524
|
+
}
|
|
16525
|
+
function boolean3(params) {
|
|
16526
|
+
return _coercedBoolean(ZodBoolean, params);
|
|
16527
|
+
}
|
|
16528
|
+
function bigint2(params) {
|
|
16529
|
+
return _coercedBigint(ZodBigInt, params);
|
|
16530
|
+
}
|
|
16531
|
+
function date3(params) {
|
|
16532
|
+
return _coercedDate(ZodDate, params);
|
|
16533
|
+
}
|
|
16534
|
+
|
|
15841
16535
|
// node_modules/zod/v4/classic/external.js
|
|
15842
16536
|
config(en_default());
|
|
15843
16537
|
|
|
@@ -16242,6 +16936,7 @@ var InitializedNotificationSchema = NotificationSchema.extend({
|
|
|
16242
16936
|
method: literal("notifications/initialized"),
|
|
16243
16937
|
params: NotificationsParamsSchema.optional()
|
|
16244
16938
|
});
|
|
16939
|
+
var isInitializedNotification = (value) => InitializedNotificationSchema.safeParse(value).success;
|
|
16245
16940
|
var PingRequestSchema = RequestSchema.extend({
|
|
16246
16941
|
method: literal("ping"),
|
|
16247
16942
|
params: BaseRequestParamsSchema.optional()
|
|
@@ -19142,12 +19837,12 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
19142
19837
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
19143
19838
|
|
|
19144
19839
|
// src/index.ts
|
|
19145
|
-
import
|
|
19840
|
+
import crypto2 from "crypto";
|
|
19146
19841
|
import http from "http";
|
|
19147
|
-
import
|
|
19148
|
-
import
|
|
19842
|
+
import fs3 from "fs";
|
|
19843
|
+
import path3 from "path";
|
|
19149
19844
|
import { execFileSync } from "child_process";
|
|
19150
|
-
import
|
|
19845
|
+
import os2 from "os";
|
|
19151
19846
|
import { fileURLToPath } from "url";
|
|
19152
19847
|
|
|
19153
19848
|
// ../api/_lib/mcp-tools.ts
|
|
@@ -19163,6 +19858,11 @@ var HIDE_CLIP_IDS = {
|
|
|
19163
19858
|
items: { type: "string" },
|
|
19164
19859
|
description: "Render as if these clips were not there. The timeline is not changed."
|
|
19165
19860
|
};
|
|
19861
|
+
var TEXT_BOX_PROPS = {
|
|
19862
|
+
wrapWidth: num("Widest a line may run before it wraps, as a fraction of the frame width (0.05\u20131). Defaults to about 0.86. Set it to keep body copy inside a column or a card."),
|
|
19863
|
+
anchorX: num("Which point of the text block posX places: 0 its left edge, 0.5 its centre (default), 1 its right edge. Use 0 for left-aligned text so its left edge stays put when the words change."),
|
|
19864
|
+
anchorY: num("Which point of the text block posY places: 0 its top, 0.5 its middle (default), 1 its bottom.")
|
|
19865
|
+
};
|
|
19166
19866
|
var TEXT_STYLE_PROPS = {
|
|
19167
19867
|
fontSize: num("Font size in pixels, authored against a 1080p-tall frame."),
|
|
19168
19868
|
fontFamily: str("Font family name."),
|
|
@@ -19190,6 +19890,8 @@ var TEXT_STYLE_PROPS = {
|
|
|
19190
19890
|
textAccentColor: str("Colour for accent words. Mark an accent word in the text as *word*."),
|
|
19191
19891
|
textAccentFontFamily: str(`Font for accent words, e.g. "'Great Vibes', cursive" for a script word inside heavy caps.`),
|
|
19192
19892
|
textAccentScale: num("Size of accent words relative to the rest, e.g. 1.8."),
|
|
19893
|
+
textAccentFontWeight: { type: ["number", "string"], description: `Weight of accent words, 100\u2013900, "normal" or "bold". Default: bold with an accent font, else the text's own weight.` },
|
|
19894
|
+
textAccentFontStyle: { type: "string", enum: ["normal", "italic"], description: "Slant of accent words. Default: italic with an accent font, else the text's own style." },
|
|
19193
19895
|
textAccentGradientStart: str("Gradient start colour for accent words."),
|
|
19194
19896
|
textAccentGradientEnd: str("Gradient end colour for accent words."),
|
|
19195
19897
|
textSwooshUnderline: bool("Hand-drawn swoosh under the last line."),
|
|
@@ -19235,7 +19937,8 @@ var BASE_TOOLS = [
|
|
|
19235
19937
|
mediaFileId: str("Media bin file id. Omit to list every source that has a transcript."),
|
|
19236
19938
|
startTime: num("Only return segments overlapping at or after this source time, in seconds."),
|
|
19237
19939
|
endTime: num("Only return segments overlapping before this source time, in seconds."),
|
|
19238
|
-
includeWords: bool("Include per-word timings. Defaults to true; set false for a much smaller payload.")
|
|
19940
|
+
includeWords: bool("Include per-word timings. Defaults to true; set false for a much smaller payload."),
|
|
19941
|
+
onTimeline: bool("Return the words as they fall on the open sequence, through every cut and trim, in timeline seconds \u2014 what to time captions and shots against after the footage is edited. mediaFileId and the time range are ignored.")
|
|
19239
19942
|
}
|
|
19240
19943
|
},
|
|
19241
19944
|
method: "getTranscript"
|
|
@@ -19358,6 +20061,18 @@ var BASE_TOOLS = [
|
|
|
19358
20061
|
inputSchema: { type: "object", properties: {} },
|
|
19359
20062
|
method: "listSequences"
|
|
19360
20063
|
},
|
|
20064
|
+
{
|
|
20065
|
+
name: "export_design",
|
|
20066
|
+
description: "A sequence as design JSON \u2014 the format the Designs panel saves and inserts, with every sequence nested in it. Text, HTML and shape layers travel whole; media files are listed under files and not included. Read-only.",
|
|
20067
|
+
inputSchema: {
|
|
20068
|
+
type: "object",
|
|
20069
|
+
properties: {
|
|
20070
|
+
sequenceId: str("The sequence to export. Default: the open one."),
|
|
20071
|
+
name: str("Name to give the design. Default: the sequence name.")
|
|
20072
|
+
}
|
|
20073
|
+
},
|
|
20074
|
+
method: "exportDesign"
|
|
20075
|
+
},
|
|
19361
20076
|
{
|
|
19362
20077
|
name: "create_sequence",
|
|
19363
20078
|
description: "Make a new, empty sequence. It takes the project's frame size and rate unless width, height or fps say otherwise, and can be given a fixed length. By default it opens, so the edits that follow build it; pass open: false to stay where you are and place it later with add_sequence_clip. Returns its id.",
|
|
@@ -19572,7 +20287,8 @@ var BASE_TOOLS = [
|
|
|
19572
20287
|
duration: num("How long the card stays on screen, in seconds."),
|
|
19573
20288
|
startTime: num("Where it starts on the timeline, in seconds. Defaults to 0."),
|
|
19574
20289
|
trackId: str("Target video track. Defaults to the topmost one that is free across the card\u2019s span, creating a new track above everything if none is free."),
|
|
19575
|
-
...TEXT_STYLE_PROPS
|
|
20290
|
+
...TEXT_STYLE_PROPS,
|
|
20291
|
+
...TEXT_BOX_PROPS
|
|
19576
20292
|
},
|
|
19577
20293
|
required: ["text", "duration"]
|
|
19578
20294
|
},
|
|
@@ -19586,7 +20302,8 @@ var BASE_TOOLS = [
|
|
|
19586
20302
|
properties: {
|
|
19587
20303
|
clipId: CLIP_ID,
|
|
19588
20304
|
text: str("New text. Omit to change only the styling."),
|
|
19589
|
-
...TEXT_STYLE_PROPS
|
|
20305
|
+
...TEXT_STYLE_PROPS,
|
|
20306
|
+
...TEXT_BOX_PROPS
|
|
19590
20307
|
},
|
|
19591
20308
|
required: ["clipId"]
|
|
19592
20309
|
},
|
|
@@ -20855,7 +21572,135 @@ var BASE_TOOLS = [
|
|
|
20855
21572
|
description: "Re-apply the last undone edit.",
|
|
20856
21573
|
inputSchema: { type: "object", properties: {} },
|
|
20857
21574
|
method: "redo"
|
|
20858
|
-
}
|
|
21575
|
+
},
|
|
21576
|
+
{
|
|
21577
|
+
name: "studio_tasks",
|
|
21578
|
+
description: 'The work GoatEdit Studio has for you in this project. Studio makes a video in stages (brief, research, script, breakdown (the script cut into parts), moodboard, styleGuide (the design language every part follows), storyboard, edit plan, combine (the parts joined into the final edit plan), timeline, mix, QC, export, plus any the user added, whose ids start "x-" and whose document is {"notes": string, "points"?: string[]}); a stage opens once the stages it reads are approved, so several are often open at once. Each task is kind "write" (write that stage\'s JSON document: follow `role` as your system prompt, read `inputs`, follow `lessons` when present (what this user has asked for before), and if `previousDraft` is there, revise it using `note` and `problems`) or kind "run" (ask the tab to do it with studio_run_stage). Open tasks in one run do not depend on each other: hand each to its own subagent and do them side by side. When a task names an `agent`, the user wants that subagent or skill of yours on it: hand the task to the subagent with that name, or use the skill with that name. In a batch of reels each run has `batch` (reel number, name, avatar); stages listed in batch.filled are filled by Studio itself (the locked script, the pilot\'s look), so leave them. For each write task: studio_claim it first (the person sees your agent working on that stage), then studio_submit the document. The reply to a submit names the stages it opened; call studio_tasks again for them. Stages waiting for the person are listed under waitingForPerson \u2014 stop there and tell the user to approve them in the Studio panel.',
|
|
21579
|
+
inputSchema: {
|
|
21580
|
+
type: "object",
|
|
21581
|
+
properties: {
|
|
21582
|
+
runId: str("Only this run. Omit for every run in the project."),
|
|
21583
|
+
detail: bool("Include each write task's role, inputs and previous draft (default true). False lists the tasks only.")
|
|
21584
|
+
}
|
|
21585
|
+
},
|
|
21586
|
+
method: "getStudioTasks"
|
|
21587
|
+
},
|
|
21588
|
+
{
|
|
21589
|
+
name: "studio_claim",
|
|
21590
|
+
description: 'Take a Studio write task before working on it, so the Studio panel shows your agent on that stage and nobody else starts it. agent names who is doing it as the person will see it ("Claude Code \u2014 script writer"). Claiming a task you already hold is fine; one someone else holds is refused.',
|
|
21591
|
+
inputSchema: {
|
|
21592
|
+
type: "object",
|
|
21593
|
+
properties: {
|
|
21594
|
+
runId: str("The run, from studio_tasks."),
|
|
21595
|
+
stage: str('The stage id, from studio_tasks (e.g. "script").'),
|
|
21596
|
+
agent: str("Who is doing it, shown in the panel.")
|
|
21597
|
+
},
|
|
21598
|
+
required: ["runId", "stage", "agent"]
|
|
21599
|
+
},
|
|
21600
|
+
method: "studioClaim"
|
|
21601
|
+
},
|
|
21602
|
+
{
|
|
21603
|
+
name: "studio_submit",
|
|
21604
|
+
description: "Hand in the document for a Studio stage you claimed. It goes through the same checks as Studio's own agents: if it fails them the reply lists the problems and the task stays yours to fix and submit again; if it passes it waits for the person, or passes on its own when the workflow says so. The reply names the stages that opened because of it.",
|
|
21605
|
+
inputSchema: {
|
|
21606
|
+
type: "object",
|
|
21607
|
+
properties: {
|
|
21608
|
+
runId: str("The run, from studio_tasks."),
|
|
21609
|
+
stage: str("The stage id."),
|
|
21610
|
+
document: { type: "object", description: "The stage's document, in the shape its role card gives." },
|
|
21611
|
+
agent: str("Who wrote it, as in studio_claim.")
|
|
21612
|
+
},
|
|
21613
|
+
required: ["runId", "stage", "document"]
|
|
21614
|
+
},
|
|
21615
|
+
method: "studioSubmit"
|
|
21616
|
+
},
|
|
21617
|
+
{
|
|
21618
|
+
name: "studio_run_stage",
|
|
21619
|
+
description: `Start a Studio stage the tab does itself: "timeline" (build the edit from the approved plan) or "qc" (check it), or a stage the workflow gives to Studio's agent in the tab. Returns at once; the work goes on in the tab and the panel shows it. Poll studio_tasks to see it finish.`,
|
|
21620
|
+
inputSchema: {
|
|
21621
|
+
type: "object",
|
|
21622
|
+
properties: {
|
|
21623
|
+
runId: str("The run, from studio_tasks."),
|
|
21624
|
+
stage: str("The stage id.")
|
|
21625
|
+
},
|
|
21626
|
+
required: ["runId", "stage"]
|
|
21627
|
+
},
|
|
21628
|
+
method: "studioRunStage"
|
|
21629
|
+
},
|
|
21630
|
+
{
|
|
21631
|
+
name: "studio_start_run",
|
|
21632
|
+
description: `Start a new Studio run in this project, for a video the user asked you to make with Studio. workflow "outside" gives every writing stage to you (the brief first); the person still approves the brief, script, storyboard and export in the Studio panel, and on any workflow the brief, the look (moodboard, styleGuide) and the export. Refused when it would push an unfinished run out of the project's Studio history. Then call studio_tasks.`,
|
|
21633
|
+
inputSchema: {
|
|
21634
|
+
type: "object",
|
|
21635
|
+
properties: {
|
|
21636
|
+
title: str("What the video is, in a few words."),
|
|
21637
|
+
workflow: str('A workflow id or name from the Studio panel: "outside" (default), "guided", "autopilot", "hands-on", or one the user saved.')
|
|
21638
|
+
},
|
|
21639
|
+
required: ["title"]
|
|
21640
|
+
},
|
|
21641
|
+
method: "studioStartRun"
|
|
21642
|
+
},
|
|
21643
|
+
{
|
|
21644
|
+
name: "studio_workflows",
|
|
21645
|
+
description: `The Studio workflows the user has (built-in and saved), and one of them stage by stage: what each stage holds, which stages it waits for, who writes it ("agent" = Studio's agent in the tab on the user's key, "outside" = you over MCP, "manual" = the person, "tab" = the tab builds it), who approves it, and the agent of yours named for it. Read this before studio_save_workflow.`,
|
|
21646
|
+
inputSchema: {
|
|
21647
|
+
type: "object",
|
|
21648
|
+
properties: {
|
|
21649
|
+
workflow: str('A workflow id or name to see stage by stage. Omit for the list, with the "outside" workflow in full.')
|
|
21650
|
+
}
|
|
21651
|
+
},
|
|
21652
|
+
method: "studioWorkflows"
|
|
21653
|
+
},
|
|
21654
|
+
{
|
|
21655
|
+
name: "studio_save_workflow",
|
|
21656
|
+
description: `Set Studio up for the user's way of working: save a workflow that says, stage by stage, who writes it and who approves it, and names your own subagent or skill for the stages you write. Only the name is kept: your agents, skills and their files stay with you and are never sent to GoatEdit. When a stage's task comes up, studio_tasks names the agent and you hand it over. Starts from another workflow (default "outside": you write every writing stage) and changes only what you give. Stages of your own (an avatar check, a sound pass) go under add; each writes {"notes", "points"} for the stages it feeds. The brief, moodboard, design language (styleGuide) and export always stay approved by the person. The same name replaces a workflow you saved earlier, never one the person made (yours is then saved under another name). The person sees it in the Studio panel and can change it there.`,
|
|
21657
|
+
inputSchema: {
|
|
21658
|
+
type: "object",
|
|
21659
|
+
properties: {
|
|
21660
|
+
workflow: {
|
|
21661
|
+
type: "object",
|
|
21662
|
+
description: "The workflow.",
|
|
21663
|
+
properties: {
|
|
21664
|
+
name: str('What the person will see, e.g. "Avatar reels".'),
|
|
21665
|
+
from: str('The workflow to start from, by id or name (default "outside").'),
|
|
21666
|
+
stages: {
|
|
21667
|
+
type: "object",
|
|
21668
|
+
description: 'Stage id (from studio_workflows) to its settings: { enabled?, writer?: "agent" | "outside" | "manual", approver?: "person" | "auto", agent?: your subagent or skill for it (implies writer "outside"), instructions?, tier?: "fast" | "writer" | "strong", review? }. Only optional stages can be turned off.',
|
|
21669
|
+
additionalProperties: { type: "object" }
|
|
21670
|
+
},
|
|
21671
|
+
add: {
|
|
21672
|
+
type: "array",
|
|
21673
|
+
description: 'Stages of your own: { label, brief? (what it does), agent?, after? (stage id it waits for, default "brief"), feeds? (stage ids that wait for it), writer?, approver? }.',
|
|
21674
|
+
items: { type: "object" }
|
|
21675
|
+
}
|
|
21676
|
+
},
|
|
21677
|
+
required: ["name"]
|
|
21678
|
+
}
|
|
21679
|
+
},
|
|
21680
|
+
required: ["workflow"]
|
|
21681
|
+
},
|
|
21682
|
+
method: "studioSaveWorkflow"
|
|
21683
|
+
},
|
|
21684
|
+
{
|
|
21685
|
+
name: "studio_start_batch",
|
|
21686
|
+
description: `Start a batch of reels: finished scripts (up to 20), one run and one sequence each, going side by side as one series. Reel 1 is the pilot: it designs the series look (moodboard, design language), the person approves it, and every other reel takes it. Each script is final: once its brief is approved Studio cuts it into beats word for word, so do not rewrite it. The person approves the pilot's brief, the look and each export, whatever the workflow says. Refused when it would push unfinished runs out of the project's Studio history (it keeps 60 batch reels). Give reels, or text the person pasted (blocks split by "---" with Name: and Avatar: lines at the top, or a CSV with name, avatar and script columns). Then call studio_tasks.`,
|
|
21687
|
+
inputSchema: {
|
|
21688
|
+
type: "object",
|
|
21689
|
+
properties: {
|
|
21690
|
+
title: str('The series name, e.g. "Health tips".'),
|
|
21691
|
+
series: str("The series: brand, audience, tone, platform. Every reel's brief is written from it."),
|
|
21692
|
+
reels: {
|
|
21693
|
+
type: "array",
|
|
21694
|
+
description: "One per reel: { name, script (word for word), avatar? (the HeyGen avatar that speaks it) }.",
|
|
21695
|
+
items: { type: "object" }
|
|
21696
|
+
},
|
|
21697
|
+
text: str("Instead of reels: the scripts as the person pasted them."),
|
|
21698
|
+
workflow: str('A workflow id or name (default "outside"); studio_save_workflow makes one.')
|
|
21699
|
+
},
|
|
21700
|
+
required: ["title"]
|
|
21701
|
+
},
|
|
21702
|
+
method: "studioStartBatch"
|
|
21703
|
+
}
|
|
20859
21704
|
];
|
|
20860
21705
|
var SEQUENCE_EDITS = /* @__PURE__ */ new Set([
|
|
20861
21706
|
"addClip",
|
|
@@ -20982,122 +21827,2563 @@ function typeError(key, schema, value) {
|
|
|
20982
21827
|
if (schema.enum && !schema.enum.includes(value)) {
|
|
20983
21828
|
return `Argument "${key}" must be one of: ${schema.enum.join(", ")}`;
|
|
20984
21829
|
}
|
|
20985
|
-
return null;
|
|
20986
|
-
}
|
|
20987
|
-
function validateArgs(tool, args) {
|
|
20988
|
-
for (const key of tool.inputSchema.required ?? []) {
|
|
20989
|
-
if (args[key] === void 0 || args[key] === null) return `Missing required argument: ${key}`;
|
|
21830
|
+
return null;
|
|
21831
|
+
}
|
|
21832
|
+
function validateArgs(tool, args) {
|
|
21833
|
+
for (const key of tool.inputSchema.required ?? []) {
|
|
21834
|
+
if (args[key] === void 0 || args[key] === null) return `Missing required argument: ${key}`;
|
|
21835
|
+
}
|
|
21836
|
+
const known = Object.keys(tool.inputSchema.properties);
|
|
21837
|
+
for (const [key, value] of Object.entries(args)) {
|
|
21838
|
+
if (value === void 0) continue;
|
|
21839
|
+
const schema = tool.inputSchema.properties[key];
|
|
21840
|
+
if (!schema) {
|
|
21841
|
+
const near = known.map((candidate) => ({ candidate, distance: editDistance(key.toLowerCase(), candidate.toLowerCase()) })).filter(({ candidate, distance }) => distance <= (candidate.length <= 4 ? 1 : 2)).sort((a, b) => a.distance - b.distance)[0];
|
|
21842
|
+
return near ? `Unknown argument "${key}" for ${tool.name}. Did you mean "${near.candidate}"?` : `Unknown argument "${key}" for ${tool.name}. Accepted: ${known.join(", ") || "(none)"}`;
|
|
21843
|
+
}
|
|
21844
|
+
if (value === null) continue;
|
|
21845
|
+
const problem = typeError(key, schema, value);
|
|
21846
|
+
if (problem) return problem;
|
|
21847
|
+
}
|
|
21848
|
+
return null;
|
|
21849
|
+
}
|
|
21850
|
+
|
|
21851
|
+
// ../api/_lib/mcp-content.ts
|
|
21852
|
+
var isImage = (v) => !!v && typeof v === "object" && typeof v.data === "string" && typeof v.mimeType === "string";
|
|
21853
|
+
function toContent(result) {
|
|
21854
|
+
if (!result || typeof result !== "object") {
|
|
21855
|
+
return [{ type: "text", text: JSON.stringify(result) ?? "null" }];
|
|
21856
|
+
}
|
|
21857
|
+
const { _image, _images, _file: _file2, ...rest } = result;
|
|
21858
|
+
if (_file2) rest.fileNote = "A file was made but this connection cannot deliver it. Use the local GoatEdit MCP server, which saves it to disk.";
|
|
21859
|
+
const blocks = [];
|
|
21860
|
+
const captions = [];
|
|
21861
|
+
for (const candidate of [_image, ...Array.isArray(_images) ? _images : []]) {
|
|
21862
|
+
if (!isImage(candidate)) continue;
|
|
21863
|
+
blocks.push({ type: "image", data: candidate.data, mimeType: candidate.mimeType });
|
|
21864
|
+
if (typeof candidate.caption === "string") captions.push(candidate.caption);
|
|
21865
|
+
}
|
|
21866
|
+
const text = captions.length ? JSON.stringify({ ...rest, frameCaptions: captions }) : JSON.stringify(Array.isArray(result) ? result : rest);
|
|
21867
|
+
blocks.push({ type: "text", text });
|
|
21868
|
+
return blocks;
|
|
21869
|
+
}
|
|
21870
|
+
|
|
21871
|
+
// src/find-local-file.ts
|
|
21872
|
+
import fs from "fs";
|
|
21873
|
+
import path from "path";
|
|
21874
|
+
function findLocalFile(root, wanted, maxDepth) {
|
|
21875
|
+
const name = wanted.trim();
|
|
21876
|
+
if (!name || !fs.existsSync(root)) return null;
|
|
21877
|
+
if (name.includes("/") || name.includes(path.sep)) {
|
|
21878
|
+
const full = path.resolve(root, name);
|
|
21879
|
+
if (!full.startsWith(root + path.sep)) return null;
|
|
21880
|
+
try {
|
|
21881
|
+
return fs.statSync(full).isFile() ? full : null;
|
|
21882
|
+
} catch {
|
|
21883
|
+
return null;
|
|
21884
|
+
}
|
|
21885
|
+
}
|
|
21886
|
+
const target = name.toLowerCase();
|
|
21887
|
+
let level = [root];
|
|
21888
|
+
for (let depth = 0; depth <= maxDepth && level.length; depth++) {
|
|
21889
|
+
const hits = [];
|
|
21890
|
+
const next = [];
|
|
21891
|
+
for (const dir of level) {
|
|
21892
|
+
let entries;
|
|
21893
|
+
try {
|
|
21894
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
21895
|
+
} catch {
|
|
21896
|
+
continue;
|
|
21897
|
+
}
|
|
21898
|
+
for (const entry of entries) {
|
|
21899
|
+
if (entry.name.startsWith(".")) continue;
|
|
21900
|
+
const full = path.join(dir, entry.name);
|
|
21901
|
+
if (entry.isDirectory()) next.push(full);
|
|
21902
|
+
else if (entry.isFile() && entry.name.toLowerCase() === target) hits.push(full);
|
|
21903
|
+
}
|
|
21904
|
+
}
|
|
21905
|
+
if (hits.length > 1) {
|
|
21906
|
+
throw new Error(
|
|
21907
|
+
`Several files are named "${name}": ${hits.map((h) => path.relative(root, h)).sort().join(", ")}. Pass one of these paths as filename.`
|
|
21908
|
+
);
|
|
21909
|
+
}
|
|
21910
|
+
if (hits.length === 1) return hits[0];
|
|
21911
|
+
level = next;
|
|
21912
|
+
}
|
|
21913
|
+
return null;
|
|
21914
|
+
}
|
|
21915
|
+
|
|
21916
|
+
// src/run-refs.ts
|
|
21917
|
+
function resolveRefs(value, refs) {
|
|
21918
|
+
if (typeof value === "string") {
|
|
21919
|
+
const m = /^\$([A-Za-z_][\w-]*)((?:\.[^.]+)*)$/.exec(value);
|
|
21920
|
+
if (!m || !refs.has(m[1])) return value;
|
|
21921
|
+
let x = refs.get(m[1]);
|
|
21922
|
+
for (const key of m[2].split(".").slice(1)) {
|
|
21923
|
+
x = x && typeof x === "object" ? x[key] : void 0;
|
|
21924
|
+
if (x === void 0) throw new Error(`${value}: step "${m[1]}" has no "${m[2].slice(1)}". It returned ${JSON.stringify(refs.get(m[1])).slice(0, 300)}`);
|
|
21925
|
+
}
|
|
21926
|
+
return x;
|
|
21927
|
+
}
|
|
21928
|
+
if (Array.isArray(value)) return value.map((v) => resolveRefs(v, refs));
|
|
21929
|
+
if (value && typeof value === "object") {
|
|
21930
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, resolveRefs(v, refs)]));
|
|
21931
|
+
}
|
|
21932
|
+
return value;
|
|
21933
|
+
}
|
|
21934
|
+
function withRunProject(stepArgs, projectId) {
|
|
21935
|
+
if (typeof projectId !== "string" || !projectId || typeof stepArgs.projectId === "string") return stepArgs;
|
|
21936
|
+
return { ...stepArgs, projectId };
|
|
21937
|
+
}
|
|
21938
|
+
|
|
21939
|
+
// src/tab-registry.ts
|
|
21940
|
+
function indexTabs(reports, isOpen) {
|
|
21941
|
+
const index = /* @__PURE__ */ new Map();
|
|
21942
|
+
for (const r of [...reports].sort((a, b) => a.at - b.at)) {
|
|
21943
|
+
if (isOpen(r.socket)) index.set(r.projectId, r);
|
|
21944
|
+
}
|
|
21945
|
+
return index;
|
|
21946
|
+
}
|
|
21947
|
+
|
|
21948
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
|
|
21949
|
+
var ExperimentalClientTasks = class {
|
|
21950
|
+
constructor(_client) {
|
|
21951
|
+
this._client = _client;
|
|
21952
|
+
}
|
|
21953
|
+
/**
|
|
21954
|
+
* Calls a tool and returns an AsyncGenerator that yields response messages.
|
|
21955
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
21956
|
+
*
|
|
21957
|
+
* This method provides streaming access to tool execution, allowing you to
|
|
21958
|
+
* observe intermediate task status updates for long-running tool calls.
|
|
21959
|
+
* Automatically validates structured output if the tool has an outputSchema.
|
|
21960
|
+
*
|
|
21961
|
+
* @example
|
|
21962
|
+
* ```typescript
|
|
21963
|
+
* const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
|
|
21964
|
+
* for await (const message of stream) {
|
|
21965
|
+
* switch (message.type) {
|
|
21966
|
+
* case 'taskCreated':
|
|
21967
|
+
* console.log('Tool execution started:', message.task.taskId);
|
|
21968
|
+
* break;
|
|
21969
|
+
* case 'taskStatus':
|
|
21970
|
+
* console.log('Tool status:', message.task.status);
|
|
21971
|
+
* break;
|
|
21972
|
+
* case 'result':
|
|
21973
|
+
* console.log('Tool result:', message.result);
|
|
21974
|
+
* break;
|
|
21975
|
+
* case 'error':
|
|
21976
|
+
* console.error('Tool error:', message.error);
|
|
21977
|
+
* break;
|
|
21978
|
+
* }
|
|
21979
|
+
* }
|
|
21980
|
+
* ```
|
|
21981
|
+
*
|
|
21982
|
+
* @param params - Tool call parameters (name and arguments)
|
|
21983
|
+
* @param resultSchema - Zod schema for validating the result (defaults to CallToolResultSchema)
|
|
21984
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
21985
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
21986
|
+
*
|
|
21987
|
+
* @experimental
|
|
21988
|
+
*/
|
|
21989
|
+
async *callToolStream(params, resultSchema = CallToolResultSchema, options) {
|
|
21990
|
+
const clientInternal = this._client;
|
|
21991
|
+
const optionsWithTask = {
|
|
21992
|
+
...options,
|
|
21993
|
+
// We check if the tool is known to be a task during auto-configuration, but assume
|
|
21994
|
+
// the caller knows what they're doing if they pass this explicitly
|
|
21995
|
+
task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : void 0)
|
|
21996
|
+
};
|
|
21997
|
+
const stream = clientInternal.requestStream({ method: "tools/call", params }, resultSchema, optionsWithTask);
|
|
21998
|
+
const validator = clientInternal.getToolOutputValidator(params.name);
|
|
21999
|
+
for await (const message of stream) {
|
|
22000
|
+
if (message.type === "result" && validator) {
|
|
22001
|
+
const result = message.result;
|
|
22002
|
+
if (!result.structuredContent && !result.isError) {
|
|
22003
|
+
yield {
|
|
22004
|
+
type: "error",
|
|
22005
|
+
error: new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`)
|
|
22006
|
+
};
|
|
22007
|
+
return;
|
|
22008
|
+
}
|
|
22009
|
+
if (result.structuredContent) {
|
|
22010
|
+
try {
|
|
22011
|
+
const validationResult = validator(result.structuredContent);
|
|
22012
|
+
if (!validationResult.valid) {
|
|
22013
|
+
yield {
|
|
22014
|
+
type: "error",
|
|
22015
|
+
error: new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`)
|
|
22016
|
+
};
|
|
22017
|
+
return;
|
|
22018
|
+
}
|
|
22019
|
+
} catch (error2) {
|
|
22020
|
+
if (error2 instanceof McpError) {
|
|
22021
|
+
yield { type: "error", error: error2 };
|
|
22022
|
+
return;
|
|
22023
|
+
}
|
|
22024
|
+
yield {
|
|
22025
|
+
type: "error",
|
|
22026
|
+
error: new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error2 instanceof Error ? error2.message : String(error2)}`)
|
|
22027
|
+
};
|
|
22028
|
+
return;
|
|
22029
|
+
}
|
|
22030
|
+
}
|
|
22031
|
+
}
|
|
22032
|
+
yield message;
|
|
22033
|
+
}
|
|
22034
|
+
}
|
|
22035
|
+
/**
|
|
22036
|
+
* Gets the current status of a task.
|
|
22037
|
+
*
|
|
22038
|
+
* @param taskId - The task identifier
|
|
22039
|
+
* @param options - Optional request options
|
|
22040
|
+
* @returns The task status
|
|
22041
|
+
*
|
|
22042
|
+
* @experimental
|
|
22043
|
+
*/
|
|
22044
|
+
async getTask(taskId, options) {
|
|
22045
|
+
return this._client.getTask({ taskId }, options);
|
|
22046
|
+
}
|
|
22047
|
+
/**
|
|
22048
|
+
* Retrieves the result of a completed task.
|
|
22049
|
+
*
|
|
22050
|
+
* @param taskId - The task identifier
|
|
22051
|
+
* @param resultSchema - Zod schema for validating the result
|
|
22052
|
+
* @param options - Optional request options
|
|
22053
|
+
* @returns The task result
|
|
22054
|
+
*
|
|
22055
|
+
* @experimental
|
|
22056
|
+
*/
|
|
22057
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
22058
|
+
return this._client.getTaskResult({ taskId }, resultSchema, options);
|
|
22059
|
+
}
|
|
22060
|
+
/**
|
|
22061
|
+
* Lists tasks with optional pagination.
|
|
22062
|
+
*
|
|
22063
|
+
* @param cursor - Optional pagination cursor
|
|
22064
|
+
* @param options - Optional request options
|
|
22065
|
+
* @returns List of tasks with optional next cursor
|
|
22066
|
+
*
|
|
22067
|
+
* @experimental
|
|
22068
|
+
*/
|
|
22069
|
+
async listTasks(cursor, options) {
|
|
22070
|
+
return this._client.listTasks(cursor ? { cursor } : void 0, options);
|
|
22071
|
+
}
|
|
22072
|
+
/**
|
|
22073
|
+
* Cancels a running task.
|
|
22074
|
+
*
|
|
22075
|
+
* @param taskId - The task identifier
|
|
22076
|
+
* @param options - Optional request options
|
|
22077
|
+
*
|
|
22078
|
+
* @experimental
|
|
22079
|
+
*/
|
|
22080
|
+
async cancelTask(taskId, options) {
|
|
22081
|
+
return this._client.cancelTask({ taskId }, options);
|
|
22082
|
+
}
|
|
22083
|
+
/**
|
|
22084
|
+
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
22085
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
22086
|
+
*
|
|
22087
|
+
* This method provides streaming access to request processing, allowing you to
|
|
22088
|
+
* observe intermediate task status updates for task-augmented requests.
|
|
22089
|
+
*
|
|
22090
|
+
* @param request - The request to send
|
|
22091
|
+
* @param resultSchema - Zod schema for validating the result
|
|
22092
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
22093
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
22094
|
+
*
|
|
22095
|
+
* @experimental
|
|
22096
|
+
*/
|
|
22097
|
+
requestStream(request, resultSchema, options) {
|
|
22098
|
+
return this._client.requestStream(request, resultSchema, options);
|
|
22099
|
+
}
|
|
22100
|
+
};
|
|
22101
|
+
|
|
22102
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
|
|
22103
|
+
function applyElicitationDefaults(schema, data) {
|
|
22104
|
+
if (!schema || data === null || typeof data !== "object")
|
|
22105
|
+
return;
|
|
22106
|
+
if (schema.type === "object" && schema.properties && typeof schema.properties === "object") {
|
|
22107
|
+
const obj = data;
|
|
22108
|
+
const props = schema.properties;
|
|
22109
|
+
for (const key of Object.keys(props)) {
|
|
22110
|
+
const propSchema = props[key];
|
|
22111
|
+
if (obj[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) {
|
|
22112
|
+
obj[key] = propSchema.default;
|
|
22113
|
+
}
|
|
22114
|
+
if (obj[key] !== void 0) {
|
|
22115
|
+
applyElicitationDefaults(propSchema, obj[key]);
|
|
22116
|
+
}
|
|
22117
|
+
}
|
|
22118
|
+
}
|
|
22119
|
+
if (Array.isArray(schema.anyOf)) {
|
|
22120
|
+
for (const sub of schema.anyOf) {
|
|
22121
|
+
if (typeof sub !== "boolean") {
|
|
22122
|
+
applyElicitationDefaults(sub, data);
|
|
22123
|
+
}
|
|
22124
|
+
}
|
|
22125
|
+
}
|
|
22126
|
+
if (Array.isArray(schema.oneOf)) {
|
|
22127
|
+
for (const sub of schema.oneOf) {
|
|
22128
|
+
if (typeof sub !== "boolean") {
|
|
22129
|
+
applyElicitationDefaults(sub, data);
|
|
22130
|
+
}
|
|
22131
|
+
}
|
|
22132
|
+
}
|
|
22133
|
+
}
|
|
22134
|
+
function getSupportedElicitationModes(capabilities) {
|
|
22135
|
+
if (!capabilities) {
|
|
22136
|
+
return { supportsFormMode: false, supportsUrlMode: false };
|
|
22137
|
+
}
|
|
22138
|
+
const hasFormCapability = capabilities.form !== void 0;
|
|
22139
|
+
const hasUrlCapability = capabilities.url !== void 0;
|
|
22140
|
+
const supportsFormMode = hasFormCapability || !hasFormCapability && !hasUrlCapability;
|
|
22141
|
+
const supportsUrlMode = hasUrlCapability;
|
|
22142
|
+
return { supportsFormMode, supportsUrlMode };
|
|
22143
|
+
}
|
|
22144
|
+
var Client = class extends Protocol {
|
|
22145
|
+
/**
|
|
22146
|
+
* Initializes this client with the given name and version information.
|
|
22147
|
+
*/
|
|
22148
|
+
constructor(_clientInfo, options) {
|
|
22149
|
+
super(options);
|
|
22150
|
+
this._clientInfo = _clientInfo;
|
|
22151
|
+
this._cachedToolOutputValidators = /* @__PURE__ */ new Map();
|
|
22152
|
+
this._cachedKnownTaskTools = /* @__PURE__ */ new Set();
|
|
22153
|
+
this._cachedRequiredTaskTools = /* @__PURE__ */ new Set();
|
|
22154
|
+
this._listChangedDebounceTimers = /* @__PURE__ */ new Map();
|
|
22155
|
+
this._capabilities = options?.capabilities ?? {};
|
|
22156
|
+
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator();
|
|
22157
|
+
if (options?.listChanged) {
|
|
22158
|
+
this._pendingListChangedConfig = options.listChanged;
|
|
22159
|
+
}
|
|
22160
|
+
}
|
|
22161
|
+
/**
|
|
22162
|
+
* Set up handlers for list changed notifications based on config and server capabilities.
|
|
22163
|
+
* This should only be called after initialization when server capabilities are known.
|
|
22164
|
+
* Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
|
|
22165
|
+
* @internal
|
|
22166
|
+
*/
|
|
22167
|
+
_setupListChangedHandlers(config2) {
|
|
22168
|
+
if (config2.tools && this._serverCapabilities?.tools?.listChanged) {
|
|
22169
|
+
this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config2.tools, async () => {
|
|
22170
|
+
const result = await this.listTools();
|
|
22171
|
+
return result.tools;
|
|
22172
|
+
});
|
|
22173
|
+
}
|
|
22174
|
+
if (config2.prompts && this._serverCapabilities?.prompts?.listChanged) {
|
|
22175
|
+
this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config2.prompts, async () => {
|
|
22176
|
+
const result = await this.listPrompts();
|
|
22177
|
+
return result.prompts;
|
|
22178
|
+
});
|
|
22179
|
+
}
|
|
22180
|
+
if (config2.resources && this._serverCapabilities?.resources?.listChanged) {
|
|
22181
|
+
this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config2.resources, async () => {
|
|
22182
|
+
const result = await this.listResources();
|
|
22183
|
+
return result.resources;
|
|
22184
|
+
});
|
|
22185
|
+
}
|
|
22186
|
+
}
|
|
22187
|
+
/**
|
|
22188
|
+
* Access experimental features.
|
|
22189
|
+
*
|
|
22190
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
22191
|
+
*
|
|
22192
|
+
* @experimental
|
|
22193
|
+
*/
|
|
22194
|
+
get experimental() {
|
|
22195
|
+
if (!this._experimental) {
|
|
22196
|
+
this._experimental = {
|
|
22197
|
+
tasks: new ExperimentalClientTasks(this)
|
|
22198
|
+
};
|
|
22199
|
+
}
|
|
22200
|
+
return this._experimental;
|
|
22201
|
+
}
|
|
22202
|
+
/**
|
|
22203
|
+
* Registers new capabilities. This can only be called before connecting to a transport.
|
|
22204
|
+
*
|
|
22205
|
+
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
|
22206
|
+
*/
|
|
22207
|
+
registerCapabilities(capabilities) {
|
|
22208
|
+
if (this.transport) {
|
|
22209
|
+
throw new Error("Cannot register capabilities after connecting to transport");
|
|
22210
|
+
}
|
|
22211
|
+
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
|
|
22212
|
+
}
|
|
22213
|
+
/**
|
|
22214
|
+
* Override request handler registration to enforce client-side validation for elicitation.
|
|
22215
|
+
*/
|
|
22216
|
+
setRequestHandler(requestSchema, handler) {
|
|
22217
|
+
const shape = getObjectShape(requestSchema);
|
|
22218
|
+
const methodSchema = shape?.method;
|
|
22219
|
+
if (!methodSchema) {
|
|
22220
|
+
throw new Error("Schema is missing a method literal");
|
|
22221
|
+
}
|
|
22222
|
+
let methodValue;
|
|
22223
|
+
if (isZ4Schema(methodSchema)) {
|
|
22224
|
+
const v4Schema = methodSchema;
|
|
22225
|
+
const v4Def = v4Schema._zod?.def;
|
|
22226
|
+
methodValue = v4Def?.value ?? v4Schema.value;
|
|
22227
|
+
} else {
|
|
22228
|
+
const v3Schema = methodSchema;
|
|
22229
|
+
const legacyDef = v3Schema._def;
|
|
22230
|
+
methodValue = legacyDef?.value ?? v3Schema.value;
|
|
22231
|
+
}
|
|
22232
|
+
if (typeof methodValue !== "string") {
|
|
22233
|
+
throw new Error("Schema method literal must be a string");
|
|
22234
|
+
}
|
|
22235
|
+
const method = methodValue;
|
|
22236
|
+
if (method === "elicitation/create") {
|
|
22237
|
+
const wrappedHandler = async (request, extra) => {
|
|
22238
|
+
const validatedRequest = safeParse2(ElicitRequestSchema, request);
|
|
22239
|
+
if (!validatedRequest.success) {
|
|
22240
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
22241
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation request: ${errorMessage}`);
|
|
22242
|
+
}
|
|
22243
|
+
const { params } = validatedRequest.data;
|
|
22244
|
+
params.mode = params.mode ?? "form";
|
|
22245
|
+
const { supportsFormMode, supportsUrlMode } = getSupportedElicitationModes(this._capabilities.elicitation);
|
|
22246
|
+
if (params.mode === "form" && !supportsFormMode) {
|
|
22247
|
+
throw new McpError(ErrorCode.InvalidParams, "Client does not support form-mode elicitation requests");
|
|
22248
|
+
}
|
|
22249
|
+
if (params.mode === "url" && !supportsUrlMode) {
|
|
22250
|
+
throw new McpError(ErrorCode.InvalidParams, "Client does not support URL-mode elicitation requests");
|
|
22251
|
+
}
|
|
22252
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
22253
|
+
if (params.task) {
|
|
22254
|
+
const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
|
|
22255
|
+
if (!taskValidationResult.success) {
|
|
22256
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
22257
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
22258
|
+
}
|
|
22259
|
+
return taskValidationResult.data;
|
|
22260
|
+
}
|
|
22261
|
+
const validationResult = safeParse2(ElicitResultSchema, result);
|
|
22262
|
+
if (!validationResult.success) {
|
|
22263
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
22264
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation result: ${errorMessage}`);
|
|
22265
|
+
}
|
|
22266
|
+
const validatedResult = validationResult.data;
|
|
22267
|
+
const requestedSchema = params.mode === "form" ? params.requestedSchema : void 0;
|
|
22268
|
+
if (params.mode === "form" && validatedResult.action === "accept" && validatedResult.content && requestedSchema) {
|
|
22269
|
+
if (this._capabilities.elicitation?.form?.applyDefaults) {
|
|
22270
|
+
try {
|
|
22271
|
+
applyElicitationDefaults(requestedSchema, validatedResult.content);
|
|
22272
|
+
} catch {
|
|
22273
|
+
}
|
|
22274
|
+
}
|
|
22275
|
+
}
|
|
22276
|
+
return validatedResult;
|
|
22277
|
+
};
|
|
22278
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
22279
|
+
}
|
|
22280
|
+
if (method === "sampling/createMessage") {
|
|
22281
|
+
const wrappedHandler = async (request, extra) => {
|
|
22282
|
+
const validatedRequest = safeParse2(CreateMessageRequestSchema, request);
|
|
22283
|
+
if (!validatedRequest.success) {
|
|
22284
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
22285
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling request: ${errorMessage}`);
|
|
22286
|
+
}
|
|
22287
|
+
const { params } = validatedRequest.data;
|
|
22288
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
22289
|
+
if (params.task) {
|
|
22290
|
+
const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
|
|
22291
|
+
if (!taskValidationResult.success) {
|
|
22292
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
22293
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
22294
|
+
}
|
|
22295
|
+
return taskValidationResult.data;
|
|
22296
|
+
}
|
|
22297
|
+
const hasTools = params.tools || params.toolChoice;
|
|
22298
|
+
const resultSchema = hasTools ? CreateMessageResultWithToolsSchema : CreateMessageResultSchema;
|
|
22299
|
+
const validationResult = safeParse2(resultSchema, result);
|
|
22300
|
+
if (!validationResult.success) {
|
|
22301
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
22302
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling result: ${errorMessage}`);
|
|
22303
|
+
}
|
|
22304
|
+
return validationResult.data;
|
|
22305
|
+
};
|
|
22306
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
22307
|
+
}
|
|
22308
|
+
return super.setRequestHandler(requestSchema, handler);
|
|
22309
|
+
}
|
|
22310
|
+
assertCapability(capability, method) {
|
|
22311
|
+
if (!this._serverCapabilities?.[capability]) {
|
|
22312
|
+
throw new Error(`Server does not support ${capability} (required for ${method})`);
|
|
22313
|
+
}
|
|
22314
|
+
}
|
|
22315
|
+
async connect(transport, options) {
|
|
22316
|
+
await super.connect(transport);
|
|
22317
|
+
if (transport.sessionId !== void 0) {
|
|
22318
|
+
return;
|
|
22319
|
+
}
|
|
22320
|
+
try {
|
|
22321
|
+
const result = await this.request({
|
|
22322
|
+
method: "initialize",
|
|
22323
|
+
params: {
|
|
22324
|
+
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
22325
|
+
capabilities: this._capabilities,
|
|
22326
|
+
clientInfo: this._clientInfo
|
|
22327
|
+
}
|
|
22328
|
+
}, InitializeResultSchema, options);
|
|
22329
|
+
if (result === void 0) {
|
|
22330
|
+
throw new Error(`Server sent invalid initialize result: ${result}`);
|
|
22331
|
+
}
|
|
22332
|
+
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
|
22333
|
+
throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
|
|
22334
|
+
}
|
|
22335
|
+
this._serverCapabilities = result.capabilities;
|
|
22336
|
+
this._serverVersion = result.serverInfo;
|
|
22337
|
+
if (transport.setProtocolVersion) {
|
|
22338
|
+
transport.setProtocolVersion(result.protocolVersion);
|
|
22339
|
+
}
|
|
22340
|
+
this._instructions = result.instructions;
|
|
22341
|
+
await this.notification({
|
|
22342
|
+
method: "notifications/initialized"
|
|
22343
|
+
});
|
|
22344
|
+
if (this._pendingListChangedConfig) {
|
|
22345
|
+
this._setupListChangedHandlers(this._pendingListChangedConfig);
|
|
22346
|
+
this._pendingListChangedConfig = void 0;
|
|
22347
|
+
}
|
|
22348
|
+
} catch (error2) {
|
|
22349
|
+
void this.close();
|
|
22350
|
+
throw error2;
|
|
22351
|
+
}
|
|
22352
|
+
}
|
|
22353
|
+
/**
|
|
22354
|
+
* After initialization has completed, this will be populated with the server's reported capabilities.
|
|
22355
|
+
*/
|
|
22356
|
+
getServerCapabilities() {
|
|
22357
|
+
return this._serverCapabilities;
|
|
22358
|
+
}
|
|
22359
|
+
/**
|
|
22360
|
+
* After initialization has completed, this will be populated with information about the server's name and version.
|
|
22361
|
+
*/
|
|
22362
|
+
getServerVersion() {
|
|
22363
|
+
return this._serverVersion;
|
|
22364
|
+
}
|
|
22365
|
+
/**
|
|
22366
|
+
* After initialization has completed, this may be populated with information about the server's instructions.
|
|
22367
|
+
*/
|
|
22368
|
+
getInstructions() {
|
|
22369
|
+
return this._instructions;
|
|
22370
|
+
}
|
|
22371
|
+
assertCapabilityForMethod(method) {
|
|
22372
|
+
switch (method) {
|
|
22373
|
+
case "logging/setLevel":
|
|
22374
|
+
if (!this._serverCapabilities?.logging) {
|
|
22375
|
+
throw new Error(`Server does not support logging (required for ${method})`);
|
|
22376
|
+
}
|
|
22377
|
+
break;
|
|
22378
|
+
case "prompts/get":
|
|
22379
|
+
case "prompts/list":
|
|
22380
|
+
if (!this._serverCapabilities?.prompts) {
|
|
22381
|
+
throw new Error(`Server does not support prompts (required for ${method})`);
|
|
22382
|
+
}
|
|
22383
|
+
break;
|
|
22384
|
+
case "resources/list":
|
|
22385
|
+
case "resources/templates/list":
|
|
22386
|
+
case "resources/read":
|
|
22387
|
+
case "resources/subscribe":
|
|
22388
|
+
case "resources/unsubscribe":
|
|
22389
|
+
if (!this._serverCapabilities?.resources) {
|
|
22390
|
+
throw new Error(`Server does not support resources (required for ${method})`);
|
|
22391
|
+
}
|
|
22392
|
+
if (method === "resources/subscribe" && !this._serverCapabilities.resources.subscribe) {
|
|
22393
|
+
throw new Error(`Server does not support resource subscriptions (required for ${method})`);
|
|
22394
|
+
}
|
|
22395
|
+
break;
|
|
22396
|
+
case "tools/call":
|
|
22397
|
+
case "tools/list":
|
|
22398
|
+
if (!this._serverCapabilities?.tools) {
|
|
22399
|
+
throw new Error(`Server does not support tools (required for ${method})`);
|
|
22400
|
+
}
|
|
22401
|
+
break;
|
|
22402
|
+
case "completion/complete":
|
|
22403
|
+
if (!this._serverCapabilities?.completions) {
|
|
22404
|
+
throw new Error(`Server does not support completions (required for ${method})`);
|
|
22405
|
+
}
|
|
22406
|
+
break;
|
|
22407
|
+
case "initialize":
|
|
22408
|
+
break;
|
|
22409
|
+
case "ping":
|
|
22410
|
+
break;
|
|
22411
|
+
}
|
|
22412
|
+
}
|
|
22413
|
+
assertNotificationCapability(method) {
|
|
22414
|
+
switch (method) {
|
|
22415
|
+
case "notifications/roots/list_changed":
|
|
22416
|
+
if (!this._capabilities.roots?.listChanged) {
|
|
22417
|
+
throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
|
|
22418
|
+
}
|
|
22419
|
+
break;
|
|
22420
|
+
case "notifications/initialized":
|
|
22421
|
+
break;
|
|
22422
|
+
case "notifications/cancelled":
|
|
22423
|
+
break;
|
|
22424
|
+
case "notifications/progress":
|
|
22425
|
+
break;
|
|
22426
|
+
}
|
|
22427
|
+
}
|
|
22428
|
+
assertRequestHandlerCapability(method) {
|
|
22429
|
+
if (!this._capabilities) {
|
|
22430
|
+
return;
|
|
22431
|
+
}
|
|
22432
|
+
switch (method) {
|
|
22433
|
+
case "sampling/createMessage":
|
|
22434
|
+
if (!this._capabilities.sampling) {
|
|
22435
|
+
throw new Error(`Client does not support sampling capability (required for ${method})`);
|
|
22436
|
+
}
|
|
22437
|
+
break;
|
|
22438
|
+
case "elicitation/create":
|
|
22439
|
+
if (!this._capabilities.elicitation) {
|
|
22440
|
+
throw new Error(`Client does not support elicitation capability (required for ${method})`);
|
|
22441
|
+
}
|
|
22442
|
+
break;
|
|
22443
|
+
case "roots/list":
|
|
22444
|
+
if (!this._capabilities.roots) {
|
|
22445
|
+
throw new Error(`Client does not support roots capability (required for ${method})`);
|
|
22446
|
+
}
|
|
22447
|
+
break;
|
|
22448
|
+
case "tasks/get":
|
|
22449
|
+
case "tasks/list":
|
|
22450
|
+
case "tasks/result":
|
|
22451
|
+
case "tasks/cancel":
|
|
22452
|
+
if (!this._capabilities.tasks) {
|
|
22453
|
+
throw new Error(`Client does not support tasks capability (required for ${method})`);
|
|
22454
|
+
}
|
|
22455
|
+
break;
|
|
22456
|
+
case "ping":
|
|
22457
|
+
break;
|
|
22458
|
+
}
|
|
22459
|
+
}
|
|
22460
|
+
assertTaskCapability(method) {
|
|
22461
|
+
assertToolsCallTaskCapability(this._serverCapabilities?.tasks?.requests, method, "Server");
|
|
22462
|
+
}
|
|
22463
|
+
assertTaskHandlerCapability(method) {
|
|
22464
|
+
if (!this._capabilities) {
|
|
22465
|
+
return;
|
|
22466
|
+
}
|
|
22467
|
+
assertClientRequestTaskCapability(this._capabilities.tasks?.requests, method, "Client");
|
|
22468
|
+
}
|
|
22469
|
+
async ping(options) {
|
|
22470
|
+
return this.request({ method: "ping" }, EmptyResultSchema, options);
|
|
22471
|
+
}
|
|
22472
|
+
async complete(params, options) {
|
|
22473
|
+
return this.request({ method: "completion/complete", params }, CompleteResultSchema, options);
|
|
22474
|
+
}
|
|
22475
|
+
async setLoggingLevel(level, options) {
|
|
22476
|
+
return this.request({ method: "logging/setLevel", params: { level } }, EmptyResultSchema, options);
|
|
22477
|
+
}
|
|
22478
|
+
async getPrompt(params, options) {
|
|
22479
|
+
return this.request({ method: "prompts/get", params }, GetPromptResultSchema, options);
|
|
22480
|
+
}
|
|
22481
|
+
async listPrompts(params, options) {
|
|
22482
|
+
return this.request({ method: "prompts/list", params }, ListPromptsResultSchema, options);
|
|
22483
|
+
}
|
|
22484
|
+
async listResources(params, options) {
|
|
22485
|
+
return this.request({ method: "resources/list", params }, ListResourcesResultSchema, options);
|
|
22486
|
+
}
|
|
22487
|
+
async listResourceTemplates(params, options) {
|
|
22488
|
+
return this.request({ method: "resources/templates/list", params }, ListResourceTemplatesResultSchema, options);
|
|
22489
|
+
}
|
|
22490
|
+
async readResource(params, options) {
|
|
22491
|
+
return this.request({ method: "resources/read", params }, ReadResourceResultSchema, options);
|
|
22492
|
+
}
|
|
22493
|
+
async subscribeResource(params, options) {
|
|
22494
|
+
return this.request({ method: "resources/subscribe", params }, EmptyResultSchema, options);
|
|
22495
|
+
}
|
|
22496
|
+
async unsubscribeResource(params, options) {
|
|
22497
|
+
return this.request({ method: "resources/unsubscribe", params }, EmptyResultSchema, options);
|
|
22498
|
+
}
|
|
22499
|
+
/**
|
|
22500
|
+
* Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
|
|
22501
|
+
*
|
|
22502
|
+
* For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
|
|
22503
|
+
*/
|
|
22504
|
+
async callTool(params, resultSchema = CallToolResultSchema, options) {
|
|
22505
|
+
if (this.isToolTaskRequired(params.name)) {
|
|
22506
|
+
throw new McpError(ErrorCode.InvalidRequest, `Tool "${params.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);
|
|
22507
|
+
}
|
|
22508
|
+
const result = await this.request({ method: "tools/call", params }, resultSchema, options);
|
|
22509
|
+
const validator = this.getToolOutputValidator(params.name);
|
|
22510
|
+
if (validator) {
|
|
22511
|
+
if (!result.structuredContent && !result.isError) {
|
|
22512
|
+
throw new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`);
|
|
22513
|
+
}
|
|
22514
|
+
if (result.structuredContent) {
|
|
22515
|
+
try {
|
|
22516
|
+
const validationResult = validator(result.structuredContent);
|
|
22517
|
+
if (!validationResult.valid) {
|
|
22518
|
+
throw new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`);
|
|
22519
|
+
}
|
|
22520
|
+
} catch (error2) {
|
|
22521
|
+
if (error2 instanceof McpError) {
|
|
22522
|
+
throw error2;
|
|
22523
|
+
}
|
|
22524
|
+
throw new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
22525
|
+
}
|
|
22526
|
+
}
|
|
22527
|
+
}
|
|
22528
|
+
return result;
|
|
22529
|
+
}
|
|
22530
|
+
isToolTask(toolName) {
|
|
22531
|
+
if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
|
|
22532
|
+
return false;
|
|
22533
|
+
}
|
|
22534
|
+
return this._cachedKnownTaskTools.has(toolName);
|
|
22535
|
+
}
|
|
22536
|
+
/**
|
|
22537
|
+
* Check if a tool requires task-based execution.
|
|
22538
|
+
* Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
|
|
22539
|
+
*/
|
|
22540
|
+
isToolTaskRequired(toolName) {
|
|
22541
|
+
return this._cachedRequiredTaskTools.has(toolName);
|
|
22542
|
+
}
|
|
22543
|
+
/**
|
|
22544
|
+
* Cache validators for tool output schemas.
|
|
22545
|
+
* Called after listTools() to pre-compile validators for better performance.
|
|
22546
|
+
*/
|
|
22547
|
+
cacheToolMetadata(tools) {
|
|
22548
|
+
this._cachedToolOutputValidators.clear();
|
|
22549
|
+
this._cachedKnownTaskTools.clear();
|
|
22550
|
+
this._cachedRequiredTaskTools.clear();
|
|
22551
|
+
for (const tool of tools) {
|
|
22552
|
+
if (tool.outputSchema) {
|
|
22553
|
+
const toolValidator = this._jsonSchemaValidator.getValidator(tool.outputSchema);
|
|
22554
|
+
this._cachedToolOutputValidators.set(tool.name, toolValidator);
|
|
22555
|
+
}
|
|
22556
|
+
const taskSupport = tool.execution?.taskSupport;
|
|
22557
|
+
if (taskSupport === "required" || taskSupport === "optional") {
|
|
22558
|
+
this._cachedKnownTaskTools.add(tool.name);
|
|
22559
|
+
}
|
|
22560
|
+
if (taskSupport === "required") {
|
|
22561
|
+
this._cachedRequiredTaskTools.add(tool.name);
|
|
22562
|
+
}
|
|
22563
|
+
}
|
|
22564
|
+
}
|
|
22565
|
+
/**
|
|
22566
|
+
* Get cached validator for a tool
|
|
22567
|
+
*/
|
|
22568
|
+
getToolOutputValidator(toolName) {
|
|
22569
|
+
return this._cachedToolOutputValidators.get(toolName);
|
|
22570
|
+
}
|
|
22571
|
+
async listTools(params, options) {
|
|
22572
|
+
const result = await this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
|
|
22573
|
+
this.cacheToolMetadata(result.tools);
|
|
22574
|
+
return result;
|
|
22575
|
+
}
|
|
22576
|
+
/**
|
|
22577
|
+
* Set up a single list changed handler.
|
|
22578
|
+
* @internal
|
|
22579
|
+
*/
|
|
22580
|
+
_setupListChangedHandler(listType, notificationSchema, options, fetcher) {
|
|
22581
|
+
const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
|
|
22582
|
+
if (!parseResult.success) {
|
|
22583
|
+
throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
|
22584
|
+
}
|
|
22585
|
+
if (typeof options.onChanged !== "function") {
|
|
22586
|
+
throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
|
|
22587
|
+
}
|
|
22588
|
+
const { autoRefresh, debounceMs } = parseResult.data;
|
|
22589
|
+
const { onChanged } = options;
|
|
22590
|
+
const refresh = async () => {
|
|
22591
|
+
if (!autoRefresh) {
|
|
22592
|
+
onChanged(null, null);
|
|
22593
|
+
return;
|
|
22594
|
+
}
|
|
22595
|
+
try {
|
|
22596
|
+
const items = await fetcher();
|
|
22597
|
+
onChanged(null, items);
|
|
22598
|
+
} catch (e) {
|
|
22599
|
+
const error2 = e instanceof Error ? e : new Error(String(e));
|
|
22600
|
+
onChanged(error2, null);
|
|
22601
|
+
}
|
|
22602
|
+
};
|
|
22603
|
+
const handler = () => {
|
|
22604
|
+
if (debounceMs) {
|
|
22605
|
+
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
|
22606
|
+
if (existingTimer) {
|
|
22607
|
+
clearTimeout(existingTimer);
|
|
22608
|
+
}
|
|
22609
|
+
const timer = setTimeout(refresh, debounceMs);
|
|
22610
|
+
this._listChangedDebounceTimers.set(listType, timer);
|
|
22611
|
+
} else {
|
|
22612
|
+
refresh();
|
|
22613
|
+
}
|
|
22614
|
+
};
|
|
22615
|
+
this.setNotificationHandler(notificationSchema, handler);
|
|
22616
|
+
}
|
|
22617
|
+
async sendRootsListChanged() {
|
|
22618
|
+
return this.notification({ method: "notifications/roots/list_changed" });
|
|
22619
|
+
}
|
|
22620
|
+
};
|
|
22621
|
+
|
|
22622
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
|
|
22623
|
+
var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
22624
|
+
import process4 from "node:process";
|
|
22625
|
+
import { PassThrough } from "node:stream";
|
|
22626
|
+
var DEFAULT_INHERITED_ENV_VARS = process4.platform === "win32" ? [
|
|
22627
|
+
"APPDATA",
|
|
22628
|
+
"HOMEDRIVE",
|
|
22629
|
+
"HOMEPATH",
|
|
22630
|
+
"LOCALAPPDATA",
|
|
22631
|
+
"PATH",
|
|
22632
|
+
"PROCESSOR_ARCHITECTURE",
|
|
22633
|
+
"SYSTEMDRIVE",
|
|
22634
|
+
"SYSTEMROOT",
|
|
22635
|
+
"TEMP",
|
|
22636
|
+
"USERNAME",
|
|
22637
|
+
"USERPROFILE",
|
|
22638
|
+
"PROGRAMFILES"
|
|
22639
|
+
] : (
|
|
22640
|
+
/* list inspired by the default env inheritance of sudo */
|
|
22641
|
+
["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"]
|
|
22642
|
+
);
|
|
22643
|
+
function getDefaultEnvironment() {
|
|
22644
|
+
const env = {};
|
|
22645
|
+
for (const key of DEFAULT_INHERITED_ENV_VARS) {
|
|
22646
|
+
const value = process4.env[key];
|
|
22647
|
+
if (value === void 0) {
|
|
22648
|
+
continue;
|
|
22649
|
+
}
|
|
22650
|
+
if (value.startsWith("()")) {
|
|
22651
|
+
continue;
|
|
22652
|
+
}
|
|
22653
|
+
env[key] = value;
|
|
22654
|
+
}
|
|
22655
|
+
return env;
|
|
22656
|
+
}
|
|
22657
|
+
var StdioClientTransport = class {
|
|
22658
|
+
constructor(server2) {
|
|
22659
|
+
this._readBuffer = new ReadBuffer();
|
|
22660
|
+
this._stderrStream = null;
|
|
22661
|
+
this._serverParams = server2;
|
|
22662
|
+
if (server2.stderr === "pipe" || server2.stderr === "overlapped") {
|
|
22663
|
+
this._stderrStream = new PassThrough();
|
|
22664
|
+
}
|
|
22665
|
+
}
|
|
22666
|
+
/**
|
|
22667
|
+
* Starts the server process and prepares to communicate with it.
|
|
22668
|
+
*/
|
|
22669
|
+
async start() {
|
|
22670
|
+
if (this._process) {
|
|
22671
|
+
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
22672
|
+
}
|
|
22673
|
+
return new Promise((resolve, reject) => {
|
|
22674
|
+
this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
|
|
22675
|
+
// merge default env with server env because mcp server needs some env vars
|
|
22676
|
+
env: {
|
|
22677
|
+
...getDefaultEnvironment(),
|
|
22678
|
+
...this._serverParams.env
|
|
22679
|
+
},
|
|
22680
|
+
stdio: ["pipe", "pipe", this._serverParams.stderr ?? "inherit"],
|
|
22681
|
+
shell: false,
|
|
22682
|
+
windowsHide: process4.platform === "win32",
|
|
22683
|
+
cwd: this._serverParams.cwd
|
|
22684
|
+
});
|
|
22685
|
+
this._process.on("error", (error2) => {
|
|
22686
|
+
reject(error2);
|
|
22687
|
+
this.onerror?.(error2);
|
|
22688
|
+
});
|
|
22689
|
+
this._process.on("spawn", () => {
|
|
22690
|
+
resolve();
|
|
22691
|
+
});
|
|
22692
|
+
this._process.on("close", (_code) => {
|
|
22693
|
+
this._process = void 0;
|
|
22694
|
+
this.onclose?.();
|
|
22695
|
+
});
|
|
22696
|
+
this._process.stdin?.on("error", (error2) => {
|
|
22697
|
+
this.onerror?.(error2);
|
|
22698
|
+
});
|
|
22699
|
+
this._process.stdout?.on("data", (chunk) => {
|
|
22700
|
+
this._readBuffer.append(chunk);
|
|
22701
|
+
this.processReadBuffer();
|
|
22702
|
+
});
|
|
22703
|
+
this._process.stdout?.on("error", (error2) => {
|
|
22704
|
+
this.onerror?.(error2);
|
|
22705
|
+
});
|
|
22706
|
+
if (this._stderrStream && this._process.stderr) {
|
|
22707
|
+
this._process.stderr.pipe(this._stderrStream);
|
|
22708
|
+
}
|
|
22709
|
+
});
|
|
22710
|
+
}
|
|
22711
|
+
/**
|
|
22712
|
+
* The stderr stream of the child process, if `StdioServerParameters.stderr` was set to "pipe" or "overlapped".
|
|
22713
|
+
*
|
|
22714
|
+
* If stderr piping was requested, a PassThrough stream is returned _immediately_, allowing callers to
|
|
22715
|
+
* attach listeners before the start method is invoked. This prevents loss of any early
|
|
22716
|
+
* error output emitted by the child process.
|
|
22717
|
+
*/
|
|
22718
|
+
get stderr() {
|
|
22719
|
+
if (this._stderrStream) {
|
|
22720
|
+
return this._stderrStream;
|
|
22721
|
+
}
|
|
22722
|
+
return this._process?.stderr ?? null;
|
|
22723
|
+
}
|
|
22724
|
+
/**
|
|
22725
|
+
* The child process pid spawned by this transport.
|
|
22726
|
+
*
|
|
22727
|
+
* This is only available after the transport has been started.
|
|
22728
|
+
*/
|
|
22729
|
+
get pid() {
|
|
22730
|
+
return this._process?.pid ?? null;
|
|
22731
|
+
}
|
|
22732
|
+
processReadBuffer() {
|
|
22733
|
+
while (true) {
|
|
22734
|
+
try {
|
|
22735
|
+
const message = this._readBuffer.readMessage();
|
|
22736
|
+
if (message === null) {
|
|
22737
|
+
break;
|
|
22738
|
+
}
|
|
22739
|
+
this.onmessage?.(message);
|
|
22740
|
+
} catch (error2) {
|
|
22741
|
+
this.onerror?.(error2);
|
|
22742
|
+
}
|
|
22743
|
+
}
|
|
22744
|
+
}
|
|
22745
|
+
async close() {
|
|
22746
|
+
if (this._process) {
|
|
22747
|
+
const processToClose = this._process;
|
|
22748
|
+
this._process = void 0;
|
|
22749
|
+
const closePromise = new Promise((resolve) => {
|
|
22750
|
+
processToClose.once("close", () => {
|
|
22751
|
+
resolve();
|
|
22752
|
+
});
|
|
22753
|
+
});
|
|
22754
|
+
try {
|
|
22755
|
+
processToClose.stdin?.end();
|
|
22756
|
+
} catch {
|
|
22757
|
+
}
|
|
22758
|
+
await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
|
|
22759
|
+
if (processToClose.exitCode === null) {
|
|
22760
|
+
try {
|
|
22761
|
+
processToClose.kill("SIGTERM");
|
|
22762
|
+
} catch {
|
|
22763
|
+
}
|
|
22764
|
+
await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
|
|
22765
|
+
}
|
|
22766
|
+
if (processToClose.exitCode === null) {
|
|
22767
|
+
try {
|
|
22768
|
+
processToClose.kill("SIGKILL");
|
|
22769
|
+
} catch {
|
|
22770
|
+
}
|
|
22771
|
+
}
|
|
22772
|
+
}
|
|
22773
|
+
this._readBuffer.clear();
|
|
22774
|
+
}
|
|
22775
|
+
send(message) {
|
|
22776
|
+
return new Promise((resolve) => {
|
|
22777
|
+
if (!this._process?.stdin) {
|
|
22778
|
+
throw new Error("Not connected");
|
|
22779
|
+
}
|
|
22780
|
+
const json = serializeMessage(message);
|
|
22781
|
+
if (this._process.stdin.write(json)) {
|
|
22782
|
+
resolve();
|
|
22783
|
+
} else {
|
|
22784
|
+
this._process.stdin.once("drain", resolve);
|
|
22785
|
+
}
|
|
22786
|
+
});
|
|
22787
|
+
}
|
|
22788
|
+
};
|
|
22789
|
+
|
|
22790
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
|
|
22791
|
+
function normalizeHeaders(headers) {
|
|
22792
|
+
if (!headers)
|
|
22793
|
+
return {};
|
|
22794
|
+
if (headers instanceof Headers) {
|
|
22795
|
+
return Object.fromEntries(headers.entries());
|
|
22796
|
+
}
|
|
22797
|
+
if (Array.isArray(headers)) {
|
|
22798
|
+
return Object.fromEntries(headers);
|
|
22799
|
+
}
|
|
22800
|
+
return { ...headers };
|
|
22801
|
+
}
|
|
22802
|
+
function createFetchWithInit(baseFetch = fetch, baseInit) {
|
|
22803
|
+
if (!baseInit) {
|
|
22804
|
+
return baseFetch;
|
|
22805
|
+
}
|
|
22806
|
+
return async (url2, init) => {
|
|
22807
|
+
const mergedInit = {
|
|
22808
|
+
...baseInit,
|
|
22809
|
+
...init,
|
|
22810
|
+
// Headers need special handling - merge instead of replace
|
|
22811
|
+
headers: init?.headers ? { ...normalizeHeaders(baseInit.headers), ...normalizeHeaders(init.headers) } : baseInit.headers
|
|
22812
|
+
};
|
|
22813
|
+
return baseFetch(url2, mergedInit);
|
|
22814
|
+
};
|
|
22815
|
+
}
|
|
22816
|
+
|
|
22817
|
+
// node_modules/pkce-challenge/dist/index.node.js
|
|
22818
|
+
var crypto;
|
|
22819
|
+
crypto = globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
|
|
22820
|
+
globalThis.crypto ?? // Node.js >18
|
|
22821
|
+
import("node:crypto").then((m) => m.webcrypto);
|
|
22822
|
+
async function getRandomValues(size) {
|
|
22823
|
+
return (await crypto).getRandomValues(new Uint8Array(size));
|
|
22824
|
+
}
|
|
22825
|
+
async function random(size) {
|
|
22826
|
+
const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
|
22827
|
+
const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
|
|
22828
|
+
let result = "";
|
|
22829
|
+
while (result.length < size) {
|
|
22830
|
+
const randomBytes = await getRandomValues(size - result.length);
|
|
22831
|
+
for (const randomByte of randomBytes) {
|
|
22832
|
+
if (randomByte < evenDistCutoff) {
|
|
22833
|
+
result += mask[randomByte % mask.length];
|
|
22834
|
+
}
|
|
22835
|
+
}
|
|
22836
|
+
}
|
|
22837
|
+
return result;
|
|
22838
|
+
}
|
|
22839
|
+
async function generateVerifier(length) {
|
|
22840
|
+
return await random(length);
|
|
22841
|
+
}
|
|
22842
|
+
async function generateChallenge(code_verifier) {
|
|
22843
|
+
const buffer = await (await crypto).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
|
|
22844
|
+
return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
|
|
22845
|
+
}
|
|
22846
|
+
async function pkceChallenge(length) {
|
|
22847
|
+
if (!length)
|
|
22848
|
+
length = 43;
|
|
22849
|
+
if (length < 43 || length > 128) {
|
|
22850
|
+
throw `Expected a length between 43 and 128. Received ${length}.`;
|
|
22851
|
+
}
|
|
22852
|
+
const verifier = await generateVerifier(length);
|
|
22853
|
+
const challenge = await generateChallenge(verifier);
|
|
22854
|
+
return {
|
|
22855
|
+
code_verifier: verifier,
|
|
22856
|
+
code_challenge: challenge
|
|
22857
|
+
};
|
|
22858
|
+
}
|
|
22859
|
+
|
|
22860
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
|
|
22861
|
+
var SafeUrlSchema = url().superRefine((val, ctx) => {
|
|
22862
|
+
if (!URL.canParse(val)) {
|
|
22863
|
+
ctx.addIssue({
|
|
22864
|
+
code: ZodIssueCode.custom,
|
|
22865
|
+
message: "URL must be parseable",
|
|
22866
|
+
fatal: true
|
|
22867
|
+
});
|
|
22868
|
+
return NEVER;
|
|
22869
|
+
}
|
|
22870
|
+
}).refine((url2) => {
|
|
22871
|
+
const u = new URL(url2);
|
|
22872
|
+
return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
|
|
22873
|
+
}, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
|
|
22874
|
+
var OAuthProtectedResourceMetadataSchema = looseObject({
|
|
22875
|
+
resource: string2().url(),
|
|
22876
|
+
authorization_servers: array(SafeUrlSchema).optional(),
|
|
22877
|
+
jwks_uri: string2().url().optional(),
|
|
22878
|
+
scopes_supported: array(string2()).optional(),
|
|
22879
|
+
bearer_methods_supported: array(string2()).optional(),
|
|
22880
|
+
resource_signing_alg_values_supported: array(string2()).optional(),
|
|
22881
|
+
resource_name: string2().optional(),
|
|
22882
|
+
resource_documentation: string2().optional(),
|
|
22883
|
+
resource_policy_uri: string2().url().optional(),
|
|
22884
|
+
resource_tos_uri: string2().url().optional(),
|
|
22885
|
+
tls_client_certificate_bound_access_tokens: boolean2().optional(),
|
|
22886
|
+
authorization_details_types_supported: array(string2()).optional(),
|
|
22887
|
+
dpop_signing_alg_values_supported: array(string2()).optional(),
|
|
22888
|
+
dpop_bound_access_tokens_required: boolean2().optional()
|
|
22889
|
+
});
|
|
22890
|
+
var OAuthMetadataSchema = looseObject({
|
|
22891
|
+
issuer: string2(),
|
|
22892
|
+
authorization_endpoint: SafeUrlSchema,
|
|
22893
|
+
token_endpoint: SafeUrlSchema,
|
|
22894
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
22895
|
+
scopes_supported: array(string2()).optional(),
|
|
22896
|
+
response_types_supported: array(string2()),
|
|
22897
|
+
response_modes_supported: array(string2()).optional(),
|
|
22898
|
+
grant_types_supported: array(string2()).optional(),
|
|
22899
|
+
token_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22900
|
+
token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22901
|
+
service_documentation: SafeUrlSchema.optional(),
|
|
22902
|
+
revocation_endpoint: SafeUrlSchema.optional(),
|
|
22903
|
+
revocation_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22904
|
+
revocation_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22905
|
+
introspection_endpoint: string2().optional(),
|
|
22906
|
+
introspection_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22907
|
+
introspection_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22908
|
+
code_challenge_methods_supported: array(string2()).optional(),
|
|
22909
|
+
client_id_metadata_document_supported: boolean2().optional()
|
|
22910
|
+
});
|
|
22911
|
+
var OpenIdProviderMetadataSchema = looseObject({
|
|
22912
|
+
issuer: string2(),
|
|
22913
|
+
authorization_endpoint: SafeUrlSchema,
|
|
22914
|
+
token_endpoint: SafeUrlSchema,
|
|
22915
|
+
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
22916
|
+
jwks_uri: SafeUrlSchema,
|
|
22917
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
22918
|
+
scopes_supported: array(string2()).optional(),
|
|
22919
|
+
response_types_supported: array(string2()),
|
|
22920
|
+
response_modes_supported: array(string2()).optional(),
|
|
22921
|
+
grant_types_supported: array(string2()).optional(),
|
|
22922
|
+
acr_values_supported: array(string2()).optional(),
|
|
22923
|
+
subject_types_supported: array(string2()),
|
|
22924
|
+
id_token_signing_alg_values_supported: array(string2()),
|
|
22925
|
+
id_token_encryption_alg_values_supported: array(string2()).optional(),
|
|
22926
|
+
id_token_encryption_enc_values_supported: array(string2()).optional(),
|
|
22927
|
+
userinfo_signing_alg_values_supported: array(string2()).optional(),
|
|
22928
|
+
userinfo_encryption_alg_values_supported: array(string2()).optional(),
|
|
22929
|
+
userinfo_encryption_enc_values_supported: array(string2()).optional(),
|
|
22930
|
+
request_object_signing_alg_values_supported: array(string2()).optional(),
|
|
22931
|
+
request_object_encryption_alg_values_supported: array(string2()).optional(),
|
|
22932
|
+
request_object_encryption_enc_values_supported: array(string2()).optional(),
|
|
22933
|
+
token_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22934
|
+
token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22935
|
+
display_values_supported: array(string2()).optional(),
|
|
22936
|
+
claim_types_supported: array(string2()).optional(),
|
|
22937
|
+
claims_supported: array(string2()).optional(),
|
|
22938
|
+
service_documentation: string2().optional(),
|
|
22939
|
+
claims_locales_supported: array(string2()).optional(),
|
|
22940
|
+
ui_locales_supported: array(string2()).optional(),
|
|
22941
|
+
claims_parameter_supported: boolean2().optional(),
|
|
22942
|
+
request_parameter_supported: boolean2().optional(),
|
|
22943
|
+
request_uri_parameter_supported: boolean2().optional(),
|
|
22944
|
+
require_request_uri_registration: boolean2().optional(),
|
|
22945
|
+
op_policy_uri: SafeUrlSchema.optional(),
|
|
22946
|
+
op_tos_uri: SafeUrlSchema.optional(),
|
|
22947
|
+
client_id_metadata_document_supported: boolean2().optional()
|
|
22948
|
+
});
|
|
22949
|
+
var OpenIdProviderDiscoveryMetadataSchema = object2({
|
|
22950
|
+
...OpenIdProviderMetadataSchema.shape,
|
|
22951
|
+
...OAuthMetadataSchema.pick({
|
|
22952
|
+
code_challenge_methods_supported: true
|
|
22953
|
+
}).shape
|
|
22954
|
+
});
|
|
22955
|
+
var OAuthTokensSchema = object2({
|
|
22956
|
+
access_token: string2(),
|
|
22957
|
+
id_token: string2().optional(),
|
|
22958
|
+
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
22959
|
+
token_type: string2(),
|
|
22960
|
+
expires_in: coerce_exports.number().optional(),
|
|
22961
|
+
scope: string2().optional(),
|
|
22962
|
+
refresh_token: string2().optional()
|
|
22963
|
+
}).strip();
|
|
22964
|
+
var OAuthErrorResponseSchema = object2({
|
|
22965
|
+
error: string2(),
|
|
22966
|
+
error_description: string2().optional(),
|
|
22967
|
+
error_uri: string2().optional()
|
|
22968
|
+
});
|
|
22969
|
+
var OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => void 0));
|
|
22970
|
+
var OAuthClientMetadataSchema = object2({
|
|
22971
|
+
redirect_uris: array(SafeUrlSchema),
|
|
22972
|
+
token_endpoint_auth_method: string2().optional(),
|
|
22973
|
+
grant_types: array(string2()).optional(),
|
|
22974
|
+
response_types: array(string2()).optional(),
|
|
22975
|
+
client_name: string2().optional(),
|
|
22976
|
+
client_uri: SafeUrlSchema.optional(),
|
|
22977
|
+
logo_uri: OptionalSafeUrlSchema,
|
|
22978
|
+
scope: string2().optional(),
|
|
22979
|
+
contacts: array(string2()).optional(),
|
|
22980
|
+
tos_uri: OptionalSafeUrlSchema,
|
|
22981
|
+
policy_uri: string2().optional(),
|
|
22982
|
+
jwks_uri: SafeUrlSchema.optional(),
|
|
22983
|
+
jwks: any().optional(),
|
|
22984
|
+
software_id: string2().optional(),
|
|
22985
|
+
software_version: string2().optional(),
|
|
22986
|
+
software_statement: string2().optional()
|
|
22987
|
+
}).strip();
|
|
22988
|
+
var OAuthClientInformationSchema = object2({
|
|
22989
|
+
client_id: string2(),
|
|
22990
|
+
client_secret: string2().optional(),
|
|
22991
|
+
client_id_issued_at: number2().optional(),
|
|
22992
|
+
client_secret_expires_at: number2().optional()
|
|
22993
|
+
}).strip();
|
|
22994
|
+
var OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
|
|
22995
|
+
var OAuthClientRegistrationErrorSchema = object2({
|
|
22996
|
+
error: string2(),
|
|
22997
|
+
error_description: string2().optional()
|
|
22998
|
+
}).strip();
|
|
22999
|
+
var OAuthTokenRevocationRequestSchema = object2({
|
|
23000
|
+
token: string2(),
|
|
23001
|
+
token_type_hint: string2().optional()
|
|
23002
|
+
}).strip();
|
|
23003
|
+
|
|
23004
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
|
|
23005
|
+
function resourceUrlFromServerUrl(url2) {
|
|
23006
|
+
const resourceURL = typeof url2 === "string" ? new URL(url2) : new URL(url2.href);
|
|
23007
|
+
resourceURL.hash = "";
|
|
23008
|
+
return resourceURL;
|
|
23009
|
+
}
|
|
23010
|
+
function checkResourceAllowed({ requestedResource, configuredResource }) {
|
|
23011
|
+
const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
|
|
23012
|
+
const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
|
|
23013
|
+
if (requested.origin !== configured.origin) {
|
|
23014
|
+
return false;
|
|
23015
|
+
}
|
|
23016
|
+
if (requested.pathname.length < configured.pathname.length) {
|
|
23017
|
+
return false;
|
|
23018
|
+
}
|
|
23019
|
+
const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
|
|
23020
|
+
const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
|
|
23021
|
+
return requestedPath.startsWith(configuredPath);
|
|
23022
|
+
}
|
|
23023
|
+
|
|
23024
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
23025
|
+
var OAuthError = class extends Error {
|
|
23026
|
+
constructor(message, errorUri) {
|
|
23027
|
+
super(message);
|
|
23028
|
+
this.errorUri = errorUri;
|
|
23029
|
+
this.name = this.constructor.name;
|
|
23030
|
+
}
|
|
23031
|
+
/**
|
|
23032
|
+
* Converts the error to a standard OAuth error response object
|
|
23033
|
+
*/
|
|
23034
|
+
toResponseObject() {
|
|
23035
|
+
const response = {
|
|
23036
|
+
error: this.errorCode,
|
|
23037
|
+
error_description: this.message
|
|
23038
|
+
};
|
|
23039
|
+
if (this.errorUri) {
|
|
23040
|
+
response.error_uri = this.errorUri;
|
|
23041
|
+
}
|
|
23042
|
+
return response;
|
|
23043
|
+
}
|
|
23044
|
+
get errorCode() {
|
|
23045
|
+
return this.constructor.errorCode;
|
|
23046
|
+
}
|
|
23047
|
+
};
|
|
23048
|
+
var InvalidRequestError = class extends OAuthError {
|
|
23049
|
+
};
|
|
23050
|
+
InvalidRequestError.errorCode = "invalid_request";
|
|
23051
|
+
var InvalidClientError = class extends OAuthError {
|
|
23052
|
+
};
|
|
23053
|
+
InvalidClientError.errorCode = "invalid_client";
|
|
23054
|
+
var InvalidGrantError = class extends OAuthError {
|
|
23055
|
+
};
|
|
23056
|
+
InvalidGrantError.errorCode = "invalid_grant";
|
|
23057
|
+
var UnauthorizedClientError = class extends OAuthError {
|
|
23058
|
+
};
|
|
23059
|
+
UnauthorizedClientError.errorCode = "unauthorized_client";
|
|
23060
|
+
var UnsupportedGrantTypeError = class extends OAuthError {
|
|
23061
|
+
};
|
|
23062
|
+
UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
|
|
23063
|
+
var InvalidScopeError = class extends OAuthError {
|
|
23064
|
+
};
|
|
23065
|
+
InvalidScopeError.errorCode = "invalid_scope";
|
|
23066
|
+
var AccessDeniedError = class extends OAuthError {
|
|
23067
|
+
};
|
|
23068
|
+
AccessDeniedError.errorCode = "access_denied";
|
|
23069
|
+
var ServerError = class extends OAuthError {
|
|
23070
|
+
};
|
|
23071
|
+
ServerError.errorCode = "server_error";
|
|
23072
|
+
var TemporarilyUnavailableError = class extends OAuthError {
|
|
23073
|
+
};
|
|
23074
|
+
TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
|
|
23075
|
+
var UnsupportedResponseTypeError = class extends OAuthError {
|
|
23076
|
+
};
|
|
23077
|
+
UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
|
|
23078
|
+
var UnsupportedTokenTypeError = class extends OAuthError {
|
|
23079
|
+
};
|
|
23080
|
+
UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
|
|
23081
|
+
var InvalidTokenError = class extends OAuthError {
|
|
23082
|
+
};
|
|
23083
|
+
InvalidTokenError.errorCode = "invalid_token";
|
|
23084
|
+
var MethodNotAllowedError = class extends OAuthError {
|
|
23085
|
+
};
|
|
23086
|
+
MethodNotAllowedError.errorCode = "method_not_allowed";
|
|
23087
|
+
var TooManyRequestsError = class extends OAuthError {
|
|
23088
|
+
};
|
|
23089
|
+
TooManyRequestsError.errorCode = "too_many_requests";
|
|
23090
|
+
var InvalidClientMetadataError = class extends OAuthError {
|
|
23091
|
+
};
|
|
23092
|
+
InvalidClientMetadataError.errorCode = "invalid_client_metadata";
|
|
23093
|
+
var InsufficientScopeError = class extends OAuthError {
|
|
23094
|
+
};
|
|
23095
|
+
InsufficientScopeError.errorCode = "insufficient_scope";
|
|
23096
|
+
var InvalidTargetError = class extends OAuthError {
|
|
23097
|
+
};
|
|
23098
|
+
InvalidTargetError.errorCode = "invalid_target";
|
|
23099
|
+
var OAUTH_ERRORS = {
|
|
23100
|
+
[InvalidRequestError.errorCode]: InvalidRequestError,
|
|
23101
|
+
[InvalidClientError.errorCode]: InvalidClientError,
|
|
23102
|
+
[InvalidGrantError.errorCode]: InvalidGrantError,
|
|
23103
|
+
[UnauthorizedClientError.errorCode]: UnauthorizedClientError,
|
|
23104
|
+
[UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
|
|
23105
|
+
[InvalidScopeError.errorCode]: InvalidScopeError,
|
|
23106
|
+
[AccessDeniedError.errorCode]: AccessDeniedError,
|
|
23107
|
+
[ServerError.errorCode]: ServerError,
|
|
23108
|
+
[TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
|
|
23109
|
+
[UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
|
|
23110
|
+
[UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
|
|
23111
|
+
[InvalidTokenError.errorCode]: InvalidTokenError,
|
|
23112
|
+
[MethodNotAllowedError.errorCode]: MethodNotAllowedError,
|
|
23113
|
+
[TooManyRequestsError.errorCode]: TooManyRequestsError,
|
|
23114
|
+
[InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
|
|
23115
|
+
[InsufficientScopeError.errorCode]: InsufficientScopeError,
|
|
23116
|
+
[InvalidTargetError.errorCode]: InvalidTargetError
|
|
23117
|
+
};
|
|
23118
|
+
|
|
23119
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
|
|
23120
|
+
var UnauthorizedError = class extends Error {
|
|
23121
|
+
constructor(message) {
|
|
23122
|
+
super(message ?? "Unauthorized");
|
|
23123
|
+
}
|
|
23124
|
+
};
|
|
23125
|
+
function isClientAuthMethod(method) {
|
|
23126
|
+
return ["client_secret_basic", "client_secret_post", "none"].includes(method);
|
|
23127
|
+
}
|
|
23128
|
+
var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
|
|
23129
|
+
var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
|
|
23130
|
+
function selectClientAuthMethod(clientInformation, supportedMethods) {
|
|
23131
|
+
const hasClientSecret = clientInformation.client_secret !== void 0;
|
|
23132
|
+
if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && (supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method))) {
|
|
23133
|
+
return clientInformation.token_endpoint_auth_method;
|
|
23134
|
+
}
|
|
23135
|
+
if (supportedMethods.length === 0) {
|
|
23136
|
+
return hasClientSecret ? "client_secret_basic" : "none";
|
|
23137
|
+
}
|
|
23138
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
|
|
23139
|
+
return "client_secret_basic";
|
|
23140
|
+
}
|
|
23141
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
|
|
23142
|
+
return "client_secret_post";
|
|
23143
|
+
}
|
|
23144
|
+
if (supportedMethods.includes("none")) {
|
|
23145
|
+
return "none";
|
|
23146
|
+
}
|
|
23147
|
+
return hasClientSecret ? "client_secret_post" : "none";
|
|
23148
|
+
}
|
|
23149
|
+
function applyClientAuthentication(method, clientInformation, headers, params) {
|
|
23150
|
+
const { client_id, client_secret } = clientInformation;
|
|
23151
|
+
switch (method) {
|
|
23152
|
+
case "client_secret_basic":
|
|
23153
|
+
applyBasicAuth(client_id, client_secret, headers);
|
|
23154
|
+
return;
|
|
23155
|
+
case "client_secret_post":
|
|
23156
|
+
applyPostAuth(client_id, client_secret, params);
|
|
23157
|
+
return;
|
|
23158
|
+
case "none":
|
|
23159
|
+
applyPublicAuth(client_id, params);
|
|
23160
|
+
return;
|
|
23161
|
+
default:
|
|
23162
|
+
throw new Error(`Unsupported client authentication method: ${method}`);
|
|
23163
|
+
}
|
|
23164
|
+
}
|
|
23165
|
+
function applyBasicAuth(clientId, clientSecret, headers) {
|
|
23166
|
+
if (!clientSecret) {
|
|
23167
|
+
throw new Error("client_secret_basic authentication requires a client_secret");
|
|
23168
|
+
}
|
|
23169
|
+
const credentials = btoa(`${clientId}:${clientSecret}`);
|
|
23170
|
+
headers.set("Authorization", `Basic ${credentials}`);
|
|
23171
|
+
}
|
|
23172
|
+
function applyPostAuth(clientId, clientSecret, params) {
|
|
23173
|
+
params.set("client_id", clientId);
|
|
23174
|
+
if (clientSecret) {
|
|
23175
|
+
params.set("client_secret", clientSecret);
|
|
23176
|
+
}
|
|
23177
|
+
}
|
|
23178
|
+
function applyPublicAuth(clientId, params) {
|
|
23179
|
+
params.set("client_id", clientId);
|
|
23180
|
+
}
|
|
23181
|
+
async function parseErrorResponse(input) {
|
|
23182
|
+
const statusCode = input instanceof Response ? input.status : void 0;
|
|
23183
|
+
const body = input instanceof Response ? await input.text() : input;
|
|
23184
|
+
try {
|
|
23185
|
+
const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
|
|
23186
|
+
const { error: error2, error_description, error_uri } = result;
|
|
23187
|
+
const errorClass = OAUTH_ERRORS[error2] || ServerError;
|
|
23188
|
+
return new errorClass(error_description || "", error_uri);
|
|
23189
|
+
} catch (error2) {
|
|
23190
|
+
const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error2}. Raw body: ${body}`;
|
|
23191
|
+
return new ServerError(errorMessage);
|
|
23192
|
+
}
|
|
23193
|
+
}
|
|
23194
|
+
async function auth(provider, options) {
|
|
23195
|
+
try {
|
|
23196
|
+
return await authInternal(provider, options);
|
|
23197
|
+
} catch (error2) {
|
|
23198
|
+
if (error2 instanceof InvalidClientError || error2 instanceof UnauthorizedClientError) {
|
|
23199
|
+
await provider.invalidateCredentials?.("all");
|
|
23200
|
+
return await authInternal(provider, options);
|
|
23201
|
+
} else if (error2 instanceof InvalidGrantError) {
|
|
23202
|
+
await provider.invalidateCredentials?.("tokens");
|
|
23203
|
+
return await authInternal(provider, options);
|
|
23204
|
+
}
|
|
23205
|
+
throw error2;
|
|
23206
|
+
}
|
|
23207
|
+
}
|
|
23208
|
+
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
|
|
23209
|
+
const cachedState = await provider.discoveryState?.();
|
|
23210
|
+
let resourceMetadata;
|
|
23211
|
+
let authorizationServerUrl;
|
|
23212
|
+
let metadata;
|
|
23213
|
+
let effectiveResourceMetadataUrl = resourceMetadataUrl;
|
|
23214
|
+
if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
|
|
23215
|
+
effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
|
|
23216
|
+
}
|
|
23217
|
+
if (cachedState?.authorizationServerUrl) {
|
|
23218
|
+
authorizationServerUrl = cachedState.authorizationServerUrl;
|
|
23219
|
+
resourceMetadata = cachedState.resourceMetadata;
|
|
23220
|
+
metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
|
|
23221
|
+
if (!resourceMetadata) {
|
|
23222
|
+
try {
|
|
23223
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
|
|
23224
|
+
} catch {
|
|
23225
|
+
}
|
|
23226
|
+
}
|
|
23227
|
+
if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
|
|
23228
|
+
await provider.saveDiscoveryState?.({
|
|
23229
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
23230
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
23231
|
+
resourceMetadata,
|
|
23232
|
+
authorizationServerMetadata: metadata
|
|
23233
|
+
});
|
|
23234
|
+
}
|
|
23235
|
+
} else {
|
|
23236
|
+
const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
|
|
23237
|
+
authorizationServerUrl = serverInfo.authorizationServerUrl;
|
|
23238
|
+
metadata = serverInfo.authorizationServerMetadata;
|
|
23239
|
+
resourceMetadata = serverInfo.resourceMetadata;
|
|
23240
|
+
await provider.saveDiscoveryState?.({
|
|
23241
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
23242
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
23243
|
+
resourceMetadata,
|
|
23244
|
+
authorizationServerMetadata: metadata
|
|
23245
|
+
});
|
|
23246
|
+
}
|
|
23247
|
+
const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
|
|
23248
|
+
const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
|
|
23249
|
+
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
23250
|
+
if (!clientInformation) {
|
|
23251
|
+
if (authorizationCode !== void 0) {
|
|
23252
|
+
throw new Error("Existing OAuth client information is required when exchanging an authorization code");
|
|
23253
|
+
}
|
|
23254
|
+
const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
|
|
23255
|
+
const clientMetadataUrl = provider.clientMetadataUrl;
|
|
23256
|
+
if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) {
|
|
23257
|
+
throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
|
|
23258
|
+
}
|
|
23259
|
+
const shouldUseUrlBasedClientId = supportsUrlBasedClientId && clientMetadataUrl;
|
|
23260
|
+
if (shouldUseUrlBasedClientId) {
|
|
23261
|
+
clientInformation = {
|
|
23262
|
+
client_id: clientMetadataUrl
|
|
23263
|
+
};
|
|
23264
|
+
await provider.saveClientInformation?.(clientInformation);
|
|
23265
|
+
} else {
|
|
23266
|
+
if (!provider.saveClientInformation) {
|
|
23267
|
+
throw new Error("OAuth client information must be saveable for dynamic registration");
|
|
23268
|
+
}
|
|
23269
|
+
const fullInformation = await registerClient(authorizationServerUrl, {
|
|
23270
|
+
metadata,
|
|
23271
|
+
clientMetadata: provider.clientMetadata,
|
|
23272
|
+
scope: resolvedScope,
|
|
23273
|
+
fetchFn
|
|
23274
|
+
});
|
|
23275
|
+
await provider.saveClientInformation(fullInformation);
|
|
23276
|
+
clientInformation = fullInformation;
|
|
23277
|
+
}
|
|
23278
|
+
}
|
|
23279
|
+
const nonInteractiveFlow = !provider.redirectUrl;
|
|
23280
|
+
if (authorizationCode !== void 0 || nonInteractiveFlow) {
|
|
23281
|
+
const tokens2 = await fetchToken(provider, authorizationServerUrl, {
|
|
23282
|
+
metadata,
|
|
23283
|
+
resource,
|
|
23284
|
+
authorizationCode,
|
|
23285
|
+
fetchFn
|
|
23286
|
+
});
|
|
23287
|
+
await provider.saveTokens(tokens2);
|
|
23288
|
+
return "AUTHORIZED";
|
|
23289
|
+
}
|
|
23290
|
+
const tokens = await provider.tokens();
|
|
23291
|
+
if (tokens?.refresh_token) {
|
|
23292
|
+
try {
|
|
23293
|
+
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
23294
|
+
metadata,
|
|
23295
|
+
clientInformation,
|
|
23296
|
+
refreshToken: tokens.refresh_token,
|
|
23297
|
+
resource,
|
|
23298
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
23299
|
+
fetchFn
|
|
23300
|
+
});
|
|
23301
|
+
await provider.saveTokens(newTokens);
|
|
23302
|
+
return "AUTHORIZED";
|
|
23303
|
+
} catch (error2) {
|
|
23304
|
+
if (!(error2 instanceof OAuthError) || error2 instanceof ServerError) {
|
|
23305
|
+
} else {
|
|
23306
|
+
throw error2;
|
|
23307
|
+
}
|
|
23308
|
+
}
|
|
23309
|
+
}
|
|
23310
|
+
const state = provider.state ? await provider.state() : void 0;
|
|
23311
|
+
const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
|
|
23312
|
+
metadata,
|
|
23313
|
+
clientInformation,
|
|
23314
|
+
state,
|
|
23315
|
+
redirectUrl: provider.redirectUrl,
|
|
23316
|
+
scope: resolvedScope,
|
|
23317
|
+
resource
|
|
23318
|
+
});
|
|
23319
|
+
await provider.saveCodeVerifier(codeVerifier);
|
|
23320
|
+
await provider.redirectToAuthorization(authorizationUrl);
|
|
23321
|
+
return "REDIRECT";
|
|
23322
|
+
}
|
|
23323
|
+
function isHttpsUrl(value) {
|
|
23324
|
+
if (!value)
|
|
23325
|
+
return false;
|
|
23326
|
+
try {
|
|
23327
|
+
const url2 = new URL(value);
|
|
23328
|
+
return url2.protocol === "https:" && url2.pathname !== "/";
|
|
23329
|
+
} catch {
|
|
23330
|
+
return false;
|
|
23331
|
+
}
|
|
23332
|
+
}
|
|
23333
|
+
async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
23334
|
+
const defaultResource = resourceUrlFromServerUrl(serverUrl);
|
|
23335
|
+
if (provider.validateResourceURL) {
|
|
23336
|
+
return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
|
|
23337
|
+
}
|
|
23338
|
+
if (!resourceMetadata) {
|
|
23339
|
+
return void 0;
|
|
23340
|
+
}
|
|
23341
|
+
if (!checkResourceAllowed({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource })) {
|
|
23342
|
+
throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
|
|
23343
|
+
}
|
|
23344
|
+
return new URL(resourceMetadata.resource);
|
|
23345
|
+
}
|
|
23346
|
+
function extractWWWAuthenticateParams(res) {
|
|
23347
|
+
const authenticateHeader = res.headers.get("WWW-Authenticate");
|
|
23348
|
+
if (!authenticateHeader) {
|
|
23349
|
+
return {};
|
|
23350
|
+
}
|
|
23351
|
+
const [type, scheme] = authenticateHeader.split(" ");
|
|
23352
|
+
if (type.toLowerCase() !== "bearer" || !scheme) {
|
|
23353
|
+
return {};
|
|
23354
|
+
}
|
|
23355
|
+
const resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || void 0;
|
|
23356
|
+
let resourceMetadataUrl;
|
|
23357
|
+
if (resourceMetadataMatch) {
|
|
23358
|
+
try {
|
|
23359
|
+
resourceMetadataUrl = new URL(resourceMetadataMatch);
|
|
23360
|
+
} catch {
|
|
23361
|
+
}
|
|
23362
|
+
}
|
|
23363
|
+
const scope = extractFieldFromWwwAuth(res, "scope") || void 0;
|
|
23364
|
+
const error2 = extractFieldFromWwwAuth(res, "error") || void 0;
|
|
23365
|
+
return {
|
|
23366
|
+
resourceMetadataUrl,
|
|
23367
|
+
scope,
|
|
23368
|
+
error: error2
|
|
23369
|
+
};
|
|
23370
|
+
}
|
|
23371
|
+
function extractFieldFromWwwAuth(response, fieldName) {
|
|
23372
|
+
const wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
23373
|
+
if (!wwwAuthHeader) {
|
|
23374
|
+
return null;
|
|
23375
|
+
}
|
|
23376
|
+
const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
|
|
23377
|
+
const match = wwwAuthHeader.match(pattern);
|
|
23378
|
+
if (match) {
|
|
23379
|
+
return match[1] || match[2];
|
|
23380
|
+
}
|
|
23381
|
+
return null;
|
|
23382
|
+
}
|
|
23383
|
+
async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
|
|
23384
|
+
const response = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
|
|
23385
|
+
protocolVersion: opts?.protocolVersion,
|
|
23386
|
+
metadataUrl: opts?.resourceMetadataUrl
|
|
23387
|
+
});
|
|
23388
|
+
if (!response || response.status === 404) {
|
|
23389
|
+
await response?.body?.cancel();
|
|
23390
|
+
throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
|
|
23391
|
+
}
|
|
23392
|
+
if (!response.ok) {
|
|
23393
|
+
await response.body?.cancel();
|
|
23394
|
+
throw new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
|
|
23395
|
+
}
|
|
23396
|
+
return OAuthProtectedResourceMetadataSchema.parse(await response.json());
|
|
23397
|
+
}
|
|
23398
|
+
async function fetchWithCorsRetry(url2, headers, fetchFn = fetch) {
|
|
23399
|
+
try {
|
|
23400
|
+
return await fetchFn(url2, { headers });
|
|
23401
|
+
} catch (error2) {
|
|
23402
|
+
if (error2 instanceof TypeError) {
|
|
23403
|
+
if (headers) {
|
|
23404
|
+
return fetchWithCorsRetry(url2, void 0, fetchFn);
|
|
23405
|
+
} else {
|
|
23406
|
+
return void 0;
|
|
23407
|
+
}
|
|
23408
|
+
}
|
|
23409
|
+
throw error2;
|
|
23410
|
+
}
|
|
23411
|
+
}
|
|
23412
|
+
function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
|
|
23413
|
+
if (pathname.endsWith("/")) {
|
|
23414
|
+
pathname = pathname.slice(0, -1);
|
|
23415
|
+
}
|
|
23416
|
+
return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
|
|
23417
|
+
}
|
|
23418
|
+
async function tryMetadataDiscovery(url2, protocolVersion, fetchFn = fetch) {
|
|
23419
|
+
const headers = {
|
|
23420
|
+
"MCP-Protocol-Version": protocolVersion
|
|
23421
|
+
};
|
|
23422
|
+
return await fetchWithCorsRetry(url2, headers, fetchFn);
|
|
23423
|
+
}
|
|
23424
|
+
function shouldAttemptFallback(response, pathname) {
|
|
23425
|
+
return !response || response.status >= 400 && response.status < 500 && pathname !== "/";
|
|
23426
|
+
}
|
|
23427
|
+
async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
|
|
23428
|
+
const issuer = new URL(serverUrl);
|
|
23429
|
+
const protocolVersion = opts?.protocolVersion ?? LATEST_PROTOCOL_VERSION;
|
|
23430
|
+
let url2;
|
|
23431
|
+
if (opts?.metadataUrl) {
|
|
23432
|
+
url2 = new URL(opts.metadataUrl);
|
|
23433
|
+
} else {
|
|
23434
|
+
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
|
|
23435
|
+
url2 = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
|
|
23436
|
+
url2.search = issuer.search;
|
|
23437
|
+
}
|
|
23438
|
+
let response = await tryMetadataDiscovery(url2, protocolVersion, fetchFn);
|
|
23439
|
+
if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) {
|
|
23440
|
+
const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
|
|
23441
|
+
response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
|
|
23442
|
+
}
|
|
23443
|
+
return response;
|
|
23444
|
+
}
|
|
23445
|
+
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
23446
|
+
const url2 = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
|
23447
|
+
const hasPath = url2.pathname !== "/";
|
|
23448
|
+
const urlsToTry = [];
|
|
23449
|
+
if (!hasPath) {
|
|
23450
|
+
urlsToTry.push({
|
|
23451
|
+
url: new URL("/.well-known/oauth-authorization-server", url2.origin),
|
|
23452
|
+
type: "oauth"
|
|
23453
|
+
});
|
|
23454
|
+
urlsToTry.push({
|
|
23455
|
+
url: new URL(`/.well-known/openid-configuration`, url2.origin),
|
|
23456
|
+
type: "oidc"
|
|
23457
|
+
});
|
|
23458
|
+
return urlsToTry;
|
|
23459
|
+
}
|
|
23460
|
+
let pathname = url2.pathname;
|
|
23461
|
+
if (pathname.endsWith("/")) {
|
|
23462
|
+
pathname = pathname.slice(0, -1);
|
|
23463
|
+
}
|
|
23464
|
+
urlsToTry.push({
|
|
23465
|
+
url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url2.origin),
|
|
23466
|
+
type: "oauth"
|
|
23467
|
+
});
|
|
23468
|
+
urlsToTry.push({
|
|
23469
|
+
url: new URL(`/.well-known/openid-configuration${pathname}`, url2.origin),
|
|
23470
|
+
type: "oidc"
|
|
23471
|
+
});
|
|
23472
|
+
urlsToTry.push({
|
|
23473
|
+
url: new URL(`${pathname}/.well-known/openid-configuration`, url2.origin),
|
|
23474
|
+
type: "oidc"
|
|
23475
|
+
});
|
|
23476
|
+
return urlsToTry;
|
|
23477
|
+
}
|
|
23478
|
+
async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
|
|
23479
|
+
const headers = {
|
|
23480
|
+
"MCP-Protocol-Version": protocolVersion,
|
|
23481
|
+
Accept: "application/json"
|
|
23482
|
+
};
|
|
23483
|
+
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
23484
|
+
for (const { url: endpointUrl, type } of urlsToTry) {
|
|
23485
|
+
const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
|
23486
|
+
if (!response) {
|
|
23487
|
+
continue;
|
|
23488
|
+
}
|
|
23489
|
+
if (!response.ok) {
|
|
23490
|
+
await response.body?.cancel();
|
|
23491
|
+
if (response.status >= 400 && response.status < 500) {
|
|
23492
|
+
continue;
|
|
23493
|
+
}
|
|
23494
|
+
throw new Error(`HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
|
|
23495
|
+
}
|
|
23496
|
+
if (type === "oauth") {
|
|
23497
|
+
return OAuthMetadataSchema.parse(await response.json());
|
|
23498
|
+
} else {
|
|
23499
|
+
return OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
|
|
23500
|
+
}
|
|
23501
|
+
}
|
|
23502
|
+
return void 0;
|
|
23503
|
+
}
|
|
23504
|
+
async function discoverOAuthServerInfo(serverUrl, opts) {
|
|
23505
|
+
let resourceMetadata;
|
|
23506
|
+
let authorizationServerUrl;
|
|
23507
|
+
try {
|
|
23508
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
|
|
23509
|
+
if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
|
|
23510
|
+
authorizationServerUrl = resourceMetadata.authorization_servers[0];
|
|
23511
|
+
}
|
|
23512
|
+
} catch {
|
|
23513
|
+
}
|
|
23514
|
+
if (!authorizationServerUrl) {
|
|
23515
|
+
authorizationServerUrl = String(new URL("/", serverUrl));
|
|
23516
|
+
}
|
|
23517
|
+
const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
|
|
23518
|
+
return {
|
|
23519
|
+
authorizationServerUrl,
|
|
23520
|
+
authorizationServerMetadata,
|
|
23521
|
+
resourceMetadata
|
|
23522
|
+
};
|
|
23523
|
+
}
|
|
23524
|
+
async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
|
|
23525
|
+
let authorizationUrl;
|
|
23526
|
+
if (metadata) {
|
|
23527
|
+
authorizationUrl = new URL(metadata.authorization_endpoint);
|
|
23528
|
+
if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
|
|
23529
|
+
throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
|
|
23530
|
+
}
|
|
23531
|
+
if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
|
|
23532
|
+
throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
|
|
23533
|
+
}
|
|
23534
|
+
} else {
|
|
23535
|
+
authorizationUrl = new URL("/authorize", authorizationServerUrl);
|
|
23536
|
+
}
|
|
23537
|
+
const challenge = await pkceChallenge();
|
|
23538
|
+
const codeVerifier = challenge.code_verifier;
|
|
23539
|
+
const codeChallenge = challenge.code_challenge;
|
|
23540
|
+
authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
|
|
23541
|
+
authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
|
|
23542
|
+
authorizationUrl.searchParams.set("code_challenge", codeChallenge);
|
|
23543
|
+
authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
|
|
23544
|
+
authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
|
|
23545
|
+
if (state) {
|
|
23546
|
+
authorizationUrl.searchParams.set("state", state);
|
|
23547
|
+
}
|
|
23548
|
+
if (scope) {
|
|
23549
|
+
authorizationUrl.searchParams.set("scope", scope);
|
|
23550
|
+
}
|
|
23551
|
+
if (scope?.includes("offline_access")) {
|
|
23552
|
+
authorizationUrl.searchParams.append("prompt", "consent");
|
|
23553
|
+
}
|
|
23554
|
+
if (resource) {
|
|
23555
|
+
authorizationUrl.searchParams.set("resource", resource.href);
|
|
23556
|
+
}
|
|
23557
|
+
return { authorizationUrl, codeVerifier };
|
|
23558
|
+
}
|
|
23559
|
+
function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
|
|
23560
|
+
return new URLSearchParams({
|
|
23561
|
+
grant_type: "authorization_code",
|
|
23562
|
+
code: authorizationCode,
|
|
23563
|
+
code_verifier: codeVerifier,
|
|
23564
|
+
redirect_uri: String(redirectUri)
|
|
23565
|
+
});
|
|
23566
|
+
}
|
|
23567
|
+
async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
|
|
23568
|
+
const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
|
|
23569
|
+
const headers = new Headers({
|
|
23570
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
23571
|
+
Accept: "application/json"
|
|
23572
|
+
});
|
|
23573
|
+
if (resource) {
|
|
23574
|
+
tokenRequestParams.set("resource", resource.href);
|
|
23575
|
+
}
|
|
23576
|
+
if (addClientAuthentication) {
|
|
23577
|
+
await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
|
|
23578
|
+
} else if (clientInformation) {
|
|
23579
|
+
const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];
|
|
23580
|
+
const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
|
|
23581
|
+
applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
|
|
23582
|
+
}
|
|
23583
|
+
const response = await (fetchFn ?? fetch)(tokenUrl, {
|
|
23584
|
+
method: "POST",
|
|
23585
|
+
headers,
|
|
23586
|
+
body: tokenRequestParams
|
|
23587
|
+
});
|
|
23588
|
+
if (!response.ok) {
|
|
23589
|
+
throw await parseErrorResponse(response);
|
|
23590
|
+
}
|
|
23591
|
+
return OAuthTokensSchema.parse(await response.json());
|
|
23592
|
+
}
|
|
23593
|
+
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
|
23594
|
+
const tokenRequestParams = new URLSearchParams({
|
|
23595
|
+
grant_type: "refresh_token",
|
|
23596
|
+
refresh_token: refreshToken
|
|
23597
|
+
});
|
|
23598
|
+
const tokens = await executeTokenRequest(authorizationServerUrl, {
|
|
23599
|
+
metadata,
|
|
23600
|
+
tokenRequestParams,
|
|
23601
|
+
clientInformation,
|
|
23602
|
+
addClientAuthentication,
|
|
23603
|
+
resource,
|
|
23604
|
+
fetchFn
|
|
23605
|
+
});
|
|
23606
|
+
return { refresh_token: refreshToken, ...tokens };
|
|
23607
|
+
}
|
|
23608
|
+
async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
|
|
23609
|
+
const scope = provider.clientMetadata.scope;
|
|
23610
|
+
let tokenRequestParams;
|
|
23611
|
+
if (provider.prepareTokenRequest) {
|
|
23612
|
+
tokenRequestParams = await provider.prepareTokenRequest(scope);
|
|
23613
|
+
}
|
|
23614
|
+
if (!tokenRequestParams) {
|
|
23615
|
+
if (!authorizationCode) {
|
|
23616
|
+
throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
|
|
23617
|
+
}
|
|
23618
|
+
if (!provider.redirectUrl) {
|
|
23619
|
+
throw new Error("redirectUrl is required for authorization_code flow");
|
|
23620
|
+
}
|
|
23621
|
+
const codeVerifier = await provider.codeVerifier();
|
|
23622
|
+
tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
|
|
23623
|
+
}
|
|
23624
|
+
const clientInformation = await provider.clientInformation();
|
|
23625
|
+
return executeTokenRequest(authorizationServerUrl, {
|
|
23626
|
+
metadata,
|
|
23627
|
+
tokenRequestParams,
|
|
23628
|
+
clientInformation: clientInformation ?? void 0,
|
|
23629
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
23630
|
+
resource,
|
|
23631
|
+
fetchFn
|
|
23632
|
+
});
|
|
23633
|
+
}
|
|
23634
|
+
async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
|
|
23635
|
+
let registrationUrl;
|
|
23636
|
+
if (metadata) {
|
|
23637
|
+
if (!metadata.registration_endpoint) {
|
|
23638
|
+
throw new Error("Incompatible auth server: does not support dynamic client registration");
|
|
23639
|
+
}
|
|
23640
|
+
registrationUrl = new URL(metadata.registration_endpoint);
|
|
23641
|
+
} else {
|
|
23642
|
+
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
23643
|
+
}
|
|
23644
|
+
const response = await (fetchFn ?? fetch)(registrationUrl, {
|
|
23645
|
+
method: "POST",
|
|
23646
|
+
headers: {
|
|
23647
|
+
"Content-Type": "application/json"
|
|
23648
|
+
},
|
|
23649
|
+
body: JSON.stringify({
|
|
23650
|
+
...clientMetadata,
|
|
23651
|
+
...scope !== void 0 ? { scope } : {}
|
|
23652
|
+
})
|
|
23653
|
+
});
|
|
23654
|
+
if (!response.ok) {
|
|
23655
|
+
throw await parseErrorResponse(response);
|
|
23656
|
+
}
|
|
23657
|
+
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
23658
|
+
}
|
|
23659
|
+
|
|
23660
|
+
// node_modules/eventsource-parser/dist/index.js
|
|
23661
|
+
var ParseError = class extends Error {
|
|
23662
|
+
constructor(message, options) {
|
|
23663
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
23664
|
+
}
|
|
23665
|
+
};
|
|
23666
|
+
var LF = 10;
|
|
23667
|
+
var CR = 13;
|
|
23668
|
+
var SPACE = 32;
|
|
23669
|
+
function noop(_arg) {
|
|
23670
|
+
}
|
|
23671
|
+
function createParser(config2) {
|
|
23672
|
+
if (typeof config2 == "function")
|
|
23673
|
+
throw new TypeError(
|
|
23674
|
+
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
23675
|
+
);
|
|
23676
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config2, pendingFragments = [];
|
|
23677
|
+
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
|
|
23678
|
+
function feed(chunk) {
|
|
23679
|
+
if (terminated)
|
|
23680
|
+
throw new Error(
|
|
23681
|
+
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
23682
|
+
);
|
|
23683
|
+
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
23684
|
+
const trailing2 = processLines(chunk);
|
|
23685
|
+
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
23686
|
+
return;
|
|
23687
|
+
}
|
|
23688
|
+
if (chunk.indexOf(`
|
|
23689
|
+
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
23690
|
+
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
23691
|
+
return;
|
|
23692
|
+
}
|
|
23693
|
+
pendingFragments.push(chunk);
|
|
23694
|
+
const input = pendingFragments.join("");
|
|
23695
|
+
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
23696
|
+
const trailing = processLines(input);
|
|
23697
|
+
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
23698
|
+
}
|
|
23699
|
+
function checkBufferSize() {
|
|
23700
|
+
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
23701
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
23702
|
+
type: "max-buffer-size-exceeded"
|
|
23703
|
+
})
|
|
23704
|
+
)));
|
|
23705
|
+
}
|
|
23706
|
+
function processLines(chunk) {
|
|
23707
|
+
let searchIndex = 0;
|
|
23708
|
+
if (chunk.indexOf("\r") === -1) {
|
|
23709
|
+
let lfIndex = chunk.indexOf(`
|
|
23710
|
+
`, searchIndex);
|
|
23711
|
+
for (; lfIndex !== -1; ) {
|
|
23712
|
+
if (searchIndex === lfIndex) {
|
|
23713
|
+
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
23714
|
+
`, searchIndex);
|
|
23715
|
+
continue;
|
|
23716
|
+
}
|
|
23717
|
+
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
23718
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
23719
|
+
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
23720
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
23721
|
+
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
23722
|
+
`, searchIndex);
|
|
23723
|
+
continue;
|
|
23724
|
+
}
|
|
23725
|
+
data = dataLines === 0 ? value : `${data}
|
|
23726
|
+
${value}`, dataLines++;
|
|
23727
|
+
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
23728
|
+
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
23729
|
+
lfIndex
|
|
23730
|
+
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
23731
|
+
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
23732
|
+
`, searchIndex);
|
|
23733
|
+
}
|
|
23734
|
+
return chunk.slice(searchIndex);
|
|
23735
|
+
}
|
|
23736
|
+
for (; searchIndex < chunk.length; ) {
|
|
23737
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
23738
|
+
`, searchIndex);
|
|
23739
|
+
let lineEnd = -1;
|
|
23740
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
|
|
23741
|
+
break;
|
|
23742
|
+
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
23743
|
+
}
|
|
23744
|
+
return chunk.slice(searchIndex);
|
|
23745
|
+
}
|
|
23746
|
+
function parseLine(chunk, start, end) {
|
|
23747
|
+
if (start === end) {
|
|
23748
|
+
dispatchEvent();
|
|
23749
|
+
return;
|
|
23750
|
+
}
|
|
23751
|
+
const firstCharCode = chunk.charCodeAt(start);
|
|
23752
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
23753
|
+
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
23754
|
+
data = dataLines === 0 ? value2 : `${data}
|
|
23755
|
+
${value2}`, dataLines++;
|
|
23756
|
+
return;
|
|
23757
|
+
}
|
|
23758
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
23759
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
23760
|
+
return;
|
|
23761
|
+
}
|
|
23762
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
23763
|
+
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
23764
|
+
id = value2.includes("\0") ? void 0 : value2;
|
|
23765
|
+
return;
|
|
23766
|
+
}
|
|
23767
|
+
if (firstCharCode === 58) {
|
|
23768
|
+
if (onComment) {
|
|
23769
|
+
const line2 = chunk.slice(start, end);
|
|
23770
|
+
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
23771
|
+
}
|
|
23772
|
+
return;
|
|
23773
|
+
}
|
|
23774
|
+
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
23775
|
+
if (fieldSeparatorIndex === -1) {
|
|
23776
|
+
processField(line, "", line);
|
|
23777
|
+
return;
|
|
23778
|
+
}
|
|
23779
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
23780
|
+
processField(field, value, line);
|
|
23781
|
+
}
|
|
23782
|
+
function processField(field, value, line) {
|
|
23783
|
+
switch (field) {
|
|
23784
|
+
case "event":
|
|
23785
|
+
eventType = value || void 0;
|
|
23786
|
+
break;
|
|
23787
|
+
case "data":
|
|
23788
|
+
data = dataLines === 0 ? value : `${data}
|
|
23789
|
+
${value}`, dataLines++;
|
|
23790
|
+
break;
|
|
23791
|
+
case "id":
|
|
23792
|
+
id = value.includes("\0") ? void 0 : value;
|
|
23793
|
+
break;
|
|
23794
|
+
case "retry":
|
|
23795
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
23796
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
23797
|
+
type: "invalid-retry",
|
|
23798
|
+
value,
|
|
23799
|
+
line
|
|
23800
|
+
})
|
|
23801
|
+
);
|
|
23802
|
+
break;
|
|
23803
|
+
default:
|
|
23804
|
+
onError(
|
|
23805
|
+
new ParseError(
|
|
23806
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
23807
|
+
{ type: "unknown-field", field, value, line }
|
|
23808
|
+
)
|
|
23809
|
+
);
|
|
23810
|
+
break;
|
|
23811
|
+
}
|
|
23812
|
+
}
|
|
23813
|
+
function dispatchEvent() {
|
|
23814
|
+
dataLines > 0 && onEvent({
|
|
23815
|
+
id,
|
|
23816
|
+
event: eventType,
|
|
23817
|
+
data
|
|
23818
|
+
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
20990
23819
|
}
|
|
20991
|
-
|
|
20992
|
-
|
|
20993
|
-
|
|
20994
|
-
|
|
20995
|
-
if (!schema) {
|
|
20996
|
-
const near = known.map((candidate) => ({ candidate, distance: editDistance(key.toLowerCase(), candidate.toLowerCase()) })).filter(({ candidate, distance }) => distance <= (candidate.length <= 4 ? 1 : 2)).sort((a, b) => a.distance - b.distance)[0];
|
|
20997
|
-
return near ? `Unknown argument "${key}" for ${tool.name}. Did you mean "${near.candidate}"?` : `Unknown argument "${key}" for ${tool.name}. Accepted: ${known.join(", ") || "(none)"}`;
|
|
23820
|
+
function reset(options = {}) {
|
|
23821
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
23822
|
+
const incompleteLine = pendingFragments.join("");
|
|
23823
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
20998
23824
|
}
|
|
20999
|
-
|
|
21000
|
-
const problem = typeError(key, schema, value);
|
|
21001
|
-
if (problem) return problem;
|
|
23825
|
+
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
|
|
21002
23826
|
}
|
|
21003
|
-
return
|
|
23827
|
+
return { feed, reset };
|
|
23828
|
+
}
|
|
23829
|
+
function isDataPrefix(chunk, i, firstCharCode) {
|
|
23830
|
+
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
23831
|
+
}
|
|
23832
|
+
function isEventPrefix(chunk, i, firstCharCode) {
|
|
23833
|
+
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
21004
23834
|
}
|
|
21005
23835
|
|
|
21006
|
-
//
|
|
21007
|
-
var
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
|
|
21013
|
-
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
|
|
21017
|
-
|
|
21018
|
-
|
|
21019
|
-
|
|
23836
|
+
// node_modules/eventsource-parser/dist/stream.js
|
|
23837
|
+
var EventSourceParserStream = class extends TransformStream {
|
|
23838
|
+
constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
|
|
23839
|
+
let parser;
|
|
23840
|
+
super({
|
|
23841
|
+
start(controller) {
|
|
23842
|
+
parser = createParser({
|
|
23843
|
+
onEvent: (event) => {
|
|
23844
|
+
controller.enqueue(event);
|
|
23845
|
+
},
|
|
23846
|
+
onError(error2) {
|
|
23847
|
+
typeof onError == "function" && onError(error2), (onError === "terminate" || error2.type === "max-buffer-size-exceeded") && controller.error(error2);
|
|
23848
|
+
},
|
|
23849
|
+
onRetry,
|
|
23850
|
+
onComment,
|
|
23851
|
+
maxBufferSize
|
|
23852
|
+
});
|
|
23853
|
+
},
|
|
23854
|
+
transform(chunk) {
|
|
23855
|
+
parser.feed(chunk);
|
|
23856
|
+
}
|
|
23857
|
+
});
|
|
21020
23858
|
}
|
|
21021
|
-
|
|
21022
|
-
blocks.push({ type: "text", text });
|
|
21023
|
-
return blocks;
|
|
21024
|
-
}
|
|
23859
|
+
};
|
|
21025
23860
|
|
|
21026
|
-
//
|
|
21027
|
-
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
|
|
23861
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
|
|
23862
|
+
var DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
|
|
23863
|
+
initialReconnectionDelay: 1e3,
|
|
23864
|
+
maxReconnectionDelay: 3e4,
|
|
23865
|
+
reconnectionDelayGrowFactor: 1.5,
|
|
23866
|
+
maxRetries: 2
|
|
23867
|
+
};
|
|
23868
|
+
var StreamableHTTPError = class extends Error {
|
|
23869
|
+
constructor(code, message) {
|
|
23870
|
+
super(`Streamable HTTP error: ${message}`);
|
|
23871
|
+
this.code = code;
|
|
23872
|
+
}
|
|
23873
|
+
};
|
|
23874
|
+
var StreamableHTTPClientTransport = class {
|
|
23875
|
+
constructor(url2, opts) {
|
|
23876
|
+
this._hasCompletedAuthFlow = false;
|
|
23877
|
+
this._url = url2;
|
|
23878
|
+
this._resourceMetadataUrl = void 0;
|
|
23879
|
+
this._scope = void 0;
|
|
23880
|
+
this._requestInit = opts?.requestInit;
|
|
23881
|
+
this._authProvider = opts?.authProvider;
|
|
23882
|
+
this._fetch = opts?.fetch;
|
|
23883
|
+
this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
|
|
23884
|
+
this._sessionId = opts?.sessionId;
|
|
23885
|
+
this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
|
|
23886
|
+
}
|
|
23887
|
+
async _authThenStart() {
|
|
23888
|
+
if (!this._authProvider) {
|
|
23889
|
+
throw new UnauthorizedError("No auth provider");
|
|
23890
|
+
}
|
|
23891
|
+
let result;
|
|
21035
23892
|
try {
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
23893
|
+
result = await auth(this._authProvider, {
|
|
23894
|
+
serverUrl: this._url,
|
|
23895
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
23896
|
+
scope: this._scope,
|
|
23897
|
+
fetchFn: this._fetchWithInit
|
|
23898
|
+
});
|
|
23899
|
+
} catch (error2) {
|
|
23900
|
+
this.onerror?.(error2);
|
|
23901
|
+
throw error2;
|
|
23902
|
+
}
|
|
23903
|
+
if (result !== "AUTHORIZED") {
|
|
23904
|
+
throw new UnauthorizedError();
|
|
21039
23905
|
}
|
|
23906
|
+
return await this._startOrAuthSse({ resumptionToken: void 0 });
|
|
21040
23907
|
}
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
|
|
21046
|
-
|
|
21047
|
-
let entries;
|
|
21048
|
-
try {
|
|
21049
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
21050
|
-
} catch {
|
|
21051
|
-
continue;
|
|
23908
|
+
async _commonHeaders() {
|
|
23909
|
+
const headers = {};
|
|
23910
|
+
if (this._authProvider) {
|
|
23911
|
+
const tokens = await this._authProvider.tokens();
|
|
23912
|
+
if (tokens) {
|
|
23913
|
+
headers["Authorization"] = `Bearer ${tokens.access_token}`;
|
|
21052
23914
|
}
|
|
21053
|
-
|
|
21054
|
-
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
|
|
23915
|
+
}
|
|
23916
|
+
if (this._sessionId) {
|
|
23917
|
+
headers["mcp-session-id"] = this._sessionId;
|
|
23918
|
+
}
|
|
23919
|
+
if (this._protocolVersion) {
|
|
23920
|
+
headers["mcp-protocol-version"] = this._protocolVersion;
|
|
23921
|
+
}
|
|
23922
|
+
const extraHeaders = normalizeHeaders(this._requestInit?.headers);
|
|
23923
|
+
return new Headers({
|
|
23924
|
+
...headers,
|
|
23925
|
+
...extraHeaders
|
|
23926
|
+
});
|
|
23927
|
+
}
|
|
23928
|
+
async _startOrAuthSse(options) {
|
|
23929
|
+
const { resumptionToken } = options;
|
|
23930
|
+
try {
|
|
23931
|
+
const headers = await this._commonHeaders();
|
|
23932
|
+
headers.set("Accept", "text/event-stream");
|
|
23933
|
+
if (resumptionToken) {
|
|
23934
|
+
headers.set("last-event-id", resumptionToken);
|
|
23935
|
+
}
|
|
23936
|
+
const response = await (this._fetch ?? fetch)(this._url, {
|
|
23937
|
+
method: "GET",
|
|
23938
|
+
headers,
|
|
23939
|
+
signal: this._abortController?.signal
|
|
23940
|
+
});
|
|
23941
|
+
if (!response.ok) {
|
|
23942
|
+
await response.body?.cancel();
|
|
23943
|
+
if (response.status === 401 && this._authProvider) {
|
|
23944
|
+
return await this._authThenStart();
|
|
23945
|
+
}
|
|
23946
|
+
if (response.status === 405) {
|
|
23947
|
+
return;
|
|
23948
|
+
}
|
|
23949
|
+
throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
|
|
21058
23950
|
}
|
|
23951
|
+
this._handleSseStream(response.body, options, true);
|
|
23952
|
+
} catch (error2) {
|
|
23953
|
+
this.onerror?.(error2);
|
|
23954
|
+
throw error2;
|
|
21059
23955
|
}
|
|
21060
|
-
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
23956
|
+
}
|
|
23957
|
+
/**
|
|
23958
|
+
* Calculates the next reconnection delay using backoff algorithm
|
|
23959
|
+
*
|
|
23960
|
+
* @param attempt Current reconnection attempt count for the specific stream
|
|
23961
|
+
* @returns Time to wait in milliseconds before next reconnection attempt
|
|
23962
|
+
*/
|
|
23963
|
+
_getNextReconnectionDelay(attempt) {
|
|
23964
|
+
if (this._serverRetryMs !== void 0) {
|
|
23965
|
+
return this._serverRetryMs;
|
|
21064
23966
|
}
|
|
21065
|
-
|
|
21066
|
-
|
|
23967
|
+
const initialDelay = this._reconnectionOptions.initialReconnectionDelay;
|
|
23968
|
+
const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;
|
|
23969
|
+
const maxDelay = this._reconnectionOptions.maxReconnectionDelay;
|
|
23970
|
+
return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
|
|
21067
23971
|
}
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
if (x === void 0) throw new Error(`${value}: step "${m[1]}" has no "${m[2].slice(1)}". It returned ${JSON.stringify(refs.get(m[1])).slice(0, 300)}`);
|
|
23972
|
+
/**
|
|
23973
|
+
* Schedule a reconnection attempt using server-provided retry interval or backoff
|
|
23974
|
+
*
|
|
23975
|
+
* @param lastEventId The ID of the last received event for resumability
|
|
23976
|
+
* @param attemptCount Current reconnection attempt count for this specific stream
|
|
23977
|
+
*/
|
|
23978
|
+
_scheduleReconnection(options, attemptCount = 0) {
|
|
23979
|
+
const maxRetries = this._reconnectionOptions.maxRetries;
|
|
23980
|
+
if (attemptCount >= maxRetries) {
|
|
23981
|
+
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
23982
|
+
return;
|
|
21080
23983
|
}
|
|
21081
|
-
|
|
23984
|
+
const delay = this._getNextReconnectionDelay(attemptCount);
|
|
23985
|
+
this._reconnectionTimeout = setTimeout(() => {
|
|
23986
|
+
this._startOrAuthSse(options).catch((error2) => {
|
|
23987
|
+
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
23988
|
+
this._scheduleReconnection(options, attemptCount + 1);
|
|
23989
|
+
});
|
|
23990
|
+
}, delay);
|
|
21082
23991
|
}
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
|
|
23992
|
+
_handleSseStream(stream, options, isReconnectable) {
|
|
23993
|
+
if (!stream) {
|
|
23994
|
+
return;
|
|
23995
|
+
}
|
|
23996
|
+
const { onresumptiontoken, replayMessageId } = options;
|
|
23997
|
+
let lastEventId;
|
|
23998
|
+
let hasPrimingEvent = false;
|
|
23999
|
+
let receivedResponse = false;
|
|
24000
|
+
const processStream = async () => {
|
|
24001
|
+
try {
|
|
24002
|
+
const reader = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({
|
|
24003
|
+
onRetry: (retryMs) => {
|
|
24004
|
+
this._serverRetryMs = retryMs;
|
|
24005
|
+
}
|
|
24006
|
+
})).getReader();
|
|
24007
|
+
while (true) {
|
|
24008
|
+
const { value: event, done } = await reader.read();
|
|
24009
|
+
if (done) {
|
|
24010
|
+
break;
|
|
24011
|
+
}
|
|
24012
|
+
if (event.id) {
|
|
24013
|
+
lastEventId = event.id;
|
|
24014
|
+
hasPrimingEvent = true;
|
|
24015
|
+
onresumptiontoken?.(event.id);
|
|
24016
|
+
}
|
|
24017
|
+
if (!event.data) {
|
|
24018
|
+
continue;
|
|
24019
|
+
}
|
|
24020
|
+
if (!event.event || event.event === "message") {
|
|
24021
|
+
try {
|
|
24022
|
+
const message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
|
24023
|
+
if (isJSONRPCResultResponse(message)) {
|
|
24024
|
+
receivedResponse = true;
|
|
24025
|
+
if (replayMessageId !== void 0) {
|
|
24026
|
+
message.id = replayMessageId;
|
|
24027
|
+
}
|
|
24028
|
+
}
|
|
24029
|
+
this.onmessage?.(message);
|
|
24030
|
+
} catch (error2) {
|
|
24031
|
+
this.onerror?.(error2);
|
|
24032
|
+
}
|
|
24033
|
+
}
|
|
24034
|
+
}
|
|
24035
|
+
const canResume = isReconnectable || hasPrimingEvent;
|
|
24036
|
+
const needsReconnect = canResume && !receivedResponse;
|
|
24037
|
+
if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
|
|
24038
|
+
this._scheduleReconnection({
|
|
24039
|
+
resumptionToken: lastEventId,
|
|
24040
|
+
onresumptiontoken,
|
|
24041
|
+
replayMessageId
|
|
24042
|
+
}, 0);
|
|
24043
|
+
}
|
|
24044
|
+
} catch (error2) {
|
|
24045
|
+
this.onerror?.(new Error(`SSE stream disconnected: ${error2}`));
|
|
24046
|
+
const canResume = isReconnectable || hasPrimingEvent;
|
|
24047
|
+
const needsReconnect = canResume && !receivedResponse;
|
|
24048
|
+
if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
|
|
24049
|
+
try {
|
|
24050
|
+
this._scheduleReconnection({
|
|
24051
|
+
resumptionToken: lastEventId,
|
|
24052
|
+
onresumptiontoken,
|
|
24053
|
+
replayMessageId
|
|
24054
|
+
}, 0);
|
|
24055
|
+
} catch (error3) {
|
|
24056
|
+
this.onerror?.(new Error(`Failed to reconnect: ${error3 instanceof Error ? error3.message : String(error3)}`));
|
|
24057
|
+
}
|
|
24058
|
+
}
|
|
24059
|
+
}
|
|
24060
|
+
};
|
|
24061
|
+
processStream();
|
|
21086
24062
|
}
|
|
21087
|
-
|
|
24063
|
+
async start() {
|
|
24064
|
+
if (this._abortController) {
|
|
24065
|
+
throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
24066
|
+
}
|
|
24067
|
+
this._abortController = new AbortController();
|
|
24068
|
+
}
|
|
24069
|
+
/**
|
|
24070
|
+
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
|
|
24071
|
+
*/
|
|
24072
|
+
async finishAuth(authorizationCode) {
|
|
24073
|
+
if (!this._authProvider) {
|
|
24074
|
+
throw new UnauthorizedError("No auth provider");
|
|
24075
|
+
}
|
|
24076
|
+
const result = await auth(this._authProvider, {
|
|
24077
|
+
serverUrl: this._url,
|
|
24078
|
+
authorizationCode,
|
|
24079
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
24080
|
+
scope: this._scope,
|
|
24081
|
+
fetchFn: this._fetchWithInit
|
|
24082
|
+
});
|
|
24083
|
+
if (result !== "AUTHORIZED") {
|
|
24084
|
+
throw new UnauthorizedError("Failed to authorize");
|
|
24085
|
+
}
|
|
24086
|
+
}
|
|
24087
|
+
async close() {
|
|
24088
|
+
if (this._reconnectionTimeout) {
|
|
24089
|
+
clearTimeout(this._reconnectionTimeout);
|
|
24090
|
+
this._reconnectionTimeout = void 0;
|
|
24091
|
+
}
|
|
24092
|
+
this._abortController?.abort();
|
|
24093
|
+
this.onclose?.();
|
|
24094
|
+
}
|
|
24095
|
+
async send(message, options) {
|
|
24096
|
+
try {
|
|
24097
|
+
const { resumptionToken, onresumptiontoken } = options || {};
|
|
24098
|
+
if (resumptionToken) {
|
|
24099
|
+
this._startOrAuthSse({ resumptionToken, replayMessageId: isJSONRPCRequest(message) ? message.id : void 0 }).catch((err) => this.onerror?.(err));
|
|
24100
|
+
return;
|
|
24101
|
+
}
|
|
24102
|
+
const headers = await this._commonHeaders();
|
|
24103
|
+
headers.set("content-type", "application/json");
|
|
24104
|
+
headers.set("accept", "application/json, text/event-stream");
|
|
24105
|
+
const init = {
|
|
24106
|
+
...this._requestInit,
|
|
24107
|
+
method: "POST",
|
|
24108
|
+
headers,
|
|
24109
|
+
body: JSON.stringify(message),
|
|
24110
|
+
signal: this._abortController?.signal
|
|
24111
|
+
};
|
|
24112
|
+
const response = await (this._fetch ?? fetch)(this._url, init);
|
|
24113
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
24114
|
+
if (sessionId) {
|
|
24115
|
+
this._sessionId = sessionId;
|
|
24116
|
+
}
|
|
24117
|
+
if (!response.ok) {
|
|
24118
|
+
const text = await response.text().catch(() => null);
|
|
24119
|
+
if (response.status === 401 && this._authProvider) {
|
|
24120
|
+
if (this._hasCompletedAuthFlow) {
|
|
24121
|
+
throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
|
|
24122
|
+
}
|
|
24123
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
24124
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
24125
|
+
this._scope = scope;
|
|
24126
|
+
const result = await auth(this._authProvider, {
|
|
24127
|
+
serverUrl: this._url,
|
|
24128
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
24129
|
+
scope: this._scope,
|
|
24130
|
+
fetchFn: this._fetchWithInit
|
|
24131
|
+
});
|
|
24132
|
+
if (result !== "AUTHORIZED") {
|
|
24133
|
+
throw new UnauthorizedError();
|
|
24134
|
+
}
|
|
24135
|
+
this._hasCompletedAuthFlow = true;
|
|
24136
|
+
return this.send(message);
|
|
24137
|
+
}
|
|
24138
|
+
if (response.status === 403 && this._authProvider) {
|
|
24139
|
+
const { resourceMetadataUrl, scope, error: error2 } = extractWWWAuthenticateParams(response);
|
|
24140
|
+
if (error2 === "insufficient_scope") {
|
|
24141
|
+
const wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
24142
|
+
if (this._lastUpscopingHeader === wwwAuthHeader) {
|
|
24143
|
+
throw new StreamableHTTPError(403, "Server returned 403 after trying upscoping");
|
|
24144
|
+
}
|
|
24145
|
+
if (scope) {
|
|
24146
|
+
this._scope = scope;
|
|
24147
|
+
}
|
|
24148
|
+
if (resourceMetadataUrl) {
|
|
24149
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
24150
|
+
}
|
|
24151
|
+
this._lastUpscopingHeader = wwwAuthHeader ?? void 0;
|
|
24152
|
+
const result = await auth(this._authProvider, {
|
|
24153
|
+
serverUrl: this._url,
|
|
24154
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
24155
|
+
scope: this._scope,
|
|
24156
|
+
fetchFn: this._fetch
|
|
24157
|
+
});
|
|
24158
|
+
if (result !== "AUTHORIZED") {
|
|
24159
|
+
throw new UnauthorizedError();
|
|
24160
|
+
}
|
|
24161
|
+
return this.send(message);
|
|
24162
|
+
}
|
|
24163
|
+
}
|
|
24164
|
+
throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${text}`);
|
|
24165
|
+
}
|
|
24166
|
+
this._hasCompletedAuthFlow = false;
|
|
24167
|
+
this._lastUpscopingHeader = void 0;
|
|
24168
|
+
if (response.status === 202) {
|
|
24169
|
+
await response.body?.cancel();
|
|
24170
|
+
if (isInitializedNotification(message)) {
|
|
24171
|
+
this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => this.onerror?.(err));
|
|
24172
|
+
}
|
|
24173
|
+
return;
|
|
24174
|
+
}
|
|
24175
|
+
const messages = Array.isArray(message) ? message : [message];
|
|
24176
|
+
const hasRequests = messages.filter((msg) => "method" in msg && "id" in msg && msg.id !== void 0).length > 0;
|
|
24177
|
+
const contentType = response.headers.get("content-type");
|
|
24178
|
+
if (hasRequests) {
|
|
24179
|
+
if (contentType?.includes("text/event-stream")) {
|
|
24180
|
+
this._handleSseStream(response.body, { onresumptiontoken }, false);
|
|
24181
|
+
} else if (contentType?.includes("application/json")) {
|
|
24182
|
+
const data = await response.json();
|
|
24183
|
+
const responseMessages = Array.isArray(data) ? data.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(data)];
|
|
24184
|
+
for (const msg of responseMessages) {
|
|
24185
|
+
this.onmessage?.(msg);
|
|
24186
|
+
}
|
|
24187
|
+
} else {
|
|
24188
|
+
await response.body?.cancel();
|
|
24189
|
+
throw new StreamableHTTPError(-1, `Unexpected content type: ${contentType}`);
|
|
24190
|
+
}
|
|
24191
|
+
} else {
|
|
24192
|
+
await response.body?.cancel();
|
|
24193
|
+
}
|
|
24194
|
+
} catch (error2) {
|
|
24195
|
+
this.onerror?.(error2);
|
|
24196
|
+
throw error2;
|
|
24197
|
+
}
|
|
24198
|
+
}
|
|
24199
|
+
get sessionId() {
|
|
24200
|
+
return this._sessionId;
|
|
24201
|
+
}
|
|
24202
|
+
/**
|
|
24203
|
+
* Terminates the current session by sending a DELETE request to the server.
|
|
24204
|
+
*
|
|
24205
|
+
* Clients that no longer need a particular session
|
|
24206
|
+
* (e.g., because the user is leaving the client application) SHOULD send an
|
|
24207
|
+
* HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
|
|
24208
|
+
* terminate the session.
|
|
24209
|
+
*
|
|
24210
|
+
* The server MAY respond with HTTP 405 Method Not Allowed, indicating that
|
|
24211
|
+
* the server does not allow clients to terminate sessions.
|
|
24212
|
+
*/
|
|
24213
|
+
async terminateSession() {
|
|
24214
|
+
if (!this._sessionId) {
|
|
24215
|
+
return;
|
|
24216
|
+
}
|
|
24217
|
+
try {
|
|
24218
|
+
const headers = await this._commonHeaders();
|
|
24219
|
+
const init = {
|
|
24220
|
+
...this._requestInit,
|
|
24221
|
+
method: "DELETE",
|
|
24222
|
+
headers,
|
|
24223
|
+
signal: this._abortController?.signal
|
|
24224
|
+
};
|
|
24225
|
+
const response = await (this._fetch ?? fetch)(this._url, init);
|
|
24226
|
+
await response.body?.cancel();
|
|
24227
|
+
if (!response.ok && response.status !== 405) {
|
|
24228
|
+
throw new StreamableHTTPError(response.status, `Failed to terminate session: ${response.statusText}`);
|
|
24229
|
+
}
|
|
24230
|
+
this._sessionId = void 0;
|
|
24231
|
+
} catch (error2) {
|
|
24232
|
+
this.onerror?.(error2);
|
|
24233
|
+
throw error2;
|
|
24234
|
+
}
|
|
24235
|
+
}
|
|
24236
|
+
setProtocolVersion(version2) {
|
|
24237
|
+
this._protocolVersion = version2;
|
|
24238
|
+
}
|
|
24239
|
+
get protocolVersion() {
|
|
24240
|
+
return this._protocolVersion;
|
|
24241
|
+
}
|
|
24242
|
+
/**
|
|
24243
|
+
* Resume an SSE stream from a previous event ID.
|
|
24244
|
+
* Opens a GET SSE connection with Last-Event-ID header to replay missed events.
|
|
24245
|
+
*
|
|
24246
|
+
* @param lastEventId The event ID to resume from
|
|
24247
|
+
* @param options Optional callback to receive new resumption tokens
|
|
24248
|
+
*/
|
|
24249
|
+
async resumeStream(lastEventId, options) {
|
|
24250
|
+
await this._startOrAuthSse({
|
|
24251
|
+
resumptionToken: lastEventId,
|
|
24252
|
+
onresumptiontoken: options?.onresumptiontoken
|
|
24253
|
+
});
|
|
24254
|
+
}
|
|
24255
|
+
};
|
|
24256
|
+
|
|
24257
|
+
// src/services.ts
|
|
24258
|
+
import dns from "dns/promises";
|
|
24259
|
+
import fs2 from "fs";
|
|
24260
|
+
import net from "net";
|
|
24261
|
+
import os from "os";
|
|
24262
|
+
import path2 from "path";
|
|
24263
|
+
import { Readable } from "stream";
|
|
24264
|
+
import { pipeline } from "stream/promises";
|
|
24265
|
+
var SERVICES_FILE = path2.resolve(
|
|
24266
|
+
process.env.GOATEDIT_SERVICES_FILE || path2.join(os.homedir(), ".goatedit", "services.json")
|
|
24267
|
+
);
|
|
24268
|
+
var MAX_DOWNLOAD_BYTES = 4 * 1024 ** 3;
|
|
24269
|
+
var CALL_TIMEOUT_MS = 12e4;
|
|
24270
|
+
function readConfig() {
|
|
24271
|
+
let raw;
|
|
24272
|
+
try {
|
|
24273
|
+
raw = fs2.readFileSync(SERVICES_FILE, "utf8");
|
|
24274
|
+
} catch {
|
|
24275
|
+
return {};
|
|
24276
|
+
}
|
|
24277
|
+
const parsed = JSON.parse(raw);
|
|
24278
|
+
const servers = parsed && typeof parsed === "object" ? parsed.servers : null;
|
|
24279
|
+
return servers && typeof servers === "object" ? servers : {};
|
|
21088
24280
|
}
|
|
21089
|
-
|
|
21090
|
-
|
|
21091
|
-
|
|
24281
|
+
var clients = /* @__PURE__ */ new Map();
|
|
24282
|
+
async function connect(name, config2) {
|
|
24283
|
+
const client = new Client({ name: "goatedit-studio", version: "1.0.0" });
|
|
24284
|
+
if ("url" in config2) {
|
|
24285
|
+
await client.connect(new StreamableHTTPClientTransport(new URL(config2.url), { requestInit: { headers: config2.headers ?? {} } }));
|
|
24286
|
+
} else {
|
|
24287
|
+
const env = {};
|
|
24288
|
+
for (const [k, v] of Object.entries(process.env)) if (typeof v === "string") env[k] = v;
|
|
24289
|
+
await client.connect(new StdioClientTransport({
|
|
24290
|
+
command: config2.command,
|
|
24291
|
+
args: config2.args ?? [],
|
|
24292
|
+
env: { ...env, ...config2.env ?? {} },
|
|
24293
|
+
...config2.cwd ? { cwd: config2.cwd } : {},
|
|
24294
|
+
stderr: "ignore"
|
|
24295
|
+
}));
|
|
24296
|
+
}
|
|
24297
|
+
client.onclose = () => {
|
|
24298
|
+
clients.delete(name);
|
|
24299
|
+
};
|
|
24300
|
+
return client;
|
|
21092
24301
|
}
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
|
|
21098
|
-
|
|
24302
|
+
function clientFor(name) {
|
|
24303
|
+
const config2 = readConfig()[name];
|
|
24304
|
+
if (!config2) throw new Error(`No service "${name}" in ${SERVICES_FILE}.`);
|
|
24305
|
+
let pending = clients.get(name);
|
|
24306
|
+
if (!pending) {
|
|
24307
|
+
pending = connect(name, config2);
|
|
24308
|
+
clients.set(name, pending);
|
|
24309
|
+
pending.catch(() => clients.delete(name));
|
|
24310
|
+
}
|
|
24311
|
+
return pending;
|
|
24312
|
+
}
|
|
24313
|
+
async function listServices() {
|
|
24314
|
+
const names = Object.keys(readConfig());
|
|
24315
|
+
return Promise.all(names.map(async (server2) => {
|
|
24316
|
+
try {
|
|
24317
|
+
const { tools } = await (await clientFor(server2)).listTools();
|
|
24318
|
+
return { server: server2, tools: tools.map((t) => ({ name: t.name, ...t.description ? { description: t.description } : {} })) };
|
|
24319
|
+
} catch (err) {
|
|
24320
|
+
return { server: server2, error: err instanceof Error ? err.message : String(err) };
|
|
24321
|
+
}
|
|
24322
|
+
}));
|
|
24323
|
+
}
|
|
24324
|
+
async function callService(server2, tool, args = {}) {
|
|
24325
|
+
const client = await clientFor(server2);
|
|
24326
|
+
const result = await client.callTool({ name: tool, arguments: args }, void 0, { timeout: CALL_TIMEOUT_MS });
|
|
24327
|
+
return result;
|
|
24328
|
+
}
|
|
24329
|
+
function isPrivateAddress(ip) {
|
|
24330
|
+
if (net.isIPv4(ip)) {
|
|
24331
|
+
const [a, b] = ip.split(".").map(Number);
|
|
24332
|
+
return a === 10 || a === 127 || a === 0 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 100 && b >= 64 && b <= 127;
|
|
24333
|
+
}
|
|
24334
|
+
const v6 = ip.toLowerCase();
|
|
24335
|
+
if (v6.startsWith("::ffff:")) return isPrivateAddress(v6.slice(7));
|
|
24336
|
+
return v6 === "::1" || v6 === "::" || v6.startsWith("fc") || v6.startsWith("fd") || v6.startsWith("fe80");
|
|
24337
|
+
}
|
|
24338
|
+
async function checkUrl(raw) {
|
|
24339
|
+
let url2;
|
|
24340
|
+
try {
|
|
24341
|
+
url2 = new URL(raw);
|
|
24342
|
+
} catch {
|
|
24343
|
+
throw new Error("Not a URL.");
|
|
21099
24344
|
}
|
|
21100
|
-
|
|
24345
|
+
if (url2.protocol !== "https:") throw new Error("Only https links are downloaded.");
|
|
24346
|
+
const addresses = await dns.lookup(url2.hostname, { all: true });
|
|
24347
|
+
if (!addresses.length || addresses.some((a) => isPrivateAddress(a.address))) throw new Error(`${url2.hostname} is not a public address.`);
|
|
24348
|
+
return url2;
|
|
24349
|
+
}
|
|
24350
|
+
var safeName = (s) => s.replace(/[^\w.-]+/g, "_").replace(/^[._]+/, "").slice(0, 80) || "file";
|
|
24351
|
+
async function downloadToAssets(assetsDir, rawUrl, name) {
|
|
24352
|
+
let url2 = await checkUrl(rawUrl);
|
|
24353
|
+
let res = null;
|
|
24354
|
+
for (let hop = 0; hop < 5; hop++) {
|
|
24355
|
+
res = await fetch(url2, { redirect: "manual" });
|
|
24356
|
+
const next = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
24357
|
+
if (!next) break;
|
|
24358
|
+
url2 = await checkUrl(new URL(next, url2).toString());
|
|
24359
|
+
res = null;
|
|
24360
|
+
}
|
|
24361
|
+
if (!res) throw new Error("Too many redirects.");
|
|
24362
|
+
if (!res.ok || !res.body) throw new Error(`The download failed: HTTP ${res.status}.`);
|
|
24363
|
+
const declared = Number(res.headers.get("content-length") || 0);
|
|
24364
|
+
if (declared > MAX_DOWNLOAD_BYTES) throw new Error("The file is too big.");
|
|
24365
|
+
const fromUrl = path2.basename(url2.pathname);
|
|
24366
|
+
const file = safeName(name || fromUrl);
|
|
24367
|
+
const ext = path2.extname(file) ? "" : path2.extname(fromUrl);
|
|
24368
|
+
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
24369
|
+
const rel = path2.join("GoatEdit Downloads", day, `${Date.now().toString(36)}-${file}${ext}`);
|
|
24370
|
+
const dest = path2.join(assetsDir, rel);
|
|
24371
|
+
fs2.mkdirSync(path2.dirname(dest), { recursive: true });
|
|
24372
|
+
const partial2 = `${dest}.part`;
|
|
24373
|
+
let bytes = 0;
|
|
24374
|
+
const counted = Readable.fromWeb(res.body);
|
|
24375
|
+
counted.on("data", (chunk) => {
|
|
24376
|
+
bytes += chunk.length;
|
|
24377
|
+
if (bytes > MAX_DOWNLOAD_BYTES) counted.destroy(new Error("The file is too big."));
|
|
24378
|
+
});
|
|
24379
|
+
try {
|
|
24380
|
+
await pipeline(counted, fs2.createWriteStream(partial2));
|
|
24381
|
+
fs2.renameSync(partial2, dest);
|
|
24382
|
+
} catch (err) {
|
|
24383
|
+
fs2.rmSync(partial2, { force: true });
|
|
24384
|
+
throw err;
|
|
24385
|
+
}
|
|
24386
|
+
return { rel, path: dest, bytes, contentType: res.headers.get("content-type") || "" };
|
|
21101
24387
|
}
|
|
21102
24388
|
|
|
21103
24389
|
// src/index.ts
|
|
@@ -21126,32 +24412,32 @@ function isLoopbackHost(host) {
|
|
|
21126
24412
|
return false;
|
|
21127
24413
|
}
|
|
21128
24414
|
}
|
|
21129
|
-
var CONTROLLER_TOKEN = process.env.GOATEDIT_CONTROLLER_TOKEN ||
|
|
21130
|
-
var CONTROLLER_TOKEN_FILE =
|
|
24415
|
+
var CONTROLLER_TOKEN = process.env.GOATEDIT_CONTROLLER_TOKEN || crypto2.randomBytes(32).toString("hex");
|
|
24416
|
+
var CONTROLLER_TOKEN_FILE = path3.join(os2.homedir(), ".goatedit", "mcp-controller-token");
|
|
21131
24417
|
function writeControllerToken() {
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
24418
|
+
fs3.mkdirSync(path3.dirname(CONTROLLER_TOKEN_FILE), { recursive: true, mode: 448 });
|
|
24419
|
+
fs3.writeFileSync(CONTROLLER_TOKEN_FILE, CONTROLLER_TOKEN, { mode: 384 });
|
|
24420
|
+
fs3.chmodSync(CONTROLLER_TOKEN_FILE, 384);
|
|
21135
24421
|
}
|
|
21136
24422
|
function hasControllerToken(req) {
|
|
21137
24423
|
const header = req.headers.authorization || "";
|
|
21138
24424
|
const presented = header.startsWith("Bearer ") ? header.slice(7) : new URL(req.url || "/", "http://localhost").searchParams.get("token") || "";
|
|
21139
24425
|
const a = Buffer.from(presented);
|
|
21140
24426
|
const b = Buffer.from(CONTROLLER_TOKEN);
|
|
21141
|
-
return a.length === b.length &&
|
|
24427
|
+
return a.length === b.length && crypto2.timingSafeEqual(a, b);
|
|
21142
24428
|
}
|
|
21143
24429
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
21144
|
-
var LOCAL_ASSETS_DIR =
|
|
21145
|
-
process.env.GOATEDIT_ASSETS_DIR ||
|
|
24430
|
+
var LOCAL_ASSETS_DIR = path3.resolve(
|
|
24431
|
+
process.env.GOATEDIT_ASSETS_DIR || path3.join(os2.homedir(), "Movies")
|
|
21146
24432
|
);
|
|
21147
|
-
var FRAMES_DIR =
|
|
21148
|
-
process.env.GOATEDIT_FRAMES_DIR ||
|
|
24433
|
+
var FRAMES_DIR = path3.resolve(
|
|
24434
|
+
process.env.GOATEDIT_FRAMES_DIR || path3.join(os2.homedir(), ".goatedit", "frames")
|
|
21149
24435
|
);
|
|
21150
24436
|
var VERSION = (() => {
|
|
21151
|
-
const here =
|
|
24437
|
+
const here = path3.dirname(fileURLToPath(import.meta.url));
|
|
21152
24438
|
for (const rel of ["../package.json", "../../../package.json"]) {
|
|
21153
24439
|
try {
|
|
21154
|
-
const pkg = JSON.parse(
|
|
24440
|
+
const pkg = JSON.parse(fs3.readFileSync(path3.join(here, rel), "utf8"));
|
|
21155
24441
|
if (pkg.name === "goatedit-mcp") return String(pkg.version);
|
|
21156
24442
|
} catch {
|
|
21157
24443
|
}
|
|
@@ -21180,18 +24466,18 @@ var MEDIA_TYPES = {
|
|
|
21180
24466
|
".glb": { mime: "model/gltf-binary", kind: "model" }
|
|
21181
24467
|
};
|
|
21182
24468
|
function mediaUrl(rel) {
|
|
21183
|
-
return `http://localhost:${WEBSOCKET_PORT}/media/${rel.split(
|
|
24469
|
+
return `http://localhost:${WEBSOCKET_PORT}/media/${rel.split(path3.sep).map(encodeURIComponent).join("/")}`;
|
|
21184
24470
|
}
|
|
21185
24471
|
var MAX_LISTED_ASSETS = 500;
|
|
21186
24472
|
var MAX_ASSET_DEPTH = 4;
|
|
21187
24473
|
async function handleListLocalAssets(args = {}) {
|
|
21188
|
-
if (!
|
|
24474
|
+
if (!fs3.existsSync(LOCAL_ASSETS_DIR)) {
|
|
21189
24475
|
throw new Error(
|
|
21190
24476
|
`Assets directory does not exist: ${LOCAL_ASSETS_DIR}. Set GOATEDIT_ASSETS_DIR to a folder of media.`
|
|
21191
24477
|
);
|
|
21192
24478
|
}
|
|
21193
|
-
const start =
|
|
21194
|
-
if (start !== LOCAL_ASSETS_DIR && !start.startsWith(LOCAL_ASSETS_DIR +
|
|
24479
|
+
const start = path3.resolve(LOCAL_ASSETS_DIR, args.folder || "");
|
|
24480
|
+
if (start !== LOCAL_ASSETS_DIR && !start.startsWith(LOCAL_ASSETS_DIR + path3.sep)) {
|
|
21195
24481
|
throw new Error("folder must be inside the assets directory.");
|
|
21196
24482
|
}
|
|
21197
24483
|
const files = [];
|
|
@@ -21199,7 +24485,7 @@ async function handleListLocalAssets(args = {}) {
|
|
|
21199
24485
|
const walk = (dir, depth) => {
|
|
21200
24486
|
let entries;
|
|
21201
24487
|
try {
|
|
21202
|
-
entries =
|
|
24488
|
+
entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
21203
24489
|
} catch {
|
|
21204
24490
|
return;
|
|
21205
24491
|
}
|
|
@@ -21210,17 +24496,17 @@ async function handleListLocalAssets(args = {}) {
|
|
|
21210
24496
|
return;
|
|
21211
24497
|
}
|
|
21212
24498
|
if (entry.name.startsWith(".")) continue;
|
|
21213
|
-
const full =
|
|
24499
|
+
const full = path3.join(dir, entry.name);
|
|
21214
24500
|
if (entry.isDirectory()) {
|
|
21215
24501
|
if (depth < MAX_ASSET_DEPTH) walk(full, depth + 1);
|
|
21216
24502
|
continue;
|
|
21217
24503
|
}
|
|
21218
|
-
const type = MEDIA_TYPES[
|
|
24504
|
+
const type = MEDIA_TYPES[path3.extname(entry.name).toLowerCase()];
|
|
21219
24505
|
if (!type || !entry.isFile()) continue;
|
|
21220
|
-
const rel =
|
|
24506
|
+
const rel = path3.relative(LOCAL_ASSETS_DIR, full);
|
|
21221
24507
|
let bytes = 0;
|
|
21222
24508
|
try {
|
|
21223
|
-
bytes =
|
|
24509
|
+
bytes = fs3.statSync(full).size;
|
|
21224
24510
|
} catch {
|
|
21225
24511
|
}
|
|
21226
24512
|
files.push({ name: entry.name, path: rel, type: type.kind, bytes, url: mediaUrl(rel) });
|
|
@@ -21236,10 +24522,10 @@ async function handleListLocalAssets(args = {}) {
|
|
|
21236
24522
|
async function handleFindLocalFile(args = {}) {
|
|
21237
24523
|
const hit = findLocalFile(LOCAL_ASSETS_DIR, String(args.filename ?? ""), MAX_ASSET_DEPTH);
|
|
21238
24524
|
if (!hit) return null;
|
|
21239
|
-
const type = MEDIA_TYPES[
|
|
24525
|
+
const type = MEDIA_TYPES[path3.extname(hit).toLowerCase()];
|
|
21240
24526
|
if (!type || type.kind === "lottie") return null;
|
|
21241
|
-
const rel =
|
|
21242
|
-
return { name:
|
|
24527
|
+
const rel = path3.relative(LOCAL_ASSETS_DIR, hit);
|
|
24528
|
+
return { name: path3.basename(hit), path: rel, url: mediaUrl(rel), contentType: type.mime };
|
|
21243
24529
|
}
|
|
21244
24530
|
function audioDuration(file) {
|
|
21245
24531
|
try {
|
|
@@ -21258,15 +24544,15 @@ async function handleGenerateVoiceover(text, projectId) {
|
|
|
21258
24544
|
throw new Error("generate_voiceover needs macOS `say`. Not available on this platform.");
|
|
21259
24545
|
}
|
|
21260
24546
|
const filename = `voiceover_${Date.now()}.wav`;
|
|
21261
|
-
const filePath =
|
|
21262
|
-
|
|
21263
|
-
const scriptPath =
|
|
21264
|
-
|
|
24547
|
+
const filePath = path3.join(LOCAL_ASSETS_DIR, filename);
|
|
24548
|
+
fs3.mkdirSync(LOCAL_ASSETS_DIR, { recursive: true });
|
|
24549
|
+
const scriptPath = path3.join(LOCAL_ASSETS_DIR, `.voiceover_${Date.now()}.txt`);
|
|
24550
|
+
fs3.writeFileSync(scriptPath, text, "utf8");
|
|
21265
24551
|
try {
|
|
21266
24552
|
execFileSync("say", ["-o", filePath, "-f", scriptPath], { stdio: "ignore" });
|
|
21267
24553
|
const duration3 = audioDuration(filePath) ?? text.split(/\s+/).length * 0.45 + 1;
|
|
21268
24554
|
const audioAsset = {
|
|
21269
|
-
id: `media-${
|
|
24555
|
+
id: `media-${crypto2.randomUUID()}`,
|
|
21270
24556
|
name: filename,
|
|
21271
24557
|
type: "audio",
|
|
21272
24558
|
duration: duration3,
|
|
@@ -21279,7 +24565,7 @@ async function handleGenerateVoiceover(text, projectId) {
|
|
|
21279
24565
|
throw new Error(`Failed to generate voiceover: ${err.message}`);
|
|
21280
24566
|
} finally {
|
|
21281
24567
|
try {
|
|
21282
|
-
|
|
24568
|
+
fs3.unlinkSync(scriptPath);
|
|
21283
24569
|
} catch {
|
|
21284
24570
|
}
|
|
21285
24571
|
}
|
|
@@ -21287,12 +24573,12 @@ async function handleGenerateVoiceover(text, projectId) {
|
|
|
21287
24573
|
function saveFileToDisk(result) {
|
|
21288
24574
|
const file = result && typeof result === "object" ? result._file : void 0;
|
|
21289
24575
|
if (!file || typeof file.data !== "string") return result;
|
|
21290
|
-
|
|
24576
|
+
fs3.mkdirSync(FRAMES_DIR, { recursive: true });
|
|
21291
24577
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
21292
24578
|
const safe = String(file.name ?? "file").replace(/[^\w.-]+/g, "_").slice(0, 80);
|
|
21293
|
-
const target =
|
|
24579
|
+
const target = path3.join(FRAMES_DIR, `${stamp}-${safe}`);
|
|
21294
24580
|
const bytes = Buffer.from(file.data, "base64");
|
|
21295
|
-
|
|
24581
|
+
fs3.writeFileSync(target, bytes);
|
|
21296
24582
|
const { _file: _file2, ...rest } = result;
|
|
21297
24583
|
return { ...rest, savedTo: target, bytes: bytes.length };
|
|
21298
24584
|
}
|
|
@@ -21300,14 +24586,14 @@ function saveFramesToDisk(result, label) {
|
|
|
21300
24586
|
if (!result || typeof result !== "object") return result;
|
|
21301
24587
|
const frames = [result._image, ...Array.isArray(result._images) ? result._images : []].filter((f) => f && typeof f.data === "string" && typeof f.mimeType === "string");
|
|
21302
24588
|
if (!frames.length) return result;
|
|
21303
|
-
|
|
24589
|
+
fs3.mkdirSync(FRAMES_DIR, { recursive: true });
|
|
21304
24590
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
21305
24591
|
const safe = label.replace(/[^\w.-]+/g, "_").slice(0, 60);
|
|
21306
24592
|
const saved = frames.map((f, i) => {
|
|
21307
24593
|
const ext = f.mimeType === "image/png" ? "png" : f.mimeType === "image/webp" ? "webp" : "jpg";
|
|
21308
|
-
const file =
|
|
24594
|
+
const file = path3.join(FRAMES_DIR, `${stamp}-${safe}${frames.length > 1 ? `-${i}` : ""}.${ext}`);
|
|
21309
24595
|
const bytes = Buffer.from(f.data, "base64");
|
|
21310
|
-
|
|
24596
|
+
fs3.writeFileSync(file, bytes);
|
|
21311
24597
|
return { path: file, bytes: bytes.length, ...f.caption ? { caption: f.caption } : {} };
|
|
21312
24598
|
});
|
|
21313
24599
|
const { _image, _images, ...rest } = result;
|
|
@@ -21318,8 +24604,8 @@ function saveFramesToDisk(result, label) {
|
|
|
21318
24604
|
};
|
|
21319
24605
|
}
|
|
21320
24606
|
function serveFile(req, res, filePath) {
|
|
21321
|
-
const size =
|
|
21322
|
-
const type = MEDIA_TYPES[
|
|
24607
|
+
const size = fs3.statSync(filePath).size;
|
|
24608
|
+
const type = MEDIA_TYPES[path3.extname(filePath).toLowerCase()]?.mime ?? "application/octet-stream";
|
|
21323
24609
|
const headers = { "Content-Type": type, "Accept-Ranges": "bytes" };
|
|
21324
24610
|
const range = /^bytes=(\d*)-(\d*)$/.exec(req.headers.range || "");
|
|
21325
24611
|
if (range && (range[1] || range[2])) {
|
|
@@ -21342,7 +24628,7 @@ function serveFile(req, res, filePath) {
|
|
|
21342
24628
|
res.end();
|
|
21343
24629
|
return;
|
|
21344
24630
|
}
|
|
21345
|
-
|
|
24631
|
+
fs3.createReadStream(filePath, { start, end }).pipe(res);
|
|
21346
24632
|
return;
|
|
21347
24633
|
}
|
|
21348
24634
|
res.writeHead(200, { ...headers, "Content-Length": size });
|
|
@@ -21350,11 +24636,11 @@ function serveFile(req, res, filePath) {
|
|
|
21350
24636
|
res.end();
|
|
21351
24637
|
return;
|
|
21352
24638
|
}
|
|
21353
|
-
|
|
24639
|
+
fs3.createReadStream(filePath).pipe(res);
|
|
21354
24640
|
}
|
|
21355
24641
|
var httpServer = http.createServer((req, res) => {
|
|
21356
|
-
const
|
|
21357
|
-
const pathname =
|
|
24642
|
+
const url2 = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
24643
|
+
const pathname = url2.pathname;
|
|
21358
24644
|
if (!isLoopbackHost(req.headers.host)) {
|
|
21359
24645
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
21360
24646
|
res.end("Forbidden");
|
|
@@ -21388,9 +24674,9 @@ var httpServer = http.createServer((req, res) => {
|
|
|
21388
24674
|
res.end("Bad path");
|
|
21389
24675
|
return;
|
|
21390
24676
|
}
|
|
21391
|
-
const filePath =
|
|
21392
|
-
const inRoot = filePath === LOCAL_ASSETS_DIR || filePath.startsWith(LOCAL_ASSETS_DIR +
|
|
21393
|
-
if (inRoot &&
|
|
24677
|
+
const filePath = path3.resolve(LOCAL_ASSETS_DIR, filename);
|
|
24678
|
+
const inRoot = filePath === LOCAL_ASSETS_DIR || filePath.startsWith(LOCAL_ASSETS_DIR + path3.sep);
|
|
24679
|
+
if (inRoot && fs3.existsSync(filePath) && fs3.statSync(filePath).isFile()) {
|
|
21394
24680
|
serveFile(req, res, filePath);
|
|
21395
24681
|
} else {
|
|
21396
24682
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
@@ -21475,9 +24761,24 @@ function explainTabError(error2) {
|
|
|
21475
24761
|
function sendJson(ws, message) {
|
|
21476
24762
|
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(message));
|
|
21477
24763
|
}
|
|
24764
|
+
async function answerService(ws, message) {
|
|
24765
|
+
const { id, action, params = {} } = message;
|
|
24766
|
+
try {
|
|
24767
|
+
let result;
|
|
24768
|
+
if (action === "list") result = await listServices();
|
|
24769
|
+
else if (action === "call") result = await callService(String(params.server), String(params.tool), params.args ?? {});
|
|
24770
|
+
else if (action === "download") {
|
|
24771
|
+
const saved = await downloadToAssets(LOCAL_ASSETS_DIR, String(params.url), typeof params.name === "string" ? params.name : void 0);
|
|
24772
|
+
result = { ...saved, mediaUrl: mediaUrl(saved.rel) };
|
|
24773
|
+
} else throw new Error(`Unknown service action: ${action}`);
|
|
24774
|
+
sendJson(ws, { type: "serviceReply", id, result });
|
|
24775
|
+
} catch (err) {
|
|
24776
|
+
sendJson(ws, { type: "serviceReply", id, error: err?.message ?? String(err) });
|
|
24777
|
+
}
|
|
24778
|
+
}
|
|
21478
24779
|
wss.on("connection", (ws, req) => {
|
|
21479
|
-
const
|
|
21480
|
-
if (
|
|
24780
|
+
const url2 = req.url || "/";
|
|
24781
|
+
if (url2.startsWith("/controller")) {
|
|
21481
24782
|
console.error("[GoatEdit MCP] Controller client connected");
|
|
21482
24783
|
controllerSockets.add(ws);
|
|
21483
24784
|
ws.on("message", async (data) => {
|
|
@@ -21527,6 +24828,10 @@ wss.on("connection", (ws, req) => {
|
|
|
21527
24828
|
for (const controller2 of controllerSockets) sendJson(controller2, message);
|
|
21528
24829
|
return;
|
|
21529
24830
|
}
|
|
24831
|
+
if (message.type === "service") {
|
|
24832
|
+
void answerService(ws, message);
|
|
24833
|
+
return;
|
|
24834
|
+
}
|
|
21530
24835
|
if (message.id === void 0 || message.result === void 0 && message.error === void 0) return;
|
|
21531
24836
|
const key = String(message.id);
|
|
21532
24837
|
const pending = pendingRequests.get(key);
|
|
@@ -21590,7 +24895,7 @@ function connectUpstream() {
|
|
|
21590
24895
|
upstreamReady = new Promise((resolve, reject) => {
|
|
21591
24896
|
let token;
|
|
21592
24897
|
try {
|
|
21593
|
-
token = process.env.GOATEDIT_CONTROLLER_TOKEN ||
|
|
24898
|
+
token = process.env.GOATEDIT_CONTROLLER_TOKEN || fs3.readFileSync(CONTROLLER_TOKEN_FILE, "utf8").trim();
|
|
21594
24899
|
} catch {
|
|
21595
24900
|
reject(new Error(notConnectedMessage()));
|
|
21596
24901
|
return;
|
|
@@ -21636,7 +24941,7 @@ async function ensureTransport() {
|
|
|
21636
24941
|
}
|
|
21637
24942
|
function sendUpstream(method, params, projectId) {
|
|
21638
24943
|
return connectUpstream().then((ws) => new Promise((resolve, reject) => {
|
|
21639
|
-
const id =
|
|
24944
|
+
const id = crypto2.randomUUID();
|
|
21640
24945
|
const timeoutId = setTimeout(() => {
|
|
21641
24946
|
upstreamPending.delete(id);
|
|
21642
24947
|
reject(new Error(`Request timed out: ${method}`));
|
|
@@ -21650,7 +24955,7 @@ async function sendToBrowser(method, params = {}, projectId) {
|
|
|
21650
24955
|
if (!ownsPort) return sendUpstream(method, params, projectId ?? chosenProjectId);
|
|
21651
24956
|
const tab = resolveTab(projectId);
|
|
21652
24957
|
return new Promise((resolve, reject) => {
|
|
21653
|
-
const id =
|
|
24958
|
+
const id = crypto2.randomUUID();
|
|
21654
24959
|
const timeoutId = setTimeout(() => {
|
|
21655
24960
|
pendingRequests.delete(id);
|
|
21656
24961
|
reject(new Error(`Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s: ${method}. Call get_timeline to see whether it landed.`));
|