goatedit-mcp 1.1.8 → 1.1.10
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 +3549 -195
- 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
|
|
@@ -20585,24 +21280,78 @@ var BASE_TOOLS = [
|
|
|
20585
21280
|
method: "setProjectSettings"
|
|
20586
21281
|
},
|
|
20587
21282
|
{
|
|
20588
|
-
name: "
|
|
20589
|
-
description:
|
|
21283
|
+
name: "begin_request",
|
|
21284
|
+
description: 'Call once at the start of each new request from the user, before editing. It tells the editor what kind of edit this is and which words describe the style, so it can learn what this user means by them, and measures any reference video the user gave. Pass words from the request ("punchy", "cinematic"), not the request itself \u2014 nothing else is kept. References must be in the media bin (import_local_file or add_media_file first); only their measurements are kept (cut pacing, grade, colours), never frames. Replies with those measurements, to use while editing.',
|
|
20590
21285
|
inputSchema: {
|
|
20591
21286
|
type: "object",
|
|
20592
21287
|
properties: {
|
|
20593
|
-
|
|
20594
|
-
|
|
20595
|
-
|
|
20596
|
-
|
|
20597
|
-
|
|
20598
|
-
|
|
20599
|
-
|
|
21288
|
+
editType: {
|
|
21289
|
+
type: "string",
|
|
21290
|
+
enum: ["reel", "short", "ad", "promo", "trailer", "podcast", "interview", "talking-head", "vlog", "tutorial", "explainer", "documentary", "music-video", "wedding", "event", "product", "real-estate", "gaming", "montage", "slideshow", "corporate", "other"],
|
|
21291
|
+
description: "What the user is making."
|
|
21292
|
+
},
|
|
21293
|
+
styleWords: { type: "array", items: { type: "string" }, description: 'Style words from the request, e.g. ["punchy", "warm"].' },
|
|
21294
|
+
referenceMediaIds: { type: "array", items: { type: "string" }, description: "Media ids of reference videos the user gave (up to 3)." }
|
|
20600
21295
|
}
|
|
20601
21296
|
},
|
|
20602
|
-
method: "
|
|
21297
|
+
method: "beginRequest"
|
|
20603
21298
|
},
|
|
20604
21299
|
{
|
|
20605
|
-
name: "
|
|
21300
|
+
name: "record_choice",
|
|
21301
|
+
description: "When you offer the user several versions of an edit (one sequence each, e.g. a fast cut, a story cut, a minimal cut) and they pick one, record it here. The editor compares the pick with the others \u2014 pacing, transitions, effects, text size, music level, grade \u2014 and learns which way this user leans, which get_style_profile then reports under preferences. A pick says more than many silent edits, so offer variants for open-ended requests.",
|
|
21302
|
+
inputSchema: {
|
|
21303
|
+
type: "object",
|
|
21304
|
+
properties: {
|
|
21305
|
+
sequenceIds: { type: "array", items: { type: "string" }, description: "Every variant offered, as sequence ids (2\u20136)." },
|
|
21306
|
+
chosenSequenceId: str("The one the user picked.")
|
|
21307
|
+
},
|
|
21308
|
+
required: ["sequenceIds", "chosenSequenceId"]
|
|
21309
|
+
},
|
|
21310
|
+
method: "recordChoice"
|
|
21311
|
+
},
|
|
21312
|
+
{
|
|
21313
|
+
name: "set_style_brand",
|
|
21314
|
+
description: "Say which brand or client this project is for, so its style is learned and read apart from the user\u2019s other clients. Ask the user first \u2014 when get_style_profile reports a brandGuess, confirm it with them before setting it. name: null files the project under the user\u2019s own style again.",
|
|
21315
|
+
inputSchema: {
|
|
21316
|
+
type: "object",
|
|
21317
|
+
properties: { name: { type: ["string", "null"], description: 'Brand or client name, e.g. "Nike"; null for none.' } },
|
|
21318
|
+
required: ["name"]
|
|
21319
|
+
},
|
|
21320
|
+
method: "setStyleBrand"
|
|
21321
|
+
},
|
|
21322
|
+
{
|
|
21323
|
+
name: "get_style_profile",
|
|
21324
|
+
description: 'What this user\u2019s edits have in common, learned from their past projects: pacing, transitions, text and captions, colour, effects, audio levels, frame shape \u2014 plus the changes they keep making to the agent\u2019s work (corrections) and what their style words ("punchy", "clean") have meant before. Read it before choosing a look, and treat it as defaults: the request in front of you wins. Pass topic to get just one part. Scoped to the project\u2019s brand/client when it has one, so one editor\u2019s clients stay apart. Reports enabled: false when the user has not switched style memory on.',
|
|
21325
|
+
inputSchema: {
|
|
21326
|
+
type: "object",
|
|
21327
|
+
properties: {
|
|
21328
|
+
topic: { type: "string", enum: ["pacing", "transitions", "text", "color", "effects", "audio", "format"], description: "One part of the style. Omit for all of it." },
|
|
21329
|
+
brandId: str("Read another brand\u2019s style instead of this project\u2019s."),
|
|
21330
|
+
editType: str("Read the style for this kind of edit (reel, ad, podcast\u2026) instead of this project\u2019s own."),
|
|
21331
|
+
sheets: bool("Also return up to 2 contact sheets of the user\u2019s own exported edits that fit (people are blurred out). Off by default: each is an image.")
|
|
21332
|
+
}
|
|
21333
|
+
},
|
|
21334
|
+
method: "getStyleProfile"
|
|
21335
|
+
},
|
|
21336
|
+
{
|
|
21337
|
+
name: "set_audio_master",
|
|
21338
|
+
description: "The sequence\u2019s master bus: tag tracks as voice, music or sfx, duck music under voice, and put a safety limiter on the mix. Ducking follows the spans of clips on voice-role tracks (and nested sequences placed on them), dipping music-role tracks by duckDb, starting `attack` seconds before each line so the first word is clear. Playback, probe_audio and export all hear the same bus. With no arguments it reports the current roles and settings.",
|
|
21339
|
+
inputSchema: {
|
|
21340
|
+
type: "object",
|
|
21341
|
+
properties: {
|
|
21342
|
+
roles: { type: "object", description: 'Track roles: { "<trackId>": "voice" | "music" | "sfx" | "none" }.' },
|
|
21343
|
+
ducking: bool("Duck music-role tracks under voice-role tracks."),
|
|
21344
|
+
duckDb: num("How far music dips under voice, in dB (negative). Defaults to -12."),
|
|
21345
|
+
attack: num("Seconds the dip takes, finishing as the voice starts. Defaults to 0.25."),
|
|
21346
|
+
release: num("Seconds music takes to come back after the voice ends. Defaults to 0.6."),
|
|
21347
|
+
limiter: bool("Limit the mix so it does not clip."),
|
|
21348
|
+
ceilingDb: num("Limiter ceiling in dBFS. Defaults to -1.")
|
|
21349
|
+
}
|
|
21350
|
+
},
|
|
21351
|
+
method: "setAudioMaster"
|
|
21352
|
+
},
|
|
21353
|
+
{
|
|
21354
|
+
name: "apply_ai_edit",
|
|
20606
21355
|
description: "Tighten the cut from the transcript: remove filler words, remove long pauses, or both. Works on the transcript derived from the clips currently on the timeline, so it respects the cuts already made. Run it with dryRun first to see exactly which ranges would go before anything is removed.",
|
|
20607
21356
|
inputSchema: {
|
|
20608
21357
|
type: "object",
|
|
@@ -20801,6 +21550,134 @@ var BASE_TOOLS = [
|
|
|
20801
21550
|
description: "Re-apply the last undone edit.",
|
|
20802
21551
|
inputSchema: { type: "object", properties: {} },
|
|
20803
21552
|
method: "redo"
|
|
21553
|
+
},
|
|
21554
|
+
{
|
|
21555
|
+
name: "studio_tasks",
|
|
21556
|
+
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.',
|
|
21557
|
+
inputSchema: {
|
|
21558
|
+
type: "object",
|
|
21559
|
+
properties: {
|
|
21560
|
+
runId: str("Only this run. Omit for every run in the project."),
|
|
21561
|
+
detail: bool("Include each write task's role, inputs and previous draft (default true). False lists the tasks only.")
|
|
21562
|
+
}
|
|
21563
|
+
},
|
|
21564
|
+
method: "getStudioTasks"
|
|
21565
|
+
},
|
|
21566
|
+
{
|
|
21567
|
+
name: "studio_claim",
|
|
21568
|
+
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.',
|
|
21569
|
+
inputSchema: {
|
|
21570
|
+
type: "object",
|
|
21571
|
+
properties: {
|
|
21572
|
+
runId: str("The run, from studio_tasks."),
|
|
21573
|
+
stage: str('The stage id, from studio_tasks (e.g. "script").'),
|
|
21574
|
+
agent: str("Who is doing it, shown in the panel.")
|
|
21575
|
+
},
|
|
21576
|
+
required: ["runId", "stage", "agent"]
|
|
21577
|
+
},
|
|
21578
|
+
method: "studioClaim"
|
|
21579
|
+
},
|
|
21580
|
+
{
|
|
21581
|
+
name: "studio_submit",
|
|
21582
|
+
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.",
|
|
21583
|
+
inputSchema: {
|
|
21584
|
+
type: "object",
|
|
21585
|
+
properties: {
|
|
21586
|
+
runId: str("The run, from studio_tasks."),
|
|
21587
|
+
stage: str("The stage id."),
|
|
21588
|
+
document: { type: "object", description: "The stage's document, in the shape its role card gives." },
|
|
21589
|
+
agent: str("Who wrote it, as in studio_claim.")
|
|
21590
|
+
},
|
|
21591
|
+
required: ["runId", "stage", "document"]
|
|
21592
|
+
},
|
|
21593
|
+
method: "studioSubmit"
|
|
21594
|
+
},
|
|
21595
|
+
{
|
|
21596
|
+
name: "studio_run_stage",
|
|
21597
|
+
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.`,
|
|
21598
|
+
inputSchema: {
|
|
21599
|
+
type: "object",
|
|
21600
|
+
properties: {
|
|
21601
|
+
runId: str("The run, from studio_tasks."),
|
|
21602
|
+
stage: str("The stage id.")
|
|
21603
|
+
},
|
|
21604
|
+
required: ["runId", "stage"]
|
|
21605
|
+
},
|
|
21606
|
+
method: "studioRunStage"
|
|
21607
|
+
},
|
|
21608
|
+
{
|
|
21609
|
+
name: "studio_start_run",
|
|
21610
|
+
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.`,
|
|
21611
|
+
inputSchema: {
|
|
21612
|
+
type: "object",
|
|
21613
|
+
properties: {
|
|
21614
|
+
title: str("What the video is, in a few words."),
|
|
21615
|
+
workflow: str('A workflow id or name from the Studio panel: "outside" (default), "guided", "autopilot", "hands-on", or one the user saved.')
|
|
21616
|
+
},
|
|
21617
|
+
required: ["title"]
|
|
21618
|
+
},
|
|
21619
|
+
method: "studioStartRun"
|
|
21620
|
+
},
|
|
21621
|
+
{
|
|
21622
|
+
name: "studio_workflows",
|
|
21623
|
+
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.`,
|
|
21624
|
+
inputSchema: {
|
|
21625
|
+
type: "object",
|
|
21626
|
+
properties: {
|
|
21627
|
+
workflow: str('A workflow id or name to see stage by stage. Omit for the list, with the "outside" workflow in full.')
|
|
21628
|
+
}
|
|
21629
|
+
},
|
|
21630
|
+
method: "studioWorkflows"
|
|
21631
|
+
},
|
|
21632
|
+
{
|
|
21633
|
+
name: "studio_save_workflow",
|
|
21634
|
+
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.`,
|
|
21635
|
+
inputSchema: {
|
|
21636
|
+
type: "object",
|
|
21637
|
+
properties: {
|
|
21638
|
+
workflow: {
|
|
21639
|
+
type: "object",
|
|
21640
|
+
description: "The workflow.",
|
|
21641
|
+
properties: {
|
|
21642
|
+
name: str('What the person will see, e.g. "Avatar reels".'),
|
|
21643
|
+
from: str('The workflow to start from, by id or name (default "outside").'),
|
|
21644
|
+
stages: {
|
|
21645
|
+
type: "object",
|
|
21646
|
+
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.',
|
|
21647
|
+
additionalProperties: { type: "object" }
|
|
21648
|
+
},
|
|
21649
|
+
add: {
|
|
21650
|
+
type: "array",
|
|
21651
|
+
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? }.',
|
|
21652
|
+
items: { type: "object" }
|
|
21653
|
+
}
|
|
21654
|
+
},
|
|
21655
|
+
required: ["name"]
|
|
21656
|
+
}
|
|
21657
|
+
},
|
|
21658
|
+
required: ["workflow"]
|
|
21659
|
+
},
|
|
21660
|
+
method: "studioSaveWorkflow"
|
|
21661
|
+
},
|
|
21662
|
+
{
|
|
21663
|
+
name: "studio_start_batch",
|
|
21664
|
+
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.`,
|
|
21665
|
+
inputSchema: {
|
|
21666
|
+
type: "object",
|
|
21667
|
+
properties: {
|
|
21668
|
+
title: str('The series name, e.g. "Health tips".'),
|
|
21669
|
+
series: str("The series: brand, audience, tone, platform. Every reel's brief is written from it."),
|
|
21670
|
+
reels: {
|
|
21671
|
+
type: "array",
|
|
21672
|
+
description: "One per reel: { name, script (word for word), avatar? (the HeyGen avatar that speaks it) }.",
|
|
21673
|
+
items: { type: "object" }
|
|
21674
|
+
},
|
|
21675
|
+
text: str("Instead of reels: the scripts as the person pasted them."),
|
|
21676
|
+
workflow: str('A workflow id or name (default "outside"); studio_save_workflow makes one.')
|
|
21677
|
+
},
|
|
21678
|
+
required: ["title"]
|
|
21679
|
+
},
|
|
21680
|
+
method: "studioStartBatch"
|
|
20804
21681
|
}
|
|
20805
21682
|
];
|
|
20806
21683
|
var SEQUENCE_EDITS = /* @__PURE__ */ new Set([
|
|
@@ -21032,128 +21909,2582 @@ function resolveRefs(value, refs) {
|
|
|
21032
21909
|
}
|
|
21033
21910
|
return value;
|
|
21034
21911
|
}
|
|
21912
|
+
function withRunProject(stepArgs, projectId) {
|
|
21913
|
+
if (typeof projectId !== "string" || !projectId || typeof stepArgs.projectId === "string") return stepArgs;
|
|
21914
|
+
return { ...stepArgs, projectId };
|
|
21915
|
+
}
|
|
21035
21916
|
|
|
21036
|
-
// src/
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
...(process.env.GOATEDIT_ALLOWED_ORIGINS || "").split(",").map((s) => s.trim()).filter(Boolean)
|
|
21042
|
-
]);
|
|
21043
|
-
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
21044
|
-
function isAllowedOrigin(origin) {
|
|
21045
|
-
if (!origin) return false;
|
|
21046
|
-
if (ALLOWED_ORIGINS.has(origin)) return true;
|
|
21047
|
-
try {
|
|
21048
|
-
const u = new URL(origin);
|
|
21049
|
-
return (u.protocol === "http:" || u.protocol === "https:") && LOOPBACK_HOSTNAMES.has(u.hostname);
|
|
21050
|
-
} catch {
|
|
21051
|
-
return false;
|
|
21917
|
+
// src/tab-registry.ts
|
|
21918
|
+
function indexTabs(reports, isOpen) {
|
|
21919
|
+
const index = /* @__PURE__ */ new Map();
|
|
21920
|
+
for (const r of [...reports].sort((a, b) => a.at - b.at)) {
|
|
21921
|
+
if (isOpen(r.socket)) index.set(r.projectId, r);
|
|
21052
21922
|
}
|
|
21923
|
+
return index;
|
|
21053
21924
|
}
|
|
21054
|
-
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
|
|
21058
|
-
|
|
21059
|
-
return false;
|
|
21925
|
+
|
|
21926
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
|
|
21927
|
+
var ExperimentalClientTasks = class {
|
|
21928
|
+
constructor(_client) {
|
|
21929
|
+
this._client = _client;
|
|
21060
21930
|
}
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
|
|
21931
|
+
/**
|
|
21932
|
+
* Calls a tool and returns an AsyncGenerator that yields response messages.
|
|
21933
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
21934
|
+
*
|
|
21935
|
+
* This method provides streaming access to tool execution, allowing you to
|
|
21936
|
+
* observe intermediate task status updates for long-running tool calls.
|
|
21937
|
+
* Automatically validates structured output if the tool has an outputSchema.
|
|
21938
|
+
*
|
|
21939
|
+
* @example
|
|
21940
|
+
* ```typescript
|
|
21941
|
+
* const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
|
|
21942
|
+
* for await (const message of stream) {
|
|
21943
|
+
* switch (message.type) {
|
|
21944
|
+
* case 'taskCreated':
|
|
21945
|
+
* console.log('Tool execution started:', message.task.taskId);
|
|
21946
|
+
* break;
|
|
21947
|
+
* case 'taskStatus':
|
|
21948
|
+
* console.log('Tool status:', message.task.status);
|
|
21949
|
+
* break;
|
|
21950
|
+
* case 'result':
|
|
21951
|
+
* console.log('Tool result:', message.result);
|
|
21952
|
+
* break;
|
|
21953
|
+
* case 'error':
|
|
21954
|
+
* console.error('Tool error:', message.error);
|
|
21955
|
+
* break;
|
|
21956
|
+
* }
|
|
21957
|
+
* }
|
|
21958
|
+
* ```
|
|
21959
|
+
*
|
|
21960
|
+
* @param params - Tool call parameters (name and arguments)
|
|
21961
|
+
* @param resultSchema - Zod schema for validating the result (defaults to CallToolResultSchema)
|
|
21962
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
21963
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
21964
|
+
*
|
|
21965
|
+
* @experimental
|
|
21966
|
+
*/
|
|
21967
|
+
async *callToolStream(params, resultSchema = CallToolResultSchema, options) {
|
|
21968
|
+
const clientInternal = this._client;
|
|
21969
|
+
const optionsWithTask = {
|
|
21970
|
+
...options,
|
|
21971
|
+
// We check if the tool is known to be a task during auto-configuration, but assume
|
|
21972
|
+
// the caller knows what they're doing if they pass this explicitly
|
|
21973
|
+
task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : void 0)
|
|
21974
|
+
};
|
|
21975
|
+
const stream = clientInternal.requestStream({ method: "tools/call", params }, resultSchema, optionsWithTask);
|
|
21976
|
+
const validator = clientInternal.getToolOutputValidator(params.name);
|
|
21977
|
+
for await (const message of stream) {
|
|
21978
|
+
if (message.type === "result" && validator) {
|
|
21979
|
+
const result = message.result;
|
|
21980
|
+
if (!result.structuredContent && !result.isError) {
|
|
21981
|
+
yield {
|
|
21982
|
+
type: "error",
|
|
21983
|
+
error: new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`)
|
|
21984
|
+
};
|
|
21985
|
+
return;
|
|
21986
|
+
}
|
|
21987
|
+
if (result.structuredContent) {
|
|
21988
|
+
try {
|
|
21989
|
+
const validationResult = validator(result.structuredContent);
|
|
21990
|
+
if (!validationResult.valid) {
|
|
21991
|
+
yield {
|
|
21992
|
+
type: "error",
|
|
21993
|
+
error: new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`)
|
|
21994
|
+
};
|
|
21995
|
+
return;
|
|
21996
|
+
}
|
|
21997
|
+
} catch (error2) {
|
|
21998
|
+
if (error2 instanceof McpError) {
|
|
21999
|
+
yield { type: "error", error: error2 };
|
|
22000
|
+
return;
|
|
22001
|
+
}
|
|
22002
|
+
yield {
|
|
22003
|
+
type: "error",
|
|
22004
|
+
error: new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error2 instanceof Error ? error2.message : String(error2)}`)
|
|
22005
|
+
};
|
|
22006
|
+
return;
|
|
22007
|
+
}
|
|
22008
|
+
}
|
|
22009
|
+
}
|
|
22010
|
+
yield message;
|
|
21090
22011
|
}
|
|
21091
22012
|
}
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
|
|
21098
|
-
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21103
|
-
".aac": { mime: "audio/aac", kind: "audio" },
|
|
21104
|
-
".ogg": { mime: "audio/ogg", kind: "audio" },
|
|
21105
|
-
".flac": { mime: "audio/flac", kind: "audio" },
|
|
21106
|
-
".png": { mime: "image/png", kind: "image" },
|
|
21107
|
-
".jpg": { mime: "image/jpeg", kind: "image" },
|
|
21108
|
-
".jpeg": { mime: "image/jpeg", kind: "image" },
|
|
21109
|
-
".gif": { mime: "image/gif", kind: "image" },
|
|
21110
|
-
".webp": { mime: "image/webp", kind: "image" },
|
|
21111
|
-
".svg": { mime: "image/svg+xml", kind: "image" },
|
|
21112
|
-
".json": { mime: "application/json", kind: "lottie" },
|
|
21113
|
-
".glb": { mime: "model/gltf-binary", kind: "model" }
|
|
21114
|
-
};
|
|
21115
|
-
function mediaUrl(rel) {
|
|
21116
|
-
return `http://localhost:${WEBSOCKET_PORT}/media/${rel.split(path2.sep).map(encodeURIComponent).join("/")}`;
|
|
21117
|
-
}
|
|
21118
|
-
var MAX_LISTED_ASSETS = 500;
|
|
21119
|
-
var MAX_ASSET_DEPTH = 4;
|
|
21120
|
-
async function handleListLocalAssets(args = {}) {
|
|
21121
|
-
if (!fs2.existsSync(LOCAL_ASSETS_DIR)) {
|
|
21122
|
-
throw new Error(
|
|
21123
|
-
`Assets directory does not exist: ${LOCAL_ASSETS_DIR}. Set GOATEDIT_ASSETS_DIR to a folder of media.`
|
|
21124
|
-
);
|
|
22013
|
+
/**
|
|
22014
|
+
* Gets the current status of a task.
|
|
22015
|
+
*
|
|
22016
|
+
* @param taskId - The task identifier
|
|
22017
|
+
* @param options - Optional request options
|
|
22018
|
+
* @returns The task status
|
|
22019
|
+
*
|
|
22020
|
+
* @experimental
|
|
22021
|
+
*/
|
|
22022
|
+
async getTask(taskId, options) {
|
|
22023
|
+
return this._client.getTask({ taskId }, options);
|
|
21125
22024
|
}
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
22025
|
+
/**
|
|
22026
|
+
* Retrieves the result of a completed task.
|
|
22027
|
+
*
|
|
22028
|
+
* @param taskId - The task identifier
|
|
22029
|
+
* @param resultSchema - Zod schema for validating the result
|
|
22030
|
+
* @param options - Optional request options
|
|
22031
|
+
* @returns The task result
|
|
22032
|
+
*
|
|
22033
|
+
* @experimental
|
|
22034
|
+
*/
|
|
22035
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
22036
|
+
return this._client.getTaskResult({ taskId }, resultSchema, options);
|
|
21129
22037
|
}
|
|
21130
|
-
|
|
21131
|
-
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
21135
|
-
|
|
21136
|
-
|
|
21137
|
-
|
|
21138
|
-
|
|
21139
|
-
|
|
21140
|
-
|
|
21141
|
-
|
|
21142
|
-
|
|
21143
|
-
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
|
|
21147
|
-
|
|
21148
|
-
|
|
22038
|
+
/**
|
|
22039
|
+
* Lists tasks with optional pagination.
|
|
22040
|
+
*
|
|
22041
|
+
* @param cursor - Optional pagination cursor
|
|
22042
|
+
* @param options - Optional request options
|
|
22043
|
+
* @returns List of tasks with optional next cursor
|
|
22044
|
+
*
|
|
22045
|
+
* @experimental
|
|
22046
|
+
*/
|
|
22047
|
+
async listTasks(cursor, options) {
|
|
22048
|
+
return this._client.listTasks(cursor ? { cursor } : void 0, options);
|
|
22049
|
+
}
|
|
22050
|
+
/**
|
|
22051
|
+
* Cancels a running task.
|
|
22052
|
+
*
|
|
22053
|
+
* @param taskId - The task identifier
|
|
22054
|
+
* @param options - Optional request options
|
|
22055
|
+
*
|
|
22056
|
+
* @experimental
|
|
22057
|
+
*/
|
|
22058
|
+
async cancelTask(taskId, options) {
|
|
22059
|
+
return this._client.cancelTask({ taskId }, options);
|
|
22060
|
+
}
|
|
22061
|
+
/**
|
|
22062
|
+
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
22063
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
22064
|
+
*
|
|
22065
|
+
* This method provides streaming access to request processing, allowing you to
|
|
22066
|
+
* observe intermediate task status updates for task-augmented requests.
|
|
22067
|
+
*
|
|
22068
|
+
* @param request - The request to send
|
|
22069
|
+
* @param resultSchema - Zod schema for validating the result
|
|
22070
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
22071
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
22072
|
+
*
|
|
22073
|
+
* @experimental
|
|
22074
|
+
*/
|
|
22075
|
+
requestStream(request, resultSchema, options) {
|
|
22076
|
+
return this._client.requestStream(request, resultSchema, options);
|
|
22077
|
+
}
|
|
22078
|
+
};
|
|
22079
|
+
|
|
22080
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
|
|
22081
|
+
function applyElicitationDefaults(schema, data) {
|
|
22082
|
+
if (!schema || data === null || typeof data !== "object")
|
|
22083
|
+
return;
|
|
22084
|
+
if (schema.type === "object" && schema.properties && typeof schema.properties === "object") {
|
|
22085
|
+
const obj = data;
|
|
22086
|
+
const props = schema.properties;
|
|
22087
|
+
for (const key of Object.keys(props)) {
|
|
22088
|
+
const propSchema = props[key];
|
|
22089
|
+
if (obj[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) {
|
|
22090
|
+
obj[key] = propSchema.default;
|
|
22091
|
+
}
|
|
22092
|
+
if (obj[key] !== void 0) {
|
|
22093
|
+
applyElicitationDefaults(propSchema, obj[key]);
|
|
22094
|
+
}
|
|
22095
|
+
}
|
|
22096
|
+
}
|
|
22097
|
+
if (Array.isArray(schema.anyOf)) {
|
|
22098
|
+
for (const sub of schema.anyOf) {
|
|
22099
|
+
if (typeof sub !== "boolean") {
|
|
22100
|
+
applyElicitationDefaults(sub, data);
|
|
22101
|
+
}
|
|
22102
|
+
}
|
|
22103
|
+
}
|
|
22104
|
+
if (Array.isArray(schema.oneOf)) {
|
|
22105
|
+
for (const sub of schema.oneOf) {
|
|
22106
|
+
if (typeof sub !== "boolean") {
|
|
22107
|
+
applyElicitationDefaults(sub, data);
|
|
22108
|
+
}
|
|
22109
|
+
}
|
|
22110
|
+
}
|
|
22111
|
+
}
|
|
22112
|
+
function getSupportedElicitationModes(capabilities) {
|
|
22113
|
+
if (!capabilities) {
|
|
22114
|
+
return { supportsFormMode: false, supportsUrlMode: false };
|
|
22115
|
+
}
|
|
22116
|
+
const hasFormCapability = capabilities.form !== void 0;
|
|
22117
|
+
const hasUrlCapability = capabilities.url !== void 0;
|
|
22118
|
+
const supportsFormMode = hasFormCapability || !hasFormCapability && !hasUrlCapability;
|
|
22119
|
+
const supportsUrlMode = hasUrlCapability;
|
|
22120
|
+
return { supportsFormMode, supportsUrlMode };
|
|
22121
|
+
}
|
|
22122
|
+
var Client = class extends Protocol {
|
|
22123
|
+
/**
|
|
22124
|
+
* Initializes this client with the given name and version information.
|
|
22125
|
+
*/
|
|
22126
|
+
constructor(_clientInfo, options) {
|
|
22127
|
+
super(options);
|
|
22128
|
+
this._clientInfo = _clientInfo;
|
|
22129
|
+
this._cachedToolOutputValidators = /* @__PURE__ */ new Map();
|
|
22130
|
+
this._cachedKnownTaskTools = /* @__PURE__ */ new Set();
|
|
22131
|
+
this._cachedRequiredTaskTools = /* @__PURE__ */ new Set();
|
|
22132
|
+
this._listChangedDebounceTimers = /* @__PURE__ */ new Map();
|
|
22133
|
+
this._capabilities = options?.capabilities ?? {};
|
|
22134
|
+
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator();
|
|
22135
|
+
if (options?.listChanged) {
|
|
22136
|
+
this._pendingListChangedConfig = options.listChanged;
|
|
22137
|
+
}
|
|
22138
|
+
}
|
|
22139
|
+
/**
|
|
22140
|
+
* Set up handlers for list changed notifications based on config and server capabilities.
|
|
22141
|
+
* This should only be called after initialization when server capabilities are known.
|
|
22142
|
+
* Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
|
|
22143
|
+
* @internal
|
|
22144
|
+
*/
|
|
22145
|
+
_setupListChangedHandlers(config2) {
|
|
22146
|
+
if (config2.tools && this._serverCapabilities?.tools?.listChanged) {
|
|
22147
|
+
this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config2.tools, async () => {
|
|
22148
|
+
const result = await this.listTools();
|
|
22149
|
+
return result.tools;
|
|
22150
|
+
});
|
|
22151
|
+
}
|
|
22152
|
+
if (config2.prompts && this._serverCapabilities?.prompts?.listChanged) {
|
|
22153
|
+
this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config2.prompts, async () => {
|
|
22154
|
+
const result = await this.listPrompts();
|
|
22155
|
+
return result.prompts;
|
|
22156
|
+
});
|
|
22157
|
+
}
|
|
22158
|
+
if (config2.resources && this._serverCapabilities?.resources?.listChanged) {
|
|
22159
|
+
this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config2.resources, async () => {
|
|
22160
|
+
const result = await this.listResources();
|
|
22161
|
+
return result.resources;
|
|
22162
|
+
});
|
|
22163
|
+
}
|
|
22164
|
+
}
|
|
22165
|
+
/**
|
|
22166
|
+
* Access experimental features.
|
|
22167
|
+
*
|
|
22168
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
22169
|
+
*
|
|
22170
|
+
* @experimental
|
|
22171
|
+
*/
|
|
22172
|
+
get experimental() {
|
|
22173
|
+
if (!this._experimental) {
|
|
22174
|
+
this._experimental = {
|
|
22175
|
+
tasks: new ExperimentalClientTasks(this)
|
|
22176
|
+
};
|
|
22177
|
+
}
|
|
22178
|
+
return this._experimental;
|
|
22179
|
+
}
|
|
22180
|
+
/**
|
|
22181
|
+
* Registers new capabilities. This can only be called before connecting to a transport.
|
|
22182
|
+
*
|
|
22183
|
+
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
|
22184
|
+
*/
|
|
22185
|
+
registerCapabilities(capabilities) {
|
|
22186
|
+
if (this.transport) {
|
|
22187
|
+
throw new Error("Cannot register capabilities after connecting to transport");
|
|
22188
|
+
}
|
|
22189
|
+
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
|
|
22190
|
+
}
|
|
22191
|
+
/**
|
|
22192
|
+
* Override request handler registration to enforce client-side validation for elicitation.
|
|
22193
|
+
*/
|
|
22194
|
+
setRequestHandler(requestSchema, handler) {
|
|
22195
|
+
const shape = getObjectShape(requestSchema);
|
|
22196
|
+
const methodSchema = shape?.method;
|
|
22197
|
+
if (!methodSchema) {
|
|
22198
|
+
throw new Error("Schema is missing a method literal");
|
|
22199
|
+
}
|
|
22200
|
+
let methodValue;
|
|
22201
|
+
if (isZ4Schema(methodSchema)) {
|
|
22202
|
+
const v4Schema = methodSchema;
|
|
22203
|
+
const v4Def = v4Schema._zod?.def;
|
|
22204
|
+
methodValue = v4Def?.value ?? v4Schema.value;
|
|
22205
|
+
} else {
|
|
22206
|
+
const v3Schema = methodSchema;
|
|
22207
|
+
const legacyDef = v3Schema._def;
|
|
22208
|
+
methodValue = legacyDef?.value ?? v3Schema.value;
|
|
22209
|
+
}
|
|
22210
|
+
if (typeof methodValue !== "string") {
|
|
22211
|
+
throw new Error("Schema method literal must be a string");
|
|
22212
|
+
}
|
|
22213
|
+
const method = methodValue;
|
|
22214
|
+
if (method === "elicitation/create") {
|
|
22215
|
+
const wrappedHandler = async (request, extra) => {
|
|
22216
|
+
const validatedRequest = safeParse2(ElicitRequestSchema, request);
|
|
22217
|
+
if (!validatedRequest.success) {
|
|
22218
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
22219
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation request: ${errorMessage}`);
|
|
22220
|
+
}
|
|
22221
|
+
const { params } = validatedRequest.data;
|
|
22222
|
+
params.mode = params.mode ?? "form";
|
|
22223
|
+
const { supportsFormMode, supportsUrlMode } = getSupportedElicitationModes(this._capabilities.elicitation);
|
|
22224
|
+
if (params.mode === "form" && !supportsFormMode) {
|
|
22225
|
+
throw new McpError(ErrorCode.InvalidParams, "Client does not support form-mode elicitation requests");
|
|
22226
|
+
}
|
|
22227
|
+
if (params.mode === "url" && !supportsUrlMode) {
|
|
22228
|
+
throw new McpError(ErrorCode.InvalidParams, "Client does not support URL-mode elicitation requests");
|
|
22229
|
+
}
|
|
22230
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
22231
|
+
if (params.task) {
|
|
22232
|
+
const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
|
|
22233
|
+
if (!taskValidationResult.success) {
|
|
22234
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
22235
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
22236
|
+
}
|
|
22237
|
+
return taskValidationResult.data;
|
|
22238
|
+
}
|
|
22239
|
+
const validationResult = safeParse2(ElicitResultSchema, result);
|
|
22240
|
+
if (!validationResult.success) {
|
|
22241
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
22242
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation result: ${errorMessage}`);
|
|
22243
|
+
}
|
|
22244
|
+
const validatedResult = validationResult.data;
|
|
22245
|
+
const requestedSchema = params.mode === "form" ? params.requestedSchema : void 0;
|
|
22246
|
+
if (params.mode === "form" && validatedResult.action === "accept" && validatedResult.content && requestedSchema) {
|
|
22247
|
+
if (this._capabilities.elicitation?.form?.applyDefaults) {
|
|
22248
|
+
try {
|
|
22249
|
+
applyElicitationDefaults(requestedSchema, validatedResult.content);
|
|
22250
|
+
} catch {
|
|
22251
|
+
}
|
|
22252
|
+
}
|
|
22253
|
+
}
|
|
22254
|
+
return validatedResult;
|
|
22255
|
+
};
|
|
22256
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
22257
|
+
}
|
|
22258
|
+
if (method === "sampling/createMessage") {
|
|
22259
|
+
const wrappedHandler = async (request, extra) => {
|
|
22260
|
+
const validatedRequest = safeParse2(CreateMessageRequestSchema, request);
|
|
22261
|
+
if (!validatedRequest.success) {
|
|
22262
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
22263
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling request: ${errorMessage}`);
|
|
22264
|
+
}
|
|
22265
|
+
const { params } = validatedRequest.data;
|
|
22266
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
22267
|
+
if (params.task) {
|
|
22268
|
+
const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
|
|
22269
|
+
if (!taskValidationResult.success) {
|
|
22270
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
22271
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
22272
|
+
}
|
|
22273
|
+
return taskValidationResult.data;
|
|
22274
|
+
}
|
|
22275
|
+
const hasTools = params.tools || params.toolChoice;
|
|
22276
|
+
const resultSchema = hasTools ? CreateMessageResultWithToolsSchema : CreateMessageResultSchema;
|
|
22277
|
+
const validationResult = safeParse2(resultSchema, result);
|
|
22278
|
+
if (!validationResult.success) {
|
|
22279
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
22280
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling result: ${errorMessage}`);
|
|
22281
|
+
}
|
|
22282
|
+
return validationResult.data;
|
|
22283
|
+
};
|
|
22284
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
22285
|
+
}
|
|
22286
|
+
return super.setRequestHandler(requestSchema, handler);
|
|
22287
|
+
}
|
|
22288
|
+
assertCapability(capability, method) {
|
|
22289
|
+
if (!this._serverCapabilities?.[capability]) {
|
|
22290
|
+
throw new Error(`Server does not support ${capability} (required for ${method})`);
|
|
22291
|
+
}
|
|
22292
|
+
}
|
|
22293
|
+
async connect(transport, options) {
|
|
22294
|
+
await super.connect(transport);
|
|
22295
|
+
if (transport.sessionId !== void 0) {
|
|
22296
|
+
return;
|
|
22297
|
+
}
|
|
22298
|
+
try {
|
|
22299
|
+
const result = await this.request({
|
|
22300
|
+
method: "initialize",
|
|
22301
|
+
params: {
|
|
22302
|
+
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
22303
|
+
capabilities: this._capabilities,
|
|
22304
|
+
clientInfo: this._clientInfo
|
|
22305
|
+
}
|
|
22306
|
+
}, InitializeResultSchema, options);
|
|
22307
|
+
if (result === void 0) {
|
|
22308
|
+
throw new Error(`Server sent invalid initialize result: ${result}`);
|
|
22309
|
+
}
|
|
22310
|
+
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
|
22311
|
+
throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
|
|
22312
|
+
}
|
|
22313
|
+
this._serverCapabilities = result.capabilities;
|
|
22314
|
+
this._serverVersion = result.serverInfo;
|
|
22315
|
+
if (transport.setProtocolVersion) {
|
|
22316
|
+
transport.setProtocolVersion(result.protocolVersion);
|
|
22317
|
+
}
|
|
22318
|
+
this._instructions = result.instructions;
|
|
22319
|
+
await this.notification({
|
|
22320
|
+
method: "notifications/initialized"
|
|
22321
|
+
});
|
|
22322
|
+
if (this._pendingListChangedConfig) {
|
|
22323
|
+
this._setupListChangedHandlers(this._pendingListChangedConfig);
|
|
22324
|
+
this._pendingListChangedConfig = void 0;
|
|
22325
|
+
}
|
|
22326
|
+
} catch (error2) {
|
|
22327
|
+
void this.close();
|
|
22328
|
+
throw error2;
|
|
22329
|
+
}
|
|
22330
|
+
}
|
|
22331
|
+
/**
|
|
22332
|
+
* After initialization has completed, this will be populated with the server's reported capabilities.
|
|
22333
|
+
*/
|
|
22334
|
+
getServerCapabilities() {
|
|
22335
|
+
return this._serverCapabilities;
|
|
22336
|
+
}
|
|
22337
|
+
/**
|
|
22338
|
+
* After initialization has completed, this will be populated with information about the server's name and version.
|
|
22339
|
+
*/
|
|
22340
|
+
getServerVersion() {
|
|
22341
|
+
return this._serverVersion;
|
|
22342
|
+
}
|
|
22343
|
+
/**
|
|
22344
|
+
* After initialization has completed, this may be populated with information about the server's instructions.
|
|
22345
|
+
*/
|
|
22346
|
+
getInstructions() {
|
|
22347
|
+
return this._instructions;
|
|
22348
|
+
}
|
|
22349
|
+
assertCapabilityForMethod(method) {
|
|
22350
|
+
switch (method) {
|
|
22351
|
+
case "logging/setLevel":
|
|
22352
|
+
if (!this._serverCapabilities?.logging) {
|
|
22353
|
+
throw new Error(`Server does not support logging (required for ${method})`);
|
|
22354
|
+
}
|
|
22355
|
+
break;
|
|
22356
|
+
case "prompts/get":
|
|
22357
|
+
case "prompts/list":
|
|
22358
|
+
if (!this._serverCapabilities?.prompts) {
|
|
22359
|
+
throw new Error(`Server does not support prompts (required for ${method})`);
|
|
22360
|
+
}
|
|
22361
|
+
break;
|
|
22362
|
+
case "resources/list":
|
|
22363
|
+
case "resources/templates/list":
|
|
22364
|
+
case "resources/read":
|
|
22365
|
+
case "resources/subscribe":
|
|
22366
|
+
case "resources/unsubscribe":
|
|
22367
|
+
if (!this._serverCapabilities?.resources) {
|
|
22368
|
+
throw new Error(`Server does not support resources (required for ${method})`);
|
|
22369
|
+
}
|
|
22370
|
+
if (method === "resources/subscribe" && !this._serverCapabilities.resources.subscribe) {
|
|
22371
|
+
throw new Error(`Server does not support resource subscriptions (required for ${method})`);
|
|
22372
|
+
}
|
|
22373
|
+
break;
|
|
22374
|
+
case "tools/call":
|
|
22375
|
+
case "tools/list":
|
|
22376
|
+
if (!this._serverCapabilities?.tools) {
|
|
22377
|
+
throw new Error(`Server does not support tools (required for ${method})`);
|
|
22378
|
+
}
|
|
22379
|
+
break;
|
|
22380
|
+
case "completion/complete":
|
|
22381
|
+
if (!this._serverCapabilities?.completions) {
|
|
22382
|
+
throw new Error(`Server does not support completions (required for ${method})`);
|
|
22383
|
+
}
|
|
22384
|
+
break;
|
|
22385
|
+
case "initialize":
|
|
22386
|
+
break;
|
|
22387
|
+
case "ping":
|
|
22388
|
+
break;
|
|
22389
|
+
}
|
|
22390
|
+
}
|
|
22391
|
+
assertNotificationCapability(method) {
|
|
22392
|
+
switch (method) {
|
|
22393
|
+
case "notifications/roots/list_changed":
|
|
22394
|
+
if (!this._capabilities.roots?.listChanged) {
|
|
22395
|
+
throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
|
|
22396
|
+
}
|
|
22397
|
+
break;
|
|
22398
|
+
case "notifications/initialized":
|
|
22399
|
+
break;
|
|
22400
|
+
case "notifications/cancelled":
|
|
22401
|
+
break;
|
|
22402
|
+
case "notifications/progress":
|
|
22403
|
+
break;
|
|
22404
|
+
}
|
|
22405
|
+
}
|
|
22406
|
+
assertRequestHandlerCapability(method) {
|
|
22407
|
+
if (!this._capabilities) {
|
|
22408
|
+
return;
|
|
22409
|
+
}
|
|
22410
|
+
switch (method) {
|
|
22411
|
+
case "sampling/createMessage":
|
|
22412
|
+
if (!this._capabilities.sampling) {
|
|
22413
|
+
throw new Error(`Client does not support sampling capability (required for ${method})`);
|
|
22414
|
+
}
|
|
22415
|
+
break;
|
|
22416
|
+
case "elicitation/create":
|
|
22417
|
+
if (!this._capabilities.elicitation) {
|
|
22418
|
+
throw new Error(`Client does not support elicitation capability (required for ${method})`);
|
|
22419
|
+
}
|
|
22420
|
+
break;
|
|
22421
|
+
case "roots/list":
|
|
22422
|
+
if (!this._capabilities.roots) {
|
|
22423
|
+
throw new Error(`Client does not support roots capability (required for ${method})`);
|
|
22424
|
+
}
|
|
22425
|
+
break;
|
|
22426
|
+
case "tasks/get":
|
|
22427
|
+
case "tasks/list":
|
|
22428
|
+
case "tasks/result":
|
|
22429
|
+
case "tasks/cancel":
|
|
22430
|
+
if (!this._capabilities.tasks) {
|
|
22431
|
+
throw new Error(`Client does not support tasks capability (required for ${method})`);
|
|
22432
|
+
}
|
|
22433
|
+
break;
|
|
22434
|
+
case "ping":
|
|
22435
|
+
break;
|
|
22436
|
+
}
|
|
22437
|
+
}
|
|
22438
|
+
assertTaskCapability(method) {
|
|
22439
|
+
assertToolsCallTaskCapability(this._serverCapabilities?.tasks?.requests, method, "Server");
|
|
22440
|
+
}
|
|
22441
|
+
assertTaskHandlerCapability(method) {
|
|
22442
|
+
if (!this._capabilities) {
|
|
22443
|
+
return;
|
|
22444
|
+
}
|
|
22445
|
+
assertClientRequestTaskCapability(this._capabilities.tasks?.requests, method, "Client");
|
|
22446
|
+
}
|
|
22447
|
+
async ping(options) {
|
|
22448
|
+
return this.request({ method: "ping" }, EmptyResultSchema, options);
|
|
22449
|
+
}
|
|
22450
|
+
async complete(params, options) {
|
|
22451
|
+
return this.request({ method: "completion/complete", params }, CompleteResultSchema, options);
|
|
22452
|
+
}
|
|
22453
|
+
async setLoggingLevel(level, options) {
|
|
22454
|
+
return this.request({ method: "logging/setLevel", params: { level } }, EmptyResultSchema, options);
|
|
22455
|
+
}
|
|
22456
|
+
async getPrompt(params, options) {
|
|
22457
|
+
return this.request({ method: "prompts/get", params }, GetPromptResultSchema, options);
|
|
22458
|
+
}
|
|
22459
|
+
async listPrompts(params, options) {
|
|
22460
|
+
return this.request({ method: "prompts/list", params }, ListPromptsResultSchema, options);
|
|
22461
|
+
}
|
|
22462
|
+
async listResources(params, options) {
|
|
22463
|
+
return this.request({ method: "resources/list", params }, ListResourcesResultSchema, options);
|
|
22464
|
+
}
|
|
22465
|
+
async listResourceTemplates(params, options) {
|
|
22466
|
+
return this.request({ method: "resources/templates/list", params }, ListResourceTemplatesResultSchema, options);
|
|
22467
|
+
}
|
|
22468
|
+
async readResource(params, options) {
|
|
22469
|
+
return this.request({ method: "resources/read", params }, ReadResourceResultSchema, options);
|
|
22470
|
+
}
|
|
22471
|
+
async subscribeResource(params, options) {
|
|
22472
|
+
return this.request({ method: "resources/subscribe", params }, EmptyResultSchema, options);
|
|
22473
|
+
}
|
|
22474
|
+
async unsubscribeResource(params, options) {
|
|
22475
|
+
return this.request({ method: "resources/unsubscribe", params }, EmptyResultSchema, options);
|
|
22476
|
+
}
|
|
22477
|
+
/**
|
|
22478
|
+
* Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
|
|
22479
|
+
*
|
|
22480
|
+
* For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
|
|
22481
|
+
*/
|
|
22482
|
+
async callTool(params, resultSchema = CallToolResultSchema, options) {
|
|
22483
|
+
if (this.isToolTaskRequired(params.name)) {
|
|
22484
|
+
throw new McpError(ErrorCode.InvalidRequest, `Tool "${params.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);
|
|
22485
|
+
}
|
|
22486
|
+
const result = await this.request({ method: "tools/call", params }, resultSchema, options);
|
|
22487
|
+
const validator = this.getToolOutputValidator(params.name);
|
|
22488
|
+
if (validator) {
|
|
22489
|
+
if (!result.structuredContent && !result.isError) {
|
|
22490
|
+
throw new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`);
|
|
22491
|
+
}
|
|
22492
|
+
if (result.structuredContent) {
|
|
22493
|
+
try {
|
|
22494
|
+
const validationResult = validator(result.structuredContent);
|
|
22495
|
+
if (!validationResult.valid) {
|
|
22496
|
+
throw new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`);
|
|
22497
|
+
}
|
|
22498
|
+
} catch (error2) {
|
|
22499
|
+
if (error2 instanceof McpError) {
|
|
22500
|
+
throw error2;
|
|
22501
|
+
}
|
|
22502
|
+
throw new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
22503
|
+
}
|
|
22504
|
+
}
|
|
22505
|
+
}
|
|
22506
|
+
return result;
|
|
22507
|
+
}
|
|
22508
|
+
isToolTask(toolName) {
|
|
22509
|
+
if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
|
|
22510
|
+
return false;
|
|
22511
|
+
}
|
|
22512
|
+
return this._cachedKnownTaskTools.has(toolName);
|
|
22513
|
+
}
|
|
22514
|
+
/**
|
|
22515
|
+
* Check if a tool requires task-based execution.
|
|
22516
|
+
* Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
|
|
22517
|
+
*/
|
|
22518
|
+
isToolTaskRequired(toolName) {
|
|
22519
|
+
return this._cachedRequiredTaskTools.has(toolName);
|
|
22520
|
+
}
|
|
22521
|
+
/**
|
|
22522
|
+
* Cache validators for tool output schemas.
|
|
22523
|
+
* Called after listTools() to pre-compile validators for better performance.
|
|
22524
|
+
*/
|
|
22525
|
+
cacheToolMetadata(tools) {
|
|
22526
|
+
this._cachedToolOutputValidators.clear();
|
|
22527
|
+
this._cachedKnownTaskTools.clear();
|
|
22528
|
+
this._cachedRequiredTaskTools.clear();
|
|
22529
|
+
for (const tool of tools) {
|
|
22530
|
+
if (tool.outputSchema) {
|
|
22531
|
+
const toolValidator = this._jsonSchemaValidator.getValidator(tool.outputSchema);
|
|
22532
|
+
this._cachedToolOutputValidators.set(tool.name, toolValidator);
|
|
22533
|
+
}
|
|
22534
|
+
const taskSupport = tool.execution?.taskSupport;
|
|
22535
|
+
if (taskSupport === "required" || taskSupport === "optional") {
|
|
22536
|
+
this._cachedKnownTaskTools.add(tool.name);
|
|
22537
|
+
}
|
|
22538
|
+
if (taskSupport === "required") {
|
|
22539
|
+
this._cachedRequiredTaskTools.add(tool.name);
|
|
22540
|
+
}
|
|
22541
|
+
}
|
|
22542
|
+
}
|
|
22543
|
+
/**
|
|
22544
|
+
* Get cached validator for a tool
|
|
22545
|
+
*/
|
|
22546
|
+
getToolOutputValidator(toolName) {
|
|
22547
|
+
return this._cachedToolOutputValidators.get(toolName);
|
|
22548
|
+
}
|
|
22549
|
+
async listTools(params, options) {
|
|
22550
|
+
const result = await this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
|
|
22551
|
+
this.cacheToolMetadata(result.tools);
|
|
22552
|
+
return result;
|
|
22553
|
+
}
|
|
22554
|
+
/**
|
|
22555
|
+
* Set up a single list changed handler.
|
|
22556
|
+
* @internal
|
|
22557
|
+
*/
|
|
22558
|
+
_setupListChangedHandler(listType, notificationSchema, options, fetcher) {
|
|
22559
|
+
const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
|
|
22560
|
+
if (!parseResult.success) {
|
|
22561
|
+
throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
|
22562
|
+
}
|
|
22563
|
+
if (typeof options.onChanged !== "function") {
|
|
22564
|
+
throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
|
|
22565
|
+
}
|
|
22566
|
+
const { autoRefresh, debounceMs } = parseResult.data;
|
|
22567
|
+
const { onChanged } = options;
|
|
22568
|
+
const refresh = async () => {
|
|
22569
|
+
if (!autoRefresh) {
|
|
22570
|
+
onChanged(null, null);
|
|
22571
|
+
return;
|
|
22572
|
+
}
|
|
22573
|
+
try {
|
|
22574
|
+
const items = await fetcher();
|
|
22575
|
+
onChanged(null, items);
|
|
22576
|
+
} catch (e) {
|
|
22577
|
+
const error2 = e instanceof Error ? e : new Error(String(e));
|
|
22578
|
+
onChanged(error2, null);
|
|
22579
|
+
}
|
|
22580
|
+
};
|
|
22581
|
+
const handler = () => {
|
|
22582
|
+
if (debounceMs) {
|
|
22583
|
+
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
|
22584
|
+
if (existingTimer) {
|
|
22585
|
+
clearTimeout(existingTimer);
|
|
22586
|
+
}
|
|
22587
|
+
const timer = setTimeout(refresh, debounceMs);
|
|
22588
|
+
this._listChangedDebounceTimers.set(listType, timer);
|
|
22589
|
+
} else {
|
|
22590
|
+
refresh();
|
|
22591
|
+
}
|
|
22592
|
+
};
|
|
22593
|
+
this.setNotificationHandler(notificationSchema, handler);
|
|
22594
|
+
}
|
|
22595
|
+
async sendRootsListChanged() {
|
|
22596
|
+
return this.notification({ method: "notifications/roots/list_changed" });
|
|
22597
|
+
}
|
|
22598
|
+
};
|
|
22599
|
+
|
|
22600
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
|
|
22601
|
+
var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
22602
|
+
import process4 from "node:process";
|
|
22603
|
+
import { PassThrough } from "node:stream";
|
|
22604
|
+
var DEFAULT_INHERITED_ENV_VARS = process4.platform === "win32" ? [
|
|
22605
|
+
"APPDATA",
|
|
22606
|
+
"HOMEDRIVE",
|
|
22607
|
+
"HOMEPATH",
|
|
22608
|
+
"LOCALAPPDATA",
|
|
22609
|
+
"PATH",
|
|
22610
|
+
"PROCESSOR_ARCHITECTURE",
|
|
22611
|
+
"SYSTEMDRIVE",
|
|
22612
|
+
"SYSTEMROOT",
|
|
22613
|
+
"TEMP",
|
|
22614
|
+
"USERNAME",
|
|
22615
|
+
"USERPROFILE",
|
|
22616
|
+
"PROGRAMFILES"
|
|
22617
|
+
] : (
|
|
22618
|
+
/* list inspired by the default env inheritance of sudo */
|
|
22619
|
+
["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"]
|
|
22620
|
+
);
|
|
22621
|
+
function getDefaultEnvironment() {
|
|
22622
|
+
const env = {};
|
|
22623
|
+
for (const key of DEFAULT_INHERITED_ENV_VARS) {
|
|
22624
|
+
const value = process4.env[key];
|
|
22625
|
+
if (value === void 0) {
|
|
22626
|
+
continue;
|
|
22627
|
+
}
|
|
22628
|
+
if (value.startsWith("()")) {
|
|
22629
|
+
continue;
|
|
22630
|
+
}
|
|
22631
|
+
env[key] = value;
|
|
22632
|
+
}
|
|
22633
|
+
return env;
|
|
22634
|
+
}
|
|
22635
|
+
var StdioClientTransport = class {
|
|
22636
|
+
constructor(server2) {
|
|
22637
|
+
this._readBuffer = new ReadBuffer();
|
|
22638
|
+
this._stderrStream = null;
|
|
22639
|
+
this._serverParams = server2;
|
|
22640
|
+
if (server2.stderr === "pipe" || server2.stderr === "overlapped") {
|
|
22641
|
+
this._stderrStream = new PassThrough();
|
|
22642
|
+
}
|
|
22643
|
+
}
|
|
22644
|
+
/**
|
|
22645
|
+
* Starts the server process and prepares to communicate with it.
|
|
22646
|
+
*/
|
|
22647
|
+
async start() {
|
|
22648
|
+
if (this._process) {
|
|
22649
|
+
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
22650
|
+
}
|
|
22651
|
+
return new Promise((resolve, reject) => {
|
|
22652
|
+
this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
|
|
22653
|
+
// merge default env with server env because mcp server needs some env vars
|
|
22654
|
+
env: {
|
|
22655
|
+
...getDefaultEnvironment(),
|
|
22656
|
+
...this._serverParams.env
|
|
22657
|
+
},
|
|
22658
|
+
stdio: ["pipe", "pipe", this._serverParams.stderr ?? "inherit"],
|
|
22659
|
+
shell: false,
|
|
22660
|
+
windowsHide: process4.platform === "win32",
|
|
22661
|
+
cwd: this._serverParams.cwd
|
|
22662
|
+
});
|
|
22663
|
+
this._process.on("error", (error2) => {
|
|
22664
|
+
reject(error2);
|
|
22665
|
+
this.onerror?.(error2);
|
|
22666
|
+
});
|
|
22667
|
+
this._process.on("spawn", () => {
|
|
22668
|
+
resolve();
|
|
22669
|
+
});
|
|
22670
|
+
this._process.on("close", (_code) => {
|
|
22671
|
+
this._process = void 0;
|
|
22672
|
+
this.onclose?.();
|
|
22673
|
+
});
|
|
22674
|
+
this._process.stdin?.on("error", (error2) => {
|
|
22675
|
+
this.onerror?.(error2);
|
|
22676
|
+
});
|
|
22677
|
+
this._process.stdout?.on("data", (chunk) => {
|
|
22678
|
+
this._readBuffer.append(chunk);
|
|
22679
|
+
this.processReadBuffer();
|
|
22680
|
+
});
|
|
22681
|
+
this._process.stdout?.on("error", (error2) => {
|
|
22682
|
+
this.onerror?.(error2);
|
|
22683
|
+
});
|
|
22684
|
+
if (this._stderrStream && this._process.stderr) {
|
|
22685
|
+
this._process.stderr.pipe(this._stderrStream);
|
|
22686
|
+
}
|
|
22687
|
+
});
|
|
22688
|
+
}
|
|
22689
|
+
/**
|
|
22690
|
+
* The stderr stream of the child process, if `StdioServerParameters.stderr` was set to "pipe" or "overlapped".
|
|
22691
|
+
*
|
|
22692
|
+
* If stderr piping was requested, a PassThrough stream is returned _immediately_, allowing callers to
|
|
22693
|
+
* attach listeners before the start method is invoked. This prevents loss of any early
|
|
22694
|
+
* error output emitted by the child process.
|
|
22695
|
+
*/
|
|
22696
|
+
get stderr() {
|
|
22697
|
+
if (this._stderrStream) {
|
|
22698
|
+
return this._stderrStream;
|
|
22699
|
+
}
|
|
22700
|
+
return this._process?.stderr ?? null;
|
|
22701
|
+
}
|
|
22702
|
+
/**
|
|
22703
|
+
* The child process pid spawned by this transport.
|
|
22704
|
+
*
|
|
22705
|
+
* This is only available after the transport has been started.
|
|
22706
|
+
*/
|
|
22707
|
+
get pid() {
|
|
22708
|
+
return this._process?.pid ?? null;
|
|
22709
|
+
}
|
|
22710
|
+
processReadBuffer() {
|
|
22711
|
+
while (true) {
|
|
22712
|
+
try {
|
|
22713
|
+
const message = this._readBuffer.readMessage();
|
|
22714
|
+
if (message === null) {
|
|
22715
|
+
break;
|
|
22716
|
+
}
|
|
22717
|
+
this.onmessage?.(message);
|
|
22718
|
+
} catch (error2) {
|
|
22719
|
+
this.onerror?.(error2);
|
|
22720
|
+
}
|
|
22721
|
+
}
|
|
22722
|
+
}
|
|
22723
|
+
async close() {
|
|
22724
|
+
if (this._process) {
|
|
22725
|
+
const processToClose = this._process;
|
|
22726
|
+
this._process = void 0;
|
|
22727
|
+
const closePromise = new Promise((resolve) => {
|
|
22728
|
+
processToClose.once("close", () => {
|
|
22729
|
+
resolve();
|
|
22730
|
+
});
|
|
22731
|
+
});
|
|
22732
|
+
try {
|
|
22733
|
+
processToClose.stdin?.end();
|
|
22734
|
+
} catch {
|
|
22735
|
+
}
|
|
22736
|
+
await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
|
|
22737
|
+
if (processToClose.exitCode === null) {
|
|
22738
|
+
try {
|
|
22739
|
+
processToClose.kill("SIGTERM");
|
|
22740
|
+
} catch {
|
|
22741
|
+
}
|
|
22742
|
+
await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
|
|
22743
|
+
}
|
|
22744
|
+
if (processToClose.exitCode === null) {
|
|
22745
|
+
try {
|
|
22746
|
+
processToClose.kill("SIGKILL");
|
|
22747
|
+
} catch {
|
|
22748
|
+
}
|
|
22749
|
+
}
|
|
22750
|
+
}
|
|
22751
|
+
this._readBuffer.clear();
|
|
22752
|
+
}
|
|
22753
|
+
send(message) {
|
|
22754
|
+
return new Promise((resolve) => {
|
|
22755
|
+
if (!this._process?.stdin) {
|
|
22756
|
+
throw new Error("Not connected");
|
|
22757
|
+
}
|
|
22758
|
+
const json = serializeMessage(message);
|
|
22759
|
+
if (this._process.stdin.write(json)) {
|
|
22760
|
+
resolve();
|
|
22761
|
+
} else {
|
|
22762
|
+
this._process.stdin.once("drain", resolve);
|
|
22763
|
+
}
|
|
22764
|
+
});
|
|
22765
|
+
}
|
|
22766
|
+
};
|
|
22767
|
+
|
|
22768
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
|
|
22769
|
+
function normalizeHeaders(headers) {
|
|
22770
|
+
if (!headers)
|
|
22771
|
+
return {};
|
|
22772
|
+
if (headers instanceof Headers) {
|
|
22773
|
+
return Object.fromEntries(headers.entries());
|
|
22774
|
+
}
|
|
22775
|
+
if (Array.isArray(headers)) {
|
|
22776
|
+
return Object.fromEntries(headers);
|
|
22777
|
+
}
|
|
22778
|
+
return { ...headers };
|
|
22779
|
+
}
|
|
22780
|
+
function createFetchWithInit(baseFetch = fetch, baseInit) {
|
|
22781
|
+
if (!baseInit) {
|
|
22782
|
+
return baseFetch;
|
|
22783
|
+
}
|
|
22784
|
+
return async (url2, init) => {
|
|
22785
|
+
const mergedInit = {
|
|
22786
|
+
...baseInit,
|
|
22787
|
+
...init,
|
|
22788
|
+
// Headers need special handling - merge instead of replace
|
|
22789
|
+
headers: init?.headers ? { ...normalizeHeaders(baseInit.headers), ...normalizeHeaders(init.headers) } : baseInit.headers
|
|
22790
|
+
};
|
|
22791
|
+
return baseFetch(url2, mergedInit);
|
|
22792
|
+
};
|
|
22793
|
+
}
|
|
22794
|
+
|
|
22795
|
+
// node_modules/pkce-challenge/dist/index.node.js
|
|
22796
|
+
var crypto;
|
|
22797
|
+
crypto = globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
|
|
22798
|
+
globalThis.crypto ?? // Node.js >18
|
|
22799
|
+
import("node:crypto").then((m) => m.webcrypto);
|
|
22800
|
+
async function getRandomValues(size) {
|
|
22801
|
+
return (await crypto).getRandomValues(new Uint8Array(size));
|
|
22802
|
+
}
|
|
22803
|
+
async function random(size) {
|
|
22804
|
+
const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
|
22805
|
+
const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
|
|
22806
|
+
let result = "";
|
|
22807
|
+
while (result.length < size) {
|
|
22808
|
+
const randomBytes = await getRandomValues(size - result.length);
|
|
22809
|
+
for (const randomByte of randomBytes) {
|
|
22810
|
+
if (randomByte < evenDistCutoff) {
|
|
22811
|
+
result += mask[randomByte % mask.length];
|
|
22812
|
+
}
|
|
22813
|
+
}
|
|
22814
|
+
}
|
|
22815
|
+
return result;
|
|
22816
|
+
}
|
|
22817
|
+
async function generateVerifier(length) {
|
|
22818
|
+
return await random(length);
|
|
22819
|
+
}
|
|
22820
|
+
async function generateChallenge(code_verifier) {
|
|
22821
|
+
const buffer = await (await crypto).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
|
|
22822
|
+
return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
|
|
22823
|
+
}
|
|
22824
|
+
async function pkceChallenge(length) {
|
|
22825
|
+
if (!length)
|
|
22826
|
+
length = 43;
|
|
22827
|
+
if (length < 43 || length > 128) {
|
|
22828
|
+
throw `Expected a length between 43 and 128. Received ${length}.`;
|
|
22829
|
+
}
|
|
22830
|
+
const verifier = await generateVerifier(length);
|
|
22831
|
+
const challenge = await generateChallenge(verifier);
|
|
22832
|
+
return {
|
|
22833
|
+
code_verifier: verifier,
|
|
22834
|
+
code_challenge: challenge
|
|
22835
|
+
};
|
|
22836
|
+
}
|
|
22837
|
+
|
|
22838
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
|
|
22839
|
+
var SafeUrlSchema = url().superRefine((val, ctx) => {
|
|
22840
|
+
if (!URL.canParse(val)) {
|
|
22841
|
+
ctx.addIssue({
|
|
22842
|
+
code: ZodIssueCode.custom,
|
|
22843
|
+
message: "URL must be parseable",
|
|
22844
|
+
fatal: true
|
|
22845
|
+
});
|
|
22846
|
+
return NEVER;
|
|
22847
|
+
}
|
|
22848
|
+
}).refine((url2) => {
|
|
22849
|
+
const u = new URL(url2);
|
|
22850
|
+
return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
|
|
22851
|
+
}, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
|
|
22852
|
+
var OAuthProtectedResourceMetadataSchema = looseObject({
|
|
22853
|
+
resource: string2().url(),
|
|
22854
|
+
authorization_servers: array(SafeUrlSchema).optional(),
|
|
22855
|
+
jwks_uri: string2().url().optional(),
|
|
22856
|
+
scopes_supported: array(string2()).optional(),
|
|
22857
|
+
bearer_methods_supported: array(string2()).optional(),
|
|
22858
|
+
resource_signing_alg_values_supported: array(string2()).optional(),
|
|
22859
|
+
resource_name: string2().optional(),
|
|
22860
|
+
resource_documentation: string2().optional(),
|
|
22861
|
+
resource_policy_uri: string2().url().optional(),
|
|
22862
|
+
resource_tos_uri: string2().url().optional(),
|
|
22863
|
+
tls_client_certificate_bound_access_tokens: boolean2().optional(),
|
|
22864
|
+
authorization_details_types_supported: array(string2()).optional(),
|
|
22865
|
+
dpop_signing_alg_values_supported: array(string2()).optional(),
|
|
22866
|
+
dpop_bound_access_tokens_required: boolean2().optional()
|
|
22867
|
+
});
|
|
22868
|
+
var OAuthMetadataSchema = looseObject({
|
|
22869
|
+
issuer: string2(),
|
|
22870
|
+
authorization_endpoint: SafeUrlSchema,
|
|
22871
|
+
token_endpoint: SafeUrlSchema,
|
|
22872
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
22873
|
+
scopes_supported: array(string2()).optional(),
|
|
22874
|
+
response_types_supported: array(string2()),
|
|
22875
|
+
response_modes_supported: array(string2()).optional(),
|
|
22876
|
+
grant_types_supported: array(string2()).optional(),
|
|
22877
|
+
token_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22878
|
+
token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22879
|
+
service_documentation: SafeUrlSchema.optional(),
|
|
22880
|
+
revocation_endpoint: SafeUrlSchema.optional(),
|
|
22881
|
+
revocation_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22882
|
+
revocation_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22883
|
+
introspection_endpoint: string2().optional(),
|
|
22884
|
+
introspection_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22885
|
+
introspection_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22886
|
+
code_challenge_methods_supported: array(string2()).optional(),
|
|
22887
|
+
client_id_metadata_document_supported: boolean2().optional()
|
|
22888
|
+
});
|
|
22889
|
+
var OpenIdProviderMetadataSchema = looseObject({
|
|
22890
|
+
issuer: string2(),
|
|
22891
|
+
authorization_endpoint: SafeUrlSchema,
|
|
22892
|
+
token_endpoint: SafeUrlSchema,
|
|
22893
|
+
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
22894
|
+
jwks_uri: SafeUrlSchema,
|
|
22895
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
22896
|
+
scopes_supported: array(string2()).optional(),
|
|
22897
|
+
response_types_supported: array(string2()),
|
|
22898
|
+
response_modes_supported: array(string2()).optional(),
|
|
22899
|
+
grant_types_supported: array(string2()).optional(),
|
|
22900
|
+
acr_values_supported: array(string2()).optional(),
|
|
22901
|
+
subject_types_supported: array(string2()),
|
|
22902
|
+
id_token_signing_alg_values_supported: array(string2()),
|
|
22903
|
+
id_token_encryption_alg_values_supported: array(string2()).optional(),
|
|
22904
|
+
id_token_encryption_enc_values_supported: array(string2()).optional(),
|
|
22905
|
+
userinfo_signing_alg_values_supported: array(string2()).optional(),
|
|
22906
|
+
userinfo_encryption_alg_values_supported: array(string2()).optional(),
|
|
22907
|
+
userinfo_encryption_enc_values_supported: array(string2()).optional(),
|
|
22908
|
+
request_object_signing_alg_values_supported: array(string2()).optional(),
|
|
22909
|
+
request_object_encryption_alg_values_supported: array(string2()).optional(),
|
|
22910
|
+
request_object_encryption_enc_values_supported: array(string2()).optional(),
|
|
22911
|
+
token_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
22912
|
+
token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
22913
|
+
display_values_supported: array(string2()).optional(),
|
|
22914
|
+
claim_types_supported: array(string2()).optional(),
|
|
22915
|
+
claims_supported: array(string2()).optional(),
|
|
22916
|
+
service_documentation: string2().optional(),
|
|
22917
|
+
claims_locales_supported: array(string2()).optional(),
|
|
22918
|
+
ui_locales_supported: array(string2()).optional(),
|
|
22919
|
+
claims_parameter_supported: boolean2().optional(),
|
|
22920
|
+
request_parameter_supported: boolean2().optional(),
|
|
22921
|
+
request_uri_parameter_supported: boolean2().optional(),
|
|
22922
|
+
require_request_uri_registration: boolean2().optional(),
|
|
22923
|
+
op_policy_uri: SafeUrlSchema.optional(),
|
|
22924
|
+
op_tos_uri: SafeUrlSchema.optional(),
|
|
22925
|
+
client_id_metadata_document_supported: boolean2().optional()
|
|
22926
|
+
});
|
|
22927
|
+
var OpenIdProviderDiscoveryMetadataSchema = object2({
|
|
22928
|
+
...OpenIdProviderMetadataSchema.shape,
|
|
22929
|
+
...OAuthMetadataSchema.pick({
|
|
22930
|
+
code_challenge_methods_supported: true
|
|
22931
|
+
}).shape
|
|
22932
|
+
});
|
|
22933
|
+
var OAuthTokensSchema = object2({
|
|
22934
|
+
access_token: string2(),
|
|
22935
|
+
id_token: string2().optional(),
|
|
22936
|
+
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
22937
|
+
token_type: string2(),
|
|
22938
|
+
expires_in: coerce_exports.number().optional(),
|
|
22939
|
+
scope: string2().optional(),
|
|
22940
|
+
refresh_token: string2().optional()
|
|
22941
|
+
}).strip();
|
|
22942
|
+
var OAuthErrorResponseSchema = object2({
|
|
22943
|
+
error: string2(),
|
|
22944
|
+
error_description: string2().optional(),
|
|
22945
|
+
error_uri: string2().optional()
|
|
22946
|
+
});
|
|
22947
|
+
var OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => void 0));
|
|
22948
|
+
var OAuthClientMetadataSchema = object2({
|
|
22949
|
+
redirect_uris: array(SafeUrlSchema),
|
|
22950
|
+
token_endpoint_auth_method: string2().optional(),
|
|
22951
|
+
grant_types: array(string2()).optional(),
|
|
22952
|
+
response_types: array(string2()).optional(),
|
|
22953
|
+
client_name: string2().optional(),
|
|
22954
|
+
client_uri: SafeUrlSchema.optional(),
|
|
22955
|
+
logo_uri: OptionalSafeUrlSchema,
|
|
22956
|
+
scope: string2().optional(),
|
|
22957
|
+
contacts: array(string2()).optional(),
|
|
22958
|
+
tos_uri: OptionalSafeUrlSchema,
|
|
22959
|
+
policy_uri: string2().optional(),
|
|
22960
|
+
jwks_uri: SafeUrlSchema.optional(),
|
|
22961
|
+
jwks: any().optional(),
|
|
22962
|
+
software_id: string2().optional(),
|
|
22963
|
+
software_version: string2().optional(),
|
|
22964
|
+
software_statement: string2().optional()
|
|
22965
|
+
}).strip();
|
|
22966
|
+
var OAuthClientInformationSchema = object2({
|
|
22967
|
+
client_id: string2(),
|
|
22968
|
+
client_secret: string2().optional(),
|
|
22969
|
+
client_id_issued_at: number2().optional(),
|
|
22970
|
+
client_secret_expires_at: number2().optional()
|
|
22971
|
+
}).strip();
|
|
22972
|
+
var OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
|
|
22973
|
+
var OAuthClientRegistrationErrorSchema = object2({
|
|
22974
|
+
error: string2(),
|
|
22975
|
+
error_description: string2().optional()
|
|
22976
|
+
}).strip();
|
|
22977
|
+
var OAuthTokenRevocationRequestSchema = object2({
|
|
22978
|
+
token: string2(),
|
|
22979
|
+
token_type_hint: string2().optional()
|
|
22980
|
+
}).strip();
|
|
22981
|
+
|
|
22982
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
|
|
22983
|
+
function resourceUrlFromServerUrl(url2) {
|
|
22984
|
+
const resourceURL = typeof url2 === "string" ? new URL(url2) : new URL(url2.href);
|
|
22985
|
+
resourceURL.hash = "";
|
|
22986
|
+
return resourceURL;
|
|
22987
|
+
}
|
|
22988
|
+
function checkResourceAllowed({ requestedResource, configuredResource }) {
|
|
22989
|
+
const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
|
|
22990
|
+
const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
|
|
22991
|
+
if (requested.origin !== configured.origin) {
|
|
22992
|
+
return false;
|
|
22993
|
+
}
|
|
22994
|
+
if (requested.pathname.length < configured.pathname.length) {
|
|
22995
|
+
return false;
|
|
22996
|
+
}
|
|
22997
|
+
const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
|
|
22998
|
+
const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
|
|
22999
|
+
return requestedPath.startsWith(configuredPath);
|
|
23000
|
+
}
|
|
23001
|
+
|
|
23002
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
23003
|
+
var OAuthError = class extends Error {
|
|
23004
|
+
constructor(message, errorUri) {
|
|
23005
|
+
super(message);
|
|
23006
|
+
this.errorUri = errorUri;
|
|
23007
|
+
this.name = this.constructor.name;
|
|
23008
|
+
}
|
|
23009
|
+
/**
|
|
23010
|
+
* Converts the error to a standard OAuth error response object
|
|
23011
|
+
*/
|
|
23012
|
+
toResponseObject() {
|
|
23013
|
+
const response = {
|
|
23014
|
+
error: this.errorCode,
|
|
23015
|
+
error_description: this.message
|
|
23016
|
+
};
|
|
23017
|
+
if (this.errorUri) {
|
|
23018
|
+
response.error_uri = this.errorUri;
|
|
23019
|
+
}
|
|
23020
|
+
return response;
|
|
23021
|
+
}
|
|
23022
|
+
get errorCode() {
|
|
23023
|
+
return this.constructor.errorCode;
|
|
23024
|
+
}
|
|
23025
|
+
};
|
|
23026
|
+
var InvalidRequestError = class extends OAuthError {
|
|
23027
|
+
};
|
|
23028
|
+
InvalidRequestError.errorCode = "invalid_request";
|
|
23029
|
+
var InvalidClientError = class extends OAuthError {
|
|
23030
|
+
};
|
|
23031
|
+
InvalidClientError.errorCode = "invalid_client";
|
|
23032
|
+
var InvalidGrantError = class extends OAuthError {
|
|
23033
|
+
};
|
|
23034
|
+
InvalidGrantError.errorCode = "invalid_grant";
|
|
23035
|
+
var UnauthorizedClientError = class extends OAuthError {
|
|
23036
|
+
};
|
|
23037
|
+
UnauthorizedClientError.errorCode = "unauthorized_client";
|
|
23038
|
+
var UnsupportedGrantTypeError = class extends OAuthError {
|
|
23039
|
+
};
|
|
23040
|
+
UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
|
|
23041
|
+
var InvalidScopeError = class extends OAuthError {
|
|
23042
|
+
};
|
|
23043
|
+
InvalidScopeError.errorCode = "invalid_scope";
|
|
23044
|
+
var AccessDeniedError = class extends OAuthError {
|
|
23045
|
+
};
|
|
23046
|
+
AccessDeniedError.errorCode = "access_denied";
|
|
23047
|
+
var ServerError = class extends OAuthError {
|
|
23048
|
+
};
|
|
23049
|
+
ServerError.errorCode = "server_error";
|
|
23050
|
+
var TemporarilyUnavailableError = class extends OAuthError {
|
|
23051
|
+
};
|
|
23052
|
+
TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
|
|
23053
|
+
var UnsupportedResponseTypeError = class extends OAuthError {
|
|
23054
|
+
};
|
|
23055
|
+
UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
|
|
23056
|
+
var UnsupportedTokenTypeError = class extends OAuthError {
|
|
23057
|
+
};
|
|
23058
|
+
UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
|
|
23059
|
+
var InvalidTokenError = class extends OAuthError {
|
|
23060
|
+
};
|
|
23061
|
+
InvalidTokenError.errorCode = "invalid_token";
|
|
23062
|
+
var MethodNotAllowedError = class extends OAuthError {
|
|
23063
|
+
};
|
|
23064
|
+
MethodNotAllowedError.errorCode = "method_not_allowed";
|
|
23065
|
+
var TooManyRequestsError = class extends OAuthError {
|
|
23066
|
+
};
|
|
23067
|
+
TooManyRequestsError.errorCode = "too_many_requests";
|
|
23068
|
+
var InvalidClientMetadataError = class extends OAuthError {
|
|
23069
|
+
};
|
|
23070
|
+
InvalidClientMetadataError.errorCode = "invalid_client_metadata";
|
|
23071
|
+
var InsufficientScopeError = class extends OAuthError {
|
|
23072
|
+
};
|
|
23073
|
+
InsufficientScopeError.errorCode = "insufficient_scope";
|
|
23074
|
+
var InvalidTargetError = class extends OAuthError {
|
|
23075
|
+
};
|
|
23076
|
+
InvalidTargetError.errorCode = "invalid_target";
|
|
23077
|
+
var OAUTH_ERRORS = {
|
|
23078
|
+
[InvalidRequestError.errorCode]: InvalidRequestError,
|
|
23079
|
+
[InvalidClientError.errorCode]: InvalidClientError,
|
|
23080
|
+
[InvalidGrantError.errorCode]: InvalidGrantError,
|
|
23081
|
+
[UnauthorizedClientError.errorCode]: UnauthorizedClientError,
|
|
23082
|
+
[UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
|
|
23083
|
+
[InvalidScopeError.errorCode]: InvalidScopeError,
|
|
23084
|
+
[AccessDeniedError.errorCode]: AccessDeniedError,
|
|
23085
|
+
[ServerError.errorCode]: ServerError,
|
|
23086
|
+
[TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
|
|
23087
|
+
[UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
|
|
23088
|
+
[UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
|
|
23089
|
+
[InvalidTokenError.errorCode]: InvalidTokenError,
|
|
23090
|
+
[MethodNotAllowedError.errorCode]: MethodNotAllowedError,
|
|
23091
|
+
[TooManyRequestsError.errorCode]: TooManyRequestsError,
|
|
23092
|
+
[InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
|
|
23093
|
+
[InsufficientScopeError.errorCode]: InsufficientScopeError,
|
|
23094
|
+
[InvalidTargetError.errorCode]: InvalidTargetError
|
|
23095
|
+
};
|
|
23096
|
+
|
|
23097
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
|
|
23098
|
+
var UnauthorizedError = class extends Error {
|
|
23099
|
+
constructor(message) {
|
|
23100
|
+
super(message ?? "Unauthorized");
|
|
23101
|
+
}
|
|
23102
|
+
};
|
|
23103
|
+
function isClientAuthMethod(method) {
|
|
23104
|
+
return ["client_secret_basic", "client_secret_post", "none"].includes(method);
|
|
23105
|
+
}
|
|
23106
|
+
var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
|
|
23107
|
+
var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
|
|
23108
|
+
function selectClientAuthMethod(clientInformation, supportedMethods) {
|
|
23109
|
+
const hasClientSecret = clientInformation.client_secret !== void 0;
|
|
23110
|
+
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))) {
|
|
23111
|
+
return clientInformation.token_endpoint_auth_method;
|
|
23112
|
+
}
|
|
23113
|
+
if (supportedMethods.length === 0) {
|
|
23114
|
+
return hasClientSecret ? "client_secret_basic" : "none";
|
|
23115
|
+
}
|
|
23116
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
|
|
23117
|
+
return "client_secret_basic";
|
|
23118
|
+
}
|
|
23119
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
|
|
23120
|
+
return "client_secret_post";
|
|
23121
|
+
}
|
|
23122
|
+
if (supportedMethods.includes("none")) {
|
|
23123
|
+
return "none";
|
|
23124
|
+
}
|
|
23125
|
+
return hasClientSecret ? "client_secret_post" : "none";
|
|
23126
|
+
}
|
|
23127
|
+
function applyClientAuthentication(method, clientInformation, headers, params) {
|
|
23128
|
+
const { client_id, client_secret } = clientInformation;
|
|
23129
|
+
switch (method) {
|
|
23130
|
+
case "client_secret_basic":
|
|
23131
|
+
applyBasicAuth(client_id, client_secret, headers);
|
|
23132
|
+
return;
|
|
23133
|
+
case "client_secret_post":
|
|
23134
|
+
applyPostAuth(client_id, client_secret, params);
|
|
23135
|
+
return;
|
|
23136
|
+
case "none":
|
|
23137
|
+
applyPublicAuth(client_id, params);
|
|
23138
|
+
return;
|
|
23139
|
+
default:
|
|
23140
|
+
throw new Error(`Unsupported client authentication method: ${method}`);
|
|
23141
|
+
}
|
|
23142
|
+
}
|
|
23143
|
+
function applyBasicAuth(clientId, clientSecret, headers) {
|
|
23144
|
+
if (!clientSecret) {
|
|
23145
|
+
throw new Error("client_secret_basic authentication requires a client_secret");
|
|
23146
|
+
}
|
|
23147
|
+
const credentials = btoa(`${clientId}:${clientSecret}`);
|
|
23148
|
+
headers.set("Authorization", `Basic ${credentials}`);
|
|
23149
|
+
}
|
|
23150
|
+
function applyPostAuth(clientId, clientSecret, params) {
|
|
23151
|
+
params.set("client_id", clientId);
|
|
23152
|
+
if (clientSecret) {
|
|
23153
|
+
params.set("client_secret", clientSecret);
|
|
23154
|
+
}
|
|
23155
|
+
}
|
|
23156
|
+
function applyPublicAuth(clientId, params) {
|
|
23157
|
+
params.set("client_id", clientId);
|
|
23158
|
+
}
|
|
23159
|
+
async function parseErrorResponse(input) {
|
|
23160
|
+
const statusCode = input instanceof Response ? input.status : void 0;
|
|
23161
|
+
const body = input instanceof Response ? await input.text() : input;
|
|
23162
|
+
try {
|
|
23163
|
+
const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
|
|
23164
|
+
const { error: error2, error_description, error_uri } = result;
|
|
23165
|
+
const errorClass = OAUTH_ERRORS[error2] || ServerError;
|
|
23166
|
+
return new errorClass(error_description || "", error_uri);
|
|
23167
|
+
} catch (error2) {
|
|
23168
|
+
const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error2}. Raw body: ${body}`;
|
|
23169
|
+
return new ServerError(errorMessage);
|
|
23170
|
+
}
|
|
23171
|
+
}
|
|
23172
|
+
async function auth(provider, options) {
|
|
23173
|
+
try {
|
|
23174
|
+
return await authInternal(provider, options);
|
|
23175
|
+
} catch (error2) {
|
|
23176
|
+
if (error2 instanceof InvalidClientError || error2 instanceof UnauthorizedClientError) {
|
|
23177
|
+
await provider.invalidateCredentials?.("all");
|
|
23178
|
+
return await authInternal(provider, options);
|
|
23179
|
+
} else if (error2 instanceof InvalidGrantError) {
|
|
23180
|
+
await provider.invalidateCredentials?.("tokens");
|
|
23181
|
+
return await authInternal(provider, options);
|
|
23182
|
+
}
|
|
23183
|
+
throw error2;
|
|
23184
|
+
}
|
|
23185
|
+
}
|
|
23186
|
+
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
|
|
23187
|
+
const cachedState = await provider.discoveryState?.();
|
|
23188
|
+
let resourceMetadata;
|
|
23189
|
+
let authorizationServerUrl;
|
|
23190
|
+
let metadata;
|
|
23191
|
+
let effectiveResourceMetadataUrl = resourceMetadataUrl;
|
|
23192
|
+
if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
|
|
23193
|
+
effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
|
|
23194
|
+
}
|
|
23195
|
+
if (cachedState?.authorizationServerUrl) {
|
|
23196
|
+
authorizationServerUrl = cachedState.authorizationServerUrl;
|
|
23197
|
+
resourceMetadata = cachedState.resourceMetadata;
|
|
23198
|
+
metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
|
|
23199
|
+
if (!resourceMetadata) {
|
|
23200
|
+
try {
|
|
23201
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
|
|
23202
|
+
} catch {
|
|
23203
|
+
}
|
|
23204
|
+
}
|
|
23205
|
+
if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
|
|
23206
|
+
await provider.saveDiscoveryState?.({
|
|
23207
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
23208
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
23209
|
+
resourceMetadata,
|
|
23210
|
+
authorizationServerMetadata: metadata
|
|
23211
|
+
});
|
|
23212
|
+
}
|
|
23213
|
+
} else {
|
|
23214
|
+
const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
|
|
23215
|
+
authorizationServerUrl = serverInfo.authorizationServerUrl;
|
|
23216
|
+
metadata = serverInfo.authorizationServerMetadata;
|
|
23217
|
+
resourceMetadata = serverInfo.resourceMetadata;
|
|
23218
|
+
await provider.saveDiscoveryState?.({
|
|
23219
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
23220
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
23221
|
+
resourceMetadata,
|
|
23222
|
+
authorizationServerMetadata: metadata
|
|
23223
|
+
});
|
|
23224
|
+
}
|
|
23225
|
+
const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
|
|
23226
|
+
const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
|
|
23227
|
+
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
23228
|
+
if (!clientInformation) {
|
|
23229
|
+
if (authorizationCode !== void 0) {
|
|
23230
|
+
throw new Error("Existing OAuth client information is required when exchanging an authorization code");
|
|
23231
|
+
}
|
|
23232
|
+
const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
|
|
23233
|
+
const clientMetadataUrl = provider.clientMetadataUrl;
|
|
23234
|
+
if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) {
|
|
23235
|
+
throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
|
|
23236
|
+
}
|
|
23237
|
+
const shouldUseUrlBasedClientId = supportsUrlBasedClientId && clientMetadataUrl;
|
|
23238
|
+
if (shouldUseUrlBasedClientId) {
|
|
23239
|
+
clientInformation = {
|
|
23240
|
+
client_id: clientMetadataUrl
|
|
23241
|
+
};
|
|
23242
|
+
await provider.saveClientInformation?.(clientInformation);
|
|
23243
|
+
} else {
|
|
23244
|
+
if (!provider.saveClientInformation) {
|
|
23245
|
+
throw new Error("OAuth client information must be saveable for dynamic registration");
|
|
23246
|
+
}
|
|
23247
|
+
const fullInformation = await registerClient(authorizationServerUrl, {
|
|
23248
|
+
metadata,
|
|
23249
|
+
clientMetadata: provider.clientMetadata,
|
|
23250
|
+
scope: resolvedScope,
|
|
23251
|
+
fetchFn
|
|
23252
|
+
});
|
|
23253
|
+
await provider.saveClientInformation(fullInformation);
|
|
23254
|
+
clientInformation = fullInformation;
|
|
23255
|
+
}
|
|
23256
|
+
}
|
|
23257
|
+
const nonInteractiveFlow = !provider.redirectUrl;
|
|
23258
|
+
if (authorizationCode !== void 0 || nonInteractiveFlow) {
|
|
23259
|
+
const tokens2 = await fetchToken(provider, authorizationServerUrl, {
|
|
23260
|
+
metadata,
|
|
23261
|
+
resource,
|
|
23262
|
+
authorizationCode,
|
|
23263
|
+
fetchFn
|
|
23264
|
+
});
|
|
23265
|
+
await provider.saveTokens(tokens2);
|
|
23266
|
+
return "AUTHORIZED";
|
|
23267
|
+
}
|
|
23268
|
+
const tokens = await provider.tokens();
|
|
23269
|
+
if (tokens?.refresh_token) {
|
|
23270
|
+
try {
|
|
23271
|
+
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
23272
|
+
metadata,
|
|
23273
|
+
clientInformation,
|
|
23274
|
+
refreshToken: tokens.refresh_token,
|
|
23275
|
+
resource,
|
|
23276
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
23277
|
+
fetchFn
|
|
23278
|
+
});
|
|
23279
|
+
await provider.saveTokens(newTokens);
|
|
23280
|
+
return "AUTHORIZED";
|
|
23281
|
+
} catch (error2) {
|
|
23282
|
+
if (!(error2 instanceof OAuthError) || error2 instanceof ServerError) {
|
|
23283
|
+
} else {
|
|
23284
|
+
throw error2;
|
|
23285
|
+
}
|
|
23286
|
+
}
|
|
23287
|
+
}
|
|
23288
|
+
const state = provider.state ? await provider.state() : void 0;
|
|
23289
|
+
const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
|
|
23290
|
+
metadata,
|
|
23291
|
+
clientInformation,
|
|
23292
|
+
state,
|
|
23293
|
+
redirectUrl: provider.redirectUrl,
|
|
23294
|
+
scope: resolvedScope,
|
|
23295
|
+
resource
|
|
23296
|
+
});
|
|
23297
|
+
await provider.saveCodeVerifier(codeVerifier);
|
|
23298
|
+
await provider.redirectToAuthorization(authorizationUrl);
|
|
23299
|
+
return "REDIRECT";
|
|
23300
|
+
}
|
|
23301
|
+
function isHttpsUrl(value) {
|
|
23302
|
+
if (!value)
|
|
23303
|
+
return false;
|
|
23304
|
+
try {
|
|
23305
|
+
const url2 = new URL(value);
|
|
23306
|
+
return url2.protocol === "https:" && url2.pathname !== "/";
|
|
23307
|
+
} catch {
|
|
23308
|
+
return false;
|
|
23309
|
+
}
|
|
23310
|
+
}
|
|
23311
|
+
async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
23312
|
+
const defaultResource = resourceUrlFromServerUrl(serverUrl);
|
|
23313
|
+
if (provider.validateResourceURL) {
|
|
23314
|
+
return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
|
|
23315
|
+
}
|
|
23316
|
+
if (!resourceMetadata) {
|
|
23317
|
+
return void 0;
|
|
23318
|
+
}
|
|
23319
|
+
if (!checkResourceAllowed({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource })) {
|
|
23320
|
+
throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
|
|
23321
|
+
}
|
|
23322
|
+
return new URL(resourceMetadata.resource);
|
|
23323
|
+
}
|
|
23324
|
+
function extractWWWAuthenticateParams(res) {
|
|
23325
|
+
const authenticateHeader = res.headers.get("WWW-Authenticate");
|
|
23326
|
+
if (!authenticateHeader) {
|
|
23327
|
+
return {};
|
|
23328
|
+
}
|
|
23329
|
+
const [type, scheme] = authenticateHeader.split(" ");
|
|
23330
|
+
if (type.toLowerCase() !== "bearer" || !scheme) {
|
|
23331
|
+
return {};
|
|
23332
|
+
}
|
|
23333
|
+
const resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || void 0;
|
|
23334
|
+
let resourceMetadataUrl;
|
|
23335
|
+
if (resourceMetadataMatch) {
|
|
23336
|
+
try {
|
|
23337
|
+
resourceMetadataUrl = new URL(resourceMetadataMatch);
|
|
23338
|
+
} catch {
|
|
23339
|
+
}
|
|
23340
|
+
}
|
|
23341
|
+
const scope = extractFieldFromWwwAuth(res, "scope") || void 0;
|
|
23342
|
+
const error2 = extractFieldFromWwwAuth(res, "error") || void 0;
|
|
23343
|
+
return {
|
|
23344
|
+
resourceMetadataUrl,
|
|
23345
|
+
scope,
|
|
23346
|
+
error: error2
|
|
23347
|
+
};
|
|
23348
|
+
}
|
|
23349
|
+
function extractFieldFromWwwAuth(response, fieldName) {
|
|
23350
|
+
const wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
23351
|
+
if (!wwwAuthHeader) {
|
|
23352
|
+
return null;
|
|
23353
|
+
}
|
|
23354
|
+
const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
|
|
23355
|
+
const match = wwwAuthHeader.match(pattern);
|
|
23356
|
+
if (match) {
|
|
23357
|
+
return match[1] || match[2];
|
|
23358
|
+
}
|
|
23359
|
+
return null;
|
|
23360
|
+
}
|
|
23361
|
+
async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
|
|
23362
|
+
const response = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
|
|
23363
|
+
protocolVersion: opts?.protocolVersion,
|
|
23364
|
+
metadataUrl: opts?.resourceMetadataUrl
|
|
23365
|
+
});
|
|
23366
|
+
if (!response || response.status === 404) {
|
|
23367
|
+
await response?.body?.cancel();
|
|
23368
|
+
throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
|
|
23369
|
+
}
|
|
23370
|
+
if (!response.ok) {
|
|
23371
|
+
await response.body?.cancel();
|
|
23372
|
+
throw new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
|
|
23373
|
+
}
|
|
23374
|
+
return OAuthProtectedResourceMetadataSchema.parse(await response.json());
|
|
23375
|
+
}
|
|
23376
|
+
async function fetchWithCorsRetry(url2, headers, fetchFn = fetch) {
|
|
23377
|
+
try {
|
|
23378
|
+
return await fetchFn(url2, { headers });
|
|
23379
|
+
} catch (error2) {
|
|
23380
|
+
if (error2 instanceof TypeError) {
|
|
23381
|
+
if (headers) {
|
|
23382
|
+
return fetchWithCorsRetry(url2, void 0, fetchFn);
|
|
23383
|
+
} else {
|
|
23384
|
+
return void 0;
|
|
23385
|
+
}
|
|
23386
|
+
}
|
|
23387
|
+
throw error2;
|
|
23388
|
+
}
|
|
23389
|
+
}
|
|
23390
|
+
function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
|
|
23391
|
+
if (pathname.endsWith("/")) {
|
|
23392
|
+
pathname = pathname.slice(0, -1);
|
|
23393
|
+
}
|
|
23394
|
+
return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
|
|
23395
|
+
}
|
|
23396
|
+
async function tryMetadataDiscovery(url2, protocolVersion, fetchFn = fetch) {
|
|
23397
|
+
const headers = {
|
|
23398
|
+
"MCP-Protocol-Version": protocolVersion
|
|
23399
|
+
};
|
|
23400
|
+
return await fetchWithCorsRetry(url2, headers, fetchFn);
|
|
23401
|
+
}
|
|
23402
|
+
function shouldAttemptFallback(response, pathname) {
|
|
23403
|
+
return !response || response.status >= 400 && response.status < 500 && pathname !== "/";
|
|
23404
|
+
}
|
|
23405
|
+
async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
|
|
23406
|
+
const issuer = new URL(serverUrl);
|
|
23407
|
+
const protocolVersion = opts?.protocolVersion ?? LATEST_PROTOCOL_VERSION;
|
|
23408
|
+
let url2;
|
|
23409
|
+
if (opts?.metadataUrl) {
|
|
23410
|
+
url2 = new URL(opts.metadataUrl);
|
|
23411
|
+
} else {
|
|
23412
|
+
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
|
|
23413
|
+
url2 = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
|
|
23414
|
+
url2.search = issuer.search;
|
|
23415
|
+
}
|
|
23416
|
+
let response = await tryMetadataDiscovery(url2, protocolVersion, fetchFn);
|
|
23417
|
+
if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) {
|
|
23418
|
+
const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
|
|
23419
|
+
response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
|
|
23420
|
+
}
|
|
23421
|
+
return response;
|
|
23422
|
+
}
|
|
23423
|
+
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
23424
|
+
const url2 = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
|
23425
|
+
const hasPath = url2.pathname !== "/";
|
|
23426
|
+
const urlsToTry = [];
|
|
23427
|
+
if (!hasPath) {
|
|
23428
|
+
urlsToTry.push({
|
|
23429
|
+
url: new URL("/.well-known/oauth-authorization-server", url2.origin),
|
|
23430
|
+
type: "oauth"
|
|
23431
|
+
});
|
|
23432
|
+
urlsToTry.push({
|
|
23433
|
+
url: new URL(`/.well-known/openid-configuration`, url2.origin),
|
|
23434
|
+
type: "oidc"
|
|
23435
|
+
});
|
|
23436
|
+
return urlsToTry;
|
|
23437
|
+
}
|
|
23438
|
+
let pathname = url2.pathname;
|
|
23439
|
+
if (pathname.endsWith("/")) {
|
|
23440
|
+
pathname = pathname.slice(0, -1);
|
|
23441
|
+
}
|
|
23442
|
+
urlsToTry.push({
|
|
23443
|
+
url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url2.origin),
|
|
23444
|
+
type: "oauth"
|
|
23445
|
+
});
|
|
23446
|
+
urlsToTry.push({
|
|
23447
|
+
url: new URL(`/.well-known/openid-configuration${pathname}`, url2.origin),
|
|
23448
|
+
type: "oidc"
|
|
23449
|
+
});
|
|
23450
|
+
urlsToTry.push({
|
|
23451
|
+
url: new URL(`${pathname}/.well-known/openid-configuration`, url2.origin),
|
|
23452
|
+
type: "oidc"
|
|
23453
|
+
});
|
|
23454
|
+
return urlsToTry;
|
|
23455
|
+
}
|
|
23456
|
+
async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
|
|
23457
|
+
const headers = {
|
|
23458
|
+
"MCP-Protocol-Version": protocolVersion,
|
|
23459
|
+
Accept: "application/json"
|
|
23460
|
+
};
|
|
23461
|
+
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
23462
|
+
for (const { url: endpointUrl, type } of urlsToTry) {
|
|
23463
|
+
const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
|
23464
|
+
if (!response) {
|
|
23465
|
+
continue;
|
|
23466
|
+
}
|
|
23467
|
+
if (!response.ok) {
|
|
23468
|
+
await response.body?.cancel();
|
|
23469
|
+
if (response.status >= 400 && response.status < 500) {
|
|
23470
|
+
continue;
|
|
23471
|
+
}
|
|
23472
|
+
throw new Error(`HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
|
|
23473
|
+
}
|
|
23474
|
+
if (type === "oauth") {
|
|
23475
|
+
return OAuthMetadataSchema.parse(await response.json());
|
|
23476
|
+
} else {
|
|
23477
|
+
return OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
|
|
23478
|
+
}
|
|
23479
|
+
}
|
|
23480
|
+
return void 0;
|
|
23481
|
+
}
|
|
23482
|
+
async function discoverOAuthServerInfo(serverUrl, opts) {
|
|
23483
|
+
let resourceMetadata;
|
|
23484
|
+
let authorizationServerUrl;
|
|
23485
|
+
try {
|
|
23486
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
|
|
23487
|
+
if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
|
|
23488
|
+
authorizationServerUrl = resourceMetadata.authorization_servers[0];
|
|
23489
|
+
}
|
|
23490
|
+
} catch {
|
|
23491
|
+
}
|
|
23492
|
+
if (!authorizationServerUrl) {
|
|
23493
|
+
authorizationServerUrl = String(new URL("/", serverUrl));
|
|
23494
|
+
}
|
|
23495
|
+
const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
|
|
23496
|
+
return {
|
|
23497
|
+
authorizationServerUrl,
|
|
23498
|
+
authorizationServerMetadata,
|
|
23499
|
+
resourceMetadata
|
|
23500
|
+
};
|
|
23501
|
+
}
|
|
23502
|
+
async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
|
|
23503
|
+
let authorizationUrl;
|
|
23504
|
+
if (metadata) {
|
|
23505
|
+
authorizationUrl = new URL(metadata.authorization_endpoint);
|
|
23506
|
+
if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
|
|
23507
|
+
throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
|
|
23508
|
+
}
|
|
23509
|
+
if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
|
|
23510
|
+
throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
|
|
23511
|
+
}
|
|
23512
|
+
} else {
|
|
23513
|
+
authorizationUrl = new URL("/authorize", authorizationServerUrl);
|
|
23514
|
+
}
|
|
23515
|
+
const challenge = await pkceChallenge();
|
|
23516
|
+
const codeVerifier = challenge.code_verifier;
|
|
23517
|
+
const codeChallenge = challenge.code_challenge;
|
|
23518
|
+
authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
|
|
23519
|
+
authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
|
|
23520
|
+
authorizationUrl.searchParams.set("code_challenge", codeChallenge);
|
|
23521
|
+
authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
|
|
23522
|
+
authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
|
|
23523
|
+
if (state) {
|
|
23524
|
+
authorizationUrl.searchParams.set("state", state);
|
|
23525
|
+
}
|
|
23526
|
+
if (scope) {
|
|
23527
|
+
authorizationUrl.searchParams.set("scope", scope);
|
|
23528
|
+
}
|
|
23529
|
+
if (scope?.includes("offline_access")) {
|
|
23530
|
+
authorizationUrl.searchParams.append("prompt", "consent");
|
|
23531
|
+
}
|
|
23532
|
+
if (resource) {
|
|
23533
|
+
authorizationUrl.searchParams.set("resource", resource.href);
|
|
23534
|
+
}
|
|
23535
|
+
return { authorizationUrl, codeVerifier };
|
|
23536
|
+
}
|
|
23537
|
+
function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
|
|
23538
|
+
return new URLSearchParams({
|
|
23539
|
+
grant_type: "authorization_code",
|
|
23540
|
+
code: authorizationCode,
|
|
23541
|
+
code_verifier: codeVerifier,
|
|
23542
|
+
redirect_uri: String(redirectUri)
|
|
23543
|
+
});
|
|
23544
|
+
}
|
|
23545
|
+
async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
|
|
23546
|
+
const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
|
|
23547
|
+
const headers = new Headers({
|
|
23548
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
23549
|
+
Accept: "application/json"
|
|
23550
|
+
});
|
|
23551
|
+
if (resource) {
|
|
23552
|
+
tokenRequestParams.set("resource", resource.href);
|
|
23553
|
+
}
|
|
23554
|
+
if (addClientAuthentication) {
|
|
23555
|
+
await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
|
|
23556
|
+
} else if (clientInformation) {
|
|
23557
|
+
const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];
|
|
23558
|
+
const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
|
|
23559
|
+
applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
|
|
23560
|
+
}
|
|
23561
|
+
const response = await (fetchFn ?? fetch)(tokenUrl, {
|
|
23562
|
+
method: "POST",
|
|
23563
|
+
headers,
|
|
23564
|
+
body: tokenRequestParams
|
|
23565
|
+
});
|
|
23566
|
+
if (!response.ok) {
|
|
23567
|
+
throw await parseErrorResponse(response);
|
|
23568
|
+
}
|
|
23569
|
+
return OAuthTokensSchema.parse(await response.json());
|
|
23570
|
+
}
|
|
23571
|
+
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
|
23572
|
+
const tokenRequestParams = new URLSearchParams({
|
|
23573
|
+
grant_type: "refresh_token",
|
|
23574
|
+
refresh_token: refreshToken
|
|
23575
|
+
});
|
|
23576
|
+
const tokens = await executeTokenRequest(authorizationServerUrl, {
|
|
23577
|
+
metadata,
|
|
23578
|
+
tokenRequestParams,
|
|
23579
|
+
clientInformation,
|
|
23580
|
+
addClientAuthentication,
|
|
23581
|
+
resource,
|
|
23582
|
+
fetchFn
|
|
23583
|
+
});
|
|
23584
|
+
return { refresh_token: refreshToken, ...tokens };
|
|
23585
|
+
}
|
|
23586
|
+
async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
|
|
23587
|
+
const scope = provider.clientMetadata.scope;
|
|
23588
|
+
let tokenRequestParams;
|
|
23589
|
+
if (provider.prepareTokenRequest) {
|
|
23590
|
+
tokenRequestParams = await provider.prepareTokenRequest(scope);
|
|
23591
|
+
}
|
|
23592
|
+
if (!tokenRequestParams) {
|
|
23593
|
+
if (!authorizationCode) {
|
|
23594
|
+
throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
|
|
23595
|
+
}
|
|
23596
|
+
if (!provider.redirectUrl) {
|
|
23597
|
+
throw new Error("redirectUrl is required for authorization_code flow");
|
|
23598
|
+
}
|
|
23599
|
+
const codeVerifier = await provider.codeVerifier();
|
|
23600
|
+
tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
|
|
23601
|
+
}
|
|
23602
|
+
const clientInformation = await provider.clientInformation();
|
|
23603
|
+
return executeTokenRequest(authorizationServerUrl, {
|
|
23604
|
+
metadata,
|
|
23605
|
+
tokenRequestParams,
|
|
23606
|
+
clientInformation: clientInformation ?? void 0,
|
|
23607
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
23608
|
+
resource,
|
|
23609
|
+
fetchFn
|
|
23610
|
+
});
|
|
23611
|
+
}
|
|
23612
|
+
async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
|
|
23613
|
+
let registrationUrl;
|
|
23614
|
+
if (metadata) {
|
|
23615
|
+
if (!metadata.registration_endpoint) {
|
|
23616
|
+
throw new Error("Incompatible auth server: does not support dynamic client registration");
|
|
23617
|
+
}
|
|
23618
|
+
registrationUrl = new URL(metadata.registration_endpoint);
|
|
23619
|
+
} else {
|
|
23620
|
+
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
23621
|
+
}
|
|
23622
|
+
const response = await (fetchFn ?? fetch)(registrationUrl, {
|
|
23623
|
+
method: "POST",
|
|
23624
|
+
headers: {
|
|
23625
|
+
"Content-Type": "application/json"
|
|
23626
|
+
},
|
|
23627
|
+
body: JSON.stringify({
|
|
23628
|
+
...clientMetadata,
|
|
23629
|
+
...scope !== void 0 ? { scope } : {}
|
|
23630
|
+
})
|
|
23631
|
+
});
|
|
23632
|
+
if (!response.ok) {
|
|
23633
|
+
throw await parseErrorResponse(response);
|
|
23634
|
+
}
|
|
23635
|
+
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
23636
|
+
}
|
|
23637
|
+
|
|
23638
|
+
// node_modules/eventsource-parser/dist/index.js
|
|
23639
|
+
var ParseError = class extends Error {
|
|
23640
|
+
constructor(message, options) {
|
|
23641
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
23642
|
+
}
|
|
23643
|
+
};
|
|
23644
|
+
var LF = 10;
|
|
23645
|
+
var CR = 13;
|
|
23646
|
+
var SPACE = 32;
|
|
23647
|
+
function noop(_arg) {
|
|
23648
|
+
}
|
|
23649
|
+
function createParser(config2) {
|
|
23650
|
+
if (typeof config2 == "function")
|
|
23651
|
+
throw new TypeError(
|
|
23652
|
+
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
23653
|
+
);
|
|
23654
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config2, pendingFragments = [];
|
|
23655
|
+
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
|
|
23656
|
+
function feed(chunk) {
|
|
23657
|
+
if (terminated)
|
|
23658
|
+
throw new Error(
|
|
23659
|
+
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
23660
|
+
);
|
|
23661
|
+
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
23662
|
+
const trailing2 = processLines(chunk);
|
|
23663
|
+
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
23664
|
+
return;
|
|
23665
|
+
}
|
|
23666
|
+
if (chunk.indexOf(`
|
|
23667
|
+
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
23668
|
+
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
23669
|
+
return;
|
|
23670
|
+
}
|
|
23671
|
+
pendingFragments.push(chunk);
|
|
23672
|
+
const input = pendingFragments.join("");
|
|
23673
|
+
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
23674
|
+
const trailing = processLines(input);
|
|
23675
|
+
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
23676
|
+
}
|
|
23677
|
+
function checkBufferSize() {
|
|
23678
|
+
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
23679
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
23680
|
+
type: "max-buffer-size-exceeded"
|
|
23681
|
+
})
|
|
23682
|
+
)));
|
|
23683
|
+
}
|
|
23684
|
+
function processLines(chunk) {
|
|
23685
|
+
let searchIndex = 0;
|
|
23686
|
+
if (chunk.indexOf("\r") === -1) {
|
|
23687
|
+
let lfIndex = chunk.indexOf(`
|
|
23688
|
+
`, searchIndex);
|
|
23689
|
+
for (; lfIndex !== -1; ) {
|
|
23690
|
+
if (searchIndex === lfIndex) {
|
|
23691
|
+
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
23692
|
+
`, searchIndex);
|
|
23693
|
+
continue;
|
|
23694
|
+
}
|
|
23695
|
+
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
23696
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
23697
|
+
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
23698
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
23699
|
+
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
23700
|
+
`, searchIndex);
|
|
23701
|
+
continue;
|
|
23702
|
+
}
|
|
23703
|
+
data = dataLines === 0 ? value : `${data}
|
|
23704
|
+
${value}`, dataLines++;
|
|
23705
|
+
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
23706
|
+
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
23707
|
+
lfIndex
|
|
23708
|
+
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
23709
|
+
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
23710
|
+
`, searchIndex);
|
|
23711
|
+
}
|
|
23712
|
+
return chunk.slice(searchIndex);
|
|
23713
|
+
}
|
|
23714
|
+
for (; searchIndex < chunk.length; ) {
|
|
23715
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
23716
|
+
`, searchIndex);
|
|
23717
|
+
let lineEnd = -1;
|
|
23718
|
+
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)
|
|
23719
|
+
break;
|
|
23720
|
+
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
23721
|
+
}
|
|
23722
|
+
return chunk.slice(searchIndex);
|
|
23723
|
+
}
|
|
23724
|
+
function parseLine(chunk, start, end) {
|
|
23725
|
+
if (start === end) {
|
|
23726
|
+
dispatchEvent();
|
|
23727
|
+
return;
|
|
23728
|
+
}
|
|
23729
|
+
const firstCharCode = chunk.charCodeAt(start);
|
|
23730
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
23731
|
+
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
23732
|
+
data = dataLines === 0 ? value2 : `${data}
|
|
23733
|
+
${value2}`, dataLines++;
|
|
23734
|
+
return;
|
|
23735
|
+
}
|
|
23736
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
23737
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
23738
|
+
return;
|
|
23739
|
+
}
|
|
23740
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
23741
|
+
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
23742
|
+
id = value2.includes("\0") ? void 0 : value2;
|
|
23743
|
+
return;
|
|
23744
|
+
}
|
|
23745
|
+
if (firstCharCode === 58) {
|
|
23746
|
+
if (onComment) {
|
|
23747
|
+
const line2 = chunk.slice(start, end);
|
|
23748
|
+
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
23749
|
+
}
|
|
23750
|
+
return;
|
|
23751
|
+
}
|
|
23752
|
+
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
23753
|
+
if (fieldSeparatorIndex === -1) {
|
|
23754
|
+
processField(line, "", line);
|
|
23755
|
+
return;
|
|
23756
|
+
}
|
|
23757
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
23758
|
+
processField(field, value, line);
|
|
23759
|
+
}
|
|
23760
|
+
function processField(field, value, line) {
|
|
23761
|
+
switch (field) {
|
|
23762
|
+
case "event":
|
|
23763
|
+
eventType = value || void 0;
|
|
23764
|
+
break;
|
|
23765
|
+
case "data":
|
|
23766
|
+
data = dataLines === 0 ? value : `${data}
|
|
23767
|
+
${value}`, dataLines++;
|
|
23768
|
+
break;
|
|
23769
|
+
case "id":
|
|
23770
|
+
id = value.includes("\0") ? void 0 : value;
|
|
23771
|
+
break;
|
|
23772
|
+
case "retry":
|
|
23773
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
23774
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
23775
|
+
type: "invalid-retry",
|
|
23776
|
+
value,
|
|
23777
|
+
line
|
|
23778
|
+
})
|
|
23779
|
+
);
|
|
23780
|
+
break;
|
|
23781
|
+
default:
|
|
23782
|
+
onError(
|
|
23783
|
+
new ParseError(
|
|
23784
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
23785
|
+
{ type: "unknown-field", field, value, line }
|
|
23786
|
+
)
|
|
23787
|
+
);
|
|
23788
|
+
break;
|
|
23789
|
+
}
|
|
23790
|
+
}
|
|
23791
|
+
function dispatchEvent() {
|
|
23792
|
+
dataLines > 0 && onEvent({
|
|
23793
|
+
id,
|
|
23794
|
+
event: eventType,
|
|
23795
|
+
data
|
|
23796
|
+
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
23797
|
+
}
|
|
23798
|
+
function reset(options = {}) {
|
|
23799
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
23800
|
+
const incompleteLine = pendingFragments.join("");
|
|
23801
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
23802
|
+
}
|
|
23803
|
+
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
|
|
23804
|
+
}
|
|
23805
|
+
return { feed, reset };
|
|
23806
|
+
}
|
|
23807
|
+
function isDataPrefix(chunk, i, firstCharCode) {
|
|
23808
|
+
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
23809
|
+
}
|
|
23810
|
+
function isEventPrefix(chunk, i, firstCharCode) {
|
|
23811
|
+
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;
|
|
23812
|
+
}
|
|
23813
|
+
|
|
23814
|
+
// node_modules/eventsource-parser/dist/stream.js
|
|
23815
|
+
var EventSourceParserStream = class extends TransformStream {
|
|
23816
|
+
constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
|
|
23817
|
+
let parser;
|
|
23818
|
+
super({
|
|
23819
|
+
start(controller) {
|
|
23820
|
+
parser = createParser({
|
|
23821
|
+
onEvent: (event) => {
|
|
23822
|
+
controller.enqueue(event);
|
|
23823
|
+
},
|
|
23824
|
+
onError(error2) {
|
|
23825
|
+
typeof onError == "function" && onError(error2), (onError === "terminate" || error2.type === "max-buffer-size-exceeded") && controller.error(error2);
|
|
23826
|
+
},
|
|
23827
|
+
onRetry,
|
|
23828
|
+
onComment,
|
|
23829
|
+
maxBufferSize
|
|
23830
|
+
});
|
|
23831
|
+
},
|
|
23832
|
+
transform(chunk) {
|
|
23833
|
+
parser.feed(chunk);
|
|
23834
|
+
}
|
|
23835
|
+
});
|
|
23836
|
+
}
|
|
23837
|
+
};
|
|
23838
|
+
|
|
23839
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
|
|
23840
|
+
var DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
|
|
23841
|
+
initialReconnectionDelay: 1e3,
|
|
23842
|
+
maxReconnectionDelay: 3e4,
|
|
23843
|
+
reconnectionDelayGrowFactor: 1.5,
|
|
23844
|
+
maxRetries: 2
|
|
23845
|
+
};
|
|
23846
|
+
var StreamableHTTPError = class extends Error {
|
|
23847
|
+
constructor(code, message) {
|
|
23848
|
+
super(`Streamable HTTP error: ${message}`);
|
|
23849
|
+
this.code = code;
|
|
23850
|
+
}
|
|
23851
|
+
};
|
|
23852
|
+
var StreamableHTTPClientTransport = class {
|
|
23853
|
+
constructor(url2, opts) {
|
|
23854
|
+
this._hasCompletedAuthFlow = false;
|
|
23855
|
+
this._url = url2;
|
|
23856
|
+
this._resourceMetadataUrl = void 0;
|
|
23857
|
+
this._scope = void 0;
|
|
23858
|
+
this._requestInit = opts?.requestInit;
|
|
23859
|
+
this._authProvider = opts?.authProvider;
|
|
23860
|
+
this._fetch = opts?.fetch;
|
|
23861
|
+
this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
|
|
23862
|
+
this._sessionId = opts?.sessionId;
|
|
23863
|
+
this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
|
|
23864
|
+
}
|
|
23865
|
+
async _authThenStart() {
|
|
23866
|
+
if (!this._authProvider) {
|
|
23867
|
+
throw new UnauthorizedError("No auth provider");
|
|
23868
|
+
}
|
|
23869
|
+
let result;
|
|
23870
|
+
try {
|
|
23871
|
+
result = await auth(this._authProvider, {
|
|
23872
|
+
serverUrl: this._url,
|
|
23873
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
23874
|
+
scope: this._scope,
|
|
23875
|
+
fetchFn: this._fetchWithInit
|
|
23876
|
+
});
|
|
23877
|
+
} catch (error2) {
|
|
23878
|
+
this.onerror?.(error2);
|
|
23879
|
+
throw error2;
|
|
23880
|
+
}
|
|
23881
|
+
if (result !== "AUTHORIZED") {
|
|
23882
|
+
throw new UnauthorizedError();
|
|
23883
|
+
}
|
|
23884
|
+
return await this._startOrAuthSse({ resumptionToken: void 0 });
|
|
23885
|
+
}
|
|
23886
|
+
async _commonHeaders() {
|
|
23887
|
+
const headers = {};
|
|
23888
|
+
if (this._authProvider) {
|
|
23889
|
+
const tokens = await this._authProvider.tokens();
|
|
23890
|
+
if (tokens) {
|
|
23891
|
+
headers["Authorization"] = `Bearer ${tokens.access_token}`;
|
|
23892
|
+
}
|
|
23893
|
+
}
|
|
23894
|
+
if (this._sessionId) {
|
|
23895
|
+
headers["mcp-session-id"] = this._sessionId;
|
|
23896
|
+
}
|
|
23897
|
+
if (this._protocolVersion) {
|
|
23898
|
+
headers["mcp-protocol-version"] = this._protocolVersion;
|
|
23899
|
+
}
|
|
23900
|
+
const extraHeaders = normalizeHeaders(this._requestInit?.headers);
|
|
23901
|
+
return new Headers({
|
|
23902
|
+
...headers,
|
|
23903
|
+
...extraHeaders
|
|
23904
|
+
});
|
|
23905
|
+
}
|
|
23906
|
+
async _startOrAuthSse(options) {
|
|
23907
|
+
const { resumptionToken } = options;
|
|
23908
|
+
try {
|
|
23909
|
+
const headers = await this._commonHeaders();
|
|
23910
|
+
headers.set("Accept", "text/event-stream");
|
|
23911
|
+
if (resumptionToken) {
|
|
23912
|
+
headers.set("last-event-id", resumptionToken);
|
|
23913
|
+
}
|
|
23914
|
+
const response = await (this._fetch ?? fetch)(this._url, {
|
|
23915
|
+
method: "GET",
|
|
23916
|
+
headers,
|
|
23917
|
+
signal: this._abortController?.signal
|
|
23918
|
+
});
|
|
23919
|
+
if (!response.ok) {
|
|
23920
|
+
await response.body?.cancel();
|
|
23921
|
+
if (response.status === 401 && this._authProvider) {
|
|
23922
|
+
return await this._authThenStart();
|
|
23923
|
+
}
|
|
23924
|
+
if (response.status === 405) {
|
|
23925
|
+
return;
|
|
23926
|
+
}
|
|
23927
|
+
throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
|
|
23928
|
+
}
|
|
23929
|
+
this._handleSseStream(response.body, options, true);
|
|
23930
|
+
} catch (error2) {
|
|
23931
|
+
this.onerror?.(error2);
|
|
23932
|
+
throw error2;
|
|
23933
|
+
}
|
|
23934
|
+
}
|
|
23935
|
+
/**
|
|
23936
|
+
* Calculates the next reconnection delay using backoff algorithm
|
|
23937
|
+
*
|
|
23938
|
+
* @param attempt Current reconnection attempt count for the specific stream
|
|
23939
|
+
* @returns Time to wait in milliseconds before next reconnection attempt
|
|
23940
|
+
*/
|
|
23941
|
+
_getNextReconnectionDelay(attempt) {
|
|
23942
|
+
if (this._serverRetryMs !== void 0) {
|
|
23943
|
+
return this._serverRetryMs;
|
|
23944
|
+
}
|
|
23945
|
+
const initialDelay = this._reconnectionOptions.initialReconnectionDelay;
|
|
23946
|
+
const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;
|
|
23947
|
+
const maxDelay = this._reconnectionOptions.maxReconnectionDelay;
|
|
23948
|
+
return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
|
|
23949
|
+
}
|
|
23950
|
+
/**
|
|
23951
|
+
* Schedule a reconnection attempt using server-provided retry interval or backoff
|
|
23952
|
+
*
|
|
23953
|
+
* @param lastEventId The ID of the last received event for resumability
|
|
23954
|
+
* @param attemptCount Current reconnection attempt count for this specific stream
|
|
23955
|
+
*/
|
|
23956
|
+
_scheduleReconnection(options, attemptCount = 0) {
|
|
23957
|
+
const maxRetries = this._reconnectionOptions.maxRetries;
|
|
23958
|
+
if (attemptCount >= maxRetries) {
|
|
23959
|
+
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
23960
|
+
return;
|
|
23961
|
+
}
|
|
23962
|
+
const delay = this._getNextReconnectionDelay(attemptCount);
|
|
23963
|
+
this._reconnectionTimeout = setTimeout(() => {
|
|
23964
|
+
this._startOrAuthSse(options).catch((error2) => {
|
|
23965
|
+
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
23966
|
+
this._scheduleReconnection(options, attemptCount + 1);
|
|
23967
|
+
});
|
|
23968
|
+
}, delay);
|
|
23969
|
+
}
|
|
23970
|
+
_handleSseStream(stream, options, isReconnectable) {
|
|
23971
|
+
if (!stream) {
|
|
23972
|
+
return;
|
|
23973
|
+
}
|
|
23974
|
+
const { onresumptiontoken, replayMessageId } = options;
|
|
23975
|
+
let lastEventId;
|
|
23976
|
+
let hasPrimingEvent = false;
|
|
23977
|
+
let receivedResponse = false;
|
|
23978
|
+
const processStream = async () => {
|
|
23979
|
+
try {
|
|
23980
|
+
const reader = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({
|
|
23981
|
+
onRetry: (retryMs) => {
|
|
23982
|
+
this._serverRetryMs = retryMs;
|
|
23983
|
+
}
|
|
23984
|
+
})).getReader();
|
|
23985
|
+
while (true) {
|
|
23986
|
+
const { value: event, done } = await reader.read();
|
|
23987
|
+
if (done) {
|
|
23988
|
+
break;
|
|
23989
|
+
}
|
|
23990
|
+
if (event.id) {
|
|
23991
|
+
lastEventId = event.id;
|
|
23992
|
+
hasPrimingEvent = true;
|
|
23993
|
+
onresumptiontoken?.(event.id);
|
|
23994
|
+
}
|
|
23995
|
+
if (!event.data) {
|
|
23996
|
+
continue;
|
|
23997
|
+
}
|
|
23998
|
+
if (!event.event || event.event === "message") {
|
|
23999
|
+
try {
|
|
24000
|
+
const message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
|
24001
|
+
if (isJSONRPCResultResponse(message)) {
|
|
24002
|
+
receivedResponse = true;
|
|
24003
|
+
if (replayMessageId !== void 0) {
|
|
24004
|
+
message.id = replayMessageId;
|
|
24005
|
+
}
|
|
24006
|
+
}
|
|
24007
|
+
this.onmessage?.(message);
|
|
24008
|
+
} catch (error2) {
|
|
24009
|
+
this.onerror?.(error2);
|
|
24010
|
+
}
|
|
24011
|
+
}
|
|
24012
|
+
}
|
|
24013
|
+
const canResume = isReconnectable || hasPrimingEvent;
|
|
24014
|
+
const needsReconnect = canResume && !receivedResponse;
|
|
24015
|
+
if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
|
|
24016
|
+
this._scheduleReconnection({
|
|
24017
|
+
resumptionToken: lastEventId,
|
|
24018
|
+
onresumptiontoken,
|
|
24019
|
+
replayMessageId
|
|
24020
|
+
}, 0);
|
|
24021
|
+
}
|
|
24022
|
+
} catch (error2) {
|
|
24023
|
+
this.onerror?.(new Error(`SSE stream disconnected: ${error2}`));
|
|
24024
|
+
const canResume = isReconnectable || hasPrimingEvent;
|
|
24025
|
+
const needsReconnect = canResume && !receivedResponse;
|
|
24026
|
+
if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
|
|
24027
|
+
try {
|
|
24028
|
+
this._scheduleReconnection({
|
|
24029
|
+
resumptionToken: lastEventId,
|
|
24030
|
+
onresumptiontoken,
|
|
24031
|
+
replayMessageId
|
|
24032
|
+
}, 0);
|
|
24033
|
+
} catch (error3) {
|
|
24034
|
+
this.onerror?.(new Error(`Failed to reconnect: ${error3 instanceof Error ? error3.message : String(error3)}`));
|
|
24035
|
+
}
|
|
24036
|
+
}
|
|
24037
|
+
}
|
|
24038
|
+
};
|
|
24039
|
+
processStream();
|
|
24040
|
+
}
|
|
24041
|
+
async start() {
|
|
24042
|
+
if (this._abortController) {
|
|
24043
|
+
throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
24044
|
+
}
|
|
24045
|
+
this._abortController = new AbortController();
|
|
24046
|
+
}
|
|
24047
|
+
/**
|
|
24048
|
+
* 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.
|
|
24049
|
+
*/
|
|
24050
|
+
async finishAuth(authorizationCode) {
|
|
24051
|
+
if (!this._authProvider) {
|
|
24052
|
+
throw new UnauthorizedError("No auth provider");
|
|
24053
|
+
}
|
|
24054
|
+
const result = await auth(this._authProvider, {
|
|
24055
|
+
serverUrl: this._url,
|
|
24056
|
+
authorizationCode,
|
|
24057
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
24058
|
+
scope: this._scope,
|
|
24059
|
+
fetchFn: this._fetchWithInit
|
|
24060
|
+
});
|
|
24061
|
+
if (result !== "AUTHORIZED") {
|
|
24062
|
+
throw new UnauthorizedError("Failed to authorize");
|
|
24063
|
+
}
|
|
24064
|
+
}
|
|
24065
|
+
async close() {
|
|
24066
|
+
if (this._reconnectionTimeout) {
|
|
24067
|
+
clearTimeout(this._reconnectionTimeout);
|
|
24068
|
+
this._reconnectionTimeout = void 0;
|
|
24069
|
+
}
|
|
24070
|
+
this._abortController?.abort();
|
|
24071
|
+
this.onclose?.();
|
|
24072
|
+
}
|
|
24073
|
+
async send(message, options) {
|
|
24074
|
+
try {
|
|
24075
|
+
const { resumptionToken, onresumptiontoken } = options || {};
|
|
24076
|
+
if (resumptionToken) {
|
|
24077
|
+
this._startOrAuthSse({ resumptionToken, replayMessageId: isJSONRPCRequest(message) ? message.id : void 0 }).catch((err) => this.onerror?.(err));
|
|
24078
|
+
return;
|
|
24079
|
+
}
|
|
24080
|
+
const headers = await this._commonHeaders();
|
|
24081
|
+
headers.set("content-type", "application/json");
|
|
24082
|
+
headers.set("accept", "application/json, text/event-stream");
|
|
24083
|
+
const init = {
|
|
24084
|
+
...this._requestInit,
|
|
24085
|
+
method: "POST",
|
|
24086
|
+
headers,
|
|
24087
|
+
body: JSON.stringify(message),
|
|
24088
|
+
signal: this._abortController?.signal
|
|
24089
|
+
};
|
|
24090
|
+
const response = await (this._fetch ?? fetch)(this._url, init);
|
|
24091
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
24092
|
+
if (sessionId) {
|
|
24093
|
+
this._sessionId = sessionId;
|
|
24094
|
+
}
|
|
24095
|
+
if (!response.ok) {
|
|
24096
|
+
const text = await response.text().catch(() => null);
|
|
24097
|
+
if (response.status === 401 && this._authProvider) {
|
|
24098
|
+
if (this._hasCompletedAuthFlow) {
|
|
24099
|
+
throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
|
|
24100
|
+
}
|
|
24101
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
24102
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
24103
|
+
this._scope = scope;
|
|
24104
|
+
const result = await auth(this._authProvider, {
|
|
24105
|
+
serverUrl: this._url,
|
|
24106
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
24107
|
+
scope: this._scope,
|
|
24108
|
+
fetchFn: this._fetchWithInit
|
|
24109
|
+
});
|
|
24110
|
+
if (result !== "AUTHORIZED") {
|
|
24111
|
+
throw new UnauthorizedError();
|
|
24112
|
+
}
|
|
24113
|
+
this._hasCompletedAuthFlow = true;
|
|
24114
|
+
return this.send(message);
|
|
24115
|
+
}
|
|
24116
|
+
if (response.status === 403 && this._authProvider) {
|
|
24117
|
+
const { resourceMetadataUrl, scope, error: error2 } = extractWWWAuthenticateParams(response);
|
|
24118
|
+
if (error2 === "insufficient_scope") {
|
|
24119
|
+
const wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
24120
|
+
if (this._lastUpscopingHeader === wwwAuthHeader) {
|
|
24121
|
+
throw new StreamableHTTPError(403, "Server returned 403 after trying upscoping");
|
|
24122
|
+
}
|
|
24123
|
+
if (scope) {
|
|
24124
|
+
this._scope = scope;
|
|
24125
|
+
}
|
|
24126
|
+
if (resourceMetadataUrl) {
|
|
24127
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
24128
|
+
}
|
|
24129
|
+
this._lastUpscopingHeader = wwwAuthHeader ?? void 0;
|
|
24130
|
+
const result = await auth(this._authProvider, {
|
|
24131
|
+
serverUrl: this._url,
|
|
24132
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
24133
|
+
scope: this._scope,
|
|
24134
|
+
fetchFn: this._fetch
|
|
24135
|
+
});
|
|
24136
|
+
if (result !== "AUTHORIZED") {
|
|
24137
|
+
throw new UnauthorizedError();
|
|
24138
|
+
}
|
|
24139
|
+
return this.send(message);
|
|
24140
|
+
}
|
|
24141
|
+
}
|
|
24142
|
+
throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${text}`);
|
|
24143
|
+
}
|
|
24144
|
+
this._hasCompletedAuthFlow = false;
|
|
24145
|
+
this._lastUpscopingHeader = void 0;
|
|
24146
|
+
if (response.status === 202) {
|
|
24147
|
+
await response.body?.cancel();
|
|
24148
|
+
if (isInitializedNotification(message)) {
|
|
24149
|
+
this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => this.onerror?.(err));
|
|
24150
|
+
}
|
|
24151
|
+
return;
|
|
24152
|
+
}
|
|
24153
|
+
const messages = Array.isArray(message) ? message : [message];
|
|
24154
|
+
const hasRequests = messages.filter((msg) => "method" in msg && "id" in msg && msg.id !== void 0).length > 0;
|
|
24155
|
+
const contentType = response.headers.get("content-type");
|
|
24156
|
+
if (hasRequests) {
|
|
24157
|
+
if (contentType?.includes("text/event-stream")) {
|
|
24158
|
+
this._handleSseStream(response.body, { onresumptiontoken }, false);
|
|
24159
|
+
} else if (contentType?.includes("application/json")) {
|
|
24160
|
+
const data = await response.json();
|
|
24161
|
+
const responseMessages = Array.isArray(data) ? data.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(data)];
|
|
24162
|
+
for (const msg of responseMessages) {
|
|
24163
|
+
this.onmessage?.(msg);
|
|
24164
|
+
}
|
|
24165
|
+
} else {
|
|
24166
|
+
await response.body?.cancel();
|
|
24167
|
+
throw new StreamableHTTPError(-1, `Unexpected content type: ${contentType}`);
|
|
24168
|
+
}
|
|
24169
|
+
} else {
|
|
24170
|
+
await response.body?.cancel();
|
|
24171
|
+
}
|
|
24172
|
+
} catch (error2) {
|
|
24173
|
+
this.onerror?.(error2);
|
|
24174
|
+
throw error2;
|
|
24175
|
+
}
|
|
24176
|
+
}
|
|
24177
|
+
get sessionId() {
|
|
24178
|
+
return this._sessionId;
|
|
24179
|
+
}
|
|
24180
|
+
/**
|
|
24181
|
+
* Terminates the current session by sending a DELETE request to the server.
|
|
24182
|
+
*
|
|
24183
|
+
* Clients that no longer need a particular session
|
|
24184
|
+
* (e.g., because the user is leaving the client application) SHOULD send an
|
|
24185
|
+
* HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
|
|
24186
|
+
* terminate the session.
|
|
24187
|
+
*
|
|
24188
|
+
* The server MAY respond with HTTP 405 Method Not Allowed, indicating that
|
|
24189
|
+
* the server does not allow clients to terminate sessions.
|
|
24190
|
+
*/
|
|
24191
|
+
async terminateSession() {
|
|
24192
|
+
if (!this._sessionId) {
|
|
24193
|
+
return;
|
|
24194
|
+
}
|
|
24195
|
+
try {
|
|
24196
|
+
const headers = await this._commonHeaders();
|
|
24197
|
+
const init = {
|
|
24198
|
+
...this._requestInit,
|
|
24199
|
+
method: "DELETE",
|
|
24200
|
+
headers,
|
|
24201
|
+
signal: this._abortController?.signal
|
|
24202
|
+
};
|
|
24203
|
+
const response = await (this._fetch ?? fetch)(this._url, init);
|
|
24204
|
+
await response.body?.cancel();
|
|
24205
|
+
if (!response.ok && response.status !== 405) {
|
|
24206
|
+
throw new StreamableHTTPError(response.status, `Failed to terminate session: ${response.statusText}`);
|
|
24207
|
+
}
|
|
24208
|
+
this._sessionId = void 0;
|
|
24209
|
+
} catch (error2) {
|
|
24210
|
+
this.onerror?.(error2);
|
|
24211
|
+
throw error2;
|
|
24212
|
+
}
|
|
24213
|
+
}
|
|
24214
|
+
setProtocolVersion(version2) {
|
|
24215
|
+
this._protocolVersion = version2;
|
|
24216
|
+
}
|
|
24217
|
+
get protocolVersion() {
|
|
24218
|
+
return this._protocolVersion;
|
|
24219
|
+
}
|
|
24220
|
+
/**
|
|
24221
|
+
* Resume an SSE stream from a previous event ID.
|
|
24222
|
+
* Opens a GET SSE connection with Last-Event-ID header to replay missed events.
|
|
24223
|
+
*
|
|
24224
|
+
* @param lastEventId The event ID to resume from
|
|
24225
|
+
* @param options Optional callback to receive new resumption tokens
|
|
24226
|
+
*/
|
|
24227
|
+
async resumeStream(lastEventId, options) {
|
|
24228
|
+
await this._startOrAuthSse({
|
|
24229
|
+
resumptionToken: lastEventId,
|
|
24230
|
+
onresumptiontoken: options?.onresumptiontoken
|
|
24231
|
+
});
|
|
24232
|
+
}
|
|
24233
|
+
};
|
|
24234
|
+
|
|
24235
|
+
// src/services.ts
|
|
24236
|
+
import dns from "dns/promises";
|
|
24237
|
+
import fs2 from "fs";
|
|
24238
|
+
import net from "net";
|
|
24239
|
+
import os from "os";
|
|
24240
|
+
import path2 from "path";
|
|
24241
|
+
import { Readable } from "stream";
|
|
24242
|
+
import { pipeline } from "stream/promises";
|
|
24243
|
+
var SERVICES_FILE = path2.resolve(
|
|
24244
|
+
process.env.GOATEDIT_SERVICES_FILE || path2.join(os.homedir(), ".goatedit", "services.json")
|
|
24245
|
+
);
|
|
24246
|
+
var MAX_DOWNLOAD_BYTES = 4 * 1024 ** 3;
|
|
24247
|
+
var CALL_TIMEOUT_MS = 12e4;
|
|
24248
|
+
function readConfig() {
|
|
24249
|
+
let raw;
|
|
24250
|
+
try {
|
|
24251
|
+
raw = fs2.readFileSync(SERVICES_FILE, "utf8");
|
|
24252
|
+
} catch {
|
|
24253
|
+
return {};
|
|
24254
|
+
}
|
|
24255
|
+
const parsed = JSON.parse(raw);
|
|
24256
|
+
const servers = parsed && typeof parsed === "object" ? parsed.servers : null;
|
|
24257
|
+
return servers && typeof servers === "object" ? servers : {};
|
|
24258
|
+
}
|
|
24259
|
+
var clients = /* @__PURE__ */ new Map();
|
|
24260
|
+
async function connect(name, config2) {
|
|
24261
|
+
const client = new Client({ name: "goatedit-studio", version: "1.0.0" });
|
|
24262
|
+
if ("url" in config2) {
|
|
24263
|
+
await client.connect(new StreamableHTTPClientTransport(new URL(config2.url), { requestInit: { headers: config2.headers ?? {} } }));
|
|
24264
|
+
} else {
|
|
24265
|
+
const env = {};
|
|
24266
|
+
for (const [k, v] of Object.entries(process.env)) if (typeof v === "string") env[k] = v;
|
|
24267
|
+
await client.connect(new StdioClientTransport({
|
|
24268
|
+
command: config2.command,
|
|
24269
|
+
args: config2.args ?? [],
|
|
24270
|
+
env: { ...env, ...config2.env ?? {} },
|
|
24271
|
+
...config2.cwd ? { cwd: config2.cwd } : {},
|
|
24272
|
+
stderr: "ignore"
|
|
24273
|
+
}));
|
|
24274
|
+
}
|
|
24275
|
+
client.onclose = () => {
|
|
24276
|
+
clients.delete(name);
|
|
24277
|
+
};
|
|
24278
|
+
return client;
|
|
24279
|
+
}
|
|
24280
|
+
function clientFor(name) {
|
|
24281
|
+
const config2 = readConfig()[name];
|
|
24282
|
+
if (!config2) throw new Error(`No service "${name}" in ${SERVICES_FILE}.`);
|
|
24283
|
+
let pending = clients.get(name);
|
|
24284
|
+
if (!pending) {
|
|
24285
|
+
pending = connect(name, config2);
|
|
24286
|
+
clients.set(name, pending);
|
|
24287
|
+
pending.catch(() => clients.delete(name));
|
|
24288
|
+
}
|
|
24289
|
+
return pending;
|
|
24290
|
+
}
|
|
24291
|
+
async function listServices() {
|
|
24292
|
+
const names = Object.keys(readConfig());
|
|
24293
|
+
return Promise.all(names.map(async (server2) => {
|
|
24294
|
+
try {
|
|
24295
|
+
const { tools } = await (await clientFor(server2)).listTools();
|
|
24296
|
+
return { server: server2, tools: tools.map((t) => ({ name: t.name, ...t.description ? { description: t.description } : {} })) };
|
|
24297
|
+
} catch (err) {
|
|
24298
|
+
return { server: server2, error: err instanceof Error ? err.message : String(err) };
|
|
24299
|
+
}
|
|
24300
|
+
}));
|
|
24301
|
+
}
|
|
24302
|
+
async function callService(server2, tool, args = {}) {
|
|
24303
|
+
const client = await clientFor(server2);
|
|
24304
|
+
const result = await client.callTool({ name: tool, arguments: args }, void 0, { timeout: CALL_TIMEOUT_MS });
|
|
24305
|
+
return result;
|
|
24306
|
+
}
|
|
24307
|
+
function isPrivateAddress(ip) {
|
|
24308
|
+
if (net.isIPv4(ip)) {
|
|
24309
|
+
const [a, b] = ip.split(".").map(Number);
|
|
24310
|
+
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;
|
|
24311
|
+
}
|
|
24312
|
+
const v6 = ip.toLowerCase();
|
|
24313
|
+
if (v6.startsWith("::ffff:")) return isPrivateAddress(v6.slice(7));
|
|
24314
|
+
return v6 === "::1" || v6 === "::" || v6.startsWith("fc") || v6.startsWith("fd") || v6.startsWith("fe80");
|
|
24315
|
+
}
|
|
24316
|
+
async function checkUrl(raw) {
|
|
24317
|
+
let url2;
|
|
24318
|
+
try {
|
|
24319
|
+
url2 = new URL(raw);
|
|
24320
|
+
} catch {
|
|
24321
|
+
throw new Error("Not a URL.");
|
|
24322
|
+
}
|
|
24323
|
+
if (url2.protocol !== "https:") throw new Error("Only https links are downloaded.");
|
|
24324
|
+
const addresses = await dns.lookup(url2.hostname, { all: true });
|
|
24325
|
+
if (!addresses.length || addresses.some((a) => isPrivateAddress(a.address))) throw new Error(`${url2.hostname} is not a public address.`);
|
|
24326
|
+
return url2;
|
|
24327
|
+
}
|
|
24328
|
+
var safeName = (s) => s.replace(/[^\w.-]+/g, "_").replace(/^[._]+/, "").slice(0, 80) || "file";
|
|
24329
|
+
async function downloadToAssets(assetsDir, rawUrl, name) {
|
|
24330
|
+
let url2 = await checkUrl(rawUrl);
|
|
24331
|
+
let res = null;
|
|
24332
|
+
for (let hop = 0; hop < 5; hop++) {
|
|
24333
|
+
res = await fetch(url2, { redirect: "manual" });
|
|
24334
|
+
const next = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
24335
|
+
if (!next) break;
|
|
24336
|
+
url2 = await checkUrl(new URL(next, url2).toString());
|
|
24337
|
+
res = null;
|
|
24338
|
+
}
|
|
24339
|
+
if (!res) throw new Error("Too many redirects.");
|
|
24340
|
+
if (!res.ok || !res.body) throw new Error(`The download failed: HTTP ${res.status}.`);
|
|
24341
|
+
const declared = Number(res.headers.get("content-length") || 0);
|
|
24342
|
+
if (declared > MAX_DOWNLOAD_BYTES) throw new Error("The file is too big.");
|
|
24343
|
+
const fromUrl = path2.basename(url2.pathname);
|
|
24344
|
+
const file = safeName(name || fromUrl);
|
|
24345
|
+
const ext = path2.extname(file) ? "" : path2.extname(fromUrl);
|
|
24346
|
+
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
24347
|
+
const rel = path2.join("GoatEdit Downloads", day, `${Date.now().toString(36)}-${file}${ext}`);
|
|
24348
|
+
const dest = path2.join(assetsDir, rel);
|
|
24349
|
+
fs2.mkdirSync(path2.dirname(dest), { recursive: true });
|
|
24350
|
+
const partial2 = `${dest}.part`;
|
|
24351
|
+
let bytes = 0;
|
|
24352
|
+
const counted = Readable.fromWeb(res.body);
|
|
24353
|
+
counted.on("data", (chunk) => {
|
|
24354
|
+
bytes += chunk.length;
|
|
24355
|
+
if (bytes > MAX_DOWNLOAD_BYTES) counted.destroy(new Error("The file is too big."));
|
|
24356
|
+
});
|
|
24357
|
+
try {
|
|
24358
|
+
await pipeline(counted, fs2.createWriteStream(partial2));
|
|
24359
|
+
fs2.renameSync(partial2, dest);
|
|
24360
|
+
} catch (err) {
|
|
24361
|
+
fs2.rmSync(partial2, { force: true });
|
|
24362
|
+
throw err;
|
|
24363
|
+
}
|
|
24364
|
+
return { rel, path: dest, bytes, contentType: res.headers.get("content-type") || "" };
|
|
24365
|
+
}
|
|
24366
|
+
|
|
24367
|
+
// src/index.ts
|
|
24368
|
+
var WEBSOCKET_PORT = 9e3;
|
|
24369
|
+
var BIND_HOST = "127.0.0.1";
|
|
24370
|
+
var ALLOWED_ORIGINS = /* @__PURE__ */ new Set([
|
|
24371
|
+
"https://ai.goatedit.com",
|
|
24372
|
+
...(process.env.GOATEDIT_ALLOWED_ORIGINS || "").split(",").map((s) => s.trim()).filter(Boolean)
|
|
24373
|
+
]);
|
|
24374
|
+
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
24375
|
+
function isAllowedOrigin(origin) {
|
|
24376
|
+
if (!origin) return false;
|
|
24377
|
+
if (ALLOWED_ORIGINS.has(origin)) return true;
|
|
24378
|
+
try {
|
|
24379
|
+
const u = new URL(origin);
|
|
24380
|
+
return (u.protocol === "http:" || u.protocol === "https:") && LOOPBACK_HOSTNAMES.has(u.hostname);
|
|
24381
|
+
} catch {
|
|
24382
|
+
return false;
|
|
24383
|
+
}
|
|
24384
|
+
}
|
|
24385
|
+
function isLoopbackHost(host) {
|
|
24386
|
+
if (!host) return false;
|
|
24387
|
+
try {
|
|
24388
|
+
return LOOPBACK_HOSTNAMES.has(new URL(`http://${host}`).hostname);
|
|
24389
|
+
} catch {
|
|
24390
|
+
return false;
|
|
24391
|
+
}
|
|
24392
|
+
}
|
|
24393
|
+
var CONTROLLER_TOKEN = process.env.GOATEDIT_CONTROLLER_TOKEN || crypto2.randomBytes(32).toString("hex");
|
|
24394
|
+
var CONTROLLER_TOKEN_FILE = path3.join(os2.homedir(), ".goatedit", "mcp-controller-token");
|
|
24395
|
+
function writeControllerToken() {
|
|
24396
|
+
fs3.mkdirSync(path3.dirname(CONTROLLER_TOKEN_FILE), { recursive: true, mode: 448 });
|
|
24397
|
+
fs3.writeFileSync(CONTROLLER_TOKEN_FILE, CONTROLLER_TOKEN, { mode: 384 });
|
|
24398
|
+
fs3.chmodSync(CONTROLLER_TOKEN_FILE, 384);
|
|
24399
|
+
}
|
|
24400
|
+
function hasControllerToken(req) {
|
|
24401
|
+
const header = req.headers.authorization || "";
|
|
24402
|
+
const presented = header.startsWith("Bearer ") ? header.slice(7) : new URL(req.url || "/", "http://localhost").searchParams.get("token") || "";
|
|
24403
|
+
const a = Buffer.from(presented);
|
|
24404
|
+
const b = Buffer.from(CONTROLLER_TOKEN);
|
|
24405
|
+
return a.length === b.length && crypto2.timingSafeEqual(a, b);
|
|
24406
|
+
}
|
|
24407
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
24408
|
+
var LOCAL_ASSETS_DIR = path3.resolve(
|
|
24409
|
+
process.env.GOATEDIT_ASSETS_DIR || path3.join(os2.homedir(), "Movies")
|
|
24410
|
+
);
|
|
24411
|
+
var FRAMES_DIR = path3.resolve(
|
|
24412
|
+
process.env.GOATEDIT_FRAMES_DIR || path3.join(os2.homedir(), ".goatedit", "frames")
|
|
24413
|
+
);
|
|
24414
|
+
var VERSION = (() => {
|
|
24415
|
+
const here = path3.dirname(fileURLToPath(import.meta.url));
|
|
24416
|
+
for (const rel of ["../package.json", "../../../package.json"]) {
|
|
24417
|
+
try {
|
|
24418
|
+
const pkg = JSON.parse(fs3.readFileSync(path3.join(here, rel), "utf8"));
|
|
24419
|
+
if (pkg.name === "goatedit-mcp") return String(pkg.version);
|
|
24420
|
+
} catch {
|
|
24421
|
+
}
|
|
24422
|
+
}
|
|
24423
|
+
return "0.0.0";
|
|
24424
|
+
})();
|
|
24425
|
+
var INSTRUCTIONS = `Edits a GoatEdit video project live in the user's browser tab at ai.goatedit.com. At the start of each new request from the user, call begin_request with the kind of edit, its style words and any reference videos, then get_style_profile for how this user edits; treat that style as defaults, the request wins. Call get_timeline before your first edit \u2014 clip ids change after every split, trim or delete, and a stale id is rejected. Each edit's reply carries timelineChanges (clips added, with their ids and placement; clips changed; ids removed), so take the next ids from there instead of reading the timeline again. get_timeline is lean by default; pass detail: "full" only when you need effect parameters, and trackId or from/to to read part of it. Several edits in a row go faster as one run_tools call. With more than one tab open, call list_connected_projects, then use_project to pick one. To work on several projects at once (one helper agent per video), do not use use_project \u2014 it moves every caller \u2014 but pass projectId on each call, or once on run_tools for all its steps. render_preview_frame and preview_media accept saveToDisk: true, which writes the frame to a file and returns its path instead of the image. If a tool reports the editor is not connected, ask the user to open ai.goatedit.com and switch on Local in the AI status menu.`;
|
|
24426
|
+
var MEDIA_TYPES = {
|
|
24427
|
+
".mp4": { mime: "video/mp4", kind: "video" },
|
|
24428
|
+
".m4v": { mime: "video/mp4", kind: "video" },
|
|
24429
|
+
".mov": { mime: "video/quicktime", kind: "video" },
|
|
24430
|
+
".webm": { mime: "video/webm", kind: "video" },
|
|
24431
|
+
".mp3": { mime: "audio/mpeg", kind: "audio" },
|
|
24432
|
+
".wav": { mime: "audio/wav", kind: "audio" },
|
|
24433
|
+
".m4a": { mime: "audio/mp4", kind: "audio" },
|
|
24434
|
+
".aac": { mime: "audio/aac", kind: "audio" },
|
|
24435
|
+
".ogg": { mime: "audio/ogg", kind: "audio" },
|
|
24436
|
+
".flac": { mime: "audio/flac", kind: "audio" },
|
|
24437
|
+
".png": { mime: "image/png", kind: "image" },
|
|
24438
|
+
".jpg": { mime: "image/jpeg", kind: "image" },
|
|
24439
|
+
".jpeg": { mime: "image/jpeg", kind: "image" },
|
|
24440
|
+
".gif": { mime: "image/gif", kind: "image" },
|
|
24441
|
+
".webp": { mime: "image/webp", kind: "image" },
|
|
24442
|
+
".svg": { mime: "image/svg+xml", kind: "image" },
|
|
24443
|
+
".json": { mime: "application/json", kind: "lottie" },
|
|
24444
|
+
".glb": { mime: "model/gltf-binary", kind: "model" }
|
|
24445
|
+
};
|
|
24446
|
+
function mediaUrl(rel) {
|
|
24447
|
+
return `http://localhost:${WEBSOCKET_PORT}/media/${rel.split(path3.sep).map(encodeURIComponent).join("/")}`;
|
|
24448
|
+
}
|
|
24449
|
+
var MAX_LISTED_ASSETS = 500;
|
|
24450
|
+
var MAX_ASSET_DEPTH = 4;
|
|
24451
|
+
async function handleListLocalAssets(args = {}) {
|
|
24452
|
+
if (!fs3.existsSync(LOCAL_ASSETS_DIR)) {
|
|
24453
|
+
throw new Error(
|
|
24454
|
+
`Assets directory does not exist: ${LOCAL_ASSETS_DIR}. Set GOATEDIT_ASSETS_DIR to a folder of media.`
|
|
24455
|
+
);
|
|
24456
|
+
}
|
|
24457
|
+
const start = path3.resolve(LOCAL_ASSETS_DIR, args.folder || "");
|
|
24458
|
+
if (start !== LOCAL_ASSETS_DIR && !start.startsWith(LOCAL_ASSETS_DIR + path3.sep)) {
|
|
24459
|
+
throw new Error("folder must be inside the assets directory.");
|
|
24460
|
+
}
|
|
24461
|
+
const files = [];
|
|
24462
|
+
let truncated = false;
|
|
24463
|
+
const walk = (dir, depth) => {
|
|
24464
|
+
let entries;
|
|
24465
|
+
try {
|
|
24466
|
+
entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
24467
|
+
} catch {
|
|
24468
|
+
return;
|
|
24469
|
+
}
|
|
24470
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
24471
|
+
for (const entry of entries) {
|
|
24472
|
+
if (files.length >= MAX_LISTED_ASSETS) {
|
|
24473
|
+
truncated = true;
|
|
24474
|
+
return;
|
|
24475
|
+
}
|
|
24476
|
+
if (entry.name.startsWith(".")) continue;
|
|
24477
|
+
const full = path3.join(dir, entry.name);
|
|
24478
|
+
if (entry.isDirectory()) {
|
|
24479
|
+
if (depth < MAX_ASSET_DEPTH) walk(full, depth + 1);
|
|
21149
24480
|
continue;
|
|
21150
24481
|
}
|
|
21151
|
-
const type = MEDIA_TYPES[
|
|
24482
|
+
const type = MEDIA_TYPES[path3.extname(entry.name).toLowerCase()];
|
|
21152
24483
|
if (!type || !entry.isFile()) continue;
|
|
21153
|
-
const rel =
|
|
24484
|
+
const rel = path3.relative(LOCAL_ASSETS_DIR, full);
|
|
21154
24485
|
let bytes = 0;
|
|
21155
24486
|
try {
|
|
21156
|
-
bytes =
|
|
24487
|
+
bytes = fs3.statSync(full).size;
|
|
21157
24488
|
} catch {
|
|
21158
24489
|
}
|
|
21159
24490
|
files.push({ name: entry.name, path: rel, type: type.kind, bytes, url: mediaUrl(rel) });
|
|
@@ -21169,10 +24500,10 @@ async function handleListLocalAssets(args = {}) {
|
|
|
21169
24500
|
async function handleFindLocalFile(args = {}) {
|
|
21170
24501
|
const hit = findLocalFile(LOCAL_ASSETS_DIR, String(args.filename ?? ""), MAX_ASSET_DEPTH);
|
|
21171
24502
|
if (!hit) return null;
|
|
21172
|
-
const type = MEDIA_TYPES[
|
|
24503
|
+
const type = MEDIA_TYPES[path3.extname(hit).toLowerCase()];
|
|
21173
24504
|
if (!type || type.kind === "lottie") return null;
|
|
21174
|
-
const rel =
|
|
21175
|
-
return { name:
|
|
24505
|
+
const rel = path3.relative(LOCAL_ASSETS_DIR, hit);
|
|
24506
|
+
return { name: path3.basename(hit), path: rel, url: mediaUrl(rel), contentType: type.mime };
|
|
21176
24507
|
}
|
|
21177
24508
|
function audioDuration(file) {
|
|
21178
24509
|
try {
|
|
@@ -21191,15 +24522,15 @@ async function handleGenerateVoiceover(text, projectId) {
|
|
|
21191
24522
|
throw new Error("generate_voiceover needs macOS `say`. Not available on this platform.");
|
|
21192
24523
|
}
|
|
21193
24524
|
const filename = `voiceover_${Date.now()}.wav`;
|
|
21194
|
-
const filePath =
|
|
21195
|
-
|
|
21196
|
-
const scriptPath =
|
|
21197
|
-
|
|
24525
|
+
const filePath = path3.join(LOCAL_ASSETS_DIR, filename);
|
|
24526
|
+
fs3.mkdirSync(LOCAL_ASSETS_DIR, { recursive: true });
|
|
24527
|
+
const scriptPath = path3.join(LOCAL_ASSETS_DIR, `.voiceover_${Date.now()}.txt`);
|
|
24528
|
+
fs3.writeFileSync(scriptPath, text, "utf8");
|
|
21198
24529
|
try {
|
|
21199
24530
|
execFileSync("say", ["-o", filePath, "-f", scriptPath], { stdio: "ignore" });
|
|
21200
24531
|
const duration3 = audioDuration(filePath) ?? text.split(/\s+/).length * 0.45 + 1;
|
|
21201
24532
|
const audioAsset = {
|
|
21202
|
-
id: `media-${
|
|
24533
|
+
id: `media-${crypto2.randomUUID()}`,
|
|
21203
24534
|
name: filename,
|
|
21204
24535
|
type: "audio",
|
|
21205
24536
|
duration: duration3,
|
|
@@ -21212,7 +24543,7 @@ async function handleGenerateVoiceover(text, projectId) {
|
|
|
21212
24543
|
throw new Error(`Failed to generate voiceover: ${err.message}`);
|
|
21213
24544
|
} finally {
|
|
21214
24545
|
try {
|
|
21215
|
-
|
|
24546
|
+
fs3.unlinkSync(scriptPath);
|
|
21216
24547
|
} catch {
|
|
21217
24548
|
}
|
|
21218
24549
|
}
|
|
@@ -21220,12 +24551,12 @@ async function handleGenerateVoiceover(text, projectId) {
|
|
|
21220
24551
|
function saveFileToDisk(result) {
|
|
21221
24552
|
const file = result && typeof result === "object" ? result._file : void 0;
|
|
21222
24553
|
if (!file || typeof file.data !== "string") return result;
|
|
21223
|
-
|
|
24554
|
+
fs3.mkdirSync(FRAMES_DIR, { recursive: true });
|
|
21224
24555
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
21225
24556
|
const safe = String(file.name ?? "file").replace(/[^\w.-]+/g, "_").slice(0, 80);
|
|
21226
|
-
const target =
|
|
24557
|
+
const target = path3.join(FRAMES_DIR, `${stamp}-${safe}`);
|
|
21227
24558
|
const bytes = Buffer.from(file.data, "base64");
|
|
21228
|
-
|
|
24559
|
+
fs3.writeFileSync(target, bytes);
|
|
21229
24560
|
const { _file: _file2, ...rest } = result;
|
|
21230
24561
|
return { ...rest, savedTo: target, bytes: bytes.length };
|
|
21231
24562
|
}
|
|
@@ -21233,14 +24564,14 @@ function saveFramesToDisk(result, label) {
|
|
|
21233
24564
|
if (!result || typeof result !== "object") return result;
|
|
21234
24565
|
const frames = [result._image, ...Array.isArray(result._images) ? result._images : []].filter((f) => f && typeof f.data === "string" && typeof f.mimeType === "string");
|
|
21235
24566
|
if (!frames.length) return result;
|
|
21236
|
-
|
|
24567
|
+
fs3.mkdirSync(FRAMES_DIR, { recursive: true });
|
|
21237
24568
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
21238
24569
|
const safe = label.replace(/[^\w.-]+/g, "_").slice(0, 60);
|
|
21239
24570
|
const saved = frames.map((f, i) => {
|
|
21240
24571
|
const ext = f.mimeType === "image/png" ? "png" : f.mimeType === "image/webp" ? "webp" : "jpg";
|
|
21241
|
-
const file =
|
|
24572
|
+
const file = path3.join(FRAMES_DIR, `${stamp}-${safe}${frames.length > 1 ? `-${i}` : ""}.${ext}`);
|
|
21242
24573
|
const bytes = Buffer.from(f.data, "base64");
|
|
21243
|
-
|
|
24574
|
+
fs3.writeFileSync(file, bytes);
|
|
21244
24575
|
return { path: file, bytes: bytes.length, ...f.caption ? { caption: f.caption } : {} };
|
|
21245
24576
|
});
|
|
21246
24577
|
const { _image, _images, ...rest } = result;
|
|
@@ -21251,8 +24582,8 @@ function saveFramesToDisk(result, label) {
|
|
|
21251
24582
|
};
|
|
21252
24583
|
}
|
|
21253
24584
|
function serveFile(req, res, filePath) {
|
|
21254
|
-
const size =
|
|
21255
|
-
const type = MEDIA_TYPES[
|
|
24585
|
+
const size = fs3.statSync(filePath).size;
|
|
24586
|
+
const type = MEDIA_TYPES[path3.extname(filePath).toLowerCase()]?.mime ?? "application/octet-stream";
|
|
21256
24587
|
const headers = { "Content-Type": type, "Accept-Ranges": "bytes" };
|
|
21257
24588
|
const range = /^bytes=(\d*)-(\d*)$/.exec(req.headers.range || "");
|
|
21258
24589
|
if (range && (range[1] || range[2])) {
|
|
@@ -21275,7 +24606,7 @@ function serveFile(req, res, filePath) {
|
|
|
21275
24606
|
res.end();
|
|
21276
24607
|
return;
|
|
21277
24608
|
}
|
|
21278
|
-
|
|
24609
|
+
fs3.createReadStream(filePath, { start, end }).pipe(res);
|
|
21279
24610
|
return;
|
|
21280
24611
|
}
|
|
21281
24612
|
res.writeHead(200, { ...headers, "Content-Length": size });
|
|
@@ -21283,11 +24614,11 @@ function serveFile(req, res, filePath) {
|
|
|
21283
24614
|
res.end();
|
|
21284
24615
|
return;
|
|
21285
24616
|
}
|
|
21286
|
-
|
|
24617
|
+
fs3.createReadStream(filePath).pipe(res);
|
|
21287
24618
|
}
|
|
21288
24619
|
var httpServer = http.createServer((req, res) => {
|
|
21289
|
-
const
|
|
21290
|
-
const pathname =
|
|
24620
|
+
const url2 = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
24621
|
+
const pathname = url2.pathname;
|
|
21291
24622
|
if (!isLoopbackHost(req.headers.host)) {
|
|
21292
24623
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
21293
24624
|
res.end("Forbidden");
|
|
@@ -21321,9 +24652,9 @@ var httpServer = http.createServer((req, res) => {
|
|
|
21321
24652
|
res.end("Bad path");
|
|
21322
24653
|
return;
|
|
21323
24654
|
}
|
|
21324
|
-
const filePath =
|
|
21325
|
-
const inRoot = filePath === LOCAL_ASSETS_DIR || filePath.startsWith(LOCAL_ASSETS_DIR +
|
|
21326
|
-
if (inRoot &&
|
|
24655
|
+
const filePath = path3.resolve(LOCAL_ASSETS_DIR, filename);
|
|
24656
|
+
const inRoot = filePath === LOCAL_ASSETS_DIR || filePath.startsWith(LOCAL_ASSETS_DIR + path3.sep);
|
|
24657
|
+
if (inRoot && fs3.existsSync(filePath) && fs3.statSync(filePath).isFile()) {
|
|
21327
24658
|
serveFile(req, res, filePath);
|
|
21328
24659
|
} else {
|
|
21329
24660
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
@@ -21347,6 +24678,14 @@ var wss = new import_websocket_server.default({
|
|
|
21347
24678
|
wss.on("error", () => {
|
|
21348
24679
|
});
|
|
21349
24680
|
var tabs = /* @__PURE__ */ new Map();
|
|
24681
|
+
var tabReports = /* @__PURE__ */ new Map();
|
|
24682
|
+
function reindexTabs() {
|
|
24683
|
+
tabs.clear();
|
|
24684
|
+
for (const [pid, r] of indexTabs(tabReports.values(), (s) => s.readyState === import_websocket.default.OPEN)) {
|
|
24685
|
+
tabs.set(pid, { ws: r.socket, projectId: pid, projectName: r.projectName });
|
|
24686
|
+
}
|
|
24687
|
+
if (lastActiveProjectId && !tabs.has(lastActiveProjectId)) lastActiveProjectId = null;
|
|
24688
|
+
}
|
|
21350
24689
|
var lastActiveProjectId = null;
|
|
21351
24690
|
var chosenProjectId = null;
|
|
21352
24691
|
var controllerSockets = /* @__PURE__ */ new Set();
|
|
@@ -21400,9 +24739,24 @@ function explainTabError(error2) {
|
|
|
21400
24739
|
function sendJson(ws, message) {
|
|
21401
24740
|
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(message));
|
|
21402
24741
|
}
|
|
24742
|
+
async function answerService(ws, message) {
|
|
24743
|
+
const { id, action, params = {} } = message;
|
|
24744
|
+
try {
|
|
24745
|
+
let result;
|
|
24746
|
+
if (action === "list") result = await listServices();
|
|
24747
|
+
else if (action === "call") result = await callService(String(params.server), String(params.tool), params.args ?? {});
|
|
24748
|
+
else if (action === "download") {
|
|
24749
|
+
const saved = await downloadToAssets(LOCAL_ASSETS_DIR, String(params.url), typeof params.name === "string" ? params.name : void 0);
|
|
24750
|
+
result = { ...saved, mediaUrl: mediaUrl(saved.rel) };
|
|
24751
|
+
} else throw new Error(`Unknown service action: ${action}`);
|
|
24752
|
+
sendJson(ws, { type: "serviceReply", id, result });
|
|
24753
|
+
} catch (err) {
|
|
24754
|
+
sendJson(ws, { type: "serviceReply", id, error: err?.message ?? String(err) });
|
|
24755
|
+
}
|
|
24756
|
+
}
|
|
21403
24757
|
wss.on("connection", (ws, req) => {
|
|
21404
|
-
const
|
|
21405
|
-
if (
|
|
24758
|
+
const url2 = req.url || "/";
|
|
24759
|
+
if (url2.startsWith("/controller")) {
|
|
21406
24760
|
console.error("[GoatEdit MCP] Controller client connected");
|
|
21407
24761
|
controllerSockets.add(ws);
|
|
21408
24762
|
ws.on("message", async (data) => {
|
|
@@ -21420,7 +24774,7 @@ wss.on("connection", (ws, req) => {
|
|
|
21420
24774
|
}
|
|
21421
24775
|
const target = resolveTab(projectId);
|
|
21422
24776
|
if (id !== void 0) controllerRequests.set(String(id), ws);
|
|
21423
|
-
target.ws.send(JSON.stringify({ id, method, params }));
|
|
24777
|
+
target.ws.send(JSON.stringify({ id, method, params, projectId: target.projectId }));
|
|
21424
24778
|
} catch (err) {
|
|
21425
24779
|
sendJson(ws, { id, error: err?.message ?? String(err) });
|
|
21426
24780
|
}
|
|
@@ -21433,7 +24787,6 @@ wss.on("connection", (ws, req) => {
|
|
|
21433
24787
|
return;
|
|
21434
24788
|
}
|
|
21435
24789
|
console.error("[GoatEdit MCP] Browser editor connected via WebSocket");
|
|
21436
|
-
let myProjectId = null;
|
|
21437
24790
|
ws.on("message", (data) => {
|
|
21438
24791
|
let message;
|
|
21439
24792
|
try {
|
|
@@ -21445,15 +24798,18 @@ wss.on("connection", (ws, req) => {
|
|
|
21445
24798
|
if (message.type === "status") {
|
|
21446
24799
|
if (typeof message.projectId === "string" && message.projectId) {
|
|
21447
24800
|
const pid = message.projectId;
|
|
21448
|
-
|
|
21449
|
-
myProjectId = pid;
|
|
21450
|
-
tabs.set(pid, { ws, projectId: pid, projectName: message.projectName ?? null });
|
|
24801
|
+
tabReports.set(ws, { socket: ws, projectId: pid, projectName: message.projectName ?? null, at: Date.now() });
|
|
21451
24802
|
lastActiveProjectId = pid;
|
|
24803
|
+
reindexTabs();
|
|
21452
24804
|
console.error(`[GoatEdit MCP] Active project: ${message.projectName} (${pid})`);
|
|
21453
24805
|
}
|
|
21454
24806
|
for (const controller2 of controllerSockets) sendJson(controller2, message);
|
|
21455
24807
|
return;
|
|
21456
24808
|
}
|
|
24809
|
+
if (message.type === "service") {
|
|
24810
|
+
void answerService(ws, message);
|
|
24811
|
+
return;
|
|
24812
|
+
}
|
|
21457
24813
|
if (message.id === void 0 || message.result === void 0 && message.error === void 0) return;
|
|
21458
24814
|
const key = String(message.id);
|
|
21459
24815
|
const pending = pendingRequests.get(key);
|
|
@@ -21473,11 +24829,8 @@ wss.on("connection", (ws, req) => {
|
|
|
21473
24829
|
ws.on("close", () => {
|
|
21474
24830
|
console.error("[GoatEdit MCP] Browser editor disconnected");
|
|
21475
24831
|
rejectPendingOn(ws, "The editor tab disconnected");
|
|
21476
|
-
|
|
21477
|
-
|
|
21478
|
-
tabs.delete(pid);
|
|
21479
|
-
if (lastActiveProjectId === pid) lastActiveProjectId = null;
|
|
21480
|
-
}
|
|
24832
|
+
tabReports.delete(ws);
|
|
24833
|
+
reindexTabs();
|
|
21481
24834
|
});
|
|
21482
24835
|
});
|
|
21483
24836
|
var ownsPort = false;
|
|
@@ -21520,7 +24873,7 @@ function connectUpstream() {
|
|
|
21520
24873
|
upstreamReady = new Promise((resolve, reject) => {
|
|
21521
24874
|
let token;
|
|
21522
24875
|
try {
|
|
21523
|
-
token = process.env.GOATEDIT_CONTROLLER_TOKEN ||
|
|
24876
|
+
token = process.env.GOATEDIT_CONTROLLER_TOKEN || fs3.readFileSync(CONTROLLER_TOKEN_FILE, "utf8").trim();
|
|
21524
24877
|
} catch {
|
|
21525
24878
|
reject(new Error(notConnectedMessage()));
|
|
21526
24879
|
return;
|
|
@@ -21566,7 +24919,7 @@ async function ensureTransport() {
|
|
|
21566
24919
|
}
|
|
21567
24920
|
function sendUpstream(method, params, projectId) {
|
|
21568
24921
|
return connectUpstream().then((ws) => new Promise((resolve, reject) => {
|
|
21569
|
-
const id =
|
|
24922
|
+
const id = crypto2.randomUUID();
|
|
21570
24923
|
const timeoutId = setTimeout(() => {
|
|
21571
24924
|
upstreamPending.delete(id);
|
|
21572
24925
|
reject(new Error(`Request timed out: ${method}`));
|
|
@@ -21580,13 +24933,13 @@ async function sendToBrowser(method, params = {}, projectId) {
|
|
|
21580
24933
|
if (!ownsPort) return sendUpstream(method, params, projectId ?? chosenProjectId);
|
|
21581
24934
|
const tab = resolveTab(projectId);
|
|
21582
24935
|
return new Promise((resolve, reject) => {
|
|
21583
|
-
const id =
|
|
24936
|
+
const id = crypto2.randomUUID();
|
|
21584
24937
|
const timeoutId = setTimeout(() => {
|
|
21585
24938
|
pendingRequests.delete(id);
|
|
21586
24939
|
reject(new Error(`Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s: ${method}. Call get_timeline to see whether it landed.`));
|
|
21587
24940
|
}, REQUEST_TIMEOUT_MS);
|
|
21588
24941
|
pendingRequests.set(id, { resolve, reject, timeoutId, socket: tab.ws, method });
|
|
21589
|
-
tab.ws.send(JSON.stringify({ id, method, params }));
|
|
24942
|
+
tab.ws.send(JSON.stringify({ id, method, params, projectId: tab.projectId }));
|
|
21590
24943
|
});
|
|
21591
24944
|
}
|
|
21592
24945
|
var LOCAL_HANDLERS = {
|
|
@@ -21656,7 +25009,8 @@ var LOCAL_TOOLS = [
|
|
|
21656
25009
|
}
|
|
21657
25010
|
},
|
|
21658
25011
|
continueOnError: { type: "boolean", description: "Run the remaining steps after one fails." },
|
|
21659
|
-
rollback: { type: "boolean", description: "Take a checkpoint first and restore it if any step fails, so a run either lands whole or not at all. Cannot be combined with continueOnError." }
|
|
25012
|
+
rollback: { type: "boolean", description: "Take a checkpoint first and restore it if any step fails, so a run either lands whole or not at all. Cannot be combined with continueOnError." },
|
|
25013
|
+
projectId: { type: "string", description: "Run every step on this project (from list_connected_projects). Use it when several agents edit different tabs at once; a step's own projectId wins." }
|
|
21660
25014
|
},
|
|
21661
25015
|
required: ["calls"]
|
|
21662
25016
|
}
|
|
@@ -21743,7 +25097,7 @@ async function runTools(args) {
|
|
|
21743
25097
|
let failed = 0;
|
|
21744
25098
|
let checkpointId;
|
|
21745
25099
|
if (args.rollback) {
|
|
21746
|
-
const made = await callTool("create_checkpoint", { name: "run_tools rollback" });
|
|
25100
|
+
const made = await callTool("create_checkpoint", withRunProject({ name: "run_tools rollback" }, args.projectId));
|
|
21747
25101
|
checkpointId = made?.checkpointId;
|
|
21748
25102
|
}
|
|
21749
25103
|
for (let i = 0; i < calls.length; i++) {
|
|
@@ -21751,7 +25105,7 @@ async function runTools(args) {
|
|
|
21751
25105
|
const tool = typeof step?.tool === "string" ? step.tool : "";
|
|
21752
25106
|
try {
|
|
21753
25107
|
const stepArgs = resolveRefs(step.args && typeof step.args === "object" ? step.args : {}, refs);
|
|
21754
|
-
const raw = await callTool(tool, stepArgs);
|
|
25108
|
+
const raw = await callTool(tool, withRunProject(stepArgs, args.projectId));
|
|
21755
25109
|
if (typeof step.as === "string" && step.as) {
|
|
21756
25110
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
21757
25111
|
const { _image, _images, ...kept } = raw;
|
|
@@ -21781,7 +25135,7 @@ async function runTools(args) {
|
|
|
21781
25135
|
let rolledBack;
|
|
21782
25136
|
if (failed && checkpointId) {
|
|
21783
25137
|
try {
|
|
21784
|
-
await callTool("restore_checkpoint", { checkpointId });
|
|
25138
|
+
await callTool("restore_checkpoint", withRunProject({ checkpointId }, args.projectId));
|
|
21785
25139
|
rolledBack = true;
|
|
21786
25140
|
} catch (err) {
|
|
21787
25141
|
rolledBack = `failed: ${err?.message ?? err}. Restore ${checkpointId} with restore_checkpoint.`;
|